From 3e8f7f239bedae0b4f04a1ac6bd443ba6298f73c Mon Sep 17 00:00:00 2001
From: 朱桂飞 <zhuguifei@zhuguifeideMacBook-Air.local>
Date: 星期四, 09 一月 2025 15:26:03 +0800
Subject: [PATCH] 首次提交

---
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java                                             |   53 
 eims-ui/apps/web-antd/src/api/helper.ts                                                                                                        |   28 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts                                                                |   27 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/index.vue                                                                                       |   26 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts                                                                                 |    9 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java                                       |   70 
 eims/.gitignore                                                                                                                                |   48 
 eims-ui/scripts/turbo-run/tsconfig.json                                                                                                        |    6 
 eims/ruoyi-modules/ruoyi-generator/pom.xml                                                                                                     |   84 
 eims-ui/internal/lint-configs/commitlint-config/index.mjs                                                                                      |  153 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java                                        |  152 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue                                                                             |   16 
 eims/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    1 
 eims-ui/playground/src/views/demos/features/vue-query/infinite-queries.vue                                                                     |   58 
 eims-ui/apps/web-antd/src/views/system/notice/data.ts                                                                                          |  127 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java                                     |   47 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaType.java                                                 |   29 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java                                                  |   40 
 eims-ui/docs/.vitepress/components/index.ts                                                                                                    |    1 
 eims-ui/playground/public/favicon.ico                                                                                                          |    0 
 eims/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports        |    6 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java                                     |   81 
 eims-ui/docs/src/demos/vben-modal/draggable/modal.vue                                                                                          |   10 
 eims-ui/packages/effects/layouts/src/widgets/language-toggle.vue                                                                               |   37 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css                                                                      |    1 
 eims-ui/apps/web-antd/src/views/tool/gen/data.tsx                                                                                              |   61 
 eims-ui/apps/web-naive/tsconfig.json                                                                                                           |   12 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nl.js                                                                         |   93 
 eims-ui/docs/src/guide/in-depth/access.md                                                                                                      |  311 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml                                                |   10 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml                                                             |   70 
 eims-ui/apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js                                                                           |    4 
 eims-ui/apps/web-antd/src/components/dict/src/index.vue                                                                                        |   54 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/I18nLocaleResolver.java                                           |   31 
 eims-ui/packages/@core/ui-kit/layout-ui/tsconfig.json                                                                                          |    6 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/PlusTenantLineHandler.java                                |   56 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue                                                             |   17 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java                                                |   58 
 eims-ui/internal/tsconfig/base.json                                                                                                            |   40 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java                                           |   35 
 eims-ui/apps/web-antd/src/views/workflow/model/index.vue                                                                                       |    9 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic.tsx                                                                                  |  195 
 eims-ui/playground/src/api/index.ts                                                                                                            |    2 
 eims-ui/packages/styles/src/ele/index.css                                                                                                      |    3 
 eims-ui/apps/web-antd/src/router/routes/core.ts                                                                                                |   96 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml                                                    |    7 
 eims-ui/docs/src/demos/vben-vxe-table/custom-cell/index.vue                                                                                    |  105 
 eims-ui/docs/src/guide/in-depth/ui-framework.md                                                                                                |   17 
 eims-ui/apps/backend-mock/.nitro/types/nitro-imports.d.ts                                                                                      |  166 
 eims-ui/apps/web-ele/postcss.config.mjs                                                                                                        |    1 
 eims-ui/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts                                                                       |   68 
 eims-ui/packages/@core/ui-kit/form-ui/postcss.config.mjs                                                                                       |    1 
 eims-ui/apps/web-naive/src/api/index.ts                                                                                                        |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java                                              |   95 
 eims/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java                                                                             |   23 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java                                         |  295 
 eims-ui/docs/src/demos/vben-drawer/basic/index.vue                                                                                             |   11 
 eims-ui/apps/web-antd/src/views/system/tenant/data.tsx                                                                                         |  266 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java                                             |   39 
 eims-ui/docs/.vitepress/theme/styles/variables.css                                                                                             |  127 
 eims-ui/packages/utils/src/helpers/merge-route-modules.ts                                                                                      |   28 
 eims-ui/apps/web-ele/.env.production                                                                                                           |   19 
 eims-ui/packages/@core/ui-kit/layout-ui/package.json                                                                                           |   48 
 eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.min.css                                                                        |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue                                                           |   45 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml                                                           |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts                                                                                 |   11 
 eims-ui/playground/src/views/_core/fallback/coming-soon.vue                                                                                    |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts                                                                     |    2 
 eims-ui/playground/src/api/core/user.ts                                                                                                        |   10 
 eims-ui/docs/src/friend-links/index.md                                                                                                         |   27 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java                          |   86 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java                                              |    9 
 eims-ui/packages/@core/base/design/src/scss-bem/constants.scss                                                                                 |    5 
 eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue                                            |   52 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java                                                |   30 
 eims-ui/docs/src/public/logos/turborepo.svg                                                                                                    |   32 
 eims-ui/apps/web-antd/src/components/upload/src/use-upload.ts                                                                                  |   60 
 eims/ruoyi-extend/ruoyi-snailjob-server/Dockerfile                                                                                             |   21 
 eims-ui/apps/web-ele/.env.development                                                                                                          |   16 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue                                                                       |   11 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java                                         |   89 
 eims/ruoyi-common/ruoyi-common-log/pom.xml                                                                                                     |   32 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue                                                               |   49 
 eims-ui/scripts/vsh/src/index.ts                                                                                                               |   41 
 eims-ui/apps/web-antd/src/api/system/oss-config/model.d.ts                                                                                     |   16 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue                                                             |   64 
 eims-ui/packages/@core/base/shared/src/color/generator.ts                                                                                      |   45 
 eims-ui/apps/web-antd/src/views/system/menu/index.vue                                                                                          |  194 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/index.ts                                                                        |   10 
 eims/ruoyi-common/ruoyi-common-mail/pom.xml                                                                                                    |   34 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.min.css                                                                     |    1 
 eims-ui/docs/src/guide/in-depth/layout.md                                                                                                      |    1 
 eims-ui/packages/@core/ui-kit/menu-ui/tsconfig.json                                                                                            |    6 
 eims-ui/packages/@core/base/typings/src/menu-record.ts                                                                                         |   77 
 eims-ui/apps/web-antd/src/views/common.tsx                                                                                                     |   18 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java                                          |  369 
 eims-ui/apps/web-ele/src/api/core/user.ts                                                                                                      |   10 
 eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java                                            |   47 
 eims-ui/apps/web-ele/src/views/_core/fallback/internal-error.vue                                                                               |    9 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/index.ts                                                                                      |    3 
 eims-ui/apps/web-antd/src/views/_core/README.md                                                                                                |    3 
 eims-ui/apps/web-antd/src/api/monitor/online/model.d.ts                                                                                        |   10 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue                                                                               |   25 
 eims-ui/playground/src/views/demos/features/icons/index.vue                                                                                    |  106 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm                                                                          |   63 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue                                                                  |  119 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java                                           |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue                                                                               |   16 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/uk.js                                                                         |   93 
 eims-ui/apps/web-ele/.env                                                                                                                      |    5 
 eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.js                                                                         |    2 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue                                                              |  141 
 eims/README.md                                                                                                                                 |  182 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java                                                                      |   46 
 eims-ui/apps/web-ele/src/router/access.ts                                                                                                      |   42 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java                                   |   30 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm                                                              |  154 
 eims-ui/packages/@core/ui-kit/form-ui/tailwind.config.mjs                                                                                      |    1 
 eims-ui/packages/stores/src/modules/user.ts                                                                                                    |   68 
 eims-ui/apps/web-ele/src/preferences.ts                                                                                                        |   13 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts                                                                      |    1 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquTypeVo.java                                                          |   90 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue                                                                              |   18 
 eims-ui/packages/utils/src/helpers/uuid.ts                                                                                                     |   42 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java                         |  121 
 eims-ui/apps/web-naive/src/adapter/form.ts                                                                                                     |   45 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue                                                             |   34 
 eims/ruoyi-common/ruoyi-common-satoken/pom.xml                                                                                                 |   46 
 eims/ruoyi-modules/lb-eims/pom.xml                                                                                                             |  102 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java                                    |  152 
 eims-ui/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs                                                                                     |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue                                                                  |   41 
 eims-ui/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue                                                              |  142 
 eims/script/sql/update/update_5.0-5.1.sql                                                                                                      |  101 
 eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.min.css                                                                   |    1 
 eims-ui/docs/src/en/guide/in-depth/login.md                                                                                                    |  119 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml                                                   |    7 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java                                       |   54 
 eims-ui/apps/backend-mock/tsconfig.build.json                                                                                                  |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue                                                                        |   20 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue                                                                            |   29 
 eims-ui/apps/web-antd/src/views/eims/equ-type/equ-type-drawer.vue                                                                              |  137 
 eims-ui/packages/@core/base/shared/src/utils/window.ts                                                                                         |   37 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/block.vue                                                                      |   22 
 eims-ui/scripts/preview/7.png                                                                                                                  |    0 
 eims/ruoyi-common/ruoyi-common-encrypt/pom.xml                                                                                                 |   54 
 eims-ui/packages/effects/common-ui/src/components/captcha/types.ts                                                                             |  175 
 eims-ui/packages/effects/layouts/src/basic/copyright/index.ts                                                                                  |    1 
 eims-ui/packages/@core/composables/src/use-simple-locale/README.md                                                                             |    3 
 eims-ui/packages/effects/hooks/src/use-refresh.ts                                                                                              |   16 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java                                               |   46 
 eims-ui/apps/web-antd/src/api/workflow/category/model.d.ts                                                                                     |   87 
 eims-ui/packages/@core/composables/src/index.ts                                                                                                |   13 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue                                                                       |   11 
 eims-ui/apps/web-antd/src/components/upload/src/image-upload.vue                                                                               |  269 
 eims-ui/apps/web-antd/src/views/_core/fallback/not-found.vue                                                                                   |    9 
 eims-ui/apps/backend-mock/api/auth/login.post.ts                                                                                               |   36 
 eims-ui/internal/lint-configs/eslint-config/src/configs/ignores.ts                                                                             |   52 
 eims-ui/packages/effects/layouts/src/authentication/toolbar.vue                                                                                |   49 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue                                                                         |   15 
 eims-ui/packages/effects/request/src/request-client/request-client.ts                                                                          |  162 
 eims-ui/apps/web-naive/src/locales/langs/zh-CN/page.json                                                                                       |   15 
 eims-ui/packages/@core/preferences/build.config.ts                                                                                             |    7 
 eims-ui/playground/src/locales/langs/en-US/demos.json                                                                                          |   70 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java                               |   38 
 eims-ui/playground/src/views/demos/features/hide-menu-children/children.vue                                                                    |    3 
 eims-ui/packages/effects/request/package.json                                                                                                  |   32 
 eims-ui/apps/web-ele/src/layouts/basic.vue                                                                                                     |  157 
 eims-ui/apps/web-naive/src/router/index.ts                                                                                                     |   37 
 eims-ui/apps/web-ele/src/views/demos/form/basic.vue                                                                                            |  180 
 eims-ui/packages/@core/base/shared/src/utils/merge.ts                                                                                          |   10 
 eims/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql                                                                                        |   10 
 eims/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java                                                               |  136 
 eims-ui/packages/@core/ui-kit/tabs-ui/package.json                                                                                             |   47 
 eims-ui/packages/effects/common-ui/src/components/markdown/index.ts                                                                            |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue                                                            |   17 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java                                              |   31 
 eims-ui/packages/@core/base/shared/src/utils/state-handler.ts                                                                                  |   50 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts                                                                                  |   10 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java                                              |   76 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue                                                                |   83 
 eims-ui/package.json                                                                                                                           |  124 
 eims-ui/apps/web-antd/src/locales/langs/en-US/component.json                                                                                   |   55 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue                                                                |   67 
 eims-ui/apps/backend-mock/api/test.get.ts                                                                                                      |    1 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java                                              |   95 
 eims-ui/apps/web-antd/src/api/eims/equ-type/model.d.ts                                                                                         |   67 
 eims-ui/packages/effects/layouts/src/basic/footer/index.ts                                                                                     |    1 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java                               |   62 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java                                                |   23 
 eims-ui/apps/web-antd/src/views/system/tenantPackage/data.ts                                                                                   |   77 
 eims-ui/docs/.vitepress/config/shared.mts                                                                                                      |  172 
 eims-ui/internal/vite-config/src/typing.ts                                                                                                     |  164 
 eims-ui/packages/effects/common-ui/src/ui/index.ts                                                                                             |    4 
 eims-ui/apps/web-antd/src/components/global/index.ts                                                                                           |   14 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue                                                                |   51 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue                                                                            |   57 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts                                                                             |    3 
 eims-ui/pnpm-workspace.yaml                                                                                                                    |  183 
 eims-ui/packages/stores/src/modules/lock.test.ts                                                                                               |   31 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java                               |  144 
 eims-ui/packages/effects/plugins/src/vxe-table/init.ts                                                                                         |  131 
 eims-ui/packages/locales/src/langs/en-US/ui.json                                                                                               |   82 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.min.css                                                                |    1 
 eims-ui/apps/web-naive/src/router/routes/modules/dashboard.ts                                                                                  |   40 
 eims-ui/packages/utils/src/helpers/__tests__/generate-menus.test.ts                                                                            |  236 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java                                               |   14 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue                                                              |   11 
 eims-ui/apps/web-antd/src/components/description/src/description.vue                                                                           |  210 
 eims/ruoyi-admin/src/main/resources/application.yml                                                                                            |  295 
 eims-ui/apps/web-antd/.env.production                                                                                                          |   32 
 eims-ui/internal/vite-config/package.json                                                                                                      |   59 
 eims-ui/docs/src/guide/essentials/settings.md                                                                                                  |  540 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue                                                                        |   28 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts                                                                              |    1 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/exception/OssException.java                                            |   19 
 eims-ui/apps/web-antd/src/views/_core/oauth-common.ts                                                                                          |  104 
 eims-ui/apps/web-ele/src/router/routes/index.ts                                                                                                |   37 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hu_HU.js                                                                      |   93 
 eims-ui/apps/web-ele/src/bootstrap.ts                                                                                                          |   51 
 eims-ui/apps/web-antd/src/views/demo/demo/demo-modal.vue                                                                                       |   87 
 eims/ruoyi-modules/ruoyi-system/pom.xml                                                                                                        |  105 
 eims-ui/packages/effects/plugins/src/vxe-table/extends.ts                                                                                      |   80 
 eims-ui/packages/effects/plugins/src/echarts/use-echarts.ts                                                                                    |  118 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java                                         |  202 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue                                                                                 |   32 
 eims-ui/playground/src/views/demos/badge/index.vue                                                                                             |    7 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.min.css                                                                       |    1 
 eims-ui/packages/effects/common-ui/src/components/page/index.ts                                                                                |    1 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/index.vue                                                                                 |   90 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java                                    |   32 
 eims-ui/apps/web-antd/src/views/system/dict/data/index.vue                                                                                     |  186 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java                                         |  137 
 eims-ui/apps/web-naive/src/router/routes/core.ts                                                                                               |   88 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts                                                                                  |    3 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm                                                                            |   19 
 eims-ui/packages/types/tsconfig.json                                                                                                           |    6 
 eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue                                             |   63 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue                                                                     |  137 
 eims-ui/apps/web-antd/src/views/system/config/data.ts                                                                                          |  125 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue                                                                        |   19 
 eims/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java                                                                  |  234 
 eims-ui/apps/web-naive/src/router/routes/modules/vben.ts                                                                                       |   82 
 eims-ui/packages/utils/src/helpers/get-popup-container.ts                                                                                      |   34 
 eims/ruoyi-common/ruoyi-common-security/pom.xml                                                                                                |   26 
 eims-ui/packages/effects/common-ui/src/components/resize/resize.vue                                                                            | 1122 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue                                                               |   54 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts                                                                         |    3 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue                                                                          |  151 
 eims/ruoyi-common/ruoyi-common-sensitive/pom.xml                                                                                               |   25 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts                                                                   |   60 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java                                                         |  136 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java                                        |   70 
 eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts                                                                            |   55 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.min.css                                                                   |    1 
 eims-ui/apps/web-ele/src/store/auth.ts                                                                                                         |  116 
 eims-ui/docs/src/demos/vben-vxe-table/tree/index.vue                                                                                           |   80 
 eims-ui/playground/src/views/examples/form/api.vue                                                                                             |  265 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts                                                                 |   45 
 eims-ui/packages/@core/base/shared/src/utils/util.ts                                                                                           |   44 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts                                                                                  |   22 
 eims-ui/apps/web-ele/src/main.ts                                                                                                               |   31 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/OssUrlTranslationImpl.java                   |   29 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue                                                          |   54 
 eims-ui/apps/web-ele/src/locales/langs/en-US/demos.json                                                                                        |   13 
 eims/script/bpmn/模型.zip                                                                                                                        |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java                                                       |   29 
 eims-ui/docs/src/en/guide/project/changeset.md                                                                                                 |   21 
 eims-ui/packages/effects/layouts/src/widgets/index.ts                                                                                          |   11 
 eims-ui/playground/src/views/dashboard/analytics/analytics-visits-sales.vue                                                                    |   48 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java                                      |   59 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java                               |   73 
 eims-ui/packages/@core/base/shared/src/utils/nprogress.ts                                                                                      |   43 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml                                                    |    7 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md                                                                   |    3 
 eims-ui/packages/@core/base/design/src/design-tokens/index.ts                                                                                  |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue                                                        |   19 
 eims-ui/apps/web-antd/src/views/workflow/task/taskCopyList.vue                                                                                 |    9 
 eims-ui/docs/.vitepress/theme/components/site-layout.vue                                                                                       |   97 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue                                                                             |  133 
 eims-ui/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs                                                                                    |    1 
 eims-ui/scripts/preview/5.png                                                                                                                  |    0 
 eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java                                               |   37 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sk.js                                                                         |   93 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue                                                                       |   42 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue                                                                                 |   16 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java                                 |   52 
 eims-ui/apps/web-antd/src/views/workflow/components/approval-card.vue                                                                          |   61 
 eims-ui/packages/effects/common-ui/src/ui/authentication/third-party-login.vue                                                                 |   43 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml                                                                 |   50 
 eims-ui/packages/@core/ui-kit/form-ui/src/types.ts                                                                                             |  389 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java                                                |   21 
 eims-ui/apps/web-antd/src/views/_core/authentication/register.vue                                                                              |   95 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts                                                                                        |   28 
 eims-ui/.env.production                                                                                                                        |   35 
 eims/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue                                                                          |   11 
 eims-ui/cspell.json                                                                                                                            |   74 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts                                                                 |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts                                                                                   |    5 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml                                                                            |   10 
 eims-ui/docs/src/public/guide/update-notice.png                                                                                                |    0 
 eims-ui/apps/web-antd/src/views/_core/authentication/login.vue                                                                                 |  163 
 eims-ui/packages/effects/layouts/src/widgets/lock-screen/index.ts                                                                              |    2 
 eims-ui/packages/@core/ui-kit/popup-ui/src/index.ts                                                                                            |    2 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java                                                     |   63 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue                                                                       |   42 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java                                    |   20 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java                               |   61 
 eims-ui/packages/effects/layouts/package.json                                                                                                  |   43 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java                                                      |  102 
 eims-ui/apps/backend-mock/api/status.ts                                                                                                        |    5 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts                                                                           |    5 
 eims-ui/packages/effects/layouts/src/widgets/global-search/search-panel.vue                                                                    |  287 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm                                                                   |   20 
 eims-ui/docs/tsconfig.json                                                                                                                     |   19 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java                                                   |   14 
 eims-ui/apps/web-naive/src/main.ts                                                                                                             |   31 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue                                                         |   45 
 eims-ui/playground/src/views/examples/modal/auto-height-demo.vue                                                                               |   46 
 eims-ui/scripts/deploy/Dockerfile                                                                                                              |   31 
 eims-ui/internal/lint-configs/eslint-config/src/configs/command.ts                                                                             |   10 
 eims-ui/playground/src/api/request.ts                                                                                                          |  114 
 eims-ui/apps/web-antd/public/tinymce/plugins/wordcount/plugin.min.js                                                                           |    4 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts                                                                                |  143 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java                                    |   21 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_CN.js                                                                      |   87 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue                                                             |   55 
 eims/ruoyi-common/ruoyi-common-web/pom.xml                                                                                                     |   75 
 eims-ui/playground/src/layouts/auth.vue                                                                                                        |   23 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java                                     |  431 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue                                                                              |  273 
 eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading.html                                                               |  113 
 eims-ui/packages/effects/common-ui/src/ui/about/index.ts                                                                                       |    1 
 eims-ui/apps/web-antd/src/store/index.ts                                                                                                       |    2 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java                                                   |   75 
 eims-ui/packages/effects/layouts/src/iframe/iframe-router-view.vue                                                                             |   85 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts                                                                          |    3 
 eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java                                                                    |   25 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java                             |   61 
 eims-ui/docs/src/public/guide/devtools.png                                                                                                     |    0 
 eims-ui/internal/vite-config/src/plugins/extra-app-config.ts                                                                                   |   92 
 eims-ui/packages/effects/plugins/src/echarts/echarts.ts                                                                                        |   70 
 eims-ui/apps/web-ele/src/api/core/auth.ts                                                                                                      |   51 
 eims-ui/docs/src/demos/vben-modal/auto-height/modal.vue                                                                                        |   45 
 eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue                                                             |  243 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts                                                                     |   38 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts                                                               |    1 
 eims-ui/packages/@core/ui-kit/menu-ui/postcss.config.mjs                                                                                       |    1 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue                                                           |   44 
 eims-ui/docs/src/en/index.md                                                                                                                   |   76 
 eims-ui/packages/@core/preferences/src/types.ts                                                                                                |  281 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts                                                                                  |  117 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js                                                                      |   93 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java                                        |  148 
 eims-ui/apps/web-antd/src/views/monitor/online/index.vue                                                                                       |   71 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue                                                            |   37 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java                                                  |  295 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.vue                                                                                     |  311 
 eims-ui/packages/effects/plugins/src/vxe-table/style.css                                                                                       |  112 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts                                                                                     |  127 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java                                                       |   29 
 eims-ui/apps/web-antd/src/components/description/src/useDescription.ts                                                                         |   44 
 eims-ui/packages/icons/src/iconify-offline/index.ts                                                                                            |  186 
 eims-ui/docs/src/guide/essentials/build.md                                                                                                     |  243 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue                                                                  |   68 
 eims-ui/packages/effects/plugins/src/vxe-table/index.ts                                                                                        |    4 
 eims-ui/apps/web-antd/src/views/demo/demo/api/index.ts                                                                                         |   60 
 eims-ui/apps/web-antd/src/store/dict.ts                                                                                                        |  111 
 eims-ui/playground/src/router/routes/modules/vben.ts                                                                                           |   94 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java                               |   97 
 eims-ui/apps/web-naive/src/views/demos/form/basic.vue                                                                                          |  143 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java                                        |  577 
 eims-ui/docs/src/demos/vben-modal/dynamic/index.vue                                                                                            |   30 
 eims-ui/packages/locales/src/i18n.ts                                                                                                           |  146 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue                                                                 |   35 
 eims-ui/apps/web-naive/src/locales/langs/en-US/page.json                                                                                       |   15 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java                           |   29 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java                                            |   15 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts                                                                            |    2 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java                                               |    9 
 eims-ui/docs/.vitepress/theme/components/vben-contributors.vue                                                                                 |   29 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java                                   |   83 
 eims-ui/packages/@core/ui-kit/popup-ui/tsconfig.json                                                                                           |    6 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue                                                                        |   40 
 eims-ui/scripts/preview/3.png                                                                                                                  |    0 
 eims-ui/apps/web-antd/src/views/system/client/data.tsx                                                                                         |  193 
 eims-ui/apps/web-antd/src/views/system/oss/index.vue                                                                                           |  227 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue                                                        |   37 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.js                                                                                    |    2 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java                                                   |   14 
 eims-ui/internal/tailwind-config/package.json                                                                                                  |   66 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue                                                                                 |   29 
 eims-ui/packages/effects/request/src/request-client/modules/interceptor.ts                                                                     |   40 
 eims-ui/playground/src/views/demos/access/button-control.vue                                                                                   |  155 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java                                           |   93 
 eims-ui/apps/web-antd/src/components/tenant-toggle/src/index.vue                                                                               |  123 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java                           |   34 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java                                                |   70 
 eims-ui/apps/backend-mock/.nitro/types/tsconfig.json                                                                                           |   37 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue                                                                           |   33 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java                                                    |  114 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/EquTypeService.java                                          |   11 
 eims-ui/internal/vite-config/src/plugins/archiver.ts                                                                                           |   75 
 eims/script/sql/oracle/flowable.sql                                                                                                            |  261 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts                                                                                 |    2 
 eims-ui/apps/backend-mock/package.json                                                                                                         |   21 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/pages/loginLine.vue                                                                             |   83 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java                                      |  300 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java                                                      |  142 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java                                 |   75 
 eims-ui/playground/src/views/examples/drawer/dynamic-demo.vue                                                                                  |   31 
 eims-ui/scripts/turbo-run/README.md                                                                                                            |    3 
 eims-ui/playground/src/app.vue                                                                                                                 |   39 
 eims-ui/internal/node-utils/src/monorepo.ts                                                                                                    |   46 
 eims-ui/docs/src/components/layout-ui/page.md                                                                                                  |   44 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/pages/isp.vue                                                                                   |   62 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts                                                                          |    2 
 eims-ui/packages/utils/src/helpers/__tests__/enum-options.test.ts                                                                              |   19 
 eims-ui/packages/utils/src/helpers/mitt.ts                                                                                                     |  135 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java                                                 |   13 
 eims-ui/packages/utils/src/index.ts                                                                                                            |    5 
 eims-ui/docs/src/demos/vben-vxe-table/edit-cell/index.vue                                                                                      |   55 
 eims-ui/apps/backend-mock/utils/response.ts                                                                                                    |   68 
 eims-ui/apps/web-antd/src/api/system/notice/model.d.ts                                                                                         |   11 
 eims-ui/packages/effects/layouts/src/basic/content/index.ts                                                                                    |    2 
 eims/ruoyi-common/ruoyi-common-job/pom.xml                                                                                                     |   46 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx                                                                                |    0 
 eims-ui/packages/effects/request/src/request-client/modules/uploader.test.ts                                                                   |  118 
 eims-ui/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts                                                                               |  189 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java                                       |   55 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml                                                       |    7 
 eims-ui/docs/src/guide/essentials/route.md                                                                                                     |  600 
 eims-ui/LICENSE                                                                                                                                |    9 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java                                            |   28 
 eims-ui/docs/src/public/guide/test.png                                                                                                         |    0 
 eims-ui/packages/@core/base/design/src/scss-bem/bem.scss                                                                                       |   34 
 eims-ui/playground/__tests__/e2e/common/auth.ts                                                                                                |   46 
 eims/ruoyi-modules/ruoyi-workflow/pom.xml                                                                                                      |  119 
 eims-ui/apps/web-naive/src/store/index.ts                                                                                                      |    1 
 eims-ui/docs/src/en/guide/essentials/route.md                                                                                                  |  606 
 eims-ui/apps/web-antd/src/router/guard.ts                                                                                                      |  125 
 eims-ui/apps/web-antd/src/views/system/user/dept-tree.vue                                                                                      |  121 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java                                                    |   52 
 eims-ui/apps/web-antd/.env.analyze                                                                                                             |    7 
 eims-ui/apps/web-antd/src/views/eims/equ-type/data.tsx                                                                                         |  196 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java                                                 |   13 
 eims/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java                                                                            |   45 
 eims-ui/packages/@core/base/shared/src/cache/storage-manager.ts                                                                                |  118 
 eims-ui/packages/@core/base/design/src/css/nprogress.css                                                                                       |   59 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java                                  |  127 
 eims-ui/apps/web-antd/src/router/routes/modules/dashboard.ts                                                                                   |   40 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java                                         |  230 
 eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js                                                                           |    4 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java                                                             |  102 
 eims-ui/docs/src/demos/vben-vxe-table/edit-row/index.vue                                                                                       |   92 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquTypeMapper.xml                                                                 |    7 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/diff.test.ts                                                                            |   53 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java                                      |   87 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java                               |  130 
 eims-ui/packages/@core/base/shared/src/utils/cn.ts                                                                                             |    8 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java                                                  |   51 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts                                                                                  |    1 
 eims/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java                                                                      |   18 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java                                              |   44 
 eims-ui/playground/src/views/examples/form/basic.vue                                                                                           |  407 
 eims-ui/packages/effects/layouts/src/authentication/index.ts                                                                                   |    1 
 eims-ui/apps/web-antd/src/api/tool/gen/model.d.ts                                                                                              |  186 
 eims-ui/packages/effects/layouts/src/widgets/check-updates/check-updates.vue                                                                   |  134 
 eims-ui/playground/__tests__/e2e/auth-login.spec.ts                                                                                            |   20 
 eims-ui/apps/web-antd/src/api/system/post/index.ts                                                                                             |   46 
 eims-ui/scripts/vsh/src/publint/index.ts                                                                                                       |  185 
 eims-ui/apps/backend-mock/README.md                                                                                                            |   15 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java                                   |   44 
 eims/script/sql/oracle/snail_job_oracle.sql                                                                                                    |  905 
 eims-ui/packages/effects/layouts/src/basic/menu/menu.vue                                                                                       |   37 
 eims-ui/packages/@core/base/design/src/css/global.css                                                                                          |  160 
 eims-ui/packages/effects/common-ui/src/components/json-preview/json-preview.vue                                                                |   19 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue                                                                       |   43 
 eims-ui/docs/src/en/guide/introduction/quick-start.md                                                                                          |   95 
 eims-ui/docs/src/en/guide/essentials/external-module.md                                                                                        |   58 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ko_KR.js                                                                      |   93 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java                                |   31 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/BoundedQueueController.java                                      |   92 
 eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts                                                                                  |   17 
 eims-ui/apps/web-antd/src/locales/langs/en-US/pages.json                                                                                       |   23 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue                                                                        |   57 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue                                                                 |   51 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/exception/TenantException.java                                   |   20 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.js                                                                      |    2 
 eims-ui/internal/node-utils/src/__tests__/hash.test.ts                                                                                         |   52 
 eims-ui/apps/web-antd/src/components/cropper/src/cropper.vue                                                                                   |  195 
 eims-ui/scripts/vsh/tsconfig.json                                                                                                              |    6 
 eims-ui/packages/icons/src/svg/icons/antdv-logo.svg                                                                                            |   29 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml                                                         |    7 
 eims-ui/playground/src/views/demos/features/file-download/base64.ts                                                                            |    1 
 eims-ui/packages/@core/base/README.md                                                                                                          |    5 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm                                                                      |  459 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue                                                                      |  194 
 eims-ui/apps/web-antd/src/views/system/user/user-drawer.vue                                                                                    |  227 
 eims-ui/packages/preferences/tsconfig.json                                                                                                     |    6 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java                                                 |   23 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md                                                                    |    3 
 eims-ui/packages/@core/base/design/vite.config.mts                                                                                             |    9 
 eims/script/sql/update/update_5.1.1-5.1.2.sql                                                                                                  |    5 
 eims-ui/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue                                                                        |   33 
 eims-ui/scripts/turbo-run/src/index.ts                                                                                                         |   29 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue                                                        |   19 
 eims-ui/playground/src/views/demos/features/vue-query/typing.ts                                                                                |   18 
 eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java                                       |   30 
 eims-ui/packages/utils/src/helpers/find-menu-by-path.ts                                                                                        |   37 
 eims-ui/packages/icons/src/svg/icons/avatar-3.svg                                                                                              |    1 
 eims-ui/internal/lint-configs/stylelint-config/index.mjs                                                                                       |  140 
 eims-ui/internal/lint-configs/eslint-config/src/configs/import.ts                                                                              |   24 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts                                                                           |    1 
 eims-ui/apps/web-antd/src/views/_core/profile/index.vue                                                                                        |   54 
 eims-ui/apps/web-antd/src/views/system/dict/data/data.ts                                                                                       |  107 
 eims-ui/packages/@core/ui-kit/shadcn-ui/components.json                                                                                        |   16 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java                                |  192 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml                                                           |    7 
 eims-ui/packages/effects/layouts/src/widgets/color-toggle.vue                                                                                  |   63 
 eims-ui/apps/backend-mock/.nitro/nitro.json                                                                                                    |   17 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java                                               |   53 
 eims-ui/apps/web-antd/src/views/workflow/task/allTaskWaiting.vue                                                                               |    9 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue                                                                 |   19 
 eims-ui/docs/src/public/logos/vite.svg                                                                                                         |   15 
 eims-ui/packages/icons/src/svg/icons/avatar-1.svg                                                                                              |    1 
 eims-ui/internal/lint-configs/stylelint-config/package.json                                                                                    |   43 
 eims-ui/packages/effects/request/src/request-client/types.ts                                                                                   |   78 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue                                                                          |  215 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml                                                         |    7 
 eims-ui/apps/web-antd/src/assets/img/img-lower-limit.png                                                                                       |    0 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java                             |   47 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java                                               |   67 
 eims-ui/packages/constants/src/index.ts                                                                                                        |    2 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java                                                |   23 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java                                                 |   44 
 eims-ui/docs/src/demos/vben-form/custom/index.vue                                                                                              |   68 
 eims-ui/scripts/preview/1.png                                                                                                                  |    0 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts                                                                   |    3 
 eims-ui/packages/@core/ui-kit/shadcn-ui/build.config.ts                                                                                        |   27 
 eims-ui/packages/@core/composables/src/use-priority-value.ts                                                                                   |   93 
 eims-ui/docs/src/demos/vben-drawer/dynamic/index.vue                                                                                           |   30 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue                                                                          |   31 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.min.css                                                                 |    1 
 eims-ui/docs/src/en/guide/essentials/build.md                                                                                                  |  243 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java                                 |   30 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java                                                |   96 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java                                                  |   35 
 eims-ui/internal/tailwind-config/src/plugins/entry.ts                                                                                          |   53 
 eims-ui/packages/icons/src/iconify/index.ts                                                                                                    |   18 
 eims-ui/apps/web-naive/src/api/request.ts                                                                                                      |  112 
 eims-ui/apps/web-antd/public/tinymce/plugins/quickbars/plugin.min.js                                                                           |    4 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java                                              |   81 
 eims-ui/packages/@core/base/design/src/index.ts                                                                                                |    8 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/单列表.xlsx                                                                                |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java                                                           |  191 
 eims-ui/internal/lint-configs/eslint-config/src/configs/typescript.ts                                                                          |   72 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java                 |   27 
 eims-ui/scripts/vsh/bin/vsh.mjs                                                                                                                |    3 
 eims-ui/packages/effects/access/src/access-control.vue                                                                                         |   47 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pl.js                                                                         |   93 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java                                                   |  144 
 eims-ui/packages/effects/request/src/request-client/modules/downloader.test.ts                                                                 |   84 
 eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |    7 
 eims/ruoyi-common/ruoyi-common-tenant/pom.xml                                                                                                  |   32 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/vi.js                                                                         |   93 
 eims-ui/packages/@core/base/typings/src/index.ts                                                                                               |    6 
 eims-ui/apps/web-naive/src/views/demos/naive/index.vue                                                                                         |   68 
 eims-ui/packages/utils/src/helpers/request.ts                                                                                                  |   24 
 eims-ui/docs/src/guide/other/remove-code.md                                                                                                    |   18 
 eims-ui/internal/lint-configs/eslint-config/tsconfig.json                                                                                      |    6 
 eims-ui/apps/web-antd/src/components/cropper/src/cropper-avatar.vue                                                                            |  174 
 eims/ruoyi-common/ruoyi-common-translation/pom.xml                                                                                             |   27 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm                                                                     |    7 
 eims-ui/packages/effects/layouts/src/iframe/index.ts                                                                                           |    2 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts                                                                          |  124 
 eims-ui/apps/web-antd/tailwind.config.mjs                                                                                                      |    1 
 eims-ui/packages/icons/package.json                                                                                                            |   60 
 eims-ui/apps/web-antd/src/views/system/dict/type/data.ts                                                                                       |   76 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml                                                                   |   13 
 eims-ui/docs/src/commercial/customized.md                                                                                                      |   12 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/warning.svg                                                                           |    1 
 eims-ui/docs/src/demos/vben-vxe-table/mock-api.ts                                                                                              |   36 
 eims-ui/packages/effects/common-ui/src/components/page/__tests__/page.test.ts                                                                  |   88 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java                            |   41 
 eims-ui/apps/web-naive/src/views/_core/fallback/offline.vue                                                                                    |    9 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java                           |  108 
 eims-ui/playground/src/locales/langs/zh-CN/examples.json                                                                                       |   63 
 eims-ui/playground/src/views/examples/captcha/point-selection-captcha.vue                                                                      |  181 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/setting.vue                                                                     |   12 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java                                                     |   62 
 eims-ui/docs/src/en/guide/other/faq.md                                                                                                         |  159 
 eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java                              |   58 
 eims-ui/apps/web-antd/src/views/demo/tree/api/model.d.ts                                                                                       |  102 
 eims-ui/docs/.vitepress/theme/styles/base.css                                                                                                  |   22 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java                                                           |   79 
 eims-ui/apps/web-antd/public/tinymce/plugins/visualchars/plugin.min.js                                                                         |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue                                                           |   96 
 eims-ui/stylelint.config.mjs                                                                                                                   |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java                                                   |   14 
 eims-ui/apps/web-antd/src/layouts/basic.vue                                                                                                    |  168 
 eims-ui/apps/web-antd/public/tinymce/plugins/insertdatetime/plugin.min.js                                                                      |    4 
 eims-ui/internal/node-utils/src/git.ts                                                                                                         |   34 
 eims-ui/internal/lint-configs/eslint-config/src/configs/regexp.ts                                                                              |   20 
 eims/script/sql/update/sqlserver/update_5.0-5.1.sql                                                                                            |  409 
 eims-ui/apps/backend-mock/utils/mock-data.ts                                                                                                   |  186 
 eims-ui/apps/web-antd/public/tinymce/langs/README.md                                                                                           |    3 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue                                                                   |   43 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java                                                     |   36 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.min.css                                                                        |    1 
 eims-ui/packages/effects/common-ui/src/ui/authentication/auth-title.vue                                                                        |   13 
 eims-ui/apps/web-antd/src/views/dashboard/workspace/index.vue                                                                                  |  266 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts                                                                                |   34 
 eims/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java                                                                               |   54 
 eims-ui/docs/src/demos/vben-form/dynamic/index.vue                                                                                             |  168 
 eims-ui/internal/lint-configs/eslint-config/src/configs/javascript.ts                                                                          |  242 
 eims-ui/packages/icons/src/index.ts                                                                                                            |    5 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java                           |   18 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java                                 |   18 
 eims-ui/packages/icons/src/svg/icons/card.svg                                                                                                  |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java                                        |  219 
 eims-ui/apps/web-antd/src/locales/langs/en-US/page.json                                                                                        |   15 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java                                    |   61 
 eims-ui/docs/src/demos/vben-api-component/cascader/index.vue                                                                                   |  100 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue                                                                |   67 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/pages/device.vue                                                                                |   62 
 eims-ui/apps/web-antd/src/api/system/user/index.ts                                                                                             |  167 
 eims-ui/apps/web-antd/src/api/system/tenant/model.d.ts                                                                                         |   16 
 eims-ui/apps/web-antd/src/api/eims/equ/model.d.ts                                                                                              |  124 
 eims-ui/docs/src/en/guide/introduction/thin.md                                                                                                 |   67 
 eims-ui/docs/src/guide/essentials/icons.md                                                                                                     |   78 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue                                                               |   98 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DictTypeTranslationImpl.java                 |   28 
 eims-ui/packages/effects/layouts/src/basic/layout.vue                                                                                          |  342 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.min.css                                                                            |    1 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/wechat/index.vue                                                                                      |   37 
 eims-ui/docs/src/_env/adapter/vxe-table.ts                                                                                                     |   70 
 eims-ui/apps/web-ele/src/views/_core/fallback/not-found.vue                                                                                    |    9 
 eims-ui/docs/src/guide/in-depth/loading.md                                                                                                     |   46 
 eims-ui/packages/icons/src/svg/icons/download.svg                                                                                              |    1 
 eims-ui/internal/tsconfig/web-app.json                                                                                                         |    8 
 eims/script/sql/update/postgres/update_5.1.2-5.2.0.sql                                                                                         |    9 
 eims-ui/docs/src/guide/other/faq.md                                                                                                            |  159 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestBatchController.java                                               |   90 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java                                    |   80 
 eims-ui/apps/web-antd/src/components/tree/src/tree-select-panel.vue                                                                            |  217 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquBo.java                                                              |  148 
 eims-ui/playground/src/views/examples/vxe-table/basic.vue                                                                                      |   96 
 eims-ui/apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js                                                                      |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java                                                   |   15 
 eims-ui/apps/web-antd/src/api/core/captcha.ts                                                                                                  |   42 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/I18nConfig.java                                                 |   22 
 eims-ui/packages/effects/layouts/src/basic/README.md                                                                                           |    7 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java                                              |   26 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue                                                                 |  153 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java                                      |  174 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java                                            |   33 
 eims-ui/packages/@core/base/shared/src/utils/unique.ts                                                                                         |   15 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue                                                           |   37 
 eims/script/sql/update/oracle/update_5.1.1-5.1.2.sql                                                                                           |    6 
 eims-ui/apps/backend-mock/.nitro/dev/index.mjs                                                                                                 | 1333 
 eims-ui/apps/web-antd/src/views/_core/profile/mitt.ts                                                                                          |    7 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java                                                    |  115 
 eims-ui/apps/web-antd/src/views/system/user/user-info-modal.vue                                                                                |   56 
 eims-ui/docs/src/guide/essentials/development.md                                                                                               |  188 
 eims-ui/apps/web-antd/src/views/system/oss/data.tsx                                                                                            |   75 
 eims-ui/docs/src/guide/essentials/concept.md                                                                                                   |   70 
 eims-ui/packages/@core/base/shared/src/utils/date.ts                                                                                           |   26 
 eims-ui/docs/src/demos/vben-modal/extra/index.vue                                                                                              |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts                                                                                 |    4 
 eims-ui/playground/src/views/examples/modal/base-demo.vue                                                                                      |   26 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue                                                       |   57 
 eims-ui/docs/src/public/guide/loading.png                                                                                                      |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java                                                |   60 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css                                                                |    1 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java                                               |  323 
 eims-ui/packages/utils/src/helpers/unmount-global-loading.ts                                                                                   |   31 
 eims-ui/docs/src/demos/vben-drawer/auto-height/drawer.vue                                                                                      |   45 
 eims-ui/docs/src/en/guide/essentials/development.md                                                                                            |  188 
 eims-ui/packages/@core/base/typings/src/tabs.ts                                                                                                |    3 
 eims/ruoyi-admin/src/main/resources/i18n/messages.properties                                                                                   |   61 
 eims-ui/apps/web-ele/src/router/routes/modules/demos.ts                                                                                        |   38 
 eims-ui/playground/src/api/examples/table.ts                                                                                                   |   18 
 eims-ui/CHANGELOG.md                                                                                                                           |  114 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java                                            |   45 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue                                                                      |   11 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm                                                                     |   19 
 eims-ui/apps/web-naive/src/views/_core/authentication/forget-password.vue                                                                      |   42 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java                                          |   63 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestEncryptController.java                                             |   55 
 eims-ui/packages/effects/layouts/src/authentication/authentication.vue                                                                         |  156 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts                                                                        |  116 
 eims-ui/packages/@core/README.md                                                                                                               |    3 
 eims-ui/.editorconfig                                                                                                                          |   21 
 eims-ui/apps/web-antd/src/locales/index.ts                                                                                                     |  100 
 eims-ui/packages/effects/common-ui/src/components/code-mirror/code-mirror.vue                                                                  |   68 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.js                                                                          |    2 
 eims-ui/packages/@core/base/typings/src/app.d.ts                                                                                               |  106 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java                                                            |  131 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java                                            |   56 
 eims-ui/apps/web-antd/public/tinymce/plugins/pagebreak/plugin.min.js                                                                           |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue                                                                             |   13 
 eims-ui/packages/@core/ui-kit/popup-ui/package.json                                                                                            |   48 
 eims-ui/packages/locales/src/langs/en-US/authentication.json                                                                                   |   56 
 eims-ui/apps/web-antd/src/layouts/index.ts                                                                                                     |    6 
 eims-ui/apps/web-antd/src/utils/file/base64Conver.ts                                                                                           |   46 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java                                                 |  193 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java                                                  |   88 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue                                                          |   51 
 eims-ui/packages/styles/src/antd/index.css                                                                                                     |  110 
 eims-ui/docs/src/en/guide/introduction/roadmap.md                                                                                              |    3 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java                            |   48 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js                                                                         |   93 
 eims/ruoyi-modules/ruoyi-demo/pom.xml                                                                                                          |  108 
 eims/ruoyi-modules/ruoyi-job/pom.xml                                                                                                           |   34 
 eims-ui/apps/web-antd/src/views/_core/about/index.vue                                                                                          |    9 
 eims-ui/docs/src/components/common-ui/vben-drawer.md                                                                                           |  137 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java                                               |   26 
 eims-ui/apps/web-antd/src/api/system/oss-config/index.ts                                                                                       |   41 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue                                                                   |   26 
 eims/script/sql/postgres/flowable.sql                                                                                                          |  275 
 eims-ui/packages/locales/package.json                                                                                                          |   28 
 eims-ui/playground/src/views/_core/authentication/forget-password.vue                                                                          |   42 
 eims-ui/vitest.workspace.ts                                                                                                                    |    3 
 eims-ui/playground/src/layouts/basic.vue                                                                                                       |  158 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java                                                       |   71 
 eims-ui/apps/web-antd/src/api/system/dict/dict-type.ts                                                                                         |   84 
 eims-ui/internal/node-utils/src/__tests__/path.test.ts                                                                                         |   67 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestSensitiveController.java                                           |   76 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java                                                 |   40 
 eims/ruoyi-admin/src/main/resources/application-prod.yml                                                                                       |  263 
 eims-ui/apps/web-antd/public/tinymce/tinymce.d.ts                                                                                              | 3254 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue                                                                      |   24 
 eims-ui/packages/@core/preferences/src/config.ts                                                                                               |  116 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/banner.txt                                                                          |   11 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts                                                                        |    2 
 eims-ui/packages/@core/composables/src/use-is-mobile.ts                                                                                        |    7 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java                                                  |  221 
 eims-ui/internal/vite-config/src/plugins/importmap.ts                                                                                          |  245 
 eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java                             |   21 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts                                                                                    |  151 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue                                                               |   35 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java    |   29 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java                                           |  141 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java                                                  |  125 
 eims-ui/apps/web-antd/tsconfig.node.json                                                                                                       |   10 
 eims-ui/packages/@core/ui-kit/menu-ui/README.md                                                                                                |    1 
 eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue                                                                                     |  121 
 eims-ui/internal/node-utils/src/constants.ts                                                                                                   |    6 
 eims-ui/internal/node-utils/tsconfig.json                                                                                                      |    6 
 eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java                                            |  253 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java                                                        |   21 
 eims-ui/apps/web-antd/src/views/system/config/index.vue                                                                                        |  179 
 eims-ui/packages/@core/base/design/tsconfig.json                                                                                               |    6 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css                                                                     |    1 
 eims-ui/apps/web-naive/src/views/_core/fallback/forbidden.vue                                                                                  |    9 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java                            |  147 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/WeSocketController.java                                                |   33 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java                                        |   31 
 eims/script/bin/ry.sh                                                                                                                          |   86 
 eims-ui/apps/web-antd/src/views/system/role/role-drawer.vue                                                                                    |  137 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/index.vue                                                                                   |   90 
 eims-ui/playground/src/views/demos/features/new-window/index.vue                                                                               |   11 
 eims-ui/packages/effects/request/src/index.ts                                                                                                  |    3 
 eims-ui/packages/stores/src/modules/tabbar.ts                                                                                                  |  558 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue                                                            |   31 
 eims-ui/packages/stores/src/modules/tabbar.test.ts                                                                                             |  295 
 eims-ui/packages/effects/common-ui/src/components/markdown/preview.vue                                                                         |  107 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.js                                                                     |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue                                                                   |   33 
 eims-ui/apps/web-antd/src/views/monitor/cache/index.vue                                                                                        |  101 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue                                                                   |   20 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java                                                      |   94 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue                                                             |   39 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java                                         |   76 
 eims-ui/playground/src/views/examples/drawer/base-demo.vue                                                                                     |   24 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java                                           |  269 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java                                              |   47 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts                                                                             |    7 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantSaTokenDao.java                                       |  148 
 eims-ui/apps/web-antd/src/views/_core/profile/setting-panel.vue                                                                                |   59 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports   |    1 
 eims-ui/apps/web-antd/src/components/description/src/typing.ts                                                                                 |   47 
 eims-ui/apps/web-antd/src/components/tinymce/index.ts                                                                                          |    1 
 eims-ui/playground/playwright.config.ts                                                                                                        |  108 
 eims/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql                                                                                             | 3549 
 eims/script/docker/docker-compose.yml                                                                                                          |  156 
 eims-ui/internal/lint-configs/eslint-config/src/custom-config.ts                                                                               |  165 
 eims-ui/apps/web-naive/src/views/_core/about/index.vue                                                                                         |    9 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/index.ts                                                                                             |    3 
 eims-ui/docs/src/en/guide/essentials/icons.md                                                                                                  |   78 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue                                                                  |   71 
 eims-ui/apps/web-antd/vite.config.mts                                                                                                          |   46 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue                                                          |   45 
 eims-ui/apps/web-antd/src/adapter/vxe-table.ts                                                                                                 |  153 
 eims-ui/docs/src/demos/vben-drawer/extra/index.vue                                                                                             |   21 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java                                                       |   29 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java                                             |   73 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java                                                     |  169 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java                                              |   33 
 eims-ui/apps/web-antd/src/views/_core/fallback/forbidden.vue                                                                                   |    9 
 eims-ui/playground/src/views/_core/authentication/register.vue                                                                                 |   96 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java                                              |   30 
 eims-ui/packages/@core/ui-kit/shadcn-ui/tsconfig.json                                                                                          |   12 
 eims-ui/packages/effects/README.md                                                                                                             |   10 
 eims-ui/packages/types/global.d.ts                                                                                                             |   44 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java                                             |   47 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java                                    |  105 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports     |    1 
 eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.ts                                                                                 |   25 
 eims-ui/playground/src/api/core/auth.ts                                                                                                        |   51 
 eims-ui/apps/backend-mock/api/auth/codes.ts                                                                                                    |   14 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/util.test.ts                                                                            |  156 
 eims-ui/packages/effects/layouts/src/widgets/check-updates/index.ts                                                                            |    1 
 eims-ui/internal/lint-configs/prettier-config/package.json                                                                                     |   28 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue                                                                      |   11 
 eims-ui/playground/src/router/routes/index.ts                                                                                                  |   37 
 eims-ui/packages/effects/plugins/package.json                                                                                                  |   42 
 eims-ui/packages/effects/common-ui/src/components/markdown/editor.vue                                                                          |  136 
 eims-ui/packages/stores/src/modules/lock.ts                                                                                                    |   33 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java                                       |   28 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/tinymce/index.vue                                                                                     |   24 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java                                                |   87 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java                                    |   38 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java                                             |   52 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/.DS_Store                                                                                 |    0 
 eims-ui/docs/src/guide/in-depth/check-updates.md                                                                                               |   48 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java                     |  124 
 eims-ui/apps/web-ele/tsconfig.json                                                                                                             |   12 
 eims-ui/playground/src/views/_core/fallback/forbidden.vue                                                                                      |    9 
 eims-ui/apps/web-antd/src/views/_core/authentication/forget-password.vue                                                                       |   42 
 eims-ui/apps/web-naive/src/store/auth.ts                                                                                                       |  116 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java                                       |   73 
 eims-ui/apps/web-ele/src/locales/langs/zh-CN/demos.json                                                                                        |   13 
 eims-ui/packages/@core/base/shared/src/constants/vben.ts                                                                                       |   26 
 eims-ui/packages/styles/README.md                                                                                                              |   19 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java                                                 |   29 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts                                                                       |    1 
 eims-ui/apps/web-antd/src/api/workflow/category/index.ts                                                                                       |   50 
 eims-ui/docs/src/demos/vben-vxe-table/form/index.vue                                                                                           |  122 
 eims-ui/packages/@core/ui-kit/form-ui/build.config.ts                                                                                          |   21 
 eims/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports  |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue                                                           |   25 
 eims-ui/docs/src/en/guide/in-depth/check-updates.md                                                                                            |   48 
 eims-ui/docs/src/public/favicon.ico                                                                                                            |    0 
 eims-ui/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts                                                                              |  129 
 eims-ui/packages/utils/src/helpers/reset-routes.ts                                                                                             |   31 
 eims-ui/apps/web-antd/src/views/system/notice/index.vue                                                                                        |  150 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue                                                     |   19 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue                                                                              |   13 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue                                                                |   47 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java                                        |  372 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hr.js                                                                         |   93 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java                                    |   90 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java                                        |  157 
 eims-ui/docs/src/en/guide/project/vite.md                                                                                                      |   33 
 eims-ui/packages/@core/base/shared/src/constants/index.ts                                                                                      |    3 
 eims-ui/scripts/vsh/src/lint/index.ts                                                                                                          |   48 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java                                                      |  231 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java                                                |   80 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue                                                              |   38 
 eims-ui/packages/utils/README.md                                                                                                               |   19 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts                                                                    |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue                                                                               |   29 
 eims-ui/docs/src/components/common-ui/vben-vxe-table.md                                                                                        |  238 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java                                                          |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue                                                                               |   19 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/plugin.min.js                                                                                |    4 
 eims-ui/internal/node-utils/src/date.ts                                                                                                        |   12 
 eims-ui/docs/src/demos/vben-vxe-table/fixed/index.vue                                                                                          |   67 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java                                      |  140 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java                                               |  436 
 eims-ui/apps/web-antd/src/views/monitor/operlog/data.tsx                                                                                       |  199 
 eims-ui/apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js                                                                            |    4 
 eims-ui/apps/web-ele/src/router/routes/modules/vben.ts                                                                                         |   82 
 eims-ui/docs/src/guide/in-depth/features.md                                                                                                    |   84 
 eims-ui/playground/src/api/examples/index.ts                                                                                                   |    2 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/it.js                                                                         |   93 
 eims-ui/packages/@core/ui-kit/form-ui/package.json                                                                                             |   51 
 eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html                                                          |  107 
 eims-ui/playground/src/views/examples/vxe-table/custom-cell.vue                                                                                |  107 
 eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java                    |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts                                                                            |    2 
 eims-ui/playground/src/views/examples/doc-button.vue                                                                                           |   16 
 eims-ui/apps/web-antd/src/store/notify.ts                                                                                                      |  149 
 eims/.run/ruoyi-monitor-admin.run.xml                                                                                                          |   12 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java                                         |   56 
 eims-ui/playground/src/views/examples/modal/index.vue                                                                                          |  143 
 eims-ui/apps/web-antd/src/views/system/menu/menu-drawer.vue                                                                                    |  138 
 eims-ui/packages/effects/layouts/src/index.ts                                                                                                  |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java                                                       |   41 
 eims-ui/docs/src/guide/essentials/styles.md                                                                                                    |  106 
 eims-ui/scripts/vsh/src/check-dep/index.ts                                                                                                     |   85 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java                                  |  119 
 eims-ui/apps/web-antd/src/utils/dict.ts                                                                                                        |   64 
 eims/ruoyi-common/ruoyi-common-doc/pom.xml                                                                                                     |   41 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquTypeMapper.java                                                         |   15 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java                                                         |    1 
 eims-ui/playground/src/store/index.ts                                                                                                          |    1 
 eims/script/sql/postgres/postgres_ry_vue_5.X.sql                                                                                               | 1356 
 eims-ui/scripts/菜单图标替换sql/update_icon.sql                                                                                                      |   46 
 eims-ui/docs/src/guide/introduction/roadmap.md                                                                                                 |    3 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java                             |  142 
 eims-ui/apps/web-antd/public/tinymce/plugins/link/plugin.min.js                                                                                |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java                                                |   87 
 eims-ui/apps/web-naive/public/favicon.ico                                                                                                      |    0 
 eims-ui/apps/web-antd/src/views/system/role/data.tsx                                                                                           |  225 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java                            |   39 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml                                                             |   29 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java                                            |   14 
 eims-ui/apps/web-antd/src/views/system/client/secret-input.vue                                                                                 |   59 
 eims-ui/packages/effects/layouts/src/widgets/theme-toggle/index.ts                                                                             |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts                                                                      |    3 
 eims-ui/apps/web-antd/src/views/system/oss-config/oss-config-drawer.vue                                                                        |   90 
 eims-ui/packages/@core/ui-kit/tabs-ui/postcss.config.mjs                                                                                       |    1 
 eims-ui/apps/web-antd/public/tinymce/plugins/media/plugin.min.js                                                                               |    4 
 eims/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql                                                                                        |   19 
 eims-ui/playground/src/views/examples/modal/shared-data-demo.vue                                                                               |   29 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java                           |  117 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue                                                                               |   45 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java                                    |  115 
 eims-ui/apps/web-antd/src/components/tinymce/src/editor.vue                                                                                    |  370 
 eims-ui/packages/effects/hooks/tsconfig.json                                                                                                   |    9 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java                 |  181 
 eims-ui/packages/icons/src/svg/icons/cake.svg                                                                                                  |    1 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java                                                |  107 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java                                                     |   71 
 eims-ui/apps/web-antd/src/api/core/index.ts                                                                                                    |    4 
 eims-ui/apps/web-antd/src/api/core/user.ts                                                                                                     |   46 
 eims-ui/apps/web-antd/src/views/workflow/task/taskFinish.vue                                                                                   |    9 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java                                            |   14 
 eims-ui/playground/src/views/demos/nested/menu-3-2-1.vue                                                                                       |    7 
 eims-ui/docs/src/demos/vben-modal/shared-data/index.vue                                                                                        |   26 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts                                                                      |   30 
 eims-ui/apps/web-antd/src/adapter/form.ts                                                                                                      |   54 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue                                                          |   56 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts                                                                                   |    6 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue                                                                          |   13 
 eims-ui/playground/src/api/core/index.ts                                                                                                       |    3 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java                                   |  130 
 eims-ui/apps/web-antd/public/tinymce/plugins/preview/plugin.min.js                                                                             |    4 
 eims-ui/internal/node-utils/src/index.ts                                                                                                       |   19 
 eims-ui/playground/src/views/demos/features/vue-query/paginated-queries.vue                                                                    |   51 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java                                    |   31 
 eims-ui/apps/web-antd/public/tinymce/plugins/table/plugin.min.js                                                                               |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue                                                                            |   13 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml                                                                |   11 
 eims-ui/apps/web-antd/src/views/system/post/post-drawer.vue                                                                                    |  102 
 eims-ui/apps/web-antd/src/views/tool/gen/table-import-modal.vue                                                                                |  141 
 eims-ui/docs/src/public/guide/login.png                                                                                                        |    0 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts                                                              |    1 
 eims-ui/docs/.vitepress/theme/plugins/hm.ts                                                                                                    |   28 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java                                   |  110 
 eims-ui/apps/web-ele/src/locales/langs/zh-CN/page.json                                                                                         |   14 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java                                                     |   52 
 eims-ui/scripts/preview/9.png                                                                                                                  |    0 
 eims-ui/packages/@core/ui-kit/form-ui/src/config.ts                                                                                            |   84 
 eims-ui/docs/src/en/guide/in-depth/layout.md                                                                                                   |    1 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sl_SI.js                                                                      |   93 
 eims-ui/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts                                                               |   16 
 eims-ui/docs/src/en/guide/essentials/server.md                                                                                                 |  356 
 eims-ui/internal/lint-configs/eslint-config/src/configs/node.ts                                                                                |   57 
 eims-ui/apps/backend-mock/.nitro/types/nitro.d.ts                                                                                              |    3 
 eims-ui/packages/@core/base/icons/build.config.ts                                                                                              |    7 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml                                                                      |   34 
 eims-ui/packages/@core/base/shared/src/utils/to.ts                                                                                             |   21 
 eims-ui/docs/src/components/common-ui/vben-count-to-animator.md                                                                                |   52 
 eims-ui/apps/web-naive/src/views/_core/authentication/code-login.vue                                                                           |   64 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue                                                                               |   20 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java                                             |   18 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/Swagger3DemoController.java                                            |   31 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts                                                                        |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue                                                                             |   19 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts                                                                            |   38 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/pages/map.vue                                                                                   |  111 
 eims-ui/apps/web-naive/vite.config.mts                                                                                                         |   20 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java                                            |  160 
 eims-ui/apps/web-antd/src/api/system/dict/dict-type-model.d.ts                                                                                 |    8 
 eims-ui/packages/@core/composables/tsconfig.json                                                                                               |    6 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java                                        |   72 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java                                        |  311 
 eims-ui/docs/src/components/common-ui/vben-modal.md                                                                                            |  150 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue                                                                  |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue                                                                            |   18 
 eims-ui/apps/web-antd/src/views/monitor/cache/components/redis-description.vue                                                                 |  104 
 eims-ui/internal/lint-configs/eslint-config/src/configs/turbo.ts                                                                               |   18 
 eims-ui/docs/src/demos/vben-count-to-animator/custom/index.vue                                                                                 |   12 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/unique.test.ts                                                                          |   60 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java                                            |   93 
 eims-ui/apps/backend-mock/utils/jwt-utils.ts                                                                                                   |   59 
 eims-ui/internal/tsconfig/web.json                                                                                                             |   14 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java                                                                    |  246 
 eims-ui/apps/backend-mock/.nitro/types/nitro-config.d.ts                                                                                       |   16 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java                                 |  157 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java                                    |  100 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java                                                      |  116 
 eims-ui/apps/web-antd/public/tinymce/tinymce.min.js                                                                                            |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java                                                     |   46 
 eims-ui/docs/src/guide/in-depth/login.md                                                                                                       |  220 
 eims-ui/apps/web-antd/src/views/workflow/processDefinition/index.vue                                                                           |    9 
 eims-ui/apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js                                                                             |    4 
 eims-ui/internal/node-utils/src/path.ts                                                                                                        |   11 
 eims-ui/apps/web-antd/src/api/system/oss/model.d.ts                                                                                            |   28 
 eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java                                       |   33 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java                          |  122 
 eims-ui/apps/web-antd/src/views/workflow/components/rejection.png                                                                              |    0 
 eims-ui/packages/@core/base/shared/src/constants/globals.ts                                                                                    |   16 
 eims-ui/apps/web-antd/src/api/core/upload.ts                                                                                                   |   18 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/context.ts                                                                               |   24 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java                                                         |   77 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java                                                 |  168 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js                                                                         |   93 
 eims-ui/packages/effects/common-ui/src/components/ellipsis-text/index.ts                                                                       |    1 
 eims-ui/apps/web-naive/package.json                                                                                                            |   49 
 eims-ui/packages/effects/layouts/src/widgets/breadcrumb.vue                                                                                    |   72 
 eims-ui/internal/tsconfig/package.json                                                                                                         |   25 
 eims-ui/docs/src/guide/introduction/vben.md                                                                                                    |   49 
 eims-ui/playground/src/views/dashboard/workspace/index.vue                                                                                     |  266 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquMapper.xml                                                                     |    7 
 eims/ruoyi-admin/src/main/resources/application-dev.yml                                                                                        |  261 
 eims-ui/apps/web-antd/types/global-components.d.ts                                                                                             |    9 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue                                                          |   13 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java                                        |   45 
 eims-ui/apps/web-ele/src/api/request.ts                                                                                                        |  113 
 eims-ui/docs/src/en/guide/essentials/settings.md                                                                                               |  514 
 eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.js                                                                   |    2 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/index.ts                                                                                  |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts                                                                     |   17 
 eims-ui/apps/web-naive/.env.production                                                                                                         |   19 
 eims-ui/docs/tailwind.config.mjs                                                                                                               |   11 
 eims-ui/apps/web-antd/src/locales/langs/zh-CN/page.json                                                                                        |   18 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java                                       |   35 
 eims-ui/apps/web-antd/src/components/upload/src/file-upload.vue                                                                                |  216 
 eims-ui/apps/web-antd/src/api/eims/equ/index.ts                                                                                                |   61 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts                                                                           |   14 
 eims-ui/playground/src/views/demos/features/login-expired/index.vue                                                                            |   39 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquTypeService.java                                                      |   75 
 eims-ui/apps/web-antd/postcss.config.mjs                                                                                                       |    1 
 eims-ui/packages/@core/preferences/src/preferences.ts                                                                                          |  228 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java                                                 |   38 
 eims/script/sql/sqlserver/flowable.sql                                                                                                         |  456 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue                                                                    |   30 
 eims-ui/apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js                                                                            |    4 
 eims-ui/apps/web-antd/src/views/system/dict/type/dict-type-modal.vue                                                                           |   79 
 eims/ruoyi-common/ruoyi-common-sse/pom.xml                                                                                                     |   36 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java                                                            |   50 
 eims-ui/apps/web-antd/src/views/monitor/admin/index.vue                                                                                        |    6 
 eims-ui/packages/effects/access/src/directive.ts                                                                                               |   42 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java             |   18 
 eims-ui/apps/web-naive/src/router/routes/index.ts                                                                                              |   37 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java                                             |   64 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.js                                                                      |    2 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java                                                     |   33 
 eims-ui/playground/src/router/routes/core.ts                                                                                                   |   88 
 eims-ui/apps/web-antd/src/views/workflow/leave/index.vue                                                                                       |    9 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java                                                    |   59 
 eims-ui/apps/web-antd/.env.development                                                                                                         |   25 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java                                     |   20 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue                                                          |   19 
 eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java                                     |   42 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/helper.ts                                                                                |   60 
 eims-ui/packages/effects/common-ui/src/ui/authentication/types.ts                                                                              |  117 
 eims-ui/playground/src/views/dashboard/analytics/analytics-trends.vue                                                                          |  100 
 eims-ui/apps/web-antd/src/locales/langs/en-US/demos.json                                                                                       |   12 
 eims-ui/packages/effects/hooks/src/use-watermark.ts                                                                                            |   88 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue                                                                 |   15 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/types.ts                                                                                             |   64 
 eims-ui/apps/web-antd/src/api/system/dept/index.ts                                                                                             |   45 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java                                          |   48 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml                                                          |    7 
 eims-ui/apps/web-antd/src/views/system/post/index.vue                                                                                          |  187 
 eims-ui/docs/src/guide/project/dir.md                                                                                                          |   68 
 eims-ui/internal/lint-configs/eslint-config/src/configs/jsdoc.ts                                                                               |   34 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java                                                    |   73 
 eims-ui/apps/web-antd/public/favicon.ico                                                                                                       |    0 
 eims-ui/internal/tailwind-config/build.config.ts                                                                                               |   10 
 eims-ui/apps/web-antd/src/components/upload/src/helper.ts                                                                                      |   51 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java                                     |   31 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java                                          |  672 
 eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java                                                                        |   25 
 eims-ui/packages/@core/preferences/src/use-preferences.ts                                                                                      |  232 
 eims-ui/docs/.vitepress/theme/index.ts                                                                                                         |   29 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java                                      |  105 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java                                                        |  115 
 eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java                             |   29 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue                                                         |   29 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue                                                                   |   17 
 eims-ui/playground/src/views/examples/drawer/form-drawer-demo.vue                                                                              |   56 
 eims-ui/packages/preferences/src/index.ts                                                                                                      |   17 
 eims-ui/apps/web-naive/tailwind.config.mjs                                                                                                     |    1 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.js                                                                                 |    2 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue                                                             |   51 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue                                                                          |   11 
 eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java                                                                     |   31 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java                                      |   15 
 eims-ui/docs/src/public/logos/nitro.svg                                                                                                        |   42 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue                                                               |   38 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml                                                   |    7 
 eims-ui/internal/lint-configs/eslint-config/src/configs/prettier.ts                                                                            |   19 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue                                                          |   22 
 eims-ui/docs/src/demos/vben-modal/extra/modal.vue                                                                                              |    8 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue                                                                |   40 
 eims-ui/playground/src/views/demos/access/index.vue                                                                                            |   93 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue                                                   |   52 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue                                                                            |   31 
 eims-ui/playground/src/views/examples/vxe-table/virtual.vue                                                                                    |   66 
 eims-ui/apps/web-antd/src/locales/langs/en-US/menu.json                                                                                        |   55 
 eims-ui/packages/@core/preferences/tsconfig.json                                                                                               |    6 
 eims-ui/apps/backend-mock/api/test.post.ts                                                                                                     |    1 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java                                             |   63 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java                                          |  149 
 eims-ui/apps/web-antd/src/views/system/dept/data.ts                                                                                            |  146 
 eims-ui/packages/@core/base/typings/tsconfig.json                                                                                              |    6 
 eims-ui/docs/src/demos/vben-drawer/extra/drawer.vue                                                                                            |    8 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java                                             |   66 
 eims-ui/docs/src/public/guide/login-expired.png                                                                                                |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java                                                      |   75 
 eims-ui/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue                                                               |   56 
 eims-ui/apps/web-antd/public/tinymce/plugins/nonbreaking/plugin.min.js                                                                         |    4 
 eims-ui/docs/src/public/logos/shadcn-ui.svg                                                                                                    |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java                                                    |  144 
 eims-ui/internal/vite-config/src/plugins/vxe-table.ts                                                                                          |   20 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue                                                                    |   26 
 eims-ui/internal/vite-config/src/config/application.ts                                                                                         |  125 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue                                                               |   19 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml                                                              |    5 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.min.css                                                                               |    1 
 eims-ui/packages/@core/base/shared/src/utils/tree.ts                                                                                           |   97 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java                                             |   34 
 eims-ui/internal/lint-configs/eslint-config/src/configs/unicorn.ts                                                                             |   45 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java                                       |   82 
 eims-ui/docs/src/guide/introduction/quick-start.md                                                                                             |  111 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java                                |   51 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java                                                         |   51 
 eims-ui/apps/web-ele/src/store/index.ts                                                                                                        |    1 
 eims-ui/playground/tsconfig.json                                                                                                               |   12 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml                                                           |    7 
 eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue                                                                                |  356 
 eims-ui/internal/vite-config/src/plugins/inject-app-loading/README.md                                                                          |    3 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java                                         |  373 
 eims-ui/playground/src/views/examples/vxe-table/fixed.vue                                                                                      |   69 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js                                                                         |   93 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java                                                         |   26 
 eims-ui/packages/effects/common-ui/src/components/page/page.vue                                                                                |  123 
 eims/ruoyi-common/ruoyi-common-oss/pom.xml                                                                                                     |   71 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java                                        |   34 
 eims-ui/packages/effects/layouts/src/basic/copyright/copyright.vue                                                                             |   48 
 eims-ui/packages/effects/plugins/tsconfig.json                                                                                                 |    6 
 eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue                                                                |  423 
 eims-ui/apps/web-antd/src/components/cropper/src/cropper-modal.vue                                                                             |  373 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue                                                                          |   11 
 eims-ui/packages/effects/common-ui/tsconfig.json                                                                                               |    6 
 eims-ui/apps/web-ele/src/router/routes/core.ts                                                                                                 |   88 
 eims-ui/packages/constants/src/core.ts                                                                                                         |   29 
 eims-ui/apps/web-antd/src/views/system/user/user-import-modal.vue                                                                              |  108 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts                                                                           |    2 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java                                                   |   80 
 eims-ui/apps/web-antd/src/views/monitor/online/data.ts                                                                                         |   84 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java                        |  103 
 eims-ui/apps/web-ele/src/api/core/index.ts                                                                                                     |    3 
 eims/ruoyi-modules/lb-eims/src/main/resources/.DS_Store                                                                                        |    0 
 eims-ui/turbo.json                                                                                                                             |   49 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java                                         |   54 
 eims-ui/docs/src/en/guide/project/tailwindcss.md                                                                                               |   13 
 eims-ui/apps/web-antd/public/tinymce/plugins/importcss/plugin.min.js                                                                           |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java                                        |  151 
 eims-ui/apps/web-naive/src/api/core/auth.ts                                                                                                    |   51 
 eims/ruoyi-common/ruoyi-common-core/pom.xml                                                                                                    |   99 
 eims-ui/packages/styles/package.json                                                                                                           |   31 
 eims-ui/apps/web-antd/src/api/monitor/cache/index.ts                                                                                           |   24 
 eims-ui/internal/lint-configs/eslint-config/src/configs/perfectionist.ts                                                                       |  112 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java                                            |   54 
 eims-ui/apps/web-antd/src/views/system/oss/image-upload-modal.vue                                                                              |   51 
 eims-ui/playground/src/views/examples/modal/form-modal-demo.vue                                                                                |   78 
 eims-ui/scripts/turbo-run/package.json                                                                                                         |   29 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java                                                           |  115 
 eims/script/sql/update/oracle/update_5.1.0-5.1.1.sql                                                                                           |    5 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js                                                                         |   93 
 eims-ui/apps/web-antd/src/views/system/tenantPackage/tree-item.tsx                                                                             |   42 
 eims-ui/apps/web-ele/src/router/guard.ts                                                                                                       |  125 
 eims-ui/apps/web-antd/src/views/tool/gen/index.vue                                                                                             |  285 
 eims-ui/docs/src/en/guide/project/cli.md                                                                                                       |  106 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json                                                              |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts                                                                           |    1 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java                                        |   17 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java                                   |  172 
 eims-ui/playground/src/main.ts                                                                                                                 |   31 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java                           |   52 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java                                           |   28 
 eims-ui/packages/@core/base/icons/tsconfig.json                                                                                                |    6 
 eims-ui/packages/effects/request/src/request-client/index.ts                                                                                   |    3 
 eims-ui/docs/src/demos/vben-modal/shared-data/modal.vue                                                                                        |   26 
 eims-ui/apps/web-naive/src/views/_core/README.md                                                                                               |    3 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java                               |  139 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.js                                                                 |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue                                                                     |   11 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue                                                          |   37 
 eims-ui/docs/src/guide/introduction/why.md                                                                                                     |   23 
 eims-ui/packages/@core/ui-kit/tabs-ui/build.config.ts                                                                                          |   21 
 eims-ui/apps/web-antd/src/locales/langs/zh-CN/menu.json                                                                                        |   55 
 eims-ui/docs/src/demos/vben-drawer/shared-data/drawer.vue                                                                                      |   26 
 eims-ui/internal/lint-configs/eslint-config/src/util.ts                                                                                        |    8 
 eims-ui/packages/@core/ui-kit/form-ui/src/vben-use-form.vue                                                                                    |  113 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue                                                               |   16 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts                                                                         |    1 
 eims-ui/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue                                                                      |   94 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm                                                                        |   64 
 eims/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java                                                                 |   32 
 eims-ui/playground/.env.analyze                                                                                                                |    7 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatedlyRequestWrapper.java                                   |   68 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java                                            |  156 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ro.js                                                                         |   93 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue                                                                        |  117 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts                                                                                  |    1 
 eims-ui/packages/icons/src/svg/icons/message.svg                                                                                               |    1 
 eims-ui/playground/src/views/examples/form/custom.vue                                                                                          |   75 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java                        |   32 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java                                          |  100 
 eims-ui/apps/web-antd/src/utils/file/download.ts                                                                                               |  262 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue                                                             |   46 
 eims-ui/apps/backend-mock/middleware/1.api.ts                                                                                                  |    7 
 eims-ui/apps/web-antd/src/views/demo/demo/api/model.d.ts                                                                                       |   82 
 eims-ui/docs/src/guide/essentials/external-module.md                                                                                           |   58 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java                                                       |   18 
 eims-ui/apps/web-antd/src/router/routes/modules/demos.ts                                                                                       |   30 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml                                                      |    7 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java                                       |  110 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue                                                                   |   19 
 eims-ui/packages/@core/ui-kit/form-ui/src/vben-form.vue                                                                                        |   77 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java                                                       |   62 
 eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java                                                                          |   54 
 eims-ui/packages/@core/ui-kit/menu-ui/package.json                                                                                             |   48 
 eims-ui/playground/src/router/guard.ts                                                                                                         |  123 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java                                              |  548 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java                                  |   75 
 eims-ui/apps/web-antd/src/api/system/social/model.d.ts                                                                                         |   26 
 eims-ui/apps/web-ele/src/views/_core/authentication/code-login.vue                                                                             |   64 
 eims-ui/internal/node-utils/src/prettier.ts                                                                                                    |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue                                                                    |   48 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.js                                                                               |    2 
 eims-ui/apps/web-ele/src/views/_core/authentication/register.vue                                                                               |   95 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java                                          |  337 
 eims-ui/packages/constants/package.json                                                                                                        |   25 
 eims-ui/apps/web-antd/src/views/system/dict/mitt.ts                                                                                            |   10 
 eims-ui/apps/web-antd/src/views/system/dict/type/index.vue                                                                                     |  197 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/changelog/index.vue                                                                                   |   24 
 eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java                          |  146 
 eims-ui/apps/web-antd/src/views/eims/equ-detail/index.vue                                                                                      |  141 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java                                                |  147 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue                                                    |   66 
 eims-ui/packages/stores/src/setup.ts                                                                                                           |   43 
 eims-ui/apps/web-antd/src/views/system/config/config-modal.vue                                                                                 |   78 
 eims-ui/apps/web-antd/src/api/index.ts                                                                                                         |    1 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java                                              |   52 
 eims-ui/packages/@core/ui-kit/README.md                                                                                                        |    3 
 eims/ruoyi-common/ruoyi-common-idempotent/pom.xml                                                                                              |   41 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java                                                |   53 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue                                                                          |  154 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java                                       |   65 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java                                                      |   76 
 eims-ui/apps/web-antd/src/layouts/auth.vue                                                                                                     |   23 
 eims-ui/packages/@core/base/shared/src/utils/inference.ts                                                                                      |  164 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java                                                |   76 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/TranslationType.java                        |   23 
 eims-ui/apps/web-antd/src/router/routes/modules/vben.ts                                                                                        |   81 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java                         |   70 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java                                    |   30 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java                                                |   16 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_TW.js                                                                      |   93 
 eims-ui/apps/web-antd/src/views/_core/profile/components/secure-setting.vue                                                                    |  106 
 eims-ui/packages/@core/ui-kit/menu-ui/build.config.ts                                                                                          |   26 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/index.ts                                                                                   |    3 
 eims-ui/apps/web-antd/src/views/system/user/data.tsx                                                                                           |  206 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java                                             |   58 
 eims-ui/internal/lint-configs/eslint-config/src/configs/test.ts                                                                                |   45 
 eims-ui/playground/src/views/demos/features/vue-query/index.vue                                                                                |   25 
 eims-ui/packages/@core/preferences/__tests__/preferences.test.ts                                                                               |  253 
 eims-ui/packages/locales/src/typing.ts                                                                                                         |   25 
 eims/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports        |    1 
 eims-ui/apps/web-naive/src/router/guard.ts                                                                                                     |  124 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/upload/index.vue                                                                                      |   64 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sv_SE.js                                                                      |   93 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java                                                 |   14 
 eims-ui/apps/web-ele/src/adapter/component/index.ts                                                                                            |  234 
 eims-ui/docs/src/en/guide/other/remove-code.md                                                                                                 |   18 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue                                                               |   32 
 eims-ui/apps/web-antd/src/views/system/role-assign/index.vue                                                                                   |  154 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue                                                                |   50 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml                                                         |    7 
 eims-ui/packages/@core/ui-kit/popup-ui/postcss.config.mjs                                                                                      |    1 
 eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.vue                                                                                    |  596 
 eims-ui/docs/src/_env/adapter/component.ts                                                                                                     |  127 
 eims-ui/apps/web-antd/src/views/eims/equ/data.tsx                                                                                              |  389 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java                                           |   33 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue                                                                      |   50 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestTreeBo.java                                                         |   54 
 eims-ui/docs/.vitepress/config/en.mts                                                                                                          |  229 
 eims-ui/.prettierrc                                                                                                                            |   20 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-gen.vue                                                                                          |   62 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java                                                     |   82 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java                                                     |  173 
 eims-ui/docs/src/commercial/community.md                                                                                                       |   30 
 eims/script/sql/sqlserver/snail_job_sqlserver.sql                                                                                              | 2745 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/sse/index.vue                                                                                         |  100 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java                                               |   34 
 eims-ui/packages/effects/layouts/src/basic/menu/use-extra-menu.ts                                                                              |  109 
 eims-ui/scripts/preview/6.png                                                                                                                  |    0 
 eims/ruoyi-common/ruoyi-common-sms/pom.xml                                                                                                     |   33 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java                            |   41 
 eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.js                                                                           |    2 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java                                         |   78 
 eims-ui/packages/effects/common-ui/src/ui/authentication/login.vue                                                                             |  186 
 eims-ui/apps/web-antd/src/api/monitor/logininfo/index.ts                                                                                       |   60 
 eims-ui/packages/@core/preferences/src/update-css-variables.ts                                                                                 |  116 
 eims-ui/packages/@core/preferences/src/index.ts                                                                                                |   35 
 eims-ui/apps/web-antd/src/views/_core/fallback/coming-soon.vue                                                                                 |    7 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue                                                               |   63 
 eims-ui/playground/src/views/examples/vxe-table/remote.vue                                                                                     |   74 
 eims-ui/apps/web-ele/package.json                                                                                                              |   53 
 eims/script/sql/oracle/oracle_ry_vue_5.X.sql                                                                                                   | 1364 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java                                             |  116 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css                                                                 |    1 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue                                                               |  161 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java                                     |   51 
 eims-ui/apps/web-antd/src/components/upload/index.ts                                                                                           |    2 
 eims-ui/packages/effects/hooks/src/index.ts                                                                                                    |    8 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue                                                                          |   11 
 eims-ui/apps/web-naive/src/adapter/naive.ts                                                                                                    |   25 
 eims-ui/packages/icons/src/svg/icons/system.svg                                                                                                |    1 
 eims-ui/scripts/vsh/src/check-circular/index.ts                                                                                                |   80 
 eims-ui/apps/web-naive/.env.development                                                                                                        |   16 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts                                                                 |    1 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue                                                              |   45 
 eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue                                                                                        |  169 
 eims-ui/playground/src/views/dashboard/analytics/analytics-visits.vue                                                                          |   57 
 eims-ui/packages/effects/layouts/src/widgets/global-search/global-search.vue                                                                   |  156 
 eims-ui/apps/web-antd/src/api/system/user/model.d.ts                                                                                           |  116 
 eims-ui/playground/src/adapter/vxe-table.ts                                                                                                    |   68 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue                                                                           |   32 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java                                             |   75 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue                                                                      |   52 
 eims-ui/apps/web-naive/src/locales/README.md                                                                                                   |    3 
 eims-ui/packages/locales/src/langs/en-US/common.json                                                                                           |   13 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java                                   |  132 
 eims/ruoyi-modules/.DS_Store                                                                                                                   |    0 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue                                                                      |   57 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml                                              |    7 
 eims-ui/apps/web-antd/src/views/system/oss/file-upload-modal.vue                                                                               |   51 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue                                                   |   31 
 eims-ui/packages/@core/base/design/src/design-tokens/default.css                                                                               |  379 
 eims-ui/docs/src/components/common-ui/vben-form.md                                                                                             |  524 
 eims/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    1 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java                                     |   40 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue                                                                                   |   20 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java                                               |   15 
 eims-ui/apps/web-antd/src/components/description/index.ts                                                                                      |    3 
 eims-ui/apps/web-ele/src/views/demos/element/index.vue                                                                                         |  117 
 eims-ui/apps/backend-mock/tsconfig.json                                                                                                        |    3 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java                                                    |  595 
 eims-ui/packages/effects/layouts/src/authentication/icons/slogan.vue                                                                           | 4568 
 eims-ui/internal/vite-config/src/config/index.ts                                                                                               |   37 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml                                                             |   36 
 eims-ui/vitest.config.ts                                                                                                                       |   11 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java                 |   29 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java                     |  120 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisRateLimiterController.java                                        |   64 
 eims-ui/playground/src/views/examples/drawer/shared-data-demo.vue                                                                              |   29 
 eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java                                                                   |    1 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java                                          |   94 
 eims/script/sql/flowable.sql                                                                                                                   |  176 
 eims-ui/apps/web-antd/src/utils/modal.tsx                                                                                                      |   63 
 eims-ui/docs/src/demos/vben-count-to-animator/basic/index.vue                                                                                  |    6 
 eims-ui/packages/icons/tsconfig.json                                                                                                           |    6 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml                                                    |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue                                                             |   20 
 eims-ui/apps/web-ele/src/locales/langs/en-US/page.json                                                                                         |   14 
 eims-ui/packages/effects/hooks/src/use-content-maximize.ts                                                                                     |   24 
 eims-ui/packages/@core/ui-kit/tabs-ui/tsconfig.json                                                                                            |    6 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java                                              |   52 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java                                         |   48 
 eims-ui/docs/src/index.md                                                                                                                      |  108 
 eims-ui/packages/types/src/index.ts                                                                                                            |    2 
 eims-ui/apps/web-antd/index.html                                                                                                               |   22 
 eims-ui/packages/constants/tsconfig.json                                                                                                       |    6 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts                                                              |   32 
 eims-ui/apps/web-antd/src/views/demo/tree/data.ts                                                                                              |  107 
 eims-ui/packages/@core/base/shared/src/color/convert.ts                                                                                        |   62 
 eims-ui/docs/src/demos/vben-modal/dynamic/modal.vue                                                                                            |   38 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue                                                                      |   22 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |    1 
 eims-ui/packages/utils/tsconfig.json                                                                                                           |    9 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java                                    |   74 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm                                                                       |   66 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java                                          |   43 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue                                                                       |  100 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml                                                         |   78 
 eims-ui/packages/icons/src/svg/load.ts                                                                                                         |   61 
 eims-ui/apps/web-antd/package.json                                                                                                             |   63 
 eims-ui/docs/src/en/guide/introduction/why.md                                                                                                  |    9 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue                                                                                   |  251 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue                                                             |   28 
 eims-ui/playground/src/views/demos/features/tabs/index.vue                                                                                     |  105 
 eims-ui/apps/web-antd/src/api/system/client/index.ts                                                                                           |   41 
 eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts                                                                                 |   45 
 eims-ui/packages/@core/ui-kit/form-ui/src/index.ts                                                                                             |   12 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java                                                     |  289 
 eims-ui/playground/src/views/examples/ellipsis/index.vue                                                                                       |   41 
 eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java                                                  |   19 
 eims/script/sql/update/postgres/update_5.1.1-5.1.2.sql                                                                                         |    5 
 eims-ui/.env.development                                                                                                                       |   32 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java                                                         |   51 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java                                  |  123 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquServiceImpl.java                                                  |  188 
 eims-ui/apps/backend-mock/.env                                                                                                                 |    3 
 eims-ui/packages/effects/common-ui/package.json                                                                                                |   54 
 eims-ui/packages/effects/layouts/src/widgets/notification/index.ts                                                                             |    3 
 eims-ui/apps/web-antd/src/locales/langs/zh-CN/demos.json                                                                                       |   12 
 eims-ui/packages/types/src/user.ts                                                                                                             |   11 
 eims-ui/internal/lint-configs/eslint-config/package.json                                                                                       |   56 
 eims-ui/apps/web-antd/public/tinymce/themes/silver/theme.min.js                                                                                |    4 
 eims-ui/apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue                                                                          |  127 
 eims-ui/scripts/turbo-run/bin/turbo-run.mjs                                                                                                    |    3 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.min.css                                                                          |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java                                            |   47 
 eims-ui/apps/web-antd/src/views/system/user/index.vue                                                                                          |  299 
 eims-ui/docs/src/demos/vben-modal/basic/index.vue                                                                                              |   11 
 eims-ui/packages/effects/layouts/src/basic/header/header.vue                                                                                   |  168 
 eims-ui/packages/effects/hooks/src/use-design-tokens.ts                                                                                        |  280 
 eims-ui/apps/web-ele/src/app.vue                                                                                                               |   17 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java                                                      |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts                                                                                  |   23 
 eims-ui/apps/web-antd/src/api/core/menu.ts                                                                                                     |   45 
 eims-ui/apps/web-antd/src/views/system/tenant/index.vue                                                                                        |  236 
 eims-ui/apps/web-antd/tsconfig.json                                                                                                            |   12 
 eims-ui/scripts/clean.mjs                                                                                                                      |   53 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java                               |  148 
 eims/script/docker/redis/conf/redis.conf                                                                                                       |   28 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js                                                                         |   93 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java                                        |   40 
 eims-ui/packages/effects/hooks/README.md                                                                                                       |   19 
 eims-ui/scripts/preview/4.png                                                                                                                  |    0 
 eims/ruoyi-modules/pom.xml                                                                                                                     |   28 
 eims-ui/internal/lint-configs/eslint-config/src/configs/vue.ts                                                                                 |  150 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java                                      |  106 
 eims-ui/playground/src/adapter/form.ts                                                                                                         |   45 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue                                                                   |   19 
 eims/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties                                                                             |   61 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java                                            |   61 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml                                                             |   73 
 eims-ui/docs/src/en/guide/essentials/styles.md                                                                                                 |  106 
 eims-ui/docs/src/demos/vben-drawer/auto-height/index.vue                                                                                       |   21 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java                                      |   56 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/enums/LimitType.java                                   |   24 
 eims-ui/packages/@core/base/design/src/design-tokens/dark.css                                                                                  |  442 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue                                                        |   37 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue                                                                                        |   95 
 eims/script/bin/ry.bat                                                                                                                         |   68 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue                                                       |   50 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java                                                 |   17 
 eims-ui/apps/web-antd/src/store/tenant.ts                                                                                                      |   45 
 eims-ui/packages/effects/access/package.json                                                                                                   |   29 
 eims-ui/apps/web-antd/src/views/_core/authentication/qrcode-login.vue                                                                          |   10 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/index.ts                                                                  |    1 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquVo.java                                                              |  201 
 eims-ui/apps/web-antd/src/views/workflow/processInstance/index.vue                                                                             |    9 
 eims-ui/apps/web-ele/src/adapter/form.ts                                                                                                       |   39 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml                                                        |    7 
 eims-ui/packages/@core/ui-kit/form-ui/src/use-vben-form.ts                                                                                     |   50 
 eims-ui/packages/stores/package.json                                                                                                           |   30 
 eims-ui/packages/locales/src/langs/zh-CN/preferences.json                                                                                      |  169 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java                                                    |   80 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java                                           |   51 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java                                            |   35 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java                                 |  111 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/th_TH.js                                                                      |   93 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue                                                                |   31 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm                                                                  |   72 
 eims-ui/playground/src/views/demos/nested/menu-1.vue                                                                                           |    7 
 eims-ui/apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js                                                                              |    4 
 eims-ui/internal/vite-config/src/plugins/nitro-mock.ts                                                                                         |   98 
 eims-ui/playground/src/views/demos/breadcrumb/lateral-detail.vue                                                                               |   21 
 eims-ui/playground/index.html                                                                                                                  |   35 
 eims-ui/apps/web-antd/src/views/monitor/snailjob/index.vue                                                                                     |    3 
 eims-ui/apps/web-antd/src/views/_core/profile/components/online-device.vue                                                                     |   49 
 eims-ui/playground/src/views/examples/drawer/in-content-demo.vue                                                                               |   21 
 eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-button.vue                                                                |   19 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java                                     |   77 
 eims-ui/apps/web-naive/tsconfig.node.json                                                                                                      |   10 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java                                                  |   37 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form.vue                                                                                 |  160 
 eims-ui/packages/@core/ui-kit/form-ui/tsconfig.json                                                                                            |    6 
 eims-ui/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts                                                            |   19 
 eims-ui/docs/src/demos/vben-vxe-table/virtual/index.vue                                                                                        |   64 
 eims-ui/packages/@core/base/shared/src/utils/update-css-variables.ts                                                                           |   35 
 eims-ui/apps/web-antd/src/views/demos/antd/index.vue                                                                                           |   66 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/package-info.java                                                    |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java                                     |  176 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm                                                                  |   19 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.ts                                                                                      |  175 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue                                                 |  111 
 eims-ui/packages/stores/tsconfig.json                                                                                                          |    5 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java                                                |   61 
 eims-ui/apps/web-antd/src/views/tool/gen/mitt.ts                                                                                               |   15 
 eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java                                |   69 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java                                   |   61 
 eims-ui/apps/web-ele/src/locales/index.ts                                                                                                      |  100 
 eims/ruoyi-common/ruoyi-common-redis/pom.xml                                                                                                   |   47 
 eims-ui/packages/effects/common-ui/src/ui/about/about.vue                                                                                      |  182 
 eims-ui/playground/src/locales/index.ts                                                                                                        |  100 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java                                      |   50 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts                                                                                |  105 
 eims-ui/docs/src/en/guide/in-depth/features.md                                                                                                 |   84 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml                                                                     |   39 
 eims-ui/packages/effects/common-ui/src/ui/authentication/forget-password.vue                                                                   |  115 
 eims-ui/playground/src/locales/langs/en-US/page.json                                                                                           |   14 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js                                                                 |    2 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java                                 |   37 
 eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js                                                                        |    2 
 eims-ui/packages/effects/common-ui/src/components/icon-picker/index.ts                                                                         |    1 
 eims/script/docker/redis/data/README.md                                                                                                        |    1 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java                          |  135 
 eims-ui/packages/stores/shim-pinia.d.ts                                                                                                        |    9 
 eims-ui/apps/web-naive/postcss.config.mjs                                                                                                      |    1 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/index.vue                                                                                  |   90 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts                                                                      |    2 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java                               |   55 
 eims-ui/apps/web-naive/src/preferences.ts                                                                                                      |   13 
 eims/script/sql/ry_vue_5.X.sql                                                                                                                 |  935 
 eims-ui/packages/stores/src/modules/access.ts                                                                                                  |   85 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue                                                                     |  116 
 eims-ui/apps/web-antd/src/api/system/menu/index.ts                                                                                             |   61 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java                                                 |  341 
 eims-ui/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue                                                                   |  227 
 eims-ui/internal/vite-config/src/plugins/license.ts                                                                                            |   63 
 eims-ui/docs/src/demos/vben-modal/auto-height/index.vue                                                                                        |   21 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquTypeServiceImpl.java                                              |  205 
 eims-ui/apps/web-antd/src/views/monitor/cache/components/command-chart.vue                                                                     |   75 
 eims-ui/apps/web-antd/src/views/workflow/category/data.ts                                                                                      |   75 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue                                                           |   37 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java                                    |  137 
 eims-ui/apps/web-ele/index.html                                                                                                                |   35 
 eims-ui/apps/web-ele/src/views/_core/about/index.vue                                                                                           |    9 
 eims/script/docker/database.yml                                                                                                                |   61 
 eims/ruoyi-admin/src/main/resources/banner.txt                                                                                                 |    8 
 eims-ui/packages/effects/common-ui/src/index.ts                                                                                                |    2 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java                  |   75 
 eims-ui/internal/vite-config/src/plugins/index.ts                                                                                              |  247 
 eims-ui/internal/vite-config/src/plugins/print.ts                                                                                              |   28 
 eims-ui/playground/src/views/examples/drawer/auto-height-demo.vue                                                                              |   47 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java                                                               |  102 
 eims-ui/apps/web-antd/src/views/workflow/formManage/index.vue                                                                                  |    9 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml                                                       |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts                                                                          |   16 
 eims-ui/playground/.env.development                                                                                                            |   16 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java                                       |  146 
 eims-ui/docs/src/demos/vben-drawer/dynamic/drawer.vue                                                                                          |   26 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts                                                            |   30 
 eims-ui/playground/src/views/demos/features/file-download/index.vue                                                                            |   74 
 eims-ui/packages/effects/layouts/src/basic/menu/mixed-menu.vue                                                                                 |   44 
 eims-ui/playground/src/views/examples/vxe-table/edit-cell.vue                                                                                  |   57 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java                                                    |   48 
 eims-ui/packages/utils/src/helpers/safe.ts                                                                                                     |   10 
 eims-ui/packages/icons/README.md                                                                                                               |   19 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java                                          |  142 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java                                                    |   90 
 eims-ui/internal/lint-configs/eslint-config/src/index.ts                                                                                       |   60 
 eims-ui/docs/src/en/guide/project/test.md                                                                                                      |   33 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue                                                                           |   15 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue                                                         |   49 
 eims-ui/apps/web-ele/src/api/index.ts                                                                                                          |    1 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java                         |  111 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue                                                                  |   48 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue                                                                  |   39 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java                                      |  229 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java                                                    |   48 
 eims/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql                                                                                        |   29 
 eims-ui/playground/src/views/dashboard/analytics/analytics-visits-data.vue                                                                     |   84 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts                                                                        |    2 
 eims-ui/apps/web-antd/public/tinymce/icons/default/icons.min.js                                                                                |    1 
 eims-ui/apps/web-antd/types/directive.d.ts                                                                                                     |   12 
 eims-ui/apps/web-naive/src/views/_core/fallback/internal-error.vue                                                                             |    9 
 eims-ui/packages/icons/src/svg/icons/avatar-2.svg                                                                                              |    1 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java                                     |  104 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic-setting.vue                                                                          |  143 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/input-captcha.vue                                                         |   58 
 eims-ui/playground/src/bootstrap.ts                                                                                                            |   52 
 eims/ruoyi-common/pom.xml                                                                                                                      |   46 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java                                           |   18 
 eims-ui/apps/web-antd/src/preferences.ts                                                                                                       |   70 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquTypeController.java                                                 |  124 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java                                                 |   28 
 eims-ui/scripts/deploy/build-local-docker-image.sh                                                                                             |   55 
 eims-ui/packages/effects/layouts/src/widgets/user-dropdown/index.ts                                                                            |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue                                                                          |   21 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java                          |   83 
 eims-ui/.prettierignore                                                                                                                        |    9 
 eims-ui/apps/web-ele/src/views/_core/authentication/qrcode-login.vue                                                                           |   10 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java                                                       |   72 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/index.ts                                                                       |   19 
 eims-ui/scripts/preview/2.png                                                                                                                  |    0 
 eims/script/sql/update/update_5.1.0-5.1.1.sql                                                                                                  |    3 
 eims-ui/packages/effects/layouts/src/widgets/global-search/index.ts                                                                            |    1 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/index.ts                                                                                |    5 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml                                                                |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts                                                                         |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue                                                                               |   30 
 eims-ui/apps/web-antd/src/views/_core/profile/components/base-setting.vue                                                                      |  120 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue                                                           |   44 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js                                                                         |   93 
 eims-ui/apps/web-antd/src/views/demo/tree/index.vue                                                                                            |  144 
 eims-ui/apps/web-antd/public/tinymce/plugins/save/plugin.min.js                                                                                |    4 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestTreeVo.java                                                         |   64 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java                                        |  124 
 eims-ui/playground/src/views/demos/features/clipboard/index.vue                                                                                |   25 
 eims-ui/playground/package.json                                                                                                                |   54 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java                                                 |   97 
 eims-ui/packages/@core/ui-kit/menu-ui/src/index.ts                                                                                             |    3 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/index.ts                                                                                  |    2 
 eims-ui/apps/web-naive/src/locales/index.ts                                                                                                    |   38 
 eims-ui/playground/src/views/_core/README.md                                                                                                   |    3 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java                                               |   53 
 eims-ui/docs/src/demos/vben-form/api/index.vue                                                                                                 |  236 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java                                    |  114 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm                                                                   |   15 
 eims-ui/apps/web-antd/src/main.ts                                                                                                              |   31 
 eims-ui/docs/src/guide/project/changeset.md                                                                                                    |   21 
 eims-ui/apps/web-antd/src/views/workflow/category/category-modal.vue                                                                           |  126 
 eims-ui/packages/@core/composables/src/use-simple-locale/messages.ts                                                                           |   22 
 eims-ui/apps/web-antd/src/components/upload/src/typing.ts                                                                                      |   37 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nb_NO.js                                                                      |   93 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue                                                                           |  346 
 eims-ui/README.md                                                                                                                              |  152 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue                                                                          |    9 
 eims-ui/apps/web-antd/src/router/routes/local.ts                                                                                               |  224 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java                         |  444 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue                                                                |   46 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java                                                              |   68 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue                                                                            |   11 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityDemo.java                                                |   22 
 eims-ui/internal/lint-configs/eslint-config/src/configs/disableds.ts                                                                           |   28 
 eims-ui/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts                                                                                |  220 
 eims-ui/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs                                                                                      |    1 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java                                               |  283 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java                                             |   35 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/dto/WebSocketMessageDto.java                               |   29 
 eims-ui/packages/locales/src/langs/zh-CN/ui.json                                                                                               |   82 
 eims-ui/apps/web-naive/src/views/dashboard/workspace/index.vue                                                                                 |  266 
 eims-ui/apps/web-antd/src/views/workflow/components/approval-timeline.vue                                                                      |   50 
 eims-ui/packages/effects/layouts/src/widgets/preferences/index.ts                                                                              |    3 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java                                              |  237 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java                              |   23 
 eims-ui/docs/src/en/guide/introduction/changelog.md                                                                                            |    3 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java                                    |   35 
 eims-ui/apps/web-antd/src/locales/langs/zh-CN/pages.json                                                                                       |   23 
 eims-ui/docs/src/en/guide/project/standard.md                                                                                                  |  165 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/pages/browser.vue                                                                               |   62 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java                                                         |  104 
 eims-ui/playground/src/views/demos/features/vue-query/query-retries.vue                                                                        |   34 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestTree.java                                                              |   65 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java                                              |   42 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml                                                                |   50 
 eims-ui/packages/effects/access/src/index.ts                                                                                                   |    4 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css                                                            |    1 
 eims-ui/internal/node-utils/src/fs.ts                                                                                                          |   39 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.js                                                                             |    2 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java                                             |   67 
 eims-ui/playground/src/views/demos/access/super-visible.vue                                                                                    |   11 
 eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.vue                                                                                |  163 
 eims-ui/packages/effects/request/src/request-client/modules/downloader.ts                                                                      |   31 
 eims/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java                                             |   37 
 eims-ui/packages/@core/base/shared/src/utils/index.ts                                                                                          |   19 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue                                                                   |  161 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue                                                                     |  125 
 eims-ui/apps/web-antd/src/api/monitor/operlog/model.d.ts                                                                                       |   21 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java                                              |   29 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java                                     |  158 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java                        | 1120 
 eims-ui/playground/src/locales/langs/en-US/examples.json                                                                                       |   60 
 eims-ui/playground/src/views/_core/about/index.vue                                                                                             |    9 
 eims-ui/packages/icons/src/icons/empty-icon.vue                                                                                                |   27 
 eims-ui/apps/web-ele/src/router/index.ts                                                                                                       |   37 
 eims-ui/packages/effects/layouts/src/basic/header/index.ts                                                                                     |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/index.ts                                                                                |   24 
 eims/script/docker/nginx/conf/nginx.conf                                                                                                       |  115 
 eims-ui/playground/.env                                                                                                                        |    5 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java                                               |   56 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java                                     |   19 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java                                             |   63 
 eims-ui/packages/@core/base/typings/src/basic.d.ts                                                                                             |   39 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.js                                                                                |    2 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java                           |   46 
 eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/index.ts                                                                                       |    2 
 eims-ui/apps/backend-mock/error.ts                                                                                                             |    7 
 eims-ui/apps/web-naive/src/bootstrap.ts                                                                                                        |   46 
 eims-ui/apps/web-naive/src/layouts/index.ts                                                                                                    |    6 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.js                                                                          |    2 
 eims-ui/apps/web-antd/src/api/monitor/operlog/index.ts                                                                                         |   31 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue                                                                |   48 
 eims-ui/packages/effects/common-ui/src/components/json-preview/index.ts                                                                        |    1 
 eims-ui/playground/src/views/_core/authentication/qrcode-login.vue                                                                             |   10 
 eims-ui/apps/web-antd/src/api/system/notice/index.ts                                                                                           |   30 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml                                                      |   42 
 eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java                                            |  126 
 eims-ui/apps/web-antd/src/views/system/notice/notice-modal.vue                                                                                 |   78 
 eims-ui/apps/web-naive/src/views/_core/authentication/qrcode-login.vue                                                                         |   10 
 eims-ui/internal/lint-configs/prettier-config/index.mjs                                                                                        |   18 
 eims-ui/docs/src/en/guide/essentials/concept.md                                                                                                |   70 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java                          |   24 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java                                              |  161 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java                                |  348 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java                                                  |   59 
 eims-ui/packages/effects/plugins/src/echarts/echarts-ui.vue                                                                                    |   15 
 eims-ui/apps/web-ele/src/views/dashboard/workspace/index.vue                                                                                   |  266 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java                                          |   26 
 eims-ui/packages/effects/layouts/src/widgets/notification/notification.vue                                                                     |  186 
 eims-ui/internal/vite-config/tsconfig.json                                                                                                     |    6 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/typing.ts                                                                                  |   48 
 eims-ui/apps/web-antd/src/views/_core/profile/profile-panel.vue                                                                                |   84 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java                                    |  159 
 eims-ui/playground/src/views/_core/authentication/code-login.vue                                                                               |   65 
 eims-ui/playground/src/views/_core/authentication/login.vue                                                                                    |  115 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm                                                                       |   50 
 eims-ui/packages/effects/layouts/tsconfig.json                                                                                                 |    6 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue                                                                      |  100 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java                                                 |  152 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue                                                                 |   11 
 eims/ruoyi-admin/Dockerfile                                                                                                                    |   26 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java                                           |  217 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java                                         |   30 
 eims/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports    |    2 
 eims-ui/apps/web-antd/src/views/demo/tree/api/index.ts                                                                                         |   50 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue                                                                   |   33 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java                                           |   73 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java                                           |   31 
 eims-ui/scripts/deploy/nginx.conf                                                                                                              |   75 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java                                                     |   91 
 eims-ui/packages/effects/common-ui/src/ui/authentication/register.vue                                                                          |  119 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java                                       |   41 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts                                                                               |    1 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.js                                                                           |    2 
 eims-ui/packages/@core/base/shared/src/utils/diff.ts                                                                                           |   96 
 eims-ui/apps/web-antd/src/views/workflow/task/taskWaiting.vue                                                                                  |  172 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts                                                                            |   99 
 eims-ui/internal/vite-config/src/config/library.ts                                                                                             |   59 
 eims-ui/packages/effects/plugins/README.md                                                                                                     |   28 
 eims-ui/docs/src/commercial/technical-support.md                                                                                               |    8 
 eims-ui/docs/src/components/common-ui/vben-api-component.md                                                                                    |  150 
 eims-ui/packages/@core/base/shared/src/utils/dom.ts                                                                                            |   95 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts                                                                           |    4 
 eims-ui/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue                                                                  |  230 
 eims-ui/packages/effects/request/src/request-client/request-client.test.ts                                                                     |   99 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue                                                                       |   49 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue                                                        |   44 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue                                                              |   95 
 eims-ui/apps/web-antd/src/api/system/tenant-package/index.ts                                                                                   |   49 
 eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js                                                                   |    3 
 eims-ui/packages/icons/src/svg/icons/avatar-4.svg                                                                                              |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts                                                                       |    1 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue                                                                             |  122 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports     |    1 
 eims-ui/playground/src/views/demos/active-icon/index.vue                                                                                       |   11 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java                                         |   81 
 eims-ui/packages/@core/composables/src/use-layout-style.ts                                                                                     |   87 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityQueueController.java                                     |   89 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js                                                                         |   93 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue                                                                           |   65 
 eims-ui/packages/@core/ui-kit/form-ui/src/use-form-context.ts                                                                                  |   59 
 eims-ui/packages/styles/src/index.ts                                                                                                           |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java                                                           |   83 
 eims-ui/.eslintrc.cjs                                                                                                                          |   51 
 eims-ui/docs/src/demos/vben-form/rules/index.vue                                                                                               |  189 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java                                |   63 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java                                       |  108 
 eims-ui/apps/web-antd/src/views/system/user/info.tsx                                                                                           |  129 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts                                                                      |    3 
 eims-ui/playground/src/views/demos/access/admin-visible.vue                                                                                    |   11 
 eims-ui/packages/@core/base/shared/package.json                                                                                                |  101 
 eims-ui/docs/.vitepress/config/plugins/demo-preview.ts                                                                                         |  143 
 eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.ts                                                                                     |  165 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java                                                    |   52 
 eims-ui/packages/effects/layouts/src/basic/menu/extra-menu.vue                                                                                 |   40 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ms.js                                                                         |   93 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/utils/UnsignedMathGenerator.java                                       |   88 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java                                               |   54 
 eims-ui/playground/src/router/routes/modules/dashboard.ts                                                                                      |   40 
 eims-ui/playground/src/views/examples/captcha/slider-rotate-captcha.vue                                                                        |   28 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue                                                                                 |   19 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java                                     |  121 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java                                                    |  196 
 eims-ui/docs/src/guide/introduction/thin.md                                                                                                    |   94 
 eims-ui/packages/@core/preferences/package.json                                                                                                |   37 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java                                                      |  119 
 eims-ui/apps/web-antd/public/tinymce/plugins/visualblocks/plugin.min.js                                                                        |    4 
 eims-ui/packages/locales/src/langs/zh-CN/authentication.json                                                                                   |   56 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/tr.js                                                                         |   93 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js                                                                         |   93 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml                                                         |   13 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-api.ts                                                                                          |  351 
 eims-ui/playground/.env.production                                                                                                             |   19 
 eims-ui/packages/@core/base/shared/src/cache/index.ts                                                                                          |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue                                                                               |   48 
 eims/ruoyi-admin/.DS_Store                                                                                                                     |    0 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java                                       |   41 
 eims-ui/apps/web-antd/src/views/monitor/operlog/operation-preview-drawer.vue                                                                   |   32 
 eims-ui/apps/web-antd/src/views/system/role-assign/role-assign-drawer.vue                                                                      |   84 
 eims-ui/docs/src/guide/project/vite.md                                                                                                         |   33 
 eims-ui/internal/lint-configs/eslint-config/src/configs/comments.ts                                                                            |   24 
 eims-ui/scripts/turbo-run/src/run.ts                                                                                                           |   67 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java                                                 |  109 
 eims-ui/apps/web-antd/src/views/monitor/operlog/index.vue                                                                                      |  181 
 eims-ui/packages/@core/ui-kit/menu-ui/src/sub-menu.vue                                                                                         |   71 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue                                                                   |   84 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js                                                                      |   93 
 eims/ruoyi-admin/src/main/resources/logback-plus.xml                                                                                           |  129 
 eims-ui/apps/web-antd/src/views/system/tenantPackage/tenant-package-drawer.vue                                                                 |  145 
 eims-ui/docs/src/en/guide/in-depth/loading.md                                                                                                  |   44 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java                                            |   48 
 eims-ui/playground/src/router/index.ts                                                                                                         |   37 
 eims-ui/packages/effects/common-ui/src/ui/fallback/index.ts                                                                                    |    2 
 eims-ui/packages/effects/layouts/src/basic/content/content-spinner.vue                                                                         |   12 
 eims-ui/scripts/vsh/README.md                                                                                                                  |    3 
 eims-ui/apps/web-antd/src/views/demo/tree/tree-modal.vue                                                                                       |  104 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts                                                                                |   20 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue                                                                             |   13 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java                                          |  222 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts                                                                             |   10 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java                                                        |   60 
 eims/ruoyi-extend/ruoyi-monitor-admin/pom.xml                                                                                                  |   76 
 eims-ui/apps/web-antd/public/tinymce/plugins/image/plugin.min.js                                                                               |    4 
 eims-ui/packages/effects/layouts/src/basic/tabbar/index.ts                                                                                     |    2 
 eims-ui/apps/web-antd/src/components/tinymce/src/img-upload.vue                                                                                |  115 
 eims-ui/playground/src/layouts/index.ts                                                                                                        |    6 
 eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java                                  |   28 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java                                                           |   61 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java                                               |  160 
 eims-ui/internal/tsconfig/library.json                                                                                                         |   13 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts                                                                                |    4 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue                                                                   |   96 
 eims-ui/apps/web-antd/src/views/system/client/client-drawer.vue                                                                                |  129 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue                                                            |   63 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue                                                                 |   59 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java                                               |   54 
 eims-ui/packages/effects/layouts/src/basic/content/use-content-spinner.ts                                                                      |   50 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java                                     |   55 
 eims-ui/apps/web-naive/src/layouts/basic.vue                                                                                                   |  158 
 eims/script/sql/update/oracle/update_5.0-5.1.sql                                                                                               |  151 
 eims-ui/internal/node-utils/package.json                                                                                                       |   43 
 eims-ui/internal/vite-config/src/options.ts                                                                                                    |   45 
 eims-ui/apps/web-antd/src/api/system/oss/index.ts                                                                                              |   53 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java                          |   30 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue                                                                        |   67 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue                                                                      |   49 
 eims-ui/apps/web-antd/src/store/auth.ts                                                                                                        |  140 
 eims-ui/docs/src/guide/project/standard.md                                                                                                     |  165 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java                                 |  105 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java                                      |   36 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_PT.js                                                                      |   93 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatableFilter.java                                           |   40 
 eims-ui/packages/effects/hooks/src/use-pagination.ts                                                                                           |   57 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/index.ts                                                                                           |    3 
 eims-ui/apps/web-antd/src/components/tree/index.ts                                                                                             |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts                                                                                 |    1 
 eims-ui/apps/web-ele/src/router/routes/modules/dashboard.ts                                                                                    |   40 
 eims/LICENSE                                                                                                                                   |   20 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md                                                                      |    3 
 eims-ui/apps/backend-mock/api/table/list.ts                                                                                                    |   48 
 eims-ui/apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js                                                                          |    4 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoBo.java                                                         |   62 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java                                             |   88 
 eims-ui/packages/effects/common-ui/src/ui/about/about.ts                                                                                       |   14 
 eims/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    1 
 eims-ui/apps/web-naive/src/views/_core/authentication/register.vue                                                                             |   95 
 eims-ui/docs/.vitepress/theme/styles/index.ts                                                                                                  |    4 
 eims-ui/packages/@core/base/shared/src/color/index.ts                                                                                          |    3 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue                                                                         |   42 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquTypeBo.java                                                          |   69 
 eims-ui/packages/@core/preferences/src/constants.ts                                                                                            |   88 
 eims-ui/apps/web-antd/src/views/system/dept/index.vue                                                                                          |  182 
 eims/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java                                                                             |   72 
 eims-ui/playground/src/views/demos/breadcrumb/level-detail.vue                                                                                 |   11 
 eims/ruoyi-common/ruoyi-common-bom/pom.xml                                                                                                     |  185 
 eims/ruoyi-modules/ruoyi-workflow/README.md                                                                                                    |    3 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue                                                           |   17 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java                                                          |  123 
 eims-ui/apps/web-antd/src/router/access.ts                                                                                                     |  221 
 eims/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports      |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java                                                  |   80 
 eims-ui/packages/@core/composables/build.config.ts                                                                                             |    7 
 eims/pom.xml                                                                                                                                   |  521 
 eims-ui/packages/effects/common-ui/src/ui/authentication/code-login.vue                                                                        |  118 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEquType.java                                                               |   71 
 eims-ui/docs/src/demos/vben-form/query/index.vue                                                                                               |   94 
 eims/script/sql/update/update_5.1.2-5.2.0.sql                                                                                                  |    5 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue                                                               |   11 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/index.ts                                                                                 |    3 
 eims-ui/packages/@core/base/icons/src/index.ts                                                                                                 |   16 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports     |    3 
 eims-ui/packages/@core/base/shared/src/utils/download.ts                                                                                       |  156 
 eims-ui/apps/web-antd/src/views/index.vue                                                                                                      |  662 
 eims-ui/.gitignore                                                                                                                             |   29 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java                                         |   51 
 eims-ui/packages/@core/base/shared/src/color/color.ts                                                                                          |    9 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue                                                                       |   11 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java                                      |   73 
 eims-ui/docs/src/guide/project/cli.md                                                                                                          |  113 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/id.js                                                                         |   93 
 eims/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java                                                                |  165 
 eims-ui/apps/web-antd/src/api/system/dept/model.d.ts                                                                                           |   19 
 eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue                                                                           |   25 
 eims-ui/apps/web-antd/src/views/_core/profile/components/account-bind.vue                                                                      |  210 
 eims-ui/packages/effects/common-ui/src/components/code-mirror/index.ts                                                                         |    2 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java                                                     |   85 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java                                  |  125 
 eims/ruoyi-modules/lb-eims/src/.DS_Store                                                                                                       |    0 
 eims-ui/packages/@core/composables/src/use-simple-locale/index.ts                                                                              |   25 
 eims-ui/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap                                                                 |  115 
 eims-ui/apps/backend-mock/.nitro/dev/index.mjs.map                                                                                             |    1 
 eims-ui/packages/@core/ui-kit/menu-ui/tailwind.config.mjs                                                                                      |    1 
 eims-ui/apps/web-antd/src/api/system/menu/model.d.ts                                                                                           |   46 
 eims/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports       |    2 
 eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue                                                                     |  185 
 eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue                                                    |  175 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java                                              |   15 
 eims-ui/internal/node-utils/build.config.ts                                                                                                    |    7 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue                                                           |   26 
 eims-ui/playground/src/views/demos/access/user-visible.vue                                                                                     |   11 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports      |    1 
 eims-ui/packages/types/README.md                                                                                                               |   20 
 eims-ui/packages/effects/common-ui/src/components/index.ts                                                                                     |   23 
 eims/.DS_Store                                                                                                                                 |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java                                                     |   30 
 eims-ui/apps/web-antd/src/views/demo/demo/data.ts                                                                                              |   92 
 eims-ui/internal/tailwind-config/tsconfig.json                                                                                                 |    6 
 eims-ui/scripts/vsh/build.config.ts                                                                                                            |    7 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java                                              |   45 
 eims-ui/apps/web-antd/src/views/system/menu/data.tsx                                                                                           |  381 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm                                                                 |  498 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue                                                                           |   11 
 eims-ui/docs/src/public/guide/qq_channel.png                                                                                                   |    0 
 eims-ui/apps/web-antd/src/app.vue                                                                                                              |   39 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java                                          |  242 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java                                              |   43 
 eims-ui/playground/src/router/routes/modules/demos.ts                                                                                          |  572 
 eims-ui/packages/stores/src/modules/index.ts                                                                                                   |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue                                                                        |   13 
 eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue                             |   83 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue                                                               |   22 
 eims-ui/apps/web-antd/src/views/system/client/index.vue                                                                                        |  184 
 eims/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    5 
 eims-ui/docs/src/guide/project/tailwindcss.md                                                                                                  |   13 
 eims-ui/playground/postcss.config.mjs                                                                                                          |    1 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue                                                                     |   18 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.min.css                                                                           |    1 
 eims-ui/apps/web-antd/src/assets/logo.png                                                                                                      |    0 
 eims-ui/internal/node-utils/src/hash.ts                                                                                                        |   18 
 eims-ui/internal/node-utils/src/spinner.ts                                                                                                     |   24 
 eims-ui/playground/src/views/examples/form/rules.vue                                                                                           |  243 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java                                        |   15 
 eims-ui/packages/utils/src/helpers/generate-routes-backend.ts                                                                                  |   87 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java                                               |   71 
 eims-ui/packages/effects/hooks/src/use-tabs.ts                                                                                                 |  113 
 eims-ui/apps/web-antd/src/views/_core/fallback/offline.vue                                                                                     |    9 
 eims-ui/internal/vite-config/src/plugins/inject-metadata.ts                                                                                    |  111 
 eims-ui/packages/utils/package.json                                                                                                            |   28 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue                                                              |   21 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue                                                                   |   33 
 eims-ui/apps/web-ele/vite.config.mts                                                                                                           |   27 
 eims-ui/packages/effects/plugins/src/echarts/index.ts                                                                                          |    3 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css                                                            |    1 
 eims-ui/internal/vite-config/src/index.ts                                                                                                      |    4 
 eims-ui/playground/src/views/demos/features/hide-menu-children/parent.vue                                                                      |   11 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java                                              |   73 
 eims-ui/apps/web-antd/src/router/index.ts                                                                                                      |   37 
 eims-ui/packages/effects/common-ui/src/components/api-component/api-component.vue                                                              |  205 
 eims-ui/playground/src/views/examples/modal/dynamic-demo.vue                                                                                   |   41 
 eims-ui/packages/@core/ui-kit/menu-ui/src/types.ts                                                                                             |  139 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue                                                                    |   18 
 eims-ui/.eslintignore                                                                                                                          |   17 
 eims-ui/apps/web-antd/src/views/_core/social-callback/index.vue                                                                                |   81 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java                                                       |   29 
 eims-ui/apps/web-antd/src/views/eims/equ/equ-drawer.vue                                                                                        |  206 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts                                                                                  |  180 
 eims-ui/apps/web-naive/src/app.vue                                                                                                             |   56 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue                                                                        |   11 
 eims-ui/apps/web-antd/src/assets/img/img-up-limit.png                                                                                          |    0 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java                                        |   58 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java                                        |   34 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java                                                               |   92 
 eims/ruoyi-common/ruoyi-common-websocket/pom.xml                                                                                               |   40 
 eims-ui/apps/web-antd/src/api/request.ts                                                                                                       |  259 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java                                              |   65 
 eims-ui/apps/web-ele/src/adapter/vxe-table.ts                                                                                                  |   68 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java                                           |  119 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java                                            |   61 
 eims-ui/packages/@core/composables/src/__tests__/use-sortable.test.ts                                                                          |   48 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java                                              |   29 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/china.json                                                                                      | 103310 ++++++++++++++++++++
 eims-ui/apps/web-naive/src/views/_core/authentication/login.vue                                                                                |   98 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts                                                                              |    4 
 eims-ui/apps/web-ele/src/api/core/menu.ts                                                                                                      |   10 
 eims-ui/packages/effects/layouts/src/widgets/preferences/preferences.vue                                                                       |   71 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java                   |   18 
 eims-ui/playground/src/views/demos/breadcrumb/lateral.vue                                                                                      |   25 
 eims-ui/docs/src/sponsor/personal.md                                                                                                           |   12 
 eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.min.css                                                                      |    1 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue                                                                         |   15 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java                                |   18 
 eims-ui/apps/web-antd/.env                                                                                                                     |    5 
 eims-ui/packages/locales/tsconfig.json                                                                                                         |    6 
 eims-ui/apps/web-antd/src/views/system/role-assign/data.tsx                                                                                    |   43 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java                         |  274 
 eims-ui/apps/web-antd/src/views/monitor/logininfor/index.vue                                                                                   |  213 
 eims-ui/docs/src/guide/other/project-update.md                                                                                                 |   55 
 eims-ui/internal/tailwind-config/src/index.ts                                                                                                  |  266 
 eims-ui/apps/web-antd/public/tinymce/plugins/lists/plugin.min.js                                                                               |    4 
 eims-ui/apps/web-antd/src/components/global/button.ts                                                                                          |   21 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue                                                                 |   48 
 eims-ui/docs/src/guide/project/test.md                                                                                                         |   33 
 eims-ui/apps/web-ele/public/favicon.ico                                                                                                        |    0 
 eims-ui/packages/@core/ui-kit/layout-ui/tailwind.config.mjs                                                                                    |    1 
 eims-ui/packages/effects/layouts/src/widgets/layout-toggle.vue                                                                                 |   61 
 eims-ui/packages/effects/request/src/request-client/modules/uploader.ts                                                                        |   35 
 eims-ui/packages/stores/src/index.ts                                                                                                           |    3 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts                                                                         |    5 
 eims-ui/apps/web-antd/src/views/monitor/cache/components/memory-chart.vue                                                                      |   94 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue                                                                      |   63 
 eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/config/RateLimiterConfig.java                          |   20 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java                              |  160 
 eims-ui/apps/web-antd/src/views/system/role/role-auth-modal.vue                                                                                |  118 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java                                                    |   61 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java                           |  691 
 eims-ui/apps/web-antd/src/api/system/client/model.d.ts                                                                                         |   12 
 eims-ui/packages/effects/plugins/src/vxe-table/types.ts                                                                                        |   61 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts                                                                        |   24 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue                                                             |   40 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue                                                                     |   43 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts                                                                                 |    5 
 eims-ui/apps/web-ele/src/views/_core/fallback/offline.vue                                                                                      |    9 
 eims-ui/docs/src/en/guide/project/dir.md                                                                                                       |   68 
 eims-ui/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue                                                      |  213 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu.vue                                                                                  |  854 
 eims-ui/playground/src/views/examples/vxe-table/table-data.ts                                                                                  |  172 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java                                            |   67 
 eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.min.css                                                              |    1 
 eims-ui/apps/web-antd/src/views/workflow/components/index.ts                                                                                   |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts                                                                     |    3 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java                                           |   66 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java                                              |   75 
 eims-ui/packages/preferences/package.json                                                                                                      |   26 
 eims/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports         |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml                                                         |    7 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java                                                       |   29 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java                                                      |  110 
 eims-ui/apps/web-naive/src/adapter/vxe-table.ts                                                                                                |   67 
 eims-ui/packages/effects/layouts/src/basic/index.ts                                                                                            |    1 
 eims-ui/playground/src/preferences.ts                                                                                                          |   13 
 eims-ui/playground/src/views/demos/access/menu-visible-403.vue                                                                                 |   11 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java                                              |   18 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java                                |   92 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java                                                     |   29 
 eims-ui/apps/web-antd/src/api/system/tenant-package/model.d.ts                                                                                 |   17 
 eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java                                                                 |  115 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java                                          |  152 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue                                                       |   39 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/properties/WebSocketProperties.java                 |   26 
 eims-ui/packages/@core/composables/src/use-scroll-lock.ts                                                                                      |   54 
 eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue                                                                     |   82 
 eims-ui/docs/src/en/guide/other/project-update.md                                                                                              |   54 
 eims-ui/internal/lint-configs/eslint-config/src/configs/jsonc.ts                                                                               |  258 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue                                                              |   71 
 eims-ui/packages/utils/src/helpers/index.ts                                                                                                    |   14 
 eims-ui/apps/web-antd/src/utils/encryption/jsencrypt.ts                                                                                        |   31 
 eims-ui/packages/effects/common-ui/src/ui/authentication/index.ts                                                                              |   12 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java                                        |   11 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java                                 |   91 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquController.java                                                     |  107 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties                                                                       |   20 
 eims-ui/docs/src/en/guide/in-depth/ui-framework.md                                                                                             |   17 
 eims-ui/docs/.vitepress/config/zh.mts                                                                                                          |  348 
 eims-ui/packages/locales/src/langs/en-US/preferences.json                                                                                      |  169 
 eims-ui/playground/src/views/examples/modal/drag-demo.vue                                                                                      |   19 
 eims-ui/playground/src/views/demos/features/menu-query/index.vue                                                                               |   11 
 eims-ui/playground/src/views/examples/form/dynamic.vue                                                                                         |  262 
 eims-ui/apps/web-naive/src/views/demos/table/index.vue                                                                                         |   38 
 eims-ui/packages/@core/ui-kit/menu-ui/src/menu.vue                                                                                             |   38 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquMapper.java                                                             |   15 
 eims-ui/docs/src/demos/vben-vxe-table/table-data.ts                                                                                            |  384 
 eims-ui/apps/web-antd/src/views/monitor/logininfor/data.tsx                                                                                    |  166 
 eims-ui/packages/@core/base/shared/src/color/__tests__/convert.test.ts                                                                         |   58 
 eims-ui/README.zh-CN.md                                                                                                                        |  197 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java                                                 |   47 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts                                                                        |    2 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java                                              |   21 
 eims/ruoyi-admin/pom.xml                                                                                                                       |  159 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java                                              |  186 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java                                          |   29 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java                                              |  222 
 eims-ui/apps/web-antd/public/tinymce/license.md                                                                                                |    6 
 eims-ui/packages/@core/base/icons/src/create-icon.ts                                                                                           |   30 
 eims-ui/docs/src/_env/node/adapter/form.ts                                                                                                     |    4 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml                                                                    |   92 
 eims-ui/apps/web-antd/src/views/system/user/user-reset-pwd-modal.vue                                                                           |  111 
 eims-ui/apps/web-naive/src/router/access.ts                                                                                                    |   40 
 eims-ui/packages/@core/base/design/src/css/transition.css                                                                                      |  236 
 eims-ui/packages/effects/layouts/src/widgets/notification/types.ts                                                                             |   10 
 eims/.editorconfig                                                                                                                             |   18 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java                                                       |   49 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue                                                                      |  112 
 eims/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties                                                                             |   61 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java                                             |    9 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java                                      |   97 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue                                                                  |   26 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ru.js                                                                         |   93 
 eims-ui/apps/web-ele/src/layouts/auth.vue                                                                                                      |   23 
 eims-ui/apps/web-ele/src/locales/README.md                                                                                                     |    3 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java                          |   94 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquService.java                                                          |   69 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java                                                  |   50 
 eims-ui/packages/@core/ui-kit/menu-ui/src/utils/index.ts                                                                                       |   51 
 eims-ui/apps/web-antd/src/api/system/dict/dict-data.ts                                                                                         |   75 
 eims-ui/playground/src/views/examples/drawer/index.vue                                                                                         |  188 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java                                               |   58 
 eims-ui/apps/web-antd/public/static/logo.png                                                                                                   |    0 
 eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java                                 |   30 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java                                                |   67 
 eims-ui/apps/web-antd/src/components/tinymce/src/helper.ts                                                                                     |   85 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java                               |   55 
 eims-ui/docs/src/guide/in-depth/locale.md                                                                                                      |  227 
 eims-ui/packages/effects/layouts/src/iframe/iframe-view.vue                                                                                    |    3 
 eims-ui/apps/web-naive/src/views/_core/fallback/not-found.vue                                                                                  |    9 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java                            |   39 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java                                             |   49 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/kk.js                                                                         |   93 
 eims-ui/internal/lint-configs/commitlint-config/package.json                                                                                   |   33 
 eims-ui/internal/vite-config/src/plugins/inject-app-loading/index.ts                                                                           |   66 
 eims-ui/apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js                                                                             |    4 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-config.vue                                                                             |  108 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/letter.test.ts                                                                          |  116 
 eims-ui/playground/src/locales/langs/zh-CN/page.json                                                                                           |   14 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java                                            |   15 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java                                       |   27 
 eims-ui/apps/web-antd/src/api/tool/gen/index.ts                                                                                                |  102 
 eims-ui/apps/web-antd/src/views/workflow/category/index.vue                                                                                    |  153 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue                                                                            |   24 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java                                                 |   37 
 eims-ui/apps/web-ele/src/views/_core/README.md                                                                                                 |    3 
 eims-ui/packages/@core/ui-kit/form-ui/src/components/form-actions.vue                                                                          |  205 
 eims-ui/apps/backend-mock/utils/cookie-utils.ts                                                                                                |   26 
 eims-ui/packages/locales/src/langs/zh-CN/common.json                                                                                           |   13 
 eims-ui/apps/web-antd/src/api/common.d.ts                                                                                                      |   41 
 eims-ui/apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js                                                                          |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue                                                                      |   29 
 eims-ui/playground/src/locales/langs/zh-CN/demos.json                                                                                          |   70 
 eims-ui/apps/web-antd/src/api/eims/equ-type/index.ts                                                                                           |   69 
 eims-ui/apps/web-antd/src/views/system/oss-config/data.tsx                                                                                     |  212 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue                                                                 |   43 
 eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java                                   |   94 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue                                                                   |   18 
 eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java                                                 |  469 
 eims-ui/packages/types/package.json                                                                                                            |   27 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java                                              |   40 
 eims-ui/apps/web-antd/src/views/tool/gen/code-preview-modal.vue                                                                                |  213 
 eims-ui/apps/web-naive/index.html                                                                                                              |   35 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java                                                  |  122 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue                                                                           |   46 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue                                                                 |   84 
 eims-ui/README.ja-JP.md                                                                                                                        |  153 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoEncryptMapper.java                                                 |   13 
 eims-ui/playground/src/views/_core/fallback/offline.vue                                                                                        |    9 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java                                      |  156 
 eims-ui/apps/web-antd/src/components/table/src/table-switch.vue                                                                                |   84 
 eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue                                                               |   67 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java                                            |   35 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java                                             |   26 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java                                                 |   13 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java                                                |   73 
 eims-ui/apps/web-antd/src/components/dict/src/data.tsx                                                                                         |   44 
 eims-ui/apps/web-antd/src/utils/encryption/crypto.ts                                                                                           |   80 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java                   |   65 
 eims-ui/packages/effects/common-ui/src/components/code-mirror/data.ts                                                                          |   24 
 eims-ui/docs/src/en/guide/in-depth/access.md                                                                                                   |  318 
 eims-ui/playground/vite.config.mts                                                                                                             |   20 
 eims-ui/docs/.vitepress/config/index.mts                                                                                                       |   25 
 eims-ui/apps/backend-mock/api/menu/all.ts                                                                                                      |   13 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java                                       |  120 
 eims-ui/apps/web-antd/src/views/system/dict/data/tag-style-picker.vue                                                                          |   84 
 eims-ui/apps/web-ele/src/views/_core/fallback/coming-soon.vue                                                                                  |    7 
 eims-ui/apps/web-antd/src/views/eims/equ/index.vue                                                                                             |  198 
 eims-ui/packages/@core/composables/package.json                                                                                                |   47 
 eims-ui/docs/src/_env/adapter/form.ts                                                                                                          |   49 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue                                                           |  173 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue                                                                       |   76 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java                                             |   59 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts                                                                               |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java                                                     |   63 
 eims/script/sql/postgres/snail_job_postgre.sql                                                                                                 |  836 
 eims-ui/docs/src/demos/vben-vxe-table/basic/index.vue                                                                                          |   85 
 eims-ui/apps/backend-mock/routes/[...].ts                                                                                                      |   12 
 eims-ui/apps/web-antd/src/views/system/tenant/tenant-drawer.vue                                                                                |  119 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java                                           |   16 
 eims-ui/apps/backend-mock/api/auth/refresh.post.ts                                                                                             |   33 
 eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue                                                |   38 
 eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue                                                                  |  262 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml                                                                   |   33 
 eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java                                               |   72 
 eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue                                                                       |  155 
 eims-ui/docs/src/en/guide/in-depth/theme.md                                                                                                    | 1293 
 eims-ui/internal/vite-config/src/config/common.ts                                                                                              |   13 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java                                                  |  147 
 eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js                                                                            |    1 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java                                       |   29 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java                                                 |   28 
 eims-ui/internal/lint-configs/eslint-config/build.config.ts                                                                                    |    7 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml                                                         |    7 
 eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/AllUrlHandler.java                                   |   39 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEqu.java                                                                   |  151 
 eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.js                                                                        |    2 
 eims-ui/docs/src/demos/vben-drawer/shared-data/index.vue                                                                                       |   26 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue                                                                           |   45 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue                                                               |   27 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java                                          |   30 
 eims-ui/eslint.config.mjs                                                                                                                      |    5 
 eims-ui/playground/src/api/core/menu.ts                                                                                                        |   10 
 eims-ui/apps/web-naive/.env.analyze                                                                                                            |    7 
 eims-ui/internal/lint-configs/eslint-config/src/configs/index.ts                                                                               |   17 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/tree.test.ts                                                                            |  196 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java                                       |   59 
 eims-ui/packages/utils/src/helpers/tree.ts                                                                                                     |  400 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java                                          |   13 
 eims-ui/apps/web-antd/src/views/system/post/data.ts                                                                                            |  132 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java                                     |   51 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java                                    |  179 
 eims-ui/apps/web-antd/public/tinymce/plugins/searchreplace/plugin.min.js                                                                       |    4 
 eims/script/sql/update/postgres/update_5.0-5.1.sql                                                                                             |  150 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue                                                                       |   31 
 eims-ui/packages/effects/common-ui/src/components/resize/index.ts                                                                              |    1 
 eims-ui/packages/@core/base/typings/src/vue-router.d.ts                                                                                        |  143 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java                                  |   33 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue                                                              |   68 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java                                                  |   18 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue                                                                     |   23 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts                                                                                |   25 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue                                                              |   17 
 eims-ui/apps/web-ele/src/views/_core/fallback/forbidden.vue                                                                                    |    9 
 eims-ui/packages/@core/ui-kit/layout-ui/postcss.config.mjs                                                                                     |    1 
 eims-ui/apps/web-antd/src/views/system/dict/index.vue                                                                                          |   21 
 eims-ui/packages/@core/base/typings/vue-router.d.ts                                                                                            |    9 
 eims-ui/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts                                                                  |  105 
 eims-ui/playground/src/views/examples/captcha/slider-captcha.vue                                                                               |  117 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java                                              |   33 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java                                                         |  103 
 eims-ui/playground/src/views/examples/form/query.vue                                                                                           |  147 
 eims-ui/packages/effects/layouts/src/authentication/form.vue                                                                                   |   33 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java                        |   64 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue                                                                 |   67 
 eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java                       |   50 
 eims-ui/internal/tailwind-config/src/module.d.ts                                                                                               |    3 
 eims/ruoyi-common/ruoyi-common-excel/pom.xml                                                                                                   |   35 
 eims-ui/apps/web-antd/src/locales/README.md                                                                                                    |    3 
 eims-ui/packages/@core/ui-kit/layout-ui/src/index.ts                                                                                           |    2 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java              |   30 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java                                         |   62 
 eims-ui/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts                                                                 |  130 
 eims-ui/playground/src/views/demos/features/tabs/tab-detail.vue                                                                                |   23 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java                                                  |   54 
 eims-ui/playground/src/views/demos/features/full-screen/index.vue                                                                              |   47 
 eims-ui/playground/src/views/examples/form/merge.vue                                                                                           |  116 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java                            |   29 
 eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml                                                  |    7 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue                                                                        |   11 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ja.js                                                                         |   93 
 eims-ui/packages/@core/ui-kit/layout-ui/build.config.ts                                                                                        |   21 
 eims-ui/packages/effects/hooks/src/use-app-config.ts                                                                                           |   40 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/listener/ExportDemoListener.java                                                  |   68 
 eims-ui/apps/web-antd/src/bootstrap.ts                                                                                                         |   52 
 eims-ui/playground/tsconfig.node.json                                                                                                          |   10 
 eims-ui/packages/@core/base/design/src/css/ui.css                                                                                              |   83 
 eims-ui/packages/styles/tsconfig.json                                                                                                          |    6 
 eims/ruoyi-extend/pom.xml                                                                                                                      |   19 
 eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue                                                          |   65 
 eims-ui/packages/effects/layouts/src/basic/menu/use-navigation.ts                                                                              |   33 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java                                                    |   72 
 eims-ui/apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js                                                                          |    4 
 eims/.run/ruoyi-snailjob-server.run.xml                                                                                                        |   12 
 eims-ui/packages/@core/base/typings/build.config.ts                                                                                            |    7 
 eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java                                                |  115 
 eims-ui/packages/effects/layouts/src/basic/content/content.vue                                                                                 |  114 
 eims-ui/docs/package.json                                                                                                                      |   35 
 eims-ui/apps/web-naive/src/views/_core/fallback/coming-soon.vue                                                                                |    7 
 eims-ui/docs/src/demos/vben-vxe-table/remote/index.vue                                                                                         |  112 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue                                                    |  109 
 eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java                                                   |   23 
 eims-ui/apps/backend-mock/api/auth/logout.post.ts                                                                                              |   15 
 eims-ui/packages/locales/src/index.ts                                                                                                          |   28 
 eims/.run/ruoyi-server.run.xml                                                                                                                 |   12 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java                                          |   87 
 eims-ui/packages/constants/README.md                                                                                                           |   19 
 eims/ruoyi-extend/ruoyi-snailjob-server/pom.xml                                                                                                |   46 
 eims-ui/playground/src/views/examples/vxe-table/form.vue                                                                                       |  112 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java                                                  |  222 
 eims-ui/apps/web-antd/src/api/system/profile/index.ts                                                                                          |   65 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js                                                                      |   93 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java                                           |   35 
 eims/script/sql/update/postgres/update_5.1.0-5.1.1.sql                                                                                         |    5 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml                                                           |    7 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java                          |   18 
 eims-ui/playground/src/views/_core/fallback/internal-error.vue                                                                                 |    9 
 eims-ui/scripts/preview/10.png                                                                                                                 |    0 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java                                      |  133 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java                                             |   83 
 eims/ruoyi-modules/lb-eims/.DS_Store                                                                                                           |    0 
 eims/ruoyi-common/ruoyi-common-ratelimiter/pom.xml                                                                                             |   30 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml                                                                       |   48 
 eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue                                                                      |  105 
 eims-ui/apps/web-antd/src/locales/langs/zh-CN/component.json                                                                                   |   55 
 eims-ui/apps/web-antd/src/views/demo/demo/index.vue                                                                                            |  170 
 eims-ui/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts                                                                   |  128 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml                                                           |    7 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java                                      |  258 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java                                        |  112 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java                          |   39 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java                                                  |   61 
 eims-ui/apps/web-ele/tsconfig.node.json                                                                                                        |   10 
 eims-ui/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts                                                                         |   88 
 eims-ui/apps/web-antd/src/api/system/social/index.ts                                                                                           |   20 
 eims-ui/apps/web-antd/src/views/system/oss-config/index.vue                                                                                    |  166 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/TranslationInterface.java                         |   20 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java                                                  |   62 
 eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java                                                 |  170 
 eims-ui/packages/@core/base/shared/src/store.ts                                                                                                |    1 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js                                                                         |   93 
 eims-ui/scripts/preview/8.png                                                                                                                  |    0 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue                                                                          |   28 
 eims-ui/docs/src/public/guide/report.png                                                                                                       |    0 
 eims-ui/packages/@core/composables/src/use-namespace.ts                                                                                        |  106 
 eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts                                                                                    |   48 
 eims-ui/internal/vite-config/src/utils/env.ts                                                                                                  |  110 
 eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java                             |   94 
 eims/script/sql/snail_job.sql                                                                                                                  |  514 
 eims-ui/docs/src/public/guide/qq.png                                                                                                           |    0 
 eims-ui/apps/backend-mock/api/user/info.ts                                                                                                     |   10 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java                                                      |  100 
 eims/ruoyi-admin/src/main/resources/ip2region.xdb                                                                                              |    0 
 eims-ui/apps/web-antd/src/components/cropper/index.ts                                                                                          |    4 
 eims-ui/apps/web-antd/src/views/_core/fallback/internal-error.vue                                                                              |    9 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue                                                             |   11 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts                                                                              |    4 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts                                                                                |    4 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java                                                      |   89 
 eims-ui/packages/icons/src/svg/icons/bell.svg                                                                                                  |    1 
 eims-ui/scripts/vsh/src/code-workspace/index.ts                                                                                                |   78 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java                                                   |  127 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue                                                                          |   83 
 eims-ui/playground/src/views/_core/fallback/not-found.vue                                                                                      |    9 
 eims-ui/playground/src/views/examples/vxe-table/tree.vue                                                                                       |   62 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.js                                                                     |    2 
 eims-ui/docs/src/demos/vben-form/basic/index.vue                                                                                               |  231 
 eims/ruoyi-common/ruoyi-common-json/pom.xml                                                                                                    |   37 
 eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml                                                             |   59 
 eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.min.css                                                                     |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java                                                  |   14 
 eims-ui/apps/web-antd/public/tinymce/models/dom/model.min.js                                                                                   |    4 
 eims-ui/docs/src/en/guide/in-depth/locale.md                                                                                                   |  227 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/dom.test.ts                                                                             |  127 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue                                                                            |   19 
 eims-ui/apps/web-antd/src/api/system/post/model.d.ts                                                                                           |   12 
 eims-ui/packages/@core/composables/src/use-sortable.ts                                                                                         |   29 
 eims-ui/tea.yaml                                                                                                                               |    6 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts                                                                                 |   20 
 eims-ui/.eslintrc-auto-import.json                                                                                                             |  312 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java                                             |   93 
 eims-ui/apps/web-naive/src/api/core/index.ts                                                                                                   |    3 
 eims-ui/packages/stores/src/modules/access.test.ts                                                                                             |   46 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java                                                |  106 
 eims-ui/apps/web-antd/src/api/system/config/index.ts                                                                                           |   55 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java                                                    |  142 
 eims-ui/apps/web-antd/src/views/system/dept/dept-drawer.vue                                                                                    |  164 
 eims-ui/docs/src/_env/node/adapter/vxe-table.ts                                                                                                |    3 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue                                                                         |   19 
 eims-ui/apps/web-antd/public/tinymce/plugins/code/plugin.min.js                                                                                |    4 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js                                                                         |   93 
 eims-ui/apps/web-ele/src/views/_core/authentication/forget-password.vue                                                                        |   42 
 eims-ui/apps/web-naive/src/adapter/component/index.ts                                                                                          |  182 
 eims/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports        |    1 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/window.test.ts                                                                          |   33 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue                                                                 |  153 
 eims-ui/apps/web-antd/public/tinymce/langs/zh_CN.js                                                                                            |    1 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java                                    |   70 
 eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java                                       |   36 
 eims-ui/apps/web-antd/src/api/system/config/model.d.ts                                                                                         |    9 
 eims-ui/apps/web-antd/src/components/cropper/src/typing.ts                                                                                     |    8 
 eims-ui/apps/web-naive/src/router/routes/modules/demos.ts                                                                                      |   46 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java                                          |   40 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java                                                      |   13 
 eims-ui/apps/web-antd/src/api/core/auth.ts                                                                                                     |  175 
 eims-ui/packages/effects/access/src/use-access.ts                                                                                              |   59 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java                                     |   52 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java                                                  |  200 
 eims-ui/packages/stores/src/modules/user.test.ts                                                                                               |   37 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue                                                                     |   27 
 eims-ui/apps/web-antd/src/views/monitor/cache/components/index.ts                                                                              |    3 
 eims-ui/docs/src/demos/vben-modal/draggable/index.vue                                                                                          |   21 
 eims-ui/packages/utils/src/helpers/generate-menus.ts                                                                                           |   80 
 eims-ui/playground/src/views/examples/vxe-table/edit-row.vue                                                                                   |   94 
 eims-ui/docs/.vitepress/components/preview-group.vue                                                                                           |  108 
 eims-ui/apps/web-antd/src/components/table/index.ts                                                                                            |    1 
 eims-ui/packages/@core/base/shared/tsconfig.json                                                                                               |    6 
 eims/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java                                                                              |   70 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue                                                      |   44 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java                                            |   43 
 eims-ui/apps/web-antd/src/views/system/tenantPackage/index.vue                                                                                 |  194 
 eims-ui/packages/effects/layouts/src/basic/footer/footer.vue                                                                                   |   11 
 eims-ui/packages/effects/request/src/request-client/preset-interceptors.ts                                                                     |  126 
 eims-ui/scripts/vsh/package.json                                                                                                               |   31 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java                                       |   48 
 eims-ui/packages/effects/hooks/package.json                                                                                                    |   32 
 eims-ui/packages/effects/access/tsconfig.json                                                                                                  |    6 
 eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java                                                   |   73 
 eims-ui/apps/web-naive/src/layouts/auth.vue                                                                                                    |   23 
 eims-ui/apps/web-antd/src/router/routes/index.ts                                                                                               |   37 
 eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue                                                                 |  101 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_BR.js                                                                      |   93 
 eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts                                                                              |  194 
 eims-ui/apps/web-antd/src/api/monitor/online/index.ts                                                                                          |   40 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue                                                                      |  315 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java                                             |   65 
 eims-ui/packages/effects/common-ui/src/components/captcha/index.ts                                                                             |    6 
 eims-ui/playground/src/views/examples/modal/in-content-demo.vue                                                                                |   25 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java                                      |  858 
 eims/ruoyi-extend/ruoyi-monitor-admin/Dockerfile                                                                                               |   20 
 eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java                                   |   89 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java                                                   |   14 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java                                       |   32 
 eims-ui/apps/web-antd/src/api/system/dict/dict-data-model.d.ts                                                                                 |   17 
 eims-ui/docs/src/guide/introduction/changelog.md                                                                                               |    3 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java                                                     |   76 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/visit/api.ts                                                                                          |   32 
 eims-ui/docs/src/guide/essentials/server.md                                                                                                    |  359 
 eims-ui/playground/src/views/dashboard/analytics/analytics-visits-source.vue                                                                   |   67 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java                                                |   82 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-success.vue                                                                            |   25 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts                                                                  |    4 
 eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java               |   75 
 eims-ui/apps/web-naive/src/locales/langs/en-US/demos.json                                                                                      |   14 
 eims-ui/apps/web-antd/src/components/tenant-toggle/index.ts                                                                                    |    1 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue                                                                  |   84 
 eims-ui/apps/web-antd/src/adapter/component/index.ts                                                                                           |  177 
 eims-ui/apps/web-ele/tailwind.config.mjs                                                                                                       |    1 
 eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js                                                                       |    1 
 eims-ui/apps/web-naive/src/api/core/menu.ts                                                                                                    |   10 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java                                                    |   66 
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java                                               |   30 
 eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue                                                                       |   29 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts                                                                      |    6 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java                                                         |   61 
 eims-ui/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue                                                             |  119 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.js                                                                        |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue                                                                                   |   16 
 eims-ui/apps/web-antd/src/api/monitor/logininfo/model.d.ts                                                                                     |   12 
 eims-ui/packages/@core/base/shared/src/utils/letter.ts                                                                                         |   47 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue                                                                  |   33 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java                                                   |   53 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/package-info.java                                                          |    1 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java                             |   50 
 eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/banner.txt                                                                            |    8 
 eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.min.css                                                                    |    1 
 eims-ui/packages/@core/base/shared/src/global-state.ts                                                                                         |   45 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java                                                        |  110 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java                                                      |   91 
 eims-ui/apps/web-antd/src/views/system/role/index.vue                                                                                          |  249 
 eims-ui/packages/effects/request/tsconfig.json                                                                                                 |    6 
 eims-ui/internal/vite-config/build.config.ts                                                                                                   |    7 
 eims-ui/packages/effects/layouts/src/authentication/types.ts                                                                                   |    1 
 eims-ui/packages/icons/src/iconify-offline/menu-icons.ts                                                                                       |  104 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java                            |   48 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts                                                               |   38 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java                               |   89 
 eims-ui/apps/web-antd/src/views/_core/authentication/oauth-login.vue                                                                           |   44 
 eims-ui/docs/src/public/guide/locale.png                                                                                                       |    0 
 eims-ui/playground/src/views/examples/resize/basic.vue                                                                                         |   58 
 eims-ui/apps/web-antd/src/utils/render.tsx                                                                                                     |  229 
 eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java                                |   99 
 eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java                                 |   18 
 eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue                                                                       |   57 
 eims-ui/apps/web-ele/src/views/_core/authentication/login.vue                                                                                  |   98 
 eims-ui/playground/src/router/access.ts                                                                                                        |   42 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java                                                |   37 
 eims-ui/packages/@core/preferences/__tests__/config.test.ts                                                                                    |   10 
 eims-ui/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts                                                                                |   41 
 eims-ui/packages/@core/base/shared/src/cache/types.ts                                                                                          |   17 
 eims-ui/packages/utils/src/helpers/enum-options.ts                                                                                             |   47 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java                                   |   40 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java                              |   79 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md                                                                        |    3 
 eims-ui/apps/backend-mock/nitro.config.ts                                                                                                      |   19 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts                                                                                   |   11 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm                                                               |  115 
 eims-ui/docs/src/public/guide/preferences.png                                                                                                  |    0 
 eims-ui/packages/effects/common-ui/src/components/api-component/index.ts                                                                       |    1 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java                                                          |   47 
 eims-ui/packages/@core/ui-kit/popup-ui/tailwind.config.mjs                                                                                     |    1 
 eims-ui/apps/web-antd/src/api/system/profile/model.d.ts                                                                                        |   75 
 eims-ui/apps/web-antd/src/api/system/tenant/index.ts                                                                                           |   97 
 eims/ruoyi-common/ruoyi-common-social/pom.xml                                                                                                  |   34 
 eims-ui/packages/@core/base/shared/src/utils/__tests__/inference.test.ts                                                                       |  183 
 eims-ui/packages/@core/base/shared/build.config.ts                                                                                             |   14 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-data.tsx                                                                               |  326 
 eims-ui/playground/src/views/dashboard/analytics/index.vue                                                                                     |   90 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java                                          |  514 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java                                       |  106 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java                               |   37 
 eims-ui/packages/icons/src/svg/index.ts                                                                                                        |   27 
 eims-ui/playground/src/locales/README.md                                                                                                       |    3 
 eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/多sheet列表.xlsx                                                                           |    0 
 eims-ui/playground/src/router/routes/modules/examples.ts                                                                                       |  244 
 eims-ui/packages/@core/ui-kit/popup-ui/build.config.ts                                                                                         |   21 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/sse/api.ts                                                                                            |   26 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts                                                                     |    1 
 eims-ui/apps/web-antd/src/api/system/role/index.ts                                                                                             |  123 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue                                                          |   40 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/index.ts                                                                                     |    3 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/sse/send-msg-modal.vue                                                                                |   77 
 eims-ui/playground/src/api/examples/status.ts                                                                                                  |   10 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestI18nController.java                                                |   71 
 eims-ui/apps/web-naive/src/locales/langs/zh-CN/demos.json                                                                                      |   14 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java                          |   50 
 eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java                                           |   16 
 eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue                                                                        |  100 
 eims-ui/apps/web-antd/src/api/system/role/model.d.ts                                                                                           |   29 
 eims-ui/docs/src/guide/in-depth/theme.md                                                                                                       | 1293 
 eims-ui/scripts/turbo-run/build.config.ts                                                                                                      |    7 
 eims-ui/apps/web-naive/src/api/core/user.ts                                                                                                    |   10 
 eims-ui/docs/src/components/introduction.md                                                                                                    |   15 
 eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java                                 |   52 
 eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/org/dromara/snailjob/SnailJobServerApplication.java                                      |   19 
 eims/ruoyi-common/ruoyi-common-mybatis/pom.xml                                                                                                 |   47 
 eims-ui/apps/web-antd/src/components/dict/index.ts                                                                                             |    2 
 eims-ui/playground/tailwind.config.mjs                                                                                                         |    1 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java                                              |  228 
 eims/ruoyi-modules/lb-eims/src/main/.DS_Store                                                                                                  |    0 
 eims-ui/apps/web-antd/src/views/演示使用自行删除/query/index.vue                                                                                       |   17 
 eims-ui/packages/@core/base/typings/src/helper.d.ts                                                                                            |  129 
 eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java                                 |   27 
 eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java                                                       |  118 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue                                                                     |   57 
 eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.js                                                                            |    2 
 eims-ui/apps/web-antd/src/views/workflow/task/myDocument.vue                                                                                   |    9 
 eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java                                      |   54 
 eims-ui/apps/web-ele/.env.analyze                                                                                                              |    7 
 eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.js                                                                          |    2 
 eims-ui/playground/src/views/demos/nested/menu-3-1.vue                                                                                         |    7 
 eims-ui/playground/src/views/demos/features/watermark/index.vue                                                                                |   86 
 eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.js                                                                             |    2 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue                                                          |   43 
 eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java                         |   49 
 eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/BaseController.java                                               |   40 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java                                             |   85 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js                                                                         |   93 
 eims-ui/apps/backend-mock/.nitro/types/nitro-routes.d.ts                                                                                       |   39 
 eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/index.ts                                                                                   |    3 
 eims-ui/packages/effects/plugins/src/vxe-table/api.ts                                                                                          |  115 
 eims-ui/docs/src/en/guide/introduction/vben.md                                                                                                 |   49 
 eims-ui/packages/effects/layouts/src/basic/menu/index.ts                                                                                       |    5 
 eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm                                                                   |   60 
 eims-ui/internal/tsconfig/node.json                                                                                                            |   12 
 eims-ui/packages/@core/base/icons/src/lucide.ts                                                                                                |   59 
 eims-ui/playground/src/views/demos/nested/menu-2-1.vue                                                                                         |    7 
 eims-ui/docs/.vitepress/components/demo-preview.vue                                                                                            |   45 
 eims-ui/packages/styles/src/global/index.scss                                                                                                  |    1 
 eims-ui/packages/@core/base/typings/package.json                                                                                               |   44 
 eims-ui/playground/src/adapter/component/index.ts                                                                                              |  169 
 eims-ui/packages/@core/base/icons/package.json                                                                                                 |   41 
 eims/script/sql/update/oracle/update_5.1.2-5.2.0.sql                                                                                           |    9 
 eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js                                                                         |   93 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java                                               |   26 
 eims-ui/apps/web-naive/.env                                                                                                                    |    5 
 eims-ui/internal/tailwind-config/src/postcss.config.ts                                                                                         |   15 
 eims-ui/apps/web-ele/src/layouts/index.ts                                                                                                      |    6 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java                                                      |   29 
 eims-ui/packages/effects/layouts/src/basic/tabbar/tabbar.vue                                                                                   |   72 
 /dev/null                                                                                                                                      |  369 
 eims-ui/packages/@core/ui-kit/shadcn-ui/package.json                                                                                           |   54 
 eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue                                                                     |   32 
 eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue                                                           |   24 
 eims-ui/apps/web-antd/src/components/tinymce/src/tinymce.ts                                                                                    |   11 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java                                    |  176 
 eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts                                                                 |  113 
 eims-ui/packages/effects/access/src/accessible.ts                                                                                              |  100 
 eims-ui/packages/@core/base/design/package.json                                                                                                |   41 
 eims-ui/packages/utils/src/helpers/generate-routes-frontend.ts                                                                                 |   58 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java                 |   29 
 eims-ui/apps/web-antd/src/views/_core/authentication/code-login.vue                                                                            |  138 
 eims-ui/playground/src/store/auth.ts                                                                                                           |  117 
 2,595 files changed, 302,023 insertions(+), 369 deletions(-)

diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index 69d7c74..0000000
--- a/NOTICE
+++ /dev/null
@@ -1,369 +0,0 @@
-Gitblit
-Copyright 2011 gitblit.com
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-This is an aggregated NOTICE file for the projects included
-in this distribution or linked to by this distribution.
-
----------------------------------------------------------------------------
-Bootstrap
----------------------------------------------------------------------------
-   Bootstrap, released under the
-   Apache Software License, Version 2.0.
-
-   http://twitter.github.com/bootstrap
-
----------------------------------------------------------------------------
-google-code-prettify
----------------------------------------------------------------------------
-   google-code-prettify, released under the
-   Apache Software License, Version 2.0.
-
-   http://code.google.com/p/google-code-prettify
-
----------------------------------------------------------------------------
-Commons Daemon
----------------------------------------------------------------------------
-   Commons Daemon, released under the
-   Apache Software License, Version 2.0.
-
-   http://commons.apache.org/daemon
-   
----------------------------------------------------------------------------
-JGit
----------------------------------------------------------------------------
-   JGit, released under the
-   Eclipse Distribution License 1.0.
-
-   http://eclipse.org/jgit
-   
----------------------------------------------------------------------------
-Apache Wicket
----------------------------------------------------------------------------
-   Apache Wicket, released under the
-   Apache Software License, Version 2.0.
-
-   http://wicket.apache.org
-   
----------------------------------------------------------------------------
-Jetty
----------------------------------------------------------------------------
-   Jetty, released under the
-   Apache Software License, Version 2.0.
-
-   http://eclipse.org/jetty
-
----------------------------------------------------------------------------
-Apache Lucene
----------------------------------------------------------------------------
-   Apache Lucene, released under the
-   Apache Software License, Version 2.0.
-
-   http://lucene.apache.org
-
----------------------------------------------------------------------------
-Groovy
----------------------------------------------------------------------------
-   Groovy, released under the
-   Apache Software License, Version 2.0.
-
-   http://groovy.codehaus.org
-
----------------------------------------------------------------------------
-SLF4J
----------------------------------------------------------------------------
-   SLF4J, released under the
-   MIT/X11 License.
-
-   http://www.slf4j.org
-   
----------------------------------------------------------------------------
-Log4j
----------------------------------------------------------------------------
-   Log4j, released under the
-   Apache Software License, Version 2.0.
-
-   http://logging.apache.org/log4j   
- 
----------------------------------------------------------------------------
-BouncyCastle
----------------------------------------------------------------------------
-   BouncyCastle, released under the
-   MIT/X11 License.
-
-   http://www.bouncycastle.org
-   
----------------------------------------------------------------------------
-JSch
----------------------------------------------------------------------------
-   JSch - Java Secure Channel, released under the
-   BSD License.
-
-   http://www.jcraft.com/jsch
-
----------------------------------------------------------------------------
-Rome
----------------------------------------------------------------------------
-   Rome RSS and Atom Java Utilities, released under the
-   Apache Software License, Version 1.1.
-
-   http://rome.dev.java.net
-
----------------------------------------------------------------------------
-jdom
----------------------------------------------------------------------------
-   jdom xml library, released under the
-   Apache-style Software License.
-
-   http://www.jdom.org
-
----------------------------------------------------------------------------
-google-gson
----------------------------------------------------------------------------
-   google-gson, released under the
-   Apache-style Software License.
-
-   http://code.google.com/p/google-gson
-
----------------------------------------------------------------------------
-javamail
----------------------------------------------------------------------------
-   javamail, released under multiple licenses
-   CDDL-1.0, BSD, GPL-2.0, GNU-Classpath.
-
-   http://kenai.com/projects/javamail
-
----------------------------------------------------------------------------
-JUnit
----------------------------------------------------------------------------
-   JUnit, released under the
-   Common Public License.
-
-   http://junit.org
-
----------------------------------------------------------------------------
-Fancybox image viewer
----------------------------------------------------------------------------
-   Fancybox image viewer, released under the
-   MIT and GPL Licenses.
-
-   http://fancybox.net
-   
----------------------------------------------------------------------------
-FatCow Icons
----------------------------------------------------------------------------
-   FatCow Icons, released under the
-   Creative Commons CC-BY License.
-
-   http://www.fatcow.com/free-icons
-
----------------------------------------------------------------------------
-Git logo
----------------------------------------------------------------------------
-   Git logo, released under the
-   Creative Commons CC-BY License.
-
-   http://henrik.nyh.se/2007/06/alternative-git-logo-and-favicon
-
----------------------------------------------------------------------------
-Git logo
----------------------------------------------------------------------------
-   Git logo, released under the
-   Creative Commons Attribution 3.0 Unported License.
-
-   http://git-scm.com/downloads/logos
-   
----------------------------------------------------------------------------
-magnifying glass search icon
----------------------------------------------------------------------------
-   magnifying glass search icon, released under the
-   Creative Commons CC-BY License.
-
-   http://gnome.org
-
----------------------------------------------------------------------------
-GLYHPICONS
----------------------------------------------------------------------------
-   GLPYHICONS, released under the
-   Creative Commons CC-BY License.
-
-   http://glyphicons.com
-      
----------------------------------------------------------------------------
-UnboundID
----------------------------------------------------------------------------
-   UnboundID, released under the
-   GNU LESSER GENERAL PUBLIC LICENSE.
-
-   http://www.unboundid.com
-
----------------------------------------------------------------------------
-JCalendar
----------------------------------------------------------------------------
-   JCalendar, released under the
-   GNU LESSER GENERAL PUBLIC LICENSE.
-
-   http://www.toedter.com/en/jcalendar
-   
----------------------------------------------------------------------------
-Commons-Compress
----------------------------------------------------------------------------
-   Commons-Compress, released under the
-   Apache Software License, Version 2.0.
-
-   http://commons.apache.org/compress
-
----------------------------------------------------------------------------
-XZ for Java
----------------------------------------------------------------------------
-   XZ for Java, released under the
-   Public Domain
-
-   http://tukaani.org/xz/java.html
-
----------------------------------------------------------------------------
-Iconic
----------------------------------------------------------------------------
-   Iconic, release under the
-   Creative Commons Share Alike 3.0 License.
-   
-   http://somerandomdude.com/work/iconic
-   
----------------------------------------------------------------------------
-AngularJS
----------------------------------------------------------------------------
-   AngularJS, release under the
-   MIT License.
-   
-   http://angularjs.org/   
-   
----------------------------------------------------------------------------
-FreeMarker
----------------------------------------------------------------------------
-   FreeMarker, release under a
-   modified BSD License. (http://www.freemarker.org/docs/app_license.html)
-   
-   http://www.freemarker.org/
-
----------------------------------------------------------------------------
-Waffle
----------------------------------------------------------------------------
-   Waffle, release under the
-   Eclipse Public License, version 1.0
-   
-   http://dblock.github.io/waffle
-
----------------------------------------------------------------------------
-JNA
----------------------------------------------------------------------------
-   JNA, release under the
-   Lesser GNU Public License, version 2.1
-   
-   https://github.com/twall/jna
-   
----------------------------------------------------------------------------
-Guava
----------------------------------------------------------------------------
-   Guava, release under the
-   Apache License 2.0.
-   
-   https://code.google.com/p/guava-libraries
-
----------------------------------------------------------------------------
-libpam4j
----------------------------------------------------------------------------
-   libpam4j, release under the
-   MIT license.
-   
-   https://github.com/kohsuke/libpam4j
-
----------------------------------------------------------------------------
-commons-codec
----------------------------------------------------------------------------
-   commons-codec, release under the
-   Apache License 2.0.
-   
-   http://commons.apache.org/proper/commons-codec
-
----------------------------------------------------------------------------
-pegdown
----------------------------------------------------------------------------
-   pegdown, release under the
-   Apache License 2.0.
-   
-   https://github.com/sirthias/pegdown
-
----------------------------------------------------------------------------
-font-awesome
----------------------------------------------------------------------------
-   font-awesome, release under the
-   SIL OFL 1.1.
-   
-   https://github.com/FortAwesome/Font-Awesome
-
----------------------------------------------------------------------------
-AUI (excerpts)
----------------------------------------------------------------------------
-   AUI, release under the
-   Apache License 2.0
-   
-   https://bitbucket.org/atlassian/aui
-
----------------------------------------------------------------------------
-Jedis
----------------------------------------------------------------------------
-   Jedis, release under the
-   MIT license
-   
-   https://github.com/xetorthio/jedis
-
----------------------------------------------------------------------------
-args4j
----------------------------------------------------------------------------
-   args4j, release under the
-   Apache License 2.0
-   
-   http://args4j.kohsuke.org
-
----------------------------------------------------------------------------
-jQuery
----------------------------------------------------------------------------
-   jQuery, release under the
-   MIT License
-   
-   https://jquery.org
-
----------------------------------------------------------------------------
-flotr2
----------------------------------------------------------------------------
-   flotr2, release under the
-   BSD License
-   
-   http://humblesoftware.com/flotr2
-
----------------------------------------------------------------------------
-Mina SSHD
----------------------------------------------------------------------------
-   Mina SSHD, release under the 
-   Apache License 2.0
-
-   https://mina.apache.org
-
----------------------------------------------------------------------------
-pf4j
----------------------------------------------------------------------------
-   pf4j, release under the 
-   Apache License 2.0
-
-   https://github.com/decebals/pf4j
-
----------------------------------------------------------------------------
-google-guice
----------------------------------------------------------------------------
-   google-guice, release under the 
-   Apache License 2.0
-
-   https://code.google.com/p/google-guice
-   
\ No newline at end of file
diff --git a/eims-ui/.editorconfig b/eims-ui/.editorconfig
new file mode 100644
index 0000000..5b1a804
--- /dev/null
+++ b/eims-ui/.editorconfig
@@ -0,0 +1,21 @@
+# 鍛婅瘔EditorConfig鎻掍欢锛岃繖鏄牴鏂囦欢锛屼笉鐢ㄧ户缁線涓婃煡鎵�
+root = true
+
+# 鍖归厤鍏ㄩ儴鏂囦欢
+[*]
+# 缂╄繘椋庢牸锛屽彲閫塻pace銆乼ab
+indent_style = space
+# 缂╄繘鐨勭┖鏍兼暟
+indent_size = 2
+# 璁剧疆瀛楃闆�
+charset = utf-8
+# 缁撳熬鎹㈣绗︼紝鍙�塴f銆乧r銆乧rlf
+end_of_line = lf
+# 鍦ㄦ枃浠剁粨灏炬彃鍏ユ柊琛�
+trim_trailing_whitespace = true
+# 鍒犻櫎涓�琛屼腑鐨勫墠鍚庣┖鏍�
+insert_final_newline = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/eims-ui/.env.development b/eims-ui/.env.development
new file mode 100644
index 0000000..f4d6da3
--- /dev/null
+++ b/eims-ui/.env.development
@@ -0,0 +1,32 @@
+# 椤甸潰鏍囬
+VITE_APP_TITLE = 鏅鸿兘璁惧绠$悊绯荤粺
+
+# 寮�鍙戠幆澧冮厤缃�
+VITE_APP_ENV = 'development'
+
+# 寮�鍙戠幆澧�
+VITE_APP_BASE_API = '/dev-api'
+
+# 搴旂敤璁块棶璺緞 渚嬪浣跨敤鍓嶇紑 /admin/
+VITE_APP_CONTEXT_PATH = '/'
+
+# 鐩戞帶鍦板潃
+VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
+
+# SnailJob 鎺у埗鍙板湴鍧�
+VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
+
+VITE_APP_PORT = 80
+
+# 鎺ュ彛鍔犲瘑鍔熻兘寮�鍏�(濡傞渶鍏抽棴 鍚庣涔熷繀椤诲搴斿叧闂�)
+VITE_APP_ENCRYPT = false
+# 鎺ュ彛鍔犲瘑浼犺緭 RSA 鍏挜涓庡悗绔В瀵嗙閽ュ搴� 濡傛洿鎹㈤渶鍓嶅悗绔竴鍚屾洿鎹�
+VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 鎺ュ彛鍝嶅簲瑙e瘑 RSA 绉侀挜涓庡悗绔姞瀵嗗叕閽ュ搴� 濡傛洿鎹㈤渶鍓嶅悗绔竴鍚屾洿鎹�
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
+
+# 瀹㈡埛绔痠d
+VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
+
+# websocket 寮�鍏� 榛樿浣跨敤sse鎺ㄩ��
+VITE_APP_WEBSOCKET = false
diff --git a/eims-ui/.env.production b/eims-ui/.env.production
new file mode 100644
index 0000000..1c3f9dc
--- /dev/null
+++ b/eims-ui/.env.production
@@ -0,0 +1,35 @@
+# 椤甸潰鏍囬
+VITE_APP_TITLE = 鏅鸿兘璁惧绠$悊绯荤粺
+
+# 鐢熶骇鐜閰嶇疆
+VITE_APP_ENV = 'production'
+
+# 搴旂敤璁块棶璺緞 渚嬪浣跨敤鍓嶇紑 /admin/
+VITE_APP_CONTEXT_PATH = '/'
+
+# 鐩戞帶鍦板潃
+VITE_APP_MONITOR_ADMIN = '/admin/applications'
+
+# SnailJob 鎺у埗鍙板湴鍧�
+VITE_APP_SNAILJOB_ADMIN = '/snail-job'
+
+# 鐢熶骇鐜
+VITE_APP_BASE_API = '/prod-api'
+
+# 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
+VITE_BUILD_COMPRESS = gzip
+
+VITE_APP_PORT = 80
+
+# 鎺ュ彛鍔犲瘑鍔熻兘寮�鍏�(濡傞渶鍏抽棴 鍚庣涔熷繀椤诲搴斿叧闂�)
+VITE_APP_ENCRYPT = true
+# 鎺ュ彛鍔犲瘑浼犺緭 RSA 鍏挜涓庡悗绔В瀵嗙閽ュ搴� 濡傛洿鎹㈤渶鍓嶅悗绔竴鍚屾洿鎹�
+VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+# 鎺ュ彛鍝嶅簲瑙e瘑 RSA 绉侀挜涓庡悗绔姞瀵嗗叕閽ュ搴� 濡傛洿鎹㈤渶鍓嶅悗绔竴鍚屾洿鎹�
+VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
+
+# 瀹㈡埛绔痠d
+VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
+
+# websocket 寮�鍏� 榛樿浣跨敤sse鎺ㄩ��
+VITE_APP_WEBSOCKET = false
diff --git a/eims-ui/.eslintignore b/eims-ui/.eslintignore
new file mode 100644
index 0000000..e74db40
--- /dev/null
+++ b/eims-ui/.eslintignore
@@ -0,0 +1,17 @@
+*.sh
+node_modules
+*.md
+*.woff
+*.ttf
+.vscode
+.idea
+dist
+/public
+/docs
+.husky
+.local
+/bin
+.eslintrc.cjs
+prettier.config.js
+src/assets
+tailwind.config.js
diff --git a/eims-ui/.eslintrc-auto-import.json b/eims-ui/.eslintrc-auto-import.json
new file mode 100644
index 0000000..a6661b6
--- /dev/null
+++ b/eims-ui/.eslintrc-auto-import.json
@@ -0,0 +1,312 @@
+{
+  "globals": {
+    "ComponentInternalInstance": true,
+    "TransferKey": true,
+    "ElFormRules": true,
+    "CheckboxValueType": true,
+    "PropType": true,
+    "DateModelType": true,
+    "UploadFile": true,
+    "ElFormInstance": true,
+    "ElTableInstance": true,
+    "ElTreeInstance": true,
+    "ElTreeSelectInstance": true,
+    "ElSelectInstance": true,
+    "ElUploadInstance": true,
+    "ElCardInstance": true,
+    "ElDialogInstance": true,
+    "ElInputInstance": true,
+    "ElInputNumberInstance": true,
+    "ElRadioInstance": true,
+    "ElRadioGroupInstance": true,
+    "ElRadioButtonInstance": true,
+    "ElCheckboxInstance": true,
+    "ElCheckboxGroupInstance": true,
+    "ElSwitchInstance": true,
+    "ElDatePickerInstance": true,
+    "ElTimePickerInstance": true,
+    "ElTimeSelectInstance": true,
+    "ElScrollbarInstance": true,
+    "ElCascaderInstance": true,
+    "ElColorPickerInstance": true,
+    "ElRateInstance": true,
+    "ElSliderInstance": true,
+    "useRouter": true,
+    "useRoute": true,
+    "EffectScope": true,
+    "ElTable": true,
+    "ElSelect": true,
+    "ElUpload": true,
+    "ElForm": true,
+    "ElTree": true,
+    "ElMessage": true,
+    "ElMessageBox": true,
+    "asyncComputed": true,
+    "autoResetRef": true,
+    "computed": true,
+    "computedAsync": true,
+    "computedEager": true,
+    "computedInject": true,
+    "computedWithControl": true,
+    "controlledComputed": true,
+    "controlledRef": true,
+    "createApp": true,
+    "createEventHook": true,
+    "createGlobalState": true,
+    "createInjectionState": true,
+    "createReactiveFn": true,
+    "createSharedComposable": true,
+    "createUnrefFn": true,
+    "customRef": true,
+    "debouncedRef": true,
+    "debouncedWatch": true,
+    "defineAsyncComponent": true,
+    "defineComponent": true,
+    "eagerComputed": true,
+    "effectScope": true,
+    "extendRef": true,
+    "getCurrentInstance": true,
+    "getCurrentScope": true,
+    "h": true,
+    "ignorableWatch": true,
+    "inject": true,
+    "isDefined": true,
+    "isProxy": true,
+    "isReactive": true,
+    "isReadonly": true,
+    "isRef": true,
+    "makeDestructurable": true,
+    "markRaw": true,
+    "nextTick": true,
+    "onActivated": true,
+    "onBeforeMount": true,
+    "onBeforeUnmount": true,
+    "onBeforeUpdate": true,
+    "onClickOutside": true,
+    "onDeactivated": true,
+    "onErrorCaptured": true,
+    "onKeyStroke": true,
+    "onLongPress": true,
+    "onMounted": true,
+    "onRenderTracked": true,
+    "onRenderTriggered": true,
+    "onScopeDispose": true,
+    "onServerPrefetch": true,
+    "onStartTyping": true,
+    "onUnmounted": true,
+    "onUpdated": true,
+    "pausableWatch": true,
+    "provide": true,
+    "reactify": true,
+    "reactifyObject": true,
+    "reactive": true,
+    "reactiveComputed": true,
+    "reactiveOmit": true,
+    "reactivePick": true,
+    "readonly": true,
+    "ref": true,
+    "refAutoReset": true,
+    "refDebounced": true,
+    "refDefault": true,
+    "refThrottled": true,
+    "refWithControl": true,
+    "resolveComponent": true,
+    "resolveDirective": true,
+    "resolveRef": true,
+    "resolveUnref": true,
+    "shallowReactive": true,
+    "shallowReadonly": true,
+    "shallowRef": true,
+    "syncRef": true,
+    "syncRefs": true,
+    "templateRef": true,
+    "throttledRef": true,
+    "throttledWatch": true,
+    "toRaw": true,
+    "toReactive": true,
+    "toRef": true,
+    "toRefs": true,
+    "triggerRef": true,
+    "tryOnBeforeMount": true,
+    "tryOnBeforeUnmount": true,
+    "tryOnMounted": true,
+    "tryOnScopeDispose": true,
+    "tryOnUnmounted": true,
+    "unref": true,
+    "unrefElement": true,
+    "until": true,
+    "useActiveElement": true,
+    "useArrayEvery": true,
+    "useArrayFilter": true,
+    "useArrayFind": true,
+    "useArrayFindIndex": true,
+    "useArrayFindLast": true,
+    "useArrayJoin": true,
+    "useArrayMap": true,
+    "useArrayReduce": true,
+    "useArraySome": true,
+    "useArrayUnique": true,
+    "useAsyncQueue": true,
+    "useAsyncState": true,
+    "useAttrs": true,
+    "useBase64": true,
+    "useBattery": true,
+    "useBluetooth": true,
+    "useBreakpoints": true,
+    "useBroadcastChannel": true,
+    "useBrowserLocation": true,
+    "useCached": true,
+    "useClipboard": true,
+    "useCloned": true,
+    "useColorMode": true,
+    "useConfirmDialog": true,
+    "useCounter": true,
+    "useCssModule": true,
+    "useCssVar": true,
+    "useCssVars": true,
+    "useCurrentElement": true,
+    "useCycleList": true,
+    "useDark": true,
+    "useDateFormat": true,
+    "useDebounce": true,
+    "useDebounceFn": true,
+    "useDebouncedRefHistory": true,
+    "useDeviceMotion": true,
+    "useDeviceOrientation": true,
+    "useDevicePixelRatio": true,
+    "useDevicesList": true,
+    "useDisplayMedia": true,
+    "useDocumentVisibility": true,
+    "useDraggable": true,
+    "useDropZone": true,
+    "useElementBounding": true,
+    "useElementByPoint": true,
+    "useElementHover": true,
+    "useElementSize": true,
+    "useElementVisibility": true,
+    "useEventBus": true,
+    "useEventListener": true,
+    "useEventSource": true,
+    "useEyeDropper": true,
+    "useFavicon": true,
+    "useFetch": true,
+    "useFileDialog": true,
+    "useFileSystemAccess": true,
+    "useFocus": true,
+    "useFocusWithin": true,
+    "useFps": true,
+    "useFullscreen": true,
+    "useGamepad": true,
+    "useGeolocation": true,
+    "useIdle": true,
+    "useImage": true,
+    "useInfiniteScroll": true,
+    "useIntersectionObserver": true,
+    "useInterval": true,
+    "useIntervalFn": true,
+    "useKeyModifier": true,
+    "useLastChanged": true,
+    "useLocalStorage": true,
+    "useMagicKeys": true,
+    "useManualRefHistory": true,
+    "useMediaControls": true,
+    "useMediaQuery": true,
+    "useMemoize": true,
+    "useMemory": true,
+    "useMounted": true,
+    "useMouse": true,
+    "useMouseInElement": true,
+    "useMousePressed": true,
+    "useMutationObserver": true,
+    "useNavigatorLanguage": true,
+    "useNetwork": true,
+    "useNow": true,
+    "useObjectUrl": true,
+    "useOffsetPagination": true,
+    "useOnline": true,
+    "usePageLeave": true,
+    "useParallax": true,
+    "usePermission": true,
+    "usePointer": true,
+    "usePointerLock": true,
+    "usePointerSwipe": true,
+    "usePreferredColorScheme": true,
+    "usePreferredContrast": true,
+    "usePreferredDark": true,
+    "usePreferredLanguages": true,
+    "usePreferredReducedMotion": true,
+    "usePrevious": true,
+    "useRafFn": true,
+    "useRefHistory": true,
+    "useResizeObserver": true,
+    "useScreenOrientation": true,
+    "useScreenSafeArea": true,
+    "useScriptTag": true,
+    "useScroll": true,
+    "useScrollLock": true,
+    "useSessionStorage": true,
+    "useShare": true,
+    "useSlots": true,
+    "useSorted": true,
+    "useSpeechRecognition": true,
+    "useSpeechSynthesis": true,
+    "useStepper": true,
+    "useStorage": true,
+    "useStorageAsync": true,
+    "useStyleTag": true,
+    "useSupported": true,
+    "useSwipe": true,
+    "useTemplateRefsList": true,
+    "useTextDirection": true,
+    "useTextSelection": true,
+    "useTextareaAutosize": true,
+    "useThrottle": true,
+    "useThrottleFn": true,
+    "useThrottledRefHistory": true,
+    "useTimeAgo": true,
+    "useTimeout": true,
+    "useTimeoutFn": true,
+    "useTimeoutPoll": true,
+    "useTimestamp": true,
+    "useTitle": true,
+    "useToNumber": true,
+    "useToString": true,
+    "useToggle": true,
+    "useTransition": true,
+    "useUrlSearchParams": true,
+    "useUserMedia": true,
+    "useVModel": true,
+    "useVModels": true,
+    "useVibrate": true,
+    "useVirtualList": true,
+    "useWakeLock": true,
+    "useWebNotification": true,
+    "useWebSocket": true,
+    "useWebWorker": true,
+    "useWebWorkerFn": true,
+    "useWindowFocus": true,
+    "useWindowScroll": true,
+    "useWindowSize": true,
+    "watch": true,
+    "watchArray": true,
+    "watchAtMost": true,
+    "watchDebounced": true,
+    "watchEffect": true,
+    "watchIgnorable": true,
+    "watchOnce": true,
+    "watchPausable": true,
+    "watchPostEffect": true,
+    "watchSyncEffect": true,
+    "watchThrottled": true,
+    "watchTriggerable": true,
+    "watchWithFilter": true,
+    "whenever": true,
+    "ImportOption": true,
+    "TreeType": true,
+    "FieldOption": true,
+    "PageData": true,
+    "storeToRefs": true,
+    "DictDataOption": true,
+    "UploadOption": true
+  }
+}
diff --git a/eims-ui/.eslintrc.cjs b/eims-ui/.eslintrc.cjs
new file mode 100644
index 0000000..6042c39
--- /dev/null
+++ b/eims-ui/.eslintrc.cjs
@@ -0,0 +1,51 @@
+module.exports = {
+  env: {
+    browser: true,
+    node: true,
+    es6: true
+  },
+  parser: 'vue-eslint-parser',
+  extends: [
+    'plugin:vue/vue3-recommended',
+    './.eslintrc-auto-import.json',
+    'plugin:@typescript-eslint/recommended',
+    'prettier',
+    'plugin:prettier/recommended'
+  ],
+  parserOptions: {
+    ecmaVersion: '2020',
+    sourceType: 'module',
+    project: './tsconfig.*?.json',
+    parser: '@typescript-eslint/parser'
+  },
+  plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'],
+  rules: {
+    '@typescript-eslint/no-empty-function': 'off',
+    '@typescript-eslint/no-explicit-any': 'off',
+    '@typescript-eslint/no-unused-vars': 'off',
+    '@typescript-eslint/no-this-alias': 'off',
+
+    // vue
+    'vue/multi-word-component-names': 'off',
+    'vue/valid-define-props': 'off',
+    'vue/no-v-model-argument': 'off',
+    'prefer-rest-params': 'off',
+    // prettier
+    'prettier/prettier': 'error',
+    '@typescript-eslint/ban-types': [
+      'error',
+      {
+        // 鍏抽棴绌虹被鍨嬫鏌� {}
+        extendDefaults: true,
+        types: {
+          '{}': false,
+          Function: false
+        }
+      }
+    ]
+  },
+  globals: {
+    DialogOption: 'readonly',
+    OptionType: 'readonly'
+  }
+};
diff --git a/eims-ui/.gitignore b/eims-ui/.gitignore
new file mode 100644
index 0000000..1fd56f0
--- /dev/null
+++ b/eims-ui/.gitignore
@@ -0,0 +1,29 @@
+.DS_Store
+.history
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
+pnpm-lock.yaml
+
+# 缂栬瘧鐢熸垚鐨勬枃浠�
+auto-imports.d.ts
+components.d.ts
diff --git a/eims-ui/.prettierignore b/eims-ui/.prettierignore
new file mode 100644
index 0000000..d251d2e
--- /dev/null
+++ b/eims-ui/.prettierignore
@@ -0,0 +1,9 @@
+/dist/*
+.local
+.output.js
+/node_modules/**
+
+**/*.svg
+**/*.sh
+
+/public/*
\ No newline at end of file
diff --git a/eims-ui/.prettierrc b/eims-ui/.prettierrc
new file mode 100644
index 0000000..6ca3ce5
--- /dev/null
+++ b/eims-ui/.prettierrc
@@ -0,0 +1,20 @@
+{
+  "printWidth": 150,
+  "tabWidth": 2,
+  "useTabs": false,
+  "semi": true,
+  "singleQuote": true,
+  "quoteProps": "preserve",
+  "jsxSingleQuote": false,
+  "bracketSameLine": false,
+  "trailingComma": "none",
+  "bracketSpacing": true,
+  "embeddedLanguageFormatting": "auto",
+  "arrowParens": "always",
+  "requirePragma": false,
+  "insertPragma": false,
+  "proseWrap": "preserve",
+  "htmlWhitespaceSensitivity": "css",
+  "vueIndentScriptAndStyle": false,
+  "endOfLine": "auto"
+}
diff --git a/eims-ui/CHANGELOG.md b/eims-ui/CHANGELOG.md
new file mode 100644
index 0000000..834f825
--- /dev/null
+++ b/eims-ui/CHANGELOG.md
@@ -0,0 +1,114 @@
+# 1.1.4
+
+**Features**
+
+- 閫氱敤鐨剉xe-table鎺掑簭浜嬩欢(鎺掑簭閫昏緫鏀逛负鍦ㄦ帓搴忎簨浠朵腑澶勭悊鑰岄潪鍦╝pi澶勭悊)
+
+**BUG FIXES**
+
+- 瀛楀吀椤逛负绌烘椂getDict鏂规硶鏃犻檺璋冪敤鎺ュ彛((鏃犲鍏煎 涓嶇粰瀛楀吀item鏈潵灏辨槸閿欒鐢ㄦ硶))
+
+# 1.1.3
+
+**REFACTOR**
+
+- 閲嶆瀯: 鍒ゆ柇vxe-table鐨勫閫夋鏄惁閫変腑
+
+**Bug Fixes**
+
+- 鑺傜偣鏍戝湪缂栬緫 & 绌烘暟缁�(涓嶅嬀閫�)鎯呭喌 鍕鹃�夎妭鐐逛細閫犳垚watch寤惰繜瑙﹀彂 瀵艰嚧浼氬甫涓婄埗鑺傜偣id閫犳垚id閲嶅
+- 鑺傜偣鏍戝湪鑺傜偣鐙珛鎯呭喌涓嬬殑鎺у埗鍙皐arning: Invalid prop: type check failed for prop "value". Expected Array, got Object
+
+**Others**
+
+- 瑙掕壊绠$悊 浼樺寲Drawer甯冨眬
+- unplugin-vue-components鎻掍欢(榛樿鏈紑鍚�) 闇�瑕佹帓闄utton缁勪欢 鍏ㄥ眬宸茬粡榛樿瀵煎叆浜�
+
+**BUG FIXES**
+
+- 鎿嶄綔鏃ュ織璇︽儏 鍦╠escription缁勪欢涓璲son棰勮鏍峰紡寮傚父
+- 寰湇鍔$増鏈� 鍖洪棿鏌ヨ鍜屼腑鏂囨悳绱㈡潯浠朵竴璧蜂娇鐢� 鏃犳硶姝g‘鏌ヨ
+
+# 1.1.2
+
+**Features**
+
+- Options杞珽num宸ュ叿鍑芥暟
+
+**OTHERS**
+
+- 鑿滃崟绠$悊 鏀逛负铏氭嫙婊氬姩
+- 绉婚櫎requestClient鐨勪竴浜涘啑浣欏弬鏁�
+- 涓诲姩閫�鍑虹櫥褰�(鍙充笂瑙掍釜浜洪�夐」)涓嶉渶瑕佸甫璺宠浆鍦板潃
+
+**BUG FIXES**
+
+- 璇█ 婕忓姞Content-Language璇锋眰澶�
+- 鐢ㄦ埛绠$悊/宀椾綅绠$悊 宸﹁竟閮ㄩ棬鏍戦敊璇痚mit瀵艰嚧浼氳皟鐢ㄤ袱娆″垪琛╝pi
+
+# 1.1.1
+
+**REFACTOR**
+
+- 浣跨敤VxeTable閲嶆瀯OAuth璐﹀彿缁戝畾鍒楄〃(鏇夸唬antdv鐨凾able)
+- commonDownloadExcel鏂规硶 鏀寔澶勭悊鍖洪棿閫夋嫨鍣ㄥ瓧娈靛鍑篹xcel
+
+**BUG FIXES**
+
+- 淇鍦∕odal/Drawer涓娇鐢╒xeTable鏃�, 绗簩娆℃墦寮�琛ㄥ崟鍙傛暟渚濇棫涓虹涓�娆℃彁浜ょ殑鍙傛暟
+
+**OTHERS**
+
+- 搴熷純downloadExcel鏂规硶 缁熶竴浣跨敤commonDownloadExcel鏂规硶
+
+# 1.1.0
+
+**FEATURES**
+
+- 鏀寔绂荤嚎鍥炬爣鍔熻兘(鍏ㄥ眬鍙湪鍐呯綉鐜涓娇鐢�)
+
+**BUG FIXES**
+
+- 鍦╒xeTable鍥哄畾鍒楁椂, getPopupContainer浼氬鑷村搴︿笉澶�, 寮瑰嚭灞傛牱寮忓紓甯� 瑙e喅鍔炴硶(灏嗗脊绐楀厓绱犳寕杞藉埌VXe婊氬姩瀹瑰櫒涓�)
+
+**OTHERS**
+
+- 浠g爜鐢熸垚 - 瀛楁淇℃伅淇敼 鏀逛负minWidth 闃叉鍦ㄩ珮鍒嗚鲸鐜囧睆骞曞嚭鐜扮┖鐧�
+
+# 1.0.0
+
+**FEATURES**
+
+- 鐢ㄦ埛绠$悊 鏂板浠庡弬鏁板彇榛樿瀵嗙爜
+- 鍏ㄥ眬琛ㄦ牸鍔犱笂id 鏂逛究杩涜缂撳瓨鍒楁帓搴忕殑鎿嶄綔
+- 鏀寔鑿滃崟鍚嶇Оi18n
+- 鐧诲綍椤� 楠岃瘉鐮佺櫥褰�
+- Markdown缂栬緫/棰勮缁勪欢(鍩轰簬vditor)
+- VxeTable鎼滅储琛ㄥ崟 enter鎻愪氦
+
+**BUG FIXES**
+
+- 鐧诲綍椤甸潰 鍏抽棴绉熸埛鍚庝笅鎷夋娌℃湁姝e父闅愯棌
+- 瀛楀吀绠$悊 鍏抽棴绉熸埛涓嶅簲鏄剧ず`鍚屾绉熸埛瀛楀吀`鎸夐挳
+- 鐧诲綍鏃ュ織 婕忔帀浜嗙櫥褰曟棩蹇楁棩鏈熸煡璇�
+- 鐧诲嚭鐩稿叧閫昏緫鍦ㄥ苟鍙�(闈瀉wait)鎯呭喌涓嬮噸澶嶆墽琛岀殑闂
+- VxeTable鍦ㄥ紑鍚�/鍏抽棴鏌ヨ琛ㄥ崟鏃� 闇�瑕佷娇鐢ㄤ笉鍚岀殑padding
+- VxeTable琛ㄦ牸鍒锋柊 榛樿涓簉eload 淇敼涓哄湪褰撳墠椤靛埛鏂�(query)
+- 宀椾綅绠$悊 閮ㄩ棬鍙傛暟閿欒
+- 瑙掕壊绠$悊 鑿滃崟鍒嗛厤 鑺傜偣鐙珛涓嬬殑鍥炴樉鍙婃彁浜ら棶棰�
+- 绉熸埛绠$悊 濂楅绠$悊 鍥炴樉鏃跺�檂宸查�変腑鑺傜偣`鏁伴噺涓�0
+- 鐢ㄦ埛绠$悊 鏇存柊鐢ㄦ埛鏃舵墦寮�drawer闇�瑕佸姞杞借閮ㄩ棬涓嬬殑宀椾綅淇℃伅
+
+**OTHERS**
+
+- 鐧诲綍椤� 绉熸埛閫夋嫨妗嗘诞灞傚浐瀹氶珮搴256px] 瓒呰繃楂樺害鑷姩婊氬姩
+- 琛ㄥ崟鐨凩abel榛樿鏂瑰悜鏀逛负`top` 鏀寔\n鎹㈣
+- 鎵�鏈夎〃鏍肩殑鎼滅储鍔犱笂allowClear灞炴�� 鏀寔娓呴櫎
+- vxe琛ㄦ牸loading 鍙姞杞借〃鏍� 涓嶅姞杞戒笂闈㈢殑琛ㄥ崟
+
+# 1.0.0-beta (2024-10-8)
+
+**FEATURES**
+
+- 鍩虹鍔熻兘宸茬粡寮�鍙戝畬姣�
+- 宸ヤ綔娴佺浉鍏虫ā鍧楃瓑寰呭悗绔噸鏋勫悗寮�鍙�
diff --git a/eims-ui/LICENSE b/eims-ui/LICENSE
new file mode 100644
index 0000000..cec5b42
--- /dev/null
+++ b/eims-ui/LICENSE
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) 2024-present, Vben
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/eims-ui/README.ja-JP.md b/eims-ui/README.ja-JP.md
new file mode 100644
index 0000000..baa4cc4
--- /dev/null
+++ b/eims-ui/README.ja-JP.md
@@ -0,0 +1,153 @@
+<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp"> </a> <br> <br>
+
+[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
+
+<h1>Vue Vben Admin</h1>
+</div>
+
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
+
+**鏃ユ湰瑾�** | [English](./README.md) | [涓枃](./README.zh-CN.md)
+
+## 绱逛粙
+
+Vue Vben Admin銇�佹渶鏂般伄`vue3`銆乣vite`銆乣TypeScript`銇仼銇富娴佹妧琛撱倰浣跨敤銇椼仸闁嬬櫤銇曘倢銇熴�佺劇鏂欍仹銈兗銉椼兂銈姐兗銈广伄涓兓寰岀銉嗐兂銉椼儸銉笺儓銇с仚銆傘仚銇愩伀浣裤亪銈嬩腑銉诲緦绔伄銉曘儹銉炽儓銈ㄣ兂銉夈偨銉儱銉笺偡銉с兂銇ㄣ仐銇︺�佸缈掋伄鍙傝�冦伀銈傘仾銈娿伨銇欍��
+
+## 銈€儍銉椼偘銉兗銉夐�氱煡
+
+銇撱倢銇渶鏂般儛銉笺偢銉с兂5.0銇с亗銈娿�佷互鍓嶃伄銉愩兗銈搞儳銉炽仺銇簰鎻涙�с亴銇傘倞銇俱仜銈撱�傛柊銇椼亜銉椼儹銈搞偋銈儓銈掗枊濮嬨仚銈嬪牬鍚堛伅銆佹渶鏂般儛銉笺偢銉с兂銈掍娇鐢ㄣ仚銈嬨亾銇ㄣ倰銇婂嫥銈併仐銇俱仚銆傚彜銇勩儛銉笺偢銉с兂銈掕〃绀恒仐銇熴亜鍫村悎銇�乕v2銉栥儵銉炽儊](https://github.com/vbenjs/vue-vben-admin/tree/v2)銈掍娇鐢ㄣ仐銇︺亸銇犮仌銇勩��
+
+## 鐗瑰敬
+
+- **鏈�鏂版妧琛撱偣銈裤儍銈�**: Vue 3銈刅ite銇仼銇渶鍏堢銉曘儹銉炽儓銈ㄣ兂銉夋妧琛撱仹闁嬬櫤
+- **TypeScript**: 銈€儣銉偙銉笺偡銉с兂瑕忔ā銇甁avaScript銇仧銈併伄瑷�瑾�
+- **銉嗐兗銉�**: 瑜囨暟銇儐銉笺優銈儵銉笺亴鍒╃敤鍙兘銇с�併偒銈广偪銉炪偆銈恒偑銉椼偡銉с兂銈傝眾瀵�
+- **鍥介殯鍖�**: 瀹屽叏銇唴钄靛浗闅涘寲銈点儩銉笺儓
+- **妯╅檺绠$悊**: 鍕曠殑銉兗銉堛儥銉笺偣銇ī闄愮敓鎴愩偨銉儱銉笺偡銉с兂銈掑唴钄�
+
+## 銉椼儸銉撱儱銉�
+
+- [Vben Admin](https://vben.pro/) - 銉曘儷銉愩兗銈搞儳銉炽伄涓浗瑾炪偟銈ゃ儓
+
+銉嗐偣銉堛偄銈偊銉炽儓: vben/123456
+
+<p align="center">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
+</p>
+
+### Gitpod銈掍娇鐢�
+
+Gitpod锛圙itHub鐢ㄣ伄鐒℃枡銈兂銉┿偆銉抽枊鐧虹挵澧冿級銇с儣銉偢銈с偗銉堛倰闁嬨亶銆併仚銇愩伀銈炽兗銉囥偅銉炽偘銈掗枊濮嬨仐銇俱仚銆�
+
+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
+
+## 銉夈偔銉ャ儭銉炽儓
+
+[銉夈偔銉ャ儭銉炽儓](https://doc.vben.pro/)
+
+## 銈ゃ兂銈广儓銉笺儷銇ㄤ娇鐢�
+
+- 銉椼儹銈搞偋銈儓銈炽兗銉夈倰鍙栧緱
+
+```bash
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+- 渚濆瓨闁總銇偆銉炽偣銉堛兗銉�
+
+```bash
+cd vue-vben-admin
+
+corepack enable
+
+pnpm install
+
+```
+
+- 瀹熻
+
+```bash
+pnpm dev
+```
+
+- 銉撱儷銉�
+
+```bash
+pnpm build
+```
+
+## 澶夋洿銉偘
+
+[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
+
+## 璨㈢尞鏂规硶
+
+銇斿弬鍔犮倰銇婂緟銇°仐銇︺亰銈娿伨銇欙紒[Issue銈掓彁鍑篯(https://github.com/anncwb/vue-vben-admin/issues/new/choose)銇欍倠銇嬨�丳ull Request銈掗�佷俊銇椼仸銇忋仩銇曘亜銆�
+
+**Pull Request:**
+
+1. 銈炽兗銉夈倰銉曘偐銉笺偗锛�
+2. 鑷垎銇儢銉┿兂銉併倰浣滄垚: `git checkout -b feat/xxxx`
+3. 澶夋洿銈掋偝銉熴儍銉�: `git commit -am 'feat(function): add xxxxx'`
+4. 銉栥儵銉炽儊銈掋儣銉冦偡銉�: `git push origin feat/xxxx`
+5. `pull request`銈掗�佷俊
+
+## Git璨㈢尞鎻愬嚭瑕忓墖
+
+- 鍙傝�� [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 瑕忓墖 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
+
+  - `feat` 鏂版鑳姐伄杩藉姞
+  - `fix` 鍟忛/銉愩偘銇慨姝�
+  - `style` 銈炽兗銉夈偣銈裤偆銉伀闁㈤�c仐銆佸疅琛岀祼鏋溿伀褰遍熆銇椼仾銇�
+  - `perf` 鏈�閬╁寲/銉戙儠銈┿兗銉炪兂銈瑰悜涓�
+  - `refactor` 銉儠銈°偗銈裤儶銉炽偘
+  - `revert` 澶夋洿銇彇銈婃秷銇�
+  - `test` 銉嗐偣銉堥枹閫�
+  - `docs` 銉夈偔銉ャ儭銉炽儓/娉ㄩ噲
+  - `chore` 渚濆瓨闁總銇洿鏂�/銈广偔銉c儠銈┿兗銉儑銈c兂銈拌ō瀹氥伄澶夋洿銇仼
+  - `ci` 缍欑稓鐨勩偆銉炽儐銈般儸銉笺偡銉с兂
+  - `types` 鍨嬪畾缇┿儠銈°偆銉伄澶夋洿
+  - `wip` 闁嬬櫤涓�
+
+## 銉栥儵銈︺偠銈点儩銉笺儓
+
+銉兗銈儷闁嬬櫤銇伅`Chrome 80+`銉栥儵銈︺偠銈掓帹濂ㄣ仐銇俱仚
+
+銉€儉銉炽儢銉┿偊銈躲倰銈点儩銉笺儓銇椼�両E銇偟銉濄兗銉堛仐銇俱仜銈�
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| 銈点儩銉笺儓銇椼仾銇� | 鏈�鏂�2銉愩兗銈搞儳銉� | 鏈�鏂�2銉愩兗銈搞儳銉� | 鏈�鏂�2銉愩兗銈搞儳銉� | 鏈�鏂�2銉愩兗銈搞儳銉� |
+
+## 銉°兂銉嗐儕銉�
+
+[@Vben](https://github.com/anncwb)
+
+## 銈广偪銉兼鍙�
+
+[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date)
+
+## 瀵勪粯
+
+銇撱伄銉椼儹銈搞偋銈儓銇屽焦銇珛銇ゃ仺鎬濄倧銈屻仧鍫村悎銆佷綔鑰呫伀銈炽兗銉掋兗銈掍竴鏉亰銇斻仯銇︺偟銉濄兗銉堛倰绀恒仚銇撱仺銇屻仹銇嶃伨銇欙紒
+
+![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)
+
+<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aed;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
+
+## 璨㈢尞鑰�
+
+<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
+ <img alt="Contributors"
+        src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
+</a>
+
+## Discord
+
+- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
+
+## 銉┿偆銈汇兂銈�
+
+[MIT 漏 Vben-2020](./LICENSE)
diff --git a/eims-ui/README.md b/eims-ui/README.md
new file mode 100644
index 0000000..e84c839
--- /dev/null
+++ b/eims-ui/README.md
@@ -0,0 +1,152 @@
+<div align="center"> <a href="https://github.com/anncwb/vue-vben-admin"> <img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp"> </a> <br> <br>
+
+[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
+
+<h1>Vue Vben Admin</h1>
+</div>
+
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
+
+**English** | [涓枃](./README.zh-CN.md) | [鏃ユ湰瑾瀅(./README.ja-JP.md)
+
+## Introduction
+
+Vue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference.
+
+## Upgrade Notice
+
+This is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2).
+
+## Feature
+
+- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite
+- **TypeScript**: A language for application-scale JavaScript
+- **Themes**: Multiple theme colors available with customizable options
+- **Internationalization**: Comprehensive built-in internationalization support
+- **Permissions**: Built-in solution for dynamic route-based permission generation
+
+## Preview
+
+- [Vben Admin](https://vben.pro/) - Full version Chinese site
+
+Test Account: vben/123456
+
+<p align="center">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview1.png">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview2.png">
+    <img alt="VbenAdmin Logo" width="100%" src="https://anncwb.github.io/anncwb/images/preview3.png">
+</p>
+
+### Use Gitpod
+
+Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately.
+
+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin)
+
+## Documentation
+
+[Document](https://doc.vben.pro/)
+
+## Install and use
+
+- Get the project code
+
+```bash
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+- Installation dependencies
+
+```bash
+cd vue-vben-admin
+
+corepack enable
+
+pnpm install
+```
+
+- run
+
+```bash
+pnpm dev
+```
+
+- build
+
+```bash
+pnpm build
+```
+
+## Change Log
+
+[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases)
+
+## How to contribute
+
+You are very welcome to join锛乕Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) Or submit a Pull Request銆�
+
+**Pull Request:**
+
+1. Fork code!
+2. Create your own branch: `git checkout -b feat/xxxx`
+3. Submit your changes: `git commit -am 'feat(function): add xxxxx'`
+4. Push your branch: `git push origin feat/xxxx`
+5. submit`pull request`
+
+## Git Contribution submission specification
+
+- reference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
+
+  - `feat` Add new features
+  - `fix` Fix the problem/BUG
+  - `style` The code style is related and does not affect the running result
+  - `perf` Optimization/performance improvement
+  - `refactor` Refactor
+  - `revert` Undo edit
+  - `test` Test related
+  - `docs` Documentation/notes
+  - `chore` Dependency update/scaffolding configuration modification etc.
+  - `ci` Continuous integration
+  - `types` Type definition file changes
+  - `wip` In development
+
+## Browser support
+
+The `Chrome 80+` browser is recommended for local development
+
+Support modern browsers, not IE
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## Maintainer
+
+[@Vben](https://github.com/anncwb)
+
+## Star History
+
+[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date)
+
+## Donate
+
+If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support!
+
+![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)
+
+<a style="display: block;width: 100px;height: 50px;line-height: 50px; color: #fff;text-align: center; background: #408aee;border-radius: 4px;" href="https://www.paypal.com/paypalme/cvvben">Paypal Me</a>
+
+## Contributor
+
+<a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
+  <img alt="Contributors"
+        src="https://opencollective.com/vbenjs/contributors.svg?button=false" />
+</a>
+
+## Discord
+
+- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions)
+
+## License
+
+[MIT 漏 Vben-2020](./LICENSE)
diff --git a/eims-ui/README.zh-CN.md b/eims-ui/README.zh-CN.md
new file mode 100644
index 0000000..c4cff38
--- /dev/null
+++ b/eims-ui/README.zh-CN.md
@@ -0,0 +1,197 @@
+[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE)
+
+## 鎻愮ず
+
+璇ヤ粨搴撲娇鐢╲ben鏈�鏂扮増鏈瑅5寮�鍙�, ~~鑰佺増鏈瑅2鍦板潃(涓嶇淮鎶�)~~ [鍓嶅線](https://gitee.com/dapppp/ruoyi-plus-vben)
+
+v5鐗堟湰閲囩敤鍒嗕粨(鍖�)鐩綍缁撴瀯, 鍏蜂綋寮�鍙戣矾寰勪负: `鏍圭洰褰�/apps/web-antd`
+
+鐩墠瀵瑰簲鍚庣鐗堟湰: **5.2.3/2.2.3**
+
+V1.1.0鐗堟湰宸叉敮鎸佺绾垮浘鏍�
+
+## 杩涘害
+
+**宸ヤ綔娴佺浉鍏虫ā鍧楃瓑寰呭悗绔噸鏋勫悗寮�鍙�**
+
+鍩虹鍔熻兘宸茬粡寮�鍙戝畬姣�
+
+馃憠 [鏇存柊鏃ュ織](https://gitee.com/dapppp/ruoyi-plus-vben5/blob/main/CHANGELOG.md)
+
+## 绠�浠�
+
+鍩轰簬 [vben5 & ant-design-vue](https://github.com/vbenjs/vue-vben-admin) 鐨� RuoYi-Vue-Plus 鍓嶇椤圭洰
+
+| 缁勪欢/妗嗘灦      | 鐗堟湰   |
+| :------------- | :----- |
+| vben           | 5.4.5  |
+| ant-design-vue | 4.2.5  |
+| vue            | 3.5.11 |
+
+瀵瑰簲鍚庣椤圭洰: **(鍒嗗竷寮� 5.X 鍒嗘敮 寰湇鍔� 2.鍒嗘敮)**
+
+鍒嗗竷寮� [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/)
+
+寰湇鍔� [RuoYi-Cloud-Plus](https://gitee.com/dromara/RuoYi-Cloud-Plus/tree/2.X/)
+
+## 棰勮
+
+admin 璐﹀彿: admin admin123
+
+[棰勮鍦板潃鐐硅繖閲宂(http://vben5.dapdap.top)
+
+## WX Group
+
+婕旂ず绔� - 寰俊缇よ彍鍗�
+
+## 鏂囨。
+
+[鏈鏋舵枃妗� 寮虹儓寤鸿闃呰](https://dapdap.top/)
+
+[Vben V5 鏂囨。鍦板潃](https://doc.vben.pro/)
+
+[RuoYi-Plus 鏂囨。鍦板潃](https://plus-doc.dromara.org/#/)
+
+## 棰勮鍥�
+
+![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/1.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/2.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/3.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/4.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/5.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/6.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/7.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/8.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/9.png) ![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben5/raw/main/scripts/preview/10.png)
+
+## 瀹夎浣跨敤
+
+鍓嶇疆鍑嗗鐜(鍙兘鐢╬npm)
+
+```json
+"packageManager": "pnpm",
+"engines": {
+  "node": ">=20.15.0",
+  "pnpm": "latest"
+},
+```
+
+- 鑾峰彇椤圭洰浠g爜
+
+```bash
+git clone https://gitee.com/dapppp/ruoyi-plus-vben5.git
+```
+
+- 瀹夎渚濊禆
+
+```bash
+cd ruoyi-plus-vben5
+
+pnpm install
+```
+
+- 鑿滃崟鍥炬爣鏇挎崲
+
+鍙傝�� [鑿滃崟鍥炬爣鏇挎崲](https://dapdap.top/guide/quick-start.html#%E8%8F%9C%E5%8D%95%E5%9B%BE%E6%A0%87%E5%AF%BC%E5%85%A5)
+
+- 鍏充簬浠g爜鐢熸垚
+
+V5鐗堟湰浠g爜鐢熸垚妯℃澘涓轰粯璐瑰姛鑳� [璇﹁](https://dapdap.top/other/template.html)
+
+- 鍏充簬涓�浜涚洃鎺х殑鍦板潃閰嶇疆(寰湇鍔$増鏈彲浠ヨ烦杩囪繖涓�灏忚妭)
+
+浣跨敤[RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus/tree/5.X/)娉ㄦ剰 `宸茬粡鍘婚櫎 admin/snailjob 鐨�.env 閰嶇疆` 鍙嚜琛屼慨鏀� 鏈変袱绉嶆柟寮�
+
+1. 淇敼婧愮爜`/views/monitor/admin` `views/monitor/snailjob`
+
+```html
+<!-- 淇敼鍦板潃 -->
+<template>
+  <iframe
+    class="size-full"
+    src="http://localhost:9090/admin/applications"
+  ></iframe>
+</template>
+```
+
+2. **鎺ㄨ崘** 浣跨敤鑿滃崟鑷閰嶇疆 (璺� cloud 鐗堟湰鎵撳紑鏂瑰紡涓�鑷�)
+
+![鍥剧墖](https://gitee.com/dapppp/ruoyi-plus-vben/raw/main/preview/鑿滃崟淇敼.png)
+
+浣跨敤鍐呭祵 iframe 鏂瑰紡闇�瑕佽В鍐宠法鍩熼棶棰� 鍙弬鑰僛nginx.conf](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/script/docker/nginx/conf/nginx.conf#LC87)閰嶇疆
+
+- 淇敼.env.development 閰嶇疆鏂囦欢
+- **娉ㄦ剰 RSA 鍏閽ヤ竴瀹氳淇敼鍜屽悗绔尮閰�**
+- RSA 鍏閽ヤ负涓ゅ `鍓嶇璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵筦 `鍚庣鍝嶅簲鍔犲瘑 鍓嶇瑙e瘑鏄竴瀵筦
+
+```properties
+# 绔彛鍙�
+VITE_PORT=5666
+# 鎵撳寘璺緞
+VITE_BASE=/
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=false
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=false
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鍚庡彴璇锋眰璺緞 鍏蜂綋鍦╲ite.config.mts閰嶇疆浠g悊
+VITE_GLOB_API_URL=/api
+# 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
+VITE_GLOB_ENABLE_ENCRYPT=true
+# RSA鍏挜 璇锋眰鍔犲瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PUBLIC_KEY=
+# RSA绉侀挜 鍝嶅簲瑙e瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PRIVATE_KEY=
+# 瀹㈡埛绔痠d
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+# 寮�鍚疻EBSOCKET
+VITE_GLOB_WEBSOCKET_ENABLE=false
+```
+
+- 杩愯
+
+```bash
+pnpm dev:antd
+```
+
+- 鎵撳寘
+
+```bash
+pnpm build:antd
+```
+
+## 杩欐槸涓�涓壒鎬� 鑰屼笉鏄竴涓猙ug!
+
+1. 鑿滃崟绠$悊鍙垎閰� 浣嗗彧鏈塦admin`/`superadmin`瑙掕壊鑳借闂� 鍏朵粬瑙掕壊璁块棶浼氬埌403椤甸潰
+2. 绉熸埛鐩稿叧鑿滃崟鍙垎閰� 浣嗗彧鏈塦superadmin`瑙掕壊鑳借闂� 鍏朵粬瑙掕壊璁块棶浼氬埌403椤甸潰
+3. 鍒嗛厤鐨勭鎴风鐞嗗憳鏃犳硶淇敼鑷繁鐨勮鑹茬殑鑿滃崟(鍗崇鐞嗗憳瑙掕壊鐨勮彍鍗�) 闃叉鑷繁鎶婅嚜宸辨潈闄愬紕娌′簡
+
+## Git 璐$尞鎻愪氦瑙勮寖
+
+- 鍙傝�� [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 瑙勮寖 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular))
+
+  - `feat` 澧炲姞鏂板姛鑳�
+  - `fix` 淇闂/BUG
+  - `style` 浠g爜椋庢牸鐩稿叧鏃犲奖鍝嶈繍琛岀粨鏋滅殑
+  - `perf` 浼樺寲/鎬ц兘鎻愬崌
+  - `refactor` 閲嶆瀯
+  - `revert` 鎾ら攢淇敼
+  - `test` 娴嬭瘯鐩稿叧
+  - `docs` 鏂囨。/娉ㄩ噴
+  - `chore` 渚濊禆鏇存柊/鑴氭墜鏋堕厤缃慨鏀圭瓑
+  - `workflow` 宸ヤ綔娴佹敼杩�
+  - `ci` 鎸佺画闆嗘垚
+  - `types` 绫诲瀷瀹氫箟鏂囦欢鏇存敼
+  - `wip` 寮�鍙戜腑
+
+## 娴忚鍣ㄦ敮鎸�
+
+鏈�浣庨�傞厤搴旇涓篳Chrome 88+`浠ヤ笂娴忚鍣� 璇﹁ [css - where](https://developer.mozilla.org/en-US/docs/Web/CSS/:where#browser_compatibility)
+
+鏈湴寮�鍙戞帹鑽愪娇鐢╜Chrome` 鏈�鏂扮増鏈祻瑙堝櫒
+
+鏀寔鐜颁唬娴忚鍣�, 涓嶆敮鎸� IE
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## 鎹愯禒
+
+濡傛灉椤圭洰甯姪鍒版偍 鍙互鑰冭檻璇蜂綔鑰呭枬鏉挅鍟� 涓囧垎鎰熻阿鎮ㄥ寮�婧愮殑鏀寔!
+
+<img src=https://plus.dapdap.top/minio-server/plus/2024/03/16/98a9d704eb0c4c04b721bf7799217571.jpg height=360px />
diff --git a/eims-ui/apps/backend-mock/.env b/eims-ui/apps/backend-mock/.env
new file mode 100644
index 0000000..b20c4a6
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.env
@@ -0,0 +1,3 @@
+PORT=5320
+ACCESS_TOKEN_SECRET=access_token_secret
+REFRESH_TOKEN_SECRET=refresh_token_secret
diff --git a/eims-ui/apps/backend-mock/.nitro/dev/index.mjs b/eims-ui/apps/backend-mock/.nitro/dev/index.mjs
new file mode 100644
index 0000000..58e2e34
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/dev/index.mjs
@@ -0,0 +1,1333 @@
+import process from 'node:process';globalThis._importMeta_={url:import.meta.url,env:process.env};import destr from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/destr@2.0.3/node_modules/destr/dist/index.mjs';
+import { defineEventHandler, handleCacheHeaders, splitCookiesString, createEvent, fetchWithEvent, isEvent, eventHandler, setHeaders, sendRedirect, proxyRequest, createApp, createRouter as createRouter$1, toNodeListener, lazyEventHandler, createError, getRouterParam, getQuery as getQuery$1, readBody, setResponseStatus, getHeader, deleteCookie, setCookie, getCookie } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/h3@1.13.0/node_modules/h3/dist/index.mjs';
+import { createHooks } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/hookable@5.5.3/node_modules/hookable/dist/index.mjs';
+import { createFetch as createFetch$1, Headers as Headers$1 } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/ofetch@1.4.1/node_modules/ofetch/dist/node.mjs';
+import { createCall, createFetch } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/unenv@1.10.0/node_modules/unenv/runtime/fetch/index.mjs';
+import { hash } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/ohash@1.1.4/node_modules/ohash/dist/index.mjs';
+import { parseURL, withoutBase, joinURL, getQuery, withQuery } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/ufo@1.5.4/node_modules/ufo/dist/index.mjs';
+import { createStorage, prefixStorage } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/unstorage@1.14.1_db0@0.2.1_ioredis@5.4.2/node_modules/unstorage/dist/index.mjs';
+import unstorage_47drivers_47fs from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/unstorage@1.14.1_db0@0.2.1_ioredis@5.4.2/node_modules/unstorage/drivers/fs.mjs';
+import { klona } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/klona@2.0.6/node_modules/klona/dist/index.mjs';
+import defu, { defuFn } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs';
+import { snakeCase } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/scule@1.3.0/node_modules/scule/dist/index.mjs';
+import { getContext } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/unctx@2.4.1/node_modules/unctx/dist/index.mjs';
+import { toRouteMatcher, createRouter } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/radix3@1.1.2/node_modules/radix3/dist/index.mjs';
+import { Server } from 'node:http';
+import { mkdirSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { parentPort, threadId } from 'node:worker_threads';
+import { provider, isWindows } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/std-env@3.8.0/node_modules/std-env/dist/index.mjs';
+import { faker } from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/@faker-js+faker@9.3.0/node_modules/@faker-js/faker/dist/index.js';
+import jwt from 'file:///Users/zhuguifei/Downloads/eims-ui/node_modules/.pnpm/jsonwebtoken@9.0.2/node_modules/jsonwebtoken/index.js';
+
+const errorHandler = function(error, event) {
+  event.node.res.end(`[Error Handler] ${error.stack}`);
+};
+
+const plugins = [
+  
+];
+
+const _uwIvJk = defineEventHandler((event) => {
+  if (event.method === "OPTIONS") {
+    event.node.res.statusCode = 204;
+    event.node.res.statusMessage = "No Content.";
+    return "OK";
+  }
+});
+
+const _lazy_nACJPr = () => Promise.resolve().then(function () { return codes$1; });
+const _lazy_6XUUbB = () => Promise.resolve().then(function () { return login_post$1; });
+const _lazy_32dDsb = () => Promise.resolve().then(function () { return logout_post$1; });
+const _lazy_GMWG5t = () => Promise.resolve().then(function () { return refresh_post$1; });
+const _lazy_Zyhkpg = () => Promise.resolve().then(function () { return all$1; });
+const _lazy_8eXRty = () => Promise.resolve().then(function () { return status$1; });
+const _lazy_Vmncfw = () => Promise.resolve().then(function () { return list$1; });
+const _lazy_5qsZ3U = () => Promise.resolve().then(function () { return test_get$1; });
+const _lazy_HBIYHI = () => Promise.resolve().then(function () { return test_post$1; });
+const _lazy_8M3Odh = () => Promise.resolve().then(function () { return info$1; });
+const _lazy_aAnmms = () => Promise.resolve().then(function () { return _____$1; });
+
+const handlers = [
+  { route: '', handler: _uwIvJk, lazy: false, middleware: true, method: undefined },
+  { route: '/api/auth/codes', handler: _lazy_nACJPr, lazy: true, middleware: false, method: undefined },
+  { route: '/api/auth/login', handler: _lazy_6XUUbB, lazy: true, middleware: false, method: "post" },
+  { route: '/api/auth/logout', handler: _lazy_32dDsb, lazy: true, middleware: false, method: "post" },
+  { route: '/api/auth/refresh', handler: _lazy_GMWG5t, lazy: true, middleware: false, method: "post" },
+  { route: '/api/menu/all', handler: _lazy_Zyhkpg, lazy: true, middleware: false, method: undefined },
+  { route: '/api/status', handler: _lazy_8eXRty, lazy: true, middleware: false, method: undefined },
+  { route: '/api/table/list', handler: _lazy_Vmncfw, lazy: true, middleware: false, method: undefined },
+  { route: '/api/test', handler: _lazy_5qsZ3U, lazy: true, middleware: false, method: "get" },
+  { route: '/api/test', handler: _lazy_HBIYHI, lazy: true, middleware: false, method: "post" },
+  { route: '/api/user/info', handler: _lazy_8M3Odh, lazy: true, middleware: false, method: undefined },
+  { route: '/**', handler: _lazy_aAnmms, lazy: true, middleware: false, method: undefined }
+];
+
+const serverAssets = [{"baseName":"server","dir":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock/assets"}];
+
+const assets = createStorage();
+
+for (const asset of serverAssets) {
+  assets.mount(asset.baseName, unstorage_47drivers_47fs({ base: asset.dir, ignore: (asset?.ignore || []) }));
+}
+
+const storage = createStorage({});
+
+storage.mount('/assets', assets);
+
+storage.mount('root', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock","ignore":["**/node_modules/**","**/.git/**"]}));
+storage.mount('src', unstorage_47drivers_47fs({"driver":"fs","readOnly":true,"base":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock","ignore":["**/node_modules/**","**/.git/**"]}));
+storage.mount('build', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock/.nitro","ignore":["**/node_modules/**","**/.git/**"]}));
+storage.mount('cache', unstorage_47drivers_47fs({"driver":"fs","readOnly":false,"base":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock/.nitro/cache","ignore":["**/node_modules/**","**/.git/**"]}));
+storage.mount('data', unstorage_47drivers_47fs({"driver":"fs","base":"/Users/zhuguifei/Downloads/eims-ui/apps/backend-mock/.data/kv","ignore":["**/node_modules/**","**/.git/**"]}));
+
+function useStorage(base = "") {
+  return base ? prefixStorage(storage, base) : storage;
+}
+
+function defaultCacheOptions() {
+  return {
+    name: "_",
+    base: "/cache",
+    swr: true,
+    maxAge: 1
+  };
+}
+function defineCachedFunction(fn, opts = {}) {
+  opts = { ...defaultCacheOptions(), ...opts };
+  const pending = {};
+  const group = opts.group || "nitro/functions";
+  const name = opts.name || fn.name || "_";
+  const integrity = opts.integrity || hash([fn, opts]);
+  const validate = opts.validate || ((entry) => entry.value !== void 0);
+  async function get(key, resolver, shouldInvalidateCache, event) {
+    const cacheKey = [opts.base, group, name, key + ".json"].filter(Boolean).join(":").replace(/:\/$/, ":index");
+    let entry = await useStorage().getItem(cacheKey).catch((error) => {
+      console.error(`[nitro] [cache] Cache read error.`, error);
+      useNitroApp().captureError(error, { event, tags: ["cache"] });
+    }) || {};
+    if (typeof entry !== "object") {
+      entry = {};
+      const error = new Error("Malformed data read from cache.");
+      console.error("[nitro] [cache]", error);
+      useNitroApp().captureError(error, { event, tags: ["cache"] });
+    }
+    const ttl = (opts.maxAge ?? 0) * 1e3;
+    if (ttl) {
+      entry.expires = Date.now() + ttl;
+    }
+    const expired = shouldInvalidateCache || entry.integrity !== integrity || ttl && Date.now() - (entry.mtime || 0) > ttl || validate(entry) === false;
+    const _resolve = async () => {
+      const isPending = pending[key];
+      if (!isPending) {
+        if (entry.value !== void 0 && (opts.staleMaxAge || 0) >= 0 && opts.swr === false) {
+          entry.value = void 0;
+          entry.integrity = void 0;
+          entry.mtime = void 0;
+          entry.expires = void 0;
+        }
+        pending[key] = Promise.resolve(resolver());
+      }
+      try {
+        entry.value = await pending[key];
+      } catch (error) {
+        if (!isPending) {
+          delete pending[key];
+        }
+        throw error;
+      }
+      if (!isPending) {
+        entry.mtime = Date.now();
+        entry.integrity = integrity;
+        delete pending[key];
+        if (validate(entry) !== false) {
+          let setOpts;
+          if (opts.maxAge && !opts.swr) {
+            setOpts = { ttl: opts.maxAge };
+          }
+          const promise = useStorage().setItem(cacheKey, entry, setOpts).catch((error) => {
+            console.error(`[nitro] [cache] Cache write error.`, error);
+            useNitroApp().captureError(error, { event, tags: ["cache"] });
+          });
+          if (event?.waitUntil) {
+            event.waitUntil(promise);
+          }
+        }
+      }
+    };
+    const _resolvePromise = expired ? _resolve() : Promise.resolve();
+    if (entry.value === void 0) {
+      await _resolvePromise;
+    } else if (expired && event && event.waitUntil) {
+      event.waitUntil(_resolvePromise);
+    }
+    if (opts.swr && validate(entry) !== false) {
+      _resolvePromise.catch((error) => {
+        console.error(`[nitro] [cache] SWR handler error.`, error);
+        useNitroApp().captureError(error, { event, tags: ["cache"] });
+      });
+      return entry;
+    }
+    return _resolvePromise.then(() => entry);
+  }
+  return async (...args) => {
+    const shouldBypassCache = await opts.shouldBypassCache?.(...args);
+    if (shouldBypassCache) {
+      return fn(...args);
+    }
+    const key = await (opts.getKey || getKey)(...args);
+    const shouldInvalidateCache = await opts.shouldInvalidateCache?.(...args);
+    const entry = await get(
+      key,
+      () => fn(...args),
+      shouldInvalidateCache,
+      args[0] && isEvent(args[0]) ? args[0] : void 0
+    );
+    let value = entry.value;
+    if (opts.transform) {
+      value = await opts.transform(entry, ...args) || value;
+    }
+    return value;
+  };
+}
+function cachedFunction(fn, opts = {}) {
+  return defineCachedFunction(fn, opts);
+}
+function getKey(...args) {
+  return args.length > 0 ? hash(args, {}) : "";
+}
+function escapeKey(key) {
+  return String(key).replace(/\W/g, "");
+}
+function defineCachedEventHandler(handler, opts = defaultCacheOptions()) {
+  const variableHeaderNames = (opts.varies || []).filter(Boolean).map((h) => h.toLowerCase()).sort();
+  const _opts = {
+    ...opts,
+    getKey: async (event) => {
+      const customKey = await opts.getKey?.(event);
+      if (customKey) {
+        return escapeKey(customKey);
+      }
+      const _path = event.node.req.originalUrl || event.node.req.url || event.path;
+      let _pathname;
+      try {
+        _pathname = escapeKey(decodeURI(parseURL(_path).pathname)).slice(0, 16) || "index";
+      } catch {
+        _pathname = "-";
+      }
+      const _hashedPath = `${_pathname}.${hash(_path)}`;
+      const _headers = variableHeaderNames.map((header) => [header, event.node.req.headers[header]]).map(([name, value]) => `${escapeKey(name)}.${hash(value)}`);
+      return [_hashedPath, ..._headers].join(":");
+    },
+    validate: (entry) => {
+      if (!entry.value) {
+        return false;
+      }
+      if (entry.value.code >= 400) {
+        return false;
+      }
+      if (entry.value.body === void 0) {
+        return false;
+      }
+      if (entry.value.headers.etag === "undefined" || entry.value.headers["last-modified"] === "undefined") {
+        return false;
+      }
+      return true;
+    },
+    group: opts.group || "nitro/handlers",
+    integrity: opts.integrity || hash([handler, opts])
+  };
+  const _cachedHandler = cachedFunction(
+    async (incomingEvent) => {
+      const variableHeaders = {};
+      for (const header of variableHeaderNames) {
+        const value = incomingEvent.node.req.headers[header];
+        if (value !== void 0) {
+          variableHeaders[header] = value;
+        }
+      }
+      const reqProxy = cloneWithProxy(incomingEvent.node.req, {
+        headers: variableHeaders
+      });
+      const resHeaders = {};
+      let _resSendBody;
+      const resProxy = cloneWithProxy(incomingEvent.node.res, {
+        statusCode: 200,
+        writableEnded: false,
+        writableFinished: false,
+        headersSent: false,
+        closed: false,
+        getHeader(name) {
+          return resHeaders[name];
+        },
+        setHeader(name, value) {
+          resHeaders[name] = value;
+          return this;
+        },
+        getHeaderNames() {
+          return Object.keys(resHeaders);
+        },
+        hasHeader(name) {
+          return name in resHeaders;
+        },
+        removeHeader(name) {
+          delete resHeaders[name];
+        },
+        getHeaders() {
+          return resHeaders;
+        },
+        end(chunk, arg2, arg3) {
+          if (typeof chunk === "string") {
+            _resSendBody = chunk;
+          }
+          if (typeof arg2 === "function") {
+            arg2();
+          }
+          if (typeof arg3 === "function") {
+            arg3();
+          }
+          return this;
+        },
+        write(chunk, arg2, arg3) {
+          if (typeof chunk === "string") {
+            _resSendBody = chunk;
+          }
+          if (typeof arg2 === "function") {
+            arg2(void 0);
+          }
+          if (typeof arg3 === "function") {
+            arg3();
+          }
+          return true;
+        },
+        writeHead(statusCode, headers2) {
+          this.statusCode = statusCode;
+          if (headers2) {
+            if (Array.isArray(headers2) || typeof headers2 === "string") {
+              throw new TypeError("Raw headers  is not supported.");
+            }
+            for (const header in headers2) {
+              const value = headers2[header];
+              if (value !== void 0) {
+                this.setHeader(
+                  header,
+                  value
+                );
+              }
+            }
+          }
+          return this;
+        }
+      });
+      const event = createEvent(reqProxy, resProxy);
+      event.fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, {
+        fetch: useNitroApp().localFetch
+      });
+      event.$fetch = (url, fetchOptions) => fetchWithEvent(event, url, fetchOptions, {
+        fetch: globalThis.$fetch
+      });
+      event.context = incomingEvent.context;
+      event.context.cache = {
+        options: _opts
+      };
+      const body = await handler(event) || _resSendBody;
+      const headers = event.node.res.getHeaders();
+      headers.etag = String(
+        headers.Etag || headers.etag || `W/"${hash(body)}"`
+      );
+      headers["last-modified"] = String(
+        headers["Last-Modified"] || headers["last-modified"] || (/* @__PURE__ */ new Date()).toUTCString()
+      );
+      const cacheControl = [];
+      if (opts.swr) {
+        if (opts.maxAge) {
+          cacheControl.push(`s-maxage=${opts.maxAge}`);
+        }
+        if (opts.staleMaxAge) {
+          cacheControl.push(`stale-while-revalidate=${opts.staleMaxAge}`);
+        } else {
+          cacheControl.push("stale-while-revalidate");
+        }
+      } else if (opts.maxAge) {
+        cacheControl.push(`max-age=${opts.maxAge}`);
+      }
+      if (cacheControl.length > 0) {
+        headers["cache-control"] = cacheControl.join(", ");
+      }
+      const cacheEntry = {
+        code: event.node.res.statusCode,
+        headers,
+        body
+      };
+      return cacheEntry;
+    },
+    _opts
+  );
+  return defineEventHandler(async (event) => {
+    if (opts.headersOnly) {
+      if (handleCacheHeaders(event, { maxAge: opts.maxAge })) {
+        return;
+      }
+      return handler(event);
+    }
+    const response = await _cachedHandler(
+      event
+    );
+    if (event.node.res.headersSent || event.node.res.writableEnded) {
+      return response.body;
+    }
+    if (handleCacheHeaders(event, {
+      modifiedTime: new Date(response.headers["last-modified"]),
+      etag: response.headers.etag,
+      maxAge: opts.maxAge
+    })) {
+      return;
+    }
+    event.node.res.statusCode = response.code;
+    for (const name in response.headers) {
+      const value = response.headers[name];
+      if (name === "set-cookie") {
+        event.node.res.appendHeader(
+          name,
+          splitCookiesString(value)
+        );
+      } else {
+        if (value !== void 0) {
+          event.node.res.setHeader(name, value);
+        }
+      }
+    }
+    return response.body;
+  });
+}
+function cloneWithProxy(obj, overrides) {
+  return new Proxy(obj, {
+    get(target, property, receiver) {
+      if (property in overrides) {
+        return overrides[property];
+      }
+      return Reflect.get(target, property, receiver);
+    },
+    set(target, property, value, receiver) {
+      if (property in overrides) {
+        overrides[property] = value;
+        return true;
+      }
+      return Reflect.set(target, property, value, receiver);
+    }
+  });
+}
+const cachedEventHandler = defineCachedEventHandler;
+
+const inlineAppConfig = {};
+
+
+
+const appConfig = defuFn(inlineAppConfig);
+
+function getEnv(key, opts) {
+  const envKey = snakeCase(key).toUpperCase();
+  return destr(
+    process.env[opts.prefix + envKey] ?? process.env[opts.altPrefix + envKey]
+  );
+}
+function _isObject(input) {
+  return typeof input === "object" && !Array.isArray(input);
+}
+function applyEnv(obj, opts, parentKey = "") {
+  for (const key in obj) {
+    const subKey = parentKey ? `${parentKey}_${key}` : key;
+    const envValue = getEnv(subKey, opts);
+    if (_isObject(obj[key])) {
+      if (_isObject(envValue)) {
+        obj[key] = { ...obj[key], ...envValue };
+        applyEnv(obj[key], opts, subKey);
+      } else if (envValue === void 0) {
+        applyEnv(obj[key], opts, subKey);
+      } else {
+        obj[key] = envValue ?? obj[key];
+      }
+    } else {
+      obj[key] = envValue ?? obj[key];
+    }
+    if (opts.envExpansion && typeof obj[key] === "string") {
+      obj[key] = _expandFromEnv(obj[key]);
+    }
+  }
+  return obj;
+}
+const envExpandRx = /{{(.*?)}}/g;
+function _expandFromEnv(value) {
+  return value.replace(envExpandRx, (match, key) => {
+    return process.env[key] || match;
+  });
+}
+
+const _inlineRuntimeConfig = {
+  "app": {
+    "baseURL": "/"
+  },
+  "nitro": {
+    "routeRules": {
+      "/api/**": {
+        "cors": true,
+        "headers": {
+          "access-control-allow-origin": "*",
+          "access-control-allow-methods": "*",
+          "access-control-allow-headers": "*",
+          "access-control-max-age": "0",
+          "Access-Control-Allow-Credentials": "true",
+          "Access-Control-Allow-Headers": "*",
+          "Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
+          "Access-Control-Allow-Origin": "*",
+          "Access-Control-Expose-Headers": "*"
+        }
+      }
+    }
+  }
+};
+const envOptions = {
+  prefix: "NITRO_",
+  altPrefix: _inlineRuntimeConfig.nitro.envPrefix ?? process.env.NITRO_ENV_PREFIX ?? "_",
+  envExpansion: _inlineRuntimeConfig.nitro.envExpansion ?? process.env.NITRO_ENV_EXPANSION ?? false
+};
+const _sharedRuntimeConfig = _deepFreeze(
+  applyEnv(klona(_inlineRuntimeConfig), envOptions)
+);
+function useRuntimeConfig(event) {
+  {
+    return _sharedRuntimeConfig;
+  }
+}
+_deepFreeze(klona(appConfig));
+function _deepFreeze(object) {
+  const propNames = Object.getOwnPropertyNames(object);
+  for (const name of propNames) {
+    const value = object[name];
+    if (value && typeof value === "object") {
+      _deepFreeze(value);
+    }
+  }
+  return Object.freeze(object);
+}
+new Proxy(/* @__PURE__ */ Object.create(null), {
+  get: (_, prop) => {
+    console.warn(
+      "Please use `useRuntimeConfig()` instead of accessing config directly."
+    );
+    const runtimeConfig = useRuntimeConfig();
+    if (prop in runtimeConfig) {
+      return runtimeConfig[prop];
+    }
+    return void 0;
+  }
+});
+
+getContext("nitro-app", {
+  asyncContext: undefined,
+  AsyncLocalStorage: void 0
+});
+
+const config = useRuntimeConfig();
+const _routeRulesMatcher = toRouteMatcher(
+  createRouter({ routes: config.nitro.routeRules })
+);
+function createRouteRulesHandler(ctx) {
+  return eventHandler((event) => {
+    const routeRules = getRouteRules(event);
+    if (routeRules.headers) {
+      setHeaders(event, routeRules.headers);
+    }
+    if (routeRules.redirect) {
+      let target = routeRules.redirect.to;
+      if (target.endsWith("/**")) {
+        let targetPath = event.path;
+        const strpBase = routeRules.redirect._redirectStripBase;
+        if (strpBase) {
+          targetPath = withoutBase(targetPath, strpBase);
+        }
+        target = joinURL(target.slice(0, -3), targetPath);
+      } else if (event.path.includes("?")) {
+        const query = getQuery(event.path);
+        target = withQuery(target, query);
+      }
+      return sendRedirect(event, target, routeRules.redirect.statusCode);
+    }
+    if (routeRules.proxy) {
+      let target = routeRules.proxy.to;
+      if (target.endsWith("/**")) {
+        let targetPath = event.path;
+        const strpBase = routeRules.proxy._proxyStripBase;
+        if (strpBase) {
+          targetPath = withoutBase(targetPath, strpBase);
+        }
+        target = joinURL(target.slice(0, -3), targetPath);
+      } else if (event.path.includes("?")) {
+        const query = getQuery(event.path);
+        target = withQuery(target, query);
+      }
+      return proxyRequest(event, target, {
+        fetch: ctx.localFetch,
+        ...routeRules.proxy
+      });
+    }
+  });
+}
+function getRouteRules(event) {
+  event.context._nitro = event.context._nitro || {};
+  if (!event.context._nitro.routeRules) {
+    event.context._nitro.routeRules = getRouteRulesForPath(
+      withoutBase(event.path.split("?")[0], useRuntimeConfig().app.baseURL)
+    );
+  }
+  return event.context._nitro.routeRules;
+}
+function getRouteRulesForPath(path) {
+  return defu({}, ..._routeRulesMatcher.matchAll(path).reverse());
+}
+
+function _captureError(error, type) {
+  console.error(`[nitro] [${type}]`, error);
+  useNitroApp().captureError(error, { tags: [type] });
+}
+function trapUnhandledNodeErrors() {
+  process.on(
+    "unhandledRejection",
+    (error) => _captureError(error, "unhandledRejection")
+  );
+  process.on(
+    "uncaughtException",
+    (error) => _captureError(error, "uncaughtException")
+  );
+}
+function joinHeaders(value) {
+  return Array.isArray(value) ? value.join(", ") : String(value);
+}
+function normalizeFetchResponse(response) {
+  if (!response.headers.has("set-cookie")) {
+    return response;
+  }
+  return new Response(response.body, {
+    status: response.status,
+    statusText: response.statusText,
+    headers: normalizeCookieHeaders(response.headers)
+  });
+}
+function normalizeCookieHeader(header = "") {
+  return splitCookiesString(joinHeaders(header));
+}
+function normalizeCookieHeaders(headers) {
+  const outgoingHeaders = new Headers();
+  for (const [name, header] of headers) {
+    if (name === "set-cookie") {
+      for (const cookie of normalizeCookieHeader(header)) {
+        outgoingHeaders.append("set-cookie", cookie);
+      }
+    } else {
+      outgoingHeaders.set(name, joinHeaders(header));
+    }
+  }
+  return outgoingHeaders;
+}
+
+function createNitroApp() {
+  const config = useRuntimeConfig();
+  const hooks = createHooks();
+  const captureError = (error, context = {}) => {
+    const promise = hooks.callHookParallel("error", error, context).catch((error_) => {
+      console.error("Error while capturing another error", error_);
+    });
+    if (context.event && isEvent(context.event)) {
+      const errors = context.event.context.nitro?.errors;
+      if (errors) {
+        errors.push({ error, context });
+      }
+      if (context.event.waitUntil) {
+        context.event.waitUntil(promise);
+      }
+    }
+  };
+  const h3App = createApp({
+    debug: destr(true),
+    onError: (error, event) => {
+      captureError(error, { event, tags: ["request"] });
+      return errorHandler(error, event);
+    },
+    onRequest: async (event) => {
+      await nitroApp$1.hooks.callHook("request", event).catch((error) => {
+        captureError(error, { event, tags: ["request"] });
+      });
+    },
+    onBeforeResponse: async (event, response) => {
+      await nitroApp$1.hooks.callHook("beforeResponse", event, response).catch((error) => {
+        captureError(error, { event, tags: ["request", "response"] });
+      });
+    },
+    onAfterResponse: async (event, response) => {
+      await nitroApp$1.hooks.callHook("afterResponse", event, response).catch((error) => {
+        captureError(error, { event, tags: ["request", "response"] });
+      });
+    }
+  });
+  const router = createRouter$1({
+    preemptive: true
+  });
+  const localCall = createCall(toNodeListener(h3App));
+  const _localFetch = createFetch(localCall, globalThis.fetch);
+  const localFetch = (input, init) => _localFetch(input, init).then(
+    (response) => normalizeFetchResponse(response)
+  );
+  const $fetch = createFetch$1({
+    fetch: localFetch,
+    Headers: Headers$1,
+    defaults: { baseURL: config.app.baseURL }
+  });
+  globalThis.$fetch = $fetch;
+  h3App.use(createRouteRulesHandler({ localFetch }));
+  h3App.use(
+    eventHandler((event) => {
+      event.context.nitro = event.context.nitro || { errors: [] };
+      const envContext = event.node.req?.__unenv__;
+      if (envContext) {
+        Object.assign(event.context, envContext);
+      }
+      event.fetch = (req, init) => fetchWithEvent(event, req, init, { fetch: localFetch });
+      event.$fetch = (req, init) => fetchWithEvent(event, req, init, {
+        fetch: $fetch
+      });
+      event.waitUntil = (promise) => {
+        if (!event.context.nitro._waitUntilPromises) {
+          event.context.nitro._waitUntilPromises = [];
+        }
+        event.context.nitro._waitUntilPromises.push(promise);
+        if (envContext?.waitUntil) {
+          envContext.waitUntil(promise);
+        }
+      };
+      event.captureError = (error, context) => {
+        captureError(error, { event, ...context });
+      };
+    })
+  );
+  for (const h of handlers) {
+    let handler = h.lazy ? lazyEventHandler(h.handler) : h.handler;
+    if (h.middleware || !h.route) {
+      const middlewareBase = (config.app.baseURL + (h.route || "/")).replace(
+        /\/+/g,
+        "/"
+      );
+      h3App.use(middlewareBase, handler);
+    } else {
+      const routeRules = getRouteRulesForPath(
+        h.route.replace(/:\w+|\*\*/g, "_")
+      );
+      if (routeRules.cache) {
+        handler = cachedEventHandler(handler, {
+          group: "nitro/routes",
+          ...routeRules.cache
+        });
+      }
+      router.use(h.route, handler, h.method);
+    }
+  }
+  h3App.use(config.app.baseURL, router.handler);
+  const app = {
+    hooks,
+    h3App,
+    router,
+    localCall,
+    localFetch,
+    captureError
+  };
+  return app;
+}
+function runNitroPlugins(nitroApp2) {
+  for (const plugin of plugins) {
+    try {
+      plugin(nitroApp2);
+    } catch (error) {
+      nitroApp2.captureError(error, { tags: ["plugin"] });
+      throw error;
+    }
+  }
+}
+const nitroApp$1 = createNitroApp();
+function useNitroApp() {
+  return nitroApp$1;
+}
+runNitroPlugins(nitroApp$1);
+
+const scheduledTasks = false;
+
+const tasks = {
+  
+};
+
+const __runningTasks__ = {};
+async function runTask(name, {
+  payload = {},
+  context = {}
+} = {}) {
+  if (__runningTasks__[name]) {
+    return __runningTasks__[name];
+  }
+  if (!(name in tasks)) {
+    throw createError({
+      message: `Task \`${name}\` is not available!`,
+      statusCode: 404
+    });
+  }
+  if (!tasks[name].resolve) {
+    throw createError({
+      message: `Task \`${name}\` is not implemented!`,
+      statusCode: 501
+    });
+  }
+  const handler = await tasks[name].resolve();
+  const taskEvent = { name, payload, context };
+  __runningTasks__[name] = handler.run(taskEvent);
+  try {
+    const res = await __runningTasks__[name];
+    return res;
+  } finally {
+    delete __runningTasks__[name];
+  }
+}
+
+const nitroApp = useNitroApp();
+const server = new Server(toNodeListener(nitroApp.h3App));
+function getAddress() {
+  if (provider === "stackblitz" || process.env.NITRO_NO_UNIX_SOCKET || process.versions.bun) {
+    return 0;
+  }
+  const socketName = `worker-${process.pid}-${threadId}.sock`;
+  if (isWindows) {
+    return join(String.raw`\\.\pipe\nitro`, socketName);
+  }
+  const socketDir = join(tmpdir(), "nitro");
+  mkdirSync(socketDir, { recursive: true });
+  return join(socketDir, socketName);
+}
+const listenAddress = getAddress();
+server.listen(listenAddress, () => {
+  const _address = server.address();
+  parentPort?.postMessage({
+    event: "listen",
+    address: typeof _address === "string" ? { socketPath: _address } : { host: "localhost", port: _address?.port }
+  });
+});
+nitroApp.router.get(
+  "/_nitro/tasks",
+  defineEventHandler(async (event) => {
+    const _tasks = await Promise.all(
+      Object.entries(tasks).map(async ([name, task]) => {
+        const _task = await task.resolve?.();
+        return [name, { description: _task?.meta?.description }];
+      })
+    );
+    return {
+      tasks: Object.fromEntries(_tasks),
+      scheduledTasks
+    };
+  })
+);
+nitroApp.router.use(
+  "/_nitro/tasks/:name",
+  defineEventHandler(async (event) => {
+    const name = getRouterParam(event, "name");
+    const payload = {
+      ...getQuery$1(event),
+      ...await readBody(event).then((r) => r?.payload).catch(() => ({}))
+    };
+    return await runTask(name, { payload });
+  })
+);
+trapUnhandledNodeErrors();
+async function onShutdown(signal) {
+  await nitroApp.hooks.callHook("close");
+}
+parentPort?.on("message", async (msg) => {
+  if (msg && msg.event === "shutdown") {
+    await onShutdown();
+    parentPort?.postMessage({ event: "exit" });
+  }
+});
+
+const MOCK_USERS = [
+  {
+    id: 0,
+    password: "123456",
+    realName: "Vben",
+    roles: ["super"],
+    username: "vben"
+  },
+  {
+    id: 1,
+    password: "123456",
+    realName: "Admin",
+    roles: ["admin"],
+    username: "admin"
+  },
+  {
+    id: 2,
+    password: "123456",
+    realName: "Jack",
+    roles: ["user"],
+    username: "jack"
+  }
+];
+const MOCK_CODES = [
+  // super
+  {
+    codes: ["AC_100100", "AC_100110", "AC_100120", "AC_100010"],
+    username: "vben"
+  },
+  {
+    // admin
+    codes: ["AC_100010", "AC_100020", "AC_100030"],
+    username: "admin"
+  },
+  {
+    // user
+    codes: ["AC_1000001", "AC_1000002"],
+    username: "jack"
+  }
+];
+const dashboardMenus = [
+  {
+    component: "BasicLayout",
+    meta: {
+      order: -1,
+      title: "page.dashboard.title"
+    },
+    name: "Dashboard",
+    path: "/",
+    redirect: "/analytics",
+    children: [
+      {
+        name: "Analytics",
+        path: "/analytics",
+        component: "/dashboard/analytics/index",
+        meta: {
+          affixTab: true,
+          title: "page.dashboard.analytics"
+        }
+      },
+      {
+        name: "Workspace",
+        path: "/workspace",
+        component: "/dashboard/workspace/index",
+        meta: {
+          title: "page.dashboard.workspace"
+        }
+      }
+    ]
+  }
+];
+const createDemosMenus = (role) => {
+  const roleWithMenus = {
+    admin: {
+      component: "/demos/access/admin-visible",
+      meta: {
+        icon: "mdi:button-cursor",
+        title: "demos.access.adminVisible"
+      },
+      name: "AccessAdminVisibleDemo",
+      path: "/demos/access/admin-visible"
+    },
+    super: {
+      component: "/demos/access/super-visible",
+      meta: {
+        icon: "mdi:button-cursor",
+        title: "demos.access.superVisible"
+      },
+      name: "AccessSuperVisibleDemo",
+      path: "/demos/access/super-visible"
+    },
+    user: {
+      component: "/demos/access/user-visible",
+      meta: {
+        icon: "mdi:button-cursor",
+        title: "demos.access.userVisible"
+      },
+      name: "AccessUserVisibleDemo",
+      path: "/demos/access/user-visible"
+    }
+  };
+  return [
+    {
+      component: "BasicLayout",
+      meta: {
+        icon: "ic:baseline-view-in-ar",
+        keepAlive: true,
+        order: 1e3,
+        title: "demos.title"
+      },
+      name: "Demos",
+      path: "/demos",
+      redirect: "/demos/access",
+      children: [
+        {
+          name: "AccessDemos",
+          path: "/demosaccess",
+          meta: {
+            icon: "mdi:cloud-key-outline",
+            title: "demos.access.backendPermissions"
+          },
+          redirect: "/demos/access/page-control",
+          children: [
+            {
+              name: "AccessPageControlDemo",
+              path: "/demos/access/page-control",
+              component: "/demos/access/index",
+              meta: {
+                icon: "mdi:page-previous-outline",
+                title: "demos.access.pageAccess"
+              }
+            },
+            {
+              name: "AccessButtonControlDemo",
+              path: "/demos/access/button-control",
+              component: "/demos/access/button-control",
+              meta: {
+                icon: "mdi:button-cursor",
+                title: "demos.access.buttonControl"
+              }
+            },
+            {
+              name: "AccessMenuVisible403Demo",
+              path: "/demos/access/menu-visible-403",
+              component: "/demos/access/menu-visible-403",
+              meta: {
+                authority: ["no-body"],
+                icon: "mdi:button-cursor",
+                menuVisibleWithForbidden: true,
+                title: "demos.access.menuVisible403"
+              }
+            },
+            roleWithMenus[role]
+          ]
+        }
+      ]
+    }
+  ];
+};
+const MOCK_MENUS = [
+  {
+    menus: [...dashboardMenus, ...createDemosMenus("super")],
+    username: "vben"
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus("admin")],
+    username: "admin"
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus("user")],
+    username: "jack"
+  }
+];
+
+function useResponseSuccess(data) {
+  return {
+    code: 0,
+    data,
+    error: null,
+    message: "ok"
+  };
+}
+function usePageResponseSuccess(page, pageSize, list, { message = "ok" } = {}) {
+  const pageData = pagination(
+    Number.parseInt(`${page}`),
+    Number.parseInt(`${pageSize}`),
+    list
+  );
+  return {
+    ...useResponseSuccess({
+      items: pageData,
+      total: list.length
+    }),
+    message
+  };
+}
+function useResponseError(message, error = null) {
+  return {
+    code: -1,
+    data: null,
+    error,
+    message
+  };
+}
+function forbiddenResponse(event, message = "Forbidden Exception") {
+  setResponseStatus(event, 403);
+  return useResponseError(message, message);
+}
+function unAuthorizedResponse(event) {
+  setResponseStatus(event, 401);
+  return useResponseError("Unauthorized Exception", "Unauthorized Exception");
+}
+function sleep(ms) {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+function pagination(pageNo, pageSize, array) {
+  const offset = (pageNo - 1) * Number(pageSize);
+  return offset + Number(pageSize) >= array.length ? array.slice(offset) : array.slice(offset, offset + Number(pageSize));
+}
+
+const ACCESS_TOKEN_SECRET = "access_token_secret";
+const REFRESH_TOKEN_SECRET = "refresh_token_secret";
+function generateAccessToken(user) {
+  return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: "7d" });
+}
+function generateRefreshToken(user) {
+  return jwt.sign(user, REFRESH_TOKEN_SECRET, {
+    expiresIn: "30d"
+  });
+}
+function verifyAccessToken(event) {
+  const authHeader = getHeader(event, "Authorization");
+  if (!(authHeader == null ? void 0 : authHeader.startsWith("Bearer"))) {
+    return null;
+  }
+  const token = authHeader.split(" ")[1];
+  try {
+    const decoded = jwt.verify(token, ACCESS_TOKEN_SECRET);
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}
+function verifyRefreshToken(token) {
+  try {
+    const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET);
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}
+
+const codes = eventHandler((event) => {
+  var _a, _b;
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const codes = (_b = (_a = MOCK_CODES.find((item) => item.username === userinfo.username)) == null ? void 0 : _a.codes) != null ? _b : [];
+  return useResponseSuccess(codes);
+});
+
+const codes$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: codes
+});
+
+function clearRefreshTokenCookie(event) {
+  deleteCookie(event, "jwt", {
+    httpOnly: true,
+    sameSite: "none",
+    secure: true
+  });
+}
+function setRefreshTokenCookie(event, refreshToken) {
+  setCookie(event, "jwt", refreshToken, {
+    httpOnly: true,
+    maxAge: 24 * 60 * 60 * 1e3,
+    sameSite: "none",
+    secure: true
+  });
+}
+function getRefreshTokenFromCookie(event) {
+  const refreshToken = getCookie(event, "jwt");
+  return refreshToken;
+}
+
+const login_post = defineEventHandler(async (event) => {
+  const { password, username } = await readBody(event);
+  if (!password || !username) {
+    setResponseStatus(event, 400);
+    return useResponseError(
+      "BadRequestException",
+      "Username and password are required"
+    );
+  }
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === username && item.password === password
+  );
+  if (!findUser) {
+    clearRefreshTokenCookie(event);
+    return forbiddenResponse(event, "Username or password is incorrect.");
+  }
+  const accessToken = generateAccessToken(findUser);
+  const refreshToken = generateRefreshToken(findUser);
+  setRefreshTokenCookie(event, refreshToken);
+  return useResponseSuccess({
+    ...findUser,
+    accessToken
+  });
+});
+
+const login_post$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: login_post
+});
+
+const logout_post = defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return useResponseSuccess("");
+  }
+  clearRefreshTokenCookie(event);
+  return useResponseSuccess("");
+});
+
+const logout_post$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: logout_post
+});
+
+const refresh_post = defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return forbiddenResponse(event);
+  }
+  clearRefreshTokenCookie(event);
+  const userinfo = verifyRefreshToken(refreshToken);
+  if (!userinfo) {
+    return forbiddenResponse(event);
+  }
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === userinfo.username
+  );
+  if (!findUser) {
+    return forbiddenResponse(event);
+  }
+  const accessToken = generateAccessToken(findUser);
+  setRefreshTokenCookie(event, refreshToken);
+  return accessToken;
+});
+
+const refresh_post$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: refresh_post
+});
+
+const all = eventHandler(async (event) => {
+  var _a, _b;
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const menus = (_b = (_a = MOCK_MENUS.find((item) => item.username === userinfo.username)) == null ? void 0 : _a.menus) != null ? _b : [];
+  return useResponseSuccess(menus);
+});
+
+const all$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: all
+});
+
+const status = eventHandler((event) => {
+  const { status } = getQuery$1(event);
+  setResponseStatus(event, Number(status));
+  return useResponseError(`${status}`);
+});
+
+const status$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: status
+});
+
+function generateMockDataList(count) {
+  const dataList = [];
+  for (let i = 0; i < count; i++) {
+    const dataItem = {
+      id: faker.string.uuid(),
+      imageUrl: faker.image.avatar(),
+      imageUrl2: faker.image.avatar(),
+      open: faker.datatype.boolean(),
+      status: faker.helpers.arrayElement(["success", "error", "warning"]),
+      productName: faker.commerce.productName(),
+      price: faker.commerce.price(),
+      currency: faker.finance.currencyCode(),
+      quantity: faker.number.int({ min: 1, max: 100 }),
+      available: faker.datatype.boolean(),
+      category: faker.commerce.department(),
+      releaseDate: faker.date.past(),
+      rating: faker.number.float({ min: 1, max: 5 }),
+      description: faker.commerce.productDescription(),
+      weight: faker.number.float({ min: 0.1, max: 10 }),
+      color: faker.color.human(),
+      inProduction: faker.datatype.boolean(),
+      tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective())
+    };
+    dataList.push(dataItem);
+  }
+  return dataList;
+}
+const mockData = generateMockDataList(100);
+const list = eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  await sleep(600);
+  const { page, pageSize } = getQuery$1(event);
+  return usePageResponseSuccess(page, pageSize, mockData);
+});
+
+const list$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: list
+});
+
+const test_get = defineEventHandler(() => "Test get handler");
+
+const test_get$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: test_get
+});
+
+const test_post = defineEventHandler(() => "Test post handler");
+
+const test_post$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: test_post
+});
+
+const info = eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  return useResponseSuccess(userinfo);
+});
+
+const info$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: info
+});
+
+const _____ = defineEventHandler(() => {
+  return `
+<h1>Hello Vben Admin</h1>
+<h2>Mock service is starting</h2>
+<ul>
+<li><a href="/api/user">/api/user/info</a></li>
+<li><a href="/api/menu">/api/menu/all</a></li>
+<li><a href="/api/auth/codes">/api/auth/codes</a></li>
+<li><a href="/api/auth/login">/api/auth/login</a></li>
+</ul>
+`;
+});
+
+const _____$1 = /*#__PURE__*/Object.freeze({
+  __proto__: null,
+  default: _____
+});
+//# sourceMappingURL=index.mjs.map
diff --git a/eims-ui/apps/backend-mock/.nitro/dev/index.mjs.map b/eims-ui/apps/backend-mock/.nitro/dev/index.mjs.map
new file mode 100644
index 0000000..f695f3f
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/dev/index.mjs.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.mjs","sources":["../../error.ts","../../middleware/1.api.ts","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/storage.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/cache.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/utils.env.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/config.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/context.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/route-rules.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/utils.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/app.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/task.mjs","../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/presets/_nitro/runtime/nitro-dev.mjs","../../utils/mock-data.ts","../../utils/response.ts","../../utils/jwt-utils.ts","../../api/auth/codes.ts","../../utils/cookie-utils.ts","../../api/auth/login.post.ts","../../api/auth/logout.post.ts","../../api/auth/refresh.post.ts","../../api/menu/all.ts","../../api/status.ts","../../api/table/list.ts","../../api/test.get.ts","../../api/test.post.ts","../../api/user/info.ts","../../routes/[...].ts"],"sourcesContent":null,"names":["_inlineAppConfig","createRadixRouter","nitroApp","createRouter","createLocalFetch","createFetch","Headers","getQuery"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,YAAA,CAAkC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,KAAO,CAAA,CAAA;AAC9D,CAAA,CAAA,KAAA,CAAM,CAAA,CAAA,CAAA,EAAK,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAI,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAE,CAAA,CAAA;AACrD,CAAA;;;;;;ACJA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,WAAA,SAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACJO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAAE,CAAE,CAAA;AACtC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACtD;;ACQA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,mBAAmB,CAAG,CAAA,CAAA;AAC/B,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,EAAE,CAAG,CAAA,CAAA;AACb,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,EAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAAE,CAAI,CAAA,CAAA,CAAA;AACb,CAAA,CAAA,CAAA,CAAI,MAAM,CAAE,CAAA;AACZ,CAAG,CAAA,CAAA;AACH;AACO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,oBAAoB,CAAC,CAAA,CAAE,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAAE,CAAE,CAAA;AACpD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,GAAG,CAAE,CAAA,CAAA,CAAA,CAAG,mBAAmB,CAAE,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AAC9C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAE,CAAA;AACpB,CAAA,CAAE,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,IAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,IAAI,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC/C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAG,CAAA,CAAA;AAC1C,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC;AACtD,CAAA,CAAE,MAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAC,QAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC;AACvE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAG,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAqB,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAClE,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAG,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAG,GAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC;AAChH,CAAA,CAAA,CAAA,CAAI,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACtE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAiC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAC/D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,WAAW,CAAE,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACnE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAE,CAAA;AACZ,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,QAAQ,CAAE,CAAA;AACnC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,GAAG,CAAE,CAAA;AAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,iCAAiC,CAAC;AAChE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAC;AAC7C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,WAAW,CAAE,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACnE,CAAA,CAAA,CAAA,CAAA;AACA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAI,CAAG,CAAA,CAAA;AACxC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,GAAG,CAAE,CAAA;AACb,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,IAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA;AACtC,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAqB,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,IAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACvJ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAC;AACpC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACtB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,WAAW,CAAI,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAI,IAAI,CAAC,CAAA,CAAA,CAAG,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC1F,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,KAAK,CAAC;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,KAAK,CAAC;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,KAAK,CAAC;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,KAAK,CAAC;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAClD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA;AACV,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,MAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAC;AACxC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AACtB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACtB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,GAAG,CAAI,CAAA,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,IAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,KAAK,CAAE,CAAA;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACrB,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,IAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AACxC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,GAAG,CAAE,CAAA,CAAA,CAAA,CAAG,EAAE,CAAI,CAAA,CAAA,CAAA,CAAC,MAAM,CAAE,CAAA;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,MAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAE,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAC1F,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAkC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACtE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,WAAW,CAAE,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACzE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC;AACZ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AACpC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AACpE,CAAA,CAAA,CAAA,CAAI,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,KAAK,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACpD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,eAAe,CAAC;AACtC,CAAA,CAAA,CAAA,CAAA;AACA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC/C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,eAAe,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACvC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAkC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAClE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,WAAW,CAAE,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC;AAC5C,CAAA,CAAA;AACA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AAC5B,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC;AACrE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,iBAAiB,CAAE,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAG,IAAI,CAAC;AACxB,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA,CAAA,CAAA,CAAG,IAAI,CAAC;AACtD,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC;AAC7E,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAG,IAAI,CAAC;AACvB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAC,CAAC,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC,CAAC,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AACnD,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAC,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AAC3D,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AAChB,CAAG,CAAA,CAAA;AACH;AACO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,cAAc,CAAC,CAAA,CAAE,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAAE,CAAE,CAAA;AAC9C,CAAA,CAAE,OAAO,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAE,IAAI,CAAC;AACvC;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACzB,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,GAAG,CAAC,CAAA,CAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAC,GAAG,CAAE,CAAA;AAC9C;AACA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AACxB,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAE,CAAC;AACvC;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAwB,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,EAAE,CAAE,CAAA;AAChF,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACpG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA;AAChB,CAAA,CAAA,CAAA,CAAI,GAAG,CAAI,CAAA,CAAA,CAAA;AACX,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAC7B,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,SAAS,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAClD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,SAAS,CAAE,CAAA;AACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,GAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA;AAClF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA;AACV,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,GAAG,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,SAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAE,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1F,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACd,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,GAAG,CAAG,CAAA,CAAA;AACvB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAG,CAAA,CAAA,CAAC,EAAE,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC;AACvD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,QAAQ,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAC,CAAA,CAAA,CAAA,CAAI,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC,CAAC;AAChK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA,CAAA,CAAA,CAAG,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC;AACjD,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACzB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,GAAG,CAAE,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC5G,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAI,CAAA,CAAA,CAAA;AACjB,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,KAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,IAAI,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACzC,CAAA,CAAA,CAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC;AACrD,CAAG,CAAA,CAAA;AACH,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,aAAa,CAAK,CAAA,CAAA,CAAA,CAAA;AAC7B,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,mBAAmB,CAAE,CAAA;AAChD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC;AAC5D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,aAAa,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AAC9D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAE,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACtB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,aAAa,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AAC9D,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAE,CAAG,CAAA,CAAA;AACvB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA;AAC5B,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA;AAC/B,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA;AAC1B,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA;AACrB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AACjC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAE,CAAA;AAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAI,CAAA,CAAA,CAAA;AACrB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,cAAc,CAAG,CAAA,CAAA;AACzB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,UAAU,CAAC;AACxC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACxB,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AACjC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,UAAU,CAAG,CAAA,CAAA;AACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,GAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA;AAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,QAAQ,CAAE,CAAA;AACzC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,UAAU,CAAE,CAAA;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,IAAI,CAAE,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,UAAU,CAAE,CAAA;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,IAAI,CAAE,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAI,CAAA,CAAA,CAAA;AACrB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,QAAQ,CAAE,CAAA;AACzC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,UAAU,CAAE,CAAA;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAI,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,UAAU,CAAE,CAAA;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,IAAI,CAAE,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAI,CAAA,CAAA,CAAA;AACrB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAE,CAAA;AACxC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACtC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,QAAQ,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA;AACzE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,gCAAgC,CAAC;AACnE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,QAAQ,CAAE,CAAA;AAC3C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC;AAC5C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AACpC,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACxB,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClB,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,OAAO,CAAI,CAAA,CAAA,CAAA;AACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC;AACnD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAA,CAAE,YAAY,CAAE,CAAA;AACpF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAA,CAAE,YAAY,CAAE,CAAA;AACrF,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAG,CAAA,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA;AACjB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA;AACjD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAC,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,EAAE,CAAI,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAC;AAC1D,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAE,CAAA;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA;AACzB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAC,CAAC;AACtD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAuB,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAC,CAAC;AACzE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACf,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,wBAAwB,CAAC;AACrD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAC,MAAM,CAAE,CAAA;AAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAC,CAAC;AACnD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAE,CAAA;AACnC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAC,CAAA,CAAA,CAAG,YAAY,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AAC1D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAG,CAAA,CAAA;AACzB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACf,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACR,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvB,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACJ,CAAG,CAAA,CAAA;AACH,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAC7C,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAE,CAAA;AAC9D,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAC3B,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACzC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACN,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,GAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,aAAa,CAAE,CAAA;AACpE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAClC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC;AAC/D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAI,CAAA,CAAA,CAAA;AACjC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AACR,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACN,CAAA,CAAA,CAAA,CAAA;AACA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA;AAC7C,CAAA,CAAA,CAAA,CAAI,KAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,IAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAE,CAAA;AACzC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAE,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,KAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAI,CAAA,CAAA,CAAA;AACd,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA;AAClC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AAC9B,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAC/C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA;AACA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA;AACxB,CAAA,CAAA,CAAG,CAAC;AACJ;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,SAAS,CAAE,CAAA;AACxC,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA;AACxB,CAAA,CAAA,CAAA,CAAI,GAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAE,CAAA;AACpC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,MAAM,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC;AACpD,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA;AAC3C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAI,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC;AAC3D,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAG,CAAC;AACJ;AACO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,GAAG,CAAwB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;ACtVnD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA;AAClC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC7C,CAAA,CAAE,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACd,CAAA,CAAA,CAAA,CAAI,OAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAG,CAAA,CAAA,CAAC,IAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,GAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AAC5E,CAAG,CAAA,CAAA;AACH;AACA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC1B,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AAC3D;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAG,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA;AACpD,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,GAAG,CAAE,CAAA;AACzB,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,GAAG,CAAC,CAAA,CAAE,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA,CAAG,CAAC,CAAC,GAAG,CAAG,CAAA,CAAA;AAC1D,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,QAAQ,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAC;AACzC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAE,CAAA;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAE,CAAA;AAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAG,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA,CAAA,CAAA,CAAG,CAAG,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAG,QAAQ,CAAE,CAAA;AAC/C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC;AACxC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,MAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AACtC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC;AACxC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACb,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,QAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,QAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC;AACrC,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAG,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA;AAC3D,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC;AACzC,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;AACA,CAAA,CAAE,OAAO,CAAG,CAAA,CAAA;AACZ;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,GAAG,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAChC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC/B,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AACpD,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,OAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAG,CAAA,CAAA,CAAC,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AACpC,CAAA,CAAA,CAAG,CAAC;AACJ;;ACnCA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,oBAAoB,CAAG,CAAA,CAAA;AAAA,CAAA,CAAA,KAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,OAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,YAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,+BAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAAA,CAA0B;AACvD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAG,CAAA,CAAA;AACnB,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClB,CAAA,CAAE,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,IAAI,CAAG,CAAA,CAAA;AACxF,CAAA,CAAE,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,mBAAmB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC9F,CAAC;AACD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,GAAG,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxC,CAAA,CAAE,QAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClD,CAAC;AACM,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AACxC,CAAc,CAAA;AACd,CAAA,CAAA,CAAA,CAAI,OAAO,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC/B,CAAA,CAAA;AAQA;AACyB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAACA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAgB,CAAC,CAAA;AAY5D,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA;AAC7B,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,SAAS,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC;AACtD,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,SAAS,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAI,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC;AAC9B,CAAA,CAAA,CAAA,CAAI,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,QAAQ,CAAE,CAAA;AAC5C,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACxB,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;AACA,CAAA,CAAE,OAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC;AAC9B;AACe,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,iBAAiB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAE,CAAA;AAC9D,CAAA,CAAE,GAAG,CAAE,CAAA,CAAC,CAAC,CAAA,CAAE,IAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AACpB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAI,CAAA,CAAA,CAAA;AAChB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACN,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAE,CAAA;AAC5C,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAE,CAAA;AAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AAChC,CAAA,CAAA,CAAA,CAAA;AACA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,KAAK,CAAC;AACjB,CAAA,CAAA;AACA,CAAC,CAAC;;ACtD+B,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,WAAW,CAAE,CAAA;AACzD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,EAAE,CAAyB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACzC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiB,EAAkD,CAAK,CAAA,CAAA,CAAA,CAAA;AAC1E,CAAC,CAAA;;ACID,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAE,CAAA;AACjC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,GAAG,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACzC,CAAEC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAiB,CAAC,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,MAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA;AACvD,CAAC;AACM,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAuB,CAAC,CAAA,CAAA,CAAG,CAAE,CAAA;AAC7C,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACjC,CAAA,CAAA,CAAA,CAAI,MAAM,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC;AAC3C,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AAC3C,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAE,CAAA;AACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,QAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC/D,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,QAAQ,CAAE,CAAA;AACtB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,UAAU,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC;AACxD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA,CAAE,UAAU,CAAC;AACzD,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAE,CAAA;AAC3C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAC;AACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC;AACxE,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AACtC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,QAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACzD,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,QAAQ,CAAE,CAAA;AACtB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,UAAU,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC;AACxD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA,CAAE,UAAU,CAAC;AACzD,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAE,CAAA;AAC3C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC;AAC1C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAC;AACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,MAAM,CAAE,CAAA;AACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC7B,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA;AACtB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAG,CAAC;AACJ;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AACrC,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACnD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA;AACxC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,GAAG,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,WAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC,CAAC,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,EAAE,CAAC,CAAA,CAAA,CAAG,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1E,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA;AACA,CAAA,CAAE,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxC;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AAC3C,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAE,EAAE,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAC;AACjE;;ACVA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA;AACpC,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC,CAAC,CAAA,CAAE,KAAK,CAAC;AAC3C,CAAA,CAAE,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACrD;AACO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,uBAAuB,CAAG,CAAA,CAAA;AAC1C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAE,CAAA;AACZ,CAAA,CAAA,CAAA,CAAI,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxB,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,aAAa,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxD,CAAG,CAAA,CAAA;AACH,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAE,CAAA;AACZ,CAAA,CAAA,CAAA,CAAI,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvB,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,aAAa,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvD,CAAG,CAAA,CAAA;AACH;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AACnC,CAAA,CAAE,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,GAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC;AAChE;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAE,CAAA;AACjD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAG,CAAA,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA;AAC3C,CAAA,CAAA,CAAA,CAAI,OAAO,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA;AACA,CAAA,CAAE,OAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAE,CAAA;AACrC,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3B,CAAA,CAAA,CAAA,CAAI,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnC,CAAA,CAAA,CAAA,CAAI,OAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACpD,CAAA,CAAA,CAAG,CAAC;AACJ;AACO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAAE,CAAE,CAAA;AACnD,CAAA,CAAE,OAAO,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,WAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAC;AAChD;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AAChD,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAE,CAAA;AACvC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,MAAM,CAAC,CAAA,CAAA,CAAA,CAAI,EAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AACxC,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAE,CAAA;AAC/B,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,MAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,qBAAqB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAE,CAAA;AAC1D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,eAAe,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,MAAM,CAAC;AACpD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAI,EAAE,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC;AACpD,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;AACA,CAAA,CAAE,OAAO,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACxB;;AC1EA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,cAAc,CAAG,CAAA,CAAA;AAC1B,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAE,CAAA;AACnC,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC7B,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,YAAY,CAAG,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA;AAChD,CAAA,CAAA,CAAA,CAAI,MAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA;AACtF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAqC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,MAAM,CAAC;AAClE,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACN,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA;AACjD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACxD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,MAAM,CAAE,CAAA;AAClB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,SAAS,CAAE,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AACxC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA;AACA,CAAG,CAAA,CAAA;AACH,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC;AAC1B,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAiB,CAAC;AACnC,CAAA,CAAA,CAAA,CAAI,OAAO,CAAE,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACvD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,KAAK,CAAC;AACvC,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAChC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAMC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,QAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACvE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACzD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,gBAAgB,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAK,CAAA,CAAA,CAAA,CAAA;AACjD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAMA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACxF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,eAAe,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAK,CAAA,CAAA,CAAA,CAAA;AAChD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAMA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACvF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAG,CAAC;AACJ,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAGC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAY,CAAC;AAC9B,CAAA,CAAA,CAAA,CAAI,UAAU,CAAE,CAAA,CAAA,CAAA,CAAA;AAChB,CAAA,CAAA,CAAG,CAAC;AACJ,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,SAAS,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC;AACrD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAGC,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,SAAS,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACnE,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAG,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAI,CAAA,CAAA,CAAA;AACnE,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjD,CAAG,CAAA,CAAA;AACH,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAGC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAAC;AAC7B,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,EAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC3C,CAAA,CAAA,CAAG,CAAC;AACJ,CAAA,CAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AAC5B,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAuB,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA,CAAC,CAAC;AACpD,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAG,CAAA,CAAA;AACX,CAAA,CAAA,CAAA,CAAI,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAE,CAAA;AACjE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,UAAU,CAAE,CAAA;AACtB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC;AAChD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAG,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAE,CAAA,CAAA,CAAA,CAAG,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAC1F,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAG,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA;AACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,KAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACf,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAG,CAAA,CAAA,CAAC,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AACrC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAE,CAAA;AACrD,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,GAAG,CAAE,CAAA;AACrD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AAC5D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AACvC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,OAAO,CAAK,CAAA,CAAA,CAAA,CAAA;AAC/C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAE,KAAK,CAAE,CAAA,CAAA,CAAA,CAAG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAClD,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAG,CAAA,CAAA;AACH,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAI,QAAQ,CAAE,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAI,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAC,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAC,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAClE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,IAAI,CAAC,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAG,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,IAAI,CAAG,CAAA,CAAA,CAAC,EAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC5E,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACd,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACR,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAG,CAAC,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,OAAO,CAAC;AACxC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC7C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,EAAE,CAAG,CAAA,CAAA;AACzC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAE,CAAA;AAC9C,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC/B,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,UAAU,CAAC,CAAA,CAAA,CAAA,CAAA;AACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC;AACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;AACA,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AAQ/C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,GAAG,CAAG,CAAA,CAAA;AACd,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACV,CAAA,CAAA,CAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACb,CAAA,CAAA,CAAA,CAAI,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACd,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACJ,CAAG,CAAA,CAAA;AACH,CAAA,CAAE,OAAO,CAAG,CAAA,CAAA;AACZ;AACA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAE,CAAA;AACpC,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAE,CAAA;AAChC,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA;AACR,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC;AACvB,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAC;AACzD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA;AACjB,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;AACA;AACO,CAAMJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAE,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,WAAW,CAAG,CAAA,CAAA;AAC9B,CAAA,CAAE,OAAOA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjB;AACA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAACA,UAAQ,CAAC;;;;;;;;AChJzB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,GAAG,CAAE,CAAA;AACpB,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA;AACpC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,GAAG,CAAE,CAAA;AACd,CAAA,CAAE,OAAO,CAAG,CAAA,CAAA,CAAA;AACZ,CAAC,CAAA,CAAA,CAAG,EAAE,CAAE,CAAA;AACR,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAE,CAAA;AAC9B,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AACjC,CAAA,CAAA;AACA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAE,CAAA;AACxB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,WAAW,CAAC;AACtB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAI,CAAA,CAAA,CAAA,CAAC,oBAAoB,CAAC;AACnD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAE,CAAA,CAAA,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACN,CAAA,CAAA;AACA,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC,CAAC,OAAO,CAAE,CAAA;AAC5B,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,WAAW,CAAC;AACtB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAI,CAAA,CAAA,CAAA,CAAC,sBAAsB,CAAC;AACrD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAE,CAAA,CAAA,CAAA;AAClB,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACN,CAAA,CAAA;AACA,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAI,CAAA,CAAA,CAAA,CAAC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AAC7C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,SAAS,CAAG,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA;AAC9C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAG,OAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC;AACjD,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA;AACN,CAAA,CAAA,CAAA,CAAI,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAG,MAAM,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAC;AAC5C,CAAA,CAAA,CAAA,CAAI,OAAO,CAAG,CAAA,CAAA;AACd,CAAA,CAAA,CAAG,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACZ,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC,CAAA,CAAA,CAAA,CAAI,CAAC;AACjC,CAAA,CAAA;AACA;;ACrBA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA;AAC9B,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC;AAKzD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,UAAU,CAAG,CAAA,CAAA;AACtB,CAAA,CAAE,IAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,OAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,IAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,GAAG,CAAE,CAAA;AAC7F,CAAA,CAAA,CAAA,CAAI,OAAO,CAAC;AACZ,CAAA,CAAA;AACA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAG,CAAA,CAAA,CAAC,OAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAG,CAAC,CAAC,CAAA,CAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC;AAC7D,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,SAAS,CAAE,CAAA;AACjB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA,CAAC,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC;AACvD,CAAA,CAAA;AACA,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,SAAS,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC;AAC3C,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,EAAE,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAC3C,CAAA,CAAE,OAAO,CAAI,CAAA,CAAA,CAAA,CAAC,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,UAAU,CAAC;AACpC;AACA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA;AACjB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,EAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AACpD,CAAA,CAAE,MAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAE,CAAA;AACnC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC;AAC1B,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,EAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,KAAK,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,EAAE,CAAG,CAAA,CAAA,CAAA,CAAE,IAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA;AAChH,CAAA,CAAA,CAAG,CAAC;AACJ,CAAC,CAAA;AACD,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA;AACnB,CAAA,CAAE,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACjB,CAAA,CAAE,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACtC,CAAA,CAAA,CAAA,CAAI,MAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAG,CAAA,CAAA;AACpC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAC,CAAG,CAAA,CAAA,CAAC,OAAO,CAAC,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA;AACxD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,MAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,MAAM,CAAI,CAAA,CAAA,CAAA,CAAC,OAAO,CAAI,CAAA,CAAA,CAAA;AAC5C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAE,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAE,CAAC;AAChE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAA,CAAA,CAAA,CAAI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAC,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,MAAM,CAAC;AACvC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACN,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAG,CAAA,CAAA;AACH,CAAC;AACD,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG,CAAA,CAAA;AACnB,CAAA,CAAE,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvB,CAAA,CAAE,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK,CAAA,CAAA,CAAA,CAAA;AACtC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,MAAM,CAAC;AAC9C,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,OAAO,CAAG,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAGK,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC;AACxB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,MAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AACvE,CAAK,CAAA,CAAA,CAAA,CAAA;AACL,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,MAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,IAAI,CAAE,CAAA,CAAA,CAAE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAC3C,CAAG,CAAA,CAAA;AACH,CAAC;AACD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAuB,CAAE,CAAA;AACzB,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAE,CAAA;AAClC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,QAAQ,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,OAAO,CAAC;AACxC;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAE,CAAE,CAAA,CAAC,SAAS,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,GAAG,CAAK,CAAA,CAAA,CAAA,CAAA;AACzC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAI,GAAG,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAC,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,UAAU,CAAE,CAAA;AACvC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAU,CAAE,CAAA;AACtB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAE,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAC;AAC9C,CAAA,CAAA;AACA,CAAC,CAAC;;ACzEK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAyB,CAAA,CAAA,CAAA;AAAA,CACpC,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAI,EAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA;AAAA,CAAA,CAAA,CAAA,CACf,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAI,EAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA;AAAA,CAAA,CAAA,CAAA,CACf,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAI,EAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACV,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA;AAAA,CAAA,CAAA,CAAA,CACd,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEd,CAAA;AAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAa,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAExB,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAC,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,WAAA,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA;AAAA,CAAA,CAAA,CAAA,CAC1D,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAEE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAA,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,WAAW,CAAA;AAAA,CAAA,CAAA,CAAA,CAC7C,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAEE,KAAA,CAAO,CAAA,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,YAAY,CAAA;AAAA,CAAA,CAAA,CAAA,CAClC,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEd,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,cAAiB,CAAA,CAAA,CAAA;AAAA,CACrB,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACP,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACV,QAAU,CAAA,CAAA;AAAA,CACR,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACV,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACJ,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACF,CAAA,CAAA,CAAA,CAAA;AACF,CAAA,CAAA;AAEJ,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAC,CAAA,CAAA,CAAA,CAAqC,CAAA,CAAA,CAAA,CAAA,CAAA;AAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,aAAgB,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACpB,KAAO,CAAA,CAAA;AAAA,CACL,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,IAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACR,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,KAAO,CAAA,CAAA;AAAA,CACL,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,IAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACR,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,IAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA;AACR,CACF,CAAA,CAAA;AAEA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACL,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACX,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACP,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACV,QAAU,CAAA,CAAA;AAAA,CACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACV,QAAU,CAAA,CAAA;AAAA,CACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACX,IAAM,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAA;AAAA,CACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAA0B,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAC1B,KAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAc,CAAI,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACF,CAAA,CAAA,CAAA,CAAA;AACF,CACF,CAAA,CAAA;AACF,CAAA;AAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAa,CAAA,CAAA,CAAA;AAAA,CACxB,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAO,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAgB,CAAA,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAA;AAAA,CAAA,CAAA,CAAA,CACvD,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAO,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAgB,CAAA,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAA;AAAA,CAAA,CAAA,CAAA,CACvD,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACZ,CAAA,CAAA;AAAA,CACA,CAAA;AAAA,CACE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAO,CAAA,CAAC,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAgB,CAAA,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAA;AAAA,CAAA,CAAA,CAAA,CACtD,QAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEd,CAAA;;ACvLA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,MACA,QACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,gBAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,iBAAA,CACA,CAAA,CAAA,CAAA,CAAA,CACA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,qBACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,GAAA,CAAA;AACA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SAAA,OAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,GAAA,CAAA;AACA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,0BAAA,wBAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,UAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,KACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SACA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,MAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA;;AC5DA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAOA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,qBAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,oBAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EACA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,UAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,eAAA,CAAA;AACA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,aAAA,QAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EACA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,aAAA,QAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEA;;ACvDA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,MAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,YAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;ACXA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,KAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,OACA,YACA,CAAA,CAAA;AACA,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,OAAA,YAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,YAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA;AACA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA;;AClBA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,QAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,GAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,oCAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,oBAAA,QAAA,CAAA;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,qBAAA,QAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,YAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CACA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CACA,CAAA;AACA,CAAA,CAAA;;;;;;;AC9BA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,0BAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;ACNA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,0BAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,mBAAA,YAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,oBAAA,QAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,YAAA,CAAA;AAEA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;AC7BA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,MAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,YAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;ACZA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,gBAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;ACAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,WAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,QAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,QAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,MAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,WAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,WAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,QAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,YAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,QAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,SAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,QAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,UAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,WAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,EAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,WAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,YAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,gBAAA,CAAA,CAAA;AAAA,CACA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,KAAA,QAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,OAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,qBAAA,GAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,sBAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,QAAA,CAAA;AACA,CAAA,CAAA;;;;;;;AC/CA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;ACAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;ACGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,kBAAA,KAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA;;;;;;;ACTA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAA;AAUA,CAAA,CAAA;;;;;","x_google_ignoreList":[2,3,4,5,6,7,8,9,10,11]}
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/nitro.json b/eims-ui/apps/backend-mock/.nitro/nitro.json
new file mode 100644
index 0000000..56c9888
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/nitro.json
@@ -0,0 +1,17 @@
+{
+  "date": "2024-12-27T07:28:57.105Z",
+  "preset": "nitro-dev",
+  "framework": {
+    "name": "nitro",
+    "version": ""
+  },
+  "versions": {
+    "nitro": "2.10.4"
+  },
+  "dev": {
+    "pid": 57704,
+    "workerAddress": {
+      "socketPath": "/var/folders/q5/48k6t5nx67x3gc5_lhr9h56m0000gn/T/nitro/worker-57704-1.sock"
+    }
+  }
+}
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/types/nitro-config.d.ts b/eims-ui/apps/backend-mock/.nitro/types/nitro-config.d.ts
new file mode 100644
index 0000000..42e138f
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/types/nitro-config.d.ts
@@ -0,0 +1,16 @@
+// Generated by nitro
+
+// App Config
+import type { Defu } from 'defu'
+
+
+
+type UserAppConfig = Defu<{}, []>
+
+declare module "nitropack/types" {
+  interface AppConfig extends UserAppConfig {}
+  interface NitroRuntimeConfig {
+
+  }
+}
+export {}
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/types/nitro-imports.d.ts b/eims-ui/apps/backend-mock/.nitro/types/nitro-imports.d.ts
new file mode 100644
index 0000000..79665a6
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/types/nitro-imports.d.ts
@@ -0,0 +1,166 @@
+declare global {
+  const MOCK_CODES: typeof import('../../utils/mock-data')['MOCK_CODES']
+  const MOCK_MENUS: typeof import('../../utils/mock-data')['MOCK_MENUS']
+  const MOCK_USERS: typeof import('../../utils/mock-data')['MOCK_USERS']
+  const appendCorsHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendCorsHeaders']
+  const appendCorsPreflightHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendCorsPreflightHeaders']
+  const appendHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendHeader']
+  const appendHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendHeaders']
+  const appendResponseHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendResponseHeader']
+  const appendResponseHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['appendResponseHeaders']
+  const assertMethod: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['assertMethod']
+  const cachedEventHandler: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/cache')['cachedEventHandler']
+  const cachedFunction: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/cache')['cachedFunction']
+  const callNodeListener: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['callNodeListener']
+  const clearRefreshTokenCookie: typeof import('../../utils/cookie-utils')['clearRefreshTokenCookie']
+  const clearResponseHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['clearResponseHeaders']
+  const clearSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['clearSession']
+  const createApp: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createApp']
+  const createAppEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createAppEventHandler']
+  const createError: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createError']
+  const createEvent: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createEvent']
+  const createEventStream: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createEventStream']
+  const createRouter: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['createRouter']
+  const defaultContentType: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defaultContentType']
+  const defineCachedEventHandler: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/cache')['defineCachedEventHandler']
+  const defineCachedFunction: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/cache')['defineCachedFunction']
+  const defineEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineEventHandler']
+  const defineLazyEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineLazyEventHandler']
+  const defineNitroErrorHandler: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/error')['defineNitroErrorHandler']
+  const defineNitroPlugin: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/plugin')['defineNitroPlugin']
+  const defineNodeListener: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineNodeListener']
+  const defineNodeMiddleware: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineNodeMiddleware']
+  const defineRenderHandler: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/renderer')['defineRenderHandler']
+  const defineRequestMiddleware: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineRequestMiddleware']
+  const defineResponseMiddleware: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineResponseMiddleware']
+  const defineRouteMeta: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/meta')['defineRouteMeta']
+  const defineTask: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/task')['defineTask']
+  const defineWebSocket: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineWebSocket']
+  const defineWebSocketHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['defineWebSocketHandler']
+  const deleteCookie: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['deleteCookie']
+  const dynamicEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['dynamicEventHandler']
+  const eventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['eventHandler']
+  const fetchWithEvent: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['fetchWithEvent']
+  const forbiddenResponse: typeof import('../../utils/response')['forbiddenResponse']
+  const fromNodeMiddleware: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['fromNodeMiddleware']
+  const fromPlainHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['fromPlainHandler']
+  const fromWebHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['fromWebHandler']
+  const generateAccessToken: typeof import('../../utils/jwt-utils')['generateAccessToken']
+  const generateRefreshToken: typeof import('../../utils/jwt-utils')['generateRefreshToken']
+  const getCookie: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getCookie']
+  const getHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getHeader']
+  const getHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getHeaders']
+  const getMethod: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getMethod']
+  const getProxyRequestHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getProxyRequestHeaders']
+  const getQuery: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getQuery']
+  const getRefreshTokenFromCookie: typeof import('../../utils/cookie-utils')['getRefreshTokenFromCookie']
+  const getRequestFingerprint: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestFingerprint']
+  const getRequestHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestHeader']
+  const getRequestHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestHeaders']
+  const getRequestHost: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestHost']
+  const getRequestIP: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestIP']
+  const getRequestPath: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestPath']
+  const getRequestProtocol: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestProtocol']
+  const getRequestURL: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestURL']
+  const getRequestWebStream: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRequestWebStream']
+  const getResponseHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getResponseHeader']
+  const getResponseHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getResponseHeaders']
+  const getResponseStatus: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getResponseStatus']
+  const getResponseStatusText: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getResponseStatusText']
+  const getRouteRules: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/route-rules')['getRouteRules']
+  const getRouterParam: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRouterParam']
+  const getRouterParams: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getRouterParams']
+  const getSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getSession']
+  const getValidatedQuery: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getValidatedQuery']
+  const getValidatedRouterParams: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['getValidatedRouterParams']
+  const handleCacheHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['handleCacheHeaders']
+  const handleCors: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['handleCors']
+  const isCorsOriginAllowed: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isCorsOriginAllowed']
+  const isError: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isError']
+  const isEvent: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isEvent']
+  const isEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isEventHandler']
+  const isMethod: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isMethod']
+  const isPreflightRequest: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isPreflightRequest']
+  const isStream: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isStream']
+  const isWebResponse: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['isWebResponse']
+  const lazyEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['lazyEventHandler']
+  const nitroPlugin: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/plugin')['nitroPlugin']
+  const pagination: typeof import('../../utils/response')['pagination']
+  const parseCookies: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['parseCookies']
+  const promisifyNodeListener: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['promisifyNodeListener']
+  const proxyRequest: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['proxyRequest']
+  const readBody: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['readBody']
+  const readFormData: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['readFormData']
+  const readMultipartFormData: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['readMultipartFormData']
+  const readRawBody: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['readRawBody']
+  const readValidatedBody: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['readValidatedBody']
+  const removeResponseHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['removeResponseHeader']
+  const runTask: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/task')['runTask']
+  const sanitizeStatusCode: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sanitizeStatusCode']
+  const sanitizeStatusMessage: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sanitizeStatusMessage']
+  const sealSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sealSession']
+  const send: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['send']
+  const sendError: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendError']
+  const sendIterable: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendIterable']
+  const sendNoContent: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendNoContent']
+  const sendProxy: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendProxy']
+  const sendRedirect: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendRedirect']
+  const sendStream: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendStream']
+  const sendWebResponse: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['sendWebResponse']
+  const serveStatic: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['serveStatic']
+  const setCookie: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setCookie']
+  const setHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setHeader']
+  const setHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setHeaders']
+  const setRefreshTokenCookie: typeof import('../../utils/cookie-utils')['setRefreshTokenCookie']
+  const setResponseHeader: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setResponseHeader']
+  const setResponseHeaders: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setResponseHeaders']
+  const setResponseStatus: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['setResponseStatus']
+  const sleep: typeof import('../../utils/response')['sleep']
+  const splitCookiesString: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['splitCookiesString']
+  const toEventHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['toEventHandler']
+  const toNodeListener: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['toNodeListener']
+  const toPlainHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['toPlainHandler']
+  const toWebHandler: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['toWebHandler']
+  const toWebRequest: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['toWebRequest']
+  const unAuthorizedResponse: typeof import('../../utils/response')['unAuthorizedResponse']
+  const unsealSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['unsealSession']
+  const updateSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['updateSession']
+  const useAppConfig: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/config')['useAppConfig']
+  const useBase: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['useBase']
+  const useEvent: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/context')['useEvent']
+  const useNitroApp: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/app')['useNitroApp']
+  const usePageResponseSuccess: typeof import('../../utils/response')['usePageResponseSuccess']
+  const useResponseError: typeof import('../../utils/response')['useResponseError']
+  const useResponseSuccess: typeof import('../../utils/response')['useResponseSuccess']
+  const useRuntimeConfig: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/config')['useRuntimeConfig']
+  const useSession: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['useSession']
+  const useStorage: typeof import('../../../../node_modules/.pnpm/nitropack@2.10.4_encoding@0.1.13_typescript@5.7.2/node_modules/nitropack/dist/runtime/internal/storage')['useStorage']
+  const verifyAccessToken: typeof import('../../utils/jwt-utils')['verifyAccessToken']
+  const verifyRefreshToken: typeof import('../../utils/jwt-utils')['verifyRefreshToken']
+  const writeEarlyHints: typeof import('../../../../node_modules/.pnpm/h3@1.13.0/node_modules/h3')['writeEarlyHints']
+}
+// for type re-export
+declare global {
+  // @ts-ignore
+  export type { UserPayload } from '../../utils/jwt-utils'
+  import('../../utils/jwt-utils')
+  // @ts-ignore
+  export type { UserInfo } from '../../utils/mock-data'
+  import('../../utils/mock-data')
+}
+export { useNitroApp } from 'nitropack/runtime/internal/app';
+export { useRuntimeConfig, useAppConfig } from 'nitropack/runtime/internal/config';
+export { defineNitroPlugin, nitroPlugin } from 'nitropack/runtime/internal/plugin';
+export { defineCachedFunction, defineCachedEventHandler, cachedFunction, cachedEventHandler } from 'nitropack/runtime/internal/cache';
+export { useStorage } from 'nitropack/runtime/internal/storage';
+export { defineRenderHandler } from 'nitropack/runtime/internal/renderer';
+export { defineRouteMeta } from 'nitropack/runtime/internal/meta';
+export { getRouteRules } from 'nitropack/runtime/internal/route-rules';
+export { useEvent } from 'nitropack/runtime/internal/context';
+export { defineTask, runTask } from 'nitropack/runtime/internal/task';
+export { defineNitroErrorHandler } from 'nitropack/runtime/internal/error';
+export { appendCorsHeaders, appendCorsPreflightHeaders, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, clearResponseHeaders, clearSession, createApp, createAppEventHandler, createError, createEvent, createEventStream, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, defineRequestMiddleware, defineResponseMiddleware, defineWebSocket, defineWebSocketHandler, deleteCookie, dynamicEventHandler, eventHandler, fetchWithEvent, fromNodeMiddleware, fromPlainHandler, fromWebHandler, getCookie, getHeader, getHeaders, getMethod, getProxyRequestHeaders, getQuery, getRequestFingerprint, getRequestHeader, getRequestHeaders, getRequestHost, getRequestIP, getRequestPath, getRequestProtocol, getRequestURL, getRequestWebStream, getResponseHeader, getResponseHeaders, getResponseStatus, getResponseStatusText, getRouterParam, getRouterParams, getSession, getValidatedQuery, getValidatedRouterParams, handleCacheHeaders, handleCors, isCorsOriginAllowed, isError, isEvent, isEventHandler, isMethod, isPreflightRequest, isStream, isWebResponse, lazyEventHandler, parseCookies, promisifyNodeListener, proxyRequest, readBody, readFormData, readMultipartFormData, readRawBody, readValidatedBody, removeResponseHeader, sanitizeStatusCode, sanitizeStatusMessage, sealSession, send, sendError, sendIterable, sendNoContent, sendProxy, sendRedirect, sendStream, sendWebResponse, serveStatic, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, setResponseStatus, splitCookiesString, toEventHandler, toNodeListener, toPlainHandler, toWebHandler, toWebRequest, unsealSession, updateSession, useBase, useSession, writeEarlyHints } from 'h3';
+export { clearRefreshTokenCookie, setRefreshTokenCookie, getRefreshTokenFromCookie } from '../../utils/cookie-utils';
+export { generateAccessToken, generateRefreshToken, verifyAccessToken, verifyRefreshToken } from '../../utils/jwt-utils';
+export { MOCK_USERS, MOCK_CODES, MOCK_MENUS } from '../../utils/mock-data';
+export { useResponseSuccess, usePageResponseSuccess, useResponseError, forbiddenResponse, unAuthorizedResponse, sleep, pagination } from '../../utils/response';
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/types/nitro-routes.d.ts b/eims-ui/apps/backend-mock/.nitro/types/nitro-routes.d.ts
new file mode 100644
index 0000000..e61fd59
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/types/nitro-routes.d.ts
@@ -0,0 +1,39 @@
+// Generated by nitro
+import type { Serialize, Simplify } from "nitropack/types";
+declare module "nitropack/types" {
+  type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T
+  interface InternalApi {
+    '/api/auth/codes': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/auth/codes').default>>>>
+    }
+    '/api/auth/login': {
+      'post': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/auth/login.post').default>>>>
+    }
+    '/api/auth/logout': {
+      'post': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/auth/logout.post').default>>>>
+    }
+    '/api/auth/refresh': {
+      'post': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/auth/refresh.post').default>>>>
+    }
+    '/api/menu/all': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/menu/all').default>>>>
+    }
+    '/api/status': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/status').default>>>>
+    }
+    '/api/table/list': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/table/list').default>>>>
+    }
+    '/api/test': {
+      'get': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/test.get').default>>>>
+      'post': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/test.post').default>>>>
+    }
+    '/api/user/info': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../api/user/info').default>>>>
+    }
+    '/**': {
+      'default': Simplify<Serialize<Awaited<ReturnType<typeof import('../../routes/[...]').default>>>>
+    }
+  }
+}
+export {}
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/types/nitro.d.ts b/eims-ui/apps/backend-mock/.nitro/types/nitro.d.ts
new file mode 100644
index 0000000..bf09bd4
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/types/nitro.d.ts
@@ -0,0 +1,3 @@
+/// <reference path="./nitro-routes.d.ts" />
+/// <reference path="./nitro-config.d.ts" />
+/// <reference path="./nitro-imports.d.ts" />
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/.nitro/types/tsconfig.json b/eims-ui/apps/backend-mock/.nitro/types/tsconfig.json
new file mode 100644
index 0000000..2544b01
--- /dev/null
+++ b/eims-ui/apps/backend-mock/.nitro/types/tsconfig.json
@@ -0,0 +1,37 @@
+{
+  "compilerOptions": {
+    "forceConsistentCasingInFileNames": true,
+    "strict": false,
+    "noEmit": true,
+    "target": "ESNext",
+    "module": "ESNext",
+    "moduleResolution": "Bundler",
+    "allowJs": true,
+    "resolveJsonModule": true,
+    "jsx": "preserve",
+    "allowSyntheticDefaultImports": true,
+    "jsxFactory": "h",
+    "jsxFragmentFactory": "Fragment",
+    "paths": {
+      "#imports": [
+        "./nitro-imports"
+      ],
+      "~/*": [
+        "../../*"
+      ],
+      "@/*": [
+        "../../*"
+      ],
+      "~~/*": [
+        "../../*"
+      ],
+      "@@/*": [
+        "../../*"
+      ]
+    }
+  },
+  "include": [
+    "./nitro.d.ts",
+    "../../**/*"
+  ]
+}
\ No newline at end of file
diff --git a/eims-ui/apps/backend-mock/README.md b/eims-ui/apps/backend-mock/README.md
new file mode 100644
index 0000000..401bda7
--- /dev/null
+++ b/eims-ui/apps/backend-mock/README.md
@@ -0,0 +1,15 @@
+# @vben/backend-mock
+
+## Description
+
+Vben Admin 鏁版嵁 mock 鏈嶅姟锛屾病鏈夊鎺ヤ换浣曠殑鏁版嵁搴擄紝鎵�鏈夋暟鎹兘鏄ā鎷熺殑锛岀敤浜庡墠绔紑鍙戞椂鎻愪緵鏁版嵁鏀寔銆傜嚎涓婄幆澧冧笉鍐嶆彁渚� mock 闆嗘垚锛屽彲鑷閮ㄧ讲鏈嶅姟鎴栬�呭鎺ョ湡瀹炴暟鎹紝鐢变簬 `mock.js` 绛夊伐鍏锋湁涓�浜涢檺鍒讹紝姣斿涓婁紶鏂囦欢涓嶈銆佹棤娉曟ā鎷熷鏉傜殑閫昏緫绛夛紝鎵�浠ヨ繖閲屼娇鐢ㄤ簡鐪熷疄鐨勫悗绔湇鍔℃潵瀹炵幇銆傚敮涓�楹荤儲鐨勬槸鏈湴闇�瑕佸悓鏃跺惎鍔ㄥ悗绔湇鍔″拰鍓嶇鏈嶅姟锛屼絾鏄繖鏍峰彲浠ユ洿濂界殑妯℃嫙鐪熷疄鐜銆傝鏈嶅姟涓嶉渶瑕佹墜鍔ㄥ惎鍔紝宸茬粡闆嗘垚鍦� vite 鎻掍欢鍐咃紝闅忓簲鐢ㄤ竴璧峰惎鐢ㄣ��
+
+## Running the app
+
+```bash
+# development
+$ pnpm run start
+
+# production mode
+$ pnpm run build
+```
diff --git a/eims-ui/apps/backend-mock/api/auth/codes.ts b/eims-ui/apps/backend-mock/api/auth/codes.ts
new file mode 100644
index 0000000..7ba0127
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/auth/codes.ts
@@ -0,0 +1,14 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const codes =
+    MOCK_CODES.find((item) => item.username === userinfo.username)?.codes ?? [];
+
+  return useResponseSuccess(codes);
+});
diff --git a/eims-ui/apps/backend-mock/api/auth/login.post.ts b/eims-ui/apps/backend-mock/api/auth/login.post.ts
new file mode 100644
index 0000000..df5737a
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/auth/login.post.ts
@@ -0,0 +1,36 @@
+import {
+  clearRefreshTokenCookie,
+  setRefreshTokenCookie,
+} from '~/utils/cookie-utils';
+import { generateAccessToken, generateRefreshToken } from '~/utils/jwt-utils';
+import { forbiddenResponse } from '~/utils/response';
+
+export default defineEventHandler(async (event) => {
+  const { password, username } = await readBody(event);
+  if (!password || !username) {
+    setResponseStatus(event, 400);
+    return useResponseError(
+      'BadRequestException',
+      'Username and password are required',
+    );
+  }
+
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === username && item.password === password,
+  );
+
+  if (!findUser) {
+    clearRefreshTokenCookie(event);
+    return forbiddenResponse(event, 'Username or password is incorrect.');
+  }
+
+  const accessToken = generateAccessToken(findUser);
+  const refreshToken = generateRefreshToken(findUser);
+
+  setRefreshTokenCookie(event, refreshToken);
+
+  return useResponseSuccess({
+    ...findUser,
+    accessToken,
+  });
+});
diff --git a/eims-ui/apps/backend-mock/api/auth/logout.post.ts b/eims-ui/apps/backend-mock/api/auth/logout.post.ts
new file mode 100644
index 0000000..ac6afe9
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/auth/logout.post.ts
@@ -0,0 +1,15 @@
+import {
+  clearRefreshTokenCookie,
+  getRefreshTokenFromCookie,
+} from '~/utils/cookie-utils';
+
+export default defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return useResponseSuccess('');
+  }
+
+  clearRefreshTokenCookie(event);
+
+  return useResponseSuccess('');
+});
diff --git a/eims-ui/apps/backend-mock/api/auth/refresh.post.ts b/eims-ui/apps/backend-mock/api/auth/refresh.post.ts
new file mode 100644
index 0000000..7df4d34
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/auth/refresh.post.ts
@@ -0,0 +1,33 @@
+import {
+  clearRefreshTokenCookie,
+  getRefreshTokenFromCookie,
+  setRefreshTokenCookie,
+} from '~/utils/cookie-utils';
+import { verifyRefreshToken } from '~/utils/jwt-utils';
+import { forbiddenResponse } from '~/utils/response';
+
+export default defineEventHandler(async (event) => {
+  const refreshToken = getRefreshTokenFromCookie(event);
+  if (!refreshToken) {
+    return forbiddenResponse(event);
+  }
+
+  clearRefreshTokenCookie(event);
+
+  const userinfo = verifyRefreshToken(refreshToken);
+  if (!userinfo) {
+    return forbiddenResponse(event);
+  }
+
+  const findUser = MOCK_USERS.find(
+    (item) => item.username === userinfo.username,
+  );
+  if (!findUser) {
+    return forbiddenResponse(event);
+  }
+  const accessToken = generateAccessToken(findUser);
+
+  setRefreshTokenCookie(event, refreshToken);
+
+  return accessToken;
+});
diff --git a/eims-ui/apps/backend-mock/api/menu/all.ts b/eims-ui/apps/backend-mock/api/menu/all.ts
new file mode 100644
index 0000000..580cee4
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/menu/all.ts
@@ -0,0 +1,13 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  const menus =
+    MOCK_MENUS.find((item) => item.username === userinfo.username)?.menus ?? [];
+  return useResponseSuccess(menus);
+});
diff --git a/eims-ui/apps/backend-mock/api/status.ts b/eims-ui/apps/backend-mock/api/status.ts
new file mode 100644
index 0000000..41773e1
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/status.ts
@@ -0,0 +1,5 @@
+export default eventHandler((event) => {
+  const { status } = getQuery(event);
+  setResponseStatus(event, Number(status));
+  return useResponseError(`${status}`);
+});
diff --git a/eims-ui/apps/backend-mock/api/table/list.ts b/eims-ui/apps/backend-mock/api/table/list.ts
new file mode 100644
index 0000000..4a0db94
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/table/list.ts
@@ -0,0 +1,48 @@
+import { faker } from '@faker-js/faker';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+function generateMockDataList(count: number) {
+  const dataList = [];
+
+  for (let i = 0; i < count; i++) {
+    const dataItem = {
+      id: faker.string.uuid(),
+      imageUrl: faker.image.avatar(),
+      imageUrl2: faker.image.avatar(),
+      open: faker.datatype.boolean(),
+      status: faker.helpers.arrayElement(['success', 'error', 'warning']),
+      productName: faker.commerce.productName(),
+      price: faker.commerce.price(),
+      currency: faker.finance.currencyCode(),
+      quantity: faker.number.int({ min: 1, max: 100 }),
+      available: faker.datatype.boolean(),
+      category: faker.commerce.department(),
+      releaseDate: faker.date.past(),
+      rating: faker.number.float({ min: 1, max: 5 }),
+      description: faker.commerce.productDescription(),
+      weight: faker.number.float({ min: 0.1, max: 10 }),
+      color: faker.color.human(),
+      inProduction: faker.datatype.boolean(),
+      tags: Array.from({ length: 3 }, () => faker.commerce.productAdjective()),
+    };
+
+    dataList.push(dataItem);
+  }
+
+  return dataList;
+}
+
+const mockData = generateMockDataList(100);
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+
+  await sleep(600);
+
+  const { page, pageSize } = getQuery(event);
+  return usePageResponseSuccess(page as string, pageSize as string, mockData);
+});
diff --git a/eims-ui/apps/backend-mock/api/test.get.ts b/eims-ui/apps/backend-mock/api/test.get.ts
new file mode 100644
index 0000000..ca4a500
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/test.get.ts
@@ -0,0 +1 @@
+export default defineEventHandler(() => 'Test get handler');
diff --git a/eims-ui/apps/backend-mock/api/test.post.ts b/eims-ui/apps/backend-mock/api/test.post.ts
new file mode 100644
index 0000000..698cf21
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/test.post.ts
@@ -0,0 +1 @@
+export default defineEventHandler(() => 'Test post handler');
diff --git a/eims-ui/apps/backend-mock/api/user/info.ts b/eims-ui/apps/backend-mock/api/user/info.ts
new file mode 100644
index 0000000..cfa2346
--- /dev/null
+++ b/eims-ui/apps/backend-mock/api/user/info.ts
@@ -0,0 +1,10 @@
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse } from '~/utils/response';
+
+export default eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  return useResponseSuccess(userinfo);
+});
diff --git a/eims-ui/apps/backend-mock/error.ts b/eims-ui/apps/backend-mock/error.ts
new file mode 100644
index 0000000..e20beac
--- /dev/null
+++ b/eims-ui/apps/backend-mock/error.ts
@@ -0,0 +1,7 @@
+import type { NitroErrorHandler } from 'nitropack';
+
+const errorHandler: NitroErrorHandler = function (error, event) {
+  event.node.res.end(`[Error Handler] ${error.stack}`);
+};
+
+export default errorHandler;
diff --git a/eims-ui/apps/backend-mock/middleware/1.api.ts b/eims-ui/apps/backend-mock/middleware/1.api.ts
new file mode 100644
index 0000000..84e2ce0
--- /dev/null
+++ b/eims-ui/apps/backend-mock/middleware/1.api.ts
@@ -0,0 +1,7 @@
+export default defineEventHandler((event) => {
+  if (event.method === 'OPTIONS') {
+    event.node.res.statusCode = 204;
+    event.node.res.statusMessage = 'No Content.';
+    return 'OK';
+  }
+});
diff --git a/eims-ui/apps/backend-mock/nitro.config.ts b/eims-ui/apps/backend-mock/nitro.config.ts
new file mode 100644
index 0000000..c2d7297
--- /dev/null
+++ b/eims-ui/apps/backend-mock/nitro.config.ts
@@ -0,0 +1,19 @@
+import errorHandler from './error';
+
+process.env.COMPATIBILITY_DATE = new Date().toISOString();
+export default defineNitroConfig({
+  devErrorHandler: errorHandler,
+  errorHandler: '~/error',
+  routeRules: {
+    '/api/**': {
+      cors: true,
+      headers: {
+        'Access-Control-Allow-Credentials': 'true',
+        'Access-Control-Allow-Headers': '*',
+        'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
+        'Access-Control-Allow-Origin': '*',
+        'Access-Control-Expose-Headers': '*',
+      },
+    },
+  },
+});
diff --git a/eims-ui/apps/backend-mock/package.json b/eims-ui/apps/backend-mock/package.json
new file mode 100644
index 0000000..cc0b8d5
--- /dev/null
+++ b/eims-ui/apps/backend-mock/package.json
@@ -0,0 +1,21 @@
+{
+  "name": "@vben/backend-mock",
+  "version": "0.0.1",
+  "description": "",
+  "private": true,
+  "license": "MIT",
+  "author": "",
+  "scripts": {
+    "build": "nitro build",
+    "start": "nitro dev"
+  },
+  "dependencies": {
+    "@faker-js/faker": "catalog:",
+    "jsonwebtoken": "catalog:",
+    "nitropack": "catalog:"
+  },
+  "devDependencies": {
+    "@types/jsonwebtoken": "catalog:",
+    "h3": "catalog:"
+  }
+}
diff --git "a/eims-ui/apps/backend-mock/routes/\133...\135.ts" "b/eims-ui/apps/backend-mock/routes/\133...\135.ts"
new file mode 100644
index 0000000..70c5f7c
--- /dev/null
+++ "b/eims-ui/apps/backend-mock/routes/\133...\135.ts"
@@ -0,0 +1,12 @@
+export default defineEventHandler(() => {
+  return `
+<h1>Hello Vben Admin</h1>
+<h2>Mock service is starting</h2>
+<ul>
+<li><a href="/api/user">/api/user/info</a></li>
+<li><a href="/api/menu">/api/menu/all</a></li>
+<li><a href="/api/auth/codes">/api/auth/codes</a></li>
+<li><a href="/api/auth/login">/api/auth/login</a></li>
+</ul>
+`;
+});
diff --git a/eims-ui/apps/backend-mock/tsconfig.build.json b/eims-ui/apps/backend-mock/tsconfig.build.json
new file mode 100644
index 0000000..64f86c6
--- /dev/null
+++ b/eims-ui/apps/backend-mock/tsconfig.build.json
@@ -0,0 +1,4 @@
+{
+  "extends": "./tsconfig.json",
+  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+}
diff --git a/eims-ui/apps/backend-mock/tsconfig.json b/eims-ui/apps/backend-mock/tsconfig.json
new file mode 100644
index 0000000..43008af
--- /dev/null
+++ b/eims-ui/apps/backend-mock/tsconfig.json
@@ -0,0 +1,3 @@
+{
+  "extends": "./.nitro/types/tsconfig.json"
+}
diff --git a/eims-ui/apps/backend-mock/utils/cookie-utils.ts b/eims-ui/apps/backend-mock/utils/cookie-utils.ts
new file mode 100644
index 0000000..0d92f57
--- /dev/null
+++ b/eims-ui/apps/backend-mock/utils/cookie-utils.ts
@@ -0,0 +1,26 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+export function clearRefreshTokenCookie(event: H3Event<EventHandlerRequest>) {
+  deleteCookie(event, 'jwt', {
+    httpOnly: true,
+    sameSite: 'none',
+    secure: true,
+  });
+}
+
+export function setRefreshTokenCookie(
+  event: H3Event<EventHandlerRequest>,
+  refreshToken: string,
+) {
+  setCookie(event, 'jwt', refreshToken, {
+    httpOnly: true,
+    maxAge: 24 * 60 * 60 * 1000,
+    sameSite: 'none',
+    secure: true,
+  });
+}
+
+export function getRefreshTokenFromCookie(event: H3Event<EventHandlerRequest>) {
+  const refreshToken = getCookie(event, 'jwt');
+  return refreshToken;
+}
diff --git a/eims-ui/apps/backend-mock/utils/jwt-utils.ts b/eims-ui/apps/backend-mock/utils/jwt-utils.ts
new file mode 100644
index 0000000..8cfc684
--- /dev/null
+++ b/eims-ui/apps/backend-mock/utils/jwt-utils.ts
@@ -0,0 +1,59 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+import jwt from 'jsonwebtoken';
+
+import { UserInfo } from './mock-data';
+
+// TODO: Replace with your own secret key
+const ACCESS_TOKEN_SECRET = 'access_token_secret';
+const REFRESH_TOKEN_SECRET = 'refresh_token_secret';
+
+export interface UserPayload extends UserInfo {
+  iat: number;
+  exp: number;
+}
+
+export function generateAccessToken(user: UserInfo) {
+  return jwt.sign(user, ACCESS_TOKEN_SECRET, { expiresIn: '7d' });
+}
+
+export function generateRefreshToken(user: UserInfo) {
+  return jwt.sign(user, REFRESH_TOKEN_SECRET, {
+    expiresIn: '30d',
+  });
+}
+
+export function verifyAccessToken(
+  event: H3Event<EventHandlerRequest>,
+): null | Omit<UserInfo, 'password'> {
+  const authHeader = getHeader(event, 'Authorization');
+  if (!authHeader?.startsWith('Bearer')) {
+    return null;
+  }
+
+  const token = authHeader.split(' ')[1];
+  try {
+    const decoded = jwt.verify(token, ACCESS_TOKEN_SECRET) as UserPayload;
+
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}
+
+export function verifyRefreshToken(
+  token: string,
+): null | Omit<UserInfo, 'password'> {
+  try {
+    const decoded = jwt.verify(token, REFRESH_TOKEN_SECRET) as UserPayload;
+    const username = decoded.username;
+    const user = MOCK_USERS.find((item) => item.username === username);
+    const { password: _pwd, ...userinfo } = user;
+    return userinfo;
+  } catch {
+    return null;
+  }
+}
diff --git a/eims-ui/apps/backend-mock/utils/mock-data.ts b/eims-ui/apps/backend-mock/utils/mock-data.ts
new file mode 100644
index 0000000..71970a2
--- /dev/null
+++ b/eims-ui/apps/backend-mock/utils/mock-data.ts
@@ -0,0 +1,186 @@
+export interface UserInfo {
+  id: number;
+  password: string;
+  realName: string;
+  roles: string[];
+  username: string;
+}
+
+export const MOCK_USERS: UserInfo[] = [
+  {
+    id: 0,
+    password: '123456',
+    realName: 'Vben',
+    roles: ['super'],
+    username: 'vben',
+  },
+  {
+    id: 1,
+    password: '123456',
+    realName: 'Admin',
+    roles: ['admin'],
+    username: 'admin',
+  },
+  {
+    id: 2,
+    password: '123456',
+    realName: 'Jack',
+    roles: ['user'],
+    username: 'jack',
+  },
+];
+
+export const MOCK_CODES = [
+  // super
+  {
+    codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'],
+    username: 'vben',
+  },
+  {
+    // admin
+    codes: ['AC_100010', 'AC_100020', 'AC_100030'],
+    username: 'admin',
+  },
+  {
+    // user
+    codes: ['AC_1000001', 'AC_1000002'],
+    username: 'jack',
+  },
+];
+
+const dashboardMenus = [
+  {
+    component: 'BasicLayout',
+    meta: {
+      order: -1,
+      title: 'page.dashboard.title',
+    },
+    name: 'Dashboard',
+    path: '/',
+    redirect: '/analytics',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: '/dashboard/analytics/index',
+        meta: {
+          affixTab: true,
+          title: 'page.dashboard.analytics',
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: '/dashboard/workspace/index',
+        meta: {
+          title: 'page.dashboard.workspace',
+        },
+      },
+    ],
+  },
+];
+
+const createDemosMenus = (role: 'admin' | 'super' | 'user') => {
+  const roleWithMenus = {
+    admin: {
+      component: '/demos/access/admin-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.adminVisible',
+      },
+      name: 'AccessAdminVisibleDemo',
+      path: '/demos/access/admin-visible',
+    },
+    super: {
+      component: '/demos/access/super-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.superVisible',
+      },
+      name: 'AccessSuperVisibleDemo',
+      path: '/demos/access/super-visible',
+    },
+    user: {
+      component: '/demos/access/user-visible',
+      meta: {
+        icon: 'mdi:button-cursor',
+        title: 'demos.access.userVisible',
+      },
+      name: 'AccessUserVisibleDemo',
+      path: '/demos/access/user-visible',
+    },
+  };
+
+  return [
+    {
+      component: 'BasicLayout',
+      meta: {
+        icon: 'ic:baseline-view-in-ar',
+        keepAlive: true,
+        order: 1000,
+        title: 'demos.title',
+      },
+      name: 'Demos',
+      path: '/demos',
+      redirect: '/demos/access',
+      children: [
+        {
+          name: 'AccessDemos',
+          path: '/demosaccess',
+          meta: {
+            icon: 'mdi:cloud-key-outline',
+            title: 'demos.access.backendPermissions',
+          },
+          redirect: '/demos/access/page-control',
+          children: [
+            {
+              name: 'AccessPageControlDemo',
+              path: '/demos/access/page-control',
+              component: '/demos/access/index',
+              meta: {
+                icon: 'mdi:page-previous-outline',
+                title: 'demos.access.pageAccess',
+              },
+            },
+            {
+              name: 'AccessButtonControlDemo',
+              path: '/demos/access/button-control',
+              component: '/demos/access/button-control',
+              meta: {
+                icon: 'mdi:button-cursor',
+                title: 'demos.access.buttonControl',
+              },
+            },
+            {
+              name: 'AccessMenuVisible403Demo',
+              path: '/demos/access/menu-visible-403',
+              component: '/demos/access/menu-visible-403',
+              meta: {
+                authority: ['no-body'],
+                icon: 'mdi:button-cursor',
+                menuVisibleWithForbidden: true,
+                title: 'demos.access.menuVisible403',
+              },
+            },
+            roleWithMenus[role],
+          ],
+        },
+      ],
+    },
+  ];
+};
+
+export const MOCK_MENUS = [
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('super')],
+    username: 'vben',
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('admin')],
+    username: 'admin',
+  },
+  {
+    menus: [...dashboardMenus, ...createDemosMenus('user')],
+    username: 'jack',
+  },
+];
diff --git a/eims-ui/apps/backend-mock/utils/response.ts b/eims-ui/apps/backend-mock/utils/response.ts
new file mode 100644
index 0000000..2a5a908
--- /dev/null
+++ b/eims-ui/apps/backend-mock/utils/response.ts
@@ -0,0 +1,68 @@
+import type { EventHandlerRequest, H3Event } from 'h3';
+
+export function useResponseSuccess<T = any>(data: T) {
+  return {
+    code: 0,
+    data,
+    error: null,
+    message: 'ok',
+  };
+}
+
+export function usePageResponseSuccess<T = any>(
+  page: number | string,
+  pageSize: number | string,
+  list: T[],
+  { message = 'ok' } = {},
+) {
+  const pageData = pagination(
+    Number.parseInt(`${page}`),
+    Number.parseInt(`${pageSize}`),
+    list,
+  );
+
+  return {
+    ...useResponseSuccess({
+      items: pageData,
+      total: list.length,
+    }),
+    message,
+  };
+}
+
+export function useResponseError(message: string, error: any = null) {
+  return {
+    code: -1,
+    data: null,
+    error,
+    message,
+  };
+}
+
+export function forbiddenResponse(
+  event: H3Event<EventHandlerRequest>,
+  message = 'Forbidden Exception',
+) {
+  setResponseStatus(event, 403);
+  return useResponseError(message, message);
+}
+
+export function unAuthorizedResponse(event: H3Event<EventHandlerRequest>) {
+  setResponseStatus(event, 401);
+  return useResponseError('Unauthorized Exception', 'Unauthorized Exception');
+}
+
+export function sleep(ms: number) {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+export function pagination<T = any>(
+  pageNo: number,
+  pageSize: number,
+  array: T[],
+): T[] {
+  const offset = (pageNo - 1) * Number(pageSize);
+  return offset + Number(pageSize) >= array.length
+    ? array.slice(offset)
+    : array.slice(offset, offset + Number(pageSize));
+}
diff --git a/eims-ui/apps/web-antd/.env b/eims-ui/apps/web-antd/.env
new file mode 100644
index 0000000..a69ae12
--- /dev/null
+++ b/eims-ui/apps/web-antd/.env
@@ -0,0 +1,5 @@
+# 搴旂敤鏍囬
+VITE_APP_TITLE=eims-ui
+
+# 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
+VITE_APP_NAMESPACE=eims-ui
diff --git a/eims-ui/apps/web-antd/.env.analyze b/eims-ui/apps/web-antd/.env.analyze
new file mode 100644
index 0000000..ffafa8d
--- /dev/null
+++ b/eims-ui/apps/web-antd/.env.analyze
@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true
diff --git a/eims-ui/apps/web-antd/.env.development b/eims-ui/apps/web-antd/.env.development
new file mode 100644
index 0000000..7f1129b
--- /dev/null
+++ b/eims-ui/apps/web-antd/.env.development
@@ -0,0 +1,25 @@
+# 绔彛鍙�
+VITE_PORT=5666
+
+VITE_BASE=/
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=false
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=true
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鍚庡彴璇锋眰璺緞 鍏蜂綋鍦╲ite.config.mts閰嶇疆浠g悊
+VITE_GLOB_API_URL=/api
+
+# 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
+VITE_GLOB_ENABLE_ENCRYPT=false
+# RSA鍏挜 璇锋眰鍔犲瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+# RSA绉侀挜 鍝嶅簲瑙e瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+# 瀹㈡埛绔痠d
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+
+# 寮�鍚疭SE
+VITE_GLOB_SSE_ENABLE=true
diff --git a/eims-ui/apps/web-antd/.env.production b/eims-ui/apps/web-antd/.env.production
new file mode 100644
index 0000000..4086f92
--- /dev/null
+++ b/eims-ui/apps/web-antd/.env.production
@@ -0,0 +1,32 @@
+VITE_BASE=/
+
+# 鏄惁寮�鍚帇缂╋紝鍙互璁剧疆涓� none, brotli, gzip
+VITE_COMPRESS=gzip
+
+# 鏄惁寮�鍚� PWA
+VITE_PWA=false
+
+# vue-router 鐨勬ā寮�
+VITE_ROUTER_HISTORY=history
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鎵撳寘鍚庢槸鍚︾敓鎴恉ist.zip
+VITE_ARCHIVER=true
+
+# 鍚庡彴璇锋眰璺緞 鍏蜂綋鍦╲ite.config.mts閰嶇疆浠g悊
+VITE_GLOB_API_URL=/prod-api
+
+# 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
+VITE_GLOB_ENABLE_ENCRYPT=true
+# RSA鍏挜 璇锋眰鍔犲瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+# RSA绉侀挜 鍝嶅簲瑙e瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
+VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+# 瀹㈡埛绔痠d
+VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
+
+# 寮�鍚疭SE
+VITE_GLOB_SSE_ENABLE=true
+
diff --git a/eims-ui/apps/web-antd/index.html b/eims-ui/apps/web-antd/index.html
new file mode 100644
index 0000000..33d34a9
--- /dev/null
+++ b/eims-ui/apps/web-antd/index.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html lang="zh">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta name="description" content="A Modern Back-end Management System" />
+    <meta name="keywords" content="Vben Admin Vue3 Vite" />
+    <meta name="author" content="Vben" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <!-- 鐢� vite 娉ㄥ叆 VITE_APP_TITLE 鍙橀噺锛屽湪 .env 鏂囦欢鍐呴厤缃� -->
+    <title><%= VITE_APP_TITLE %></title>
+    <link rel="icon" href="/favicon.ico" />
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>
diff --git a/eims-ui/apps/web-antd/package.json b/eims-ui/apps/web-antd/package.json
new file mode 100644
index 0000000..d303cf5
--- /dev/null
+++ b/eims-ui/apps/web-antd/package.json
@@ -0,0 +1,63 @@
+{
+  "name": "@vben/web-antd",
+  "version": "1.1.3",
+  "homepage": "https://vben.pro",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "apps/web-antd"
+  },
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build --mode production",
+    "build:analyze": "pnpm vite build --mode analyze",
+    "dev": "pnpm vite --mode development",
+    "preview": "vite preview",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck"
+  },
+  "imports": {
+    "#/*": "./src/*"
+  },
+  "dependencies": {
+    "@ant-design/icons-vue": "^7.0.1",
+    "@tinymce/tinymce-vue": "^6.0.1",
+    "@vben/access": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/layouts": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/request": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "ant-design-vue": "catalog:",
+    "cropperjs": "^1.6.2",
+    "crypto-js": "^4.2.0",
+    "dayjs": "catalog:",
+    "echarts": "^5.5.1",
+    "jsencrypt": "^3.3.2",
+    "lodash-es": "^4.17.21",
+    "pinia": "catalog:",
+    "tinymce": "^7.3.0",
+    "unplugin-vue-components": "^0.27.3",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  },
+  "devDependencies": {
+    "@types/crypto-js": "^4.2.2",
+    "@types/lodash-es": "^4.17.12"
+  }
+}
diff --git a/eims-ui/apps/web-antd/postcss.config.mjs b/eims-ui/apps/web-antd/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/apps/web-antd/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/apps/web-antd/public/favicon.ico b/eims-ui/apps/web-antd/public/favicon.ico
new file mode 100644
index 0000000..fcf9818
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/favicon.ico
Binary files differ
diff --git a/eims-ui/apps/web-antd/public/static/logo.png b/eims-ui/apps/web-antd/public/static/logo.png
new file mode 100644
index 0000000..fd0c6ba
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/static/logo.png
Binary files differ
diff --git a/eims-ui/apps/web-antd/public/tinymce/icons/default/icons.min.js b/eims-ui/apps/web-antd/public/tinymce/icons/default/icons.min.js
new file mode 100644
index 0000000..5b761cb
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/icons/default/icons.min.js
@@ -0,0 +1 @@
+tinymce.IconManager.add("default",{icons:{"accessibility-check":'<svg width="24" height="24"><path d="M12 2a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2c0-1.1.9-2 2-2Zm8 7h-5v12c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5c0-.6-.4-1-1-1a1 1 0 0 0-1 1v5c0 .6-.4 1-1 1a1 1 0 0 1-1-1V9H4a1 1 0 1 1 0-2h16c.6 0 1 .4 1 1s-.4 1-1 1Z" fill-rule="nonzero"/></svg>',"accordion-toggle":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 15c0-.6.4-1 1-1h6c.6 0 1 .4 1 1s-.4 1-1 1h-6a1 1 0 0 1-1-1Z"/><path opacity=".2" fill-rule="evenodd" clip-rule="evenodd" d="M4 15c0-.6.4-1 1-1h6c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1-1-1Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12 19c0-.6.4-1 1-1h6c.6 0 1 .4 1 1s-.4 1-1 1h-6a1 1 0 0 1-1-1Z"/><path opacity=".2" fill-rule="evenodd" clip-rule="evenodd" d="M4 19c0-.6.4-1 1-1h6c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1-1-1Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.3 7.3a1 1 0 0 1 1.4 0L16 9.6l2.3-2.3a1 1 0 1 1 1.4 1.4L16 12.4l-3.7-3.7a1 1 0 0 1 0-1.4ZM4.3 11.7a1 1 0 0 1 0-1.4L6.6 8 4.3 5.7a1 1 0 0 1 1.4-1.4L9.4 8l-3.7 3.7a1 1 0 0 1-1.4 0Z"/></svg>',accordion:'<svg width="24" height="24"><rect x="12" y="7" width="10" height="2" rx="1"/><rect x="12" y="11" width="10" height="2" rx="1"/><rect x="12" y="15" width="6" height="2" rx="1"/><path fill-rule="evenodd" clip-rule="evenodd" d="M2.3 7.3a1 1 0 0 1 1.4 0L6 9.6l2.3-2.3a1 1 0 0 1 1.4 1.4L6 12.4 2.3 8.7a1 1 0 0 1 0-1.4Z"/></svg>',"action-next":'<svg width="24" height="24"><path fill-rule="nonzero" d="M5.7 7.3a1 1 0 0 0-1.4 1.4l7.7 7.7 7.7-7.7a1 1 0 1 0-1.4-1.4L12 13.6 5.7 7.3Z"/></svg>',"action-prev":'<svg width="24" height="24"><path fill-rule="nonzero" d="M18.3 15.7a1 1 0 0 0 1.4-1.4L12 6.6l-7.7 7.7a1 1 0 0 0 1.4 1.4L12 9.4l6.3 6.3Z"/></svg>',addtag:'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M15 5a2 2 0 0 1 1.6.8L21 12l-4.4 6.2a2 2 0 0 1-1.6.8h-3v-2h3l3.5-5L15 7H5v3H3V7c0-1.1.9-2 2-2h10Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M6 12a1 1 0 0 0-1 1v2H3a1 1 0 1 0 0 2h2v2a1 1 0 1 0 2 0v-2h2a1 1 0 1 0 0-2H7v-2c0-.6-.4-1-1-1Z"/></svg>',"ai-prompt":'<svg width="24" height="24"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M15 6.7a1 1 0 0 0-1.4 0l-9.9 10a1 1 0 0 0 0 1.3l2.1 2.1c.4.4 1 .4 1.4 0l10-9.9c.3-.3.3-1 0-1.4l-2.2-2Zm1.4 2.8-2-2-3 2.7 2.2 2.2 2.8-2.9Z"/><path d="m18.5 7.3-.7-1.5-1.5-.8 1.5-.7.7-1.5.7 1.5 1.5.7-1.5.8-.7 1.5ZM18.5 16.5l-.7-1.6-1.5-.7 1.5-.7.7-1.6.7 1.6 1.5.7-1.5.7-.7 1.6ZM9.7 7.3 9 5.8 7.5 5 9 4.3l.7-1.5.7 1.5L12 5l-1.5.8-.7 1.5Z"/></g><defs><clipPath id="a"><path d="M0 0h24v24H0z"/></clipPath></defs></svg>',ai:'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M5 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3H5Zm6.8 11.5.5 1.2a68.3 68.3 0 0 0 .7 1.1l.4.1c.3 0 .5 0 .7-.3.2-.1.3-.3.3-.6l-.3-1-2.6-6.2a20.4 20.4 0 0 0-.5-1.3l-.5-.4-.7-.2c-.2 0-.5 0-.6.2-.2 0-.4.2-.5.4l-.3.6-.3.7L5.7 15l-.2.6-.1.4c0 .3 0 .5.3.7l.6.2c.3 0 .5 0 .7-.2l.4-1 .5-1.2h3.9ZM9.8 9l1.5 4h-3l1.5-4Zm5.6-.9v7.6c0 .4 0 .7.2 1l.7.2c.3 0 .6 0 .8-.3l.2-.9V8.1c0-.4 0-.7-.2-.9a1 1 0 0 0-.8-.3c-.2 0-.5.1-.7.3l-.2 1Z"/></svg>',"align-center":'<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm3 4h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm-3-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',"align-justify":'<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',"align-left":'<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',"align-none":'<svg width="24" height="24"><path d="M14.2 5 13 7H5a1 1 0 1 1 0-2h9.2Zm4 0h.8a1 1 0 0 1 0 2h-2l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h6.8Zm4 0H19a1 1 0 0 1 0 2h-4.4l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h4.4Zm4 0H19a1 1 0 0 1 0 2h-6.8l1.2-2ZM7 17l-1.2 2H5a1 1 0 0 1 0-2h2Zm4 0h8a1 1 0 0 1 0 2H9.8l1.2-2Zm5.2-13.5 1.3.7-9.7 16.3-1.3-.7 9.7-16.3Z" fill-rule="evenodd"/></svg>',"align-right":'<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm6 4h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-6-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',"arrow-left":'<svg width="24" height="24"><path d="m5.6 13 12 6a1 1 0 0 0 1.4-1V6a1 1 0 0 0-1.4-.9l-12 6a1 1 0 0 0 0 1.8Z" fill-rule="evenodd"/></svg>',"arrow-right":'<svg width="24" height="24"><path d="m18.5 13-12 6A1 1 0 0 1 5 18V6a1 1 0 0 1 1.4-.9l12 6a1 1 0 0 1 0 1.8Z" fill-rule="evenodd"/></svg>',bold:'<svg width="24" height="24"><path d="M7.8 19c-.3 0-.5 0-.6-.2l-.2-.5V5.7c0-.2 0-.4.2-.5l.6-.2h5c1.5 0 2.7.3 3.5 1 .7.6 1.1 1.4 1.1 2.5a3 3 0 0 1-.6 1.9c-.4.6-1 1-1.6 1.2.4.1.9.3 1.3.6s.8.7 1 1.2c.4.4.5 1 .5 1.6 0 1.3-.4 2.3-1.3 3-.8.7-2.1 1-3.8 1H7.8Zm5-8.3c.6 0 1.2-.1 1.6-.5.4-.3.6-.7.6-1.3 0-1.1-.8-1.7-2.3-1.7H9.3v3.5h3.4Zm.5 6c.7 0 1.3-.1 1.7-.4.4-.4.6-.9.6-1.5s-.2-1-.7-1.4c-.4-.3-1-.4-2-.4H9.4v3.8h4Z" fill-rule="evenodd"/></svg>',bookmark:'<svg width="24" height="24"><path d="M6 4v17l6-4 6 4V4c0-.6-.4-1-1-1H7a1 1 0 0 0-1 1Z" fill-rule="nonzero"/></svg>',"border-style":'<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="2" x="3" y="6" rx="1"/><rect width="2.8" height="2" x="3" y="16" rx="1"/><rect width="2.8" height="2" x="6.8" y="16" rx="1"/><rect width="2.8" height="2" x="10.6" y="16" rx="1"/><rect width="2.8" height="2" x="14.4" y="16" rx="1"/><rect width="2.8" height="2" x="18.2" y="16" rx="1"/><rect width="8" height="2" x="3" y="11" rx="1"/><rect width="8" height="2" x="13" y="11" rx="1"/></g></svg>',"border-width":'<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="5" x="3" y="5" rx="1"/><rect width="18" height="3.5" x="3" y="11.5" rx="1"/><rect width="18" height="2" x="3" y="17" rx="1"/></g></svg>',brightness:'<svg width="24" height="24"><path d="M12 17c.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7v-1c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3Zm0-10a1 1 0 0 1-.7-.3A1 1 0 0 1 11 6V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3Zm7 4c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-1a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1ZM7 12c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H5a1 1 0 0 1-.7-.3A1 1 0 0 1 4 12c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1c.3 0 .5.1.7.3.2.2.3.4.3.7Zm10 3.5.7.8c.2.1.3.4.3.6 0 .3-.1.6-.3.8a1 1 0 0 1-.8.3 1 1 0 0 1-.6-.3l-.8-.7a1 1 0 0 1-.3-.8c0-.2.1-.5.3-.7a1 1 0 0 1 1.4 0Zm-10-7-.7-.8a1 1 0 0 1-.3-.6c0-.3.1-.6.3-.8.2-.2.5-.3.8-.3.2 0 .5.1.7.3l.7.7c.2.2.3.5.3.8 0 .2-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.8-.3Zm10 0a1 1 0 0 1-.8.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.6.3-.8l.8-.7c.1-.2.4-.3.6-.3.3 0 .6.1.8.3.2.2.3.5.3.8 0 .2-.1.5-.3.7l-.7.7Zm-10 7c.2-.2.5-.3.8-.3.2 0 .5.1.7.3a1 1 0 0 1 0 1.4l-.8.8a1 1 0 0 1-.6.3 1 1 0 0 1-.8-.3 1 1 0 0 1-.3-.8c0-.2.1-.5.3-.6l.7-.8ZM12 8a4 4 0 0 1 3.7 2.4 4 4 0 0 1 0 3.2A4 4 0 0 1 12 16a4 4 0 0 1-3.7-2.4 4 4 0 0 1 0-3.2A4 4 0 0 1 12 8Zm0 6.5c.7 0 1.3-.2 1.8-.7.5-.5.7-1.1.7-1.8s-.2-1.3-.7-1.8c-.5-.5-1.1-.7-1.8-.7s-1.3.2-1.8.7c-.5.5-.7 1.1-.7 1.8s.2 1.3.7 1.8c.5.5 1.1.7 1.8.7Z" fill-rule="evenodd"/></svg>',browse:'<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4v-2h4V8H5v10h4v2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9.4-2.3 2.3a1 1 0 1 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 0 1-1.4 1.4L13 13.4V20a1 1 0 0 1-2 0v-6.6Z" fill-rule="nonzero"/></svg>',cancel:'<svg width="24" height="24"><path d="M12 4.6a7.4 7.4 0 1 1 0 14.8 7.4 7.4 0 0 1 0-14.8ZM12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18Zm0 8L14.8 8l1 1.1-2.7 2.8 2.7 2.7-1.1 1.1-2.7-2.7-2.7 2.7-1-1.1 2.6-2.7-2.7-2.7 1-1.1 2.8 2.7Z" fill-rule="nonzero"/></svg>',"cell-background-color":'<svg width="24" height="24"><path d="m15.7 2 1.6 1.6-2.7 2.6 5.9 5.8c.7.7.7 1.7 0 2.4l-6.3 6.1a1.7 1.7 0 0 1-2.4 0l-6.3-6.1c-.7-.7-.7-1.7 0-2.4L15.7 2ZM18 12l-4.5-4L9 12h9ZM4 16s2 2.4 2 3.8C6 21 5.1 22 4 22s-2-1-2-2.2C2 18.4 4 16 4 16Z"/></svg>',"cell-border-color":'<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M5 13v5h2v2H5a2 2 0 0 1-2-2v-5h2zm8-7V4h6a2 2 0 0 1 2 2h-8z" opacity=".2"/><path fill-rule="nonzero" d="M13 4v2H5v7H3V6c0-1.1.9-2 2-2h8zm-2.6 14.1.1-.1.1.1.2.3.2.2.2.2c.4.6.8 1.2.8 1.7 0 .8-.7 1.5-1.5 1.5S9 21.3 9 20.5c0-.5.4-1.1.8-1.7l.2-.2.2-.2.2-.3z"/><path d="m13 11-2 2H5v-2h6V6h2z"/><path fill-rule="nonzero" d="m18.4 8 1 1-1.8 1.9 4 4c.5.4.5 1.1 0 1.6l-4.3 4.2a1.2 1.2 0 0 1-1.6 0l-4.4-4.2c-.4-.5-.4-1.2 0-1.7l7-6.8Zm1.6 7-3-3-3 3h6Z"/></g></svg>',"change-case":'<svg width="24" height="24"><path d="M18.4 18.2v-.6c-.5.8-1.3 1.2-2.4 1.2-2.2 0-3.3-1.6-3.3-4.8 0-3.1 1-4.7 3.3-4.7 1.1 0 1.8.3 2.4 1.1v-.6c0-.5.4-.8.8-.8s.8.3.8.8v8.4c0 .5-.4.8-.8.8a.8.8 0 0 1-.8-.8zm-2-7.4c-1.3 0-1.8.9-1.8 3.2 0 2.4.5 3.3 1.7 3.3 1.3 0 1.8-.9 1.8-3.2 0-2.4-.5-3.3-1.7-3.3zM10 15.7H5.5l-.8 2.6a1 1 0 0 1-1 .7h-.2a.7.7 0 0 1-.7-1l4-12a1 1 0 0 1 2 0l4 12a.7.7 0 0 1-.8 1h-.2a1 1 0 0 1-1-.7l-.8-2.6zm-.3-1.5-2-6.5-1.9 6.5h3.9z" fill-rule="evenodd"/></svg>',"character-count":'<svg width="24" height="24"><path d="M4 11.5h16v1H4v-1Zm4.8-6.8V10H7.7V5.8h-1v-1h2ZM11 8.3V9h2v1h-3V7.7l2-1v-.9h-2v-1h3v2.4l-2 1Zm6.3-3.4V10h-3.1V9h2.1V8h-2.1V6.8h2.1v-1h-2.1v-1h3.1ZM5.8 16.4c0-.5.2-.8.5-1 .2-.2.6-.3 1.2-.3l.8.1c.2 0 .4.2.5.3l.4.4v2.8l.2.3H8.2V18.7l-.6.3H7c-.4 0-.7 0-1-.2a1 1 0 0 1-.3-.9c0-.3 0-.6.3-.8.3-.2.7-.4 1.2-.4l.6-.2h.3v-.2l-.1-.2a.8.8 0 0 0-.5-.1 1 1 0 0 0-.4 0l-.3.4h-1Zm2.3.8h-.2l-.2.1-.4.1a1 1 0 0 0-.4.2l-.2.2.1.3.5.1h.4l.4-.4v-.6Zm2-3.4h1.2v1.7l.5-.3h.5c.5 0 .9.1 1.2.5.3.4.5.8.5 1.4 0 .6-.2 1.1-.5 1.5-.3.4-.7.6-1.3.6l-.6-.1-.4-.4v.4h-1.1v-5.4Zm1.1 3.3c0 .3 0 .6.2.8a.7.7 0 0 0 1.2 0l.2-.8c0-.4 0-.6-.2-.8a.7.7 0 0 0-.6-.3l-.6.3-.2.8Zm6.1-.5c0-.2 0-.3-.2-.4a.8.8 0 0 0-.5-.2c-.3 0-.5.1-.6.3l-.2.9c0 .3 0 .6.2.8.1.2.3.3.6.3.2 0 .4 0 .5-.2l.2-.4h1.1c0 .5-.3.8-.6 1.1a2 2 0 0 1-1.3.4c-.5 0-1-.2-1.3-.6a2 2 0 0 1-.5-1.4c0-.6.1-1.1.5-1.5.3-.4.8-.5 1.4-.5.5 0 1 0 1.2.3.4.3.5.7.5 1.2h-1v-.1Z" fill-rule="evenodd"/></svg>',"checklist-rtl":'<svg width="24" height="24"><path d="M5 17h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm14.2 11c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 8c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8z" fill-rule="evenodd"/></svg>',checklist:'<svg width="24" height="24"><path d="M11 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2h-8a1 1 0 0 1 0-2ZM7.2 16c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 8c-.2.3-.7.4-1 0L3.8 6.9a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Z" fill-rule="evenodd"/></svg>',checkmark:'<svg width="24" height="24"><path d="M18.2 5.4a1 1 0 0 1 1.6 1.2l-8 12a1 1 0 0 1-1.5.1l-5-5a1 1 0 1 1 1.4-1.4l4.1 4.1 7.4-11Z" fill-rule="nonzero"/></svg>',"chevron-down":'<svg width="10" height="10"><path d="M8.7 2.2c.3-.3.8-.3 1 0 .4.4.4.9 0 1.2L5.7 7.8c-.3.3-.9.3-1.2 0L.2 3.4a.8.8 0 0 1 0-1.2c.3-.3.8-.3 1.1 0L5 6l3.7-3.8Z" fill-rule="nonzero"/></svg>',"chevron-left":'<svg width="10" height="10"><path d="M7.8 1.3 4 5l3.8 3.7c.3.3.3.8 0 1-.4.4-.9.4-1.2 0L2.2 5.7a.8.8 0 0 1 0-1.2L6.6.2C7 0 7.4 0 7.8.2c.3.3.3.8 0 1.1Z" fill-rule="nonzero"/></svg>',"chevron-right":'<svg width="10" height="10"><path d="M2.2 1.3a.8.8 0 0 1 0-1c.4-.4.9-.4 1.2 0l4.4 4.1c.3.4.3.9 0 1.2L3.4 9.8c-.3.3-.8.3-1.2 0a.8.8 0 0 1 0-1.1L6 5 2.2 1.3Z" fill-rule="nonzero"/></svg>',"chevron-up":'<svg width="10" height="10"><path d="M8.7 7.8 5 4 1.3 7.8c-.3.3-.8.3-1 0a.8.8 0 0 1 0-1.2l4.1-4.4c.3-.3.9-.3 1.2 0l4.2 4.4c.3.3.3.9 0 1.2-.3.3-.8.3-1.1 0Z" fill-rule="nonzero"/></svg>',close:'<svg width="24" height="24"><path d="M17.3 8.2 13.4 12l3.9 3.8a1 1 0 0 1-1.5 1.5L12 13.4l-3.8 3.9a1 1 0 0 1-1.5-1.5l3.9-3.8-3.9-3.8a1 1 0 0 1 1.5-1.5l3.8 3.9 3.8-3.9a1 1 0 0 1 1.5 1.5Z" fill-rule="evenodd"/></svg>',"code-sample":'<svg width="24" height="26"><path d="M7.1 11a2.8 2.8 0 0 1-.8 2 2.8 2.8 0 0 1 .8 2v1.7c0 .3.1.6.4.8.2.3.5.4.8.4.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.7 0-1.4-.3-2-.8-.5-.6-.8-1.3-.8-2V15c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4v-.8c0-.2.2-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V9.3c0-.7.3-1.4.8-2 .6-.5 1.3-.8 2-.8.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8V11Zm9.8 0V9.3c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4V7c0-.2.1-.4.4-.4.7 0 1.4.3 2 .8.5.6.8 1.3.8 2V11c0 .3.1.6.4.8.2.3.5.4.8.4.2 0 .4.2.4.4v.8c0 .2-.2.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8v1.7c0 .7-.3 1.4-.8 2-.6.5-1.3.8-2 .8a.4.4 0 0 1-.4-.4v-.8c0-.2.1-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V15a2.8 2.8 0 0 1 .8-2 2.8 2.8 0 0 1-.8-2Zm-3.3-.4c0 .4-.1.8-.5 1.1-.3.3-.7.5-1.1.5-.4 0-.8-.2-1.1-.5-.4-.3-.5-.7-.5-1.1 0-.5.1-.9.5-1.2.3-.3.7-.4 1.1-.4.4 0 .8.1 1.1.4.4.3.5.7.5 1.2ZM12 13c.4 0 .8.1 1.1.5.4.3.5.7.5 1.1 0 1-.1 1.6-.5 2a3 3 0 0 1-1.1 1c-.4.3-.8.4-1.1.4a.5.5 0 0 1-.5-.5V17a3 3 0 0 0 1-.2l.6-.6c-.6 0-1-.2-1.3-.5-.2-.3-.3-.7-.3-1 0-.5.1-1 .5-1.2.3-.4.7-.5 1.1-.5Z" fill-rule="evenodd"/></svg>',"color-levels":'<svg width="24" height="24"><path d="M17.5 11.4A9 9 0 0 1 18 14c0 .5 0 1-.2 1.4 0 .4-.3.9-.5 1.3a6.2 6.2 0 0 1-3.7 3 5.7 5.7 0 0 1-3.2 0A5.9 5.9 0 0 1 7.6 18a6.2 6.2 0 0 1-1.4-2.6 6.7 6.7 0 0 1 0-2.8c0-.4.1-.9.3-1.3a13.6 13.6 0 0 1 2.3-4A20 20 0 0 1 12 4a26.4 26.4 0 0 1 3.2 3.4 18.2 18.2 0 0 1 2.3 4Zm-2 4.5c.4-.7.5-1.4.5-2a7.3 7.3 0 0 0-1-3.2c.2.6.2 1.2.2 1.9a4.5 4.5 0 0 1-1.3 3 5.3 5.3 0 0 1-2.3 1.5 4.9 4.9 0 0 1-2 .1 4.3 4.3 0 0 0 2.4.8 4 4 0 0 0 2-.6 4 4 0 0 0 1.5-1.5Z" fill-rule="evenodd"/></svg>',"color-picker":'<svg width="24" height="24"><path d="M12 3a9 9 0 0 0 0 18 1.5 1.5 0 0 0 1.1-2.5c-.2-.3-.4-.6-.4-1 0-.8.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.4-4-8-9-8Zm-5.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3-4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z" fill-rule="nonzero"/></svg>',"color-swatch-remove-color":'<svg width="24" height="24"><path stroke="#000" stroke-width="2" d="M21 3 3 21" fill-rule="evenodd"/></svg>',"color-swatch":'<svg width="24" height="24"><rect x="3" y="3" width="18" height="18" rx="1" fill-rule="evenodd"/></svg>',"comment-add":'<svg width="24" height="24"><g fill-rule="nonzero"><path d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/><path d="M13 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2Z"/></g></svg>',comment:'<svg width="24" height="24"><path fill-rule="nonzero" d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/></svg>',contrast:'<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-6 8a6 6 0 0 0 6 6V6a6 6 0 0 0-6 6Z" fill-rule="evenodd"/></svg>',copy:'<svg width="24" height="24"><path d="M16 3H6a2 2 0 0 0-2 2v11h2V5h10V3Zm1 4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7Zm0 12V9h-7v10h7Z" fill-rule="nonzero"/></svg>',crop:'<svg width="24" height="24"><path d="M17 8v7h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v2c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-2H7V9H5a1 1 0 1 1 0-2h2V5c0-.6.4-1 1-1s1 .4 1 1v2h7l3-3 1 1-3 3ZM9 9v5l5-5H9Zm1 6h5v-5l-5 5Z" fill-rule="evenodd"/></svg>',"cut-column":'<svg width="24" height="24"><path fill-rule="evenodd" d="M7.2 4.5c.9 0 1.6.4 2.2 1A3.7 3.7 0 0 1 10.5 8v.5l1 1 4-4 1-.5a3.3 3.3 0 0 1 2 0c.4 0 .7.3 1 .5L17 8h4v13h-6V10l-1.5 1.5.5.5v4l-2.5-2.5-1 1v.5c0 .4 0 .8-.3 1.2-.2.5-.4.9-.8 1.2-.6.7-1.3 1-2.2 1-.8.2-1.5 0-2-.6l-.5-.8-.2-1c0-.4 0-.8.3-1.2A3.9 3.9 0 0 1 7 12.7c.5-.2 1-.3 1.5-.2l1-1-1-1c-.5 0-1 0-1.5-.2-.5-.1-1-.4-1.4-.9-.4-.3-.6-.7-.8-1.2L4.5 7c0-.4 0-.7.2-1 0-.3.3-.6.5-.8.5-.5 1.2-.8 2-.7Zm12.3 5h-3v10h3v-10ZM8 13.8h-.3l-.4.2a2.8 2.8 0 0 0-.7.4v.1a2.8 2.8 0 0 0-.6.8l-.1.4v.7l.2.5.5.2h.7a2.6 2.6 0 0 0 .8-.3 2.4 2.4 0 0 0 .7-.7 2.5 2.5 0 0 0 .3-.8 1.5 1.5 0 0 0 0-.8 1 1 0 0 0-.2-.4 1 1 0 0 0-.5-.2H8Zm3.5-3.7c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4ZM7 5.8h-.4a1 1 0 0 0-.5.3 1 1 0 0 0-.2.5v.7a2.5 2.5 0 0 0 .3.8l.2.3h.1l.4.4.4.2.4.1h.7L9 9l.2-.4a1.6 1.6 0 0 0 0-.8 2.6 2.6 0 0 0-.3-.8A2.5 2.5 0 0 0 7.7 6l-.4-.1H7Z"/></svg>',"cut-row":'<svg width="24" height="24"><path fill-rule="evenodd" d="M22 3v5H9l3 3 2-2h4l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8.7.6 1 1.3 1 2.2.2.8 0 1.5-.6 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l2 2V3h14ZM8.5 15.3h-.3a2.6 2.6 0 0 0-.8.4 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3L9 18V18l.4-.4.2-.4.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2h-.5Zm7 0H15a1 1 0 0 0-.4.3 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4a2.8 2.8 0 0 0 .5.7h.1a2.8 2.8 0 0 0 .8.6l.4.1h.7l.5-.2.2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3h-.3ZM12 11.6c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4Zm8.5-7.1h-11v2h11v-2Z"/></svg>',cut:'<svg width="24" height="24"><path d="M18 15c.6.7 1 1.4 1 2.3 0 .8-.2 1.5-.7 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l6 6 6-6 .5 1a3.3 3.3 0 0 1 0 2c0 .4-.3.7-.5 1l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8Zm-8.5 2.2.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2 1.6 1.6 0 0 0-.8 0 2.6 2.6 0 0 0-.8.3 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3 2.8 2.8 0 0 0 1-1Zm2.5-2.8c.4 0 .7-.1 1-.4.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4Zm5.4 4 .2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3 1.5 1.5 0 0 0-.8 0 1 1 0 0 0-.4.2 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4l.3.4.3.4a2.8 2.8 0 0 0 .8.5l.4.1h.7l.5-.2Z" fill-rule="evenodd"/></svg>',"document-properties":'<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',drag:'<svg width="24" height="24"><path d="M13 5h2v2h-2V5Zm0 4h2v2h-2V9ZM9 9h2v2H9V9Zm4 4h2v2h-2v-2Zm-4 0h2v2H9v-2Zm0 4h2v2H9v-2Zm4 0h2v2h-2v-2ZM9 5h2v2H9V5Z" fill-rule="evenodd"/></svg>',"duplicate-column":'<svg width="24" height="24"><path d="M17 6v16h-7V6h7Zm-2 2h-3v12h3V8Zm-2-6v2H8v15H6V2h7Z"/></svg>',"duplicate-row":'<svg width="24" height="24"><path d="M22 11v7H6v-7h16Zm-2 2H8v3h12v-3Zm-1-6v2H4v5H2V7h17Z"/></svg>',duplicate:'<svg width="24" height="24"><g fill-rule="nonzero"><path d="M16 3v2H6v11H4V5c0-1.1.9-2 2-2h10Zm3 8h-2V9h-7v10h9a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7a2 2 0 0 1 2 2v2Z"/><path d="M17 14h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1h-1a1 1 0 0 1 0-2h1v-1a1 1 0 0 1 2 0v1Z"/></g></svg>',"edit-block":'<svg width="24" height="24"><path fill-rule="nonzero" d="m19.8 8.8-9.4 9.4c-.2.2-.5.4-.9.4l-5.4 1.2 1.2-5.4.5-.8 9.4-9.4c.7-.7 1.8-.7 2.5 0l2.1 2.1c.7.7.7 1.8 0 2.5Zm-2-.2 1-.9v-.3l-2.2-2.2a.3.3 0 0 0-.3 0l-1 1L18 8.5Zm-1 1-2.5-2.4-6 6 2.5 2.5 6-6Zm-7 7.1-2.6-2.4-.3.3-.1.2-.7 3 3.1-.6h.1l.4-.5Z"/></svg>',"edit-image":'<svg width="24" height="24"><path d="M18 16h2V7a2 2 0 0 0-2-2H7v2h11v9ZM6 17h15a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1H6a2 2 0 0 1-2-2V7H3a1 1 0 1 1 0-2h1V4a1 1 0 1 1 2 0v13Zm3-5.3 1.3 2 3-4.7 3.7 6H7l2-3.3Z" fill-rule="nonzero"/></svg>',"embed-page":'<svg width="24" height="24"><path d="M19 6V5H5v14h2A13 13 0 0 1 19 6Zm0 1.4c-.8.8-1.6 2.4-2.2 4.6H19V7.4Zm0 5.6h-2.4c-.4 1.8-.6 3.8-.6 6h3v-6Zm-4 6c0-2.2.2-4.2.6-6H13c-.7 1.8-1.1 3.8-1.1 6h3Zm-4 0c0-2.2.4-4.2 1-6H9.6A12 12 0 0 0 8 19h3ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm11.8 9c.4-1.9 1-3.4 1.8-4.5a9.2 9.2 0 0 0-4 4.5h2.2Zm-3.4 0a12 12 0 0 1 2.8-4 12 12 0 0 0-5 4h2.2Z" fill-rule="nonzero"/></svg>',embed:'<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm4.8 2.6 5.6 4a.5.5 0 0 1 0 .8l-5.6 4A.5.5 0 0 1 9 16V8a.5.5 0 0 1 .8-.4Z" fill-rule="nonzero"/></svg>',emoji:'<svg width="24" height="24"><path d="M9 11c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm6 0c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm-3 5.5c2.1 0 4-1.5 4.4-3.5H7.6c.5 2 2.3 3.5 4.4 3.5ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm0 14.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13Z" fill-rule="nonzero"/></svg>',export:'<svg width="24" height="24"><g fill-rule="nonzero"><path d="M14.4 3 18 7v1h-5V5H7v14h9a1 1 0 0 1 2 0c0 1-.8 2-1.9 2H7c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2h7.5Z"/><path d="M18.1 12c.5 0 .9.4.9 1 0 .5-.3 1-.8 1h-7.3c-.5 0-.9-.4-.9-1 0-.5.3-1 .8-1h7.3Z"/><path d="M16.4 9.2a1 1 0 0 1 1.4.2l2.4 3.6-2.4 3.6a1 1 0 0 1-1.7-1v-.2l1.7-2.4-1.6-2.4a1 1 0 0 1 .2-1.4Z"/></g></svg>',fill:'<svg width="24" height="26"><path d="m16.6 12-9-9-1.4 1.4 2.4 2.4-5.2 5.1c-.5.6-.5 1.6 0 2.2L9 19.6a1.5 1.5 0 0 0 2.2 0l5.5-5.5c.5-.6.5-1.6 0-2.2ZM5.2 13 10 8.2l4.8 4.8H5.2ZM19 14.5s-2 2.2-2 3.5c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.3-2-3.5-2-3.5Z" fill-rule="nonzero"/></svg>',"flip-horizontally":'<svg width="24" height="24"><path d="M14 19h2v-2h-2v2Zm4-8h2V9h-2v2ZM4 7v10c0 1.1.9 2 2 2h3v-2H6V7h3V5H6a2 2 0 0 0-2 2Zm14-2v2h2a2 2 0 0 0-2-2Zm-7 16h2V3h-2v18Zm7-6h2v-2h-2v2Zm-4-8h2V5h-2v2Zm4 12a2 2 0 0 0 2-2h-2v2Z" fill-rule="nonzero"/></svg>',"flip-vertically":'<svg width="24" height="24"><path d="M5 14v2h2v-2H5Zm8 4v2h2v-2h-2Zm4-14H7a2 2 0 0 0-2 2v3h2V6h10v3h2V6a2 2 0 0 0-2-2Zm2 14h-2v2a2 2 0 0 0 2-2ZM3 11v2h18v-2H3Zm6 7v2h2v-2H9Zm8-4v2h2v-2h-2ZM5 18c0 1.1.9 2 2 2v-2H5Z" fill-rule="nonzero"/></svg>',footnote:'<svg width="24" height="24"><path d="M19 13c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2h14Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19 4v6h-1V5h-1.5V4h2.6Z"/><path d="M12 18c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2h7ZM14 8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2h9Z"/></svg>',"format-painter":'<svg width="24" height="24"><path d="M18 5V4c0-.5-.4-1-1-1H5a1 1 0 0 0-1 1v4c0 .6.5 1 1 1h12c.6 0 1-.4 1-1V7h1v4H9v9c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-7h8V5h-3Z" fill-rule="nonzero"/></svg>',format:'<svg width="24" height="24"><path fill-rule="evenodd" d="M17 5a1 1 0 0 1 0 2h-4v11a1 1 0 0 1-2 0V7H7a1 1 0 1 1 0-2h10Z"/></svg>',fullscreen:'<svg width="24" height="24"><path d="m15.3 10-1.2-1.3 2.9-3h-2.3a.9.9 0 1 1 0-1.7H19c.5 0 .9.4.9.9v4.4a.9.9 0 1 1-1.8 0V7l-2.9 3Zm0 4 3 3v-2.3a.9.9 0 1 1 1.7 0V19c0 .5-.4.9-.9.9h-4.4a.9.9 0 1 1 0-1.8H17l-3-2.9 1.3-1.2ZM10 15.4l-2.9 3h2.3a.9.9 0 1 1 0 1.7H5a.9.9 0 0 1-.9-.9v-4.4a.9.9 0 1 1 1.8 0V17l2.9-3 1.2 1.3ZM8.7 10 5.7 7v2.3a.9.9 0 0 1-1.7 0V5c0-.5.4-.9.9-.9h4.4a.9.9 0 0 1 0 1.8H7l3 2.9-1.3 1.2Z" fill-rule="nonzero"/></svg>',gallery:'<svg width="24" height="24"><path fill-rule="nonzero" d="m5 15.7 2.3-2.2c.3-.3.7-.3 1 0L11 16l5.1-5c.3-.4.8-.4 1 0l2 1.9V8H5v7.7ZM5 18V19h3l1.8-1.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 6h16c.6 0 1 .4 1 1v13c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V7c0-.6.4-1 1-1Zm6 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4ZM4.5 4h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1Zm2-2h11a.5.5 0 1 1 0 1h-11a.5.5 0 0 1 0-1Z"/></svg>',gamma:'<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm6.5 11.8V14L9.2 8.7a5.1 5.1 0 0 0-.4-.8l-.1-.2H8v-1l.3-.1.3-.1h.7a1 1 0 0 1 .6.5l.1.3a8.5 8.5 0 0 1 .3.6l1.9 4.6 2-5.2a1 1 0 0 1 1-.6.5.5 0 0 1 .5.6L13 14v2.8a.7.7 0 0 1-1.4 0Z" fill-rule="nonzero"/></svg>',help:'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M12 5.5a6.5 6.5 0 0 0-6 9 6.3 6.3 0 0 0 1.4 2l1 1a6.3 6.3 0 0 0 3.6 1 6.5 6.5 0 0 0 6-9 6.3 6.3 0 0 0-1.4-2l-1-1a6.3 6.3 0 0 0-3.6-1ZM12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Z"/><path d="M9.6 9.7a.7.7 0 0 1-.7-.8c0-1.1 1.5-1.8 3.2-1.8 1.8 0 3.2.8 3.2 2.4 0 1.4-.4 2.1-1.5 2.8-.2 0-.3.1-.3.2a2 2 0 0 0-.8.8.8.8 0 0 1-1.4-.6c.3-.7.8-1 1.3-1.5l.4-.2c.7-.4.8-.6.8-1.5 0-.5-.6-.9-1.7-.9-.5 0-1 .1-1.4.3-.2 0-.3.1-.3.2v-.2c0 .4-.4.8-.8.8Z" fill-rule="nonzero"/><circle cx="12" cy="16" r="1"/></g></svg>',"highlight-bg-color":'<svg width="24" height="24"><g fill-rule="evenodd"><path class="tox-icon-highlight-bg-color__color" d="M3 18h18v3H3z"/><path fill-rule="nonzero" d="M7.7 16.7H3l3.3-3.3-.7-.8L10.2 8l4 4.1-4 4.2c-.2.2-.6.2-.8 0l-.6-.7-1.1 1.1zm5-7.5L11 7.4l3-2.9a2 2 0 0 1 2.6 0L18 6c.7.7.7 2 0 2.7l-2.9 2.9-1.8-1.8-.5-.6"/></g></svg>',home:'<svg width="24" height="24"><path fill-rule="nonzero" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',"horizontal-rule":'<svg width="24" height="24"><path d="M4 11h16v2H4z" fill-rule="evenodd"/></svg>',"image-options":'<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',image:'<svg width="24" height="24"><path d="m5 15.7 3.3-3.2c.3-.3.7-.3 1 0L12 15l4.1-4c.3-.4.8-.4 1 0l2 1.9V5H5v10.7ZM5 18V19h3l2.8-2.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" fill-rule="nonzero"/></svg>',indent:'<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm-2.6-3.8L6.2 12l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',info:'<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-1 3v2h2V7h-2Zm3 10v-1h-1v-5h-3v1h1v4h-1v1h4Z" fill-rule="evenodd"/></svg>',"insert-character":'<svg width="24" height="24"><path d="M15 18h4l1-2v4h-6v-3.3l1.4-1a6 6 0 0 0 1.8-2.9 6.3 6.3 0 0 0-.1-4.1 5.8 5.8 0 0 0-3-3.2c-.6-.3-1.3-.5-2.1-.5a5.1 5.1 0 0 0-3.9 1.8 6.3 6.3 0 0 0-1.3 6 6.2 6.2 0 0 0 1.8 3l1.4.9V20H4v-4l1 2h4v-.5l-2-1L5.4 15A6.5 6.5 0 0 1 4 11c0-1 .2-1.9.6-2.7A7 7 0 0 1 6.3 6C7.1 5.4 8 5 9 4.5c1-.3 2-.5 3.1-.5a8.8 8.8 0 0 1 5.7 2 7 7 0 0 1 1.7 2.3 6 6 0 0 1 .2 4.8c-.2.7-.6 1.3-1 1.9a7.6 7.6 0 0 1-3.6 2.5v.5Z" fill-rule="evenodd"/></svg>',"insert-time":'<svg width="24" height="24"><g fill-rule="nonzero"><path d="M12 19a7 7 0 1 0 0-14 7 7 0 0 0 0 14Zm0 2a9 9 0 1 1 0-18 9 9 0 0 1 0 18Z"/><path d="M16 12h-3V7c0-.6-.4-1-1-1a1 1 0 0 0-1 1v7h5c.6 0 1-.4 1-1s-.4-1-1-1Z"/></g></svg>',invert:'<svg width="24" height="24"><path d="M18 19.3 16.5 18a5.8 5.8 0 0 1-3.1 1.9 6.1 6.1 0 0 1-5.5-1.6A5.8 5.8 0 0 1 6 14v-.3l.1-1.2A13.9 13.9 0 0 1 7.7 9l-3-3 .7-.8 2.8 2.9 9 8.9 1.5 1.6-.7.6Zm0-5.5v.3l-.1 1.1-.4 1-1.2-1.2a4.3 4.3 0 0 0 .2-1v-.2c0-.4 0-.8-.2-1.3l-.5-1.4a14.8 14.8 0 0 0-3-4.2L12 6a26.1 26.1 0 0 0-2.2 2.5l-1-1a20.9 20.9 0 0 1 2.9-3.3L12 4l1 .8a22.2 22.2 0 0 1 4 5.4c.6 1.2 1 2.4 1 3.6Z" fill-rule="evenodd"/></svg>',italic:'<svg width="24" height="24"><path d="m16.7 4.7-.1.9h-.3c-.6 0-1 0-1.4.3-.3.3-.4.6-.5 1.1l-2.1 9.8v.6c0 .5.4.8 1.4.8h.2l-.2.8H8l.2-.8h.2c1.1 0 1.8-.5 2-1.5l2-9.8.1-.5c0-.6-.4-.8-1.4-.8h-.3l.2-.9h5.8Z" fill-rule="evenodd"/></svg>',language:'<svg width="24" height="24"><path d="M12 3a9 9 0 1 1 0 18 9 9 0 0 1 0-18Zm4.3 13.3c-.5 1-1.2 2-2 2.9a7.5 7.5 0 0 0 3.2-2.1l-.2-.2a6 6 0 0 0-1-.6Zm-8.6 0c-.5.2-.9.5-1.2.8.9 1 2 1.7 3.2 2a10 10 0 0 1-2-2.8Zm3.6-.8c-.8 0-1.6.1-2.2.3.5 1 1.2 1.9 2.1 2.7Zm1.5 0v3c.9-.8 1.6-1.7 2.1-2.7-.6-.2-1.4-.3-2.1-.3Zm-6-2.7H4.5c.2 1 .5 2.1 1 3h.3l1.3-1a10 10 0 0 1-.3-2Zm12.7 0h-2.3c0 .7-.1 1.4-.3 2l1.6 1.1c.5-1 .9-2 1-3.1Zm-3.8 0h-3V14c1 0 2 .1 2.7.4.2-.5.3-1 .3-1.6Zm-4.4 0h-3l.3 1.6c.8-.3 1.7-.4 2.7-.4v-1.3Zm-5.5-5c-.7 1-1.1 2.2-1.3 3.5h2.3c0-1 .2-1.8.5-2.6l-1.5-1Zm2.9 1.4v.1c-.2.6-.4 1.3-.4 2h3V9.4c-1 0-1.8-.1-2.6-.3Zm6.6 0h-.1l-2.4.3v1.8h3l-.5-2.1Zm3-1.4-.3.1-1.3.8c.3.8.5 1.6.5 2.6h2.3a7.5 7.5 0 0 0-1.3-3.5Zm-9 0 2 .2V5.5a9 9 0 0 0-2 2.2Zm3.5-2.3V8c.6 0 1.3 0 1.9-.2a9 9 0 0 0-2-2.3Zm-3-.7h-.1c-1.1.4-2.1 1-3 1.8l1.2.7a10 10 0 0 1 1.9-2.5Zm4.4 0 .1.1a10 10 0 0 1 1.8 2.4l1.1-.7a7.5 7.5 0 0 0-3-1.8Z"/></svg>',"line-height":'<svg width="24" height="24"><path d="M21 5a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zM7 3.6l3.7 3.7a1 1 0 0 1-1.3 1.5h-.1L8 7.3v9.2l1.3-1.3a1 1 0 0 1 1.3 0h.1c.4.4.4 1 0 1.3v.1L7 20.4l-3.7-3.7a1 1 0 0 1 1.3-1.5h.1L6 16.7V7.4L4.7 8.7a1 1 0 0 1-1.3 0h-.1a1 1 0 0 1 0-1.3v-.1L7 3.6z"/></svg>',line:'<svg width="24" height="24"><path d="m15 9-8 8H4v-3l8-8 3 3Zm1-1-3-3 1-1h1c-.2 0 0 0 0 0l2 2s0 .2 0 0v1l-1 1ZM4 18h16v2H4v-2Z" fill-rule="evenodd"/></svg>',link:'<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2-2a2 2 0 1 0-2.6-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2Z" fill-rule="nonzero"/></svg>',"list-bull-circle":'<svg width="48" height="48"><g fill-rule="evenodd"><path d="M11 16a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 26a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 36a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" fill-rule="nonzero"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',"list-bull-default":'<svg width="48" height="48"><g fill-rule="evenodd"><circle cx="11" cy="14" r="3"/><circle cx="11" cy="24" r="3"/><circle cx="11" cy="34" r="3"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',"list-bull-square":'<svg width="48" height="48"><g fill-rule="evenodd"><path d="M8 11h6v6H8zM8 21h6v6H8zM8 31h6v6H8z"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',"list-num-default-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 17v-4.8h-.1l-1.5 1v-1.1l1.6-1.1h1.2v6zM33.3 17.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm1.7 5.7c0-1.2 1-2 2.2-2 1.3 0 2.1.8 2.1 1.8 0 .7-.3 1.2-1.3 2.2l-1.2 1v.2h2.6v1h-4.3v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H35zm-1.7 4.3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm3.2 7.3v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H35c0-1.1 1-1.8 2.2-1.8 1.2 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.7.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .6 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7zm-3.3 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7z"/></g></svg>',"list-num-default":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10 17v-4.8l-1.5 1v-1.1l1.6-1h1.2V17h-1.2Zm3.6.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-5 5.7c0-1.2.8-2 2.1-2s2.1.8 2.1 1.8c0 .7-.3 1.2-1.4 2.2l-1.1 1v.2h2.6v1H8.6v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H8.5Zm6.3 4.3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM10 34.4v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H8.6c0-1.1 1-1.8 2.2-1.8 1.3 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.8.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .7 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7Zm4.7 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Z"/></g></svg>',"list-num-lower-alpha-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M36.5 16c-.9 0-1.5-.5-1.5-1.3s.6-1.3 1.8-1.4h1v-.4c0-.4-.2-.6-.7-.6-.4 0-.7.1-.8.4h-1.1c0-.8.8-1.4 2-1.4S39 12 39 13V16h-1.2v-.6c-.3.4-.8.7-1.4.7Zm.4-.8c.6 0 1-.4 1-.9V14h-1c-.5.1-.7.3-.7.6 0 .4.3.6.7.6ZM33.1 16.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7ZM37.7 26c-.7 0-1.2-.2-1.5-.7v.7H35v-6.3h1.2v2.5c.3-.5.8-.9 1.5-.9 1.1 0 1.8 1 1.8 2.4 0 1.5-.7 2.4-1.8 2.4Zm-.5-3.6c-.6 0-1 .5-1 1.3s.4 1.4 1 1.4c.7 0 1-.6 1-1.4 0-.8-.3-1.3-1-1.3ZM33.2 26.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zm6 7h-1c-.1-.5-.4-.8-1-.8s-1 .5-1 1.4c0 1 .4 1.4 1 1.4.5 0 .9-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7zm-6.1 3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',"list-num-lower-alpha":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.3 15.2c.5 0 1-.4 1-.9V14h-1c-.5.1-.8.3-.8.6 0 .4.3.6.8.6Zm-.4.9c-1 0-1.5-.6-1.5-1.4 0-.8.6-1.3 1.7-1.4h1.1v-.4c0-.4-.2-.6-.7-.6-.5 0-.8.1-.9.4h-1c0-.8.8-1.4 2-1.4 1.1 0 1.8.6 1.8 1.6V16h-1.1v-.6h-.1c-.2.4-.7.7-1.3.7Zm4.6 0c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-3.2 10c-.6 0-1.2-.3-1.4-.8v.7H8.5v-6.3H10v2.5c.3-.5.8-.9 1.4-.9 1.2 0 1.9 1 1.9 2.4 0 1.5-.7 2.4-1.9 2.4Zm-.4-3.7c-.7 0-1 .5-1 1.3s.3 1.4 1 1.4c.6 0 1-.6 1-1.4 0-.8-.4-1.3-1-1.3Zm4 3.7c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-2.2 7h-1.2c0-.5-.4-.8-.9-.8-.6 0-1 .5-1 1.4 0 1 .4 1.4 1 1.4.5 0 .8-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7Zm1.8 3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',"list-num-lower-greek-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 16c-1.2 0-2-.8-2-2.3 0-1.5.8-2.4 2-2.4.6 0 1 .4 1.3 1v-.9H40v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1-.7h-.2c-.2.4-.7.8-1.3.8Zm.3-1c.6 0 1-.5 1-1.3s-.4-1.3-1-1.3-1 .5-1 1.3.4 1.4 1 1.4ZM33.3 16.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM36 21.9c0-1.5.8-2.3 2.1-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.9 1.3.9.3 1.3.8 1.3 1.7 0 1.2-.7 1.9-1.8 1.9-.6 0-1.1-.3-1.4-.8v2.2H36V22Zm1.8 1.2v-1h.3c.5 0 .9-.2.9-.7 0-.5-.3-.8-.9-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1 1.3s1-.4 1-1-.4-1-1.2-1h-.3ZM33.3 26.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM37.1 34.6 34.8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.2.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1ZM33.3 36.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',"list-num-lower-greek":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.5 15c.7 0 1-.5 1-1.3s-.3-1.3-1-1.3c-.5 0-.9.5-.9 1.3s.4 1.4 1 1.4Zm-.3 1c-1.1 0-1.8-.8-1.8-2.3 0-1.5.7-2.4 1.8-2.4.7 0 1.1.4 1.3 1h.1v-.9h1.2v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1.1-.7h-.1c-.2.4-.7.8-1.4.8Zm5 .1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Zm-4.9 7v-1h.3c.6 0 1-.2 1-.7 0-.5-.4-.8-1-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1.1 1.3.6 0 1-.4 1-1s-.5-1-1.3-1h-.3ZM8.6 22c0-1.5.7-2.3 2-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.8 1.3.8.3 1.3.8 1.3 1.7 0 1.2-.8 1.9-1.9 1.9-.6 0-1.1-.3-1.3-.8v2.2H8.5V22Zm6.2 4.2c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-4.5 8.5L8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.1.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1Zm4.5.5c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',"list-num-lower-roman-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M32.9 16v-1.2h-1.3V16H33Zm0 10v-1.2h-1.3V26H33Zm0 10v-1.2h-1.3V36H33Z"/><path fill-rule="nonzero" d="M36 21h-1.5v5H36zM36 31h-1.5v5H36zM39 21h-1.5v5H39zM39 31h-1.5v5H39zM42 31h-1.5v5H42zM36 11h-1.5v5H36zM36 19h-1.5v1H36zM36 29h-1.5v1H36zM39 19h-1.5v1H39zM39 29h-1.5v1H39zM42 29h-1.5v1H42zM36 9h-1.5v1H36z"/></g></svg>',"list-num-lower-roman":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 16v-1.2h1.3V16H15Zm0 10v-1.2h1.3V26H15Zm0 10v-1.2h1.3V36H15Z"/><path fill-rule="nonzero" d="M12 21h1.5v5H12zM12 31h1.5v5H12zM9 21h1.5v5H9zM9 31h1.5v5H9zM6 31h1.5v5H6zM12 11h1.5v5H12zM12 19h1.5v1H12zM12 29h1.5v1H12zM9 19h1.5v1H9zM9 29h1.5v1H9zM6 29h1.5v1H6zM12 9h1.5v1H12z"/></g></svg>',"list-num-upper-alpha-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="m39.3 17-.5-1.4h-2l-.5 1.4H35l2-6h1.6l2 6h-1.3Zm-1.6-4.7-.7 2.3h1.6l-.8-2.3ZM33.4 17c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm4.7 9.9h-2.7v-6H38c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7Zm-1.4-5v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4h1.1c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9h-1.1V26ZM33 27.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm4.9 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm-4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',"list-num-upper-alpha":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="m12.6 17-.5-1.4h-2L9.5 17H8.3l2-6H12l2 6h-1.3ZM11 12.3l-.7 2.3h1.6l-.8-2.3Zm4.7 4.8c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7ZM11.4 27H8.7v-6h2.6c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7ZM10 22v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4H11c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9H10V26Zm5.4 1.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-4.1 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',"list-num-upper-roman-rtl":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M31.6 17v-1.2H33V17h-1.3Zm0 10v-1.2H33V27h-1.3Zm0 10v-1.2H33V37h-1.3Z"/><path fill-rule="nonzero" d="M34.5 20H36v7h-1.5zM34.5 30H36v7h-1.5zM37.5 20H39v7h-1.5zM37.5 30H39v7h-1.5zM40.5 30H42v7h-1.5zM34.5 10H36v7h-1.5z"/></g></svg>',"list-num-upper-roman":'<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 17v-1.2h1.3V17H15Zm0 10v-1.2h1.3V27H15Zm0 10v-1.2h1.3V37H15Z"/><path fill-rule="nonzero" d="M12 20h1.5v7H12zM12 30h1.5v7H12zM9 20h1.5v7H9zM9 30h1.5v7H9zM6 30h1.5v7H6zM12 10h1.5v7H12z"/></g></svg>',lock:'<svg width="24" height="24"><path d="M16.3 11c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H8V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h.3ZM10 8v3h4V8a1 1 0 0 0-.3-.7A1 1 0 0 0 13 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7Z" fill-rule="evenodd"/></svg>',ltr:'<svg width="24" height="24"><path d="M11 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 7.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L11 5ZM4.4 16.2 6.2 15l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',"math-equation":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 4.8c.1-.5.5-.8 1-.8h10a1 1 0 1 1 0 2h-9.2L8.3 19.2a1 1 0 0 1-1.7.4l-3.4-4.2a1 1 0 0 1 1.6-1.2l2 2.5L9 4.8Zm9.7 5.5c.4.4.4 1 0 1.4L17 13.5l1.8 1.8a1 1 0 1 1-1.4 1.4L15.5 15l-1.8 1.8a1 1 0 0 1-1.4-1.4l1.8-1.8-1.8-1.8a1 1 0 0 1 1.4-1.4l1.8 1.8 1.8-1.8a1 1 0 0 1 1.4 0Z"/></svg>',minus:'<svg width="24" height="24"><path d="M19 11a1 1 0 0 1 .1 2H5a1 1 0 0 1-.1-2H19Z"/></svg>',"more-drawer":'<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',"new-document":'<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',"new-tab":'<svg width="24" height="24"><path d="m15 13 2-2v8H5V7h8l-2 2H7v8h8v-4Zm4-8v5.5l-2-2-5.6 5.5H10v-1.4L15.5 7l-2-2H19Z" fill-rule="evenodd"/></svg>',"non-breaking":'<svg width="24" height="24"><path d="M11 11H8a1 1 0 1 1 0-2h3V6c0-.6.4-1 1-1s1 .4 1 1v3h3c.6 0 1 .4 1 1s-.4 1-1 1h-3v3c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-3Zm10 4v5H3v-5c0-.6.4-1 1-1s1 .4 1 1v3h14v-3c0-.6.4-1 1-1s1 .4 1 1Z" fill-rule="evenodd"/></svg>',notice:'<svg width="24" height="24"><path d="M15.5 4 20 8.5v7L15.5 20h-7L4 15.5v-7L8.5 4h7ZM13 17v-2h-2v2h2Zm0-4V7h-2v6h2Z" fill-rule="evenodd" clip-rule="evenodd"/></svg>',"ordered-list-rtl":'<svg width="24" height="24"><path d="M6 17h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2Zm13-1v3.5a.5.5 0 1 1-1 0V5h-.5a.5.5 0 1 1 0-1H19Zm-1 8.8.2.2h1.3a.5.5 0 1 1 0 1h-1.6a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2h-1.3a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3Zm2 4.2v2c0 .6-.4 1-1 1h-1.5a.5.5 0 0 1 0-1h1.2a.3.3 0 1 0 0-.6h-1.3a.4.4 0 1 1 0-.8h1.3a.3.3 0 0 0 0-.6h-1.2a.5.5 0 1 1 0-1H19c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',"ordered-list":'<svg width="24" height="24"><path d="M10 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 1 1 0-2ZM6 4v3.5c0 .3-.2.5-.5.5a.5.5 0 0 1-.5-.5V5h-.5a.5.5 0 0 1 0-1H6Zm-1 8.8.2.2h1.3c.3 0 .5.2.5.5s-.2.5-.5.5H4.9a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2H4.5a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3ZM7 17v2c0 .6-.4 1-1 1H4.5a.5.5 0 0 1 0-1h1.2c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.4a.4.4 0 1 1 0-.8h1.3c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.5a.5.5 0 1 1 0-1H6c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',orientation:'<svg width="24" height="24"><path d="M7.3 6.4 1 13l6.4 6.5 6.5-6.5-6.5-6.5ZM3.7 13l3.6-3.7L11 13l-3.7 3.7-3.6-3.7ZM12 6l2.8 2.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0L9.2 5.7a.8.8 0 0 1 0-1.2L13.6.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L12 4h1a9 9 0 1 1-4.3 16.9l1.5-1.5A7 7 0 1 0 13 6h-1Z" fill-rule="nonzero"/></svg>',outdent:'<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm1.6-3.8a1 1 0 0 1-1.2 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 0 1 1.2 1.6L6.8 12l1.8 1.2Z" fill-rule="evenodd"/></svg>',"page-break":'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M5 11c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1h-1a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2ZM7 3v5h10V3c0-.6.4-1 1-1s1 .4 1 1v7H5V3c0-.6.4-1 1-1s1 .4 1 1ZM6 22a1 1 0 0 1-1-1v-7h14v7c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5H7v5c0 .6-.4 1-1 1Z"/></g></svg>',paragraph:'<svg width="24" height="24"><path fill-rule="evenodd" d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z"/></svg>',"paste-column-after":'<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h7v2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm8 7v12h-6V8h6Zm-1.5 1.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',"paste-column-before":'<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V18c0 1-.8 2-1.9 2H11v-2h7V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v2H4V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm-2 7v12H4V8h6ZM8.5 9.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',"paste-row-after":'<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V11h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h14c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 11v5H8v-5h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',"paste-row-before":'<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h12v-4h2v4c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 7v5H8V8h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',"paste-text":'<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Zm0 9h6v2h-.5l-.5-1h-1v4h.8v1h-3.6v-1h.8v-4h-1l-.5 1H12v-2Z" fill-rule="nonzero"/></svg>',paste:'<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Z" fill-rule="nonzero"/></svg>',"permanent-pen":'<svg width="24" height="24"><path d="M10.5 17.5 8 20H3v-3l3.5-3.5a2 2 0 0 1 0-3L14 3l1 1-7.3 7.3a1 1 0 0 0 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0L20 9l1 1-7.6 7.6a2 2 0 0 1-2.8 0l-.1-.1Z" fill-rule="nonzero"/></svg>',plus:'<svg width="24" height="24"><path d="M12 4c.5 0 1 .4 1 .9V11h6a1 1 0 0 1 .1 2H13v6a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H11V5c0-.6.4-1 1-1Z"/></svg>',preferences:'<svg width="24" height="24"><path d="m20.1 13.5-1.9.2a5.8 5.8 0 0 1-.6 1.5l1.2 1.5c.4.4.3 1 0 1.4l-.7.7a1 1 0 0 1-1.4 0l-1.5-1.2a6.2 6.2 0 0 1-1.5.6l-.2 1.9c0 .5-.5.9-1 .9h-1a1 1 0 0 1-1-.9l-.2-1.9a5.8 5.8 0 0 1-1.5-.6l-1.5 1.2a1 1 0 0 1-1.4 0l-.7-.7a1 1 0 0 1 0-1.4l1.2-1.5a6.2 6.2 0 0 1-.6-1.5l-1.9-.2a1 1 0 0 1-.9-1v-1c0-.5.4-1 .9-1l1.9-.2a5.8 5.8 0 0 1 .6-1.5L5.2 7.3a1 1 0 0 1 0-1.4l.7-.7a1 1 0 0 1 1.4 0l1.5 1.2a6.2 6.2 0 0 1 1.5-.6l.2-1.9c0-.5.5-.9 1-.9h1c.5 0 1 .4 1 .9l.2 1.9a5.8 5.8 0 0 1 1.5.6l1.5-1.2a1 1 0 0 1 1.4 0l.7.7c.3.4.4 1 0 1.4l-1.2 1.5a6.2 6.2 0 0 1 .6 1.5l1.9.2c.5 0 .9.5.9 1v1c0 .5-.4 1-.9 1ZM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" fill-rule="evenodd"/></svg>',preview:'<svg width="24" height="24"><path d="M3.5 12.5c.5.8 1.1 1.6 1.8 2.3 2 2 4.2 3.2 6.7 3.2s4.7-1.2 6.7-3.2a16.2 16.2 0 0 0 2.1-2.8 15.7 15.7 0 0 0-2.1-2.8c-2-2-4.2-3.2-6.7-3.2a9.3 9.3 0 0 0-6.7 3.2A16.2 16.2 0 0 0 3.2 12c0 .2.2.3.3.5Zm-2.4-1 .7-1.2L4 7.8C6.2 5.4 8.9 4 12 4c3 0 5.8 1.4 8.1 3.8a18.2 18.2 0 0 1 2.8 3.7v1l-.7 1.2-2.1 2.5c-2.3 2.4-5 3.8-8.1 3.8-3 0-5.8-1.4-8.1-3.8a18.2 18.2 0 0 1-2.8-3.7 1 1 0 0 1 0-1Zm12-3.3a2 2 0 1 0 2.7 2.6 4 4 0 1 1-2.6-2.6Z" fill-rule="nonzero"/></svg>',print:'<svg width="24" height="24"><path d="M18 8H6a3 3 0 0 0-3 3v6h2v3h14v-3h2v-6a3 3 0 0 0-3-3Zm-1 10H7v-4h10v4Zm.5-5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5Zm.5-8H6v2h12V5Z" fill-rule="nonzero"/></svg>',quote:'<svg width="24" height="24"><path d="M7.5 17h.9c.4 0 .7-.2.9-.6L11 13V8c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Zm8 0h.9c.4 0 .7-.2.9-.6L19 13V8c0-.6-.4-1-1-1h-4a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Z" fill-rule="nonzero"/></svg>',redo:'<svg width="24" height="24"><path d="M17.6 10H12c-2.8 0-4.4 1.4-4.9 3.5-.4 2 .3 4 1.4 4.6a1 1 0 1 1-1 1.8c-2-1.2-2.9-4.1-2.3-6.8.6-3 3-5.1 6.8-5.1h5.6l-3.3-3.3a1 1 0 1 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4-1.4l3.3-3.3Z" fill-rule="nonzero"/></svg>',reload:'<svg width="24" height="24"><g fill-rule="nonzero"><path d="m5 22.1-1.2-4.7v-.2a1 1 0 0 1 1-1l5 .4a1 1 0 1 1-.2 2l-2.2-.2a7.8 7.8 0 0 0 8.4.2 7.5 7.5 0 0 0 3.5-6.4 1 1 0 1 1 2 0 9.5 9.5 0 0 1-4.5 8 9.9 9.9 0 0 1-10.2 0l.4 1.4a1 1 0 1 1-2 .5ZM13.6 7.4c0-.5.5-1 1-.9l2.8.2a8 8 0 0 0-9.5-1 7.5 7.5 0 0 0-3.6 7 1 1 0 0 1-2 0 9.5 9.5 0 0 1 4.5-8.6 10 10 0 0 1 10.9.3l-.3-1a1 1 0 0 1 2-.5l1.1 4.8a1 1 0 0 1-1 1.2l-5-.4a1 1 0 0 1-.9-1Z"/></g></svg>',"remove-formatting":'<svg width="24" height="24"><path d="M13.2 6a1 1 0 0 1 0 .2l-2.6 10a1 1 0 0 1-1 .8h-.2a.8.8 0 0 1-.8-1l2.6-10H8a1 1 0 1 1 0-2h9a1 1 0 0 1 0 2h-3.8ZM5 18h7a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Zm13 1.5L16.5 18 15 19.5a.7.7 0 0 1-1-1l1.5-1.5-1.5-1.5a.7.7 0 0 1 1-1l1.5 1.5 1.5-1.5a.7.7 0 0 1 1 1L17.5 17l1.5 1.5a.7.7 0 0 1-1 1Z" fill-rule="evenodd"/></svg>',remove:'<svg width="24" height="24"><path d="M16 7h3a1 1 0 0 1 0 2h-1v9a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V9H5a1 1 0 1 1 0-2h3V6a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v1Zm-2 0V6c0-.6-.4-1-1-1h-2a1 1 0 0 0-1 1v1h4Zm2 2H8v9c0 .6.4 1 1 1h6c.6 0 1-.4 1-1V9Zm-7 3a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Zm4 0a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Z" fill-rule="nonzero"/></svg>',"resize-handle":'<svg width="10" height="10"><g fill-rule="nonzero"><path d="M8.1 1.1A.5.5 0 1 1 9 2l-7 7A.5.5 0 1 1 1 8l7-7ZM8.1 5.1A.5.5 0 1 1 9 6l-3 3A.5.5 0 1 1 5 8l3-3Z"/></g></svg>',resize:'<svg width="24" height="24"><path d="M4 5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h6c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H7.4L18 16.6V13c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v6c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-6a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3.6L6 7.4V11c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3A1 1 0 0 1 4 11V5Z" fill-rule="evenodd"/></svg>',"restore-draft":'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M17 13c0 .6-.4 1-1 1h-4V8c0-.6.4-1 1-1s1 .4 1 1v4h2c.6 0 1 .4 1 1Z"/><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></g></svg>',"revision-history":'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M17 13c0 .6-.4 1-1 1h-4V8c0-.6.4-1 1-1s1 .4 1 1v4h2c.6 0 1 .4 1 1Z"/><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></g></svg>',"rotate-left":'<svg width="24" height="24"><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></svg>',"rotate-right":'<svg width="24" height="24"><path d="M20 8V5a1 1 0 0 1 2 0v6c0 .6-.4 1-1 1h-6a1 1 0 0 1 0-2h4.3L16 7A7.2 7.2 0 0 0 7.7 6a7 7 0 0 0 3 13.1c1.9.1 3.7-.5 5-1.7a1 1 0 0 1 1.4 1.5A9.2 9.2 0 0 1 2.2 14c-.9-3.9 1-8 4.5-9.9 3.5-1.9 8-1.3 10.8 1.5L20 8Z" fill-rule="nonzero"/></svg>',rtl:'<svg width="24" height="24"><path d="M8 5h8v2h-2v12h-2V7h-2v12H8v-7c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 4.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L8 5Zm12 11.2a1 1 0 1 1-1 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 1 1 1 1.6L18.4 15l1.8 1.2Z" fill-rule="evenodd"/></svg>',save:'<svg width="24" height="24"><path d="M5 16h14a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2c0-1.1.9-2 2-2Zm0 2v2h14v-2H5Zm10 0h2v2h-2v-2Zm-4-6.4L8.7 9.3a1 1 0 1 0-1.4 1.4l4 4c.4.4 1 .4 1.4 0l4-4a1 1 0 1 0-1.4-1.4L13 11.6V4a1 1 0 0 0-2 0v7.6Z" fill-rule="nonzero"/></svg>',search:'<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z" fill-rule="nonzero"/></svg>',"select-all":'<svg width="24" height="24"><path d="M3 5h2V3a2 2 0 0 0-2 2Zm0 8h2v-2H3v2Zm4 8h2v-2H7v2ZM3 9h2V7H3v2Zm10-6h-2v2h2V3Zm6 0v2h2a2 2 0 0 0-2-2ZM5 21v-2H3c0 1.1.9 2 2 2Zm-2-4h2v-2H3v2ZM9 3H7v2h2V3Zm2 18h2v-2h-2v2Zm8-8h2v-2h-2v2Zm0 8a2 2 0 0 0 2-2h-2v2Zm0-12h2V7h-2v2Zm0 8h2v-2h-2v2Zm-4 4h2v-2h-2v2Zm0-16h2V3h-2v2ZM7 17h10V7H7v10Zm2-8h6v6H9V9Z" fill-rule="nonzero"/></svg>',selected:'<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm3.6 10.9L7 12.3a.7.7 0 0 0-1 1L9.6 17 18 8.6a.7.7 0 0 0 0-1 .7.7 0 0 0-1 0l-7.4 7.3Z"/></svg>',send:'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="m13.3 22 7-18.3-18.3 7L9 15l4.3 7ZM18 6.8l-.7-.7L9.4 14l.7.7L18 6.8Z"/></svg>',settings:'<svg width="24" height="24"><path d="M11 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V8H5a1 1 0 1 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.5V6ZM8 8h2V6H8v2Zm9 2.8v.2h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v.3c0 .2 0 .3-.2.5l-.6.2h-2.4c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V13H5a1 1 0 0 1 0-2h8v-.3c0-.2 0-.3.2-.5l.6-.2h2.4c.3 0 .4 0 .6.2l.2.6ZM14 13h2v-2h-2v2Zm-3 2.8v.2h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V18H5a1 1 0 0 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.6ZM8 18h2v-2H8v2Z" fill-rule="evenodd"/></svg>',sharpen:'<svg width="24" height="24"><path d="m16 6 4 4-8 9-8-9 4-4h8Zm-4 10.2 5.5-6.2-.1-.1H12v-.3h5.1l-.2-.2H12V9h4.6l-.2-.2H12v-.3h4.1l-.2-.2H12V8h3.6l-.2-.2H8.7L6.5 10l.1.1H12v.3H6.9l.2.2H12v.3H7.3l.2.2H12v.3H7.7l.3.2h4v.3H8.2l.2.2H12v.3H8.6l.3.2H12v.3H9l.3.2H12v.3H9.5l.2.2H12v.3h-2l.2.2H12v.3h-1.6l.2.2H12v.3h-1.1l.2.2h.9v.3h-.7l.2.2h.5v.3h-.3l.3.2Z" fill-rule="evenodd"/></svg>',sourcecode:'<svg width="24" height="24"><g fill-rule="nonzero"><path d="M9.8 15.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0l-4.4-4.1a.8.8 0 0 1 0-1.2l4.4-4.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L6 12l3.8 3.7ZM14.2 15.7c-.3.3-.3.8 0 1 .4.4.9.4 1.2 0l4.4-4.1c.3-.3.3-.9 0-1.2l-4.4-4.2a.8.8 0 0 0-1.2 0c-.3.3-.3.8 0 1.1L18 12l-3.8 3.7Z"/></g></svg>',"spell-check":'<svg width="24" height="24"><path d="M6 8v3H5V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h2c.3 0 .5.1.7.3.2.2.3.4.3.7v6H8V8H6Zm0-3v2h2V5H6Zm13 0h-3v5h3v1h-3a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3v1Zm-5 1.5-.1.7c-.1.2-.3.3-.6.3.3 0 .5.1.6.3l.1.7V10c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-3V4h3c.3 0 .5.1.7.3.2.2.3.4.3.7v1.5ZM13 10V8h-2v2h2Zm0-3V5h-2v2h2Zm3 5 1 1-6.5 7L7 15.5l1.3-1 2.2 2.2L16 12Z" fill-rule="evenodd"/></svg>',"strike-through":'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M15.6 8.5c-.5-.7-1-1.1-1.3-1.3-.6-.4-1.3-.6-2-.6-2.7 0-2.8 1.7-2.8 2.1 0 1.6 1.8 2 3.2 2.3 4.4.9 4.6 2.8 4.6 3.9 0 1.4-.7 4.1-5 4.1A6.2 6.2 0 0 1 7 16.4l1.5-1.1c.4.6 1.6 2 3.7 2 1.6 0 2.5-.4 3-1.2.4-.8.3-2-.8-2.6-.7-.4-1.6-.7-2.9-1-1-.2-3.9-.8-3.9-3.6C7.6 6 10.3 5 12.4 5c2.9 0 4.2 1.6 4.7 2.4l-1.5 1.1Z"/><path d="M5 11h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z" fill-rule="nonzero"/></g></svg>',subscript:'<svg width="24" height="24"><path d="m10.4 10 4.6 4.6-1.4 1.4L9 11.4 4.4 16 3 14.6 7.6 10 3 5.4 4.4 4 9 8.6 13.6 4 15 5.4 10.4 10ZM21 19h-5v-1l1-.8 1.7-1.6c.3-.4.5-.8.5-1.2 0-.3 0-.6-.2-.7-.2-.2-.5-.3-.9-.3a2 2 0 0 0-.8.2l-.7.3-.4-1.1 1-.6 1.2-.2c.8 0 1.4.3 1.8.7.4.4.6.9.6 1.5s-.2 1.1-.5 1.6a8 8 0 0 1-1.3 1.3l-.6.6h2.6V19Z" fill-rule="nonzero"/></svg>',superscript:'<svg width="24" height="24"><path d="M15 9.4 10.4 14l4.6 4.6-1.4 1.4L9 15.4 4.4 20 3 18.6 7.6 14 3 9.4 4.4 8 9 12.6 13.6 8 15 9.4Zm5.9 1.6h-5v-1l1-.8 1.7-1.6c.3-.5.5-.9.5-1.3 0-.3 0-.5-.2-.7-.2-.2-.5-.3-.9-.3l-.8.2-.7.4-.4-1.2c.2-.2.5-.4 1-.5.3-.2.8-.2 1.2-.2.8 0 1.4.2 1.8.6.4.4.6 1 .6 1.6 0 .5-.2 1-.5 1.5l-1.3 1.4-.6.5h2.6V11Z" fill-rule="nonzero"/></svg>',"table-caption":'<svg width="24" height="24"><g fill-rule="nonzero"><rect width="12" height="2" x="3" y="4" rx="1"/><path d="M19 8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-8c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></g></svg>',"table-cell-classes":'<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M13 4v9H3V6c0-1.1.9-2 2-2h8Zm-2 2H5v5h6V6Z"/><path fill-rule="nonzero" d="M13 4h6a2 2 0 0 1 2 2v7h-8v-2h6V6h-6V4Z" opacity=".2"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/><path fill-rule="nonzero" d="M3 13v5c0 1.1.9 2 2 2h8v-7h-2v5H5v-5H3Z" opacity=".2"/></g></svg>',"table-cell-properties":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8 0h-6v5h6v-5Zm-8-7H5v5h6V6Z"/></svg>',"table-cell-select-all":'<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z" opacity=".2"/></g></svg>',"table-cell-select-inner":'<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z" opacity=".2"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z"/></g></svg>',"table-classes":'<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v7h-8v7H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8-7h-6v5h6V6Zm-8 0H5v5h6V6Z"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/></g></svg>',"table-delete-column":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-4 4h-2V6h-2v2H9V6H5v12h4v-2h2v2h2v-2h2v2h4V6h-4v2Zm.3.5 1 1.2-3 2.3 3 2.3-1 1.2L12 13l-3.3 2.6-1-1.2 3-2.3-3-2.3 1-1.2L12 11l3.3-2.5Z"/></svg>',"table-delete-row":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v3h2.5v2H5v2h2.5v2H5v3h14v-3h-2.5v-2H19v-2h-2.5V9H19V6Zm-4.7 1.8 1.2 1L13 12l2.6 3.3-1.2 1-2.3-3-2.3 3-1.2-1L11 12 8.5 8.7l1.2-1 2.3 3 2.3-3Z"/></svg>',"table-delete-table":'<svg width="24" height="24"><g fill-rule="nonzero"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 6v12h14V6H5Z"/><path d="m14.4 8.6 1.1 1-2.4 2.4 2.4 2.4-1.1 1.1-2.4-2.4-2.4 2.4-1-1.1 2.3-2.4-2.3-2.4 1-1 2.4 2.3z"/></g></svg>',"table-insert-column-after":'<svg width="24" height="24"><path fill-rule="nonzero" d="M20 4c.6 0 1 .4 1 1v2a1 1 0 0 1-2 0V6h-8v12h8v-1a1 1 0 0 1 2 0v2c0 .5-.4 1-.9 1H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h15ZM9 13H5v5h4v-5Zm7-5c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H17v2a1 1 0 0 1-2 .1V13h-2a1 1 0 0 1-.1-2H15V9c0-.6.4-1 1-1ZM9 6H5v5h4V6Z"/></svg>',"table-insert-column-before":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a1 1 0 0 1-1-1v-2a1 1 0 0 1 2 0v1h8V6H5v1a1 1 0 1 1-2 0V5c0-.6.4-1 1-1h15Zm0 9h-4v5h4v-5ZM8 8c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H9v2a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H7V9c0-.6.4-1 1-1Zm11-2h-4v5h4V6Z"/></svg>',"table-insert-row-above":'<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4a1 1 0 1 1 0 2H5v6h14V6h-1a1 1 0 0 1 0-2h2c.6 0 1 .4 1 1v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-.6.4-1 1-1h2Zm5 10H5v4h6v-4Zm8 0h-6v4h6v-4ZM12 3c.5 0 1 .4 1 .9V6h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 .1V8H9a1 1 0 0 1 0-2h2V4c0-.6.4-1 1-1Z"/></svg>',"table-insert-row-after":'<svg width="24" height="24"><path fill-rule="nonzero" d="M12 13c.5 0 1 .4 1 .9V16h2a1 1 0 0 1 .1 2H13v2a1 1 0 0 1-2 .1V18H9a1 1 0 0 1-.1-2H11v-2c0-.6.4-1 1-1Zm6 7a1 1 0 0 1 0-2h1v-6H5v6h1a1 1 0 0 1 0 2H4a1 1 0 0 1-1-1V6c0-1.1.9-2 2-2h14a2 2 0 0 1 2 2v13c0 .5-.4 1-.9 1H18ZM11 6H5v4h6V6Zm8 0h-6v4h6V6Z"/></svg>',"table-left-header":'<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 9h-4v5h4v-5Zm-6 0H9v5h4v-5Zm0-7H9v5h4V6Zm6 0h-4v5h4V6Z"/></svg>',"table-merge-cells":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15.5V18h3v-2.5H5Zm14-5h-9V18h9v-7.5ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Zm-8 7.5h3v-3H5v3Z"/></svg>',"table-row-numbering-rtl":'<svg width="24" height="24"><path d="M6 4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6Zm0 12h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 11h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 6h8v3H6V6Zm11 0c.6 0 1 .4 1 1v1a1 1 0 1 1-2 0V7c0-.6.4-1 1-1Z"/></svg>',"table-row-numbering":'<svg width="24" height="24"><path d="M18 4a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h12Zm0 12h-8v3h8v-3ZM7 16a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8v-3ZM7 11a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8V6ZM7 6a1 1 0 0 0-1 1v1a1 1 0 1 0 2 0V7c0-.6-.4-1-1-1Z"/></svg>',"table-row-properties":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-9h-6v3h6V6ZM5 9h6V6H5v3Z"/></svg>',"table-split-cells":'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM8 15.5H5V18h3v-2.5Zm11-5h-9V18h9v-7.5Zm-2.5 1 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2Zm-8.5-1H5v3h3v-3ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Z"/></svg>',"table-top-header":'<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 11H5v3h6v-3Zm8 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></svg>',table:'<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 14v4h6v-4H5Zm14 0h-6v4h6v-4Zm0-6h-6v4h6V8ZM5 12h6V8H5v4Z"/></svg>',"template-add":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 12v4H5a2 2 0 0 0-2 2v3h9.3a6 6 0 0 1-.3-2H5v-1h7a6 6 0 0 1 .8-2H11v-5l-.8-.6a3 3 0 1 1 3.6 0l-.8.6v4.7a6 6 0 0 1 2-1.9V12a5 5 0 1 0-6 0Z"/><path d="M18 15c.5 0 1 .4 1 .9V18h2a1 1 0 0 1 .1 2H19v2a1 1 0 0 1-2 .1V20h-2a1 1 0 0 1-.1-2H17v-2c0-.6.4-1 1-1Z"/></svg>',template:'<svg width="24" height="24"><path d="M19 19v-1H5v1h14ZM9 16v-4a5 5 0 1 1 6 0v4h4a2 2 0 0 1 2 2v3H3v-3c0-1.1.9-2 2-2h4Zm4 0v-5l.8-.6a3 3 0 1 0-3.6 0l.8.6v5h2Z" fill-rule="nonzero"/></svg>',"temporary-placeholder":'<svg width="24" height="24"><g fill-rule="evenodd"><path d="M9 7.6V6h2.5V4.5a.5.5 0 1 1 1 0V6H15v1.6a8 8 0 1 1-6 0Zm-2.6 5.3a.5.5 0 0 0 .3.6c.3 0 .6 0 .6-.3l.1-.2a5 5 0 0 1 3.3-2.8c.3-.1.4-.4.4-.6-.1-.3-.4-.5-.6-.4a6 6 0 0 0-4.1 3.7Z"/><circle cx="14" cy="4" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="10" cy="4" r="1"/></g></svg>',"text-color":'<svg width="24" height="24"><g fill-rule="evenodd"><path class="tox-icon-text-color__color" d="M3 18h18v3H3z"/><path d="M8.7 16h-.8a.5.5 0 0 1-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 0 1-.5.6h-.8a.5.5 0 0 1-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4Zm2.6-7.6-.6 2a.5.5 0 0 0 .5.6h1.6a.5.5 0 0 0 .5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4Z"/></g></svg>',"text-size-decrease":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5a1 1 0 1 1 0 2h-4v11a1 1 0 1 1-2 0V7H4a1 1 0 0 1 0-2h10ZM14 12a1 1 0 1 0 0 2h6a1 1 0 1 0 0-2h-6Z"/></svg>',"text-size-increase":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5a1 1 0 1 1 0 2h-4v11a1 1 0 1 1-2 0V7H4a1 1 0 0 1 0-2h10ZM17 9a1 1 0 0 0-1 1v2h-2a1 1 0 1 0 0 2h2v2a1 1 0 1 0 2 0v-2h2a1 1 0 1 0 0-2h-2v-2c0-.6-.4-1-1-1Z"/></svg>',toc:'<svg width="24" height="24"><path d="M5 5c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm0-4c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',translate:'<svg width="24" height="24"><path d="m12.7 14.3-.3.7-.4.7-2.2-2.2-3.1 3c-.3.4-.8.4-1 0a.7.7 0 0 1 0-1l3.1-3A12.4 12.4 0 0 1 6.7 9H8a10.1 10.1 0 0 0 1.7 2.4c.5-.5 1-1.1 1.4-1.8l.9-2H4.7a.7.7 0 1 1 0-1.5h4.4v-.7c0-.4.3-.8.7-.8.4 0 .7.4.7.8v.7H15c.4 0 .8.3.8.7 0 .4-.4.8-.8.8h-1.4a12.3 12.3 0 0 1-1 2.4 13.5 13.5 0 0 1-1.7 2.3l1.9 1.8Zm4.3-3 2.7 7.3a.5.5 0 0 1-.4.7 1 1 0 0 1-1-.7l-.6-1.5h-3.4l-.6 1.5a1 1 0 0 1-1 .7.5.5 0 0 1-.4-.7l2.7-7.4a1 1 0 0 1 2 0Zm-2.2 4.4h2.4L16 12.5l-1.2 3.2Z" fill-rule="evenodd"/></svg>',typography:'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M17 5a1 1 0 1 1 0 2h-4v11a1 1 0 1 1-2 0V7H7a1 1 0 0 1 0-2h10Z"/><path d="m17.5 14 .8-1.7 1.7-.8-1.7-.8-.8-1.7-.8 1.7-1.7.8 1.7.8.8 1.7ZM7 14l1 2 2 1-2 1-1 2-1-2-2-1 2-1 1-2Z"/></svg>',underline:'<svg width="24" height="24"><path d="M16 5c.6 0 1 .4 1 1v5.5a4 4 0 0 1-.4 1.8l-1 1.4a5.3 5.3 0 0 1-5.5 1 5 5 0 0 1-1.6-1c-.5-.4-.8-.9-1.1-1.4a4 4 0 0 1-.4-1.8V6c0-.6.4-1 1-1s1 .4 1 1v5.5c0 .3 0 .6.2 1l.6.7a3.3 3.3 0 0 0 2.2.8 3.4 3.4 0 0 0 2.2-.8c.3-.2.4-.5.6-.8l.2-.9V6c0-.6.4-1 1-1ZM8 17h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',undo:'<svg width="24" height="24"><path d="M6.4 8H12c3.7 0 6.2 2 6.8 5.1.6 2.7-.4 5.6-2.3 6.8a1 1 0 0 1-1-1.8c1.1-.6 1.8-2.7 1.4-4.6-.5-2.1-2.1-3.5-4.9-3.5H6.4l3.3 3.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 1.4L6.4 8Z" fill-rule="nonzero"/></svg>',unlink:'<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2.1-2a2 2 0 1 0-2.7-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2ZM7.6 6.3a.8.8 0 0 1-1 1.1L3.3 4.2a.7.7 0 1 1 1-1l3.2 3.1ZM5.1 8.6a.8.8 0 0 1 0 1.5H3a.8.8 0 0 1 0-1.5H5Zm5-3.5a.8.8 0 0 1-1.5 0V3a.8.8 0 0 1 1.5 0V5Zm6 11.8a.8.8 0 0 1 1-1l3.2 3.2a.8.8 0 0 1-1 1L16 17Zm-2.2 2a.8.8 0 0 1 1.5 0V21a.8.8 0 0 1-1.5 0V19Zm5-3.5a.7.7 0 1 1 0-1.5H21a.8.8 0 0 1 0 1.5H19Z" fill-rule="nonzero"/></svg>',unlock:'<svg width="24" height="24"><path d="M16 5c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h-2V8a1 1 0 0 0-.3-.7A1 1 0 0 0 16 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7v3h.3c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H4.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H11V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2Z" fill-rule="evenodd"/></svg>',"unordered-list":'<svg width="24" height="24"><path d="M11 5h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2ZM4.5 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Z" fill-rule="evenodd"/></svg>',unselected:'<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm0 1a1 1 0 0 0-1 1v12c0 .6.4 1 1 1h12c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H6Z"/></svg>',upload:'<svg width="24" height="24"><path d="M18 19v-2a1 1 0 0 1 2 0v3c0 .6-.4 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 2 0v2h12ZM11 6.4 8.7 8.7a1 1 0 0 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 1 1-1.4 1.4L13 6.4V16a1 1 0 0 1-2 0V6.4Z" fill-rule="nonzero"/></svg>',user:'<svg width="24" height="24"><path d="M12 24a12 12 0 1 1 0-24 12 12 0 0 1 0 24Zm-8.7-5.3a11 11 0 0 0 17.4 0C19.4 16.3 14.6 15 12 15c-2.6 0-7.4 1.3-8.7 3.7ZM12 13c2.2 0 4-2 4-4.5S14.2 4 12 4 8 6 8 8.5 9.8 13 12 13Z" fill-rule="nonzero"/></svg>',"vertical-align":'<svg width="24" height="24"><g fill-rule="nonzero"><rect width="18" height="2" x="3" y="11" rx="1"/><path d="M12 2c.6 0 1 .4 1 1v4l2-1.3a1 1 0 0 1 1.2 1.5l-.1.1-4.1 3-4-3a1 1 0 0 1 1-1.7l2 1.5V3c0-.6.4-1 1-1zm0 11.8 4 2.9a1 1 0 0 1-1 1.7l-2-1.5V21c0 .5-.4 1-.9 1H12a1 1 0 0 1-1-1v-4l-2 1.3a1 1 0 0 1-1.2-.1l-.1-.1a1 1 0 0 1 .1-1.3l.1-.1 4.1-3z"/></g></svg>',visualblocks:'<svg width="24" height="24"><path d="M9 19v2H7v-2h2Zm-4 0v2a2 2 0 0 1-2-2h2Zm8 0v2h-2v-2h2Zm8 0a2 2 0 0 1-2 2v-2h2Zm-4 0v2h-2v-2h2ZM15 7a1 1 0 0 1 0 2v7a1 1 0 0 1-2 0V9h-1v7a1 1 0 0 1-2 0v-4a2.5 2.5 0 0 1-.2-5H15ZM5 15v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 11v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 7v2H3V7h2Zm16 0v2h-2V7h2ZM5 3v2H3c0-1.1.9-2 2-2Zm8 0v2h-2V3h2Zm6 0a2 2 0 0 1 2 2h-2V3ZM9 3v2H7V3h2Zm8 0v2h-2V3h2Z" fill-rule="evenodd"/></svg>',visualchars:'<svg width="24" height="24"><path d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z" fill-rule="evenodd"/></svg>',warning:'<svg width="24" height="24"><path d="M19.8 18.3c.2.5.3.9 0 1.2-.1.3-.5.5-1 .5H5.2c-.5 0-.9-.2-1-.5-.3-.3-.2-.7 0-1.2L11 4.7l.5-.5.5-.2c.2 0 .3 0 .5.2.2 0 .3.3.5.5l6.8 13.6ZM12 18c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7c0 .3.1.5.3.7.2.2.4.3.7.3Zm.7-3 .3-4a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7l.3 4h1.4Z" fill-rule="evenodd"/></svg>',"zoom-in":'<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-1-9a1 1 0 0 1 2 0v6a1 1 0 0 1-2 0V8Zm-2 4a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>',"zoom-out":'<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>',"export-pdf":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3h7.4L19 7.6V17h-2V9h-4V5H7v3H5V5c0-1.1.9-2 2-2Z"/><path d="M2.6 15.2v-1.9h1c.6 0 1-.2 1.4-.5.3-.3.5-.7.5-1.2s-.2-.9-.5-1.2a2 2 0 0 0-1.3-.4H1v5.2h1.6Zm.4-3h-.4v-1.1h.5l.6.1.2.5c0 .1 0 .3-.2.4l-.7.1Zm5.7 3 1-.1c.3 0 .5-.2.7-.4l.5-.8c.2-.3.2-.7.2-1.3v-1l-.5-.8c-.2-.3-.4-.5-.7-.6L8.7 10H6.3v5.2h2.4Zm-.4-1.1H8v-3h.4c.5 0 .8.2 1 .4l.2 1.1-.1 1-.3.3-.8.2Zm5.3 1.2V13h2v-1h-2v-1H16V10h-4v5.2h1.6Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M15 17a1 1 0 1 0-2 0v3.1l-1.4-1a1 1 0 1 0-1.2 1.7l3.6 2.4 3.6-2.4a1 1 0 0 0-1.2-1.6l-1.4 1V17Z"/></svg>',"export-word":'<svg width="24" height="24"><path d="M9.5 7A1.5 1.5 0 0 1 11 8.4v7.1A1.5 1.5 0 0 1 9.6 17H2.5A1.5 1.5 0 0 1 1 15.6V8.5A1.5 1.5 0 0 1 2.4 7h7.1Zm-1 2.8-1 2.6-1-2.5v-.1a.6.6 0 0 0-1 0l-.1.1-.9 2.5-1-2.5v-.1a.6.6 0 0 0-1 .4v.1l1.5 4v.1a.6.6 0 0 0 1 0v-.1l1-2.5.9 2.5v.1a.6.6 0 0 0 1 0H8l1.6-4v-.2a.6.6 0 0 0-1.1-.4Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3h7.4L19 7.6V17h-2V9h-4V5H5c0-1.1.9-2 2-2ZM15 17a1 1 0 1 0-2 0v3.1l-1.4-1a1 1 0 1 0-1.2 1.7l3.6 2.4 3.6-2.4a1 1 0 0 0-1.2-1.6l-1.4 1V17Z"/></svg>',"import-word":'<svg width="24" height="24"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3h7.4L19 7.6V15h-2V9h-4V5H5c0-1.1.9-2 2-2Z"/><path d="M9.5 7A1.5 1.5 0 0 1 11 8.4v7.1A1.5 1.5 0 0 1 9.6 17H2.5A1.5 1.5 0 0 1 1 15.6V8.5A1.5 1.5 0 0 1 2.4 7h7.1Zm-1 2.8-1 2.6-1-2.5v-.1a.6.6 0 0 0-1 0l-.1.1-.9 2.5-1-2.5v-.1a.6.6 0 0 0-1 .4v.1l1.5 4v.1a.6.6 0 0 0 1 0v-.1l1-2.5.9 2.5v.1a.6.6 0 0 0 1 0H8l1.6-4v-.2a.6.6 0 0 0-1.1-.4Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M11.4 18.2a1 1 0 0 0 1.2 1.6l1.4-1V22a1 1 0 1 0 2 0v-3.1l1.4 1a1 1 0 0 0 1.2-1.7L15 15.8l-3.6 2.4Z"/></svg>'}});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/langs/README.md b/eims-ui/apps/web-antd/public/tinymce/langs/README.md
new file mode 100644
index 0000000..cd93d8c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/langs/README.md
@@ -0,0 +1,3 @@
+This is where language files should be placed.
+
+Please DO NOT translate these directly, use this service instead: https://crowdin.com/project/tinymce
diff --git a/eims-ui/apps/web-antd/public/tinymce/langs/zh_CN.js b/eims-ui/apps/web-antd/public/tinymce/langs/zh_CN.js
new file mode 100644
index 0000000..ff4b559
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/langs/zh_CN.js
@@ -0,0 +1 @@
+tinymce.addI18n("zh_CN",{"#":"#","Accessibility":"\u8f85\u52a9\u529f\u80fd","Accordion":"","Accordion body...":"","Accordion summary...":"","Action":"\u52a8\u4f5c","Activity":"\u6d3b\u52a8","Address":"\u5730\u5740","Advanced":"\u9ad8\u7ea7","Align":"\u5bf9\u9f50","Align center":"\u5c45\u4e2d\u5bf9\u9f50","Align left":"\u5de6\u5bf9\u9f50","Align right":"\u53f3\u5bf9\u9f50","Alignment":"\u5bf9\u9f50","Alignment {0}":"","All":"\u5168\u90e8","Alternative description":"\u66ff\u4ee3\u63cf\u8ff0","Alternative source":"\u955c\u50cf","Alternative source URL":"\u66ff\u4ee3\u6765\u6e90\u7f51\u5740","Anchor":"\u951a\u70b9","Anchor...":"\u951a\u70b9...","Anchors":"\u951a\u70b9","Animals and Nature":"\u52a8\u7269\u548c\u81ea\u7136","Arrows":"\u7bad\u5934","B":"B","Background color":"\u80cc\u666f\u989c\u8272","Background color {0}":"","Black":"\u9ed1\u8272","Block":"\u5757","Block {0}":"","Blockquote":"\u5f15\u6587\u533a\u5757","Blocks":"\u6837\u5f0f","Blue":"\u84dd\u8272","Blue component":"\u767d\u8272\u90e8\u5206","Body":"\u8868\u4f53","Bold":"\u7c97\u4f53","Border":"\u6846\u7ebf","Border color":"\u6846\u7ebf\u989c\u8272","Border style":"\u8fb9\u6846\u6837\u5f0f","Border width":"\u8fb9\u6846\u5bbd\u5ea6","Bottom":"\u4e0b\u65b9\u5bf9\u9f50","Browse files":"","Browse for an image":"\u6d4f\u89c8\u56fe\u50cf","Browse links":"","Bullet list":"\u65e0\u5e8f\u5217\u8868","Cancel":"\u53d6\u6d88","Caption":"\u6807\u9898","Cell":"\u5355\u5143\u683c","Cell padding":"\u5355\u5143\u683c\u5185\u8fb9\u8ddd","Cell properties":"\u5355\u5143\u683c\u5c5e\u6027","Cell spacing":"\u5355\u5143\u683c\u5916\u95f4\u8ddd","Cell styles":"\u5355\u5143\u683c\u6837\u5f0f","Cell type":"\u50a8\u5b58\u683c\u522b","Center":"\u5c45\u4e2d","Characters":"\u5b57\u7b26","Characters (no spaces)":"\u5b57\u7b26(\u65e0\u7a7a\u683c)","Circle":"\u7a7a\u5fc3\u5706","Class":"\u7c7b\u578b","Clear formatting":"\u6e05\u9664\u683c\u5f0f","Close":"\u5173\u95ed","Code":"\u4ee3\u7801","Code sample...":"\u793a\u4f8b\u4ee3\u7801...","Code view":"\u4ee3\u7801\u89c6\u56fe","Color Picker":"\u9009\u8272\u5668","Color swatch":"\u989c\u8272\u6837\u672c","Cols":"\u5217","Column":"\u5217","Column clipboard actions":"\u5217\u526a\u8d34\u677f\u64cd\u4f5c","Column group":"\u5217\u7ec4","Column header":"\u5217\u6807\u9898","Constrain proportions":"\u4fdd\u6301\u6bd4\u4f8b","Copy":"\u590d\u5236","Copy column":"\u590d\u5236\u5217","Copy row":"\u590d\u5236\u884c","Could not find the specified string.":"\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9\u3002","Could not load emojis":"\u65e0\u6cd5\u52a0\u8f7dEmojis","Count":"\u8ba1\u6570","Currency":"\u8d27\u5e01","Current window":"\u5f53\u524d\u7a97\u53e3","Custom color":"\u81ea\u5b9a\u4e49\u989c\u8272","Custom...":"\u81ea\u5b9a\u4e49......","Cut":"\u526a\u5207","Cut column":"\u526a\u5207\u5217","Cut row":"\u526a\u5207\u884c","Dark Blue":"\u6df1\u84dd\u8272","Dark Gray":"\u6df1\u7070\u8272","Dark Green":"\u6df1\u7eff\u8272","Dark Orange":"\u6df1\u6a59\u8272","Dark Purple":"\u6df1\u7d2b\u8272","Dark Red":"\u6df1\u7ea2\u8272","Dark Turquoise":"\u6df1\u84dd\u7eff\u8272","Dark Yellow":"\u6697\u9ec4\u8272","Dashed":"\u865a\u7ebf","Date/time":"\u65e5\u671f/\u65f6\u95f4","Decrease indent":"\u51cf\u5c11\u7f29\u8fdb","Default":"\u9884\u8bbe","Delete accordion":"","Delete column":"\u5220\u9664\u5217","Delete row":"\u5220\u9664\u884c","Delete table":"\u5220\u9664\u8868\u683c","Dimensions":"\u5c3a\u5bf8","Disc":"\u5b9e\u5fc3\u5706","Div":"Div","Document":"\u6587\u6863","Dotted":"\u865a\u7ebf","Double":"\u53cc\u7cbe\u5ea6","Drop an image here":"\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64","Dropped file type is not supported":"\u6b64\u6587\u4ef6\u7c7b\u578b\u4e0d\u652f\u6301\u62d6\u653e","Edit":"\u7f16\u8f91","Embed":"\u5185\u5d4c","Emojis":"Emojis","Emojis...":"Emojis...","Error":"\u9519\u8bef","Error: Form submit field collision.":"\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002","Error: No form element found.":"\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002","Extended Latin":"\u62c9\u4e01\u8bed\u6269\u5145","Failed to initialize plugin: {0}":"\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}","Failed to load plugin url: {0}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}","Failed to load plugin: {0} from url {1}":"\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}","Failed to upload image: {0}":"\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}","File":"\u6587\u4ef6","Find":"\u5bfb\u627e","Find (if searchreplace plugin activated)":"\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Find and Replace":"\u67e5\u627e\u548c\u66ff\u6362","Find and replace...":"\u67e5\u627e\u5e76\u66ff\u6362...","Find in selection":"\u5728\u9009\u533a\u4e2d\u67e5\u627e","Find whole words only":"\u5168\u5b57\u5339\u914d","Flags":"\u65d7\u5e1c","Focus to contextual toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355","Focus to element path":"\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84","Focus to menubar":"\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f","Focus to toolbar":"\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f","Font":"\u5b57\u4f53","Font size {0}":"","Font sizes":"\u5b57\u4f53\u5927\u5c0f","Font {0}":"","Fonts":"\u5b57\u4f53","Food and Drink":"\u98df\u7269\u548c\u996e\u54c1","Footer":"\u8868\u5c3e","Format":"\u683c\u5f0f","Format {0}":"","Formats":"\u683c\u5f0f","Fullscreen":"\u5168\u5c4f","G":"G","General":"\u4e00\u822c","Gray":"\u7070\u8272","Green":"\u7eff\u8272","Green component":"\u7eff\u8272\u90e8\u5206","Groove":"\u51f9\u69fd","Handy Shortcuts":"\u5feb\u6377\u952e","Header":"\u8868\u5934","Header cell":"\u8868\u5934\u5355\u5143\u683c","Heading 1":"\u4e00\u7ea7\u6807\u9898","Heading 2":"\u4e8c\u7ea7\u6807\u9898","Heading 3":"\u4e09\u7ea7\u6807\u9898","Heading 4":"\u56db\u7ea7\u6807\u9898","Heading 5":"\u4e94\u7ea7\u6807\u9898","Heading 6":"\u516d\u7ea7\u6807\u9898","Headings":"\u6807\u9898","Height":"\u9ad8\u5ea6","Help":"\u5e2e\u52a9","Hex color code":"\u5341\u516d\u8fdb\u5236\u989c\u8272\u4ee3\u7801","Hidden":"\u9690\u85cf","Horizontal align":"\u6c34\u5e73\u5bf9\u9f50","Horizontal line":"\u6c34\u5e73\u5206\u5272\u7ebf","Horizontal space":"\u6c34\u5e73\u95f4\u8ddd","ID":"ID","ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.":"ID\u5e94\u8be5\u4ee5\u82f1\u6587\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u53ea\u80fd\u6709\u82f1\u6587\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002","Image is decorative":"\u56fe\u50cf\u662f\u88c5\u9970\u6027\u7684","Image list":"\u56fe\u7247\u6e05\u5355","Image title":"\u56fe\u7247\u6807\u9898","Image...":"\u56fe\u7247...","ImageProxy HTTP error: Could not find Image Proxy":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u65e0\u6cd5\u627e\u5230\u56fe\u7247\u4ee3\u7406","ImageProxy HTTP error: Incorrect Image Proxy URL":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u56fe\u7247\u4ee3\u7406\u5730\u5740\u9519\u8bef","ImageProxy HTTP error: Rejected request":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u8bf7\u6c42\u88ab\u62d2\u7edd","ImageProxy HTTP error: Unknown ImageProxy error":"\u56fe\u7247\u4ee3\u7406\u8bf7\u6c42\u9519\u8bef\uff1a\u672a\u77e5\u7684\u56fe\u7247\u4ee3\u7406\u9519\u8bef","Increase indent":"\u589e\u52a0\u7f29\u8fdb","Inline":"\u6587\u672c","Insert":"\u63d2\u5165","Insert Template":"\u63d2\u5165\u6a21\u677f","Insert accordion":"","Insert column after":"\u5728\u53f3\u4fa7\u63d2\u5165\u5217","Insert column before":"\u5728\u5de6\u4fa7\u63d2\u5165\u5217","Insert date/time":"\u63d2\u5165\u65e5\u671f/\u65f6\u95f4","Insert image":"\u63d2\u5165\u56fe\u7247","Insert link (if link plugin activated)":"\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Insert row after":"\u5728\u4e0b\u65b9\u63d2\u5165\u884c","Insert row before":"\u5728\u4e0a\u65b9\u63d2\u5165\u884c","Insert table":"\u63d2\u5165\u8868\u683c","Insert template...":"\u63d2\u5165\u6a21\u677f...","Insert video":"\u63d2\u5165\u89c6\u9891","Insert/Edit code sample":"\u63d2\u5165/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b","Insert/edit image":"\u63d2\u5165/\u7f16\u8f91\u56fe\u7247","Insert/edit link":"\u63d2\u5165/\u7f16\u8f91\u94fe\u63a5","Insert/edit media":"\u63d2\u5165/\u7f16\u8f91\u5a92\u4f53","Insert/edit video":"\u63d2\u5165/\u7f16\u8f91\u89c6\u9891","Inset":"\u5d4c\u5165","Invalid hex color code: {0}":"\u5341\u516d\u8fdb\u5236\u989c\u8272\u4ee3\u7801\u65e0\u6548\uff1a {0}","Invalid input":"\u65e0\u6548\u8f93\u5165","Italic":"\u659c\u4f53","Justify":"\u4e24\u7aef\u5bf9\u9f50","Keyboard Navigation":"\u952e\u76d8\u6307\u5f15","Language":"\u8bed\u8a00","Learn more...":"\u4e86\u89e3\u66f4\u591a...","Left":"\u5de6","Left to right":"\u7531\u5de6\u5230\u53f3","Light Blue":"\u6d45\u84dd\u8272","Light Gray":"\u6d45\u7070\u8272","Light Green":"\u6d45\u7eff\u8272","Light Purple":"\u6d45\u7d2b\u8272","Light Red":"\u6d45\u7ea2\u8272","Light Yellow":"\u6d45\u9ec4\u8272","Line height":"\u884c\u9ad8","Link list":"\u94fe\u63a5\u6e05\u5355","Link...":"\u94fe\u63a5...","List Properties":"\u5217\u8868\u5c5e\u6027","List properties...":"\u6807\u9898\u5b57\u4f53\u5c5e\u6027","Loading emojis...":"\u6b63\u5728\u52a0\u8f7dEmojis...","Loading...":"\u52a0\u8f7d\u4e2d...","Lower Alpha":"\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd","Lower Greek":"\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd","Lower Roman":"\u5c0f\u5199\u7f57\u9a6c\u6570\u5b57","Match case":"\u5927\u5c0f\u5199\u5339\u914d","Mathematical":"\u6570\u5b66","Media poster (Image URL)":"\u5c01\u9762(\u56fe\u7247\u5730\u5740)","Media...":"\u591a\u5a92\u4f53...","Medium Blue":"\u4e2d\u84dd\u8272","Medium Gray":"\u4e2d\u7070\u8272","Medium Purple":"\u4e2d\u7d2b\u8272","Merge cells":"\u5408\u5e76\u5355\u5143\u683c","Middle":"\u5c45\u4e2d\u5bf9\u9f50","Midnight Blue":"\u6df1\u84dd\u8272","More...":"\u66f4\u591a...","Name":"\u540d\u79f0","Navy Blue":"\u6d77\u519b\u84dd","New document":"\u65b0\u5efa\u6587\u6863","New window":"\u65b0\u7a97\u53e3","Next":"\u4e0b\u4e00\u4e2a","No":"\u5426","No alignment":"\u672a\u5bf9\u9f50","No color":"\u65e0","Nonbreaking space":"\u4e0d\u95f4\u65ad\u7a7a\u683c","None":"\u65e0","Numbered list":"\u6709\u5e8f\u5217\u8868","OR":"\u6216","Objects":"\u7269\u4ef6","Ok":"\u786e\u5b9a","Open help dialog":"\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846","Open link":"\u6253\u5f00\u94fe\u63a5","Open link in...":"\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...","Open popup menu for split buttons":"\u6253\u5f00\u5f39\u51fa\u5f0f\u83dc\u5355\uff0c\u7528\u4e8e\u62c6\u5206\u6309\u94ae","Orange":"\u6a59\u8272","Outset":"\u5916\u7f6e","Page break":"\u5206\u9875\u7b26","Paragraph":"\u6bb5\u843d","Paste":"\u7c98\u8d34","Paste as text":"\u7c98\u8d34\u4e3a\u6587\u672c","Paste column after":"\u7c98\u8d34\u540e\u9762\u7684\u5217","Paste column before":"\u7c98\u8d34\u6b64\u5217\u524d","Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.":"\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002","Paste or type a link":"\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5","Paste row after":"\u7c98\u8d34\u884c\u5230\u4e0b\u65b9","Paste row before":"\u7c98\u8d34\u884c\u5230\u4e0a\u65b9","Paste your embed code below:":"\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:","People":"\u4eba\u7c7b","Plugins":"\u63d2\u4ef6","Plugins installed ({0}):":"\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):","Powered by {0}":"\u7531{0}\u9a71\u52a8","Pre":"\u524d\u8a00","Preferences":"\u9996\u9009\u9879","Preformatted":"\u9884\u5148\u683c\u5f0f\u5316\u7684","Premium plugins:":"\u4f18\u79c0\u63d2\u4ef6\uff1a","Press the Up and Down arrow keys to resize the editor.":"","Press the arrow keys to resize the editor.":"","Press {0} for help":"","Preview":"\u9884\u89c8","Previous":"\u4e0a\u4e00\u4e2a","Print":"\u6253\u5370","Print...":"\u6253\u5370...","Purple":"\u7d2b\u8272","Quotations":"\u5f15\u7528","R":"R","Range 0 to 255":"\u8303\u56f40\u81f3255","Red":"\u7ea2\u8272","Red component":"\u7ea2\u8272\u90e8\u5206","Redo":"\u91cd\u505a","Remove":"\u79fb\u9664","Remove color":"\u79fb\u9664\u989c\u8272","Remove link":"\u79fb\u9664\u94fe\u63a5","Replace":"\u66ff\u6362","Replace all":"\u66ff\u6362\u5168\u90e8","Replace with":"\u66ff\u6362\u4e3a","Resize":"\u8c03\u6574\u5927\u5c0f","Restore last draft":"\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f","Reveal or hide additional toolbar items":"","Rich Text Area":"\u5bcc\u6587\u672c\u533a\u57df","Rich Text Area. Press ALT-0 for help.":"\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002","Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help":"\u7f16\u8f91\u533a\u3002\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9","Ridge":"\u6d77\u810a\u5ea7","Right":"\u53f3","Right to left":"\u7531\u53f3\u5230\u5de6","Row":"\u884c","Row clipboard actions":"\u884c\u526a\u8d34\u677f\u64cd\u4f5c","Row group":"\u884c\u7ec4","Row header":"\u884c\u5934","Row properties":"\u884c\u5c5e\u6027","Row type":"\u884c\u7c7b\u578b","Rows":"\u884c\u6570","Save":"\u4fdd\u5b58","Save (if save plugin activated)":"\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)","Scope":"\u8303\u56f4","Search":"\u641c\u7d22","Select all":"\u5168\u9009","Select...":"\u9009\u62e9...","Selection":"\u9009\u62e9","Shortcut":"\u5feb\u6377\u65b9\u5f0f","Show blocks":"\u663e\u793a\u533a\u5757\u8fb9\u6846","Show caption":"\u663e\u793a\u6807\u9898","Show invisible characters":"\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26","Size":"\u5b57\u53f7","Solid":"\u5b9e\u7ebf","Source":"\u6e90","Source code":"\u6e90\u4ee3\u7801","Special Character":"\u7279\u6b8a\u5b57\u7b26","Special character...":"\u7279\u6b8a\u5b57\u7b26...","Split cell":"\u62c6\u5206\u5355\u5143\u683c","Square":"\u5b9e\u5fc3\u65b9\u5757","Start list at number":"\u4ee5\u6570\u5b57\u5f00\u59cb\u5217\u8868","Strikethrough":"\u5220\u9664\u7ebf","Style":"\u6837\u5f0f","Subscript":"\u4e0b\u6807","Superscript":"\u4e0a\u6807","Switch to or from fullscreen mode":"\u5207\u6362\u5168\u5c4f\u6a21\u5f0f","Symbols":"\u7b26\u53f7","System Font":"\u7cfb\u7edf\u5b57\u4f53","Table":"\u8868\u683c","Table caption":"\u8868\u683c\u6807\u9898","Table properties":"\u8868\u683c\u5c5e\u6027","Table styles":"\u8868\u683c\u6837\u5f0f","Template":"\u6a21\u677f","Templates":"\u6a21\u677f","Text":"\u6587\u5b57","Text color":"\u6587\u672c\u989c\u8272","Text color {0}":"","Text to display":"\u8981\u663e\u793a\u7684\u6587\u672c","The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto: \u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required http:// prefix?":"\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:// \u524d\u7f00\u5417\uff1f","The URL you entered seems to be an external link. Do you want to add the required https:// prefix?":"\u60a8\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\u3002\u60a8\u60f3\u6dfb\u52a0\u6240\u9700\u7684 https:// \u524d\u7f00\u5417\uff1f","Title":"\u6807\u9898","To open the popup, press Shift+Enter":"\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846","Toggle accordion":"","Tools":"\u5de5\u5177","Top":"\u4e0a\u65b9\u5bf9\u9f50","Travel and Places":"\u65c5\u6e38\u548c\u5730\u70b9","Turquoise":"\u9752\u7eff\u8272","Underline":"\u4e0b\u5212\u7ebf","Undo":"\u64a4\u9500","Upload":"\u4e0a\u4f20","Uploading image":"\u4e0a\u4f20\u56fe\u7247","Upper Alpha":"\u5927\u5199\u82f1\u6587\u5b57\u6bcd","Upper Roman":"\u5927\u5199\u7f57\u9a6c\u6570\u5b57","Url":"\u5730\u5740","User Defined":"\u81ea\u5b9a\u4e49","Valid":"\u6709\u6548","Version":"\u7248\u672c","Vertical align":"\u5782\u76f4\u5bf9\u9f50","Vertical space":"\u5782\u76f4\u95f4\u8ddd","View":"\u67e5\u770b","Visual aids":"\u7f51\u683c\u7ebf","Warn":"\u8b66\u544a","White":"\u767d\u8272","Width":"\u5bbd\u5ea6","Word count":"\u5b57\u6570","Words":"\u5355\u8bcd","Words: {0}":"\u5b57\u6570\uff1a{0}","Yellow":"\u9ec4\u8272","Yes":"\u662f","You are using {0}":"\u4f60\u6b63\u5728\u4f7f\u7528 {0}","You have unsaved changes are you sure you want to navigate away?":"\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f","Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":"\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X/C/V\u7b49\u5feb\u6377\u952e\u3002","alignment":"\u5bf9\u9f50","austral sign":"\u6fb3\u5143\u7b26\u53f7","cedi sign":"\u585e\u5730\u7b26\u53f7","colon sign":"\u5192\u53f7","cruzeiro sign":"\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7","currency sign":"\u8d27\u5e01\u7b26\u53f7","dollar sign":"\u7f8e\u5143\u7b26\u53f7","dong sign":"\u8d8a\u5357\u76fe\u7b26\u53f7","drachma sign":"\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7","euro-currency sign":"\u6b27\u5143\u7b26\u53f7","example":"\u793a\u4f8b","formatting":"\u683c\u5f0f\u5316","french franc sign":"\u6cd5\u90ce\u7b26\u53f7","german penny symbol":"\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7","guarani sign":"\u74dc\u62c9\u5c3c\u7b26\u53f7","history":"\u5386\u53f2","hryvnia sign":"\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7","indentation":"\u7f29\u8fdb","indian rupee sign":"\u5370\u5ea6\u5362\u6bd4","kip sign":"\u8001\u631d\u57fa\u666e\u7b26\u53f7","lira sign":"\u91cc\u62c9\u7b26\u53f7","livre tournois sign":"\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7","manat sign":"\u9a6c\u7eb3\u7279\u7b26\u53f7","mill sign":"\u5bc6\u5c14\u7b26\u53f7","naira sign":"\u5948\u62c9\u7b26\u53f7","new sheqel sign":"\u65b0\u8c22\u514b\u5c14\u7b26\u53f7","nordic mark sign":"\u5317\u6b27\u9a6c\u514b","peseta sign":"\u6bd4\u585e\u5854\u7b26\u53f7","peso sign":"\u6bd4\u7d22\u7b26\u53f7","ruble sign":"\u5362\u5e03\u7b26\u53f7","rupee sign":"\u5362\u6bd4\u7b26\u53f7","spesmilo sign":"spesmilo\u7b26\u53f7","styles":"\u6837\u5f0f","tenge sign":"\u575a\u6208\u7b26\u53f7","tugrik sign":"\u56fe\u683c\u91cc\u514b\u7b26\u53f7","turkish lira sign":"\u571f\u8033\u5176\u91cc\u62c9","won sign":"\u97e9\u5143\u7b26\u53f7","yen character":"\u65e5\u5143\u5b57\u6837","yen/yuan character variant one":"\u5143\u5b57\u6837\uff08\u5927\u5199\uff09","yuan character":"\u4eba\u6c11\u5e01\u5143\u5b57\u6837","yuan character, in hong kong and taiwan":"\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09","{0} characters":"{0} \u4e2a\u5b57\u7b26","{0} columns, {1} rows":"","{0} words":"{0} \u5b57"});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/license.md b/eims-ui/apps/web-antd/public/tinymce/license.md
new file mode 100644
index 0000000..70454a6
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/license.md
@@ -0,0 +1,6 @@
+# Software License Agreement
+
+**TinyMCE** 鈥� [<https://github.com/tinymce/tinymce>](https://github.com/tinymce/tinymce)
+Copyright (c) 2024, Ephox Corporation DBA Tiny Technologies, Inc.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
diff --git a/eims-ui/apps/web-antd/public/tinymce/models/dom/model.min.js b/eims-ui/apps/web-antd/public/tinymce/models/dom/model.min.js
new file mode 100644
index 0000000..718c585
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/models/dom/model.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.ModelManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(t)===e,o=e=>t=>typeof t===e,n=e=>t=>e===t,r=t("string"),s=t("object"),l=t("array"),a=n(null),c=o("boolean"),i=n(void 0),m=e=>!(e=>null==e)(e),d=o("function"),u=o("number"),f=()=>{},g=e=>()=>e,h=e=>e,p=(e,t)=>e===t;function b(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const w=e=>t=>!e(t),v=e=>e(),y=g(!1),x=g(!0);class C{constructor(e,t){this.tag=e,this.value=t}static some(e){return new C(!0,e)}static none(){return C.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?C.some(e(this.value)):C.none()}bind(e){return this.tag?e(this.value):C.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:C.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return m(e)?C.some(e):C.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}C.singletonNone=new C(!1);const S=Array.prototype.slice,T=Array.prototype.indexOf,R=Array.prototype.push,D=(e,t)=>{return o=e,n=t,T.call(o,n)>-1;var o,n},O=(e,t)=>{for(let o=0,n=e.length;o<n;o++)if(t(e[o],o))return!0;return!1},k=(e,t)=>{const o=[];for(let n=0;n<e;n++)o.push(t(n));return o},E=(e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r<o;r++){const o=e[r];n[r]=t(o,r)}return n},N=(e,t)=>{for(let o=0,n=e.length;o<n;o++)t(e[o],o)},B=(e,t)=>{const o=[],n=[];for(let r=0,s=e.length;r<s;r++){const s=e[r];(t(s,r)?o:n).push(s)}return{pass:o,fail:n}},_=(e,t)=>{const o=[];for(let n=0,r=e.length;n<r;n++){const r=e[n];t(r,n)&&o.push(r)}return o},z=(e,t,o)=>(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),A=(e,t,o)=>(N(e,((e,n)=>{o=t(o,e,n)})),o),L=(e,t)=>((e,t,o)=>{for(let n=0,r=e.length;n<r;n++){const r=e[n];if(t(r,n))return C.some(r);if(o(r,n))break}return C.none()})(e,t,y),W=(e,t)=>{for(let o=0,n=e.length;o<n;o++)if(t(e[o],o))return C.some(o);return C.none()},M=e=>{const t=[];for(let o=0,n=e.length;o<n;++o){if(!l(e[o]))throw new Error("Arr.flatten item "+o+" was not an array, input: "+e);R.apply(t,e[o])}return t},j=(e,t)=>M(E(e,t)),P=(e,t)=>{for(let o=0,n=e.length;o<n;++o)if(!0!==t(e[o],o))return!1;return!0},I=(e,t)=>{const o={};for(let n=0,r=e.length;n<r;n++){const r=e[n];o[String(r)]=t(r,n)}return o},F=(e,t)=>t>=0&&t<e.length?C.some(e[t]):C.none(),H=e=>F(e,0),$=e=>F(e,e.length-1),V=(e,t)=>{for(let o=0;o<e.length;o++){const n=t(e[o],o);if(n.isSome())return n}return C.none()},q=Object.keys,U=Object.hasOwnProperty,G=(e,t)=>{const o=q(e);for(let n=0,r=o.length;n<r;n++){const r=o[n];t(e[r],r)}},K=(e,t)=>Y(e,((e,o)=>({k:o,v:t(e,o)}))),Y=(e,t)=>{const o={};return G(e,((e,n)=>{const r=t(e,n);o[r.k]=r.v})),o},J=(e,t)=>{const o=[];return G(e,((e,n)=>{o.push(t(e,n))})),o},Q=e=>J(e,h),X=(e,t)=>U.call(e,t),Z="undefined"!=typeof window?window:Function("return this;")(),ee=(e,t)=>((e,t)=>{let o=null!=t?t:Z;for(let t=0;t<e.length&&null!=o;++t)o=o[e[t]];return o})(e.split("."),t),te=Object.getPrototypeOf,oe=e=>{const t=ee("ownerDocument.defaultView",e);return s(e)&&((e=>((e,t)=>{const o=((e,t)=>ee(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(te(e).constructor.name))},ne=e=>e.dom.nodeName.toLowerCase(),re=e=>e.dom.nodeType,se=e=>t=>re(t)===e,le=e=>8===re(e)||"#comment"===ne(e),ae=e=>ce(e)&&oe(e.dom),ce=se(1),ie=se(3),me=se(9),de=se(11),ue=e=>t=>ce(t)&&ne(t)===e,fe=(e,t,o)=>{if(!(r(o)||c(o)||u(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},ge=(e,t,o)=>{fe(e.dom,t,o)},he=(e,t)=>{const o=e.dom;G(t,((e,t)=>{fe(o,t,e)}))},pe=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},be=(e,t)=>C.from(pe(e,t)),we=(e,t)=>{e.dom.removeAttribute(t)},ve=e=>A(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),ye=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},xe={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return ye(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return ye(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return ye(o)},fromDom:ye,fromPoint:(e,t,o)=>C.from(e.dom.elementFromPoint(t,o)).map(ye)},Ce=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Se=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Te=(e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?C.none():C.from(o.querySelector(e)).map(xe.fromDom)},Re=(e,t)=>e.dom===t.dom,De=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},Oe=Ce,ke=e=>xe.fromDom(e.dom.ownerDocument),Ee=e=>me(e)?e:ke(e),Ne=e=>C.from(e.dom.parentNode).map(xe.fromDom),Be=e=>C.from(e.dom.parentElement).map(xe.fromDom),_e=(e,t)=>{const o=d(t)?t:y;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=xe.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r},ze=e=>C.from(e.dom.previousSibling).map(xe.fromDom),Ae=e=>C.from(e.dom.nextSibling).map(xe.fromDom),Le=e=>E(e.dom.childNodes,xe.fromDom),We=(e,t)=>{const o=e.dom.childNodes;return C.from(o[t]).map(xe.fromDom)},Me=(e,t)=>{Ne(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},je=(e,t)=>{Ae(e).fold((()=>{Ne(e).each((e=>{Ie(e,t)}))}),(e=>{Me(e,t)}))},Pe=(e,t)=>{const o=(e=>We(e,0))(e);o.fold((()=>{Ie(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Ie=(e,t)=>{e.dom.appendChild(t.dom)},Fe=(e,t)=>{Me(e,t),Ie(t,e)},He=(e,t)=>{N(t,((o,n)=>{const r=0===n?e:t[n-1];je(r,o)}))},$e=(e,t)=>{N(t,(t=>{Ie(e,t)}))},Ve=e=>{e.dom.textContent="",N(Le(e),(e=>{qe(e)}))},qe=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Ue=e=>{const t=Le(e);t.length>0&&He(e,t),qe(e)},Ge=(e,t)=>xe.fromDom(e.dom.cloneNode(t)),Ke=e=>Ge(e,!1),Ye=e=>Ge(e,!0),Je=(e,t)=>{const o=xe.fromTag(t),n=ve(e);return he(o,n),o},Qe=["tfoot","thead","tbody","colgroup"],Xe=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ze=(e,t,o)=>({element:e,cells:t,section:o}),et=(e,t,o)=>({element:e,isNew:t,isLocked:o}),tt=(e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}),ot=d(Element.prototype.attachShadow)&&d(Node.prototype.getRootNode),nt=g(ot),rt=ot?e=>xe.fromDom(e.dom.getRootNode()):Ee,st=e=>xe.fromDom(e.dom.host),lt=e=>{const t=ie(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=rt(e);return de(o=t)&&m(o.dom.host)?C.some(t):C.none();var o})(xe.fromDom(t)).fold((()=>o.body.contains(t)),(n=lt,r=st,e=>n(r(e))));var n,r},at=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return xe.fromDom(t)},ct=(e,t)=>{let o=[];return N(Le(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(ct(e,t))})),o},it=(e,t,o)=>((e,o,n)=>_(_e(e,n),(e=>Ce(e,t))))(e,0,o),mt=(e,t)=>((e,o)=>_(Le(e),(e=>Ce(e,t))))(e),dt=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Se(o)?[]:E(o.querySelectorAll(e),xe.fromDom)})(t,e);var ut=(e,t,o,n,r)=>e(o,n)?C.some(o):d(r)&&r(o)?C.none():t(o,n,r);const ft=(e,t,o)=>{let n=e.dom;const r=d(o)?o:y;for(;n.parentNode;){n=n.parentNode;const e=xe.fromDom(n);if(t(e))return C.some(e);if(r(e))break}return C.none()},gt=(e,t,o)=>ut(((e,t)=>t(e)),ft,e,t,o),ht=(e,t,o)=>ft(e,(e=>Ce(e,t)),o),pt=(e,t)=>((e,o)=>L(e.dom.childNodes,(e=>{return o=xe.fromDom(e),Ce(o,t);var o})).map(xe.fromDom))(e),bt=(e,t)=>Te(t,e),wt=(e,t,o)=>ut(((e,t)=>Ce(e,t)),ht,e,t,o),vt=(e,t,o=p)=>e.exists((e=>o(e,t))),yt=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(o);return t},xt=(e,t)=>e?C.some(t):C.none(),Ct=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,St=(e,t,o=0,n)=>{const r=e.indexOf(t,o);return-1!==r&&(!!i(n)||r+t.length<=n)},Tt=(e,t)=>Ct(e,t,0),Rt=(e,t)=>Ct(e,t,e.length-t.length),Dt=(e=>t=>t.replace(e,""))(/^\s+|\s+$/g),Ot=e=>e.length>0,kt=e=>void 0!==e.style&&d(e.style.getPropertyValue),Et=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);kt(e)&&e.style.setProperty(t,o)},Nt=(e,t,o)=>{const n=e.dom;Et(n,t,o)},Bt=(e,t)=>{const o=e.dom;G(t,((e,t)=>{Et(o,t,e)}))},_t=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||lt(e)?n:zt(o,t)},zt=(e,t)=>kt(e)?e.style.getPropertyValue(t):"",At=(e,t)=>{const o=e.dom,n=zt(o,t);return C.from(n).filter((e=>e.length>0))},Lt=(e,t)=>{((e,t)=>{kt(e)&&e.style.removeProperty(t)})(e.dom,t),vt(be(e,"style").map(Dt),"")&&we(e,"style")},Wt=(e,t,o=0)=>be(e,t).map((e=>parseInt(e,10))).getOr(o),Mt=(e,t)=>Wt(e,t,1),jt=e=>ue("col")(e)?Wt(e,"span",1)>1:Mt(e,"colspan")>1,Pt=(e,t)=>parseInt(_t(e,t),10),It=g(10),Ft=g(10),Ht=(e,t)=>$t(e,t,x),$t=(e,t,o)=>j(Le(e),(e=>Ce(e,t)?o(e)?[e]:[]:$t(e,t,o))),Vt=(e,t)=>((e,t,o=y)=>o(t)?C.none():D(e,ne(t))?C.some(t):ht(t,e.join(","),(e=>Ce(e,"table")||o(e))))(["td","th"],e,t),qt=e=>Ht(e,"th,td"),Ut=e=>Ce(e,"colgroup")?mt(e,"col"):j(Yt(e),(e=>mt(e,"col"))),Gt=(e,t)=>wt(e,"table",t),Kt=e=>Ht(e,"tr"),Yt=e=>Gt(e).fold(g([]),(e=>mt(e,"colgroup"))),Jt=(e,t)=>E(e,(e=>{if("colgroup"===ne(e)){const t=E(Ut(e),(e=>{const t=Wt(e,"span",1);return Xe(e,1,t)}));return Ze(e,t,"colgroup")}{const o=E(qt(e),(e=>{const t=Wt(e,"rowspan",1),o=Wt(e,"colspan",1);return Xe(e,t,o)}));return Ze(e,o,t(e))}})),Qt=e=>Ne(e).map((e=>{const t=ne(e);return(e=>D(Qe,e))(t)?t:"tbody"})).getOr("tbody"),Xt=e=>{const t=Kt(e),o=[...Yt(e),...t];return Jt(o,Qt)},Zt=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},eo=()=>to(0,0),to=(e,t)=>({major:e,minor:t}),oo={nu:to,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?eo():((e,t)=>{const o=((e,t)=>{for(let o=0;o<e.length;o++){const n=e[o];if(n.test(t))return n}})(e,t);if(!o)return{major:0,minor:0};const n=e=>Number(t.replace(o,"$"+e));return to(n(1),n(2))})(e,o)},unknown:eo},no=(e,t)=>{const o=String(t).toLowerCase();return L(e,(e=>e.search(o)))},ro=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,so=e=>t=>St(t,e),lo=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>St(e,"edge/")&&St(e,"chrome")&&St(e,"safari")&&St(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,ro],search:e=>St(e,"chrome")&&!St(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>St(e,"msie")||St(e,"trident")},{name:"Opera",versionRegexes:[ro,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:so("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:so("firefox")},{name:"Safari",versionRegexes:[ro,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(St(e,"safari")||St(e,"mobile/"))&&St(e,"applewebkit")}],ao=[{name:"Windows",search:so("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>St(e,"iphone")||St(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:so("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:so("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:so("linux"),versionRegexes:[]},{name:"Solaris",search:so("sunos"),versionRegexes:[]},{name:"FreeBSD",search:so("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:so("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],co={browsers:g(lo),oses:g(ao)},io="Edge",mo="Chromium",uo="Opera",fo="Firefox",go="Safari",ho=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(io),isChromium:n(mo),isIE:n("IE"),isOpera:n(uo),isFirefox:n(fo),isSafari:n(go)}},po=()=>ho({current:void 0,version:oo.unknown()}),bo=ho,wo=(g(io),g(mo),g("IE"),g(uo),g(fo),g(go),"Windows"),vo="Android",yo="Linux",xo="macOS",Co="Solaris",So="FreeBSD",To="ChromeOS",Ro=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(wo),isiOS:n("iOS"),isAndroid:n(vo),isMacOS:n(xo),isLinux:n(yo),isSolaris:n(Co),isFreeBSD:n(So),isChromeOS:n(To)}},Do=()=>Ro({current:void 0,version:oo.unknown()}),Oo=Ro,ko=(g(wo),g("iOS"),g(vo),g(yo),g(xo),g(Co),g(So),g(To),e=>window.matchMedia(e).matches);let Eo=Zt((()=>((e,t,o)=>{const n=co.browsers(),r=co.oses(),s=t.bind((e=>((e,t)=>V(t.brands,(t=>{const o=t.brand.toLowerCase();return L(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:oo.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>no(e,t).map((e=>{const o=oo.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(po,bo),l=((e,t)=>no(e,t).map((e=>{const o=oo.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(r,e).fold(Do,Oo),a=((e,t,o,n)=>{const r=e.isiOS()&&!0===/ipad/i.test(o),s=e.isiOS()&&!r,l=e.isiOS()||e.isAndroid(),a=l||n("(pointer:coarse)"),c=r||!s&&l&&n("(min-device-width:768px)"),i=s||l&&!c,m=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),d=!i&&!c&&!m;return{isiPad:g(r),isiPhone:g(s),isTablet:g(c),isPhone:g(i),isTouch:g(a),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:g(m),isDesktop:g(d)}})(l,s,e,o);return{browser:s,os:l,deviceType:a}})(navigator.userAgent,C.from(navigator.userAgentData),ko)));const No=()=>Eo(),Bo=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=_t(o,e);return parseFloat(t)||0}return n},n=(e,t)=>A(t,((t,o)=>{const n=_t(e,o),r=void 0===n?0:parseInt(n,10);return isNaN(r)?t:t+r}),0);return{set:(t,o)=>{if(!u(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;kt(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const r=n(e,o);return t>r?t-r:0}}},_o=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?C.none():C.some(t)})(e).getOr(t))(_t(e,t),o),zo=Bo("width",(e=>e.dom.offsetWidth)),Ao=e=>zo.get(e),Lo=e=>zo.getOuter(e),Wo=e=>((e,t)=>{const o=e.dom,n=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?n:((e,t,o,n)=>t-_o(e,`padding-${o}`,0)-_o(e,`padding-${n}`,0)-_o(e,`border-${o}-width`,0)-_o(e,`border-${n}-width`,0))(e,n,"left","right")})(e,"content-box"),Mo=(e,t,o)=>{const n=e.cells,r=n.slice(0,t),s=n.slice(t),l=r.concat(o).concat(s);return Io(e,l)},jo=(e,t,o)=>Mo(e,t,[o]),Po=(e,t,o)=>{e.cells[t]=o},Io=(e,t)=>tt(e.element,t,e.section,e.isNew),Fo=(e,t)=>e.cells[t],Ho=(e,t)=>Fo(e,t).element,$o=e=>e.cells.length,Vo=e=>{const t=B(e,(e=>"colgroup"===e.section));return{rows:t.fail,cols:t.pass}},qo=(e,t,o)=>{const n=E(e.cells,o);return tt(t(e.element),n,e.section,!0)},Uo="data-snooker-locked-cols",Go=e=>be(e,Uo).bind((e=>C.from(e.match(/\d+/g)))).map((e=>I(e,x))),Ko=e=>{const t=A(Vo(e).rows,((e,t)=>(N(t.cells,((t,o)=>{t.isLocked&&(e[o]=!0)})),e)),{}),o=J(t,((e,t)=>parseInt(t,10)));return((e,t)=>{const o=S.call(e,0);return o.sort(void 0),o})(o)},Yo=(e,t)=>e+","+t,Jo=(e,t)=>{const o=j(e.all,(e=>e.cells));return _(o,t)},Qo=e=>{const t={},o=[],n=H(e).map((e=>e.element)).bind(Gt).bind(Go).getOr({});let r=0,s=0,l=0;const{pass:a,fail:c}=B(e,(e=>"colgroup"===e.section));N(c,(e=>{const a=[];N(e.cells,(e=>{let o=0;for(;void 0!==t[Yo(l,o)];)o++;const r=((e,t)=>X(e,t)&&void 0!==e[t]&&null!==e[t])(n,o.toString()),c=((e,t,o,n,r,s)=>({element:e,rowspan:t,colspan:o,row:n,column:r,isLocked:s}))(e.element,e.rowspan,e.colspan,l,o,r);for(let n=0;n<e.colspan;n++)for(let r=0;r<e.rowspan;r++){const e=o+n,a=Yo(l+r,e);t[a]=c,s=Math.max(s,e+1)}a.push(c)})),r++,o.push(Ze(e.element,a,e.section)),l++}));const{columns:i,colgroups:m}=$(a).map((e=>{const t=(e=>{const t={};let o=0;return N(e.cells,(e=>{const n=e.colspan;k(n,(r=>{const s=o+r;t[s]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,n,s)})),o+=n})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,Q(t));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),d=((e,t)=>({rows:e,columns:t}))(r,s);return{grid:d,access:t,all:o,columns:i,colgroups:m}},Xo=e=>{const t=Xt(e);return Qo(t)},Zo=Qo,en=(e,t,o)=>C.from(e.access[Yo(t,o)]),tn=(e,t,o)=>{const n=Jo(e,(e=>o(t,e.element)));return n.length>0?C.some(n[0]):C.none()},on=Jo,nn=e=>j(e.all,(e=>e.cells)),rn=e=>Q(e.columns),sn=e=>q(e.columns).length>0,ln=(e,t)=>C.from(e.columns[t]),an=(e,t=x)=>{const o=e.grid,n=k(o.columns,h),r=k(o.rows,h);return E(n,(o=>cn((()=>j(r,(t=>en(e,t,o).filter((e=>e.column===o)).toArray()))),(e=>1===e.colspan&&t(e.element)),(()=>en(e,0,o)))))},cn=(e,t,o)=>{const n=e();return L(n,t).orThunk((()=>C.from(n[0]).orThunk(o))).map((e=>e.element))},mn=e=>{const t=e.grid,o=k(t.rows,h),n=k(t.columns,h);return E(o,(t=>cn((()=>j(n,(o=>en(e,t,o).filter((e=>e.row===t)).fold(g([]),(e=>[e]))))),(e=>1===e.rowspan),(()=>en(e,t,0)))))},dn=(e,t)=>o=>"rtl"===un(o)?t:e,un=e=>"rtl"===_t(e,"direction")?"rtl":"ltr",fn=Bo("height",(e=>{const t=e.dom;return lt(e)?t.getBoundingClientRect().height:t.offsetHeight})),gn=e=>fn.get(e),hn=e=>fn.getOuter(e),pn=(e,t)=>({left:e,top:t,translate:(o,n)=>pn(e+o,t+n)}),bn=pn,wn=(e,t)=>void 0!==e?e:void 0!==t?t:0,vn=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,r=t.documentElement;if(o===e.dom)return bn(o.offsetLeft,o.offsetTop);const s=wn(null==n?void 0:n.pageYOffset,r.scrollTop),l=wn(null==n?void 0:n.pageXOffset,r.scrollLeft),a=wn(r.clientTop,o.clientTop),c=wn(r.clientLeft,o.clientLeft);return yn(e).translate(l-c,s-a)},yn=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?bn(o.offsetLeft,o.offsetTop):lt(e)?(e=>{const t=e.getBoundingClientRect();return bn(t.left,t.top)})(t):bn(0,0)},xn=(e,t)=>({row:e,y:t}),Cn=(e,t)=>({col:e,x:t}),Sn=e=>vn(e).left+Lo(e),Tn=e=>vn(e).left,Rn=(e,t)=>Cn(e,Tn(t)),Dn=(e,t)=>Cn(e,Sn(t)),On=e=>vn(e).top,kn=(e,t)=>xn(e,On(t)),En=(e,t)=>xn(e,On(t)+hn(t)),Nn=(e,t,o)=>{if(0===o.length)return[];const n=E(o.slice(1),((t,o)=>t.map((t=>e(o,t))))),r=o[o.length-1].map((e=>t(o.length-1,e)));return n.concat([r])},Bn={delta:h,positions:e=>Nn(kn,En,e),edge:On},_n=dn({delta:h,edge:Tn,positions:e=>Nn(Rn,Dn,e)},{delta:e=>-e,edge:Sn,positions:e=>Nn(Dn,Rn,e)}),zn={delta:(e,t)=>_n(t).delta(e,t),positions:(e,t)=>_n(t).positions(e,t),edge:e=>_n(e).edge(e)},An={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},Ln=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),Wn=/(\d+(\.\d+)?)%/,Mn=/(\d+(\.\d+)?)px|em/,jn=ue("col"),Pn=ue("tr"),In=(e,t,o)=>{const n=Be(e).getOrThunk((()=>at(ke(e))));return t(e)/o(n)*100},Fn=(e,t)=>{Nt(e,"width",t+"px")},Hn=(e,t)=>{Nt(e,"width",t+"%")},$n=(e,t)=>{Nt(e,"height",t+"px")},Vn=e=>{const t=(e=>{return _o(t=e,"height",t.dom.offsetHeight)+"px";var t})(e);return t?((e,t,o,n)=>{const r=parseFloat(e);return Rt(e,"%")&&"table"!==ne(t)?((e,t,o,n)=>{const r=Gt(e).map((e=>{const n=o(e);return Math.floor(t/100*n)})).getOr(t);return n(e,r),r})(t,r,o,n):r})(t,e,gn,$n):gn(e)},qn=(e,t)=>At(e,t).orThunk((()=>be(e,t).map((e=>e+"px")))),Un=e=>qn(e,"width"),Gn=e=>In(e,Ao,Wo),Kn=e=>{return jn(e)?Ao(e):_o(t=e,"width",t.dom.offsetWidth);var t},Yn=e=>Pn(e)?gn(e):((e,t,o)=>o(e)/Mt(e,"rowspan"))(e,0,Vn),Jn=(e,t,o)=>{Nt(e,"width",t+o)},Qn=e=>In(e,Ao,Wo)+"%",Xn=g(Wn),Zn=ue("col"),er=e=>Un(e).getOrThunk((()=>Kn(e)+"px")),tr=e=>{return(t=e,qn(t,"height")).getOrThunk((()=>Yn(e)+"px"));var t},or=(e,t,o,n,r,s)=>e.filter(n).fold((()=>s(((e,t)=>{if(t<0||t>=e.length-1)return C.none();const o=e[t].fold((()=>{const o=(e=>{const t=S.call(e,0);return t.reverse(),t})(e.slice(0,t));return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:0}))),n=e[t+1].fold((()=>{const o=e.slice(t+1);return V(o,((e,t)=>e.map((e=>({value:e,delta:t+1})))))}),(e=>C.some({value:e,delta:1})));return o.bind((e=>n.map((t=>{const o=t.delta+e.delta;return Math.abs(t.value-e.value)/o}))))})(o,t))),(e=>r(e))),nr=(e,t,o,n)=>{const r=an(e),s=sn(e)?(e=>E(rn(e),(e=>C.from(e.element))))(e):r,l=[C.some(zn.edge(t))].concat(E(zn.positions(r,t),(e=>e.map((e=>e.x))))),a=w(jt);return E(s,((e,t)=>or(e,t,l,a,(e=>{if((e=>{const t=No().browser,o=t.isChromium()||t.isFirefox();return!Zn(e)||o})(e))return o(e);{const e=null!=(s=r[t])?h(s):C.none();return or(e,t,l,a,(e=>n(C.some(Ao(e)))),n)}var s}),n)))},rr=e=>e.map((e=>e+"px")).getOr(""),sr=(e,t,o)=>nr(e,t,Kn,(e=>e.getOrThunk(o.minCellWidth))),lr=(e,t,o,n)=>{const r=mn(e),s=E(e.all,(e=>C.some(e.element))),l=[C.some(Bn.edge(t))].concat(E(Bn.positions(r,t),(e=>e.map((e=>e.y)))));return E(s,((e,t)=>or(e,t,l,x,o,n)))},ar=(e,t)=>()=>lt(e)?t(e):parseFloat(At(e,"width").getOr("0")),cr=e=>{const t=ar(e,(e=>parseFloat(Qn(e)))),o=ar(e,Ao);return{width:t,pixelWidth:o,getWidths:(t,o)=>((e,t,o)=>nr(e,t,Gn,(e=>e.fold((()=>o.minCellWidth()),(e=>e/o.pixelWidth()*100)))))(t,e,o),getCellDelta:e=>e/o()*100,singleColumnWidth:(e,t)=>[100-e],minCellWidth:()=>It()/o()*100,setElementWidth:Hn,adjustTableWidth:o=>{const n=t();Hn(e,n+o/100*n)},isRelative:!0,label:"percent"}},ir=e=>{const t=ar(e,Ao);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:h,singleColumnWidth:(e,t)=>[Math.max(It(),e+t)-e],minCellWidth:It,setElementWidth:Fn,adjustTableWidth:o=>{const n=t()+o;Fn(e,n)},isRelative:!1,label:"pixel"}},mr=e=>Un(e).fold((()=>(e=>{const t=ar(e,Ao),o=g(0);return{width:t,pixelWidth:t,getWidths:(t,o)=>sr(t,e,o),getCellDelta:o,singleColumnWidth:g([0]),minCellWidth:o,setElementWidth:f,adjustTableWidth:f,isRelative:!0,label:"none"}})(e)),(t=>((e,t)=>null!==Xn().exec(t)?cr(e):ir(e))(e,t))),dr=ir,ur=cr,fr=(e,t,o)=>{const n=e[o].element,r=xe.fromTag("td");Ie(r,xe.fromTag("br")),(t?Ie:Pe)(n,r)},gr=((e,t)=>{const o=t=>e(t)?C.from(t.dom.nodeValue):C.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(ie),hr=e=>gr.get(e),pr=e=>gr.getOption(e),br=(e,t)=>gr.set(e,t),wr=e=>"img"===ne(e)?1:pr(e).fold((()=>Le(e).length),(e=>e.length)),vr=["img","br"],yr=e=>pr(e).filter((e=>0!==e.trim().length||e.indexOf("\xa0")>-1)).isSome()||D(vr,ne(e))||(e=>ae(e)&&"false"===pe(e,"contenteditable"))(e),xr=e=>((e,t)=>{const o=e=>{for(let n=0;n<e.childNodes.length;n++){const r=xe.fromDom(e.childNodes[n]);if(t(r))return C.some(r);const s=o(e.childNodes[n]);if(s.isSome())return s}return C.none()};return o(e.dom)})(e,yr),Cr=e=>Sr(e,yr),Sr=(e,t)=>{const o=e=>{const n=Le(e);for(let e=n.length-1;e>=0;e--){const r=n[e];if(t(r))return C.some(r);const s=o(r);if(s.isSome())return s}return C.none()};return o(e)},Tr={scope:["row","col"]},Rr=e=>()=>{const t=xe.fromTag("td",e.dom);return Ie(t,xe.fromTag("br",e.dom)),t},Dr=e=>()=>xe.fromTag("col",e.dom),Or=e=>()=>xe.fromTag("colgroup",e.dom),kr=e=>()=>xe.fromTag("tr",e.dom),Er=(e,t,o)=>{const n=((e,t)=>{const o=Je(e,t),n=Le(Ye(e));return $e(o,n),o})(e,t);return G(o,((e,t)=>{null===e?we(n,t):ge(n,t,e)})),n},Nr=e=>e,Br=(e,t,o)=>{const n=(e,t)=>{((e,t)=>{const o=e.dom,n=t.dom;kt(o)&&kt(n)&&(n.style.cssText=o.style.cssText)})(e.element,t),Lt(t,"height"),1!==e.colspan&&Lt(t,"width")};return{col:o=>{const r=xe.fromTag(ne(o.element),t.dom);return n(o,r),e(o.element,r),r},colgroup:Or(t),row:kr(t),cell:r=>{const s=xe.fromTag(ne(r.element),t.dom),l=o.getOr(["strong","em","b","i","span","font","h1","h2","h3","h4","h5","h6","p","div"]),a=l.length>0?((e,t,o)=>xr(e).map((n=>{const r=o.join(","),s=it(n,r,(t=>Re(t,e)));return z(s,((e,t)=>{const o=Ke(t);return Ie(e,o),o}),t)})).getOr(t))(r.element,s,l):s;return Ie(a,xe.fromTag("br")),n(r,s),((e,t)=>{G(Tr,((o,n)=>be(e,n).filter((e=>D(o,e))).each((e=>ge(t,n,e)))))})(r.element,s),e(r.element,s),s},replace:Er,colGap:Dr(t),gap:Rr(t)}},_r=e=>({col:Dr(e),colgroup:Or(e),row:kr(e),cell:Rr(e),replace:Nr,colGap:Dr(e),gap:Rr(e)}),zr=e=>t=>t.options.get(e),Ar="100%",Lr=e=>{var t;const o=e.dom,n=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return Wo(xe.fromDom(n))+"px"},Wr=e=>C.from(e.options.get("table_clone_elements")),Mr=zr("table_header_type"),jr=zr("table_column_resizing"),Pr=e=>"preservetable"===jr(e),Ir=e=>"resizetable"===jr(e),Fr=zr("table_sizing_mode"),Hr=e=>"relative"===Fr(e),$r=e=>"fixed"===Fr(e),Vr=e=>"responsive"===Fr(e),qr=zr("table_resize_bars"),Ur=zr("table_style_by_css"),Gr=zr("table_merge_content_on_paste"),Kr=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>Vr(e)||Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)},Yr=zr("table_use_colgroups"),Jr=e=>wt(e,"[contenteditable]"),Qr=(e,t=!1)=>lt(e)?e.dom.isContentEditable:Jr(e).fold(g(t),(e=>"true"===Xr(e))),Xr=e=>e.dom.contentEditable,Zr=e=>xe.fromDom(e.getBody()),es=e=>t=>Re(t,Zr(e)),ts=e=>{we(e,"data-mce-style");const t=e=>we(e,"data-mce-style");N(qt(e),t),N(Ut(e),t),N(Kt(e),t)},os=e=>xe.fromDom(e.selection.getStart()),ns=e=>e.getBoundingClientRect().width,rs=e=>e.getBoundingClientRect().height,ss=e=>(t,o)=>{const n=t.dom.getStyle(o,e)||t.dom.getAttrib(o,e);return C.from(n).filter(Ot)},ls=ss("width"),as=ss("height"),cs=e=>gt(e,ue("table")).exists(Qr),is=(e,t)=>{const o=t.column,n=t.column+t.colspan-1,r=t.row,s=t.row+t.rowspan-1;return o<=e.finishCol&&n>=e.startCol&&r<=e.finishRow&&s>=e.startRow},ms=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,ds=(e,t,o)=>{const n=tn(e,t,Re),r=tn(e,o,Re);return n.bind((e=>r.map((t=>{return o=e,n=t,{startRow:Math.min(o.row,n.row),startCol:Math.min(o.column,n.column),finishRow:Math.max(o.row+o.rowspan-1,n.row+n.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,n.column+n.colspan-1)};var o,n}))))},us=(e,t,o)=>ds(e,t,o).map((t=>{const o=on(e,b(is,t));return E(o,(e=>e.element))})),fs=(e,t)=>tn(e,t,((e,t)=>De(t,e))).map((e=>e.element)),gs=(e,t,o)=>{const n=ps(e);return us(n,t,o)},hs=(e,t,o,n,r)=>{const s=ps(e),l=Re(e,o)?C.some(t):fs(s,t),a=Re(e,r)?C.some(n):fs(s,n);return l.bind((e=>a.bind((t=>us(s,e,t)))))},ps=Xo;var bs=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],ws=()=>({up:g({selector:ht,closest:wt,predicate:ft,all:_e}),down:g({selector:dt,predicate:ct}),styles:g({get:_t,getRaw:At,set:Nt,remove:Lt}),attrs:g({get:pe,set:ge,remove:we,copyTo:(e,t)=>{const o=ve(e);he(t,o)}}),insert:g({before:Me,after:je,afterAll:He,append:Ie,appendAll:$e,prepend:Pe,wrap:Fe}),remove:g({unwrap:Ue,remove:qe}),create:g({nu:xe.fromTag,clone:e=>xe.fromDom(e.dom.cloneNode(!1)),text:xe.fromText}),query:g({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:ze,nextSibling:Ae}),property:g({children:Le,name:ne,parent:Ne,document:e=>Ee(e).dom,isText:ie,isComment:le,isElement:ce,isSpecial:e=>{const t=ne(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>ce(e)?be(e,"lang"):C.none(),getText:hr,setText:br,isBoundary:e=>!!ce(e)&&("body"===ne(e)||D(bs,ne(e))),isEmptyTag:e=>!!ce(e)&&D(["br","img","hr","input"],ne(e)),isNonEditable:e=>ce(e)&&"false"===pe(e,"contenteditable")}),eq:Re,is:Oe});const vs=(e,t,o,n)=>{const r=t(e,o);return z(n,((o,n)=>{const r=t(e,n);return ys(e,o,r)}),r)},ys=(e,t,o)=>t.bind((t=>o.filter(b(e.eq,t)))),xs=ws(),Cs=(e,t)=>((e,t,o)=>o.length>0?((e,t,o,n)=>n(e,t,o[0],o.slice(1)))(e,t,o,vs):C.none())(xs,((t,o)=>e(o)),t),Ss=e=>ht(e,"table"),Ts=(e,t,o)=>{const n=e=>t=>void 0!==o&&o(t)||Re(t,e);return Re(e,t)?C.some({boxes:C.some([e]),start:e,finish:t}):Ss(e).bind((r=>Ss(t).bind((s=>{if(Re(r,s))return C.some({boxes:gs(r,e,t),start:e,finish:t});if(De(r,s)){const o=it(t,"td,th",n(r)),l=o.length>0?o[o.length-1]:t;return C.some({boxes:hs(r,e,r,t,s),start:e,finish:l})}if(De(s,r)){const o=it(e,"td,th",n(s)),l=o.length>0?o[o.length-1]:e;return C.some({boxes:hs(s,e,r,t,s),start:e,finish:l})}return((e,t,o)=>((e,t,o,n=y)=>{const r=[t].concat(e.up().all(t)),s=[o].concat(e.up().all(o)),l=e=>W(e,n).fold((()=>e),(t=>e.slice(0,t+1))),a=l(r),c=l(s),i=L(a,(t=>O(c,((e,t)=>b(e.eq,t))(e,t))));return{firstpath:a,secondpath:c,shared:i}})(xs,e,t,void 0))(e,t).shared.bind((l=>wt(l,"table",o).bind((o=>{const l=it(t,"td,th",n(o)),a=l.length>0?l[l.length-1]:t,c=it(e,"td,th",n(o)),i=c.length>0?c[c.length-1]:e;return C.some({boxes:hs(o,e,r,t,s),start:i,finish:a})}))))}))))},Rs=(e,t)=>{const o=dt(e,t);return o.length>0?C.some(o):C.none()},Ds=(e,t,o)=>bt(e,t).bind((t=>bt(e,o).bind((e=>Cs(Ss,[t,e]).map((o=>({first:t,last:e,table:o}))))))),Os=(e,t,o,n,r)=>((e,t)=>L(e,(e=>Ce(e,t))))(e,r).bind((e=>((e,t,o)=>Gt(e).bind((n=>((e,t,o,n)=>tn(e,t,Re).bind((t=>{const r=o>0?t.row+t.rowspan-1:t.row,s=n>0?t.column+t.colspan-1:t.column;return en(e,r+o,s+n).map((e=>e.element))})))(ps(n),e,t,o))))(e,t,o).bind((e=>((e,t)=>ht(e,"table").bind((o=>bt(o,t).bind((t=>Ts(t,e).bind((e=>e.boxes.map((t=>({boxes:t,start:e.start,finish:e.finish}))))))))))(e,n))))),ks=(e,t)=>Rs(e,t),Es=(e,t,o)=>Ds(e,t,o).bind((t=>{const o=t=>Re(e,t),n="thead,tfoot,tbody,table",r=ht(t.first,n,o),s=ht(t.last,n,o);return r.bind((e=>s.bind((o=>Re(e,o)?((e,t,o)=>((e,t,o)=>ds(e,t,o).bind((t=>((e,t)=>{let o=!0;const n=b(ms,t);for(let r=t.startRow;r<=t.finishRow;r++)for(let s=t.startCol;s<=t.finishCol;s++)o=o&&en(e,r,s).exists(n);return o?C.some(t):C.none()})(e,t))))(ps(e),t,o))(t.table,t.first,t.last):C.none()))))})),Ns=h,Bs=e=>{const t=(e,t)=>be(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&P(e,(e=>t(e,"rowspan")||t(e,"colspan")))?C.some(e):C.none()},_s=(e,t,o)=>t.length<=1?C.none():Es(e,o.firstSelectedSelector,o.lastSelectedSelector).map((e=>({bounds:e,cells:t}))),zs="data-mce-selected",As="data-mce-first-selected",Ls="data-mce-last-selected",Ws="["+zs+"]",Ms={selected:zs,selectedSelector:"td["+zs+"],th["+zs+"]",firstSelected:As,firstSelectedSelector:"td["+As+"],th["+As+"]",lastSelected:Ls,lastSelectedSelector:"td["+Ls+"],th["+Ls+"]"},js=(e,t,o)=>({element:o,mergable:_s(t,e,Ms),unmergable:Bs(e),selection:Ns(e)}),Ps=e=>(t,o)=>{const n=ne(t),r="col"===n||"colgroup"===n?Gt(s=t).bind((e=>ks(e,Ms.firstSelectedSelector))).fold(g(s),(e=>e[0])):t;var s;return wt(r,e,o)},Is=Ps("th,td,caption"),Fs=Ps("th,td"),Hs=e=>{return t=e.model.table.getSelectedCells(),E(t,xe.fromDom);var t},$s=(e,t)=>{e.on("BeforeGetContent",(t=>{const o=o=>{t.preventDefault(),(e=>Gt(e[0]).map((e=>{const t=((e,t)=>{const o=e=>Ce(e.element,t),n=Ye(e),r=Xt(n),s=mr(e),l=Zo(r),a=((e,t)=>{const o=e.grid.columns;let n=e.grid.rows,r=o,s=0,l=0;const a=[],c=[];return G(e.access,(e=>{if(a.push(e),t(e)){c.push(e);const t=e.row,o=t+e.rowspan-1,a=e.column,i=a+e.colspan-1;t<n?n=t:o>s&&(s=o),a<r?r=a:i>l&&(l=i)}})),((e,t,o,n,r,s)=>({minRow:e,minCol:t,maxRow:o,maxCol:n,allCells:r,selectedCells:s}))(n,r,s,l,a,c)})(l,o),c="th:not("+t+"),td:not("+t+")",i=$t(n,"th,td",(e=>Ce(e,c)));N(i,qe),((e,t,o,n)=>{const r=_(e,(e=>"colgroup"!==e.section)),s=t.grid.columns,l=t.grid.rows;for(let e=0;e<l;e++){let l=!1;for(let a=0;a<s;a++)e<o.minRow||e>o.maxRow||a<o.minCol||a>o.maxCol||(en(t,e,a).filter(n).isNone()?fr(r,l,e):l=!0)}})(r,l,a,o);const m=((e,t,o,n)=>{if(0===n.minCol&&t.grid.columns===n.maxCol+1)return 0;const r=sr(t,e,o),s=A(r,((e,t)=>e+t),0),l=A(r.slice(n.minCol,n.maxCol+1),((e,t)=>e+t),0),a=l/s*o.pixelWidth()-o.pixelWidth();return o.getCellDelta(a)})(e,Xo(e),s,a);return((e,t,o,n)=>{G(o.columns,(e=>{(e.column<t.minCol||e.column>t.maxCol)&&qe(e.element)}));const r=_(Ht(e,"tr"),(e=>0===e.dom.childElementCount));N(r,qe),t.minCol!==t.maxCol&&t.minRow!==t.maxRow||N(Ht(e,"th,td"),(e=>{we(e,"rowspan"),we(e,"colspan")})),we(e,Uo),we(e,"data-snooker-col-series"),mr(e).adjustTableWidth(n)})(n,a,l,m),n})(e,Ws);return ts(t),[t]})))(o).each((o=>{t.content="text"===t.format?(e=>E(e,(e=>e.dom.innerText)).join(""))(o):((e,t)=>E(t,(t=>e.selection.serializer.serialize(t.dom,{}))).join(""))(e,o)}))};if(!0===t.selection){const t=(e=>_(Hs(e),(e=>Ce(e,Ms.selectedSelector))))(e);t.length>=1&&o(t)}})),e.on("BeforeSetContent",(o=>{if(!0===o.selection&&!0===o.paste){const n=Hs(e);H(n).each((n=>{Gt(n).each((r=>{const s=_(((e,t)=>{const o=document.createElement("div");return o.innerHTML=e,Le(xe.fromDom(o))})(o.content),(e=>"meta"!==ne(e))),l=ue("table");if(Gr(e)&&1===s.length&&l(s[0])){o.preventDefault();const l=xe.fromDom(e.getDoc()),a=_r(l),c=((e,t,o)=>({element:e,clipboard:t,generators:o}))(n,s[0],a);t.pasteCells(r,c).each((()=>{e.focus()}))}}))}))}}))},Vs=(e,t)=>({element:e,offset:t}),qs=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>qs(e,t,o).orThunk((()=>C.some(t))))):C.none(),Us=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,Gs=(e,t)=>{const o=qs(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return Vs(o,Us(e,o));const n=e.property().children(o);return n.length>0?Gs(e,n[n.length-1]):Vs(o,Us(e,o))},Ks=Gs,Ys=ws(),Js=(e,t)=>{if(!jt(e)){const o=(e=>Un(e).bind((e=>{return t=e,o=["fixed","relative","empty"],C.from(Ln.exec(t)).bind((e=>{const t=Number(e[1]),n=e[2];return((e,t)=>O(t,(t=>O(An[t],(t=>e===t)))))(n,o)?C.some({value:t,unit:n}):C.none()}));var t,o})))(e);o.each((o=>{const n=o.value/2;Jn(e,n,o.unit),Jn(t,n,o.unit)}))}},Qs=e=>E(e,g(0)),Xs=(e,t,o,n,r)=>r(e.slice(0,t)).concat(n).concat(r(e.slice(o))),Zs=e=>(t,o,n,r)=>{if(e(n)){const e=Math.max(r,t[o]-Math.abs(n)),s=Math.abs(e-t[o]);return n>=0?s:-s}return n},el=Zs((e=>e<0)),tl=Zs(x),ol=()=>{const e=(e,t,o,n)=>{const r=(100+o)/100,s=Math.max(n,(e[t]+o)/r);return E(e,((e,o)=>(o===t?s:e/r)-e))},t=(t,o,n,r,s,l)=>l?e(t,o,r,s):((e,t,o,n,r)=>{const s=el(e,t,n,r);return Xs(e,t,o+1,[s,0],Qs)})(t,o,n,r,s);return{resizeTable:(e,t)=>e(t),clampTableDelta:el,calcLeftEdgeDeltas:t,calcMiddleDeltas:(e,o,n,r,s,l,a)=>t(e,n,r,s,l,a),calcRightEdgeDeltas:(t,o,n,r,s,l)=>{if(l)return e(t,n,r,s);{const e=el(t,n,r,s);return Qs(t.slice(0,n)).concat([e])}},calcRedestributedWidths:(e,t,o,n)=>{if(n){const n=(t+o)/t,r=E(e,(e=>e/n));return{delta:100*n-100,newSizes:r}}return{delta:o,newSizes:e}}}},nl=()=>{const e=(e,t,o,n,r)=>{const s=tl(e,n>=0?o:t,n,r);return Xs(e,t,o+1,[s,-s],Qs)};return{resizeTable:(e,t,o)=>{o&&e(t)},clampTableDelta:(e,t,o,n,r)=>{if(r){if(o>=0)return o;{const t=A(e,((e,t)=>e+t-n),0);return Math.max(-t,o)}}return el(e,t,o,n)},calcLeftEdgeDeltas:e,calcMiddleDeltas:(t,o,n,r,s,l)=>e(t,n,r,s,l),calcRightEdgeDeltas:(e,t,o,n,r,s)=>{if(s)return Qs(e);{const t=n/e.length;return E(e,g(t))}},calcRedestributedWidths:(e,t,o,n)=>({delta:0,newSizes:e})}},rl=e=>Xo(e).grid,sl=ue("th"),ll=e=>P(e,(e=>sl(e.element))),al=(e,t)=>e&&t?"sectionCells":e?"section":"cells",cl=e=>{const t="thead"===e.section,o=vt(il(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:al(t,o)}:{type:"body"}},il=e=>{const t=_(e,(e=>sl(e.element)));return 0===t.length?C.some("td"):t.length===e.length?C.some("th"):C.none()},ml=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),dl=(e,t)=>e.section!==t?tt(e.element,e.cells,t,e.isNew):e,ul=()=>({transformRow:dl,transformCell:(e,t,o)=>{const n=o(e.element,t),r="td"!==ne(n)?((e,t)=>{const o=Je(e,"td");je(e,o);const n=Le(e);return $e(o,n),qe(e),o})(n):n;return et(r,e.isNew,e.isLocked)}}),fl=()=>({transformRow:dl,transformCell:ml}),gl=()=>({transformRow:(e,t)=>dl(e,"thead"===t?"tbody":t),transformCell:ml}),hl=ul,pl=fl,bl=gl,wl=()=>({transformRow:h,transformCell:ml}),vl=(e,t,o,n)=>{o===n?we(e,t):ge(e,t,o)},yl=(e,t,o)=>{$(mt(e,t)).fold((()=>Pe(e,o)),(e=>je(e,o)))},xl=(e,t)=>{const o=[],n=[],r=e=>E(e,(e=>{e.isNew&&o.push(e.element);const t=e.element;return Ve(t),N(e.cells,(e=>{e.isNew&&n.push(e.element),vl(e.element,"colspan",e.colspan,1),vl(e.element,"rowspan",e.rowspan,1),Ie(t,e.element)})),t})),s=e=>j(e,(e=>E(e.cells,(e=>(vl(e.element,"span",e.colspan,1),e.element))))),l=(t,o)=>{const n=((e,t)=>{const o=pt(e,t).getOrThunk((()=>{const o=xe.fromTag(t,ke(e).dom);return"thead"===t?yl(e,"caption,colgroup",o):"colgroup"===t?yl(e,"caption",o):Ie(e,o),o}));return Ve(o),o})(e,o),l=("colgroup"===o?s:r)(t);$e(n,l)},a=(t,o)=>{t.length>0?l(t,o):(t=>{pt(e,t).each(qe)})(o)},c=[],i=[],m=[],d=[];return N(t,(e=>{switch(e.section){case"thead":c.push(e);break;case"tbody":i.push(e);break;case"tfoot":m.push(e);break;case"colgroup":d.push(e)}})),a(d,"colgroup"),a(c,"thead"),a(i,"tbody"),a(m,"tfoot"),{newRows:o,newCells:n}},Cl=(e,t)=>{if(0===e.length)return 0;const o=e[0];return W(e,(e=>!t(o.element,e.element))).getOr(e.length)},Sl=(e,t)=>{const o=E(e,(e=>E(e.cells,y)));return E(e,((n,r)=>{const s=j(n.cells,((n,s)=>{if(!1===o[r][s]){const m=((e,t,o,n)=>{const r=((e,t)=>e[t])(e,t),s="colgroup"===r.section,l=Cl(r.cells.slice(o),n),a=s?1:Cl(((e,t)=>E(e,(e=>Fo(e,t))))(e.slice(t),o),n);return{colspan:l,rowspan:a}})(e,r,s,t);return((e,t,n,r)=>{for(let s=e;s<e+n;s++)for(let e=t;e<t+r;e++)o[s][e]=!0})(r,s,m.rowspan,m.colspan),[(l=n.element,a=m.rowspan,c=m.colspan,i=n.isNew,{element:l,rowspan:a,colspan:c,isNew:i})]}return[];var l,a,c,i}));return((e,t,o,n)=>({element:e,cells:t,section:o,isNew:n}))(n.element,s,n.section,n.isNew)}))},Tl=(e,t,o)=>{const n=[];N(e.colgroups,(r=>{const s=[];for(let n=0;n<e.grid.columns;n++){const r=ln(e,n).map((e=>et(e.element,o,!1))).getOrThunk((()=>et(t.colGap(),!0,!1)));s.push(r)}n.push(tt(r.element,s,"colgroup",o))}));for(let r=0;r<e.grid.rows;r++){const s=[];for(let n=0;n<e.grid.columns;n++){const l=en(e,r,n).map((e=>et(e.element,o,e.isLocked))).getOrThunk((()=>et(t.gap(),!0,!1)));s.push(l)}const l=e.all[r],a=tt(l.element,s,l.section,o);n.push(a)}return n},Rl=e=>Sl(e,Re),Dl=(e,t)=>V(e.all,(e=>L(e.cells,(e=>Re(t,e.element))))),Ol=(e,t,o)=>{const n=E(t.selection,(t=>Vt(t).bind((t=>Dl(e,t))).filter(o))),r=yt(n);return xt(r.length>0,r)},kl=(e,t,o,n,r)=>(s,l,a,c)=>{const i=Xo(s),m=C.from(null==c?void 0:c.section).getOrThunk(wl);return t(i,l).map((t=>{const o=((e,t)=>Tl(e,t,!1))(i,a),n=e(o,t,Re,r(a),m),s=Ko(n.grid);return{info:t,grid:Rl(n.grid),cursor:n.cursor,lockedColumns:s}})).bind((e=>{const t=xl(s,e.grid),r=C.from(null==c?void 0:c.sizing).getOrThunk((()=>mr(s))),l=C.from(null==c?void 0:c.resize).getOrThunk(nl);return o(s,e.grid,e.info,{sizing:r,resize:l,section:m}),n(s),we(s,Uo),e.lockedColumns.length>0&&ge(s,Uo,e.lockedColumns.join(",")),C.some({cursor:e.cursor,newRows:t.newRows,newCells:t.newCells})}))},El=(e,t)=>Ol(e,t,x).map((e=>({cells:e,generators:t.generators,clipboard:t.clipboard}))),Nl=(e,t)=>Ol(e,t,x),Bl=(e,t)=>Ol(e,t,(e=>!e.isLocked)),_l=(e,t)=>P(t,(t=>((e,t)=>Dl(e,t).exists((e=>!e.isLocked)))(e,t))),zl=(e,t,o,n)=>{const r=Vo(e).rows;let s=!0;for(let e=0;e<r.length;e++)for(let l=0;l<$o(r[0]);l++){const a=r[e],c=Fo(a,l),i=o(c.element,t);i&&!s?Po(a,l,et(n(),!0,c.isLocked)):i&&(s=!1)}return e},Al=e=>{const t=t=>t(e),o=g(e),n=()=>r,r={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:x,isError:y,map:t=>Wl.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>C.some(e)};return r},Ll=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:y,isError:x,map:t,mapError:t=>Wl.error(t(e)),bind:t,exists:y,forall:x,getOr:h,or:h,getOrThunk:v,orThunk:v,getOrDie:(n=String(e),()=>{throw new Error(n)}),each:f,toOptional:C.none};var n;return o},Wl={value:Al,error:Ll,fromOption:(e,t)=>e.fold((()=>Ll(t)),Al)},Ml=(e,t)=>({rowDelta:0,colDelta:$o(e[0])-$o(t[0])}),jl=(e,t)=>({rowDelta:e.length-t.length,colDelta:0}),Pl=(e,t,o,n)=>{const r="colgroup"===t.section?o.col:o.cell;return k(e,(e=>et(r(),!0,n(e))))},Il=(e,t,o,n)=>{const r=e[e.length-1];return e.concat(k(t,(()=>{const e="colgroup"===r.section?o.colgroup:o.row,t=qo(r,e,h),s=Pl(t.cells.length,t,o,(e=>X(n,e.toString())));return Io(t,s)})))},Fl=(e,t,o,n)=>E(e,(e=>{const r=Pl(t,e,o,y);return Mo(e,n,r)})),Hl=(e,t,o)=>{const n=t.colDelta<0?Fl:h,r=t.rowDelta<0?Il:h,s=Ko(e),l=$o(e[0]),a=O(s,(e=>e===l-1)),c=n(e,Math.abs(t.colDelta),o,a?l-1:l),i=Ko(c);return r(c,Math.abs(t.rowDelta),o,I(i,x))},$l=(e,t,o,n)=>{const r=b(n,Fo(e[t],o).element),s=e[t];return e.length>1&&$o(s)>1&&(o>0&&r(Ho(s,o-1))||o<s.cells.length-1&&r(Ho(s,o+1))||t>0&&r(Ho(e[t-1],o))||t<e.length-1&&r(Ho(e[t+1],o)))},Vl=(e,t,o)=>_(o,(o=>o>=e.column&&o<=$o(t[0])+e.column)),ql=(e,t,o,n,r)=>{((e,t,o,n)=>{t>0&&t<e[0].cells.length&&N(e,(e=>{const r=e.cells[t-1];let s=0;const l=n();for(;e.cells.length>t+s&&o(r.element,e.cells[t+s].element);)Po(e,t+s,et(l,!0,e.cells[t+s].isLocked)),s++}))})(t,e,r,n.cell);const s=jl(o,t),l=Hl(o,s,n),a=jl(t,l),c=Hl(t,a,n);return E(c,((t,o)=>Mo(t,e,l[o].cells)))},Ul=(e,t,o,n,r)=>{((e,t,o,n)=>{const r=Vo(e).rows;if(t>0&&t<r.length){const e=((e,t)=>A(e,((e,o)=>O(e,(e=>t(e.element,o.element)))?e:e.concat([o])),[]))(r[t-1].cells,o);N(e,(e=>{let s=C.none();for(let l=t;l<r.length;l++)for(let t=0;t<$o(r[0]);t++){const a=r[l],c=Fo(a,t);o(c.element,e.element)&&(s.isNone()&&(s=C.some(n())),s.each((e=>{Po(a,t,et(e,!0,c.isLocked))})))}}))}})(t,e,r,n.cell);const s=Ko(t),l=Ml(t,o),a={...l,colDelta:l.colDelta-s.length},c=Hl(t,a,n),{cols:i,rows:m}=Vo(c),d=Ko(c),u=Ml(o,t),f={...u,colDelta:u.colDelta+d.length},g=(p=n,b=d,E(o,(e=>A(b,((t,o)=>{const n=Pl(1,e,p,x)[0];return jo(t,o,n)}),e)))),h=Hl(g,f,n);var p,b;return[...i,...m.slice(0,e),...h,...m.slice(e,m.length)]},Gl=(e,t,o,n,r)=>{const{rows:s,cols:l}=Vo(e),a=s.slice(0,t),c=s.slice(t);return[...l,...a,((e,t,o,n)=>qo(e,(e=>n(e,o)),t))(s[o],((e,o)=>t>0&&t<s.length&&n(Ho(s[t-1],o),Ho(s[t],o))?Fo(s[t],o):et(r(e.element,n),!0,e.isLocked)),n,r),...c]},Kl=(e,t,o,n,r)=>E(e,(e=>{const s=t>0&&t<$o(e)&&n(Ho(e,t-1),Ho(e,t)),l=((e,t,o,n,r,s,l)=>{if("colgroup"!==o&&n)return Fo(e,t);{const t=Fo(e,r);return et(l(t.element,s),!0,!1)}})(e,t,e.section,s,o,n,r);return jo(e,t,l)})),Yl=(e,t,o,n)=>((e,t,o,n)=>void 0!==Ho(e[t],o)&&t>0&&n(Ho(e[t-1],o),Ho(e[t],o)))(e,t,o,n)||((e,t,o)=>t>0&&o(Ho(e,t-1),Ho(e,t)))(e[t],o,n),Jl=(e,t,o,n)=>{const r=e=>(e=>"row"===e?(e=>Mt(e,"rowspan")>1)(t):jt(t))(e)?`${e}group`:e;return e?sl(t)?r(o):null:n&&sl(t)?r("row"===o?"col":"row"):null},Ql=(e,t,o)=>et(o(e.element,t),!0,e.isLocked),Xl=(e,t,o,n,r,s,l)=>E(e,((e,a)=>((e,c)=>{const i=e.cells,m=E(i,((e,c)=>{if((e=>O(t,(t=>o(e.element,t.element))))(e)){const t=l(e,a,c)?r(e,o,n):e;return s(t,a,c).each((e=>{var o,n;o=t.element,n={scope:C.from(e)},G(n,((e,t)=>{e.fold((()=>{we(o,t)}),(e=>{fe(o.dom,t,e)}))}))})),t}return e}));return tt(e.element,m,e.section,e.isNew)})(e))),Zl=(e,t,o)=>j(e,((n,r)=>Yl(e,r,t,o)?[]:[Fo(n,t)])),ea=(e,t,o,n,r)=>{const s=Vo(e).rows,l=j(t,(e=>Zl(s,e,n))),a=E(s,(e=>ll(e.cells))),c=((e,t)=>P(t,h)&&ll(e)?x:(e,o,n)=>!("th"===ne(e.element)&&t[o]))(l,a),i=((e,t)=>(o,n)=>C.some(Jl(e,o.element,"row",t[n])))(o,a);return Xl(e,l,n,r,Ql,i,c)},ta=(e,t,o,n)=>{const r=Vo(e).rows,s=E(t,(e=>Fo(r[e.row],e.column)));return Xl(e,s,o,n,Ql,C.none,x)},oa=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return N(e,((n,r)=>{const s=q(n);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],c=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(c))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==c.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+c.length+" ("+c+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const n=q(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!P(t,(e=>D(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o},na={...oa([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}])},ra=(e,t,o)=>{const n=((e,t)=>sn(e)?((e,t)=>{const o=rn(e);return E(o,((e,o)=>({element:e.element,width:t[o],colspan:e.colspan})))})(e,t):((e,t)=>{const o=nn(e);return E(o,(e=>{const o=((e,t,o)=>{let n=0;for(let r=e;r<t;r++)n+=void 0!==o[r]?o[r]:0;return n})(e.column,e.column+e.colspan,t);return{element:e.element,width:o,colspan:e.colspan}}))})(e,t))(e,t);N(n,(e=>{o.setElementWidth(e.element,e.width)}))},sa=(e,t,o,n,r)=>{const s=Xo(e),l=r.getCellDelta(t),a=r.getWidths(s,r),c=o===s.grid.columns-1,i=n.clampTableDelta(a,o,l,r.minCellWidth(),c),m=((e,t,o,n,r)=>{const s=e.slice(0),l=((e,t)=>0===e.length?na.none():1===e.length?na.only(0):0===t?na.left(0,1):t===e.length-1?na.right(t-1,t):t>0&&t<e.length-1?na.middle(t-1,t,t+1):na.none())(e,t),a=g(E(s,g(0)));return l.fold(a,(e=>n.singleColumnWidth(s[e],o)),((e,t)=>r.calcLeftEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)),((e,t,l)=>r.calcMiddleDeltas(s,e,t,l,o,n.minCellWidth(),n.isRelative)),((e,t)=>r.calcRightEdgeDeltas(s,e,t,o,n.minCellWidth(),n.isRelative)))})(a,o,i,r,n),d=E(m,((e,t)=>e+a[t]));ra(s,d,r),n.resizeTable(r.adjustTableWidth,i,c)},la=(e,t,o)=>{const n=Xo(e),r=((e,t)=>lr(e,t,Yn,(e=>e.getOrThunk(Ft))))(n,e),s=E(r,((e,n)=>o===n?Math.max(t+e,Ft()):e)),l=((e,t)=>E(e.all,((e,o)=>({element:e.element,height:t[o]}))))(n,s);N(l,(e=>{$n(e.element,e.height)})),N(nn(n),(e=>{(e=>{Lt(e,"height")})(e.element)}));const a=z(s,((e,t)=>e+t),0);$n(e,a)},aa=e=>A(e,((e,t)=>O(e,(e=>e.column===t.column))?e:e.concat([t])),[]).sort(((e,t)=>e.column-t.column)),ca=ue("col"),ia=ue("colgroup"),ma=e=>"tr"===ne(e)||ia(e),da=e=>({element:e,colspan:Wt(e,"colspan",1),rowspan:Wt(e,"rowspan",1)}),ua=e=>be(e,"scope").map((e=>e.substr(0,3))),fa=(e,t=da)=>{const o=o=>{if(ma(o))return ia((r={element:o}).element)?e.colgroup(r):e.row(r);{const r=o,s=(t=>ca(t.element)?e.col(t):e.cell(t))(t(r));return n=C.some({item:r,replacement:s}),s}var r};let n=C.none();return{getOrInit:(e,t)=>n.fold((()=>o(e)),(n=>t(e,n.item)?n.replacement:o(e)))}},ga=e=>t=>{const o=[],n=n=>{const r="td"===e?{scope:null}:{},s=t.replace(n,e,r);return o.push({item:n,sub:s}),s};return{replaceOrInit:(e,t)=>{if(ma(e)||ca(e))return e;{const r=e;return((e,t)=>L(o,(o=>t(o.item,e))))(r,t).fold((()=>n(r)),(o=>t(e,o.item)?o.sub:n(r)))}}}},ha=e=>({unmerge:t=>{const o=ua(t);return o.each((e=>ge(t,"scope",e))),()=>{const n=e.cell({element:t,colspan:1,rowspan:1});return Lt(n,"width"),Lt(t,"width"),o.each((e=>ge(n,"scope",e))),n}},merge:e=>(Lt(e[0],"width"),(()=>{const t=yt(E(e,ua));if(0===t.length)return C.none();{const e=t[0],o=["row","col"];return O(t,(t=>t!==e&&D(o,t)))?C.none():C.from(e)}})().fold((()=>we(e[0],"scope")),(t=>ge(e[0],"scope",t+"group"))),g(e[0]))}),pa=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","table","thead","tfoot","tbody","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"],ba=ws(),wa=e=>((e,t)=>{const o=e.property().name(t);return D(pa,o)})(ba,e),va=e=>((e,t)=>{const o=e.property().name(t);return D(["ol","ul"],o)})(ba,e),ya=e=>{const t=ue("br"),o=e=>Cr(e).bind((o=>{const n=Ae(o).map((e=>!!wa(e)||!!((e,t)=>D(["br","img","hr","input"],e.property().name(t)))(ba,e)&&"img"!==ne(e))).getOr(!1);return Ne(o).map((r=>{return!0===n||("li"===ne(s=r)||ft(s,va).isSome())||t(o)||wa(r)&&!Re(e,r)?[]:[xe.fromTag("br")];var s}))})).getOr([]),n=(()=>{const n=j(e,(e=>{const n=Le(e);return(e=>P(e,(e=>t(e)||ie(e)&&0===hr(e).trim().length)))(n)?[]:n.concat(o(e))}));return 0===n.length?[xe.fromTag("br")]:n})();Ve(e[0]),$e(e[0],n)},xa=e=>Qr(e,!0),Ca=e=>{0===qt(e).length&&qe(e)},Sa=(e,t)=>({grid:e,cursor:t}),Ta=(e,t,o)=>{const n=((e,t,o)=>{var n,r;const s=Vo(e).rows;return C.from(null===(r=null===(n=s[t])||void 0===n?void 0:n.cells[o])||void 0===r?void 0:r.element).filter(xa).orThunk((()=>(e=>V(e,(e=>V(e.cells,(e=>{const t=e.element;return xt(xa(t),t)})))))(s)))})(e,t,o);return Sa(e,n)},Ra=e=>A(e,((e,t)=>O(e,(e=>e.row===t.row))?e:e.concat([t])),[]).sort(((e,t)=>e.row-t.row)),Da=(e,t)=>(o,n,r,s,l)=>{const a=Ra(n),c=E(a,(e=>e.row)),i=((e,t,o,n,r,s,l)=>{const{cols:a,rows:c}=Vo(e),i=c[t[0]],m=j(t,(e=>((e,t,o)=>{const n=e[t];return j(n.cells,((n,r)=>Yl(e,t,r,o)?[]:[n]))})(c,e,r))),d=E(i.cells,((e,t)=>ll(Zl(c,t,r)))),u=[...c];N(t,(e=>{u[e]=l.transformRow(c[e],o)}));const f=[...a,...u],g=((e,t)=>P(t,h)&&ll(e.cells)?x:(e,o,n)=>!("th"===ne(e.element)&&t[n]))(i,d),p=((e,t)=>(o,n,r)=>C.some(Jl(e,o.element,"col",t[r])))(n,d);return Xl(f,m,r,s,l.transformCell,p,g)})(o,c,e,t,r,s.replaceOrInit,l);return Ta(i,n[0].row,n[0].column)},Oa=Da("thead",!0),ka=Da("tbody",!1),Ea=Da("tfoot",!1),Na=(e,t,o)=>{const n=((e,t)=>Jt(e,(()=>t)))(e,o.section),r=Zo(n);return Tl(r,t,!0)},Ba=(e,t,o,n)=>((e,t,o,n)=>{const r=Zo(t),s=n.getWidths(r,n);ra(r,s,n)})(0,t,0,n.sizing),_a=(e,t,o,n)=>((e,t,o,n,r)=>{const s=Zo(t),l=n.getWidths(s,n),a=n.pixelWidth(),{newSizes:c,delta:i}=r.calcRedestributedWidths(l,a,o.pixelDelta,n.isRelative);ra(s,c,n),n.adjustTableWidth(i)})(0,t,o,n.sizing,n.resize),za=(e,t)=>O(t,(e=>0===e.column&&e.isLocked)),Aa=(e,t)=>O(t,(t=>t.column+t.colspan>=e.grid.columns&&t.isLocked)),La=(e,t)=>{const o=an(e),n=aa(t);return A(n,((e,t)=>e+o[t.column].map(Lo).getOr(0)),0)},Wa=e=>(t,o)=>Nl(t,o).filter((o=>!(e?za:Aa)(t,o))).map((e=>({details:e,pixelDelta:La(t,e)}))),Ma=e=>(t,o)=>El(t,o).filter((o=>!(e?za:Aa)(t,o.cells))),ja=ga("th"),Pa=ga("td"),Ia=kl(((e,t,o,n)=>{const r=t[0].row,s=Ra(t),l=z(s,((e,t)=>({grid:Gl(e.grid,r,t.row+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ta(l,r,t[0].column)}),Nl,f,f,fa),Fa=kl(((e,t,o,n)=>{const r=Ra(t),s=r[r.length-1],l=s.row+s.rowspan,a=z(r,((e,t)=>Gl(e,l,t.row,o,n.getOrInit)),e);return Ta(a,l,t[0].column)}),Nl,f,f,fa),Ha=kl(((e,t,o,n)=>{const r=t.details,s=aa(r),l=s[0].column,a=z(s,((e,t)=>({grid:Kl(e.grid,l,t.column+e.delta,o,n.getOrInit),delta:e.delta+1})),{grid:e,delta:0}).grid;return Ta(a,r[0].row,l)}),Wa(!0),_a,f,fa),$a=kl(((e,t,o,n)=>{const r=t.details,s=r[r.length-1],l=s.column+s.colspan,a=aa(r),c=z(a,((e,t)=>Kl(e,l,t.column,o,n.getOrInit)),e);return Ta(c,r[0].row,l)}),Wa(!1),_a,f,fa),Va=kl(((e,t,o,n)=>{const r=aa(t.details),s=((e,t)=>j(e,(e=>{const o=e.cells,n=z(t,((e,t)=>t>=0&&t<e.length?e.slice(0,t).concat(e.slice(t+1)):e),o);return n.length>0?[tt(e.element,n,e.section,e.isNew)]:[]})))(e,E(r,(e=>e.column))),l=s.length>0?s[0].cells.length-1:0;return Ta(s,r[0].row,Math.min(r[0].column,l))}),((e,t)=>Bl(e,t).map((t=>({details:t,pixelDelta:-La(e,t)})))),_a,Ca,fa),qa=kl(((e,t,o,n)=>{const r=Ra(t),s=((e,t,o)=>{const{rows:n,cols:r}=Vo(e);return[...r,...n.slice(0,t),...n.slice(o+1)]})(e,r[0].row,r[r.length-1].row),l=Math.max(Vo(s).rows.length-1,0);return Ta(s,Math.min(t[0].row,l),t[0].column)}),Nl,f,Ca,fa),Ua=kl(((e,t,o,n)=>{const r=aa(t),s=E(r,(e=>e.column)),l=ea(e,s,!0,o,n.replaceOrInit);return Ta(l,t[0].row,t[0].column)}),Bl,f,f,ja),Ga=kl(((e,t,o,n)=>{const r=aa(t),s=E(r,(e=>e.column)),l=ea(e,s,!1,o,n.replaceOrInit);return Ta(l,t[0].row,t[0].column)}),Bl,f,f,Pa),Ka=kl(Oa,Bl,f,f,ja),Ya=kl(ka,Bl,f,f,Pa),Ja=kl(Ea,Bl,f,f,Pa),Qa=kl(((e,t,o,n)=>{const r=ta(e,t,o,n.replaceOrInit);return Ta(r,t[0].row,t[0].column)}),Bl,f,f,ja),Xa=kl(((e,t,o,n)=>{const r=ta(e,t,o,n.replaceOrInit);return Ta(r,t[0].row,t[0].column)}),Bl,f,f,Pa),Za=kl(((e,t,o,n)=>{const r=t.cells;ya(r);const s=((e,t,o,n)=>{const r=Vo(e).rows;if(0===r.length)return e;for(let e=t.startRow;e<=t.finishRow;e++)for(let o=t.startCol;o<=t.finishCol;o++){const t=r[e],s=Fo(t,o).isLocked;Po(t,o,et(n(),!1,s))}return e})(e,t.bounds,0,n.merge(r));return Sa(s,C.from(r[0]))}),((e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>_l(e,t.cells)))),Ba,f,ha),ec=kl(((e,t,o,n)=>{const r=z(t,((e,t)=>zl(e,t,o,n.unmerge(t))),e);return Sa(r,C.from(t[0]))}),((e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>_l(e,t)))),Ba,f,ha),tc=kl(((e,t,o,n)=>{const r=((e,t)=>{const o=Xo(e);return Tl(o,t,!0)})(t.clipboard,t.generators);var s,l;return((e,t,o,n,r)=>{const s=Ko(t),l=((e,t,o)=>{const n=$o(t[0]),r=Vo(t).cols.length+e.row,s=k(n-e.column,(t=>t+e.column));return{row:r,column:L(s,(e=>P(o,(t=>t!==e)))).getOr(n-1)}})(e,t,s),a=Vo(o).rows,c=Vl(l,a,s),i=((e,t,o)=>{if(e.row>=t.length||e.column>$o(t[0]))return Wl.error("invalid start address out of table bounds, row: "+e.row+", column: "+e.column);const n=t.slice(e.row),r=n[0].cells.slice(e.column),s=$o(o[0]),l=o.length;return Wl.value({rowDelta:n.length-l,colDelta:r.length-s})})(l,t,a);return i.map((e=>{const o={...e,colDelta:e.colDelta-c.length},s=Hl(t,o,n),i=Ko(s),m=Vl(l,a,i);return((e,t,o,n,r,s)=>{const l=e.row,a=e.column,c=l+o.length,i=a+$o(o[0])+s.length,m=I(s,x);for(let e=l;e<c;e++){let s=0;for(let c=a;c<i;c++){if(m[c]){s++;continue}$l(t,e,c,r)&&zl(t,Ho(t[e],c),r,n.cell);const i=c-a-s,d=Fo(o[e-l],i),u=d.element,f=n.replace(u);Po(t[e],c,et(f,!0,d.isLocked))}}return t})(l,s,a,n,r,m)}))})((s=t.row,l=t.column,{row:s,column:l}),e,r,t.generators,o).fold((()=>Sa(e,C.some(t.element))),(e=>Ta(e,t.row,t.column)))}),((e,t)=>Vt(t.element).bind((o=>Dl(e,o).map((e=>({...e,generators:t.generators,clipboard:t.clipboard})))))),Ba,f,fa),oc=kl(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[0].column,l=r[t.cells[0].row],a=Na(t.clipboard,t.generators,l),c=ql(s,e,a,t.generators,o);return Ta(c,t.cells[0].row,t.cells[0].column)}),Ma(!0),f,f,fa),nc=kl(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[t.cells.length-1].column+t.cells[t.cells.length-1].colspan,l=r[t.cells[0].row],a=Na(t.clipboard,t.generators,l),c=ql(s,e,a,t.generators,o);return Ta(c,t.cells[0].row,s)}),Ma(!1),f,f,fa),rc=kl(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[0].row,l=r[s],a=Na(t.clipboard,t.generators,l),c=Ul(s,e,a,t.generators,o);return Ta(c,t.cells[0].row,t.cells[0].column)}),El,f,f,fa),sc=kl(((e,t,o,n)=>{const r=Vo(e).rows,s=t.cells[t.cells.length-1].row+t.cells[t.cells.length-1].rowspan,l=r[t.cells[0].row],a=Na(t.clipboard,t.generators,l),c=Ul(s,e,a,t.generators,o);return Ta(c,s,t.cells[0].column)}),El,f,f,fa),lc=(e,t)=>{const o=Xo(e);return Nl(o,t).bind((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=M(E(o.all,(e=>_(e.cells,(e=>e.column>=n&&e.column<r)))));return il(s)})).getOr("")},ac=(e,t)=>{const o=Xo(e);return Nl(o,t).bind(il).getOr("")},cc=(e,t)=>{const o=Xo(e);return Nl(o,t).bind((e=>{const t=e[e.length-1],n=e[0].row,r=t.row+t.rowspan;return(e=>{const t=E(e,(e=>cl(e).type)),o=D(t,"header"),n=D(t,"footer");if(o||n){const e=D(t,"body");return!o||e||n?o||e||!n?C.none():C.some("footer"):C.some("header")}return C.some("body")})(o.all.slice(n,r))})).getOr("")},ic=(e,t)=>e.dispatch("NewRow",{node:t}),mc=(e,t)=>e.dispatch("NewCell",{node:t}),dc=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},uc={structure:!1,style:!0},fc={structure:!0,style:!1},gc={structure:!0,style:!0},hc=(e,t)=>Hr(e)?ur(t):$r(e)?dr(t):mr(t),pc=(e,t,o)=>{const n=e=>"table"===ne(Zr(e)),r=Wr(e),s=Ir(e)?f:Js,l=t=>{switch(Mr(e)){case"section":return hl();case"sectionCells":return pl();case"cells":return bl();default:return((e,t)=>{var o;switch((o=Xo(e),V(o.all,(e=>{const t=cl(e);return"header"===t.type?C.from(t.subType):C.none()}))).getOr(t)){case"section":return ul();case"sectionCells":return fl();case"cells":return gl()}})(t,"section")}},a=(n,s,a,c)=>(i,m,d=!1)=>{ts(i);const u=xe.fromDom(e.getDoc()),f=Br(a,u,r),g={sizing:hc(e,i),resize:Ir(e)?ol():nl(),section:l(i)};return s(i)?n(i,m,f,g).bind((n=>{t.refresh(i.dom),N(n.newRows,(t=>{ic(e,t.dom)})),N(n.newCells,(t=>{mc(e,t.dom)}));const r=((t,n)=>n.cursor.fold((()=>{const n=qt(t);return H(n).filter(lt).map((n=>{o.clearSelectedCells(t.dom);const r=e.dom.createRng();return r.selectNode(n.dom),e.selection.setRng(r),ge(n,"data-mce-selected","1"),r}))}),(n=>{const r=Ks(Ys,n),s=e.dom.createRng();return s.setStart(r.element.dom,r.offset),s.setEnd(r.element.dom,r.offset),e.selection.setRng(s),o.clearSelectedCells(t.dom),C.some(s)})))(i,n);return lt(i)&&(ts(i),d||dc(e,i.dom,c)),r.map((e=>({rng:e,effect:c})))})):C.none()},c=a(qa,(t=>!n(e)||rl(t).rows>1),f,fc),i=a(Va,(t=>!n(e)||rl(t).columns>1),f,fc);return{deleteRow:c,deleteColumn:i,insertRowsBefore:a(Ia,x,f,fc),insertRowsAfter:a(Fa,x,f,fc),insertColumnsBefore:a(Ha,x,s,fc),insertColumnsAfter:a($a,x,s,fc),mergeCells:a(Za,x,f,fc),unmergeCells:a(ec,x,f,fc),pasteColsBefore:a(oc,x,f,fc),pasteColsAfter:a(nc,x,f,fc),pasteRowsBefore:a(rc,x,f,fc),pasteRowsAfter:a(sc,x,f,fc),pasteCells:a(tc,x,f,gc),makeCellsHeader:a(Qa,x,f,fc),unmakeCellsHeader:a(Xa,x,f,fc),makeColumnsHeader:a(Ua,x,f,fc),unmakeColumnsHeader:a(Ga,x,f,fc),makeRowsHeader:a(Ka,x,f,fc),makeRowsBody:a(Ya,x,f,fc),makeRowsFooter:a(Ja,x,f,fc),getTableRowType:cc,getTableCellType:ac,getTableColType:lc}},bc=(e,t,o)=>{const n=Wt(e,t,1);1===o||n<=1?we(e,t):ge(e,t,Math.min(o,n))},wc=(e,t)=>o=>{const n=o.column+o.colspan-1,r=o.column;return n>=e&&r<t},vc=oa([{invalid:["raw"]},{pixels:["value"]},{percent:["value"]}]),yc=(e,t,o)=>{const n=o.substring(0,o.length-e.length),r=parseFloat(n);return n===r.toString()?t(r):vc.invalid(o)},xc={...vc,from:e=>Rt(e,"%")?yc("%",vc.percent,e):Rt(e,"px")?yc("px",vc.pixels,e):vc.invalid(e)},Cc=(e,t,o)=>{const n=xc.from(o),r=P(e,(e=>"0px"===e))?((e,t)=>{const o=e.fold((()=>g("")),(e=>g(e/t+"px")),(()=>g(100/t+"%")));return k(t,o)})(n,e.length):((e,t,o)=>e.fold((()=>t),(e=>((e,t,o)=>{const n=o/t;return E(e,(e=>xc.from(e).fold((()=>e),(e=>e*n+"px"),(e=>e/100*o+"px"))))})(t,o,e)),(e=>((e,t)=>E(e,(e=>xc.from(e).fold((()=>e),(e=>e/t*100+"%"),(e=>e+"%")))))(t,o))))(n,e,t);return Rc(r)},Sc=(e,t)=>0===e.length?t:z(e,((e,t)=>xc.from(t).fold(g(0),h,h)+e),0),Tc=(e,t)=>xc.from(e).fold(g(e),(e=>e+t+"px"),(e=>e+t+"%")),Rc=e=>{if(0===e.length)return e;const t=z(e,((e,t)=>{const o=xc.from(t).fold((()=>({value:t,remainder:0})),(e=>((e,t)=>{const o=Math.floor(e);return{value:o+"px",remainder:e-o}})(e)),(e=>({value:e+"%",remainder:0})));return{output:[o.value].concat(e.output),remainder:e.remainder+o.remainder}}),{output:[],remainder:0}),o=t.output;return o.slice(0,o.length-1).concat([Tc(o[o.length-1],Math.round(t.remainder))])},Dc=xc.from,Oc=(e,t,o)=>{const n=Xo(e),r=n.all,s=nn(n),l=rn(n);t.each((t=>{const o=Dc(t).fold(g("px"),g("px"),g("%")),r=Ao(e),a=((e,t)=>nr(e,t,er,rr))(n,e),c=Cc(a,r,t);sn(n)?((e,t,o)=>{N(t,((t,n)=>{const r=Sc([e[n]],It());Nt(t.element,"width",r+o)}))})(c,l,o):((e,t,o)=>{N(t,(t=>{const n=e.slice(t.column,t.colspan+t.column),r=Sc(n,It());Nt(t.element,"width",r+o)}))})(c,s,o),Nt(e,"width",t)})),o.each((t=>{const o=gn(e),l=((e,t)=>lr(e,t,tr,rr))(n,e);((e,t,o)=>{N(o,(e=>{Lt(e.element,"height")})),N(t,((t,o)=>{Nt(t.element,"height",e[o])}))})(Cc(l,o,t),r,s),Nt(e,"height",t)}))},kc=e=>Un(e).exists((e=>Wn.test(e))),Ec=e=>Un(e).exists((e=>Mn.test(e))),Nc=e=>Un(e).isNone(),Bc=e=>{we(e,"width"),we(e,"height")},_c=e=>{const t=Qn(e);Oc(e,C.some(t),C.none()),Bc(e)},zc=e=>{const t=(e=>Ao(e)+"px")(e);Oc(e,C.some(t),C.none()),Bc(e)},Ac=e=>{Lt(e,"width");const t=Ut(e),o=t.length>0?t:qt(e);N(o,(e=>{Lt(e,"width"),Bc(e)})),Bc(e)},Lc={styles:{"border-collapse":"collapse",width:"100%"},attributes:{border:"1"},colGroups:!1},Wc=(e,t,o,n)=>k(e,(e=>((e,t,o,n)=>{const r=xe.fromTag("tr");for(let s=0;s<e;s++){const e=xe.fromTag(n<t||s<o?"th":"td");s<o&&ge(e,"scope","row"),n<t&&ge(e,"scope","col"),Ie(e,xe.fromTag("br")),Ie(r,e)}return r})(t,o,n,e))),Mc=(e,t)=>{e.selection.select(t.dom,!0),e.selection.collapse(!0)},jc=(e,t,o,n,s)=>{const l=(e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>Vr(e)||!Ur(e)?t:$r(e)?{...t,width:Lr(e)}:{...t,width:Ar})(e,o)})(e),a={styles:l,attributes:Kr(e),colGroups:Yr(e)};return e.undoManager.ignore((()=>{const r=((e,t,o,n,r,s=Lc)=>{const l=xe.fromTag("table"),a="cells"!==r;Bt(l,s.styles),he(l,s.attributes),s.colGroups&&Ie(l,(e=>{const t=xe.fromTag("colgroup");return k(e,(()=>Ie(t,xe.fromTag("col")))),t})(t));const c=Math.min(e,o);if(a&&o>0){const e=xe.fromTag("thead");Ie(l,e);const s=Wc(o,t,"sectionCells"===r?c:0,n);$e(e,s)}const i=xe.fromTag("tbody");Ie(l,i);const m=Wc(a?e-c:e,t,a?0:o,n);return $e(i,m),l})(o,t,s,n,Mr(e),a);ge(r,"data-mce-id","__mce");const l=(e=>{const t=xe.fromTag("div"),o=xe.fromDom(e.dom.cloneNode(!0));return Ie(t,o),(e=>e.dom.innerHTML)(t)})(r);e.insertContent(l),e.addVisual()})),bt(Zr(e),'table[data-mce-id="__mce"]').map((t=>($r(e)?zc(t):Vr(e)?Ac(t):(Hr(e)||(e=>r(e)&&-1!==e.indexOf("%"))(l.width))&&_c(t),ts(t),we(t,"data-mce-id"),((e,t)=>{N(dt(t,"tr"),(t=>{ic(e,t.dom),N(dt(t,"th,td"),(t=>{mc(e,t.dom)}))}))})(e,t),((e,t)=>{bt(t,"td,th").each(b(Mc,e))})(e,t),t.dom))).getOrNull()};var Pc=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const Ic="x-tinymce/dom-table-",Fc=Ic+"rows",Hc=Ic+"columns",$c=e=>{const t=Pc.FakeClipboardItem(e);Pc.write([t])},Vc=e=>{var t;const o=null!==(t=Pc.read())&&void 0!==t?t:[];return V(o,(t=>C.from(t.getType(e))))},qc=e=>{Vc(e).isSome()&&Pc.clear()},Uc=e=>{e.fold(Kc,(e=>$c({[Fc]:e})))},Gc=()=>Vc(Fc),Kc=()=>qc(Fc),Yc=e=>{e.fold(Qc,(e=>$c({[Hc]:e})))},Jc=()=>Vc(Hc),Qc=()=>qc(Hc),Xc=e=>Is(os(e),es(e)).filter(cs),Zc=(e,t)=>{const o=es(e),n=e=>Gt(e,o),l=t=>(e=>Fs(os(e),es(e)).filter(cs))(e).bind((e=>n(e).map((o=>t(o,e))))),a=t=>{e.focus()},c=(t,o=!1)=>l(((n,r)=>{const s=js(Hs(e),n,r);t(n,s,o).each(a)})),i=()=>l(((t,o)=>((e,t,o)=>{const n=Xo(e);return Nl(n,t).bind((e=>{const t=Tl(n,o,!1),r=Vo(t).rows.slice(e[0].row,e[e.length-1].row+e[e.length-1].rowspan),s=j(r,(e=>{const t=_(e.cells,(e=>!e.isLocked));return t.length>0?[{...e,cells:t}]:[]})),l=Rl(s);return xt(l.length>0,l)})).map((e=>E(e,(e=>{const t=Ke(e.element);return N(e.cells,(e=>{const o=Ye(e.element);vl(o,"colspan",e.colspan,1),vl(o,"rowspan",e.rowspan,1),Ie(t,o)})),t}))))})(t,js(Hs(e),t,o),Br(f,xe.fromDom(e.getDoc()),C.none())))),m=()=>l(((t,o)=>((e,t)=>{const o=Xo(e);return Bl(o,t).map((e=>{const t=e[e.length-1],n=e[0].column,r=t.column+t.colspan,s=((e,t,o)=>{if(sn(e)){const n=_(rn(e),wc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return bc(n,"span",o-t),n})),s=xe.fromTag("colgroup");return $e(s,r),[s]}return[]})(o,n,r),l=((e,t,o)=>E(e.all,(e=>{const n=_(e.cells,wc(t,o)),r=E(n,(e=>{const n=Ye(e.element);return bc(n,"colspan",o-t),n})),s=xe.fromTag("tr");return $e(s,r),s})))(o,n,r);return[...s,...l]}))})(t,js(Hs(e),t,o)))),d=(t,o)=>o().each((o=>{const n=E(o,(e=>Ye(e)));l(((o,r)=>{const s=_r(xe.fromDom(e.getDoc())),l=((e,t,o,n)=>({selection:Ns(e),clipboard:o,generators:n}))(Hs(e),0,n,s);t(o,l).each(a)}))})),g=e=>(t,o)=>((e,t)=>X(e,t)?C.from(e[t]):C.none())(o,"type").each((t=>{c(e(t),o.no_events)}));G({mceTableSplitCells:()=>c(t.unmergeCells),mceTableMergeCells:()=>c(t.mergeCells),mceTableInsertRowBefore:()=>c(t.insertRowsBefore),mceTableInsertRowAfter:()=>c(t.insertRowsAfter),mceTableInsertColBefore:()=>c(t.insertColumnsBefore),mceTableInsertColAfter:()=>c(t.insertColumnsAfter),mceTableDeleteCol:()=>c(t.deleteColumn),mceTableDeleteRow:()=>c(t.deleteRow),mceTableCutCol:()=>m().each((e=>{Yc(e),c(t.deleteColumn)})),mceTableCutRow:()=>i().each((e=>{Uc(e),c(t.deleteRow)})),mceTableCopyCol:()=>m().each((e=>Yc(e))),mceTableCopyRow:()=>i().each((e=>Uc(e))),mceTablePasteColBefore:()=>d(t.pasteColsBefore,Jc),mceTablePasteColAfter:()=>d(t.pasteColsAfter,Jc),mceTablePasteRowBefore:()=>d(t.pasteRowsBefore,Gc),mceTablePasteRowAfter:()=>d(t.pasteRowsAfter,Gc),mceTableDelete:()=>Xc(e).each((t=>{Gt(t,o).filter(w(o)).each((t=>{const o=xe.fromText("");if(je(t,o),qe(t),e.dom.isEmpty(e.getBody()))e.setContent(""),e.selection.setCursorLocation();else{const t=e.dom.createRng();t.setStart(o.dom,0),t.setEnd(o.dom,0),e.selection.setRng(t),e.nodeChanged()}}))})),mceTableCellToggleClass:(t,o)=>{l((t=>{const n=Hs(e),r=P(n,(t=>e.formatter.match("tablecellclass",{value:o},t.dom))),s=r?e.formatter.remove:e.formatter.apply;N(n,(e=>s("tablecellclass",{value:o},e.dom))),dc(e,t.dom,uc)}))},mceTableToggleClass:(t,o)=>{l((t=>{e.formatter.toggle("tableclass",{value:o},t.dom),dc(e,t.dom,uc)}))},mceTableToggleCaption:()=>{Xc(e).each((t=>{Gt(t,o).each((o=>{pt(o,"caption").fold((()=>{const t=xe.fromTag("caption");Ie(t,xe.fromText("Caption")),((e,t,o)=>{We(e,0).fold((()=>{Ie(e,t)}),(e=>{Me(e,t)}))})(o,t),e.selection.setCursorLocation(t.dom,0)}),(n=>{ue("caption")(t)&&Te("td",o).each((t=>e.selection.setCursorLocation(t.dom,0))),qe(n)})),dc(e,o.dom,fc)}))}))},mceTableSizingMode:(t,n)=>(t=>Xc(e).each((n=>{Vr(e)||$r(e)||Hr(e)||Gt(n,o).each((o=>{"relative"!==t||kc(o)?"fixed"!==t||Ec(o)?"responsive"!==t||Nc(o)||Ac(o):zc(o):_c(o),ts(o),dc(e,o.dom,fc)}))})))(n),mceTableCellType:g((e=>"th"===e?t.makeCellsHeader:t.unmakeCellsHeader)),mceTableColType:g((e=>"th"===e?t.makeColumnsHeader:t.unmakeColumnsHeader)),mceTableRowType:g((e=>{switch(e){case"header":return t.makeRowsHeader;case"footer":return t.makeRowsFooter;default:return t.makeRowsBody}}))},((t,o)=>e.addCommand(o,t))),e.addCommand("mceInsertTable",((t,o)=>{((e,t,o,n={})=>{const r=e=>u(e)&&e>0;if(r(t)&&r(o)){const r=n.headerRows||0,s=n.headerColumns||0;return jc(e,o,t,s,r)}console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.")})(e,o.rows,o.columns,o.options)})),e.addCommand("mceTableApplyCellStyle",((t,o)=>{const l=e=>"tablecell"+e.toLowerCase().replace("-","");if(!s(o))return;const a=_(Hs(e),cs);if(0===a.length)return;const c=((e,t)=>{const o={};return((e,t,o,n)=>{G(e,((e,r)=>{(t(e,r)?o:n)(e,r)}))})(e,t,(e=>(t,o)=>{e[o]=t})(o),f),o})(o,((t,o)=>e.formatter.has(l(o))&&r(t)));(e=>{for(const t in e)if(U.call(e,t))return!1;return!0})(c)||(G(c,((t,o)=>{const n=l(o);N(a,(o=>{""===t?e.formatter.remove(n,{value:null},o.dom,!0):e.formatter.apply(n,{value:t},o.dom)}))})),n(a[0]).each((t=>dc(e,t.dom,uc))))}))},ei=oa([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),ti={before:ei.before,on:ei.on,after:ei.after,cata:(e,t,o,n)=>e.fold(t,o,n),getStart:e=>e.fold(h,h,h)},oi=(e,t)=>({selection:e,kill:t}),ni=(e,t)=>{const o=e.document.createRange();return o.selectNode(t.dom),o},ri=(e,t)=>{const o=e.document.createRange();return si(o,t),o},si=(e,t)=>e.selectNodeContents(t.dom),li=(e,t,o)=>{const n=e.document.createRange();var r;return r=n,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},ai=(e,t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},ci=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),ii=oa([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),mi=(e,t,o)=>t(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset),di=(e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:g(e),rtl:C.none}),relative:(t,o)=>({ltr:Zt((()=>li(e,t,o))),rtl:Zt((()=>C.some(li(e,o,t))))}),exact:(t,o,n,r)=>({ltr:Zt((()=>ai(e,t,o,n,r))),rtl:Zt((()=>C.some(ai(e,n,r,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>ii.rtl(xe.fromDom(e.endContainer),e.endOffset,xe.fromDom(e.startContainer),e.startOffset))).getOrThunk((()=>mi(0,ii.ltr,o))):mi(0,ii.ltr,o)})(0,o)},ui=(e,t)=>di(e,t).match({ltr:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(t.dom,o),s.setEnd(n.dom,r),s},rtl:(t,o,n,r)=>{const s=e.document.createRange();return s.setStart(n.dom,r),s.setEnd(t.dom,o),s}});ii.ltr,ii.rtl;const fi=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),gi=(e,t,o,n)=>({start:ti.on(e,t),finish:ti.on(o,n)}),hi=(e,t)=>{const o=ui(e,t);return fi(xe.fromDom(o.startContainer),o.startOffset,xe.fromDom(o.endContainer),o.endOffset)},pi=gi,bi=(e,t,o,n,r)=>Re(o,n)?C.none():Ts(o,n,t).bind((t=>{const n=t.boxes.getOr([]);return n.length>1?(r(e,n,t.start,t.finish),C.some(oi(C.some(pi(o,0,o,wr(o))),!0))):C.none()})),wi=(e,t)=>({item:e,mode:t}),vi=(e,t,o,n=yi)=>e.property().parent(t).map((e=>wi(e,n))),yi=(e,t,o,n=xi)=>o.sibling(e,t).map((e=>wi(e,n))),xi=(e,t,o,n=xi)=>{const r=e.property().children(t);return o.first(r).map((e=>wi(e,n)))},Ci=[{current:vi,next:yi,fallback:C.none()},{current:yi,next:xi,fallback:C.some(vi)},{current:xi,next:xi,fallback:C.some(yi)}],Si=(e,t,o,n,r=Ci)=>L(r,(e=>e.current===o)).bind((o=>o.current(e,t,n,o.next).orThunk((()=>o.fallback.bind((o=>Si(e,t,o,n))))))),Ti=(e,t,o,n,r,s)=>Si(e,t,n,r).bind((t=>s(t.item)?C.none():o(t.item)?C.some(t.item):Ti(e,t.item,o,t.mode,r,s))),Ri=e=>t=>0===e.property().children(t).length,Di=(e,t,o,n)=>Ti(e,t,o,yi,{sibling:(e,t)=>e.query().prevSibling(t),first:e=>e.length>0?C.some(e[e.length-1]):C.none()},n),Oi=(e,t,o,n)=>Ti(e,t,o,yi,{sibling:(e,t)=>e.query().nextSibling(t),first:e=>e.length>0?C.some(e[0]):C.none()},n),ki=ws(),Ei=(e,t)=>((e,t,o)=>Di(e,t,Ri(e),o))(ki,e,t),Ni=(e,t)=>((e,t,o)=>Oi(e,t,Ri(e),o))(ki,e,t),Bi=oa([{none:["message"]},{success:[]},{failedUp:["cell"]},{failedDown:["cell"]}]),_i=e=>wt(e,"tr"),zi={...Bi,verify:(e,t,o,n,r,s,l)=>wt(n,"td,th",l).bind((o=>wt(t,"td,th",l).map((t=>Re(o,t)?Re(n,o)&&wr(o)===r?s(t):Bi.none("in same cell"):Cs(_i,[o,t]).fold((()=>((e,t,o)=>{const n=e.getRect(t),r=e.getRect(o);return r.right>n.left&&r.left<n.right})(e,t,o)?Bi.success():s(t)),(e=>s(t))))))).getOr(Bi.none("default")),cata:(e,t,o,n,r)=>e.fold(t,o,n,r)},Ai=ue("br"),Li=(e,t,o)=>t(e,o).bind((e=>ie(e)&&0===hr(e).trim().length?Li(e,t,o):C.some(e))),Wi=(e,t,o,n)=>((e,t)=>We(e,t).filter(Ai).orThunk((()=>We(e,t-1).filter(Ai))))(t,o).bind((t=>n.traverse(t).fold((()=>Li(t,n.gather,e).map(n.relative)),(e=>(e=>Ne(e).bind((t=>{const o=Le(t);return((e,t)=>W(e,b(Re,t)))(o,e).map((n=>((e,t,o,n)=>({parent:e,children:t,element:o,index:n}))(t,o,e,n)))})))(e).map((e=>ti.on(e.parent,e.index))))))),Mi=(e,t)=>({left:e.left,top:e.top+t,right:e.right,bottom:e.bottom+t}),ji=(e,t)=>({left:e.left,top:e.top-t,right:e.right,bottom:e.bottom-t}),Pi=(e,t,o)=>({left:e.left+t,top:e.top+o,right:e.right+t,bottom:e.bottom+o}),Ii=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom}),Fi=(e,t)=>C.some(e.getRect(t)),Hi=(e,t,o)=>ce(t)?Fi(e,t).map(Ii):ie(t)?((e,t,o)=>o>=0&&o<wr(t)?e.getRangedRect(t,o,t,o+1):o>0?e.getRangedRect(t,o-1,t,o):C.none())(e,t,o).map(Ii):C.none(),$i=(e,t)=>ce(t)?Fi(e,t).map(Ii):ie(t)?e.getRangedRect(t,0,t,wr(t)).map(Ii):C.none(),Vi=oa([{none:[]},{retry:["caret"]}]),qi=(e,t,o)=>gt(t,wa).fold(y,(t=>$i(e,t).exists((e=>((e,t)=>e.left<t.left||Math.abs(t.right-e.left)<1||e.left>t.right)(o,e))))),Ui={point:e=>e.bottom,adjuster:(e,t,o,n,r)=>{const s=Mi(r,5);return Math.abs(o.bottom-n.bottom)<1||o.top>r.bottom?Vi.retry(s):o.top===r.bottom?Vi.retry(Mi(r,1)):qi(e,t,r)?Vi.retry(Pi(s,5,0)):Vi.none()},move:Mi,gather:Ni},Gi=(e,t,o,n,r)=>0===r?C.some(n):((e,t,o)=>e.elementFromPoint(t,o).filter((e=>"table"===ne(e))).isSome())(e,n.left,t.point(n))?((e,t,o,n,r)=>Gi(e,t,o,t.move(n,5),r))(e,t,o,n,r-1):e.situsFromPoint(n.left,t.point(n)).bind((s=>s.start.fold(C.none,(s=>$i(e,s).bind((l=>t.adjuster(e,s,l,o,n).fold(C.none,(n=>Gi(e,t,o,n,r-1))))).orThunk((()=>C.some(n)))),C.none))),Ki=(e,t,o)=>{const n=e.move(o,5),r=Gi(t,e,o,n,100).getOr(n);return((e,t,o)=>e.point(t)>o.getInnerHeight()?C.some(e.point(t)-o.getInnerHeight()):e.point(t)<0?C.some(-e.point(t)):C.none())(e,r,t).fold((()=>t.situsFromPoint(r.left,e.point(r))),(o=>(t.scrollBy(0,o),t.situsFromPoint(r.left,e.point(r)-o))))},Yi={tryUp:b(Ki,{point:e=>e.top,adjuster:(e,t,o,n,r)=>{const s=ji(r,5);return Math.abs(o.top-n.top)<1||o.bottom<r.top?Vi.retry(s):o.bottom===r.top?Vi.retry(ji(r,1)):qi(e,t,r)?Vi.retry(Pi(s,5,0)):Vi.none()},move:ji,gather:Ei}),tryDown:b(Ki,Ui),getJumpSize:g(5)},Ji=(e,t,o)=>e.getSelection().bind((n=>((e,t,o,n)=>{const r=Ai(t)?((e,t,o)=>o.traverse(t).orThunk((()=>Li(t,o.gather,e))).map(o.relative))(e,t,n):Wi(e,t,o,n);return r.map((e=>({start:e,finish:e})))})(t,n.finish,n.foffset,o).fold((()=>C.some(Vs(n.finish,n.foffset))),(r=>{const s=e.fromSitus(r);return l=zi.verify(e,n.finish,n.foffset,s.finish,s.foffset,o.failure,t),zi.cata(l,(e=>C.none()),(()=>C.none()),(e=>C.some(Vs(e,0))),(e=>C.some(Vs(e,wr(e)))));var l})))),Qi=(e,t,o,n,r,s)=>0===s?C.none():em(e,t,o,n,r).bind((l=>{const a=e.fromSitus(l),c=zi.verify(e,o,n,a.finish,a.foffset,r.failure,t);return zi.cata(c,(()=>C.none()),(()=>C.some(l)),(l=>Re(o,l)&&0===n?Xi(e,o,n,ji,r):Qi(e,t,l,0,r,s-1)),(l=>Re(o,l)&&n===wr(l)?Xi(e,o,n,Mi,r):Qi(e,t,l,wr(l),r,s-1)))})),Xi=(e,t,o,n,r)=>Hi(e,t,o).bind((t=>Zi(e,r,n(t,Yi.getJumpSize())))),Zi=(e,t,o)=>{const n=No().browser;return n.isChromium()||n.isSafari()||n.isFirefox()?t.retry(e,o):C.none()},em=(e,t,o,n,r)=>Hi(e,o,n).bind((t=>Zi(e,r,t))),tm=(e,t,o,n,r)=>wt(n,"td,th",t).bind((n=>wt(n,"table",t).bind((s=>((e,t)=>ft(e,(e=>Ne(e).exists((e=>Re(e,t)))),void 0).isSome())(r,s)?((e,t,o)=>Ji(e,t,o).bind((n=>Qi(e,t,n.element,n.offset,o,20).map(e.fromSitus))))(e,t,o).bind((e=>wt(e.finish,"td,th",t).map((t=>({start:n,finish:t,range:e}))))):C.none())))),om=(e,t,o,n,r,s)=>s(n,t).orThunk((()=>tm(e,t,o,n,r).map((e=>{const t=e.range;return oi(C.some(pi(t.start,t.soffset,t.finish,t.foffset)),!0)})))),nm=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[0])?((e,t,o)=>Di(ki,e,(e=>Cr(e).isSome()),o))(o,0,t).map((e=>{const t=wr(e);return oi(C.some(pi(e,t,e,t)),!0)})):C.none()})))),rm=(e,t)=>wt(e,"tr",t).bind((e=>wt(e,"table",t).bind((o=>{const n=dt(o,"tr");return Re(e,n[n.length-1])?((e,t,o)=>Oi(ki,e,(e=>xr(e).isSome()),o))(o,0,t).map((e=>oi(C.some(pi(e,0,e,0)),!0))):C.none()})))),sm=(e,t,o,n,r,s,l)=>tm(e,o,n,r,s).bind((e=>bi(t,o,e.start,e.finish,l))),lm=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},am=()=>{const e=(e=>{const t=lm(C.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(C.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(C.some(e))}}})(f);return{...e,on:t=>e.get().each(t)}},cm=(e,t)=>wt(e,"td,th",t),im=e=>Be(e).exists(Qr),mm={traverse:Ae,gather:Ni,relative:ti.before,retry:Yi.tryDown,failure:zi.failedDown},dm={traverse:ze,gather:Ei,relative:ti.before,retry:Yi.tryUp,failure:zi.failedUp},um=e=>t=>t===e,fm=um(38),gm=um(40),hm=e=>e>=37&&e<=40,pm={isBackward:um(37),isForward:um(39)},bm={isBackward:um(39),isForward:um(37)},wm=oa([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),vm={domRange:wm.domRange,relative:wm.relative,exact:wm.exact,exactFromRange:e=>wm.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>xe.fromDom(e.startContainer),relative:(e,t)=>ti.getStart(e),exact:(e,t,o,n)=>e}))(e);return xe.fromDom(Ee(t).dom.defaultView)},range:fi},ym=document.caretPositionFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretPositionFromPoint)||void 0===r?void 0:r.call(n,t,o)).bind((t=>{if(null===t.offsetNode)return C.none();const o=e.dom.createRange();return o.setStart(t.offsetNode,t.offset),o.collapse(),C.some(o)}))}:document.caretRangeFromPoint?(e,t,o)=>{var n,r;return C.from(null===(r=(n=e.dom).caretRangeFromPoint)||void 0===r?void 0:r.call(n,t,o))}:C.none,xm=(e,t)=>{const o=ne(e);return"input"===o?ti.after(e):D(["br","img"],o)?0===t?ti.before(e):ti.after(e):ti.on(e,t)},Cm=e=>C.from(e.getSelection()),Sm=(e,t)=>{Cm(e).each((e=>{e.removeAllRanges(),e.addRange(t)}))},Tm=(e,t,o,n,r)=>{const s=ai(e,t,o,n,r);Sm(e,s)},Rm=(e,t)=>di(e,t).match({ltr:(t,o,n,r)=>{Tm(e,t,o,n,r)},rtl:(t,o,n,r)=>{Cm(e).each((s=>{if(s.setBaseAndExtent)s.setBaseAndExtent(t.dom,o,n.dom,r);else if(s.extend)try{((e,t,o,n,r,s)=>{t.collapse(o.dom,n),t.extend(r.dom,s)})(0,s,t,o,n,r)}catch(s){Tm(e,n,r,t,o)}else Tm(e,n,r,t,o)}))}}),Dm=(e,t,o,n,r)=>{const s=((e,t,o,n)=>{const r=xm(e,t),s=xm(o,n);return vm.relative(r,s)})(t,o,n,r);Rm(e,s)},Om=(e,t,o)=>{const n=((e,t)=>{const o=e.fold(ti.before,xm,ti.after),n=t.fold(ti.before,xm,ti.after);return vm.relative(o,n)})(t,o);Rm(e,n)},km=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return C.some(fi(xe.fromDom(t.startContainer),t.startOffset,xe.fromDom(o.endContainer),o.endOffset))}return C.none()},Em=e=>{if(null===e.anchorNode||null===e.focusNode)return km(e);{const t=xe.fromDom(e.anchorNode),o=xe.fromDom(e.focusNode);return((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=ke(e).dom.createRange();return r.setStart(e.dom,t),r.setEnd(o.dom,n),r})(e,t,o,n),s=Re(e,o)&&t===n;return r.collapsed&&!s})(t,e.anchorOffset,o,e.focusOffset)?C.some(fi(t,e.anchorOffset,o,e.focusOffset)):km(e)}},Nm=(e,t,o=!0)=>{const n=(o?ri:ni)(e,t);Sm(e,n)},Bm=e=>(e=>Cm(e).filter((e=>e.rangeCount>0)).bind(Em))(e).map((e=>vm.exact(e.start,e.soffset,e.finish,e.foffset))),_m=e=>({elementFromPoint:(t,o)=>xe.fromPoint(xe.fromDom(e.document),t,o),getRect:e=>e.dom.getBoundingClientRect(),getRangedRect:(t,o,n,r)=>{const s=vm.exact(t,o,n,r);return((e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?C.some(o).map(ci):C.none()})(ui(e,t)))(e,s)},getSelection:()=>Bm(e).map((t=>hi(e,t))),fromSitus:t=>{const o=vm.relative(t.start,t.finish);return hi(e,o)},situsFromPoint:(t,o)=>((e,t,o)=>((e,t,o)=>{const n=xe.fromDom(e.document);return ym(n,t,o).map((e=>fi(xe.fromDom(e.startContainer),e.startOffset,xe.fromDom(e.endContainer),e.endOffset)))})(e,t,o))(e,t,o).map((e=>gi(e.start,e.soffset,e.finish,e.foffset))),clearSelection:()=>{(e=>{Cm(e).each((e=>e.removeAllRanges()))})(e)},collapseSelection:(t=!1)=>{Bm(e).each((o=>o.fold((e=>e.collapse(t)),((o,n)=>{const r=t?o:n;Om(e,r,r)}),((o,n,r,s)=>{const l=t?o:r,a=t?n:s;Dm(e,l,a,l,a)}))))},setSelection:t=>{Dm(e,t.start,t.soffset,t.finish,t.foffset)},setRelativeSelection:(t,o)=>{Om(e,t,o)},selectNode:t=>{Nm(e,t,!1)},selectContents:t=>{Nm(e,t)},getInnerHeight:()=>e.innerHeight,getScrollY:()=>(e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return bn(o,n)})(xe.fromDom(e.document)).top,scrollBy:(t,o)=>{((e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollBy(e,t)})(t,o,xe.fromDom(e.document))}}),zm=(e,t)=>({rows:e,cols:t}),Am=e=>gt(e,ae).exists(Qr),Lm=(e,t)=>Am(e)||Am(t),Wm=e=>void 0!==e.dom.classList,Mm=(e,t)=>((e,t,o)=>{const n=((e,t)=>{const o=pe(e,t);return void 0===o||""===o?[]:o.split(" ")})(e,t).concat([o]);return ge(e,t,n.join(" ")),!0})(e,"class",t),jm=(e,t)=>{Wm(e)?e.dom.classList.add(t):Mm(e,t)},Pm=(e,t)=>Wm(e)&&e.dom.classList.contains(t),Im=()=>({tag:"none"}),Fm=e=>({tag:"multiple",elements:e}),Hm=e=>({tag:"single",element:e}),$m=e=>{const t=xe.fromDom((e=>{if(nt()&&m(e.target)){const t=xe.fromDom(e.target);if(ce(t)&&m(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return H(t)}}return C.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),r=(s=n,l=o,(...e)=>s(l.apply(null,e)));var s,l;return((e,t,o,n,r,s,l)=>({target:e,x:t,y:o,stop:n,prevent:r,kill:s,raw:l}))(t,e.clientX,e.clientY,o,n,r,e)},Vm=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},qm=x,Um=(e,t,o)=>((e,t,o,n)=>((e,t,o,n,r)=>{const s=((e,t)=>o=>{e(o)&&t($m(o))})(o,n);return e.dom.addEventListener(t,s,r),{unbind:b(Vm,e,t,s,r)}})(e,t,o,n,!1))(e,t,qm,o),Gm=$m,Km=e=>!Pm(xe.fromDom(e.target),"ephox-snooker-resizer-bar"),Ym=(e,t)=>{const o=(r=Ms.selectedSelector,{get:()=>ks(xe.fromDom(e.getBody()),r).fold((()=>Fs(os(e),es(e)).fold(Im,Hm)),Fm)}),n=((e,t,o)=>{const n=t=>{we(t,e.selected),we(t,e.firstSelected),we(t,e.lastSelected)},r=t=>{ge(t,e.selected,"1")},s=e=>{l(e),o()},l=t=>{const o=dt(t,`${e.selectedSelector},${e.firstSelectedSelector},${e.lastSelectedSelector}`);N(o,n)};return{clearBeforeUpdate:l,clear:s,selectRange:(o,n,l,a)=>{s(o),N(n,r),ge(l,e.firstSelected,"1"),ge(a,e.lastSelected,"1"),t(n,l,a)},selectedSelector:e.selectedSelector,firstSelectedSelector:e.firstSelectedSelector,lastSelectedSelector:e.lastSelectedSelector}})(Ms,((t,o,n)=>{Gt(o).each((r=>{const s=E(t,(e=>e.dom)),l=Wr(e),a=Br(f,xe.fromDom(e.getDoc()),l),c=((e,t,o)=>{const n=Xo(e);return Nl(n,t).map((e=>{const t=Tl(n,o,!1),{rows:r}=Vo(t),s=((e,t)=>{const o=e.slice(0,t[t.length-1].row+1),n=Rl(o);return j(n,(e=>{const o=e.cells.slice(0,t[t.length-1].column+1);return E(o,(e=>e.element))}))})(r,e),l=((e,t)=>{const o=e.slice(t[0].row+t[0].rowspan-1,e.length),n=Rl(o);return j(n,(e=>{const o=e.cells.slice(t[0].column+t[0].colspan-1,e.cells.length);return E(o,(e=>e.element))}))})(r,e);return{upOrLeftCells:s,downOrRightCells:l}}))})(r,{selection:Hs(e)},a).map((e=>K(e,(e=>E(e,(e=>e.dom)))))).getOrUndefined();((e,t,o,n,r)=>{e.dispatch("TableSelectionChange",{cells:t,start:o,finish:n,otherCells:r})})(e,s,o.dom,n.dom,c)}))}),(()=>(e=>{e.dispatch("TableSelectionClear")})(e)));var r;return e.on("init",(o=>{const r=e.getWin(),s=Zr(e),l=es(e),a=((e,t,o,n)=>{const r=((e,t,o,n)=>{const r=am(),s=r.clear,l=s=>{r.on((r=>{n.clearBeforeUpdate(t),cm(s.target,o).each((l=>{Ts(r,l,o).each((o=>{const r=o.boxes.getOr([]);if(1===r.length){const e=r[0],o="false"===Xr(e),l=vt(Jr(s.target),e,Re);o&&l&&n.selectRange(t,r,e,e)}else r.length>1&&(n.selectRange(t,r,o.start,o.finish),e.selectContents(l))}))}))}))};return{clearstate:s,mousedown:e=>{n.clear(t),cm(e.target,o).filter(im).each(r.set)},mouseover:e=>{l(e)},mouseup:e=>{l(e),s()}}})(_m(e),t,o,n);return{clearstate:r.clearstate,mousedown:r.mousedown,mouseover:r.mouseover,mouseup:r.mouseup}})(r,s,l,n),c=((e,t,o,n)=>{const r=_m(e),s=()=>(n.clear(t),C.none());return{keydown:(e,l,a,c,i,m)=>{const d=e.raw,u=d.which,f=!0===d.shiftKey,g=Rs(t,n.selectedSelector).fold((()=>(hm(u)&&!f&&n.clearBeforeUpdate(t),hm(u)&&f&&!Lm(l,c)?C.none:gm(u)&&f?b(sm,r,t,o,mm,c,l,n.selectRange):fm(u)&&f?b(sm,r,t,o,dm,c,l,n.selectRange):gm(u)?b(om,r,o,mm,c,l,rm):fm(u)?b(om,r,o,dm,c,l,nm):C.none)),(e=>{const o=o=>()=>{const s=V(o,(o=>((e,t,o,n,r)=>Os(n,e,t,r.firstSelectedSelector,r.lastSelectedSelector).map((e=>(r.clearBeforeUpdate(o),r.selectRange(o,e.boxes,e.start,e.finish),e.boxes))))(o.rows,o.cols,t,e,n)));return s.fold((()=>Ds(t,n.firstSelectedSelector,n.lastSelectedSelector).map((e=>{const o=gm(u)||m.isForward(u)?ti.after:ti.before;return r.setRelativeSelection(ti.on(e.first,0),o(e.table)),n.clear(t),oi(C.none(),!0)}))),(e=>C.some(oi(C.none(),!0))))};return hm(u)&&f&&!Lm(l,c)?C.none:gm(u)&&f?o([zm(1,0)]):fm(u)&&f?o([zm(-1,0)]):m.isBackward(u)&&f?o([zm(0,-1),zm(-1,0)]):m.isForward(u)&&f?o([zm(0,1),zm(1,0)]):hm(u)&&!f?s:C.none}));return g()},keyup:(e,r,s,l,a)=>Rs(t,n.selectedSelector).fold((()=>{const c=e.raw,i=c.which;return!0===c.shiftKey&&hm(i)&&Lm(r,l)?((e,t,o,n,r,s,l)=>Re(o,r)&&n===s?C.none():wt(o,"td,th",t).bind((o=>wt(r,"td,th",t).bind((n=>bi(e,t,o,n,l))))))(t,o,r,s,l,a,n.selectRange):C.none()}),C.none)}})(r,s,l,n),i=((e,t,o,n)=>{const r=_m(e);return(e,s)=>{n.clearBeforeUpdate(t),Ts(e,s,o).each((e=>{const o=e.boxes.getOr([]);n.selectRange(t,o,e.start,e.finish),r.selectContents(s),r.collapseSelection()}))}})(r,s,l,n);e.on("TableSelectorChange",(e=>i(e.start,e.finish)));const m=(t,o)=>{(e=>!0===e.raw.shiftKey)(t)&&(o.kill&&t.kill(),o.selection.each((t=>{const o=vm.relative(t.start,t.finish),n=ui(r,o);e.selection.setRng(n)})))},d=e=>0===e.button,u=(()=>{const e=lm(xe.fromDom(s)),t=lm(0);return{touchEnd:o=>{const n=xe.fromDom(o.target);if(ue("td")(n)||ue("th")(n)){const r=e.get(),s=t.get();Re(r,n)&&o.timeStamp-s<300&&(o.preventDefault(),i(n,n))}e.set(n),t.set(o.timeStamp)}}})();e.on("dragstart",(e=>{a.clearstate()})),e.on("mousedown",(e=>{d(e)&&Km(e)&&a.mousedown(Gm(e))})),e.on("mouseover",(e=>{var t;void 0!==(t=e).buttons&&0==(1&t.buttons)||!Km(e)||a.mouseover(Gm(e))})),e.on("mouseup",(e=>{d(e)&&Km(e)&&a.mouseup(Gm(e))})),e.on("touchend",u.touchEnd),e.on("keyup",(t=>{const o=Gm(t);if(o.raw.shiftKey&&hm(o.raw.which)){const t=e.selection.getRng(),n=xe.fromDom(t.startContainer),r=xe.fromDom(t.endContainer);c.keyup(o,n,t.startOffset,r,t.endOffset).each((e=>{m(o,e)}))}})),e.on("keydown",(o=>{const n=Gm(o);t.hide();const r=e.selection.getRng(),s=xe.fromDom(r.startContainer),l=xe.fromDom(r.endContainer),a=dn(pm,bm)(xe.fromDom(e.selection.getStart()));c.keydown(n,s,r.startOffset,l,r.endOffset,a).each((e=>{m(n,e)})),t.show()})),e.on("NodeChange",(()=>{const t=e.selection,o=xe.fromDom(t.getStart()),r=xe.fromDom(t.getEnd());Cs(Gt,[o,r]).fold((()=>n.clear(s)),f)}))})),e.on("PreInit",(()=>{e.serializer.addTempAttr(Ms.firstSelected),e.serializer.addTempAttr(Ms.lastSelected)})),{getSelectedCells:()=>((e,t,o,n)=>{switch(e.tag){case"none":return t();case"single":return(e=>[e.dom])(e.element);case"multiple":return(e=>E(e,(e=>e.dom)))(e.elements)}})(o.get(),g([])),clearSelectedCells:e=>n.clear(xe.fromDom(e))}},Jm=e=>{let t=[];return{bind:e=>{if(void 0===e)throw new Error("Event bind error: undefined handler");t.push(e)},unbind:e=>{t=_(t,(t=>t!==e))},trigger:(...o)=>{const n={};N(e,((e,t)=>{n[e]=o[t]})),N(t,(e=>{e(n)}))}}},Qm=e=>({registry:K(e,(e=>({bind:e.bind,unbind:e.unbind}))),trigger:K(e,(e=>e.trigger))}),Xm=e=>e.slice(0).sort(),Zm=(e,t)=>{const o=_(t,(t=>!D(e,t)));o.length>0&&(e=>{throw new Error("Unsupported keys for object: "+Xm(e).join(", "))})(o)},ed=e=>((e,t)=>((e,t,o)=>{if(0===t.length)throw new Error("You must specify at least one required field.");return((e,t)=>{if(!l(t))throw new Error("The "+e+" fields must be an array. Was: "+t+".");N(t,(t=>{if(!r(t))throw new Error("The value "+t+" in the "+e+" fields was not a string.")}))})("required",t),(e=>{const t=Xm(e);L(t,((e,o)=>o<t.length-1&&e===t[o+1])).each((e=>{throw new Error("The field: "+e+" occurs more than once in the combined fields: ["+t.join(", ")+"].")}))})(t),n=>{const r=q(n);P(t,(e=>D(r,e)))||((e,t)=>{throw new Error("All required keys ("+Xm(e).join(", ")+") were not specified. Specified keys were: "+Xm(t).join(", ")+".")})(t,r),e(t,r);const s=_(t,(e=>!o.validate(n[e],e)));return s.length>0&&((e,t)=>{throw new Error("All values need to be of type: "+t+". Keys ("+Xm(e).join(", ")+") were not.")})(s,o.label),n}})(e,t,{validate:d,label:"function"}))(Zm,e),td=ed(["compare","extract","mutate","sink"]),od=ed(["element","start","stop","destroy"]),nd=ed(["forceDrop","drop","move","delayDrop"]),rd=()=>{const e=(()=>{const e=Qm({move:Jm(["info"])});return{onEvent:f,reset:f,events:e.registry}})(),t=(()=>{let e=C.none();const t=Qm({move:Jm(["info"])});return{onEvent:(o,n)=>{n.extract(o).each((o=>{const r=((t,o)=>{const n=e.map((e=>t.compare(e,o)));return e=C.some(o),n})(n,o);r.each((e=>{t.trigger.move(e)}))}))},reset:()=>{e=C.none()},events:t.registry}})();let o=e;return{on:()=>{o.reset(),o=t},off:()=>{o.reset(),o=e},isOn:()=>o===t,onEvent:(e,t)=>{o.onEvent(e,t)},events:t.events}},sd=e=>{const t=e.replace(/\./g,"-");return{resolve:e=>t+"-"+e}},ld=sd("ephox-dragster").resolve;var ad=td({compare:(e,t)=>bn(t.left-e.left,t.top-e.top),extract:e=>C.some(bn(e.x,e.y)),sink:(e,t)=>{const o=(e=>{const t={layerClass:ld("blocker"),...e},o=xe.fromTag("div");return ge(o,"role","presentation"),Bt(o,{position:"fixed",left:"0px",top:"0px",width:"100%",height:"100%"}),jm(o,ld("blocker")),jm(o,t.layerClass),{element:g(o),destroy:()=>{qe(o)}}})(t),n=Um(o.element(),"mousedown",e.forceDrop),r=Um(o.element(),"mouseup",e.drop),s=Um(o.element(),"mousemove",e.move),l=Um(o.element(),"mouseout",e.delayDrop);return od({element:o.element,start:e=>{Ie(e,o.element())},stop:()=>{qe(o.element())},destroy:()=>{o.destroy(),r.unbind(),s.unbind(),l.unbind(),n.unbind()}})},mutate:(e,t)=>{e.mutate(t.left,t.top)}});const cd=sd("ephox-snooker").resolve,id=cd("resizer-bar"),md=cd("resizer-rows"),dd=cd("resizer-cols"),ud=e=>{const t=dt(e.parent(),"."+id);N(t,qe)},fd=(e,t,o)=>{const n=e.origin();N(t,(t=>{t.each((t=>{const r=o(n,t);jm(r,id),Ie(e.parent(),r)}))}))},gd=(e,t,o,n,r)=>{const s=vn(o),l=t.isResizable,a=n.length>0?Bn.positions(n,o):[],c=a.length>0?((e,t)=>j(e.all,((e,o)=>t(e.element)?[o]:[])))(e,l):[];((e,t,o,n)=>{fd(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t+"px",top:o-3.5+"px",height:"7px",width:n+"px"}),he(s,{"data-row":e,role:"presentation"}),s})(t.row,o.left-e.left,t.y-e.top,n);return jm(r,md),r}))})(t,_(a,((e,t)=>O(c,(e=>t===e)))),s,Lo(o));const i=r.length>0?zn.positions(r,o):[],m=i.length>0?((e,t)=>{const o=[];return k(e.grid.columns,(n=>{ln(e,n).map((e=>e.element)).forall(t)&&o.push(n)})),_(o,(o=>{const n=on(e,(e=>e.column===o));return P(n,(e=>t(e.element)))}))})(e,l):[];((e,t,o,n)=>{fd(e,t,((e,t)=>{const r=((e,t,o,n,r)=>{const s=xe.fromTag("div");return Bt(s,{position:"absolute",left:t-3.5+"px",top:o+"px",height:r+"px",width:"7px"}),he(s,{"data-column":e,role:"presentation"}),s})(t.col,t.x-e.left,o.top-e.top,0,n);return jm(r,dd),r}))})(t,_(i,((e,t)=>O(m,(e=>t===e)))),s,hn(o))},hd=(e,t)=>{if(ud(e),e.isResizable(t)){const o=Xo(t),n=mn(o),r=an(o);gd(o,e,t,n,r)}},pd=(e,t)=>{const o=dt(e.parent(),"."+id);N(o,t)},bd=e=>{pd(e,(e=>{Nt(e,"display","none")}))},wd=e=>{pd(e,(e=>{Nt(e,"display","block")}))},vd=cd("resizer-bar-dragging"),yd=e=>{const t=(()=>{const e=Qm({drag:Jm(["xDelta","yDelta","target"])});let t=C.none();const o=(()=>{const e=Qm({drag:Jm(["xDelta","yDelta"])});return{mutate:(t,o)=>{e.trigger.drag(t,o)},events:e.registry}})();return o.events.drag.bind((o=>{t.each((t=>{e.trigger.drag(o.xDelta,o.yDelta,t)}))})),{assign:e=>{t=C.some(e)},get:()=>t,mutate:o.mutate,events:e.registry}})(),o=((e,t={})=>{var o;return((e,t,o)=>{let n=!1;const r=Qm({start:Jm([]),stop:Jm([])}),s=rd(),l=()=>{m.stop(),s.isOn()&&(s.off(),r.trigger.stop())},c=((e,t)=>{let o=null;const n=()=>{a(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...t)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,t)}),200)}}})(l);s.events.move.bind((o=>{t.mutate(e,o.info)}));const i=e=>(...t)=>{n&&e.apply(null,t)},m=t.sink(nd({forceDrop:l,drop:i(l),move:i((e=>{c.cancel(),s.onEvent(e,t)})),delayDrop:i(c.throttle)}),o);return{element:m.element,go:e=>{m.start(e),s.on(),r.trigger.start()},on:()=>{n=!0},off:()=>{n=!1},isActive:()=>n,destroy:()=>{m.destroy()},events:r.registry}})(e,null!==(o=t.mode)&&void 0!==o?o:ad,t)})(t,{});let n=C.none();const r=(e,t)=>C.from(pe(e,t));t.events.drag.bind((e=>{r(e.target,"data-row").each((t=>{const o=Pt(e.target,"top");Nt(e.target,"top",o+e.yDelta+"px")})),r(e.target,"data-column").each((t=>{const o=Pt(e.target,"left");Nt(e.target,"left",o+e.xDelta+"px")}))}));const s=(e,t)=>Pt(e,t)-Wt(e,"data-initial-"+t,0);o.events.stop.bind((()=>{t.get().each((t=>{n.each((o=>{r(t,"data-row").each((e=>{const n=s(t,"top");we(t,"data-initial-top"),d.trigger.adjustHeight(o,n,parseInt(e,10))})),r(t,"data-column").each((e=>{const n=s(t,"left");we(t,"data-initial-left"),d.trigger.adjustWidth(o,n,parseInt(e,10))})),hd(e,o)}))}))}));const l=(n,r)=>{d.trigger.startAdjust(),t.assign(n),ge(n,"data-initial-"+r,Pt(n,r)),jm(n,vd),Nt(n,"opacity","0.2"),o.go(e.parent())},c=Um(e.parent(),"mousedown",(e=>{var t;t=e.target,Pm(t,md)&&l(e.target,"top"),(e=>Pm(e,dd))(e.target)&&l(e.target,"left")})),i=t=>Re(t,e.view()),m=Um(e.view(),"mouseover",(t=>{var r;(r=t.target,wt(r,"table",i).filter(Qr)).fold((()=>{lt(t.target)&&ud(e)}),(t=>{o.isActive()&&(n=C.some(t),hd(e,t))}))})),d=Qm({adjustHeight:Jm(["table","delta","row"]),adjustWidth:Jm(["table","delta","column"]),startAdjust:Jm([])});return{destroy:()=>{c.unbind(),m.unbind(),o.destroy(),ud(e)},refresh:t=>{hd(e,t)},on:o.on,off:o.off,hideBars:b(bd,e),showBars:b(wd,e),events:d.registry}},xd=e=>m(e)&&"TABLE"===e.nodeName,Cd="bar-",Sd=e=>"false"!==pe(e,"data-mce-resize"),Td=e=>{const t=am(),o=am(),n=am();let r,s,l,a;const c=t=>hc(e,t),i=()=>Pr(e)?nl():ol(),m=(t,o,n,m)=>{const d=(e=>{return Tt(t=e,"corner-")?((e,t)=>e.substring(7))(t):t;var t})(o),u=Rt(d,"e"),f=Tt(d,"n");if(""===s&&_c(t),""===a&&(e=>{const t=(e=>gn(e)+"px")(e);Oc(e,C.none(),C.some(t)),Bc(e)})(t),n!==r&&""!==s){Nt(t,"width",s);const o=i(),l=c(t),a=Pr(e)||u?(e=>rl(e).columns)(t)-1:0;sa(t,n-r,a,o,l)}else if((e=>/^(\d+(\.\d+)?)%$/.test(e))(s)){const e=parseFloat(s.replace("%",""));Nt(t,"width",n*e/r+"%")}if((e=>/^(\d+(\.\d+)?)px$/.test(e))(s)&&(e=>{const t=Xo(e);sn(t)||N(qt(e),(e=>{const t=_t(e,"width");Nt(e,"width",t),we(e,"width")}))})(t),m!==l&&""!==a){Nt(t,"height",a);const e=f?0:(e=>rl(e).rows)(t)-1;la(t,m-l,e)}};return e.on("init",(()=>{const r=((e,t)=>e.inline?((e,t,o)=>({parent:g(t),view:g(e),origin:g(bn(0,0)),isResizable:o}))(xe.fromDom(e.getBody()),(()=>{const e=xe.fromTag("div");return Bt(e,{position:"static",height:"0",width:"0",padding:"0",margin:"0",border:"0"}),Ie(at(xe.fromDom(document)),e),e})(),t):((e,t)=>{const o=me(e)?(e=>xe.fromDom(Ee(e).dom.documentElement))(e):e;return{parent:g(o),view:g(e),origin:g(bn(0,0)),isResizable:t}})(xe.fromDom(e.getDoc()),t))(e,Sd);if(n.set(r),(e=>{const t=e.options.get("object_resizing");return D(t.split(","),"table")})(e)&&qr(e)){const n=((e,t,o)=>{const n=Bn,r=zn,s=yd(e),l=Qm({beforeResize:Jm(["table","type"]),afterResize:Jm(["table","type"]),startDrag:Jm([])});return s.events.adjustHeight.bind((e=>{const t=e.table;l.trigger.beforeResize(t,"row");const o=n.delta(e.delta,t);la(t,o,e.row),l.trigger.afterResize(t,"row")})),s.events.startAdjust.bind((e=>{l.trigger.startDrag()})),s.events.adjustWidth.bind((e=>{const n=e.table;l.trigger.beforeResize(n,"col");const s=r.delta(e.delta,n),a=o(n);sa(n,s,e.column,t,a),l.trigger.afterResize(n,"col")})),{on:s.on,off:s.off,refreshBars:s.refresh,hideBars:s.hideBars,showBars:s.showBars,destroy:s.destroy,events:l.registry}})(r,i(),c);n.on(),n.events.startDrag.bind((o=>{t.set(e.selection.getRng())})),n.events.beforeResize.bind((t=>{const o=t.table.dom;((e,t,o,n,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:o,height:n,origin:r})})(e,o,ns(o),rs(o),Cd+t.type)})),n.events.afterResize.bind((o=>{const n=o.table,r=n.dom;ts(n),t.on((t=>{e.selection.setRng(t),e.focus()})),((e,t,o,n,r)=>{e.dispatch("ObjectResized",{target:t,width:o,height:n,origin:r})})(e,r,ns(r),rs(r),Cd+o.type),e.undoManager.add()})),o.set(n)}})),e.on("ObjectResizeStart",(t=>{const o=t.target;if(xd(o)){const n=xe.fromDom(o);N(e.dom.select(".mce-clonedresizable"),(t=>{e.dom.addClass(t,"mce-"+jr(e)+"-columns")})),!Ec(n)&&$r(e)?zc(n):!kc(n)&&Hr(e)&&_c(n),Nc(n)&&Tt(t.origin,Cd)&&_c(n),r=t.width,s=Vr(e)?"":ls(e,o).getOr(""),l=t.height,a=as(e,o).getOr("")}})),e.on("ObjectResized",(t=>{const o=t.target;if(xd(o)){const n=xe.fromDom(o),r=t.origin;(e=>Tt(e,"corner-"))(r)&&m(n,r,t.width,t.height),ts(n),dc(e,n.dom,uc)}})),e.on("SwitchMode",(()=>{o.on((t=>{e.mode.isReadOnly()?t.hideBars():t.showBars()}))})),e.on("dragstart dragend",(e=>{o.on((t=>{"dragstart"===e.type?(t.hideBars(),t.off()):(t.on(),t.showBars())}))})),e.on("remove",(()=>{o.on((e=>{e.destroy()})),n.on((t=>{((e,t)=>{e.inline&&qe(t.parent())})(e,t)}))})),{refresh:e=>{o.on((t=>t.refreshBars(xe.fromDom(e))))},hide:()=>{o.on((e=>e.hideBars()))},show:()=>{o.on((e=>e.showBars()))}}},Rd=e=>{(e=>{const t=e.options.register;t("table_clone_elements",{processor:"string[]"}),t("table_use_colgroups",{processor:"boolean",default:!0}),t("table_header_type",{processor:e=>{const t=D(["section","cells","sectionCells","auto"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: section, cells, sectionCells or auto."}},default:"section"}),t("table_sizing_mode",{processor:"string",default:"auto"}),t("table_default_attributes",{processor:"object",default:{border:"1"}}),t("table_default_styles",{processor:"object",default:{"border-collapse":"collapse"}}),t("table_column_resizing",{processor:e=>{const t=D(["preservetable","resizetable"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be preservetable, or resizetable."}},default:"preservetable"}),t("table_resize_bars",{processor:"boolean",default:!0}),t("table_style_by_css",{processor:"boolean",default:!0}),t("table_merge_content_on_paste",{processor:"boolean",default:!0})})(e);const t=Td(e),o=Ym(e,t),n=pc(e,t,o);return Zc(e,n),((e,t)=>{const o=es(e),n=t=>Fs(os(e)).bind((n=>Gt(n,o).map((o=>{const r=js(Hs(e),o,n);return t(o,r)})))).getOr("");G({mceTableRowType:()=>n(t.getTableRowType),mceTableCellType:()=>n(t.getTableCellType),mceTableColType:()=>n(t.getTableColType)},((t,o)=>e.addQueryValueHandler(o,t)))})(e,n),$s(e,n),{getSelectedCells:o.getSelectedCells,clearSelectedCells:o.clearSelectedCells}};e.add("dom",(e=>({table:Rd(e)})))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js
new file mode 100644
index 0000000..8dc4f86
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/accordion/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const o=e=>t=>typeof t===e,n=e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=n=e,(r=String).prototype.isPrototypeOf(o)||(null===(s=n.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var o,n,r,s})(e),r=o("boolean"),s=e=>null==e,a=e=>!s(e),i=o("function"),d=o("number"),l=e=>()=>e,c=(e,t)=>e===t,m=l(!1);class u{constructor(e,t){this.tag=e,this.value=t}static some(e){return new u(!0,e)}static none(){return u.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?u.some(e(this.value)):u.none()}bind(e){return this.tag?e(this.value):u.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:u.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return a(e)?u.some(e):u.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}u.singletonNone=new u(!1);const g=Array.prototype.indexOf,p=(e,t)=>{return o=e,n=t,g.call(o,n)>-1;var o,n},h=(e,t)=>{const o=e.length,n=new Array(o);for(let r=0;r<o;r++){const o=e[r];n[r]=t(o,r)}return n},f=(e,t)=>{for(let o=0,n=e.length;o<n;o++)t(e[o],o)},y=Object.keys;"undefined"!=typeof window?window:Function("return this;")();const v=e=>e.dom.nodeName.toLowerCase(),w=e=>e.dom.nodeType,b=e=>t=>w(t)===e,N=b(1),T=b(3),A=b(9),C=b(11),S=(e,t,o)=>{if(!(n(o)||r(o)||d(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},x=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},E=(e,t)=>u.from(x(e,t)),D=(e,t)=>{e.dom.removeAttribute(t)},M=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},P={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return M(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return M(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return M(o)},fromDom:M,fromPoint:(e,t,o)=>u.from(e.dom.elementFromPoint(t,o)).map(M)},O=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},k=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,B=O,R=(L=/^\s+|\s+$/g,e=>e.replace(L,""));var L;const $=e=>void 0!==e.style&&i(e.style.getPropertyValue),I=e=>A(e)?e:P.fromDom(e.dom.ownerDocument),V=e=>u.from(e.dom.parentNode).map(P.fromDom),j=e=>u.from(e.dom.nextSibling).map(P.fromDom),q=e=>h(e.dom.childNodes,P.fromDom),F=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?e=>P.fromDom(e.dom.getRootNode()):I,H=e=>P.fromDom(e.dom.host),z=e=>{const t=T(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=F(e);return C(o=t)&&a(o.dom.host)?u.some(t):u.none();var o})(P.fromDom(t)).fold((()=>o.body.contains(t)),(n=z,r=H,e=>n(r(e))));var n,r},K=(e,t)=>$(e)?e.style.getPropertyValue(t):"",U=(e,t)=>{V(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},Y=(e,t)=>{j(e).fold((()=>{V(e).each((e=>{_(e,t)}))}),(e=>{U(e,t)}))},_=(e,t)=>{e.dom.appendChild(t.dom)},G=(e,t)=>{f(t,((o,n)=>{const r=0===n?e:t[n-1];Y(r,o)}))},J=(e,t)=>{let o=[];return f(q(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(J(e,t))})),o},Q=(e,t,o)=>{let n=e.dom;const r=i(o)?o:m;for(;n.parentNode;){n=n.parentNode;const e=P.fromDom(n);if(t(e))return u.some(e);if(r(e))break}return u.none()},W=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},X=(e,t,o)=>Q(e,(e=>O(e,t)),o),Z=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return k(o)?u.none():u.from(o.querySelector(e)).map(P.fromDom)})(t,e),ee=((e,t)=>{const o=t=>e(t)?u.from(t.dom.nodeValue):u.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(T);var te=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"];const oe=(e,t)=>({element:e,offset:t}),ne=(e,t,o)=>e.property().isText(t)&&0===e.property().getText(t).trim().length||e.property().isComment(t)?o(t).bind((t=>ne(e,t,o).orThunk((()=>u.some(t))))):u.none(),re=(e,t)=>e.property().isText(t)?e.property().getText(t).length:e.property().children(t).length,se=(e,t)=>{const o=ne(e,t,e.query().prevSibling).getOr(t);if(e.property().isText(o))return oe(o,re(e,o));const n=e.property().children(o);return n.length>0?se(e,n[n.length-1]):oe(o,re(e,o))},ae=se,ie={up:l({selector:X,closest:(e,t,o)=>((e,t,o,n,r)=>((e,t)=>O(e,t))(o,n)?u.some(o):i(r)&&r(o)?u.none():t(o,n,r))(0,X,e,t,o),predicate:Q,all:(e,t)=>{const o=i(t)?t:m;let n=e.dom;const r=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=P.fromDom(e);if(r.push(t),!0===o(t))break;n=e}return r}}),down:l({selector:(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return k(o)?[]:h(o.querySelectorAll(e),P.fromDom)})(t,e),predicate:J}),styles:l({get:(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||z(e)?n:K(o,t)},getRaw:(e,t)=>{const o=e.dom,n=K(o,t);return u.from(n).filter((e=>e.length>0))},set:(e,t,o)=>{((e,t,o)=>{if(!n(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);$(e)&&e.style.setProperty(t,o)})(e.dom,t,o)},remove:(e,t)=>{((e,t)=>{$(e)&&e.style.removeProperty(t)})(e.dom,t),((e,t,o=c)=>e.exists((e=>o(e,t))))(E(e,"style").map(R),"")&&D(e,"style")}}),attrs:l({get:x,set:(e,t,o)=>{S(e.dom,t,o)},remove:D,copyTo:(e,t)=>{const o=(n=e.dom.attributes,r=(e,t)=>(e[t.name]=t.value,e),s={},f(n,((e,t)=>{s=r(s,e)})),s);var n,r,s;((e,t)=>{const o=e.dom;((e,t)=>{const o=y(e);for(let n=0,r=o.length;n<r;n++){const r=o[n];t(e[r],r)}})(t,((e,t)=>{S(o,t,e)}))})(t,o)}}),insert:l({before:U,after:Y,afterAll:G,append:_,appendAll:(e,t)=>{f(t,(t=>{_(e,t)}))},prepend:(e,t)=>{(e=>((e,t)=>{const o=e.dom.childNodes;return u.from(o[0]).map(P.fromDom)})(e))(e).fold((()=>{_(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},wrap:(e,t)=>{U(e,t),_(t,e)}}),remove:l({unwrap:e=>{const t=q(e);t.length>0&&G(e,t),W(e)},remove:W}),create:l({nu:P.fromTag,clone:e=>P.fromDom(e.dom.cloneNode(!1)),text:P.fromText}),query:l({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:e=>u.from(e.dom.previousSibling).map(P.fromDom),nextSibling:j}),property:l({children:q,name:v,parent:V,document:e=>I(e).dom,isText:T,isComment:e=>8===w(e)||"#comment"===v(e),isElement:N,isSpecial:e=>{const t=v(e);return p(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>N(e)?E(e,"lang"):u.none(),getText:e=>ee.get(e),setText:(e,t)=>ee.set(e,t),isBoundary:e=>!!N(e)&&("body"===v(e)||p(te,v(e))),isEmptyTag:e=>!!N(e)&&p(["br","img","hr","input"],v(e)),isNonEditable:e=>N(e)&&"false"===x(e,"contenteditable")}),eq:(e,t)=>e.dom===t.dom,is:B},de="details",le="mce-accordion",ce="mce-accordion-summary",me="mce-accordion-body",ue="div";var ge=tinymce.util.Tools.resolve("tinymce.util.Tools");const pe=e=>"SUMMARY"===(null==e?void 0:e.nodeName),he=e=>"DETAILS"===(null==e?void 0:e.nodeName),fe=e=>e.hasAttribute("open"),ye=e=>{const t=e.selection.getNode();return pe(t)||Boolean(e.dom.getParent(t,pe))},ve=e=>!ye(e)&&e.dom.isEditable(e.selection.getNode()),we=e=>u.from(e.dom.getParent(e.selection.getNode(),he)),be=e=>(e.innerHTML='<br data-mce-bogus="1" />',e),Ne=e=>be(e.dom.create("p")),Te=e=>t=>{((e,t)=>{if(pe(null==t?void 0:t.lastChild)){const o=Ne(e);t.appendChild(o),e.selection.setCursorLocation(o,0)}})(e,t),((e,t)=>{if(!pe(null==t?void 0:t.firstChild)){const o=(e=>be(e.dom.create("summary")))(e);t.prepend(o),e.selection.setCursorLocation(o,0)}})(e,t)},Ae=(e,t)=>{const o=null!=t?t:!fe(e);return o?e.setAttribute("open","open"):e.removeAttribute("open"),o},Ce=e=>{e.addCommand("InsertAccordion",(()=>(e=>{if(!ve(e))return;const o=P.fromDom(e.getBody()),n=(e=>{const o=(new Date).getTime(),n=Math.floor(1e9*Math.random());return t++,"acc_"+n+t+String(o)})(),r=e.dom.encode(e.selection.getRng().toString()||e.translate("Accordion summary...")),s=e.dom.encode(e.translate("Accordion body...")),a=`<summary class="${ce}">${r}</summary>`,i=`<${ue} class="${me}"><p>${s}</p></${ue}>`;e.undoManager.transact((()=>{e.insertContent([`<details data-mce-id="${n}" class="${le}" open="open">`,a,i,"</details>"].join("")),Z(o,`[data-mce-id="${n}"]`).each((t=>{D(t,"data-mce-id"),Z(t,"summary").each((t=>{const o=e.dom.createRng(),n=ae(ie,t);o.setStart(n.element.dom,n.offset),o.setEnd(n.element.dom,n.offset),e.selection.setRng(o)}))}))}))})(e))),e.addCommand("ToggleAccordion",((t,o)=>((e,t)=>{we(e).each((o=>{((e,t,o)=>{e.dispatch("ToggledAccordion",{element:t,state:o})})(e,o,Ae(o,t))}))})(e,o))),e.addCommand("ToggleAllAccordions",((t,o)=>((e,t)=>{const o=Array.from(e.getBody().querySelectorAll("details"));0!==o.length&&(f(o,(e=>Ae(e,null!=t?t:!fe(e)))),((e,t,o)=>{e.dispatch("ToggledAllAccordions",{elements:t,state:o})})(e,o,t))})(e,o))),e.addCommand("RemoveAccordion",(()=>(e=>{we(e).each((t=>{const{nextSibling:o}=t;o?(e.selection.select(o,!0),e.selection.collapse(!0)):((e,t)=>{const o=Ne(e);t.insertAdjacentElement("afterend",o),e.selection.setCursorLocation(o,0)})(e,t),t.remove()}))})(e)))};var Se=tinymce.util.Tools.resolve("tinymce.html.Node");const xe=e=>{var t,o;return null!==(o=null===(t=e.attr("class"))||void 0===t?void 0:t.split(" "))&&void 0!==o?o:[]},Ee=(e,t)=>{const o=new Set([...xe(e),...t]),n=Array.from(o);n.length>0&&e.attr("class",n.join(" "))},De=(e,t)=>{const o=((e,o)=>{const n=[];for(let o=0,s=e.length;o<s;o++){const s=e[o];r=s,!t.has(r)&&n.push(s)}var r;return n})(xe(e));e.attr("class",o.length>0?o.join(" "):null)},Me=e=>e.name===de&&p(xe(e),le),Pe=e=>{const t=e.children();let o,n;const r=[];for(let e=0;e<t.length;e++){const i=t[e];"summary"===i.name&&s(o)?o=i:(a=i).name===ue&&p(xe(a),me)&&s(n)?n=i:r.push(i)}var a;return{summaryNode:o,wrapperNode:n,otherNodes:r}},Oe=e=>{const t=new Se("br",1);t.attr("data-mce-bogus","1"),e.empty(),e.append(t)};var ke=tinymce.util.Tools.resolve("tinymce.util.VK");const Be=e=>{(e=>{e.on("keydown",(t=>{(!t.shiftKey&&t.keyCode===ke.ENTER&&ye(e)||(e=>{const t=e.selection.getRng();return he(t.startContainer)&&t.collapsed&&0===t.startOffset})(e))&&(t.preventDefault(),e.execCommand("ToggleAccordion"))}))})(e),e.on("ExecCommand",(t=>{const o=t.command.toLowerCase();"delete"!==o&&"forwarddelete"!==o||!(e=>we(e).isSome())(e)||(e=>{ge.each(ge.grep(e.dom.select("details",e.getBody())),Te(e))})(e)}))};var Re=tinymce.util.Tools.resolve("tinymce.Env");const Le=e=>t=>{const o=()=>t.setEnabled(ve(e));return e.on("NodeChange",o),()=>e.off("NodeChange",o)};e.add("accordion",(e=>{(e=>{const t=()=>e.execCommand("InsertAccordion");e.ui.registry.addButton("accordion",{icon:"accordion",tooltip:"Insert accordion",onSetup:Le(e),onAction:t}),e.ui.registry.addMenuItem("accordion",{icon:"accordion",text:"Accordion",onSetup:Le(e),onAction:t}),e.ui.registry.addToggleButton("accordiontoggle",{icon:"accordion-toggle",tooltip:"Toggle accordion",onAction:()=>e.execCommand("ToggleAccordion")}),e.ui.registry.addToggleButton("accordionremove",{icon:"remove",tooltip:"Delete accordion",onAction:()=>e.execCommand("RemoveAccordion")}),e.ui.registry.addContextToolbar("accordion",{predicate:t=>e.dom.is(t,"details")&&e.getBody().contains(t)&&e.dom.isEditable(t.parentNode),items:"accordiontoggle accordionremove",scope:"node",position:"node"})})(e),Ce(e),Be(e),(e=>{e.on("PreInit",(()=>{const{serializer:t,parser:o}=e;o.addNodeFilter(de,(e=>{for(let t=0;t<e.length;t++){const o=e[t];if(Me(o)){const e=o,{summaryNode:t,wrapperNode:n,otherNodes:r}=Pe(e),i=a(t),d=i?t:new Se("summary",1);s(d.firstChild)&&Oe(d),Ee(d,[ce]),i||(a(e.firstChild)?e.insert(d,e.firstChild,!0):e.append(d));const l=a(n),c=l?n:new Se(ue,1);if(c.attr("data-mce-bogus","1"),Ee(c,[me]),r.length>0)for(let e=0;e<r.length;e++){const t=r[e];c.append(t)}if(s(c.firstChild)){const e=new Se("p",1);Oe(e),c.append(e)}l||e.append(c)}}})),t.addNodeFilter(de,(e=>{const t=new Set([ce]);for(let o=0;o<e.length;o++){const n=e[o];if(Me(n)){const e=n,{summaryNode:o,wrapperNode:r}=Pe(e);a(o)&&De(o,t),a(r)&&r.unwrap()}}}))}))})(e),(e=>{Re.browser.isSafari()&&e.on("click",(t=>{if(pe(t.target)){const o=t.target,n=e.selection.getRng();n.collapsed&&n.startContainer===o.parentNode&&0===n.startOffset&&e.selection.setCursorLocation(o,0)}}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js
new file mode 100644
index 0000000..dac3959
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/advlist/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),i=t=>null==t,l=t=>!i(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return l(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>l(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>i(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;e<n;e++){const n=t[e];if(d(r=n)&&!/\btox\-/.test(r.className))return a.some(n);if(s(n,e))break}var r;return a.none()})(e,0,g).exists((e=>e.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)&&t.selection.isEditable()})(t,n)&&t.selection.isEditable())})(t,r.parents))),m=(t,s,r,n,i,l)=>{l.length>1?((t,s,r,n,i,l)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(l,(t=>{const e="OL"===i?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,i,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,i)})})(t,s,r,n,i,l):((t,s,r,n,i,l)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:h(t,i),onAction:()=>t.queryCommandState(n)||""===l?t.execCommand(n):e(t,i,l)})})(t,s,r,n,i,c(l[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js
new file mode 100644
index 0000000..59c4d25
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/anchor/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;o<t.length;o++){const n=t[o];c(n)&&n.attr("contenteditable",e)}},u=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js
new file mode 100644
index 0000000..ba5d144
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/autolink/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js
new file mode 100644
index 0000000..b817813
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/autoresize/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),g=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},l=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},a=(e,o,r,c)=>{var d;const u=e.dom,h=e.getDoc();if(!h)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void g(e,!0);const m=h.documentElement,f=c?c():i(e),p=null!==(d=n(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=l(u,m,"margin-top",!0),v=l(u,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+f;C<0&&(C=0);const H=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+H>p&&(y=C+H);const b=s(e);b&&y>b?(y=b,g(e,!0)):g(e,!1);const w=o.get();if(w.set&&(e.dom.setStyles(e.getDoc().documentElement,{"min-height":0}),e.dom.setStyles(e.getBody(),{"min-height":"inherit"})),y!==w.totalHeight&&(C-f!==w.contentHeight||!w.set)){const n=y-w.totalHeight;if(u.setStyle(e.getContainer(),"height",y+"px"),o.set({totalHeight:y,contentHeight:C,set:!0}),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t={totalHeight:0,contentHeight:0,set:!1};return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{const n=()=>r(e);e.on("init",(s=>{const r=i(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,s,n)})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{a(e,o,t,n)}))})(e,o)}}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js
new file mode 100644
index 0000000..944621b
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/autosave/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js
new file mode 100644
index 0000000..f86de54
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/charmap/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=(e,t)=>{const r=((e,t)=>e.dispatch("insertCustomChar",{chr:t}))(e,t).chr;e.execCommand("mceInsertContent",!1,r)},r=e=>t=>e===t,a=("array",e=>"array"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=a=e,(n=String).prototype.isPrototypeOf(r)||(null===(i=a.constructor)||void 0===i?void 0:i.name)===n.name)?"string":t;var r,a,n,i})(e));const n=r(null),i=r(void 0),o=e=>"function"==typeof e,s=(!1,()=>false);class l{constructor(e,t){this.tag=e,this.value=t}static some(e){return new l(!0,e)}static none(){return l.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?l.some(e(this.value)):l.none()}bind(e){return this.tag?e(this.value):l.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:l.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?l.none():l.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}l.singletonNone=new l(!1);const c=Array.prototype.push,u=(e,t)=>{const r=e.length,a=new Array(r);for(let n=0;n<r;n++){const r=e[n];a[n]=t(r,n)}return a};var g=tinymce.util.Tools.resolve("tinymce.util.Tools");const h=e=>t=>t.options.get(e),m=h("charmap"),p=h("charmap_append"),d=g.isArray,f="User Defined",y=e=>{return d(e)?(t=e,g.grep(t,(e=>d(e)&&2===e.length))):"function"==typeof e?e():[];var t},b=e=>{const t=((e,t)=>{const r=m(e);r&&(t=[{name:f,characters:y(r)}]);const a=p(e);if(a){const e=g.grep(t,(e=>e.name===f));return e.length?(e[0].characters=[...e[0].characters,...y(a)],t):t.concat({name:f,characters:y(a)})}return t})(e,[{name:"Currency",characters:[[36,"dollar sign"],[162,"cent sign"],[8364,"euro sign"],[163,"pound sign"],[165,"yen sign"],[164,"currency sign"],[8352,"euro-currency sign"],[8353,"colon sign"],[8354,"cruzeiro sign"],[8355,"french franc sign"],[8356,"lira sign"],[8357,"mill sign"],[8358,"naira sign"],[8359,"peseta sign"],[8360,"rupee sign"],[8361,"won sign"],[8362,"new sheqel sign"],[8363,"dong sign"],[8365,"kip sign"],[8366,"tugrik sign"],[8367,"drachma sign"],[8368,"german penny symbol"],[8369,"peso sign"],[8370,"guarani sign"],[8371,"austral sign"],[8372,"hryvnia sign"],[8373,"cedi sign"],[8374,"livre tournois sign"],[8375,"spesmilo sign"],[8376,"tenge sign"],[8377,"indian rupee sign"],[8378,"turkish lira sign"],[8379,"nordic mark sign"],[8380,"manat sign"],[8381,"ruble sign"],[20870,"yen character"],[20803,"yuan character"],[22291,"yuan character, in hong kong and taiwan"],[22278,"yen/yuan character variant one"]]},{name:"Text",characters:[[169,"copyright sign"],[174,"registered sign"],[8482,"trade mark sign"],[8240,"per mille sign"],[181,"micro sign"],[183,"middle dot"],[8226,"bullet"],[8230,"three dot leader"],[8242,"minutes / feet"],[8243,"seconds / inches"],[167,"section sign"],[182,"paragraph sign"],[223,"sharp s / ess-zed"]]},{name:"Quotations",characters:[[8249,"single left-pointing angle quotation mark"],[8250,"single right-pointing angle quotation mark"],[171,"left pointing guillemet"],[187,"right pointing guillemet"],[8216,"left single quotation mark"],[8217,"right single quotation mark"],[8220,"left double quotation mark"],[8221,"right double quotation mark"],[8218,"single low-9 quotation mark"],[8222,"double low-9 quotation mark"],[60,"less-than sign"],[62,"greater-than sign"],[8804,"less-than or equal to"],[8805,"greater-than or equal to"],[8211,"en dash"],[8212,"em dash"],[175,"macron"],[8254,"overline"],[164,"currency sign"],[166,"broken bar"],[168,"diaeresis"],[161,"inverted exclamation mark"],[191,"turned question mark"],[710,"circumflex accent"],[732,"small tilde"],[176,"degree sign"],[8722,"minus sign"],[177,"plus-minus sign"],[247,"division sign"],[8260,"fraction slash"],[215,"multiplication sign"],[185,"superscript one"],[178,"superscript two"],[179,"superscript three"],[188,"fraction one quarter"],[189,"fraction one half"],[190,"fraction three quarters"]]},{name:"Mathematical",characters:[[402,"function / florin"],[8747,"integral"],[8721,"n-ary sumation"],[8734,"infinity"],[8730,"square root"],[8764,"similar to"],[8773,"approximately equal to"],[8776,"almost equal to"],[8800,"not equal to"],[8801,"identical to"],[8712,"element of"],[8713,"not an element of"],[8715,"contains as member"],[8719,"n-ary product"],[8743,"logical and"],[8744,"logical or"],[172,"not sign"],[8745,"intersection"],[8746,"union"],[8706,"partial differential"],[8704,"for all"],[8707,"there exists"],[8709,"diameter"],[8711,"backward difference"],[8727,"asterisk operator"],[8733,"proportional to"],[8736,"angle"]]},{name:"Extended Latin",characters:[[192,"A - grave"],[193,"A - acute"],[194,"A - circumflex"],[195,"A - tilde"],[196,"A - diaeresis"],[197,"A - ring above"],[256,"A - macron"],[198,"ligature AE"],[199,"C - cedilla"],[200,"E - grave"],[201,"E - acute"],[202,"E - circumflex"],[203,"E - diaeresis"],[274,"E - macron"],[204,"I - grave"],[205,"I - acute"],[206,"I - circumflex"],[207,"I - diaeresis"],[298,"I - macron"],[208,"ETH"],[209,"N - tilde"],[210,"O - grave"],[211,"O - acute"],[212,"O - circumflex"],[213,"O - tilde"],[214,"O - diaeresis"],[216,"O - slash"],[332,"O - macron"],[338,"ligature OE"],[352,"S - caron"],[217,"U - grave"],[218,"U - acute"],[219,"U - circumflex"],[220,"U - diaeresis"],[362,"U - macron"],[221,"Y - acute"],[376,"Y - diaeresis"],[562,"Y - macron"],[222,"THORN"],[224,"a - grave"],[225,"a - acute"],[226,"a - circumflex"],[227,"a - tilde"],[228,"a - diaeresis"],[229,"a - ring above"],[257,"a - macron"],[230,"ligature ae"],[231,"c - cedilla"],[232,"e - grave"],[233,"e - acute"],[234,"e - circumflex"],[235,"e - diaeresis"],[275,"e - macron"],[236,"i - grave"],[237,"i - acute"],[238,"i - circumflex"],[239,"i - diaeresis"],[299,"i - macron"],[240,"eth"],[241,"n - tilde"],[242,"o - grave"],[243,"o - acute"],[244,"o - circumflex"],[245,"o - tilde"],[246,"o - diaeresis"],[248,"o slash"],[333,"o macron"],[339,"ligature oe"],[353,"s - caron"],[249,"u - grave"],[250,"u - acute"],[251,"u - circumflex"],[252,"u - diaeresis"],[363,"u - macron"],[253,"y - acute"],[254,"thorn"],[255,"y - diaeresis"],[563,"y - macron"],[913,"Alpha"],[914,"Beta"],[915,"Gamma"],[916,"Delta"],[917,"Epsilon"],[918,"Zeta"],[919,"Eta"],[920,"Theta"],[921,"Iota"],[922,"Kappa"],[923,"Lambda"],[924,"Mu"],[925,"Nu"],[926,"Xi"],[927,"Omicron"],[928,"Pi"],[929,"Rho"],[931,"Sigma"],[932,"Tau"],[933,"Upsilon"],[934,"Phi"],[935,"Chi"],[936,"Psi"],[937,"Omega"],[945,"alpha"],[946,"beta"],[947,"gamma"],[948,"delta"],[949,"epsilon"],[950,"zeta"],[951,"eta"],[952,"theta"],[953,"iota"],[954,"kappa"],[955,"lambda"],[956,"mu"],[957,"nu"],[958,"xi"],[959,"omicron"],[960,"pi"],[961,"rho"],[962,"final sigma"],[963,"sigma"],[964,"tau"],[965,"upsilon"],[966,"phi"],[967,"chi"],[968,"psi"],[969,"omega"]]},{name:"Symbols",characters:[[8501,"alef symbol"],[982,"pi symbol"],[8476,"real part symbol"],[978,"upsilon - hook symbol"],[8472,"Weierstrass p"],[8465,"imaginary part"]]},{name:"Arrows",characters:[[8592,"leftwards arrow"],[8593,"upwards arrow"],[8594,"rightwards arrow"],[8595,"downwards arrow"],[8596,"left right arrow"],[8629,"carriage return"],[8656,"leftwards double arrow"],[8657,"upwards double arrow"],[8658,"rightwards double arrow"],[8659,"downwards double arrow"],[8660,"left right double arrow"],[8756,"therefore"],[8834,"subset of"],[8835,"superset of"],[8836,"not a subset of"],[8838,"subset of or equal to"],[8839,"superset of or equal to"],[8853,"circled plus"],[8855,"circled times"],[8869,"perpendicular"],[8901,"dot operator"],[8968,"left ceiling"],[8969,"right ceiling"],[8970,"left floor"],[8971,"right floor"],[9001,"left-pointing angle bracket"],[9002,"right-pointing angle bracket"],[9674,"lozenge"],[9824,"black spade suit"],[9827,"black club suit"],[9829,"black heart suit"],[9830,"black diamond suit"],[8194,"en space"],[8195,"em space"],[8201,"thin space"],[8204,"zero width non-joiner"],[8205,"zero width joiner"],[8206,"left-to-right mark"],[8207,"right-to-left mark"]]}]);return t.length>1?[{name:"All",characters:(r=t,n=e=>e.characters,(e=>{const t=[];for(let r=0,n=e.length;r<n;++r){if(!a(e[r]))throw new Error("Arr.flatten item "+r+" was not an array, input: "+e);c.apply(t,e[r])}return t})(u(r,n)))}].concat(t):t;var r,n},w=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},v=(e,t,r=0,a)=>{const n=e.indexOf(t,r);return-1!==n&&(!!i(a)||n+t.length<=a)},k=String.fromCodePoint,C=(e,t)=>{const r=[],a=t.toLowerCase();return((e,t)=>{for(let t=0,i=e.length;t<i;t++)((e,t,r)=>!!v(k(e).toLowerCase(),r)||v(t.toLowerCase(),r)||v(t.toLowerCase().replace(/\s+/g,""),r))((n=e[t])[0],n[1],a)&&r.push(n);var n})(e.characters),u(r,(e=>({text:e[1],value:k(e[0]),icon:k(e[0])})))},x="pattern",A=(e,r)=>{const a=()=>[{label:"Search",type:"input",name:x},{type:"collection",name:"results"}],i=1===r.length?w(f):w("All"),o=((e,t)=>{let r=null;const a=()=>{n(r)||(clearTimeout(r),r=null)};return{cancel:a,throttle:(...t)=>{a(),r=setTimeout((()=>{r=null,e.apply(null,t)}),40)}}})((e=>{const t=e.getData().pattern;((e,t)=>{var a,n;(a=r,n=e=>e.name===i.get(),((e,t,r)=>{for(let a=0,n=e.length;a<n;a++){const n=e[a];if(t(n,a))return l.some(n);if(r(n,a))break}return l.none()})(a,n,s)).each((r=>{const a=C(r,t);e.setData({results:a})}))})(e,t)})),c={title:"Special Character",size:"normal",body:1===r.length?{type:"panel",items:a()}:{type:"tabpanel",tabs:u(r,(e=>({title:e.name,name:e.name,items:a()})))},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{pattern:"",results:C(r[0],"")},onAction:(r,a)=>{"results"===a.name&&(t(e,a.value),r.close())},onTabChange:(e,t)=>{i.set(t.newTabName),o.throttle(e)},onChange:(e,t)=>{t.name===x&&o.throttle(e)}};e.windowManager.open(c).focus(x)},q=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("charmap",(e=>{(e=>{const t=e.options.register,r=e=>o(e)||a(e);t("charmap",{processor:r}),t("charmap_append",{processor:r})})(e);const r=b(e);return((e,t)=>{e.addCommand("mceShowCharmap",(()=>{A(e,t)}))})(e,r),(e=>{const t=()=>e.execCommand("mceShowCharmap");e.ui.registry.addButton("charmap",{icon:"insert-character",tooltip:"Special character",onAction:t,onSetup:q(e)}),e.ui.registry.addMenuItem("charmap",{icon:"insert-character",text:"Special character...",onAction:t,onSetup:q(e)})})(e),((e,t)=>{e.ui.registry.addAutocompleter("charmap",{trigger:":",columns:"auto",minChars:2,fetch:(e,r)=>new Promise(((r,a)=>{r(C(t,e))})),onAction:(t,r,a)=>{e.selection.setRng(r),e.insertContent(a),t.hide()}})})(e,r[0]),(e=>({getCharMap:()=>b(e),insertChar:r=>{t(e,r)}}))(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/code/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/code/plugin.min.js
new file mode 100644
index 0000000..4d91653
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/code/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js
new file mode 100644
index 0000000..dfb812a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/codesample/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>!(e=>null==e)(e),n=()=>{};class a{constructor(e,t){this.tag=e,this.value=t}static some(e){return new a(!0,e)}static none(){return a.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?a.some(e(this.value)):a.none()}bind(e){return this.tag?e(this.value):a.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:a.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return t(e)?a.some(e):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);var s=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");const r="undefined"!=typeof window?window:Function("return this;")(),i=function(e,t,n){const a=window.Prism;window.Prism={manual:!0};var s=function(e){var t=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,a={},s={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(t){return t instanceof r?new r(t.type,e(t.content),t.alias):Array.isArray(t)?t.map(e):t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function e(t,n){var a,r;switch(n=n||{},s.util.type(t)){case"Object":if(r=s.util.objId(t),n[r])return n[r];for(var i in a={},n[r]=a,t)t.hasOwnProperty(i)&&(a[i]=e(t[i],n));return a;case"Array":return r=s.util.objId(t),n[r]?n[r]:(a=[],n[r]=a,t.forEach((function(t,s){a[s]=e(t,n)})),a);default:return t}},getLanguage:function(e){for(;e;){var n=t.exec(e.className);if(n)return n[1].toLowerCase();e=e.parentElement}return"none"},setLanguage:function(e,n){e.className=e.className.replace(RegExp(t,"gi"),""),e.classList.add("language-"+n)},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(a){var e=(/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(a.stack)||[])[1];if(e){var t=document.getElementsByTagName("script");for(var n in t)if(t[n].src==e)return t[n]}return null}},isActive:function(e,t,n){for(var a="no-"+t;e;){var s=e.classList;if(s.contains(t))return!0;if(s.contains(a))return!1;e=e.parentElement}return!!n}},languages:{plain:a,plaintext:a,text:a,txt:a,extend:function(e,t){var n=s.util.clone(s.languages[e]);for(var a in t)n[a]=t[a];return n},insertBefore:function(e,t,n,a){var r=(a=a||s.languages)[e],i={};for(var o in r)if(r.hasOwnProperty(o)){if(o==t)for(var l in n)n.hasOwnProperty(l)&&(i[l]=n[l]);n.hasOwnProperty(o)||(i[o]=r[o])}var u=a[e];return a[e]=i,s.languages.DFS(s.languages,(function(t,n){n===u&&t!=e&&(this[t]=i)})),i},DFS:function e(t,n,a,r){r=r||{};var i=s.util.objId;for(var o in t)if(t.hasOwnProperty(o)){n.call(t,o,t[o],a||o);var l=t[o],u=s.util.type(l);"Object"!==u||r[i(l)]?"Array"!==u||r[i(l)]||(r[i(l)]=!0,e(l,n,o,r)):(r[i(l)]=!0,e(l,n,null,r))}}},plugins:{},highlightAll:function(e,t){s.highlightAllUnder(document,e,t)},highlightAllUnder:function(e,t,n){var a={callback:n,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};s.hooks.run("before-highlightall",a),a.elements=Array.prototype.slice.apply(a.container.querySelectorAll(a.selector)),s.hooks.run("before-all-elements-highlight",a);for(var r,i=0;r=a.elements[i++];)s.highlightElement(r,!0===t,a.callback)},highlightElement:function(t,n,a){var r=s.util.getLanguage(t),i=s.languages[r];s.util.setLanguage(t,r);var o=t.parentElement;o&&"pre"===o.nodeName.toLowerCase()&&s.util.setLanguage(o,r);var l={element:t,language:r,grammar:i,code:t.textContent};function u(e){l.highlightedCode=e,s.hooks.run("before-insert",l),l.element.innerHTML=l.highlightedCode,s.hooks.run("after-highlight",l),s.hooks.run("complete",l),a&&a.call(l.element)}if(s.hooks.run("before-sanity-check",l),(o=l.element.parentElement)&&"pre"===o.nodeName.toLowerCase()&&!o.hasAttribute("tabindex")&&o.setAttribute("tabindex","0"),!l.code)return s.hooks.run("complete",l),void(a&&a.call(l.element));if(s.hooks.run("before-highlight",l),l.grammar)if(n&&e.Worker){var c=new Worker(s.filename);c.onmessage=function(e){u(e.data)},c.postMessage(JSON.stringify({language:l.language,code:l.code,immediateClose:!0}))}else u(s.highlight(l.code,l.grammar,l.language));else u(s.util.encode(l.code))},highlight:function(e,t,n){var a={code:e,grammar:t,language:n};if(s.hooks.run("before-tokenize",a),!a.grammar)throw new Error('The language "'+a.language+'" has no grammar.');return a.tokens=s.tokenize(a.code,a.grammar),s.hooks.run("after-tokenize",a),r.stringify(s.util.encode(a.tokens),a.language)},tokenize:function(e,t){var n=t.rest;if(n){for(var a in n)t[a]=n[a];delete t.rest}var s=new l;return u(s,s.head,e),o(e,s,t,s.head,0),function(e){for(var t=[],n=e.head.next;n!==e.tail;)t.push(n.value),n=n.next;return t}(s)},hooks:{all:{},add:function(e,t){var n=s.hooks.all;n[e]=n[e]||[],n[e].push(t)},run:function(e,t){var n=s.hooks.all[e];if(n&&n.length)for(var a,r=0;a=n[r++];)a(t)}},Token:r};function r(e,t,n,a){this.type=e,this.content=t,this.alias=n,this.length=0|(a||"").length}function i(e,t,n,a){e.lastIndex=t;var s=e.exec(n);if(s&&a&&s[1]){var r=s[1].length;s.index+=r,s[0]=s[0].slice(r)}return s}function o(e,t,n,a,l,d){for(var g in n)if(n.hasOwnProperty(g)&&n[g]){var p=n[g];p=Array.isArray(p)?p:[p];for(var b=0;b<p.length;++b){if(d&&d.cause==g+","+b)return;var h=p[b],f=h.inside,m=!!h.lookbehind,y=!!h.greedy,w=h.alias;if(y&&!h.pattern.global){var k=h.pattern.toString().match(/[imsuy]*$/)[0];h.pattern=RegExp(h.pattern.source,k+"g")}for(var v=h.pattern||h,_=a.next,x=l;_!==t.tail&&!(d&&x>=d.reach);x+=_.value.length,_=_.next){var F=_.value;if(t.length>e.length)return;if(!(F instanceof r)){var A,S=1;if(y){if(!(A=i(v,x,e,m))||A.index>=e.length)break;var $=A.index,z=A.index+A[0].length,E=x;for(E+=_.value.length;$>=E;)E+=(_=_.next).value.length;if(x=E-=_.value.length,_.value instanceof r)continue;for(var C=_;C!==t.tail&&(E<z||"string"==typeof C.value);C=C.next)S++,E+=C.value.length;S--,F=e.slice(x,E),A.index-=x}else if(!(A=i(v,0,F,m)))continue;$=A.index;var j=A[0],B=F.slice(0,$),T=F.slice($+j.length),O=x+F.length;d&&O>d.reach&&(d.reach=O);var P=_.prev;if(B&&(P=u(t,P,B),x+=B.length),c(t,P,S),_=u(t,P,new r(g,f?s.tokenize(j,f):j,w,j)),T&&u(t,_,T),S>1){var N={cause:g+","+b,reach:O};o(e,t,n,_.prev,x,N),d&&N.reach>d.reach&&(d.reach=N.reach)}}}}}}function l(){var e={value:null,prev:null,next:null},t={value:null,prev:e,next:null};e.next=t,this.head=e,this.tail=t,this.length=0}function u(e,t,n){var a=t.next,s={value:n,prev:t,next:a};return t.next=s,a.prev=s,e.length++,s}function c(e,t,n){for(var a=t.next,s=0;s<n&&a!==e.tail;s++)a=a.next;t.next=a,a.prev=t,e.length-=s}if(e.Prism=s,r.stringify=function e(t,n){if("string"==typeof t)return t;if(Array.isArray(t)){var a="";return t.forEach((function(t){a+=e(t,n)})),a}var r={type:t.type,content:e(t.content,n),tag:"span",classes:["token",t.type],attributes:{},language:n},i=t.alias;i&&(Array.isArray(i)?Array.prototype.push.apply(r.classes,i):r.classes.push(i)),s.hooks.run("wrap",r);var o="";for(var l in r.attributes)o+=" "+l+'="'+(r.attributes[l]||"").replace(/"/g,"&quot;")+'"';return"<"+r.tag+' class="'+r.classes.join(" ")+'"'+o+">"+r.content+"</"+r.tag+">"},!e.document)return e.addEventListener?(s.disableWorkerMessageHandler||e.addEventListener("message",(function(t){var n=JSON.parse(t.data),a=n.language,r=n.code,i=n.immediateClose;e.postMessage(s.highlight(r,s.languages[a],a)),i&&e.close()}),!1),s):s;var d=s.util.currentScript();function g(){s.manual||s.highlightAll()}if(d&&(s.filename=d.src,d.hasAttribute("data-manual")&&(s.manual=!0)),!s.manual){var p=document.readyState;"loading"===p||"interactive"===p&&d&&d.defer?document.addEventListener("DOMContentLoaded",g):window.requestAnimationFrame?window.requestAnimationFrame(g):window.setTimeout(g,16)}return s}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});return s.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},function(e){function t(e,t){return"___"+e.toUpperCase()+t+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(n,a,s,r){if(n.language===a){var i=n.tokenStack=[];n.code=n.code.replace(s,(function(e){if("function"==typeof r&&!r(e))return e;for(var s,o=i.length;-1!==n.code.indexOf(s=t(a,o));)++o;return i[o]=e,s})),n.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(n,a){if(n.language===a&&n.tokenStack){n.grammar=e.languages[a];var s=0,r=Object.keys(n.tokenStack);!function i(o){for(var l=0;l<o.length&&!(s>=r.length);l++){var u=o[l];if("string"==typeof u||u.content&&"string"==typeof u.content){var c=r[s],d=n.tokenStack[c],g="string"==typeof u?u:u.content,p=t(a,c),b=g.indexOf(p);if(b>-1){++s;var h=g.substring(0,b),f=new e.Token(a,e.tokenize(d,n.grammar),"language-"+a,d),m=g.substring(b+p.length),y=[];h&&y.push.apply(y,i([h])),y.push(f),m&&y.push.apply(y,i([m])),"string"==typeof u?o.splice.apply(o,[l,1].concat(y)):u.content=y}}else u.content&&i(u.content)}return o}(n.tokens)}}}})}(s),s.languages.c=s.languages.extend("clike",{comment:{pattern:/\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},string:{pattern:/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/,greedy:!0},"class-name":{pattern:/(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/,lookbehind:!0},keyword:/\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/,function:/\b[a-z_]\w*(?=\s*\()/i,number:/(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/}),s.languages.insertBefore("c","string",{char:{pattern:/'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/,greedy:!0}}),s.languages.insertBefore("c","string",{macro:{pattern:/(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im,lookbehind:!0,greedy:!0,alias:"property",inside:{string:[{pattern:/^(#\s*include\s*)<[^>]+>/,lookbehind:!0},s.languages.c.string],char:s.languages.c.char,comment:s.languages.c.comment,"macro-name":[{pattern:/(^#\s*define\s+)\w+\b(?!\()/i,lookbehind:!0},{pattern:/(^#\s*define\s+)\w+\b(?=\()/i,lookbehind:!0,alias:"function"}],directive:{pattern:/^(#\s*)[a-z]+/,lookbehind:!0,alias:"keyword"},"directive-hash":/^#/,punctuation:/##|\\(?=[\r\n])/,expression:{pattern:/\S[\s\S]*/,inside:s.languages.c}}}}),s.languages.insertBefore("c","function",{constant:/\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/}),delete s.languages.c.boolean,function(e){var t=/\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,n=/\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend("c",{"class-name":[{pattern:RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/,/\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i,/\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/],keyword:t,number:{pattern:/(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/,boolean:/\b(?:false|true)\b/}),e.languages.insertBefore("cpp","string",{module:{pattern:RegExp(/(\b(?:import|module)\s+)/.source+"(?:"+/"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source+"|"+/<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g,(function(){return n}))+")"),lookbehind:!0,greedy:!0,inside:{string:/^[<"][\s\S]+/,operator:/:/,punctuation:/\./}},"raw-string":{pattern:/R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,alias:"string",greedy:!0}}),e.languages.insertBefore("cpp","keyword",{"generic-function":{pattern:/\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i,inside:{function:/^\w+/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:e.languages.cpp}}}}),e.languages.insertBefore("cpp","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}}),e.languages.insertBefore("cpp","class-name",{"base-clause":{pattern:/(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend("cpp",{})}}),e.languages.insertBefore("inside","double-colon",{"class-name":/\b[a-z_]\w*\b(?!\s*::)/i},e.languages.cpp["base-clause"])}(s),function(e){function t(e,t){return e.replace(/<<(\d+)>>/g,(function(e,n){return"(?:"+t[+n]+")"}))}function n(e,n,a){return RegExp(t(e,n),a||"")}function a(e,t){for(var n=0;n<t;n++)e=e.replace(/<<self>>/g,(function(){return"(?:"+e+")"}));return e.replace(/<<self>>/g,"[^\\s\\S]")}var s="bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void",r="class enum interface record struct",i="add alias and ascending async await by descending from(?=\\s*(?:\\w|$)) get global group into init(?=\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\s*{)",o="abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield";function l(e){return"\\b(?:"+e.trim().replace(/ /g,"|")+")\\b"}var u=l(r),c=RegExp(l(s+" "+r+" "+i+" "+o)),d=l(r+" "+i+" "+o),g=l(s+" "+r+" "+o),p=a(/<(?:[^<>;=+\-*/%&|^]|<<self>>)*>/.source,2),b=a(/\((?:[^()]|<<self>>)*\)/.source,2),h=/@?\b[A-Za-z_]\w*\b/.source,f=t(/<<0>>(?:\s*<<1>>)?/.source,[h,p]),m=t(/(?!<<0>>)<<1>>(?:\s*\.\s*<<1>>)*/.source,[d,f]),y=/\[\s*(?:,\s*)*\]/.source,w=t(/<<0>>(?:\s*(?:\?\s*)?<<1>>)*(?:\s*\?)?/.source,[m,y]),k=t(/[^,()<>[\];=+\-*/%&|^]|<<0>>|<<1>>|<<2>>/.source,[p,b,y]),v=t(/\(<<0>>+(?:,<<0>>+)+\)/.source,[k]),_=t(/(?:<<0>>|<<1>>)(?:\s*(?:\?\s*)?<<2>>)*(?:\s*\?)?/.source,[v,m,y]),x={keyword:c,punctuation:/[<>()?,.:[\]]/},F=/'(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'/.source,A=/"(?:\\.|[^\\"\r\n])*"/.source,S=/@"(?:""|\\[\s\S]|[^\\"])*"(?!")/.source;e.languages.csharp=e.languages.extend("clike",{string:[{pattern:n(/(^|[^$\\])<<0>>/.source,[S]),lookbehind:!0,greedy:!0},{pattern:n(/(^|[^@$\\])<<0>>/.source,[A]),lookbehind:!0,greedy:!0}],"class-name":[{pattern:n(/(\busing\s+static\s+)<<0>>(?=\s*;)/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+<<0>>\s*=\s*)<<1>>(?=\s*;)/.source,[h,_]),lookbehind:!0,inside:x},{pattern:n(/(\busing\s+)<<0>>(?=\s*=)/.source,[h]),lookbehind:!0},{pattern:n(/(\b<<0>>\s+)<<1>>/.source,[u,f]),lookbehind:!0,inside:x},{pattern:n(/(\bcatch\s*\(\s*)<<0>>/.source,[m]),lookbehind:!0,inside:x},{pattern:n(/(\bwhere\s+)<<0>>/.source,[h]),lookbehind:!0},{pattern:n(/(\b(?:is(?:\s+not)?|as)\s+)<<0>>/.source,[w]),lookbehind:!0,inside:x},{pattern:n(/\b<<0>>(?=\s+(?!<<1>>|with\s*\{)<<2>>(?:\s*[=,;:{)\]]|\s+(?:in|when)\b))/.source,[_,g,h]),inside:x}],keyword:c,number:/(?:\b0(?:x[\da-f_]*[\da-f]|b[01_]*[01])|(?:\B\.\d+(?:_+\d+)*|\b\d+(?:_+\d+)*(?:\.\d+(?:_+\d+)*)?)(?:e[-+]?\d+(?:_+\d+)*)?)(?:[dflmu]|lu|ul)?\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\1|~|\?\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\?\.?|::|[{}[\];(),.:]/}),e.languages.insertBefore("csharp","number",{range:{pattern:/\.\./,alias:"operator"}}),e.languages.insertBefore("csharp","punctuation",{"named-parameter":{pattern:n(/([(,]\s*)<<0>>(?=\s*:)/.source,[h]),lookbehind:!0,alias:"punctuation"}}),e.languages.insertBefore("csharp","class-name",{namespace:{pattern:n(/(\b(?:namespace|using)\s+)<<0>>(?:\s*\.\s*<<0>>)*(?=\s*[;{])/.source,[h]),lookbehind:!0,inside:{punctuation:/\./}},"type-expression":{pattern:n(/(\b(?:default|sizeof|typeof)\s*\(\s*(?!\s))(?:[^()\s]|\s(?!\s)|<<0>>)*(?=\s*\))/.source,[b]),lookbehind:!0,alias:"class-name",inside:x},"return-type":{pattern:n(/<<0>>(?=\s+(?:<<1>>\s*(?:=>|[({]|\.\s*this\s*\[)|this\s*\[))/.source,[_,m]),inside:x,alias:"class-name"},"constructor-invocation":{pattern:n(/(\bnew\s+)<<0>>(?=\s*[[({])/.source,[_]),lookbehind:!0,inside:x,alias:"class-name"},"generic-method":{pattern:n(/<<0>>\s*<<1>>(?=\s*\()/.source,[h,p]),inside:{function:n(/^<<0>>/.source,[h]),generic:{pattern:RegExp(p),alias:"class-name",inside:x}}},"type-list":{pattern:n(/\b((?:<<0>>\s+<<1>>|record\s+<<1>>\s*<<5>>|where\s+<<2>>)\s*:\s*)(?:<<3>>|<<4>>|<<1>>\s*<<5>>|<<6>>)(?:\s*,\s*(?:<<3>>|<<4>>|<<6>>))*(?=\s*(?:where|[{;]|=>|$))/.source,[u,f,h,_,c.source,b,/\bnew\s*\(\s*\)/.source]),lookbehind:!0,inside:{"record-arguments":{pattern:n(/(^(?!new\s*\()<<0>>\s*)<<1>>/.source,[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:c,"class-name":{pattern:RegExp(_),greedy:!0,inside:x},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\t ]*)#.*/m,lookbehind:!0,alias:"property",inside:{directive:{pattern:/(#)\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\b/,lookbehind:!0,alias:"keyword"}}}});var $=A+"|"+F,z=t(/\/(?![*/])|\/\/[^\r\n]*[\r\n]|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>/.source,[$]),E=a(t(/[^"'/()]|<<0>>|\(<<self>>*\)/.source,[z]),2),C=/\b(?:assembly|event|field|method|module|param|property|return|type)\b/.source,j=t(/<<0>>(?:\s*\(<<1>>*\))?/.source,[m,E]);e.languages.insertBefore("csharp","class-name",{attribute:{pattern:n(/((?:^|[^\s\w>)?])\s*\[\s*)(?:<<0>>\s*:\s*)?<<1>>(?:\s*,\s*<<1>>)*(?=\s*\])/.source,[C,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:n(/^<<0>>(?=\s*:)/.source,[C]),alias:"keyword"},"attribute-arguments":{pattern:n(/\(<<0>>*\)/.source,[E]),inside:e.languages.csharp},"class-name":{pattern:RegExp(m),inside:{punctuation:/\./}},punctuation:/[:,]/}}});var B=/:[^}\r\n]+/.source,T=a(t(/[^"'/()]|<<0>>|\(<<self>>*\)/.source,[z]),2),O=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[T,B]),P=a(t(/[^"'/()]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|<<0>>|\(<<self>>*\)/.source,[$]),2),N=t(/\{(?!\{)(?:(?![}:])<<0>>)*<<1>>?\}/.source,[P,B]);function R(t,a){return{interpolation:{pattern:n(/((?:^|[^{])(?:\{\{)*)<<0>>/.source,[t]),lookbehind:!0,inside:{"format-string":{pattern:n(/(^\{(?:(?![}:])<<0>>)*)<<1>>(?=\}$)/.source,[a,B]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\{|\}$/,expression:{pattern:/[\s\S]+/,alias:"language-csharp",inside:e.languages.csharp}}},string:/[\s\S]+/}}e.languages.insertBefore("csharp","string",{"interpolation-string":[{pattern:n(/(^|[^\\])(?:\$@|@\$)"(?:""|\\[\s\S]|\{\{|<<0>>|[^\\{"])*"/.source,[O]),lookbehind:!0,greedy:!0,inside:R(O,T)},{pattern:n(/(^|[^@\\])\$"(?:\\.|\{\{|<<0>>|[^\\"{])*"/.source,[N]),lookbehind:!0,greedy:!0,inside:R(N,P)}],char:{pattern:RegExp(F),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(s),function(e){var t=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+t.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+t.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+t.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+t.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:t,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;var n=e.languages.markup;n&&(n.tag.addInlined("style","css"),n.tag.addAttribute("style","css"))}(s),function(e){var t=/\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/,n=/(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source,a={pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/,inside:{punctuation:/\./}},punctuation:/\./}};e.languages.java=e.languages.extend("clike",{string:{pattern:/(^|[^\\])"(?:\\.|[^"\\\r\n])*"/,lookbehind:!0,greedy:!0},"class-name":[a,{pattern:RegExp(/(^|[^\w.])/.source+n+/[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source),lookbehind:!0,inside:a.inside},{pattern:RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source+n+/[A-Z]\w*\b/.source),lookbehind:!0,inside:a.inside}],keyword:t,function:[e.languages.clike.function,{pattern:/(::\s*)[a-z_]\w*/,lookbehind:!0}],number:/\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\b[A-Z][A-Z_\d]+\b/}),e.languages.insertBefore("java","string",{"triple-quoted-string":{pattern:/"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/,greedy:!0,alias:"string"},char:{pattern:/'(?:\\.|[^'\\\r\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore("java","class-name",{annotation:{pattern:/(^|[^.])@\w+(?:\s*\.\s*\w+)*/,lookbehind:!0,alias:"punctuation"},generics:{pattern:/<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{"class-name":a,keyword:t,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(/(\bimport\s+)/.source+n+/(?:[A-Z]\w*|\*)(?=\s*;)/.source),lookbehind:!0,inside:{namespace:a.inside.namespace,punctuation:/\./,operator:/\*/,"class-name":/\w+/}},{pattern:RegExp(/(\bimport\s+static\s+)/.source+n+/(?:\w+|\*)(?=\s*;)/.source),lookbehind:!0,alias:"static",inside:{namespace:a.inside.namespace,static:/\b\w+$/,punctuation:/\./,operator:/\*/,"class-name":/\w+/}}],namespace:{pattern:RegExp(/(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0,inside:{punctuation:/\./}}})}(s),s.languages.javascript=s.languages.extend("clike",{"class-name":[s.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),s.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,s.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:s.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:s.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:s.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:s.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:s.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),s.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:s.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),s.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),s.languages.markup&&(s.languages.markup.tag.addInlined("script","javascript"),s.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),s.languages.js=s.languages.javascript,s.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},s.languages.markup.tag.inside["attr-value"].inside.entity=s.languages.markup.entity,s.languages.markup.doctype.inside["internal-subset"].inside=s.languages.markup,s.hooks.add("wrap",(function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,"&"))})),Object.defineProperty(s.languages.markup.tag,"addInlined",{value:function(e,t){var n={};n["language-"+t]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:s.languages[t]},n.cdata=/^<!\[CDATA\[|\]\]>$/i;var a={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:n}};a["language-"+t]={pattern:/[\s\S]+/,inside:s.languages[t]};var r={};r[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,(function(){return e})),"i"),lookbehind:!0,greedy:!0,inside:a},s.languages.insertBefore("markup","cdata",r)}}),Object.defineProperty(s.languages.markup.tag,"addAttribute",{value:function(e,t){s.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[t,"language-"+t],inside:s.languages[t]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),s.languages.html=s.languages.markup,s.languages.mathml=s.languages.markup,s.languages.svg=s.languages.markup,s.languages.xml=s.languages.extend("markup",{}),s.languages.ssml=s.languages.xml,s.languages.atom=s.languages.xml,s.languages.rss=s.languages.xml,function(e){var t=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,n=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],a=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,s=/<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,r=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:t,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:a,operator:s,punctuation:r};var i={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},o=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:i}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:i}}];e.languages.insertBefore("php","variable",{string:o,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:t,string:o,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:n,number:a,operator:s,punctuation:r}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(t){/<\?/.test(t.code)&&e.languages["markup-templating"].buildPlaceholders(t,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(t){e.languages["markup-templating"].tokenizePlaceholders(t,"php")}))}(s),s.languages.python={comment:{pattern:/(^|[^\\])#.*/,lookbehind:!0,greedy:!0},"string-interpolation":{pattern:/(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,lookbehind:!0,inside:{"format-spec":{pattern:/(:)[^:(){}]+(?=\}$)/,lookbehind:!0},"conversion-option":{pattern:/![sra](?=[:}]$)/,alias:"punctuation"},rest:null}},string:/[\s\S]+/}},"triple-quoted-string":{pattern:/(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,greedy:!0,alias:"string"},string:{pattern:/(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,greedy:!0},function:{pattern:/((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,lookbehind:!0},"class-name":{pattern:/(\bclass\s+)\w+/i,lookbehind:!0},decorator:{pattern:/(^[\t ]*)@\w+(?:\.\w+)*/m,lookbehind:!0,alias:["annotation","punctuation"],inside:{punctuation:/\./}},keyword:/\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,builtin:/\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,boolean:/\b(?:False|None|True)\b/,number:/\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,operator:/[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\];(),.:]/},s.languages.python["string-interpolation"].inside.interpolation.inside.rest=s.languages.python,s.languages.py=s.languages.python,function(e){e.languages.ruby=e.languages.extend("clike",{comment:{pattern:/#.*|^=begin\s[\s\S]*?^=end/m,greedy:!0},"class-name":{pattern:/(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/,operator:/\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/,punctuation:/[(){}[\].,;]/}),e.languages.insertBefore("ruby","operator",{"double-colon":{pattern:/::/,alias:"punctuation"}});var t={pattern:/((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/,lookbehind:!0,inside:{content:{pattern:/^(#\{)[\s\S]+(?=\}$)/,lookbehind:!0,inside:e.languages.ruby},delimiter:{pattern:/^#\{|\}$/,alias:"punctuation"}}};delete e.languages.ruby.function;var n="(?:"+[/([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source,/\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source,/\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source,/\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source,/<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source].join("|")+")",a=/(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source;e.languages.insertBefore("ruby","keyword",{"regex-literal":[{pattern:RegExp(/%r/.source+n+/[egimnosux]{0,6}/.source),greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:t,regex:/[\s\S]+/}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:[{pattern:RegExp(/(^|[^:]):/.source+a),lookbehind:!0,greedy:!0},{pattern:RegExp(/([\r\n{(,][ \t]*)/.source+a+/(?=:(?!:))/.source),lookbehind:!0,greedy:!0}],"method-definition":{pattern:/(\bdef\s+)\w+(?:\s*\.\s*\w+)?/,lookbehind:!0,inside:{function:/\b\w+$/,keyword:/^self\b/,"class-name":/^\w+/,punctuation:/\./}}}),e.languages.insertBefore("ruby","string",{"string-literal":[{pattern:RegExp(/%[qQiIwWs]?/.source+n),greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?/}},interpolation:t,string:/[\s\S]+/}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i,inside:{symbol:/\b\w+/,punctuation:/^<<[-~]?'|'$/}},string:/[\s\S]+/}}],"command-literal":[{pattern:RegExp(/%x/.source+n),greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}},{pattern:/`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/,greedy:!0,inside:{interpolation:t,command:{pattern:/[\s\S]+/,alias:"string"}}}]}),delete e.languages.ruby.string,e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/,constant:/\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/}),e.languages.rb=e.languages.ruby}(s),window.Prism=a,s}(),o=e=>t=>t.options.get(e),l=o("codesample_languages"),u=o("codesample_global_prismjs"),c=e=>r.Prism&&u(e)?r.Prism:i,d=e=>t(e)&&"PRE"===e.nodeName&&-1!==e.className.indexOf("language-"),g=e=>{const t=e.selection?e.selection.getNode():null;return d(t)?a.some(t):a.none()},p=e=>{const t=(e=>l(e)||[{text:"HTML/XML",value:"markup"},{text:"JavaScript",value:"javascript"},{text:"CSS",value:"css"},{text:"PHP",value:"php"},{text:"Ruby",value:"ruby"},{text:"Python",value:"python"},{text:"Java",value:"java"},{text:"C",value:"c"},{text:"C#",value:"csharp"},{text:"C++",value:"cpp"}])(e),n=(r=t,((e,t)=>0<e.length?a.some(e[0]):a.none())(r)).fold(("",()=>""),(e=>e.value));var r;const i=((e,t)=>g(e).fold((()=>t),(e=>{const n=e.className.match(/language-(\w+)/);return n?n[1]:t})))(e,n),o=(e=>g(e).bind((e=>a.from(e.textContent))).getOr(""))(e);e.windowManager.open({title:"Insert/Edit Code Sample",size:"large",body:{type:"panel",items:[{type:"listbox",name:"language",label:"Language",items:t},{type:"textarea",name:"code",label:"Code view"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{language:i,code:o},onSubmit:t=>{const n=t.getData();((e,t,n)=>{const a=e.dom;e.undoManager.transact((()=>{const r=g(e);return n=s.DOM.encode(n),r.fold((()=>{e.insertContent('<pre id="__new" class="language-'+t+'">'+n+"</pre>");const s=a.select("#__new")[0];a.setAttrib(s,"id",null),e.selection.select(s)}),(s=>{a.setAttrib(s,"class","language-"+t),s.innerHTML=n,c(e).highlightElement(s),e.selection.select(s)}))}))})(e,n.language,n.code),t.close()}})},b=(h=/^\s+|\s+$/g,e=>e.replace(h,""));var h,f=tinymce.util.Tools.resolve("tinymce.util.Tools");const m=(e,t=n)=>n=>{const a=()=>{n.setEnabled(e.selection.isEditable()),t(n)};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("codesample",(e=>{(e=>{const t=e.options.register;t("codesample_languages",{processor:"object[]"}),t("codesample_global_prismjs",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreProcess",(t=>{const n=e.dom,a=n.select("pre[contenteditable=false]",t.node);f.each(f.grep(a,d),(e=>{const t=e.textContent;let a;for(n.setAttrib(e,"class",b(n.getAttrib(e,"class"))),n.setAttrib(e,"contentEditable",null),n.setAttrib(e,"data-mce-highlighted",null);a=e.firstChild;)e.removeChild(a);n.add(e,"code").textContent=t}))})),e.on("SetContent",(()=>{const t=e.dom,n=f.grep(t.select("pre"),(e=>d(e)&&"true"!==t.getAttrib(e,"data-mce-highlighted")));n.length&&e.undoManager.transact((()=>{f.each(n,(n=>{var a;f.each(t.select("br",n),(n=>{t.replace(e.getDoc().createTextNode("\n"),n)})),n.innerHTML=t.encode(null!==(a=n.textContent)&&void 0!==a?a:""),c(e).highlightElement(n),t.setAttrib(n,"data-mce-highlighted",!0),n.className=b(n.className)}))}))})),e.on("PreInit",(()=>{e.parser.addNodeFilter("pre",(e=>{var t;for(let n=0,a=e.length;n<a;n++){const a=e[n];-1!==(null!==(t=a.attr("class"))&&void 0!==t?t:"").indexOf("language-")&&(a.attr("contenteditable","false"),a.attr("data-mce-highlighted","false"))}}))}))})(e),(e=>{const t=()=>e.execCommand("codesample");e.ui.registry.addToggleButton("codesample",{icon:"code-sample",tooltip:"Insert/edit code sample",onAction:t,onSetup:m(e,(t=>{t.setActive((e=>{const t=e.selection.getStart();return e.dom.is(t,'pre[class*="language-"]')})(e))}))}),e.ui.registry.addMenuItem("codesample",{text:"Code sample...",icon:"code-sample",onAction:t,onSetup:m(e)})})(e),(e=>{e.addCommand("codesample",(()=>{const t=e.selection.getNode();e.selection.isCollapsed()||d(t)?p(e):e.formatter.toggle("code")}))})(e),e.on("dblclick",(t=>{d(t.target)&&p(e)}))}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js
new file mode 100644
index 0000000..eccdc50
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/directionality/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o<r;o++)e(t[o],o)},c=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),y=m(11),p=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),b=t=>d(t.dom.host),N=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return y(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=N,i=b,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||N(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r<n;r++){const n=t[r];e(n,r)&&o.push(n)}return o})(((t,e)=>{const o=t.length,r=new Array(o);for(let n=0;n<o;n++){const o=t[n];r[n]=e(o,n)}return r})(t.dom.childNodes,d),(t=>h(t,e))))(t),E=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const T=(t,e,n)=>{u(e,(e=>{const c=d(e),m=E(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),S(e)===n?p(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),S(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=A(f,"li[dir],li[style]");u(e,(e=>{p(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},C=(t,e)=>{t.selection.isEditable()&&(T(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},D=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(S(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js
new file mode 100644
index 0000000..6fcec71
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.js
@@ -0,0 +1 @@
+window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挴" src="1f4af.png"/>',fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敘" src="1f522.png"/>',fitzpatrick_scale:false,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃榾" src="1f600.png"/>',fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槵" src="1f62c.png"/>',fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃榿" src="1f601.png"/>',fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槀" src="1f602.png"/>',fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぃ" src="1f923.png"/>',fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃コ" src="1f973.png"/>',fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槂" src="1f603.png"/>',fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槃" src="1f604.png"/>',fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槄" src="1f605.png"/>',fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槅" src="1f606.png"/>',fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槆" src="1f607.png"/>',fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槈" src="1f609.png"/>',fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槉" src="1f60a.png"/>',fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檪" src="1f642.png"/>',fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檭" src="1f643.png"/>',fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽猴笍" src="263a.png"/>',fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃構" src="1f60b.png"/>',fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槍" src="1f60c.png"/>',fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槏" src="1f60d.png"/>',fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃グ" src="1f970.png"/>',fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槝" src="1f618.png"/>',fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槜" src="1f617.png"/>',fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槞" src="1f619.png"/>',fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槡" src="1f61a.png"/>',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槣" src="1f61c.png"/>',fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃お" src="1f92a.png"/>',fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃え" src="1f928.png"/>',fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d0.png"/>',fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槤" src="1f61d.png"/>',fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槢" src="1f61b.png"/>',fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f911.png"/>',fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f913.png"/>',fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槑" src="1f60e.png"/>',fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぉ" src="1f929.png"/>',fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぁ" src="1f921.png"/>',fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f920.png"/>',fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f917.png"/>',fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槒" src="1f60f.png"/>',fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樁" src="1f636.png"/>',fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槓" src="1f610.png"/>',fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槕" src="1f611.png"/>',fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槖" src="1f612.png"/>',fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檮" src="1f644.png"/>',fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f914.png"/>',fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぅ" src="1f925.png"/>',fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃き" src="1f92d.png"/>',fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃か" src="1f92b.png"/>',fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃が" src="1f92c.png"/>',fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃く" src="1f92f.png"/>',fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槼" src="1f633.png"/>',fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槥" src="1f61e.png"/>',fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槦" src="1f61f.png"/>',fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槧" src="1f620.png"/>',fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槨" src="1f621.png"/>',fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃様" src="1f614.png"/>',fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槙" src="1f615.png"/>',fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檨" src="1f641.png"/>',fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2639.png"/>',fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槪" src="1f623.png"/>',fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槚" src="1f616.png"/>',fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槴" src="1f62b.png"/>',fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槱" src="1f629.png"/>',fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ズ" src="1f97a.png"/>',fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槫" src="1f624.png"/>',fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槷" src="1f62e.png"/>',fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槺" src="1f631.png"/>',fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槰" src="1f628.png"/>',fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槹" src="1f630.png"/>',fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槸" src="1f62f.png"/>',fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槮" src="1f626.png"/>',fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槯" src="1f627.png"/>',fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槩" src="1f622.png"/>',fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槬" src="1f625.png"/>',fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃い" src="1f924.png"/>',fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槳" src="1f62a.png"/>',fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槗" src="1f613.png"/>',fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃サ" src="1f975.png"/>',fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ザ" src="1f976.png"/>',fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槶" src="1f62d.png"/>',fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樀" src="1f635.png"/>',fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槻" src="1f632.png"/>',fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f910.png"/>',fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃あ" src="1f922.png"/>',fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぇ" src="1f927.png"/>',fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぎ" src="1f92e.png"/>',fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樂" src="1f637.png"/>',fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f912.png"/>',fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f915.png"/>',fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ゴ" src="1f974.png"/>',fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槾" src="1f634.png"/>',fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挙" src="1f4a4.png"/>',fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挬" src="1f4a9.png"/>',fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃槇" src="1f608.png"/>',fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懣" src="1f47f.png"/>',fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懝" src="1f479.png"/>',fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懞" src="1f47a.png"/>',fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拃" src="1f480.png"/>',fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懟" src="1f47b.png"/>',fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懡" src="1f47d.png"/>',fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f916.png"/>',fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樅" src="1f63a.png"/>',fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樃" src="1f638.png"/>',fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樄" src="1f639.png"/>',fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樆" src="1f63b.png"/>',fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樇" src="1f63c.png"/>',fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樈" src="1f63d.png"/>',fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檧" src="1f640.png"/>',fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樋" src="1f63f.png"/>',fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃樉" src="1f63e.png"/>',fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃げ" src="1f932.png"/>',fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檶" src="1f64c.png"/>',fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憦" src="1f44f.png"/>',fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憢" src="1f44b.png"/>',fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f919.png"/>',fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憤" src="1f44d.png"/>',fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憥" src="1f44e.png"/>',fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憡" src="1f44a.png"/>',fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="270a.png"/>',fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91b.png"/>',fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91c.png"/>',fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="270c.png"/>',fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憣" src="1f44c.png"/>',fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="270b.png"/>',fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91a.png"/>',fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憪" src="1f450.png"/>',fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挭" src="1f4aa.png"/>',fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檹" src="1f64f.png"/>',fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Χ" src="1f9b6.png"/>',fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Φ" src="1f9b5.png"/>',fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91d.png"/>',fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="261d.png"/>',fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憜" src="1f446.png"/>',fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憞" src="1f447.png"/>',fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憟" src="1f448.png"/>',fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憠" src="1f449.png"/>',fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枙" src="1f595.png"/>',fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枑" src="1f590.png"/>',fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91f.png"/>',fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f918.png"/>',fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f91e.png"/>',fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枛" src="1f596.png"/>',fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="270d.png"/>',fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃こ" src="1f933.png"/>',fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拝" src="1f485.png"/>',fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憚" src="1f444.png"/>',fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ψ" src="1f9b7.png"/>',fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憛" src="1f445.png"/>',fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憘" src="1f442.png"/>',fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憙" src="1f443.png"/>',fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憗" src="1f441.png"/>',fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憖" src="1f440.png"/>',fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9e0.png"/>',fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懁" src="1f464.png"/>',fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懃" src="1f465.png"/>',fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棧" src="1f5e3.png"/>',fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懚" src="1f476.png"/>',fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d2.png"/>',fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懄" src="1f466.png"/>',fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懅" src="1f467.png"/>',fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d1.png"/>',fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆" src="1f468.png"/>',fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇" src="1f469.png"/>',fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懕鈥嶁檧锔�" src="1f471-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懕" src="1f471.png"/>',fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d4.png"/>',fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d3.png"/>',fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懘" src="1f474.png"/>',fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懙" src="1f475.png"/>',fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懖" src="1f472.png"/>',fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9d5.png"/>',fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懗鈥嶁檧锔�" src="1f473-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懗" src="1f473.png"/>',fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懏鈥嶁檧锔�" src="1f46e-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懏" src="1f46e.png"/>',fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懛鈥嶁檧锔�" src="1f477-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懛" src="1f477.png"/>',fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拏鈥嶁檧锔�" src="1f482-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拏" src="1f482.png"/>',fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暤锔忊�嶁檧锔�" src="1f575-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暤" src="1f575.png"/>',fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶁殨锔�" src="1f469-200d-2695-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶁殨锔�" src="1f468-200d-2695-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煂�" src="1f469-200d-1f33e.png"/>',fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煂�" src="1f468-200d-1f33e.png"/>',fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煃�" src="1f469-200d-1f373.png"/>',fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煃�" src="1f468-200d-1f373.png"/>',fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煄�" src="1f469-200d-1f393.png"/>',fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煄�" src="1f468-200d-1f393.png"/>',fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煄�" src="1f469-200d-1f3a4.png"/>',fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煄�" src="1f468-200d-1f3a4.png"/>',fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煆�" src="1f469-200d-1f3eb.png"/>',fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煆�" src="1f468-200d-1f3eb.png"/>',fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煆�" src="1f469-200d-1f3ed.png"/>',fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煆�" src="1f468-200d-1f3ed.png"/>',fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煉�" src="1f469-200d-1f4bb.png"/>',fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煉�" src="1f468-200d-1f4bb.png"/>',fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煉�" src="1f469-200d-1f4bc.png"/>',fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煉�" src="1f468-200d-1f4bc.png"/>',fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煍�" src="1f469-200d-1f527.png"/>',fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煍�" src="1f468-200d-1f527.png"/>',fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煍�" src="1f469-200d-1f52c.png"/>',fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煍�" src="1f468-200d-1f52c.png"/>',fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煄�" src="1f469-200d-1f3a8.png"/>',fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煄�" src="1f468-200d-1f3a8.png"/>',fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煔�" src="1f469-200d-1f692.png"/>',fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煔�" src="1f468-200d-1f692.png"/>',fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶁湀锔�" src="1f469-200d-2708-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶁湀锔�" src="1f468-200d-2708-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煔�" src="1f469-200d-1f680.png"/>',fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煔�" src="1f468-200d-1f680.png"/>',fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶁殩锔�" src="1f469-200d-2696-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶁殩锔�" src="1f468-200d-2696-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ω鈥嶁檧锔�" src="1f9b8-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ω鈥嶁檪锔�" src="1f9b8-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9b9-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9b9-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ざ" src="1f936.png"/>',fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巺" src="1f385.png"/>',fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9d9-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9d9-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9dd-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9dd-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9db-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9db-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9df-200d-2640-fe0f.png"/>',fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9df-200d-2642-fe0f.png"/>',fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9de-200d-2640-fe0f.png"/>',fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9de-200d-2642-fe0f.png"/>',fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9dc-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9dc-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9da-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9da-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懠" src="1f47c.png"/>',fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぐ" src="1f930.png"/>',fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃け" src="1f931.png"/>',fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懜" src="1f478.png"/>',fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ご" src="1f934.png"/>',fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懓" src="1f470.png"/>',fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃さ" src="1f935.png"/>',fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弮鈥嶁檧锔�" src="1f3c3-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弮" src="1f3c3.png"/>',fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毝鈥嶁檧锔�" src="1f6b6-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毝" src="1f6b6.png"/>',fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拑" src="1f483.png"/>',fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暫" src="1f57a.png"/>',fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懐" src="1f46f.png"/>',fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懐鈥嶁檪锔�" src="1f46f-200d-2642-fe0f.png"/>',fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懌" src="1f46b.png"/>',fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懍" src="1f46c.png"/>',fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懎" src="1f46d.png"/>',fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檱鈥嶁檧锔�" src="1f647-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檱" src="1f647.png"/>',fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃う鈥嶁檪锔�" src="1f926-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃う鈥嶁檧锔�" src="1f926-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃し" src="1f937.png"/>',fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃し鈥嶁檪锔�" src="1f937-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拋" src="1f481.png"/>',fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拋鈥嶁檪锔�" src="1f481-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檯" src="1f645.png"/>',fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檯鈥嶁檪锔�" src="1f645-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檰" src="1f646.png"/>',fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檰鈥嶁檪锔�" src="1f646-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檵" src="1f64b.png"/>',fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檵鈥嶁檪锔�" src="1f64b-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檸" src="1f64e.png"/>',fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檸鈥嶁檪锔�" src="1f64e-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檷" src="1f64d.png"/>',fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檷鈥嶁檪锔�" src="1f64d-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拠" src="1f487.png"/>',fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拠鈥嶁檪锔�" src="1f487-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拞" src="1f486.png"/>',fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拞鈥嶁檪锔�" src="1f486-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9d6-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9d6-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拺" src="1f491.png"/>',fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶁潳锔忊�嶐煈�" src="1f469-200d-2764-fe0f-200d-1f469.png"/>',fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶁潳锔忊�嶐煈�" src="1f468-200d-2764-fe0f-200d-1f468.png"/>',fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拸" src="1f48f.png"/>',fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶁潳锔忊�嶐煉嬧�嶐煈�" src="1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png"/>',fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶁潳锔忊�嶐煉嬧�嶐煈�" src="1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png"/>',fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃應" src="1f46a.png"/>',fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈┾�嶐煈�" src="1f468-200d-1f469-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈┾�嶐煈р�嶐煈�" src="1f468-200d-1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈┾�嶐煈︹�嶐煈�" src="1f468-200d-1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈┾�嶐煈р�嶐煈�" src="1f468-200d-1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈┾�嶐煈�" src="1f469-200d-1f469-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈┾�嶐煈�" src="1f469-200d-1f469-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈┾�嶐煈р�嶐煈�" src="1f469-200d-1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈┾�嶐煈︹�嶐煈�" src="1f469-200d-1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈┾�嶐煈р�嶐煈�" src="1f469-200d-1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈ㄢ�嶐煈�" src="1f468-200d-1f468-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈ㄢ�嶐煈�" src="1f468-200d-1f468-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈ㄢ�嶐煈р�嶐煈�" src="1f468-200d-1f468-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈ㄢ�嶐煈︹�嶐煈�" src="1f468-200d-1f468-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈ㄢ�嶐煈р�嶐煈�" src="1f468-200d-1f468-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈�" src="1f469-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈�" src="1f469-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈р�嶐煈�" src="1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈︹�嶐煈�" src="1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懇鈥嶐煈р�嶐煈�" src="1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈�" src="1f468-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈�" src="1f468-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈р�嶐煈�" src="1f468-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈︹�嶐煈�" src="1f468-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懆鈥嶐煈р�嶐煈�" src="1f468-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ф" src="1f9f6.png"/>',fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃У" src="1f9f5.png"/>',fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Д" src="1f9e5.png"/>',fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ゼ" src="1f97c.png"/>',fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憵" src="1f45a.png"/>',fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憰" src="1f455.png"/>',fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憱" src="1f456.png"/>',fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憯" src="1f454.png"/>',fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憲" src="1f457.png"/>',fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憴" src="1f459.png"/>',fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憳" src="1f458.png"/>',fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拕" src="1f484.png"/>',fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拫" src="1f48b.png"/>',fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懀" src="1f463.png"/>',fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃タ" src="1f97f.png"/>',fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憼" src="1f460.png"/>',fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憽" src="1f461.png"/>',fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憿" src="1f462.png"/>',fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憺" src="1f45e.png"/>',fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憻" src="1f45f.png"/>',fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ゾ" src="1f97e.png"/>',fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Е" src="1f9e6.png"/>',fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Г" src="1f9e4.png"/>',fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃В" src="1f9e3.png"/>',fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憭" src="1f452.png"/>',fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帺" src="1f3a9.png"/>',fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Б" src="1f9e2.png"/>',fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26d1.png"/>',fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帗" src="1f393.png"/>',fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憫" src="1f451.png"/>',fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帓" src="1f392.png"/>',fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃С" src="1f9f3.png"/>',fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憹" src="1f45d.png"/>',fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憶" src="1f45b.png"/>',fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憸" src="1f45c.png"/>',fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捈" src="1f4bc.png"/>',fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃憮" src="1f453.png"/>',fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暥" src="1f576.png"/>',fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ソ" src="1f97d.png"/>',fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拲" src="1f48d.png"/>',fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寕" src="1f302.png"/>',fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惗" src="1f436.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惐" src="1f431.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惌" src="1f42d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惞" src="1f439.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惏" src="1f430.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惢" src="1f43b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惣" src="1f43c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惃" src="1f428.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惎" src="1f42f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f981.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惍" src="1f42e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惙" src="1f437.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惤" src="1f43d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惛" src="1f438.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f991.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悪" src="1f419.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f990.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惖" src="1f435.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檲" src="1f648.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檳" src="1f649.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃檴" src="1f64a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悞" src="1f412.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悢" src="1f414.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惂" src="1f427.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惁" src="1f426.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悿" src="1f424.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悾" src="1f423.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惀" src="1f425.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f986.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f985.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f989.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f987.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惡" src="1f43a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悧" src="1f417.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惔" src="1f434.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f984.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悵" src="1f41d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悰" src="1f41b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悓" src="1f40c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悶" src="1f41e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悳" src="1f41c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f997.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暦" src="1f577.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f982.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f980.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悕" src="1f40d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f996.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f995.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悽" src="1f422.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悹" src="1f420.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悷" src="1f41f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悺" src="1f421.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惉" src="1f42c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f988.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惓" src="1f433.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悑" src="1f40b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悐" src="1f40a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悊" src="1f406.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f993.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悈" src="1f405.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悆" src="1f403.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悅" src="1f402.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悇" src="1f404.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惇" src="1f42a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惈" src="1f42b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f992.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悩" src="1f418.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f98f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悙" src="1f410.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悘" src="1f40f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悜" src="1f411.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悗" src="1f40e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悥" src="1f416.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悁" src="1f400.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悂" src="1f401.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悡" src="1f413.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f983.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晩" src="1f54a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悤" src="1f415.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惄" src="1f429.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悎" src="1f408.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悋" src="1f407.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惪" src="1f43f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f994.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f999.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f998.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Α" src="1f9a1.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Β" src="1f9a2.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f99f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惥" src="1f43e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悏" src="1f409.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃惒" src="1f432.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尩" src="1f335.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巹" src="1f384.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尣" src="1f332.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尦" src="1f333.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尨" src="1f334.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尡" src="1f331.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尶" src="1f33f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2618.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崁" src="1f340.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帊" src="1f38d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帇" src="1f38b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崈" src="1f343.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崅" src="1f342.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崄" src="1f341.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尵" src="1f33e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尯" src="1f33a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尰" src="1f33b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尮" src="1f339.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f940.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尫" src="1f337.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尲" src="1f33c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尭" src="1f338.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拹" src="1f490.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崉" src="1f344.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尠" src="1f330.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巸" src="1f383.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃悮" src="1f41a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暩" src="1f578.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寧" src="1f30e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃實" src="1f30d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃審" src="1f30f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寱" src="1f315.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寲" src="1f316.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寳" src="1f317.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寴" src="1f318.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寫" src="1f311.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寬" src="1f312.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寭" src="1f313.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寯" src="1f314.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寶" src="1f31a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃対" src="1f31d.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寷" src="1f31b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寽" src="1f31c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尀" src="1f31e.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寵" src="1f319.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猸�" src="2b50.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃専" src="1f31f.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挮" src="1f4ab.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="2728.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2604.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�锔�" src="2600.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尋" src="1f324.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26c5.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尌" src="1f325.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃對" src="1f326.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽侊笍" src="2601.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃導" src="1f327.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26c8.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尒" src="1f329.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26a1.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敟" src="1f525.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挜" src="1f4a5.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂勶笍" src="2744.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尐" src="1f328.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26c4.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2603.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尙" src="1f32c.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挩" src="1f4a8.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尓" src="1f32a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尗" src="1f32b.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2602.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2614.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挧" src="1f4a7.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挦" src="1f4a6.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寠" src="1f30a.png"/>',fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崗" src="1f34f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崕" src="1f34e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崘" src="1f350.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崐" src="1f34a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崑" src="1f34b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崒" src="1f34c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崏" src="1f349.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崌" src="1f347.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崜" src="1f353.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崍" src="1f348.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崚" src="1f352.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崙" src="1f351.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崓" src="1f34d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ゥ" src="1f965.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃キ" src="1f96d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f951.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ウ" src="1f966.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崊" src="1f345.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崋" src="1f346.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f952.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f955.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尪" src="1f336.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f954.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尳" src="1f33d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ガ" src="1f96c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崰" src="1f360.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵂" src="1f36f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f950.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崬" src="1f35e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f956.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ク" src="1f96f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃エ" src="1f968.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9c0.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f953.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ォ" src="1f969.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崡" src="1f357.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崠" src="1f356.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Υ" src="1f9b4.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崵" src="1f364.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵆" src="1f373.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崝" src="1f354.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崯" src="1f35f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f959.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尛" src="1f32d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崟" src="1f355.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃オ" src="1f96a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃カ" src="1f96b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崫" src="1f35d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尞" src="1f32e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尟" src="1f32f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f957.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f958.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崪" src="1f35c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵅" src="1f372.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崶" src="1f365.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f960.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崳" src="1f363.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵄" src="1f371.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崨" src="1f35b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崣" src="1f359.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崥" src="1f35a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崢" src="1f358.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崲" src="1f362.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崱" src="1f361.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崸" src="1f367.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崹" src="1f368.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崷" src="1f366.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ェ" src="1f967.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵃" src="1f370.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9c1.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ギ" src="1f96e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巶" src="1f382.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵁" src="1f36e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崿" src="1f36c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵀" src="1f36d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崼" src="1f36b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵖" src="1f37f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95f.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崺" src="1f369.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃崻" src="1f36a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f95b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵑" src="1f37a.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵒" src="1f37b.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f942.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵎" src="1f377.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f943.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵏" src="1f378.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵐" src="1f379.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵕" src="1f37e.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵍" src="1f376.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵉" src="1f375.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃イ" src="1f964.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2615.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵓" src="1f37c.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9c2.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f944.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵈" src="1f374.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嵔" src="1f37d.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ィ" src="1f963.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ァ" src="1f961.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ア" src="1f962.png"/>',fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26bd.png"/>',fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弨" src="1f3c0.png"/>',fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃張" src="1f3c8.png"/>',fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26be.png"/>',fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94e.png"/>',fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幘" src="1f3be.png"/>',fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彁" src="1f3d0.png"/>',fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弶" src="1f3c9.png"/>',fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94f.png"/>',fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幈" src="1f3b1.png"/>',fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f3.png"/>',fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弻锔忊�嶁檧锔�" src="1f3cc-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弻" src="1f3cc.png"/>',fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彄" src="1f3d3.png"/>',fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃徃" src="1f3f8.png"/>',fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f945.png"/>',fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彃" src="1f3d2.png"/>',fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彂" src="1f3d1.png"/>',fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94d.png"/>',fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弿" src="1f3cf.png"/>',fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幙" src="1f3bf.png"/>',fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f7.png"/>',fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弬" src="1f3c2.png"/>',fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ず" src="1f93a.png"/>',fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぜ鈥嶁檧锔�" src="1f93c-200d-2640-fe0f.png"/>',fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぜ鈥嶁檪锔�" src="1f93c-200d-2642-fe0f.png"/>',fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃じ鈥嶁檧锔�" src="1f938-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃じ鈥嶁檪锔�" src="1f938-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぞ鈥嶁檧锔�" src="1f93e-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃ぞ鈥嶁檪锔�" src="1f93e-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f8.png"/>',fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94c.png"/>',fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃浌" src="1f6f9.png"/>',fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃浄" src="1f6f7.png"/>',fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃徆" src="1f3f9.png"/>',fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帲" src="1f3a3.png"/>',fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94a.png"/>',fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f94b.png"/>',fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殻鈥嶁檧锔�" src="1f6a3-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殻" src="1f6a3.png"/>',fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9d7-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9d7-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃強鈥嶁檧锔�" src="1f3ca-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃強" src="1f3ca.png"/>',fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃そ鈥嶁檧锔�" src="1f93d-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃そ鈥嶁檪锔�" src="1f93d-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檧锔�" src="1f9d8-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃鈥嶁檪锔�" src="1f9d8-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弰鈥嶁檧锔�" src="1f3c4-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弰" src="1f3c4.png"/>',fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泙" src="1f6c0.png"/>',fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀癸笍鈥嶁檧锔�" src="26f9-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f9.png"/>',fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弸锔忊�嶁檧锔�" src="1f3cb-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弸" src="1f3cb.png"/>',fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毚鈥嶁檧锔�" src="1f6b4-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毚" src="1f6b4.png"/>',fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毜鈥嶁檧锔�" src="1f6b5-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毜" src="1f6b5.png"/>',fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弴" src="1f3c7.png"/>',fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暣" src="1f574.png"/>',fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弳" src="1f3c6.png"/>',fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幗" src="1f3bd.png"/>',fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弲" src="1f3c5.png"/>',fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帠" src="1f396.png"/>',fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f947.png"/>',fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f948.png"/>',fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f949.png"/>',fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帡" src="1f397.png"/>',fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彽" src="1f3f5.png"/>',fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帿" src="1f3ab.png"/>',fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃師" src="1f39f.png"/>',fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幁" src="1f3ad.png"/>',fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帹" src="1f3a8.png"/>',fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帾" src="1f3aa.png"/>',fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃す鈥嶁檧锔�" src="1f939-200d-2640-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃す鈥嶁檪锔�" src="1f939-200d-2642-fe0f.png"/>',fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帳" src="1f3a4.png"/>',fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帶" src="1f3a7.png"/>',fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幖" src="1f3bc.png"/>',fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幑" src="1f3b9.png"/>',fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f941.png"/>',fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幏" src="1f3b7.png"/>',fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幒" src="1f3ba.png"/>',fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幐" src="1f3b8.png"/>',fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幓" src="1f3bb.png"/>',fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幀" src="1f3ac.png"/>',fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幃" src="1f3ae.png"/>',fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃懢" src="1f47e.png"/>',fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幆" src="1f3af.png"/>',fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幉" src="1f3b2.png"/>',fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"鈾�",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幇" src="1f3b0.png"/>',fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃З" src="1f9e9.png"/>',fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幊" src="1f3b3.png"/>',fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殫" src="1f697.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殨" src="1f695.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殭" src="1f699.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殞" src="1f68c.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殠" src="1f68e.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弾" src="1f3ce.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殦" src="1f693.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殤" src="1f691.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殥" src="1f692.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殣" src="1f690.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殮" src="1f69a.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殯" src="1f69b.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殰" src="1f69c.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洿" src="1f6f4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弽" src="1f3cd.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毑" src="1f6b2.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃浀" src="1f6f5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毃" src="1f6a8.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殧" src="1f694.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殟" src="1f68d.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殬" src="1f698.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殩" src="1f696.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殹" src="1f6a1.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殸" src="1f6a0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殶" src="1f69f.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殐" src="1f683.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殝" src="1f68b.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殱" src="1f69d.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殑" src="1f684.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殔" src="1f685.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殘" src="1f688.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殲" src="1f69e.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殏" src="1f682.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殕" src="1f686.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殗" src="1f687.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殜" src="1f68a.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殙" src="1f689.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃浉" src="1f6f8.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殎" src="1f681.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洨" src="1f6e9.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁堬笍" src="2708.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洬" src="1f6eb.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洭" src="1f6ec.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洢" src="1f6e5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殼" src="1f6a4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洺" src="1f6f3.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殌" src="1f680.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洶" src="1f6f0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捄" src="1f4ba.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃浂" src="1f6f6.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2693.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毀" src="1f6a7.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26fd.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殢" src="1f68f.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殾" src="1f6a6.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殽" src="1f6a5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃弫" src="1f3c1.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃殺" src="1f6a2.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帯" src="1f3a1.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帰" src="1f3a2.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帬" src="1f3a0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彈" src="1f3d7.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寔" src="1f301.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椉" src="1f5fc.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彮" src="1f3ed.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f2.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帒" src="1f391.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彅" src="1f3d4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椈" src="1f5fb.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寢" src="1f30b.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椌" src="1f5fe.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彆" src="1f3d5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26fa.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彏" src="1f3de.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洠" src="1f6e3.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洡" src="1f6e4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寘" src="1f305.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寗" src="1f304.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彍" src="1f3dc.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彇" src="1f3d6.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彎" src="1f3dd.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寚" src="1f307.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寙" src="1f306.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彊" src="1f3d9.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寖" src="1f303.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寜" src="1f309.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寣" src="1f30c.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尃" src="1f320.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巼" src="1f387.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巻" src="1f386.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寛" src="1f308.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彉" src="1f3d8.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彴" src="1f3f0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彲" src="1f3ef.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彑" src="1f3df.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椊" src="1f5fd.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彔" src="1f3e0.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彙" src="1f3e1.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彋" src="1f3da.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彚" src="1f3e2.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彫" src="1f3ec.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彛" src="1f3e3.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彜" src="1f3e4.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彞" src="1f3e5.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彟" src="1f3e6.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彣" src="1f3e8.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彧" src="1f3ea.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彨" src="1f3eb.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彥" src="1f3e9.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拻" src="1f492.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彌" src="1f3db.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26ea.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晫" src="1f54c.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晬" src="1f54d.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晪" src="1f54b.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26e9.png"/>',fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈱�" src="231a.png"/>',fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摫" src="1f4f1.png"/>',fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摬" src="1f4f2.png"/>',fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捇" src="1f4bb.png"/>',fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈱�" src="2328.png"/>',fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枼" src="1f5a5.png"/>',fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枿" src="1f5a8.png"/>',fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃柋" src="1f5b1.png"/>',fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃柌" src="1f5b2.png"/>',fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暪" src="1f579.png"/>',fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棞" src="1f5dc.png"/>',fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捊" src="1f4bd.png"/>',fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捑" src="1f4be.png"/>',fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捒" src="1f4bf.png"/>',fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搥" src="1f4c0.png"/>',fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摷" src="1f4fc.png"/>',fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摲" src="1f4f7.png"/>',fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摳" src="1f4f8.png"/>',fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摴" src="1f4f9.png"/>',fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帴" src="1f3a5.png"/>',fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摻" src="1f4fd.png"/>',fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帪" src="1f39e.png"/>',fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摓" src="1f4de.png"/>',fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽庯笍" src="260e.png"/>',fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摕" src="1f4df.png"/>',fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摖" src="1f4e0.png"/>',fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摵" src="1f4fa.png"/>',fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摶" src="1f4fb.png"/>',fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帣" src="1f399.png"/>',fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帤" src="1f39a.png"/>',fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帥" src="1f39b.png"/>',fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Л" src="1f9ed.png"/>',fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f1.png"/>',fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f2.png"/>',fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f0.png"/>',fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暟" src="1f570.png"/>',fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f3.png"/>',fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈱�" src="231b.png"/>',fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摗" src="1f4e1.png"/>',fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攱" src="1f50b.png"/>',fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攲" src="1f50c.png"/>',fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挕" src="1f4a1.png"/>',fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敠" src="1f526.png"/>',fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暞" src="1f56f.png"/>',fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Н" src="1f9ef.png"/>',fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棏" src="1f5d1.png"/>',fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洟" src="1f6e2.png"/>',fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捀" src="1f4b8.png"/>',fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挼" src="1f4b5.png"/>',fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挻" src="1f4b4.png"/>',fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挾" src="1f4b6.png"/>',fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挿" src="1f4b7.png"/>',fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挵" src="1f4b0.png"/>',fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挸" src="1f4b3.png"/>',fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拵" src="1f48e.png"/>',fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2696.png"/>',fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃О" src="1f9f0.png"/>',fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敡" src="1f527.png"/>',fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敤" src="1f528.png"/>',fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2692.png"/>',fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洜" src="1f6e0.png"/>',fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26cf.png"/>',fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敥" src="1f529.png"/>',fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2699.png"/>',fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃П" src="1f9f1.png"/>',fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26d3.png"/>',fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Р" src="1f9f2.png"/>',fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敨" src="1f52b.png"/>',fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挘" src="1f4a3.png"/>',fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ж" src="1f9e8.png"/>',fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敧" src="1f52a.png"/>',fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棥" src="1f5e1.png"/>',fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2694.png"/>',fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洝" src="1f6e1.png"/>',fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毈" src="1f6ac.png"/>',fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2620.png"/>',fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26b0.png"/>',fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26b1.png"/>',fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃徍" src="1f3fa.png"/>',fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敭" src="1f52e.png"/>',fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摽" src="1f4ff.png"/>',fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Э" src="1f9ff.png"/>',fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拡" src="1f488.png"/>',fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="2697.png"/>',fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敪" src="1f52d.png"/>',fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敩" src="1f52c.png"/>',fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暢" src="1f573.png"/>',fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拪" src="1f48a.png"/>',fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拤" src="1f489.png"/>',fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃К" src="1f9ec.png"/>',fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃" src="1f9a0.png"/>',fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Й" src="1f9eb.png"/>',fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃И" src="1f9ea.png"/>',fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃尅" src="1f321.png"/>',fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ч" src="1f9f9.png"/>',fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ш" src="1f9fa.png"/>',fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Щ" src="1f9fb.png"/>',fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彿" src="1f3f7.png"/>',fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敄" src="1f516.png"/>',fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毥" src="1f6bd.png"/>',fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毧" src="1f6bf.png"/>',fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泚" src="1f6c1.png"/>',fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ъ" src="1f9fc.png"/>',fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ы" src="1f9fd.png"/>',fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Т" src="1f9f4.png"/>',fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攽" src="1f511.png"/>',fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棟" src="1f5dd.png"/>',fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泲" src="1f6cb.png"/>',fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泴" src="1f6cc.png"/>',fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洀" src="1f6cf.png"/>',fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毆" src="1f6aa.png"/>',fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泿" src="1f6ce.png"/>',fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ц" src="1f9f8.png"/>',fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃柤" src="1f5bc.png"/>',fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椇" src="1f5fa.png"/>',fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26f1.png"/>',fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃椏" src="1f5ff.png"/>',fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泹" src="1f6cd.png"/>',fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洅" src="1f6d2.png"/>',fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巿" src="1f388.png"/>',fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帍" src="1f38f.png"/>',fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巰" src="1f380.png"/>',fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃巵" src="1f381.png"/>',fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帄" src="1f38a.png"/>',fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帀" src="1f389.png"/>',fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帋" src="1f38e.png"/>',fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帎" src="1f390.png"/>',fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帉" src="1f38c.png"/>',fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彯" src="1f3ee.png"/>',fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ё" src="1f9e7.png"/>',fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁夛笍" src="2709.png"/>',fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摡" src="1f4e9.png"/>',fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摠" src="1f4e8.png"/>',fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摟" src="1f4e7.png"/>',fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃拰" src="1f48c.png"/>',fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摦" src="1f4ee.png"/>',fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摢" src="1f4ea.png"/>',fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摣" src="1f4eb.png"/>',fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摤" src="1f4ec.png"/>',fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摥" src="1f4ed.png"/>',fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摝" src="1f4e6.png"/>',fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摨" src="1f4ef.png"/>',fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摜" src="1f4e5.png"/>',fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摛" src="1f4e4.png"/>',fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摐" src="1f4dc.png"/>',fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搩" src="1f4c3.png"/>',fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搼" src="1f4d1.png"/>',fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Ь" src="1f9fe.png"/>',fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搳" src="1f4ca.png"/>',fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搱" src="1f4c8.png"/>',fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搲" src="1f4c9.png"/>',fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搫" src="1f4c4.png"/>',fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搮" src="1f4c5.png"/>',fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搯" src="1f4c6.png"/>',fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棑" src="1f5d3.png"/>',fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搰" src="1f4c7.png"/>',fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃梼" src="1f5c3.png"/>',fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棾" src="1f5f3.png"/>',fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃梽" src="1f5c4.png"/>',fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搵" src="1f4cb.png"/>',fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棐" src="1f5d2.png"/>',fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搧" src="1f4c1.png"/>',fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搨" src="1f4c2.png"/>',fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃梻" src="1f5c2.png"/>',fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棡" src="1f5de.png"/>',fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摪" src="1f4f0.png"/>',fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摀" src="1f4d3.png"/>',fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摃" src="1f4d5.png"/>',fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摋" src="1f4d7.png"/>',fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摌" src="1f4d8.png"/>',fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摍" src="1f4d9.png"/>',fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摂" src="1f4d4.png"/>',fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搾" src="1f4d2.png"/>',fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摎" src="1f4da.png"/>',fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摉" src="1f4d6.png"/>',fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃Х" src="1f9f7.png"/>',fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敆" src="1f517.png"/>',fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搸" src="1f4ce.png"/>',fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枃" src="1f587.png"/>',fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁傦笍" src="2702.png"/>',fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搻" src="1f4d0.png"/>',fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搹" src="1f4cf.png"/>',fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃М" src="1f9ee.png"/>',fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搶" src="1f4cc.png"/>',fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃搷" src="1f4cd.png"/>',fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毄" src="1f6a9.png"/>',fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彸" src="1f3f3.png"/>',fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彺" src="1f3f4.png"/>',fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彸锔忊�嶐煂�" src="1f3f3-fe0f-200d-1f308.png"/>',fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攼" src="1f510.png"/>',fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敀" src="1f512.png"/>',fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敁" src="1f513.png"/>',fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攺" src="1f50f.png"/>',fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枈" src="1f58a.png"/>',fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枊" src="1f58b.png"/>',fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁掞笍" src="2712.png"/>',fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摑" src="1f4dd.png"/>',fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁忥笍" src="270f.png"/>',fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枍" src="1f58d.png"/>',fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枌" src="1f58c.png"/>',fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攳" src="1f50d.png"/>',fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攷" src="1f50e.png"/>',fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂わ笍" src="2764.png"/>',fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃А" src="1f9e1.png"/>',fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挍" src="1f49b.png"/>',fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挌" src="1f49a.png"/>',fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挋" src="1f499.png"/>',fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挏" src="1f49c.png"/>',fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃枻" src="1f5a4.png"/>',fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挃" src="1f494.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="2763.png"/>',fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挄" src="1f495.png"/>',fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挒" src="1f49e.png"/>',fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挀" src="1f493.png"/>',fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挆" src="1f497.png"/>',fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挅" src="1f496.png"/>',fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挊" src="1f498.png"/>',fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挐" src="1f49d.png"/>',fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挓" src="1f49f.png"/>',fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="262e.png"/>',fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="271d.png"/>',fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="262a.png"/>',fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晧" src="1f549.png"/>',fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2638.png"/>',fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="2721.png"/>',fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敮" src="1f52f.png"/>',fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晭" src="1f54e.png"/>',fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="262f.png"/>',fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2626.png"/>',fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洂" src="1f6d0.png"/>',fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26ce.png"/>',fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2648.png"/>',fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2649.png"/>',fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264a.png"/>',fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264b.png"/>',fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264c.png"/>',fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264d.png"/>',fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264e.png"/>',fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="264f.png"/>',fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2650.png"/>',fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2651.png"/>',fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2652.png"/>',fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="2653.png"/>',fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啍" src="1f194.png"/>',fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="269b.png"/>',fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埑" src="1f233.png"/>',fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埞" src="1f239.png"/>',fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2622.png"/>',fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽�" src="2623.png"/>',fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摯" src="1f4f4.png"/>',fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摮" src="1f4f3.png"/>',fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埗" src="1f236.png"/>',fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃垰" src="1f21a.png"/>',fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埜" src="1f238.png"/>',fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埡" src="1f23a.png"/>',fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埛锔�" src="1f237.png"/>',fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁达笍" src="2734.png"/>',fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啔" src="1f19a.png"/>',fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃墤" src="1f251.png"/>',fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挳" src="1f4ae.png"/>',fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃墣" src="1f250.png"/>',fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="銑欙笍" src="3299.png"/>',fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="銑楋笍" src="3297.png"/>',fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埓" src="1f234.png"/>',fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埖" src="1f235.png"/>',fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埐" src="1f232.png"/>',fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃叞锔�" src="1f170.png"/>',fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃叡锔�" src="1f171.png"/>',fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啂" src="1f18e.png"/>',fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啈" src="1f191.png"/>',fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃吘锔�" src="1f17e.png"/>',fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啒" src="1f198.png"/>',fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉀�" src="26d4.png"/>',fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摏" src="1f4db.png"/>',fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毇" src="1f6ab.png"/>',fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="274c.png"/>',fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猸�" src="2b55.png"/>',fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃洃" src="1f6d1.png"/>',fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挗" src="1f4a2.png"/>',fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾笍" src="2668.png"/>',fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毞" src="1f6b7.png"/>',fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毌" src="1f6af.png"/>',fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毘" src="1f6b3.png"/>',fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毐" src="1f6b1.png"/>',fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敒" src="1f51e.png"/>',fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摰" src="1f4f5.png"/>',fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="2757.png"/>',fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="2755.png"/>',fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="2753.png"/>',fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="2754.png"/>',fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈥硷笍" src="203c.png"/>',fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈦夛笍" src="2049.png"/>',fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攨" src="1f505.png"/>',fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攩" src="1f506.png"/>',fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敱" src="1f531.png"/>',fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="269c.png"/>',fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="銆斤笍" src="303d.png"/>',fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿狅笍" src="26a0.png"/>',fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毟" src="1f6b8.png"/>',fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敯" src="1f530.png"/>',fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾伙笍" src="267b.png"/>',fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃埊" src="1f22f.png"/>',fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃捁" src="1f4b9.png"/>',fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂囷笍" src="2747.png"/>',fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁筹笍" src="2733.png"/>',fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉂�" src="274e.png"/>',fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁�" src="2705.png"/>',fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挔" src="1f4a0.png"/>',fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寑" src="1f300.png"/>',fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃�" src="27bf.png"/>',fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃寪" src="1f310.png"/>',fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈸傦笍" src="24c2.png"/>',fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彠" src="1f3e7.png"/>',fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃垈锔�" src="1f202.png"/>',fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泜" src="1f6c2.png"/>',fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泝" src="1f6c3.png"/>',fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泟" src="1f6c4.png"/>',fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃泤" src="1f6c5.png"/>',fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="267f.png"/>',fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毉" src="1f6ad.png"/>',fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毦" src="1f6be.png"/>',fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃吙锔�" src="1f17f.png"/>',fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毎" src="1f6b0.png"/>',fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毠" src="1f6b9.png"/>',fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毢" src="1f6ba.png"/>',fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毤" src="1f6bc.png"/>',fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毣" src="1f6bb.png"/>',fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃毊" src="1f6ae.png"/>',fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃帵" src="1f3a6.png"/>',fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摱" src="1f4f6.png"/>',fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃垇" src="1f201.png"/>',fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃問" src="1f196.png"/>',fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啑" src="1f197.png"/>',fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啓" src="1f199.png"/>',fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啋" src="1f192.png"/>',fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啎" src="1f195.png"/>',fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃啌" src="1f193.png"/>',fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="0锔忊儯" src="30-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="1锔忊儯" src="31-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="2锔忊儯" src="32-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="3锔忊儯" src="33-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="4锔忊儯" src="34-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="5锔忊儯" src="35-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="6锔忊儯" src="36-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="7锔忊儯" src="37-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="8锔忊儯" src="38-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="9锔忊儯" src="39-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敓" src="1f51f.png"/>',fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="*鈨�" src="2a-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴忥笍" src="23cf.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈻讹笍" src="25b6.png"/>',fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f8.png"/>',fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23ed.png"/>',fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23f9.png"/>',fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23fa.png"/>',fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23ef.png"/>',fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23ee.png"/>',fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23e9.png"/>',fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23ea.png"/>',fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攢" src="1f500.png"/>',fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攣" src="1f501.png"/>',fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攤" src="1f502.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈼�锔�" src="25c0.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敿" src="1f53c.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃斀" src="1f53d.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23eb.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈴�" src="23ec.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃★笍" src="27a1.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猬咃笍" src="2b05.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猬嗭笍" src="2b06.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猬囷笍" src="2b07.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫楋笍" src="2197.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫橈笍" src="2198.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫欙笍" src="2199.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫栵笍" src="2196.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫曪笍" src="2195.png"/>',fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫旓笍" src="2194.png"/>',fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攧" src="1f504.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫笍" src="21aa.png"/>',fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈫╋笍" src="21a9.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猡达笍" src="2934.png"/>',fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猡碉笍" src="2935.png"/>',fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="#锔忊儯" src="23-20e3.png"/>',fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈩癸笍" src="2139.png"/>',fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敜" src="1f524.png"/>',fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敗" src="1f521.png"/>',fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敔" src="1f520.png"/>',fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敚" src="1f523.png"/>',fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幍" src="1f3b5.png"/>',fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幎" src="1f3b6.png"/>',fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="銆帮笍" src="3030.png"/>',fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃�" src="27b0.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁旓笍" src="2714.png"/>',fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攦" src="1f503.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃�" src="2795.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃�" src="2796.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉃�" src="2797.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鉁栵笍" src="2716.png"/>',fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾�" src="267e.png"/>',fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挷" src="1f4b2.png"/>',fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挶" src="1f4b1.png"/>',fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="漏锔�" src="a9.png"/>',fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="庐锔�" src="ae.png"/>',fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈩笍" src="2122.png"/>',fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敋" src="1f51a.png"/>',fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敊" src="1f519.png"/>',fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敍" src="1f51b.png"/>',fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敐" src="1f51d.png"/>',fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敎" src="1f51c.png"/>',fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈽戯笍" src="2611.png"/>',fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敇" src="1f518.png"/>',fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26aa.png"/>',fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈿�" src="26ab.png"/>',fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敶" src="1f534.png"/>',fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃數" src="1f535.png"/>',fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敻" src="1f538.png"/>',fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敼" src="1f539.png"/>',fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敹" src="1f536.png"/>',fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敺" src="1f537.png"/>',fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敽" src="1f53a.png"/>',fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈻笍" src="25aa.png"/>',fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈻笍" src="25ab.png"/>',fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猬�" src="2b1b.png"/>',fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="猬�" src="2b1c.png"/>',fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敾" src="1f53b.png"/>',fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈼硷笍" src="25fc.png"/>',fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈼伙笍" src="25fb.png"/>',fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈼�" src="25fe.png"/>',fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈼�" src="25fd.png"/>',fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敳" src="1f532.png"/>',fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敵" src="1f533.png"/>',fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攬" src="1f508.png"/>',fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攭" src="1f509.png"/>',fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攰" src="1f50a.png"/>',fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃攪" src="1f507.png"/>',fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摚" src="1f4e3.png"/>',fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃摙" src="1f4e2.png"/>',fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敂" src="1f514.png"/>',fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃敃" src="1f515.png"/>',fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃儚" src="1f0cf.png"/>',fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃��" src="1f004.png"/>',fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾狅笍" src="2660.png"/>',fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾o笍" src="2663.png"/>',fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾ワ笍" src="2665.png"/>',fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="鈾︼笍" src="2666.png"/>',fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃幋" src="1f3b4.png"/>',fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挱" src="1f4ad.png"/>',fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棷" src="1f5ef.png"/>',fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃挰" src="1f4ac.png"/>',fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃棬" src="1f5e8.png"/>',fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晲" src="1f550.png"/>',fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晳" src="1f551.png"/>',fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晵" src="1f552.png"/>',fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晸" src="1f553.png"/>',fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晹" src="1f554.png"/>',fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晻" src="1f555.png"/>',fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晼" src="1f556.png"/>',fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晽" src="1f557.png"/>',fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃晿" src="1f558.png"/>',fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暀" src="1f559.png"/>',fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暁" src="1f55a.png"/>',fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暃" src="1f55b.png"/>',fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暅" src="1f55c.png"/>',fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暆" src="1f55d.png"/>',fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暈" src="1f55e.png"/>',fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暉" src="1f55f.png"/>',fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暊" src="1f560.png"/>',fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暋" src="1f561.png"/>',fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暍" src="1f562.png"/>',fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暎" src="1f563.png"/>',fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暏" src="1f564.png"/>',fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暐" src="1f565.png"/>',fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暒" src="1f566.png"/>',fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃暓" src="1f567.png"/>',fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚝" src="1f1e6-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["脜land","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚱" src="1f1e6-1f1fd.png"/>',fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚤" src="1f1e6-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚳" src="1f1e9-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚫" src="1f1e6-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚛" src="1f1e6-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚧" src="1f1e6-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚠" src="1f1e6-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚩" src="1f1e6-1f1f6.png"/>',fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚞" src="1f1e6-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚪" src="1f1e6-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚥" src="1f1e6-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚰" src="1f1e6-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚭" src="1f1e6-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚬" src="1f1e6-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚳" src="1f1e6-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚫" src="1f1e7-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚟" src="1f1e7-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚛" src="1f1e7-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚙" src="1f1e7-1f1e7.png"/>',fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚲" src="1f1e7-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚜" src="1f1e7-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚳" src="1f1e7-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚡" src="1f1e7-1f1ef.png"/>',fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚥" src="1f1e7-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚬" src="1f1e7-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚧" src="1f1e7-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚩" src="1f1e7-1f1f6.png"/>',fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚘" src="1f1e7-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚰" src="1f1e7-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚪" src="1f1e7-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚧" src="1f1ee-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚞" src="1f1fb-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚦" src="1f1e7-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚞" src="1f1e7-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚝" src="1f1e7-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚠" src="1f1e7-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚮" src="1f1e8-1f1fb.png"/>',fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚟" src="1f1f0-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚥" src="1f1e8-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚘" src="1f1e8-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚚" src="1f1ee-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚲" src="1f1f0-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚝" src="1f1e8-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚛" src="1f1f9-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚤" src="1f1e8-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚦" src="1f1e8-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚱" src="1f1e8-1f1fd.png"/>',fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚚" src="1f1e8-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚧" src="1f1e8-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚥" src="1f1f0-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚞" src="1f1e8-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚛" src="1f1e8-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚢" src="1f1e8-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚪" src="1f1e8-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚟馃嚪" src="1f1ed-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚭" src="1f1e8-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["cura莽ao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚰" src="1f1e8-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚲" src="1f1e8-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚳" src="1f1e8-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚢" src="1f1e9-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚡" src="1f1e9-1f1ef.png"/>',fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚥" src="1f1e9-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚧" src="1f1e9-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚚" src="1f1ea-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚞" src="1f1ea-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚮" src="1f1f8-1f1fb.png"/>',fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚩" src="1f1ec-1f1f6.png"/>',fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚪" src="1f1ea-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚜" src="1f1ea-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚬" src="1f1ea-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚭" src="1f1ea-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚢" src="1f1eb-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚧" src="1f1eb-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚡" src="1f1eb-1f1ef.png"/>',fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚠" src="1f1eb-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚪" src="1f1eb-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚝" src="1f1ec-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚝" src="1f1f5-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚝" src="1f1f9-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚘" src="1f1ec-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚥" src="1f1ec-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚜" src="1f1ec-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚛馃嚜" src="1f1e9-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚟" src="1f1ec-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚠" src="1f1ec-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚪" src="1f1ec-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚤" src="1f1ec-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚛" src="1f1ec-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚨" src="1f1ec-1f1f5.png"/>',fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚭" src="1f1ec-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚬" src="1f1ec-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚞" src="1f1ec-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚦" src="1f1ec-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚰" src="1f1ec-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚲" src="1f1ec-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚟馃嚬" src="1f1ed-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚟馃嚦" src="1f1ed-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚟馃嚢" src="1f1ed-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚟馃嚭" src="1f1ed-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚫" src="1f1ee-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚦" src="1f1ee-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚛" src="1f1ee-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚪" src="1f1ee-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚩" src="1f1ee-1f1f6.png"/>',fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚜" src="1f1ee-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚥" src="1f1ee-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚤" src="1f1ee-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚠馃嚬" src="1f1ee-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚠" src="1f1e8-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚡馃嚥" src="1f1ef-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚡馃嚨" src="1f1ef-1f1f5.png"/>',fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚡馃嚜" src="1f1ef-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚡馃嚧" src="1f1ef-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚳" src="1f1f0-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚜" src="1f1f0-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚠" src="1f1f0-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚱馃嚢" src="1f1fd-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚰" src="1f1f0-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚞" src="1f1f0-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚘" src="1f1f1-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚮" src="1f1f1-1f1fb.png"/>',fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚙" src="1f1f1-1f1e7.png"/>',fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚫" src="1f1f1-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚪" src="1f1f1-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚲" src="1f1f1-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚠" src="1f1f1-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚬" src="1f1f1-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚭" src="1f1f1-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚧" src="1f1f2-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚢" src="1f1f2-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚞" src="1f1f2-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚰" src="1f1f2-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚲" src="1f1f2-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚮" src="1f1f2-1f1fb.png"/>',fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚤" src="1f1f2-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚬" src="1f1f2-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚟" src="1f1f2-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚩" src="1f1f2-1f1f6.png"/>',fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚪" src="1f1f2-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚭" src="1f1f2-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚲馃嚬" src="1f1fe-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚱" src="1f1f2-1f1fd.png"/>',fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚝馃嚥" src="1f1eb-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚛" src="1f1f2-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚚" src="1f1f2-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚦" src="1f1f2-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚜" src="1f1f2-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚫" src="1f1f2-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚘" src="1f1f2-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚳" src="1f1f2-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚥" src="1f1f2-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚘" src="1f1f3-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚪" src="1f1f3-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚨" src="1f1f3-1f1f5.png"/>',fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚤" src="1f1f3-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚚" src="1f1f3-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚳" src="1f1f3-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚠" src="1f1f3-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚜" src="1f1f3-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚞" src="1f1f3-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚭" src="1f1f3-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚝" src="1f1f3-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚥馃嚨" src="1f1f2-1f1f5.png"/>',fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚨" src="1f1f0-1f1f5.png"/>',fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚦馃嚧" src="1f1f3-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚧馃嚥" src="1f1f4-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚢" src="1f1f5-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚰" src="1f1f5-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚫" src="1f1f5-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚘" src="1f1f5-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚞" src="1f1f5-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚲" src="1f1f5-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚜" src="1f1f5-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚟" src="1f1f5-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚦" src="1f1f5-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚤" src="1f1f5-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚬" src="1f1f5-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚪" src="1f1f5-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚩馃嚘" src="1f1f6-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["r茅union","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚪馃嚜" src="1f1f7-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚪馃嚧" src="1f1f7-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚪馃嚭" src="1f1f7-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚪馃嚰" src="1f1f7-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barth茅lemy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚙馃嚤" src="1f1e7-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚟" src="1f1f8-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚦" src="1f1f0-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚚" src="1f1f1-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚨馃嚥" src="1f1f5-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚚" src="1f1fb-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚰馃嚫" src="1f1fc-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚥" src="1f1f8-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚬" src="1f1f8-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚘" src="1f1f8-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚦" src="1f1f8-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚪馃嚫" src="1f1f7-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚚" src="1f1f8-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚤" src="1f1f8-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚞" src="1f1f8-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚱" src="1f1f8-1f1fd.png"/>',fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚢" src="1f1f8-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚠" src="1f1f8-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚙" src="1f1f8-1f1e7.png"/>',fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚧" src="1f1f8-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚳馃嚘" src="1f1ff-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚫" src="1f1ec-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚢馃嚪" src="1f1f0-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚫" src="1f1f8-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚫" src="1f1ea-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚤馃嚢" src="1f1f1-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚛" src="1f1f8-1f1e9.png"/>',fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚪" src="1f1f8-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚳" src="1f1f8-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚜" src="1f1f8-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚚馃嚟" src="1f1e8-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚫馃嚲" src="1f1f8-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚰" src="1f1f9-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚡" src="1f1f9-1f1ef.png"/>',fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚳" src="1f1f9-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚟" src="1f1f9-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚤" src="1f1f9-1f1f1.png"/>',fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚞" src="1f1f9-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚢" src="1f1f9-1f1f0.png"/>',fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚧" src="1f1f9-1f1f4.png"/>',fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚬" src="1f1f9-1f1f9.png"/>',fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚦" src="1f1f9-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚪" src="1f1f9-1f1f7.png"/>',fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚥" src="1f1f9-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚚" src="1f1f9-1f1e8.png"/>',fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚬馃嚮" src="1f1f9-1f1fb.png"/>',fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚞" src="1f1fa-1f1ec.png"/>',fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚘" src="1f1fa-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚘馃嚜" src="1f1e6-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚞馃嚙" src="1f1ec-1f1e7.png"/>',fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彺鬆仹鬆仮鬆仴鬆伄鬆仹鬆伩" src="1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png"/>',fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彺鬆仹鬆仮鬆伋鬆仯鬆伌鬆伩" src="1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png"/>',fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彺鬆仹鬆仮鬆伔鬆伂鬆伋鬆伩" src="1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png"/>',fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚫" src="1f1fa-1f1f8.png"/>',fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚠" src="1f1fb-1f1ee.png"/>',fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚲" src="1f1fa-1f1fe.png"/>',fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚳" src="1f1fa-1f1ff.png"/>',fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚭" src="1f1fb-1f1fa.png"/>',fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚘" src="1f1fb-1f1e6.png"/>',fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚜" src="1f1fb-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚮馃嚦" src="1f1fb-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚰馃嚝" src="1f1fc-1f1eb.png"/>',fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚜馃嚟" src="1f1ea-1f1ed.png"/>',fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚲馃嚜" src="1f1fe-1f1ea.png"/>',fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚳馃嚥" src="1f1ff-1f1f2.png"/>',fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚳馃嚰" src="1f1ff-1f1fc.png"/>',fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃嚭馃嚦" src="1f1fa-1f1f3.png"/>',fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="馃彺鈥嶁槧锔�" src="1f3f4-200d-2620-fe0f.png"/>',fitzpatrick_scale:false,category:"flags"}});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js
new file mode 100644
index 0000000..37f3bcf
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojiimages.min.js
@@ -0,0 +1,3 @@
+// Source: npm package: emojilib
+// Images provided by twemoji: https://github.com/twitter/twemoji
+window.tinymce.Resource.add("tinymce.plugins.emoticons",{100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4af}" src="1f4af.png"/>',fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f522}" src="1f522.png"/>',fitzpatrick_scale:!1,category:"symbols"},grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f600}" src="1f600.png"/>',fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62c}" src="1f62c.png"/>',fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f601}" src="1f601.png"/>',fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f602}" src="1f602.png"/>',fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f923}" src="1f923.png"/>',fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f973}" src="1f973.png"/>',fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f603}" src="1f603.png"/>',fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f604}" src="1f604.png"/>',fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f605}" src="1f605.png"/>',fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f606}" src="1f606.png"/>',fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f607}" src="1f607.png"/>',fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f609}" src="1f609.png"/>',fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60a}" src="1f60a.png"/>',fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f642}" src="1f642.png"/>',fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f643}" src="1f643.png"/>',fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u263a\ufe0f" src="263a.png"/>',fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60b}" src="1f60b.png"/>',fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60c}" src="1f60c.png"/>',fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60d}" src="1f60d.png"/>',fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f970}" src="1f970.png"/>',fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f618}" src="1f618.png"/>',fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f617}" src="1f617.png"/>',fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f619}" src="1f619.png"/>',fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61a}" src="1f61a.png"/>',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61c}" src="1f61c.png"/>',fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92a}" src="1f92a.png"/>',fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f928}" src="1f928.png"/>',fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d0}" src="1f9d0.png"/>',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61d}" src="1f61d.png"/>',fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61b}" src="1f61b.png"/>',fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f911}" src="1f911.png"/>',fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f913}" src="1f913.png"/>',fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60e}" src="1f60e.png"/>',fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f929}" src="1f929.png"/>',fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f921}" src="1f921.png"/>',fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f920}" src="1f920.png"/>',fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f917}" src="1f917.png"/>',fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f60f}" src="1f60f.png"/>',fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f636}" src="1f636.png"/>',fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f610}" src="1f610.png"/>',fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f611}" src="1f611.png"/>',fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f612}" src="1f612.png"/>',fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f644}" src="1f644.png"/>',fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f914}" src="1f914.png"/>',fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f925}" src="1f925.png"/>',fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92d}" src="1f92d.png"/>',fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92b}" src="1f92b.png"/>',fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92c}" src="1f92c.png"/>',fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92f}" src="1f92f.png"/>',fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f633}" src="1f633.png"/>',fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61e}" src="1f61e.png"/>',fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f61f}" src="1f61f.png"/>',fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f620}" src="1f620.png"/>',fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f621}" src="1f621.png"/>',fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f614}" src="1f614.png"/>',fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f615}" src="1f615.png"/>',fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f641}" src="1f641.png"/>',fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2639" src="2639.png"/>',fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f623}" src="1f623.png"/>',fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f616}" src="1f616.png"/>',fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62b}" src="1f62b.png"/>',fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f629}" src="1f629.png"/>',fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f97a}" src="1f97a.png"/>',fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f624}" src="1f624.png"/>',fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62e}" src="1f62e.png"/>',fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f631}" src="1f631.png"/>',fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f628}" src="1f628.png"/>',fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f630}" src="1f630.png"/>',fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62f}" src="1f62f.png"/>',fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f626}" src="1f626.png"/>',fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f627}" src="1f627.png"/>',fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f622}" src="1f622.png"/>',fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f625}" src="1f625.png"/>',fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f924}" src="1f924.png"/>',fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62a}" src="1f62a.png"/>',fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f613}" src="1f613.png"/>',fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f975}" src="1f975.png"/>',fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f976}" src="1f976.png"/>',fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f62d}" src="1f62d.png"/>',fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f635}" src="1f635.png"/>',fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f632}" src="1f632.png"/>',fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f910}" src="1f910.png"/>',fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f922}" src="1f922.png"/>',fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f927}" src="1f927.png"/>',fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f92e}" src="1f92e.png"/>',fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f637}" src="1f637.png"/>',fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f912}" src="1f912.png"/>',fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f915}" src="1f915.png"/>',fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f974}" src="1f974.png"/>',fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f634}" src="1f634.png"/>',fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a4}" src="1f4a4.png"/>',fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a9}" src="1f4a9.png"/>',fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f608}" src="1f608.png"/>',fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47f}" src="1f47f.png"/>',fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f479}" src="1f479.png"/>',fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47a}" src="1f47a.png"/>',fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f480}" src="1f480.png"/>',fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47b}" src="1f47b.png"/>',fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47d}" src="1f47d.png"/>',fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f916}" src="1f916.png"/>',fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63a}" src="1f63a.png"/>',fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f638}" src="1f638.png"/>',fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f639}" src="1f639.png"/>',fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63b}" src="1f63b.png"/>',fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63c}" src="1f63c.png"/>',fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63d}" src="1f63d.png"/>',fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f640}" src="1f640.png"/>',fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63f}" src="1f63f.png"/>',fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f63e}" src="1f63e.png"/>',fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f932}" src="1f932.png"/>',fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64c}" src="1f64c.png"/>',fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44f}" src="1f44f.png"/>',fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44b}" src="1f44b.png"/>',fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f919}" src="1f919.png"/>',fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44d}" src="1f44d.png"/>',fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44e}" src="1f44e.png"/>',fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44a}" src="1f44a.png"/>',fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270a" src="270a.png"/>',fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91b}" src="1f91b.png"/>',fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91c}" src="1f91c.png"/>',fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270c" src="270c.png"/>',fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f44c}" src="1f44c.png"/>',fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270b" src="270b.png"/>',fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91a}" src="1f91a.png"/>',fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f450}" src="1f450.png"/>',fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4aa}" src="1f4aa.png"/>',fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64f}" src="1f64f.png"/>',fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b6}" src="1f9b6.png"/>',fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b5}" src="1f9b5.png"/>',fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91d}" src="1f91d.png"/>',fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u261d" src="261d.png"/>',fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f446}" src="1f446.png"/>',fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f447}" src="1f447.png"/>',fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f448}" src="1f448.png"/>',fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f449}" src="1f449.png"/>',fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f595}" src="1f595.png"/>',fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f590}" src="1f590.png"/>',fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91f}" src="1f91f.png"/>',fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f918}" src="1f918.png"/>',fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f91e}" src="1f91e.png"/>',fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f596}" src="1f596.png"/>',fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270d" src="270d.png"/>',fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f933}" src="1f933.png"/>',fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f485}" src="1f485.png"/>',fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f444}" src="1f444.png"/>',fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b7}" src="1f9b7.png"/>',fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f445}" src="1f445.png"/>',fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f442}" src="1f442.png"/>',fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f443}" src="1f443.png"/>',fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f441}" src="1f441.png"/>',fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f440}" src="1f440.png"/>',fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e0}" src="1f9e0.png"/>',fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f464}" src="1f464.png"/>',fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f465}" src="1f465.png"/>',fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5e3}" src="1f5e3.png"/>',fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f476}" src="1f476.png"/>',fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d2}" src="1f9d2.png"/>',fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f466}" src="1f466.png"/>',fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f467}" src="1f467.png"/>',fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d1}" src="1f9d1.png"/>',fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}" src="1f468.png"/>',fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}" src="1f469.png"/>',fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f471}\u200d\u2640\ufe0f" src="1f471-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f471}" src="1f471.png"/>',fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d4}" src="1f9d4.png"/>',fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d3}" src="1f9d3.png"/>',fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f474}" src="1f474.png"/>',fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f475}" src="1f475.png"/>',fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f472}" src="1f472.png"/>',fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d5}" src="1f9d5.png"/>',fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f473}\u200d\u2640\ufe0f" src="1f473-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f473}" src="1f473.png"/>',fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46e}\u200d\u2640\ufe0f" src="1f46e-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46e}" src="1f46e.png"/>',fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f477}\u200d\u2640\ufe0f" src="1f477-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f477}" src="1f477.png"/>',fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f482}\u200d\u2640\ufe0f" src="1f482-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f482}" src="1f482.png"/>',fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f575}\ufe0f\u200d\u2640\ufe0f" src="1f575-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f575}" src="1f575.png"/>',fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u2695\ufe0f" src="1f469-200d-2695-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u2695\ufe0f" src="1f468-200d-2695-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f33e}" src="1f469-200d-1f33e.png"/>',fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f33e}" src="1f468-200d-1f33e.png"/>',fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f373}" src="1f469-200d-1f373.png"/>',fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f373}" src="1f468-200d-1f373.png"/>',fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f393}" src="1f469-200d-1f393.png"/>',fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f393}" src="1f468-200d-1f393.png"/>',fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f3a4}" src="1f469-200d-1f3a4.png"/>',fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f3a4}" src="1f468-200d-1f3a4.png"/>',fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f3eb}" src="1f469-200d-1f3eb.png"/>',fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f3eb}" src="1f468-200d-1f3eb.png"/>',fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f3ed}" src="1f469-200d-1f3ed.png"/>',fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f3ed}" src="1f468-200d-1f3ed.png"/>',fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f4bb}" src="1f469-200d-1f4bb.png"/>',fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f4bb}" src="1f468-200d-1f4bb.png"/>',fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f4bc}" src="1f469-200d-1f4bc.png"/>',fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f4bc}" src="1f468-200d-1f4bc.png"/>',fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f527}" src="1f469-200d-1f527.png"/>',fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f527}" src="1f468-200d-1f527.png"/>',fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f52c}" src="1f469-200d-1f52c.png"/>',fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f52c}" src="1f468-200d-1f52c.png"/>',fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f3a8}" src="1f469-200d-1f3a8.png"/>',fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f3a8}" src="1f468-200d-1f3a8.png"/>',fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f692}" src="1f469-200d-1f692.png"/>',fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f692}" src="1f468-200d-1f692.png"/>',fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u2708\ufe0f" src="1f469-200d-2708-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u2708\ufe0f" src="1f468-200d-2708-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f680}" src="1f469-200d-1f680.png"/>',fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f680}" src="1f468-200d-1f680.png"/>',fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u2696\ufe0f" src="1f469-200d-2696-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u2696\ufe0f" src="1f468-200d-2696-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b8}\u200d\u2640\ufe0f" src="1f9b8-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b8}\u200d\u2642\ufe0f" src="1f9b8-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b9}\u200d\u2640\ufe0f" src="1f9b9-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b9}\u200d\u2642\ufe0f" src="1f9b9-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f936}" src="1f936.png"/>',fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f385}" src="1f385.png"/>',fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d9}\u200d\u2640\ufe0f" src="1f9d9-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d9}\u200d\u2642\ufe0f" src="1f9d9-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9dd}\u200d\u2640\ufe0f" src="1f9dd-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9dd}\u200d\u2642\ufe0f" src="1f9dd-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9db}\u200d\u2640\ufe0f" src="1f9db-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9db}\u200d\u2642\ufe0f" src="1f9db-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9df}\u200d\u2640\ufe0f" src="1f9df-200d-2640-fe0f.png"/>',fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9df}\u200d\u2642\ufe0f" src="1f9df-200d-2642-fe0f.png"/>',fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9de}\u200d\u2640\ufe0f" src="1f9de-200d-2640-fe0f.png"/>',fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9de}\u200d\u2642\ufe0f" src="1f9de-200d-2642-fe0f.png"/>',fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9dc}\u200d\u2640\ufe0f" src="1f9dc-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9dc}\u200d\u2642\ufe0f" src="1f9dc-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9da}\u200d\u2640\ufe0f" src="1f9da-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9da}\u200d\u2642\ufe0f" src="1f9da-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47c}" src="1f47c.png"/>',fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f930}" src="1f930.png"/>',fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f931}" src="1f931.png"/>',fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f478}" src="1f478.png"/>',fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f934}" src="1f934.png"/>',fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f470}" src="1f470.png"/>',fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f935}" src="1f935.png"/>',fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c3}\u200d\u2640\ufe0f" src="1f3c3-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c3}" src="1f3c3.png"/>',fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b6}\u200d\u2640\ufe0f" src="1f6b6-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b6}" src="1f6b6.png"/>',fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f483}" src="1f483.png"/>',fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f57a}" src="1f57a.png"/>',fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46f}" src="1f46f.png"/>',fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46f}\u200d\u2642\ufe0f" src="1f46f-200d-2642-fe0f.png"/>',fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46b}" src="1f46b.png"/>',fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46c}" src="1f46c.png"/>',fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46d}" src="1f46d.png"/>',fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f647}\u200d\u2640\ufe0f" src="1f647-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f647}" src="1f647.png"/>',fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f926}\u200d\u2642\ufe0f" src="1f926-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f926}\u200d\u2640\ufe0f" src="1f926-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f937}" src="1f937.png"/>',fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f937}\u200d\u2642\ufe0f" src="1f937-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f481}" src="1f481.png"/>',fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f481}\u200d\u2642\ufe0f" src="1f481-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f645}" src="1f645.png"/>',fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f645}\u200d\u2642\ufe0f" src="1f645-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f646}" src="1f646.png"/>',fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f646}\u200d\u2642\ufe0f" src="1f646-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64b}" src="1f64b.png"/>',fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64b}\u200d\u2642\ufe0f" src="1f64b-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64e}" src="1f64e.png"/>',fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64e}\u200d\u2642\ufe0f" src="1f64e-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64d}" src="1f64d.png"/>',fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64d}\u200d\u2642\ufe0f" src="1f64d-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f487}" src="1f487.png"/>',fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f487}\u200d\u2642\ufe0f" src="1f487-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f486}" src="1f486.png"/>',fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f486}\u200d\u2642\ufe0f" src="1f486-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d6}\u200d\u2640\ufe0f" src="1f9d6-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d6}\u200d\u2642\ufe0f" src="1f9d6-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f491}" src="1f491.png"/>',fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}" src="1f469-200d-2764-fe0f-200d-1f469.png"/>',fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}" src="1f468-200d-2764-fe0f-200d-1f468.png"/>',fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48f}" src="1f48f.png"/>',fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}" src="1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.png"/>',fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}" src="1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f46a}" src="1f46a.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f469}\u200d\u{1f467}" src="1f468-200d-1f469-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}" src="1f468-200d-1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}" src="1f468-200d-1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}" src="1f468-200d-1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f469}\u200d\u{1f466}" src="1f469-200d-1f469-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f469}\u200d\u{1f467}" src="1f469-200d-1f469-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}" src="1f469-200d-1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}" src="1f469-200d-1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}" src="1f469-200d-1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f468}\u200d\u{1f466}" src="1f468-200d-1f468-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f468}\u200d\u{1f467}" src="1f468-200d-1f468-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}" src="1f468-200d-1f468-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}" src="1f468-200d-1f468-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}" src="1f468-200d-1f468-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f466}" src="1f469-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f467}" src="1f469-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f467}\u200d\u{1f466}" src="1f469-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f466}\u200d\u{1f466}" src="1f469-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f469}\u200d\u{1f467}\u200d\u{1f467}" src="1f469-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f466}" src="1f468-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f467}" src="1f468-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f467}\u200d\u{1f466}" src="1f468-200d-1f467-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f466}\u200d\u{1f466}" src="1f468-200d-1f466-200d-1f466.png"/>',fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f468}\u200d\u{1f467}\u200d\u{1f467}" src="1f468-200d-1f467-200d-1f467.png"/>',fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f6}" src="1f9f6.png"/>',fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f5}" src="1f9f5.png"/>',fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e5}" src="1f9e5.png"/>',fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f97c}" src="1f97c.png"/>',fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45a}" src="1f45a.png"/>',fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f455}" src="1f455.png"/>',fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f456}" src="1f456.png"/>',fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f454}" src="1f454.png"/>',fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f457}" src="1f457.png"/>',fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f459}" src="1f459.png"/>',fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f458}" src="1f458.png"/>',fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f484}" src="1f484.png"/>',fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48b}" src="1f48b.png"/>',fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f463}" src="1f463.png"/>',fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f97f}" src="1f97f.png"/>',fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f460}" src="1f460.png"/>',fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f461}" src="1f461.png"/>',fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f462}" src="1f462.png"/>',fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45e}" src="1f45e.png"/>',fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45f}" src="1f45f.png"/>',fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f97e}" src="1f97e.png"/>',fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e6}" src="1f9e6.png"/>',fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e4}" src="1f9e4.png"/>',fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e3}" src="1f9e3.png"/>',fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f452}" src="1f452.png"/>',fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a9}" src="1f3a9.png"/>',fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e2}" src="1f9e2.png"/>',fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d1" src="26d1.png"/>',fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f393}" src="1f393.png"/>',fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f451}" src="1f451.png"/>',fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f392}" src="1f392.png"/>',fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f3}" src="1f9f3.png"/>',fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45d}" src="1f45d.png"/>',fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45b}" src="1f45b.png"/>',fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f45c}" src="1f45c.png"/>',fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4bc}" src="1f4bc.png"/>',fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f453}" src="1f453.png"/>',fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f576}" src="1f576.png"/>',fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f97d}" src="1f97d.png"/>',fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48d}" src="1f48d.png"/>',fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f302}" src="1f302.png"/>',fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f436}" src="1f436.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f431}" src="1f431.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42d}" src="1f42d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f439}" src="1f439.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f430}" src="1f430.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98a}" src="1f98a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43b}" src="1f43b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43c}" src="1f43c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f428}" src="1f428.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42f}" src="1f42f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f981}" src="1f981.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42e}" src="1f42e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f437}" src="1f437.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43d}" src="1f43d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f438}" src="1f438.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f991}" src="1f991.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f419}" src="1f419.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f990}" src="1f990.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f435}" src="1f435.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98d}" src="1f98d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f648}" src="1f648.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f649}" src="1f649.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f64a}" src="1f64a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f412}" src="1f412.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f414}" src="1f414.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f427}" src="1f427.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f426}" src="1f426.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f424}" src="1f424.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f423}" src="1f423.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f425}" src="1f425.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f986}" src="1f986.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f985}" src="1f985.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f989}" src="1f989.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f987}" src="1f987.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43a}" src="1f43a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f417}" src="1f417.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f434}" src="1f434.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f984}" src="1f984.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41d}" src="1f41d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41b}" src="1f41b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98b}" src="1f98b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40c}" src="1f40c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41e}" src="1f41e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41c}" src="1f41c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f997}" src="1f997.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f577}" src="1f577.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f982}" src="1f982.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f980}" src="1f980.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40d}" src="1f40d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98e}" src="1f98e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f996}" src="1f996.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f995}" src="1f995.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f422}" src="1f422.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f420}" src="1f420.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41f}" src="1f41f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f421}" src="1f421.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42c}" src="1f42c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f988}" src="1f988.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f433}" src="1f433.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40b}" src="1f40b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40a}" src="1f40a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f406}" src="1f406.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f993}" src="1f993.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f405}" src="1f405.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f403}" src="1f403.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f402}" src="1f402.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f404}" src="1f404.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98c}" src="1f98c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42a}" src="1f42a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f42b}" src="1f42b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f992}" src="1f992.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f418}" src="1f418.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f98f}" src="1f98f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f410}" src="1f410.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40f}" src="1f40f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f411}" src="1f411.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f40e}" src="1f40e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f416}" src="1f416.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f400}" src="1f400.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f401}" src="1f401.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f413}" src="1f413.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f983}" src="1f983.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f54a}" src="1f54a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f415}" src="1f415.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f429}" src="1f429.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f408}" src="1f408.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f407}" src="1f407.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43f}" src="1f43f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f994}" src="1f994.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99d}" src="1f99d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f999}" src="1f999.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99b}" src="1f99b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f998}" src="1f998.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9a1}" src="1f9a1.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9a2}" src="1f9a2.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99a}" src="1f99a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99c}" src="1f99c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99e}" src="1f99e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f99f}" src="1f99f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f43e}" src="1f43e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f409}" src="1f409.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f432}" src="1f432.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f335}" src="1f335.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f384}" src="1f384.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f332}" src="1f332.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f333}" src="1f333.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f334}" src="1f334.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f331}" src="1f331.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33f}" src="1f33f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2618" src="2618.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f340}" src="1f340.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38d}" src="1f38d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38b}" src="1f38b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f343}" src="1f343.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f342}" src="1f342.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f341}" src="1f341.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33e}" src="1f33e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33a}" src="1f33a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33b}" src="1f33b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f339}" src="1f339.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f940}" src="1f940.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f337}" src="1f337.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33c}" src="1f33c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f338}" src="1f338.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f490}" src="1f490.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f344}" src="1f344.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f330}" src="1f330.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f383}" src="1f383.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f41a}" src="1f41a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f578}" src="1f578.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30e}" src="1f30e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30d}" src="1f30d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30f}" src="1f30f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f315}" src="1f315.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f316}" src="1f316.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f317}" src="1f317.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f318}" src="1f318.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f311}" src="1f311.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f312}" src="1f312.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f313}" src="1f313.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f314}" src="1f314.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31a}" src="1f31a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31d}" src="1f31d.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31b}" src="1f31b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31c}" src="1f31c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31e}" src="1f31e.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f319}" src="1f319.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b50" src="2b50.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f31f}" src="1f31f.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ab}" src="1f4ab.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2728" src="2728.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2604" src="2604.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2600\ufe0f" src="2600.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f324}" src="1f324.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c5" src="26c5.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f325}" src="1f325.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f326}" src="1f326.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2601\ufe0f" src="2601.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f327}" src="1f327.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c8" src="26c8.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f329}" src="1f329.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26a1" src="26a1.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f525}" src="1f525.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a5}" src="1f4a5.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2744\ufe0f" src="2744.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f328}" src="1f328.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26c4" src="26c4.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2603" src="2603.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32c}" src="1f32c.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a8}" src="1f4a8.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32a}" src="1f32a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32b}" src="1f32b.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2602" src="2602.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2614" src="2614.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a7}" src="1f4a7.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a6}" src="1f4a6.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30a}" src="1f30a.png"/>',fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34f}" src="1f34f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34e}" src="1f34e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f350}" src="1f350.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34a}" src="1f34a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34b}" src="1f34b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34c}" src="1f34c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f349}" src="1f349.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f347}" src="1f347.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f353}" src="1f353.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f348}" src="1f348.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f352}" src="1f352.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f351}" src="1f351.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f34d}" src="1f34d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f965}" src="1f965.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95d}" src="1f95d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96d}" src="1f96d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f951}" src="1f951.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f966}" src="1f966.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f345}" src="1f345.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f346}" src="1f346.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f952}" src="1f952.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f955}" src="1f955.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f336}" src="1f336.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f954}" src="1f954.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f33d}" src="1f33d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96c}" src="1f96c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f360}" src="1f360.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95c}" src="1f95c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36f}" src="1f36f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f950}" src="1f950.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35e}" src="1f35e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f956}" src="1f956.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96f}" src="1f96f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f968}" src="1f968.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9c0}" src="1f9c0.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95a}" src="1f95a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f953}" src="1f953.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f969}" src="1f969.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95e}" src="1f95e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f357}" src="1f357.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f356}" src="1f356.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9b4}" src="1f9b4.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f364}" src="1f364.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f373}" src="1f373.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f354}" src="1f354.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35f}" src="1f35f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f959}" src="1f959.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32d}" src="1f32d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f355}" src="1f355.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96a}" src="1f96a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96b}" src="1f96b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35d}" src="1f35d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32e}" src="1f32e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f32f}" src="1f32f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f957}" src="1f957.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f958}" src="1f958.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35c}" src="1f35c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f372}" src="1f372.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f365}" src="1f365.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f960}" src="1f960.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f363}" src="1f363.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f371}" src="1f371.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35b}" src="1f35b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f359}" src="1f359.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f35a}" src="1f35a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f358}" src="1f358.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f362}" src="1f362.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f361}" src="1f361.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f367}" src="1f367.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f368}" src="1f368.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f366}" src="1f366.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f967}" src="1f967.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f370}" src="1f370.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9c1}" src="1f9c1.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f96e}" src="1f96e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f382}" src="1f382.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36e}" src="1f36e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36c}" src="1f36c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36d}" src="1f36d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36b}" src="1f36b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37f}" src="1f37f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95f}" src="1f95f.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f369}" src="1f369.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f36a}" src="1f36a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f95b}" src="1f95b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37a}" src="1f37a.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37b}" src="1f37b.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f942}" src="1f942.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f377}" src="1f377.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f943}" src="1f943.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f378}" src="1f378.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f379}" src="1f379.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37e}" src="1f37e.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f376}" src="1f376.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f375}" src="1f375.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f964}" src="1f964.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2615" src="2615.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37c}" src="1f37c.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9c2}" src="1f9c2.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f944}" src="1f944.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f374}" src="1f374.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f37d}" src="1f37d.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f963}" src="1f963.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f961}" src="1f961.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f962}" src="1f962.png"/>',fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26bd" src="26bd.png"/>',fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c0}" src="1f3c0.png"/>',fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c8}" src="1f3c8.png"/>',fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26be" src="26be.png"/>',fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94e}" src="1f94e.png"/>',fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3be}" src="1f3be.png"/>',fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d0}" src="1f3d0.png"/>',fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c9}" src="1f3c9.png"/>',fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94f}" src="1f94f.png"/>',fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b1}" src="1f3b1.png"/>',fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f3" src="26f3.png"/>',fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cc}\ufe0f\u200d\u2640\ufe0f" src="1f3cc-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cc}" src="1f3cc.png"/>',fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d3}" src="1f3d3.png"/>',fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f8}" src="1f3f8.png"/>',fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f945}" src="1f945.png"/>',fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d2}" src="1f3d2.png"/>',fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d1}" src="1f3d1.png"/>',fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94d}" src="1f94d.png"/>',fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cf}" src="1f3cf.png"/>',fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3bf}" src="1f3bf.png"/>',fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f7" src="26f7.png"/>',fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c2}" src="1f3c2.png"/>',fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93a}" src="1f93a.png"/>',fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93c}\u200d\u2640\ufe0f" src="1f93c-200d-2640-fe0f.png"/>',fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93c}\u200d\u2642\ufe0f" src="1f93c-200d-2642-fe0f.png"/>',fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f938}\u200d\u2640\ufe0f" src="1f938-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f938}\u200d\u2642\ufe0f" src="1f938-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93e}\u200d\u2640\ufe0f" src="1f93e-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93e}\u200d\u2642\ufe0f" src="1f93e-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f8" src="26f8.png"/>',fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94c}" src="1f94c.png"/>',fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f9}" src="1f6f9.png"/>',fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f7}" src="1f6f7.png"/>',fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f9}" src="1f3f9.png"/>',fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a3}" src="1f3a3.png"/>',fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94a}" src="1f94a.png"/>',fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f94b}" src="1f94b.png"/>',fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a3}\u200d\u2640\ufe0f" src="1f6a3-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a3}" src="1f6a3.png"/>',fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d7}\u200d\u2640\ufe0f" src="1f9d7-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d7}\u200d\u2642\ufe0f" src="1f9d7-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ca}\u200d\u2640\ufe0f" src="1f3ca-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ca}" src="1f3ca.png"/>',fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93d}\u200d\u2640\ufe0f" src="1f93d-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f93d}\u200d\u2642\ufe0f" src="1f93d-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d8}\u200d\u2640\ufe0f" src="1f9d8-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9d8}\u200d\u2642\ufe0f" src="1f9d8-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c4}\u200d\u2640\ufe0f" src="1f3c4-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c4}" src="1f3c4.png"/>',fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c0}" src="1f6c0.png"/>',fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f9\ufe0f\u200d\u2640\ufe0f" src="26f9-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f9" src="26f9.png"/>',fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cb}\ufe0f\u200d\u2640\ufe0f" src="1f3cb-fe0f-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cb}" src="1f3cb.png"/>',fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b4}\u200d\u2640\ufe0f" src="1f6b4-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b4}" src="1f6b4.png"/>',fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b5}\u200d\u2640\ufe0f" src="1f6b5-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b5}" src="1f6b5.png"/>',fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c7}" src="1f3c7.png"/>',fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f574}" src="1f574.png"/>',fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c6}" src="1f3c6.png"/>',fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3bd}" src="1f3bd.png"/>',fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c5}" src="1f3c5.png"/>',fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f396}" src="1f396.png"/>',fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f947}" src="1f947.png"/>',fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f948}" src="1f948.png"/>',fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f949}" src="1f949.png"/>',fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f397}" src="1f397.png"/>',fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f5}" src="1f3f5.png"/>',fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ab}" src="1f3ab.png"/>',fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f39f}" src="1f39f.png"/>',fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ad}" src="1f3ad.png"/>',fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a8}" src="1f3a8.png"/>',fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3aa}" src="1f3aa.png"/>',fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f939}\u200d\u2640\ufe0f" src="1f939-200d-2640-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f939}\u200d\u2642\ufe0f" src="1f939-200d-2642-fe0f.png"/>',fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a4}" src="1f3a4.png"/>',fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a7}" src="1f3a7.png"/>',fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3bc}" src="1f3bc.png"/>',fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b9}" src="1f3b9.png"/>',fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f941}" src="1f941.png"/>',fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b7}" src="1f3b7.png"/>',fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ba}" src="1f3ba.png"/>',fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b8}" src="1f3b8.png"/>',fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3bb}" src="1f3bb.png"/>',fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ac}" src="1f3ac.png"/>',fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ae}" src="1f3ae.png"/>',fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f47e}" src="1f47e.png"/>',fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3af}" src="1f3af.png"/>',fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b2}" src="1f3b2.png"/>',fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b0}" src="1f3b0.png"/>',fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e9}" src="1f9e9.png"/>',fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b3}" src="1f3b3.png"/>',fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f697}" src="1f697.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f695}" src="1f695.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f699}" src="1f699.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68c}" src="1f68c.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68e}" src="1f68e.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ce}" src="1f3ce.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f693}" src="1f693.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f691}" src="1f691.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f692}" src="1f692.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f690}" src="1f690.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69a}" src="1f69a.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69b}" src="1f69b.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69c}" src="1f69c.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f4}" src="1f6f4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3cd}" src="1f3cd.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b2}" src="1f6b2.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f5}" src="1f6f5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a8}" src="1f6a8.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f694}" src="1f694.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68d}" src="1f68d.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f698}" src="1f698.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f696}" src="1f696.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a1}" src="1f6a1.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a0}" src="1f6a0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69f}" src="1f69f.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f683}" src="1f683.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68b}" src="1f68b.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69d}" src="1f69d.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f684}" src="1f684.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f685}" src="1f685.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f688}" src="1f688.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f69e}" src="1f69e.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f682}" src="1f682.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f686}" src="1f686.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f687}" src="1f687.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68a}" src="1f68a.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f689}" src="1f689.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f8}" src="1f6f8.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f681}" src="1f681.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e9}" src="1f6e9.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2708\ufe0f" src="2708.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6eb}" src="1f6eb.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ec}" src="1f6ec.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f5" src="26f5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e5}" src="1f6e5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a4}" src="1f6a4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f4" src="26f4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f3}" src="1f6f3.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f680}" src="1f680.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f0}" src="1f6f0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ba}" src="1f4ba.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6f6}" src="1f6f6.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2693" src="2693.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a7}" src="1f6a7.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26fd" src="26fd.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f68f}" src="1f68f.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a6}" src="1f6a6.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a5}" src="1f6a5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3c1}" src="1f3c1.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a2}" src="1f6a2.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a1}" src="1f3a1.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a2}" src="1f3a2.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a0}" src="1f3a0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d7}" src="1f3d7.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f301}" src="1f301.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5fc}" src="1f5fc.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ed}" src="1f3ed.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f2" src="26f2.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f391}" src="1f391.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f0" src="26f0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d4}" src="1f3d4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5fb}" src="1f5fb.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30b}" src="1f30b.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5fe}" src="1f5fe.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d5}" src="1f3d5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26fa" src="26fa.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3de}" src="1f3de.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e3}" src="1f6e3.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e4}" src="1f6e4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f305}" src="1f305.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f304}" src="1f304.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3dc}" src="1f3dc.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d6}" src="1f3d6.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3dd}" src="1f3dd.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f307}" src="1f307.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f306}" src="1f306.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d9}" src="1f3d9.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f303}" src="1f303.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f309}" src="1f309.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f30c}" src="1f30c.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f320}" src="1f320.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f387}" src="1f387.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f386}" src="1f386.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f308}" src="1f308.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3d8}" src="1f3d8.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f0}" src="1f3f0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ef}" src="1f3ef.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3df}" src="1f3df.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5fd}" src="1f5fd.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e0}" src="1f3e0.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e1}" src="1f3e1.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3da}" src="1f3da.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e2}" src="1f3e2.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ec}" src="1f3ec.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e3}" src="1f3e3.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e4}" src="1f3e4.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e5}" src="1f3e5.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e6}" src="1f3e6.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e8}" src="1f3e8.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ea}" src="1f3ea.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3eb}" src="1f3eb.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e9}" src="1f3e9.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f492}" src="1f492.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3db}" src="1f3db.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ea" src="26ea.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f54c}" src="1f54c.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f54d}" src="1f54d.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f54b}" src="1f54b.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26e9" src="26e9.png"/>',fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u231a" src="231a.png"/>',fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f1}" src="1f4f1.png"/>',fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f2}" src="1f4f2.png"/>',fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4bb}" src="1f4bb.png"/>',fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2328" src="2328.png"/>',fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5a5}" src="1f5a5.png"/>',fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5a8}" src="1f5a8.png"/>',fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5b1}" src="1f5b1.png"/>',fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5b2}" src="1f5b2.png"/>',fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f579}" src="1f579.png"/>',fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5dc}" src="1f5dc.png"/>',fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4bd}" src="1f4bd.png"/>',fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4be}" src="1f4be.png"/>',fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4bf}" src="1f4bf.png"/>',fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c0}" src="1f4c0.png"/>',fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4fc}" src="1f4fc.png"/>',fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f7}" src="1f4f7.png"/>',fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f8}" src="1f4f8.png"/>',fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f9}" src="1f4f9.png"/>',fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a5}" src="1f3a5.png"/>',fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4fd}" src="1f4fd.png"/>',fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f39e}" src="1f39e.png"/>',fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4de}" src="1f4de.png"/>',fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u260e\ufe0f" src="260e.png"/>',fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4df}" src="1f4df.png"/>',fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e0}" src="1f4e0.png"/>',fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4fa}" src="1f4fa.png"/>',fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4fb}" src="1f4fb.png"/>',fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f399}" src="1f399.png"/>',fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f39a}" src="1f39a.png"/>',fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f39b}" src="1f39b.png"/>',fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ed}" src="1f9ed.png"/>',fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f1" src="23f1.png"/>',fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f2" src="23f2.png"/>',fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f0" src="23f0.png"/>',fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f570}" src="1f570.png"/>',fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f3" src="23f3.png"/>',fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u231b" src="231b.png"/>',fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e1}" src="1f4e1.png"/>',fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50b}" src="1f50b.png"/>',fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50c}" src="1f50c.png"/>',fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a1}" src="1f4a1.png"/>',fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f526}" src="1f526.png"/>',fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f56f}" src="1f56f.png"/>',fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ef}" src="1f9ef.png"/>',fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5d1}" src="1f5d1.png"/>',fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e2}" src="1f6e2.png"/>',fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b8}" src="1f4b8.png"/>',fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b5}" src="1f4b5.png"/>',fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b4}" src="1f4b4.png"/>',fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b6}" src="1f4b6.png"/>',fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b7}" src="1f4b7.png"/>',fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b0}" src="1f4b0.png"/>',fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b3}" src="1f4b3.png"/>',fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48e}" src="1f48e.png"/>',fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2696" src="2696.png"/>',fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f0}" src="1f9f0.png"/>',fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f527}" src="1f527.png"/>',fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f528}" src="1f528.png"/>',fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2692" src="2692.png"/>',fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e0}" src="1f6e0.png"/>',fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26cf" src="26cf.png"/>',fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f529}" src="1f529.png"/>',fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2699" src="2699.png"/>',fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f1}" src="1f9f1.png"/>',fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d3" src="26d3.png"/>',fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f2}" src="1f9f2.png"/>',fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52b}" src="1f52b.png"/>',fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a3}" src="1f4a3.png"/>',fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e8}" src="1f9e8.png"/>',fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52a}" src="1f52a.png"/>',fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5e1}" src="1f5e1.png"/>',fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2694" src="2694.png"/>',fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6e1}" src="1f6e1.png"/>',fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ac}" src="1f6ac.png"/>',fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2620" src="2620.png"/>',fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26b0" src="26b0.png"/>',fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26b1" src="26b1.png"/>',fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3fa}" src="1f3fa.png"/>',fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52e}" src="1f52e.png"/>',fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ff}" src="1f4ff.png"/>',fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ff}" src="1f9ff.png"/>',fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f488}" src="1f488.png"/>',fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2697" src="2697.png"/>',fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52d}" src="1f52d.png"/>',fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52c}" src="1f52c.png"/>',fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f573}" src="1f573.png"/>',fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48a}" src="1f48a.png"/>',fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f489}" src="1f489.png"/>',fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ec}" src="1f9ec.png"/>',fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9a0}" src="1f9a0.png"/>',fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9eb}" src="1f9eb.png"/>',fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ea}" src="1f9ea.png"/>',fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f321}" src="1f321.png"/>',fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f9}" src="1f9f9.png"/>',fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9fa}" src="1f9fa.png"/>',fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9fb}" src="1f9fb.png"/>',fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f7}" src="1f3f7.png"/>',fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f516}" src="1f516.png"/>',fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6bd}" src="1f6bd.png"/>',fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6bf}" src="1f6bf.png"/>',fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c1}" src="1f6c1.png"/>',fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9fc}" src="1f9fc.png"/>',fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9fd}" src="1f9fd.png"/>',fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f4}" src="1f9f4.png"/>',fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f511}" src="1f511.png"/>',fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5dd}" src="1f5dd.png"/>',fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6cb}" src="1f6cb.png"/>',fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6cc}" src="1f6cc.png"/>',fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6cf}" src="1f6cf.png"/>',fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6aa}" src="1f6aa.png"/>',fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ce}" src="1f6ce.png"/>',fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f8}" src="1f9f8.png"/>',fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5bc}" src="1f5bc.png"/>',fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5fa}" src="1f5fa.png"/>',fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26f1" src="26f1.png"/>',fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5ff}" src="1f5ff.png"/>',fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6cd}" src="1f6cd.png"/>',fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6d2}" src="1f6d2.png"/>',fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f388}" src="1f388.png"/>',fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38f}" src="1f38f.png"/>',fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f380}" src="1f380.png"/>',fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f381}" src="1f381.png"/>',fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38a}" src="1f38a.png"/>',fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f389}" src="1f389.png"/>',fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38e}" src="1f38e.png"/>',fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f390}" src="1f390.png"/>',fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f38c}" src="1f38c.png"/>',fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3ee}" src="1f3ee.png"/>',fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e7}" src="1f9e7.png"/>',fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2709\ufe0f" src="2709.png"/>',fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e9}" src="1f4e9.png"/>',fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e8}" src="1f4e8.png"/>',fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e7}" src="1f4e7.png"/>',fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f48c}" src="1f48c.png"/>',fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ee}" src="1f4ee.png"/>',fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ea}" src="1f4ea.png"/>',fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4eb}" src="1f4eb.png"/>',fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ec}" src="1f4ec.png"/>',fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ed}" src="1f4ed.png"/>',fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e6}" src="1f4e6.png"/>',fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ef}" src="1f4ef.png"/>',fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e5}" src="1f4e5.png"/>',fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e4}" src="1f4e4.png"/>',fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4dc}" src="1f4dc.png"/>',fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c3}" src="1f4c3.png"/>',fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d1}" src="1f4d1.png"/>',fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9fe}" src="1f9fe.png"/>',fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ca}" src="1f4ca.png"/>',fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c8}" src="1f4c8.png"/>',fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c9}" src="1f4c9.png"/>',fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c4}" src="1f4c4.png"/>',fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c5}" src="1f4c5.png"/>',fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c6}" src="1f4c6.png"/>',fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5d3}" src="1f5d3.png"/>',fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c7}" src="1f4c7.png"/>',fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5c3}" src="1f5c3.png"/>',fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5f3}" src="1f5f3.png"/>',fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5c4}" src="1f5c4.png"/>',fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4cb}" src="1f4cb.png"/>',fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5d2}" src="1f5d2.png"/>',fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c1}" src="1f4c1.png"/>',fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4c2}" src="1f4c2.png"/>',fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5c2}" src="1f5c2.png"/>',fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5de}" src="1f5de.png"/>',fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f0}" src="1f4f0.png"/>',fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d3}" src="1f4d3.png"/>',fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d5}" src="1f4d5.png"/>',fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d7}" src="1f4d7.png"/>',fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d8}" src="1f4d8.png"/>',fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d9}" src="1f4d9.png"/>',fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d4}" src="1f4d4.png"/>',fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d2}" src="1f4d2.png"/>',fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4da}" src="1f4da.png"/>',fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d6}" src="1f4d6.png"/>',fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9f7}" src="1f9f7.png"/>',fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f517}" src="1f517.png"/>',fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ce}" src="1f4ce.png"/>',fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f587}" src="1f587.png"/>',fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2702\ufe0f" src="2702.png"/>',fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4d0}" src="1f4d0.png"/>',fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4cf}" src="1f4cf.png"/>',fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9ee}" src="1f9ee.png"/>',fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4cc}" src="1f4cc.png"/>',fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4cd}" src="1f4cd.png"/>',fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6a9}" src="1f6a9.png"/>',fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f3}" src="1f3f3.png"/>',fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f4}" src="1f3f4.png"/>',fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f3}\ufe0f\u200d\u{1f308}" src="1f3f3-fe0f-200d-1f308.png"/>',fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f510}" src="1f510.png"/>',fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f512}" src="1f512.png"/>',fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f513}" src="1f513.png"/>',fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50f}" src="1f50f.png"/>',fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f58a}" src="1f58a.png"/>',fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f58b}" src="1f58b.png"/>',fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2712\ufe0f" src="2712.png"/>',fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4dd}" src="1f4dd.png"/>',fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u270f\ufe0f" src="270f.png"/>',fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f58d}" src="1f58d.png"/>',fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f58c}" src="1f58c.png"/>',fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50d}" src="1f50d.png"/>',fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50e}" src="1f50e.png"/>',fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2764\ufe0f" src="2764.png"/>',fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f9e1}" src="1f9e1.png"/>',fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49b}" src="1f49b.png"/>',fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49a}" src="1f49a.png"/>',fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f499}" src="1f499.png"/>',fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49c}" src="1f49c.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5a4}" src="1f5a4.png"/>',fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f494}" src="1f494.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2763" src="2763.png"/>',fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f495}" src="1f495.png"/>',fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49e}" src="1f49e.png"/>',fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f493}" src="1f493.png"/>',fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f497}" src="1f497.png"/>',fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f496}" src="1f496.png"/>',fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f498}" src="1f498.png"/>',fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49d}" src="1f49d.png"/>',fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f49f}" src="1f49f.png"/>',fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262e" src="262e.png"/>',fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u271d" src="271d.png"/>',fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262a" src="262a.png"/>',fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f549}" src="1f549.png"/>',fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2638" src="2638.png"/>',fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2721" src="2721.png"/>',fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f52f}" src="1f52f.png"/>',fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f54e}" src="1f54e.png"/>',fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u262f" src="262f.png"/>',fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2626" src="2626.png"/>',fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6d0}" src="1f6d0.png"/>',fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ce" src="26ce.png"/>',fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2648" src="2648.png"/>',fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2649" src="2649.png"/>',fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264a" src="264a.png"/>',fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264b" src="264b.png"/>',fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264c" src="264c.png"/>',fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264d" src="264d.png"/>',fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264e" src="264e.png"/>',fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u264f" src="264f.png"/>',fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2650" src="2650.png"/>',fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2651" src="2651.png"/>',fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2652" src="2652.png"/>',fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2653" src="2653.png"/>',fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f194}" src="1f194.png"/>',fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u269b" src="269b.png"/>',fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f233}" src="1f233.png"/>',fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f239}" src="1f239.png"/>',fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2622" src="2622.png"/>',fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2623" src="2623.png"/>',fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f4}" src="1f4f4.png"/>',fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f3}" src="1f4f3.png"/>',fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f236}" src="1f236.png"/>',fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f21a}" src="1f21a.png"/>',fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f238}" src="1f238.png"/>',fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f23a}" src="1f23a.png"/>',fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f237}\ufe0f" src="1f237.png"/>',fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2734\ufe0f" src="2734.png"/>',fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f19a}" src="1f19a.png"/>',fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f251}" src="1f251.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ae}" src="1f4ae.png"/>',fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f250}" src="1f250.png"/>',fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3299\ufe0f" src="3299.png"/>',fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3297\ufe0f" src="3297.png"/>',fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f234}" src="1f234.png"/>',fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f235}" src="1f235.png"/>',fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f232}" src="1f232.png"/>',fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f170}\ufe0f" src="1f170.png"/>',fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f171}\ufe0f" src="1f171.png"/>',fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f18e}" src="1f18e.png"/>',fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f191}" src="1f191.png"/>',fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f17e}\ufe0f" src="1f17e.png"/>',fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f198}" src="1f198.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26d4" src="26d4.png"/>',fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4db}" src="1f4db.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ab}" src="1f6ab.png"/>',fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u274c" src="274c.png"/>',fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b55" src="2b55.png"/>',fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6d1}" src="1f6d1.png"/>',fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a2}" src="1f4a2.png"/>',fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2668\ufe0f" src="2668.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b7}" src="1f6b7.png"/>',fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6af}" src="1f6af.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b3}" src="1f6b3.png"/>',fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b1}" src="1f6b1.png"/>',fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51e}" src="1f51e.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f5}" src="1f4f5.png"/>',fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2757" src="2757.png"/>',fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2755" src="2755.png"/>',fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2753" src="2753.png"/>',fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2754" src="2754.png"/>',fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u203c\ufe0f" src="203c.png"/>',fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2049\ufe0f" src="2049.png"/>',fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f505}" src="1f505.png"/>',fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f506}" src="1f506.png"/>',fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f531}" src="1f531.png"/>',fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u269c" src="269c.png"/>',fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u303d\ufe0f" src="303d.png"/>',fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26a0\ufe0f" src="26a0.png"/>',fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b8}" src="1f6b8.png"/>',fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f530}" src="1f530.png"/>',fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267b\ufe0f" src="267b.png"/>',fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f22f}" src="1f22f.png"/>',fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b9}" src="1f4b9.png"/>',fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2747\ufe0f" src="2747.png"/>',fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2733\ufe0f" src="2733.png"/>',fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u274e" src="274e.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2705" src="2705.png"/>',fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4a0}" src="1f4a0.png"/>',fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f300}" src="1f300.png"/>',fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27bf" src="27bf.png"/>',fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f310}" src="1f310.png"/>',fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u24c2\ufe0f" src="24c2.png"/>',fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3e7}" src="1f3e7.png"/>',fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f202}\ufe0f" src="1f202.png"/>',fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c2}" src="1f6c2.png"/>',fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c3}" src="1f6c3.png"/>',fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c4}" src="1f6c4.png"/>',fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6c5}" src="1f6c5.png"/>',fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267f" src="267f.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ad}" src="1f6ad.png"/>',fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6be}" src="1f6be.png"/>',fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f17f}\ufe0f" src="1f17f.png"/>',fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b0}" src="1f6b0.png"/>',fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6b9}" src="1f6b9.png"/>',fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ba}" src="1f6ba.png"/>',fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6bc}" src="1f6bc.png"/>',fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6bb}" src="1f6bb.png"/>',fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f6ae}" src="1f6ae.png"/>',fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3a6}" src="1f3a6.png"/>',fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4f6}" src="1f4f6.png"/>',fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f201}" src="1f201.png"/>',fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f196}" src="1f196.png"/>',fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f197}" src="1f197.png"/>',fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f199}" src="1f199.png"/>',fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f192}" src="1f192.png"/>',fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f195}" src="1f195.png"/>',fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f193}" src="1f193.png"/>',fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="0\ufe0f\u20e3" src="30-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="1\ufe0f\u20e3" src="31-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="2\ufe0f\u20e3" src="32-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="3\ufe0f\u20e3" src="33-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="4\ufe0f\u20e3" src="34-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="5\ufe0f\u20e3" src="35-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="6\ufe0f\u20e3" src="36-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="7\ufe0f\u20e3" src="37-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="8\ufe0f\u20e3" src="38-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="9\ufe0f\u20e3" src="39-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51f}" src="1f51f.png"/>',fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="*\u20e3" src="2a-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23cf\ufe0f" src="23cf.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25b6\ufe0f" src="25b6.png"/>',fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f8" src="23f8.png"/>',fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ed" src="23ed.png"/>',fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23f9" src="23f9.png"/>',fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23fa" src="23fa.png"/>',fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ef" src="23ef.png"/>',fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ee" src="23ee.png"/>',fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23e9" src="23e9.png"/>',fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ea" src="23ea.png"/>',fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f500}" src="1f500.png"/>',fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f501}" src="1f501.png"/>',fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f502}" src="1f502.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25c0\ufe0f" src="25c0.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f53c}" src="1f53c.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f53d}" src="1f53d.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23eb" src="23eb.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u23ec" src="23ec.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27a1\ufe0f" src="27a1.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b05\ufe0f" src="2b05.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b06\ufe0f" src="2b06.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b07\ufe0f" src="2b07.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2197\ufe0f" src="2197.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2198\ufe0f" src="2198.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2199\ufe0f" src="2199.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2196\ufe0f" src="2196.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2195\ufe0f" src="2195.png"/>',fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2194\ufe0f" src="2194.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f504}" src="1f504.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u21aa\ufe0f" src="21aa.png"/>',fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u21a9\ufe0f" src="21a9.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2934\ufe0f" src="2934.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2935\ufe0f" src="2935.png"/>',fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="#\ufe0f\u20e3" src="23-20e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2139\ufe0f" src="2139.png"/>',fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f524}" src="1f524.png"/>',fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f521}" src="1f521.png"/>',fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f520}" src="1f520.png"/>',fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f523}" src="1f523.png"/>',fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b5}" src="1f3b5.png"/>',fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b6}" src="1f3b6.png"/>',fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u3030\ufe0f" src="3030.png"/>',fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u27b0" src="27b0.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2714\ufe0f" src="2714.png"/>',fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f503}" src="1f503.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2795" src="2795.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2796" src="2796.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2797" src="2797.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2716\ufe0f" src="2716.png"/>',fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u267e" src="267e.png"/>',fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b2}" src="1f4b2.png"/>',fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4b1}" src="1f4b1.png"/>',fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\xa9\ufe0f" src="a9.png"/>',fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\xae\ufe0f" src="ae.png"/>',fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2122\ufe0f" src="2122.png"/>',fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51a}" src="1f51a.png"/>',fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f519}" src="1f519.png"/>',fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51b}" src="1f51b.png"/>',fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51d}" src="1f51d.png"/>',fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f51c}" src="1f51c.png"/>',fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2611\ufe0f" src="2611.png"/>',fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f518}" src="1f518.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26aa" src="26aa.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u26ab" src="26ab.png"/>',fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f534}" src="1f534.png"/>',fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f535}" src="1f535.png"/>',fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f538}" src="1f538.png"/>',fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f539}" src="1f539.png"/>',fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f536}" src="1f536.png"/>',fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f537}" src="1f537.png"/>',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f53a}" src="1f53a.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25aa\ufe0f" src="25aa.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25ab\ufe0f" src="25ab.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b1b" src="2b1b.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2b1c" src="2b1c.png"/>',fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f53b}" src="1f53b.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fc\ufe0f" src="25fc.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fb\ufe0f" src="25fb.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fe" src="25fe.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u25fd" src="25fd.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f532}" src="1f532.png"/>',fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f533}" src="1f533.png"/>',fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f508}" src="1f508.png"/>',fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f509}" src="1f509.png"/>',fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f50a}" src="1f50a.png"/>',fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f507}" src="1f507.png"/>',fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e3}" src="1f4e3.png"/>',fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4e2}" src="1f4e2.png"/>',fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f514}" src="1f514.png"/>',fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f515}" src="1f515.png"/>',fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f0cf}" src="1f0cf.png"/>',fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f004}" src="1f004.png"/>',fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2660\ufe0f" src="2660.png"/>',fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2663\ufe0f" src="2663.png"/>',fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2665\ufe0f" src="2665.png"/>',fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u2666\ufe0f" src="2666.png"/>',fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3b4}" src="1f3b4.png"/>',fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ad}" src="1f4ad.png"/>',fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5ef}" src="1f5ef.png"/>',fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f4ac}" src="1f4ac.png"/>',fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f5e8}" src="1f5e8.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f550}" src="1f550.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f551}" src="1f551.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f552}" src="1f552.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f553}" src="1f553.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f554}" src="1f554.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f555}" src="1f555.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f556}" src="1f556.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f557}" src="1f557.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f558}" src="1f558.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f559}" src="1f559.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55a}" src="1f55a.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55b}" src="1f55b.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55c}" src="1f55c.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55d}" src="1f55d.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55e}" src="1f55e.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f55f}" src="1f55f.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f560}" src="1f560.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f561}" src="1f561.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f562}" src="1f562.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f563}" src="1f563.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f564}" src="1f564.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f565}" src="1f565.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f566}" src="1f566.png"/>',fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f567}" src="1f567.png"/>',fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1eb}" src="1f1e6-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1fd}" src="1f1e6-1f1fd.png"/>',fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f1}" src="1f1e6-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1ff}" src="1f1e9-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f8}" src="1f1e6-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1e9}" src="1f1e6-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f4}" src="1f1e6-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1ee}" src="1f1e6-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f6}" src="1f1e6-1f1f6.png"/>',fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1ec}" src="1f1e6-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f7}" src="1f1e6-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f2}" src="1f1e6-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1fc}" src="1f1e6-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1fa}" src="1f1e6-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1f9}" src="1f1e6-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1ff}" src="1f1e6-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f8}" src="1f1e7-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ed}" src="1f1e7-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1e9}" src="1f1e7-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1e7}" src="1f1e7-1f1e7.png"/>',fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1fe}" src="1f1e7-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ea}" src="1f1e7-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ff}" src="1f1e7-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ef}" src="1f1e7-1f1ef.png"/>',fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f2}" src="1f1e7-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f9}" src="1f1e7-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f4}" src="1f1e7-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f6}" src="1f1e7-1f1f6.png"/>',fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1e6}" src="1f1e7-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1fc}" src="1f1e7-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f7}" src="1f1e7-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f4}" src="1f1ee-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1ec}" src="1f1fb-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f3}" src="1f1e7-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ec}" src="1f1e7-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1eb}" src="1f1e7-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1ee}" src="1f1e7-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1fb}" src="1f1e8-1f1fb.png"/>',fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1ed}" src="1f1f0-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f2}" src="1f1e8-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1e6}" src="1f1e8-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1e8}" src="1f1ee-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1fe}" src="1f1f0-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1eb}" src="1f1e8-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1e9}" src="1f1f9-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f1}" src="1f1e8-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f3}" src="1f1e8-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1fd}" src="1f1e8-1f1fd.png"/>',fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1e8}" src="1f1e8-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f4}" src="1f1e8-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1f2}" src="1f1f0-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1ec}" src="1f1e8-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1e9}" src="1f1e8-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f0}" src="1f1e8-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1f7}" src="1f1e8-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ed}\u{1f1f7}" src="1f1ed-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1fa}" src="1f1e8-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1fc}" src="1f1e8-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1fe}" src="1f1e8-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1ff}" src="1f1e8-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1f0}" src="1f1e9-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1ef}" src="1f1e9-1f1ef.png"/>',fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1f2}" src="1f1e9-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1f4}" src="1f1e9-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1e8}" src="1f1ea-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1ec}" src="1f1ea-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1fb}" src="1f1f8-1f1fb.png"/>',fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f6}" src="1f1ec-1f1f6.png"/>',fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1f7}" src="1f1ea-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1ea}" src="1f1ea-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1f9}" src="1f1ea-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1fa}" src="1f1ea-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1f0}" src="1f1eb-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1f4}" src="1f1eb-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1ef}" src="1f1eb-1f1ef.png"/>',fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1ee}" src="1f1eb-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1f7}" src="1f1eb-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1eb}" src="1f1ec-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1eb}" src="1f1f5-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1eb}" src="1f1f9-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1e6}" src="1f1ec-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f2}" src="1f1ec-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1ea}" src="1f1ec-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e9}\u{1f1ea}" src="1f1e9-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1ed}" src="1f1ec-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1ee}" src="1f1ec-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f7}" src="1f1ec-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f1}" src="1f1ec-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1e9}" src="1f1ec-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f5}" src="1f1ec-1f1f5.png"/>',fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1fa}" src="1f1ec-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f9}" src="1f1ec-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1ec}" src="1f1ec-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f3}" src="1f1ec-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1fc}" src="1f1ec-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1fe}" src="1f1ec-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ed}\u{1f1f9}" src="1f1ed-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ed}\u{1f1f3}" src="1f1ed-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ed}\u{1f1f0}" src="1f1ed-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ed}\u{1f1fa}" src="1f1ed-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f8}" src="1f1ee-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f3}" src="1f1ee-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1e9}" src="1f1ee-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f7}" src="1f1ee-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f6}" src="1f1ee-1f1f6.png"/>',fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1ea}" src="1f1ee-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f2}" src="1f1ee-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f1}" src="1f1ee-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ee}\u{1f1f9}" src="1f1ee-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1ee}" src="1f1e8-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ef}\u{1f1f2}" src="1f1ef-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ef}\u{1f1f5}" src="1f1ef-1f1f5.png"/>',fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ef}\u{1f1ea}" src="1f1ef-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ef}\u{1f1f4}" src="1f1ef-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1ff}" src="1f1f0-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1ea}" src="1f1f0-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1ee}" src="1f1f0-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fd}\u{1f1f0}" src="1f1fd-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1fc}" src="1f1f0-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1ec}" src="1f1f0-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1e6}" src="1f1f1-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1fb}" src="1f1f1-1f1fb.png"/>',fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1e7}" src="1f1f1-1f1e7.png"/>',fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1f8}" src="1f1f1-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1f7}" src="1f1f1-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1fe}" src="1f1f1-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1ee}" src="1f1f1-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1f9}" src="1f1f1-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1fa}" src="1f1f1-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f4}" src="1f1f2-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f0}" src="1f1f2-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1ec}" src="1f1f2-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1fc}" src="1f1f2-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1fe}" src="1f1f2-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1fb}" src="1f1f2-1f1fb.png"/>',fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f1}" src="1f1f2-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f9}" src="1f1f2-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1ed}" src="1f1f2-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f6}" src="1f1f2-1f1f6.png"/>',fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f7}" src="1f1f2-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1fa}" src="1f1f2-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fe}\u{1f1f9}" src="1f1fe-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1fd}" src="1f1f2-1f1fd.png"/>',fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1eb}\u{1f1f2}" src="1f1eb-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1e9}" src="1f1f2-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1e8}" src="1f1f2-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f3}" src="1f1f2-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1ea}" src="1f1f2-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f8}" src="1f1f2-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1e6}" src="1f1f2-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1ff}" src="1f1f2-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f2}" src="1f1f2-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1e6}" src="1f1f3-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1f7}" src="1f1f3-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1f5}" src="1f1f3-1f1f5.png"/>',fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1f1}" src="1f1f3-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1e8}" src="1f1f3-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1ff}" src="1f1f3-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1ee}" src="1f1f3-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1ea}" src="1f1f3-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1ec}" src="1f1f3-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1fa}" src="1f1f3-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1eb}" src="1f1f3-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f2}\u{1f1f5}" src="1f1f2-1f1f5.png"/>',fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1f5}" src="1f1f0-1f1f5.png"/>',fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f3}\u{1f1f4}" src="1f1f3-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f4}\u{1f1f2}" src="1f1f4-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f0}" src="1f1f5-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1fc}" src="1f1f5-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f8}" src="1f1f5-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1e6}" src="1f1f5-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1ec}" src="1f1f5-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1fe}" src="1f1f5-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1ea}" src="1f1f5-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1ed}" src="1f1f5-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f3}" src="1f1f5-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f1}" src="1f1f5-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f9}" src="1f1f5-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f7}" src="1f1f5-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f6}\u{1f1e6}" src="1f1f6-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f7}\u{1f1ea}" src="1f1f7-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f7}\u{1f1f4}" src="1f1f7-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f7}\u{1f1fa}" src="1f1f7-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f7}\u{1f1fc}" src="1f1f7-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e7}\u{1f1f1}" src="1f1e7-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1ed}" src="1f1f8-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1f3}" src="1f1f0-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1e8}" src="1f1f1-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f5}\u{1f1f2}" src="1f1f5-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1e8}" src="1f1fb-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fc}\u{1f1f8}" src="1f1fc-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f2}" src="1f1f8-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f9}" src="1f1f8-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1e6}" src="1f1f8-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f3}" src="1f1f8-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f7}\u{1f1f8}" src="1f1f7-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1e8}" src="1f1f8-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f1}" src="1f1f8-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1ec}" src="1f1f8-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1fd}" src="1f1f8-1f1fd.png"/>',fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f0}" src="1f1f8-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1ee}" src="1f1f8-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1e7}" src="1f1f8-1f1e7.png"/>',fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f4}" src="1f1f8-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ff}\u{1f1e6}" src="1f1ff-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1f8}" src="1f1ec-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f0}\u{1f1f7}" src="1f1f0-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f8}" src="1f1f8-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1f8}" src="1f1ea-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f1}\u{1f1f0}" src="1f1f1-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1e9}" src="1f1f8-1f1e9.png"/>',fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1f7}" src="1f1f8-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1ff}" src="1f1f8-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1ea}" src="1f1f8-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e8}\u{1f1ed}" src="1f1e8-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f8}\u{1f1fe}" src="1f1f8-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1fc}" src="1f1f9-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1ef}" src="1f1f9-1f1ef.png"/>',fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1ff}" src="1f1f9-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1ed}" src="1f1f9-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f1}" src="1f1f9-1f1f1.png"/>',fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1ec}" src="1f1f9-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f0}" src="1f1f9-1f1f0.png"/>',fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f4}" src="1f1f9-1f1f4.png"/>',fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f9}" src="1f1f9-1f1f9.png"/>',fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f3}" src="1f1f9-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f7}" src="1f1f9-1f1f7.png"/>',fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1f2}" src="1f1f9-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1e8}" src="1f1f9-1f1e8.png"/>',fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1f9}\u{1f1fb}" src="1f1f9-1f1fb.png"/>',fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1ec}" src="1f1fa-1f1ec.png"/>',fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1e6}" src="1f1fa-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1e6}\u{1f1ea}" src="1f1e6-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ec}\u{1f1e7}" src="1f1ec-1f1e7.png"/>',fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}" src="1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png"/>',fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}" src="1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png"/>',fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}" src="1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png"/>',fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1f8}" src="1f1fa-1f1f8.png"/>',fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1ee}" src="1f1fb-1f1ee.png"/>',fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1fe}" src="1f1fa-1f1fe.png"/>',fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1ff}" src="1f1fa-1f1ff.png"/>',fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1fa}" src="1f1fb-1f1fa.png"/>',fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1e6}" src="1f1fb-1f1e6.png"/>',fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1ea}" src="1f1fb-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fb}\u{1f1f3}" src="1f1fb-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fc}\u{1f1eb}" src="1f1fc-1f1eb.png"/>',fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ea}\u{1f1ed}" src="1f1ea-1f1ed.png"/>',fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fe}\u{1f1ea}" src="1f1fe-1f1ea.png"/>',fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ff}\u{1f1f2}" src="1f1ff-1f1f2.png"/>',fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1ff}\u{1f1fc}" src="1f1ff-1f1fc.png"/>',fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f1fa}\u{1f1f3}" src="1f1fa-1f1f3.png"/>',fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:'<img data-emoticon="true" style="width:1em;height:1em;margin:0 .05em 0 .1em;vertical-align:-.1em" draggable="false" alt="\u{1f3f4}\u200d\u2620\ufe0f" src="1f3f4-200d-2620-fe0f.png"/>',fitzpatrick_scale:!1,category:"flags"}});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js
new file mode 100644
index 0000000..88455e9
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.js
@@ -0,0 +1 @@
+window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"馃榾",fitzpatrick_scale:false,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"馃槵",fitzpatrick_scale:false,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"馃榿",fitzpatrick_scale:false,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"馃槀",fitzpatrick_scale:false,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"馃ぃ",fitzpatrick_scale:false,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"馃コ",fitzpatrick_scale:false,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"馃槂",fitzpatrick_scale:false,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"馃槃",fitzpatrick_scale:false,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"馃槄",fitzpatrick_scale:false,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"馃槅",fitzpatrick_scale:false,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"馃槆",fitzpatrick_scale:false,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"馃槈",fitzpatrick_scale:false,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"馃槉",fitzpatrick_scale:false,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"馃檪",fitzpatrick_scale:false,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"馃檭",fitzpatrick_scale:false,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"鈽猴笍",fitzpatrick_scale:false,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"馃構",fitzpatrick_scale:false,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"馃槍",fitzpatrick_scale:false,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"馃槏",fitzpatrick_scale:false,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"馃グ",fitzpatrick_scale:false,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"馃槝",fitzpatrick_scale:false,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"馃槜",fitzpatrick_scale:false,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"馃槞",fitzpatrick_scale:false,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"馃槡",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"馃槣",fitzpatrick_scale:false,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"馃お",fitzpatrick_scale:false,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"馃え",fitzpatrick_scale:false,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"馃",fitzpatrick_scale:false,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"馃槤",fitzpatrick_scale:false,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"馃槢",fitzpatrick_scale:false,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"馃",fitzpatrick_scale:false,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"馃",fitzpatrick_scale:false,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"馃槑",fitzpatrick_scale:false,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"馃ぉ",fitzpatrick_scale:false,category:"people"},clown_face:{keywords:["face"],char:"馃ぁ",fitzpatrick_scale:false,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"馃",fitzpatrick_scale:false,category:"people"},hugs:{keywords:["face","smile","hug"],char:"馃",fitzpatrick_scale:false,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"馃槒",fitzpatrick_scale:false,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"馃樁",fitzpatrick_scale:false,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"馃槓",fitzpatrick_scale:false,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"馃槕",fitzpatrick_scale:false,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"馃槖",fitzpatrick_scale:false,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"馃檮",fitzpatrick_scale:false,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"馃",fitzpatrick_scale:false,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"馃ぅ",fitzpatrick_scale:false,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"馃き",fitzpatrick_scale:false,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"馃か",fitzpatrick_scale:false,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"馃が",fitzpatrick_scale:false,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"馃く",fitzpatrick_scale:false,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"馃槼",fitzpatrick_scale:false,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"馃槥",fitzpatrick_scale:false,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"馃槦",fitzpatrick_scale:false,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"馃槧",fitzpatrick_scale:false,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"馃槨",fitzpatrick_scale:false,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"馃様",fitzpatrick_scale:false,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"馃槙",fitzpatrick_scale:false,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"馃檨",fitzpatrick_scale:false,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"鈽�",fitzpatrick_scale:false,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"馃槪",fitzpatrick_scale:false,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"馃槚",fitzpatrick_scale:false,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"馃槴",fitzpatrick_scale:false,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"馃槱",fitzpatrick_scale:false,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"馃ズ",fitzpatrick_scale:false,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"馃槫",fitzpatrick_scale:false,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"馃槷",fitzpatrick_scale:false,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"馃槺",fitzpatrick_scale:false,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"馃槰",fitzpatrick_scale:false,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"馃槹",fitzpatrick_scale:false,category:"people"},hushed:{keywords:["face","woo","shh"],char:"馃槸",fitzpatrick_scale:false,category:"people"},frowning:{keywords:["face","aw","what"],char:"馃槮",fitzpatrick_scale:false,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"馃槯",fitzpatrick_scale:false,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"馃槩",fitzpatrick_scale:false,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"馃槬",fitzpatrick_scale:false,category:"people"},drooling_face:{keywords:["face"],char:"馃い",fitzpatrick_scale:false,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"馃槳",fitzpatrick_scale:false,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"馃槗",fitzpatrick_scale:false,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"馃サ",fitzpatrick_scale:false,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"馃ザ",fitzpatrick_scale:false,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"馃槶",fitzpatrick_scale:false,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"馃樀",fitzpatrick_scale:false,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"馃槻",fitzpatrick_scale:false,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"馃",fitzpatrick_scale:false,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"馃あ",fitzpatrick_scale:false,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"馃ぇ",fitzpatrick_scale:false,category:"people"},vomiting:{keywords:["face","sick"],char:"馃ぎ",fitzpatrick_scale:false,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"馃樂",fitzpatrick_scale:false,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"馃",fitzpatrick_scale:false,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"馃",fitzpatrick_scale:false,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"馃ゴ",fitzpatrick_scale:false,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"馃槾",fitzpatrick_scale:false,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"馃挙",fitzpatrick_scale:false,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"馃挬",fitzpatrick_scale:false,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"馃槇",fitzpatrick_scale:false,category:"people"},imp:{keywords:["devil","angry","horns"],char:"馃懣",fitzpatrick_scale:false,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"馃懝",fitzpatrick_scale:false,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"馃懞",fitzpatrick_scale:false,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"馃拃",fitzpatrick_scale:false,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"馃懟",fitzpatrick_scale:false,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"馃懡",fitzpatrick_scale:false,category:"people"},robot:{keywords:["computer","machine","bot"],char:"馃",fitzpatrick_scale:false,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"馃樅",fitzpatrick_scale:false,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"馃樃",fitzpatrick_scale:false,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"馃樄",fitzpatrick_scale:false,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"馃樆",fitzpatrick_scale:false,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"馃樇",fitzpatrick_scale:false,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"馃樈",fitzpatrick_scale:false,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"馃檧",fitzpatrick_scale:false,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"馃樋",fitzpatrick_scale:false,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"馃樉",fitzpatrick_scale:false,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"馃げ",fitzpatrick_scale:true,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"馃檶",fitzpatrick_scale:true,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"馃憦",fitzpatrick_scale:true,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"馃憢",fitzpatrick_scale:true,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"馃",fitzpatrick_scale:true,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"馃憤",fitzpatrick_scale:true,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"馃憥",fitzpatrick_scale:true,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"馃憡",fitzpatrick_scale:true,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"鉁�",fitzpatrick_scale:true,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"馃",fitzpatrick_scale:true,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"馃",fitzpatrick_scale:true,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"鉁�",fitzpatrick_scale:true,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"馃憣",fitzpatrick_scale:true,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"鉁�",fitzpatrick_scale:true,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"馃",fitzpatrick_scale:true,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"馃憪",fitzpatrick_scale:true,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"馃挭",fitzpatrick_scale:true,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"馃檹",fitzpatrick_scale:true,category:"people"},foot:{keywords:["kick","stomp"],char:"馃Χ",fitzpatrick_scale:true,category:"people"},leg:{keywords:["kick","limb"],char:"馃Φ",fitzpatrick_scale:true,category:"people"},handshake:{keywords:["agreement","shake"],char:"馃",fitzpatrick_scale:false,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"鈽�",fitzpatrick_scale:true,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"馃憜",fitzpatrick_scale:true,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"馃憞",fitzpatrick_scale:true,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"馃憟",fitzpatrick_scale:true,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"馃憠",fitzpatrick_scale:true,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"馃枙",fitzpatrick_scale:true,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"馃枑",fitzpatrick_scale:true,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"馃",fitzpatrick_scale:true,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"馃",fitzpatrick_scale:true,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"馃",fitzpatrick_scale:true,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"馃枛",fitzpatrick_scale:true,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"鉁�",fitzpatrick_scale:true,category:"people"},selfie:{keywords:["camera","phone"],char:"馃こ",fitzpatrick_scale:true,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"馃拝",fitzpatrick_scale:true,category:"people"},lips:{keywords:["mouth","kiss"],char:"馃憚",fitzpatrick_scale:false,category:"people"},tooth:{keywords:["teeth","dentist"],char:"馃Ψ",fitzpatrick_scale:false,category:"people"},tongue:{keywords:["mouth","playful"],char:"馃憛",fitzpatrick_scale:false,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"馃憘",fitzpatrick_scale:true,category:"people"},nose:{keywords:["smell","sniff"],char:"馃憙",fitzpatrick_scale:true,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"馃憗",fitzpatrick_scale:false,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"馃憖",fitzpatrick_scale:false,category:"people"},brain:{keywords:["smart","intelligent"],char:"馃",fitzpatrick_scale:false,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"馃懁",fitzpatrick_scale:false,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"馃懃",fitzpatrick_scale:false,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"馃棧",fitzpatrick_scale:false,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"馃懚",fitzpatrick_scale:true,category:"people"},child:{keywords:["gender-neutral","young"],char:"馃",fitzpatrick_scale:true,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"馃懄",fitzpatrick_scale:true,category:"people"},girl:{keywords:["female","woman","teenager"],char:"馃懅",fitzpatrick_scale:true,category:"people"},adult:{keywords:["gender-neutral","person"],char:"馃",fitzpatrick_scale:true,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"馃懆",fitzpatrick_scale:true,category:"people"},woman:{keywords:["female","girls","lady"],char:"馃懇",fitzpatrick_scale:true,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"馃懕鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"馃懕",fitzpatrick_scale:true,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"馃",fitzpatrick_scale:true,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"馃",fitzpatrick_scale:true,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"馃懘",fitzpatrick_scale:true,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"馃懙",fitzpatrick_scale:true,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"馃懖",fitzpatrick_scale:true,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"馃",fitzpatrick_scale:true,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"馃懗鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"馃懗",fitzpatrick_scale:true,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"馃懏鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"馃懏",fitzpatrick_scale:true,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"馃懛鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"馃懛",fitzpatrick_scale:true,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"馃拏鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"馃拏",fitzpatrick_scale:true,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"馃暤锔忊�嶁檧锔�",fitzpatrick_scale:true,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"馃暤",fitzpatrick_scale:true,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"馃懇鈥嶁殨锔�",fitzpatrick_scale:true,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"馃懆鈥嶁殨锔�",fitzpatrick_scale:true,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"馃懇鈥嶐煂�",fitzpatrick_scale:true,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"馃懆鈥嶐煂�",fitzpatrick_scale:true,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"馃懇鈥嶐煃�",fitzpatrick_scale:true,category:"people"},man_cook:{keywords:["chef","man","human"],char:"馃懆鈥嶐煃�",fitzpatrick_scale:true,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"馃懇鈥嶐煄�",fitzpatrick_scale:true,category:"people"},man_student:{keywords:["graduate","man","human"],char:"馃懆鈥嶐煄�",fitzpatrick_scale:true,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"馃懇鈥嶐煄�",fitzpatrick_scale:true,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"馃懆鈥嶐煄�",fitzpatrick_scale:true,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"馃懇鈥嶐煆�",fitzpatrick_scale:true,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"馃懆鈥嶐煆�",fitzpatrick_scale:true,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"馃懇鈥嶐煆�",fitzpatrick_scale:true,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"馃懆鈥嶐煆�",fitzpatrick_scale:true,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"馃懇鈥嶐煉�",fitzpatrick_scale:true,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"馃懆鈥嶐煉�",fitzpatrick_scale:true,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"馃懇鈥嶐煉�",fitzpatrick_scale:true,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"馃懆鈥嶐煉�",fitzpatrick_scale:true,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"馃懇鈥嶐煍�",fitzpatrick_scale:true,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"馃懆鈥嶐煍�",fitzpatrick_scale:true,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"馃懇鈥嶐煍�",fitzpatrick_scale:true,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"馃懆鈥嶐煍�",fitzpatrick_scale:true,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"馃懇鈥嶐煄�",fitzpatrick_scale:true,category:"people"},man_artist:{keywords:["painter","man","human"],char:"馃懆鈥嶐煄�",fitzpatrick_scale:true,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"馃懇鈥嶐煔�",fitzpatrick_scale:true,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"馃懆鈥嶐煔�",fitzpatrick_scale:true,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"馃懇鈥嶁湀锔�",fitzpatrick_scale:true,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"馃懆鈥嶁湀锔�",fitzpatrick_scale:true,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"馃懇鈥嶐煔�",fitzpatrick_scale:true,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"馃懆鈥嶐煔�",fitzpatrick_scale:true,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"馃懇鈥嶁殩锔�",fitzpatrick_scale:true,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"馃懆鈥嶁殩锔�",fitzpatrick_scale:true,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"馃Ω鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"馃Ω鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"馃ざ",fitzpatrick_scale:true,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"馃巺",fitzpatrick_scale:true,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_elf:{keywords:["woman","female"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_elf:{keywords:["man","male"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_vampire:{keywords:["woman","female"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:false,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:false,category:"people"},woman_genie:{keywords:["woman","female"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:false,category:"people"},man_genie:{keywords:["man","male"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:false,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},merman:{keywords:["man","male","triton"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_fairy:{keywords:["woman","female"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_fairy:{keywords:["man","male"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"馃懠",fitzpatrick_scale:true,category:"people"},pregnant_woman:{keywords:["baby"],char:"馃ぐ",fitzpatrick_scale:true,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"馃け",fitzpatrick_scale:true,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"馃懜",fitzpatrick_scale:true,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"馃ご",fitzpatrick_scale:true,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"馃懓",fitzpatrick_scale:true,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"馃さ",fitzpatrick_scale:true,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"馃弮鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"馃弮",fitzpatrick_scale:true,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"馃毝鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"馃毝",fitzpatrick_scale:true,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"馃拑",fitzpatrick_scale:true,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"馃暫",fitzpatrick_scale:true,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"馃懐",fitzpatrick_scale:false,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"馃懐鈥嶁檪锔�",fitzpatrick_scale:false,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"馃懌",fitzpatrick_scale:false,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"馃懍",fitzpatrick_scale:false,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"馃懎",fitzpatrick_scale:false,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"馃檱鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"馃檱",fitzpatrick_scale:true,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"馃う鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"馃う鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"馃し",fitzpatrick_scale:true,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"馃し鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"馃拋",fitzpatrick_scale:true,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"馃拋鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"馃檯",fitzpatrick_scale:true,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"馃檯鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"馃檰",fitzpatrick_scale:true,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"馃檰鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"馃檵",fitzpatrick_scale:true,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"馃檵鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"馃檸",fitzpatrick_scale:true,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"馃檸鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"馃檷",fitzpatrick_scale:true,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"馃檷鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"馃拠",fitzpatrick_scale:true,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"馃拠鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"馃拞",fitzpatrick_scale:true,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"馃拞鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"馃拺",fitzpatrick_scale:false,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"馃懇鈥嶁潳锔忊�嶐煈�",fitzpatrick_scale:false,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"馃懆鈥嶁潳锔忊�嶐煈�",fitzpatrick_scale:false,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"馃拸",fitzpatrick_scale:false,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"馃懇鈥嶁潳锔忊�嶐煉嬧�嶐煈�",fitzpatrick_scale:false,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"馃懆鈥嶁潳锔忊�嶐煉嬧�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"馃應",fitzpatrick_scale:false,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"馃懆鈥嶐煈┾�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈┾�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈┾�嶐煈︹�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈┾�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"馃懇鈥嶐煈┾�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"馃懇鈥嶐煈┾�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"馃懇鈥嶐煈┾�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"馃懇鈥嶐煈┾�嶐煈︹�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"馃懇鈥嶐煈┾�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈ㄢ�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈ㄢ�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈ㄢ�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈ㄢ�嶐煈︹�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"馃懆鈥嶐煈ㄢ�嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"馃懇鈥嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"馃懇鈥嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"馃懇鈥嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"馃懇鈥嶐煈︹�嶐煈�",fitzpatrick_scale:false,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"馃懇鈥嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"馃懆鈥嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"馃懆鈥嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"馃懆鈥嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"馃懆鈥嶐煈︹�嶐煈�",fitzpatrick_scale:false,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"馃懆鈥嶐煈р�嶐煈�",fitzpatrick_scale:false,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"馃Ф",fitzpatrick_scale:false,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"馃У",fitzpatrick_scale:false,category:"people"},coat:{keywords:["jacket"],char:"馃Д",fitzpatrick_scale:false,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"馃ゼ",fitzpatrick_scale:false,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"馃憵",fitzpatrick_scale:false,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"馃憰",fitzpatrick_scale:false,category:"people"},jeans:{keywords:["fashion","shopping"],char:"馃憱",fitzpatrick_scale:false,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"馃憯",fitzpatrick_scale:false,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"馃憲",fitzpatrick_scale:false,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"馃憴",fitzpatrick_scale:false,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"馃憳",fitzpatrick_scale:false,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"馃拕",fitzpatrick_scale:false,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"馃拫",fitzpatrick_scale:false,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"馃懀",fitzpatrick_scale:false,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"馃タ",fitzpatrick_scale:false,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"馃憼",fitzpatrick_scale:false,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"馃憽",fitzpatrick_scale:false,category:"people"},boot:{keywords:["shoes","fashion"],char:"馃憿",fitzpatrick_scale:false,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"馃憺",fitzpatrick_scale:false,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"馃憻",fitzpatrick_scale:false,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"馃ゾ",fitzpatrick_scale:false,category:"people"},socks:{keywords:["stockings","clothes"],char:"馃Е",fitzpatrick_scale:false,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"馃Г",fitzpatrick_scale:false,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"馃В",fitzpatrick_scale:false,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"馃憭",fitzpatrick_scale:false,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"馃帺",fitzpatrick_scale:false,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"馃Б",fitzpatrick_scale:false,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"鉀�",fitzpatrick_scale:false,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"馃帗",fitzpatrick_scale:false,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"馃憫",fitzpatrick_scale:false,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"馃帓",fitzpatrick_scale:false,category:"people"},luggage:{keywords:["packing","travel"],char:"馃С",fitzpatrick_scale:false,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"馃憹",fitzpatrick_scale:false,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"馃憶",fitzpatrick_scale:false,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"馃憸",fitzpatrick_scale:false,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"馃捈",fitzpatrick_scale:false,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"馃憮",fitzpatrick_scale:false,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"馃暥",fitzpatrick_scale:false,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"馃ソ",fitzpatrick_scale:false,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"馃拲",fitzpatrick_scale:false,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"馃寕",fitzpatrick_scale:false,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"馃惗",fitzpatrick_scale:false,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"馃惐",fitzpatrick_scale:false,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"馃惌",fitzpatrick_scale:false,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"馃惞",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"馃惏",fitzpatrick_scale:false,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"馃惢",fitzpatrick_scale:false,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"馃惣",fitzpatrick_scale:false,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"馃惃",fitzpatrick_scale:false,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"馃惎",fitzpatrick_scale:false,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"馃惍",fitzpatrick_scale:false,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"馃惙",fitzpatrick_scale:false,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"馃惤",fitzpatrick_scale:false,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"馃惛",fitzpatrick_scale:false,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"馃悪",fitzpatrick_scale:false,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"馃惖",fitzpatrick_scale:false,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"馃檲",fitzpatrick_scale:false,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"馃檳",fitzpatrick_scale:false,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"馃檴",fitzpatrick_scale:false,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"馃悞",fitzpatrick_scale:false,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"馃悢",fitzpatrick_scale:false,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"馃惂",fitzpatrick_scale:false,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"馃惁",fitzpatrick_scale:false,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"馃悿",fitzpatrick_scale:false,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"馃悾",fitzpatrick_scale:false,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"馃惀",fitzpatrick_scale:false,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"馃惡",fitzpatrick_scale:false,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"馃悧",fitzpatrick_scale:false,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"馃惔",fitzpatrick_scale:false,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"馃悵",fitzpatrick_scale:false,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"馃悰",fitzpatrick_scale:false,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"馃悓",fitzpatrick_scale:false,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"馃悶",fitzpatrick_scale:false,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"馃悳",fitzpatrick_scale:false,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"馃暦",fitzpatrick_scale:false,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"馃悕",fitzpatrick_scale:false,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"馃悽",fitzpatrick_scale:false,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"馃悹",fitzpatrick_scale:false,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"馃悷",fitzpatrick_scale:false,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"馃悺",fitzpatrick_scale:false,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"馃惉",fitzpatrick_scale:false,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"馃惓",fitzpatrick_scale:false,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"馃悑",fitzpatrick_scale:false,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"馃悐",fitzpatrick_scale:false,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"馃悊",fitzpatrick_scale:false,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"馃悈",fitzpatrick_scale:false,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"馃悆",fitzpatrick_scale:false,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"馃悅",fitzpatrick_scale:false,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"馃悇",fitzpatrick_scale:false,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"馃惇",fitzpatrick_scale:false,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"馃惈",fitzpatrick_scale:false,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"馃悩",fitzpatrick_scale:false,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"馃悙",fitzpatrick_scale:false,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"馃悘",fitzpatrick_scale:false,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"馃悜",fitzpatrick_scale:false,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"馃悗",fitzpatrick_scale:false,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"馃悥",fitzpatrick_scale:false,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"馃悁",fitzpatrick_scale:false,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"馃悂",fitzpatrick_scale:false,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"馃悡",fitzpatrick_scale:false,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"馃晩",fitzpatrick_scale:false,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"馃悤",fitzpatrick_scale:false,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"馃惄",fitzpatrick_scale:false,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"馃悎",fitzpatrick_scale:false,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"馃悋",fitzpatrick_scale:false,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"馃惪",fitzpatrick_scale:false,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"馃Α",fitzpatrick_scale:false,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"馃Β",fitzpatrick_scale:false,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"馃惥",fitzpatrick_scale:false,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"馃悏",fitzpatrick_scale:false,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"馃惒",fitzpatrick_scale:false,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"馃尩",fitzpatrick_scale:false,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"馃巹",fitzpatrick_scale:false,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"馃尣",fitzpatrick_scale:false,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"馃尦",fitzpatrick_scale:false,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"馃尨",fitzpatrick_scale:false,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"馃尡",fitzpatrick_scale:false,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"馃尶",fitzpatrick_scale:false,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"鈽�",fitzpatrick_scale:false,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"馃崁",fitzpatrick_scale:false,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"馃帊",fitzpatrick_scale:false,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"馃帇",fitzpatrick_scale:false,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"馃崈",fitzpatrick_scale:false,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"馃崅",fitzpatrick_scale:false,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"馃崄",fitzpatrick_scale:false,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"馃尵",fitzpatrick_scale:false,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"馃尯",fitzpatrick_scale:false,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"馃尰",fitzpatrick_scale:false,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"馃尮",fitzpatrick_scale:false,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"馃",fitzpatrick_scale:false,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"馃尫",fitzpatrick_scale:false,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"馃尲",fitzpatrick_scale:false,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"馃尭",fitzpatrick_scale:false,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"馃拹",fitzpatrick_scale:false,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"馃崉",fitzpatrick_scale:false,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"馃尠",fitzpatrick_scale:false,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"馃巸",fitzpatrick_scale:false,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"馃悮",fitzpatrick_scale:false,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"馃暩",fitzpatrick_scale:false,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"馃寧",fitzpatrick_scale:false,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"馃實",fitzpatrick_scale:false,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"馃審",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"馃寱",fitzpatrick_scale:false,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"馃寲",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寳",fitzpatrick_scale:false,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寴",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寫",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寬",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寭",fitzpatrick_scale:false,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"馃寯",fitzpatrick_scale:false,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寶",fitzpatrick_scale:false,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃対",fitzpatrick_scale:false,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寷",fitzpatrick_scale:false,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"馃寽",fitzpatrick_scale:false,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"馃尀",fitzpatrick_scale:false,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"馃寵",fitzpatrick_scale:false,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"猸�",fitzpatrick_scale:false,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"馃専",fitzpatrick_scale:false,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"馃挮",fitzpatrick_scale:false,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"鉁�",fitzpatrick_scale:false,category:"animals_and_nature"},comet:{keywords:["space"],char:"鈽�",fitzpatrick_scale:false,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"鈽�锔�",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"馃尋",fitzpatrick_scale:false,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"鉀�",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"馃尌",fitzpatrick_scale:false,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"馃對",fitzpatrick_scale:false,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"鈽侊笍",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"馃導",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"鉀�",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"馃尒",fitzpatrick_scale:false,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"鈿�",fitzpatrick_scale:false,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"馃敟",fitzpatrick_scale:false,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"馃挜",fitzpatrick_scale:false,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"鉂勶笍",fitzpatrick_scale:false,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"馃尐",fitzpatrick_scale:false,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"鉀�",fitzpatrick_scale:false,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"鈽�",fitzpatrick_scale:false,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"馃尙",fitzpatrick_scale:false,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"馃挩",fitzpatrick_scale:false,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"馃尓",fitzpatrick_scale:false,category:"animals_and_nature"},fog:{keywords:["weather"],char:"馃尗",fitzpatrick_scale:false,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"鈽�",fitzpatrick_scale:false,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"鈽�",fitzpatrick_scale:false,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"馃挧",fitzpatrick_scale:false,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"馃挦",fitzpatrick_scale:false,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"馃寠",fitzpatrick_scale:false,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"馃崗",fitzpatrick_scale:false,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"馃崕",fitzpatrick_scale:false,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"馃崘",fitzpatrick_scale:false,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"馃崐",fitzpatrick_scale:false,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"馃崑",fitzpatrick_scale:false,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"馃崒",fitzpatrick_scale:false,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"馃崏",fitzpatrick_scale:false,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"馃崌",fitzpatrick_scale:false,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"馃崜",fitzpatrick_scale:false,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"馃崍",fitzpatrick_scale:false,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"馃崚",fitzpatrick_scale:false,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"馃崙",fitzpatrick_scale:false,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"馃崓",fitzpatrick_scale:false,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"馃ゥ",fitzpatrick_scale:false,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"馃キ",fitzpatrick_scale:false,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"馃ウ",fitzpatrick_scale:false,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"馃崊",fitzpatrick_scale:false,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"馃崋",fitzpatrick_scale:false,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"馃尪",fitzpatrick_scale:false,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"馃尳",fitzpatrick_scale:false,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"馃ガ",fitzpatrick_scale:false,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"馃崰",fitzpatrick_scale:false,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"馃嵂",fitzpatrick_scale:false,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"馃崬",fitzpatrick_scale:false,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"馃ク",fitzpatrick_scale:false,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"馃エ",fitzpatrick_scale:false,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"馃ォ",fitzpatrick_scale:false,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"馃崡",fitzpatrick_scale:false,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"馃崠",fitzpatrick_scale:false,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"馃Υ",fitzpatrick_scale:false,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"馃崵",fitzpatrick_scale:false,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"馃嵆",fitzpatrick_scale:false,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"馃崝",fitzpatrick_scale:false,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"馃崯",fitzpatrick_scale:false,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"馃尛",fitzpatrick_scale:false,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"馃崟",fitzpatrick_scale:false,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"馃オ",fitzpatrick_scale:false,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"馃カ",fitzpatrick_scale:false,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"馃崫",fitzpatrick_scale:false,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"馃尞",fitzpatrick_scale:false,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"馃尟",fitzpatrick_scale:false,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"馃崪",fitzpatrick_scale:false,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"馃嵅",fitzpatrick_scale:false,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"馃崶",fitzpatrick_scale:false,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"馃崳",fitzpatrick_scale:false,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"馃嵄",fitzpatrick_scale:false,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"馃崨",fitzpatrick_scale:false,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"馃崣",fitzpatrick_scale:false,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"馃崥",fitzpatrick_scale:false,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"馃崢",fitzpatrick_scale:false,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"馃崲",fitzpatrick_scale:false,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"馃崱",fitzpatrick_scale:false,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"馃崸",fitzpatrick_scale:false,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"馃崹",fitzpatrick_scale:false,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"馃崷",fitzpatrick_scale:false,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"馃ェ",fitzpatrick_scale:false,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"馃嵃",fitzpatrick_scale:false,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"馃ギ",fitzpatrick_scale:false,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"馃巶",fitzpatrick_scale:false,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"馃嵁",fitzpatrick_scale:false,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"馃崿",fitzpatrick_scale:false,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"馃嵀",fitzpatrick_scale:false,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"馃崼",fitzpatrick_scale:false,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"馃嵖",fitzpatrick_scale:false,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"馃崺",fitzpatrick_scale:false,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"馃崻",fitzpatrick_scale:false,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"馃嵑",fitzpatrick_scale:false,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"馃嵒",fitzpatrick_scale:false,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"馃嵎",fitzpatrick_scale:false,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"馃嵏",fitzpatrick_scale:false,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"馃嵐",fitzpatrick_scale:false,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"馃嵕",fitzpatrick_scale:false,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"馃嵍",fitzpatrick_scale:false,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"馃嵉",fitzpatrick_scale:false,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"馃イ",fitzpatrick_scale:false,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"鈽�",fitzpatrick_scale:false,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"馃嵓",fitzpatrick_scale:false,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"馃",fitzpatrick_scale:false,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"馃嵈",fitzpatrick_scale:false,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"馃嵔",fitzpatrick_scale:false,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"馃ィ",fitzpatrick_scale:false,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"馃ァ",fitzpatrick_scale:false,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"馃ア",fitzpatrick_scale:false,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"鈿�",fitzpatrick_scale:false,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"馃弨",fitzpatrick_scale:false,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"馃張",fitzpatrick_scale:false,category:"activity"},baseball:{keywords:["sports","balls"],char:"鈿�",fitzpatrick_scale:false,category:"activity"},softball:{keywords:["sports","balls"],char:"馃",fitzpatrick_scale:false,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"馃幘",fitzpatrick_scale:false,category:"activity"},volleyball:{keywords:["sports","balls"],char:"馃彁",fitzpatrick_scale:false,category:"activity"},rugby_football:{keywords:["sports","team"],char:"馃弶",fitzpatrick_scale:false,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"馃",fitzpatrick_scale:false,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"馃幈",fitzpatrick_scale:false,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"鉀�",fitzpatrick_scale:false,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"馃弻锔忊�嶁檧锔�",fitzpatrick_scale:false,category:"activity"},golfing_man:{keywords:["sports","business"],char:"馃弻",fitzpatrick_scale:true,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"馃彄",fitzpatrick_scale:false,category:"activity"},badminton:{keywords:["sports"],char:"馃徃",fitzpatrick_scale:false,category:"activity"},goal_net:{keywords:["sports"],char:"馃",fitzpatrick_scale:false,category:"activity"},ice_hockey:{keywords:["sports"],char:"馃彃",fitzpatrick_scale:false,category:"activity"},field_hockey:{keywords:["sports"],char:"馃彂",fitzpatrick_scale:false,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"馃",fitzpatrick_scale:false,category:"activity"},cricket:{keywords:["sports"],char:"馃弿",fitzpatrick_scale:false,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"馃幙",fitzpatrick_scale:false,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"鉀�",fitzpatrick_scale:false,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"馃弬",fitzpatrick_scale:true,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"馃ず",fitzpatrick_scale:false,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"馃ぜ鈥嶁檧锔�",fitzpatrick_scale:false,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"馃ぜ鈥嶁檪锔�",fitzpatrick_scale:false,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"馃じ鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"馃じ鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"馃ぞ鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},man_playing_handball:{keywords:["sports"],char:"馃ぞ鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},ice_skate:{keywords:["sports"],char:"鉀�",fitzpatrick_scale:false,category:"activity"},curling_stone:{keywords:["sports"],char:"馃",fitzpatrick_scale:false,category:"activity"},skateboard:{keywords:["board"],char:"馃浌",fitzpatrick_scale:false,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"馃浄",fitzpatrick_scale:false,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"馃徆",fitzpatrick_scale:false,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"馃帲",fitzpatrick_scale:false,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"馃",fitzpatrick_scale:false,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"馃",fitzpatrick_scale:false,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"馃殻鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"馃殻",fitzpatrick_scale:true,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"馃強鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"馃強",fitzpatrick_scale:true,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"馃そ鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"馃そ鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"馃鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"馃鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"馃弰鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"馃弰",fitzpatrick_scale:true,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"馃泙",fitzpatrick_scale:true,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"鉀癸笍鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},basketball_man:{keywords:["sports","human"],char:"鉀�",fitzpatrick_scale:true,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"馃弸锔忊�嶁檧锔�",fitzpatrick_scale:true,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"馃弸",fitzpatrick_scale:true,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"馃毚鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"馃毚",fitzpatrick_scale:true,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"馃毜鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"馃毜",fitzpatrick_scale:true,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"馃弴",fitzpatrick_scale:true,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"馃暣",fitzpatrick_scale:true,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"馃弳",fitzpatrick_scale:false,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"馃幗",fitzpatrick_scale:false,category:"activity"},medal_sports:{keywords:["award","winning"],char:"馃弲",fitzpatrick_scale:false,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"馃帠",fitzpatrick_scale:false,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"馃",fitzpatrick_scale:false,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"馃",fitzpatrick_scale:false,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"馃",fitzpatrick_scale:false,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"馃帡",fitzpatrick_scale:false,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"馃彽",fitzpatrick_scale:false,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"馃帿",fitzpatrick_scale:false,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"馃師",fitzpatrick_scale:false,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"馃幁",fitzpatrick_scale:false,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"馃帹",fitzpatrick_scale:false,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"馃帾",fitzpatrick_scale:false,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"馃す鈥嶁檧锔�",fitzpatrick_scale:true,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"馃す鈥嶁檪锔�",fitzpatrick_scale:true,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"馃帳",fitzpatrick_scale:false,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"馃帶",fitzpatrick_scale:false,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"馃幖",fitzpatrick_scale:false,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"馃幑",fitzpatrick_scale:false,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"馃",fitzpatrick_scale:false,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"馃幏",fitzpatrick_scale:false,category:"activity"},trumpet:{keywords:["music","brass"],char:"馃幒",fitzpatrick_scale:false,category:"activity"},guitar:{keywords:["music","instrument"],char:"馃幐",fitzpatrick_scale:false,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"馃幓",fitzpatrick_scale:false,category:"activity"},clapper:{keywords:["movie","film","record"],char:"馃幀",fitzpatrick_scale:false,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"馃幃",fitzpatrick_scale:false,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"馃懢",fitzpatrick_scale:false,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"馃幆",fitzpatrick_scale:false,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"馃幉",fitzpatrick_scale:false,category:"activity"},chess_pawn:{keywords:["expendable"],char:"鈾�",fitzpatrick_scale:false,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"馃幇",fitzpatrick_scale:false,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"馃З",fitzpatrick_scale:false,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"馃幊",fitzpatrick_scale:false,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"馃殫",fitzpatrick_scale:false,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"馃殨",fitzpatrick_scale:false,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"馃殭",fitzpatrick_scale:false,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"馃殞",fitzpatrick_scale:false,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"馃殠",fitzpatrick_scale:false,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"馃弾",fitzpatrick_scale:false,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"馃殦",fitzpatrick_scale:false,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"馃殤",fitzpatrick_scale:false,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"馃殥",fitzpatrick_scale:false,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"馃殣",fitzpatrick_scale:false,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"馃殮",fitzpatrick_scale:false,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"馃殯",fitzpatrick_scale:false,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"馃殰",fitzpatrick_scale:false,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"馃洿",fitzpatrick_scale:false,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"馃弽",fitzpatrick_scale:false,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"馃毑",fitzpatrick_scale:false,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"馃浀",fitzpatrick_scale:false,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"馃毃",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"馃殧",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"馃殟",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"馃殬",fitzpatrick_scale:false,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"馃殩",fitzpatrick_scale:false,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"馃殹",fitzpatrick_scale:false,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"馃殸",fitzpatrick_scale:false,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"馃殶",fitzpatrick_scale:false,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"馃殐",fitzpatrick_scale:false,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"馃殝",fitzpatrick_scale:false,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"馃殱",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"馃殑",fitzpatrick_scale:false,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"馃殔",fitzpatrick_scale:false,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"馃殘",fitzpatrick_scale:false,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"馃殲",fitzpatrick_scale:false,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"馃殏",fitzpatrick_scale:false,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"馃殕",fitzpatrick_scale:false,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"馃殗",fitzpatrick_scale:false,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"馃殜",fitzpatrick_scale:false,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"馃殙",fitzpatrick_scale:false,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"馃浉",fitzpatrick_scale:false,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"馃殎",fitzpatrick_scale:false,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"馃洨",fitzpatrick_scale:false,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"鉁堬笍",fitzpatrick_scale:false,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"馃洬",fitzpatrick_scale:false,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"馃洭",fitzpatrick_scale:false,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"馃洢",fitzpatrick_scale:false,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"馃殼",fitzpatrick_scale:false,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"馃洺",fitzpatrick_scale:false,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"馃殌",fitzpatrick_scale:false,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"馃洶",fitzpatrick_scale:false,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"馃捄",fitzpatrick_scale:false,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"馃浂",fitzpatrick_scale:false,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"鈿�",fitzpatrick_scale:false,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"馃毀",fitzpatrick_scale:false,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"馃殢",fitzpatrick_scale:false,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"馃殾",fitzpatrick_scale:false,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"馃殽",fitzpatrick_scale:false,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"馃弫",fitzpatrick_scale:false,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"馃殺",fitzpatrick_scale:false,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"馃帯",fitzpatrick_scale:false,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"馃帰",fitzpatrick_scale:false,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"馃帬",fitzpatrick_scale:false,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"馃彈",fitzpatrick_scale:false,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"馃寔",fitzpatrick_scale:false,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"馃椉",fitzpatrick_scale:false,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"馃彮",fitzpatrick_scale:false,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"馃帒",fitzpatrick_scale:false,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"馃彅",fitzpatrick_scale:false,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"馃椈",fitzpatrick_scale:false,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"馃寢",fitzpatrick_scale:false,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"馃椌",fitzpatrick_scale:false,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"馃彆",fitzpatrick_scale:false,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"馃彏",fitzpatrick_scale:false,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"馃洠",fitzpatrick_scale:false,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"馃洡",fitzpatrick_scale:false,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"馃寘",fitzpatrick_scale:false,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"馃寗",fitzpatrick_scale:false,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"馃彍",fitzpatrick_scale:false,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"馃彇",fitzpatrick_scale:false,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"馃彎",fitzpatrick_scale:false,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"馃寚",fitzpatrick_scale:false,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"馃寙",fitzpatrick_scale:false,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"馃彊",fitzpatrick_scale:false,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"馃寖",fitzpatrick_scale:false,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"馃寜",fitzpatrick_scale:false,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"馃寣",fitzpatrick_scale:false,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"馃尃",fitzpatrick_scale:false,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"馃巼",fitzpatrick_scale:false,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"馃巻",fitzpatrick_scale:false,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"馃寛",fitzpatrick_scale:false,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"馃彉",fitzpatrick_scale:false,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"馃彴",fitzpatrick_scale:false,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"馃彲",fitzpatrick_scale:false,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"馃彑",fitzpatrick_scale:false,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"馃椊",fitzpatrick_scale:false,category:"travel_and_places"},house:{keywords:["building","home"],char:"馃彔",fitzpatrick_scale:false,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"馃彙",fitzpatrick_scale:false,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"馃彋",fitzpatrick_scale:false,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"馃彚",fitzpatrick_scale:false,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"馃彫",fitzpatrick_scale:false,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"馃彛",fitzpatrick_scale:false,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"馃彜",fitzpatrick_scale:false,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"馃彞",fitzpatrick_scale:false,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"馃彟",fitzpatrick_scale:false,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"馃彣",fitzpatrick_scale:false,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"馃彧",fitzpatrick_scale:false,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"馃彨",fitzpatrick_scale:false,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"馃彥",fitzpatrick_scale:false,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"馃拻",fitzpatrick_scale:false,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"馃彌",fitzpatrick_scale:false,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"馃晫",fitzpatrick_scale:false,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"馃晬",fitzpatrick_scale:false,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"馃晪",fitzpatrick_scale:false,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"鉀�",fitzpatrick_scale:false,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"鈱�",fitzpatrick_scale:false,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"馃摫",fitzpatrick_scale:false,category:"objects"},calling:{keywords:["iphone","incoming"],char:"馃摬",fitzpatrick_scale:false,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"馃捇",fitzpatrick_scale:false,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"鈱�",fitzpatrick_scale:false,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"馃枼",fitzpatrick_scale:false,category:"objects"},printer:{keywords:["paper","ink"],char:"馃枿",fitzpatrick_scale:false,category:"objects"},computer_mouse:{keywords:["click"],char:"馃柋",fitzpatrick_scale:false,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"馃柌",fitzpatrick_scale:false,category:"objects"},joystick:{keywords:["game","play"],char:"馃暪",fitzpatrick_scale:false,category:"objects"},clamp:{keywords:["tool"],char:"馃棞",fitzpatrick_scale:false,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"馃捊",fitzpatrick_scale:false,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"馃捑",fitzpatrick_scale:false,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"馃捒",fitzpatrick_scale:false,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"馃搥",fitzpatrick_scale:false,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"馃摷",fitzpatrick_scale:false,category:"objects"},camera:{keywords:["gadgets","photography"],char:"馃摲",fitzpatrick_scale:false,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"馃摳",fitzpatrick_scale:false,category:"objects"},video_camera:{keywords:["film","record"],char:"馃摴",fitzpatrick_scale:false,category:"objects"},movie_camera:{keywords:["film","record"],char:"馃帴",fitzpatrick_scale:false,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"馃摻",fitzpatrick_scale:false,category:"objects"},film_strip:{keywords:["movie"],char:"馃帪",fitzpatrick_scale:false,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"馃摓",fitzpatrick_scale:false,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"鈽庯笍",fitzpatrick_scale:false,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"馃摕",fitzpatrick_scale:false,category:"objects"},fax:{keywords:["communication","technology"],char:"馃摖",fitzpatrick_scale:false,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"馃摵",fitzpatrick_scale:false,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"馃摶",fitzpatrick_scale:false,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"馃帣",fitzpatrick_scale:false,category:"objects"},level_slider:{keywords:["scale"],char:"馃帤",fitzpatrick_scale:false,category:"objects"},control_knobs:{keywords:["dial"],char:"馃帥",fitzpatrick_scale:false,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"馃Л",fitzpatrick_scale:false,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"鈴�",fitzpatrick_scale:false,category:"objects"},timer_clock:{keywords:["alarm"],char:"鈴�",fitzpatrick_scale:false,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"鈴�",fitzpatrick_scale:false,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"馃暟",fitzpatrick_scale:false,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"鈴�",fitzpatrick_scale:false,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"鈱�",fitzpatrick_scale:false,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"馃摗",fitzpatrick_scale:false,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"馃攱",fitzpatrick_scale:false,category:"objects"},electric_plug:{keywords:["charger","power"],char:"馃攲",fitzpatrick_scale:false,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"馃挕",fitzpatrick_scale:false,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"馃敠",fitzpatrick_scale:false,category:"objects"},candle:{keywords:["fire","wax"],char:"馃暞",fitzpatrick_scale:false,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"馃Н",fitzpatrick_scale:false,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"馃棏",fitzpatrick_scale:false,category:"objects"},oil_drum:{keywords:["barrell"],char:"馃洟",fitzpatrick_scale:false,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"馃捀",fitzpatrick_scale:false,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"馃挼",fitzpatrick_scale:false,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"馃挻",fitzpatrick_scale:false,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"馃挾",fitzpatrick_scale:false,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"馃挿",fitzpatrick_scale:false,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"馃挵",fitzpatrick_scale:false,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"馃挸",fitzpatrick_scale:false,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"馃拵",fitzpatrick_scale:false,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"馃О",fitzpatrick_scale:false,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"馃敡",fitzpatrick_scale:false,category:"objects"},hammer:{keywords:["tools","build","create"],char:"馃敤",fitzpatrick_scale:false,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"馃洜",fitzpatrick_scale:false,category:"objects"},pick:{keywords:["tools","dig"],char:"鉀�",fitzpatrick_scale:false,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"馃敥",fitzpatrick_scale:false,category:"objects"},gear:{keywords:["cog"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},brick:{keywords:["bricks"],char:"馃П",fitzpatrick_scale:false,category:"objects"},chains:{keywords:["lock","arrest"],char:"鉀�",fitzpatrick_scale:false,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"馃Р",fitzpatrick_scale:false,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"馃敨",fitzpatrick_scale:false,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"馃挘",fitzpatrick_scale:false,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"馃Ж",fitzpatrick_scale:false,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"馃敧",fitzpatrick_scale:false,category:"objects"},dagger:{keywords:["weapon"],char:"馃棥",fitzpatrick_scale:false,category:"objects"},crossed_swords:{keywords:["weapon"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},shield:{keywords:["protection","security"],char:"馃洝",fitzpatrick_scale:false,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"馃毈",fitzpatrick_scale:false,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"鈽�",fitzpatrick_scale:false,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},amphora:{keywords:["vase","jar"],char:"馃徍",fitzpatrick_scale:false,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"馃敭",fitzpatrick_scale:false,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"馃摽",fitzpatrick_scale:false,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"馃Э",fitzpatrick_scale:false,category:"objects"},barber:{keywords:["hair","salon","style"],char:"馃拡",fitzpatrick_scale:false,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"鈿�",fitzpatrick_scale:false,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"馃敪",fitzpatrick_scale:false,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"馃敩",fitzpatrick_scale:false,category:"objects"},hole:{keywords:["embarrassing"],char:"馃暢",fitzpatrick_scale:false,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"馃拪",fitzpatrick_scale:false,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"馃拤",fitzpatrick_scale:false,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"馃К",fitzpatrick_scale:false,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"馃",fitzpatrick_scale:false,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"馃Й",fitzpatrick_scale:false,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"馃И",fitzpatrick_scale:false,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"馃尅",fitzpatrick_scale:false,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"馃Ч",fitzpatrick_scale:false,category:"objects"},basket:{keywords:["laundry"],char:"馃Ш",fitzpatrick_scale:false,category:"objects"},toilet_paper:{keywords:["roll"],char:"馃Щ",fitzpatrick_scale:false,category:"objects"},label:{keywords:["sale","tag"],char:"馃彿",fitzpatrick_scale:false,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"馃敄",fitzpatrick_scale:false,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"馃毥",fitzpatrick_scale:false,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"馃毧",fitzpatrick_scale:false,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"馃泚",fitzpatrick_scale:false,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"馃Ъ",fitzpatrick_scale:false,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"馃Ы",fitzpatrick_scale:false,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"馃Т",fitzpatrick_scale:false,category:"objects"},key:{keywords:["lock","door","password"],char:"馃攽",fitzpatrick_scale:false,category:"objects"},old_key:{keywords:["lock","door","password"],char:"馃棟",fitzpatrick_scale:false,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"馃泲",fitzpatrick_scale:false,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"馃泴",fitzpatrick_scale:true,category:"objects"},bed:{keywords:["sleep","rest"],char:"馃洀",fitzpatrick_scale:false,category:"objects"},door:{keywords:["house","entry","exit"],char:"馃毆",fitzpatrick_scale:false,category:"objects"},bellhop_bell:{keywords:["service"],char:"馃泿",fitzpatrick_scale:false,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"馃Ц",fitzpatrick_scale:false,category:"objects"},framed_picture:{keywords:["photography"],char:"馃柤",fitzpatrick_scale:false,category:"objects"},world_map:{keywords:["location","direction"],char:"馃椇",fitzpatrick_scale:false,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"鉀�",fitzpatrick_scale:false,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"馃椏",fitzpatrick_scale:false,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"馃泹",fitzpatrick_scale:false,category:"objects"},shopping_cart:{keywords:["trolley"],char:"馃洅",fitzpatrick_scale:false,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"馃巿",fitzpatrick_scale:false,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"馃帍",fitzpatrick_scale:false,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"馃巰",fitzpatrick_scale:false,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"馃巵",fitzpatrick_scale:false,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"馃帄",fitzpatrick_scale:false,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"馃帀",fitzpatrick_scale:false,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"馃帋",fitzpatrick_scale:false,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"馃帎",fitzpatrick_scale:false,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"馃帉",fitzpatrick_scale:false,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"馃彯",fitzpatrick_scale:false,category:"objects"},red_envelope:{keywords:["gift"],char:"馃Ё",fitzpatrick_scale:false,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"鉁夛笍",fitzpatrick_scale:false,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"馃摡",fitzpatrick_scale:false,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"馃摠",fitzpatrick_scale:false,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"馃摟",fitzpatrick_scale:false,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"馃拰",fitzpatrick_scale:false,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"馃摦",fitzpatrick_scale:false,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"馃摢",fitzpatrick_scale:false,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"馃摣",fitzpatrick_scale:false,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"馃摤",fitzpatrick_scale:false,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"馃摥",fitzpatrick_scale:false,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"馃摝",fitzpatrick_scale:false,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"馃摨",fitzpatrick_scale:false,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"馃摜",fitzpatrick_scale:false,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"馃摛",fitzpatrick_scale:false,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"馃摐",fitzpatrick_scale:false,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"馃搩",fitzpatrick_scale:false,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"馃搼",fitzpatrick_scale:false,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"馃Ь",fitzpatrick_scale:false,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"馃搳",fitzpatrick_scale:false,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"馃搱",fitzpatrick_scale:false,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"馃搲",fitzpatrick_scale:false,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"馃搫",fitzpatrick_scale:false,category:"objects"},date:{keywords:["calendar","schedule"],char:"馃搮",fitzpatrick_scale:false,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"馃搯",fitzpatrick_scale:false,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"馃棑",fitzpatrick_scale:false,category:"objects"},card_index:{keywords:["business","stationery"],char:"馃搰",fitzpatrick_scale:false,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"馃梼",fitzpatrick_scale:false,category:"objects"},ballot_box:{keywords:["election","vote"],char:"馃棾",fitzpatrick_scale:false,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"馃梽",fitzpatrick_scale:false,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"馃搵",fitzpatrick_scale:false,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"馃棐",fitzpatrick_scale:false,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"馃搧",fitzpatrick_scale:false,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"馃搨",fitzpatrick_scale:false,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"馃梻",fitzpatrick_scale:false,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"馃棡",fitzpatrick_scale:false,category:"objects"},newspaper:{keywords:["press","headline"],char:"馃摪",fitzpatrick_scale:false,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"馃摀",fitzpatrick_scale:false,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"馃摃",fitzpatrick_scale:false,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"馃摋",fitzpatrick_scale:false,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"馃摌",fitzpatrick_scale:false,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"馃摍",fitzpatrick_scale:false,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"馃摂",fitzpatrick_scale:false,category:"objects"},ledger:{keywords:["notes","paper"],char:"馃搾",fitzpatrick_scale:false,category:"objects"},books:{keywords:["literature","library","study"],char:"馃摎",fitzpatrick_scale:false,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"馃摉",fitzpatrick_scale:false,category:"objects"},safety_pin:{keywords:["diaper"],char:"馃Х",fitzpatrick_scale:false,category:"objects"},link:{keywords:["rings","url"],char:"馃敆",fitzpatrick_scale:false,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"馃搸",fitzpatrick_scale:false,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"馃枃",fitzpatrick_scale:false,category:"objects"},scissors:{keywords:["stationery","cut"],char:"鉁傦笍",fitzpatrick_scale:false,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"馃搻",fitzpatrick_scale:false,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"馃搹",fitzpatrick_scale:false,category:"objects"},abacus:{keywords:["calculation"],char:"馃М",fitzpatrick_scale:false,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"馃搶",fitzpatrick_scale:false,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"馃搷",fitzpatrick_scale:false,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"馃毄",fitzpatrick_scale:false,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"馃彸",fitzpatrick_scale:false,category:"objects"},black_flag:{keywords:["pirate"],char:"馃彺",fitzpatrick_scale:false,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"馃彸锔忊�嶐煂�",fitzpatrick_scale:false,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"馃攼",fitzpatrick_scale:false,category:"objects"},lock:{keywords:["security","password","padlock"],char:"馃敀",fitzpatrick_scale:false,category:"objects"},unlock:{keywords:["privacy","security"],char:"馃敁",fitzpatrick_scale:false,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"馃攺",fitzpatrick_scale:false,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"馃枈",fitzpatrick_scale:false,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"馃枊",fitzpatrick_scale:false,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"鉁掞笍",fitzpatrick_scale:false,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"馃摑",fitzpatrick_scale:false,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"鉁忥笍",fitzpatrick_scale:false,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"馃枍",fitzpatrick_scale:false,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"馃枌",fitzpatrick_scale:false,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"馃攳",fitzpatrick_scale:false,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"馃攷",fitzpatrick_scale:false,category:"objects"},heart:{keywords:["love","like","valentines"],char:"鉂わ笍",fitzpatrick_scale:false,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"馃А",fitzpatrick_scale:false,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"馃挍",fitzpatrick_scale:false,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"馃挌",fitzpatrick_scale:false,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"馃挋",fitzpatrick_scale:false,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"馃挏",fitzpatrick_scale:false,category:"symbols"},black_heart:{keywords:["evil"],char:"馃枻",fitzpatrick_scale:false,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"馃挃",fitzpatrick_scale:false,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"馃挄",fitzpatrick_scale:false,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"馃挒",fitzpatrick_scale:false,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"馃挀",fitzpatrick_scale:false,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"馃挆",fitzpatrick_scale:false,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"馃挅",fitzpatrick_scale:false,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"馃挊",fitzpatrick_scale:false,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"馃挐",fitzpatrick_scale:false,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"馃挓",fitzpatrick_scale:false,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},latin_cross:{keywords:["christianity"],char:"鉁�",fitzpatrick_scale:false,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"馃晧",fitzpatrick_scale:false,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},star_of_david:{keywords:["judaism"],char:"鉁�",fitzpatrick_scale:false,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"馃敮",fitzpatrick_scale:false,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"馃晭",fitzpatrick_scale:false,category:"symbols"},yin_yang:{keywords:["balance"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"馃洂",fitzpatrick_scale:false,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"鉀�",fitzpatrick_scale:false,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},id:{keywords:["purple-square","words"],char:"馃啍",fitzpatrick_scale:false,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"鈿�",fitzpatrick_scale:false,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"馃埑",fitzpatrick_scale:false,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"馃埞",fitzpatrick_scale:false,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},biohazard:{keywords:["danger"],char:"鈽�",fitzpatrick_scale:false,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"馃摯",fitzpatrick_scale:false,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"馃摮",fitzpatrick_scale:false,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"馃埗",fitzpatrick_scale:false,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"馃垰",fitzpatrick_scale:false,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"馃埜",fitzpatrick_scale:false,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"馃埡",fitzpatrick_scale:false,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"馃埛锔�",fitzpatrick_scale:false,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"鉁达笍",fitzpatrick_scale:false,category:"symbols"},vs:{keywords:["words","orange-square"],char:"馃啔",fitzpatrick_scale:false,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"馃墤",fitzpatrick_scale:false,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"馃挳",fitzpatrick_scale:false,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"馃墣",fitzpatrick_scale:false,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"銑欙笍",fitzpatrick_scale:false,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"銑楋笍",fitzpatrick_scale:false,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"馃埓",fitzpatrick_scale:false,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"馃埖",fitzpatrick_scale:false,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"馃埐",fitzpatrick_scale:false,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"馃叞锔�",fitzpatrick_scale:false,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"馃叡锔�",fitzpatrick_scale:false,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"馃啂",fitzpatrick_scale:false,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"馃啈",fitzpatrick_scale:false,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"馃吘锔�",fitzpatrick_scale:false,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"馃啒",fitzpatrick_scale:false,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"鉀�",fitzpatrick_scale:false,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"馃摏",fitzpatrick_scale:false,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"馃毇",fitzpatrick_scale:false,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},o:{keywords:["circle","round"],char:"猸�",fitzpatrick_scale:false,category:"symbols"},stop_sign:{keywords:["stop"],char:"馃洃",fitzpatrick_scale:false,category:"symbols"},anger:{keywords:["angry","mad"],char:"馃挗",fitzpatrick_scale:false,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"鈾笍",fitzpatrick_scale:false,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"馃毞",fitzpatrick_scale:false,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"馃毌",fitzpatrick_scale:false,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"馃毘",fitzpatrick_scale:false,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"馃毐",fitzpatrick_scale:false,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"馃敒",fitzpatrick_scale:false,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"馃摰",fitzpatrick_scale:false,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},question:{keywords:["doubt","confused"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"鈥硷笍",fitzpatrick_scale:false,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"鈦夛笍",fitzpatrick_scale:false,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"馃挴",fitzpatrick_scale:false,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"馃攨",fitzpatrick_scale:false,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"馃攩",fitzpatrick_scale:false,category:"symbols"},trident:{keywords:["weapon","spear"],char:"馃敱",fitzpatrick_scale:false,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"鈿�",fitzpatrick_scale:false,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"銆斤笍",fitzpatrick_scale:false,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"鈿狅笍",fitzpatrick_scale:false,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"馃毟",fitzpatrick_scale:false,category:"symbols"},beginner:{keywords:["badge","shield"],char:"馃敯",fitzpatrick_scale:false,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"鈾伙笍",fitzpatrick_scale:false,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"馃埊",fitzpatrick_scale:false,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"馃捁",fitzpatrick_scale:false,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"鉂囷笍",fitzpatrick_scale:false,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"鉁筹笍",fitzpatrick_scale:false,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"鉂�",fitzpatrick_scale:false,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"鉁�",fitzpatrick_scale:false,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"馃挔",fitzpatrick_scale:false,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"馃寑",fitzpatrick_scale:false,category:"symbols"},loop:{keywords:["tape","cassette"],char:"鉃�",fitzpatrick_scale:false,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"馃寪",fitzpatrick_scale:false,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"鈸傦笍",fitzpatrick_scale:false,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"馃彠",fitzpatrick_scale:false,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"馃垈锔�",fitzpatrick_scale:false,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"馃泜",fitzpatrick_scale:false,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"馃泝",fitzpatrick_scale:false,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"馃泟",fitzpatrick_scale:false,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"馃泤",fitzpatrick_scale:false,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"馃毉",fitzpatrick_scale:false,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"馃毦",fitzpatrick_scale:false,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"馃吙锔�",fitzpatrick_scale:false,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"馃毎",fitzpatrick_scale:false,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"馃毠",fitzpatrick_scale:false,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"馃毢",fitzpatrick_scale:false,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"馃毤",fitzpatrick_scale:false,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"馃毣",fitzpatrick_scale:false,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"馃毊",fitzpatrick_scale:false,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"馃帵",fitzpatrick_scale:false,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"馃摱",fitzpatrick_scale:false,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"馃垇",fitzpatrick_scale:false,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"馃問",fitzpatrick_scale:false,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"馃啑",fitzpatrick_scale:false,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"馃啓",fitzpatrick_scale:false,category:"symbols"},cool:{keywords:["words","blue-square"],char:"馃啋",fitzpatrick_scale:false,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"馃啎",fitzpatrick_scale:false,category:"symbols"},free:{keywords:["blue-square","words"],char:"馃啌",fitzpatrick_scale:false,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0锔忊儯",fitzpatrick_scale:false,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1锔忊儯",fitzpatrick_scale:false,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2锔忊儯",fitzpatrick_scale:false,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3锔忊儯",fitzpatrick_scale:false,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4锔忊儯",fitzpatrick_scale:false,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5锔忊儯",fitzpatrick_scale:false,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6锔忊儯",fitzpatrick_scale:false,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7锔忊儯",fitzpatrick_scale:false,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8锔忊儯",fitzpatrick_scale:false,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9锔忊儯",fitzpatrick_scale:false,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"馃敓",fitzpatrick_scale:false,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*鈨�",fitzpatrick_scale:false,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"馃敘",fitzpatrick_scale:false,category:"symbols"},eject_button:{keywords:["blue-square"],char:"鈴忥笍",fitzpatrick_scale:false,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"鈻讹笍",fitzpatrick_scale:false,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},stop_button:{keywords:["blue-square"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},record_button:{keywords:["blue-square"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},previous_track_button:{keywords:["backward"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"馃攢",fitzpatrick_scale:false,category:"symbols"},repeat:{keywords:["loop","record"],char:"馃攣",fitzpatrick_scale:false,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"馃攤",fitzpatrick_scale:false,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"鈼�锔�",fitzpatrick_scale:false,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"馃敿",fitzpatrick_scale:false,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"馃斀",fitzpatrick_scale:false,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"鈴�",fitzpatrick_scale:false,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"鉃★笍",fitzpatrick_scale:false,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"猬咃笍",fitzpatrick_scale:false,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"猬嗭笍",fitzpatrick_scale:false,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"猬囷笍",fitzpatrick_scale:false,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"鈫楋笍",fitzpatrick_scale:false,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"鈫橈笍",fitzpatrick_scale:false,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"鈫欙笍",fitzpatrick_scale:false,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"鈫栵笍",fitzpatrick_scale:false,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"鈫曪笍",fitzpatrick_scale:false,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"鈫旓笍",fitzpatrick_scale:false,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"馃攧",fitzpatrick_scale:false,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"鈫笍",fitzpatrick_scale:false,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"鈫╋笍",fitzpatrick_scale:false,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"猡达笍",fitzpatrick_scale:false,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"猡碉笍",fitzpatrick_scale:false,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#锔忊儯",fitzpatrick_scale:false,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"鈩癸笍",fitzpatrick_scale:false,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"馃敜",fitzpatrick_scale:false,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"馃敗",fitzpatrick_scale:false,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"馃敔",fitzpatrick_scale:false,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"馃敚",fitzpatrick_scale:false,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"馃幍",fitzpatrick_scale:false,category:"symbols"},notes:{keywords:["music","score"],char:"馃幎",fitzpatrick_scale:false,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"銆帮笍",fitzpatrick_scale:false,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"鉃�",fitzpatrick_scale:false,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"鉁旓笍",fitzpatrick_scale:false,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"馃攦",fitzpatrick_scale:false,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"鉃�",fitzpatrick_scale:false,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"鉃�",fitzpatrick_scale:false,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"鉃�",fitzpatrick_scale:false,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"鉁栵笍",fitzpatrick_scale:false,category:"symbols"},infinity:{keywords:["forever"],char:"鈾�",fitzpatrick_scale:false,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"馃挷",fitzpatrick_scale:false,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"馃挶",fitzpatrick_scale:false,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"漏锔�",fitzpatrick_scale:false,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"庐锔�",fitzpatrick_scale:false,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"鈩笍",fitzpatrick_scale:false,category:"symbols"},end:{keywords:["words","arrow"],char:"馃敋",fitzpatrick_scale:false,category:"symbols"},back:{keywords:["arrow","words","return"],char:"馃敊",fitzpatrick_scale:false,category:"symbols"},on:{keywords:["arrow","words"],char:"馃敍",fitzpatrick_scale:false,category:"symbols"},top:{keywords:["words","blue-square"],char:"馃敐",fitzpatrick_scale:false,category:"symbols"},soon:{keywords:["arrow","words"],char:"馃敎",fitzpatrick_scale:false,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"鈽戯笍",fitzpatrick_scale:false,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"馃敇",fitzpatrick_scale:false,category:"symbols"},white_circle:{keywords:["shape","round"],char:"鈿�",fitzpatrick_scale:false,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"鈿�",fitzpatrick_scale:false,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"馃敶",fitzpatrick_scale:false,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"馃數",fitzpatrick_scale:false,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"馃敻",fitzpatrick_scale:false,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"馃敼",fitzpatrick_scale:false,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"馃敹",fitzpatrick_scale:false,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"馃敺",fitzpatrick_scale:false,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"馃敽",fitzpatrick_scale:false,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"鈻笍",fitzpatrick_scale:false,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"鈻笍",fitzpatrick_scale:false,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"猬�",fitzpatrick_scale:false,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"猬�",fitzpatrick_scale:false,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"馃敾",fitzpatrick_scale:false,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"鈼硷笍",fitzpatrick_scale:false,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"鈼伙笍",fitzpatrick_scale:false,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"鈼�",fitzpatrick_scale:false,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"鈼�",fitzpatrick_scale:false,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"馃敳",fitzpatrick_scale:false,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"馃敵",fitzpatrick_scale:false,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"馃攬",fitzpatrick_scale:false,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"馃攭",fitzpatrick_scale:false,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"馃攰",fitzpatrick_scale:false,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"馃攪",fitzpatrick_scale:false,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"馃摚",fitzpatrick_scale:false,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"馃摙",fitzpatrick_scale:false,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"馃敂",fitzpatrick_scale:false,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"馃敃",fitzpatrick_scale:false,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"馃儚",fitzpatrick_scale:false,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"馃��",fitzpatrick_scale:false,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"鈾狅笍",fitzpatrick_scale:false,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"鈾o笍",fitzpatrick_scale:false,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"鈾ワ笍",fitzpatrick_scale:false,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"鈾︼笍",fitzpatrick_scale:false,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"馃幋",fitzpatrick_scale:false,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"馃挱",fitzpatrick_scale:false,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"馃棷",fitzpatrick_scale:false,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"馃挰",fitzpatrick_scale:false,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"馃棬",fitzpatrick_scale:false,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"馃晲",fitzpatrick_scale:false,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"馃晳",fitzpatrick_scale:false,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"馃晵",fitzpatrick_scale:false,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"馃晸",fitzpatrick_scale:false,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"馃晹",fitzpatrick_scale:false,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"馃晻",fitzpatrick_scale:false,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"馃晼",fitzpatrick_scale:false,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"馃晽",fitzpatrick_scale:false,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"馃晿",fitzpatrick_scale:false,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"馃暀",fitzpatrick_scale:false,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"馃暁",fitzpatrick_scale:false,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"馃暃",fitzpatrick_scale:false,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"馃暅",fitzpatrick_scale:false,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"馃暆",fitzpatrick_scale:false,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"馃暈",fitzpatrick_scale:false,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"馃暉",fitzpatrick_scale:false,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"馃暊",fitzpatrick_scale:false,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"馃暋",fitzpatrick_scale:false,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"馃暍",fitzpatrick_scale:false,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"馃暎",fitzpatrick_scale:false,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"馃暏",fitzpatrick_scale:false,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"馃暐",fitzpatrick_scale:false,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"馃暒",fitzpatrick_scale:false,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"馃暓",fitzpatrick_scale:false,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"馃嚘馃嚝",fitzpatrick_scale:false,category:"flags"},aland_islands:{keywords:["脜land","islands","flag","nation","country","banner"],char:"馃嚘馃嚱",fitzpatrick_scale:false,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"馃嚘馃嚤",fitzpatrick_scale:false,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"馃嚛馃嚳",fitzpatrick_scale:false,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"馃嚘馃嚫",fitzpatrick_scale:false,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"馃嚘馃嚛",fitzpatrick_scale:false,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"馃嚘馃嚧",fitzpatrick_scale:false,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"馃嚘馃嚠",fitzpatrick_scale:false,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"馃嚘馃嚩",fitzpatrick_scale:false,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"馃嚘馃嚞",fitzpatrick_scale:false,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"馃嚘馃嚪",fitzpatrick_scale:false,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"馃嚘馃嚥",fitzpatrick_scale:false,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"馃嚘馃嚰",fitzpatrick_scale:false,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"馃嚘馃嚭",fitzpatrick_scale:false,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"馃嚘馃嚬",fitzpatrick_scale:false,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"馃嚘馃嚳",fitzpatrick_scale:false,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"馃嚙馃嚫",fitzpatrick_scale:false,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"馃嚙馃嚟",fitzpatrick_scale:false,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"馃嚙馃嚛",fitzpatrick_scale:false,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"馃嚙馃嚙",fitzpatrick_scale:false,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"馃嚙馃嚲",fitzpatrick_scale:false,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"馃嚙馃嚜",fitzpatrick_scale:false,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"馃嚙馃嚳",fitzpatrick_scale:false,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"馃嚙馃嚡",fitzpatrick_scale:false,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"馃嚙馃嚥",fitzpatrick_scale:false,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"馃嚙馃嚬",fitzpatrick_scale:false,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"馃嚙馃嚧",fitzpatrick_scale:false,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"馃嚙馃嚩",fitzpatrick_scale:false,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"馃嚙馃嚘",fitzpatrick_scale:false,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"馃嚙馃嚰",fitzpatrick_scale:false,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"馃嚙馃嚪",fitzpatrick_scale:false,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"馃嚠馃嚧",fitzpatrick_scale:false,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"馃嚮馃嚞",fitzpatrick_scale:false,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"馃嚙馃嚦",fitzpatrick_scale:false,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"馃嚙馃嚞",fitzpatrick_scale:false,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"馃嚙馃嚝",fitzpatrick_scale:false,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"馃嚙馃嚠",fitzpatrick_scale:false,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"馃嚚馃嚮",fitzpatrick_scale:false,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"馃嚢馃嚟",fitzpatrick_scale:false,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"馃嚚馃嚥",fitzpatrick_scale:false,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"馃嚚馃嚘",fitzpatrick_scale:false,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"馃嚠馃嚚",fitzpatrick_scale:false,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"馃嚢馃嚲",fitzpatrick_scale:false,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"馃嚚馃嚝",fitzpatrick_scale:false,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"馃嚬馃嚛",fitzpatrick_scale:false,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"馃嚚馃嚤",fitzpatrick_scale:false,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"馃嚚馃嚦",fitzpatrick_scale:false,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"馃嚚馃嚱",fitzpatrick_scale:false,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"馃嚚馃嚚",fitzpatrick_scale:false,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"馃嚚馃嚧",fitzpatrick_scale:false,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"馃嚢馃嚥",fitzpatrick_scale:false,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"馃嚚馃嚞",fitzpatrick_scale:false,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"馃嚚馃嚛",fitzpatrick_scale:false,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"馃嚚馃嚢",fitzpatrick_scale:false,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"馃嚚馃嚪",fitzpatrick_scale:false,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"馃嚟馃嚪",fitzpatrick_scale:false,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"馃嚚馃嚭",fitzpatrick_scale:false,category:"flags"},curacao:{keywords:["cura莽ao","flag","nation","country","banner"],char:"馃嚚馃嚰",fitzpatrick_scale:false,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"馃嚚馃嚲",fitzpatrick_scale:false,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"馃嚚馃嚳",fitzpatrick_scale:false,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"馃嚛馃嚢",fitzpatrick_scale:false,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"馃嚛馃嚡",fitzpatrick_scale:false,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"馃嚛馃嚥",fitzpatrick_scale:false,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"馃嚛馃嚧",fitzpatrick_scale:false,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"馃嚜馃嚚",fitzpatrick_scale:false,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"馃嚜馃嚞",fitzpatrick_scale:false,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"馃嚫馃嚮",fitzpatrick_scale:false,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"馃嚞馃嚩",fitzpatrick_scale:false,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"馃嚜馃嚪",fitzpatrick_scale:false,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"馃嚜馃嚜",fitzpatrick_scale:false,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"馃嚜馃嚬",fitzpatrick_scale:false,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"馃嚜馃嚭",fitzpatrick_scale:false,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"馃嚝馃嚢",fitzpatrick_scale:false,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"馃嚝馃嚧",fitzpatrick_scale:false,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"馃嚝馃嚡",fitzpatrick_scale:false,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"馃嚝馃嚠",fitzpatrick_scale:false,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"馃嚝馃嚪",fitzpatrick_scale:false,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"馃嚞馃嚝",fitzpatrick_scale:false,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"馃嚨馃嚝",fitzpatrick_scale:false,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"馃嚬馃嚝",fitzpatrick_scale:false,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"馃嚞馃嚘",fitzpatrick_scale:false,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"馃嚞馃嚥",fitzpatrick_scale:false,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"馃嚞馃嚜",fitzpatrick_scale:false,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"馃嚛馃嚜",fitzpatrick_scale:false,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"馃嚞馃嚟",fitzpatrick_scale:false,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"馃嚞馃嚠",fitzpatrick_scale:false,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"馃嚞馃嚪",fitzpatrick_scale:false,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"馃嚞馃嚤",fitzpatrick_scale:false,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"馃嚞馃嚛",fitzpatrick_scale:false,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"馃嚞馃嚨",fitzpatrick_scale:false,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"馃嚞馃嚭",fitzpatrick_scale:false,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"馃嚞馃嚬",fitzpatrick_scale:false,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"馃嚞馃嚞",fitzpatrick_scale:false,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"馃嚞馃嚦",fitzpatrick_scale:false,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"馃嚞馃嚰",fitzpatrick_scale:false,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"馃嚞馃嚲",fitzpatrick_scale:false,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"馃嚟馃嚬",fitzpatrick_scale:false,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"馃嚟馃嚦",fitzpatrick_scale:false,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"馃嚟馃嚢",fitzpatrick_scale:false,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"馃嚟馃嚭",fitzpatrick_scale:false,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"馃嚠馃嚫",fitzpatrick_scale:false,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"馃嚠馃嚦",fitzpatrick_scale:false,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"馃嚠馃嚛",fitzpatrick_scale:false,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"馃嚠馃嚪",fitzpatrick_scale:false,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"馃嚠馃嚩",fitzpatrick_scale:false,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"馃嚠馃嚜",fitzpatrick_scale:false,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"馃嚠馃嚥",fitzpatrick_scale:false,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"馃嚠馃嚤",fitzpatrick_scale:false,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"馃嚠馃嚬",fitzpatrick_scale:false,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"馃嚚馃嚠",fitzpatrick_scale:false,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"馃嚡馃嚥",fitzpatrick_scale:false,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"馃嚡馃嚨",fitzpatrick_scale:false,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"馃嚡馃嚜",fitzpatrick_scale:false,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"馃嚡馃嚧",fitzpatrick_scale:false,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"馃嚢馃嚳",fitzpatrick_scale:false,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"馃嚢馃嚜",fitzpatrick_scale:false,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"馃嚢馃嚠",fitzpatrick_scale:false,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"馃嚱馃嚢",fitzpatrick_scale:false,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"馃嚢馃嚰",fitzpatrick_scale:false,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"馃嚢馃嚞",fitzpatrick_scale:false,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"馃嚤馃嚘",fitzpatrick_scale:false,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"馃嚤馃嚮",fitzpatrick_scale:false,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"馃嚤馃嚙",fitzpatrick_scale:false,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"馃嚤馃嚫",fitzpatrick_scale:false,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"馃嚤馃嚪",fitzpatrick_scale:false,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"馃嚤馃嚲",fitzpatrick_scale:false,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"馃嚤馃嚠",fitzpatrick_scale:false,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"馃嚤馃嚬",fitzpatrick_scale:false,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"馃嚤馃嚭",fitzpatrick_scale:false,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"馃嚥馃嚧",fitzpatrick_scale:false,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"馃嚥馃嚢",fitzpatrick_scale:false,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"馃嚥馃嚞",fitzpatrick_scale:false,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"馃嚥馃嚰",fitzpatrick_scale:false,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"馃嚥馃嚲",fitzpatrick_scale:false,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"馃嚥馃嚮",fitzpatrick_scale:false,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"馃嚥馃嚤",fitzpatrick_scale:false,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"馃嚥馃嚬",fitzpatrick_scale:false,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"馃嚥馃嚟",fitzpatrick_scale:false,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"馃嚥馃嚩",fitzpatrick_scale:false,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"馃嚥馃嚪",fitzpatrick_scale:false,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"馃嚥馃嚭",fitzpatrick_scale:false,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"馃嚲馃嚬",fitzpatrick_scale:false,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"馃嚥馃嚱",fitzpatrick_scale:false,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"馃嚝馃嚥",fitzpatrick_scale:false,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"馃嚥馃嚛",fitzpatrick_scale:false,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"馃嚥馃嚚",fitzpatrick_scale:false,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"馃嚥馃嚦",fitzpatrick_scale:false,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"馃嚥馃嚜",fitzpatrick_scale:false,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"馃嚥馃嚫",fitzpatrick_scale:false,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"馃嚥馃嚘",fitzpatrick_scale:false,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"馃嚥馃嚳",fitzpatrick_scale:false,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"馃嚥馃嚥",fitzpatrick_scale:false,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"馃嚦馃嚘",fitzpatrick_scale:false,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"馃嚦馃嚪",fitzpatrick_scale:false,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"馃嚦馃嚨",fitzpatrick_scale:false,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"馃嚦馃嚤",fitzpatrick_scale:false,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"馃嚦馃嚚",fitzpatrick_scale:false,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"馃嚦馃嚳",fitzpatrick_scale:false,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"馃嚦馃嚠",fitzpatrick_scale:false,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"馃嚦馃嚜",fitzpatrick_scale:false,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"馃嚦馃嚞",fitzpatrick_scale:false,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"馃嚦馃嚭",fitzpatrick_scale:false,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"馃嚦馃嚝",fitzpatrick_scale:false,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"馃嚥馃嚨",fitzpatrick_scale:false,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"馃嚢馃嚨",fitzpatrick_scale:false,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"馃嚦馃嚧",fitzpatrick_scale:false,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"馃嚧馃嚥",fitzpatrick_scale:false,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"馃嚨馃嚢",fitzpatrick_scale:false,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"馃嚨馃嚰",fitzpatrick_scale:false,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"馃嚨馃嚫",fitzpatrick_scale:false,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"馃嚨馃嚘",fitzpatrick_scale:false,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"馃嚨馃嚞",fitzpatrick_scale:false,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"馃嚨馃嚲",fitzpatrick_scale:false,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"馃嚨馃嚜",fitzpatrick_scale:false,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"馃嚨馃嚟",fitzpatrick_scale:false,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"馃嚨馃嚦",fitzpatrick_scale:false,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"馃嚨馃嚤",fitzpatrick_scale:false,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"馃嚨馃嚬",fitzpatrick_scale:false,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"馃嚨馃嚪",fitzpatrick_scale:false,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"馃嚩馃嚘",fitzpatrick_scale:false,category:"flags"},reunion:{keywords:["r茅union","flag","nation","country","banner"],char:"馃嚪馃嚜",fitzpatrick_scale:false,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"馃嚪馃嚧",fitzpatrick_scale:false,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"馃嚪馃嚭",fitzpatrick_scale:false,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"馃嚪馃嚰",fitzpatrick_scale:false,category:"flags"},st_barthelemy:{keywords:["saint","barth茅lemy","flag","nation","country","banner"],char:"馃嚙馃嚤",fitzpatrick_scale:false,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"馃嚫馃嚟",fitzpatrick_scale:false,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"馃嚢馃嚦",fitzpatrick_scale:false,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"馃嚤馃嚚",fitzpatrick_scale:false,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"馃嚨馃嚥",fitzpatrick_scale:false,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"馃嚮馃嚚",fitzpatrick_scale:false,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"馃嚰馃嚫",fitzpatrick_scale:false,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"馃嚫馃嚥",fitzpatrick_scale:false,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"馃嚫馃嚬",fitzpatrick_scale:false,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"馃嚫馃嚘",fitzpatrick_scale:false,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"馃嚫馃嚦",fitzpatrick_scale:false,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"馃嚪馃嚫",fitzpatrick_scale:false,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"馃嚫馃嚚",fitzpatrick_scale:false,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"馃嚫馃嚤",fitzpatrick_scale:false,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"馃嚫馃嚞",fitzpatrick_scale:false,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"馃嚫馃嚱",fitzpatrick_scale:false,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"馃嚫馃嚢",fitzpatrick_scale:false,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"馃嚫馃嚠",fitzpatrick_scale:false,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"馃嚫馃嚙",fitzpatrick_scale:false,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"馃嚫馃嚧",fitzpatrick_scale:false,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"馃嚳馃嚘",fitzpatrick_scale:false,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"馃嚞馃嚫",fitzpatrick_scale:false,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"馃嚢馃嚪",fitzpatrick_scale:false,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"馃嚫馃嚫",fitzpatrick_scale:false,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"馃嚜馃嚫",fitzpatrick_scale:false,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"馃嚤馃嚢",fitzpatrick_scale:false,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"馃嚫馃嚛",fitzpatrick_scale:false,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"馃嚫馃嚪",fitzpatrick_scale:false,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"馃嚫馃嚳",fitzpatrick_scale:false,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"馃嚫馃嚜",fitzpatrick_scale:false,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"馃嚚馃嚟",fitzpatrick_scale:false,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"馃嚫馃嚲",fitzpatrick_scale:false,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"馃嚬馃嚰",fitzpatrick_scale:false,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"馃嚬馃嚡",fitzpatrick_scale:false,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"馃嚬馃嚳",fitzpatrick_scale:false,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"馃嚬馃嚟",fitzpatrick_scale:false,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"馃嚬馃嚤",fitzpatrick_scale:false,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"馃嚬馃嚞",fitzpatrick_scale:false,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"馃嚬馃嚢",fitzpatrick_scale:false,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"馃嚬馃嚧",fitzpatrick_scale:false,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"馃嚬馃嚬",fitzpatrick_scale:false,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"馃嚬馃嚦",fitzpatrick_scale:false,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"馃嚬馃嚪",fitzpatrick_scale:false,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"馃嚬馃嚥",fitzpatrick_scale:false,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"馃嚬馃嚚",fitzpatrick_scale:false,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"馃嚬馃嚮",fitzpatrick_scale:false,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"馃嚭馃嚞",fitzpatrick_scale:false,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"馃嚭馃嚘",fitzpatrick_scale:false,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"馃嚘馃嚜",fitzpatrick_scale:false,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"馃嚞馃嚙",fitzpatrick_scale:false,category:"flags"},england:{keywords:["flag","english"],char:"馃彺鬆仹鬆仮鬆仴鬆伄鬆仹鬆伩",fitzpatrick_scale:false,category:"flags"},scotland:{keywords:["flag","scottish"],char:"馃彺鬆仹鬆仮鬆伋鬆仯鬆伌鬆伩",fitzpatrick_scale:false,category:"flags"},wales:{keywords:["flag","welsh"],char:"馃彺鬆仹鬆仮鬆伔鬆伂鬆伋鬆伩",fitzpatrick_scale:false,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"馃嚭馃嚫",fitzpatrick_scale:false,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"馃嚮馃嚠",fitzpatrick_scale:false,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"馃嚭馃嚲",fitzpatrick_scale:false,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"馃嚭馃嚳",fitzpatrick_scale:false,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"馃嚮馃嚭",fitzpatrick_scale:false,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"馃嚮馃嚘",fitzpatrick_scale:false,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"馃嚮馃嚜",fitzpatrick_scale:false,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"馃嚮馃嚦",fitzpatrick_scale:false,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"馃嚰馃嚝",fitzpatrick_scale:false,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"馃嚜馃嚟",fitzpatrick_scale:false,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"馃嚲馃嚜",fitzpatrick_scale:false,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"馃嚳馃嚥",fitzpatrick_scale:false,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"馃嚳馃嚰",fitzpatrick_scale:false,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"馃嚭馃嚦",fitzpatrick_scale:false,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"馃彺鈥嶁槧锔�",fitzpatrick_scale:false,category:"flags"}});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js
new file mode 100644
index 0000000..5a1c491
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/js/emojis.min.js
@@ -0,0 +1,2 @@
+// Source: npm package: emojilib, file:emojis.json
+window.tinymce.Resource.add("tinymce.plugins.emoticons",{grinning:{keywords:["face","smile","happy","joy",":D","grin"],char:"\u{1f600}",fitzpatrick_scale:!1,category:"people"},grimacing:{keywords:["face","grimace","teeth"],char:"\u{1f62c}",fitzpatrick_scale:!1,category:"people"},grin:{keywords:["face","happy","smile","joy","kawaii"],char:"\u{1f601}",fitzpatrick_scale:!1,category:"people"},joy:{keywords:["face","cry","tears","weep","happy","happytears","haha"],char:"\u{1f602}",fitzpatrick_scale:!1,category:"people"},rofl:{keywords:["face","rolling","floor","laughing","lol","haha"],char:"\u{1f923}",fitzpatrick_scale:!1,category:"people"},partying:{keywords:["face","celebration","woohoo"],char:"\u{1f973}",fitzpatrick_scale:!1,category:"people"},smiley:{keywords:["face","happy","joy","haha",":D",":)","smile","funny"],char:"\u{1f603}",fitzpatrick_scale:!1,category:"people"},smile:{keywords:["face","happy","joy","funny","haha","laugh","like",":D",":)"],char:"\u{1f604}",fitzpatrick_scale:!1,category:"people"},sweat_smile:{keywords:["face","hot","happy","laugh","sweat","smile","relief"],char:"\u{1f605}",fitzpatrick_scale:!1,category:"people"},laughing:{keywords:["happy","joy","lol","satisfied","haha","face","glad","XD","laugh"],char:"\u{1f606}",fitzpatrick_scale:!1,category:"people"},innocent:{keywords:["face","angel","heaven","halo"],char:"\u{1f607}",fitzpatrick_scale:!1,category:"people"},wink:{keywords:["face","happy","mischievous","secret",";)","smile","eye"],char:"\u{1f609}",fitzpatrick_scale:!1,category:"people"},blush:{keywords:["face","smile","happy","flushed","crush","embarrassed","shy","joy"],char:"\u{1f60a}",fitzpatrick_scale:!1,category:"people"},slightly_smiling_face:{keywords:["face","smile"],char:"\u{1f642}",fitzpatrick_scale:!1,category:"people"},upside_down_face:{keywords:["face","flipped","silly","smile"],char:"\u{1f643}",fitzpatrick_scale:!1,category:"people"},relaxed:{keywords:["face","blush","massage","happiness"],char:"\u263a\ufe0f",fitzpatrick_scale:!1,category:"people"},yum:{keywords:["happy","joy","tongue","smile","face","silly","yummy","nom","delicious","savouring"],char:"\u{1f60b}",fitzpatrick_scale:!1,category:"people"},relieved:{keywords:["face","relaxed","phew","massage","happiness"],char:"\u{1f60c}",fitzpatrick_scale:!1,category:"people"},heart_eyes:{keywords:["face","love","like","affection","valentines","infatuation","crush","heart"],char:"\u{1f60d}",fitzpatrick_scale:!1,category:"people"},smiling_face_with_three_hearts:{keywords:["face","love","like","affection","valentines","infatuation","crush","hearts","adore"],char:"\u{1f970}",fitzpatrick_scale:!1,category:"people"},kissing_heart:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f618}",fitzpatrick_scale:!1,category:"people"},kissing:{keywords:["love","like","face","3","valentines","infatuation","kiss"],char:"\u{1f617}",fitzpatrick_scale:!1,category:"people"},kissing_smiling_eyes:{keywords:["face","affection","valentines","infatuation","kiss"],char:"\u{1f619}",fitzpatrick_scale:!1,category:"people"},kissing_closed_eyes:{keywords:["face","love","like","affection","valentines","infatuation","kiss"],char:"\u{1f61a}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_winking_eye:{keywords:["face","prank","childish","playful","mischievous","smile","wink","tongue"],char:"\u{1f61c}",fitzpatrick_scale:!1,category:"people"},zany:{keywords:["face","goofy","crazy"],char:"\u{1f92a}",fitzpatrick_scale:!1,category:"people"},raised_eyebrow:{keywords:["face","distrust","scepticism","disapproval","disbelief","surprise"],char:"\u{1f928}",fitzpatrick_scale:!1,category:"people"},monocle:{keywords:["face","stuffy","wealthy"],char:"\u{1f9d0}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue_closed_eyes:{keywords:["face","prank","playful","mischievous","smile","tongue"],char:"\u{1f61d}",fitzpatrick_scale:!1,category:"people"},stuck_out_tongue:{keywords:["face","prank","childish","playful","mischievous","smile","tongue"],char:"\u{1f61b}",fitzpatrick_scale:!1,category:"people"},money_mouth_face:{keywords:["face","rich","dollar","money"],char:"\u{1f911}",fitzpatrick_scale:!1,category:"people"},nerd_face:{keywords:["face","nerdy","geek","dork"],char:"\u{1f913}",fitzpatrick_scale:!1,category:"people"},sunglasses:{keywords:["face","cool","smile","summer","beach","sunglass"],char:"\u{1f60e}",fitzpatrick_scale:!1,category:"people"},star_struck:{keywords:["face","smile","starry","eyes","grinning"],char:"\u{1f929}",fitzpatrick_scale:!1,category:"people"},clown_face:{keywords:["face"],char:"\u{1f921}",fitzpatrick_scale:!1,category:"people"},cowboy_hat_face:{keywords:["face","cowgirl","hat"],char:"\u{1f920}",fitzpatrick_scale:!1,category:"people"},hugs:{keywords:["face","smile","hug"],char:"\u{1f917}",fitzpatrick_scale:!1,category:"people"},smirk:{keywords:["face","smile","mean","prank","smug","sarcasm"],char:"\u{1f60f}",fitzpatrick_scale:!1,category:"people"},no_mouth:{keywords:["face","hellokitty"],char:"\u{1f636}",fitzpatrick_scale:!1,category:"people"},neutral_face:{keywords:["indifference","meh",":|","neutral"],char:"\u{1f610}",fitzpatrick_scale:!1,category:"people"},expressionless:{keywords:["face","indifferent","-_-","meh","deadpan"],char:"\u{1f611}",fitzpatrick_scale:!1,category:"people"},unamused:{keywords:["indifference","bored","straight face","serious","sarcasm","unimpressed","skeptical","dubious","side_eye"],char:"\u{1f612}",fitzpatrick_scale:!1,category:"people"},roll_eyes:{keywords:["face","eyeroll","frustrated"],char:"\u{1f644}",fitzpatrick_scale:!1,category:"people"},thinking:{keywords:["face","hmmm","think","consider"],char:"\u{1f914}",fitzpatrick_scale:!1,category:"people"},lying_face:{keywords:["face","lie","pinocchio"],char:"\u{1f925}",fitzpatrick_scale:!1,category:"people"},hand_over_mouth:{keywords:["face","whoops","shock","surprise"],char:"\u{1f92d}",fitzpatrick_scale:!1,category:"people"},shushing:{keywords:["face","quiet","shhh"],char:"\u{1f92b}",fitzpatrick_scale:!1,category:"people"},symbols_over_mouth:{keywords:["face","swearing","cursing","cussing","profanity","expletive"],char:"\u{1f92c}",fitzpatrick_scale:!1,category:"people"},exploding_head:{keywords:["face","shocked","mind","blown"],char:"\u{1f92f}",fitzpatrick_scale:!1,category:"people"},flushed:{keywords:["face","blush","shy","flattered"],char:"\u{1f633}",fitzpatrick_scale:!1,category:"people"},disappointed:{keywords:["face","sad","upset","depressed",":("],char:"\u{1f61e}",fitzpatrick_scale:!1,category:"people"},worried:{keywords:["face","concern","nervous",":("],char:"\u{1f61f}",fitzpatrick_scale:!1,category:"people"},angry:{keywords:["mad","face","annoyed","frustrated"],char:"\u{1f620}",fitzpatrick_scale:!1,category:"people"},rage:{keywords:["angry","mad","hate","despise"],char:"\u{1f621}",fitzpatrick_scale:!1,category:"people"},pensive:{keywords:["face","sad","depressed","upset"],char:"\u{1f614}",fitzpatrick_scale:!1,category:"people"},confused:{keywords:["face","indifference","huh","weird","hmmm",":/"],char:"\u{1f615}",fitzpatrick_scale:!1,category:"people"},slightly_frowning_face:{keywords:["face","frowning","disappointed","sad","upset"],char:"\u{1f641}",fitzpatrick_scale:!1,category:"people"},frowning_face:{keywords:["face","sad","upset","frown"],char:"\u2639",fitzpatrick_scale:!1,category:"people"},persevere:{keywords:["face","sick","no","upset","oops"],char:"\u{1f623}",fitzpatrick_scale:!1,category:"people"},confounded:{keywords:["face","confused","sick","unwell","oops",":S"],char:"\u{1f616}",fitzpatrick_scale:!1,category:"people"},tired_face:{keywords:["sick","whine","upset","frustrated"],char:"\u{1f62b}",fitzpatrick_scale:!1,category:"people"},weary:{keywords:["face","tired","sleepy","sad","frustrated","upset"],char:"\u{1f629}",fitzpatrick_scale:!1,category:"people"},pleading:{keywords:["face","begging","mercy"],char:"\u{1f97a}",fitzpatrick_scale:!1,category:"people"},triumph:{keywords:["face","gas","phew","proud","pride"],char:"\u{1f624}",fitzpatrick_scale:!1,category:"people"},open_mouth:{keywords:["face","surprise","impressed","wow","whoa",":O"],char:"\u{1f62e}",fitzpatrick_scale:!1,category:"people"},scream:{keywords:["face","munch","scared","omg"],char:"\u{1f631}",fitzpatrick_scale:!1,category:"people"},fearful:{keywords:["face","scared","terrified","nervous","oops","huh"],char:"\u{1f628}",fitzpatrick_scale:!1,category:"people"},cold_sweat:{keywords:["face","nervous","sweat"],char:"\u{1f630}",fitzpatrick_scale:!1,category:"people"},hushed:{keywords:["face","woo","shh"],char:"\u{1f62f}",fitzpatrick_scale:!1,category:"people"},frowning:{keywords:["face","aw","what"],char:"\u{1f626}",fitzpatrick_scale:!1,category:"people"},anguished:{keywords:["face","stunned","nervous"],char:"\u{1f627}",fitzpatrick_scale:!1,category:"people"},cry:{keywords:["face","tears","sad","depressed","upset",":'("],char:"\u{1f622}",fitzpatrick_scale:!1,category:"people"},disappointed_relieved:{keywords:["face","phew","sweat","nervous"],char:"\u{1f625}",fitzpatrick_scale:!1,category:"people"},drooling_face:{keywords:["face"],char:"\u{1f924}",fitzpatrick_scale:!1,category:"people"},sleepy:{keywords:["face","tired","rest","nap"],char:"\u{1f62a}",fitzpatrick_scale:!1,category:"people"},sweat:{keywords:["face","hot","sad","tired","exercise"],char:"\u{1f613}",fitzpatrick_scale:!1,category:"people"},hot:{keywords:["face","feverish","heat","red","sweating"],char:"\u{1f975}",fitzpatrick_scale:!1,category:"people"},cold:{keywords:["face","blue","freezing","frozen","frostbite","icicles"],char:"\u{1f976}",fitzpatrick_scale:!1,category:"people"},sob:{keywords:["face","cry","tears","sad","upset","depressed"],char:"\u{1f62d}",fitzpatrick_scale:!1,category:"people"},dizzy_face:{keywords:["spent","unconscious","xox","dizzy"],char:"\u{1f635}",fitzpatrick_scale:!1,category:"people"},astonished:{keywords:["face","xox","surprised","poisoned"],char:"\u{1f632}",fitzpatrick_scale:!1,category:"people"},zipper_mouth_face:{keywords:["face","sealed","zipper","secret"],char:"\u{1f910}",fitzpatrick_scale:!1,category:"people"},nauseated_face:{keywords:["face","vomit","gross","green","sick","throw up","ill"],char:"\u{1f922}",fitzpatrick_scale:!1,category:"people"},sneezing_face:{keywords:["face","gesundheit","sneeze","sick","allergy"],char:"\u{1f927}",fitzpatrick_scale:!1,category:"people"},vomiting:{keywords:["face","sick"],char:"\u{1f92e}",fitzpatrick_scale:!1,category:"people"},mask:{keywords:["face","sick","ill","disease"],char:"\u{1f637}",fitzpatrick_scale:!1,category:"people"},face_with_thermometer:{keywords:["sick","temperature","thermometer","cold","fever"],char:"\u{1f912}",fitzpatrick_scale:!1,category:"people"},face_with_head_bandage:{keywords:["injured","clumsy","bandage","hurt"],char:"\u{1f915}",fitzpatrick_scale:!1,category:"people"},woozy:{keywords:["face","dizzy","intoxicated","tipsy","wavy"],char:"\u{1f974}",fitzpatrick_scale:!1,category:"people"},sleeping:{keywords:["face","tired","sleepy","night","zzz"],char:"\u{1f634}",fitzpatrick_scale:!1,category:"people"},zzz:{keywords:["sleepy","tired","dream"],char:"\u{1f4a4}",fitzpatrick_scale:!1,category:"people"},poop:{keywords:["hankey","shitface","fail","turd","shit"],char:"\u{1f4a9}",fitzpatrick_scale:!1,category:"people"},smiling_imp:{keywords:["devil","horns"],char:"\u{1f608}",fitzpatrick_scale:!1,category:"people"},imp:{keywords:["devil","angry","horns"],char:"\u{1f47f}",fitzpatrick_scale:!1,category:"people"},japanese_ogre:{keywords:["monster","red","mask","halloween","scary","creepy","devil","demon","japanese","ogre"],char:"\u{1f479}",fitzpatrick_scale:!1,category:"people"},japanese_goblin:{keywords:["red","evil","mask","monster","scary","creepy","japanese","goblin"],char:"\u{1f47a}",fitzpatrick_scale:!1,category:"people"},skull:{keywords:["dead","skeleton","creepy","death"],char:"\u{1f480}",fitzpatrick_scale:!1,category:"people"},ghost:{keywords:["halloween","spooky","scary"],char:"\u{1f47b}",fitzpatrick_scale:!1,category:"people"},alien:{keywords:["UFO","paul","weird","outer_space"],char:"\u{1f47d}",fitzpatrick_scale:!1,category:"people"},robot:{keywords:["computer","machine","bot"],char:"\u{1f916}",fitzpatrick_scale:!1,category:"people"},smiley_cat:{keywords:["animal","cats","happy","smile"],char:"\u{1f63a}",fitzpatrick_scale:!1,category:"people"},smile_cat:{keywords:["animal","cats","smile"],char:"\u{1f638}",fitzpatrick_scale:!1,category:"people"},joy_cat:{keywords:["animal","cats","haha","happy","tears"],char:"\u{1f639}",fitzpatrick_scale:!1,category:"people"},heart_eyes_cat:{keywords:["animal","love","like","affection","cats","valentines","heart"],char:"\u{1f63b}",fitzpatrick_scale:!1,category:"people"},smirk_cat:{keywords:["animal","cats","smirk"],char:"\u{1f63c}",fitzpatrick_scale:!1,category:"people"},kissing_cat:{keywords:["animal","cats","kiss"],char:"\u{1f63d}",fitzpatrick_scale:!1,category:"people"},scream_cat:{keywords:["animal","cats","munch","scared","scream"],char:"\u{1f640}",fitzpatrick_scale:!1,category:"people"},crying_cat_face:{keywords:["animal","tears","weep","sad","cats","upset","cry"],char:"\u{1f63f}",fitzpatrick_scale:!1,category:"people"},pouting_cat:{keywords:["animal","cats"],char:"\u{1f63e}",fitzpatrick_scale:!1,category:"people"},palms_up:{keywords:["hands","gesture","cupped","prayer"],char:"\u{1f932}",fitzpatrick_scale:!0,category:"people"},raised_hands:{keywords:["gesture","hooray","yea","celebration","hands"],char:"\u{1f64c}",fitzpatrick_scale:!0,category:"people"},clap:{keywords:["hands","praise","applause","congrats","yay"],char:"\u{1f44f}",fitzpatrick_scale:!0,category:"people"},wave:{keywords:["hands","gesture","goodbye","solong","farewell","hello","hi","palm"],char:"\u{1f44b}",fitzpatrick_scale:!0,category:"people"},call_me_hand:{keywords:["hands","gesture"],char:"\u{1f919}",fitzpatrick_scale:!0,category:"people"},"+1":{keywords:["thumbsup","yes","awesome","good","agree","accept","cool","hand","like"],char:"\u{1f44d}",fitzpatrick_scale:!0,category:"people"},"-1":{keywords:["thumbsdown","no","dislike","hand"],char:"\u{1f44e}",fitzpatrick_scale:!0,category:"people"},facepunch:{keywords:["angry","violence","fist","hit","attack","hand"],char:"\u{1f44a}",fitzpatrick_scale:!0,category:"people"},fist:{keywords:["fingers","hand","grasp"],char:"\u270a",fitzpatrick_scale:!0,category:"people"},fist_left:{keywords:["hand","fistbump"],char:"\u{1f91b}",fitzpatrick_scale:!0,category:"people"},fist_right:{keywords:["hand","fistbump"],char:"\u{1f91c}",fitzpatrick_scale:!0,category:"people"},v:{keywords:["fingers","ohyeah","hand","peace","victory","two"],char:"\u270c",fitzpatrick_scale:!0,category:"people"},ok_hand:{keywords:["fingers","limbs","perfect","ok","okay"],char:"\u{1f44c}",fitzpatrick_scale:!0,category:"people"},raised_hand:{keywords:["fingers","stop","highfive","palm","ban"],char:"\u270b",fitzpatrick_scale:!0,category:"people"},raised_back_of_hand:{keywords:["fingers","raised","backhand"],char:"\u{1f91a}",fitzpatrick_scale:!0,category:"people"},open_hands:{keywords:["fingers","butterfly","hands","open"],char:"\u{1f450}",fitzpatrick_scale:!0,category:"people"},muscle:{keywords:["arm","flex","hand","summer","strong","biceps"],char:"\u{1f4aa}",fitzpatrick_scale:!0,category:"people"},pray:{keywords:["please","hope","wish","namaste","highfive"],char:"\u{1f64f}",fitzpatrick_scale:!0,category:"people"},foot:{keywords:["kick","stomp"],char:"\u{1f9b6}",fitzpatrick_scale:!0,category:"people"},leg:{keywords:["kick","limb"],char:"\u{1f9b5}",fitzpatrick_scale:!0,category:"people"},handshake:{keywords:["agreement","shake"],char:"\u{1f91d}",fitzpatrick_scale:!1,category:"people"},point_up:{keywords:["hand","fingers","direction","up"],char:"\u261d",fitzpatrick_scale:!0,category:"people"},point_up_2:{keywords:["fingers","hand","direction","up"],char:"\u{1f446}",fitzpatrick_scale:!0,category:"people"},point_down:{keywords:["fingers","hand","direction","down"],char:"\u{1f447}",fitzpatrick_scale:!0,category:"people"},point_left:{keywords:["direction","fingers","hand","left"],char:"\u{1f448}",fitzpatrick_scale:!0,category:"people"},point_right:{keywords:["fingers","hand","direction","right"],char:"\u{1f449}",fitzpatrick_scale:!0,category:"people"},fu:{keywords:["hand","fingers","rude","middle","flipping"],char:"\u{1f595}",fitzpatrick_scale:!0,category:"people"},raised_hand_with_fingers_splayed:{keywords:["hand","fingers","palm"],char:"\u{1f590}",fitzpatrick_scale:!0,category:"people"},love_you:{keywords:["hand","fingers","gesture"],char:"\u{1f91f}",fitzpatrick_scale:!0,category:"people"},metal:{keywords:["hand","fingers","evil_eye","sign_of_horns","rock_on"],char:"\u{1f918}",fitzpatrick_scale:!0,category:"people"},crossed_fingers:{keywords:["good","lucky"],char:"\u{1f91e}",fitzpatrick_scale:!0,category:"people"},vulcan_salute:{keywords:["hand","fingers","spock","star trek"],char:"\u{1f596}",fitzpatrick_scale:!0,category:"people"},writing_hand:{keywords:["lower_left_ballpoint_pen","stationery","write","compose"],char:"\u270d",fitzpatrick_scale:!0,category:"people"},selfie:{keywords:["camera","phone"],char:"\u{1f933}",fitzpatrick_scale:!0,category:"people"},nail_care:{keywords:["beauty","manicure","finger","fashion","nail"],char:"\u{1f485}",fitzpatrick_scale:!0,category:"people"},lips:{keywords:["mouth","kiss"],char:"\u{1f444}",fitzpatrick_scale:!1,category:"people"},tooth:{keywords:["teeth","dentist"],char:"\u{1f9b7}",fitzpatrick_scale:!1,category:"people"},tongue:{keywords:["mouth","playful"],char:"\u{1f445}",fitzpatrick_scale:!1,category:"people"},ear:{keywords:["face","hear","sound","listen"],char:"\u{1f442}",fitzpatrick_scale:!0,category:"people"},nose:{keywords:["smell","sniff"],char:"\u{1f443}",fitzpatrick_scale:!0,category:"people"},eye:{keywords:["face","look","see","watch","stare"],char:"\u{1f441}",fitzpatrick_scale:!1,category:"people"},eyes:{keywords:["look","watch","stalk","peek","see"],char:"\u{1f440}",fitzpatrick_scale:!1,category:"people"},brain:{keywords:["smart","intelligent"],char:"\u{1f9e0}",fitzpatrick_scale:!1,category:"people"},bust_in_silhouette:{keywords:["user","person","human"],char:"\u{1f464}",fitzpatrick_scale:!1,category:"people"},busts_in_silhouette:{keywords:["user","person","human","group","team"],char:"\u{1f465}",fitzpatrick_scale:!1,category:"people"},speaking_head:{keywords:["user","person","human","sing","say","talk"],char:"\u{1f5e3}",fitzpatrick_scale:!1,category:"people"},baby:{keywords:["child","boy","girl","toddler"],char:"\u{1f476}",fitzpatrick_scale:!0,category:"people"},child:{keywords:["gender-neutral","young"],char:"\u{1f9d2}",fitzpatrick_scale:!0,category:"people"},boy:{keywords:["man","male","guy","teenager"],char:"\u{1f466}",fitzpatrick_scale:!0,category:"people"},girl:{keywords:["female","woman","teenager"],char:"\u{1f467}",fitzpatrick_scale:!0,category:"people"},adult:{keywords:["gender-neutral","person"],char:"\u{1f9d1}",fitzpatrick_scale:!0,category:"people"},man:{keywords:["mustache","father","dad","guy","classy","sir","moustache"],char:"\u{1f468}",fitzpatrick_scale:!0,category:"people"},woman:{keywords:["female","girls","lady"],char:"\u{1f469}",fitzpatrick_scale:!0,category:"people"},blonde_woman:{keywords:["woman","female","girl","blonde","person"],char:"\u{1f471}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},blonde_man:{keywords:["man","male","boy","blonde","guy","person"],char:"\u{1f471}",fitzpatrick_scale:!0,category:"people"},bearded_person:{keywords:["person","bewhiskered"],char:"\u{1f9d4}",fitzpatrick_scale:!0,category:"people"},older_adult:{keywords:["human","elder","senior","gender-neutral"],char:"\u{1f9d3}",fitzpatrick_scale:!0,category:"people"},older_man:{keywords:["human","male","men","old","elder","senior"],char:"\u{1f474}",fitzpatrick_scale:!0,category:"people"},older_woman:{keywords:["human","female","women","lady","old","elder","senior"],char:"\u{1f475}",fitzpatrick_scale:!0,category:"people"},man_with_gua_pi_mao:{keywords:["male","boy","chinese"],char:"\u{1f472}",fitzpatrick_scale:!0,category:"people"},woman_with_headscarf:{keywords:["female","hijab","mantilla","tichel"],char:"\u{1f9d5}",fitzpatrick_scale:!0,category:"people"},woman_with_turban:{keywords:["female","indian","hinduism","arabs","woman"],char:"\u{1f473}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_with_turban:{keywords:["male","indian","hinduism","arabs"],char:"\u{1f473}",fitzpatrick_scale:!0,category:"people"},policewoman:{keywords:["woman","police","law","legal","enforcement","arrest","911","female"],char:"\u{1f46e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},policeman:{keywords:["man","police","law","legal","enforcement","arrest","911"],char:"\u{1f46e}",fitzpatrick_scale:!0,category:"people"},construction_worker_woman:{keywords:["female","human","wip","build","construction","worker","labor","woman"],char:"\u{1f477}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},construction_worker_man:{keywords:["male","human","wip","guy","build","construction","worker","labor"],char:"\u{1f477}",fitzpatrick_scale:!0,category:"people"},guardswoman:{keywords:["uk","gb","british","female","royal","woman"],char:"\u{1f482}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},guardsman:{keywords:["uk","gb","british","male","guy","royal"],char:"\u{1f482}",fitzpatrick_scale:!0,category:"people"},female_detective:{keywords:["human","spy","detective","female","woman"],char:"\u{1f575}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},male_detective:{keywords:["human","spy","detective"],char:"\u{1f575}",fitzpatrick_scale:!0,category:"people"},woman_health_worker:{keywords:["doctor","nurse","therapist","healthcare","woman","human"],char:"\u{1f469}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},man_health_worker:{keywords:["doctor","nurse","therapist","healthcare","man","human"],char:"\u{1f468}\u200d\u2695\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_farmer:{keywords:["rancher","gardener","woman","human"],char:"\u{1f469}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},man_farmer:{keywords:["rancher","gardener","man","human"],char:"\u{1f468}\u200d\u{1f33e}",fitzpatrick_scale:!0,category:"people"},woman_cook:{keywords:["chef","woman","human"],char:"\u{1f469}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},man_cook:{keywords:["chef","man","human"],char:"\u{1f468}\u200d\u{1f373}",fitzpatrick_scale:!0,category:"people"},woman_student:{keywords:["graduate","woman","human"],char:"\u{1f469}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},man_student:{keywords:["graduate","man","human"],char:"\u{1f468}\u200d\u{1f393}",fitzpatrick_scale:!0,category:"people"},woman_singer:{keywords:["rockstar","entertainer","woman","human"],char:"\u{1f469}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},man_singer:{keywords:["rockstar","entertainer","man","human"],char:"\u{1f468}\u200d\u{1f3a4}",fitzpatrick_scale:!0,category:"people"},woman_teacher:{keywords:["instructor","professor","woman","human"],char:"\u{1f469}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},man_teacher:{keywords:["instructor","professor","man","human"],char:"\u{1f468}\u200d\u{1f3eb}",fitzpatrick_scale:!0,category:"people"},woman_factory_worker:{keywords:["assembly","industrial","woman","human"],char:"\u{1f469}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},man_factory_worker:{keywords:["assembly","industrial","man","human"],char:"\u{1f468}\u200d\u{1f3ed}",fitzpatrick_scale:!0,category:"people"},woman_technologist:{keywords:["coder","developer","engineer","programmer","software","woman","human","laptop","computer"],char:"\u{1f469}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},man_technologist:{keywords:["coder","developer","engineer","programmer","software","man","human","laptop","computer"],char:"\u{1f468}\u200d\u{1f4bb}",fitzpatrick_scale:!0,category:"people"},woman_office_worker:{keywords:["business","manager","woman","human"],char:"\u{1f469}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},man_office_worker:{keywords:["business","manager","man","human"],char:"\u{1f468}\u200d\u{1f4bc}",fitzpatrick_scale:!0,category:"people"},woman_mechanic:{keywords:["plumber","woman","human","wrench"],char:"\u{1f469}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},man_mechanic:{keywords:["plumber","man","human","wrench"],char:"\u{1f468}\u200d\u{1f527}",fitzpatrick_scale:!0,category:"people"},woman_scientist:{keywords:["biologist","chemist","engineer","physicist","woman","human"],char:"\u{1f469}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},man_scientist:{keywords:["biologist","chemist","engineer","physicist","man","human"],char:"\u{1f468}\u200d\u{1f52c}",fitzpatrick_scale:!0,category:"people"},woman_artist:{keywords:["painter","woman","human"],char:"\u{1f469}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},man_artist:{keywords:["painter","man","human"],char:"\u{1f468}\u200d\u{1f3a8}",fitzpatrick_scale:!0,category:"people"},woman_firefighter:{keywords:["fireman","woman","human"],char:"\u{1f469}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},man_firefighter:{keywords:["fireman","man","human"],char:"\u{1f468}\u200d\u{1f692}",fitzpatrick_scale:!0,category:"people"},woman_pilot:{keywords:["aviator","plane","woman","human"],char:"\u{1f469}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},man_pilot:{keywords:["aviator","plane","man","human"],char:"\u{1f468}\u200d\u2708\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_astronaut:{keywords:["space","rocket","woman","human"],char:"\u{1f469}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},man_astronaut:{keywords:["space","rocket","man","human"],char:"\u{1f468}\u200d\u{1f680}",fitzpatrick_scale:!0,category:"people"},woman_judge:{keywords:["justice","court","woman","human"],char:"\u{1f469}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},man_judge:{keywords:["justice","court","man","human"],char:"\u{1f468}\u200d\u2696\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_superhero:{keywords:["woman","female","good","heroine","superpowers"],char:"\u{1f9b8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_superhero:{keywords:["man","male","good","hero","superpowers"],char:"\u{1f9b8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_supervillain:{keywords:["woman","female","evil","bad","criminal","heroine","superpowers"],char:"\u{1f9b9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_supervillain:{keywords:["man","male","evil","bad","criminal","hero","superpowers"],char:"\u{1f9b9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},mrs_claus:{keywords:["woman","female","xmas","mother christmas"],char:"\u{1f936}",fitzpatrick_scale:!0,category:"people"},santa:{keywords:["festival","man","male","xmas","father christmas"],char:"\u{1f385}",fitzpatrick_scale:!0,category:"people"},sorceress:{keywords:["woman","female","mage","witch"],char:"\u{1f9d9}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},wizard:{keywords:["man","male","mage","sorcerer"],char:"\u{1f9d9}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_elf:{keywords:["woman","female"],char:"\u{1f9dd}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_elf:{keywords:["man","male"],char:"\u{1f9dd}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_vampire:{keywords:["woman","female"],char:"\u{1f9db}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_vampire:{keywords:["man","male","dracula"],char:"\u{1f9db}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_zombie:{keywords:["woman","female","undead","walking dead"],char:"\u{1f9df}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_zombie:{keywords:["man","male","dracula","undead","walking dead"],char:"\u{1f9df}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},woman_genie:{keywords:["woman","female"],char:"\u{1f9de}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"people"},man_genie:{keywords:["man","male"],char:"\u{1f9de}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},mermaid:{keywords:["woman","female","merwoman","ariel"],char:"\u{1f9dc}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},merman:{keywords:["man","male","triton"],char:"\u{1f9dc}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_fairy:{keywords:["woman","female"],char:"\u{1f9da}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_fairy:{keywords:["man","male"],char:"\u{1f9da}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},angel:{keywords:["heaven","wings","halo"],char:"\u{1f47c}",fitzpatrick_scale:!0,category:"people"},pregnant_woman:{keywords:["baby"],char:"\u{1f930}",fitzpatrick_scale:!0,category:"people"},breastfeeding:{keywords:["nursing","baby"],char:"\u{1f931}",fitzpatrick_scale:!0,category:"people"},princess:{keywords:["girl","woman","female","blond","crown","royal","queen"],char:"\u{1f478}",fitzpatrick_scale:!0,category:"people"},prince:{keywords:["boy","man","male","crown","royal","king"],char:"\u{1f934}",fitzpatrick_scale:!0,category:"people"},bride_with_veil:{keywords:["couple","marriage","wedding","woman","bride"],char:"\u{1f470}",fitzpatrick_scale:!0,category:"people"},man_in_tuxedo:{keywords:["couple","marriage","wedding","groom"],char:"\u{1f935}",fitzpatrick_scale:!0,category:"people"},running_woman:{keywords:["woman","walking","exercise","race","running","female"],char:"\u{1f3c3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},running_man:{keywords:["man","walking","exercise","race","running"],char:"\u{1f3c3}",fitzpatrick_scale:!0,category:"people"},walking_woman:{keywords:["human","feet","steps","woman","female"],char:"\u{1f6b6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},walking_man:{keywords:["human","feet","steps"],char:"\u{1f6b6}",fitzpatrick_scale:!0,category:"people"},dancer:{keywords:["female","girl","woman","fun"],char:"\u{1f483}",fitzpatrick_scale:!0,category:"people"},man_dancing:{keywords:["male","boy","fun","dancer"],char:"\u{1f57a}",fitzpatrick_scale:!0,category:"people"},dancing_women:{keywords:["female","bunny","women","girls"],char:"\u{1f46f}",fitzpatrick_scale:!1,category:"people"},dancing_men:{keywords:["male","bunny","men","boys"],char:"\u{1f46f}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"people"},couple:{keywords:["pair","people","human","love","date","dating","like","affection","valentines","marriage"],char:"\u{1f46b}",fitzpatrick_scale:!1,category:"people"},two_men_holding_hands:{keywords:["pair","couple","love","like","bromance","friendship","people","human"],char:"\u{1f46c}",fitzpatrick_scale:!1,category:"people"},two_women_holding_hands:{keywords:["pair","friendship","couple","love","like","female","people","human"],char:"\u{1f46d}",fitzpatrick_scale:!1,category:"people"},bowing_woman:{keywords:["woman","female","girl"],char:"\u{1f647}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},bowing_man:{keywords:["man","male","boy"],char:"\u{1f647}",fitzpatrick_scale:!0,category:"people"},man_facepalming:{keywords:["man","male","boy","disbelief"],char:"\u{1f926}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_facepalming:{keywords:["woman","female","girl","disbelief"],char:"\u{1f926}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_shrugging:{keywords:["woman","female","girl","confused","indifferent","doubt"],char:"\u{1f937}",fitzpatrick_scale:!0,category:"people"},man_shrugging:{keywords:["man","male","boy","confused","indifferent","doubt"],char:"\u{1f937}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},tipping_hand_woman:{keywords:["female","girl","woman","human","information"],char:"\u{1f481}",fitzpatrick_scale:!0,category:"people"},tipping_hand_man:{keywords:["male","boy","man","human","information"],char:"\u{1f481}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},no_good_woman:{keywords:["female","girl","woman","nope"],char:"\u{1f645}",fitzpatrick_scale:!0,category:"people"},no_good_man:{keywords:["male","boy","man","nope"],char:"\u{1f645}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},ok_woman:{keywords:["women","girl","female","pink","human","woman"],char:"\u{1f646}",fitzpatrick_scale:!0,category:"people"},ok_man:{keywords:["men","boy","male","blue","human","man"],char:"\u{1f646}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},raising_hand_woman:{keywords:["female","girl","woman"],char:"\u{1f64b}",fitzpatrick_scale:!0,category:"people"},raising_hand_man:{keywords:["male","boy","man"],char:"\u{1f64b}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},pouting_woman:{keywords:["female","girl","woman"],char:"\u{1f64e}",fitzpatrick_scale:!0,category:"people"},pouting_man:{keywords:["male","boy","man"],char:"\u{1f64e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},frowning_woman:{keywords:["female","girl","woman","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}",fitzpatrick_scale:!0,category:"people"},frowning_man:{keywords:["male","boy","man","sad","depressed","discouraged","unhappy"],char:"\u{1f64d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},haircut_woman:{keywords:["female","girl","woman"],char:"\u{1f487}",fitzpatrick_scale:!0,category:"people"},haircut_man:{keywords:["male","boy","man"],char:"\u{1f487}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},massage_woman:{keywords:["female","girl","woman","head"],char:"\u{1f486}",fitzpatrick_scale:!0,category:"people"},massage_man:{keywords:["male","boy","man","head"],char:"\u{1f486}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},woman_in_steamy_room:{keywords:["female","woman","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"people"},man_in_steamy_room:{keywords:["male","man","spa","steamroom","sauna"],char:"\u{1f9d6}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"people"},couple_with_heart_woman_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f491}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_woman_woman:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couple_with_heart_man_man:{keywords:["pair","love","like","affection","human","dating","valentines","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f48f}",fitzpatrick_scale:!1,category:"people"},couplekiss_woman_woman:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f469}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f469}",fitzpatrick_scale:!1,category:"people"},couplekiss_man_man:{keywords:["pair","valentines","love","like","dating","marriage"],char:"\u{1f468}\u200d\u2764\ufe0f\u200d\u{1f48b}\u200d\u{1f468}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy:{keywords:["home","parents","child","mom","dad","father","mother","people","human"],char:"\u{1f46a}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl:{keywords:["home","parents","people","human","child"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_woman_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f469}\u200d\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_boy_boy:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_man_girl_girl:{keywords:["home","parents","people","human","children"],char:"\u{1f468}\u200d\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f469}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_woman_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f469}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_boy:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl:{keywords:["home","parent","people","human","child"],char:"\u{1f468}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},family_man_girl_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_boy_boy:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f466}\u200d\u{1f466}",fitzpatrick_scale:!1,category:"people"},family_man_girl_girl:{keywords:["home","parent","people","human","children"],char:"\u{1f468}\u200d\u{1f467}\u200d\u{1f467}",fitzpatrick_scale:!1,category:"people"},yarn:{keywords:["ball","crochet","knit"],char:"\u{1f9f6}",fitzpatrick_scale:!1,category:"people"},thread:{keywords:["needle","sewing","spool","string"],char:"\u{1f9f5}",fitzpatrick_scale:!1,category:"people"},coat:{keywords:["jacket"],char:"\u{1f9e5}",fitzpatrick_scale:!1,category:"people"},labcoat:{keywords:["doctor","experiment","scientist","chemist"],char:"\u{1f97c}",fitzpatrick_scale:!1,category:"people"},womans_clothes:{keywords:["fashion","shopping_bags","female"],char:"\u{1f45a}",fitzpatrick_scale:!1,category:"people"},tshirt:{keywords:["fashion","cloth","casual","shirt","tee"],char:"\u{1f455}",fitzpatrick_scale:!1,category:"people"},jeans:{keywords:["fashion","shopping"],char:"\u{1f456}",fitzpatrick_scale:!1,category:"people"},necktie:{keywords:["shirt","suitup","formal","fashion","cloth","business"],char:"\u{1f454}",fitzpatrick_scale:!1,category:"people"},dress:{keywords:["clothes","fashion","shopping"],char:"\u{1f457}",fitzpatrick_scale:!1,category:"people"},bikini:{keywords:["swimming","female","woman","girl","fashion","beach","summer"],char:"\u{1f459}",fitzpatrick_scale:!1,category:"people"},kimono:{keywords:["dress","fashion","women","female","japanese"],char:"\u{1f458}",fitzpatrick_scale:!1,category:"people"},lipstick:{keywords:["female","girl","fashion","woman"],char:"\u{1f484}",fitzpatrick_scale:!1,category:"people"},kiss:{keywords:["face","lips","love","like","affection","valentines"],char:"\u{1f48b}",fitzpatrick_scale:!1,category:"people"},footprints:{keywords:["feet","tracking","walking","beach"],char:"\u{1f463}",fitzpatrick_scale:!1,category:"people"},flat_shoe:{keywords:["ballet","slip-on","slipper"],char:"\u{1f97f}",fitzpatrick_scale:!1,category:"people"},high_heel:{keywords:["fashion","shoes","female","pumps","stiletto"],char:"\u{1f460}",fitzpatrick_scale:!1,category:"people"},sandal:{keywords:["shoes","fashion","flip flops"],char:"\u{1f461}",fitzpatrick_scale:!1,category:"people"},boot:{keywords:["shoes","fashion"],char:"\u{1f462}",fitzpatrick_scale:!1,category:"people"},mans_shoe:{keywords:["fashion","male"],char:"\u{1f45e}",fitzpatrick_scale:!1,category:"people"},athletic_shoe:{keywords:["shoes","sports","sneakers"],char:"\u{1f45f}",fitzpatrick_scale:!1,category:"people"},hiking_boot:{keywords:["backpacking","camping","hiking"],char:"\u{1f97e}",fitzpatrick_scale:!1,category:"people"},socks:{keywords:["stockings","clothes"],char:"\u{1f9e6}",fitzpatrick_scale:!1,category:"people"},gloves:{keywords:["hands","winter","clothes"],char:"\u{1f9e4}",fitzpatrick_scale:!1,category:"people"},scarf:{keywords:["neck","winter","clothes"],char:"\u{1f9e3}",fitzpatrick_scale:!1,category:"people"},womans_hat:{keywords:["fashion","accessories","female","lady","spring"],char:"\u{1f452}",fitzpatrick_scale:!1,category:"people"},tophat:{keywords:["magic","gentleman","classy","circus"],char:"\u{1f3a9}",fitzpatrick_scale:!1,category:"people"},billed_hat:{keywords:["cap","baseball"],char:"\u{1f9e2}",fitzpatrick_scale:!1,category:"people"},rescue_worker_helmet:{keywords:["construction","build"],char:"\u26d1",fitzpatrick_scale:!1,category:"people"},mortar_board:{keywords:["school","college","degree","university","graduation","cap","hat","legal","learn","education"],char:"\u{1f393}",fitzpatrick_scale:!1,category:"people"},crown:{keywords:["king","kod","leader","royalty","lord"],char:"\u{1f451}",fitzpatrick_scale:!1,category:"people"},school_satchel:{keywords:["student","education","bag","backpack"],char:"\u{1f392}",fitzpatrick_scale:!1,category:"people"},luggage:{keywords:["packing","travel"],char:"\u{1f9f3}",fitzpatrick_scale:!1,category:"people"},pouch:{keywords:["bag","accessories","shopping"],char:"\u{1f45d}",fitzpatrick_scale:!1,category:"people"},purse:{keywords:["fashion","accessories","money","sales","shopping"],char:"\u{1f45b}",fitzpatrick_scale:!1,category:"people"},handbag:{keywords:["fashion","accessory","accessories","shopping"],char:"\u{1f45c}",fitzpatrick_scale:!1,category:"people"},briefcase:{keywords:["business","documents","work","law","legal","job","career"],char:"\u{1f4bc}",fitzpatrick_scale:!1,category:"people"},eyeglasses:{keywords:["fashion","accessories","eyesight","nerdy","dork","geek"],char:"\u{1f453}",fitzpatrick_scale:!1,category:"people"},dark_sunglasses:{keywords:["face","cool","accessories"],char:"\u{1f576}",fitzpatrick_scale:!1,category:"people"},goggles:{keywords:["eyes","protection","safety"],char:"\u{1f97d}",fitzpatrick_scale:!1,category:"people"},ring:{keywords:["wedding","propose","marriage","valentines","diamond","fashion","jewelry","gem","engagement"],char:"\u{1f48d}",fitzpatrick_scale:!1,category:"people"},closed_umbrella:{keywords:["weather","rain","drizzle"],char:"\u{1f302}",fitzpatrick_scale:!1,category:"people"},dog:{keywords:["animal","friend","nature","woof","puppy","pet","faithful"],char:"\u{1f436}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat:{keywords:["animal","meow","nature","pet","kitten"],char:"\u{1f431}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse:{keywords:["animal","nature","cheese_wedge","rodent"],char:"\u{1f42d}",fitzpatrick_scale:!1,category:"animals_and_nature"},hamster:{keywords:["animal","nature"],char:"\u{1f439}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit:{keywords:["animal","nature","pet","spring","magic","bunny"],char:"\u{1f430}",fitzpatrick_scale:!1,category:"animals_and_nature"},fox_face:{keywords:["animal","nature","face"],char:"\u{1f98a}",fitzpatrick_scale:!1,category:"animals_and_nature"},bear:{keywords:["animal","nature","wild"],char:"\u{1f43b}",fitzpatrick_scale:!1,category:"animals_and_nature"},panda_face:{keywords:["animal","nature","panda"],char:"\u{1f43c}",fitzpatrick_scale:!1,category:"animals_and_nature"},koala:{keywords:["animal","nature"],char:"\u{1f428}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger:{keywords:["animal","cat","danger","wild","nature","roar"],char:"\u{1f42f}",fitzpatrick_scale:!1,category:"animals_and_nature"},lion:{keywords:["animal","nature"],char:"\u{1f981}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f42e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig:{keywords:["animal","oink","nature"],char:"\u{1f437}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig_nose:{keywords:["animal","oink"],char:"\u{1f43d}",fitzpatrick_scale:!1,category:"animals_and_nature"},frog:{keywords:["animal","nature","croak","toad"],char:"\u{1f438}",fitzpatrick_scale:!1,category:"animals_and_nature"},squid:{keywords:["animal","nature","ocean","sea"],char:"\u{1f991}",fitzpatrick_scale:!1,category:"animals_and_nature"},octopus:{keywords:["animal","creature","ocean","sea","nature","beach"],char:"\u{1f419}",fitzpatrick_scale:!1,category:"animals_and_nature"},shrimp:{keywords:["animal","ocean","nature","seafood"],char:"\u{1f990}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey_face:{keywords:["animal","nature","circus"],char:"\u{1f435}",fitzpatrick_scale:!1,category:"animals_and_nature"},gorilla:{keywords:["animal","nature","circus"],char:"\u{1f98d}",fitzpatrick_scale:!1,category:"animals_and_nature"},see_no_evil:{keywords:["monkey","animal","nature","haha"],char:"\u{1f648}",fitzpatrick_scale:!1,category:"animals_and_nature"},hear_no_evil:{keywords:["animal","monkey","nature"],char:"\u{1f649}",fitzpatrick_scale:!1,category:"animals_and_nature"},speak_no_evil:{keywords:["monkey","animal","nature","omg"],char:"\u{1f64a}",fitzpatrick_scale:!1,category:"animals_and_nature"},monkey:{keywords:["animal","nature","banana","circus"],char:"\u{1f412}",fitzpatrick_scale:!1,category:"animals_and_nature"},chicken:{keywords:["animal","cluck","nature","bird"],char:"\u{1f414}",fitzpatrick_scale:!1,category:"animals_and_nature"},penguin:{keywords:["animal","nature"],char:"\u{1f427}",fitzpatrick_scale:!1,category:"animals_and_nature"},bird:{keywords:["animal","nature","fly","tweet","spring"],char:"\u{1f426}",fitzpatrick_scale:!1,category:"animals_and_nature"},baby_chick:{keywords:["animal","chicken","bird"],char:"\u{1f424}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatching_chick:{keywords:["animal","chicken","egg","born","baby","bird"],char:"\u{1f423}",fitzpatrick_scale:!1,category:"animals_and_nature"},hatched_chick:{keywords:["animal","chicken","baby","bird"],char:"\u{1f425}",fitzpatrick_scale:!1,category:"animals_and_nature"},duck:{keywords:["animal","nature","bird","mallard"],char:"\u{1f986}",fitzpatrick_scale:!1,category:"animals_and_nature"},eagle:{keywords:["animal","nature","bird"],char:"\u{1f985}",fitzpatrick_scale:!1,category:"animals_and_nature"},owl:{keywords:["animal","nature","bird","hoot"],char:"\u{1f989}",fitzpatrick_scale:!1,category:"animals_and_nature"},bat:{keywords:["animal","nature","blind","vampire"],char:"\u{1f987}",fitzpatrick_scale:!1,category:"animals_and_nature"},wolf:{keywords:["animal","nature","wild"],char:"\u{1f43a}",fitzpatrick_scale:!1,category:"animals_and_nature"},boar:{keywords:["animal","nature"],char:"\u{1f417}",fitzpatrick_scale:!1,category:"animals_and_nature"},horse:{keywords:["animal","brown","nature"],char:"\u{1f434}",fitzpatrick_scale:!1,category:"animals_and_nature"},unicorn:{keywords:["animal","nature","mystical"],char:"\u{1f984}",fitzpatrick_scale:!1,category:"animals_and_nature"},honeybee:{keywords:["animal","insect","nature","bug","spring","honey"],char:"\u{1f41d}",fitzpatrick_scale:!1,category:"animals_and_nature"},bug:{keywords:["animal","insect","nature","worm"],char:"\u{1f41b}",fitzpatrick_scale:!1,category:"animals_and_nature"},butterfly:{keywords:["animal","insect","nature","caterpillar"],char:"\u{1f98b}",fitzpatrick_scale:!1,category:"animals_and_nature"},snail:{keywords:["slow","animal","shell"],char:"\u{1f40c}",fitzpatrick_scale:!1,category:"animals_and_nature"},beetle:{keywords:["animal","insect","nature","ladybug"],char:"\u{1f41e}",fitzpatrick_scale:!1,category:"animals_and_nature"},ant:{keywords:["animal","insect","nature","bug"],char:"\u{1f41c}",fitzpatrick_scale:!1,category:"animals_and_nature"},grasshopper:{keywords:["animal","cricket","chirp"],char:"\u{1f997}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider:{keywords:["animal","arachnid"],char:"\u{1f577}",fitzpatrick_scale:!1,category:"animals_and_nature"},scorpion:{keywords:["animal","arachnid"],char:"\u{1f982}",fitzpatrick_scale:!1,category:"animals_and_nature"},crab:{keywords:["animal","crustacean"],char:"\u{1f980}",fitzpatrick_scale:!1,category:"animals_and_nature"},snake:{keywords:["animal","evil","nature","hiss","python"],char:"\u{1f40d}",fitzpatrick_scale:!1,category:"animals_and_nature"},lizard:{keywords:["animal","nature","reptile"],char:"\u{1f98e}",fitzpatrick_scale:!1,category:"animals_and_nature"},"t-rex":{keywords:["animal","nature","dinosaur","tyrannosaurus","extinct"],char:"\u{1f996}",fitzpatrick_scale:!1,category:"animals_and_nature"},sauropod:{keywords:["animal","nature","dinosaur","brachiosaurus","brontosaurus","diplodocus","extinct"],char:"\u{1f995}",fitzpatrick_scale:!1,category:"animals_and_nature"},turtle:{keywords:["animal","slow","nature","tortoise"],char:"\u{1f422}",fitzpatrick_scale:!1,category:"animals_and_nature"},tropical_fish:{keywords:["animal","swim","ocean","beach","nemo"],char:"\u{1f420}",fitzpatrick_scale:!1,category:"animals_and_nature"},fish:{keywords:["animal","food","nature"],char:"\u{1f41f}",fitzpatrick_scale:!1,category:"animals_and_nature"},blowfish:{keywords:["animal","nature","food","sea","ocean"],char:"\u{1f421}",fitzpatrick_scale:!1,category:"animals_and_nature"},dolphin:{keywords:["animal","nature","fish","sea","ocean","flipper","fins","beach"],char:"\u{1f42c}",fitzpatrick_scale:!1,category:"animals_and_nature"},shark:{keywords:["animal","nature","fish","sea","ocean","jaws","fins","beach"],char:"\u{1f988}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale:{keywords:["animal","nature","sea","ocean"],char:"\u{1f433}",fitzpatrick_scale:!1,category:"animals_and_nature"},whale2:{keywords:["animal","nature","sea","ocean"],char:"\u{1f40b}",fitzpatrick_scale:!1,category:"animals_and_nature"},crocodile:{keywords:["animal","nature","reptile","lizard","alligator"],char:"\u{1f40a}",fitzpatrick_scale:!1,category:"animals_and_nature"},leopard:{keywords:["animal","nature"],char:"\u{1f406}",fitzpatrick_scale:!1,category:"animals_and_nature"},zebra:{keywords:["animal","nature","stripes","safari"],char:"\u{1f993}",fitzpatrick_scale:!1,category:"animals_and_nature"},tiger2:{keywords:["animal","nature","roar"],char:"\u{1f405}",fitzpatrick_scale:!1,category:"animals_and_nature"},water_buffalo:{keywords:["animal","nature","ox","cow"],char:"\u{1f403}",fitzpatrick_scale:!1,category:"animals_and_nature"},ox:{keywords:["animal","cow","beef"],char:"\u{1f402}",fitzpatrick_scale:!1,category:"animals_and_nature"},cow2:{keywords:["beef","ox","animal","nature","moo","milk"],char:"\u{1f404}",fitzpatrick_scale:!1,category:"animals_and_nature"},deer:{keywords:["animal","nature","horns","venison"],char:"\u{1f98c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dromedary_camel:{keywords:["animal","hot","desert","hump"],char:"\u{1f42a}",fitzpatrick_scale:!1,category:"animals_and_nature"},camel:{keywords:["animal","nature","hot","desert","hump"],char:"\u{1f42b}",fitzpatrick_scale:!1,category:"animals_and_nature"},giraffe:{keywords:["animal","nature","spots","safari"],char:"\u{1f992}",fitzpatrick_scale:!1,category:"animals_and_nature"},elephant:{keywords:["animal","nature","nose","th","circus"],char:"\u{1f418}",fitzpatrick_scale:!1,category:"animals_and_nature"},rhinoceros:{keywords:["animal","nature","horn"],char:"\u{1f98f}",fitzpatrick_scale:!1,category:"animals_and_nature"},goat:{keywords:["animal","nature"],char:"\u{1f410}",fitzpatrick_scale:!1,category:"animals_and_nature"},ram:{keywords:["animal","sheep","nature"],char:"\u{1f40f}",fitzpatrick_scale:!1,category:"animals_and_nature"},sheep:{keywords:["animal","nature","wool","shipit"],char:"\u{1f411}",fitzpatrick_scale:!1,category:"animals_and_nature"},racehorse:{keywords:["animal","gamble","luck"],char:"\u{1f40e}",fitzpatrick_scale:!1,category:"animals_and_nature"},pig2:{keywords:["animal","nature"],char:"\u{1f416}",fitzpatrick_scale:!1,category:"animals_and_nature"},rat:{keywords:["animal","mouse","rodent"],char:"\u{1f400}",fitzpatrick_scale:!1,category:"animals_and_nature"},mouse2:{keywords:["animal","nature","rodent"],char:"\u{1f401}",fitzpatrick_scale:!1,category:"animals_and_nature"},rooster:{keywords:["animal","nature","chicken"],char:"\u{1f413}",fitzpatrick_scale:!1,category:"animals_and_nature"},turkey:{keywords:["animal","bird"],char:"\u{1f983}",fitzpatrick_scale:!1,category:"animals_and_nature"},dove:{keywords:["animal","bird"],char:"\u{1f54a}",fitzpatrick_scale:!1,category:"animals_and_nature"},dog2:{keywords:["animal","nature","friend","doge","pet","faithful"],char:"\u{1f415}",fitzpatrick_scale:!1,category:"animals_and_nature"},poodle:{keywords:["dog","animal","101","nature","pet"],char:"\u{1f429}",fitzpatrick_scale:!1,category:"animals_and_nature"},cat2:{keywords:["animal","meow","pet","cats"],char:"\u{1f408}",fitzpatrick_scale:!1,category:"animals_and_nature"},rabbit2:{keywords:["animal","nature","pet","magic","spring"],char:"\u{1f407}",fitzpatrick_scale:!1,category:"animals_and_nature"},chipmunk:{keywords:["animal","nature","rodent","squirrel"],char:"\u{1f43f}",fitzpatrick_scale:!1,category:"animals_and_nature"},hedgehog:{keywords:["animal","nature","spiny"],char:"\u{1f994}",fitzpatrick_scale:!1,category:"animals_and_nature"},raccoon:{keywords:["animal","nature"],char:"\u{1f99d}",fitzpatrick_scale:!1,category:"animals_and_nature"},llama:{keywords:["animal","nature","alpaca"],char:"\u{1f999}",fitzpatrick_scale:!1,category:"animals_and_nature"},hippopotamus:{keywords:["animal","nature"],char:"\u{1f99b}",fitzpatrick_scale:!1,category:"animals_and_nature"},kangaroo:{keywords:["animal","nature","australia","joey","hop","marsupial"],char:"\u{1f998}",fitzpatrick_scale:!1,category:"animals_and_nature"},badger:{keywords:["animal","nature","honey"],char:"\u{1f9a1}",fitzpatrick_scale:!1,category:"animals_and_nature"},swan:{keywords:["animal","nature","bird"],char:"\u{1f9a2}",fitzpatrick_scale:!1,category:"animals_and_nature"},peacock:{keywords:["animal","nature","peahen","bird"],char:"\u{1f99a}",fitzpatrick_scale:!1,category:"animals_and_nature"},parrot:{keywords:["animal","nature","bird","pirate","talk"],char:"\u{1f99c}",fitzpatrick_scale:!1,category:"animals_and_nature"},lobster:{keywords:["animal","nature","bisque","claws","seafood"],char:"\u{1f99e}",fitzpatrick_scale:!1,category:"animals_and_nature"},mosquito:{keywords:["animal","nature","insect","malaria"],char:"\u{1f99f}",fitzpatrick_scale:!1,category:"animals_and_nature"},paw_prints:{keywords:["animal","tracking","footprints","dog","cat","pet","feet"],char:"\u{1f43e}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f409}",fitzpatrick_scale:!1,category:"animals_and_nature"},dragon_face:{keywords:["animal","myth","nature","chinese","green"],char:"\u{1f432}",fitzpatrick_scale:!1,category:"animals_and_nature"},cactus:{keywords:["vegetable","plant","nature"],char:"\u{1f335}",fitzpatrick_scale:!1,category:"animals_and_nature"},christmas_tree:{keywords:["festival","vacation","december","xmas","celebration"],char:"\u{1f384}",fitzpatrick_scale:!1,category:"animals_and_nature"},evergreen_tree:{keywords:["plant","nature"],char:"\u{1f332}",fitzpatrick_scale:!1,category:"animals_and_nature"},deciduous_tree:{keywords:["plant","nature"],char:"\u{1f333}",fitzpatrick_scale:!1,category:"animals_and_nature"},palm_tree:{keywords:["plant","vegetable","nature","summer","beach","mojito","tropical"],char:"\u{1f334}",fitzpatrick_scale:!1,category:"animals_and_nature"},seedling:{keywords:["plant","nature","grass","lawn","spring"],char:"\u{1f331}",fitzpatrick_scale:!1,category:"animals_and_nature"},herb:{keywords:["vegetable","plant","medicine","weed","grass","lawn"],char:"\u{1f33f}",fitzpatrick_scale:!1,category:"animals_and_nature"},shamrock:{keywords:["vegetable","plant","nature","irish","clover"],char:"\u2618",fitzpatrick_scale:!1,category:"animals_and_nature"},four_leaf_clover:{keywords:["vegetable","plant","nature","lucky","irish"],char:"\u{1f340}",fitzpatrick_scale:!1,category:"animals_and_nature"},bamboo:{keywords:["plant","nature","vegetable","panda","pine_decoration"],char:"\u{1f38d}",fitzpatrick_scale:!1,category:"animals_and_nature"},tanabata_tree:{keywords:["plant","nature","branch","summer"],char:"\u{1f38b}",fitzpatrick_scale:!1,category:"animals_and_nature"},leaves:{keywords:["nature","plant","tree","vegetable","grass","lawn","spring"],char:"\u{1f343}",fitzpatrick_scale:!1,category:"animals_and_nature"},fallen_leaf:{keywords:["nature","plant","vegetable","leaves"],char:"\u{1f342}",fitzpatrick_scale:!1,category:"animals_and_nature"},maple_leaf:{keywords:["nature","plant","vegetable","ca","fall"],char:"\u{1f341}",fitzpatrick_scale:!1,category:"animals_and_nature"},ear_of_rice:{keywords:["nature","plant"],char:"\u{1f33e}",fitzpatrick_scale:!1,category:"animals_and_nature"},hibiscus:{keywords:["plant","vegetable","flowers","beach"],char:"\u{1f33a}",fitzpatrick_scale:!1,category:"animals_and_nature"},sunflower:{keywords:["nature","plant","fall"],char:"\u{1f33b}",fitzpatrick_scale:!1,category:"animals_and_nature"},rose:{keywords:["flowers","valentines","love","spring"],char:"\u{1f339}",fitzpatrick_scale:!1,category:"animals_and_nature"},wilted_flower:{keywords:["plant","nature","flower"],char:"\u{1f940}",fitzpatrick_scale:!1,category:"animals_and_nature"},tulip:{keywords:["flowers","plant","nature","summer","spring"],char:"\u{1f337}",fitzpatrick_scale:!1,category:"animals_and_nature"},blossom:{keywords:["nature","flowers","yellow"],char:"\u{1f33c}",fitzpatrick_scale:!1,category:"animals_and_nature"},cherry_blossom:{keywords:["nature","plant","spring","flower"],char:"\u{1f338}",fitzpatrick_scale:!1,category:"animals_and_nature"},bouquet:{keywords:["flowers","nature","spring"],char:"\u{1f490}",fitzpatrick_scale:!1,category:"animals_and_nature"},mushroom:{keywords:["plant","vegetable"],char:"\u{1f344}",fitzpatrick_scale:!1,category:"animals_and_nature"},chestnut:{keywords:["food","squirrel"],char:"\u{1f330}",fitzpatrick_scale:!1,category:"animals_and_nature"},jack_o_lantern:{keywords:["halloween","light","pumpkin","creepy","fall"],char:"\u{1f383}",fitzpatrick_scale:!1,category:"animals_and_nature"},shell:{keywords:["nature","sea","beach"],char:"\u{1f41a}",fitzpatrick_scale:!1,category:"animals_and_nature"},spider_web:{keywords:["animal","insect","arachnid","silk"],char:"\u{1f578}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_americas:{keywords:["globe","world","USA","international"],char:"\u{1f30e}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_africa:{keywords:["globe","world","international"],char:"\u{1f30d}",fitzpatrick_scale:!1,category:"animals_and_nature"},earth_asia:{keywords:["globe","world","east","international"],char:"\u{1f30f}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon:{keywords:["nature","yellow","twilight","planet","space","night","evening","sleep"],char:"\u{1f315}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_gibbous_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep","waxing_gibbous_moon"],char:"\u{1f316}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f317}",fitzpatrick_scale:!1,category:"animals_and_nature"},waning_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f318}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f311}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_crescent_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f312}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f313}",fitzpatrick_scale:!1,category:"animals_and_nature"},waxing_gibbous_moon:{keywords:["nature","night","sky","gray","twilight","planet","space","evening","sleep"],char:"\u{1f314}",fitzpatrick_scale:!1,category:"animals_and_nature"},new_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31a}",fitzpatrick_scale:!1,category:"animals_and_nature"},full_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31d}",fitzpatrick_scale:!1,category:"animals_and_nature"},first_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31b}",fitzpatrick_scale:!1,category:"animals_and_nature"},last_quarter_moon_with_face:{keywords:["nature","twilight","planet","space","night","evening","sleep"],char:"\u{1f31c}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_with_face:{keywords:["nature","morning","sky"],char:"\u{1f31e}",fitzpatrick_scale:!1,category:"animals_and_nature"},crescent_moon:{keywords:["night","sleep","sky","evening","magic"],char:"\u{1f319}",fitzpatrick_scale:!1,category:"animals_and_nature"},star:{keywords:["night","yellow"],char:"\u2b50",fitzpatrick_scale:!1,category:"animals_and_nature"},star2:{keywords:["night","sparkle","awesome","good","magic"],char:"\u{1f31f}",fitzpatrick_scale:!1,category:"animals_and_nature"},dizzy:{keywords:["star","sparkle","shoot","magic"],char:"\u{1f4ab}",fitzpatrick_scale:!1,category:"animals_and_nature"},sparkles:{keywords:["stars","shine","shiny","cool","awesome","good","magic"],char:"\u2728",fitzpatrick_scale:!1,category:"animals_and_nature"},comet:{keywords:["space"],char:"\u2604",fitzpatrick_scale:!1,category:"animals_and_nature"},sunny:{keywords:["weather","nature","brightness","summer","beach","spring"],char:"\u2600\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_small_cloud:{keywords:["weather"],char:"\u{1f324}",fitzpatrick_scale:!1,category:"animals_and_nature"},partly_sunny:{keywords:["weather","nature","cloudy","morning","fall","spring"],char:"\u26c5",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_large_cloud:{keywords:["weather"],char:"\u{1f325}",fitzpatrick_scale:!1,category:"animals_and_nature"},sun_behind_rain_cloud:{keywords:["weather"],char:"\u{1f326}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud:{keywords:["weather","sky"],char:"\u2601\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_rain:{keywords:["weather"],char:"\u{1f327}",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning_and_rain:{keywords:["weather","lightning"],char:"\u26c8",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_lightning:{keywords:["weather","thunder"],char:"\u{1f329}",fitzpatrick_scale:!1,category:"animals_and_nature"},zap:{keywords:["thunder","weather","lightning bolt","fast"],char:"\u26a1",fitzpatrick_scale:!1,category:"animals_and_nature"},fire:{keywords:["hot","cook","flame"],char:"\u{1f525}",fitzpatrick_scale:!1,category:"animals_and_nature"},boom:{keywords:["bomb","explode","explosion","collision","blown"],char:"\u{1f4a5}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowflake:{keywords:["winter","season","cold","weather","christmas","xmas"],char:"\u2744\ufe0f",fitzpatrick_scale:!1,category:"animals_and_nature"},cloud_with_snow:{keywords:["weather"],char:"\u{1f328}",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman:{keywords:["winter","season","cold","weather","christmas","xmas","frozen","without_snow"],char:"\u26c4",fitzpatrick_scale:!1,category:"animals_and_nature"},snowman_with_snow:{keywords:["winter","season","cold","weather","christmas","xmas","frozen"],char:"\u2603",fitzpatrick_scale:!1,category:"animals_and_nature"},wind_face:{keywords:["gust","air"],char:"\u{1f32c}",fitzpatrick_scale:!1,category:"animals_and_nature"},dash:{keywords:["wind","air","fast","shoo","fart","smoke","puff"],char:"\u{1f4a8}",fitzpatrick_scale:!1,category:"animals_and_nature"},tornado:{keywords:["weather","cyclone","twister"],char:"\u{1f32a}",fitzpatrick_scale:!1,category:"animals_and_nature"},fog:{keywords:["weather"],char:"\u{1f32b}",fitzpatrick_scale:!1,category:"animals_and_nature"},open_umbrella:{keywords:["weather","spring"],char:"\u2602",fitzpatrick_scale:!1,category:"animals_and_nature"},umbrella:{keywords:["rainy","weather","spring"],char:"\u2614",fitzpatrick_scale:!1,category:"animals_and_nature"},droplet:{keywords:["water","drip","faucet","spring"],char:"\u{1f4a7}",fitzpatrick_scale:!1,category:"animals_and_nature"},sweat_drops:{keywords:["water","drip","oops"],char:"\u{1f4a6}",fitzpatrick_scale:!1,category:"animals_and_nature"},ocean:{keywords:["sea","water","wave","nature","tsunami","disaster"],char:"\u{1f30a}",fitzpatrick_scale:!1,category:"animals_and_nature"},green_apple:{keywords:["fruit","nature"],char:"\u{1f34f}",fitzpatrick_scale:!1,category:"food_and_drink"},apple:{keywords:["fruit","mac","school"],char:"\u{1f34e}",fitzpatrick_scale:!1,category:"food_and_drink"},pear:{keywords:["fruit","nature","food"],char:"\u{1f350}",fitzpatrick_scale:!1,category:"food_and_drink"},tangerine:{keywords:["food","fruit","nature","orange"],char:"\u{1f34a}",fitzpatrick_scale:!1,category:"food_and_drink"},lemon:{keywords:["fruit","nature"],char:"\u{1f34b}",fitzpatrick_scale:!1,category:"food_and_drink"},banana:{keywords:["fruit","food","monkey"],char:"\u{1f34c}",fitzpatrick_scale:!1,category:"food_and_drink"},watermelon:{keywords:["fruit","food","picnic","summer"],char:"\u{1f349}",fitzpatrick_scale:!1,category:"food_and_drink"},grapes:{keywords:["fruit","food","wine"],char:"\u{1f347}",fitzpatrick_scale:!1,category:"food_and_drink"},strawberry:{keywords:["fruit","food","nature"],char:"\u{1f353}",fitzpatrick_scale:!1,category:"food_and_drink"},melon:{keywords:["fruit","nature","food"],char:"\u{1f348}",fitzpatrick_scale:!1,category:"food_and_drink"},cherries:{keywords:["food","fruit"],char:"\u{1f352}",fitzpatrick_scale:!1,category:"food_and_drink"},peach:{keywords:["fruit","nature","food"],char:"\u{1f351}",fitzpatrick_scale:!1,category:"food_and_drink"},pineapple:{keywords:["fruit","nature","food"],char:"\u{1f34d}",fitzpatrick_scale:!1,category:"food_and_drink"},coconut:{keywords:["fruit","nature","food","palm"],char:"\u{1f965}",fitzpatrick_scale:!1,category:"food_and_drink"},kiwi_fruit:{keywords:["fruit","food"],char:"\u{1f95d}",fitzpatrick_scale:!1,category:"food_and_drink"},mango:{keywords:["fruit","food","tropical"],char:"\u{1f96d}",fitzpatrick_scale:!1,category:"food_and_drink"},avocado:{keywords:["fruit","food"],char:"\u{1f951}",fitzpatrick_scale:!1,category:"food_and_drink"},broccoli:{keywords:["fruit","food","vegetable"],char:"\u{1f966}",fitzpatrick_scale:!1,category:"food_and_drink"},tomato:{keywords:["fruit","vegetable","nature","food"],char:"\u{1f345}",fitzpatrick_scale:!1,category:"food_and_drink"},eggplant:{keywords:["vegetable","nature","food","aubergine"],char:"\u{1f346}",fitzpatrick_scale:!1,category:"food_and_drink"},cucumber:{keywords:["fruit","food","pickle"],char:"\u{1f952}",fitzpatrick_scale:!1,category:"food_and_drink"},carrot:{keywords:["vegetable","food","orange"],char:"\u{1f955}",fitzpatrick_scale:!1,category:"food_and_drink"},hot_pepper:{keywords:["food","spicy","chilli","chili"],char:"\u{1f336}",fitzpatrick_scale:!1,category:"food_and_drink"},potato:{keywords:["food","tuber","vegatable","starch"],char:"\u{1f954}",fitzpatrick_scale:!1,category:"food_and_drink"},corn:{keywords:["food","vegetable","plant"],char:"\u{1f33d}",fitzpatrick_scale:!1,category:"food_and_drink"},leafy_greens:{keywords:["food","vegetable","plant","bok choy","cabbage","kale","lettuce"],char:"\u{1f96c}",fitzpatrick_scale:!1,category:"food_and_drink"},sweet_potato:{keywords:["food","nature"],char:"\u{1f360}",fitzpatrick_scale:!1,category:"food_and_drink"},peanuts:{keywords:["food","nut"],char:"\u{1f95c}",fitzpatrick_scale:!1,category:"food_and_drink"},honey_pot:{keywords:["bees","sweet","kitchen"],char:"\u{1f36f}",fitzpatrick_scale:!1,category:"food_and_drink"},croissant:{keywords:["food","bread","french"],char:"\u{1f950}",fitzpatrick_scale:!1,category:"food_and_drink"},bread:{keywords:["food","wheat","breakfast","toast"],char:"\u{1f35e}",fitzpatrick_scale:!1,category:"food_and_drink"},baguette_bread:{keywords:["food","bread","french"],char:"\u{1f956}",fitzpatrick_scale:!1,category:"food_and_drink"},bagel:{keywords:["food","bread","bakery","schmear"],char:"\u{1f96f}",fitzpatrick_scale:!1,category:"food_and_drink"},pretzel:{keywords:["food","bread","twisted"],char:"\u{1f968}",fitzpatrick_scale:!1,category:"food_and_drink"},cheese:{keywords:["food","chadder"],char:"\u{1f9c0}",fitzpatrick_scale:!1,category:"food_and_drink"},egg:{keywords:["food","chicken","breakfast"],char:"\u{1f95a}",fitzpatrick_scale:!1,category:"food_and_drink"},bacon:{keywords:["food","breakfast","pork","pig","meat"],char:"\u{1f953}",fitzpatrick_scale:!1,category:"food_and_drink"},steak:{keywords:["food","cow","meat","cut","chop","lambchop","porkchop"],char:"\u{1f969}",fitzpatrick_scale:!1,category:"food_and_drink"},pancakes:{keywords:["food","breakfast","flapjacks","hotcakes"],char:"\u{1f95e}",fitzpatrick_scale:!1,category:"food_and_drink"},poultry_leg:{keywords:["food","meat","drumstick","bird","chicken","turkey"],char:"\u{1f357}",fitzpatrick_scale:!1,category:"food_and_drink"},meat_on_bone:{keywords:["good","food","drumstick"],char:"\u{1f356}",fitzpatrick_scale:!1,category:"food_and_drink"},bone:{keywords:["skeleton"],char:"\u{1f9b4}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_shrimp:{keywords:["food","animal","appetizer","summer"],char:"\u{1f364}",fitzpatrick_scale:!1,category:"food_and_drink"},fried_egg:{keywords:["food","breakfast","kitchen","egg"],char:"\u{1f373}",fitzpatrick_scale:!1,category:"food_and_drink"},hamburger:{keywords:["meat","fast food","beef","cheeseburger","mcdonalds","burger king"],char:"\u{1f354}",fitzpatrick_scale:!1,category:"food_and_drink"},fries:{keywords:["chips","snack","fast food"],char:"\u{1f35f}",fitzpatrick_scale:!1,category:"food_and_drink"},stuffed_flatbread:{keywords:["food","flatbread","stuffed","gyro"],char:"\u{1f959}",fitzpatrick_scale:!1,category:"food_and_drink"},hotdog:{keywords:["food","frankfurter"],char:"\u{1f32d}",fitzpatrick_scale:!1,category:"food_and_drink"},pizza:{keywords:["food","party"],char:"\u{1f355}",fitzpatrick_scale:!1,category:"food_and_drink"},sandwich:{keywords:["food","lunch","bread"],char:"\u{1f96a}",fitzpatrick_scale:!1,category:"food_and_drink"},canned_food:{keywords:["food","soup"],char:"\u{1f96b}",fitzpatrick_scale:!1,category:"food_and_drink"},spaghetti:{keywords:["food","italian","noodle"],char:"\u{1f35d}",fitzpatrick_scale:!1,category:"food_and_drink"},taco:{keywords:["food","mexican"],char:"\u{1f32e}",fitzpatrick_scale:!1,category:"food_and_drink"},burrito:{keywords:["food","mexican"],char:"\u{1f32f}",fitzpatrick_scale:!1,category:"food_and_drink"},green_salad:{keywords:["food","healthy","lettuce"],char:"\u{1f957}",fitzpatrick_scale:!1,category:"food_and_drink"},shallow_pan_of_food:{keywords:["food","cooking","casserole","paella"],char:"\u{1f958}",fitzpatrick_scale:!1,category:"food_and_drink"},ramen:{keywords:["food","japanese","noodle","chopsticks"],char:"\u{1f35c}",fitzpatrick_scale:!1,category:"food_and_drink"},stew:{keywords:["food","meat","soup"],char:"\u{1f372}",fitzpatrick_scale:!1,category:"food_and_drink"},fish_cake:{keywords:["food","japan","sea","beach","narutomaki","pink","swirl","kamaboko","surimi","ramen"],char:"\u{1f365}",fitzpatrick_scale:!1,category:"food_and_drink"},fortune_cookie:{keywords:["food","prophecy"],char:"\u{1f960}",fitzpatrick_scale:!1,category:"food_and_drink"},sushi:{keywords:["food","fish","japanese","rice"],char:"\u{1f363}",fitzpatrick_scale:!1,category:"food_and_drink"},bento:{keywords:["food","japanese","box"],char:"\u{1f371}",fitzpatrick_scale:!1,category:"food_and_drink"},curry:{keywords:["food","spicy","hot","indian"],char:"\u{1f35b}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_ball:{keywords:["food","japanese"],char:"\u{1f359}",fitzpatrick_scale:!1,category:"food_and_drink"},rice:{keywords:["food","china","asian"],char:"\u{1f35a}",fitzpatrick_scale:!1,category:"food_and_drink"},rice_cracker:{keywords:["food","japanese"],char:"\u{1f358}",fitzpatrick_scale:!1,category:"food_and_drink"},oden:{keywords:["food","japanese"],char:"\u{1f362}",fitzpatrick_scale:!1,category:"food_and_drink"},dango:{keywords:["food","dessert","sweet","japanese","barbecue","meat"],char:"\u{1f361}",fitzpatrick_scale:!1,category:"food_and_drink"},shaved_ice:{keywords:["hot","dessert","summer"],char:"\u{1f367}",fitzpatrick_scale:!1,category:"food_and_drink"},ice_cream:{keywords:["food","hot","dessert"],char:"\u{1f368}",fitzpatrick_scale:!1,category:"food_and_drink"},icecream:{keywords:["food","hot","dessert","summer"],char:"\u{1f366}",fitzpatrick_scale:!1,category:"food_and_drink"},pie:{keywords:["food","dessert","pastry"],char:"\u{1f967}",fitzpatrick_scale:!1,category:"food_and_drink"},cake:{keywords:["food","dessert"],char:"\u{1f370}",fitzpatrick_scale:!1,category:"food_and_drink"},cupcake:{keywords:["food","dessert","bakery","sweet"],char:"\u{1f9c1}",fitzpatrick_scale:!1,category:"food_and_drink"},moon_cake:{keywords:["food","autumn"],char:"\u{1f96e}",fitzpatrick_scale:!1,category:"food_and_drink"},birthday:{keywords:["food","dessert","cake"],char:"\u{1f382}",fitzpatrick_scale:!1,category:"food_and_drink"},custard:{keywords:["dessert","food"],char:"\u{1f36e}",fitzpatrick_scale:!1,category:"food_and_drink"},candy:{keywords:["snack","dessert","sweet","lolly"],char:"\u{1f36c}",fitzpatrick_scale:!1,category:"food_and_drink"},lollipop:{keywords:["food","snack","candy","sweet"],char:"\u{1f36d}",fitzpatrick_scale:!1,category:"food_and_drink"},chocolate_bar:{keywords:["food","snack","dessert","sweet"],char:"\u{1f36b}",fitzpatrick_scale:!1,category:"food_and_drink"},popcorn:{keywords:["food","movie theater","films","snack"],char:"\u{1f37f}",fitzpatrick_scale:!1,category:"food_and_drink"},dumpling:{keywords:["food","empanada","pierogi","potsticker"],char:"\u{1f95f}",fitzpatrick_scale:!1,category:"food_and_drink"},doughnut:{keywords:["food","dessert","snack","sweet","donut"],char:"\u{1f369}",fitzpatrick_scale:!1,category:"food_and_drink"},cookie:{keywords:["food","snack","oreo","chocolate","sweet","dessert"],char:"\u{1f36a}",fitzpatrick_scale:!1,category:"food_and_drink"},milk_glass:{keywords:["beverage","drink","cow"],char:"\u{1f95b}",fitzpatrick_scale:!1,category:"food_and_drink"},beer:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37a}",fitzpatrick_scale:!1,category:"food_and_drink"},beers:{keywords:["relax","beverage","drink","drunk","party","pub","summer","alcohol","booze"],char:"\u{1f37b}",fitzpatrick_scale:!1,category:"food_and_drink"},clinking_glasses:{keywords:["beverage","drink","party","alcohol","celebrate","cheers","wine","champagne","toast"],char:"\u{1f942}",fitzpatrick_scale:!1,category:"food_and_drink"},wine_glass:{keywords:["drink","beverage","drunk","alcohol","booze"],char:"\u{1f377}",fitzpatrick_scale:!1,category:"food_and_drink"},tumbler_glass:{keywords:["drink","beverage","drunk","alcohol","liquor","booze","bourbon","scotch","whisky","glass","shot"],char:"\u{1f943}",fitzpatrick_scale:!1,category:"food_and_drink"},cocktail:{keywords:["drink","drunk","alcohol","beverage","booze","mojito"],char:"\u{1f378}",fitzpatrick_scale:!1,category:"food_and_drink"},tropical_drink:{keywords:["beverage","cocktail","summer","beach","alcohol","booze","mojito"],char:"\u{1f379}",fitzpatrick_scale:!1,category:"food_and_drink"},champagne:{keywords:["drink","wine","bottle","celebration"],char:"\u{1f37e}",fitzpatrick_scale:!1,category:"food_and_drink"},sake:{keywords:["wine","drink","drunk","beverage","japanese","alcohol","booze"],char:"\u{1f376}",fitzpatrick_scale:!1,category:"food_and_drink"},tea:{keywords:["drink","bowl","breakfast","green","british"],char:"\u{1f375}",fitzpatrick_scale:!1,category:"food_and_drink"},cup_with_straw:{keywords:["drink","soda"],char:"\u{1f964}",fitzpatrick_scale:!1,category:"food_and_drink"},coffee:{keywords:["beverage","caffeine","latte","espresso"],char:"\u2615",fitzpatrick_scale:!1,category:"food_and_drink"},baby_bottle:{keywords:["food","container","milk"],char:"\u{1f37c}",fitzpatrick_scale:!1,category:"food_and_drink"},salt:{keywords:["condiment","shaker"],char:"\u{1f9c2}",fitzpatrick_scale:!1,category:"food_and_drink"},spoon:{keywords:["cutlery","kitchen","tableware"],char:"\u{1f944}",fitzpatrick_scale:!1,category:"food_and_drink"},fork_and_knife:{keywords:["cutlery","kitchen"],char:"\u{1f374}",fitzpatrick_scale:!1,category:"food_and_drink"},plate_with_cutlery:{keywords:["food","eat","meal","lunch","dinner","restaurant"],char:"\u{1f37d}",fitzpatrick_scale:!1,category:"food_and_drink"},bowl_with_spoon:{keywords:["food","breakfast","cereal","oatmeal","porridge"],char:"\u{1f963}",fitzpatrick_scale:!1,category:"food_and_drink"},takeout_box:{keywords:["food","leftovers"],char:"\u{1f961}",fitzpatrick_scale:!1,category:"food_and_drink"},chopsticks:{keywords:["food"],char:"\u{1f962}",fitzpatrick_scale:!1,category:"food_and_drink"},soccer:{keywords:["sports","football"],char:"\u26bd",fitzpatrick_scale:!1,category:"activity"},basketball:{keywords:["sports","balls","NBA"],char:"\u{1f3c0}",fitzpatrick_scale:!1,category:"activity"},football:{keywords:["sports","balls","NFL"],char:"\u{1f3c8}",fitzpatrick_scale:!1,category:"activity"},baseball:{keywords:["sports","balls"],char:"\u26be",fitzpatrick_scale:!1,category:"activity"},softball:{keywords:["sports","balls"],char:"\u{1f94e}",fitzpatrick_scale:!1,category:"activity"},tennis:{keywords:["sports","balls","green"],char:"\u{1f3be}",fitzpatrick_scale:!1,category:"activity"},volleyball:{keywords:["sports","balls"],char:"\u{1f3d0}",fitzpatrick_scale:!1,category:"activity"},rugby_football:{keywords:["sports","team"],char:"\u{1f3c9}",fitzpatrick_scale:!1,category:"activity"},flying_disc:{keywords:["sports","frisbee","ultimate"],char:"\u{1f94f}",fitzpatrick_scale:!1,category:"activity"},"8ball":{keywords:["pool","hobby","game","luck","magic"],char:"\u{1f3b1}",fitzpatrick_scale:!1,category:"activity"},golf:{keywords:["sports","business","flag","hole","summer"],char:"\u26f3",fitzpatrick_scale:!1,category:"activity"},golfing_woman:{keywords:["sports","business","woman","female"],char:"\u{1f3cc}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},golfing_man:{keywords:["sports","business"],char:"\u{1f3cc}",fitzpatrick_scale:!0,category:"activity"},ping_pong:{keywords:["sports","pingpong"],char:"\u{1f3d3}",fitzpatrick_scale:!1,category:"activity"},badminton:{keywords:["sports"],char:"\u{1f3f8}",fitzpatrick_scale:!1,category:"activity"},goal_net:{keywords:["sports"],char:"\u{1f945}",fitzpatrick_scale:!1,category:"activity"},ice_hockey:{keywords:["sports"],char:"\u{1f3d2}",fitzpatrick_scale:!1,category:"activity"},field_hockey:{keywords:["sports"],char:"\u{1f3d1}",fitzpatrick_scale:!1,category:"activity"},lacrosse:{keywords:["sports","ball","stick"],char:"\u{1f94d}",fitzpatrick_scale:!1,category:"activity"},cricket:{keywords:["sports"],char:"\u{1f3cf}",fitzpatrick_scale:!1,category:"activity"},ski:{keywords:["sports","winter","cold","snow"],char:"\u{1f3bf}",fitzpatrick_scale:!1,category:"activity"},skier:{keywords:["sports","winter","snow"],char:"\u26f7",fitzpatrick_scale:!1,category:"activity"},snowboarder:{keywords:["sports","winter"],char:"\u{1f3c2}",fitzpatrick_scale:!0,category:"activity"},person_fencing:{keywords:["sports","fencing","sword"],char:"\u{1f93a}",fitzpatrick_scale:!1,category:"activity"},women_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2640\ufe0f",fitzpatrick_scale:!1,category:"activity"},men_wrestling:{keywords:["sports","wrestlers"],char:"\u{1f93c}\u200d\u2642\ufe0f",fitzpatrick_scale:!1,category:"activity"},woman_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_cartwheeling:{keywords:["gymnastics"],char:"\u{1f938}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_handball:{keywords:["sports"],char:"\u{1f93e}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},ice_skate:{keywords:["sports"],char:"\u26f8",fitzpatrick_scale:!1,category:"activity"},curling_stone:{keywords:["sports"],char:"\u{1f94c}",fitzpatrick_scale:!1,category:"activity"},skateboard:{keywords:["board"],char:"\u{1f6f9}",fitzpatrick_scale:!1,category:"activity"},sled:{keywords:["sleigh","luge","toboggan"],char:"\u{1f6f7}",fitzpatrick_scale:!1,category:"activity"},bow_and_arrow:{keywords:["sports"],char:"\u{1f3f9}",fitzpatrick_scale:!1,category:"activity"},fishing_pole_and_fish:{keywords:["food","hobby","summer"],char:"\u{1f3a3}",fitzpatrick_scale:!1,category:"activity"},boxing_glove:{keywords:["sports","fighting"],char:"\u{1f94a}",fitzpatrick_scale:!1,category:"activity"},martial_arts_uniform:{keywords:["judo","karate","taekwondo"],char:"\u{1f94b}",fitzpatrick_scale:!1,category:"activity"},rowing_woman:{keywords:["sports","hobby","water","ship","woman","female"],char:"\u{1f6a3}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},rowing_man:{keywords:["sports","hobby","water","ship"],char:"\u{1f6a3}",fitzpatrick_scale:!0,category:"activity"},climbing_woman:{keywords:["sports","hobby","woman","female","rock"],char:"\u{1f9d7}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},climbing_man:{keywords:["sports","hobby","man","male","rock"],char:"\u{1f9d7}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_woman:{keywords:["sports","exercise","human","athlete","water","summer","woman","female"],char:"\u{1f3ca}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},swimming_man:{keywords:["sports","exercise","human","athlete","water","summer"],char:"\u{1f3ca}",fitzpatrick_scale:!0,category:"activity"},woman_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_playing_water_polo:{keywords:["sports","pool"],char:"\u{1f93d}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},woman_in_lotus_position:{keywords:["woman","female","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_in_lotus_position:{keywords:["man","male","meditation","yoga","serenity","zen","mindfulness"],char:"\u{1f9d8}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_woman:{keywords:["sports","ocean","sea","summer","beach","woman","female"],char:"\u{1f3c4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},surfing_man:{keywords:["sports","ocean","sea","summer","beach"],char:"\u{1f3c4}",fitzpatrick_scale:!0,category:"activity"},bath:{keywords:["clean","shower","bathroom"],char:"\u{1f6c0}",fitzpatrick_scale:!0,category:"activity"},basketball_woman:{keywords:["sports","human","woman","female"],char:"\u26f9\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},basketball_man:{keywords:["sports","human"],char:"\u26f9",fitzpatrick_scale:!0,category:"activity"},weight_lifting_woman:{keywords:["sports","training","exercise","woman","female"],char:"\u{1f3cb}\ufe0f\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},weight_lifting_man:{keywords:["sports","training","exercise"],char:"\u{1f3cb}",fitzpatrick_scale:!0,category:"activity"},biking_woman:{keywords:["sports","bike","exercise","hipster","woman","female"],char:"\u{1f6b4}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},biking_man:{keywords:["sports","bike","exercise","hipster"],char:"\u{1f6b4}",fitzpatrick_scale:!0,category:"activity"},mountain_biking_woman:{keywords:["transportation","sports","human","race","bike","woman","female"],char:"\u{1f6b5}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},mountain_biking_man:{keywords:["transportation","sports","human","race","bike"],char:"\u{1f6b5}",fitzpatrick_scale:!0,category:"activity"},horse_racing:{keywords:["animal","betting","competition","gambling","luck"],char:"\u{1f3c7}",fitzpatrick_scale:!0,category:"activity"},business_suit_levitating:{keywords:["suit","business","levitate","hover","jump"],char:"\u{1f574}",fitzpatrick_scale:!0,category:"activity"},trophy:{keywords:["win","award","contest","place","ftw","ceremony"],char:"\u{1f3c6}",fitzpatrick_scale:!1,category:"activity"},running_shirt_with_sash:{keywords:["play","pageant"],char:"\u{1f3bd}",fitzpatrick_scale:!1,category:"activity"},medal_sports:{keywords:["award","winning"],char:"\u{1f3c5}",fitzpatrick_scale:!1,category:"activity"},medal_military:{keywords:["award","winning","army"],char:"\u{1f396}",fitzpatrick_scale:!1,category:"activity"},"1st_place_medal":{keywords:["award","winning","first"],char:"\u{1f947}",fitzpatrick_scale:!1,category:"activity"},"2nd_place_medal":{keywords:["award","second"],char:"\u{1f948}",fitzpatrick_scale:!1,category:"activity"},"3rd_place_medal":{keywords:["award","third"],char:"\u{1f949}",fitzpatrick_scale:!1,category:"activity"},reminder_ribbon:{keywords:["sports","cause","support","awareness"],char:"\u{1f397}",fitzpatrick_scale:!1,category:"activity"},rosette:{keywords:["flower","decoration","military"],char:"\u{1f3f5}",fitzpatrick_scale:!1,category:"activity"},ticket:{keywords:["event","concert","pass"],char:"\u{1f3ab}",fitzpatrick_scale:!1,category:"activity"},tickets:{keywords:["sports","concert","entrance"],char:"\u{1f39f}",fitzpatrick_scale:!1,category:"activity"},performing_arts:{keywords:["acting","theater","drama"],char:"\u{1f3ad}",fitzpatrick_scale:!1,category:"activity"},art:{keywords:["design","paint","draw","colors"],char:"\u{1f3a8}",fitzpatrick_scale:!1,category:"activity"},circus_tent:{keywords:["festival","carnival","party"],char:"\u{1f3aa}",fitzpatrick_scale:!1,category:"activity"},woman_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2640\ufe0f",fitzpatrick_scale:!0,category:"activity"},man_juggling:{keywords:["juggle","balance","skill","multitask"],char:"\u{1f939}\u200d\u2642\ufe0f",fitzpatrick_scale:!0,category:"activity"},microphone:{keywords:["sound","music","PA","sing","talkshow"],char:"\u{1f3a4}",fitzpatrick_scale:!1,category:"activity"},headphones:{keywords:["music","score","gadgets"],char:"\u{1f3a7}",fitzpatrick_scale:!1,category:"activity"},musical_score:{keywords:["treble","clef","compose"],char:"\u{1f3bc}",fitzpatrick_scale:!1,category:"activity"},musical_keyboard:{keywords:["piano","instrument","compose"],char:"\u{1f3b9}",fitzpatrick_scale:!1,category:"activity"},drum:{keywords:["music","instrument","drumsticks","snare"],char:"\u{1f941}",fitzpatrick_scale:!1,category:"activity"},saxophone:{keywords:["music","instrument","jazz","blues"],char:"\u{1f3b7}",fitzpatrick_scale:!1,category:"activity"},trumpet:{keywords:["music","brass"],char:"\u{1f3ba}",fitzpatrick_scale:!1,category:"activity"},guitar:{keywords:["music","instrument"],char:"\u{1f3b8}",fitzpatrick_scale:!1,category:"activity"},violin:{keywords:["music","instrument","orchestra","symphony"],char:"\u{1f3bb}",fitzpatrick_scale:!1,category:"activity"},clapper:{keywords:["movie","film","record"],char:"\u{1f3ac}",fitzpatrick_scale:!1,category:"activity"},video_game:{keywords:["play","console","PS4","controller"],char:"\u{1f3ae}",fitzpatrick_scale:!1,category:"activity"},space_invader:{keywords:["game","arcade","play"],char:"\u{1f47e}",fitzpatrick_scale:!1,category:"activity"},dart:{keywords:["game","play","bar","target","bullseye"],char:"\u{1f3af}",fitzpatrick_scale:!1,category:"activity"},game_die:{keywords:["dice","random","tabletop","play","luck"],char:"\u{1f3b2}",fitzpatrick_scale:!1,category:"activity"},chess_pawn:{keywords:["expendable"],char:"\u265f",fitzpatrick_scale:!1,category:"activity"},slot_machine:{keywords:["bet","gamble","vegas","fruit machine","luck","casino"],char:"\u{1f3b0}",fitzpatrick_scale:!1,category:"activity"},jigsaw:{keywords:["interlocking","puzzle","piece"],char:"\u{1f9e9}",fitzpatrick_scale:!1,category:"activity"},bowling:{keywords:["sports","fun","play"],char:"\u{1f3b3}",fitzpatrick_scale:!1,category:"activity"},red_car:{keywords:["red","transportation","vehicle"],char:"\u{1f697}",fitzpatrick_scale:!1,category:"travel_and_places"},taxi:{keywords:["uber","vehicle","cars","transportation"],char:"\u{1f695}",fitzpatrick_scale:!1,category:"travel_and_places"},blue_car:{keywords:["transportation","vehicle"],char:"\u{1f699}",fitzpatrick_scale:!1,category:"travel_and_places"},bus:{keywords:["car","vehicle","transportation"],char:"\u{1f68c}",fitzpatrick_scale:!1,category:"travel_and_places"},trolleybus:{keywords:["bart","transportation","vehicle"],char:"\u{1f68e}",fitzpatrick_scale:!1,category:"travel_and_places"},racing_car:{keywords:["sports","race","fast","formula","f1"],char:"\u{1f3ce}",fitzpatrick_scale:!1,category:"travel_and_places"},police_car:{keywords:["vehicle","cars","transportation","law","legal","enforcement"],char:"\u{1f693}",fitzpatrick_scale:!1,category:"travel_and_places"},ambulance:{keywords:["health","911","hospital"],char:"\u{1f691}",fitzpatrick_scale:!1,category:"travel_and_places"},fire_engine:{keywords:["transportation","cars","vehicle"],char:"\u{1f692}",fitzpatrick_scale:!1,category:"travel_and_places"},minibus:{keywords:["vehicle","car","transportation"],char:"\u{1f690}",fitzpatrick_scale:!1,category:"travel_and_places"},truck:{keywords:["cars","transportation"],char:"\u{1f69a}",fitzpatrick_scale:!1,category:"travel_and_places"},articulated_lorry:{keywords:["vehicle","cars","transportation","express"],char:"\u{1f69b}",fitzpatrick_scale:!1,category:"travel_and_places"},tractor:{keywords:["vehicle","car","farming","agriculture"],char:"\u{1f69c}",fitzpatrick_scale:!1,category:"travel_and_places"},kick_scooter:{keywords:["vehicle","kick","razor"],char:"\u{1f6f4}",fitzpatrick_scale:!1,category:"travel_and_places"},motorcycle:{keywords:["race","sports","fast"],char:"\u{1f3cd}",fitzpatrick_scale:!1,category:"travel_and_places"},bike:{keywords:["sports","bicycle","exercise","hipster"],char:"\u{1f6b2}",fitzpatrick_scale:!1,category:"travel_and_places"},motor_scooter:{keywords:["vehicle","vespa","sasha"],char:"\u{1f6f5}",fitzpatrick_scale:!1,category:"travel_and_places"},rotating_light:{keywords:["police","ambulance","911","emergency","alert","error","pinged","law","legal"],char:"\u{1f6a8}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_police_car:{keywords:["vehicle","law","legal","enforcement","911"],char:"\u{1f694}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_bus:{keywords:["vehicle","transportation"],char:"\u{1f68d}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_automobile:{keywords:["car","vehicle","transportation"],char:"\u{1f698}",fitzpatrick_scale:!1,category:"travel_and_places"},oncoming_taxi:{keywords:["vehicle","cars","uber"],char:"\u{1f696}",fitzpatrick_scale:!1,category:"travel_and_places"},aerial_tramway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a1}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_cableway:{keywords:["transportation","vehicle","ski"],char:"\u{1f6a0}",fitzpatrick_scale:!1,category:"travel_and_places"},suspension_railway:{keywords:["vehicle","transportation"],char:"\u{1f69f}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_car:{keywords:["transportation","vehicle"],char:"\u{1f683}",fitzpatrick_scale:!1,category:"travel_and_places"},train:{keywords:["transportation","vehicle","carriage","public","travel"],char:"\u{1f68b}",fitzpatrick_scale:!1,category:"travel_and_places"},monorail:{keywords:["transportation","vehicle"],char:"\u{1f69d}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_side:{keywords:["transportation","vehicle"],char:"\u{1f684}",fitzpatrick_scale:!1,category:"travel_and_places"},bullettrain_front:{keywords:["transportation","vehicle","speed","fast","public","travel"],char:"\u{1f685}",fitzpatrick_scale:!1,category:"travel_and_places"},light_rail:{keywords:["transportation","vehicle"],char:"\u{1f688}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_railway:{keywords:["transportation","vehicle"],char:"\u{1f69e}",fitzpatrick_scale:!1,category:"travel_and_places"},steam_locomotive:{keywords:["transportation","vehicle","train"],char:"\u{1f682}",fitzpatrick_scale:!1,category:"travel_and_places"},train2:{keywords:["transportation","vehicle"],char:"\u{1f686}",fitzpatrick_scale:!1,category:"travel_and_places"},metro:{keywords:["transportation","blue-square","mrt","underground","tube"],char:"\u{1f687}",fitzpatrick_scale:!1,category:"travel_and_places"},tram:{keywords:["transportation","vehicle"],char:"\u{1f68a}",fitzpatrick_scale:!1,category:"travel_and_places"},station:{keywords:["transportation","vehicle","public"],char:"\u{1f689}",fitzpatrick_scale:!1,category:"travel_and_places"},flying_saucer:{keywords:["transportation","vehicle","ufo"],char:"\u{1f6f8}",fitzpatrick_scale:!1,category:"travel_and_places"},helicopter:{keywords:["transportation","vehicle","fly"],char:"\u{1f681}",fitzpatrick_scale:!1,category:"travel_and_places"},small_airplane:{keywords:["flight","transportation","fly","vehicle"],char:"\u{1f6e9}",fitzpatrick_scale:!1,category:"travel_and_places"},airplane:{keywords:["vehicle","transportation","flight","fly"],char:"\u2708\ufe0f",fitzpatrick_scale:!1,category:"travel_and_places"},flight_departure:{keywords:["airport","flight","landing"],char:"\u{1f6eb}",fitzpatrick_scale:!1,category:"travel_and_places"},flight_arrival:{keywords:["airport","flight","boarding"],char:"\u{1f6ec}",fitzpatrick_scale:!1,category:"travel_and_places"},sailboat:{keywords:["ship","summer","transportation","water","sailing"],char:"\u26f5",fitzpatrick_scale:!1,category:"travel_and_places"},motor_boat:{keywords:["ship"],char:"\u{1f6e5}",fitzpatrick_scale:!1,category:"travel_and_places"},speedboat:{keywords:["ship","transportation","vehicle","summer"],char:"\u{1f6a4}",fitzpatrick_scale:!1,category:"travel_and_places"},ferry:{keywords:["boat","ship","yacht"],char:"\u26f4",fitzpatrick_scale:!1,category:"travel_and_places"},passenger_ship:{keywords:["yacht","cruise","ferry"],char:"\u{1f6f3}",fitzpatrick_scale:!1,category:"travel_and_places"},rocket:{keywords:["launch","ship","staffmode","NASA","outer space","outer_space","fly"],char:"\u{1f680}",fitzpatrick_scale:!1,category:"travel_and_places"},artificial_satellite:{keywords:["communication","gps","orbit","spaceflight","NASA","ISS"],char:"\u{1f6f0}",fitzpatrick_scale:!1,category:"travel_and_places"},seat:{keywords:["sit","airplane","transport","bus","flight","fly"],char:"\u{1f4ba}",fitzpatrick_scale:!1,category:"travel_and_places"},canoe:{keywords:["boat","paddle","water","ship"],char:"\u{1f6f6}",fitzpatrick_scale:!1,category:"travel_and_places"},anchor:{keywords:["ship","ferry","sea","boat"],char:"\u2693",fitzpatrick_scale:!1,category:"travel_and_places"},construction:{keywords:["wip","progress","caution","warning"],char:"\u{1f6a7}",fitzpatrick_scale:!1,category:"travel_and_places"},fuelpump:{keywords:["gas station","petroleum"],char:"\u26fd",fitzpatrick_scale:!1,category:"travel_and_places"},busstop:{keywords:["transportation","wait"],char:"\u{1f68f}",fitzpatrick_scale:!1,category:"travel_and_places"},vertical_traffic_light:{keywords:["transportation","driving"],char:"\u{1f6a6}",fitzpatrick_scale:!1,category:"travel_and_places"},traffic_light:{keywords:["transportation","signal"],char:"\u{1f6a5}",fitzpatrick_scale:!1,category:"travel_and_places"},checkered_flag:{keywords:["contest","finishline","race","gokart"],char:"\u{1f3c1}",fitzpatrick_scale:!1,category:"travel_and_places"},ship:{keywords:["transportation","titanic","deploy"],char:"\u{1f6a2}",fitzpatrick_scale:!1,category:"travel_and_places"},ferris_wheel:{keywords:["photo","carnival","londoneye"],char:"\u{1f3a1}",fitzpatrick_scale:!1,category:"travel_and_places"},roller_coaster:{keywords:["carnival","playground","photo","fun"],char:"\u{1f3a2}",fitzpatrick_scale:!1,category:"travel_and_places"},carousel_horse:{keywords:["photo","carnival"],char:"\u{1f3a0}",fitzpatrick_scale:!1,category:"travel_and_places"},building_construction:{keywords:["wip","working","progress"],char:"\u{1f3d7}",fitzpatrick_scale:!1,category:"travel_and_places"},foggy:{keywords:["photo","mountain"],char:"\u{1f301}",fitzpatrick_scale:!1,category:"travel_and_places"},tokyo_tower:{keywords:["photo","japanese"],char:"\u{1f5fc}",fitzpatrick_scale:!1,category:"travel_and_places"},factory:{keywords:["building","industry","pollution","smoke"],char:"\u{1f3ed}",fitzpatrick_scale:!1,category:"travel_and_places"},fountain:{keywords:["photo","summer","water","fresh"],char:"\u26f2",fitzpatrick_scale:!1,category:"travel_and_places"},rice_scene:{keywords:["photo","japan","asia","tsukimi"],char:"\u{1f391}",fitzpatrick_scale:!1,category:"travel_and_places"},mountain:{keywords:["photo","nature","environment"],char:"\u26f0",fitzpatrick_scale:!1,category:"travel_and_places"},mountain_snow:{keywords:["photo","nature","environment","winter","cold"],char:"\u{1f3d4}",fitzpatrick_scale:!1,category:"travel_and_places"},mount_fuji:{keywords:["photo","mountain","nature","japanese"],char:"\u{1f5fb}",fitzpatrick_scale:!1,category:"travel_and_places"},volcano:{keywords:["photo","nature","disaster"],char:"\u{1f30b}",fitzpatrick_scale:!1,category:"travel_and_places"},japan:{keywords:["nation","country","japanese","asia"],char:"\u{1f5fe}",fitzpatrick_scale:!1,category:"travel_and_places"},camping:{keywords:["photo","outdoors","tent"],char:"\u{1f3d5}",fitzpatrick_scale:!1,category:"travel_and_places"},tent:{keywords:["photo","camping","outdoors"],char:"\u26fa",fitzpatrick_scale:!1,category:"travel_and_places"},national_park:{keywords:["photo","environment","nature"],char:"\u{1f3de}",fitzpatrick_scale:!1,category:"travel_and_places"},motorway:{keywords:["road","cupertino","interstate","highway"],char:"\u{1f6e3}",fitzpatrick_scale:!1,category:"travel_and_places"},railway_track:{keywords:["train","transportation"],char:"\u{1f6e4}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise:{keywords:["morning","view","vacation","photo"],char:"\u{1f305}",fitzpatrick_scale:!1,category:"travel_and_places"},sunrise_over_mountains:{keywords:["view","vacation","photo"],char:"\u{1f304}",fitzpatrick_scale:!1,category:"travel_and_places"},desert:{keywords:["photo","warm","saharah"],char:"\u{1f3dc}",fitzpatrick_scale:!1,category:"travel_and_places"},beach_umbrella:{keywords:["weather","summer","sunny","sand","mojito"],char:"\u{1f3d6}",fitzpatrick_scale:!1,category:"travel_and_places"},desert_island:{keywords:["photo","tropical","mojito"],char:"\u{1f3dd}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunrise:{keywords:["photo","good morning","dawn"],char:"\u{1f307}",fitzpatrick_scale:!1,category:"travel_and_places"},city_sunset:{keywords:["photo","evening","sky","buildings"],char:"\u{1f306}",fitzpatrick_scale:!1,category:"travel_and_places"},cityscape:{keywords:["photo","night life","urban"],char:"\u{1f3d9}",fitzpatrick_scale:!1,category:"travel_and_places"},night_with_stars:{keywords:["evening","city","downtown"],char:"\u{1f303}",fitzpatrick_scale:!1,category:"travel_and_places"},bridge_at_night:{keywords:["photo","sanfrancisco"],char:"\u{1f309}",fitzpatrick_scale:!1,category:"travel_and_places"},milky_way:{keywords:["photo","space","stars"],char:"\u{1f30c}",fitzpatrick_scale:!1,category:"travel_and_places"},stars:{keywords:["night","photo"],char:"\u{1f320}",fitzpatrick_scale:!1,category:"travel_and_places"},sparkler:{keywords:["stars","night","shine"],char:"\u{1f387}",fitzpatrick_scale:!1,category:"travel_and_places"},fireworks:{keywords:["photo","festival","carnival","congratulations"],char:"\u{1f386}",fitzpatrick_scale:!1,category:"travel_and_places"},rainbow:{keywords:["nature","happy","unicorn_face","photo","sky","spring"],char:"\u{1f308}",fitzpatrick_scale:!1,category:"travel_and_places"},houses:{keywords:["buildings","photo"],char:"\u{1f3d8}",fitzpatrick_scale:!1,category:"travel_and_places"},european_castle:{keywords:["building","royalty","history"],char:"\u{1f3f0}",fitzpatrick_scale:!1,category:"travel_and_places"},japanese_castle:{keywords:["photo","building"],char:"\u{1f3ef}",fitzpatrick_scale:!1,category:"travel_and_places"},stadium:{keywords:["photo","place","sports","concert","venue"],char:"\u{1f3df}",fitzpatrick_scale:!1,category:"travel_and_places"},statue_of_liberty:{keywords:["american","newyork"],char:"\u{1f5fd}",fitzpatrick_scale:!1,category:"travel_and_places"},house:{keywords:["building","home"],char:"\u{1f3e0}",fitzpatrick_scale:!1,category:"travel_and_places"},house_with_garden:{keywords:["home","plant","nature"],char:"\u{1f3e1}",fitzpatrick_scale:!1,category:"travel_and_places"},derelict_house:{keywords:["abandon","evict","broken","building"],char:"\u{1f3da}",fitzpatrick_scale:!1,category:"travel_and_places"},office:{keywords:["building","bureau","work"],char:"\u{1f3e2}",fitzpatrick_scale:!1,category:"travel_and_places"},department_store:{keywords:["building","shopping","mall"],char:"\u{1f3ec}",fitzpatrick_scale:!1,category:"travel_and_places"},post_office:{keywords:["building","envelope","communication"],char:"\u{1f3e3}",fitzpatrick_scale:!1,category:"travel_and_places"},european_post_office:{keywords:["building","email"],char:"\u{1f3e4}",fitzpatrick_scale:!1,category:"travel_and_places"},hospital:{keywords:["building","health","surgery","doctor"],char:"\u{1f3e5}",fitzpatrick_scale:!1,category:"travel_and_places"},bank:{keywords:["building","money","sales","cash","business","enterprise"],char:"\u{1f3e6}",fitzpatrick_scale:!1,category:"travel_and_places"},hotel:{keywords:["building","accomodation","checkin"],char:"\u{1f3e8}",fitzpatrick_scale:!1,category:"travel_and_places"},convenience_store:{keywords:["building","shopping","groceries"],char:"\u{1f3ea}",fitzpatrick_scale:!1,category:"travel_and_places"},school:{keywords:["building","student","education","learn","teach"],char:"\u{1f3eb}",fitzpatrick_scale:!1,category:"travel_and_places"},love_hotel:{keywords:["like","affection","dating"],char:"\u{1f3e9}",fitzpatrick_scale:!1,category:"travel_and_places"},wedding:{keywords:["love","like","affection","couple","marriage","bride","groom"],char:"\u{1f492}",fitzpatrick_scale:!1,category:"travel_and_places"},classical_building:{keywords:["art","culture","history"],char:"\u{1f3db}",fitzpatrick_scale:!1,category:"travel_and_places"},church:{keywords:["building","religion","christ"],char:"\u26ea",fitzpatrick_scale:!1,category:"travel_and_places"},mosque:{keywords:["islam","worship","minaret"],char:"\u{1f54c}",fitzpatrick_scale:!1,category:"travel_and_places"},synagogue:{keywords:["judaism","worship","temple","jewish"],char:"\u{1f54d}",fitzpatrick_scale:!1,category:"travel_and_places"},kaaba:{keywords:["mecca","mosque","islam"],char:"\u{1f54b}",fitzpatrick_scale:!1,category:"travel_and_places"},shinto_shrine:{keywords:["temple","japan","kyoto"],char:"\u26e9",fitzpatrick_scale:!1,category:"travel_and_places"},watch:{keywords:["time","accessories"],char:"\u231a",fitzpatrick_scale:!1,category:"objects"},iphone:{keywords:["technology","apple","gadgets","dial"],char:"\u{1f4f1}",fitzpatrick_scale:!1,category:"objects"},calling:{keywords:["iphone","incoming"],char:"\u{1f4f2}",fitzpatrick_scale:!1,category:"objects"},computer:{keywords:["technology","laptop","screen","display","monitor"],char:"\u{1f4bb}",fitzpatrick_scale:!1,category:"objects"},keyboard:{keywords:["technology","computer","type","input","text"],char:"\u2328",fitzpatrick_scale:!1,category:"objects"},desktop_computer:{keywords:["technology","computing","screen"],char:"\u{1f5a5}",fitzpatrick_scale:!1,category:"objects"},printer:{keywords:["paper","ink"],char:"\u{1f5a8}",fitzpatrick_scale:!1,category:"objects"},computer_mouse:{keywords:["click"],char:"\u{1f5b1}",fitzpatrick_scale:!1,category:"objects"},trackball:{keywords:["technology","trackpad"],char:"\u{1f5b2}",fitzpatrick_scale:!1,category:"objects"},joystick:{keywords:["game","play"],char:"\u{1f579}",fitzpatrick_scale:!1,category:"objects"},clamp:{keywords:["tool"],char:"\u{1f5dc}",fitzpatrick_scale:!1,category:"objects"},minidisc:{keywords:["technology","record","data","disk","90s"],char:"\u{1f4bd}",fitzpatrick_scale:!1,category:"objects"},floppy_disk:{keywords:["oldschool","technology","save","90s","80s"],char:"\u{1f4be}",fitzpatrick_scale:!1,category:"objects"},cd:{keywords:["technology","dvd","disk","disc","90s"],char:"\u{1f4bf}",fitzpatrick_scale:!1,category:"objects"},dvd:{keywords:["cd","disk","disc"],char:"\u{1f4c0}",fitzpatrick_scale:!1,category:"objects"},vhs:{keywords:["record","video","oldschool","90s","80s"],char:"\u{1f4fc}",fitzpatrick_scale:!1,category:"objects"},camera:{keywords:["gadgets","photography"],char:"\u{1f4f7}",fitzpatrick_scale:!1,category:"objects"},camera_flash:{keywords:["photography","gadgets"],char:"\u{1f4f8}",fitzpatrick_scale:!1,category:"objects"},video_camera:{keywords:["film","record"],char:"\u{1f4f9}",fitzpatrick_scale:!1,category:"objects"},movie_camera:{keywords:["film","record"],char:"\u{1f3a5}",fitzpatrick_scale:!1,category:"objects"},film_projector:{keywords:["video","tape","record","movie"],char:"\u{1f4fd}",fitzpatrick_scale:!1,category:"objects"},film_strip:{keywords:["movie"],char:"\u{1f39e}",fitzpatrick_scale:!1,category:"objects"},telephone_receiver:{keywords:["technology","communication","dial"],char:"\u{1f4de}",fitzpatrick_scale:!1,category:"objects"},phone:{keywords:["technology","communication","dial","telephone"],char:"\u260e\ufe0f",fitzpatrick_scale:!1,category:"objects"},pager:{keywords:["bbcall","oldschool","90s"],char:"\u{1f4df}",fitzpatrick_scale:!1,category:"objects"},fax:{keywords:["communication","technology"],char:"\u{1f4e0}",fitzpatrick_scale:!1,category:"objects"},tv:{keywords:["technology","program","oldschool","show","television"],char:"\u{1f4fa}",fitzpatrick_scale:!1,category:"objects"},radio:{keywords:["communication","music","podcast","program"],char:"\u{1f4fb}",fitzpatrick_scale:!1,category:"objects"},studio_microphone:{keywords:["sing","recording","artist","talkshow"],char:"\u{1f399}",fitzpatrick_scale:!1,category:"objects"},level_slider:{keywords:["scale"],char:"\u{1f39a}",fitzpatrick_scale:!1,category:"objects"},control_knobs:{keywords:["dial"],char:"\u{1f39b}",fitzpatrick_scale:!1,category:"objects"},compass:{keywords:["magnetic","navigation","orienteering"],char:"\u{1f9ed}",fitzpatrick_scale:!1,category:"objects"},stopwatch:{keywords:["time","deadline"],char:"\u23f1",fitzpatrick_scale:!1,category:"objects"},timer_clock:{keywords:["alarm"],char:"\u23f2",fitzpatrick_scale:!1,category:"objects"},alarm_clock:{keywords:["time","wake"],char:"\u23f0",fitzpatrick_scale:!1,category:"objects"},mantelpiece_clock:{keywords:["time"],char:"\u{1f570}",fitzpatrick_scale:!1,category:"objects"},hourglass_flowing_sand:{keywords:["oldschool","time","countdown"],char:"\u23f3",fitzpatrick_scale:!1,category:"objects"},hourglass:{keywords:["time","clock","oldschool","limit","exam","quiz","test"],char:"\u231b",fitzpatrick_scale:!1,category:"objects"},satellite:{keywords:["communication","future","radio","space"],char:"\u{1f4e1}",fitzpatrick_scale:!1,category:"objects"},battery:{keywords:["power","energy","sustain"],char:"\u{1f50b}",fitzpatrick_scale:!1,category:"objects"},electric_plug:{keywords:["charger","power"],char:"\u{1f50c}",fitzpatrick_scale:!1,category:"objects"},bulb:{keywords:["light","electricity","idea"],char:"\u{1f4a1}",fitzpatrick_scale:!1,category:"objects"},flashlight:{keywords:["dark","camping","sight","night"],char:"\u{1f526}",fitzpatrick_scale:!1,category:"objects"},candle:{keywords:["fire","wax"],char:"\u{1f56f}",fitzpatrick_scale:!1,category:"objects"},fire_extinguisher:{keywords:["quench"],char:"\u{1f9ef}",fitzpatrick_scale:!1,category:"objects"},wastebasket:{keywords:["bin","trash","rubbish","garbage","toss"],char:"\u{1f5d1}",fitzpatrick_scale:!1,category:"objects"},oil_drum:{keywords:["barrell"],char:"\u{1f6e2}",fitzpatrick_scale:!1,category:"objects"},money_with_wings:{keywords:["dollar","bills","payment","sale"],char:"\u{1f4b8}",fitzpatrick_scale:!1,category:"objects"},dollar:{keywords:["money","sales","bill","currency"],char:"\u{1f4b5}",fitzpatrick_scale:!1,category:"objects"},yen:{keywords:["money","sales","japanese","dollar","currency"],char:"\u{1f4b4}",fitzpatrick_scale:!1,category:"objects"},euro:{keywords:["money","sales","dollar","currency"],char:"\u{1f4b6}",fitzpatrick_scale:!1,category:"objects"},pound:{keywords:["british","sterling","money","sales","bills","uk","england","currency"],char:"\u{1f4b7}",fitzpatrick_scale:!1,category:"objects"},moneybag:{keywords:["dollar","payment","coins","sale"],char:"\u{1f4b0}",fitzpatrick_scale:!1,category:"objects"},credit_card:{keywords:["money","sales","dollar","bill","payment","shopping"],char:"\u{1f4b3}",fitzpatrick_scale:!1,category:"objects"},gem:{keywords:["blue","ruby","diamond","jewelry"],char:"\u{1f48e}",fitzpatrick_scale:!1,category:"objects"},balance_scale:{keywords:["law","fairness","weight"],char:"\u2696",fitzpatrick_scale:!1,category:"objects"},toolbox:{keywords:["tools","diy","fix","maintainer","mechanic"],char:"\u{1f9f0}",fitzpatrick_scale:!1,category:"objects"},wrench:{keywords:["tools","diy","ikea","fix","maintainer"],char:"\u{1f527}",fitzpatrick_scale:!1,category:"objects"},hammer:{keywords:["tools","build","create"],char:"\u{1f528}",fitzpatrick_scale:!1,category:"objects"},hammer_and_pick:{keywords:["tools","build","create"],char:"\u2692",fitzpatrick_scale:!1,category:"objects"},hammer_and_wrench:{keywords:["tools","build","create"],char:"\u{1f6e0}",fitzpatrick_scale:!1,category:"objects"},pick:{keywords:["tools","dig"],char:"\u26cf",fitzpatrick_scale:!1,category:"objects"},nut_and_bolt:{keywords:["handy","tools","fix"],char:"\u{1f529}",fitzpatrick_scale:!1,category:"objects"},gear:{keywords:["cog"],char:"\u2699",fitzpatrick_scale:!1,category:"objects"},brick:{keywords:["bricks"],char:"\u{1f9f1}",fitzpatrick_scale:!1,category:"objects"},chains:{keywords:["lock","arrest"],char:"\u26d3",fitzpatrick_scale:!1,category:"objects"},magnet:{keywords:["attraction","magnetic"],char:"\u{1f9f2}",fitzpatrick_scale:!1,category:"objects"},gun:{keywords:["violence","weapon","pistol","revolver"],char:"\u{1f52b}",fitzpatrick_scale:!1,category:"objects"},bomb:{keywords:["boom","explode","explosion","terrorism"],char:"\u{1f4a3}",fitzpatrick_scale:!1,category:"objects"},firecracker:{keywords:["dynamite","boom","explode","explosion","explosive"],char:"\u{1f9e8}",fitzpatrick_scale:!1,category:"objects"},hocho:{keywords:["knife","blade","cutlery","kitchen","weapon"],char:"\u{1f52a}",fitzpatrick_scale:!1,category:"objects"},dagger:{keywords:["weapon"],char:"\u{1f5e1}",fitzpatrick_scale:!1,category:"objects"},crossed_swords:{keywords:["weapon"],char:"\u2694",fitzpatrick_scale:!1,category:"objects"},shield:{keywords:["protection","security"],char:"\u{1f6e1}",fitzpatrick_scale:!1,category:"objects"},smoking:{keywords:["kills","tobacco","cigarette","joint","smoke"],char:"\u{1f6ac}",fitzpatrick_scale:!1,category:"objects"},skull_and_crossbones:{keywords:["poison","danger","deadly","scary","death","pirate","evil"],char:"\u2620",fitzpatrick_scale:!1,category:"objects"},coffin:{keywords:["vampire","dead","die","death","rip","graveyard","cemetery","casket","funeral","box"],char:"\u26b0",fitzpatrick_scale:!1,category:"objects"},funeral_urn:{keywords:["dead","die","death","rip","ashes"],char:"\u26b1",fitzpatrick_scale:!1,category:"objects"},amphora:{keywords:["vase","jar"],char:"\u{1f3fa}",fitzpatrick_scale:!1,category:"objects"},crystal_ball:{keywords:["disco","party","magic","circus","fortune_teller"],char:"\u{1f52e}",fitzpatrick_scale:!1,category:"objects"},prayer_beads:{keywords:["dhikr","religious"],char:"\u{1f4ff}",fitzpatrick_scale:!1,category:"objects"},nazar_amulet:{keywords:["bead","charm"],char:"\u{1f9ff}",fitzpatrick_scale:!1,category:"objects"},barber:{keywords:["hair","salon","style"],char:"\u{1f488}",fitzpatrick_scale:!1,category:"objects"},alembic:{keywords:["distilling","science","experiment","chemistry"],char:"\u2697",fitzpatrick_scale:!1,category:"objects"},telescope:{keywords:["stars","space","zoom","science","astronomy"],char:"\u{1f52d}",fitzpatrick_scale:!1,category:"objects"},microscope:{keywords:["laboratory","experiment","zoomin","science","study"],char:"\u{1f52c}",fitzpatrick_scale:!1,category:"objects"},hole:{keywords:["embarrassing"],char:"\u{1f573}",fitzpatrick_scale:!1,category:"objects"},pill:{keywords:["health","medicine","doctor","pharmacy","drug"],char:"\u{1f48a}",fitzpatrick_scale:!1,category:"objects"},syringe:{keywords:["health","hospital","drugs","blood","medicine","needle","doctor","nurse"],char:"\u{1f489}",fitzpatrick_scale:!1,category:"objects"},dna:{keywords:["biologist","genetics","life"],char:"\u{1f9ec}",fitzpatrick_scale:!1,category:"objects"},microbe:{keywords:["amoeba","bacteria","germs"],char:"\u{1f9a0}",fitzpatrick_scale:!1,category:"objects"},petri_dish:{keywords:["bacteria","biology","culture","lab"],char:"\u{1f9eb}",fitzpatrick_scale:!1,category:"objects"},test_tube:{keywords:["chemistry","experiment","lab","science"],char:"\u{1f9ea}",fitzpatrick_scale:!1,category:"objects"},thermometer:{keywords:["weather","temperature","hot","cold"],char:"\u{1f321}",fitzpatrick_scale:!1,category:"objects"},broom:{keywords:["cleaning","sweeping","witch"],char:"\u{1f9f9}",fitzpatrick_scale:!1,category:"objects"},basket:{keywords:["laundry"],char:"\u{1f9fa}",fitzpatrick_scale:!1,category:"objects"},toilet_paper:{keywords:["roll"],char:"\u{1f9fb}",fitzpatrick_scale:!1,category:"objects"},label:{keywords:["sale","tag"],char:"\u{1f3f7}",fitzpatrick_scale:!1,category:"objects"},bookmark:{keywords:["favorite","label","save"],char:"\u{1f516}",fitzpatrick_scale:!1,category:"objects"},toilet:{keywords:["restroom","wc","washroom","bathroom","potty"],char:"\u{1f6bd}",fitzpatrick_scale:!1,category:"objects"},shower:{keywords:["clean","water","bathroom"],char:"\u{1f6bf}",fitzpatrick_scale:!1,category:"objects"},bathtub:{keywords:["clean","shower","bathroom"],char:"\u{1f6c1}",fitzpatrick_scale:!1,category:"objects"},soap:{keywords:["bar","bathing","cleaning","lather"],char:"\u{1f9fc}",fitzpatrick_scale:!1,category:"objects"},sponge:{keywords:["absorbing","cleaning","porous"],char:"\u{1f9fd}",fitzpatrick_scale:!1,category:"objects"},lotion_bottle:{keywords:["moisturizer","sunscreen"],char:"\u{1f9f4}",fitzpatrick_scale:!1,category:"objects"},key:{keywords:["lock","door","password"],char:"\u{1f511}",fitzpatrick_scale:!1,category:"objects"},old_key:{keywords:["lock","door","password"],char:"\u{1f5dd}",fitzpatrick_scale:!1,category:"objects"},couch_and_lamp:{keywords:["read","chill"],char:"\u{1f6cb}",fitzpatrick_scale:!1,category:"objects"},sleeping_bed:{keywords:["bed","rest"],char:"\u{1f6cc}",fitzpatrick_scale:!0,category:"objects"},bed:{keywords:["sleep","rest"],char:"\u{1f6cf}",fitzpatrick_scale:!1,category:"objects"},door:{keywords:["house","entry","exit"],char:"\u{1f6aa}",fitzpatrick_scale:!1,category:"objects"},bellhop_bell:{keywords:["service"],char:"\u{1f6ce}",fitzpatrick_scale:!1,category:"objects"},teddy_bear:{keywords:["plush","stuffed"],char:"\u{1f9f8}",fitzpatrick_scale:!1,category:"objects"},framed_picture:{keywords:["photography"],char:"\u{1f5bc}",fitzpatrick_scale:!1,category:"objects"},world_map:{keywords:["location","direction"],char:"\u{1f5fa}",fitzpatrick_scale:!1,category:"objects"},parasol_on_ground:{keywords:["weather","summer"],char:"\u26f1",fitzpatrick_scale:!1,category:"objects"},moyai:{keywords:["rock","easter island","moai"],char:"\u{1f5ff}",fitzpatrick_scale:!1,category:"objects"},shopping:{keywords:["mall","buy","purchase"],char:"\u{1f6cd}",fitzpatrick_scale:!1,category:"objects"},shopping_cart:{keywords:["trolley"],char:"\u{1f6d2}",fitzpatrick_scale:!1,category:"objects"},balloon:{keywords:["party","celebration","birthday","circus"],char:"\u{1f388}",fitzpatrick_scale:!1,category:"objects"},flags:{keywords:["fish","japanese","koinobori","carp","banner"],char:"\u{1f38f}",fitzpatrick_scale:!1,category:"objects"},ribbon:{keywords:["decoration","pink","girl","bowtie"],char:"\u{1f380}",fitzpatrick_scale:!1,category:"objects"},gift:{keywords:["present","birthday","christmas","xmas"],char:"\u{1f381}",fitzpatrick_scale:!1,category:"objects"},confetti_ball:{keywords:["festival","party","birthday","circus"],char:"\u{1f38a}",fitzpatrick_scale:!1,category:"objects"},tada:{keywords:["party","congratulations","birthday","magic","circus","celebration"],char:"\u{1f389}",fitzpatrick_scale:!1,category:"objects"},dolls:{keywords:["japanese","toy","kimono"],char:"\u{1f38e}",fitzpatrick_scale:!1,category:"objects"},wind_chime:{keywords:["nature","ding","spring","bell"],char:"\u{1f390}",fitzpatrick_scale:!1,category:"objects"},crossed_flags:{keywords:["japanese","nation","country","border"],char:"\u{1f38c}",fitzpatrick_scale:!1,category:"objects"},izakaya_lantern:{keywords:["light","paper","halloween","spooky"],char:"\u{1f3ee}",fitzpatrick_scale:!1,category:"objects"},red_envelope:{keywords:["gift"],char:"\u{1f9e7}",fitzpatrick_scale:!1,category:"objects"},email:{keywords:["letter","postal","inbox","communication"],char:"\u2709\ufe0f",fitzpatrick_scale:!1,category:"objects"},envelope_with_arrow:{keywords:["email","communication"],char:"\u{1f4e9}",fitzpatrick_scale:!1,category:"objects"},incoming_envelope:{keywords:["email","inbox"],char:"\u{1f4e8}",fitzpatrick_scale:!1,category:"objects"},"e-mail":{keywords:["communication","inbox"],char:"\u{1f4e7}",fitzpatrick_scale:!1,category:"objects"},love_letter:{keywords:["email","like","affection","envelope","valentines"],char:"\u{1f48c}",fitzpatrick_scale:!1,category:"objects"},postbox:{keywords:["email","letter","envelope"],char:"\u{1f4ee}",fitzpatrick_scale:!1,category:"objects"},mailbox_closed:{keywords:["email","communication","inbox"],char:"\u{1f4ea}",fitzpatrick_scale:!1,category:"objects"},mailbox:{keywords:["email","inbox","communication"],char:"\u{1f4eb}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_mail:{keywords:["email","inbox","communication"],char:"\u{1f4ec}",fitzpatrick_scale:!1,category:"objects"},mailbox_with_no_mail:{keywords:["email","inbox"],char:"\u{1f4ed}",fitzpatrick_scale:!1,category:"objects"},package:{keywords:["mail","gift","cardboard","box","moving"],char:"\u{1f4e6}",fitzpatrick_scale:!1,category:"objects"},postal_horn:{keywords:["instrument","music"],char:"\u{1f4ef}",fitzpatrick_scale:!1,category:"objects"},inbox_tray:{keywords:["email","documents"],char:"\u{1f4e5}",fitzpatrick_scale:!1,category:"objects"},outbox_tray:{keywords:["inbox","email"],char:"\u{1f4e4}",fitzpatrick_scale:!1,category:"objects"},scroll:{keywords:["documents","ancient","history","paper"],char:"\u{1f4dc}",fitzpatrick_scale:!1,category:"objects"},page_with_curl:{keywords:["documents","office","paper"],char:"\u{1f4c3}",fitzpatrick_scale:!1,category:"objects"},bookmark_tabs:{keywords:["favorite","save","order","tidy"],char:"\u{1f4d1}",fitzpatrick_scale:!1,category:"objects"},receipt:{keywords:["accounting","expenses"],char:"\u{1f9fe}",fitzpatrick_scale:!1,category:"objects"},bar_chart:{keywords:["graph","presentation","stats"],char:"\u{1f4ca}",fitzpatrick_scale:!1,category:"objects"},chart_with_upwards_trend:{keywords:["graph","presentation","stats","recovery","business","economics","money","sales","good","success"],char:"\u{1f4c8}",fitzpatrick_scale:!1,category:"objects"},chart_with_downwards_trend:{keywords:["graph","presentation","stats","recession","business","economics","money","sales","bad","failure"],char:"\u{1f4c9}",fitzpatrick_scale:!1,category:"objects"},page_facing_up:{keywords:["documents","office","paper","information"],char:"\u{1f4c4}",fitzpatrick_scale:!1,category:"objects"},date:{keywords:["calendar","schedule"],char:"\u{1f4c5}",fitzpatrick_scale:!1,category:"objects"},calendar:{keywords:["schedule","date","planning"],char:"\u{1f4c6}",fitzpatrick_scale:!1,category:"objects"},spiral_calendar:{keywords:["date","schedule","planning"],char:"\u{1f5d3}",fitzpatrick_scale:!1,category:"objects"},card_index:{keywords:["business","stationery"],char:"\u{1f4c7}",fitzpatrick_scale:!1,category:"objects"},card_file_box:{keywords:["business","stationery"],char:"\u{1f5c3}",fitzpatrick_scale:!1,category:"objects"},ballot_box:{keywords:["election","vote"],char:"\u{1f5f3}",fitzpatrick_scale:!1,category:"objects"},file_cabinet:{keywords:["filing","organizing"],char:"\u{1f5c4}",fitzpatrick_scale:!1,category:"objects"},clipboard:{keywords:["stationery","documents"],char:"\u{1f4cb}",fitzpatrick_scale:!1,category:"objects"},spiral_notepad:{keywords:["memo","stationery"],char:"\u{1f5d2}",fitzpatrick_scale:!1,category:"objects"},file_folder:{keywords:["documents","business","office"],char:"\u{1f4c1}",fitzpatrick_scale:!1,category:"objects"},open_file_folder:{keywords:["documents","load"],char:"\u{1f4c2}",fitzpatrick_scale:!1,category:"objects"},card_index_dividers:{keywords:["organizing","business","stationery"],char:"\u{1f5c2}",fitzpatrick_scale:!1,category:"objects"},newspaper_roll:{keywords:["press","headline"],char:"\u{1f5de}",fitzpatrick_scale:!1,category:"objects"},newspaper:{keywords:["press","headline"],char:"\u{1f4f0}",fitzpatrick_scale:!1,category:"objects"},notebook:{keywords:["stationery","record","notes","paper","study"],char:"\u{1f4d3}",fitzpatrick_scale:!1,category:"objects"},closed_book:{keywords:["read","library","knowledge","textbook","learn"],char:"\u{1f4d5}",fitzpatrick_scale:!1,category:"objects"},green_book:{keywords:["read","library","knowledge","study"],char:"\u{1f4d7}",fitzpatrick_scale:!1,category:"objects"},blue_book:{keywords:["read","library","knowledge","learn","study"],char:"\u{1f4d8}",fitzpatrick_scale:!1,category:"objects"},orange_book:{keywords:["read","library","knowledge","textbook","study"],char:"\u{1f4d9}",fitzpatrick_scale:!1,category:"objects"},notebook_with_decorative_cover:{keywords:["classroom","notes","record","paper","study"],char:"\u{1f4d4}",fitzpatrick_scale:!1,category:"objects"},ledger:{keywords:["notes","paper"],char:"\u{1f4d2}",fitzpatrick_scale:!1,category:"objects"},books:{keywords:["literature","library","study"],char:"\u{1f4da}",fitzpatrick_scale:!1,category:"objects"},open_book:{keywords:["book","read","library","knowledge","literature","learn","study"],char:"\u{1f4d6}",fitzpatrick_scale:!1,category:"objects"},safety_pin:{keywords:["diaper"],char:"\u{1f9f7}",fitzpatrick_scale:!1,category:"objects"},link:{keywords:["rings","url"],char:"\u{1f517}",fitzpatrick_scale:!1,category:"objects"},paperclip:{keywords:["documents","stationery"],char:"\u{1f4ce}",fitzpatrick_scale:!1,category:"objects"},paperclips:{keywords:["documents","stationery"],char:"\u{1f587}",fitzpatrick_scale:!1,category:"objects"},scissors:{keywords:["stationery","cut"],char:"\u2702\ufe0f",fitzpatrick_scale:!1,category:"objects"},triangular_ruler:{keywords:["stationery","math","architect","sketch"],char:"\u{1f4d0}",fitzpatrick_scale:!1,category:"objects"},straight_ruler:{keywords:["stationery","calculate","length","math","school","drawing","architect","sketch"],char:"\u{1f4cf}",fitzpatrick_scale:!1,category:"objects"},abacus:{keywords:["calculation"],char:"\u{1f9ee}",fitzpatrick_scale:!1,category:"objects"},pushpin:{keywords:["stationery","mark","here"],char:"\u{1f4cc}",fitzpatrick_scale:!1,category:"objects"},round_pushpin:{keywords:["stationery","location","map","here"],char:"\u{1f4cd}",fitzpatrick_scale:!1,category:"objects"},triangular_flag_on_post:{keywords:["mark","milestone","place"],char:"\u{1f6a9}",fitzpatrick_scale:!1,category:"objects"},white_flag:{keywords:["losing","loser","lost","surrender","give up","fail"],char:"\u{1f3f3}",fitzpatrick_scale:!1,category:"objects"},black_flag:{keywords:["pirate"],char:"\u{1f3f4}",fitzpatrick_scale:!1,category:"objects"},rainbow_flag:{keywords:["flag","rainbow","pride","gay","lgbt","glbt","queer","homosexual","lesbian","bisexual","transgender"],char:"\u{1f3f3}\ufe0f\u200d\u{1f308}",fitzpatrick_scale:!1,category:"objects"},closed_lock_with_key:{keywords:["security","privacy"],char:"\u{1f510}",fitzpatrick_scale:!1,category:"objects"},lock:{keywords:["security","password","padlock"],char:"\u{1f512}",fitzpatrick_scale:!1,category:"objects"},unlock:{keywords:["privacy","security"],char:"\u{1f513}",fitzpatrick_scale:!1,category:"objects"},lock_with_ink_pen:{keywords:["security","secret"],char:"\u{1f50f}",fitzpatrick_scale:!1,category:"objects"},pen:{keywords:["stationery","writing","write"],char:"\u{1f58a}",fitzpatrick_scale:!1,category:"objects"},fountain_pen:{keywords:["stationery","writing","write"],char:"\u{1f58b}",fitzpatrick_scale:!1,category:"objects"},black_nib:{keywords:["pen","stationery","writing","write"],char:"\u2712\ufe0f",fitzpatrick_scale:!1,category:"objects"},memo:{keywords:["write","documents","stationery","pencil","paper","writing","legal","exam","quiz","test","study","compose"],char:"\u{1f4dd}",fitzpatrick_scale:!1,category:"objects"},pencil2:{keywords:["stationery","write","paper","writing","school","study"],char:"\u270f\ufe0f",fitzpatrick_scale:!1,category:"objects"},crayon:{keywords:["drawing","creativity"],char:"\u{1f58d}",fitzpatrick_scale:!1,category:"objects"},paintbrush:{keywords:["drawing","creativity","art"],char:"\u{1f58c}",fitzpatrick_scale:!1,category:"objects"},mag:{keywords:["search","zoom","find","detective"],char:"\u{1f50d}",fitzpatrick_scale:!1,category:"objects"},mag_right:{keywords:["search","zoom","find","detective"],char:"\u{1f50e}",fitzpatrick_scale:!1,category:"objects"},heart:{keywords:["love","like","valentines"],char:"\u2764\ufe0f",fitzpatrick_scale:!1,category:"symbols"},orange_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f9e1}",fitzpatrick_scale:!1,category:"symbols"},yellow_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49b}",fitzpatrick_scale:!1,category:"symbols"},green_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49a}",fitzpatrick_scale:!1,category:"symbols"},blue_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f499}",fitzpatrick_scale:!1,category:"symbols"},purple_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f49c}",fitzpatrick_scale:!1,category:"symbols"},black_heart:{keywords:["evil"],char:"\u{1f5a4}",fitzpatrick_scale:!1,category:"symbols"},broken_heart:{keywords:["sad","sorry","break","heart","heartbreak"],char:"\u{1f494}",fitzpatrick_scale:!1,category:"symbols"},heavy_heart_exclamation:{keywords:["decoration","love"],char:"\u2763",fitzpatrick_scale:!1,category:"symbols"},two_hearts:{keywords:["love","like","affection","valentines","heart"],char:"\u{1f495}",fitzpatrick_scale:!1,category:"symbols"},revolving_hearts:{keywords:["love","like","affection","valentines"],char:"\u{1f49e}",fitzpatrick_scale:!1,category:"symbols"},heartbeat:{keywords:["love","like","affection","valentines","pink","heart"],char:"\u{1f493}",fitzpatrick_scale:!1,category:"symbols"},heartpulse:{keywords:["like","love","affection","valentines","pink"],char:"\u{1f497}",fitzpatrick_scale:!1,category:"symbols"},sparkling_heart:{keywords:["love","like","affection","valentines"],char:"\u{1f496}",fitzpatrick_scale:!1,category:"symbols"},cupid:{keywords:["love","like","heart","affection","valentines"],char:"\u{1f498}",fitzpatrick_scale:!1,category:"symbols"},gift_heart:{keywords:["love","valentines"],char:"\u{1f49d}",fitzpatrick_scale:!1,category:"symbols"},heart_decoration:{keywords:["purple-square","love","like"],char:"\u{1f49f}",fitzpatrick_scale:!1,category:"symbols"},peace_symbol:{keywords:["hippie"],char:"\u262e",fitzpatrick_scale:!1,category:"symbols"},latin_cross:{keywords:["christianity"],char:"\u271d",fitzpatrick_scale:!1,category:"symbols"},star_and_crescent:{keywords:["islam"],char:"\u262a",fitzpatrick_scale:!1,category:"symbols"},om:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u{1f549}",fitzpatrick_scale:!1,category:"symbols"},wheel_of_dharma:{keywords:["hinduism","buddhism","sikhism","jainism"],char:"\u2638",fitzpatrick_scale:!1,category:"symbols"},star_of_david:{keywords:["judaism"],char:"\u2721",fitzpatrick_scale:!1,category:"symbols"},six_pointed_star:{keywords:["purple-square","religion","jewish","hexagram"],char:"\u{1f52f}",fitzpatrick_scale:!1,category:"symbols"},menorah:{keywords:["hanukkah","candles","jewish"],char:"\u{1f54e}",fitzpatrick_scale:!1,category:"symbols"},yin_yang:{keywords:["balance"],char:"\u262f",fitzpatrick_scale:!1,category:"symbols"},orthodox_cross:{keywords:["suppedaneum","religion"],char:"\u2626",fitzpatrick_scale:!1,category:"symbols"},place_of_worship:{keywords:["religion","church","temple","prayer"],char:"\u{1f6d0}",fitzpatrick_scale:!1,category:"symbols"},ophiuchus:{keywords:["sign","purple-square","constellation","astrology"],char:"\u26ce",fitzpatrick_scale:!1,category:"symbols"},aries:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2648",fitzpatrick_scale:!1,category:"symbols"},taurus:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2649",fitzpatrick_scale:!1,category:"symbols"},gemini:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264a",fitzpatrick_scale:!1,category:"symbols"},cancer:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264b",fitzpatrick_scale:!1,category:"symbols"},leo:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264c",fitzpatrick_scale:!1,category:"symbols"},virgo:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u264d",fitzpatrick_scale:!1,category:"symbols"},libra:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u264e",fitzpatrick_scale:!1,category:"symbols"},scorpius:{keywords:["sign","zodiac","purple-square","astrology","scorpio"],char:"\u264f",fitzpatrick_scale:!1,category:"symbols"},sagittarius:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2650",fitzpatrick_scale:!1,category:"symbols"},capricorn:{keywords:["sign","zodiac","purple-square","astrology"],char:"\u2651",fitzpatrick_scale:!1,category:"symbols"},aquarius:{keywords:["sign","purple-square","zodiac","astrology"],char:"\u2652",fitzpatrick_scale:!1,category:"symbols"},pisces:{keywords:["purple-square","sign","zodiac","astrology"],char:"\u2653",fitzpatrick_scale:!1,category:"symbols"},id:{keywords:["purple-square","words"],char:"\u{1f194}",fitzpatrick_scale:!1,category:"symbols"},atom_symbol:{keywords:["science","physics","chemistry"],char:"\u269b",fitzpatrick_scale:!1,category:"symbols"},u7a7a:{keywords:["kanji","japanese","chinese","empty","sky","blue-square"],char:"\u{1f233}",fitzpatrick_scale:!1,category:"symbols"},u5272:{keywords:["cut","divide","chinese","kanji","pink-square"],char:"\u{1f239}",fitzpatrick_scale:!1,category:"symbols"},radioactive:{keywords:["nuclear","danger"],char:"\u2622",fitzpatrick_scale:!1,category:"symbols"},biohazard:{keywords:["danger"],char:"\u2623",fitzpatrick_scale:!1,category:"symbols"},mobile_phone_off:{keywords:["mute","orange-square","silence","quiet"],char:"\u{1f4f4}",fitzpatrick_scale:!1,category:"symbols"},vibration_mode:{keywords:["orange-square","phone"],char:"\u{1f4f3}",fitzpatrick_scale:!1,category:"symbols"},u6709:{keywords:["orange-square","chinese","have","kanji"],char:"\u{1f236}",fitzpatrick_scale:!1,category:"symbols"},u7121:{keywords:["nothing","chinese","kanji","japanese","orange-square"],char:"\u{1f21a}",fitzpatrick_scale:!1,category:"symbols"},u7533:{keywords:["chinese","japanese","kanji","orange-square"],char:"\u{1f238}",fitzpatrick_scale:!1,category:"symbols"},u55b6:{keywords:["japanese","opening hours","orange-square"],char:"\u{1f23a}",fitzpatrick_scale:!1,category:"symbols"},u6708:{keywords:["chinese","month","moon","japanese","orange-square","kanji"],char:"\u{1f237}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_pointed_black_star:{keywords:["orange-square","shape","polygon"],char:"\u2734\ufe0f",fitzpatrick_scale:!1,category:"symbols"},vs:{keywords:["words","orange-square"],char:"\u{1f19a}",fitzpatrick_scale:!1,category:"symbols"},accept:{keywords:["ok","good","chinese","kanji","agree","yes","orange-circle"],char:"\u{1f251}",fitzpatrick_scale:!1,category:"symbols"},white_flower:{keywords:["japanese","spring"],char:"\u{1f4ae}",fitzpatrick_scale:!1,category:"symbols"},ideograph_advantage:{keywords:["chinese","kanji","obtain","get","circle"],char:"\u{1f250}",fitzpatrick_scale:!1,category:"symbols"},secret:{keywords:["privacy","chinese","sshh","kanji","red-circle"],char:"\u3299\ufe0f",fitzpatrick_scale:!1,category:"symbols"},congratulations:{keywords:["chinese","kanji","japanese","red-circle"],char:"\u3297\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u5408:{keywords:["japanese","chinese","join","kanji","red-square"],char:"\u{1f234}",fitzpatrick_scale:!1,category:"symbols"},u6e80:{keywords:["full","chinese","japanese","red-square","kanji"],char:"\u{1f235}",fitzpatrick_scale:!1,category:"symbols"},u7981:{keywords:["kanji","japanese","chinese","forbidden","limit","restricted","red-square"],char:"\u{1f232}",fitzpatrick_scale:!1,category:"symbols"},a:{keywords:["red-square","alphabet","letter"],char:"\u{1f170}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},b:{keywords:["red-square","alphabet","letter"],char:"\u{1f171}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},ab:{keywords:["red-square","alphabet"],char:"\u{1f18e}",fitzpatrick_scale:!1,category:"symbols"},cl:{keywords:["alphabet","words","red-square"],char:"\u{1f191}",fitzpatrick_scale:!1,category:"symbols"},o2:{keywords:["alphabet","red-square","letter"],char:"\u{1f17e}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},sos:{keywords:["help","red-square","words","emergency","911"],char:"\u{1f198}",fitzpatrick_scale:!1,category:"symbols"},no_entry:{keywords:["limit","security","privacy","bad","denied","stop","circle"],char:"\u26d4",fitzpatrick_scale:!1,category:"symbols"},name_badge:{keywords:["fire","forbid"],char:"\u{1f4db}",fitzpatrick_scale:!1,category:"symbols"},no_entry_sign:{keywords:["forbid","stop","limit","denied","disallow","circle"],char:"\u{1f6ab}",fitzpatrick_scale:!1,category:"symbols"},x:{keywords:["no","delete","remove","cancel","red"],char:"\u274c",fitzpatrick_scale:!1,category:"symbols"},o:{keywords:["circle","round"],char:"\u2b55",fitzpatrick_scale:!1,category:"symbols"},stop_sign:{keywords:["stop"],char:"\u{1f6d1}",fitzpatrick_scale:!1,category:"symbols"},anger:{keywords:["angry","mad"],char:"\u{1f4a2}",fitzpatrick_scale:!1,category:"symbols"},hotsprings:{keywords:["bath","warm","relax"],char:"\u2668\ufe0f",fitzpatrick_scale:!1,category:"symbols"},no_pedestrians:{keywords:["rules","crossing","walking","circle"],char:"\u{1f6b7}",fitzpatrick_scale:!1,category:"symbols"},do_not_litter:{keywords:["trash","bin","garbage","circle"],char:"\u{1f6af}",fitzpatrick_scale:!1,category:"symbols"},no_bicycles:{keywords:["cyclist","prohibited","circle"],char:"\u{1f6b3}",fitzpatrick_scale:!1,category:"symbols"},"non-potable_water":{keywords:["drink","faucet","tap","circle"],char:"\u{1f6b1}",fitzpatrick_scale:!1,category:"symbols"},underage:{keywords:["18","drink","pub","night","minor","circle"],char:"\u{1f51e}",fitzpatrick_scale:!1,category:"symbols"},no_mobile_phones:{keywords:["iphone","mute","circle"],char:"\u{1f4f5}",fitzpatrick_scale:!1,category:"symbols"},exclamation:{keywords:["heavy_exclamation_mark","danger","surprise","punctuation","wow","warning"],char:"\u2757",fitzpatrick_scale:!1,category:"symbols"},grey_exclamation:{keywords:["surprise","punctuation","gray","wow","warning"],char:"\u2755",fitzpatrick_scale:!1,category:"symbols"},question:{keywords:["doubt","confused"],char:"\u2753",fitzpatrick_scale:!1,category:"symbols"},grey_question:{keywords:["doubts","gray","huh","confused"],char:"\u2754",fitzpatrick_scale:!1,category:"symbols"},bangbang:{keywords:["exclamation","surprise"],char:"\u203c\ufe0f",fitzpatrick_scale:!1,category:"symbols"},interrobang:{keywords:["wat","punctuation","surprise"],char:"\u2049\ufe0f",fitzpatrick_scale:!1,category:"symbols"},100:{keywords:["score","perfect","numbers","century","exam","quiz","test","pass","hundred"],char:"\u{1f4af}",fitzpatrick_scale:!1,category:"symbols"},low_brightness:{keywords:["sun","afternoon","warm","summer"],char:"\u{1f505}",fitzpatrick_scale:!1,category:"symbols"},high_brightness:{keywords:["sun","light"],char:"\u{1f506}",fitzpatrick_scale:!1,category:"symbols"},trident:{keywords:["weapon","spear"],char:"\u{1f531}",fitzpatrick_scale:!1,category:"symbols"},fleur_de_lis:{keywords:["decorative","scout"],char:"\u269c",fitzpatrick_scale:!1,category:"symbols"},part_alternation_mark:{keywords:["graph","presentation","stats","business","economics","bad"],char:"\u303d\ufe0f",fitzpatrick_scale:!1,category:"symbols"},warning:{keywords:["exclamation","wip","alert","error","problem","issue"],char:"\u26a0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},children_crossing:{keywords:["school","warning","danger","sign","driving","yellow-diamond"],char:"\u{1f6b8}",fitzpatrick_scale:!1,category:"symbols"},beginner:{keywords:["badge","shield"],char:"\u{1f530}",fitzpatrick_scale:!1,category:"symbols"},recycle:{keywords:["arrow","environment","garbage","trash"],char:"\u267b\ufe0f",fitzpatrick_scale:!1,category:"symbols"},u6307:{keywords:["chinese","point","green-square","kanji"],char:"\u{1f22f}",fitzpatrick_scale:!1,category:"symbols"},chart:{keywords:["green-square","graph","presentation","stats"],char:"\u{1f4b9}",fitzpatrick_scale:!1,category:"symbols"},sparkle:{keywords:["stars","green-square","awesome","good","fireworks"],char:"\u2747\ufe0f",fitzpatrick_scale:!1,category:"symbols"},eight_spoked_asterisk:{keywords:["star","sparkle","green-square"],char:"\u2733\ufe0f",fitzpatrick_scale:!1,category:"symbols"},negative_squared_cross_mark:{keywords:["x","green-square","no","deny"],char:"\u274e",fitzpatrick_scale:!1,category:"symbols"},white_check_mark:{keywords:["green-square","ok","agree","vote","election","answer","tick"],char:"\u2705",fitzpatrick_scale:!1,category:"symbols"},diamond_shape_with_a_dot_inside:{keywords:["jewel","blue","gem","crystal","fancy"],char:"\u{1f4a0}",fitzpatrick_scale:!1,category:"symbols"},cyclone:{keywords:["weather","swirl","blue","cloud","vortex","spiral","whirlpool","spin","tornado","hurricane","typhoon"],char:"\u{1f300}",fitzpatrick_scale:!1,category:"symbols"},loop:{keywords:["tape","cassette"],char:"\u27bf",fitzpatrick_scale:!1,category:"symbols"},globe_with_meridians:{keywords:["earth","international","world","internet","interweb","i18n"],char:"\u{1f310}",fitzpatrick_scale:!1,category:"symbols"},m:{keywords:["alphabet","blue-circle","letter"],char:"\u24c2\ufe0f",fitzpatrick_scale:!1,category:"symbols"},atm:{keywords:["money","sales","cash","blue-square","payment","bank"],char:"\u{1f3e7}",fitzpatrick_scale:!1,category:"symbols"},sa:{keywords:["japanese","blue-square","katakana"],char:"\u{1f202}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},passport_control:{keywords:["custom","blue-square"],char:"\u{1f6c2}",fitzpatrick_scale:!1,category:"symbols"},customs:{keywords:["passport","border","blue-square"],char:"\u{1f6c3}",fitzpatrick_scale:!1,category:"symbols"},baggage_claim:{keywords:["blue-square","airport","transport"],char:"\u{1f6c4}",fitzpatrick_scale:!1,category:"symbols"},left_luggage:{keywords:["blue-square","travel"],char:"\u{1f6c5}",fitzpatrick_scale:!1,category:"symbols"},wheelchair:{keywords:["blue-square","disabled","a11y","accessibility"],char:"\u267f",fitzpatrick_scale:!1,category:"symbols"},no_smoking:{keywords:["cigarette","blue-square","smell","smoke"],char:"\u{1f6ad}",fitzpatrick_scale:!1,category:"symbols"},wc:{keywords:["toilet","restroom","blue-square"],char:"\u{1f6be}",fitzpatrick_scale:!1,category:"symbols"},parking:{keywords:["cars","blue-square","alphabet","letter"],char:"\u{1f17f}\ufe0f",fitzpatrick_scale:!1,category:"symbols"},potable_water:{keywords:["blue-square","liquid","restroom","cleaning","faucet"],char:"\u{1f6b0}",fitzpatrick_scale:!1,category:"symbols"},mens:{keywords:["toilet","restroom","wc","blue-square","gender","male"],char:"\u{1f6b9}",fitzpatrick_scale:!1,category:"symbols"},womens:{keywords:["purple-square","woman","female","toilet","loo","restroom","gender"],char:"\u{1f6ba}",fitzpatrick_scale:!1,category:"symbols"},baby_symbol:{keywords:["orange-square","child"],char:"\u{1f6bc}",fitzpatrick_scale:!1,category:"symbols"},restroom:{keywords:["blue-square","toilet","refresh","wc","gender"],char:"\u{1f6bb}",fitzpatrick_scale:!1,category:"symbols"},put_litter_in_its_place:{keywords:["blue-square","sign","human","info"],char:"\u{1f6ae}",fitzpatrick_scale:!1,category:"symbols"},cinema:{keywords:["blue-square","record","film","movie","curtain","stage","theater"],char:"\u{1f3a6}",fitzpatrick_scale:!1,category:"symbols"},signal_strength:{keywords:["blue-square","reception","phone","internet","connection","wifi","bluetooth","bars"],char:"\u{1f4f6}",fitzpatrick_scale:!1,category:"symbols"},koko:{keywords:["blue-square","here","katakana","japanese","destination"],char:"\u{1f201}",fitzpatrick_scale:!1,category:"symbols"},ng:{keywords:["blue-square","words","shape","icon"],char:"\u{1f196}",fitzpatrick_scale:!1,category:"symbols"},ok:{keywords:["good","agree","yes","blue-square"],char:"\u{1f197}",fitzpatrick_scale:!1,category:"symbols"},up:{keywords:["blue-square","above","high"],char:"\u{1f199}",fitzpatrick_scale:!1,category:"symbols"},cool:{keywords:["words","blue-square"],char:"\u{1f192}",fitzpatrick_scale:!1,category:"symbols"},new:{keywords:["blue-square","words","start"],char:"\u{1f195}",fitzpatrick_scale:!1,category:"symbols"},free:{keywords:["blue-square","words"],char:"\u{1f193}",fitzpatrick_scale:!1,category:"symbols"},zero:{keywords:["0","numbers","blue-square","null"],char:"0\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},one:{keywords:["blue-square","numbers","1"],char:"1\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},two:{keywords:["numbers","2","prime","blue-square"],char:"2\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},three:{keywords:["3","numbers","prime","blue-square"],char:"3\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},four:{keywords:["4","numbers","blue-square"],char:"4\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},five:{keywords:["5","numbers","blue-square","prime"],char:"5\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},six:{keywords:["6","numbers","blue-square"],char:"6\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},seven:{keywords:["7","numbers","blue-square","prime"],char:"7\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},eight:{keywords:["8","blue-square","numbers"],char:"8\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},nine:{keywords:["blue-square","numbers","9"],char:"9\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},keycap_ten:{keywords:["numbers","10","blue-square"],char:"\u{1f51f}",fitzpatrick_scale:!1,category:"symbols"},asterisk:{keywords:["star","keycap"],char:"*\u20e3",fitzpatrick_scale:!1,category:"symbols"},1234:{keywords:["numbers","blue-square"],char:"\u{1f522}",fitzpatrick_scale:!1,category:"symbols"},eject_button:{keywords:["blue-square"],char:"\u23cf\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_forward:{keywords:["blue-square","right","direction","play"],char:"\u25b6\ufe0f",fitzpatrick_scale:!1,category:"symbols"},pause_button:{keywords:["pause","blue-square"],char:"\u23f8",fitzpatrick_scale:!1,category:"symbols"},next_track_button:{keywords:["forward","next","blue-square"],char:"\u23ed",fitzpatrick_scale:!1,category:"symbols"},stop_button:{keywords:["blue-square"],char:"\u23f9",fitzpatrick_scale:!1,category:"symbols"},record_button:{keywords:["blue-square"],char:"\u23fa",fitzpatrick_scale:!1,category:"symbols"},play_or_pause_button:{keywords:["blue-square","play","pause"],char:"\u23ef",fitzpatrick_scale:!1,category:"symbols"},previous_track_button:{keywords:["backward"],char:"\u23ee",fitzpatrick_scale:!1,category:"symbols"},fast_forward:{keywords:["blue-square","play","speed","continue"],char:"\u23e9",fitzpatrick_scale:!1,category:"symbols"},rewind:{keywords:["play","blue-square"],char:"\u23ea",fitzpatrick_scale:!1,category:"symbols"},twisted_rightwards_arrows:{keywords:["blue-square","shuffle","music","random"],char:"\u{1f500}",fitzpatrick_scale:!1,category:"symbols"},repeat:{keywords:["loop","record"],char:"\u{1f501}",fitzpatrick_scale:!1,category:"symbols"},repeat_one:{keywords:["blue-square","loop"],char:"\u{1f502}",fitzpatrick_scale:!1,category:"symbols"},arrow_backward:{keywords:["blue-square","left","direction"],char:"\u25c0\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_small:{keywords:["blue-square","triangle","direction","point","forward","top"],char:"\u{1f53c}",fitzpatrick_scale:!1,category:"symbols"},arrow_down_small:{keywords:["blue-square","direction","bottom"],char:"\u{1f53d}",fitzpatrick_scale:!1,category:"symbols"},arrow_double_up:{keywords:["blue-square","direction","top"],char:"\u23eb",fitzpatrick_scale:!1,category:"symbols"},arrow_double_down:{keywords:["blue-square","direction","bottom"],char:"\u23ec",fitzpatrick_scale:!1,category:"symbols"},arrow_right:{keywords:["blue-square","next"],char:"\u27a1\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_left:{keywords:["blue-square","previous","back"],char:"\u2b05\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up:{keywords:["blue-square","continue","top","direction"],char:"\u2b06\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_down:{keywords:["blue-square","direction","bottom"],char:"\u2b07\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_right:{keywords:["blue-square","point","direction","diagonal","northeast"],char:"\u2197\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_right:{keywords:["blue-square","direction","diagonal","southeast"],char:"\u2198\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_lower_left:{keywords:["blue-square","direction","diagonal","southwest"],char:"\u2199\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_upper_left:{keywords:["blue-square","point","direction","diagonal","northwest"],char:"\u2196\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_up_down:{keywords:["blue-square","direction","way","vertical"],char:"\u2195\ufe0f",fitzpatrick_scale:!1,category:"symbols"},left_right_arrow:{keywords:["shape","direction","horizontal","sideways"],char:"\u2194\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_counterclockwise:{keywords:["blue-square","sync","cycle"],char:"\u{1f504}",fitzpatrick_scale:!1,category:"symbols"},arrow_right_hook:{keywords:["blue-square","return","rotate","direction"],char:"\u21aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},leftwards_arrow_with_hook:{keywords:["back","return","blue-square","undo","enter"],char:"\u21a9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_up:{keywords:["blue-square","direction","top"],char:"\u2934\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrow_heading_down:{keywords:["blue-square","direction","bottom"],char:"\u2935\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hash:{keywords:["symbol","blue-square","twitter"],char:"#\ufe0f\u20e3",fitzpatrick_scale:!1,category:"symbols"},information_source:{keywords:["blue-square","alphabet","letter"],char:"\u2139\ufe0f",fitzpatrick_scale:!1,category:"symbols"},abc:{keywords:["blue-square","alphabet"],char:"\u{1f524}",fitzpatrick_scale:!1,category:"symbols"},abcd:{keywords:["blue-square","alphabet"],char:"\u{1f521}",fitzpatrick_scale:!1,category:"symbols"},capital_abcd:{keywords:["alphabet","words","blue-square"],char:"\u{1f520}",fitzpatrick_scale:!1,category:"symbols"},symbols:{keywords:["blue-square","music","note","ampersand","percent","glyphs","characters"],char:"\u{1f523}",fitzpatrick_scale:!1,category:"symbols"},musical_note:{keywords:["score","tone","sound"],char:"\u{1f3b5}",fitzpatrick_scale:!1,category:"symbols"},notes:{keywords:["music","score"],char:"\u{1f3b6}",fitzpatrick_scale:!1,category:"symbols"},wavy_dash:{keywords:["draw","line","moustache","mustache","squiggle","scribble"],char:"\u3030\ufe0f",fitzpatrick_scale:!1,category:"symbols"},curly_loop:{keywords:["scribble","draw","shape","squiggle"],char:"\u27b0",fitzpatrick_scale:!1,category:"symbols"},heavy_check_mark:{keywords:["ok","nike","answer","yes","tick"],char:"\u2714\ufe0f",fitzpatrick_scale:!1,category:"symbols"},arrows_clockwise:{keywords:["sync","cycle","round","repeat"],char:"\u{1f503}",fitzpatrick_scale:!1,category:"symbols"},heavy_plus_sign:{keywords:["math","calculation","addition","more","increase"],char:"\u2795",fitzpatrick_scale:!1,category:"symbols"},heavy_minus_sign:{keywords:["math","calculation","subtract","less"],char:"\u2796",fitzpatrick_scale:!1,category:"symbols"},heavy_division_sign:{keywords:["divide","math","calculation"],char:"\u2797",fitzpatrick_scale:!1,category:"symbols"},heavy_multiplication_x:{keywords:["math","calculation"],char:"\u2716\ufe0f",fitzpatrick_scale:!1,category:"symbols"},infinity:{keywords:["forever"],char:"\u267e",fitzpatrick_scale:!1,category:"symbols"},heavy_dollar_sign:{keywords:["money","sales","payment","currency","buck"],char:"\u{1f4b2}",fitzpatrick_scale:!1,category:"symbols"},currency_exchange:{keywords:["money","sales","dollar","travel"],char:"\u{1f4b1}",fitzpatrick_scale:!1,category:"symbols"},copyright:{keywords:["ip","license","circle","law","legal"],char:"\xa9\ufe0f",fitzpatrick_scale:!1,category:"symbols"},registered:{keywords:["alphabet","circle"],char:"\xae\ufe0f",fitzpatrick_scale:!1,category:"symbols"},tm:{keywords:["trademark","brand","law","legal"],char:"\u2122\ufe0f",fitzpatrick_scale:!1,category:"symbols"},end:{keywords:["words","arrow"],char:"\u{1f51a}",fitzpatrick_scale:!1,category:"symbols"},back:{keywords:["arrow","words","return"],char:"\u{1f519}",fitzpatrick_scale:!1,category:"symbols"},on:{keywords:["arrow","words"],char:"\u{1f51b}",fitzpatrick_scale:!1,category:"symbols"},top:{keywords:["words","blue-square"],char:"\u{1f51d}",fitzpatrick_scale:!1,category:"symbols"},soon:{keywords:["arrow","words"],char:"\u{1f51c}",fitzpatrick_scale:!1,category:"symbols"},ballot_box_with_check:{keywords:["ok","agree","confirm","black-square","vote","election","yes","tick"],char:"\u2611\ufe0f",fitzpatrick_scale:!1,category:"symbols"},radio_button:{keywords:["input","old","music","circle"],char:"\u{1f518}",fitzpatrick_scale:!1,category:"symbols"},white_circle:{keywords:["shape","round"],char:"\u26aa",fitzpatrick_scale:!1,category:"symbols"},black_circle:{keywords:["shape","button","round"],char:"\u26ab",fitzpatrick_scale:!1,category:"symbols"},red_circle:{keywords:["shape","error","danger"],char:"\u{1f534}",fitzpatrick_scale:!1,category:"symbols"},large_blue_circle:{keywords:["shape","icon","button"],char:"\u{1f535}",fitzpatrick_scale:!1,category:"symbols"},small_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f538}",fitzpatrick_scale:!1,category:"symbols"},small_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f539}",fitzpatrick_scale:!1,category:"symbols"},large_orange_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f536}",fitzpatrick_scale:!1,category:"symbols"},large_blue_diamond:{keywords:["shape","jewel","gem"],char:"\u{1f537}",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle:{keywords:["shape","direction","up","top"],char:"\u{1f53a}",fitzpatrick_scale:!1,category:"symbols"},black_small_square:{keywords:["shape","icon"],char:"\u25aa\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_small_square:{keywords:["shape","icon"],char:"\u25ab\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_large_square:{keywords:["shape","icon","button"],char:"\u2b1b",fitzpatrick_scale:!1,category:"symbols"},white_large_square:{keywords:["shape","icon","stone","button"],char:"\u2b1c",fitzpatrick_scale:!1,category:"symbols"},small_red_triangle_down:{keywords:["shape","direction","bottom"],char:"\u{1f53b}",fitzpatrick_scale:!1,category:"symbols"},black_medium_square:{keywords:["shape","button","icon"],char:"\u25fc\ufe0f",fitzpatrick_scale:!1,category:"symbols"},white_medium_square:{keywords:["shape","stone","icon"],char:"\u25fb\ufe0f",fitzpatrick_scale:!1,category:"symbols"},black_medium_small_square:{keywords:["icon","shape","button"],char:"\u25fe",fitzpatrick_scale:!1,category:"symbols"},white_medium_small_square:{keywords:["shape","stone","icon","button"],char:"\u25fd",fitzpatrick_scale:!1,category:"symbols"},black_square_button:{keywords:["shape","input","frame"],char:"\u{1f532}",fitzpatrick_scale:!1,category:"symbols"},white_square_button:{keywords:["shape","input"],char:"\u{1f533}",fitzpatrick_scale:!1,category:"symbols"},speaker:{keywords:["sound","volume","silence","broadcast"],char:"\u{1f508}",fitzpatrick_scale:!1,category:"symbols"},sound:{keywords:["volume","speaker","broadcast"],char:"\u{1f509}",fitzpatrick_scale:!1,category:"symbols"},loud_sound:{keywords:["volume","noise","noisy","speaker","broadcast"],char:"\u{1f50a}",fitzpatrick_scale:!1,category:"symbols"},mute:{keywords:["sound","volume","silence","quiet"],char:"\u{1f507}",fitzpatrick_scale:!1,category:"symbols"},mega:{keywords:["sound","speaker","volume"],char:"\u{1f4e3}",fitzpatrick_scale:!1,category:"symbols"},loudspeaker:{keywords:["volume","sound"],char:"\u{1f4e2}",fitzpatrick_scale:!1,category:"symbols"},bell:{keywords:["sound","notification","christmas","xmas","chime"],char:"\u{1f514}",fitzpatrick_scale:!1,category:"symbols"},no_bell:{keywords:["sound","volume","mute","quiet","silent"],char:"\u{1f515}",fitzpatrick_scale:!1,category:"symbols"},black_joker:{keywords:["poker","cards","game","play","magic"],char:"\u{1f0cf}",fitzpatrick_scale:!1,category:"symbols"},mahjong:{keywords:["game","play","chinese","kanji"],char:"\u{1f004}",fitzpatrick_scale:!1,category:"symbols"},spades:{keywords:["poker","cards","suits","magic"],char:"\u2660\ufe0f",fitzpatrick_scale:!1,category:"symbols"},clubs:{keywords:["poker","cards","magic","suits"],char:"\u2663\ufe0f",fitzpatrick_scale:!1,category:"symbols"},hearts:{keywords:["poker","cards","magic","suits"],char:"\u2665\ufe0f",fitzpatrick_scale:!1,category:"symbols"},diamonds:{keywords:["poker","cards","magic","suits"],char:"\u2666\ufe0f",fitzpatrick_scale:!1,category:"symbols"},flower_playing_cards:{keywords:["game","sunset","red"],char:"\u{1f3b4}",fitzpatrick_scale:!1,category:"symbols"},thought_balloon:{keywords:["bubble","cloud","speech","thinking","dream"],char:"\u{1f4ad}",fitzpatrick_scale:!1,category:"symbols"},right_anger_bubble:{keywords:["caption","speech","thinking","mad"],char:"\u{1f5ef}",fitzpatrick_scale:!1,category:"symbols"},speech_balloon:{keywords:["bubble","words","message","talk","chatting"],char:"\u{1f4ac}",fitzpatrick_scale:!1,category:"symbols"},left_speech_bubble:{keywords:["words","message","talk","chatting"],char:"\u{1f5e8}",fitzpatrick_scale:!1,category:"symbols"},clock1:{keywords:["time","late","early","schedule"],char:"\u{1f550}",fitzpatrick_scale:!1,category:"symbols"},clock2:{keywords:["time","late","early","schedule"],char:"\u{1f551}",fitzpatrick_scale:!1,category:"symbols"},clock3:{keywords:["time","late","early","schedule"],char:"\u{1f552}",fitzpatrick_scale:!1,category:"symbols"},clock4:{keywords:["time","late","early","schedule"],char:"\u{1f553}",fitzpatrick_scale:!1,category:"symbols"},clock5:{keywords:["time","late","early","schedule"],char:"\u{1f554}",fitzpatrick_scale:!1,category:"symbols"},clock6:{keywords:["time","late","early","schedule","dawn","dusk"],char:"\u{1f555}",fitzpatrick_scale:!1,category:"symbols"},clock7:{keywords:["time","late","early","schedule"],char:"\u{1f556}",fitzpatrick_scale:!1,category:"symbols"},clock8:{keywords:["time","late","early","schedule"],char:"\u{1f557}",fitzpatrick_scale:!1,category:"symbols"},clock9:{keywords:["time","late","early","schedule"],char:"\u{1f558}",fitzpatrick_scale:!1,category:"symbols"},clock10:{keywords:["time","late","early","schedule"],char:"\u{1f559}",fitzpatrick_scale:!1,category:"symbols"},clock11:{keywords:["time","late","early","schedule"],char:"\u{1f55a}",fitzpatrick_scale:!1,category:"symbols"},clock12:{keywords:["time","noon","midnight","midday","late","early","schedule"],char:"\u{1f55b}",fitzpatrick_scale:!1,category:"symbols"},clock130:{keywords:["time","late","early","schedule"],char:"\u{1f55c}",fitzpatrick_scale:!1,category:"symbols"},clock230:{keywords:["time","late","early","schedule"],char:"\u{1f55d}",fitzpatrick_scale:!1,category:"symbols"},clock330:{keywords:["time","late","early","schedule"],char:"\u{1f55e}",fitzpatrick_scale:!1,category:"symbols"},clock430:{keywords:["time","late","early","schedule"],char:"\u{1f55f}",fitzpatrick_scale:!1,category:"symbols"},clock530:{keywords:["time","late","early","schedule"],char:"\u{1f560}",fitzpatrick_scale:!1,category:"symbols"},clock630:{keywords:["time","late","early","schedule"],char:"\u{1f561}",fitzpatrick_scale:!1,category:"symbols"},clock730:{keywords:["time","late","early","schedule"],char:"\u{1f562}",fitzpatrick_scale:!1,category:"symbols"},clock830:{keywords:["time","late","early","schedule"],char:"\u{1f563}",fitzpatrick_scale:!1,category:"symbols"},clock930:{keywords:["time","late","early","schedule"],char:"\u{1f564}",fitzpatrick_scale:!1,category:"symbols"},clock1030:{keywords:["time","late","early","schedule"],char:"\u{1f565}",fitzpatrick_scale:!1,category:"symbols"},clock1130:{keywords:["time","late","early","schedule"],char:"\u{1f566}",fitzpatrick_scale:!1,category:"symbols"},clock1230:{keywords:["time","late","early","schedule"],char:"\u{1f567}",fitzpatrick_scale:!1,category:"symbols"},afghanistan:{keywords:["af","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},aland_islands:{keywords:["\xc5land","islands","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},albania:{keywords:["al","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},algeria:{keywords:["dz","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},american_samoa:{keywords:["american","ws","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},andorra:{keywords:["ad","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},angola:{keywords:["ao","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},anguilla:{keywords:["ai","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},antarctica:{keywords:["aq","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},antigua_barbuda:{keywords:["antigua","barbuda","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},argentina:{keywords:["ar","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},armenia:{keywords:["am","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},aruba:{keywords:["aw","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},australia:{keywords:["au","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},austria:{keywords:["at","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},azerbaijan:{keywords:["az","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},bahamas:{keywords:["bs","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},bahrain:{keywords:["bh","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},bangladesh:{keywords:["bd","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},barbados:{keywords:["bb","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},belarus:{keywords:["by","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},belgium:{keywords:["be","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},belize:{keywords:["bz","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},benin:{keywords:["bj","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},bermuda:{keywords:["bm","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},bhutan:{keywords:["bt","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},bolivia:{keywords:["bo","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},caribbean_netherlands:{keywords:["bonaire","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},bosnia_herzegovina:{keywords:["bosnia","herzegovina","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},botswana:{keywords:["bw","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},brazil:{keywords:["br","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},british_indian_ocean_territory:{keywords:["british","indian","ocean","territory","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},british_virgin_islands:{keywords:["british","virgin","islands","bvi","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},brunei:{keywords:["bn","darussalam","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},bulgaria:{keywords:["bg","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},burkina_faso:{keywords:["burkina","faso","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},burundi:{keywords:["bi","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},cape_verde:{keywords:["cabo","verde","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},cambodia:{keywords:["kh","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},cameroon:{keywords:["cm","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},canada:{keywords:["ca","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},canary_islands:{keywords:["canary","islands","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},cayman_islands:{keywords:["cayman","islands","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},central_african_republic:{keywords:["central","african","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},chad:{keywords:["td","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},chile:{keywords:["flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},cn:{keywords:["china","chinese","prc","flag","country","nation","banner"],char:"\u{1f1e8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},christmas_island:{keywords:["christmas","island","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},cocos_islands:{keywords:["cocos","keeling","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},colombia:{keywords:["co","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},comoros:{keywords:["km","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},congo_brazzaville:{keywords:["congo","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},congo_kinshasa:{keywords:["congo","democratic","republic","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},cook_islands:{keywords:["cook","islands","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},costa_rica:{keywords:["costa","rica","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},croatia:{keywords:["hr","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},cuba:{keywords:["cu","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},curacao:{keywords:["cura\xe7ao","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},cyprus:{keywords:["cy","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},czech_republic:{keywords:["cz","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},denmark:{keywords:["dk","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},djibouti:{keywords:["dj","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},dominica:{keywords:["dm","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},dominican_republic:{keywords:["dominican","republic","flag","nation","country","banner"],char:"\u{1f1e9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ecuador:{keywords:["ec","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},egypt:{keywords:["eg","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},el_salvador:{keywords:["el","salvador","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},equatorial_guinea:{keywords:["equatorial","gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},eritrea:{keywords:["er","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},estonia:{keywords:["ee","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ethiopia:{keywords:["et","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},eu:{keywords:["european","union","flag","banner"],char:"\u{1f1ea}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},falkland_islands:{keywords:["falkland","islands","malvinas","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},faroe_islands:{keywords:["faroe","islands","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},fiji:{keywords:["fj","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},finland:{keywords:["fi","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},fr:{keywords:["banner","flag","nation","france","french","country"],char:"\u{1f1eb}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},french_guiana:{keywords:["french","guiana","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_polynesia:{keywords:["french","polynesia","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},french_southern_territories:{keywords:["french","southern","territories","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},gabon:{keywords:["ga","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},gambia:{keywords:["gm","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},georgia:{keywords:["ge","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},de:{keywords:["german","nation","flag","country","banner"],char:"\u{1f1e9}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},ghana:{keywords:["gh","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},gibraltar:{keywords:["gi","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},greece:{keywords:["gr","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},greenland:{keywords:["gl","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},grenada:{keywords:["gd","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},guadeloupe:{keywords:["gp","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},guam:{keywords:["gu","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},guatemala:{keywords:["gt","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},guernsey:{keywords:["gg","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},guinea:{keywords:["gn","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},guinea_bissau:{keywords:["gw","bissau","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},guyana:{keywords:["gy","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},haiti:{keywords:["ht","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},honduras:{keywords:["hn","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},hong_kong:{keywords:["hong","kong","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},hungary:{keywords:["hu","flag","nation","country","banner"],char:"\u{1f1ed}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},iceland:{keywords:["is","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},india:{keywords:["in","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},indonesia:{keywords:["flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},iran:{keywords:["iran,","islamic","republic","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},iraq:{keywords:["iq","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},ireland:{keywords:["ie","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},isle_of_man:{keywords:["isle","man","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},israel:{keywords:["il","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},it:{keywords:["italy","flag","nation","country","banner"],char:"\u{1f1ee}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},cote_divoire:{keywords:["ivory","coast","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},jamaica:{keywords:["jm","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},jp:{keywords:["japanese","nation","flag","country","banner"],char:"\u{1f1ef}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},jersey:{keywords:["je","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},jordan:{keywords:["jo","flag","nation","country","banner"],char:"\u{1f1ef}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},kazakhstan:{keywords:["kz","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},kenya:{keywords:["ke","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},kiribati:{keywords:["ki","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},kosovo:{keywords:["xk","flag","nation","country","banner"],char:"\u{1f1fd}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},kuwait:{keywords:["kw","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},kyrgyzstan:{keywords:["kg","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},laos:{keywords:["lao","democratic","republic","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},latvia:{keywords:["lv","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},lebanon:{keywords:["lb","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},lesotho:{keywords:["ls","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},liberia:{keywords:["lr","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},libya:{keywords:["ly","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},liechtenstein:{keywords:["li","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},lithuania:{keywords:["lt","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},luxembourg:{keywords:["lu","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},macau:{keywords:["macao","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},macedonia:{keywords:["macedonia,","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},madagascar:{keywords:["mg","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},malawi:{keywords:["mw","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},malaysia:{keywords:["my","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},maldives:{keywords:["mv","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},mali:{keywords:["ml","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},malta:{keywords:["mt","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},marshall_islands:{keywords:["marshall","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},martinique:{keywords:["mq","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f6}",fitzpatrick_scale:!1,category:"flags"},mauritania:{keywords:["mr","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},mauritius:{keywords:["mu","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},mayotte:{keywords:["yt","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},mexico:{keywords:["mx","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},micronesia:{keywords:["micronesia,","federated","states","flag","nation","country","banner"],char:"\u{1f1eb}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},moldova:{keywords:["moldova,","republic","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},monaco:{keywords:["mc","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},mongolia:{keywords:["mn","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},montenegro:{keywords:["me","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},montserrat:{keywords:["ms","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},morocco:{keywords:["ma","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},mozambique:{keywords:["mz","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},myanmar:{keywords:["mm","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},namibia:{keywords:["na","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},nauru:{keywords:["nr","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},nepal:{keywords:["np","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},netherlands:{keywords:["nl","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},new_caledonia:{keywords:["new","caledonia","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},new_zealand:{keywords:["new","zealand","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},nicaragua:{keywords:["ni","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},niger:{keywords:["ne","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},nigeria:{keywords:["flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},niue:{keywords:["nu","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},norfolk_island:{keywords:["norfolk","island","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},northern_mariana_islands:{keywords:["northern","mariana","islands","flag","nation","country","banner"],char:"\u{1f1f2}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},north_korea:{keywords:["north","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f5}",fitzpatrick_scale:!1,category:"flags"},norway:{keywords:["no","flag","nation","country","banner"],char:"\u{1f1f3}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},oman:{keywords:["om_symbol","flag","nation","country","banner"],char:"\u{1f1f4}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},pakistan:{keywords:["pk","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},palau:{keywords:["pw","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},palestinian_territories:{keywords:["palestine","palestinian","territories","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},panama:{keywords:["pa","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},papua_new_guinea:{keywords:["papua","new","guinea","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},paraguay:{keywords:["py","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},peru:{keywords:["pe","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},philippines:{keywords:["ph","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},pitcairn_islands:{keywords:["pitcairn","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},poland:{keywords:["pl","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},portugal:{keywords:["pt","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},puerto_rico:{keywords:["puerto","rico","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},qatar:{keywords:["qa","flag","nation","country","banner"],char:"\u{1f1f6}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},reunion:{keywords:["r\xe9union","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},romania:{keywords:["ro","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},ru:{keywords:["russian","federation","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},rwanda:{keywords:["rw","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},st_barthelemy:{keywords:["saint","barth\xe9lemy","flag","nation","country","banner"],char:"\u{1f1e7}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},st_helena:{keywords:["saint","helena","ascension","tristan","cunha","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},st_kitts_nevis:{keywords:["saint","kitts","nevis","flag","nation","country","banner"],char:"\u{1f1f0}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},st_lucia:{keywords:["saint","lucia","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},st_pierre_miquelon:{keywords:["saint","pierre","miquelon","flag","nation","country","banner"],char:"\u{1f1f5}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},st_vincent_grenadines:{keywords:["saint","vincent","grenadines","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},samoa:{keywords:["ws","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},san_marino:{keywords:["san","marino","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},sao_tome_principe:{keywords:["sao","tome","principe","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},saudi_arabia:{keywords:["flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},senegal:{keywords:["sn","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},serbia:{keywords:["rs","flag","nation","country","banner"],char:"\u{1f1f7}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},seychelles:{keywords:["sc","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},sierra_leone:{keywords:["sierra","leone","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},singapore:{keywords:["sg","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},sint_maarten:{keywords:["sint","maarten","dutch","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fd}",fitzpatrick_scale:!1,category:"flags"},slovakia:{keywords:["sk","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},slovenia:{keywords:["si","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},solomon_islands:{keywords:["solomon","islands","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},somalia:{keywords:["so","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},south_africa:{keywords:["south","africa","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},south_georgia_south_sandwich_islands:{keywords:["south","georgia","sandwich","islands","flag","nation","country","banner"],char:"\u{1f1ec}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},kr:{keywords:["south","korea","nation","flag","country","banner"],char:"\u{1f1f0}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},south_sudan:{keywords:["south","sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},es:{keywords:["spain","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},sri_lanka:{keywords:["sri","lanka","flag","nation","country","banner"],char:"\u{1f1f1}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},sudan:{keywords:["sd","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1e9}",fitzpatrick_scale:!1,category:"flags"},suriname:{keywords:["sr","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},swaziland:{keywords:["sz","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},sweden:{keywords:["se","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},switzerland:{keywords:["ch","flag","nation","country","banner"],char:"\u{1f1e8}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},syria:{keywords:["syrian","arab","republic","flag","nation","country","banner"],char:"\u{1f1f8}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},taiwan:{keywords:["tw","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},tajikistan:{keywords:["tj","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ef}",fitzpatrick_scale:!1,category:"flags"},tanzania:{keywords:["tanzania,","united","republic","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},thailand:{keywords:["th","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},timor_leste:{keywords:["timor","leste","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f1}",fitzpatrick_scale:!1,category:"flags"},togo:{keywords:["tg","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},tokelau:{keywords:["tk","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f0}",fitzpatrick_scale:!1,category:"flags"},tonga:{keywords:["to","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f4}",fitzpatrick_scale:!1,category:"flags"},trinidad_tobago:{keywords:["trinidad","tobago","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f9}",fitzpatrick_scale:!1,category:"flags"},tunisia:{keywords:["tn","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},tr:{keywords:["turkey","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f7}",fitzpatrick_scale:!1,category:"flags"},turkmenistan:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},turks_caicos_islands:{keywords:["turks","caicos","islands","flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1e8}",fitzpatrick_scale:!1,category:"flags"},tuvalu:{keywords:["flag","nation","country","banner"],char:"\u{1f1f9}\u{1f1fb}",fitzpatrick_scale:!1,category:"flags"},uganda:{keywords:["ug","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ec}",fitzpatrick_scale:!1,category:"flags"},ukraine:{keywords:["ua","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},united_arab_emirates:{keywords:["united","arab","emirates","flag","nation","country","banner"],char:"\u{1f1e6}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},uk:{keywords:["united","kingdom","great","britain","northern","ireland","flag","nation","country","banner","british","UK","english","england","union jack"],char:"\u{1f1ec}\u{1f1e7}",fitzpatrick_scale:!1,category:"flags"},england:{keywords:["flag","english"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0065}\u{e006e}\u{e0067}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},scotland:{keywords:["flag","scottish"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0073}\u{e0063}\u{e0074}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},wales:{keywords:["flag","welsh"],char:"\u{1f3f4}\u{e0067}\u{e0062}\u{e0077}\u{e006c}\u{e0073}\u{e007f}",fitzpatrick_scale:!1,category:"flags"},us:{keywords:["united","states","america","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1f8}",fitzpatrick_scale:!1,category:"flags"},us_virgin_islands:{keywords:["virgin","islands","us","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ee}",fitzpatrick_scale:!1,category:"flags"},uruguay:{keywords:["uy","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1fe}",fitzpatrick_scale:!1,category:"flags"},uzbekistan:{keywords:["uz","flag","nation","country","banner"],char:"\u{1f1fa}\u{1f1ff}",fitzpatrick_scale:!1,category:"flags"},vanuatu:{keywords:["vu","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1fa}",fitzpatrick_scale:!1,category:"flags"},vatican_city:{keywords:["vatican","city","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1e6}",fitzpatrick_scale:!1,category:"flags"},venezuela:{keywords:["ve","bolivarian","republic","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},vietnam:{keywords:["viet","nam","flag","nation","country","banner"],char:"\u{1f1fb}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},wallis_futuna:{keywords:["wallis","futuna","flag","nation","country","banner"],char:"\u{1f1fc}\u{1f1eb}",fitzpatrick_scale:!1,category:"flags"},western_sahara:{keywords:["western","sahara","flag","nation","country","banner"],char:"\u{1f1ea}\u{1f1ed}",fitzpatrick_scale:!1,category:"flags"},yemen:{keywords:["ye","flag","nation","country","banner"],char:"\u{1f1fe}\u{1f1ea}",fitzpatrick_scale:!1,category:"flags"},zambia:{keywords:["zm","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1f2}",fitzpatrick_scale:!1,category:"flags"},zimbabwe:{keywords:["zw","flag","nation","country","banner"],char:"\u{1f1ff}\u{1f1fc}",fitzpatrick_scale:!1,category:"flags"},united_nations:{keywords:["un","flag","banner"],char:"\u{1f1fa}\u{1f1f3}",fitzpatrick_scale:!1,category:"flags"},pirate_flag:{keywords:["skull","crossbones","flag","banner"],char:"\u{1f3f4}\u200d\u2620\ufe0f",fitzpatrick_scale:!1,category:"flags"}});
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js
new file mode 100644
index 0000000..988cd6c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/emoticons/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>t===e,o=e(null),n=e(void 0),s=()=>{},r=()=>!1;class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return null==t?a.none():a.some(t)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const i=(t,e)=>{const o=t.length,n=new Array(o);for(let s=0;s<o;s++){const o=t[s];n[s]=e(o,s)}return n},l=t=>{let e=t;return{get:()=>e,set:t=>{e=t}}},c=Object.keys,u=Object.hasOwnProperty,g=(t,e)=>{const o=c(t);for(let n=0,s=o.length;n<s;n++){const s=o[n];e(t[s],s)}},d=(t,e)=>u.call(t,e),m=(h=(t,e)=>e,(...t)=>{if(0===t.length)throw new Error("Can't merge zero objects");const e={};for(let o=0;o<t.length;o++){const n=t[o];for(const t in n)d(n,t)&&(e[t]=h(e[t],n[t]))}return e});var h;const p=()=>{const t=(t=>{const e=l(a.none()),o=()=>e.get().each(t);return{clear:()=>{o(),e.set(a.none())},isSet:()=>e.get().isSome(),get:()=>e.get(),set:t=>{o(),e.set(a.some(t))}}})(s);return{...t,on:e=>t.get().each(e)}},y=(t,e,o=0,s)=>{const r=t.indexOf(e,o);return-1!==r&&(!!n(s)||r+e.length<=s)};var v=tinymce.util.Tools.resolve("tinymce.Resource");const f=t=>e=>e.options.get(t),b=f("emoticons_database"),w=f("emoticons_database_url"),j=f("emoticons_database_id"),C=f("emoticons_append"),_=f("emoticons_images_url"),A="All",k={symbols:"Symbols",people:"People",animals_and_nature:"Animals and Nature",food_and_drink:"Food and Drink",activity:"Activity",travel_and_places:"Travel and Places",objects:"Objects",flags:"Flags",user:"User Defined"},O=(t,e)=>d(t,e)?t[e]:e,x=t=>{const e=C(t);return o=t=>({keywords:[],category:"user",...t}),((t,e)=>{const o={};return g(t,((t,n)=>{const s=e(t,n);o[s.k]=s.v})),o})(e,((t,e)=>({k:e,v:o(t)})));var o},E=(t,e)=>y(t.title.toLowerCase(),e)||((t,o)=>{for(let o=0,s=t.length;o<s;o++)if(n=t[o],y(n.toLowerCase(),e))return!0;var n;return!1})(t.keywords),L=(t,e,o)=>{const n=[],s=e.toLowerCase(),a=o.fold((()=>r),(t=>e=>e>=t));for(let o=0;o<t.length&&(0!==e.length&&!E(t[o],s)||(n.push({value:t[o].char,text:t[o].title,icon:t[o].char}),!a(n.length)));o++);return n},S="pattern",N=(t,e)=>{const n={pattern:"",results:L(e.listAll(),"",a.some(300))},s=l(A),r=((t,e)=>{let n=null;const s=()=>{o(n)||(clearTimeout(n),n=null)};return{cancel:s,throttle:(...e)=>{s(),n=setTimeout((()=>{n=null,t.apply(null,e)}),200)}}})((t=>{(t=>{const o=t.getData(),n=s.get(),r=e.listCategory(n),i=L(r,o[S],n===A?a.some(300):a.none());t.setData({results:i})})(t)})),c={label:"Search",type:"input",name:S},u={type:"collection",name:"results"},g=()=>({title:"Emojis",size:"normal",body:{type:"tabpanel",tabs:i(e.listCategories(),(t=>({title:t,name:t,items:[c,u]})))},initialData:n,onTabChange:(t,e)=>{s.set(e.newTabName),r.throttle(t)},onChange:r.throttle,onAction:(e,o)=>{"results"===o.name&&(((t,e)=>{t.insertContent(e)})(t,o.value),e.close())},buttons:[{type:"cancel",text:"Close",primary:!0}]}),d=t.windowManager.open(g());d.focus(S),e.hasLoaded()||(d.block("Loading emojis..."),e.waitForLoad().then((()=>{d.redial(g()),r.throttle(d),d.focus(S),d.unblock()})).catch((t=>{d.redial({title:"Emojis",body:{type:"panel",items:[{type:"alertbanner",level:"error",icon:"warning",text:"Could not load emojis"}]},buttons:[{type:"cancel",text:"Close",primary:!0}],initialData:{pattern:"",results:[]}}),d.focus(S),d.unblock()})))},T=t=>e=>{const o=()=>{e.setEnabled(t.selection.isEditable())};return t.on("NodeChange",o),o(),()=>{t.off("NodeChange",o)}};t.add("emoticons",((t,e)=>{((t,e)=>{const o=t.options.register;o("emoticons_database",{processor:"string",default:"emojis"}),o("emoticons_database_url",{processor:"string",default:`${e}/js/${b(t)}${t.suffix}.js`}),o("emoticons_database_id",{processor:"string",default:"tinymce.plugins.emoticons"}),o("emoticons_append",{processor:"object",default:{}}),o("emoticons_images_url",{processor:"string",default:"https://cdnjs.cloudflare.com/ajax/libs/twemoji/15.1.0/72x72/"})})(t,e);const o=((t,e,o)=>{const n=p(),s=p(),r=_(t),i=t=>{return o="<img",(e=t.char).length>=4&&e.substr(0,4)===o?t.char.replace(/src="([^"]+)"/,((t,e)=>`src="${r}${e}"`)):t.char;var e,o};t.on("init",(()=>{v.load(o,e).then((e=>{const o=x(t);(t=>{const e={},o=[];g(t,((t,n)=>{const s={title:n,keywords:t.keywords,char:i(t),category:O(k,t.category)},r=void 0!==e[s.category]?e[s.category]:[];e[s.category]=r.concat([s]),o.push(s)})),n.set(e),s.set(o)})(m(e,o))}),(t=>{console.log(`Failed to load emojis: ${t}`),n.set({}),s.set([])}))}));const l=()=>s.get().getOr([]),u=()=>n.isSet()&&s.isSet();return{listCategories:()=>[A].concat(c(n.get().getOr({}))),hasLoaded:u,waitForLoad:()=>u()?Promise.resolve(!0):new Promise(((t,o)=>{let n=15;const s=setInterval((()=>{u()?(clearInterval(s),t(!0)):(n--,n<0&&(console.log("Could not load emojis from url: "+e),clearInterval(s),o(!1)))}),100)})),listAll:l,listCategory:t=>t===A?l():n.get().bind((e=>a.from(e[t]))).getOr([])}})(t,w(t),j(t));return((t,e)=>{t.addCommand("mceEmoticons",(()=>N(t,e)))})(t,o),(t=>{const e=()=>t.execCommand("mceEmoticons");t.ui.registry.addButton("emoticons",{tooltip:"Emojis",icon:"emoji",onAction:e,onSetup:T(t)}),t.ui.registry.addMenuItem("emoticons",{text:"Emojis...",icon:"emoji",onAction:e,onSetup:T(t)})})(t),((t,e)=>{t.ui.registry.addAutocompleter("emoticons",{trigger:":",columns:"auto",minChars:2,fetch:(t,o)=>e.waitForLoad().then((()=>{const n=e.listAll();return L(n,t,a.some(o))})),onAction:(e,o,n)=>{t.selection.setRng(o),t.insertContent(n),e.hide()}})})(t,o),(t=>{t.on("PreInit",(()=>{t.parser.addAttributeFilter("data-emoticon",(t=>{((t,e)=>{for(let e=0,n=t.length;e<n;e++)(o=t[e]).attr("data-mce-resize","false"),o.attr("data-mce-placeholder","1");var o})(t)}))}))})(t),{getAllEmojis:()=>o.waitForLoad().then((()=>o.listAll()))}}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js
new file mode 100644
index 0000000..18a522c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/fullscreen/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";const e=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}};var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,r=e=>t=>typeof t===e,o=e=>t=>e===t,s=n("string"),i=n("object"),l=n("array"),a=o(null),c=r("boolean"),u=o(void 0),d=e=>!(e=>null==e)(e),m=r("function"),h=r("number"),g=()=>{},p=e=>()=>e;function f(e,...t){return(...n)=>{const r=t.concat(n);return e.apply(null,r)}}const v=p(!1),w=p(!0);class y{constructor(e,t){this.tag=e,this.value=t}static some(e){return new y(!0,e)}static none(){return y.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?y.some(e(this.value)):y.none()}bind(e){return this.tag?e(this.value):y.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:y.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?y.some(e):y.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}y.singletonNone=new y(!1);const b=Array.prototype.push,S=(e,t)=>{const n=e.length,r=new Array(n);for(let o=0;o<n;o++){const n=e[o];r[o]=t(n,o)}return r},x=(e,t)=>{for(let n=0,r=e.length;n<r;n++)t(e[n],n)},E=(e,t)=>{const n=[];for(let r=0,o=e.length;r<o;r++){const o=e[r];t(o,r)&&n.push(o)}return n},F=(e,t)=>((e,t,n)=>{for(let r=0,o=e.length;r<o;r++){const o=e[r];if(t(o,r))return y.some(o);if(n(o,r))break}return y.none()})(e,t,v),O=t=>{const n=e(y.none()),r=()=>n.get().each(t);return{clear:()=>{r(),n.set(y.none())},isSet:()=>n.get().isSome(),get:()=>n.get(),set:e=>{r(),n.set(y.some(e))}}},k=()=>O((e=>e.unbind())),T=Object.keys,C="undefined"!=typeof window?window:Function("return this;")(),A=(e,t)=>((e,t)=>{let n=null!=t?t:C;for(let t=0;t<e.length&&null!=n;++t)n=n[e[t]];return n})(e.split("."),t),R=Object.getPrototypeOf,L=e=>{const t=A("ownerDocument.defaultView",e);return i(e)&&((e=>((e,t)=>{const n=((e,t)=>A(e,t))(e,t);if(null==n)throw new Error(e+" not available on this browser");return n})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(R(e).constructor.name))},M=e=>t=>(e=>e.dom.nodeType)(t)===e,P=M(1),D=M(3),N=M(9),H=M(11),V=(e,t)=>{const n=e.dom.getAttribute(t);return null===n?void 0:n},W=(e,t)=>{e.dom.removeAttribute(t)},q=(e,t,n=0,r)=>{const o=e.indexOf(t,n);return-1!==o&&(!!u(r)||o+t.length<=r)},B=e=>void 0!==e.style&&m(e.style.getPropertyValue),I=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},j=I,_=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},z=e=>j(e.dom.ownerDocument),K=e=>S(e.dom.childNodes,j),$=m(Element.prototype.attachShadow)&&m(Node.prototype.getRootNode),U=p($),X=$?e=>j(e.dom.getRootNode()):e=>N(e)?e:z(e),Y=e=>{const t=X(e);return H(n=t)&&d(n.dom.host)?y.some(t):y.none();var n},G=e=>j(e.dom.host),J=e=>{const t=D(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return Y(j(t)).fold((()=>n.body.contains(t)),(r=J,o=G,e=>r(o(e))));var r,o},Q=(e,t,n)=>{if(!s(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);B(e)&&e.style.setProperty(t,n)},Z=(e,t,n)=>{const r=e.dom;Q(r,t,n)},ee=(e,t)=>{const n=e.dom;((e,t)=>{const n=T(e);for(let r=0,o=n.length;r<o;r++){const o=n[r];t(e[o],o)}})(t,((e,t)=>{Q(n,t,e)}))},te=(e,t)=>{const n=e.dom,r=window.getComputedStyle(n).getPropertyValue(t);return""!==r||J(e)?r:ne(n,t)},ne=(e,t)=>B(e)?e.style.getPropertyValue(t):"",re=e=>{const t=j((e=>{if(U()&&d(e.target)){const t=j(e.target);if(P(t)&&d(t.dom.shadowRoot)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return((e,t)=>0<e.length?y.some(e[0]):y.none())(t)}}return y.from(e.target)})(e).getOr(e.target)),n=()=>e.stopPropagation(),r=()=>e.preventDefault(),o=(s=r,i=n,(...e)=>s(i.apply(null,e)));var s,i;return((e,t,n,r,o,s,i)=>({target:e,x:t,y:n,stop:r,prevent:o,kill:s,raw:i}))(t,e.clientX,e.clientY,n,r,o,e)},oe=(e,t,n,r)=>{e.dom.removeEventListener(t,n,r)},se=w,ie=(e,t,n)=>((e,t,n,r)=>((e,t,n,r,o)=>{const s=((e,t)=>n=>{e(n)&&t(re(n))})(n,r);return e.dom.addEventListener(t,s,o),{unbind:f(oe,e,t,s,o)}})(e,t,n,r,!1))(e,t,se,n),le=()=>ae(0,0),ae=(e,t)=>({major:e,minor:t}),ce={nu:ae,detect:(e,t)=>{const n=String(t).toLowerCase();return 0===e.length?le():((e,t)=>{const n=((e,t)=>{for(let n=0;n<e.length;n++){const r=e[n];if(r.test(t))return r}})(e,t);if(!n)return{major:0,minor:0};const r=e=>Number(t.replace(n,"$"+e));return ae(r(1),r(2))})(e,n)},unknown:le},ue=(e,t)=>{const n=String(t).toLowerCase();return F(e,(e=>e.search(n)))},de=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,me=e=>t=>q(t,e),he=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>q(e,"edge/")&&q(e,"chrome")&&q(e,"safari")&&q(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,de],search:e=>q(e,"chrome")&&!q(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>q(e,"msie")||q(e,"trident")},{name:"Opera",versionRegexes:[de,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:me("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:me("firefox")},{name:"Safari",versionRegexes:[de,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(q(e,"safari")||q(e,"mobile/"))&&q(e,"applewebkit")}],ge=[{name:"Windows",search:me("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>q(e,"iphone")||q(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:me("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:me("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:me("linux"),versionRegexes:[]},{name:"Solaris",search:me("sunos"),versionRegexes:[]},{name:"FreeBSD",search:me("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:me("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],pe={browsers:p(he),oses:p(ge)},fe="Edge",ve="Chromium",we="Opera",ye="Firefox",be="Safari",Se=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isEdge:r(fe),isChromium:r(ve),isIE:r("IE"),isOpera:r(we),isFirefox:r(ye),isSafari:r(be)}},xe=()=>Se({current:void 0,version:ce.unknown()}),Ee=Se,Fe=(p(fe),p(ve),p("IE"),p(we),p(ye),p(be),"Windows"),Oe="Android",ke="Linux",Te="macOS",Ce="Solaris",Ae="FreeBSD",Re="ChromeOS",Le=e=>{const t=e.current,n=e.version,r=e=>()=>t===e;return{current:t,version:n,isWindows:r(Fe),isiOS:r("iOS"),isAndroid:r(Oe),isMacOS:r(Te),isLinux:r(ke),isSolaris:r(Ce),isFreeBSD:r(Ae),isChromeOS:r(Re)}},Me=()=>Le({current:void 0,version:ce.unknown()}),Pe=Le,De=(p(Fe),p("iOS"),p(Oe),p(ke),p(Te),p(Ce),p(Ae),p(Re),(e,t,n)=>{const r=pe.browsers(),o=pe.oses(),s=t.bind((e=>((e,t)=>((e,t)=>{for(let n=0;n<e.length;n++){const r=t(e[n]);if(r.isSome())return r}return y.none()})(t.brands,(t=>{const n=t.brand.toLowerCase();return F(e,(e=>{var t;return n===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:ce.nu(parseInt(t.version,10),0)})))})))(r,e))).orThunk((()=>((e,t)=>ue(e,t).map((e=>{const n=ce.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(r,e))).fold(xe,Ee),i=((e,t)=>ue(e,t).map((e=>{const n=ce.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(o,e).fold(Me,Pe),l=((e,t,n,r)=>{const o=e.isiOS()&&!0===/ipad/i.test(n),s=e.isiOS()&&!o,i=e.isiOS()||e.isAndroid(),l=i||r("(pointer:coarse)"),a=o||!s&&i&&r("(min-device-width:768px)"),c=s||i&&!a,u=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(n),d=!c&&!a&&!u;return{isiPad:p(o),isiPhone:p(s),isTablet:p(a),isPhone:p(c),isTouch:p(l),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:p(u),isDesktop:p(d)}})(i,s,e,n);return{browser:s,os:i,deviceType:l}}),Ne=e=>window.matchMedia(e).matches;let He=(e=>{let t,n=!1;return(...r)=>(n||(n=!0,t=e.apply(null,r)),t)})((()=>De(navigator.userAgent,y.from(navigator.userAgentData),Ne)));const Ve=(e,t)=>({left:e,top:t,translate:(n,r)=>Ve(e+n,t+r)}),We=Ve,qe=e=>{const t=void 0===e?window:e;return He().browser.isFirefox()?y.none():y.from(t.visualViewport)},Be=(e,t,n,r)=>({x:e,y:t,width:n,height:r,right:e+n,bottom:t+r}),Ie=e=>{const t=void 0===e?window:e,n=t.document,r=(e=>{const t=void 0!==e?e.dom:document,n=t.body.scrollLeft||t.documentElement.scrollLeft,r=t.body.scrollTop||t.documentElement.scrollTop;return We(n,r)})(j(n));return qe(t).fold((()=>{const e=t.document.documentElement,n=e.clientWidth,o=e.clientHeight;return Be(r.left,r.top,n,o)}),(e=>Be(Math.max(e.pageLeft,r.left),Math.max(e.pageTop,r.top),e.width,e.height)))},je=(e,t,n)=>qe(n).map((n=>{const r=e=>t(re(e));return n.addEventListener(e,r),{unbind:()=>n.removeEventListener(e,r)}})).getOrThunk((()=>({unbind:g})));var _e=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),ze=tinymce.util.Tools.resolve("tinymce.Env");const Ke=(e,t)=>{e.dispatch("FullscreenStateChanged",{state:t}),e.dispatch("ResizeEditor")},$e=("fullscreen_native",e=>e.options.get("fullscreen_native"));const Ue=e=>{return e.dom===(void 0!==(t=z(e).dom).fullscreenElement?t.fullscreenElement:void 0!==t.msFullscreenElement?t.msFullscreenElement:void 0!==t.webkitFullscreenElement?t.webkitFullscreenElement:null);var t},Xe=(e,t,n)=>((e,t,n)=>E(((e,t)=>{const n=m(t)?t:v;let r=e.dom;const o=[];for(;null!==r.parentNode&&void 0!==r.parentNode;){const e=r.parentNode,t=j(e);if(o.push(t),!0===n(t))break;r=e}return o})(e,n),t))(e,(e=>_(e,t)),n),Ye=(e,t)=>((e,n)=>{return E((e=>y.from(e.dom.parentNode).map(j))(r=e).map(K).map((e=>E(e,(e=>{return t=e,!(r.dom===t.dom);var t})))).getOr([]),(e=>_(e,t)));var r})(e),Ge="data-ephox-mobile-fullscreen-style",Je="position:absolute!important;",Qe="top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;",Ze=ze.os.isAndroid(),et=(e,t,n)=>{const r=t=>n=>{const r=V(n,"style"),o=void 0===r?"no-styles":r.trim();o!==t&&(((e,t,n)=>{((e,t,n)=>{if(!(s(n)||c(n)||h(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(e.dom,t,n)})(n,Ge,o),ee(n,e.parseStyle(t)))},o=Xe(t,"*"),i=(e=>{const t=[];for(let n=0,r=e.length;n<r;++n){if(!l(e[n]))throw new Error("Arr.flatten item "+n+" was not an array, input: "+e);b.apply(t,e[n])}return t})(S(o,(e=>Ye(e,"*:not(.tox-silver-sink)")))),a=(e=>{const t=te(e,"background-color");return void 0!==t&&""!==t?"background-color:"+t+"!important":"background-color:rgb(255,255,255)!important;"})(n);x(i,r("display:none!important;")),x(o,r(Je+Qe+a)),r((!0===Ze?"":Je)+Qe+a)(t)},tt=_e.DOM,nt=qe().fold((()=>({bind:g,unbind:g})),(e=>{const t=(()=>{const e=O(g);return{...e,on:t=>e.get().each(t)}})(),n=k(),r=k(),o=((e,t)=>{let n=null;return{cancel:()=>{a(n)||(clearTimeout(n),n=null)},throttle:(...t)=>{a(n)&&(n=setTimeout((()=>{n=null,e.apply(null,t)}),50))}}})((()=>{document.body.scrollTop=0,document.documentElement.scrollTop=0,window.requestAnimationFrame((()=>{t.on((t=>ee(t,{top:e.offsetTop+"px",left:e.offsetLeft+"px",height:e.height+"px",width:e.width+"px"})))}))}));return{bind:e=>{t.set(e),o.throttle(),n.set(je("resize",o.throttle)),r.set(je("scroll",o.throttle))},unbind:()=>{t.on((()=>{n.clear(),r.clear()})),t.clear()}}})),rt=(e,t)=>{const n=document.body,r=document.documentElement,o=e.getContainer(),s=j(o),i=(l=s,y.from(l.dom.nextSibling).map(j)).filter((e=>(e=>P(e)&&L(e.dom))(e)&&((e,t)=>(e=>void 0!==e.dom.classList)(e)&&e.dom.classList.contains("tox-silver-sink"))(e)));var l;const a=(e=>{const t=j(e.getElement());return Y(t).map(G).getOrThunk((()=>(e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return j(t)})(z(t))))})(e),c=t.get(),u=j(e.getBody()),d=ze.deviceType.isTouch(),m=o.style,h=e.iframeElement,g=null==h?void 0:h.style,p=e=>{e(n,"tox-fullscreen"),e(r,"tox-fullscreen"),e(o,"tox-fullscreen"),Y(s).map((e=>G(e).dom)).each((t=>{e(t,"tox-fullscreen"),e(t,"tox-shadowhost")}))},f=()=>{d&&(e=>{const t=((e,t)=>{const n=document;return 1!==(r=n).nodeType&&9!==r.nodeType&&11!==r.nodeType||0===r.childElementCount?[]:S(n.querySelectorAll(e),j);var r})("["+Ge+"]");x(t,(t=>{const n=V(t,Ge);n&&"no-styles"!==n?ee(t,e.parseStyle(n)):W(t,"style"),W(t,Ge)}))})(e.dom),p(tt.removeClass),nt.unbind(),y.from(t.get()).each((e=>e.fullscreenChangeHandler.unbind()))};if(c)c.fullscreenChangeHandler.unbind(),$e(e)&&Ue(a)&&(e=>{const t=e.dom;t.exitFullscreen?t.exitFullscreen():t.msExitFullscreen?t.msExitFullscreen():t.webkitCancelFullScreen&&t.webkitCancelFullScreen()})(z(a)),g.width=c.iframeWidth,g.height=c.iframeHeight,m.width=c.containerWidth,m.height=c.containerHeight,m.top=c.containerTop,m.left=c.containerLeft,w=i,b=c.sinkCssPosition,E=(e,t)=>{Z(e,"position",t)},w.isSome()&&b.isSome()?y.some(E(w.getOrDie(),b.getOrDie())):y.none(),f(),v=c.scrollPos,window.scrollTo(v.x,v.y),t.set(null),Ke(e,!1),e.off("remove",f);else{const n=ie(z(a),void 0!==document.fullscreenElement?"fullscreenchange":void 0!==document.msFullscreenElement?"MSFullscreenChange":void 0!==document.webkitFullscreenElement?"webkitfullscreenchange":"fullscreenchange",(n=>{$e(e)&&(Ue(a)||null===t.get()||rt(e,t))})),r={scrollPos:Ie(window),containerWidth:m.width,containerHeight:m.height,containerTop:m.top,containerLeft:m.left,iframeWidth:g.width,iframeHeight:g.height,fullscreenChangeHandler:n,sinkCssPosition:i.map((e=>te(e,"position")))};d&&et(e.dom,s,u),g.width=g.height="100%",m.width=m.height="",p(tt.addClass),i.each((e=>{Z(e,"position","fixed")})),nt.bind(s),e.on("remove",f),t.set(r),$e(e)&&(e=>{const t=e.dom;t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullScreen&&t.webkitRequestFullScreen()})(a),Ke(e,!0)}var v,w,b,E};var ot=tinymce.util.Tools.resolve("tinymce.util.VK");const st=(e,t)=>n=>{n.setActive(null!==t.get());const r=e=>n.setActive(e.state);return e.on("FullscreenStateChanged",r),()=>e.off("FullscreenStateChanged",r)};t.add("fullscreen",(t=>{const n=e(null);return t.inline||((e=>{(0,e.options.register)("fullscreen_native",{processor:"boolean",default:!1})})(t),((e,t)=>{e.addCommand("mceFullScreen",(()=>{rt(e,t)}))})(t,n),((e,t)=>{const n=()=>e.execCommand("mceFullScreen");e.ui.registry.addToggleMenuItem("fullscreen",{text:"Fullscreen",icon:"fullscreen",shortcut:"Meta+Shift+F",onAction:n,onSetup:st(e,t)}),e.ui.registry.addToggleButton("fullscreen",{tooltip:"Fullscreen",icon:"fullscreen",onAction:n,onSetup:st(e,t),shortcut:"Meta+Shift+F"})})(t,n),((e,t)=>{e.on("init",(()=>{e.on("keydown",(e=>{e.keyCode!==ot.TAB||e.metaKey||e.ctrlKey||!t.get()||e.preventDefault()}))}))})(t,n),t.addShortcut("Meta+Shift+F","","mceFullScreen")),(e=>({isFullscreen:()=>null!==e.get()}))(n)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js
new file mode 100644
index 0000000..e2cf02f
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ar.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ar',
+'<h1>亘丿亍 丕賱鬲賳賯賱 亘賵丕爻胤丞 賱賵丨丞 丕賱賲賮丕鬲賷丨</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>丕賱鬲乇賰賷夭 毓賱賶 卮乇賷胤 丕賱賯賵丕卅賲</dt>\n' +
+  '  <dd>賳馗丕賲丕 丕賱鬲卮睾賷賱 Windows 兀賵 Linux: Alt + F9</dd>\n' +
+  '  <dd>賳馗丕賲 丕賱鬲卮睾賷賱 macOS: &#x2325;F9</dd>\n' +
+  '  <dt>丕賱鬲乇賰賷夭 毓賱賶 卮乇賷胤 丕賱兀丿賵丕鬲</dt>\n' +
+  '  <dd>賳馗丕賲丕 丕賱鬲卮睾賷賱 Windows 兀賵 Linux: Alt + F10</dd>\n' +
+  '  <dd>賳馗丕賲 丕賱鬲卮睾賷賱 macOS: &#x2325;F10</dd>\n' +
+  '  <dt>丕賱鬲乇賰賷夭 毓賱賶 丕賱鬲匕賷賷賱</dt>\n' +
+  '  <dd>賳馗丕賲丕 丕賱鬲卮睾賷賱 Windows 兀賵 Linux: Alt + F11</dd>\n' +
+  '  <dd>賳馗丕賲 丕賱鬲卮睾賷賱 macOS: &#x2325;F11</dd>\n' +
+  '  <dt>鬲乇賰賷夭 丕賱廿卮毓丕乇丕鬲</dt>\n' +
+  '  <dd>賳馗丕賲丕 丕賱鬲卮睾賷賱 Windows 兀賵 Linux: Alt + F12</dd>\n' +
+  '  <dd>賳馗丕賲 丕賱鬲卮睾賷賱 macOS: &#x2325;F12</dd>\n' +
+  '  <dt>丕賱鬲乇賰賷夭 毓賱賶 卮乇賷胤 兀丿賵丕鬲 丕賱爻賷丕賯</dt>\n' +
+  '  <dd>兀賳馗賲丞 丕賱鬲卮睾賷賱 Windows 兀賵 Linux 兀賵 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>爻賷亘丿兀 丕賱鬲賳賯賱 毓賳丿 毓賳氐乇 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 丕賱兀賵賱貙 賵丕賱匕賷 爻賷鬲賲 鬲賲賷賷夭賴 兀賵 鬲爻胤賷乇賴 賮賷 丨丕賱丞 丕賱毓賳氐乇 丕賱兀賵賱 賮賷\n' +
+  '  賲爻丕乇 毓賳氐乇 丕賱鬲匕賷賷賱.</p>\n' +
+  '\n' +
+  '<h1>丕賱鬲賳賯賱 亘賷賳 兀賯爻丕賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲</h1>\n' +
+  '\n' +
+  '<p>賱賱丕賳鬲賯丕賱 賲賳 兀丨丿 兀賯爻丕賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 廿賱賶 丕賱賯爻賲 丕賱鬲丕賱賷貙 丕囟睾胤 毓賱賶 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>賱賱丕賳鬲賯丕賱 賲賳 兀丨丿 兀賯爻丕賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 廿賱賶 丕賱賯爻賲 丕賱爻丕亘賯貙 丕囟睾胤 毓賱賶 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>鬲乇鬲賷亘 毓賱丕賲丕鬲 <strong>Tab</strong> 賱兀賯爻丕賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 賴匕賴 賴賵:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>卮乇賷胤 丕賱賯賵丕卅賲</li>\n' +
+  '  <li>賰賱 賲噩賲賵毓丞 卮乇賷胤 丕賱兀丿賵丕鬲</li>\n' +
+  '  <li>丕賱卮乇賷胤 丕賱噩丕賳亘賷</li>\n' +
+  '  <li>賲爻丕乇 丕賱毓賳氐乇 賮賷 丕賱鬲匕賷賷賱</li>\n' +
+  '  <li>夭乇 鬲亘丿賷賱 毓丿丿 丕賱賰賱賲丕鬲 賮賷 丕賱鬲匕賷賷賱</li>\n' +
+  '  <li>乇丕亘胤 廿丿乇丕噩 丕賱毓賱丕賲丞 丕賱鬲噩丕乇賷丞 賮賷 丕賱鬲匕賷賷賱</li>\n' +
+  '  <li>賲丐卮乇 鬲睾賷賷乇 丨噩賲 丕賱賲丨乇乇 賮賷 丕賱鬲匕賷賷賱</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>廿匕丕 賱賲 賷賰賳 賯爻賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 賲賵噩賵丿賸丕貙 賮爻賷鬲賲 鬲禺胤賷賴.</p>\n' +
+  '\n' +
+  '<p>廿匕丕 賰丕賳 丕賱鬲匕賷賷賱 賷丨鬲賵賷 毓賱賶 丕賱鬲乇賰賷夭 毓賱賶 鈥忊�з勜嗁傎� 亘賵丕爻胤丞 賱賵丨丞 丕賱賲賮丕鬲賷丨貙 賵賱丕 賷賵噩丿 卮乇賷胤 噩丕賳亘賷 賲乇卅賷貙 賮廿賳 丕賱囟睾胤 毓賱賶 <strong>Shift+Tab</strong>\n' +
+  '  賷賳賯賱 丕賱鬲乇賰賷夭 廿賱賶 賲噩賲賵毓丞 卮乇賷胤 丕賱兀丿賵丕鬲 丕賱兀賵賱賶貙 賵賱賷爻 丕賱兀禺賷乇丞.</p>\n' +
+  '\n' +
+  '<h1>丕賱鬲賳賯賱 亘賷賳 兀賯爻丕賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲</h1>\n' +
+  '\n' +
+  '<p>賱賱丕賳鬲賯丕賱 賲賳 兀丨丿 毓賳丕氐乇 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 廿賱賶 丕賱毓賳氐乇 丕賱鬲丕賱賷貙 丕囟睾胤 毓賱賶 賲賮鬲丕丨 <strong>丕賱爻賴賲</strong> 丕賱賲賳丕爻亘.</p>\n' +
+  '\n' +
+  '<p>賲賮鬲丕丨丕 丕賱爻賴賲賷賳 <strong>丕賱賷爻丕乇鈥�</strong> 賵<strong>丕賱賷賲賷賳鈥�</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>丕賱鬲賳賯賱 亘賷賳 丕賱賯賵丕卅賲 賮賷 卮乇賷胤 丕賱賯賵丕卅賲.</li>\n' +
+  '  <li>賮鬲丨 賯丕卅賲丞 賮乇毓賷丞 賮賷 丕賱賯丕卅賲丞.</li>\n' +
+  '  <li>丕賱鬲賳賯賱 亘賷賳 丕賱兀夭乇丕乇 賮賷 賲噩賲賵毓丞 卮乇賷胤 丕賱兀丿賵丕鬲.</li>\n' +
+  '  <li>丕賱鬲賳賯賱 亘賷賳 丕賱毓賳丕氐乇 賮賷 賲爻丕乇 毓賳氐乇 丕賱鬲匕賷賷賱.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>賲賮鬲丕丨丕 丕賱爻賴賲賷賳 <strong>賱兀爻賮賱鈥�</strong> 賵<strong>賱兀毓賱賶鈥�</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>丕賱鬲賳賯賱 亘賷賳 毓賳丕氐乇 丕賱賯丕卅賲丞 賮賷 丕賱賯丕卅賲丞.</li>\n' +
+  '  <li>丕賱鬲賳賯賱 亘賷賳 丕賱毓賳丕氐乇 賮賷 賯丕卅賲丞 卮乇賷胤 丕賱兀丿賵丕鬲 丕賱賲賳亘孬賯丞.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>丿賵乇丞 賲賮丕鬲賷丨 <strong>丕賱兀爻賴賲鈥�</strong> 丿丕禺賱 賯爻賲 賵丕噩賴丞 丕賱賲爻鬲禺丿賲 丕賱鬲賷 鬲賲 丕賱鬲乇賰賷夭 毓賱賷賴丕.</p>\n' +
+  '\n' +
+  '<p>賱廿睾賱丕賯 賯丕卅賲丞 賲賮鬲賵丨丞 兀賵 賯丕卅賲丞 賮乇毓賷丞 賲賮鬲賵丨丞 兀賵 賯丕卅賲丞 賲賳亘孬賯丞 賲賮鬲賵丨丞貙 丕囟睾胤 毓賱賶 賲賮鬲丕丨 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>廿匕丕 賰丕賳 丕賱鬲乇賰賷夭 丕賱丨丕賱賷 毓賱賶 "丕賱噩夭亍 丕賱毓賱賵賷" 賲賳 賯爻賲 賲毓賷賳 賱賵丕噩賴丞 丕賱賲爻鬲禺丿賲貙 賮廿賳 丕賱囟睾胤 毓賱賶 賲賮鬲丕丨 <strong>Esc</strong> 賷丐丿賷 兀賷囟賸丕 廿賱賶 丕賱禺乇賵噩\n' +
+  '  賲賳 丕賱鬲賳賯賱 亘賵丕爻胤丞 賱賵丨丞 丕賱賲賮丕鬲賷丨 亘丕賱賰丕賲賱.</p>\n' +
+  '\n' +
+  '<h1>鬲賳賮賷匕 毓賳氐乇 賯丕卅賲丞 兀賵 夭乇 卮乇賷胤 兀丿賵丕鬲</h1>\n' +
+  '\n' +
+  '<p>毓賳丿賲丕 賷鬲賲 鬲賲賷賷夭 毓賳氐乇 丕賱賯丕卅賲丞 丕賱賲胤賱賵亘 兀賵 夭乇 卮乇賷胤 丕賱兀丿賵丕鬲貙 丕囟睾胤 毓賱賶 夭乇 <strong>Return</strong>貙 兀賵 <strong>Enter</strong>貙\n' +
+  '  兀賵 <strong>賲賮鬲丕丨 丕賱賲爻丕賮丞</strong> 賱鬲賳賮賷匕 丕賱毓賳氐乇.</p>\n' +
+  '\n' +
+  '<h1>丕賱鬲賳賯賱 賮賷 賲乇亘毓丕鬲 丕賱丨賵丕乇 睾賷乇 丕賱賲亘賵亘丞</h1>\n' +
+  '\n' +
+  '<p>賮賷 賲乇亘毓丕鬲 丕賱丨賵丕乇 睾賷乇 丕賱賲亘賵亘丞貙 賷鬲賲 丕賱鬲乇賰賷夭 毓賱賶 丕賱賲賰賵賳 丕賱鬲賮丕毓賱賷 丕賱兀賵賱 毓賳丿 賮鬲丨 賲乇亘毓 丕賱丨賵丕乇.</p>\n' +
+  '\n' +
+  '<p>丕賱鬲賳賯賱 亘賷賳 賲賰賵賳丕鬲 丕賱丨賵丕乇 丕賱鬲賮丕毓賱賷 亘丕賱囟睾胤 毓賱賶 夭乇 <strong>Tab</strong> 兀賵 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>丕賱鬲賳賯賱 賮賷 賲乇亘毓丕鬲 丕賱丨賵丕乇 丕賱賲亘賵亘丞</h1>\n' +
+  '\n' +
+  '<p>賮賷 賲乇亘毓丕鬲 丕賱丨賵丕乇 丕賱賲亘賵亘丞貙 賷鬲賲 丕賱鬲乇賰賷夭 毓賱賶 丕賱夭乇 丕賱兀賵賱 賮賷 賯丕卅賲丞 毓賱丕賲丕鬲 丕賱鬲亘賵賷亘 毓賳丿 賮鬲丨 賲乇亘毓 丕賱丨賵丕乇.</p>\n' +
+  '\n' +
+  '<p>丕賱鬲賳賯賱 亘賷賳 丕賱賲賰賵賳丕鬲 丕賱鬲賮丕毓賱賷丞 賱毓賱丕賲丞 丕賱鬲亘賵賷亘 賱賲乇亘毓 丕賱丨賵丕乇 賴匕賴 亘丕賱囟睾胤 毓賱賶 夭乇 <strong>Tab</strong> 兀賵\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>丕賱鬲亘丿賷賱 廿賱賶 毓賱丕賲丞 鬲亘賵賷亘 兀禺乇賶 賱賲乇亘毓 丕賱丨賵丕乇 賲賳 禺賱丕賱 丕賱鬲乇賰賷夭 毓賱賶 賯丕卅賲丞 毓賱丕賲丞 丕賱鬲亘賵賷亘 孬賲 丕賱囟睾胤 毓賱賶 夭乇 <strong>丕賱爻賴賲</strong> 丕賱賲賳丕爻亘\n' +
+  '  賲賮鬲丕丨 賱賱鬲賳賯賱 亘賷賳 毓賱丕賲丕鬲 丕賱鬲亘賵賷亘 丕賱賲鬲丕丨丞.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js
new file mode 100644
index 0000000..09eacf3
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/bg_BG.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.bg_BG',
+'<h1>袧邪褔邪谢芯 薪邪 薪邪胁懈谐邪褑懈褟褌邪 褋 泻谢邪胁懈邪褌褍褉邪褌邪</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>肖芯泻褍褋懈褉邪薪械 胁褗褉褏褍 谢械薪褌邪褌邪 褋 屑械薪褞褌邪</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>肖芯泻褍褋懈褉邪薪械 胁褗褉褏褍 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>肖芯泻褍褋懈褉邪薪械 胁褗褉褏褍 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>肖芯泻褍褋懈褉邪薪械 薪邪 懈蟹胁械褋褌懈械褌芯</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>肖芯泻褍褋懈褉邪薪械 胁褗褉褏褍 泻芯薪褌械泻褋褌褍邪谢薪邪褌邪 谢械薪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈</dt>\n' +
+  '  <dd>Windows, Linux 懈谢懈 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>袧邪胁懈谐邪褑懈褟褌邪 褖械 蟹邪锌芯褔薪械 褋 锌褗褉胁懈褟 械谢械屑械薪褌 薪邪 袩袠, 泻芯泄褌芯 褖械 斜褗写械 屑邪褉泻懈褉邪薪 懈谢懈 锌芯写褔械褉褌邪薪 胁 褋谢褍褔邪褟 薪邪 锌褗褉胁懈褟 械谢械屑械薪褌 胁\n' +
+  '  锌褗褌褟 写芯 械谢械屑械薪褌邪 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁懈谐懈褉邪薪械 屑械卸写褍 褉邪蟹写械谢懈 薪邪 袩袠</h1>\n' +
+  '\n' +
+  '<p>袟邪 写邪 锌褉械屑懈薪械褌械 芯褌 械写懈薪 褉邪蟹写械谢 薪邪 袩袠 泻褗屑 褋谢械写胁邪褖懈褟, 薪邪褌懈褋薪械褌械 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>袟邪 写邪 锌褉械屑懈薪械褌械 芯褌 械写懈薪 褉邪蟹写械谢 薪邪 袩袠 泻褗屑 锌褉械写懈褕薪懈褟, 薪邪褌懈褋薪械褌械 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>袪械写褗褌 蟹邪 <strong>芯斜褏芯卸写邪薪械 褋 褌邪斜褍谢邪褑懈褟</strong> 薪邪 褌械蟹懈 褉邪蟹写械谢懈 薪邪 袩袠 械:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>袥械薪褌邪褌邪 褋 屑械薪褞褌邪</li>\n' +
+  '  <li>袙褋褟泻邪 谐褉褍锌邪 薪邪 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈</li>\n' +
+  '  <li>小褌褉邪薪懈褔薪邪褌邪 谢械薪褌邪</li>\n' +
+  '  <li>袩褗褌褟褌 写芯 械谢械屑械薪褌邪 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢</li>\n' +
+  '  <li>袘褍褌芯薪褗褌 蟹邪 锌褉械胁泻谢褞褔胁邪薪械 薪邪 斜褉芯褟 薪邪 写褍屑懈褌械 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢</li>\n' +
+  '  <li>袙褉褗蟹泻邪褌邪 蟹邪 褌褗褉谐芯胁褋泻邪 屑邪褉泻邪 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢</li>\n' +
+  '  <li>袦邪薪懈锌褍谢邪褌芯褉褗褌 蟹邪 锌褉械芯褉邪蟹屑械褉褟胁邪薪械 薪邪 褉械写邪泻褌芯褉邪 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>袗泻芯 薪褟泻芯泄 褉邪蟹写械谢 薪邪 袩袠 谢懈锌褋胁邪, 褌芯泄 褋械 锌褉芯锌褍褋泻邪.</p>\n' +
+  '\n' +
+  '<p>袗泻芯 写芯谢薪懈褟褌 泻芯谢芯薪褌懈褌褍谢 懈屑邪 褎芯泻褍褋 蟹邪 薪邪胁懈谐邪褑懈褟 褋 泻谢邪胁懈邪褌褍褉邪褌邪 懈 薪褟屑邪 褋褌褉邪薪懈褔薪邪 谢械薪褌邪, 薪邪褌懈褋泻邪薪械褌芯 薪邪 <strong>Shift+Tab</strong>\n' +
+  '  锌褉械屑械褋褌胁邪 褎芯泻褍褋邪 泻褗屑 锌褗褉胁邪褌邪 谐褉褍锌邪 薪邪 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈, 邪 薪械 泻褗屑 锌芯褋谢械写薪邪褌邪.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁懈谐懈褉邪薪械 胁 褉邪蟹写械谢懈褌械 薪邪 袩袠</h1>\n' +
+  '\n' +
+  '<p>袟邪 写邪 锌褉械屑懈薪械褌械 芯褌 械写懈薪 械谢械屑械薪褌 薪邪 袩袠 泻褗屑 褋谢械写胁邪褖懈褟, 薪邪褌懈褋薪械褌械 褋褗芯褌胁械褌薪懈褟 泻谢邪胁懈褕 褋褗褋 <strong>褋褌褉械谢泻邪</strong>.</p>\n' +
+  '\n' +
+  '<p>小 泻谢邪胁懈褕懈褌械 褋褗褋 褋褌褉械谢泻邪 <strong>薪邪谢褟胁芯</strong> 懈 <strong>薪邪写褟褋薪芯</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>褋械 锌褉懈写胁懈卸胁邪褌械 屑械卸写褍 屑械薪褞褌邪褌邪 胁 谢械薪褌邪褌邪 褋 屑械薪褞褌芯;</li>\n' +
+  '  <li>芯褌胁邪褉褟褌械 锌芯写屑械薪褞 胁 屑械薪褞;</li>\n' +
+  '  <li>褋械 锌褉懈写胁懈卸胁邪褌械 屑械卸写褍 斜褍褌芯薪懈褌械 胁 谐褉褍锌邪 薪邪 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈;</li>\n' +
+  '  <li>褋械 锌褉懈写胁懈卸胁邪褌械 屑械卸写褍 械谢械屑械薪褌懈 胁 锌褗褌褟 写芯 械谢械屑械薪褌 胁 写芯谢薪懈褟 泻芯谢芯薪褌懈褌褍谢.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>小 泻谢邪胁懈褕懈褌械 褋褗褋 褋褌褉械谢泻邪 <strong>薪邪写芯谢褍</strong> 懈 <strong>薪邪谐芯褉械</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>褋械 锌褉懈写胁懈卸胁邪褌械 屑械卸写褍 械谢械屑械薪褌懈褌械 芯褌 屑械薪褞褌芯 胁 写邪写械薪芯 屑械薪褞;</li>\n' +
+  '  <li>褋械 锌褉懈写胁懈卸胁邪褌械 屑械卸写褍 械谢械屑械薪褌懈褌械 胁 懈蟹褋泻邪褔邪褖芯 屑械薪褞 薪邪 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>袣谢邪胁懈褕懈褌械 褋褗褋 <strong>褋褌褉械谢泻懈</strong> 褋械 锌褉懈写胁懈卸胁邪褌 胁 褉邪屑泻懈褌械 薪邪 褎芯泻褍褋懈褉邪薪懈褟 褉邪蟹写械谢 薪邪 袩袠.</p>\n' +
+  '\n' +
+  '<p>袟邪 写邪 蟹邪褌胁芯褉懈褌械 芯褌胁芯褉械薪芯 屑械薪褞, 锌芯写屑械薪褞 懈谢懈 懈蟹褋泻邪褔邪褖芯 屑械薪褞, 薪邪褌懈褋薪械褌械 泻谢邪胁懈褕邪 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>袗泻芯 褌械泻褍褖懈褟褌 褎芯泻褍褋 械 胁褗褉褏褍 鈥炐承狙�薪邪褌邪 褔邪褋褌鈥� 薪邪 泻芯薪泻褉械褌械薪 褉邪蟹写械谢 薪邪 袩袠, 薪邪褌懈褋泻邪薪械褌芯 薪邪 泻谢邪胁懈褕邪 <strong>Esc</strong> 褋褗褖芯 懈蟹谢懈蟹邪\n' +
+  '  薪邪锌褗谢薪芯 芯褌 薪邪胁懈谐邪褑懈褟褌邪 褋 泻谢邪胁懈邪褌褍褉邪褌邪.</p>\n' +
+  '\n' +
+  '<h1>袠蟹锌褗谢薪械薪懈械 薪邪 械谢械屑械薪褌 芯褌 屑械薪褞褌芯 懈谢懈 斜褍褌芯薪 芯褌 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈</h1>\n' +
+  '\n' +
+  '<p>袣芯谐邪褌芯 卸械谢邪薪懈褟褌 械谢械屑械薪褌 芯褌 屑械薪褞褌芯 懈谢懈 斜褍褌芯薪 芯褌 谢械薪褌邪褌邪 褋 懈薪褋褌褉褍屑械薪褌懈 械 屑邪褉泻懈褉邪薪, 薪邪褌懈褋薪械褌械 <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  懈谢懈 <strong>泻谢邪胁懈褕邪 蟹邪 懈薪褌械褉胁邪谢</strong>, 蟹邪 写邪 懈蟹锌褗谢薪懈褌械 械谢械屑械薪褌邪.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁懈谐懈褉邪薪械 胁 写懈邪谢芯谐芯胁懈 锌褉芯蟹芯褉褑懈 斜械蟹 褉邪蟹写械谢懈</h1>\n' +
+  '\n' +
+  '<p>袙 写懈邪谢芯谐芯胁懈褌械 锌褉芯蟹芯褉褑懈 斜械蟹 褉邪蟹写械谢懈 锌褗褉胁懈褟褌 懈薪褌械褉邪泻褌懈胁械薪 泻芯屑锌芯薪械薪褌 褋械 褎芯泻褍褋懈褉邪, 泻芯谐邪褌芯 褋械 芯褌胁芯褉懈 写懈邪谢芯谐芯胁懈褟褌 锌褉芯蟹芯褉械褑.</p>\n' +
+  '\n' +
+  '<p>袧邪胁懈谐懈褉邪泄褌械 屑械卸写褍 懈薪褌械褉邪泻褌懈胁薪懈褌械 泻芯屑锌芯薪械薪褌懈 薪邪 写懈邪谢芯谐芯胁懈褟 锌褉芯蟹芯褉械褑, 泻邪褌芯 薪邪褌懈褋薪械褌械 <strong>Tab</strong> 懈谢懈 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁懈谐懈褉邪薪械 胁 写懈邪谢芯谐芯胁懈 锌褉芯蟹芯褉褑懈 褋 褉邪蟹写械谢懈</h1>\n' +
+  '\n' +
+  '<p>袙 写懈邪谢芯谐芯胁懈褌械 锌褉芯蟹芯褉褑懈 褋 褉邪蟹写械谢懈 锌褗褉胁懈褟褌 斜褍褌芯薪 胁 屑械薪褞褌芯 褋 褉邪蟹写械谢懈 褋械 褎芯泻褍褋懈褉邪, 泻芯谐邪褌芯 褋械 芯褌胁芯褉懈 写懈邪谢芯谐芯胁懈褟褌 锌褉芯蟹芯褉械褑.</p>\n' +
+  '\n' +
+  '<p>袧邪胁懈谐懈褉邪泄褌械 屑械卸写褍 懈薪褌械褉邪泻褌懈胁薪懈褌械 泻芯屑锌芯薪械薪褌懈 薪邪 褌芯蟹懈 写懈邪谢芯谐芯胁 褉邪蟹写械谢, 泻邪褌芯 薪邪褌懈褋薪械褌械 <strong>Tab</strong> 懈谢懈\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>袩褉械胁泻谢褞褔械褌械 泻褗屑 写褉褍谐 写懈邪谢芯谐芯胁 褉邪蟹写械谢, 泻邪褌芯 褎芯泻褍褋懈褉邪褌械 胁褗褉褏褍 屑械薪褞褌芯 褋 褉邪蟹写械谢懈 懈 褋谢械写 褌芯胁邪 薪邪褌懈褋薪械褌械 褋褗芯褌胁械褌薪懈褟 泻谢邪胁懈褕 褋褗褋 <strong>褋褌褉械谢泻邪</strong>,\n' +
+  '  蟹邪 写邪 锌褉械屑懈薪械褌械 锌褉械蟹 薪邪谢懈褔薪懈褌械 褉邪蟹写械谢懈.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js
new file mode 100644
index 0000000..996e29c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ca.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ca',
+'<h1>Inici de la navegaci贸 amb el teclat</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Enfocar la barra de men煤s</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  "  <dt>Enfocar la barra d'eines</dt>\n" +
+  '  <dd>Windows o Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Enfocar el peu de p脿gina</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Enfocar la notificaci贸</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  "  <dt>Enfocar una barra d'eines contextual</dt>\n" +
+  '  <dd>Windows, Linux o macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  "<p>La navegaci贸 comen莽ar脿 en el primer element de la interf铆cie d'usuari, que es ressaltar脿 o subratllar脿 per al primer element a\n" +
+  "  la ruta de l'element de peu de p脿gina.</p>\n" +
+  '\n' +
+  "<h1>Navegaci贸 entre seccions de la interf铆cie d'usuari</h1>\n" +
+  '\n' +
+  "<p>Per despla莽ar-vos des d'una secci贸 de la interf铆cie d'usuari a la seg眉ent, premeu la tecla <strong>Tab</strong>.</p>\n" +
+  '\n' +
+  "<p>Per despla莽ar-vos des d'una secci贸 de la interf铆cie d'usuari a l'anterior, premeu les tecles <strong>Maj+Tab</strong>.</p>\n" +
+  '\n' +
+  "<p>L'ordre en pr茅mer la tecla <strong>Tab</strong> d'aquestes secciones de la interf铆cie d'usuari 茅s:</p>\n" +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de men煤s</li>\n' +
+  "  <li>Cada grup de la barra d'eines</li>\n" +
+  '  <li>Barra lateral</li>\n' +
+  "  <li>Ruta de l'element del peu de p脿gina</li>\n" +
+  '  <li>Bot贸 de commutaci贸 de recompte de paraules al peu de p脿gina</li>\n' +
+  '  <li>Enlla莽 de marca del peu de p脿gina</li>\n' +
+  "  <li>Control de canvi de mida de l'editor al peu de p脿gina</li>\n" +
+  '</ol>\n' +
+  '\n' +
+  "<p>Si no hi ha una secci贸 de la interf铆cie d'usuari, s'ometr脿.</p>\n" +
+  '\n' +
+  '<p>Si el peu de p脿gina t茅 el focus de navegaci贸 del teclat i no hi ha cap barra lateral visible, en pr茅mer <strong>Maj+Tab</strong>\n' +
+  "  el focus es mou al primer grup de la barra d'eines, no l'煤ltim.</p>\n" +
+  '\n' +
+  "<h1>Navegaci贸 dins de les seccions de la interf铆cie d'usuari</h1>\n" +
+  '\n' +
+  "<p>Per despla莽ar-vos des d'un element de la interf铆cie d'usuari al seg眉ent, premeu la tecla de <strong>Fletxa</strong> adequada.</p>\n" +
+  '\n' +
+  '<p>Les tecles de fletxa <strong>Esquerra</strong> i <strong>Dreta</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>us permeten despla莽ar-vos entre men煤s de la barra de men煤s.</li>\n' +
+  '  <li>obren un submen煤 en un men煤.</li>\n' +
+  "  <li>us permeten despla莽ar-vos entre botons d'un grup de la barra d'eines.</li>\n" +
+  "  <li>us permeten despla莽ar-vos entre elements de la ruta d'elements del peu de p脿gina.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  '<p>Les tecles de fletxa <strong>Avall</strong> i <strong>Amunt</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  "  <li>us permeten despla莽ar-vos entre elements de men煤 d'un men煤.</li>\n" +
+  "  <li>us permeten despla莽ar-vos entre elements d'un men煤 emergent de la barra d'eines.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  "<p>Les tecles de <strong>Fletxa</strong> us permeten despla莽ar-vos dins de la secci贸 de la interf铆cie d'usuari que t茅 el focus.</p>\n" +
+  '\n' +
+  '<p>Per tancar un men煤, un submen煤 o un men煤 emergent oberts, premeu la tecla <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  "<p>Si el focus actual es troba a la 鈥榩art superior鈥� d'una secci贸 espec铆fica de la interf铆cie d'usuari, en pr茅mer la tecla <strong>Esc</strong> tamb茅 es tanca\n" +
+  '  completament la navegaci贸 amb el teclat.</p>\n' +
+  '\n' +
+  "<h1>Execuci贸 d'un element de men煤 o d'un bot贸 de la barra d'eines</h1>\n" +
+  '\n' +
+  "<p>Quan l'element del men煤 o el bot贸 de la barra d'eines que desitgeu estigui ressaltat, premeu <strong>Retorn</strong>, <strong>Intro</strong>\n" +
+  "  o la <strong>barra d'espai</strong> per executar l'element.</p>\n" +
+  '\n' +
+  '<h1>Navegaci贸 per quadres de di脿leg sense pestanyes</h1>\n' +
+  '\n' +
+  "<p>En els quadres de di脿leg sense pestanyes, el primer component interactiu pren el focus quan s'obre el quadre di脿leg.</p>\n" +
+  '\n' +
+  '<p>Premeu la tecla <strong>Tab</strong> o les tecles <strong>Maj+Tab</strong> per despla莽ar-vos entre components interactius del quadre de di脿leg.</p>\n' +
+  '\n' +
+  '<h1>Navegaci贸 per quadres de di脿leg amb pestanyes</h1>\n' +
+  '\n' +
+  "<p>En els quadres de di脿leg amb pestanyes, el primer bot贸 del men煤 de la pestanya pren el focus quan s'obre el quadre di脿leg.</p>\n" +
+  '\n' +
+  "<p>Per despla莽ar-vos entre components interactius d'aquest quadre de di脿leg, premeu la tecla <strong>Tab</strong> o\n" +
+  '  les tecles <strong>Maj+Tab</strong>.</p>\n' +
+  '\n' +
+  "<p>Canvieu a la pestanya d'un altre quadre de di脿leg, tot enfocant el men煤 de la pestanya, i despr茅s premeu la tecla <strong>Fletxa</strong> adequada\n" +
+  '  per canviar entre les pestanyes disponibles.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js
new file mode 100644
index 0000000..4a5a902
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/cs.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.cs',
+'<h1>Za膷铆n谩me navigovat pomoc铆 kl谩vesnice</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>P艡ej铆t na 艡谩dek nab铆dek</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>P艡ej铆t na panel n谩stroj暖</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>P艡ej铆t na z谩pat铆</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>P艡ej铆t na ozn谩men铆</dt>\n' +
+  '  <dd>Windows nebo Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>P艡ej铆t na kontextov媒 panel n谩stroj暖</dt>\n' +
+  '  <dd>Windows, Linux nebo macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigace za膷ne u聽prvn铆 polo啪ky u啪ivatelsk茅ho rozhran铆, kter谩 bude zv媒razn臎na nebo v聽p艡铆pad臎 prvn铆 polo啪ky\n' +
+  '  cesty k聽prvku z谩pat铆 podtr啪ena.</p>\n' +
+  '\n' +
+  '<h1>Navigace mezi odd铆ly u啪ivatelsk茅ho rozhran铆</h1>\n' +
+  '\n' +
+  '<p>Stisknut铆m kl谩vesy <strong>Tab</strong> se posunete z聽jednoho odd铆lu u啪ivatelsk茅ho rozhran铆 na dal拧铆.</p>\n' +
+  '\n' +
+  '<p>Stisknut铆m kl谩ves <strong>Shift+Tab</strong> se posunete z聽jednoho odd铆lu u啪ivatelsk茅ho rozhran铆 na p艡edchoz铆.</p>\n' +
+  '\n' +
+  '<p>Po艡ad铆 p艡ep铆n谩n铆 mezi odd铆ly u啪ivatelsk茅ho rozhran铆 pomoc铆 kl谩vesy <strong>Tab</strong>:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>艠谩dek nab铆dek</li>\n' +
+  '  <li>Ka啪d谩 skupina panelu n谩stroj暖</li>\n' +
+  '  <li>Bo膷n铆 panel</li>\n' +
+  '  <li>Cesta k聽prvku v聽z谩pat铆.</li>\n' +
+  '  <li>Tla膷铆tko p艡ep铆na膷e po膷tu slov v聽z谩pat铆</li>\n' +
+  '  <li>Odkaz na informace o聽zna膷ce v聽z谩pat铆</li>\n' +
+  '  <li>脷chyt pro zm臎nu velikosti editoru v聽z谩pat铆</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Pokud n臎jak媒 odd铆l u啪ivatelsk茅ho rozhran铆 nen铆 p艡铆tomen, je p艡esko膷en.</p>\n' +
+  '\n' +
+  '<p>Pokud je z谩pat铆 vybran茅 pro navigaci pomoc铆 kl谩vesnice a聽nen铆 zobrazen 啪谩dn媒 bo膷n铆 panel, stisknut铆m kl谩ves <strong>Shift+Tab</strong>\n' +
+  '  p艡ejdete na prvn铆 skupinu panelu n谩stroj暖, nikoli na posledn铆.</p>\n' +
+  '\n' +
+  '<h1>Navigace v聽r谩mci odd铆l暖 u啪ivatelsk茅ho rozhran铆</h1>\n' +
+  '\n' +
+  '<p>Chcete-li se p艡esunout z聽jednoho prvku u啪ivatelsk茅ho rozhran铆 na dal拧铆, stiskn臎te p艡铆slu拧nou kl谩vesu s聽<strong>拧ipkou</strong>.</p>\n' +
+  '\n' +
+  '<p>Kl谩vesy s聽拧ipkou <strong>vlevo</strong> a聽<strong>vpravo</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umo啪艌uj铆 p艡esun mezi nab铆dkami na 艡谩dku nab铆dek;</li>\n' +
+  '  <li>otev铆raj铆 podnab铆dku nab铆dky;</li>\n' +
+  '  <li>umo啪艌uj铆 p艡esun mezi tla膷铆tky ve skupin臎 panelu n谩stroj暖;</li>\n' +
+  '  <li>umo啪艌uj铆 p艡esun mezi polo啪kami cesty prvku v聽z谩pat铆.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Kl谩vesy se 拧ipkou <strong>dol暖</strong> a聽<strong>nahoru</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umo啪艌uj铆 p艡esun mezi polo啪kami nab铆dky;</li>\n' +
+  '  <li>umo啪艌uj铆 p艡esun mezi polo啪kami m铆stn铆 nab铆dky panelu n谩stroj暖.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>艩ipky</strong> prov谩d铆 p艡ep铆n谩n铆 v聽r谩mci vybran茅ho odd铆lu u啪ivatelsk茅ho rozhran铆.</p>\n' +
+  '\n' +
+  '<p>Chcete-li zav艡铆t otev艡enou nab铆dku, podnab铆dku nebo m铆stn铆 nab铆dku, stiskn臎te kl谩vesu <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Pokud je aktu谩ln臎 vybr谩na horn铆 膷谩st odd铆lu u啪ivatelsk茅ho rozhran铆, stisknut铆m kl谩vesy <strong>Esc</strong> zcela ukon膷铆te tak茅\n' +
+  '  navigaci pomoc铆 kl谩vesnice.</p>\n' +
+  '\n' +
+  '<h1>Proveden铆 p艡铆kazu polo啪ky nab铆dky nebo tla膷铆tka panelu n谩stroj暖</h1>\n' +
+  '\n' +
+  '<p>Pokud je zv媒razn臎na po啪adovan谩 polo啪ka nab铆dky nebo tla膷铆tko panelu n谩stroj暖, stisknut铆m kl谩vesy <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  nebo <strong>mezern铆ku</strong> provedete p艡铆slu拧n媒 p艡铆kaz.</p>\n' +
+  '\n' +
+  '<h1>Navigace v聽dialogov媒ch oknech bez z谩lo啪ek</h1>\n' +
+  '\n' +
+  '<p>P艡i otev艡en铆 dialogov媒ch oken bez z谩lo啪ek p艡ejdete na prvn铆 interaktivn铆 komponentu.</p>\n' +
+  '\n' +
+  '<p>P艡ech谩zet mezi interaktivn铆mi komponentami dialogov茅ho okna m暖啪ete stisknut铆m kl谩vesy <strong>Tab</strong> nebo kombinace <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigace v聽dialogov媒ch oknech se z谩lo啪kami</h1>\n' +
+  '\n' +
+  '<p>P艡i otev艡en铆 dialogov媒ch oken se z谩lo啪kami p艡ejdete na prvn铆 tla膷铆tko v聽nab铆dce z谩lo啪ek.</p>\n' +
+  '\n' +
+  '<p>P艡ech谩zet mezi interaktivn铆mi komponentami t茅to z谩lo啪ky dialogov茅ho okna m暖啪ete stisknut铆m kl谩vesy <strong>Tab</strong> nebo\n' +
+  '  kombinace <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Chcete-li p艡epnout na dal拧铆 z谩lo啪ku dialogov茅ho okna, p艡ejd臎te na nab铆dku z谩lo啪ek a聽pot茅 m暖啪ete stisknut铆m po啪adovan茅 <strong>拧ipky</strong>\n' +
+  '  p艡ep铆nat mezi dostupn媒mi z谩lo啪kami.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js
new file mode 100644
index 0000000..4d1e1d4
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/da.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.da',
+'<h1>Start tastaturnavigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokuser p氓 menulinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokuser p氓 v忙rkt酶jslinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokuser p氓 sidefoden</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuser p氓 meddelelsen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokuser p氓 kontekstuel v忙rkt酶jslinje</dt>\n' +
+  '  <dd>Windows, Linux eller macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigationen starter ved det f酶rste UI-element, som fremh忙ves eller understreges hvad ang氓r det f酶rste element i\n' +
+  '  sidefodens sti til elementet.</p>\n' +
+  '\n' +
+  '<h1>Naviger mellem UI-sektioner</h1>\n' +
+  '\n' +
+  '<p>G氓 fra 茅n UI-sektion til den n忙ste ved at trykke p氓 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>G氓 fra 茅n UI-sektion til den forrige ved at trykke p氓 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong>-r忙kkef酶lgen af disse UI-sektioner er:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menulinje</li>\n' +
+  '  <li>Hver v忙rkt酶jsgruppe</li>\n' +
+  '  <li>Sidepanel</li>\n' +
+  '  <li>Sti til elementet i sidefoden</li>\n' +
+  '  <li>Til/fra-knap for ordopt忙lling i sidefoden</li>\n' +
+  '  <li>Brandinglink i sidefoden</li>\n' +
+  '  <li>Tilpasningsh氓ndtag for editor i sidefoden</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Hvis en UI-sektion ikke er til stede, springes den over.</p>\n' +
+  '\n' +
+  '<p>Hvis sidefoden har fokus til tastaturnavigation, og der ikke er noget synligt sidepanel, kan der trykkes p氓 <strong>Shift+Tab</strong>\n' +
+  '  for at flytte fokus til den f酶rste v忙rkt酶jsgruppe, ikke den sidste.</p>\n' +
+  '\n' +
+  '<h1>Naviger inden for UI-sektioner</h1>\n' +
+  '\n' +
+  '<p>G氓 fra 茅t UI-element til det n忙ste ved at trykke p氓 den relevante <strong>piletast</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Venstre</strong> og <strong>h酶jre</strong> piletast</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytter mellem menuerne i menulinjen.</li>\n' +
+  '  <li>氓bner en undermenu i en menu.</li>\n' +
+  '  <li>flytter mellem knapperne i en v忙rkt酶jsgruppe.</li>\n' +
+  '  <li>flytter mellem elementer i sidefodens sti til elementet.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Pil <strong>ned</strong> og <strong>op</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytter mellem menupunkterne i en menu.</li>\n' +
+  '  <li>flytter mellem punkterne i en genvejsmenu i v忙rkt酶jslinjen.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Piletasterne</strong> k酶rer rundt inden for UI-sektionen, der fokuseres p氓.</p>\n' +
+  '\n' +
+  '<p>For at lukke en 氓ben menu, en 氓ben undermenu eller en 氓ben genvejsmenu trykkes der p氓 <strong>Esc</strong>-tasten.</p>\n' +
+  '\n' +
+  "<p>Hvis det aktuelle fokus er i 'toppen' af en bestemt UI-sektion, vil tryk p氓 <strong>Esc</strong>-tasten ogs氓 afslutte\n" +
+  '  tastaturnavigationen helt.</p>\n' +
+  '\n' +
+  '<h1>Udf酶r et menupunkt eller en v忙rkt酶jslinjeknap</h1>\n' +
+  '\n' +
+  '<p>N氓r det 酶nskede menupunkt eller den 酶nskede v忙rkt酶jslinjeknap er fremh忙vet, trykkes der p氓 <strong>Retur</strong>, <strong>Enter</strong>\n' +
+  '  eller <strong>mellemrumstasten</strong> for at udf酶re elementet.</p>\n' +
+  '\n' +
+  '<h1>Naviger i ikke-faneopdelte dialogbokse</h1>\n' +
+  '\n' +
+  '<p>I ikke-faneopdelte dialogbokse f氓r den f酶rste interaktive komponent fokus, n氓r dialogboksen 氓bnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellem interaktive dialogbokskomponenter ved at trykke p氓 <strong>Tab</strong> eller <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Naviger i faneopdelte dialogbokse</h1>\n' +
+  '\n' +
+  '<p>I faneopdelte dialogbokse f氓r den f酶rste knap i fanemenuen fokus, n氓r dialogboksen 氓bnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellem interaktive komponenter i denne dialogboksfane ved at trykke p氓 <strong>Tab</strong> eller\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Skift til en anden dialogboksfane ved at fokusere p氓 fanemenuen og derefter trykke p氓 den relevante <strong>piletast</strong>\n' +
+  '  for at k酶re igennem de tilg忙ngelige faner.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js
new file mode 100644
index 0000000..b8711ed
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/de.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.de',
+'<h1>Grundlagen der Tastaturnavigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokus auf Men眉leiste</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokus auf Symbolleiste</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokus auf Fu脽zeile</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Benachrichtigung fokussieren</dt>\n' +
+  '  <dd>Windows oder Linux: ALT+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokus auf kontextbezogene Symbolleiste</dt>\n' +
+  '  <dd>Windows, Linux oder macOS: STRG+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Die Navigation beginnt beim ersten Benutzeroberfl盲chenelement, welches hervorgehoben ist. Falls sich das erste Element im Pfad der Fu脽zeile befindet,\n' +
+  '  ist es unterstrichen.</p>\n' +
+  '\n' +
+  '<h1>Zwischen Abschnitten der Benutzeroberfl盲che navigieren</h1>\n' +
+  '\n' +
+  '<p>Um von einem Abschnitt der Benutzeroberfl盲che zum n盲chsten zu wechseln, dr眉cken Sie <strong>TAB</strong>.</p>\n' +
+  '\n' +
+  '<p>Um von einem Abschnitt der Benutzeroberfl盲che zum vorherigen zu wechseln, dr眉cken Sie <strong>UMSCHALT+TAB</strong>.</p>\n' +
+  '\n' +
+  '<p>Die Abschnitte der Benutzeroberfl盲che haben folgende <strong>TAB</strong>-Reihenfolge:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Men眉leiste</li>\n' +
+  '  <li>Einzelne Gruppen der Symbolleiste</li>\n' +
+  '  <li>Randleiste</li>\n' +
+  '  <li>Elementpfad in der Fu脽zeile</li>\n' +
+  '  <li>Umschaltfl盲che 鈥濿枚rter z盲hlen鈥� in der Fu脽zeile</li>\n' +
+  '  <li>Branding-Link in der Fu脽zeile</li>\n' +
+  '  <li>Editor-Ziehpunkt zur Gr枚脽en盲nderung in der Fu脽zeile</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Falls ein Abschnitt der Benutzeroberfl盲chen nicht vorhanden ist, wird er 眉bersprungen.</p>\n' +
+  '\n' +
+  '<p>Wenn in der Fu脽zeile die Tastaturnavigation fokussiert ist und keine Randleiste angezeigt wird, wechselt der Fokus durch Dr眉cken von <strong>UMSCHALT+TAB</strong>\n' +
+  '  zur ersten Gruppe der Symbolleiste, nicht zur letzten.</p>\n' +
+  '\n' +
+  '<h1>Innerhalb von Abschnitten der Benutzeroberfl盲che navigieren</h1>\n' +
+  '\n' +
+  '<p>Um von einem Element der Benutzeroberfl盲che zum n盲chsten zu wechseln, dr眉cken Sie die entsprechende <strong>Pfeiltaste</strong>.</p>\n' +
+  '\n' +
+  '<p>Die Pfeiltasten <strong>Links</strong> und <strong>Rechts</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>wechseln zwischen Men眉s in der Men眉leiste.</li>\n' +
+  '  <li>枚ffnen das Untermen眉 eines Men眉s.</li>\n' +
+  '  <li>wechseln zwischen Schaltfl盲chen in einer Gruppe der Symbolleiste.</li>\n' +
+  '  <li>wechseln zwischen Elementen im Elementpfad der Fu脽zeile.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Die Pfeiltasten <strong>Abw盲rts</strong> und <strong>Aufw盲rts</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>wechseln zwischen Men眉elementen in einem Men眉.</li>\n' +
+  '  <li>wechseln zwischen Elementen in einem Popupmen眉 der Symbolleiste.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Die <strong>Pfeiltasten</strong> rotieren innerhalb des fokussierten Abschnitts der Benutzeroberfl盲che.</p>\n' +
+  '\n' +
+  '<p>Um ein ge枚ffnetes Men眉, ein ge枚ffnetes Untermen眉 oder ein ge枚ffnetes Popupmen眉 zu schlie脽en, dr眉cken Sie die <strong>ESC</strong>-Taste.</p>\n' +
+  '\n' +
+  '<p>Wenn sich der aktuelle Fokus ganz oben in einem bestimmten Abschnitt der Benutzeroberfl盲che befindet, wird durch Dr眉cken der <strong>ESC</strong>-Taste auch\n' +
+  '  die Tastaturnavigation beendet.</p>\n' +
+  '\n' +
+  '<h1>Ein Men眉element oder eine Symbolleistenschaltfl盲che ausf眉hren</h1>\n' +
+  '\n' +
+  '<p>Wenn das gew眉nschte Men眉element oder die gew眉nschte Symbolleistenschaltfl盲che hervorgehoben ist, dr眉cken Sie <strong>Zur眉ck</strong>, <strong>Eingabe</strong>\n' +
+  '  oder die <strong>Leertaste</strong>, um das Element auszuf眉hren.</p>\n' +
+  '\n' +
+  '<h1>In Dialogfeldern ohne Registerkarten navigieren</h1>\n' +
+  '\n' +
+  '<p>In Dialogfeldern ohne Registerkarten ist beim 脰ffnen eines Dialogfelds die erste interaktive Komponente fokussiert.</p>\n' +
+  '\n' +
+  '<p>Navigieren Sie zwischen den interaktiven Komponenten eines Dialogfelds, indem Sie <strong>TAB</strong> oder <strong>UMSCHALT+TAB</strong> dr眉cken.</p>\n' +
+  '\n' +
+  '<h1>In Dialogfeldern mit Registerkarten navigieren</h1>\n' +
+  '\n' +
+  '<p>In Dialogfeldern mit Registerkarten ist beim 脰ffnen eines Dialogfelds die erste Schaltfl盲che eines Registerkartenmen眉s fokussiert.</p>\n' +
+  '\n' +
+  '<p>Navigieren Sie zwischen den interaktiven Komponenten auf dieser Registerkarte des Dialogfelds, indem Sie <strong>TAB</strong> oder\n' +
+  '  <strong>UMSCHALT+TAB</strong> dr眉cken.</p>\n' +
+  '\n' +
+  '<p>Wechseln Sie zu einer anderen Registerkarte des Dialogfelds, indem Sie den Fokus auf das Registerkartenmen眉 legen und dann die entsprechende <strong>Pfeiltaste</strong>\n' +
+  '  dr眉cken, um durch die verf眉gbaren Registerkarten zu rotieren.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js
new file mode 100644
index 0000000..98afabe
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/el.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.el',
+'<h1>螆谓伪蟻尉畏 蟺位慰萎纬畏蟽畏蟼 渭苇蟽蠅 蟺位畏魏蟿蟻慰位慰纬委慰蠀</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>螘蟽蟿委伪蟽畏 蟽蟿畏 纬蟻伪渭渭萎 渭蔚谓慰蠉</dt>\n' +
+  '  <dd>Windows 萎 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>螘蟽蟿委伪蟽畏 蟽蟿畏 纬蟻伪渭渭萎 蔚蟻纬伪位蔚委蠅谓</dt>\n' +
+  '  <dd>Windows 萎 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>螘蟽蟿委伪蟽畏 蟽蟿慰 蠀蟺慰蟽苇位喂未慰</dt>\n' +
+  '  <dd>Windows 萎 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>螘蟽蟿委伪蟽畏 蟽蟿畏谓 蔚喂未慰蟺慰委畏蟽畏</dt>\n' +
+  '  <dd>Windows 萎 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>螘蟽蟿委伪蟽畏 蟽蔚 纬蟻伪渭渭萎 蔚蟻纬伪位蔚委蠅谓 尾维蟽蔚喂 蟺蔚蟻喂蔚蠂慰渭苇谓慰蠀</dt>\n' +
+  '  <dd>Windows, Linux 萎 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>螚 蟺位慰萎纬畏蟽畏 胃伪 尉蔚魏喂谓萎蟽蔚喂 伪蟺蠈 蟿慰 蟺蟻蠋蟿慰 蟽蟿慰喂蠂蔚委慰 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏, 蟺慰蠀 胃伪 蔚蟺喂蟽畏渭伪委谓蔚蟿伪喂 萎 胃伪 蔚委谓伪喂 蠀蟺慰纬蟻伪渭渭喂蟽渭苇谓慰,\n' +
+  '  蠈蟺蠅蟼 蟽蟿畏谓 蟺蔚蟻委蟺蟿蠅蟽畏 蟿畏蟼 未喂伪未蟻慰渭萎蟼 蟿慰蠀 蟽蟿慰喂蠂蔚委慰蠀 违蟺慰蟽苇位喂未慰蠀.</p>\n' +
+  '\n' +
+  '<h1>螤位慰萎纬畏蟽畏 渭蔚蟿伪尉蠉 蔚谓慰蟿萎蟿蠅谓 蟿慰蠀 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏</h1>\n' +
+  '\n' +
+  '<p>螕喂伪 谓伪 渭蔚蟿伪魏喂谓畏胃蔚委蟿蔚 伪蟺蠈 渭喂伪 蔚谓蠈蟿畏蟿伪 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏 蟽蟿畏谓 蔚蟺蠈渭蔚谓畏, 蟺喂苇蟽蟿蔚 蟿慰 蟺位萎魏蟿蟻慰 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>螕喂伪 谓伪 渭蔚蟿伪魏喂谓畏胃蔚委蟿蔚 伪蟺蠈 渭喂伪 蔚谓蠈蟿畏蟿伪 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏 蟽蟿畏谓 蟺蟻慰畏纬慰蠉渭蔚谓畏, 蟺喂苇蟽蟿蔚 蟿伪 蟺位萎魏蟿蟻伪 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>螚 蟽蔚喂蟻维 <strong>Tab</strong> 伪蠀蟿蠋谓 蟿蠅谓 蔚谓慰蟿萎蟿蠅谓 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏 蔚委谓伪喂 畏 蔚尉萎蟼:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>螕蟻伪渭渭萎 渭蔚谓慰蠉</li>\n' +
+  '  <li>螝维胃蔚 慰渭维未伪 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓</li>\n' +
+  '  <li>螤位伪蠆谓萎 纬蟻伪渭渭萎</li>\n' +
+  '  <li>螖喂伪未蟻慰渭萎 蟽蟿慰喂蠂蔚委慰蠀 蟽蟿慰 蠀蟺慰蟽苇位喂未慰</li>\n' +
+  '  <li>螝慰蠀渭蟺委 蔚谓伪位位伪纬萎蟼 渭苇蟿蟻畏蟽畏蟼 位苇尉蔚蠅谓 蟽蟿慰 蠀蟺慰蟽苇位喂未慰</li>\n' +
+  '  <li>危蠉谓未蔚蟽渭慰蟼 蔚蟺蠅谓蠀渭委伪蟼 蟽蟿慰 蠀蟺慰蟽苇位喂未慰</li>\n' +
+  '  <li>螞伪尾萎 伪位位伪纬萎蟼 渭蔚纬苇胃慰蠀蟼 蟺蟻慰纬蟻维渭渭伪蟿慰蟼 蔚蟺蔚尉蔚蟻纬伪蟽委伪蟼 蟽蟿慰 蠀蟺慰蟽苇位喂未慰</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>螘维谓 未蔚谓 蔚渭蠁伪谓委味蔚蟿伪喂 蔚谓蠈蟿畏蟿伪 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏, 蟺伪蟻伪位蔚委蟺蔚蟿伪喂.</p>\n' +
+  '\n' +
+  '<p>螘维谓 畏 蔚蟽蟿委伪蟽畏 蟺位慰萎纬畏蟽畏蟼 尾蟻委蟽魏蔚蟿伪喂 蟽蟿慰 蟺位畏魏蟿蟻慰位蠈纬喂慰 魏伪喂 未蔚谓 蠀蟺维蟻蠂蔚喂 蔚渭蠁伪谓萎蟼 蟺位伪蠆谓萎 纬蟻伪渭渭萎, 蔚维谓 蟺喂苇蟽蔚蟿蔚 <strong>Shift+Tab</strong>\n' +
+  '  畏 蔚蟽蟿委伪蟽畏 渭蔚蟿伪魏喂谓蔚委蟿伪喂 蟽蟿畏谓 蟺蟻蠋蟿畏 慰渭维未伪 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓, 蠈蠂喂 蟽蟿畏谓 蟿蔚位蔚蠀蟿伪委伪.</p>\n' +
+  '\n' +
+  '<h1>螤位慰萎纬畏蟽畏 蔚谓蟿蠈蟼 蟿蠅谓 蔚谓慰蟿萎蟿蠅谓 蟿慰蠀 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏</h1>\n' +
+  '\n' +
+  '<p>螕喂伪 谓伪 渭蔚蟿伪魏喂谓畏胃蔚委蟿蔚 伪蟺蠈 苇谓伪 蟽蟿慰喂蠂蔚委慰 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏 蟽蟿慰 蔚蟺蠈渭蔚谓慰, 蟺喂苇蟽蟿蔚 蟿慰 伪谓蟿委蟽蟿慰喂蠂慰 蟺位萎魏蟿蟻慰 <strong>尾苇位慰蠀蟼</strong>.</p>\n' +
+  '\n' +
+  '<p>螠蔚 蟿伪 蟺位萎魏蟿蟻伪 <strong>伪蟻喂蟽蟿蔚蟻慰蠉</strong> 魏伪喂 <strong>未蔚尉喂慰蠉</strong> 尾苇位慰蠀蟼</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>纬委谓蔚蟿伪喂 渭蔚蟿伪魏委谓畏蟽畏 渭蔚蟿伪尉蠉 蟿蠅谓 渭蔚谓慰蠉 蟽蟿畏 纬蟻伪渭渭萎 渭蔚谓慰蠉.</li>\n' +
+  '  <li>伪谓慰委纬蔚喂 苇谓伪 蠀蟺慰渭蔚谓慰蠉 蟽蔚 苇谓伪 渭蔚谓慰蠉.</li>\n' +
+  '  <li>纬委谓蔚蟿伪喂 渭蔚蟿伪魏委谓畏蟽畏 渭蔚蟿伪尉蠉 魏慰蠀渭蟺喂蠋谓 蟽蔚 渭喂伪 慰渭维未伪 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓.</li>\n' +
+  '  <li>纬委谓蔚蟿伪喂 渭蔚蟿伪魏委谓畏蟽畏 渭蔚蟿伪尉蠉 蟽蟿慰喂蠂蔚委蠅谓 蟽蟿畏 未喂伪未蟻慰渭萎 蟽蟿慰喂蠂蔚委慰蠀 蟽蟿慰 蠀蟺慰蟽苇位喂未慰.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>螠蔚 蟿伪 蟺位萎魏蟿蟻伪 <strong>蔚蟺维谓蠅</strong> 魏伪喂 <strong>魏维蟿蠅</strong> 尾苇位慰蠀蟼</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>纬委谓蔚蟿伪喂 渭蔚蟿伪魏委谓畏蟽畏 渭蔚蟿伪尉蠉 蟿蠅谓 蟽蟿慰喂蠂蔚委蠅谓 渭蔚谓慰蠉 蟽蔚 苇谓伪 渭蔚谓慰蠉.</li>\n' +
+  '  <li>纬委谓蔚蟿伪喂 渭蔚蟿伪魏委谓畏蟽畏 渭蔚蟿伪尉蠉 蟿蠅谓 蟽蟿慰喂蠂蔚委蠅谓 渭蔚谓慰蠉 蟽蔚 苇谓伪 伪谓伪未蠀蠈渭蔚谓慰 渭蔚谓慰蠉 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>螠蔚 蟿伪 蟺位萎魏蟿蟻伪 <strong>尾苇位慰蠀蟼</strong> 纬委谓蔚蟿伪喂 魏蠀魏位喂魏萎 渭蔚蟿伪魏委谓畏蟽畏 蔚谓蟿蠈蟼 蟿畏蟼 蔚蟽蟿喂伪蟽渭苇谓畏蟼 蔚谓蠈蟿畏蟿伪蟼 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏.</p>\n' +
+  '\n' +
+  '<p>螕喂伪 谓伪 魏位蔚委蟽蔚蟿蔚 苇谓伪 伪谓慰喂蠂蟿蠈 渭蔚谓慰蠉, 苇谓伪 伪谓慰喂蠂蟿蠈 蠀蟺慰渭蔚谓慰蠉 萎 苇谓伪 伪谓慰喂蠂蟿蠈 伪谓伪未蠀蠈渭蔚谓慰 渭蔚谓慰蠉, 蟺喂苇蟽蟿蔚 蟿慰 蟺位萎魏蟿蟻慰 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>螘维谓 畏 蟿蟻苇蠂慰蠀蟽伪 蔚蟽蟿委伪蟽畏 尾蟻委蟽魏蔚蟿伪喂 蟽蟿畏谓 魏慰蟻蠀蠁萎 渭喂伪蟼 蔚谓蠈蟿畏蟿伪蟼 蟺蔚蟻喂尾维位位慰谓蟿慰蟼 蠂蟻萎蟽蟿畏, 蟺喂苇味慰谓蟿伪蟼 蟿慰 蟺位萎魏蟿蟻慰 <strong>Esc</strong>,\n' +
+  '  纬委谓蔚蟿伪喂 蔚蟺委蟽畏蟼 蟺位萎蟻畏蟼 苇尉慰未慰蟼 伪蟺蠈 蟿畏谓 蟺位慰萎纬畏蟽畏 渭苇蟽蠅 蟺位畏魏蟿蟻慰位慰纬委慰蠀.</p>\n' +
+  '\n' +
+  '<h1>螘魏蟿苇位蔚蟽畏 蔚谓蠈蟼 蟽蟿慰喂蠂蔚委慰蠀 渭蔚谓慰蠉 萎 魏慰蠀渭蟺喂慰蠉 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓</h1>\n' +
+  '\n' +
+  '<p>螌蟿伪谓 蟿慰 蔚蟺喂胃蠀渭畏蟿蠈 蟽蟿慰喂蠂蔚委慰 渭蔚谓慰蠉 萎 魏慰蠀渭蟺委 纬蟻伪渭渭萎蟼 蔚蟻纬伪位蔚委蠅谓 蔚委谓伪喂 蔚蟺喂蟽畏渭伪蟽渭苇谓慰, 蟺喂苇蟽蟿蔚 蟿伪 蟺位萎魏蟿蟻伪 <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  萎 蟿慰 <strong>蟺位萎魏蟿蟻慰 未喂伪蟽蟿萎渭伪蟿慰蟼</strong> 纬喂伪 谓伪 蔚魏蟿蔚位苇蟽蔚蟿蔚 蟿慰 蟽蟿慰喂蠂蔚委慰.</p>\n' +
+  '\n' +
+  '<h1>螤位慰萎纬畏蟽畏 蟽蔚 蟺伪蟻维胃蠀蟻伪 未喂伪位蠈纬慰蠀 蠂蠅蟻委蟼 魏伪蟻蟿苇位蔚蟼</h1>\n' +
+  '\n' +
+  '<p>危蔚 蟺伪蟻维胃蠀蟻伪 未喂伪位蠈纬慰蠀 蠂蠅蟻委蟼 魏伪蟻蟿苇位蔚蟼, 蟿慰 蟺蟻蠋蟿慰 伪位位畏位蔚蟺喂未蟻伪蟽蟿喂魏蠈 蟽蟿慰喂蠂蔚委慰 位伪渭尾维谓蔚喂 蟿畏谓 蔚蟽蟿委伪蟽畏 蠈蟿伪谓 伪谓慰委纬蔚喂 蟿慰 蟺伪蟻维胃蠀蟻慰 未喂伪位蠈纬慰蠀.</p>\n' +
+  '\n' +
+  '<p>螠蟺慰蟻蔚委蟿蔚 谓伪 蟺位慰畏纬畏胃蔚委蟿蔚 渭蔚蟿伪尉蠉 蟿蠅谓 伪位位畏位蔚蟺喂未蟻伪蟽蟿喂魏蠋谓 蟽蟿慰喂蠂蔚委蠅谓 蟺伪蟻伪胃蠉蟻蠅谓 未喂伪位蠈纬蠅谓 蟺喂苇味慰谓蟿伪蟼 蟿伪 蟺位萎魏蟿蟻伪 <strong>Tab</strong> 萎 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>螤位慰萎纬畏蟽畏 蟽蔚 蟺伪蟻维胃蠀蟻伪 未喂伪位蠈纬慰蠀 渭蔚 魏伪蟻蟿苇位蔚蟼</h1>\n' +
+  '\n' +
+  '<p>危蔚 蟺伪蟻维胃蠀蟻伪 未喂伪位蠈纬慰蠀 渭蔚 魏伪蟻蟿苇位蔚蟼, 蟿慰 蟺蟻蠋蟿慰 魏慰蠀渭蟺委 蟽蟿慰 渭蔚谓慰蠉 魏伪蟻蟿苇位伪蟼 位伪渭尾维谓蔚喂 蟿畏谓 蔚蟽蟿委伪蟽畏 蠈蟿伪谓 伪谓慰委纬蔚喂 蟿慰 蟺伪蟻维胃蠀蟻慰 未喂伪位蠈纬慰蠀.</p>\n' +
+  '\n' +
+  '<p>螠蟺慰蟻蔚委蟿蔚 谓伪 蟺位慰畏纬畏胃蔚委蟿蔚 渭蔚蟿伪尉蠉 蟿蠅谓 伪位位畏位蔚蟺喂未蟻伪蟽蟿喂魏蠋谓 蟽蟿慰喂蠂蔚委蠅谓 伪蠀蟿萎蟼 蟿畏蟼 魏伪蟻蟿苇位伪 未喂伪位蠈纬慰蠀 蟺喂苇味慰谓蟿伪蟼 蟿伪 蟺位萎魏蟿蟻伪 <strong>Tab</strong> 萎\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>螠蟺慰蟻蔚委蟿蔚 谓伪 魏维谓蔚蟿蔚 蔚谓伪位位伪纬萎 蟽蔚 维位位畏 魏伪蟻蟿苇位伪 蟿慰蠀 蟺伪蟻伪胃蠉蟻慰蠀 未喂伪位蠈纬慰蠀, 渭蔚蟿伪蠁苇蟻慰谓蟿伪蟼 蟿畏谓 蔚蟽蟿委伪蟽畏 蟽蟿慰 渭蔚谓慰蠉 魏伪蟻蟿苇位伪蟼 魏伪喂 蟺喂苇味慰谓蟿伪蟼 蟿慰 魏伪蟿维位位畏位慰 蟺位萎魏蟿蟻慰 <strong>尾苇位慰蠀蟼</strong>\n' +
+  '  纬喂伪 谓伪 渭蔚蟿伪魏喂谓畏胃蔚委蟿蔚 魏蠀魏位喂魏维 蟽蟿喂蟼 未喂伪胃苇蟽喂渭蔚蟼 魏伪蟻蟿苇位蔚蟼.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js
new file mode 100644
index 0000000..5dd753e
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/en.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.en',
+'<h1>Begin keyboard navigation</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Focus the Menu bar</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Focus the Toolbar</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Focus the footer</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Focus the notification</dt>\n' +
+  '  <dd>Windows or Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Focus a contextual toolbar</dt>\n' +
+  '  <dd>Windows, Linux or macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigation will start at the first UI item, which will be highlighted, or underlined in the case of the first item in\n' +
+  '  the Footer element path.</p>\n' +
+  '\n' +
+  '<h1>Navigate between UI sections</h1>\n' +
+  '\n' +
+  '<p>To move from one UI section to the next, press <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>To move from one UI section to the previous, press <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>The <strong>Tab</strong> order of these UI sections is:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menu bar</li>\n' +
+  '  <li>Each toolbar group</li>\n' +
+  '  <li>Sidebar</li>\n' +
+  '  <li>Element path in the footer</li>\n' +
+  '  <li>Word count toggle button in the footer</li>\n' +
+  '  <li>Branding link in the footer</li>\n' +
+  '  <li>Editor resize handle in the footer</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>If a UI section is not present, it is skipped.</p>\n' +
+  '\n' +
+  '<p>If the footer has keyboard navigation focus, and there is no visible sidebar, pressing <strong>Shift+Tab</strong>\n' +
+  '  moves focus to the first toolbar group, not the last.</p>\n' +
+  '\n' +
+  '<h1>Navigate within UI sections</h1>\n' +
+  '\n' +
+  '<p>To move from one UI element to the next, press the appropriate <strong>Arrow</strong> key.</p>\n' +
+  '\n' +
+  '<p>The <strong>Left</strong> and <strong>Right</strong> arrow keys</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>move between menus in the menu bar.</li>\n' +
+  '  <li>open a sub-menu in a menu.</li>\n' +
+  '  <li>move between buttons in a toolbar group.</li>\n' +
+  '  <li>move between items in the footer鈥檚 element path.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>The <strong>Down</strong> and <strong>Up</strong> arrow keys</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>move between menu items in a menu.</li>\n' +
+  '  <li>move between items in a toolbar pop-up menu.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Arrow</strong> keys cycle within the focused UI section.</p>\n' +
+  '\n' +
+  '<p>To close an open menu, an open sub-menu, or an open pop-up menu, press the <strong>Esc</strong> key.</p>\n' +
+  '\n' +
+  '<p>If the current focus is at the 鈥榯op鈥� of a particular UI section, pressing the <strong>Esc</strong> key also exits\n' +
+  '  keyboard navigation entirely.</p>\n' +
+  '\n' +
+  '<h1>Execute a menu item or toolbar button</h1>\n' +
+  '\n' +
+  '<p>When the desired menu item or toolbar button is highlighted, press <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  or the <strong>Space bar</strong> to execute the item.</p>\n' +
+  '\n' +
+  '<h1>Navigate non-tabbed dialogs</h1>\n' +
+  '\n' +
+  '<p>In non-tabbed dialogs, the first interactive component takes focus when the dialog opens.</p>\n' +
+  '\n' +
+  '<p>Navigate between interactive dialog components by pressing <strong>Tab</strong> or <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigate tabbed dialogs</h1>\n' +
+  '\n' +
+  '<p>In tabbed dialogs, the first button in the tab menu takes focus when the dialog opens.</p>\n' +
+  '\n' +
+  '<p>Navigate between interactive components of this dialog tab by pressing <strong>Tab</strong> or\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Switch to another dialog tab by giving the tab menu focus and then pressing the appropriate <strong>Arrow</strong>\n' +
+  '  key to cycle through the available tabs.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js
new file mode 100644
index 0000000..e426c2e
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/es.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.es',
+'<h1>Iniciar la navegaci贸n con el teclado</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Enfocar la barra de men煤s</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Enfocar la barra de herramientas</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Enfocar el pie de p谩gina</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Enfocar la notificaci贸n</dt>\n' +
+  '  <dd>Windows o Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Enfocar una barra de herramientas contextual</dt>\n' +
+  '  <dd>Windows, Linux o macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>La navegaci贸n comenzar谩 por el primer elemento de la interfaz de usuario (IU), de tal manera que se resaltar谩, o bien se subrayar谩 si se trata del primer elemento de\n' +
+  '  la ruta de elemento del pie de p谩gina.</p>\n' +
+  '\n' +
+  '<h1>Navegar entre las secciones de la IU</h1>\n' +
+  '\n' +
+  '<p>Para pasar de una secci贸n de la IU a la siguiente, pulse la tecla <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Para pasar de una secci贸n de la IU a la anterior, pulse <strong>May煤s+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>El orden de <strong>tabulaci贸n</strong> de estas secciones de la IU es:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de men煤s</li>\n' +
+  '  <li>Cada grupo de barra de herramientas</li>\n' +
+  '  <li>Barra lateral</li>\n' +
+  '  <li>Ruta del elemento en el pie de p谩gina</li>\n' +
+  '  <li>Bot贸n de alternancia de recuento de palabras en el pie de p谩gina</li>\n' +
+  '  <li>Enlace de personalizaci贸n de marca en el pie de p谩gina</li>\n' +
+  '  <li>Controlador de cambio de tama帽o en el pie de p谩gina</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Si una secci贸n de la IU no est谩 presente, esta se omite.</p>\n' +
+  '\n' +
+  '<p>Si el pie de p谩gina tiene un enfoque de navegaci贸n con el teclado y no hay ninguna barra lateral visible, al pulsar <strong>May煤s+Tab</strong>,\n' +
+  '  el enfoque se mover谩 al primer grupo de barra de herramientas, en lugar de al 煤ltimo.</p>\n' +
+  '\n' +
+  '<h1>Navegar dentro de las secciones de la IU</h1>\n' +
+  '\n' +
+  '<p>Para pasar de un elemento de la IU al siguiente, pulse la tecla de <strong>flecha</strong> correspondiente.</p>\n' +
+  '\n' +
+  '<p>Las teclas de flecha <strong>izquierda</strong> y <strong>derecha</strong> permiten</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>desplazarse entre los men煤s de la barra de men煤s.</li>\n' +
+  '  <li>abrir el submen煤 de un men煤.</li>\n' +
+  '  <li>desplazarse entre los botones de un grupo de barra de herramientas.</li>\n' +
+  '  <li>desplazarse entre los elementos de la ruta de elemento del pie de p谩gina.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Las teclas de flecha <strong>abajo</strong> y <strong>arriba</strong> permiten</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>desplazarse entre los elementos de men煤 de un men煤.</li>\n' +
+  '  <li>desplazarse entre los elementos de un men煤 emergente de una barra de herramientas.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Las teclas de <strong>flecha</strong> van cambiando dentro de la secci贸n de la IU enfocada.</p>\n' +
+  '\n' +
+  '<p>Para cerrar un men煤, un submen煤 o un men煤 emergente que est茅n abiertos, pulse la tecla <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Si el enfoque actual se encuentra en la parte superior de una secci贸n de la IU determinada, al pulsar la tecla <strong>Esc</strong> saldr谩\n' +
+  '  de la navegaci贸n con el teclado por completo.</p>\n' +
+  '\n' +
+  '<h1>Ejecutar un elemento de men煤 o un bot贸n de barra de herramientas</h1>\n' +
+  '\n' +
+  '<p>Si el elemento de men煤 o el bot贸n de barra de herramientas deseado est谩 resaltado, pulse la tecla <strong>Retorno</strong> o <strong>Entrar</strong>,\n' +
+  '  o la <strong>barra espaciadora</strong> para ejecutar el elemento.</p>\n' +
+  '\n' +
+  '<h1>Navegar por cuadros de di谩logo sin pesta帽as</h1>\n' +
+  '\n' +
+  '<p>En los cuadros de di谩logo sin pesta帽as, el primer componente interactivo se enfoca al abrirse el cuadro de di谩logo.</p>\n' +
+  '\n' +
+  '<p>Para navegar entre los componentes interactivos del cuadro de di谩logo, pulse las teclas <strong>Tab</strong> o <strong>May煤s+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navegar por cuadros de di谩logo con pesta帽as</h1>\n' +
+  '\n' +
+  '<p>En los cuadros de di谩logo con pesta帽as, el primer bot贸n del men煤 de pesta帽a se enfoca al abrirse el cuadro de di谩logo.</p>\n' +
+  '\n' +
+  '<p>Para navegar entre componentes interactivos de esta pesta帽a del cuadro de di谩logo, pulse las teclas <strong>Tab</strong> o\n' +
+  '  <strong>May煤s+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Si desea cambiar a otra pesta帽a del cuadro de di谩logo, enfoque el men煤 de pesta帽as y, a continuaci贸n, pulse la tecla de <strong>flecha</strong>\n' +
+  '  correspondiente para moverse por las pesta帽as disponibles.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js
new file mode 100644
index 0000000..c18b940
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/eu.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.eu',
+'<h1>Hasi teklatuaren nabigazioa</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokuratu menu-barra</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokuratu tresna-barra</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokuratu orri-oina</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuratu jakinarazpena</dt>\n' +
+  '  <dd>Windows edo Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokuratu testuinguruaren tresna-barra</dt>\n' +
+  '  <dd>Windows, Linux edo macOS: Ktrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Nabigazioa EIko lehen elementuan hasiko da: elementu hori nabarmendu egingo da, edo azpimarratu lehen elementua bada\n' +
+  '  orri-oineko elementuaren bidea.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu EIko atalen artean</h1>\n' +
+  '\n' +
+  '<p>EIko atal batetik hurrengora mugitzeko, sakatu <strong>Tabuladorea</strong>.</p>\n' +
+  '\n' +
+  '<p>EIko atal batetik aurrekora mugitzeko, sakatu <strong>Maius+Tabuladorea</strong>.</p>\n' +
+  '\n' +
+  '<p>EIko atal hauen <strong>Tabuladorea</strong> da:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menu-barra</li>\n' +
+  '  <li>Tresna-barraren talde bakoitza</li>\n' +
+  '  <li>Alboko barra</li>\n' +
+  '  <li>Orri-oineko elementuaren bidea</li>\n' +
+  '  <li>Orri-oneko urrats-kontaketa txandakatzeko botoia</li>\n' +
+  '  <li>Orri-oineko marken esteka</li>\n' +
+  '  <li>Orri-oineko editorearen tamaina aldatzeko heldulekua</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>EIko atal bat ez badago, saltatu egin da.</p>\n' +
+  '\n' +
+  '<p>Orri-oinak teklatuaren nabigazioa fokuratuta badago, eta alboko barra ikusgai ez badago, <strong>Maius+Tabuladorea</strong> sakatuz gero,\n' +
+  '  fokua tresna-barrako lehen taldera eramaten da, ez azkenera.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu EIko atalen barruan</h1>\n' +
+  '\n' +
+  '<p>EIko elementu batetik hurrengora mugitzeko, sakatu dagokion <strong>Gezia</strong> tekla.</p>\n' +
+  '\n' +
+  '<p><strong>Ezkerrera</strong> eta <strong>Eskuinera</strong> gezi-teklak</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>menu-barrako menuen artean mugitzen da.</li>\n' +
+  '  <li>ireki azpimenu bat menuan.</li>\n' +
+  '  <li>mugitu botoi batetik bestera tresna-barren talde batean.</li>\n' +
+  '  <li>mugitu orri-oineko elementuaren bideko elementu batetik bestera.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Gora</strong> eta <strong>Behera</strong> gezi-teklak</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>mugitu menu bateko menu-elementuen artean.</li>\n' +
+  '  <li>mugitu tresna-barrako menu gainerakor bateko menu-elementuen artean.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Gezia</strong> teklen zikloa nabarmendutako EI atalen barruan.</p>\n' +
+  '\n' +
+  '<p>Irekitako menu bat ixteko, ireki azpimenua, edo ireki menu gainerakorra, sakatu <strong>Ihes</strong> tekla.</p>\n' +
+  '\n' +
+  '<p>Une horretan fokuratzea EIko atal jakin baten "goialdean" badago, <strong>Ihes</strong> tekla sakatuz gero\n' +
+  '  teklatuaren nabigaziotik irtengo zara.</p>\n' +
+  '\n' +
+  '<h1>Exekutatu menuko elementu bat edo tresna-barrako botoi bat</h1>\n' +
+  '\n' +
+  '<p>Nahi den menuaren elementua edo tresna-barraren botoia nabarmenduta dagoenean, sakatu <strong>Itzuli</strong>, <strong>Sartu</strong>\n' +
+  '  edo <strong>Zuriune-barra</strong> elementua exekutatzeko.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu fitxarik gabeko elkarrizketak</h1>\n' +
+  '\n' +
+  '<p>Fitxarik gabeko elkarrizketetan, lehen osagai interaktiboa fokuratzen da elkarrizketa irekitzen denean.</p>\n' +
+  '\n' +
+  '<p>Nabigatu elkarrizketa interaktiboko osagai batetik bestera <strong>Tabuladorea</strong> edo <strong>Maius+Tabuladorea</strong> sakatuta.</p>\n' +
+  '\n' +
+  '<h1>Nabigatu fitxadun elkarrizketak</h1>\n' +
+  '\n' +
+  '<p>Fitxadun elkarrizketetan, fitxa-menuko lehen botoia fokuratzen da elkarrizketa irekitzen denean.</p>\n' +
+  '\n' +
+  '<p>Nabigatu elkarrizketa-fitxa honen interaktiboko osagai batetik bestera <strong>Tabuladorea</strong> edo\n' +
+  '  <strong>Maius+Tabuladorea</strong> sakatuta.</p>\n' +
+  '\n' +
+  '<p>Aldatu beste elkarrizketa-fitxa batera fitxa-menua fokuratu eta dagokion <strong>Gezia</strong>\n' +
+  '  tekla sakatzeko, erabilgarri dauden fitxa batetik bestera txandakatzeko.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js
new file mode 100644
index 0000000..2a55012
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fa.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fa',
+'<h1>卮乇賵毓 倬蹖賲丕蹖卮 氐賮丨賴鈥屭┵勠屫�</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>鬲賲乇讴夭 亘乇 賳賵丕乇 賲賳賵</dt>\n' +
+  '  <dd>Windows 蹖丕 Linux:鈥庘��: Alt+F9</dd>\n' +
+  '  <dd>鈥庘�弇acOS: &#x2325;F9鈥庘��</dd>\n' +
+  '  <dt>鬲賲乇讴夭 亘乇 賳賵丕乇 丕亘夭丕乇</dt>\n' +
+  '  <dd>Windows 蹖丕 Linux鈥庘��: Alt+F10</dd>\n' +
+  '  <dd>鈥庘�弇acOS: &#x2325;F10鈥庘��</dd>\n' +
+  '  <dt>鬲賲乇讴夭 亘乇 倬丕賳賵蹖爻</dt>\n' +
+  '  <dd>Windows 蹖丕 Linux鈥庘��: Alt+F11</dd>\n' +
+  '  <dd>鈥庘�弇acOS: &#x2325;F11鈥庘��</dd>\n' +
+  '  <dt>鬲賲乇讴夭 丕毓賱丕賳</dt>\n' +
+  '  <dd>賵蹖賳丿賵夭 蹖丕 賱蹖賳賵讴爻: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>鬲賲乇讴夭 亘乇 賳賵丕乇 丕亘夭丕乇 亘丕賮鬲丕乇蹖</dt>\n' +
+  '  <dd>Windows 貙Linux 蹖丕 macOS:鈥� Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>倬蹖賲丕蹖卮 丿乇 丕賵賱蹖賳 賲賵乇丿 乇丕亘胤 讴丕乇亘乇蹖 卮乇賵毓 賲蹖鈥屫促堌� 賵 丿乇禺氐賵氐 丕賵賱蹖賳 賲賵乇丿 丿乇\n' +
+  '  賲爻蹖乇 毓賳氐乇 倬丕賳賵蹖爻貙 亘乇噩爻鬲賴 蹖丕 夭蹖乇禺胤鈥屫ж� 賲蹖鈥屫促堌�.</p>\n' +
+  '\n' +
+  '<h1>倬蹖賲丕蹖卮 亘蹖賳 亘禺卮鈥屬囏й� 乇丕亘胤 讴丕乇亘乇蹖</h1>\n' +
+  '\n' +
+  '<p>亘乇丕蹖 噩丕亘噩丕蹖蹖 丕夭 蹖讴 亘禺卮 乇丕亘胤 讴丕乇亘乇蹖 亘賴 亘禺卮 亘毓丿蹖貙 <strong>Tab</strong> 乇丕 賮卮丕乇 丿賴蹖丿.</p>\n' +
+  '\n' +
+  '<p>亘乇丕蹖 噩丕亘噩丕蹖蹖 丕夭 蹖讴 亘禺卮 乇丕亘胤 讴丕乇亘乇蹖 亘賴 亘禺卮 賯亘賱蹖貙 <strong>Shift+Tab</strong> 乇丕 賮卮丕乇 丿賴蹖丿.</p>\n' +
+  '\n' +
+  '<p>鬲乇鬲蹖亘 <strong>Tab</strong> 丕蹖賳 亘禺卮鈥屬囏й� 乇丕亘胤 讴丕乇亘乇蹖 毓亘丕乇鬲賳丿 丕夭:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>賳賵丕乇 賲賳賵</li>\n' +
+  '  <li>賴乇 诏乇賵賴 賳賵丕乇 丕亘夭丕乇</li>\n' +
+  '  <li>賳賵丕乇 讴賳丕乇蹖</li>\n' +
+  '  <li>賲爻蹖乇 毓賳氐乇 丿乇 倬丕賳賵蹖爻</li>\n' +
+  '  <li>丿讴賲賴 鬲睾蹖蹖乇 賵囟毓蹖鬲 鬲毓丿丕丿 讴賱賲丕鬲 丿乇 倬丕賳賵蹖爻</li>\n' +
+  '  <li>倬蹖賵賳丿 賳賲丕賳丕賲鈥屫池ж槽� 丿乇 倬丕賳賵蹖爻</li>\n' +
+  '  <li>丿爻鬲賴 鬲睾蹖蹖乇 丕賳丿丕夭賴 賵蹖乇丕蹖卮诏乇 丿乇 倬丕賳賵蹖爻</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>丕诏乇 亘禺卮蹖 丕夭 乇丕亘胤 讴丕乇亘乇蹖 賲賵噩賵丿 賳亘丕卮丿貙 乇丿 賲蹖鈥屫促堌�.</p>\n' +
+  '\n' +
+  '<p>丕诏乇 倬丕賳賵蹖爻 丿丕乇丕蹖 鬲賲乇讴夭 亘乇 倬蹖賲丕蹖卮 氐賮丨賴鈥屭┵勠屫� 亘丕卮丿貙鈥� 賵 賳賵丕乇 讴賳丕乇蹖 賯丕亘賱鈥屬呚簇з囏� 賵噩賵丿 賳丿丕乇丿貙 賮卮乇丿賳 <strong>Shift+Tab</strong>\n' +
+  '  鬲賲乇讴夭 乇丕 亘賴 诏乇賵賴 賳賵丕乇 丕亘夭丕乇 丕賵賱 賲蹖鈥屫ㄘ必� 賳賴 丌禺乇.</p>\n' +
+  '\n' +
+  '<h1>倬蹖賲丕蹖卮 丿乇 亘禺卮鈥屬囏й� 乇丕亘胤 讴丕乇亘乇蹖</h1>\n' +
+  '\n' +
+  '<p>亘乇丕蹖 噩丕亘噩丕蹖蹖 丕夭 蹖讴 毓賳氐乇 乇丕亘胤 讴丕乇亘乇蹖 亘賴 亘毓丿蹖貙 讴賱蹖丿 <strong>噩賴鬲鈥屬嗁呚й�</strong> 賲賳丕爻亘 乇丕 賮卮丕乇 丿賴蹖丿.</p>\n' +
+  '\n' +
+  '<p>讴賱蹖丿賴丕蹖 噩賴鬲鈥屬嗁呚й� <strong>趩倬</strong> 賵 <strong>乇丕爻鬲</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>噩丕亘噩丕蹖蹖 亘蹖賳 賲賳賵賴丕 丿乇 賳賵丕乇 賲賳賵.</li>\n' +
+  '  <li>亘丕夭 讴乇丿賳 賲賳賵蹖 賮乇毓蹖 丿乇 蹖讴 賲賳賵.</li>\n' +
+  '  <li>噩丕亘噩丕蹖蹖 亘蹖賳 丿讴賲賴鈥屬囏� 丿乇 蹖讴 诏乇賵賴 賳賵丕乇 丕亘夭丕乇.</li>\n' +
+  '  <li>噩丕亘噩丕蹖蹖 亘蹖賳 賲賵丕乇丿 丿乇 賲爻蹖乇 毓賳氐乇 倬丕賳賵蹖爻.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>讴賱蹖丿賴丕蹖 噩賴鬲鈥屬嗁呚й� <strong>倬丕蹖蹖賳</strong> 賵 <strong>亘丕賱丕</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>噩丕亘噩丕蹖蹖 亘蹖賳 賲賵丕乇丿 賲賳賵 丿乇 蹖讴 賲賳賵.</li>\n' +
+  '  <li>噩丕亘噩丕蹖蹖 亘蹖賳 賲賵丕乇丿 丿乇 蹖讴 賲賳賵蹖 亘丕夭卮賵蹖 賳賵丕乇 丕亘夭丕乇.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>讴賱蹖丿賴丕蹖<strong>噩賴鬲鈥屬嗁呚�</strong> 丿乇 亘禺卮 乇丕亘胤 讴丕乇亘乇蹖 賲鬲賲乇讴夭 賲蹖鈥屭嗀必嗀�.</p>\n' +
+  '\n' +
+  '<p>亘乇丕蹖 亘爻鬲賳 蹖讴 賲賳賵蹖 亘丕夭貙 蹖讴 賲賳賵蹖 賮乇毓蹖 亘丕夭貙 蹖丕 蹖讴 賲賳賵蹖 亘丕夭卮賵蹖 亘丕夭貙 讴賱蹖丿 <strong>Esc</strong> 乇丕 賮卮丕乇 丿賴蹖丿.</p>\n' +
+  '\n' +
+  '<p>丕诏乇 鬲賲乇讴夭 賮毓賱蹖 丿乇 芦亘丕賱丕蹖禄 蹖讴 亘禺卮 乇丕亘胤 讴丕乇亘乇蹖 禺丕氐 丕爻鬲貙 賮卮乇丿賳 讴賱蹖丿 <strong>Esc</strong> 賳蹖夭 賲賵噩亘\n' +
+  '  禺乇賵噩 讴丕賲賱 丕夭 倬蹖賲丕蹖卮 氐賮丨賴鈥屭┵勠屫� 賲蹖鈥屫促堌�.</p>\n' +
+  '\n' +
+  '<h1>丕噩乇丕蹖 蹖讴 賲賵乇丿 賲賳賵 蹖丕 丿讴賲賴 賳賵丕乇 丕亘夭丕乇</h1>\n' +
+  '\n' +
+  '<p>賵賯鬲蹖 賲賵乇丿 賲賳賵 蹖丕 丿讴賲賴 賳賵丕乇 丕亘夭丕乇 賲賵乇丿 賳馗乇 賴丕蹖賱丕蹖鬲 卮丿貙 丿讴賲賴 <strong>亘丕夭诏卮鬲</strong>貙 <strong>Enter</strong>貙\n' +
+  '  蹖丕 <strong>賳賵丕乇 Space</strong> 乇丕 賮卮丕乇 丿賴蹖丿 鬲丕 賲賵乇丿 乇丕 丕噩乇丕 讴賳蹖丿.</p>\n' +
+  '\n' +
+  '<h1>倬蹖賲丕蹖卮 丿乇 讴丕丿乇賴丕蹖 诏賮鬲诏賵蹖 亘丿賵賳 夭亘丕賳賴</h1>\n' +
+  '\n' +
+  '<p>丿乇 讴丕丿乇賴丕蹖 诏賮鬲诏賵蹖 亘丿賵賳 夭亘丕賳賴貙 賵賯鬲蹖 讴丕丿乇 诏賮鬲诏賵 亘丕夭 賲蹖鈥屫促堌� 丕賵賱蹖賳 噩夭亍 鬲毓丕賲賱蹖 賲鬲賲乇讴夭 賲蹖鈥屫促堌�.</p>\n' +
+  '\n' +
+  '<p>亘丕 賮卮乇丿賳 <strong>Tab</strong> 蹖丕 <strong>Shift+Tab</strong>貙 亘蹖賳 丕噩夭丕蹖 讴丕丿乇 诏賮鬲诏賵蹖 鬲毓丕賲賱蹖 倬蹖賲丕蹖卮 讴賳蹖丿.</p>\n' +
+  '\n' +
+  '<h1>倬蹖賲丕蹖卮 讴丕丿乇賴丕蹖 诏賮鬲诏賵蹖 夭亘丕賳賴鈥屫ж�</h1>\n' +
+  '\n' +
+  '<p>丿乇 讴丕丿乇賴丕蹖 诏賮鬲诏賵蹖 夭亘丕賳賴鈥屫ж必� 賵賯鬲蹖 讴丕丿乇 诏賮鬲诏賵 亘丕夭 賲蹖鈥屫促堌� 丕賵賱蹖賳 丿讴賲賴 丿乇 賲賳賵蹖 夭亘丕賳賴 賲鬲賲乇讴夭 賲蹖鈥屫促堌�.</p>\n' +
+  '\n' +
+  '<p>亘丕 賮卮乇丿賳 <strong>Tab</strong> 蹖丕\n' +
+  '  <strong>Shift+Tab</strong>貙 亘蹖賳 丕噩夭丕蹖 鬲毓丕賲賱蹖 丕蹖賳 夭亘丕賳賴 讴丕丿乇 诏賮鬲诏賵 倬蹖賲丕蹖卮 讴賳蹖丿.</p>\n' +
+  '\n' +
+  '<p>亘丕 丿丕丿賳 鬲賲乇讴夭 亘賴 賲賳賵蹖 夭亘丕賳賴 賵 爻倬爻 賮卮丕乇 丿丕丿賳 讴賱蹖丿 <strong>噩賴鬲鈥屬嗁呚й�</strong>\n' +
+  '  賲賳丕爻亘 亘乇丕蹖 趩乇禺卮 賲蹖丕賳 夭亘丕賳賴鈥屬囏й� 賲賵噩賵丿貙 亘賴 夭亘丕賳賴 讴丕丿乇 诏賮鬲诏賵蹖 丿蹖诏乇蹖 亘乇賵蹖丿.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js
new file mode 100644
index 0000000..f01dc91
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fi.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fi',
+'<h1>N盲pp盲imist枚navigoinnin aloittaminen</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Siirr盲 kohdistus valikkopalkkiin</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Siirr盲 kohdistus ty枚kalupalkkiin</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Siirr盲 kohdistus alatunnisteeseen</dt>\n' +
+  '  <dd>Windows tai Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Keskit盲 ilmoitukseen</dt>\n' +
+  '  <dd>Windows ja Linux: Alt + F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Siirr盲 kohdistus kontekstuaaliseen ty枚kalupalkkiin</dt>\n' +
+  '  <dd>Windows, Linux tai macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigointi aloitetaan ensimm盲isest盲 k盲ytt枚liittym盲n kohteesta, joka joko korostetaan tai alleviivataan, jos\n' +
+  '  kyseess盲 on Alatunniste-elementin polun ensimm盲inen kohde.</p>\n' +
+  '\n' +
+  '<h1>K盲ytt枚liittym盲n eri osien v盲lill盲 navigointi</h1>\n' +
+  '\n' +
+  '<p>Paina <strong>sarkainn盲pp盲int盲</strong> siirty盲ksesi k盲ytt枚liittym盲n osasta seuraavaan.</p>\n' +
+  '\n' +
+  '<p>Jos haluat siirty盲 edelliseen k盲ytt枚liittym盲n osaan, paina <strong>Shift+sarkainn盲pp盲in</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Sarkainn盲pp盲in</strong> siirt盲盲 sinua n盲iss盲 k盲ytt枚liittym盲n osissa t盲ss盲 j盲rjestyksess盲:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Valikkopalkki</li>\n' +
+  '  <li>Ty枚kalupalkin ryhm盲t</li>\n' +
+  '  <li>Sivupalkki</li>\n' +
+  '  <li>Elementin polku alatunnisteessa</li>\n' +
+  '  <li>Sanalaskurin vaihtopainike alatunnisteessa</li>\n' +
+  '  <li>Br盲nd盲yslinkki alatunnisteessa</li>\n' +
+  '  <li>Editorin koon muuttamisen kahva alatunnisteessa</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Jos jotakin k盲ytt枚liittym盲n osaa ei ole, se ohitetaan.</p>\n' +
+  '\n' +
+  '<p>Jos kohdistus on siirretty alatunnisteeseen n盲pp盲imist枚navigoinnilla eik盲 sivupalkkia ole n盲kyviss盲, <strong>Shift+sarkainn盲pp盲in</strong>\n' +
+  '  siirt盲盲 kohdistuksen ty枚kalupalkin ensimm盲iseen ryhm盲盲n, eik盲 viimeiseen.</p>\n' +
+  '\n' +
+  '<h1>K盲ytt枚liittym盲n eri osien sis盲ll盲聽navigointi</h1>\n' +
+  '\n' +
+  '<p>Paina <strong>nuolin盲pp盲imi盲</strong> siirty盲ksesi k盲ytt枚liittym盲elementist盲 seuraavaan.</p>\n' +
+  '\n' +
+  '<p><strong>Vasen</strong>- ja <strong>Oikea</strong>-nuolin盲pp盲imet</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>siirt盲v盲t sinua valikkopalkin valikoiden v盲lill盲.</li>\n' +
+  '  <li>avaavat valikon alavalikon.</li>\n' +
+  '  <li>siirt盲v盲t sinua ty枚kalupalkin ryhm盲n painikkeiden v盲lill盲.</li>\n' +
+  '  <li>siirt盲v盲t sinua kohteiden v盲lill盲 alatunnisteen elementin polussa.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Alas</strong>- ja <strong>Yl枚s</strong>-nuolin盲pp盲imet</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>siirt盲v盲t sinua valikon valikkokohteiden v盲lill盲.</li>\n' +
+  '  <li>siirt盲v盲t sinua ty枚kalupalkin ponnahdusvalikon kohteiden v盲lill盲.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Nuolin盲pp盲imet</strong> siirt盲v盲t sinua k盲ytt枚liittym盲n korostetun osan sis盲ll盲 sykliss盲.</p>\n' +
+  '\n' +
+  '<p>Paina <strong>Esc</strong>-n盲pp盲int盲 sulkeaksesi avoimen valikon, avataksesi alavalikon tai avataksesi ponnahdusvalikon.</p>\n' +
+  '\n' +
+  '<p>Jos kohdistus on k盲ytt枚liittym盲n tietyn osion yl盲laidassa, <strong>Esc</strong>-n盲pp盲imen painaminen\n' +
+  '  poistuu my枚s n盲pp盲imist枚navigoinnista kokonaan.</p>\n' +
+  '\n' +
+  '<h1>Suorita valikkokohde tai ty枚kalupalkin painike</h1>\n' +
+  '\n' +
+  '<p>Kun haluamasi valikkokohde tai ty枚kalupalkin painike on korostettuna, paina <strong>Return</strong>-, <strong>Enter</strong>-\n' +
+  '  tai <strong>v盲lily枚ntin盲pp盲int盲</strong> suorittaaksesi kohteen.</p>\n' +
+  '\n' +
+  '<h1>V盲lilehditt枚miss盲 valintaikkunoissa navigointi</h1>\n' +
+  '\n' +
+  '<p>Kun v盲lilehdet枚n valintaikkuna avautuu, kohdistus siirtyy sen ensimm盲iseen interaktiiviseen komponenttiin.</p>\n' +
+  '\n' +
+  '<p>Voit siirty盲 valintaikkunan interaktiivisten komponenttien v盲lill盲 painamalla <strong>sarkainn盲pp盲int盲</strong> tai <strong>Shift+sarkainn盲pp盲in</strong>.</p>\n' +
+  '\n' +
+  '<h1>V盲lilehdellisiss盲 valintaikkunoissa navigointi</h1>\n' +
+  '\n' +
+  '<p>Kun v盲lilehdellinen valintaikkuna avautuu, kohdistus siirtyy v盲lilehtivalikon ensimm盲iseen painikkeeseen.</p>\n' +
+  '\n' +
+  '<p>Voit siirty盲 valintaikkunan v盲lilehden interaktiivisen komponenttien v盲lill盲 painamalla <strong>sarkainn盲pp盲int盲</strong> tai\n' +
+  '  <strong>Shift+sarkainn盲pp盲in</strong>.</p>\n' +
+  '\n' +
+  '<p>Voit siirty盲 valintaikkunan toiseen v盲lilehteen siirt盲m盲ll盲 kohdistuksen v盲lilehtivalikkoon ja painamalla sopivaa <strong>nuolin盲pp盲int盲</strong>\n' +
+  '  siirty盲ksesi k盲ytett盲viss盲 olevien v盲lilehtien v盲lill盲 sykliss盲.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js
new file mode 100644
index 0000000..3f611e8
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/fr_FR.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.fr_FR',
+'<h1>D茅buter la navigation au clavier</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Cibler la barre du menu</dt>\n' +
+  '  <dd>Windows ou Linux聽: Alt+F9</dd>\n' +
+  '  <dd>macOS聽: &#x2325;F9</dd>\n' +
+  "  <dt>Cibler la barre d'outils</dt>\n" +
+  '  <dd>Windows ou Linux聽: Alt+F10</dd>\n' +
+  '  <dd>macOS聽: &#x2325;F10</dd>\n' +
+  '  <dt>Cibler le pied de page</dt>\n' +
+  '  <dd>Windows ou Linux聽: Alt+F11</dd>\n' +
+  '  <dd>macOS聽: &#x2325;F11</dd>\n' +
+  '  <dt>Cibler la notification</dt>\n' +
+  '  <dd>Windows ou Linux : Alt+F12</dd>\n' +
+  '  <dd>macOS : &#x2325;F12</dd>\n' +
+  "  <dt>Cibler une barre d'outils contextuelle</dt>\n" +
+  '  <dd>Windows, Linux ou macOS聽: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  "<p>La navigation d茅butera sur le premier 茅l茅ment de l'interface utilisateur, qui sera mis en surbrillance ou bien soulign茅 dans le cas du premier 茅l茅ment du\n" +
+  "  chemin d'茅l茅ments du pied de page.</p>\n" +
+  '\n' +
+  "<h1>Naviguer entre les sections de l'interface utilisateur</h1>\n" +
+  '\n' +
+  "<p>Pour passer d'une section de l'interface utilisateur 脿 la suivante, appuyez sur <strong>Tabulation</strong>.</p>\n" +
+  '\n' +
+  "<p>Pour passer d'une section de l'interface utilisateur 脿 la pr茅c茅dente, appuyez sur <strong>Maj+Tabulation</strong>.</p>\n" +
+  '\n' +
+  "<p>L'ordre de <strong>Tabulation</strong> de ces sections de l'interface utilisateur est le suivant聽:</p>\n" +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barre du menu</li>\n' +
+  "  <li>Chaque groupe de barres d'outils</li>\n" +
+  '  <li>Barre lat茅rale</li>\n' +
+  "  <li>Chemin d'茅l茅ments du pied de page</li>\n" +
+  "  <li>Bouton d'activation du compteur de mots dans le pied de page</li>\n" +
+  '  <li>Lien de marque dans le pied de page</li>\n' +
+  "  <li>Poign茅e de redimensionnement de l'茅diteur dans le pied de page</li>\n" +
+  '</ol>\n' +
+  '\n' +
+  "<p>Si une section de l'interface utilisateur n'est pas pr茅sente, elle sera ignor茅e.</p>\n" +
+  '\n' +
+  "<p>Si le pied de page comporte un ciblage par navigation au clavier et qu'il n'y a aucune barre lat茅rale visible, appuyer sur <strong>Maj+Tabulation</strong>\n" +
+  "  d茅place le ciblage vers le premier groupe de barres d'outils et non le dernier.</p>\n" +
+  '\n' +
+  "<h1>Naviguer au sein des sections de l'interface utilisateur</h1>\n" +
+  '\n' +
+  "<p>Pour passer d'un 茅l茅ment de l'interface utilisateur au suivant, appuyez sur la <strong>Fl猫che</strong> appropri茅e.</p>\n" +
+  '\n' +
+  '<p>Les touches fl茅ch茅es <strong>Gauche</strong> et <strong>Droite</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>se d茅placent entre les menus de la barre des menus.</li>\n' +
+  "  <li>ouvrent un sous-menu au sein d'un menu.</li>\n" +
+  "  <li>se d茅placent entre les boutons d'un groupe de barres d'outils.</li>\n" +
+  "  <li>se d茅placent entre les 茅l茅ments du chemin d'茅l茅ments du pied de page.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  '<p>Les touches fl茅ch茅es <strong>Bas</strong> et <strong>Haut</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  "  <li>se d茅placent entre les 茅l茅ments de menu au sein d'un menu.</li>\n" +
+  "  <li>se d茅placent entre les 茅l茅ments au sein d'un menu contextuel de barre d'outils.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  "<p>Les <strong>Fl猫ches</strong> parcourent la section de l'interface utilisateur cibl茅e.</p>\n" +
+  '\n' +
+  '<p>Pour fermer un menu ouvert, un sous-menu ouvert ou un menu contextuel ouvert, appuyez sur <strong>Echap</strong>.</p>\n' +
+  '\n' +
+  "<p>Si l'actuel ciblage se trouve en 芦聽haut聽禄 d'une section sp茅cifique de l'interface utilisateur, appuyer sur <strong>Echap</strong> permet 茅galement de quitter\n" +
+  '  enti猫rement la navigation au clavier.</p>\n' +
+  '\n' +
+  "<h1>Ex茅cuter un 茅l茅ment de menu ou un bouton de barre d'outils</h1>\n" +
+  '\n' +
+  "<p>Lorsque l'茅l茅ment de menu ou le bouton de barre d'outils d茅sir茅 est mis en surbrillance, appuyez sur la touche <strong>Retour arri猫re</strong>, <strong>Entr茅e</strong>\n" +
+  "  ou la <strong>Barre d'espace</strong> pour ex茅cuter l'茅l茅ment.</p>\n" +
+  '\n' +
+  '<h1>Naviguer au sein de dialogues sans onglets</h1>\n' +
+  '\n' +
+  "<p>Dans les dialogues sans onglets, le premier composant interactif est cibl茅 lorsque le dialogue s'ouvre.</p>\n" +
+  '\n' +
+  '<p>Naviguez entre les composants du dialogue interactif en appuyant sur <strong>Tabulation</strong> ou <strong>Maj+Tabulation</strong>.</p>\n' +
+  '\n' +
+  '<h1>Naviguer au sein de dialogues avec onglets</h1>\n' +
+  '\n' +
+  "<p>Dans les dialogues avec onglets, le premier bouton du menu de l'onglet est cibl茅 lorsque le dialogue s'ouvre.</p>\n" +
+  '\n' +
+  '<p>Naviguez entre les composants interactifs de cet onglet de dialogue en appuyant sur <strong>Tabulation</strong> ou\n' +
+  '  <strong>Maj+Tabulation</strong>.</p>\n' +
+  '\n' +
+  "<p>Passez 脿 un autre onglet de dialogue en ciblant le menu de l'onglet et en appuyant sur la <strong>Fl猫che</strong>\n" +
+  '  appropri茅e pour parcourir les onglets disponibles.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js
new file mode 100644
index 0000000..7d6513a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/he_IL.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.he_IL',
+'<h1>讛转讞诇 谞讬讜讜讟 讘诪拽诇讚转</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>讛转诪拽讚 讘砖讜专转 讛转驻专讬讟讬诐</dt>\n' +
+  '  <dd>Windows 讗讜 Linux:鈥� Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>讛注讘专 诪讬拽讜讚 诇住专讙诇 讛讻诇讬诐</dt>\n' +
+  '  <dd>Windows 讗讜 Linux:鈥� Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>讛注讘专 诪讬拽讜讚 诇讻讜转专转 讛转讞转讜谞讛</dt>\n' +
+  '  <dd>Windows 讗讜 Linux:鈥� Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>讛注讘专 诪讬拽讜讚 诇讛讜讚注讛</dt>\n' +
+  '  <dd>Windows 讗讜 Linux:鈥� Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>讛注讘专 诪讬拽讜讚 诇住专讙诇 讻诇讬诐 讛拽砖专讬</dt>\n' +
+  '  <dd>Windows鈥�, Linux 讗讜 macOS:鈥� Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>讛谞讬讜讜讟 讬转讞讬诇 讘专讻讬讘 讛专讗砖讜谉 讘诪砖讱, 砖讬讜讚讙砖 讗讜 砖讬讛讬讛 诪转讞转讬讜 拽讜 转讞转讜谉 讘诪拽专讛 砖诇 讛驻专讬讟 讛专讗砖讜谉\n' +
+  '  讛谞转讬讘 砖诇 专讻讬讘 讛讻讜转专转 讛转讞转讜谞讛.</p>\n' +
+  '\n' +
+  '<h1>注讘讜专 讘讬谉 诪拽讟注讬诐 讘诪住讱</h1>\n' +
+  '\n' +
+  '<p>讻讚讬 诇注讘讜专 讘讬谉 讛诪拽讟注讬诐 讘诪住讱, 讛拽砖 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>讻讚讬 诇注讘讜专 诇诪拽讟注 讛拽讜讚诐 讘诪住讱, 讛拽砖 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>讛住讚专 诪讘讞讬谞转 诪拽砖 <strong>Tab</strong> 砖诇 讛专讻讬讘讬诐 讘诪住讱:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>砖讜专转 讛转驻专讬讟讬诐</li>\n' +
+  '  <li>讻诇 拽讘讜爪讛 讘住专讙诇 讛讻诇讬诐</li>\n' +
+  '  <li>讛住专讙诇 讛爪讬讚讬</li>\n' +
+  '  <li>谞转讬讘 砖诇 专讻讬讘 讘讻讜转专转 讛转讞转讜谞讛</li>\n' +
+  '  <li>诇讞爪谉 诇住驻讬专转 诪讬诇讬诐 讘讻讜转专转 讛转讞转讜谞讛</li>\n' +
+  '  <li>拽讬砖讜专 砖诇 讛诪讜转讙 讘讻讜转专转 讛转讞转讜谞讛</li>\n' +
+  '  <li>讬讚讬转 诇砖讬谞讜讬 讙讜讚诇 注讘讜专 讛注讜专讱 讘讻讜转专转 讛转讞转讜谞讛</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>讗诐 专讻讬讘 讻诇砖讛讜 讘诪住讱 诇讗 诪讜驻讬注, 讛诪注专讻转 转讚诇讙 注诇讬讜.</p>\n' +
+  '\n' +
+  '<p>讗诐 讘讻讜转专转 讛转讞转讜谞讛 讬砖 诪讬拽讜讚 砖诇 谞讬讜讜讟 讘诪拽诇讚转, 讜诇讗 诪讜驻讬注 住专讙诇 讘爪讚, 讬砖 诇讛拽讬砖 <strong>Shift+Tab</strong>\n' +
+  '  诪注讘讬专 讗转 讛诪讬拽讜讚 诇拽讘讜爪讛 讛专讗砖讜谞讛 讘住专讙诇 讛讻诇讬诐, 诇讗 讛讗讞专讜谞讛.</p>\n' +
+  '\n' +
+  '<h1>注讘讜专 讘转讜讱 诪拽讟注讬诐 讘诪住讱</h1>\n' +
+  '\n' +
+  '<p>讻讚讬 诇注讘讜专 诪专讻讬讘 讗讞讚 诇专讻讬讘 讗讞专 讘诪住讱, 讛拽砖 注诇 诪拽砖 <strong>讛讞抓</strong> 讛诪转讗讬诐.</p>\n' +
+  '\n' +
+  '<p>诪拽砖讬 讛讞讬爪讬诐 <strong>砖诪讗诇讛</strong> 讜<strong>讬诪讬谞讛</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>注讘讜专 讘讬谉 转驻专讬讟讬诐 讘砖讜专转 讛转驻专讬讟讬诐.</li>\n' +
+  '  <li>驻转讞 转驻专讬讟 诪砖谞讬 讘转驻专讬讟.</li>\n' +
+  '  <li>注讘讜专 讘讬谉 诇讞爪谞讬诐 讘拽讘讜爪讛 讘住专讙诇 讛讻诇讬诐.</li>\n' +
+  '  <li>注讘讜专 讘讬谉 驻专讬讟讬诐 讘专讻讬讘 讘讻讜转专转 讛转讞转讜谞讛.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>诪拽砖讬 讛讞讬爪讬诐 <strong>诇诪讟讛</strong> 讜<strong>诇诪注诇讛</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>注讘讜专 讘讬谉 驻专讬讟讬诐 讘转驻专讬讟.</li>\n' +
+  '  <li>注讘讜专 讘讬谉 驻专讬讟讬诐 讘讞诇讜谉 讛拽讜讘抓 砖诇 住专讙诇 讛讻诇讬诐.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>诪拽砖讬 <strong>讛讞爪讬诐</strong> 诪砖转谞讬诐 讘转讜讱 讛诪拽讟注 讘诪住讱 砖注诇讬讜 谞诪爪讗 讛诪讬拽讜讚.</p>\n' +
+  '\n' +
+  '<p>讻讚讬 诇住讙讜专 转驻专讬讟 驻转讜讞, 转驻专讬讟 诪砖谞讬 驻转讜讞 讗讜 讞诇讜谉 拽讜驻抓, 讛拽砖 注诇 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  "<p>讗诐 讛诪讬拽讜讚 讛讜讗 注诇 讛讞诇拽 '讛注诇讬讜谉' 砖诇 诪拽讟注 诪住讜讬诐 讘诪住讱, 讛拽砖讛 注诇 <strong>Esc</strong> 诪讘讬讗讛 讙诐 诇讬爪讬讗讛\n" +
+  '  诪讛谞讬讜讜讟 讘诪拽诇讚转 诇讞诇讜讟讬谉.</p>\n' +
+  '\n' +
+  '<h1>讛驻注诇 驻专讬讟 讘转驻专讬讟 讗讜 诇讞爪谉 讘住专讙诇 讛讻诇讬诐</h1>\n' +
+  '\n' +
+  '<p>讻讗砖专 讛驻专讬讟 讛专爪讜讬 讘转驻专讬讟 讗讜 讛诇讞爪谉 讘住专讙诇 讛讻诇讬诐 诪讜讚讙砖讬诐, 讛拽砖 注诇 <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  讗讜 注诇 <strong>诪拽砖 讛专讜讜讞</strong> 讻讚讬 诇讛驻注讬诇 讗转 讛驻专讬讟.</p>\n' +
+  '\n' +
+  '<h1>谞讬讜讜讟 讘讞诇讜谞讜转 讚讜-砖讬讞 讘诇讬 讻专讟讬住讬讜转</h1>\n' +
+  '\n' +
+  '<p>讘讞诇讜谞讜转 讚讜-砖讬讞 讘诇讬 讻专讟讬住讬讜转, 讛专讻讬讘 讛讗讬谞讟专讗拽讟讬讘讬 讛专讗砖讜谉 诪拽讘诇 讗转 讛诪讬拽讜讚 讻讗砖专 讛讞诇讜谉 谞驻转讞.</p>\n' +
+  '\n' +
+  '<p>注讘讜专 讘讬谉 专讻讬讘讬诐 讗讬谞讟专讗拽讟讬讘讬讬诐 讘讞诇讜谉 注诇 讬讚讬 讛拽砖讛 注诇 <strong>Tab</strong> 讗讜 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>谞讬讜讜讟 讘讞诇讜谞讜转 讚讜-砖讬讞 注诐 讻专讟讬住讬讜转</h1>\n' +
+  '\n' +
+  '<p>讘讞诇讜谞讜转 讚讜-砖讬讞 注诐 讻专讟讬住讬讜转, 讛诇讞爪谉 讛专讗砖讜谉 讘转驻专讬讟 诪拽讘诇 讗转 讛诪讬拽讜讚 讻讗砖专 讛讞诇讜谉 谞驻转讞.</p>\n' +
+  '\n' +
+  '<p>注讘讜专 讘讬谉 专讻讬讘讬诐 讗讬谞讟专讗拽讟讬讘讬讬诐 讘讞诇讜谉 注诇 讬讚讬 讛拽砖讛 注诇 <strong>Tab</strong> 讗讜\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>注讘讜专 诇讻专讟讬住讬讛 讗讞专转 讘讞诇讜谉 注诇 讬讚讬 讛注讘专转 讛诪讬拽讜讚 诇转驻专讬讟 讛讻专讟讬住讬讜转 讜讛拽砖讛 注诇 <strong>讛讞抓</strong>讛诪转讗讬诐\n' +
+  '  讻讚讬 诇注讘讜专 讘讬谉 讛讻专讟讬住讬讜转 讛讝诪讬谞讜转.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js
new file mode 100644
index 0000000..ef59a5c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hi.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.hi',
+'<h1>啶曕啶啶班啶� 啶ㄠ啶掂た啶椸啶多え 啶多啶班 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>啶啶ㄠ啶 啶ぞ啶� 啶ぐ 啶ぜ啷嬥啶� 啶曕ぐ啷囙</dt>\n' +
+  '  <dd>Windows 啶ぞ Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>啶熰啶侧が啶距ぐ 啶ぐ 啶ぜ啷嬥啶� 啶曕ぐ啷囙</dt>\n' +
+  '  <dd>Windows 啶ぞ Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>啶ぜ啷佮啶� 啶ぐ 啶ぜ啷嬥啶� 啶曕ぐ啷囙</dt>\n' +
+  '  <dd>Windows 啶ぞ Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>啶ㄠ啶熰た啶ぜ啶苦啷囙ざ啶� 啶ぜ啷嬥啶�</dt>\n' +
+  '  <dd>Windows 啶ぞ Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>啶啶班ぞ啶膏啶椸た啶� 啶熰啶侧が啶距ぐ 啶ぐ 啶ぜ啷嬥啶� 啶曕ぐ啷囙</dt>\n' +
+  '  <dd>Windows, Linux 啶ぞ macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>啶ㄠ啶掂た啶椸啶多え 啶す啶侧 UI 啶嗋啶熰ぎ 啶ぐ 啶多啶班 啶灌啶椸ぞ, 啶溹た啶膏 啶灌ぞ啶囙げ啶距啶� 啶曕た啶ぞ 啶溹ぞ啶忇啶� 啶ぞ 啶す啶侧 啶嗋啶熰ぎ 啶曕 啶ぞ啶げ啷� 啶啶� 啶ぜ啷佮啶� 啶むい啷嵿さ 啶ぅ 啶啶俓n' +
+  '  啶班啶栢ぞ啶傕啶苦い 啶曕た啶ぞ 啶溹ぞ啶忇啶距イ</p>\n' +
+  '\n' +
+  '<h1>UI 啶膏啶曕啶多え 啶曕 啶啶� 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<p>啶忇 UI 啶膏啶曕啶多え 啶膏 啶︵啶膏ぐ啷� 啶膏啶曕啶多え 啶啶� 啶溹ぞ啶ㄠ 啶曕 啶侧た啶�, <strong>Tab</strong> 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  '<p>啶忇 UI 啶膏啶曕啶多え 啶膏 啶た啶涏げ啷� 啶膏啶曕啶多え 啶啶� 啶溹ぞ啶ㄠ 啶曕 啶侧た啶�, <strong>Shift+Tab</strong> 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  '<p>啶囙え UI 啶膏啶曕啶多え 啶曕ぞ <strong>Tab</strong> 啶曕啶班ぎ 啶ㄠ啶氞 啶︵た啶ぞ 啶椸く啶� 啶灌:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>啶啶ㄠ啶 啶ぞ啶�</li>\n' +
+  '  <li>啶啶班い啷嵿く啷囙 啶熰啶侧が啶距ぐ 啶膏ぎ啷傕す</li>\n' +
+  '  <li>啶膏ぞ啶囙ぁ啶ぞ啶�</li>\n' +
+  '  <li>啶ぜ啷佮啶� 啶啶� 啶むい啷嵿さ 啶ぅ</li>\n' +
+  '  <li>啶ぜ啷佮啶� 啶啶� 啶多が啷嵿う 啶椸ぃ啶ㄠぞ 啶熰啶椸げ 啶啶�</li>\n' +
+  '  <li>啶ぜ啷佮啶� 啶啶� 啶啶班ぞ啶傕ぁ啶苦啶� 啶侧た啶傕</li>\n' +
+  '  <li>啶ぜ啷佮啶� 啶啶� 啶膏啶ぞ啶︵ 啶曕ぞ 啶嗋啶距ぐ 啶う啶侧え啷� 啶曕ぞ 啶灌啶傕ぁ啶�</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>啶呧啶� 啶曕啶� UI 啶膏啶曕啶多え 啶啶溹啶� 啶ㄠす啷�啶� 啶灌, 啶む 啶夃じ啷� 啶涏啶∴ぜ 啶︵た啶ぞ 啶溹ぞ啶むぞ 啶灌啷�</p>\n' +
+  '\n' +
+  '<p>啶呧啶� 啶ぜ啷佮啶� 啶啶� 啶曕啶啶班啶� 啶ㄠ啶掂た啶椸啶多え 啶ぜ啷嬥啶� 啶灌, 啶斷ぐ 啶曕啶� 啶︵た啶栢ぞ 啶︵啶ㄠ 啶掂ぞ啶侧ぞ 啶膏ぞ啶囙ぁ啶ぞ啶� 啶ㄠす啷�啶� 啶灌, 啶む <strong>Shift+Tab</strong> 啶︵が啶距え啷� 啶膏\n' +
+  '  啶ぜ啷嬥啶� 啶す啶侧 啶熰啶侧が啶距ぐ 啶膏ぎ啷傕す 啶ぐ 啶氞げ啶� 啶溹ぞ啶むぞ 啶灌, 啶た啶涏げ啷� 啶ぐ 啶ㄠす啷�啶傕イ</p>\n' +
+  '\n' +
+  '<h1>UI 啶膏啶曕啶多え 啶曕 啶啶むぐ 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<p>啶忇 UI 啶むい啷嵿さ 啶膏 啶︵啶膏ぐ啷� 啶啶� 啶溹ぞ啶ㄠ 啶曕 啶侧た啶� 啶夃お啶啶曕啶� <strong>啶愢ぐ啷�</strong> 啶曕啶傕啷� 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  '<p><strong>啶ぞ啶忇</strong> 啶斷ぐ <strong>啶︵ぞ啶忇</strong> 啶愢ぐ啷� 啶曕啶傕啶苦く啶距</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>啶啶ㄠ啶 啶ぞ啶� 啶啶� 啶啶ㄠ啶 啶曕 啶啶� 啶侧 啶溹ぞ啶む 啶灌啶傕イ</li>\n' +
+  '  <li>啶啶ㄠ啶 啶啶� 啶忇 啶膏が-啶啶ㄠ啶 啶栢啶侧啶傕イ</li>\n' +
+  '  <li>啶熰啶侧が啶距ぐ 啶膏ぎ啷傕す 啶啶� 啶啶ㄠ啶� 啶曕 啶啶� 啶侧 啶溹ぞ啶忇啷�</li>\n' +
+  '  <li>啶ぜ啷佮啶� 啶曕 啶むい啷嵿さ 啶ぅ 啶啶� 啶嗋啶熰ぎ 啶曕 啶啶� 啶侧 啶溹ぞ啶忇啷�</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>啶ㄠ啶氞</strong> 啶斷ぐ <strong>啶娻お啶�</strong> 啶愢ぐ啷� 啶曕啶傕啶苦く啶距</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>啶啶ㄠ啶 啶啶� 啶啶ㄠ啶 啶嗋啶熰ぎ 啶曕 啶啶� 啶侧 啶溹ぞ啶む 啶灌啶傕イ</li>\n' +
+  '  <li>啶熰啶侧が啶距ぐ 啶啶�-啶呧お 啶啶ㄠ啶 啶啶� 啶嗋啶熰ぎ 啶曕 啶啶� 啶侧 啶溹ぞ啶忇啷�</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>啶ぜ啷嬥啶� 啶掂ぞ啶侧 UI 啶膏啶曕啶多え 啶曕 啶啶むぐ <strong>啶愢ぐ啷�</strong> 啶曕啶傕啶苦く啶距 啶氞げ啶距い啷� 啶班す啶む 啶灌啶傕イ</p>\n' +
+  '\n' +
+  '<p>啶曕啶� 啶栢啶侧ぞ 啶啶ㄠ啶, 啶曕啶� 啶栢啶侧ぞ 啶膏が-啶啶ㄠ啶 啶ぞ 啶曕啶� 啶栢啶侧ぞ 啶啶�-啶呧お 啶啶ㄠ啶 啶啶� 啶曕ぐ啶ㄠ 啶曕 啶侧た啶� <strong>Esc</strong> 啶曕啶傕啷� 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  "<p>啶呧啶� 啶啶溹啶︵ぞ 啶ぜ啷嬥啶� 啶曕た啶膏 啶掂た啶多啶� UI 啶膏啶曕啶多え 啶曕 '啶多啶班啶�' 啶ぐ 啶灌, 啶む <strong>Esc</strong> 啶曕啶傕啷� 啶︵が啶距え啷� 啶膏 啶\n" +
+  '  啶曕啶啶班啶� 啶ㄠ啶掂た啶椸啶多え 啶啶班 啶むぐ啶� 啶膏 啶ぞ啶灌ぐ 啶灌 啶溹ぞ啶むぞ 啶灌啷�</p>\n' +
+  '\n' +
+  '<h1>啶啶ㄠ啶 啶嗋啶熰ぎ 啶ぞ 啶熰啶侧が啶距ぐ 啶啶� 啶ㄠた啶粪啶ぞ啶︵た啶� 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<p>啶溹が 啶掂ぞ啶傕啶苦い 啶啶ㄠ啶 啶嗋啶熰ぎ 啶ぞ 啶熰啶侧が啶距ぐ 啶啶� 啶灌ぞ啶囙げ啶距啶� 啶曕た啶ぞ 啶溹ぞ啶むぞ 啶灌, 啶む 啶嗋啶熰ぎ 啶曕 啶ㄠた啶粪啶ぞ啶︵た啶� 啶曕ぐ啶ㄠ 啶曕 啶侧た啶� <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  啶ぞ <strong>Space bar</strong> 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  '<h1>啶椸啶�-啶熰啶� 啶掂ぞ啶侧 啶∴ぞ啶げ啷夃 啶ぐ 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<p>啶椸啶�-啶熰啶� 啶掂ぞ啶侧 啶∴ぞ啶げ啷夃 啶啶�, 啶∴ぞ啶げ啷夃 啶栢啶侧え啷� 啶ぐ 啶す啶侧ぞ 啶囙啶熰ぐ啷堗啷嵿啶苦さ 啶樴啶� 啶ぜ啷嬥啶� 啶侧啶むぞ 啶灌啷�</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> or <strong>Shift+Tab</strong> 啶︵が啶距啶� 啶囙啶熰ぐ啷堗啷嵿啶苦さ 啶∴ぞ啶げ啷夃 啶樴啶曕啶� 啶曕 啶啶� 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啷囙啷�</p>\n' +
+  '\n' +
+  '<h1>啶熰啶� 啶曕た啶� 啶椸 啶∴ぞ啶げ啷夃 啶ぐ 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啷囙</h1>\n' +
+  '\n' +
+  '<p>啶熰啶� 啶曕た啶� 啶椸 啶∴ぞ啶げ啷夃 啶啶�, 啶∴ぞ啶げ啷夃 啶栢啶侧え啷� 啶ぐ 啶熰啶� 啶啶ㄠ啶 啶啶� 啶す啶侧ぞ 啶啶� 啶ぜ啷嬥啶� 啶侧啶むぞ 啶灌啷�</p>\n' +
+  '\n' +
+  '<p>啶囙じ 啶∴ぞ啶げ啷夃 啶熰啶� 啶曕 啶囙啶熰ぐ啷堗啷嵿啶苦さ 啶樴啶曕啶� 啶曕 啶啶� 啶ㄠ啶掂た啶椸啶� 啶曕ぐ啶ㄠ 啶曕 啶侧た啶� <strong>Tab</strong> 啶ぞ\n' +
+  '  <strong>Shift+Tab</strong> 啶︵が啶距啶傕イ</p>\n' +
+  '\n' +
+  '<p>啶熰啶� 啶啶ㄠ啶 啶曕 啶ぜ啷嬥啶� 啶︵啶曕ぐ 啶斷ぐ 啶た啶� 啶夃お啶侧が啷嵿ぇ 啶熰啶� 啶啶� 啶曕 啶啶� 啶溹ぞ啶ㄠ 啶曕 啶侧た啶� 啶夃お啶啶曕啶� <strong>啶愢ぐ啷�</strong>\n' +
+  '  啶曕啶傕啷� 啶︵が啶距啶� 啶︵啶膏ぐ啷� 啶∴ぞ啶げ啷夃 啶熰啶� 啶ぐ 啶膏啶掂た啶� 啶曕ぐ啷囙啷�</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hr.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hr.js
new file mode 100644
index 0000000..1bf35c5
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hr.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.hr',
+'<h1>Po膷etak navigacije na tipkovnici</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokusiranje trake izbornika</dt>\n' +
+  '  <dd>Windows ili Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokusiranje alatne trake</dt>\n' +
+  '  <dd>Windows ili Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokusiranje podno啪ja</dt>\n' +
+  '  <dd>Windows ili Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokusiranje obavijesti</dt>\n' +
+  '  <dd>Windows ili Linux: Alt + F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokusiranje kontekstne alatne trake</dt>\n' +
+  '  <dd>Windows, Linux ili macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigacija 膰e zapo膷eti kod prve stavke na korisni膷kom su膷elju, koja 膰e biti istaknuta ili podcrtana ako se radi o prvoj stavci u\n' +
+  '  putu elementa u podno啪ju.</p>\n' +
+  '\n' +
+  '<h1>Navigacija izme膽u dijelova korisni膷kog su膷elja</h1>\n' +
+  '\n' +
+  '<p>Za pomicanje s jednog dijela korisni膷kog su膷elja na drugi pritisnite <strong>tabulator</strong>.</p>\n' +
+  '\n' +
+  '<p>Za pomicanje s jednog dijela korisni膷kog su膷elja na prethodni pritisnite <strong>Shift + tabulator</strong>.</p>\n' +
+  '\n' +
+  '<p>Ovo je redoslijed pomicanja <strong>tabulatora</strong> po dijelovima korisni膷kog su膷elja:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Traka izbornika</li>\n' +
+  '  <li>Pojedina膷ne grupe na alatnoj traci</li>\n' +
+  '  <li>Bo膷na traka</li>\n' +
+  '  <li>Put elemenata u podno啪ju</li>\n' +
+  '  <li>Gumb za pomicanje po broju rije膷i u podno啪ju</li>\n' +
+  '  <li>Veza na brand u podno啪ju</li>\n' +
+  '  <li>Zna膷ajka za promjenu veli膷ine alata za ure膽ivanje u podno啪ju</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Ako neki dio korisni膷kog su膷elja nije naveden, on se preska膷e.</p>\n' +
+  '\n' +
+  '<p>Ako u podno啪ju postoji fokus za navigaciju na tipkovnici, a nema vidljive bo膷ne trake, pritiskom na <strong>Shift + tabulator</strong>\n' +
+  '  fokus se prebacuje na prvu skupinu na alatnoj traci, ne na zadnju.</p>\n' +
+  '\n' +
+  '<h1>Navigacija unutar dijelova korisni膷kog su膷elja</h1>\n' +
+  '\n' +
+  '<p>Za pomicanje s jednog elementa korisni膷kog su膷elja na drugi pritisnite tipku s odgovaraju膰om <strong>strelicom</strong>.</p>\n' +
+  '\n' +
+  '<p>Tipke s <strong>lijevom</strong> i <strong>desnom</strong> strelicom</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>slu啪e za pomicanje izme膽u izbornika na alatnoj traci.</li>\n' +
+  '  <li>otvaraju podizbornik unutar izbornika.</li>\n' +
+  '  <li>slu啪e za pomicanje izme膽u gumba unutar skupina na alatnoj traci.</li>\n' +
+  '  <li>slu啪e za pomicanje izme膽u stavki na elementu puta u podno啪ju.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tipke s <strong>donjom</strong> i <strong>gornjom</strong> strelicom</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>slu啪e za pomicanje izme膽u stavki unutar izbornika.</li>\n' +
+  '  <li>slu啪e za pomicanje izme膽u stavki na alatnoj traci sko膷nog izbornika.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tipkama <strong>strelica</strong> kru啪no se pomi膷ete unutar dijela korisni膷kog su膷elja koji je u fokusu.</p>\n' +
+  '\n' +
+  '<p>Za zatvaranje otvorenog izbornika, otvorenog podizbornika ili otvorenog sko膷nog izbornika pritisnite tipku <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Ako je fokus trenuta膷no postavljen na vrh pojedina膷nog dijela korisni膷kog su膷elja, pritiskom na tipku <strong>Esc</strong> tako膽er\n' +
+  '  u potpunosti zatvarate navigaciju na tipkovnici.</p>\n' +
+  '\n' +
+  '<h1>Izvr拧avanje radnji putem stavki izbornika ili gumba na alatnoj traci</h1>\n' +
+  '\n' +
+  '<p>Nakon 拧to se istakne stavka izbornika ili gumb na alatnoj traci s radnjom koju 啪elite izvr拧iti, pritisnite tipku <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  ili <strong>razmak</strong> da biste pokrenuli 啪eljenu radnju.</p>\n' +
+  '\n' +
+  '<h1>Navigacija dijalo拧kim okvirima izvan kartica</h1>\n' +
+  '\n' +
+  '<p>Prilikom otvaranja dijalo拧kih okvira izvan kartica fokus se nalazi na prvoj interaktivnoj komponenti.</p>\n' +
+  '\n' +
+  '<p>Navigaciju izme膽u interaktivnih dijalo拧kih komponenata vr拧ite pritiskom na <strong>tabulator</strong> ili <strong>Shift + tabulator</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigacija dijalo拧kim okvirima u karticama</h1>\n' +
+  '\n' +
+  '<p>Prilikom otvaranja dijalo拧kih okvira u karticama fokus se nalazi na prvom gumbu u izborniku unutar kartice.</p>\n' +
+  '\n' +
+  '<p>Navigaciju izme膽u interaktivnih komponenata dijalo拧kog okvira u kartici vr拧ite pritiskom na <strong>tabulator</strong> ili\n' +
+  '  <strong>Shift + tabulator</strong>.</p>\n' +
+  '\n' +
+  '<p>Na karticu s drugim dijalo拧kim okvirom mo啪ete se prebaciti tako da stavite fokus na izbornik kartice pa pritisnete tipku s odgovaraju膰om <strong>strelicom</strong>\n' +
+  '  za kru啪no pomicanje izme膽u dostupnih kartica.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hu_HU.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hu_HU.js
new file mode 100644
index 0000000..5c984bb
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/hu_HU.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.hu_HU',
+'<h1>Billenty疟zetes navig谩ci贸 ind铆t谩sa</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>F贸kusz a men眉s谩vra</dt>\n' +
+  '  <dd>Windows 茅s Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>F贸kusz az eszk枚zt谩rra</dt>\n' +
+  '  <dd>Windows 茅s Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>F贸kusz a l谩bl茅cre</dt>\n' +
+  '  <dd>Windows 茅s Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>R谩k枚zel铆t茅s az 茅rtes铆t茅sre</dt>\n' +
+  '  <dd>Windows vagy Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>F贸kusz egy k枚rnyezetf眉gg艖 eszk枚zt谩rra</dt>\n' +
+  '  <dd>Windows, Linux 茅s macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>A navig谩ci贸 az els艖 felhaszn谩l贸i fel眉leti elemn茅l kezd艖dik, amelyet a rendszer kiemel, illetve al谩h煤z, amennyiben az az els艖 elem\n' +
+  '  a l谩bl茅c elem煤tvonal谩n.</p>\n' +
+  '\n' +
+  '<h1>Navig谩l谩s a felhaszn谩l贸i fel眉let szakaszai k枚z枚tt</h1>\n' +
+  '\n' +
+  '<p>A felhaszn谩l贸i fel眉let k枚vetkez艖 szakasz谩ra v谩lt谩shoz nyomja meg a <strong>Tab</strong> billenty疟t.</p>\n' +
+  '\n' +
+  '<p>A felhaszn谩l贸i fel眉let el艖z艖 szakasz谩ra v谩lt谩shoz nyomja meg a <strong>Shift+Tab</strong> billenty疟t.</p>\n' +
+  '\n' +
+  '<p>A <strong>Tab</strong> billenty疟vel a felhaszn谩l贸i fel眉let szakaszai k枚z枚tt a k枚vetkez艖 sorrendben v谩lt:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Men眉s谩v</li>\n' +
+  '  <li>Az egyes eszk枚zt谩rcsoportok</li>\n' +
+  '  <li>Oldals谩v</li>\n' +
+  '  <li>Elem煤tvonal a l谩bl茅cen</li>\n' +
+  '  <li>Sz贸sz谩m谩tkapcsol贸 gomb a l谩bl茅cen</li>\n' +
+  '  <li>M谩rkalink a l谩bl茅cen</li>\n' +
+  '  <li>Szerkeszt艖 谩tm茅retez茅si fog贸pontja a l谩bl茅cen</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Ha a felhaszn谩l贸i fel眉let valamelyik eleme nincs jelen, a rendszer kihagyja.</p>\n' +
+  '\n' +
+  '<p>Ha a billenty疟zetes navig谩ci贸 f贸kusza a l谩bl茅cen van, 茅s nincs l谩that贸 oldals谩v, a <strong>Shift+Tab</strong>\n' +
+  '  billenty疟kombin谩ci贸 lenyom谩sakor az els艖 eszk枚zt谩rcsoportra ugrik a f贸kusz, nem az utols贸ra.</p>\n' +
+  '\n' +
+  '<h1>Navig谩l谩s a felhaszn谩l贸i fel眉let szakaszain bel眉l</h1>\n' +
+  '\n' +
+  '<p>A felhaszn谩l贸i fel眉let k枚vetkez艖 elem茅re v谩lt谩shoz nyomja meg a megfelel艖 <strong>ny铆lbillenty疟t</strong>.</p>\n' +
+  '\n' +
+  '<p>A <strong>bal</strong> 茅s a <strong>jobb</strong> ny铆lgomb</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>a men眉s谩vban a men眉k k枚z枚tt v谩lt.</li>\n' +
+  '  <li>a men眉kben megnyit egy almen眉t.</li>\n' +
+  '  <li>az eszk枚zt谩rcsoportban a gombok k枚z枚tt v谩lt.</li>\n' +
+  '  <li>a l谩bl茅c elem煤tvonal谩n az elemek k枚z枚tt v谩lt.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>A <strong>le</strong> 茅s a <strong>fel</strong> ny铆lgomb</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>a men眉kben a men眉pontok k枚z枚tt v谩lt.</li>\n' +
+  '  <li>az eszk枚zt谩r el艖ugr贸 men眉j茅ben az elemek k枚z枚tt v谩lt.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>A <strong>ny铆lbillenty疟k</strong> lenyom谩s谩val k枚rk枚r枚sen l茅pkedhet a f贸kuszban l茅v艖 felhaszn谩l贸i fel眉leti szakasz elemei k枚z枚tt.</p>\n' +
+  '\n' +
+  '<p>A megnyitott men眉ket, almen眉ket 茅s el艖ugr贸 men眉ket az <strong>Esc</strong> billenty疟vel z谩rhatja be.</p>\n' +
+  '\n' +
+  '<p>Ha a f贸kusz az aktu谩lis fel眉leti elem 鈥瀎els艖鈥� r茅sz茅n van, az <strong>Esc</strong> billenty疟vel az eg茅sz\n' +
+  '  billenty疟zetes navig谩ci贸b贸l kil茅p.</p>\n' +
+  '\n' +
+  '<h1>Men眉pont vagy eszk枚zt谩rgomb aktiv谩l谩sa</h1>\n' +
+  '\n' +
+  '<p>Amikor a k铆v谩nt men眉elem vagy eszk枚zt谩rgomb van kijel枚lve, nyomja meg a <strong>Return</strong>, az <strong>Enter</strong>\n' +
+  '  vagy a <strong>Sz贸k枚z</strong> billenty疟t az adott elem vagy gomb aktiv谩l谩s谩hoz.</p>\n' +
+  '\n' +
+  '<h1>Navig谩l谩s a lapokkal nem rendelkez艖 p谩rbesz茅dablakokban</h1>\n' +
+  '\n' +
+  '<p>A lapokkal nem rendelkez艖 p谩rbesz茅dablakokban az els艖 interakt铆v 枚sszetev艖 kapja a f贸kuszt, amikor a p谩rbesz茅dpanel megny铆lik.</p>\n' +
+  '\n' +
+  '<p>A p谩rbesz茅dpanelek interakt铆v 枚sszetev艖i k枚z枚tt a <strong>Tab</strong> vagy a <strong>Shift+Tab</strong> billenty疟vel navig谩lhat.</p>\n' +
+  '\n' +
+  '<h1>Navig谩l谩s a lapokkal rendelkez艖 p谩rbesz茅dablakokban</h1>\n' +
+  '\n' +
+  '<p>A lapokkal rendelkez艖 p谩rbesz茅dablakokban a lapmen眉 els艖 gombja kapja a f贸kuszt, amikor a p谩rbesz茅dpanel megny铆lik.</p>\n' +
+  '\n' +
+  '<p>A p谩rbesz茅dpanel e lapj谩nak interakt铆v 枚sszetev艖i k枚z枚tt a <strong>Tab</strong> vagy\n' +
+  '  <strong>Shift+Tab</strong> billenty疟vel navig谩lhat.</p>\n' +
+  '\n' +
+  '<p>A p谩rbesz茅dablak m谩sik lapj谩ra 煤gy l茅phet, hogy a f贸kuszt a lapmen眉re 谩ll铆tja, majd lenyomja a megfelel艖 <strong>ny铆lbillenty疟t</strong>\n' +
+  '  a rendelkez茅sre 谩ll贸 lapok k枚z枚tti l茅pked茅shez.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/id.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/id.js
new file mode 100644
index 0000000..d607dd1
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/id.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.id',
+'<h1>Memulai navigasi keyboard</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokus pada bilah Menu</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokus pada Bilah Alat</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokus pada footer</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuskan pemberitahuan</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokus pada bilah alat kontekstual</dt>\n' +
+  '  <dd>Windows, Linux, atau macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigasi akan dimulai dari item pertama UI, yang akan disorot atau digarisbawahi di\n' +
+  '  alur elemen Footer.</p>\n' +
+  '\n' +
+  '<h1>Berpindah antar-bagian UI</h1>\n' +
+  '\n' +
+  '<p>Untuk berpindah dari satu bagian UI ke bagian berikutnya, tekan <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Untuk berpindah dari satu bagian UI ke bagian sebelumnya, tekan <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Urutan <strong>Tab</strong> bagian-bagian UI ini adalah:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Bilah menu</li>\n' +
+  '  <li>Tiap grup bilah alat</li>\n' +
+  '  <li>Bilah sisi</li>\n' +
+  '  <li>Alur elemen di footer</li>\n' +
+  '  <li>Tombol aktifkan/nonaktifkan jumlah kata di footer</li>\n' +
+  '  <li>Tautan merek di footer</li>\n' +
+  '  <li>Pengatur pengubahan ukuran editor di footer</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Jika suatu bagian UI tidak ada, bagian tersebut dilewati.</p>\n' +
+  '\n' +
+  '<p>Jika fokus navigasi keyboard ada pada footer, tetapi tidak ada bilah sisi yang terlihat, menekan <strong>Shift+Tab</strong>\n' +
+  '  akan memindahkan fokus ke grup bilah alat pertama, bukan yang terakhir.</p>\n' +
+  '\n' +
+  '<h1>Berpindah di dalam bagian-bagian UI</h1>\n' +
+  '\n' +
+  '<p>Untuk berpindah dari satu elemen UI ke elemen berikutnya, tekan tombol <strong>Panah</strong> yang sesuai.</p>\n' +
+  '\n' +
+  '<p>Tombol panah <strong>Kiri</strong> dan <strong>Kanan</strong> untuk</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>berpindah-pindah antar-menu di dalam bilah menu.</li>\n' +
+  '  <li>membuka sub-menu di dalam menu.</li>\n' +
+  '  <li>berpindah-pindah antar-tombol di dalam grup bilah alat.</li>\n' +
+  '  <li>berpindah-pindah antar-item di dalam alur elemen footer.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tombol panah <strong>Bawah</strong> dan <strong>Atas</strong> untuk</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>berpindah-pindah antar-item menu di dalam menu.</li>\n' +
+  '  <li>berpindah-pindah antar-item di dalam menu pop-up bilah alat.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tombol <strong>Panah</strong> hanya bergerak di dalam bagian UI yang difokuskan.</p>\n' +
+  '\n' +
+  '<p>Untuk menutup menu, sub-menu, atau menu pop-up yang terbuka, tekan tombol <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Jika fokus sedang berada di 鈥榓tas鈥� bagian UI tertentu, menekan tombol <strong>Esc</strong> juga dapat mengeluarkan fokus\n' +
+  '  dari seluruh navigasi keyboard.</p>\n' +
+  '\n' +
+  '<h1>Menjalankan item menu atau tombol bilah alat</h1>\n' +
+  '\n' +
+  '<p>Jika item menu atau tombol bilah alat yang diinginkan tersorot, tekan <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  atau <strong>Spasi</strong> untuk menjalankan item.</p>\n' +
+  '\n' +
+  '<h1>Berpindah dalam dialog tanpa tab</h1>\n' +
+  '\n' +
+  '<p>Dalam dialog tanpa tab, fokus diarahkan pada komponen interaktif pertama saat dialog terbuka.</p>\n' +
+  '\n' +
+  '<p>Berpindah di antara komponen dalam dialog interaktif dengan menekan <strong>Tab</strong> atau <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Berpindah dalam dialog dengan tab</h1>\n' +
+  '\n' +
+  '<p>Dalam dialog yang memiliki tab, fokus diarahkan pada tombol pertama di dalam menu saat dialog terbuka.</p>\n' +
+  '\n' +
+  '<p>Berpindah di antara komponen-komponen interaktif pada tab dialog ini dengan menekan <strong>Tab</strong> atau\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Beralih ke tab dialog lain dengan mengarahkan fokus pada menu tab lalu tekan tombol <strong>Panah</strong>\n' +
+  '  yang sesuai untuk berpindah ke berbagai tab yang tersedia.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/it.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/it.js
new file mode 100644
index 0000000..3a791c9
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/it.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.it',
+'<h1>Iniziare la navigazione tramite tastiera</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Impostare lo stato attivo per la barra dei menu</dt>\n' +
+  '  <dd>Windows o Linux: ALT+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Impostare lo stato attivo per la barra degli strumenti</dt>\n' +
+  '  <dd>Windows o Linux: ALT+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Impostare lo stato attivo per il pi猫 di pagina</dt>\n' +
+  '  <dd>Windows o Linux: ALT+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Metti a fuoco la notifica</dt>\n' +
+  '  <dd>Windows o Linux: ALT+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Impostare lo stato attivo per la barra degli strumenti contestuale</dt>\n' +
+  '  <dd>Windows, Linux o macOS: CTRL+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  "<p>La navigazione inizier脿 dalla prima voce dell'interfaccia utente, che sar脿 evidenziata o sottolineata nel caso della prima voce\n" +
+  "  nel percorso dell'elemento del pi猫 di pagina.</p>\n" +
+  '\n' +
+  "<h1>Navigare tra le sezioni dell'interfaccia utente</h1>\n" +
+  '\n' +
+  "<p>Per passare da una sezione dell'interfaccia utente alla successiva, premere <strong>TAB</strong>.</p>\n" +
+  '\n' +
+  "<p>Per passare da una sezione dell'interfaccia utente alla precedente, premere <strong>MAIUSC+TAB</strong>.</p>\n" +
+  '\n' +
+  "<p>L'ordine di <strong>tabulazione</strong> di queste sezioni dell'interfaccia utente 猫:</p>\n" +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra dei menu</li>\n' +
+  '  <li>Ogni gruppo di barre degli strumenti</li>\n' +
+  '  <li>Barra laterale</li>\n' +
+  "  <li>Percorso dell'elemento nel pi猫 di pagina</li>\n" +
+  '  <li>Pulsante di attivazione/disattivazione del conteggio delle parole nel pi猫 di pagina</li>\n' +
+  '  <li>Collegamento al marchio nel pi猫 di pagina</li>\n' +
+  "  <li>Quadratino di ridimensionamento dell'editor nel pi猫 di pagina</li>\n" +
+  '</ol>\n' +
+  '\n' +
+  "<p>Se una sezione dell'interfaccia utente non 猫 presente, viene saltata.</p>\n" +
+  '\n' +
+  '<p>Se il pi猫 di pagina ha lo stato attivo per la navigazione tramite tastiera e non 猫 presente alcuna barra laterale visibile, premendo <strong>MAIUSC+TAB</strong>\n' +
+  "  si sposta lo stato attivo sul primo gruppo di barre degli strumenti, non sull'ultimo.</p>\n" +
+  '\n' +
+  "<h1>Navigare all'interno delle sezioni dell'interfaccia utente</h1>\n" +
+  '\n' +
+  "<p>Per passare da un elemento dell'interfaccia utente al successivo, premere il tasto <strong>freccia</strong> appropriato.</p>\n" +
+  '\n' +
+  '<p>I tasti freccia <strong>Sinistra</strong> e <strong>Destra</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>consentono di spostarsi tra i menu della barra dei menu.</li>\n' +
+  '  <li>aprono un sottomenu in un menu.</li>\n' +
+  '  <li>consentono di spostarsi tra i pulsanti di un gruppo di barre degli strumenti.</li>\n' +
+  "  <li>consentono di spostarsi tra le voci nel percorso dell'elemento del pi猫 di pagina.</li>\n" +
+  '</ul>\n' +
+  '\n' +
+  '<p>I tasti freccia <strong>Gi霉</strong> e <strong>Su</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>consentono di spostarsi tra le voci di un menu.</li>\n' +
+  '  <li>consentono di spostarsi tra le voci di un menu a comparsa della barra degli strumenti.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  "<p>I tasti <strong>freccia</strong> consentono di spostarsi all'interno della sezione dell'interfaccia utente con stato attivo.</p>\n" +
+  '\n' +
+  '<p>Per chiudere un menu aperto, un sottomenu aperto o un menu a comparsa aperto, premere il tasto <strong>ESC</strong>.</p>\n' +
+  '\n' +
+  "<p>Se lo stato attivo corrente si trova nella parte superiore di una particolare sezione dell'interfaccia utente, premendo il tasto <strong>ESC</strong> si esce\n" +
+  '  completamente dalla navigazione tramite tastiera.</p>\n' +
+  '\n' +
+  '<h1>Eseguire una voce di menu o un pulsante della barra degli strumenti</h1>\n' +
+  '\n' +
+  '<p>Quando la voce di menu o il pulsante della barra degli strumenti desiderati sono evidenziati, premere il tasto di<strong>ritorno a capo</strong>, il tasto <strong>Invio</strong>\n' +
+  '  o la <strong>barra spaziatrice</strong> per eseguirli.</p>\n' +
+  '\n' +
+  '<h1>Navigare nelle finestre di dialogo non a schede</h1>\n' +
+  '\n' +
+  "<p>Nelle finestre di dialogo non a schede, all'apertura della finestra di dialogo diventa attivo il primo componente interattivo.</p>\n" +
+  '\n' +
+  '<p>Per spostarsi tra i componenti interattivi della finestra di dialogo, premere <strong>TAB</strong> o <strong>MAIUSC+TAB</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigare nelle finestre di dialogo a schede</h1>\n' +
+  '\n' +
+  "<p>Nelle finestre di dialogo a schede, all'apertura della finestra di dialogo diventa attivo il primo pulsante del menu della scheda.</p>\n" +
+  '\n' +
+  '<p>Per spostarsi tra i componenti interattivi di questa scheda della finestra di dialogo, premere <strong>TAB</strong> o\n' +
+  '  <strong>MAIUSC+TAB</strong>.</p>\n' +
+  '\n' +
+  "<p>Per passare a un'altra scheda della finestra di dialogo, attivare il menu della scheda e premere il tasto <strong>freccia</strong>\n" +
+  '  appropriato per scorrere le schede disponibili.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ja.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ja.js
new file mode 100644
index 0000000..26872db
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ja.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ja',
+'<h1>銈兗銉溿兗銉� 銉娿儞銈层兗銈枫儳銉炽伄闁嬪</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>銉°儖銉ャ兗 銉愩兗銈掋儠銈┿兗銈偣</dt>\n' +
+  '  <dd>Windows 銇俱仧銇� Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>銉勩兗銉� 銉愩兗銈掋儠銈┿兗銈偣</dt>\n' +
+  '  <dd>Windows 銇俱仧銇� Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>銉曘儍銈裤兗銈掋儠銈┿兗銈偣</dt>\n' +
+  '  <dd>Windows 銇俱仧銇� Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>閫氱煡銇儠銈┿兗銈偣</dt>\n' +
+  '  <dd>Windows 銇俱仧銇� Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>銈炽兂銉嗐偔銈广儓 銉勩兗銉� 銉愩兗銈掋儠銈┿兗銈偣</dt>\n' +
+  '  <dd>Windows銆丩inux 銇俱仧銇� macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>銉娿儞銈层兗銈枫儳銉炽伅鏈�鍒濄伄 UI 闋呯洰銇嬨倝闁嬪銇曘倢銆佸挤瑾胯〃绀恒仌銈屻倠銇嬨�併儠銉冦偪銉笺伄瑕佺礌銉戙偣銇亗銈嬫渶鍒濄伄闋呯洰銇牬鍚堛伅\n' +
+  '  涓嬬窔銇屽紩銇嬨倢銇俱仚銆�</p>\n' +
+  '\n' +
+  '<h1>UI 銈汇偗銈枫儳銉抽枔銇Щ鍕�</h1>\n' +
+  '\n' +
+  '<p>娆°伄 UI 銈汇偗銈枫儳銉炽伀绉诲嫊銇欍倠銇伅銆�<strong>Tab</strong> 銈掓娂銇椼伨銇欍��</p>\n' +
+  '\n' +
+  '<p>鍓嶃伄 UI 銈汇偗銈枫儳銉炽伀绉诲嫊銇欍倠銇伅銆�<strong>Shift+Tab</strong> 銈掓娂銇椼伨銇欍��</p>\n' +
+  '\n' +
+  '<p>銇撱倢銈夈伄 UI 銈汇偗銈枫儳銉炽伄 <strong>Tab</strong> 銇爢搴�:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>銉°儖銉ャ兗 銉愩兗</li>\n' +
+  '  <li>鍚勩儎銉笺儷 銉愩兗 銈般儷銉笺儣</li>\n' +
+  '  <li>銈点偆銉� 銉愩兗</li>\n' +
+  '  <li>銉曘儍銈裤兗銇绱犮儜銈�</li>\n' +
+  '  <li>銉曘儍銈裤兗銇崢瑾炴暟鍒囥倞鏇裤亪銉溿偪銉�</li>\n' +
+  '  <li>銉曘儍銈裤兗銇儢銉┿兂銉� 銉兂銈�</li>\n' +
+  '  <li>銉曘儍銈裤兗銇偍銉囥偅銈裤兗 銈点偆銈哄鏇淬儚銉炽儔銉�</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>UI 銈汇偗銈枫儳銉炽亴瀛樺湪銇椼仾銇勫牬鍚堛伅銆併偣銈儍銉椼仌銈屻伨銇欍��</p>\n' +
+  '\n' +
+  '<p>銉曘儍銈裤兗銇偔銉笺儨銉笺儔 銉娿儞銈层兗銈枫儳銉� 銉曘偐銉笺偒銈广亴銇傘倞銆佽〃绀哄彲鑳姐仾銈点偆銉� 銉愩兗銇屻仾銇勫牬鍚堛��<strong>Shift+Tab</strong> 銈掓娂銇欍仺銆乗n' +
+  '  銉曘偐銉笺偒銈广亴鏈�寰屻仹銇仾銇忔渶鍒濄伄銉勩兗銉� 銉愩兗 銈般儷銉笺儣銇Щ鍕曘仐銇俱仚銆�</p>\n' +
+  '\n' +
+  '<h1>UI 銈汇偗銈枫儳銉冲唴銇Щ鍕�</h1>\n' +
+  '\n' +
+  '<p>娆°伄 UI 瑕佺礌銇Щ鍕曘仚銈嬨伀銇�侀仼鍒囥仾<strong>鐭㈠嵃</strong>銈兗銈掓娂銇椼伨銇欍��</p>\n' +
+  '\n' +
+  '<p><strong>宸︾煝鍗�</strong>銇�<strong>鍙崇煝鍗�</strong>銇偔銉�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>銉°儖銉ャ兗 銉愩兗銇儭銉嬨儱銉奸枔銇хЩ鍕曘仐銇俱仚銆�</li>\n' +
+  '  <li>銉°儖銉ャ兗鍐呫伄銈点儢銉°儖銉ャ兗銈掗枊銇嶃伨銇欍��</li>\n' +
+  '  <li>銉勩兗銉� 銉愩兗 銈般儷銉笺儣銇儨銈裤兂闁撱仹绉诲嫊銇椼伨銇欍��</li>\n' +
+  '  <li>銉曘儍銈裤兗銇绱犮儜銈广伄闋呯洰闁撱仹绉诲嫊銇椼伨銇欍��</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>涓嬬煝鍗�</strong>銇�<strong>涓婄煝鍗�</strong>銇偔銉�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>銉°儖銉ャ兗鍐呫伄銉°儖銉ャ兗闋呯洰闁撱仹绉诲嫊銇椼伨銇欍��</li>\n' +
+  '  <li>銉勩兗銉� 銉愩兗 銉濄儍銉椼偄銉冦儣 銉°儖銉ャ兗鍐呫伄銉°儖銉ャ兗闋呯洰闁撱仹绉诲嫊銇椼伨銇欍��</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>鐭㈠嵃</strong>銈兗銇с�併儠銈┿兗銈偣銇曘倢銇� UI 銈汇偗銈枫儳銉冲唴銇у惊鐠般仐銇俱仚銆�</p>\n' +
+  '\n' +
+  '<p>闁嬨亜銇熴儭銉嬨儱銉笺�侀枊銇勩仧銈点儢銉°儖銉ャ兗銆侀枊銇勩仧銉濄儍銉椼偄銉冦儣 銉°儖銉ャ兗銈掗枆銇樸倠銇伅銆�<strong>Esc</strong> 銈兗銈掓娂銇椼伨銇欍��</p>\n' +
+  '\n' +
+  '<p>鐝惧湪銇儠銈┿兗銈偣銇岀壒瀹氥伄 UI 銈汇偗銈枫儳銉炽伄銆屼竴鐣笂銆嶃伀銇傘倠鍫村悎銆�<strong>Esc</strong> 銈兗銈掓娂銇欍仺\n' +
+  '  銈兗銉溿兗銉� 銉娿儞銈层兗銈枫儳銉炽倐瀹屽叏銇枆銇樸倝銈屻伨銇欍��</p>\n' +
+  '\n' +
+  '<h1>銉°儖銉ャ兗闋呯洰銇俱仧銇儎銉笺儷 銉愩兗 銉溿偪銉炽伄瀹熻</h1>\n' +
+  '\n' +
+  '<p>鐩殑銇儭銉嬨儱銉奸爡鐩倓銉勩兗銉� 銉愩兗 銉溿偪銉炽亴寮疯琛ㄧず銇曘倢銇︺亜銈嬪牬鍚堛��<strong>銉偪銉笺兂</strong>銆�<strong>Enter</strong>銆乗n' +
+  '  銇俱仧銇�<strong>銈广儦銉笺偣 銈兗</strong>銈掓娂銇椼仸闋呯洰銈掑疅琛屻仐銇俱仚銆�</p>\n' +
+  '\n' +
+  '<h1>銈裤儢銇仾銇勩儉銈ゃ偄銉偘銇Щ鍕�</h1>\n' +
+  '\n' +
+  '<p>銈裤儢銇仾銇勩儉銈ゃ偄銉偘銇с伅銆併儉銈ゃ偄銉偘銇岄枊銇忋仺鏈�鍒濄伄瀵捐┍鍨嬨偝銉炽儩銉笺儘銉炽儓銇屻儠銈┿兗銈偣銇曘倢銇俱仚銆�</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> 銇俱仧銇� <strong>Shift+Tab</strong> 銈掓娂銇椼仸銆佸瑭卞瀷銉�銈ゃ偄銉偘 銈炽兂銉濄兗銉嶃兂銉堥枔銇хЩ鍕曘仐銇俱仚銆�</p>\n' +
+  '\n' +
+  '<h1>銈裤儢浠樸亶銉�銈ゃ偄銉偘銇Щ鍕�</h1>\n' +
+  '\n' +
+  '<p>銈裤儢浠樸亶銉�銈ゃ偄銉偘銇с伅銆併儉銈ゃ偄銉偘銇岄枊銇忋仺銈裤儢 銉°儖銉ャ兗銇渶鍒濄伄銉溿偪銉炽亴銉曘偐銉笺偒銈广仌銈屻伨銇欍��</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> 銇俱仧銇痋n' +
+  '  <strong>Shift+Tab</strong> 銈掓娂銇椼仸銆併亾銇儉銈ゃ偄銉偘 銈裤儢銇瑭卞瀷銈炽兂銉濄兗銉嶃兂銉堥枔銇хЩ鍕曘仐銇俱仚銆�</p>\n' +
+  '\n' +
+  '<p>銈裤儢 銉°儖銉ャ兗銈掋儠銈┿兗銈偣銇椼仸銇嬨倝閬╁垏銇�<strong>鐭㈠嵃</strong>銈兗銈掓娂銇椼仸琛ㄧず鍙兘銇偪銉栥倰寰挵銇椼仸銆乗n' +
+  '  鍒ャ伄銉�銈ゃ偄銉偘銇垏銈婃浛銇堛伨銇欍��</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/kk.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/kk.js
new file mode 100644
index 0000000..e31532f
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/kk.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.kk',
+'<h1>袩械褉薪械褌邪覜褌邪 薪邪胁懈谐邪褑懈褟褋褘薪 斜邪褋褌邪褍</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>袦訖蟹褨褉 卸芯谢邪覔褘薪 褎芯泻褍褋褌邪褍</dt>\n' +
+  '  <dd>Windows 薪械屑械褋械 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>覛冶褉邪谢写邪褉 褌邪覜褌邪褋褘薪 褎芯泻褍褋褌邪褍</dt>\n' +
+  '  <dd>Windows 薪械屑械褋械 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>孝萤屑械薪谐褨 写械褉械泻褌械屑械薪褨 褎芯泻褍褋褌邪褍</dt>\n' +
+  '  <dd>Windows 薪械屑械褋械 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>啸邪斜邪褉谢邪薪写褘褉褍写褘 斜械谢谐褨谢械褍</dt>\n' +
+  '  <dd>Windows 薪械屑械褋械 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>袦訖褌褨薪屑訖薪写褨泻 覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘薪 褎芯泻褍褋褌邪褍</dt>\n' +
+  '  <dd>Windows, Linux 薪械屑械褋械 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>袧邪胁懈谐邪褑懈褟 斜萤谢械泻褌械谢械褌褨薪 薪械屑械褋械 孝萤屑械薪谐褨 写械褉械泻褌械屑械 褝谢械屑械薪褌褨薪褨遥 卸芯谢褘薪写邪覔褘 斜褨褉褨薪褕褨 褝谢械屑械薪褌 卸邪覔写邪泄褘薪写邪 邪褋褌褘 褋褘蟹褘谢邪褌褘薪\n' +
+  '  斜褨褉褨薪褕褨 袩袠 褝谢械屑械薪褌褨薪械薪 斜邪褋褌邪谢邪写褘.</p>\n' +
+  '\n' +
+  '<h1>袩袠 斜萤谢褨屑写械褉褨 邪褉邪褋褘薪写邪 薪邪胁懈谐邪褑懈褟谢邪褍</h1>\n' +
+  '\n' +
+  '<p>袘褨褉 袩袠 斜萤谢褨屑褨薪械薪 泻械谢械褋褨褋褨薪械 萤褌褍 爷褕褨薪 <strong>Tab</strong> 锌械褉薪械褋褨薪 斜邪褋褘遥褘蟹.</p>\n' +
+  '\n' +
+  '<p>袘褨褉 袩袠 斜萤谢褨屑褨薪械薪 邪谢写褘遥覔褘褋褘薪邪 萤褌褍 爷褕褨薪 <strong>Shift+Tab</strong> 锌械褉薪械褋褨薪 斜邪褋褘遥褘蟹.</p>\n' +
+  '\n' +
+  '<p>袨褋褘 袩袠 斜萤谢褨屑写械褉褨薪褨遥 <strong>Tab</strong> 褉械褌褨:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>袦訖蟹褨褉 卸芯谢邪覔褘</li>\n' +
+  '  <li>訕褉斜褨褉 覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘 褌芯斜褘</li>\n' +
+  '  <li>袘爷泄褨褉谢褨泻 卸芯谢邪覜</li>\n' +
+  '  <li>孝萤屑械薪谐褨 写械褉械泻褌械屑械写械谐褨 褝谢械屑械薪褌 卸芯谢褘</li>\n' +
+  '  <li>孝萤屑械薪谐褨 写械褉械泻褌械屑械写械谐褨 褋萤蟹写械褉 褋邪薪褘薪 邪褍褘褋褌褘褉褍 褌爷泄屑械褋褨</li>\n' +
+  '  <li>孝萤屑械薪谐褨 写械褉械泻褌械屑械写械谐褨 斜褉械薪写懈薪谐褌褨泻 褋褨谢褌械屑械</li>\n' +
+  '  <li>孝萤屑械薪谐褨 写械褉械泻褌械屑械写械谐褨 褉械写邪泻褌芯褉 萤谢褕械屑褨薪 萤蟹谐械褉褌褍 褌冶褌覜邪褋褘</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>袩袠 斜萤谢褨屑褨 泻萤褉褋械褌褨谢屑械褋械, 芯谢 萤褌泻褨蟹褨锌 卸褨斜械褉褨谢械写褨.</p>\n' +
+  '\n' +
+  '<p>孝萤屑械薪谐褨 写械褉械泻褌械屑械写械 锌械褉薪械褌邪覜褌邪 薪邪胁懈谐邪褑懈褟褋褘薪褘遥 褎芯泻褍褋褘 斜芯谢褋邪 卸訖薪械 斜爷泄褨褉谢褨泻 卸芯谢邪覜 泻萤褉褨薪斜械褋械, <strong>Shift+Tab</strong> 褌褨褉泻械褋褨屑褨薪 斜邪褋褍 訖褉械泻械褌褨\n' +
+  '  褎芯泻褍褋褌褘 褋芯遥覔褘褋褘 械屑械褋, 斜褨褉褨薪褕褨 覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘 褌芯斜褘薪邪 卸褘谢卸褘褌邪写褘.</p>\n' +
+  '\n' +
+  '<h1>袩袠 斜萤谢褨屑写械褉褨薪写械 薪邪胁懈谐邪褑懈褟谢邪褍</h1>\n' +
+  '\n' +
+  '<p>袘褨褉 袩袠 褝谢械屑械薪褌褨薪械薪 泻械谢械褋褨褋褨薪械 萤褌褍 爷褕褨薪 <strong>Arrow</strong> (袣萤褉褋械褌泻褨) 锌械褉薪械褋褨薪 斜邪褋褘遥褘蟹.</p>\n' +
+  '\n' +
+  '<p><strong>Left</strong> (小芯谢 卸邪覜) 卸訖薪械 <strong>Right</strong> (袨遥 卸邪覜) 泻萤褉褋械褌泻褨 锌械褉薪械谢械褉褨</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>屑訖蟹褨褉 卸芯谢邪覔褘薪写邪覔褘 屑訖蟹褨褉谢械褉 邪褉邪褋褘薪写邪 卸褘谢卸褘褌褍.</li>\n' +
+  '  <li>屑訖蟹褨褉写械 褨褕泻褨 屑訖蟹褨褉写褨 邪褕褍.</li>\n' +
+  '  <li>覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘 褌芯斜褘薪写邪覔褘 褌爷泄屑械谢械褉 邪褉邪褋褘薪写邪 卸褘谢卸褘褌褍.</li>\n' +
+  '  <li>褌萤屑械薪谐褨 写械褉械泻褌械屑械 褝谢械屑械薪褌褨薪褨遥 卸芯谢褘薪写邪覔褘 褝谢械屑械薪褌褌械褉 邪褉邪褋褘薪写邪 卸褘谢卸褘褌褍.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Down</strong> (孝萤屑械薪) 卸訖薪械 <strong>Up</strong> (袞芯覔邪褉褘) 泻萤褉褋械褌泻褨 锌械褉薪械谢械褉褨</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>屑訖蟹褨褉写械谐褨 屑訖蟹褨褉 褝谢械屑械薪褌褌械褉褨 邪褉邪褋褘薪写邪 卸褘谢卸褘褌褍.</li>\n' +
+  '  <li>覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘薪褘遥 邪褕褘谢屑邪谢褘 屑訖蟹褨褉褨薪写械谐褨 屑訖蟹褨褉 褝谢械屑械薪褌褌械褉褨 邪褉邪褋褘薪写邪 卸褘谢卸褘褌褍.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>肖芯泻褍褋褌邪谢覔邪薪 袩袠 斜萤谢褨屑褨薪写械谐褨 <strong>Arrow</strong> (袣萤褉褋械褌泻褨) 锌械褉薪械谢械褉褨薪褨遥 褑懈泻谢褨.</p>\n' +
+  '\n' +
+  '<p>袗褕褘覜 屑訖蟹褨褉写褨 卸邪斜褍 爷褕褨薪 褨褕泻褨 屑訖蟹褨褉写褨 邪褕褘锌 薪械屑械褋械 邪褕褘谢屑邪谢褘 屑訖蟹褨褉写褨 邪褕褘锌, <strong>Esc</strong> 锌械褉薪械褋褨薪 斜邪褋褘遥褘蟹.</p>\n' +
+  '\n' +
+  '<p>袗覔褘屑写邪覔褘 褎芯泻褍褋 斜械谢谐褨谢褨 斜褨褉 袩袠 斜萤谢褨屑褨薪褨遥 芦爷褋褌褨薪写械禄 斜芯谢褋邪, <strong>Esc</strong> 锌械褉薪械褋褨薪 斜邪褋褍 訖褉械泻械褌褨 锌械褉薪械褌邪覜褌邪\n' +
+  '  薪邪胁懈谐邪褑懈褟褋褘薪 褌芯谢褘覔褘屑械薪 卸邪斜邪写褘.</p>\n' +
+  '\n' +
+  '<h1>袦訖蟹褨褉 褝谢械屑械薪褌褨薪 薪械屑械褋械 覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘 褌爷泄屑械褋褨薪 芯褉褘薪写邪褍</h1>\n' +
+  '\n' +
+  '<p>覛邪卸械褌褌褨 屑訖蟹褨褉 褝谢械屑械薪褌褨 薪械屑械褋械 覜冶褉邪谢写邪褉 褌邪覜褌邪褋褘 褌爷泄屑械褋褨 斜萤谢械泻褌械谢谐械薪 泻械蟹写械, 褝谢械屑械薪褌褌褨 芯褉褘薪写邪褍 爷褕褨薪 <strong>Return</strong> (覛邪泄褌邪褉褍), <strong>Enter</strong> (袝薪谐褨蟹褍)\n' +
+  '  薪械屑械褋械 <strong>Space bar</strong> (袘芯褋 芯褉褘薪) 锌械褉薪械褋褨薪 斜邪褋褘遥褘蟹.</p>\n' +
+  '\n' +
+  '<h1>袘械谢谐褨谢械薪斜械谐械薪 写懈邪谢芯谐 褌械褉械蟹械谢械褉褨薪 薪邪胁懈谐邪褑懈褟谢邪褍</h1>\n' +
+  '\n' +
+  '<p>袘械谢谐褨谢械薪斜械谐械薪 写懈邪谢芯谐 褌械褉械蟹械谢械褉褨薪写械 写懈邪谢芯谐 褌械褉械蟹械褋褨 邪褕褘谢覔邪薪 泻械蟹写械 斜褨褉褨薪褕褨 懈薪褌械褉邪泻褌懈胁褌褨 覜冶褉邪屑写邪褋 褎芯泻褍褋褌邪谢邪写褘.</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> 薪械屑械褋械 <strong>Shift+Tab</strong> 锌械褉薪械褋褨薪 斜邪褋褍 邪褉覜褘谢褘 懈薪褌械褉邪泻褌懈胁褌褨 写懈邪谢芯谐 褌械褉械蟹械褋褨薪褨遥 覜冶褉邪屑写邪褋褌邪褉褘 邪褉邪褋褘薪写邪 薪邪胁懈谐邪褑懈褟谢邪遥褘蟹.</p>\n' +
+  '\n' +
+  '<h1>袘械谢谐褨谢械薪谐械薪 写懈邪谢芯谐 褌械褉械蟹械谢械褉褨薪 薪邪胁懈谐邪褑懈褟谢邪褍</h1>\n' +
+  '\n' +
+  '<p>袘械谢谐褨谢械薪谐械薪 写懈邪谢芯谐 褌械褉械蟹械谢械褉褨薪写械 写懈邪谢芯谐 褌械褉械蟹械褋褨 邪褕褘谢覔邪薪 泻械蟹写械 覜芯泄褘薪写褘 屑訖蟹褨褉褨薪写械谐褨 斜褨褉褨薪褕褨 褌爷泄屑械 褎芯泻褍褋褌邪谢邪写褘.</p>\n' +
+  '\n' +
+  '<p><strong>Tab</strong> 薪械屑械褋械\n' +
+  '  <strong>Shift+Tab</strong> 锌械褉薪械褋褨薪 斜邪褋褍 邪褉覜褘谢褘 芯褋褘 写懈邪谢芯谐 褌械褉械蟹械褋褨 覜芯泄褘薪写褘褋褘薪褘遥 懈薪褌械褉邪泻褌懈胁褌褨 覜冶褉邪屑写邪褋褌邪褉褘 邪褉邪褋褘薪写邪 薪邪胁懈谐邪褑懈褟谢邪遥褘蟹.</p>\n' +
+  '\n' +
+  '<p>覛芯泄褘薪写褘 屑訖蟹褨褉褨薪褨遥 褎芯泻褍褋褘薪 斜械褉褍 邪褉覜褘谢褘 斜邪褋覜邪 写懈邪谢芯谐 褌械褉械蟹械褋褨薪褨遥 覜芯泄褘薪写褘褋褘薪邪 邪褍褘褋褘锌, 褌懈褨褋褌褨 <strong>Arrow</strong> (袣萤褉褋械褌泻褨)\n' +
+  '  锌械褉薪械褋褨薪 斜邪褋褍 邪褉覜褘谢褘 覜芯谢卸械褌褨屑写褨 覜芯泄褘薪写褘谢邪褉 邪褉邪褋褘薪写邪 邪泄薪邪谢写褘褉褍覔邪 斜芯谢邪写褘.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ko_KR.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ko_KR.js
new file mode 100644
index 0000000..e7c8e7f
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ko_KR.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ko_KR',
+'<h1>韨る炒霌� 韮愳儔 鞁滌瀾</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>氅旊壌 氇潓 韽护鞀� 響滌嫓</dt>\n' +
+  '  <dd>Windows 霕愲姅 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>霃勱惮 氇潓 韽护鞀� 響滌嫓</dt>\n' +
+  '  <dd>Windows 霕愲姅 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>響疙劙 韽护鞀� 響滌嫓</dt>\n' +
+  '  <dd>Windows 霕愲姅 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>鞎岆 韽护鞀�</dt>\n' +
+  '  <dd>Windows 霕愲姅 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>旎厤鞀ろ姼 霃勱惮 氇潓鞐� 韽护鞀� 響滌嫓</dt>\n' +
+  '  <dd>Windows, Linux 霕愲姅 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>觳� 氩堨Ц UI 頃鞐愳劀 韮愳儔鞚� 鞁滌瀾霅橂┌, 鞚措晫 觳� 氩堨Ц 頃鞚� 臧曥“ 響滌嫓霅橁卑雮� 響疙劙 鞖旍唽 瓴诫鞐� 鞛堧姅\n' +
+  '  瓴届毎 氚戩 響滌嫓霅╇媹雼�.</p>\n' +
+  '\n' +
+  '<h1>UI 靹轨厴 臧� 韮愳儔</h1>\n' +
+  '\n' +
+  '<p>頃� UI 靹轨厴鞐愳劀 雼れ潓 UI 靹轨厴鞙茧 鞚措彊頃橂牑氅� <strong>Tab(韮�)</strong>鞚� 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  '<p>頃� UI 靹轨厴鞐愳劀 鞚挫爠 UI 靹轨厴鞙茧 霃岇晞臧�霠る┐ <strong>Shift+Tab(鞁滍攧韸�+韮�)</strong>鞚� 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  '<p>鞚� UI 靹轨厴鞚� <strong>Tab(韮�)</strong> 靾滌劀電� 雼れ潓瓿� 臧欖姷雼堧嫟.</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>氅旊壌 氚�</li>\n' +
+  '  <li>臧� 霃勱惮 氇潓 攴鸽9</li>\n' +
+  '  <li>靷澊霌滊皵</li>\n' +
+  '  <li>響疙劙鞚� 鞖旍唽 瓴诫</li>\n' +
+  '  <li>響疙劙鞚� 雼柎 靾� 韱犼竴 氩勴娂</li>\n' +
+  '  <li>響疙劙鞚� 敫岆灉霐� 毵來伂</li>\n' +
+  '  <li>響疙劙鞚� 鞐愲敂韯� 韥赴 氤�瓴� 頃鸽摛</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>UI 靹轨厴鞚� 鞐嗠姅 瓴届毎 瓯措剤霙瓣赴頃╇媹雼�.</p>\n' +
+  '\n' +
+  '<p>響疙劙鞐� 韨る炒霌� 韮愳儔 韽护鞀り皜 鞛堦碃 靷澊霌滊皵電� 氤挫澊歆� 鞎婋姅 瓴届毎 <strong>Shift+Tab(鞁滍攧韸�+韮�)</strong>鞚� 雸勲ゴ氅碶n' +
+  '  韽护鞀� 響滌嫓臧� 毵堨毵夓澊 鞎勲媽 觳� 氩堨Ц 霃勱惮 氇潓 攴鸽9鞙茧 鞚措彊頃╇媹雼�.</p>\n' +
+  '\n' +
+  '<h1>UI 靹轨厴 雮� 韮愳儔</h1>\n' +
+  '\n' +
+  '<p>頃� UI 鞖旍唽鞐愳劀 雼れ潓 UI 鞖旍唽搿� 鞚措彊頃橂牑氅� 鞝侅爤頃� <strong>頇旍偞響�</strong> 韨るゼ 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  '<p><strong>鞕检</strong>瓿� <strong>鞓るジ飒�</strong> 頇旍偞響� 韨れ潣 鞖╇弰:</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>氅旊壌 氇潓鞐愳劀 氅旊壌 頃 靷澊毳� 鞚措彊頃╇媹雼�.</li>\n' +
+  '  <li>氅旊壌鞐愳劀 頃橃渼 氅旊壌毳� 鞐诫媹雼�.</li>\n' +
+  '  <li>霃勱惮 氇潓 攴鸽9鞐愳劀 氩勴娂 靷澊毳� 鞚措彊頃╇媹雼�.</li>\n' +
+  '  <li>響疙劙鞚� 鞖旍唽 瓴诫鞐愳劀 頃 臧勳棎 鞚措彊頃╇媹雼�.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>鞎勲灅</strong>鞕� <strong>鞙�</strong> 頇旍偞響� 韨れ潣 鞖╇弰:</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>氅旊壌鞐愳劀 氅旊壌 頃 靷澊毳� 鞚措彊頃╇媹雼�.</li>\n' +
+  '  <li>霃勱惮 氇潓 韺濎梾 氅旊壌鞐愳劀 氅旊壌 頃 靷澊毳� 鞚措彊頃╇媹雼�.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>頇旍偞響�</strong> 韨る姅 韽护鞀� 響滌嫓 UI 靹轨厴 雮挫棎靹� 靾滍櫂霅╇媹雼�.</p>\n' +
+  '\n' +
+  '<p>鞐措牑 鞛堧姅 氅旊壌, 鞐措牑 鞛堧姅 頃橃渼 氅旊壌 霕愲姅 鞐措牑 鞛堧姅 韺濎梾 氅旊壌毳� 雼溂霠る┐ <strong>Esc</strong> 韨るゼ 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  "<p>順勳灛 韽护鞀� 響滌嫓臧� 韸轨爼 UI 靹轨厴 '靸侂嫧'鞐� 鞛堧姅 瓴届毎 鞚措晫霃� <strong>Esc</strong> 韨るゼ 雸勲ゴ氅碶n" +
+  '  韨る炒霌� 韮愳儔鞚� 鞕勳爠頌� 膦呺霅╇媹雼�.</p>\n' +
+  '\n' +
+  '<h1>氅旊壌 頃 霕愲姅 霃勱惮 氇潓 氩勴娂 鞁ろ枆</h1>\n' +
+  '\n' +
+  '<p>鞗愴晿電� 氅旊壌 頃 霕愲姅 霃勱惮 氇潓 氩勴娂鞚� 臧曥“ 響滌嫓霅橃柎 鞛堨潉 霑� <strong>Return(毽劥)</strong>, <strong>Enter(鞐旐劙)</strong>,\n' +
+  '  霕愲姅 <strong>Space bar(鞀ろ帢鞚挫姢氚�)</strong>毳� 雸岆煬 頃措嫻 頃鞚� 鞁ろ枆頃╇媹雼�.</p>\n' +
+  '\n' +
+  '<h1>韮澊 鞐嗠姅 雽�頇� 韮愳儔</h1>\n' +
+  '\n' +
+  '<p>韮澊 鞐嗠姅 雽�頇旍潣 瓴届毎, 觳� 氩堨Ц 雽�頇旐槙 鞖旍唽臧� 韽护鞀� 響滌嫓霅� 靸來儨搿� 雽�頇旉皜 鞐措雼堧嫟.</p>\n' +
+  '\n' +
+  '<p>雽�頇旐槙 鞖旍唽霌� 靷澊毳� 鞚措彊頃� 霑岆姅 <strong>Tab(韮�)</strong> 霕愲姅 <strong>Shift+Tab(鞁滍攧韸�+韮�)</strong>鞚� 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  '<h1>韮澊 鞛堧姅 雽�頇� 韮愳儔</h1>\n' +
+  '\n' +
+  '<p>韮澊 鞛堧姅 雽�頇旍潣 瓴届毎, 韮� 氅旊壌鞐愳劀 觳� 氩堨Ц 氩勴娂鞚� 韽护鞀� 響滌嫓霅� 靸來儨搿� 雽�頇旉皜 鞐措雼堧嫟.</p>\n' +
+  '\n' +
+  '<p>鞚� 雽�頇� 韮潣 雽�頇旐槙 鞖旍唽霌� 靷澊毳� 鞚措彊頃� 霑岆姅 <strong>Tab(韮�)</strong> 霕愲姅\n' +
+  '  <strong>Shift+Tab(鞁滍攧韸�+韮�)</strong>鞚� 雸勲雼堧嫟.</p>\n' +
+  '\n' +
+  '<p>雼るジ 雽�頇� 韮溂搿� 鞚措彊頃橂牑氅� 韮� 氅旊壌毳� 韽护鞀� 響滌嫓頃� 雼れ潓 鞝侅爤頃� <strong>頇旍偞響�</strong>\n' +
+  '  韨るゼ 雸岆煬 靷毄 臧�電ロ暅 韮摛鞚� 歆�雮� 鞗愴晿電� 韮溂搿� 鞚措彊頃╇媹雼�.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ms.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ms.js
new file mode 100644
index 0000000..2c047bb
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ms.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ms',
+'<h1>Mulakan navigasi papan kekunci</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokus bar Menu</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokus Bar Alat</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokus pengaki</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Tumpu kepada pemberitahuan</dt>\n' +
+  '  <dd>Windows atau Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokus bar alat kontekstual</dt>\n' +
+  '  <dd>Windows, Linux atau macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigasi akan bermula pada item UI pertama, yang akan diserlahkan atau digaris bawah dalam saiz item pertama dalam\n' +
+  '  laluan elemen Pengaki.</p>\n' +
+  '\n' +
+  '<h1>Navigasi antara bahagian UI</h1>\n' +
+  '\n' +
+  '<p>Untuk bergerak dari satu bahagian UI ke yang seterusnya, tekan <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Untuk bergerak dari satu bahagian UI ke yang sebelumnya, tekan <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Tertib <strong>Tab</strong> bahagian UI ini ialah:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Bar menu</li>\n' +
+  '  <li>Setiap kumpulan bar alat</li>\n' +
+  '  <li>Bar sisi</li>\n' +
+  '  <li>Laluan elemen dalam pengaki</li>\n' +
+  '  <li>Butang togol kiraan perkataan dalam pengaki</li>\n' +
+  '  <li>Pautan penjenamaan dalam pengaki</li>\n' +
+  '  <li>Pemegang saiz semula editor dalam pengaki</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Jika bahagian UI tidak wujud, ia dilangkau.</p>\n' +
+  '\n' +
+  '<p>Jika pengaki mempunyai fokus navigasi papan kekunci dan tiada bar sisi kelihatan, menekan <strong>Shift+Tab</strong>\n' +
+  '  akan mengalihkan fokus ke kumpulan bar alat pertama, bukannya yang terakhir.</p>\n' +
+  '\n' +
+  '<h1>Navigasi dalam bahagian UI</h1>\n' +
+  '\n' +
+  '<p>Untuk bergerak dari satu elemen UI ke yang seterusnya, tekan kekunci <strong>Anak Panah</strong> yang bersesuaian.</p>\n' +
+  '\n' +
+  '<p>Kekunci anak panah <strong>Kiri</strong> dan <strong>Kanan</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>bergerak antara menu dalam bar menu.</li>\n' +
+  '  <li>membukan submenu dalam menu.</li>\n' +
+  '  <li>bergerak antara butang dalam kumpulan bar alat.</li>\n' +
+  '  <li>Laluan elemen dalam pengaki.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Kekunci anak panah <strong>Bawah</strong> dan <strong>Atas</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>bergerak antara item menu dalam menu.</li>\n' +
+  '  <li>bergerak antara item dalam menu timbul bar alat.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Kekunci <strong>Anak Panah</strong> berkitar dalam bahagian UI difokuskan.</p>\n' +
+  '\n' +
+  '<p>Untuk menutup menu buka, submenu terbuka atau menu timbul terbuka, tekan kekunci <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  "<p>Jika fokus semasa berada di bahagian 'atas' bahagian UI tertentu, menekan kekunci <strong>Esc</strong> juga akan keluar daripada\n" +
+  '  navigasi papan kekunci sepenuhnya.</p>\n' +
+  '\n' +
+  '<h1>Laksanakan item menu atau butang bar alat</h1>\n' +
+  '\n' +
+  '<p>Apabila item menu atau butang bar alat yang diinginkan diserlahkan, tekan <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  atau <strong>bar Space</strong> untuk melaksanakan item.</p>\n' +
+  '\n' +
+  '<h1>Navigasi ke dialog tidak bertab</h1>\n' +
+  '\n' +
+  '<p>Dalam dialog tidak bertab, komponen interaksi pertama difokuskan apabila dialog dibuka.</p>\n' +
+  '\n' +
+  '<p>Navigasi antara komponen dialog interaktif dengan menekan <strong>Tab</strong> atau <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigasi ke dialog bertab</h1>\n' +
+  '\n' +
+  '<p>Dalam dialog bertab, butang pertama dalam menu tab difokuskan apabila dialog dibuka.</p>\n' +
+  '\n' +
+  '<p>Navigasi antara komponen interaktif tab dialog ini dengan menekan <strong>Tab</strong> atau\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Tukar kepada tab dialog lain dengan memfokuskan menu tab, kemudian menekan kekunci <strong>Anak Panah</strong> yang bersesuaian\n' +
+  '  untuk berkitar menerusi tab yang tersedia.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nb_NO.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nb_NO.js
new file mode 100644
index 0000000..071e3f5
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nb_NO.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.nb_NO',
+'<h1>Starte tastaturnavigering</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Utheve menylinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt聽+聽F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Utheve verkt酶ylinjen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt聽+聽F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Utheve bunnteksten</dt>\n' +
+  '  <dd>Windows eller Linux: Alt聽+聽F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokuser p氓 varselet</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Utheve en kontekstuell verkt酶ylinje</dt>\n' +
+  '  <dd>Windows, Linux eller macOS: Ctrl聽+聽F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigeringen starter ved det f酶rste grensesnittelementet, som utheves, eller understrekes n氓r det gjelder det f酶rste elementet i\n' +
+  '  elementstien i bunnteksten.</p>\n' +
+  '\n' +
+  '<h1>Navigere mellom grensesnittdeler</h1>\n' +
+  '\n' +
+  '<p>Du kan bevege deg fra 茅n grensesnittdel til den neste ved 氓 trykke p氓 <strong>tabulatortasten</strong>.</p>\n' +
+  '\n' +
+  '<p>Du kan bevege deg fra 茅n grensesnittdel til den forrige ved 氓 trykke p氓 <strong>Shift + tabulatortasten</strong>.</p>\n' +
+  '\n' +
+  '<p>Rekkef酶lgen til <strong>tabulatortasten</strong> gjennom grensesnittdelene er:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menylinjen</li>\n' +
+  '  <li>Hver gruppe p氓 verkt酶ylinjen</li>\n' +
+  '  <li>Sidestolpen</li>\n' +
+  '  <li>Elementstien i bunnteksten</li>\n' +
+  '  <li>Veksleknappen for ordantall i bunnteksten</li>\n' +
+  '  <li>Merkelenken i bunnteksten</li>\n' +
+  '  <li>Skaleringsh氓ndtaket for redigeringsprogrammet i bunnteksten</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Hvis en grensesnittdel ikke er til stede, blir den hoppet over.</p>\n' +
+  '\n' +
+  '<p>Hvis tastaturnavigeringen har uthevet bunnteksten og det ikke finnes en synlig sidestolpe, kan du trykke p氓 <strong>Shift + tabulatortasten</strong>\n' +
+  '  for 氓 flytte fokuset til den f酶rste gruppen p氓 verkt酶ylinjen i stedet for den siste.</p>\n' +
+  '\n' +
+  '<h1>Navigere innenfor grensesnittdeler</h1>\n' +
+  '\n' +
+  '<p>Du kan bevege deg fra ett grensesnittelement til det neste ved 氓 trykke p氓 den aktuelle <strong>piltasten</strong>.</p>\n' +
+  '\n' +
+  '<p>De <strong>venstre</strong> og <strong>h酶yre</strong> piltastene</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>beveger deg mellom menyer p氓 menylinjen.</li>\n' +
+  '  <li>氓pner en undermeny i en meny.</li>\n' +
+  '  <li>beveger deg mellom knapper i en gruppe p氓 verkt酶ylinjen.</li>\n' +
+  '  <li>beveger deg mellom elementer i elementstien i bunnteksten.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Ned</strong>- og <strong>opp</strong>-piltastene</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>beveger deg mellom menyelementer i en meny.</li>\n' +
+  '  <li>beveger deg mellom elementer i en hurtigmeny p氓 verkt酶ylinjen.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Med <strong>piltastene</strong> kan du bevege deg innenfor den uthevede grensesnittdelen.</p>\n' +
+  '\n' +
+  '<p>Du kan lukke en 氓pen meny, en 氓pen undermeny eller en 氓pen hurtigmeny ved 氓 klikke p氓 <strong>Esc</strong>-tasten.</p>\n' +
+  '\n' +
+  '<p>Hvis det 酶verste niv氓et i en grensesnittdel er uthevet, kan du ved 氓 trykke p氓 <strong>Esc</strong> ogs氓 avslutte\n' +
+  '  tastaturnavigeringen helt.</p>\n' +
+  '\n' +
+  '<h1>Utf酶re et menyelement eller en knapp p氓 en verkt酶ylinje</h1>\n' +
+  '\n' +
+  '<p>N氓r det 酶nskede menyelementet eller verkt酶ylinjeknappen er uthevet, trykker du p氓 <strong>Retur</strong>, <strong>Enter</strong>,\n' +
+  '  eller <strong>mellomromstasten</strong> for 氓 utf酶re elementet.</p>\n' +
+  '\n' +
+  '<h1>Navigere i dialogbokser uten faner</h1>\n' +
+  '\n' +
+  '<p>I dialogbokser uten faner blir den f酶rste interaktive komponenten uthevet n氓r dialogboksen 氓pnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellom interaktive komponenter i dialogboksen ved 氓 trykke p氓 <strong>tabulatortasten</strong> eller <strong>Shift + tabulatortasten</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigere i fanebaserte dialogbokser</h1>\n' +
+  '\n' +
+  '<p>I fanebaserte dialogbokser blir den f酶rste knappen i fanemenyen uthevet n氓r dialogboksen 氓pnes.</p>\n' +
+  '\n' +
+  '<p>Naviger mellom interaktive komponenter i fanen ved 氓 trykke p氓 <strong>tabulatortasten</strong> eller\n' +
+  '  <strong>Shift + tabulatortasten</strong>.</p>\n' +
+  '\n' +
+  '<p>Veksle til en annen fane i dialogboksen ved 氓 utheve fanemenyen, og trykk deretter p氓 den aktuelle <strong>piltasten</strong>\n' +
+  '  for 氓 bevege deg mellom de tilgjengelige fanene.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nl.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nl.js
new file mode 100644
index 0000000..05c07ae
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/nl.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.nl',
+'<h1>Toetsenbordnavigatie starten</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Focus op de menubalk instellen</dt>\n' +
+  '  <dd>Windows of Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Focus op de werkbalk instellen</dt>\n' +
+  '  <dd>Windows of Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Focus op de voettekst instellen</dt>\n' +
+  '  <dd>Windows of Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Focus op de melding instellen</dt>\n' +
+  '  <dd>Windows of Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Focus op een contextuele werkbalk instellen</dt>\n' +
+  '  <dd>Windows, Linux of macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>De navigatie start bij het eerste UI-item, dat wordt gemarkeerd of onderstreept als het eerste item zich in\n' +
+  '  in het elementenpad van de voettekst bevindt.</p>\n' +
+  '\n' +
+  '<h1>Navigeren tussen UI-secties</h1>\n' +
+  '\n' +
+  '<p>Druk op <strong>Tab</strong> om naar de volgende UI-sectie te gaan.</p>\n' +
+  '\n' +
+  '<p>Druk op <strong>Shift+Tab</strong> om naar de vorige UI-sectie te gaan.</p>\n' +
+  '\n' +
+  '<p>De <strong>Tab</strong>-volgorde van deze UI-secties is:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menubalk</li>\n' +
+  '  <li>Elke werkbalkgroep</li>\n' +
+  '  <li>Zijbalk</li>\n' +
+  '  <li>Elementenpad in de voettekst</li>\n' +
+  '  <li>Wisselknop voor aantal woorden in de voettekst</li>\n' +
+  '  <li>Merkkoppeling in de voettekst</li>\n' +
+  '  <li>Greep voor het wijzigen van het formaat van de editor in de voettekst</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Als een UI-sectie niet aanwezig is, wordt deze overgeslagen.</p>\n' +
+  '\n' +
+  '<p>Als de focus van de toetsenbordnavigatie is ingesteld op de voettekst en er geen zichtbare zijbalk is, kun je op <strong>Shift+Tab</strong> drukken\n' +
+  '  om de focus naar de eerste werkbalkgroep in plaats van de laatste te verplaatsen.</p>\n' +
+  '\n' +
+  '<h1>Navigeren binnen UI-secties</h1>\n' +
+  '\n' +
+  '<p>Druk op de <strong>pijltjestoets</strong> om naar het betreffende UI-element te gaan.</p>\n' +
+  '\n' +
+  '<p>Met de pijltjestoetsen <strong>Links</strong> en <strong>Rechts</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  "  <li>wissel je tussen menu's in de menubalk.</li>\n" +
+  '  <li>open je een submenu in een menu.</li>\n' +
+  '  <li>wissel je tussen knoppen in een werkbalkgroep.</li>\n' +
+  '  <li>wissel je tussen items in het elementenpad in de voettekst.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Met de pijltjestoetsen <strong>Omlaag</strong> en <strong>Omhoog</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>wissel je tussen menu-items in een menu.</li>\n' +
+  '  <li>wissel je tussen items in een werkbalkpop-upmenu.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Met de <strong>pijltjestoetsen</strong> wissel je binnen de UI-sectie waarop de focus is ingesteld.</p>\n' +
+  '\n' +
+  '<p>Druk op de toets <strong>Esc</strong> om een geopend menu, submenu of pop-upmenu te sluiten.</p>\n' +
+  '\n' +
+  "<p>Als de huidige focus is ingesteld 'bovenaan' een bepaalde UI-sectie, kun je op de toets <strong>Esc</strong> drukken\n" +
+  '  om de toetsenbordnavigatie af te sluiten.</p>\n' +
+  '\n' +
+  '<h1>Een menu-item of werkbalkknop uitvoeren</h1>\n' +
+  '\n' +
+  '<p>Als het gewenste menu-item of de gewenste werkbalkknop is gemarkeerd, kun je op <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  of de <strong>spatiebalk</strong> drukken om het item uit te voeren.</p>\n' +
+  '\n' +
+  '<h1>Navigeren in dialoogvensters zonder tabblad</h1>\n' +
+  '\n' +
+  '<p>Als een dialoogvenster zonder tabblad wordt geopend, wordt de focus ingesteld op het eerste interactieve onderdeel.</p>\n' +
+  '\n' +
+  '<p>Je kunt navigeren tussen interactieve onderdelen van een dialoogvenster door op <strong>Tab</strong> of <strong>Shift+Tab</strong> te drukken.</p>\n' +
+  '\n' +
+  '<h1>Navigeren in dialoogvensters met tabblad</h1>\n' +
+  '\n' +
+  '<p>Als een dialoogvenster met tabblad wordt geopend, wordt de focus ingesteld op de eerste knop in het tabbladmenu.</p>\n' +
+  '\n' +
+  '<p>Je kunt navigeren tussen interactieve onderdelen van dit tabblad van het dialoogvenster door op <strong>Tab</strong> of\n' +
+  '  <strong>Shift+Tab</strong> te drukken.</p>\n' +
+  '\n' +
+  '<p>Je kunt overschakelen naar een ander tabblad van het dialoogvenster door de focus in te stellen op het tabbladmenu en vervolgens op de juiste <strong>pijltjestoets</strong>\n' +
+  '  te drukken om tussen de beschikbare tabbladen te wisselen.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pl.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pl.js
new file mode 100644
index 0000000..e89f808
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pl.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.pl',
+'<h1>Pocz膮tek nawigacji przy u偶yciu klawiatury</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Ustaw fokus na pasek menu</dt>\n' +
+  '  <dd>Windows lub Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Ustaw fokus na pasek narz臋dzi</dt>\n' +
+  '  <dd>Windows lub Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Ustaw fokus na sekcj臋 Footer</dt>\n' +
+  '  <dd>Windows lub Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Skup si臋 na powiadomieniu</dt>\n' +
+  '  <dd>Windows lub Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Ustaw fokus na kontekstowy pasek narz臋dzi</dt>\n' +
+  '  <dd>Windows, Linux lub macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Nawigacja zostanie rozpocz臋ta od pierwszego elementu interfejsu u偶ytkownika, kt贸ry jest pod艣wietlony lub 鈥� w przypadku pierwszego elementu\n' +
+  '  w 艣cie偶ce element贸w w sekcji Footer 鈥� podkre艣lony.</p>\n' +
+  '\n' +
+  '<h1>Nawigacja pomi臋dzy sekcjami interfejsu u偶ytkownika</h1>\n' +
+  '\n' +
+  '<p>Aby przenie艣膰 si臋 z danej sekcji interfejsu u偶ytkownika do nast臋pnej, naci艣nij <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Aby przenie艣膰 si臋 z danej sekcji interfejsu u偶ytkownika do poprzedniej, naci艣nij <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Kolejno艣膰 klawisza <strong>Tab</strong> w takich sekcjach interfejsu u偶ytkownika jest nast臋puj膮ca:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Pasek menu</li>\n' +
+  '  <li>Ka偶da grupa na pasku narz臋dzi</li>\n' +
+  '  <li>Pasek boczny</li>\n' +
+  '  <li>艢cie偶ka element贸w w sekcji Footer</li>\n' +
+  '  <li>Przycisk prze艂膮czania liczby s艂贸w w sekcji Footer</li>\n' +
+  '  <li>艁膮cze branduj膮ce w sekcji Footer</li>\n' +
+  '  <li>Uchwyt zmiany rozmiaru edytora w sekcji Footer</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Je偶eli nie ma sekcji interfejsu u偶ytkownika, jest to pomijane.</p>\n' +
+  '\n' +
+  '<p>Je偶eli na sekcji Footer jest ustawiony fokus nawigacji przy u偶yciu klawiatury i nie ma widocznego paska bocznego, naci艣ni臋cie <strong>Shift+Tab</strong>\n' +
+  '  przenosi fokus na pierwsz膮 grup臋 paska narz臋dzi, a nie na ostatni膮.</p>\n' +
+  '\n' +
+  '<h1>Nawigacja wewn膮trz sekcji interfejsu u偶ytkownika</h1>\n' +
+  '\n' +
+  '<p>Aby przenie艣膰 si臋 z danego elementu interfejsu u偶ytkownika do nast臋pnego, naci艣nij odpowiedni klawisz <strong>strza艂ki</strong>.</p>\n' +
+  '\n' +
+  '<p>Klawisze strza艂ek <strong>w prawo</strong> i <strong>w lewo</strong> s艂u偶膮 do</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>przenoszenia si臋 pomi臋dzy menu na pasku menu,</li>\n' +
+  '  <li>otwarcia podmenu w menu,</li>\n' +
+  '  <li>przenoszenia si臋 pomi臋dzy przyciskami w grupie paska narz臋dzi,</li>\n' +
+  '  <li>przenoszenia si臋 pomi臋dzy elementami w 艣cie偶ce element贸w w sekcji Footer.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Klawisze strza艂ek <strong>w d贸艂</strong> i <strong>w g贸r臋</strong> s艂u偶膮 do</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>przenoszenia si臋 pomi臋dzy elementami menu w menu,</li>\n' +
+  '  <li>przenoszenia si臋 pomi臋dzy elementami w wyskakuj膮cym menu paska narz臋dzi.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Klawisze <strong>strza艂ek</strong> s艂u偶膮 do przemieszczania si臋 w sekcji interfejsu u偶ytkownika z ustawionym fokusem.</p>\n' +
+  '\n' +
+  '<p>Aby zamkn膮膰 otwarte menu, otwarte podmenu lub otwarte menu wyskakuj膮ce, naci艣nij klawisz <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Je偶eli fokus jest ustawiony na g贸rze konkretnej sekcji interfejsu u偶ytkownika, naci艣ni臋cie klawisza <strong>Esc</strong> powoduje wyj艣cie\n' +
+  '  z nawigacji przy u偶yciu klawiatury.</p>\n' +
+  '\n' +
+  '<h1>Wykonanie elementu menu lub przycisku paska narz臋dzi</h1>\n' +
+  '\n' +
+  '<p>Gdy pod艣wietlony jest 偶膮dany element menu lub przycisk paska narz臋dzi, naci艣nij klawisz <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  lub <strong>Spacja</strong>, aby go wykona膰.</p>\n' +
+  '\n' +
+  '<h1>Nawigacja po oknie dialogowym bez kart</h1>\n' +
+  '\n' +
+  '<p>Gdy otwiera si臋 okno dialogowe bez kart, fokus ustawiany jest na pierwsz膮 interaktywn膮 cz臋艣膰 okna.</p>\n' +
+  '\n' +
+  '<p>Pomi臋dzy interaktywnymi cz臋艣ciami okna dialogowego nawiguj, naciskaj膮c klawisze <strong>Tab</strong> lub <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Nawigacja po oknie dialogowym z kartami</h1>\n' +
+  '\n' +
+  '<p>W przypadku okna dialogowego z kartami po otwarciu okna dialogowego fokus ustawiany jest na pierwszy przycisk w menu karty.</p>\n' +
+  '\n' +
+  '<p>Nawigacj臋 pomi臋dzy interaktywnymi cz臋艣ciami karty okna dialogowego prowadzi si臋 poprzez naciskanie klawiszy <strong>Tab</strong> lub\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Prze艂膮czenie si臋 na inn膮 kart臋 okna dialogowego wykonuje si臋 poprzez ustawienie fokusu na menu karty i naci艣ni臋cie odpowiedniego klawisza <strong>strza艂ki</strong>\n' +
+  '  w celu przemieszczenia si臋 pomi臋dzy dost臋pnymi kartami.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_BR.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_BR.js
new file mode 100644
index 0000000..2938fcf
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_BR.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.pt_BR',
+'<h1>Iniciar navega莽茫o pelo teclado</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Foco na barra de menus</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Foco na barra de ferramentas</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Foco no rodap茅</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Foco na notifica莽茫o</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Foco na barra de ferramentas contextual</dt>\n' +
+  '  <dd>Windows, Linux ou macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>A navega莽茫o inicia no primeiro item da IU, que ser谩 destacado ou sublinhado no caso do primeiro item no\n' +
+  '  caminho do elemento Rodap茅.</p>\n' +
+  '\n' +
+  '<h1>Navegar entre se莽玫es da IU</h1>\n' +
+  '\n' +
+  '<p>Para ir de uma se莽茫o da IU para a seguinte, pressione <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Para ir de uma se莽茫o da IU para a anterior, pressione <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>A ordem de <strong>Tab</strong> destas se莽玫es da IU 茅:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de menus</li>\n' +
+  '  <li>Cada grupo da barra de ferramentas</li>\n' +
+  '  <li>Barra lateral</li>\n' +
+  '  <li>Caminho do elemento no rodap茅</li>\n' +
+  '  <li>Bot茫o de alternar contagem de palavras no rodap茅</li>\n' +
+  '  <li>Link da marca no rodap茅</li>\n' +
+  '  <li>Al莽a de redimensionamento do editor no rodap茅</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Se n茫o houver uma se莽茫o da IU, ela ser谩 pulada.</p>\n' +
+  '\n' +
+  '<p>Se o rodap茅 tiver o foco da navega莽茫o pelo teclado e n茫o houver uma barra lateral vis铆vel, pressionar <strong>Shift+Tab</strong>\n' +
+  '  move o foco para o primeiro grupo da barra de ferramentas, n茫o para o 煤ltimo.</p>\n' +
+  '\n' +
+  '<h1>Navegar dentro das se莽玫es da IU</h1>\n' +
+  '\n' +
+  '<p>Para ir de um elemento da IU para o seguinte, pressione a <strong>Seta</strong> correspondente.</p>\n' +
+  '\n' +
+  '<p>As teclas de seta <strong>Esquerda</strong> e <strong>Direita</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>movem entre menus na barra de menus.</li>\n' +
+  '  <li>abrem um submenu em um menu.</li>\n' +
+  '  <li>movem entre bot玫es em um grupo da barra de ferramentas.</li>\n' +
+  '  <li>movem entre itens no caminho do elemento do rodap茅.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>As teclas de seta <strong>Abaixo</strong> e <strong>Acima</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>movem entre itens de menu em um menu.</li>\n' +
+  '  <li>movem entre itens em um menu suspenso da barra de ferramentas.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>As teclas de <strong>Seta</strong> alternam dentre a se莽茫o da IU em foco.</p>\n' +
+  '\n' +
+  '<p>Para fechar um menu aberto, um submenu aberto ou um menu suspenso aberto, pressione <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Se o foco atual estiver no 鈥榓lto鈥� de determinada se莽茫o da IU, pressionar <strong>Esc</strong> tamb茅m sai\n' +
+  '  totalmente da navega莽茫o pelo teclado.</p>\n' +
+  '\n' +
+  '<h1>Executar um item de menu ou bot茫o da barra de ferramentas</h1>\n' +
+  '\n' +
+  '<p>Com o item de menu ou bot茫o da barra de ferramentas desejado destacado, pressione <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  ou a <strong>Barra de espa莽o</strong> para executar o item.</p>\n' +
+  '\n' +
+  '<h1>Navegar por caixas de di谩logo sem guias</h1>\n' +
+  '\n' +
+  '<p>Em caixas de di谩logo sem guias, o primeiro componente interativo recebe o foco quando a caixa de di谩logo abre.</p>\n' +
+  '\n' +
+  '<p>Navegue entre componentes interativos de caixa de di谩logo pressionando <strong>Tab</strong> ou <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navegar por caixas de di谩logo com guias</h1>\n' +
+  '\n' +
+  '<p>Em caixas de di谩logo com guias, o primeiro bot茫o no menu da guia recebe o foco quando a caixa de di谩logo abre.</p>\n' +
+  '\n' +
+  '<p>Navegue entre componentes interativos dessa guia da caixa de di谩logo pressionando <strong>Tab</strong> ou\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Alterne para outra guia da caixa de di谩logo colocando o foco no menu da guia e pressionando a <strong>Seta</strong>\n' +
+  '  adequada para percorrer as guias dispon铆veis.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_PT.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_PT.js
new file mode 100644
index 0000000..03da3d6
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/pt_PT.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.pt_PT',
+'<h1>Iniciar navega莽茫o com teclado</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Foco na barra de menu</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Foco na barra de ferramentas</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Foco no rodap茅</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Focar a notifica莽茫o</dt>\n' +
+  '  <dd>Windows ou Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Foco numa barra de ferramentas contextual</dt>\n' +
+  '  <dd>Windows, Linux ou macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>A navega莽茫o come莽ar谩 no primeiro item de IU, que estar谩 real莽ado ou sublinhado, no caso do primeiro item no\n' +
+  '  caminho do elemento do rodap茅.</p>\n' +
+  '\n' +
+  '<h1>Navegar entre sec莽玫es de IU</h1>\n' +
+  '\n' +
+  '<p>Para se mover de uma sec莽茫o de IU para a seguinte, prima <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Para se mover de uma sec莽茫o de IU para a anterior, prima <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>A ordem de <strong>tabula莽茫o</strong> destas sec莽玫es de IU 茅:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Barra de menu</li>\n' +
+  '  <li>Cada grupo da barra de ferramentas</li>\n' +
+  '  <li>Barra lateral</li>\n' +
+  '  <li>Caminho do elemento no rodap茅</li>\n' +
+  '  <li>Bot茫o de alternar da contagem de palavras no rodap茅</li>\n' +
+  '  <li>Liga莽茫o da marca no rodap茅</li>\n' +
+  '  <li>Al莽a de redimensionamento do editor no rodap茅</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Se uma sec莽茫o de IU n茫o estiver presente, 茅 ignorada.</p>\n' +
+  '\n' +
+  '<p>Se o rodap茅 tiver foco de navega莽茫o com teclado e n茫o existir uma barra lateral vis铆vel, premir <strong>Shift+Tab</strong>\n' +
+  '  move o foco para o primeiro grupo da barra de ferramentas e n茫o para o 煤ltimo.</p>\n' +
+  '\n' +
+  '<h1>Navegar nas sec莽玫es de IU</h1>\n' +
+  '\n' +
+  '<p>Para se mover de um elemento de IU para o seguinte, prima a tecla de <strong>seta</strong> adequada.</p>\n' +
+  '\n' +
+  '<p>As teclas de seta <strong>Para a esquerda</strong> e <strong>Para a direita</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>movem-se entre menus na barra de menu.</li>\n' +
+  '  <li>abrem um submenu num menu.</li>\n' +
+  '  <li>movem-se entre bot玫es num grupo da barra de ferramentas.</li>\n' +
+  '  <li>movem-se entre itens no caminho do elemento do rodap茅.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>As teclas de seta <strong>Para cima</strong> e <strong>Para baixo</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>movem-se entre itens de menu num menu.</li>\n' +
+  '  <li>movem-se entre itens num menu de pop-up da barra de ferramentas.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>As teclas de <strong>seta</strong> deslocam-se ciclicamente na sec莽茫o de IU em foco.</p>\n' +
+  '\n' +
+  '<p>Para fechar um menu aberto, um submenu aberto ou um menu de pop-up aberto, prima a tecla <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Se o foco atual estiver no "topo" de determinada sec莽茫o de IU, premir a tecla <strong>Esc</strong> tamb茅m fecha\n' +
+  '  completamente a navega莽茫o com teclado.</p>\n' +
+  '\n' +
+  '<h1>Executar um item de menu ou bot茫o da barra de ferramentas</h1>\n' +
+  '\n' +
+  '<p>Quando o item de menu ou o bot茫o da barra de ferramentas pretendido estiver real莽ado, prima <strong>Retrocesso</strong>, <strong>Enter</strong>\n' +
+  '  ou a <strong>Barra de espa莽o</strong> para executar o item.</p>\n' +
+  '\n' +
+  '<h1>Navegar em di谩logos sem separadores</h1>\n' +
+  '\n' +
+  '<p>Nos di谩logos sem separadores, o primeiro componente interativo fica em foco quando o di谩logo abre.</p>\n' +
+  '\n' +
+  '<p>Navegue entre componentes interativos do di谩logo, premindo <strong>Tab</strong> ou <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navegar em di谩logos com separadores</h1>\n' +
+  '\n' +
+  '<p>Nos di谩logos com separadores, o primeiro bot茫o no menu do separador fica em foco quando o di谩logo abre.</p>\n' +
+  '\n' +
+  '<p>Navegue entre os componentes interativos deste separador do di谩logo, premindo <strong>Tab</strong> ou\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Mude para outro separador do di谩logo colocando o menu do separador em foco e, em seguida, premindo a tecla de <strong>seta</strong>\n' +
+  '  adequada para se deslocar ciclicamente pelos separadores dispon铆veis.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ro.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ro.js
new file mode 100644
index 0000000..38d3441
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ro.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ro',
+'<h1>脦ncepe葲i navigarea de la tastatur膬</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Focalizare pe bara de meniu</dt>\n' +
+  '  <dd>Windows sau Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Focalizare pe bara de instrumente</dt>\n' +
+  '  <dd>Windows sau Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Focalizare pe subsol</dt>\n' +
+  '  <dd>Windows sau Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Focalizare pe notificare</dt>\n' +
+  '  <dd>Windows sau Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Focalizare pe o bar膬 de instrumente contextual膬</dt>\n' +
+  '  <dd>Windows, Linux sau macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigarea va 卯ncepe de la primul element al interfe葲ei cu utilizatorul, care va fi eviden葲iat sau subliniat 卯n cazul primului element din\n' +
+  '  calea elementului Subsol.</p>\n' +
+  '\n' +
+  '<h1>Naviga葲i 卯ntre sec葲iunile interfe葲ei cu utilizatorul</h1>\n' +
+  '\n' +
+  '<p>Pentru a trece de la o sec葲iune a interfe葲ei cu utilizatorul la alta, ap膬sa葲i <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Pentru a trece de la o sec葲iune a interfe葲ei cu utilizatorul la cea anterioar膬, ap膬sa葲i <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Ordinea cu <strong>Tab</strong> a acestor sec葲iuni ale interfe葲ei cu utilizatorul este urm膬toarea:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Bara de meniu</li>\n' +
+  '  <li>Fiecare grup de bare de instrumente</li>\n' +
+  '  <li>Bara lateral膬</li>\n' +
+  '  <li>Calea elementului 卯n subsol</li>\n' +
+  '  <li>Buton de comutare a num膬rului de cuvinte 卯n subsol</li>\n' +
+  '  <li>Link de branding 卯n subsol</li>\n' +
+  '  <li>M芒ner de redimensionare a editorului 卯n subsol</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>脦n cazul 卯n care o sec葲iune a interfe葲ei cu utilizatorul nu este prezent膬, aceasta este omis膬.</p>\n' +
+  '\n' +
+  '<p>脦n cazul 卯n care subsolul are focalizarea naviga葲iei asupra tastaturii 葯i nu exist膬 o bar膬 lateral膬 vizibil膬, ap膬sarea butonului <strong>Shift+Tab</strong>\n' +
+  '  mut膬 focalizarea pe primul grup de bare de instrumente, nu pe ultimul.</p>\n' +
+  '\n' +
+  '<h1>Naviga葲i 卯n sec葲iunile interfe葲ei cu utilizatorul</h1>\n' +
+  '\n' +
+  '<p>Pentru a trece de la un element de interfa葲膬 cu utilizatorul la urm膬torul, ap膬sa葲i tasta cu <strong>s膬geata</strong> corespunz膬toare.</p>\n' +
+  '\n' +
+  '<p>Tastele cu s膬ge葲i c膬tre <strong>st芒nga</strong> 葯i <strong>dreapta</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>navigheaz膬 卯ntre meniurile din bara de meniuri.</li>\n' +
+  '  <li>deschid un sub-meniu dintr-un meniu.</li>\n' +
+  '  <li>navigheaz膬 卯ntre butoanele dintr-un grup de bare de instrumente.</li>\n' +
+  '  <li>navigheaz膬 卯ntre elementele din calea elementelor subsolului.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tastele cu s膬ge葲i 卯n <strong>sus</strong> 葯i 卯n <strong>jos</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>navigheaz膬 卯ntre elementele de meniu dintr-un meniu.</li>\n' +
+  '  <li>navigheaz膬 卯ntre elementele unui meniu pop-up din bara de instrumente.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Tastele cu <strong>s膬ge葲i</strong> navigheaz膬 卯n cadrul sec葲iunii interfe葲ei cu utilizatorul asupra c膬reia se focalizeaz膬.</p>\n' +
+  '\n' +
+  '<p>Pentru a 卯nchide un meniu deschis, un sub-meniu deschis sau un meniu pop-up deschis, ap膬sa葲i tasta <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Dac膬 focalizarea curent膬 este asupra 鈥瀙膬r葲ii superioare鈥� a unei anumite sec葲iuni a interfe葲ei cu utilizatorul, prin ap膬sarea tastei <strong>Esc</strong> se iese, de asemenea,\n' +
+  '  卯n 卯ntregime din navigarea de la tastatur膬.</p>\n' +
+  '\n' +
+  '<h1>Executarea unui element de meniu sau a unui buton din bara de instrumente</h1>\n' +
+  '\n' +
+  '<p>Atunci c芒nd elementul de meniu dorit sau butonul dorit din bara de instrumente este eviden葲iat, ap膬sa葲i <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  sau <strong>bara de spa葲iu</strong> pentru a executa elementul.</p>\n' +
+  '\n' +
+  '<h1>Navigarea de dialoguri f膬r膬 file</h1>\n' +
+  '\n' +
+  '<p>脦n dialogurile f膬r膬 file, prima component膬 interactiv膬 beneficiaz膬 de focalizare la deschiderea dialogului.</p>\n' +
+  '\n' +
+  '<p>Naviga葲i 卯ntre componentele dialogului interactiv ap膬s芒nd <strong>Tab</strong> sau <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigarea de dialoguri cu file</h1>\n' +
+  '\n' +
+  '<p>脦n dialogurile cu file, primul buton din meniul cu file beneficiaz膬 de focalizare la deschiderea dialogului.</p>\n' +
+  '\n' +
+  '<p>Naviga葲i 卯ntre componentele interactive ale acestei file de dialog ap膬s芒nd <strong>Tab</strong> sau\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Trece葲i la o alt膬 fil膬 de dialog focaliz芒nd asupra meniului cu file 葯i apoi ap膬s芒nd <strong>s膬geata</strong> corespunz膬toare\n' +
+  '  pentru a parcurge filele disponibile.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ru.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ru.js
new file mode 100644
index 0000000..d310f54
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/ru.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.ru',
+'<h1>袧邪褔薪懈褌械 褍锌褉邪胁谢械薪懈械 褋 锌芯屑芯褖褜褞 泻谢邪胁懈邪褌褍褉褘</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 锌邪薪械谢懈 屑械薪褞</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 薪懈卸薪械屑 泻芯谢芯薪褌懈褌褍谢械</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 褍胁械写芯屑谢械薪懈懈</dt>\n' +
+  '  <dd>Windows 懈谢懈 Linux: Alt+12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 泻芯薪褌械泻褋褌薪芯泄 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁</dt>\n' +
+  '  <dd>Windows, Linux 懈谢懈 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>袩械褉胁褘泄 写芯褋褌褍锌薪褘泄 写谢褟 褍锌褉邪胁谢械薪懈褟 褝谢械屑械薪褌 懈薪褌械褉褎械泄褋邪 斜褍写械褌 胁褘写械谢械薪 褑胁械褌芯屑 懈谢懈 锌芯写褔械褉泻薪褍褌 (械褋谢懈 芯薪 薪邪褏芯写懈褌褋褟\n' +
+  '  胁 锌褍褌懈 褝谢械屑械薪褌芯胁 薪懈卸薪械谐芯 泻芯谢芯薪褌懈褌褍谢邪).</p>\n' +
+  '\n' +
+  '<h1>袩械褉械褏芯写 屑械卸写褍 褉邪蟹写械谢邪屑懈 锌芯谢褜蟹芯胁邪褌械谢褜褋泻芯谐芯 懈薪褌械褉褎械泄褋邪</h1>\n' +
+  '\n' +
+  '<p>效褌芯斜褘 锌械褉械泄褌懈 懈蟹 褌械泻褍褖械谐芯 褉邪蟹写械谢邪 懈薪褌械褉褎械泄褋邪 胁 褋谢械写褍褞褖懈泄, 薪邪卸屑懈褌械 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>效褌芯斜褘 锌械褉械泄褌懈 懈蟹 褌械泻褍褖械谐芯 褉邪蟹写械谢邪 懈薪褌械褉褎械泄褋邪 胁 锌褉械写褘写褍褖懈泄, 薪邪卸屑懈褌械 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>袙泻谢邪写泻懈</strong> 褉邪蟹写械谢芯胁 懈薪褌械褉褎械泄褋邪 褉邪褋锌芯谢芯卸械薪褘 胁 褋谢械写褍褞褖械屑 锌芯褉褟写泻械:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>袩邪薪械谢褜 屑械薪褞</li>\n' +
+  '  <li>袚褉褍锌锌褘 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁</li>\n' +
+  '  <li>袘芯泻芯胁邪褟 锌邪薪械谢褜</li>\n' +
+  '  <li>袩褍褌褜 褝谢械屑械薪褌芯胁 薪懈卸薪械谐芯 泻芯谢芯薪褌懈褌褍谢邪</li>\n' +
+  '  <li>袩芯写褋褔械褌 褋谢芯胁/褋懈屑胁芯谢芯胁 胁 薪懈卸薪械屑 泻芯谢芯薪褌懈褌褍谢械</li>\n' +
+  '  <li>袘褉械薪写芯胁邪褟 褋褋褘谢泻邪 胁 薪懈卸薪械屑 泻芯谢芯薪褌懈褌褍谢械</li>\n' +
+  '  <li>校谐芯谢 写谢褟 懈蟹屑械薪械薪懈褟 褉邪蟹屑械褉邪 芯泻薪邪 褉械写邪泻褌芯褉邪</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>袝褋谢懈 褉邪蟹写械谢 懈薪褌械褉褎械泄褋邪 芯褌褋褍褌褋褌胁褍械褌, 芯薪 锌褉芯锌褍褋泻邪械褌褋褟.</p>\n' +
+  '\n' +
+  '<p>袝褋谢懈 锌褉懈 褍锌褉邪胁谢械薪懈懈 褋 泻谢邪胁懈邪褌褍褉褘 褎芯泻褍褋 薪邪褏芯写懈褌褋褟 薪邪 薪懈卸薪械屑 泻芯谢芯薪褌懈褌褍谢械, 邪 胁懈写懈屑邪褟 斜芯泻芯胁邪褟 锌邪薪械谢褜 芯褌褋褍褌褋褌胁褍械褌, 褌芯 锌褉懈 薪邪卸邪褌懈懈 褋芯褔械褌邪薪懈褟 泻谢邪胁懈褕 <strong>Shift+Tab</strong>\n' +
+  '  褎芯泻褍褋 锌械褉械薪芯褋懈褌褋褟 薪邪 锌械褉胁褍褞 谐褉褍锌锌褍 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁, 邪 薪械 薪邪 锌芯褋谢械写薪褞褞.</p>\n' +
+  '\n' +
+  '<h1>袩械褉械褏芯写 屑械卸写褍 褝谢械屑械薪褌邪屑懈 胁薪褍褌褉懈 褉邪蟹写械谢芯胁 锌芯谢褜蟹芯胁邪褌械谢褜褋泻芯谐芯 懈薪褌械褉褎械泄褋邪</h1>\n' +
+  '\n' +
+  '<p>效褌芯斜褘 锌械褉械泄褌懈 芯褌 褌械泻褍褖械谐芯 褝谢械屑械薪褌邪 懈薪褌械褉褎械泄褋邪 泻 褋谢械写褍褞褖械屑褍, 薪邪卸屑懈褌械 褋芯芯褌胁械褌褋褌胁褍褞褖褍褞 <strong>泻谢邪胁懈褕褍 褋芯 褋褌褉械谢泻芯泄</strong>.</p>\n' +
+  '\n' +
+  '<p>袣谢邪胁懈褕懈 褋芯 褋褌褉械谢泻邪屑懈 <strong>胁谢械胁芯</strong> 懈 <strong>胁锌褉邪胁芯</strong> 锌芯蟹胁芯谢褟褞褌</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>锌械褉械屑械褖邪褌褜褋褟 屑械卸写褍 褉邪蟹薪褘屑懈 屑械薪褞 胁 锌邪薪械谢懈 屑械薪褞.</li>\n' +
+  '  <li>芯褌泻褉褘胁邪褌褜 褉邪蟹写械谢褘 屑械薪褞.</li>\n' +
+  '  <li>锌械褉械屑械褖邪褌褜褋褟 屑械卸写褍 泻薪芯锌泻邪屑懈 胁 谐褉褍锌锌械 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁.</li>\n' +
+  '  <li>锌械褉械屑械褖邪褌褜褋褟 屑械卸写褍 褝谢械屑械薪褌邪屑懈 胁 锌褍褌懈 褝谢械屑械薪褌芯胁 薪懈卸薪械谐芯 泻芯谢芯薪褌懈褌褍谢邪.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>袣谢邪胁懈褕懈 褋芯 褋褌褉械谢泻邪屑懈 <strong>胁薪懈蟹</strong> 懈 <strong>胁胁械褉褏</strong> 锌芯蟹胁芯谢褟褞褌</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>锌械褉械屑械褖邪褌褜褋褟 屑械卸写褍 褝谢械屑械薪褌邪屑懈 芯写薪芯谐芯 屑械薪褞.</li>\n' +
+  '  <li>锌械褉械屑械褖邪褌褜褋褟 屑械卸写褍 褝谢械屑械薪褌邪屑懈 胁褋锌谢褘胁邪褞褖械谐芯 屑械薪褞 胁 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>袩褉懈 懈褋锌芯谢褜蟹芯胁邪薪懈懈 <strong>泻谢邪胁懈褕 褋芯 褋褌褉械谢泻邪屑懈</strong> 胁褘 斜褍写械褌械 褑懈泻谢懈褔械褋泻懈 锌械褉械屑械褖邪褌褜褋褟 锌芯 褝谢械屑械薪褌邪屑 胁 锌褉械写械谢邪褏 胁褘斜褉邪薪薪芯谐芯 褉邪蟹写械谢邪 懈薪褌械褉褎械泄褋邪.</p>\n' +
+  '\n' +
+  '<p>效褌芯斜褘 蟹邪泻褉褘褌褜 芯褌泻褉褘褌芯械 屑械薪褞, 械谐芯 褉邪蟹写械谢 懈谢懈 胁褋锌谢褘胁邪褞褖械械 屑械薪褞, 薪邪卸屑懈褌械 泻谢邪胁懈褕褍 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>袝褋谢懈 褎芯泻褍褋 薪邪褏芯写懈褌褋褟 薪邪胁械褉褏褍 泻邪泻芯谐芯-谢懈斜芯 褉邪蟹写械谢邪 懈薪褌械褉褎械泄褋邪, 薪邪卸邪褌懈械 泻谢邪胁懈褕懈 <strong>Esc</strong> 褌邪泻卸械 锌褉懈胁械写械褌\n' +
+  '  泻 胁褘褏芯写褍 懈蟹 褉械卸懈屑邪 褍锌褉邪胁谢械薪懈褟 褋 锌芯屑芯褖褜褞 泻谢邪胁懈邪褌褍褉褘.</p>\n' +
+  '\n' +
+  '<h1>袠褋锌芯谢褜蟹芯胁邪薪懈械 褝谢械屑械薪褌邪 屑械薪褞 懈谢懈 泻薪芯锌泻懈 薪邪 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁</h1>\n' +
+  '\n' +
+  '<p>袣芯谐写邪 褝谢械屑械薪褌 屑械薪褞 懈谢懈 泻薪芯锌泻邪 锌邪薪械谢懈 懈薪褋褌褉褍屑械薪褌芯胁 斜褍写褍褌 胁褘写械谢械薪褘, 薪邪卸屑懈褌械 <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  懈谢懈 <strong>Space</strong>, 褔褌芯斜褘 懈褏 邪泻褌懈胁懈褉芯胁邪褌褜.</p>\n' +
+  '\n' +
+  '<h1>校锌褉邪胁谢械薪懈械 胁 写懈邪谢芯谐芯胁芯屑 芯泻薪械 斜械蟹 胁泻谢邪写芯泻</h1>\n' +
+  '\n' +
+  '<p>袩褉懈 芯褌泻褉褘褌懈懈 写懈邪谢芯谐芯胁芯谐芯 芯泻薪邪 斜械蟹 胁泻谢邪写芯泻 褎芯泻褍褋 锌械褉械薪芯褋懈褌褋褟 薪邪 锌械褉胁褘泄 懈薪褌械褉邪泻褌懈胁薪褘泄 泻芯屑锌芯薪械薪褌.</p>\n' +
+  '\n' +
+  '<p>袛谢褟 锌械褉械褏芯写邪 屑械卸写褍 懈薪褌械褉邪泻褌懈胁薪褘屑懈 泻芯屑锌芯薪械薪褌邪屑懈 写懈邪谢芯谐芯胁芯谐芯 芯泻薪邪 薪邪卸懈屑邪泄褌械 <strong>Tab</strong> 懈谢懈 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>校锌褉邪胁谢械薪懈械 胁 写懈邪谢芯谐芯胁芯屑 芯泻薪械 褋 胁泻谢邪写泻邪屑懈</h1>\n' +
+  '\n' +
+  '<p>袩褉懈 芯褌泻褉褘褌懈懈 写懈邪谢芯谐芯胁芯谐芯 芯泻薪邪 褋 胁泻谢邪写泻邪屑懈 褎芯泻褍褋 锌械褉械薪芯褋懈褌褋褟 薪邪 锌械褉胁褍褞 泻薪芯锌泻褍 胁 屑械薪褞 胁泻谢邪写芯泻.</p>\n' +
+  '\n' +
+  '<p>袛谢褟 锌械褉械褏芯写邪 屑械卸写褍 懈薪褌械褉邪泻褌懈胁薪褘屑懈 泻芯屑锌芯薪械薪褌邪屑懈 褝褌芯泄 胁泻谢邪写泻懈 写懈邪谢芯谐芯胁芯谐芯 芯泻薪邪 薪邪卸懈屑邪泄褌械 <strong>Tab</strong> 懈谢懈\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>袛谢褟 锌械褉械褏芯写邪 薪邪 写褉褍谐褍褞 胁泻谢邪写泻褍 写懈邪谢芯谐芯胁芯谐芯 芯泻薪邪 锌械褉械屑械褋褌懈褌械 褎芯泻褍褋 薪邪 屑械薪褞 胁泻谢邪写芯泻, 邪 蟹邪褌械屑 懈褋锌芯谢褜蟹褍泄褌械 <strong>泻谢邪胁懈褕懈 褋芯 褋褌褉械谢泻邪屑懈</strong>\n' +
+  '  写谢褟 褑懈泻谢懈褔械褋泻芯谐芯 锌械褉械泻谢褞褔械薪懈褟 屑械卸写褍 写芯褋褌褍锌薪褘屑懈 胁泻谢邪写泻邪屑懈.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sk.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sk.js
new file mode 100644
index 0000000..60cc628
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sk.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.sk',
+'<h1>Za膷铆name s聽navig谩ciou pomocou kl谩vesnice</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Prejs钮 na panel s聽ponukami</dt>\n' +
+  '  <dd>Windows alebo Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Prejs钮 na panel n谩strojov</dt>\n' +
+  '  <dd>Windows alebo Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Prejs钮 na p盲ti膷ku</dt>\n' +
+  '  <dd>Windows alebo Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Zaostri钮 na ozn谩menie</dt>\n' +
+  '  <dd>Windows alebo Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Prejs钮 na kontextov媒 panel n谩strojov</dt>\n' +
+  '  <dd>Windows, Linux alebo macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navig谩cia za膷ne pri prvej polo啪ke pou啪铆vate木sk茅ho rozhrania, ktor谩 bude zv媒raznen谩 alebo v聽pr铆pade prvej polo啪ky\n' +
+  '  cesty k聽p盲ti膷ke pod膷iarknut谩.</p>\n' +
+  '\n' +
+  '<h1>Navig谩cia medzi 膷as钮ami pou啪铆vate木sk茅ho rozhrania</h1>\n' +
+  '\n' +
+  '<p>Ak sa chcete posun煤钮 z聽jednej 膷asti pou啪铆vate木sk茅ho rozhrania do druhej, stla膷te tla膷idlo <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Ak sa chcete posun煤钮 z聽jednej 膷asti pou啪铆vate木sk茅ho rozhrania do predch谩dzaj煤cej, stla膷te tla膷idl谩 <strong>Shift + Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Poradie prep铆nania medzi t媒mito 膷as钮ami pou啪铆vate木sk茅ho rozhrania pri stl谩膷an铆 tla膷idla <strong>Tab</strong>:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Panel s聽ponukou</li>\n' +
+  '  <li>Ka啪d谩 skupina panela n谩strojov</li>\n' +
+  '  <li>Bo膷n媒 panel</li>\n' +
+  '  <li>Cesta k聽prvku v聽p盲ti膷ke</li>\n' +
+  '  <li>Prep铆na膷 po膷tu slov v聽p盲ti膷ke</li>\n' +
+  '  <li>Odkaz na inform谩cie o聽zna膷ke v聽p盲ti膷ke</li>\n' +
+  '  <li>脷chyt na zmenu ve木kosti editora v聽p盲ti膷ke</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Ak nejak谩 膷as钮 pou啪铆vate木sk茅ho rozhrania nie je pr铆tomn谩, presko膷铆 sa.</p>\n' +
+  '\n' +
+  '<p>Ak je p盲ti膷ka vybrat谩 na navig谩ciu pomocou kl谩vesnice a nie je vidite木n媒 bo膷n媒 panel, stla膷en铆m kl谩vesov <strong>Shift+Tab</strong>\n' +
+  '  prejdete na prv煤 skupinu panela n谩strojov, nie na posledn煤.</p>\n' +
+  '\n' +
+  '<h1>Navig谩cia v聽r谩mci 膷ast铆 pou啪铆vate木sk茅ho rozhrania</h1>\n' +
+  '\n' +
+  '<p>Ak sa chcete posun煤钮 z聽jedn茅ho prvku pou啪铆vate木sk茅ho rozhrania na 膹al拧铆, stla膷te pr铆slu拧n媒 kl谩ves so <strong>拧铆pkou</strong>.</p>\n' +
+  '\n' +
+  '<p>Kl谩vesy so 拧铆pkami <strong>do木ava</strong> a <strong>doprava</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umo啪艌uj煤 presun medzi ponukami na paneli pon煤k,</li>\n' +
+  '  <li>otv谩raj煤 podponuku v聽r谩mci ponuky,</li>\n' +
+  '  <li>umo啪艌uj煤 presun medzi tla膷idlami v聽skupine panelov n谩strojov,</li>\n' +
+  '  <li>umo啪艌uj煤 presun medzi polo啪kami cesty prvku v聽p盲ti膷ke.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Kl谩vesy so 拧铆pkami <strong>dole</strong> a <strong>hore</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>umo啪艌uj煤 presun medzi polo啪kami ponuky,</li>\n' +
+  '  <li>umo啪艌uj煤 presun medzi polo啪kami v聽kontextovej ponuke panela n谩strojov.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>Kl谩vesy so <strong>拧铆pkami</strong> vykon谩vaj煤 prep铆nanie v聽r谩mci vybranej 膷asti pou啪铆vate木sk茅ho rozhrania.</p>\n' +
+  '\n' +
+  '<p>Ak chcete zatvori钮 otvoren煤 ponuku, otvoren煤 podponuku alebo otvoren煤 kontextov煤 ponuku, stla膷te kl谩ves <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>Ak je aktu谩lne vybrat谩 horn谩 膷as钮 konkr茅tneho pou啪铆vate木sk茅ho rozhrania, stla膷en铆m kl谩vesu <strong>Esc</strong> 煤plne ukon膷铆te tie啪\n' +
+  '  navig谩ciu pomocou kl谩vesnice.</p>\n' +
+  '\n' +
+  '<h1>Vykonanie pr铆kazu polo啪ky ponuky alebo tla膷idla panela n谩strojov</h1>\n' +
+  '\n' +
+  '<p>Ke膹 je zv媒raznen谩 po啪adovan谩 polo啪ka ponuky alebo tla膷idlo panela n谩strojov, stla膷en铆m kl谩vesov <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  alebo <strong>medzern铆ka</strong> vykon谩te pr铆slu拧n媒 pr铆kaz polo啪ky.</p>\n' +
+  '\n' +
+  '<h1>Navig谩cia v聽dial贸gov媒ch okn谩ch bez z谩lo啪iek</h1>\n' +
+  '\n' +
+  '<p>Pri otvoren铆 dial贸gov媒ch okien bez z谩lo啪iek prejdete na prv媒 interakt铆vny komponent.</p>\n' +
+  '\n' +
+  '<p>Medzi interakt铆vnymi dial贸gov媒mi komponentmi m么啪ete prech谩dza钮 stla膷en铆m kl谩vesov <strong>Tab</strong> alebo <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navig谩cia v聽dial贸gov媒ch okn谩ch so z谩lo啪kami</h1>\n' +
+  '\n' +
+  '<p>Pri otvoren铆 dial贸gov媒ch okien so z谩lo啪kami prejdete na prv茅 tla膷idlo v聽ponuke z谩lo啪iek.</p>\n' +
+  '\n' +
+  '<p>Medzi interakt铆vnymi komponentmi tejto dial贸govej z谩lo啪ky m么啪ete prech谩dza钮 stla膷en铆m kl谩vesov <strong>Tab</strong> alebo\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Ak chcete prepn煤钮 na 膹al拧iu z谩lo啪ku dial贸gov茅ho okna, prejdite do ponuky z谩lo啪iek a聽potom m么啪ete stla膷en铆m pr铆slu拧n茅ho kl谩vesu so <strong>拧铆pkou</strong>\n' +
+  '  prep铆na钮 medzi dostupn媒mi z谩lo啪kami.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sl_SI.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sl_SI.js
new file mode 100644
index 0000000..2b25f5a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sl_SI.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.sl_SI',
+'<h1>Za膷etek krmarjenja s tipkovnico</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokus na menijsko vrstico</dt>\n' +
+  '  <dd>Windows ali Linux: Alt + F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokus na orodno vrstico</dt>\n' +
+  '  <dd>Windows ali Linux: Alt + F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokus na nogo</dt>\n' +
+  '  <dd>Windows ali Linux: Alt + F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Ozna膷itev obvestila</dt>\n' +
+  '  <dd>Windows ali Linux: Alt + F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokus na kontekstualno orodno vrstico</dt>\n' +
+  '  <dd>Windows, Linux ali macOS: Ctrl + F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Krmarjenje se bo za膷elo s prvim elementom uporabni拧kega vmesnika, ki bo izpostavljena ali pod膷rtan, 膷e gre za prvi element na\n' +
+  '  poti do elementa noge.</p>\n' +
+  '\n' +
+  '<h1>Krmarjenje med razdelki uporabni拧kega vmesnika</h1>\n' +
+  '\n' +
+  '<p>膶e se 啪elite pomakniti z enega dela uporabni拧kega vmesnika na naslednjega, pritisnite <strong>tabulatorko</strong>.</p>\n' +
+  '\n' +
+  '<p>膶e se 啪elite pomakniti z enega dela uporabni拧kega vmesnika na prej拧njega, pritisnite <strong>shift + tabulatorko</strong>.</p>\n' +
+  '\n' +
+  '<p>Zaporedje teh razdelkov uporabni拧kega vmesnika, ko pritiskate <strong>tabulatorko</strong>, je:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menijska vrstica</li>\n' +
+  '  <li>Posamezne skupine orodne vrstice</li>\n' +
+  '  <li>Stranska vrstica</li>\n' +
+  '  <li>Pod do elementa v nogi</li>\n' +
+  '  <li>Gumb za preklop 拧tetja besed v nogi</li>\n' +
+  '  <li>Povezava do blagovne znamke v nogi</li>\n' +
+  '  <li>Ro膷aj za spreminjanje velikosti urejevalnika v nogi</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>膶e razdelek uporabni拧kega vmesnika ni prisoten, je presko膷en.</p>\n' +
+  '\n' +
+  '<p>膶e ima noga fokus za krmarjenje s tipkovnico in ni vidne stranske vrstice, s pritiskom na <strong>shift + tabulatorko</strong>\n' +
+  '  fokus premaknete na prvo skupino orodne vrstice, ne zadnjo.</p>\n' +
+  '\n' +
+  '<h1>Krmarjenje v razdelkih uporabni拧kega vmesnika</h1>\n' +
+  '\n' +
+  '<p>膶e se 啪elite premakniti z enega elementa uporabni拧kega vmesnika na naslednjega, pritisnite ustrezno <strong>pu拧膷i膷no</strong> tipko.</p>\n' +
+  '\n' +
+  '<p><strong>Leva</strong> in <strong>desna</strong> pu拧膷i膷na tipka</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>omogo膷ata premikanje med meniji v menijski vrstici.</li>\n' +
+  '  <li>odpreta podmeni v meniju.</li>\n' +
+  '  <li>omogo膷ata premikanje med gumbi v skupini orodne vrstice.</li>\n' +
+  '  <li>omogo膷ata premikanje med elementi na poti do elementov noge.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Spodnja</strong> in <strong>zgornja</strong> pu拧膷i膷na tipka</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>omogo膷ata premikanje med elementi menija.</li>\n' +
+  '  <li>omogo膷ata premikanje med elementi v pojavnem meniju orodne vrstice.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Pu拧膷i膷ne</strong> tipke omogo膷ajo kro啪enje znotraj razdelka uporabni拧kega vmesnika, na katerem je fokus.</p>\n' +
+  '\n' +
+  '<p>膶e 啪elite zapreti odprt meni, podmeni ali pojavni meni, pritisnite tipko <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>膶e je trenutni fokus na 禄vrhu芦 dolo膷enega razdelka uporabni拧kega vmesnika, s pritiskom tipke <strong>Esc</strong> zaprete\n' +
+  '  tudi celotno krmarjenje s tipkovnico.</p>\n' +
+  '\n' +
+  '<h1>Izvajanje menijskega elementa ali gumba orodne vrstice</h1>\n' +
+  '\n' +
+  '<p>Ko je ozna膷en 啪eleni menijski element ali orodja vrstica, pritisnite <strong>vra膷alko</strong>, <strong>Enter</strong>\n' +
+  '  ali <strong>preslednico</strong>, da izvedete element.</p>\n' +
+  '\n' +
+  '<h1>Krmarjenje po pogovornih oknih brez zavihkov</h1>\n' +
+  '\n' +
+  '<p>Ko odprete pogovorno okno brez zavihkov, ima fokus prva interaktivna komponenta.</p>\n' +
+  '\n' +
+  '<p>Med interaktivnimi komponentami pogovornega okna se premikate s pritiskom <strong>tabulatorke</strong> ali kombinacije tipke <strong>shift + tabulatorke</strong>.</p>\n' +
+  '\n' +
+  '<h1>Krmarjenje po pogovornih oknih z zavihki</h1>\n' +
+  '\n' +
+  '<p>Ko odprete pogovorno okno z zavihki, ima fokus prvi gumb v meniju zavihka.</p>\n' +
+  '\n' +
+  '<p>Med interaktivnimi komponentami tega zavihka pogovornega okna se premikate s pritiskom <strong>tabulatorke</strong> ali\n' +
+  '  kombinacije tipke <strong>shift + tabulatorke</strong>.</p>\n' +
+  '\n' +
+  '<p>Na drug zavihek pogovornega okna preklopite tako, da fokus prestavite na meni zavihka in nato pritisnete ustrezno <strong>pu拧膷i膷no</strong>\n' +
+  '  tipko, da se pomaknete med razpolo啪ljivimi zavihki.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sv_SE.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sv_SE.js
new file mode 100644
index 0000000..c30f2f2
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/sv_SE.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.sv_SE',
+'<h1>P氓b枚rja tangentbordsnavigering</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Fokusera p氓 menyraden</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Fokusera p氓 verktygsraden</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Fokusera p氓 verktygsraden</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Fokusera aviseringen</dt>\n' +
+  '  <dd>Windows eller Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Fokusera p氓 en snabbverktygsrad</dt>\n' +
+  '  <dd>Windows, Linux eller macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Navigeringen b枚rjar vid det f枚rsta gr盲nssnittsobjektet, vilket 盲r markerat eller understruket om det g盲ller det f枚rsta objektet i\n' +
+  '  sidfotens elements枚kv盲g.</p>\n' +
+  '\n' +
+  '<h1>Navigera mellan UI-avsnitt</h1>\n' +
+  '\n' +
+  '<p>Flytta fr氓n ett UI-avsnitt till n盲sta genom att trycka p氓 <strong>Tabb</strong>.</p>\n' +
+  '\n' +
+  '<p>Flytta fr氓n ett UI-avsnitt till det f枚reg氓ende genom att trycka p氓 <strong>Skift+Tabb</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>Tabb</strong>-ordningen f枚r dessa UI-avsnitt 盲r:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Menyrad</li>\n' +
+  '  <li>Varje verktygsradsgrupp</li>\n' +
+  '  <li>Sidoruta</li>\n' +
+  '  <li>Elements枚kv盲g i sidfoten</li>\n' +
+  '  <li>V盲xlingsknapp f枚r ordantal i sidfoten</li>\n' +
+  '  <li>Varum盲rkesl盲nk i sidfoten</li>\n' +
+  '  <li>Storlekshandtag f枚r redigeraren i sidfoten</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Om ett UI-avsnitt inte finns hoppas det 枚ver.</p>\n' +
+  '\n' +
+  '<p>Om sidfoten har fokus p氓 tangentbordsnavigering, och det inte finns n氓gon synlig sidoruta, flyttas fokus till den f枚rsta verktygsradsgruppen\n' +
+  '  n盲r du trycker p氓 <strong>Skift+Tabb</strong>, inte till den sista.</p>\n' +
+  '\n' +
+  '<h1>Navigera i UI-avsnitt</h1>\n' +
+  '\n' +
+  '<p>Flytta fr氓n ett UI-element till n盲sta genom att trycka p氓 motsvarande <strong>piltangent</strong>.</p>\n' +
+  '\n' +
+  '<p><strong>V盲nsterpil</strong> och <strong>h枚gerpil</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytta mellan menyer p氓 menyraden.</li>\n' +
+  '  <li>枚ppna en undermeny p氓 en meny.</li>\n' +
+  '  <li>flytta mellan knappar i en verktygsradgrupp.</li>\n' +
+  '  <li>flytta mellan objekt i sidfotens elements枚kv盲g.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Nedpil</strong> och <strong>uppil</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>flytta mellan menyalternativ p氓 en meny.</li>\n' +
+  '  <li>flytta mellan alternativ p氓 en popup-meny p氓 verktygsraden.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Piltangenterna</strong> cirkulerar inom det fokuserade UI-avsnittet.</p>\n' +
+  '\n' +
+  '<p>Tryck p氓 <strong>Esc</strong>-tangenten om du vill st盲nga en 枚ppen meny, undermeny eller popup-meny.</p>\n' +
+  '\n' +
+  '<p>Om det aktuella fokuset 盲r h枚gst upp i ett UI-avsnitt avlutas 盲ven tangentbordsnavigeringen helt n盲r\n' +
+  '  du trycker p氓 <strong>Esc</strong>-tangenten.</p>\n' +
+  '\n' +
+  '<h1>K枚ra ett menyalternativ eller en verktygf盲ltsknapp</h1>\n' +
+  '\n' +
+  '<p>N盲r menyalternativet eller verktygsradsknappen 盲r markerad trycker du p氓 <strong>Retur</strong>, <strong>Enter</strong>\n' +
+  '  eller <strong>blanksteg</strong> f枚r att k枚ra alternativet.</p>\n' +
+  '\n' +
+  '<h1>Navigera i dialogrutor utan flikar</h1>\n' +
+  '\n' +
+  '<p>I dialogrutor utan flikar 盲r den f枚rsta interaktiva komponenten i fokus n盲r dialogrutan 枚ppnas.</p>\n' +
+  '\n' +
+  '<p>Navigera mellan interaktiva dialogkomponenter genom att trycka p氓 <strong>Tabb</strong> eller <strong>Skift+Tabb</strong>.</p>\n' +
+  '\n' +
+  '<h1>Navigera i dialogrutor med flikar</h1>\n' +
+  '\n' +
+  '<p>I dialogrutor utan flikar 盲r den f枚rsta knappen p氓 flikmenyn i fokus n盲r dialogrutan 枚ppnas.</p>\n' +
+  '\n' +
+  '<p>Navigera mellan interaktiva komponenter p氓 dialogrutefliken genom att trycka p氓 <strong>Tabb</strong> eller\n' +
+  '  <strong>Skift+Tabb</strong>.</p>\n' +
+  '\n' +
+  '<p>V盲xla till en annan dialogruta genom att fokusera p氓 flikmenyn och sedan trycka p氓 motsvarande <strong>piltangent</strong>\n' +
+  '  f枚r att cirkulera mellan de tillg盲ngliga flikarna.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/th_TH.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/th_TH.js
new file mode 100644
index 0000000..562fe7a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/th_TH.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.th_TH',
+'<h1>喙�喔`复喙堗浮喔曕箟喔權竵喔侧福喔權赋喔椸覆喔囙笖喙夃抚喔⑧箒喔涏箟喔權笧喔脆浮喔炧箤</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>喙傕笩喔佮副喔笚喔掂箞喙佮笘喔氞箑喔∴笝喔�</dt>\n' +
+  '  <dd>Windows 喔福喔粪腑 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>喙傕笩喔佮副喔笚喔掂箞喙佮笘喔氞箑喔勦福喔粪箞喔竾喔∴阜喔�</dt>\n' +
+  '  <dd>Windows 喔福喔粪腑 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>喙傕笩喔佮副喔笚喔掂箞喔箞喔о笝喔椸箟喔侧涪</dt>\n' +
+  '  <dd>Windows 喔福喔粪腑 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>喙傕笩喔佮副喔箘喔涏笚喔掂箞喔佮覆喔`箒喔堗箟喔囙箑喔曕阜喔笝</dt>\n' +
+  '  <dd>Windows 喔福喔粪腑 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>喙傕笩喔佮副喔笚喔掂箞喙佮笘喔氞箑喔勦福喔粪箞喔竾喔∴阜喔笗喔侧浮喔氞福喔脆笟喔�</dt>\n' +
+  '  <dd>Windows, Linux 喔福喔粪腑 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>喔佮覆喔`笝喔赤笚喔侧竾喔堗赴喙�喔`复喙堗浮喔椸傅喙堗福喔侧涪喔佮覆喔� UI 喙佮福喔� 喔嬥付喙堗竾喔堗赴喔∴傅喔佮覆喔`箘喔箘喔ム笗喙屶斧喔`阜喔競喔掂笖喙�喔箟喔權箖喔曕箟喙勦抚喙夃箖喔權竵喔`笓喔掂笚喔掂箞喔`覆喔⑧竵喔侧福喙佮福喔佮腑喔⑧腹喙堗箖喔橽n' +
+  '  喔炧覆喔樴腑喔囙竸喙屶笡喔`赴喔佮腑喔氞釜喙堗抚喔權笚喙夃覆喔�</p>\n' +
+  '\n' +
+  '<h1>喔佮覆喔`笝喔赤笚喔侧竾喔`赴喔抚喙堗覆喔囙釜喙堗抚喔權笗喙堗覆喔囙箚 喔傕腑喔� UI</h1>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮覆喔`涪喙夃覆喔⑧笀喔侧竵喔箞喔о笝 UI 喔笝喔多箞喔囙箘喔涏涪喔编竾喔箞喔о笝喔栢副喔斷箘喔� 喙冟斧喙夃竵喔� <strong>Tab</strong></p>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮覆喔`涪喙夃覆喔⑧笀喔侧竵喔箞喔о笝 UI 喔笝喔多箞喔囙箘喔涏涪喔编竾喔箞喔о笝喔佮箞喔笝喔笝喙夃覆 喙冟斧喙夃竵喔� <strong>Shift+Tab</strong></p>\n' +
+  '\n' +
+  '<p>喔ム赋喔斷副喔�<strong>喙佮笚喙囙笟</strong>喔傕腑喔囙釜喙堗抚喔權笗喙堗覆喔囙箚 喔傕腑喔� UI 喔勦阜喔�:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>喙佮笘喔氞箑喔∴笝喔�</li>\n' +
+  '  <li>喙佮笗喙堗弗喔班竵喔ム父喙堗浮喙佮笘喔氞箑喔勦福喔粪箞喔竾喔∴阜喔�</li>\n' +
+  '  <li>喙佮笘喔氞競喙夃覆喔�</li>\n' +
+  '  <li>喔炧覆喔樴腑喔囙竸喙屶笡喔`赴喔佮腑喔氞箖喔權釜喙堗抚喔權笚喙夃覆喔�</li>\n' +
+  '  <li>喔涏父喙堗浮喔弗喔编笟喙�喔涏复喔�/喔涏复喔斷笀喔赤笝喔о笝喔勦赋喙冟笝喔箞喔о笝喔椸箟喔侧涪</li>\n' +
+  '  <li>喔ム复喔囙竵喙屶笂喔粪箞喔箒喔氞福喔權笖喙屶箖喔權釜喙堗抚喔權笚喙夃覆喔�</li>\n' +
+  '  <li>喔堗父喔斷笀喔编笟喔涏福喔编笟喔傕笝喔侧笖喔傕腑喔囙笗喔编抚喙佮竵喙夃箘喔傕箖喔權釜喙堗抚喔權笚喙夃覆喔�</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>喔覆喔佮釜喙堗抚喔� UI 喙勦浮喙堗笡喔`覆喔佮笍 喙佮釜喔斷竾喔о箞喔侧笘喔灌竵喔傕箟喔侧浮喙勦笡</p>\n' +
+  '\n' +
+  '<p>喔覆喔佮釜喙堗抚喔權笚喙夃覆喔⑧浮喔掂竵喔侧福喙傕笩喔佮副喔竵喔侧福喔權赋喔椸覆喔囙箒喔涏箟喔權笧喔脆浮喔炧箤喙佮弗喔班箘喔∴箞喔∴傅喙佮笘喔氞競喙夃覆喔囙笡喔`覆喔佮笍 喔佮覆喔`竵喔� <strong>Shift+Tab</strong>\n' +
+  '  喔堗赴喔⑧箟喔侧涪喔佮覆喔`箓喔熰竵喔编釜喙勦笡喔椸傅喙堗竵喔ム父喙堗浮喙佮笘喔氞箑喔勦福喔粪箞喔竾喔∴阜喔箒喔`竵 喙勦浮喙堗箖喔娻箞喔父喔斷笚喙夃覆喔�</p>\n' +
+  '\n' +
+  '<h1>喔佮覆喔`笝喔赤笚喔侧竾喔犩覆喔⑧箖喔權釜喙堗抚喔權笗喙堗覆喔囙箚 喔傕腑喔� UI</h1>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮覆喔`涪喙夃覆喔⑧笀喔侧竵喔竾喔勦箤喔涏福喔班竵喔笟 UI 喔笝喔多箞喔囙箘喔涏涪喔编竾喔竾喔勦箤喔涏福喔班竵喔笟喔箞喔о笝喔栢副喔斷箘喔� 喙冟斧喙夃竵喔斷笡喔膏箞喔�<strong>喔ム腹喔佮辅喔�</strong>喔椸傅喙堗箑喔浮喔侧赴喔浮</p>\n' +
+  '\n' +
+  '<p>喔涏父喙堗浮喔ム腹喔佮辅喔�<strong>喔嬥箟喔侧涪</strong>喙佮弗喔�<strong>喔傕抚喔�</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>喔⑧箟喔侧涪喙勦笡喔∴覆喔`赴喔抚喙堗覆喔囙箑喔∴笝喔灌笗喙堗覆喔囙箚 喙冟笝喙佮笘喔氞箑喔∴笝喔�</li>\n' +
+  '  <li>喙�喔涏复喔斷箑喔∴笝喔灌涪喙堗腑喔⑧箖喔權箑喔∴笝喔�</li>\n' +
+  '  <li>喔⑧箟喔侧涪喙勦笡喔∴覆喔`赴喔抚喙堗覆喔囙笡喔膏箞喔∴笗喙堗覆喔囙箚 喙冟笝喔佮弗喔膏箞喔∴箒喔栢笟喙�喔勦福喔粪箞喔竾喔∴阜喔�</li>\n' +
+  '  <li>喔⑧箟喔侧涪喙勦笡喔∴覆喔`赴喔抚喙堗覆喔囙福喔侧涪喔佮覆喔`笗喙堗覆喔囙箚 喙冟笝喔炧覆喔樴腑喔囙竸喙屶笡喔`赴喔佮腑喔氞競喔竾喔箞喔о笝喔椸箟喔侧涪</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>喔涏父喙堗浮喔ム腹喔佮辅喔�<strong>喔ム竾</strong>喙佮弗喔�<strong>喔傕付喙夃笝</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>喔⑧箟喔侧涪喙勦笡喔∴覆喔`赴喔抚喙堗覆喔囙福喔侧涪喔佮覆喔`箑喔∴笝喔灌笗喙堗覆喔囙箚 喙冟笝喙�喔∴笝喔�</li>\n' +
+  '  <li>喔⑧箟喔侧涪喙勦笡喔∴覆喔`赴喔抚喙堗覆喔囙福喔侧涪喔佮覆喔`笗喙堗覆喔囙箚 喙冟笝喙�喔∴笝喔灌笡喙娻腑喔氞腑喔编笧喙佮笘喔氞箑喔勦福喔粪箞喔竾喔∴阜喔�</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>喔涏父喙堗浮<strong>喔ム腹喔佮辅喔�</strong>喔堗赴喙�喔ム阜喙堗腑喔權箘喔涏浮喔侧笭喔侧涪喙冟笝喔箞喔о笝 UI 喔椸傅喙堗箓喔熰竵喔编釜</p>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮覆喔`笡喔脆笖喙�喔∴笝喔灌笚喔掂箞喙�喔涏复喔斷腑喔⑧腹喙� 喙�喔∴笝喔灌涪喙堗腑喔⑧笚喔掂箞喙�喔涏复喔斷腑喔⑧腹喙� 喔福喔粪腑喙�喔∴笝喔灌笡喙娻腑喔氞腑喔编笧喔椸傅喙堗箑喔涏复喔斷腑喔⑧腹喙� 喙冟斧喙夃竵喔斷笡喔膏箞喔� <strong>Esc</strong></p>\n' +
+  '\n' +
+  '<p>喔覆喔佮箓喔熰竵喔编釜喔涏副喔堗笀喔膏笟喔编笝喔涪喔灌箞喔椸傅喙� 鈥樴笖喙夃覆喔權笟喔權釜喔膏笖鈥� 喔傕腑喔囙釜喙堗抚喔� UI 喙�喔夃笧喔侧赴 喔佮覆喔`竵喔斷笡喔膏箞喔� <strong>Esc</strong> 喔堗赴喔椸赋喙冟斧喙夃腑喔竵喔堗覆喔乗n' +
+  '  喔佮覆喔`笝喔赤笚喔侧竾喔斷箟喔о涪喙佮笡喙夃笝喔炧复喔∴笧喙屶笚喔编箟喔囙斧喔∴笖喙�喔娻箞喔權竵喔编笝</p>\n' +
+  '\n' +
+  '<h1>喔佮覆喔`笖喔赤箑喔權复喔權竵喔侧福喔`覆喔⑧竵喔侧福喙�喔∴笝喔灌斧喔`阜喔笡喔膏箞喔∴箖喔權箒喔栢笟喙�喔勦福喔粪箞喔竾喔∴阜喔�</h1>\n' +
+  '\n' +
+  '<p>喙�喔∴阜喙堗腑喙勦府喙勦弗喔曕箤喔`覆喔⑧竵喔侧福喙�喔∴笝喔灌斧喔`阜喔笡喔膏箞喔∴箖喔權箒喔栢笟喙�喔勦福喔粪箞喔竾喔∴阜喔笚喔掂箞喔曕箟喔竾喔佮覆喔� 喙冟斧喙夃竵喔� <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  喔福喔粪腑 <strong>Space bar</strong> 喙�喔炧阜喙堗腑喔斷赋喙�喔權复喔權竵喔侧福喔`覆喔⑧竵喔侧福喔斷副喔囙竵喔ム箞喔侧抚</p>\n' +
+  '\n' +
+  '<h1>喔佮覆喔`笝喔赤笚喔侧竾喔赋喔福喔编笟喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞笚喔掂箞喙勦浮喙堗腑喔⑧腹喙堗箖喔權箒喔椸箛喔�</h1>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞笚喔掂箞喙勦浮喙堗腑喔⑧腹喙堗箖喔權箒喔椸箛喔� 喔堗赴喙傕笩喔佮副喔笚喔掂箞喔箞喔о笝喔涏福喔班竵喔笟喙�喔娻复喔囙箓喔曕箟喔曕腑喔氞箒喔`竵喙�喔∴阜喙堗腑喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞箑喔涏复喔�</p>\n' +
+  '\n' +
+  '<p>喔權赋喔椸覆喔囙福喔班斧喔о箞喔侧竾喔箞喔о笝喔涏福喔班竵喔笟喙�喔娻复喔囙箓喔曕箟喔曕腑喔氞笗喙堗覆喔囙箚 喔傕腑喔囙竵喔ム箞喔竾喙傕笗喙夃笗喔笟 喙傕笖喔⑧竵喔侧福喔佮笖 <strong>Tab</strong> 喔福喔粪腑 <strong>Shift+Tab</strong></p>\n' +
+  '\n' +
+  '<h1>喔佮覆喔`笝喔赤笚喔侧竾喔赋喔福喔编笟喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞笚喔掂箞喔涪喔灌箞喙冟笝喙佮笚喙囙笟</h1>\n' +
+  '\n' +
+  '<p>喙冟笝喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞笚喔掂箞喔涪喔灌箞喙冟笝喙佮笚喙囙笟 喔堗赴喙傕笩喔佮副喔笚喔掂箞喔涏父喙堗浮喙佮福喔佮箖喔權箑喔∴笝喔灌箒喔椸箛喔氞箑喔∴阜喙堗腑喔佮弗喙堗腑喔囙箓喔曕箟喔曕腑喔氞箑喔涏复喔�</p>\n' +
+  '\n' +
+  '<p>喔權赋喔椸覆喔囙福喔班斧喔о箞喔侧竾喔箞喔о笝喔涏福喔班竵喔笟喙�喔娻复喔囙箓喔曕箟喔曕腑喔氞笗喙堗覆喔囙箚 喔傕腑喔囙箒喔椸箛喔氞竵喔ム箞喔竾喙傕笗喙夃笗喔笟喔權傅喙夃箓喔斷涪喔佮覆喔`竵喔� <strong>Tab</strong> 喔福喔粪腑\n' +
+  '  <strong>Shift+Tab</strong></p>\n' +
+  '\n' +
+  '<p>喔弗喔编笟喙勦笡喔⑧副喔囙箒喔椸箛喔氞竵喔ム箞喔竾喙傕笗喙夃笗喔笟喔阜喙堗笝喙傕笖喔⑧竵喔侧福喙�喔ム阜喔竵喙傕笩喔佮副喔笚喔掂箞喙�喔∴笝喔灌箒喔椸箛喔� 喙佮弗喙夃抚喔佮笖喔涏父喙堗浮<strong>喔ム腹喔佮辅喔�</strong>喔椸傅喙堗箑喔浮喔侧赴喔浮\n' +
+  '  喙�喔炧阜喙堗腑喙�喔ム阜喔竵喙佮笚喙囙笟喔椸傅喙堗箖喔娻箟喙勦笖喙�</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/tr.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/tr.js
new file mode 100644
index 0000000..37f39b0
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/tr.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.tr',
+'<h1>Klavyeyle gezintiyi ba艧latma</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>Men眉 莽ubu臒una odaklan</dt>\n' +
+  '  <dd>Windows veya Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>Ara莽 莽ubu臒una odaklan</dt>\n' +
+  '  <dd>Windows veya Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>Alt bilgiye odaklan</dt>\n' +
+  '  <dd>Windows veya Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>Bildirime odakla</dt>\n' +
+  '  <dd>Windows veya Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>Ba臒lamsal ara莽 莽ubu臒una odaklan</dt>\n' +
+  '  <dd>Windows, Linux veya macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>Gezinti ilk kullan谋c谋 arabirimi 枚臒esinden ba艧lar, bu 枚臒e vurgulan谋r ya da ilk 枚臒e, Alt bilgi eleman谋\n' +
+  '  yolundaysa alt谋 莽izilir.</p>\n' +
+  '\n' +
+  '<h1>Kullan谋c谋 arabirimi b枚l眉mleri aras谋nda gezinme</h1>\n' +
+  '\n' +
+  '<p>Sonraki kullan谋c谋 arabirimi b枚l眉m眉ne gitmek i莽in <strong>Sekme</strong> tu艧una bas谋n.</p>\n' +
+  '\n' +
+  '<p>脰nceki kullan谋c谋 arabirimi b枚l眉m眉ne gitmek i莽in <strong>Shift+Sekme</strong> tu艧lar谋na bas谋n.</p>\n' +
+  '\n' +
+  '<p>Bu kullan谋c谋 arabirimi b枚l眉mlerinin <strong>Sekme</strong> s谋ras谋:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Men眉 莽ubu臒u</li>\n' +
+  '  <li>Her ara莽 莽ubu臒u grubu</li>\n' +
+  '  <li>Kenar 莽ubu臒u</li>\n' +
+  '  <li>Alt bilgide 枚臒e yolu</li>\n' +
+  '  <li>Alt bilgide s枚zc眉k say谋s谋 ge莽i艧 d眉臒mesi</li>\n' +
+  '  <li>Alt bilgide marka ba臒lant谋s谋</li>\n' +
+  '  <li>Alt bilgide d眉zenleyiciyi yeniden boyutland谋rma tutamac谋</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>Kullan谋c谋 arabirimi b枚l眉m眉 yoksa atlan谋r.</p>\n' +
+  '\n' +
+  '<p>Alt bilgide klavyeyle gezinti oda臒谋 yoksa ve g枚r眉n眉r bir kenar 莽ubu臒u mevcut de臒ilse <strong>Shift+Sekme</strong> tu艧lar谋na bas谋ld谋臒谋nda\n' +
+  '  odak son ara莽 莽ubu臒u yerine ilk ara莽 莽ubu臒u grubuna ta艧谋n谋r.</p>\n' +
+  '\n' +
+  '<h1>Kullan谋c谋 arabirimi b枚l眉mleri i莽inde gezinme</h1>\n' +
+  '\n' +
+  '<p>Sonraki kullan谋c谋 arabirimi eleman谋na gitmek i莽in uygun <strong>Ok</strong> tu艧una bas谋n.</p>\n' +
+  '\n' +
+  '<p><strong>Sol</strong> ve <strong>Sa臒</strong> ok tu艧lar谋</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>men眉 莽ubu臒undaki men眉ler aras谋nda hareket eder.</li>\n' +
+  '  <li>men眉de bir alt men眉 a莽ar.</li>\n' +
+  '  <li>ara莽 莽ubu臒u grubundaki d眉臒meler aras谋nda hareket eder.</li>\n' +
+  '  <li>alt bilginin 枚臒e yolundaki 枚臒eler aras谋nda hareket eder.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>A艧a臒谋</strong> ve <strong>Yukar谋</strong> ok tu艧lar谋</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>men眉deki men眉 枚臒eleri aras谋nda hareket eder.</li>\n' +
+  '  <li>ara莽 莽ubu臒u a莽谋l谋r men眉s眉ndeki 枚臒eler aras谋nda hareket eder.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>Ok</strong> tu艧lar谋, odaklan谋lan kullan谋c谋 arabirimi b枚l眉m眉 i莽inde d枚ng眉sel olarak hareket eder.</p>\n' +
+  '\n' +
+  '<p>A莽谋k bir men眉y眉, a莽谋k bir alt men眉y眉 veya a莽谋k bir a莽谋l谋r men眉y眉 kapatmak i莽in <strong>Esc</strong> tu艧una bas谋n.</p>\n' +
+  '\n' +
+  '<p>Ge莽erli odak belirli bir kullan谋c谋 arabirimi b枚l眉m眉n眉n "眉st" k谋sm谋ndaysa <strong>Esc</strong> tu艧una bas谋ld谋臒谋nda\n' +
+  '  klavyeyle gezintiden de tamamen 莽谋k谋l谋r.</p>\n' +
+  '\n' +
+  '<h1>Men眉 枚臒esini veya ara莽 莽ubu臒u d眉臒mesini y眉r眉tme</h1>\n' +
+  '\n' +
+  '<p>陌stedi臒iniz men眉 枚臒esi veya ara莽 莽ubu臒u d眉臒mesi vurguland谋臒谋nda <strong>Return</strong>, <strong>Enter</strong>\n' +
+  '  veya <strong>Ara 莽ubu臒u</strong> tu艧una bas谋n.</p>\n' +
+  '\n' +
+  '<h1>Sekme bulunmayan ileti艧im kutular谋nda gezinme</h1>\n' +
+  '\n' +
+  '<p>Sekme bulunmayan ileti艧im kutular谋nda, ileti艧im kutusu a莽谋ld谋臒谋nda ilk etkile艧imli bile艧ene odaklan谋l谋r.</p>\n' +
+  '\n' +
+  '<p>Etkile艧imli ileti艧im kutusu bile艧enleri aras谋nda gezinmek i莽in <strong>Sekme</strong> veya <strong>Shift+ Sekme</strong> tu艧lar谋na bas谋n.</p>\n' +
+  '\n' +
+  '<h1>Sekmeli ileti艧im kutular谋nda gezinme</h1>\n' +
+  '\n' +
+  '<p>Sekmeli ileti艧im kutular谋nda, ileti艧im kutusu a莽谋ld谋臒谋nda sekme men眉s眉ndeki ilk d眉臒meye odaklan谋l谋r.</p>\n' +
+  '\n' +
+  '<p>Bu ileti艧im kutusu sekmesinin etkile艧imli bile艧enleri aras谋nda gezinmek i莽in <strong>Sekme</strong> veya\n' +
+  '  <strong>Shift+Sekme</strong> tu艧lar谋na bas谋n.</p>\n' +
+  '\n' +
+  '<p>Mevcut sekmeler aras谋nda ge莽i艧 yapmak i莽in sekme men眉s眉ne odaklan谋p uygun <strong>Ok</strong> tu艧una basarak\n' +
+  '  ba艧ka bir ileti艧im kutusu sekmesine ge莽i艧 yap谋n.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/uk.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/uk.js
new file mode 100644
index 0000000..028d4a4
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/uk.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.uk',
+'<h1>袩芯褔邪褌芯泻 褉芯斜芯褌懈 蟹 薪邪胁褨谐邪褑褨褦褞 蟹邪 写芯锌芯屑芯谐芯褞 泻谢邪胁褨邪褌褍褉懈</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 褉褟写芯泻 屑械薪褞</dt>\n' +
+  '  <dd>Windows 邪斜芯 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁</dt>\n' +
+  '  <dd>Windows 邪斜芯 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢"</dt>\n' +
+  '  <dd>Windows 邪斜芯 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 褋锌芯胁褨褖械薪薪褟</dt>\n' +
+  '  <dd>Windows 邪斜芯 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>肖芯泻褍褋 薪邪 泻芯薪褌械泻褋褌薪褨泄 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁</dt>\n' +
+  '  <dd>Windows, Linux 邪斜芯 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>袧邪胁褨谐邪褑褨褟 锌芯褔薪械褌褜褋褟 蟹 锌械褉褕芯谐芯 械谢械屑械薪褌邪 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪, 褟泻懈泄 斜褍写械 胁懈写褨谢械薪芯 邪斜芯 锌褨写泻褉械褋谢械薪芯 胁 褉邪蟹褨, 褟泻褖芯 锌械褉褕懈泄 械谢械屑械薪褌 蟹薪邪褏芯写懈褌褜褋褟 胁\n' +
+  '  褕谢褟褏褍 写芯 械谢械屑械薪褌邪 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢".</p>\n' +
+  '\n' +
+  '<h1>袧邪胁褨谐邪褑褨褟 屑褨卸 褉芯蟹写褨谢邪屑懈 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪</h1>\n' +
+  '\n' +
+  '<p>些芯斜 锌械褉械泄褌懈 蟹 芯写薪芯谐芯 褉芯蟹写褨谢褍 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪 写芯 薪邪褋褌褍锌薪芯谐芯 褉芯蟹写褨谢褍, 薪邪褌懈褋薪褨褌褜 泻谢邪胁褨褕褍 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>些芯斜 锌械褉械泄褌懈 蟹 芯写薪芯谐芯 褉芯蟹写褨谢褍 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪 写芯 锌芯锌械褉械写薪褜芯谐芯 褉芯蟹写褨谢褍, 薪邪褌懈褋薪褨褌褜 褋锌芯谢褍褔械薪薪褟 泻谢邪胁褨褕 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>袩芯褉褟写芯泻 <strong>袙泻谢邪写芯泻</strong> 褑懈褏 褉芯蟹写褨谢褨胁 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪 褌邪泻懈泄:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>袪褟写芯泻 屑械薪褞</li>\n' +
+  '  <li>袣芯卸薪邪 谐褉褍锌邪 锌邪薪械谢械泄 褨薪褋褌褉褍屑械薪褌褨胁</li>\n' +
+  '  <li>袘褨褔薪邪 锌邪薪械谢褜</li>\n' +
+  '  <li>楔谢褟褏 写芯 械谢械屑械薪褌褨胁 褍 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢"</li>\n' +
+  '  <li>袣薪芯锌泻邪 锌械褉械屑懈泻邪褔邪 "袣褨谢褜泻褨褋褌褜 褋谢褨胁" 褍 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢"</li>\n' +
+  '  <li>袩芯褋懈谢邪薪薪褟 薪邪 斜褉械薪写懈薪谐 褍 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢"</li>\n' +
+  '  <li>袦邪褉泻械褉 蟹屑褨薪械薪薪褟 褉芯蟹屑褨褉褍 胁 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢"</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>携泻褖芯 褉芯蟹写褨谢 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪 胁褨写褋褍褌薪褨泄, 胁褨薪 锌褉芯锌褍褋泻邪褦褌褜褋褟.</p>\n' +
+  '\n' +
+  '<p>携泻褖芯 褎芯泻褍褋 薪邪胁褨谐邪褑褨褩 泻谢邪胁褨邪褌褍褉懈 蟹薪邪褏芯写懈褌褜褋褟 薪邪 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢", 邪谢械 泻芯褉懈褋褌褍胁邪褔 薪械 斜邪褔懈褌褜 胁懈写懈屑褍 斜褨褔薪褍 锌邪薪械谢褜, 薪邪褌懈褋薪褨褌褜 <strong>Shift+Tab</strong>,\n' +
+  '  褖芯斜 锌械褉械屑褨褋褌懈褌懈 褎芯泻褍褋 薪邪 锌械褉褕褍 谐褉褍锌褍 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁, 邪 薪械 薪邪 芯褋褌邪薪薪褞.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁褨谐邪褑褨褟 胁 屑械卸邪褏 褉芯蟹写褨谢褨胁 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪</h1>\n' +
+  '\n' +
+  '<p>些芯斜 锌械褉械泄褌懈 蟹 芯写薪芯谐芯 械谢械屑械薪褌褍 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪 写芯 薪邪褋褌褍锌薪芯谐芯, 薪邪褌懈褋薪褨褌褜 胁褨写锌芯胁褨写薪褍 泻谢邪胁褨褕褍 <strong>蟹褨 褋褌褉褨谢泻芯褞</strong>.</p>\n' +
+  '\n' +
+  '<p>袣谢邪胁褨褕褨 蟹褨 褋褌褉褨谢泻邪屑懈 <strong>袥褨胁芯褉褍褔</strong> 褨 <strong>袩褉邪胁芯褉褍褔</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>锌械褉械屑褨褖褍褞褌褜 屑褨卸 屑械薪褞 胁 褉褟写泻褍 屑械薪褞.</li>\n' +
+  '  <li>胁褨写泻褉懈胁邪褞褌褜 胁泻谢邪写械薪械 屑械薪褞 胁 屑械薪褞.</li>\n' +
+  '  <li>锌械褉械屑褨褖褍褞褌褜 泻芯褉懈褋褌褍胁邪褔邪 屑褨卸 泻薪芯锌泻邪屑懈 胁 谐褉褍锌褨 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁.</li>\n' +
+  '  <li>锌械褉械屑褨褖褍褞褌褜 屑褨卸 械谢械屑械薪褌邪屑懈 胁 褕谢褟褏褍 写芯 械谢械屑械薪褌褨胁 褍 褉芯蟹写褨谢褨 "袧懈卸薪褨泄 泻芯谢芯薪褌懈褌褍谢".</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>袣谢邪胁褨褕褨 蟹褨 褋褌褉褨谢泻邪屑懈 <strong>袙薪懈蟹</strong> 褨 <strong>袙谐芯褉褍</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>锌械褉械屑褨褖褍褞褌褜 屑褨卸 械谢械屑械薪褌邪屑懈 屑械薪褞 胁 屑械薪褞.</li>\n' +
+  '  <li>锌械褉械屑褨褖褍褞褌褜 屑褨卸 械谢械屑械薪褌邪屑懈 胁 褋锌谢懈胁邪褞褔芯屑褍 屑械薪褞 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>袣谢邪胁褨褕褨 <strong>蟹褨 褋褌褉褨谢泻邪屑懈</strong> 锌械褉械屑褨褖褍褞褌褜 褎芯泻褍褋 褑懈泻谢褨褔薪芯 胁 屑械卸邪褏 褉芯蟹写褨谢褍 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪, 薪邪 褟泻芯屑褍 蟹薪邪褏芯写懈褌褜褋褟 褎芯泻褍褋.</p>\n' +
+  '\n' +
+  '<p>些芯斜 蟹邪泻褉懈褌懈 胁褨写泻褉懈褌械 屑械薪褞, 胁褨写泻褉懈褌械 胁泻谢邪写械薪械 屑械薪褞 邪斜芯 胁褨写泻褉懈褌械 褋锌谢懈胁邪褞褔械 屑械薪褞, 薪邪褌懈褋薪褨褌褜 泻谢邪胁褨褕褍 <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>携泻褖芯 锌芯褌芯褔薪懈泄 褎芯泻褍褋 蟹薪邪褏芯写懈褌褜褋褟 薪邪 胁械褉褏薪褜芯屑褍 褉褨胁薪褨 锌械胁薪芯谐芯 褉芯蟹写褨谢褍 褨薪褌械褉褎械泄褋褍 泻芯褉懈褋褌褍胁邪褔邪, 薪邪褌懈褋泻邪薪薪褟 泻谢邪胁褨褕褨 <strong>Esc</strong> 褌邪泻芯卸 胁懈泻芯薪褍褦 胁懈褏褨写\n' +
+  '  蟹 薪邪胁褨谐邪褑褨褩 蟹邪 写芯锌芯屑芯谐芯褞 泻谢邪胁褨邪褌褍褉懈 锌芯胁薪褨褋褌褞.</p>\n' +
+  '\n' +
+  '<h1>袙懈泻芯薪邪薪薪褟 械谢械屑械薪褌褍 屑械薪褞 邪斜芯 泻薪芯锌泻懈 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁</h1>\n' +
+  '\n' +
+  '<p>袣芯谢懈 锌芯褌褉褨斜薪懈泄 械谢械屑械薪褌 屑械薪褞 邪斜芯 泻薪芯锌泻褍 锌邪薪械谢褨 褨薪褋褌褉褍屑械薪褌褨胁 胁懈写褨谢械薪芯, 薪邪褌懈褋薪褨褌褜 泻谢邪胁褨褕褨 <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  邪斜芯 <strong>袩褉芯斜褨谢</strong>, 褖芯斜 胁懈泻芯薪邪褌懈 褑械泄 械谢械屑械薪褌.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁褨谐邪褑褨褟 锌芯 写褨邪谢芯谐芯胁懈屑 胁褨泻薪邪屑 斜械蟹 胁泻谢邪写芯泻</h1>\n' +
+  '\n' +
+  '<p>校 写褨邪谢芯谐芯胁懈褏 胁褨泻薪邪褏 斜械蟹 胁泻谢邪写芯泻 锌械褉褕懈泄 褨薪褌械褉邪泻褌懈胁薪懈泄 泻芯屑锌芯薪械薪褌 锌褉懈泄屑邪褦 褎芯泻褍褋, 泻芯谢懈 胁褨写泻褉懈胁邪褦褌褜褋褟 写褨邪谢芯谐芯胁械 胁褨泻薪芯.</p>\n' +
+  '\n' +
+  '<p>袩械褉械褏芯写褜褌械 屑褨卸 褨薪褌械褉邪泻褌懈胁薪懈屑懈 泻芯屑锌芯薪械薪褌邪屑懈 写褨邪谢芯谐芯胁芯谐芯 胁褨泻薪邪, 薪邪褌懈褋泻邪褞褔懈 泻谢邪胁褨褕褨 <strong>Tab</strong> 邪斜芯 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>袧邪胁褨谐邪褑褨褟 锌芯 写褨邪谢芯谐芯胁懈屑 胁褨泻薪邪屑 蟹 胁泻谢邪写泻邪屑懈</h1>\n' +
+  '\n' +
+  '<p>校 写褨邪谢芯谐芯胁懈褏 胁褨泻薪邪褏 褨蟹 胁泻谢邪写泻邪屑懈 锌械褉褕邪 泻薪芯锌泻邪 胁 屑械薪褞 胁泻谢邪写泻懈 锌褉懈泄屑邪褦 褎芯泻褍褋, 泻芯谢懈 胁褨写泻褉懈胁邪褦褌褜褋褟 写褨邪谢芯谐芯胁械 胁褨泻薪芯.</p>\n' +
+  '\n' +
+  '<p>袩械褉械褏芯写褜褌械 屑褨卸 褨薪褌械褉邪泻褌懈胁薪懈屑懈 泻芯屑锌芯薪械薪褌邪屑懈 褑褨褦褩 胁泻谢邪写泻懈 写褨邪谢芯谐芯胁芯谐芯 胁褨泻薪邪, 薪邪褌懈褋泻邪褞褔懈 泻谢邪胁褨褕褨 <strong>Tab</strong> 邪斜芯\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>些芯斜 锌械褉械泄褌懈 薪邪 褨薪褕褍 胁泻谢邪写泻褍 写褨邪谢芯谐芯胁芯谐芯 胁褨泻薪邪, 锌械褉械屑褨褋褌褨褌褜 褎芯泻褍褋 薪邪 屑械薪褞 胁泻谢邪写泻懈, 邪 锌芯褌褨屑 薪邪褌懈褋薪褨褌褜 胁褨写锌芯胁褨写薪褍 泻谢邪胁褨褕褍 <strong>蟹褨 褋褌褉褨谢泻芯褞</strong>,\n' +
+  '  褖芯斜 褑懈泻谢褨褔薪芯 锌械褉械褏芯写懈褌懈 锌芯 写芯褋褌褍锌薪懈屑 胁泻谢邪写泻邪屑.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/vi.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/vi.js
new file mode 100644
index 0000000..d8eda11
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/vi.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.vi',
+'<h1>B岷痶 膽岷 膽i峄乽 h瓢峄沶g b脿n ph铆m</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>T岷璸 trung v脿o thanh menu</dt>\n' +
+  '  <dd>Windows ho岷穋 Linux: Alt+F9</dd>\n' +
+  '  <dd>macOS: &#x2325;F9</dd>\n' +
+  '  <dt>T岷璸 trung v脿o thanh c么ng c峄�</dt>\n' +
+  '  <dd>Windows ho岷穋 Linux: Alt+F10</dd>\n' +
+  '  <dd>macOS: &#x2325;F10</dd>\n' +
+  '  <dt>T岷璸 trung v脿o ch芒n trang</dt>\n' +
+  '  <dd>Windows ho岷穋 Linux: Alt+F11</dd>\n' +
+  '  <dd>macOS: &#x2325;F11</dd>\n' +
+  '  <dt>T岷璸 trung v脿o th么ng b谩o</dt>\n' +
+  '  <dd>Windows ho岷穋 Linux: Alt+F12</dd>\n' +
+  '  <dd>macOS: &#x2325;F12</dd>\n' +
+  '  <dt>T岷璸 trung v脿o thanh c么ng c峄� ng峄� c岷h</dt>\n' +
+  '  <dd>Windows, Linux ho岷穋 macOS: Ctrl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>膼i峄乽 h瓢峄沶g s岷� b岷痶 膽岷 t峄� m峄 UI 膽岷 ti锚n. M峄 n脿y s岷� 膽瓢峄 t么 s谩ng ho岷穋 c贸 g岷h d瓢峄沬 (n岷縰 l脿 m峄 膽岷 ti锚n trong\n' +
+  '  膽瓢峄漬g d岷玭 ph岷 t峄� Ch芒n trang).</p>\n' +
+  '\n' +
+  '<h1>Di chuy峄僴 qua l岷 gi峄痑 c谩c ph岷 UI</h1>\n' +
+  '\n' +
+  '<p>膼峄� di chuy峄僴 t峄� m峄檛 ph岷 UI sang ph岷 ti岷縫 theo, 岷 <strong>Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>膼峄� di chuy峄僴 t峄� m峄檛 ph岷 UI v峄� ph岷 tr瓢峄沜 膽贸, 岷 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Th峄� t峄� <strong>Tab</strong> c峄 c谩c ph岷 UI n脿y nh瓢 sau:</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>Thanh menu</li>\n' +
+  '  <li>T峄玭g nh贸m thanh c么ng c峄�</li>\n' +
+  '  <li>Thanh b锚n</li>\n' +
+  '  <li>膼瓢峄漬g d岷玭 ph岷 t峄� trong ch芒n trang</li>\n' +
+  '  <li>N煤t chuy峄僴 膽峄昳 膽岷縨 ch峄� 峄� ch芒n trang</li>\n' +
+  '  <li>Li锚n k岷縯 th瓢啤ng hi峄噓 峄� ch芒n trang</li>\n' +
+  '  <li>N煤m 膽i峄乽 t谩c ch峄塶h k铆ch c峄� tr矛nh so岷 th岷 峄� ch芒n trang</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>N岷縰 ng瓢峄漣 d霉ng kh么ng th岷 m峄檛 ph岷 UI, th矛 c贸 ngh末a ph岷 膽贸 b峄� b峄� qua.</p>\n' +
+  '\n' +
+  '<p>N岷縰 峄� ch芒n trang c贸 t铆nh n膬ng t岷璸 trung 膽i峄乽 h瓢峄沶g b脿n ph铆m, m脿 kh么ng c贸 thanh b锚n n脿o hi峄噉 h峄痷, thao t谩c 岷 <strong>Shift+Tab</strong>\n' +
+  '  s岷� chuy峄僴 h瓢峄沶g t岷璸 trung v脿o nh贸m thanh c么ng c峄� 膽岷 ti锚n, kh么ng ph岷 cu峄慽 c霉ng.</p>\n' +
+  '\n' +
+  '<h1>Di chuy峄僴 qua l岷 trong c谩c ph岷 UI</h1>\n' +
+  '\n' +
+  '<p>膼峄� di chuy峄僴 t峄� m峄檛 ph岷 t峄� UI sang ph岷 ti岷縫 theo, 岷 ph铆m <strong>M农i t锚n</strong> t瓢啤ng 峄﹏g cho ph霉 h峄.</p>\n' +
+  '\n' +
+  '<p>C谩c ph铆m m农i t锚n <strong>Tr谩i</strong> v脿 <strong>Ph岷</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>di chuy峄僴 gi峄痑 c谩c menu trong thanh menu.</li>\n' +
+  '  <li>m峄� menu ph峄� trong m峄檛 menu.</li>\n' +
+  '  <li>di chuy峄僴 gi峄痑 c谩c n煤t trong nh贸m thanh c么ng c峄�.</li>\n' +
+  '  <li>di chuy峄僴 gi峄痑 c谩c m峄 trong 膽瓢峄漬g d岷玭 ph岷 t峄� c峄 ch芒n trang.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>C谩c ph铆m m农i t锚n <strong>H瓢峄沶g xu峄憂g</strong> v脿 <strong>H瓢峄沶g l锚n</strong></p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>di chuy峄僴 gi峄痑 c谩c m峄 menu trong menu.</li>\n' +
+  '  <li>di chuy峄僴 gi峄痑 c谩c m峄 trong menu thanh c么ng c峄� d岷g b岷璽 l锚n.</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p>C谩c ph铆m <strong>m农i t锚n</strong> xoay v貌ng trong m峄檛 ph岷 UI t岷璸 trung.</p>\n' +
+  '\n' +
+  '<p>膼峄� 膽贸ng m峄檛 menu m峄�, m峄檛 menu ph峄� 膽ang m峄�, ho岷穋 m峄檛 menu d岷g b岷璽 l锚n 膽ang m峄�, h茫y 岷 ph铆m <strong>Esc</strong>.</p>\n' +
+  '\n' +
+  '<p>N岷縰 tr峄峮g t芒m hi峄噉 t岷 l脿 峄� ph岷 鈥溎戓骇u鈥� c峄 m峄檛 ph岷 UI c峄� th峄�, thao t谩c 岷 ph铆m <strong>Esc</strong> c农ng s岷� tho谩t\n' +
+  '  to脿n b峄� ph岷 膽i峄乽 h瓢峄沶g b脿n ph铆m.</p>\n' +
+  '\n' +
+  '<h1>Th峄眂 hi峄噉 ch峄ヽ n膬ng c峄 m峄檛 m峄 menu ho岷穋 n煤t thanh c么ng c峄�</h1>\n' +
+  '\n' +
+  '<p>Khi m峄 menu ho岷穋 n煤t thanh c么ng c峄� mu峄憂 d霉ng 膽瓢峄 t么 s谩ng, h茫y 岷 <strong>Return</strong>, <strong>Enter</strong>,\n' +
+  '  ho岷穋 <strong>Ph铆m c谩ch</strong> 膽峄� th峄眂 hi峄噉 ch峄ヽ n膬ng m峄 膽贸.</p>\n' +
+  '\n' +
+  '<h1>膼i峄乽 h瓢峄沶g gi峄痑 c谩c h峄檖 tho岷 kh么ng c贸 nhi峄乽 tab</h1>\n' +
+  '\n' +
+  '<p>Trong c谩c h峄檖 tho岷 kh么ng c贸 nhi峄乽 tab, khi h峄檖 tho岷 m峄� ra, tr峄峮g t芒m s岷� h瓢峄沶g v脿o th脿nh ph岷 t瓢啤ng t谩c 膽岷 ti锚n.</p>\n' +
+  '\n' +
+  '<p>Di chuy峄僴 gi峄痑 c谩c th脿nh ph岷 h峄檖 tho岷 t瓢啤ng t谩c b岷眓g c谩ch 岷 <strong>Tab</strong> ho岷穋 <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<h1>膼i峄乽 h瓢峄沶g gi峄痑 c谩c h峄檖 tho岷 c贸 nhi峄乽 tab</h1>\n' +
+  '\n' +
+  '<p>Trong c谩c h峄檖 tho岷 c贸 nhi峄乽 tab, khi h峄檖 tho岷 m峄� ra, tr峄峮g t芒m s岷� h瓢峄沶g v脿o n煤t 膽岷 ti锚n trong menu tab.</p>\n' +
+  '\n' +
+  '<p>Di chuy峄僴 gi峄痑 c谩c th脿nh ph岷 t瓢啤ng t谩c c峄 tab h峄檖 tho岷 n脿y b岷眓g c谩ch 岷 <strong>Tab</strong> ho岷穋\n' +
+  '  <strong>Shift+Tab</strong>.</p>\n' +
+  '\n' +
+  '<p>Chuy峄僴 sang m峄檛 tab h峄檖 tho岷 kh谩c b岷眓g c谩ch chuy峄僴 tr峄峮g t芒m v脿o menu tab, r峄搃 岷 ph铆m <strong>M农i t锚n</strong> ph霉 h峄\n' +
+  '  膽峄� xoay v貌ng c谩c tab hi峄噉 c贸.</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_CN.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_CN.js
new file mode 100644
index 0000000..f7e73d1
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_CN.js
@@ -0,0 +1,87 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_CN',
+'<h1>寮�濮嬮敭鐩樺鑸�</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>浣胯彍鍗曟爮澶勪簬鐒︾偣</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F9</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F9</dd>\n' +
+  '  <dt>浣垮伐鍏锋爮澶勪簬鐒︾偣</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F10</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F10</dd>\n' +
+  '  <dt>浣块〉鑴氬浜庣劍鐐�</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F11</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F11</dd>\n' +
+  '  <dt>浣块�氱煡澶勪簬鐒︾偣</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F12</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F12</dd>\n' +
+  '  <dt>浣夸笂涓嬫枃宸ュ叿鏍忓浜庣劍鐐�</dt>\n' +
+  '  <dd>Windows銆丩inux 鎴� macOS锛欳trl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>瀵艰埅灏嗗湪绗竴涓� UI 椤逛笂寮�濮嬶紝鍏朵腑绐佸嚭鏄剧ず璇ラ」锛屾垨鑰呭浜庨〉鑴氬厓绱犺矾寰勪腑鐨勭涓�椤癸紝灏嗕负鍏舵坊鍔犱笅鍒掔嚎銆�</p>\n' +
+  '\n' +
+  '<h1>鍦� UI 閮ㄥ垎涔嬮棿瀵艰埅</h1>\n' +
+  '\n' +
+  '<p>瑕佷粠涓�涓� UI 閮ㄥ垎绉昏嚦涓嬩竴涓紝璇锋寜 <strong>Tab</strong>銆�</p>\n' +
+  '\n' +
+  '<p>瑕佷粠涓�涓� UI 閮ㄥ垎绉昏嚦涓婁竴涓紝璇锋寜 <strong>Shift+Tab</strong>銆�</p>\n' +
+  '\n' +
+  '<p>杩欎簺 UI 閮ㄥ垎鐨� <strong>Tab</strong> 椤哄簭涓猴細</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>鑿滃崟鏍�</li>\n' +
+  '  <li>姣忎釜宸ュ叿鏍忕粍</li>\n' +
+  '  <li>杈规爮</li>\n' +
+  '  <li>椤佃剼涓殑鍏冪礌璺緞</li>\n' +
+  '  <li>椤佃剼涓殑瀛楁暟鍒囨崲鎸夐挳</li>\n' +
+  '  <li>椤佃剼涓殑鍝佺墝閾炬帴</li>\n' +
+  '  <li>椤佃剼涓殑缂栬緫鍣ㄨ皟鏁村ぇ灏忓浘鏌�</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>濡傛灉涓嶅瓨鍦ㄦ煇涓� UI 閮ㄥ垎锛屽垯璺宠繃瀹冦��</p>\n' +
+  '\n' +
+  '<p>濡傛灉閿洏瀵艰埅鐒︾偣鍦ㄩ〉鑴氾紝骞朵笖娌℃湁鍙鐨勮竟鏍忥紝鍒欐寜 <strong>Shift+Tab</strong> 灏嗙劍鐐圭Щ鑷崇涓�涓伐鍏锋爮缁勮�岄潪鏈�鍚庝竴涓��</p>\n' +
+  '\n' +
+  '<h1>鍦� UI 閮ㄥ垎鍐呭鑸�</h1>\n' +
+  '\n' +
+  '<p>瑕佷粠涓�涓� UI 鍏冪礌绉昏嚦涓嬩竴涓紝璇锋寜鐩稿簲鐨�<strong>绠ご</strong>閿��</p>\n' +
+  '\n' +
+  '<p><strong>宸�</strong>鍜�<strong>鍙�</strong>绠ご閿�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>鍦ㄨ彍鍗曟爮涓殑鑿滃崟涔嬮棿绉诲姩銆�</li>\n' +
+  '  <li>鎵撳紑鑿滃崟涓殑瀛愯彍鍗曘��</li>\n' +
+  '  <li>鍦ㄥ伐鍏锋爮缁勪腑鐨勬寜閽箣闂寸Щ鍔ㄣ��</li>\n' +
+  '  <li>鍦ㄩ〉鑴氱殑鍏冪礌璺緞涓殑鍚勯」涔嬮棿绉诲姩銆�</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>涓�</strong>鍜�<strong>涓�</strong>绠ご閿�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>鍦ㄨ彍鍗曚腑鐨勮彍鍗曢」涔嬮棿绉诲姩銆�</li>\n' +
+  '  <li>鍦ㄥ伐鍏锋爮寮瑰嚭鑿滃崟涓殑鍚勯」涔嬮棿绉诲姩銆�</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>绠ご</strong>閿湪鍏锋湁鐒︾偣鐨� UI 閮ㄥ垎鍐呭惊鐜��</p>\n' +
+  '\n' +
+  '<p>瑕佸叧闂墦寮�鐨勮彍鍗曘�佹墦寮�鐨勫瓙鑿滃崟鎴栨墦寮�鐨勫脊鍑鸿彍鍗曪紝璇锋寜 <strong>Esc</strong> 閿��</p>\n' +
+  '\n' +
+  '<p>濡傛灉褰撳墠鐨勭劍鐐瑰湪鐗瑰畾 UI 閮ㄥ垎鐨勨�滈《閮ㄢ�濓紝鍒欐寜 <strong>Esc</strong> 閿繕灏嗗畬鍏ㄩ��鍑洪敭鐩樺鑸��</p>\n' +
+  '\n' +
+  '<h1>鎵ц鑿滃崟椤规垨宸ュ叿鏍忔寜閽�</h1>\n' +
+  '\n' +
+  '<p>褰撶獊鍑烘樉绀烘墍闇�鐨勮彍鍗曢」鎴栧伐鍏锋爮鎸夐挳鏃讹紝鎸� <strong>Return</strong>銆�<strong>Enter</strong> 鎴�<strong>绌烘牸</strong>浠ユ墽琛岃椤广��</p>\n' +
+  '\n' +
+  '<h1>鍦ㄩ潪鏍囩椤靛紡瀵硅瘽妗嗕腑瀵艰埅</h1>\n' +
+  '\n' +
+  '<p>鍦ㄩ潪鏍囩椤靛紡瀵硅瘽妗嗕腑锛屽綋瀵硅瘽妗嗘墦寮�鏃讹紝绗竴涓氦浜掔粍浠惰幏寰楃劍鐐广��</p>\n' +
+  '\n' +
+  '<p>閫氳繃鎸� <strong>Tab</strong> 鎴� <strong>Shift+Tab</strong>锛屽湪浜や簰瀵硅瘽妗嗙粍浠朵箣闂村鑸��</p>\n' +
+  '\n' +
+  '<h1>鍦ㄦ爣绛鹃〉寮忓璇濇涓鑸�</h1>\n' +
+  '\n' +
+  '<p>鍦ㄦ爣绛鹃〉寮忓璇濇涓紝褰撳璇濇鎵撳紑鏃讹紝鏍囩椤佃彍鍗曚腑鐨勭涓�涓寜閽幏寰楃劍鐐广��</p>\n' +
+  '\n' +
+  '<p>閫氳繃鎸� <strong>Tab</strong> 鎴� <strong>Shift+Tab</strong>锛屽湪姝ゅ璇濇鐨勪氦浜掔粍浠朵箣闂村鑸��</p>\n' +
+  '\n' +
+  '<p>閫氳繃灏嗙劍鐐圭Щ鑷冲彟涓�瀵硅瘽妗嗘爣绛鹃〉鐨勮彍鍗曪紝鐒跺悗鎸夌浉搴旂殑<strong>绠ご</strong>閿互鍦ㄥ彲鐢ㄧ殑鏍囩椤甸棿寰幆锛屼粠鑰屽垏鎹㈠埌璇ュ璇濇鏍囩椤点��</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_TW.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_TW.js
new file mode 100644
index 0000000..5912770
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/js/i18n/keynav/zh_TW.js
@@ -0,0 +1,93 @@
+tinymce.Resource.add('tinymce.html-i18n.help-keynav.zh_TW',
+'<h1>闁嬪閸电洡鐎忚</h1>\n' +
+  '\n' +
+  '<dl>\n' +
+  '  <dt>璺宠嚦鍔熻兘琛ㄥ垪</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F9</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F9</dd>\n' +
+  '  <dt>璺宠嚦宸ュ叿鍒�</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F10</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F10</dd>\n' +
+  '  <dt>璺宠嚦闋佸熬</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F11</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F11</dd>\n' +
+  '  <dt>璺宠嚦閫氱煡</dt>\n' +
+  '  <dd>Windows 鎴� Linux锛欰lt+F12</dd>\n' +
+  '  <dd>macOS锛�&#x2325;F12</dd>\n' +
+  '  <dt>璺宠嚦闂滆伅寮忓伐鍏峰垪</dt>\n' +
+  '  <dd>Windows銆丩inux 鎴� macOS锛欳trl+F9</dd>\n' +
+  '</dl>\n' +
+  '\n' +
+  '<p>鐎忚鏈冨緸绗竴鍊� UI 闋呯洰闁嬪锛岃┎闋呯洰鏈冨弽鐧介’绀猴紝浣嗗鏋滄槸銆岄爜灏俱�嶅厓绱犺矾寰戠殑绗竴闋咃紝\n' +
+  '  鍓囧姞搴曠窔銆�</p>\n' +
+  '\n' +
+  '<h1>鍦� UI 鍗�娈典箣闁撶�忚</h1>\n' +
+  '\n' +
+  '<p>寰� UI 鍗�娈电Щ鑷充笅涓�鍊嬶紝璜嬫寜 <strong>Tab</strong>銆�</p>\n' +
+  '\n' +
+  '<p>寰� UI 鍗�娈电Щ鍥炰笂涓�鍊嬶紝璜嬫寜 <strong>Shift+Tab</strong>銆�</p>\n' +
+  '\n' +
+  '<p>閫欎簺 UI 鍗�娈电殑 <strong>Tab</strong> 闋嗗簭濡備笅锛�</p>\n' +
+  '\n' +
+  '<ol>\n' +
+  '  <li>鍔熻兘琛ㄥ垪</li>\n' +
+  '  <li>鍚勫�嬪伐鍏峰垪缇ょ祫</li>\n' +
+  '  <li>鍋撮倞娆�</li>\n' +
+  '  <li>闋佸熬涓殑鍏冪礌璺緫</li>\n' +
+  '  <li>闋佸熬涓瓧鏁稿垏鎻涙寜閳�</li>\n' +
+  '  <li>闋佸熬涓殑鍝佺墝閫g祼</li>\n' +
+  '  <li>闋佸熬涓法杓櫒瑾挎暣澶у皬鎺ч粸</li>\n' +
+  '</ol>\n' +
+  '\n' +
+  '<p>濡傛灉 UI 鍗�娈垫湭椤ず锛岃〃绀哄凡鐣ラ亷瑭插崁娈点��</p>\n' +
+  '\n' +
+  '<p>濡傛灉閸电洡鐎忚璺宠嚦闋佸熬锛屼絾娌掓湁椤ず鍋撮倞娆勶紝鍓囨寜涓� <strong>Shift+Tab</strong>\n' +
+  '  鏈冭烦鑷崇涓�鍊嬪伐鍏峰垪缇ょ祫锛岃�屼笉鏄渶寰屼竴鍊嬨��</p>\n' +
+  '\n' +
+  '<h1>鍦� UI 鍗�娈典箣鍏х�忚</h1>\n' +
+  '\n' +
+  '<p>鍦ㄥ叐鍊� UI 鍏冪礌涔嬮枔绉诲嫊锛岃珛鎸夐仼鐣剁殑<strong>鏂瑰悜</strong>閸点��</p>\n' +
+  '\n' +
+  '<p><strong>鍚戝乏</strong>鍜�<strong>鍚戝彸</strong>鏂瑰悜閸�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>鍦ㄥ姛鑳借〃鍒椾腑鐨勫姛鑳借〃涔嬮枔绉诲嫊銆�</li>\n' +
+  '  <li>闁嬪暉鍔熻兘琛ㄤ腑鐨勫瓙鍔熻兘琛ㄣ��</li>\n' +
+  '  <li>鍦ㄥ伐鍏峰垪缇ょ祫涓殑鎸夐垥涔嬮枔绉诲嫊銆�</li>\n' +
+  '  <li>鍦ㄩ爜灏剧殑鍏冪礌璺緫涓爡鐩箣闁撶Щ鍕曘��</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>鍚戜笅</strong>鍜�<strong>鍚戜笂</strong>鏂瑰悜閸�</p>\n' +
+  '\n' +
+  '<ul>\n' +
+  '  <li>鍦ㄥ姛鑳借〃涓殑鍔熻兘琛ㄩ爡鐩箣闁撶Щ鍕曘��</li>\n' +
+  '  <li>鍦ㄥ伐鍏峰垪蹇’鍔熻兘琛ㄤ腑鐨勯爡鐩箣闁撶Щ鍕曘��</li>\n' +
+  '</ul>\n' +
+  '\n' +
+  '<p><strong>鏂瑰悜</strong>閸垫渻鍦ㄦ墍璺宠嚦 UI 鍗�娈典箣鍏у惊鐠般��</p>\n' +
+  '\n' +
+  '<p>鑻ヨ闂滈枆宸查枊鍟熺殑鍔熻兘琛ㄣ�佸凡闁嬪暉鐨勫瓙鍔熻兘琛紝鎴栧凡闁嬪暉鐨勫揩椤姛鑳借〃锛岃珛鎸� <strong>Esc</strong> 閸点��</p>\n' +
+  '\n' +
+  '<p>濡傛灉鐩墠宸茶烦鑷崇壒瀹� UI 鍗�娈电殑銆岄爞绔�嶏紝鍓囨寜 <strong>Esc</strong> 閸典篃鏈冪祼鏉焅n' +
+  '  鏁村�嬮嵉鐩ょ�忚銆�</p>\n' +
+  '\n' +
+  '<h1>鍩疯鍔熻兘琛ㄥ垪闋呯洰鎴栧伐鍏峰垪鎸夐垥</h1>\n' +
+  '\n' +
+  '<p>鐣舵兂瑕佺殑鍔熻兘琛ㄩ爡鐩垨宸ュ叿鍒楁寜閳曞凡鍙嶇櫧椤ず鏅傦紝鎸� <strong>Return</strong>銆�<strong>Enter</strong>銆乗n' +
+  '  鎴�<strong>绌虹櫧閸�</strong>鍗冲彲鍩疯瑭查爡鐩��</p>\n' +
+  '\n' +
+  '<h1>鐎忚闈炵储寮曟绫ゅ紡灏嶈┍鏂瑰</h1>\n' +
+  '\n' +
+  '<p>鍦ㄩ潪绱㈠紩妯欑堡寮忓皪瑭辨柟濉婁腑锛岄枊鍟熷皪瑭辨柟濉婃檪鏈冭烦鑷崇涓�鍊嬩簰鍕曞厓浠躲��</p>\n' +
+  '\n' +
+  '<p>鎸� <strong>Tab</strong> 鎴� <strong>Shift+Tab</strong> 鍗冲彲鍦ㄤ簰鍕曞紡灏嶈┍鏂瑰鍏冧欢涔嬮枔鐎忚銆�</p>\n' +
+  '\n' +
+  '<h1>鐎忚绱㈠紩妯欑堡寮忓皪瑭辨柟濉�</h1>\n' +
+  '\n' +
+  '<p>鍦ㄧ储寮曟绫ゅ紡灏嶈┍鏂瑰涓紝闁嬪暉灏嶈┍鏂瑰鏅傛渻璺宠嚦绱㈠紩妯欑堡寮忓姛鑳借〃涓殑绗竴鍊嬫寜閳曘��</p>\n' +
+  '\n' +
+  '<p>鑻ヨ鍦ㄦ灏嶈┍鏂瑰鐨勪簰鍕曞紡鍏冧欢涔嬮枔鐎忚锛岃珛鎸� <strong>Tab</strong> 鎴朶n' +
+  '  <strong>Shift+Tab</strong>銆�</p>\n' +
+  '\n' +
+  '<p>鍏堣烦鑷崇储寮曟绫ゅ紡鍔熻兘琛紝鐒跺緦鎸夐仼鐣剁殑<strong>鏂瑰悜</strong>閸碉紝鍗冲彲鍒囨彌鑷冲彟涓�鍊嬪皪瑭辨柟濉婄储寮曟绫わ紝\n' +
+  '  浠ュ惊鐠扮�忚鍙敤鐨勭储寮曟绫ゃ��</p>\n');
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/help/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/help/plugin.min.js
new file mode 100644
index 0000000..b5d4f8d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/help/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");let t=0;const n=e=>{const n=(new Date).getTime(),a=Math.floor(1e9*Math.random());return t++,e+"_"+a+t+String(n)},a=e=>t=>t.options.get(e),r=a("help_tabs"),o=a("forced_plugins"),i=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=a=e,(r=String).prototype.isPrototypeOf(n)||(null===(o=a.constructor)||void 0===o?void 0:o.name)===r.name)?"string":t;var n,a,r,o})(e));const s=(void 0,e=>undefined===e);const l=e=>"function"==typeof e,m=(!1,()=>false);class c{constructor(e,t){this.tag=e,this.value=t}static some(e){return new c(!0,e)}static none(){return c.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?c.some(e(this.value)):c.none()}bind(e){return this.tag?e(this.value):c.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:c.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?c.none():c.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}c.singletonNone=new c(!1);const u=Array.prototype.slice,p=Array.prototype.indexOf,y=(e,t)=>{const n=e.length,a=new Array(n);for(let r=0;r<n;r++){const n=e[r];a[r]=t(n,r)}return a},h=(e,t)=>{const n=[];for(let a=0,r=e.length;a<r;a++){const r=e[a];t(r,a)&&n.push(r)}return n},d=(e,t)=>{const n=u.call(e,0);return n.sort(t),n},g=Object.keys,k=Object.hasOwnProperty,v=(e,t)=>k.call(e,t);var b=tinymce.util.Tools.resolve("tinymce.Resource"),f=tinymce.util.Tools.resolve("tinymce.util.I18n");const A=(e,t)=>b.load(`tinymce.html-i18n.help-keynav.${t}`,`${e}/js/i18n/keynav/${t}.js`),w=e=>A(e,f.getCode()).catch((()=>A(e,"en")));var C=tinymce.util.Tools.resolve("tinymce.Env");const M=e=>{const t=C.os.isMacOS()||C.os.isiOS(),n=t?{alt:"&#x2325;",ctrl:"&#x2303;",shift:"&#x21E7;",meta:"&#x2318;",access:"&#x2303;&#x2325;"}:{meta:"Ctrl ",access:"Shift + Alt "},a=e.split("+"),r=y(a,(e=>{const t=e.toLowerCase().trim();return v(n,t)?n[t]:e}));return t?r.join("").replace(/\s/,""):r.join("+")},S=[{shortcuts:["Meta + B"],action:"Bold"},{shortcuts:["Meta + I"],action:"Italic"},{shortcuts:["Meta + U"],action:"Underline"},{shortcuts:["Meta + A"],action:"Select all"},{shortcuts:["Meta + Y","Meta + Shift + Z"],action:"Redo"},{shortcuts:["Meta + Z"],action:"Undo"},{shortcuts:["Access + 1"],action:"Heading 1"},{shortcuts:["Access + 2"],action:"Heading 2"},{shortcuts:["Access + 3"],action:"Heading 3"},{shortcuts:["Access + 4"],action:"Heading 4"},{shortcuts:["Access + 5"],action:"Heading 5"},{shortcuts:["Access + 6"],action:"Heading 6"},{shortcuts:["Access + 7"],action:"Paragraph"},{shortcuts:["Access + 8"],action:"Div"},{shortcuts:["Access + 9"],action:"Address"},{shortcuts:["Alt + 0"],action:"Open help dialog"},{shortcuts:["Alt + F9"],action:"Focus to menubar"},{shortcuts:["Alt + F10"],action:"Focus to toolbar"},{shortcuts:["Alt + F11"],action:"Focus to element path"},{shortcuts:["Alt + F12"],action:"Focus to notification"},{shortcuts:["Ctrl + F9"],action:"Focus to contextual toolbar"},{shortcuts:["Shift + Enter"],action:"Open popup menu for split buttons"},{shortcuts:["Meta + K"],action:"Insert link (if link plugin activated)"},{shortcuts:["Meta + S"],action:"Save (if save plugin activated)"},{shortcuts:["Meta + F"],action:"Find (if searchreplace plugin activated)"},{shortcuts:["Meta + Shift + F"],action:"Switch to or from fullscreen mode"}],_=()=>({name:"shortcuts",title:"Handy Shortcuts",items:[{type:"table",header:["Action","Shortcut"],cells:y(S,(e=>{const t=y(e.shortcuts,M).join(" or ");return[e.action,t]}))}]}),x=y([{key:"accordion",name:"Accordion"},{key:"anchor",name:"Anchor"},{key:"autolink",name:"Autolink"},{key:"autoresize",name:"Autoresize"},{key:"autosave",name:"Autosave"},{key:"charmap",name:"Character Map"},{key:"code",name:"Code"},{key:"codesample",name:"Code Sample"},{key:"colorpicker",name:"Color Picker"},{key:"directionality",name:"Directionality"},{key:"emoticons",name:"Emoticons"},{key:"fullscreen",name:"Full Screen"},{key:"help",name:"Help"},{key:"image",name:"Image"},{key:"importcss",name:"Import CSS"},{key:"insertdatetime",name:"Insert Date/Time"},{key:"link",name:"Link"},{key:"lists",name:"Lists"},{key:"advlist",name:"List Styles"},{key:"media",name:"Media"},{key:"nonbreaking",name:"Nonbreaking"},{key:"pagebreak",name:"Page Break"},{key:"preview",name:"Preview"},{key:"quickbars",name:"Quick Toolbars"},{key:"save",name:"Save"},{key:"searchreplace",name:"Search and Replace"},{key:"table",name:"Table"},{key:"textcolor",name:"Text Color"},{key:"visualblocks",name:"Visual Blocks"},{key:"visualchars",name:"Visual Characters"},{key:"wordcount",name:"Word Count"},{key:"a11ychecker",name:"Accessibility Checker",type:"premium"},{key:"typography",name:"Advanced Typography",type:"premium",slug:"advanced-typography"},{key:"ai",name:"AI Assistant",type:"premium"},{key:"casechange",name:"Case Change",type:"premium"},{key:"checklist",name:"Checklist",type:"premium"},{key:"advcode",name:"Enhanced Code Editor",type:"premium"},{key:"mediaembed",name:"Enhanced Media Embed",type:"premium",slug:"introduction-to-mediaembed"},{key:"advtable",name:"Enhanced Tables",type:"premium"},{key:"exportpdf",name:"Export to PDF",type:"premium"},{key:"exportword",name:"Export to Word",type:"premium"},{key:"footnotes",name:"Footnotes",type:"premium"},{key:"formatpainter",name:"Format Painter",type:"premium"},{key:"editimage",name:"Image Editing",type:"premium"},{key:"importword",name:"Import from Word",type:"premium"},{key:"inlinecss",name:"Inline CSS",type:"premium",slug:"inline-css"},{key:"linkchecker",name:"Link Checker",type:"premium"},{key:"math",name:"Math",type:"premium"},{key:"markdown",name:"Markdown",type:"premium"},{key:"mentions",name:"Mentions",type:"premium"},{key:"mergetags",name:"Merge Tags",type:"premium"},{key:"pageembed",name:"Page Embed",type:"premium"},{key:"permanentpen",name:"Permanent Pen",type:"premium"},{key:"powerpaste",name:"PowerPaste",type:"premium",slug:"introduction-to-powerpaste"},{key:"revisionhistory",name:"Revision History",type:"premium"},{key:"tinymcespellchecker",name:"Spell Checker",type:"premium",slug:"introduction-to-tiny-spellchecker"},{key:"autocorrect",name:"Spelling Autocorrect",type:"premium"},{key:"tableofcontents",name:"Table of Contents",type:"premium"},{key:"advtemplate",name:"Templates",type:"premium",slug:"advanced-templates"},{key:"tinycomments",name:"Tiny Comments",type:"premium",slug:"introduction-to-tiny-comments"},{key:"tinydrive",name:"Tiny Drive",type:"premium",slug:"tinydrive-introduction"}],(e=>({...e,type:e.type||"opensource",slug:e.slug||e.key}))),T=e=>{const t=e=>`<a data-alloy-tabstop="true" tabindex="-1" href="${e.url}" target="_blank" rel="noopener">${e.name}</a>`,n=(e,n)=>{return(a=x,r=e=>e.key===n,((e,t,n)=>{for(let a=0,r=e.length;a<r;a++){const r=e[a];if(t(r,a))return c.some(r);if(n(r,a))break}return c.none()})(a,r,m)).fold((()=>((e,n)=>{const a=e.plugins[n].getMetadata;if(l(a)){const e=a();return{name:e.name,html:t(e)}}return{name:n,html:n}})(e,n)),(e=>{const n="premium"===e.type?`${e.name}*`:e.name;return{name:n,html:t({name:n,url:`https://www.tiny.cloud/docs/tinymce/7/${e.slug}/`})}}));var a,r},a=e=>{const t=(e=>{const t=g(e.plugins),n=o(e);return s(n)?t:h(t,(e=>!(((e,t)=>p.call(e,t))(n,e)>-1)))})(e),a=d(y(t,(t=>n(e,t))),((e,t)=>e.name.localeCompare(t.name))),r=y(a,(e=>"<li>"+e.html+"</li>")),i=r.length,l=r.join("");return"<p><b>"+f.translate(["Plugins installed ({0}):",i])+"</b></p><ul>"+l+"</ul>"},r={type:"htmlpanel",presets:"document",html:[(e=>null==e?"":"<div>"+a(e)+"</div>")(e),(()=>{const e=h(x,(({type:e})=>"premium"===e)),t=d(y(e,(e=>e.name)),((e,t)=>e.localeCompare(t))),n=y(t,(e=>`<li>${e}</li>`)).join("");return"<div><p><b>"+f.translate("Premium plugins:")+"</b></p><ul>"+n+'<li class="tox-help__more-link" "><a href="https://www.tiny.cloud/pricing/?utm_campaign=help_dialog_plugin_tab&utm_source=tiny&utm_medium=referral&utm_term=read_more&utm_content=premium_plugin_heading" rel="noopener" target="_blank" data-alloy-tabstop="true" tabindex="-1">'+f.translate("Learn more...")+"</a></li></ul></div>"})()].join("")};return{name:"plugins",title:"Plugins",items:[r]}};var O=tinymce.util.Tools.resolve("tinymce.EditorManager");const F=(e,t,a)=>()=>{(async(e,t,a)=>{const o=_(),s=await(async e=>({name:"keyboardnav",title:"Keyboard Navigation",items:[{type:"htmlpanel",presets:"document",html:await w(e)}]}))(a),l=T(e),m=(()=>{var e,t;const n='<a data-alloy-tabstop="true" tabindex="-1" href="https://www.tiny.cloud/docs/tinymce/7/changelog/?utm_campaign=help_dialog_version_tab&utm_source=tiny&utm_medium=referral" rel="noopener" target="_blank">TinyMCE '+(e=O.majorVersion,t=O.minorVersion,(0===e.indexOf("@")?"X.X.X":e+"."+t)+"</a>");return{name:"versions",title:"Version",items:[{type:"htmlpanel",html:"<p>"+f.translate(["You are using {0}",n])+"</p>",presets:"document"}]}})(),u={[o.name]:o,[s.name]:s,[l.name]:l,[m.name]:m,...t.get()};return c.from(r(e)).fold((()=>(e=>{const t=g(e),n=t.indexOf("versions");return-1!==n&&(t.splice(n,1),t.push("versions")),{tabs:e,names:t}})(u)),(e=>((e,t)=>{const a={},r=y(e,(e=>{var r;if(i(e))return v(t,e)&&(a[e]=t[e]),e;{const t=null!==(r=e.name)&&void 0!==r?r:n("tab-name");return a[t]=e,t}}));return{tabs:a,names:r}})(e,u)))})(e,t,a).then((({tabs:t,names:n})=>{const a={type:"tabpanel",tabs:(e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(n);return t})(y(n,(e=>{return v(n=t,a=e)?c.from(n[a]):c.none();var n,a})))};e.windowManager.open({title:"Help",size:"medium",body:a,buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{}})}))};e.add("help",((e,t)=>{const a=(e=>{let t={};return{get:()=>t,set:e=>{t=e}}})(),r=(e=>({addTab:t=>{var a;const r=null!==(a=t.name)&&void 0!==a?a:n("tab-name"),o=e.get();o[r]=t,e.set(o)}}))(a);(e=>{(0,e.options.register)("help_tabs",{processor:"array"})})(e);const o=F(e,a,t);return((e,t)=>{e.ui.registry.addButton("help",{icon:"help",tooltip:"Help",onAction:t}),e.ui.registry.addMenuItem("help",{text:"Help",icon:"help",shortcut:"Alt+0",onAction:t})})(e,o),((e,t)=>{e.addCommand("mceHelp",t)})(e,o),e.shortcuts.add("Alt+0","Open help dialog","mceHelp"),((e,t)=>{e.on("init",(()=>{w(t)}))})(e,t),r}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/image/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/image/plugin.min.js
new file mode 100644
index 0000000..87959cc
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/image/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=Object.getPrototypeOf,a=(e,t,a)=>{var i;return!!a(e,t.prototype)||(null===(i=e.constructor)||void 0===i?void 0:i.name)===t.name},i=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&a(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,s=e=>t=>typeof t===e,r=i("string"),o=i("object"),n=e=>((e,i)=>o(e)&&a(e,i,((e,a)=>t(e)===a)))(e,Object),l=i("array"),c=(null,e=>null===e);const m=s("boolean"),d=e=>!(e=>null==e)(e),g=s("function"),u=s("number"),p=()=>{};class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return d(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const b=Object.keys,v=Object.hasOwnProperty,y=(e,t)=>v.call(e,t),f=Array.prototype.push,w=e=>{const t=[];for(let a=0,i=e.length;a<i;++a){if(!l(e[a]))throw new Error("Arr.flatten item "+a+" was not an array, input: "+e);f.apply(t,e[a])}return t};"undefined"!=typeof window?window:Function("return this;")();const A=(e,t,a)=>{((e,t,a)=>{if(!(r(a)||m(a)||u(a)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",a,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,a+"")})(e.dom,t,a)},D=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},_=D;var C=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),I=tinymce.util.Tools.resolve("tinymce.util.URI");const U=e=>e.length>0,x=e=>t=>t.options.get(e),S=x("image_dimensions"),N=x("image_advtab"),T=x("image_uploadtab"),O=x("image_prepend_url"),E=x("image_class_list"),L=x("image_description"),j=x("image_title"),M=x("image_caption"),R=x("image_list"),k=x("a11y_advanced_options"),z=x("automatic_uploads"),B=(e,t)=>Math.max(parseInt(e,10),parseInt(t,10)),P=e=>(e&&(e=e.replace(/px$/,"")),e),F=e=>(e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e),H=e=>"IMG"===e.nodeName&&(e.hasAttribute("data-mce-object")||e.hasAttribute("data-mce-placeholder")),G=(e,t)=>{const a=e.options.get;return I.isDomSafe(t,"img",{allow_html_data_urls:a("allow_html_data_urls"),allow_script_urls:a("allow_script_urls"),allow_svg_data_urls:a("allow_svg_data_urls")})},W=C.DOM,$=e=>e.style.marginLeft&&e.style.marginRight&&e.style.marginLeft===e.style.marginRight?P(e.style.marginLeft):"",V=e=>e.style.marginTop&&e.style.marginBottom&&e.style.marginTop===e.style.marginBottom?P(e.style.marginTop):"",K=e=>e.style.borderWidth?P(e.style.borderWidth):"",Z=(e,t)=>{var a;return e.hasAttribute(t)&&null!==(a=e.getAttribute(t))&&void 0!==a?a:""},q=e=>null!==e.parentNode&&"FIGURE"===e.parentNode.nodeName,J=(e,t,a)=>{""===a||null===a?e.removeAttribute(t):e.setAttribute(t,a)},Q=(e,t)=>{const a=e.getAttribute("style"),i=t(null!==a?a:"");i.length>0?(e.setAttribute("style",i),e.setAttribute("data-mce-style",i)):e.removeAttribute("style")},X=(e,t)=>(e,a,i)=>{const s=e.style;s[a]?(s[a]=F(i),Q(e,t)):J(e,a,i)},Y=(e,t)=>e.style[t]?P(e.style[t]):Z(e,t),ee=(e,t)=>{const a=F(t);e.style.marginLeft=a,e.style.marginRight=a},te=(e,t)=>{const a=F(t);e.style.marginTop=a,e.style.marginBottom=a},ae=(e,t)=>{const a=F(t);e.style.borderWidth=a},ie=(e,t)=>{e.style.borderStyle=t},se=e=>{var t;return null!==(t=e.style.borderStyle)&&void 0!==t?t:""},re=e=>d(e)&&"FIGURE"===e.nodeName,oe=e=>0===W.getAttrib(e,"alt").length&&"presentation"===W.getAttrib(e,"role"),ne=e=>oe(e)?"":Z(e,"alt"),le=(e,t)=>{var a;const i=document.createElement("img");return J(i,"style",t.style),($(i)||""!==t.hspace)&&ee(i,t.hspace),(V(i)||""!==t.vspace)&&te(i,t.vspace),(K(i)||""!==t.border)&&ae(i,t.border),(se(i)||""!==t.borderStyle)&&ie(i,t.borderStyle),e(null!==(a=i.getAttribute("style"))&&void 0!==a?a:"")},ce=(e,t)=>({src:Z(t,"src"),alt:ne(t),title:Z(t,"title"),width:Y(t,"width"),height:Y(t,"height"),class:Z(t,"class"),style:e(Z(t,"style")),caption:q(t),hspace:$(t),vspace:V(t),border:K(t),borderStyle:se(t),isDecorative:oe(t)}),me=(e,t,a,i,s)=>{a[i]!==t[i]&&s(e,i,String(a[i]))},de=(e,t,a)=>{if(a){W.setAttrib(e,"role","presentation");const t=_(e);A(t,"alt","")}else{if(c(t)){"alt",_(e).dom.removeAttribute("alt")}else{const a=_(e);A(a,"alt",t)}"presentation"===W.getAttrib(e,"role")&&W.setAttrib(e,"role","")}},ge=(e,t)=>(a,i,s)=>{e(a,s),Q(a,t)},ue=(e,t,a)=>{const i=ce(e,a);me(a,i,t,"caption",((e,t,a)=>(e=>{q(e)?(e=>{const t=e.parentNode;d(t)&&(W.insertAfter(e,t),W.remove(t))})(e):(e=>{const t=W.create("figure",{class:"image"});W.insertAfter(t,e),t.appendChild(e),t.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),t.contentEditable="false"})(e)})(e))),me(a,i,t,"src",J),me(a,i,t,"title",J),me(a,i,t,"width",X(0,e)),me(a,i,t,"height",X(0,e)),me(a,i,t,"class",J),me(a,i,t,"style",ge(((e,t)=>J(e,"style",t)),e)),me(a,i,t,"hspace",ge(ee,e)),me(a,i,t,"vspace",ge(te,e)),me(a,i,t,"border",ge(ae,e)),me(a,i,t,"borderStyle",ge(ie,e)),((e,t,a)=>{a.alt===t.alt&&a.isDecorative===t.isDecorative||de(e,a.alt,a.isDecorative)})(a,i,t)},pe=(e,t)=>{const a=(e=>{if(e.margin){const t=String(e.margin).split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e})(e.dom.styles.parse(t)),i=e.dom.styles.parse(e.dom.styles.serialize(a));return e.dom.styles.serialize(i)},he=e=>{const t=e.selection.getNode(),a=e.dom.getParent(t,"figure.image");return a?e.dom.select("img",a)[0]:t&&("IMG"!==t.nodeName||H(t))?null:t},be=(e,t)=>{var a;const i=e.dom,s=((t,a)=>{const i={};var s;return((e,t,a,i)=>{((e,t)=>{const a=b(e);for(let i=0,s=a.length;i<s;i++){const s=a[i];t(e[s],s)}})(e,((e,s)=>{(t(e,s)?a:i)(e,s)}))})(t,((t,a)=>!e.schema.isValidChild(a,"figure")),(s=i,(e,t)=>{s[t]=e}),p),i})(e.schema.getTextBlockElements()),r=i.getParent(t.parentNode,(e=>{return t=s,a=e.nodeName,y(t,a)&&void 0!==t[a]&&null!==t[a];var t,a}),e.getBody());return r&&null!==(a=i.split(r,t))&&void 0!==a?a:t},ve=(e,t)=>{const a=((t,a)=>{const i=document.createElement("img");if(ue((t=>pe(e,t)),{...a,caption:!1},i),de(i,a.alt,a.isDecorative),a.caption){const e=W.create("figure",{class:"image"});return e.appendChild(i),e.appendChild(W.create("figcaption",{contentEditable:"true"},"Caption")),e.contentEditable="false",e}return i})(0,t);e.dom.setAttrib(a,"data-mce-id","__mcenew"),e.focus(),e.selection.setContent(a.outerHTML);const i=e.dom.select('*[data-mce-id="__mcenew"]')[0];if(e.dom.setAttrib(i,"data-mce-id",null),re(i)){const t=be(e,i);e.selection.select(t)}else e.selection.select(i)},ye=(e,t)=>{const a=he(e);if(a){const i={...ce((t=>pe(e,t)),a),...t},s=((e,t)=>{const a=t.src;return{...t,src:G(e,a)?a:""}})(e,i);i.src?((e,t)=>{const a=he(e);if(a)if(ue((t=>pe(e,t)),t,a),((e,t)=>{e.dom.setAttrib(t,"src",t.getAttribute("src"))})(e,a),re(a.parentNode)){const t=a.parentNode;be(e,t),e.selection.select(a.parentNode)}else e.selection.select(a),((e,t,a)=>{const i=()=>{a.onload=a.onerror=null,e.selection&&(e.selection.select(a),e.nodeChanged())};a.onload=()=>{t.width||t.height||!S(e)||e.dom.setAttribs(a,{width:String(a.clientWidth),height:String(a.clientHeight)}),i()},a.onerror=i})(e,t,a)})(e,s):((e,t)=>{if(t){const a=e.dom.is(t.parentNode,"figure.image")?t.parentNode:t;e.dom.remove(a),e.focus(),e.nodeChanged(),e.dom.isEmpty(e.getBody())&&(e.setContent(""),e.selection.setCursorLocation())}})(e,a)}else t.src&&ve(e,{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1,...t})},fe=(we=(e,t)=>n(e)&&n(t)?fe(e,t):t,(...e)=>{if(0===e.length)throw new Error("Can't merge zero objects");const t={};for(let a=0;a<e.length;a++){const i=e[a];for(const e in i)y(i,e)&&(t[e]=we(t[e],i[e]))}return t});var we,Ae=tinymce.util.Tools.resolve("tinymce.util.ImageUploader"),De=tinymce.util.Tools.resolve("tinymce.util.Tools");const _e=e=>r(e.value)?e.value:"",Ce=(e,t)=>{const a=[];return De.each(e,(e=>{const i=(e=>r(e.text)?e.text:r(e.title)?e.title:"")(e);if(void 0!==e.menu){const s=Ce(e.menu,t);a.push({text:i,items:s})}else{const s=t(e);a.push({text:i,value:s})}})),a},Ie=(e=_e)=>t=>t?h.from(t).map((t=>Ce(t,e))):h.none(),Ue=(e,t)=>((e,a)=>{for(let a=0;a<e.length;a++){const s=(e=>y(e,"items"))(i=e[a])?Ue(i.items,t):i.value===t?h.some(i):h.none();if(s.isSome())return s}var i;return h.none()})(e),xe=Ie,Se=(e,t)=>e.bind((e=>Ue(e,t))),Ne=e=>{const t=xe((t=>e.convertURL(t.value||t.url||"","src"))),a=new Promise((a=>{((e,t)=>{const a=R(e);r(a)?fetch(a).then((e=>{e.ok&&e.json().then(t)})):g(a)?a(t):t(a)})(e,(e=>{a(t(e).map((e=>w([[{text:"None",value:""}],e]))))}))})),i=(A=E(e),Ie(_e)(A)),s=N(e),o=T(e),n=(e=>U(e.options.get("images_upload_url")))(e),l=(e=>d(e.options.get("images_upload_handler")))(e),c=(e=>{const t=he(e);return t?ce((t=>pe(e,t)),t):{src:"",alt:"",title:"",width:"",height:"",class:"",style:"",caption:!1,hspace:"",vspace:"",border:"",borderStyle:"",isDecorative:!1}})(e),m=L(e),u=j(e),p=S(e),b=M(e),v=k(e),y=z(e),f=h.some(O(e)).filter((e=>r(e)&&e.length>0));var A;return a.then((e=>({image:c,imageList:e,classList:i,hasAdvTab:s,hasUploadTab:o,hasUploadUrl:n,hasUploadHandler:l,hasDescription:m,hasImageTitle:u,hasDimensions:p,hasImageCaption:b,prependURL:f,hasAccessibilityOptions:v,automaticUploads:y})))},Te=e=>{const t=e.imageList.map((e=>({name:"images",type:"listbox",label:"Image list",items:e}))),a={name:"alt",type:"input",label:"Alternative description",enabled:!(e.hasAccessibilityOptions&&e.image.isDecorative)},i=e.classList.map((e=>({name:"classes",type:"listbox",label:"Class",items:e})));return w([[{name:"src",type:"urlinput",filetype:"image",label:"Source",picker_text:"Browse files"}],t.toArray(),e.hasAccessibilityOptions&&e.hasDescription?[{type:"label",label:"Accessibility",items:[{name:"isDecorative",type:"checkbox",label:"Image is decorative"}]}]:[],e.hasDescription?[a]:[],e.hasImageTitle?[{name:"title",type:"input",label:"Image title"}]:[],e.hasDimensions?[{name:"dimensions",type:"sizeinput"}]:[],[{...(s=e.classList.isSome()&&e.hasImageCaption,s?{type:"grid",columns:2}:{type:"panel"}),items:w([i.toArray(),e.hasImageCaption?[{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[]])}]]);var s},Oe=e=>({title:"General",name:"general",items:Te(e)}),Ee=Te,Le=e=>({src:{value:e.src,meta:{}},images:e.src,alt:e.alt,title:e.title,dimensions:{width:e.width,height:e.height},classes:e.class,caption:e.caption,style:e.style,vspace:e.vspace,border:e.border,hspace:e.hspace,borderstyle:e.borderStyle,fileinput:[],isDecorative:e.isDecorative}),je=(e,t)=>({src:e.src.value,alt:null!==e.alt&&0!==e.alt.length||!t?e.alt:null,title:e.title,width:e.dimensions.width,height:e.dimensions.height,class:e.classes,style:e.style,caption:e.caption,hspace:e.hspace,vspace:e.vspace,border:e.border,borderStyle:e.borderstyle,isDecorative:e.isDecorative}),Me=(e,t,a,i)=>{((e,t)=>{const a=t.getData();((e,t)=>/^(?:[a-zA-Z]+:)?\/\//.test(t)?h.none():e.prependURL.bind((e=>t.substring(0,e.length)!==e?h.some(e+t):h.none())))(e,a.src.value).each((e=>{t.setData({src:{value:e,meta:a.src.meta}})}))})(t,i),((e,t)=>{const a=t.getData(),i=a.src.meta;if(void 0!==i){const s=fe({},a);((e,t,a)=>{e.hasDescription&&r(a.alt)&&(t.alt=a.alt),e.hasAccessibilityOptions&&(t.isDecorative=a.isDecorative||t.isDecorative||!1),e.hasImageTitle&&r(a.title)&&(t.title=a.title),e.hasDimensions&&(r(a.width)&&(t.dimensions.width=a.width),r(a.height)&&(t.dimensions.height=a.height)),r(a.class)&&Se(e.classList,a.class).each((e=>{t.classes=e.value})),e.hasImageCaption&&m(a.caption)&&(t.caption=a.caption),e.hasAdvTab&&(r(a.style)&&(t.style=a.style),r(a.vspace)&&(t.vspace=a.vspace),r(a.border)&&(t.border=a.border),r(a.hspace)&&(t.hspace=a.hspace),r(a.borderstyle)&&(t.borderstyle=a.borderstyle))})(e,s,i),t.setData(s)}})(t,i),((e,t,a,i)=>{const s=i.getData(),r=s.src.value,o=s.src.meta||{};o.width||o.height||!t.hasDimensions||(U(r)?e.imageSize(r).then((e=>{a.open&&i.setData({dimensions:e})})).catch((e=>console.error(e))):i.setData({dimensions:{width:"",height:""}}))})(e,t,a,i),((e,t,a)=>{const i=a.getData(),s=Se(e.imageList,i.src.value);t.prevImage=s,a.setData({images:s.map((e=>e.value)).getOr("")})})(t,a,i)},Re=(e,t,a,i)=>{const s=i.getData();var r;i.block("Uploading image"),(r=s.fileinput,((e,t)=>0<e.length?h.some(e[0]):h.none())(r)).fold((()=>{i.unblock()}),(s=>{const r=URL.createObjectURL(s),o=()=>{i.unblock(),URL.revokeObjectURL(r)},n=s=>{i.setData({src:{value:s,meta:{}}}),i.showTab("general"),Me(e,t,a,i),i.focus("src")};var l;(l=s,new Promise(((e,t)=>{const a=new FileReader;a.onload=()=>{e(a.result)},a.onerror=()=>{var e;t(null===(e=a.error)||void 0===e?void 0:e.message)},a.readAsDataURL(l)}))).then((a=>{const l=e.createBlobCache(s,r,a);t.automaticUploads?e.uploadImage(l).then((e=>{n(e.url),o()})).catch((t=>{o(),e.alertErr(t)})):(e.addToBlobCache(l),n(l.blobUri()),i.unblock())}))}))},ke=(e,t,a)=>(i,s)=>{"src"===s.name?Me(e,t,a,i):"images"===s.name?((e,t,a,i)=>{const s=i.getData(),r=Se(t.imageList,s.images);r.each((e=>{const t=""===s.alt||a.prevImage.map((e=>e.text===s.alt)).getOr(!1);t?""===e.value?i.setData({src:e,alt:a.prevAlt}):i.setData({src:e,alt:e.text}):i.setData({src:e})})),a.prevImage=r,Me(e,t,a,i)})(e,t,a,i):"alt"===s.name?a.prevAlt=i.getData().alt:"fileinput"===s.name?Re(e,t,a,i):"isDecorative"===s.name&&i.setEnabled("alt",!i.getData().isDecorative)},ze=e=>()=>{e.open=!1},Be=e=>e.hasAdvTab||e.hasUploadUrl||e.hasUploadHandler?{type:"tabpanel",tabs:w([[Oe(e)],e.hasAdvTab?[{title:"Advanced",name:"advanced",items:[{type:"grid",columns:2,items:[{type:"input",label:"Vertical space",name:"vspace",inputMode:"numeric"},{type:"input",label:"Horizontal space",name:"hspace",inputMode:"numeric"},{type:"input",label:"Border width",name:"border",inputMode:"numeric"},{type:"listbox",name:"borderstyle",label:"Border style",items:[{text:"Select...",value:""},{text:"Solid",value:"solid"},{text:"Dotted",value:"dotted"},{text:"Dashed",value:"dashed"},{text:"Double",value:"double"},{text:"Groove",value:"groove"},{text:"Ridge",value:"ridge"},{text:"Inset",value:"inset"},{text:"Outset",value:"outset"},{text:"None",value:"none"},{text:"Hidden",value:"hidden"}]}]}]}]:[],e.hasUploadTab&&(e.hasUploadUrl||e.hasUploadHandler)?[{title:"Upload",name:"upload",items:[{type:"dropzone",name:"fileinput"}]}]:[]])}:{type:"panel",items:Ee(e)},Pe=(e,t,a)=>i=>{const s=fe(Le(t.image),i.getData()),r={...s,style:le(a.normalizeCss,je(s,!1))};e.execCommand("mceUpdateImage",!1,je(r,t.hasAccessibilityOptions)),e.editorUpload.uploadImagesAuto(),i.close()},Fe=e=>t=>G(e,t)?(e=>new Promise((t=>{const a=document.createElement("img"),i=e=>{a.onload=a.onerror=null,a.parentNode&&a.parentNode.removeChild(a),t(e)};a.onload=()=>{const e={width:B(a.width,a.clientWidth),height:B(a.height,a.clientHeight)};i(Promise.resolve(e))},a.onerror=()=>{i(Promise.reject(`Failed to get image dimensions for: ${e}`))};const s=a.style;s.visibility="hidden",s.position="fixed",s.bottom=s.left="0px",s.width=s.height="auto",document.body.appendChild(a),a.src=e})))(e.documentBaseURI.toAbsolute(t)).then((e=>({width:String(e.width),height:String(e.height)}))):Promise.resolve({width:"",height:""}),He=e=>(t,a,i)=>{var s;return e.editorUpload.blobCache.create({blob:t,blobUri:a,name:null===(s=t.name)||void 0===s?void 0:s.replace(/\.[^\.]+$/,""),filename:t.name,base64:i.split(",")[1]})},Ge=e=>t=>{e.editorUpload.blobCache.add(t)},We=e=>t=>{e.windowManager.alert(t)},$e=e=>t=>pe(e,t),Ve=e=>t=>e.dom.parseStyle(t),Ke=e=>(t,a)=>e.dom.serializeStyle(t,a),Ze=e=>t=>Ae(e).upload([t],!1).then((e=>{var t;return 0===e.length?Promise.reject("Failed to upload image"):!1===e[0].status?Promise.reject(null===(t=e[0].error)||void 0===t?void 0:t.message):e[0]})),qe=e=>{const t={imageSize:Fe(e),addToBlobCache:Ge(e),createBlobCache:He(e),alertErr:We(e),normalizeCss:$e(e),parseStyle:Ve(e),serializeStyle:Ke(e),uploadImage:Ze(e)};return{open:()=>{Ne(e).then((a=>{const i=(e=>({prevImage:Se(e.imageList,e.image.src),prevAlt:e.image.alt,open:!0}))(a);return{title:"Insert/Edit Image",size:"normal",body:Be(a),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:Le(a.image),onSubmit:Pe(e,a,t),onChange:ke(t,a,i),onClose:ze(i)}})).then(e.windowManager.open)}}},Je=e=>{const t=e.attr("class");return d(t)&&/\bimage\b/.test(t)},Qe=e=>t=>{let a=t.length;const i=t=>{t.attr("contenteditable",e?"true":null)};for(;a--;){const s=t[a];Je(s)&&(s.attr("contenteditable",e?"false":null),De.each(s.getAll("figcaption"),i))}},Xe=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("image",(e=>{(e=>{const t=e.options.register;t("image_dimensions",{processor:"boolean",default:!0}),t("image_advtab",{processor:"boolean",default:!1}),t("image_uploadtab",{processor:"boolean",default:!0}),t("image_prepend_url",{processor:"string",default:""}),t("image_class_list",{processor:"object[]"}),t("image_description",{processor:"boolean",default:!0}),t("image_title",{processor:"boolean",default:!1}),t("image_caption",{processor:"boolean",default:!1}),t("image_list",{processor:e=>{const t=!1===e||r(e)||((e,t)=>{if(l(e)){for(let a=0,i=e.length;a<i;++a)if(!t(e[a]))return!1;return!0}return!1})(e,o)||g(e);return t?{value:e,valid:t}:{valid:!1,message:"Must be false, a string, an array or a function."}},default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("figure",Qe(!0)),e.serializer.addNodeFilter("figure",Qe(!1))}))})(e),(e=>{e.ui.registry.addToggleButton("image",{icon:"image",tooltip:"Insert/edit image",onAction:qe(e).open,onSetup:t=>{t.setActive(d(he(e)));const a=e.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image",t.setActive).unbind,i=Xe(e)(t);return()=>{a(),i()}}}),e.ui.registry.addMenuItem("image",{icon:"image",text:"Image...",onAction:qe(e).open,onSetup:Xe(e)}),e.ui.registry.addContextMenu("image",{update:t=>e.selection.isEditable()&&(re(t)||"IMG"===t.nodeName&&!H(t))?["image"]:[]})})(e),(e=>{e.addCommand("mceImage",qe(e).open),e.addCommand("mceUpdateImage",((t,a)=>{e.undoManager.transact((()=>ye(e,a)))}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/importcss/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/importcss/plugin.min.js
new file mode 100644
index 0000000..a59099b
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/importcss/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),g=p("importcss_file_filter"),_=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),M=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s<r;++s){if(!o(e[s]))throw new Error("Arr.flatten item "+s+" was not an array, input: "+e);b.apply(t,e[s])}return t})(((e,t)=>{const s=e.length,r=new Array(s);for(let o=0;o<s;o++){const s=e[o];r[o]=t(s,o)}return r})(r,n))).concat(e);var r,n}}})(),r={},n=T(y(e)),p=(e=>a.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=_(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/",c=e.editorManager.suffix;return t===o+"/content"+(e.inline?".inline":"")+`${c}.css`||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet&&e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(g(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),M(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/insertdatetime/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/insertdatetime/plugin.min.js
new file mode 100644
index 0000000..06b5a09
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/insertdatetime/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),n=t("insertdatetime_timeformat"),r=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length<t)for(let a=0;a<t-e.length;a++)e="0"+e;return e},d=(e,t,a=new Date)=>(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let n;n=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const r=e.dom.getParent(e.selection.getStart(),"time");r?((e,t,a,n)=>{const r=e.dom.create("time",{datetime:a},n);e.dom.replace(r,t),e.selection.select(r,!0),e.selection.collapse(!1)})(e,r,n,a):e.insertContent('<time datetime="'+n+'">'+a+"</time>")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const g=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,n)=>{u(e,null!=n?n:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:n(e))}))})(e),(e=>{const t=r(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=r(e);return t.length>0?t[0]:n(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)},onSetup:g(e)});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)}))),onSetup:g(e)})})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/link/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/link/plugin.min.js
new file mode 100644
index 0000000..65e9efa
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/link/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(l=o.constructor)||void 0===l?void 0:l.name)===r.name)?"string":t;var n,o,r,l})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),l=t("array"),s=(null,e=>null===e);const a=n("boolean"),i=e=>!(e=>null==e)(e),c=n("function"),u=(e,t)=>{if(l(e)){for(let n=0,o=e.length;n<o;++n)if(!t(e[n]))return!1;return!0}return!1},g=()=>{},d=(e,t)=>e===t;class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return i(e)?m.some(e):m.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const h=Array.prototype.indexOf,p=Array.prototype.push,f=e=>{const t=[];for(let n=0,o=e.length;n<o;++n){if(!l(e[n]))throw new Error("Arr.flatten item "+n+" was not an array, input: "+e);p.apply(t,e[n])}return t},k=(e,t)=>{for(let n=0;n<e.length;n++){const o=t(e[n],n);if(o.isSome())return o}return m.none()},v=(e,t,n=d)=>e.exists((e=>n(e,t))),x=e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(n);return t},y=(e,t)=>e?m.some(t):m.none(),b=e=>t=>t.options.get(e),_=b("link_assume_external_targets"),w=b("link_context_toolbar"),C=b("link_list"),O=b("link_default_target"),S=b("link_default_protocol"),N=b("link_target_list"),A=b("link_rel_list"),T=b("link_class_list"),E=b("link_title"),L=b("allow_unsafe_link_target"),R=b("link_quicklink"),P=Object.keys,M=Object.hasOwnProperty,D=(e,t)=>M.call(e,t);var B=tinymce.util.Tools.resolve("tinymce.util.URI"),I=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),K=tinymce.util.Tools.resolve("tinymce.util.Tools");const j=e=>i(e)&&"a"===e.nodeName.toLowerCase(),U=e=>j(e)&&!!V(e),q=(e,t)=>{if(e.collapsed)return[];{const n=e.cloneContents(),o=n.firstChild,r=new I(o,n),l=[];let s=o;do{t(s)&&l.push(s)}while(s=r.next());return l}},F=e=>/^\w+:/i.test(e),V=e=>{var t,n;return null!==(n=null!==(t=e.getAttribute("data-mce-href"))&&void 0!==t?t:e.getAttribute("href"))&&void 0!==n?n:""},$=(e,t)=>{const n=["noopener"],o=e?e.split(/\s+/):[],r=e=>e.filter((e=>-1===K.inArray(n,e))),l=t?(e=>(e=r(e)).length>0?e.concat(n):n)(o):r(o);return l.length>0?(e=>K.trim(e.sort().join(" ")))(l):""},z=(e,t)=>(t=t||J(e.selection.getRng())[0]||e.selection.getNode(),Y(t)?m.from(e.dom.select("a[href]",t)[0]):m.from(e.dom.getParent(t,"a[href]"))),G=(e,t)=>z(e,t).isSome(),H=(e,t)=>t.fold((()=>e.getContent({format:"text"})),(e=>e.innerText||e.textContent||"")).replace(/\uFEFF/g,""),J=e=>q(e,U),W=e=>K.grep(e,U),Q=e=>W(e).length>0,X=e=>{const t=e.schema.getTextInlineElements();if(z(e).exists((e=>e.hasAttribute("data-mce-block"))))return!1;const n=e.selection.getRng();return!!n.collapsed||0===q(n,(e=>1===e.nodeType&&!j(e)&&!D(t,e.nodeName.toLowerCase()))).length},Y=e=>i(e)&&"FIGURE"===e.nodeName&&/\bimage\b/i.test(e.className),Z=(e,t,n)=>{const o=e.selection.getNode(),r=z(e,o),l=((e,t)=>{const n={...t};if(0===A(e).length&&!L(e)){const e=$(n.rel,"_blank"===n.target);n.rel=e||null}return m.from(n.target).isNone()&&!1===N(e)&&(n.target=O(e)),n.href=((e,t)=>"http"!==t&&"https"!==t||F(e)?e:t+"://"+e)(n.href,_(e)),n})(e,(e=>{return t=["title","rel","class","target"],n=(t,n)=>(e[n].each((e=>{t[n]=e.length>0?e:null})),t),o={href:e.href},((e,t)=>{for(let n=0,o=e.length;n<o;n++)t(e[n],n)})(t,((e,t)=>{o=n(o,e)})),o;var t,n,o})(n));e.undoManager.transact((()=>{n.href===t.href&&t.attach(),r.fold((()=>{((e,t,n,o)=>{const r=e.dom;Y(t)?re(r,t,o):n.fold((()=>{e.execCommand("mceInsertLink",!1,o)}),(t=>{e.insertContent(r.createHTML("a",o,r.encode(t)))}))})(e,o,n.text,l)}),(t=>{e.focus(),((e,t,n,o)=>{n.each((e=>{D(t,"innerText")?t.innerText=e:t.textContent=e})),e.dom.setAttribs(t,o),e.selection.select(t)})(e,t,n.text,l)}))}))},ee=e=>{const{class:t,href:n,rel:o,target:r,text:l,title:a}=e;return((e,t)=>{const n={};var o;return((e,t,n,o)=>{((e,t)=>{const n=P(e);for(let o=0,r=n.length;o<r;o++){const r=n[o];t(e[r],r)}})(e,((e,r)=>{(t(e,r)?n:o)(e,r)}))})(e,((e,t)=>!1===s(e)),(o=n,(e,t)=>{o[t]=e}),g),n})({class:t.getOrNull(),href:n,rel:o.getOrNull(),target:r.getOrNull(),text:l.getOrNull(),title:a.getOrNull()})},te=(e,t,n)=>{const o=((e,t)=>{const n=e.options.get,o={allow_html_data_urls:n("allow_html_data_urls"),allow_script_urls:n("allow_script_urls"),allow_svg_data_urls:n("allow_svg_data_urls")},r=t.href;return{...t,href:B.isDomSafe(r,"a",o)?r:""}})(e,n);e.hasPlugin("rtc",!0)?e.execCommand("createlink",!1,ee(o)):Z(e,t,o)},ne=e=>{e.hasPlugin("rtc",!0)?e.execCommand("unlink"):(e=>{e.undoManager.transact((()=>{const t=e.selection.getNode();Y(t)?oe(e,t):(e=>{const t=e.dom,n=e.selection,o=n.getBookmark(),r=n.getRng().cloneRange(),l=t.getParent(r.startContainer,"a[href]",e.getBody()),s=t.getParent(r.endContainer,"a[href]",e.getBody());l&&r.setStartBefore(l),s&&r.setEndAfter(s),n.setRng(r),e.execCommand("unlink"),n.moveToBookmark(o)})(e),e.focus()}))})(e)},oe=(e,t)=>{var n;const o=e.dom.select("img",t)[0];if(o){const r=e.dom.getParents(o,"a[href]",t)[0];r&&(null===(n=r.parentNode)||void 0===n||n.insertBefore(o,r),e.dom.remove(r))}},re=(e,t,n)=>{var o;const r=e.select("img",t)[0];if(r){const t=e.create("a",n);null===(o=r.parentNode)||void 0===o||o.insertBefore(t,r),t.appendChild(r)}},le=e=>o(e.value)?e.value:"",se=(e,t)=>{const n=[];return K.each(e,(e=>{const r=(e=>o(e.text)?e.text:o(e.title)?e.title:"")(e);if(void 0!==e.menu){const o=se(e.menu,t);n.push({text:r,items:o})}else{const o=t(e);n.push({text:r,value:o})}})),n},ae=(e=le)=>t=>m.from(t).map((t=>se(t,e))),ie=e=>ae(le)(e),ce=ae,ue=(e,t)=>n=>({name:e,type:"listbox",label:t,items:n}),ge=le,de=(e,t)=>k(t,(t=>(e=>{return D(t=e,n="items")&&void 0!==t[n]&&null!==t[n];var t,n})(t)?de(e,t.items):y(t.value===e,t))),me=(e,t)=>{const n={text:e.text,title:e.title},o=(e,o)=>{const r=(l=t,s=o,"link"===s?l.link:"anchor"===s?l.anchor:m.none()).getOr([]);var l,s;return((e,t,n,o)=>{const r=o[t],l=e.length>0;return void 0!==r?de(r,n).map((t=>({url:{value:t.value,meta:{text:l?e:t.text,attach:g}},text:l?e:t.text}))):m.none()})(n.text,o,r,e)};return{onChange:(e,t)=>{const r=t.name;return"url"===r?(e=>{const t=(o=e.url,y(n.text.length<=0,m.from(null===(r=o.meta)||void 0===r?void 0:r.text).getOr(o.value)));var o,r;const l=(e=>{var t;return y(n.title.length<=0,m.from(null===(t=e.meta)||void 0===t?void 0:t.title).getOr(""))})(e.url);return t.isSome()||l.isSome()?m.some({...t.map((e=>({text:e}))).getOr({}),...l.map((e=>({title:e}))).getOr({})}):m.none()})(e()):((e,t)=>h.call(e,t))(["anchor","link"],r)>-1?o(e(),r):"text"===r||"title"===r?(n[r]=e()[r],m.none()):m.none()}}};var he=tinymce.util.Tools.resolve("tinymce.util.Delay");const pe=e=>{const t=e.href;return t.indexOf("@")>0&&-1===t.indexOf("/")&&-1===t.indexOf("mailto:")?m.some({message:"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",preprocess:e=>({...e,href:"mailto:"+t})}):m.none()},fe=(e,t)=>n=>{const o=n.href;return 1===e&&!F(o)||0===e&&/^\s*www(\.|\d\.)/i.test(o)?m.some({message:`The URL you entered seems to be an external link. Do you want to add the required ${t}:// prefix?`,preprocess:e=>({...e,href:t+"://"+o})}):m.none()},ke=e=>{const t=e.dom.select("a:not([href])"),n=f(((e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r<n;r++){const n=e[r];o[r]=t(n,r)}return o})(t,(e=>{const t=e.name||e.id;return t?[{text:t,value:"#"+t}]:[]})));return n.length>0?m.some([{text:"None",value:""}].concat(n)):m.none()},ve=e=>{const t=T(e);return t.length>0?ie(t):m.none()},xe=e=>{try{return m.some(JSON.parse(e))}catch(e){return m.none()}},ye=(e,t)=>{const n=A(e);if(n.length>0){const o=v(t,"_blank"),r=e=>$(ge(e),o);return(!1===L(e)?ce(r):ie)(n)}return m.none()},be=[{text:"Current window",value:""},{text:"New window",value:"_blank"}],_e=e=>{const t=N(e);return l(t)?ie(t).orThunk((()=>m.some(be))):!1===t?m.none():m.some(be)},we=(e,t,n)=>{const o=e.getAttrib(t,n);return null!==o&&o.length>0?m.some(o):m.none()},Ce=(e,t)=>(e=>{const t=t=>e.convertURL(t.value||t.url||"","href"),n=C(e);return new Promise((e=>{o(n)?fetch(n).then((e=>e.ok?e.text().then(xe):Promise.reject())).then(e,(()=>e(m.none()))):c(n)?n((t=>e(m.some(t)))):e(m.from(n))})).then((e=>e.bind(ce(t)).map((e=>e.length>0?[{text:"None",value:""}].concat(e):e))))})(e).then((n=>{const o=((e,t)=>{const n=e.dom,o=X(e)?m.some(H(e.selection,t)):m.none(),r=t.bind((e=>m.from(n.getAttrib(e,"href")))),l=t.bind((e=>m.from(n.getAttrib(e,"target")))),s=t.bind((e=>we(n,e,"rel"))),a=t.bind((e=>we(n,e,"class")));return{url:r,text:o,title:t.bind((e=>we(n,e,"title"))),target:l,rel:s,linkClass:a}})(e,t);return{anchor:o,catalogs:{targets:_e(e),rels:ye(e,o.target),classes:ve(e),anchor:ke(e),link:n},optNode:t,flags:{titleEnabled:E(e)}}})),Oe=e=>{const t=(e=>{const t=z(e);return Ce(e,t)})(e);t.then((t=>{const n=((e,t)=>n=>{const o=n.getData();if(!o.url.value)return ne(e),void n.close();const r=e=>m.from(o[e]).filter((n=>!v(t.anchor[e],n))),l={href:o.url.value,text:r("text"),target:r("target"),rel:r("rel"),class:r("linkClass"),title:r("title")},s={href:o.url.value,attach:void 0!==o.url.meta&&o.url.meta.attach?o.url.meta.attach:g};((e,t)=>k([pe,fe(_(e),S(e))],(e=>e(t))).fold((()=>Promise.resolve(t)),(n=>new Promise((o=>{((e,t,n)=>{const o=e.selection.getRng();he.setEditorTimeout(e,(()=>{e.windowManager.confirm(t,(t=>{e.selection.setRng(o),n(t)}))}))})(e,n.message,(e=>{o(e?n.preprocess(t):t)}))})))))(e,l).then((t=>{te(e,s,t)})),n.close()})(e,t);return((e,t,n)=>{const o=e.anchor.text.map((()=>({name:"text",type:"input",label:"Text to display"}))).toArray(),r=e.flags.titleEnabled?[{name:"title",type:"input",label:"Title"}]:[],l=((e,t)=>{const n=e.anchor,o=n.url.getOr("");return{url:{value:o,meta:{original:{value:o}}},text:n.text.getOr(""),title:n.title.getOr(""),anchor:o,link:o,rel:n.rel.getOr(""),target:n.target.or(t).getOr(""),linkClass:n.linkClass.getOr("")}})(e,m.from(O(n))),s=e.catalogs,a=me(l,s);return{title:"Insert/Edit Link",size:"normal",body:{type:"panel",items:f([[{name:"url",type:"urlinput",filetype:"file",label:"URL",picker_text:"Browse links"}],o,r,x([s.anchor.map(ue("anchor","Anchors")),s.rels.map(ue("rel","Rel")),s.targets.map(ue("target","Open link in...")),s.link.map(ue("link","Link list")),s.classes.map(ue("linkClass","Class"))])])},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onChange:(e,{name:t})=>{a.onChange(e.getData,{name:t}).each((t=>{e.setData(t)}))},onSubmit:t}})(t,n,e)})).then((t=>{e.windowManager.open(t)}))};var Se=tinymce.util.Tools.resolve("tinymce.util.VK");const Ne=(e,t)=>{if(t){const n=V(t);if(/^#/.test(n)){const t=e.dom.select(n);t.length&&e.selection.scrollIntoView(t[0],!0)}else(e=>{const t=document.createElement("a");t.target="_blank",t.href=e,t.rel="noreferrer noopener";const n=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window});document.dispatchEvent(n),((e,t)=>{document.body.appendChild(e),e.dispatchEvent(t),document.body.removeChild(e)})(t,n)})(t.href)}},Ae=(e,t)=>{const n=W(e.dom.getParents(t));return y(1===n.length,n[0])},Te=e=>e.selection.isCollapsed()||(e=>{const t=e.selection.getRng(),n=t.startContainer;return U(n)&&t.startContainer===t.endContainer&&1===e.dom.select("img",n).length})(e)?Ae(e,e.selection.getStart()):(e=>{const t=J(e.selection.getRng());return y(t.length>0,t[0]).or(Ae(e,e.selection.getNode()))})(e),Ee=e=>()=>{e.execCommand("mceLink",!1,{dialog:!0})},Le=(e,t)=>(e.on("NodeChange",t),()=>e.off("NodeChange",t)),Re=e=>t=>{const n=()=>{t.setActive(!e.mode.isReadOnly()&&G(e,e.selection.getNode())),t.setEnabled(e.selection.isEditable())};return n(),Le(e,n)},Pe=e=>t=>{const n=()=>{t.setEnabled(e.selection.isEditable())};return n(),Le(e,n)},Me=e=>t=>{const n=e.dom.getParents(e.selection.getStart()),o=n=>{t.setEnabled((t=>{return Q(t)||(n=e.selection.getRng(),J(n).length>0);var n})(n)&&e.selection.isEditable())};return o(n),Le(e,(e=>o(e.parents)))},De=e=>{const t=(e=>{const t=(()=>{const e=(e=>{const t=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(m.none()),n=()=>t.get().each(e);return{clear:()=>{n(),t.set(m.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{n(),t.set(m.some(e))}}})(g);return{...e,on:t=>e.get().each(t)}})(),n=()=>t.get().or(Te(e));return e.on("contextmenu",(n=>{Ae(e,n.target).each(t.set)})),e.on("SelectionChange",(()=>{t.isSet()||Te(e).each(t.set)})),e.on("click",(n=>{t.clear();const o=W(e.dom.getParents(n.target));1===o.length&&Se.metaKeyPressed(n)&&(n.preventDefault(),Ne(e,o[0]))})),e.on("keydown",(o=>{t.clear(),!o.isDefaultPrevented()&&13===o.keyCode&&(e=>!0===e.altKey&&!1===e.shiftKey&&!1===e.ctrlKey&&!1===e.metaKey)(o)&&n().each((t=>{o.preventDefault(),Ne(e,t)}))})),{gotoSelectedLink:()=>n().each((t=>Ne(e,t)))}})(e);((e,t)=>{e.ui.registry.addToggleButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Meta+K",onAction:Ee(e),onSetup:Re(e)}),e.ui.registry.addButton("openlink",{icon:"new-tab",tooltip:"Open link",onAction:t.gotoSelectedLink,onSetup:Me(e)}),e.ui.registry.addButton("unlink",{icon:"unlink",tooltip:"Remove link",onAction:()=>ne(e),onSetup:Me(e)})})(e,t),((e,t)=>{e.ui.registry.addMenuItem("openlink",{text:"Open link",icon:"new-tab",onAction:t.gotoSelectedLink,onSetup:Me(e)}),e.ui.registry.addMenuItem("link",{icon:"link",text:"Link...",shortcut:"Meta+K",onAction:Ee(e),onSetup:Pe(e)}),e.ui.registry.addMenuItem("unlink",{icon:"unlink",text:"Remove link",onAction:()=>ne(e),onSetup:Me(e)})})(e,t),(e=>{e.ui.registry.addContextMenu("link",{update:t=>e.dom.isEditable(t)?Q(e.dom.getParents(t,"a"))?"link unlink openlink":"link":""})})(e),((e,t)=>{const n=t=>{const n=e.selection.getNode();return t.setEnabled(G(e,n)),g};e.ui.registry.addContextForm("quicklink",{launch:{type:"contextformtogglebutton",icon:"link",tooltip:"Link",onSetup:Re(e)},label:"Link",predicate:t=>w(e)&&G(e,t),initValue:()=>z(e).fold((()=>""),V),commands:[{type:"contextformtogglebutton",icon:"link",tooltip:"Link",primary:!0,onSetup:t=>{const n=e.selection.getNode();return t.setActive(G(e,n)),Re(e)(t)},onAction:t=>{const n=t.getValue(),o=(t=>{const n=z(e),o=X(e);if(n.isNone()&&o){const o=H(e.selection,n);return y(0===o.length,t)}return m.none()})(n);te(e,{href:n,attach:g},{href:n,text:o,title:m.none(),rel:m.none(),target:m.from(O(e)),class:m.none()}),(e=>{e.selection.collapse(!1)})(e),t.hide()}},{type:"contextformbutton",icon:"unlink",tooltip:"Remove link",onSetup:n,onAction:t=>{ne(e),t.hide()}},{type:"contextformbutton",icon:"new-tab",tooltip:"Open link",onSetup:n,onAction:e=>{t.gotoSelectedLink(),e.hide()}}]})})(e,t)};e.add("link",(e=>{(e=>{const t=e.options.register;t("link_assume_external_targets",{processor:e=>{const t=o(e)||a(e);return t?!0===e?{value:1,valid:t}:"http"===e||"https"===e?{value:e,valid:t}:{value:0,valid:t}:{valid:!1,message:"Must be a string or a boolean."}},default:!1}),t("link_context_toolbar",{processor:"boolean",default:!1}),t("link_list",{processor:e=>o(e)||c(e)||u(e,r)}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"}),t("link_target_list",{processor:e=>a(e)||u(e,r),default:!0}),t("link_rel_list",{processor:"object[]",default:[]}),t("link_class_list",{processor:"object[]",default:[]}),t("link_title",{processor:"boolean",default:!0}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("link_quicklink",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceLink",((t,n)=>{!0!==(null==n?void 0:n.dialog)&&R(e)?e.dispatch("contexttoolbar-show",{toolbarKey:"quicklink"}):Oe(e)}))})(e),De(e),(e=>{e.addShortcut("Meta+K","",(()=>{e.execCommand("mceLink")}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/lists/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/lists/plugin.min.js
new file mode 100644
index 0000000..8231445
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/lists/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===r.name)?"string":t;var n,o,r,s})(t)===e,n=e=>t=>typeof t===e,o=t("string"),r=t("object"),s=t("array"),i=n("boolean"),l=e=>!(e=>null==e)(e),a=n("function"),d=n("number"),c=()=>{},m=e=>()=>e,u=(e,t)=>e===t,p=e=>t=>!e(t),g=m(!1);class h{constructor(e,t){this.tag=e,this.value=t}static some(e){return new h(!0,e)}static none(){return h.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?h.some(e(this.value)):h.none()}bind(e){return this.tag?e(this.value):h.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:h.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return l(e)?h.some(e):h.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}h.singletonNone=new h(!1);const f=Array.prototype.slice,y=Array.prototype.indexOf,v=Array.prototype.push,C=(e,t)=>{return n=e,o=t,y.call(n,o)>-1;var n,o},b=(e,t)=>{for(let n=0,o=e.length;n<o;n++)if(t(e[n],n))return!0;return!1},N=(e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r<n;r++){const n=e[r];o[r]=t(n,r)}return o},S=(e,t)=>{for(let n=0,o=e.length;n<o;n++)t(e[n],n)},L=(e,t)=>{const n=[];for(let o=0,r=e.length;o<r;o++){const r=e[o];t(r,o)&&n.push(r)}return n},O=(e,t,n)=>(S(e,((e,o)=>{n=t(n,e,o)})),n),A=(e,t,n)=>{for(let o=0,r=e.length;o<r;o++){const r=e[o];if(t(r,o))return h.some(r);if(n(r,o))break}return h.none()},T=(e,t)=>A(e,t,g),w=(e,t)=>(e=>{const t=[];for(let n=0,o=e.length;n<o;++n){if(!s(e[n]))throw new Error("Arr.flatten item "+n+" was not an array, input: "+e);v.apply(t,e[n])}return t})(N(e,t)),x=e=>{const t=f.call(e,0);return t.reverse(),t},E=(e,t)=>t>=0&&t<e.length?h.some(e[t]):h.none(),k=e=>E(e,0),D=e=>E(e,e.length-1),B=(e,t)=>{const n=[],o=a(t)?e=>b(n,(n=>t(n,e))):e=>C(n,e);for(let t=0,r=e.length;t<r;t++){const r=e[t];o(r)||n.push(r)}return n},M=(e,t,n=u)=>e.exists((e=>n(e,t))),P=(e,t,n)=>e.isSome()&&t.isSome()?h.some(n(e.getOrDie(),t.getOrDie())):h.none(),I=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},R=(e,t)=>{const n=(t||document).createElement("div");if(n.innerHTML=e,!n.hasChildNodes()||n.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return I(n.childNodes[0])},U=(e,t)=>{const n=(t||document).createElement(e);return I(n)},$=I,_=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},H=(e,t)=>e.dom===t.dom,F=_,V="undefined"!=typeof window?window:Function("return this;")(),j=(e,t)=>((e,t)=>{let n=null!=t?t:V;for(let t=0;t<e.length&&null!=n;++t)n=n[e[t]];return n})(e.split("."),t),K=Object.getPrototypeOf,z=e=>{const t=j("ownerDocument.defaultView",e);return r(e)&&((e=>((e,t)=>{const n=((e,t)=>j(e,t))(e,t);if(null==n)throw new Error(e+" not available on this browser");return n})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(K(e).constructor.name))},Q=e=>e.dom.nodeName.toLowerCase(),W=e=>e.dom.nodeType,q=e=>t=>W(t)===e,Z=e=>G(e)&&z(e.dom),G=q(1),J=q(3),X=q(9),Y=q(11),ee=e=>t=>G(t)&&Q(t)===e,te=e=>h.from(e.dom.parentNode).map($),ne=e=>N(e.dom.childNodes,$),oe=(e,t)=>{const n=e.dom.childNodes;return h.from(n[t]).map($)},re=e=>oe(e,0),se=e=>oe(e,e.dom.childNodes.length-1),ie=a(Element.prototype.attachShadow)&&a(Node.prototype.getRootNode)?e=>$(e.dom.getRootNode()):e=>X(e)?e:$(e.dom.ownerDocument),le=e=>$(e.dom.host),ae=e=>{const t=J(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return(e=>{const t=ie(e);return Y(n=t)&&l(n.dom.host)?h.some(t):h.none();var n})($(t)).fold((()=>n.body.contains(t)),(o=ae,r=le,e=>o(r(e))));var o,r};var de=(e,t,n,o,r)=>e(n,o)?h.some(n):a(r)&&r(n)?h.none():t(n,o,r);const ce=(e,t,n)=>{let o=e.dom;const r=a(n)?n:g;for(;o.parentNode;){o=o.parentNode;const e=$(o);if(t(e))return h.some(e);if(r(e))break}return h.none()},me=(e,t,n)=>de(((e,t)=>t(e)),ce,e,t,n),ue=(e,t,n)=>ce(e,(e=>_(e,t)),n),pe=(e,t)=>{te(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},ge=(e,t)=>{e.dom.appendChild(t.dom)},he=(e,t)=>{S(t,(t=>{ge(e,t)}))},fe=e=>{e.dom.textContent="",S(ne(e),(e=>{ye(e)}))},ye=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)};var ve=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),Ce=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker"),be=tinymce.util.Tools.resolve("tinymce.util.VK");const Ne=e=>N(e,$),Se=Object.keys,Le=(e,t)=>{const n=Se(e);for(let o=0,r=n.length;o<r;o++){const r=n[o];t(e[r],r)}},Oe=(e,t)=>{const n=e.dom;Le(t,((e,t)=>{((e,t,n)=>{if(!(o(n)||i(n)||d(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(n,t,e)}))},Ae=e=>O(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),Te=e=>((e,t)=>$(e.dom.cloneNode(!0)))(e),we=(e,t)=>{const n=((e,t)=>{const n=U(t),o=Ae(e);return Oe(n,o),n})(e,t);var o,r;r=n,(e=>h.from(e.dom.nextSibling).map($))(o=e).fold((()=>{te(o).each((e=>{ge(e,r)}))}),(e=>{pe(e,r)}));const s=ne(e);return he(n,s),ye(e),n};var xe=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),Ee=tinymce.util.Tools.resolve("tinymce.util.Tools");const ke=e=>t=>l(t)&&t.nodeName.toLowerCase()===e,De=e=>t=>l(t)&&e.test(t.nodeName),Be=e=>l(e)&&3===e.nodeType,Me=e=>l(e)&&1===e.nodeType,Pe=De(/^(OL|UL|DL)$/),Ie=De(/^(OL|UL)$/),Re=ke("ol"),Ue=De(/^(LI|DT|DD)$/),$e=De(/^(DT|DD)$/),_e=De(/^(TH|TD)$/),He=ke("br"),Fe=(e,t)=>l(t)&&t.nodeName in e.schema.getTextBlockElements(),Ve=(e,t)=>l(e)&&e.nodeName in t,je=(e,t)=>l(t)&&t.nodeName in e.schema.getVoidElements(),Ke=(e,t,n)=>{const o=e.isEmpty(t);return!(n&&e.select("span[data-mce-type=bookmark]",t).length>0)&&o},ze=(e,t)=>e.isChildOf(t,e.getRoot()),Qe=e=>t=>t.options.get(e),We=Qe("lists_indent_on_tab"),qe=Qe("forced_root_block"),Ze=Qe("forced_root_block_attrs"),Ge=(e,t,n={})=>{const o=e.dom,r=e.schema.getBlockElements(),s=o.createFragment(),i=qe(e),l=Ze(e);let a,d,c=!1;for(d=o.create(i,{...l,...n.style?{style:n.style}:{}}),Ve(t.firstChild,r)||s.appendChild(d);a=t.firstChild;){const e=a.nodeName;c||"SPAN"===e&&"bookmark"===a.getAttribute("data-mce-type")||(c=!0),Ve(a,r)?(s.appendChild(a),d=null):(d||(d=o.create(i,l),s.appendChild(d)),d.appendChild(a))}return!c&&d&&d.appendChild(o.create("br",{"data-mce-bogus":"1"})),s},Je=xe.DOM,Xe=ee("dd"),Ye=ee("dt"),et=(e,t)=>{var n;Xe(t)?we(t,"dt"):Ye(t)&&(n=t,h.from(n.dom.parentElement).map($)).each((n=>((e,t,n)=>{const o=Je.select('span[data-mce-type="bookmark"]',t),r=Ge(e,n),s=Je.createRng();s.setStartAfter(n),s.setEndAfter(t);const i=s.extractContents();for(let t=i.firstChild;t;t=t.firstChild)if("LI"===t.nodeName&&e.dom.isEmpty(t)){Je.remove(t);break}e.dom.isEmpty(i)||Je.insertAfter(i,t),Je.insertAfter(r,t);const l=n.parentElement;l&&Ke(e.dom,l)&&(e=>{const t=e.parentNode;t&&Ee.each(o,(e=>{t.insertBefore(e,n.parentNode)})),Je.remove(e)})(l),Je.remove(n),Ke(e.dom,t)&&Je.remove(t)})(e,n.dom,t.dom)))},tt=e=>{Ye(e)&&we(e,"dd")},nt=(e,t)=>{if(Be(e))return{container:e,offset:t};const n=ve.getNode(e,t);return Be(n)?{container:n,offset:t>=e.childNodes.length?n.data.length:0}:n.previousSibling&&Be(n.previousSibling)?{container:n.previousSibling,offset:n.previousSibling.data.length}:n.nextSibling&&Be(n.nextSibling)?{container:n.nextSibling,offset:0}:{container:e,offset:t}},ot=e=>{const t=e.cloneRange(),n=nt(e.startContainer,e.startOffset);t.setStart(n.container,n.offset);const o=nt(e.endContainer,e.endOffset);return t.setEnd(o.container,o.offset),t},rt=["OL","UL","DL"],st=rt.join(","),it=(e,t)=>{const n=t||e.selection.getStart(!0);return e.dom.getParent(n,st,dt(e,n))},lt=e=>{const t=e.selection.getSelectedBlocks();return L(((e,t)=>{const n=Ee.map(t,(t=>e.dom.getParent(t,"li,dd,dt",dt(e,t))||t));return B(n)})(e,t),Ue)},at=(e,t)=>{const n=e.dom.getParents(t,"TD,TH");return n.length>0?n[0]:e.getBody()},dt=(e,t)=>{const n=e.dom.getParents(t,e.dom.isBlock),o=T(n,(t=>{return(t=>t.nodeName.toLowerCase()!==qe(e))(t)&&(n=e.schema,!Pe(o=t)&&!Ue(o)&&b(rt,(e=>n.isValidChild(o.nodeName,e))));var n,o}));return o.getOr(e.getBody())},ct=(e,t)=>{const n=e.dom.getParents(t,"ol,ul",dt(e,t));return D(n)},mt=(e,t)=>{const n=N(t,(t=>ct(e,t).getOr(t)));return B(n)},ut=e=>/\btox\-/.test(e.className),pt=(e,t)=>A(e,Pe,_e).exists((e=>e.nodeName===t&&!ut(e))),gt=(e,t)=>null!==t&&!e.dom.isEditable(t),ht=(e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return gt(e,n)},ft=(e,t)=>{const n=e.selection.getNode();return t({parents:e.dom.getParents(n),element:n}),e.on("NodeChange",t),()=>e.off("NodeChange",t)},yt=(e,t)=>{const n=(t||document).createDocumentFragment();return S(e,(e=>{n.appendChild(e.dom)})),$(n)},vt=(e,t,n)=>e.dispatch("ListMutation",{action:t,element:n}),Ct=(bt=/^\s+|\s+$/g,e=>e.replace(bt,""));var bt;const Nt=(e,t,n)=>{((e,t,n)=>{if(!o(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);(e=>void 0!==e.style&&a(e.style.getPropertyValue))(e)&&e.style.setProperty(t,n)})(e.dom,t,n)},St=e=>F(e,"OL,UL"),Lt=e=>re(e).exists(St),Ot=e=>"listAttributes"in e,At=e=>"isComment"in e,Tt=e=>e.depth>0,wt=e=>e.isSelected,xt=e=>{const t=ne(e),n=se(e).exists(St)?t.slice(0,-1):t;return N(n,Te)},Et=(e,t)=>{ge(e.item,t.list)},kt=(e,t)=>{const n={list:U(t,e),item:U("li",e)};return ge(n.list,n.item),n},Dt=(e,t,n)=>{const o=t.slice(0,n.depth);return D(o).each((t=>{if(Ot(n)){const o=((e,t,n)=>{const o=U("li",e);return Oe(o,t),he(o,n),o})(e,n.itemAttributes,n.content);((e,t)=>{ge(e.list,t),e.item=t})(t,o),((e,t)=>{Q(e.list)!==t.listType&&(e.list=we(e.list,t.listType)),Oe(e.list,t.listAttributes)})(t,n)}else if((e=>"isFragment"in e)(n))he(t.item,n.content);else{const e=R(`\x3c!--${n.content}--\x3e`);ge(t.list,e)}})),o},Bt=(e,t)=>{let n=h.none();const o=O(t,((t,o,r)=>At(o)?0===r?(n=h.some(o),t):Dt(e,t,o):o.depth>t.length?((e,t,n)=>{const o=((e,t,n)=>{const o=[];for(let r=0;r<n;r++)o.push(kt(e,Ot(t)?t.listType:t.parentListType));return o})(e,n,n.depth-t.length);var r;return(e=>{for(let t=1;t<e.length;t++)Et(e[t-1],e[t])})(o),((e,t)=>{for(let t=0;t<e.length-1;t++)Nt(e[t].item,"list-style-type","none");D(e).each((e=>{Ot(t)&&(Oe(e.list,t.listAttributes),Oe(e.item,t.itemAttributes)),he(e.item,t.content)}))})(o,n),r=o,P(D(t),k(r),Et),t.concat(o)})(e,t,o):Dt(e,t,o)),[]);return n.each((e=>{const t=R(`\x3c!--${e.content}--\x3e`);k(o).each((e=>{((e,t)=>{re(e).fold((()=>{ge(e,t)}),(n=>{e.dom.insertBefore(t.dom,n.dom)}))})(e.list,t)}))})),k(o).map((e=>e.list))},Mt=e=>(S(e,((t,n)=>{((e,t)=>{const n=e[t].depth,o=e=>e.depth===n&&!e.dirty,r=e=>e.depth<n;return A(x(e.slice(0,t)),o,r).orThunk((()=>A(e.slice(t+1),o,r)))})(e,n).fold((()=>{t.dirty&&Ot(t)&&(e=>{e.listAttributes=((e,t)=>{const n={};var o;return((e,t,n,o)=>{Le(e,((e,r)=>{(t(e,r)?n:o)(e,r)}))})(e,t,(o=n,(e,t)=>{o[t]=e}),c),n})(e.listAttributes,((e,t)=>"start"!==t))})(t)}),(e=>{return o=e,void(Ot(n=t)&&Ot(o)&&(n.listType=o.listType,n.listAttributes={...o.listAttributes}));var n,o}))})),e),Pt=(e,t,n,o)=>{var r,s;if(8===W(s=o)||"#comment"===Q(s))return[{depth:e+1,content:null!==(r=o.dom.nodeValue)&&void 0!==r?r:"",dirty:!1,isSelected:!1,isComment:!0}];t.each((e=>{H(e.start,o)&&n.set(!0)}));const i=((e,t,n)=>te(e).filter(G).map((o=>({depth:t,dirty:!1,isSelected:n,content:xt(e),itemAttributes:Ae(e),listAttributes:Ae(o),listType:Q(o),isInPreviousLi:!1}))))(o,e,n.get());t.each((e=>{H(e.end,o)&&n.set(!1)}));const l=se(o).filter(St).map((o=>Rt(e,t,n,o))).getOr([]);return i.toArray().concat(l)},It=(e,t,n,o)=>re(o).filter(St).fold((()=>Pt(e,t,n,o)),(r=>{const s=O(ne(o),((o,s,i)=>{if(0===i)return o;if(F(s,"LI"))return o.concat(Pt(e,t,n,s));{const t={isFragment:!0,depth:e,content:[s],isSelected:!1,dirty:!1,parentListType:Q(r)};return o.concat(t)}}),[]);return Rt(e,t,n,r).concat(s)})),Rt=(e,t,n,o)=>w(ne(o),(o=>(St(o)?Rt:It)(e+1,t,n,o))),Ut=(e,t,n)=>{const o=((e,t)=>{const n=(e=>{let t=!1;return{get:()=>t,set:e=>{t=e}}})();return N(e,(e=>({sourceList:e,entries:Rt(0,t,n,e)})))})(t,(e=>{const t=N(lt(e),$);return P(T(t,p(Lt)),T(x(t),p(Lt)),((e,t)=>({start:e,end:t})))})(e));S(o,(t=>{((e,t)=>{S(L(e,wt),(e=>((e,t)=>{switch(e){case"Indent":t.depth++;break;case"Outdent":t.depth--;break;case"Flatten":t.depth=0}t.dirty=!0})(t,e)))})(t.entries,n);const o=((e,t)=>w(((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const o=[];let r=[];for(let s=0,i=e.length;s<i;s++){const i=e[s],l=t(i);l!==n&&(o.push(r),r=[]),n=l,r.push(i)}return 0!==r.length&&o.push(r),o}})(t,Tt),(t=>k(t).exists(Tt)?((e,t)=>{const n=Mt(t);return Bt(e.contentDocument,n).toArray()})(e,t):((e,t)=>{const n=Mt(t);return N(n,(t=>{const n=At(t)?yt([R(`\x3c!--${t.content}--\x3e`)]):yt(t.content),o=Ot(t)?t.itemAttributes:{};return $(Ge(e,n.dom,o))}))})(e,t))))(e,t.entries);var r;S(o,(t=>{vt(e,"Indent"===n?"IndentList":"OutdentList",t.dom)})),r=t.sourceList,S(o,(e=>{pe(r,e)})),ye(t.sourceList)}))},$t=(e,t)=>{const n=Ne((e=>{const t=(e=>{const t=ct(e,e.selection.getStart()),n=L(e.selection.getSelectedBlocks(),Ie);return t.toArray().concat(n)})(e),n=(e=>{const t=e.selection.getStart();return e.dom.getParents(t,"ol,ul",dt(e,t))})(e);return T(n,(e=>{return t=$(e),te(t).exists((e=>Ue(e.dom)&&re(e).exists((e=>!Pe(e.dom)))&&se(e).exists((e=>!Pe(e.dom)))));var t})).fold((()=>mt(e,t)),(e=>[e]))})(e)),o=Ne((e=>L(lt(e),$e))(e));let r=!1;if(n.length||o.length){const s=e.selection.getBookmark();Ut(e,n,t),((e,t,n)=>{S(n,"Indent"===t?tt:t=>et(e,t))})(e,t,o),e.selection.moveToBookmark(s),e.selection.setRng(ot(e.selection.getRng())),e.nodeChanged(),r=!0}return r},_t=(e,t)=>!(e=>{const t=it(e);return gt(e,t)})(e)&&$t(e,t),Ht=e=>_t(e,"Indent"),Ft=e=>_t(e,"Outdent"),Vt=e=>_t(e,"Flatten"),jt=e=>"\ufeff"===e;var Kt=tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");const zt=xe.DOM,Qt=e=>{const t={},n=n=>{let o=e[n?"startContainer":"endContainer"],r=e[n?"startOffset":"endOffset"];if(Me(o)){const e=zt.create("span",{"data-mce-type":"bookmark"});o.hasChildNodes()?(r=Math.min(r,o.childNodes.length-1),n?o.insertBefore(e,o.childNodes[r]):zt.insertAfter(e,o.childNodes[r])):o.appendChild(e),o=e,r=0}t[n?"startContainer":"endContainer"]=o,t[n?"startOffset":"endOffset"]=r};return n(!0),e.collapsed||n(),t},Wt=e=>{const t=t=>{let n=e[t?"startContainer":"endContainer"],o=e[t?"startOffset":"endOffset"];if(n){if(Me(n)&&n.parentNode){const e=n;o=(e=>{var t;let n=null===(t=e.parentNode)||void 0===t?void 0:t.firstChild,o=0;for(;n;){if(n===e)return o;Me(n)&&"bookmark"===n.getAttribute("data-mce-type")||o++,n=n.nextSibling}return-1})(n),n=n.parentNode,zt.remove(e),!n.hasChildNodes()&&zt.isBlock(n)&&n.appendChild(zt.create("br"))}e[t?"startContainer":"endContainer"]=n,e[t?"startOffset":"endOffset"]=o}};t(!0),t();const n=zt.createRng();return n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),ot(n)},qt=e=>{switch(e){case"UL":return"ToggleUlList";case"OL":return"ToggleOlList";case"DL":return"ToggleDLList"}},Zt=(e,t)=>{Ee.each(t,((t,n)=>{e.setAttribute(n,t)}))},Gt=(e,t,n)=>{((e,t,n)=>{const o=n["list-style-type"]?n["list-style-type"]:null;e.setStyle(t,"list-style-type",o)})(e,t,n),((e,t,n)=>{Zt(t,n["list-attributes"]),Ee.each(e.select("li",t),(e=>{Zt(e,n["list-item-attributes"])}))})(e,t,n)},Jt=(e,t)=>l(t)&&!Ve(t,e.schema.getBlockElements()),Xt=(e,t,n,o)=>{let r=t[n?"startContainer":"endContainer"];const s=t[n?"startOffset":"endOffset"];Me(r)&&(r=r.childNodes[Math.min(s,r.childNodes.length-1)]||r),!n&&He(r.nextSibling)&&(r=r.nextSibling);const i=(t,n)=>{var r;const s=new Ce(t,(t=>{for(;!e.dom.isBlock(t)&&t.parentNode&&o!==t;)t=t.parentNode;return t})(t)),i=n?"next":"prev";let l;for(;l=s[i]();)if(!je(e,l)&&!jt(l.textContent)&&0!==(null===(r=l.textContent)||void 0===r?void 0:r.length))return h.some(l);return h.none()};if(n&&Be(r))if(jt(r.textContent))r=i(r,!1).getOr(r);else for(null!==r.parentNode&&Jt(e,r.parentNode)&&(r=r.parentNode);null!==r.previousSibling&&(Jt(e,r.previousSibling)||Be(r.previousSibling));)r=r.previousSibling;if(!n&&Be(r))if(jt(r.textContent))r=i(r,!0).getOr(r);else for(null!==r.parentNode&&Jt(e,r.parentNode)&&(r=r.parentNode);null!==r.nextSibling&&(Jt(e,r.nextSibling)||Be(r.nextSibling));)r=r.nextSibling;for(;r.parentNode!==o;){const t=r.parentNode;if(Fe(e,r))return r;if(/^(TD|TH)$/.test(t.nodeName))return r;r=t}return r},Yt=(e,t,n)=>{const o=e.selection.getRng();let r="LI";const s=dt(e,((e,t)=>{const n=e.selection.getStart(!0),o=Xt(e,t,!0,e.getBody());return r=$(o),s=$(t.commonAncestorContainer),i=r,l=function(e,...t){return(...n)=>{const o=t.concat(n);return e.apply(null,o)}}(H,s),ce(i,l,void 0).isSome()?t.commonAncestorContainer:n;var r,s,i,l})(e,o)),i=e.dom;if("false"===i.getContentEditable(e.selection.getNode()))return;"DL"===(t=t.toUpperCase())&&(r="DT");const l=Qt(o),a=L(((e,t,n)=>{const o=[],r=e.dom,s=Xt(e,t,!0,n),i=Xt(e,t,!1,n);let l;const a=[];for(let e=s;e&&(a.push(e),e!==i);e=e.nextSibling);return Ee.each(a,(t=>{var s;if(Fe(e,t))return o.push(t),void(l=null);if(r.isBlock(t)||He(t))return He(t)&&r.remove(t),void(l=null);const i=t.nextSibling;Kt.isBookmarkNode(t)&&(Pe(i)||Fe(e,i)||!i&&t.parentNode===n)?l=null:(l||(l=r.create("p"),null===(s=t.parentNode)||void 0===s||s.insertBefore(l,t),o.push(l)),l.appendChild(t))})),o})(e,o,s),e.dom.isEditable);Ee.each(a,(o=>{let s;const l=o.previousSibling,a=o.parentNode;Ue(a)||(l&&Pe(l)&&l.nodeName===t&&((e,t,n)=>{const o=e.getStyle(t,"list-style-type");let r=n?n["list-style-type"]:"";return r=null===r?"":r,o===r})(i,l,n)?(s=l,o=i.rename(o,r),l.appendChild(o)):(s=i.create(t),a.insertBefore(s,o),s.appendChild(o),o=i.rename(o,r)),((e,t,n)=>{Ee.each(["margin","margin-right","margin-bottom","margin-left","margin-top","padding","padding-right","padding-bottom","padding-left","padding-top"],(n=>e.setStyle(t,n,"")))})(i,o),Gt(i,s,n),tn(e.dom,s))})),e.selection.setRng(Wt(l))},en=(e,t,n)=>{return((e,t)=>Pe(e)&&e.nodeName===(null==t?void 0:t.nodeName))(t,n)&&((e,t,n)=>e.getStyle(t,"list-style-type",!0)===e.getStyle(n,"list-style-type",!0))(e,t,n)&&(o=n,t.className===o.className);var o},tn=(e,t)=>{let n,o=t.nextSibling;if(en(e,t,o)){const r=o;for(;n=r.firstChild;)t.appendChild(n);e.remove(r)}if(o=t.previousSibling,en(e,t,o)){const r=o;for(;n=r.lastChild;)t.insertBefore(n,t.firstChild);e.remove(r)}},nn=(e,t,n,o)=>{if(t.nodeName!==n){const r=e.dom.rename(t,n);Gt(e.dom,r,o),vt(e,qt(n),r)}else Gt(e.dom,t,o),vt(e,qt(n),t)},on=(e,t,n,o)=>{if(t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),t.nodeName!==n){const r=e.dom.rename(t,n);Gt(e.dom,r,o),vt(e,qt(n),r)}else Gt(e.dom,t,o),vt(e,qt(n),t)},rn=e=>"list-style-type"in e,sn=(e,t,n)=>{const o=it(e);if(ht(e,o))return;const s=(e=>{const t=it(e),n=e.selection.getSelectedBlocks();return((e,t)=>l(e)&&1===t.length&&t[0]===e)(t,n)?(e=>L(e.querySelectorAll(st),Pe))(t):L(n,(e=>Pe(e)&&t!==e))})(e),i=r(n)?n:{};s.length>0?((e,t,n,o,r)=>{const s=Pe(t);if(!s||t.nodeName!==o||rn(r)||ut(t)){Yt(e,o,r);const i=Qt(e.selection.getRng()),l=s?[t,...n]:n,a=s&&ut(t)?on:nn;Ee.each(l,(t=>{a(e,t,o,r)})),e.selection.setRng(Wt(i))}else Vt(e)})(e,o,s,t,i):((e,t,n,o)=>{if(t!==e.getBody())if(t)if(t.nodeName!==n||rn(o)||ut(t)){const r=Qt(e.selection.getRng());ut(t)&&t.classList.forEach(((e,n,o)=>{e.startsWith("tox-")&&(o.remove(e),0===o.length&&t.removeAttribute("class"))})),Gt(e.dom,t,o);const s=e.dom.rename(t,n);tn(e.dom,s),e.selection.setRng(Wt(r)),Yt(e,n,o),vt(e,qt(n),s)}else Vt(e);else Yt(e,n,o),vt(e,qt(n),t)})(e,o,t,i)},ln=xe.DOM,an=(e,t)=>{const n=Ee.grep(e.select("ol,ul",t));Ee.each(n,(t=>{((e,t)=>{const n=t.parentElement;if(n&&"LI"===n.nodeName&&n.firstChild===t){const o=n.previousSibling;o&&"LI"===o.nodeName?(o.appendChild(t),Ke(e,n)&&ln.remove(n)):ln.setStyle(n,"listStyleType","none")}if(Pe(n)){const e=n.previousSibling;e&&"LI"===e.nodeName&&e.appendChild(t)}})(e,t)}))},dn=(e,t,n,o)=>{let r=t.startContainer;const s=t.startOffset;if(Be(r)&&(n?s<r.data.length:s>0))return r;const i=e.schema.getNonEmptyElements();Me(r)&&(r=ve.getNode(r,s));const l=new Ce(r,o);n&&((e,t)=>!!He(t)&&e.isBlock(t.nextSibling)&&!He(t.previousSibling))(e.dom,r)&&l.next();const a=n?l.next.bind(l):l.prev2.bind(l);for(;r=a();){if("LI"===r.nodeName&&!r.hasChildNodes())return r;if(i[r.nodeName])return r;if(Be(r)&&r.data.length>0)return r}return null},cn=(e,t)=>{const n=t.childNodes;return 1===n.length&&!Pe(n[0])&&e.isBlock(n[0])},mn=e=>h.from(e).map($).filter(Z).exists((e=>((e,t=!1)=>{return ae(e)?e.dom.isContentEditable:(n=e,de(((e,t)=>_(e,t)),ue,n,"[contenteditable]",void 0)).fold(m(t),(e=>"true"===(e=>e.dom.contentEditable)(e)));var n})(e)&&!C(["details"],Q(e)))),un=(e,t,n)=>{let o;const r=cn(e,n)?n.firstChild:n;if(((e,t)=>{cn(e,t)&&mn(t.firstChild)&&e.remove(t.firstChild,!0)})(e,t),!Ke(e,t,!0))for(;o=t.firstChild;)r.appendChild(o)},pn=(e,t,n)=>{let o;const r=t.parentNode;if(!ze(e,t)||!ze(e,n))return;Pe(n.lastChild)&&(o=n.lastChild),r===n.lastChild&&He(r.previousSibling)&&e.remove(r.previousSibling);const s=n.lastChild;s&&He(s)&&t.hasChildNodes()&&e.remove(s),Ke(e,n,!0)&&fe($(n)),un(e,t,n),o&&n.appendChild(o);const i=((e,t)=>{const n=e.dom,o=t.dom;return n!==o&&n.contains(o)})($(n),$(t))?e.getParents(t,Pe,n):[];e.remove(t),S(i,(t=>{Ke(e,t)&&t!==e.getRoot()&&e.remove(t)}))},gn=(e,t)=>{const n=e.dom,o=e.selection,r=o.getStart(),s=at(e,r),i=n.getParent(o.getStart(),"LI",s);if(i){const r=i.parentElement;if(r===e.getBody()&&Ke(n,r))return!0;const l=ot(o.getRng()),a=n.getParent(dn(e,l,t,s),"LI",s),d=a&&(t?n.isChildOf(i,a):n.isChildOf(a,i));if(a&&a!==i&&!d)return e.undoManager.transact((()=>{var n,o;t?((e,t,n,o)=>{const r=e.dom;if(r.isEmpty(o))((e,t,n)=>{fe($(n)),pn(e.dom,t,n),e.selection.setCursorLocation(n,0)})(e,n,o);else{const s=Qt(t);pn(r,n,o),e.selection.setRng(Wt(s))}})(e,l,a,i):(null===(o=(n=i).parentNode)||void 0===o?void 0:o.firstChild)===n?Ft(e):((e,t,n,o)=>{const r=Qt(t);pn(e.dom,n,o);const s=Wt(r);e.selection.setRng(s)})(e,l,i,a)})),!0;if(d&&!t&&a!==i)return e.undoManager.transact((()=>{if(l.commonAncestorContainer.parentElement){const t=Qt(l),o=l.commonAncestorContainer.parentElement;un(n,l.commonAncestorContainer.parentElement,a),o.remove();const r=Wt(t);e.selection.setRng(r)}})),!0;if(!a&&!t&&0===l.startOffset&&0===l.endOffset)return e.undoManager.transact((()=>{Vt(e)})),!0}return!1},hn=e=>{const t=e.selection.getStart(),n=at(e,t);return e.dom.getParent(t,"LI,DT,DD",n)||lt(e).length>0},fn=(e,t)=>{const n=e.selection;return!ht(e,n.getNode())&&(n.isCollapsed()?((e,t)=>gn(e,t)||((e,t)=>{const n=e.dom,o=e.selection.getStart(),r=at(e,o),s=n.getParent(o,n.isBlock,r);if(s&&n.isEmpty(s,void 0,{checkRootAsContent:!0})){const o=ot(e.selection.getRng()),i=n.getParent(dn(e,o,t,r),"LI",r);if(i){const l=e=>C(["td","th","caption"],Q(e)),a=e=>e.dom===r;return!!((e,t,n=u)=>P(e,t,n).getOr(e.isNone()&&t.isNone()))(me($(i),l,a),me($(o.startContainer),l,a),H)&&(e.undoManager.transact((()=>{const o=i.parentNode;((e,t,n)=>{const o=e.getParent(t.parentNode,e.isBlock,n);e.remove(t),o&&e.isEmpty(o)&&e.remove(o)})(n,s,r),tn(n,o),e.selection.select(i,!0),e.selection.collapse(t)})),!0)}}return!1})(e,t))(e,t):(e=>!!hn(e)&&(e.undoManager.transact((()=>{e.execCommand("Delete"),an(e.dom,e.getBody())})),!0))(e))},yn=e=>{const t=x(Ct(e).split("")),n=N(t,((e,t)=>{const n=e.toUpperCase().charCodeAt(0)-"A".charCodeAt(0)+1;return Math.pow(26,t)*n}));return O(n,((e,t)=>e+t),0)},vn=e=>{if(--e<0)return"";{const t=e%26,n=Math.floor(e/26);return vn(n)+String.fromCharCode("A".charCodeAt(0)+t)}},Cn=e=>{const t=parseInt(e.start,10);return M(e.listStyleType,"upper-alpha")?vn(t):M(e.listStyleType,"lower-alpha")?vn(t).toLowerCase():e.start},bn=(e,t)=>()=>{const n=it(e);return l(n)&&n.nodeName===t},Nn=e=>{e.addCommand("mceListProps",(()=>{(e=>{const t=it(e);Re(t)&&!ht(e,t)&&e.windowManager.open({title:"List Properties",body:{type:"panel",items:[{type:"input",name:"start",label:"Start list at number",inputMode:"numeric"}]},initialData:{start:Cn({start:e.dom.getAttrib(t,"start","1"),listStyleType:h.from(e.dom.getStyle(t,"list-style-type"))})},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{(e=>{switch((e=>/^[0-9]+$/.test(e)?2:/^[A-Z]+$/.test(e)?0:/^[a-z]+$/.test(e)?1:e.length>0?4:3)(e)){case 2:return h.some({listStyleType:h.none(),start:e});case 0:return h.some({listStyleType:h.some("upper-alpha"),start:yn(e).toString()});case 1:return h.some({listStyleType:h.some("lower-alpha"),start:yn(e).toString()});case 3:return h.some({listStyleType:h.none(),start:""});case 4:return h.none()}})(t.getData().start).each((t=>{e.execCommand("mceListUpdate",!1,{attrs:{start:"1"===t.start?"":t.start},styles:{"list-style-type":t.listStyleType.getOr("")}})})),t.close()}})})(e)}))};var Sn=tinymce.util.Tools.resolve("tinymce.html.Node");const Ln=e=>3===e.type,On=e=>0===e.length,An=e=>{const t=(t,n)=>{const o=Sn.create("li");S(t,(e=>o.append(e))),n?e.insert(o,n,!0):e.append(o)},n=O(e.children(),((e,n)=>Ln(n)?[...e,n]:On(e)||Ln(n)?e:(t(e,n),[])),[]);On(n)||t(n)},Tn=(e,t)=>n=>(n.setEnabled(e.selection.isEditable()),ft(e,(o=>{n.setActive(pt(o.parents,t)),n.setEnabled(!ht(e,o.element)&&e.selection.isEditable())}))),wn=(e,t)=>n=>ft(e,(o=>n.setEnabled(pt(o.parents,t)&&!ht(e,o.element))));e.add("lists",(e=>((e=>{(0,e.options.register)("lists_indent_on_tab",{processor:"boolean",default:!0})})(e),(e=>{e.on("PreInit",(()=>{const{parser:t}=e;t.addNodeFilter("ul,ol",(e=>S(e,An)))}))})(e),e.hasPlugin("rtc",!0)?Nn(e):((e=>{We(e)&&(e=>{e.on("keydown",(t=>{t.keyCode!==be.TAB||be.metaKeyPressed(t)||e.undoManager.transact((()=>{(t.shiftKey?Ft(e):Ht(e))&&t.preventDefault()}))}))})(e),(e=>{e.on("ExecCommand",(t=>{const n=t.command.toLowerCase();"delete"!==n&&"forwarddelete"!==n||!hn(e)||an(e.dom,e.getBody())})),e.on("keydown",(t=>{t.keyCode===be.BACKSPACE?fn(e,!1)&&t.preventDefault():t.keyCode===be.DELETE&&fn(e,!0)&&t.preventDefault()}))})(e)})(e),(e=>{e.on("BeforeExecCommand",(t=>{const n=t.command.toLowerCase();"indent"===n?Ht(e):"outdent"===n&&Ft(e)})),e.addCommand("InsertUnorderedList",((t,n)=>{sn(e,"UL",n)})),e.addCommand("InsertOrderedList",((t,n)=>{sn(e,"OL",n)})),e.addCommand("InsertDefinitionList",((t,n)=>{sn(e,"DL",n)})),e.addCommand("RemoveList",(()=>{Vt(e)})),Nn(e),e.addCommand("mceListUpdate",((t,n)=>{r(n)&&((e,t)=>{const n=it(e);null===n||ht(e,n)||e.undoManager.transact((()=>{r(t.styles)&&e.dom.setStyles(n,t.styles),r(t.attrs)&&Le(t.attrs,((t,o)=>e.dom.setAttrib(n,o,t)))}))})(e,n)})),e.addQueryStateHandler("InsertUnorderedList",bn(e,"UL")),e.addQueryStateHandler("InsertOrderedList",bn(e,"OL")),e.addQueryStateHandler("InsertDefinitionList",bn(e,"DL"))})(e)),(e=>{const t=t=>()=>e.execCommand(t);e.hasPlugin("advlist")||(e.ui.registry.addToggleButton("numlist",{icon:"ordered-list",active:!1,tooltip:"Numbered list",onAction:t("InsertOrderedList"),onSetup:Tn(e,"OL")}),e.ui.registry.addToggleButton("bullist",{icon:"unordered-list",active:!1,tooltip:"Bullet list",onAction:t("InsertUnorderedList"),onSetup:Tn(e,"UL")}))})(e),(e=>{const t={text:"List properties...",icon:"ordered-list",onAction:()=>e.execCommand("mceListProps"),onSetup:wn(e,"OL")};e.ui.registry.addMenuItem("listprops",t),e.ui.registry.addContextMenu("lists",{update:t=>{const n=it(e,t);return Re(n)?["listprops"]:[]}})})(e),(e=>({backspaceDelete:t=>{fn(e,t)}}))(e))))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/media/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/media/plugin.min.js
new file mode 100644
index 0000000..dc10a16
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/media/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(r=o=e,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":t;var r,o,a,s})(t)===e,r=t("string"),o=t("object"),a=t("array"),s=e=>!(e=>null==e)(e);class i{constructor(e,t){this.tag=e,this.value=t}static some(e){return new i(!0,e)}static none(){return i.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?i.some(e(this.value)):i.none()}bind(e){return this.tag?e(this.value):i.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:i.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?i.some(e):i.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const n=Array.prototype.push,l=(e,t)=>{for(let r=0,o=e.length;r<o;r++)t(e[r],r)},c=e=>{const t=[];for(let r=0,o=e.length;r<o;++r){if(!a(e[r]))throw new Error("Arr.flatten item "+r+" was not an array, input: "+e);n.apply(t,e[r])}return t},m=Object.keys,u=Object.hasOwnProperty,d=(e,t)=>h(e,t)?i.from(e[t]):i.none(),h=(e,t)=>u.call(e,t),p=e=>t=>t.options.get(e),g=p("audio_template_callback"),b=p("video_template_callback"),w=p("iframe_template_callback"),v=p("media_live_embeds"),f=p("media_filter_html"),y=p("media_url_resolver"),x=p("media_alt_source"),_=p("media_poster"),k=p("media_dimensions");var j=tinymce.util.Tools.resolve("tinymce.util.Tools"),O=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),A=tinymce.util.Tools.resolve("tinymce.html.DomParser");const S=O.DOM,$=e=>e.replace(/px$/,""),C=e=>{const t=e.attr("style"),r=t?S.parseStyle(t):{};return{type:"ephox-embed-iri",source:e.attr("data-ephox-embed-iri"),altsource:"",poster:"",width:d(r,"max-width").map($).getOr(""),height:d(r,"max-height").map($).getOr("")}},T=(e,t)=>{let r={};for(let o=A({validate:!1,forced_root_block:!1},t).parse(e);o;o=o.walk())if(1===o.type){const e=o.name;if(o.attr("data-ephox-embed-iri")){r=C(o);break}r.source||"param"!==e||(r.source=o.attr("movie")),"iframe"!==e&&"object"!==e&&"embed"!==e&&"video"!==e&&"audio"!==e||(r.type||(r.type=e),r=j.extend(o.attributes.map,r)),"source"===e&&(r.source?r.altsource||(r.altsource=o.attr("src")):r.source=o.attr("src")),"img"!==e||r.poster||(r.poster=o.attr("src"))}return r.source=r.source||r.src||"",r.altsource=r.altsource||"",r.poster=r.poster||"",r},z=e=>{var t;const r=null!==(t=e.toLowerCase().split(".").pop())&&void 0!==t?t:"";return d({mp3:"audio/mpeg",m4a:"audio/x-m4a",wav:"audio/wav",mp4:"video/mp4",webm:"video/webm",ogg:"video/ogg",swf:"application/x-shockwave-flash"},r).getOr("")};var D=tinymce.util.Tools.resolve("tinymce.html.Node"),F=tinymce.util.Tools.resolve("tinymce.html.Serializer");const M=(e,t={})=>A({forced_root_block:!1,validate:!1,allow_conditional_comments:!0,...t},e),N=O.DOM,P=e=>/^[0-9.]+$/.test(e)?e+"px":e,R=(e,t)=>{const r=t.attr("style"),o=r?N.parseStyle(r):{};s(e.width)&&(o["max-width"]=P(e.width)),s(e.height)&&(o["max-height"]=P(e.height)),t.attr("style",N.serializeStyle(o))},E=["source","altsource"],U=(e,t,r,o)=>{let a=0,s=0;const i=M(o);i.addNodeFilter("source",(e=>a=e.length));const n=i.parse(e);for(let e=n;e;e=e.walk())if(1===e.type){const o=e.name;if(e.attr("data-ephox-embed-iri")){R(t,e);break}switch(o){case"video":case"object":case"embed":case"img":case"iframe":void 0!==t.height&&void 0!==t.width&&(e.attr("width",t.width),e.attr("height",t.height))}if(r)switch(o){case"video":e.attr("poster",t.poster),e.attr("src",null);for(let r=a;r<2;r++)if(t[E[r]]){const o=new D("source",1);o.attr("src",t[E[r]]),o.attr("type",t[E[r]+"mime"]||null),e.append(o)}break;case"iframe":e.attr("src",t.source);break;case"object":const r=e.getAll("img").length>0;if(t.poster&&!r){e.attr("src",t.poster);const r=new D("img",1);r.attr("src",t.poster),r.attr("width",t.width),r.attr("height",t.height),e.append(r)}break;case"source":if(s<2&&(e.attr("src",t[E[s]]),e.attr("type",t[E[s]+"mime"]||null),!t[E[s]])){e.remove();continue}s++;break;case"img":t.poster||e.remove()}}return F({},o).serialize(n)},L=[{regex:/youtu\.be\/([\w\-_\?&=.]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$2?$4",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,type:"iframe",w:560,h:314,url:"www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?h=$3&title=0&amp;byline=0",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowFullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"player.vimeo.com/video/$2?title=0&amp;byline=0",allowFullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0},{regex:/dai\.ly\/([^_]+)/,type:"iframe",w:480,h:270,url:"www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],I=(e,t)=>{const r=(e=>{const t=e.match(/^(https?:\/\/|www\.)(.+)$/i);return t&&t.length>1?"www."===t[1]?"https://":t[1]:"https://"})(t),o=e.regex.exec(t);let a=r+e.url;if(s(o))for(let e=0;e<o.length;e++)a=a.replace("$"+e,(()=>o[e]?o[e]:""));return a.replace(/\?$/,"")},B=e=>{const t=L.filter((t=>t.regex.test(e)));return t.length>0?j.extend({},t[0],{url:I(t[0],e)}):null},G=(e,t)=>{var r;const o=j.extend({},t);if(!o.source&&(j.extend(o,T(null!==(r=o.embed)&&void 0!==r?r:"",e.schema)),!o.source))return"";o.altsource||(o.altsource=""),o.poster||(o.poster=""),o.source=e.convertURL(o.source,"source"),o.altsource=e.convertURL(o.altsource,"source"),o.sourcemime=z(o.source),o.altsourcemime=z(o.altsource),o.poster=e.convertURL(o.poster,"poster");const a=B(o.source);if(a&&(o.source=a.url,o.type=a.type,o.allowfullscreen=a.allowFullscreen,o.width=o.width||String(a.w),o.height=o.height||String(a.h)),o.embed)return U(o.embed,o,!0,e.schema);{const t=g(e),r=b(e),a=w(e);return o.width=o.width||"300",o.height=o.height||"150",j.each(o,((t,r)=>{o[r]=e.dom.encode(""+t)})),"iframe"===o.type?((e,t)=>{if(t)return t(e);{const t=e.allowfullscreen?' allowFullscreen="1"':"";return'<iframe src="'+e.source+'" width="'+e.width+'" height="'+e.height+'"'+t+"></iframe>"}})(o,a):"application/x-shockwave-flash"===o.sourcemime?(e=>{let t='<object data="'+e.source+'" width="'+e.width+'" height="'+e.height+'" type="application/x-shockwave-flash">';return e.poster&&(t+='<img src="'+e.poster+'" width="'+e.width+'" height="'+e.height+'" />'),t+="</object>",t})(o):-1!==o.sourcemime.indexOf("audio")?((e,t)=>t?t(e):'<audio controls="controls" src="'+e.source+'">'+(e.altsource?'\n<source src="'+e.altsource+'"'+(e.altsourcemime?' type="'+e.altsourcemime+'"':"")+" />\n":"")+"</audio>")(o,t):((e,t)=>t?t(e):'<video width="'+e.width+'" height="'+e.height+'"'+(e.poster?' poster="'+e.poster+'"':"")+' controls="controls">\n<source src="'+e.source+'"'+(e.sourcemime?' type="'+e.sourcemime+'"':"")+" />\n"+(e.altsource?'<source src="'+e.altsource+'"'+(e.altsourcemime?' type="'+e.altsourcemime+'"':"")+" />\n":"")+"</video>")(o,r)}},W=e=>e.hasAttribute("data-mce-object")||e.hasAttribute("data-ephox-embed-iri"),q={},H=e=>t=>G(e,t),J=(e,t)=>{const r=y(e);return r?((e,t,r)=>new Promise(((o,a)=>{const s=r=>(r.html&&(q[e.source]=r),o({url:e.source,html:r.html?r.html:t(e)}));q[e.source]?s(q[e.source]):r({url:e.source}).then(s).catch(a)})))(t,H(e),r):((e,t)=>Promise.resolve({html:t(e),url:e.source}))(t,H(e))},K=(e,t)=>{const r={};return d(e,"dimensions").each((e=>{l(["width","height"],(o=>{d(t,o).orThunk((()=>d(e,o))).each((e=>r[o]=e))}))})),r},Q=(e,t)=>{const r=t&&"dimensions"!==t?((e,t)=>d(t,e).bind((e=>d(e,"meta"))))(t,e).getOr({}):{},a=((e,t,r)=>a=>{const s=()=>d(e,a),n=()=>d(t,a),l=e=>d(e,"value").bind((e=>e.length>0?i.some(e):i.none()));return{[a]:(a===r?s().bind((e=>o(e)?l(e).orThunk(n):n().orThunk((()=>i.from(e))))):n().orThunk((()=>s().bind((e=>o(e)?l(e):i.from(e)))))).getOr("")}})(e,r,t);return{...a("source"),...a("altsource"),...a("poster"),...a("embed"),...K(e,r)}},V=e=>{const t={...e,source:{value:d(e,"source").getOr("")},altsource:{value:d(e,"altsource").getOr("")},poster:{value:d(e,"poster").getOr("")}};return l(["width","height"],(r=>{d(e,r).each((e=>{const o=t.dimensions||{};o[r]=e,t.dimensions=o}))})),t},X=e=>t=>{const r=t&&t.msg?"Media embed handler error: "+t.msg:"Media embed handler threw unknown error.";e.notificationManager.open({type:"error",text:r})},Y=(e,t)=>o=>{if(r(o.url)&&o.url.trim().length>0){const r=o.html,a={...T(r,t.schema),source:o.url,embed:r};e.setData(V(a))}},Z=(e,t)=>{const r=e.dom.select("*[data-mce-object]");e.insertContent(t),((e,t)=>{const r=e.dom.select("*[data-mce-object]");for(let e=0;e<t.length;e++)for(let o=r.length-1;o>=0;o--)t[e]===r[o]&&r.splice(o,1);e.selection.select(r[0])})(e,r),e.nodeChanged()},ee=(e,t)=>s(t)&&"ephox-embed-iri"===t&&s(B(e)),te=(e,t)=>((e,t)=>e.width!==t.width||e.height!==t.height)(e,t)&&ee(t.source,e.type),re=e=>{const t=(e=>{const t=e.selection.getNode(),r=W(t)?e.serializer.serialize(t,{selection:!0}):"",o=T(r,e.schema),a=(()=>{if(ee(o.source,o.type)){const r=e.dom.getRect(t);return{width:r.w.toString().replace(/px$/,""),height:r.h.toString().replace(/px$/,"")}}return{}})();return{embed:r,...o,...a}})(e),r=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})(t),o=V(t),a=k(e)?[{type:"sizeinput",name:"dimensions",label:"Constrain proportions",constrain:!0}]:[],s={title:"General",name:"general",items:c([[{name:"source",type:"urlinput",filetype:"media",label:"Source",picker_text:"Browse files"}],a])},i=[];x(e)&&i.push({name:"altsource",type:"urlinput",filetype:"media",label:"Alternative source URL"}),_(e)&&i.push({name:"poster",type:"urlinput",filetype:"image",label:"Media poster (Image URL)"});const n={title:"Advanced",name:"advanced",items:i},l=[s,{title:"Embed",items:[{type:"textarea",name:"embed",label:"Paste your embed code below:"}]}];i.length>0&&l.push(n);const m={type:"tabpanel",tabs:l},u=e.windowManager.open({title:"Insert/Edit Media",size:"normal",body:m,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],onSubmit:t=>{const o=Q(t.getData());((e,t,r)=>{var o,a;t.embed=te(e,t)&&k(r)?G(r,{...t,embed:""}):U(null!==(o=t.embed)&&void 0!==o?o:"",t,!1,r.schema),t.embed&&(e.source===t.source||(a=t.source,h(q,a)))?Z(r,t.embed):J(r,t).then((e=>{Z(r,e.html)})).catch(X(r))})(r.get(),o,e),t.close()},onChange:(t,o)=>{switch(o.name){case"source":((t,r)=>{const o=Q(r.getData(),"source");t.source!==o.source&&(Y(u,e)({url:o.source,html:""}),J(e,o).then(Y(u,e)).catch(X(e)))})(r.get(),t);break;case"embed":(t=>{var r;const o=Q(t.getData()),a=T(null!==(r=o.embed)&&void 0!==r?r:"",e.schema);t.setData(V(a))})(t);break;case"dimensions":case"altsource":case"poster":((t,r,o)=>{const a=Q(t.getData(),r),s=te(o,a)&&k(e)?{...a,embed:""}:a,i=G(e,s);t.setData(V({...s,embed:i}))})(t,o.name,r.get())}r.set(Q(t.getData()))},initialData:o})};var oe=tinymce.util.Tools.resolve("tinymce.Env");const ae=e=>{const t=e.name;return"iframe"===t||"video"===t||"audio"===t},se=(e,t,r,o=null)=>{const a=e.attr(r);return s(a)?a:h(t,r)?null:o},ie=(e,t,r)=>{const o="img"===t.name||"video"===e.name,a=o?"300":null,s="audio"===e.name?"30":"150",i=o?s:null;t.attr({width:se(e,r,"width",a),height:se(e,r,"height",i)})},ne=(e,t)=>{const r=t.name,o=new D("img",1);return ce(e,t,o),ie(t,o,{}),o.attr({style:t.attr("style"),src:oe.transparentSrc,"data-mce-object":r,class:"mce-object mce-object-"+r}),o},le=(e,t)=>{var r;const o=t.name,a=new D("span",1);a.attr({contentEditable:"false",style:t.attr("style"),"data-mce-object":o,class:"mce-preview-object mce-object-"+o}),ce(e,t,a);const i=e.dom.parseStyle(null!==(r=t.attr("style"))&&void 0!==r?r:""),n=new D(o,1);if(ie(t,n,i),n.attr({src:t.attr("src"),style:t.attr("style"),class:t.attr("class")}),"iframe"===o)n.attr({allowfullscreen:t.attr("allowfullscreen"),frameborder:"0",sandbox:t.attr("sandbox"),referrerpolicy:t.attr("referrerpolicy")});else{l(["controls","crossorigin","currentTime","loop","muted","poster","preload"],(e=>{n.attr(e,t.attr(e))}));const r=a.attr("data-mce-html");s(r)&&((e,t,r,o)=>{const a=M(e.schema).parse(o,{context:t});for(;a.firstChild;)r.append(a.firstChild)})(e,o,n,unescape(r))}const c=new D("span",1);return c.attr("class","mce-shim"),a.append(n),a.append(c),a},ce=(e,t,r)=>{var o;const a=null!==(o=t.attributes)&&void 0!==o?o:[];let s=a.length;for(;s--;){const t=a[s].name;let o=a[s].value;"width"===t||"height"===t||"style"===t||(n="data-mce-",(i=t).length>=9&&i.substr(0,9)===n)||("data"!==t&&"src"!==t||(o=e.convertURL(o,t)),r.attr("data-mce-p-"+t,o))}var i,n;const c=F({inner:!0},e.schema),m=new D("div",1);l(t.children(),(e=>m.append(e)));const u=c.serialize(m);u&&(r.attr("data-mce-html",escape(u)),r.empty())},me=e=>{const t=e.attr("class");return r(t)&&/\btiny-pageembed\b/.test(t)},ue=e=>{let t=e;for(;t=t.parent;)if(t.attr("data-ephox-embed-iri")||me(t))return!0;return!1},de=(e,t,r)=>{const o=(0,e.options.get)("xss_sanitization"),a=f(e);return M(e.schema,{sanitize:o,validate:a}).parse(r,{context:t})},he=e=>t=>{const r=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",r),r(),()=>{e.off("NodeChange",r)}};e.add("media",(e=>((e=>{const t=e.options.register;t("audio_template_callback",{processor:"function"}),t("video_template_callback",{processor:"function"}),t("iframe_template_callback",{processor:"function"}),t("media_live_embeds",{processor:"boolean",default:!0}),t("media_filter_html",{processor:"boolean",default:!0}),t("media_url_resolver",{processor:"function"}),t("media_alt_source",{processor:"boolean",default:!0}),t("media_poster",{processor:"boolean",default:!0}),t("media_dimensions",{processor:"boolean",default:!0})})(e),(e=>{e.addCommand("mceMedia",(()=>{re(e)}))})(e),(e=>{const t=()=>e.execCommand("mceMedia");e.ui.registry.addToggleButton("media",{tooltip:"Insert/edit media",icon:"embed",onAction:t,onSetup:t=>{const r=e.selection;t.setActive(W(r.getNode()));const o=r.selectorChangedWithUnbind("img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]",t.setActive).unbind,a=he(e)(t);return()=>{o(),a()}}}),e.ui.registry.addMenuItem("media",{icon:"embed",text:"Media...",onAction:t,onSetup:he(e)})})(e),(e=>{e.on("ResolveName",(e=>{let t;1===e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}))})(e),(e=>{e.on("PreInit",(()=>{const{schema:t,serializer:r,parser:o}=e,a=t.getBoolAttrs();l("webkitallowfullscreen mozallowfullscreen".split(" "),(e=>{a[e]={}})),((e,t)=>{const r=m(e);for(let o=0,a=r.length;o<a;o++){const a=r[o];t(e[a],a)}})({embed:["wmode"]},((e,r)=>{const o=t.getElementRule(r);o&&l(e,(e=>{o.attributes[e]={},o.attributesOrder.push(e)}))})),o.addNodeFilter("iframe,video,audio,object,embed",(e=>t=>{let r,o=t.length;for(;o--;)r=t[o],r.parent&&(r.parent.attr("data-mce-object")||(ae(r)&&v(e)?ue(r)||r.replace(le(e,r)):ue(r)||r.replace(ne(e,r))))})(e)),r.addAttributeFilter("data-mce-object",((t,r)=>{var o;let a=t.length;for(;a--;){const s=t[a];if(!s.parent)continue;const i=s.attr(r),n=new D(i,1);if("audio"!==i){const e=s.attr("class");e&&-1!==e.indexOf("mce-preview-object")&&s.firstChild?n.attr({width:s.firstChild.attr("width"),height:s.firstChild.attr("height")}):n.attr({width:s.attr("width"),height:s.attr("height")})}n.attr({style:s.attr("style")});const c=null!==(o=s.attributes)&&void 0!==o?o:[];let m=c.length;for(;m--;){const e=c[m].name;0===e.indexOf("data-mce-p-")&&n.attr(e.substr(11),c[m].value)}const u=s.attr("data-mce-html");if(u){const t=de(e,i,unescape(u));l(t.children(),(e=>n.append(e)))}s.replace(n)}}))})),e.on("SetContent",(()=>{const t=e.dom;l(t.select("span.mce-preview-object"),(e=>{0===t.select("span.mce-shim",e).length&&t.add(e,"span",{class:"mce-shim"})}))}))})(e),(e=>{e.on("mousedown",(t=>{const r=e.dom.getParent(t.target,".mce-preview-object");r&&"2"===e.dom.getAttrib(r,"data-mce-selected")&&t.stopImmediatePropagation()})),e.on("click keyup touchend",(()=>{const t=e.selection.getNode();t&&e.dom.hasClass(t,"mce-preview-object")&&e.dom.getAttrib(t,"data-mce-selected")&&t.setAttribute("data-mce-selected","2")})),e.on("ObjectResized",(t=>{const r=t.target;if(r.getAttribute("data-mce-object")){let o=r.getAttribute("data-mce-html");o&&(o=unescape(o),r.setAttribute("data-mce-html",escape(U(o,{width:String(t.width),height:String(t.height)},!1,e.schema))))}}))})(e),(e=>({showDialog:()=>{re(e)}}))(e))))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/nonbreaking/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/nonbreaking/plugin.min.js
new file mode 100644
index 0000000..25f2e0e
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/nonbreaking/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,o=e("boolean"),a=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),s=t("nonbreaking_wrap"),r=(n,e)=>{let o="";for(let a=0;a<e;a++)o+=n;return o},c=(n,e)=>{const o=s(n)||n.plugins.visualchars?`<span class="${(n=>!!n.plugins.visualchars&&n.plugins.visualchars.isEnabled())(n)?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap"}" contenteditable="false">${r("&nbsp;",e)}</span>`:r("&nbsp;",e);n.undoManager.transact((()=>n.insertContent(o)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");const u=n=>e=>{const o=()=>{e.setEnabled(n.selection.isEditable())};return n.on("NodeChange",o),o(),()=>{n.off("NodeChange",o)}};n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>o(n)?{value:n?3:0,valid:!0}:a(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e,onSetup:u(n)}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e,onSetup:u(n)})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(o=>{if(o.keyCode===l.TAB&&!o.isDefaultPrevented()){if(o.shiftKey)return;o.preventDefault(),o.stopImmediatePropagation(),c(n,e)}}))})(n)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/pagebreak/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/pagebreak/plugin.min.js
new file mode 100644
index 0000000..a505295
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/pagebreak/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),n=t("pagebreak_separator"),o=t("pagebreak_split_block"),r="mce-pagebreak",s=e=>{const t=`<img src="${a.transparentSrc}" class="${r}" data-mce-resize="false" data-mce-placeholder />`;return e?`<p>${t}</p>`:t},c=e=>a=>{const t=()=>{a.setEnabled(e.selection.isEditable())};return e.on("NodeChange",t),t(),()=>{e.off("NodeChange",t)}};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(o(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a,onSetup:c(e)}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a,onSetup:c(e)})})(e),(e=>{const a=n(e),t=()=>o(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(n=>{let o,s,c=n.length;for(;c--;)if(o=n[c],s=o.attr("class"),s&&-1!==s.indexOf(r)){const n=o.parent;if(n&&e.schema.getBlockElements()[n.name]&&t()){n.type=3,n.value=a,n.raw=!0,o.remove();continue}o.type=3,o.value=a,o.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,r)&&(a.name="pagebreak")}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/preview/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/preview/plugin.min.js
new file mode 100644
index 0000000..3096240
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/preview/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='<base href="'+a(e.documentBaseURI.getURI())+'">';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='<link type="text/css" rel="stylesheet" href="'+a(e.documentBaseURI.toAbsolute(t))+'"'+m+">"})),d&&(l+='<style type="text/css">'+d+"</style>");const y=r(e),u=c(e),v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(t.os.isMacOS()||t.os.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",p=e.getBody().dir,w=p?' dir="'+a(p)+'"':"";return"<!DOCTYPE html><html><head>"+l+'</head><body id="'+a(y)+'" class="mce-content-body '+a(u)+'"'+w+">"+e.getContent()+v+"</body></html>"})(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0,transparent:!1}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:n}}).focus("close")})(e)}))})(e),(e=>{const t=()=>e.execCommand("mcePreview");e.ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:t}),e.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:t})})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/quickbars/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/quickbars/plugin.min.js
new file mode 100644
index 0000000..2c06412
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/quickbars/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=n=t,(r=String).prototype.isPrototypeOf(o)||(null===(i=n.constructor)||void 0===i?void 0:i.name)===r.name)?"string":e;var o,n,r,i})(t));const n=e("boolean"),r=e("function"),i=t=>e=>e.options.get(t),s=i("quickbars_selection_toolbar"),a=i("quickbars_insert_toolbar"),l=i("quickbars_image_toolbar");let c=0;var u=tinymce.util.Tools.resolve("tinymce.util.Delay");const d=t=>{t.ui.registry.addButton("quickimage",{icon:"image",tooltip:"Insert image",onAction:()=>{(t=>new Promise((e=>{let o=!1;const n=document.createElement("input");n.type="file",n.accept="image/*",n.style.position="fixed",n.style.left="0",n.style.top="0",n.style.opacity="0.001",document.body.appendChild(n);const r=t=>{var r;o||(null===(r=n.parentNode)||void 0===r||r.removeChild(n),o=!0,e(t))},i=t=>{r(Array.prototype.slice.call(t.target.files))};n.addEventListener("input",i),n.addEventListener("change",i);const s=e=>{const n=()=>{r([])};o||("focusin"===e.type?u.setEditorTimeout(t,n,1e3):n()),t.off("focusin remove",s)};t.on("focusin remove",s),n.click()})))(t).then((e=>{if(e.length>0){const o=e[0];(t=>new Promise((e=>{const o=new FileReader;o.onloadend=()=>{e(o.result.split(",")[1])},o.readAsDataURL(t)})))(o).then((e=>{((t,e,o)=>{const n=t.editorUpload.blobCache,r=n.create((t=>{const e=(new Date).getTime(),o=Math.floor(1e9*Math.random());return c++,"mceu_"+o+c+String(e)})(),o,e);n.add(r),t.insertContent(t.dom.createHTML("img",{src:r.blobUri()}))})(t,e,o)}))}}))}}),t.ui.registry.addButton("quicktable",{icon:"table",tooltip:"Insert table",onAction:()=>{((t,e,o)=>{t.execCommand("mceInsertTable",!1,{rows:2,columns:2})})(t)}})},m=(!1,()=>false);class g{constructor(t,e){this.tag=t,this.value=e}static some(t){return new g(!0,t)}static none(){return g.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?g.some(t(this.value)):g.none()}bind(t){return this.tag?t(this.value):g.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:g.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return null==t?g.none():g.some(t)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}g.singletonNone=new g(!1),"undefined"!=typeof window?window:Function("return this;")();var h=(t,e,o,n,i)=>t(o,n)?g.some(o):r(i)&&i(o)?g.none():e(o,n,i);const b=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},p=b,v=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}},f=(t,e,o)=>{let n=t.dom;const i=r(o)?o:m;for(;n.parentNode;){n=n.parentNode;const t=p(n);if(e(t))return g.some(t);if(i(t))break}return g.none()},y=(t,e,o)=>f(t,(t=>v(t,e)),o),k=t=>{const e=a(t);e.length>0&&t.ui.registry.addContextToolbar("quickblock",{predicate:e=>{const o=p(e),n=t.schema.getTextBlockElements(),r=e=>e.dom===t.getBody();return!((t,e)=>{const o=t.dom;return!(!o||!o.hasAttribute)&&o.hasAttribute("data-mce-bogus")})(o)&&((t,e,o)=>h(((t,e)=>v(t,e)),y,t,'table,[data-mce-bogus="all"]',o))(o,0,r).fold((()=>((t,e,o)=>((t,e,o)=>h(((t,e)=>e(t)),f,t,e,o))(t,e,o).isSome())(o,(e=>e.dom.nodeName.toLowerCase()in n&&t.dom.isEmpty(e.dom)),r)),m)},items:e,position:"line",scope:"editor"})};t.add("quickbars",(t=>{(t=>{const e=t.options.register,r=t=>e=>{const r=n(e)||o(e);return r?n(e)?{value:e?t:"",valid:r}:{value:e.trim(),valid:r}:{valid:!1,message:"Must be a boolean or string."}},i="bold italic | quicklink h2 h3 blockquote";e("quickbars_selection_toolbar",{processor:r(i),default:i});const s="quickimage quicktable";e("quickbars_insert_toolbar",{processor:r(s),default:s});const a="alignleft aligncenter alignright";e("quickbars_image_toolbar",{processor:r(a),default:a})})(t),d(t),k(t),(t=>{const e=e=>t.dom.isEditable(e),o=t=>{const o="FIGURE"===t.nodeName&&/image/i.test(t.className),n="IMG"===t.nodeName||o,r=(t=>void 0!==t.dom.classList)(i=p(t))&&i.dom.classList.contains("mce-pagebreak");var i;return n&&e(t.parentElement)&&!r},n=l(t);n.length>0&&t.ui.registry.addContextToolbar("imageselection",{predicate:o,items:n,position:"node"});const r=s(t);r.length>0&&t.ui.registry.addContextToolbar("textselection",{predicate:n=>!o(n)&&!t.selection.isCollapsed()&&e(n),items:r,position:"selection",scope:"editor"})})(t)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/save/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/save/plugin.min.js
new file mode 100644
index 0000000..1896175
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/save/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const o=("function",e=>"function"==typeof e);var n=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),t=tinymce.util.Tools.resolve("tinymce.util.Tools");const a=e=>o=>o.options.get(e),c=a("save_enablewhendirty"),i=a("save_onsavecallback"),s=a("save_oncancelcallback"),r=(e,o)=>{e.notificationManager.open({text:o,type:"error"})},l=e=>o=>{const n=()=>{o.setEnabled(!c(e)||e.isDirty())};return n(),e.on("NodeChange dirty",n),()=>e.off("NodeChange dirty",n)};e.add("save",(e=>{(e=>{const o=e.options.register;o("save_enablewhendirty",{processor:"boolean",default:!0}),o("save_onsavecallback",{processor:"function"}),o("save_oncancelcallback",{processor:"function"})})(e),(e=>{e.ui.registry.addButton("save",{icon:"save",tooltip:"Save",enabled:!1,onAction:()=>e.execCommand("mceSave"),onSetup:l(e),shortcut:"Meta+S"}),e.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",enabled:!1,onAction:()=>e.execCommand("mceCancel"),onSetup:l(e)}),e.addShortcut("Meta+S","","mceSave")})(e),(e=>{e.addCommand("mceSave",(()=>{(e=>{const t=n.DOM.getParent(e.id,"form");if(c(e)&&!e.isDirty())return;e.save();const a=i(e);if(o(a))return a.call(e,e),void e.nodeChanged();t?(e.setDirty(!1),t.onsubmit&&!t.onsubmit()||("function"==typeof t.submit?t.submit():r(e,"Error: Form submit field collision.")),e.nodeChanged()):r(e,"Error: No form element found.")})(e)})),e.addCommand("mceCancel",(()=>{(e=>{const n=t.trim(e.startContent),a=s(e);o(a)?a.call(e,e):e.resetContent(n)})(e)}))})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/searchreplace/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/searchreplace/plugin.min.js
new file mode 100644
index 0000000..fef1387
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/searchreplace/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";const e=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}};var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const n=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=r=e,(o=String).prototype.isPrototypeOf(n)||(null===(s=r.constructor)||void 0===s?void 0:s.name)===o.name)?"string":t;var n,r,o,s})(t)===e,r=e=>t=>typeof t===e,o=n("string"),s=n("array"),a=r("boolean"),l=r("number"),i=()=>{},c=e=>()=>e,d=c(!0),u=c("[~\u2116|!-*+-\\/:;?@\\[-`{}\xa1\xab\xb7\xbb\xbf;\xb7\u055a-\u055f\u0589\u058a\u05be\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f3a-\u0f3d\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1361-\u1368\u1400\u166d\u166e\u169b\u169c\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cd3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205e\u207d\u207e\u208d\u208e\u3008\u3009\u2768-\u2775\u27c5\u27c6\u27e6-\u27ef\u2983-\u2998\u29d8-\u29db\u29fc\u29fd\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e2e\u2e30\u2e31\u3001-\u3003\u3008-\u3011\u3014-\u301f\u3030\u303d\u30a0\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uabeb\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe61\ufe63\ufe68\ufe6a\ufe6b\uff01-\uff03\uff05-\uff0a\uff0c-\uff0f\uff1a\uff1b\uff1f\uff20\uff3b-\uff3d\uff3f\uff5b\uff5d\uff5f-\uff65]");class m{constructor(e,t){this.tag=e,this.value=t}static some(e){return new m(!0,e)}static none(){return m.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?m.some(e(this.value)):m.none()}bind(e){return this.tag?e(this.value):m.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:m.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return null==e?m.none():m.some(e)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}m.singletonNone=new m(!1);const h=u;var g=tinymce.util.Tools.resolve("tinymce.Env"),f=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=Array.prototype.slice,x=Array.prototype.push,y=(e,t)=>{const n=e.length,r=new Array(n);for(let o=0;o<n;o++){const n=e[o];r[o]=t(n,o)}return r},b=(e,t)=>{for(let n=0,r=e.length;n<r;n++)t(e[n],n)},w=(e,t)=>{for(let n=e.length-1;n>=0;n--)t(e[n],n)},v=(e,t)=>(e=>{const t=[];for(let n=0,r=e.length;n<r;++n){if(!s(e[n]))throw new Error("Arr.flatten item "+n+" was not an array, input: "+e);x.apply(t,e[n])}return t})(y(e,t)),C=Object.hasOwnProperty,E=(e,t)=>C.call(e,t);"undefined"!=typeof window?window:Function("return this;")();const O=(3,e=>3===(e=>e.dom.nodeType)(e));const N=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},T=N,k=(e,t)=>({element:e,offset:t}),A=(e,t)=>{((e,t)=>{const n=(e=>m.from(e.dom.parentNode).map(T))(e);n.each((n=>{n.dom.insertBefore(t.dom,e.dom)}))})(e,t),((e,t)=>{e.dom.appendChild(t.dom)})(t,e)},S=((e,t)=>{const n=t=>e(t)?m.from(t.dom.nodeValue):m.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return n(t).getOr("")},getOption:n,set:(t,n)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=n}}})(O),B=e=>S.get(e);var F=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");const I=(e,t)=>e.isBlock(t)||E(e.schema.getVoidElements(),t.nodeName),M=(e,t)=>!e.isEditable(t),R=(e,t)=>!e.isBlock(t)&&E(e.schema.getWhitespaceElements(),t.nodeName),D=(e,t)=>((e,t)=>{const n=(e=>y(e.dom.childNodes,T))(e);return n.length>0&&t<n.length?k(n[t],0):k(e,t)})(T(e),t),P=(e,t,n,r,o,s=!0)=>{let a=s?t(!1):n;for(;a;){const n=M(e,a);if(n||R(e,a)){if(n?r.cef(a):r.boundary(a))break;a=t(!0)}else{if(I(e,a)){if(r.boundary(a))break}else 3===a.nodeType&&r.text(a);if(a===o)break;a=t(!1)}}},W=(e,t,n,r,o)=>{var s;if(((e,t)=>I(e,t)||M(e,t)||R(e,t)||((e,t)=>"true"===e.getContentEditable(t)&&t.parentNode&&!e.isEditable(t.parentNode))(e,t))(e,n))return;const a=null!==(s=e.getParent(r,e.isBlock))&&void 0!==s?s:e.getRoot(),l=new F(n,a),i=o?l.next.bind(l):l.prev.bind(l);P(e,i,n,{boundary:d,cef:d,text:e=>{o?t.fOffset+=e.length:t.sOffset+=e.length,t.elements.push(T(e))}})},$=(e,t,n,r,o,s=!0)=>{const a=new F(n,t),l=[];let i={sOffset:0,fOffset:0,elements:[]};W(e,i,n,t,!1);const c=()=>(i.elements.length>0&&(l.push(i),i={sOffset:0,fOffset:0,elements:[]}),!1);return P(e,a.next.bind(a),n,{boundary:c,cef:e=>(c(),o&&l.push(...o.cef(e)),!1),text:e=>{i.elements.push(T(e)),o&&o.text(e,i)}},r,s),r&&W(e,i,r,t,!0),c(),l},V=(e,t)=>{const n=D(t.startContainer,t.startOffset),r=n.element.dom,o=D(t.endContainer,t.endOffset),s=o.element.dom;return $(e,t.commonAncestorContainer,r,s,{text:(e,t)=>{e===s?t.fOffset+=e.length-o.offset:e===r&&(t.sOffset+=n.offset)},cef:t=>{return((e,t)=>{const n=p.call(e,0);return n.sort(((e,t)=>((e,t)=>((e,t,n)=>0!=(e.compareDocumentPosition(t)&n))(e,t,Node.DOCUMENT_POSITION_PRECEDING))(e.elements[0].dom,t.elements[0].dom)?1:-1)),n})(v((n=T(t),((e,t)=>{const n=void 0===t?document:t.dom;return 1!==(r=n).nodeType&&9!==r.nodeType&&11!==r.nodeType||0===r.childElementCount?[]:y(n.querySelectorAll(e),T);var r})("*[contenteditable=true]",n)),(t=>{const n=t.dom;return $(e,n,n)})));var n}},!1)},j=(e,t)=>t.collapsed?[]:V(e,t),z=(e,t)=>{const n=e.createRng();return n.selectNode(t),j(e,n)},U=(e,t)=>v(t,(t=>{const n=t.elements,r=y(n,B).join(""),o=((e,t,n=0,r=e.length)=>{const o=t.regex;o.lastIndex=n;const s=[];let a;for(;a=o.exec(e);){const e=a[t.matchIndex],n=a.index+a[0].indexOf(e),l=n+e.length;if(l>r)break;s.push({start:n,finish:l}),o.lastIndex=l}return s})(r,e,t.sOffset,r.length-t.fOffset);return((e,t)=>{const n=(r=e,o=(e,n)=>{const r=B(n),o=e.last,s=o+r.length,a=v(t,((e,t)=>e.start<s&&e.finish>o?[{element:n,start:Math.max(o,e.start)-o,finish:Math.min(s,e.finish)-o,matchId:t}]:[]));return{results:e.results.concat(a),last:s}},s={results:[],last:0},b(r,((e,t)=>{s=o(s,e)})),s).results;var r,o,s;return((e,t)=>{if(0===e.length)return[];{let n=t(e[0]);const r=[];let o=[];for(let s=0,a=e.length;s<a;s++){const a=e[s],l=t(a);l!==n&&(r.push(o),o=[]),n=l,o.push(a)}return 0!==o.length&&r.push(o),r}})(n,(e=>e.matchId))})(n,o)})),_=(e,t)=>{w(e,((e,n)=>{w(e,(e=>{const r=T(t.cloneNode(!1));((e,t,n)=>{((e,t,n)=>{if(!(o(n)||a(n)||l(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")})(e.dom,t,n)})(r,"data-mce-index",n);const s=e.element.dom;if(s.length===e.finish&&0===e.start)A(e.element,r);else{s.length!==e.finish&&s.splitText(e.finish);const t=s.splitText(e.start);A(T(t),r)}}))}))},q=e=>e.getAttribute("data-mce-index"),G=(e,t,n,r)=>{const o=e.dom.create("span",{"data-mce-bogus":1});o.className="mce-match-marker";const s=e.getBody();return te(e,t,!1),r?((e,t,n,r)=>{const o=n.getBookmark(),s=e.select("td[data-mce-selected],th[data-mce-selected]"),a=s.length>0?((e,t)=>v(t,(t=>z(e,t))))(e,s):j(e,n.getRng()),l=U(t,a);return _(l,r),n.moveToBookmark(o),l.length})(e.dom,n,e.selection,o):((e,t,n,r)=>{const o=z(e,n),s=U(t,o);return _(s,r),s.length})(e.dom,n,s,o)},K=e=>{var t;const n=e.parentNode;e.firstChild&&n.insertBefore(e.firstChild,e),null===(t=e.parentNode)||void 0===t||t.removeChild(e)},H=(e,t)=>{const n=[],r=f.toArray(e.getBody().getElementsByTagName("span"));if(r.length)for(let e=0;e<r.length;e++){const o=q(r[e]);null!==o&&o.length&&o===t.toString()&&n.push(r[e])}return n},J=(e,t,n)=>{const r=t.get();let o=r.index;const s=e.dom;n?o+1===r.count?o=0:o++:o-1==-1?o=r.count-1:o--,s.removeClass(H(e,r.index),"mce-match-marker-selected");const a=H(e,o);return a.length?(s.addClass(H(e,o),"mce-match-marker-selected"),e.selection.scrollIntoView(a[0]),o):-1},L=(e,t)=>{const n=t.parentNode;e.remove(t),n&&e.isEmpty(n)&&e.remove(n)},Q=(e,t,n,r,o,s)=>{const a=e.selection,l=((e,t)=>{const n="("+e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&").replace(/\s/g,"[^\\S\\r\\n\\uFEFF]")+")";return t?`(?:^|\\s|${h()})`+n+`(?=$|\\s|${h()})`:n})(n,o),i=a.isForward(),c={regex:new RegExp(l,r?"g":"gi"),matchIndex:1},d=G(e,t,c,s);if(g.browser.isSafari()&&a.setRng(a.getRng(),i),d){const a=J(e,t,!0);t.set({index:a,count:d,text:n,matchCase:r,wholeWord:o,inSelection:s})}return d},X=(e,t)=>{const n=J(e,t,!0);t.set({...t.get(),index:n})},Y=(e,t)=>{const n=J(e,t,!1);t.set({...t.get(),index:n})},Z=e=>{const t=q(e);return null!==t&&t.length>0},ee=(e,t,n,r,o)=>{const s=t.get(),a=s.index;let l,i=a;r=!1!==r;const c=e.getBody(),d=f.grep(f.toArray(c.getElementsByTagName("span")),Z);for(let t=0;t<d.length;t++){const c=q(d[t]);let u=l=parseInt(c,10);if(o||u===s.index){for(n.length?(d[t].innerText=n,K(d[t])):L(e.dom,d[t]);d[++t];){if(u=parseInt(q(d[t]),10),u!==l){t--;break}L(e.dom,d[t])}r&&i--}else l>a&&d[t].setAttribute("data-mce-index",String(l-1))}return t.set({...s,count:o?0:s.count-1,index:i}),r?X(e,t):Y(e,t),!o&&t.get().count>0},te=(e,t,n)=>{let r,o;const s=t.get(),a=f.toArray(e.getBody().getElementsByTagName("span"));for(let e=0;e<a.length;e++){const t=q(a[e]);null!==t&&t.length&&(t===s.index.toString()&&(r||(r=a[e].firstChild),o=a[e].firstChild),K(a[e]))}if(t.set({...s,index:-1,count:0,text:""}),r&&o){const t=e.dom.createRng();return t.setStart(r,0),t.setEnd(o,o.data.length),!1!==n&&e.selection.setRng(t),t}},ne=(t,n)=>{const r=(()=>{const t=(t=>{const n=e(m.none()),r=()=>n.get().each(t);return{clear:()=>{r(),n.set(m.none())},isSet:()=>n.get().isSome(),get:()=>n.get(),set:e=>{r(),n.set(m.some(e))}}})(i);return{...t,on:e=>t.get().each(e)}})();t.undoManager.add();const o=f.trim(t.selection.getContent({format:"text"})),s=e=>{e.setEnabled("next",((e,t)=>t.get().count>1)(0,n)),e.setEnabled("prev",((e,t)=>t.get().count>1)(0,n))},a=(e,t)=>{b(["replace","replaceall","prev","next"],(n=>e.setEnabled(n,!t)))},l=(e,t)=>{t.redial(y(e,t.getData()))},c=(e,t)=>{g.browser.isSafari()&&g.deviceType.isTouch()&&("find"===t||"replace"===t||"replaceall"===t)&&e.focus(t)},d=e=>{te(t,n,!1),a(e,!0),s(e)},u=e=>{const r=e.getData(),o=n.get();if(r.findtext.length){if(o.text===r.findtext&&o.matchCase===r.matchcase&&o.wholeWord===r.wholewords)X(t,n);else{const o=Q(t,n,r.findtext,r.matchcase,r.wholewords,r.inselection);o<=0&&l(!0,e),a(e,0===o)}s(e)}else d(e)},h=n.get(),p={findtext:o,replacetext:"",wholewords:h.wholeWord,matchcase:h.matchCase,inselection:h.inSelection},x=e=>{const t=[{type:"label",label:"Find",for:"findtext",items:[{type:"bar",items:[{type:"input",name:"findtext",maximized:!0,inputMode:"search"},{type:"button",name:"prev",text:"Previous",icon:"action-prev",enabled:!1,borderless:!0},{type:"button",name:"next",text:"Next",icon:"action-next",enabled:!1,borderless:!0}]}]},{type:"input",name:"replacetext",label:"Replace with",inputMode:"search"}];return e&&t.push({type:"alertbanner",level:"error",text:"Could not find the specified string.",icon:"warning"}),t},y=(e,r)=>({title:"Find and Replace",size:"normal",body:{type:"panel",items:x(e)},buttons:[{type:"menu",name:"options",icon:"preferences",tooltip:"Preferences",align:"start",items:[{type:"togglemenuitem",name:"matchcase",text:"Match case"},{type:"togglemenuitem",name:"wholewords",text:"Find whole words only"},{type:"togglemenuitem",name:"inselection",text:"Find in selection"}]},{type:"custom",name:"find",text:"Find",primary:!0},{type:"custom",name:"replace",text:"Replace",enabled:!1},{type:"custom",name:"replaceall",text:"Replace all",enabled:!1}],initialData:r,onChange:(t,r)=>{e&&l(!1,t),"findtext"===r.name&&n.get().count>0&&d(t)},onAction:(e,r)=>{const o=e.getData();switch(r.name){case"find":u(e);break;case"replace":ee(t,n,o.replacetext)?s(e):d(e);break;case"replaceall":ee(t,n,o.replacetext,!0,!0),d(e);break;case"prev":Y(t,n),s(e);break;case"next":X(t,n),s(e);break;case"matchcase":case"wholewords":case"inselection":l(!1,e),(e=>{const t=e.getData(),r=n.get();n.set({...r,matchCase:t.matchcase,wholeWord:t.wholewords,inSelection:t.inselection})})(e),d(e)}c(e,r.name)},onSubmit:e=>{u(e),c(e,"find")},onClose:()=>{t.focus(),te(t,n),t.undoManager.add()}});r.set(t.windowManager.open(y(!1,p),{inline:"toolbar"}))},re=(e,t)=>()=>{ne(e,t)};t.add("searchreplace",(t=>{const n=e({index:-1,count:0,text:"",matchCase:!1,wholeWord:!1,inSelection:!1});return((e,t)=>{e.addCommand("SearchReplace",(()=>{ne(e,t)}))})(t,n),((e,t)=>{e.ui.registry.addMenuItem("searchreplace",{text:"Find and replace...",shortcut:"Meta+F",onAction:re(e,t),icon:"search"}),e.ui.registry.addButton("searchreplace",{tooltip:"Find and replace",onAction:re(e,t),icon:"search",shortcut:"Meta+F"}),e.shortcuts.add("Meta+F","",re(e,t))})(t,n),((e,t)=>({done:n=>te(e,t,n),find:(n,r,o,s=!1)=>Q(e,t,n,r,o,s),next:()=>X(e,t),prev:()=>Y(e,t),replace:(n,r,o)=>ee(e,t,n,r,o)}))(t,n)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/table/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/table/plugin.min.js
new file mode 100644
index 0000000..b522b93
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/table/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(o=l=e,(n=String).prototype.isPrototypeOf(o)||(null===(r=l.constructor)||void 0===r?void 0:r.name)===n.name)?"string":t;var o,l,n,r})(t)===e,o=e=>t=>typeof t===e,l=t("string"),n=t("array"),r=o("boolean"),a=(void 0,e=>undefined===e);const s=e=>!(e=>null==e)(e),c=o("function"),i=o("number"),m=()=>{},d=e=>()=>e,u=e=>e,p=(e,t)=>e===t;function b(e,...t){return(...o)=>{const l=t.concat(o);return e.apply(null,l)}}const g=e=>{e()},h=d(!1),f=d(!0);class y{constructor(e,t){this.tag=e,this.value=t}static some(e){return new y(!0,e)}static none(){return y.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?y.some(e(this.value)):y.none()}bind(e){return this.tag?e(this.value):y.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:y.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return s(e)?y.some(e):y.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}y.singletonNone=new y(!1);const w=Object.keys,S=Object.hasOwnProperty,C=(e,t)=>{const o=w(e);for(let l=0,n=o.length;l<n;l++){const n=o[l];t(e[n],n)}},v=(e,t)=>{const o={};var l;return((e,t,o,l)=>{C(e,((e,n)=>{(t(e,n)?o:l)(e,n)}))})(e,t,(l=o,(e,t)=>{l[t]=e}),m),o},T=e=>w(e).length,x=(e,t)=>A(e,t)?y.from(e[t]):y.none(),A=(e,t)=>S.call(e,t),R=(e,t)=>A(e,t)&&void 0!==e[t]&&null!==e[t],O=Array.prototype.indexOf,_=Array.prototype.push,D=(e,t)=>((e,t)=>O.call(e,t))(e,t)>-1,N=(e,t)=>{for(let o=0,l=e.length;o<l;o++)if(t(e[o],o))return!0;return!1},I=(e,t)=>{const o=[];for(let l=0;l<e;l++)o.push(t(l));return o},M=(e,t)=>{const o=e.length,l=new Array(o);for(let n=0;n<o;n++){const o=e[n];l[n]=t(o,n)}return l},P=(e,t)=>{for(let o=0,l=e.length;o<l;o++)t(e[o],o)},k=(e,t)=>{const o=[];for(let l=0,n=e.length;l<n;l++){const n=e[l];t(n,l)&&o.push(n)}return o},E=(e,t,o)=>(P(e,((e,l)=>{o=t(o,e,l)})),o),B=(e,t)=>((e,t,o)=>{for(let l=0,n=e.length;l<n;l++){const n=e[l];if(t(n,l))return y.some(n);if(o(n,l))break}return y.none()})(e,t,h),F=(e,t)=>(e=>{const t=[];for(let o=0,l=e.length;o<l;++o){if(!n(e[o]))throw new Error("Arr.flatten item "+o+" was not an array, input: "+e);_.apply(t,e[o])}return t})(M(e,t)),q=(e,t)=>{for(let o=0,l=e.length;o<l;++o)if(!0!==t(e[o],o))return!1;return!0},L=(e,t)=>t>=0&&t<e.length?y.some(e[t]):y.none(),j=(e,t)=>{for(let o=0;o<e.length;o++){const l=t(e[o],o);if(l.isSome())return l}return y.none()},H=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},V={fromHtml:(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return H(o.childNodes[0])},fromTag:(e,t)=>{const o=(t||document).createElement(e);return H(o)},fromText:(e,t)=>{const o=(t||document).createTextNode(e);return H(o)},fromDom:H,fromPoint:(e,t,o)=>y.from(e.dom.elementFromPoint(t,o)).map(H)},$=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},W=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,z=(e,t)=>e.dom===t.dom,U=$;"undefined"!=typeof window?window:Function("return this;")();const G=e=>e.dom.nodeName.toLowerCase(),K=e=>e.dom.nodeType,J=e=>t=>K(t)===e,Q=J(1),X=J(3),Y=J(9),Z=J(11),ee=e=>t=>Q(t)&&G(t)===e,te=e=>Y(e)?e:V.fromDom(e.dom.ownerDocument),oe=e=>y.from(e.dom.parentNode).map(V.fromDom),le=e=>y.from(e.dom.nextSibling).map(V.fromDom),ne=e=>M(e.dom.childNodes,V.fromDom),re=c(Element.prototype.attachShadow)&&c(Node.prototype.getRootNode)?e=>V.fromDom(e.dom.getRootNode()):te,ae=e=>V.fromDom(e.dom.host),se=e=>{const t=X(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return(e=>{const t=re(e);return Z(o=t)&&s(o.dom.host)?y.some(t):y.none();var o})(V.fromDom(t)).fold((()=>o.body.contains(t)),(l=se,n=ae,e=>l(n(e))));var l,n};var ce=(e,t,o,l,n)=>e(o,l)?y.some(o):c(n)&&n(o)?y.none():t(o,l,n);const ie=(e,t,o)=>{let l=e.dom;const n=c(o)?o:h;for(;l.parentNode;){l=l.parentNode;const e=V.fromDom(l);if(t(e))return y.some(e);if(n(e))break}return y.none()},me=(e,t,o)=>ie(e,(e=>$(e,t)),o),de=(e,t)=>((e,o)=>B(e.dom.childNodes,(e=>{return o=V.fromDom(e),$(o,t);var o})).map(V.fromDom))(e),ue=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return W(o)?y.none():y.from(o.querySelector(e)).map(V.fromDom)})(t,e),pe=(e,t,o)=>ce(((e,t)=>$(e,t)),me,e,t,o),be=(e,t=!1)=>{return se(e)?e.dom.isContentEditable:(o=e,pe(o,"[contenteditable]")).fold(d(t),(e=>"true"===ge(e)));var o},ge=e=>e.dom.contentEditable,he=e=>t=>z(t,(e=>V.fromDom(e.getBody()))(e)),fe=e=>/^\d+(\.\d+)?$/.test(e)?e+"px":e,ye=e=>V.fromDom(e.selection.getStart()),we=(e,t)=>{let o=[];return P(ne(e),(e=>{t(e)&&(o=o.concat([e])),o=o.concat(we(e,t))})),o},Se=(e,t)=>((e,o)=>k(ne(e),(e=>$(e,t))))(e),Ce=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return W(o)?[]:M(o.querySelectorAll(e),V.fromDom)})(t,e),ve=(e,t,o)=>{if(!(l(o)||r(o)||i(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},Te=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},xe=(e,t)=>y.from(Te(e,t)),Ae=(e,t)=>{e.dom.removeAttribute(t)},Re=(e,t,o=p)=>e.exists((e=>o(e,t))),Oe=(e,t,o)=>e.isSome()&&t.isSome()?y.some(o(e.getOrDie(),t.getOrDie())):y.none(),_e=(e,t)=>((e,t,o)=>""===t||e.length>=t.length&&e.substr(0,0+t.length)===t)(e,t),De=(Ne=/^\s+|\s+$/g,e=>e.replace(Ne,""));var Ne;const Ie=e=>e.length>0,Me=(e,t=10)=>{const o=parseInt(e,t);return isNaN(o)?y.none():y.some(o)},Pe=e=>void 0!==e.style&&c(e.style.getPropertyValue),ke=(e,t)=>{const o=e.dom,l=window.getComputedStyle(o).getPropertyValue(t);return""!==l||se(e)?l:Ee(o,t)},Ee=(e,t)=>Pe(e)?e.style.getPropertyValue(t):"",Be=(e,t)=>{const o=e.dom,l=Ee(o,t);return y.from(l).filter((e=>e.length>0))},Fe=(e,t,o=0)=>xe(e,t).map((e=>parseInt(e,10))).getOr(o),qe=(e,t)=>Le(e,t,f),Le=(e,t,o)=>F(ne(e),(e=>$(e,t)?o(e)?[e]:[]:Le(e,t,o))),je=["tfoot","thead","tbody","colgroup"],He=(e,t,o)=>({element:e,rowspan:t,colspan:o}),Ve=(e,t,o)=>({element:e,cells:t,section:o}),$e=(e,t)=>pe(e,"table",t),We=e=>qe(e,"tr"),ze=e=>$e(e).fold(d([]),(e=>Se(e,"colgroup"))),Ue=e=>oe(e).map((e=>{const t=G(e);return(e=>D(je,e))(t)?t:"tbody"})).getOr("tbody"),Ge=e=>xe(e,"data-snooker-locked-cols").bind((e=>y.from(e.match(/\d+/g)))).map((e=>((e,t)=>{const o={};for(let l=0,n=e.length;l<n;l++){const n=e[l];o[String(n)]=t(n,l)}return o})(e,f))),Ke=(e,t)=>e+","+t,Je=e=>{const t={},o=[];var l;const n=(l=e,L(l,0)).map((e=>e.element)).bind($e).bind(Ge).getOr({});let r=0,a=0,s=0;const{pass:c,fail:i}=((e,t)=>{const o=[],l=[];for(let t=0,r=e.length;t<r;t++){const r=e[t];(n=r,"colgroup"===n.section?o:l).push(r)}var n;return{pass:o,fail:l}})(e);P(i,(e=>{const l=[];P(e.cells,(e=>{let o=0;for(;void 0!==t[Ke(s,o)];)o++;const r=R(n,o.toString()),c=((e,t,o,l,n,r)=>({element:e,rowspan:t,colspan:o,row:l,column:n,isLocked:r}))(e.element,e.rowspan,e.colspan,s,o,r);for(let l=0;l<e.colspan;l++)for(let n=0;n<e.rowspan;n++){const e=o+l,r=Ke(s+n,e);t[r]=c,a=Math.max(a,e+1)}l.push(c)})),r++,o.push(Ve(e.element,l,e.section)),s++}));const{columns:m,colgroups:d}=(e=>L(e,e.length-1))(c).map((e=>{const t=(e=>{const t={};let o=0;return P(e.cells,(e=>{const l=e.colspan;I(l,(n=>{const r=o+n;t[r]=((e,t,o)=>({element:e,colspan:t,column:o}))(e.element,l,r)})),o+=l})),t})(e),o=((e,t)=>({element:e,columns:t}))(e.element,((e,t)=>{const o=[];return C(e,((e,l)=>{o.push(t(e,l))})),o})(t,u));return{colgroups:[o],columns:t}})).getOrThunk((()=>({colgroups:[],columns:{}}))),p=((e,t)=>({rows:e,columns:t}))(r,a);return{grid:p,access:t,all:o,columns:m,colgroups:d}},Qe=e=>{const t=(e=>{const t=We(e);return((e,t)=>M(e,(e=>{if("colgroup"===G(e)){const t=M((e=>$(e,"colgroup")?Se(e,"col"):F(ze(e),(e=>Se(e,"col"))))(e),(e=>{const t=Fe(e,"span",1);return He(e,1,t)}));return Ve(e,t,"colgroup")}{const o=M((e=>qe(e,"th,td"))(e),(e=>{const t=Fe(e,"rowspan",1),o=Fe(e,"colspan",1);return He(e,t,o)}));return Ve(e,o,t(e))}})))([...ze(e),...t],Ue)})(e);return Je(t)},Xe=(e,t,o)=>y.from(e.access[Ke(t,o)]),Ye=(e,t,o)=>{const l=((e,t)=>{const o=F(e.all,(e=>e.cells));return k(o,t)})(e,(e=>o(t,e.element)));return l.length>0?y.some(l[0]):y.none()},Ze=(e,t)=>y.from(e.columns[t]);var et=tinymce.util.Tools.resolve("tinymce.util.Tools");const tt=(e,t,o)=>{const l=e.select("td,th",t);let n;for(let t=0;t<l.length;t++){const r=e.getStyle(l[t],o);if(a(n)&&(n=r),n!==r)return""}return n},ot=(e,t,o)=>{et.each("left center right".split(" "),(l=>{l!==o&&e.formatter.remove("align"+l,{},t)})),o&&e.formatter.apply("align"+o,{},t)},lt=(e,t,o)=>{e.dispatch("TableModified",{...o,table:t})},nt=(e,t,o)=>((e,t)=>(e=>{const t=parseFloat(e);return isNaN(t)?y.none():y.some(t)})(e).getOr(t))(ke(e,t),o),rt=e=>((e,t)=>{const o=e.dom,l=o.getBoundingClientRect().width||o.offsetWidth;return"border-box"===t?l:((e,t,o,l)=>t-nt(e,`padding-${o}`,0)-nt(e,`padding-${l}`,0)-nt(e,`border-${o}-width`,0)-nt(e,`border-${l}-width`,0))(e,l,"left","right")})(e,"content-box");var at=tinymce.util.Tools.resolve("tinymce.Env");const st=I(5,(e=>{const t=`${e+1}px`;return{title:t,value:t}})),ct=M(["Solid","Dotted","Dashed","Double","Groove","Ridge","Inset","Outset","None","Hidden"],(e=>({title:e,value:e.toLowerCase()}))),it="100%",mt=e=>{var t;const o=e.dom,l=null!==(t=o.getParent(e.selection.getStart(),o.isBlock))&&void 0!==t?t:e.getBody();return rt(V.fromDom(l))+"px"},dt=e=>t=>t.options.get(e),ut=dt("table_sizing_mode"),pt=dt("table_border_widths"),bt=dt("table_border_styles"),gt=dt("table_cell_advtab"),ht=dt("table_row_advtab"),ft=dt("table_advtab"),yt=dt("table_appearance_options"),wt=dt("table_grid"),St=dt("table_style_by_css"),Ct=dt("table_cell_class_list"),vt=dt("table_row_class_list"),Tt=dt("table_class_list"),xt=dt("table_toolbar"),At=dt("table_background_color_map"),Rt=dt("table_border_color_map"),Ot=e=>"fixed"===ut(e),_t=e=>"responsive"===ut(e),Dt=e=>{const t=e.options,o=t.get("table_default_styles");return t.isSet("table_default_styles")?o:((e,t)=>_t(e)||!St(e)?t:Ot(e)?{...t,width:mt(e)}:{...t,width:it})(e,o)},Nt=e=>{const t=e.options,o=t.get("table_default_attributes");return t.isSet("table_default_attributes")?o:((e,t)=>_t(e)||St(e)?t:Ot(e)?{...t,width:mt(e)}:{...t,width:it})(e,o)},It=(e,t)=>t.column>=e.startCol&&t.column+t.colspan-1<=e.finishCol&&t.row>=e.startRow&&t.row+t.rowspan-1<=e.finishRow,Mt=(e,t,o)=>((e,t,o)=>{const l=Ye(e,t,z),n=Ye(e,o,z);return l.bind((e=>n.map((t=>{return o=e,l=t,{startRow:Math.min(o.row,l.row),startCol:Math.min(o.column,l.column),finishRow:Math.max(o.row+o.rowspan-1,l.row+l.rowspan-1),finishCol:Math.max(o.column+o.colspan-1,l.column+l.colspan-1)};var o,l}))))})(e,t,o).bind((t=>((e,t)=>{let o=!0;const l=b(It,t);for(let n=t.startRow;n<=t.finishRow;n++)for(let r=t.startCol;r<=t.finishCol;r++)o=o&&Xe(e,n,r).exists(l);return o?y.some(t):y.none()})(e,t))),Pt=Qe,kt=(e,t)=>{oe(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},Et=(e,t)=>{le(e).fold((()=>{oe(e).each((e=>{Bt(e,t)}))}),(e=>{kt(e,t)}))},Bt=(e,t)=>{e.dom.appendChild(t.dom)},Ft=(e,t)=>{P(t,((o,l)=>{const n=0===l?e:t[l-1];Et(n,o)}))},qt=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Lt=((e,t)=>{const o=t=>e(t)?y.from(t.dom.nodeValue):y.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(X);var jt=["body","p","div","article","aside","figcaption","figure","footer","header","nav","section","ol","ul","li","table","thead","tbody","tfoot","caption","tr","td","th","h1","h2","h3","h4","h5","h6","blockquote","pre","address"];const Ht=(e,t,o,l)=>{const n=t(e,o);return r=(o,l)=>{const n=t(e,l);return Vt(e,o,n)},a=n,((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(l,((e,t)=>{a=r(a,e)})),a;var r,a},Vt=(e,t,o)=>t.bind((t=>o.filter(b(e.eq,t)))),$t={up:d({selector:me,closest:pe,predicate:ie,all:(e,t)=>{const o=c(t)?t:h;let l=e.dom;const n=[];for(;null!==l.parentNode&&void 0!==l.parentNode;){const e=l.parentNode,t=V.fromDom(e);if(n.push(t),!0===o(t))break;l=e}return n}}),down:d({selector:Ce,predicate:we}),styles:d({get:ke,getRaw:Be,set:(e,t,o)=>{((e,t,o)=>{if(!l(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);Pe(e)&&e.style.setProperty(t,o)})(e.dom,t,o)},remove:(e,t)=>{((e,t)=>{Pe(e)&&e.style.removeProperty(t)})(e.dom,t),Re(xe(e,"style").map(De),"")&&Ae(e,"style")}}),attrs:d({get:Te,set:(e,t,o)=>{ve(e.dom,t,o)},remove:Ae,copyTo:(e,t)=>{((e,t)=>{const o=e.dom;C(t,((e,t)=>{ve(o,t,e)}))})(t,E(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}))}}),insert:d({before:kt,after:Et,afterAll:Ft,append:Bt,appendAll:(e,t)=>{P(t,(t=>{Bt(e,t)}))},prepend:(e,t)=>{(e=>((e,t)=>{const o=e.dom.childNodes;return y.from(o[0]).map(V.fromDom)})(e))(e).fold((()=>{Bt(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},wrap:(e,t)=>{kt(e,t),Bt(t,e)}}),remove:d({unwrap:e=>{const t=ne(e);t.length>0&&Ft(e,t),qt(e)},remove:qt}),create:d({nu:V.fromTag,clone:e=>V.fromDom(e.dom.cloneNode(!1)),text:V.fromText}),query:d({comparePosition:(e,t)=>e.dom.compareDocumentPosition(t.dom),prevSibling:e=>y.from(e.dom.previousSibling).map(V.fromDom),nextSibling:le}),property:d({children:ne,name:G,parent:oe,document:e=>te(e).dom,isText:X,isComment:e=>8===K(e)||"#comment"===G(e),isElement:Q,isSpecial:e=>{const t=G(e);return D(["script","noscript","iframe","noframes","noembed","title","style","textarea","xmp"],t)},getLanguage:e=>Q(e)?xe(e,"lang"):y.none(),getText:e=>Lt.get(e),setText:(e,t)=>Lt.set(e,t),isBoundary:e=>!!Q(e)&&("body"===G(e)||D(jt,G(e))),isEmptyTag:e=>!!Q(e)&&D(["br","img","hr","input"],G(e)),isNonEditable:e=>Q(e)&&"false"===Te(e,"contenteditable")}),eq:z,is:U},Wt=e=>me(e,"table"),zt=(e,t,o)=>ue(e,t).bind((t=>ue(e,o).bind((e=>{return(o=Wt,l=[t,e],((e,t,o)=>o.length>0?((e,t,o,l)=>l(e,t,o[0],o.slice(1)))(e,t,o,Ht):y.none())($t,((e,t)=>o(t)),l)).map((o=>({first:t,last:e,table:o})));var o,l})))),Ut=e=>M(e,V.fromDom),Gt="data-mce-selected",Kt="data-mce-first-selected",Jt="data-mce-last-selected",Qt={selected:Gt,selectedSelector:"td["+Gt+"],th["+Gt+"]",firstSelected:Kt,firstSelectedSelector:"td["+Kt+"],th["+Kt+"]",lastSelected:Jt,lastSelectedSelector:"td["+Jt+"],th["+Jt+"]"},Xt=e=>(t,o)=>{const l=G(t),n="col"===l||"colgroup"===l?$e(r=t).bind((e=>((e,t)=>((e,t)=>{const o=Ce(e,t);return o.length>0?y.some(o):y.none()})(e,t))(e,Qt.firstSelectedSelector))).fold(d(r),(e=>e[0])):t;var r;return pe(n,e,o)},Yt=Xt("th,td,caption"),Zt=Xt("th,td"),eo=e=>Ut(e.model.table.getSelectedCells()),to=(e,t)=>{const o=Zt(e),l=o.bind((e=>$e(e))).map((e=>We(e)));return Oe(o,l,((e,o)=>k(o,(o=>N(Ut(o.dom.cells),(o=>"1"===Te(o,t)||z(o,e))))))).getOr([])},oo=[{text:"None",value:""},{text:"Top",value:"top"},{text:"Middle",value:"middle"},{text:"Bottom",value:"bottom"}],lo=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,no=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,ro=e=>{return(t=e,"#",_e(t,"#")?((e,t)=>e.substring(1))(t):t).toUpperCase();var t},ao=e=>{const t=e.toString(16);return(1===t.length?"0"+t:t).toUpperCase()},so=e=>{return t=ao(e.red)+ao(e.green)+ao(e.blue),{value:ro(t)};var t},co=/^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i,io=/^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i,mo=(e,t,o,l)=>({red:e,green:t,blue:o,alpha:l}),uo=(e,t,o,l)=>{const n=parseInt(e,10),r=parseInt(t,10),a=parseInt(o,10),s=parseFloat(l);return mo(n,r,a,s)},po=e=>{const t=co.exec(e);if(null!==t)return y.some(uo(t[1],t[2],t[3],"1"));const o=io.exec(e);return null!==o?y.some(uo(o[1],o[2],o[3],o[4])):y.none()},bo=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},go=(e,t,o)=>l=>{const n=(e=>{const t=bo(y.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(y.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(y.some(e))}}})((e=>e.unbind())),r=!Ie(o),a=()=>{const a=eo(e),s=l=>e.formatter.match(t,{value:o},l.dom,r);r?(l.setActive(!N(a,s)),n.set(e.formatter.formatChanged(t,(e=>l.setActive(!e)),!0))):(l.setActive(q(a,s)),n.set(e.formatter.formatChanged(t,l.setActive,!1,{value:o})))};return e.initialized?a():e.on("init",a),n.clear},ho=e=>R(e,"menu"),fo=e=>M(e,(e=>{const t=e.text||e.title||"";return ho(e)?{text:t,items:fo(e.menu)}:{text:t,value:e.value}})),yo=e=>e.length?y.some(fo([{text:"Select...",value:"mce-no-match"},...e])):y.none(),wo=(e,t,o,l)=>M(t,(t=>{const n=t.text||t.title;return ho(t)?{type:"nestedmenuitem",text:n,getSubmenuItems:()=>wo(e,t.menu,o,l)}:{text:n,type:"togglemenuitem",onAction:()=>l(t.value),onSetup:go(e,o,t.value)}})),So=(e,t)=>o=>{e.execCommand("mceTableApplyCellStyle",!1,{[t]:o})},Co=e=>F(e,(e=>ho(e)?[{...e,menu:Co(e.menu)}]:Ie(e.value)?[e]:[])),vo=(e,t,o,l)=>n=>n(wo(e,t,o,l)),To=(e,t,o)=>{const l=M(t,(e=>{return{text:e.title,value:"#"+(o=e.value,(t=o,(e=>lo.test(e)||no.test(e))(t)?y.some({value:ro(t)}):y.none()).orThunk((()=>po(o).map(so))).getOrThunk((()=>{const e=document.createElement("canvas");e.height=1,e.width=1;const t=e.getContext("2d");t.clearRect(0,0,e.width,e.height),t.fillStyle="#FFFFFF",t.fillStyle=o,t.fillRect(0,0,1,1);const l=t.getImageData(0,0,1,1).data,n=l[0],r=l[1],a=l[2],s=l[3];return so(mo(n,r,a,s))}))).value,type:"choiceitem"};var t,o}));return[{type:"fancymenuitem",fancytype:"colorswatch",initData:{colors:l.length>0?l:void 0,allowCustomColors:!1},onAction:t=>{const l="remove"===t.value?"":t.value;e.execCommand("mceTableApplyCellStyle",!1,{[o]:l})}}]},xo=e=>()=>{const t="header"===e.queryCommandValue("mceTableRowType")?"body":"header";e.execCommand("mceTableRowType",!1,{type:t})},Ao=e=>()=>{const t="th"===e.queryCommandValue("mceTableColType")?"td":"th";e.execCommand("mceTableColType",!1,{type:t})},Ro=[{name:"width",type:"input",label:"Width"},{name:"celltype",type:"listbox",label:"Cell type",items:[{text:"Cell",value:"td"},{text:"Header cell",value:"th"}]},{name:"scope",type:"listbox",label:"Scope",items:[{text:"None",value:""},{text:"Row",value:"row"},{text:"Column",value:"col"},{text:"Row group",value:"rowgroup"},{text:"Column group",value:"colgroup"}]},{name:"halign",type:"listbox",label:"Horizontal align",items:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]},{name:"valign",type:"listbox",label:"Vertical align",items:oo}],Oo=e=>Ro.concat((e=>yo(Ct(e)).map((e=>({name:"class",type:"listbox",label:"Class",items:e}))))(e).toArray()),_o=(e,t)=>{const o=[{name:"borderstyle",type:"listbox",label:"Border style",items:[{text:"Select...",value:""}].concat(fo(bt(e)))},{name:"bordercolor",type:"colorinput",label:"Border color"},{name:"backgroundcolor",type:"colorinput",label:"Background color"}];return{title:"Advanced",name:"advanced",items:"cell"===t?[{name:"borderwidth",type:"input",label:"Border width"}].concat(o):o}},Do=(e,t)=>{const o=e.dom;return{setAttrib:(e,l)=>{o.setAttrib(t,e,l)},setStyle:(e,l)=>{o.setStyle(t,e,l)},setFormat:(o,l)=>{""===l?e.formatter.remove(o,{value:null},t,!0):e.formatter.apply(o,{value:l},t)}}},No=ee("th"),Io=(e,t)=>e&&t?"sectionCells":e?"section":"cells",Mo=e=>{const t=M(e,(e=>(e=>{const t="thead"===e.section,o=Re((e=>{const t=k(e,(e=>No(e.element)));return 0===t.length?y.some("td"):t.length===e.length?y.some("th"):y.none()})(e.cells),"th");return"tfoot"===e.section?{type:"footer"}:t||o?{type:"header",subType:Io(t,o)}:{type:"body"}})(e).type)),o=D(t,"header"),l=D(t,"footer");if(o||l){const e=D(t,"body");return!o||e||l?o||e||!l?y.none():y.some("footer"):y.some("header")}return y.some("body")},Po=(e,t)=>j(e.all,(e=>B(e.cells,(e=>z(t,e.element))))),ko=(e,t,o)=>{const l=(e=>{const t=[],o=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(o);return t})(M(t.selection,(t=>{return(l=t,((e,t,o=h)=>o(t)?y.none():D(e,G(t))?y.some(t):me(t,e.join(","),(e=>$(e,"table")||o(e))))(["td","th"],l,n)).bind((t=>Po(e,t))).filter(o);var l,n})));return n=l,l.length>0?y.some(n):y.none();var n},Eo=(e,t)=>ko(e,t,f),Bo=(e,t)=>q(t,(t=>((e,t)=>Po(e,t).exists((e=>!e.isLocked)))(e,t))),Fo=(e,t)=>((e,t)=>t.mergable)(0,t).filter((t=>Bo(e,t.cells))),qo=(e,t)=>((e,t)=>t.unmergable)(0,t).filter((t=>Bo(e,t))),Lo=((e=>{if(!n(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};P(e,((l,r)=>{const a=w(l);if(1!==a.length)throw new Error("one and only one name per case");const s=a[0],c=l[s];if(void 0!==o[s])throw new Error("duplicate key detected:"+s);if("cata"===s)throw new Error("cannot have a case named cata (sorry)");if(!n(c))throw new Error("case arguments must be an array");t.push(s),o[s]=(...o)=>{const l=o.length;if(l!==c.length)throw new Error("Wrong number of arguments to case "+s+". Expected "+c.length+" ("+c+"), got "+l);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,o)},match:e=>{const l=w(e);if(t.length!==l.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+l.join(","));if(!q(t,(e=>D(l,e))))throw new Error("Not all branches were specified when using match. Specified: "+l.join(", ")+"\nRequired: "+t.join(", "));return e[s].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:s,params:o})}}}}))})([{none:[]},{only:["index"]},{left:["index","next"]},{middle:["prev","index","next"]},{right:["prev","index"]}]),(e,t)=>{const o=Qe(e);return Eo(o,t).bind((e=>{const t=e[e.length-1],l=e[0].row,n=t.row+t.rowspan,r=o.all.slice(l,n);return Mo(r)})).getOr("")}),jo=e=>{return _e(e,"rgb")?po(t=e).map(so).map((e=>"#"+e.value)).getOr(t):e;var t},Ho=e=>{const t=V.fromDom(e);return{borderwidth:Be(t,"border-width").getOr(""),borderstyle:Be(t,"border-style").getOr(""),bordercolor:Be(t,"border-color").map(jo).getOr(""),backgroundcolor:Be(t,"background-color").map(jo).getOr("")}},Vo=e=>{const t=e[0],o=e.slice(1);return P(o,(e=>{P(w(t),(o=>{C(e,((e,l)=>{const n=t[o];""!==n&&o===l&&n!==e&&(t[o]="class"===o?"mce-no-match":"")}))}))})),t},$o=(e,t,o,l)=>B(e,(e=>!a(o.formatter.matchNode(l,t+e)))).getOr(""),Wo=b($o,["left","center","right"],"align"),zo=b($o,["top","middle","bottom"],"valign"),Uo=e=>$e(V.fromDom(e)).map((t=>{const o={selection:Ut(e.cells)};return Lo(t,o)})).getOr(""),Go=(e,t)=>{const o=Qe(e),l=(e=>F(e.all,(e=>e.cells)))(o),n=k(l,(e=>N(t,(t=>z(e.element,t)))));return M(n,(e=>({element:e.element.dom,column:Ze(o,e.column).map((e=>e.element.dom))})))},Ko=(e,t,o,l)=>{const n=l.getData();l.close(),e.undoManager.transact((()=>{((e,t,o,l)=>{const n=v(l,((e,t)=>o[t]!==e));T(n)>0&&t.length>=1&&$e(t[0]).each((o=>{const r=Go(o,t),a=T(v(n,((e,t)=>"scope"!==t&&"celltype"!==t)))>0,s=A(n,"celltype");(a||A(n,"scope"))&&((e,t,o,l)=>{const n=1===t.length;P(t,(t=>{const r=t.element,a=n?f:l,s=Do(e,r);((e,t,o,l)=>{l("scope")&&e.setAttrib("scope",o.scope),l("class")&&"mce-no-match"!==o.class&&e.setAttrib("class",o.class),l("width")&&t.setStyle("width",fe(o.width))})(s,t.column.map((t=>Do(e,t))).getOr(s),o,a),gt(e)&&((e,t,o)=>{o("backgroundcolor")&&e.setFormat("tablecellbackgroundcolor",t.backgroundcolor),o("bordercolor")&&e.setFormat("tablecellbordercolor",t.bordercolor),o("borderstyle")&&e.setFormat("tablecellborderstyle",t.borderstyle),o("borderwidth")&&e.setFormat("tablecellborderwidth",fe(t.borderwidth))})(s,o,a),l("halign")&&ot(e,r,o.halign),l("valign")&&((e,t,o)=>{et.each("top middle bottom".split(" "),(l=>{l!==o&&e.formatter.remove("valign"+l,{},t)})),o&&e.formatter.apply("valign"+o,{},t)})(e,r,o.valign)}))})(e,r,l,b(A,n)),s&&((e,t)=>{e.execCommand("mceTableCellType",!1,{type:t.celltype,no_events:!0})})(e,l),lt(e,o.dom,{structure:s,style:a})}))})(e,t,o,n),e.focus()}))},Jo=e=>{const t=eo(e);if(0===t.length)return;const o=((e,t)=>{const o=$e(t[0]).map((o=>M(Go(o,t),(t=>((e,t,o,l)=>{const n=e.dom;return{width:(a=l.getOr(t),s="width",n.getStyle(a,s)||n.getAttrib(a,s)),scope:n.getAttrib(t,"scope"),celltype:(r=t,r.nodeName.toLowerCase()),class:n.getAttrib(t,"class",""),halign:Wo(e,t),valign:zo(e,t),...o?Ho(t):{}};var r,a,s})(e,t.element,gt(e),t.column)))));return Vo(o.getOrDie())})(e,t),l={type:"tabpanel",tabs:[{title:"General",name:"general",items:Oo(e)},_o(e,"cell")]},n={type:"panel",items:[{type:"grid",columns:2,items:Oo(e)}]};e.windowManager.open({title:"Cell Properties",size:"normal",body:gt(e)?l:n,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:o,onSubmit:b(Ko,e,t,o)})},Qo=[{type:"listbox",name:"type",label:"Row type",items:[{text:"Header",value:"header"},{text:"Body",value:"body"},{text:"Footer",value:"footer"}]},{type:"listbox",name:"align",label:"Alignment",items:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]},{label:"Height",name:"height",type:"input"}],Xo=e=>Qo.concat((e=>yo(vt(e)).map((e=>({name:"class",type:"listbox",label:"Class",items:e}))))(e).toArray()),Yo=(e,t,o,l)=>{const n=l.getData();l.close(),e.undoManager.transact((()=>{((e,t,o,l)=>{const n=v(l,((e,t)=>o[t]!==e));if(T(n)>0){const o=A(n,"type"),r=!o||T(n)>1;r&&((e,t,o,l)=>{const n=1===t.length?f:l;P(t,(t=>{const r=Se(V.fromDom(t),"td,th"),a=Do(e,t);((e,t,o)=>{o("class")&&"mce-no-match"!==t.class&&e.setAttrib("class",t.class),o("height")&&e.setStyle("height",fe(t.height))})(a,o,n),ht(e)&&((e,t,o)=>{o("backgroundcolor")&&e.setStyle("background-color",t.backgroundcolor),o("bordercolor")&&e.setStyle("border-color",t.bordercolor),o("borderstyle")&&e.setStyle("border-style",t.borderstyle)})(a,o,n),l("height")&&P(r,(t=>{e.dom.setStyle(t.dom,"height",null)})),l("align")&&ot(e,t,o.align)}))})(e,t,l,b(A,n)),o&&((e,t)=>{e.execCommand("mceTableRowType",!1,{type:t.type,no_events:!0})})(e,l),$e(V.fromDom(t[0])).each((t=>lt(e,t.dom,{structure:o,style:r})))}})(e,t,o,n),e.focus()}))},Zo=e=>{const t=to(ye(e),Qt.selected);if(0===t.length)return;const o=M(t,(t=>((e,t,o)=>{const l=e.dom;return{height:l.getStyle(t,"height")||l.getAttrib(t,"height"),class:l.getAttrib(t,"class",""),type:Uo(t),align:Wo(e,t),...o?Ho(t):{}}})(e,t.dom,ht(e)))),l=Vo(o),n={type:"tabpanel",tabs:[{title:"General",name:"general",items:Xo(e)},_o(e,"row")]},r={type:"panel",items:[{type:"grid",columns:2,items:Xo(e)}]};e.windowManager.open({title:"Row Properties",size:"normal",body:ht(e)?n:r,buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:l,onSubmit:b(Yo,e,M(t,(e=>e.dom)),l)})},el=(e,t,o)=>{const l=o?[{type:"input",name:"cols",label:"Cols",inputMode:"numeric"},{type:"input",name:"rows",label:"Rows",inputMode:"numeric"}]:[],n=yt(e)?[{type:"input",name:"cellspacing",label:"Cell spacing",inputMode:"numeric"},{type:"input",name:"cellpadding",label:"Cell padding",inputMode:"numeric"},{type:"input",name:"border",label:"Border width"},{type:"label",label:"Caption",items:[{type:"checkbox",name:"caption",label:"Show caption"}]}]:[],r=t.length>0?[{name:"class",type:"listbox",label:"Class",items:t}]:[];return l.concat([{type:"input",name:"width",label:"Width"},{type:"input",name:"height",label:"Height"}]).concat(n).concat([{type:"listbox",name:"align",label:"Alignment",items:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]).concat(r)},tl=(e,t,o,n)=>{if("TD"===t.tagName||"TH"===t.tagName)l(o)&&s(n)?e.setStyle(t,o,n):e.setStyles(t,o);else if(t.children)for(let l=0;l<t.children.length;l++)tl(e,t.children[l],o,n)},ol=(e,t,o,l)=>{const n=e.dom,r=l.getData(),s=v(r,((e,t)=>o[t]!==e));l.close(),e.undoManager.transact((()=>{if(!t){const o=Me(r.cols).getOr(1),l=Me(r.rows).getOr(1);e.execCommand("mceInsertTable",!1,{rows:l,columns:o}),t=Zt(ye(e),he(e)).bind((t=>$e(t,he(e)))).map((e=>e.dom)).getOrDie()}if(T(s)>0){const o={border:A(s,"border"),bordercolor:A(s,"bordercolor"),cellpadding:A(s,"cellpadding")};((e,t,o,l)=>{const n=e.dom,r={},s={},c=St(e),i=ft(e),m=0===parseFloat(o.border);if(a(o.class)||"mce-no-match"===o.class||(r.class=o.class),s.height=fe(o.height),c?s.width=fe(o.width):n.getAttrib(t,"width")&&(r.width=(e=>e?e.replace(/px$/,""):"")(o.width)),c?(m?(r.border=0,s["border-width"]=""):(s["border-width"]=fe(o.border),r.border=1),s["border-spacing"]=fe(o.cellspacing)):(r.border=m?0:o.border,r.cellpadding=o.cellpadding,r.cellspacing=o.cellspacing),c&&t.children){const e={};if(m?e["border-width"]="":l.border&&(e["border-width"]=fe(o.border)),l.cellpadding&&(e.padding=fe(o.cellpadding)),i&&l.bordercolor&&(e["border-color"]=o.bordercolor),!(e=>{for(const t in e)if(S.call(e,t))return!1;return!0})(e))for(let o=0;o<t.children.length;o++)tl(n,t.children[o],e)}if(i){const e=o;s["background-color"]=e.backgroundcolor,s["border-color"]=e.bordercolor,s["border-style"]=e.borderstyle}n.setStyles(t,{...Dt(e),...s}),n.setAttribs(t,{...Nt(e),...r})})(e,t,r,o);const l=n.select("caption",t)[0];(l&&!r.caption||!l&&r.caption)&&e.execCommand("mceTableToggleCaption"),ot(e,t,r.align)}if(e.focus(),e.addVisual(),T(s)>0){const o=A(s,"caption"),l=!o||T(s)>1;lt(e,t,{structure:o,style:l})}}))},ll=(e,t)=>{const o=e.dom;let l,n=((e,t)=>{const o=Dt(e),l=Nt(e),n=t?{borderstyle:x(o,"border-style").getOr(""),bordercolor:jo(x(o,"border-color").getOr("")),backgroundcolor:jo(x(o,"background-color").getOr(""))}:{};return{height:"",width:"100%",cellspacing:"",cellpadding:"",caption:!1,class:"",align:"",border:"",...o,...l,...n,...(()=>{const t=o["border-width"];return St(e)&&t?{border:t}:x(l,"border").fold((()=>({})),(e=>({border:e})))})(),...{...x(o,"border-spacing").or(x(l,"cellspacing")).fold((()=>({})),(e=>({cellspacing:e}))),...x(o,"border-padding").or(x(l,"cellpadding")).fold((()=>({})),(e=>({cellpadding:e})))}}})(e,ft(e));t?(n.cols="1",n.rows="1",ft(e)&&(n.borderstyle="",n.bordercolor="",n.backgroundcolor="")):(l=o.getParent(e.selection.getStart(),"table",e.getBody()),l?n=((e,t,o)=>{const l=e.dom,n=St(e)?l.getStyle(t,"border-spacing")||l.getAttrib(t,"cellspacing"):l.getAttrib(t,"cellspacing")||l.getStyle(t,"border-spacing"),r=St(e)?tt(l,t,"padding")||l.getAttrib(t,"cellpadding"):l.getAttrib(t,"cellpadding")||tt(l,t,"padding");return{width:l.getStyle(t,"width")||l.getAttrib(t,"width"),height:l.getStyle(t,"height")||l.getAttrib(t,"height"),cellspacing:null!=n?n:"",cellpadding:null!=r?r:"",border:((t,o)=>{const l=Be(V.fromDom(o),"border-width");return St(e)&&l.isSome()?l.getOr(""):t.getAttrib(o,"border")||tt(e.dom,o,"border-width")||tt(e.dom,o,"border")||""})(l,t),caption:!!l.select("caption",t)[0],class:l.getAttrib(t,"class",""),align:Wo(e,t),...o?Ho(t):{}}})(e,l,ft(e)):ft(e)&&(n.borderstyle="",n.bordercolor="",n.backgroundcolor=""));const r=yo(Tt(e));r.isSome()&&n.class&&(n.class=n.class.replace(/\s*mce\-item\-table\s*/g,""));const a={type:"grid",columns:2,items:el(e,r.getOr([]),t)},s=ft(e)?{type:"tabpanel",tabs:[{title:"General",name:"general",items:[a]},_o(e,"table")]}:{type:"panel",items:[a]};e.windowManager.open({title:"Table Properties",size:"normal",body:s,onSubmit:b(ol,e,l,n),buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:n})},nl=e=>{C({mceTableProps:b(ll,e,!1),mceTableRowProps:b(Zo,e),mceTableCellProps:b(Jo,e),mceInsertTableDialog:b(ll,e,!0)},((t,o)=>e.addCommand(o,(()=>{return o=t,void((e=>{return(t=e,o=ee("table"),ce(((e,t)=>t(e)),ie,t,o,void 0)).forall(be);var t,o})(ye(e))&&o());var o}))))},rl=u,al=e=>{const t=(e,t)=>xe(e,t).exists((e=>parseInt(e,10)>1));return e.length>0&&q(e,(e=>t(e,"rowspan")||t(e,"colspan")))?y.some(e):y.none()},sl=(e,t,o)=>{return t.length<=1?y.none():(l=e,n=o.firstSelectedSelector,r=o.lastSelectedSelector,zt(l,n,r).bind((e=>{const t=e=>z(l,e),o="thead,tfoot,tbody,table",n=me(e.first,o,t),r=me(e.last,o,t);return n.bind((t=>r.bind((o=>z(t,o)?((e,t,o)=>{const l=Pt(e);return Mt(l,t,o)})(e.table,e.first,e.last):y.none()))))}))).map((e=>({bounds:e,cells:t})));var l,n,r},cl=e=>{const t=bo(y.none()),o=bo([]);let l=y.none();const n=ee("caption"),r=e=>l.forall((t=>!t[e])),a=()=>Yt(ye(e),he(e)).bind((t=>{return o=Oe($e(t),Yt((e=>V.fromDom(e.selection.getEnd()))(e),he(e)).bind($e),((o,l)=>z(o,l)?n(t)?y.some((e=>({element:e,mergable:y.none(),unmergable:y.none(),selection:[e]}))(t)):y.some(((e,t,o)=>({element:o,mergable:sl(t,e,Qt),unmergable:al(e),selection:rl(e)}))(eo(e),o,t)):y.none())),o.bind(u);var o})),s=e=>$e(e.element).map((t=>{const o=Qe(t),l=Eo(o,e).getOr([]),n=E(l,((e,t)=>(t.isLocked&&(e.onAny=!0,0===t.column?e.onFirst=!0:t.column+t.colspan>=o.grid.columns&&(e.onLast=!0)),e)),{onAny:!1,onFirst:!1,onLast:!1});return{mergeable:Fo(o,e).isSome(),unmergeable:qo(o,e).isSome(),locked:n}})),c=()=>{t.set((e=>{let t,o=!1;return(...l)=>(o||(o=!0,t=e.apply(null,l)),t)})(a)()),l=t.get().bind(s),P(o.get(),g)},i=e=>(e(),o.set(o.get().concat([e])),()=>{o.set(k(o.get(),(t=>t!==e)))}),m=(o,l)=>i((()=>t.get().fold((()=>{o.setEnabled(!1)}),(t=>{o.setEnabled(!l(t)&&e.selection.isEditable())})))),d=(o,l,n)=>i((()=>t.get().fold((()=>{o.setEnabled(!1),o.setActive(!1)}),(t=>{o.setEnabled(!l(t)&&e.selection.isEditable()),o.setActive(n(t))})))),p=e=>l.exists((t=>t.locked[e])),b=(t,o)=>l=>d(l,(e=>n(e.element)),(()=>e.queryCommandValue(t)===o)),f=b("mceTableRowType","header"),w=b("mceTableColType","th");return e.on("NodeChange ExecCommand TableSelectorChange",c),{onSetupTable:e=>m(e,(e=>!1)),onSetupCellOrRow:e=>m(e,(e=>n(e.element))),onSetupColumn:e=>t=>m(t,(t=>n(t.element)||p(e))),onSetupPasteable:e=>t=>m(t,(t=>n(t.element)||e().isNone())),onSetupPasteableColumn:(e,t)=>o=>m(o,(o=>n(o.element)||e().isNone()||p(t))),onSetupMergeable:e=>m(e,(e=>r("mergeable"))),onSetupUnmergeable:e=>m(e,(e=>r("unmergeable"))),resetTargets:c,onSetupTableWithCaption:t=>d(t,h,(t=>$e(t.element,he(e)).exists((e=>de(e,"caption").isSome())))),onSetupTableRowHeaders:f,onSetupTableColumnHeaders:w,targets:t.get}};var il=tinymce.util.Tools.resolve("tinymce.FakeClipboard");const ml="x-tinymce/dom-table-",dl=ml+"rows",ul=ml+"columns",pl=e=>{var t;const o=null!==(t=il.read())&&void 0!==t?t:[];return j(o,(t=>y.from(t.getType(e))))},bl=()=>pl(dl),gl=()=>pl(ul),hl=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}},fl=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("table",(e=>{const t=cl(e);(e=>{const t=e.options.register;t("table_border_widths",{processor:"object[]",default:st}),t("table_border_styles",{processor:"object[]",default:ct}),t("table_cell_advtab",{processor:"boolean",default:!0}),t("table_row_advtab",{processor:"boolean",default:!0}),t("table_advtab",{processor:"boolean",default:!0}),t("table_appearance_options",{processor:"boolean",default:!0}),t("table_grid",{processor:"boolean",default:!at.deviceType.isTouch()}),t("table_cell_class_list",{processor:"object[]",default:[]}),t("table_row_class_list",{processor:"object[]",default:[]}),t("table_class_list",{processor:"object[]",default:[]}),t("table_toolbar",{processor:"string",default:"tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol"}),t("table_background_color_map",{processor:"object[]",default:[]}),t("table_border_color_map",{processor:"object[]",default:[]})})(e),nl(e),((e,t)=>{const o=t=>()=>e.execCommand(t),l=(t,l)=>!!e.queryCommandSupported(l.command)&&(e.ui.registry.addMenuItem(t,{...l,onAction:c(l.onAction)?l.onAction:o(l.command)}),!0),n=(t,l)=>{e.queryCommandSupported(l.command)&&e.ui.registry.addToggleMenuItem(t,{...l,onAction:c(l.onAction)?l.onAction:o(l.command)})},r=t=>{e.execCommand("mceInsertTable",!1,{rows:t.numRows,columns:t.numColumns})},a=[l("tableinsertrowbefore",{text:"Insert row before",icon:"table-insert-row-above",command:"mceTableInsertRowBefore",onSetup:t.onSetupCellOrRow}),l("tableinsertrowafter",{text:"Insert row after",icon:"table-insert-row-after",command:"mceTableInsertRowAfter",onSetup:t.onSetupCellOrRow}),l("tabledeleterow",{text:"Delete row",icon:"table-delete-row",command:"mceTableDeleteRow",onSetup:t.onSetupCellOrRow}),l("tablerowprops",{text:"Row properties",icon:"table-row-properties",command:"mceTableRowProps",onSetup:t.onSetupCellOrRow}),l("tablecutrow",{text:"Cut row",icon:"cut-row",command:"mceTableCutRow",onSetup:t.onSetupCellOrRow}),l("tablecopyrow",{text:"Copy row",icon:"duplicate-row",command:"mceTableCopyRow",onSetup:t.onSetupCellOrRow}),l("tablepasterowbefore",{text:"Paste row before",icon:"paste-row-before",command:"mceTablePasteRowBefore",onSetup:t.onSetupPasteable(bl)}),l("tablepasterowafter",{text:"Paste row after",icon:"paste-row-after",command:"mceTablePasteRowAfter",onSetup:t.onSetupPasteable(bl)})],s=[l("tableinsertcolumnbefore",{text:"Insert column before",icon:"table-insert-column-before",command:"mceTableInsertColBefore",onSetup:t.onSetupColumn("onFirst")}),l("tableinsertcolumnafter",{text:"Insert column after",icon:"table-insert-column-after",command:"mceTableInsertColAfter",onSetup:t.onSetupColumn("onLast")}),l("tabledeletecolumn",{text:"Delete column",icon:"table-delete-column",command:"mceTableDeleteCol",onSetup:t.onSetupColumn("onAny")}),l("tablecutcolumn",{text:"Cut column",icon:"cut-column",command:"mceTableCutCol",onSetup:t.onSetupColumn("onAny")}),l("tablecopycolumn",{text:"Copy column",icon:"duplicate-column",command:"mceTableCopyCol",onSetup:t.onSetupColumn("onAny")}),l("tablepastecolumnbefore",{text:"Paste column before",icon:"paste-column-before",command:"mceTablePasteColBefore",onSetup:t.onSetupPasteableColumn(gl,"onFirst")}),l("tablepastecolumnafter",{text:"Paste column after",icon:"paste-column-after",command:"mceTablePasteColAfter",onSetup:t.onSetupPasteableColumn(gl,"onLast")})],i=[l("tablecellprops",{text:"Cell properties",icon:"table-cell-properties",command:"mceTableCellProps",onSetup:t.onSetupCellOrRow}),l("tablemergecells",{text:"Merge cells",icon:"table-merge-cells",command:"mceTableMergeCells",onSetup:t.onSetupMergeable}),l("tablesplitcells",{text:"Split cell",icon:"table-split-cells",command:"mceTableSplitCells",onSetup:t.onSetupUnmergeable})];wt(e)?e.ui.registry.addNestedMenuItem("inserttable",{text:"Table",icon:"table",getSubmenuItems:()=>[{type:"fancymenuitem",fancytype:"inserttable",onAction:r}],onSetup:fl(e)}):e.ui.registry.addMenuItem("inserttable",{text:"Table",icon:"table",onAction:o("mceInsertTableDialog"),onSetup:fl(e)}),e.ui.registry.addMenuItem("inserttabledialog",{text:"Insert table",icon:"table",onAction:o("mceInsertTableDialog"),onSetup:fl(e)}),l("tableprops",{text:"Table properties",onSetup:t.onSetupTable,command:"mceTableProps"}),l("deletetable",{text:"Delete table",icon:"table-delete-table",onSetup:t.onSetupTable,command:"mceTableDelete"}),D(a,!0)&&e.ui.registry.addNestedMenuItem("row",{type:"nestedmenuitem",text:"Row",getSubmenuItems:d("tableinsertrowbefore tableinsertrowafter tabledeleterow tablerowprops | tablecutrow tablecopyrow tablepasterowbefore tablepasterowafter")}),D(s,!0)&&e.ui.registry.addNestedMenuItem("column",{type:"nestedmenuitem",text:"Column",getSubmenuItems:d("tableinsertcolumnbefore tableinsertcolumnafter tabledeletecolumn | tablecutcolumn tablecopycolumn tablepastecolumnbefore tablepastecolumnafter")}),D(i,!0)&&e.ui.registry.addNestedMenuItem("cell",{type:"nestedmenuitem",text:"Cell",getSubmenuItems:d("tablecellprops tablemergecells tablesplitcells")}),e.ui.registry.addContextMenu("table",{update:()=>(t.resetTargets(),t.targets().fold(d(""),(e=>"caption"===G(e.element)?"tableprops deletetable":"cell row column | advtablesort | tableprops deletetable")))});const m=Co(Tt(e));0!==m.length&&e.queryCommandSupported("mceTableToggleClass")&&e.ui.registry.addNestedMenuItem("tableclass",{icon:"table-classes",text:"Table styles",getSubmenuItems:()=>wo(e,m,"tableclass",(t=>e.execCommand("mceTableToggleClass",!1,t))),onSetup:t.onSetupTable});const u=Co(Ct(e));0!==u.length&&e.queryCommandSupported("mceTableCellToggleClass")&&e.ui.registry.addNestedMenuItem("tablecellclass",{icon:"table-cell-classes",text:"Cell styles",getSubmenuItems:()=>wo(e,u,"tablecellclass",(t=>e.execCommand("mceTableCellToggleClass",!1,t))),onSetup:t.onSetupCellOrRow}),e.queryCommandSupported("mceTableApplyCellStyle")&&(e.ui.registry.addNestedMenuItem("tablecellvalign",{icon:"vertical-align",text:"Vertical align",getSubmenuItems:()=>wo(e,oo,"tablecellverticalalign",So(e,"vertical-align")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addNestedMenuItem("tablecellborderwidth",{icon:"border-width",text:"Border width",getSubmenuItems:()=>wo(e,pt(e),"tablecellborderwidth",So(e,"border-width")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addNestedMenuItem("tablecellborderstyle",{icon:"border-style",text:"Border style",getSubmenuItems:()=>wo(e,bt(e),"tablecellborderstyle",So(e,"border-style")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addNestedMenuItem("tablecellbackgroundcolor",{icon:"cell-background-color",text:"Background color",getSubmenuItems:()=>To(e,At(e),"background-color"),onSetup:t.onSetupCellOrRow}),e.ui.registry.addNestedMenuItem("tablecellbordercolor",{icon:"cell-border-color",text:"Border color",getSubmenuItems:()=>To(e,Rt(e),"border-color"),onSetup:t.onSetupCellOrRow})),n("tablecaption",{icon:"table-caption",text:"Table caption",command:"mceTableToggleCaption",onSetup:t.onSetupTableWithCaption}),n("tablerowheader",{text:"Row header",icon:"table-top-header",command:"mceTableRowType",onAction:xo(e),onSetup:t.onSetupTableRowHeaders}),n("tablecolheader",{text:"Column header",icon:"table-left-header",command:"mceTableColType",onAction:Ao(e),onSetup:t.onSetupTableRowHeaders})})(e,t),((e,t)=>{e.ui.registry.addMenuButton("table",{tooltip:"Table",icon:"table",onSetup:hl(e),fetch:e=>e("inserttable | cell row column | advtablesort | tableprops deletetable")});const o=t=>()=>e.execCommand(t),l=(t,l)=>{e.queryCommandSupported(l.command)&&e.ui.registry.addButton(t,{...l,onAction:c(l.onAction)?l.onAction:o(l.command)})},n=(t,l)=>{e.queryCommandSupported(l.command)&&e.ui.registry.addToggleButton(t,{...l,onAction:c(l.onAction)?l.onAction:o(l.command)})};l("tableprops",{tooltip:"Table properties",command:"mceTableProps",icon:"table",onSetup:t.onSetupTable}),l("tabledelete",{tooltip:"Delete table",command:"mceTableDelete",icon:"table-delete-table",onSetup:t.onSetupTable}),l("tablecellprops",{tooltip:"Cell properties",command:"mceTableCellProps",icon:"table-cell-properties",onSetup:t.onSetupCellOrRow}),l("tablemergecells",{tooltip:"Merge cells",command:"mceTableMergeCells",icon:"table-merge-cells",onSetup:t.onSetupMergeable}),l("tablesplitcells",{tooltip:"Split cell",command:"mceTableSplitCells",icon:"table-split-cells",onSetup:t.onSetupUnmergeable}),l("tableinsertrowbefore",{tooltip:"Insert row before",command:"mceTableInsertRowBefore",icon:"table-insert-row-above",onSetup:t.onSetupCellOrRow}),l("tableinsertrowafter",{tooltip:"Insert row after",command:"mceTableInsertRowAfter",icon:"table-insert-row-after",onSetup:t.onSetupCellOrRow}),l("tabledeleterow",{tooltip:"Delete row",command:"mceTableDeleteRow",icon:"table-delete-row",onSetup:t.onSetupCellOrRow}),l("tablerowprops",{tooltip:"Row properties",command:"mceTableRowProps",icon:"table-row-properties",onSetup:t.onSetupCellOrRow}),l("tableinsertcolbefore",{tooltip:"Insert column before",command:"mceTableInsertColBefore",icon:"table-insert-column-before",onSetup:t.onSetupColumn("onFirst")}),l("tableinsertcolafter",{tooltip:"Insert column after",command:"mceTableInsertColAfter",icon:"table-insert-column-after",onSetup:t.onSetupColumn("onLast")}),l("tabledeletecol",{tooltip:"Delete column",command:"mceTableDeleteCol",icon:"table-delete-column",onSetup:t.onSetupColumn("onAny")}),l("tablecutrow",{tooltip:"Cut row",command:"mceTableCutRow",icon:"cut-row",onSetup:t.onSetupCellOrRow}),l("tablecopyrow",{tooltip:"Copy row",command:"mceTableCopyRow",icon:"duplicate-row",onSetup:t.onSetupCellOrRow}),l("tablepasterowbefore",{tooltip:"Paste row before",command:"mceTablePasteRowBefore",icon:"paste-row-before",onSetup:t.onSetupPasteable(bl)}),l("tablepasterowafter",{tooltip:"Paste row after",command:"mceTablePasteRowAfter",icon:"paste-row-after",onSetup:t.onSetupPasteable(bl)}),l("tablecutcol",{tooltip:"Cut column",command:"mceTableCutCol",icon:"cut-column",onSetup:t.onSetupColumn("onAny")}),l("tablecopycol",{tooltip:"Copy column",command:"mceTableCopyCol",icon:"duplicate-column",onSetup:t.onSetupColumn("onAny")}),l("tablepastecolbefore",{tooltip:"Paste column before",command:"mceTablePasteColBefore",icon:"paste-column-before",onSetup:t.onSetupPasteableColumn(gl,"onFirst")}),l("tablepastecolafter",{tooltip:"Paste column after",command:"mceTablePasteColAfter",icon:"paste-column-after",onSetup:t.onSetupPasteableColumn(gl,"onLast")}),l("tableinsertdialog",{tooltip:"Insert table",command:"mceInsertTableDialog",icon:"table",onSetup:hl(e)});const r=Co(Tt(e));0!==r.length&&e.queryCommandSupported("mceTableToggleClass")&&e.ui.registry.addMenuButton("tableclass",{icon:"table-classes",tooltip:"Table styles",fetch:vo(e,r,"tableclass",(t=>e.execCommand("mceTableToggleClass",!1,t))),onSetup:t.onSetupTable});const a=Co(Ct(e));0!==a.length&&e.queryCommandSupported("mceTableCellToggleClass")&&e.ui.registry.addMenuButton("tablecellclass",{icon:"table-cell-classes",tooltip:"Cell styles",fetch:vo(e,a,"tablecellclass",(t=>e.execCommand("mceTableCellToggleClass",!1,t))),onSetup:t.onSetupCellOrRow}),e.queryCommandSupported("mceTableApplyCellStyle")&&(e.ui.registry.addMenuButton("tablecellvalign",{icon:"vertical-align",tooltip:"Vertical align",fetch:vo(e,oo,"tablecellverticalalign",So(e,"vertical-align")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addMenuButton("tablecellborderwidth",{icon:"border-width",tooltip:"Border width",fetch:vo(e,pt(e),"tablecellborderwidth",So(e,"border-width")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addMenuButton("tablecellborderstyle",{icon:"border-style",tooltip:"Border style",fetch:vo(e,bt(e),"tablecellborderstyle",So(e,"border-style")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addMenuButton("tablecellbackgroundcolor",{icon:"cell-background-color",tooltip:"Background color",fetch:t=>t(To(e,At(e),"background-color")),onSetup:t.onSetupCellOrRow}),e.ui.registry.addMenuButton("tablecellbordercolor",{icon:"cell-border-color",tooltip:"Border color",fetch:t=>t(To(e,Rt(e),"border-color")),onSetup:t.onSetupCellOrRow})),n("tablecaption",{tooltip:"Table caption",icon:"table-caption",command:"mceTableToggleCaption",onSetup:t.onSetupTableWithCaption}),n("tablerowheader",{tooltip:"Row header",icon:"table-top-header",command:"mceTableRowType",onAction:xo(e),onSetup:t.onSetupTableRowHeaders}),n("tablecolheader",{tooltip:"Column header",icon:"table-left-header",command:"mceTableColType",onAction:Ao(e),onSetup:t.onSetupTableColumnHeaders})})(e,t),(e=>{const t=xt(e);t.length>0&&e.ui.registry.addContextToolbar("table",{predicate:t=>e.dom.is(t,"table")&&e.getBody().contains(t)&&e.dom.isEditable(t.parentNode),items:t,scope:"node",position:"node"})})(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/visualblocks/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/visualblocks/plugin.min.js
new file mode 100644
index 0000000..6ec4c40
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/visualblocks/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const s=(t,s,o)=>{t.dom.toggleClass(t.getBody(),"mce-visualblocks"),o.set(!o.get()),((t,s)=>{t.dispatch("VisualBlocks",{state:s})})(t,o.get())},o=("visualblocks_default_state",t=>t.options.get("visualblocks_default_state"));const e=(t,s)=>o=>{o.setActive(s.get());const e=t=>o.setActive(t.state);return t.on("VisualBlocks",e),()=>t.off("VisualBlocks",e)};t.add("visualblocks",((t,l)=>{(t=>{(0,t.options.register)("visualblocks_default_state",{processor:"boolean",default:!1})})(t);const a=(t=>{let s=!1;return{get:()=>s,set:t=>{s=t}}})();((t,o,e)=>{t.addCommand("mceVisualBlocks",(()=>{s(t,0,e)}))})(t,0,a),((t,s)=>{const o=()=>t.execCommand("mceVisualBlocks");t.ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:o,onSetup:e(t,s)}),t.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:o,onSetup:e(t,s)})})(t,a),((t,e,l)=>{t.on("PreviewFormats AfterPreviewFormats",(s=>{l.get()&&t.dom.toggleClass(t.getBody(),"mce-visualblocks","afterpreviewformats"===s.type)})),t.on("init",(()=>{o(t)&&s(t,0,l)}))})(t,0,a)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/visualchars/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/visualchars/plugin.min.js
new file mode 100644
index 0000000..64fbf68
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/visualchars/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(n=o=t,(r=String).prototype.isPrototypeOf(n)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===r.name)?"string":e;var n,o,r,s})(e)===t,n=t=>e=>typeof e===t,o=e("string"),r=e("object"),s=(null,t=>null===t);const a=n("boolean"),l=n("number");class i{constructor(t,e){this.tag=t,this.value=e}static some(t){return new i(!0,t)}static none(){return i.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?i.some(t(this.value)):i.none()}bind(t){return this.tag?t(this.value):i.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:i.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return null==t?i.none():i.some(t)}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}i.singletonNone=new i(!1);const u=(t,e)=>{for(let n=0,o=t.length;n<o;n++)e(t[n],n)},c=Object.keys,d=(t,e)=>{const n=c(t);for(let o=0,r=n.length;o<r;o++){const r=n[o];e(t[r],r)}},h="undefined"!=typeof window?window:Function("return this;")(),m=(t,e)=>((t,e)=>{let n=null!=e?e:h;for(let e=0;e<t.length&&null!=n;++e)n=n[t[e]];return n})(t.split("."),e),g=Object.getPrototypeOf,v=t=>{const e=m("ownerDocument.defaultView",t);return r(t)&&((t=>((t,e)=>{const n=((t,e)=>m(t,e))(t,e);if(null==n)throw new Error(t+" not available on this browser");return n})("HTMLElement",t))(e).prototype.isPrototypeOf(t)||/^HTML\w*Element$/.test(g(t).constructor.name))},f=t=>t.dom.nodeValue,p=t=>e=>(t=>t.dom.nodeType)(e)===t,b=t=>w(t)&&v(t.dom),w=p(1),y=p(3),A=(t,e,n)=>{((t,e,n)=>{if(!(o(n)||a(n)||l(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)},k=(t,e)=>{t.dom.removeAttribute(e)},N=(t,e)=>{const n=((t,e)=>{const n=t.dom.getAttribute(e);return null===n?void 0:n})(t,e);return void 0===n||""===n?[]:n.split(" ")},T=t=>void 0!==t.dom.classList,C=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},E=C,O={"\xa0":"nbsp","\xad":"shy"},L=(t,e)=>{let n="";return d(t,((t,e)=>{n+=e})),new RegExp("["+n+"]",e?"g":"")},V=L(O),j=L(O,!0),B=(t=>{let e="";return d(t,(t=>{e&&(e+=","),e+="span.mce-"+t})),e})(O),S="mce-nbsp",_=t=>t.dom.contentEditable,x=t=>'<span data-mce-bogus="1" class="mce-'+O[t]+'">'+t+"</span>",M=t=>"span"===t.nodeName.toLowerCase()&&t.classList.contains("mce-nbsp-wrap"),P=t=>{const e=f(t);return y(t)&&o(e)&&V.test(e)},D=(t,e,n)=>{let o=[];const r=((t,e)=>{const n=t.length,o=new Array(n);for(let r=0;r<n;r++){const n=t[r];o[r]=e(n,r)}return o})(t.dom.childNodes,E);return u(r,(t=>{var r;n&&(M((r=t).dom)||!(t=>b(t)&&"false"===_(t))(r))&&e(t)&&(o=o.concat([t])),o=o.concat(D(t,e,((t,e)=>{if(b(t)&&!M(t.dom)){const e=_(t);if("true"===e)return!0;if("false"===e)return!1}return e})(t,n)))})),o},H=(t,e)=>{const n=t.dom,o=D(E(e),P,t.dom.isEditable(e));u(o,(e=>{var o;const r=e.dom.parentNode;if(M(r))s=E(r),a=S,T(s)?s.dom.classList.add(a):((t,e)=>{((t,e,n)=>{const o=N(t,e).concat([n]);A(t,e,o.join(" "))})(t,"class",e)})(s,a);else{const r=n.encode(null!==(o=f(e))&&void 0!==o?o:"").replace(j,x),s=n.create("div",{},r);let a;for(;a=s.lastChild;)n.insertAfter(a,e.dom);t.dom.remove(e.dom)}var s,a}))},I=(t,e)=>{const n=t.dom.select(B,e);u(n,(e=>{var n,o;M(e)?(n=E(e),o=S,T(n)?n.dom.classList.remove(o):((t,e)=>{((t,e,n)=>{const o=((t,e)=>{const o=[];for(let e=0,r=t.length;e<r;e++){const r=t[e];r!==n&&o.push(r)}return o})(N(t,e));o.length>0?A(t,e,o.join(" ")):k(t,e)})(t,"class",e)})(n,o),(t=>{const e=T(t)?t.dom.classList:(t=>N(t,"class"))(t);0===e.length&&k(t,"class")})(n)):t.dom.remove(e,!0)}))},$=t=>{const e=t.getBody(),n=t.selection.getBookmark();let o=((t,e)=>{for(;t.parentNode;){if(t.parentNode===e)return e;t=t.parentNode}})(t.selection.getNode(),e);o=void 0!==o?o:e,I(t,o),H(t,o),t.selection.moveToBookmark(n)},F=(t,e)=>{((t,e)=>{t.dispatch("VisualChars",{state:e})})(t,e.get());const n=t.getBody();!0===e.get()?H(t,n):I(t,n)},K=("visualchars_default_state",t=>t.options.get("visualchars_default_state"));const R=(t,e)=>{const n=((t,e)=>{let n=null;return{cancel:()=>{s(n)||(clearTimeout(n),n=null)},throttle:(...e)=>{s(n)&&(n=setTimeout((()=>{n=null,t.apply(null,e)}),300))}}})((()=>{$(t)}));t.on("keydown",(o=>{!0===e.get()&&(13===o.keyCode?$(t):n.throttle())})),t.on("remove",n.cancel)},U=(t,e)=>n=>{n.setActive(e.get());const o=t=>n.setActive(t.state);return t.on("VisualChars",o),()=>t.off("VisualChars",o)};t.add("visualchars",(t=>{(t=>{(0,t.options.register)("visualchars_default_state",{processor:"boolean",default:!1})})(t);const e=(t=>{let e=t;return{get:()=>e,set:t=>{e=t}}})(K(t));return((t,e)=>{t.addCommand("mceVisualChars",(()=>{((t,e)=>{e.set(!e.get());const n=t.selection.getBookmark();F(t,e),t.selection.moveToBookmark(n)})(t,e)}))})(t,e),((t,e)=>{const n=()=>t.execCommand("mceVisualChars");t.ui.registry.addToggleButton("visualchars",{tooltip:"Show invisible characters",icon:"visualchars",onAction:n,onSetup:U(t,e)}),t.ui.registry.addToggleMenuItem("visualchars",{text:"Show invisible characters",icon:"visualchars",onAction:n,onSetup:U(t,e)})})(t,e),R(t,e),((t,e)=>{t.on("init",(()=>{F(t,e)}))})(t,e),(t=>({isEnabled:()=>t.get()}))(e)}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/plugins/wordcount/plugin.min.js b/eims-ui/apps/web-antd/public/tinymce/plugins/wordcount/plugin.min.js
new file mode 100644
index 0000000..044df36
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/plugins/wordcount/plugin.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(null,t=>null===t);const n=t=>t,o=(t,e)=>{const n=t.length,o=new Array(n);for(let r=0;r<n;r++){const n=t[r];o[r]=e(n,r)}return o},r="[-'\\.\u2018\u2019\u2024\ufe52\uff07\uff0e]",c="[:\xb7\xb7\u05f4\u2027\ufe13\ufe55\uff1a]",u="[\xb1+*/,;;\u0589\u060c\u060d\u066c\u07f8\u2044\ufe10\ufe14\ufe50\ufe54\uff0c\uff1b]",s="[0-9\u0660-\u0669\u066b\u06f0-\u06f9\u07c0-\u07c9\u0966-\u096f\u09e6-\u09ef\u0a66-\u0a6f\u0ae6-\u0aef\u0b66-\u0b6f\u0be6-\u0bef\u0c66-\u0c6f\u0ce6-\u0cef\u0d66-\u0d6f\u0e50-\u0e59\u0ed0-\u0ed9\u0f20-\u0f29\u1040-\u1049\u1090-\u1099\u17e0-\u17e9\u1810-\u1819\u1946-\u194f\u19d0-\u19d9\u1a80-\u1a89\u1a90-\u1a99\u1b50-\u1b59\u1bb0-\u1bb9\u1c40-\u1c49\u1c50-\u1c59\ua620-\ua629\ua8d0-\ua8d9\ua900-\ua909\ua9d0-\ua9d9\uaa50-\uaa59\uabf0-\uabf9]",a="\\r",l="\\n",i="[\v\f\x85\u2028\u2029]",d="[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f\u109a-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b6-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u192b\u1930-\u193b\u19b0-\u19c0\u19c8\u19c9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f\u1b00-\u1b04\u1b34-\u1b44\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1baa\u1be6-\u1bf3\u1c24-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe3-\uabea\uabec\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]",g="[\xad\u0600-\u0603\u06dd\u070f\u17b4\u17b5\u200e\u200f\u202a-\u202e\u2060-\u2064\u206a-\u206f\ufeff\ufff9-\ufffb]",p="[\u3031-\u3035\u309b\u309c\u30a0-\u30fa\u30fc-\u30ff\u31f0-\u31ff\u32d0-\u32fe\u3300-\u3357\uff66-\uff9d]",h="[=_\u203f\u2040\u2054\ufe33\ufe34\ufe4d-\ufe4f\uff3f\u2200-\u22ff<>]",C="[~\u2116|!-*+-\\/:;?@\\[-`{}\xa1\xab\xb7\xbb\xbf;\xb7\u055a-\u055f\u0589\u058a\u05be\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f3a-\u0f3d\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1361-\u1368\u1400\u166d\u166e\u169b\u169c\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cd3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205e\u207d\u207e\u208d\u208e\u3008\u3009\u2768-\u2775\u27c5\u27c6\u27e6-\u27ef\u2983-\u2998\u29d8-\u29db\u29fc\u29fd\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e2e\u2e30\u2e31\u3001-\u3003\u3008-\u3011\u3014-\u301f\u3030\u303d\u30a0\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uabeb\ufd3e\ufd3f\ufe10-\ufe19\ufe30-\ufe52\ufe54-\ufe61\ufe63\ufe68\ufe6a\ufe6b\uff01-\uff03\uff05-\uff0a\uff0c-\uff0f\uff1a\uff1b\uff1f\uff20\uff3b-\uff3d\uff3f\uff5b\uff5d\uff5f-\uff65]",y=10,m=[new RegExp("[A-Za-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f3\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u10a0-\u10c5\u10d0-\u10fa\u10fc\u1100-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1a00-\u1a16\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bc0-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u24b6-\u24e9\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2d00-\u2d25\u2d30-\u2d65\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005\u303b\u303c\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790\ua791\ua7a0-\ua7a9\ua7fa-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uffa0-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]"),new RegExp(r),new RegExp(c),new RegExp(u),new RegExp(s),new RegExp(a),new RegExp(l),new RegExp(i),new RegExp(d),new RegExp(g),new RegExp(p),new RegExp(h),new RegExp("@")],w=new RegExp("^"+C+"$"),W=m,f=t=>{let e=13;const n=W.length;for(let o=0;o<n;++o){const n=W[o];if(n&&n.test(t)){e=o;break}}return e},x=(t,e)=>{const n=t[e],o=t[e+1];if(e<0||e>t.length-1&&0!==e)return!1;if(0===n&&0===o)return!1;const r=t[e+2];if(0===n&&(2===o||1===o||12===o)&&0===r)return!1;const c=t[e-1];return(2!==n&&1!==n&&12!==o||0!==o||0!==c)&&(4!==n&&0!==n||4!==o&&0!==o)&&(3!==n&&1!==n||4!==o||4!==c)&&(4!==n||3!==o&&1!==o||4!==r)&&(8!==n&&9!==n||0!==o&&4!==o&&o!==y&&8!==o&&9!==o)&&(8!==o&&(9!==o||0!==r&&4!==r&&r!==y&&8!==r&&9!==r)||0!==n&&4!==n&&n!==y&&8!==n&&9!==n)&&(5!==n||6!==o)&&(7===n||5===n||6===n||7===o||5===o||6===o||(n!==y||o!==y)&&(11!==o||0!==n&&4!==n&&n!==y&&11!==n)&&(11!==n||0!==o&&4!==o&&o!==y)&&12!==n)},E=/^\s+$/,R=w,S=t=>"http"===t||"https"===t,b=(t,e)=>{const n=((t,e)=>{let n;for(n=e;n<t.length&&!E.test(t[n]);n++);return n})(t,e+1);return"://"===t.slice(e+1,n).join("").substr(0,3)?n:e},v=(t,e,n)=>((t,e,n)=>{n={includeWhitespace:!1,includePunctuation:!1,...n};const r=o(t,e);return((t,e,n,o)=>{const r=[],c=[];let u=[];for(let s=0;s<n.length;++s)if(u.push(t[s]),x(n,s)){const n=e[s];if((o.includeWhitespace||!E.test(n))&&(o.includePunctuation||!R.test(n))){const n=s-u.length+1,o=s+1,a=e.slice(n,o).join("");if(S(a)){const n=b(e,s),r=t.slice(o,n);Array.prototype.push.apply(u,r),s=n}"."===e[s+1]&&/^([a-zA-Z]\.)+$/.test(a+".")?(u.push(t[s+1]),c.push({start:n,end:o+1})):c.push({start:n,end:o}),r.push(u)}u=[]}return{words:r,indices:c}})(t,r,(t=>{const e=(t=>{const e={};return n=>{if(e[n])return e[n];{const o=t(n);return e[n]=o,o}}})(f);return o(t,e)})(r),n)})(t,e,n).words;var F=tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");const T=(t,e)=>{const n=e.getBlockElements(),o=e.getVoidElements(),r=t=>n[t.nodeName]||o[t.nodeName],c=[];let u="";const s=new F(t,t);let a;for(;a=s.next();)3===a.nodeType?u+=a.data.replace(/\uFEFF/g,""):r(a)&&u.length&&(c.push(u),u="");return u.length&&c.push(u),c},A=t=>t.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"_").length,B=(t,e)=>{const o=(t=>t.replace(/\u200B/g,""))(T(t,e).join("\n"));return v(o.split(""),n).length},D=(t,e)=>{const n=T(t,e).join("");return A(n)},j=(t,e)=>{const n=T(t,e).join("").replace(/\s/g,"");return A(n)},k=(t,e)=>()=>e(t.getBody(),t.schema),U=(t,e)=>()=>e(t.selection.getRng().cloneContents(),t.schema),M=t=>k(t,B);var P=tinymce.util.Tools.resolve("tinymce.util.Delay");const $=(t,e)=>{((t,e)=>{t.dispatch("wordCountUpdate",{wordCount:{words:e.body.getWordCount(),characters:e.body.getCharacterCount(),charactersWithoutSpaces:e.body.getCharacterCountWithoutSpaces()}})})(t,e)},z=(t,n,o)=>{const r=((t,n)=>{let o=null;return{cancel:()=>{e(o)||(clearTimeout(o),o=null)},throttle:(...r)=>{e(o)&&(o=setTimeout((()=>{o=null,t.apply(null,r)}),n))}}})((()=>$(t,n)),o);t.on("init",(()=>{$(t,n),P.setEditorTimeout(t,(()=>{t.on("SetContent BeforeAddUndo Undo Redo ViewUpdate keyup",r.throttle)}),0),t.on("remove",r.cancel)}))};((e=300)=>{t.add("wordcount",(t=>{const n=(t=>({body:{getWordCount:M(t),getCharacterCount:k(t,D),getCharacterCountWithoutSpaces:k(t,j)},selection:{getWordCount:U(t,B),getCharacterCount:U(t,D),getCharacterCountWithoutSpaces:U(t,j)},getCount:M(t)}))(t);return((t,e)=>{t.addCommand("mceWordCount",(()=>((t,e)=>{t.windowManager.open({title:"Word Count",body:{type:"panel",items:[{type:"table",header:["Count","Document","Selection"],cells:[["Words",String(e.body.getWordCount()),String(e.selection.getWordCount())],["Characters (no spaces)",String(e.body.getCharacterCountWithoutSpaces()),String(e.selection.getCharacterCountWithoutSpaces())],["Characters",String(e.body.getCharacterCount()),String(e.selection.getCharacterCount())]]}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}]})})(t,e)))})(t,n),(t=>{const e=()=>t.execCommand("mceWordCount");t.ui.registry.addButton("wordcount",{tooltip:"Word count",icon:"character-count",onAction:e}),t.ui.registry.addMenuItem("wordcount",{text:"Word count",icon:"character-count",onAction:e})})(t),z(t,n,e),n}))})()}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.js
new file mode 100644
index 0000000..e6c4254
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/dark/content.css', "body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.min.css
new file mode 100644
index 0000000..c9fe30a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/dark/content.min.css
@@ -0,0 +1 @@
+body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.js
new file mode 100644
index 0000000..3772402
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/default/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.min.css
new file mode 100644
index 0000000..54bb28d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/default/content.min.css
@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.js
new file mode 100644
index 0000000..18a0405
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/document/content.css', "@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.min.css
new file mode 100644
index 0000000..a8b7021
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/document/content.min.css
@@ -0,0 +1 @@
+@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.js
new file mode 100644
index 0000000..f99dddf
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/tinymce-5-dark/content.css', "body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.min.css
new file mode 100644
index 0000000..33c4009
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5-dark/content.min.css
@@ -0,0 +1 @@
+body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.js
new file mode 100644
index 0000000..2ed6b82
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/tinymce-5/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.min.css
new file mode 100644
index 0000000..54bb28d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/tinymce-5/content.min.css
@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.js
new file mode 100644
index 0000000..c682f29
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('content/writer/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.min.css
new file mode 100644
index 0000000..186d62d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/content/writer/content.min.css
@@ -0,0 +1 @@
+body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.js
new file mode 100644
index 0000000..01ee89c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/dark/content.inline.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}")
+//# sourceMappingURL=content.inline.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.min.css
new file mode 100644
index 0000000..747b11d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.inline.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.js
new file mode 100644
index 0000000..6159708
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/dark/content.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#50fa7b}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.important,.token.regex{color:#ffb86c}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.3)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.3);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #4099ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #4099ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #4099ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #4099ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #4099ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#4099ff}.mce-content-body .mce-edit-focus{outline:3px solid #4099ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid transparent;bottom:-1px;content:'';left:-1px;mix-blend-mode:lighten;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#4099ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.min.css
new file mode 100644
index 0000000..b367b41
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/content.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#50fa7b}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.important,.token.regex{color:#ffb86c}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.3)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.3);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #4099ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #4099ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #4099ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #4099ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #4099ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#4099ff}.mce-content-body .mce-edit-focus{outline:3px solid #4099ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid transparent;bottom:-1px;content:'';left:-1px;mix-blend-mode:lighten;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#4099ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.js
new file mode 100644
index 0000000..34ea0ac
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/dark/skin.css', ".tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:2px solid #161f29;border-radius:10px;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#222f3e;border:2px solid #161f29;border-radius:10px;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:6px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(0,101,216,.4);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#006ce7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#0060ce}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#0054b4}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#161f29;border-radius:10px;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#006ce7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#006ce7;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:6px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #006ce7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#006ce7;background-image:none;border-color:#006ce7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#003c81;background-image:none;border-color:#003c81;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#3d546f;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#3d546f;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;color:#fff;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#3d546f;background-image:none;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:hover:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:active:not(:disabled){background-color:#2b3b4e;background-image:none;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled{background-color:#2b5c93;background-image:none;border-color:#2b5c93;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#2b5c93;background-image:none;border-color:#2b5c93;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#254f80;background-image:none;border-color:#254f80;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#254f80;background-image:none;border-color:#254f80;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#1f436c;background-image:none;border-color:#1f436c;box-shadow:none;color:#fff}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked[disabled]{background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:rgba(255,255,255,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked:focus:not(:disabled){background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked:active:not(:disabled){background-color:rgba(255,255,255,.3);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#fff}.tox .tox-checkbox{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:6px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(255,255,255,.2)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#006ce7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#006ce7}.tox .tox-checkbox--disabled{color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(255,255,255,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:6px;box-shadow:inset 0 0 0 1px #006ce7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:rgba(255,255,255,.15);border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.5);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#fff;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#2b3b4e;color:#fff}.tox .tox-collection--list .tox-collection__item--active{background-color:#006ce7}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#599fef;color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#2b3b4e;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#2f4055;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#2f4055;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#599fef;color:#fff}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#2f4055;color:#fff;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(255,255,255,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#2b3b4e;border:1px solid rgba(255,255,255,.15);border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:28px;margin:6px 1px 5px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid transparent}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid transparent}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:5px 0 6px 11px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px -4px}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#fff;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#2f4055}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#fff;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#2b3b4e;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#2b3b4e;border:1px solid #161f29;border-radius:6px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#fff;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#fff;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#fff;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(255,255,255,.5);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#2b3b4e;bottom:0;content:\"\";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(43,59,78,0),#2b3b4e);bottom:0;content:\"\";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#2b3b4e;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#fff;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#2b3b4e;box-shadow:0 0 8px 8px #2b3b4e;color:#fff;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#2b3b4e;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(255,255,255,.5)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#fff;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(34,47,62,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#222f3e}.tox .tox-dialog{background-color:#2b3b4e;border-color:#161f29;border-radius:10px;border-style:solid;border-width:0;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#2b3b4e;border-bottom:none;color:#fff;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#fff;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(255,255,255,.5);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(0,108,231,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #67aeff;color:#67aeff}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#67aeff;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#cde5ff;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #67aeff;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#fff;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#fff}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#fff;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#fff;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#2b3b4e;border-top:none;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(34,47,62,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #000}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #161f29;border-radius:6px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:6px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #161f29;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(255,255,255,.5);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:2px solid #fff;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:2px solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #161f29}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#222f3e;border-bottom:1px solid rgba(255,255,255,.15);box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid rgba(255,255,255,.15);box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#222f3e;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:none}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#006ce7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #2b3b4e;border-radius:6px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(255,255,255,.5);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#222f3e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#2b3b4e;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#006ce7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#fff}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#fff}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#2b3b4e;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size=\"0\"],.tox:not([dir=rtl]) .tox-selectfield select[size=\"1\"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size=\"0\"],.tox[dir=rtl] .tox-selectfield select[size=\"1\"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#222f3e;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:rgba(255,255,255,.15);border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:#006ce7;border-color:rgba(255,255,255,.15)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:#fff;display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#2b3b4e;border:1px solid rgba(255,255,255,.15);border-radius:6px;box-shadow:none;display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 4px}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:8px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:8px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 11px 0 12px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#222f3e;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:5px 1px 6px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#222f3e;border:0;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#334840;border-color:#3c5440;color:#fff}.tox .tox-notification--success p{color:#fff}.tox .tox-notification--success a{color:#b5d199}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#82b153;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #b5d199;outline-offset:2px}.tox .tox-notification--success a:active{color:#689041;text-decoration:underline}.tox .tox-notification--success svg{fill:#fff}.tox .tox-notification--error{background-color:#442632;border-color:#55212b;color:#fff}.tox .tox-notification--error p{color:#fff}.tox .tox-notification--error a{color:#e68080}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#d42b2b;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #e68080;outline-offset:2px}.tox .tox-notification--error a:active{color:#a22;text-decoration:underline}.tox .tox-notification--error svg{fill:#fff}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#222f3e;border-color:rgba(255,255,255,.15);color:#fff0b3}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#fff0b3}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#fc0}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#997a00;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #fc0;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#665200;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#fff0b3}.tox .tox-notification--info{background-color:#254161;border-color:#264972;color:#fff}.tox .tox-notification--info p{color:#fff}.tox .tox-notification--info a{color:#83b7f3}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#2681ea;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #83b7f3;outline-offset:2px}.tox .tox-notification--info a:active{color:#1368c9;text-decoration:underline}.tox .tox-notification--info svg{fill:#fff}.tox .tox-notification__body{align-self:center;color:#fff;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#222f3e;border:1px solid #161f29;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#222f3e transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#161f29 transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #222f3e transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #161f29 transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #222f3e transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #161f29 transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #222f3e;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #161f29;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#222f3e;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #161f29;border-radius:6px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#006ce7;border:2px solid #0054b4;border-radius:6px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(255,255,255,.5);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#222f3e;border-top:1px solid rgba(255,255,255,.15);color:rgba(255,255,255,.75);display:flex;flex:0 0 auto;font-size:14px;font-weight:400;height:25px;overflow:hidden;padding:0 8px;position:relative;text-transform:none}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(255,255,255,.75);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(255,255,255,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#fff}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px 5px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(34,47,62,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:6px 1px 5px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#fff}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#222f3e;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:hover svg{fill:#fff}.tox .tox-tbtn:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:active svg{fill:#fff}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#599fef;border:0;box-shadow:none;color:#fff;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#fff}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#fff}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:42px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:56px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:#2f4055;border-radius:3px;display:flex;margin:6px 1px 5px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#2f4055}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#2f4055;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#fff;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#2f4055;color:#fff}.tox .tox-number-input input:focus{background-color:#2f4055}.tox .tox-number-input input:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button{color:#fff;height:28px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#fff;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#2f4055;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:hover svg{fill:#fff}.tox .tox-number-input button:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:active svg{fill:#fff}.tox .tox-number-input button:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#2f4055}.tox .tox-tbtn--select{margin:6px 1px 5px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:#2f4055}.tox .tox-tbtn--bespoke:focus{background:#2f4055}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:4px}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:6px 1px 5px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #2f4055 inset}.tox .tox-split-button:focus{background:#222f3e;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#222f3e;box-shadow:none;color:rgba(255,255,255,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#222f3e}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#222f3e;background-image:repeating-linear-gradient(rgba(255,255,255,.15) 0 1px,transparent 1px 39px);background-position:center top 40px;background-repeat:no-repeat;background-size:calc(100% - 11px * 2) calc(100% - 41px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 11px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid transparent;margin-top:-1px;padding-bottom:1px;padding-top:1px}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#222f3e;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 11px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 11px 0 12px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid transparent}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid transparent}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#324053;border-radius:6px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #324053;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #324053;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #324053;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #324053;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#fff}.tox .tox-tree .tox-trbtn:focus{background:#2f4055;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:active svg{fill:#fff}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#fff}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#2b3b4e;border-radius:4px;border-top:1px solid #161f29;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #161f29;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #161f29;color:#fff;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0;border-radius:6px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #161f29;border-radius:6px;color:#fff;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#2f4055;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:6px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#599fef;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(255,255,255,.5);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#222f3e;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:10px 10px 2px 10px;position:relative}.tox .tox-view__label{color:#fff;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:10px 10px 2px 10px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #161f29;border-radius:6px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #161f29;border-radius:6px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #161f29;border-radius:6px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:\"\";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox.tox-tinymce-aux .tox-toolbar__overflow{box-shadow:0 0 0 1px rgba(255,255,255,.15)}")
+//# sourceMappingURL=skin.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.min.css
new file mode 100644
index 0000000..4e30beb
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.min.css
@@ -0,0 +1 @@
+.tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:2px solid #161f29;border-radius:10px;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#222f3e;border:2px solid #161f29;border-radius:10px;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:6px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(0,101,216,.4);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#006ce7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#0060ce}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#0054b4}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#161f29;border-radius:10px;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#006ce7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#006ce7;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:6px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #006ce7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#006ce7;background-image:none;border-color:#006ce7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#003c81;background-image:none;border-color:#003c81;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#3d546f;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#3d546f;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;color:#fff;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#3d546f;background-image:none;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:hover:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:active:not(:disabled){background-color:#2b3b4e;background-image:none;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled{background-color:#2b5c93;background-image:none;border-color:#2b5c93;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#2b5c93;background-image:none;border-color:#2b5c93;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#254f80;background-image:none;border-color:#254f80;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#254f80;background-image:none;border-color:#254f80;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#1f436c;background-image:none;border-color:#1f436c;box-shadow:none;color:#fff}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked[disabled]{background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:rgba(255,255,255,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked:focus:not(:disabled){background-color:rgba(255,255,255,.2);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked:active:not(:disabled){background-color:rgba(255,255,255,.3);border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#fff}.tox .tox-checkbox{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:6px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(255,255,255,.2)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#006ce7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#006ce7}.tox .tox-checkbox--disabled{color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(255,255,255,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:6px;box-shadow:inset 0 0 0 1px #006ce7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:rgba(255,255,255,.15);border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:rgba(255,255,255,.15);color:rgba(255,255,255,.5);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#fff;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#2b3b4e;color:#fff}.tox .tox-collection--list .tox-collection__item--active{background-color:#006ce7}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#599fef;color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#2b3b4e;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#2f4055;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#2f4055;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#599fef;color:#fff}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#2f4055;color:#fff;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(255,255,255,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#2b3b4e;border:1px solid rgba(255,255,255,.15);border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:28px;margin:6px 1px 5px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid transparent}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid transparent}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:5px 0 6px 11px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px -4px}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#fff;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#2f4055}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#fff;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#2b3b4e;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#2b3b4e;border:1px solid #161f29;border-radius:6px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#fff;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#fff;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#fff;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(255,255,255,.5);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#2b3b4e;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(43,59,78,0),#2b3b4e);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#2b3b4e;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#fff;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#2b3b4e;box-shadow:0 0 8px 8px #2b3b4e;color:#fff;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#2b3b4e;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(255,255,255,.5)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#fff;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(34,47,62,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#222f3e}.tox .tox-dialog{background-color:#2b3b4e;border-color:#161f29;border-radius:10px;border-style:solid;border-width:0;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#2b3b4e;border-bottom:none;color:#fff;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#fff;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(255,255,255,.5);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(0,108,231,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #67aeff;color:#67aeff}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#67aeff;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#cde5ff;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #67aeff;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#fff;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#fff}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#fff;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#fff;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#2b3b4e;border-top:none;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(34,47,62,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #000}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #161f29;border-radius:6px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:6px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #161f29;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(255,255,255,.5);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:2px solid #fff;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:2px solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #161f29}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#222f3e;border-bottom:1px solid rgba(255,255,255,.15);box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid rgba(255,255,255,.15);box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#222f3e;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:none}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#006ce7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #2b3b4e;border-radius:6px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(255,255,255,.5);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#222f3e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#2b3b4e;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#006ce7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#fff}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#fff}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#2b3b4e;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#161f29;border-radius:6px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#222f3e;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:rgba(255,255,255,.15);border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:#006ce7;border-color:rgba(255,255,255,.15)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:#fff;display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#2b3b4e;border:1px solid rgba(255,255,255,.15);border-radius:6px;box-shadow:none;display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 4px}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:8px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:8px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 11px 0 12px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#222f3e;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:5px 1px 6px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#222f3e;border:0;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#334840;border-color:#3c5440;color:#fff}.tox .tox-notification--success p{color:#fff}.tox .tox-notification--success a{color:#b5d199}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#82b153;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #b5d199;outline-offset:2px}.tox .tox-notification--success a:active{color:#689041;text-decoration:underline}.tox .tox-notification--success svg{fill:#fff}.tox .tox-notification--error{background-color:#442632;border-color:#55212b;color:#fff}.tox .tox-notification--error p{color:#fff}.tox .tox-notification--error a{color:#e68080}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#d42b2b;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #e68080;outline-offset:2px}.tox .tox-notification--error a:active{color:#a22;text-decoration:underline}.tox .tox-notification--error svg{fill:#fff}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#222f3e;border-color:rgba(255,255,255,.15);color:#fff0b3}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#fff0b3}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#fc0}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#997a00;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #fc0;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#665200;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#fff0b3}.tox .tox-notification--info{background-color:#254161;border-color:#264972;color:#fff}.tox .tox-notification--info p{color:#fff}.tox .tox-notification--info a{color:#83b7f3}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#2681ea;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #83b7f3;outline-offset:2px}.tox .tox-notification--info a:active{color:#1368c9;text-decoration:underline}.tox .tox-notification--info svg{fill:#fff}.tox .tox-notification__body{align-self:center;color:#fff;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#222f3e;border:1px solid #161f29;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#222f3e transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#161f29 transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #222f3e transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #161f29 transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #222f3e transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #161f29 transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #222f3e;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #161f29;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#222f3e;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #161f29;border-radius:6px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#006ce7;border:2px solid #0054b4;border-radius:6px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(255,255,255,.5);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#222f3e;border-top:1px solid rgba(255,255,255,.15);color:rgba(255,255,255,.75);display:flex;flex:0 0 auto;font-size:14px;font-weight:400;height:25px;overflow:hidden;padding:0 8px;position:relative;text-transform:none}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(255,255,255,.75);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(255,255,255,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#fff}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px 5px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(34,47,62,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:6px 1px 5px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#fff}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#222f3e;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:hover svg{fill:#fff}.tox .tox-tbtn:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:active svg{fill:#fff}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#599fef;border:0;box-shadow:none;color:#fff;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#fff}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#fff}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:42px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:56px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:#2f4055;border-radius:3px;display:flex;margin:6px 1px 5px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#2f4055}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#2f4055;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#fff;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#2f4055;color:#fff}.tox .tox-number-input input:focus{background-color:#2f4055}.tox .tox-number-input input:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button{color:#fff;height:28px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#fff;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#2f4055;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:hover svg{fill:#fff}.tox .tox-number-input button:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:active svg{fill:#fff}.tox .tox-number-input button:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#2f4055}.tox .tox-tbtn--select{margin:6px 1px 5px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:#2f4055}.tox .tox-tbtn--bespoke:focus{background:#2f4055}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:4px}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:6px 1px 5px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #2f4055 inset}.tox .tox-split-button:focus{background:#222f3e;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#222f3e;box-shadow:none;color:rgba(255,255,255,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#222f3e}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#222f3e;background-image:repeating-linear-gradient(rgba(255,255,255,.15) 0 1px,transparent 1px 39px);background-position:center top 40px;background-repeat:no-repeat;background-size:calc(100% - 11px * 2) calc(100% - 41px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 11px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid transparent;margin-top:-1px;padding-bottom:1px;padding-top:1px}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#222f3e;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 11px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 11px 0 12px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid transparent}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid transparent}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#324053;border-radius:6px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #324053;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #324053;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #324053;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #324053;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#fff}.tox .tox-tree .tox-trbtn:focus{background:#2f4055;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#2f4055;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:active{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:active svg{fill:#fff}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#599fef;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#fff}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#2b3b4e;border-radius:4px;border-top:1px solid #161f29;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #161f29;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #161f29;color:#fff;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0;border-radius:6px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #161f29;border-radius:6px;color:#fff;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#2f4055;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:6px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #fff;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#599fef;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(255,255,255,.5);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#222f3e;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:10px 10px 2px 10px;position:relative}.tox .tox-view__label{color:#fff;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:10px 10px 2px 10px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #161f29;border-radius:6px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #161f29;border-radius:6px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #161f29;border-radius:6px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox.tox-tinymce-aux .tox-toolbar__overflow{box-shadow:0 0 0 1px rgba(255,255,255,.15)}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.js
new file mode 100644
index 0000000..0b647fd
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/dark/skin.shadowdom.css', "body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}")
+//# sourceMappingURL=skin.shadowdom.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css
new file mode 100644
index 0000000..8745951
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css
@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.js
new file mode 100644
index 0000000..1d69d68
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/default/content.inline.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}")
+//# sourceMappingURL=content.inline.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.min.css
new file mode 100644
index 0000000..747b11d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.inline.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.js
new file mode 100644
index 0000000..5fb4919
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/default/content.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.min.css
new file mode 100644
index 0000000..1e3ee0c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/content.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.js
new file mode 100644
index 0000000..6036a23
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/default/skin.css', ".tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:2px solid #eee;border-radius:10px;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#fff;border:2px solid #eee;border-radius:10px;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:6px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(0,101,216,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#006ce7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#006ce7}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#006ce7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#0060ce}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#0054b4}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.08);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#c00}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#527530}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#527530}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#eee;border-radius:10px;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#006ce7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#006ce7;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:6px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #006ce7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#006ce7;background-image:none;border-color:#006ce7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#003c81;background-image:none;border-color:#003c81;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#f0f0f0;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#f0f0f0;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;color:#222f3e;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#f0f0f0;background-image:none;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:hover:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:active:not(:disabled){background-color:#d6d6d6;background-image:none;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled{background-color:#a8c8ed;background-image:none;border-color:#a8c8ed;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#a8c8ed;background-image:none;border-color:#a8c8ed;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#93bbe9;background-image:none;border-color:#93bbe9;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#93bbe9;background-image:none;border-color:#93bbe9;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#7daee4;background-image:none;border-color:#7daee4;box-shadow:none;color:#222f3e}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked[disabled]{background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:rgba(34,47,62,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked:focus:not(:disabled){background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked:active:not(:disabled){background-color:rgba(34,47,62,.18);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#222f3e}.tox .tox-checkbox{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:6px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(34,47,62,.3)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#006ce7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#006ce7}.tox .tox-checkbox--disabled{color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(34,47,62,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:6px;box-shadow:inset 0 0 0 1px #006ce7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#e3e3e3;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#fcfcfc;color:rgba(34,47,62,.7);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#222f3e;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#fff;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active{background-color:#006ce7}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#a6ccf7;color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#fff;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#f0f0f0;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#f0f0f0;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#a6ccf7;color:#222f3e}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#f0f0f0;color:#222f3e;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7 inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(34,47,62,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#fff;border:1px solid #e3e3e3;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:28px;margin:6px 1px 5px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid transparent}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid transparent}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:5px 0 6px 11px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px -4px}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#222f3e;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#f0f0f0}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#222f3e;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#fff;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#fff;border:1px solid #eee;border-radius:6px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#222f3e;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#222f3e;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#222f3e;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(34,47,62,.7);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#fff;bottom:0;content:\"\";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(255,255,255,0),#fff);bottom:0;content:\"\";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#fff;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#222f3e;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#fff;box-shadow:0 0 8px 8px #fff;color:#222f3e;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#fff;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(34,47,62,.7)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#222f3e;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(255,255,255,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#fff}.tox .tox-dialog{background-color:#fff;border-color:#eee;border-radius:10px;border-style:solid;border-width:0;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#fff;border-bottom:none;color:#222f3e;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#222f3e;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(34,47,62,.7);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(0,108,231,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #006ce7;color:#006ce7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#006ce7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#003c81;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #006ce7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#00244e;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#222f3e}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#222f3e;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#222f3e;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#fff;border-top:none;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(255,255,255,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #626262}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #eee;border-radius:6px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:6px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #eee;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(34,47,62,.7);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:2px solid #006ce7;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:2px solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #eee}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#fff;border-bottom:none;box-shadow:0 2px 2px -2px rgba(34,47,62,.1),0 8px 8px -4px rgba(34,47,62,.07);padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #e3e3e3;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#fff;box-shadow:0 2px 2px -2px rgba(34,47,62,.2),0 8px 8px -4px rgba(34,47,62,.15);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 2px 2px -2px rgba(34,47,62,.2),0 8px 8px -4px rgba(34,47,62,.15)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#006ce7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #fff;border-radius:6px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(34,47,62,.7);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#fff;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#006ce7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#222f3e}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#222f3e}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#fff;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size=\"0\"],.tox:not([dir=rtl]) .tox-selectfield select[size=\"1\"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size=\"0\"],.tox[dir=rtl] .tox-selectfield select[size=\"1\"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#fff;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#eee;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:#006ce7;border-color:#eee}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:rgba(34,47,62,.7);display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#fff;border:1px solid transparent;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 4px}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:8px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:8px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 11px 0 12px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#fff;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:5px 1px 6px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#fff;border:0;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#222f3e}.tox .tox-notification--success p{color:#222f3e}.tox .tox-notification--success a{color:#517342}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#24321d;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #517342;outline-offset:2px}.tox .tox-notification--success a:active{color:#0d120a;text-decoration:underline}.tox .tox-notification--success svg{fill:#222f3e}.tox .tox-notification--error{background-color:#f5cccc;border-color:#f0b3b3;color:#222f3e}.tox .tox-notification--error p{color:#222f3e}.tox .tox-notification--error a{color:#77181f}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#220709;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #77181f;outline-offset:2px}.tox .tox-notification--error a:active{color:#000;text-decoration:underline}.tox .tox-notification--error svg{fill:#222f3e}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fff5cc;border-color:#fff0b3;color:#222f3e}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#222f3e}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#7a6e25}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#2c280d;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #7a6e25;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#050502;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#222f3e}.tox .tox-notification--info{background-color:#d6e7fb;border-color:#c1dbf9;color:#222f3e}.tox .tox-notification--info p{color:#222f3e}.tox .tox-notification--info a{color:#2a64a6}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#163355;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #2a64a6;outline-offset:2px}.tox .tox-notification--info a:active{color:#0b1a2c;text-decoration:underline}.tox .tox-notification--info svg{fill:#222f3e}.tox .tox-notification__body{align-self:center;color:#222f3e;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#fff;border:1px solid #eee;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#fff transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#eee transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #fff transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #eee transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #fff transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #eee transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #fff;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #eee;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#fff;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #eee;border-radius:6px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#006ce7;border:2px solid #0054b4;border-radius:6px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(34,47,62,.7);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#fff;border-top:1px solid #e3e3e3;color:rgba(34,47,62,.7);display:flex;flex:0 0 auto;font-size:14px;font-weight:400;height:25px;overflow:hidden;padding:0 8px;position:relative;text-transform:none}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(34,47,62,.7);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(34,47,62,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#222f3e}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px 5px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(255,255,255,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:6px 1px 5px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#222f3e}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#fff;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:hover svg{fill:#222f3e}.tox .tox-tbtn:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:active svg{fill:#222f3e}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#222f3e}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:42px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:56px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:#f7f7f7;border-radius:3px;display:flex;margin:6px 1px 5px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#f7f7f7}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#f7f7f7;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#222f3e;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#f0f0f0;color:#222f3e}.tox .tox-number-input input:focus{background-color:#f7f7f7}.tox .tox-number-input input:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button{color:#222f3e;height:28px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#222f3e;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#f7f7f7;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:hover svg{fill:#222f3e}.tox .tox-number-input button:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:active svg{fill:#222f3e}.tox .tox-number-input button:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#f7f7f7}.tox .tox-tbtn--select{margin:6px 1px 5px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:#f7f7f7}.tox .tox-tbtn--bespoke:focus{background:#f7f7f7}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:4px}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:6px 1px 5px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #f0f0f0 inset}.tox .tox-split-button:focus{background:#fff;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#fff;box-shadow:none;color:rgba(34,47,62,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#fff}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#fff;background-image:repeating-linear-gradient(#e3e3e3 0 1px,transparent 1px 39px);background-position:center top 40px;background-repeat:no-repeat;background-size:calc(100% - 11px * 2) calc(100% - 41px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 11px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid transparent;margin-top:-1px;padding-bottom:1px;padding-top:1px}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#fff;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 11px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 11px 0 12px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid transparent}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid transparent}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#222f3e;border-radius:6px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #222f3e;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #222f3e;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #222f3e;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #222f3e;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#222f3e}.tox .tox-tree .tox-trbtn:focus{background:#f0f0f0;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:active svg{fill:#222f3e}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#fff;border-radius:4px;border-top:1px solid #eee;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #eee;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #eee;color:#222f3e;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0;border-radius:6px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #eee;border-radius:6px;color:#222f3e;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#f0f0f0;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:6px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#a6ccf7;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(34,47,62,.7);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#fff;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:10px 10px 2px 10px;position:relative}.tox .tox-view__label{color:#222f3e;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:10px 10px 2px 10px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #eee;border-radius:6px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #eee;border-radius:6px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #eee;border-radius:6px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:\"\";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}")
+//# sourceMappingURL=skin.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.min.css
new file mode 100644
index 0000000..4cdf9cc
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.min.css
@@ -0,0 +1 @@
+.tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:2px solid #eee;border-radius:10px;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#fff;border:2px solid #eee;border-radius:10px;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:6px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(0,101,216,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#006ce7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#006ce7}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#006ce7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#0060ce}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#0054b4}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.08);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#c00}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#527530}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#527530}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#eee;border-radius:10px;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#006ce7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#006ce7;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:6px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #006ce7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#006ce7;background-image:none;border-color:#006ce7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#0060ce;background-image:none;border-color:#0060ce;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#0054b4;background-image:none;border-color:#0054b4;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#00489b;background-image:none;border-color:#00489b;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#003c81;background-image:none;border-color:#003c81;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#f0f0f0;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#f0f0f0;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;color:#222f3e;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#f0f0f0;background-image:none;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:hover:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:active:not(:disabled){background-color:#d6d6d6;background-image:none;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled{background-color:#a8c8ed;background-image:none;border-color:#a8c8ed;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#a8c8ed;background-image:none;border-color:#a8c8ed;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#93bbe9;background-image:none;border-color:#93bbe9;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#93bbe9;background-image:none;border-color:#93bbe9;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#7daee4;background-image:none;border-color:#7daee4;box-shadow:none;color:#222f3e}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked[disabled]{background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:rgba(34,47,62,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked:focus:not(:disabled){background-color:rgba(34,47,62,.12);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked:active:not(:disabled){background-color:rgba(34,47,62,.18);border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#222f3e}.tox .tox-checkbox{align-items:center;border-radius:6px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:6px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(34,47,62,.3)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#006ce7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#006ce7}.tox .tox-checkbox--disabled{color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(34,47,62,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:6px;box-shadow:inset 0 0 0 1px #006ce7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#e3e3e3;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#fcfcfc;color:rgba(34,47,62,.7);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#222f3e;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#fff;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active{background-color:#006ce7}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#a6ccf7;color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#fff;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#f0f0f0;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#f0f0f0;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#a6ccf7;color:#222f3e}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#f0f0f0;color:#222f3e;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7 inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(34,47,62,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#fff;border:1px solid #e3e3e3;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:28px;margin:6px 1px 5px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid transparent}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid transparent}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:5px 0 6px 11px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px -4px}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#222f3e;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#f0f0f0}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#222f3e;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#fff;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#fff;border:1px solid #eee;border-radius:6px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#222f3e;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#222f3e;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#222f3e;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(34,47,62,.7);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#fff;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(255,255,255,0),#fff);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#fff;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#222f3e;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#fff;box-shadow:0 0 8px 8px #fff;color:#222f3e;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#fff;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(34,47,62,.7)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#222f3e;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(255,255,255,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#fff}.tox .tox-dialog{background-color:#fff;border-color:#eee;border-radius:10px;border-style:solid;border-width:0;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#fff;border-bottom:none;color:#222f3e;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#222f3e;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(34,47,62,.7);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(0,108,231,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #006ce7;color:#006ce7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#006ce7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#003c81;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #006ce7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#00244e;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#222f3e}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#222f3e;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#222f3e;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#fff;border-top:none;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(255,255,255,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #626262}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #eee;border-radius:6px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:6px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #eee;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(34,47,62,.7);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:2px solid #006ce7;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:2px solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #eee}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#fff;border-bottom:none;box-shadow:0 2px 2px -2px rgba(34,47,62,.1),0 8px 8px -4px rgba(34,47,62,.07);padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #e3e3e3;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#fff;box-shadow:0 2px 2px -2px rgba(34,47,62,.2),0 8px 8px -4px rgba(34,47,62,.15);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 2px 2px -2px rgba(34,47,62,.2),0 8px 8px -4px rgba(34,47,62,.15)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#006ce7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #fff;border-radius:6px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(34,47,62,.7);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#fff;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#006ce7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#222f3e}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#222f3e}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 5.5px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#fff;border-color:#006ce7;box-shadow:0 0 0 1px #006ce7;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#eee;border-radius:6px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#fff;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#eee;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:#006ce7;border-color:#eee}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:rgba(34,47,62,.7);display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#fff;border:1px solid transparent;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 4px}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:8px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:8px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 11px 0 12px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:repeating-linear-gradient(transparent 0 1px,transparent 1px 39px) center top 39px/100% calc(100% - 39px) no-repeat;background-color:#fff;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:5px 1px 6px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#fff;border:0;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:6px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#006ce7;box-shadow:0 0 0 1px #006ce7}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#222f3e}.tox .tox-notification--success p{color:#222f3e}.tox .tox-notification--success a{color:#517342}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#24321d;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #517342;outline-offset:2px}.tox .tox-notification--success a:active{color:#0d120a;text-decoration:underline}.tox .tox-notification--success svg{fill:#222f3e}.tox .tox-notification--error{background-color:#f5cccc;border-color:#f0b3b3;color:#222f3e}.tox .tox-notification--error p{color:#222f3e}.tox .tox-notification--error a{color:#77181f}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#220709;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #77181f;outline-offset:2px}.tox .tox-notification--error a:active{color:#000;text-decoration:underline}.tox .tox-notification--error svg{fill:#222f3e}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fff5cc;border-color:#fff0b3;color:#222f3e}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#222f3e}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#7a6e25}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#2c280d;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #7a6e25;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#050502;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#222f3e}.tox .tox-notification--info{background-color:#d6e7fb;border-color:#c1dbf9;color:#222f3e}.tox .tox-notification--info p{color:#222f3e}.tox .tox-notification--info a{color:#2a64a6}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#163355;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #2a64a6;outline-offset:2px}.tox .tox-notification--info a:active{color:#0b1a2c;text-decoration:underline}.tox .tox-notification--info svg{fill:#222f3e}.tox .tox-notification__body{align-self:center;color:#222f3e;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#fff;border:1px solid #eee;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#fff transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#eee transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #fff transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #eee transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #fff transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #eee transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #fff;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #eee;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#fff;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #eee;border-radius:6px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#006ce7;border:2px solid #0054b4;border-radius:6px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(34,47,62,.7);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#fff;border-top:1px solid #e3e3e3;color:rgba(34,47,62,.7);display:flex;flex:0 0 auto;font-size:14px;font-weight:400;height:25px;overflow:hidden;padding:0 8px;position:relative;text-transform:none}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(34,47,62,.7);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(34,47,62,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#222f3e}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px 5px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(255,255,255,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;justify-content:center;margin:6px 1px 5px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#222f3e}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#fff;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:hover svg{fill:#222f3e}.tox .tox-tbtn:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:active svg{fill:#222f3e}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#222f3e}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:42px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:56px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:#f7f7f7;border-radius:3px;display:flex;margin:6px 1px 5px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#f7f7f7}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#f7f7f7;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#222f3e;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#f0f0f0;color:#222f3e}.tox .tox-number-input input:focus{background-color:#f7f7f7}.tox .tox-number-input input:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button{color:#222f3e;height:28px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#222f3e;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#f7f7f7;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:hover svg{fill:#222f3e}.tox .tox-number-input button:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:active svg{fill:#222f3e}.tox .tox-number-input button:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#f7f7f7}.tox .tox-tbtn--select{margin:6px 1px 5px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:#f7f7f7}.tox .tox-tbtn--bespoke:focus{background:#f7f7f7}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:4px}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:6px 1px 5px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #f0f0f0 inset}.tox .tox-split-button:focus{background:#fff;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#fff;box-shadow:none;color:rgba(34,47,62,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#fff}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#fff;background-image:repeating-linear-gradient(#e3e3e3 0 1px,transparent 1px 39px);background-position:center top 40px;background-repeat:no-repeat;background-size:calc(100% - 11px * 2) calc(100% - 41px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 11px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid transparent;margin-top:-1px;padding-bottom:1px;padding-top:1px}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#fff;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:6px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 11px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 11px 0 12px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid transparent}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid transparent}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#222f3e;border-radius:6px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #222f3e;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #222f3e;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #222f3e;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #222f3e;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#222f3e}.tox .tox-tree .tox-trbtn:focus{background:#f0f0f0;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#f0f0f0;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:active svg{fill:#222f3e}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#a6ccf7;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#fff;border-radius:4px;border-top:1px solid #eee;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #eee;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #eee;color:#222f3e;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0;border-radius:6px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #eee;border-radius:6px;color:#222f3e;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#f0f0f0;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:6px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 2px #006ce7;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#a6ccf7;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(34,47,62,.7);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#fff;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:10px 10px 2px 10px;position:relative}.tox .tox-view__label{color:#222f3e;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:10px 10px 2px 10px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #eee;border-radius:6px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #eee;border-radius:6px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #eee;border-radius:6px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.js
new file mode 100644
index 0000000..9c75844
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/default/skin.shadowdom.css', "body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}")
+//# sourceMappingURL=skin.shadowdom.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css
new file mode 100644
index 0000000..8745951
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/oxide/skin.shadowdom.min.css
@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.js
new file mode 100644
index 0000000..d09218a
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5-dark/content.inline.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}")
+//# sourceMappingURL=content.inline.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css
new file mode 100644
index 0000000..747b11d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.js
new file mode 100644
index 0000000..496df6d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5-dark/content.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#50fa7b}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.important,.token.regex{color:#ffb86c}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.3)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.3);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #4099ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #4099ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #4099ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #4099ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #4099ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#4099ff}.mce-content-body .mce-edit-focus{outline:3px solid #4099ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid transparent;bottom:-1px;content:'';left:-1px;mix-blend-mode:lighten;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#4099ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.min.css
new file mode 100644
index 0000000..b367b41
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/content.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#50fa7b}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.important,.token.regex{color:#ffb86c}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.3)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.3);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #4099ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #4099ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #4099ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #4099ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #4099ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#4099ff}.mce-content-body .mce-edit-focus{outline:3px solid #4099ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid transparent;bottom:-1px;content:'';left:-1px;mix-blend-mode:lighten;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#4099ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.js
new file mode 100644
index 0000000..105ca86
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5-dark/skin.css', ".tox{box-shadow:none;box-sizing:content-box;color:#2a3746;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #000;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#222f3e;border:1px solid #000;border-radius:0;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(30,113,170,.4);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#207ab7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#1c6ca1}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#185d8c}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#000;border-radius:0;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:3px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #207ab7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#114060;background-image:none;border-color:#114060;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#3d546f;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#3d546f;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#fff;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#3d546f;background-image:none;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:hover:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:active:not(:disabled){background-color:#2b3b4e;background-image:none;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled{background-color:#346085;background-image:none;border-color:#346085;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#346085;background-image:none;border-color:#346085;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#2d5373;background-image:none;border-color:#2d5373;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#2d5373;background-image:none;border-color:#2d5373;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#264560;background-image:none;border-color:#264560;box-shadow:none;color:#fff}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked[disabled]{background-color:#3d546f;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:focus:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:active:not(:disabled){background-color:#2b3b4e;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#fff}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(255,255,255,.2)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(255,255,255,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#1a1a1a;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#333;color:#fff;cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#fff;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#2b3b4e;color:#fff}.tox .tox-collection--list .tox-collection__item--active{background-color:#4a5562}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#757d87;color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#2b3b4e;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#4a5562;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#4a5562;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#757d87;color:#fff}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#4a5562;color:#fff;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(255,255,255,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#2b3b4e;border:1px solid #1a1a1a;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:3px 0 2px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #000}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #000}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#fff;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#4a5562}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#fff;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#2b3b4e;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#fff;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#fff;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#fff;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(255,255,255,.5);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#2b3b4e;bottom:0;content:\"\";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(43,59,78,0),#2b3b4e);bottom:0;content:\"\";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#2b3b4e;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#fff;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#2b3b4e;box-shadow:0 0 8px 8px #2b3b4e;color:#fff;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#2b3b4e;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(255,255,255,.5)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#fff;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(34,47,62,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#222f3e}.tox .tox-dialog{background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(42,55,70,.15),0 0 40px 1px rgba(42,55,70,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#2b3b4e;border-bottom:none;color:#fff;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#fff;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(255,255,255,.5);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#114060;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #207ab7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#092335;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#fff}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#fff;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#fff;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#2b3b4e;border-top:1px solid #000;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(34,47,62,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #000}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #000;border-radius:3px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:3px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #000;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(255,255,255,.5);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:0 solid transparent;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:0 solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #000}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#222f3e;border-bottom:none;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #000;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#222f3e;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#000;border-radius:3px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(42,55,70,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #2b3b4e;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(255,255,255,.5);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#222f3e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#fff}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#fff}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size=\"0\"],.tox:not([dir=rtl]) .tox-selectfield select[size=\"1\"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size=\"0\"],.tox[dir=rtl] .tox-selectfield select[size=\"1\"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#000;border-radius:3px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#222f3e;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#000;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:0 -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:#fff;display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E\") left 0 top 0 #222f3e;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 4px 0 4px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E\") left 0 top 0 #222f3e;background-color:#222f3e;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#4a5562;border:0;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#207ab7;box-shadow:none}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#334840;border-color:#3c5440;color:#fff}.tox .tox-notification--success p{color:#fff}.tox .tox-notification--success a{color:#b5d199}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#82b153;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #b5d199;outline-offset:2px}.tox .tox-notification--success a:active{color:#689041;text-decoration:underline}.tox .tox-notification--success svg{fill:#fff}.tox .tox-notification--error{background-color:#442632;border-color:#55212b;color:#fff}.tox .tox-notification--error p{color:#fff}.tox .tox-notification--error a{color:#e68080}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#d42b2b;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #e68080;outline-offset:2px}.tox .tox-notification--error a:active{color:#a22;text-decoration:underline}.tox .tox-notification--error svg{fill:#fff}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#222f3e;border-color:#000;color:#fff0b3}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#fff0b3}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#fc0}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#997a00;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #fc0;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#665200;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#fff0b3}.tox .tox-notification--info{background-color:#254161;border-color:#264972;color:#fff}.tox .tox-notification--info p{color:#fff}.tox .tox-notification--info a{color:#83b7f3}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#2681ea;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #83b7f3;outline-offset:2px}.tox .tox-notification--info a:active{color:#1368c9;text-decoration:underline}.tox .tox-notification--info svg{fill:#fff}.tox .tox-notification__body{align-self:center;color:#fff;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#222f3e;border:1px solid #000;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#222f3e transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#000 transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #222f3e transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #000 transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #222f3e transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #000 transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #222f3e;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #000;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#222f3e;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #000;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(255,255,255,.5);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#222f3e;border-top:1px solid #000;color:#fff;display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:#fff;position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(255,255,255,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#fff}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px -4px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(34,47,62,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:3px 0 2px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#fff}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#4a5562;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:hover svg{fill:#fff}.tox .tox-tbtn:active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:active svg{fill:#fff}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#757d87;border:0;box-shadow:none;color:#fff;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#fff}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#fff}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:0 0;border-radius:3px;display:flex;margin:3px 0 2px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#4a5562}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#4a5562;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#fff;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#4a5562;color:#fff}.tox .tox-number-input input:focus{background-color:#4a5562}.tox .tox-number-input input:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button{color:#fff;height:34px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#fff;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#4a5562;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:hover svg{fill:#fff}.tox .tox-number-input button:active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:active svg{fill:#fff}.tox .tox-number-input button:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#4a5562}.tox .tox-tbtn--select{margin:3px 0 2px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:0 0}.tox .tox-tbtn--bespoke:focus{background:#4a5562}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:0}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:3px 0 2px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #4a5562 inset}.tox .tox-split-button:focus{background:#4a5562;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#222f3e;box-shadow:none;color:rgba(255,255,255,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#222f3e}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#222f3e;background-image:repeating-linear-gradient(#000 0 1px,transparent 1px 39px);background-position:center top 39px;background-repeat:no-repeat;background-size:calc(100% - 4px * 2) calc(100% - 39px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 4px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid #000;margin-top:-1px;padding-bottom:0;padding-top:0}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#222f3e;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 4px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #000}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #000}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#2a3746;border-radius:3px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #2a3746;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #2a3746;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #2a3746;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #2a3746;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#fff}.tox .tox-tree .tox-trbtn:focus{background:#4a5562;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:active{background:#6ea9d0;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:active svg{fill:#fff}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#6ea9d0;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#fff}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#2b3b4e;border-radius:4px;border-top:1px solid #000;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #000;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #000;color:#fff;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0;border-radius:3px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #000;border-radius:3px;color:#fff;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#4a5562;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:3px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#6ea9d0;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(255,255,255,.5);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#222f3e;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:8px 8px 0 8px;position:relative}.tox .tox-view__label{color:#fff;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:8px 8px 0 8px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #000;border-radius:3px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #000;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #000;border-radius:3px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:\"\";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:none;padding:0}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce-inline .tox-editor-container{overflow:hidden}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:none;box-shadow:none}.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:0}.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-pop{box-shadow:none}.tox .tox-number-input,.tox .tox-split-button,.tox .tox-tbtn,.tox .tox-tbtn--select{margin:2px 0 3px 0}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E\") left 0 top 0 #222f3e!important}.tox .tox-menubar+.tox-toolbar-overlord{border-top:none}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #000;margin-top:-1px}.tox.tox-tinymce-aux .tox-toolbar__overflow{border:1px solid #000;padding:0}.tox .tox-pop .tox-pop__dialog .tox-toolbar{padding:0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #000}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #000}.tox .tox-toolbar__group{padding:0 4px 0 4px}.tox .tox-collection__item{border-radius:0;cursor:pointer}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-statusbar__resize-handle{padding-bottom:0;padding-right:0}.tox .tox-button::before{display:none}")
+//# sourceMappingURL=skin.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css
new file mode 100644
index 0000000..439bfeb
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.min.css
@@ -0,0 +1 @@
+.tox{box-shadow:none;box-sizing:content-box;color:#2a3746;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #000;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#222f3e;border:1px solid #000;border-radius:0;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(30,113,170,.4);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#207ab7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#1c6ca1}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#185d8c}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#2a3746}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.5);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#000;border-radius:0;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:3px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #207ab7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#114060;background-image:none;border-color:#114060;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#3d546f;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#3d546f;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#fff;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#3d546f;background-image:none;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:hover:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:active:not(:disabled){background-color:#2b3b4e;background-image:none;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled{background-color:#346085;background-image:none;border-color:#346085;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#346085;background-image:none;border-color:#346085;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#2d5373;background-image:none;border-color:#2d5373;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#2d5373;background-image:none;border-color:#2d5373;box-shadow:none;color:#fff}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#264560;background-image:none;border-color:#264560;box-shadow:none;color:#fff}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked[disabled]{background-color:#3d546f;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:focus:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:active:not(:disabled){background-color:#2b3b4e;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#fff}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(255,255,255,.2)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(255,255,255,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#1a1a1a;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#333;color:#fff;cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#fff;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#2b3b4e;color:#fff}.tox .tox-collection--list .tox-collection__item--active{background-color:#4a5562}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#757d87;color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#2b3b4e;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#4a5562;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#4a5562;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#757d87;color:#fff}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#4a5562;color:#fff;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(255,255,255,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#2b3b4e;border:1px solid #1a1a1a;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:3px 0 2px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #000}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #000}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#fff;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#4a5562}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#fff;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#2b3b4e;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#fff;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#fff;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#fff;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(255,255,255,.5);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#2b3b4e;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(43,59,78,0),#2b3b4e);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#2b3b4e;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#fff;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#2b3b4e;box-shadow:0 0 8px 8px #2b3b4e;color:#fff;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#2b3b4e;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(255,255,255,.5)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#fff;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(34,47,62,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#222f3e}.tox .tox-dialog{background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(42,55,70,.15),0 0 40px 1px rgba(42,55,70,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#2b3b4e;border-bottom:none;color:#fff;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#fff;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(255,255,255,.5);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#114060;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #207ab7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#092335;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#fff}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#fff;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#fff;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#2b3b4e;border-top:1px solid #000;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(34,47,62,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #000}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #000;border-radius:3px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:3px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #000;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(255,255,255,.5);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:0 solid transparent;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:0 solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #000}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#222f3e;border-bottom:none;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #000;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#222f3e;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#000;border-radius:3px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(42,55,70,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #2b3b4e;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(255,255,255,.5);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#222f3e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#fff}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#fff}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#000;border-radius:3px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#222f3e;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#000;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:0 -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:#fff;display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 4px 0 4px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e;background-color:#222f3e;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#4a5562;border:0;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#207ab7;box-shadow:none}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#334840;border-color:#3c5440;color:#fff}.tox .tox-notification--success p{color:#fff}.tox .tox-notification--success a{color:#b5d199}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#82b153;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #b5d199;outline-offset:2px}.tox .tox-notification--success a:active{color:#689041;text-decoration:underline}.tox .tox-notification--success svg{fill:#fff}.tox .tox-notification--error{background-color:#442632;border-color:#55212b;color:#fff}.tox .tox-notification--error p{color:#fff}.tox .tox-notification--error a{color:#e68080}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#d42b2b;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #e68080;outline-offset:2px}.tox .tox-notification--error a:active{color:#a22;text-decoration:underline}.tox .tox-notification--error svg{fill:#fff}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#222f3e;border-color:#000;color:#fff0b3}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#fff0b3}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#fc0}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#997a00;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #fc0;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#665200;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#fff0b3}.tox .tox-notification--info{background-color:#254161;border-color:#264972;color:#fff}.tox .tox-notification--info p{color:#fff}.tox .tox-notification--info a{color:#83b7f3}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#2681ea;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #83b7f3;outline-offset:2px}.tox .tox-notification--info a:active{color:#1368c9;text-decoration:underline}.tox .tox-notification--info svg{fill:#fff}.tox .tox-notification__body{align-self:center;color:#fff;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#222f3e;border:1px solid #000;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#222f3e transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#000 transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #222f3e transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #000 transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #222f3e transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #000 transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #222f3e;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #000;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#222f3e;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #000;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(255,255,255,.5);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#222f3e;border-top:1px solid #000;color:#fff;display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:#fff;position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(255,255,255,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#fff}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px -4px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(34,47,62,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#222f3e;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:3px 0 2px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#fff}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#4a5562;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:hover svg{fill:#fff}.tox .tox-tbtn:active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:active svg{fill:#fff}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#757d87;border:0;box-shadow:none;color:#fff;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#fff}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#fff}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:0 0;border-radius:3px;display:flex;margin:3px 0 2px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#4a5562}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#4a5562;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#fff;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#4a5562;color:#fff}.tox .tox-number-input input:focus{background-color:#4a5562}.tox .tox-number-input input:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button{color:#fff;height:34px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#fff;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#4a5562;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:hover svg{fill:#fff}.tox .tox-number-input button:active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-number-input button:active svg{fill:#fff}.tox .tox-number-input button:disabled{background:#222f3e;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(255,255,255,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#4a5562}.tox .tox-tbtn--select{margin:3px 0 2px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:0 0}.tox .tox-tbtn--bespoke:focus{background:#4a5562}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:0}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:3px 0 2px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #4a5562 inset}.tox .tox-split-button:focus{background:#4a5562;box-shadow:none;color:#fff;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(255,255,255,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#222f3e;box-shadow:none;color:rgba(255,255,255,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#222f3e}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#222f3e;background-image:repeating-linear-gradient(#000 0 1px,transparent 1px 39px);background-position:center top 39px;background-repeat:no-repeat;background-size:calc(100% - 4px * 2) calc(100% - 39px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 4px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid #000;margin-top:-1px;padding-bottom:0;padding-top:0}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#222f3e;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:3px;box-shadow:0 0 2px 0 rgba(42,55,70,.2),0 4px 8px 0 rgba(42,55,70,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 4px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #000}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #000}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#2a3746;border-radius:3px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #2a3746;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #2a3746;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #2a3746;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #2a3746;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#fff}.tox .tox-tree .tox-trbtn:focus{background:#4a5562;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:active{background:#6ea9d0;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn:active svg{fill:#fff}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#6ea9d0;border:0;box-shadow:none;color:#fff}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#fff}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#fff}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#fff}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#fff}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#2b3b4e;border-radius:4px;border-top:1px solid #000;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #000;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #000;color:#fff;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0;border-radius:3px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #000;border-radius:3px;color:#fff;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#4a5562;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:3px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#6ea9d0;box-shadow:none;color:#fff}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(255,255,255,.5);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#222f3e;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:8px 8px 0 8px;position:relative}.tox .tox-view__label{color:#fff;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:8px 8px 0 8px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #000;border-radius:3px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #000;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #000;border-radius:3px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:none;padding:0}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce-inline .tox-editor-container{overflow:hidden}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:none;box-shadow:none}.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:0}.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-pop{box-shadow:none}.tox .tox-number-input,.tox .tox-split-button,.tox .tox-tbtn,.tox .tox-tbtn--select{margin:2px 0 3px 0}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e!important}.tox .tox-menubar+.tox-toolbar-overlord{border-top:none}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #000;margin-top:-1px}.tox.tox-tinymce-aux .tox-toolbar__overflow{border:1px solid #000;padding:0}.tox .tox-pop .tox-pop__dialog .tox-toolbar{padding:0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #000}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #000}.tox .tox-toolbar__group{padding:0 4px 0 4px}.tox .tox-collection__item{border-radius:0;cursor:pointer}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#fff}.tox .tox-statusbar__branding svg{fill:rgba(255,255,255,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#fff}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-statusbar__resize-handle{padding-bottom:0;padding-right:0}.tox .tox-button::before{display:none}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js
new file mode 100644
index 0000000..8490587
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5-dark/skin.shadowdom.css', "body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}")
+//# sourceMappingURL=skin.shadowdom.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css
new file mode 100644
index 0000000..8745951
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css
@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.js
new file mode 100644
index 0000000..30890e1
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5/content.inline.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}")
+//# sourceMappingURL=content.inline.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.min.css
new file mode 100644
index 0000000..747b11d
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.inline.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.js
new file mode 100644
index 0000000..25a7a7b
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5/content.css', ".mce-content-body .mce-item-anchor{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A\")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A\"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected=\"2\"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A\") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected=\"2\"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A\") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url(\"data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A\");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border=\"0\"],.mce-item-table[border=\"0\"] caption,.mce-item-table[border=\"0\"] td,.mce-item-table[border=\"0\"] th,table[style*=\"border-width: 0px\"],table[style*=\"border-width: 0px\"] caption,table[style*=\"border-width: 0px\"] td,table[style*=\"border-width: 0px\"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}")
+//# sourceMappingURL=content.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.min.css
new file mode 100644
index 0000000..1e3ee0c
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/content.min.css
@@ -0,0 +1 @@
+.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center}.mce-content-body .mce-item-anchor:empty{cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor:not(:empty){background-position-x:2px;display:inline-block;padding-left:12px}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment[contenteditable=false]:not([data-mce-selected]),.tox-comments-visible span.tox-comment img:not([data-mce-selected]),.tox-comments-visible span.tox-comment span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment>video:not([data-mce-selected]){outline:3px solid #ffe89d}.tox-comments-visible .tox-comment[contenteditable=false][data-mce-annotation-active=true]:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] img:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true] span.mce-preview-object:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>audio:not([data-mce-selected]),.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]>video:not([data-mce-selected]){outline:3px solid #fed635}.tox-comments-visible span.tox-comment:not([data-mce-selected]){background-color:#ffe89d;outline:0}.tox-comments-visible span.tox-comment[data-mce-annotation-active=true]:not([data-mce-selected=inline-boundary]){background-color:#fed635}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}div.mce-footnotes hr{margin-inline-end:auto;margin-inline-start:0;width:25%}div.mce-footnotes li>a.mce-footnotes-backlink{text-decoration:none}@media print{sup.mce-footnote a{color:#000;text-decoration:none}div.mce-footnotes{break-inside:avoid;width:100%}div.mce-footnotes li>a.mce-footnotes-backlink{display:none}}tiny-math-block{display:flex;justify-content:center;margin:16px 0 16px 0}tiny-math-inline{display:inline-block}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-content-body .mce-mergetag{cursor:default!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body .mce-mergetag:hover{background-color:rgba(0,108,231,.1)}.mce-content-body .mce-mergetag-affix{background-color:rgba(0,108,231,.1);color:#006ce7}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}@media (forced-colors:active){.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:highlight;filter:brightness(30%);z-index:-1}}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:1298}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body details[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body img[data-mce-selected]::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc ul>li{list-style-type:none}[data-mce-block]{display:block}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.js
new file mode 100644
index 0000000..1a2bba5
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5/skin.css', ".tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #ccc;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#fff;border:1px solid #ccc;border-radius:0;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(30,113,170,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#207ab7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#1c6ca1}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#185d8c}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.08);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#c00}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#527530}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#527530}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#ccc;border-radius:0;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:3px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #207ab7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#114060;background-image:none;border-color:#114060;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#f0f0f0;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#f0f0f0;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#222f3e;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#f0f0f0;background-image:none;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:hover:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:active:not(:disabled){background-color:#d6d6d6;background-image:none;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled{background-color:#b1ccdf;background-image:none;border-color:#b1ccdf;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#b1ccdf;background-image:none;border-color:#b1ccdf;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#9fc1d7;background-image:none;border-color:#9fc1d7;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#9fc1d7;background-image:none;border-color:#9fc1d7;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#8db5d0;background-image:none;border-color:#8db5d0;box-shadow:none;color:#222f3e}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked[disabled]{background-color:#f0f0f0;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:focus:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:active:not(:disabled){background-color:#d6d6d6;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#222f3e}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(34,47,62,.3)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(34,47,62,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#ccc;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#e6e6e6;color:rgba(34,47,62,.7);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#222f3e;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#fff;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active{background-color:#dee0e2}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#c8cbcf;color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#fff;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#dee0e2;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#dee0e2;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#c8cbcf;color:#222f3e}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#dee0e2;color:#222f3e;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(34,47,62,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:3px 0 2px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #ccc}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #ccc}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#222f3e;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#dee0e2}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#222f3e;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#fff;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#222f3e;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#222f3e;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#222f3e;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(34,47,62,.7);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#fff;bottom:0;content:\"\";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(255,255,255,0),#fff);bottom:0;content:\"\";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#fff;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#222f3e;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#fff;box-shadow:0 0 8px 8px #fff;color:#222f3e;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#fff;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(34,47,62,.7)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#222f3e;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(255,255,255,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#fff}.tox .tox-dialog{background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#fff;border-bottom:none;color:#222f3e;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#222f3e;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(34,47,62,.7);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#114060;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #207ab7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#092335;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#222f3e}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#222f3e;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#222f3e;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#fff;border-top:1px solid #ccc;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(255,255,255,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #404040}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #ccc;border-radius:3px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:3px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #ccc;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(34,47,62,.7);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:0 solid transparent;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:0 solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #ccc}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#fff;border-bottom:none;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #ccc;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#fff;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #fff;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(34,47,62,.7);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#222f3e}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#222f3e}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size=\"0\"],.tox:not([dir=rtl]) .tox-selectfield select[size=\"1\"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size=\"0\"],.tox[dir=rtl] .tox-selectfield select[size=\"1\"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#fff;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#ccc;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:0 -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:rgba(34,47,62,.7);display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E\") left 0 top 0 #fff;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 4px 0 4px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E\") left 0 top 0 #fff;background-color:#fff;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#dee0e2;border:0;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#207ab7;box-shadow:none}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#222f3e}.tox .tox-notification--success p{color:#222f3e}.tox .tox-notification--success a{color:#517342}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#24321d;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #517342;outline-offset:2px}.tox .tox-notification--success a:active{color:#0d120a;text-decoration:underline}.tox .tox-notification--success svg{fill:#222f3e}.tox .tox-notification--error{background-color:#f5cccc;border-color:#f0b3b3;color:#222f3e}.tox .tox-notification--error p{color:#222f3e}.tox .tox-notification--error a{color:#77181f}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#220709;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #77181f;outline-offset:2px}.tox .tox-notification--error a:active{color:#000;text-decoration:underline}.tox .tox-notification--error svg{fill:#222f3e}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fff5cc;border-color:#fff0b3;color:#222f3e}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#222f3e}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#7a6e25}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#2c280d;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #7a6e25;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#050502;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#222f3e}.tox .tox-notification--info{background-color:#d6e7fb;border-color:#c1dbf9;color:#222f3e}.tox .tox-notification--info p{color:#222f3e}.tox .tox-notification--info a{color:#2a64a6}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#163355;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #2a64a6;outline-offset:2px}.tox .tox-notification--info a:active{color:#0b1a2c;text-decoration:underline}.tox .tox-notification--info svg{fill:#222f3e}.tox .tox-notification__body{align-self:center;color:#222f3e;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#fff transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#ccc transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #fff transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #ccc transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #fff transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #ccc transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #fff;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #ccc;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#fff;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #ccc;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(34,47,62,.7);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#fff;border-top:1px solid #ccc;color:rgba(34,47,62,.7);display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(34,47,62,.7);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(34,47,62,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#222f3e}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px -4px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(255,255,255,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:3px 0 2px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#222f3e}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#dee0e2;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:hover svg{fill:#222f3e}.tox .tox-tbtn:active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:active svg{fill:#222f3e}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#222f3e}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:0 0;border-radius:3px;display:flex;margin:3px 0 2px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#dee0e2}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#dee0e2;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#222f3e;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#dee0e2;color:#222f3e}.tox .tox-number-input input:focus{background-color:#dee0e2}.tox .tox-number-input input:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button{color:#222f3e;height:34px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#222f3e;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#dee0e2;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:hover svg{fill:#222f3e}.tox .tox-number-input button:active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:active svg{fill:#222f3e}.tox .tox-number-input button:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#dee0e2}.tox .tox-tbtn--select{margin:3px 0 2px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:0 0}.tox .tox-tbtn--bespoke:focus{background:#dee0e2}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:0}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:3px 0 2px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #dee0e2 inset}.tox .tox-split-button:focus{background:#dee0e2;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#fff;box-shadow:none;color:rgba(34,47,62,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#fff}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#fff;background-image:repeating-linear-gradient(#ccc 0 1px,transparent 1px 39px);background-position:center top 39px;background-repeat:no-repeat;background-size:calc(100% - 4px * 2) calc(100% - 39px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 4px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid #ccc;margin-top:-1px;padding-bottom:0;padding-top:0}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#fff;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 4px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #ccc}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #ccc}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#222f3e;border-radius:3px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #222f3e;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #222f3e;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #222f3e;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #222f3e;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#222f3e}.tox .tox-tree .tox-trbtn:focus{background:#dee0e2;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active{background:#b1d0e6;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:active svg{fill:#222f3e}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#b1d0e6;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#fff;border-radius:4px;border-top:1px solid #ccc;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #ccc;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #ccc;color:#222f3e;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0;border-radius:3px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #ccc;border-radius:3px;color:#222f3e;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#dee0e2;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:3px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#b1d0e6;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(34,47,62,.7);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#fff;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:8px 8px 0 8px;position:relative}.tox .tox-view__label{color:#222f3e;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:8px 8px 0 8px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #ccc;border-radius:3px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #ccc;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #ccc;border-radius:3px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:\"\";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:none;padding:0}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce-inline .tox-editor-container{overflow:hidden}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:none;box-shadow:none}.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:0}.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-pop{box-shadow:none}.tox .tox-number-input,.tox .tox-split-button,.tox .tox-tbtn,.tox .tox-tbtn--select{margin:2px 0 3px 0}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url(\"data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E\") left 0 top 0 #fff!important}.tox .tox-menubar+.tox-toolbar-overlord{border-top:none}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #ccc;margin-top:-1px}.tox.tox-tinymce-aux .tox-toolbar__overflow{border:1px solid #ccc;padding:0}.tox .tox-pop .tox-pop__dialog .tox-toolbar{padding:0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #ccc}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #ccc}.tox .tox-toolbar__group{padding:0 4px 0 4px}.tox .tox-collection__item{border-radius:0;cursor:pointer}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-statusbar__resize-handle{padding-bottom:0;padding-right:0}.tox .tox-button::before{display:none}")
+//# sourceMappingURL=skin.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.min.css
new file mode 100644
index 0000000..ea1c617
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.min.css
@@ -0,0 +1 @@
+.tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #ccc;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox.tox-tinymce-inline{border:none;box-shadow:none;overflow:initial}.tox.tox-tinymce-inline .tox-editor-container{overflow:initial}.tox.tox-tinymce-inline .tox-editor-header{background-color:#fff;border:1px solid #ccc;border-radius:0;box-shadow:none;overflow:hidden}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox[dir=rtl] .tox-icon--flip svg{transform:rotateY(180deg)}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>div>div .tox-icon svg{display:block}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(30,113,170,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon{background-color:#207ab7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:hover{background-color:#1c6ca1}.tox .tox-dialog__body-content .accessibility-issue--info a.tox-button--naked.tox-button--icon:active{background-color:#185d8c}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.08);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#8f5d00}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon{background-color:#ffe89d;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:hover{background-color:#f2d574;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn a.tox-button--naked.tox-button--icon:active{background-color:#e8c657;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#c00}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon{background-color:#f2bfbf;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:focus,.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:hover{background-color:#e9a4a4;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error a.tox-button--naked.tox-button--icon:active{background-color:#ee9494;color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.1);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{display:none}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#527530}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#527530}.tox .tox-dialog__body-content .accessibility-issue__header .tox-form__group h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{font-size:14px;margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox .mce-codemirror{background:#fff;bottom:0;font-size:13px;left:0;position:absolute;right:0;top:0;z-index:1}.tox .mce-codemirror.tox-inline-codemirror{margin:8px;position:absolute}.tox .tox-advtemplate .tox-form__grid{flex:1}.tox .tox-advtemplate .tox-form__grid>div:first-child{display:flex;flex-direction:column;width:30%}.tox .tox-advtemplate .tox-form__grid>div:first-child>div:nth-child(2){flex-basis:0;flex-grow:1;overflow:auto}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-advtemplate .tox-form__grid>div:first-child{width:100%}}.tox .tox-advtemplate iframe{border-color:#ccc;border-radius:0;border-style:solid;border-width:1px;margin:0 10px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bottom-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;position:relative;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button::before{border-radius:3px;bottom:-1px;box-shadow:inset 0 0 0 1px #fff,0 0 0 2px #207ab7;content:'';left:-1px;opacity:0;pointer-events:none;position:absolute;right:-1px;top:-1px}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:focus:not(:disabled)::before{opacity:1}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled[disabled]{background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button.tox-button--enabled:focus:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:hover:not(:disabled){background-color:#154f76;background-image:none;border-color:#154f76;box-shadow:none;color:#fff}.tox .tox-button.tox-button--enabled:active:not(:disabled){background-color:#114060;background-image:none;border-color:#114060;box-shadow:none;color:#fff}.tox .tox-button--icon-and-text,.tox .tox-button.tox-button--icon-and-text,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text{display:flex;padding:5px 4px}.tox .tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--icon-and-text .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon-and-text .tox-icon svg{display:block;fill:currentColor}.tox .tox-button--secondary{background-color:#f0f0f0;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#f0f0f0;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#222f3e;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#f0f0f0;background-image:none;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:hover:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:active:not(:disabled){background-color:#d6d6d6;background-image:none;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled{background-color:#b1ccdf;background-image:none;border-color:#b1ccdf;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled[disabled]{background-color:#b1ccdf;background-image:none;border-color:#b1ccdf;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary.tox-button--enabled:focus:not(:disabled){background-color:#9fc1d7;background-image:none;border-color:#9fc1d7;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:hover:not(:disabled){background-color:#9fc1d7;background-image:none;border-color:#9fc1d7;box-shadow:none;color:#222f3e}.tox .tox-button--secondary.tox-button--enabled:active:not(:disabled){background-color:#8db5d0;background-image:none;border-color:#8db5d0;box-shadow:none;color:#222f3e}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked[disabled]{background-color:#f0f0f0;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:focus:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:active:not(:disabled){background-color:#d6d6d6;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#222f3e}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(34,47,62,.3)}@media (forced-colors:active){.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:currentColor!important}}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(34,47,62,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#ccc;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#e6e6e6;color:rgba(34,47,62,.7);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;border-radius:3px;color:#222f3e;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#fff;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active{background-color:#dee0e2}.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{background-color:#c8cbcf;color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--enabled,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active,.tox .tox-collection--toolbar .tox-collection__item--enabled.tox-collection__item--active:hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#fff;position:relative}.tox .tox-collection--toolbar .tox-collection__item--active:hover{background-color:#dee0e2;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus{background-color:#dee0e2;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:focus::after{border:2px solid highlight}}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#c8cbcf;color:#222f3e}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#dee0e2;color:#222f3e;position:relative;z-index:1}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent inset;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled):focus::after{border:2px solid highlight}}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){border:solid 1px}}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}@media (forced-colors:active){.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled):hover{border-radius:3px;outline:solid 1px}}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;font-size:14px;font-style:normal;font-weight:400;line-height:24px;max-width:100%;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:currentColor;display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:currentColor}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-collection__item--state-disabled .tox-collection__item-caret svg{fill:rgba(34,47,62,.5)}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:3px 0 2px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #ccc}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #ccc}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}@media (forced-colors:active){.tox .tox-hue-slider,.tox .tox-rgb-form .tox-rgba-preview{background-color:currentColor!important;border:1px solid highlight!important;forced-color-adjust:none}}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-spectrum:focus,.tox .tox-sv-palette-spectrum:focus{outline:#08f solid}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}@media (forced-colors:active){.tox .tox-swatches__row{forced-color-adjust:none}}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{fill:#222f3e;height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#dee0e2}.tox div.tox-swatch:not(.tox-swatch--remove) svg{display:none;fill:#222f3e;height:24px;margin:calc((30px - 24px)/ 2) calc((30px - 24px)/ 2);width:24px}.tox div.tox-swatch:not(.tox-swatch--remove) svg path{fill:#fff;paint-order:stroke;stroke:#222f3e;stroke-width:2px}.tox div.tox-swatch:not(.tox-swatch--remove).tox-collection__item--enabled svg{display:block}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#fff;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#222f3e;display:flex;justify-content:space-between}.tox .tox-comment__date{color:#222f3e;font-size:12px;line-height:18px}.tox .tox-comment__body{color:#222f3e;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(34,47,62,.7);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#fff;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(255,255,255,0),#fff);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#fff;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#222f3e;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#fff;box-shadow:0 0 8px 8px #fff;color:#222f3e;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#fff;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(34,47,62,.7)}.tox .tox-user__avatar img{border-radius:50%;height:36px;object-fit:cover;vertical-align:middle;width:36px}.tox .tox-user__name{color:#222f3e;font-size:14px;font-style:normal;font-weight:700;line-height:18px;text-transform:none}.tox:not([dir=rtl]) .tox-user__avatar img,.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar img,.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(255,255,255,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#fff}.tox .tox-dialog{background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;max-height:calc(100vh - 8px * 2);width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#fff;border-bottom:none;color:#222f3e;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#222f3e;display:flex;flex:1;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;flex-shrink:0;padding:16px 16px}@media only screen and (min-width:768px){.tox .tox-dialog__body-nav{max-width:11em}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(34,47,62,.7);display:inline-block;flex-shrink:0;font-size:14px;line-height:1.3;margin-bottom:8px;max-width:13em;text-decoration:none}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}@media (forced-colors:active){.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid highlight;color:highlight}}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;max-height:min(650px,calc(100vh - 110px));overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:underline}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#114060;text-decoration:underline}.tox .tox-dialog__body-content a:focus-visible{border-radius:1px;outline:2px solid #207ab7;outline-offset:2px}.tox .tox-dialog__body-content a:active{color:#092335;text-decoration:underline}.tox .tox-dialog__body-content svg{fill:#222f3e}.tox .tox-dialog__body-content strong{font-weight:700}.tox .tox-dialog__body-content ul{list-style-type:disc}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{padding-inline-start:2.5rem}.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{margin-bottom:16px}.tox .tox-dialog__body-content dd,.tox .tox-dialog__body-content dl,.tox .tox-dialog__body-content dt,.tox .tox-dialog__body-content ol,.tox .tox-dialog__body-content ul{display:block;margin-inline-end:0;margin-inline-start:0}.tox .tox-dialog__body-content .tox-form__group h1{color:#222f3e;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#222f3e;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--center{text-align:center}.tox .tox-dialog__body-content .tox-form__group .tox-label.tox-label--end{text-align:end}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--fullscreen{height:100%;max-width:100%}.tox .tox-dialog--fullscreen .tox-dialog__body-content{max-height:100%}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#fff;border-top:1px solid #ccc;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(255,255,255,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table thead th:first-child{padding-right:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #404040}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__table td:first-child{padding-right:8px}.tox .tox-dialog__iframe{min-height:200px}.tox .tox-dialog__iframe.tox-dialog__iframe--opaque{background:#fff}.tox .tox-navobj-bordered{position:relative}.tox .tox-navobj-bordered::before{border:1px solid #ccc;border-radius:3px;content:'';inset:0;opacity:1;pointer-events:none;position:absolute;z-index:1}.tox .tox-navobj-bordered iframe{border-radius:3px}.tox .tox-navobj-bordered-focus.tox-navobj-bordered::before{border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #ccc;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(34,47,62,.7);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-edit-area::before{border:0 solid transparent;border-radius:4px;content:'';inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .15s;z-index:1}@media (forced-colors:active){.tox .tox-edit-area::before{border:0 solid highlight}}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;height:100%;position:absolute;width:100%}.tox.tox-edit-focus .tox-edit-area::before{opacity:1}.tox.tox-inline-edit-area{border:1px dotted #ccc}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{display:grid;grid-template-columns:1fr min-content;z-index:2}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:#fff;border-bottom:none;box-shadow:none;padding:4px 0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(.tox-editor-dock-transition){transition:box-shadow .5s}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:1px solid #ccc;box-shadow:none}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:#fff;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:4px 0}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox.tox:not(.tox-tinymce-inline) .tox-editor-header.tox-editor-header--empty{background:0 0;border:none;box-shadow:none;padding:0}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-custom-preview{border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;flex:1;padding:8px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{box-sizing:border-box;max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}@media (forced-colors:active){.tox .tox-color-input span{border-color:currentColor;border-width:2px!important;forced-color-adjust:none}}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #fff;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}@media (forced-colors:active){.tox .tox-color-input span::before{border:none}}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(34,47,62,.7);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column}.tox .tox-form__group--stretched .tox-textarea{flex:1}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textarea-wrap .tox-textarea:focus,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-custom-editor:focus-within,.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea-wrap:focus-within,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#222f3e}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#222f3e}@media (forced-colors:active){.tox .tox-listbox__select-chevron svg{fill:currentColor!important}}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:2px solid rgba(32,122,183,.25)}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea-wrap{border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;display:flex;flex:1;overflow:hidden}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox .tox-textarea-wrap .tox-textarea{border:none}.tox .tox-textarea-wrap .tox-textarea:focus{border:none}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-imagepreview{background-color:#666;height:380px;overflow:hidden;position:relative;width:100%}.tox .tox-imagepreview.tox-imagepreview__loaded{overflow:auto}.tox .tox-imagepreview__container{display:flex;left:100vw;position:absolute;top:100vw}.tox .tox-imagepreview__image{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools .tox-spacer{flex:1}.tox .tox-image-tools .tox-bar{align-items:center;display:flex;height:60px;justify-content:center}.tox .tox-image-tools .tox-imagepreview,.tox .tox-image-tools .tox-imagepreview+.tox-bar{margin-top:8px}.tox .tox-image-tools .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-image-tools .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-image-tools .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-image-tools .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-image-tools .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-image-tools .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-image-tools .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox .tox-insert-table-picker{background-color:#fff;display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#ccc;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:0 -4px}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}@media (forced-colors:active){.tox .tox-insert-table-picker .tox-insert-table-picker__selected{border-color:Highlight;filter:contrast(50%)}}.tox .tox-insert-table-picker__label{color:rgba(34,47,62,.7);display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0 0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}@media only screen and (min-width:768px){.tox .tox-menu .tox-collection__item-label{overflow-wrap:break-word;word-break:normal}.tox .tox-dialog__popups .tox-menu .tox-collection__item-label{word-break:break-all}}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;grid-column:1/-1;grid-row:1;padding:0 4px 0 4px}.tox .tox-promotion+.tox-menubar{grid-column:1}.tox .tox-promotion{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff;background-color:#fff;grid-column:2;grid-row:1;padding-inline-end:8px;padding-inline-start:4px;padding-top:5px}.tox .tox-promotion-link{align-items:unsafe center;background-color:#e8f1f8;border-radius:5px;color:#086be6;cursor:pointer;display:flex;font-size:14px;height:26.6px;padding:4px 8px;white-space:nowrap}.tox .tox-promotion-link:hover{background-color:#b4d7ff}.tox .tox-promotion-link:focus{background-color:#d9edf7}.tox .tox-mbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#dee0e2;border:0;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-mbtn:focus:not(:disabled)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-mbtn:focus:not(:disabled)::after{border:2px solid highlight}}.tox .tox-mbtn--active,.tox .tox-mbtn:not(:disabled).tox-mbtn--active:focus{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:grid;font-size:14px;font-weight:400;grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-left:auto;margin-right:auto;margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in;width:-moz-max-content;width:max-content}.tox .tox-notification a{cursor:pointer;text-decoration:underline}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification:focus{border-color:#207ab7;box-shadow:none}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#222f3e}.tox .tox-notification--success p{color:#222f3e}.tox .tox-notification--success a{color:#517342}.tox .tox-notification--success a:focus,.tox .tox-notification--success a:hover{color:#24321d;text-decoration:underline}.tox .tox-notification--success a:focus-visible{border-radius:1px;outline:2px solid #517342;outline-offset:2px}.tox .tox-notification--success a:active{color:#0d120a;text-decoration:underline}.tox .tox-notification--success svg{fill:#222f3e}.tox .tox-notification--error{background-color:#f5cccc;border-color:#f0b3b3;color:#222f3e}.tox .tox-notification--error p{color:#222f3e}.tox .tox-notification--error a{color:#77181f}.tox .tox-notification--error a:focus,.tox .tox-notification--error a:hover{color:#220709;text-decoration:underline}.tox .tox-notification--error a:focus-visible{border-radius:1px;outline:2px solid #77181f;outline-offset:2px}.tox .tox-notification--error a:active{color:#000;text-decoration:underline}.tox .tox-notification--error svg{fill:#222f3e}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fff5cc;border-color:#fff0b3;color:#222f3e}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#222f3e}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#7a6e25}.tox .tox-notification--warn a:focus,.tox .tox-notification--warn a:hover,.tox .tox-notification--warning a:focus,.tox .tox-notification--warning a:hover{color:#2c280d;text-decoration:underline}.tox .tox-notification--warn a:focus-visible,.tox .tox-notification--warning a:focus-visible{border-radius:1px;outline:2px solid #7a6e25;outline-offset:2px}.tox .tox-notification--warn a:active,.tox .tox-notification--warning a:active{color:#050502;text-decoration:underline}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#222f3e}.tox .tox-notification--info{background-color:#d6e7fb;border-color:#c1dbf9;color:#222f3e}.tox .tox-notification--info p{color:#222f3e}.tox .tox-notification--info a{color:#2a64a6}.tox .tox-notification--info a:focus,.tox .tox-notification--info a:hover{color:#163355;text-decoration:underline}.tox .tox-notification--info a:focus-visible{border-radius:1px;outline:2px solid #2a64a6;outline-offset:2px}.tox .tox-notification--info a:active{color:#0b1a2c;text-decoration:underline}.tox .tox-notification--info svg{fill:#222f3e}.tox .tox-notification__body{align-self:center;color:#222f3e;font-size:14px;grid-column-end:3;grid-column-start:2;grid-row-end:2;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{align-self:center;grid-column-end:2;grid-column-start:1;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{align-self:start;grid-column-end:4;grid-column-start:3;grid-row-end:2;grid-row-start:1;justify-self:end}.tox .tox-notification .tox-progress-bar{grid-column-end:4;grid-column-start:1;grid-row-end:3;grid-row-start:2;justify-self:center}.tox .tox-notification-container-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-notification-container-dock-fadein{opacity:1;visibility:visible}.tox .tox-notification-container-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-notification-container-dock-transition.tox-notification-container-dock-fadein{transition-delay:0s}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar,.tox .tox-pop--resizing .tox-toolbar__group{flex-wrap:nowrap}.tox .tox-pop--transition{transition:.15s ease;transition-property:left,right,top,bottom}.tox .tox-pop--transition::after,.tox .tox-pop--transition::before{transition:all .15s,visibility 0s,opacity 75ms ease 75ms}.tox .tox-pop__dialog{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;opacity:1;position:absolute;width:0}@media (forced-colors:active){.tox .tox-pop::after,.tox .tox-pop::before{content:none}}.tox .tox-pop.tox-pop--inset::after,.tox .tox-pop.tox-pop--inset::before{opacity:0;transition:all 0s .15s,visibility 0s,opacity 75ms ease}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#fff transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#ccc transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #fff transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #ccc transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #fff transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #ccc transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #fff;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #ccc;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;min-height:0}.tox .tox-sidebar{background-color:#fff;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #ccc;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-form__controls-h-stack>.tox-slider:not(:first-of-type){margin-inline-start:8px}.tox .tox-form__controls-h-stack>.tox-form__group+.tox-slider{margin-inline-start:32px}.tox .tox-form__controls-h-stack>.tox-slider+.tox-form__group{margin-inline-start:32px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(34,47,62,.7);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#fff;border-top:1px solid #ccc;color:rgba(34,47,62,.7);display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__right-container{display:flex;justify-content:flex-end;white-space:nowrap}.tox .tox-statusbar__help-text{text-align:center}.tox .tox-statusbar__text-container{align-items:flex-start;display:flex;flex:1 1 auto;height:16px;justify-content:space-between;overflow:hidden}@media only screen and (min-width:768px){.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__help-text,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__path,.tox .tox-statusbar__text-container.tox-statusbar__text-container-3-cols>.tox-statusbar__right-container{flex:0 0 calc(100% / 3)}}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-end{justify-content:flex-end}.tox .tox-statusbar__text-container.tox-statusbar__text-container--flex-start{justify-content:flex-start}.tox .tox-statusbar__text-container.tox-statusbar__text-container--space-around{justify-content:space-around}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}@media only screen and (max-width:767px){.tox .tox-statusbar__text-container .tox-statusbar__help-text{display:none}.tox .tox-statusbar__text-container .tox-statusbar__help-text:only-child{display:block}}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(34,47,62,.7);position:relative;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e;cursor:pointer}.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar a:focus-visible::after,.tox .tox-statusbar__path-item:focus-visible::after,.tox .tox-statusbar__wordcount:focus-visible::after{border:2px solid highlight}}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-bottom:3px;margin-left:4px;margin-right:calc(3px - 8px);margin-top:3px;padding-bottom:0;padding-left:0;padding-right:0;position:relative}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(34,47,62,.5)}.tox .tox-statusbar__resize-handle:focus svg,.tox .tox-statusbar__resize-handle:hover svg{fill:#222f3e}.tox .tox-statusbar__resize-handle:focus-visible{background-color:transparent;border-radius:1px 1px -4px 1px;box-shadow:0 0 0 2px transparent}.tox .tox-statusbar__resize-handle:focus-visible::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-statusbar__resize-handle:focus-visible::after{border:2px solid highlight}}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:2ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(255,255,255,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:#fff;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:3px 0 2px 0;outline:0;padding:0;text-transform:none;width:34px}@media (forced-colors:active){.tox .tox-tbtn.tox-tbtn:hover,.tox .tox-tbtn:hover{outline:1px dashed currentColor}.tox .tox-tbtn.tox-tbtn--active,.tox .tox-tbtn.tox-tbtn--enabled,.tox .tox-tbtn.tox-tbtn--enabled:focus,.tox .tox-tbtn.tox-tbtn--enabled:hover,.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){outline:1px solid currentColor;position:relative}}.tox .tox-tbtn svg{display:block;fill:#222f3e}@media (forced-colors:active){.tox .tox-tbtn svg{fill:currentColor!important}.tox .tox-tbtn svg.tox-tbtn--enabled,.tox .tox-tbtn svg:focus:not(.tox-tbtn--disabled){fill:currentColor!important}.tox .tox-tbtn svg .tox-tbtn:disabled,.tox .tox-tbtn svg .tox-tbtn:disabled:hover,.tox .tox-tbtn svg.tox-tbtn--disabled,.tox .tox-tbtn svg.tox-tbtn--disabled:hover{filter:contrast(0)}}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#dee0e2;border:0;box-shadow:none;position:relative;z-index:1}.tox .tox-tbtn:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn:focus::after{border:2px solid highlight}}.tox .tox-tbtn:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:hover svg{fill:#222f3e}.tox .tox-tbtn:active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:active svg{fill:#222f3e}.tox .tox-tbtn--disabled .tox-tbtn--enabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--active,.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:focus,.tox .tox-tbtn--enabled:hover{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e;position:relative}.tox .tox-tbtn--active>*,.tox .tox-tbtn--enabled:focus>*,.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--active svg,.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:focus svg,.tox .tox-tbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tbtn--active.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:focus.tox-tbtn--disabled svg,.tox .tox-tbtn--enabled:hover.tox-tbtn--disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--enabled:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-tbtn--enabled:focus::after{border:2px solid highlight}}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#222f3e}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-number-input{background:0 0;border-radius:3px;display:flex;margin:3px 0 2px 0;position:relative;width:auto}.tox .tox-number-input:focus{background:#dee0e2}.tox .tox-number-input:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper{display:flex;pointer-events:none;position:relative;text-align:center}.tox .tox-number-input .tox-input-wrapper:focus{background-color:#dee0e2;z-index:1}.tox .tox-number-input .tox-input-wrapper:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:focus::after{border:2px solid highlight}}.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input .tox-input-wrapper:has(input:focus)::after{border:2px solid highlight}}.tox .tox-number-input input{border-radius:3px;color:#222f3e;font-size:14px;margin:2px 0;pointer-events:all;position:relative;width:60px}.tox .tox-number-input input:hover{background:#dee0e2;color:#222f3e}.tox .tox-number-input input:focus{background-color:#dee0e2}.tox .tox-number-input input:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button{color:#222f3e;height:34px;position:relative;text-align:center;width:24px}@media (forced-colors:active){.tox .tox-number-input button:active,.tox .tox-number-input button:focus,.tox .tox-number-input button:hover{outline:1px solid currentColor!important}}.tox .tox-number-input button svg{display:block;fill:#222f3e;margin:0 auto;transform:scale(.67)}@media (forced-colors:active){.tox .tox-number-input button svg,.tox .tox-number-input button svg:active,.tox .tox-number-input button svg:hover{fill:currentColor!important}.tox .tox-number-input button svg:disabled{filter:contrast(0)}}.tox .tox-number-input button:focus{background:#dee0e2;z-index:1}.tox .tox-number-input button:focus::after{border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-number-input button:focus::after{border:2px solid highlight}}.tox .tox-number-input button:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:hover svg{fill:#222f3e}.tox .tox-number-input button:active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-number-input button:active svg{fill:#222f3e}.tox .tox-number-input button:disabled{background:#fff;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-number-input button:disabled svg{fill:rgba(34,47,62,.5)}.tox .tox-number-input button.minus{border-radius:3px 0 0 3px}.tox .tox-number-input button.plus{border-radius:0 3px 3px 0}.tox .tox-number-input:focus:not(:active)>.tox-input-wrapper,.tox .tox-number-input:focus:not(:active)>button{background:#dee0e2}.tox .tox-tbtn--select{margin:3px 0 2px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;height:initial;margin:0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-tbtn__select-chevron svg{fill:currentColor}}.tox .tox-tbtn--bespoke{background:0 0}.tox .tox-tbtn--bespoke:focus{background:#dee0e2}.tox .tox-tbtn--bespoke+.tox-tbtn--bespoke{margin-inline-start:0}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-tbtn--disabled .tox-tbtn__select-label,.tox .tox-tbtn--select:disabled .tox-tbtn__select-label{cursor:not-allowed}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:3px 0 2px 0}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #dee0e2 inset}.tox .tox-split-button:focus{background:#dee0e2;box-shadow:none;color:#222f3e;position:relative;z-index:1}.tox .tox-split-button:focus::after{pointer-events:none;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-split-button:focus::after{border:2px solid highlight}}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button>:nth-child(1){border-bottom-left-radius:3px;border-top-left-radius:3px}.tox .tox-split-button>:nth-child(2){border-bottom-right-radius:3px;border-top-right-radius:3px}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(34,47,62,.5)}@media (forced-colors:active){.tox .tox-split-button__chevron svg{fill:currentColor}}.tox .tox-split-button .tox-tbtn{margin:0}.tox .tox-split-button:focus .tox-tbtn{background-color:transparent}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:#fff;box-shadow:none;color:rgba(34,47,62,.5)}.tox.tox-platform-touch .tox-split-button .tox-tbtn--select{padding:0 0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:not(.tox-tbtn--select):first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-highlight-bg-color__color,.tox .tox-split-button.tox-tbtn--disabled svg #tox-icon-text-color__color{opacity:.6}.tox .tox-toolbar-overlord{background-color:#fff}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background-attachment:local;background-color:#fff;background-image:repeating-linear-gradient(#ccc 0 1px,transparent 1px 39px);background-position:center top 39px;background-repeat:no-repeat;background-size:calc(100% - 4px * 2) calc(100% - 39px);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0;transform:perspective(1px)}.tox .tox-toolbar-overlord>.tox-toolbar,.tox .tox-toolbar-overlord>.tox-toolbar__overflow,.tox .tox-toolbar-overlord>.tox-toolbar__primary{background-position:center top 0;background-size:calc(100% - 4px * 2) calc(100% - 0px)}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-anchorbar,.tox .tox-toolbar-overlord{grid-column:1/-1}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{border-top:1px solid #ccc;margin-top:-1px;padding-bottom:0;padding-top:0}@media (forced-colors:active){.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord{outline:1px solid currentColor}}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox .tox-toolbar-overlord .tox-toolbar:not(.tox-toolbar--scrolling):first-child,.tox .tox-toolbar-overlord .tox-toolbar__primary{background-position:center top 39px}.tox .tox-editor-header>.tox-toolbar--scrolling,.tox .tox-toolbar-overlord .tox-toolbar--scrolling:first-child{background-image:none}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#fff;background-position:center top 43px;background-size:calc(100% - 8px * 2) calc(100% - 51px);border:none;border-radius:3px;box-shadow:0 0 2px 0 rgba(34,47,62,.2),0 4px 8px 0 rgba(34,47,62,.15);overscroll-behavior:none;padding:4px 0}@media (forced-colors:active){.tox.tox-tinymce-aux .tox-toolbar__overflow{border:solid}}.tox-pop .tox-pop__dialog .tox-toolbar{background-position:center top 43px;background-size:calc(100% - 4px * 2) calc(100% - 51px);padding:4px 0}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #ccc}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #ccc}.tox .tox-tooltip{display:inline-block;max-width:15em;padding:8px;pointer-events:none;position:relative;width:-moz-max-content;width:max-content;z-index:1150}.tox .tox-tooltip__body{background-color:#222f3e;border-radius:3px;box-shadow:none;color:#fff;font-size:12px;font-style:normal;font-weight:600;overflow-wrap:break-word;padding:4px 6px;text-transform:none}@media (forced-colors:active){.tox .tox-tooltip__body{outline:outset 1px}}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #222f3e;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #222f3e;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #222f3e;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #222f3e;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-tree{display:flex;flex-direction:column}.tox .tox-tree .tox-trbtn{align-items:center;background:0 0;border:0;border-radius:4px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:28px;margin-bottom:4px;margin-top:4px;outline:0;overflow:hidden;padding:0;padding-left:8px;text-transform:none}.tox .tox-tree .tox-trbtn .tox-tree__label{cursor:default;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-tree .tox-trbtn svg{display:block;fill:#222f3e}.tox .tox-tree .tox-trbtn:focus{background:#dee0e2;border:0;box-shadow:none}.tox .tox-tree .tox-trbtn:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active{background:#b1d0e6;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn:active svg{fill:#222f3e}.tox .tox-tree .tox-trbtn--disabled,.tox .tox-tree .tox-trbtn--disabled:hover,.tox .tox-tree .tox-trbtn:disabled,.tox .tox-tree .tox-trbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tree .tox-trbtn--disabled svg,.tox .tox-tree .tox-trbtn--disabled:hover svg,.tox .tox-tree .tox-trbtn:disabled svg,.tox .tox-tree .tox-trbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tree .tox-trbtn--enabled,.tox .tox-tree .tox-trbtn--enabled:hover{background:#b1d0e6;border:0;box-shadow:none;color:#222f3e}.tox .tox-tree .tox-trbtn--enabled:hover>*,.tox .tox-tree .tox-trbtn--enabled>*{transform:none}.tox .tox-tree .tox-trbtn--enabled svg,.tox .tox-tree .tox-trbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled){color:#222f3e}.tox .tox-tree .tox-trbtn:focus:not(.tox-trbtn--disabled) svg{fill:#222f3e}.tox .tox-tree .tox-trbtn:active>*{transform:none}.tox .tox-tree .tox-trbtn--return{align-self:stretch;height:unset;width:16px}.tox .tox-tree .tox-trbtn--labeled{padding:0 4px;width:unset}.tox .tox-tree .tox-trbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tree .tox-tree--directory{display:flex;flex-direction:column}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label{font-weight:700}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:focus .tox-mbtn svg,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label .tox-chevron{margin-right:6px}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--shrinking) .tox-chevron{transition:transform .5s ease-in-out}.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--growing) .tox-chevron,.tox .tox-tree .tox-tree--directory .tox-tree--directory__label:has(+.tox-tree--directory__children--open) .tox-chevron{transform:rotate(90deg)}.tox .tox-tree .tox-tree--leaf__label{font-weight:400}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn{margin-left:auto}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn svg{fill:transparent}.tox .tox-tree .tox-tree--leaf__label .tox-mbtn.tox-mbtn--active svg,.tox .tox-tree .tox-tree--leaf__label .tox-mbtn:focus svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover .tox-mbtn svg{fill:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover){background-color:transparent;color:#222f3e}.tox .tox-tree .tox-tree--leaf__label:hover:has(.tox-mbtn:hover) .tox-chevron svg{fill:#222f3e}.tox .tox-tree .tox-tree--directory__children{overflow:hidden;padding-left:16px}.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--growing,.tox .tox-tree .tox-tree--directory__children.tox-tree--directory__children--shrinking{transition:height .5s ease-in-out}.tox .tox-tree .tox-trbtn.tox-tree--leaf__label{display:flex;justify-content:space-between}.tox .tox-revisionhistory__pane{padding:0!important}.tox .tox-revisionhistory__container{display:flex;flex-direction:column;height:100%}.tox .tox-revisionhistory{background-color:#fff;border-radius:4px;border-top:1px solid #ccc;display:flex;flex:1;height:100%;margin-top:8px;overflow-x:auto;overflow-y:hidden;position:relative;width:100%}.tox .tox-revisionhistory--align-right{margin-left:auto}.tox .tox-revisionhistory__iframe{flex:1}.tox .tox-revisionhistory__sidebar{border-left:1px solid #ccc;height:100%;max-width:360px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__sidebar-title{border-bottom:1px solid #ccc;color:#222f3e;font-size:20px;font-weight:400;height:60px;min-width:192px;padding:16px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions{flex-direction:column;max-height:calc(100% - 60px);min-width:192px;overflow-y:auto;padding:8px}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus{height:100%;position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0;border-radius:3px;bottom:1px;left:1px;right:1px;top:1px}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card{border:1px solid #ccc;border-radius:3px;color:#222f3e;cursor:pointer;font-size:14px;margin-bottom:8px;padding:8px;text-overflow:ellipsis;text-wrap:nowrap;width:100%}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:hover{background-color:#dee0e2;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus{position:relative;z-index:1}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border-radius:3px!important;border-radius:3px;bottom:0;box-shadow:0 0 0 0 transparent;content:'';left:0;position:absolute;right:0;top:0}@media (forced-colors:active){.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card:focus::after{border:2px solid highlight}}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__card.tox-revisionhistory__card--selected{background-color:#b1d0e6;box-shadow:none;color:#222f3e}.tox .tox-revisionhistory__sidebar .tox-revisionhistory__revisions .tox-revisionhistory__norevision{color:rgba(34,47,62,.7);font-size:16px;line-height:24px;padding:5px 5.5px}.tox .tox-view-wrap,.tox .tox-view-wrap__slot-container{background-color:#fff;display:flex;flex:1;flex-direction:column;height:100%}.tox .tox-view{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-view__header{align-items:center;display:flex;font-size:16px;justify-content:space-between;padding:8px 8px 0 8px;position:relative}.tox .tox-view__label{color:#222f3e;font-weight:700;line-height:24px;padding:4px 16px;text-align:center;white-space:nowrap}.tox .tox-view__label--normal{font-size:16px}.tox .tox-view__label--large{font-size:20px}.tox .tox-view--mobile.tox-view__header,.tox .tox-view--mobile.tox-view__toolbar{padding:8px}.tox .tox-view--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-view__toolbar{display:flex;flex-direction:row;gap:8px;justify-content:space-between;overflow-x:auto;padding:8px 8px 0 8px}.tox .tox-view__toolbar__group{display:flex;flex-direction:row;gap:12px}.tox .tox-view__header-end,.tox .tox-view__header-start{display:flex}.tox .tox-view__pane{height:100%;padding:8px;position:relative;width:100%}.tox .tox-view__pane_panel{border:1px solid #ccc;border-radius:3px}.tox:not([dir=rtl]) .tox-view__header .tox-view__header-end>*,.tox:not([dir=rtl]) .tox-view__header .tox-view__header-start>*{margin-left:8px}.tox[dir=rtl] .tox-view__header .tox-view__header-end>*,.tox[dir=rtl] .tox-view__header .tox-view__header-start>*{margin-right:8px}.tox .tox-well{border:1px solid #ccc;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #ccc;border-radius:3px;display:flex;flex:1;overflow:hidden;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1}.tox:not(.tox-tinymce-inline) .tox-editor-header{background-color:none;padding:0}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce-inline .tox-editor-container{overflow:hidden}.tox:not(.tox-tinymce-inline).tox-tinymce--toolbar-bottom .tox-editor-header{border-top:none;box-shadow:none}.tox.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25);padding:0}.tox.tox.tox-tinymce--toolbar-sticky-on.tox-tinymce--toolbar-bottom .tox-editor-header{box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-pop{box-shadow:none}.tox .tox-number-input,.tox .tox-split-button,.tox .tox-tbtn,.tox .tox-tbtn--select{margin:2px 0 3px 0}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff!important}.tox .tox-menubar+.tox-toolbar-overlord{border-top:none}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #ccc;margin-top:-1px}.tox.tox-tinymce-aux .tox-toolbar__overflow{border:1px solid #ccc;padding:0}.tox .tox-pop .tox-pop__dialog .tox-toolbar{padding:0}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #ccc}.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #ccc}.tox .tox-toolbar__group{padding:0 4px 0 4px}.tox .tox-collection__item{border-radius:0;cursor:pointer}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){color:#222f3e}.tox .tox-statusbar__branding svg{fill:rgba(34,47,62,.8);height:1em;margin-left:.3em;width:auto}@media (forced-colors:active){.tox .tox-statusbar__branding svg{fill:currentColor}}.tox .tox-statusbar__branding a{align-items:center;display:inline-flex}.tox .tox-statusbar__branding a:focus:not(:disabled):not([aria-disabled=true]) svg,.tox .tox-statusbar__branding a:hover:not(:disabled):not([aria-disabled=true]) svg{fill:#222f3e}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar__branding svg{margin-left:0;margin-right:.3em}.tox .tox-statusbar__resize-handle{padding-bottom:0;padding-right:0}.tox .tox-button::before{display:none}
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.js b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.js
new file mode 100644
index 0000000..d5b3692
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.js
@@ -0,0 +1,2 @@
+tinymce.Resource.add('ui/tinymce-5/skin.shadowdom.css', "body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}")
+//# sourceMappingURL=skin.shadowdom.js.map
diff --git a/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css
new file mode 100644
index 0000000..8745951
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css
@@ -0,0 +1 @@
+body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}
diff --git a/eims-ui/apps/web-antd/public/tinymce/themes/silver/theme.min.js b/eims-ui/apps/web-antd/public/tinymce/themes/silver/theme.min.js
new file mode 100644
index 0000000..b046995
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/themes/silver/theme.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";const e=Object.getPrototypeOf,t=(e,t,o)=>{var n;return!!o(e,t.prototype)||(null===(n=e.constructor)||void 0===n?void 0:n.name)===t.name},o=e=>o=>(e=>{const o=typeof e;return null===e?"null":"object"===o&&Array.isArray(e)?"array":"object"===o&&t(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":o})(o)===e,n=e=>t=>typeof t===e,s=e=>t=>e===t,r=o("string"),a=o("object"),i=o=>((o,n)=>a(o)&&t(o,n,((t,o)=>e(t)===o)))(o,Object),l=o("array"),c=s(null),d=n("boolean"),u=s(void 0),m=e=>null==e,g=e=>!m(e),p=n("function"),h=n("number"),f=(e,t)=>{if(l(e)){for(let o=0,n=e.length;o<n;++o)if(!t(e[o]))return!1;return!0}return!1},b=()=>{},v=e=>()=>e(),y=(e,t)=>(...o)=>e(t.apply(null,o)),x=e=>()=>e,w=e=>e,S=(e,t)=>e===t;function k(e,...t){return(...o)=>{const n=t.concat(o);return e.apply(null,n)}}const C=e=>t=>!e(t),O=e=>()=>{throw new Error(e)},_=e=>e(),T=x(!1),E=x(!0);class A{constructor(e,t){this.tag=e,this.value=t}static some(e){return new A(!0,e)}static none(){return A.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?A.some(e(this.value)):A.none()}bind(e){return this.tag?e(this.value):A.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:A.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return g(e)?A.some(e):A.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}A.singletonNone=new A(!1);const M=Array.prototype.slice,D=Array.prototype.indexOf,B=Array.prototype.push,I=(e,t)=>D.call(e,t),F=(e,t)=>I(e,t)>-1,R=(e,t)=>{for(let o=0,n=e.length;o<n;o++)if(t(e[o],o))return!0;return!1},N=(e,t)=>{const o=[];for(let n=0;n<e;n++)o.push(t(n));return o},z=(e,t)=>{const o=[];for(let n=0;n<e.length;n+=t){const s=M.call(e,n,n+t);o.push(s)}return o},L=(e,t)=>{const o=e.length,n=new Array(o);for(let s=0;s<o;s++){const o=e[s];n[s]=t(o,s)}return n},V=(e,t)=>{for(let o=0,n=e.length;o<n;o++)t(e[o],o)},H=(e,t)=>{const o=[],n=[];for(let s=0,r=e.length;s<r;s++){const r=e[s];(t(r,s)?o:n).push(r)}return{pass:o,fail:n}},P=(e,t)=>{const o=[];for(let n=0,s=e.length;n<s;n++){const s=e[n];t(s,n)&&o.push(s)}return o},U=(e,t,o)=>(((e,t)=>{for(let o=e.length-1;o>=0;o--)t(e[o],o)})(e,((e,n)=>{o=t(o,e,n)})),o),W=(e,t,o)=>(V(e,((e,n)=>{o=t(o,e,n)})),o),j=(e,t)=>((e,t,o)=>{for(let n=0,s=e.length;n<s;n++){const s=e[n];if(t(s,n))return A.some(s);if(o(s,n))break}return A.none()})(e,t,T),$=(e,t)=>{for(let o=0,n=e.length;o<n;o++)if(t(e[o],o))return A.some(o);return A.none()},G=e=>{const t=[];for(let o=0,n=e.length;o<n;++o){if(!l(e[o]))throw new Error("Arr.flatten item "+o+" was not an array, input: "+e);B.apply(t,e[o])}return t},q=(e,t)=>G(L(e,t)),Y=(e,t)=>{for(let o=0,n=e.length;o<n;++o)if(!0!==t(e[o],o))return!1;return!0},X=e=>{const t=M.call(e,0);return t.reverse(),t},K=(e,t)=>P(e,(e=>!F(t,e))),J=(e,t)=>{const o={};for(let n=0,s=e.length;n<s;n++){const s=e[n];o[String(s)]=t(s,n)}return o},Q=e=>[e],Z=(e,t)=>{const o=M.call(e,0);return o.sort(t),o},ee=(e,t)=>t>=0&&t<e.length?A.some(e[t]):A.none(),te=e=>ee(e,0),oe=e=>ee(e,e.length-1),ne=p(Array.from)?Array.from:e=>M.call(e),se=(e,t)=>{for(let o=0;o<e.length;o++){const n=t(e[o],o);if(n.isSome())return n}return A.none()},re=Object.keys,ae=Object.hasOwnProperty,ie=(e,t)=>{const o=re(e);for(let n=0,s=o.length;n<s;n++){const s=o[n];t(e[s],s)}},le=(e,t)=>ce(e,((e,o)=>({k:o,v:t(e,o)}))),ce=(e,t)=>{const o={};return ie(e,((e,n)=>{const s=t(e,n);o[s.k]=s.v})),o},de=e=>(t,o)=>{e[o]=t},ue=(e,t,o,n)=>{ie(e,((e,s)=>{(t(e,s)?o:n)(e,s)}))},me=(e,t)=>{const o={};return ue(e,t,de(o),b),o},ge=(e,t)=>{const o=[];return ie(e,((e,n)=>{o.push(t(e,n))})),o},pe=(e,t)=>{const o=re(e);for(let n=0,s=o.length;n<s;n++){const s=o[n],r=e[s];if(t(r,s,e))return A.some(r)}return A.none()},he=e=>ge(e,w),fe=(e,t)=>be(e,t)?A.from(e[t]):A.none(),be=(e,t)=>ae.call(e,t),ve=(e,t)=>be(e,t)&&void 0!==e[t]&&null!==e[t],ye=(e,t,o=S)=>e.exists((e=>o(e,t))),xe=e=>{const t=[],o=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(o);return t},we=(e,t,o)=>e.isSome()&&t.isSome()?A.some(o(e.getOrDie(),t.getOrDie())):A.none(),Se=(e,t)=>null!=e?A.some(t(e)):A.none(),ke=(e,t)=>e?A.some(t):A.none(),Ce=(e,t,o)=>""===t||e.length>=t.length&&e.substr(o,o+t.length)===t,Oe=(e,t)=>Te(e,t)?((e,t)=>e.substring(t))(e,t.length):e,_e=(e,t,o=0,n)=>{const s=e.indexOf(t,o);return-1!==s&&(!!u(n)||s+t.length<=n)},Te=(e,t)=>Ce(e,t,0),Ee=(e,t)=>Ce(e,t,e.length-t.length),Ae=(Mo=/^\s+|\s+$/g,e=>e.replace(Mo,"")),Me=e=>e.length>0,De=e=>!Me(e),Be=e=>void 0!==e.style&&p(e.style.getPropertyValue),Ie=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},Fe=(e,t)=>{const o=(t||document).createElement("div");if(o.innerHTML=e,!o.hasChildNodes()||o.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return Ie(o.childNodes[0])},Re=(e,t)=>{const o=(t||document).createElement(e);return Ie(o)},Ne=(e,t)=>{const o=(t||document).createTextNode(e);return Ie(o)},ze=Ie,Le="undefined"!=typeof window?window:Function("return this;")(),Ve=(e,t)=>((e,t)=>{let o=null!=t?t:Le;for(let t=0;t<e.length&&null!=o;++t)o=o[e[t]];return o})(e.split("."),t),He=Object.getPrototypeOf,Pe=e=>{const t=Ve("ownerDocument.defaultView",e);return a(e)&&((e=>((e,t)=>{const o=((e,t)=>Ve(e,t))(e,t);if(null==o)throw new Error(e+" not available on this browser");return o})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(He(e).constructor.name))},Ue=e=>e.dom.nodeName.toLowerCase(),We=e=>t=>(e=>e.dom.nodeType)(t)===e,je=e=>$e(e)&&Pe(e.dom),$e=We(1),Ge=We(3),qe=We(9),Ye=We(11),Xe=e=>t=>$e(t)&&Ue(t)===e,Ke=(e,t)=>{const o=e.dom;if(1!==o.nodeType)return!1;{const e=o;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},Je=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,Qe=(e,t)=>{const o=void 0===t?document:t.dom;return Je(o)?A.none():A.from(o.querySelector(e)).map(ze)},Ze=(e,t)=>e.dom===t.dom,et=(e,t)=>{const o=e.dom,n=t.dom;return o!==n&&o.contains(n)},tt=e=>ze(e.dom.ownerDocument),ot=e=>qe(e)?e:tt(e),nt=e=>ze(ot(e).dom.documentElement),st=e=>ze(ot(e).dom.defaultView),rt=e=>A.from(e.dom.parentNode).map(ze),at=e=>A.from(e.dom.parentElement).map(ze),it=e=>A.from(e.dom.offsetParent).map(ze),lt=e=>L(e.dom.childNodes,ze),ct=(e,t)=>{const o=e.dom.childNodes;return A.from(o[t]).map(ze)},dt=e=>ct(e,0),ut=(e,t)=>({element:e,offset:t}),mt=(e,t)=>{const o=lt(e);return o.length>0&&t<o.length?ut(o[t],0):ut(e,t)},gt=e=>Ye(e)&&g(e.dom.host),pt=p(Element.prototype.attachShadow)&&p(Node.prototype.getRootNode),ht=x(pt),ft=pt?e=>ze(e.dom.getRootNode()):ot,bt=e=>gt(e)?e:ze(ot(e).dom.body),vt=e=>{const t=ft(e);return gt(t)?A.some(t):A.none()},yt=e=>ze(e.dom.host),xt=e=>{const t=Ge(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const o=t.ownerDocument;return vt(ze(t)).fold((()=>o.body.contains(t)),(n=xt,s=yt,e=>n(s(e))));var n,s},wt=()=>St(ze(document)),St=e=>{const t=e.dom.body;if(null==t)throw new Error("Body is not available yet");return ze(t)},kt=(e,t,o)=>{if(!(r(o)||d(o)||h(o)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",o,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,o+"")},Ct=(e,t,o)=>{kt(e.dom,t,o)},Ot=(e,t)=>{const o=e.dom;ie(t,((e,t)=>{kt(o,t,e)}))},_t=(e,t)=>{const o=e.dom.getAttribute(t);return null===o?void 0:o},Tt=(e,t)=>A.from(_t(e,t)),Et=(e,t)=>{const o=e.dom;return!(!o||!o.hasAttribute)&&o.hasAttribute(t)},At=(e,t)=>{e.dom.removeAttribute(t)},Mt=(e,t,o)=>{if(!r(o))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",o,":: Element ",e),new Error("CSS value must be a string: "+o);Be(e)&&e.style.setProperty(t,o)},Dt=(e,t)=>{Be(e)&&e.style.removeProperty(t)},Bt=(e,t,o)=>{const n=e.dom;Mt(n,t,o)},It=(e,t)=>{const o=e.dom;ie(t,((e,t)=>{Mt(o,t,e)}))},Ft=(e,t)=>{const o=e.dom;ie(t,((e,t)=>{e.fold((()=>{Dt(o,t)}),(e=>{Mt(o,t,e)}))}))},Rt=(e,t)=>{const o=e.dom,n=window.getComputedStyle(o).getPropertyValue(t);return""!==n||xt(e)?n:Nt(o,t)},Nt=(e,t)=>Be(e)?e.style.getPropertyValue(t):"",zt=(e,t)=>{const o=e.dom,n=Nt(o,t);return A.from(n).filter((e=>e.length>0))},Lt=e=>{const t={},o=e.dom;if(Be(o))for(let e=0;e<o.style.length;e++){const n=o.style.item(e);t[n]=o.style[n]}return t},Vt=(e,t,o)=>{const n=Re(e);return Bt(n,t,o),zt(n,t).isSome()},Ht=(e,t)=>{const o=e.dom;Dt(o,t),ye(Tt(e,"style").map(Ae),"")&&At(e,"style")},Pt=e=>e.dom.offsetWidth,Ut=(e,t)=>{const o=o=>{const n=t(o);if(n<=0||null===n){const t=Rt(o,e);return parseFloat(t)||0}return n},n=(e,t)=>W(t,((t,o)=>{const n=Rt(e,o),s=void 0===n?0:parseInt(n,10);return isNaN(s)?t:t+s}),0);return{set:(t,o)=>{if(!h(o)&&!o.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+o);const n=t.dom;Be(n)&&(n.style[e]=o+"px")},get:o,getOuter:o,aggregate:n,max:(e,t,o)=>{const s=n(e,o);return t>s?t-s:0}}},Wt=Ut("height",(e=>{const t=e.dom;return xt(e)?t.getBoundingClientRect().height:t.offsetHeight})),jt=e=>Wt.get(e),$t=e=>Wt.getOuter(e),Gt=(e,t)=>({left:e,top:t,translate:(o,n)=>Gt(e+o,t+n)}),qt=Gt,Yt=(e,t)=>void 0!==e?e:void 0!==t?t:0,Xt=e=>{const t=e.dom.ownerDocument,o=t.body,n=t.defaultView,s=t.documentElement;if(o===e.dom)return qt(o.offsetLeft,o.offsetTop);const r=Yt(null==n?void 0:n.pageYOffset,s.scrollTop),a=Yt(null==n?void 0:n.pageXOffset,s.scrollLeft),i=Yt(s.clientTop,o.clientTop),l=Yt(s.clientLeft,o.clientLeft);return Kt(e).translate(a-l,r-i)},Kt=e=>{const t=e.dom,o=t.ownerDocument.body;return o===t?qt(o.offsetLeft,o.offsetTop):xt(e)?(e=>{const t=e.getBoundingClientRect();return qt(t.left,t.top)})(t):qt(0,0)},Jt=Ut("width",(e=>e.dom.offsetWidth)),Qt=e=>Jt.get(e),Zt=e=>Jt.getOuter(e),eo=e=>{let t,o=!1;return(...n)=>(o||(o=!0,t=e.apply(null,n)),t)},to=()=>oo(0,0),oo=(e,t)=>({major:e,minor:t}),no={nu:oo,detect:(e,t)=>{const o=String(t).toLowerCase();return 0===e.length?to():((e,t)=>{const o=((e,t)=>{for(let o=0;o<e.length;o++){const n=e[o];if(n.test(t))return n}})(e,t);if(!o)return{major:0,minor:0};const n=e=>Number(t.replace(o,"$"+e));return oo(n(1),n(2))})(e,o)},unknown:to},so=(e,t)=>{const o=String(t).toLowerCase();return j(e,(e=>e.search(o)))},ro=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,ao=e=>t=>_e(t,e),io=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>_e(e,"edge/")&&_e(e,"chrome")&&_e(e,"safari")&&_e(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,ro],search:e=>_e(e,"chrome")&&!_e(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>_e(e,"msie")||_e(e,"trident")},{name:"Opera",versionRegexes:[ro,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:ao("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:ao("firefox")},{name:"Safari",versionRegexes:[ro,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(_e(e,"safari")||_e(e,"mobile/"))&&_e(e,"applewebkit")}],lo=[{name:"Windows",search:ao("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>_e(e,"iphone")||_e(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:ao("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:ao("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:ao("linux"),versionRegexes:[]},{name:"Solaris",search:ao("sunos"),versionRegexes:[]},{name:"FreeBSD",search:ao("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:ao("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],co={browsers:x(io),oses:x(lo)},uo="Edge",mo="Chromium",go="Opera",po="Firefox",ho="Safari",fo=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isEdge:n(uo),isChromium:n(mo),isIE:n("IE"),isOpera:n(go),isFirefox:n(po),isSafari:n(ho)}},bo=()=>fo({current:void 0,version:no.unknown()}),vo=fo,yo=(x(uo),x(mo),x("IE"),x(go),x(po),x(ho),"Windows"),xo="Android",wo="Linux",So="macOS",ko="Solaris",Co="FreeBSD",Oo="ChromeOS",_o=e=>{const t=e.current,o=e.version,n=e=>()=>t===e;return{current:t,version:o,isWindows:n(yo),isiOS:n("iOS"),isAndroid:n(xo),isMacOS:n(So),isLinux:n(wo),isSolaris:n(ko),isFreeBSD:n(Co),isChromeOS:n(Oo)}},To=()=>_o({current:void 0,version:no.unknown()}),Eo=_o,Ao=(x(yo),x("iOS"),x(xo),x(wo),x(So),x(ko),x(Co),x(Oo),e=>window.matchMedia(e).matches);var Mo;let Do=eo((()=>((e,t,o)=>{const n=co.browsers(),s=co.oses(),r=t.bind((e=>((e,t)=>se(t.brands,(t=>{const o=t.brand.toLowerCase();return j(e,(e=>{var t;return o===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:no.nu(parseInt(t.version,10),0)})))})))(n,e))).orThunk((()=>((e,t)=>so(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(n,e))).fold(bo,vo),a=((e,t)=>so(e,t).map((e=>{const o=no.detect(e.versionRegexes,t);return{current:e.name,version:o}})))(s,e).fold(To,Eo),i=((e,t,o,n)=>{const s=e.isiOS()&&!0===/ipad/i.test(o),r=e.isiOS()&&!s,a=e.isiOS()||e.isAndroid(),i=a||n("(pointer:coarse)"),l=s||!r&&a&&n("(min-device-width:768px)"),c=r||a&&!l,d=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(o),u=!c&&!l&&!d;return{isiPad:x(s),isiPhone:x(r),isTablet:x(l),isPhone:x(c),isTouch:x(i),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:x(d),isDesktop:x(u)}})(a,r,e,o);return{browser:r,os:a,deviceType:i}})(navigator.userAgent,A.from(navigator.userAgentData),Ao)));const Bo=()=>Do(),Io=e=>{const t=ze((e=>{if(ht()&&g(e.target)){const t=ze(e.target);if($e(t)&&(e=>g(e.dom.shadowRoot))(t)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return te(t)}}return A.from(e.target)})(e).getOr(e.target)),o=()=>e.stopPropagation(),n=()=>e.preventDefault(),s=y(n,o);return((e,t,o,n,s,r,a)=>({target:e,x:t,y:o,stop:n,prevent:s,kill:r,raw:a}))(t,e.clientX,e.clientY,o,n,s,e)},Fo=(e,t,o,n,s)=>{const r=((e,t)=>o=>{e(o)&&t(Io(o))})(o,n);return e.dom.addEventListener(t,r,s),{unbind:k(Ro,e,t,r,s)}},Ro=(e,t,o,n)=>{e.dom.removeEventListener(t,o,n)},No=(e,t)=>{rt(e).each((o=>{o.dom.insertBefore(t.dom,e.dom)}))},zo=(e,t)=>{const o=(e=>A.from(e.dom.nextSibling).map(ze))(e);o.fold((()=>{rt(e).each((e=>{Vo(e,t)}))}),(e=>{No(e,t)}))},Lo=(e,t)=>{dt(e).fold((()=>{Vo(e,t)}),(o=>{e.dom.insertBefore(t.dom,o.dom)}))},Vo=(e,t)=>{e.dom.appendChild(t.dom)},Ho=(e,t)=>{V(t,(t=>{Vo(e,t)}))},Po=e=>{e.dom.textContent="",V(lt(e),(e=>{Uo(e)}))},Uo=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},Wo=e=>{const t=void 0!==e?e.dom:document,o=t.body.scrollLeft||t.documentElement.scrollLeft,n=t.body.scrollTop||t.documentElement.scrollTop;return qt(o,n)},jo=(e,t,o)=>{const n=(void 0!==o?o.dom:document).defaultView;n&&n.scrollTo(e,t)},$o=(e,t,o,n)=>({x:e,y:t,width:o,height:n,right:e+o,bottom:t+n}),Go=e=>{const t=void 0===e?window:e,o=t.document,n=Wo(ze(o));return(e=>{const t=void 0===e?window:e;return Bo().browser.isFirefox()?A.none():A.from(t.visualViewport)})(t).fold((()=>{const e=t.document.documentElement,o=e.clientWidth,s=e.clientHeight;return $o(n.left,n.top,o,s)}),(e=>$o(Math.max(e.pageLeft,n.left),Math.max(e.pageTop,n.top),e.width,e.height)))},qo=()=>ze(document),Yo=(e,t)=>e.view(t).fold(x([]),(t=>{const o=e.owner(t),n=Yo(e,o);return[t].concat(n)}));var Xo=Object.freeze({__proto__:null,view:e=>{var t;return(e.dom===document?A.none():A.from(null===(t=e.dom.defaultView)||void 0===t?void 0:t.frameElement)).map(ze)},owner:e=>tt(e)});const Ko=e=>{const t=qo(),o=Wo(t),n=((e,t)=>{const o=t.owner(e),n=Yo(t,o);return A.some(n)})(e,Xo);return n.fold(k(Xt,e),(t=>{const n=Kt(e),s=U(t,((e,t)=>{const o=Kt(t);return{left:e.left+o.left,top:e.top+o.top}}),{left:0,top:0});return qt(s.left+n.left+o.left,s.top+n.top+o.top)}))},Jo=(e,t,o,n)=>({x:e,y:t,width:o,height:n,right:e+o,bottom:t+n}),Qo=e=>{const t=Xt(e),o=Zt(e),n=$t(e);return Jo(t.left,t.top,o,n)},Zo=e=>{const t=Ko(e),o=Zt(e),n=$t(e);return Jo(t.left,t.top,o,n)},en=(e,t)=>{const o=Math.max(e.x,t.x),n=Math.max(e.y,t.y),s=Math.min(e.right,t.right),r=Math.min(e.bottom,t.bottom);return Jo(o,n,s-o,r-n)},tn=()=>Go(window),on=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},nn=e=>{const t=on(A.none()),o=()=>t.get().each(e);return{clear:()=>{o(),t.set(A.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{o(),t.set(A.some(e))}}},sn=()=>nn((e=>e.unbind())),rn=()=>{const e=nn(b);return{...e,on:t=>e.get().each(t)}};var an=tinymce.util.Tools.resolve("tinymce.ThemeManager");const ln=e=>{const t=t=>t(e),o=x(e),n=()=>s,s={tag:!0,inner:e,fold:(t,o)=>o(e),isValue:E,isError:T,map:t=>dn.value(t(e)),mapError:n,bind:t,exists:t,forall:t,getOr:o,or:n,getOrThunk:o,orThunk:n,getOrDie:o,each:t=>{t(e)},toOptional:()=>A.some(e)};return s},cn=e=>{const t=()=>o,o={tag:!1,inner:e,fold:(t,o)=>t(e),isValue:T,isError:E,map:t,mapError:t=>dn.error(t(e)),bind:t,exists:T,forall:E,getOr:w,or:w,getOrThunk:_,orThunk:_,getOrDie:O(String(e)),each:b,toOptional:A.none};return o},dn={value:ln,error:cn,fromOption:(e,t)=>e.fold((()=>cn(t)),ln)};var un;!function(e){e[e.Error=0]="Error",e[e.Value=1]="Value"}(un||(un={}));const mn=(e,t,o)=>e.stype===un.Error?t(e.serror):o(e.svalue),gn=e=>({stype:un.Value,svalue:e}),pn=e=>({stype:un.Error,serror:e}),hn=gn,fn=pn,bn=mn,vn=(e,t,o,n)=>({tag:"field",key:e,newKey:t,presence:o,prop:n}),yn=(e,t,o)=>{switch(e.tag){case"field":return t(e.key,e.newKey,e.presence,e.prop);case"custom":return o(e.newKey,e.instantiator)}},xn=e=>(...t)=>{if(0===t.length)throw new Error("Can't merge zero objects");const o={};for(let n=0;n<t.length;n++){const s=t[n];for(const t in s)be(s,t)&&(o[t]=e(o[t],s[t]))}return o},wn=xn(((e,t)=>i(e)&&i(t)?wn(e,t):t)),Sn=xn(((e,t)=>t)),kn=e=>({tag:"defaultedThunk",process:e}),Cn=e=>kn(x(e)),On=e=>({tag:"mergeWithThunk",process:e}),_n=e=>{const t=(e=>{const t=[],o=[];return V(e,(e=>{mn(e,(e=>o.push(e)),(e=>t.push(e)))})),{values:t,errors:o}})(e);return t.errors.length>0?(o=t.errors,y(fn,G)(o)):hn(t.values);var o},Tn=e=>a(e)&&re(e).length>100?" removed due to size":JSON.stringify(e,null,2),En=(e,t)=>fn([{path:e,getErrorInfo:t}]),An=e=>({extract:(t,o)=>((e,t)=>e.stype===un.Error?t(e.serror):e)(e(o),(e=>((e,t)=>En(e,x(t)))(t,e))),toString:x("val")}),Mn=An(hn),Dn=(e,t,o,n)=>n(fe(e,t).getOrThunk((()=>o(e)))),Bn=(e,t,o,n,s)=>{const r=e=>s.extract(t.concat([n]),e),a=e=>e.fold((()=>hn(A.none())),(e=>((e,t)=>e.stype===un.Value?{stype:un.Value,svalue:t(e.svalue)}:e)(s.extract(t.concat([n]),e),A.some)));switch(e.tag){case"required":return((e,t,o,n)=>fe(t,o).fold((()=>((e,t,o)=>En(e,(()=>'Could not find valid *required* value for "'+t+'" in '+Tn(o))))(e,o,t)),n))(t,o,n,r);case"defaultedThunk":return Dn(o,n,e.process,r);case"option":return((e,t,o)=>o(fe(e,t)))(o,n,a);case"defaultedOptionThunk":return((e,t,o,n)=>n(fe(e,t).map((t=>!0===t?o(e):t))))(o,n,e.process,a);case"mergeWithThunk":return Dn(o,n,x({}),(t=>{const n=wn(e.process(o),t);return r(n)}))}},In=e=>({extract:(t,o)=>e().extract(t,o),toString:()=>e().toString()}),Fn=e=>re(me(e,g)),Rn=e=>{const t=Nn(e),o=U(e,((e,t)=>yn(t,(t=>wn(e,{[t]:!0})),x(e))),{});return{extract:(e,n)=>{const s=d(n)?[]:Fn(n),r=P(s,(e=>!ve(o,e)));return 0===r.length?t.extract(e,n):((e,t)=>En(e,(()=>"There are unsupported fields: ["+t.join(", ")+"] specified")))(e,r)},toString:t.toString}},Nn=e=>({extract:(t,o)=>((e,t,o)=>{const n={},s=[];for(const r of o)yn(r,((o,r,a,i)=>{const l=Bn(a,e,t,o,i);bn(l,(e=>{s.push(...e)}),(e=>{n[r]=e}))}),((e,o)=>{n[e]=o(t)}));return s.length>0?fn(s):hn(n)})(t,o,e),toString:()=>{const t=L(e,(e=>yn(e,((e,t,o,n)=>e+" -> "+n.toString()),((e,t)=>"state("+e+")"))));return"obj{\n"+t.join("\n")+"}"}}),zn=e=>({extract:(t,o)=>{const n=L(o,((o,n)=>e.extract(t.concat(["["+n+"]"]),o)));return _n(n)},toString:()=>"array("+e.toString()+")"}),Ln=(e,t)=>{const o=void 0!==t?t:w;return{extract:(t,n)=>{const s=[];for(const r of e){const e=r.extract(t,n);if(e.stype===un.Value)return{stype:un.Value,svalue:o(e.svalue)};s.push(e)}return _n(s)},toString:()=>"oneOf("+L(e,(e=>e.toString())).join(", ")+")"}},Vn=(e,t)=>({extract:(o,n)=>{const s=re(n),r=((t,o)=>zn(An(e)).extract(t,o))(o,s);return((e,t)=>e.stype===un.Value?t(e.svalue):e)(r,(e=>{const s=L(e,(e=>vn(e,e,{tag:"required",process:{}},t)));return Nn(s).extract(o,n)}))},toString:()=>"setOf("+t.toString()+")"}),Hn=y(zn,Nn),Pn=x(Mn),Un=(e,t)=>An((o=>{const n=typeof o;return e(o)?hn(o):fn(`Expected type: ${t} but got: ${n}`)})),Wn=Un(h,"number"),jn=Un(r,"string"),$n=Un(d,"boolean"),Gn=Un(p,"function"),qn=e=>{if(Object(e)!==e)return!0;switch({}.toString.call(e).slice(8,-1)){case"Boolean":case"Number":case"String":case"Date":case"RegExp":case"Blob":case"FileList":case"ImageData":case"ImageBitmap":case"ArrayBuffer":return!0;case"Array":case"Object":return Object.keys(e).every((t=>qn(e[t])));default:return!1}},Yn=An((e=>qn(e)?hn(e):fn("Expected value to be acceptable for sending via postMessage"))),Xn=(e,t)=>({extract:(o,n)=>fe(n,e).fold((()=>((e,t)=>En(e,(()=>'Choice schema did not contain choice key: "'+t+'"')))(o,e)),(e=>((e,t,o,n)=>fe(o,n).fold((()=>((e,t,o)=>En(e,(()=>'The chosen schema: "'+o+'" did not exist in branches: '+Tn(t))))(e,o,n)),(o=>o.extract(e.concat(["branch: "+n]),t))))(o,n,t,e))),toString:()=>"chooseOn("+e+"). Possible values: "+re(t)}),Kn=e=>An((t=>e(t).fold(fn,hn))),Jn=(e,t)=>Vn((t=>e(t).fold(pn,gn)),t),Qn=(e,t,o)=>{return n=((e,t,o)=>((e,t)=>e.stype===un.Error?{stype:un.Error,serror:t(e.serror)}:e)(t.extract([e],o),(e=>({input:o,errors:e}))))(e,t,o),mn(n,dn.error,dn.value);var n},Zn=e=>e.fold((e=>{throw new Error(ts(e))}),w),es=(e,t,o)=>Zn(Qn(e,t,o)),ts=e=>"Errors: \n"+(e=>{const t=e.length>10?e.slice(0,10).concat([{path:[],getErrorInfo:x("... (only showing first ten failures)")}]):e;return L(t,(e=>"Failed path: ("+e.path.join(" > ")+")\n"+e.getErrorInfo()))})(e.errors).join("\n")+"\n\nInput object: "+Tn(e.input),os=(e,t)=>Xn(e,le(t,Nn)),ns=(e,t)=>((e,t)=>{const o=eo(t);return{extract:(e,t)=>o().extract(e,t),toString:()=>o().toString()}})(0,t),ss=vn,rs=(e,t)=>({tag:"custom",newKey:e,instantiator:t}),as=e=>Kn((t=>F(e,t)?dn.value(t):dn.error(`Unsupported value: "${t}", choose one of "${e.join(", ")}".`))),is=e=>ss(e,e,{tag:"required",process:{}},Pn()),ls=(e,t)=>ss(e,e,{tag:"required",process:{}},t),cs=e=>ls(e,Wn),ds=e=>ls(e,jn),us=(e,t)=>ss(e,e,{tag:"required",process:{}},as(t)),ms=e=>ls(e,Gn),gs=(e,t)=>ss(e,e,{tag:"required",process:{}},Nn(t)),ps=(e,t)=>ss(e,e,{tag:"required",process:{}},Hn(t)),hs=(e,t)=>ss(e,e,{tag:"required",process:{}},zn(t)),fs=e=>ss(e,e,{tag:"option",process:{}},Pn()),bs=(e,t)=>ss(e,e,{tag:"option",process:{}},t),vs=e=>bs(e,Wn),ys=e=>bs(e,jn),xs=(e,t)=>bs(e,as(t)),ws=e=>bs(e,Gn),Ss=(e,t)=>bs(e,zn(t)),ks=(e,t)=>bs(e,Nn(t)),Cs=(e,t)=>ss(e,e,Cn(t),Pn()),Os=(e,t,o)=>ss(e,e,Cn(t),o),_s=(e,t)=>Os(e,t,Wn),Ts=(e,t)=>Os(e,t,jn),Es=(e,t,o)=>Os(e,t,as(o)),As=(e,t)=>Os(e,t,$n),Ms=(e,t)=>Os(e,t,Gn),Ds=(e,t,o)=>Os(e,t,zn(o)),Bs=(e,t,o)=>Os(e,t,Nn(o)),Is=e=>{if(!l(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],o={};return V(e,((n,s)=>{const r=re(n);if(1!==r.length)throw new Error("one and only one name per case");const a=r[0],i=n[a];if(void 0!==o[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!l(i))throw new Error("case arguments must be an array");t.push(a),o[a]=(...o)=>{const n=o.length;if(n!==i.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+i.length+" ("+i+"), got "+n);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[s].apply(null,o)},match:e=>{const n=re(e);if(t.length!==n.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+n.join(","));if(!Y(t,(e=>F(n,e))))throw new Error("Not all branches were specified when using match. Specified: "+n.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,o)},log:e=>{console.log(e,{constructors:t,constructor:a,params:o})}}}})),o};Is([{bothErrors:["error1","error2"]},{firstError:["error1","value2"]},{secondError:["value1","error2"]},{bothValues:["value1","value2"]}]);const Fs=(e,t)=>((e,t)=>({[e]:t}))(e,t),Rs=e=>(e=>{const t={};return V(e,(e=>{t[e.key]=e.value})),t})(e),Ns=e=>p(e)?e:T,zs=(e,t,o)=>{let n=e.dom;const s=Ns(o);for(;n.parentNode;){n=n.parentNode;const e=ze(n),o=t(e);if(o.isSome())return o;if(s(e))break}return A.none()},Ls=(e,t,o)=>{const n=t(e),s=Ns(o);return n.orThunk((()=>s(e)?A.none():zs(e,t,s)))},Vs=(e,t)=>Ze(e.element,t.event.target),Hs={can:E,abort:T,run:b},Ps=e=>{if(!ve(e,"can")&&!ve(e,"abort")&&!ve(e,"run"))throw new Error("EventHandler defined by: "+JSON.stringify(e,null,2)+" does not have can, abort, or run!");return{...Hs,...e}},Us=x,Ws=Us("touchstart"),js=Us("touchmove"),$s=Us("touchend"),Gs=Us("touchcancel"),qs=Us("mousedown"),Ys=Us("mousemove"),Xs=Us("mouseout"),Ks=Us("mouseup"),Js=Us("mouseover"),Qs=Us("focusin"),Zs=Us("focusout"),er=Us("keydown"),tr=Us("keyup"),or=Us("input"),nr=Us("change"),sr=Us("click"),rr=Us("transitioncancel"),ar=Us("transitionend"),ir=Us("transitionstart"),lr=Us("selectstart"),cr=e=>x("alloy."+e),dr={tap:cr("tap")},ur=cr("focus"),mr=cr("blur.post"),gr=cr("paste.post"),pr=cr("receive"),hr=cr("execute"),fr=cr("focus.item"),br=dr.tap,vr=cr("longpress"),yr=cr("sandbox.close"),xr=cr("typeahead.cancel"),wr=cr("system.init"),Sr=cr("system.touchmove"),kr=cr("system.touchend"),Cr=cr("system.scroll"),Or=cr("system.resize"),_r=cr("system.attached"),Tr=cr("system.detached"),Er=cr("system.dismissRequested"),Ar=cr("system.repositionRequested"),Mr=cr("focusmanager.shifted"),Dr=cr("slotcontainer.visibility"),Br=cr("system.external.element.scroll"),Ir=cr("change.tab"),Fr=cr("dismiss.tab"),Rr=cr("highlight"),Nr=cr("dehighlight"),zr=(e,t)=>{Pr(e,e.element,t,{})},Lr=(e,t,o)=>{Pr(e,e.element,t,o)},Vr=e=>{zr(e,hr())},Hr=(e,t,o)=>{Pr(e,t,o,{})},Pr=(e,t,o,n)=>{const s={target:t,...n};e.getSystem().triggerEvent(o,t,s)},Ur=(e,t,o,n)=>{e.getSystem().triggerEvent(o,t,n.event)},Wr=e=>Rs(e),jr=(e,t)=>({key:e,value:Ps({abort:t})}),$r=e=>({key:e,value:Ps({run:(e,t)=>{t.event.prevent()}})}),Gr=(e,t)=>({key:e,value:Ps({run:t})}),qr=(e,t,o)=>({key:e,value:Ps({run:(e,n)=>{t.apply(void 0,[e,n].concat(o))}})}),Yr=e=>t=>({key:e,value:Ps({run:(e,o)=>{Vs(e,o)&&t(e,o)}})}),Xr=(e,t,o)=>((e,t)=>Gr(e,((o,n)=>{o.getSystem().getByUid(t).each((t=>{Ur(t,t.element,e,n)}))})))(e,t.partUids[o]),Kr=(e,t)=>Gr(e,((e,o)=>{const n=o.event,s=e.getSystem().getByDom(n.target).getOrThunk((()=>Ls(n.target,(t=>e.getSystem().getByDom(t).toOptional()),T).getOr(e)));t(e,s,o)})),Jr=e=>Gr(e,((e,t)=>{t.cut()})),Qr=e=>Gr(e,((e,t)=>{t.stop()})),Zr=(e,t)=>Yr(e)(t),ea=Yr(_r()),ta=Yr(Tr()),oa=Yr(wr()),na=(ti=hr(),e=>Gr(ti,e)),sa=e=>L(e,(e=>Ee(e,"/*")?e.substring(0,e.length-2):e)),ra=(e,t)=>{const o=e.toString(),n=o.indexOf(")")+1,s=o.indexOf("("),r=o.substring(s+1,n-1).split(/,\s*/);return e.toFunctionAnnotation=()=>({name:t,parameters:sa(r)}),e},aa=e=>({classes:u(e.classes)?[]:e.classes,attributes:u(e.attributes)?{}:e.attributes,styles:u(e.styles)?{}:e.styles}),ia=(e,t,o)=>oa(((n,s)=>{o(n,e,t)})),la=e=>({key:e,value:void 0}),ca=(e,t,o,n,s,r,a)=>{const i=e=>ve(e,o)?e[o]():A.none(),l=le(s,((e,t)=>((e,t,o)=>((e,t,o)=>{const n=o.toString(),s=n.indexOf(")")+1,r=n.indexOf("("),a=n.substring(r+1,s-1).split(/,\s*/);return e.toFunctionAnnotation=()=>({name:t,parameters:sa(a.slice(0,1).concat(a.slice(3)))}),e})(((n,...s)=>{const r=[n].concat(s);return n.config({name:x(e)}).fold((()=>{throw new Error("We could not find any behaviour configuration for: "+e+". Using API: "+o)}),(e=>{const o=Array.prototype.slice.call(r,1);return t.apply(void 0,[n,e.config,e.state].concat(o))}))}),o,t))(o,e,t))),c={...le(r,((e,t)=>ra(e,t))),...l,revoke:k(la,o),config:t=>{const n=es(o+"-config",e,t);return{key:o,value:{config:n,me:c,configAsRaw:eo((()=>es(o+"-config",e,t))),initialConfig:t,state:a}}},schema:x(t),exhibit:(e,t)=>we(i(e),fe(n,"exhibit"),((e,o)=>o(t,e.config,e.state))).getOrThunk((()=>aa({}))),name:x(o),handlers:e=>i(e).map((e=>fe(n,"events").getOr((()=>({})))(e.config,e.state))).getOr({})};return c},da={init:()=>ua({readState:x("No State required")})},ua=e=>e,ma=e=>Rs(e),ga=Rn([is("fields"),is("name"),Cs("active",{}),Cs("apis",{}),Cs("state",da),Cs("extra",{})]),pa=e=>{const t=es("Creating behaviour: "+e.name,ga,e);return((e,t,o,n,s,r)=>{const a=Rn(e),i=ks(t,[("config",l=e,bs("config",Rn(l)))]);var l;return ca(a,i,t,o,n,s,r)})(t.fields,t.name,t.active,t.apis,t.extra,t.state)},ha=Rn([is("branchKey"),is("branches"),is("name"),Cs("active",{}),Cs("apis",{}),Cs("state",da),Cs("extra",{})]),fa=e=>{const t=es("Creating behaviour: "+e.name,ha,e);return((e,t,o,n,s,r)=>{const a=e,i=ks(t,[bs("config",e)]);return ca(a,i,t,o,n,s,r)})(os(t.branchKey,t.branches),t.name,t.active,t.apis,t.extra,t.state)},ba=x(void 0),va=(e,t)=>{const o=_t(e,t);return void 0===o||""===o?[]:o.split(" ")},ya=e=>void 0!==e.dom.classList,xa=e=>va(e,"class"),wa=(e,t)=>((e,t,o)=>{const n=va(e,t).concat([o]);return Ct(e,t,n.join(" ")),!0})(e,"class",t),Sa=(e,t)=>((e,t,o)=>{const n=P(va(e,t),(e=>e!==o));return n.length>0?Ct(e,t,n.join(" ")):At(e,t),!1})(e,"class",t),ka=(e,t)=>{ya(e)?e.dom.classList.add(t):wa(e,t)},Ca=e=>{0===(ya(e)?e.dom.classList:xa(e)).length&&At(e,"class")},Oa=(e,t)=>{ya(e)?e.dom.classList.remove(t):Sa(e,t),Ca(e)},_a=(e,t)=>ya(e)&&e.dom.classList.contains(t),Ta=(e,t)=>{V(t,(t=>{ka(e,t)}))},Ea=(e,t)=>{V(t,(t=>{Oa(e,t)}))},Aa=e=>ya(e)?(e=>{const t=e.dom.classList,o=new Array(t.length);for(let e=0;e<t.length;e++){const n=t.item(e);null!==n&&(o[e]=n)}return o})(e):xa(e),Ma=(e,t,o,n,s)=>{const r=e=>e+"px";return{position:e,left:t.map(r),top:o.map(r),right:n.map(r),bottom:s.map(r)}},Da=(e,t)=>{Ft(e,(e=>({...e,position:A.some(e.position)}))(t))},Ba=e=>(ye(zt(e,"position"),"fixed")?A.none():it(e)).orThunk((()=>{const t=Re("span");return rt(e).bind((e=>{Vo(e,t);const o=it(t);return Uo(t),o}))})),Ia=e=>Ba(e).map(Xt).getOrThunk((()=>qt(0,0))),Fa=(e,t)=>{const o=e.element;ka(o,t.transitionClass),Oa(o,t.fadeOutClass),ka(o,t.fadeInClass),t.onShow(e)},Ra=(e,t)=>{const o=e.element;ka(o,t.transitionClass),Oa(o,t.fadeInClass),ka(o,t.fadeOutClass),t.onHide(e)},Na=(e,t)=>e.y>=t.y,za=(e,t)=>e.bottom<=t.bottom,La=(e,t,o)=>({location:"top",leftX:t,topY:o.bounds.y-e.y}),Va=(e,t,o)=>({location:"bottom",leftX:t,bottomY:e.bottom-o.bounds.bottom}),Ha=e=>e.box.x-e.win.x,Pa=(e,t,o)=>o.getInitialPos().map((o=>{const n=((e,t)=>{const o=t.optScrollEnv.fold(x(e.bounds.y),(t=>t.scrollElmTop+(e.bounds.y-t.currentScrollTop)));return qt(e.bounds.x,o)})(o,t);return{box:Jo(n.left,n.top,Qt(e),jt(e)),location:o.location}})),Ua=(e,t,o,n,s)=>{const r=((e,t)=>{const o=t.optScrollEnv.fold(x(e.y),(t=>e.y+t.currentScrollTop-t.scrollElmTop));return qt(e.x,o)})(t,o),a=Jo(r.left,r.top,t.width,t.height);n.setInitialPos({style:Lt(e),position:Rt(e,"position")||"static",bounds:a,location:s.location})},Wa=(e,t,o)=>o.getInitialPos().bind((n=>{var s;switch(o.clearInitialPos(),n.position){case"static":return A.some({morph:"static"});case"absolute":const o=Ba(e).getOr(wt()),r=Qo(o),a=null!==(s=o.dom.scrollTop)&&void 0!==s?s:0;return A.some({morph:"absolute",positionCss:Ma("absolute",fe(n.style,"left").map((e=>t.x-r.x)),fe(n.style,"top").map((e=>t.y-r.y+a)),fe(n.style,"right").map((e=>r.right-t.right)),fe(n.style,"bottom").map((e=>r.bottom-t.bottom)))});default:return A.none()}})),ja=e=>{switch(e.location){case"top":return A.some({morph:"fixed",positionCss:Ma("fixed",A.some(e.leftX),A.some(e.topY),A.none(),A.none())});case"bottom":return A.some({morph:"fixed",positionCss:Ma("fixed",A.some(e.leftX),A.none(),A.none(),A.some(e.bottomY))});default:return A.none()}},$a=(e,t,o)=>{const n=e.element;return ye(zt(n,"position"),"fixed")?((e,t,o)=>((e,t,o)=>Pa(e,t,o).filter((({box:e})=>((e,t,o)=>Y(e,(e=>{switch(e){case"bottom":return za(t,o.bounds);case"top":return Na(t,o.bounds)}})))(o.getModes(),e,t))).bind((({box:t})=>Wa(e,t,o))))(e,t,o).orThunk((()=>t.optScrollEnv.bind((n=>Pa(e,t,o))).bind((({box:e,location:o})=>{const n=tn(),s=Ha({win:n,box:e}),r="top"===o?La(n,s,t):Va(n,s,t);return ja(r)})))))(n,t,o):((e,t,o)=>{const n=Qo(e),s=tn(),r=((e,t,o)=>{const n=t.win,s=t.box,r=Ha(t);return se(e,(e=>{switch(e){case"bottom":return za(s,o.bounds)?A.none():A.some(Va(n,r,o));case"top":return Na(s,o.bounds)?A.none():A.some(La(n,r,o));default:return A.none()}})).getOr({location:"no-dock"})})(o.getModes(),{win:s,box:n},t);return"top"===r.location||"bottom"===r.location?(Ua(e,n,t,o,r),ja(r)):A.none()})(n,t,o)},Ga=(e,t,o)=>{o.setDocked(!1),V(["left","right","top","bottom","position"],(t=>Ht(e.element,t))),t.onUndocked(e)},qa=(e,t,o,n)=>{const s="fixed"===n.position;o.setDocked(s),Da(e.element,n),(s?t.onDocked:t.onUndocked)(e)},Ya=(e,t,o,n,s=!1)=>{t.contextual.each((t=>{t.lazyContext(e).each((r=>{const a=((e,t)=>e.y<t.bottom&&e.bottom>t.y)(r,n.bounds);a!==o.isVisible()&&(o.setVisible(a),s&&!a?(Ta(e.element,[t.fadeOutClass]),t.onHide(e)):(a?Fa:Ra)(e,t))}))}))},Xa=(e,t,o,n,s)=>{Ya(e,t,o,n,!0),qa(e,t,o,s.positionCss)},Ka=(e,t,o)=>{e.getSystem().isConnected()&&((e,t,o)=>{const n=t.lazyViewport(e);Ya(e,t,o,n),$a(e,n,o).each((s=>{((e,t,o,n,s)=>{switch(s.morph){case"static":return Ga(e,t,o);case"absolute":return qa(e,t,o,s.positionCss);case"fixed":Xa(e,t,o,n,s)}})(e,t,o,n,s)}))})(e,t,o)},Ja=(e,t,o)=>{o.isDocked()&&((e,t,o)=>{const n=e.element;o.setDocked(!1);const s=t.lazyViewport(e);((e,t,o)=>{const n=e.element;return Pa(n,t,o).bind((({box:e})=>Wa(n,e,o)))})(e,s,o).each((n=>{switch(n.morph){case"static":Ga(e,t,o);break;case"absolute":qa(e,t,o,n.positionCss)}})),o.setVisible(!0),t.contextual.each((t=>{Ea(n,[t.fadeInClass,t.fadeOutClass,t.transitionClass]),t.onShow(e)})),Ka(e,t,o)})(e,t,o)},Qa=e=>(t,o,n)=>{const s=o.lazyViewport(t);((e,t,o,n)=>{const s=Qo(e),r=tn(),a=n(r,Ha({win:r,box:s}),t);return"bottom"===a.location||"top"===a.location?(((e,t,o,n,s)=>{n.getInitialPos().fold((()=>Ua(e,t,o,n,s)),(()=>b))})(e,s,t,o,a),ja(a)):A.none()})(t.element,s,n,e).each((e=>{Xa(t,o,n,s,e)}))},Za=Qa(La),ei=Qa(Va);var ti,oi=Object.freeze({__proto__:null,refresh:Ka,reset:Ja,isDocked:(e,t,o)=>o.isDocked(),getModes:(e,t,o)=>o.getModes(),setModes:(e,t,o,n)=>o.setModes(n),forceDockToTop:Za,forceDockToBottom:ei}),ni=Object.freeze({__proto__:null,events:(e,t)=>Wr([Zr(ar(),((o,n)=>{e.contextual.each((e=>{_a(o.element,e.transitionClass)&&(Ea(o.element,[e.transitionClass,e.fadeInClass]),(t.isVisible()?e.onShown:e.onHidden)(o)),n.stop()}))})),Gr(Cr(),((o,n)=>{Ka(o,e,t)})),Gr(Br(),((o,n)=>{Ka(o,e,t)})),Gr(Or(),((o,n)=>{Ja(o,e,t)}))])});const si=e=>e.dom.innerHTML,ri=(e,t)=>{const o=tt(e).dom,n=ze(o.createDocumentFragment()),s=((e,t)=>{const o=(t||document).createElement("div");return o.innerHTML=e,lt(ze(o))})(t,o);Ho(n,s),Po(e),Vo(e,n)},ai=(e,t)=>ze(e.dom.cloneNode(t)),ii=e=>(e=>{if(gt(e))return"#shadow-root";{const t=(e=>ai(e,!1))(e);return(e=>{const t=Re("div"),o=ze(e.dom.cloneNode(!0));return Vo(t,o),si(t)})(t)}})(e);var li;!function(e){e[e.STOP=0]="STOP",e[e.NORMAL=1]="NORMAL",e[e.LOGGING=2]="LOGGING"}(li||(li={}));const ci=on({}),di=["alloy/data/Fields","alloy/debugging/Debugging"],ui=(e,t,o)=>((e,t,o)=>{switch(fe(ci.get(),e).orThunk((()=>{const t=re(ci.get());return se(t,(t=>e.indexOf(t)>-1?A.some(ci.get()[t]):A.none()))})).getOr(li.NORMAL)){case li.NORMAL:return o(mi());case li.LOGGING:{const n=((e,t)=>{const o=[],n=(new Date).getTime();return{logEventCut:(e,t,n)=>{o.push({outcome:"cut",target:t,purpose:n})},logEventStopped:(e,t,n)=>{o.push({outcome:"stopped",target:t,purpose:n})},logNoParent:(e,t,n)=>{o.push({outcome:"no-parent",target:t,purpose:n})},logEventNoHandlers:(e,t)=>{o.push({outcome:"no-handlers-left",target:t})},logEventResponse:(e,t,n)=>{o.push({outcome:"response",purpose:n,target:t})},write:()=>{const s=(new Date).getTime();F(["mousemove","mouseover","mouseout",wr()],e)||console.log(e,{event:e,time:s-n,target:t.dom,sequence:L(o,(e=>F(["cut","stopped","response"],e.outcome)?"{"+e.purpose+"} "+e.outcome+" at ("+ii(e.target)+")":e.outcome))})}}})(e,t),s=o(n);return n.write(),s}case li.STOP:return!0}})(e,t,o),mi=x({logEventCut:b,logEventStopped:b,logNoParent:b,logEventNoHandlers:b,logEventResponse:b,write:b}),gi=x([is("menu"),is("selectedMenu")]),pi=x([is("item"),is("selectedItem")]);x(Nn(pi().concat(gi())));const hi=x(Nn(pi())),fi=gs("initSize",[is("numColumns"),is("numRows")]),bi=()=>gs("markers",[is("backgroundMenu")].concat(gi()).concat(pi())),vi=e=>gs("markers",L(e,is)),yi=(e,t,o)=>((()=>{const e=new Error;if(void 0!==e.stack){const t=e.stack.split("\n");j(t,(e=>e.indexOf("alloy")>0&&!R(di,(t=>e.indexOf(t)>-1)))).getOr("unknown")}})(),ss(t,t,o,Kn((e=>dn.value(((...t)=>e.apply(void 0,t))))))),xi=e=>yi(0,e,Cn(b)),wi=e=>yi(0,e,Cn(A.none)),Si=e=>yi(0,e,{tag:"required",process:{}}),ki=e=>yi(0,e,{tag:"required",process:{}}),Ci=(e,t)=>rs(e,x(t)),Oi=e=>rs(e,w),_i=x(fi);var Ti=[ks("contextual",[ds("fadeInClass"),ds("fadeOutClass"),ds("transitionClass"),ms("lazyContext"),xi("onShow"),xi("onShown"),xi("onHide"),xi("onHidden")]),Ms("lazyViewport",(()=>({bounds:tn(),optScrollEnv:A.none()}))),Ds("modes",["top","bottom"],jn),xi("onDocked"),xi("onUndocked")];const Ei=pa({fields:Ti,name:"docking",active:ni,apis:oi,state:Object.freeze({__proto__:null,init:e=>{const t=on(!1),o=on(!0),n=rn(),s=on(e.modes);return ua({isDocked:t.get,setDocked:t.set,getInitialPos:n.get,setInitialPos:n.set,clearInitialPos:n.clear,isVisible:o.get,setVisible:o.set,getModes:s.get,setModes:s.set,readState:()=>`docked:  ${t.get()}, visible: ${o.get()}, modes: ${s.get().join(",")}`})}})}),Ai=Wr([((e,t)=>({key:e,value:Ps({can:(e,t)=>{const o=t.event,n=o.originator,s=o.target;return!((e,t,o)=>Ze(t,e.element)&&!Ze(t,o))(e,n,s)||(console.warn(ur()+" did not get interpreted by the desired target. \nOriginator: "+ii(n)+"\nTarget: "+ii(s)+"\nCheck the "+ur()+" event handlers"),!1)}})}))(ur())]);var Mi=Object.freeze({__proto__:null,events:Ai});let Di=0;const Bi=e=>{const t=(new Date).getTime(),o=Math.floor(1e9*Math.random());return Di++,e+"_"+o+Di+String(t)},Ii=x("alloy-id-"),Fi=x("data-alloy-id"),Ri=Ii(),Ni=Fi(),zi=(e,t)=>{Object.defineProperty(e.dom,Ni,{value:t,writable:!0})},Li=e=>{const t=$e(e)?e.dom[Ni]:null;return A.from(t)},Vi=e=>Bi(e),Hi=w,Pi=e=>{const t=t=>`The component must be in a context to execute: ${t}`+(e?"\n"+ii(e().element)+" is not in context.":""),o=e=>()=>{throw new Error(t(e))},n=e=>()=>{console.warn(t(e))};return{debugInfo:x("fake"),triggerEvent:n("triggerEvent"),triggerFocus:n("triggerFocus"),triggerEscape:n("triggerEscape"),broadcast:n("broadcast"),broadcastOn:n("broadcastOn"),broadcastEvent:n("broadcastEvent"),build:o("build"),buildOrPatch:o("buildOrPatch"),addToWorld:o("addToWorld"),removeFromWorld:o("removeFromWorld"),addToGui:o("addToGui"),removeFromGui:o("removeFromGui"),getByUid:o("getByUid"),getByDom:o("getByDom"),isConnected:T}},Ui=Pi(),Wi=Bi("alloy-premade"),ji=e=>(Object.defineProperty(e.element.dom,Wi,{value:e.uid,writable:!0}),Fs(Wi,e)),$i=e=>fe(e,Wi),Gi=e=>((e,t)=>{const o=t.toString(),n=o.indexOf(")")+1,s=o.indexOf("("),r=o.substring(s+1,n-1).split(/,\s*/);return e.toFunctionAnnotation=()=>({name:"OVERRIDE",parameters:sa(r.slice(1))}),e})(((t,...o)=>e(t.getApis(),t,...o)),e),qi=(e,t)=>{const o={};return ie(e,((e,n)=>{ie(e,((e,s)=>{const r=fe(o,s).getOr([]);o[s]=r.concat([t(n,e)])}))})),o},Yi=e=>e.cHandler,Xi=(e,t)=>({name:e,handler:t}),Ki=(e,t)=>{const o={};return V(e,(e=>{o[e.name()]=e.handlers(t)})),o},Ji=(e,t,o)=>{const n=t[o];return n?((e,t,o,n)=>{try{const s=Z(o,((o,s)=>{const r=o[t],a=s[t],i=n.indexOf(r),l=n.indexOf(a);if(-1===i)throw new Error("The ordering for "+e+" does not have an entry for "+r+".\nOrder specified: "+JSON.stringify(n,null,2));if(-1===l)throw new Error("The ordering for "+e+" does not have an entry for "+a+".\nOrder specified: "+JSON.stringify(n,null,2));return i<l?-1:l<i?1:0}));return dn.value(s)}catch(e){return dn.error([e])}})("Event: "+o,"name",e,n).map((e=>(e=>{const t=((e,t)=>(...t)=>W(e,((e,o)=>e&&(e=>e.can)(o).apply(void 0,t)),!0))(e),o=((e,t)=>(...t)=>W(e,((e,o)=>e||(e=>e.abort)(o).apply(void 0,t)),!1))(e);return{can:t,abort:o,run:(...t)=>{V(e,(e=>{e.run.apply(void 0,t)}))}}})(L(e,(e=>e.handler))))):((e,t)=>dn.error(["The event ("+e+') has more than one behaviour that listens to it.\nWhen this occurs, you must specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that can trigger it are: '+JSON.stringify(L(t,(e=>e.name)),null,2)]))(o,e)},Qi=(e,t)=>((e,t)=>{const o=(e=>{const t=[],o=[];return V(e,(e=>{e.fold((e=>{t.push(e)}),(e=>{o.push(e)}))})),{errors:t,values:o}})(e);return o.errors.length>0?(n=o.errors,dn.error(G(n))):((e,t)=>0===e.length?dn.value(t):dn.value(wn(t,Sn.apply(void 0,e))))(o.values,t);var n})(ge(e,((e,o)=>(1===e.length?dn.value(e[0].handler):Ji(e,t,o)).map((n=>{const s=(e=>{const t=(e=>p(e)?{can:E,abort:T,run:e}:e)(e);return(e,o,...n)=>{const s=[e,o].concat(n);t.abort.apply(void 0,s)?o.stop():t.can.apply(void 0,s)&&t.run.apply(void 0,s)}})(n),r=e.length>1?P(t[o],(t=>R(e,(e=>e.name===t)))).join(" > "):e[0].name;return Fs(o,((e,t)=>({handler:e,purpose:t}))(s,r))})))),{}),Zi="alloy.base.behaviour",el=Nn([ss("dom","dom",{tag:"required",process:{}},Nn([is("tag"),Cs("styles",{}),Cs("classes",[]),Cs("attributes",{}),fs("value"),fs("innerHtml")])),is("components"),is("uid"),Cs("events",{}),Cs("apis",{}),ss("eventOrder","eventOrder",(bl={[hr()]:["disabling",Zi,"toggling","typeaheadevents"],[ur()]:[Zi,"focusing","keying"],[wr()]:[Zi,"disabling","toggling","representing"],[or()]:[Zi,"representing","streaming","invalidating"],[Tr()]:[Zi,"representing","item-events","toolbar-button-events","tooltipping"],[qs()]:["focusing",Zi,"item-type-events"],[Ws()]:["focusing",Zi,"item-type-events"],[Js()]:["item-type-events","tooltipping"],[pr()]:["receiving","reflecting","tooltipping"]},On(x(bl))),Pn()),fs("domModification")]),tl=e=>e.events,ol=e=>e.dom.value,nl=(e,t)=>{if(void 0===t)throw new Error("Value.set was undefined");e.dom.value=t},sl=(e,t,o)=>{o.fold((()=>Vo(e,t)),(e=>{Ze(e,t)||(No(e,t),Uo(e))}))},rl=(e,t,o)=>{const n=L(t,o),s=lt(e);return V(s.slice(n.length),Uo),n},al=(e,t,o,n)=>{const s=ct(e,t),r=n(o,s),a=((e,t,o)=>ct(e,t).map((e=>{if(o.exists((t=>!Ze(t,e)))){const t=o.map(Ue).getOr("span"),n=Re(t);return No(e,n),n}return e})))(e,t,s);return sl(e,r.element,a),r},il=(e,t)=>{const o=re(e),n=re(t),s=K(n,o),r=((e,o)=>{const n={},s={};return ue(e,((e,o)=>!be(t,o)||e!==t[o]),de(n),de(s)),{t:n,f:s}})(e).t;return{toRemove:s,toSet:r}},ll=(e,t)=>{const o=t.filter((t=>Ue(t)===e.tag&&!(e=>e.innerHtml.isSome()&&e.domChildren.length>0)(e)&&!(e=>be(e.dom,Wi))(t))).bind((t=>((e,t)=>{try{const o=((e,t)=>{const{class:o,style:n,...s}=(e=>W(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}))(t),{toSet:r,toRemove:a}=il(e.attributes,s),i=Lt(t),{toSet:l,toRemove:c}=il(e.styles,i),d=Aa(t),u=K(d,e.classes),m=K(e.classes,d);return V(a,(e=>At(t,e))),Ot(t,r),Ta(t,m),Ea(t,u),V(c,(e=>Ht(t,e))),It(t,l),e.innerHtml.fold((()=>{const o=e.domChildren;((e,t)=>{rl(e,t,((t,o)=>{const n=ct(e,o);return sl(e,t,n),t}))})(t,o)}),(e=>{ri(t,e)})),(()=>{const o=t,n=e.value.getOrUndefined();n!==ol(o)&&nl(o,null!=n?n:"")})(),t})(e,t);return A.some(o)}catch(e){return A.none()}})(e,t))).getOrThunk((()=>(e=>{const t=Re(e.tag);Ot(t,e.attributes),Ta(t,e.classes),It(t,e.styles),e.innerHtml.each((e=>ri(t,e)));const o=e.domChildren;return Ho(t,o),e.value.each((e=>{nl(t,e)})),t})(e)));return zi(o,e.uid),o},cl=e=>{const t=(e=>{const t=fe(e,"behaviours").getOr({});return q(re(t),(e=>{const o=t[e];return g(o)?[o.me]:[]}))})(e);return((e,t)=>((e,t)=>{const o=L(t,(e=>ks(e.name(),[is("config"),Cs("state",da)]))),n=Qn("component.behaviours",Nn(o),e.behaviours).fold((t=>{throw new Error(ts(t)+"\nComplete spec:\n"+JSON.stringify(e,null,2))}),w);return{list:t,data:le(n,(e=>{const t=e.map((e=>({config:e.config,state:e.state.init(e.config)})));return x(t)}))}})(e,t))(e,t)},dl=(e,t)=>{const o=()=>m,n=on(Ui),s=Zn((e=>Qn("custom.definition",el,e))(e)),r=cl(e),a=(e=>e.list)(r),i=(e=>e.data)(r),l=((e,t,o)=>{const n={...(s=e).dom,uid:s.uid,domChildren:L(s.components,(e=>e.element))};var s;const r=(e=>e.domModification.fold((()=>aa({})),aa))(e),a={"alloy.base.modification":r},i=t.length>0?((e,t,o,n)=>{const s={...t};V(o,(t=>{s[t.name()]=t.exhibit(e,n)}));const r=qi(s,((e,t)=>({name:e,modification:t}))),a=e=>U(e,((e,t)=>({...t.modification,...e})),{}),i=U(r.classes,((e,t)=>t.modification.concat(e)),[]),l=a(r.attributes),c=a(r.styles);return aa({classes:i,attributes:l,styles:c})})(o,a,t,n):r;return l=n,c=i,{...l,attributes:{...l.attributes,...c.attributes},styles:{...l.styles,...c.styles},classes:l.classes.concat(c.classes)};var l,c})(s,a,i),c=ll(l,t),d=((e,t,o)=>{const n={"alloy.base.behaviour":tl(e)};return((e,t,o,n)=>{const s=((e,t,o)=>{const n={...o,...Ki(t,e)};return qi(n,Xi)})(e,o,n);return Qi(s,t)})(o,e.eventOrder,t,n).getOrDie()})(s,a,i),u=on(s.components),m={uid:e.uid,getSystem:n.get,config:t=>{const o=i;return(p(o[t.name()])?o[t.name()]:()=>{throw new Error("Could not find "+t.name()+" in "+JSON.stringify(e,null,2))})()},hasConfigured:e=>p(i[e.name()]),spec:e,readState:e=>i[e]().map((e=>e.state.readState())).getOr("not enabled"),getApis:()=>s.apis,connect:e=>{n.set(e)},disconnect:()=>{n.set(Pi(o))},element:c,syncComponents:()=>{const e=lt(c),t=q(e,(e=>n.get().getByDom(e).fold((()=>[]),Q)));u.set(t)},components:u.get,events:d};return m},ul=e=>{const t=Ne(e);return ml({element:t})},ml=e=>{const t=es("external.component",Rn([is("element"),fs("uid")]),e),o=on(Pi()),n=t.uid.getOrThunk((()=>Vi("external")));zi(t.element,n);const s={uid:n,getSystem:o.get,config:A.none,hasConfigured:T,connect:e=>{o.set(e)},disconnect:()=>{o.set(Pi((()=>s)))},getApis:()=>({}),element:t.element,spec:e,readState:x("No state"),syncComponents:b,components:x([]),events:{}};return ji(s)},gl=Vi,pl=(e,t)=>$i(e).getOrThunk((()=>((e,t)=>{const{events:o,...n}=Hi(e),s=((e,t)=>{const o=fe(e,"components").getOr([]);return t.fold((()=>L(o,hl)),(e=>L(o,((t,o)=>pl(t,ct(e,o))))))})(n,t),r={...n,events:{...Mi,...o},components:s};return dn.value(dl(r,t))})((e=>be(e,"uid"))(e)?e:{uid:gl(""),...e},t).getOrDie())),hl=e=>pl(e,A.none()),fl=ji;var bl,vl=(e,t,o,n,s)=>e(o,n)?A.some(o):p(s)&&s(o)?A.none():t(o,n,s);const yl=(e,t,o)=>{let n=e.dom;const s=p(o)?o:T;for(;n.parentNode;){n=n.parentNode;const e=ze(n);if(t(e))return A.some(e);if(s(e))break}return A.none()},xl=(e,t,o)=>vl(((e,t)=>t(e)),yl,e,t,o),wl=(e,t)=>j(e.dom.childNodes,(e=>t(ze(e)))).map(ze),Sl=(e,t,o)=>xl(e,t,o).isSome(),kl=(e,t,o)=>yl(e,(e=>Ke(e,t)),o),Cl=(e,t)=>((e,o)=>{const n=e.dom;return n.parentNode?wl(ze(n.parentNode),(o=>!Ze(e,o)&&Ke(o,t))):A.none()})(e),Ol=(e,t)=>wl(e,(e=>Ke(e,t))),_l=(e,t)=>Qe(t,e),Tl=(e,t,o)=>vl(((e,t)=>Ke(e,t)),kl,e,t,o),El="aria-controls",Al=()=>{const e=Bi(El);return{id:e,link:t=>{Ct(t,El,e)},unlink:e=>{At(e,El)}}},Ml=(e,t)=>Sl(t,(t=>Ze(t,e.element)),T)||((e,t)=>(e=>xl(e,(e=>{if(!$e(e))return!1;const t=_t(e,"id");return void 0!==t&&t.indexOf(El)>-1})).bind((e=>{const t=_t(e,"id"),o=ft(e);return _l(o,`[${El}="${t}"]`)})))(t).exists((t=>Ml(e,t))))(e,t),Dl=(e,t,o,n,s,r,a,i=!1)=>({x:e,y:t,bubble:o,direction:n,placement:s,restriction:r,label:`${a}-${s}`,alwaysFit:i}),Bl=Is([{southeast:[]},{southwest:[]},{northeast:[]},{northwest:[]},{south:[]},{north:[]},{east:[]},{west:[]}]),Il=Bl.southeast,Fl=Bl.southwest,Rl=Bl.northeast,Nl=Bl.northwest,zl=Bl.south,Ll=Bl.north,Vl=Bl.east,Hl=Bl.west,Pl=(e,t,o,n)=>{const s=e+t;return s>n?o:s<o?n:s},Ul=(e,t,o)=>Math.min(Math.max(e,t),o),Wl=(e,t)=>J(["left","right","top","bottom"],(o=>fe(t,o).map((t=>((e,t)=>{switch(t){case 1:return e.x;case 0:return e.x+e.width;case 2:return e.y;case 3:return e.y+e.height}})(e,t))))),jl="layout",$l=e=>e.x,Gl=(e,t)=>e.x+e.width/2-t.width/2,ql=(e,t)=>e.x+e.width-t.width,Yl=(e,t)=>e.y-t.height,Xl=e=>e.y+e.height,Kl=(e,t)=>e.y+e.height/2-t.height/2,Jl=(e,t,o)=>Dl($l(e),Xl(e),o.southeast(),Il(),"southeast",Wl(e,{left:1,top:3}),jl),Ql=(e,t,o)=>Dl(ql(e,t),Xl(e),o.southwest(),Fl(),"southwest",Wl(e,{right:0,top:3}),jl),Zl=(e,t,o)=>Dl($l(e),Yl(e,t),o.northeast(),Rl(),"northeast",Wl(e,{left:1,bottom:2}),jl),ec=(e,t,o)=>Dl(ql(e,t),Yl(e,t),o.northwest(),Nl(),"northwest",Wl(e,{right:0,bottom:2}),jl),tc=(e,t,o)=>Dl(Gl(e,t),Yl(e,t),o.north(),Ll(),"north",Wl(e,{bottom:2}),jl),oc=(e,t,o)=>Dl(Gl(e,t),Xl(e),o.south(),zl(),"south",Wl(e,{top:3}),jl),nc=(e,t,o)=>Dl((e=>e.x+e.width)(e),Kl(e,t),o.east(),Vl(),"east",Wl(e,{left:0}),jl),sc=(e,t,o)=>Dl(((e,t)=>e.x-t.width)(e,t),Kl(e,t),o.west(),Hl(),"west",Wl(e,{right:1}),jl),rc=()=>[Jl,Ql,Zl,ec,oc,tc,nc,sc],ac=()=>[Ql,Jl,ec,Zl,oc,tc,nc,sc],ic=()=>[Zl,ec,Jl,Ql,tc,oc],lc=()=>[ec,Zl,Ql,Jl,tc,oc],cc=()=>[Jl,Ql,Zl,ec,oc,tc],dc=()=>[Ql,Jl,ec,Zl,oc,tc];var uc=Object.freeze({__proto__:null,events:e=>Wr([Gr(pr(),((t,o)=>{const n=e.channels,s=re(n),r=o,a=((e,t)=>t.universal?e:P(e,(e=>F(t.channels,e))))(s,r);V(a,(e=>{const o=n[e],s=o.schema,a=es("channel["+e+"] data\nReceiver: "+ii(t.element),s,r.data);o.onReceive(t,a)}))}))])}),mc=[ls("channels",Jn(dn.value,Rn([Si("onReceive"),Cs("schema",Pn())])))];const gc=pa({fields:mc,name:"receiving",active:uc});var pc=Object.freeze({__proto__:null,exhibit:(e,t)=>aa({classes:[],styles:t.useFixed()?{}:{position:"relative"}})});const hc=(e,t=!1)=>e.dom.focus({preventScroll:t}),fc=e=>e.dom.blur(),bc=e=>{const t=ft(e).dom;return e.dom===t.activeElement},vc=(e=qo())=>A.from(e.dom.activeElement).map(ze),yc=e=>vc(ft(e)).filter((t=>e.dom.contains(t.dom))),xc=(e,t)=>{const o=ft(t),n=vc(o).bind((e=>{const o=t=>Ze(e,t);return o(t)?A.some(t):((e,t)=>{const o=e=>{for(let n=0;n<e.childNodes.length;n++){const s=ze(e.childNodes[n]);if(t(s))return A.some(s);const r=o(e.childNodes[n]);if(r.isSome())return r}return A.none()};return o(e.dom)})(t,o)})),s=e(t);return n.each((e=>{vc(o).filter((t=>Ze(t,e))).fold((()=>{hc(e)}),b)})),s},wc=Is([{none:[]},{relative:["x","y","width","height"]},{fixed:["x","y","width","height"]}]),Sc=(e,t,o,n,s,r)=>{const a=t.rect,i=a.x-o,l=a.y-n,c=s-(i+a.width),d=r-(l+a.height),u=A.some(i),m=A.some(l),g=A.some(c),p=A.some(d),h=A.none();return t.direction.fold((()=>Ma(e,u,m,h,h)),(()=>Ma(e,h,m,g,h)),(()=>Ma(e,u,h,h,p)),(()=>Ma(e,h,h,g,p)),(()=>Ma(e,u,m,h,h)),(()=>Ma(e,u,h,h,p)),(()=>Ma(e,u,m,h,h)),(()=>Ma(e,h,m,g,h)))},kc=(e,t)=>e.fold((()=>{const e=t.rect;return Ma("absolute",A.some(e.x),A.some(e.y),A.none(),A.none())}),((e,o,n,s)=>Sc("absolute",t,e,o,n,s)),((e,o,n,s)=>Sc("fixed",t,e,o,n,s))),Cc=(e,t)=>{const o=k(Ko,t),n=e.fold(o,o,(()=>{const e=Wo();return Ko(t).translate(-e.left,-e.top)})),s=Zt(t),r=$t(t);return Jo(n.left,n.top,s,r)},Oc=(e,t)=>t.fold((()=>e.fold(tn,tn,Jo)),(t=>e.fold(x(t),x(t),(()=>{const o=_c(e,t.x,t.y);return Jo(o.left,o.top,t.width,t.height)})))),_c=(e,t,o)=>{const n=qt(t,o);return e.fold(x(n),x(n),(()=>{const e=Wo();return n.translate(-e.left,-e.top)}))};wc.none;const Tc=wc.relative,Ec=wc.fixed,Ac="data-alloy-placement",Mc=e=>Tt(e,Ac),Dc=Is([{fit:["reposition"]},{nofit:["reposition","visibleW","visibleH","isVisible"]}]),Bc=(e,t,o,n)=>{const s=e.bubble,r=s.offset,a=((e,t,o)=>{const n=(n,s)=>t[n].map((t=>{const r="top"===n||"bottom"===n,a=r?o.top:o.left,i=("left"===n||"top"===n?Math.max:Math.min)(t,s)+a;return r?Ul(i,e.y,e.bottom):Ul(i,e.x,e.right)})).getOr(s),s=n("left",e.x),r=n("top",e.y),a=n("right",e.right),i=n("bottom",e.bottom);return Jo(s,r,a-s,i-r)})(n,e.restriction,r),i=e.x+r.left,l=e.y+r.top,c=Jo(i,l,t,o),{originInBounds:d,sizeInBounds:u,visibleW:m,visibleH:g}=((e,t)=>{const{x:o,y:n,right:s,bottom:r}=t,{x:a,y:i,right:l,bottom:c,width:d,height:u}=e;return{originInBounds:a>=o&&a<=s&&i>=n&&i<=r,sizeInBounds:l<=s&&l>=o&&c<=r&&c>=n,visibleW:Math.min(d,a>=o?s-a:l-o),visibleH:Math.min(u,i>=n?r-i:c-n)}})(c,a),p=d&&u,h=p?c:((e,t)=>{const{x:o,y:n,right:s,bottom:r}=t,{x:a,y:i,width:l,height:c}=e,d=Math.max(o,s-l),u=Math.max(n,r-c),m=Ul(a,o,d),g=Ul(i,n,u),p=Math.min(m+l,s)-m,h=Math.min(g+c,r)-g;return Jo(m,g,p,h)})(c,a),f=h.width>0&&h.height>0,{maxWidth:b,maxHeight:v}=((e,t,o)=>{const n=x(t.bottom-o.y),s=x(o.bottom-t.y),r=((e,t,o,n)=>e.fold(t,t,n,n,t,n,o,o))(e,s,s,n),a=x(t.right-o.x),i=x(o.right-t.x),l=((e,t,o,n)=>e.fold(t,n,t,n,o,o,t,n))(e,i,i,a);return{maxWidth:l,maxHeight:r}})(e.direction,h,n),y={rect:h,maxHeight:v,maxWidth:b,direction:e.direction,placement:e.placement,classes:{on:s.classesOn,off:s.classesOff},layout:e.label,testY:l};return p||e.alwaysFit?Dc.fit(y):Dc.nofit(y,m,g,f)},Ic=E,Fc=(e,t,o)=>((e,t,o,n)=>Fo(e,t,o,n,!1))(e,t,Ic,o),Rc=(e,t,o)=>((e,t,o,n)=>Fo(e,t,o,n,!0))(e,t,Ic,o),Nc=Io,zc=["top","bottom","right","left"],Lc="data-alloy-transition-timer",Vc=(e,t,o,n,s,a)=>{const i=((e,t,o)=>o.exists((o=>{const n=e.mode;return"all"===n||o[n]!==t[n]})))(n,s,a);if(i||((e,t)=>((e,t)=>Y(t,(t=>_a(e,t))))(e,t.classes))(e,n)){Bt(e,"position",o.position);const a=Cc(t,e),l=kc(t,{...s,rect:a}),c=J(zc,(e=>l[e]));((e,t)=>{const o=e=>parseFloat(e).toFixed(3);return pe(t,((t,n)=>!((e,t,o=S)=>we(e,t,o).getOr(e.isNone()&&t.isNone()))(e[n].map(o),t.map(o)))).isSome()})(o,c)&&(Ft(e,c),i&&((e,t)=>{Ta(e,t.classes),Tt(e,Lc).each((t=>{clearTimeout(parseInt(t,10)),At(e,Lc)})),((e,t)=>{const o=sn(),n=sn();let s;const a=t=>{var o;const n=null!==(o=t.raw.pseudoElement)&&void 0!==o?o:"";return Ze(t.target,e)&&De(n)&&F(zc,t.raw.propertyName)},i=r=>{if(m(r)||a(r)){o.clear(),n.clear();const a=null==r?void 0:r.raw.type;(m(a)||a===ar())&&(clearTimeout(s),At(e,Lc),Ea(e,t.classes))}},l=Fc(e,ir(),(t=>{a(t)&&(l.unbind(),o.set(Fc(e,ar(),i)),n.set(Fc(e,rr(),i)))})),c=(e=>{const t=t=>{const o=Rt(e,t).split(/\s*,\s*/);return P(o,Me)},o=e=>{if(r(e)&&/^[\d.]+/.test(e)){const t=parseFloat(e);return Ee(e,"ms")?t:1e3*t}return 0},n=t("transition-delay"),s=t("transition-duration");return W(s,((e,t,s)=>{const r=o(n[s])+o(t);return Math.max(e,r)}),0)})(e);requestAnimationFrame((()=>{s=setTimeout(i,c+17),Ct(e,Lc,s)}))})(e,t)})(e,n),Pt(e))}else Ea(e,n.classes)},Hc=(e,t)=>{((e,t)=>{const o=Wt.max(e,t,["margin-top","border-top-width","padding-top","padding-bottom","border-bottom-width","margin-bottom"]);Bt(e,"max-height",o+"px")})(e,Math.floor(t))},Pc=x(((e,t)=>{Hc(e,t),It(e,{"overflow-x":"hidden","overflow-y":"auto"})})),Uc=x(((e,t)=>{Hc(e,t)})),Wc=(e,t,o)=>void 0===e[t]?o:e[t],jc=(e,t,o,n)=>{const s=((e,t,o,n)=>{Ht(t,"max-height"),Ht(t,"max-width");const s={width:Zt(r=t),height:$t(r)};var r;return((e,t,o,n,s,r)=>{const a=n.width,i=n.height,l=(t,l,c,d,u)=>{const m=t(o,n,s,e,r),g=Bc(m,a,i,r);return g.fold(x(g),((e,t,o,n)=>(u===n?o>d||t>c:!u&&n)?g:Dc.nofit(l,c,d,u)))};return W(t,((e,t)=>{const o=k(l,t);return e.fold(x(e),o)}),Dc.nofit({rect:o,maxHeight:n.height,maxWidth:n.width,direction:Il(),placement:"southeast",classes:{on:[],off:[]},layout:"none",testY:o.y},-1,-1,!1)).fold(w,w)})(t,n.preference,e,s,o,n.bounds)})(e,t,o,n);return((e,t,o)=>{const n=kc(o.origin,t);o.transition.each((s=>{Vc(e,o.origin,n,s,t,o.lastPlacement)})),Da(e,n)})(t,s,n),((e,t)=>{((e,t)=>{Ct(e,Ac,t)})(e,t.placement)})(t,s),((e,t)=>{const o=t.classes;Ea(e,o.off),Ta(e,o.on)})(t,s),((e,t,o)=>{(0,o.maxHeightFunction)(e,t.maxHeight)})(t,s,n),((e,t,o)=>{(0,o.maxWidthFunction)(e,t.maxWidth)})(t,s,n),{layout:s.layout,placement:s.placement}},$c=["valignCentre","alignLeft","alignRight","alignCentre","top","bottom","left","right","inset"],Gc=(e,t,o,n=1)=>{const s=e*n,r=t*n,a=e=>fe(o,e).getOr([]),i=(e,t,o)=>{const n=K($c,o);return{offset:qt(e,t),classesOn:q(o,a),classesOff:q(n,a)}};return{southeast:()=>i(-e,t,["top","alignLeft"]),southwest:()=>i(e,t,["top","alignRight"]),south:()=>i(-e/2,t,["top","alignCentre"]),northeast:()=>i(-e,-t,["bottom","alignLeft"]),northwest:()=>i(e,-t,["bottom","alignRight"]),north:()=>i(-e/2,-t,["bottom","alignCentre"]),east:()=>i(e,-t/2,["valignCentre","left"]),west:()=>i(-e,-t/2,["valignCentre","right"]),insetNortheast:()=>i(s,r,["top","alignLeft","inset"]),insetNorthwest:()=>i(-s,r,["top","alignRight","inset"]),insetNorth:()=>i(-s/2,r,["top","alignCentre","inset"]),insetSoutheast:()=>i(s,-r,["bottom","alignLeft","inset"]),insetSouthwest:()=>i(-s,-r,["bottom","alignRight","inset"]),insetSouth:()=>i(-s/2,-r,["bottom","alignCentre","inset"]),insetEast:()=>i(-s,-r/2,["valignCentre","right","inset"]),insetWest:()=>i(s,-r/2,["valignCentre","left","inset"])}},qc=()=>Gc(0,0,{}),Yc=w,Xc=(e,t)=>o=>"rtl"===Kc(o)?t:e,Kc=e=>"rtl"===Rt(e,"direction")?"rtl":"ltr";var Jc;!function(e){e.TopToBottom="toptobottom",e.BottomToTop="bottomtotop"}(Jc||(Jc={}));const Qc="data-alloy-vertical-dir",Zc=e=>Sl(e,(e=>$e(e)&&_t(e,"data-alloy-vertical-dir")===Jc.BottomToTop)),ed=()=>ks("layouts",[is("onLtr"),is("onRtl"),fs("onBottomLtr"),fs("onBottomRtl")]),td=(e,t,o,n,s,r,a)=>{const i=a.map(Zc).getOr(!1),l=t.layouts.map((t=>t.onLtr(e))),c=t.layouts.map((t=>t.onRtl(e))),d=i?t.layouts.bind((t=>t.onBottomLtr.map((t=>t(e))))).or(l).getOr(s):l.getOr(o),u=i?t.layouts.bind((t=>t.onBottomRtl.map((t=>t(e))))).or(c).getOr(r):c.getOr(n);return Xc(d,u)(e)};var od=[is("hotspot"),fs("bubble"),Cs("overrides",{}),ed(),Ci("placement",((e,t,o)=>{const n=t.hotspot,s=Cc(o,n.element),r=td(e.element,t,cc(),dc(),ic(),lc(),A.some(t.hotspot.element));return A.some(Yc({anchorBox:s,bubble:t.bubble.getOr(qc()),overrides:t.overrides,layouts:r}))}))],nd=[is("x"),is("y"),Cs("height",0),Cs("width",0),Cs("bubble",qc()),Cs("overrides",{}),ed(),Ci("placement",((e,t,o)=>{const n=_c(o,t.x,t.y),s=Jo(n.left,n.top,t.width,t.height),r=td(e.element,t,rc(),ac(),rc(),ac(),A.none());return A.some(Yc({anchorBox:s,bubble:t.bubble,overrides:t.overrides,layouts:r}))}))];const sd=Is([{screen:["point"]},{absolute:["point","scrollLeft","scrollTop"]}]),rd=e=>e.fold(w,((e,t,o)=>e.translate(-t,-o))),ad=e=>e.fold(w,w),id=e=>W(e,((e,t)=>e.translate(t.left,t.top)),qt(0,0)),ld=e=>{const t=L(e,ad);return id(t)},cd=sd.screen,dd=sd.absolute,ud=(e,t,o)=>{const n=tt(e.element),s=Wo(n),r=((e,t,o)=>{const n=st(o.root).dom;return A.from(n.frameElement).map(ze).filter((t=>{const o=tt(t),n=tt(e.element);return Ze(o,n)})).map(Xt)})(e,0,o).getOr(s);return dd(r,s.left,s.top)},md=(e,t,o,n)=>{const s=cd(qt(e,t));return A.some(((e,t,o)=>({point:e,width:t,height:o}))(s,o,n))},gd=(e,t,o,n,s)=>e.map((e=>{const r=[t,e.point],a=(i=()=>ld(r),l=()=>ld(r),c=()=>(e=>{const t=L(e,rd);return id(t)})(r),n.fold(i,l,c));var i,l,c;const d=(p=a.left,h=a.top,f=e.width,b=e.height,{x:p,y:h,width:f,height:b}),u=o.showAbove?ic():cc(),m=o.showAbove?lc():dc(),g=td(s,o,u,m,u,m,A.none());var p,h,f,b;return Yc({anchorBox:d,bubble:o.bubble.getOr(qc()),overrides:o.overrides,layouts:g})}));var pd=[is("node"),is("root"),fs("bubble"),ed(),Cs("overrides",{}),Cs("showAbove",!1),Ci("placement",((e,t,o)=>{const n=ud(e,0,t);return t.node.filter(xt).bind((s=>{const r=s.dom.getBoundingClientRect(),a=md(r.left,r.top,r.width,r.height),i=t.node.getOr(e.element);return gd(a,n,t,o,i)}))}))];const hd=(e,t,o,n)=>({start:e,soffset:t,finish:o,foffset:n}),fd=Is([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),bd=(fd.before,fd.on,fd.after,e=>e.fold(w,w,w)),vd=Is([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),yd={domRange:vd.domRange,relative:vd.relative,exact:vd.exact,exactFromRange:e=>vd.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>ze(e.startContainer),relative:(e,t)=>bd(e),exact:(e,t,o,n)=>e}))(e);return st(t)},range:hd},xd=(e,t,o)=>{const n=e.document.createRange();var s;return s=n,t.fold((e=>{s.setStartBefore(e.dom)}),((e,t)=>{s.setStart(e.dom,t)}),(e=>{s.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,o)=>{e.setEnd(t.dom,o)}),(t=>{e.setEndAfter(t.dom)}))})(n,o),n},wd=(e,t,o,n,s)=>{const r=e.document.createRange();return r.setStart(t.dom,o),r.setEnd(n.dom,s),r},Sd=e=>({left:e.left,top:e.top,right:e.right,bottom:e.bottom,width:e.width,height:e.height}),kd=Is([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),Cd=(e,t,o)=>t(ze(o.startContainer),o.startOffset,ze(o.endContainer),o.endOffset),Od=(e,t)=>((e,t)=>{const o=((e,t)=>t.match({domRange:e=>({ltr:x(e),rtl:A.none}),relative:(t,o)=>({ltr:eo((()=>xd(e,t,o))),rtl:eo((()=>A.some(xd(e,o,t))))}),exact:(t,o,n,s)=>({ltr:eo((()=>wd(e,t,o,n,s))),rtl:eo((()=>A.some(wd(e,n,s,t,o))))})}))(e,t);return((e,t)=>{const o=t.ltr();return o.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>kd.rtl(ze(e.endContainer),e.endOffset,ze(e.startContainer),e.startOffset))).getOrThunk((()=>Cd(0,kd.ltr,o))):Cd(0,kd.ltr,o)})(0,o)})(e,t).match({ltr:(t,o,n,s)=>{const r=e.document.createRange();return r.setStart(t.dom,o),r.setEnd(n.dom,s),r},rtl:(t,o,n,s)=>{const r=e.document.createRange();return r.setStart(n.dom,s),r.setEnd(t.dom,o),r}});kd.ltr,kd.rtl;const _d=(e,t,o)=>P(((e,t)=>{const o=p(t)?t:T;let n=e.dom;const s=[];for(;null!==n.parentNode&&void 0!==n.parentNode;){const e=n.parentNode,t=ze(e);if(s.push(t),!0===o(t))break;n=e}return s})(e,o),t),Td=(e,t)=>((e,t)=>{const o=void 0===t?document:t.dom;return Je(o)?[]:L(o.querySelectorAll(e),ze)})(t,e),Ed=e=>{if(e.rangeCount>0){const t=e.getRangeAt(0),o=e.getRangeAt(e.rangeCount-1);return A.some(hd(ze(t.startContainer),t.startOffset,ze(o.endContainer),o.endOffset))}return A.none()},Ad=e=>{if(null===e.anchorNode||null===e.focusNode)return Ed(e);{const t=ze(e.anchorNode),o=ze(e.focusNode);return((e,t,o,n)=>{const s=((e,t,o,n)=>{const s=tt(e).dom.createRange();return s.setStart(e.dom,t),s.setEnd(o.dom,n),s})(e,t,o,n),r=Ze(e,o)&&t===n;return s.collapsed&&!r})(t,e.anchorOffset,o,e.focusOffset)?A.some(hd(t,e.anchorOffset,o,e.focusOffset)):Ed(e)}},Md=(e,t)=>(e=>{const t=e.getClientRects(),o=t.length>0?t[0]:e.getBoundingClientRect();return o.width>0||o.height>0?A.some(o).map(Sd):A.none()})(Od(e,t)),Dd=((e,t)=>{const o=t=>e(t)?A.from(t.dom.nodeValue):A.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return o(t).getOr("")},getOption:o,set:(t,o)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=o}}})(Ge),Bd=(e,t)=>({element:e,offset:t}),Id=(e,t)=>Ge(e)?Bd(e,t):((e,t)=>{const o=lt(e);if(0===o.length)return Bd(e,t);if(t<o.length)return Bd(o[t],0);{const e=o[o.length-1],t=Ge(e)?(e=>Dd.get(e))(e).length:lt(e).length;return Bd(e,t)}})(e,t),Fd=e=>void 0!==e.foffset,Rd=(e,t)=>t.getSelection.getOrThunk((()=>()=>(e=>(e=>A.from(e.getSelection()))(e).filter((e=>e.rangeCount>0)).bind(Ad))(e)))().map((e=>{if(Fd(e)){const t=Id(e.start,e.soffset),o=Id(e.finish,e.foffset);return yd.range(t.element,t.offset,o.element,o.offset)}return e}));var Nd=[fs("getSelection"),is("root"),fs("bubble"),ed(),Cs("overrides",{}),Cs("showAbove",!1),Ci("placement",((e,t,o)=>{const n=st(t.root).dom,s=ud(e,0,t),r=Rd(n,t).bind((e=>{if(Fd(e)){const t=((e,t)=>(e=>{const t=e.getBoundingClientRect();return t.width>0||t.height>0?A.some(t).map(Sd):A.none()})(Od(e,t)))(n,yd.exactFromRange(e)).orThunk((()=>{const t=Ne("\ufeff");No(e.start,t);const o=Md(n,yd.exact(t,0,t,1));return Uo(t),o}));return t.bind((e=>md(e.left,e.top,e.width,e.height)))}{const t=le(e,(e=>e.dom.getBoundingClientRect())),o={left:Math.min(t.firstCell.left,t.lastCell.left),right:Math.max(t.firstCell.right,t.lastCell.right),top:Math.min(t.firstCell.top,t.lastCell.top),bottom:Math.max(t.firstCell.bottom,t.lastCell.bottom)};return md(o.left,o.top,o.right-o.left,o.bottom-o.top)}})),a=Rd(n,t).bind((e=>Fd(e)?$e(e.start)?A.some(e.start):at(e.start):A.some(e.firstCell))).getOr(e.element);return gd(r,s,t,o,a)}))];const zd="link-layout",Ld=e=>e.x+e.width,Vd=(e,t)=>e.x-t.width,Hd=(e,t)=>e.y-t.height+e.height,Pd=e=>e.y,Ud=(e,t,o)=>Dl(Ld(e),Pd(e),o.southeast(),Il(),"southeast",Wl(e,{left:0,top:2}),zd),Wd=(e,t,o)=>Dl(Vd(e,t),Pd(e),o.southwest(),Fl(),"southwest",Wl(e,{right:1,top:2}),zd),jd=(e,t,o)=>Dl(Ld(e),Hd(e,t),o.northeast(),Rl(),"northeast",Wl(e,{left:0,bottom:3}),zd),$d=(e,t,o)=>Dl(Vd(e,t),Hd(e,t),o.northwest(),Nl(),"northwest",Wl(e,{right:1,bottom:3}),zd),Gd=()=>[Ud,Wd,jd,$d],qd=()=>[Wd,Ud,$d,jd];var Yd=[is("item"),ed(),Cs("overrides",{}),Ci("placement",((e,t,o)=>{const n=Cc(o,t.item.element),s=td(e.element,t,Gd(),qd(),Gd(),qd(),A.none());return A.some(Yc({anchorBox:n,bubble:qc(),overrides:t.overrides,layouts:s}))}))],Xd=os("type",{selection:Nd,node:pd,hotspot:od,submenu:Yd,makeshift:nd});const Kd=[hs("classes",jn),Es("mode","all",["all","layout","placement"])],Jd=[Cs("useFixed",T),fs("getBounds")],Qd=[ls("anchor",Xd),ks("transition",Kd)],Zd=(e,t,o,n,s,r)=>{const a=es("placement.info",Nn(Qd),s),i=a.anchor,l=n.element,c=o.get(n.uid);xc((()=>{Bt(l,"position","fixed");const s=zt(l,"visibility");Bt(l,"visibility","hidden");const d=t.useFixed()?(()=>{const e=document.documentElement;return Ec(0,0,e.clientWidth,e.clientHeight)})():(e=>{const t=Xt(e.element),o=e.element.dom.getBoundingClientRect();return Tc(t.left,t.top,o.width,o.height)})(e);i.placement(e,i,d).each((e=>{const s=r.orThunk((()=>t.getBounds.map(_))),i=((e,t,o,n,s,r)=>((e,t,o,n,s,r,a,i)=>{const l=Wc(a,"maxHeightFunction",Pc()),c=Wc(a,"maxWidthFunction",b),d=e.anchorBox,u=e.origin,m={bounds:Oc(u,r),origin:u,preference:n,maxHeightFunction:l,maxWidthFunction:c,lastPlacement:s,transition:i};return jc(d,t,o,m)})(((e,t)=>((e,t)=>({anchorBox:e,origin:t}))(e,t))(t.anchorBox,e),n.element,t.bubble,t.layouts,s,o,t.overrides,r))(d,e,s,n,c,a.transition);o.set(n.uid,i)})),s.fold((()=>{Ht(l,"visibility")}),(e=>{Bt(l,"visibility",e)})),zt(l,"left").isNone()&&zt(l,"top").isNone()&&zt(l,"right").isNone()&&zt(l,"bottom").isNone()&&ye(zt(l,"position"),"fixed")&&Ht(l,"position")}),l)};var eu=Object.freeze({__proto__:null,position:(e,t,o,n,s)=>{const r=A.none();Zd(e,t,o,n,s,r)},positionWithinBounds:Zd,getMode:(e,t,o)=>t.useFixed()?"fixed":"absolute",reset:(e,t,o,n)=>{const s=n.element;V(["position","left","right","top","bottom"],(e=>Ht(s,e))),(e=>{At(e,Ac)})(s),o.clear(n.uid)}});const tu=pa({fields:Jd,name:"positioning",active:pc,apis:eu,state:Object.freeze({__proto__:null,init:()=>{let e={};return ua({readState:()=>e,clear:t=>{g(t)?delete e[t]:e={}},set:(t,o)=>{e[t]=o},get:t=>fe(e,t)})}})}),ou=e=>e.getSystem().isConnected(),nu=e=>{zr(e,Tr());const t=e.components();V(t,nu)},su=e=>{const t=e.components();V(t,su),zr(e,_r())},ru=(e,t)=>{e.getSystem().addToWorld(t),xt(e.element)&&su(t)},au=e=>{nu(e),e.getSystem().removeFromWorld(e)},iu=(e,t)=>{Vo(e.element,t.element)},lu=(e,t)=>{cu(e,t,Vo)},cu=(e,t,o)=>{e.getSystem().addToWorld(t),o(e.element,t.element),xt(e.element)&&su(t),e.syncComponents()},du=e=>{nu(e),Uo(e.element),e.getSystem().removeFromWorld(e)},uu=e=>{const t=rt(e.element).bind((t=>e.getSystem().getByDom(t).toOptional()));du(e),t.each((e=>{e.syncComponents()}))},mu=e=>{const t=e.components();V(t,du),Po(e.element),e.syncComponents()},gu=(e,t)=>{hu(e,t,Vo)},pu=(e,t)=>{hu(e,t,zo)},hu=(e,t,o)=>{o(e,t.element);const n=lt(t.element);V(n,(e=>{t.getByDom(e).each(su)}))},fu=e=>{const t=lt(e.element);V(t,(t=>{e.getByDom(t).each(nu)})),Uo(e.element)},bu=(e,t,o,n)=>{o.get().each((t=>{mu(e)}));const s=t.getAttachPoint(e);lu(s,e);const r=e.getSystem().build(n);return lu(e,r),o.set(r),r},vu=(e,t,o,n)=>{const s=bu(e,t,o,n);return t.onOpen(e,s),s},yu=(e,t,o)=>{o.get().each((n=>{mu(e),uu(e),t.onClose(e,n),o.clear()}))},xu=(e,t,o)=>o.isOpen(),wu=(e,t,o)=>{const n=t.getAttachPoint(e);Bt(e.element,"position",tu.getMode(n)),((e,t,o,n)=>{zt(e.element,t).fold((()=>{At(e.element,o)}),(t=>{Ct(e.element,o,t)})),Bt(e.element,t,"hidden")})(e,"visibility",t.cloakVisibilityAttr)},Su=(e,t,o)=>{(e=>R(["top","left","right","bottom"],(t=>zt(e,t).isSome())))(e.element)||Ht(e.element,"position"),((e,t,o)=>{Tt(e.element,o).fold((()=>Ht(e.element,t)),(o=>Bt(e.element,t,o)))})(e,"visibility",t.cloakVisibilityAttr)};var ku=Object.freeze({__proto__:null,cloak:wu,decloak:Su,open:vu,openWhileCloaked:(e,t,o,n,s)=>{wu(e,t),vu(e,t,o,n),s(),Su(e,t)},close:yu,isOpen:xu,isPartOf:(e,t,o,n)=>xu(0,0,o)&&o.get().exists((o=>t.isPartOf(e,o,n))),getState:(e,t,o)=>o.get(),setContent:(e,t,o,n)=>o.get().map((()=>bu(e,t,o,n)))}),Cu=Object.freeze({__proto__:null,events:(e,t)=>Wr([Gr(yr(),((o,n)=>{yu(o,e,t)}))])}),Ou=[xi("onOpen"),xi("onClose"),is("isPartOf"),is("getAttachPoint"),Cs("cloakVisibilityAttr","data-precloak-visibility")],_u=Object.freeze({__proto__:null,init:()=>{const e=rn(),t=x("not-implemented");return ua({readState:t,isOpen:e.isSet,clear:e.clear,set:e.set,get:e.get})}});const Tu=pa({fields:Ou,name:"sandboxing",active:Cu,apis:ku,state:_u}),Eu=x("dismiss.popups"),Au=x("reposition.popups"),Mu=x("mouse.released"),Du=Rn([Cs("isExtraPart",T),ks("fireEventInstead",[Cs("event",Er())])]),Bu=e=>{const t=es("Dismissal",Du,e);return{[Eu()]:{schema:Rn([is("target")]),onReceive:(e,o)=>{Tu.isOpen(e)&&(Tu.isPartOf(e,o.target)||t.isExtraPart(e,o.target)||t.fireEventInstead.fold((()=>Tu.close(e)),(t=>zr(e,t.event))))}}}},Iu=Rn([ks("fireEventInstead",[Cs("event",Ar())]),ms("doReposition")]),Fu=e=>{const t=es("Reposition",Iu,e);return{[Au()]:{onReceive:e=>{Tu.isOpen(e)&&t.fireEventInstead.fold((()=>t.doReposition(e)),(t=>zr(e,t.event)))}}}},Ru=(e,t,o)=>{t.store.manager.onLoad(e,t,o)},Nu=(e,t,o)=>{t.store.manager.onUnload(e,t,o)};var zu=Object.freeze({__proto__:null,onLoad:Ru,onUnload:Nu,setValue:(e,t,o,n)=>{t.store.manager.setValue(e,t,o,n)},getValue:(e,t,o)=>t.store.manager.getValue(e,t,o),getState:(e,t,o)=>o}),Lu=Object.freeze({__proto__:null,events:(e,t)=>{const o=e.resetOnDom?[ea(((o,n)=>{Ru(o,e,t)})),ta(((o,n)=>{Nu(o,e,t)}))]:[ia(e,t,Ru)];return Wr(o)}});const Vu=()=>{const e=on(null);return ua({set:e.set,get:e.get,isNotSet:()=>null===e.get(),clear:()=>{e.set(null)},readState:()=>({mode:"memory",value:e.get()})})},Hu=()=>{const e=on({}),t=on({});return ua({readState:()=>({mode:"dataset",dataByValue:e.get(),dataByText:t.get()}),lookup:o=>fe(e.get(),o).orThunk((()=>fe(t.get(),o))),update:o=>{const n=e.get(),s=t.get(),r={},a={};V(o,(e=>{r[e.value]=e,fe(e,"meta").each((t=>{fe(t,"text").each((t=>{a[t]=e}))}))})),e.set({...n,...r}),t.set({...s,...a})},clear:()=>{e.set({}),t.set({})}})};var Pu=Object.freeze({__proto__:null,memory:Vu,dataset:Hu,manual:()=>ua({readState:b}),init:e=>e.store.manager.state(e)});const Uu=(e,t,o,n)=>{const s=t.store;o.update([n]),s.setValue(e,n),t.onSetValue(e,n)};var Wu=[fs("initialValue"),is("getFallbackEntry"),is("getDataKey"),is("setValue"),Ci("manager",{setValue:Uu,getValue:(e,t,o)=>{const n=t.store,s=n.getDataKey(e);return o.lookup(s).getOrThunk((()=>n.getFallbackEntry(s)))},onLoad:(e,t,o)=>{t.store.initialValue.each((n=>{Uu(e,t,o,n)}))},onUnload:(e,t,o)=>{o.clear()},state:Hu})],ju=[is("getValue"),Cs("setValue",b),fs("initialValue"),Ci("manager",{setValue:(e,t,o,n)=>{t.store.setValue(e,n),t.onSetValue(e,n)},getValue:(e,t,o)=>t.store.getValue(e),onLoad:(e,t,o)=>{t.store.initialValue.each((o=>{t.store.setValue(e,o)}))},onUnload:b,state:da.init})],$u=[fs("initialValue"),Ci("manager",{setValue:(e,t,o,n)=>{o.set(n),t.onSetValue(e,n)},getValue:(e,t,o)=>o.get(),onLoad:(e,t,o)=>{t.store.initialValue.each((e=>{o.isNotSet()&&o.set(e)}))},onUnload:(e,t,o)=>{o.clear()},state:Vu})],Gu=[Os("store",{mode:"memory"},os("mode",{memory:$u,manual:ju,dataset:Wu})),xi("onSetValue"),Cs("resetOnDom",!1)];const qu=pa({fields:Gu,name:"representing",active:Lu,apis:zu,extra:{setValueFrom:(e,t)=>{const o=qu.getValue(t);qu.setValue(e,o)}},state:Pu}),Yu=(e,t)=>Bs(e,{},L(t,(t=>{return o=t.name(),n="Cannot configure "+t.name()+" for "+e,ss(o,o,{tag:"option",process:{}},An((e=>fn("The field: "+o+" is forbidden. "+n))));var o,n})).concat([rs("dump",w)])),Xu=e=>e.dump,Ku=(e,t)=>({...ma(t),...e.dump}),Ju=Yu,Qu=Ku,Zu="placeholder",em=Is([{single:["required","valueThunk"]},{multiple:["required","valueThunks"]}]),tm=e=>be(e,"uiType"),om=(e,t,o,n)=>((e,t,o,n)=>tm(o)&&o.uiType===Zu?((e,t,o,n)=>e.exists((e=>e!==o.owner))?em.single(!0,x(o)):fe(n,o.name).fold((()=>{throw new Error("Unknown placeholder component: "+o.name+"\nKnown: ["+re(n)+"]\nNamespace: "+e.getOr("none")+"\nSpec: "+JSON.stringify(o,null,2))}),(e=>e.replace())))(e,0,o,n):em.single(!1,x(o)))(e,0,o,n).fold(((s,r)=>{const a=tm(o)?r(t,o.config,o.validated):r(t),i=fe(a,"components").getOr([]),l=q(i,(o=>om(e,t,o,n)));return[{...a,components:l}]}),((e,n)=>{if(tm(o)){const e=n(t,o.config,o.validated);return o.validated.preprocess.getOr(w)(e)}return n(t)})),nm=em.single,sm=em.multiple,rm=x(Zu),am=Is([{required:["data"]},{external:["data"]},{optional:["data"]},{group:["data"]}]),im=Cs("factory",{sketch:w}),lm=Cs("schema",[]),cm=is("name"),dm=ss("pname","pname",kn((e=>"<alloy."+Bi(e.name)+">")),Pn()),um=rs("schema",(()=>[fs("preprocess")])),mm=Cs("defaults",x({})),gm=Cs("overrides",x({})),pm=Nn([im,lm,cm,dm,mm,gm]),hm=Nn([im,lm,cm,mm,gm]),fm=Nn([im,lm,cm,dm,mm,gm]),bm=Nn([im,um,cm,is("unit"),dm,mm,gm]),vm=e=>e.fold(A.some,A.none,A.some,A.some),ym=e=>{const t=e=>e.name;return e.fold(t,t,t,t)},xm=(e,t)=>o=>{const n=es("Converting part type",t,o);return e(n)},wm=xm(am.required,pm),Sm=xm(am.external,hm),km=xm(am.optional,fm),Cm=xm(am.group,bm),Om=x("entirety");var _m=Object.freeze({__proto__:null,required:wm,external:Sm,optional:km,group:Cm,asNamedPart:vm,name:ym,asCommon:e=>e.fold(w,w,w,w),original:Om});const Tm=(e,t,o,n)=>wn(t.defaults(e,o,n),o,{uid:e.partUids[t.name]},t.overrides(e,o,n)),Em=(e,t)=>{const o={};return V(t,(t=>{vm(t).each((t=>{const n=Am(e,t.pname);o[t.name]=o=>{const s=es("Part: "+t.name+" in "+e,Nn(t.schema),o);return{...n,config:o,validated:s}}}))})),o},Am=(e,t)=>({uiType:rm(),owner:e,name:t}),Mm=(e,t,o)=>({uiType:rm(),owner:e,name:t,config:o,validated:{}}),Dm=e=>q(e,(e=>e.fold(A.none,A.some,A.none,A.none).map((e=>gs(e.name,e.schema.concat([Oi(Om())])))).toArray())),Bm=e=>L(e,ym),Im=(e,t,o)=>((e,t,o)=>{const n={},s={};return V(o,(e=>{e.fold((e=>{n[e.pname]=nm(!0,((t,o,n)=>e.factory.sketch(Tm(t,e,o,n))))}),(e=>{const o=t.parts[e.name];s[e.name]=x(e.factory.sketch(Tm(t,e,o[Om()]),o))}),(e=>{n[e.pname]=nm(!1,((t,o,n)=>e.factory.sketch(Tm(t,e,o,n))))}),(e=>{n[e.pname]=sm(!0,((t,o,n)=>{const s=t[e.name];return L(s,(o=>e.factory.sketch(wn(e.defaults(t,o,n),o,e.overrides(t,o)))))}))}))})),{internals:x(n),externals:x(s)}})(0,t,o),Fm=(e,t,o)=>((e,t,o,n)=>{const s=le(n,((e,t)=>((e,t)=>{let o=!1;return{name:x(e),required:()=>t.fold(((e,t)=>e),((e,t)=>e)),used:()=>o,replace:()=>{if(o)throw new Error("Trying to use the same placeholder more than once: "+e);return o=!0,t}}})(t,e))),r=((e,t,o,n)=>q(o,(o=>om(e,t,o,n))))(e,t,o,s);return ie(s,(o=>{if(!1===o.used()&&o.required())throw new Error("Placeholder: "+o.name()+" was not found in components list\nNamespace: "+e.getOr("none")+"\nComponents: "+JSON.stringify(t.components,null,2))})),r})(A.some(e),t,t.components,o),Rm=(e,t,o)=>{const n=t.partUids[o];return e.getSystem().getByUid(n).toOptional()},Nm=(e,t,o)=>Rm(e,t,o).getOrDie("Could not find part: "+o),zm=(e,t,o)=>{const n={},s=t.partUids,r=e.getSystem();return V(o,(e=>{n[e]=x(r.getByUid(s[e]))})),n},Lm=(e,t)=>{const o=e.getSystem();return le(t.partUids,((e,t)=>x(o.getByUid(e))))},Vm=e=>re(e.partUids),Hm=(e,t,o)=>{const n={},s=t.partUids,r=e.getSystem();return V(o,(e=>{n[e]=x(r.getByUid(s[e]).getOrDie())})),n},Pm=(e,t)=>{const o=Bm(t);return Rs(L(o,(t=>({key:t,value:e+"-"+t}))))},Um=e=>ss("partUids","partUids",On((t=>Pm(t.uid,e))),Pn());var Wm=Object.freeze({__proto__:null,generate:Em,generateOne:Mm,schemas:Dm,names:Bm,substitutes:Im,components:Fm,defaultUids:Pm,defaultUidsSchema:Um,getAllParts:Lm,getAllPartNames:Vm,getPart:Rm,getPartOrDie:Nm,getParts:zm,getPartsOrDie:Hm});const jm=(e,t,o,n,s)=>{const r=((e,t)=>(e.length>0?[gs("parts",e)]:[]).concat([is("uid"),Cs("dom",{}),Cs("components",[]),Oi("originalSpec"),Cs("debug.sketcher",{})]).concat(t))(n,s);return es(e+" [SpecSchema]",Rn(r.concat(t)),o)},$m=(e,t,o,n,s)=>{const r=Gm(s),a=Dm(o),i=Um(o),l=jm(e,t,r,a,[i]),c=Im(0,l,o);return n(l,Fm(e,l,c.internals()),r,c.externals())},Gm=e=>(e=>be(e,"uid"))(e)?e:{...e,uid:Vi("uid")},qm=Rn([is("name"),is("factory"),is("configFields"),Cs("apis",{}),Cs("extraApis",{})]),Ym=Rn([is("name"),is("factory"),is("configFields"),is("partFields"),Cs("apis",{}),Cs("extraApis",{})]),Xm=e=>{const t=es("Sketcher for "+e.name,qm,e),o=le(t.apis,Gi),n=le(t.extraApis,((e,t)=>ra(e,t)));return{name:t.name,configFields:t.configFields,sketch:e=>((e,t,o,n)=>{const s=Gm(n);return o(jm(e,t,s,[],[]),s)})(t.name,t.configFields,t.factory,e),...o,...n}},Km=e=>{const t=es("Sketcher for "+e.name,Ym,e),o=Em(t.name,t.partFields),n=le(t.apis,Gi),s=le(t.extraApis,((e,t)=>ra(e,t)));return{name:t.name,partFields:t.partFields,configFields:t.configFields,sketch:e=>$m(t.name,t.configFields,t.partFields,t.factory,e),parts:o,...n,...s}},Jm=e=>Xe("input")(e)&&"radio"!==_t(e,"type")||Xe("textarea")(e);var Qm=Object.freeze({__proto__:null,getCurrent:(e,t,o)=>t.find(e)});const Zm=[is("find")],eg=pa({fields:Zm,name:"composing",apis:Qm}),tg=["input","button","textarea","select"],og=(e,t,o)=>{(t.disabled()?lg:cg)(e,t)},ng=(e,t)=>!0===t.useNative&&F(tg,Ue(e.element)),sg=e=>{Ct(e.element,"disabled","disabled")},rg=e=>{At(e.element,"disabled")},ag=e=>{Ct(e.element,"aria-disabled","true")},ig=e=>{Ct(e.element,"aria-disabled","false")},lg=(e,t,o)=>{t.disableClass.each((t=>{ka(e.element,t)})),(ng(e,t)?sg:ag)(e),t.onDisabled(e)},cg=(e,t,o)=>{t.disableClass.each((t=>{Oa(e.element,t)})),(ng(e,t)?rg:ig)(e),t.onEnabled(e)},dg=(e,t)=>ng(e,t)?(e=>Et(e.element,"disabled"))(e):(e=>"true"===_t(e.element,"aria-disabled"))(e);var ug=Object.freeze({__proto__:null,enable:cg,disable:lg,isDisabled:dg,onLoad:og,set:(e,t,o,n)=>{(n?lg:cg)(e,t)}}),mg=Object.freeze({__proto__:null,exhibit:(e,t)=>aa({classes:t.disabled()?t.disableClass.toArray():[]}),events:(e,t)=>Wr([jr(hr(),((t,o)=>dg(t,e))),ia(e,t,og)])}),gg=[Ms("disabled",T),Cs("useNative",!0),fs("disableClass"),xi("onDisabled"),xi("onEnabled")];const pg=pa({fields:gg,name:"disabling",active:mg,apis:ug}),hg=(e,t,o,n)=>{const s=Td(e.element,"."+t.highlightClass);V(s,(o=>{R(n,(e=>Ze(e.element,o)))||(Oa(o,t.highlightClass),e.getSystem().getByDom(o).each((o=>{t.onDehighlight(e,o),zr(o,Nr())})))}))},fg=(e,t,o,n)=>{hg(e,t,0,[n]),bg(e,t,o,n)||(ka(n.element,t.highlightClass),t.onHighlight(e,n),zr(n,Rr()))},bg=(e,t,o,n)=>_a(n.element,t.highlightClass),vg=(e,t,o)=>_l(e.element,"."+t.itemClass).bind((t=>e.getSystem().getByDom(t).toOptional())),yg=(e,t,o)=>{const n=Td(e.element,"."+t.itemClass);return(n.length>0?A.some(n[n.length-1]):A.none()).bind((t=>e.getSystem().getByDom(t).toOptional()))},xg=(e,t,o,n)=>{const s=Td(e.element,"."+t.itemClass);return $(s,(e=>_a(e,t.highlightClass))).bind((t=>{const o=Pl(t,n,0,s.length-1);return e.getSystem().getByDom(s[o]).toOptional()}))},wg=(e,t,o)=>{const n=Td(e.element,"."+t.itemClass);return xe(L(n,(t=>e.getSystem().getByDom(t).toOptional())))};var Sg=Object.freeze({__proto__:null,dehighlightAll:(e,t,o)=>hg(e,t,0,[]),dehighlight:(e,t,o,n)=>{bg(e,t,o,n)&&(Oa(n.element,t.highlightClass),t.onDehighlight(e,n),zr(n,Nr()))},highlight:fg,highlightFirst:(e,t,o)=>{vg(e,t).each((n=>{fg(e,t,o,n)}))},highlightLast:(e,t,o)=>{yg(e,t).each((n=>{fg(e,t,o,n)}))},highlightAt:(e,t,o,n)=>{((e,t,o,n)=>{const s=Td(e.element,"."+t.itemClass);return A.from(s[n]).fold((()=>dn.error(new Error("No element found with index "+n))),e.getSystem().getByDom)})(e,t,0,n).fold((e=>{throw e}),(n=>{fg(e,t,o,n)}))},highlightBy:(e,t,o,n)=>{const s=wg(e,t);j(s,n).each((n=>{fg(e,t,o,n)}))},isHighlighted:bg,getHighlighted:(e,t,o)=>_l(e.element,"."+t.highlightClass).bind((t=>e.getSystem().getByDom(t).toOptional())),getFirst:vg,getLast:yg,getPrevious:(e,t,o)=>xg(e,t,0,-1),getNext:(e,t,o)=>xg(e,t,0,1),getCandidates:wg}),kg=[is("highlightClass"),is("itemClass"),xi("onHighlight"),xi("onDehighlight")];const Cg=pa({fields:kg,name:"highlighting",apis:Sg}),Og=[8],_g=[9],Tg=[13],Eg=[27],Ag=[32],Mg=[37],Dg=[38],Bg=[39],Ig=[40],Fg=(e,t,o)=>{const n=X(e.slice(0,t)),s=X(e.slice(t+1));return j(n.concat(s),o)},Rg=(e,t,o)=>{const n=X(e.slice(0,t));return j(n,o)},Ng=(e,t,o)=>{const n=e.slice(0,t),s=e.slice(t+1);return j(s.concat(n),o)},zg=(e,t,o)=>{const n=e.slice(t+1);return j(n,o)},Lg=e=>t=>{const o=t.raw;return F(e,o.which)},Vg=e=>t=>Y(e,(e=>e(t))),Hg=e=>!0===e.raw.shiftKey,Pg=e=>!0===e.raw.ctrlKey,Ug=C(Hg),Wg=(e,t)=>({matches:e,classification:t}),jg=(e,t,o)=>{t.exists((e=>o.exists((t=>Ze(t,e)))))||Lr(e,Mr(),{prevFocus:t,newFocus:o})},$g=()=>{const e=e=>yc(e.element);return{get:e,set:(t,o)=>{const n=e(t);t.getSystem().triggerFocus(o,t.element);const s=e(t);jg(t,n,s)}}},Gg=()=>{const e=e=>Cg.getHighlighted(e).map((e=>e.element));return{get:e,set:(t,o)=>{const n=e(t);t.getSystem().getByDom(o).fold(b,(e=>{Cg.highlight(t,e)}));const s=e(t);jg(t,n,s)}}};var qg;!function(e){e.OnFocusMode="onFocus",e.OnEnterOrSpaceMode="onEnterOrSpace",e.OnApiMode="onApi"}(qg||(qg={}));const Yg=(e,t,o,n,s)=>{const r=(e,t,o,n,s)=>{return(r=o(e,t,n,s),a=t.event,j(r,(e=>e.matches(a))).map((e=>e.classification))).bind((o=>o(e,t,n,s)));var r,a},a={schema:()=>e.concat([Cs("focusManager",$g()),Os("focusInside","onFocus",Kn((e=>F(["onFocus","onEnterOrSpace","onApi"],e)?dn.value(e):dn.error("Invalid value for focusInside")))),Ci("handler",a),Ci("state",t),Ci("sendFocusIn",s)]),processKey:r,toEvents:(e,t)=>{const a=e.focusInside!==qg.OnFocusMode?A.none():s(e).map((o=>Gr(ur(),((n,s)=>{o(n,e,t),s.stop()})))),i=[Gr(er(),((n,a)=>{r(n,a,o,e,t).fold((()=>{((o,n)=>{const r=Lg(Ag.concat(Tg))(n.event);e.focusInside===qg.OnEnterOrSpaceMode&&r&&Vs(o,n)&&s(e).each((s=>{s(o,e,t),n.stop()}))})(n,a)}),(e=>{a.stop()}))})),Gr(tr(),((o,s)=>{r(o,s,n,e,t).each((e=>{s.stop()}))}))];return Wr(a.toArray().concat(i))}};return a},Xg=e=>{const t=[fs("onEscape"),fs("onEnter"),Cs("selector",'[data-alloy-tabstop="true"]:not(:disabled)'),Cs("firstTabstop",0),Cs("useTabstopAt",E),fs("visibilitySelector")].concat([e]),o=(e,t)=>{const o=e.visibilitySelector.bind((e=>Tl(t,e))).getOr(t);return jt(o)>0},n=(e,t)=>t.focusManager.get(e).bind((e=>Tl(e,t.selector))),s=(e,t,n)=>{((e,t)=>{const n=Td(e.element,t.selector),s=P(n,(e=>o(t,e)));return A.from(s[t.firstTabstop])})(e,t).each((o=>{t.focusManager.set(e,o)}))},r=(e,t,s,r)=>{const a=Td(e.element,s.selector);return n(e,s).bind((t=>$(a,k(Ze,t)).bind((t=>((e,t,n,s,r)=>r(t,n,(e=>((e,t)=>o(e,t)&&e.useTabstopAt(t))(s,e))).fold((()=>s.cyclic?A.some(!0):A.none()),(t=>(s.focusManager.set(e,t),A.some(!0)))))(e,a,t,s,r)))))},a=(e,t,o)=>{const n=o.cyclic?Fg:Rg;return r(e,0,o,n)},i=(e,t,o)=>{const n=o.cyclic?Ng:zg;return r(e,0,o,n)},l=x([Wg(Vg([Hg,Lg(_g)]),a),Wg(Lg(_g),i),Wg(Vg([Ug,Lg(Tg)]),((e,t,o)=>o.onEnter.bind((o=>o(e,t)))))]),c=x([Wg(Lg(Eg),((e,t,o)=>o.onEscape.bind((o=>o(e,t))))),Wg(Lg(_g),((e,t,o)=>n(e,o).filter((e=>!o.useTabstopAt(e))).bind((n=>((e=>(e=>rt(e))(e).bind(dt).exists((t=>Ze(t,e))))(n)?a:i)(e,t,o)))))]);return Yg(t,da.init,l,c,(()=>A.some(s)))};var Kg=Xg(rs("cyclic",T)),Jg=Xg(rs("cyclic",E));const Qg=(e,t,o)=>Jm(o)&&Lg(Ag)(t.event)?A.none():((e,t,o)=>(Hr(e,o,hr()),A.some(!0)))(e,0,o),Zg=(e,t)=>A.some(!0),ep=[Cs("execute",Qg),Cs("useSpace",!1),Cs("useEnter",!0),Cs("useControlEnter",!1),Cs("useDown",!1)],tp=(e,t,o)=>o.execute(e,t,e.element);var op=Yg(ep,da.init,((e,t,o,n)=>{const s=o.useSpace&&!Jm(e.element)?Ag:[],r=o.useEnter?Tg:[],a=o.useDown?Ig:[],i=s.concat(r).concat(a);return[Wg(Lg(i),tp)].concat(o.useControlEnter?[Wg(Vg([Pg,Lg(Tg)]),tp)]:[])}),((e,t,o,n)=>o.useSpace&&!Jm(e.element)?[Wg(Lg(Ag),Zg)]:[]),(()=>A.none()));const np=()=>{const e=rn();return ua({readState:()=>e.get().map((e=>({numRows:String(e.numRows),numColumns:String(e.numColumns)}))).getOr({numRows:"?",numColumns:"?"}),setGridSize:(t,o)=>{e.set({numRows:t,numColumns:o})},getNumRows:()=>e.get().map((e=>e.numRows)),getNumColumns:()=>e.get().map((e=>e.numColumns))})};var sp=Object.freeze({__proto__:null,flatgrid:np,init:e=>e.state(e)});const rp=e=>(t,o,n,s)=>{const r=e(t.element);return cp(r,t,o,n,s)},ap=(e,t)=>{const o=Xc(e,t);return rp(o)},ip=(e,t)=>{const o=Xc(t,e);return rp(o)},lp=e=>(t,o,n,s)=>cp(e,t,o,n,s),cp=(e,t,o,n,s)=>n.focusManager.get(t).bind((o=>e(t.element,o,n,s))).map((e=>(n.focusManager.set(t,e),!0))),dp=lp,up=lp,mp=lp,gp=e=>!(e=>e.offsetWidth<=0&&e.offsetHeight<=0)(e.dom),pp=(e,t,o)=>{const n=Td(e,o);return((e,o)=>$(e,(e=>Ze(e,t))).map((t=>({index:t,candidates:e}))))(P(n,gp))},hp=(e,t)=>$(e,(e=>Ze(t,e))),fp=(e,t,o,n)=>n(Math.floor(t/o),t%o).bind((t=>{const n=t.row*o+t.column;return n>=0&&n<e.length?A.some(e[n]):A.none()})),bp=(e,t,o,n,s)=>fp(e,t,n,((t,r)=>{const a=t===o-1?e.length-t*n:n,i=Pl(r,s,0,a-1);return A.some({row:t,column:i})})),vp=(e,t,o,n,s)=>fp(e,t,n,((t,r)=>{const a=Pl(t,s,0,o-1),i=a===o-1?e.length-a*n:n,l=Ul(r,0,i-1);return A.some({row:a,column:l})})),yp=[is("selector"),Cs("execute",Qg),wi("onEscape"),Cs("captureTab",!1),_i()],xp=(e,t,o)=>{_l(e.element,t.selector).each((o=>{t.focusManager.set(e,o)}))},wp=e=>(t,o,n,s)=>pp(t,o,n.selector).bind((t=>e(t.candidates,t.index,s.getNumRows().getOr(n.initSize.numRows),s.getNumColumns().getOr(n.initSize.numColumns)))),Sp=(e,t,o)=>o.captureTab?A.some(!0):A.none(),kp=wp(((e,t,o,n)=>bp(e,t,o,n,-1))),Cp=wp(((e,t,o,n)=>bp(e,t,o,n,1))),Op=wp(((e,t,o,n)=>vp(e,t,o,n,-1))),_p=wp(((e,t,o,n)=>vp(e,t,o,n,1))),Tp=x([Wg(Lg(Mg),ap(kp,Cp)),Wg(Lg(Bg),ip(kp,Cp)),Wg(Lg(Dg),dp(Op)),Wg(Lg(Ig),up(_p)),Wg(Vg([Hg,Lg(_g)]),Sp),Wg(Vg([Ug,Lg(_g)]),Sp),Wg(Lg(Ag.concat(Tg)),((e,t,o,n)=>((e,t)=>t.focusManager.get(e).bind((e=>Tl(e,t.selector))))(e,o).bind((n=>o.execute(e,t,n)))))]),Ep=x([Wg(Lg(Eg),((e,t,o)=>o.onEscape(e,t))),Wg(Lg(Ag),Zg)]);var Ap=Yg(yp,np,Tp,Ep,(()=>A.some(xp)));const Mp=(e,t,o,n,s)=>{const r=(e,t,o)=>s(e,t,n,0,o.length-1,o[t],(t=>{return n=o[t],"button"===Ue(n)&&"disabled"===_t(n,"disabled")?r(e,t,o):A.from(o[t]);var n}));return pp(e,o,t).bind((e=>{const t=e.index,o=e.candidates;return r(t,t,o)}))},Dp=(e,t,o,n)=>Mp(e,t,o,n,((e,t,o,n,s,r,a)=>{const i=Ul(t+o,n,s);return i===e?A.from(r):a(i)})),Bp=(e,t,o,n)=>Mp(e,t,o,n,((e,t,o,n,s,r,a)=>{const i=Pl(t,o,n,s);return i===e?A.none():a(i)})),Ip=[is("selector"),Cs("getInitial",A.none),Cs("execute",Qg),wi("onEscape"),Cs("executeOnMove",!1),Cs("allowVertical",!0),Cs("allowHorizontal",!0),Cs("cycles",!0)],Fp=(e,t,o)=>((e,t)=>t.focusManager.get(e).bind((e=>Tl(e,t.selector))))(e,o).bind((n=>o.execute(e,t,n))),Rp=(e,t,o)=>{t.getInitial(e).orThunk((()=>_l(e.element,t.selector))).each((o=>{t.focusManager.set(e,o)}))},Np=(e,t,o)=>(o.cycles?Bp:Dp)(e,o.selector,t,-1),zp=(e,t,o)=>(o.cycles?Bp:Dp)(e,o.selector,t,1),Lp=e=>(t,o,n,s)=>e(t,o,n,s).bind((()=>n.executeOnMove?Fp(t,o,n):A.some(!0))),Vp=x([Wg(Lg(Ag),Zg),Wg(Lg(Eg),((e,t,o)=>o.onEscape(e,t)))]);var Hp=Yg(Ip,da.init,((e,t,o,n)=>{const s=[...o.allowHorizontal?Mg:[]].concat(o.allowVertical?Dg:[]),r=[...o.allowHorizontal?Bg:[]].concat(o.allowVertical?Ig:[]);return[Wg(Lg(s),Lp(ap(Np,zp))),Wg(Lg(r),Lp(ip(Np,zp))),Wg(Lg(Tg),Fp),Wg(Lg(Ag),Fp)]}),Vp,(()=>A.some(Rp)));const Pp=(e,t,o)=>A.from(e[t]).bind((e=>A.from(e[o]).map((e=>({rowIndex:t,columnIndex:o,cell:e}))))),Up=(e,t,o,n)=>{const s=e[t].length,r=Pl(o,n,0,s-1);return Pp(e,t,r)},Wp=(e,t,o,n)=>{const s=Pl(o,n,0,e.length-1),r=e[s].length,a=Ul(t,0,r-1);return Pp(e,s,a)},jp=(e,t,o,n)=>{const s=e[t].length,r=Ul(o+n,0,s-1);return Pp(e,t,r)},$p=(e,t,o,n)=>{const s=Ul(o+n,0,e.length-1),r=e[s].length,a=Ul(t,0,r-1);return Pp(e,s,a)},Gp=[gs("selectors",[is("row"),is("cell")]),Cs("cycles",!0),Cs("previousSelector",A.none),Cs("execute",Qg)],qp=(e,t,o)=>{t.previousSelector(e).orThunk((()=>{const o=t.selectors;return _l(e.element,o.cell)})).each((o=>{t.focusManager.set(e,o)}))},Yp=(e,t)=>(o,n,s)=>{const r=s.cycles?e:t;return Tl(n,s.selectors.row).bind((e=>{const t=Td(e,s.selectors.cell);return hp(t,n).bind((t=>{const n=Td(o,s.selectors.row);return hp(n,e).bind((e=>{const o=((e,t)=>L(e,(e=>Td(e,t.selectors.cell))))(n,s);return r(o,e,t).map((e=>e.cell))}))}))}))},Xp=Yp(((e,t,o)=>Up(e,t,o,-1)),((e,t,o)=>jp(e,t,o,-1))),Kp=Yp(((e,t,o)=>Up(e,t,o,1)),((e,t,o)=>jp(e,t,o,1))),Jp=Yp(((e,t,o)=>Wp(e,o,t,-1)),((e,t,o)=>$p(e,o,t,-1))),Qp=Yp(((e,t,o)=>Wp(e,o,t,1)),((e,t,o)=>$p(e,o,t,1))),Zp=x([Wg(Lg(Mg),ap(Xp,Kp)),Wg(Lg(Bg),ip(Xp,Kp)),Wg(Lg(Dg),dp(Jp)),Wg(Lg(Ig),up(Qp)),Wg(Lg(Ag.concat(Tg)),((e,t,o)=>yc(e.element).bind((n=>o.execute(e,t,n)))))]),eh=x([Wg(Lg(Ag),Zg)]);var th=Yg(Gp,da.init,Zp,eh,(()=>A.some(qp)));const oh=[is("selector"),Cs("execute",Qg),Cs("moveOnTab",!1)],nh=(e,t,o)=>o.focusManager.get(e).bind((n=>o.execute(e,t,n))),sh=(e,t,o)=>{_l(e.element,t.selector).each((o=>{t.focusManager.set(e,o)}))},rh=(e,t,o)=>Bp(e,o.selector,t,-1),ah=(e,t,o)=>Bp(e,o.selector,t,1),ih=x([Wg(Lg(Dg),mp(rh)),Wg(Lg(Ig),mp(ah)),Wg(Vg([Hg,Lg(_g)]),((e,t,o,n)=>o.moveOnTab?mp(rh)(e,t,o,n):A.none())),Wg(Vg([Ug,Lg(_g)]),((e,t,o,n)=>o.moveOnTab?mp(ah)(e,t,o,n):A.none())),Wg(Lg(Tg),nh),Wg(Lg(Ag),nh)]),lh=x([Wg(Lg(Ag),Zg)]);var ch=Yg(oh,da.init,ih,lh,(()=>A.some(sh)));const dh=[wi("onSpace"),wi("onEnter"),wi("onShiftEnter"),wi("onLeft"),wi("onRight"),wi("onTab"),wi("onShiftTab"),wi("onUp"),wi("onDown"),wi("onEscape"),Cs("stopSpaceKeyup",!1),fs("focusIn")];var uh=Yg(dh,da.init,((e,t,o)=>[Wg(Lg(Ag),o.onSpace),Wg(Vg([Ug,Lg(Tg)]),o.onEnter),Wg(Vg([Hg,Lg(Tg)]),o.onShiftEnter),Wg(Vg([Hg,Lg(_g)]),o.onShiftTab),Wg(Vg([Ug,Lg(_g)]),o.onTab),Wg(Lg(Dg),o.onUp),Wg(Lg(Ig),o.onDown),Wg(Lg(Mg),o.onLeft),Wg(Lg(Bg),o.onRight),Wg(Lg(Ag),o.onSpace)]),((e,t,o)=>[...o.stopSpaceKeyup?[Wg(Lg(Ag),Zg)]:[],Wg(Lg(Eg),o.onEscape)]),(e=>e.focusIn));const mh=Kg.schema(),gh=Jg.schema(),ph=Hp.schema(),hh=Ap.schema(),fh=th.schema(),bh=op.schema(),vh=ch.schema(),yh=uh.schema(),xh=fa({branchKey:"mode",branches:Object.freeze({__proto__:null,acyclic:mh,cyclic:gh,flow:ph,flatgrid:hh,matrix:fh,execution:bh,menu:vh,special:yh}),name:"keying",active:{events:(e,t)=>e.handler.toEvents(e,t)},apis:{focusIn:(e,t,o)=>{t.sendFocusIn(t).fold((()=>{e.getSystem().triggerFocus(e.element,e.element)}),(n=>{n(e,t,o)}))},setGridSize:(e,t,o,n,s)=>{(e=>ve(e,"setGridSize"))(o)?o.setGridSize(n,s):console.error("Layout does not support setGridSize")}},state:sp}),wh=(e,t)=>{xc((()=>{((e,t,o)=>{const n=e.components();(e=>{V(e.components(),(e=>Uo(e.element))),Po(e.element),e.syncComponents()})(e);const s=o(t),r=K(n,s);V(r,(t=>{nu(t),e.getSystem().removeFromWorld(t)})),V(s,(t=>{ou(t)?iu(e,t):(e.getSystem().addToWorld(t),iu(e,t),xt(e.element)&&su(t))})),e.syncComponents()})(e,t,(()=>L(t,e.getSystem().build)))}),e.element)},Sh=(e,t)=>{xc((()=>{((o,n,s)=>{const r=o.components(),a=q(n,(e=>$i(e).toArray()));V(r,(e=>{F(a,e)||au(e)}));const i=((e,t,o)=>rl(e,t,((t,n)=>al(e,n,t,o))))(e.element,t,e.getSystem().buildOrPatch),l=K(r,i);V(l,(e=>{ou(e)&&au(e)})),V(i,(e=>{ou(e)||ru(o,e)})),o.syncComponents()})(e,t)}),e.element)},kh=(e,t,o,n)=>{au(t);const s=al(e.element,o,n,e.getSystem().buildOrPatch);ru(e,s),e.syncComponents()},Ch=(e,t,o)=>{const n=e.getSystem().build(o);cu(e,n,t)},Oh=(e,t,o,n)=>{uu(t),Ch(e,((e,t)=>((e,t,o)=>{ct(e,o).fold((()=>{Vo(e,t)}),(e=>{No(e,t)}))})(e,t,o)),n)},_h=(e,t)=>e.components(),Th=(e,t,o,n,s)=>{const r=_h(e);return A.from(r[n]).map((o=>(s.fold((()=>uu(o)),(s=>{(t.reuseDom?kh:Oh)(e,o,n,s)})),o)))};var Eh=Object.freeze({__proto__:null,append:(e,t,o,n)=>{Ch(e,Vo,n)},prepend:(e,t,o,n)=>{Ch(e,Lo,n)},remove:(e,t,o,n)=>{const s=_h(e),r=j(s,(e=>Ze(n.element,e.element)));r.each(uu)},replaceAt:Th,replaceBy:(e,t,o,n,s)=>{const r=_h(e);return $(r,n).bind((o=>Th(e,t,0,o,s)))},set:(e,t,o,n)=>(t.reuseDom?Sh:wh)(e,n),contents:_h});const Ah=pa({fields:[As("reuseDom",!0)],name:"replacing",apis:Eh}),Mh=(e,t)=>{const o=((e,t)=>{const o=Wr(t);return pa({fields:[is("enabled")],name:e,active:{events:x(o)}})})(e,t);return{key:e,value:{config:{},me:o,configAsRaw:x({}),initialConfig:{},state:da}}},Dh=(e,t)=>{t.ignore||(hc(e.element),t.onFocus(e))};var Bh=Object.freeze({__proto__:null,focus:Dh,blur:(e,t)=>{t.ignore||fc(e.element)},isFocused:e=>bc(e.element)}),Ih=Object.freeze({__proto__:null,exhibit:(e,t)=>{const o=t.ignore?{}:{attributes:{tabindex:"-1"}};return aa(o)},events:e=>Wr([Gr(ur(),((t,o)=>{Dh(t,e),o.stop()}))].concat(e.stopMousedown?[Gr(qs(),((e,t)=>{t.event.prevent()}))]:[]))}),Fh=[xi("onFocus"),Cs("stopMousedown",!1),Cs("ignore",!1)];const Rh=pa({fields:Fh,name:"focusing",active:Ih,apis:Bh}),Nh=(e,t,o,n)=>{const s=o.get();o.set(n),((e,t,o)=>{t.toggleClass.each((t=>{o.get()?ka(e.element,t):Oa(e.element,t)}))})(e,t,o),((e,t,o)=>{const n=t.aria;n.update(e,n,o.get())})(e,t,o),s!==n&&t.onToggled(e,n)},zh=(e,t,o)=>{Nh(e,t,o,!o.get())},Lh=(e,t,o)=>{Nh(e,t,o,t.selected)};var Vh=Object.freeze({__proto__:null,onLoad:Lh,toggle:zh,isOn:(e,t,o)=>o.get(),on:(e,t,o)=>{Nh(e,t,o,!0)},off:(e,t,o)=>{Nh(e,t,o,!1)},set:Nh}),Hh=Object.freeze({__proto__:null,exhibit:()=>aa({}),events:(e,t)=>{const o=(n=e,s=t,r=zh,na((e=>{r(e,n,s)})));var n,s,r;const a=ia(e,t,Lh);return Wr(G([e.toggleOnExecute?[o]:[],[a]]))}});const Ph=(e,t,o)=>{Ct(e.element,"aria-expanded",o)};var Uh=[Cs("selected",!1),fs("toggleClass"),Cs("toggleOnExecute",!0),xi("onToggled"),Os("aria",{mode:"none"},os("mode",{pressed:[Cs("syncWithExpanded",!1),Ci("update",((e,t,o)=>{Ct(e.element,"aria-pressed",o),t.syncWithExpanded&&Ph(e,0,o)}))],checked:[Ci("update",((e,t,o)=>{Ct(e.element,"aria-checked",o)}))],expanded:[Ci("update",Ph)],selected:[Ci("update",((e,t,o)=>{Ct(e.element,"aria-selected",o)}))],none:[Ci("update",b)]}))];const Wh=pa({fields:Uh,name:"toggling",active:Hh,apis:Vh,state:(!1,{init:()=>{const e=on(false);return{get:()=>e.get(),set:t=>e.set(t),clear:()=>e.set(false),readState:()=>e.get()}}})});const jh=()=>{const e=(e,t)=>{t.stop(),Vr(e)};return[Gr(sr(),e),Gr(br(),e),Jr(Ws()),Jr(qs())]},$h=e=>Wr(G([e.map((e=>na(((t,o)=>{e(t),o.stop()})))).toArray(),jh()])),Gh="alloy.item-hover",qh="alloy.item-focus",Yh="alloy.item-toggled",Xh=e=>{(yc(e.element).isNone()||Rh.isFocused(e))&&(Rh.isFocused(e)||Rh.focus(e),Lr(e,Gh,{item:e}))},Kh=e=>{Lr(e,qh,{item:e})},Jh=x(Gh),Qh=x(qh),Zh=x(Yh),ef=e=>e.role.fold((()=>e.toggling.map((e=>e.exclusive?"menuitemradio":"menuitemcheckbox")).getOr("menuitem")),w),tf=[is("data"),is("components"),is("dom"),Cs("hasSubmenu",!1),fs("toggling"),fs("role"),Ju("itemBehaviours",[Wh,Rh,xh,qu]),Cs("ignoreFocus",!1),Cs("domModification",{}),Ci("builder",(e=>({dom:e.dom,domModification:{...e.domModification,attributes:{role:ef(e),...e.domModification.attributes,"aria-haspopup":e.hasSubmenu,...e.hasSubmenu?{"aria-expanded":!1}:{}}},behaviours:Qu(e.itemBehaviours,[e.toggling.fold(Wh.revoke,(t=>Wh.config(((e,t)=>({aria:{mode:t?"selected":"checked"},...me(e,((e,t)=>"exclusive"!==t)),onToggled:(t,o)=>{p(e.onToggled)&&e.onToggled(t,o),((e,t)=>{Lr(e,Yh,{item:e,state:t})})(t,o)}}))(t,e.role.exists((e=>"option"===e)))))),Rh.config({ignore:e.ignoreFocus,stopMousedown:e.ignoreFocus,onFocus:e=>{Kh(e)}}),xh.config({mode:"execution"}),qu.config({store:{mode:"memory",initialValue:e.data}}),Mh("item-type-events",[...jh(),Gr(Js(),Xh),Gr(fr(),Rh.focus)])]),components:e.components,eventOrder:e.eventOrder}))),Cs("eventOrder",{})],of=[is("dom"),is("components"),Ci("builder",(e=>({dom:e.dom,components:e.components,events:Wr([Qr(fr())])})))],nf=x("item-widget"),sf=x([wm({name:"widget",overrides:e=>({behaviours:ma([qu.config({store:{mode:"manual",getValue:t=>e.data,setValue:b}})])})})]),rf=[is("uid"),is("data"),is("components"),is("dom"),Cs("autofocus",!1),Cs("ignoreFocus",!1),Ju("widgetBehaviours",[qu,Rh,xh]),Cs("domModification",{}),Um(sf()),Ci("builder",(e=>{const t=Im(nf(),e,sf()),o=Fm(nf(),e,t.internals()),n=t=>Rm(t,e,"widget").map((e=>(xh.focusIn(e),e))),s=(t,o)=>Jm(o.event.target)?A.none():e.autofocus?(o.setSource(t.element),A.none()):A.none();return{dom:e.dom,components:o,domModification:e.domModification,events:Wr([na(((e,t)=>{n(e).each((e=>{t.stop()}))})),Gr(Js(),Xh),Gr(fr(),((t,o)=>{e.autofocus?n(t):Rh.focus(t)}))]),behaviours:Qu(e.widgetBehaviours,[qu.config({store:{mode:"memory",initialValue:e.data}}),Rh.config({ignore:e.ignoreFocus,onFocus:e=>{Kh(e)}}),xh.config({mode:"special",focusIn:e.autofocus?e=>{n(e)}:ba(),onLeft:s,onRight:s,onEscape:(t,o)=>Rh.isFocused(t)||e.autofocus?e.autofocus?(o.setSource(t.element),A.none()):A.none():(Rh.focus(t),A.some(!0))})])}}))],af=os("type",{widget:rf,item:tf,separator:of}),lf=x([Cm({factory:{sketch:e=>{const t=es("menu.spec item",af,e);return t.builder(t)}},name:"items",unit:"item",defaults:(e,t)=>be(t,"uid")?t:{...t,uid:Vi("item")},overrides:(e,t)=>({type:t.type,ignoreFocus:e.fakeFocus,domModification:{classes:[e.markers.item]}})})]),cf=x([ys("role"),is("value"),is("items"),is("dom"),is("components"),Cs("eventOrder",{}),Yu("menuBehaviours",[Cg,qu,eg,xh]),Os("movement",{mode:"menu",moveOnTab:!0},os("mode",{grid:[_i(),Ci("config",((e,t)=>({mode:"flatgrid",selector:"."+e.markers.item,initSize:{numColumns:t.initSize.numColumns,numRows:t.initSize.numRows},focusManager:e.focusManager})))],matrix:[Ci("config",((e,t)=>({mode:"matrix",selectors:{row:t.rowSelector,cell:"."+e.markers.item},previousSelector:t.previousSelector,focusManager:e.focusManager}))),is("rowSelector"),Cs("previousSelector",A.none)],menu:[Cs("moveOnTab",!0),Ci("config",((e,t)=>({mode:"menu",selector:"."+e.markers.item,moveOnTab:t.moveOnTab,focusManager:e.focusManager})))]})),ls("markers",hi()),Cs("fakeFocus",!1),Cs("focusManager",$g()),xi("onHighlight"),xi("onDehighlight"),Cs("showMenuRole",!0)]),df=x("alloy.menu-focus"),uf=Km({name:"Menu",configFields:cf(),partFields:lf(),factory:(e,t,o,n)=>({uid:e.uid,dom:e.dom,markers:e.markers,behaviours:Ku(e.menuBehaviours,[Cg.config({highlightClass:e.markers.selectedItem,itemClass:e.markers.item,onHighlight:e.onHighlight,onDehighlight:e.onDehighlight}),qu.config({store:{mode:"memory",initialValue:e.value}}),eg.config({find:A.some}),xh.config(e.movement.config(e,e.movement))]),events:Wr([Gr(Qh(),((e,t)=>{const o=t.event;e.getSystem().getByDom(o.target).each((o=>{Cg.highlight(e,o),t.stop(),Lr(e,df(),{menu:e,item:o})}))})),Gr(Jh(),((e,t)=>{const o=t.event.item;Cg.highlight(e,o)})),Gr(Zh(),((e,t)=>{const{item:o,state:n}=t.event;n&&"menuitemradio"===_t(o.element,"role")&&((e,t)=>{const o=Td(e.element,'[role="menuitemradio"][aria-checked="true"]');V(o,(o=>{Ze(o,t.element)||e.getSystem().getByDom(o).each((e=>{Wh.off(e)}))}))})(e,o)}))]),components:t,eventOrder:e.eventOrder,...e.showMenuRole?{domModification:{attributes:{role:e.role.getOr("menu")}}}:{}})}),mf=(e,t,o,n)=>fe(o,n).bind((n=>fe(e,n).bind((n=>{const s=mf(e,t,o,n);return A.some([n].concat(s))})))).getOr([]),gf=e=>"prepared"===e.type?A.some(e.menu):A.none(),pf=()=>{const e=on({}),t=on({}),o=on({}),n=rn(),s=on({}),r=e=>a(e).bind(gf),a=e=>fe(t.get(),e),i=t=>fe(e.get(),t);return{setMenuBuilt:(e,o)=>{t.set({...t.get(),[e]:{type:"prepared",menu:o}})},setContents:(r,a,i,l)=>{n.set(r),e.set(i),t.set(a),s.set(l);const c=((e,t)=>{const o={};ie(e,((e,t)=>{V(e,(e=>{o[e]=t}))}));const n=t,s=ce(t,((e,t)=>({k:e,v:t}))),r=le(s,((e,t)=>[t].concat(mf(o,n,s,t))));return le(o,(e=>fe(r,e).getOr([e])))})(l,i);o.set(c)},expand:t=>fe(e.get(),t).map((e=>{const n=fe(o.get(),t).getOr([]);return[e].concat(n)})),refresh:e=>fe(o.get(),e),collapse:e=>fe(o.get(),e).bind((e=>e.length>1?A.some(e.slice(1)):A.none())),lookupMenu:a,lookupItem:i,otherMenus:e=>{const t=s.get();return K(re(t),e)},getPrimary:()=>n.get().bind(r),getMenus:()=>t.get(),clear:()=>{e.set({}),t.set({}),o.set({}),n.clear()},isClear:()=>n.get().isNone(),getTriggeringPath:(t,s)=>{const a=P(i(t).toArray(),(e=>r(e).isSome()));return fe(o.get(),t).bind((t=>{const o=X(a.concat(t));return(e=>{const t=[];for(let o=0;o<e.length;o++){const n=e[o];if(!n.isSome())return A.none();t.push(n.getOrDie())}return A.some(t)})(q(o,((t,a)=>((t,o,n)=>r(t).bind((s=>(t=>pe(e.get(),((e,o)=>e===t)))(t).bind((e=>o(e).map((e=>({triggeredMenu:s,triggeringItem:e,triggeringPath:n}))))))))(t,s,o.slice(0,a+1)).fold((()=>ye(n.get(),t)?[]:[A.none()]),(e=>[A.some(e)])))))}))}}},hf=gf,ff=Bi("tiered-menu-item-highlight"),bf=Bi("tiered-menu-item-dehighlight");var vf;!function(e){e[e.HighlightMenuAndItem=0]="HighlightMenuAndItem",e[e.HighlightJustMenu=1]="HighlightJustMenu",e[e.HighlightNone=2]="HighlightNone"}(vf||(vf={}));const yf=x("collapse-item"),xf=Xm({name:"TieredMenu",configFields:[ki("onExecute"),ki("onEscape"),Si("onOpenMenu"),Si("onOpenSubmenu"),xi("onRepositionMenu"),xi("onCollapseMenu"),Cs("highlightOnOpen",vf.HighlightMenuAndItem),gs("data",[is("primary"),is("menus"),is("expansions")]),Cs("fakeFocus",!1),xi("onHighlightItem"),xi("onDehighlightItem"),xi("onHover"),bi(),is("dom"),Cs("navigateOnHover",!0),Cs("stayInDom",!1),Yu("tmenuBehaviours",[xh,Cg,eg,Ah]),Cs("eventOrder",{})],apis:{collapseMenu:(e,t)=>{e.collapseMenu(t)},highlightPrimary:(e,t)=>{e.highlightPrimary(t)},repositionMenus:(e,t)=>{e.repositionMenus(t)}},factory:(e,t)=>{const o=rn(),n=pf(),s=e=>qu.getValue(e).value,r=t=>le(e.data.menus,((e,t)=>q(e.items,(e=>"separator"===e.type?[]:[e.data.value])))),a=Cg.highlight,i=(t,o)=>{a(t,o),Cg.getHighlighted(o).orThunk((()=>Cg.getFirst(o))).each((n=>{e.fakeFocus?Cg.highlight(o,n):Hr(t,n.element,fr())}))},l=(e,t)=>xe(L(t,(t=>e.lookupMenu(t).bind((e=>"prepared"===e.type?A.some(e.menu):A.none()))))),c=(t,o,n)=>{const s=l(o,o.otherMenus(n));V(s,(o=>{Ea(o.element,[e.markers.backgroundMenu]),e.stayInDom||Ah.remove(t,o)}))},d=(t,n)=>{const r=(t=>o.get().getOrThunk((()=>{const n={},r=Td(t.element,`.${e.markers.item}`),a=P(r,(e=>"true"===_t(e,"aria-haspopup")));return V(a,(e=>{t.getSystem().getByDom(e).each((e=>{const t=s(e);n[t]=e}))})),o.set(n),n})))(t);ie(r,((e,t)=>{const o=F(n,t);Ct(e.element,"aria-expanded",o)}))},u=(t,o,n)=>A.from(n[0]).bind((s=>o.lookupMenu(s).bind((s=>{if("notbuilt"===s.type)return A.none();{const r=s.menu,a=l(o,n.slice(1));return V(a,(t=>{ka(t.element,e.markers.backgroundMenu)})),xt(r.element)||Ah.append(t,fl(r)),Ea(r.element,[e.markers.backgroundMenu]),i(t,r),c(t,o,n),A.some(r)}}))));let m;!function(e){e[e.HighlightSubmenu=0]="HighlightSubmenu",e[e.HighlightParent=1]="HighlightParent"}(m||(m={}));const g=(t,o,r=m.HighlightSubmenu)=>{if(o.hasConfigured(pg)&&pg.isDisabled(o))return A.some(o);{const a=s(o);return n.expand(a).bind((s=>(d(t,s),A.from(s[0]).bind((a=>n.lookupMenu(a).bind((i=>{const l=((e,t,o)=>{if("notbuilt"===o.type){const s=e.getSystem().build(o.nbMenu());return n.setMenuBuilt(t,s),s}return o.menu})(t,a,i);return xt(l.element)||Ah.append(t,fl(l)),e.onOpenSubmenu(t,o,l,X(s)),r===m.HighlightSubmenu?(Cg.highlightFirst(l),u(t,n,s)):(Cg.dehighlightAll(l),A.some(o))})))))))}},p=(t,o)=>{const r=s(o);return n.collapse(r).bind((s=>(d(t,s),u(t,n,s).map((n=>(e.onCollapseMenu(t,o,n),n))))))},h=t=>(o,n)=>Tl(n.getSource(),`.${e.markers.item}`).bind((e=>o.getSystem().getByDom(e).toOptional().bind((e=>t(o,e).map(E))))),f=Wr([Gr(df(),((e,t)=>{const o=t.event.item;n.lookupItem(s(o)).each((()=>{const o=t.event.menu;Cg.highlight(e,o);const r=s(t.event.item);n.refresh(r).each((t=>c(e,n,t)))}))})),na(((t,o)=>{const n=o.event.target;t.getSystem().getByDom(n).each((o=>{0===s(o).indexOf("collapse-item")&&p(t,o),g(t,o,m.HighlightSubmenu).fold((()=>{e.onExecute(t,o)}),b)}))})),ea(((t,o)=>{(t=>{const o=((t,o,n)=>le(n,((n,s)=>{const r=()=>uf.sketch({...n,value:s,markers:e.markers,fakeFocus:e.fakeFocus,onHighlight:(e,t)=>{Lr(e,ff,{menuComp:e,itemComp:t})},onDehighlight:(e,t)=>{Lr(e,bf,{menuComp:e,itemComp:t})},focusManager:e.fakeFocus?Gg():$g()});return s===o?{type:"prepared",menu:t.getSystem().build(r())}:{type:"notbuilt",nbMenu:r}})))(t,e.data.primary,e.data.menus),s=r();return n.setContents(e.data.primary,o,e.data.expansions,s),n.getPrimary()})(t).each((o=>{Ah.append(t,fl(o)),e.onOpenMenu(t,o),e.highlightOnOpen===vf.HighlightMenuAndItem?i(t,o):e.highlightOnOpen===vf.HighlightJustMenu&&a(t,o)}))})),Gr(ff,((t,o)=>{e.onHighlightItem(t,o.event.menuComp,o.event.itemComp)})),Gr(bf,((t,o)=>{e.onDehighlightItem(t,o.event.menuComp,o.event.itemComp)})),...e.navigateOnHover?[Gr(Jh(),((t,o)=>{const r=o.event.item;((e,t)=>{const o=s(t);n.refresh(o).bind((t=>(d(e,t),u(e,n,t))))})(t,r),g(t,r,m.HighlightParent),e.onHover(t,r)}))]:[]]),v=e=>Cg.getHighlighted(e).bind(Cg.getHighlighted),y={collapseMenu:e=>{v(e).each((t=>{p(e,t)}))},highlightPrimary:e=>{n.getPrimary().each((t=>{i(e,t)}))},repositionMenus:t=>{const o=n.getPrimary().bind((e=>v(t).bind((e=>{const t=s(e),o=he(n.getMenus()),r=xe(L(o,hf));return n.getTriggeringPath(t,(e=>((e,t,o)=>se(t,(e=>{if(!e.getSystem().isConnected())return A.none();const t=Cg.getCandidates(e);return j(t,(e=>s(e)===o))})))(0,r,e)))})).map((t=>({primary:e,triggeringPath:t})))));o.fold((()=>{(e=>A.from(e.components()[0]).filter((e=>"menu"===_t(e.element,"role"))))(t).each((o=>{e.onRepositionMenu(t,o,[])}))}),(({primary:o,triggeringPath:n})=>{e.onRepositionMenu(t,o,n)}))}};return{uid:e.uid,dom:e.dom,markers:e.markers,behaviours:Ku(e.tmenuBehaviours,[xh.config({mode:"special",onRight:h(((e,t)=>Jm(t.element)?A.none():g(e,t,m.HighlightSubmenu))),onLeft:h(((e,t)=>Jm(t.element)?A.none():p(e,t))),onEscape:h(((t,o)=>p(t,o).orThunk((()=>e.onEscape(t,o).map((()=>t)))))),focusIn:(e,t)=>{n.getPrimary().each((t=>{Hr(e,t.element,fr())}))}}),Cg.config({highlightClass:e.markers.selectedMenu,itemClass:e.markers.menu}),eg.config({find:e=>Cg.getHighlighted(e)}),Ah.config({})]),eventOrder:e.eventOrder,apis:y,events:f}},extraApis:{tieredData:(e,t,o)=>({primary:e,menus:t,expansions:o}),singleData:(e,t)=>({primary:e,menus:Fs(e,t),expansions:{}}),collapseItem:e=>({value:Bi(yf()),meta:{text:e}})}}),wf=Xm({name:"InlineView",configFields:[is("lazySink"),xi("onShow"),xi("onHide"),ws("onEscape"),Yu("inlineBehaviours",[Tu,qu,gc]),ks("fireDismissalEventInstead",[Cs("event",Er())]),ks("fireRepositionEventInstead",[Cs("event",Ar())]),Cs("getRelated",A.none),Cs("isExtraPart",T),Cs("eventOrder",A.none)],factory:(e,t)=>{const o=(t,o,n,s)=>{const r=e.lazySink(t).getOrDie();Tu.openWhileCloaked(t,o,(()=>tu.positionWithinBounds(r,t,n,s()))),qu.setValue(t,A.some({mode:"position",config:n,getBounds:s}))},n=(t,o,n,s)=>{const r=((e,t,o,n,s)=>{const r=()=>e.lazySink(t),a="horizontal"===n.type?{layouts:{onLtr:()=>cc(),onRtl:()=>dc()}}:{},i=e=>(e=>2===e.length)(e)?a:{};return xf.sketch({dom:{tag:"div"},data:n.data,markers:n.menu.markers,highlightOnOpen:n.menu.highlightOnOpen,fakeFocus:n.menu.fakeFocus,onEscape:()=>(Tu.close(t),e.onEscape.map((e=>e(t))),A.some(!0)),onExecute:()=>A.some(!0),onOpenMenu:(e,t)=>{tu.positionWithinBounds(r().getOrDie(),t,o,s())},onOpenSubmenu:(e,t,o,n)=>{const s=r().getOrDie();tu.position(s,o,{anchor:{type:"submenu",item:t,...i(n)}})},onRepositionMenu:(e,t,n)=>{const a=r().getOrDie();tu.positionWithinBounds(a,t,o,s()),V(n,(e=>{const t=i(e.triggeringPath);tu.position(a,e.triggeredMenu,{anchor:{type:"submenu",item:e.triggeringItem,...t}})}))}})})(e,t,o,n,s);Tu.open(t,r),qu.setValue(t,A.some({mode:"menu",menu:r}))},s=t=>{Tu.isOpen(t)&&qu.getValue(t).each((o=>{switch(o.mode){case"menu":Tu.getState(t).each(xf.repositionMenus);break;case"position":const n=e.lazySink(t).getOrDie();tu.positionWithinBounds(n,t,o.config,o.getBounds())}}))},r={setContent:(e,t)=>{Tu.setContent(e,t)},showAt:(e,t,n)=>{const s=A.none;o(e,t,n,s)},showWithinBounds:o,showMenuAt:(e,t,o)=>{n(e,t,o,A.none)},showMenuWithinBounds:n,hide:e=>{Tu.isOpen(e)&&(qu.setValue(e,A.none()),Tu.close(e))},getContent:e=>Tu.getState(e),reposition:s,isOpen:Tu.isOpen};return{uid:e.uid,dom:e.dom,behaviours:Ku(e.inlineBehaviours,[Tu.config({isPartOf:(t,o,n)=>Ml(o,n)||((t,o)=>e.getRelated(t).exists((e=>Ml(e,o))))(t,n),getAttachPoint:t=>e.lazySink(t).getOrDie(),onOpen:t=>{e.onShow(t)},onClose:t=>{e.onHide(t)}}),qu.config({store:{mode:"memory",initialValue:A.none()}}),gc.config({channels:{...Bu({isExtraPart:t.isExtraPart,...e.fireDismissalEventInstead.map((e=>({fireEventInstead:{event:e.event}}))).getOr({})}),...Fu({...e.fireRepositionEventInstead.map((e=>({fireEventInstead:{event:e.event}}))).getOr({}),doReposition:s})}})]),eventOrder:e.eventOrder,apis:r}},apis:{showAt:(e,t,o,n)=>{e.showAt(t,o,n)},showWithinBounds:(e,t,o,n,s)=>{e.showWithinBounds(t,o,n,s)},showMenuAt:(e,t,o,n)=>{e.showMenuAt(t,o,n)},showMenuWithinBounds:(e,t,o,n,s)=>{e.showMenuWithinBounds(t,o,n,s)},hide:(e,t)=>{e.hide(t)},isOpen:(e,t)=>e.isOpen(t),getContent:(e,t)=>e.getContent(t),setContent:(e,t,o)=>{e.setContent(t,o)},reposition:(e,t)=>{e.reposition(t)}}});var Sf,kf,Cf=tinymce.util.Tools.resolve("tinymce.util.Delay"),Of=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),_f=tinymce.util.Tools.resolve("tinymce.EditorManager"),Tf=tinymce.util.Tools.resolve("tinymce.Env");!function(e){e.default="wrap",e.floating="floating",e.sliding="sliding",e.scrolling="scrolling"}(Sf||(Sf={})),function(e){e.auto="auto",e.top="top",e.bottom="bottom"}(kf||(kf={}));const Ef=e=>t=>t.options.get(e),Af=e=>t=>A.from(e(t)),Mf=e=>{const t=Tf.deviceType.isPhone(),o=Tf.deviceType.isTablet()||t,n=e.options.register,s=e=>r(e)||!1===e,a=e=>r(e)||h(e);n("skin",{processor:e=>r(e)||!1===e,default:"oxide"}),n("skin_url",{processor:"string"}),n("height",{processor:a,default:Math.max(e.getElement().offsetHeight,400)}),n("width",{processor:a,default:Of.DOM.getStyle(e.getElement(),"width")}),n("min_height",{processor:"number",default:100}),n("min_width",{processor:"number"}),n("max_height",{processor:"number"}),n("max_width",{processor:"number"}),n("style_formats",{processor:"object[]"}),n("style_formats_merge",{processor:"boolean",default:!1}),n("style_formats_autohide",{processor:"boolean",default:!1}),n("line_height_formats",{processor:"string",default:"1 1.1 1.2 1.3 1.4 1.5 2"}),n("font_family_formats",{processor:"string",default:"Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats"}),n("font_size_formats",{processor:"string",default:"8pt 10pt 12pt 14pt 18pt 24pt 36pt"}),n("font_size_input_default_unit",{processor:"string",default:"pt"}),n("block_formats",{processor:"string",default:"Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre"}),n("content_langs",{processor:"object[]"}),n("removed_menuitems",{processor:"string",default:""}),n("menubar",{processor:e=>r(e)||d(e),default:!t}),n("menu",{processor:"object",default:{}}),n("toolbar",{processor:e=>d(e)||r(e)||l(e)?{value:e,valid:!0}:{valid:!1,message:"Must be a boolean, string or array."},default:!0}),N(9,(e=>{n("toolbar"+(e+1),{processor:"string"})})),n("toolbar_mode",{processor:"string",default:o?"scrolling":"floating"}),n("toolbar_groups",{processor:"object",default:{}}),n("toolbar_location",{processor:"string",default:kf.auto}),n("toolbar_persist",{processor:"boolean",default:!1}),n("toolbar_sticky",{processor:"boolean",default:e.inline}),n("toolbar_sticky_offset",{processor:"number",default:0}),n("fixed_toolbar_container",{processor:"string",default:""}),n("fixed_toolbar_container_target",{processor:"object"}),n("ui_mode",{processor:"string",default:"combined"}),n("file_picker_callback",{processor:"function"}),n("file_picker_validator_handler",{processor:"function"}),n("file_picker_types",{processor:"string"}),n("typeahead_urls",{processor:"boolean",default:!0}),n("anchor_top",{processor:s,default:"#top"}),n("anchor_bottom",{processor:s,default:"#bottom"}),n("draggable_modal",{processor:"boolean",default:!1}),n("statusbar",{processor:"boolean",default:!0}),n("elementpath",{processor:"boolean",default:!0}),n("branding",{processor:"boolean",default:!0}),n("promotion",{processor:"boolean",default:!0}),n("resize",{processor:e=>"both"===e||d(e),default:!Tf.deviceType.isTouch()}),n("sidebar_show",{processor:"string"}),n("help_accessibility",{processor:"boolean",default:e.hasPlugin("help")}),n("default_font_stack",{processor:"string[]",default:[]})},Df=Ef("readonly"),Bf=Ef("height"),If=Ef("width"),Ff=Af(Ef("min_width")),Rf=Af(Ef("min_height")),Nf=Af(Ef("max_width")),zf=Af(Ef("max_height")),Lf=Af(Ef("style_formats")),Vf=Ef("style_formats_merge"),Hf=Ef("style_formats_autohide"),Pf=Ef("content_langs"),Uf=Ef("removed_menuitems"),Wf=Ef("toolbar_mode"),jf=Ef("toolbar_groups"),$f=Ef("toolbar_location"),Gf=Ef("fixed_toolbar_container"),qf=Ef("fixed_toolbar_container_target"),Yf=Ef("toolbar_persist"),Xf=Ef("toolbar_sticky_offset"),Kf=Ef("menubar"),Jf=Ef("toolbar"),Qf=Ef("file_picker_callback"),Zf=Ef("file_picker_validator_handler"),eb=Ef("font_size_input_default_unit"),tb=Ef("file_picker_types"),ob=Ef("typeahead_urls"),nb=Ef("anchor_top"),sb=Ef("anchor_bottom"),rb=Ef("draggable_modal"),ab=Ef("statusbar"),ib=Ef("elementpath"),lb=Ef("branding"),cb=Ef("resize"),db=Ef("paste_as_text"),ub=Ef("sidebar_show"),mb=Ef("promotion"),gb=Ef("help_accessibility"),pb=Ef("default_font_stack"),hb=e=>!1===e.options.get("skin"),fb=e=>!1!==e.options.get("menubar"),bb=e=>{const t=e.options.get("skin_url");if(hb(e))return t;if(t)return e.documentBaseURI.toAbsolute(t);{const t=e.options.get("skin");return _f.baseURL+"/skins/ui/"+t}},vb=e=>A.from(e.options.get("skin_url")),yb=e=>e.options.get("line_height_formats").split(" "),xb=e=>{const t=Jf(e),o=r(t),n=l(t)&&t.length>0;return!Sb(e)&&(n||o||!0===t)},wb=e=>{const t=N(9,(t=>e.options.get("toolbar"+(t+1)))),o=P(t,r);return ke(o.length>0,o)},Sb=e=>wb(e).fold((()=>{const t=Jf(e);return f(t,r)&&t.length>0}),E),kb=e=>$f(e)===kf.bottom,Cb=e=>{var t;if(!e.inline)return A.none();const o=null!==(t=Gf(e))&&void 0!==t?t:"";if(o.length>0)return _l(wt(),o);const n=qf(e);return g(n)?A.some(ze(n)):A.none()},Ob=e=>e.inline&&Cb(e).isSome(),_b=e=>Cb(e).getOrThunk((()=>bt(ft(ze(e.getElement()))))),Tb=e=>e.inline&&!fb(e)&&!xb(e)&&!Sb(e),Eb=e=>(e.options.get("toolbar_sticky")||e.inline)&&!Ob(e)&&!Tb(e),Ab=e=>!Ob(e)&&"split"===e.options.get("ui_mode"),Mb=e=>{const t=e.options.get("menu");return le(t,(e=>({...e,items:e.items})))};var Db=Object.freeze({__proto__:null,get ToolbarMode(){return Sf},get ToolbarLocation(){return kf},register:Mf,getSkinUrl:bb,getSkinUrlOption:vb,isReadOnly:Df,isSkinDisabled:hb,getHeightOption:Bf,getWidthOption:If,getMinWidthOption:Ff,getMinHeightOption:Rf,getMaxWidthOption:Nf,getMaxHeightOption:zf,getUserStyleFormats:Lf,shouldMergeStyleFormats:Vf,shouldAutoHideStyleFormats:Hf,getLineHeightFormats:yb,getContentLanguages:Pf,getRemovedMenuItems:Uf,isMenubarEnabled:fb,isMultipleToolbars:Sb,isToolbarEnabled:xb,isToolbarPersist:Yf,getMultipleToolbarsOption:wb,getUiContainer:_b,useFixedContainer:Ob,isSplitUiMode:Ab,getToolbarMode:Wf,isDraggableModal:rb,isDistractionFree:Tb,isStickyToolbar:Eb,getStickyToolbarOffset:Xf,getToolbarLocation:$f,isToolbarLocationBottom:kb,getToolbarGroups:jf,getMenus:Mb,getMenubar:Kf,getToolbar:Jf,getFilePickerCallback:Qf,getFilePickerTypes:tb,useTypeaheadUrls:ob,getAnchorTop:nb,getAnchorBottom:sb,getFilePickerValidatorHandler:Zf,getFontSizeInputDefaultUnit:eb,useStatusBar:ab,useElementPath:ib,promotionEnabled:mb,useBranding:lb,getResize:cb,getPasteAsText:db,getSidebarShow:ub,useHelpAccessibility:gb,getDefaultFontStack:pb});const Bb=["visible","hidden","clip"],Ib=e=>Ae(e).length>0&&!F(Bb,e),Fb=e=>{if(je(e)){const t=Rt(e,"overflow-x"),o=Rt(e,"overflow-y");return Ib(t)||Ib(o)}return!1},Rb=(e,t)=>Ab(e)?(e=>{const t=_d(e,Fb),o=0===t.length?vt(e).map(yt).map((e=>_d(e,Fb))).getOr([]):t;return te(o).map((e=>({element:e,others:o.slice(1)})))})(t):A.none(),Nb=e=>{const t=[...L(e.others,Qo),tn()];return((e,t)=>W(t,((e,t)=>en(e,t)),e))(Qo(e.element),t)},zb=Xm({name:"Button",factory:e=>{const t=$h(e.action),o=e.dom.tag,n=t=>fe(e.dom,"attributes").bind((e=>fe(e,t)));return{uid:e.uid,dom:e.dom,components:e.components,events:t,behaviours:Qu(e.buttonBehaviours,[Rh.config({}),xh.config({mode:"execution",useSpace:!0,useEnter:!0})]),domModification:{attributes:"button"===o?{type:n("type").getOr("button"),...n("role").map((e=>({role:e}))).getOr({})}:{role:e.role.getOr(n("role").getOr("button"))}},eventOrder:e.eventOrder}},configFields:[Cs("uid",void 0),is("dom"),Cs("components",[]),Ju("buttonBehaviours",[Rh,xh]),fs("action"),fs("role"),Cs("eventOrder",{})]}),Lb=e=>{const t=Fe(e),o=lt(t),n=(e=>{const t=void 0!==e.dom.attributes?e.dom.attributes:[];return W(t,((e,t)=>"class"===t.name?e:{...e,[t.name]:t.value}),{})})(t),s=(e=>Array.prototype.slice.call(e.dom.classList,0))(t),r=0===o.length?{}:{innerHtml:si(t)};return{tag:Ue(t),classes:s,attributes:n,...r}},Vb=e=>{const t=(e=>void 0!==e.uid)(e)&&ve(e,"uid")?e.uid:Vi("memento");return{get:e=>e.getSystem().getByUid(t).getOrDie(),getOpt:e=>e.getSystem().getByUid(t).toOptional(),asSpec:()=>({...e,uid:t})}};var Hb=Object.freeze({__proto__:null,exhibit:(e,t)=>aa({attributes:Rs([{key:t.tabAttr,value:"true"}])})}),Pb=[Cs("tabAttr","data-alloy-tabstop")];const Ub=pa({fields:Pb,name:"tabstopping",active:Hb}),Wb=Bi("tooltip.exclusive"),jb=Bi("tooltip.show"),$b=Bi("tooltip.hide"),Gb=Bi("tooltip.immediateHide"),qb=Bi("tooltip.immediateShow"),Yb=(e,t,o)=>{e.getSystem().broadcastOn([Wb],{})};var Xb=Object.freeze({__proto__:null,hideAllExclusive:Yb,setComponents:(e,t,o,n)=>{o.getTooltip().each((e=>{e.getSystem().isConnected()&&Ah.set(e,n)}))}}),Kb=Object.freeze({__proto__:null,events:(e,t)=>{const o=o=>{t.getTooltip().each((n=>{n.getSystem().isConnected()&&(uu(n),e.onHide(o,n),t.clearTooltip())})),t.clearTimer()},n=o=>{if(!t.isShowing()){Yb(o);const n=e.lazySink(o).getOrDie(),s=o.getSystem().build({dom:e.tooltipDom,components:e.tooltipComponents,events:Wr("normal"===e.mode?[Gr(Js(),(e=>{zr(o,jb)})),Gr(Xs(),(e=>{zr(o,$b)}))]:[]),behaviours:ma([Ah.config({})])});t.setTooltip(s),lu(n,s),e.onShow(o,s),tu.position(n,s,{anchor:e.anchor(o)})}},s=o=>{t.getTooltip().each((t=>{const n=e.lazySink(o).getOrDie();tu.position(n,t,{anchor:e.anchor(o)})}))};return Wr(G([[Gr(jb,(o=>{t.resetTimer((()=>{n(o)}),e.delayForShow())})),Gr($b,(n=>{t.resetTimer((()=>{o(n)}),e.delayForHide())})),Gr(qb,(e=>{t.resetTimer((()=>{n(e)}),0)})),Gr(Gb,(e=>{t.resetTimer((()=>{o(e)}),0)})),Gr(pr(),((e,t)=>{const n=t;n.universal||F(n.channels,Wb)&&o(e)})),ta((e=>{o(e)}))],(()=>{switch(e.mode){case"normal":return[Gr(Qs(),(e=>{zr(e,qb)})),Gr(mr(),(e=>{zr(e,Gb)})),Gr(Js(),(e=>{zr(e,jb)})),Gr(Xs(),(e=>{zr(e,$b)}))];case"follow-highlight":return[Gr(Rr(),((e,t)=>{zr(e,jb)})),Gr(Nr(),(e=>{zr(e,$b)}))];case"children-normal":return[Gr(Qs(),((o,n)=>{yc(o.element).each((r=>{Ke(n.event.target,"[data-mce-tooltip]")&&t.getTooltip().fold((()=>{zr(o,qb)}),(n=>{t.isShowing()&&(e.onShow(o,n),s(o))}))}))})),Gr(mr(),(e=>{yc(e.element).fold((()=>{zr(e,Gb)}),b)})),Gr(Js(),(o=>{_l(o.element,"[data-mce-tooltip]:hover").each((n=>{t.getTooltip().fold((()=>{zr(o,jb)}),(n=>{t.isShowing()&&(e.onShow(o,n),s(o))}))}))})),Gr(Xs(),(e=>{_l(e.element,"[data-mce-tooltip]:hover").fold((()=>{zr(e,$b)}),b)}))];default:return[Gr(Qs(),((o,n)=>{yc(o.element).each((r=>{Ke(n.event.target,"[data-mce-tooltip]")&&t.getTooltip().fold((()=>{zr(o,qb)}),(n=>{t.isShowing()&&(e.onShow(o,n),s(o))}))}))})),Gr(mr(),(e=>{yc(e.element).fold((()=>{zr(e,Gb)}),b)}))]}})()]))}}),Jb=[is("lazySink"),is("tooltipDom"),Cs("exclusive",!0),Cs("tooltipComponents",[]),Ms("delayForShow",x(300)),Ms("delayForHide",x(300)),Es("mode","normal",["normal","follow-highlight","children-keyboard-focus","children-normal"]),Cs("anchor",(e=>({type:"hotspot",hotspot:e,layouts:{onLtr:x([oc,tc,Jl,Zl,Ql,ec]),onRtl:x([oc,tc,Jl,Zl,Ql,ec])},bubble:Gc(0,-2,{})}))),xi("onHide"),xi("onShow")],Qb=Object.freeze({__proto__:null,init:()=>{const e=rn(),t=rn(),o=()=>{e.on(clearTimeout)},n=x("not-implemented");return ua({getTooltip:t.get,isShowing:t.isSet,setTooltip:t.set,clearTooltip:t.clear,clearTimer:o,resetTimer:(t,n)=>{o(),e.set(setTimeout(t,n))},readState:n})}});const Zb=pa({fields:Jb,name:"tooltipping",active:Kb,state:Qb,apis:Xb}),{entries:ev,setPrototypeOf:tv,isFrozen:ov,getPrototypeOf:nv,getOwnPropertyDescriptor:sv}=Object;let{freeze:rv,seal:av,create:iv}=Object,{apply:lv,construct:cv}="undefined"!=typeof Reflect&&Reflect;lv||(lv=function(e,t,o){return e.apply(t,o)}),rv||(rv=function(e){return e}),av||(av=function(e){return e}),cv||(cv=function(e,t){return new e(...t)});const dv=Sv(Array.prototype.forEach),uv=Sv(Array.prototype.pop),mv=Sv(Array.prototype.push),gv=Sv(String.prototype.toLowerCase),pv=Sv(String.prototype.toString),hv=Sv(String.prototype.match),fv=Sv(String.prototype.replace),bv=Sv(String.prototype.indexOf),vv=Sv(String.prototype.trim),yv=Sv(RegExp.prototype.test),xv=(wv=TypeError,function(){for(var e=arguments.length,t=new Array(e),o=0;o<e;o++)t[o]=arguments[o];return cv(wv,t)});var wv;function Sv(e){return function(t){for(var o=arguments.length,n=new Array(o>1?o-1:0),s=1;s<o;s++)n[s-1]=arguments[s];return lv(e,t,n)}}function kv(e,t,o){var n;o=null!==(n=o)&&void 0!==n?n:gv,tv&&tv(e,null);let s=t.length;for(;s--;){let n=t[s];if("string"==typeof n){const e=o(n);e!==n&&(ov(t)||(t[s]=e),n=e)}e[n]=!0}return e}function Cv(e){const t=iv(null);for(const[o,n]of ev(e))t[o]=n;return t}function Ov(e,t){for(;null!==e;){const o=sv(e,t);if(o){if(o.get)return Sv(o.get);if("function"==typeof o.value)return Sv(o.value)}e=nv(e)}return function(e){return console.warn("fallback value for",e),null}}const _v=rv(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),Tv=rv(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),Ev=rv(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Av=rv(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),Mv=rv(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),Dv=rv(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Bv=rv(["#text"]),Iv=rv(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","xmlns","slot"]),Fv=rv(["accent-height","accumulate","additive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),Rv=rv(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),Nv=rv(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),zv=av(/\{\{[\w\W]*|[\w\W]*\}\}/gm),Lv=av(/<%[\w\W]*|[\w\W]*%>/gm),Vv=av(/\${[\w\W]*}/gm),Hv=av(/^data-[\-\w.\u00B7-\uFFFF]/),Pv=av(/^aria-[\-\w]+$/),Uv=av(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Wv=av(/^(?:\w+script|data):/i),jv=av(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),$v=av(/^html$/i);var Gv=Object.freeze({__proto__:null,MUSTACHE_EXPR:zv,ERB_EXPR:Lv,TMPLIT_EXPR:Vv,DATA_ATTR:Hv,ARIA_ATTR:Pv,IS_ALLOWED_URI:Uv,IS_SCRIPT_OR_DATA:Wv,ATTR_WHITESPACE:jv,DOCTYPE_NAME:$v});const qv=()=>"undefined"==typeof window?null:window;var Yv=function e(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:qv();const o=t=>e(t);if(o.version="3.0.5",o.removed=[],!t||!t.document||9!==t.document.nodeType)return o.isSupported=!1,o;const n=t.document,s=n.currentScript;let{document:r}=t;const{DocumentFragment:a,HTMLTemplateElement:i,Node:l,Element:c,NodeFilter:d,NamedNodeMap:u=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:m,DOMParser:g,trustedTypes:p}=t,h=c.prototype,f=Ov(h,"cloneNode"),b=Ov(h,"nextSibling"),v=Ov(h,"childNodes"),y=Ov(h,"parentNode");if("function"==typeof i){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let x,w="";const{implementation:S,createNodeIterator:k,createDocumentFragment:C,getElementsByTagName:O}=r,{importNode:_}=n;let T={};o.isSupported="function"==typeof ev&&"function"==typeof y&&S&&void 0!==S.createHTMLDocument;const{MUSTACHE_EXPR:E,ERB_EXPR:A,TMPLIT_EXPR:M,DATA_ATTR:D,ARIA_ATTR:B,IS_SCRIPT_OR_DATA:I,ATTR_WHITESPACE:F}=Gv;let{IS_ALLOWED_URI:R}=Gv,N=null;const z=kv({},[..._v,...Tv,...Ev,...Mv,...Bv]);let L=null;const V=kv({},[...Iv,...Fv,...Rv,...Nv]);let H=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),P=null,U=null,W=!0,j=!0,$=!1,G=!0,q=!1,Y=!1,X=!1,K=!1,J=!1,Q=!1,Z=!1,ee=!0,te=!1,oe=!0,ne=!1,se={},re=null;const ae=kv({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let ie=null;const le=kv({},["audio","video","img","source","image","track"]);let ce=null;const de=kv({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ue="http://www.w3.org/1998/Math/MathML",me="http://www.w3.org/2000/svg",ge="http://www.w3.org/1999/xhtml";let pe=ge,he=!1,fe=null;const be=kv({},[ue,me,ge],pv);let ve;const ye=["application/xhtml+xml","text/html"];let xe,we=null;const Se=r.createElement("form"),ke=function(e){return e instanceof RegExp||e instanceof Function},Ce=function(e){if(!we||we!==e){if(e&&"object"==typeof e||(e={}),e=Cv(e),ve=ve=-1===ye.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,xe="application/xhtml+xml"===ve?pv:gv,N="ALLOWED_TAGS"in e?kv({},e.ALLOWED_TAGS,xe):z,L="ALLOWED_ATTR"in e?kv({},e.ALLOWED_ATTR,xe):V,fe="ALLOWED_NAMESPACES"in e?kv({},e.ALLOWED_NAMESPACES,pv):be,ce="ADD_URI_SAFE_ATTR"in e?kv(Cv(de),e.ADD_URI_SAFE_ATTR,xe):de,ie="ADD_DATA_URI_TAGS"in e?kv(Cv(le),e.ADD_DATA_URI_TAGS,xe):le,re="FORBID_CONTENTS"in e?kv({},e.FORBID_CONTENTS,xe):ae,P="FORBID_TAGS"in e?kv({},e.FORBID_TAGS,xe):{},U="FORBID_ATTR"in e?kv({},e.FORBID_ATTR,xe):{},se="USE_PROFILES"in e&&e.USE_PROFILES,W=!1!==e.ALLOW_ARIA_ATTR,j=!1!==e.ALLOW_DATA_ATTR,$=e.ALLOW_UNKNOWN_PROTOCOLS||!1,G=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,q=e.SAFE_FOR_TEMPLATES||!1,Y=e.WHOLE_DOCUMENT||!1,J=e.RETURN_DOM||!1,Q=e.RETURN_DOM_FRAGMENT||!1,Z=e.RETURN_TRUSTED_TYPE||!1,K=e.FORCE_BODY||!1,ee=!1!==e.SANITIZE_DOM,te=e.SANITIZE_NAMED_PROPS||!1,oe=!1!==e.KEEP_CONTENT,ne=e.IN_PLACE||!1,R=e.ALLOWED_URI_REGEXP||Uv,pe=e.NAMESPACE||ge,H=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ke(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(H.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ke(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(H.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(H.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),q&&(j=!1),Q&&(J=!0),se&&(N=kv({},[...Bv]),L=[],!0===se.html&&(kv(N,_v),kv(L,Iv)),!0===se.svg&&(kv(N,Tv),kv(L,Fv),kv(L,Nv)),!0===se.svgFilters&&(kv(N,Ev),kv(L,Fv),kv(L,Nv)),!0===se.mathMl&&(kv(N,Mv),kv(L,Rv),kv(L,Nv))),e.ADD_TAGS&&(N===z&&(N=Cv(N)),kv(N,e.ADD_TAGS,xe)),e.ADD_ATTR&&(L===V&&(L=Cv(L)),kv(L,e.ADD_ATTR,xe)),e.ADD_URI_SAFE_ATTR&&kv(ce,e.ADD_URI_SAFE_ATTR,xe),e.FORBID_CONTENTS&&(re===ae&&(re=Cv(re)),kv(re,e.FORBID_CONTENTS,xe)),oe&&(N["#text"]=!0),Y&&kv(N,["html","head","body"]),N.table&&(kv(N,["tbody"]),delete P.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw xv('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw xv('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');x=e.TRUSTED_TYPES_POLICY,w=x.createHTML("")}else void 0===x&&(x=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let o=null;const n="data-tt-policy-suffix";t&&t.hasAttribute(n)&&(o=t.getAttribute(n));const s="dompurify"+(o?"#"+o:"");try{return e.createPolicy(s,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+s+" could not be created."),null}}(p,s)),null!==x&&"string"==typeof w&&(w=x.createHTML(""));rv&&rv(e),we=e}},Oe=kv({},["mi","mo","mn","ms","mtext"]),_e=kv({},["foreignobject","desc","title","annotation-xml"]),Te=kv({},["title","style","font","a","script"]),Ee=kv({},Tv);kv(Ee,Ev),kv(Ee,Av);const Ae=kv({},Mv);kv(Ae,Dv);const Me=function(e){mv(o.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.remove()}},De=function(e,t){try{mv(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){mv(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!L[e])if(J||Q)try{Me(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Be=function(e){let t,o;if(K)e="<remove></remove>"+e;else{const t=hv(e,/^[\r\n\t ]+/);o=t&&t[0]}"application/xhtml+xml"===ve&&pe===ge&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const n=x?x.createHTML(e):e;if(pe===ge)try{t=(new g).parseFromString(n,ve)}catch(e){}if(!t||!t.documentElement){t=S.createDocument(pe,"template",null);try{t.documentElement.innerHTML=he?w:n}catch(e){}}const s=t.body||t.documentElement;return e&&o&&s.insertBefore(r.createTextNode(o),s.childNodes[0]||null),pe===ge?O.call(t,Y?"html":"body")[0]:Y?t.documentElement:s},Ie=function(e){return k.call(e.ownerDocument||e,e,d.SHOW_ELEMENT|d.SHOW_COMMENT|d.SHOW_TEXT,null,!1)},Fe=function(e){return"object"==typeof l?e instanceof l:e&&"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},Re=function(e,t,n){T[e]&&dv(T[e],(e=>{e.call(o,t,n,we)}))},Ne=function(e){let t;if(Re("beforeSanitizeElements",e,null),(n=e)instanceof m&&("string"!=typeof n.nodeName||"string"!=typeof n.textContent||"function"!=typeof n.removeChild||!(n.attributes instanceof u)||"function"!=typeof n.removeAttribute||"function"!=typeof n.setAttribute||"string"!=typeof n.namespaceURI||"function"!=typeof n.insertBefore||"function"!=typeof n.hasChildNodes))return Me(e),!0;var n;const s=xe(e.nodeName);if(Re("uponSanitizeElement",e,{tagName:s,allowedTags:N}),e.hasChildNodes()&&!Fe(e.firstElementChild)&&(!Fe(e.content)||!Fe(e.content.firstElementChild))&&yv(/<[/\w]/g,e.innerHTML)&&yv(/<[/\w]/g,e.textContent))return Me(e),!0;if(!N[s]||P[s]){if(!P[s]&&Le(s)){if(H.tagNameCheck instanceof RegExp&&yv(H.tagNameCheck,s))return!1;if(H.tagNameCheck instanceof Function&&H.tagNameCheck(s))return!1}if(oe&&!re[s]){const t=y(e)||e.parentNode,o=v(e)||e.childNodes;if(o&&t)for(let n=o.length-1;n>=0;--n)t.insertBefore(f(o[n],!0),b(e))}return Me(e),!0}return e instanceof c&&!function(e){let t=y(e);t&&t.tagName||(t={namespaceURI:pe,tagName:"template"});const o=gv(e.tagName),n=gv(t.tagName);return!!fe[e.namespaceURI]&&(e.namespaceURI===me?t.namespaceURI===ge?"svg"===o:t.namespaceURI===ue?"svg"===o&&("annotation-xml"===n||Oe[n]):Boolean(Ee[o]):e.namespaceURI===ue?t.namespaceURI===ge?"math"===o:t.namespaceURI===me?"math"===o&&_e[n]:Boolean(Ae[o]):e.namespaceURI===ge?!(t.namespaceURI===me&&!_e[n])&&!(t.namespaceURI===ue&&!Oe[n])&&!Ae[o]&&(Te[o]||!Ee[o]):!("application/xhtml+xml"!==ve||!fe[e.namespaceURI]))}(e)?(Me(e),!0):"noscript"!==s&&"noembed"!==s&&"noframes"!==s||!yv(/<\/no(script|embed|frames)/i,e.innerHTML)?(q&&3===e.nodeType&&(t=e.textContent,t=fv(t,E," "),t=fv(t,A," "),t=fv(t,M," "),e.textContent!==t&&(mv(o.removed,{element:e.cloneNode()}),e.textContent=t)),Re("afterSanitizeElements",e,null),!1):(Me(e),!0)},ze=function(e,t,o){if(ee&&("id"===t||"name"===t)&&(o in r||o in Se))return!1;if(j&&!U[t]&&yv(D,t));else if(W&&yv(B,t));else if(!L[t]||U[t]){if(!(Le(e)&&(H.tagNameCheck instanceof RegExp&&yv(H.tagNameCheck,e)||H.tagNameCheck instanceof Function&&H.tagNameCheck(e))&&(H.attributeNameCheck instanceof RegExp&&yv(H.attributeNameCheck,t)||H.attributeNameCheck instanceof Function&&H.attributeNameCheck(t))||"is"===t&&H.allowCustomizedBuiltInElements&&(H.tagNameCheck instanceof RegExp&&yv(H.tagNameCheck,o)||H.tagNameCheck instanceof Function&&H.tagNameCheck(o))))return!1}else if(ce[t]);else if(yv(R,fv(o,F,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==bv(o,"data:")||!ie[e])if($&&!yv(I,fv(o,F,"")));else if(o)return!1;return!0},Le=function(e){return e.indexOf("-")>0},Ve=function(e){let t,o,n,s;Re("beforeSanitizeAttributes",e,null);const{attributes:r}=e;if(!r)return;const a={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:L};for(s=r.length;s--;){t=r[s];const{name:i,namespaceURI:l}=t;o="value"===i?t.value:vv(t.value);const c=o;if(n=xe(i),a.attrName=n,a.attrValue=o,a.keepAttr=!0,a.forceKeepAttr=void 0,Re("uponSanitizeAttribute",e,a),o=a.attrValue,a.forceKeepAttr)continue;if(!a.keepAttr){De(i,e);continue}if(!G&&yv(/\/>/i,o)){De(i,e);continue}q&&(o=fv(o,E," "),o=fv(o,A," "),o=fv(o,M," "));const d=xe(e.nodeName);if(ze(d,n,o)){if(!te||"id"!==n&&"name"!==n||(De(i,e),o="user-content-"+o),x&&"object"==typeof p&&"function"==typeof p.getAttributeType)if(l);else switch(p.getAttributeType(d,n)){case"TrustedHTML":o=x.createHTML(o);break;case"TrustedScriptURL":o=x.createScriptURL(o)}if(o!==c)try{l?e.setAttributeNS(l,i,o):e.setAttribute(i,o)}catch(t){De(i,e)}}else De(i,e)}Re("afterSanitizeAttributes",e,null)},He=function e(t){let o;const n=Ie(t);for(Re("beforeSanitizeShadowDOM",t,null);o=n.nextNode();)Re("uponSanitizeShadowNode",o,null),Ne(o)||(o.content instanceof a&&e(o.content),Ve(o));Re("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t,s,r,i,c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(he=!e,he&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Fe(e)){if("function"!=typeof e.toString)throw xv("toString is not a function");if("string"!=typeof(e=e.toString()))throw xv("dirty is not a string, aborting")}if(!o.isSupported)return e;if(X||Ce(c),o.removed=[],"string"==typeof e&&(ne=!1),ne){if(e.nodeName){const t=xe(e.nodeName);if(!N[t]||P[t])throw xv("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof l)t=Be("\x3c!----\x3e"),s=t.ownerDocument.importNode(e,!0),1===s.nodeType&&"BODY"===s.nodeName||"HTML"===s.nodeName?t=s:t.appendChild(s);else{if(!J&&!q&&!Y&&-1===e.indexOf("<"))return x&&Z?x.createHTML(e):e;if(t=Be(e),!t)return J?null:Z?w:""}t&&K&&Me(t.firstChild);const d=Ie(ne?e:t);for(;r=d.nextNode();)Ne(r)||(r.content instanceof a&&He(r.content),Ve(r));if(ne)return e;if(J){if(Q)for(i=C.call(t.ownerDocument);t.firstChild;)i.appendChild(t.firstChild);else i=t;return(L.shadowroot||L.shadowrootmode)&&(i=_.call(n,i,!0)),i}let u=Y?t.outerHTML:t.innerHTML;return Y&&N["!doctype"]&&t.ownerDocument&&t.ownerDocument.doctype&&t.ownerDocument.doctype.name&&yv($v,t.ownerDocument.doctype.name)&&(u="<!DOCTYPE "+t.ownerDocument.doctype.name+">\n"+u),q&&(u=fv(u,E," "),u=fv(u,A," "),u=fv(u,M," ")),x&&Z?x.createHTML(u):u},o.setConfig=function(e){Ce(e),X=!0},o.clearConfig=function(){we=null,X=!1},o.isValidAttribute=function(e,t,o){we||Ce({});const n=xe(e),s=xe(t);return ze(n,s,o)},o.addHook=function(e,t){"function"==typeof t&&(T[e]=T[e]||[],mv(T[e],t))},o.removeHook=function(e){if(T[e])return uv(T[e])},o.removeHooks=function(e){T[e]&&(T[e]=[])},o.removeAllHooks=function(){T={}},o}();const Xv=e=>Yv().sanitize(e);var Kv=tinymce.util.Tools.resolve("tinymce.util.I18n");const Jv={indent:!0,outdent:!0,"table-insert-column-after":!0,"table-insert-column-before":!0,"paste-column-after":!0,"paste-column-before":!0,"unordered-list":!0,"list-bull-circle":!0,"list-bull-default":!0,"list-bull-square":!0},Qv="temporary-placeholder",Zv=e=>()=>fe(e,Qv).getOr("!not found!"),ey=(e,t)=>{const o=e.toLowerCase();if(Kv.isRtl()){const e=((e,t)=>Ee(e,t)?e:((e,t)=>e+t)(e,t))(o,"-rtl");return be(t,e)?e:o}return o},ty=(e,t)=>fe(t,ey(e,t)),oy=(e,t)=>{const o=t();return ty(e,o).getOrThunk(Zv(o))},ny=()=>Mh("add-focusable",[ea((e=>{Ol(e.element,"svg").each((e=>Ct(e,"focusable","false")))}))]),sy=(e,t,o,n)=>{var s,r;const a=(e=>!!Kv.isRtl()&&be(Jv,e))(t)?["tox-icon--flip"]:[],i=fe(o,ey(t,o)).or(n).getOrThunk(Zv(o));return{dom:{tag:e.tag,attributes:null!==(s=e.attributes)&&void 0!==s?s:{},classes:e.classes.concat(a),innerHtml:i},behaviours:ma([...null!==(r=e.behaviours)&&void 0!==r?r:[],ny()])}},ry=(e,t,o,n=A.none())=>sy(t,e,o(),n),ay={success:"checkmark",error:"warning",err:"error",warning:"warning",warn:"warning",info:"info"},iy=Xm({name:"Notification",factory:e=>{const t=Bi("notification-text"),o=Vb({dom:Lb(`<p id=${t}>${Xv(e.backstageProvider.translate(e.text))}</p>`),behaviours:ma([Ah.config({})])}),n=e=>({dom:{tag:"div",classes:["tox-bar"],styles:{width:`${e}%`}}}),s=e=>({dom:{tag:"div",classes:["tox-text"],innerHtml:`${e}%`}}),r=Vb({dom:{tag:"div",classes:e.progress?["tox-progress-bar","tox-progress-indicator"]:["tox-progress-bar"]},components:[{dom:{tag:"div",classes:["tox-bar-container"]},components:[n(0)]},s(0)],behaviours:ma([Ah.config({})])}),a={updateProgress:(e,t)=>{e.getSystem().isConnected()&&r.getOpt(e).each((e=>{Ah.set(e,[{dom:{tag:"div",classes:["tox-bar-container"]},components:[n(t)]},s(t)])}))},updateText:(e,t)=>{if(e.getSystem().isConnected()){const n=o.get(e);Ah.set(n,[ul(t)])}}},i=G([e.icon.toArray(),e.level.toArray(),e.level.bind((e=>A.from(ay[e]))).toArray()]),l=Vb(zb.sketch({dom:{tag:"button",classes:["tox-notification__dismiss","tox-button","tox-button--naked","tox-button--icon"],attributes:{"aria-label":e.backstageProvider.translate("Close")}},components:[ry("close",{tag:"span",classes:["tox-icon"]},e.iconProvider)],buttonBehaviours:ma([Ub.config({}),Zb.config({...e.backstageProvider.tooltips.getConfig({tooltipText:e.backstageProvider.translate("Close")})})]),action:t=>{e.onAction(t)}})),c=((e,t,o)=>{const n=o(),s=j(e,(e=>be(n,ey(e,n))));return sy({tag:"div",classes:["tox-notification__icon"]},s.getOr(Qv),n,A.none())})(i,0,e.iconProvider),d=[c,{dom:{tag:"div",classes:["tox-notification__body"]},components:[o.asSpec()],behaviours:ma([Ah.config({})])}];return{uid:e.uid,dom:{tag:"div",attributes:{role:"alert","aria-labelledby":t},classes:e.level.map((e=>["tox-notification","tox-notification--in",`tox-notification--${e}`])).getOr(["tox-notification","tox-notification--in"])},behaviours:ma([Ub.config({}),Rh.config({}),xh.config({mode:"special",onEscape:t=>(e.onAction(t),A.some(!0))})]),components:d.concat(e.progress?[r.asSpec()]:[]).concat([l.asSpec()]),apis:a}},configFields:[fs("level"),is("progress"),fs("icon"),is("onAction"),is("text"),is("iconProvider"),is("backstageProvider")],apis:{updateProgress:(e,t,o)=>{e.updateProgress(t,o)},updateText:(e,t,o)=>{e.updateText(t,o)}}});var ly=(e,t,o,n)=>{const s=t.backstage.shared,r=()=>{const t=Qo(ze(e.getContentAreaContainer()));return A.some(t)},a=e=>{r().each((t=>{V(e,(e=>{Qt(e.element)>t.width&&Bt(e.element,"width",t.width+"px")}))}))};return{open:(t,i,l)=>{const c=()=>{n.on((t=>{i();const o=l();(e=>{Ah.remove(e,d),u()})(t),((t,o)=>{0===lt(t.element).length?((t,o)=>{wf.hide(t),n.clear(),o&&e.focus()})(t,o):((e,t)=>{t&&xh.focusIn(e)})(t,o)})(t,o)}))},d=hl(iy.sketch({text:t.text,level:F(["success","error","warning","warn","info"],t.type)?t.type:void 0,progress:!0===t.progressBar,icon:t.icon,onAction:c,iconProvider:s.providers.icons,backstageProvider:s.providers}));if(n.isSet()){const e=fl(d);n.on((t=>{Ah.append(t,e),wf.reposition(t),Ei.refresh(t),a(t.components())}))}else{const t=hl(wf.sketch({dom:{tag:"div",classes:["tox-notifications-container"],attributes:{"aria-label":"Notifications",role:"region"}},lazySink:s.getSink,fireDismissalEventInstead:{},...s.header.isPositionedAtTop()?{}:{fireRepositionEventInstead:{}},inlineBehaviours:ma([xh.config({mode:"cyclic",selector:".tox-notification, .tox-notification a, .tox-notification button"}),Ah.config({}),...Eb(e)&&!s.header.isPositionedAtTop()?[]:[Ei.config({contextual:{lazyContext:()=>A.some(Qo(ze(e.getContentAreaContainer()))),fadeInClass:"tox-notification-container-dock-fadein",fadeOutClass:"tox-notification-container-dock-fadeout",transitionClass:"tox-notification-container-dock-transition"},modes:["top"],lazyViewport:t=>Rb(e,t.element).map((e=>({bounds:Nb(e),optScrollEnv:A.some({currentScrollTop:e.element.dom.scrollTop,scrollElmTop:Xt(e.element).top})}))).getOrThunk((()=>({bounds:tn(),optScrollEnv:A.none()})))})]])})),a=fl(d),i={maxHeightFunction:Uc()},l={...s.anchors.banner(),overrides:i};n.set(t),o.add(t),wf.showWithinBounds(t,a,{anchor:l},r)}h(t.timeout)&&t.timeout>0&&Cf.setEditorTimeout(e,(()=>{c()}),t.timeout);const u=()=>{n.on((e=>{wf.reposition(e),Ei.refresh(e),a(e.components())}))};return{close:c,reposition:u,text:e=>{iy.updateText(d,e)},settings:t,getEl:()=>d.element.dom,progressBar:{value:e=>{iy.updateProgress(d,e)}}}},close:e=>{e.close()},getArgs:e=>e.settings}};var cy;!function(e){e[e.CLOSE_ON_EXECUTE=0]="CLOSE_ON_EXECUTE",e[e.BUBBLE_TO_SANDBOX=1]="BUBBLE_TO_SANDBOX"}(cy||(cy={}));var dy=cy;const uy="tox-menu-nav__js",my="tox-collection__item",gy="tox-swatch",py={normal:uy,color:gy},hy="tox-collection__item--enabled",fy="tox-collection__item-icon",by="tox-collection__item-label",vy="tox-collection__item-caret",yy="tox-collection__item--active",xy="tox-collection__item-container",wy="tox-collection__item-container--row",Sy=e=>fe(py,e).getOr(uy),ky=e=>"color"===e?"tox-swatches":"tox-menu",Cy=e=>({backgroundMenu:"tox-background-menu",selectedMenu:"tox-selected-menu",selectedItem:"tox-collection__item--active",hasIcons:"tox-menu--has-icons",menu:ky(e),tieredMenu:"tox-tiered-menu"}),Oy=e=>{const t=Cy(e);return{backgroundMenu:t.backgroundMenu,selectedMenu:t.selectedMenu,menu:t.menu,selectedItem:t.selectedItem,item:Sy(e)}},_y=(e,t,o)=>{const n=Cy(o);return{tag:"div",classes:G([[n.menu,`tox-menu-${t}-column`],e?[n.hasIcons]:[]])}},Ty=[uf.parts.items({})],Ey=(e,t,o)=>{const n=Cy(o);return{dom:{tag:"div",classes:G([[n.tieredMenu]])},markers:Oy(o)}},Ay=x([fs("data"),Cs("inputAttributes",{}),Cs("inputStyles",{}),Cs("tag","input"),Cs("inputClasses",[]),xi("onSetValue"),Cs("styles",{}),Cs("eventOrder",{}),Yu("inputBehaviours",[qu,Rh]),Cs("selectOnFocus",!0)]),My=e=>ma([Rh.config({onFocus:e.selectOnFocus?e=>{const t=e.element,o=ol(t);t.dom.setSelectionRange(0,o.length)}:b})]),Dy=e=>({...My(e),...Ku(e.inputBehaviours,[qu.config({store:{mode:"manual",...e.data.map((e=>({initialValue:e}))).getOr({}),getValue:e=>ol(e.element),setValue:(e,t)=>{ol(e.element)!==t&&nl(e.element,t)}},onSetValue:e.onSetValue})])}),By=e=>({tag:e.tag,attributes:{type:"text",...e.inputAttributes},styles:e.inputStyles,classes:e.inputClasses}),Iy=Xm({name:"Input",configFields:Ay(),factory:(e,t)=>({uid:e.uid,dom:By(e),components:[],behaviours:Dy(e),eventOrder:e.eventOrder})}),Fy=Bi("refetch-trigger-event"),Ry=Bi("redirect-menu-item-interaction"),Ny="tox-menu__searcher",zy=e=>_l(e.element,`.${Ny}`).bind((t=>e.getSystem().getByDom(t).toOptional())),Ly=zy,Vy=e=>({fetchPattern:qu.getValue(e),selectionStart:e.element.dom.selectionStart,selectionEnd:e.element.dom.selectionEnd}),Hy=e=>{const t=(e,t)=>(t.cut(),A.none()),o=(e,t)=>{const o={interactionEvent:t.event,eventType:t.event.raw.type};return Lr(e,Ry,o),A.some(!0)},n="searcher-events";return{dom:{tag:"div",classes:[my]},components:[Iy.sketch({inputClasses:[Ny,"tox-textfield"],inputAttributes:{...e.placeholder.map((t=>({placeholder:e.i18n(t)}))).getOr({}),type:"search","aria-autocomplete":"list"},inputBehaviours:ma([Mh(n,[Gr(or(),(e=>{zr(e,Fy)})),Gr(er(),((e,t)=>{"Escape"===t.event.raw.key&&t.stop()}))]),xh.config({mode:"special",onLeft:t,onRight:t,onSpace:t,onEnter:o,onEscape:o,onUp:o,onDown:o})]),eventOrder:{keydown:[n,xh.name()]}})]}},Py="tox-collection--results__js",Uy=e=>{var t;return e.dom?{...e,dom:{...e.dom,attributes:{...null!==(t=e.dom.attributes)&&void 0!==t?t:{},id:Bi("aria-item-search-result-id"),"aria-selected":"false"}}}:e},Wy=(e,t)=>o=>{const n=z(o,t);return L(n,(t=>({dom:e,components:t})))},jy=(e,t)=>{const o=[];let n=[];return V(e,((e,s)=>{t(e,s)?(n.length>0&&o.push(n),n=[],(be(e.dom,"innerHtml")||e.components&&e.components.length>0)&&n.push(e)):n.push(e)})),n.length>0&&o.push(n),L(o,(e=>({dom:{tag:"div",classes:["tox-collection__group"]},components:e})))},$y=(e,t,o)=>uf.parts.items({preprocess:n=>{const s=L(n,o);return"auto"!==e&&e>1?Wy({tag:"div",classes:["tox-collection__group"]},e)(s):jy(s,((e,o)=>"separator"===t[o].type))}}),Gy=(e,t,o=!0)=>({dom:{tag:"div",classes:["tox-menu","tox-collection"].concat(1===e?["tox-collection--list"]:["tox-collection--grid"])},components:[$y(e,t,w)]}),qy=e=>R(e,(e=>"icon"in e&&void 0!==e.icon)),Yy=e=>(console.error(ts(e)),console.log(e),A.none()),Xy=(e,t,o,n,s)=>{const r=(a=o,{dom:{tag:"div",classes:["tox-collection","tox-collection--horizontal"]},components:[uf.parts.items({preprocess:e=>jy(e,((e,t)=>"separator"===a[t].type))})]});var a;return{value:e,dom:r.dom,components:r.components,items:o}},Ky=(e,t,o,n,s)=>{if("color"===s.menuType){const t=(e=>({dom:{tag:"div",classes:["tox-menu","tox-swatches-menu"]},components:[{dom:{tag:"div",classes:["tox-swatches"]},components:[uf.parts.items({preprocess:"auto"!==e?Wy({tag:"div",classes:["tox-swatches__row"]},e):w})]}]}))(n);return{value:e,dom:t.dom,components:t.components,items:o}}if("normal"===s.menuType&&"auto"===n){const t=Gy(n,o);return{value:e,dom:t.dom,components:t.components,items:o}}if("normal"===s.menuType||"searchable"===s.menuType){const t="searchable"!==s.menuType?Gy(n,o):"search-with-field"===s.searchMode.searchMode?((e,t,o)=>{const n=Bi("aria-controls-search-results");return{dom:{tag:"div",classes:["tox-menu","tox-collection"].concat(1===e?["tox-collection--list"]:["tox-collection--grid"])},components:[Hy({i18n:Kv.translate,placeholder:o.placeholder}),{dom:{tag:"div",classes:[...1===e?["tox-collection--list"]:["tox-collection--grid"],Py],attributes:{id:n}},components:[$y(e,t,Uy)]}]}})(n,o,s.searchMode):((e,t,o=!0)=>{const n=Bi("aria-controls-search-results");return{dom:{tag:"div",classes:["tox-menu","tox-collection",Py].concat(1===e?["tox-collection--list"]:["tox-collection--grid"]),attributes:{id:n}},components:[$y(e,t,Uy)]}})(n,o);return{value:e,dom:t.dom,components:t.components,items:o}}if("listpreview"===s.menuType&&"auto"!==n){const t=(e=>({dom:{tag:"div",classes:["tox-menu","tox-collection","tox-collection--toolbar","tox-collection--toolbar-lg"]},components:[uf.parts.items({preprocess:Wy({tag:"div",classes:["tox-collection__group"]},e)})]}))(n);return{value:e,dom:t.dom,components:t.components,items:o}}return{value:e,dom:_y(t,n,s.menuType),components:Ty,items:o}},Jy=ds("type"),Qy=ds("name"),Zy=ds("label"),ex=ds("text"),tx=ds("title"),ox=ds("icon"),nx=ds("value"),sx=ms("fetch"),rx=ms("getSubmenuItems"),ax=ms("onAction"),ix=ms("onItemAction"),lx=Ms("onSetup",(()=>b)),cx=ys("name"),dx=ys("text"),ux=ys("role"),mx=ys("icon"),gx=ys("tooltip"),px=ys("label"),hx=ys("shortcut"),fx=ws("select"),bx=As("active",!1),vx=As("borderless",!1),yx=As("enabled",!0),xx=As("primary",!1),wx=e=>Cs("columns",e),Sx=Cs("meta",{}),kx=Ms("onAction",b),Cx=e=>Ts("type",e),Ox=e=>ss("name","name",kn((()=>Bi(`${e}-name`))),jn),_x=Nn([Jy,dx]),Tx=Nn([Cx("autocompleteitem"),bx,yx,Sx,nx,dx,mx]),Ex=[yx,gx,mx,dx,lx],Ax=Nn([Jy,ax,hx].concat(Ex)),Mx=e=>Qn("toolbarbutton",Ax,e),Dx=[bx].concat(Ex),Bx=Nn(Dx.concat([Jy,ax,hx])),Ix=e=>Qn("ToggleButton",Bx,e),Fx=[Ms("predicate",T),Es("scope","node",["node","editor"]),Es("position","selection",["node","selection","line"])],Rx=Ex.concat([Cx("contextformbutton"),xx,ax,rs("original",w)]),Nx=Dx.concat([Cx("contextformbutton"),xx,ax,rs("original",w)]),zx=Ex.concat([Cx("contextformbutton")]),Lx=Dx.concat([Cx("contextformtogglebutton")]),Vx=os("type",{contextformbutton:Rx,contextformtogglebutton:Nx}),Hx=Nn([Cx("contextform"),Ms("initValue",x("")),px,hs("commands",Vx),bs("launch",os("type",{contextformbutton:zx,contextformtogglebutton:Lx}))].concat(Fx)),Px=Nn([Cx("contexttoolbar"),ds("items")].concat(Fx)),Ux=[Jy,ds("src"),ys("alt"),Ds("classes",[],jn)],Wx=Nn(Ux),jx=[Jy,ex,cx,Ds("classes",["tox-collection__item-label"],jn)],$x=Nn(jx),Gx=In((()=>Xn("type",{cardimage:Wx,cardtext:$x,cardcontainer:qx}))),qx=Nn([Jy,Ts("direction","horizontal"),Ts("align","left"),Ts("valign","middle"),hs("items",Gx)]),Yx=[yx,dx,ux,hx,("menuitem",ss("value","value",kn((()=>Bi("menuitem-value"))),Pn())),Sx];const Xx=Nn([Jy,px,hs("items",Gx),lx,kx].concat(Yx)),Kx=Nn([Jy,bx,mx].concat(Yx)),Jx=[Jy,ds("fancytype"),kx],Qx=[Cs("initData",{})].concat(Jx),Zx=[ws("select"),Bs("initData",{},[As("allowCustomColors",!0),Ts("storageKey","default"),Ss("colors",Pn())])].concat(Jx),ew=os("fancytype",{inserttable:Qx,colorswatch:Zx}),tw=Nn([Jy,lx,kx,mx].concat(Yx)),ow=Nn([Jy,rx,lx,mx].concat(Yx)),nw=Nn([Jy,mx,bx,lx,ax].concat(Yx)),sw=(e,t,o)=>{const n=Td(e.element,"."+o);if(n.length>0){const e=$(n,(e=>{const o=e.dom.getBoundingClientRect().top,s=n[0].dom.getBoundingClientRect().top;return Math.abs(o-s)>t})).getOr(n.length);return A.some({numColumns:e,numRows:Math.ceil(n.length/e)})}return A.none()},rw=e=>((e,t)=>ma([Mh(e,t)]))(Bi("unnamed-events"),e),aw="silver.readonly",iw=Nn([("readonly",ls("readonly",$n))]);const lw=(e,t)=>{const o=e.mainUi.outerContainer.element,n=[e.mainUi.mothership,...e.uiMotherships];t&&V(n,(e=>{e.broadcastOn([Eu()],{target:o})})),V(n,(e=>{e.broadcastOn([aw],{readonly:t})}))},cw=(e,t)=>{e.on("init",(()=>{e.mode.isReadOnly()&&lw(t,!0)})),e.on("SwitchMode",(()=>lw(t,e.mode.isReadOnly()))),Df(e)&&e.mode.set("readonly")},dw=()=>gc.config({channels:{[aw]:{schema:iw,onReceive:(e,t)=>{pg.set(e,t.readonly)}}}}),uw=e=>pg.config({disabled:e}),mw=e=>pg.config({disabled:e,disableClass:"tox-tbtn--disabled"}),gw=e=>pg.config({disabled:e,disableClass:"tox-tbtn--disabled",useNative:!1}),pw=(e,t)=>{const o=e.getApi(t);return e=>{e(o)}},hw=(e,t)=>ea((o=>{pw(e,o)((o=>{const n=e.onSetup(o);p(n)&&t.set(n)}))})),fw=(e,t)=>ta((o=>pw(e,o)(t.get()))),bw=(e,t)=>na(((o,n)=>{pw(e,o)(e.onAction),e.triggersSubmenu||t!==dy.CLOSE_ON_EXECUTE||(o.getSystem().isConnected()&&zr(o,yr()),n.stop())})),vw={[hr()]:["disabling","alloy.base.behaviour","toggling","item-events"]},yw=xe,xw=(e,t,o,n)=>{const s=on(b);return{type:"item",dom:t.dom,components:yw(t.optComponents),data:e.data,eventOrder:vw,hasSubmenu:e.triggersSubmenu,itemBehaviours:ma([Mh("item-events",[bw(e,o),hw(e,s),fw(e,s)]),(r=()=>!e.enabled||n.isDisabled(),pg.config({disabled:r,disableClass:"tox-collection__item--state-disabled"})),dw(),Ah.config({})].concat(e.itemBehaviours))};var r},ww=e=>({value:e.value,meta:{text:e.text.getOr(""),...e.meta}}),Sw=e=>{const t=Tf.os.isMacOS()||Tf.os.isiOS(),o=t?{alt:"\u2325",ctrl:"\u2303",shift:"\u21e7",meta:"\u2318",access:"\u2303\u2325"}:{meta:"Ctrl",access:"Shift+Alt"},n=e.split("+"),s=L(n,(e=>{const t=e.toLowerCase().trim();return be(o,t)?o[t]:e}));return t?s.join(""):s.join("+")},kw=(e,t,o=[fy])=>ry(e,{tag:"div",classes:o},t),Cw=e=>({dom:{tag:"div",classes:[by]},components:[ul(Kv.translate(e))]}),Ow=(e,t)=>({dom:{tag:"div",classes:t,innerHtml:e}}),_w=(e,t)=>({dom:{tag:"div",classes:[by]},components:[{dom:{tag:e.tag,styles:e.styles},components:[ul(Kv.translate(t))]}]}),Tw=e=>({dom:{tag:"div",classes:["tox-collection__item-accessory"]},components:[ul(Sw(e))]}),Ew=e=>kw("checkmark",e,["tox-collection__item-checkmark"]),Aw=e=>{const t=e.map((e=>({attributes:{id:Bi("menu-item"),"aria-label":Kv.translate(e)}}))).getOr({});return{tag:"div",classes:[uy,my],...t}},Mw=(e,t,o,n=A.none())=>"color"===e.presets?((e,t,o)=>{const n=e.value,s=e.iconContent.map((e=>((e,t,o)=>{const n=t();return ty(e,n).or(o).getOrThunk(Zv(n))})(e,t.icons,o))),r=e.ariaLabel.map((e=>({"aria-label":t.translate(e),"data-mce-name":e}))).getOr({});return{dom:(()=>{const e=gy,t=s.getOr(""),o={tag:"div",attributes:r,classes:[e]};return"custom"===n?{...o,tag:"button",classes:[...o.classes,"tox-swatches__picker-btn"],innerHtml:t}:"remove"===n?{...o,classes:[...o.classes,"tox-swatch--remove"],innerHtml:t}:g(n)?{...o,attributes:{...o.attributes,"data-mce-color":n},styles:{"background-color":n},innerHtml:t}:o})(),optComponents:[]}})(e,t,n):((e,t,o,n)=>{const s={tag:"div",classes:[fy]},r=o?e.iconContent.map((e=>ry(e,s,t.icons,n))).orThunk((()=>A.some({dom:s}))):A.none(),a=e.checkMark,i=A.from(e.meta).fold((()=>Cw),(e=>be(e,"style")?k(_w,e.style):Cw)),l=e.htmlContent.fold((()=>e.textContent.map(i)),(e=>A.some(Ow(e,[by]))));return{dom:Aw(e.ariaLabel),optComponents:[r,l,e.shortcutContent.map(Tw),a,e.caret]}})(e,t,o,n),Dw=(e,t,o)=>fe(e,"tooltipWorker").map((e=>[Zb.config({lazySink:t.getSink,tooltipDom:{tag:"div",classes:["tox-tooltip-worker-container"]},tooltipComponents:[],anchor:e=>({type:"submenu",item:e,overrides:{maxHeightFunction:Uc}}),mode:"follow-highlight",onShow:(t,o)=>{e((e=>{Zb.setComponents(t,[ml({element:ze(e)})])}))}})])).getOrThunk((()=>o.map((e=>[Zb.config({...t.providers.tooltips.getConfig({tooltipText:e}),mode:"follow-highlight"})])).getOr([]))),Bw=(e,t)=>{const o=(e=>Of.DOM.encode(e))(Kv.translate(e));if(t.length>0){const e=new RegExp((e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"))(t),"gi");return o.replace(e,(e=>`<span class="tox-autocompleter-highlight">${e}</span>`))}return o},Iw=(e,t)=>L(e,(e=>{switch(e.type){case"cardcontainer":return((e,t)=>{const o="vertical"===e.direction?"tox-collection__item-container--column":wy,n="left"===e.align?"tox-collection__item-container--align-left":"tox-collection__item-container--align-right";return{dom:{tag:"div",classes:[xy,o,n,(()=>{switch(e.valign){case"top":return"tox-collection__item-container--valign-top";case"middle":return"tox-collection__item-container--valign-middle";case"bottom":return"tox-collection__item-container--valign-bottom"}})()]},components:t}})(e,Iw(e.items,t));case"cardimage":return((e,t,o)=>({dom:{tag:"img",classes:t,attributes:{src:e,alt:o.getOr("")}}}))(e.src,e.classes,e.alt);case"cardtext":const o=e.name.exists((e=>F(t.cardText.highlightOn,e))),n=o?A.from(t.cardText.matchText).getOr(""):"";return Ow(Bw(e.text,n),e.classes)}})),Fw=Em(nf(),sf()),Rw=e=>({value:Vw(e)}),Nw=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,zw=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,Lw=e=>Nw.test(e)||zw.test(e),Vw=e=>Oe(e,"#").toUpperCase(),Hw=e=>{const t=e.toString(16);return(1===t.length?"0"+t:t).toUpperCase()},Pw=e=>{const t=Hw(e.red)+Hw(e.green)+Hw(e.blue);return Rw(t)},Uw=Math.min,Ww=Math.max,jw=Math.round,$w=/^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i,Gw=/^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i,qw=(e,t,o,n)=>({red:e,green:t,blue:o,alpha:n}),Yw=e=>{const t=parseInt(e,10);return t.toString()===e&&t>=0&&t<=255},Xw=e=>{let t,o,n;const s=(e.hue||0)%360;let r=e.saturation/100,a=e.value/100;if(r=Ww(0,Uw(r,1)),a=Ww(0,Uw(a,1)),0===r)return t=o=n=jw(255*a),qw(t,o,n,1);const i=s/60,l=a*r,c=l*(1-Math.abs(i%2-1)),d=a-l;switch(Math.floor(i)){case 0:t=l,o=c,n=0;break;case 1:t=c,o=l,n=0;break;case 2:t=0,o=l,n=c;break;case 3:t=0,o=c,n=l;break;case 4:t=c,o=0,n=l;break;case 5:t=l,o=0,n=c;break;default:t=o=n=0}return t=jw(255*(t+d)),o=jw(255*(o+d)),n=jw(255*(n+d)),qw(t,o,n,1)},Kw=e=>{const t=(e=>{const t=(e=>{const t=e.value.replace(Nw,((e,t,o,n)=>t+t+o+o+n+n));return{value:t}})(e),o=zw.exec(t.value);return null===o?["FFFFFF","FF","FF","FF"]:o})(e),o=parseInt(t[1],16),n=parseInt(t[2],16),s=parseInt(t[3],16);return qw(o,n,s,1)},Jw=(e,t,o,n)=>{const s=parseInt(e,10),r=parseInt(t,10),a=parseInt(o,10),i=parseFloat(n);return qw(s,r,a,i)},Qw=e=>{const t=$w.exec(e);if(null!==t)return A.some(Jw(t[1],t[2],t[3],"1"));const o=Gw.exec(e);return null!==o?A.some(Jw(o[1],o[2],o[3],o[4])):A.none()},Zw=e=>`rgba(${e.red},${e.green},${e.blue},${e.alpha})`,eS=qw(255,0,0,1),tS=(e,t)=>{e.dispatch("ResizeContent",t)},oS=(e,t)=>{e.dispatch("TextColorChange",t)},nS=(e,t)=>e.dispatch("ResolveName",{name:t.nodeName.toLowerCase(),target:t}),sS=(e,t)=>()=>{e(),t()},rS=e=>iS(e,"NodeChange",(t=>{t.setEnabled(e.selection.isEditable())})),aS=(e,t)=>o=>{const n=rS(e)(o),s=((e,t)=>o=>{const n=sn(),s=()=>{o.setActive(e.formatter.match(t));const s=e.formatter.formatChanged(t,o.setActive);n.set(s)};return e.initialized?s():e.once("init",s),()=>{e.off("init",s),n.clear()}})(e,t)(o);return()=>{n(),s()}},iS=(e,t,o)=>n=>{const s=()=>o(n),r=()=>{o(n),e.on(t,s)};return e.initialized?r():e.once("init",r),()=>{e.off("init",r),e.off(t,s)}},lS=e=>t=>()=>{e.undoManager.transact((()=>{e.focus(),e.execCommand("mceToggleFormat",!1,t.format)}))},cS=(e,t)=>()=>e.execCommand(t);var dS=tinymce.util.Tools.resolve("tinymce.util.LocalStorage");const uS={},mS=e=>fe(uS,e).getOrThunk((()=>{const t=`tinymce-custom-colors-${e}`,o=dS.getItem(t);if(m(o)){const e=dS.getItem("tinymce-custom-colors");dS.setItem(t,g(e)?e:"[]")}const n=((e,t=10)=>{const o=dS.getItem(e),n=r(o)?JSON.parse(o):[],s=t-(a=n).length<0?a.slice(0,t):a;var a;const i=e=>{s.splice(e,1)};return{add:o=>{((e,t)=>{const o=I(e,t);return-1===o?A.none():A.some(o)})(s,o).each(i),s.unshift(o),s.length>t&&s.pop(),dS.setItem(e,JSON.stringify(s))},state:()=>s.slice(0)}})(t,10);return uS[e]=n,n})),gS=(e,t)=>{mS(e).add(t)},pS=(e,t,o)=>({hue:e,saturation:t,value:o}),hS=e=>{let t=0,o=0,n=0;const s=e.red/255,r=e.green/255,a=e.blue/255,i=Math.min(s,Math.min(r,a)),l=Math.max(s,Math.max(r,a));return i===l?(n=i,pS(0,0,100*n)):(t=s===i?3:a===i?1:5,t=60*(t-(s===i?r-a:a===i?s-r:a-s)/(l-i)),o=(l-i)/l,n=l,pS(Math.round(t),Math.round(100*o),Math.round(100*n)))},fS=e=>Pw(Xw(e)),bS=e=>{return(t=e,Lw(t)?A.some({value:Vw(t)}):A.none()).orThunk((()=>Qw(e).map(Pw))).getOrThunk((()=>{const t=document.createElement("canvas");t.height=1,t.width=1;const o=t.getContext("2d");o.clearRect(0,0,t.width,t.height),o.fillStyle="#FFFFFF",o.fillStyle=e,o.fillRect(0,0,1,1);const n=o.getImageData(0,0,1,1).data,s=n[0],r=n[1],a=n[2],i=n[3];return Pw(qw(s,r,a,i))}));var t},vS="forecolor",yS="hilitecolor",xS=e=>{const t=[];for(let o=0;o<e.length;o+=2)t.push({text:e[o+1],value:"#"+bS(e[o]).value,icon:"checkmark",type:"choiceitem"});return t},wS=e=>t=>t.options.get(e),SS="#000000",kS=(e,t)=>t===vS&&e.options.isSet("color_map_foreground")?wS("color_map_foreground")(e):t===yS&&e.options.isSet("color_map_background")?wS("color_map_background")(e):wS("color_map")(e),CS=(e,t="default")=>Math.max(5,Math.ceil(Math.sqrt(kS(e,t).length))),OS=(e,t)=>{const o=wS("color_cols")(e),n=CS(e,t);return o===CS(e)?n:o},_S=(e,t="default")=>Math.round(t===vS?wS("color_cols_foreground")(e):t===yS?wS("color_cols_background")(e):wS("color_cols")(e)),TS=wS("custom_colors"),ES=wS("color_default_foreground"),AS=wS("color_default_background"),MS=(e,t)=>{const o=ze(e.selection.getStart()),n="hilitecolor"===t?Ls(o,(e=>{if($e(e)){const t=Rt(e,"background-color");return ke(Qw(t).exists((e=>0!==e.alpha)),t)}return A.none()})).getOr("rgba(0, 0, 0, 0)"):Rt(o,"color");return Qw(n).map((e=>"#"+Pw(e).value))},DS=e=>{const t="choiceitem",o={type:t,text:"Remove color",icon:"color-swatch-remove-color",value:"remove"};return e?[o,{type:t,text:"Custom color",icon:"color-picker",value:"custom"}]:[o]},BS=(e,t,o,n)=>{"custom"===o?PS(e)((o=>{o.each((o=>{gS(t,o),e.execCommand("mceApplyTextcolor",t,o),n(o)}))}),MS(e,t).getOr(SS)):"remove"===o?(n(""),e.execCommand("mceRemoveTextcolor",t)):(n(o),e.execCommand("mceApplyTextcolor",t,o))},IS=(e,t,o)=>e.concat((e=>L(mS(e).state(),(e=>({type:"choiceitem",text:e,icon:"checkmark",value:e}))))(t).concat(DS(o))),FS=(e,t,o)=>n=>{n(IS(e,t,o))},RS=(e,t,o)=>{const n="forecolor"===t?"tox-icon-text-color__color":"tox-icon-highlight-bg-color__color";e.setIconFill(n,o)},NS=(e,t)=>{e.setTooltip(t)},zS=(e,t)=>o=>{const n=MS(e,t);return ye(n,o.toUpperCase())},LS=(e,t,o)=>{if(De(o))return"forecolor"===t?"Text color":"Background color";const n="forecolor"===t?"Text color {0}":"Background color {0}",s=IS(kS(e,t),t,!1),r=j(s,(e=>e.value===o)).getOr({text:""}).text;return e.translate([n,e.translate(r)])},VS=(e,t,o,n)=>{e.ui.registry.addSplitButton(t,{tooltip:LS(e,o,n.get()),presets:"color",icon:"forecolor"===t?"text-color":"highlight-bg-color",select:zS(e,o),columns:_S(e,o),fetch:FS(kS(e,o),o,TS(e)),onAction:t=>{BS(e,o,n.get(),b)},onItemAction:(s,r)=>{BS(e,o,r,(o=>{n.set(o),oS(e,{name:t,color:o})}))},onSetup:s=>{RS(s,t,n.get());const r=n=>{n.name===t&&(RS(s,n.name,n.color),NS(s,LS(e,o,n.color)))};return e.on("TextColorChange",r),sS(rS(e)(s),(()=>{e.off("TextColorChange",r)}))}})},HS=(e,t,o,n,s)=>{e.ui.registry.addNestedMenuItem(t,{text:n,icon:"forecolor"===t?"text-color":"highlight-bg-color",onSetup:n=>(NS(n,LS(e,o,s.get())),RS(n,t,s.get()),rS(e)(n)),getSubmenuItems:()=>[{type:"fancymenuitem",fancytype:"colorswatch",select:zS(e,o),initData:{storageKey:o},onAction:n=>{BS(e,o,n.value,(o=>{s.set(o),oS(e,{name:t,color:o})}))}}]})},PS=e=>(t,o)=>{let n=!1;const s={colorpicker:o};e.windowManager.open({title:"Color Picker",size:"normal",body:{type:"panel",items:[{type:"colorpicker",name:"colorpicker",label:"Color"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:s,onAction:(e,t)=>{"hex-valid"===t.name&&(n=t.value)},onSubmit:o=>{const s=o.getData().colorpicker;n?(t(A.from(s)),o.close()):e.windowManager.alert(e.translate(["Invalid hex color code: {0}",s]))},onClose:b,onCancel:()=>{t(A.none())}})},US=(e,t,o,n,s,r,a,i)=>{const l=qy(t),c=WS(t,o,n,"color"!==s?"normal":"color",r,a,i);return Ky(e,l,c,n,{menuType:s})},WS=(e,t,o,n,s,r,a)=>xe(L(e,(i=>{return"choiceitem"===i.type?(l=i,Qn("choicemenuitem",Kx,l)).fold(Yy,(i=>A.some(((e,t,o,n,s,r,a,i=!0)=>{const l=Mw({presets:o,textContent:t?e.text:A.none(),htmlContent:A.none(),ariaLabel:e.text,iconContent:e.icon,shortcutContent:t?e.shortcut:A.none(),checkMark:t?A.some(Ew(a.icons)):A.none(),caret:A.none(),value:e.value},a,i),c=e.text.filter(x(!t)).map((e=>Zb.config(a.tooltips.getConfig({tooltipText:a.translate(e)}))));return wn(xw({data:ww(e),enabled:e.enabled,getApi:e=>({setActive:t=>{Wh.set(e,t)},isActive:()=>Wh.isOn(e),isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t)}),onAction:t=>n(e.value),onSetup:e=>(e.setActive(s),b),triggersSubmenu:!1,itemBehaviours:[...c.toArray()]},l,r,a),{toggling:{toggleClass:hy,toggleOnExecute:!1,selected:e.active,exclusive:!0}})})(i,1===o,n,t,r(i.value),s,a,qy(e))))):A.none();var l}))),jS=(e,t)=>{const o=Oy(t);return 1===e?{mode:"menu",moveOnTab:!0}:"auto"===e?{mode:"grid",selector:"."+o.item,initSize:{numColumns:1,numRows:1}}:{mode:"matrix",rowSelector:"."+("color"===t?"tox-swatches__row":"tox-collection__group"),previousSelector:e=>"color"===t?_l(e.element,"[aria-checked=true]"):A.none()}},$S=Bi("cell-over"),GS=Bi("cell-execute"),qS=(e,t,o)=>{const n=o=>Lr(o,GS,{row:e,col:t}),s=(e,t)=>{t.stop(),n(e)};return hl({dom:{tag:"div",attributes:{role:"button","aria-label":o}},behaviours:ma([Mh("insert-table-picker-cell",[Gr(Js(),Rh.focus),Gr(hr(),n),Gr(sr(),s),Gr(br(),s)]),Wh.config({toggleClass:"tox-insert-table-picker__selected",toggleOnExecute:!1}),Rh.config({onFocus:o=>Lr(o,$S,{row:e,col:t})})])})},YS=e=>q(e,(e=>L(e,fl))),XS=(e,t)=>ul(`${t}x${e}`),KS={inserttable:(e,t)=>{const o=(e=>(t,o)=>e.shared.providers.translate(["{0} columns, {1} rows",o,t]))(t),n=((e,t,o)=>{const n=[];for(let t=0;t<10;t++){const o=[];for(let n=0;n<10;n++){const s=e(t+1,n+1);o.push(qS(t,n,s))}n.push(o)}return n})(o),s=XS(0,0),r=Vb({dom:{tag:"span",classes:["tox-insert-table-picker__label"]},components:[s],behaviours:ma([Ah.config({})])});return{type:"widget",data:{value:Bi("widget-id")},dom:{tag:"div",classes:["tox-fancymenuitem"]},autofocus:!0,components:[Fw.widget({dom:{tag:"div",classes:["tox-insert-table-picker"]},components:YS(n).concat(r.asSpec()),behaviours:ma([Mh("insert-table-picker",[ea((e=>{Ah.set(r.get(e),[s])})),Kr($S,((e,t,o)=>{const{row:s,col:a}=o.event;((e,t,o,n,s)=>{for(let n=0;n<10;n++)for(let s=0;s<10;s++)Wh.set(e[n][s],n<=t&&s<=o)})(n,s,a),Ah.set(r.get(e),[XS(s+1,a+1)])})),Kr(GS,((t,o,n)=>{const{row:s,col:r}=n.event;e.onAction({numRows:s+1,numColumns:r+1}),zr(t,yr())}))]),xh.config({initSize:{numRows:10,numColumns:10},mode:"flatgrid",selector:'[role="button"]'})])})]}},colorswatch:(e,t)=>{const o=((e,t)=>{const o=e.initData.allowCustomColors&&t.colorinput.hasCustomColors();return e.initData.colors.fold((()=>IS(t.colorinput.getColors(e.initData.storageKey),e.initData.storageKey,o)),(e=>e.concat(DS(o))))})(e,t),n=t.colorinput.getColorCols(e.initData.storageKey),s="color",r={...US(Bi("menu-value"),o,(t=>{e.onAction({value:t})}),n,s,dy.CLOSE_ON_EXECUTE,e.select.getOr(T),t.shared.providers),markers:Oy(s),movement:jS(n,s),showMenuRole:!1};return{type:"widget",data:{value:Bi("widget-id")},dom:{tag:"div",classes:["tox-fancymenuitem"]},autofocus:!0,components:[Fw.widget(uf.sketch(r))]}}},JS=e=>({type:"separator",dom:{tag:"div",classes:[my,"tox-collection__group-heading"]},components:e.text.map(ul).toArray()});var QS=Object.freeze({__proto__:null,getCoupled:(e,t,o,n)=>o.getOrCreate(e,t,n),getExistingCoupled:(e,t,o,n)=>o.getExisting(e,t,n)}),ZS=[ls("others",Jn(dn.value,Pn()))],ek=Object.freeze({__proto__:null,init:()=>{const e={},t=(t,o)=>{if(0===re(t.others).length)throw new Error("Cannot find any known coupled components");return fe(e,o)},o=x({});return ua({readState:o,getExisting:(e,o,n)=>t(o,n).orThunk((()=>(fe(o.others,n).getOrDie("No information found for coupled component: "+n),A.none()))),getOrCreate:(o,n,s)=>t(n,s).getOrThunk((()=>{const t=fe(n.others,s).getOrDie("No information found for coupled component: "+s)(o),r=o.getSystem().build(t);return e[s]=r,r}))})}});const tk=pa({fields:ZS,name:"coupling",apis:QS,state:ek}),ok=e=>{let t=A.none(),o=[];const n=e=>{s()?r(e):o.push(e)},s=()=>t.isSome(),r=e=>{t.each((t=>{setTimeout((()=>{e(t)}),0)}))};return e((e=>{s()||(t=A.some(e),V(o,r),o=[])})),{get:n,map:e=>ok((t=>{n((o=>{t(e(o))}))})),isReady:s}},nk={nu:ok,pure:e=>ok((t=>{t(e)}))},sk=e=>{setTimeout((()=>{throw e}),0)},rk=e=>{const t=t=>{e().then(t,sk)};return{map:t=>rk((()=>e().then(t))),bind:t=>rk((()=>e().then((e=>t(e).toPromise())))),anonBind:t=>rk((()=>e().then((()=>t.toPromise())))),toLazy:()=>nk.nu(t),toCached:()=>{let t=null;return rk((()=>(null===t&&(t=e()),t)))},toPromise:e,get:t}},ak=e=>rk((()=>new Promise(e))),ik=e=>rk((()=>Promise.resolve(e))),lk=x("sink"),ck=x(km({name:lk(),overrides:x({dom:{tag:"div"},behaviours:ma([tu.config({useFixed:E})]),events:Wr([Jr(er()),Jr(qs()),Jr(sr())])})})),dk=(e,t)=>{const o=e.getHotspot(t).getOr(t),n="hotspot",s=e.getAnchorOverrides();return e.layouts.fold((()=>({type:n,hotspot:o,overrides:s})),(e=>({type:n,hotspot:o,overrides:s,layouts:e})))},uk=(e,t,o,n,s,r,a)=>{const i=((e,t,o,n,s,r,a)=>{const i=((e,t,o)=>(0,e.fetch)(o).map(t))(e,t,n),l=pk(n,e);return i.map((t=>t.bind((t=>{const i=t.menus[t.primary];return A.from(i).each((t=>{e.listRole.each((e=>{t.role=e}))})),A.from(xf.sketch({...r.menu(),uid:Vi(""),data:t,highlightOnOpen:a,onOpenMenu:(e,t)=>{const n=l().getOrDie();tu.position(n,t,{anchor:o}),Tu.decloak(s)},onOpenSubmenu:(e,t,o)=>{const n=l().getOrDie();tu.position(n,o,{anchor:{type:"submenu",item:t}}),Tu.decloak(s)},onRepositionMenu:(e,t,n)=>{const s=l().getOrDie();tu.position(s,t,{anchor:o}),V(n,(e=>{tu.position(s,e.triggeredMenu,{anchor:{type:"submenu",item:e.triggeringItem}})}))},onEscape:()=>(Rh.focus(n),Tu.close(s),A.some(!0))}))}))))})(e,t,dk(e,o),o,n,s,a);return i.map((e=>(e.fold((()=>{Tu.isOpen(n)&&Tu.close(n)}),(e=>{Tu.cloak(n),Tu.open(n,e),r(n)})),n)))},mk=(e,t,o,n,s,r,a)=>(Tu.close(n),ik(n)),gk=(e,t,o,n,s,r)=>{const a=tk.getCoupled(o,"sandbox");return(Tu.isOpen(a)?mk:uk)(e,t,o,a,n,s,r)},pk=(e,t)=>e.getSystem().getByUid(t.uid+"-"+lk()).map((e=>()=>dn.value(e))).getOrThunk((()=>t.lazySink.fold((()=>()=>dn.error(new Error("No internal sink is specified, nor could an external sink be found"))),(t=>()=>t(e))))),hk=e=>{Tu.getState(e).each((e=>{xf.repositionMenus(e)}))},fk=(e,t,o)=>{const n=Al(),s=pk(t,e);return{dom:{tag:"div",classes:e.sandboxClasses,attributes:{id:n.id}},behaviours:Qu(e.sandboxBehaviours,[qu.config({store:{mode:"memory",initialValue:t}}),Tu.config({onOpen:(s,r)=>{const a=dk(e,t);n.link(t.element),e.matchWidth&&((e,t,o)=>{const n=eg.getCurrent(t).getOr(t),s=Qt(e.element);o?Bt(n.element,"min-width",s+"px"):((e,t)=>{Jt.set(e,t)})(n.element,s)})(a.hotspot,r,e.useMinWidth),e.onOpen(a,s,r),void 0!==o&&void 0!==o.onOpen&&o.onOpen(s,r)},onClose:(e,r)=>{n.unlink(t.element),s().getOr(r).element.dom.dispatchEvent(new window.FocusEvent("focusout")),void 0!==o&&void 0!==o.onClose&&o.onClose(e,r)},isPartOf:(e,o,n)=>Ml(o,n)||Ml(t,n),getAttachPoint:()=>s().getOrDie()}),eg.config({find:e=>Tu.getState(e).bind((e=>eg.getCurrent(e)))}),gc.config({channels:{...Bu({isExtraPart:T}),...Fu({doReposition:hk})}})])}},bk=e=>{const t=tk.getCoupled(e,"sandbox");hk(t)},vk=()=>[Cs("sandboxClasses",[]),Ju("sandboxBehaviours",[eg,gc,Tu,qu])],yk=x([is("dom"),is("fetch"),xi("onOpen"),wi("onExecute"),Cs("getHotspot",A.some),Cs("getAnchorOverrides",x({})),ed(),Yu("dropdownBehaviours",[Wh,tk,xh,Rh]),is("toggleClass"),Cs("eventOrder",{}),fs("lazySink"),Cs("matchWidth",!1),Cs("useMinWidth",!1),fs("role"),fs("listRole")].concat(vk())),xk=x([Sm({schema:[bi(),Cs("fakeFocus",!1)],name:"menu",defaults:e=>({onExecute:e.onExecute})}),ck()]),wk=Km({name:"Dropdown",configFields:yk(),partFields:xk(),factory:(e,t,o,n)=>{const s=e=>{Tu.getState(e).each((e=>{xf.highlightPrimary(e)}))},r=(t,o,s)=>gk(e,w,t,n,o,s),a={expand:e=>{Wh.isOn(e)||r(e,b,vf.HighlightNone).get(b)},open:e=>{Wh.isOn(e)||r(e,b,vf.HighlightMenuAndItem).get(b)},refetch:t=>tk.getExistingCoupled(t,"sandbox").fold((()=>r(t,b,vf.HighlightMenuAndItem).map(b)),(o=>uk(e,w,t,o,n,b,vf.HighlightMenuAndItem).map(b))),isOpen:Wh.isOn,close:e=>{Wh.isOn(e)&&r(e,b,vf.HighlightMenuAndItem).get(b)},repositionMenus:e=>{Wh.isOn(e)&&bk(e)}},i=(e,t)=>(Vr(e),A.some(!0));return{uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.dropdownBehaviours,[Wh.config({toggleClass:e.toggleClass,aria:{mode:"expanded"}}),tk.config({others:{sandbox:t=>fk(e,t,{onOpen:()=>Wh.on(t),onClose:()=>Wh.off(t)})}}),xh.config({mode:"special",onSpace:i,onEnter:i,onDown:(e,t)=>{if(wk.isOpen(e)){const t=tk.getCoupled(e,"sandbox");s(t)}else wk.open(e);return A.some(!0)},onEscape:(e,t)=>wk.isOpen(e)?(wk.close(e),A.some(!0)):A.none()}),Rh.config({})]),events:$h(A.some((e=>{r(e,s,vf.HighlightMenuAndItem).get(b)}))),eventOrder:{...e.eventOrder,[hr()]:["disabling","toggling","alloy.base.behaviour"]},apis:a,domModification:{attributes:{"aria-haspopup":e.listRole.getOr("true"),...e.role.fold((()=>({})),(e=>({role:e}))),..."button"===e.dom.tag?{type:("type",fe(e.dom,"attributes").bind((e=>fe(e,"type")))).getOr("button")}:{}}}}},apis:{open:(e,t)=>e.open(t),refetch:(e,t)=>e.refetch(t),expand:(e,t)=>e.expand(t),close:(e,t)=>e.close(t),isOpen:(e,t)=>e.isOpen(t),repositionMenus:(e,t)=>e.repositionMenus(t)}}),Sk=(e,t,o)=>{Ly(e).each((e=>{var n;((e,t)=>{Tt(t.element,"id").each((t=>Ct(e.element,"aria-activedescendant",t)))})(e,o),(_a((n=t).element,Py)?A.some(n.element):_l(n.element,"."+Py)).each((t=>{Tt(t,"id").each((t=>Ct(e.element,"aria-controls",t)))}))})),Ct(o.element,"aria-selected","true")},kk=(e,t,o)=>{Ct(o.element,"aria-selected","false")},Ck=e=>tk.getExistingCoupled(e,"sandbox").bind(zy).map(Vy).map((e=>e.fetchPattern)).getOr("");var Ok;!function(e){e[e.ContentFocus=0]="ContentFocus",e[e.UiFocus=1]="UiFocus"}(Ok||(Ok={}));const _k=(e,t,o,n,s)=>{const r=o.shared.providers,a=e=>s?{...e,shortcut:A.none(),icon:e.text.isSome()?A.none():e.icon}:e;switch(e.type){case"menuitem":return(i=e,Qn("menuitem",tw,i)).fold(Yy,(e=>A.some(((e,t,o,n=!0)=>{const s=Mw({presets:"normal",iconContent:e.icon,textContent:e.text,htmlContent:A.none(),ariaLabel:e.text,caret:A.none(),checkMark:A.none(),shortcutContent:e.shortcut},o,n);return xw({data:ww(e),getApi:e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t)}),enabled:e.enabled,onAction:e.onAction,onSetup:e.onSetup,triggersSubmenu:!1,itemBehaviours:[]},s,t,o)})(a(e),t,r,n))));case"nestedmenuitem":return(e=>Qn("nestedmenuitem",ow,e))(e).fold(Yy,(e=>A.some(((e,t,o,n=!0,s=!1)=>{const r=s?(a=o.icons,kw("chevron-down",a,[vy])):(e=>kw("chevron-right",e,[vy]))(o.icons);var a;const i=Mw({presets:"normal",iconContent:e.icon,textContent:e.text,htmlContent:A.none(),ariaLabel:e.text,caret:A.some(r),checkMark:A.none(),shortcutContent:e.shortcut},o,n);return xw({data:ww(e),getApi:e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t),setIconFill:(t,o)=>{_l(e.element,`svg path[class="${t}"], rect[class="${t}"]`).each((e=>{Ct(e,"fill",o)}))},setTooltip:t=>{const n=o.translate(t);Ct(e.element,"aria-label",n)}}),enabled:e.enabled,onAction:b,onSetup:e.onSetup,triggersSubmenu:!0,itemBehaviours:[]},i,t,o)})(a(e),t,r,n,s))));case"togglemenuitem":return(e=>Qn("togglemenuitem",nw,e))(e).fold(Yy,(e=>A.some(((e,t,o,n=!0)=>{const s=Mw({iconContent:e.icon,textContent:e.text,htmlContent:A.none(),ariaLabel:e.text,checkMark:A.some(Ew(o.icons)),caret:A.none(),shortcutContent:e.shortcut,presets:"normal",meta:e.meta},o,n);return wn(xw({data:ww(e),enabled:e.enabled,getApi:e=>({setActive:t=>{Wh.set(e,t)},isActive:()=>Wh.isOn(e),isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t)}),onAction:e.onAction,onSetup:e.onSetup,triggersSubmenu:!1,itemBehaviours:[]},s,t,o),{toggling:{toggleClass:hy,toggleOnExecute:!1,selected:e.active},role:e.role.getOrUndefined()})})(a(e),t,r,n))));case"separator":return(e=>Qn("separatormenuitem",_x,e))(e).fold(Yy,(e=>A.some(JS(e))));case"fancymenuitem":return(e=>Qn("fancymenuitem",ew,e))(e).fold(Yy,(e=>((e,t)=>fe(KS,e.fancytype).map((o=>o(e,t))))(e,o)));default:return console.error("Unknown item in general menu",e),A.none()}var i},Tk=(e,t,o,n,s,r,a)=>{const i=1===n,l=!i||qy(e);return xe(L(e,(e=>{switch(e.type){case"separator":return(n=e,Qn("Autocompleter.Separator",_x,n)).fold(Yy,(e=>A.some(JS(e))));case"cardmenuitem":return(e=>Qn("cardmenuitem",Xx,e))(e).fold(Yy,(e=>A.some(((e,t,o,n)=>{const s={dom:Aw(e.label),optComponents:[A.some({dom:{tag:"div",classes:[xy,wy]},components:Iw(e.items,n)})]};return xw({data:ww({text:A.none(),...e}),enabled:e.enabled,getApi:e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>{pg.set(e,!t),V(Td(e.element,"*"),(o=>{e.getSystem().getByDom(o).each((e=>{e.hasConfigured(pg)&&pg.set(e,!t)}))}))}}),onAction:e.onAction,onSetup:e.onSetup,triggersSubmenu:!1,itemBehaviours:A.from(n.itemBehaviours).getOr([])},s,t,o.providers)})({...e,onAction:t=>{e.onAction(t),o(e.value,e.meta)}},s,r,{itemBehaviours:Dw(e.meta,r,A.none()),cardText:{matchText:t,highlightOn:a}}))));default:return(e=>Qn("Autocompleter.Item",Tx,e))(e).fold(Yy,(e=>A.some(((e,t,o,n,s,r,a,i=!0)=>{const l=Mw({presets:n,textContent:A.none(),htmlContent:o?e.text.map((e=>Bw(e,t))):A.none(),ariaLabel:e.text,iconContent:e.icon,shortcutContent:A.none(),checkMark:A.none(),caret:A.none(),value:e.value},a.providers,i,e.icon),c=e.text.filter((e=>!o&&""!==e));return xw({data:ww(e),enabled:e.enabled,getApi:x({}),onAction:t=>s(e.value,e.meta),onSetup:x(b),triggersSubmenu:!1,itemBehaviours:Dw(e,a,c)},l,r,a.providers)})(e,t,i,"normal",o,s,r,l))))}var n})))},Ek=(e,t,o,n,s,r)=>{const a=qy(t),i=xe(L(t,(e=>{const t=e=>_k(e,o,n,(e=>s?!be(e,"text"):a)(e),s);return"nestedmenuitem"===e.type&&e.getSubmenuItems().length<=0?t({...e,enabled:!1}):t(e)}))),l=(e=>"no-search"===e.searchMode?{menuType:"normal"}:{menuType:"searchable",searchMode:e})(r);return(s?Xy:Ky)(e,a,i,1,l)},Ak=e=>xf.singleData(e.value,e),Mk=e=>hd(ze(e.startContainer),e.startOffset,ze(e.endContainer),e.endOffset),Dk=(e,t)=>{const o=Bi("autocompleter"),n=on(!1),s=on(!1),r=rn(),a=hl(wf.sketch({dom:{tag:"div",classes:["tox-autocompleter"],attributes:{id:o}},components:[],fireDismissalEventInstead:{},inlineBehaviours:ma([Mh("dismissAutocompleter",[Gr(Er(),(()=>u())),Gr(Rr(),((t,o)=>{Tt(o.event.target,"id").each((t=>Ct(ze(e.getBody()),"aria-activedescendant",t)))}))])]),lazySink:t.getSink})),i=()=>wf.isOpen(a),l=s.get,c=()=>{if(i()){wf.hide(a),e.dom.remove(o,!1);const t=ze(e.getBody());Tt(t,"aria-owns").filter((e=>e===o)).each((()=>{At(t,"aria-owns"),At(t,"aria-activedescendant")}))}},d=()=>wf.getContent(a).bind((e=>ee(e.components(),0))),u=()=>e.execCommand("mceAutocompleterClose"),m=s=>{const i=(o=>{const s=se(o,(e=>A.from(e.columns))).getOr(1);return q(o,(o=>{const a=o.items;return Tk(a,o.matchText,((t,s)=>{const a={hide:()=>u(),reload:t=>{c(),e.execCommand("mceAutocompleterReload",!1,{fetchOptions:t})}};e.execCommand("mceAutocompleterRefreshActiveRange"),r.get().each((e=>{n.set(!0),o.onAction(a,e,t,s),n.set(!1)}))}),s,dy.BUBBLE_TO_SANDBOX,t,o.highlightOn)}))})(s);i.length>0?(((t,o)=>{const n=se(t,(e=>A.from(e.columns))).getOr(1);wf.showMenuAt(a,{anchor:{type:"selection",getSelection:()=>r.get().map(Mk),root:ze(e.getBody())}},((e,t,o,n)=>{const s=jS(t,n),r=Oy(n);return{data:Ak({...e,movement:s,menuBehaviours:rw("auto"!==t?[]:[ea(((e,t)=>{sw(e,4,r.item).each((({numColumns:t,numRows:o})=>{xh.setGridSize(e,o,t)}))}))])}),menu:{markers:Oy(n),fakeFocus:o===Ok.ContentFocus}}})(Ky("autocompleter-value",!0,o,n,{menuType:"normal"}),n,Ok.ContentFocus,"normal")),d().each(Cg.highlightFirst)})(s,i),Ct(ze(e.getBody()),"aria-owns",o),e.inline||g()):c()},g=()=>{e.dom.get(o)&&e.dom.remove(o,!1);const t=e.getDoc().documentElement,n=e.selection.getNode(),s=(e=>ai(e,!0))(a.element);It(s,{border:"0",clip:"rect(0 0 0 0)",height:"1px",margin:"-1px",overflow:"hidden",padding:"0",position:"absolute",width:"1px",top:`${n.offsetTop}px`,left:`${n.offsetLeft}px`}),e.dom.add(t,s.dom),_l(s,'[role="menu"]').each((e=>{Ht(e,"position"),Ht(e,"max-height")}))};e.on("AutocompleterStart",(({lookupData:e})=>{s.set(!0),n.set(!1),m(e)})),e.on("AutocompleterUpdate",(({lookupData:e})=>m(e))),e.on("AutocompleterUpdateActiveRange",(({range:e})=>r.set(e))),e.on("AutocompleterEnd",(()=>{c(),s.set(!1),n.set(!1),r.clear()}));((e,t)=>{const o=(e,t)=>{Lr(e,er(),{raw:t})},n=()=>e.getMenu().bind(Cg.getHighlighted);t.on("keydown",(t=>{const s=t.which;e.isActive()&&(e.isMenuOpen()?13===s?(n().each(Vr),t.preventDefault()):40===s?(n().fold((()=>{e.getMenu().each(Cg.highlightFirst)}),(e=>{o(e,t)})),t.preventDefault(),t.stopImmediatePropagation()):37!==s&&38!==s&&39!==s||n().each((e=>{o(e,t),t.preventDefault(),t.stopImmediatePropagation()})):13!==s&&38!==s&&40!==s||e.cancelIfNecessary())})),t.on("NodeChange",(()=>{!e.isActive()||e.isProcessingAction()||t.queryCommandState("mceAutoCompleterInRange")||e.cancelIfNecessary()}))})({cancelIfNecessary:u,isMenuOpen:i,isActive:l,isProcessingAction:n.get,getMenu:d},e)},Bk=(e,t,o)=>Tl(e,t,o).isSome(),Ik=(e,t)=>{let o=null;return{cancel:()=>{null!==o&&(clearTimeout(o),o=null)},schedule:(...n)=>{o=setTimeout((()=>{e.apply(null,n),o=null}),t)}}},Fk=e=>{const t=e.raw;return void 0===t.touches||1!==t.touches.length?A.none():A.some(t.touches[0])},Rk=(e,t)=>{const o={stopBackspace:!0,...t},n=(e=>{const t=rn(),o=on(!1),n=Ik((t=>{e.triggerEvent(vr(),t),o.set(!0)}),400),s=Rs([{key:Ws(),value:e=>(Fk(e).each((s=>{n.cancel();const r={x:s.clientX,y:s.clientY,target:e.target};n.schedule(e),o.set(!1),t.set(r)})),A.none())},{key:js(),value:e=>(n.cancel(),Fk(e).each((e=>{t.on((o=>{((e,t)=>{const o=Math.abs(e.clientX-t.x),n=Math.abs(e.clientY-t.y);return o>5||n>5})(e,o)&&t.clear()}))})),A.none())},{key:$s(),value:s=>(n.cancel(),t.get().filter((e=>Ze(e.target,s.target))).map((t=>o.get()?(s.prevent(),!1):e.triggerEvent(br(),s))))}]);return{fireIfReady:(e,t)=>fe(s,t).bind((t=>t(e)))}})(o),s=L(["touchstart","touchmove","touchend","touchcancel","gesturestart","mousedown","mouseup","mouseover","mousemove","mouseout","click"].concat(["selectstart","input","contextmenu","change","transitionend","transitioncancel","drag","dragstart","dragend","dragenter","dragleave","dragover","drop","keyup"]),(t=>Fc(e,t,(e=>{n.fireIfReady(e,t).each((t=>{t&&e.kill()})),o.triggerEvent(t,e)&&e.kill()})))),r=rn(),a=Fc(e,"paste",(e=>{n.fireIfReady(e,"paste").each((t=>{t&&e.kill()})),o.triggerEvent("paste",e)&&e.kill(),r.set(setTimeout((()=>{o.triggerEvent(gr(),e)}),0))})),i=Fc(e,"keydown",(e=>{o.triggerEvent("keydown",e)?e.kill():o.stopBackspace&&(e=>e.raw.which===Og[0]&&!F(["input","textarea"],Ue(e.target))&&!Bk(e.target,'[contenteditable="true"]'))(e)&&e.prevent()})),l=Fc(e,"focusin",(e=>{o.triggerEvent("focusin",e)&&e.kill()})),c=rn(),d=Fc(e,"focusout",(e=>{o.triggerEvent("focusout",e)&&e.kill(),c.set(setTimeout((()=>{o.triggerEvent(mr(),e)}),0))}));return{unbind:()=>{V(s,(e=>{e.unbind()})),i.unbind(),l.unbind(),d.unbind(),a.unbind(),r.on(clearTimeout),c.on(clearTimeout)}}},Nk=(e,t)=>{const o=fe(e,"target").getOr(t);return on(o)},zk=Is([{stopped:[]},{resume:["element"]},{complete:[]}]),Lk=(e,t,o,n,s,r)=>{const a=e(t,n),i=((e,t)=>{const o=on(!1),n=on(!1);return{stop:()=>{o.set(!0)},cut:()=>{n.set(!0)},isStopped:o.get,isCut:n.get,event:e,setSource:t.set,getSource:t.get}})(o,s);return a.fold((()=>(r.logEventNoHandlers(t,n),zk.complete())),(e=>{const o=e.descHandler;return Yi(o)(i),i.isStopped()?(r.logEventStopped(t,e.element,o.purpose),zk.stopped()):i.isCut()?(r.logEventCut(t,e.element,o.purpose),zk.complete()):rt(e.element).fold((()=>(r.logNoParent(t,e.element,o.purpose),zk.complete())),(n=>(r.logEventResponse(t,e.element,o.purpose),zk.resume(n))))}))},Vk=(e,t,o,n,s,r)=>Lk(e,t,o,n,s,r).fold(E,(n=>Vk(e,t,o,n,s,r)),T),Hk=(e,t,o,n,s)=>{const r=Nk(o,n);return Vk(e,t,o,n,r,s)},Pk=()=>{const e=(()=>{const e={};return{registerId:(t,o,n)=>{ie(n,((n,s)=>{const r=void 0!==e[s]?e[s]:{};r[o]=((e,t)=>({cHandler:k.apply(void 0,[e.handler].concat(t)),purpose:e.purpose}))(n,t),e[s]=r}))},unregisterId:t=>{ie(e,((e,o)=>{be(e,t)&&delete e[t]}))},filterByType:t=>fe(e,t).map((e=>ge(e,((e,t)=>((e,t)=>({id:e,descHandler:t}))(t,e))))).getOr([]),find:(t,o,n)=>fe(e,o).bind((e=>Ls(n,(t=>((e,t)=>Li(t).bind((t=>fe(e,t))).map((e=>((e,t)=>({element:e,descHandler:t}))(t,e))))(e,t)),t)))}})(),t={},o=o=>{Li(o.element).each((o=>{delete t[o],e.unregisterId(o)}))};return{find:(t,o,n)=>e.find(t,o,n),filter:t=>e.filterByType(t),register:n=>{const s=(e=>{const t=e.element;return Li(t).getOrThunk((()=>((e,t)=>{const o=Bi(Ri+"uid-");return zi(t,o),o})(0,e.element)))})(n);ve(t,s)&&((e,n)=>{const s=t[n];if(s!==e)throw new Error('The tagId "'+n+'" is already used by: '+ii(s.element)+"\nCannot use it for: "+ii(e.element)+"\nThe conflicting element is"+(xt(s.element)?" ":" not ")+"already in the DOM");o(e)})(n,s);const r=[n];e.registerId(r,s,n.events),t[s]=n},unregister:o,getById:e=>fe(t,e)}},Uk=Xm({name:"Container",factory:e=>{const{attributes:t,...o}=e.dom;return{uid:e.uid,dom:{tag:"div",attributes:{role:"presentation",...t},...o},components:e.components,behaviours:Xu(e.containerBehaviours),events:e.events,domModification:e.domModification,eventOrder:e.eventOrder}},configFields:[Cs("components",[]),Yu("containerBehaviours",[]),Cs("events",{}),Cs("domModification",{}),Cs("eventOrder",{})]}),Wk=e=>{const t=t=>rt(e.element).fold(E,(e=>Ze(t,e))),o=Pk(),n=(e,n)=>o.find(t,e,n),s=Rk(e.element,{triggerEvent:(e,t)=>ui(e,t.target,(o=>((e,t,o,n)=>Hk(e,t,o,o.target,n))(n,e,t,o)))}),r={debugInfo:x("real"),triggerEvent:(e,t,o)=>{ui(e,t,(s=>Hk(n,e,o,t,s)))},triggerFocus:(e,t)=>{Li(e).fold((()=>{hc(e)}),(o=>{ui(ur(),e,(o=>(((e,t,o,n,s)=>{const r=Nk(o,n);Lk(e,t,o,n,r,s)})(n,ur(),{originator:t,kill:b,prevent:b,target:e},e,o),!1)))}))},triggerEscape:(e,t)=>{r.triggerEvent("keydown",e.element,t.event)},getByUid:e=>p(e),getByDom:e=>h(e),build:hl,buildOrPatch:pl,addToGui:e=>{l(e)},removeFromGui:e=>{c(e)},addToWorld:e=>{a(e)},removeFromWorld:e=>{i(e)},broadcast:e=>{u(e)},broadcastOn:(e,t)=>{m(e,t)},broadcastEvent:(e,t)=>{g(e,t)},isConnected:E},a=e=>{e.connect(r),Ge(e.element)||(o.register(e),V(e.components(),a),r.triggerEvent(wr(),e.element,{target:e.element}))},i=e=>{Ge(e.element)||(V(e.components(),i),o.unregister(e)),e.disconnect()},l=t=>{lu(e,t)},c=e=>{uu(e)},d=e=>{const t=o.filter(pr());V(t,(t=>{const o=t.descHandler;Yi(o)(e)}))},u=e=>{d({universal:!0,data:e})},m=(e,t)=>{d({universal:!1,channels:e,data:t})},g=(e,t)=>((e,t,o)=>{const n=(e=>{const t=on(!1);return{stop:()=>{t.set(!0)},cut:b,isStopped:t.get,isCut:T,event:e,setSource:O("Cannot set source of a broadcasted event"),getSource:O("Cannot get source of a broadcasted event")}})(t);return V(e,(e=>{const t=e.descHandler;Yi(t)(n)})),n.isStopped()})(o.filter(e),t),p=e=>o.getById(e).fold((()=>dn.error(new Error('Could not find component with uid: "'+e+'" in system.'))),dn.value),h=e=>{const t=Li(e).getOr("not found");return p(t)};return a(e),{root:e,element:e.element,destroy:()=>{s.unbind(),Uo(e.element)},add:l,remove:c,getByUid:p,getByDom:h,addToWorld:a,removeFromWorld:i,broadcast:u,broadcastOn:m,broadcastEvent:g}},jk=x([Cs("prefix","form-field"),Yu("fieldBehaviours",[eg,qu])]),$k=x([km({schema:[is("dom")],name:"label"}),km({factory:{sketch:e=>({uid:e.uid,dom:{tag:"span",styles:{display:"none"},attributes:{"aria-hidden":"true"},innerHtml:e.text}})},schema:[is("text")],name:"aria-descriptor"}),wm({factory:{sketch:e=>{const t=((e,t)=>{const o={};return ie(e,((e,n)=>{F(t,n)||(o[n]=e)})),o})(e,["factory"]);return e.factory.sketch(t)}},schema:[is("factory")],name:"field"})]),Gk=Km({name:"FormField",configFields:jk(),partFields:$k(),factory:(e,t,o,n)=>{const s=Ku(e.fieldBehaviours,[eg.config({find:t=>Rm(t,e,"field")}),qu.config({store:{mode:"manual",getValue:e=>eg.getCurrent(e).bind(qu.getValue),setValue:(e,t)=>{eg.getCurrent(e).each((e=>{qu.setValue(e,t)}))}}})]),r=Wr([ea(((t,o)=>{const n=zm(t,e,["label","field","aria-descriptor"]);n.field().each((t=>{const o=Bi(e.prefix);n.label().each((e=>{Ct(e.element,"for",o),Ct(t.element,"id",o)})),n["aria-descriptor"]().each((o=>{const n=Bi(e.prefix);Ct(o.element,"id",n),Ct(t.element,"aria-describedby",n)}))}))}))]),a={getField:t=>Rm(t,e,"field"),getLabel:t=>Rm(t,e,"label")};return{uid:e.uid,dom:e.dom,components:t,behaviours:s,events:r,apis:a}},apis:{getField:(e,t)=>e.getField(t),getLabel:(e,t)=>e.getLabel(t)}});var qk=tinymce.util.Tools.resolve("tinymce.html.Entities");const Yk=(e,t,o,n)=>{const s=Xk(e,t,o,n);return Gk.sketch(s)},Xk=(e,t,o,n)=>({dom:Kk(o),components:e.toArray().concat([t]),fieldBehaviours:ma(n)}),Kk=e=>({tag:"div",classes:["tox-form__group"].concat(e)}),Jk=(e,t)=>Gk.parts.label({dom:{tag:"label",classes:["tox-label"]},components:[ul(t.translate(e))]}),Qk=Bi("form-component-change"),Zk=Bi("form-close"),eC=Bi("form-cancel"),tC=Bi("form-action"),oC=Bi("form-submit"),nC=Bi("form-block"),sC=Bi("form-unblock"),rC=Bi("form-tabchange"),aC=Bi("form-resize"),iC=(e,t,o)=>{const n=e.label.map((e=>Jk(e,t))),s=t.icons(),r=e=>(t,o)=>{Tl(o.event.target,"[data-collection-item-value]").each((n=>{e(t,o,n,_t(n,"data-collection-item-value"))}))},a=r(((o,n,s,r)=>{n.stop(),t.isDisabled()||Lr(o,tC,{name:e.name,value:r})})),i=[Gr(Js(),r(((e,t,o)=>{hc(o)}))),Gr(sr(),a),Gr(br(),a),Gr(Qs(),r(((e,t,o)=>{_l(e.element,"."+yy).each((e=>{Oa(e,yy)})),ka(o,yy)}))),Gr(Zs(),r((e=>{_l(e.element,"."+yy).each((e=>{Oa(e,yy),fc(e)}))}))),na(r(((t,o,n,s)=>{Lr(t,tC,{name:e.name,value:s})})))],l=(e,t)=>L(Td(e.element,".tox-collection__item"),t),c=Gk.parts.field({dom:{tag:"div",classes:["tox-collection"].concat(1!==e.columns?["tox-collection--grid"]:["tox-collection--list"])},components:[],factory:{sketch:w},behaviours:ma([pg.config({disabled:t.isDisabled,onDisabled:e=>{l(e,(e=>{ka(e,"tox-collection__item--state-disabled"),Ct(e,"aria-disabled",!0)}))},onEnabled:e=>{l(e,(e=>{Oa(e,"tox-collection__item--state-disabled"),At(e,"aria-disabled")}))}}),dw(),Ah.config({}),Zb.config({...t.tooltips.getConfig({tooltipText:"",onShow:e=>{_l(e.element,"."+yy+"[data-mce-tooltip]").each((o=>{Tt(o,"data-mce-tooltip").each((o=>{Zb.setComponents(e,t.tooltips.getComponents({tooltipText:o}))}))}))}}),mode:"children-keyboard-focus",anchor:e=>({type:"node",node:_l(e.element,"."+yy).orThunk((()=>Qe(".tox-collection__item"))),root:e.element,layouts:{onLtr:x([oc,tc,Jl,Zl,Ql,ec]),onRtl:x([oc,tc,Jl,Zl,Ql,ec])},bubble:Gc(0,-2,{})})}),qu.config({store:{mode:"memory",initialValue:o.getOr([])},onSetValue:(o,n)=>{((o,n)=>{const r=L(n,(o=>{const n=Kv.translate(o.text),r=1===e.columns?`<div class="tox-collection__item-label">${n}</div>`:"",a=`<div class="tox-collection__item-icon">${(e=>{var t;return null!==(t=s[e])&&void 0!==t?t:e})(o.icon)}</div>`,i={_:" "," - ":" ","-":" "},l=n.replace(/\_| \- |\-/g,(e=>i[e]));return`<div data-mce-tooltip="${l}" class="tox-collection__item${t.isDisabled()?" tox-collection__item--state-disabled":""}" tabindex="-1" data-collection-item-value="${qk.encodeAllRaw(o.value)}" aria-label="${l}">${a}${r}</div>`})),a="auto"!==e.columns&&e.columns>1?z(r,e.columns):[r],i=L(a,(e=>`<div class="tox-collection__group">${e.join("")}</div>`));ri(o.element,i.join(""))})(o,n),"auto"===e.columns&&sw(o,5,"tox-collection__item").each((({numRows:e,numColumns:t})=>{xh.setGridSize(o,e,t)})),zr(o,aC)}}),Ub.config({}),xh.config((d=e.columns,"normal",1===d?{mode:"menu",moveOnTab:!1,selector:".tox-collection__item"}:"auto"===d?{mode:"flatgrid",selector:".tox-collection__item",initSize:{numColumns:1,numRows:1}}:{mode:"matrix",selectors:{row:".tox-collection__group",cell:`.${my}`}})),Mh("collection-events",i)]),eventOrder:{[hr()]:["disabling","alloy.base.behaviour","collection-events"],[Qs()]:["collection-events","tooltipping"]}});var d;return Yk(n,c,["tox-form__group--collection"],[])},lC=["input","textarea"],cC=e=>{const t=Ue(e);return F(lC,t)},dC=(e,t)=>{const o=t.getRoot(e).getOr(e.element);Oa(o,t.invalidClass),t.notify.each((t=>{cC(e.element)&&Ct(e.element,"aria-invalid",!1),t.getContainer(e).each((e=>{ri(e,t.validHtml)})),t.onValid(e)}))},uC=(e,t,o,n)=>{const s=t.getRoot(e).getOr(e.element);ka(s,t.invalidClass),t.notify.each((t=>{cC(e.element)&&Ct(e.element,"aria-invalid",!0),t.getContainer(e).each((e=>{ri(e,n)})),t.onInvalid(e,n)}))},mC=(e,t,o)=>t.validator.fold((()=>ik(dn.value(!0))),(t=>t.validate(e))),gC=(e,t,o)=>(t.notify.each((t=>{t.onValidate(e)})),mC(e,t).map((o=>e.getSystem().isConnected()?o.fold((o=>(uC(e,t,0,o),dn.error(o))),(o=>(dC(e,t),dn.value(o)))):dn.error("No longer in system"))));var pC=Object.freeze({__proto__:null,markValid:dC,markInvalid:uC,query:mC,run:gC,isInvalid:(e,t)=>{const o=t.getRoot(e).getOr(e.element);return _a(o,t.invalidClass)}}),hC=Object.freeze({__proto__:null,events:(e,t)=>e.validator.map((t=>Wr([Gr(t.onEvent,(t=>{gC(t,e).get(w)}))].concat(t.validateOnLoad?[ea((t=>{gC(t,e).get(b)}))]:[])))).getOr({})}),fC=[is("invalidClass"),Cs("getRoot",A.none),ks("notify",[Cs("aria","alert"),Cs("getContainer",A.none),Cs("validHtml",""),xi("onValid"),xi("onInvalid"),xi("onValidate")]),ks("validator",[is("validate"),Cs("onEvent","input"),Cs("validateOnLoad",!0)])];const bC=pa({fields:fC,name:"invalidating",active:hC,apis:pC,extra:{validation:e=>t=>{const o=qu.getValue(t);return ik(e(o))}}}),vC=pa({fields:[],name:"unselecting",active:Object.freeze({__proto__:null,events:()=>Wr([jr(lr(),E)]),exhibit:()=>aa({styles:{"-webkit-user-select":"none","user-select":"none","-ms-user-select":"none","-moz-user-select":"-moz-none"},attributes:{unselectable:"on"}})})}),yC=Bi("color-input-change"),xC=Bi("color-swatch-change"),wC=Bi("color-picker-cancel"),SC=km({schema:[is("dom")],name:"label"}),kC=e=>km({name:e+"-edge",overrides:t=>t.model.manager.edgeActions[e].fold((()=>({})),(e=>({events:Wr([qr(Ws(),((t,o,n)=>e(t,n)),[t]),qr(qs(),((t,o,n)=>e(t,n)),[t]),qr(Ys(),((t,o,n)=>{n.mouseIsDown.get()&&e(t,n)}),[t])])})))}),CC=kC("top-left"),OC=kC("top"),_C=kC("top-right"),TC=kC("right"),EC=kC("bottom-right"),AC=kC("bottom"),MC=kC("bottom-left"),DC=kC("left"),BC=wm({name:"thumb",defaults:x({dom:{styles:{position:"absolute"}}}),overrides:e=>({events:Wr([Xr(Ws(),e,"spectrum"),Xr(js(),e,"spectrum"),Xr($s(),e,"spectrum"),Xr(qs(),e,"spectrum"),Xr(Ys(),e,"spectrum"),Xr(Ks(),e,"spectrum")])})}),IC=e=>Hg(e.event);var FC=[SC,DC,TC,OC,AC,CC,_C,MC,EC,BC,wm({schema:[rs("mouseIsDown",(()=>on(!1)))],name:"spectrum",overrides:e=>{const t=e.model.manager,o=(o,n)=>t.getValueFromEvent(n).map((n=>t.setValueFrom(o,e,n)));return{behaviours:ma([xh.config({mode:"special",onLeft:(o,n)=>t.onLeft(o,e,IC(n)),onRight:(o,n)=>t.onRight(o,e,IC(n)),onUp:(o,n)=>t.onUp(o,e,IC(n)),onDown:(o,n)=>t.onDown(o,e,IC(n))}),Ub.config({}),Rh.config({})]),events:Wr([Gr(Ws(),o),Gr(js(),o),Gr(qs(),o),Gr(Ys(),((t,n)=>{e.mouseIsDown.get()&&o(t,n)}))])}}})];const RC=x("slider.change.value"),NC=e=>{const t=e.event.raw;if((e=>-1!==e.type.indexOf("touch"))(t)){const e=t;return void 0!==e.touches&&1===e.touches.length?A.some(e.touches[0]).map((e=>qt(e.clientX,e.clientY))):A.none()}{const e=t;return void 0!==e.clientX?A.some(e).map((e=>qt(e.clientX,e.clientY))):A.none()}},zC=e=>e.model.minX,LC=e=>e.model.minY,VC=e=>e.model.minX-1,HC=e=>e.model.minY-1,PC=e=>e.model.maxX,UC=e=>e.model.maxY,WC=e=>e.model.maxX+1,jC=e=>e.model.maxY+1,$C=(e,t,o)=>t(e)-o(e),GC=e=>$C(e,PC,zC),qC=e=>$C(e,UC,LC),YC=e=>GC(e)/2,XC=e=>qC(e)/2,KC=(e,t)=>t?e.stepSize*e.speedMultiplier:e.stepSize,JC=e=>e.snapToGrid,QC=e=>e.snapStart,ZC=e=>e.rounded,eO=(e,t)=>void 0!==e[t+"-edge"],tO=e=>eO(e,"left"),oO=e=>eO(e,"right"),nO=e=>eO(e,"top"),sO=e=>eO(e,"bottom"),rO=e=>e.model.value.get(),aO=(e,t)=>({x:e,y:t}),iO=(e,t)=>{Lr(e,RC(),{value:t})},lO=(e,t,o,n)=>e<t?e:e>o?o:e===t?t-1:Math.max(t,e-n),cO=(e,t,o,n)=>e>o?e:e<t?t:e===o?o+1:Math.min(o,e+n),dO=(e,t,o)=>Math.max(t,Math.min(o,e)),uO=e=>{const{min:t,max:o,range:n,value:s,step:r,snap:a,snapStart:i,rounded:l,hasMinEdge:c,hasMaxEdge:d,minBound:u,maxBound:m,screenRange:g}=e,p=c?t-1:t,h=d?o+1:o;if(s<u)return p;if(s>m)return h;{const e=((e,t,o)=>Math.min(o,Math.max(e,t))-t)(s,u,m),c=dO(e/g*n+t,p,h);return a&&c>=t&&c<=o?((e,t,o,n,s)=>s.fold((()=>{const s=e-t,r=Math.round(s/n)*n;return dO(t+r,t-1,o+1)}),(t=>{const s=(e-t)%n,r=Math.round(s/n),a=Math.floor((e-t)/n),i=Math.floor((o-t)/n),l=t+Math.min(i,a+r)*n;return Math.max(t,l)})))(c,t,o,r,i):l?Math.round(c):c}},mO=e=>{const{min:t,max:o,range:n,value:s,hasMinEdge:r,hasMaxEdge:a,maxBound:i,maxOffset:l,centerMinEdge:c,centerMaxEdge:d}=e;return s<t?r?0:c:s>o?a?i:d:(s-t)/n*l},gO="top",pO="right",hO="bottom",fO="left",bO=e=>e.element.dom.getBoundingClientRect(),vO=(e,t)=>e[t],yO=e=>{const t=bO(e);return vO(t,fO)},xO=e=>{const t=bO(e);return vO(t,pO)},wO=e=>{const t=bO(e);return vO(t,gO)},SO=e=>{const t=bO(e);return vO(t,hO)},kO=e=>{const t=bO(e);return vO(t,"width")},CO=e=>{const t=bO(e);return vO(t,"height")},OO=(e,t,o)=>(e+t)/2-o,_O=(e,t)=>{const o=bO(e),n=bO(t),s=vO(o,fO),r=vO(o,pO),a=vO(n,fO);return OO(s,r,a)},TO=(e,t)=>{const o=bO(e),n=bO(t),s=vO(o,gO),r=vO(o,hO),a=vO(n,gO);return OO(s,r,a)},EO=(e,t)=>{Lr(e,RC(),{value:t})},AO=(e,t,o)=>{const n={min:zC(t),max:PC(t),range:GC(t),value:o,step:KC(t),snap:JC(t),snapStart:QC(t),rounded:ZC(t),hasMinEdge:tO(t),hasMaxEdge:oO(t),minBound:yO(e),maxBound:xO(e),screenRange:kO(e)};return uO(n)},MO=e=>(t,o,n)=>((e,t,o,n)=>{const s=(e>0?cO:lO)(rO(o),zC(o),PC(o),KC(o,n));return EO(t,s),A.some(s)})(e,t,o,n).map(E),DO=(e,t,o,n,s,r)=>{const a=((e,t,o,n,s)=>{const r=kO(e),a=n.bind((t=>A.some(_O(t,e)))).getOr(0),i=s.bind((t=>A.some(_O(t,e)))).getOr(r),l={min:zC(t),max:PC(t),range:GC(t),value:o,hasMinEdge:tO(t),hasMaxEdge:oO(t),minBound:yO(e),minOffset:0,maxBound:xO(e),maxOffset:r,centerMinEdge:a,centerMaxEdge:i};return mO(l)})(t,r,o,n,s);return yO(t)-yO(e)+a},BO=MO(-1),IO=MO(1),FO=A.none,RO=A.none,NO={"top-left":A.none(),top:A.none(),"top-right":A.none(),right:A.some(((e,t)=>{iO(e,WC(t))})),"bottom-right":A.none(),bottom:A.none(),"bottom-left":A.none(),left:A.some(((e,t)=>{iO(e,VC(t))}))};var zO=Object.freeze({__proto__:null,setValueFrom:(e,t,o)=>{const n=AO(e,t,o);return EO(e,n),n},setToMin:(e,t)=>{const o=zC(t);EO(e,o)},setToMax:(e,t)=>{const o=PC(t);EO(e,o)},findValueOfOffset:AO,getValueFromEvent:e=>NC(e).map((e=>e.left)),findPositionOfValue:DO,setPositionFromValue:(e,t,o,n)=>{const s=rO(o),r=DO(e,n.getSpectrum(e),s,n.getLeftEdge(e),n.getRightEdge(e),o),a=Qt(t.element)/2;Bt(t.element,"left",r-a+"px")},onLeft:BO,onRight:IO,onUp:FO,onDown:RO,edgeActions:NO});const LO=(e,t)=>{Lr(e,RC(),{value:t})},VO=(e,t,o)=>{const n={min:LC(t),max:UC(t),range:qC(t),value:o,step:KC(t),snap:JC(t),snapStart:QC(t),rounded:ZC(t),hasMinEdge:nO(t),hasMaxEdge:sO(t),minBound:wO(e),maxBound:SO(e),screenRange:CO(e)};return uO(n)},HO=e=>(t,o,n)=>((e,t,o,n)=>{const s=(e>0?cO:lO)(rO(o),LC(o),UC(o),KC(o,n));return LO(t,s),A.some(s)})(e,t,o,n).map(E),PO=(e,t,o,n,s,r)=>{const a=((e,t,o,n,s)=>{const r=CO(e),a=n.bind((t=>A.some(TO(t,e)))).getOr(0),i=s.bind((t=>A.some(TO(t,e)))).getOr(r),l={min:LC(t),max:UC(t),range:qC(t),value:o,hasMinEdge:nO(t),hasMaxEdge:sO(t),minBound:wO(e),minOffset:0,maxBound:SO(e),maxOffset:r,centerMinEdge:a,centerMaxEdge:i};return mO(l)})(t,r,o,n,s);return wO(t)-wO(e)+a},UO=A.none,WO=A.none,jO=HO(-1),$O=HO(1),GO={"top-left":A.none(),top:A.some(((e,t)=>{iO(e,HC(t))})),"top-right":A.none(),right:A.none(),"bottom-right":A.none(),bottom:A.some(((e,t)=>{iO(e,jC(t))})),"bottom-left":A.none(),left:A.none()};var qO=Object.freeze({__proto__:null,setValueFrom:(e,t,o)=>{const n=VO(e,t,o);return LO(e,n),n},setToMin:(e,t)=>{const o=LC(t);LO(e,o)},setToMax:(e,t)=>{const o=UC(t);LO(e,o)},findValueOfOffset:VO,getValueFromEvent:e=>NC(e).map((e=>e.top)),findPositionOfValue:PO,setPositionFromValue:(e,t,o,n)=>{const s=rO(o),r=PO(e,n.getSpectrum(e),s,n.getTopEdge(e),n.getBottomEdge(e),o),a=jt(t.element)/2;Bt(t.element,"top",r-a+"px")},onLeft:UO,onRight:WO,onUp:jO,onDown:$O,edgeActions:GO});const YO=(e,t)=>{Lr(e,RC(),{value:t})},XO=(e,t)=>({x:e,y:t}),KO=(e,t)=>(o,n,s)=>((e,t,o,n,s)=>{const r=e>0?cO:lO,a=t?rO(n).x:r(rO(n).x,zC(n),PC(n),KC(n,s)),i=t?r(rO(n).y,LC(n),UC(n),KC(n,s)):rO(n).y;return YO(o,XO(a,i)),A.some(a)})(e,t,o,n,s).map(E),JO=KO(-1,!1),QO=KO(1,!1),ZO=KO(-1,!0),e_=KO(1,!0),t_={"top-left":A.some(((e,t)=>{iO(e,aO(VC(t),HC(t)))})),top:A.some(((e,t)=>{iO(e,aO(YC(t),HC(t)))})),"top-right":A.some(((e,t)=>{iO(e,aO(WC(t),HC(t)))})),right:A.some(((e,t)=>{iO(e,aO(WC(t),XC(t)))})),"bottom-right":A.some(((e,t)=>{iO(e,aO(WC(t),jC(t)))})),bottom:A.some(((e,t)=>{iO(e,aO(YC(t),jC(t)))})),"bottom-left":A.some(((e,t)=>{iO(e,aO(VC(t),jC(t)))})),left:A.some(((e,t)=>{iO(e,aO(VC(t),XC(t)))}))};var o_=Object.freeze({__proto__:null,setValueFrom:(e,t,o)=>{const n=AO(e,t,o.left),s=VO(e,t,o.top),r=XO(n,s);return YO(e,r),r},setToMin:(e,t)=>{const o=zC(t),n=LC(t);YO(e,XO(o,n))},setToMax:(e,t)=>{const o=PC(t),n=UC(t);YO(e,XO(o,n))},getValueFromEvent:e=>NC(e),setPositionFromValue:(e,t,o,n)=>{const s=rO(o),r=DO(e,n.getSpectrum(e),s.x,n.getLeftEdge(e),n.getRightEdge(e),o),a=PO(e,n.getSpectrum(e),s.y,n.getTopEdge(e),n.getBottomEdge(e),o),i=Qt(t.element)/2,l=jt(t.element)/2;Bt(t.element,"left",r-i+"px"),Bt(t.element,"top",a-l+"px")},onLeft:JO,onRight:QO,onUp:ZO,onDown:e_,edgeActions:t_});const n_=Km({name:"Slider",configFields:[Cs("stepSize",1),Cs("speedMultiplier",10),Cs("onChange",b),Cs("onChoose",b),Cs("onInit",b),Cs("onDragStart",b),Cs("onDragEnd",b),Cs("snapToGrid",!1),Cs("rounded",!0),fs("snapStart"),ls("model",os("mode",{x:[Cs("minX",0),Cs("maxX",100),rs("value",(e=>on(e.mode.minX))),is("getInitialValue"),Ci("manager",zO)],y:[Cs("minY",0),Cs("maxY",100),rs("value",(e=>on(e.mode.minY))),is("getInitialValue"),Ci("manager",qO)],xy:[Cs("minX",0),Cs("maxX",100),Cs("minY",0),Cs("maxY",100),rs("value",(e=>on({x:e.mode.minX,y:e.mode.minY}))),is("getInitialValue"),Ci("manager",o_)]})),Yu("sliderBehaviours",[xh,qu]),rs("mouseIsDown",(()=>on(!1)))],partFields:FC,factory:(e,t,o,n)=>{const s=t=>Nm(t,e,"thumb"),r=t=>Nm(t,e,"spectrum"),a=t=>Rm(t,e,"left-edge"),i=t=>Rm(t,e,"right-edge"),l=t=>Rm(t,e,"top-edge"),c=t=>Rm(t,e,"bottom-edge"),d=e.model,u=d.manager,m=(t,o)=>{u.setPositionFromValue(t,o,e,{getLeftEdge:a,getRightEdge:i,getTopEdge:l,getBottomEdge:c,getSpectrum:r})},g=(e,t)=>{d.value.set(t);const o=s(e);m(e,o)},p=t=>{const o=e.mouseIsDown.get();e.mouseIsDown.set(!1),o&&Rm(t,e,"thumb").each((o=>{const n=d.value.get();e.onChoose(t,o,n)}))},h=(t,o)=>{o.stop(),e.mouseIsDown.set(!0),e.onDragStart(t,s(t))},f=(t,o)=>{o.stop(),e.onDragEnd(t,s(t)),p(t)},b=t=>{Rm(t,e,"spectrum").map(xh.focusIn)};return{uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.sliderBehaviours,[xh.config({mode:"special",focusIn:b}),qu.config({store:{mode:"manual",getValue:e=>d.value.get(),setValue:g}}),gc.config({channels:{[Mu()]:{onReceive:p}}})]),events:Wr([Gr(RC(),((t,o)=>{((t,o)=>{g(t,o);const n=s(t);e.onChange(t,n,o),A.some(!0)})(t,o.event.value)})),ea(((t,o)=>{const n=d.getInitialValue();d.value.set(n);const a=s(t);m(t,a);const i=r(t);e.onInit(t,a,i,d.value.get())})),Gr(Ws(),h),Gr($s(),f),Gr(qs(),((e,t)=>{b(e),h(e,t)})),Gr(Ks(),f)]),apis:{resetToMin:t=>{u.setToMin(t,e)},resetToMax:t=>{u.setToMax(t,e)},setValue:g,refresh:m},domModification:{styles:{position:"relative"}}}},apis:{setValue:(e,t,o)=>{e.setValue(t,o)},resetToMin:(e,t)=>{e.resetToMin(t)},resetToMax:(e,t)=>{e.resetToMax(t)},refresh:(e,t)=>{e.refresh(t)}}}),s_=Bi("rgb-hex-update"),r_=Bi("slider-update"),a_=Bi("palette-update"),i_="form",l_=[Yu("formBehaviours",[qu])],c_=e=>"<alloy.field."+e+">",d_=(e,t)=>({uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.formBehaviours,[qu.config({store:{mode:"manual",getValue:t=>{const o=Lm(t,e);return le(o,((e,t)=>e().bind((e=>{return o=eg.getCurrent(e),n=new Error(`Cannot find a current component to extract the value from for form part '${t}': `+ii(e.element)),o.fold((()=>dn.error(n)),dn.value);var o,n})).map(qu.getValue)))},setValue:(t,o)=>{ie(o,((o,n)=>{Rm(t,e,n).each((e=>{eg.getCurrent(e).each((e=>{qu.setValue(e,o)}))}))}))}}})]),apis:{getField:(t,o)=>Rm(t,e,o).bind(eg.getCurrent)}}),u_={getField:Gi(((e,t,o)=>e.getField(t,o))),sketch:e=>{const t=(()=>{const e=[];return{field:(t,o)=>(e.push(t),Mm(i_,c_(t),o)),record:x(e)}})(),o=e(t),n=t.record(),s=L(n,(e=>wm({name:e,pname:c_(e)})));return $m(i_,l_,s,d_,o)}},m_=Bi("valid-input"),g_=Bi("invalid-input"),p_=Bi("validating-input"),h_="colorcustom.rgb.",f_=(e,t,o,n)=>{const s=(o,n)=>bC.config({invalidClass:t("invalid"),notify:{onValidate:e=>{Lr(e,p_,{type:o})},onValid:e=>{Lr(e,m_,{type:o,value:qu.getValue(e)})},onInvalid:e=>{Lr(e,g_,{type:o,value:qu.getValue(e)})}},validator:{validate:t=>{const o=qu.getValue(t),s=n(o)?dn.value(!0):dn.error(e("aria.input.invalid"));return ik(s)},validateOnLoad:!1}}),r=(o,n,r,a,i)=>{const l=e(h_+"range"),c=Gk.parts.label({dom:{tag:"label",attributes:{"aria-label":a}},components:[ul(r)]}),d=Gk.parts.field({data:i,factory:Iy,inputAttributes:{type:"text",..."hex"===n?{"aria-live":"polite"}:{}},inputClasses:[t("textfield")],inputBehaviours:ma([s(n,o),Ub.config({})]),onSetValue:e=>{bC.isInvalid(e)&&bC.run(e).get(b)}}),u=[c,d],m="hex"!==n?[Gk.parts["aria-descriptor"]({text:l})]:[];return{dom:{tag:"div",attributes:{role:"presentation"}},components:u.concat(m)}},a=(e,t)=>{const o=t.red,n=t.green,s=t.blue;qu.setValue(e,{red:o,green:n,blue:s})},i=Vb({dom:{tag:"div",classes:[t("rgba-preview")],styles:{"background-color":"white"},attributes:{role:"presentation"}}}),l=(e,t)=>{i.getOpt(e).each((e=>{Bt(e.element,"background-color","#"+t.value)}))},c=Xm({factory:()=>{const s={red:on(A.some(255)),green:on(A.some(255)),blue:on(A.some(255)),hex:on(A.some("ffffff"))},c=e=>s[e].get(),d=(e,t)=>{s[e].set(t)},u=e=>{const t=e.red,o=e.green,n=e.blue;d("red",A.some(t)),d("green",A.some(o)),d("blue",A.some(n))},m=(e,t)=>{const o=t.event;"hex"!==o.type?d(o.type,A.none()):n(e)},g=(e,t)=>{const n=t.event;(e=>"hex"===e.type)(n)?((e,t)=>{o(e);const n=Rw(t);d("hex",A.some(n.value));const s=Kw(n);a(e,s),u(s),Lr(e,s_,{hex:n}),l(e,n)})(e,n.value):((e,t,o)=>{const n=parseInt(o,10);d(t,A.some(n)),c("red").bind((e=>c("green").bind((t=>c("blue").map((o=>qw(e,t,o,1))))))).each((t=>{const o=((e,t)=>{const o=Pw(t);return u_.getField(e,"hex").each((t=>{Rh.isFocused(t)||qu.setValue(e,{hex:o.value})})),o})(e,t);Lr(e,s_,{hex:o}),l(e,o)}))})(e,n.type,n.value)},p=t=>({label:e(h_+t+".label"),description:e(h_+t+".description")}),h=p("red"),f=p("green"),b=p("blue"),v=p("hex");return wn(u_.sketch((o=>({dom:{tag:"form",classes:[t("rgb-form")],attributes:{"aria-label":e("aria.color.picker")}},components:[o.field("red",Gk.sketch(r(Yw,"red",h.label,h.description,255))),o.field("green",Gk.sketch(r(Yw,"green",f.label,f.description,255))),o.field("blue",Gk.sketch(r(Yw,"blue",b.label,b.description,255))),o.field("hex",Gk.sketch(r(Lw,"hex",v.label,v.description,"ffffff"))),i.asSpec()],formBehaviours:ma([bC.config({invalidClass:t("form-invalid")}),Mh("rgb-form-events",[Gr(m_,g),Gr(g_,m),Gr(p_,m)])])}))),{apis:{updateHex:(e,t)=>{qu.setValue(e,{hex:t.value}),((e,t)=>{const o=Kw(t);a(e,o),u(o)})(e,t),l(e,t)}}})},name:"RgbForm",configFields:[],apis:{updateHex:(e,t,o)=>{e.updateHex(t,o)}},extraApis:{}});return c},b_=(e,t)=>{const o=Xm({name:"ColourPicker",configFields:[is("dom"),Cs("onValidHex",b),Cs("onInvalidHex",b)],factory:o=>{const n=f_(e,t,o.onValidHex,o.onInvalidHex),s=((e,t)=>{const o=n_.parts.spectrum({dom:{tag:"canvas",attributes:{role:"presentation"},classes:[t("sv-palette-spectrum")]}}),n=n_.parts.thumb({dom:{tag:"div",attributes:{role:"presentation"},classes:[t("sv-palette-thumb")],innerHtml:`<div class=${t("sv-palette-inner-thumb")} role="presentation"></div>`}}),s=(e,t)=>{const{width:o,height:n}=e,s=e.getContext("2d");if(null===s)return;s.fillStyle=t,s.fillRect(0,0,o,n);const r=s.createLinearGradient(0,0,o,0);r.addColorStop(0,"rgba(255,255,255,1)"),r.addColorStop(1,"rgba(255,255,255,0)"),s.fillStyle=r,s.fillRect(0,0,o,n);const a=s.createLinearGradient(0,0,0,n);a.addColorStop(0,"rgba(0,0,0,0)"),a.addColorStop(1,"rgba(0,0,0,1)"),s.fillStyle=a,s.fillRect(0,0,o,n)};return Xm({factory:r=>{const a=x({x:0,y:0}),i=ma([eg.config({find:A.some}),Rh.config({})]);return n_.sketch({dom:{tag:"div",attributes:{role:"slider","aria-valuetext":e(["Saturation {0}%, Brightness {1}%",0,0])},classes:[t("sv-palette")]},model:{mode:"xy",getInitialValue:a},rounded:!1,components:[o,n],onChange:(t,o,n)=>{h(n)||Ct(t.element,"aria-valuetext",e(["Saturation {0}%, Brightness {1}%",Math.floor(n.x),Math.floor(100-n.y)])),Lr(t,a_,{value:n})},onInit:(e,t,o,n)=>{s(o.element.dom,Zw(eS))},sliderBehaviours:i})},name:"SaturationBrightnessPalette",configFields:[],apis:{setHue:(e,t,o)=>{((e,t)=>{const o=e.components()[0].element.dom,n=pS(t,100,100),r=Xw(n);s(o,Zw(r))})(t,o)},setThumb:(t,o,n)=>{((t,o)=>{const n=hS(Kw(o));n_.setValue(t,{x:n.saturation,y:100-n.value}),Ct(t.element,"aria-valuetext",e(["Saturation {0}%, Brightness {1}%",n.saturation,n.value]))})(o,n)}},extraApis:{}})})(e,t),r={paletteRgba:on(eS),paletteHue:on(0)},a=Vb(((e,t)=>{const o=n_.parts.spectrum({dom:{tag:"div",classes:[t("hue-slider-spectrum")],attributes:{role:"presentation"}}}),n=n_.parts.thumb({dom:{tag:"div",classes:[t("hue-slider-thumb")],attributes:{role:"presentation"}}});return n_.sketch({dom:{tag:"div",classes:[t("hue-slider")],attributes:{role:"slider","aria-valuemin":0,"aria-valuemax":360,"aria-valuenow":120}},rounded:!1,model:{mode:"y",getInitialValue:x(0)},components:[o,n],sliderBehaviours:ma([Rh.config({})]),onChange:(e,t,o)=>{Ct(e.element,"aria-valuenow",Math.floor(360-3.6*o)),Lr(e,r_,{value:o})}})})(0,t)),i=Vb(s.sketch({})),l=Vb(n.sketch({})),c=(e,t,o)=>{i.getOpt(e).each((e=>{s.setHue(e,o)}))},d=(e,t)=>{l.getOpt(e).each((e=>{n.updateHex(e,t)}))},u=(e,t,o)=>{a.getOpt(e).each((e=>{n_.setValue(e,(e=>100-e/360*100)(o))}))},m=(e,t)=>{i.getOpt(e).each((e=>{s.setThumb(e,t)}))},g=(e,t,o,n)=>{((e,t)=>{const o=Kw(e);r.paletteRgba.set(o),r.paletteHue.set(t)})(t,o),V(n,(n=>{n(e,t,o)}))};return{uid:o.uid,dom:o.dom,components:[i.asSpec(),a.asSpec(),l.asSpec()],behaviours:ma([Mh("colour-picker-events",[Gr(s_,(()=>{const e=[c,u,m];return(t,o)=>{const n=o.event.hex,s=(e=>hS(Kw(e)))(n);g(t,n,s.hue,e)}})()),Gr(a_,(()=>{const e=[d];return(t,o)=>{const n=o.event.value,s=r.paletteHue.get(),a=pS(s,n.x,100-n.y),i=fS(a);g(t,i,s,e)}})()),Gr(r_,(()=>{const e=[c,d];return(t,o)=>{const n=(e=>(100-e)/100*360)(o.event.value),s=r.paletteRgba.get(),a=hS(s),i=pS(n,a.saturation,a.value),l=fS(i);g(t,l,n,e)}})())]),eg.config({find:e=>l.getOpt(e)}),xh.config({mode:"acyclic"})])}}});return o},v_=()=>eg.config({find:A.some}),y_=e=>eg.config({find:t=>ct(t.element,e).bind((e=>t.getSystem().getByDom(e).toOptional()))}),x_=Nn([Cs("preprocess",w),Cs("postprocess",w)]),w_=(e,t)=>{const o=es("RepresentingConfigs.memento processors",x_,t);return qu.config({store:{mode:"manual",getValue:t=>{const n=e.get(t),s=qu.getValue(n);return o.postprocess(s)},setValue:(t,n)=>{const s=o.preprocess(n),r=e.get(t);qu.setValue(r,s)}}})},S_=(e,t,o)=>qu.config({store:{mode:"manual",...e.map((e=>({initialValue:e}))).getOr({}),getValue:t,setValue:o}}),k_=(e,t,o)=>S_(e,(e=>t(e.element)),((e,t)=>o(e.element,t))),C_=e=>qu.config({store:{mode:"memory",initialValue:e}}),O_={"colorcustom.rgb.red.label":"R","colorcustom.rgb.red.description":"Red component","colorcustom.rgb.green.label":"G","colorcustom.rgb.green.description":"Green component","colorcustom.rgb.blue.label":"B","colorcustom.rgb.blue.description":"Blue component","colorcustom.rgb.hex.label":"#","colorcustom.rgb.hex.description":"Hex color code","colorcustom.rgb.range":"Range 0 to 255","aria.color.picker":"Color Picker","aria.input.invalid":"Invalid input"};var __=tinymce.util.Tools.resolve("tinymce.Resource");const T_=e=>be(e,"init");var E_=tinymce.util.Tools.resolve("tinymce.util.Tools");const A_=(e,t)=>{let o=null;const n=()=>{c(o)||(clearTimeout(o),o=null)};return{cancel:n,throttle:(...s)=>{n(),o=setTimeout((()=>{o=null,e.apply(null,s)}),t)}}},M_=Bi("alloy-fake-before-tabstop"),D_=Bi("alloy-fake-after-tabstop"),B_=e=>({dom:{tag:"div",styles:{width:"1px",height:"1px",outline:"none"},attributes:{tabindex:"0"},classes:e},behaviours:ma([Rh.config({ignore:!0}),Ub.config({})])}),I_=(e,t)=>({dom:{tag:"div",classes:["tox-navobj",...e.getOr([])]},components:[B_([M_]),t,B_([D_])],behaviours:ma([y_(1)])}),F_=(e,t)=>{Lr(e,er(),{raw:{which:9,shiftKey:t}})},R_=(e,t)=>{const o=t.element;_a(o,M_)?F_(e,!0):_a(o,D_)&&F_(e,!1)},N_=e=>Bk(e,["."+M_,"."+D_].join(","),T),z_=Bi("update-dialog"),L_=Bi("update-title"),V_=Bi("update-body"),H_=Bi("update-footer"),P_=Bi("body-send-message"),U_=Bi("dialog-focus-shifted"),W_=Bo().browser,j_=W_.isSafari(),$_=W_.isFirefox(),G_=j_||$_,q_=W_.isChromium(),Y_=({scrollTop:e,scrollHeight:t,clientHeight:o})=>Math.ceil(e)+o>=t,X_=(e,t)=>e.scrollTo(0,"bottom"===t?99999999:t),K_=(e,t,o)=>{const n=e.dom;A.from(n.contentDocument).fold(o,(e=>{let o=0;const s=((e,t)=>{const o=e.body;return A.from(!/^<!DOCTYPE (html|HTML)/.test(t)&&(!q_&&!j_||g(o)&&(0!==o.scrollTop||Math.abs(o.scrollHeight-o.clientHeight)>1))?o:e.documentElement)})(e,t).map((e=>(o=e.scrollTop,e))).forall(Y_),r=()=>{const e=n.contentWindow;g(e)&&(s?X_(e,"bottom"):!s&&G_&&0!==o&&X_(e,o))};j_&&n.addEventListener("load",r,{once:!0}),e.open(),e.write(t),e.close(),j_||r()}))},J_=ke(G_,j_?500:200).map((e=>((e,t)=>{let o=null,n=null;return{cancel:()=>{c(o)||(clearTimeout(o),o=null,n=null)},throttle:(...s)=>{n=s,c(o)&&(o=setTimeout((()=>{const t=n;o=null,n=null,e.apply(null,t)}),t))}}})(K_,e))),Q_=Bi("toolbar.button.execute"),Z_=Bi("common-button-display-events"),eT={[hr()]:["disabling","alloy.base.behaviour","toggling","toolbar-button-events","tooltipping"],[_r()]:["toolbar-button-events",Z_],[Tr()]:["toolbar-button-events","dropdown-events","tooltipping"],[qs()]:["focusing","alloy.base.behaviour",Z_]},tT=e=>Bt(e.element,"width",Rt(e.element,"width")),oT=(e,t,o)=>ry(e,{tag:"span",classes:["tox-icon","tox-tbtn__icon-wrap"],behaviours:o},t),nT=(e,t)=>oT(e,t,[]),sT=(e,t)=>oT(e,t,[Ah.config({})]),rT=(e,t,o)=>({dom:{tag:"span",classes:[`${t}__select-label`]},components:[ul(o.translate(e))],behaviours:ma([Ah.config({})])}),aT=Bi("update-menu-text"),iT=Bi("update-menu-icon"),lT=(e,t,o,n)=>{const s=on(b),r=e.text.map((e=>Vb(rT(e,t,o.providers)))),a=e.icon.map((e=>Vb(sT(e,o.providers.icons)))),i=(e,t)=>{const o=qu.getValue(e);return Rh.focus(o),Lr(o,"keydown",{raw:t.event.raw}),wk.close(o),A.some(!0)},l=e.role.fold((()=>({})),(e=>({role:e}))),c=A.from(e.listRole).map((e=>({listRole:e}))).getOr({}),d=e.ariaLabel.fold((()=>({})),(e=>({"aria-label":o.providers.translate(e)}))),u=ry("chevron-down",{tag:"div",classes:[`${t}__select-chevron`]},o.providers.icons),m=Bi("common-button-display-events"),p="dropdown-events",h=Vb(wk.sketch({...e.uid?{uid:e.uid}:{},...l,...c,dom:{tag:"button",classes:[t,`${t}--select`].concat(L(e.classes,(e=>`${t}--${e}`))),attributes:{...d,...g(n)?{"data-mce-name":n}:{}}},components:yw([a.map((e=>e.asSpec())),r.map((e=>e.asSpec())),A.some(u)]),matchWidth:!0,useMinWidth:!0,onOpen:(t,o,n)=>{e.searchable&&(e=>{Ly(e).each((e=>Rh.focus(e)))})(n)},dropdownBehaviours:ma([...e.dropdownBehaviours,uw((()=>e.disabled||o.providers.isDisabled())),dw(),vC.config({}),Ah.config({}),...e.tooltip.map((e=>Zb.config(o.providers.tooltips.getConfig({tooltipText:o.providers.translate(e)})))).toArray(),Mh(p,[hw(e,s),fw(e,s)]),Mh(m,[ea(((e,t)=>tT(e)))]),Mh("menubutton-update-display-text",[Gr(aT,((e,t)=>{r.bind((t=>t.getOpt(e))).each((e=>{Ah.set(e,[ul(o.providers.translate(t.event.text))])}))})),Gr(iT,((e,t)=>{a.bind((t=>t.getOpt(e))).each((e=>{Ah.set(e,[sT(t.event.icon,o.providers.icons)])}))}))])]),eventOrder:wn(eT,{[qs()]:["focusing","alloy.base.behaviour","item-type-events","normal-dropdown-events"],[_r()]:["toolbar-button-events",Zb.name(),p,m]}),sandboxBehaviours:ma([xh.config({mode:"special",onLeft:i,onRight:i}),Mh("dropdown-sandbox-events",[Gr(Fy,((e,t)=>{(e=>{const t=qu.getValue(e),o=zy(e).map(Vy);wk.refetch(t).get((()=>{const e=tk.getCoupled(t,"sandbox");o.each((t=>zy(e).each((e=>((e,t)=>{qu.setValue(e,t.fetchPattern),e.element.dom.selectionStart=t.selectionStart,e.element.dom.selectionEnd=t.selectionEnd})(e,t)))))}))})(e),t.stop()})),Gr(Ry,((e,t)=>{((e,t)=>{(e=>Tu.getState(e).bind(Cg.getHighlighted).bind(Cg.getHighlighted))(e).each((o=>{((e,t,o,n)=>{const s={...n,target:t};e.getSystem().triggerEvent(o,t,s)})(e,o.element,t.event.eventType,t.event.interactionEvent)}))})(e,t),t.stop()}))])]),lazySink:o.getSink,toggleClass:`${t}--active`,parts:{menu:{...Ey(0,e.columns,e.presets),fakeFocus:e.searchable,..."listbox"===e.listRole?{}:{onHighlightItem:Sk,onCollapseMenu:(e,t,o)=>{Cg.getHighlighted(o).each((t=>{Sk(e,o,t)}))},onDehighlightItem:kk}}},getAnchorOverrides:()=>({maxHeightFunction:(e,t)=>{Pc()(e,t-10)}}),fetch:t=>ak(k(e.fetch,t))}));return h.asSpec()},cT=e=>"separator"===e.type,dT={type:"separator"},uT=(e,t)=>{const o=((e,t)=>{const o=W(e,((e,o)=>(e=>r(e))(o)?""===o?e:"|"===o?e.length>0&&!cT(e[e.length-1])?e.concat([dT]):e:be(t,o.toLowerCase())?e.concat([t[o.toLowerCase()]]):e:e.concat([o])),[]);return o.length>0&&cT(o[o.length-1])&&o.pop(),o})(r(e)?e.split(" "):e,t);return U(o,((e,o)=>{if((e=>be(e,"getSubmenuItems"))(o)){const n=(e=>{const t=fe(e,"value").getOrThunk((()=>Bi("generated-menu-item")));return wn({value:t},e)})(o),s=((e,t)=>{const o=e.getSubmenuItems(),n=uT(o,t);return{item:e,menus:wn(n.menus,{[e.value]:n.items}),expansions:wn(n.expansions,{[e.value]:e.value})}})(n,t);return{menus:wn(e.menus,s.menus),items:[s.item,...e.items],expansions:wn(e.expansions,s.expansions)}}return{...e,items:[o,...e.items]}}),{menus:{},expansions:{},items:[]})},mT=(e,t,o,n)=>{const s=Bi("primary-menu"),r=uT(e,o.shared.providers.menuItems());if(0===r.items.length)return A.none();const a=(e=>e.search.fold((()=>({searchMode:"no-search"})),(e=>({searchMode:"search-with-field",placeholder:e.placeholder}))))(n),i=Ek(s,r.items,t,o,n.isHorizontalMenu,a),l=(e=>e.search.fold((()=>({searchMode:"no-search"})),(e=>({searchMode:"search-with-results"}))))(n),c=le(r.menus,((e,n)=>Ek(n,e,t,o,!1,l))),d=wn(c,Fs(s,i));return A.from(xf.tieredData(s,d,r.expansions))},gT=e=>!be(e,"items"),pT="data-value",hT=(e,t,o,n,s)=>L(o,(o=>gT(o)?{type:"togglemenuitem",...s?{}:{role:"option"},text:o.text,value:o.value,active:o.value===n,onAction:()=>{qu.setValue(e,o.value),Lr(e,Qk,{name:t}),Rh.focus(e)}}:{type:"nestedmenuitem",text:o.text,getSubmenuItems:()=>hT(e,t,o.items,n,s)})),fT=(e,t)=>se(e,(e=>gT(e)?ke(e.value===t,e):fT(e.items,t))),bT=Xm({name:"HtmlSelect",configFields:[is("options"),Yu("selectBehaviours",[Rh,qu]),Cs("selectClasses",[]),Cs("selectAttributes",{}),fs("data")],factory:(e,t)=>{const o=L(e.options,(e=>({dom:{tag:"option",value:e.value,innerHtml:e.text}}))),n=e.data.map((e=>Fs("initialValue",e))).getOr({});return{uid:e.uid,dom:{tag:"select",classes:e.selectClasses,attributes:e.selectAttributes},components:o,behaviours:Ku(e.selectBehaviours,[Rh.config({}),qu.config({store:{mode:"manual",getValue:e=>ol(e.element),setValue:(t,o)=>{const n=te(e.options);j(e.options,(e=>e.value===o)).isSome()?nl(t.element,o):-1===t.element.dom.selectedIndex&&""===o&&n.each((e=>nl(t.element,e.value)))},...n}})])}}}),vT=x([Cs("field1Name","field1"),Cs("field2Name","field2"),Si("onLockedChange"),vi(["lockClass"]),Cs("locked",!1),Ju("coupledFieldBehaviours",[eg,qu])]),yT=(e,t)=>wm({factory:Gk,name:e,overrides:e=>({fieldBehaviours:ma([Mh("coupled-input-behaviour",[Gr(or(),(o=>{((e,t,o)=>Rm(e,t,o).bind(eg.getCurrent))(o,e,t).each((t=>{Rm(o,e,"lock").each((n=>{Wh.isOn(n)&&e.onLockedChange(o,t,n)}))}))}))])])})}),xT=x([yT("field1","field2"),yT("field2","field1"),wm({factory:zb,schema:[is("dom")],name:"lock",overrides:e=>({buttonBehaviours:ma([Wh.config({selected:e.locked,toggleClass:e.markers.lockClass,aria:{mode:"pressed"}})])})})]),wT=Km({name:"FormCoupledInputs",configFields:vT(),partFields:xT(),factory:(e,t,o,n)=>({uid:e.uid,dom:e.dom,components:t,behaviours:Qu(e.coupledFieldBehaviours,[eg.config({find:A.some}),qu.config({store:{mode:"manual",getValue:t=>{const o=Hm(t,e,["field1","field2"]);return{[e.field1Name]:qu.getValue(o.field1()),[e.field2Name]:qu.getValue(o.field2())}},setValue:(t,o)=>{const n=Hm(t,e,["field1","field2"]);ve(o,e.field1Name)&&qu.setValue(n.field1(),o[e.field1Name]),ve(o,e.field2Name)&&qu.setValue(n.field2(),o[e.field2Name])}}})]),apis:{getField1:t=>Rm(t,e,"field1"),getField2:t=>Rm(t,e,"field2"),getLock:t=>Rm(t,e,"lock")}}),apis:{getField1:(e,t)=>e.getField1(t),getField2:(e,t)=>e.getField2(t),getLock:(e,t)=>e.getLock(t)}}),ST=e=>{const t=/^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/.exec(e);if(null!==t){const e=parseFloat(t[1]),o=t[2];return dn.value({value:e,unit:o})}return dn.error(e)},kT=(e,t)=>{const o={"":96,px:96,pt:72,cm:2.54,pc:12,mm:25.4,in:1},n=e=>be(o,e);return e.unit===t?A.some(e.value):n(e.unit)&&n(t)?o[e.unit]===o[t]?A.some(e.value):A.some(e.value/o[e.unit]*o[t]):A.none()},CT=e=>A.none(),OT=(e,t)=>{const o=e.label.map((e=>Jk(e,t))),n=[pg.config({disabled:()=>e.disabled||t.isDisabled()}),dw(),xh.config({mode:"execution",useEnter:!0!==e.multiline,useControlEnter:!0===e.multiline,execute:e=>(zr(e,oC),A.some(!0))}),Mh("textfield-change",[Gr(or(),((t,o)=>{Lr(t,Qk,{name:e.name})})),Gr(gr(),((t,o)=>{Lr(t,Qk,{name:e.name})}))]),Ub.config({})],s=e.validation.map((e=>bC.config({getRoot:e=>at(e.element),invalidClass:"tox-invalid",validator:{validate:t=>{const o=qu.getValue(t),n=e.validator(o);return ik(!0===n?dn.value(o):dn.error(n))},validateOnLoad:e.validateOnLoad}}))).toArray(),r={...e.placeholder.fold(x({}),(e=>({placeholder:t.translate(e)}))),...e.inputMode.fold(x({}),(e=>({inputmode:e})))},a=Gk.parts.field({tag:!0===e.multiline?"textarea":"input",...e.data.map((e=>({data:e}))).getOr({}),inputAttributes:r,inputClasses:[e.classname],inputBehaviours:ma(G([n,s])),selectOnFocus:!1,factory:Iy}),i=e.multiline?{dom:{tag:"div",classes:["tox-textarea-wrap"]},components:[a]}:a,l=(e.flex?["tox-form__group--stretched"]:[]).concat(e.maximized?["tox-form-group--maximize"]:[]),c=[pg.config({disabled:()=>e.disabled||t.isDisabled(),onDisabled:e=>{Gk.getField(e).each(pg.disable)},onEnabled:e=>{Gk.getField(e).each(pg.enable)}}),dw()];return Yk(o,i,l,c)},_T=(e,t)=>t.getAnimationRoot.fold((()=>e.element),(t=>t(e))),TT=e=>e.dimension.property,ET=(e,t)=>e.dimension.getDimension(t),AT=(e,t)=>{const o=_T(e,t);Ea(o,[t.shrinkingClass,t.growingClass])},MT=(e,t)=>{Oa(e.element,t.openClass),ka(e.element,t.closedClass),Bt(e.element,TT(t),"0px"),Pt(e.element)},DT=(e,t)=>{Oa(e.element,t.closedClass),ka(e.element,t.openClass),Ht(e.element,TT(t))},BT=(e,t,o,n)=>{o.setCollapsed(),Bt(e.element,TT(t),ET(t,e.element)),AT(e,t),MT(e,t),t.onStartShrink(e),t.onShrunk(e)},IT=(e,t,o,n)=>{const s=n.getOrThunk((()=>ET(t,e.element)));o.setCollapsed(),Bt(e.element,TT(t),s),Pt(e.element);const r=_T(e,t);Oa(r,t.growingClass),ka(r,t.shrinkingClass),MT(e,t),t.onStartShrink(e)},FT=(e,t,o)=>{const n=ET(t,e.element);("0px"===n?BT:IT)(e,t,o,A.some(n))},RT=(e,t,o)=>{const n=_T(e,t),s=_a(n,t.shrinkingClass),r=ET(t,e.element);DT(e,t);const a=ET(t,e.element);(s?()=>{Bt(e.element,TT(t),r),Pt(e.element)}:()=>{MT(e,t)})(),Oa(n,t.shrinkingClass),ka(n,t.growingClass),DT(e,t),Bt(e.element,TT(t),a),o.setExpanded(),t.onStartGrow(e)},NT=(e,t,o)=>{const n=_T(e,t);return!0===_a(n,t.growingClass)},zT=(e,t,o)=>{const n=_T(e,t);return!0===_a(n,t.shrinkingClass)};var LT=Object.freeze({__proto__:null,refresh:(e,t,o)=>{if(o.isExpanded()){Ht(e.element,TT(t));const o=ET(t,e.element);Bt(e.element,TT(t),o)}},grow:(e,t,o)=>{o.isExpanded()||RT(e,t,o)},shrink:(e,t,o)=>{o.isExpanded()&&FT(e,t,o)},immediateShrink:(e,t,o)=>{o.isExpanded()&&BT(e,t,o)},hasGrown:(e,t,o)=>o.isExpanded(),hasShrunk:(e,t,o)=>o.isCollapsed(),isGrowing:NT,isShrinking:zT,isTransitioning:(e,t,o)=>NT(e,t)||zT(e,t),toggleGrow:(e,t,o)=>{(o.isExpanded()?FT:RT)(e,t,o)},disableTransitions:AT,immediateGrow:(e,t,o)=>{o.isExpanded()||(DT(e,t),Bt(e.element,TT(t),ET(t,e.element)),AT(e,t),o.setExpanded(),t.onStartGrow(e),t.onGrown(e))}}),VT=Object.freeze({__proto__:null,exhibit:(e,t,o)=>{const n=t.expanded;return aa(n?{classes:[t.openClass],styles:{}}:{classes:[t.closedClass],styles:Fs(t.dimension.property,"0px")})},events:(e,t)=>Wr([Zr(ar(),((o,n)=>{n.event.raw.propertyName===e.dimension.property&&(AT(o,e),t.isExpanded()&&Ht(o.element,e.dimension.property),(t.isExpanded()?e.onGrown:e.onShrunk)(o))}))])}),HT=[is("closedClass"),is("openClass"),is("shrinkingClass"),is("growingClass"),fs("getAnimationRoot"),xi("onShrunk"),xi("onStartShrink"),xi("onGrown"),xi("onStartGrow"),Cs("expanded",!1),ls("dimension",os("property",{width:[Ci("property","width"),Ci("getDimension",(e=>Qt(e)+"px"))],height:[Ci("property","height"),Ci("getDimension",(e=>jt(e)+"px"))]}))];const PT=pa({fields:HT,name:"sliding",active:VT,apis:LT,state:Object.freeze({__proto__:null,init:e=>{const t=on(e.expanded);return ua({isExpanded:()=>!0===t.get(),isCollapsed:()=>!1===t.get(),setCollapsed:k(t.set,!1),setExpanded:k(t.set,!0),readState:()=>"expanded: "+t.get()})}})}),UT=e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t),setActive:t=>{const o=e.element;t?(ka(o,"tox-tbtn--enabled"),Ct(o,"aria-pressed",!0)):(Oa(o,"tox-tbtn--enabled"),At(o,"aria-pressed"))},isActive:()=>_a(e.element,"tox-tbtn--enabled"),setText:t=>{Lr(e,aT,{text:t})},setIcon:t=>Lr(e,iT,{icon:t})}),WT=(e,t,o,n,s=!0,r)=>lT({text:e.text,icon:e.icon,tooltip:e.tooltip,ariaLabel:e.tooltip,searchable:e.search.isSome(),role:n,fetch:(t,n)=>{const s={pattern:e.search.isSome()?Ck(t):""};e.fetch((t=>{n(mT(t,dy.CLOSE_ON_EXECUTE,o,{isHorizontalMenu:!1,search:e.search}))}),s,UT(t))},onSetup:e.onSetup,getApi:UT,columns:1,presets:"normal",classes:[],dropdownBehaviours:[...s?[Ub.config({})]:[]]},t,o.shared,r),jT=(e,t,o)=>{const n=e=>n=>{const s=!n.isActive();n.setActive(s),e.storage.set(s),o.shared.getSink().each((o=>{t().getOpt(o).each((t=>{hc(t.element),Lr(t,tC,{name:e.name,value:e.storage.get()})}))}))},s=e=>t=>{t.setActive(e.storage.get())};return t=>{t(L(e,(e=>{const t=e.text.fold((()=>({})),(e=>({text:e})));return{type:e.type,active:!1,...t,onAction:n(e),onSetup:s(e)}})))}},$T=e=>({dom:{tag:"span",classes:["tox-tree__label"],attributes:{"aria-label":e}},components:[ul(e)]}),GT=Bi("leaf-label-event-id"),qT=({leaf:e,onLeafAction:t,visible:o,treeId:n,selectedId:s,backstage:r})=>{const a=e.menu.map((e=>WT(e,"tox-mbtn",r,A.none(),o))),i=[$T(e.title)];return a.each((e=>i.push(e))),zb.sketch({dom:{tag:"div",classes:["tox-tree--leaf__label","tox-trbtn"].concat(o?["tox-tree--leaf__label--visible"]:[])},components:i,role:"treeitem",action:o=>{t(e.id),o.getSystem().broadcastOn([`update-active-item-${n}`],{value:e.id})},eventOrder:{[er()]:[GT,"keying"]},buttonBehaviours:ma([...o?[Ub.config({})]:[],Wh.config({toggleClass:"tox-trbtn--enabled",toggleOnExecute:!1,aria:{mode:"selected"}}),gc.config({channels:{[`update-active-item-${n}`]:{onReceive:(t,o)=>{(o.value===e.id?Wh.on:Wh.off)(t)}}}}),Mh(GT,[ea(((t,o)=>{s.each((o=>{(o===e.id?Wh.on:Wh.off)(t)}))})),Gr(er(),((e,t)=>{const o="ArrowLeft"===t.event.raw.code,n="ArrowRight"===t.event.raw.code;o?(kl(e.element,".tox-tree--directory").each((t=>{e.getSystem().getByDom(t).each((e=>{Ol(t,".tox-tree--directory__label").each((t=>{e.getSystem().getByDom(t).each(Rh.focus)}))}))})),t.stop()):n&&t.stop()}))])])})},YT=Bi("directory-label-event-id"),XT=({directory:e,visible:t,noChildren:o,backstage:n})=>{const s=e.menu.map((e=>WT(e,"tox-mbtn",n,A.none()))),r=[{dom:{tag:"div",classes:["tox-chevron"]},components:[(a="chevron-right",i=n.shared.providers.icons,((e,t,o)=>ry(e,{tag:"span",classes:["tox-tree__icon-wrap","tox-icon"],behaviours:[]},t))(a,i))]},$T(e.title)];var a,i;s.each((e=>{r.push(e)}));const l=t=>{kl(t.element,".tox-tree--directory").each((o=>{t.getSystem().getByDom(o).each((o=>{const n=!Wh.isOn(o);Wh.toggle(o),Lr(t,"expand-tree-node",{expanded:n,node:e.id})}))}))};return zb.sketch({dom:{tag:"div",classes:["tox-tree--directory__label","tox-trbtn"].concat(t?["tox-tree--directory__label--visible"]:[])},components:r,action:l,eventOrder:{[er()]:[YT,"keying"]},buttonBehaviours:ma([...t?[Ub.config({})]:[],Mh(YT,[Gr(er(),((e,t)=>{const n="ArrowRight"===t.event.raw.code,s="ArrowLeft"===t.event.raw.code;n&&o&&t.stop(),(n||s)&&kl(e.element,".tox-tree--directory").each((o=>{e.getSystem().getByDom(o).each((o=>{!Wh.isOn(o)&&n||Wh.isOn(o)&&s?(l(e),t.stop()):s&&!Wh.isOn(o)&&(kl(o.element,".tox-tree--directory").each((e=>{Ol(e,".tox-tree--directory__label").each((e=>{o.getSystem().getByDom(e).each(Rh.focus)}))})),t.stop())}))}))}))])])})},KT=({children:e,onLeafAction:t,visible:o,treeId:n,expandedIds:s,selectedId:r,backstage:a})=>({dom:{tag:"div",classes:["tox-tree--directory__children"]},components:e.map((e=>"leaf"===e.type?qT({leaf:e,selectedId:r,onLeafAction:t,visible:o,treeId:n,backstage:a}):QT({directory:e,expandedIds:s,selectedId:r,onLeafAction:t,labelTabstopping:o,treeId:n,backstage:a}))),behaviours:ma([PT.config({dimension:{property:"height"},closedClass:"tox-tree--directory__children--closed",openClass:"tox-tree--directory__children--open",growingClass:"tox-tree--directory__children--growing",shrinkingClass:"tox-tree--directory__children--shrinking",expanded:o}),Ah.config({})])}),JT=Bi("directory-event-id"),QT=({directory:e,onLeafAction:t,labelTabstopping:o,treeId:n,backstage:s,expandedIds:r,selectedId:a})=>{const{children:i}=e,l=on(r),c=r.includes(e.id);return{dom:{tag:"div",classes:["tox-tree--directory"],attributes:{role:"treeitem"}},components:[XT({directory:e,visible:o,noChildren:0===e.children.length,backstage:s}),KT({children:i,expandedIds:r,selectedId:a,onLeafAction:t,visible:c,treeId:n,backstage:s})],behaviours:ma([Mh(JT,[ea(((e,t)=>{Wh.set(e,c)})),Gr("expand-tree-node",((e,t)=>{const{expanded:o,node:n}=t.event;l.set(o?[...l.get(),n]:l.get().filter((e=>e!==n)))}))]),Wh.config({...e.children.length>0?{aria:{mode:"expanded"}}:{},toggleClass:"tox-tree--directory--expanded",onToggled:(e,o)=>{const r=e.components()[1],c=(d=o,i.map((e=>"leaf"===e.type?qT({leaf:e,selectedId:a,onLeafAction:t,visible:d,treeId:n,backstage:s}):QT({directory:e,expandedIds:l.get(),selectedId:a,onLeafAction:t,labelTabstopping:d,treeId:n,backstage:s}))));var d;o?PT.grow(r):PT.shrink(r),Ah.set(r,c)}})])}},ZT=Bi("tree-event-id");var eE=Object.freeze({__proto__:null,events:(e,t)=>{const o=e.stream.streams.setup(e,t);return Wr([Gr(e.event,o),ta((()=>t.cancel()))].concat(e.cancelEvent.map((e=>[Gr(e,(()=>t.cancel()))])).getOr([])))}});const tE=e=>{const t=on(null);return ua({readState:()=>({timer:null!==t.get()?"set":"unset"}),setTimer:e=>{t.set(e)},cancel:()=>{const e=t.get();null!==e&&e.cancel()}})};var oE=Object.freeze({__proto__:null,throttle:tE,init:e=>e.stream.streams.state(e)}),nE=[ls("stream",os("mode",{throttle:[is("delay"),Cs("stopEvent",!0),Ci("streams",{setup:(e,t)=>{const o=e.stream,n=A_(e.onStream,o.delay);return t.setTimer(n),(e,t)=>{n.throttle(e,t),o.stopEvent&&t.stop()}},state:tE})]})),Cs("event","input"),fs("cancelEvent"),Si("onStream")];const sE=pa({fields:nE,name:"streaming",active:eE,state:oE}),rE=(e,t,o)=>{const n=qu.getValue(o);qu.setValue(t,n),iE(t)},aE=(e,t)=>{const o=e.element,n=ol(o),s=o.dom;"number"!==_t(o,"type")&&t(s,n)},iE=e=>{aE(e,((e,t)=>e.setSelectionRange(t.length,t.length)))},lE=x("alloy.typeahead.itemexecute"),cE=x([fs("lazySink"),is("fetch"),Cs("minChars",5),Cs("responseTime",1e3),xi("onOpen"),Cs("getHotspot",A.some),Cs("getAnchorOverrides",x({})),Cs("layouts",A.none()),Cs("eventOrder",{}),Bs("model",{},[Cs("getDisplayText",(e=>void 0!==e.meta&&void 0!==e.meta.text?e.meta.text:e.value)),Cs("selectsOver",!0),Cs("populateFromBrowse",!0)]),xi("onSetValue"),wi("onExecute"),xi("onItemExecute"),Cs("inputClasses",[]),Cs("inputAttributes",{}),Cs("inputStyles",{}),Cs("matchWidth",!0),Cs("useMinWidth",!1),Cs("dismissOnBlur",!0),vi(["openClass"]),fs("initialData"),fs("listRole"),Yu("typeaheadBehaviours",[Rh,qu,sE,xh,Wh,tk]),rs("lazyTypeaheadComp",(()=>on(A.none))),rs("previewing",(()=>on(!0)))].concat(Ay()).concat(vk())),dE=x([Sm({schema:[bi()],name:"menu",overrides:e=>({fakeFocus:!0,onHighlightItem:(t,o,n)=>{e.previewing.get()?e.lazyTypeaheadComp.get().each((t=>{((e,t,o)=>{if(e.selectsOver){const n=qu.getValue(t),s=e.getDisplayText(n),r=qu.getValue(o);return 0===e.getDisplayText(r).indexOf(s)?A.some((()=>{rE(0,t,o),((e,t)=>{aE(e,((e,o)=>e.setSelectionRange(t,o.length)))})(t,s.length)})):A.none()}return A.none()})(e.model,t,n).fold((()=>{e.model.selectsOver?(Cg.dehighlight(o,n),e.previewing.set(!0)):e.previewing.set(!1)}),(t=>{t(),e.previewing.set(!1)}))})):e.lazyTypeaheadComp.get().each((t=>{e.model.populateFromBrowse&&rE(e.model,t,n),Tt(n.element,"id").each((e=>Ct(t.element,"aria-activedescendant",e)))}))},onExecute:(t,o)=>e.lazyTypeaheadComp.get().map((e=>(Lr(e,lE(),{item:o}),!0))),onHover:(t,o)=>{e.previewing.set(!1),e.lazyTypeaheadComp.get().each((t=>{e.model.populateFromBrowse&&rE(e.model,t,o)}))}})})]),uE=Km({name:"Typeahead",configFields:cE(),partFields:dE(),factory:(e,t,o,n)=>{const s=(t,o,s)=>{e.previewing.set(!1);const r=tk.getCoupled(t,"sandbox");if(Tu.isOpen(r))eg.getCurrent(r).each((e=>{Cg.getHighlighted(e).fold((()=>{s(e)}),(()=>{Ur(r,e.element,"keydown",o)}))}));else{const o=e=>{eg.getCurrent(e).each(s)};uk(e,a(t),t,r,n,o,vf.HighlightMenuAndItem).get(b)}},r=My(e),a=e=>t=>t.map((t=>{const o=he(t.menus),n=q(o,(e=>P(e.items,(e=>"item"===e.type))));return qu.getState(e).update(L(n,(e=>e.data))),t})),i=e=>eg.getCurrent(e),l="typeaheadevents",c=[Rh.config({}),qu.config({onSetValue:e.onSetValue,store:{mode:"dataset",getDataKey:e=>ol(e.element),getFallbackEntry:e=>({value:e,meta:{}}),setValue:(t,o)=>{nl(t.element,e.model.getDisplayText(o))},...e.initialData.map((e=>Fs("initialValue",e))).getOr({})}}),sE.config({stream:{mode:"throttle",delay:e.responseTime,stopEvent:!1},onStream:(t,o)=>{const s=tk.getCoupled(t,"sandbox");if(Rh.isFocused(t)&&ol(t.element).length>=e.minChars){const o=i(s).bind((e=>Cg.getHighlighted(e).map(qu.getValue)));e.previewing.set(!0);const r=t=>{i(s).each((t=>{o.fold((()=>{e.model.selectsOver&&Cg.highlightFirst(t)}),(e=>{Cg.highlightBy(t,(t=>qu.getValue(t).value===e.value)),Cg.getHighlighted(t).orThunk((()=>(Cg.highlightFirst(t),A.none())))}))}))};uk(e,a(t),t,s,n,r,vf.HighlightJustMenu).get(b)}},cancelEvent:xr()}),xh.config({mode:"special",onDown:(e,t)=>(s(e,t,Cg.highlightFirst),A.some(!0)),onEscape:e=>{const t=tk.getCoupled(e,"sandbox");return Tu.isOpen(t)?(Tu.close(t),A.some(!0)):A.none()},onUp:(e,t)=>(s(e,t,Cg.highlightLast),A.some(!0)),onEnter:t=>{const o=tk.getCoupled(t,"sandbox"),n=Tu.isOpen(o);if(n&&!e.previewing.get())return i(o).bind((e=>Cg.getHighlighted(e))).map((e=>(Lr(t,lE(),{item:e}),!0)));{const s=qu.getValue(t);return zr(t,xr()),e.onExecute(o,t,s),n&&Tu.close(o),A.some(!0)}}}),Wh.config({toggleClass:e.markers.openClass,aria:{mode:"expanded"}}),tk.config({others:{sandbox:t=>fk(e,t,{onOpen:()=>Wh.on(t),onClose:()=>{e.lazyTypeaheadComp.get().each((e=>At(e.element,"aria-activedescendant"))),Wh.off(t)}})}}),Mh(l,[ea((t=>{e.lazyTypeaheadComp.set(A.some(t))})),ta((t=>{e.lazyTypeaheadComp.set(A.none())})),na((t=>{const o=b;gk(e,a(t),t,n,o,vf.HighlightMenuAndItem).get(b)})),Gr(lE(),((t,o)=>{const n=tk.getCoupled(t,"sandbox");rE(e.model,t,o.event.item),zr(t,xr()),e.onItemExecute(t,n,o.event.item,qu.getValue(t)),Tu.close(n),iE(t)}))].concat(e.dismissOnBlur?[Gr(mr(),(e=>{const t=tk.getCoupled(e,"sandbox");yc(t.element).isNone()&&Tu.close(t)}))]:[]))],d={[Tr()]:[qu.name(),sE.name(),l],...e.eventOrder};return{uid:e.uid,dom:By(wn(e,{inputAttributes:{role:"combobox","aria-autocomplete":"list","aria-haspopup":"true"}})),behaviours:{...r,...Ku(e.typeaheadBehaviours,c)},eventOrder:d}}}),mE=e=>({...e,toCached:()=>mE(e.toCached()),bindFuture:t=>mE(e.bind((e=>e.fold((e=>ik(dn.error(e))),(e=>t(e)))))),bindResult:t=>mE(e.map((e=>e.bind(t)))),mapResult:t=>mE(e.map((e=>e.map(t)))),mapError:t=>mE(e.map((e=>e.mapError(t)))),foldResult:(t,o)=>e.map((e=>e.fold(t,o))),withTimeout:(t,o)=>mE(ak((n=>{let s=!1;const r=setTimeout((()=>{s=!0,n(dn.error(o()))}),t);e.get((e=>{s||(clearTimeout(r),n(e))}))})))}),gE=e=>mE(ak(e)),pE=(e,t,o=[],n,s,r,a)=>{const i=t.fold((()=>({})),(e=>({action:e}))),l={buttonBehaviours:ma([uw((()=>!e.enabled||a.isDisabled())),dw(),Ub.config({}),...r.map((e=>Zb.config(a.tooltips.getConfig({tooltipText:a.translate(e)})))).toArray(),Mh("button press",[$r("click"),$r("mousedown")])].concat(o)),eventOrder:{click:["button press","alloy.base.behaviour"],mousedown:["button press","alloy.base.behaviour"]},...i},c=wn(l,{dom:n});return wn(c,{components:s})},hE=(e,t,o,n=[],s)=>{const r={tag:"button",classes:["tox-tbtn"],attributes:{...e.tooltip.map((e=>({"aria-label":o.translate(e)}))).getOr({}),"data-mce-name":s}},a=e.icon.map((e=>nT(e,o.icons))),i=yw([a]);return pE(e,t,n,r,i,e.tooltip,o)},fE=e=>{switch(e){case"primary":return["tox-button"];case"toolbar":return["tox-tbtn"];default:return["tox-button","tox-button--secondary"]}},bE=(e,t,o,n=[],s=[])=>{const r=o.translate(e.text),a=e.icon.map((e=>nT(e,o.icons))),i=[a.getOrThunk((()=>ul(r)))],l=e.buttonType.getOr(e.primary||e.borderless?"primary":"secondary"),c={tag:"button",classes:[...fE(l),...a.isSome()?["tox-button--icon"]:[],...e.borderless?["tox-button--naked"]:[],...s],attributes:{"aria-label":r,"data-mce-name":e.text}},d=e.icon.map(x(r));return pE(e,t,n,c,i,d,o)},vE=(e,t,o,n=[],s=[])=>{const r=bE(e,A.some(t),o,n,s);return zb.sketch(r)},yE=(e,t)=>o=>{"custom"===t?Lr(o,tC,{name:e,value:{}}):"submit"===t?zr(o,oC):"cancel"===t?zr(o,eC):console.error("Unknown button type: ",t)},xE=(e,t,o)=>{if(((e,t)=>"menu"===t)(0,t)){const t=()=>r,n=e,s={...e,type:"menubutton",search:A.none(),onSetup:t=>(t.setEnabled(e.enabled),b),fetch:jT(n.items,t,o)},r=Vb(WT(s,"tox-tbtn",o,A.none(),!0,e.text.or(e.tooltip).getOrUndefined()));return r.asSpec()}if(((e,t)=>"custom"===t||"cancel"===t||"submit"===t)(0,t)){const n=yE(e.name,t),s={...e,borderless:!1};return vE(s,n,o.shared.providers,[])}if(((e,t)=>"togglebutton"===t)(0,t))return((e,t,o)=>{var n,s;const r=e.icon.map((e=>sT(e,t.icons))).map(Vb),a=e.buttonType.getOr(e.primary?"primary":"secondary"),i={...e,name:null!==(n=e.name)&&void 0!==n?n:"",primary:"primary"===a,tooltip:e.tooltip,enabled:null!==(s=e.enabled)&&void 0!==s&&s,borderless:!1},l=i.tooltip.or(e.text).map((e=>({"aria-label":t.translate(e)}))).getOr({}),c=fE(null!=a?a:"secondary"),d=e.icon.isSome()&&e.text.isSome(),u={tag:"button",classes:[...c.concat(e.icon.isSome()?["tox-button--icon"]:[]),...e.active?["tox-button--enabled"]:[],...d?["tox-button--icon-and-text"]:[]],attributes:{...l,...g(o)?{"data-mce-name":o}:{}}},m=t.translate(e.text.getOr("")),p=ul(m),h=[...yw([r.map((e=>e.asSpec()))]),...e.text.isSome()?[p]:[]],f=pE(i,A.some((o=>{Lr(o,tC,{name:e.name,value:{setIcon:e=>{r.map((n=>n.getOpt(o).each((o=>{Ah.set(o,[sT(e,t.icons)])}))))}}})})),[],u,h,e.tooltip,t);return zb.sketch(f)})(e,o.shared.providers,e.text.or(e.tooltip).getOrUndefined());throw console.error("Unknown footer button type: ",t),new Error("Unknown footer button type")},wE={type:"separator"},SE=e=>({type:"menuitem",value:e.url,text:e.title,meta:{attach:e.attach},onAction:b}),kE=(e,t)=>({type:"menuitem",value:t,text:e,meta:{attach:void 0},onAction:b}),CE=(e,t)=>(e=>L(e,SE))(((e,t)=>P(t,(t=>t.type===e)))(e,t)),OE=e=>CE("header",e.targets),_E=e=>CE("anchor",e.targets),TE=e=>A.from(e.anchorTop).map((e=>kE("<top>",e))).toArray(),EE=e=>A.from(e.anchorBottom).map((e=>kE("<bottom>",e))).toArray(),AE=(e,t)=>{const o=e.toLowerCase();return P(t,(e=>{var t;const n=void 0!==e.meta&&void 0!==e.meta.text?e.meta.text:e.text,s=null!==(t=e.value)&&void 0!==t?t:"";return _e(n.toLowerCase(),o)||_e(s.toLowerCase(),o)}))},ME=Bi("aria-invalid"),DE=(e,t)=>{e.dom.checked=t},BE=e=>e.dom.checked,IE=e=>(t,o,n,s,r)=>fe(o,"name").fold((()=>e(o,s,A.none(),r)),(a=>t.field(a,e(o,s,fe(n,a),r)))),FE={bar:IE(((e,t)=>((e,t)=>({dom:{tag:"div",classes:["tox-bar","tox-form__controls-h-stack"]},components:L(e.items,t.interpreter)}))(e,t.shared))),collection:IE(((e,t,o)=>iC(e,t.shared.providers,o))),alertbanner:IE(((e,t)=>((e,t)=>{const o=oy(e.icon,t.icons);return Uk.sketch({dom:{tag:"div",attributes:{role:"alert"},classes:["tox-notification","tox-notification--in",`tox-notification--${e.level}`]},components:[{dom:{tag:"div",classes:["tox-notification__icon"],innerHtml:e.url?void 0:o},components:e.url?[zb.sketch({dom:{tag:"button",classes:["tox-button","tox-button--naked","tox-button--icon"],innerHtml:o,attributes:{title:t.translate(e.iconTooltip)}},action:t=>Lr(t,tC,{name:"alert-banner",value:e.url}),buttonBehaviours:ma([ny()])})]:void 0},{dom:{tag:"div",classes:["tox-notification__body"],innerHtml:t.translate(e.text)}}]})})(e,t.shared.providers))),input:IE(((e,t,o)=>((e,t,o)=>OT({name:e.name,multiline:!1,label:e.label,inputMode:e.inputMode,placeholder:e.placeholder,flex:!1,disabled:!e.enabled,classname:"tox-textfield",validation:A.none(),maximized:e.maximized,data:o},t))(e,t.shared.providers,o))),textarea:IE(((e,t,o)=>((e,t,o)=>OT({name:e.name,multiline:!0,label:e.label,inputMode:A.none(),placeholder:e.placeholder,flex:!0,disabled:!e.enabled,classname:"tox-textarea",validation:A.none(),maximized:e.maximized,data:o},t))(e,t.shared.providers,o))),label:IE(((e,t,o,n)=>((e,t,o)=>{const n="tox-label",s="center"===e.align?[`${n}--center`]:[],r="end"===e.align?[`${n}--end`]:[],a=Vb({dom:{tag:"label",classes:[n,...s,...r]},components:[ul(t.providers.translate(e.label))]}),i=L(e.items,t.interpreter);return{dom:{tag:"div",classes:["tox-form__group"]},components:[a.asSpec(),...i],behaviours:ma([v_(),Ah.config({}),(l=A.none(),k_(l,si,ri)),xh.config({mode:"acyclic"}),Mh("label",[ea((t=>{e.for.each((e=>{o(e).each((e=>{a.getOpt(t).each((t=>{var o;const n=null!==(o=_t(e.element,"id"))&&void 0!==o?o:Bi("form-field");Ct(e.element,"id",n),Ct(t.element,"for",n)}))}))}))}))])])};var l})(e,t.shared,n))),iframe:(iM=(e,t,o)=>((e,t,o)=>{const n="tox-dialog__iframe",s=e.transparent?[]:[`${n}--opaque`],r=e.border?["tox-navobj-bordered"]:[],a={...e.label.map((e=>({title:e}))).getOr({}),...o.map((e=>({srcdoc:e}))).getOr({}),...e.sandboxed?{sandbox:"allow-scripts allow-same-origin"}:{}},i=((e,t)=>{const o=on(e.getOr(""));return{getValue:e=>o.get(),setValue:(e,n)=>{if(o.get()!==n){const o=e.element,s=()=>Ct(o,"srcdoc",n);t?J_.fold(x(K_),(e=>e.throttle))(o,n,s):s()}o.set(n)}}})(o,e.streamContent),l=e.label.map((e=>Jk(e,t))),c=Gk.parts.field({factory:{sketch:e=>I_(A.from(r),{uid:e.uid,dom:{tag:"iframe",attributes:a,classes:[n,...s]},behaviours:ma([Ub.config({}),Rh.config({}),S_(o,i.getValue,i.setValue),gc.config({channels:{[U_]:{onReceive:(e,t)=>{t.newFocus.each((t=>{at(e.element).each((o=>{(Ze(e.element,t)?ka:Oa)(o,"tox-navobj-bordered-focus")}))}))}}}})])})}});return Yk(l,c,["tox-form__group--stretched"],[])})(e,t.shared.providers,o),(e,t,o,n,s)=>{const r=wn(t,{source:"dynamic"});return IE(iM)(e,r,o,n,s)}),button:IE(((e,t)=>((e,t)=>{const o=yE(e.name,"custom");return n=A.none(),s=Gk.parts.field({factory:zb,...bE(e,A.some(o),t,[C_(""),v_()])}),Yk(n,s,[],[]);var n,s})(e,t.shared.providers))),checkbox:IE(((e,t,o)=>((e,t,o)=>{const n=e=>(e.element.dom.click(),A.some(!0)),s=Gk.parts.field({factory:{sketch:w},dom:{tag:"input",classes:["tox-checkbox__input"],attributes:{type:"checkbox"}},behaviours:ma([v_(),pg.config({disabled:()=>!e.enabled||t.isDisabled(),onDisabled:e=>{at(e.element).each((e=>ka(e,"tox-checkbox--disabled")))},onEnabled:e=>{at(e.element).each((e=>Oa(e,"tox-checkbox--disabled")))}}),Ub.config({}),Rh.config({}),k_(o,BE,DE),xh.config({mode:"special",onEnter:n,onSpace:n,stopSpaceKeyup:!0}),Mh("checkbox-events",[Gr(nr(),((t,o)=>{Lr(t,Qk,{name:e.name})}))])])}),r=Gk.parts.label({dom:{tag:"span",classes:["tox-checkbox__label"]},components:[ul(t.translate(e.label))],behaviours:ma([vC.config({})])}),a=e=>ry("checked"===e?"selected":"unselected",{tag:"span",classes:["tox-icon","tox-checkbox-icon__"+e]},t.icons),i=Vb({dom:{tag:"div",classes:["tox-checkbox__icons"]},components:[a("checked"),a("unchecked")]});return Gk.sketch({dom:{tag:"label",classes:["tox-checkbox"]},components:[s,i.asSpec(),r],fieldBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled()}),dw()])})})(e,t.shared.providers,o))),colorinput:IE(((e,t,o)=>((e,t,o,n)=>{const s=Gk.parts.field({factory:Iy,inputClasses:["tox-textfield"],data:n,onSetValue:e=>bC.run(e).get(b),inputBehaviours:ma([pg.config({disabled:t.providers.isDisabled}),dw(),Ub.config({}),bC.config({invalidClass:"tox-textbox-field-invalid",getRoot:e=>at(e.element),notify:{onValid:e=>{const t=qu.getValue(e);Lr(e,yC,{color:t})}},validator:{validateOnLoad:!1,validate:e=>{const t=qu.getValue(e);if(0===t.length)return ik(dn.value(!0));{const e=Re("span");Bt(e,"background-color",t);const o=zt(e,"background-color").fold((()=>dn.error("blah")),(e=>dn.value(t)));return ik(o)}}}})]),selectOnFocus:!1}),r=e.label.map((e=>Jk(e,t.providers))),a=(e,t)=>{Lr(e,xC,{value:t})},i=Vb(((e,t)=>wk.sketch({dom:e.dom,components:e.components,toggleClass:"mce-active",dropdownBehaviours:ma([uw(t.providers.isDisabled),dw(),vC.config({}),Ub.config({})]),layouts:e.layouts,sandboxClasses:["tox-dialog__popups"],lazySink:t.getSink,fetch:o=>ak((t=>e.fetch(t))).map((n=>A.from(Ak(wn(US(Bi("menu-value"),n,(t=>{e.onItemAction(o,t)}),e.columns,e.presets,dy.CLOSE_ON_EXECUTE,T,t.providers),{movement:jS(e.columns,e.presets)}))))),parts:{menu:Ey(0,0,e.presets)}}))({dom:{tag:"span",attributes:{"aria-label":t.providers.translate("Color swatch")}},layouts:{onRtl:()=>[Ql,Jl,oc],onLtr:()=>[Jl,Ql,oc]},components:[],fetch:FS(o.getColors(e.storageKey),e.storageKey,o.hasCustomColors()),columns:o.getColorCols(e.storageKey),presets:"color",onItemAction:(t,n)=>{i.getOpt(t).each((t=>{"custom"===n?o.colorPicker((o=>{o.fold((()=>zr(t,wC)),(o=>{a(t,o),gS(e.storageKey,o)}))}),"#ffffff"):a(t,"remove"===n?"":n)}))}},t));return Gk.sketch({dom:{tag:"div",classes:["tox-form__group"]},components:r.toArray().concat([{dom:{tag:"div",classes:["tox-color-input"]},components:[s,i.asSpec()]}]),fieldBehaviours:ma([Mh("form-field-events",[Gr(yC,((t,o)=>{i.getOpt(t).each((e=>{Bt(e.element,"background-color",o.event.color)})),Lr(t,Qk,{name:e.name})})),Gr(xC,((e,t)=>{Gk.getField(e).each((o=>{qu.setValue(o,t.event.value),eg.getCurrent(e).each(Rh.focus)}))})),Gr(wC,((e,t)=>{Gk.getField(e).each((t=>{eg.getCurrent(e).each(Rh.focus)}))}))])])})})(e,t.shared,t.colorinput,o))),colorpicker:IE(((e,t,o)=>((e,t,o)=>{const n=e=>"tox-"+e,s=b_((e=>t=>r(t)?e.translate(O_[t]):e.translate(t))(t),n),a=Vb(s.sketch({dom:{tag:"div",classes:[n("color-picker-container")],attributes:{role:"presentation"}},onValidHex:e=>{Lr(e,tC,{name:"hex-valid",value:!0})},onInvalidHex:e=>{Lr(e,tC,{name:"hex-valid",value:!1})}}));return{dom:{tag:"div"},components:[a.asSpec()],behaviours:ma([S_(o,(e=>{const t=a.get(e);return eg.getCurrent(t).bind((e=>qu.getValue(e).hex)).map((e=>"#"+Oe(e,"#"))).getOr("")}),((e,t)=>{const o=A.from(/^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/.exec(t)).bind((e=>ee(e,1))),n=a.get(e);eg.getCurrent(n).fold((()=>{console.log("Can not find form")}),(e=>{qu.setValue(e,{hex:o.getOr("")}),u_.getField(e,"hex").each((e=>{zr(e,or())}))}))})),v_()])}})(0,t.shared.providers,o))),dropzone:IE(((e,t,o)=>((e,t,o)=>{const n=(e,t)=>{t.stop()},s=e=>(t,o)=>{V(e,(e=>{e(t,o)}))},r=(e,t)=>{var o;if(!pg.isDisabled(e)){const n=t.event.raw;i(e,null===(o=n.dataTransfer)||void 0===o?void 0:o.files)}},a=(e,t)=>{const o=t.event.raw.target;i(e,o.files)},i=(o,n)=>{n&&(qu.setValue(o,((e,t)=>{const o=E_.explode(t.getOption("images_file_types"));return P(ne(e),(e=>R(o,(t=>Ee(e.name.toLowerCase(),`.${t.toLowerCase()}`)))))})(n,t)),Lr(o,Qk,{name:e.name}))},l=Vb({dom:{tag:"input",attributes:{type:"file",accept:"image/*"},styles:{display:"none"}},behaviours:ma([Mh("input-file-events",[Jr(sr()),Jr(br())])])}),c=e.label.map((e=>Jk(e,t))),d=Gk.parts.field({factory:{sketch:e=>({uid:e.uid,dom:{tag:"div",classes:["tox-dropzone-container"]},behaviours:ma([C_(o.getOr([])),v_(),pg.config({}),Wh.config({toggleClass:"dragenter",toggleOnExecute:!1}),Mh("dropzone-events",[Gr("dragenter",s([n,Wh.toggle])),Gr("dragleave",s([n,Wh.toggle])),Gr("dragover",n),Gr("drop",s([n,r])),Gr(nr(),a)])]),components:[{dom:{tag:"div",classes:["tox-dropzone"],styles:{}},components:[{dom:{tag:"p"},components:[ul(t.translate("Drop an image here"))]},zb.sketch({dom:{tag:"button",styles:{position:"relative"},classes:["tox-button","tox-button--secondary"]},components:[ul(t.translate("Browse for an image")),l.asSpec()],action:e=>{l.get(e).element.dom.click()},buttonBehaviours:ma([Ub.config({}),uw(t.isDisabled),dw()])})]}]})}});return Yk(c,d,["tox-form__group--stretched"],[])})(e,t.shared.providers,o))),grid:IE(((e,t)=>((e,t)=>({dom:{tag:"div",classes:["tox-form__grid",`tox-form__grid--${e.columns}col`]},components:L(e.items,t.interpreter)}))(e,t.shared))),listbox:IE(((e,t,o)=>((e,t,o)=>{const n=R(e.items,(e=>!gT(e))),s=t.shared.providers,r=o.bind((t=>fT(e.items,t))).orThunk((()=>te(e.items).filter(gT))),a=e.label.map((e=>Jk(e,s))),i=Gk.parts.field({dom:{},factory:{sketch:o=>lT({uid:o.uid,text:r.map((e=>e.text)),icon:A.none(),tooltip:A.none(),role:ke(!n,"combobox"),...n?{}:{listRole:"listbox"},ariaLabel:e.label,fetch:(o,s)=>{const r=hT(o,e.name,e.items,qu.getValue(o),n);s(mT(r,dy.CLOSE_ON_EXECUTE,t,{isHorizontalMenu:!1,search:A.none()}))},onSetup:x(b),getApi:x({}),columns:1,presets:"normal",classes:[],dropdownBehaviours:[Ub.config({}),S_(r.map((e=>e.value)),(e=>_t(e.element,pT)),((t,o)=>{fT(e.items,o).each((e=>{Ct(t.element,pT,e.value),Lr(t,aT,{text:e.text})}))}))]},"tox-listbox",t.shared)}}),l={dom:{tag:"div",classes:["tox-listboxfield"]},components:[i]};return Gk.sketch({dom:{tag:"div",classes:["tox-form__group"]},components:G([a.toArray(),[l]]),fieldBehaviours:ma([pg.config({disabled:x(!e.enabled),onDisabled:e=>{Gk.getField(e).each(pg.disable)},onEnabled:e=>{Gk.getField(e).each(pg.enable)}})])})})(e,t,o))),selectbox:IE(((e,t,o)=>((e,t,o)=>{const n=L(e.items,(e=>({text:t.translate(e.text),value:e.value}))),s=e.label.map((e=>Jk(e,t))),r=Gk.parts.field({dom:{},...o.map((e=>({data:e}))).getOr({}),selectAttributes:{size:e.size},options:n,factory:bT,selectBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled()}),Ub.config({}),Mh("selectbox-change",[Gr(nr(),((t,o)=>{Lr(t,Qk,{name:e.name})}))])])}),a=e.size>1?A.none():A.some(ry("chevron-down",{tag:"div",classes:["tox-selectfield__icon-js"]},t.icons)),i={dom:{tag:"div",classes:["tox-selectfield"]},components:G([[r],a.toArray()])};return Gk.sketch({dom:{tag:"div",classes:["tox-form__group"]},components:G([s.toArray(),[i]]),fieldBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled(),onDisabled:e=>{Gk.getField(e).each(pg.disable)},onEnabled:e=>{Gk.getField(e).each(pg.enable)}}),dw()])})})(e,t.shared.providers,o))),sizeinput:IE(((e,t)=>((e,t)=>{let o=CT;const n=Bi("ratio-event"),s=e=>ry(e,{tag:"span",classes:["tox-icon","tox-lock-icon__"+e]},t.icons),r=e.label.getOr("Constrain proportions"),a=t.translate(r),i=wT.parts.lock({dom:{tag:"button",classes:["tox-lock","tox-button","tox-button--naked","tox-button--icon"],attributes:{"aria-label":a,"data-mce-name":r}},components:[s("lock"),s("unlock")],buttonBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled()}),dw(),Ub.config({}),Zb.config(t.tooltips.getConfig({tooltipText:a}))])}),l=e=>({dom:{tag:"div",classes:["tox-form__group"]},components:e}),c=o=>Gk.parts.field({factory:Iy,inputClasses:["tox-textfield"],inputBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled()}),dw(),Ub.config({}),Mh("size-input-events",[Gr(Qs(),((e,t)=>{Lr(e,n,{isField1:o})})),Gr(nr(),((t,o)=>{Lr(t,Qk,{name:e.name})}))])]),selectOnFocus:!1}),d=e=>({dom:{tag:"label",classes:["tox-label"]},components:[ul(t.translate(e))]}),u=wT.parts.field1(l([Gk.parts.label(d("Width")),c(!0)])),m=wT.parts.field2(l([Gk.parts.label(d("Height")),c(!1)]));return wT.sketch({dom:{tag:"div",classes:["tox-form__group"]},components:[{dom:{tag:"div",classes:["tox-form__controls-h-stack"]},components:[u,m,l([d("\xa0"),i])]}],field1Name:"width",field2Name:"height",locked:!0,markers:{lockClass:"tox-locked"},onLockedChange:(e,t,n)=>{ST(qu.getValue(e)).each((e=>{o(e).each((e=>{qu.setValue(t,(e=>{const t={"":0,px:0,pt:1,mm:1,pc:2,ex:2,em:2,ch:2,rem:2,cm:3,in:4,"%":4};let o=e.value.toFixed((n=e.unit)in t?t[n]:1);var n;return-1!==o.indexOf(".")&&(o=o.replace(/\.?0*$/,"")),o+e.unit})(e))}))}))},coupledFieldBehaviours:ma([pg.config({disabled:()=>!e.enabled||t.isDisabled(),onDisabled:e=>{wT.getField1(e).bind(Gk.getField).each(pg.disable),wT.getField2(e).bind(Gk.getField).each(pg.disable),wT.getLock(e).each(pg.disable)},onEnabled:e=>{wT.getField1(e).bind(Gk.getField).each(pg.enable),wT.getField2(e).bind(Gk.getField).each(pg.enable),wT.getLock(e).each(pg.enable)}}),dw(),Mh("size-input-events2",[Gr(n,((e,t)=>{const n=t.event.isField1,s=n?wT.getField1(e):wT.getField2(e),r=n?wT.getField2(e):wT.getField1(e),a=s.map(qu.getValue).getOr(""),i=r.map(qu.getValue).getOr("");o=((e,t)=>{const o=ST(e).toOptional(),n=ST(t).toOptional();return we(o,n,((e,t)=>kT(e,t.unit).map((e=>t.value/e)).map((e=>{return o=e,n=t.unit,e=>kT(e,n).map((e=>({value:e*o,unit:n})));var o,n})).getOr(CT))).getOr(CT)})(a,i)}))])])})})(e,t.shared.providers))),slider:IE(((e,t,o)=>((e,t,o)=>{const n=n_.parts.label({dom:{tag:"label",classes:["tox-label"]},components:[ul(t.translate(e.label))]}),s=n_.parts.spectrum({dom:{tag:"div",classes:["tox-slider__rail"],attributes:{role:"presentation"}}}),r=n_.parts.thumb({dom:{tag:"div",classes:["tox-slider__handle"],attributes:{role:"presentation"}}});return n_.sketch({dom:{tag:"div",classes:["tox-slider"],attributes:{role:"presentation"}},model:{mode:"x",minX:e.min,maxX:e.max,getInitialValue:x(o.getOrThunk((()=>(Math.abs(e.max)-Math.abs(e.min))/2)))},components:[n,s,r],sliderBehaviours:ma([v_(),Rh.config({})]),onChoose:(t,o,n)=>{Lr(t,Qk,{name:e.name,value:n})},onChange:(t,o,n)=>{Lr(t,Qk,{name:e.name,value:n})}})})(e,t.shared.providers,o))),urlinput:IE(((e,t,o)=>((e,t,o,n)=>{const s=t.shared.providers,r=t=>{const n=qu.getValue(t);o.addToHistory(n.value,e.filetype)},a={...n.map((e=>({initialData:e}))).getOr({}),dismissOnBlur:!0,inputClasses:["tox-textfield"],sandboxClasses:["tox-dialog__popups"],inputAttributes:{"aria-errormessage":ME,type:"url"},minChars:0,responseTime:0,fetch:n=>{const s=((e,t,o)=>{var n,s;const r=qu.getValue(t),a=null!==(s=null===(n=null==r?void 0:r.meta)||void 0===n?void 0:n.text)&&void 0!==s?s:r.value;return o.getLinkInformation().fold((()=>[]),(t=>{const n=AE(a,(e=>L(e,(e=>kE(e,e))))(o.getHistory(e)));return"file"===e?(s=[n,AE(a,OE(t)),AE(a,G([TE(t),_E(t),EE(t)]))],W(s,((e,t)=>0===e.length||0===t.length?e.concat(t):e.concat(wE,t)),[])):n;var s}))})(e.filetype,n,o),r=mT(s,dy.BUBBLE_TO_SANDBOX,t,{isHorizontalMenu:!1,search:A.none()});return ik(r)},getHotspot:e=>g.getOpt(e),onSetValue:(e,t)=>{e.hasConfigured(bC)&&bC.run(e).get(b)},typeaheadBehaviours:ma([...o.getValidationHandler().map((t=>bC.config({getRoot:e=>at(e.element),invalidClass:"tox-control-wrap--status-invalid",notify:{onInvalid:(e,t)=>{c.getOpt(e).each((e=>{Ct(e.element,"title",s.translate(t))}))}},validator:{validate:o=>{const n=qu.getValue(o);return gE((o=>{t({type:e.filetype,url:n.value},(e=>{if("invalid"===e.status){const t=dn.error(e.message);o(t)}else{const t=dn.value(e.message);o(t)}}))}))},validateOnLoad:!1}}))).toArray(),pg.config({disabled:()=>!e.enabled||s.isDisabled()}),Ub.config({}),Mh("urlinput-events",[Gr(or(),(t=>{const o=ol(t.element),n=o.trim();n!==o&&nl(t.element,n),"file"===e.filetype&&Lr(t,Qk,{name:e.name})})),Gr(nr(),(t=>{Lr(t,Qk,{name:e.name}),r(t)})),Gr(gr(),(t=>{Lr(t,Qk,{name:e.name}),r(t)}))])]),eventOrder:{[or()]:["streaming","urlinput-events","invalidating"]},model:{getDisplayText:e=>e.value,selectsOver:!1,populateFromBrowse:!1},markers:{openClass:"tox-textfield--popup-open"},lazySink:t.shared.getSink,parts:{menu:Ey(0,0,"normal")},onExecute:(e,t,o)=>{Lr(t,oC,{})},onItemExecute:(t,o,n,s)=>{r(t),Lr(t,Qk,{name:e.name})}},i=Gk.parts.field({...a,factory:uE}),l=e.label.map((e=>Jk(e,s))),c=Vb(((e,t,o=e,n=e)=>ry(o,{tag:"div",classes:["tox-icon","tox-control-wrap__status-icon-"+e],attributes:{title:s.translate(n),"aria-live":"polite",...t.fold((()=>({})),(e=>({id:e})))}},s.icons))("invalid",A.some(ME),"warning")),d=Vb({dom:{tag:"div",classes:["tox-control-wrap__status-icon-wrap"]},components:[c.asSpec()]}),u=o.getUrlPicker(e.filetype),m=Bi("browser.url.event"),g=Vb({dom:{tag:"div",classes:["tox-control-wrap"]},components:[i,d.asSpec()],behaviours:ma([pg.config({disabled:()=>!e.enabled||s.isDisabled()})])}),p=Vb(vE({name:e.name,icon:A.some("browse"),text:e.picker_text.or(e.label).getOr(""),enabled:e.enabled,primary:!1,buttonType:A.none(),borderless:!0},(e=>zr(e,m)),s,[],["tox-browse-url"]));return Gk.sketch({dom:Kk([]),components:l.toArray().concat([{dom:{tag:"div",classes:["tox-form__controls-h-stack"]},components:G([[g.asSpec()],u.map((()=>p.asSpec())).toArray()])}]),fieldBehaviours:ma([pg.config({disabled:()=>!e.enabled||s.isDisabled(),onDisabled:e=>{Gk.getField(e).each(pg.disable),p.getOpt(e).each(pg.disable)},onEnabled:e=>{Gk.getField(e).each(pg.enable),p.getOpt(e).each(pg.enable)}}),dw(),Mh("url-input-events",[Gr(m,(t=>{eg.getCurrent(t).each((o=>{const n=qu.getValue(o),s={fieldname:e.name,...n};u.each((n=>{n(s).get((n=>{qu.setValue(o,n),Lr(t,Qk,{name:e.name})}))}))}))}))])])})})(e,t,t.urlinput,o))),customeditor:IE((e=>{const t=rn(),o=Vb({dom:{tag:e.tag}}),n=rn(),s=!T_(e)&&e.onFocus.isSome()?[Rh.config({onFocus:t=>{e.onFocus.each((e=>{e(t.element.dom)}))}}),Ub.config({})]:[];return{dom:{tag:"div",classes:["tox-custom-editor"]},behaviours:ma([Mh("custom-editor-events",[ea((s=>{o.getOpt(s).each((o=>{(T_(e)?e.init(o.element.dom):__.load(e.scriptId,e.scriptUrl).then((t=>t(o.element.dom,e.settings)))).then((e=>{n.on((t=>{e.setValue(t)})),n.clear(),t.set(e)}))}))}))]),S_(A.none(),(()=>t.get().fold((()=>n.get().getOr("")),(e=>e.getValue()))),((e,o)=>{t.get().fold((()=>n.set(o)),(e=>e.setValue(o)))})),v_()].concat(s)),components:[o.asSpec()]}})),htmlpanel:IE(((e,t)=>((e,t)=>{const o=["tox-form__group",...e.stretched?["tox-form__group--stretched"]:[]],n=Mh("htmlpanel",[ea((t=>{e.onInit(t.element.dom)}))]);return"presentation"===e.presets?Uk.sketch({dom:{tag:"div",classes:o,innerHtml:e.html},containerBehaviours:ma([Zb.config({...t.tooltips.getConfig({tooltipText:"",onShow:e=>{_l(e.element,"[data-mce-tooltip]:hover").orThunk((()=>yc(e.element))).each((o=>{Tt(o,"data-mce-tooltip").each((o=>{Zb.setComponents(e,t.tooltips.getComponents({tooltipText:o}))}))}))}}),mode:"children-normal",anchor:e=>({type:"node",node:_l(e.element,"[data-mce-tooltip]:hover").orThunk((()=>yc(e.element).filter((e=>Tt(e,"data-mce-tooltip").isSome())))),root:e.element,layouts:{onLtr:x([oc,tc,Jl,Zl,Ql,ec]),onRtl:x([oc,tc,Jl,Zl,Ql,ec])},bubble:Gc(0,-2,{})})}),n])}):Uk.sketch({dom:{tag:"div",classes:o,innerHtml:e.html,attributes:{role:"document"}},containerBehaviours:ma([Ub.config({}),Rh.config({}),n])})})(e,t.shared.providers))),imagepreview:IE(((e,t,o)=>((e,t)=>{const o=on(t.getOr({url:""})),n=Vb({dom:{tag:"img",classes:["tox-imagepreview__image"],attributes:t.map((e=>({src:e.url}))).getOr({})}}),s=Vb({dom:{tag:"div",classes:["tox-imagepreview__container"],attributes:{role:"presentation"}},components:[n.asSpec()]}),r={};e.height.each((e=>r.height=e));const a=t.map((e=>({url:e.url,zoom:A.from(e.zoom),cachedWidth:A.from(e.cachedWidth),cachedHeight:A.from(e.cachedHeight)})));return{dom:{tag:"div",classes:["tox-imagepreview"],styles:r,attributes:{role:"presentation"}},components:[s.asSpec()],behaviours:ma([v_(),S_(a,(()=>o.get()),((e,t)=>{const r={url:t.url};t.zoom.each((e=>r.zoom=e)),t.cachedWidth.each((e=>r.cachedWidth=e)),t.cachedHeight.each((e=>r.cachedHeight=e)),o.set(r);const a=()=>{const{cachedWidth:t,cachedHeight:o,zoom:n}=r;if(!u(t)&&!u(o)){if(u(n)){const n=((e,t,o)=>{const n=Qt(e),s=jt(e);return Math.min(n/t,s/o,1)})(e.element,t,o);r.zoom=n}const a=((e,t,o,n,s)=>{const r=o*s,a=n*s,i=Math.max(0,e/2-r/2),l=Math.max(0,t/2-a/2);return{left:i.toString()+"px",top:l.toString()+"px",width:r.toString()+"px",height:a.toString()+"px"}})(Qt(e.element),jt(e.element),t,o,r.zoom);s.getOpt(e).each((e=>{It(e.element,a)}))}};n.getOpt(e).each((o=>{const n=o.element;var s;t.url!==_t(n,"src")&&(Ct(n,"src",t.url),Oa(e.element,"tox-imagepreview__loaded")),a(),(s=n,new Promise(((e,t)=>{const o=()=>{r(),e(s)},n=[Fc(s,"load",o),Fc(s,"error",(()=>{r(),t("Unable to load data from image: "+s.dom.src)}))],r=()=>V(n,(e=>e.unbind()));s.dom.complete&&o()}))).then((t=>{e.getSystem().isConnected()&&(ka(e.element,"tox-imagepreview__loaded"),r.cachedWidth=t.dom.naturalWidth,r.cachedHeight=t.dom.naturalHeight,a())}))}))}))])}})(e,o))),table:IE(((e,t)=>((e,t)=>{const o=e=>({dom:{tag:"td",innerHtml:t.translate(e)}});return{dom:{tag:"table",classes:["tox-dialog__table"]},components:[(s=e.header,{dom:{tag:"thead"},components:[{dom:{tag:"tr"},components:L(s,(e=>({dom:{tag:"th",innerHtml:t.translate(e)}})))}]}),(n=e.cells,{dom:{tag:"tbody"},components:L(n,(e=>({dom:{tag:"tr"},components:L(e,o)})))})],behaviours:ma([Ub.config({}),Rh.config({})])};var n,s})(e,t.shared.providers))),tree:IE(((e,t)=>((e,t)=>{const o=e.onLeafAction.getOr(b),n=e.onToggleExpand.getOr(b),s=e.defaultExpandedIds,r=on(s),a=on(e.defaultSelectedId),i=Bi("tree-id"),l=(n,s)=>e.items.map((e=>"leaf"===e.type?qT({leaf:e,selectedId:n,onLeafAction:o,visible:!0,treeId:i,backstage:t}):QT({directory:e,selectedId:n,onLeafAction:o,expandedIds:s,labelTabstopping:!0,treeId:i,backstage:t})));return{dom:{tag:"div",classes:["tox-tree"],attributes:{role:"tree"}},components:l(a.get(),r.get()),behaviours:ma([xh.config({mode:"flow",selector:".tox-tree--leaf__label--visible, .tox-tree--directory__label--visible",cycles:!1}),Mh(ZT,[Gr("expand-tree-node",((e,t)=>{const{expanded:o,node:s}=t.event;r.set(o?[...r.get(),s]:r.get().filter((e=>e!==s))),n(r.get(),{expanded:o,node:s})}))]),gc.config({channels:{[`update-active-item-${i}`]:{onReceive:(e,t)=>{a.set(A.some(t.value)),Ah.set(e,l(A.some(t.value),r.get()))}}}}),Ah.config({})])}})(e,t))),panel:IE(((e,t)=>((e,t)=>({dom:{tag:"div",classes:e.classes},components:L(e.items,t.shared.interpreter)}))(e,t)))},RE={field:(e,t)=>t,record:x([])},NE=(e,t,o,n,s)=>{const r=wn(n,{shared:{interpreter:t=>zE(e,t,o,r,s)}});return zE(e,t,o,r,s)},zE=(e,t,o,n,s)=>fe(FE,t.type).fold((()=>(console.error(`Unknown factory type "${t.type}", defaulting to container: `,t),t)),(r=>r(e,t,o,n,s))),LE=(e,t,o,n)=>zE(RE,e,t,o,n),VE="layout-inset",HE=e=>e.x,PE=(e,t)=>e.x+e.width/2-t.width/2,UE=(e,t)=>e.x+e.width-t.width,WE=e=>e.y,jE=(e,t)=>e.y+e.height-t.height,$E=(e,t)=>e.y+e.height/2-t.height/2,GE=(e,t,o)=>Dl(UE(e,t),jE(e,t),o.insetSouthwest(),Nl(),"southwest",Wl(e,{right:0,bottom:3}),VE),qE=(e,t,o)=>Dl(HE(e),jE(e,t),o.insetSoutheast(),Rl(),"southeast",Wl(e,{left:1,bottom:3}),VE),YE=(e,t,o)=>Dl(UE(e,t),WE(e),o.insetNorthwest(),Fl(),"northwest",Wl(e,{right:0,top:2}),VE),XE=(e,t,o)=>Dl(HE(e),WE(e),o.insetNortheast(),Il(),"northeast",Wl(e,{left:1,top:2}),VE),KE=(e,t,o)=>Dl(PE(e,t),WE(e),o.insetNorth(),zl(),"north",Wl(e,{top:2}),VE),JE=(e,t,o)=>Dl(PE(e,t),jE(e,t),o.insetSouth(),Ll(),"south",Wl(e,{bottom:3}),VE),QE=(e,t,o)=>Dl(UE(e,t),$E(e,t),o.insetEast(),Hl(),"east",Wl(e,{right:0}),VE),ZE=(e,t,o)=>Dl(HE(e),$E(e,t),o.insetWest(),Vl(),"west",Wl(e,{left:1}),VE),eA=e=>{switch(e){case"north":return KE;case"northeast":return XE;case"northwest":return YE;case"south":return JE;case"southeast":return qE;case"southwest":return GE;case"east":return QE;case"west":return ZE}},tA=(e,t,o,n,s)=>Mc(n).map(eA).getOr(KE)(e,t,o,n,s),oA=e=>{switch(e){case"north":return JE;case"northeast":return qE;case"northwest":return GE;case"south":return KE;case"southeast":return XE;case"southwest":return YE;case"east":return ZE;case"west":return QE}},nA=(e,t,o,n,s)=>Mc(n).map(oA).getOr(KE)(e,t,o,n,s),sA={valignCentre:[],alignCentre:[],alignLeft:[],alignRight:[],right:[],left:[],bottom:[],top:[]},rA=(e,t,o)=>{const n={maxHeightFunction:Uc()};return()=>o()?{type:"node",root:bt(ft(e())),node:A.from(e()),bubble:Gc(12,12,sA),layouts:{onRtl:()=>[XE],onLtr:()=>[YE]},overrides:n}:{type:"hotspot",hotspot:t(),bubble:Gc(-12,12,sA),layouts:{onRtl:()=>[Jl,Ql,oc],onLtr:()=>[Ql,Jl,oc]},overrides:n}},aA=(e,t,o,n)=>{const s={maxHeightFunction:Uc()};return()=>n()?{type:"node",root:bt(ft(t())),node:A.from(t()),bubble:Gc(12,12,sA),layouts:{onRtl:()=>[KE],onLtr:()=>[KE]},overrides:s}:e?{type:"node",root:bt(ft(t())),node:A.from(t()),bubble:Gc(0,-$t(t()),sA),layouts:{onRtl:()=>[tc],onLtr:()=>[tc]},overrides:s}:{type:"hotspot",hotspot:o(),bubble:Gc(0,0,sA),layouts:{onRtl:()=>[tc],onLtr:()=>[tc]},overrides:s}},iA=(e,t,o)=>()=>o()?{type:"node",root:bt(ft(e())),node:A.from(e()),layouts:{onRtl:()=>[KE],onLtr:()=>[KE]}}:{type:"hotspot",hotspot:t(),layouts:{onRtl:()=>[oc],onLtr:()=>[oc]}},lA=(e,t)=>()=>({type:"selection",root:t(),getSelection:()=>{const t=e.selection.getRng(),o=e.model.table.getSelectedCells();if(o.length>1){const e=o[0],t=o[o.length-1],n={firstCell:ze(e),lastCell:ze(t)};return A.some(n)}return A.some(yd.range(ze(t.startContainer),t.startOffset,ze(t.endContainer),t.endOffset))}}),cA=e=>t=>({type:"node",root:e(),node:t}),dA=(e,t,o,n)=>{const s=Ob(e),r=()=>ze(e.getBody()),a=()=>ze(e.getContentAreaContainer()),i=()=>s||!n();return{inlineDialog:rA(a,t,i),inlineBottomDialog:aA(e.inline,a,o,i),banner:iA(a,t,i),cursor:lA(e,r),node:cA(r)}},uA=e=>(t,o)=>{PS(e)(t,o)},mA=e=>()=>TS(e),gA=e=>t=>kS(e,t),pA=e=>t=>_S(e,t),hA=e=>()=>rb(e),fA=e=>ve(e,"items"),bA=e=>ve(e,"format"),vA=[{title:"Headings",items:[{title:"Heading 1",format:"h1"},{title:"Heading 2",format:"h2"},{title:"Heading 3",format:"h3"},{title:"Heading 4",format:"h4"},{title:"Heading 5",format:"h5"},{title:"Heading 6",format:"h6"}]},{title:"Inline",items:[{title:"Bold",format:"bold"},{title:"Italic",format:"italic"},{title:"Underline",format:"underline"},{title:"Strikethrough",format:"strikethrough"},{title:"Superscript",format:"superscript"},{title:"Subscript",format:"subscript"},{title:"Code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Align",items:[{title:"Left",format:"alignleft"},{title:"Center",format:"aligncenter"},{title:"Right",format:"alignright"},{title:"Justify",format:"alignjustify"}]}],yA=e=>W(e,((e,t)=>{if(be(t,"items")){const o=yA(t.items);return{customFormats:e.customFormats.concat(o.customFormats),formats:e.formats.concat([{title:t.title,items:o.formats}])}}if(be(t,"inline")||(e=>be(e,"block"))(t)||(e=>be(e,"selector"))(t)){const o=`custom-${r(t.name)?t.name:t.title.toLowerCase()}`;return{customFormats:e.customFormats.concat([{name:o,format:t}]),formats:e.formats.concat([{title:t.title,format:o,icon:t.icon}])}}return{...e,formats:e.formats.concat(t)}}),{customFormats:[],formats:[]}),xA=e=>Lf(e).map((t=>{const o=((e,t)=>{const o=yA(t),n=t=>{V(t,(t=>{e.formatter.has(t.name)||e.formatter.register(t.name,t.format)}))};return e.formatter?n(o.customFormats):e.on("init",(()=>{n(o.customFormats)})),o.formats})(e,t);return Vf(e)?vA.concat(o):o})).getOr(vA),wA=(e,t,o)=>({...e,type:"formatter",isSelected:t(e.format),getStylePreview:o(e.format)}),SA=(e,t,o,n)=>{const s=t=>L(t,(t=>fA(t)?(e=>{const t=s(e.items);return{...e,type:"submenu",getStyleItems:x(t)}})(t):bA(t)?(e=>wA(e,o,n))(t):(e=>{const t=re(e);return 1===t.length&&F(t,"title")})(t)?{...t,type:"separator"}:(t=>{const s=r(t.name)?t.name:Bi(t.title),a=`custom-${s}`,i={...t,type:"formatter",format:a,isSelected:o(a),getStylePreview:n(a)};return e.formatter.register(s,i),i})(t)));return s(t)},kA=e=>{let t=0;const o=e=>[{dom:{tag:"div",classes:["tox-tooltip__body"]},components:[ul(e.tooltipText)]}];return{getConfig:n=>({delayForShow:()=>t>0?60:300,delayForHide:x(300),exclusive:!0,lazySink:e,tooltipDom:{tag:"div",classes:["tox-tooltip","tox-tooltip--up"]},tooltipComponents:o(n),onShow:(e,o)=>{t++,n.onShow&&n.onShow(e,o)},onHide:(e,o)=>{t--,n.onHide&&n.onHide(e,o)}}),getComponents:o}},CA=E_.trim,OA=e=>t=>{if((e=>g(e)&&1===e.nodeType)(t)){if(t.contentEditable===e)return!0;if(t.getAttribute("data-mce-contenteditable")===e)return!0}return!1},_A=OA("true"),TA=OA("false"),EA=(e,t,o,n,s)=>({type:e,title:t,url:o,level:n,attach:s}),AA=e=>e.innerText||e.textContent,MA=e=>(e=>e&&"A"===e.nodeName&&void 0!==(e.id||e.name))(e)&&BA(e),DA=e=>e&&/^(H[1-6])$/.test(e.nodeName),BA=e=>(e=>{let t=e;for(;t=t.parentNode;){const e=t.contentEditable;if(e&&"inherit"!==e)return _A(t)}return!1})(e)&&!TA(e),IA=e=>DA(e)&&BA(e),FA=e=>{var t;const o=(e=>e.id?e.id:Bi("h"))(e);return EA("header",null!==(t=AA(e))&&void 0!==t?t:"","#"+o,(e=>DA(e)?parseInt(e.nodeName.substr(1),10):0)(e),(()=>{e.id=o}))},RA=e=>{const t=e.id||e.name,o=AA(e);return EA("anchor",o||"#"+t,"#"+t,0,b)},NA=e=>CA(e.title).length>0,zA=e=>{const t=(e=>{const t=L(Td(ze(e),"h1,h2,h3,h4,h5,h6,a:not([href])"),(e=>e.dom));return t})(e);return P((e=>L(P(e,IA),FA))(t).concat((e=>L(P(e,MA),RA))(t)),NA)},LA="tinymce-url-history",VA=e=>r(e)&&/^https?/.test(e),HA=e=>a(e)&&pe(e,(e=>{return!(l(t=e)&&t.length<=5&&Y(t,VA));var t})).isNone(),PA=()=>{const e=dS.getItem(LA);if(null===e)return{};let t;try{t=JSON.parse(e)}catch(e){if(e instanceof SyntaxError)return console.log("Local storage "+LA+" was not valid JSON",e),{};throw e}return HA(t)?t:(console.log("Local storage "+LA+" was not valid format",t),{})},UA=e=>{const t=PA();return fe(t,e).getOr([])},WA=(e,t)=>{if(!VA(e))return;const o=PA(),n=fe(o,t).getOr([]),s=P(n,(t=>t!==e));o[t]=[e].concat(s).slice(0,5),(e=>{if(!HA(e))throw new Error("Bad format for history:\n"+JSON.stringify(e));dS.setItem(LA,JSON.stringify(e))})(o)},jA=e=>!!e,$A=e=>le(E_.makeMap(e,/[, ]/),jA),GA=e=>A.from(Qf(e)),qA=e=>A.from(e).filter(r).getOrUndefined(),YA=e=>({getHistory:UA,addToHistory:WA,getLinkInformation:()=>(e=>ob(e)?A.some({targets:zA(e.getBody()),anchorTop:qA(nb(e)),anchorBottom:qA(sb(e))}):A.none())(e),getValidationHandler:()=>(e=>A.from(Zf(e)))(e),getUrlPicker:t=>((e,t)=>((e,t)=>{const o=(e=>{const t=A.from(tb(e)).filter(jA).map($A);return GA(e).fold(T,(e=>t.fold(E,(e=>re(e).length>0&&e))))})(e);return d(o)?o?GA(e):A.none():o[t]?GA(e):A.none()})(e,t).map((o=>n=>ak((s=>{const i={filetype:t,fieldname:n.fieldname,...A.from(n.meta).getOr({})};o.call(e,((e,t)=>{if(!r(e))throw new Error("Expected value to be string");if(void 0!==t&&!a(t))throw new Error("Expected meta to be a object");s({value:e,meta:t})}),n.value,i)})))))(e,t)}),XA=Wm,KA=_m,JA=x([Cs("shell",!1),is("makeItem"),Cs("setupItem",b),Ju("listBehaviours",[Ah])]),QA=km({name:"items",overrides:()=>({behaviours:ma([Ah.config({})])})}),ZA=x([QA]),eM=Km({name:x("CustomList")(),configFields:JA(),partFields:ZA(),factory:(e,t,o,n)=>{const s=e.shell?{behaviours:[Ah.config({})],components:[]}:{behaviours:[],components:t};return{uid:e.uid,dom:e.dom,components:s.components,behaviours:Ku(e.listBehaviours,s.behaviours),apis:{setItems:(t,o)=>{var n;(n=t,e.shell?A.some(n):Rm(n,e,"items")).fold((()=>{throw console.error("Custom List was defined to not be a shell, but no item container was specified in components"),new Error("Custom List was defined to not be a shell, but no item container was specified in components")}),(n=>{const s=Ah.contents(n),r=o.length,a=r-s.length,i=a>0?N(a,(()=>e.makeItem())):[],l=s.slice(r);V(l,(e=>Ah.remove(n,e))),V(i,(e=>Ah.append(n,e)));const c=Ah.contents(n);V(c,((n,s)=>{e.setupItem(t,n,o[s],s)}))}))}}}},apis:{setItems:(e,t,o)=>{e.setItems(t,o)}}}),tM=x([is("dom"),Cs("shell",!0),Yu("toolbarBehaviours",[Ah])]),oM=x([km({name:"groups",overrides:()=>({behaviours:ma([Ah.config({})])})})]),nM=Km({name:"Toolbar",configFields:tM(),partFields:oM(),factory:(e,t,o,n)=>{const s=e.shell?{behaviours:[Ah.config({})],components:[]}:{behaviours:[],components:t};return{uid:e.uid,dom:e.dom,components:s.components,behaviours:Ku(e.toolbarBehaviours,s.behaviours),apis:{setGroups:(t,o)=>{var n;(n=t,e.shell?A.some(n):Rm(n,e,"groups")).fold((()=>{throw console.error("Toolbar was defined to not be a shell, but no groups container was specified in components"),new Error("Toolbar was defined to not be a shell, but no groups container was specified in components")}),(e=>{Ah.set(e,o)}))},refresh:b},domModification:{attributes:{role:"group"}}}},apis:{setGroups:(e,t,o)=>{e.setGroups(t,o)}}}),sM=b,rM=T,aM=x([]);var iM,lM=Object.freeze({__proto__:null,setup:sM,isDocked:rM,getBehaviours:aM});const cM=x(Bi("toolbar-height-change")),dM={fadeInClass:"tox-editor-dock-fadein",fadeOutClass:"tox-editor-dock-fadeout",transitionClass:"tox-editor-dock-transition"},uM="tox-tinymce--toolbar-sticky-on",mM="tox-tinymce--toolbar-sticky-off",gM=(e,t)=>F(Ei.getModes(e),t),pM=e=>{const t=e.element;at(t).each((o=>{const n="padding-"+Ei.getModes(e)[0];if(Ei.isDocked(e)){const e=Qt(o);Bt(t,"width",e+"px"),Bt(o,n,(e=>$t(e)+(parseInt(Rt(e,"margin-top"),10)||0)+(parseInt(Rt(e,"margin-bottom"),10)||0))(t)+"px")}else Ht(t,"width"),Ht(o,n)}))},hM=(e,t)=>{t?(Oa(e,dM.fadeOutClass),Ta(e,[dM.transitionClass,dM.fadeInClass])):(Oa(e,dM.fadeInClass),Ta(e,[dM.fadeOutClass,dM.transitionClass]))},fM=(e,t)=>{const o=ze(e.getContainer());t?(ka(o,uM),Oa(o,mM)):(ka(o,mM),Oa(o,uM))},bM=(e,t)=>{const o=rn(),n=t.getSink,s=e=>{n().each((t=>e(t.element)))},r=t=>{e.inline||pM(t),fM(e,Ei.isDocked(t)),t.getSystem().broadcastOn([Au()],{}),n().each((e=>e.getSystem().broadcastOn([Au()],{})))},a=e.inline?[]:[gc.config({channels:{[cM()]:{onReceive:pM}}})];return[Rh.config({}),Ei.config({contextual:{lazyContext:t=>{const o=$t(t.element),n=e.inline?e.getContentAreaContainer():e.getContainer();return A.from(n).map((n=>{const s=Qo(ze(n));return Rb(e,t.element).fold((()=>{const e=s.height-o,n=s.y+(gM(t,"top")?0:o);return Jo(s.x,n,s.width,e)}),(e=>{const n=en(s,Nb(e)),r=gM(t,"top")?n.y:n.y+o;return Jo(n.x,r,n.width,n.height-o)}))}))},onShow:()=>{s((e=>hM(e,!0)))},onShown:e=>{s((e=>Ea(e,[dM.transitionClass,dM.fadeInClass]))),o.get().each((t=>{((e,t)=>{const o=tt(t);vc(o).filter((e=>!Ze(t,e))).filter((t=>Ze(t,ze(o.dom.body))||et(e,t))).each((()=>hc(t)))})(e.element,t),o.clear()}))},onHide:e=>{((e,t)=>yc(e).orThunk((()=>t().toOptional().bind((e=>yc(e.element))))))(e.element,n).fold(o.clear,o.set),s((e=>hM(e,!1)))},onHidden:()=>{s((e=>Ea(e,[dM.transitionClass])))},...dM},lazyViewport:t=>Rb(e,t.element).fold((()=>{const o=tn(),n=Xf(e),s=o.y+(gM(t,"top")?n:0),r=o.height-(gM(t,"bottom")?n:0);return{bounds:Jo(o.x,s,o.width,r),optScrollEnv:A.none()}}),(e=>({bounds:Nb(e),optScrollEnv:A.some({currentScrollTop:e.element.dom.scrollTop,scrollElmTop:Xt(e.element).top})}))),modes:[t.header.getDockingMode()],onDocked:r,onUndocked:r}),...a]};var vM=Object.freeze({__proto__:null,setup:(e,t,o)=>{e.inline||(t.header.isPositionedAtTop()||e.on("ResizeEditor",(()=>{o().each(Ei.reset)})),e.on("ResizeWindow ResizeEditor",(()=>{o().each(pM)})),e.on("SkinLoaded",(()=>{o().each((e=>{Ei.isDocked(e)?Ei.reset(e):Ei.refresh(e)}))})),e.on("FullscreenStateChanged",(()=>{o().each(Ei.reset)}))),e.on("AfterScrollIntoView",(e=>{o().each((t=>{Ei.refresh(t);const o=t.element;gp(o)&&((e,t)=>{const o=tt(t),n=st(t).dom.innerHeight,s=Wo(o),r=ze(e.elm),a=Zo(r),i=jt(r),l=a.y,c=l+i,d=Xt(t),u=jt(t),m=d.top,g=m+u,p=Math.abs(m-s.top)<2,h=Math.abs(g-(s.top+n))<2;if(p&&l<g)jo(s.left,l-u,o);else if(h&&c>m){const e=l-n+i+u;jo(s.left,e,o)}})(e,o)}))})),e.on("PostRender",(()=>{fM(e,!1)}))},isDocked:e=>e().map(Ei.isDocked).getOr(!1),getBehaviours:bM});const yM=Nn([Jy,ls("items",Ln([Hn([Qy,hs("items",jn)]),jn]))].concat(Ex)),xM=[ys("text"),ys("tooltip"),ys("icon"),Os("search",!1,Ln([$n,Nn([ys("placeholder")])],(e=>d(e)?e?A.some({placeholder:A.none()}):A.none():A.some(e)))),ms("fetch"),Ms("onSetup",(()=>b))],wM=Nn([Jy,...xM]),SM=e=>Qn("menubutton",wM,e),kM=Nn([Jy,gx,mx,dx,fx,sx,lx,Es("presets","normal",["normal","color","listpreview"]),wx(1),ax,ix]);var CM=Xm({factory:(e,t)=>{const o={focus:xh.focusIn,setMenus:(e,o)=>{const n=L(o,(e=>{const o={type:"menubutton",text:e.text,fetch:t=>{t(e.getItems())}},n=SM(o).mapError((e=>ts(e))).getOrDie();return WT(n,"tox-mbtn",t.backstage,A.some("menuitem"))}));Ah.set(e,n)}};return{uid:e.uid,dom:e.dom,components:[],behaviours:ma([Ah.config({}),Mh("menubar-events",[ea((t=>{e.onSetup(t)})),Gr(Js(),((e,t)=>{_l(e.element,".tox-mbtn--active").each((o=>{Tl(t.event.target,".tox-mbtn").each((t=>{Ze(o,t)||e.getSystem().getByDom(o).each((o=>{e.getSystem().getByDom(t).each((e=>{wk.expand(e),wk.close(o),Rh.focus(e)}))}))}))}))})),Gr(Mr(),((e,t)=>{t.event.prevFocus.bind((t=>e.getSystem().getByDom(t).toOptional())).each((o=>{t.event.newFocus.bind((t=>e.getSystem().getByDom(t).toOptional())).each((e=>{wk.isOpen(o)&&(wk.expand(e),wk.close(o))}))}))}))]),xh.config({mode:"flow",selector:".tox-mbtn",onEscape:t=>(e.onEscape(t),A.some(!0))}),Ub.config({})]),apis:o,domModification:{attributes:{role:"menubar"}}}},name:"silver.Menubar",configFields:[is("dom"),is("uid"),is("onEscape"),is("backstage"),Cs("onSetup",b)],apis:{focus:(e,t)=>{e.focus(t)},setMenus:(e,t,o)=>{e.setMenus(t,o)}}});const OM="container",_M=[Yu("slotBehaviours",[])],TM=e=>"<alloy.field."+e+">",EM=(e,t)=>{const o=t=>Vm(e),n=(t,o)=>(n,s)=>Rm(n,e,s).map((e=>t(e,s))).getOr(o),s=(e,t)=>"true"!==_t(e.element,"aria-hidden"),r=n(s,!1),a=n(((e,t)=>{if(s(e)){const o=e.element;Bt(o,"display","none"),Ct(o,"aria-hidden","true"),Lr(e,Dr(),{name:t,visible:!1})}})),i=(e=>(t,o)=>{V(o,(o=>e(t,o)))})(a),l=n(((e,t)=>{if(!s(e)){const o=e.element;Ht(o,"display"),At(o,"aria-hidden"),Lr(e,Dr(),{name:t,visible:!0})}})),c={getSlotNames:o,getSlot:(t,o)=>Rm(t,e,o),isShowing:r,hideSlot:a,hideAllSlots:e=>i(e,o()),showSlot:l};return{uid:e.uid,dom:e.dom,components:t,behaviours:Xu(e.slotBehaviours),apis:c}},AM=le({getSlotNames:(e,t)=>e.getSlotNames(t),getSlot:(e,t,o)=>e.getSlot(t,o),isShowing:(e,t,o)=>e.isShowing(t,o),hideSlot:(e,t,o)=>e.hideSlot(t,o),hideAllSlots:(e,t)=>e.hideAllSlots(t),showSlot:(e,t,o)=>e.showSlot(t,o)},(e=>Gi(e))),MM={...AM,sketch:e=>{const t=(()=>{const e=[];return{slot:(t,o)=>(e.push(t),Mm(OM,TM(t),o)),record:x(e)}})(),o=e(t),n=t.record(),s=L(n,(e=>wm({name:e,pname:TM(e)})));return $m(OM,_M,s,EM,o)}},DM=Nn([mx,gx,Ms("onShow",b),Ms("onHide",b),lx]),BM=e=>({element:()=>e.element.dom}),IM=(e,t)=>{const o=L(re(t),(e=>{const o=t[e],n=Zn((e=>Qn("sidebar",DM,e))(o));return{name:e,getApi:BM,onSetup:n.onSetup,onShow:n.onShow,onHide:n.onHide}}));return L(o,(t=>{const n=on(b);return e.slot(t.name,{dom:{tag:"div",classes:["tox-sidebar__pane"]},behaviours:rw([hw(t,n),fw(t,n),Gr(Dr(),((e,t)=>{const n=t.event,s=j(o,(e=>e.name===n.name));s.each((t=>{(n.visible?t.onShow:t.onHide)(t.getApi(e))}))}))])})}))},FM=e=>MM.sketch((t=>({dom:{tag:"div",classes:["tox-sidebar__pane-container"]},components:IM(t,e),slotBehaviours:rw([ea((e=>MM.hideAllSlots(e)))])}))),RM=(e,t)=>{Ct(e,"role",t)},NM=e=>eg.getCurrent(e).bind((e=>PT.isGrowing(e)||PT.hasGrown(e)?eg.getCurrent(e).bind((e=>j(MM.getSlotNames(e),(t=>MM.isShowing(e,t))))):A.none())),zM=Bi("FixSizeEvent"),LM=Bi("AutoSizeEvent");var VM=Object.freeze({__proto__:null,block:(e,t,o,n)=>{Ct(e.element,"aria-busy",!0);const s=t.getRoot(e).getOr(e),r=ma([xh.config({mode:"special",onTab:()=>A.some(!0),onShiftTab:()=>A.some(!0)}),Rh.config({})]),a=n(s,r),i=s.getSystem().build(a);Ah.append(s,fl(i)),i.hasConfigured(xh)&&t.focus&&xh.focusIn(i),o.isBlocked()||t.onBlock(e),o.blockWith((()=>Ah.remove(s,i)))},unblock:(e,t,o)=>{At(e.element,"aria-busy"),o.isBlocked()&&t.onUnblock(e),o.clear()},isBlocked:(e,t,o)=>o.isBlocked()}),HM=[Ms("getRoot",A.none),As("focus",!0),xi("onBlock"),xi("onUnblock")];const PM=pa({fields:HM,name:"blocking",apis:VM,state:Object.freeze({__proto__:null,init:()=>{const e=nn((e=>e.destroy()));return ua({readState:e.isSet,blockWith:t=>{e.set({destroy:t})},clear:e.clear,isBlocked:e.isSet})}})}),UM=e=>eg.getCurrent(e).each((e=>hc(e.element,!0))),WM=(e,t,o)=>{const n=on(!1),s=rn(),r=o=>{var s;n.get()&&(!(e=>"focusin"===e.type)(s=o)||!(s.composed?te(s.composedPath()):A.from(s.target)).map(ze).filter($e).exists((e=>_a(e,"mce-pastebin"))))&&(o.preventDefault(),UM(t()),e.editorManager.setActive(e))};e.inline||e.on("PreInit",(()=>{e.dom.bind(e.getWin(),"focusin",r),e.on("BeforeExecCommand",(e=>{"mcefocus"===e.command.toLowerCase()&&!0!==e.value&&r(e)}))}));const a=s=>{s!==n.get()&&(n.set(s),((e,t,o,n)=>{const s=t.element;if(((e,t)=>{const o="tabindex",n=`data-mce-${o}`;A.from(e.iframeElement).map(ze).each((e=>{t?(Tt(e,o).each((t=>Ct(e,n,t))),Ct(e,o,-1)):(At(e,o),Tt(e,n).each((t=>{Ct(e,o,t),At(e,n)})))}))})(e,o),o)PM.block(t,(e=>(t,o)=>({dom:{tag:"div",attributes:{"aria-label":e.translate("Loading..."),tabindex:"0"},classes:["tox-throbber__busy-spinner"]},components:[{dom:Lb('<div class="tox-spinner"><div></div><div></div><div></div></div>')}]}))(n)),Ht(s,"display"),At(s,"aria-hidden"),e.hasFocus()&&UM(t);else{const o=eg.getCurrent(t).exists((e=>bc(e.element)));PM.unblock(t),Bt(s,"display","none"),Ct(s,"aria-hidden","true"),o&&e.focus()}})(e,t(),s,o.providers),((e,t)=>{e.dispatch("AfterProgressState",{state:t})})(e,s))};e.on("ProgressState",(t=>{if(s.on(clearTimeout),h(t.time)){const o=Cf.setEditorTimeout(e,(()=>a(t.state)),t.time);s.set(o)}else a(t.state),s.clear()}))},jM=(e,t,o)=>({within:e,extra:t,withinWidth:o}),$M=(e,t,o)=>{const n=W(e,((e,t)=>((e,t)=>{const n=o(e);return A.some({element:e,start:t,finish:t+n,width:n})})(t,e.len).fold(x(e),(t=>({len:t.finish,list:e.list.concat([t])})))),{len:0,list:[]}).list,s=P(n,(e=>e.finish<=t)),r=U(s,((e,t)=>e+t.width),0);return{within:s,extra:n.slice(s.length),withinWidth:r}},GM=e=>L(e,(e=>e.element)),qM=(e,t)=>{const o=L(t,(e=>fl(e)));nM.setGroups(e,o)},YM=(e,t,o)=>{const n=t.builtGroups.get();if(0===n.length)return;const s=Nm(e,t,"primary"),r=tk.getCoupled(e,"overflowGroup");Bt(s.element,"visibility","hidden");const a=n.concat([r]),i=se(a,(e=>yc(e.element).bind((t=>e.getSystem().getByDom(t).toOptional()))));o([]),qM(s,a);const l=((e,t,o,n)=>{const s=((e,t,o)=>{const n=$M(t,e,o);return 0===n.extra.length?A.some(n):A.none()})(e,t,o).getOrThunk((()=>$M(t,e-o(n),o))),r=s.within,a=s.extra,i=s.withinWidth;return 1===a.length&&a[0].width<=o(n)?((e,t,o)=>{const n=GM(e.concat(t));return jM(n,[],o)})(r,a,i):a.length>=1?((e,t,o,n)=>{const s=GM(e).concat([o]);return jM(s,GM(t),n)})(r,a,n,i):((e,t,o)=>jM(GM(e),[],o))(r,0,i)})(Qt(s.element),t.builtGroups.get(),(e=>Math.ceil(e.element.dom.getBoundingClientRect().width)),r);0===l.extra.length?(Ah.remove(s,r),o([])):(qM(s,l.within),o(l.extra)),Ht(s.element,"visibility"),Pt(s.element),i.each(Rh.focus)},XM=x([Yu("splitToolbarBehaviours",[tk]),rs("builtGroups",(()=>on([])))]),KM=x([vi(["overflowToggledClass"]),ws("getOverflowBounds"),is("lazySink"),rs("overflowGroups",(()=>on([]))),xi("onOpened"),xi("onClosed")].concat(XM())),JM=x([wm({factory:nM,schema:tM(),name:"primary"}),Sm({schema:tM(),name:"overflow"}),Sm({name:"overflow-button"}),Sm({name:"overflow-group"})]),QM=x(((e,t)=>{((e,t)=>{const o=Jt.max(e,t,["margin-left","border-left-width","padding-left","padding-right","border-right-width","margin-right"]);Bt(e,"max-width",o+"px")})(e,Math.floor(t))})),ZM=x([vi(["toggledClass"]),is("lazySink"),ms("fetch"),ws("getBounds"),ks("fireDismissalEventInstead",[Cs("event",Er())]),ed(),xi("onToggled")]),eD=x([Sm({name:"button",overrides:e=>({dom:{attributes:{"aria-haspopup":"true"}},buttonBehaviours:ma([Wh.config({toggleClass:e.markers.toggledClass,aria:{mode:"expanded"},toggleOnExecute:!1,onToggled:e.onToggled})])})}),Sm({factory:nM,schema:tM(),name:"toolbar",overrides:e=>({toolbarBehaviours:ma([xh.config({mode:"cyclic",onEscape:t=>(Rm(t,e,"button").each(Rh.focus),A.none())})])})})]),tD=rn(),oD=(e,t)=>{const o=tk.getCoupled(e,"toolbarSandbox");Tu.isOpen(o)?Tu.close(o):Tu.open(o,t.toolbar())},nD=(e,t,o,n)=>{const s=o.getBounds.map((e=>e())),r=o.lazySink(e).getOrDie();tu.positionWithinBounds(r,t,{anchor:{type:"hotspot",hotspot:e,layouts:n,overrides:{maxWidthFunction:QM()}}},s)},sD=(e,t,o,n,s)=>{nM.setGroups(t,s),nD(e,t,o,n),Wh.on(e)},rD=Km({name:"FloatingToolbarButton",factory:(e,t,o,n)=>({...zb.sketch({...n.button(),action:e=>{oD(e,n)},buttonBehaviours:Qu({dump:n.button().buttonBehaviours},[tk.config({others:{toolbarSandbox:t=>((e,t,o)=>{const n=Al();return{dom:{tag:"div",attributes:{id:n.id}},behaviours:ma([xh.config({mode:"special",onEscape:e=>(Tu.close(e),A.some(!0))}),Tu.config({onOpen:(s,r)=>{const a=tD.get().getOr(!1);o.fetch().get((s=>{sD(e,r,o,t.layouts,s),n.link(e.element),a||xh.focusIn(r)}))},onClose:()=>{Wh.off(e),tD.get().getOr(!1)||Rh.focus(e),n.unlink(e.element)},isPartOf:(t,o,n)=>Ml(o,n)||Ml(e,n),getAttachPoint:()=>o.lazySink(e).getOrDie()}),gc.config({channels:{...Bu({isExtraPart:T,...o.fireDismissalEventInstead.map((e=>({fireEventInstead:{event:e.event}}))).getOr({})}),...Fu({doReposition:()=>{Tu.getState(tk.getCoupled(e,"toolbarSandbox")).each((n=>{nD(e,n,o,t.layouts)}))}})}})])}})(t,o,e)}})])}),apis:{setGroups:(t,n)=>{Tu.getState(tk.getCoupled(t,"toolbarSandbox")).each((s=>{sD(t,s,e,o.layouts,n)}))},reposition:t=>{Tu.getState(tk.getCoupled(t,"toolbarSandbox")).each((n=>{nD(t,n,e,o.layouts)}))},toggle:e=>{oD(e,n)},toggleWithoutFocusing:e=>{((e,t)=>{tD.set(!0),oD(e,t),tD.clear()})(e,n)},getToolbar:e=>Tu.getState(tk.getCoupled(e,"toolbarSandbox")),isOpen:e=>Tu.isOpen(tk.getCoupled(e,"toolbarSandbox"))}}),configFields:ZM(),partFields:eD(),apis:{setGroups:(e,t,o)=>{e.setGroups(t,o)},reposition:(e,t)=>{e.reposition(t)},toggle:(e,t)=>{e.toggle(t)},toggleWithoutFocusing:(e,t)=>{e.toggleWithoutFocusing(t)},getToolbar:(e,t)=>e.getToolbar(t),isOpen:(e,t)=>e.isOpen(t)}}),aD=x([is("items"),vi(["itemSelector"]),Yu("tgroupBehaviours",[xh])]),iD=x([Cm({name:"items",unit:"item"})]),lD=Km({name:"ToolbarGroup",configFields:aD(),partFields:iD(),factory:(e,t,o,n)=>({uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.tgroupBehaviours,[xh.config({mode:"flow",selector:e.markers.itemSelector})]),domModification:{attributes:{role:"toolbar"}}})}),cD=e=>L(e,(e=>fl(e))),dD=(e,t,o)=>{YM(e,o,(n=>{o.overflowGroups.set(n),t.getOpt(e).each((e=>{rD.setGroups(e,cD(n))}))}))},uD=Km({name:"SplitFloatingToolbar",configFields:KM(),partFields:JM(),factory:(e,t,o,n)=>{const s=Vb(rD.sketch({fetch:()=>ak((t=>{t(cD(e.overflowGroups.get()))})),layouts:{onLtr:()=>[Ql,Jl],onRtl:()=>[Jl,Ql],onBottomLtr:()=>[ec,Zl],onBottomRtl:()=>[Zl,ec]},getBounds:o.getOverflowBounds,lazySink:e.lazySink,fireDismissalEventInstead:{},markers:{toggledClass:e.markers.overflowToggledClass},parts:{button:n["overflow-button"](),toolbar:n.overflow()},onToggled:(t,o)=>e[o?"onOpened":"onClosed"](t)}));return{uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.splitToolbarBehaviours,[tk.config({others:{overflowGroup:()=>lD.sketch({...n["overflow-group"](),items:[s.asSpec()]})}})]),apis:{setGroups:(t,o)=>{e.builtGroups.set(L(o,t.getSystem().build)),dD(t,s,e)},refresh:t=>dD(t,s,e),toggle:e=>{s.getOpt(e).each((e=>{rD.toggle(e)}))},toggleWithoutFocusing:e=>{s.getOpt(e).each(rD.toggleWithoutFocusing)},isOpen:e=>s.getOpt(e).map(rD.isOpen).getOr(!1),reposition:e=>{s.getOpt(e).each((e=>{rD.reposition(e)}))},getOverflow:e=>s.getOpt(e).bind(rD.getToolbar)},domModification:{attributes:{role:"group"}}}},apis:{setGroups:(e,t,o)=>{e.setGroups(t,o)},refresh:(e,t)=>{e.refresh(t)},reposition:(e,t)=>{e.reposition(t)},toggle:(e,t)=>{e.toggle(t)},toggleWithoutFocusing:(e,t)=>{e.toggle(t)},isOpen:(e,t)=>e.isOpen(t),getOverflow:(e,t)=>e.getOverflow(t)}}),mD=x([vi(["closedClass","openClass","shrinkingClass","growingClass","overflowToggledClass"]),xi("onOpened"),xi("onClosed")].concat(XM())),gD=x([wm({factory:nM,schema:tM(),name:"primary"}),wm({factory:nM,schema:tM(),name:"overflow",overrides:e=>({toolbarBehaviours:ma([PT.config({dimension:{property:"height"},closedClass:e.markers.closedClass,openClass:e.markers.openClass,shrinkingClass:e.markers.shrinkingClass,growingClass:e.markers.growingClass,onShrunk:t=>{Rm(t,e,"overflow-button").each((e=>{Wh.off(e)})),e.onClosed(t)},onGrown:t=>{e.onOpened(t)},onStartGrow:t=>{Rm(t,e,"overflow-button").each(Wh.on)}}),xh.config({mode:"acyclic",onEscape:t=>(Rm(t,e,"overflow-button").each(Rh.focus),A.some(!0))})])})}),Sm({name:"overflow-button",overrides:e=>({buttonBehaviours:ma([Wh.config({toggleClass:e.markers.overflowToggledClass,aria:{mode:"expanded"},toggleOnExecute:!1})])})}),Sm({name:"overflow-group"})]),pD=(e,t,o)=>{Rm(e,t,"overflow-button").each((n=>{Rm(e,t,"overflow").each((s=>{if(hD(e,t),PT.hasShrunk(s)){const e=t.onOpened;t.onOpened=n=>{o||xh.focusIn(s),e(n),t.onOpened=e}}else{const e=t.onClosed;t.onClosed=s=>{o||Rh.focus(n),e(s),t.onClosed=e}}PT.toggleGrow(s)}))}))},hD=(e,t)=>{Rm(e,t,"overflow").each((o=>{YM(e,t,(e=>{const t=L(e,(e=>fl(e)));nM.setGroups(o,t)})),Rm(e,t,"overflow-button").each((e=>{PT.hasGrown(o)&&Wh.on(e)})),PT.refresh(o)}))},fD=Km({name:"SplitSlidingToolbar",configFields:mD(),partFields:gD(),factory:(e,t,o,n)=>{const s="alloy.toolbar.toggle";return{uid:e.uid,dom:e.dom,components:t,behaviours:Ku(e.splitToolbarBehaviours,[tk.config({others:{overflowGroup:e=>lD.sketch({...n["overflow-group"](),items:[zb.sketch({...n["overflow-button"](),action:t=>{zr(e,s)}})]})}}),Mh("toolbar-toggle-events",[Gr(s,(t=>{pD(t,e,!1)}))])]),apis:{setGroups:(t,o)=>{((t,o)=>{const n=L(o,t.getSystem().build);e.builtGroups.set(n)})(t,o),hD(t,e)},refresh:t=>hD(t,e),toggle:t=>{pD(t,e,!1)},toggleWithoutFocusing:t=>{pD(t,e,!0)},isOpen:t=>((e,t)=>Rm(e,t,"overflow").map(PT.hasGrown).getOr(!1))(t,e)},domModification:{attributes:{role:"group"}}}},apis:{setGroups:(e,t,o)=>{e.setGroups(t,o)},refresh:(e,t)=>{e.refresh(t)},toggle:(e,t)=>{e.toggle(t)},isOpen:(e,t)=>e.isOpen(t)}}),bD=e=>{const t=e.title.fold((()=>({})),(e=>({attributes:{title:e}})));return{dom:{tag:"div",classes:["tox-toolbar__group"],...t},components:[lD.parts.items({})],items:e.items,markers:{itemSelector:"*:not(.tox-split-button) > .tox-tbtn:not([disabled]), .tox-split-button:not([disabled]), .tox-toolbar-nav-js:not([disabled]), .tox-number-input:not([disabled])"},tgroupBehaviours:ma([Ub.config({}),Rh.config({})])}},vD=e=>lD.sketch(bD(e)),yD=(e,t)=>{const o=ea((t=>{const o=L(e.initGroups,vD);nM.setGroups(t,o)}));return ma([gw(e.providers.isDisabled),dw(),xh.config({mode:t,onEscape:e.onEscape,selector:".tox-toolbar__group"}),Mh("toolbar-events",[o])])},xD=e=>{const t=e.cyclicKeying?"cyclic":"acyclic";return{uid:e.uid,dom:{tag:"div",classes:["tox-toolbar-overlord"]},parts:{"overflow-group":bD({title:A.none(),items:[]}),"overflow-button":hE({name:"more",icon:A.some("more-drawer"),enabled:!0,tooltip:A.some("Reveal or hide additional toolbar items"),primary:!1,buttonType:A.none(),borderless:!1},A.none(),e.providers,[],"overflow-button")},splitToolbarBehaviours:yD(e,t)}},wD=e=>{const t=xD(e),o=uD.parts.primary({dom:{tag:"div",classes:["tox-toolbar__primary"]}});return uD.sketch({...t,lazySink:e.getSink,getOverflowBounds:()=>{const t=e.moreDrawerData.lazyHeader().element,o=Zo(t),n=nt(t),s=Zo(n),r=Math.max(n.dom.scrollHeight,s.height);return Jo(o.x+4,s.y,o.width-8,r)},parts:{...t.parts,overflow:{dom:{tag:"div",classes:["tox-toolbar__overflow"],attributes:e.attributes}}},components:[o],markers:{overflowToggledClass:"tox-tbtn--enabled"},onOpened:t=>e.onToggled(t,!0),onClosed:t=>e.onToggled(t,!1)})},SD=e=>{const t=fD.parts.primary({dom:{tag:"div",classes:["tox-toolbar__primary"]}}),o=fD.parts.overflow({dom:{tag:"div",classes:["tox-toolbar__overflow"]}}),n=xD(e);return fD.sketch({...n,components:[t,o],markers:{openClass:"tox-toolbar__overflow--open",closedClass:"tox-toolbar__overflow--closed",growingClass:"tox-toolbar__overflow--growing",shrinkingClass:"tox-toolbar__overflow--shrinking",overflowToggledClass:"tox-tbtn--enabled"},onOpened:t=>{t.getSystem().broadcastOn([cM()],{type:"opened"}),e.onToggled(t,!0)},onClosed:t=>{t.getSystem().broadcastOn([cM()],{type:"closed"}),e.onToggled(t,!1)}})},kD=e=>{const t=e.cyclicKeying?"cyclic":"acyclic";return nM.sketch({uid:e.uid,dom:{tag:"div",classes:["tox-toolbar"].concat(e.type===Sf.scrolling?["tox-toolbar--scrolling"]:[])},components:[nM.parts.groups({})],toolbarBehaviours:yD(e,t)})},CD=[dx,mx,ys("tooltip"),Es("buttonType","secondary",["primary","secondary"]),As("borderless",!1),ms("onAction")],OD={button:[...CD,ex,us("type",["button"])],togglebutton:[...CD,As("active",!1),us("type",["togglebutton"])]},_D=[us("type",["group"]),Ds("buttons",[],os("type",OD))],TD=os("type",{...OD,group:_D}),ED=Nn([Ds("buttons",[],TD),ms("onShow"),ms("onHide")]),AD=(e,t)=>((e,t)=>{var o,n;const s="togglebutton"===e.type,r=e.icon.map((e=>sT(e,t.icons))).map(Vb),a={...e,name:s?e.text.getOr(e.icon.getOr("")):null!==(o=e.text)&&void 0!==o?o:e.icon.getOr(""),primary:"primary"===e.buttonType,buttonType:A.from(e.buttonType),tooltip:e.tooltip,icon:e.icon,enabled:!0,borderless:e.borderless},i=fE(null!==(n=e.buttonType)&&void 0!==n?n:"secondary"),l=s?e.text.map(t.translate):A.some(t.translate(e.text)),c=l.map(ul),d=a.tooltip.or(l).map((e=>({"aria-label":t.translate(e)}))).getOr({}),u=r.map((e=>e.asSpec())),m=yw([u,c]),g=e.icon.isSome()&&c.isSome(),p={tag:"button",classes:i.concat(...e.icon.isSome()&&!g?["tox-button--icon"]:[]).concat(...g?["tox-button--icon-and-text"]:[]).concat(...e.borderless?["tox-button--naked"]:[]).concat(..."togglebutton"===e.type&&e.active?["tox-button--enabled"]:[]),attributes:d},h=pE(a,A.some((o=>{const n=e=>{r.map((n=>n.getOpt(o).each((o=>{Ah.set(o,[sT(e,t.icons)])}))))};return s?e.onAction({setIcon:n,setActive:e=>{const t=o.element;e?(ka(t,"tox-button--enabled"),Ct(t,"aria-pressed",!0)):(Oa(t,"tox-button--enabled"),At(t,"aria-pressed"))},isActive:()=>_a(o.element,"tox-button--enabled")}):"button"===e.type?e.onAction({setIcon:n}):void 0})),[],p,m,e.tooltip,t);return zb.sketch(h)})(e,t),MD=Bo().deviceType,DD=MD.isPhone(),BD=MD.isTablet();var ID=Km({name:"silver.View",configFields:[is("viewConfig")],partFields:[km({factory:{sketch:e=>{let t=!1;const o=L(e.buttons,(o=>"group"===o.type?(t=!0,((e,t)=>({dom:{tag:"div",classes:["tox-view__toolbar__group"]},components:L(e.buttons,(e=>AD(e,t)))}))(o,e.providers)):AD(o,e.providers)));return{uid:e.uid,dom:{tag:"div",classes:[t?"tox-view__toolbar":"tox-view__header",...DD||BD?["tox-view--mobile","tox-view--scrolling"]:[]]},behaviours:ma([Rh.config({}),xh.config({mode:"flow",selector:"button, .tox-button",focusInside:qg.OnEnterOrSpaceMode})]),components:t?o:[Uk.sketch({dom:{tag:"div",classes:["tox-view__header-start"]},components:[]}),Uk.sketch({dom:{tag:"div",classes:["tox-view__header-end"]},components:o})]}}},schema:[is("buttons"),is("providers")],name:"header"}),km({factory:{sketch:e=>({uid:e.uid,behaviours:ma([Rh.config({}),Ub.config({})]),dom:{tag:"div",classes:["tox-view__pane"]}})},schema:[],name:"pane"})],factory:(e,t,o,n)=>{const s={getPane:t=>XA.getPart(t,e,"pane"),getOnShow:t=>e.viewConfig.onShow,getOnHide:t=>e.viewConfig.onHide};return{uid:e.uid,dom:e.dom,components:t,behaviours:ma([Rh.config({}),xh.config({mode:"cyclic",focusInside:qg.OnEnterOrSpaceMode})]),apis:s}},apis:{getPane:(e,t)=>e.getPane(t),getOnShow:(e,t)=>e.getOnShow(t),getOnHide:(e,t)=>e.getOnHide(t)}});const FD=(e,t,o)=>ge(t,((t,n)=>{const s=Zn(Qn("view",ED,t));return e.slot(n,ID.sketch({dom:{tag:"div",classes:["tox-view"]},viewConfig:s,components:[...s.buttons.length>0?[ID.parts.header({buttons:s.buttons,providers:o})]:[],ID.parts.pane({})]}))})),RD=(e,t)=>MM.sketch((o=>({dom:{tag:"div",classes:["tox-view-wrap__slot-container"]},components:FD(o,e,t),slotBehaviours:rw([ea((e=>MM.hideAllSlots(e)))])}))),ND=e=>j(MM.getSlotNames(e),(t=>MM.isShowing(e,t))),zD=(e,t,o)=>{MM.getSlot(e,t).each((e=>{ID.getPane(e).each((t=>{var n;o(e)((n=t.element.dom,{getContainer:x(n)}))}))}))};var LD=Xm({factory:(e,t)=>{const o={setViews:(e,o)=>{Ah.set(e,[RD(o,t.backstage.shared.providers)])},whichView:e=>eg.getCurrent(e).bind(ND),toggleView:(e,t,o,n)=>eg.getCurrent(e).exists((s=>{const r=ND(s),a=r.exists((e=>n===e)),i=MM.getSlot(s,n).isSome();return i&&(MM.hideAllSlots(s),a?((e=>{const t=e.element;Bt(t,"display","none"),Ct(t,"aria-hidden","true")})(e),t()):(o(),(e=>{const t=e.element;Ht(t,"display"),At(t,"aria-hidden")})(e),MM.showSlot(s,n),((e,t)=>{zD(e,t,ID.getOnShow)})(s,n)),r.each((e=>((e,t)=>zD(e,t,ID.getOnHide))(s,e)))),i}))};return{uid:e.uid,dom:{tag:"div",classes:["tox-view-wrap"],attributes:{"aria-hidden":"true"},styles:{display:"none"}},components:[],behaviours:ma([Ah.config({}),eg.config({find:e=>{const t=Ah.contents(e);return te(t)}})]),apis:o}},name:"silver.ViewWrapper",configFields:[is("backstage")],apis:{setViews:(e,t,o)=>e.setViews(t,o),toggleView:(e,t,o,n,s)=>e.toggleView(t,o,n,s),whichView:(e,t)=>e.whichView(t)}});const VD=KA.optional({factory:CM,name:"menubar",schema:[is("backstage")]}),HD=KA.optional({factory:{sketch:e=>eM.sketch({uid:e.uid,dom:e.dom,listBehaviours:ma([xh.config({mode:"acyclic",selector:".tox-toolbar"})]),makeItem:()=>kD({type:e.type,uid:Bi("multiple-toolbar-item"),cyclicKeying:!1,initGroups:[],providers:e.providers,onEscape:()=>(e.onEscape(),A.some(!0))}),setupItem:(e,t,o,n)=>{nM.setGroups(t,o)},shell:!0})},name:"multiple-toolbar",schema:[is("dom"),is("onEscape")]}),PD=KA.optional({factory:{sketch:e=>{const t=(e=>e.type===Sf.sliding?SD:e.type===Sf.floating?wD:kD)(e);return t({type:e.type,uid:e.uid,onEscape:()=>(e.onEscape(),A.some(!0)),onToggled:(t,o)=>e.onToolbarToggled(o),cyclicKeying:!1,initGroups:[],getSink:e.getSink,providers:e.providers,moreDrawerData:{lazyToolbar:e.lazyToolbar,lazyMoreButton:e.lazyMoreButton,lazyHeader:e.lazyHeader},attributes:e.attributes})}},name:"toolbar",schema:[is("dom"),is("onEscape"),is("getSink")]}),UD=KA.optional({factory:{sketch:e=>{const t=e.editor,o=e.sticky?bM:aM;return{uid:e.uid,dom:e.dom,components:e.components,behaviours:ma(o(t,e.sharedBackstage))}}},name:"header",schema:[is("dom")]}),WD=KA.optional({factory:{sketch:e=>({uid:e.uid,dom:e.dom,components:[{dom:{tag:"a",attributes:{href:"https://www.tiny.cloud/tinymce-self-hosted-premium-features/?utm_campaign=self_hosted_upgrade_promo&utm_source=tiny&utm_medium=referral",rel:"noopener",target:"_blank","aria-hidden":"true"},classes:["tox-promotion-link"],innerHtml:"\u26a1\ufe0fUpgrade"}}]})},name:"promotion",schema:[is("dom")]}),jD=KA.optional({name:"socket",schema:[is("dom")]}),$D=KA.optional({factory:{sketch:e=>({uid:e.uid,dom:{tag:"div",classes:["tox-sidebar"],attributes:{role:"presentation"}},components:[{dom:{tag:"div",classes:["tox-sidebar__slider"]},components:[],behaviours:ma([Ub.config({}),Rh.config({}),PT.config({dimension:{property:"width"},closedClass:"tox-sidebar--sliding-closed",openClass:"tox-sidebar--sliding-open",shrinkingClass:"tox-sidebar--sliding-shrinking",growingClass:"tox-sidebar--sliding-growing",onShrunk:e=>{eg.getCurrent(e).each(MM.hideAllSlots),zr(e,LM)},onGrown:e=>{zr(e,LM)},onStartGrow:e=>{Lr(e,zM,{width:zt(e.element,"width").getOr("")})},onStartShrink:e=>{Lr(e,zM,{width:Qt(e.element)+"px"})}}),Ah.config({}),eg.config({find:e=>{const t=Ah.contents(e);return te(t)}})])}],behaviours:ma([y_(0),Mh("sidebar-sliding-events",[Gr(zM,((e,t)=>{Bt(e.element,"width",t.event.width)})),Gr(LM,((e,t)=>{Ht(e.element,"width")}))])])})},name:"sidebar",schema:[is("dom")]}),GD=KA.optional({factory:{sketch:e=>({uid:e.uid,dom:{tag:"div",attributes:{"aria-hidden":"true"},classes:["tox-throbber"],styles:{display:"none"}},behaviours:ma([Ah.config({}),PM.config({focus:!1}),eg.config({find:e=>te(e.components())})]),components:[]})},name:"throbber",schema:[is("dom")]}),qD=KA.optional({factory:LD,name:"viewWrapper",schema:[is("backstage")]}),YD=KA.optional({factory:{sketch:e=>({uid:e.uid,dom:{tag:"div",classes:["tox-editor-container"]},components:e.components})},name:"editorContainer",schema:[]});var XD=Km({name:"OuterContainer",factory:(e,t,o)=>{let n=!1;const s=e=>{Cl(e,".tox-statusbar").each((e=>{"none"===Rt(e,"display")&&"true"===_t(e,"aria-hidden")?(Ht(e,"display"),At(e,"aria-hidden")):(Bt(e,"display","none"),Ct(e,"aria-hidden","true"))}))},a={getSocket:t=>XA.getPart(t,e,"socket"),setSidebar:(t,o,n)=>{XA.getPart(t,e,"sidebar").each((e=>((e,t,o)=>{eg.getCurrent(e).each((n=>{Ah.set(n,[FM(t)]);const s=null==o?void 0:o.toLowerCase();r(s)&&be(t,s)&&eg.getCurrent(n).each((t=>{MM.showSlot(t,s),PT.immediateGrow(n),Ht(n.element,"width"),RM(e.element,"region")}))}))})(e,o,n)))},toggleSidebar:(t,o)=>{XA.getPart(t,e,"sidebar").each((e=>((e,t)=>{eg.getCurrent(e).each((o=>{eg.getCurrent(o).each((n=>{PT.hasGrown(o)?MM.isShowing(n,t)?(PT.shrink(o),RM(e.element,"presentation")):(MM.hideAllSlots(n),MM.showSlot(n,t),RM(e.element,"region")):(MM.hideAllSlots(n),MM.showSlot(n,t),PT.grow(o),RM(e.element,"region"))}))}))})(e,o)))},whichSidebar:t=>XA.getPart(t,e,"sidebar").bind(NM).getOrNull(),getHeader:t=>XA.getPart(t,e,"header"),getToolbar:t=>XA.getPart(t,e,"toolbar"),setToolbar:(t,o)=>{XA.getPart(t,e,"toolbar").each((e=>{const t=L(o,vD);e.getApis().setGroups(e,t)}))},setToolbars:(t,o)=>{XA.getPart(t,e,"multiple-toolbar").each((e=>{const t=L(o,(e=>L(e,vD)));eM.setItems(e,t)}))},refreshToolbar:t=>{XA.getPart(t,e,"toolbar").each((e=>e.getApis().refresh(e)))},toggleToolbarDrawer:t=>{XA.getPart(t,e,"toolbar").each((e=>{Se(e.getApis().toggle,(t=>t(e)))}))},toggleToolbarDrawerWithoutFocusing:t=>{XA.getPart(t,e,"toolbar").each((e=>{Se(e.getApis().toggleWithoutFocusing,(t=>t(e)))}))},isToolbarDrawerToggled:t=>XA.getPart(t,e,"toolbar").bind((e=>A.from(e.getApis().isOpen).map((t=>t(e))))).getOr(!1),getThrobber:t=>XA.getPart(t,e,"throbber"),focusToolbar:t=>{XA.getPart(t,e,"toolbar").orThunk((()=>XA.getPart(t,e,"multiple-toolbar"))).each((e=>{xh.focusIn(e)}))},setMenubar:(t,o)=>{XA.getPart(t,e,"menubar").each((e=>{CM.setMenus(e,o)}))},focusMenubar:t=>{XA.getPart(t,e,"menubar").each((e=>{CM.focus(e)}))},setViews:(t,o)=>{XA.getPart(t,e,"viewWrapper").each((e=>{LD.setViews(e,o)}))},toggleView:(t,o)=>XA.getPart(t,e,"viewWrapper").exists((e=>LD.toggleView(e,(()=>a.showMainView(t)),(()=>a.hideMainView(t)),o))),whichView:t=>XA.getPart(t,e,"viewWrapper").bind(LD.whichView).getOrNull(),hideMainView:t=>{n=a.isToolbarDrawerToggled(t),n&&a.toggleToolbarDrawer(t),XA.getPart(t,e,"editorContainer").each((e=>{const t=e.element;s(t),Bt(t,"display","none"),Ct(t,"aria-hidden","true")}))},showMainView:t=>{n&&a.toggleToolbarDrawer(t),XA.getPart(t,e,"editorContainer").each((e=>{const t=e.element;s(t),Ht(t,"display"),At(t,"aria-hidden")}))}};return{uid:e.uid,dom:e.dom,components:t,apis:a,behaviours:e.behaviours}},configFields:[is("dom"),is("behaviours")],partFields:[UD,VD,PD,HD,jD,$D,WD,GD,qD,YD],apis:{getSocket:(e,t)=>e.getSocket(t),setSidebar:(e,t,o,n)=>{e.setSidebar(t,o,n)},toggleSidebar:(e,t,o)=>{e.toggleSidebar(t,o)},whichSidebar:(e,t)=>e.whichSidebar(t),getHeader:(e,t)=>e.getHeader(t),getToolbar:(e,t)=>e.getToolbar(t),setToolbar:(e,t,o)=>{e.setToolbar(t,o)},setToolbars:(e,t,o)=>{e.setToolbars(t,o)},refreshToolbar:(e,t)=>e.refreshToolbar(t),toggleToolbarDrawer:(e,t)=>{e.toggleToolbarDrawer(t)},toggleToolbarDrawerWithoutFocusing:(e,t)=>{e.toggleToolbarDrawerWithoutFocusing(t)},isToolbarDrawerToggled:(e,t)=>e.isToolbarDrawerToggled(t),getThrobber:(e,t)=>e.getThrobber(t),setMenubar:(e,t,o)=>{e.setMenubar(t,o)},focusMenubar:(e,t)=>{e.focusMenubar(t)},focusToolbar:(e,t)=>{e.focusToolbar(t)},setViews:(e,t,o)=>{e.setViews(t,o)},toggleView:(e,t,o)=>e.toggleView(t,o),whichView:(e,t)=>e.whichView(t)}});const KD={file:{title:"File",items:"newdocument restoredraft | preview | importword exportpdf exportword | export print | deleteallconversations"},edit:{title:"Edit",items:"undo redo | cut copy paste pastetext | selectall | searchreplace"},view:{title:"View",items:"code revisionhistory | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments"},insert:{title:"Insert",items:"image link media addcomment pageembed inserttemplate codesample inserttable accordion math | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime"},format:{title:"Format",items:"bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat"},tools:{title:"Tools",items:"aidialog aishortcuts | spellchecker spellcheckerlanguage | autocorrect capitalization | a11ycheck code typography wordcount addtemplate"},table:{title:"Table",items:"inserttable | cell row column | advtablesort | tableprops deletetable"},help:{title:"Help",items:"help"}},JD=e=>e.split(" "),QD=(e,t)=>{const o={...KD,...t.menus},n=re(t.menus).length>0,s=void 0===t.menubar||!0===t.menubar?JD("file edit view insert format tools table help"):JD(!1===t.menubar?"":t.menubar),a=P(s,(e=>{const o=be(KD,e);return n?o||fe(t.menus,e).exists((e=>be(e,"items"))):o})),i=L(a,(n=>{const s=o[n];return((e,t,o)=>{const n=Uf(o).split(/[ ,]/);return{text:e.title,getItems:()=>q(e.items,(e=>{const o=e.toLowerCase();return 0===o.trim().length||R(n,(e=>e===o))?[]:"separator"===o||"|"===o?[{type:"separator"}]:t.menuItems[o]?[t.menuItems[o]]:[]}))}})({title:s.title,items:JD(s.items)},t,e)}));return P(i,(e=>e.getItems().length>0&&R(e.getItems(),(e=>r(e)||"separator"!==e.type))))},ZD=(e,t,o)=>(e.on("remove",(()=>o.unload(t))),o.load(t)),eB=(e,t,o,n)=>(e.on("remove",(()=>n.unloadRawCss(t))),n.loadRawCss(t,o)),tB=async(e,t)=>{const o="ui/"+vb(e).getOr("default")+"/skin.css",n=tinymce.Resource.get(o);if(!r(n)){const o=e.editorManager.suffix;return ZD(e,t+`/skin${o}.css`,e.ui.styleSheetLoader)}eB(e,o,n,e.ui.styleSheetLoader)},oB=async(e,t)=>{var o;if(o=ze(e.getElement()),vt(o).isSome()){const o="ui/"+vb(e).getOr("default")+"/skin.shadowdom.css",n=tinymce.Resource.get(o);if(!r(n)){const o=e.editorManager.suffix;return ZD(e,t+`/skin.shadowdom${o}.css`,Of.DOM.styleSheetLoader)}eB(e,o,n,Of.DOM.styleSheetLoader)}},nB=(e,t)=>(async(e,t)=>{const o=()=>{const o=bb(t),n=t.editorManager.suffix;o&&t.contentCSS.push(o+(e?"/content.inline":"/content")+`${n}.css`)};vb(t).fold(o,(n=>{const s="ui/"+n+(e?"/content.inline":"/content")+".css",a=tinymce.Resource.get(s);r(a)?eB(t,s,a,t.ui.styleSheetLoader):o()}));const n=bb(t);if(!hb(t)&&r(n))return Promise.all([tB(t,n),oB(t,n)]).then()})(e,t).then((e=>{const t=()=>{e._skinLoaded=!0,(e=>{e.dispatch("SkinLoaded")})(e)};return()=>{e.initialized?t():e.on("init",t)}})(t),((e,t)=>()=>((e,t)=>{e.dispatch("SkinLoadError",t)})(e,{message:"Skin could not be loaded"}))(t)),sB=k(nB,!1),rB=k(nB,!0),aB=(e,t,o)=>De(o)?e.translate(t):e.translate([t,e.translate(o)]),iB=(e,t)=>{const o=(o,s,r,a)=>{const i=e.shared.providers.translate(o.title);if("separator"===o.type)return A.some({type:"separator",text:i});if("submenu"===o.type){const e=q(o.getStyleItems(),(e=>n(e,s,a)));return 0===s&&e.length<=0?A.none():A.some({type:"nestedmenuitem",text:i,enabled:e.length>0,getSubmenuItems:()=>q(o.getStyleItems(),(e=>n(e,s,a)))})}return A.some({type:"togglemenuitem",text:i,icon:o.icon,active:o.isSelected(a),enabled:!r,onAction:t.onAction(o),...o.getStylePreview().fold((()=>({})),(e=>({meta:{style:e}})))})},n=(e,n,s)=>{const r="formatter"===e.type&&t.isInvalid(e);return 0===n?r?[]:o(e,n,!1,s).toArray():o(e,n,r,s).toArray()},s=e=>{const o=t.getCurrentValue(),s=t.shouldHide?0:1;return q(e,(e=>n(e,s,o)))};return{validateItems:s,getFetch:(e,t)=>(o,n)=>{const r=t(),a=s(r);n(mT(a,dy.CLOSE_ON_EXECUTE,e,{isHorizontalMenu:!1,search:A.none()}))}}},lB=(e,t)=>{const o=t.dataset,n="basic"===o.type?()=>L(o.data,(e=>wA(e,t.isSelectedFor,t.getPreviewFor))):o.getData;return{items:iB(e,t),getStyleItems:n}},cB=(e,t,o,n,s,r)=>{const{items:a,getStyleItems:i}=lB(t,o),l=on(o.tooltip);return lT({text:o.icon.isSome()?A.none():o.text,icon:o.icon,ariaLabel:A.some(o.tooltip),tooltip:A.none(),role:A.none(),fetch:a.getFetch(t,i),onSetup:t=>{const r=o=>t.setTooltip(aB(e,n(o.value),o.value));return e.on(s,r),sS(iS(e,"NodeChange",(t=>{const n=t.getComponent();o.updateText(n),pg.set(t.getComponent(),!e.selection.isEditable())}))(t),(()=>e.off(s,r)))},getApi:e=>({getComponent:x(e),setTooltip:o=>{const n=t.shared.providers.translate(o);Ct(e.element,"aria-label",n),l.set(o)}}),columns:1,presets:"normal",classes:o.icon.isSome()?[]:["bespoke"],dropdownBehaviours:[Zb.config({...t.shared.providers.tooltips.getConfig({tooltipText:t.shared.providers.translate(o.tooltip),onShow:e=>{if(o.tooltip!==l.get()){const o=t.shared.providers.translate(l.get());Zb.setComponents(e,t.shared.providers.tooltips.getComponents({tooltipText:o}))}}})})]},"tox-tbtn",t.shared,r)};var dB;!function(e){e[e.SemiColon=0]="SemiColon",e[e.Space=1]="Space"}(dB||(dB={}));const uB=(e,t,o)=>{const n=(s=((e,t)=>t===dB.SemiColon?e.replace(/;$/,"").split(";"):e.split(" "))(e.options.get(t),o),L(s,(e=>{let t=e,o=e;const n=e.split("=");return n.length>1&&(t=n[0],o=n[1]),{title:t,format:o}})));var s;return{type:"basic",data:n}},mB=x("Alignment {0}"),gB="left",pB=[{title:"Left",icon:"align-left",format:"alignleft",command:"JustifyLeft"},{title:"Center",icon:"align-center",format:"aligncenter",command:"JustifyCenter"},{title:"Right",icon:"align-right",format:"alignright",command:"JustifyRight"},{title:"Justify",icon:"align-justify",format:"alignjustify",command:"JustifyFull"}],hB=e=>{const t={type:"basic",data:pB};return{tooltip:aB(e,mB(),gB),text:A.none(),icon:A.some("align-left"),isSelectedFor:t=>()=>e.formatter.match(t),getCurrentValue:A.none,getPreviewFor:e=>A.none,onAction:t=>()=>j(pB,(e=>e.format===t.format)).each((t=>e.execCommand(t.command))),updateText:t=>{const o=j(pB,(t=>e.formatter.match(t.format))).fold(x(gB),(e=>e.title.toLowerCase()));Lr(t,iT,{icon:`align-${o}`}),((e,t)=>{e.dispatch("AlignTextUpdate",t)})(e,{value:o})},dataset:t,shouldHide:!1,isInvalid:t=>!e.formatter.canApply(t.format)}},fB=(e,t)=>{const o=t(),n=L(o,(e=>e.format));return A.from(e.formatter.closest(n)).bind((e=>j(o,(t=>t.format===e))))},bB=x("Block {0}"),vB="Paragraph",yB=e=>{const t=uB(e,"block_formats",dB.SemiColon);return{tooltip:aB(e,bB(),vB),text:A.some(vB),icon:A.none(),isSelectedFor:t=>()=>e.formatter.match(t),getCurrentValue:A.none,getPreviewFor:t=>()=>{const o=e.formatter.get(t);return o?A.some({tag:o.length>0&&(o[0].inline||o[0].block)||"div",styles:e.dom.parseStyle(e.formatter.getCssText(t))}):A.none()},onAction:lS(e),updateText:o=>{const n=fB(e,(()=>t.data)).fold(x(vB),(e=>e.title));Lr(o,aT,{text:n}),((e,t)=>{e.dispatch("BlocksTextUpdate",t)})(e,{value:n})},dataset:t,shouldHide:!1,isInvalid:t=>!e.formatter.canApply(t.format)}},xB=x("Font {0}"),wB="System Font",SB=["-apple-system","Segoe UI","Roboto","Helvetica Neue","sans-serif"],kB=e=>{const t=e.split(/\s*,\s*/);return L(t,(e=>e.replace(/^['"]+|['"]+$/g,"")))},CB=(e,t)=>t.length>0&&Y(t,(t=>e.indexOf(t.toLowerCase())>-1)),OB=e=>{const t=()=>{const t=e=>e?kB(e)[0]:"",n=e.queryCommandValue("FontName"),s=o.data,r=n?n.toLowerCase():"",a=pb(e),i=j(s,(e=>{const o=e.format;return o.toLowerCase()===r||t(o).toLowerCase()===t(r).toLowerCase()})).orThunk((()=>ke(((e,t)=>{if(0===e.indexOf("-apple-system")||t.length>0){const o=kB(e.toLowerCase());return CB(o,SB)||CB(o,t)}return!1})(r,a),{title:wB,format:r})));return{matchOpt:i,font:n}},o=uB(e,"font_family_formats",dB.SemiColon);return{tooltip:aB(e,xB(),wB),text:A.some(wB),icon:A.none(),isSelectedFor:e=>t=>t.exists((t=>t.format===e)),getCurrentValue:()=>{const{matchOpt:e}=t();return e},getPreviewFor:e=>()=>A.some({tag:"div",styles:-1===e.indexOf("dings")?{"font-family":e}:{}}),onAction:t=>()=>{e.undoManager.transact((()=>{e.focus(),e.execCommand("FontName",!1,t.format)}))},updateText:o=>{const{matchOpt:n,font:s}=t(),r=n.fold(x(s),(e=>e.title));Lr(o,aT,{text:r}),((e,t)=>{e.dispatch("FontFamilyTextUpdate",t)})(e,{value:r})},dataset:o,shouldHide:!1,isInvalid:T}},_B={unsupportedLength:["em","ex","cap","ch","ic","rem","lh","rlh","vw","vh","vi","vb","vmin","vmax","cm","mm","Q","in","pc","pt","px"],fixed:["px","pt"],relative:["%"],empty:[""]},TB=(()=>{const e="[0-9]+",t="[eE][+-]?"+e,o=e=>`(?:${e})?`,n=["Infinity",e+"\\."+o(e)+o(t),"\\."+e+o(t),e+o(t)].join("|");return new RegExp(`^([+-]?(?:${n}))(.*)$`)})(),EB=(e,t)=>A.from(TB.exec(e)).bind((e=>{const o=Number(e[1]),n=e[2];return((e,t)=>R(t,(t=>R(_B[t],(t=>e===t)))))(n,t)?A.some({value:o,unit:n}):A.none()})),AB={tab:x(9),escape:x(27),enter:x(13),backspace:x(8),delete:x(46),left:x(37),up:x(38),right:x(39),down:x(40),space:x(32),home:x(36),end:x(35),pageUp:x(33),pageDown:x(34)},MB=x("Font size {0}"),DB="12pt",BB={"8pt":"1","10pt":"2","12pt":"3","14pt":"4","18pt":"5","24pt":"6","36pt":"7"},IB={"xx-small":"7pt","x-small":"8pt",small:"10pt",medium:"12pt",large:"14pt","x-large":"18pt","xx-large":"24pt"},FB=(e,t)=>/[0-9.]+px$/.test(e)?((e,t)=>{const o=Math.pow(10,t);return Math.round(e*o)/o})(72*parseInt(e,10)/96,t||0)+"pt":fe(IB,e).getOr(e),RB=e=>fe(BB,e).getOr(""),NB=e=>{const t=()=>{let t=A.none();const o=n.data,s=e.queryCommandValue("FontSize");if(s)for(let e=3;t.isNone()&&e>=0;e--){const n=FB(s,e),r=RB(n);t=j(o,(e=>e.format===s||e.format===n||e.format===r))}return{matchOpt:t,size:s}},o=x(A.none),n=uB(e,"font_size_formats",dB.Space);return{tooltip:aB(e,MB(),DB),text:A.some(DB),icon:A.none(),isSelectedFor:e=>t=>t.exists((t=>t.format===e)),getPreviewFor:o,getCurrentValue:()=>{const{matchOpt:e}=t();return e},onAction:t=>()=>{e.undoManager.transact((()=>{e.focus(),e.execCommand("FontSize",!1,t.format)}))},updateText:o=>{const{matchOpt:n,size:s}=t(),r=n.fold(x(s),(e=>e.title));Lr(o,aT,{text:r}),((e,t)=>{e.dispatch("FontSizeTextUpdate",t)})(e,{value:r})},dataset:n,shouldHide:!1,isInvalid:T}},zB=e=>De(e)?"Formats":"Format {0}",LB=(e,t)=>{const o="Formats";return{tooltip:aB(e,zB(""),""),text:A.some(o),icon:A.none(),isSelectedFor:t=>()=>e.formatter.match(t),getCurrentValue:A.none,getPreviewFor:t=>()=>{const o=e.formatter.get(t);return void 0!==o?A.some({tag:o.length>0&&(o[0].inline||o[0].block)||"div",styles:e.dom.parseStyle(e.formatter.getCssText(t))}):A.none()},onAction:lS(e),updateText:t=>{const n=e=>fA(e)?q(e.items,n):bA(e)?[{title:e.title,format:e.format}]:[],s=q(xA(e),n),r=fB(e,x(s)).fold(x({title:o,tooltipLabel:""}),(e=>({title:e.title,tooltipLabel:e.title})));Lr(t,aT,{text:r.title}),((e,t)=>{e.dispatch("StylesTextUpdate",t)})(e,{value:r.tooltipLabel})},shouldHide:Hf(e),isInvalid:t=>!e.formatter.canApply(t.format),dataset:t}},VB=x([is("toggleClass"),is("fetch"),Si("onExecute"),Cs("getHotspot",A.some),Cs("getAnchorOverrides",x({})),ed(),Si("onItemExecute"),fs("lazySink"),is("dom"),xi("onOpen"),Yu("splitDropdownBehaviours",[tk,xh,Rh]),Cs("matchWidth",!1),Cs("useMinWidth",!1),Cs("eventOrder",{}),fs("role"),fs("listRole")].concat(vk())),HB=wm({factory:zb,schema:[is("dom")],name:"arrow",defaults:()=>({buttonBehaviours:ma([Rh.revoke()])}),overrides:e=>({dom:{tag:"span",attributes:{role:"presentation"}},action:t=>{t.getSystem().getByUid(e.uid).each(Vr)},buttonBehaviours:ma([Wh.config({toggleOnExecute:!1,toggleClass:e.toggleClass})])})}),PB=wm({factory:zb,schema:[is("dom")],name:"button",defaults:()=>({buttonBehaviours:ma([Rh.revoke()])}),overrides:e=>({dom:{tag:"span",attributes:{role:"presentation"}},action:t=>{t.getSystem().getByUid(e.uid).each((o=>{e.onExecute(o,t)}))}})}),UB=x([HB,PB,km({factory:{sketch:e=>({uid:e.uid,dom:{tag:"span",styles:{display:"none"},attributes:{"aria-hidden":"true"},innerHtml:e.text}})},schema:[is("text")],name:"aria-descriptor"}),Sm({schema:[bi()],name:"menu",defaults:e=>({onExecute:(t,o)=>{t.getSystem().getByUid(e.uid).each((n=>{e.onItemExecute(n,t,o)}))}})}),ck()]),WB=Km({name:"SplitDropdown",configFields:VB(),partFields:UB(),factory:(e,t,o,n)=>{const s=e=>{eg.getCurrent(e).each((e=>{Cg.highlightFirst(e),xh.focusIn(e)}))},r=t=>{gk(e,w,t,n,s,vf.HighlightMenuAndItem).get(b)},a=t=>{const o=Nm(t,e,"button");return Vr(o),A.some(!0)},i={...Wr([ea(((t,o)=>{Rm(t,e,"aria-descriptor").each((e=>{const o=Bi("aria");Ct(e.element,"id",o),Ct(t.element,"aria-describedby",o)}))}))]),...$h(A.some(r))},l={repositionMenus:e=>{Wh.isOn(e)&&bk(e)}};return{uid:e.uid,dom:e.dom,components:t,apis:l,eventOrder:{...e.eventOrder,[hr()]:["disabling","toggling","alloy.base.behaviour"]},events:i,behaviours:Ku(e.splitDropdownBehaviours,[tk.config({others:{sandbox:t=>{const o=Nm(t,e,"arrow");return fk(e,t,{onOpen:()=>{Wh.on(o),Wh.on(t)},onClose:()=>{Wh.off(o),Wh.off(t)}})}}}),xh.config({mode:"special",onSpace:a,onEnter:a,onDown:e=>(r(e),A.some(!0))}),Rh.config({}),Wh.config({toggleOnExecute:!1,aria:{mode:"expanded"}})]),domModification:{attributes:{role:e.role.getOr("button"),"aria-haspopup":!0}}}},apis:{repositionMenus:(e,t)=>e.repositionMenus(t)}}),jB=e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t),setText:t=>Lr(e,aT,{text:t}),setIcon:t=>Lr(e,iT,{icon:t})}),$B=e=>({setActive:t=>{Wh.set(e,t)},isActive:()=>Wh.isOn(e),isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t),setText:t=>Lr(e,aT,{text:t}),setIcon:t=>Lr(e,iT,{icon:t})}),GB=(e,t)=>e.map((e=>({"aria-label":t.translate(e)}))).getOr({}),qB=Bi("focus-button"),YB=(e,t,o,n,s,r)=>{const a=t.map((e=>Vb(rT(e,"tox-tbtn",s)))),i=e.map((e=>Vb(sT(e,s.icons))));return{dom:{tag:"button",classes:["tox-tbtn"].concat(t.isSome()?["tox-tbtn--select"]:[]),attributes:{...GB(o,s),...g(r)?{"data-mce-name":r}:{}}},components:yw([i.map((e=>e.asSpec())),a.map((e=>e.asSpec()))]),eventOrder:{[qs()]:["focusing","alloy.base.behaviour",Z_],[_r()]:[Z_,"toolbar-group-button-events"]},buttonBehaviours:ma([gw(s.isDisabled),dw(),Mh(Z_,[ea(((e,t)=>tT(e))),Gr(aT,((e,t)=>{a.bind((t=>t.getOpt(e))).each((e=>{Ah.set(e,[ul(s.translate(t.event.text))])}))})),Gr(iT,((e,t)=>{i.bind((t=>t.getOpt(e))).each((e=>{Ah.set(e,[sT(t.event.icon,s.icons)])}))})),Gr(qs(),((e,t)=>{t.event.prevent(),zr(e,qB)}))])].concat(n.getOr([])))}},XB=(e,t,o,n)=>{var s;const r=on(b),a=YB(e.icon,e.text,e.tooltip,A.none(),o,n);return zb.sketch({dom:a.dom,components:a.components,eventOrder:eT,buttonBehaviours:{...ma([Mh("toolbar-button-events",[(i={onAction:e.onAction,getApi:t.getApi},na(((e,t)=>{pw(i,e)((t=>{Lr(e,Q_,{buttonApi:t}),i.onAction(t)}))}))),hw(t,r),fw(t,r)]),...e.tooltip.map((t=>Zb.config(o.tooltips.getConfig({tooltipText:o.translate(t)+e.shortcut.map((e=>` (${Sw(e)})`)).getOr("")})))).toArray(),gw((()=>!e.enabled||o.isDisabled())),dw()].concat(t.toolbarButtonBehaviours)),[Z_]:null===(s=a.buttonBehaviours)||void 0===s?void 0:s[Z_]}});var i},KB=(e,t,o,n)=>XB(e,{toolbarButtonBehaviours:o.length>0?[Mh("toolbarButtonWith",o)]:[],getApi:jB,onSetup:e.onSetup},t,n),JB=(e,t,o,n)=>XB(e,{toolbarButtonBehaviours:[Ah.config({}),Wh.config({toggleClass:"tox-tbtn--enabled",aria:{mode:"pressed"},toggleOnExecute:!1})].concat(o.length>0?[Mh("toolbarToggleButtonWith",o)]:[]),getApi:$B,onSetup:e.onSetup},t,n),QB=(e,t,o)=>n=>ak((e=>t.fetch(e))).map((s=>A.from(Ak(wn(US(Bi("menu-value"),s,(o=>{t.onItemAction(e(n),o)}),t.columns,t.presets,dy.CLOSE_ON_EXECUTE,t.select.getOr(T),o),{movement:jS(t.columns,t.presets),menuBehaviours:rw("auto"!==t.columns?[]:[ea(((e,o)=>{sw(e,4,Sy(t.presets)).each((({numRows:t,numColumns:o})=>{xh.setGridSize(e,t,o)}))}))])}))))),ZB=[{name:"history",items:["undo","redo"]},{name:"ai",items:["aidialog","aishortcuts"]},{name:"styles",items:["styles"]},{name:"formatting",items:["bold","italic"]},{name:"alignment",items:["alignleft","aligncenter","alignright","alignjustify"]},{name:"indentation",items:["outdent","indent"]},{name:"permanent pen",items:["permanentpen"]},{name:"comments",items:["addcomment"]}],eI=(e,t)=>(o,n,s,r)=>{const a=e(o).mapError((e=>ts(e))).getOrDie();return t(a,n,s,r)},tI={button:eI(Mx,((e,t,o,n)=>((e,t,o)=>KB(e,t,[],o))(e,t.shared.providers,n))),togglebutton:eI(Ix,((e,t,o,n)=>((e,t,o)=>JB(e,t,[],o))(e,t.shared.providers,n))),menubutton:eI(SM,((e,t,o,n)=>WT(e,"tox-tbtn",t,A.none(),!1,n))),splitbutton:eI((e=>Qn("SplitButton",kM,e)),((e,t,o,n)=>((e,t,o)=>{const n=on(e.tooltip.getOr("")),s=e=>({isEnabled:()=>!pg.isDisabled(e),setEnabled:t=>pg.set(e,!t),setIconFill:(t,o)=>{_l(e.element,`svg path[class="${t}"], rect[class="${t}"]`).each((e=>{Ct(e,"fill",o)}))},setActive:t=>{Ct(e.element,"aria-pressed",t),_l(e.element,"span").each((o=>{e.getSystem().getByDom(o).each((e=>Wh.set(e,t)))}))},isActive:()=>_l(e.element,"span").exists((t=>e.getSystem().getByDom(t).exists(Wh.isOn))),setText:t=>_l(e.element,"span").each((o=>e.getSystem().getByDom(o).each((e=>Lr(e,aT,{text:t}))))),setIcon:t=>_l(e.element,"span").each((o=>e.getSystem().getByDom(o).each((e=>Lr(e,iT,{icon:t}))))),setTooltip:o=>{const s=t.providers.translate(o);Ct(e.element,"aria-label",s),n.set(o)}}),r=on(b),a={getApi:s,onSetup:e.onSetup};return WB.sketch({dom:{tag:"div",classes:["tox-split-button"],attributes:{"aria-pressed":!1,...GB(e.tooltip,t.providers),...g(o)?{"data-mce-name":o}:{}}},onExecute:t=>{const o=s(t);o.isEnabled()&&e.onAction(o)},onItemExecute:(e,t,o)=>{},splitDropdownBehaviours:ma([mw(t.providers.isDisabled),dw(),Mh("split-dropdown-events",[ea(((e,t)=>tT(e))),Gr(qB,Rh.focus),hw(a,r),fw(a,r)]),vC.config({}),...e.tooltip.map((e=>Zb.config({...t.providers.tooltips.getConfig({tooltipText:t.providers.translate(e),onShow:o=>{if(n.get()!==e){const e=t.providers.translate(n.get());Zb.setComponents(o,t.providers.tooltips.getComponents({tooltipText:e}))}}})}))).toArray()]),eventOrder:{[_r()]:["alloy.base.behaviour","split-dropdown-events","tooltipping"],[Tr()]:["split-dropdown-events","tooltipping"]},toggleClass:"tox-tbtn--enabled",lazySink:t.getSink,fetch:QB(s,e,t.providers),parts:{menu:Ey(0,e.columns,e.presets)},components:[WB.parts.button(YB(e.icon,e.text,A.none(),A.some([Wh.config({toggleClass:"tox-tbtn--enabled",toggleOnExecute:!1})]),t.providers)),WB.parts.arrow({dom:{tag:"button",classes:["tox-tbtn","tox-split-button__chevron"],innerHtml:oy("chevron-down",t.providers.icons)},buttonBehaviours:ma([mw(t.providers.isDisabled),dw(),ny()])}),WB.parts["aria-descriptor"]({text:t.providers.translate("To open the popup, press Shift+Enter")})]})})(e,t.shared,n))),grouptoolbarbutton:eI((e=>Qn("GroupToolbarButton",yM,e)),((e,t,o,n)=>{const s=o.ui.registry.getAll().buttons,r={[Qc]:t.shared.header.isPositionedAtTop()?Jc.TopToBottom:Jc.BottomToTop};if(Wf(o)===Sf.floating)return((e,t,o,n,s)=>{const r=t.shared,a=on(b),i={toolbarButtonBehaviours:[],getApi:jB,onSetup:e.onSetup},l=[Mh("toolbar-group-button-events",[hw(i,a),fw(i,a)])];return rD.sketch({lazySink:r.getSink,fetch:()=>ak((t=>{t(L(o(e.items),vD))})),markers:{toggledClass:"tox-tbtn--enabled"},parts:{button:YB(e.icon,e.text,e.tooltip,A.some(l),r.providers,s),toolbar:{dom:{tag:"div",classes:["tox-toolbar__overflow"],attributes:n}}}})})(e,t,(e=>nI(o,{buttons:s,toolbar:e,allowToolbarGroups:!1},t,A.none())),r,n);throw new Error("Toolbar groups are only supported when using floating toolbar mode")}))},oI={styles:(e,t)=>{const o={type:"advanced",...t.styles};return cB(e,t,LB(e,o),zB,"StylesTextUpdate","styles")},fontsize:(e,t)=>cB(e,t,NB(e),MB,"FontSizeTextUpdate","fontsize"),fontsizeinput:(e,t)=>((e,t,o,n)=>{let s=A.none();const r=iS(e,"NodeChange SwitchMode",(t=>{const n=t.getComponent();s=A.some(n),o.updateInputValue(n),pg.set(n,!e.selection.isEditable())})),a=e=>({getComponent:x(e)}),i=on(b),l=Bi("custom-number-input-events"),c=(e,t,n)=>{const r=s.map((e=>qu.getValue(e))).getOr(""),a=o.getNewValue(r,e),i=r.length-`${a}`.length,l=s.map((e=>e.element.dom.selectionStart-i)),c=s.map((e=>e.element.dom.selectionEnd-i));o.onAction(a,n),s.each((e=>{qu.setValue(e,a),t&&(l.each((t=>e.element.dom.selectionStart=t)),c.each((t=>e.element.dom.selectionEnd=t)))}))},d=(e,t)=>c(((e,t)=>e-t),e,t),u=(e,t)=>c(((e,t)=>e+t),e,t),m=e=>at(e.element).fold(A.none,(e=>(hc(e),A.some(!0)))),p=e=>bc(e.element)?(dt(e.element).each((e=>hc(e))),A.some(!0)):A.none(),h=(o,n,s,r)=>{const i=on(b),l=t.shared.providers.translate(s),c=Bi("altExecuting"),d=iS(e,"NodeChange SwitchMode",(t=>{pg.set(t.getComponent(),!e.selection.isEditable())})),u=e=>{pg.isDisabled(e)||o(!0)};return zb.sketch({dom:{tag:"button",attributes:{"aria-label":l,"data-mce-name":n},classes:r.concat(n)},components:[nT(n,t.shared.providers.icons)],buttonBehaviours:ma([pg.config({}),Zb.config(t.shared.providers.tooltips.getConfig({tooltipText:l})),Mh(c,[hw({onSetup:d,getApi:a},i),fw({getApi:a},i),Gr(er(),((e,t)=>{t.event.raw.keyCode!==AB.space()&&t.event.raw.keyCode!==AB.enter()||pg.isDisabled(e)||o(!1)})),Gr(sr(),u),Gr($s(),u)])]),eventOrder:{[er()]:[c,"keying"],[sr()]:[c,"alloy.base.behaviour"],[$s()]:[c,"alloy.base.behaviour"],[_r()]:["alloy.base.behaviour",c,"tooltipping"],[Tr()]:[c,"tooltipping"]}})},f=Vb(h((e=>d(!1,e)),"minus","Decrease font size",[])),v=Vb(h((e=>u(!1,e)),"plus","Increase font size",[])),y=Vb({dom:{tag:"div",classes:["tox-input-wrapper"]},components:[Iy.sketch({inputBehaviours:ma([pg.config({}),Mh(l,[hw({onSetup:r,getApi:a},i),fw({getApi:a},i)]),Mh("input-update-display-text",[Gr(aT,((e,t)=>{qu.setValue(e,t.event.text)})),Gr(Zs(),(e=>{o.onAction(qu.getValue(e))})),Gr(nr(),(e=>{o.onAction(qu.getValue(e))}))]),xh.config({mode:"special",onEnter:e=>(c(w,!0,!0),A.some(!0)),onEscape:m,onUp:e=>(u(!0,!1),A.some(!0)),onDown:e=>(d(!0,!1),A.some(!0)),onLeft:(e,t)=>(t.cut(),A.none()),onRight:(e,t)=>(t.cut(),A.none())})])})],behaviours:ma([Rh.config({}),xh.config({mode:"special",onEnter:p,onSpace:p,onEscape:m}),Mh("input-wrapper-events",[Gr(Js(),(e=>{V([f,v],(t=>{const o=ze(t.get(e).element.dom);bc(o)&&fc(o)}))}))])])});return{dom:{tag:"div",classes:["tox-number-input"],attributes:{...g(n)?{"data-mce-name":n}:{}}},components:[f.asSpec(),y.asSpec(),v.asSpec()],behaviours:ma([Rh.config({}),xh.config({mode:"flow",focusInside:qg.OnEnterOrSpaceMode,cycles:!1,selector:"button, .tox-input-wrapper",onEscape:e=>bc(e.element)?A.none():(hc(e.element),A.some(!0))})])}})(e,t,(e=>{const t=()=>e.queryCommandValue("FontSize");return{updateInputValue:e=>Lr(e,aT,{text:t()}),onAction:(t,o)=>e.execCommand("FontSize",!1,t,{skip_focus:!o}),getNewValue:(o,n)=>{EB(o,["unsupportedLength","empty"]);const s=t(),r=EB(o,["unsupportedLength","empty"]).or(EB(s,["unsupportedLength","empty"])),a=r.map((e=>e.value)).getOr(16),i=eb(e),l=r.map((e=>e.unit)).filter((e=>""!==e)).getOr(i),c=n(a,(e=>{var t;return null!==(t={em:{step:.1},cm:{step:.1},in:{step:.1},pc:{step:.1},ch:{step:.1},rem:{step:.1}}[e])&&void 0!==t?t:{step:1}})(l).step),d=`${(e=>e>=0)(c)?c:a}${l}`;return d!==s&&((e,t)=>{e.dispatch("FontSizeInputTextUpdate",t)})(e,{value:d}),d}}})(e),"fontsizeinput"),fontfamily:(e,t)=>cB(e,t,OB(e),xB,"FontFamilyTextUpdate","fontfamily"),blocks:(e,t)=>cB(e,t,yB(e),bB,"BlocksTextUpdate","blocks"),align:(e,t)=>cB(e,t,hB(e),mB,"AlignTextUpdate","align")},nI=(e,t,o,n)=>{const s=(e=>{const t=e.toolbar,o=e.buttons;return!1===t?[]:void 0===t||!0===t?(e=>{const t=L(ZB,(t=>{const o=P(t.items,(t=>be(e,t)||be(oI,t)));return{name:t.name,items:o}}));return P(t,(e=>e.items.length>0))})(o):r(t)?(e=>{const t=e.split("|");return L(t,(e=>({items:e.trim().split(" ")})))})(t):(e=>f(e,(e=>be(e,"name")&&be(e,"items"))))(t)?t:(console.error("Toolbar type should be string, string[], boolean or ToolbarGroup[]"),[])})(t),a=L(s,(s=>{const r=q(s.items,(s=>0===s.trim().length?[]:((e,t,o,n,s,r)=>fe(t,o.toLowerCase()).orThunk((()=>r.bind((e=>se(e,(e=>fe(t,e+o.toLowerCase()))))))).fold((()=>fe(oI,o.toLowerCase()).map((t=>t(e,s)))),(t=>"grouptoolbarbutton"!==t.type||n?((e,t,o,n)=>fe(tI,e.type).fold((()=>(console.error("skipping button defined by",e),A.none())),(s=>A.some(s(e,t,o,n)))))(t,s,e,o.toLowerCase()):(console.warn(`Ignoring the '${o}' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`),A.none()))))(e,t.buttons,s,t.allowToolbarGroups,o,n).toArray()));return{title:A.from(e.translate(s.name)),items:r}}));return P(a,(e=>e.items.length>0))},sI=(e,t,o,n)=>{const s=t.mainUi.outerContainer,a=o.toolbar,i=o.buttons;if(f(a,r)){const t=a.map((t=>{const s={toolbar:t,buttons:i,allowToolbarGroups:o.allowToolbarGroups};return nI(e,s,n,A.none())}));XD.setToolbars(s,t)}else XD.setToolbar(s,nI(e,o,n,A.none()))},rI=Bo(),aI=rI.os.isiOS()&&rI.os.version.major<=12;var iI=Object.freeze({__proto__:null,render:(e,t,o,n,s)=>{const{mainUi:r,uiMotherships:a}=t,i=on(0),l=r.outerContainer;sB(e);const d=ze(s.targetNode),u=bt(ft(d));pu(d,r.mothership),((e,t,o)=>{Ab(e)&&pu(o.mainUi.mothership.element,o.popupUi.mothership),gu(t,o.dialogUi.mothership)})(e,u,t),e.on("SkinLoaded",(()=>{XD.setSidebar(l,o.sidebar,ub(e)),sI(e,t,o,n),i.set(e.getWin().innerWidth),XD.setMenubar(l,QD(e,o)),XD.setViews(l,o.views),((e,t)=>{const{uiMotherships:o}=t,n=e.dom;let s=e.getWin();const r=e.getDoc().documentElement,a=on(qt(s.innerWidth,s.innerHeight)),i=on(qt(r.offsetWidth,r.offsetHeight)),l=()=>{const t=a.get();t.left===s.innerWidth&&t.top===s.innerHeight||(a.set(qt(s.innerWidth,s.innerHeight)),tS(e))},c=()=>{const t=e.getDoc().documentElement,o=i.get();o.left===t.offsetWidth&&o.top===t.offsetHeight||(i.set(qt(t.offsetWidth,t.offsetHeight)),tS(e))},d=t=>{((e,t)=>{e.dispatch("ScrollContent",t)})(e,t)};n.bind(s,"resize",l),n.bind(s,"scroll",d);const u=Rc(ze(e.getBody()),"load",c);e.on("hide",(()=>{V(o,(e=>{Bt(e.element,"display","none")}))})),e.on("show",(()=>{V(o,(e=>{Ht(e.element,"display")}))})),e.on("NodeChange",c),e.on("remove",(()=>{u.unbind(),n.unbind(s,"resize",l),n.unbind(s,"scroll",d),s=null}))})(e,t)}));const m=XD.getSocket(l).getOrDie("Could not find expected socket element");if(aI){It(m.element,{overflow:"scroll","-webkit-overflow-scrolling":"touch"});const t=((e,t)=>{let o=null;return{cancel:()=>{c(o)||(clearTimeout(o),o=null)},throttle:(...t)=>{c(o)&&(o=setTimeout((()=>{o=null,e.apply(null,t)}),20))}}})((()=>{e.dispatch("ScrollContent")})),o=Fc(m.element,"scroll",t.throttle);e.on("remove",o.unbind)}cw(e,t),e.addCommand("ToggleSidebar",((t,o)=>{XD.toggleSidebar(l,o),e.dispatch("ToggleSidebar")})),e.addQueryValueHandler("ToggleSidebar",(()=>{var e;return null!==(e=XD.whichSidebar(l))&&void 0!==e?e:""})),e.addCommand("ToggleView",((t,o)=>{if(XD.toggleView(l,o)){const t=l.element;r.mothership.broadcastOn([Eu()],{target:t}),V(a,(e=>{e.broadcastOn([Eu()],{target:t})})),c(XD.whichView(l))&&(e.focus(),e.nodeChanged(),XD.refreshToolbar(l))}})),e.addQueryValueHandler("ToggleView",(()=>{var e;return null!==(e=XD.whichView(l))&&void 0!==e?e:""}));const g=Wf(e);g!==Sf.sliding&&g!==Sf.floating||e.on("ResizeWindow ResizeEditor ResizeContent",(()=>{const o=e.getWin().innerWidth;o!==i.get()&&(XD.refreshToolbar(t.mainUi.outerContainer),i.set(o))}));const p={setEnabled:e=>{lw(t,!e)},isEnabled:()=>!pg.isDisabled(l)};return{iframeContainer:m.element.dom,editorContainer:l.element.dom,api:p}}});const lI=e=>/^[0-9\.]+(|px)$/i.test(""+e)?A.some(parseInt(""+e,10)):A.none(),cI=e=>h(e)?e+"px":e,dI=(e,t,o)=>{const n=t.filter((t=>e<t)),s=o.filter((t=>e>t));return n.or(s).getOr(e)},uI=e=>{const t=If(e),o=Ff(e),n=Nf(e);return lI(t).map((e=>dI(e,o,n)))},{ToolbarLocation:mI,ToolbarMode:gI}=Db,pI=(e,t,o,n,s)=>{const{mainUi:r,uiMotherships:a}=o,i=Of.DOM,l=Ob(e),c=Eb(e),d=Nf(e).or(uI(e)),u=n.shared.header,m=u.isPositionedAtTop,g=Wf(e),p=g===gI.sliding||g===gI.floating,h=on(!1),f=()=>h.get()&&!e.removed,b=e=>p?e.fold(x(0),(e=>e.components().length>1?jt(e.components()[1].element):0)):0,v=()=>{V(a,(e=>{e.broadcastOn([Au()],{})}))},y=o=>{if(!f())return;l||s.on((e=>{const o=d.getOrThunk((()=>Go().width-Kt(t).left-10));Bt(e.element,"max-width",o+"px")}));const n=Wo(),a=!(l||l||!(Xt(r.outerContainer.element).left+Zt(r.outerContainer.element)>=window.innerWidth-40||zt(r.outerContainer.element,"width").isSome())||(Bt(r.outerContainer.element,"position","absolute"),Bt(r.outerContainer.element,"left","0px"),Ht(r.outerContainer.element,"width"),0));if(p&&XD.refreshToolbar(r.outerContainer),!l){const o=Wo(),i=ke(n.left!==o.left,n);((o,n)=>{s.on((s=>{const a=XD.getToolbar(r.outerContainer),i=b(a),l=Qo(t),c=((e,t)=>Ab(e)?Ba(t):A.none())(e,r.outerContainer.element),d=c.fold((()=>l.x),(e=>{const t=Qo(e);return Ze(e,wt())?l.x:l.x-t.x})),u=ke(o,Math.ceil(r.outerContainer.element.dom.getBoundingClientRect().width)).filter((e=>e>150)).map((e=>{const t=n.getOr(Wo()),o=window.innerWidth-(d-t.left),s=Math.max(Math.min(e,o),150);return o<e&&Bt(r.outerContainer.element,"width",s+"px"),{width:s+"px"}})).getOr({width:"max-content"}),g={position:"absolute",left:Math.round(d)+"px",top:c.fold((()=>m()?Math.max(l.y-jt(s.element)+i,0):l.bottom),(e=>{var t;const o=Qo(e),n=null!==(t=e.dom.scrollTop)&&void 0!==t?t:0,r=Ze(e,wt())?Math.max(l.y-jt(s.element)+i,0):l.y-o.y+n-jt(s.element)+i;return m()?r:l.bottom}))+"px"};It(r.outerContainer.element,{...g,...u})}))})(a,i),i.each((e=>{jo(e.left,o.top)}))}c&&s.on(o),v()},w=()=>!(l||!c||!f())&&s.get().exists((o=>{const n=u.getDockingMode(),a=(o=>{switch($f(e)){case mI.auto:const e=XD.getToolbar(r.outerContainer),n=b(e),s=jt(o.element)-n,a=Qo(t);if(a.y>s)return"top";{const e=nt(t),o=Math.max(e.dom.scrollHeight,jt(e));return a.bottom<o-s||tn().bottom<a.bottom-s?"bottom":"top"}case mI.bottom:return"bottom";case mI.top:default:return"top"}})(o);return a!==n&&(i=a,s.on((e=>{Ei.setModes(e,[i]),u.setDockingMode(i);const t=m()?Jc.TopToBottom:Jc.BottomToTop;Ct(e.element,Qc,t)})),!0);var i}));return{isVisible:f,isPositionedAtTop:m,show:()=>{h.set(!0),Bt(r.outerContainer.element,"display","flex"),i.addClass(e.getBody(),"mce-edit-focus"),V(a,(e=>{Ht(e.element,"display")})),w(),Ab(e)?y((e=>Ei.isDocked(e)?Ei.reset(e):Ei.refresh(e))):y(Ei.refresh)},hide:()=>{h.set(!1),Bt(r.outerContainer.element,"display","none"),i.removeClass(e.getBody(),"mce-edit-focus"),V(a,(e=>{Bt(e.element,"display","none")}))},update:y,updateMode:()=>{w()&&y(Ei.reset)},repositionPopups:v}},hI=(e,t)=>{const o=Qo(e);return{pos:t?o.y:o.bottom,bounds:o}};var fI=Object.freeze({__proto__:null,render:(e,t,o,n,s)=>{const{mainUi:r}=t,a=rn(),i=ze(s.targetNode),l=pI(e,i,t,n,a),c=Yf(e);rB(e);const d=()=>{if(a.isSet())return void l.show();a.set(XD.getHeader(r.outerContainer).getOrDie());const s=_b(e);Ab(e)?(pu(i,r.mothership),pu(i,t.popupUi.mothership)):gu(s,r.mothership),gu(s,t.dialogUi.mothership);const d=()=>{sI(e,t,o,n),XD.setMenubar(r.outerContainer,QD(e,o)),l.show(),((e,t,o,n)=>{const s=on(hI(t,o.isPositionedAtTop())),r=n=>{const{pos:r,bounds:a}=hI(t,o.isPositionedAtTop()),{pos:i,bounds:l}=s.get(),c=a.height!==l.height||a.width!==l.width;s.set({pos:r,bounds:a}),c&&tS(e,n),o.isVisible()&&(i!==r?o.update(Ei.reset):c&&(o.updateMode(),o.repositionPopups()))};n||(e.on("activate",o.show),e.on("deactivate",o.hide)),e.on("SkinLoaded ResizeWindow",(()=>o.update(Ei.reset))),e.on("NodeChange keydown",(e=>{requestAnimationFrame((()=>r(e)))}));let a=0;const i=A_((()=>o.update(Ei.refresh)),33);e.on("ScrollWindow",(()=>{const e=Wo().left;e!==a&&(a=e,i.throttle()),o.updateMode()})),Ab(e)&&e.on("ElementScroll",(e=>{o.update(Ei.refresh)}));const l=sn();l.set(Rc(ze(e.getBody()),"load",(e=>r(e.raw)))),e.on("remove",(()=>{l.clear()}))})(e,i,l,c),e.nodeChanged()};c?e.once("SkinLoaded",d):d()};e.on("show",d),e.on("hide",l.hide),c||(e.on("focus",d),e.on("blur",l.hide)),e.on("init",(()=>{(e.hasFocus()||c)&&d()})),cw(e,t);const u={show:d,hide:l.hide,setEnabled:e=>{lw(t,!e)},isEnabled:()=>!pg.isDisabled(r.outerContainer)};return{editorContainer:r.outerContainer.element.dom,api:u}}});const bI="contexttoolbar-hide",vI=(e,t)=>Gr(Q_,((o,n)=>{const s=(e=>({hide:()=>zr(e,yr()),getValue:()=>qu.getValue(e)}))(e.get(o));t.onAction(s,n.event.buttonApi)})),yI=(e,t)=>{const o=e.label.fold((()=>({})),(e=>({"aria-label":e}))),n=Vb(Iy.sketch({inputClasses:["tox-toolbar-textfield","tox-toolbar-nav-js"],data:e.initValue(),inputAttributes:o,selectOnFocus:!0,inputBehaviours:ma([xh.config({mode:"special",onEnter:e=>s.findPrimary(e).map((e=>(Vr(e),!0))),onLeft:(e,t)=>(t.cut(),A.none()),onRight:(e,t)=>(t.cut(),A.none())})])})),s=((e,t,o)=>{const n=L(t,(t=>Vb(((e,t,o)=>(e=>"contextformtogglebutton"===e.type)(t)?((e,t,o)=>{const{primary:n,...s}=t.original,r=Zn(Ix({...s,type:"togglebutton",onAction:b}));return JB(r,o,[vI(e,t)])})(e,t,o):((e,t,o)=>{const{primary:n,...s}=t.original,r=Zn(Mx({...s,type:"button",onAction:b}));return KB(r,o,[vI(e,t)])})(e,t,o))(e,t,o))));return{asSpecs:()=>L(n,(e=>e.asSpec())),findPrimary:e=>se(t,((t,o)=>t.primary?A.from(n[o]).bind((t=>t.getOpt(e))).filter(C(pg.isDisabled)):A.none()))}})(n,e.commands,t);return[{title:A.none(),items:[n.asSpec()]},{title:A.none(),items:s.asSpecs()}]},xI=(e,t,o)=>t.bottom-e.y>=o&&e.bottom-t.y>=o,wI=e=>{const t=(e=>{const t=e.getBoundingClientRect();if(t.height<=0&&t.width<=0){const o=mt(ze(e.startContainer),e.startOffset).element;return(Ge(o)?rt(o):A.some(o)).filter($e).map((e=>e.dom.getBoundingClientRect())).getOr(t)}return t})(e.selection.getRng());if(e.inline){const e=Wo();return Jo(e.left+t.left,e.top+t.top,t.width,t.height)}{const o=Zo(ze(e.getBody()));return Jo(o.x+t.left,o.y+t.top,t.width,t.height)}},SI=(e,t,o,n=0)=>{const s=Go(window),r=Qo(ze(e.getContentAreaContainer())),a=fb(e)||xb(e)||Sb(e),{x:i,width:l}=((e,t,o)=>{const n=Math.max(e.x+o,t.x);return{x:n,width:Math.min(e.right-o,t.right)-n}})(r,s,n);if(e.inline&&!a)return Jo(i,s.y,l,s.height);{const a=t.header.isPositionedAtTop(),{y:c,bottom:d}=((e,t,o,n,s,r)=>{const a=ze(e.getContainer()),i=_l(a,".tox-editor-header").getOr(a),l=Qo(i),c=l.y>=t.bottom,d=n&&!c;if(e.inline&&d)return{y:Math.max(l.bottom+r,o.y),bottom:o.bottom};if(e.inline&&!d)return{y:o.y,bottom:Math.min(l.y-r,o.bottom)};const u="line"===s?Qo(a):t;return d?{y:Math.max(l.bottom+r,o.y),bottom:Math.min(u.bottom-r,o.bottom)}:{y:Math.max(u.y+r,o.y),bottom:Math.min(l.y-r,o.bottom)}})(e,r,s,a,o,n);return Jo(i,c,l,d-c)}},kI={valignCentre:[],alignCentre:[],alignLeft:["tox-pop--align-left"],alignRight:["tox-pop--align-right"],right:["tox-pop--right"],left:["tox-pop--left"],bottom:["tox-pop--bottom"],top:["tox-pop--top"],inset:["tox-pop--inset"]},CI={maxHeightFunction:Uc(),maxWidthFunction:QM()},OI=e=>"node"===e,_I=(e,t,o,n,s)=>{const r=wI(e),a=n.lastElement().exists((e=>Ze(o,e)));return((e,t)=>{const o=e.selection.getRng(),n=mt(ze(o.startContainer),o.startOffset);return o.startContainer===o.endContainer&&o.startOffset===o.endOffset-1&&Ze(n.element,t)})(e,o)?a?tA:KE:a?((e,o,s)=>{const a=zt(e,"position");Bt(e,"position",o);const i=xI(r,Qo(t),-20)&&!n.isReposition()?nA:tA;return a.each((t=>Bt(e,"position",t))),i})(t,n.getMode()):("fixed"===n.getMode()?s.y+Wo().top:s.y)+(jt(t)+12)<=r.y?KE:JE},TI=(e,t,o,n)=>{const s=t=>(n,s,r,a,i)=>({..._I(e,a,t,o,i)({...n,y:i.y,height:i.height},s,r,a,i),alwaysFit:!0}),r=e=>OI(n)?[s(e)]:[];return t?{onLtr:e=>[oc,Jl,Ql,Zl,ec,tc].concat(r(e)),onRtl:e=>[oc,Ql,Jl,ec,Zl,tc].concat(r(e))}:{onLtr:e=>[tc,oc,Zl,Jl,ec,Ql].concat(r(e)),onRtl:e=>[tc,oc,ec,Ql,Zl,Jl].concat(r(e))}},EI=(e,t)=>{const o=P(t,(t=>t.predicate(e.dom))),{pass:n,fail:s}=H(o,(e=>"contexttoolbar"===e.type));return{contextToolbars:n,contextForms:s}},AI=(e,t)=>{const o={},n=[],s=[],r={},a={},i=re(e);return V(i,(i=>{const l=e[i];"contextform"===l.type?((e,i)=>{const l=Zn(Qn("ContextForm",Hx,i));o[e]=l,l.launch.map((o=>{r["form:"+e]={...i.launch,type:"contextformtogglebutton"===o.type?"togglebutton":"button",onAction:()=>{t(l)}}})),"editor"===l.scope?s.push(l):n.push(l),a[e]=l})(i,l):"contexttoolbar"===l.type&&((e,t)=>{var o;(o=t,Qn("ContextToolbar",Px,o)).each((o=>{"editor"===t.scope?s.push(o):n.push(o),a[e]=o}))})(i,l)})),{forms:o,inNodeScope:n,inEditorScope:s,lookupTable:a,formNavigators:r}},MI=Bi("forward-slide"),DI=Bi("backward-slide"),BI=Bi("change-slide-event"),II="tox-pop--resizing",FI="tox-pop--transition",RI=(e,t,o,n)=>{const s=n.backstage,r=s.shared,a=Bo().deviceType.isTouch,i=rn(),l=rn(),c=rn(),d=hl((e=>{const t=on([]);return wf.sketch({dom:{tag:"div",classes:["tox-pop"]},fireDismissalEventInstead:{event:"doNotDismissYet"},onShow:e=>{t.set([]),wf.getContent(e).each((e=>{Ht(e.element,"visibility")})),Oa(e.element,II),Ht(e.element,"width")},inlineBehaviours:ma([Mh("context-toolbar-events",[Zr(ar(),((e,t)=>{"width"===t.event.raw.propertyName&&(Oa(e.element,II),Ht(e.element,"width"))})),Gr(BI,((e,t)=>{const o=e.element;Ht(o,"width");const n=Qt(o);wf.setContent(e,t.event.contents),ka(o,II);const s=Qt(o);Bt(o,"width",n+"px"),wf.getContent(e).each((e=>{t.event.focus.bind((e=>(hc(e),yc(o)))).orThunk((()=>(xh.focusIn(e),vc(ft(o)))))})),setTimeout((()=>{Bt(e.element,"width",s+"px")}),0)})),Gr(MI,((e,o)=>{wf.getContent(e).each((o=>{t.set(t.get().concat([{bar:o,focus:vc(ft(e.element))}]))})),Lr(e,BI,{contents:o.event.forwardContents,focus:A.none()})})),Gr(DI,((e,o)=>{oe(t.get()).each((o=>{t.set(t.get().slice(0,t.get().length-1)),Lr(e,BI,{contents:fl(o.bar),focus:o.focus})}))}))]),xh.config({mode:"special",onEscape:o=>oe(t.get()).fold((()=>e.onEscape()),(e=>(zr(o,DI),A.some(!0))))})]),lazySink:()=>dn.value(e.sink)})})({sink:o,onEscape:()=>(e.focus(),A.some(!0))})),u=()=>{const t=c.get().getOr("node"),o=OI(t)?1:0;return SI(e,r,t,o)},m=()=>!(e.removed||a()&&s.isContextMenuOpen()),g=()=>{if(m()){const t=u(),o=ye(c.get(),"node")?((e,t)=>t.filter((e=>xt(e)&&je(e))).map(Zo).getOrThunk((()=>wI(e))))(e,i.get()):wI(e);return t.height<=0||!xI(o,t,.01)}return!0},p=()=>{i.clear(),l.clear(),c.clear(),wf.hide(d)},h=()=>{if(wf.isOpen(d)){const e=d.element;Ht(e,"display"),g()?Bt(e,"display","none"):(l.set(0),wf.reposition(d))}},f=t=>({dom:{tag:"div",classes:["tox-pop__dialog"]},components:[t],behaviours:ma([xh.config({mode:"acyclic"}),Mh("pop-dialog-wrap-events",[ea((t=>{e.shortcuts.add("ctrl+F9","focus statusbar",(()=>xh.focusIn(t)))})),ta((t=>{e.shortcuts.remove("ctrl+F9")}))])])}),v=eo((()=>AI(t,(e=>{const t=y([e]);Lr(d,MI,{forwardContents:f(t)})})))),y=t=>{const{buttons:o}=e.ui.registry.getAll(),s={...o,...v().formNavigators},a=Wf(e)===Sf.scrolling?Sf.scrolling:Sf.default,i=G(L(t,(t=>"contexttoolbar"===t.type?((t,o)=>nI(e,{buttons:t,toolbar:o.items,allowToolbarGroups:!1},n.backstage,A.some(["form:"])))(s,t):((e,t)=>yI(e,t))(t,r.providers))));return kD({type:a,uid:Bi("context-toolbar"),initGroups:i,onEscape:A.none,cyclicKeying:!0,providers:r.providers})},x=(t,n)=>{if(S.cancel(),!m())return;const s=y(t),p=t[0].position,h=((t,n)=>{const s="node"===t?r.anchors.node(n):r.anchors.cursor(),c=((e,t,o,n)=>"line"===t?{bubble:Gc(12,0,kI),layouts:{onLtr:()=>[nc],onRtl:()=>[sc]},overrides:CI}:{bubble:Gc(0,12,kI,1/12),layouts:TI(e,o,n,t),overrides:CI})(e,t,a(),{lastElement:i.get,isReposition:()=>ye(l.get(),0),getMode:()=>tu.getMode(o)});return wn(s,c)})(p,n);c.set(p),l.set(1);const b=d.element;Ht(b,"display"),(e=>ye(we(e,i.get(),Ze),!0))(n)||(Oa(b,FI),tu.reset(o,d)),wf.showWithinBounds(d,f(s),{anchor:h,transition:{classes:[FI],mode:"placement"}},(()=>A.some(u()))),n.fold(i.clear,i.set),g()&&Bt(b,"display","none")};let w=!1;const S=A_((()=>{!e.hasFocus()||e.removed||w||(_a(d.element,FI)?S.throttle():((e,t)=>{const o=ze(t.getBody()),n=e=>Ze(e,o),s=ze(t.selection.getNode());return(e=>!n(e)&&!et(o,e))(s)?A.none():((e,t,o)=>{const n=EI(e,t);if(n.contextForms.length>0)return A.some({elem:e,toolbars:[n.contextForms[0]]});{const t=EI(e,o);if(t.contextForms.length>0)return A.some({elem:e,toolbars:[t.contextForms[0]]});if(n.contextToolbars.length>0||t.contextToolbars.length>0){const o=(e=>{if(e.length<=1)return e;{const t=t=>R(e,(e=>e.position===t)),o=t=>P(e,(e=>e.position===t)),n=t("selection"),s=t("node");if(n||s){if(s&&n){const e=o("node"),t=L(o("selection"),(e=>({...e,position:"node"})));return e.concat(t)}return o(n?"selection":"node")}return o("line")}})(n.contextToolbars.concat(t.contextToolbars));return A.some({elem:e,toolbars:o})}return A.none()}})(s,e.inNodeScope,e.inEditorScope).orThunk((()=>((e,t,o)=>e(t)?A.none():zs(t,(e=>{if($e(e)){const{contextToolbars:t,contextForms:n}=EI(e,o.inNodeScope),s=n.length>0?n:(e=>{if(e.length<=1)return e;{const t=t=>j(e,(e=>e.position===t));return t("selection").orThunk((()=>t("node"))).orThunk((()=>t("line"))).map((e=>e.position)).fold((()=>[]),(t=>P(e,(e=>e.position===t))))}})(t);return s.length>0?A.some({elem:e,toolbars:s}):A.none()}return A.none()}),e))(n,s,e)))})(v(),e).fold(p,(e=>{x(e.toolbars,A.some(e.elem))})))}),17);e.on("init",(()=>{e.on("remove",p),e.on("ScrollContent ScrollWindow ObjectResized ResizeEditor longpress",h),e.on("click keyup focus SetContent",S.throttle),e.on(bI,p),e.on("contexttoolbar-show",(t=>{const o=v();fe(o.lookupTable,t.toolbarKey).each((o=>{x([o],ke(t.target!==e,t.target)),wf.getContent(d).each(xh.focusIn)}))})),e.on("focusout",(t=>{Cf.setEditorTimeout(e,(()=>{yc(o.element).isNone()&&yc(d.element).isNone()&&p()}),0)})),e.on("SwitchMode",(()=>{e.mode.isReadOnly()&&p()})),e.on("ExecCommand",(({command:e})=>{"toggleview"===e.toLowerCase()&&p()})),e.on("AfterProgressState",(t=>{t.state?p():e.hasFocus()&&S.throttle()})),e.on("dragstart",(()=>{w=!0})),e.on("dragend drop",(()=>{w=!1})),e.on("NodeChange",(e=>{yc(d.element).fold(S.throttle,b)}))}))},NI=(e,t)=>{const o=()=>{const o=t.getOptions(e),n=t.getCurrent(e).map(t.hash),s=rn();return L(o,(o=>({type:"togglemenuitem",text:t.display(o),onSetup:r=>{const a=e=>{e&&(s.on((e=>e.setActive(!1))),s.set(r)),r.setActive(e)};a(ye(n,t.hash(o)));const i=t.watcher(e,o,a);return()=>{s.clear(),i()}},onAction:()=>t.setCurrent(e,o)})))};e.ui.registry.addMenuButton(t.name,{tooltip:t.text,icon:t.icon,fetch:e=>e(o()),onSetup:t.onToolbarSetup}),e.ui.registry.addNestedMenuItem(t.name,{type:"nestedmenuitem",text:t.text,getSubmenuItems:o,onSetup:t.onMenuSetup})},zI=e=>{NI(e,(e=>({name:"lineheight",text:"Line height",icon:"line-height",getOptions:yb,hash:e=>((e,t)=>EB(e,["fixed","relative","empty"]).map((({value:e,unit:t})=>e+t)))(e).getOr(e),display:w,watcher:(e,t,o)=>e.formatter.formatChanged("lineheight",o,!1,{value:t}).unbind,getCurrent:e=>A.from(e.queryCommandValue("LineHeight")),setCurrent:(e,t)=>e.execCommand("LineHeight",!1,t),onToolbarSetup:rS(e),onMenuSetup:rS(e)}))(e)),(e=>A.from(Pf(e)).map((t=>({name:"language",text:"Language",icon:"language",getOptions:x(t),hash:e=>u(e.customCode)?e.code:`${e.code}/${e.customCode}`,display:e=>e.title,watcher:(e,t,o)=>{var n;return e.formatter.formatChanged("lang",o,!1,{value:t.code,customValue:null!==(n=t.customCode)&&void 0!==n?n:null}).unbind},getCurrent:e=>{const t=ze(e.selection.getNode());return Ls(t,(e=>A.some(e).filter($e).bind((e=>Tt(e,"lang").map((t=>({code:t,customCode:Tt(e,"data-mce-lang").getOrUndefined(),title:""})))))))},setCurrent:(e,t)=>e.execCommand("Lang",!1,t),onToolbarSetup:t=>{const o=sn();return t.setActive(e.formatter.match("lang",{},void 0,!0)),o.set(e.formatter.formatChanged("lang",t.setActive,!0)),sS(o.clear,rS(e)(t))},onMenuSetup:rS(e)}))))(e).each((t=>NI(e,t)))},LI=e=>iS(e,"NodeChange",(t=>{t.setEnabled(e.queryCommandState("outdent")&&e.selection.isEditable())})),VI=(e,t)=>o=>{o.setActive(t.get());const n=e=>{t.set(e.state),o.setActive(e.state)};return e.on("PastePlainTextToggle",n),sS((()=>e.off("PastePlainTextToggle",n)),rS(e)(o))},HI=(e,t)=>()=>{e.execCommand("mceToggleFormat",!1,t)},PI=e=>{(e=>{(e=>{E_.each([{name:"bold",text:"Bold",icon:"bold",shortcut:"Meta+B"},{name:"italic",text:"Italic",icon:"italic",shortcut:"Meta+I"},{name:"underline",text:"Underline",icon:"underline",shortcut:"Meta+U"},{name:"strikethrough",text:"Strikethrough",icon:"strike-through"},{name:"subscript",text:"Subscript",icon:"subscript"},{name:"superscript",text:"Superscript",icon:"superscript"}],((t,o)=>{e.ui.registry.addToggleButton(t.name,{tooltip:t.text,icon:t.icon,onSetup:aS(e,t.name),onAction:HI(e,t.name),shortcut:t.shortcut})}));for(let t=1;t<=6;t++){const o="h"+t,n=`Access+${t}`;e.ui.registry.addToggleButton(o,{text:o.toUpperCase(),tooltip:"Heading "+t,onSetup:aS(e,o),onAction:HI(e,o),shortcut:n})}})(e),(e=>{E_.each([{name:"copy",text:"Copy",action:"Copy",icon:"copy"},{name:"help",text:"Help",action:"mceHelp",icon:"help",shortcut:"Alt+0"},{name:"selectall",text:"Select all",action:"SelectAll",icon:"select-all",shortcut:"Meta+A"},{name:"newdocument",text:"New document",action:"mceNewDocument",icon:"new-document"},{name:"print",text:"Print",action:"mcePrint",icon:"print",shortcut:"Meta+P"}],(t=>{e.ui.registry.addButton(t.name,{tooltip:t.text,icon:t.icon,onAction:cS(e,t.action),shortcut:t.shortcut})})),E_.each([{name:"cut",text:"Cut",action:"Cut",icon:"cut"},{name:"paste",text:"Paste",action:"Paste",icon:"paste"},{name:"removeformat",text:"Clear formatting",action:"RemoveFormat",icon:"remove-formatting"},{name:"remove",text:"Remove",action:"Delete",icon:"remove"},{name:"hr",text:"Horizontal line",action:"InsertHorizontalRule",icon:"horizontal-rule"}],(t=>{e.ui.registry.addButton(t.name,{tooltip:t.text,icon:t.icon,onSetup:rS(e),onAction:cS(e,t.action)})}))})(e),(e=>{E_.each([{name:"blockquote",text:"Blockquote",action:"mceBlockQuote",icon:"quote"}],(t=>{e.ui.registry.addToggleButton(t.name,{tooltip:t.text,icon:t.icon,onAction:cS(e,t.action),onSetup:aS(e,t.name)})}))})(e)})(e),(e=>{E_.each([{name:"newdocument",text:"New document",action:"mceNewDocument",icon:"new-document"},{name:"copy",text:"Copy",action:"Copy",icon:"copy",shortcut:"Meta+C"},{name:"selectall",text:"Select all",action:"SelectAll",icon:"select-all",shortcut:"Meta+A"},{name:"print",text:"Print...",action:"mcePrint",icon:"print",shortcut:"Meta+P"}],(t=>{e.ui.registry.addMenuItem(t.name,{text:t.text,icon:t.icon,shortcut:t.shortcut,onAction:cS(e,t.action)})})),E_.each([{name:"bold",text:"Bold",action:"Bold",icon:"bold",shortcut:"Meta+B"},{name:"italic",text:"Italic",action:"Italic",icon:"italic",shortcut:"Meta+I"},{name:"underline",text:"Underline",action:"Underline",icon:"underline",shortcut:"Meta+U"},{name:"strikethrough",text:"Strikethrough",action:"Strikethrough",icon:"strike-through"},{name:"subscript",text:"Subscript",action:"Subscript",icon:"subscript"},{name:"superscript",text:"Superscript",action:"Superscript",icon:"superscript"},{name:"removeformat",text:"Clear formatting",action:"RemoveFormat",icon:"remove-formatting"},{name:"cut",text:"Cut",action:"Cut",icon:"cut",shortcut:"Meta+X"},{name:"paste",text:"Paste",action:"Paste",icon:"paste",shortcut:"Meta+V"},{name:"hr",text:"Horizontal line",action:"InsertHorizontalRule",icon:"horizontal-rule"}],(t=>{e.ui.registry.addMenuItem(t.name,{text:t.text,icon:t.icon,shortcut:t.shortcut,onSetup:rS(e),onAction:cS(e,t.action)})})),e.ui.registry.addMenuItem("codeformat",{text:"Code",icon:"sourcecode",onSetup:rS(e),onAction:HI(e,"code")})})(e)},UI=(e,t)=>iS(e,"Undo Redo AddUndo TypingUndo ClearUndos SwitchMode",(o=>{o.setEnabled(!e.mode.isReadOnly()&&e.undoManager[t]())})),WI=e=>iS(e,"VisualAid",(t=>{t.setActive(e.hasVisual)})),jI=(e,t)=>{(e=>{V([{name:"alignleft",text:"Align left",cmd:"JustifyLeft",icon:"align-left"},{name:"aligncenter",text:"Align center",cmd:"JustifyCenter",icon:"align-center"},{name:"alignright",text:"Align right",cmd:"JustifyRight",icon:"align-right"},{name:"alignjustify",text:"Justify",cmd:"JustifyFull",icon:"align-justify"}],(t=>{e.ui.registry.addToggleButton(t.name,{tooltip:t.text,icon:t.icon,onAction:cS(e,t.cmd),onSetup:aS(e,t.name)})})),e.ui.registry.addButton("alignnone",{tooltip:"No alignment",icon:"align-none",onSetup:rS(e),onAction:cS(e,"JustifyNone")})})(e),PI(e),((e,t)=>{((e,t)=>{const o=lB(t,hB(e));e.ui.registry.addNestedMenuItem("align",{text:t.shared.providers.translate("Align"),onSetup:rS(e),getSubmenuItems:()=>o.items.validateItems(o.getStyleItems())})})(e,t),((e,t)=>{const o=lB(t,OB(e));e.ui.registry.addNestedMenuItem("fontfamily",{text:t.shared.providers.translate("Fonts"),onSetup:rS(e),getSubmenuItems:()=>o.items.validateItems(o.getStyleItems())})})(e,t),((e,t)=>{const o={type:"advanced",...t.styles},n=lB(t,LB(e,o));e.ui.registry.addNestedMenuItem("styles",{text:"Formats",onSetup:rS(e),getSubmenuItems:()=>n.items.validateItems(n.getStyleItems())})})(e,t),((e,t)=>{const o=lB(t,yB(e));e.ui.registry.addNestedMenuItem("blocks",{text:"Blocks",onSetup:rS(e),getSubmenuItems:()=>o.items.validateItems(o.getStyleItems())})})(e,t),((e,t)=>{const o=lB(t,NB(e));e.ui.registry.addNestedMenuItem("fontsize",{text:"Font sizes",onSetup:rS(e),getSubmenuItems:()=>o.items.validateItems(o.getStyleItems())})})(e,t)})(e,t),(e=>{(e=>{e.ui.registry.addMenuItem("undo",{text:"Undo",icon:"undo",shortcut:"Meta+Z",onSetup:UI(e,"hasUndo"),onAction:cS(e,"undo")}),e.ui.registry.addMenuItem("redo",{text:"Redo",icon:"redo",shortcut:"Meta+Y",onSetup:UI(e,"hasRedo"),onAction:cS(e,"redo")})})(e),(e=>{e.ui.registry.addButton("undo",{tooltip:"Undo",icon:"undo",enabled:!1,onSetup:UI(e,"hasUndo"),onAction:cS(e,"undo"),shortcut:"Meta+Z"}),e.ui.registry.addButton("redo",{tooltip:"Redo",icon:"redo",enabled:!1,onSetup:UI(e,"hasRedo"),onAction:cS(e,"redo"),shortcut:"Meta+Y"})})(e)})(e),(e=>{(e=>{e.addCommand("mceApplyTextcolor",((t,o)=>{((e,t,o)=>{e.undoManager.transact((()=>{e.focus(),e.formatter.apply(t,{value:o}),e.nodeChanged()}))})(e,t,o)})),e.addCommand("mceRemoveTextcolor",(t=>{((e,t)=>{e.undoManager.transact((()=>{e.focus(),e.formatter.remove(t,{value:null},void 0,!0),e.nodeChanged()}))})(e,t)}))})(e);const t=ES(e),o=AS(e),n=on(t),s=on(o);VS(e,"forecolor","forecolor",n),VS(e,"backcolor","hilitecolor",s),HS(e,"forecolor","forecolor","Text color",n),HS(e,"backcolor","hilitecolor","Background color",s)})(e),(e=>{(e=>{e.ui.registry.addButton("visualaid",{tooltip:"Visual aids",text:"Visual aids",onAction:cS(e,"mceToggleVisualAid")})})(e),(e=>{e.ui.registry.addToggleMenuItem("visualaid",{text:"Visual aids",onSetup:WI(e),onAction:cS(e,"mceToggleVisualAid")})})(e)})(e),(e=>{(e=>{e.ui.registry.addButton("outdent",{tooltip:"Decrease indent",icon:"outdent",onSetup:LI(e),onAction:cS(e,"outdent")}),e.ui.registry.addButton("indent",{tooltip:"Increase indent",icon:"indent",onSetup:rS(e),onAction:cS(e,"indent")})})(e)})(e),zI(e),(e=>{const t=on(db(e)),o=()=>e.execCommand("mceTogglePlainTextPaste");e.ui.registry.addToggleButton("pastetext",{active:!1,icon:"paste-text",tooltip:"Paste as text",onAction:o,onSetup:VI(e,t)}),e.ui.registry.addToggleMenuItem("pastetext",{text:"Paste as text",icon:"paste-text",onAction:o,onSetup:VI(e,t)})})(e)},$I=e=>r(e)?e.split(/[ ,]/):e,GI=e=>t=>t.options.get(e),qI=GI("contextmenu_never_use_native"),YI=GI("contextmenu_avoid_overlap"),XI=e=>{const t=e.ui.registry.getAll().contextMenus,o=e.options.get("contextmenu");return e.options.isSet("contextmenu")?o:P(o,(e=>be(t,e)))},KI=(e,t)=>({type:"makeshift",x:e,y:t}),JI=e=>"longpress"===e.type||0===e.type.indexOf("touch"),QI=(e,t)=>"contextmenu"===t.type||"longpress"===t.type?e.inline?(e=>{if(JI(e)){const t=e.touches[0];return KI(t.pageX,t.pageY)}return KI(e.pageX,e.pageY)})(t):((e,t)=>{const o=Of.DOM.getPos(e);return((e,t,o)=>KI(e.x+t,e.y+o))(t,o.x,o.y)})(e.getContentAreaContainer(),(e=>{if(JI(e)){const t=e.touches[0];return KI(t.clientX,t.clientY)}return KI(e.clientX,e.clientY)})(t)):ZI(e),ZI=e=>({type:"selection",root:ze(e.selection.getNode())}),eF=(e,t,o)=>{switch(o){case"node":return(e=>({type:"node",node:A.some(ze(e.selection.getNode())),root:ze(e.getBody())}))(e);case"point":return QI(e,t);case"selection":return ZI(e)}},tF=(e,t,o,n,s,r)=>{const a=o(),i=eF(e,t,r);mT(a,dy.CLOSE_ON_EXECUTE,n,{isHorizontalMenu:!1,search:A.none()}).map((e=>{t.preventDefault(),wf.showMenuAt(s,{anchor:i},{menu:{markers:Oy("normal")},data:e})}))},oF={onLtr:()=>[oc,Jl,Ql,Zl,ec,tc,KE,JE,XE,qE,YE,GE],onRtl:()=>[oc,Ql,Jl,ec,Zl,tc,KE,JE,YE,GE,XE,qE]},nF={valignCentre:[],alignCentre:[],alignLeft:["tox-pop--align-left"],alignRight:["tox-pop--align-right"],right:["tox-pop--right"],left:["tox-pop--left"],bottom:["tox-pop--bottom"],top:["tox-pop--top"]},sF=(e,t,o,n,s,r)=>{const a=Bo(),i=a.os.isiOS(),l=a.os.isMacOS(),c=a.os.isAndroid(),d=a.deviceType.isTouch(),u=()=>{const a=o();((e,t,o,n,s,r,a)=>{const i=((e,t,o)=>{const n=eF(e,t,o);return{bubble:Gc(0,"point"===o?12:0,nF),layouts:oF,overrides:{maxWidthFunction:QM(),maxHeightFunction:Uc()},...n}})(e,t,r);mT(o,dy.CLOSE_ON_EXECUTE,n,{isHorizontalMenu:!0,search:A.none()}).map((o=>{t.preventDefault();const l=a?vf.HighlightMenuAndItem:vf.HighlightNone;wf.showMenuWithinBounds(s,{anchor:i},{menu:{markers:Oy("normal"),highlightOnOpen:l},data:o,type:"horizontal"},(()=>A.some(SI(e,n.shared,"node"===r?"node":"selection")))),e.dispatch(bI)}))})(e,t,a,n,s,r,!(c||i||l&&d))};if((l||i)&&"node"!==r){const o=()=>{(e=>{const t=e.selection.getRng(),o=()=>{Cf.setEditorTimeout(e,(()=>{e.selection.setRng(t)}),10),r()};e.once("touchend",o);const n=e=>{e.preventDefault(),e.stopImmediatePropagation()};e.on("mousedown",n,!0);const s=()=>r();e.once("longpresscancel",s);const r=()=>{e.off("touchend",o),e.off("longpresscancel",s),e.off("mousedown",n)}})(e),u()};((e,t)=>{const o=e.selection;if(o.isCollapsed()||t.touches.length<1)return!1;{const n=t.touches[0],s=o.getRng();return Md(e.getWin(),yd.domRange(s)).exists((e=>e.left<=n.clientX&&e.right>=n.clientX&&e.top<=n.clientY&&e.bottom>=n.clientY))}})(e,t)?o():(e.once("selectionchange",o),e.once("touchend",(()=>e.off("selectionchange",o))))}else u()},rF=e=>r(e)?"|"===e:"separator"===e.type,aF={type:"separator"},iF=e=>{const t=e=>({text:e.text,icon:e.icon,enabled:e.enabled,shortcut:e.shortcut});if(r(e))return e;switch(e.type){case"separator":return aF;case"submenu":return{type:"nestedmenuitem",...t(e),getSubmenuItems:()=>{const t=e.getSubmenuItems();return r(t)?t:L(t,iF)}};default:const o=e;return{type:"menuitem",...t(o),onAction:v(o.onAction)}}},lF=(e,t)=>{if(0===t.length)return e;const o=oe(e).filter((e=>!rF(e))).fold((()=>[]),(e=>[aF]));return e.concat(o).concat(t).concat([aF])},cF=(e,t)=>!(e=>"longpress"===e.type||be(e,"touches"))(t)&&(2!==t.button||t.target===e.getBody()&&""===t.pointerType),dF=(e,t)=>cF(e,t)?e.selection.getStart(!0):t.target,uF=(e,t,o)=>{const n=Bo().deviceType.isTouch,s=hl(wf.sketch({dom:{tag:"div"},lazySink:t,onEscape:()=>e.focus(),onShow:()=>o.setContextMenuState(!0),onHide:()=>o.setContextMenuState(!1),fireDismissalEventInstead:{},inlineBehaviours:ma([Mh("dismissContextMenu",[Gr(Er(),((t,o)=>{Tu.close(t),e.focus()}))])])})),a=()=>wf.hide(s),i=t=>{if(qI(e)&&t.preventDefault(),((e,t)=>t.ctrlKey&&!qI(e))(e,t)||(e=>0===XI(e).length)(e))return;const a=((e,t)=>{const o=YI(e),n=cF(e,t)?"selection":"point";if(Me(o)){const s=dF(e,t);return Bk(ze(s),o)?"node":n}return n})(e,t);(n()?sF:tF)(e,t,(()=>{const o=dF(e,t),n=e.ui.registry.getAll(),s=XI(e);return((e,t,o)=>{const n=W(t,((t,n)=>fe(e,n.toLowerCase()).map((e=>{const n=e.update(o);if(r(n)&&Me(Ae(n)))return lF(t,n.split(" "));if(l(n)&&n.length>0){const e=L(n,iF);return lF(t,e)}return t})).getOrThunk((()=>t.concat([n])))),[]);return n.length>0&&rF(n[n.length-1])&&n.pop(),n})(n.contextMenus,s,o)}),o,s,a)};e.on("init",(()=>{const t="ResizeEditor ScrollContent ScrollWindow longpresscancel"+(n()?"":" ResizeWindow");e.on(t,a),e.on("longpress contextmenu",i)}))},mF=Is([{offset:["x","y"]},{absolute:["x","y"]},{fixed:["x","y"]}]),gF=e=>t=>t.translate(-e.left,-e.top),pF=e=>t=>t.translate(e.left,e.top),hF=e=>(t,o)=>W(e,((e,t)=>t(e)),qt(t,o)),fF=(e,t,o)=>e.fold(hF([pF(o),gF(t)]),hF([gF(t)]),hF([])),bF=(e,t,o)=>e.fold(hF([pF(o)]),hF([]),hF([pF(t)])),vF=(e,t,o)=>e.fold(hF([]),hF([gF(o)]),hF([pF(t),gF(o)])),yF=(e,t,o)=>{const n=e.fold(((e,t)=>({position:A.some("absolute"),left:A.some(e+"px"),top:A.some(t+"px")})),((e,t)=>({position:A.some("absolute"),left:A.some(e-o.left+"px"),top:A.some(t-o.top+"px")})),((e,t)=>({position:A.some("fixed"),left:A.some(e+"px"),top:A.some(t+"px")})));return{right:A.none(),bottom:A.none(),...n}},xF=(e,t,o,n)=>{const s=(e,s)=>(r,a)=>{const i=e(t,o,n);return s(r.getOr(i.left),a.getOr(i.top))};return e.fold(s(vF,wF),s(bF,SF),s(fF,kF))},wF=mF.offset,SF=mF.absolute,kF=mF.fixed,CF=(e,t)=>{const o=_t(e,t);return u(o)?NaN:parseInt(o,10)},OF=(e,t,o,n,s,r)=>{const a=((e,t,o,n)=>((e,t)=>{const o=e.element,n=CF(o,t.leftAttr),s=CF(o,t.topAttr);return isNaN(n)||isNaN(s)?A.none():A.some(qt(n,s))})(e,t).fold((()=>o),(e=>kF(e.left+n.left,e.top+n.top))))(e,t,o,n),i=t.mustSnap?TF(e,t,a,s,r):EF(e,t,a,s,r),l=fF(a,s,r);return((e,t,o)=>{const n=e.element;Ct(n,t.leftAttr,o.left+"px"),Ct(n,t.topAttr,o.top+"px")})(e,t,l),i.fold((()=>({coord:kF(l.left,l.top),extra:A.none()})),(e=>({coord:e.output,extra:e.extra})))},_F=(e,t,o,n)=>se(e,(e=>{const s=e.sensor,r=((e,t,o,n,s,r)=>{const a=bF(e,s,r),i=bF(t,s,r);return Math.abs(a.left-i.left)<=o&&Math.abs(a.top-i.top)<=n})(t,s,e.range.left,e.range.top,o,n);return r?A.some({output:xF(e.output,t,o,n),extra:e.extra}):A.none()})),TF=(e,t,o,n,s)=>{const r=t.getSnapPoints(e);return _F(r,o,n,s).orThunk((()=>{const e=W(r,((e,t)=>{const r=t.sensor,a=((e,t,o,n,s,r)=>{const a=bF(e,s,r),i=bF(t,s,r),l=Math.abs(a.left-i.left),c=Math.abs(a.top-i.top);return qt(l,c)})(o,r,t.range.left,t.range.top,n,s);return e.deltas.fold((()=>({deltas:A.some(a),snap:A.some(t)})),(o=>(a.left+a.top)/2<=(o.left+o.top)/2?{deltas:A.some(a),snap:A.some(t)}:e))}),{deltas:A.none(),snap:A.none()});return e.snap.map((e=>({output:xF(e.output,o,n,s),extra:e.extra})))}))},EF=(e,t,o,n,s)=>{const r=t.getSnapPoints(e);return _F(r,o,n,s)};var AF=Object.freeze({__proto__:null,snapTo:(e,t,o,n)=>{const s=t.getTarget(e.element);if(t.repositionTarget){const t=tt(e.element),o=Wo(t),r=Ia(s),a=((e,t,o)=>({coord:xF(e.output,e.output,t,o),extra:e.extra}))(n,o,r),i=yF(a.coord,0,r);Ft(s,i)}}});const MF="data-initial-z-index",DF=(e,t)=>{e.getSystem().addToGui(t),(e=>{rt(e.element).filter($e).each((t=>{zt(t,"z-index").each((e=>{Ct(t,MF,e)})),Bt(t,"z-index",Rt(e.element,"z-index"))}))})(t)},BF=e=>{(e=>{rt(e.element).filter($e).each((e=>{Tt(e,MF).fold((()=>Ht(e,"z-index")),(t=>Bt(e,"z-index",t))),At(e,MF)}))})(e),e.getSystem().removeFromGui(e)},IF=(e,t,o)=>e.getSystem().build(Uk.sketch({dom:{styles:{left:"0px",top:"0px",width:"100%",height:"100%",position:"fixed","z-index":"1000000000000000"},classes:[t]},events:o}));var FF=ks("snaps",[is("getSnapPoints"),xi("onSensor"),is("leftAttr"),is("topAttr"),Cs("lazyViewport",tn),Cs("mustSnap",!1)]);const RF=[Cs("useFixed",T),is("blockerClass"),Cs("getTarget",w),Cs("onDrag",b),Cs("repositionTarget",!0),Cs("onDrop",b),Ms("getBounds",tn),FF],NF=e=>{return(t=zt(e,"left"),o=zt(e,"top"),n=zt(e,"position"),t.isSome()&&o.isSome()&&n.isSome()?A.some(((e,t,o)=>("fixed"===o?kF:wF)(parseInt(e,10),parseInt(t,10)))(t.getOrDie(),o.getOrDie(),n.getOrDie())):A.none()).getOrThunk((()=>{const t=Xt(e);return SF(t.left,t.top)}));var t,o,n},zF=(e,t)=>({bounds:e.getBounds(),height:$t(t.element),width:Zt(t.element)}),LF=(e,t,o,n,s)=>{const r=o.update(n,s),a=o.getStartData().getOrThunk((()=>zF(t,e)));r.each((o=>{((e,t,o,n)=>{const s=t.getTarget(e.element);if(t.repositionTarget){const r=tt(e.element),a=Wo(r),i=Ia(s),l=NF(s),c=((e,t,o,n,s,r,a)=>((e,t,o,n,s)=>{const r=s.bounds,a=bF(t,o,n),i=Ul(a.left,r.x,r.x+r.width-s.width),l=Ul(a.top,r.y,r.y+r.height-s.height),c=SF(i,l);return t.fold((()=>{const e=vF(c,o,n);return wF(e.left,e.top)}),x(c),(()=>{const e=fF(c,o,n);return kF(e.left,e.top)}))})(0,t.fold((()=>{const e=(t=o,a=r.left,i=r.top,t.fold(((e,t)=>wF(e+a,t+i)),((e,t)=>SF(e+a,t+i)),((e,t)=>kF(e+a,t+i))));var t,a,i;const l=fF(e,n,s);return kF(l.left,l.top)}),(t=>{const a=OF(e,t,o,r,n,s);return a.extra.each((o=>{t.onSensor(e,o)})),a.coord})),n,s,a))(e,t.snaps,l,a,i,n,o),d=yF(c,0,i);Ft(s,d)}t.onDrag(e,s,n)})(e,t,a,o)}))},VF=(e,t,o,n)=>{t.each(BF),o.snaps.each((t=>{((e,t)=>{((e,t)=>{const o=e.element;At(o,t.leftAttr),At(o,t.topAttr)})(e,t)})(e,t)}));const s=o.getTarget(e.element);n.reset(),o.onDrop(e,s)},HF=e=>(t,o)=>{const n=e=>{o.setStartData(zF(t,e))};return Wr([Gr(Cr(),(e=>{o.getStartData().each((()=>n(e)))})),...e(t,o,n)])};var PF=Object.freeze({__proto__:null,getData:e=>A.from(qt(e.x,e.y)),getDelta:(e,t)=>qt(t.left-e.left,t.top-e.top)});const UF=(e,t,o)=>[Gr(qs(),((n,s)=>{if(0!==s.event.raw.button)return;s.stop();const r=()=>VF(n,A.some(l),e,t),a=Ik(r,200),i={drop:r,delayDrop:a.schedule,forceDrop:r,move:o=>{a.cancel(),LF(n,e,t,PF,o)}},l=IF(n,e.blockerClass,(e=>Wr([Gr(qs(),e.forceDrop),Gr(Ks(),e.drop),Gr(Ys(),((t,o)=>{e.move(o.event)})),Gr(Xs(),e.delayDrop)]))(i));o(n),DF(n,l)}))],WF=[...RF,Ci("dragger",{handlers:HF(UF)})];var jF=Object.freeze({__proto__:null,getData:e=>{const t=e.raw.touches;return 1===t.length?(e=>{const t=e[0];return A.some(qt(t.clientX,t.clientY))})(t):A.none()},getDelta:(e,t)=>qt(t.left-e.left,t.top-e.top)});const $F=(e,t,o)=>{const n=rn(),s=o=>{VF(o,n.get(),e,t),n.clear()};return[Gr(Ws(),((r,a)=>{a.stop();const i=()=>s(r),l={drop:i,delayDrop:b,forceDrop:i,move:o=>{LF(r,e,t,jF,o)}},c=IF(r,e.blockerClass,(e=>Wr([Gr(Ws(),e.forceDrop),Gr($s(),e.drop),Gr(Gs(),e.drop),Gr(js(),((t,o)=>{e.move(o.event)}))]))(l));n.set(c),o(r),DF(r,c)})),Gr(js(),((o,n)=>{n.stop(),LF(o,e,t,jF,n.event)})),Gr($s(),((e,t)=>{t.stop(),s(e)})),Gr(Gs(),s)]},GF=WF,qF=[...RF,Ci("dragger",{handlers:HF($F)})],YF=[...RF,Ci("dragger",{handlers:HF(((e,t,o)=>[...UF(e,t,o),...$F(e,t,o)]))})];var XF=Object.freeze({__proto__:null,mouse:GF,touch:qF,mouseOrTouch:YF}),KF=Object.freeze({__proto__:null,init:()=>{let e=A.none(),t=A.none();const o=x({});return ua({readState:o,reset:()=>{e=A.none(),t=A.none()},update:(t,o)=>t.getData(o).bind((o=>((t,o)=>{const n=e.map((e=>t.getDelta(e,o)));return e=A.some(o),n})(t,o))),getStartData:()=>t,setStartData:e=>{t=A.some(e)}})}});const JF=fa({branchKey:"mode",branches:XF,name:"dragging",active:{events:(e,t)=>e.dragger.handlers(e,t)},extra:{snap:e=>({sensor:e.sensor,range:e.range,output:e.output,extra:A.from(e.extra)})},state:KF,apis:AF}),QF=(e,t,o,n,s,r)=>e.fold((()=>JF.snap({sensor:SF(o-20,n-20),range:qt(s,r),output:SF(A.some(o),A.some(n)),extra:{td:t}})),(e=>{const s=o-20,r=n-20,a=e.element.dom.getBoundingClientRect();return JF.snap({sensor:SF(s,r),range:qt(40,40),output:SF(A.some(o-a.width/2),A.some(n-a.height/2)),extra:{td:t}})})),ZF=(e,t,o)=>({getSnapPoints:e,leftAttr:"data-drag-left",topAttr:"data-drag-top",onSensor:(e,n)=>{const s=n.td;((e,t)=>e.exists((e=>Ze(e,t))))(t.get(),s)||(t.set(s),o(s))},mustSnap:!0}),eR=e=>Vb(zb.sketch({dom:{tag:"div",classes:["tox-selector"]},buttonBehaviours:ma([JF.config({mode:"mouseOrTouch",blockerClass:"blocker",snaps:e}),vC.config({})]),eventOrder:{mousedown:["dragging","alloy.base.behaviour"],touchstart:["dragging","alloy.base.behaviour"]}})),tR=(e,t)=>{const o=on([]),n=on([]),s=on(!1),r=rn(),a=rn(),i=e=>{const o=Zo(e);return QF(u.getOpt(t),e,o.x,o.y,o.width,o.height)},l=e=>{const o=Zo(e);return QF(m.getOpt(t),e,o.right,o.bottom,o.width,o.height)},c=ZF((()=>L(o.get(),(e=>i(e)))),r,(t=>{a.get().each((o=>{e.dispatch("TableSelectorChange",{start:t,finish:o})}))})),d=ZF((()=>L(n.get(),(e=>l(e)))),a,(t=>{r.get().each((o=>{e.dispatch("TableSelectorChange",{start:o,finish:t})}))})),u=eR(c),m=eR(d),g=hl(u.asSpec()),p=hl(m.asSpec()),h=(t,o,n,s)=>{const r=n(o);JF.snapTo(t,r),((t,o,n,r)=>{const a=o.dom.getBoundingClientRect();Ht(t.element,"display");const i=st(ze(e.getBody())).dom.innerHeight,l=a[s]<0,c=((e,t)=>e[s]>t)(a,i);(l||c)&&Bt(t.element,"display","none")})(t,o)},f=e=>h(g,e,i,"top"),b=e=>h(p,e,l,"bottom");if(Bo().deviceType.isTouch()){const i=e=>L(e,ze);e.on("TableSelectionChange",(e=>{s.get()||(lu(t,g),lu(t,p),s.set(!0));const l=ze(e.start),c=ze(e.finish);r.set(l),a.set(c),A.from(e.otherCells).each((e=>{o.set(i(e.upOrLeftCells)),n.set(i(e.downOrRightCells)),f(l),b(c)}))})),e.on("ResizeEditor ResizeWindow ScrollContent",(()=>{r.get().each(f),a.get().each(b)})),e.on("TableSelectionClear",(()=>{s.get()&&(uu(g),uu(p),s.set(!1)),r.clear(),a.clear()}))}},oR=(e,t,o)=>{var n;const s=null!==(n=t.delimiter)&&void 0!==n?n:"\u203a";return{dom:{tag:"div",classes:["tox-statusbar__path"],attributes:{role:"navigation"}},behaviours:ma([xh.config({mode:"flow",selector:"div[role=button]"}),pg.config({disabled:o.isDisabled}),dw(),Ub.config({}),Ah.config({}),Mh("elementPathEvents",[ea(((t,n)=>{e.shortcuts.add("alt+F11","focus statusbar elementpath",(()=>xh.focusIn(t))),e.on("NodeChange",(n=>{const r=(t=>{const o=[];let n=t.length;for(;n-- >0;){const r=t[n];if(1===r.nodeType&&"BR"!==(s=r).nodeName&&!s.getAttribute("data-mce-bogus")&&"bookmark"!==s.getAttribute("data-mce-type")){const t=nS(e,r);if(t.isDefaultPrevented()||o.push({name:t.name,element:r}),t.isPropagationStopped())break}}var s;return o})(n.parents),a=r.length>0?W(r,((t,n,r)=>{const a=((t,n,s)=>zb.sketch({dom:{tag:"div",classes:["tox-statusbar__path-item"],attributes:{"data-index":s}},components:[ul(t)],action:t=>{e.focus(),e.selection.select(n),e.nodeChanged()},buttonBehaviours:ma([Zb.config({...o.tooltips.getConfig({tooltipText:o.translate(["Select the {0} element",n.nodeName.toLowerCase()]),onShow:(e,t)=>{((e,t)=>{const o=A.from(_t(e,"id")).getOrThunk((()=>{const e=Bi("aria");return Ct(t,"id",e),e}));Ct(e,"aria-describedby",o)})(e.element,t.element)},onHide:e=>{var t;t=e.element,At(t,"aria-describedby")}})}),uw(o.isDisabled),dw()])}))(n.name,n.element,r);return 0===r?t.concat([a]):t.concat([{dom:{tag:"div",classes:["tox-statusbar__path-divider"],attributes:{"aria-hidden":!0}},components:[ul(` ${s} `)]},a])}),[]):[];Ah.set(t,a)}))}))])]),components:[]}};var nR;!function(e){e[e.None=0]="None",e[e.Both=1]="Both",e[e.Vertical=2]="Vertical"}(nR||(nR={}));const sR=(e,t,o)=>{const n=ze(e.getContainer()),s=((e,t,o,n,s)=>{const r={height:dI(n+t.top,Rf(e),zf(e))};return o===nR.Both&&(r.width=dI(s+t.left,Ff(e),Nf(e))),r})(e,t,o,jt(n),Qt(n));ie(s,((e,t)=>{h(e)&&Bt(n,t,cI(e))})),(e=>{e.dispatch("ResizeEditor")})(e)},rR=(e,t,o,n)=>{const s=qt(20*o,20*n);return sR(e,s,t),A.some(!0)},aR=(e,t)=>{const o=()=>{const o=[],n=gb(e),s=ib(e),r=lb(e)||e.hasPlugin("wordcount");return s&&o.push(oR(e,{},t)),n&&o.push((()=>{const e=Sw("Alt+0");return{dom:{tag:"div",classes:["tox-statusbar__help-text"]},components:[ul(Kv.translate(["Press {0} for help",e]))]}})()),r&&o.push((()=>{const o=[];return e.hasPlugin("wordcount")&&o.push(((e,t)=>{const o=(e,o,n)=>Ah.set(e,[ul(t.translate(["{0} "+n,o[n]]))]);return zb.sketch({dom:{tag:"button",classes:["tox-statusbar__wordcount"]},components:[],buttonBehaviours:ma([uw(t.isDisabled),dw(),Ub.config({}),Ah.config({}),qu.config({store:{mode:"memory",initialValue:{mode:"words",count:{words:0,characters:0}}}}),Mh("wordcount-events",[na((e=>{const t=qu.getValue(e),n="words"===t.mode?"characters":"words";qu.setValue(e,{mode:n,count:t.count}),o(e,t.count,n)})),ea((t=>{e.on("wordCountUpdate",(e=>{const{mode:n}=qu.getValue(t);qu.setValue(t,{mode:n,count:e.wordCount}),o(t,e.wordCount,n)}))}))])]),eventOrder:{[hr()]:["disabling","alloy.base.behaviour","wordcount-events"]}})})(e,t)),lb(e)&&o.push({dom:{tag:"span",classes:["tox-statusbar__branding"]},components:[{dom:{tag:"a",attributes:{href:"https://www.tiny.cloud/powered-by-tiny?utm_campaign=poweredby&utm_source=tiny&utm_medium=referral&utm_content=v7",rel:"noopener",target:"_blank","aria-label":e.translate(["Build with {0}","TinyMCE"])},innerHtml:e.translate(["Build with {0}",'<svg height="16" viewBox="0 0 80 16" width="80" xmlns="http://www.w3.org/2000/svg"><g opacity=".8"><path d="m80 3.537v-2.202h-7.976v11.585h7.976v-2.25h-5.474v-2.621h4.812v-2.069h-4.812v-2.443zm-10.647 6.929c-.493.217-1.13.337-1.864.337s-1.276-.156-1.805-.47a3.732 3.732 0 0 1 -1.3-1.298c-.324-.554-.48-1.191-.48-1.877s.156-1.335.48-1.877a3.635 3.635 0 0 1 1.3-1.299 3.466 3.466 0 0 1 1.805-.481c.65 0 .914.06 1.263.18.36.12.698.277.986.47.289.192.578.384.842.6l.12.085v-2.586l-.023-.024c-.385-.35-.855-.614-1.384-.818-.53-.205-1.155-.313-1.877-.313-.721 0-1.6.144-2.333.445a5.773 5.773 0 0 0 -1.937 1.251 5.929 5.929 0 0 0 -1.324 1.9c-.324.735-.48 1.565-.48 2.455s.156 1.72.48 2.454c.325.734.758 1.383 1.324 1.913.553.53 1.215.938 1.937 1.25a6.286 6.286 0 0 0 2.333.434c.819 0 1.384-.108 1.961-.313.59-.216 1.083-.505 1.468-.866l.024-.024v-2.49l-.12.096c-.41.337-.878.626-1.396.866zm-14.869-4.15-4.8-5.04-.024-.025h-.902v11.67h2.502v-6.847l2.827 3.08.385.409.397-.41 2.791-3.067v6.845h2.502v-11.679h-.902l-4.788 5.052z"/><path clip-rule="evenodd" d="m15.543 5.137c0-3.032-2.466-5.113-4.957-5.137-.36 0-.745.024-1.094.096-.157.024-3.85.758-3.85.758-3.032.602-4.62 2.466-4.704 4.788-.024.89-.024 4.27-.024 4.27.036 3.165 2.406 5.138 5.017 5.126.337 0 1.119-.109 1.287-.145.144-.024.385-.084.746-.144.661-.12 1.684-.325 3.067-.602 2.37-.409 4.103-2.009 4.44-4.33.156-1.023.084-4.692.084-4.692zm-3.213 3.308-2.346.457v2.31l-5.859 1.143v-5.75l2.346-.458v3.441l3.513-.686v-3.44l-3.513.685v-2.297l5.859-1.143v5.75zm20.09-3.296-.083-1.023h-2.13v8.794h2.346v-4.884c0-1.107.95-1.985 2.057-1.997 1.095 0 1.901.89 1.901 1.997v4.884h2.346v-5.245c-.012-2.105-1.588-3.777-3.67-3.765a3.764 3.764 0 0 0 -2.778 1.25l.012-.011zm-6.014-4.102 2.346-.458v2.298l-2.346.457z" fill-rule="evenodd"/><path d="m28.752 4.126h-2.346v8.794h2.346z"/><path clip-rule="evenodd" d="m43.777 15.483 4.043-11.357h-2.418l-1.54 4.355-.445 1.324-.36-1.324-1.54-4.355h-2.418l3.151 8.794-1.083 3.08zm-21.028-5.51c0 .722.541 1.034.878 1.034s.638-.048.95-.144l.518 1.708c-.217.145-.879.518-2.13.518a2.565 2.565 0 0 1 -2.562-2.587c-.024-1.082-.024-2.49 0-4.21h-1.54v-2.142h1.54v-1.912l2.346-.458v2.37h2.201v2.142h-2.2v3.693-.012z" fill-rule="evenodd"/></g></svg>\n'.trim()])},behaviours:ma([Rh.config({})])}]}),{dom:{tag:"div",classes:["tox-statusbar__right-container"]},components:o}})()),o.length>0?[{dom:{tag:"div",classes:["tox-statusbar__text-container",...(()=>{const e="tox-statusbar__text-container--flex-start",t="tox-statusbar__text-container--flex-end";if(n){const o="tox-statusbar__text-container-3-cols";return r||s?r&&!s?[o,t]:[o,e]:[o,"tox-statusbar__text-container--space-around"]}return[r&&!s?t:e]})()]},components:o}]:[]};return{dom:{tag:"div",classes:["tox-statusbar"]},components:(()=>{const n=o(),s=((e,t)=>{const o=(e=>{const t=cb(e);return!1===t?nR.None:"both"===t?nR.Both:nR.Vertical})(e);if(o===nR.None)return A.none();const n=o===nR.Both?"Press the arrow keys to resize the editor.":"Press the Up and Down arrow keys to resize the editor.";return A.some(ry("resize-handle",{tag:"div",classes:["tox-statusbar__resize-handle"],attributes:{"aria-label":t.translate(n),"data-mce-name":"resize-handle"},behaviours:[JF.config({mode:"mouse",repositionTarget:!1,onDrag:(t,n,s)=>sR(e,s,o),blockerClass:"tox-blocker"}),xh.config({mode:"special",onLeft:()=>rR(e,o,-1,0),onRight:()=>rR(e,o,1,0),onUp:()=>rR(e,o,0,-1),onDown:()=>rR(e,o,0,1)}),Ub.config({}),Rh.config({}),Zb.config(t.tooltips.getConfig({tooltipText:t.translate("Resize")}))]},t.icons))})(e,t);return n.concat(s.toArray())})()}},iR=(e,t)=>t.get().getOrDie(`UI for ${e} has not been rendered`),lR=(e,t)=>{const o=e.inline,n=o?fI:iI,s=Eb(e)?vM:lM,r=(()=>{const e=rn(),t=rn(),o=rn();return{dialogUi:e,popupUi:t,mainUi:o,getUiMotherships:()=>{const o=e.get().map((e=>e.mothership)),n=t.get().map((e=>e.mothership));return o.fold((()=>n.toArray()),(e=>n.fold((()=>[e]),(t=>Ze(e.element,t.element)?[e]:[e,t]))))},lazyGetInOuterOrDie:(e,t)=>()=>o.get().bind((e=>t(e.outerContainer))).getOrDie(`Could not find ${e} element in OuterContainer`)}})(),a=rn(),i=rn(),l=rn(),c=Bo().deviceType.isTouch()?["tox-platform-touch"]:[],d=kb(e),u=Wf(e),m=Vb({dom:{tag:"div",classes:["tox-anchorbar"]}}),g=Vb({dom:{tag:"div",classes:["tox-bottom-anchorbar"]}}),p=()=>r.mainUi.get().map((e=>e.outerContainer)).bind(XD.getHeader),h=r.lazyGetInOuterOrDie("anchor bar",m.getOpt),f=r.lazyGetInOuterOrDie("bottom anchor bar",g.getOpt),b=r.lazyGetInOuterOrDie("toolbar",XD.getToolbar),v=r.lazyGetInOuterOrDie("throbber",XD.getThrobber),y=((e,t,o,n)=>{const s=on(!1),r=(e=>{const t=on(kb(e)?"bottom":"top");return{isPositionedAtTop:()=>"top"===t.get(),getDockingMode:t.get,setDockingMode:t.set}})(t),a={icons:()=>t.ui.registry.getAll().icons,menuItems:()=>t.ui.registry.getAll().menuItems,translate:Kv.translate,isDisabled:()=>t.mode.isReadOnly()||!t.ui.isEnabled(),getOption:t.options.get,tooltips:kA(e.dialog)},i=YA(t),l=(e=>{const t=t=>()=>e.formatter.match(t),o=t=>()=>{const o=e.formatter.get(t);return void 0!==o?A.some({tag:o.length>0&&(o[0].inline||o[0].block)||"div",styles:e.dom.parseStyle(e.formatter.getCssText(t))}):A.none()},n=on([]),s=on([]),r=on(!1);return e.on("PreInit",(s=>{const r=xA(e),a=SA(e,r,t,o);n.set(a)})),e.on("addStyleModifications",(n=>{const a=SA(e,n.items,t,o);s.set(a),r.set(n.replace)})),{getData:()=>{const e=r.get()?[]:n.get(),t=s.get();return e.concat(t)}}})(t),c=(e=>({colorPicker:uA(e),hasCustomColors:mA(e),getColors:gA(e),getColorCols:pA(e)}))(t),d=(e=>({isDraggableModal:hA(e)}))(t),u={shared:{providers:a,anchors:dA(t,o,n,r.isPositionedAtTop),header:r},urlinput:i,styles:l,colorinput:c,dialog:d,isContextMenuOpen:()=>s.get(),setContextMenuState:e=>s.set(e)},m=e=>A.none(),g={...u,shared:{...u.shared,interpreter:e=>LE(e,{},g,m),getSink:e.popup}},p={...u,shared:{...u.shared,interpreter:e=>LE(e,{},p,m),getSink:e.dialog}};return{popup:g,dialog:p}})({popup:()=>dn.fromOption(r.popupUi.get().map((e=>e.sink)),"(popup) UI has not been rendered"),dialog:()=>dn.fromOption(r.dialogUi.get().map((e=>e.sink)),"UI has not been rendered")},e,h,f),x=()=>{const t=(()=>{const t={attributes:{[Qc]:d?Jc.BottomToTop:Jc.TopToBottom}},o=XD.parts.menubar({dom:{tag:"div",classes:["tox-menubar"]},backstage:y.popup,onEscape:()=>{e.focus()}}),n=XD.parts.toolbar({dom:{tag:"div",classes:["tox-toolbar"]},getSink:y.popup.shared.getSink,providers:y.popup.shared.providers,onEscape:()=>{e.focus()},onToolbarToggled:t=>{((e,t)=>{e.dispatch("ToggleToolbarDrawer",{state:t})})(e,t)},type:u,lazyToolbar:b,lazyHeader:()=>p().getOrDie("Could not find header element"),...t}),s=XD.parts["multiple-toolbar"]({dom:{tag:"div",classes:["tox-toolbar-overlord"]},providers:y.popup.shared.providers,onEscape:()=>{e.focus()},type:u}),r=Sb(e),a=xb(e),i=fb(e),l=mb(e),c=XD.parts.promotion({dom:{tag:"div",classes:["tox-promotion"]}}),g=r||a||i,h=l?[c,o]:[o];return XD.parts.header({dom:{tag:"div",classes:["tox-editor-header"].concat(g?[]:["tox-editor-header--empty"]),...t},components:G([i?h:[],r?[s]:a?[n]:[],Ob(e)?[]:[m.asSpec()]]),sticky:Eb(e),editor:e,sharedBackstage:y.popup.shared})})(),n={dom:{tag:"div",classes:["tox-sidebar-wrap"]},components:[XD.parts.socket({dom:{tag:"div",classes:["tox-edit-area"]}}),XD.parts.sidebar({dom:{tag:"div",classes:["tox-sidebar"]}})]},s=XD.parts.throbber({dom:{tag:"div",classes:["tox-throbber"]},backstage:y.popup}),r=XD.parts.viewWrapper({backstage:y.popup}),i=ab(e)&&!o?A.some(aR(e,y.popup.shared.providers)):A.none(),l=G([d?[]:[t],o?[]:[n],d?[t]:[]]),h=XD.parts.editorContainer({components:G([l,o?[]:[g.asSpec()]])}),f=Tb(e),v={role:"application",...Kv.isRtl()?{dir:"rtl"}:{},...f?{"aria-hidden":"true"}:{}},x=hl(XD.sketch({dom:{tag:"div",classes:["tox","tox-tinymce"].concat(o?["tox-tinymce-inline"]:[]).concat(d?["tox-tinymce--toolbar-bottom"]:[]).concat(c),styles:{visibility:"hidden",...f?{opacity:"0",border:"0"}:{}},attributes:v},components:[h,...o?[]:[r,...i.toArray()],s],behaviours:ma([dw(),pg.config({disableClass:"tox-tinymce--disabled"}),xh.config({mode:"cyclic",selector:".tox-menubar, .tox-toolbar, .tox-toolbar__primary, .tox-toolbar__overflow--open, .tox-sidebar__overflow--open, .tox-statusbar__path, .tox-statusbar__wordcount, .tox-statusbar__branding a, .tox-statusbar__resize-handle"})])})),w=Wk(x);return a.set(w),{mothership:w,outerContainer:x}},w=t=>{const o=cI((e=>{const t=(e=>{const t=Bf(e),o=Rf(e),n=zf(e);return lI(t).map((e=>dI(e,o,n)))})(e);return t.getOr(Bf(e))})(e)),n=cI((e=>uI(e).getOr(If(e)))(e));return e.inline||(Vt("div","width",n)&&Bt(t.element,"width",n),Vt("div","height",o)?Bt(t.element,"height",o):Bt(t.element,"height","400px")),o};return{popups:{backstage:y.popup,getMothership:()=>iR("popups",l)},dialogs:{backstage:y.dialog,getMothership:()=>iR("dialogs",i)},renderUI:()=>{const o=x(),a=(()=>{const t=_b(e),o=Ze(wt(),t)&&"grid"===Rt(t,"display"),n={dom:{tag:"div",classes:["tox","tox-silver-sink","tox-tinymce-aux"].concat(c),attributes:{...Kv.isRtl()?{dir:"rtl"}:{}}},behaviours:ma([tu.config({useFixed:()=>s.isDocked(p)})])},r={dom:{styles:{width:document.body.clientWidth+"px"}},events:Wr([Gr(Or(),(e=>{Bt(e.element,"width",document.body.clientWidth+"px")}))])},a=hl(wn(n,o?r:{})),l=Wk(a);return i.set(l),{sink:a,mothership:l}})(),d=Ab(e)?(()=>{const e={dom:{tag:"div",classes:["tox","tox-silver-sink","tox-silver-popup-sink","tox-tinymce-aux"].concat(c),attributes:{...Kv.isRtl()?{dir:"rtl"}:{}}},behaviours:ma([tu.config({useFixed:()=>s.isDocked(p),getBounds:()=>t.getPopupSinkBounds()})])},o=hl(e),n=Wk(o);return l.set(n),{sink:o,mothership:n}})():(e=>(l.set(e.mothership),e))(a);r.dialogUi.set(a),r.popupUi.set(d),r.mainUi.set(o);return(t=>{const{mainUi:o,popupUi:r,uiMotherships:a}=t;le(jf(e),((t,o)=>{e.ui.registry.addGroupToolbarButton(o,t)}));const{buttons:i,menuItems:l,contextToolbars:c,sidebars:d,views:m}=e.ui.registry.getAll(),g=wb(e),h={menuItems:l,menus:Mb(e),menubar:Kf(e),toolbar:g.getOrThunk((()=>Jf(e))),allowToolbarGroups:u===Sf.floating,buttons:i,sidebar:d,views:m};var f;f=o.outerContainer,e.addShortcut("alt+F9","focus menubar",(()=>{XD.focusMenubar(f)})),e.addShortcut("alt+F10","focus toolbar",(()=>{XD.focusToolbar(f)})),e.addCommand("ToggleToolbarDrawer",((e,t)=>{(null==t?void 0:t.skipFocus)?XD.toggleToolbarDrawerWithoutFocusing(f):XD.toggleToolbarDrawer(f)})),e.addQueryStateHandler("ToggleToolbarDrawer",(()=>XD.isToolbarDrawerToggled(f))),((e,t,o)=>{const n=(e,n)=>{V([t,...o],(t=>{t.broadcastEvent(e,n)}))},s=(e,n)=>{V([t,...o],(t=>{t.broadcastOn([e],n)}))},r=e=>s(Eu(),{target:e.target}),a=qo(),i=Fc(a,"touchstart",r),l=Fc(a,"touchmove",(e=>n(Sr(),e))),c=Fc(a,"touchend",(e=>n(kr(),e))),d=Fc(a,"mousedown",r),u=Fc(a,"mouseup",(e=>{0===e.raw.button&&s(Mu(),{target:e.target})})),m=e=>s(Eu(),{target:ze(e.target)}),g=e=>{0===e.button&&s(Mu(),{target:ze(e.target)})},p=()=>{V(e.editorManager.get(),(t=>{e!==t&&t.dispatch("DismissPopups",{relatedTarget:e})}))},h=e=>n(Cr(),Nc(e)),f=e=>{s(Au(),{}),n(Or(),Nc(e))},b=ft(ze(e.getElement())),v=Rc(b,"scroll",(o=>{requestAnimationFrame((()=>{if(null!=e.getContainer()){const s=Rb(e,t.element).map((e=>[e.element,...e.others])).getOr([]);R(s,(e=>Ze(e,o.target)))&&(e.dispatch("ElementScroll",{target:o.target.dom}),n(Br(),o))}}))})),y=()=>s(Au(),{}),x=t=>{t.state&&s(Eu(),{target:ze(e.getContainer())})},w=e=>{s(Eu(),{target:ze(e.relatedTarget.getContainer())})},S=t=>e.dispatch("focusin",t),k=t=>e.dispatch("focusout",t);e.on("PostRender",(()=>{e.on("click",m),e.on("tap",m),e.on("mouseup",g),e.on("mousedown",p),e.on("ScrollWindow",h),e.on("ResizeWindow",f),e.on("ResizeEditor",y),e.on("AfterProgressState",x),e.on("DismissPopups",w),V([t,...o],(e=>{e.element.dom.addEventListener("focusin",S),e.element.dom.addEventListener("focusout",k)}))})),e.on("remove",(()=>{e.off("click",m),e.off("tap",m),e.off("mouseup",g),e.off("mousedown",p),e.off("ScrollWindow",h),e.off("ResizeWindow",f),e.off("ResizeEditor",y),e.off("AfterProgressState",x),e.off("DismissPopups",w),V([t,...o],(e=>{e.element.dom.removeEventListener("focusin",S),e.element.dom.removeEventListener("focusout",k)})),d.unbind(),i.unbind(),l.unbind(),c.unbind(),u.unbind(),v.unbind()})),e.on("detach",(()=>{V([t,...o],fu),V([t,...o],(e=>e.destroy()))}))})(e,o.mothership,a),s.setup(e,y.popup.shared,p),jI(e,y.popup),uF(e,y.popup.shared.getSink,y.popup),(e=>{const{sidebars:t}=e.ui.registry.getAll();V(re(t),(o=>{const n=t[o],s=()=>ye(A.from(e.queryCommandValue("ToggleSidebar")),o);e.ui.registry.addToggleButton(o,{icon:n.icon,tooltip:n.tooltip,onAction:t=>{e.execCommand("ToggleSidebar",!1,o),t.setActive(s())},onSetup:t=>{t.setActive(s());const o=()=>t.setActive(s());return e.on("ToggleSidebar",o),()=>{e.off("ToggleSidebar",o)}}})}))})(e),WM(e,v,y.popup.shared),RI(e,c,r.sink,{backstage:y.popup}),tR(e,r.sink);const b={targetNode:e.getElement(),height:w(o.outerContainer)};return n.render(e,t,h,y.popup,b)})({popupUi:d,dialogUi:a,mainUi:o,uiMotherships:r.getUiMotherships()})}}},cR=x([is("lazySink"),fs("dragBlockClass"),Ms("getBounds",tn),Cs("useTabstopAt",E),Cs("firstTabstop",0),Cs("eventOrder",{}),Yu("modalBehaviours",[xh]),wi("onExecute"),ki("onEscape")]),dR={sketch:w},uR=x([km({name:"draghandle",overrides:(e,t)=>({behaviours:ma([JF.config({mode:"mouse",getTarget:e=>kl(e,'[role="dialog"]').getOr(e),blockerClass:e.dragBlockClass.getOrDie(new Error("The drag blocker class was not specified for a dialog with a drag handle: \n"+JSON.stringify(t,null,2)).message),getBounds:e.getDragBounds})])})}),wm({schema:[is("dom")],name:"title"}),wm({factory:dR,schema:[is("dom")],name:"close"}),wm({factory:dR,schema:[is("dom")],name:"body"}),km({factory:dR,schema:[is("dom")],name:"footer"}),Sm({factory:{sketch:(e,t)=>({...e,dom:t.dom,components:t.components})},schema:[Cs("dom",{tag:"div",styles:{position:"fixed",left:"0px",top:"0px",right:"0px",bottom:"0px"}}),Cs("components",[])],name:"blocker"})]),mR=Km({name:"ModalDialog",configFields:cR(),partFields:uR(),factory:(e,t,o,n)=>{const s=rn(),r=Bi("modal-events"),a={...e.eventOrder,[_r()]:[r].concat(e.eventOrder["alloy.system.attached"]||[])},i=Bo();return{uid:e.uid,dom:e.dom,components:t,apis:{show:t=>{s.set(t);const o=e.lazySink(t).getOrDie(),r=n.blocker(),a=o.getSystem().build({...r,components:r.components.concat([fl(t)]),behaviours:ma([Rh.config({}),Mh("dialog-blocker-events",[Zr(Qs(),(()=>{PM.isBlocked(t)||xh.focusIn(t)}))])])});lu(o,a),xh.focusIn(t)},hide:e=>{s.clear(),rt(e.element).each((t=>{e.getSystem().getByDom(t).each((e=>{uu(e)}))}))},getBody:t=>Nm(t,e,"body"),getFooter:t=>Rm(t,e,"footer"),setIdle:e=>{PM.unblock(e)},setBusy:(e,t)=>{PM.block(e,t)}},eventOrder:a,domModification:{attributes:{role:"dialog","aria-modal":"true"}},behaviours:Ku(e.modalBehaviours,[Ah.config({}),xh.config({mode:"cyclic",onEnter:e.onExecute,onEscape:e.onEscape,useTabstopAt:e.useTabstopAt,firstTabstop:e.firstTabstop}),PM.config({getRoot:s.get}),Mh(r,[ea((t=>{const o=Nm(t,e,"title").element,n=(e=>e.dom.textContent)(o);i.os.isMacOS()&&g(n)?Ct(t.element,"aria-label",n):((e,t)=>{const o=Tt(e,"id").fold((()=>{const e=Bi("dialog-label");return Ct(t,"id",e),e}),w);Ct(e,"aria-labelledby",o)})(t.element,o)}))])])}},apis:{show:(e,t)=>{e.show(t)},hide:(e,t)=>{e.hide(t)},getBody:(e,t)=>e.getBody(t),getFooter:(e,t)=>e.getFooter(t),setBusy:(e,t,o)=>{e.setBusy(t,o)},setIdle:(e,t)=>{e.setIdle(t)}}}),gR=Nn([Jy,Qy].concat(Yx)),pR=$n,hR=[Ox("button"),mx,Es("align","end",["start","end"]),xx,yx,xs("buttonType",["primary","secondary"])],fR=[...hR,ex],bR=[us("type",["submit","cancel","custom"]),...fR],vR=[us("type",["menu"]),dx,gx,mx,hs("items",gR),...hR],yR=[...hR,us("type",["togglebutton"]),gx,mx,dx,As("active",!1)],xR=os("type",{submit:bR,cancel:bR,custom:bR,menu:vR,togglebutton:yR}),wR=[Jy,ex,us("level",["info","warn","error","success"]),ox,Cs("url","")],SR=Nn(wR),kR=[Jy,ex,yx,Ox("button"),mx,vx,xs("buttonType",["primary","secondary","toolbar"]),xx],CR=Nn(kR),OR=[Jy,Qy],_R=OR.concat([px]),TR=OR.concat([Zy,yx]),ER=Nn(TR),AR=$n,MR=_R.concat([wx("auto")]),DR=Nn(MR),BR=Hn([nx,ex,ox]),IR=_R.concat([Ts("storageKey","default")]),FR=Nn(IR),RR=jn,NR=Nn(_R),zR=jn,LR=OR.concat([Ts("tag","textarea"),ds("scriptId"),ds("scriptUrl"),ws("onFocus"),Os("settings",void 0,Yn)]),VR=OR.concat([Ts("tag","textarea"),ms("init")]),HR=Kn((e=>Qn("customeditor.old",Rn(VR),e).orThunk((()=>Qn("customeditor.new",Rn(LR),e))))),PR=jn,UR=Nn(_R),WR=zn(Mn),jR=e=>[Jy,cs("columns"),e],$R=[Jy,ds("html"),Es("presets","presentation",["presentation","document"]),Ms("onInit",b),As("stretched",!1)],GR=Nn($R),qR=_R.concat([As("border",!1),As("sandboxed",!0),As("streamContent",!1),As("transparent",!0)]),YR=Nn(qR),XR=jn,KR=Nn(OR.concat([ys("height")])),JR=Nn([ds("url"),vs("zoom"),vs("cachedWidth"),vs("cachedHeight")]),QR=_R.concat([ys("inputMode"),ys("placeholder"),As("maximized",!1),yx]),ZR=Nn(QR),eN=jn,tN=e=>[Jy,Zy,e,Es("align","start",["start","center","end"]),ys("for")],oN=[ex,nx],nN=[ex,hs("items",ns(0,(()=>sN)))],sN=Ln([Nn(oN),Nn(nN)]),rN=_R.concat([hs("items",sN),yx]),aN=Nn(rN),iN=jn,lN=_R.concat([ps("items",[ex,nx]),_s("size",1),yx]),cN=Nn(lN),dN=jn,uN=_R.concat([As("constrain",!0),yx]),mN=Nn(uN),gN=Nn([ds("width"),ds("height")]),pN=OR.concat([Zy,_s("min",0),_s("max",0)]),hN=Nn(pN),fN=Wn,bN=[Jy,hs("header",jn),hs("cells",zn(jn))],vN=Nn(bN),yN=_R.concat([ys("placeholder"),As("maximized",!1),yx]),xN=Nn(yN),wN=jn,SN=[us("type",["directory","leaf"]),tx,ds("id"),bs("menu",wM)],kN=Nn(SN),CN=SN.concat([hs("children",ns(0,(()=>Xn("type",{directory:ON,leaf:kN}))))]),ON=Nn(CN),_N=Xn("type",{directory:ON,leaf:kN}),TN=[Jy,hs("items",_N),ws("onLeafAction"),ws("onToggleExpand"),Ds("defaultExpandedIds",[],jn),ys("defaultSelectedId")],EN=Nn(TN),AN=_R.concat([Es("filetype","file",["image","media","file"]),yx,ys("picker_text")]),MN=Nn(AN),DN=Nn([nx,Sx]),BN=e=>ss("items","items",{tag:"required",process:{}},zn(Kn((t=>Qn(`Checking item of ${e}`,IN,t).fold((e=>dn.error(ts(e))),(e=>dn.value(e))))))),IN=In((()=>{return Xn("type",{alertbanner:SR,bar:Nn((e=BN("bar"),[Jy,e])),button:CR,checkbox:ER,colorinput:FR,colorpicker:NR,dropzone:UR,grid:Nn(jR(BN("grid"))),iframe:YR,input:ZR,listbox:aN,selectbox:cN,sizeinput:mN,slider:hN,textarea:xN,urlinput:MN,customeditor:HR,htmlpanel:GR,imagepreview:KR,collection:DR,label:Nn(tN(BN("label"))),table:vN,tree:EN,panel:RN});var e})),FN=[Jy,Cs("classes",[]),hs("items",IN)],RN=Nn(FN),NN=[Ox("tab"),tx,hs("items",IN)],zN=[Jy,ps("tabs",NN)],LN=Nn(zN),VN=fR,HN=xR,PN=Nn([ds("title"),ls("body",Xn("type",{panel:RN,tabpanel:LN})),Ts("size","normal"),Ds("buttons",[],HN),Cs("initialData",{}),Ms("onAction",b),Ms("onChange",b),Ms("onSubmit",b),Ms("onClose",b),Ms("onCancel",b),Ms("onTabChange",b)]),UN=Nn([us("type",["cancel","custom"]),...VN]),WN=Nn([ds("title"),ds("url"),vs("height"),vs("width"),Ss("buttons",UN),Ms("onAction",b),Ms("onCancel",b),Ms("onClose",b),Ms("onMessage",b)]),jN=e=>a(e)?[e].concat(q(he(e),jN)):l(e)?q(e,jN):[],$N=e=>r(e.type)&&r(e.name),GN={checkbox:AR,colorinput:RR,colorpicker:zR,dropzone:WR,input:eN,iframe:XR,imagepreview:JR,selectbox:dN,sizeinput:gN,slider:fN,listbox:iN,size:gN,textarea:wN,urlinput:DN,customeditor:PR,collection:BR,togglemenuitem:pR},qN=e=>{const t=(e=>P(jN(e),$N))(e),o=q(t,(e=>(e=>A.from(GN[e.type]))(e).fold((()=>[]),(t=>[ls(e.name,t)]))));return Nn(o)},YN=e=>{var t;return{internalDialog:Zn(Qn("dialog",PN,e)),dataValidator:qN(e),initialData:null!==(t=e.initialData)&&void 0!==t?t:{}}},XN={open:(e,t)=>{const o=YN(t);return e(o.internalDialog,o.initialData,o.dataValidator)},openUrl:(e,t)=>e(Zn(Qn("dialog",WN,t))),redial:e=>YN(e)};var KN=Object.freeze({__proto__:null,events:(e,t)=>{const o=(o,n)=>{e.updateState.each((e=>{const s=e(o,n);t.set(s)})),e.renderComponents.each((s=>{const r=s(n,t.get());(e.reuseDom?Sh:wh)(o,r)}))};return Wr([Gr(pr(),((t,n)=>{const s=n;if(!s.universal){const n=e.channel;F(s.channels,n)&&o(t,s.data)}})),ea(((t,n)=>{e.initialData.each((e=>{o(t,e)}))}))])}}),JN=Object.freeze({__proto__:null,getState:(e,t,o)=>o}),QN=[is("channel"),fs("renderComponents"),fs("updateState"),fs("initialData"),As("reuseDom",!0)];const ZN=pa({fields:QN,name:"reflecting",active:KN,apis:JN,state:Object.freeze({__proto__:null,init:()=>{const e=on(A.none());return{readState:()=>e.get().getOr("none"),get:e.get,set:e.set,clear:()=>e.set(A.none())}}})}),ez=e=>{const t=[],o={};return ie(e,((e,n)=>{e.fold((()=>{t.push(n)}),(e=>{o[n]=e}))})),t.length>0?dn.error(t):dn.value(o)},tz=(e,t,o,n)=>{const s=Vb(u_.sketch((s=>({dom:{tag:"div",classes:["tox-form"].concat(e.classes)},components:L(e.items,(e=>NE(s,e,t,o,n)))}))));return{dom:{tag:"div",classes:["tox-dialog__body"]},components:[{dom:{tag:"div",classes:["tox-dialog__body-content"]},components:[s.asSpec()]}],behaviours:ma([xh.config({mode:"acyclic",useTabstopAt:C(N_)}),(r=s,eg.config({find:r.getOpt})),w_(s,{postprocess:e=>ez(e).fold((e=>(console.error(e),{})),w)}),Mh("dialog-body-panel",[Gr(Qs(),((e,t)=>{e.getSystem().broadcastOn([U_],{newFocus:A.some(t.event.target)})}))])])};var r},oz=Xm({name:"TabButton",configFields:[Cs("uid",void 0),is("value"),ss("dom","dom",On((()=>({attributes:{role:"tab",id:Bi("aria"),"aria-selected":"false"}}))),Pn()),fs("action"),Cs("domModification",{}),Yu("tabButtonBehaviours",[Rh,xh,qu]),is("view")],factory:(e,t)=>({uid:e.uid,dom:e.dom,components:e.components,events:$h(e.action),behaviours:Ku(e.tabButtonBehaviours,[Rh.config({}),xh.config({mode:"execution",useSpace:!0,useEnter:!0}),qu.config({store:{mode:"memory",initialValue:e.value}})]),domModification:e.domModification})}),nz=x([is("tabs"),is("dom"),Cs("clickToDismiss",!1),Yu("tabbarBehaviours",[Cg,xh]),vi(["tabClass","selectedClass"])]),sz=Cm({factory:oz,name:"tabs",unit:"tab",overrides:e=>{const t=(e,t)=>{Cg.dehighlight(e,t),Lr(e,Fr(),{tabbar:e,button:t})},o=(e,t)=>{Cg.highlight(e,t),Lr(e,Ir(),{tabbar:e,button:t})};return{action:n=>{const s=n.getSystem().getByUid(e.uid).getOrDie(),r=Cg.isHighlighted(s,n);(r&&e.clickToDismiss?t:r?b:o)(s,n)},domModification:{classes:[e.markers.tabClass]}}}}),rz=x([sz]),az=Km({name:"Tabbar",configFields:nz(),partFields:rz(),factory:(e,t,o,n)=>({uid:e.uid,dom:e.dom,components:t,"debug.sketcher":"Tabbar",domModification:{attributes:{role:"tablist"}},behaviours:Ku(e.tabbarBehaviours,[Cg.config({highlightClass:e.markers.selectedClass,itemClass:e.markers.tabClass,onHighlight:(e,t)=>{Ct(t.element,"aria-selected","true")},onDehighlight:(e,t)=>{Ct(t.element,"aria-selected","false")}}),xh.config({mode:"flow",getInitial:e=>Cg.getHighlighted(e).map((e=>e.element)),selector:"."+e.markers.tabClass,executeOnMove:!0})])})}),iz=Xm({name:"Tabview",configFields:[Yu("tabviewBehaviours",[Ah])],factory:(e,t)=>({uid:e.uid,dom:e.dom,behaviours:Ku(e.tabviewBehaviours,[Ah.config({})]),domModification:{attributes:{role:"tabpanel"}}})}),lz=x([Cs("selectFirst",!0),xi("onChangeTab"),xi("onDismissTab"),Cs("tabs",[]),Yu("tabSectionBehaviours",[])]),cz=wm({factory:az,schema:[is("dom"),gs("markers",[is("tabClass"),is("selectedClass")])],name:"tabbar",defaults:e=>({tabs:e.tabs})}),dz=wm({factory:iz,name:"tabview"}),uz=x([cz,dz]),mz=Km({name:"TabSection",configFields:lz(),partFields:uz(),factory:(e,t,o,n)=>{const s=(t,o)=>{Rm(t,e,"tabbar").each((e=>{o(e).each(Vr)}))};return{uid:e.uid,dom:e.dom,components:t,behaviours:Xu(e.tabSectionBehaviours),events:Wr(G([e.selectFirst?[ea(((e,t)=>{s(e,Cg.getFirst)}))]:[],[Gr(Ir(),((t,o)=>{(t=>{const o=qu.getValue(t);Rm(t,e,"tabview").each((n=>{j(e.tabs,(e=>e.value===o)).each((o=>{const s=o.view();Tt(t.element,"id").each((e=>{Ct(n.element,"aria-labelledby",e)})),Ah.set(n,s),e.onChangeTab(n,t,s)}))}))})(o.event.button)})),Gr(Fr(),((t,o)=>{const n=o.event.button;e.onDismissTab(t,n)}))]])),apis:{getViewItems:t=>Rm(t,e,"tabview").map((e=>Ah.contents(e))).getOr([]),showTab:(e,t)=>{s(e,(e=>{const o=Cg.getCandidates(e);return j(o,(e=>qu.getValue(e)===t)).filter((t=>!Cg.isHighlighted(e,t)))}))}}}},apis:{getViewItems:(e,t)=>e.getViewItems(t),showTab:(e,t,o)=>{e.showTab(t,o)}}}),gz=(e,t)=>{Bt(e,"height",t+"px"),Bt(e,"flex-basis",t+"px")},pz=(e,t,o)=>{kl(e,'[role="dialog"]').each((e=>{_l(e,'[role="tablist"]').each((n=>{o.get().map((o=>(Bt(t,"height","0"),Bt(t,"flex-basis","0"),Math.min(o,((e,t,o)=>{const n=nt(e).dom,s=kl(e,".tox-dialog-wrap").getOr(e);let r;r="fixed"===Rt(s,"position")?Math.max(n.clientHeight,window.innerHeight):Math.max(n.offsetHeight,n.scrollHeight);const a=jt(t),i=t.dom.offsetLeft>=o.dom.offsetLeft+Qt(o)?Math.max(jt(o),a):a,l=parseInt(Rt(e,"margin-top"),10)||0,c=parseInt(Rt(e,"margin-bottom"),10)||0;return r-(jt(e)+l+c-i)})(e,t,n))))).each((e=>{gz(t,e)}))}))}))},hz=e=>_l(e,'[role="tabpanel"]'),fz="send-data-to-section",bz="send-data-to-view",vz=(e,t,o,n)=>{const s=on({}),r=e=>{const t=qu.getValue(e),o=ez(t).getOr({}),n=s.get(),r=wn(n,o);s.set(r)},a=e=>{const t=s.get();qu.setValue(e,t)},i=on(null),l=L(e.tabs,(e=>({value:e.name,dom:{tag:"div",classes:["tox-dialog__body-nav-item"]},components:[ul(o.shared.providers.translate(e.title))],view:()=>[u_.sketch((s=>({dom:{tag:"div",classes:["tox-form"]},components:L(e.items,(e=>NE(s,e,t,o,n))),formBehaviours:ma([xh.config({mode:"acyclic",useTabstopAt:C(N_)}),Mh("TabView.form.events",[ea(a),ta(r)]),gc.config({channels:Rs([{key:fz,value:{onReceive:r}},{key:bz,value:{onReceive:a}}])})])})))]}))),c=(e=>{const t=rn(),o=[ea((o=>{const n=o.element;hz(n).each((s=>{Bt(s,"visibility","hidden"),o.getSystem().getByDom(s).toOptional().each((o=>{const n=((e,t,o)=>L(e,((n,s)=>{Ah.set(o,e[s].view());const r=t.dom.getBoundingClientRect();return Ah.set(o,[]),r.height})))(e,s,o),r=(e=>te(Z(e,((e,t)=>e>t?-1:e<t?1:0))))(n);r.fold(t.clear,t.set)})),pz(n,s,t),Ht(s,"visibility"),((e,t)=>{te(e).each((e=>mz.showTab(t,e.value)))})(e,o),requestAnimationFrame((()=>{pz(n,s,t)}))}))})),Gr(Or(),(e=>{const o=e.element;hz(o).each((e=>{pz(o,e,t)}))})),Gr(aC,((e,o)=>{const n=e.element;hz(n).each((e=>{const o=vc(ft(e));Bt(e,"visibility","hidden");const s=zt(e,"height").map((e=>parseInt(e,10)));Ht(e,"height"),Ht(e,"flex-basis");const r=e.dom.getBoundingClientRect().height;s.forall((e=>r>e))?(t.set(r),pz(n,e,t)):s.each((t=>{gz(e,t)})),Ht(e,"visibility"),o.each(hc)}))}))];return{extraEvents:o,selectFirst:!1}})(l);return mz.sketch({dom:{tag:"div",classes:["tox-dialog__body"]},onChangeTab:(e,t,o)=>{const n=qu.getValue(t);Lr(e,rC,{name:n,oldName:i.get()}),i.set(n)},tabs:l,components:[mz.parts.tabbar({dom:{tag:"div",classes:["tox-dialog__body-nav"]},components:[az.parts.tabs({})],markers:{tabClass:"tox-tab",selectedClass:"tox-dialog__body-nav-item--active"},tabbarBehaviours:ma([Ub.config({})])}),mz.parts.tabview({dom:{tag:"div",classes:["tox-dialog__body-content"]}})],selectFirst:c.selectFirst,tabSectionBehaviours:ma([Mh("tabpanel",c.extraEvents),xh.config({mode:"acyclic"}),eg.config({find:e=>te(mz.getViewItems(e))}),S_(A.none(),(e=>(e.getSystem().broadcastOn([fz],{}),s.get())),((e,t)=>{s.set(t),e.getSystem().broadcastOn([bz],{})}))])})},yz=(e,t,o,n,s,r)=>({dom:{tag:"div",classes:["tox-dialog__content-js"],attributes:{...o.map((e=>({id:e}))).getOr({}),...s?{"aria-live":"polite"}:{}}},components:[],behaviours:ma([y_(0),ZN.config({channel:`${V_}-${t}`,updateState:(e,t)=>A.some({isTabPanel:()=>"tabpanel"===t.body.type}),renderComponents:e=>{const t=e.body;return"tabpanel"===t.type?[vz(t,e.initialData,n,r)]:[tz(t,e.initialData,n,r)]},initialData:e})])}),xz=Tf.deviceType.isTouch(),wz=(e,t)=>({dom:{tag:"div",styles:{display:"none"},classes:["tox-dialog__header"]},components:[e,t]}),Sz=(e,t)=>mR.parts.close(zb.sketch({dom:{tag:"button",classes:["tox-button","tox-button--icon","tox-button--naked"],attributes:{type:"button","aria-label":t.translate("Close")}},action:e,buttonBehaviours:ma([Ub.config({})])})),kz=()=>mR.parts.title({dom:{tag:"div",classes:["tox-dialog__title"],innerHtml:"",styles:{display:"none"}}}),Cz=(e,t)=>mR.parts.body({dom:{tag:"div",classes:["tox-dialog__body"]},components:[{dom:{tag:"div",classes:["tox-dialog__body-content"]},components:[{dom:Lb(`<p>${Xv(t.translate(e))}</p>`)}]}]}),Oz=e=>mR.parts.footer({dom:{tag:"div",classes:["tox-dialog__footer"]},components:e}),_z=(e,t)=>[Uk.sketch({dom:{tag:"div",classes:["tox-dialog__footer-start"]},components:e}),Uk.sketch({dom:{tag:"div",classes:["tox-dialog__footer-end"]},components:t})],Tz=e=>{const t="tox-dialog",o=t+"-wrap",n=o+"__backdrop",s=t+"__disable-scroll";return mR.sketch({lazySink:e.lazySink,onEscape:t=>(e.onEscape(t),A.some(!0)),useTabstopAt:e=>!N_(e),firstTabstop:e.firstTabstop,dom:{tag:"div",classes:[t].concat(e.extraClasses),styles:{position:"relative",...e.extraStyles}},components:[e.header,e.body,...e.footer.toArray()],parts:{blocker:{dom:Lb(`<div class="${o}"></div>`),components:[{dom:{tag:"div",classes:xz?[n,n+"--opaque"]:[n]}}]}},dragBlockClass:o,modalBehaviours:ma([Rh.config({}),Mh("dialog-events",e.dialogEvents.concat([Zr(Qs(),((e,t)=>{PM.isBlocked(e)||xh.focusIn(e)})),Gr(Mr(),((e,t)=>{e.getSystem().broadcastOn([U_],{newFocus:t.event.newFocus})}))])),Mh("scroll-lock",[ea((()=>{ka(wt(),s)})),ta((()=>{Oa(wt(),s)}))]),...e.extraBehaviours]),eventOrder:{[hr()]:["dialog-events"],[_r()]:["scroll-lock","dialog-events","alloy.base.behaviour"],[Tr()]:["alloy.base.behaviour","dialog-events","scroll-lock"],...e.eventOrder}})},Ez=e=>zb.sketch({dom:{tag:"button",classes:["tox-button","tox-button--icon","tox-button--naked"],attributes:{type:"button","aria-label":e.translate("Close"),"data-mce-name":"close"}},buttonBehaviours:ma([Ub.config({}),Zb.config(e.tooltips.getConfig({tooltipText:e.translate("Close")}))]),components:[ry("close",{tag:"span",classes:["tox-icon"]},e.icons)],action:e=>{zr(e,eC)}}),Az=(e,t,o,n)=>({dom:{tag:"h1",classes:["tox-dialog__title"],attributes:{...o.map((e=>({id:e}))).getOr({})}},components:[],behaviours:ma([ZN.config({channel:`${L_}-${t}`,initialData:e,renderComponents:e=>[ul(n.translate(e.title))]})])}),Mz=()=>({dom:Lb('<div class="tox-dialog__draghandle"></div>')}),Dz=(e,t,o)=>((e,t,o)=>{const n=mR.parts.title(Az(e,t,A.none(),o)),s=mR.parts.draghandle(Mz()),r=mR.parts.close(Ez(o)),a=[n].concat(e.draggable?[s]:[]).concat([r]);return Uk.sketch({dom:Lb('<div class="tox-dialog__header"></div>'),components:a})})({title:o.shared.providers.translate(e),draggable:o.dialog.isDraggableModal()},t,o.shared.providers),Bz=(e,t,o,n)=>({dom:{tag:"div",classes:["tox-dialog__busy-spinner"],attributes:{"aria-label":o.translate(e)},styles:{left:"0px",right:"0px",bottom:"0px",top:`${n.getOr(0)}px`,position:"absolute"}},behaviours:t,components:[{dom:Lb('<div class="tox-spinner"><div></div><div></div><div></div></div>')}]}),Iz=(e,t,o)=>({onClose:()=>o.closeWindow(),onBlock:o=>{const n=_l(e().element,".tox-dialog__header").map((e=>jt(e)));mR.setBusy(e(),((e,s)=>Bz(o.message,s,t,n)))},onUnblock:()=>{mR.setIdle(e())}}),Fz="tox-dialog--fullscreen",Rz="tox-dialog--width-lg",Nz="tox-dialog--width-md",zz=e=>{switch(e){case"large":return A.some(Rz);case"medium":return A.some(Nz);default:return A.none()}},Lz=(e,t)=>{const o=ze(t.element.dom);_a(o,Fz)||(Ea(o,[Rz,Nz]),zz(e).each((e=>ka(o,e))))},Vz=(e,t)=>{const o=ze(e.element.dom),n=Aa(o),s=j(n,(e=>e===Rz||e===Nz)).or(zz(t));((e,t)=>{V(t,(t=>{((e,t)=>{const o=ya(e)?e.dom.classList.toggle(t):((e,t)=>F(xa(e),t)?Sa(e,t):wa(e,t))(e,t);Ca(e)})(e,t)}))})(o,[Fz,...s.toArray()])},Hz=(e,t,o)=>hl(Tz({...e,firstTabstop:1,lazySink:o.shared.getSink,extraBehaviours:[C_({}),...e.extraBehaviours],onEscape:e=>{zr(e,eC)},dialogEvents:t,eventOrder:{[pr()]:[ZN.name(),gc.name()],[_r()]:["scroll-lock",ZN.name(),"messages","dialog-events","alloy.base.behaviour"],[Tr()]:["alloy.base.behaviour","dialog-events","messages",ZN.name(),"scroll-lock"]}})),Pz=(e,t={})=>L(e,(e=>"menu"===e.type?(e=>{const o=L(e.items,(e=>{const o=fe(t,e.name).getOr(on(!1));return{...e,storage:o}}));return{...e,items:o}})(e):e)),Uz=e=>W(e,((e,t)=>"menu"===t.type?W(t.items,((e,t)=>(e[t.name]=t.storage,e)),e):e),{}),Wz=(e,t)=>[Kr(Qs(),R_),e(Zk,((e,o,n,s)=>{vc(ft(s.element)).fold(b,fc),t.onClose(),o.onClose()})),e(eC,((e,t,o,n)=>{t.onCancel(e),zr(n,Zk)})),Gr(sC,((e,o)=>t.onUnblock())),Gr(nC,((e,o)=>t.onBlock(o.event)))],jz=(e,t,o)=>{const n=(t,o)=>Gr(t,((t,n)=>{s(t,((s,r)=>{o(e(),s,n.event,t)}))})),s=(e,t)=>{ZN.getState(e).get().each((o=>{t(o.internalDialog,e)}))};return[...Wz(n,t),n(oC,((e,t)=>t.onSubmit(e))),n(Qk,((e,t,o)=>{t.onChange(e,{name:o.name})})),n(tC,((e,t,n,s)=>{const r=()=>s.getSystem().isConnected()?xh.focusIn(s):void 0,a=e=>Et(e,"disabled")||Tt(e,"aria-disabled").exists((e=>"true"===e)),i=ft(s.element),l=vc(i);t.onAction(e,{name:n.name,value:n.value}),vc(i).fold(r,(e=>{a(e)||l.exists((t=>et(e,t)&&a(t)))?r():o().toOptional().filter((t=>!et(t.element,e))).each(r)}))})),n(rC,((e,t,o)=>{t.onTabChange(e,{newTabName:o.name,oldTabName:o.oldName})})),ta((t=>{const o=e();qu.setValue(t,o.getData())}))]},$z=(e,t)=>{const o=t.map((e=>e.footerButtons)).getOr([]),n=H(o,(e=>"start"===e.align)),s=(e,t)=>Uk.sketch({dom:{tag:"div",classes:[`tox-dialog__footer-${e}`]},components:L(t,(e=>e.memento.asSpec()))});return[s("start",n.pass),s("end",n.fail)]},Gz=(e,t,o)=>({dom:Lb('<div class="tox-dialog__footer"></div>'),components:[],behaviours:ma([ZN.config({channel:`${H_}-${t}`,initialData:e,updateState:(e,t)=>{const n=L(t.buttons,(e=>{const t=Vb(((e,t)=>xE(e,e.type,t))(e,o));return{name:e.name,align:e.align,memento:t}}));return A.some({lookupByName:t=>((e,t,o)=>j(t,(e=>e.name===o)).bind((t=>t.memento.getOpt(e))))(e,n,t),footerButtons:n})},renderComponents:$z})])}),qz=(e,t,o)=>mR.parts.footer(Gz(e,t,o)),Yz=(e,t)=>{if(e.getRoot().getSystem().isConnected()){const o=eg.getCurrent(e.getFormWrapper()).getOr(e.getFormWrapper());return u_.getField(o,t).orThunk((()=>{const o=e.getFooter().bind((e=>ZN.getState(e).get()));return o.bind((e=>e.lookupByName(t)))}))}return A.none()},Xz=(e,t,o)=>{const n=t=>{const o=e.getRoot();o.getSystem().isConnected()&&t(o)},s={getData:()=>{const t=e.getRoot(),n=t.getSystem().isConnected()?e.getFormWrapper():t;return{...qu.getValue(n),...le(o,(e=>e.get()))}},setData:t=>{n((n=>{const r=s.getData(),a=wn(r,t),i=((e,t)=>{const o=e.getRoot();return ZN.getState(o).get().map((e=>Zn(Qn("data",e.dataValidator,t)))).getOr(t)})(e,a),l=e.getFormWrapper();qu.setValue(l,i),ie(o,((e,t)=>{be(a,t)&&e.set(a[t])}))}))},setEnabled:(t,o)=>{Yz(e,t).each(o?pg.enable:pg.disable)},focus:t=>{Yz(e,t).each(Rh.focus)},block:e=>{if(!r(e))throw new Error("The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument");n((t=>{Lr(t,nC,{message:e})}))},unblock:()=>{n((e=>{zr(e,sC)}))},showTab:t=>{n((o=>{const n=e.getBody();ZN.getState(n).get().exists((e=>e.isTabPanel()))&&eg.getCurrent(n).each((e=>{mz.showTab(e,t)}))}))},redial:r=>{n((n=>{const a=e.getId(),i=t(r),l=Pz(i.internalDialog.buttons,o);n.getSystem().broadcastOn([`${z_}-${a}`],i),n.getSystem().broadcastOn([`${L_}-${a}`],i.internalDialog),n.getSystem().broadcastOn([`${V_}-${a}`],i.internalDialog),n.getSystem().broadcastOn([`${H_}-${a}`],{...i.internalDialog,buttons:l}),s.setData(i.initialData)}))},close:()=>{n((e=>{zr(e,Zk)}))},toggleFullscreen:e.toggleFullscreen};return s},Kz=(e,t,o,n=!1,s)=>{const r=Bi("dialog"),a=Bi("dialog-label"),i=Bi("dialog-content"),l=e.internalDialog,c=on(l.size),d=zz(c.get()).toArray(),u=Vb(((e,t,o,n)=>Uk.sketch({dom:Lb('<div class="tox-dialog__header"></div>'),components:[Az(e,t,A.some(o),n),Mz(),Ez(n)],containerBehaviours:ma([JF.config({mode:"mouse",blockerClass:"blocker",getTarget:e=>Tl(e,'[role="dialog"]').getOrDie(),snaps:{getSnapPoints:()=>[],leftAttr:"data-drag-left",topAttr:"data-drag-top"}})])}))({title:l.title,draggable:!0},r,a,o.shared.providers)),m=Vb(((e,t,o,n,s,r)=>yz(e,t,A.some(o),n,s,r))({body:l.body,initialData:l.initialData},r,i,o,n,(e=>Yz(y,e)))),g=Pz(l.buttons),p=Uz(g),h=ke(0!==g.length,Vb(((e,t,o)=>Gz(e,t,o))({buttons:g},r,o))),f=jz((()=>w),{onBlock:e=>{PM.block(v,((t,n)=>{const s=u.getOpt(v).map((e=>jt(e.element)));return Bz(e.message,n,o.shared.providers,s)}))},onUnblock:()=>{PM.unblock(v)},onClose:()=>t.closeWindow()},o.shared.getSink),b=Bo().os,v=hl({dom:{tag:"div",classes:["tox-dialog","tox-dialog-inline",...d],attributes:{role:"dialog",...b.isMacOS()?{"aria-label":l.title}:{"aria-labelledby":a}}},eventOrder:{[pr()]:[ZN.name(),gc.name()],[hr()]:["execute-on-form"],[_r()]:["reflecting","execute-on-form"]},behaviours:ma([xh.config({mode:"cyclic",onEscape:e=>(zr(e,Zk),A.some(!0)),useTabstopAt:e=>!N_(e)&&("button"!==Ue(e)||"disabled"!==_t(e,"disabled")),firstTabstop:1}),ZN.config({channel:`${z_}-${r}`,updateState:(e,t)=>(c.set(t.internalDialog.size),Lz(t.internalDialog.size,e),s(),A.some(t)),initialData:e}),Rh.config({}),Mh("execute-on-form",f.concat([Zr(Qs(),((e,t)=>{xh.focusIn(e)})),Gr(Mr(),((e,t)=>{e.getSystem().broadcastOn([U_],{newFocus:t.event.newFocus})}))])),PM.config({getRoot:()=>A.some(v)}),Ah.config({}),C_({})]),components:[u.asSpec(),m.asSpec(),...h.map((e=>e.asSpec())).toArray()]}),y={getId:x(r),getRoot:x(v),getFooter:()=>h.map((e=>e.get(v))),getBody:()=>m.get(v),getFormWrapper:()=>{const e=m.get(v);return eg.getCurrent(e).getOr(e)},toggleFullscreen:()=>{Vz(v,c.get())}},w=Xz(y,t.redial,p);return{dialog:v,instanceApi:w}};var Jz=tinymce.util.Tools.resolve("tinymce.util.URI");const Qz=["insertContent","setContent","execCommand","close","block","unblock"],Zz=e=>a(e)&&-1!==Qz.indexOf(e.mceAction),eL=(e,t,o,n)=>{const s=Bi("dialog"),i=Dz(e.title,s,n),l=(e=>{const t={dom:{tag:"div",classes:["tox-dialog__content-js"]},components:[{dom:{tag:"div",classes:["tox-dialog__body-iframe"]},components:[I_(A.none(),{dom:{tag:"iframe",attributes:{src:e.url}},behaviours:ma([Ub.config({}),Rh.config({})])})]}],behaviours:ma([xh.config({mode:"acyclic",useTabstopAt:C(N_)})])};return mR.parts.body(t)})(e),c=e.buttons.bind((e=>0===e.length?A.none():A.some(qz({buttons:e},s,n)))),u=((e,t)=>{const o=(e,t)=>Gr(e,((e,o)=>{n(e,((n,s)=>{t(x,n,o.event,e)}))})),n=(e,t)=>{ZN.getState(e).get().each((o=>{t(o,e)}))};return[...Wz(o,t),o(tC,((e,t,o)=>{t.onAction(e,{name:o.name})}))]})(0,Iz((()=>y),n.shared.providers,t)),m={...e.height.fold((()=>({})),(e=>({height:e+"px","max-height":e+"px"}))),...e.width.fold((()=>({})),(e=>({width:e+"px","max-width":e+"px"})))},p=e.width.isNone()&&e.height.isNone()?["tox-dialog--width-lg"]:[],h=new Jz(e.url,{base_uri:new Jz(window.location.href)}),f=`${h.protocol}://${h.host}${h.port?":"+h.port:""}`,b=sn(),v=[ZN.config({channel:`${z_}-${s}`,updateState:(e,t)=>A.some(t),initialData:e}),Mh("messages",[ea((()=>{const t=Fc(ze(window),"message",(t=>{if(h.isSameOrigin(new Jz(t.raw.origin))){const n=t.raw.data;Zz(n)?((e,t,o)=>{switch(o.mceAction){case"insertContent":e.insertContent(o.content);break;case"setContent":e.setContent(o.content);break;case"execCommand":const n=!!d(o.ui)&&o.ui;e.execCommand(o.cmd,n,o.value);break;case"close":t.close();break;case"block":t.block(o.message);break;case"unblock":t.unblock()}})(o,x,n):(e=>!Zz(e)&&a(e)&&be(e,"mceAction"))(n)&&e.onMessage(x,n)}}));b.set(t)})),ta(b.clear)]),gc.config({channels:{[P_]:{onReceive:(e,t)=>{_l(e.element,"iframe").each((e=>{const o=e.dom.contentWindow;g(o)&&o.postMessage(t,f)}))}}}})],y=Hz({id:s,header:i,body:l,footer:c,extraClasses:p,extraBehaviours:v,extraStyles:m},u,n),x=(e=>{const t=t=>{e.getSystem().isConnected()&&t(e)};return{block:e=>{if(!r(e))throw new Error("The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument");t((t=>{Lr(t,nC,{message:e})}))},unblock:()=>{t((e=>{zr(e,sC)}))},close:()=>{t((e=>{zr(e,Zk)}))},sendMessage:e=>{t((t=>{t.getSystem().broadcastOn([P_],e)}))}}})(y);return{dialog:y,instanceApi:x}},tL=(e,t)=>Zn(Qn("data",t,e)),oL=e=>Bk(e,".tox-alert-dialog")||Bk(e,".tox-confirm-dialog"),nL=(e,t,o)=>t&&o?[]:[Ei.config({contextual:{lazyContext:()=>A.some(Qo(ze(e.getContentAreaContainer()))),fadeInClass:"tox-dialog-dock-fadein",fadeOutClass:"tox-dialog-dock-fadeout",transitionClass:"tox-dialog-dock-transition"},modes:["top"],lazyViewport:t=>Rb(e,t.element).map((e=>({bounds:Nb(e),optScrollEnv:A.some({currentScrollTop:e.element.dom.scrollTop,scrollElmTop:Xt(e.element).top})}))).getOrThunk((()=>({bounds:tn(),optScrollEnv:A.none()})))})],sL=e=>{const t=e.editor,o=Eb(t),n=(e=>{const t=e.shared;return{open:(o,n)=>{const s=()=>{mR.hide(l),n()},r=Vb(xE({name:"close-alert",text:"OK",primary:!0,buttonType:A.some("primary"),align:"end",enabled:!0,icon:A.none()},"cancel",e)),a=kz(),i=Sz(s,t.providers),l=hl(Tz({lazySink:()=>t.getSink(),header:wz(a,i),body:Cz(o,t.providers),footer:A.some(Oz(_z([],[r.asSpec()]))),onEscape:s,extraClasses:["tox-alert-dialog"],extraBehaviours:[],extraStyles:{},dialogEvents:[Gr(eC,s)],eventOrder:{}}));mR.show(l);const c=r.get(l);Rh.focus(c)}}})(e.backstages.dialog),s=(e=>{const t=e.shared;return{open:(o,n)=>{const s=e=>{mR.hide(c),n(e)},r=Vb(xE({name:"yes",text:"Yes",primary:!0,buttonType:A.some("primary"),align:"end",enabled:!0,icon:A.none()},"submit",e)),a=xE({name:"no",text:"No",primary:!1,buttonType:A.some("secondary"),align:"end",enabled:!0,icon:A.none()},"cancel",e),i=kz(),l=Sz((()=>s(!1)),t.providers),c=hl(Tz({lazySink:()=>t.getSink(),header:wz(i,l),body:Cz(o,t.providers),footer:A.some(Oz(_z([],[a,r.asSpec()]))),onEscape:()=>s(!1),extraClasses:["tox-confirm-dialog"],extraBehaviours:[],extraStyles:{},dialogEvents:[Gr(eC,(()=>s(!1))),Gr(oC,(()=>s(!0)))],eventOrder:{}}));mR.show(c);const d=r.get(c);Rh.focus(d)}}})(e.backstages.dialog),r=(t,o)=>XN.open(((t,n,s)=>{const r=n,a=((e,t,o)=>{const n=Bi("dialog"),s=e.internalDialog,r=Dz(s.title,n,o),a=on(s.size),i=zz(a.get()).toArray(),l=((e,t,o,n)=>{const s=yz(e,t,A.none(),o,!1,n);return mR.parts.body(s)})({body:s.body,initialData:s.initialData},n,o,(e=>Yz(h,e))),c=Pz(s.buttons),d=Uz(c),u=ke(0!==c.length,qz({buttons:c},n,o)),m=jz((()=>f),Iz((()=>p),o.shared.providers,t),o.shared.getSink),g={id:n,header:r,body:l,footer:u,extraClasses:i,extraBehaviours:[ZN.config({channel:`${z_}-${n}`,updateState:(e,t)=>(a.set(t.internalDialog.size),Lz(t.internalDialog.size,e),A.some(t)),initialData:e})],extraStyles:{}},p=Hz(g,m,o),h={getId:x(n),getRoot:x(p),getBody:()=>mR.getBody(p),getFooter:()=>mR.getFooter(p),getFormWrapper:()=>{const e=mR.getBody(p);return eg.getCurrent(e).getOr(e)},toggleFullscreen:()=>{Vz(p,a.get())}},f=Xz(h,t.redial,d);return{dialog:p,instanceApi:f}})({dataValidator:s,initialData:r,internalDialog:t},{redial:XN.redial,closeWindow:()=>{mR.hide(a.dialog),o(a.instanceApi)}},e.backstages.dialog);return mR.show(a.dialog),a.instanceApi.setData(r),a.instanceApi}),t),a=(n,s,r,a)=>XN.open(((n,i,l)=>{const c=tL(i,l),d=rn(),u=e.backstages.popup.shared.header.isPositionedAtTop(),m=()=>d.on((e=>{wf.reposition(e),o&&u||Ei.refresh(e)})),g=Kz({dataValidator:l,initialData:c,internalDialog:n},{redial:XN.redial,closeWindow:()=>{d.on(wf.hide),t.off("ResizeEditor",m),d.clear(),r(g.instanceApi)}},e.backstages.popup,a.ariaAttrs,m),p=hl(wf.sketch({lazySink:e.backstages.popup.shared.getSink,dom:{tag:"div",classes:[]},fireDismissalEventInstead:a.persistent?{event:"doNotDismissYet"}:{},...u?{}:{fireRepositionEventInstead:{}},inlineBehaviours:ma([Mh("window-manager-inline-events",[Gr(Er(),((e,t)=>{zr(g.dialog,eC)}))]),...nL(t,o,u)]),isExtraPart:(e,t)=>oL(t)}));return d.set(p),wf.showWithinBounds(p,fl(g.dialog),{anchor:s},(()=>{const e=t.inline?wt():ze(t.getContainer()),o=Qo(e);return A.some(o)})),o&&u||(Ei.refresh(p),t.on("ResizeEditor",m)),g.instanceApi.setData(c),xh.focusIn(g.dialog),g.instanceApi}),n),i=(o,n,s,r)=>XN.open(((o,a,i)=>{const l=tL(a,i),c=rn(),d=e.backstages.popup.shared.header.isPositionedAtTop(),u=()=>c.on((e=>{wf.reposition(e),Ei.refresh(e)})),m=Kz({dataValidator:i,initialData:l,internalDialog:o},{redial:XN.redial,closeWindow:()=>{c.on(wf.hide),t.off("ResizeEditor ScrollWindow ElementScroll",u),c.clear(),s(m.instanceApi)}},e.backstages.popup,r.ariaAttrs,u),g=hl(wf.sketch({lazySink:e.backstages.popup.shared.getSink,dom:{tag:"div",classes:[]},fireDismissalEventInstead:r.persistent?{event:"doNotDismissYet"}:{},...d?{}:{fireRepositionEventInstead:{}},inlineBehaviours:ma([Mh("window-manager-inline-events",[Gr(Er(),((e,t)=>{zr(m.dialog,eC)}))]),Ei.config({contextual:{lazyContext:()=>A.some(Qo(ze(t.getContentAreaContainer()))),fadeInClass:"tox-dialog-dock-fadein",fadeOutClass:"tox-dialog-dock-fadeout",transitionClass:"tox-dialog-dock-transition"},modes:["top","bottom"],lazyViewport:e=>Rb(t,e.element).map((e=>({bounds:Nb(e),optScrollEnv:A.some({currentScrollTop:e.element.dom.scrollTop,scrollElmTop:Xt(e.element).top})}))).getOrThunk((()=>({bounds:tn(),optScrollEnv:A.none()})))})]),isExtraPart:(e,t)=>oL(t)}));return c.set(g),wf.showWithinBounds(g,fl(m.dialog),{anchor:n},(()=>e.backstages.popup.shared.getSink().toOptional().bind((e=>{const o=Rb(t,e.element).map((e=>Nb(e))).getOr(tn()),n=Qo(ze(t.getContentAreaContainer())),s=en(n,o);return A.some(Jo(s.x,s.y,s.width,s.height-15))})))),Ei.refresh(g),t.on("ResizeEditor ScrollWindow ElementScroll ResizeWindow",u),m.instanceApi.setData(l),xh.focusIn(m.dialog),m.instanceApi}),o);return{open:(t,o,n)=>{if(!u(o)){if("toolbar"===o.inline)return a(t,e.backstages.popup.shared.anchors.inlineDialog(),n,o);if("bottom"===o.inline)return i(t,e.backstages.popup.shared.anchors.inlineBottomDialog(),n,o);if("cursor"===o.inline)return a(t,e.backstages.popup.shared.anchors.cursor(),n,o)}return r(t,n)},openUrl:(o,n)=>((o,n)=>XN.openUrl((o=>{const s=eL(o,{closeWindow:()=>{mR.hide(s.dialog),n(s.instanceApi)}},t,e.backstages.dialog);return mR.show(s.dialog),s.instanceApi}),o))(o,n),alert:(e,t)=>{n.open(e,t)},close:e=>{e.close()},confirm:(e,t)=>{s.open(e,t)}}};an.add("silver",(e=>{(e=>{Mf(e),(e=>{const t=e.options.register,o=e=>f(e,r)?{value:xS(e),valid:!0}:{valid:!1,message:"Must be an array of strings."},n=e=>h(e)&&e>0?{value:e,valid:!0}:{valid:!1,message:"Must be a positive number."};t("color_map",{processor:o,default:["#BFEDD2","Light Green","#FBEEB8","Light Yellow","#F8CAC6","Light Red","#ECCAFA","Light Purple","#C2E0F4","Light Blue","#2DC26B","Green","#F1C40F","Yellow","#E03E2D","Red","#B96AD9","Purple","#3598DB","Blue","#169179","Dark Turquoise","#E67E23","Orange","#BA372A","Dark Red","#843FA1","Dark Purple","#236FA1","Dark Blue","#ECF0F1","Light Gray","#CED4D9","Medium Gray","#95A5A6","Gray","#7E8C8D","Dark Gray","#34495E","Navy Blue","#000000","Black","#ffffff","White"]}),t("color_map_background",{processor:o}),t("color_map_foreground",{processor:o}),t("color_cols",{processor:n,default:CS(e)}),t("color_cols_foreground",{processor:n,default:OS(e,vS)}),t("color_cols_background",{processor:n,default:OS(e,yS)}),t("custom_colors",{processor:"boolean",default:!0}),t("color_default_foreground",{processor:"string",default:SS}),t("color_default_background",{processor:"string",default:SS})})(e),(e=>{const t=e.options.register;t("contextmenu_avoid_overlap",{processor:"string",default:""}),t("contextmenu_never_use_native",{processor:"boolean",default:!1}),t("contextmenu",{processor:e=>!1===e?{value:[],valid:!0}:r(e)||f(e,r)?{value:$I(e),valid:!0}:{valid:!1,message:"Must be false or a string."},default:"link linkchecker image editimage table spellchecker configurepermanentpen"})})(e)})(e);let t=()=>tn();const{dialogs:o,popups:n,renderUI:s}=lR(e,{getPopupSinkBounds:()=>t()});Dk(e,n.backstage.shared);const a=sL({editor:e,backstages:{popup:n.backstage,dialog:o.backstage}}),i=rn();return{renderUI:()=>{const o=s();return Rb(e,n.getMothership().element).each((e=>{t=()=>Nb(e)})),o},getWindowManagerImpl:x(a),getNotificationManagerImpl:()=>ly(e,{backstage:n.backstage},n.getMothership(),i)}}))}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/public/tinymce/tinymce.d.ts b/eims-ui/apps/web-antd/public/tinymce/tinymce.d.ts
new file mode 100644
index 0000000..a554aa9
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/tinymce.d.ts
@@ -0,0 +1,3254 @@
+interface StringPathBookmark {
+    start: string;
+    end?: string;
+    forward?: boolean;
+}
+interface RangeBookmark {
+    rng: Range;
+    forward?: boolean;
+}
+interface IdBookmark {
+    id: string;
+    keep?: boolean;
+    forward?: boolean;
+}
+interface IndexBookmark {
+    name: string;
+    index: number;
+}
+interface PathBookmark {
+    start: number[];
+    end?: number[];
+    isFakeCaret?: boolean;
+    forward?: boolean;
+}
+type Bookmark = StringPathBookmark | RangeBookmark | IdBookmark | IndexBookmark | PathBookmark;
+type NormalizedEvent<E, T = any> = E & {
+    readonly type: string;
+    readonly target: T;
+    readonly isDefaultPrevented: () => boolean;
+    readonly preventDefault: () => void;
+    readonly isPropagationStopped: () => boolean;
+    readonly stopPropagation: () => void;
+    readonly isImmediatePropagationStopped: () => boolean;
+    readonly stopImmediatePropagation: () => void;
+};
+type MappedEvent<T extends {}, K extends string> = K extends keyof T ? T[K] : any;
+interface NativeEventMap {
+    'beforepaste': Event;
+    'blur': FocusEvent;
+    'beforeinput': InputEvent;
+    'click': MouseEvent;
+    'compositionend': Event;
+    'compositionstart': Event;
+    'compositionupdate': Event;
+    'contextmenu': PointerEvent;
+    'copy': ClipboardEvent;
+    'cut': ClipboardEvent;
+    'dblclick': MouseEvent;
+    'drag': DragEvent;
+    'dragdrop': DragEvent;
+    'dragend': DragEvent;
+    'draggesture': DragEvent;
+    'dragover': DragEvent;
+    'dragstart': DragEvent;
+    'drop': DragEvent;
+    'focus': FocusEvent;
+    'focusin': FocusEvent;
+    'focusout': FocusEvent;
+    'input': InputEvent;
+    'keydown': KeyboardEvent;
+    'keypress': KeyboardEvent;
+    'keyup': KeyboardEvent;
+    'mousedown': MouseEvent;
+    'mouseenter': MouseEvent;
+    'mouseleave': MouseEvent;
+    'mousemove': MouseEvent;
+    'mouseout': MouseEvent;
+    'mouseover': MouseEvent;
+    'mouseup': MouseEvent;
+    'paste': ClipboardEvent;
+    'selectionchange': Event;
+    'submit': Event;
+    'touchend': TouchEvent;
+    'touchmove': TouchEvent;
+    'touchstart': TouchEvent;
+    'touchcancel': TouchEvent;
+    'wheel': WheelEvent;
+}
+type EditorEvent<T> = NormalizedEvent<T>;
+interface EventDispatcherSettings {
+    scope?: any;
+    toggleEvent?: (name: string, state: boolean) => void | boolean;
+    beforeFire?: <T>(args: EditorEvent<T>) => void;
+}
+interface EventDispatcherConstructor<T extends {}> {
+    readonly prototype: EventDispatcher<T>;
+    new (settings?: EventDispatcherSettings): EventDispatcher<T>;
+    isNative: (name: string) => boolean;
+}
+declare class EventDispatcher<T extends {}> {
+    static isNative(name: string): boolean;
+    private readonly settings;
+    private readonly scope;
+    private readonly toggleEvent;
+    private bindings;
+    constructor(settings?: EventDispatcherSettings);
+    fire<K extends string, U extends MappedEvent<T, K>>(name: K, args?: U): EditorEvent<U>;
+    dispatch<K extends string, U extends MappedEvent<T, K>>(name: K, args?: U): EditorEvent<U>;
+    on<K extends string>(name: K, callback: false | ((event: EditorEvent<MappedEvent<T, K>>) => void | boolean), prepend?: boolean, extra?: {}): this;
+    off<K extends string>(name?: K, callback?: (event: EditorEvent<MappedEvent<T, K>>) => void): this;
+    once<K extends string>(name: K, callback: (event: EditorEvent<MappedEvent<T, K>>) => void, prepend?: boolean): this;
+    has(name: string): boolean;
+}
+type UndoLevelType = 'fragmented' | 'complete';
+interface BaseUndoLevel {
+    type: UndoLevelType;
+    bookmark: Bookmark | null;
+    beforeBookmark: Bookmark | null;
+}
+interface FragmentedUndoLevel extends BaseUndoLevel {
+    type: 'fragmented';
+    fragments: string[];
+    content: '';
+}
+interface CompleteUndoLevel extends BaseUndoLevel {
+    type: 'complete';
+    fragments: null;
+    content: string;
+}
+type NewUndoLevel = CompleteUndoLevel | FragmentedUndoLevel;
+type UndoLevel = NewUndoLevel & {
+    bookmark: Bookmark;
+};
+interface UndoManager {
+    data: UndoLevel[];
+    typing: boolean;
+    add: (level?: Partial<UndoLevel>, event?: EditorEvent<any>) => UndoLevel | null;
+    dispatchChange: () => void;
+    beforeChange: () => void;
+    undo: () => UndoLevel | undefined;
+    redo: () => UndoLevel | undefined;
+    clear: () => void;
+    reset: () => void;
+    hasUndo: () => boolean;
+    hasRedo: () => boolean;
+    transact: (callback: () => void) => UndoLevel | null;
+    ignore: (callback: () => void) => void;
+    extra: (callback1: () => void, callback2: () => void) => void;
+}
+type SchemaType = 'html4' | 'html5' | 'html5-strict';
+interface ElementSettings {
+    block_elements?: string;
+    boolean_attributes?: string;
+    move_caret_before_on_enter_elements?: string;
+    non_empty_elements?: string;
+    self_closing_elements?: string;
+    text_block_elements?: string;
+    text_inline_elements?: string;
+    void_elements?: string;
+    whitespace_elements?: string;
+    transparent_elements?: string;
+    wrap_block_elements?: string;
+}
+interface SchemaSettings extends ElementSettings {
+    custom_elements?: string | Record<string, CustomElementSpec>;
+    extended_valid_elements?: string;
+    invalid_elements?: string;
+    invalid_styles?: string | Record<string, string>;
+    schema?: SchemaType;
+    valid_children?: string;
+    valid_classes?: string | Record<string, string>;
+    valid_elements?: string;
+    valid_styles?: string | Record<string, string>;
+    verify_html?: boolean;
+    padd_empty_block_inline_children?: boolean;
+}
+interface Attribute {
+    required?: boolean;
+    defaultValue?: string;
+    forcedValue?: string;
+    validValues?: Record<string, {}>;
+}
+interface DefaultAttribute {
+    name: string;
+    value: string;
+}
+interface AttributePattern extends Attribute {
+    pattern: RegExp;
+}
+interface ElementRule {
+    attributes: Record<string, Attribute>;
+    attributesDefault?: DefaultAttribute[];
+    attributesForced?: DefaultAttribute[];
+    attributesOrder: string[];
+    attributePatterns?: AttributePattern[];
+    attributesRequired?: string[];
+    paddEmpty?: boolean;
+    removeEmpty?: boolean;
+    removeEmptyAttrs?: boolean;
+    paddInEmptyBlock?: boolean;
+}
+interface SchemaElement extends ElementRule {
+    outputName?: string;
+    parentsRequired?: string[];
+    pattern?: RegExp;
+}
+interface SchemaMap {
+    [name: string]: {};
+}
+interface SchemaRegExpMap {
+    [name: string]: RegExp;
+}
+interface CustomElementSpec {
+    extends?: string;
+    attributes?: string[];
+    children?: string[];
+    padEmpty?: boolean;
+}
+interface Schema {
+    type: SchemaType;
+    children: Record<string, SchemaMap>;
+    elements: Record<string, SchemaElement>;
+    getValidStyles: () => Record<string, string[]> | undefined;
+    getValidClasses: () => Record<string, SchemaMap> | undefined;
+    getBlockElements: () => SchemaMap;
+    getInvalidStyles: () => Record<string, SchemaMap> | undefined;
+    getVoidElements: () => SchemaMap;
+    getTextBlockElements: () => SchemaMap;
+    getTextInlineElements: () => SchemaMap;
+    getBoolAttrs: () => SchemaMap;
+    getElementRule: (name: string) => SchemaElement | undefined;
+    getSelfClosingElements: () => SchemaMap;
+    getNonEmptyElements: () => SchemaMap;
+    getMoveCaretBeforeOnEnterElements: () => SchemaMap;
+    getWhitespaceElements: () => SchemaMap;
+    getTransparentElements: () => SchemaMap;
+    getSpecialElements: () => SchemaRegExpMap;
+    isValidChild: (name: string, child: string) => boolean;
+    isValid: (name: string, attr?: string) => boolean;
+    isBlock: (name: string) => boolean;
+    isInline: (name: string) => boolean;
+    isWrapper: (name: string) => boolean;
+    getCustomElements: () => SchemaMap;
+    addValidElements: (validElements: string) => void;
+    setValidElements: (validElements: string) => void;
+    addCustomElements: (customElements: string | Record<string, CustomElementSpec>) => void;
+    addValidChildren: (validChildren: any) => void;
+}
+type Attributes$1 = Array<{
+    name: string;
+    value: string;
+}> & {
+    map: Record<string, string>;
+};
+interface AstNodeConstructor {
+    readonly prototype: AstNode;
+    new (name: string, type: number): AstNode;
+    create(name: string, attrs?: Record<string, string>): AstNode;
+}
+declare class AstNode {
+    static create(name: string, attrs?: Record<string, string>): AstNode;
+    name: string;
+    type: number;
+    attributes?: Attributes$1;
+    value?: string;
+    parent?: AstNode | null;
+    firstChild?: AstNode | null;
+    lastChild?: AstNode | null;
+    next?: AstNode | null;
+    prev?: AstNode | null;
+    raw?: boolean;
+    constructor(name: string, type: number);
+    replace(node: AstNode): AstNode;
+    attr(name: string, value: string | null | undefined): AstNode | undefined;
+    attr(name: Record<string, string | null | undefined> | undefined): AstNode | undefined;
+    attr(name: string): string | undefined;
+    clone(): AstNode;
+    wrap(wrapper: AstNode): AstNode;
+    unwrap(): void;
+    remove(): AstNode;
+    append(node: AstNode): AstNode;
+    insert(node: AstNode, refNode: AstNode, before?: boolean): AstNode;
+    getAll(name: string): AstNode[];
+    children(): AstNode[];
+    empty(): AstNode;
+    isEmpty(elements: SchemaMap, whitespace?: SchemaMap, predicate?: (node: AstNode) => boolean): boolean;
+    walk(prev?: boolean): AstNode | null | undefined;
+}
+type Content = string | AstNode;
+type ContentFormat = 'raw' | 'text' | 'html' | 'tree';
+interface GetContentArgs {
+    format: ContentFormat;
+    get: boolean;
+    getInner: boolean;
+    no_events?: boolean;
+    save?: boolean;
+    source_view?: boolean;
+    [key: string]: any;
+}
+interface SetContentArgs {
+    format: string;
+    set: boolean;
+    content: Content;
+    no_events?: boolean;
+    no_selection?: boolean;
+    paste?: boolean;
+    load?: boolean;
+    initial?: boolean;
+    [key: string]: any;
+}
+interface GetSelectionContentArgs extends GetContentArgs {
+    selection?: boolean;
+    contextual?: boolean;
+}
+interface SetSelectionContentArgs extends SetContentArgs {
+    content: string;
+    selection?: boolean;
+}
+interface BlobInfoData {
+    id?: string;
+    name?: string;
+    filename?: string;
+    blob: Blob;
+    base64: string;
+    blobUri?: string;
+    uri?: string;
+}
+interface BlobInfo {
+    id: () => string;
+    name: () => string;
+    filename: () => string;
+    blob: () => Blob;
+    base64: () => string;
+    blobUri: () => string;
+    uri: () => string | undefined;
+}
+interface BlobCache {
+    create: {
+        (o: BlobInfoData): BlobInfo;
+        (id: string, blob: Blob, base64: string, name?: string, filename?: string): BlobInfo;
+    };
+    add: (blobInfo: BlobInfo) => void;
+    get: (id: string) => BlobInfo | undefined;
+    getByUri: (blobUri: string) => BlobInfo | undefined;
+    getByData: (base64: string, type: string) => BlobInfo | undefined;
+    findFirst: (predicate: (blobInfo: BlobInfo) => boolean) => BlobInfo | undefined;
+    removeByUri: (blobUri: string) => void;
+    destroy: () => void;
+}
+interface BlobInfoImagePair {
+    image: HTMLImageElement;
+    blobInfo: BlobInfo;
+}
+declare class NodeChange {
+    private readonly editor;
+    private lastPath;
+    constructor(editor: Editor);
+    nodeChanged(args?: Record<string, any>): void;
+    private isSameElementPath;
+}
+interface SelectionOverrides {
+    showCaret: (direction: number, node: HTMLElement, before: boolean, scrollIntoView?: boolean) => Range | null;
+    showBlockCaretContainer: (blockCaretContainer: HTMLElement) => void;
+    hideFakeCaret: () => void;
+    destroy: () => void;
+}
+interface Quirks {
+    refreshContentEditable(): void;
+    isHidden(): boolean;
+}
+type DecoratorData = Record<string, any>;
+type Decorator = (uid: string, data: DecoratorData) => {
+    attributes?: {};
+    classes?: string[];
+};
+type AnnotationListener = (state: boolean, name: string, data?: {
+    uid: string;
+    nodes: any[];
+}) => void;
+type AnnotationListenerApi = AnnotationListener;
+interface AnnotatorSettings {
+    decorate: Decorator;
+    persistent?: boolean;
+}
+interface Annotator {
+    register: (name: string, settings: AnnotatorSettings) => void;
+    annotate: (name: string, data: DecoratorData) => void;
+    annotationChanged: (name: string, f: AnnotationListenerApi) => void;
+    remove: (name: string) => void;
+    removeAll: (name: string) => void;
+    getAll: (name: string) => Record<string, Element[]>;
+}
+interface IsEmptyOptions {
+    readonly skipBogus?: boolean;
+    readonly includeZwsp?: boolean;
+    readonly checkRootAsContent?: boolean;
+    readonly isContent?: (node: Node) => boolean;
+}
+interface GeomRect {
+    readonly x: number;
+    readonly y: number;
+    readonly w: number;
+    readonly h: number;
+}
+interface Rect {
+    inflate: (rect: GeomRect, w: number, h: number) => GeomRect;
+    relativePosition: (rect: GeomRect, targetRect: GeomRect, rel: string) => GeomRect;
+    findBestRelativePosition: (rect: GeomRect, targetRect: GeomRect, constrainRect: GeomRect, rels: string[]) => string | null;
+    intersect: (rect: GeomRect, cropRect: GeomRect) => GeomRect | null;
+    clamp: (rect: GeomRect, clampRect: GeomRect, fixedSize?: boolean) => GeomRect;
+    create: (x: number, y: number, w: number, h: number) => GeomRect;
+    fromClientRect: (clientRect: DOMRect) => GeomRect;
+}
+interface NotificationManagerImpl {
+    open: (spec: NotificationSpec, closeCallback: () => void, hasEditorFocus: () => boolean) => NotificationApi;
+    close: <T extends NotificationApi>(notification: T) => void;
+    getArgs: <T extends NotificationApi>(notification: T) => NotificationSpec;
+}
+interface NotificationSpec {
+    type?: 'info' | 'warning' | 'error' | 'success';
+    text: string;
+    icon?: string;
+    progressBar?: boolean;
+    timeout?: number;
+}
+interface NotificationApi {
+    close: () => void;
+    progressBar: {
+        value: (percent: number) => void;
+    };
+    text: (text: string) => void;
+    reposition: () => void;
+    getEl: () => HTMLElement;
+    settings: NotificationSpec;
+}
+interface NotificationManager {
+    open: (spec: NotificationSpec) => NotificationApi;
+    close: () => void;
+    getNotifications: () => NotificationApi[];
+}
+interface UploadFailure {
+    message: string;
+    remove?: boolean;
+}
+type ProgressFn = (percent: number) => void;
+type UploadHandler = (blobInfo: BlobInfo, progress: ProgressFn) => Promise<string>;
+interface UploadResult$2 {
+    url: string;
+    blobInfo: BlobInfo;
+    status: boolean;
+    error?: UploadFailure;
+}
+type BlockPatternTrigger = 'enter' | 'space';
+interface RawPattern {
+    start?: any;
+    end?: any;
+    format?: any;
+    cmd?: any;
+    value?: any;
+    replacement?: any;
+    trigger?: BlockPatternTrigger;
+}
+interface InlineBasePattern {
+    readonly start: string;
+    readonly end: string;
+}
+interface InlineFormatPattern extends InlineBasePattern {
+    readonly type: 'inline-format';
+    readonly format: string[];
+}
+interface InlineCmdPattern extends InlineBasePattern {
+    readonly type: 'inline-command';
+    readonly cmd: string;
+    readonly value?: any;
+}
+type InlinePattern = InlineFormatPattern | InlineCmdPattern;
+interface BlockBasePattern {
+    readonly start: string;
+    readonly trigger: BlockPatternTrigger;
+}
+interface BlockFormatPattern extends BlockBasePattern {
+    readonly type: 'block-format';
+    readonly format: string;
+}
+interface BlockCmdPattern extends BlockBasePattern {
+    readonly type: 'block-command';
+    readonly cmd: string;
+    readonly value?: any;
+}
+type BlockPattern = BlockFormatPattern | BlockCmdPattern;
+type Pattern = InlinePattern | BlockPattern;
+interface DynamicPatternContext {
+    readonly text: string;
+    readonly block: Element;
+}
+type DynamicPatternsLookup = (ctx: DynamicPatternContext) => Pattern[];
+type RawDynamicPatternsLookup = (ctx: DynamicPatternContext) => RawPattern[];
+interface AlertBannerSpec {
+    type: 'alertbanner';
+    level: 'info' | 'warn' | 'error' | 'success';
+    text: string;
+    icon: string;
+    url?: string;
+}
+interface ButtonSpec {
+    type: 'button';
+    text: string;
+    enabled?: boolean;
+    primary?: boolean;
+    name?: string;
+    icon?: string;
+    borderless?: boolean;
+    buttonType?: 'primary' | 'secondary' | 'toolbar';
+}
+interface FormComponentSpec {
+    type: string;
+    name: string;
+}
+interface FormComponentWithLabelSpec extends FormComponentSpec {
+    label?: string;
+}
+interface CheckboxSpec extends FormComponentSpec {
+    type: 'checkbox';
+    label: string;
+    enabled?: boolean;
+}
+interface CollectionSpec extends FormComponentWithLabelSpec {
+    type: 'collection';
+}
+interface CollectionItem {
+    value: string;
+    text: string;
+    icon: string;
+}
+interface ColorInputSpec extends FormComponentWithLabelSpec {
+    type: 'colorinput';
+    storageKey?: string;
+}
+interface ColorPickerSpec extends FormComponentWithLabelSpec {
+    type: 'colorpicker';
+}
+interface CustomEditorInit {
+    setValue: (value: string) => void;
+    getValue: () => string;
+    destroy: () => void;
+}
+type CustomEditorInitFn = (elm: HTMLElement, settings: any) => Promise<CustomEditorInit>;
+interface CustomEditorOldSpec extends FormComponentSpec {
+    type: 'customeditor';
+    tag?: string;
+    init: (e: HTMLElement) => Promise<CustomEditorInit>;
+}
+interface CustomEditorNewSpec extends FormComponentSpec {
+    type: 'customeditor';
+    tag?: string;
+    scriptId: string;
+    scriptUrl: string;
+    onFocus?: (e: HTMLElement) => void;
+    settings?: any;
+}
+type CustomEditorSpec = CustomEditorOldSpec | CustomEditorNewSpec;
+interface DropZoneSpec extends FormComponentWithLabelSpec {
+    type: 'dropzone';
+}
+interface GridSpec {
+    type: 'grid';
+    columns: number;
+    items: BodyComponentSpec[];
+}
+interface HtmlPanelSpec {
+    type: 'htmlpanel';
+    html: string;
+    onInit?: (el: HTMLElement) => void;
+    presets?: 'presentation' | 'document';
+    stretched?: boolean;
+}
+interface IframeSpec extends FormComponentWithLabelSpec {
+    type: 'iframe';
+    border?: boolean;
+    sandboxed?: boolean;
+    streamContent?: boolean;
+    transparent?: boolean;
+}
+interface ImagePreviewSpec extends FormComponentSpec {
+    type: 'imagepreview';
+    height?: string;
+}
+interface InputSpec extends FormComponentWithLabelSpec {
+    type: 'input';
+    inputMode?: string;
+    placeholder?: string;
+    maximized?: boolean;
+    enabled?: boolean;
+}
+type Alignment = 'start' | 'center' | 'end';
+interface LabelSpec {
+    type: 'label';
+    label: string;
+    items: BodyComponentSpec[];
+    align?: Alignment;
+    for?: string;
+}
+interface ListBoxSingleItemSpec {
+    text: string;
+    value: string;
+}
+interface ListBoxNestedItemSpec {
+    text: string;
+    items: ListBoxItemSpec[];
+}
+type ListBoxItemSpec = ListBoxNestedItemSpec | ListBoxSingleItemSpec;
+interface ListBoxSpec extends FormComponentWithLabelSpec {
+    type: 'listbox';
+    items: ListBoxItemSpec[];
+    disabled?: boolean;
+}
+interface PanelSpec {
+    type: 'panel';
+    classes?: string[];
+    items: BodyComponentSpec[];
+}
+interface SelectBoxItemSpec {
+    text: string;
+    value: string;
+}
+interface SelectBoxSpec extends FormComponentWithLabelSpec {
+    type: 'selectbox';
+    items: SelectBoxItemSpec[];
+    size?: number;
+    enabled?: boolean;
+}
+interface SizeInputSpec extends FormComponentWithLabelSpec {
+    type: 'sizeinput';
+    constrain?: boolean;
+    enabled?: boolean;
+}
+interface SliderSpec extends FormComponentSpec {
+    type: 'slider';
+    label: string;
+    min?: number;
+    max?: number;
+}
+interface TableSpec {
+    type: 'table';
+    header: string[];
+    cells: string[][];
+}
+interface TextAreaSpec extends FormComponentWithLabelSpec {
+    type: 'textarea';
+    placeholder?: string;
+    maximized?: boolean;
+    enabled?: boolean;
+}
+interface BaseToolbarButtonSpec<I extends BaseToolbarButtonInstanceApi> {
+    enabled?: boolean;
+    tooltip?: string;
+    icon?: string;
+    text?: string;
+    onSetup?: (api: I) => (api: I) => void;
+}
+interface BaseToolbarButtonInstanceApi {
+    isEnabled: () => boolean;
+    setEnabled: (state: boolean) => void;
+    setText: (text: string) => void;
+    setIcon: (icon: string) => void;
+}
+interface ToolbarButtonSpec extends BaseToolbarButtonSpec<ToolbarButtonInstanceApi> {
+    type?: 'button';
+    onAction: (api: ToolbarButtonInstanceApi) => void;
+    shortcut?: string;
+}
+interface ToolbarButtonInstanceApi extends BaseToolbarButtonInstanceApi {
+}
+interface ToolbarGroupSetting {
+    name: string;
+    items: string[];
+}
+type ToolbarConfig = string | ToolbarGroupSetting[];
+interface GroupToolbarButtonInstanceApi extends BaseToolbarButtonInstanceApi {
+}
+interface GroupToolbarButtonSpec extends BaseToolbarButtonSpec<GroupToolbarButtonInstanceApi> {
+    type?: 'grouptoolbarbutton';
+    items?: ToolbarConfig;
+}
+interface CardImageSpec {
+    type: 'cardimage';
+    src: string;
+    alt?: string;
+    classes?: string[];
+}
+interface CardTextSpec {
+    type: 'cardtext';
+    text: string;
+    name?: string;
+    classes?: string[];
+}
+type CardItemSpec = CardContainerSpec | CardImageSpec | CardTextSpec;
+type CardContainerDirection = 'vertical' | 'horizontal';
+type CardContainerAlign = 'left' | 'right';
+type CardContainerValign = 'top' | 'middle' | 'bottom';
+interface CardContainerSpec {
+    type: 'cardcontainer';
+    items: CardItemSpec[];
+    direction?: CardContainerDirection;
+    align?: CardContainerAlign;
+    valign?: CardContainerValign;
+}
+interface CommonMenuItemSpec {
+    enabled?: boolean;
+    text?: string;
+    value?: string;
+    meta?: Record<string, any>;
+    shortcut?: string;
+}
+interface CommonMenuItemInstanceApi {
+    isEnabled: () => boolean;
+    setEnabled: (state: boolean) => void;
+}
+interface CardMenuItemInstanceApi extends CommonMenuItemInstanceApi {
+}
+interface CardMenuItemSpec extends Omit<CommonMenuItemSpec, 'text' | 'shortcut'> {
+    type: 'cardmenuitem';
+    label?: string;
+    items: CardItemSpec[];
+    onSetup?: (api: CardMenuItemInstanceApi) => (api: CardMenuItemInstanceApi) => void;
+    onAction?: (api: CardMenuItemInstanceApi) => void;
+}
+interface ChoiceMenuItemSpec extends CommonMenuItemSpec {
+    type?: 'choiceitem';
+    icon?: string;
+}
+interface ChoiceMenuItemInstanceApi extends CommonMenuItemInstanceApi {
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+}
+interface ContextMenuItem extends CommonMenuItemSpec {
+    text: string;
+    icon?: string;
+    type?: 'item';
+    onAction: () => void;
+}
+interface ContextSubMenu extends CommonMenuItemSpec {
+    type: 'submenu';
+    text: string;
+    icon?: string;
+    getSubmenuItems: () => string | Array<ContextMenuContents>;
+}
+type ContextMenuContents = string | ContextMenuItem | SeparatorMenuItemSpec | ContextSubMenu;
+interface ContextMenuApi {
+    update: (element: Element) => string | Array<ContextMenuContents>;
+}
+interface FancyActionArgsMap {
+    'inserttable': {
+        numRows: number;
+        numColumns: number;
+    };
+    'colorswatch': {
+        value: string;
+    };
+}
+interface BaseFancyMenuItemSpec<T extends keyof FancyActionArgsMap> {
+    type: 'fancymenuitem';
+    fancytype: T;
+    initData?: Record<string, unknown>;
+    onAction?: (data: FancyActionArgsMap[T]) => void;
+}
+interface InsertTableMenuItemSpec extends BaseFancyMenuItemSpec<'inserttable'> {
+    fancytype: 'inserttable';
+    initData?: {};
+}
+interface ColorSwatchMenuItemSpec extends BaseFancyMenuItemSpec<'colorswatch'> {
+    fancytype: 'colorswatch';
+    select?: (value: string) => boolean;
+    initData?: {
+        allowCustomColors?: boolean;
+        colors?: ChoiceMenuItemSpec[];
+        storageKey?: string;
+    };
+}
+type FancyMenuItemSpec = InsertTableMenuItemSpec | ColorSwatchMenuItemSpec;
+interface MenuItemSpec extends CommonMenuItemSpec {
+    type?: 'menuitem';
+    icon?: string;
+    onSetup?: (api: MenuItemInstanceApi) => (api: MenuItemInstanceApi) => void;
+    onAction?: (api: MenuItemInstanceApi) => void;
+}
+interface MenuItemInstanceApi extends CommonMenuItemInstanceApi {
+}
+interface SeparatorMenuItemSpec {
+    type?: 'separator';
+    text?: string;
+}
+interface ToggleMenuItemSpec extends CommonMenuItemSpec {
+    type?: 'togglemenuitem';
+    icon?: string;
+    active?: boolean;
+    onSetup?: (api: ToggleMenuItemInstanceApi) => void;
+    onAction: (api: ToggleMenuItemInstanceApi) => void;
+}
+interface ToggleMenuItemInstanceApi extends CommonMenuItemInstanceApi {
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+}
+type NestedMenuItemContents = string | MenuItemSpec | NestedMenuItemSpec | ToggleMenuItemSpec | SeparatorMenuItemSpec | FancyMenuItemSpec;
+interface NestedMenuItemSpec extends CommonMenuItemSpec {
+    type?: 'nestedmenuitem';
+    icon?: string;
+    getSubmenuItems: () => string | Array<NestedMenuItemContents>;
+    onSetup?: (api: NestedMenuItemInstanceApi) => (api: NestedMenuItemInstanceApi) => void;
+}
+interface NestedMenuItemInstanceApi extends CommonMenuItemInstanceApi {
+    setTooltip: (tooltip: string) => void;
+    setIconFill: (id: string, value: string) => void;
+}
+type MenuButtonItemTypes = NestedMenuItemContents;
+type SuccessCallback$1 = (menu: string | MenuButtonItemTypes[]) => void;
+interface MenuButtonFetchContext {
+    pattern: string;
+}
+interface BaseMenuButtonSpec {
+    text?: string;
+    tooltip?: string;
+    icon?: string;
+    search?: boolean | {
+        placeholder?: string;
+    };
+    fetch: (success: SuccessCallback$1, fetchContext: MenuButtonFetchContext, api: BaseMenuButtonInstanceApi) => void;
+    onSetup?: (api: BaseMenuButtonInstanceApi) => (api: BaseMenuButtonInstanceApi) => void;
+}
+interface BaseMenuButtonInstanceApi {
+    isEnabled: () => boolean;
+    setEnabled: (state: boolean) => void;
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+    setText: (text: string) => void;
+    setIcon: (icon: string) => void;
+}
+interface ToolbarMenuButtonSpec extends BaseMenuButtonSpec {
+    type?: 'menubutton';
+    onSetup?: (api: ToolbarMenuButtonInstanceApi) => (api: ToolbarMenuButtonInstanceApi) => void;
+}
+interface ToolbarMenuButtonInstanceApi extends BaseMenuButtonInstanceApi {
+}
+type ToolbarSplitButtonItemTypes = ChoiceMenuItemSpec | SeparatorMenuItemSpec;
+type SuccessCallback = (menu: ToolbarSplitButtonItemTypes[]) => void;
+type SelectPredicate = (value: string) => boolean;
+type PresetTypes = 'color' | 'normal' | 'listpreview';
+type ColumnTypes$1 = number | 'auto';
+interface ToolbarSplitButtonSpec {
+    type?: 'splitbutton';
+    tooltip?: string;
+    icon?: string;
+    text?: string;
+    select?: SelectPredicate;
+    presets?: PresetTypes;
+    columns?: ColumnTypes$1;
+    fetch: (success: SuccessCallback) => void;
+    onSetup?: (api: ToolbarSplitButtonInstanceApi) => (api: ToolbarSplitButtonInstanceApi) => void;
+    onAction: (api: ToolbarSplitButtonInstanceApi) => void;
+    onItemAction: (api: ToolbarSplitButtonInstanceApi, value: string) => void;
+}
+interface ToolbarSplitButtonInstanceApi {
+    isEnabled: () => boolean;
+    setEnabled: (state: boolean) => void;
+    setIconFill: (id: string, value: string) => void;
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+    setTooltip: (tooltip: string) => void;
+    setText: (text: string) => void;
+    setIcon: (icon: string) => void;
+}
+interface BaseToolbarToggleButtonSpec<I extends BaseToolbarButtonInstanceApi> extends BaseToolbarButtonSpec<I> {
+    active?: boolean;
+}
+interface BaseToolbarToggleButtonInstanceApi extends BaseToolbarButtonInstanceApi {
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+}
+interface ToolbarToggleButtonSpec extends BaseToolbarToggleButtonSpec<ToolbarToggleButtonInstanceApi> {
+    type?: 'togglebutton';
+    onAction: (api: ToolbarToggleButtonInstanceApi) => void;
+    shortcut?: string;
+}
+interface ToolbarToggleButtonInstanceApi extends BaseToolbarToggleButtonInstanceApi {
+}
+type Id = string;
+interface TreeSpec {
+    type: 'tree';
+    items: TreeItemSpec[];
+    onLeafAction?: (id: Id) => void;
+    defaultExpandedIds?: Id[];
+    onToggleExpand?: (expandedIds: Id[], { expanded, node }: {
+        expanded: boolean;
+        node: Id;
+    }) => void;
+    defaultSelectedId?: Id;
+}
+interface BaseTreeItemSpec {
+    title: string;
+    id: Id;
+    menu?: ToolbarMenuButtonSpec;
+}
+interface DirectorySpec extends BaseTreeItemSpec {
+    type: 'directory';
+    children: TreeItemSpec[];
+}
+interface LeafSpec extends BaseTreeItemSpec {
+    type: 'leaf';
+}
+type TreeItemSpec = DirectorySpec | LeafSpec;
+interface UrlInputSpec extends FormComponentWithLabelSpec {
+    type: 'urlinput';
+    filetype?: 'image' | 'media' | 'file';
+    enabled?: boolean;
+    picker_text?: string;
+}
+interface UrlInputData {
+    value: string;
+    meta: {
+        text?: string;
+    };
+}
+type BodyComponentSpec = BarSpec | ButtonSpec | CheckboxSpec | TextAreaSpec | InputSpec | ListBoxSpec | SelectBoxSpec | SizeInputSpec | SliderSpec | IframeSpec | HtmlPanelSpec | UrlInputSpec | DropZoneSpec | ColorInputSpec | GridSpec | ColorPickerSpec | ImagePreviewSpec | AlertBannerSpec | CollectionSpec | LabelSpec | TableSpec | TreeSpec | PanelSpec | CustomEditorSpec;
+interface BarSpec {
+    type: 'bar';
+    items: BodyComponentSpec[];
+}
+interface DialogToggleMenuItemSpec extends CommonMenuItemSpec {
+    type?: 'togglemenuitem';
+    name: string;
+}
+type DialogFooterMenuButtonItemSpec = DialogToggleMenuItemSpec;
+interface BaseDialogFooterButtonSpec {
+    name?: string;
+    align?: 'start' | 'end';
+    primary?: boolean;
+    enabled?: boolean;
+    icon?: string;
+    buttonType?: 'primary' | 'secondary';
+}
+interface DialogFooterNormalButtonSpec extends BaseDialogFooterButtonSpec {
+    type: 'submit' | 'cancel' | 'custom';
+    text: string;
+}
+interface DialogFooterMenuButtonSpec extends BaseDialogFooterButtonSpec {
+    type: 'menu';
+    text?: string;
+    tooltip?: string;
+    icon?: string;
+    items: DialogFooterMenuButtonItemSpec[];
+}
+interface DialogFooterToggleButtonSpec extends BaseDialogFooterButtonSpec {
+    type: 'togglebutton';
+    tooltip?: string;
+    icon?: string;
+    text?: string;
+    active?: boolean;
+}
+type DialogFooterButtonSpec = DialogFooterNormalButtonSpec | DialogFooterMenuButtonSpec | DialogFooterToggleButtonSpec;
+interface TabSpec {
+    name?: string;
+    title: string;
+    items: BodyComponentSpec[];
+}
+interface TabPanelSpec {
+    type: 'tabpanel';
+    tabs: TabSpec[];
+}
+type DialogDataItem = any;
+type DialogData = Record<string, DialogDataItem>;
+interface DialogInstanceApi<T extends DialogData> {
+    getData: () => T;
+    setData: (data: Partial<T>) => void;
+    setEnabled: (name: string, state: boolean) => void;
+    focus: (name: string) => void;
+    showTab: (name: string) => void;
+    redial: (nu: DialogSpec<T>) => void;
+    block: (msg: string) => void;
+    unblock: () => void;
+    toggleFullscreen: () => void;
+    close: () => void;
+}
+interface DialogActionDetails {
+    name: string;
+    value?: any;
+}
+interface DialogChangeDetails<T> {
+    name: keyof T;
+}
+interface DialogTabChangeDetails {
+    newTabName: string;
+    oldTabName: string;
+}
+type DialogActionHandler<T extends DialogData> = (api: DialogInstanceApi<T>, details: DialogActionDetails) => void;
+type DialogChangeHandler<T extends DialogData> = (api: DialogInstanceApi<T>, details: DialogChangeDetails<T>) => void;
+type DialogSubmitHandler<T extends DialogData> = (api: DialogInstanceApi<T>) => void;
+type DialogCloseHandler = () => void;
+type DialogCancelHandler<T extends DialogData> = (api: DialogInstanceApi<T>) => void;
+type DialogTabChangeHandler<T extends DialogData> = (api: DialogInstanceApi<T>, details: DialogTabChangeDetails) => void;
+type DialogSize = 'normal' | 'medium' | 'large';
+interface DialogSpec<T extends DialogData> {
+    title: string;
+    size?: DialogSize;
+    body: TabPanelSpec | PanelSpec;
+    buttons?: DialogFooterButtonSpec[];
+    initialData?: Partial<T>;
+    onAction?: DialogActionHandler<T>;
+    onChange?: DialogChangeHandler<T>;
+    onSubmit?: DialogSubmitHandler<T>;
+    onClose?: DialogCloseHandler;
+    onCancel?: DialogCancelHandler<T>;
+    onTabChange?: DialogTabChangeHandler<T>;
+}
+interface UrlDialogInstanceApi {
+    block: (msg: string) => void;
+    unblock: () => void;
+    close: () => void;
+    sendMessage: (msg: any) => void;
+}
+interface UrlDialogActionDetails {
+    name: string;
+    value?: any;
+}
+interface UrlDialogMessage {
+    mceAction: string;
+    [key: string]: any;
+}
+type UrlDialogActionHandler = (api: UrlDialogInstanceApi, actions: UrlDialogActionDetails) => void;
+type UrlDialogCloseHandler = () => void;
+type UrlDialogCancelHandler = (api: UrlDialogInstanceApi) => void;
+type UrlDialogMessageHandler = (api: UrlDialogInstanceApi, message: UrlDialogMessage) => void;
+interface UrlDialogFooterButtonSpec extends DialogFooterNormalButtonSpec {
+    type: 'cancel' | 'custom';
+}
+interface UrlDialogSpec {
+    title: string;
+    url: string;
+    height?: number;
+    width?: number;
+    buttons?: UrlDialogFooterButtonSpec[];
+    onAction?: UrlDialogActionHandler;
+    onClose?: UrlDialogCloseHandler;
+    onCancel?: UrlDialogCancelHandler;
+    onMessage?: UrlDialogMessageHandler;
+}
+type ColumnTypes = number | 'auto';
+type SeparatorItemSpec = SeparatorMenuItemSpec;
+interface AutocompleterItemSpec {
+    type?: 'autocompleteitem';
+    value: string;
+    text?: string;
+    icon?: string;
+    meta?: Record<string, any>;
+}
+type AutocompleterContents = SeparatorItemSpec | AutocompleterItemSpec | CardMenuItemSpec;
+interface AutocompleterSpec {
+    type?: 'autocompleter';
+    trigger: string;
+    minChars?: number;
+    columns?: ColumnTypes;
+    matches?: (rng: Range, text: string, pattern: string) => boolean;
+    fetch: (pattern: string, maxResults: number, fetchOptions: Record<string, any>) => Promise<AutocompleterContents[]>;
+    onAction: (autocompleterApi: AutocompleterInstanceApi, rng: Range, value: string, meta: Record<string, any>) => void;
+    maxResults?: number;
+    highlightOn?: string[];
+}
+interface AutocompleterInstanceApi {
+    hide: () => void;
+    reload: (fetchOptions: Record<string, any>) => void;
+}
+type ContextPosition = 'node' | 'selection' | 'line';
+type ContextScope = 'node' | 'editor';
+interface ContextBarSpec {
+    predicate?: (elem: Element) => boolean;
+    position?: ContextPosition;
+    scope?: ContextScope;
+}
+interface ContextFormLaunchButtonApi extends BaseToolbarButtonSpec<BaseToolbarButtonInstanceApi> {
+    type: 'contextformbutton';
+}
+interface ContextFormLaunchToggleButtonSpec extends BaseToolbarToggleButtonSpec<BaseToolbarToggleButtonInstanceApi> {
+    type: 'contextformtogglebutton';
+}
+interface ContextFormButtonInstanceApi extends BaseToolbarButtonInstanceApi {
+}
+interface ContextFormToggleButtonInstanceApi extends BaseToolbarToggleButtonInstanceApi {
+}
+interface ContextFormButtonSpec extends BaseToolbarButtonSpec<ContextFormButtonInstanceApi> {
+    type?: 'contextformbutton';
+    primary?: boolean;
+    onAction: (formApi: ContextFormInstanceApi, api: ContextFormButtonInstanceApi) => void;
+}
+interface ContextFormToggleButtonSpec extends BaseToolbarToggleButtonSpec<ContextFormToggleButtonInstanceApi> {
+    type?: 'contextformtogglebutton';
+    onAction: (formApi: ContextFormInstanceApi, buttonApi: ContextFormToggleButtonInstanceApi) => void;
+    primary?: boolean;
+}
+interface ContextFormInstanceApi {
+    hide: () => void;
+    getValue: () => string;
+}
+interface ContextFormSpec extends ContextBarSpec {
+    type?: 'contextform';
+    initValue?: () => string;
+    label?: string;
+    launch?: ContextFormLaunchButtonApi | ContextFormLaunchToggleButtonSpec;
+    commands: Array<ContextFormToggleButtonSpec | ContextFormButtonSpec>;
+}
+interface ContextToolbarSpec extends ContextBarSpec {
+    type?: 'contexttoolbar';
+    items: string;
+}
+type PublicDialog_d_AlertBannerSpec = AlertBannerSpec;
+type PublicDialog_d_BarSpec = BarSpec;
+type PublicDialog_d_BodyComponentSpec = BodyComponentSpec;
+type PublicDialog_d_ButtonSpec = ButtonSpec;
+type PublicDialog_d_CheckboxSpec = CheckboxSpec;
+type PublicDialog_d_CollectionItem = CollectionItem;
+type PublicDialog_d_CollectionSpec = CollectionSpec;
+type PublicDialog_d_ColorInputSpec = ColorInputSpec;
+type PublicDialog_d_ColorPickerSpec = ColorPickerSpec;
+type PublicDialog_d_CustomEditorSpec = CustomEditorSpec;
+type PublicDialog_d_CustomEditorInit = CustomEditorInit;
+type PublicDialog_d_CustomEditorInitFn = CustomEditorInitFn;
+type PublicDialog_d_DialogData = DialogData;
+type PublicDialog_d_DialogSize = DialogSize;
+type PublicDialog_d_DialogSpec<T extends DialogData> = DialogSpec<T>;
+type PublicDialog_d_DialogInstanceApi<T extends DialogData> = DialogInstanceApi<T>;
+type PublicDialog_d_DialogFooterButtonSpec = DialogFooterButtonSpec;
+type PublicDialog_d_DialogActionDetails = DialogActionDetails;
+type PublicDialog_d_DialogChangeDetails<T> = DialogChangeDetails<T>;
+type PublicDialog_d_DialogTabChangeDetails = DialogTabChangeDetails;
+type PublicDialog_d_DropZoneSpec = DropZoneSpec;
+type PublicDialog_d_GridSpec = GridSpec;
+type PublicDialog_d_HtmlPanelSpec = HtmlPanelSpec;
+type PublicDialog_d_IframeSpec = IframeSpec;
+type PublicDialog_d_ImagePreviewSpec = ImagePreviewSpec;
+type PublicDialog_d_InputSpec = InputSpec;
+type PublicDialog_d_LabelSpec = LabelSpec;
+type PublicDialog_d_ListBoxSpec = ListBoxSpec;
+type PublicDialog_d_ListBoxItemSpec = ListBoxItemSpec;
+type PublicDialog_d_ListBoxNestedItemSpec = ListBoxNestedItemSpec;
+type PublicDialog_d_ListBoxSingleItemSpec = ListBoxSingleItemSpec;
+type PublicDialog_d_PanelSpec = PanelSpec;
+type PublicDialog_d_SelectBoxSpec = SelectBoxSpec;
+type PublicDialog_d_SelectBoxItemSpec = SelectBoxItemSpec;
+type PublicDialog_d_SizeInputSpec = SizeInputSpec;
+type PublicDialog_d_SliderSpec = SliderSpec;
+type PublicDialog_d_TableSpec = TableSpec;
+type PublicDialog_d_TabSpec = TabSpec;
+type PublicDialog_d_TabPanelSpec = TabPanelSpec;
+type PublicDialog_d_TextAreaSpec = TextAreaSpec;
+type PublicDialog_d_TreeSpec = TreeSpec;
+type PublicDialog_d_TreeItemSpec = TreeItemSpec;
+type PublicDialog_d_UrlInputData = UrlInputData;
+type PublicDialog_d_UrlInputSpec = UrlInputSpec;
+type PublicDialog_d_UrlDialogSpec = UrlDialogSpec;
+type PublicDialog_d_UrlDialogFooterButtonSpec = UrlDialogFooterButtonSpec;
+type PublicDialog_d_UrlDialogInstanceApi = UrlDialogInstanceApi;
+type PublicDialog_d_UrlDialogActionDetails = UrlDialogActionDetails;
+type PublicDialog_d_UrlDialogMessage = UrlDialogMessage;
+declare namespace PublicDialog_d {
+    export { PublicDialog_d_AlertBannerSpec as AlertBannerSpec, PublicDialog_d_BarSpec as BarSpec, PublicDialog_d_BodyComponentSpec as BodyComponentSpec, PublicDialog_d_ButtonSpec as ButtonSpec, PublicDialog_d_CheckboxSpec as CheckboxSpec, PublicDialog_d_CollectionItem as CollectionItem, PublicDialog_d_CollectionSpec as CollectionSpec, PublicDialog_d_ColorInputSpec as ColorInputSpec, PublicDialog_d_ColorPickerSpec as ColorPickerSpec, PublicDialog_d_CustomEditorSpec as CustomEditorSpec, PublicDialog_d_CustomEditorInit as CustomEditorInit, PublicDialog_d_CustomEditorInitFn as CustomEditorInitFn, PublicDialog_d_DialogData as DialogData, PublicDialog_d_DialogSize as DialogSize, PublicDialog_d_DialogSpec as DialogSpec, PublicDialog_d_DialogInstanceApi as DialogInstanceApi, PublicDialog_d_DialogFooterButtonSpec as DialogFooterButtonSpec, PublicDialog_d_DialogActionDetails as DialogActionDetails, PublicDialog_d_DialogChangeDetails as DialogChangeDetails, PublicDialog_d_DialogTabChangeDetails as DialogTabChangeDetails, PublicDialog_d_DropZoneSpec as DropZoneSpec, PublicDialog_d_GridSpec as GridSpec, PublicDialog_d_HtmlPanelSpec as HtmlPanelSpec, PublicDialog_d_IframeSpec as IframeSpec, PublicDialog_d_ImagePreviewSpec as ImagePreviewSpec, PublicDialog_d_InputSpec as InputSpec, PublicDialog_d_LabelSpec as LabelSpec, PublicDialog_d_ListBoxSpec as ListBoxSpec, PublicDialog_d_ListBoxItemSpec as ListBoxItemSpec, PublicDialog_d_ListBoxNestedItemSpec as ListBoxNestedItemSpec, PublicDialog_d_ListBoxSingleItemSpec as ListBoxSingleItemSpec, PublicDialog_d_PanelSpec as PanelSpec, PublicDialog_d_SelectBoxSpec as SelectBoxSpec, PublicDialog_d_SelectBoxItemSpec as SelectBoxItemSpec, PublicDialog_d_SizeInputSpec as SizeInputSpec, PublicDialog_d_SliderSpec as SliderSpec, PublicDialog_d_TableSpec as TableSpec, PublicDialog_d_TabSpec as TabSpec, PublicDialog_d_TabPanelSpec as TabPanelSpec, PublicDialog_d_TextAreaSpec as TextAreaSpec, PublicDialog_d_TreeSpec as TreeSpec, PublicDialog_d_TreeItemSpec as TreeItemSpec, DirectorySpec as TreeDirectorySpec, LeafSpec as TreeLeafSpec, PublicDialog_d_UrlInputData as UrlInputData, PublicDialog_d_UrlInputSpec as UrlInputSpec, PublicDialog_d_UrlDialogSpec as UrlDialogSpec, PublicDialog_d_UrlDialogFooterButtonSpec as UrlDialogFooterButtonSpec, PublicDialog_d_UrlDialogInstanceApi as UrlDialogInstanceApi, PublicDialog_d_UrlDialogActionDetails as UrlDialogActionDetails, PublicDialog_d_UrlDialogMessage as UrlDialogMessage, };
+}
+type PublicInlineContent_d_AutocompleterSpec = AutocompleterSpec;
+type PublicInlineContent_d_AutocompleterItemSpec = AutocompleterItemSpec;
+type PublicInlineContent_d_AutocompleterContents = AutocompleterContents;
+type PublicInlineContent_d_AutocompleterInstanceApi = AutocompleterInstanceApi;
+type PublicInlineContent_d_ContextPosition = ContextPosition;
+type PublicInlineContent_d_ContextScope = ContextScope;
+type PublicInlineContent_d_ContextFormSpec = ContextFormSpec;
+type PublicInlineContent_d_ContextFormInstanceApi = ContextFormInstanceApi;
+type PublicInlineContent_d_ContextFormButtonSpec = ContextFormButtonSpec;
+type PublicInlineContent_d_ContextFormButtonInstanceApi = ContextFormButtonInstanceApi;
+type PublicInlineContent_d_ContextFormToggleButtonSpec = ContextFormToggleButtonSpec;
+type PublicInlineContent_d_ContextFormToggleButtonInstanceApi = ContextFormToggleButtonInstanceApi;
+type PublicInlineContent_d_ContextToolbarSpec = ContextToolbarSpec;
+type PublicInlineContent_d_SeparatorItemSpec = SeparatorItemSpec;
+declare namespace PublicInlineContent_d {
+    export { PublicInlineContent_d_AutocompleterSpec as AutocompleterSpec, PublicInlineContent_d_AutocompleterItemSpec as AutocompleterItemSpec, PublicInlineContent_d_AutocompleterContents as AutocompleterContents, PublicInlineContent_d_AutocompleterInstanceApi as AutocompleterInstanceApi, PublicInlineContent_d_ContextPosition as ContextPosition, PublicInlineContent_d_ContextScope as ContextScope, PublicInlineContent_d_ContextFormSpec as ContextFormSpec, PublicInlineContent_d_ContextFormInstanceApi as ContextFormInstanceApi, PublicInlineContent_d_ContextFormButtonSpec as ContextFormButtonSpec, PublicInlineContent_d_ContextFormButtonInstanceApi as ContextFormButtonInstanceApi, PublicInlineContent_d_ContextFormToggleButtonSpec as ContextFormToggleButtonSpec, PublicInlineContent_d_ContextFormToggleButtonInstanceApi as ContextFormToggleButtonInstanceApi, PublicInlineContent_d_ContextToolbarSpec as ContextToolbarSpec, PublicInlineContent_d_SeparatorItemSpec as SeparatorItemSpec, };
+}
+type PublicMenu_d_MenuItemSpec = MenuItemSpec;
+type PublicMenu_d_MenuItemInstanceApi = MenuItemInstanceApi;
+type PublicMenu_d_NestedMenuItemContents = NestedMenuItemContents;
+type PublicMenu_d_NestedMenuItemSpec = NestedMenuItemSpec;
+type PublicMenu_d_NestedMenuItemInstanceApi = NestedMenuItemInstanceApi;
+type PublicMenu_d_FancyMenuItemSpec = FancyMenuItemSpec;
+type PublicMenu_d_ColorSwatchMenuItemSpec = ColorSwatchMenuItemSpec;
+type PublicMenu_d_InsertTableMenuItemSpec = InsertTableMenuItemSpec;
+type PublicMenu_d_ToggleMenuItemSpec = ToggleMenuItemSpec;
+type PublicMenu_d_ToggleMenuItemInstanceApi = ToggleMenuItemInstanceApi;
+type PublicMenu_d_ChoiceMenuItemSpec = ChoiceMenuItemSpec;
+type PublicMenu_d_ChoiceMenuItemInstanceApi = ChoiceMenuItemInstanceApi;
+type PublicMenu_d_SeparatorMenuItemSpec = SeparatorMenuItemSpec;
+type PublicMenu_d_ContextMenuApi = ContextMenuApi;
+type PublicMenu_d_ContextMenuContents = ContextMenuContents;
+type PublicMenu_d_ContextMenuItem = ContextMenuItem;
+type PublicMenu_d_ContextSubMenu = ContextSubMenu;
+type PublicMenu_d_CardMenuItemSpec = CardMenuItemSpec;
+type PublicMenu_d_CardMenuItemInstanceApi = CardMenuItemInstanceApi;
+type PublicMenu_d_CardItemSpec = CardItemSpec;
+type PublicMenu_d_CardContainerSpec = CardContainerSpec;
+type PublicMenu_d_CardImageSpec = CardImageSpec;
+type PublicMenu_d_CardTextSpec = CardTextSpec;
+declare namespace PublicMenu_d {
+    export { PublicMenu_d_MenuItemSpec as MenuItemSpec, PublicMenu_d_MenuItemInstanceApi as MenuItemInstanceApi, PublicMenu_d_NestedMenuItemContents as NestedMenuItemContents, PublicMenu_d_NestedMenuItemSpec as NestedMenuItemSpec, PublicMenu_d_NestedMenuItemInstanceApi as NestedMenuItemInstanceApi, PublicMenu_d_FancyMenuItemSpec as FancyMenuItemSpec, PublicMenu_d_ColorSwatchMenuItemSpec as ColorSwatchMenuItemSpec, PublicMenu_d_InsertTableMenuItemSpec as InsertTableMenuItemSpec, PublicMenu_d_ToggleMenuItemSpec as ToggleMenuItemSpec, PublicMenu_d_ToggleMenuItemInstanceApi as ToggleMenuItemInstanceApi, PublicMenu_d_ChoiceMenuItemSpec as ChoiceMenuItemSpec, PublicMenu_d_ChoiceMenuItemInstanceApi as ChoiceMenuItemInstanceApi, PublicMenu_d_SeparatorMenuItemSpec as SeparatorMenuItemSpec, PublicMenu_d_ContextMenuApi as ContextMenuApi, PublicMenu_d_ContextMenuContents as ContextMenuContents, PublicMenu_d_ContextMenuItem as ContextMenuItem, PublicMenu_d_ContextSubMenu as ContextSubMenu, PublicMenu_d_CardMenuItemSpec as CardMenuItemSpec, PublicMenu_d_CardMenuItemInstanceApi as CardMenuItemInstanceApi, PublicMenu_d_CardItemSpec as CardItemSpec, PublicMenu_d_CardContainerSpec as CardContainerSpec, PublicMenu_d_CardImageSpec as CardImageSpec, PublicMenu_d_CardTextSpec as CardTextSpec, };
+}
+interface SidebarInstanceApi {
+    element: () => HTMLElement;
+}
+interface SidebarSpec {
+    icon?: string;
+    tooltip?: string;
+    onShow?: (api: SidebarInstanceApi) => void;
+    onSetup?: (api: SidebarInstanceApi) => (api: SidebarInstanceApi) => void;
+    onHide?: (api: SidebarInstanceApi) => void;
+}
+type PublicSidebar_d_SidebarSpec = SidebarSpec;
+type PublicSidebar_d_SidebarInstanceApi = SidebarInstanceApi;
+declare namespace PublicSidebar_d {
+    export { PublicSidebar_d_SidebarSpec as SidebarSpec, PublicSidebar_d_SidebarInstanceApi as SidebarInstanceApi, };
+}
+type PublicToolbar_d_ToolbarButtonSpec = ToolbarButtonSpec;
+type PublicToolbar_d_ToolbarButtonInstanceApi = ToolbarButtonInstanceApi;
+type PublicToolbar_d_ToolbarSplitButtonSpec = ToolbarSplitButtonSpec;
+type PublicToolbar_d_ToolbarSplitButtonInstanceApi = ToolbarSplitButtonInstanceApi;
+type PublicToolbar_d_ToolbarMenuButtonSpec = ToolbarMenuButtonSpec;
+type PublicToolbar_d_ToolbarMenuButtonInstanceApi = ToolbarMenuButtonInstanceApi;
+type PublicToolbar_d_ToolbarToggleButtonSpec = ToolbarToggleButtonSpec;
+type PublicToolbar_d_ToolbarToggleButtonInstanceApi = ToolbarToggleButtonInstanceApi;
+type PublicToolbar_d_GroupToolbarButtonSpec = GroupToolbarButtonSpec;
+type PublicToolbar_d_GroupToolbarButtonInstanceApi = GroupToolbarButtonInstanceApi;
+declare namespace PublicToolbar_d {
+    export { PublicToolbar_d_ToolbarButtonSpec as ToolbarButtonSpec, PublicToolbar_d_ToolbarButtonInstanceApi as ToolbarButtonInstanceApi, PublicToolbar_d_ToolbarSplitButtonSpec as ToolbarSplitButtonSpec, PublicToolbar_d_ToolbarSplitButtonInstanceApi as ToolbarSplitButtonInstanceApi, PublicToolbar_d_ToolbarMenuButtonSpec as ToolbarMenuButtonSpec, PublicToolbar_d_ToolbarMenuButtonInstanceApi as ToolbarMenuButtonInstanceApi, PublicToolbar_d_ToolbarToggleButtonSpec as ToolbarToggleButtonSpec, PublicToolbar_d_ToolbarToggleButtonInstanceApi as ToolbarToggleButtonInstanceApi, PublicToolbar_d_GroupToolbarButtonSpec as GroupToolbarButtonSpec, PublicToolbar_d_GroupToolbarButtonInstanceApi as GroupToolbarButtonInstanceApi, };
+}
+interface ViewButtonApi {
+    setIcon: (newIcon: string) => void;
+}
+interface ViewToggleButtonApi extends ViewButtonApi {
+    isActive: () => boolean;
+    setActive: (state: boolean) => void;
+}
+interface BaseButtonSpec<Api extends ViewButtonApi> {
+    text?: string;
+    icon?: string;
+    tooltip?: string;
+    buttonType?: 'primary' | 'secondary';
+    borderless?: boolean;
+    onAction: (api: Api) => void;
+}
+interface ViewNormalButtonSpec extends BaseButtonSpec<ViewButtonApi> {
+    text: string;
+    type: 'button';
+}
+interface ViewToggleButtonSpec extends BaseButtonSpec<ViewToggleButtonApi> {
+    type: 'togglebutton';
+    active?: boolean;
+    onAction: (api: ViewToggleButtonApi) => void;
+}
+interface ViewButtonsGroupSpec {
+    type: 'group';
+    buttons: Array<ViewNormalButtonSpec | ViewToggleButtonSpec>;
+}
+type ViewButtonSpec = ViewNormalButtonSpec | ViewToggleButtonSpec | ViewButtonsGroupSpec;
+interface ViewInstanceApi {
+    getContainer: () => HTMLElement;
+}
+interface ViewSpec {
+    buttons?: ViewButtonSpec[];
+    onShow: (api: ViewInstanceApi) => void;
+    onHide: (api: ViewInstanceApi) => void;
+}
+type PublicView_d_ViewSpec = ViewSpec;
+type PublicView_d_ViewInstanceApi = ViewInstanceApi;
+declare namespace PublicView_d {
+    export { PublicView_d_ViewSpec as ViewSpec, PublicView_d_ViewInstanceApi as ViewInstanceApi, };
+}
+interface Registry$1 {
+    addButton: (name: string, spec: ToolbarButtonSpec) => void;
+    addGroupToolbarButton: (name: string, spec: GroupToolbarButtonSpec) => void;
+    addToggleButton: (name: string, spec: ToolbarToggleButtonSpec) => void;
+    addMenuButton: (name: string, spec: ToolbarMenuButtonSpec) => void;
+    addSplitButton: (name: string, spec: ToolbarSplitButtonSpec) => void;
+    addMenuItem: (name: string, spec: MenuItemSpec) => void;
+    addNestedMenuItem: (name: string, spec: NestedMenuItemSpec) => void;
+    addToggleMenuItem: (name: string, spec: ToggleMenuItemSpec) => void;
+    addContextMenu: (name: string, spec: ContextMenuApi) => void;
+    addContextToolbar: (name: string, spec: ContextToolbarSpec) => void;
+    addContextForm: (name: string, spec: ContextFormSpec) => void;
+    addIcon: (name: string, svgData: string) => void;
+    addAutocompleter: (name: string, spec: AutocompleterSpec) => void;
+    addSidebar: (name: string, spec: SidebarSpec) => void;
+    addView: (name: string, spec: ViewSpec) => void;
+    getAll: () => {
+        buttons: Record<string, ToolbarButtonSpec | GroupToolbarButtonSpec | ToolbarMenuButtonSpec | ToolbarSplitButtonSpec | ToolbarToggleButtonSpec>;
+        menuItems: Record<string, MenuItemSpec | NestedMenuItemSpec | ToggleMenuItemSpec>;
+        popups: Record<string, AutocompleterSpec>;
+        contextMenus: Record<string, ContextMenuApi>;
+        contextToolbars: Record<string, ContextToolbarSpec | ContextFormSpec>;
+        icons: Record<string, string>;
+        sidebars: Record<string, SidebarSpec>;
+        views: Record<string, ViewSpec>;
+    };
+}
+interface AutocompleteLookupData {
+    readonly matchText: string;
+    readonly items: AutocompleterContents[];
+    readonly columns: ColumnTypes;
+    readonly onAction: (autoApi: AutocompleterInstanceApi, rng: Range, value: string, meta: Record<string, any>) => void;
+    readonly highlightOn: string[];
+}
+interface AutocompleterEventArgs {
+    readonly lookupData: AutocompleteLookupData[];
+}
+interface RangeLikeObject {
+    startContainer: Node;
+    startOffset: number;
+    endContainer: Node;
+    endOffset: number;
+}
+type ApplyFormat = BlockFormat | InlineFormat | SelectorFormat;
+type RemoveFormat = RemoveBlockFormat | RemoveInlineFormat | RemoveSelectorFormat;
+type Format = ApplyFormat | RemoveFormat;
+type Formats = Record<string, Format | Format[]>;
+type FormatAttrOrStyleValue = string | ((vars?: FormatVars) => string | null);
+type FormatVars = Record<string, string | null>;
+interface BaseFormat<T> {
+    ceFalseOverride?: boolean;
+    classes?: string | string[];
+    collapsed?: boolean;
+    exact?: boolean;
+    expand?: boolean;
+    links?: boolean;
+    mixed?: boolean;
+    block_expand?: boolean;
+    onmatch?: (node: Element, fmt: T, itemName: string) => boolean;
+    remove?: 'none' | 'empty' | 'all';
+    remove_similar?: boolean;
+    split?: boolean;
+    deep?: boolean;
+    preserve_attributes?: string[];
+}
+interface Block {
+    block: string;
+    list_block?: string;
+    wrapper?: boolean;
+}
+interface Inline {
+    inline: string;
+}
+interface Selector {
+    selector: string;
+    inherit?: boolean;
+}
+interface CommonFormat<T> extends BaseFormat<T> {
+    attributes?: Record<string, FormatAttrOrStyleValue>;
+    styles?: Record<string, FormatAttrOrStyleValue>;
+    toggle?: boolean;
+    preview?: string | false;
+    onformat?: (elm: Element, fmt: T, vars?: FormatVars, node?: Node | RangeLikeObject | null) => void;
+    clear_child_styles?: boolean;
+    merge_siblings?: boolean;
+    merge_with_parents?: boolean;
+}
+interface BlockFormat extends Block, CommonFormat<BlockFormat> {
+}
+interface InlineFormat extends Inline, CommonFormat<InlineFormat> {
+}
+interface SelectorFormat extends Selector, CommonFormat<SelectorFormat> {
+}
+interface CommonRemoveFormat<T> extends BaseFormat<T> {
+    attributes?: string[] | Record<string, FormatAttrOrStyleValue>;
+    styles?: string[] | Record<string, FormatAttrOrStyleValue>;
+}
+interface RemoveBlockFormat extends Block, CommonRemoveFormat<RemoveBlockFormat> {
+}
+interface RemoveInlineFormat extends Inline, CommonRemoveFormat<RemoveInlineFormat> {
+}
+interface RemoveSelectorFormat extends Selector, CommonRemoveFormat<RemoveSelectorFormat> {
+}
+interface Filter<C extends Function> {
+    name: string;
+    callbacks: C[];
+}
+interface ParserArgs {
+    getInner?: boolean | number;
+    forced_root_block?: boolean | string;
+    context?: string;
+    isRootContent?: boolean;
+    format?: string;
+    invalid?: boolean;
+    no_events?: boolean;
+    [key: string]: any;
+}
+type ParserFilterCallback = (nodes: AstNode[], name: string, args: ParserArgs) => void;
+interface ParserFilter extends Filter<ParserFilterCallback> {
+}
+interface DomParserSettings {
+    allow_html_data_urls?: boolean;
+    allow_svg_data_urls?: boolean;
+    allow_conditional_comments?: boolean;
+    allow_html_in_named_anchor?: boolean;
+    allow_script_urls?: boolean;
+    allow_unsafe_link_target?: boolean;
+    blob_cache?: BlobCache;
+    convert_fonts_to_spans?: boolean;
+    convert_unsafe_embeds?: boolean;
+    document?: Document;
+    fix_list_elements?: boolean;
+    font_size_legacy_values?: string;
+    forced_root_block?: boolean | string;
+    forced_root_block_attrs?: Record<string, string>;
+    inline_styles?: boolean;
+    pad_empty_with_br?: boolean;
+    preserve_cdata?: boolean;
+    root_name?: string;
+    sandbox_iframes?: boolean;
+    sandbox_iframes_exclusions?: string[];
+    sanitize?: boolean;
+    validate?: boolean;
+}
+interface DomParser {
+    schema: Schema;
+    addAttributeFilter: (name: string, callback: ParserFilterCallback) => void;
+    getAttributeFilters: () => ParserFilter[];
+    removeAttributeFilter: (name: string, callback?: ParserFilterCallback) => void;
+    addNodeFilter: (name: string, callback: ParserFilterCallback) => void;
+    getNodeFilters: () => ParserFilter[];
+    removeNodeFilter: (name: string, callback?: ParserFilterCallback) => void;
+    parse: (html: string, args?: ParserArgs) => AstNode;
+}
+interface StyleSheetLoaderSettings {
+    maxLoadTime?: number;
+    contentCssCors?: boolean;
+    referrerPolicy?: ReferrerPolicy;
+}
+interface StyleSheetLoader {
+    load: (url: string) => Promise<void>;
+    loadRawCss: (key: string, css: string) => void;
+    loadAll: (urls: string[]) => Promise<string[]>;
+    unload: (url: string) => void;
+    unloadRawCss: (key: string) => void;
+    unloadAll: (urls: string[]) => void;
+    _setReferrerPolicy: (referrerPolicy: ReferrerPolicy) => void;
+    _setContentCssCors: (contentCssCors: boolean) => void;
+}
+type Registry = Registry$1;
+interface EditorUiApi {
+    show: () => void;
+    hide: () => void;
+    setEnabled: (state: boolean) => void;
+    isEnabled: () => boolean;
+}
+interface EditorUi extends EditorUiApi {
+    registry: Registry;
+    styleSheetLoader: StyleSheetLoader;
+}
+type Ui_d_Registry = Registry;
+type Ui_d_EditorUiApi = EditorUiApi;
+type Ui_d_EditorUi = EditorUi;
+declare namespace Ui_d {
+    export { Ui_d_Registry as Registry, PublicDialog_d as Dialog, PublicInlineContent_d as InlineContent, PublicMenu_d as Menu, PublicView_d as View, PublicSidebar_d as Sidebar, PublicToolbar_d as Toolbar, Ui_d_EditorUiApi as EditorUiApi, Ui_d_EditorUi as EditorUi, };
+}
+interface WindowParams {
+    readonly inline?: 'cursor' | 'toolbar' | 'bottom';
+    readonly ariaAttrs?: boolean;
+    readonly persistent?: boolean;
+}
+type InstanceApi<T extends DialogData> = UrlDialogInstanceApi | DialogInstanceApi<T>;
+interface WindowManagerImpl {
+    open: <T extends DialogData>(config: DialogSpec<T>, params: WindowParams | undefined, closeWindow: (dialog: DialogInstanceApi<T>) => void) => DialogInstanceApi<T>;
+    openUrl: (config: UrlDialogSpec, closeWindow: (dialog: UrlDialogInstanceApi) => void) => UrlDialogInstanceApi;
+    alert: (message: string, callback: () => void) => void;
+    confirm: (message: string, callback: (state: boolean) => void) => void;
+    close: (dialog: InstanceApi<any>) => void;
+}
+interface WindowManager {
+    open: <T extends DialogData>(config: DialogSpec<T>, params?: WindowParams) => DialogInstanceApi<T>;
+    openUrl: (config: UrlDialogSpec) => UrlDialogInstanceApi;
+    alert: (message: string, callback?: () => void, scope?: any) => void;
+    confirm: (message: string, callback?: (state: boolean) => void, scope?: any) => void;
+    close: () => void;
+}
+interface ExecCommandEvent {
+    command: string;
+    ui: boolean;
+    value?: any;
+}
+interface BeforeGetContentEvent extends GetContentArgs {
+    selection?: boolean;
+}
+interface GetContentEvent extends BeforeGetContentEvent {
+    content: string;
+}
+interface BeforeSetContentEvent extends SetContentArgs {
+    content: string;
+    selection?: boolean;
+}
+interface SetContentEvent extends BeforeSetContentEvent {
+    content: string;
+}
+interface SaveContentEvent extends GetContentEvent {
+    save: boolean;
+}
+interface NewBlockEvent {
+    newBlock: Element;
+}
+interface NodeChangeEvent {
+    element: Element;
+    parents: Node[];
+    selectionChange?: boolean;
+    initial?: boolean;
+}
+interface FormatEvent {
+    format: string;
+    vars?: FormatVars;
+    node?: Node | RangeLikeObject | null;
+}
+interface ObjectResizeEvent {
+    target: HTMLElement;
+    width: number;
+    height: number;
+    origin: string;
+}
+interface ObjectSelectedEvent {
+    target: Node;
+    targetClone?: Node;
+}
+interface ScrollIntoViewEvent {
+    elm: HTMLElement;
+    alignToTop: boolean | undefined;
+}
+interface SetSelectionRangeEvent {
+    range: Range;
+    forward: boolean | undefined;
+}
+interface ShowCaretEvent {
+    target: Node;
+    direction: number;
+    before: boolean;
+}
+interface SwitchModeEvent {
+    mode: string;
+}
+interface ChangeEvent {
+    level: UndoLevel;
+    lastLevel: UndoLevel | undefined;
+}
+interface AddUndoEvent extends ChangeEvent {
+    originalEvent: Event | undefined;
+}
+interface UndoRedoEvent {
+    level: UndoLevel;
+}
+interface WindowEvent<T extends DialogData> {
+    dialog: InstanceApi<T>;
+}
+interface ProgressStateEvent {
+    state: boolean;
+    time?: number;
+}
+interface AfterProgressStateEvent {
+    state: boolean;
+}
+interface PlaceholderToggleEvent {
+    state: boolean;
+}
+interface LoadErrorEvent {
+    message: string;
+}
+interface PreProcessEvent extends ParserArgs {
+    node: Element;
+}
+interface PostProcessEvent extends ParserArgs {
+    content: string;
+}
+interface PastePlainTextToggleEvent {
+    state: boolean;
+}
+interface PastePreProcessEvent {
+    content: string;
+    readonly internal: boolean;
+}
+interface PastePostProcessEvent {
+    node: HTMLElement;
+    readonly internal: boolean;
+}
+interface EditableRootStateChangeEvent {
+    state: boolean;
+}
+interface NewTableRowEvent {
+    node: HTMLTableRowElement;
+}
+interface NewTableCellEvent {
+    node: HTMLTableCellElement;
+}
+interface TableEventData {
+    readonly structure: boolean;
+    readonly style: boolean;
+}
+interface TableModifiedEvent extends TableEventData {
+    readonly table: HTMLTableElement;
+}
+interface BeforeOpenNotificationEvent {
+    notification: NotificationSpec;
+}
+interface OpenNotificationEvent {
+    notification: NotificationApi;
+}
+interface EditorEventMap extends Omit<NativeEventMap, 'blur' | 'focus'> {
+    'activate': {
+        relatedTarget: Editor | null;
+    };
+    'deactivate': {
+        relatedTarget: Editor;
+    };
+    'focus': {
+        blurredEditor: Editor | null;
+    };
+    'blur': {
+        focusedEditor: Editor | null;
+    };
+    'resize': UIEvent;
+    'scroll': UIEvent;
+    'input': InputEvent;
+    'beforeinput': InputEvent;
+    'detach': {};
+    'remove': {};
+    'init': {};
+    'ScrollIntoView': ScrollIntoViewEvent;
+    'AfterScrollIntoView': ScrollIntoViewEvent;
+    'ObjectResized': ObjectResizeEvent;
+    'ObjectResizeStart': ObjectResizeEvent;
+    'SwitchMode': SwitchModeEvent;
+    'ScrollWindow': Event;
+    'ResizeWindow': UIEvent;
+    'SkinLoaded': {};
+    'SkinLoadError': LoadErrorEvent;
+    'PluginLoadError': LoadErrorEvent;
+    'ModelLoadError': LoadErrorEvent;
+    'IconsLoadError': LoadErrorEvent;
+    'ThemeLoadError': LoadErrorEvent;
+    'LanguageLoadError': LoadErrorEvent;
+    'BeforeExecCommand': ExecCommandEvent;
+    'ExecCommand': ExecCommandEvent;
+    'NodeChange': NodeChangeEvent;
+    'FormatApply': FormatEvent;
+    'FormatRemove': FormatEvent;
+    'ShowCaret': ShowCaretEvent;
+    'SelectionChange': {};
+    'ObjectSelected': ObjectSelectedEvent;
+    'BeforeObjectSelected': ObjectSelectedEvent;
+    'GetSelectionRange': {
+        range: Range;
+    };
+    'SetSelectionRange': SetSelectionRangeEvent;
+    'AfterSetSelectionRange': SetSelectionRangeEvent;
+    'BeforeGetContent': BeforeGetContentEvent;
+    'GetContent': GetContentEvent;
+    'BeforeSetContent': BeforeSetContentEvent;
+    'SetContent': SetContentEvent;
+    'SaveContent': SaveContentEvent;
+    'RawSaveContent': SaveContentEvent;
+    'LoadContent': {
+        load: boolean;
+        element: HTMLElement;
+    };
+    'PreviewFormats': {};
+    'AfterPreviewFormats': {};
+    'ScriptsLoaded': {};
+    'PreInit': {};
+    'PostRender': {};
+    'NewBlock': NewBlockEvent;
+    'ClearUndos': {};
+    'TypingUndo': {};
+    'Redo': UndoRedoEvent;
+    'Undo': UndoRedoEvent;
+    'BeforeAddUndo': AddUndoEvent;
+    'AddUndo': AddUndoEvent;
+    'change': ChangeEvent;
+    'CloseWindow': WindowEvent<any>;
+    'OpenWindow': WindowEvent<any>;
+    'ProgressState': ProgressStateEvent;
+    'AfterProgressState': AfterProgressStateEvent;
+    'PlaceholderToggle': PlaceholderToggleEvent;
+    'tap': TouchEvent;
+    'longpress': TouchEvent;
+    'longpresscancel': {};
+    'PreProcess': PreProcessEvent;
+    'PostProcess': PostProcessEvent;
+    'AutocompleterStart': AutocompleterEventArgs;
+    'AutocompleterUpdate': AutocompleterEventArgs;
+    'AutocompleterEnd': {};
+    'PastePlainTextToggle': PastePlainTextToggleEvent;
+    'PastePreProcess': PastePreProcessEvent;
+    'PastePostProcess': PastePostProcessEvent;
+    'TableModified': TableModifiedEvent;
+    'NewRow': NewTableRowEvent;
+    'NewCell': NewTableCellEvent;
+    'SetAttrib': SetAttribEvent;
+    'hide': {};
+    'show': {};
+    'dirty': {};
+    'BeforeOpenNotification': BeforeOpenNotificationEvent;
+    'OpenNotification': OpenNotificationEvent;
+}
+interface EditorManagerEventMap {
+    'AddEditor': {
+        editor: Editor;
+    };
+    'RemoveEditor': {
+        editor: Editor;
+    };
+    'BeforeUnload': {
+        returnValue: any;
+    };
+}
+type EventTypes_d_ExecCommandEvent = ExecCommandEvent;
+type EventTypes_d_BeforeGetContentEvent = BeforeGetContentEvent;
+type EventTypes_d_GetContentEvent = GetContentEvent;
+type EventTypes_d_BeforeSetContentEvent = BeforeSetContentEvent;
+type EventTypes_d_SetContentEvent = SetContentEvent;
+type EventTypes_d_SaveContentEvent = SaveContentEvent;
+type EventTypes_d_NewBlockEvent = NewBlockEvent;
+type EventTypes_d_NodeChangeEvent = NodeChangeEvent;
+type EventTypes_d_FormatEvent = FormatEvent;
+type EventTypes_d_ObjectResizeEvent = ObjectResizeEvent;
+type EventTypes_d_ObjectSelectedEvent = ObjectSelectedEvent;
+type EventTypes_d_ScrollIntoViewEvent = ScrollIntoViewEvent;
+type EventTypes_d_SetSelectionRangeEvent = SetSelectionRangeEvent;
+type EventTypes_d_ShowCaretEvent = ShowCaretEvent;
+type EventTypes_d_SwitchModeEvent = SwitchModeEvent;
+type EventTypes_d_ChangeEvent = ChangeEvent;
+type EventTypes_d_AddUndoEvent = AddUndoEvent;
+type EventTypes_d_UndoRedoEvent = UndoRedoEvent;
+type EventTypes_d_WindowEvent<T extends DialogData> = WindowEvent<T>;
+type EventTypes_d_ProgressStateEvent = ProgressStateEvent;
+type EventTypes_d_AfterProgressStateEvent = AfterProgressStateEvent;
+type EventTypes_d_PlaceholderToggleEvent = PlaceholderToggleEvent;
+type EventTypes_d_LoadErrorEvent = LoadErrorEvent;
+type EventTypes_d_PreProcessEvent = PreProcessEvent;
+type EventTypes_d_PostProcessEvent = PostProcessEvent;
+type EventTypes_d_PastePlainTextToggleEvent = PastePlainTextToggleEvent;
+type EventTypes_d_PastePreProcessEvent = PastePreProcessEvent;
+type EventTypes_d_PastePostProcessEvent = PastePostProcessEvent;
+type EventTypes_d_EditableRootStateChangeEvent = EditableRootStateChangeEvent;
+type EventTypes_d_NewTableRowEvent = NewTableRowEvent;
+type EventTypes_d_NewTableCellEvent = NewTableCellEvent;
+type EventTypes_d_TableEventData = TableEventData;
+type EventTypes_d_TableModifiedEvent = TableModifiedEvent;
+type EventTypes_d_BeforeOpenNotificationEvent = BeforeOpenNotificationEvent;
+type EventTypes_d_OpenNotificationEvent = OpenNotificationEvent;
+type EventTypes_d_EditorEventMap = EditorEventMap;
+type EventTypes_d_EditorManagerEventMap = EditorManagerEventMap;
+declare namespace EventTypes_d {
+    export { EventTypes_d_ExecCommandEvent as ExecCommandEvent, EventTypes_d_BeforeGetContentEvent as BeforeGetContentEvent, EventTypes_d_GetContentEvent as GetContentEvent, EventTypes_d_BeforeSetContentEvent as BeforeSetContentEvent, EventTypes_d_SetContentEvent as SetContentEvent, EventTypes_d_SaveContentEvent as SaveContentEvent, EventTypes_d_NewBlockEvent as NewBlockEvent, EventTypes_d_NodeChangeEvent as NodeChangeEvent, EventTypes_d_FormatEvent as FormatEvent, EventTypes_d_ObjectResizeEvent as ObjectResizeEvent, EventTypes_d_ObjectSelectedEvent as ObjectSelectedEvent, EventTypes_d_ScrollIntoViewEvent as ScrollIntoViewEvent, EventTypes_d_SetSelectionRangeEvent as SetSelectionRangeEvent, EventTypes_d_ShowCaretEvent as ShowCaretEvent, EventTypes_d_SwitchModeEvent as SwitchModeEvent, EventTypes_d_ChangeEvent as ChangeEvent, EventTypes_d_AddUndoEvent as AddUndoEvent, EventTypes_d_UndoRedoEvent as UndoRedoEvent, EventTypes_d_WindowEvent as WindowEvent, EventTypes_d_ProgressStateEvent as ProgressStateEvent, EventTypes_d_AfterProgressStateEvent as AfterProgressStateEvent, EventTypes_d_PlaceholderToggleEvent as PlaceholderToggleEvent, EventTypes_d_LoadErrorEvent as LoadErrorEvent, EventTypes_d_PreProcessEvent as PreProcessEvent, EventTypes_d_PostProcessEvent as PostProcessEvent, EventTypes_d_PastePlainTextToggleEvent as PastePlainTextToggleEvent, EventTypes_d_PastePreProcessEvent as PastePreProcessEvent, EventTypes_d_PastePostProcessEvent as PastePostProcessEvent, EventTypes_d_EditableRootStateChangeEvent as EditableRootStateChangeEvent, EventTypes_d_NewTableRowEvent as NewTableRowEvent, EventTypes_d_NewTableCellEvent as NewTableCellEvent, EventTypes_d_TableEventData as TableEventData, EventTypes_d_TableModifiedEvent as TableModifiedEvent, EventTypes_d_BeforeOpenNotificationEvent as BeforeOpenNotificationEvent, EventTypes_d_OpenNotificationEvent as OpenNotificationEvent, EventTypes_d_EditorEventMap as EditorEventMap, EventTypes_d_EditorManagerEventMap as EditorManagerEventMap, };
+}
+type Format_d_Formats = Formats;
+type Format_d_Format = Format;
+type Format_d_ApplyFormat = ApplyFormat;
+type Format_d_BlockFormat = BlockFormat;
+type Format_d_InlineFormat = InlineFormat;
+type Format_d_SelectorFormat = SelectorFormat;
+type Format_d_RemoveFormat = RemoveFormat;
+type Format_d_RemoveBlockFormat = RemoveBlockFormat;
+type Format_d_RemoveInlineFormat = RemoveInlineFormat;
+type Format_d_RemoveSelectorFormat = RemoveSelectorFormat;
+declare namespace Format_d {
+    export { Format_d_Formats as Formats, Format_d_Format as Format, Format_d_ApplyFormat as ApplyFormat, Format_d_BlockFormat as BlockFormat, Format_d_InlineFormat as InlineFormat, Format_d_SelectorFormat as SelectorFormat, Format_d_RemoveFormat as RemoveFormat, Format_d_RemoveBlockFormat as RemoveBlockFormat, Format_d_RemoveInlineFormat as RemoveInlineFormat, Format_d_RemoveSelectorFormat as RemoveSelectorFormat, };
+}
+type StyleFormat = BlockStyleFormat | InlineStyleFormat | SelectorStyleFormat;
+type AllowedFormat = Separator | FormatReference | StyleFormat | NestedFormatting;
+interface Separator {
+    title: string;
+}
+interface FormatReference {
+    title: string;
+    format: string;
+    icon?: string;
+}
+interface NestedFormatting {
+    title: string;
+    items: Array<FormatReference | StyleFormat>;
+}
+interface CommonStyleFormat {
+    name?: string;
+    title: string;
+    icon?: string;
+}
+interface BlockStyleFormat extends BlockFormat, CommonStyleFormat {
+}
+interface InlineStyleFormat extends InlineFormat, CommonStyleFormat {
+}
+interface SelectorStyleFormat extends SelectorFormat, CommonStyleFormat {
+}
+type EntityEncoding = 'named' | 'numeric' | 'raw' | 'named,numeric' | 'named+numeric' | 'numeric,named' | 'numeric+named';
+interface ContentLanguage {
+    readonly title: string;
+    readonly code: string;
+    readonly customCode?: string;
+}
+type ThemeInitFunc = (editor: Editor, elm: HTMLElement) => {
+    editorContainer: HTMLElement;
+    iframeContainer: HTMLElement;
+    height?: number;
+    iframeHeight?: number;
+    api?: EditorUiApi;
+};
+type SetupCallback = (editor: Editor) => void;
+type FilePickerCallback = (callback: (value: string, meta?: Record<string, any>) => void, value: string, meta: Record<string, any>) => void;
+type FilePickerValidationStatus = 'valid' | 'unknown' | 'invalid' | 'none';
+type FilePickerValidationCallback = (info: {
+    type: string;
+    url: string;
+}, callback: (validation: {
+    status: FilePickerValidationStatus;
+    message: string;
+}) => void) => void;
+type PastePreProcessFn = (editor: Editor, args: PastePreProcessEvent) => void;
+type PastePostProcessFn = (editor: Editor, args: PastePostProcessEvent) => void;
+type URLConverter = (url: string, name: string, elm?: string | Element) => string;
+type URLConverterCallback = (url: string, node: Node | string | undefined, on_save: boolean, name: string) => string;
+interface ToolbarGroup {
+    name?: string;
+    items: string[];
+}
+type ToolbarMode = 'floating' | 'sliding' | 'scrolling' | 'wrap';
+type ToolbarLocation = 'top' | 'bottom' | 'auto';
+interface BaseEditorOptions {
+    a11y_advanced_options?: boolean;
+    add_form_submit_trigger?: boolean;
+    add_unload_trigger?: boolean;
+    allow_conditional_comments?: boolean;
+    allow_html_data_urls?: boolean;
+    allow_html_in_named_anchor?: boolean;
+    allow_script_urls?: boolean;
+    allow_svg_data_urls?: boolean;
+    allow_unsafe_link_target?: boolean;
+    anchor_bottom?: false | string;
+    anchor_top?: false | string;
+    auto_focus?: string | true;
+    automatic_uploads?: boolean;
+    base_url?: string;
+    block_formats?: string;
+    block_unsupported_drop?: boolean;
+    body_id?: string;
+    body_class?: string;
+    br_in_pre?: boolean;
+    br_newline_selector?: string;
+    browser_spellcheck?: boolean;
+    branding?: boolean;
+    cache_suffix?: string;
+    color_cols?: number;
+    color_cols_foreground?: number;
+    color_cols_background?: number;
+    color_map?: string[];
+    color_map_foreground?: string[];
+    color_map_background?: string[];
+    color_default_foreground?: string;
+    color_default_background?: string;
+    content_css?: boolean | string | string[];
+    content_css_cors?: boolean;
+    content_security_policy?: string;
+    content_style?: string;
+    content_langs?: ContentLanguage[];
+    contextmenu?: string | string[] | false;
+    contextmenu_never_use_native?: boolean;
+    convert_fonts_to_spans?: boolean;
+    convert_unsafe_embeds?: boolean;
+    convert_urls?: boolean;
+    custom_colors?: boolean;
+    custom_elements?: string | Record<string, CustomElementSpec>;
+    custom_ui_selector?: string;
+    custom_undo_redo_levels?: number;
+    default_font_stack?: string[];
+    deprecation_warnings?: boolean;
+    directionality?: 'ltr' | 'rtl';
+    doctype?: string;
+    document_base_url?: string;
+    draggable_modal?: boolean;
+    editable_class?: string;
+    editable_root?: boolean;
+    element_format?: 'xhtml' | 'html';
+    elementpath?: boolean;
+    encoding?: string;
+    end_container_on_empty_block?: boolean | string;
+    entities?: string;
+    entity_encoding?: EntityEncoding;
+    extended_valid_elements?: string;
+    event_root?: string;
+    file_picker_callback?: FilePickerCallback;
+    file_picker_types?: string;
+    file_picker_validator_handler?: FilePickerValidationCallback;
+    fix_list_elements?: boolean;
+    fixed_toolbar_container?: string;
+    fixed_toolbar_container_target?: HTMLElement;
+    font_css?: string | string[];
+    font_family_formats?: string;
+    font_size_classes?: string;
+    font_size_legacy_values?: string;
+    font_size_style_values?: string;
+    font_size_formats?: string;
+    font_size_input_default_unit?: string;
+    forced_root_block?: string;
+    forced_root_block_attrs?: Record<string, string>;
+    formats?: Formats;
+    format_noneditable_selector?: string;
+    height?: number | string;
+    help_accessibility?: boolean;
+    hidden_input?: boolean;
+    highlight_on_focus?: boolean;
+    icons?: string;
+    icons_url?: string;
+    id?: string;
+    iframe_aria_text?: string;
+    iframe_attrs?: Record<string, string>;
+    images_file_types?: string;
+    images_replace_blob_uris?: boolean;
+    images_reuse_filename?: boolean;
+    images_upload_base_path?: string;
+    images_upload_credentials?: boolean;
+    images_upload_handler?: UploadHandler;
+    images_upload_url?: string;
+    indent?: boolean;
+    indent_after?: string;
+    indent_before?: string;
+    indent_use_margin?: boolean;
+    indentation?: string;
+    init_instance_callback?: SetupCallback;
+    inline?: boolean;
+    inline_boundaries?: boolean;
+    inline_boundaries_selector?: string;
+    inline_styles?: boolean;
+    invalid_elements?: string;
+    invalid_styles?: string | Record<string, string>;
+    keep_styles?: boolean;
+    language?: string;
+    language_load?: boolean;
+    language_url?: string;
+    line_height_formats?: string;
+    max_height?: number;
+    max_width?: number;
+    menu?: Record<string, {
+        title: string;
+        items: string;
+    }>;
+    menubar?: boolean | string;
+    min_height?: number;
+    min_width?: number;
+    model?: string;
+    model_url?: string;
+    newdocument_content?: string;
+    newline_behavior?: 'block' | 'linebreak' | 'invert' | 'default';
+    no_newline_selector?: string;
+    noneditable_class?: string;
+    noneditable_regexp?: RegExp | RegExp[];
+    nowrap?: boolean;
+    object_resizing?: boolean | string;
+    pad_empty_with_br?: boolean;
+    paste_as_text?: boolean;
+    paste_block_drop?: boolean;
+    paste_data_images?: boolean;
+    paste_merge_formats?: boolean;
+    paste_postprocess?: PastePostProcessFn;
+    paste_preprocess?: PastePreProcessFn;
+    paste_remove_styles_if_webkit?: boolean;
+    paste_tab_spaces?: number;
+    paste_webkit_styles?: string;
+    placeholder?: string;
+    preserve_cdata?: boolean;
+    preview_styles?: false | string;
+    promotion?: boolean;
+    protect?: RegExp[];
+    readonly?: boolean;
+    referrer_policy?: ReferrerPolicy;
+    relative_urls?: boolean;
+    remove_script_host?: boolean;
+    remove_trailing_brs?: boolean;
+    removed_menuitems?: string;
+    resize?: boolean | 'both';
+    resize_img_proportional?: boolean;
+    root_name?: string;
+    sandbox_iframes?: boolean;
+    sandbox_iframes_exclusions?: string[];
+    schema?: SchemaType;
+    selector?: string;
+    setup?: SetupCallback;
+    sidebar_show?: string;
+    skin?: boolean | string;
+    skin_url?: string;
+    smart_paste?: boolean;
+    statusbar?: boolean;
+    style_formats?: AllowedFormat[];
+    style_formats_autohide?: boolean;
+    style_formats_merge?: boolean;
+    submit_patch?: boolean;
+    suffix?: string;
+    table_tab_navigation?: boolean;
+    target?: HTMLElement;
+    text_patterns?: RawPattern[] | false;
+    text_patterns_lookup?: RawDynamicPatternsLookup;
+    theme?: string | ThemeInitFunc | false;
+    theme_url?: string;
+    toolbar?: boolean | string | string[] | Array<ToolbarGroup>;
+    toolbar1?: string;
+    toolbar2?: string;
+    toolbar3?: string;
+    toolbar4?: string;
+    toolbar5?: string;
+    toolbar6?: string;
+    toolbar7?: string;
+    toolbar8?: string;
+    toolbar9?: string;
+    toolbar_groups?: Record<string, GroupToolbarButtonSpec>;
+    toolbar_location?: ToolbarLocation;
+    toolbar_mode?: ToolbarMode;
+    toolbar_sticky?: boolean;
+    toolbar_sticky_offset?: number;
+    typeahead_urls?: boolean;
+    ui_mode?: 'combined' | 'split';
+    url_converter?: URLConverter;
+    url_converter_scope?: any;
+    urlconverter_callback?: URLConverterCallback;
+    valid_children?: string;
+    valid_classes?: string | Record<string, string>;
+    valid_elements?: string;
+    valid_styles?: string | Record<string, string>;
+    verify_html?: boolean;
+    visual?: boolean;
+    visual_anchor_class?: string;
+    visual_table_class?: string;
+    width?: number | string;
+    xss_sanitization?: boolean;
+    license_key?: string;
+    disable_nodechange?: boolean;
+    forced_plugins?: string | string[];
+    plugin_base_urls?: Record<string, string>;
+    service_message?: string;
+    [key: string]: any;
+}
+interface RawEditorOptions extends BaseEditorOptions {
+    external_plugins?: Record<string, string>;
+    mobile?: RawEditorOptions;
+    plugins?: string | string[];
+}
+interface NormalizedEditorOptions extends BaseEditorOptions {
+    external_plugins: Record<string, string>;
+    forced_plugins: string[];
+    plugins: string[];
+}
+interface EditorOptions extends NormalizedEditorOptions {
+    a11y_advanced_options: boolean;
+    allow_unsafe_link_target: boolean;
+    anchor_bottom: string;
+    anchor_top: string;
+    automatic_uploads: boolean;
+    block_formats: string;
+    body_class: string;
+    body_id: string;
+    br_newline_selector: string;
+    color_map: string[];
+    color_cols: number;
+    color_cols_foreground: number;
+    color_cols_background: number;
+    color_default_background: string;
+    color_default_foreground: string;
+    content_css: string[];
+    contextmenu: string[];
+    convert_unsafe_embeds: boolean;
+    custom_colors: boolean;
+    default_font_stack: string[];
+    document_base_url: string;
+    init_content_sync: boolean;
+    draggable_modal: boolean;
+    editable_class: string;
+    editable_root: boolean;
+    font_css: string[];
+    font_family_formats: string;
+    font_size_classes: string;
+    font_size_formats: string;
+    font_size_input_default_unit: string;
+    font_size_legacy_values: string;
+    font_size_style_values: string;
+    forced_root_block: string;
+    forced_root_block_attrs: Record<string, string>;
+    format_noneditable_selector: string;
+    height: number | string;
+    highlight_on_focus: boolean;
+    iframe_attrs: Record<string, string>;
+    images_file_types: string;
+    images_upload_base_path: string;
+    images_upload_credentials: boolean;
+    images_upload_url: string;
+    indent_use_margin: boolean;
+    indentation: string;
+    inline: boolean;
+    inline_boundaries_selector: string;
+    language: string;
+    language_load: boolean;
+    language_url: string;
+    line_height_formats: string;
+    menu: Record<string, {
+        title: string;
+        items: string;
+    }>;
+    menubar: boolean | string;
+    model: string;
+    newdocument_content: string;
+    no_newline_selector: string;
+    noneditable_class: string;
+    noneditable_regexp: RegExp[];
+    object_resizing: string;
+    pad_empty_with_br: boolean;
+    paste_as_text: boolean;
+    preview_styles: string;
+    promotion: boolean;
+    readonly: boolean;
+    removed_menuitems: string;
+    sandbox_iframes: boolean;
+    sandbox_iframes_exclusions: string[];
+    toolbar: boolean | string | string[] | Array<ToolbarGroup>;
+    toolbar_groups: Record<string, GroupToolbarButtonSpec>;
+    toolbar_location: ToolbarLocation;
+    toolbar_mode: ToolbarMode;
+    toolbar_persist: boolean;
+    toolbar_sticky: boolean;
+    toolbar_sticky_offset: number;
+    text_patterns: Pattern[];
+    text_patterns_lookup: DynamicPatternsLookup;
+    visual: boolean;
+    visual_anchor_class: string;
+    visual_table_class: string;
+    width: number | string;
+    xss_sanitization: boolean;
+}
+type StyleMap = Record<string, string | number>;
+interface StylesSettings {
+    allow_script_urls?: boolean;
+    allow_svg_data_urls?: boolean;
+    url_converter?: URLConverter;
+    url_converter_scope?: any;
+}
+interface Styles {
+    parse: (css: string | undefined) => Record<string, string>;
+    serialize: (styles: StyleMap, elementName?: string) => string;
+}
+type EventUtilsCallback<T> = (event: EventUtilsEvent<T>) => void | boolean;
+type EventUtilsEvent<T> = NormalizedEvent<T> & {
+    metaKey: boolean;
+};
+interface Callback$1<T> {
+    func: EventUtilsCallback<T>;
+    scope: any;
+}
+interface CallbackList<T> extends Array<Callback$1<T>> {
+    fakeName: string | false;
+    capture: boolean;
+    nativeHandler: EventListener;
+}
+interface EventUtilsConstructor {
+    readonly prototype: EventUtils;
+    new (): EventUtils;
+    Event: EventUtils;
+}
+declare class EventUtils {
+    static Event: EventUtils;
+    domLoaded: boolean;
+    events: Record<number, Record<string, CallbackList<any>>>;
+    private readonly expando;
+    private hasFocusIn;
+    private count;
+    constructor();
+    bind<K extends keyof HTMLElementEventMap>(target: any, name: K, callback: EventUtilsCallback<HTMLElementEventMap[K]>, scope?: any): EventUtilsCallback<HTMLElementEventMap[K]>;
+    bind<T = any>(target: any, names: string, callback: EventUtilsCallback<T>, scope?: any): EventUtilsCallback<T>;
+    unbind<K extends keyof HTMLElementEventMap>(target: any, name: K, callback?: EventUtilsCallback<HTMLElementEventMap[K]>): this;
+    unbind<T = any>(target: any, names: string, callback?: EventUtilsCallback<T>): this;
+    unbind(target: any): this;
+    fire(target: any, name: string, args?: {}): this;
+    dispatch(target: any, name: string, args?: {}): this;
+    clean(target: any): this;
+    destroy(): void;
+    cancel<T>(e: EventUtilsEvent<T>): boolean;
+    private executeHandlers;
+}
+interface SetAttribEvent {
+    attrElm: HTMLElement;
+    attrName: string;
+    attrValue: string | boolean | number | null;
+}
+interface DOMUtilsSettings {
+    schema: Schema;
+    url_converter: URLConverter;
+    url_converter_scope: any;
+    ownEvents: boolean;
+    keep_values: boolean;
+    update_styles: boolean;
+    root_element: HTMLElement | null;
+    collect: boolean;
+    onSetAttrib: (event: SetAttribEvent) => void;
+    contentCssCors: boolean;
+    referrerPolicy: ReferrerPolicy;
+}
+type Target = Node | Window;
+type RunArguments<T extends Node = Node> = string | T | Array<string | T> | null;
+type BoundEvent = [
+    Target,
+    string,
+    EventUtilsCallback<any>,
+    any
+];
+type Callback<K extends string> = EventUtilsCallback<MappedEvent<HTMLElementEventMap, K>>;
+type RunResult<T, R> = T extends Array<any> ? R[] : false | R;
+interface DOMUtils {
+    doc: Document;
+    settings: Partial<DOMUtilsSettings>;
+    win: Window;
+    files: Record<string, boolean>;
+    stdMode: boolean;
+    boxModel: boolean;
+    styleSheetLoader: StyleSheetLoader;
+    boundEvents: BoundEvent[];
+    styles: Styles;
+    schema: Schema;
+    events: EventUtils;
+    root: Node | null;
+    isBlock: {
+        (node: Node | null): node is HTMLElement;
+        (node: string): boolean;
+    };
+    clone: (node: Node, deep: boolean) => Node;
+    getRoot: () => HTMLElement;
+    getViewPort: (argWin?: Window) => GeomRect;
+    getRect: (elm: string | HTMLElement) => GeomRect;
+    getSize: (elm: string | HTMLElement) => {
+        w: number;
+        h: number;
+    };
+    getParent: {
+        <K extends keyof HTMLElementTagNameMap>(node: string | Node | null, selector: K, root?: Node): HTMLElementTagNameMap[K] | null;
+        <T extends Element>(node: string | Node | null, selector: string | ((node: Node) => node is T), root?: Node): T | null;
+        (node: string | Node | null, selector?: string | ((node: Node) => boolean | void), root?: Node): Node | null;
+    };
+    getParents: {
+        <K extends keyof HTMLElementTagNameMap>(elm: string | HTMLElementTagNameMap[K] | null, selector: K, root?: Node, collect?: boolean): Array<HTMLElementTagNameMap[K]>;
+        <T extends Element>(node: string | Node | null, selector: string | ((node: Node) => node is T), root?: Node, collect?: boolean): T[];
+        (elm: string | Node | null, selector?: string | ((node: Node) => boolean | void), root?: Node, collect?: boolean): Node[];
+    };
+    get: {
+        <T extends Node>(elm: T): T;
+        (elm: string): HTMLElement | null;
+    };
+    getNext: (node: Node | null, selector: string | ((node: Node) => boolean)) => Node | null;
+    getPrev: (node: Node | null, selector: string | ((node: Node) => boolean)) => Node | null;
+    select: {
+        <K extends keyof HTMLElementTagNameMap>(selector: K, scope?: string | Node): Array<HTMLElementTagNameMap[K]>;
+        <T extends HTMLElement = HTMLElement>(selector: string, scope?: string | Node): T[];
+    };
+    is: {
+        <T extends Element>(elm: Node | Node[] | null, selector: string): elm is T;
+        (elm: Node | Node[] | null, selector: string): boolean;
+    };
+    add: (parentElm: RunArguments, name: string | Element, attrs?: Record<string, string | boolean | number | null>, html?: string | Node | null, create?: boolean) => HTMLElement;
+    create: {
+        <K extends keyof HTMLElementTagNameMap>(name: K, attrs?: Record<string, string | boolean | number | null>, html?: string | Node | null): HTMLElementTagNameMap[K];
+        (name: string, attrs?: Record<string, string | boolean | number | null>, html?: string | Node | null): HTMLElement;
+    };
+    createHTML: (name: string, attrs?: Record<string, string | null>, html?: string) => string;
+    createFragment: (html?: string) => DocumentFragment;
+    remove: {
+        <T extends Node>(node: T | T[], keepChildren?: boolean): typeof node extends Array<any> ? T[] : T;
+        <T extends Node>(node: string, keepChildren?: boolean): T | false;
+    };
+    getStyle: {
+        (elm: Element, name: string, computed: true): string;
+        (elm: string | Element | null, name: string, computed?: boolean): string | undefined;
+    };
+    setStyle: (elm: string | Element | Element[], name: string, value: string | number | null) => void;
+    setStyles: (elm: string | Element | Element[], stylesArg: StyleMap) => void;
+    removeAllAttribs: (e: RunArguments<Element>) => void;
+    setAttrib: (elm: RunArguments<Element>, name: string, value: string | boolean | number | null) => void;
+    setAttribs: (elm: RunArguments<Element>, attrs: Record<string, string | boolean | number | null>) => void;
+    getAttrib: (elm: string | Element | null, name: string, defaultVal?: string) => string;
+    getAttribs: (elm: string | Element) => NamedNodeMap | Attr[];
+    getPos: (elm: string | Element, rootElm?: Node) => {
+        x: number;
+        y: number;
+    };
+    parseStyle: (cssText: string) => Record<string, string>;
+    serializeStyle: (stylesArg: StyleMap, name?: string) => string;
+    addStyle: (cssText: string) => void;
+    loadCSS: (url: string) => void;
+    hasClass: (elm: string | Element, cls: string) => boolean;
+    addClass: (elm: RunArguments<Element>, cls: string) => void;
+    removeClass: (elm: RunArguments<Element>, cls: string) => void;
+    toggleClass: (elm: RunArguments<Element>, cls: string, state?: boolean) => void;
+    show: (elm: string | Node | Node[]) => void;
+    hide: (elm: string | Node | Node[]) => void;
+    isHidden: (elm: string | Node) => boolean;
+    uniqueId: (prefix?: string) => string;
+    setHTML: (elm: RunArguments<Element>, html: string) => void;
+    getOuterHTML: (elm: string | Node) => string;
+    setOuterHTML: (elm: string | Node | Node[], html: string) => void;
+    decode: (text: string) => string;
+    encode: (text: string) => string;
+    insertAfter: {
+        <T extends Node>(node: T | T[], reference: string | Node): T;
+        <T extends Node>(node: RunArguments<T>, reference: string | Node): RunResult<typeof node, T>;
+    };
+    replace: {
+        <T extends Node>(newElm: Node, oldElm: T | T[], keepChildren?: boolean): T;
+        <T extends Node>(newElm: Node, oldElm: RunArguments<T>, keepChildren?: boolean): false | T;
+    };
+    rename: {
+        <K extends keyof HTMLElementTagNameMap>(elm: Element, name: K): HTMLElementTagNameMap[K];
+        (elm: Element, name: string): Element;
+    };
+    findCommonAncestor: (a: Node, b: Node) => Node | null;
+    run<R, T extends Node>(this: DOMUtils, elm: T | T[], func: (node: T) => R, scope?: any): typeof elm extends Array<any> ? R[] : R;
+    run<R, T extends Node>(this: DOMUtils, elm: RunArguments<T>, func: (node: T) => R, scope?: any): RunResult<typeof elm, R>;
+    isEmpty: (node: Node, elements?: Record<string, any>, options?: IsEmptyOptions) => boolean;
+    createRng: () => Range;
+    nodeIndex: (node: Node, normalized?: boolean) => number;
+    split: {
+        <T extends Node>(parentElm: Node, splitElm: Node, replacementElm: T): T | undefined;
+        <T extends Node>(parentElm: Node, splitElm: T): T | undefined;
+    };
+    bind: {
+        <K extends string>(target: Target, name: K, func: Callback<K>, scope?: any): Callback<K>;
+        <K extends string>(target: Target[], name: K, func: Callback<K>, scope?: any): Callback<K>[];
+    };
+    unbind: {
+        <K extends string>(target: Target, name?: K, func?: EventUtilsCallback<MappedEvent<HTMLElementEventMap, K>>): EventUtils;
+        <K extends string>(target: Target[], name?: K, func?: EventUtilsCallback<MappedEvent<HTMLElementEventMap, K>>): EventUtils[];
+    };
+    fire: (target: Node | Window, name: string, evt?: {}) => EventUtils;
+    dispatch: (target: Node | Window, name: string, evt?: {}) => EventUtils;
+    getContentEditable: (node: Node) => string | null;
+    getContentEditableParent: (node: Node) => string | null;
+    isEditable: (node: Node | null | undefined) => boolean;
+    destroy: () => void;
+    isChildOf: (node: Node, parent: Node) => boolean;
+    dumpRng: (r: Range) => string;
+}
+interface ClientRect {
+    left: number;
+    top: number;
+    bottom: number;
+    right: number;
+    width: number;
+    height: number;
+}
+interface BookmarkManager {
+    getBookmark: (type?: number, normalized?: boolean) => Bookmark;
+    moveToBookmark: (bookmark: Bookmark) => void;
+}
+interface ControlSelection {
+    isResizable: (elm: Element) => boolean;
+    showResizeRect: (elm: HTMLElement) => void;
+    hideResizeRect: () => void;
+    updateResizeRect: (evt: EditorEvent<any>) => void;
+    destroy: () => void;
+}
+interface WriterSettings {
+    element_format?: 'xhtml' | 'html';
+    entities?: string;
+    entity_encoding?: EntityEncoding;
+    indent?: boolean;
+    indent_after?: string;
+    indent_before?: string;
+}
+type Attributes = Array<{
+    name: string;
+    value: string;
+}>;
+interface Writer {
+    cdata: (text: string) => void;
+    comment: (text: string) => void;
+    doctype: (text: string) => void;
+    end: (name: string) => void;
+    getContent: () => string;
+    pi: (name: string, text?: string) => void;
+    reset: () => void;
+    start: (name: string, attrs?: Attributes | null, empty?: boolean) => void;
+    text: (text: string, raw?: boolean) => void;
+}
+interface HtmlSerializerSettings extends WriterSettings {
+    inner?: boolean;
+    validate?: boolean;
+}
+interface HtmlSerializer {
+    serialize: (node: AstNode) => string;
+}
+interface DomSerializerSettings extends DomParserSettings, WriterSettings, SchemaSettings, HtmlSerializerSettings {
+    remove_trailing_brs?: boolean;
+    url_converter?: URLConverter;
+    url_converter_scope?: {};
+}
+interface DomSerializerImpl {
+    schema: Schema;
+    addNodeFilter: (name: string, callback: ParserFilterCallback) => void;
+    addAttributeFilter: (name: string, callback: ParserFilterCallback) => void;
+    getNodeFilters: () => ParserFilter[];
+    getAttributeFilters: () => ParserFilter[];
+    removeNodeFilter: (name: string, callback?: ParserFilterCallback) => void;
+    removeAttributeFilter: (name: string, callback?: ParserFilterCallback) => void;
+    serialize: {
+        (node: Element, parserArgs: {
+            format: 'tree';
+        } & ParserArgs): AstNode;
+        (node: Element, parserArgs?: ParserArgs): string;
+    };
+    addRules: (rules: string) => void;
+    setRules: (rules: string) => void;
+    addTempAttr: (name: string) => void;
+    getTempAttrs: () => string[];
+}
+interface DomSerializer extends DomSerializerImpl {
+}
+interface EditorSelection {
+    bookmarkManager: BookmarkManager;
+    controlSelection: ControlSelection;
+    dom: DOMUtils;
+    win: Window;
+    serializer: DomSerializer;
+    editor: Editor;
+    collapse: (toStart?: boolean) => void;
+    setCursorLocation: {
+        (node: Node, offset: number): void;
+        (): void;
+    };
+    getContent: {
+        (args: {
+            format: 'tree';
+        } & Partial<GetSelectionContentArgs>): AstNode;
+        (args?: Partial<GetSelectionContentArgs>): string;
+    };
+    setContent: (content: string, args?: Partial<SetSelectionContentArgs>) => void;
+    getBookmark: (type?: number, normalized?: boolean) => Bookmark;
+    moveToBookmark: (bookmark: Bookmark) => void;
+    select: (node: Node, content?: boolean) => Node;
+    isCollapsed: () => boolean;
+    isEditable: () => boolean;
+    isForward: () => boolean;
+    setNode: (elm: Element) => Element;
+    getNode: () => HTMLElement;
+    getSel: () => Selection | null;
+    setRng: (rng: Range, forward?: boolean) => void;
+    getRng: () => Range;
+    getStart: (real?: boolean) => Element;
+    getEnd: (real?: boolean) => Element;
+    getSelectedBlocks: (startElm?: Element, endElm?: Element) => Element[];
+    normalize: () => Range;
+    selectorChanged: (selector: string, callback: (active: boolean, args: {
+        node: Node;
+        selector: String;
+        parents: Node[];
+    }) => void) => EditorSelection;
+    selectorChangedWithUnbind: (selector: string, callback: (active: boolean, args: {
+        node: Node;
+        selector: String;
+        parents: Node[];
+    }) => void) => {
+        unbind: () => void;
+    };
+    getScrollContainer: () => HTMLElement | undefined;
+    scrollIntoView: (elm?: HTMLElement, alignToTop?: boolean) => void;
+    placeCaretAt: (clientX: number, clientY: number) => void;
+    getBoundingClientRect: () => ClientRect | DOMRect;
+    destroy: () => void;
+    expand: (options?: {
+        type: 'word';
+    }) => void;
+}
+type EditorCommandCallback<S> = (this: S, ui: boolean, value: any) => void;
+type EditorCommandsCallback = (command: string, ui: boolean, value?: any) => void;
+interface Commands {
+    state: Record<string, (command: string) => boolean>;
+    exec: Record<string, EditorCommandsCallback>;
+    value: Record<string, (command: string) => string>;
+}
+interface ExecCommandArgs {
+    skip_focus?: boolean;
+}
+interface EditorCommandsConstructor {
+    readonly prototype: EditorCommands;
+    new (editor: Editor): EditorCommands;
+}
+declare class EditorCommands {
+    private readonly editor;
+    private commands;
+    constructor(editor: Editor);
+    execCommand(command: string, ui?: boolean, value?: any, args?: ExecCommandArgs): boolean;
+    queryCommandState(command: string): boolean;
+    queryCommandValue(command: string): string;
+    addCommands<K extends keyof Commands>(commandList: Commands[K], type: K): void;
+    addCommands(commandList: Record<string, EditorCommandsCallback>): void;
+    addCommand<S>(command: string, callback: EditorCommandCallback<S>, scope: S): void;
+    addCommand(command: string, callback: EditorCommandCallback<Editor>): void;
+    queryCommandSupported(command: string): boolean;
+    addQueryStateHandler<S>(command: string, callback: (this: S) => boolean, scope: S): void;
+    addQueryStateHandler(command: string, callback: (this: Editor) => boolean): void;
+    addQueryValueHandler<S>(command: string, callback: (this: S) => string, scope: S): void;
+    addQueryValueHandler(command: string, callback: (this: Editor) => string): void;
+}
+interface RawString {
+    raw: string;
+}
+type Primitive = string | number | boolean | Record<string | number, any> | Function;
+type TokenisedString = [
+    string,
+    ...Primitive[]
+];
+type Untranslated = Primitive | TokenisedString | RawString | null | undefined;
+type TranslatedString = string;
+interface I18n {
+    getData: () => Record<string, Record<string, string>>;
+    setCode: (newCode: string) => void;
+    getCode: () => string;
+    add: (code: string, items: Record<string, string>) => void;
+    translate: (text: Untranslated) => TranslatedString;
+    isRtl: () => boolean;
+    hasCode: (code: string) => boolean;
+}
+interface Observable<T extends {}> {
+    fire<K extends string, U extends MappedEvent<T, K>>(name: K, args?: U, bubble?: boolean): EditorEvent<U>;
+    dispatch<K extends string, U extends MappedEvent<T, K>>(name: K, args?: U, bubble?: boolean): EditorEvent<U>;
+    on<K extends string>(name: K, callback: (event: EditorEvent<MappedEvent<T, K>>) => void, prepend?: boolean): EventDispatcher<T>;
+    off<K extends string>(name?: K, callback?: (event: EditorEvent<MappedEvent<T, K>>) => void): EventDispatcher<T>;
+    once<K extends string>(name: K, callback: (event: EditorEvent<MappedEvent<T, K>>) => void): EventDispatcher<T>;
+    hasEventListeners(name: string): boolean;
+}
+interface URISettings {
+    base_uri?: URI;
+}
+interface URIConstructor {
+    readonly prototype: URI;
+    new (url: string, settings?: URISettings): URI;
+    getDocumentBaseUrl: (loc: {
+        protocol: string;
+        host?: string;
+        href?: string;
+        pathname?: string;
+    }) => string;
+    parseDataUri: (uri: string) => {
+        type: string;
+        data: string;
+    };
+}
+interface SafeUriOptions {
+    readonly allow_html_data_urls?: boolean;
+    readonly allow_script_urls?: boolean;
+    readonly allow_svg_data_urls?: boolean;
+}
+declare class URI {
+    static parseDataUri(uri: string): {
+        type: string | undefined;
+        data: string;
+    };
+    static isDomSafe(uri: string, context?: string, options?: SafeUriOptions): boolean;
+    static getDocumentBaseUrl(loc: {
+        protocol: string;
+        host?: string;
+        href?: string;
+        pathname?: string;
+    }): string;
+    source: string;
+    protocol: string | undefined;
+    authority: string | undefined;
+    userInfo: string | undefined;
+    user: string | undefined;
+    password: string | undefined;
+    host: string | undefined;
+    port: string | undefined;
+    relative: string | undefined;
+    path: string;
+    directory: string;
+    file: string | undefined;
+    query: string | undefined;
+    anchor: string | undefined;
+    settings: URISettings;
+    constructor(url: string, settings?: URISettings);
+    setPath(path: string): void;
+    toRelative(uri: string): string;
+    toAbsolute(uri: string, noHost?: boolean): string;
+    isSameOrigin(uri: URI): boolean;
+    toRelPath(base: string, path: string): string;
+    toAbsPath(base: string, path: string): string;
+    getURI(noProtoHost?: boolean): string;
+}
+interface EditorManager extends Observable<EditorManagerEventMap> {
+    defaultOptions: RawEditorOptions;
+    majorVersion: string;
+    minorVersion: string;
+    releaseDate: string;
+    activeEditor: Editor | null;
+    focusedEditor: Editor | null;
+    baseURI: URI;
+    baseURL: string;
+    documentBaseURL: string;
+    i18n: I18n;
+    suffix: string;
+    add(this: EditorManager, editor: Editor): Editor;
+    addI18n: (code: string, item: Record<string, string>) => void;
+    createEditor(this: EditorManager, id: string, options: RawEditorOptions): Editor;
+    execCommand(this: EditorManager, cmd: string, ui: boolean, value: any): boolean;
+    get(this: EditorManager): Editor[];
+    get(this: EditorManager, id: number | string): Editor | null;
+    init(this: EditorManager, options: RawEditorOptions): Promise<Editor[]>;
+    overrideDefaults(this: EditorManager, defaultOptions: Partial<RawEditorOptions>): void;
+    remove(this: EditorManager): void;
+    remove(this: EditorManager, selector: string): void;
+    remove(this: EditorManager, editor: Editor): Editor | null;
+    setActive(this: EditorManager, editor: Editor): void;
+    setup(this: EditorManager): void;
+    translate: (text: Untranslated) => TranslatedString;
+    triggerSave: () => void;
+    _setBaseUrl(this: EditorManager, baseUrl: string): void;
+}
+interface EditorObservable extends Observable<EditorEventMap> {
+    bindPendingEventDelegates(this: Editor): void;
+    toggleNativeEvent(this: Editor, name: string, state: boolean): void;
+    unbindAllNativeEvents(this: Editor): void;
+}
+interface ProcessorSuccess<T> {
+    valid: true;
+    value: T;
+}
+interface ProcessorError {
+    valid: false;
+    message: string;
+}
+type SimpleProcessor = (value: unknown) => boolean;
+type Processor<T> = (value: unknown) => ProcessorSuccess<T> | ProcessorError;
+interface BuiltInOptionTypeMap {
+    'string': string;
+    'number': number;
+    'boolean': boolean;
+    'array': any[];
+    'function': Function;
+    'object': any;
+    'string[]': string[];
+    'object[]': any[];
+    'regexp': RegExp;
+}
+type BuiltInOptionType = keyof BuiltInOptionTypeMap;
+interface BaseOptionSpec {
+    immutable?: boolean;
+    deprecated?: boolean;
+    docsUrl?: string;
+}
+interface BuiltInOptionSpec<K extends BuiltInOptionType> extends BaseOptionSpec {
+    processor: K;
+    default?: BuiltInOptionTypeMap[K];
+}
+interface SimpleOptionSpec<T> extends BaseOptionSpec {
+    processor: SimpleProcessor;
+    default?: T;
+}
+interface OptionSpec<T, U> extends BaseOptionSpec {
+    processor: Processor<U>;
+    default?: T;
+}
+interface Options {
+    register: {
+        <K extends BuiltInOptionType>(name: string, spec: BuiltInOptionSpec<K>): void;
+        <K extends keyof NormalizedEditorOptions>(name: K, spec: OptionSpec<NormalizedEditorOptions[K], EditorOptions[K]> | SimpleOptionSpec<NormalizedEditorOptions[K]>): void;
+        <T, U>(name: string, spec: OptionSpec<T, U>): void;
+        <T>(name: string, spec: SimpleOptionSpec<T>): void;
+    };
+    isRegistered: (name: string) => boolean;
+    get: {
+        <K extends keyof EditorOptions>(name: K): EditorOptions[K];
+        <T>(name: string): T | undefined;
+    };
+    set: <K extends string, T>(name: K, value: K extends keyof NormalizedEditorOptions ? NormalizedEditorOptions[K] : T) => boolean;
+    unset: (name: string) => boolean;
+    isSet: (name: string) => boolean;
+    debug: () => void;
+}
+interface UploadResult$1 {
+    element: HTMLImageElement;
+    status: boolean;
+    blobInfo: BlobInfo;
+    uploadUri: string;
+    removed: boolean;
+}
+interface EditorUpload {
+    blobCache: BlobCache;
+    addFilter: (filter: (img: HTMLImageElement) => boolean) => void;
+    uploadImages: () => Promise<UploadResult$1[]>;
+    uploadImagesAuto: () => Promise<UploadResult$1[]>;
+    scanForImages: () => Promise<BlobInfoImagePair[]>;
+    destroy: () => void;
+}
+type FormatChangeCallback = (state: boolean, data: {
+    node: Node;
+    format: string;
+    parents: Element[];
+}) => void;
+interface FormatRegistry {
+    get: {
+        (name: string): Format[] | undefined;
+        (): Record<string, Format[]>;
+    };
+    has: (name: string) => boolean;
+    register: (name: string | Formats, format?: Format[] | Format) => void;
+    unregister: (name: string) => Formats;
+}
+interface Formatter extends FormatRegistry {
+    apply: (name: string, vars?: FormatVars, node?: Node | RangeLikeObject | null) => void;
+    remove: (name: string, vars?: FormatVars, node?: Node | Range, similar?: boolean) => void;
+    toggle: (name: string, vars?: FormatVars, node?: Node) => void;
+    match: (name: string, vars?: FormatVars, node?: Node, similar?: boolean) => boolean;
+    closest: (names: string[]) => string | null;
+    matchAll: (names: string[], vars?: FormatVars) => string[];
+    matchNode: (node: Node | null, name: string, vars?: FormatVars, similar?: boolean) => Format | undefined;
+    canApply: (name: string) => boolean;
+    formatChanged: (names: string, callback: FormatChangeCallback, similar?: boolean, vars?: FormatVars) => {
+        unbind: () => void;
+    };
+    getCssText: (format: string | ApplyFormat) => string;
+}
+interface EditorMode {
+    isReadOnly: () => boolean;
+    set: (mode: string) => void;
+    get: () => string;
+    register: (mode: string, api: EditorModeApi) => void;
+}
+interface EditorModeApi {
+    activate: () => void;
+    deactivate: () => void;
+    editorReadOnly: boolean;
+}
+interface Model {
+    readonly table: {
+        readonly getSelectedCells: () => HTMLTableCellElement[];
+        readonly clearSelectedCells: (container: Node) => void;
+    };
+}
+type ModelManager = AddOnManager<Model>;
+interface Plugin {
+    getMetadata?: () => {
+        name: string;
+        url: string;
+    };
+    init?: (editor: Editor, url: string) => void;
+    [key: string]: any;
+}
+type PluginManager = AddOnManager<void | Plugin>;
+interface ShortcutsConstructor {
+    readonly prototype: Shortcuts;
+    new (editor: Editor): Shortcuts;
+}
+type CommandFunc = string | [
+    string,
+    boolean,
+    any
+] | (() => void);
+declare class Shortcuts {
+    private readonly editor;
+    private readonly shortcuts;
+    private pendingPatterns;
+    constructor(editor: Editor);
+    add(pattern: string, desc: string | null, cmdFunc: CommandFunc, scope?: any): boolean;
+    remove(pattern: string): boolean;
+    private normalizeCommandFunc;
+    private createShortcut;
+    private hasModifier;
+    private isFunctionKey;
+    private matchShortcut;
+    private executeShortcutAction;
+}
+interface RenderResult {
+    iframeContainer?: HTMLElement;
+    editorContainer: HTMLElement;
+    api?: Partial<EditorUiApi>;
+}
+interface Theme {
+    ui?: any;
+    inline?: any;
+    execCommand?: (command: string, ui?: boolean, value?: any) => boolean;
+    destroy?: () => void;
+    init?: (editor: Editor, url: string) => void;
+    renderUI?: () => Promise<RenderResult> | RenderResult;
+    getNotificationManagerImpl?: () => NotificationManagerImpl;
+    getWindowManagerImpl?: () => WindowManagerImpl;
+}
+type ThemeManager = AddOnManager<void | Theme>;
+interface EditorConstructor {
+    readonly prototype: Editor;
+    new (id: string, options: RawEditorOptions, editorManager: EditorManager): Editor;
+}
+declare class Editor implements EditorObservable {
+    documentBaseUrl: string;
+    baseUri: URI;
+    id: string;
+    plugins: Record<string, Plugin>;
+    documentBaseURI: URI;
+    baseURI: URI;
+    contentCSS: string[];
+    contentStyles: string[];
+    ui: EditorUi;
+    mode: EditorMode;
+    options: Options;
+    editorUpload: EditorUpload;
+    shortcuts: Shortcuts;
+    loadedCSS: Record<string, any>;
+    editorCommands: EditorCommands;
+    suffix: string;
+    editorManager: EditorManager;
+    hidden: boolean;
+    inline: boolean;
+    hasVisual: boolean;
+    isNotDirty: boolean;
+    annotator: Annotator;
+    bodyElement: HTMLElement | undefined;
+    bookmark: any;
+    composing: boolean;
+    container: HTMLElement;
+    contentAreaContainer: HTMLElement;
+    contentDocument: Document;
+    contentWindow: Window;
+    delegates: Record<string, EventUtilsCallback<any>> | undefined;
+    destroyed: boolean;
+    dom: DOMUtils;
+    editorContainer: HTMLElement;
+    eventRoot: Element | undefined;
+    formatter: Formatter;
+    formElement: HTMLElement | undefined;
+    formEventDelegate: ((e: Event) => void) | undefined;
+    hasHiddenInput: boolean;
+    iframeElement: HTMLIFrameElement | null;
+    iframeHTML: string | undefined;
+    initialized: boolean;
+    notificationManager: NotificationManager;
+    orgDisplay: string;
+    orgVisibility: string | undefined;
+    parser: DomParser;
+    quirks: Quirks;
+    readonly: boolean;
+    removed: boolean;
+    schema: Schema;
+    selection: EditorSelection;
+    serializer: DomSerializer;
+    startContent: string;
+    targetElm: HTMLElement;
+    theme: Theme;
+    model: Model;
+    undoManager: UndoManager;
+    windowManager: WindowManager;
+    _beforeUnload: (() => void) | undefined;
+    _eventDispatcher: EventDispatcher<NativeEventMap> | undefined;
+    _nodeChangeDispatcher: NodeChange;
+    _pendingNativeEvents: string[];
+    _selectionOverrides: SelectionOverrides;
+    _skinLoaded: boolean;
+    _editableRoot: boolean;
+    bindPendingEventDelegates: EditorObservable['bindPendingEventDelegates'];
+    toggleNativeEvent: EditorObservable['toggleNativeEvent'];
+    unbindAllNativeEvents: EditorObservable['unbindAllNativeEvents'];
+    fire: EditorObservable['fire'];
+    dispatch: EditorObservable['dispatch'];
+    on: EditorObservable['on'];
+    off: EditorObservable['off'];
+    once: EditorObservable['once'];
+    hasEventListeners: EditorObservable['hasEventListeners'];
+    constructor(id: string, options: RawEditorOptions, editorManager: EditorManager);
+    render(): void;
+    focus(skipFocus?: boolean): void;
+    hasFocus(): boolean;
+    translate(text: Untranslated): TranslatedString;
+    getParam<K extends BuiltInOptionType>(name: string, defaultVal: BuiltInOptionTypeMap[K], type: K): BuiltInOptionTypeMap[K];
+    getParam<K extends keyof NormalizedEditorOptions>(name: K, defaultVal?: NormalizedEditorOptions[K], type?: BuiltInOptionType): NormalizedEditorOptions[K];
+    getParam<T>(name: string, defaultVal: T, type?: BuiltInOptionType): T;
+    hasPlugin(name: string, loaded?: boolean): boolean;
+    nodeChanged(args?: any): void;
+    addCommand<S>(name: string, callback: EditorCommandCallback<S>, scope: S): void;
+    addCommand(name: string, callback: EditorCommandCallback<Editor>): void;
+    addQueryStateHandler<S>(name: string, callback: (this: S) => boolean, scope?: S): void;
+    addQueryStateHandler(name: string, callback: (this: Editor) => boolean): void;
+    addQueryValueHandler<S>(name: string, callback: (this: S) => string, scope: S): void;
+    addQueryValueHandler(name: string, callback: (this: Editor) => string): void;
+    addShortcut(pattern: string, desc: string, cmdFunc: string | [
+        string,
+        boolean,
+        any
+    ] | (() => void), scope?: any): void;
+    execCommand(cmd: string, ui?: boolean, value?: any, args?: ExecCommandArgs): boolean;
+    queryCommandState(cmd: string): boolean;
+    queryCommandValue(cmd: string): string;
+    queryCommandSupported(cmd: string): boolean;
+    show(): void;
+    hide(): void;
+    isHidden(): boolean;
+    setProgressState(state: boolean, time?: number): void;
+    load(args?: Partial<SetContentArgs>): string;
+    save(args?: Partial<GetContentArgs>): string;
+    setContent(content: string, args?: Partial<SetContentArgs>): string;
+    setContent(content: AstNode, args?: Partial<SetContentArgs>): AstNode;
+    setContent(content: Content, args?: Partial<SetContentArgs>): Content;
+    getContent(args: {
+        format: 'tree';
+    } & Partial<GetContentArgs>): AstNode;
+    getContent(args?: Partial<GetContentArgs>): string;
+    insertContent(content: string, args?: any): void;
+    resetContent(initialContent?: string): void;
+    isDirty(): boolean;
+    setDirty(state: boolean): void;
+    getContainer(): HTMLElement;
+    getContentAreaContainer(): HTMLElement;
+    getElement(): HTMLElement;
+    getWin(): Window;
+    getDoc(): Document;
+    getBody(): HTMLElement;
+    convertURL(url: string, name: string, elm?: string | Element): string;
+    addVisual(elm?: HTMLElement): void;
+    setEditableRoot(state: boolean): void;
+    hasEditableRoot(): boolean;
+    remove(): void;
+    destroy(automatic?: boolean): void;
+    uploadImages(): Promise<UploadResult$1[]>;
+    _scanForImages(): Promise<BlobInfoImagePair[]>;
+}
+interface UrlObject {
+    prefix: string;
+    resource: string;
+    suffix: string;
+}
+type WaitState = 'added' | 'loaded';
+type AddOnConstructor<T> = (editor: Editor, url: string) => T;
+interface AddOnManager<T> {
+    items: AddOnConstructor<T>[];
+    urls: Record<string, string>;
+    lookup: Record<string, {
+        instance: AddOnConstructor<T>;
+    }>;
+    get: (name: string) => AddOnConstructor<T> | undefined;
+    requireLangPack: (name: string, languages?: string) => void;
+    add: (id: string, addOn: AddOnConstructor<T>) => AddOnConstructor<T>;
+    remove: (name: string) => void;
+    createUrl: (baseUrl: UrlObject, dep: string | UrlObject) => UrlObject;
+    load: (name: string, addOnUrl: string | UrlObject) => Promise<void>;
+    waitFor: (name: string, state?: WaitState) => Promise<void>;
+}
+interface RangeUtils {
+    walk: (rng: Range, callback: (nodes: Node[]) => void) => void;
+    split: (rng: Range) => RangeLikeObject;
+    normalize: (rng: Range) => boolean;
+    expand: (rng: Range, options?: {
+        type: 'word';
+    }) => Range;
+}
+interface ScriptLoaderSettings {
+    referrerPolicy?: ReferrerPolicy;
+}
+interface ScriptLoaderConstructor {
+    readonly prototype: ScriptLoader;
+    new (): ScriptLoader;
+    ScriptLoader: ScriptLoader;
+}
+declare class ScriptLoader {
+    static ScriptLoader: ScriptLoader;
+    private settings;
+    private states;
+    private queue;
+    private scriptLoadedCallbacks;
+    private queueLoadedCallbacks;
+    private loading;
+    constructor(settings?: ScriptLoaderSettings);
+    _setReferrerPolicy(referrerPolicy: ReferrerPolicy): void;
+    loadScript(url: string): Promise<void>;
+    isDone(url: string): boolean;
+    markDone(url: string): void;
+    add(url: string): Promise<void>;
+    load(url: string): Promise<void>;
+    remove(url: string): void;
+    loadQueue(): Promise<void>;
+    loadScripts(scripts: string[]): Promise<void>;
+}
+type TextProcessCallback = (node: Text, offset: number, text: string) => number;
+interface Spot {
+    container: Text;
+    offset: number;
+}
+interface TextSeeker {
+    backwards: (node: Node, offset: number, process: TextProcessCallback, root?: Node) => Spot | null;
+    forwards: (node: Node, offset: number, process: TextProcessCallback, root?: Node) => Spot | null;
+}
+interface DomTreeWalkerConstructor {
+    readonly prototype: DomTreeWalker;
+    new (startNode: Node, rootNode: Node): DomTreeWalker;
+}
+declare class DomTreeWalker {
+    private readonly rootNode;
+    private node;
+    constructor(startNode: Node, rootNode: Node);
+    current(): Node | null | undefined;
+    next(shallow?: boolean): Node | null | undefined;
+    prev(shallow?: boolean): Node | null | undefined;
+    prev2(shallow?: boolean): Node | null | undefined;
+    private findSibling;
+    private findPreviousNode;
+}
+interface Version {
+    major: number;
+    minor: number;
+}
+interface Env {
+    transparentSrc: string;
+    documentMode: number;
+    cacheSuffix: any;
+    container: any;
+    canHaveCSP: boolean;
+    windowsPhone: boolean;
+    browser: {
+        current: string | undefined;
+        version: Version;
+        isEdge: () => boolean;
+        isChromium: () => boolean;
+        isIE: () => boolean;
+        isOpera: () => boolean;
+        isFirefox: () => boolean;
+        isSafari: () => boolean;
+    };
+    os: {
+        current: string | undefined;
+        version: Version;
+        isWindows: () => boolean;
+        isiOS: () => boolean;
+        isAndroid: () => boolean;
+        isMacOS: () => boolean;
+        isLinux: () => boolean;
+        isSolaris: () => boolean;
+        isFreeBSD: () => boolean;
+        isChromeOS: () => boolean;
+    };
+    deviceType: {
+        isiPad: () => boolean;
+        isiPhone: () => boolean;
+        isTablet: () => boolean;
+        isPhone: () => boolean;
+        isTouch: () => boolean;
+        isWebView: () => boolean;
+        isDesktop: () => boolean;
+    };
+}
+interface FakeClipboardItem {
+    readonly items: Record<string, any>;
+    readonly types: ReadonlyArray<string>;
+    readonly getType: <D = any>(type: string) => D | undefined;
+}
+interface FakeClipboard {
+    readonly FakeClipboardItem: (items: Record<string, any>) => FakeClipboardItem;
+    readonly write: (data: FakeClipboardItem[]) => void;
+    readonly read: () => FakeClipboardItem[] | undefined;
+    readonly clear: () => void;
+}
+interface FocusManager {
+    isEditorUIElement: (elm: Element) => boolean;
+}
+interface EntitiesMap {
+    [name: string]: string;
+}
+interface Entities {
+    encodeRaw: (text: string, attr?: boolean) => string;
+    encodeAllRaw: (text: string) => string;
+    encodeNumeric: (text: string, attr?: boolean) => string;
+    encodeNamed: (text: string, attr?: boolean, entities?: EntitiesMap) => string;
+    getEncodeFunc: (name: string, entities?: string) => (text: string, attr?: boolean) => string;
+    decode: (text: string) => string;
+}
+interface IconPack {
+    icons: Record<string, string>;
+}
+interface IconManager {
+    add: (id: string, iconPack: IconPack) => void;
+    get: (id: string) => IconPack;
+    has: (id: string) => boolean;
+}
+interface Resource {
+    load: <T = any>(id: string, url: string) => Promise<T>;
+    add: (id: string, data: any) => void;
+    has: (id: string) => boolean;
+    get: (id: string) => any;
+    unload: (id: string) => void;
+}
+type TextPatterns_d_Pattern = Pattern;
+type TextPatterns_d_RawPattern = RawPattern;
+type TextPatterns_d_DynamicPatternsLookup = DynamicPatternsLookup;
+type TextPatterns_d_RawDynamicPatternsLookup = RawDynamicPatternsLookup;
+type TextPatterns_d_DynamicPatternContext = DynamicPatternContext;
+type TextPatterns_d_BlockCmdPattern = BlockCmdPattern;
+type TextPatterns_d_BlockPattern = BlockPattern;
+type TextPatterns_d_BlockFormatPattern = BlockFormatPattern;
+type TextPatterns_d_InlineCmdPattern = InlineCmdPattern;
+type TextPatterns_d_InlinePattern = InlinePattern;
+type TextPatterns_d_InlineFormatPattern = InlineFormatPattern;
+declare namespace TextPatterns_d {
+    export { TextPatterns_d_Pattern as Pattern, TextPatterns_d_RawPattern as RawPattern, TextPatterns_d_DynamicPatternsLookup as DynamicPatternsLookup, TextPatterns_d_RawDynamicPatternsLookup as RawDynamicPatternsLookup, TextPatterns_d_DynamicPatternContext as DynamicPatternContext, TextPatterns_d_BlockCmdPattern as BlockCmdPattern, TextPatterns_d_BlockPattern as BlockPattern, TextPatterns_d_BlockFormatPattern as BlockFormatPattern, TextPatterns_d_InlineCmdPattern as InlineCmdPattern, TextPatterns_d_InlinePattern as InlinePattern, TextPatterns_d_InlineFormatPattern as InlineFormatPattern, };
+}
+interface Delay {
+    setEditorInterval: (editor: Editor, callback: () => void, time?: number) => number;
+    setEditorTimeout: (editor: Editor, callback: () => void, time?: number) => number;
+}
+type UploadResult = UploadResult$2;
+interface ImageUploader {
+    upload: (blobInfos: BlobInfo[], showNotification?: boolean) => Promise<UploadResult[]>;
+}
+type ArrayCallback$1<T, R> = (this: any, x: T, i: number, xs: ArrayLike<T>) => R;
+type ObjCallback$1<T, R> = (this: any, value: T, key: string, obj: Record<string, T>) => R;
+type ArrayCallback<T, R> = ArrayCallback$1<T, R>;
+type ObjCallback<T, R> = ObjCallback$1<T, R>;
+type WalkCallback<T> = (this: any, o: T, i: string, n: keyof T | undefined) => boolean | void;
+interface Tools {
+    is: (obj: any, type?: string) => boolean;
+    isArray: <T>(arr: any) => arr is Array<T>;
+    inArray: <T>(arr: ArrayLike<T>, value: T) => number;
+    grep: {
+        <T>(arr: ArrayLike<T> | null | undefined, pred?: ArrayCallback<T, boolean>): T[];
+        <T>(arr: Record<string, T> | null | undefined, pred?: ObjCallback<T, boolean>): T[];
+    };
+    trim: (str: string | null | undefined) => string;
+    toArray: <T>(obj: ArrayLike<T>) => T[];
+    hasOwn: (obj: any, name: string) => boolean;
+    makeMap: (items: ArrayLike<string> | string | undefined, delim?: string | RegExp, map?: Record<string, {}>) => Record<string, {}>;
+    each: {
+        <T>(arr: ArrayLike<T> | null | undefined, cb: ArrayCallback<T, void | boolean>, scope?: any): boolean;
+        <T>(obj: Record<string, T> | null | undefined, cb: ObjCallback<T, void | boolean>, scope?: any): boolean;
+    };
+    map: {
+        <T, R>(arr: ArrayLike<T> | null | undefined, cb: ArrayCallback<T, R>): R[];
+        <T, R>(obj: Record<string, T> | null | undefined, cb: ObjCallback<T, R>): R[];
+    };
+    extend: (obj: Object, ext: Object, ...objs: Object[]) => any;
+    walk: <T extends Record<string, any>>(obj: T, f: WalkCallback<T>, n?: keyof T, scope?: any) => void;
+    resolve: (path: string, o?: Object) => any;
+    explode: (s: string | string[], d?: string | RegExp) => string[];
+    _addCacheSuffix: (url: string) => string;
+}
+interface KeyboardLikeEvent {
+    shiftKey: boolean;
+    ctrlKey: boolean;
+    altKey: boolean;
+    metaKey: boolean;
+}
+interface VK {
+    BACKSPACE: number;
+    DELETE: number;
+    DOWN: number;
+    ENTER: number;
+    ESC: number;
+    LEFT: number;
+    RIGHT: number;
+    SPACEBAR: number;
+    TAB: number;
+    UP: number;
+    PAGE_UP: number;
+    PAGE_DOWN: number;
+    END: number;
+    HOME: number;
+    modifierPressed: (e: KeyboardLikeEvent) => boolean;
+    metaKeyPressed: (e: KeyboardLikeEvent) => boolean;
+}
+interface DOMUtilsNamespace {
+    (doc: Document, settings: Partial<DOMUtilsSettings>): DOMUtils;
+    DOM: DOMUtils;
+    nodeIndex: (node: Node, normalized?: boolean) => number;
+}
+interface RangeUtilsNamespace {
+    (dom: DOMUtils): RangeUtils;
+    compareRanges: (rng1: RangeLikeObject, rng2: RangeLikeObject) => boolean;
+    getCaretRangeFromPoint: (clientX: number, clientY: number, doc: Document) => Range;
+    getSelectedNode: (range: Range) => Node;
+    getNode: (container: Node, offset: number) => Node;
+}
+interface AddOnManagerNamespace {
+    <T>(): AddOnManager<T>;
+    language: string | undefined;
+    languageLoad: boolean;
+    baseURL: string;
+    PluginManager: PluginManager;
+    ThemeManager: ThemeManager;
+    ModelManager: ModelManager;
+}
+interface BookmarkManagerNamespace {
+    (selection: EditorSelection): BookmarkManager;
+    isBookmarkNode: (node: Node) => boolean;
+}
+interface TinyMCE extends EditorManager {
+    geom: {
+        Rect: Rect;
+    };
+    util: {
+        Delay: Delay;
+        Tools: Tools;
+        VK: VK;
+        URI: URIConstructor;
+        EventDispatcher: EventDispatcherConstructor<any>;
+        Observable: Observable<any>;
+        I18n: I18n;
+        LocalStorage: Storage;
+        ImageUploader: ImageUploader;
+    };
+    dom: {
+        EventUtils: EventUtilsConstructor;
+        TreeWalker: DomTreeWalkerConstructor;
+        TextSeeker: (dom: DOMUtils, isBlockBoundary?: (node: Node) => boolean) => TextSeeker;
+        DOMUtils: DOMUtilsNamespace;
+        ScriptLoader: ScriptLoaderConstructor;
+        RangeUtils: RangeUtilsNamespace;
+        Serializer: (settings: DomSerializerSettings, editor?: Editor) => DomSerializer;
+        ControlSelection: (selection: EditorSelection, editor: Editor) => ControlSelection;
+        BookmarkManager: BookmarkManagerNamespace;
+        Selection: (dom: DOMUtils, win: Window, serializer: DomSerializer, editor: Editor) => EditorSelection;
+        StyleSheetLoader: (documentOrShadowRoot: Document | ShadowRoot, settings: StyleSheetLoaderSettings) => StyleSheetLoader;
+        Event: EventUtils;
+    };
+    html: {
+        Styles: (settings?: StylesSettings, schema?: Schema) => Styles;
+        Entities: Entities;
+        Node: AstNodeConstructor;
+        Schema: (settings?: SchemaSettings) => Schema;
+        DomParser: (settings?: DomParserSettings, schema?: Schema) => DomParser;
+        Writer: (settings?: WriterSettings) => Writer;
+        Serializer: (settings?: HtmlSerializerSettings, schema?: Schema) => HtmlSerializer;
+    };
+    AddOnManager: AddOnManagerNamespace;
+    Annotator: (editor: Editor) => Annotator;
+    Editor: EditorConstructor;
+    EditorCommands: EditorCommandsConstructor;
+    EditorManager: EditorManager;
+    EditorObservable: EditorObservable;
+    Env: Env;
+    FocusManager: FocusManager;
+    Formatter: (editor: Editor) => Formatter;
+    NotificationManager: (editor: Editor) => NotificationManager;
+    Shortcuts: ShortcutsConstructor;
+    UndoManager: (editor: Editor) => UndoManager;
+    WindowManager: (editor: Editor) => WindowManager;
+    DOM: DOMUtils;
+    ScriptLoader: ScriptLoader;
+    PluginManager: PluginManager;
+    ThemeManager: ThemeManager;
+    ModelManager: ModelManager;
+    IconManager: IconManager;
+    Resource: Resource;
+    FakeClipboard: FakeClipboard;
+    trim: Tools['trim'];
+    isArray: Tools['isArray'];
+    is: Tools['is'];
+    toArray: Tools['toArray'];
+    makeMap: Tools['makeMap'];
+    each: Tools['each'];
+    map: Tools['map'];
+    grep: Tools['grep'];
+    inArray: Tools['inArray'];
+    extend: Tools['extend'];
+    walk: Tools['walk'];
+    resolve: Tools['resolve'];
+    explode: Tools['explode'];
+    _addCacheSuffix: Tools['_addCacheSuffix'];
+}
+declare const tinymce: TinyMCE;
+export { AddOnManager, Annotator, AstNode, Bookmark, BookmarkManager, ControlSelection, DOMUtils, Delay, DomParser, DomParserSettings, DomSerializer, DomSerializerSettings, DomTreeWalker, Editor, EditorCommands, EditorEvent, EditorManager, EditorModeApi, EditorObservable, EditorOptions, EditorSelection, Entities, Env, EventDispatcher, EventUtils, EventTypes_d as Events, FakeClipboard, FocusManager, Format_d as Formats, Formatter, GeomRect, HtmlSerializer, HtmlSerializerSettings, I18n, IconManager, Model, ModelManager, NotificationApi, NotificationManager, NotificationSpec, Observable, Plugin, PluginManager, RangeUtils, RawEditorOptions, Rect, Resource, Schema, SchemaSettings, ScriptLoader, Shortcuts, StyleSheetLoader, Styles, TextPatterns_d as TextPatterns, TextSeeker, Theme, ThemeManager, TinyMCE, Tools, URI, Ui_d as Ui, UndoManager, VK, WindowManager, Writer, WriterSettings, tinymce as default };
diff --git a/eims-ui/apps/web-antd/public/tinymce/tinymce.min.js b/eims-ui/apps/web-antd/public/tinymce/tinymce.min.js
new file mode 100644
index 0000000..70d9969
--- /dev/null
+++ b/eims-ui/apps/web-antd/public/tinymce/tinymce.min.js
@@ -0,0 +1,4 @@
+/**
+ * TinyMCE version 7.2.1 (2024-07-03)
+ */
+!function(){"use strict";var e=function(e){if(null===e)return"null";if(void 0===e)return"undefined";var t=typeof e;return"object"===t&&(Array.prototype.isPrototypeOf(e)||e.constructor&&"Array"===e.constructor.name)?"array":"object"===t&&(String.prototype.isPrototypeOf(e)||e.constructor&&"String"===e.constructor.name)?"string":t},t=function(e){return{eq:e}},n=t((function(e,t){return e===t})),o=function(e){return t((function(t,n){if(t.length!==n.length)return!1;for(var o=t.length,r=0;r<o;r++)if(!e.eq(t[r],n[r]))return!1;return!0}))},r=function(e){return t((function(r,s){var a=Object.keys(r),i=Object.keys(s);if(!function(e,n){return function(e,n){return t((function(t,o){return e.eq(n(t),n(o))}))}(o(e),(function(e){return function(e,t){return Array.prototype.slice.call(e).sort(t)}(e,n)}))}(n).eq(a,i))return!1;for(var l=a.length,d=0;d<l;d++){var c=a[d];if(!e.eq(r[c],s[c]))return!1}return!0}))},s=t((function(t,n){if(t===n)return!0;var a=e(t);return a===e(n)&&(function(e){return-1!==["undefined","boolean","number","string","function","xml","null"].indexOf(e)}(a)?t===n:"array"===a?o(s).eq(t,n):"object"===a&&r(s).eq(t,n))}));const a=Object.getPrototypeOf,i=(e,t,n)=>{var o;return!!n(e,t.prototype)||(null===(o=e.constructor)||void 0===o?void 0:o.name)===t.name},l=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&i(e,String,((e,t)=>t.isPrototypeOf(e)))?"string":t})(t)===e,d=e=>t=>typeof t===e,c=e=>t=>e===t,u=(e,t)=>f(e)&&i(e,t,((e,t)=>a(e)===t)),m=l("string"),f=l("object"),g=e=>u(e,Object),p=l("array"),h=c(null),b=d("boolean"),v=c(void 0),y=e=>null==e,C=e=>!y(e),w=d("function"),E=d("number"),x=(e,t)=>{if(p(e)){for(let n=0,o=e.length;n<o;++n)if(!t(e[n]))return!1;return!0}return!1},k=()=>{},_=(e,t)=>(...n)=>e(t.apply(null,n)),S=(e,t)=>n=>e(t(n)),N=e=>()=>e,R=e=>e,A=(e,t)=>e===t;function T(e,...t){return(...n)=>{const o=t.concat(n);return e.apply(null,o)}}const O=e=>t=>!e(t),B=e=>()=>{throw new Error(e)},P=e=>e(),D=e=>{e()},L=N(!1),M=N(!0);class I{constructor(e,t){this.tag=e,this.value=t}static some(e){return new I(!0,e)}static none(){return I.singletonNone}fold(e,t){return this.tag?t(this.value):e()}isSome(){return this.tag}isNone(){return!this.tag}map(e){return this.tag?I.some(e(this.value)):I.none()}bind(e){return this.tag?e(this.value):I.none()}exists(e){return this.tag&&e(this.value)}forall(e){return!this.tag||e(this.value)}filter(e){return!this.tag||e(this.value)?this:I.none()}getOr(e){return this.tag?this.value:e}or(e){return this.tag?this:e}getOrThunk(e){return this.tag?this.value:e()}orThunk(e){return this.tag?this:e()}getOrDie(e){if(this.tag)return this.value;throw new Error(null!=e?e:"Called getOrDie on None")}static from(e){return C(e)?I.some(e):I.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(e){this.tag&&e(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}I.singletonNone=new I(!1);const F=Array.prototype.slice,U=Array.prototype.indexOf,z=Array.prototype.push,j=(e,t)=>U.call(e,t),H=(e,t)=>j(e,t)>-1,$=(e,t)=>{for(let n=0,o=e.length;n<o;n++)if(t(e[n],n))return!0;return!1},V=(e,t)=>{const n=e.length,o=new Array(n);for(let r=0;r<n;r++){const n=e[r];o[r]=t(n,r)}return o},q=(e,t)=>{for(let n=0,o=e.length;n<o;n++)t(e[n],n)},W=(e,t)=>{for(let n=e.length-1;n>=0;n--)t(e[n],n)},K=(e,t)=>{const n=[],o=[];for(let r=0,s=e.length;r<s;r++){const s=e[r];(t(s,r)?n:o).push(s)}return{pass:n,fail:o}},Y=(e,t)=>{const n=[];for(let o=0,r=e.length;o<r;o++){const r=e[o];t(r,o)&&n.push(r)}return n},G=(e,t,n)=>(W(e,((e,o)=>{n=t(n,e,o)})),n),X=(e,t,n)=>(q(e,((e,o)=>{n=t(n,e,o)})),n),Z=(e,t,n)=>{for(let o=0,r=e.length;o<r;o++){const r=e[o];if(t(r,o))return I.some(r);if(n(r,o))break}return I.none()},Q=(e,t)=>Z(e,t,L),J=(e,t)=>{for(let n=0,o=e.length;n<o;n++)if(t(e[n],n))return I.some(n);return I.none()},ee=e=>{const t=[];for(let n=0,o=e.length;n<o;++n){if(!p(e[n]))throw new Error("Arr.flatten item "+n+" was not an array, input: "+e);z.apply(t,e[n])}return t},te=(e,t)=>ee(V(e,t)),ne=(e,t)=>{for(let n=0,o=e.length;n<o;++n)if(!0!==t(e[n],n))return!1;return!0},oe=e=>{const t=F.call(e,0);return t.reverse(),t},re=(e,t)=>Y(e,(e=>!H(t,e))),se=(e,t)=>{const n={};for(let o=0,r=e.length;o<r;o++){const r=e[o];n[String(r)]=t(r,o)}return n},ae=(e,t)=>{const n=F.call(e,0);return n.sort(t),n},ie=(e,t)=>t>=0&&t<e.length?I.some(e[t]):I.none(),le=e=>ie(e,0),de=e=>ie(e,e.length-1),ce=w(Array.from)?Array.from:e=>F.call(e),ue=(e,t)=>{for(let n=0;n<e.length;n++){const o=t(e[n],n);if(o.isSome())return o}return I.none()},me=(e,t)=>{const n=[],o=w(t)?e=>$(n,(n=>t(n,e))):e=>H(n,e);for(let t=0,r=e.length;t<r;t++){const r=e[t];o(r)||n.push(r)}return n},fe=Object.keys,ge=Object.hasOwnProperty,pe=(e,t)=>{const n=fe(e);for(let o=0,r=n.length;o<r;o++){const r=n[o];t(e[r],r)}},he=(e,t)=>be(e,((e,n)=>({k:n,v:t(e,n)}))),be=(e,t)=>{const n={};return pe(e,((e,o)=>{const r=t(e,o);n[r.k]=r.v})),n},ve=e=>(t,n)=>{e[n]=t},ye=(e,t,n,o)=>{pe(e,((e,r)=>{(t(e,r)?n:o)(e,r)}))},Ce=(e,t)=>{const n={};return ye(e,t,ve(n),k),n},we=(e,t)=>{const n=[];return pe(e,((e,o)=>{n.push(t(e,o))})),n},Ee=e=>we(e,R),xe=(e,t)=>ke(e,t)?I.from(e[t]):I.none(),ke=(e,t)=>ge.call(e,t),_e=(e,t)=>ke(e,t)&&void 0!==e[t]&&null!==e[t],Se=e=>{const t={};return q(e,(e=>{t[e]={}})),fe(t)},Ne=e=>void 0!==e.length,Re=Array.isArray,Ae=(e,t,n)=>{if(!e)return!1;if(n=n||e,Ne(e)){for(let o=0,r=e.length;o<r;o++)if(!1===t.call(n,e[o],o,e))return!1}else for(const o in e)if(ke(e,o)&&!1===t.call(n,e[o],o,e))return!1;return!0},Te=(e,t)=>{const n=[];return Ae(e,((o,r)=>{n.push(t(o,r,e))})),n},Oe=(e,t)=>{const n=[];return Ae(e,((o,r)=>{t&&!t(o,r,e)||n.push(o)})),n},Be=(e,t,n,o)=>{let r=v(n)?e[0]:n;for(let n=0;n<e.length;n++)r=t.call(o,r,e[n],n);return r},Pe=(e,t,n)=>{for(let o=0,r=e.length;o<r;o++)if(t.call(n,e[o],o,e))return o;return-1},De=e=>e[e.length-1],Le=e=>{let t,n=!1;return(...o)=>(n||(n=!0,t=e.apply(null,o)),t)},Me=()=>Ie(0,0),Ie=(e,t)=>({major:e,minor:t}),Fe={nu:Ie,detect:(e,t)=>{const n=String(t).toLowerCase();return 0===e.length?Me():((e,t)=>{const n=((e,t)=>{for(let n=0;n<e.length;n++){const o=e[n];if(o.test(t))return o}})(e,t);if(!n)return{major:0,minor:0};const o=e=>Number(t.replace(n,"$"+e));return Ie(o(1),o(2))})(e,n)},unknown:Me},Ue=(e,t)=>{const n=String(t).toLowerCase();return Q(e,(e=>e.search(n)))},ze=(e,t,n)=>""===t||e.length>=t.length&&e.substr(n,n+t.length)===t,je=(e,t)=>$e(e,t)?((e,t)=>e.substring(t))(e,t.length):e,He=(e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!v(o)||r+t.length<=o)},$e=(e,t)=>ze(e,t,0),Ve=(e,t)=>ze(e,t,e.length-t.length),qe=e=>t=>t.replace(e,""),We=qe(/^\s+|\s+$/g),Ke=qe(/^\s+/g),Ye=qe(/\s+$/g),Ge=e=>e.length>0,Xe=e=>!Ge(e),Ze=(e,t=10)=>{const n=parseInt(e,t);return isNaN(n)?I.none():I.some(n)},Qe=/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,Je=e=>t=>He(t,e),et=[{name:"Edge",versionRegexes:[/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],search:e=>He(e,"edge/")&&He(e,"chrome")&&He(e,"safari")&&He(e,"applewebkit")},{name:"Chromium",brand:"Chromium",versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/,Qe],search:e=>He(e,"chrome")&&!He(e,"chromeframe")},{name:"IE",versionRegexes:[/.*?msie\ ?([0-9]+)\.([0-9]+).*/,/.*?rv:([0-9]+)\.([0-9]+).*/],search:e=>He(e,"msie")||He(e,"trident")},{name:"Opera",versionRegexes:[Qe,/.*?opera\/([0-9]+)\.([0-9]+).*/],search:Je("opera")},{name:"Firefox",versionRegexes:[/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],search:Je("firefox")},{name:"Safari",versionRegexes:[Qe,/.*?cpu os ([0-9]+)_([0-9]+).*/],search:e=>(He(e,"safari")||He(e,"mobile/"))&&He(e,"applewebkit")}],tt=[{name:"Windows",search:Je("win"),versionRegexes:[/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]},{name:"iOS",search:e=>He(e,"iphone")||He(e,"ipad"),versionRegexes:[/.*?version\/\ ?([0-9]+)\.([0-9]+).*/,/.*cpu os ([0-9]+)_([0-9]+).*/,/.*cpu iphone os ([0-9]+)_([0-9]+).*/]},{name:"Android",search:Je("android"),versionRegexes:[/.*?android\ ?([0-9]+)\.([0-9]+).*/]},{name:"macOS",search:Je("mac os x"),versionRegexes:[/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]},{name:"Linux",search:Je("linux"),versionRegexes:[]},{name:"Solaris",search:Je("sunos"),versionRegexes:[]},{name:"FreeBSD",search:Je("freebsd"),versionRegexes:[]},{name:"ChromeOS",search:Je("cros"),versionRegexes:[/.*?chrome\/([0-9]+)\.([0-9]+).*/]}],nt={browsers:N(et),oses:N(tt)},ot="Edge",rt="Chromium",st="Opera",at="Firefox",it="Safari",lt=e=>{const t=e.current,n=e.version,o=e=>()=>t===e;return{current:t,version:n,isEdge:o(ot),isChromium:o(rt),isIE:o("IE"),isOpera:o(st),isFirefox:o(at),isSafari:o(it)}},dt=()=>lt({current:void 0,version:Fe.unknown()}),ct=lt,ut=(N(ot),N(rt),N("IE"),N(st),N(at),N(it),"Windows"),mt="Android",ft="Linux",gt="macOS",pt="Solaris",ht="FreeBSD",bt="ChromeOS",vt=e=>{const t=e.current,n=e.version,o=e=>()=>t===e;return{current:t,version:n,isWindows:o(ut),isiOS:o("iOS"),isAndroid:o(mt),isMacOS:o(gt),isLinux:o(ft),isSolaris:o(pt),isFreeBSD:o(ht),isChromeOS:o(bt)}},yt=()=>vt({current:void 0,version:Fe.unknown()}),Ct=vt,wt=(N(ut),N("iOS"),N(mt),N(ft),N(gt),N(pt),N(ht),N(bt),e=>window.matchMedia(e).matches);let Et=Le((()=>((e,t,n)=>{const o=nt.browsers(),r=nt.oses(),s=t.bind((e=>((e,t)=>ue(t.brands,(t=>{const n=t.brand.toLowerCase();return Q(e,(e=>{var t;return n===(null===(t=e.brand)||void 0===t?void 0:t.toLowerCase())})).map((e=>({current:e.name,version:Fe.nu(parseInt(t.version,10),0)})))})))(o,e))).orThunk((()=>((e,t)=>Ue(e,t).map((e=>{const n=Fe.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(o,e))).fold(dt,ct),a=((e,t)=>Ue(e,t).map((e=>{const n=Fe.detect(e.versionRegexes,t);return{current:e.name,version:n}})))(r,e).fold(yt,Ct),i=((e,t,n,o)=>{const r=e.isiOS()&&!0===/ipad/i.test(n),s=e.isiOS()&&!r,a=e.isiOS()||e.isAndroid(),i=a||o("(pointer:coarse)"),l=r||!s&&a&&o("(min-device-width:768px)"),d=s||a&&!l,c=t.isSafari()&&e.isiOS()&&!1===/safari/i.test(n),u=!d&&!l&&!c;return{isiPad:N(r),isiPhone:N(s),isTablet:N(l),isPhone:N(d),isTouch:N(i),isAndroid:e.isAndroid,isiOS:e.isiOS,isWebView:N(c),isDesktop:N(u)}})(a,s,e,n);return{browser:s,os:a,deviceType:i}})(navigator.userAgent,I.from(navigator.userAgentData),wt)));const xt=()=>Et(),kt=navigator.userAgent,_t=xt(),St=_t.browser,Nt=_t.os,Rt=_t.deviceType,At=-1!==kt.indexOf("Windows Phone"),Tt={transparentSrc:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",documentMode:St.isIE()?document.documentMode||7:10,cacheSuffix:null,container:null,canHaveCSP:!St.isIE(),windowsPhone:At,browser:{current:St.current,version:St.version,isChromium:St.isChromium,isEdge:St.isEdge,isFirefox:St.isFirefox,isIE:St.isIE,isOpera:St.isOpera,isSafari:St.isSafari},os:{current:Nt.current,version:Nt.version,isAndroid:Nt.isAndroid,isChromeOS:Nt.isChromeOS,isFreeBSD:Nt.isFreeBSD,isiOS:Nt.isiOS,isLinux:Nt.isLinux,isMacOS:Nt.isMacOS,isSolaris:Nt.isSolaris,isWindows:Nt.isWindows},deviceType:{isDesktop:Rt.isDesktop,isiPad:Rt.isiPad,isiPhone:Rt.isiPhone,isPhone:Rt.isPhone,isTablet:Rt.isTablet,isTouch:Rt.isTouch,isWebView:Rt.isWebView}},Ot=/^\s*|\s*$/g,Bt=e=>y(e)?"":(""+e).replace(Ot,""),Pt=function(e,t,n,o){o=o||this,e&&(n&&(e=e[n]),Ae(e,((e,r)=>!1!==t.call(o,e,r,n)&&(Pt(e,t,n,o),!0))))},Dt={trim:Bt,isArray:Re,is:(e,t)=>t?!("array"!==t||!Re(e))||typeof e===t:void 0!==e,toArray:e=>{if(Re(e))return e;{const t=[];for(let n=0,o=e.length;n<o;n++)t[n]=e[n];return t}},makeMap:(e,t,n={})=>{const o=m(e)?e.split(t||","):e||[];let r=o.length;for(;r--;)n[o[r]]={};return n},each:Ae,map:Te,grep:Oe,inArray:(e,t)=>{if(e)for(let n=0,o=e.length;n<o;n++)if(e[n]===t)return n;return-1},hasOwn:ke,extend:(e,...t)=>{for(let n=0;n<t.length;n++){const o=t[n];for(const t in o)if(ke(o,t)){const n=o[t];void 0!==n&&(e[t]=n)}}return e},walk:Pt,resolve:(e,t=window)=>{const n=e.split(".");for(let e=0,o=n.length;e<o&&(t=t[n[e]]);e++);return t},explode:(e,t)=>p(e)?e:""===e?[]:Te(e.split(t||","),Bt),_addCacheSuffix:e=>{const t=Tt.cacheSuffix;return t&&(e+=(-1===e.indexOf("?")?"?":"&")+t),e}},Lt=(e,t,n=A)=>e.exists((e=>n(e,t))),Mt=(e,t,n=A)=>It(e,t,n).getOr(e.isNone()&&t.isNone()),It=(e,t,n)=>e.isSome()&&t.isSome()?I.some(n(e.getOrDie(),t.getOrDie())):I.none(),Ft=(e,t)=>e?I.some(t):I.none(),Ut="undefined"!=typeof window?window:Function("return this;")(),zt=(e,t)=>((e,t)=>{let n=null!=t?t:Ut;for(let t=0;t<e.length&&null!=n;++t)n=n[e[t]];return n})(e.split("."),t),jt=Object.getPrototypeOf,Ht=e=>{const t=zt("ownerDocument.defaultView",e);return f(e)&&((e=>((e,t)=>{const n=((e,t)=>zt(e,t))(e,t);if(null==n)throw new Error(e+" not available on this browser");return n})("HTMLElement",e))(t).prototype.isPrototypeOf(e)||/^HTML\w*Element$/.test(jt(e).constructor.name))},$t=e=>e.dom.nodeName.toLowerCase(),Vt=e=>e.dom.nodeType,qt=e=>t=>Vt(t)===e,Wt=e=>Kt(e)&&Ht(e.dom),Kt=qt(1),Yt=qt(3),Gt=qt(9),Xt=qt(11),Zt=e=>t=>Kt(t)&&$t(t)===e,Qt=(e,t,n)=>{if(!(m(n)||b(n)||E(n)))throw console.error("Invalid call to Attribute.set. Key ",t,":: Value ",n,":: Element ",e),new Error("Attribute value was not simple");e.setAttribute(t,n+"")},Jt=(e,t,n)=>{Qt(e.dom,t,n)},en=(e,t)=>{const n=e.dom;pe(t,((e,t)=>{Qt(n,t,e)}))},tn=(e,t)=>{const n=e.dom.getAttribute(t);return null===n?void 0:n},nn=(e,t)=>I.from(tn(e,t)),on=(e,t)=>{const n=e.dom;return!(!n||!n.hasAttribute)&&n.hasAttribute(t)},rn=(e,t)=>{e.dom.removeAttribute(t)},sn=e=>X(e.dom.attributes,((e,t)=>(e[t.name]=t.value,e)),{}),an=(e,t)=>{const n=tn(e,t);return void 0===n||""===n?[]:n.split(" ")},ln=e=>void 0!==e.dom.classList,dn=e=>an(e,"class"),cn=(e,t)=>((e,t,n)=>{const o=an(e,t).concat([n]);return Jt(e,t,o.join(" ")),!0})(e,"class",t),un=(e,t)=>((e,t,n)=>{const o=Y(an(e,t),(e=>e!==n));return o.length>0?Jt(e,t,o.join(" ")):rn(e,t),!1})(e,"class",t),mn=(e,t)=>{ln(e)?e.dom.classList.add(t):cn(e,t)},fn=e=>{0===(ln(e)?e.dom.classList:dn(e)).length&&rn(e,"class")},gn=(e,t)=>{ln(e)?e.dom.classList.remove(t):un(e,t),fn(e)},pn=(e,t)=>ln(e)&&e.dom.classList.contains(t),hn=e=>{if(null==e)throw new Error("Node cannot be null or undefined");return{dom:e}},bn=(e,t)=>{const n=(t||document).createElement("div");if(n.innerHTML=e,!n.hasChildNodes()||n.childNodes.length>1){const t="HTML does not have a single root node";throw console.error(t,e),new Error(t)}return hn(n.childNodes[0])},vn=(e,t)=>{const n=(t||document).createElement(e);return hn(n)},yn=(e,t)=>{const n=(t||document).createTextNode(e);return hn(n)},Cn=hn,wn=(e,t,n)=>I.from(e.dom.elementFromPoint(t,n)).map(hn),En=(e,t)=>{const n=[],o=e=>(n.push(e),t(e));let r=t(e);do{r=r.bind(o)}while(r.isSome());return n},xn=(e,t)=>{const n=e.dom;if(1!==n.nodeType)return!1;{const e=n;if(void 0!==e.matches)return e.matches(t);if(void 0!==e.msMatchesSelector)return e.msMatchesSelector(t);if(void 0!==e.webkitMatchesSelector)return e.webkitMatchesSelector(t);if(void 0!==e.mozMatchesSelector)return e.mozMatchesSelector(t);throw new Error("Browser lacks native selectors")}},kn=e=>1!==e.nodeType&&9!==e.nodeType&&11!==e.nodeType||0===e.childElementCount,_n=(e,t)=>e.dom===t.dom,Sn=(e,t)=>{const n=e.dom,o=t.dom;return n!==o&&n.contains(o)},Nn=e=>Cn(e.dom.ownerDocument),Rn=e=>Gt(e)?e:Nn(e),An=e=>Cn(Rn(e).dom.defaultView),Tn=e=>I.from(e.dom.parentNode).map(Cn),On=e=>I.from(e.dom.parentElement).map(Cn),Bn=(e,t)=>{const n=w(t)?t:L;let o=e.dom;const r=[];for(;null!==o.parentNode&&void 0!==o.parentNode;){const e=o.parentNode,t=Cn(e);if(r.push(t),!0===n(t))break;o=e}return r},Pn=e=>I.from(e.dom.previousSibling).map(Cn),Dn=e=>I.from(e.dom.nextSibling).map(Cn),Ln=e=>oe(En(e,Pn)),Mn=e=>En(e,Dn),In=e=>V(e.dom.childNodes,Cn),Fn=(e,t)=>{const n=e.dom.childNodes;return I.from(n[t]).map(Cn)},Un=e=>Fn(e,0),zn=e=>Fn(e,e.dom.childNodes.length-1),jn=e=>e.dom.childNodes.length,Hn=e=>Xt(e)&&C(e.dom.host),$n=w(Element.prototype.attachShadow)&&w(Node.prototype.getRootNode),Vn=N($n),qn=$n?e=>Cn(e.dom.getRootNode()):Rn,Wn=e=>Hn(e)?e:(e=>{const t=e.dom.head;if(null==t)throw new Error("Head is not available yet");return Cn(t)})(Rn(e)),Kn=e=>Cn(e.dom.host),Yn=e=>{if(Vn()&&C(e.target)){const t=Cn(e.target);if(Kt(t)&&Gn(t)&&e.composed&&e.composedPath){const t=e.composedPath();if(t)return le(t)}}return I.from(e.target)},Gn=e=>C(e.dom.shadowRoot),Xn=e=>{const t=Yt(e)?e.dom.parentNode:e.dom;if(null==t||null===t.ownerDocument)return!1;const n=t.ownerDocument;return(e=>{const t=qn(e);return Hn(t)?I.some(t):I.none()})(Cn(t)).fold((()=>n.body.contains(t)),S(Xn,Kn))};var Zn=(e,t,n,o,r)=>e(n,o)?I.some(n):w(r)&&r(n)?I.none():t(n,o,r);const Qn=(e,t,n)=>{let o=e.dom;const r=w(n)?n:L;for(;o.parentNode;){o=o.parentNode;const e=Cn(o);if(t(e))return I.some(e);if(r(e))break}return I.none()},Jn=(e,t,n)=>Zn(((e,t)=>t(e)),Qn,e,t,n),eo=(e,t)=>{const n=e=>{for(let o=0;o<e.childNodes.length;o++){const r=Cn(e.childNodes[o]);if(t(r))return I.some(r);const s=n(e.childNodes[o]);if(s.isSome())return s}return I.none()};return n(e.dom)},to=(e,t,n)=>Qn(e,(e=>xn(e,t)),n),no=(e,t)=>((e,t)=>{const n=void 0===t?document:t.dom;return kn(n)?I.none():I.from(n.querySelector(e)).map(Cn)})(t,e),oo=(e,t,n)=>Zn(((e,t)=>xn(e,t)),to,e,t,n),ro=(e,t=!1)=>{return Xn(e)?e.dom.isContentEditable:(n=e,oo(n,"[contenteditable]")).fold(N(t),(e=>"true"===so(e)));var n},so=e=>e.dom.contentEditable,ao=e=>void 0!==e.style&&w(e.style.getPropertyValue),io=(e,t,n)=>{if(!m(n))throw console.error("Invalid call to CSS.set. Property ",t,":: Value ",n,":: Element ",e),new Error("CSS value must be a string: "+n);ao(e)&&e.style.setProperty(t,n)},lo=(e,t,n)=>{const o=e.dom;io(o,t,n)},co=(e,t)=>{const n=e.dom;pe(t,((e,t)=>{io(n,t,e)}))},uo=(e,t)=>{const n=e.dom,o=window.getComputedStyle(n).getPropertyValue(t);return""!==o||Xn(e)?o:mo(n,t)},mo=(e,t)=>ao(e)?e.style.getPropertyValue(t):"",fo=(e,t)=>{const n=e.dom,o=mo(n,t);return I.from(o).filter((e=>e.length>0))},go=e=>{const t={},n=e.dom;if(ao(n))for(let e=0;e<n.style.length;e++){const o=n.style.item(e);t[o]=n.style[o]}return t},po=(e,t)=>{((e,t)=>{ao(e)&&e.style.removeProperty(t)})(e.dom,t),Lt(nn(e,"style").map(We),"")&&rn(e,"style")},ho=(e,t)=>{Tn(e).each((n=>{n.dom.insertBefore(t.dom,e.dom)}))},bo=(e,t)=>{Dn(e).fold((()=>{Tn(e).each((e=>{yo(e,t)}))}),(e=>{ho(e,t)}))},vo=(e,t)=>{Un(e).fold((()=>{yo(e,t)}),(n=>{e.dom.insertBefore(t.dom,n.dom)}))},yo=(e,t)=>{e.dom.appendChild(t.dom)},Co=(e,t)=>{ho(e,t),yo(t,e)},wo=(e,t)=>{q(t,(t=>{yo(e,t)}))},Eo=e=>{e.dom.textContent="",q(In(e),(e=>{xo(e)}))},xo=e=>{const t=e.dom;null!==t.parentNode&&t.parentNode.removeChild(t)},ko=e=>{const t=In(e);var n,o;t.length>0&&(n=e,q(o=t,((e,t)=>{const r=0===t?n:o[t-1];bo(r,e)}))),xo(e)},_o=e=>V(e,Cn),So=e=>e.dom.innerHTML,No=(e,t)=>{const n=Nn(e).dom,o=Cn(n.createDocumentFragment()),r=((e,t)=>{const n=(t||document).createElement("div");return n.innerHTML=e,In(Cn(n))})(t,n);wo(o,r),Eo(e),yo(e,o)},Ro=(e,t,n,o)=>((e,t,n,o,r)=>{const s=((e,t)=>n=>{e(n)&&t((e=>{const t=Cn(Yn(e).getOr(e.target)),n=()=>e.stopPropagation(),o=()=>e.preventDefault(),r=_(o,n);return((e,t,n,o,r,s,a)=>({target:e,x:t,y:n,stop:o,prevent:r,kill:s,raw:a}))(t,e.clientX,e.clientY,n,o,r,e)})(n))})(n,o);return e.dom.addEventListener(t,s,false),{unbind:T(Ao,e,t,s,false)}})(e,t,n,o),Ao=(e,t,n,o)=>{e.dom.removeEventListener(t,n,o)},To=(e,t)=>({left:e,top:t,translate:(n,o)=>To(e+n,t+o)}),Oo=To,Bo=(e,t)=>void 0!==e?e:void 0!==t?t:0,Po=e=>{const t=e.dom,n=t.ownerDocument.body;return n===t?Oo(n.offsetLeft,n.offsetTop):Xn(e)?(e=>{const t=e.getBoundingClientRect();return Oo(t.left,t.top)})(t):Oo(0,0)},Do=e=>{const t=void 0!==e?e.dom:document,n=t.body.scrollLeft||t.documentElement.scrollLeft,o=t.body.scrollTop||t.documentElement.scrollTop;return Oo(n,o)},Lo=(e,t,n)=>{const o=(void 0!==n?n.dom:document).defaultView;o&&o.scrollTo(e,t)},Mo=(e,t)=>{xt().browser.isSafari()&&w(e.dom.scrollIntoViewIfNeeded)?e.dom.scrollIntoViewIfNeeded(!1):e.dom.scrollIntoView(t)},Io=(e,t,n,o)=>({x:e,y:t,width:n,height:o,right:e+n,bottom:t+o}),Fo=e=>{const t=void 0===e?window:e,n=t.document,o=Do(Cn(n));return(e=>{const t=void 0===e?window:e;return xt().browser.isFirefox()?I.none():I.from(t.visualViewport)})(t).fold((()=>{const e=t.document.documentElement,n=e.clientWidth,r=e.clientHeight;return Io(o.left,o.top,n,r)}),(e=>Io(Math.max(e.pageLeft,o.left),Math.max(e.pageTop,o.top),e.width,e.height)))},Uo=(e,t)=>{let n=[];return q(In(e),(e=>{t(e)&&(n=n.concat([e])),n=n.concat(Uo(e,t))})),n},zo=(e,t)=>((e,t)=>{const n=void 0===t?document:t.dom;return kn(n)?[]:V(n.querySelectorAll(e),Cn)})(t,e),jo=(e,t,n)=>Qn(e,t,n).isSome(),Ho=(e,t)=>((e,t)=>{const n=e.dom;return n.parentNode?((e,t)=>Q(e.dom.childNodes,(e=>t(Cn(e)))).map(Cn))(Cn(n.parentNode),(n=>!_n(e,n)&&t(n))):I.none()})(e,t).isSome(),$o=(e,t)=>eo(e,t).isSome();class Vo{constructor(e,t){this.node=e,this.rootNode=t,this.current=this.current.bind(this),this.next=this.next.bind(this),this.prev=this.prev.bind(this),this.prev2=this.prev2.bind(this)}current(){return this.node}next(e){return this.node=this.findSibling(this.node,"firstChild","nextSibling",e),this.node}prev(e){return this.node=this.findSibling(this.node,"lastChild","previousSibling",e),this.node}prev2(e){return this.node=this.findPreviousNode(this.node,e),this.node}findSibling(e,t,n,o){if(e){if(!o&&e[t])return e[t];if(e!==this.rootNode){let t=e[n];if(t)return t;for(let o=e.parentNode;o&&o!==this.rootNode;o=o.parentNode)if(t=o[n],t)return t}}}findPreviousNode(e,t){if(e){const n=e.previousSibling;if(this.rootNode&&n===this.rootNode)return;if(n){if(!t)for(let e=n.lastChild;e;e=e.lastChild)if(!e.lastChild)return e;return n}const o=e.parentNode;if(o&&o!==this.rootNode)return o}}}const qo="\ufeff",Wo="\xa0",Ko=e=>e===qo,Yo=/^[ \t\r\n]*$/,Go=e=>Yo.test(e),Xo=e=>"\n"===e||"\r"===e,Zo=(e,t=4,n=!0,o=!0)=>{const r=((e,t)=>t<=0?"":new Array(t+1).join(" "))(0,t),s=e.replace(/\t/g,r),a=X(s,((e,t)=>(e=>-1!==" \f\t\v".indexOf(e))(t)||t===Wo?e.pcIsSpace||""===e.str&&n||e.str.length===s.length-1&&o||((e,t)=>t<e.length&&t>=0&&Xo(e[t]))(s,e.str.length+1)?{pcIsSpace:!1,str:e.str+Wo}:{pcIsSpace:!0,str:e.str+" "}:{pcIsSpace:Xo(t),str:e.str+t}),{pcIsSpace:!1,str:""});return a.str},Qo=e=>t=>!!t&&t.nodeType===e,Jo=e=>!!e&&!Object.getPrototypeOf(e),er=Qo(1),tr=e=>er(e)&&Wt(Cn(e)),nr=e=>{const t=e.toLowerCase();return e=>C(e)&&e.nodeName.toLowerCase()===t},or=e=>{const t=e.map((e=>e.toLowerCase()));return e=>{if(e&&e.nodeName){const n=e.nodeName.toLowerCase();return H(t,n)}return!1}},rr=(e,t)=>{const n=t.toLowerCase().split(" ");return t=>{if(er(t)){const o=t.ownerDocument.defaultView;if(o)for(let r=0;r<n.length;r++){const s=o.getComputedStyle(t,null);if((s?s.getPropertyValue(e):null)===n[r])return!0}}return!1}},sr=e=>er(e)&&e.hasAttribute("data-mce-bogus"),ar=e=>er(e)&&"TABLE"===e.tagName,ir=e=>t=>{if(tr(t)){if(t.contentEditable===e)return!0;if(t.getAttribute("data-mce-contenteditable")===e)return!0}return!1},lr=or(["textarea","input"]),dr=Qo(3),cr=Qo(4),ur=Qo(7),mr=Qo(8),fr=Qo(9),gr=Qo(11),pr=nr("br"),hr=nr("img"),br=ir("true"),vr=ir("false"),yr=or(["td","th"]),Cr=or(["td","th","caption"]),wr=or(["video","audio","object","embed"]),Er=nr("li"),xr=nr("details"),kr=nr("summary"),_r={skipBogus:!0,includeZwsp:!1,checkRootAsContent:!1},Sr=("data-mce-bookmark",e=>er(e)&&e.hasAttribute("data-mce-bookmark"));const Nr=(e,t,n,o)=>dr(e)&&!((e,t,n)=>Go(e.data)&&!((e,t,n)=>{const o=Cn(t),r=Cn(e),s=n.getWhitespaceElements();return jo(r,(e=>ke(s,$t(e))),T(_n,o))})(e,t,n))(e,t,n)&&(!o.includeZwsp||!(e=>{for(const t of e)if(!Ko(t))return!1;return!0})(e.data)),Rr=(e,t,n,o)=>w(o.isContent)&&o.isContent(t)||((e,t)=>er(e)&&ke(t.getNonEmptyElements(),e.nodeName))(t,e)||Sr(t)||(e=>er(e)&&"A"===e.nodeName&&!e.hasAttribute("href")&&(e.hasAttribute("name")||e.hasAttribute("id")))(t)||Nr(t,n,e,o)||vr(t)||br(t)&&(e=>On(Cn(e)).exists((e=>!ro(e))))(t),Ar=(e,t,n)=>{const o={..._r,...n};if(o.checkRootAsContent&&Rr(e,t,t,o))return!1;let r=t.firstChild,s=0;if(!r)return!0;const a=new Vo(r,t);do{if(o.skipBogus&&er(r)){const e=r.getAttribute("data-mce-bogus");if(e){r=a.next("all"===e);continue}}if(mr(r))r=a.next(!0);else if(pr(r))s++,r=a.next();else{if(Rr(e,r,t,o))return!1;r=a.next()}}while(r);return s<=1},Tr=(e,t,n)=>Ar(e,t.dom,{checkRootAsContent:!0,...n}),Or=(e,t,n)=>Rr(e,t,t,{includeZwsp:_r.includeZwsp,...n}),Br=e=>{let t=e;return{get:()=>t,set:e=>{t=e}}},Pr=e=>{const t=Br(I.none()),n=()=>t.get().each((e=>clearInterval(e)));return{clear:()=>{n(),t.set(I.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:o=>{n(),t.set(I.some(setInterval(o,e)))}}},Dr=()=>{const e=(e=>{const t=Br(I.none()),n=()=>t.get().each(e);return{clear:()=>{n(),t.set(I.none())},isSet:()=>t.get().isSome(),get:()=>t.get(),set:e=>{n(),t.set(I.some(e))}}})(k);return{...e,on:t=>e.get().each(t)}},Lr=e=>{const t=e.toLowerCase();return"svg"===t?"svg":"math"===t?"math":"html"},Mr=e=>"html"!==Lr(e),Ir=e=>Mr(e.nodeName),Fr=e=>Lr(e.nodeName),Ur=["svg","math"],zr="data-mce-block",jr=e=>V((e=>Y(fe(e),(e=>!/[A-Z]/.test(e))))(e),(e=>{const t=CSS.escape(e);return`${t}:`+V(Ur,(e=>`not(${e} ${t})`)).join(":")})).join(","),Hr=(e,t)=>C(t.querySelector(e))?(t.setAttribute(zr,"true"),"inline-boundary"===t.getAttribute("data-mce-selected")&&t.removeAttribute("data-mce-selected"),!0):(t.removeAttribute(zr),!1),$r=(e,t)=>{const n=jr(e.getTransparentElements()),o=jr(e.getBlockElements());return Y(t.querySelectorAll(n),(e=>Hr(o,e)))},Vr=(e,t,n)=>{var o;const r=n?"lastChild":"firstChild";for(let n=t[r];n;n=n[r])if(Ar(e,n,{checkRootAsContent:!0}))return void(null===(o=n.parentNode)||void 0===o||o.removeChild(n))},qr=(e,t,n)=>{const o=e.getBlockElements(),r=Cn(t),s=e=>$t(e)in o,a=e=>_n(e,r);q(_o(n),(t=>{Qn(t,s,a).each((n=>{const o=((t,o)=>Y(In(t),(t=>s(t)&&!e.isValidChild($t(n),$t(t)))))(t);if(o.length>0){const t=On(n);q(o,(t=>{Qn(t,s,a).each((n=>{((e,t,n)=>{const o=document.createRange(),r=t.parentNode;if(r){o.setStartBefore(t),o.setEndBefore(n);const s=o.extractContents();Vr(e,s,!0),o.setStartAfter(n),o.setEndAfter(t);const a=o.extractContents();Vr(e,a,!1),Ar(e,s,{checkRootAsContent:!0})||r.insertBefore(s,t),Ar(e,n,{checkRootAsContent:!0})||r.insertBefore(n,t),Ar(e,a,{checkRootAsContent:!0})||r.insertBefore(a,t),r.removeChild(t)}})(e,n.dom,t.dom)}))})),t.each((t=>$r(e,t.dom)))}}))}))},Wr=(e,t)=>{const n=$r(e,t);qr(e,t,n),((e,t,n)=>{q([...n,...Zr(e,t)?[t]:[]],(t=>q(zo(Cn(t),t.nodeName.toLowerCase()),(t=>{Qr(e,t.dom)&&ko(t)}))))})(e,t,n)},Kr=(e,t)=>{if(Xr(e,t)){const n=jr(e.getBlockElements());Hr(n,t)}},Yr=e=>e.hasAttribute(zr),Gr=(e,t)=>ke(e.getTransparentElements(),t),Xr=(e,t)=>er(t)&&Gr(e,t.nodeName),Zr=(e,t)=>Xr(e,t)&&Yr(t),Qr=(e,t)=>Xr(e,t)&&!Yr(t),Jr=(e,t)=>1===t.type&&Gr(e,t.name)&&m(t.attr(zr)),es=xt().browser,ts=e=>Q(e,Kt),ns=(e,t)=>e.children&&H(e.children,t),os=(e,t={})=>{let n=0;const o={},r=Cn(e),s=Rn(r),a=e=>{yo(Wn(r),e)},i=e=>{const t=Wn(r);no(t,"#"+e).each(xo)},l=e=>xe(o,e).getOrThunk((()=>({id:"mce-u"+n++,passed:[],failed:[],count:0}))),d=e=>new Promise(((n,r)=>{let i;const d=Dt._addCacheSuffix(e),c=l(d);o[d]=c,c.count++;const u=(e,t)=>{q(e,D),c.status=t,c.passed=[],c.failed=[],i&&(i.onload=null,i.onerror=null,i=null)},m=()=>u(c.passed,2),f=()=>u(c.failed,3);if(n&&c.passed.push(n),r&&c.failed.push(r),1===c.status)return;if(2===c.status)return void m();if(3===c.status)return void f();c.status=1;const g=vn("link",s.dom);en(g,{rel:"stylesheet",type:"text/css",id:c.id}),t.contentCssCors&&Jt(g,"crossOrigin","anonymous"),t.referrerPolicy&&Jt(g,"referrerpolicy",t.referrerPolicy),i=g.dom,i.onload=m,i.onerror=f,a(g),Jt(g,"href",d)})),c=e=>{const t=Dt._addCacheSuffix(e);xe(o,t).each((e=>{0==--e.count&&(delete o[t],i(e.id))}))};return{load:d,loadRawCss:(e,t)=>{const n=l(e);o[e]=n,n.count++;const r=vn("style",s.dom);en(r,{rel:"stylesheet",type:"text/css",id:n.id}),r.dom.innerHTML=t,a(r)},loadAll:e=>Promise.allSettled(V(e,(e=>d(e).then(N(e))))).then((e=>{const t=K(e,(e=>"fulfilled"===e.status));return t.fail.length>0?Promise.reject(V(t.fail,(e=>e.reason))):V(t.pass,(e=>e.value))})),unload:c,unloadRawCss:e=>{xe(o,e).each((t=>{0==--t.count&&(delete o[e],i(t.id))}))},unloadAll:e=>{q(e,(e=>{c(e)}))},_setReferrerPolicy:e=>{t.referrerPolicy=e},_setContentCssCors:e=>{t.contentCssCors=e}}},rs=(()=>{const e=new WeakMap;return{forElement:(t,n)=>{const o=qn(t).dom;return I.from(e.get(o)).getOrThunk((()=>{const t=os(o,n);return e.set(o,t),t}))}}})(),ss=(e,t)=>C(e)&&(Or(t,e)||t.isInline(e.nodeName.toLowerCase())),as=e=>(e=>"span"===e.nodeName.toLowerCase())(e)&&"bookmark"===e.getAttribute("data-mce-type"),is=(e,t,n,o)=>{var r;const s=o||t;if(er(t)&&as(t))return t;const a=t.childNodes;for(let t=a.length-1;t>=0;t--)is(e,a[t],n,s);if(er(t)){const e=t.childNodes;1===e.length&&as(e[0])&&(null===(r=t.parentNode)||void 0===r||r.insertBefore(e[0],t))}return(e=>gr(e)||fr(e))(t)||Or(n,t)||(e=>!!er(e)&&e.childNodes.length>0)(t)||((e,t,n)=>dr(e)&&e.data.length>0&&((e,t,n)=>{const o=new Vo(e,t).prev(!1),r=new Vo(e,t).next(!1),s=v(o)||ss(o,n),a=v(r)||ss(r,n);return s&&a})(e,t,n))(t,s,n)||e.remove(t),t},ls=Dt.makeMap,ds=/[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,cs=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,us=/[<>&\"\']/g,ms=/&#([a-z0-9]+);?|&([a-z0-9]+);/gi,fs={128:"\u20ac",130:"\u201a",131:"\u0192",132:"\u201e",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02c6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017d",145:"\u2018",146:"\u2019",147:"\u201c",148:"\u201d",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02dc",153:"\u2122",154:"\u0161",155:"\u203a",156:"\u0153",158:"\u017e",159:"\u0178"},gs={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;","`":"&#96;"},ps={"&lt;":"<","&gt;":">","&amp;":"&","&quot;":'"',"&apos;":"'"},hs=(e,t)=>{const n={};if(e){const o=e.split(",");t=t||10;for(let e=0;e<o.length;e+=2){const r=String.fromCharCode(parseInt(o[e],t));if(!gs[r]){const t="&"+o[e+1]+";";n[r]=t,n[t]=r}}return n}},bs=hs("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32),vs=(e,t)=>e.replace(t?ds:cs,(e=>gs[e]||e)),ys=(e,t)=>e.replace(t?ds:cs,(e=>e.length>1?"&#"+(1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320)+65536)+";":gs[e]||"&#"+e.charCodeAt(0)+";")),Cs=(e,t,n)=>{const o=n||bs;return e.replace(t?ds:cs,(e=>gs[e]||o[e]||e))},ws={encodeRaw:vs,encodeAllRaw:e=>(""+e).replace(us,(e=>gs[e]||e)),encodeNumeric:ys,encodeNamed:Cs,getEncodeFunc:(e,t)=>{const n=hs(t)||bs,o=ls(e.replace(/\+/g,","));return o.named&&o.numeric?(e,t)=>e.replace(t?ds:cs,(e=>void 0!==gs[e]?gs[e]:void 0!==n[e]?n[e]:e.length>1?"&#"+(1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320)+65536)+";":"&#"+e.charCodeAt(0)+";")):o.named?t?(e,t)=>Cs(e,t,n):Cs:o.numeric?ys:vs},decode:e=>e.replace(ms,((e,t)=>t?(t="x"===t.charAt(0).toLowerCase()?parseInt(t.substr(1),16):parseInt(t,10))>65535?(t-=65536,String.fromCharCode(55296+(t>>10),56320+(1023&t))):fs[t]||String.fromCharCode(t):ps[e]||bs[e]||(e=>{const t=vn("div").dom;return t.innerHTML=e,t.textContent||t.innerText||e})(e)))},Es=(e,t)=>(e=Dt.trim(e))?e.split(t||" "):[],xs=e=>new RegExp("^"+e.replace(/([?+*])/g,".$1")+"$"),ks=e=>Object.freeze(["id","accesskey","class","dir","lang","style","tabindex","title","role",..."html4"!==e?["contenteditable","contextmenu","draggable","dropzone","hidden","spellcheck","translate","itemprop","itemscope","itemtype"]:[],..."html5-strict"!==e?["xml:lang"]:[]]),_s=e=>{let t,n;t="address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul",n="a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment","html4"!==e&&(t+=" article aside details dialog figure main header footer hgroup section nav a ins del canvas map",n+=" audio canvas command data datalist mark meter output picture progress time wbr video ruby bdi keygen svg"),"html5-strict"!==e&&(n=[n,"acronym applet basefont big font strike tt"].join(" "),t=[t,"center dir isindex noframes"].join(" "));const o=[t,n].join(" ");return{blockContent:t,phrasingContent:n,flowContent:o}},Ss=e=>{const{blockContent:t,phrasingContent:n,flowContent:o}=_s(e),r=e=>Object.freeze(e.split(" "));return Object.freeze({blockContent:r(t),phrasingContent:r(n),flowContent:r(o)})},Ns={html4:Le((()=>Ss("html4"))),html5:Le((()=>Ss("html5"))),"html5-strict":Le((()=>Ss("html5-strict")))},Rs=(e,t)=>{const{blockContent:n,phrasingContent:o,flowContent:r}=Ns[e]();return"blocks"===t?I.some(n):"phrasing"===t?I.some(o):"flow"===t?I.some(r):I.none()},As=e=>I.from(/^(@?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)$/.exec(e)).map((e=>({preset:"@"===e[1],name:e[2]}))),Ts={},Os=Dt.makeMap,Bs=Dt.each,Ps=Dt.extend,Ds=Dt.explode,Ls=(e,t={})=>{const n=Os(e," ",Os(e.toUpperCase()," "));return Ps(n,t)},Ms=e=>Ls("td th li dt dd figcaption caption details summary",e.getTextBlockElements()),Is=(e,t)=>{if(e){const n={};return m(e)&&(e={"*":e}),Bs(e,((e,o)=>{n[o]=n[o.toUpperCase()]="map"===t?Os(e,/[, ]/):Ds(e,/[, ]/)})),n}},Fs=(e={})=>{var t;const n={},o={};let r=[];const s={},a={},i=(t,n,o)=>{const r=e[t];if(r)return Os(r,/[, ]/,Os(r.toUpperCase(),/[, ]/));{let e=Ts[t];return e||(e=Ls(n,o),Ts[t]=e),e}},l=null!==(t=e.schema)&&void 0!==t?t:"html5",d=(e=>{const t=ks(e),{phrasingContent:n,flowContent:o}=_s(e),r={},s=(e,t,n)=>{r[e]={attributes:se(t,N({})),attributesOrder:t,children:se(n,N({}))}},a=(e,n="",o="")=>{const r=Es(o),a=Es(e);let i=a.length;const l=[...t,...Es(n)];for(;i--;)s(a[i],l.slice(),r)},i=(e,t)=>{const n=Es(e),o=Es(t);let s=n.length;for(;s--;){const e=r[n[s]];for(let t=0,n=o.length;t<n;t++)e.attributes[o[t]]={},e.attributesOrder.push(o[t])}};return"html5-strict"!==e&&(q(Es("acronym applet basefont big font strike tt"),(e=>{a(e,"",n)})),q(Es("center dir isindex noframes"),(e=>{a(e,"",o)}))),a("html","manifest","head body"),a("head","","base command link meta noscript script style title"),a("title hr noscript br"),a("base","href target"),a("link","href rel media hreflang type sizes hreflang"),a("meta","name http-equiv content charset"),a("style","media type scoped"),a("script","src async defer type charset"),a("body","onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload",o),a("dd div","",o),a("address dt caption","","html4"===e?n:o),a("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn","",n),a("blockquote","cite",o),a("ol","reversed start type","li"),a("ul","","li"),a("li","value",o),a("dl","","dt dd"),a("a","href target rel media hreflang type","html4"===e?n:o),a("q","cite",n),a("ins del","cite datetime",o),a("img","src sizes srcset alt usemap ismap width height"),a("iframe","src name width height",o),a("embed","src type width height"),a("object","data type typemustmatch name usemap form width height",[o,"param"].join(" ")),a("param","name value"),a("map","name",[o,"area"].join(" ")),a("area","alt coords shape href target rel media hreflang type"),a("table","border","caption colgroup thead tfoot tbody tr"+("html4"===e?" col":"")),a("colgroup","span","col"),a("col","span"),a("tbody thead tfoot","","tr"),a("tr","","td th"),a("td","colspan rowspan headers",o),a("th","colspan rowspan headers scope abbr",o),a("form","accept-charset action autocomplete enctype method name novalidate target",o),a("fieldset","disabled form name",[o,"legend"].join(" ")),a("label","form for",n),a("input","accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width"),a("button","disabled form formaction formenctype formmethod formnovalidate formtarget name type value","html4"===e?o:n),a("select","disabled form multiple name required size","option optgroup"),a("optgroup","disabled label","option"),a("option","disabled label selected value"),a("textarea","cols dirname disabled form maxlength name readonly required rows wrap"),a("menu","type label",[o,"li"].join(" ")),a("noscript","",o),"html4"!==e&&(a("wbr"),a("ruby","",[n,"rt rp"].join(" ")),a("figcaption","",o),a("mark rt rp bdi","",n),a("summary","",[n,"h1 h2 h3 h4 h5 h6"].join(" ")),a("canvas","width height",o),a("data","value",n),a("video","src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered",[o,"track source"].join(" ")),a("audio","src crossorigin preload autoplay mediagroup loop muted controls buffered volume",[o,"track source"].join(" ")),a("picture","","img source"),a("source","src srcset type media sizes"),a("track","kind src srclang label default"),a("datalist","",[n,"option"].join(" ")),a("article section nav aside main header footer","",o),a("hgroup","","h1 h2 h3 h4 h5 h6"),a("figure","",[o,"figcaption"].join(" ")),a("time","datetime",n),a("dialog","open",o),a("command","type label icon disabled checked radiogroup command"),a("output","for form name",n),a("progress","value max",n),a("meter","value min max low high optimum",n),a("details","open",[o,"summary"].join(" ")),a("keygen","autofocus challenge disabled form keytype name"),s("svg","id tabindex lang xml:space class style x y width height viewBox preserveAspectRatio zoomAndPan transform".split(" "),[])),"html5-strict"!==e&&(i("script","language xml:space"),i("style","xml:space"),i("object","declare classid code codebase codetype archive standby align border hspace vspace"),i("embed","align name hspace vspace"),i("param","valuetype type"),i("a","charset name rev shape coords"),i("br","clear"),i("applet","codebase archive code object alt name width height align hspace vspace"),i("img","name longdesc align border hspace vspace"),i("iframe","longdesc frameborder marginwidth marginheight scrolling align"),i("font basefont","size color face"),i("input","usemap align"),i("select"),i("textarea"),i("h1 h2 h3 h4 h5 h6 div p legend caption","align"),i("ul","type compact"),i("li","type"),i("ol dl menu dir","compact"),i("pre","width xml:space"),i("hr","align noshade size width"),i("isindex","prompt"),i("table","summary width frame rules cellspacing cellpadding align bgcolor"),i("col","width align char charoff valign"),i("colgroup","width align char charoff valign"),i("thead","align char charoff valign"),i("tr","align char charoff valign bgcolor"),i("th","axis align char charoff valign nowrap bgcolor width height"),i("form","accept"),i("td","abbr axis scope align char charoff valign nowrap bgcolor width height"),i("tfoot","align char charoff valign"),i("tbody","align char charoff valign"),i("area","nohref"),i("body","background bgcolor text link vlink alink")),"html4"!==e&&(i("input button select textarea","autofocus"),i("input textarea","placeholder"),i("a","download"),i("link script img","crossorigin"),i("img","loading"),i("iframe","sandbox seamless allow allowfullscreen loading referrerpolicy")),"html4"!==e&&q([r.video,r.audio],(e=>{delete e.children.audio,delete e.children.video})),q(Es("a form meter progress dfn"),(e=>{r[e]&&delete r[e].children[e]})),delete r.caption.children.table,delete r.script,r})(l);!1===e.verify_html&&(e.valid_elements="*[*]");const c=Is(e.valid_styles),u=Is(e.invalid_styles,"map"),g=Is(e.valid_classes,"map"),h=i("whitespace_elements","pre script noscript style textarea video audio iframe object code"),v=i("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr"),y=i("void_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr track"),C=i("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls allowfullscreen"),w="td th iframe video audio object script code",E=i("non_empty_elements",w+" pre svg textarea summary",y),x=i("move_caret_before_on_enter_elements",w+" table",y),k="h1 h2 h3 h4 h5 h6",_=i("text_block_elements",k+" p div address pre form blockquote center dir fieldset header footer article section hgroup aside main nav figure"),S=i("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex option datalist select optgroup figcaption details summary html body multicol listing",_),R=i("text_inline_elements","span strong b em i font s strike u var cite dfn code mark q sup sub samp"),A=i("transparent_elements","a ins del canvas map"),T=i("wrap_block_elements","pre "+k);Bs("script noscript iframe noframes noembed title style textarea xmp plaintext".split(" "),(e=>{a[e]=new RegExp("</"+e+"[^>]*>","gi")}));const O=e=>{const t=I.from(n["@"]),o=/[*?+]/;q(((e,t)=>{const n=/^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;return te(Es(t,","),(t=>{const o=n.exec(t);if(o){const t=o[1],n=o[2],r=o[3],s=o[4],a=o[5],i={attributes:{},attributesOrder:[]};if(e.each((e=>((e,t)=>{pe(e.attributes,((e,n)=>{t.attributes[n]=e})),t.attributesOrder.push(...e.attributesOrder)})(e,i))),"#"===t?i.paddEmpty=!0:"-"===t&&(i.removeEmpty=!0),"!"===s&&(i.removeEmptyAttrs=!0),a&&((e,t)=>{const n=/^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/,o=/[*?+]/,{attributes:r,attributesOrder:s}=t;q(Es(e,"|"),(e=>{const a=n.exec(e);if(a){const e={},n=a[1],i=a[2].replace(/[\\:]:/g,":"),l=a[3],d=a[4];if("!"===n&&(t.attributesRequired=t.attributesRequired||[],t.attributesRequired.push(i),e.required=!0),"-"===n)return delete r[i],void s.splice(Dt.inArray(s,i),1);if(l&&("="===l?(t.attributesDefault=t.attributesDefault||[],t.attributesDefault.push({name:i,value:d}),e.defaultValue=d):"~"===l?(t.attributesForced=t.attributesForced||[],t.attributesForced.push({name:i,value:d}),e.forcedValue=d):"<"===l&&(e.validValues=Dt.makeMap(d,"?"))),o.test(i)){const n=e;t.attributePatterns=t.attributePatterns||[],n.pattern=xs(i),t.attributePatterns.push(n)}else r[i]||s.push(i),r[i]=e}}))})(a,i),r&&(i.outputName=n),"@"===n){if(!e.isNone())return[];e=I.some(i)}return[r?{name:n,element:i,aliasName:r}:{name:n,element:i}]}return[]}))})(t,null!=e?e:""),(({name:e,element:t,aliasName:s})=>{if(s&&(n[s]=t),o.test(e)){const n=t;n.pattern=xs(e),r.push(n)}else n[e]=t}))},B=e=>{r=[],q(fe(n),(e=>{delete n[e]})),O(e)},P=(e,t)=>{var r,a;delete Ts.text_block_elements,delete Ts.block_elements;const i=!!t.extends&&!oe(t.extends),d=t.extends;if(o[e]=d?o[d]:{},s[e]=null!=d?d:e,E[e.toUpperCase()]={},E[e]={},i||(S[e.toUpperCase()]={},S[e]={}),d&&!n[e]&&n[d]){const t=(e=>{const t=e=>p(e)?V(e,t):(e=>f(e)&&e.source&&"[object RegExp]"===Object.prototype.toString.call(e))(e)?new RegExp(e.source,e.flags):f(e)?he(e,t):e;return t(e)})(n[d]);delete t.removeEmptyAttrs,delete t.removeEmpty,n[e]=t}else n[e]={attributesOrder:[],attributes:{}};if(p(t.attributes)){const o=e=>{s.attributesOrder.push(e),s.attributes[e]={}},s=null!==(r=n[e])&&void 0!==r?r:{};delete s.attributesDefault,delete s.attributesForced,delete s.attributePatterns,delete s.attributesRequired,s.attributesOrder=[],s.attributes={},q(t.attributes,(e=>{const t=ks(l);As(e).each((({preset:e,name:n})=>{e?"global"===n&&q(t,o):o(n)}))})),n[e]=s}if(b(t.padEmpty)){const o=null!==(a=n[e])&&void 0!==a?a:{};o.paddEmpty=t.padEmpty,n[e]=o}if(p(t.children)){const n={},r=e=>{n[e]={}},s=e=>{Rs(l,e).each((e=>{q(e,r)}))};q(t.children,(e=>{As(e).each((({preset:e,name:t})=>{e?s(t):r(t)}))})),o[e]=n}d&&pe(o,((t,n)=>{t[d]&&(o[n]=t=Ps({},o[n]),t[e]=t[d])}))},D=e=>{f(e)?pe(e,((e,t)=>P(t,e))):m(e)&&(e=>{q((e=>{const t=/^(~)?(.+)$/;return te(Es(e,","),(e=>{const n=t.exec(e);return n?[{cloneName:"~"===n[1]?"span":"div",name:n[2]}]:[]}))})(null!=e?e:""),(({name:e,cloneName:t})=>{P(e,{extends:t})}))})(e)},L=e=>{q((e=>{const t=/^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/;return te(Es(e,","),(e=>{const n=t.exec(e);if(n){const e=n[1],t=e?(e=>"-"===e?"remove":"add")(e):"replace";return[{operation:t,name:n[2],validChildren:te(Es(n[3],"|"),(e=>As(e).toArray()))}]}return[]}))})(null!=e?e:""),(({operation:e,name:t,validChildren:n})=>{const r="replace"===e?{"#comment":{}}:o[t],s=t=>{"remove"===e?delete r[t]:r[t]={}};q(n,(({preset:e,name:t})=>{e?(e=>{Rs(l,e).each((e=>{q(e,s)}))})(t):s(t)})),o[t]=r}))},M=e=>{const t=n[e];if(t)return t;let o=r.length;for(;o--;){const t=r[o];if(t.pattern.test(e))return t}},F=N(c),U=N(u),z=N(g),j=N(C),H=N(S),$=N(_),W=N(R),K=N(Object.seal(y)),Y=N(v),G=N(E),X=N(x),Z=N(h),Q=N(A),J=N(T),ee=N(Object.seal(a)),ne=(e,t)=>{const n=M(e);if(n){if(!t)return!0;{if(n.attributes[t])return!0;const e=n.attributePatterns;if(e){let n=e.length;for(;n--;)if(e[n].pattern.test(t))return!0}}}return!1},oe=e=>ke(H(),e),re=e=>!$e(e,"#")&&ne(e)&&!oe(e),ae=N(s);return e.valid_elements?(B(e.valid_elements),Bs(d,((e,t)=>{o[t]=e.children}))):(Bs(d,((e,t)=>{n[t]={attributes:e.attributes,attributesOrder:e.attributesOrder},o[t]=e.children})),Bs(Es("strong/b em/i"),(e=>{const t=Es(e,"/");n[t[1]].outputName=t[0]})),Bs(R,((t,o)=>{n[o]&&(e.padd_empty_block_inline_children&&(n[o].paddInEmptyBlock=!0),n[o].removeEmpty=!0)})),Bs(Es("ol ul blockquote a table tbody"),(e=>{n[e]&&(n[e].removeEmpty=!0)})),Bs(Es("p h1 h2 h3 h4 h5 h6 th td pre div address caption li summary"),(e=>{n[e]&&(n[e].paddEmpty=!0)})),Bs(Es("span"),(e=>{n[e].removeEmptyAttrs=!0}))),delete n.svg,D(e.custom_elements),L(e.valid_children),O(e.extended_valid_elements),L("+ol[ul|ol],+ul[ul|ol]"),Bs({dd:"dl",dt:"dl",li:"ul ol",td:"tr",th:"tr",tr:"tbody thead tfoot",tbody:"table",thead:"table",tfoot:"table",legend:"fieldset",area:"map",param:"video audio object"},((e,t)=>{n[t]&&(n[t].parentsRequired=Es(e))})),e.invalid_elements&&Bs(Ds(e.invalid_elements),(e=>{n[e]&&delete n[e]})),M("span")||O("span[!data-mce-type|*]"),{type:l,children:o,elements:n,getValidStyles:F,getValidClasses:z,getBlockElements:H,getInvalidStyles:U,getVoidElements:K,getTextBlockElements:$,getTextInlineElements:W,getBoolAttrs:j,getElementRule:M,getSelfClosingElements:Y,getNonEmptyElements:G,getMoveCaretBeforeOnEnterElements:X,getWhitespaceElements:Z,getTransparentElements:Q,getSpecialElements:ee,isValidChild:(e,t)=>{const n=o[e.toLowerCase()];return!(!n||!n[t.toLowerCase()])},isValid:ne,isBlock:oe,isInline:re,isWrapper:e=>ke(J(),e)||re(e),getCustomElements:ae,addValidElements:O,setValidElements:B,addCustomElements:D,addValidChildren:L}},Us=e=>{const t=e.toString(16);return(1===t.length?"0"+t:t).toUpperCase()},zs=e=>(e=>{return{value:(t=e,je(t,"#").toUpperCase())};var t})(Us(e.red)+Us(e.green)+Us(e.blue)),js=/^\s*rgb\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*\)\s*$/i,Hs=/^\s*rgba\s*\(\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*(\d+)\s*[,\s]\s*((?:\d?\.\d+|\d+)%?)\s*\)\s*$/i,$s=(e,t,n,o)=>((e,t,n,o)=>({red:e,green:t,blue:n,alpha:o}))(parseInt(e,10),parseInt(t,10),parseInt(n,10),parseFloat(o)),Vs=e=>{const t=js.exec(e);if(null!==t)return I.some($s(t[1],t[2],t[3],"1"));const n=Hs.exec(e);return null!==n?I.some($s(n[1],n[2],n[3],n[4])):I.none()},qs=e=>`rgba(${e.red},${e.green},${e.blue},${e.alpha})`,Ws=e=>Vs(e).map(zs).map((e=>"#"+e.value)).getOr(e),Ks=(e={},t)=>{const n=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,o=/\s*([^:]+):\s*([^;]+);?/g,r=/\s+$/,s={};let a,i;const l=qo;t&&(a=t.getValidStyles(),i=t.getInvalidStyles());const d="\\\" \\' \\; \\: ; : \ufeff".split(" ");for(let e=0;e<d.length;e++)s[d[e]]=l+e,s[l+e]=d[e];const c={parse:t=>{const a={};let i=!1;const d=e.url_converter,u=e.url_converter_scope||c,m=(e,t,n)=>{const o=a[e+"-top"+t];if(!o)return;const r=a[e+"-right"+t];if(!r)return;const s=a[e+"-bottom"+t];if(!s)return;const i=a[e+"-left"+t];if(!i)return;const l=[o,r,s,i];let d=l.length-1;for(;d--&&l[d]===l[d+1];);d>-1&&n||(a[e+t]=-1===d?l[0]:l.join(" "),delete a[e+"-top"+t],delete a[e+"-right"+t],delete a[e+"-bottom"+t],delete a[e+"-left"+t])},f=e=>{const t=a[e];if(!t)return;const n=t.indexOf(",")>-1?[t]:t.split(" ");let o=n.length;for(;o--;)if(n[o]!==n[0])return!1;return a[e]=n[0],!0},g=e=>(i=!0,s[e]),p=(e,t)=>(i&&(e=e.replace(/\uFEFF[0-9]/g,(e=>s[e]))),t||(e=e.replace(/\\([\'\";:])/g,"$1")),e),h=e=>String.fromCharCode(parseInt(e.slice(1),16)),b=e=>e.replace(/\\[0-9a-f]+/gi,h),v=(t,n,o,r,s,a)=>{if(s=s||a)return"'"+(s=p(s)).replace(/\'/g,"\\'")+"'";if(n=p(n||o||r||""),!e.allow_script_urls){const t=n.replace(/[\s\r\n]+/g,"");if(/(java|vb)script:/i.test(t))return"";if(!e.allow_svg_data_urls&&/^data:image\/svg/i.test(t))return""}return d&&(n=d.call(u,n,"style")),"url('"+n.replace(/\'/g,"\\'")+"')"};if(t){let s;for(t=(t=t.replace(/[\u0000-\u001F]/g,"")).replace(/\\[\"\';:\uFEFF]/g,g).replace(/\"[^\"]+\"|\'[^\']+\'/g,(e=>e.replace(/[;:]/g,g)));s=o.exec(t);){o.lastIndex=s.index+s[0].length;let t=s[1].replace(r,"").toLowerCase(),d=s[2].replace(r,"");if(t&&d){if(t=b(t),d=b(d),-1!==t.indexOf(l)||-1!==t.indexOf('"'))continue;if(!e.allow_script_urls&&("behavior"===t||/expression\s*\(|\/\*|\*\//.test(d)))continue;"font-weight"===t&&"700"===d?d="bold":"color"!==t&&"background-color"!==t||(d=d.toLowerCase()),"rgb"==(E=d,js.test(E)?"rgb":Hs.test(E)?"rgba":"other")&&Vs(d).each((e=>{d=Ws(qs(e)).toLowerCase()})),d=d.replace(n,v),a[t]=i?p(d,!0):d}}m("border","",!0),m("border","-width"),m("border","-color"),m("border","-style"),m("padding",""),m("margin",""),"border",C="border-style",w="border-color",f(y="border-width")&&f(C)&&f(w)&&(a.border=a[y]+" "+a[C]+" "+a[w],delete a[y],delete a[C],delete a[w]),"medium none"===a.border&&delete a.border,"none"===a["border-image"]&&delete a["border-image"]}var y,C,w,E;return a},serialize:(e,t)=>{let n="";const o=(t,o)=>{const r=o[t];if(r)for(let t=0,o=r.length;t<o;t++){const o=r[t],s=e[o];s&&(n+=(n.length>0?" ":"")+o+": "+s+";")}};return t&&a?(o("*",a),o(t,a)):pe(e,((e,o)=>{e&&((e,t)=>{if(!i||!t)return!0;let n=i["*"];return!(n&&n[e]||(n=i[t],n&&n[e]))})(o,t)&&(n+=(n.length>0?" ":"")+o+": "+e+";")})),n}};return c},Ys={keyLocation:!0,layerX:!0,layerY:!0,returnValue:!0,webkitMovementX:!0,webkitMovementY:!0,keyIdentifier:!0,mozPressure:!0},Gs=(e,t)=>{const n=null!=t?t:{};for(const t in e)ke(Ys,t)||(n[t]=e[t]);return C(e.composedPath)&&(n.composedPath=()=>e.composedPath()),C(e.getModifierState)&&(n.getModifierState=t=>e.getModifierState(t)),C(e.getTargetRanges)&&(n.getTargetRanges=()=>e.getTargetRanges()),n},Xs=(e,t,n,o)=>{var r;const s=Gs(t,o);return s.type=e,y(s.target)&&(s.target=null!==(r=s.srcElement)&&void 0!==r?r:n),(e=>y(e.preventDefault)||(e=>e instanceof Event||w(e.initEvent))(e))(t)&&(s.preventDefault=()=>{s.defaultPrevented=!0,s.isDefaultPrevented=M,w(t.preventDefault)&&t.preventDefault()},s.stopPropagation=()=>{s.cancelBubble=!0,s.isPropagationStopped=M,w(t.stopPropagation)&&t.stopPropagation()},s.stopImmediatePropagation=()=>{s.isImmediatePropagationStopped=M,s.stopPropagation()},(e=>e.isDefaultPrevented===M||e.isDefaultPrevented===L)(s)||(s.isDefaultPrevented=!0===s.defaultPrevented?M:L,s.isPropagationStopped=!0===s.cancelBubble?M:L,s.isImmediatePropagationStopped=L)),s},Zs=/^(?:mouse|contextmenu)|click/,Qs=(e,t,n,o)=>{e.addEventListener(t,n,o||!1)},Js=(e,t,n,o)=>{e.removeEventListener(t,n,o||!1)},ea=(e,t)=>{const n=Xs(e.type,e,document,t);if((e=>C(e)&&Zs.test(e.type))(e)&&v(e.pageX)&&!v(e.clientX)){const t=n.target.ownerDocument||document,o=t.documentElement,r=t.body,s=n;s.pageX=e.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),s.pageY=e.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)}return n},ta=(e,t,n)=>{const o=e.document,r={type:"ready"};if(n.domLoaded)return void t(r);const s=()=>{Js(e,"DOMContentLoaded",s),Js(e,"load",s),n.domLoaded||(n.domLoaded=!0,t(r)),e=null};"complete"===o.readyState||"interactive"===o.readyState&&o.body?s():Qs(e,"DOMContentLoaded",s),n.domLoaded||Qs(e,"load",s)};class na{constructor(){this.domLoaded=!1,this.events={},this.count=1,this.expando="mce-data-"+(+new Date).toString(32),this.hasFocusIn="onfocusin"in document.documentElement,this.count=1}bind(e,t,n,o){const r=this;let s;const a=window,i=e=>{r.executeHandlers(ea(e||a.event),l)};if(!e||dr(e)||mr(e))return n;let l;e[r.expando]?l=e[r.expando]:(l=r.count++,e[r.expando]=l,r.events[l]={}),o=o||e;const d=t.split(" ");let c=d.length;for(;c--;){let t=d[c],u=i,m=!1,f=!1;"DOMContentLoaded"===t&&(t="ready"),r.domLoaded&&"ready"===t&&"complete"===e.readyState?n.call(o,ea({type:t})):(r.hasFocusIn||"focusin"!==t&&"focusout"!==t||(m=!0,f="focusin"===t?"focus":"blur",u=e=>{const t=ea(e||a.event);t.type="focus"===t.type?"focusin":"focusout",r.executeHandlers(t,l)}),s=r.events[l][t],s?"ready"===t&&r.domLoaded?n(ea({type:t})):s.push({func:n,scope:o}):(r.events[l][t]=s=[{func:n,scope:o}],s.fakeName=f,s.capture=m,s.nativeHandler=u,"ready"===t?ta(e,u,r):Qs(e,f||t,u,m)))}return e=s=null,n}unbind(e,t,n){if(!e||dr(e)||mr(e))return this;const o=e[this.expando];if(o){let r=this.events[o];if(t){const o=t.split(" ");let s=o.length;for(;s--;){const t=o[s],a=r[t];if(a){if(n){let e=a.length;for(;e--;)if(a[e].func===n){const n=a.nativeHandler,o=a.fakeName,s=a.capture,i=a.slice(0,e).concat(a.slice(e+1));i.nativeHandler=n,i.fakeName=o,i.capture=s,r[t]=i}}n&&0!==a.length||(delete r[t],Js(e,a.fakeName||t,a.nativeHandler,a.capture))}}}else pe(r,((t,n)=>{Js(e,t.fakeName||n,t.nativeHandler,t.capture)})),r={};for(const e in r)if(ke(r,e))return this;delete this.events[o];try{delete e[this.expando]}catch(t){e[this.expando]=null}}return this}fire(e,t,n){return this.dispatch(e,t,n)}dispatch(e,t,n){if(!e||dr(e)||mr(e))return this;const o=ea({type:t,target:e},n);do{const t=e[this.expando];t&&this.executeHandlers(o,t),e=e.parentNode||e.ownerDocument||e.defaultView||e.parentWindow}while(e&&!o.isPropagationStopped());return this}clean(e){if(!e||dr(e)||mr(e))return this;if(e[this.expando]&&this.unbind(e),e.getElementsByTagName||(e=e.document),e&&e.getElementsByTagName){this.unbind(e);const t=e.getElementsByTagName("*");let n=t.length;for(;n--;)(e=t[n])[this.expando]&&this.unbind(e)}return this}destroy(){this.events={}}cancel(e){return e&&(e.preventDefault(),e.stopImmediatePropagation()),!1}executeHandlers(e,t){const n=this.events[t],o=n&&n[e.type];if(o)for(let t=0,n=o.length;t<n;t++){const n=o[t];if(n&&!1===n.func.call(n.scope,e)&&e.preventDefault(),e.isImmediatePropagationStopped())return}}}na.Event=new na;const oa=Dt.each,ra=Dt.grep,sa="data-mce-style",aa=Dt.makeMap("fill-opacity font-weight line-height opacity orphans widows z-index zoom"," "),ia=(e,t,n)=>{y(n)||""===n?rn(e,t):Jt(e,t,n)},la=e=>e.replace(/[A-Z]/g,(e=>"-"+e.toLowerCase())),da=(e,t)=>{let n=0;if(e)for(let o=e.nodeType,r=e.previousSibling;r;r=r.previousSibling){const e=r.nodeType;(!t||!dr(r)||e!==o&&r.data.length)&&(n++,o=e)}return n},ca=(e,t)=>{const n=tn(t,"style"),o=e.serialize(e.parse(n),$t(t));ia(t,sa,o)},ua=(e,t,n)=>{const o=la(t);y(n)||""===n?po(e,o):lo(e,o,((e,t)=>E(e)?ke(aa,t)?e+"":e+"px":e)(n,o))},ma=(e,t={})=>{const n={},o=window,r={};let s=0;const a=rs.forElement(Cn(e),{contentCssCors:t.contentCssCors,referrerPolicy:t.referrerPolicy}),i=[],l=t.schema?t.schema:Fs({}),d=Ks({url_converter:t.url_converter,url_converter_scope:t.url_converter_scope},t.schema),c=t.ownEvents?new na:na.Event,u=l.getBlockElements(),f=t=>t&&e&&m(t)?e.getElementById(t):t,h=e=>{const t=f(e);return C(t)?Cn(t):null},b=(e,t,n="")=>{let o;const r=h(e);if(C(r)&&Kt(r)){const e=G[t];o=e&&e.get?e.get(r.dom,t):tn(r,t)}return C(o)?o:n},v=e=>{const t=f(e);return y(t)?[]:t.attributes},E=(e,n,o)=>{B(e,(e=>{if(er(e)){const r=Cn(e),s=""===o?null:o,a=tn(r,n),i=G[n];i&&i.set?i.set(r.dom,s,n):ia(r,n,s),a!==s&&t.onSetAttrib&&t.onSetAttrib({attrElm:r.dom,attrName:n,attrValue:s})}}))},x=()=>t.root_element||e.body,_=(t,n)=>((e,t,n)=>{let o=0,r=0;const s=e.ownerDocument;if(n=n||e,t){if(n===e&&t.getBoundingClientRect&&"static"===uo(Cn(e),"position")){const n=t.getBoundingClientRect();return o=n.left+(s.documentElement.scrollLeft||e.scrollLeft)-s.documentElement.clientLeft,r=n.top+(s.documentElement.scrollTop||e.scrollTop)-s.documentElement.clientTop,{x:o,y:r}}let a=t;for(;a&&a!==n&&a.nodeType&&!ns(a,n);){const e=a;o+=e.offsetLeft||0,r+=e.offsetTop||0,a=e.offsetParent}for(a=t.parentNode;a&&a!==n&&a.nodeType&&!ns(a,n);)o-=a.scrollLeft||0,r-=a.scrollTop||0,a=a.parentNode;r+=(e=>es.isFirefox()&&"table"===$t(e)?ts(In(e)).filter((e=>"caption"===$t(e))).bind((e=>ts(Mn(e)).map((t=>{const n=t.dom.offsetTop,o=e.dom.offsetTop,r=e.dom.offsetHeight;return n<=o?-r:0})))).getOr(0):0)(Cn(t))}return{x:o,y:r}})(e.body,f(t),n),S=(e,t,n)=>{const o=f(e);var r;if(!y(o)&&(tr(o)||er(r=o)&&"http://www.w3.org/2000/svg"===r.namespaceURI))return n?uo(Cn(o),la(t)):("float"===(t=t.replace(/-(\D)/g,((e,t)=>t.toUpperCase())))&&(t="cssFloat"),o.style?o.style[t]:void 0)},R=e=>{const t=f(e);if(!t)return{w:0,h:0};let n=S(t,"width"),o=S(t,"height");return n&&-1!==n.indexOf("px")||(n="0"),o&&-1!==o.indexOf("px")||(o="0"),{w:parseInt(n,10)||t.offsetWidth||t.clientWidth,h:parseInt(o,10)||t.offsetHeight||t.clientHeight}},A=(e,t)=>{if(!e)return!1;const n=p(e)?e:[e];return $(n,(e=>xn(Cn(e),t)))},T=(e,t,n,o)=>{const r=[];let s=f(e);o=void 0===o;const a=n||("BODY"!==x().nodeName?x().parentNode:null);if(m(t))if("*"===t)t=er;else{const e=t;t=t=>A(t,e)}for(;s&&!(s===a||y(s.nodeType)||fr(s)||gr(s));){if(!t||t(s)){if(!o)return[s];r.push(s)}s=s.parentNode}return o?r:null},O=(e,t,n)=>{let o=t;if(e){m(t)&&(o=e=>A(e,t));for(let t=e[n];t;t=t[n])if(w(o)&&o(t))return t}return null},B=function(e,t,n){const o=null!=n?n:this;if(p(e)){const n=[];return oa(e,((e,r)=>{const s=f(e);s&&n.push(t.call(o,s,r))})),n}{const n=f(e);return!!n&&t.call(o,n)}},P=(e,t)=>{B(e,(e=>{pe(t,((t,n)=>{E(e,n,t)}))}))},D=(e,t)=>{B(e,(e=>{const n=Cn(e);No(n,t)}))},L=(t,n,o,r,s)=>B(t,(t=>{const a=m(n)?e.createElement(n):n;return C(o)&&P(a,o),r&&(!m(r)&&r.nodeType?a.appendChild(r):m(r)&&D(a,r)),s?a:t.appendChild(a)})),M=(t,n,o)=>L(e.createElement(t),t,n,o,!0),I=ws.encodeAllRaw,F=(e,t)=>B(e,(e=>{const n=Cn(e);return t&&q(In(n),(e=>{Yt(e)&&0===e.dom.length?xo(e):ho(n,e)})),xo(n),n.dom})),U=(e,t,n)=>{B(e,(e=>{if(er(e)){const o=Cn(e),r=t.split(" ");q(r,(e=>{C(n)?(n?mn:gn)(o,e):((e,t)=>{const n=ln(e)?e.dom.classList.toggle(t):((e,t)=>H(dn(e),t)?un(e,t):cn(e,t))(e,t);fn(e)})(o,e)}))}}))},z=(e,t,n)=>B(t,(o=>{var r;const s=p(t)?e.cloneNode(!0):e;return n&&oa(ra(o.childNodes),(e=>{s.appendChild(e)})),null===(r=o.parentNode)||void 0===r||r.replaceChild(s,o),o})),j=()=>e.createRange(),V=(n,r,s,a)=>{if(p(n)){let e=n.length;const t=[];for(;e--;)t[e]=V(n[e],r,s,a);return t}return!t.collect||n!==e&&n!==o||i.push([n,r,s,a]),c.bind(n,r,s,a||Y)},W=(t,n,r)=>{if(p(t)){let e=t.length;const o=[];for(;e--;)o[e]=W(t[e],n,r);return o}if(i.length>0&&(t===e||t===o)){let e=i.length;for(;e--;){const[o,s,a]=i[e];t!==o||n&&n!==s||r&&r!==a||c.unbind(o,s,a)}}return c.unbind(t,n,r)},K=e=>{if(e&&tr(e)){const t=e.getAttribute("data-mce-contenteditable");return t&&"inherit"!==t?t:"inherit"!==e.contentEditable?e.contentEditable:null}return null},Y={doc:e,settings:t,win:o,files:r,stdMode:!0,boxModel:!0,styleSheetLoader:a,boundEvents:i,styles:d,schema:l,events:c,isBlock:e=>m(e)?ke(u,e):er(e)&&(ke(u,e.nodeName)||Zr(l,e)),root:null,clone:(e,t)=>e.cloneNode(t),getRoot:x,getViewPort:e=>{const t=Fo(e);return{x:t.x,y:t.y,w:t.width,h:t.height}},getRect:e=>{const t=f(e),n=_(t),o=R(t);return{x:n.x,y:n.y,w:o.w,h:o.h}},getSize:R,getParent:(e,t,n)=>{const o=T(e,t,n,!1);return o&&o.length>0?o[0]:null},getParents:T,get:f,getNext:(e,t)=>O(e,t,"nextSibling"),getPrev:(e,t)=>O(e,t,"previousSibling"),select:(n,o)=>{var r,s;const a=null!==(s=null!==(r=f(o))&&void 0!==r?r:t.root_element)&&void 0!==s?s:e;return w(a.querySelectorAll)?ce(a.querySelectorAll(n)):[]},is:A,add:L,create:M,createHTML:(e,t,n="")=>{let o="<"+e;for(const e in t)_e(t,e)&&(o+=" "+e+'="'+I(t[e])+'"');return Xe(n)&&ke(l.getVoidElements(),e)?o+" />":o+">"+n+"</"+e+">"},createFragment:t=>{const n=e.createElement("div"),o=e.createDocumentFragment();let r;for(o.appendChild(n),t&&(n.innerHTML=t);r=n.firstChild;)o.appendChild(r);return o.removeChild(n),o},remove:F,setStyle:(e,n,o)=>{B(e,(e=>{const r=Cn(e);ua(r,n,o),t.update_styles&&ca(d,r)}))},getStyle:S,setStyles:(e,n)=>{B(e,(e=>{const o=Cn(e);pe(n,((e,t)=>{ua(o,t,e)})),t.update_styles&&ca(d,o)}))},removeAllAttribs:e=>B(e,(e=>{const t=e.attributes;for(let n=t.length-1;n>=0;n--)e.removeAttributeNode(t.item(n))})),setAttrib:E,setAttribs:P,getAttrib:b,getPos:_,parseStyle:e=>d.parse(e),serializeStyle:(e,t)=>d.serialize(e,t),addStyle:t=>{if(Y!==ma.DOM&&e===document){if(n[t])return;n[t]=!0}let o=e.getElementById("mceDefaultStyles");if(!o){o=e.createElement("style"),o.id="mceDefaultStyles",o.type="text/css";const t=e.head;t.firstChild?t.insertBefore(o,t.firstChild):t.appendChild(o)}o.styleSheet?o.styleSheet.cssText+=t:o.appendChild(e.createTextNode(t))},loadCSS:e=>{e||(e=""),q(e.split(","),(e=>{r[e]=!0,a.load(e).catch(k)}))},addClass:(e,t)=>{U(e,t,!0)},removeClass:(e,t)=>{U(e,t,!1)},hasClass:(e,t)=>{const n=h(e),o=t.split(" ");return C(n)&&ne(o,(e=>pn(n,e)))},toggleClass:U,show:e=>{B(e,(e=>po(Cn(e),"display")))},hide:e=>{B(e,(e=>lo(Cn(e),"display","none")))},isHidden:e=>{const t=h(e);return C(t)&&Lt(fo(t,"display"),"none")},uniqueId:e=>(e||"mce_")+s++,setHTML:D,getOuterHTML:e=>{const t=h(e);return C(t)?er(t.dom)?t.dom.outerHTML:(e=>{const t=vn("div"),n=Cn(e.dom.cloneNode(!0));return yo(t,n),So(t)})(t):""},setOuterHTML:(e,t)=>{B(e,(e=>{er(e)&&(e.outerHTML=t)}))},decode:ws.decode,encode:I,insertAfter:(e,t)=>{const n=f(t);return B(e,(e=>{const t=null==n?void 0:n.parentNode,o=null==n?void 0:n.nextSibling;return t&&(o?t.insertBefore(e,o):t.appendChild(e)),e}))},replace:z,rename:(e,t)=>{if(e.nodeName!==t.toUpperCase()){const n=M(t);return oa(v(e),(t=>{E(n,t.nodeName,b(e,t.nodeName))})),z(n,e,!0),n}return e},findCommonAncestor:(e,t)=>{let n=e;for(;n;){let e=t;for(;e&&n!==e;)e=e.parentNode;if(n===e)break;n=n.parentNode}return!n&&e.ownerDocument?e.ownerDocument.documentElement:n},run:B,getAttribs:v,isEmpty:(e,t,n)=>{if(g(t)){const o=e=>{const n=e.nodeName.toLowerCase();return Boolean(t[n])};return Ar(l,e,{...n,isContent:o})}return Ar(l,e,n)},createRng:j,nodeIndex:da,split:(e,t,n)=>{let o,r,s=j();if(e&&t&&e.parentNode&&t.parentNode){const a=e.parentNode;return s.setStart(a,da(e)),s.setEnd(t.parentNode,da(t)),o=s.extractContents(),s=j(),s.setStart(t.parentNode,da(t)+1),s.setEnd(a,da(e)+1),r=s.extractContents(),a.insertBefore(is(Y,o,l),e),n?a.insertBefore(n,e):a.insertBefore(t,e),a.insertBefore(is(Y,r,l),e),F(e),n||t}},bind:V,unbind:W,fire:(e,t,n)=>c.dispatch(e,t,n),dispatch:(e,t,n)=>c.dispatch(e,t,n),getContentEditable:K,getContentEditableParent:e=>{const t=x();let n=null;for(let o=e;o&&o!==t&&(n=K(o),null===n);o=o.parentNode);return n},isEditable:e=>{if(C(e)){const t=er(e)?e:e.parentElement;return C(t)&&tr(t)&&ro(Cn(t))}return!1},destroy:()=>{if(i.length>0){let e=i.length;for(;e--;){const[t,n,o]=i[e];c.unbind(t,n,o)}}pe(r,((e,t)=>{a.unload(t),delete r[t]}))},isChildOf:(e,t)=>e===t||t.contains(e),dumpRng:e=>"startContainer: "+e.startContainer.nodeName+", startOffset: "+e.startOffset+", endContainer: "+e.endContainer.nodeName+", endOffset: "+e.endOffset},G=((e,t,n)=>{const o=t.keep_values,r={set:(e,o,r)=>{const s=Cn(e);w(t.url_converter)&&C(o)&&(o=t.url_converter.call(t.url_converter_scope||n(),String(o),r,e)),ia(s,"data-mce-"+r,o),ia(s,r,o)},get:(e,t)=>{const n=Cn(e);return tn(n,"data-mce-"+t)||tn(n,t)}},s={style:{set:(t,n)=>{const r=Cn(t);o&&ia(r,sa,n),rn(r,"style"),m(n)&&co(r,e.parse(n))},get:t=>{const n=Cn(t),o=tn(n,sa)||tn(n,"style");return e.serialize(e.parse(o),$t(n))}}};return o&&(s.href=s.src=r),s})(d,t,N(Y));return Y};ma.DOM=ma(document),ma.nodeIndex=da;const fa=ma.DOM;class ga{constructor(e={}){this.states={},this.queue=[],this.scriptLoadedCallbacks={},this.queueLoadedCallbacks=[],this.loading=!1,this.settings=e}_setReferrerPolicy(e){this.settings.referrerPolicy=e}loadScript(e){return new Promise(((t,n)=>{const o=fa;let r;const s=()=>{o.remove(a),r&&(r.onerror=r.onload=r=null)},a=o.uniqueId();r=document.createElement("script"),r.id=a,r.type="text/javascript",r.src=Dt._addCacheSuffix(e),this.settings.referrerPolicy&&o.setAttrib(r,"referrerpolicy",this.settings.referrerPolicy),r.onload=()=>{s(),t()},r.onerror=()=>{s(),n("Failed to load script: "+e)},(document.getElementsByTagName("head")[0]||document.body).appendChild(r)}))}isDone(e){return 2===this.states[e]}markDone(e){this.states[e]=2}add(e){const t=this;return t.queue.push(e),void 0===t.states[e]&&(t.states[e]=0),new Promise(((n,o)=>{t.scriptLoadedCallbacks[e]||(t.scriptLoadedCallbacks[e]=[]),t.scriptLoadedCallbacks[e].push({resolve:n,reject:o})}))}load(e){return this.add(e)}remove(e){delete this.states[e],delete this.scriptLoadedCallbacks[e]}loadQueue(){const e=this.queue;return this.queue=[],this.loadScripts(e)}loadScripts(e){const t=this,n=(e,n)=>{xe(t.scriptLoadedCallbacks,n).each((t=>{q(t,(t=>t[e](n)))})),delete t.scriptLoadedCallbacks[n]},o=e=>{const t=Y(e,(e=>"rejected"===e.status));return t.length>0?Promise.reject(te(t,(({reason:e})=>p(e)?e:[e]))):Promise.resolve()},r=e=>Promise.allSettled(V(e,(e=>2===t.states[e]?(n("resolve",e),Promise.resolve()):3===t.states[e]?(n("reject",e),Promise.reject(e)):(t.states[e]=1,t.loadScript(e).then((()=>{t.states[e]=2,n("resolve",e);const s=t.queue;return s.length>0?(t.queue=[],r(s).then(o)):Promise.resolve()}),(()=>(t.states[e]=3,n("reject",e),Promise.reject(e)))))))),s=e=>(t.loading=!0,r(e).then((e=>{t.loading=!1;const n=t.queueLoadedCallbacks.shift();return I.from(n).each(D),o(e)}))),a=Se(e);return t.loading?new Promise(((e,n)=>{t.queueLoadedCallbacks.push((()=>{s(a).then(e,n)}))})):s(a)}}ga.ScriptLoader=new ga;const pa={},ha=Br("en"),ba=()=>xe(pa,ha.get()),va={getData:()=>he(pa,(e=>({...e}))),setCode:e=>{e&&ha.set(e)},getCode:()=>ha.get(),add:(e,t)=>{let n=pa[e];n||(pa[e]=n={});const o=V(fe(t),(e=>e.toLowerCase()));pe(t,((e,r)=>{const s=r.toLowerCase();s!==r&&((e,t)=>{const n=e.indexOf(t);return-1!==n&&e.indexOf(t,n+1)>n})(o,s)?(ke(t,s)||(n[s]=e),n[r]=e):n[s]=e}))},translate:e=>{const t=ba().getOr({}),n=e=>w(e)?Object.prototype.toString.call(e):o(e)?"":""+e,o=e=>""===e||null==e,r=e=>{const o=n(e);return ke(t,o)?n(t[o]):xe(t,o.toLowerCase()).map(n).getOr(o)},s=e=>e.replace(/{context:\w+}$/,"");if(o(e))return"";if(f(a=e)&&ke(a,"raw"))return n(e.raw);var a;if((e=>p(e)&&e.length>1)(e)){const t=e.slice(1);return s(r(e[0]).replace(/\{([0-9]+)\}/g,((e,o)=>ke(t,o)?n(t[o]):e)))}return s(r(e))},isRtl:()=>ba().bind((e=>xe(e,"_dir"))).exists((e=>"rtl"===e)),hasCode:e=>ke(pa,e)},ya=()=>{const e=[],t={},n={},o=[],r=(e,t)=>{const n=Y(o,(n=>n.name===e&&n.state===t));q(n,(e=>e.resolve()))},s=e=>ke(t,e),a=(e,n)=>{const o=va.getCode();!o||n&&-1===(","+(n||"")+",").indexOf(","+o+",")||ga.ScriptLoader.add(t[e]+"/langs/"+o+".js")},i=(e,t="added")=>"added"===t&&(e=>ke(n,e))(e)||"loaded"===t&&s(e)?Promise.resolve():new Promise((n=>{o.push({name:e,state:t,resolve:n})}));return{items:e,urls:t,lookup:n,get:e=>{if(n[e])return n[e].instance},requireLangPack:(e,t)=>{!1!==ya.languageLoad&&(s(e)?a(e,t):i(e,"loaded").then((()=>a(e,t))))},add:(t,o)=>(e.push(o),n[t]={instance:o},r(t,"added"),o),remove:e=>{delete t[e],delete n[e]},createUrl:(e,t)=>m(t)?m(e)?{prefix:"",resource:t,suffix:""}:{prefix:e.prefix,resource:t,suffix:e.suffix}:t,load:(e,o)=>{if(t[e])return Promise.resolve();let s=m(o)?o:o.prefix+o.resource+o.suffix;0!==s.indexOf("/")&&-1===s.indexOf("://")&&(s=ya.baseURL+"/"+s),t[e]=s.substring(0,s.lastIndexOf("/"));const a=()=>(r(e,"loaded"),Promise.resolve());return n[e]?a():ga.ScriptLoader.add(s).then(a)},waitFor:i}};ya.languageLoad=!0,ya.baseURL="",ya.PluginManager=ya(),ya.ThemeManager=ya(),ya.ModelManager=ya();const Ca=(e,t)=>{let n=null;return{cancel:()=>{h(n)||(clearTimeout(n),n=null)},throttle:(...o)=>{h(n)&&(n=setTimeout((()=>{n=null,e.apply(null,o)}),t))}}},wa=(e,t)=>{let n=null;const o=()=>{h(n)||(clearTimeout(n),n=null)};return{cancel:o,throttle:(...r)=>{o(),n=setTimeout((()=>{n=null,e.apply(null,r)}),t)}}},Ea=N("mce-annotation"),xa=N("data-mce-annotation"),ka=N("data-mce-annotation-uid"),_a=N("data-mce-annotation-active"),Sa=N("data-mce-annotation-classes"),Na=N("data-mce-annotation-attrs"),Ra=e=>t=>_n(t,e),Aa=(e,t)=>{const n=e.selection.getRng(),o=Cn(n.startContainer),r=Cn(e.getBody()),s=t.fold((()=>"."+Ea()),(e=>`[${xa()}="${e}"]`)),a=Fn(o,n.startOffset).getOr(o);return oo(a,s,Ra(r)).bind((t=>nn(t,`${ka()}`).bind((n=>nn(t,`${xa()}`).map((t=>{const o=Oa(e,n);return{uid:n,name:t,elements:o}}))))))},Ta=(e,t)=>on(e,"data-mce-bogus")||((e,t,n)=>to(e,'[data-mce-bogus="all"]',n).isSome())(e,0,Ra(t)),Oa=(e,t)=>{const n=Cn(e.getBody()),o=zo(n,`[${ka()}="${t}"]`);return Y(o,(e=>!Ta(e,n)))},Ba=(e,t)=>{const n=Cn(e.getBody()),o=zo(n,`[${xa()}="${t}"]`),r={};return q(o,(e=>{if(!Ta(e,n)){const t=tn(e,ka()),n=xe(r,t).getOr([]);r[t]=n.concat([e])}})),r};let Pa=0;const Da=e=>{const t=(new Date).getTime(),n=Math.floor(1e9*Math.random());return Pa++,e+"_"+n+Pa+String(t)},La=(e,t)=>Cn(e.dom.cloneNode(t)),Ma=e=>La(e,!1),Ia=e=>La(e,!0),Fa=(e,t,n=L)=>{const o=new Vo(e,t),r=e=>{let t;do{t=o[e]()}while(t&&!dr(t)&&!n(t));return I.from(t).filter(dr)};return{current:()=>I.from(o.current()).filter(dr),next:()=>r("next"),prev:()=>r("prev"),prev2:()=>r("prev2")}},Ua=(e,t)=>{const n=t||(t=>e.isBlock(t)||pr(t)||vr(t)),o=(e,t,n,r)=>{if(dr(e)){const n=r(e,t,e.data);if(-1!==n)return I.some({container:e,offset:n})}return n().bind((e=>o(e.container,e.offset,n,r)))};return{backwards:(t,r,s,a)=>{const i=Fa(t,null!=a?a:e.getRoot(),n);return o(t,r,(()=>i.prev().map((e=>({container:e,offset:e.length})))),s).getOrNull()},forwards:(t,r,s,a)=>{const i=Fa(t,null!=a?a:e.getRoot(),n);return o(t,r,(()=>i.next().map((e=>({container:e,offset:0})))),s).getOrNull()}}},za=((e,t)=>{const n=t=>e(t)?I.from(t.dom.nodeValue):I.none();return{get:t=>{if(!e(t))throw new Error("Can only get text value of a text node");return n(t).getOr("")},getOption:n,set:(t,n)=>{if(!e(t))throw new Error("Can only set raw text value of a text node");t.dom.nodeValue=n}}})(Yt),ja=e=>za.get(e),Ha=e=>{let t;return n=>(t=t||se(e,M),ke(t,$t(n)))},$a=e=>Kt(e)&&"br"===$t(e),Va=Ha(["h1","h2","h3","h4","h5","h6","p","div","address","pre","form","blockquote","center","dir","fieldset","header","footer","article","section","hgroup","aside","nav","figure"]),qa=Ha(["ul","ol","dl"]),Wa=Ha(["li","dd","dt"]),Ka=Ha(["thead","tbody","tfoot"]),Ya=Ha(["td","th"]),Ga=Ha(["pre","script","textarea","style"]),Xa=()=>{const e=vn("br");return Jt(e,"data-mce-bogus","1"),e},Za=e=>{Eo(e),yo(e,Xa())},Qa=qo,Ja=Ko,ei=e=>e.replace(/\uFEFF/g,""),ti=er,ni=dr,oi=e=>(ni(e)&&(e=e.parentNode),ti(e)&&e.hasAttribute("data-mce-caret")),ri=e=>ni(e)&&Ja(e.data),si=e=>oi(e)||ri(e),ai=e=>e.firstChild!==e.lastChild||!pr(e.firstChild),ii=e=>{const t=e.container();return!!dr(t)&&(t.data.charAt(e.offset())===Qa||e.isAtStart()&&ri(t.previousSibling))},li=e=>{const t=e.container();return!!dr(t)&&(t.data.charAt(e.offset()-1)===Qa||e.isAtEnd()&&ri(t.nextSibling))},di=e=>ni(e)&&e.data[0]===Qa,ci=e=>ni(e)&&e.data[e.data.length-1]===Qa,ui=e=>e&&e.hasAttribute("data-mce-caret")?((e=>{var t;const n=e.getElementsByTagName("br"),o=n[n.length-1];sr(o)&&(null===(t=o.parentNode)||void 0===t||t.removeChild(o))})(e),e.removeAttribute("data-mce-caret"),e.removeAttribute("data-mce-bogus"),e.removeAttribute("style"),e.removeAttribute("data-mce-style"),e.removeAttribute("_moz_abspos"),e):null,mi=e=>oi(e.startContainer),fi=Math.round,gi=e=>e?{left:fi(e.left),top:fi(e.top),bottom:fi(e.bottom),right:fi(e.right),width:fi(e.width),height:fi(e.height)}:{left:0,top:0,bottom:0,right:0,width:0,height:0},pi=(e,t)=>(e=gi(e),t||(e.left=e.left+e.width),e.right=e.left,e.width=0,e),hi=(e,t,n)=>e>=0&&e<=Math.min(t.height,n.height)/2,bi=(e,t)=>{const n=Math.min(t.height/2,e.height/2);return e.bottom-n<t.top||!(e.top>t.bottom)&&hi(t.top-e.bottom,e,t)},vi=(e,t)=>e.top>t.bottom||!(e.bottom<t.top)&&hi(t.bottom-e.top,e,t),yi=(e,t,n)=>{const o=Math.max(Math.min(t,e.left+e.width),e.left),r=Math.max(Math.min(n,e.top+e.height),e.top);return Math.sqrt((t-o)*(t-o)+(n-r)*(n-r))},Ci=e=>{const t=e.startContainer,n=e.startOffset;return t===e.endContainer&&t.hasChildNodes()&&e.endOffset===n+1?t.childNodes[n]:null},wi=(e,t)=>{if(er(e)&&e.hasChildNodes()){const n=e.childNodes,o=((e,t,n)=>Math.min(Math.max(e,0),n))(t,0,n.length-1);return n[o]}return e},Ei=new RegExp("[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1abe\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20dd-\u20e0\u20e1\u20e2-\u20e4\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\ua670-\ua672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]"),xi=e=>m(e)&&e.charCodeAt(0)>=768&&Ei.test(e),ki=br,_i=vr,Si=pr,Ni=dr,Ri=or(["script","style","textarea"]),Ai=or(["img","input","textarea","hr","iframe","video","audio","object","embed"]),Ti=or(["table"]),Oi=si,Bi=e=>!Oi(e)&&(Ni(e)?!Ri(e.parentNode):Ai(e)||Si(e)||Ti(e)||Pi(e)),Pi=e=>!(e=>er(e)&&"true"===e.getAttribute("unselectable"))(e)&&_i(e),Di=(e,t)=>Bi(e)&&((e,t)=>{for(let n=e.parentNode;n&&n!==t;n=n.parentNode){if(Pi(n))return!1;if(ki(n))return!0}return!0})(e,t),Li=er,Mi=Bi,Ii=rr("display","block table"),Fi=rr("float","left right"),Ui=((...e)=>t=>{for(let n=0;n<e.length;n++)if(!e[n](t))return!1;return!0})(Li,Mi,O(Fi)),zi=O(rr("white-space","pre pre-line pre-wrap")),ji=dr,Hi=pr,$i=ma.nodeIndex,Vi=(e,t)=>t<0&&er(e)&&e.hasChildNodes()?void 0:wi(e,t),qi=e=>e?e.createRange():ma.DOM.createRng(),Wi=e=>m(e)&&/[\r\n\t ]/.test(e),Ki=e=>!!e.setStart&&!!e.setEnd,Yi=e=>{const t=e.startContainer,n=e.startOffset;if(Wi(e.toString())&&zi(t.parentNode)&&dr(t)){const e=t.data;if(Wi(e[n-1])||Wi(e[n+1]))return!0}return!1},Gi=e=>0===e.left&&0===e.right&&0===e.top&&0===e.bottom,Xi=e=>{var t;let n;const o=e.getClientRects();return n=o.length>0?gi(o[0]):gi(e.getBoundingClientRect()),!Ki(e)&&Hi(e)&&Gi(n)?(e=>{const t=e.ownerDocument,n=qi(t),o=t.createTextNode(Wo),r=e.parentNode;r.insertBefore(o,e),n.setStart(o,0),n.setEnd(o,1);const s=gi(n.getBoundingClientRect());return r.removeChild(o),s})(e):Gi(n)&&Ki(e)&&null!==(t=(e=>{const t=e.startContainer,n=e.endContainer,o=e.startOffset,r=e.endOffset;if(t===n&&dr(n)&&0===o&&1===r){const t=e.cloneRange();return t.setEndAfter(n),Xi(t)}return null})(e))&&void 0!==t?t:n},Zi=(e,t)=>{const n=pi(e,t);return n.width=1,n.right=n.left+1,n},Qi=(e,t,n)=>{const o=()=>(n||(n=(e=>{const t=[],n=e=>{var n,o;0!==e.height&&(t.length>0&&(n=e,o=t[t.length-1],n.left===o.left&&n.top===o.top&&n.bottom===o.bottom&&n.right===o.right)||t.push(e))},o=(e,t)=>{const o=qi(e.ownerDocument);if(t<e.data.length){if(xi(e.data[t]))return;if(xi(e.data[t-1])&&(o.setStart(e,t),o.setEnd(e,t+1),!Yi(o)))return void n(Zi(Xi(o),!1))}t>0&&(o.setStart(e,t-1),o.setEnd(e,t),Yi(o)||n(Zi(Xi(o),!1))),t<e.data.length&&(o.setStart(e,t),o.setEnd(e,t+1),Yi(o)||n(Zi(Xi(o),!0)))},r=e.container(),s=e.offset();if(ji(r))return o(r,s),t;if(Li(r))if(e.isAtEnd()){const e=Vi(r,s);ji(e)&&o(e,e.data.length),Ui(e)&&!Hi(e)&&n(Zi(Xi(e),!1))}else{const a=Vi(r,s);if(ji(a)&&o(a,0),Ui(a)&&e.isAtEnd())return n(Zi(Xi(a),!1)),t;const i=Vi(e.container(),e.offset()-1);Ui(i)&&!Hi(i)&&(Ii(i)||Ii(a)||!Ui(a))&&n(Zi(Xi(i),!1)),Ui(a)&&n(Zi(Xi(a),!0))}return t})(Qi(e,t))),n);return{container:N(e),offset:N(t),toRange:()=>{const n=qi(e.ownerDocument);return n.setStart(e,t),n.setEnd(e,t),n},getClientRects:o,isVisible:()=>o().length>0,isAtStart:()=>(ji(e),0===t),isAtEnd:()=>ji(e)?t>=e.data.length:t>=e.childNodes.length,isEqual:n=>n&&e===n.container()&&t===n.offset(),getNode:n=>Vi(e,n?t-1:t)}};Qi.fromRangeStart=e=>Qi(e.startContainer,e.startOffset),Qi.fromRangeEnd=e=>Qi(e.endContainer,e.endOffset),Qi.after=e=>Qi(e.parentNode,$i(e)+1),Qi.before=e=>Qi(e.parentNode,$i(e)),Qi.isAbove=(e,t)=>It(le(t.getClientRects()),de(e.getClientRects()),bi).getOr(!1),Qi.isBelow=(e,t)=>It(de(t.getClientRects()),le(e.getClientRects()),vi).getOr(!1),Qi.isAtStart=e=>!!e&&e.isAtStart(),Qi.isAtEnd=e=>!!e&&e.isAtEnd(),Qi.isTextPosition=e=>!!e&&dr(e.container()),Qi.isElementPosition=e=>!Qi.isTextPosition(e);const Ji=(e,t)=>{dr(t)&&0===t.data.length&&e.remove(t)},el=(e,t,n)=>{gr(n)?((e,t,n)=>{const o=I.from(n.firstChild),r=I.from(n.lastChild);t.insertNode(n),o.each((t=>Ji(e,t.previousSibling))),r.each((t=>Ji(e,t.nextSibling)))})(e,t,n):((e,t,n)=>{t.insertNode(n),Ji(e,n.previousSibling),Ji(e,n.nextSibling)})(e,t,n)},tl=dr,nl=sr,ol=ma.nodeIndex,rl=e=>{const t=e.parentNode;return nl(t)?rl(t):t},sl=e=>e?Be(e.childNodes,((e,t)=>(nl(t)&&"BR"!==t.nodeName?e=e.concat(sl(t)):e.push(t),e)),[]):[],al=e=>t=>e===t,il=e=>(tl(e)?"text()":e.nodeName.toLowerCase())+"["+(e=>{let t,n;t=sl(rl(e)),n=Pe(t,al(e),e),t=t.slice(0,n+1);const o=Be(t,((e,n,o)=>(tl(n)&&tl(t[o-1])&&e++,e)),0);return t=Oe(t,or([e.nodeName])),n=Pe(t,al(e),e),n-o})(e)+"]",ll=(e,t)=>{let n,o=[],r=t.container(),s=t.offset();if(tl(r))n=((e,t)=>{let n=e;for(;(n=n.previousSibling)&&tl(n);)t+=n.data.length;return t})(r,s);else{const e=r.childNodes;s>=e.length?(n="after",s=e.length-1):n="before",r=e[s]}o.push(il(r));let a=((e,t,n)=>{const o=[];for(let n=t.parentNode;n&&n!==e;n=n.parentNode)o.push(n);return o})(e,r);return a=Oe(a,O(sr)),o=o.concat(Te(a,(e=>il(e)))),o.reverse().join("/")+","+n},dl=(e,t)=>{if(!t)return null;const n=t.split(","),o=n[0].split("/"),r=n.length>1?n[1]:"before",s=Be(o,((e,t)=>{const n=/([\w\-\(\)]+)\[([0-9]+)\]/.exec(t);return n?("text()"===n[1]&&(n[1]="#text"),((e,t,n)=>{let o=sl(e);return o=Oe(o,((e,t)=>!tl(e)||!tl(o[t-1]))),o=Oe(o,or([t])),o[n]})(e,n[1],parseInt(n[2],10))):null}),e);if(!s)return null;if(!tl(s)&&s.parentNode){let e;return e="after"===r?ol(s)+1:ol(s),Qi(s.parentNode,e)}return((e,t)=>{let n=e,o=0;for(;tl(n);){const r=n.data.length;if(t>=o&&t<=o+r){e=n,t-=o;break}if(!tl(n.nextSibling)){e=n,t=r;break}o+=r,n=n.nextSibling}return tl(e)&&t>e.data.length&&(t=e.data.length),Qi(e,t)})(s,parseInt(r,10))},cl=vr,ul=(e,t,n,o,r)=>{const s=r?o.startContainer:o.endContainer;let a=r?o.startOffset:o.endOffset;const i=[],l=e.getRoot();if(dr(s))i.push(n?((e,t,n)=>{let o=e(t.data.slice(0,n)).length;for(let n=t.previousSibling;n&&dr(n);n=n.previousSibling)o+=e(n.data).length;return o})(t,s,a):a);else{let t=0;const o=s.childNodes;a>=o.length&&o.length&&(t=1,a=Math.max(0,o.length-1)),i.push(e.nodeIndex(o[a],n)+t)}for(let t=s;t&&t!==l;t=t.parentNode)i.push(e.nodeIndex(t,n));return i},ml=(e,t,n)=>{let o=0;return Dt.each(e.select(t),(e=>"all"===e.getAttribute("data-mce-bogus")?void 0:e!==n&&void o++)),o},fl=(e,t)=>{let n=t?e.startContainer:e.endContainer,o=t?e.startOffset:e.endOffset;if(er(n)&&"TR"===n.nodeName){const r=n.childNodes;n=r[Math.min(t?o:o-1,r.length-1)],n&&(o=t?0:n.childNodes.length,t?e.setStart(n,o):e.setEnd(n,o))}},gl=e=>(fl(e,!0),fl(e,!1),e),pl=(e,t)=>{if(er(e)&&(e=wi(e,t),cl(e)))return e;if(si(e)){dr(e)&&oi(e)&&(e=e.parentNode);let t=e.previousSibling;if(cl(t))return t;if(t=e.nextSibling,cl(t))return t}},hl=(e,t,n)=>{const o=n.getNode(),r=n.getRng();if("IMG"===o.nodeName||cl(o)){const e=o.nodeName;return{name:e,index:ml(n.dom,e,o)}}const s=(e=>pl(e.startContainer,e.startOffset)||pl(e.endContainer,e.endOffset))(r);if(s){const e=s.tagName;return{name:e,index:ml(n.dom,e,s)}}return((e,t,n,o)=>{const r=t.dom,s=ul(r,e,n,o,!0),a=t.isForward(),i=mi(o)?{isFakeCaret:!0}:{};return t.isCollapsed()?{start:s,forward:a,...i}:{start:s,end:ul(r,e,n,o,!1),forward:a,...i}})(e,n,t,r)},bl=(e,t,n)=>{const o={"data-mce-type":"bookmark",id:t,style:"overflow:hidden;line-height:0px"};return n?e.create("span",o,"&#xFEFF;"):e.create("span",o)},vl=(e,t)=>{const n=e.dom;let o=e.getRng();const r=n.uniqueId(),s=e.isCollapsed(),a=e.getNode(),i=a.nodeName,l=e.isForward();if("IMG"===i)return{name:i,index:ml(n,i,a)};const d=gl(o.cloneRange());if(!s){d.collapse(!1);const e=bl(n,r+"_end",t);el(n,d,e)}o=gl(o),o.collapse(!0);const c=bl(n,r+"_start",t);return el(n,o,c),e.moveToBookmark({id:r,keep:!0,forward:l}),{id:r,forward:l}},yl=T(hl,R,!0),Cl=e=>{const t=t=>t(e),n=N(e),o=()=>r,r={tag:!0,inner:e,fold:(t,n)=>n(e),isValue:M,isError:L,map:t=>El.value(t(e)),mapError:o,bind:t,exists:t,forall:t,getOr:n,or:o,getOrThunk:n,orThunk:o,getOrDie:n,each:t=>{t(e)},toOptional:()=>I.some(e)};return r},wl=e=>{const t=()=>n,n={tag:!1,inner:e,fold:(t,n)=>t(e),isValue:L,isError:M,map:t,mapError:t=>El.error(t(e)),bind:t,exists:L,forall:M,getOr:R,or:R,getOrThunk:P,orThunk:P,getOrDie:B(String(e)),each:k,toOptional:I.none};return n},El={value:Cl,error:wl,fromOption:(e,t)=>e.fold((()=>wl(t)),Cl)},xl=e=>{if(!p(e))throw new Error("cases must be an array");if(0===e.length)throw new Error("there must be at least one case");const t=[],n={};return q(e,((o,r)=>{const s=fe(o);if(1!==s.length)throw new Error("one and only one name per case");const a=s[0],i=o[a];if(void 0!==n[a])throw new Error("duplicate key detected:"+a);if("cata"===a)throw new Error("cannot have a case named cata (sorry)");if(!p(i))throw new Error("case arguments must be an array");t.push(a),n[a]=(...n)=>{const o=n.length;if(o!==i.length)throw new Error("Wrong number of arguments to case "+a+". Expected "+i.length+" ("+i+"), got "+o);return{fold:(...t)=>{if(t.length!==e.length)throw new Error("Wrong number of arguments to fold. Expected "+e.length+", got "+t.length);return t[r].apply(null,n)},match:e=>{const o=fe(e);if(t.length!==o.length)throw new Error("Wrong number of arguments to match. Expected: "+t.join(",")+"\nActual: "+o.join(","));if(!ne(t,(e=>H(o,e))))throw new Error("Not all branches were specified when using match. Specified: "+o.join(", ")+"\nRequired: "+t.join(", "));return e[a].apply(null,n)},log:e=>{console.log(e,{constructors:t,constructor:a,params:n})}}}})),n};xl([{bothErrors:["error1","error2"]},{firstError:["error1","value2"]},{secondError:["value1","error2"]},{bothValues:["value1","value2"]}]);const kl=e=>"inline-command"===e.type||"inline-format"===e.type,_l=e=>"block-command"===e.type||"block-format"===e.type,Sl=e=>{var t;const n=t=>El.error({message:t,pattern:e}),o=(t,o,r)=>{if(void 0!==e.format){let r;if(p(e.format)){if(!ne(e.format,m))return n(t+" pattern has non-string items in the `format` array");r=e.format}else{if(!m(e.format))return n(t+" pattern has non-string `format` parameter");r=[e.format]}return El.value(o(r))}return void 0!==e.cmd?m(e.cmd)?El.value(r(e.cmd,e.value)):n(t+" pattern has non-string `cmd` parameter"):n(t+" pattern is missing both `format` and `cmd` parameters")};if(!f(e))return n("Raw pattern is not an object");if(!m(e.start))return n("Raw pattern is missing `start` parameter");if(void 0!==e.end){if(!m(e.end))return n("Inline pattern has non-string `end` parameter");if(0===e.start.length&&0===e.end.length)return n("Inline pattern has empty `start` and `end` parameters");let t=e.start,r=e.end;return 0===r.length&&(r=t,t=""),o("Inline",(e=>({type:"inline-format",start:t,end:r,format:e})),((e,n)=>({type:"inline-command",start:t,end:r,cmd:e,value:n})))}if(void 0!==e.replacement)return m(e.replacement)?0===e.start.length?n("Replacement pattern has empty `start` parameter"):El.value({type:"inline-command",start:"",end:e.start,cmd:"mceInsertContent",value:e.replacement}):n("Replacement pattern has non-string `replacement` parameter");{const r=null!==(t=e.trigger)&&void 0!==t?t:"space";return 0===e.start.length?n("Block pattern has empty `start` parameter"):o("Block",(t=>({type:"block-format",start:e.start,format:t[0],trigger:r})),((t,n)=>({type:"block-command",start:e.start,cmd:t,value:n,trigger:r})))}},Nl=e=>Y(e,_l),Rl=e=>Y(e,kl),Al=(e,t)=>({...e,blockPatterns:Y(e.blockPatterns,(e=>((e,t)=>("block-command"===e.type||"block-format"===e.type)&&e.trigger===t)(e,t)))}),Tl=e=>{const t=(e=>{const t=[],n=[];return q(e,(e=>{e.fold((e=>{t.push(e)}),(e=>{n.push(e)}))})),{errors:t,values:n}})(V(e,Sl));return q(t.errors,(e=>console.error(e.message,e.pattern))),t.values},Ol=xt().deviceType,Bl=Ol.isTouch(),Pl=ma.DOM,Dl=e=>u(e,RegExp),Ll=e=>t=>t.options.get(e),Ml=e=>m(e)||f(e),Il=(e,t="")=>n=>{const o=m(n);if(o){if(-1!==n.indexOf("=")){const r=(e=>{const t=e.indexOf("=")>0?e.split(/[;,](?![^=;,]*(?:[;,]|$))/):e.split(",");return X(t,((e,t)=>{const n=t.split("="),o=n[0],r=n.length>1?n[1]:o;return e[We(o)]=We(r),e}),{})})(n);return{value:xe(r,e.id).getOr(t),valid:o}}return{value:n,valid:o}}return{valid:!1,message:"Must be a string."}},Fl=Ll("iframe_attrs"),Ul=Ll("doctype"),zl=Ll("document_base_url"),jl=Ll("body_id"),Hl=Ll("body_class"),$l=Ll("content_security_policy"),Vl=Ll("br_in_pre"),ql=Ll("forced_root_block"),Wl=Ll("forced_root_block_attrs"),Kl=Ll("newline_behavior"),Yl=Ll("br_newline_selector"),Gl=Ll("no_newline_selector"),Xl=Ll("keep_styles"),Zl=Ll("end_container_on_empty_block"),Ql=Ll("automatic_uploads"),Jl=Ll("images_reuse_filename"),ed=Ll("images_replace_blob_uris"),td=Ll("icons"),nd=Ll("icons_url"),od=Ll("images_upload_url"),rd=Ll("images_upload_base_path"),sd=Ll("images_upload_credentials"),ad=Ll("images_upload_handler"),id=Ll("content_css_cors"),ld=Ll("referrer_policy"),dd=Ll("language"),cd=Ll("language_url"),ud=Ll("indent_use_margin"),md=Ll("indentation"),fd=Ll("content_css"),gd=Ll("content_style"),pd=Ll("font_css"),hd=Ll("directionality"),bd=Ll("inline_boundaries_selector"),vd=Ll("object_resizing"),yd=Ll("resize_img_proportional"),Cd=Ll("placeholder"),wd=Ll("event_root"),Ed=Ll("service_message"),xd=Ll("theme"),kd=Ll("theme_url"),_d=Ll("model"),Sd=Ll("model_url"),Nd=Ll("inline_boundaries"),Rd=Ll("formats"),Ad=Ll("preview_styles"),Td=Ll("format_empty_lines"),Od=Ll("format_noneditable_selector"),Bd=Ll("custom_ui_selector"),Pd=Ll("inline"),Dd=Ll("hidden_input"),Ld=Ll("submit_patch"),Md=Ll("add_form_submit_trigger"),Id=Ll("add_unload_trigger"),Fd=Ll("custom_undo_redo_levels"),Ud=Ll("disable_nodechange"),zd=Ll("readonly"),jd=Ll("editable_root"),Hd=Ll("content_css_cors"),$d=Ll("plugins"),Vd=Ll("external_plugins"),qd=Ll("block_unsupported_drop"),Wd=Ll("visual"),Kd=Ll("visual_table_class"),Yd=Ll("visual_anchor_class"),Gd=Ll("iframe_aria_text"),Xd=Ll("setup"),Zd=Ll("init_instance_callback"),Qd=Ll("urlconverter_callback"),Jd=Ll("auto_focus"),ec=Ll("browser_spellcheck"),tc=Ll("protect"),nc=Ll("paste_block_drop"),oc=Ll("paste_data_images"),rc=Ll("paste_preprocess"),sc=Ll("paste_postprocess"),ac=Ll("newdocument_content"),ic=Ll("paste_webkit_styles"),lc=Ll("paste_remove_styles_if_webkit"),dc=Ll("paste_merge_formats"),cc=Ll("smart_paste"),uc=Ll("paste_as_text"),mc=Ll("paste_tab_spaces"),fc=Ll("allow_html_data_urls"),gc=Ll("text_patterns"),pc=Ll("text_patterns_lookup"),hc=Ll("noneditable_class"),bc=Ll("editable_class"),vc=Ll("noneditable_regexp"),yc=Ll("preserve_cdata"),Cc=Ll("highlight_on_focus"),wc=Ll("xss_sanitization"),Ec=Ll("init_content_sync"),xc=e=>Dt.explode(e.options.get("images_file_types")),kc=Ll("table_tab_navigation"),_c=Ll("details_initial_state"),Sc=Ll("details_serialized_state"),Nc=Ll("sandbox_iframes"),Rc=e=>e.options.get("sandbox_iframes_exclusions"),Ac=Ll("convert_unsafe_embeds"),Tc=Ll("license_key"),Oc=Ll("api_key"),Bc=er,Pc=dr,Dc=e=>{const t=e.parentNode;t&&t.removeChild(e)},Lc=e=>{const t=ei(e);return{count:e.length-t.length,text:t}},Mc=e=>{let t;for(;-1!==(t=e.data.lastIndexOf(Qa));)e.deleteData(t,1)},Ic=(e,t)=>(Uc(e),t),Fc=(e,t)=>Qi.isTextPosition(t)?((e,t)=>Pc(e)&&t.container()===e?((e,t)=>{const n=Lc(e.data.substr(0,t.offset())),o=Lc(e.data.substr(t.offset()));return(n.text+o.text).length>0?(Mc(e),Qi(e,t.offset()-n.count)):t})(e,t):Ic(e,t))(e,t):((e,t)=>t.container()===e.parentNode?((e,t)=>{const n=t.container(),o=((e,t)=>{const n=j(e,t);return-1===n?I.none():I.some(n)})(ce(n.childNodes),e).map((e=>e<t.offset()?Qi(n,t.offset()-1):t)).getOr(t);return Uc(e),o})(e,t):Ic(e,t))(e,t),Uc=e=>{Bc(e)&&si(e)&&(ai(e)?e.removeAttribute("data-mce-caret"):Dc(e)),Pc(e)&&(Mc(e),0===e.data.length&&Dc(e))},zc=vr,jc=wr,Hc=yr,$c=(e,t,n)=>{const o=pi(t.getBoundingClientRect(),n);let r,s;if("BODY"===e.tagName){const t=e.ownerDocument.documentElement;r=e.scrollLeft||t.scrollLeft,s=e.scrollTop||t.scrollTop}else{const t=e.getBoundingClientRect();r=e.scrollLeft-t.left,s=e.scrollTop-t.top}o.left+=r,o.right+=r,o.top+=s,o.bottom+=s,o.width=1;let a=t.offsetWidth-t.clientWidth;return a>0&&(n&&(a*=-1),o.left+=a,o.right+=a),o},Vc=(e,t,n,o)=>{const r=Dr();let s,a;const i=ql(e),l=e.dom,d=()=>{(e=>{var t,n;const o=zo(Cn(e),"*[contentEditable=false],video,audio,embed,object");for(let e=0;e<o.length;e++){const r=o[e].dom;let s=r.previousSibling;if(ci(s)){const e=s.data;1===e.length?null===(t=s.parentNode)||void 0===t||t.removeChild(s):s.deleteData(e.length-1,1)}s=r.nextSibling,di(s)&&(1===s.data.length?null===(n=s.parentNode)||void 0===n||n.removeChild(s):s.deleteData(0,1))}})(t),a&&(Uc(a),a=null),r.on((e=>{l.remove(e.caret),r.clear()})),s&&(clearInterval(s),s=void 0)};return{show:(e,c)=>{let u;if(d(),Hc(c))return null;if(!n(c))return a=((e,t)=>{var n;const o=(null!==(n=e.ownerDocument)&&void 0!==n?n:document).createTextNode(Qa),r=e.parentNode;if(t){const t=e.previousSibling;if(ni(t)){if(si(t))return t;if(ci(t))return t.splitText(t.data.length-1)}null==r||r.insertBefore(o,e)}else{const t=e.nextSibling;if(ni(t)){if(si(t))return t;if(di(t))return t.splitText(1),t}e.nextSibling?null==r||r.insertBefore(o,e.nextSibling):null==r||r.appendChild(o)}return o})(c,e),u=c.ownerDocument.createRange(),Wc(a.nextSibling)?(u.setStart(a,0),u.setEnd(a,0)):(u.setStart(a,1),u.setEnd(a,1)),u;{const n=((e,t,n)=>{var o;const r=(null!==(o=t.ownerDocument)&&void 0!==o?o:document).createElement(e);r.setAttribute("data-mce-caret",n?"before":"after"),r.setAttribute("data-mce-bogus","all"),r.appendChild(Xa().dom);const s=t.parentNode;return n?null==s||s.insertBefore(r,t):t.nextSibling?null==s||s.insertBefore(r,t.nextSibling):null==s||s.appendChild(r),r})(i,c,e),d=$c(t,c,e);l.setStyle(n,"top",d.top),l.setStyle(n,"caret-color","transparent"),a=n;const m=l.create("div",{class:"mce-visual-caret","data-mce-bogus":"all"});l.setStyles(m,{...d}),l.add(t,m),r.set({caret:m,element:c,before:e}),e&&l.addClass(m,"mce-visual-caret-before"),s=setInterval((()=>{r.on((e=>{o()?l.toggleClass(e.caret,"mce-visual-caret-hidden"):l.addClass(e.caret,"mce-visual-caret-hidden")}))}),500),u=c.ownerDocument.createRange(),u.setStart(n,0),u.setEnd(n,0)}return u},hide:d,getCss:()=>".mce-visual-caret {position: absolute;background-color: black;background-color: currentcolor;}.mce-visual-caret-hidden {display: none;}*[data-mce-caret] {position: absolute;left: -1000px;right: auto;top: 0;margin: 0;padding: 0;}",reposition:()=>{r.on((e=>{const n=$c(t,e.element,e.before);l.setStyles(e.caret,{...n})}))},destroy:()=>clearInterval(s)}},qc=()=>Tt.browser.isFirefox(),Wc=e=>zc(e)||jc(e),Kc=e=>(Wc(e)||ar(e)&&qc())&&On(Cn(e)).exists(ro),Yc=br,Gc=vr,Xc=wr,Zc=rr("display","block table table-cell table-caption list-item"),Qc=si,Jc=oi,eu=er,tu=dr,nu=Bi,ou=e=>e>0,ru=e=>e<0,su=(e,t)=>{let n;for(;n=e(t);)if(!Jc(n))return n;return null},au=(e,t,n,o,r)=>{const s=new Vo(e,o),a=Gc(e)||Jc(e);let i;if(ru(t)){if(a&&(i=su(s.prev.bind(s),!0),n(i)))return i;for(;i=su(s.prev.bind(s),r);)if(n(i))return i}if(ou(t)){if(a&&(i=su(s.next.bind(s),!0),n(i)))return i;for(;i=su(s.next.bind(s),r);)if(n(i))return i}return null},iu=(e,t)=>{for(;e&&e!==t;){if(Zc(e))return e;e=e.parentNode}return null},lu=(e,t,n)=>iu(e.container(),n)===iu(t.container(),n),du=(e,t)=>{if(!t)return I.none();const n=t.container(),o=t.offset();return eu(n)?I.from(n.childNodes[o+e]):I.none()},cu=(e,t)=>{var n;const o=(null!==(n=t.ownerDocument)&&void 0!==n?n:document).createRange();return e?(o.setStartBefore(t),o.setEndBefore(t)):(o.setStartAfter(t),o.setEndAfter(t)),o},uu=(e,t,n)=>iu(t,e)===iu(n,e),mu=(e,t,n)=>{const o=e?"previousSibling":"nextSibling";let r=n;for(;r&&r!==t;){let e=r[o];if(e&&Qc(e)&&(e=e[o]),Gc(e)||Xc(e)){if(uu(t,e,r))return e;break}if(nu(e))break;r=r.parentNode}return null},fu=T(cu,!0),gu=T(cu,!1),pu=(e,t,n)=>{let o;const r=T(mu,!0,t),s=T(mu,!1,t),a=n.startContainer,i=n.startOffset;if(oi(a)){const e=tu(a)?a.parentNode:a,t=e.getAttribute("data-mce-caret");if("before"===t&&(o=e.nextSibling,Kc(o)))return fu(o);if("after"===t&&(o=e.previousSibling,Kc(o)))return gu(o)}if(!n.collapsed)return n;if(dr(a)){if(Qc(a)){if(1===e){if(o=s(a),o)return fu(o);if(o=r(a),o)return gu(o)}if(-1===e){if(o=r(a),o)return gu(o);if(o=s(a),o)return fu(o)}return n}if(ci(a)&&i>=a.data.length-1)return 1===e&&(o=s(a),o)?fu(o):n;if(di(a)&&i<=1)return-1===e&&(o=r(a),o)?gu(o):n;if(i===a.data.length)return o=s(a),o?fu(o):n;if(0===i)return o=r(a),o?gu(o):n}return n},hu=(e,t)=>du(e?0:-1,t).filter(Gc),bu=(e,t,n)=>{const o=pu(e,t,n);return-1===e?Qi.fromRangeStart(o):Qi.fromRangeEnd(o)},vu=e=>I.from(e.getNode()).map(Cn),yu=(e,t)=>{let n=t;for(;n=e(n);)if(n.isVisible())return n;return n},Cu=(e,t)=>{const n=lu(e,t);return!(n||!pr(e.getNode()))||n};var wu;!function(e){e[e.Backwards=-1]="Backwards",e[e.Forwards=1]="Forwards"}(wu||(wu={}));const Eu=vr,xu=dr,ku=er,_u=pr,Su=Bi,Nu=e=>Ai(e)||(e=>!!Pi(e)&&!X(ce(e.getElementsByTagName("*")),((e,t)=>e||ki(t)),!1))(e),Ru=Di,Au=(e,t)=>e.hasChildNodes()&&t<e.childNodes.length?e.childNodes[t]:null,Tu=(e,t)=>{if(ou(e)){if(Su(t.previousSibling)&&!xu(t.previousSibling))return Qi.before(t);if(xu(t))return Qi(t,0)}if(ru(e)){if(Su(t.nextSibling)&&!xu(t.nextSibling))return Qi.after(t);if(xu(t))return Qi(t,t.data.length)}return ru(e)?_u(t)?Qi.before(t):Qi.after(t):Qi.before(t)},Ou=(e,t,n)=>{let o,r,s,a;if(!ku(n)||!t)return null;if(t.isEqual(Qi.after(n))&&n.lastChild){if(a=Qi.after(n.lastChild),ru(e)&&Su(n.lastChild)&&ku(n.lastChild))return _u(n.lastChild)?Qi.before(n.lastChild):a}else a=t;const i=a.container();let l=a.offset();if(xu(i)){if(ru(e)&&l>0)return Qi(i,--l);if(ou(e)&&l<i.length)return Qi(i,++l);o=i}else{if(ru(e)&&l>0&&(r=Au(i,l-1),Su(r)))return!Nu(r)&&(s=au(r,e,Ru,r),s)?xu(s)?Qi(s,s.data.length):Qi.after(s):xu(r)?Qi(r,r.data.length):Qi.before(r);if(ou(e)&&l<i.childNodes.length&&(r=Au(i,l),Su(r)))return _u(r)?((e,t)=>{const n=t.nextSibling;return n&&Su(n)?xu(n)?Qi(n,0):Qi.before(n):Ou(wu.Forwards,Qi.after(t),e)})(n,r):!Nu(r)&&(s=au(r,e,Ru,r),s)?xu(s)?Qi(s,0):Qi.before(s):xu(r)?Qi(r,0):Qi.after(r);o=r||a.getNode()}if(o&&(ou(e)&&a.isAtEnd()||ru(e)&&a.isAtStart())&&(o=au(o,e,M,n,!0),Ru(o,n)))return Tu(e,o);r=o?au(o,e,Ru,n):o;const d=De(Y(((e,t)=>{const n=[];let o=e;for(;o&&o!==t;)n.push(o),o=o.parentNode;return n})(i,n),Eu));return!d||r&&d.contains(r)?r?Tu(e,r):null:(a=ou(e)?Qi.after(d):Qi.before(d),a)},Bu=e=>({next:t=>Ou(wu.Forwards,t,e),prev:t=>Ou(wu.Backwards,t,e)}),Pu=e=>Qi.isTextPosition(e)?0===e.offset():Bi(e.getNode()),Du=e=>{if(Qi.isTextPosition(e)){const t=e.container();return e.offset()===t.data.length}return Bi(e.getNode(!0))},Lu=(e,t)=>!Qi.isTextPosition(e)&&!Qi.isTextPosition(t)&&e.getNode()===t.getNode(!0),Mu=(e,t,n)=>{const o=Bu(t);return I.from(e?o.next(n):o.prev(n))},Iu=(e,t,n)=>Mu(e,t,n).bind((o=>lu(n,o,t)&&((e,t,n)=>{return e?!Lu(t,n)&&(o=t,!(!Qi.isTextPosition(o)&&pr(o.getNode())))&&Du(t)&&Pu(n):!Lu(n,t)&&Pu(t)&&Du(n);var o})(e,n,o)?Mu(e,t,o):I.some(o))),Fu=(e,t,n,o)=>Iu(e,t,n).bind((n=>o(n)?Fu(e,t,n,o):I.some(n))),Uu=(e,t)=>{const n=e?t.firstChild:t.lastChild;return dr(n)?I.some(Qi(n,e?0:n.data.length)):n?Bi(n)?I.some(e?Qi.before(n):pr(o=n)?Qi.before(o):Qi.after(o)):((e,t,n)=>{const o=e?Qi.before(n):Qi.after(n);return Mu(e,t,o)})(e,t,n):I.none();var o},zu=T(Mu,!0),ju=T(Mu,!1),Hu=T(Uu,!0),$u=T(Uu,!1),Vu="_mce_caret",qu=e=>er(e)&&e.id===Vu,Wu=(e,t)=>{let n=t;for(;n&&n!==e;){if(qu(n))return n;n=n.parentNode}return null},Ku=e=>ke(e,"name"),Yu=e=>Dt.isArray(e.start),Gu=e=>!(!Ku(e)&&b(e.forward))||e.forward,Xu=(e,t)=>(er(t)&&e.isBlock(t)&&!t.innerHTML&&(t.innerHTML='<br data-mce-bogus="1" />'),t),Zu=(e,t)=>$u(e).fold(L,(e=>(t.setStart(e.container(),e.offset()),t.setEnd(e.container(),e.offset()),!0))),Qu=(e,t,n)=>!(!(e=>!e.hasChildNodes())(t)||!Wu(e,t)||(((e,t)=>{var n;const o=(null!==(n=e.ownerDocument)&&void 0!==n?n:document).createTextNode(Qa);e.appendChild(o),t.setStart(o,0),t.setEnd(o,0)})(t,n),0)),Ju=(e,t,n,o)=>{const r=n[t?"start":"end"],s=e.getRoot();if(r){let e=s,n=r[0];for(let t=r.length-1;e&&t>=1;t--){const n=e.childNodes;if(Qu(s,e,o))return!0;if(r[t]>n.length-1)return!!Qu(s,e,o)||Zu(e,o);e=n[r[t]]}dr(e)&&(n=Math.min(r[0],e.data.length)),er(e)&&(n=Math.min(r[0],e.childNodes.length)),t?o.setStart(e,n):o.setEnd(e,n)}return!0},em=e=>dr(e)&&e.data.length>0,tm=(e,t,n)=>{const o=e.get(n.id+"_"+t),r=null==o?void 0:o.parentNode,s=n.keep;if(o&&r){let a,i;if("start"===t?s?o.hasChildNodes()?(a=o.firstChild,i=1):em(o.nextSibling)?(a=o.nextSibling,i=0):em(o.previousSibling)?(a=o.previousSibling,i=o.previousSibling.data.length):(a=r,i=e.nodeIndex(o)+1):(a=r,i=e.nodeIndex(o)):s?o.hasChildNodes()?(a=o.firstChild,i=1):em(o.previousSibling)?(a=o.previousSibling,i=o.previousSibling.data.length):(a=r,i=e.nodeIndex(o)):(a=r,i=e.nodeIndex(o)),!s){const r=o.previousSibling,s=o.nextSibling;let l;for(Dt.each(Dt.grep(o.childNodes),(e=>{dr(e)&&(e.data=e.data.replace(/\uFEFF/g,""))}));l=e.get(n.id+"_"+t);)e.remove(l,!0);if(dr(s)&&dr(r)&&!Tt.browser.isOpera()){const t=r.data.length;r.appendData(s.data),e.remove(s),a=r,i=t}}return I.some(Qi(a,i))}return I.none()},nm=(e,t,n)=>((e,t,n=!1)=>2===t?hl(ei,n,e):3===t?(e=>{const t=e.getRng();return{start:ll(e.dom.getRoot(),Qi.fromRangeStart(t)),end:ll(e.dom.getRoot(),Qi.fromRangeEnd(t)),forward:e.isForward()}})(e):t?(e=>({rng:e.getRng(),forward:e.isForward()}))(e):vl(e,!1))(e,t,n),om=(e,t)=>{((e,t)=>{const n=e.dom;if(t){if(Yu(t))return((e,t)=>{const n=e.createRng();return Ju(e,!0,t,n)&&Ju(e,!1,t,n)?I.some({range:n,forward:Gu(t)}):I.none()})(n,t);if((e=>m(e.start))(t))return((e,t)=>{const n=I.from(dl(e.getRoot(),t.start)),o=I.from(dl(e.getRoot(),t.end));return It(n,o,((n,o)=>{const r=e.createRng();return r.setStart(n.container(),n.offset()),r.setEnd(o.container(),o.offset()),{range:r,forward:Gu(t)}}))})(n,t);if((e=>ke(e,"id"))(t))return((e,t)=>{const n=tm(e,"start",t),o=tm(e,"end",t);return It(n,o.or(n),((n,o)=>{const r=e.createRng();return r.setStart(Xu(e,n.container()),n.offset()),r.setEnd(Xu(e,o.container()),o.offset()),{range:r,forward:Gu(t)}}))})(n,t);if(Ku(t))return((e,t)=>I.from(e.select(t.name)[t.index]).map((t=>{const n=e.createRng();return n.selectNode(t),{range:n,forward:!0}})))(n,t);if((e=>ke(e,"rng"))(t))return I.some({range:t.rng,forward:Gu(t)})}return I.none()})(e,t).each((({range:t,forward:n})=>{e.setRng(t,n)}))},rm=e=>er(e)&&"SPAN"===e.tagName&&"bookmark"===e.getAttribute("data-mce-type"),sm=(am=Wo,e=>am===e);var am;const im=e=>""!==e&&-1!==" \f\n\r\t\v".indexOf(e),lm=e=>!im(e)&&!sm(e)&&!Ko(e),dm=e=>{const t=[];if(e)for(let n=0;n<e.rangeCount;n++)t.push(e.getRangeAt(n));return t},cm=(e,t)=>{const n=zo(t,"td[data-mce-selected],th[data-mce-selected]");return n.length>0?n:(e=>Y((e=>te(e,(e=>{const t=Ci(e);return t?[Cn(t)]:[]})))(e),Ya))(e)},um=e=>cm(dm(e.selection.getSel()),Cn(e.getBody())),mm=(e,t)=>to(e,"table",t),fm=e=>Un(e).fold(N([e]),(t=>[e].concat(fm(t)))),gm=e=>zn(e).fold(N([e]),(t=>"br"===$t(t)?Pn(t).map((t=>[e].concat(gm(t)))).getOr([]):[e].concat(gm(t)))),pm=(e,t)=>It((e=>{const t=e.startContainer,n=e.startOffset;return dr(t)?0===n?I.some(Cn(t)):I.none():I.from(t.childNodes[n]).map(Cn)})(t),(e=>{const t=e.endContainer,n=e.endOffset;return dr(t)?n===t.data.length?I.some(Cn(t)):I.none():I.from(t.childNodes[n-1]).map(Cn)})(t),((t,n)=>{const o=Q(fm(e),T(_n,t)),r=Q(gm(e),T(_n,n));return o.isSome()&&r.isSome()})).getOr(!1),hm=(e,t,n,o)=>{const r=n,s=new Vo(n,r),a=Ce(e.schema.getMoveCaretBeforeOnEnterElements(),((e,t)=>!H(["td","th","table"],t.toLowerCase())));let i=n;do{if(dr(i)&&0!==Dt.trim(i.data).length)return void(o?t.setStart(i,0):t.setEnd(i,i.data.length));if(a[i.nodeName])return void(o?t.setStartBefore(i):"BR"===i.nodeName?t.setEndBefore(i):t.setEndAfter(i))}while(i=o?s.next():s.prev());"BODY"===r.nodeName&&(o?t.setStart(r,0):t.setEnd(r,r.childNodes.length))},bm=e=>{const t=e.selection.getSel();return C(t)&&t.rangeCount>0},vm=(e,t)=>{const n=um(e);n.length>0?q(n,(n=>{const o=n.dom,r=e.dom.createRng();r.setStartBefore(o),r.setEndAfter(o),t(r,!0)})):t(e.selection.getRng(),!1)},ym=(e,t,n)=>{const o=vl(e,t);n(o),e.moveToBookmark(o)},Cm=e=>E(null==e?void 0:e.nodeType),wm=e=>er(e)&&!rm(e)&&!qu(e)&&!sr(e),Em=(e,t,n)=>{const{selection:o,dom:r}=e,s=o.getNode(),a=vr(s);ym(o,!0,(()=>{t()})),a&&vr(s)&&r.isChildOf(s,e.getBody())?e.selection.select(s):n(o.getStart())&&xm(r,o)},xm=(e,t)=>{var n,o;const r=t.getRng(),{startContainer:s,startOffset:a}=r;if(!((e,t)=>{if(wm(t)&&!/^(TD|TH)$/.test(t.nodeName)){const n=e.getAttrib(t,"data-mce-selected"),o=parseInt(n,10);return!isNaN(o)&&o>0}return!1})(e,t.getNode())&&er(s)){const i=s.childNodes,l=e.getRoot();let d;if(a<i.length){const t=i[a];d=new Vo(t,null!==(n=e.getParent(t,e.isBlock))&&void 0!==n?n:l)}else{const t=i[i.length-1];d=new Vo(t,null!==(o=e.getParent(t,e.isBlock))&&void 0!==o?o:l),d.next(!0)}for(let n=d.current();n;n=d.next()){if("false"===e.getContentEditable(n))return;if(dr(n)&&!Nm(n))return r.setStart(n,0),void t.setRng(r)}}},km=(e,t,n)=>{if(e){const o=t?"nextSibling":"previousSibling";for(e=n?e:e[o];e;e=e[o])if(er(e)||!Nm(e))return e}},_m=(e,t)=>!!e.getTextBlockElements()[t.nodeName.toLowerCase()]||Zr(e,t),Sm=(e,t,n)=>e.schema.isValidChild(t,n),Nm=(e,t=!1)=>{if(C(e)&&dr(e)){const n=t?e.data.replace(/ /g,"\xa0"):e.data;return Go(n)}return!1},Rm=(e,t)=>{const n=e.dom;return wm(t)&&"false"===n.getContentEditable(t)&&((e,t)=>{const n="[data-mce-cef-wrappable]",o=Od(e),r=Xe(o)?n:`${n},${o}`;return xn(Cn(t),r)})(e,t)&&0===n.select('[contenteditable="true"]',t).length},Am=(e,t)=>w(e)?e(t):(C(t)&&(e=e.replace(/%(\w+)/g,((e,n)=>t[n]||e))),e),Tm=(e,t)=>(t=t||"",e=""+((e=e||"").nodeName||e),t=""+(t.nodeName||t),e.toLowerCase()===t.toLowerCase()),Om=(e,t)=>{if(y(e))return null;{let n=String(e);return"color"!==t&&"backgroundColor"!==t||(n=Ws(n)),"fontWeight"===t&&700===e&&(n="bold"),"fontFamily"===t&&(n=n.replace(/[\'\"]/g,"").replace(/,\s+/g,",")),n}},Bm=(e,t,n)=>{const o=e.getStyle(t,n);return Om(o,n)},Pm=(e,t)=>{let n;return e.getParent(t,(t=>!!er(t)&&(n=e.getStyle(t,"text-decoration"),!!n&&"none"!==n))),n},Dm=(e,t,n)=>e.getParents(t,n,e.getRoot()),Lm=(e,t,n)=>{const o=e.formatter.get(t);return C(o)&&$(o,n)},Mm=e=>_e(e,"block"),Im=e=>_e(e,"selector"),Fm=e=>_e(e,"inline"),Um=e=>Im(e)&&!1!==e.expand&&!Fm(e),zm=e=>(e=>{const t=[];let n=e;for(;n;){if(dr(n)&&n.data!==Qa||n.childNodes.length>1)return[];er(n)&&t.push(n),n=n.firstChild}return t})(e).length>0,jm=e=>qu(e.dom)&&zm(e.dom),Hm=rm,$m=Dm,Vm=Nm,qm=_m,Wm=(e,t)=>{let n=t;for(;n;){if(er(n)&&e.getContentEditable(n))return"false"===e.getContentEditable(n)?n:t;n=n.parentNode}return t},Km=(e,t,n,o)=>{const r=t.data;if(e){for(let e=n;e>0;e--)if(o(r.charAt(e-1)))return e}else for(let e=n;e<r.length;e++)if(o(r.charAt(e)))return e;return-1},Ym=(e,t,n)=>Km(e,t,n,(e=>sm(e)||im(e))),Gm=(e,t,n)=>Km(e,t,n,lm),Xm=(e,t,n,o,r,s)=>{let a;const i=e.getParent(n,e.isBlock)||t,l=(t,n,o)=>{const s=Ua(e),l=r?s.backwards:s.forwards;return I.from(l(t,n,((e,t)=>Hm(e.parentNode)?-1:(a=e,o(r,e,t))),i))};return l(n,o,Ym).bind((e=>s?l(e.container,e.offset+(r?-1:0),Gm):I.some(e))).orThunk((()=>a?I.some({container:a,offset:r?0:a.length}):I.none()))},Zm=(e,t,n,o,r)=>{const s=o[r];dr(o)&&Xe(o.data)&&s&&(o=s);const a=$m(e,o);for(let o=0;o<a.length;o++)for(let r=0;r<t.length;r++){const s=t[r];if((!C(s.collapsed)||s.collapsed===n.collapsed)&&Im(s)&&e.is(a[o],s.selector))return a[o]}return o},Qm=(e,t,n,o)=>{var r;let s=n;const a=e.getRoot(),i=t[0];if(Mm(i)&&(s=i.wrapper?null:e.getParent(n,i.block,a)),!s){const t=null!==(r=e.getParent(n,"LI,TD,TH,SUMMARY"))&&void 0!==r?r:a;s=e.getParent(dr(n)?n.parentNode:n,(t=>t!==a&&qm(e.schema,t)),t)}if(s&&Mm(i)&&i.wrapper&&(s=$m(e,s,"ul,ol").reverse()[0]||s),!s)for(s=n;s&&s[o]&&!e.isBlock(s[o])&&(s=s[o],!Tm(s,"br")););return s||n},Jm=(e,t,n,o)=>{const r=n.parentNode;return!C(n[o])&&(!(r!==t&&!y(r)&&!e.isBlock(r))||Jm(e,t,r,o))},ef=(e,t,n,o,r)=>{let s=n;const a=r?"previousSibling":"nextSibling",i=e.getRoot();if(dr(n)&&!Vm(n)&&(r?o>0:o<n.data.length))return n;for(;s;){if(!t[0].block_expand&&e.isBlock(s))return s;for(let t=s[a];t;t=t[a]){const n=dr(t)&&!Jm(e,i,t,a);if(!Hm(t)&&(!pr(l=t)||!l.getAttribute("data-mce-bogus")||l.nextSibling)&&!Vm(t,n))return s}if(s===i||s.parentNode===i){n=s;break}s=s.parentNode}var l;return n},tf=e=>Hm(e.parentNode)||Hm(e),nf=(e,t,n,o=!1)=>{let{startContainer:r,startOffset:s,endContainer:a,endOffset:i}=t;const l=n[0];return er(r)&&r.hasChildNodes()&&(r=wi(r,s),dr(r)&&(s=0)),er(a)&&a.hasChildNodes()&&(a=wi(a,t.collapsed?i:i-1),dr(a)&&(i=a.data.length)),r=Wm(e,r),a=Wm(e,a),tf(r)&&(r=Hm(r)?r:r.parentNode,r=t.collapsed?r.previousSibling||r:r.nextSibling||r,dr(r)&&(s=t.collapsed?r.length:0)),tf(a)&&(a=Hm(a)?a:a.parentNode,a=t.collapsed?a.nextSibling||a:a.previousSibling||a,dr(a)&&(i=t.collapsed?0:a.length)),t.collapsed&&(Xm(e,e.getRoot(),r,s,!0,o).each((({container:e,offset:t})=>{r=e,s=t})),Xm(e,e.getRoot(),a,i,!1,o).each((({container:e,offset:t})=>{a=e,i=t}))),(Fm(l)||l.block_expand)&&(Fm(l)&&dr(r)&&0!==s||(r=ef(e,n,r,s,!0)),Fm(l)&&dr(a)&&i!==a.data.length||(a=ef(e,n,a,i,!1))),Um(l)&&(r=Zm(e,n,t,r,"previousSibling"),a=Zm(e,n,t,a,"nextSibling")),(Mm(l)||Im(l))&&(r=Qm(e,n,r,"previousSibling"),a=Qm(e,n,a,"nextSibling"),Mm(l)&&(e.isBlock(r)||(r=ef(e,n,r,s,!0),dr(r)&&(s=0)),e.isBlock(a)||(a=ef(e,n,a,i,!1),dr(a)&&(i=a.data.length)))),er(r)&&r.parentNode&&(s=e.nodeIndex(r),r=r.parentNode),er(a)&&a.parentNode&&(i=e.nodeIndex(a)+1,a=a.parentNode),{startContainer:r,startOffset:s,endContainer:a,endOffset:i}},of=(e,t,n)=>{var o;const r=t.startOffset,s=wi(t.startContainer,r),a=t.endOffset,i=wi(t.endContainer,a-1),l=e=>{const t=e[0];dr(t)&&t===s&&r>=t.data.length&&e.splice(0,1);const n=e[e.length-1];return 0===a&&e.length>0&&n===i&&dr(n)&&e.splice(e.length-1,1),e},d=(e,t,n)=>{const o=[];for(;e&&e!==n;e=e[t])o.push(e);return o},c=(t,n)=>e.getParent(t,(e=>e.parentNode===n),n),u=(e,t,o)=>{const r=o?"nextSibling":"previousSibling";for(let s=e,a=s.parentNode;s&&s!==t;s=a){a=s.parentNode;const t=d(s===e?s:s[r],r);t.length&&(o||t.reverse(),n(l(t)))}};if(s===i)return n(l([s]));const m=null!==(o=e.findCommonAncestor(s,i))&&void 0!==o?o:e.getRoot();if(e.isChildOf(s,i))return u(s,m,!0);if(e.isChildOf(i,s))return u(i,m);const f=c(s,m)||s,g=c(i,m)||i;u(s,f,!0);const p=d(f===s?f:f.nextSibling,"nextSibling",g===i?g.nextSibling:g);p.length&&n(l(p)),u(i,g)},rf=['pre[class*=language-][contenteditable="false"]',"figure.image","div[data-ephox-embed-iri]","div.tiny-pageembed","div.mce-toc","div[data-mce-toc]"],sf=(e,t,n,o,r,s)=>{const{uid:a=t,...i}=n;mn(e,Ea()),Jt(e,`${ka()}`,a),Jt(e,`${xa()}`,o);const{attributes:l={},classes:d=[]}=r(a,i);if(en(e,l),((e,t)=>{q(t,(t=>{mn(e,t)}))})(e,d),s){d.length>0&&Jt(e,`${Sa()}`,d.join(","));const t=fe(l);t.length>0&&Jt(e,`${Na()}`,t.join(","))}},af=(e,t,n,o,r)=>{const s=vn("span",e);return sf(s,t,n,o,r,!1),s},lf=(e,t,n,o,r,s)=>{const a=[],i=af(e.getDoc(),n,s,o,r),l=Dr(),d=()=>{l.clear()},c=e=>{q(e,u)},u=t=>{switch(((e,t,n,o)=>Tn(t).fold((()=>"skipping"),(r=>"br"===o||(e=>Yt(e)&&ja(e)===Qa)(t)?"valid":(e=>Kt(e)&&pn(e,Ea()))(t)?"existing":qu(t.dom)?"caret":$(rf,(e=>xn(t,e)))?"valid-block":Sm(e,n,o)&&Sm(e,$t(r),n)?"valid":"invalid-child")))(e,t,"span",$t(t))){case"invalid-child":{d();const e=In(t);c(e),d();break}case"valid-block":d(),sf(t,n,s,o,r,!0);break;case"valid":{const e=l.get().getOrThunk((()=>{const e=Ma(i);return a.push(e),l.set(e),e}));Co(t,e);break}}};return of(e.dom,t,(e=>{d(),(e=>{const t=V(e,Cn);c(t)})(e)})),a},df=e=>{const t=(()=>{const e={};return{register:(t,n)=>{e[t]={name:t,settings:n}},lookup:t=>xe(e,t).map((e=>e.settings)),getNames:()=>fe(e)}})();((e,t)=>{const n=xa(),o=e=>I.from(e.attr(n)).bind(t.lookup),r=e=>{var t,n;e.attr(ka(),null),e.attr(xa(),null),e.attr(_a(),null);const o=I.from(e.attr(Na())).map((e=>e.split(","))).getOr([]),r=I.from(e.attr(Sa())).map((e=>e.split(","))).getOr([]);q(o,(t=>e.attr(t,null)));const s=null!==(n=null===(t=e.attr("class"))||void 0===t?void 0:t.split(" "))&&void 0!==n?n:[],a=re(s,[Ea()].concat(r));e.attr("class",a.length>0?a.join(" "):null),e.attr(Sa(),null),e.attr(Na(),null)};e.serializer.addTempAttr(_a()),e.serializer.addAttributeFilter(n,(e=>{for(const t of e)o(t).each((e=>{!1===e.persistent&&("span"===t.name?t.unwrap():r(t))}))}))})(e,t);const n=((e,t)=>{const n=Br({}),o=()=>({listeners:[],previous:Dr()}),r=(e,t)=>{s(e,(e=>(t(e),e)))},s=(e,t)=>{const r=n.get(),s=t(xe(r,e).getOrThunk(o));r[e]=s,n.set(r)},a=(t,n)=>{q(Oa(e,t),(e=>{n?Jt(e,_a(),"true"):rn(e,_a())}))},i=wa((()=>{const n=ae(t.getNames());q(n,(t=>{s(t,(n=>{const o=n.previous.get();return Aa(e,I.some(t)).fold((()=>{o.each((e=>{(e=>{r(e,(t=>{q(t.listeners,(t=>t(!1,e)))}))})(t),n.previous.clear(),a(e,!1)}))}),(({uid:e,name:t,elements:s})=>{Lt(o,e)||(o.each((e=>a(e,!1))),((e,t,n)=>{r(e,(o=>{q(o.listeners,(o=>o(!0,e,{uid:t,nodes:V(n,(e=>e.dom))})))}))})(t,e,s),n.previous.set(e),a(e,!0))})),{previous:n.previous,listeners:n.listeners}}))}))}),30);return e.on("remove",(()=>{i.cancel()})),e.on("NodeChange",(()=>{i.throttle()})),{addListener:(e,t)=>{s(e,(e=>({previous:e.previous,listeners:e.listeners.concat([t])})))}}})(e,t),o=Zt("span"),r=e=>{q(e,(e=>{o(e)?ko(e):(e=>{gn(e,Ea()),rn(e,`${ka()}`),rn(e,`${xa()}`),rn(e,`${_a()}`);const t=nn(e,`${Na()}`).map((e=>e.split(","))).getOr([]),n=nn(e,`${Sa()}`).map((e=>e.split(","))).getOr([]);var o;q(t,(t=>rn(e,t))),o=e,q(n,(e=>{gn(o,e)})),rn(e,`${Sa()}`),rn(e,`${Na()}`)})(e)}))};return{register:(e,n)=>{t.register(e,n)},annotate:(n,o)=>{t.lookup(n).each((t=>{((e,t,n,o)=>{e.undoManager.transact((()=>{const r=e.selection,s=r.getRng(),a=um(e).length>0,i=Da("mce-annotation");if(s.collapsed&&!a&&((e,t)=>{const n=nf(e.dom,t,[{inline:"span"}]);t.setStart(n.startContainer,n.startOffset),t.setEnd(n.endContainer,n.endOffset),e.selection.setRng(t)})(e,s),r.getRng().collapsed&&!a){const s=af(e.getDoc(),i,o,t,n.decorate);No(s,Wo),r.getRng().insertNode(s.dom),r.select(s.dom)}else ym(r,!1,(()=>{vm(e,(r=>{lf(e,r,i,t,n.decorate,o)}))}))}))})(e,n,t,o)}))},annotationChanged:(e,t)=>{n.addListener(e,t)},remove:t=>{Aa(e,I.some(t)).each((({elements:t})=>{const n=e.selection.getBookmark();r(t),e.selection.moveToBookmark(n)}))},removeAll:t=>{const n=e.selection.getBookmark();pe(Ba(e,t),((e,t)=>{r(e)})),e.selection.moveToBookmark(n)},getAll:t=>{const n=Ba(e,t);return he(n,(e=>V(e,(e=>e.dom))))}}},cf=e=>({getBookmark:T(nm,e),moveToBookmark:T(om,e)});cf.isBookmarkNode=rm;const uf=(e,t,n)=>!n.collapsed&&$(n.getClientRects(),(n=>((e,t,n)=>t>=e.left&&t<=e.right&&n>=e.top&&n<=e.bottom)(n,e,t))),mf=(e,t,n)=>{e.dispatch(t,n)},ff=(e,t,n,o)=>{e.dispatch("FormatApply",{format:t,node:n,vars:o})},gf=(e,t,n,o)=>{e.dispatch("FormatRemove",{format:t,node:n,vars:o})},pf=(e,t)=>e.dispatch("SetContent",t),hf=(e,t)=>e.dispatch("GetContent",t),bf=(e,t)=>{e.dispatch("AutocompleterUpdateActiveRange",t)},vf=(e,t)=>e.dispatch("PastePlainTextToggle",{state:t}),yf={BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,ESC:27,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,modifierPressed:e=>e.shiftKey||e.ctrlKey||e.altKey||yf.metaKeyPressed(e),metaKeyPressed:e=>Tt.os.isMacOS()||Tt.os.isiOS()?e.metaKey:e.ctrlKey&&!e.altKey},Cf="data-mce-selected",wf=Math.abs,Ef=Math.round,xf={nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]},kf=(e,t)=>{const n=t.dom,o=t.getDoc(),r=document,s=t.getBody();let a,i,l,d,c,u,m,f,g,p,h,b,v,y,w;const E=e=>C(e)&&(hr(e)||n.is(e,"figure.image")),x=e=>wr(e)||n.hasClass(e,"mce-preview-object"),k=e=>{const n=e.target;((e,t)=>{if((e=>"longpress"===e.type||0===e.type.indexOf("touch"))(e)){const n=e.touches[0];return E(e.target)&&!uf(n.clientX,n.clientY,t)}return E(e.target)&&!uf(e.clientX,e.clientY,t)})(e,t.selection.getRng())&&!e.isDefaultPrevented()&&t.selection.select(n)},_=e=>n.hasClass(e,"mce-preview-object")&&C(e.firstElementChild)?[e,e.firstElementChild]:n.is(e,"figure.image")?[e.querySelector("img")]:[e],S=e=>{const o=vd(t);return!!o&&"false"!==e.getAttribute("data-mce-resize")&&e!==t.getBody()&&(n.hasClass(e,"mce-preview-object")&&C(e.firstElementChild)?xn(Cn(e.firstElementChild),o):xn(Cn(e),o))},N=(e,o,r)=>{if(C(r)){const s=_(e);q(s,(e=>{e.style[o]||!t.schema.isValid(e.nodeName.toLowerCase(),o)?n.setStyle(e,o,r):n.setAttrib(e,o,""+r)}))}},R=(e,t,n)=>{N(e,"width",t),N(e,"height",n)},A=e=>{let o,r,c,C,k;o=e.screenX-u,r=e.screenY-m,b=o*d[2]+f,v=r*d[3]+g,b=b<5?5:b,v=v<5?5:v,c=(E(a)||x(a))&&!1!==yd(t)?!yf.modifierPressed(e):yf.modifierPressed(e),c&&(wf(o)>wf(r)?(v=Ef(b*p),b=Ef(v/p)):(b=Ef(v/p),v=Ef(b*p))),R(i,b,v),C=d.startPos.x+o,k=d.startPos.y+r,C=C>0?C:0,k=k>0?k:0,n.setStyles(l,{left:C,top:k,display:"block"}),l.innerHTML=b+" &times; "+v,d[2]<0&&i.clientWidth<=b&&n.setStyle(i,"left",void 0+(f-b)),d[3]<0&&i.clientHeight<=v&&n.setStyle(i,"top",void 0+(g-v)),o=s.scrollWidth-y,r=s.scrollHeight-w,o+r!==0&&n.setStyles(l,{left:C-o,top:k-r}),h||(((e,t,n,o,r)=>{e.dispatch("ObjectResizeStart",{target:t,width:n,height:o,origin:r})})(t,a,f,g,"corner-"+d.name),h=!0)},T=()=>{const e=h;h=!1,e&&(N(a,"width",b),N(a,"height",v)),n.unbind(o,"mousemove",A),n.unbind(o,"mouseup",T),r!==o&&(n.unbind(r,"mousemove",A),n.unbind(r,"mouseup",T)),n.remove(i),n.remove(l),n.remove(c),O(a),e&&(((e,t,n,o,r)=>{e.dispatch("ObjectResized",{target:t,width:n,height:o,origin:r})})(t,a,b,v,"corner-"+d.name),n.setAttrib(a,"style",n.getAttrib(a,"style"))),t.nodeChanged()},O=e=>{M();const h=n.getPos(e,s),C=h.x,E=h.y,k=e.getBoundingClientRect(),N=k.width||k.right-k.left,O=k.height||k.bottom-k.top;a!==e&&(P(),a=e,b=v=0);const B=t.dispatch("ObjectSelected",{target:e});S(e)&&!B.isDefaultPrevented()?pe(xf,((e,t)=>{let h=n.get("mceResizeHandle"+t);h&&n.remove(h),h=n.add(s,"div",{id:"mceResizeHandle"+t,"data-mce-bogus":"all",class:"mce-resizehandle",unselectable:!0,style:"cursor:"+t+"-resize; margin:0; padding:0"}),n.bind(h,"mousedown",(h=>{h.stopImmediatePropagation(),h.preventDefault(),(h=>{const b=_(a)[0];u=h.screenX,m=h.screenY,f=b.clientWidth,g=b.clientHeight,p=g/f,d=e,d.name=t,d.startPos={x:N*e[0]+C,y:O*e[1]+E},y=s.scrollWidth,w=s.scrollHeight,c=n.add(s,"div",{class:"mce-resize-backdrop","data-mce-bogus":"all"}),n.setStyles(c,{position:"fixed",left:"0",top:"0",width:"100%",height:"100%"}),i=((e,t)=>{if(x(t))return e.create("img",{src:Tt.transparentSrc});if(ar(t)){const n=$e(d.name,"n")?le:de,o=t.cloneNode(!0);return n(e.select("tr",o)).each((t=>{const n=e.select("td,th",t);e.setStyle(t,"height",null),q(n,(t=>e.setStyle(t,"height",null)))})),o}return t.cloneNode(!0)})(n,a),n.addClass(i,"mce-clonedresizable"),n.setAttrib(i,"data-mce-bogus","all"),i.contentEditable="false",n.setStyles(i,{left:C,top:E,margin:0}),R(i,N,O),i.removeAttribute(Cf),s.appendChild(i),n.bind(o,"mousemove",A),n.bind(o,"mouseup",T),r!==o&&(n.bind(r,"mousemove",A),n.bind(r,"mouseup",T)),l=n.add(s,"div",{class:"mce-resize-helper","data-mce-bogus":"all"},f+" &times; "+g)})(h)})),e.elm=h,n.setStyles(h,{left:N*e[0]+C-h.offsetWidth/2,top:O*e[1]+E-h.offsetHeight/2})})):P(!1)},B=Ca(O,0),P=(e=!0)=>{B.cancel(),M(),a&&e&&a.removeAttribute(Cf),pe(xf,((e,t)=>{const o=n.get("mceResizeHandle"+t);o&&(n.unbind(o),n.remove(o))}))},D=(e,t)=>n.isChildOf(e,t),L=o=>{if(h||t.removed||t.composing)return;const r="mousedown"===o.type?o.target:e.getNode(),a=oo(Cn(r),"table,img,figure.image,hr,video,span.mce-preview-object,details").map((e=>e.dom)).filter((e=>n.isEditable(e.parentElement)||"IMG"===e.nodeName&&n.isEditable(e))).getOrUndefined(),i=C(a)?n.getAttrib(a,Cf,"1"):"1";if(q(n.select(`img[${Cf}],hr[${Cf}]`),(e=>{e.removeAttribute(Cf)})),C(a)&&D(a,s)&&t.hasFocus()){I();const t=e.getStart(!0);if(D(t,a)&&D(e.getEnd(!0),a))return n.setAttrib(a,Cf,i),void B.throttle(a)}P()},M=()=>{pe(xf,(e=>{e.elm&&(n.unbind(e.elm),delete e.elm)}))},I=()=>{try{t.getDoc().execCommand("enableObjectResizing",!1,"false")}catch(e){}};return t.on("init",(()=>{I(),t.on("NodeChange ResizeEditor ResizeWindow ResizeContent drop",L),t.on("keyup compositionend",(e=>{a&&"TABLE"===a.nodeName&&L(e)})),t.on("hide blur",P),t.on("contextmenu longpress",k,!0)})),t.on("remove",M),{isResizable:S,showResizeRect:O,hideResizeRect:P,updateResizeRect:L,destroy:()=>{B.cancel(),a=i=c=null}}},_f=(e,t,n)=>{const o=e.document.createRange();var r;return r=o,t.fold((e=>{r.setStartBefore(e.dom)}),((e,t)=>{r.setStart(e.dom,t)}),(e=>{r.setStartAfter(e.dom)})),((e,t)=>{t.fold((t=>{e.setEndBefore(t.dom)}),((t,n)=>{e.setEnd(t.dom,n)}),(t=>{e.setEndAfter(t.dom)}))})(o,n),o},Sf=(e,t,n,o,r)=>{const s=e.document.createRange();return s.setStart(t.dom,n),s.setEnd(o.dom,r),s},Nf=xl([{ltr:["start","soffset","finish","foffset"]},{rtl:["start","soffset","finish","foffset"]}]),Rf=(e,t,n)=>t(Cn(n.startContainer),n.startOffset,Cn(n.endContainer),n.endOffset);Nf.ltr,Nf.rtl;const Af=(e,t,n,o)=>({start:e,soffset:t,finish:n,foffset:o}),Tf=document.caretPositionFromPoint?(e,t,n)=>{var o,r;return I.from(null===(r=(o=e.dom).caretPositionFromPoint)||void 0===r?void 0:r.call(o,t,n)).bind((t=>{if(null===t.offsetNode)return I.none();const n=e.dom.createRange();return n.setStart(t.offsetNode,t.offset),n.collapse(),I.some(n)}))}:document.caretRangeFromPoint?(e,t,n)=>{var o,r;return I.from(null===(r=(o=e.dom).caretRangeFromPoint)||void 0===r?void 0:r.call(o,t,n))}:I.none,Of=xl([{before:["element"]},{on:["element","offset"]},{after:["element"]}]),Bf={before:Of.before,on:Of.on,after:Of.after,cata:(e,t,n,o)=>e.fold(t,n,o),getStart:e=>e.fold(R,R,R)},Pf=xl([{domRange:["rng"]},{relative:["startSitu","finishSitu"]},{exact:["start","soffset","finish","foffset"]}]),Df={domRange:Pf.domRange,relative:Pf.relative,exact:Pf.exact,exactFromRange:e=>Pf.exact(e.start,e.soffset,e.finish,e.foffset),getWin:e=>{const t=(e=>e.match({domRange:e=>Cn(e.startContainer),relative:(e,t)=>Bf.getStart(e),exact:(e,t,n,o)=>e}))(e);return An(t)},range:Af},Lf=(e,t)=>{const n=$t(e);return"input"===n?Bf.after(e):H(["br","img"],n)?0===t?Bf.before(e):Bf.after(e):Bf.on(e,t)},Mf=(e,t)=>{const n=e.fold(Bf.before,Lf,Bf.after),o=t.fold(Bf.before,Lf,Bf.after);return Df.relative(n,o)},If=(e,t,n,o)=>{const r=Lf(e,t),s=Lf(n,o);return Df.relative(r,s)},Ff=(e,t)=>{const n=(t||document).createDocumentFragment();return q(e,(e=>{n.appendChild(e.dom)})),Cn(n)},Uf=e=>{const t=Df.getWin(e).dom,n=(e,n,o,r)=>Sf(t,e,n,o,r),o=(e=>e.match({domRange:e=>{const t=Cn(e.startContainer),n=Cn(e.endContainer);return If(t,e.startOffset,n,e.endOffset)},relative:Mf,exact:If}))(e);return((e,t)=>{const n=((e,t)=>t.match({domRange:e=>({ltr:N(e),rtl:I.none}),relative:(t,n)=>({ltr:Le((()=>_f(e,t,n))),rtl:Le((()=>I.some(_f(e,n,t))))}),exact:(t,n,o,r)=>({ltr:Le((()=>Sf(e,t,n,o,r))),rtl:Le((()=>I.some(Sf(e,o,r,t,n))))})}))(e,t);return((e,t)=>{const n=t.ltr();return n.collapsed?t.rtl().filter((e=>!1===e.collapsed)).map((e=>Nf.rtl(Cn(e.endContainer),e.endOffset,Cn(e.startContainer),e.startOffset))).getOrThunk((()=>Rf(0,Nf.ltr,n))):Rf(0,Nf.ltr,n)})(0,n)})(t,o).match({ltr:n,rtl:n})},zf=(e,t,n)=>((e,t,n)=>((e,t,n)=>{const o=Cn(e.document);return Tf(o,t,n).map((e=>Af(Cn(e.startContainer),e.startOffset,Cn(e.endContainer),e.endOffset)))})(e,t,n))(An(Cn(n)).dom,e,t).map((e=>{const t=n.createRange();return t.setStart(e.start.dom,e.soffset),t.setEnd(e.finish.dom,e.foffset),t})).getOrUndefined(),jf=(e,t)=>C(e)&&C(t)&&e.startContainer===t.startContainer&&e.startOffset===t.startOffset&&e.endContainer===t.endContainer&&e.endOffset===t.endOffset,Hf=(e,t,n)=>null!==((e,t,n)=>{let o=e;for(;o&&o!==t;){if(n(o))return o;o=o.parentNode}return null})(e,t,n),$f=(e,t,n)=>Hf(e,t,(e=>e.nodeName===n)),Vf=(e,t)=>si(e)&&!Hf(e,t,qu),qf=(e,t,n)=>{const o=t.parentNode;if(o){const r=new Vo(t,e.getParent(o,e.isBlock)||e.getRoot());let s;for(;s=r[n?"prev":"next"]();)if(pr(s))return!0}return!1},Wf=(e,t,n,o,r)=>{const s=e.getRoot(),a=e.schema.getNonEmptyElements(),i=r.parentNode;let l,d;if(!i)return I.none();const c=e.getParent(i,e.isBlock)||s;if(o&&pr(r)&&t&&e.isEmpty(c))return I.some(Qi(i,e.nodeIndex(r)));const u=new Vo(r,c);for(;d=u[o?"prev":"next"]();){if("false"===e.getContentEditableParent(d)||Vf(d,s))return I.none();if(dr(d)&&d.data.length>0)return $f(d,s,"A")?I.none():I.some(Qi(d,o?d.data.length:0));if(e.isBlock(d)||a[d.nodeName.toLowerCase()])return I.none();l=d}return mr(l)?I.none():n&&l?I.some(Qi(l,0)):I.none()},Kf=(e,t,n,o)=>{const r=e.getRoot();let s,a=!1,i=n?o.startContainer:o.endContainer,l=n?o.startOffset:o.endOffset;const d=er(i)&&l===i.childNodes.length,c=e.schema.getNonEmptyElements();let u=n;if(si(i))return I.none();if(er(i)&&l>i.childNodes.length-1&&(u=!1),fr(i)&&(i=r,l=0),i===r){if(u&&(s=i.childNodes[l>0?l-1:0],s)){if(si(s))return I.none();if(c[s.nodeName]||ar(s))return I.none()}if(i.hasChildNodes()){if(l=Math.min(!u&&l>0?l-1:l,i.childNodes.length-1),i=i.childNodes[l],l=dr(i)&&d?i.data.length:0,!t&&i===r.lastChild&&ar(i))return I.none();if(((e,t)=>{let n=t;for(;n&&n!==e;){if(vr(n))return!0;n=n.parentNode}return!1})(r,i)||si(i))return I.none();if(xr(i))return I.none();if(i.hasChildNodes()&&!ar(i)){s=i;const t=new Vo(i,r);do{if(vr(s)||si(s)){a=!1;break}if(dr(s)&&s.data.length>0){l=u?0:s.data.length,i=s,a=!0;break}if(c[s.nodeName.toLowerCase()]&&!Cr(s)){l=e.nodeIndex(s),i=s.parentNode,u||l++,a=!0;break}}while(s=u?t.next():t.prev())}}}return t&&(dr(i)&&0===l&&Wf(e,d,t,!0,i).each((e=>{i=e.container(),l=e.offset(),a=!0})),er(i)&&(s=i.childNodes[l],s||(s=i.childNodes[l-1]),!s||!pr(s)||((e,t)=>{var n;return"A"===(null===(n=e.previousSibling)||void 0===n?void 0:n.nodeName)})(s)||qf(e,s,!1)||qf(e,s,!0)||Wf(e,d,t,!0,s).each((e=>{i=e.container(),l=e.offset(),a=!0})))),u&&!t&&dr(i)&&l===i.data.length&&Wf(e,d,t,!1,i).each((e=>{i=e.container(),l=e.offset(),a=!0})),a&&i?I.some(Qi(i,l)):I.none()},Yf=(e,t)=>{const n=t.collapsed,o=t.cloneRange(),r=Qi.fromRangeStart(t);return Kf(e,n,!0,o).each((e=>{n&&Qi.isAbove(r,e)||o.setStart(e.container(),e.offset())})),n||Kf(e,n,!1,o).each((e=>{o.setEnd(e.container(),e.offset())})),n&&o.collapse(!0),jf(t,o)?I.none():I.some(o)},Gf=(e,t)=>e.splitText(t),Xf=e=>{let t=e.startContainer,n=e.startOffset,o=e.endContainer,r=e.endOffset;if(t===o&&dr(t)){if(n>0&&n<t.data.length)if(o=Gf(t,n),t=o.previousSibling,r>n){r-=n;const e=Gf(o,r).previousSibling;t=o=e,r=e.data.length,n=0}else r=0}else if(dr(t)&&n>0&&n<t.data.length&&(t=Gf(t,n),n=0),dr(o)&&r>0&&r<o.data.length){const e=Gf(o,r).previousSibling;o=e,r=e.data.length}return{startContainer:t,startOffset:n,endContainer:o,endOffset:r}},Zf=e=>({walk:(t,n)=>of(e,t,n),split:Xf,expand:(t,n={type:"word"})=>{if("word"===n.type){const n=nf(e,t,[{inline:"span"}]),o=e.createRng();return o.setStart(n.startContainer,n.startOffset),o.setEnd(n.endContainer,n.endOffset),o}return t},normalize:t=>Yf(e,t).fold(L,(e=>(t.setStart(e.startContainer,e.startOffset),t.setEnd(e.endContainer,e.endOffset),!0)))});Zf.compareRanges=jf,Zf.getCaretRangeFromPoint=zf,Zf.getSelectedNode=Ci,Zf.getNode=wi;const Qf=((e,t)=>{const n=t=>{const n=(e=>{const t=e.dom;return Xn(e)?t.getBoundingClientRect().height:t.offsetHeight})(t);if(n<=0||null===n){const n=uo(t,e);return parseFloat(n)||0}return n},o=(e,t)=>X(t,((t,n)=>{const o=uo(e,n),r=void 0===o?0:parseInt(o,10);return isNaN(r)?t:t+r}),0);return{set:(t,n)=>{if(!E(n)&&!n.match(/^[0-9]+$/))throw new Error(e+".set accepts only positive integer values. Value was "+n);const o=t.dom;ao(o)&&(o.style[e]=n+"px")},get:n,getOuter:n,aggregate:o,max:(e,t,n)=>{const r=o(e,n);return t>r?t-r:0}}})("height"),Jf=()=>Cn(document),eg=(e,t)=>e.view(t).fold(N([]),(t=>{const n=e.owner(t),o=eg(e,n);return[t].concat(o)}));var tg=Object.freeze({__proto__:null,view:e=>{var t;return(e.dom===document?I.none():I.from(null===(t=e.dom.defaultView)||void 0===t?void 0:t.frameElement)).map(Cn)},owner:e=>Rn(e)});const ng=e=>"textarea"===$t(e),og=(e,t)=>{const n=(e=>{const t=e.dom.ownerDocument,n=t.body,o=t.defaultView,r=t.documentElement;if(n===e.dom)return Oo(n.offsetLeft,n.offsetTop);const s=Bo(null==o?void 0:o.pageYOffset,r.scrollTop),a=Bo(null==o?void 0:o.pageXOffset,r.scrollLeft),i=Bo(r.clientTop,n.clientTop),l=Bo(r.clientLeft,n.clientLeft);return Po(e).translate(a-l,s-i)})(e),o=(e=>Qf.get(e))(e);return{element:e,bottom:n.top+o,height:o,pos:n,cleanup:t}},rg=(e,t,n,o)=>{lg(e,((r,s)=>ag(e,t,n,o)),n)},sg=(e,t,n,o,r)=>{const s={elm:o.element.dom,alignToTop:r};((e,t)=>e.dispatch("ScrollIntoView",t).isDefaultPrevented())(e,s)||(n(e,t,Do(t).top,o,r),((e,t)=>{e.dispatch("AfterScrollIntoView",t)})(e,s))},ag=(e,t,n,o)=>{const r=Cn(e.getBody()),s=Cn(e.getDoc());r.dom.offsetWidth;const a=((e,t)=>{const n=((e,t)=>{const n=In(e);if(0===n.length||ng(e))return{element:e,offset:t};if(t<n.length&&!ng(n[t]))return{element:n[t],offset:0};{const o=n[n.length-1];return ng(o)?{element:e,offset:t}:"img"===$t(o)?{element:o,offset:1}:Yt(o)?{element:o,offset:ja(o).length}:{element:o,offset:In(o).length}}})(e,t),o=bn('<span data-mce-bogus="all" style="display: inline-block;">\ufeff</span>');return ho(n.element,o),og(o,(()=>xo(o)))})(Cn(n.startContainer),n.startOffset);sg(e,s,t,a,o),a.cleanup()},ig=(e,t,n,o)=>{const r=Cn(e.getDoc());sg(e,r,n,(e=>og(Cn(e),k))(t),o)},lg=(e,t,n)=>{const o=n.startContainer,r=n.startOffset,s=n.endContainer,a=n.endOffset;t(Cn(o),Cn(s));const i=e.dom.createRng();i.setStart(o,r),i.setEnd(s,a),e.selection.setRng(n)},dg=(e,t,n,o,r)=>{const s=t.pos;if(o)Lo(s.left,s.top,r);else{const o=s.top-n+t.height;Lo(-e.getBody().getBoundingClientRect().left,o,r)}},cg=(e,t,n,o,r,s)=>{const a=o+n,i=r.pos.top,l=r.bottom,d=l-i>=o;i<n?dg(e,r,o,!1!==s,t):i>a?dg(e,r,o,d?!1!==s:!0===s,t):l>a&&!d&&dg(e,r,o,!0===s,t)},ug=(e,t,n,o,r)=>{const s=An(t).dom.innerHeight;cg(e,t,n,s,o,r)},mg=(e,t,n,o,r)=>{const s=An(t).dom.innerHeight;cg(e,t,n,s,o,r);const a=(e=>{const t=Jf(),n=Do(t),o=((e,t)=>{const n=t.owner(e);return eg(t,n)})(e,tg),r=Po(e),s=G(o,((e,t)=>{const n=Po(t);return{left:e.left+n.left,top:e.top+n.top}}),{left:0,top:0});return Oo(s.left+r.left+n.left,s.top+r.top+n.top)})(o.element),i=Fo(window);a.top<i.y?Mo(o.element,!1!==r):a.top>i.bottom&&Mo(o.element,!0===r)},fg=(e,t,n)=>rg(e,ug,t,n),gg=(e,t,n)=>ig(e,t,ug,n),pg=(e,t,n)=>rg(e,mg,t,n),hg=(e,t,n)=>ig(e,t,mg,n),bg=(e,t,n)=>{(e.inline?fg:pg)(e,t,n)},vg=(e,t=!1)=>e.dom.focus({preventScroll:t}),yg=e=>{const t=qn(e).dom;return e.dom===t.activeElement},Cg=(e=Jf())=>I.from(e.dom.activeElement).map(Cn),wg=(e,t)=>{const n=Yt(t)?ja(t).length:In(t).length+1;return e>n?n:e<0?0:e},Eg=e=>Df.range(e.start,wg(e.soffset,e.start),e.finish,wg(e.foffset,e.finish)),xg=(e,t)=>!Jo(t.dom)&&(Sn(e,t)||_n(e,t)),kg=e=>t=>xg(e,t.start)&&xg(e,t.finish),_g=e=>Df.range(Cn(e.startContainer),e.startOffset,Cn(e.endContainer),e.endOffset),Sg=e=>{const t=document.createRange();try{return t.setStart(e.start.dom,e.soffset),t.setEnd(e.finish.dom,e.foffset),I.some(t)}catch(e){return I.none()}},Ng=e=>{const t=(e=>e.inline||Tt.browser.isFirefox())(e)?(n=Cn(e.getBody()),(e=>{const t=e.getSelection();return(t&&0!==t.rangeCount?I.from(t.getRangeAt(0)):I.none()).map(_g)})(An(n).dom).filter(kg(n))):I.none();var n;e.bookmark=t.isSome()?t:e.bookmark},Rg=e=>(e.bookmark?e.bookmark:I.none()).bind((t=>{return n=Cn(e.getBody()),o=t,I.from(o).filter(kg(n)).map(Eg);var n,o})).bind(Sg),Ag={isEditorUIElement:e=>{const t=e.className.toString();return-1!==t.indexOf("tox-")||-1!==t.indexOf("mce-")}},Tg={setEditorTimeout:(e,t,n)=>((e,t)=>(E(t)||(t=0),setTimeout(e,t)))((()=>{e.removed||t()}),n),setEditorInterval:(e,t,n)=>{const o=((e,t)=>(E(t)||(t=0),setInterval(e,t)))((()=>{e.removed?clearInterval(o):t()}),n);return o}};let Og;const Bg=ma.DOM,Pg=e=>{const t=e.classList;return void 0!==t&&(t.contains("tox-edit-area")||t.contains("tox-edit-area__iframe")||t.contains("mce-content-body"))},Dg=(e,t)=>{const n=Bd(e),o=Bg.getParent(t,(t=>(e=>er(e)&&Ag.isEditorUIElement(e))(t)||!!n&&e.dom.is(t,n)));return null!==o},Lg=e=>{try{const t=qn(Cn(e.getElement()));return Cg(t).fold((()=>document.body),(e=>e.dom))}catch(e){return document.body}},Mg=(e,t)=>{const n=t.editor;(e=>{const t=Ca((()=>{Ng(e)}),0);e.on("init",(()=>{e.inline&&((e,t)=>{const n=()=>{t.throttle()};ma.DOM.bind(document,"mouseup",n),e.on("remove",(()=>{ma.DOM.unbind(document,"mouseup",n)}))})(e,t),((e,t)=>{((e,t)=>{e.on("mouseup touchend",(e=>{t.throttle()}))})(e,t),e.on("keyup NodeChange AfterSetSelectionRange",(t=>{(e=>"nodechange"===e.type&&e.selectionChange)(t)||Ng(e)}))})(e,t)})),e.on("remove",(()=>{t.cancel()}))})(n);const o=(e,t)=>{Cc(e)&&!0!==e.inline&&t(Cn(e.getContainer()),"tox-edit-focus")};n.on("focusin",(()=>{const t=e.focusedEditor;Pg(Lg(n))&&o(n,mn),t!==n&&(t&&t.dispatch("blur",{focusedEditor:n}),e.setActive(n),e.focusedEditor=n,n.dispatch("focus",{blurredEditor:t}),n.focus(!0))})),n.on("focusout",(()=>{Tg.setEditorTimeout(n,(()=>{const t=e.focusedEditor;Pg(Lg(n))&&t===n||o(n,gn),Dg(n,Lg(n))||t!==n||(n.dispatch("blur",{focusedEditor:null}),e.focusedEditor=null)}))})),Og||(Og=t=>{const n=e.activeEditor;n&&Yn(t).each((t=>{const o=t;o.ownerDocument===document&&(o===document.body||Dg(n,o)||e.focusedEditor!==n||(n.dispatch("blur",{focusedEditor:null}),e.focusedEditor=null))}))},Bg.bind(document,"focusin",Og))},Ig=(e,t)=>{e.focusedEditor===t.editor&&(e.focusedEditor=null),!e.activeEditor&&Og&&(Bg.unbind(document,"focusin",Og),Og=null)},Fg=(e,t)=>{((e,t)=>(e=>e.collapsed?I.from(wi(e.startContainer,e.startOffset)).map(Cn):I.none())(t).bind((t=>Ka(t)?I.some(t):Sn(e,t)?I.none():I.some(e))))(Cn(e.getBody()),t).bind((e=>Hu(e.dom))).fold((()=>{e.selection.normalize()}),(t=>e.selection.setRng(t.toRange())))},Ug=e=>{if(e.setActive)try{e.setActive()}catch(t){e.focus()}else e.focus()},zg=e=>e.inline?(e=>{const t=e.getBody();return t&&(n=Cn(t),yg(n)||(o=n,Cg(qn(o)).filter((e=>o.dom.contains(e.dom)))).isSome());var n,o})(e):(e=>C(e.iframeElement)&&yg(Cn(e.iframeElement)))(e),jg=e=>zg(e)||(e=>{const t=qn(Cn(e.getElement()));return Cg(t).filter((t=>!Pg(t.dom)&&Dg(e,t.dom))).isSome()})(e),Hg=e=>e.editorManager.setActive(e),$g=(e,t)=>t.collapsed?e.isEditable(t.startContainer):e.isEditable(t.startContainer)&&e.isEditable(t.endContainer),Vg=(e,t,n,o,r)=>{const s=n?t.startContainer:t.endContainer,a=n?t.startOffset:t.endOffset;return I.from(s).map(Cn).map((e=>o&&t.collapsed?e:Fn(e,r(e,a)).getOr(e))).bind((e=>Kt(e)?I.some(e):Tn(e).filter(Kt))).map((e=>e.dom)).getOr(e)},qg=(e,t,n=!1)=>Vg(e,t,!0,n,((e,t)=>Math.min(jn(e),t))),Wg=(e,t,n=!1)=>Vg(e,t,!1,n,((e,t)=>t>0?t-1:t)),Kg=(e,t)=>{const n=e;for(;e&&dr(e)&&0===e.length;)e=t?e.nextSibling:e.previousSibling;return e||n},Yg=(e,t)=>V(t,(t=>{const n=e.dispatch("GetSelectionRange",{range:t});return n.range!==t?n.range:t})),Gg={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11},Xg=(e,t,n)=>{const o=n?"lastChild":"firstChild",r=n?"prev":"next";if(e[o])return e[o];if(e!==t){let n=e[r];if(n)return n;for(let o=e.parent;o&&o!==t;o=o.parent)if(n=o[r],n)return n}},Zg=e=>{var t;const n=null!==(t=e.value)&&void 0!==t?t:"";if(!Go(n))return!1;const o=e.parent;return!o||"span"===o.name&&!o.attr("style")||!/^[ ]+$/.test(n)},Qg=e=>{const t="a"===e.name&&!e.attr("href")&&e.attr("id");return e.attr("name")||e.attr("id")&&!e.firstChild||e.attr("data-mce-bookmark")||t};class Jg{static create(e,t){const n=new Jg(e,Gg[e]||1);return t&&pe(t,((e,t)=>{n.attr(t,e)})),n}constructor(e,t){this.name=e,this.type=t,1===t&&(this.attributes=[],this.attributes.map={})}replace(e){const t=this;return e.parent&&e.remove(),t.insert(e,t),t.remove(),t}attr(e,t){const n=this;if(!m(e))return C(e)&&pe(e,((e,t)=>{n.attr(t,e)})),n;const o=n.attributes;if(o){if(void 0!==t){if(null===t){if(e in o.map){delete o.map[e];let t=o.length;for(;t--;)if(o[t].name===e)return o.splice(t,1),n}return n}if(e in o.map){let n=o.length;for(;n--;)if(o[n].name===e){o[n].value=t;break}}else o.push({name:e,value:t});return o.map[e]=t,n}return o.map[e]}}clone(){const e=this,t=new Jg(e.name,e.type),n=e.attributes;if(n){const e=[];e.map={};for(let t=0,o=n.length;t<o;t++){const o=n[t];"id"!==o.name&&(e[e.length]={name:o.name,value:o.value},e.map[o.name]=o.value)}t.attributes=e}return t.value=e.value,t}wrap(e){const t=this;return t.parent&&(t.parent.insert(e,t),e.append(t)),t}unwrap(){const e=this;for(let t=e.firstChild;t;){const n=t.next;e.insert(t,e,!0),t=n}e.remove()}remove(){const e=this,t=e.parent,n=e.next,o=e.prev;return t&&(t.firstChild===e?(t.firstChild=n,n&&(n.prev=null)):o&&(o.next=n),t.lastChild===e?(t.lastChild=o,o&&(o.next=null)):n&&(n.prev=o),e.parent=e.next=e.prev=null),e}append(e){const t=this;e.parent&&e.remove();const n=t.lastChild;return n?(n.next=e,e.prev=n,t.lastChild=e):t.lastChild=t.firstChild=e,e.parent=t,e}insert(e,t,n){e.parent&&e.remove();const o=t.parent||this;return n?(t===o.firstChild?o.firstChild=e:t.prev&&(t.prev.next=e),e.prev=t.prev,e.next=t,t.prev=e):(t===o.lastChild?o.lastChild=e:t.next&&(t.next.prev=e),e.next=t.next,e.prev=t,t.next=e),e.parent=o,e}getAll(e){const t=this,n=[];for(let o=t.firstChild;o;o=Xg(o,t))o.name===e&&n.push(o);return n}children(){const e=[];for(let t=this.firstChild;t;t=t.next)e.push(t);return e}empty(){const e=this;if(e.firstChild){const t=[];for(let n=e.firstChild;n;n=Xg(n,e))t.push(n);let n=t.length;for(;n--;){const e=t[n];e.parent=e.firstChild=e.lastChild=e.next=e.prev=null}}return e.firstChild=e.lastChild=null,e}isEmpty(e,t={},n){var o;const r=this;let s=r.firstChild;if(Qg(r))return!1;if(s)do{if(1===s.type){if(s.attr("data-mce-bogus"))continue;if(e[s.name])return!1;if(Qg(s))return!1}if(8===s.type)return!1;if(3===s.type&&!Zg(s))return!1;if(3===s.type&&s.parent&&t[s.parent.name]&&Go(null!==(o=s.value)&&void 0!==o?o:""))return!1;if(n&&n(s))return!1}while(s=Xg(s,r));return!0}walk(e){return Xg(this,null,e)}}const ep=Dt.makeMap("NOSCRIPT STYLE SCRIPT XMP IFRAME NOEMBED NOFRAMES PLAINTEXT"," "),tp=e=>m(e.nodeValue)&&e.nodeValue.includes(Qa),np=e=>(0===e.length?"":`${V(e,(e=>`[${e}]`)).join(",")},`)+'[data-mce-bogus="all"]',op=e=>document.createTreeWalker(e,NodeFilter.SHOW_COMMENT,(e=>tp(e)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP)),rp=e=>document.createTreeWalker(e,NodeFilter.SHOW_TEXT,(e=>{if(tp(e)){const t=e.parentNode;return t&&ke(ep,t.nodeName)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}return NodeFilter.FILTER_SKIP})),sp=e=>null!==op(e).nextNode(),ap=e=>null!==rp(e).nextNode(),ip=(e,t)=>null!==t.querySelector(np(e)),lp=(e,t)=>{q(((e,t)=>t.querySelectorAll(np(e)))(e,t),(t=>{const n=Cn(t);"all"===tn(n,"data-mce-bogus")?xo(n):q(e,(e=>{on(n,e)&&rn(n,e)}))}))},dp=e=>{let t=e.nextNode();for(;null!==t;)t.nodeValue=null,t=e.nextNode()},cp=_(dp,op),up=_(dp,rp),mp=(e,t)=>{const n=[{condition:T(ip,t),action:T(lp,t)},{condition:sp,action:cp},{condition:ap,action:up}];let o=e,r=!1;return q(n,(({condition:t,action:n})=>{t(o)&&(r||(o=e.cloneNode(!0),r=!0),n(o))})),o},fp=e=>{const t=zo(e,"[data-mce-bogus]");q(t,(e=>{"all"===tn(e,"data-mce-bogus")?xo(e):$a(e)?(ho(e,yn(qo)),xo(e)):ko(e)}))},gp=e=>{const t=zo(e,"input");q(t,(e=>{rn(e,"name")}))},pp=(e,t,n)=>{let o;return o="raw"===t.format?Dt.trim(ei(mp(n,e.serializer.getTempAttrs()).innerHTML)):"text"===t.format?((e,t)=>{const n=e.getDoc(),o=qn(Cn(e.getBody())),r=vn("div",n);Jt(r,"data-mce-bogus","all"),co(r,{position:"fixed",left:"-9999999px",top:"0"}),No(r,t.innerHTML),fp(r),gp(r);const s=(e=>Hn(e)?e:Cn(Rn(e).dom.body))(o);yo(s,r);const a=ei(r.dom.innerText);return xo(r),a})(e,n):"tree"===t.format?e.serializer.serialize(n,t):((e,t)=>{const n=ql(e),o=new RegExp(`^(<${n}[^>]*>(&nbsp;|&#160;|\\s|\xa0|<br \\/>|)<\\/${n}>[\r\n]*|<br \\/>[\r\n]*)$`);return t.replace(o,"")})(e,e.serializer.serialize(n,t)),"text"!==t.format&&!Ga(Cn(n))&&m(o)?Dt.trim(o):o},hp=Dt.makeMap,bp=e=>{const t=[],n=(e=e||{}).indent,o=hp(e.indent_before||""),r=hp(e.indent_after||""),s=ws.getEncodeFunc(e.entity_encoding||"raw",e.entities),a="xhtml"!==e.element_format;return{start:(e,i,l)=>{if(n&&o[e]&&t.length>0){const e=t[t.length-1];e.length>0&&"\n"!==e&&t.push("\n")}if(t.push("<",e),i)for(let e=0,n=i.length;e<n;e++){const n=i[e];t.push(" ",n.name,'="',s(n.value,!0),'"')}if(t[t.length]=!l||a?">":" />",l&&n&&r[e]&&t.length>0){const e=t[t.length-1];e.length>0&&"\n"!==e&&t.push("\n")}},end:e=>{let o;t.push("</",e,">"),n&&r[e]&&t.length>0&&(o=t[t.length-1],o.length>0&&"\n"!==o&&t.push("\n"))},text:(e,n)=>{e.length>0&&(t[t.length]=n?e:s(e))},cdata:e=>{t.push("<![CDATA[",e,"]]>")},comment:e=>{t.push("\x3c!--",e,"--\x3e")},pi:(e,o)=>{o?t.push("<?",e," ",s(o),"?>"):t.push("<?",e,"?>"),n&&t.push("\n")},doctype:e=>{t.push("<!DOCTYPE",e,">",n?"\n":"")},reset:()=>{t.length=0},getContent:()=>t.join("").replace(/\n$/,"")}},vp=(e={},t=Fs())=>{const n=bp(e);return e.validate=!("validate"in e)||e.validate,{serialize:o=>{const r=e.validate,s={3:e=>{var t;n.text(null!==(t=e.value)&&void 0!==t?t:"",e.raw)},8:e=>{var t;n.comment(null!==(t=e.value)&&void 0!==t?t:"")},7:e=>{n.pi(e.name,e.value)},10:e=>{var t;n.doctype(null!==(t=e.value)&&void 0!==t?t:"")},4:e=>{var t;n.cdata(null!==(t=e.value)&&void 0!==t?t:"")},11:e=>{let t=e;if(t=t.firstChild)do{a(t)}while(t=t.next)}};n.reset();const a=e=>{var o;const i=s[e.type];if(i)i(e);else{const s=e.name,i=s in t.getVoidElements();let l=e.attributes;if(r&&l&&l.length>1){const n=[];n.map={};const o=t.getElementRule(e.name);if(o){for(let e=0,t=o.attributesOrder.length;e<t;e++){const t=o.attributesOrder[e];if(t in l.map){const e=l.map[t];n.map[t]=e,n.push({name:t,value:e})}}for(let e=0,t=l.length;e<t;e++){const t=l[e].name;if(!(t in n.map)){const e=l.map[t];n.map[t]=e,n.push({name:t,value:e})}}l=n}}if(n.start(s,l,i),Mr(s))m(e.value)&&n.text(e.value,!0),n.end(s);else if(!i){let t=e.firstChild;if(t){"pre"!==s&&"textarea"!==s||3!==t.type||"\n"!==(null===(o=t.value)||void 0===o?void 0:o[0])||n.text("\n",!0);do{a(t)}while(t=t.next)}n.end(s)}}};return 1!==o.type||e.inner?3===o.type?s[3](o):s[11](o):a(o),n.getContent()}}},yp=new Set;q(["margin","margin-left","margin-right","margin-top","margin-bottom","padding","padding-left","padding-right","padding-top","padding-bottom","border","border-width","border-style","border-color","background","background-attachment","background-clip","background-image","background-origin","background-position","background-repeat","background-size","float","position","left","right","top","bottom","z-index","display","transform","width","max-width","min-width","height","max-height","min-height","overflow","overflow-x","overflow-y","text-overflow","vertical-align","transition","transition-delay","transition-duration","transition-property","transition-timing-function"],(e=>{yp.add(e)}));const Cp=new Set;q(["background-color"],(e=>{Cp.add(e)}));const wp=["font","text-decoration","text-emphasis"],Ep=(e,t)=>fe(((e,t)=>e.parseStyle(e.getAttrib(t,"style")))(e,t)),xp=(e,t)=>$(Ep(e,t),(e=>(e=>yp.has(e))(e))),kp=(e,t,n)=>I.from(n.container()).filter(dr).exists((o=>{const r=e?0:-1;return t(o.data.charAt(n.offset()+r))})),_p=T(kp,!0,im),Sp=T(kp,!1,im),Np=e=>{const t=e.container();return dr(t)&&(0===t.data.length||Ja(t.data)&&cf.isBookmarkNode(t.parentNode))},Rp=(e,t)=>n=>du(e?0:-1,n).filter(t).isSome(),Ap=e=>hr(e)&&"block"===uo(Cn(e),"display"),Tp=e=>vr(e)&&!(e=>er(e)&&"all"===e.getAttribute("data-mce-bogus"))(e),Op=Rp(!0,Ap),Bp=Rp(!1,Ap),Pp=Rp(!0,wr),Dp=Rp(!1,wr),Lp=Rp(!0,ar),Mp=Rp(!1,ar),Ip=Rp(!0,Tp),Fp=Rp(!1,Tp),Up=(e,t)=>((e,t,n)=>Sn(t,e)?Bn(e,(e=>n(e)||_n(e,t))).slice(0,-1):[])(e,t,L),zp=(e,t)=>[e].concat(Up(e,t)),jp=(e,t,n)=>Fu(e,t,n,Np),Hp=(e,t,n)=>Q(zp(Cn(t.container()),e),(e=>t=>e.isBlock($t(t)))(n)),$p=(e,t,n,o)=>jp(e,t.dom,n).forall((e=>Hp(t,n,o).fold((()=>!lu(e,n,t.dom)),(o=>!lu(e,n,t.dom)&&Sn(o,Cn(e.container())))))),Vp=(e,t,n,o)=>Hp(t,n,o).fold((()=>jp(e,t.dom,n).forall((e=>!lu(e,n,t.dom)))),(t=>jp(e,t.dom,n).isNone())),qp=T(Vp,!1),Wp=T(Vp,!0),Kp=T($p,!1),Yp=T($p,!0),Gp=e=>vu(e).exists($a),Xp=(e,t,n,o)=>{const r=Y(zp(Cn(n.container()),t),(e=>o.isBlock($t(e)))),s=le(r).getOr(t);return Mu(e,s.dom,n).filter(Gp)},Zp=(e,t,n)=>vu(t).exists($a)||Xp(!0,e,t,n).isSome(),Qp=(e,t,n)=>(e=>I.from(e.getNode(!0)).map(Cn))(t).exists($a)||Xp(!1,e,t,n).isSome(),Jp=T(Xp,!1),eh=T(Xp,!0),th=e=>Qi.isTextPosition(e)&&!e.isAtStart()&&!e.isAtEnd(),nh=(e,t,n)=>{const o=Y(zp(Cn(t.container()),e),(e=>n.isBlock($t(e))));return le(o).getOr(e)},oh=(e,t,n)=>th(t)?Sp(t):Sp(t)||ju(nh(e,t,n).dom,t).exists(Sp),rh=(e,t,n)=>th(t)?_p(t):_p(t)||zu(nh(e,t,n).dom,t).exists(_p),sh=e=>vu(e).bind((e=>Jn(e,Kt))).exists((e=>(e=>H(["pre","pre-wrap"],e))(uo(e,"white-space")))),ah=(e,t)=>n=>{return o=new Vo(n,e)[t](),C(o)&&vr(o)&&Zc(o);var o},ih=(e,t,n)=>!sh(t)&&(((e,t,n)=>((e,t)=>ju(e.dom,t).isNone())(e,t)||((e,t)=>zu(e.dom,t).isNone())(e,t)||qp(e,t,n)||Wp(e,t,n)||Qp(e,t,n)||Zp(e,t,n))(e,t,n)||oh(e,t,n)||rh(e,t,n)),lh=(e,t,n)=>!sh(t)&&(qp(e,t,n)||Kp(e,t,n)||Qp(e,t,n)||oh(e,t,n)||((e,t)=>{const n=ju(e.dom,t).getOr(t),o=ah(e.dom,"prev");return t.isAtStart()&&(o(t.container())||o(n.container()))})(e,t)),dh=(e,t,n)=>!sh(t)&&(Wp(e,t,n)||Yp(e,t,n)||Zp(e,t,n)||rh(e,t,n)||((e,t)=>{const n=zu(e.dom,t).getOr(t),o=ah(e.dom,"next");return t.isAtEnd()&&(o(t.container())||o(n.container()))})(e,t)),ch=(e,t,n)=>lh(e,t,n)||dh(e,(e=>{const t=e.container(),n=e.offset();return dr(t)&&n<t.data.length?Qi(t,n+1):e})(t),n),uh=(e,t)=>sm(e.charAt(t)),mh=(e,t)=>im(e.charAt(t)),fh=(e,t,n,o)=>{const r=t.data,s=Qi(t,0);return n||!uh(r,0)||ch(e,s,o)?!!(n&&mh(r,0)&&lh(e,s,o))&&(t.data=Wo+r.slice(1),!0):(t.data=" "+r.slice(1),!0)},gh=(e,t,n,o)=>{const r=t.data,s=Qi(t,r.length-1);return n||!uh(r,r.length-1)||ch(e,s,o)?!!(n&&mh(r,r.length-1)&&dh(e,s,o))&&(t.data=r.slice(0,-1)+Wo,!0):(t.data=r.slice(0,-1)+" ",!0)},ph=(e,t,n)=>{const o=t.container();if(!dr(o))return I.none();if((e=>{const t=e.container();return dr(t)&&He(t.data,Wo)})(t)){const r=fh(e,o,!1,n)||(e=>{const t=e.data,n=(e=>{const t=e.split("");return V(t,((e,n)=>sm(e)&&n>0&&n<t.length-1&&lm(t[n-1])&&lm(t[n+1])?" ":e)).join("")})(t);return n!==t&&(e.data=n,!0)})(o)||gh(e,o,!1,n);return Ft(r,t)}if(ch(e,t,n)){const r=fh(e,o,!0,n)||gh(e,o,!0,n);return Ft(r,t)}return I.none()},hh=(e,t,n,o)=>{if(0===n)return;const r=Cn(e),s=Qn(r,(e=>o.isBlock($t(e)))).getOr(r),a=e.data.slice(t,t+n),i=t+n>=e.data.length&&dh(s,Qi(e,e.data.length),o),l=0===t&&lh(s,Qi(e,0),o);e.replaceData(t,n,Zo(a,4,l,i))},bh=(e,t,n)=>{const o=e.data.slice(t),r=o.length-Ke(o).length;hh(e,t,r,n)},vh=(e,t,n)=>{const o=e.data.slice(0,t),r=o.length-Ye(o).length;hh(e,t-r,r,n)},yh=(e,t,n,o,r=!0)=>{const s=Ye(e.data).length,a=r?e:t,i=r?t:e;return r?a.appendData(i.data):a.insertData(0,i.data),xo(Cn(i)),o&&bh(a,s,n),a},Ch=(e,t)=>((e,t)=>{const n=e.container(),o=e.offset();return!Qi.isTextPosition(e)&&n===t.parentNode&&o>Qi.before(t).offset()})(t,e)?Qi(t.container(),t.offset()-1):t,wh=e=>{return Bi(e.previousSibling)?I.some((t=e.previousSibling,dr(t)?Qi(t,t.data.length):Qi.after(t))):e.previousSibling?$u(e.previousSibling):I.none();var t},Eh=e=>{return Bi(e.nextSibling)?I.some((t=e.nextSibling,dr(t)?Qi(t,0):Qi.before(t))):e.nextSibling?Hu(e.nextSibling):I.none();var t},xh=(e,t,n)=>((e,t,n)=>e?((e,t)=>Eh(t).orThunk((()=>wh(t))).orThunk((()=>((e,t)=>zu(e,Qi.after(t)).orThunk((()=>ju(e,Qi.before(t)))))(e,t))))(t,n):((e,t)=>wh(t).orThunk((()=>Eh(t))).orThunk((()=>((e,t)=>I.from(t.previousSibling?t.previousSibling:t.parentNode).bind((t=>ju(e,Qi.before(t)))).orThunk((()=>zu(e,Qi.after(t)))))(e,t))))(t,n))(e,t,n).map(T(Ch,n)),kh=(e,t,n)=>{n.fold((()=>{e.focus()}),(n=>{e.selection.setRng(n.toRange(),t)}))},_h=(e,t)=>t&&ke(e.schema.getBlockElements(),$t(t)),Sh=(e,t,n,o=!0,r=!1)=>{const s=xh(t,e.getBody(),n.dom),a=Qn(n,T(_h,e),(i=e.getBody(),e=>e.dom===i));var i;const l=((e,t,n,o)=>{const r=Pn(e).filter(Yt),s=Dn(e).filter(Yt);return xo(e),(a=r,i=s,l=t,d=(e,t,r)=>{const s=e.dom,a=t.dom,i=s.data.length;return yh(s,a,n,o),r.container()===a?Qi(s,i):r},a.isSome()&&i.isSome()&&l.isSome()?I.some(d(a.getOrDie(),i.getOrDie(),l.getOrDie())):I.none()).orThunk((()=>(o&&(r.each((e=>vh(e.dom,e.dom.length,n))),s.each((e=>bh(e.dom,0,n)))),t)));var a,i,l,d})(n,s,e.schema,((e,t)=>ke(e.schema.getTextInlineElements(),$t(t)))(e,n));e.dom.isEmpty(e.getBody())?(e.setContent(""),e.selection.setCursorLocation()):a.bind((t=>((e,t,n)=>{if(Tr(e,t)){const e=bn('<br data-mce-bogus="1">');return n?q(In(t),(e=>{jm(e)||xo(e)})):Eo(t),yo(t,e),I.some(Qi.before(e.dom))}return I.none()})(e.schema,t,r))).fold((()=>{o&&kh(e,t,l)}),(n=>{o&&kh(e,t,I.some(n))}))},Nh=/[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/,Rh=(e,t)=>xn(Cn(t),bd(e))&&!Zr(e.schema,t)&&e.dom.isEditable(t),Ah=e=>{var t;return"rtl"===ma.DOM.getStyle(e,"direction",!0)||(e=>Nh.test(e))(null!==(t=e.textContent)&&void 0!==t?t:"")},Th=(e,t,n)=>{const o=((e,t,n)=>Y(ma.DOM.getParents(n.container(),"*",t),e))(e,t,n);return I.from(o[o.length-1])},Oh=(e,t)=>{const n=t.container(),o=t.offset();return e?ri(n)?dr(n.nextSibling)?Qi(n.nextSibling,0):Qi.after(n):ii(t)?Qi(n,o+1):t:ri(n)?dr(n.previousSibling)?Qi(n.previousSibling,n.previousSibling.data.length):Qi.before(n):li(t)?Qi(n,o-1):t},Bh=T(Oh,!0),Ph=T(Oh,!1),Dh=(e,t)=>{const n=e=>e.stopImmediatePropagation();e.on("beforeinput input",n,!0),e.getDoc().execCommand(t),e.off("beforeinput input",n)},Lh=e=>Dh(e,"Delete"),Mh=e=>Dh(e,"ForwardDelete"),Ih=e=>Va(e)||Wa(e),Fh=(e,t)=>Sn(e,t)?Jn(t,Ih,(e=>t=>Lt(Tn(t),e,_n))(e)):I.none(),Uh=(e,t=!0)=>{e.dom.isEmpty(e.getBody())&&e.setContent("",{no_selection:!t})},zh=(e,t,n)=>It(Hu(n),$u(n),((o,r)=>{const s=Oh(!0,o),a=Oh(!1,r),i=Oh(!1,t);return e?zu(n,i).exists((e=>e.isEqual(a)&&t.isEqual(s))):ju(n,i).exists((e=>e.isEqual(s)&&t.isEqual(a)))})).getOr(!0),jh=e=>{var t;return(8===Vt(t=e)||"#comment"===$t(t)?Pn(e):zn(e)).bind(jh).orThunk((()=>I.some(e)))},Hh=(e,t,n,o=!0)=>{var r;t.deleteContents();const s=jh(n).getOr(n),a=Cn(null!==(r=e.dom.getParent(s.dom,e.dom.isBlock))&&void 0!==r?r:n.dom);if(a.dom===e.getBody()?Uh(e,o):Tr(e.schema,a,{checkRootAsContent:!1})&&(Za(a),o&&e.selection.setCursorLocation(a.dom,0)),!_n(n,a)){const t=Lt(Tn(a),n)?[]:Tn(i=a).map(In).map((e=>Y(e,(e=>!_n(i,e))))).getOr([]);q(t.concat(In(n)),(t=>{_n(t,a)||Sn(t,a)||!Tr(e.schema,t)||xo(t)}))}var i},$h=e=>zo(e,"td,th"),Vh=(e,t)=>mm(Cn(e),t),qh=(e,t)=>({start:e,end:t}),Wh=xl([{singleCellTable:["rng","cell"]},{fullTable:["table"]},{partialTable:["cells","outsideDetails"]},{multiTable:["startTableCells","endTableCells","betweenRng"]}]),Kh=(e,t)=>oo(Cn(e),"td,th",t),Yh=e=>!_n(e.start,e.end),Gh=(e,t)=>mm(e.start,t).bind((n=>mm(e.end,t).bind((e=>Ft(_n(n,e),n))))),Xh=e=>t=>Gh(t,e).map((e=>((e,t,n)=>({rng:e,table:t,cells:n}))(t,e,$h(e)))),Zh=(e,t,n,o)=>{if(n.collapsed||!e.forall(Yh))return I.none();if(t.isSameTable){const t=e.bind(Xh(o));return I.some({start:t,end:t})}{const e=Kh(n.startContainer,o),t=Kh(n.endContainer,o),r=e.bind((e=>t=>mm(t,e).bind((e=>de($h(e)).map((e=>qh(t,e))))))(o)).bind(Xh(o)),s=t.bind((e=>t=>mm(t,e).bind((e=>le($h(e)).map((e=>qh(e,t))))))(o)).bind(Xh(o));return I.some({start:r,end:s})}},Qh=(e,t)=>J(e,(e=>_n(e,t))),Jh=e=>It(Qh(e.cells,e.rng.start),Qh(e.cells,e.rng.end),((t,n)=>e.cells.slice(t,n+1))),eb=(e,t)=>{const{startTable:n,endTable:o}=t,r=e.cloneRange();return n.each((e=>r.setStartAfter(e.dom))),o.each((e=>r.setEndBefore(e.dom))),r},tb=(e,t)=>{const n=(e=>t=>_n(e,t))(e),o=((e,t)=>{const n=Kh(e.startContainer,t),o=Kh(e.endContainer,t);return It(n,o,qh)})(t,n),r=((e,t)=>{const n=Vh(e.startContainer,t),o=Vh(e.endContainer,t),r=n.isSome(),s=o.isSome(),a=It(n,o,_n).getOr(!1);return(e=>It(e.startTable,e.endTable,((t,n)=>{const o=$o(t,(e=>_n(e,n))),r=$o(n,(e=>_n(e,t)));return o||r?{...e,startTable:o?I.none():e.startTable,endTable:r?I.none():e.endTable,isSameTable:!1,isMultiTable:!1}:e})).getOr(e))({startTable:n,endTable:o,isStartInTable:r,isEndInTable:s,isSameTable:a,isMultiTable:!a&&r&&s})})(t,n);return((e,t,n)=>e.exists((e=>((e,t)=>!Yh(e)&&Gh(e,t).exists((e=>{const t=e.dom.rows;return 1===t.length&&1===t[0].cells.length})))(e,n)&&pm(e.start,t))))(o,t,n)?o.map((e=>Wh.singleCellTable(t,e.start))):r.isMultiTable?((e,t,n,o)=>Zh(e,t,n,o).bind((({start:e,end:o})=>{const r=e.bind(Jh).getOr([]),s=o.bind(Jh).getOr([]);if(r.length>0&&s.length>0){const e=eb(n,t);return I.some(Wh.multiTable(r,s,e))}return I.none()})))(o,r,t,n):((e,t,n,o)=>Zh(e,t,n,o).bind((({start:e,end:t})=>e.or(t))).bind((e=>{const{isSameTable:o}=t,r=Jh(e).getOr([]);if(o&&e.cells.length===r.length)return I.some(Wh.fullTable(e.table));if(r.length>0){if(o)return I.some(Wh.partialTable(r,I.none()));{const e=eb(n,t);return I.some(Wh.partialTable(r,I.some({...t,rng:e})))}}return I.none()})))(o,r,t,n)},nb=e=>q(e,(e=>{rn(e,"contenteditable"),Za(e)})),ob=(e,t,n,o)=>{const r=n.cloneRange();o?(r.setStart(n.startContainer,n.startOffset),r.setEndAfter(t.dom.lastChild)):(r.setStartBefore(t.dom.firstChild),r.setEnd(n.endContainer,n.endOffset)),ib(e,r,t,!1).each((e=>e()))},rb=e=>{const t=um(e),n=Cn(e.selection.getNode());yr(n.dom)&&Tr(e.schema,n)?e.selection.setCursorLocation(n.dom,0):e.selection.collapse(!0),t.length>1&&$(t,(e=>_n(e,n)))&&Jt(n,"data-mce-selected","1")},sb=(e,t,n)=>I.some((()=>{const o=e.selection.getRng(),r=n.bind((({rng:n,isStartInTable:r})=>{const s=((e,t)=>I.from(e.dom.getParent(t,e.dom.isBlock)).map(Cn))(e,r?n.endContainer:n.startContainer);n.deleteContents(),((e,t,n)=>{n.each((n=>{t?xo(n):(Za(n),e.selection.setCursorLocation(n.dom,0))}))})(e,r,s.filter(T(Tr,e.schema)));const a=r?t[0]:t[t.length-1];return ob(e,a,o,r),Tr(e.schema,a)?I.none():I.some(r?t.slice(1):t.slice(0,-1))})).getOr(t);nb(r),rb(e)})),ab=(e,t,n,o)=>I.some((()=>{const r=e.selection.getRng(),s=t[0],a=n[n.length-1];ob(e,s,r,!0),ob(e,a,r,!1);const i=Tr(e.schema,s)?t:t.slice(1),l=Tr(e.schema,a)?n:n.slice(0,-1);nb(i.concat(l)),o.deleteContents(),rb(e)})),ib=(e,t,n,o=!0)=>I.some((()=>{Hh(e,t,n,o)})),lb=(e,t)=>I.some((()=>Sh(e,!1,t))),db=(e,t)=>Q(zp(t,e),Ya),cb=(e,t)=>Q(zp(t,e),Zt("caption")),ub=(e,t)=>I.some((()=>{Za(t),e.selection.setCursorLocation(t.dom,0)})),mb=(e,t)=>e?Lp(t):Mp(t),fb=(e,t,n)=>{const o=Cn(e.getBody());return cb(o,n).fold((()=>((e,t,n,o)=>{const r=Qi.fromRangeStart(e.selection.getRng());return db(n,o).bind((o=>Tr(e.schema,o,{checkRootAsContent:!1})?ub(e,o):((e,t,n,o,r)=>Iu(n,e.getBody(),r).bind((e=>db(t,Cn(e.getNode())).bind((e=>_n(e,o)?I.none():I.some(k))))))(e,n,t,o,r)))})(e,t,o,n).orThunk((()=>Ft(((e,t)=>{const n=Qi.fromRangeStart(e.selection.getRng());return mb(t,n)||Mu(t,e.getBody(),n).exists((e=>mb(t,e)))})(e,t),k)))),(n=>((e,t,n,o)=>{const r=Qi.fromRangeStart(e.selection.getRng());return Tr(e.schema,o)?ub(e,o):((e,t,n,o,r)=>Iu(n,e.getBody(),r).fold((()=>I.some(k)),(s=>((e,t,n,o)=>Hu(e.dom).bind((r=>$u(e.dom).map((e=>t?n.isEqual(r)&&o.isEqual(e):n.isEqual(e)&&o.isEqual(r))))).getOr(!0))(o,n,r,s)?((e,t)=>ub(e,t))(e,o):((e,t,n)=>cb(e,Cn(n.getNode())).fold((()=>I.some(k)),(e=>Ft(!_n(e,t),k))))(t,o,s))))(e,n,t,o,r)})(e,t,o,n)))},gb=(e,t)=>{const n=Cn(e.selection.getStart(!0)),o=um(e);return e.selection.isCollapsed()&&0===o.length?fb(e,t,n):((e,t,n)=>{const o=Cn(e.getBody()),r=e.selection.getRng();return 0!==n.length?sb(e,n,I.none()):((e,t,n,o)=>cb(t,o).fold((()=>((e,t,n)=>tb(t,n).bind((t=>t.fold(T(ib,e),T(lb,e),T(sb,e),T(ab,e)))))(e,t,n)),(t=>((e,t)=>ub(e,t))(e,t))))(e,o,r,t)})(e,n,o)},pb=(e,t)=>{let n=t;for(;n&&n!==e;){if(br(n)||vr(n))return n;n=n.parentNode}return null},hb=["data-ephox-","data-mce-","data-alloy-","data-snooker-","_"],bb=Dt.each,vb=e=>{const t=e.dom,n=new Set(e.serializer.getTempAttrs()),o=e=>$(hb,(t=>$e(e,t)))||n.has(e);return{compare:(e,n)=>{if(e.nodeName!==n.nodeName||e.nodeType!==n.nodeType)return!1;const r=e=>{const n={};return bb(t.getAttribs(e),(r=>{const s=r.nodeName.toLowerCase();"style"===s||o(s)||(n[s]=t.getAttrib(e,s))})),n},s=(e,t)=>{for(const n in e)if(ke(e,n)){const o=t[n];if(v(o))return!1;if(e[n]!==o)return!1;delete t[n]}for(const e in t)if(ke(t,e))return!1;return!0};if(er(e)&&er(n)){if(!s(r(e),r(n)))return!1;if(!s(t.parseStyle(t.getAttrib(e,"style")),t.parseStyle(t.getAttrib(n,"style"))))return!1}return!rm(e)&&!rm(n)},isAttributeInternal:o}},yb=e=>["h1","h2","h3","h4","h5","h6"].includes(e.name),Cb=(e,t,n,o)=>{const r=n.name;for(let t=0,s=e.length;t<s;t++){const s=e[t];if(s.name===r){const e=o.nodes[r];e?e.nodes.push(n):o.nodes[r]={filter:s,nodes:[n]}}}if(n.attributes)for(let e=0,r=t.length;e<r;e++){const r=t[e],s=r.name;if(s in n.attributes.map){const e=o.attributes[s];e?e.nodes.push(n):o.attributes[s]={filter:r,nodes:[n]}}}},wb=(e,t)=>{const n=(e,n)=>{pe(e,(e=>{const o=ce(e.nodes);q(e.filter.callbacks,(r=>{for(let t=o.length-1;t>=0;t--){const r=o[t];(n?void 0!==r.attr(e.filter.name):r.name===e.filter.name)&&!y(r.parent)||o.splice(t,1)}o.length>0&&r(o,e.filter.name,t)}))}))};n(e.nodes,!1),n(e.attributes,!0)},Eb=(e,t,n,o={})=>{const r=((e,t,n)=>{const o={nodes:{},attributes:{}};return n.firstChild&&((n,r)=>{let s=n;for(;s=s.walk();)Cb(e,t,s,o)})(n),o})(e,t,n);wb(r,o)},xb=(e,t,n,o)=>{if((e.pad_empty_with_br||t.insert)&&n(o)){const e=new Jg("br",1);t.insert&&e.attr("data-mce-bogus","1"),o.empty().append(e)}else o.empty().append(new Jg("#text",3)).value=Wo},kb=(e,t)=>{const n=null==e?void 0:e.firstChild;return C(n)&&n===e.lastChild&&n.name===t},_b=(e,t,n,o)=>o.isEmpty(t,n,(t=>((e,t)=>{const n=e.getElementRule(t.name);return!0===(null==n?void 0:n.paddEmpty)})(e,t))),Sb=e=>{let t;for(let n=e;n;n=n.parent){const e=n.attr("contenteditable");if("false"===e)break;"true"===e&&(t=n)}return I.from(t)},Nb=(e,t,n=e.parent)=>{if(t.getSpecialElements()[e.name])e.empty().remove();else{const o=e.children();for(const e of o)n&&!t.isValidChild(n.name,e.name)&&Nb(e,t,n);e.unwrap()}},Rb=(e,t,n,o=k)=>{const r=t.getTextBlockElements(),s=t.getNonEmptyElements(),a=t.getWhitespaceElements(),i=Dt.makeMap("tr,td,th,tbody,thead,tfoot,table,summary"),l=new Set,d=e=>e!==n&&!i[e.name];for(let n=0;n<e.length;n++){const i=e[n];let c,u,m;if(!i.parent||l.has(i))continue;if(r[i.name]&&"li"===i.parent.name){let e=i.next;for(;e&&r[e.name];)e.name="li",l.add(e),i.parent.insert(e,i.parent),e=e.next;i.unwrap();continue}const f=[i];for(c=i.parent;c&&!t.isValidChild(c.name,i.name)&&d(c);c=c.parent)f.push(c);if(c&&f.length>1)if(Ab(t,i,c))Nb(i,t);else{f.reverse(),u=f[0].clone(),o(u);let e=u;for(let n=0;n<f.length-1;n++){t.isValidChild(e.name,f[n].name)&&n>0?(m=f[n].clone(),o(m),e.append(m)):m=e;for(let e=f[n].firstChild;e&&e!==f[n+1];){const t=e.next;m.append(e),e=t}e=m}_b(t,s,a,u)?c.insert(i,f[0],!0):(c.insert(u,f[0],!0),c.insert(i,u)),c=f[0],(_b(t,s,a,c)||kb(c,"br"))&&c.empty().remove()}else if(i.parent){if("li"===i.name){let e=i.prev;if(e&&("ul"===e.name||"ol"===e.name)){e.append(i);continue}if(e=i.next,e&&("ul"===e.name||"ol"===e.name)&&e.firstChild){e.insert(i,e.firstChild,!0);continue}const t=new Jg("ul",1);o(t),i.wrap(t);continue}if(t.isValidChild(i.parent.name,"div")&&t.isValidChild("div",i.name)){const e=new Jg("div",1);o(e),i.wrap(e)}else Nb(i,t)}}},Ab=(e,t,n=t.parent)=>!(!n||(!e.children[t.name]||e.isValidChild(n.name,t.name))&&("a"!==t.name||!((e,t)=>{let n=e;for(;n;){if("a"===n.name)return!0;n=n.parent}return!1})(n))&&(!(e=>"summary"===e.name)(n)||!yb(t)||(null==n?void 0:n.firstChild)===t&&(null==n?void 0:n.lastChild)===t)),Tb=e=>e.collapsed?e:(e=>{const t=Qi.fromRangeStart(e),n=Qi.fromRangeEnd(e),o=e.commonAncestorContainer;return Mu(!1,o,n).map((r=>!lu(t,n,o)&&lu(t,r,o)?((e,t,n,o)=>{const r=document.createRange();return r.setStart(e,t),r.setEnd(n,o),r})(t.container(),t.offset(),r.container(),r.offset()):e)).getOr(e)})(e),Ob=(e,t)=>{let n=t.firstChild,o=t.lastChild;return n&&"meta"===n.name&&(n=n.next),o&&"mce_marker"===o.attr("id")&&(o=o.prev),((e,t)=>{const n=e.getNonEmptyElements();return C(t)&&(t.isEmpty(n)||((e,t)=>e.getBlockElements()[t.name]&&(e=>C(e.firstChild)&&e.firstChild===e.lastChild)(t)&&(e=>"br"===e.name||e.value===Wo)(t.firstChild))(e,t))})(e,o)&&(o=null==o?void 0:o.prev),!(!n||n!==o||"ul"!==n.name&&"ol"!==n.name)},Bb=e=>{return e.length>0&&(!(n=e[e.length-1]).firstChild||C(null==(t=n)?void 0:t.firstChild)&&t.firstChild===t.lastChild&&(e=>e.data===Wo||pr(e))(t.firstChild))?e.slice(0,-1):e;var t,n},Pb=(e,t)=>{const n=e.getParent(t,e.isBlock);return n&&"LI"===n.nodeName?n:null},Db=(e,t)=>{const n=Qi.after(e),o=Bu(t).prev(n);return o?o.toRange():null},Lb=(e,t,n,o)=>{const r=((e,t,n)=>{const o=t.serialize(n);return(e=>{var t,n;const o=e.firstChild,r=e.lastChild;return o&&"META"===o.nodeName&&(null===(t=o.parentNode)||void 0===t||t.removeChild(o)),r&&"mce_marker"===r.id&&(null===(n=r.parentNode)||void 0===n||n.removeChild(r)),e})(e.createFragment(o))})(t,e,o),s=Pb(t,n.startContainer),a=Bb((i=r.firstChild,Y(null!==(l=null==i?void 0:i.childNodes)&&void 0!==l?l:[],(e=>"LI"===e.nodeName))));var i,l;const d=t.getRoot(),c=e=>{const o=Qi.fromRangeStart(n),r=Bu(t.getRoot()),a=1===e?r.prev(o):r.next(o),i=null==a?void 0:a.getNode();return!i||Pb(t,i)!==s};return s?c(1)?((e,t,n)=>{const o=e.parentNode;return o&&Dt.each(t,(t=>{o.insertBefore(t,e)})),((e,t)=>{const n=Qi.before(e),o=Bu(t).next(n);return o?o.toRange():null})(e,n)})(s,a,d):c(2)?((e,t,n,o)=>(o.insertAfter(t.reverse(),e),Db(t[0],n)))(s,a,d,t):((e,t,n,o)=>{const r=((e,t)=>{const n=t.cloneRange(),o=t.cloneRange();return n.setStartBefore(e),o.setEndAfter(e),[n.cloneContents(),o.cloneContents()]})(e,o),s=e.parentNode;return s&&(s.insertBefore(r[0],e),Dt.each(t,(t=>{s.insertBefore(t,e)})),s.insertBefore(r[1],e),s.removeChild(e)),Db(t[t.length-1],n)})(s,a,d,n):null},Mb=["pre"],Ib=yr,Fb=(e,t,n)=>{var o,r;const s=e.selection,a=e.dom,i=e.parser,l=n.merge,d=vp({validate:!0},e.schema),c='<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';n.preserve_zwsp||(t=ei(t)),-1===t.indexOf("{$caret}")&&(t+="{$caret}"),t=t.replace(/\{\$caret\}/,c);let u=s.getRng();const m=u.startContainer,f=e.getBody();m===f&&s.isCollapsed()&&a.isBlock(f.firstChild)&&((e,t)=>C(t)&&!e.schema.getVoidElements()[t.nodeName])(e,f.firstChild)&&a.isEmpty(f.firstChild)&&(u=a.createRng(),u.setStart(f.firstChild,0),u.setEnd(f.firstChild,0),s.setRng(u)),s.isCollapsed()||(e=>{const t=e.dom,n=Tb(e.selection.getRng());e.selection.setRng(n);const o=t.getParent(n.startContainer,Ib);((e,t,n)=>!!C(n)&&n===e.getParent(t.endContainer,Ib)&&pm(Cn(n),t))(t,n,o)?ib(e,n,Cn(o)):n.startContainer===n.endContainer&&n.endOffset-n.startOffset==1&&dr(n.startContainer.childNodes[n.startOffset])?n.deleteContents():e.getDoc().execCommand("Delete",!1)})(e);const g=s.getNode(),p={context:g.nodeName.toLowerCase(),data:n.data,insert:!0},h=i.parse(t,p);if(!0===n.paste&&Ob(e.schema,h)&&((e,t)=>!!Pb(e,t))(a,g))return u=Lb(d,a,s.getRng(),h),u&&s.setRng(u),t;!0===n.paste&&((e,t,n,o)=>{var r;const s=t.firstChild,a=t.lastChild,i=s===("bookmark"===a.attr("data-mce-type")?a.prev:a),l=H(Mb,s.name);if(i&&l){const t="false"!==s.attr("contenteditable"),a=(null===(r=e.getParent(n,e.isBlock))||void 0===r?void 0:r.nodeName.toLowerCase())===s.name,i=I.from(pb(o,n)).forall(br);return t&&a&&i}return!1})(a,h,g,e.getBody())&&(null===(o=h.firstChild)||void 0===o||o.unwrap()),(e=>{let t=e;for(;t=t.walk();)1===t.type&&t.attr("data-mce-fragment","1")})(h);let b=h.lastChild;if(b&&"mce_marker"===b.attr("id")){const t=b;for(b=b.prev;b;b=b.walk(!0))if(3===b.type||!a.isBlock(b.name)){b.parent&&e.schema.isValidChild(b.parent.name,"span")&&b.parent.insert(t,b,"br"===b.name);break}}if(e._selectionOverrides.showBlockCaretContainer(g),p.invalid||((e,t,n)=>{var o;return $(n.children(),yb)&&"SUMMARY"===(null===(o=e.getParent(t,e.isBlock))||void 0===o?void 0:o.nodeName)})(a,g,h)){e.selection.setContent(c);let n,o=s.getNode();const l=e.getBody();for(fr(o)?o=n=l:n=o;n&&n!==l;)o=n,n=n.parentNode;t=o===l?l.innerHTML:a.getOuterHTML(o);const u=i.parse(t),m=(e=>{for(let t=e;t;t=t.walk())if("mce_marker"===t.attr("id"))return I.some(t);return I.none()})(u),f=m.bind(Sb).getOr(u);m.each((e=>e.replace(h)));const g=h.children(),p=null!==(r=h.parent)&&void 0!==r?r:u;h.unwrap();const b=Y(g,(t=>Ab(e.schema,t,p)));Rb(b,e.schema,f),Eb(i.getNodeFilters(),i.getAttributeFilters(),u),t=d.serialize(u),o===l?a.setHTML(l,t):a.setOuterHTML(o,t)}else t=d.serialize(h),((e,t,n)=>{var o;if("all"===n.getAttribute("data-mce-bogus"))null===(o=n.parentNode)||void 0===o||o.insertBefore(e.dom.createFragment(t),n);else{const o=n.firstChild,r=n.lastChild;!o||o===r&&"BR"===o.nodeName?e.dom.setHTML(n,t):e.selection.setContent(t,{no_events:!0})}})(e,t,g);var v;return((e,t)=>{const n=e.schema.getTextInlineElements(),o=e.dom;if(t){const t=e.getBody(),r=vb(e),s="*[data-mce-fragment]",a=o.select(s);Dt.each(a,(e=>{const a=e=>C(n[e.nodeName.toLowerCase()]),i=e=>1===e.childNodes.length;if(!xp(o,l=e)&&!((e,t)=>xp(e,t)&&$(Ep(e,t),(e=>(e=>Cp.has(e))(e))))(o,l)&&a(e)&&i(e)){const n=Ep(o,e),l=(e,t)=>ne(e,(e=>H(t,e))),d=t=>i(e)&&o.is(t,s)&&a(t)&&(t.nodeName===e.nodeName&&l(n,Ep(o,t))||d(t.children[0])),c=n=>C(n)&&n!==t&&(r.compare(e,n)||c(n.parentElement)),u=n=>C(n)&&n!==t&&o.is(n,s)&&(((e,t,n)=>{const o=Ep(e,t),r=Ep(e,n),s=o=>{var r,s;const a=null!==(r=e.getStyle(t,o))&&void 0!==r?r:"",i=null!==(s=e.getStyle(n,o))&&void 0!==s?s:"";return Ge(a)&&Ge(i)&&a!==i};return $(o,(e=>{const t=t=>$(t,(t=>t===e));if(!t(r)&&t(wp)){const e=Y(r,(e=>$(wp,(t=>$e(e,t)))));return $(e,s)}return s(e)}))})(o,e,n)||u(n.parentElement));(d(e.children[0])||c(e.parentElement)&&!u(e.parentElement))&&o.remove(e,!0)}var l}))}})(e,l),((e,t)=>{var n,o,r;let s;const a=e.dom,i=e.selection;if(!t)return;i.scrollIntoView(t);const l=pb(e.getBody(),t);if(l&&"false"===a.getContentEditable(l))return a.remove(t),void i.select(l);let d=a.createRng();const c=t.previousSibling;if(dr(c)){d.setStart(c,null!==(o=null===(n=c.nodeValue)||void 0===n?void 0:n.length)&&void 0!==o?o:0);const e=t.nextSibling;dr(e)&&(c.appendData(e.data),null===(r=e.parentNode)||void 0===r||r.removeChild(e))}else d.setStartBefore(t),d.setEndBefore(t);const u=a.getParent(t,a.isBlock);if(a.remove(t),u&&a.isEmpty(u)){const t=Ib(u);Eo(Cn(u)),d.setStart(u,0),d.setEnd(u,0),t||(e=>!!e.getAttribute("data-mce-fragment"))(u)||!(s=(t=>{let n=Qi.fromRangeStart(t);return n=Bu(e.getBody()).next(n),null==n?void 0:n.toRange()})(d))?a.add(u,a.create("br",t?{}:{"data-mce-bogus":"1"})):(d=s,a.remove(u))}i.setRng(d)})(e,a.get("mce_marker")),v=e.getBody(),Dt.each(v.getElementsByTagName("*"),(e=>{e.removeAttribute("data-mce-fragment")})),((e,t,n)=>{I.from(e.getParent(t,"td,th")).map(Cn).each((e=>((e,t)=>{zn(e).each((n=>{Pn(n).each((o=>{t.isBlock($t(e))&&$a(n)&&t.isBlock($t(o))&&xo(n)}))}))})(e,n)))})(a,s.getStart(),e.schema),((e,t,n)=>{const o=Bn(Cn(n),(e=>_n(e,Cn(t))));ie(o,o.length-2).filter(Kt).fold((()=>Wr(e,t)),(t=>Wr(e,t.dom)))})(e.schema,e.getBody(),s.getStart()),t},Ub=e=>e instanceof Jg,zb=(e,t,n)=>{e.dom.setHTML(e.getBody(),t),!0!==n&&(e=>{zg(e)&&Hu(e.getBody()).each((t=>{const n=t.getNode(),o=ar(n)?Hu(n).getOr(t):t;e.selection.setRng(o.toRange())}))})(e)},jb=e=>w(e)?e:L,Hb=(e,t,n)=>{const o=t(e),r=jb(n);return o.orThunk((()=>r(e)?I.none():((e,t,n)=>{let o=e.dom;const r=jb(n);for(;o.parentNode;){o=o.parentNode;const e=Cn(o),n=t(e);if(n.isSome())return n;if(r(e))break}return I.none()})(e,t,r)))},$b=Tm,Vb=(e,t,n)=>{const o=e.formatter.get(n);if(o)for(let n=0;n<o.length;n++){const r=o[n];if(Im(r)&&!1===r.inherit&&e.dom.is(t,r.selector))return!0}return!1},qb=(e,t,n,o,r)=>{const s=e.dom.getRoot();if(t===s)return!1;const a=e.dom.getParent(t,(t=>!!Vb(e,t,n)||t.parentNode===s||!!Yb(e,t,n,o,!0)));return!!Yb(e,a,n,o,r)},Wb=(e,t,n)=>!(!Fm(n)||!$b(t,n.inline))||!(!Mm(n)||!$b(t,n.block))||!!Im(n)&&er(t)&&e.is(t,n.selector),Kb=(e,t,n,o,r,s)=>{const a=n[o],i="attributes"===o;if(w(n.onmatch))return n.onmatch(t,n,o);if(a)if(Ne(a)){for(let n=0;n<a.length;n++)if(i?e.getAttrib(t,a[n]):Bm(e,t,a[n]))return!0}else for(const o in a)if(ke(a,o)){const l=i?e.getAttrib(t,o):Bm(e,t,o),d=Am(a[o],s),c=y(l)||Xe(l);if(c&&y(d))continue;if(r&&c&&!n.exact)return!1;if((!r||n.exact)&&!$b(l,Om(d,o)))return!1}return!0},Yb=(e,t,n,o,r)=>{const s=e.formatter.get(n),a=e.dom;if(s&&er(t))for(let n=0;n<s.length;n++){const i=s[n];if(Wb(e.dom,t,i)&&Kb(a,t,i,"attributes",r,o)&&Kb(a,t,i,"styles",r,o)){const n=i.classes;if(n)for(let r=0;r<n.length;r++)if(!e.dom.hasClass(t,Am(n[r],o)))return;return i}}},Gb=(e,t,n,o,r)=>{if(o)return qb(e,o,t,n,r);if(o=e.selection.getNode(),qb(e,o,t,n,r))return!0;const s=e.selection.getStart();return!(s===o||!qb(e,s,t,n,r))},Xb=Qa,Zb=e=>{if(e){const t=new Vo(e,e);for(let e=t.current();e;e=t.next())if(dr(e))return e}return null},Qb=e=>{const t=vn("span");return en(t,{id:Vu,"data-mce-bogus":"1","data-mce-type":"format-caret"}),e&&yo(t,yn(Xb)),t},Jb=(e,t,n)=>{const o=e.dom,r=e.selection;if(zm(t))Sh(e,!1,Cn(t),n,!0);else{const e=r.getRng(),n=o.getParent(t,o.isBlock),s=e.startContainer,a=e.startOffset,i=e.endContainer,l=e.endOffset,d=(e=>{const t=Zb(e);return t&&t.data.charAt(0)===Xb&&t.deleteData(0,1),t})(t);o.remove(t,!0),s===d&&a>0&&e.setStart(d,a-1),i===d&&l>0&&e.setEnd(d,l-1),n&&o.isEmpty(n)&&Za(Cn(n)),r.setRng(e)}},ev=(e,t,n)=>{const o=e.dom,r=e.selection;if(t)Jb(e,t,n);else if(!(t=Wu(e.getBody(),r.getStart())))for(;t=o.get(Vu);)Jb(e,t,n)},tv=(e,t)=>(e.appendChild(t),t),nv=(e,t)=>{var n;const o=G(e,((e,t)=>tv(e,t.cloneNode(!1))),t),r=null!==(n=o.ownerDocument)&&void 0!==n?n:document;return tv(o,r.createTextNode(Xb))},ov=(e,t,n,o)=>{const a=e.dom,i=e.selection;let l=!1;const d=e.formatter.get(t);if(!d)return;const c=i.getRng(),u=c.startContainer,m=c.startOffset;let f=u;dr(u)&&(m!==u.data.length&&(l=!0),f=f.parentNode);const g=[];let h;for(;f;){if(Yb(e,f,t,n,o)){h=f;break}f.nextSibling&&(l=!0),g.push(f),f=f.parentNode}if(h)if(l){const r=i.getBookmark();c.collapse(!0);let s=nf(a,c,d,!0);s=Xf(s),e.formatter.remove(t,n,s,o),i.moveToBookmark(r)}else{const l=Wu(e.getBody(),h),d=C(l)?a.getParents(h.parentNode,M,l):[],c=Qb(!1).dom;((e,t,n)=>{var o,r;const s=e.dom,a=s.getParent(n,T(_m,e.schema));a&&s.isEmpty(a)?null===(o=n.parentNode)||void 0===o||o.replaceChild(t,n):((e=>{const t=zo(e,"br"),n=Y((e=>{const t=[];let n=e.dom;for(;n;)t.push(Cn(n)),n=n.lastChild;return t})(e).slice(-1),$a);t.length===n.length&&q(n,xo)})(Cn(n)),s.isEmpty(n)?null===(r=n.parentNode)||void 0===r||r.replaceChild(t,n):s.insertAfter(t,n))})(e,c,null!=l?l:h);const u=((e,t,n,o,a,i)=>{const l=e.formatter,d=e.dom,c=Y(fe(l.get()),(e=>e!==o&&!He(e,"removeformat"))),u=((e,t,n)=>X(n,((n,o)=>{const r=((e,t)=>Lm(e,t,(e=>{const t=e=>w(e)||e.length>1&&"%"===e.charAt(0);return $(["styles","attributes"],(n=>xe(e,n).exists((e=>{const n=p(e)?e:Ee(e);return $(n,t)}))))})))(e,o);return e.formatter.matchNode(t,o,{},r)?n.concat([o]):n}),[]))(e,n,c);if(Y(u,(t=>!((e,t,n)=>{const o=["inline","block","selector","attributes","styles","classes"],a=e=>Ce(e,((e,t)=>$(o,(e=>e===t))));return Lm(e,t,(t=>{const o=a(t);return Lm(e,n,(e=>{const t=a(e);return((e,t,n=s)=>r(n).eq(e,t))(o,t)}))}))})(e,t,o))).length>0){const e=n.cloneNode(!1);return d.add(t,e),l.remove(o,a,e,i),d.remove(e),I.some(e)}return I.none()})(e,c,h,t,n,o),m=nv([...g,...u.toArray(),...d],c);l&&Jb(e,l,C(l)),i.setCursorLocation(m,1),a.isEmpty(h)&&a.remove(h)}},rv=e=>{const t=Qb(!1),n=nv(e,t.dom);return{caretContainer:t,caretPosition:Qi(n,0)}},sv=(e,t)=>{const{caretContainer:n,caretPosition:o}=rv(t);return ho(Cn(e),n),xo(Cn(e)),o},av=(e,t)=>{if(qu(t.dom))return!1;const n=e.schema.getTextInlineElements();return ke(n,$t(t))&&!qu(t.dom)&&!sr(t.dom)},iv={},lv=or(["pre"]);((e,t)=>{iv[e]||(iv[e]=[]),iv[e].push((e=>{if(!e.selection.getRng().collapsed){const t=e.selection.getSelectedBlocks(),n=Y(Y(t,lv),(e=>t=>{const n=t.previousSibling;return lv(n)&&H(e,n)})(t));q(n,(e=>{((e,t)=>{const n=Cn(t),o=Rn(n).dom;xo(n),wo(Cn(e),[vn("br",o),vn("br",o),...In(n)])})(e.previousSibling,e)}))}}))})("pre");const dv=["fontWeight","fontStyle","color","fontSize","fontFamily"],cv=(e,t)=>{const n=e.get(t);return p(n)?Q(n,(e=>Fm(e)&&"span"===e.inline&&(e=>f(e.styles)&&$(fe(e.styles),(e=>H(dv,e))))(e))):I.none()},uv=(e,t)=>ju(t,Qi.fromRangeStart(e)).isNone(),mv=(e,t)=>!1===zu(t,Qi.fromRangeEnd(e)).exists((e=>!pr(e.getNode())||zu(t,e).isSome())),fv=e=>t=>Er(t)&&e.isEditable(t),gv=e=>Y(e.getSelectedBlocks(),fv(e.dom)),pv=Dt.each,hv=e=>er(e)&&!rm(e)&&!qu(e)&&!sr(e),bv=(e,t)=>{for(let n=e;n;n=n[t]){if(dr(n)&&Ge(n.data))return e;if(er(n)&&!rm(n))return n}return e},vv=(e,t,n)=>{const o=vb(e),r=tr(t)&&e.dom.isEditable(t),s=tr(n)&&e.dom.isEditable(n);if(r&&s){const r=bv(t,"previousSibling"),s=bv(n,"nextSibling");if(o.compare(r,s)){for(let e=r.nextSibling;e&&e!==s;){const t=e;e=e.nextSibling,r.appendChild(t)}return e.dom.remove(s),Dt.each(Dt.grep(s.childNodes),(e=>{r.appendChild(e)})),r}}return n},yv=(e,t,n,o)=>{var r;if(o&&!1!==t.merge_siblings){const t=null!==(r=vv(e,km(o),o))&&void 0!==r?r:o;vv(e,t,km(t,!0))}},Cv=(e,t,n)=>{pv(e.childNodes,(e=>{hv(e)&&(t(e)&&n(e),e.hasChildNodes()&&Cv(e,t,n))}))},wv=(e,t)=>n=>!(!n||!Bm(e,n,t)),Ev=(e,t,n)=>o=>{e.setStyle(o,t,n),""===o.getAttribute("style")&&o.removeAttribute("style"),((e,t)=>{"SPAN"===t.nodeName&&0===e.getAttribs(t).length&&e.remove(t,!0)})(e,o)},xv=xl([{keep:[]},{rename:["name"]},{removed:[]}]),kv=/^(src|href|style)$/,_v=Dt.each,Sv=Tm,Nv=(e,t,n)=>e.isChildOf(t,n)&&t!==n&&!e.isBlock(n),Rv=(e,t,n)=>{let o=t[n?"startContainer":"endContainer"],r=t[n?"startOffset":"endOffset"];if(er(o)){const e=o.childNodes.length-1;!n&&r&&r--,o=o.childNodes[r>e?e:r]}return dr(o)&&n&&r>=o.data.length&&(o=new Vo(o,e.getBody()).next()||o),dr(o)&&!n&&0===r&&(o=new Vo(o,e.getBody()).prev()||o),o},Av=(e,t)=>{const n=t?"firstChild":"lastChild",o=e[n];return(e=>/^(TR|TH|TD)$/.test(e.nodeName))(e)&&o?"TR"===e.nodeName&&o[n]||o:e},Tv=(e,t,n,o)=>{var r;const s=e.create(n,o);return null===(r=t.parentNode)||void 0===r||r.insertBefore(s,t),s.appendChild(t),s},Ov=(e,t,n,o,r)=>{const s=Cn(t),a=Cn(e.create(o,r)),i=n?Mn(s):Ln(s);return wo(a,i),n?(ho(s,a),vo(a,s)):(bo(s,a),yo(a,s)),a.dom},Bv=(e,t,n)=>{const o=t.parentNode;let r;const s=e.dom,a=ql(e);Mm(n)&&o===s.getRoot()&&(n.list_block&&Sv(t,n.list_block)||q(ce(t.childNodes),(t=>{Sm(e,a,t.nodeName.toLowerCase())?r?r.appendChild(t):(r=Tv(s,t,a),s.setAttribs(r,Wl(e))):r=null}))),(e=>Im(e)&&Fm(e)&&Lt(xe(e,"mixed"),!0))(n)&&!Sv(n.inline,t)||s.remove(t,!0)},Pv=(e,t,n)=>E(e)?{name:t,value:null}:{name:e,value:Am(t,n)},Dv=(e,t)=>{""===e.getAttrib(t,"style")&&(t.removeAttribute("style"),t.removeAttribute("data-mce-style"))},Lv=(e,t,n,o,r)=>{let s=!1;_v(n.styles,((a,i)=>{const{name:l,value:d}=Pv(i,a,o),c=Om(d,l);(n.remove_similar||h(d)||!er(r)||Sv(Bm(e,r,l),c))&&e.setStyle(t,l,""),s=!0})),s&&Dv(e,t)},Mv=(e,t,n,o,r)=>{const s=e.dom,a=vb(e),i=e.schema;if(Fm(t)&&Gr(i,t.inline)&&Zr(i,o)&&o.parentElement===e.getBody())return Bv(e,o,t),xv.removed();if(!t.ceFalseOverride&&o&&"false"===s.getContentEditableParent(o))return xv.keep();if(o&&!Wb(s,o,t)&&!((e,t)=>t.links&&"A"===e.nodeName)(o,t))return xv.keep();const l=o,d=t.preserve_attributes;if(Fm(t)&&"all"===t.remove&&p(d)){const e=Y(s.getAttribs(l),(e=>H(d,e.name.toLowerCase())));if(s.removeAllAttribs(l),q(e,(e=>s.setAttrib(l,e.name,e.value))),e.length>0)return xv.rename("span")}if("all"!==t.remove){Lv(s,l,t,n,r),_v(t.attributes,((e,o)=>{const{name:a,value:i}=Pv(o,e,n);if(t.remove_similar||h(i)||!er(r)||Sv(s.getAttrib(r,a),i)){if("class"===a){const e=s.getAttrib(l,a);if(e){let t="";if(q(e.split(/\s+/),(e=>{/mce\-\w+/.test(e)&&(t+=(t?" ":"")+e)})),t)return void s.setAttrib(l,a,t)}}if(kv.test(a)&&l.removeAttribute("data-mce-"+a),"style"===a&&or(["li"])(l)&&"none"===s.getStyle(l,"list-style-type"))return l.removeAttribute(a),void s.setStyle(l,"list-style-type","none");"class"===a&&l.removeAttribute("className"),l.removeAttribute(a)}})),_v(t.classes,(e=>{e=Am(e,n),er(r)&&!s.hasClass(r,e)||s.removeClass(l,e)}));const e=s.getAttribs(l);for(let t=0;t<e.length;t++){const n=e[t].nodeName;if(!a.isAttributeInternal(n))return xv.keep()}}return"none"!==t.remove?(Bv(e,l,t),xv.removed()):xv.keep()},Iv=(e,t,n,o)=>Mv(e,t,n,o,o).fold(N(o),(t=>(e.dom.createFragment().appendChild(o),e.dom.rename(o,t))),N(null)),Fv=(e,t,n,o,r)=>{(o||e.selection.isEditable())&&((e,t,n,o,r)=>{const s=e.formatter.get(t),a=s[0],i=e.dom,l=e.selection,d=o=>{const i=((e,t,n,o,r)=>{let s;return t.parentNode&&q(Dm(e.dom,t.parentNode).reverse(),(t=>{if(!s&&er(t)&&"_start"!==t.id&&"_end"!==t.id){const a=Yb(e,t,n,o,r);a&&!1!==a.split&&(s=t)}})),s})(e,o,t,n,r);return((e,t,n,o,r,s,a,i)=>{var l,d;let c,u;const m=e.dom;if(n){const s=n.parentNode;for(let n=o.parentNode;n&&n!==s;n=n.parentNode){let o=m.clone(n,!1);for(let n=0;n<t.length&&(o=Iv(e,t[n],i,o),null!==o);n++);o&&(c&&o.appendChild(c),u||(u=o),c=o)}a.mixed&&m.isBlock(n)||(o=null!==(l=m.split(n,o))&&void 0!==l?l:o),c&&u&&(null===(d=r.parentNode)||void 0===d||d.insertBefore(c,r),u.appendChild(r),Fm(a)&&yv(e,a,0,c))}return o})(e,s,i,o,o,0,a,n)},c=t=>$(s,(o=>Uv(e,o,n,t,t))),u=t=>{const n=ce(t.childNodes),o=c(t)||$(s,(e=>Wb(i,t,e))),r=t.parentNode;if(!o&&C(r)&&Um(a)&&c(r),a.deep&&n.length)for(let e=0;e<n.length;e++)u(n[e]);q(["underline","line-through","overline"],(n=>{er(t)&&e.dom.getStyle(t,"text-decoration")===n&&t.parentNode&&Pm(i,t.parentNode)===n&&Uv(e,{deep:!1,exact:!0,inline:"span",styles:{textDecoration:n}},void 0,t)}))},m=e=>{const t=i.get(e?"_start":"_end");if(t){let n=t[e?"firstChild":"lastChild"];return(e=>rm(e)&&er(e)&&("_start"===e.id||"_end"===e.id))(n)&&(n=n[e?"firstChild":"lastChild"]),dr(n)&&0===n.data.length&&(n=e?t.previousSibling||t.nextSibling:t.nextSibling||t.previousSibling),i.remove(t,!0),n}return null},f=t=>{let n,o,r=nf(i,t,s,t.collapsed);if(a.split){if(r=Xf(r),n=Rv(e,r,!0),o=Rv(e,r),n!==o){if(n=Av(n,!0),o=Av(o,!1),Nv(i,n,o)){const e=I.from(n.firstChild).getOr(n);return d(Ov(i,e,!0,"span",{id:"_start","data-mce-type":"bookmark"})),void m(!0)}if(Nv(i,o,n)){const e=I.from(o.lastChild).getOr(o);return d(Ov(i,e,!1,"span",{id:"_end","data-mce-type":"bookmark"})),void m(!1)}n=Tv(i,n,"span",{id:"_start","data-mce-type":"bookmark"}),o=Tv(i,o,"span",{id:"_end","data-mce-type":"bookmark"});const e=i.createRng();e.setStartAfter(n),e.setEndBefore(o),of(i,e,(e=>{q(e,(e=>{rm(e)||rm(e.parentNode)||d(e)}))})),d(n),d(o),n=m(!0),o=m()}else n=o=d(n);r.startContainer=n.parentNode?n.parentNode:n,r.startOffset=i.nodeIndex(n),r.endContainer=o.parentNode?o.parentNode:o,r.endOffset=i.nodeIndex(o)+1}of(i,r,(e=>{q(e,u)}))};if(o){if(Cm(o)){const e=i.createRng();e.setStartBefore(o),e.setEndAfter(o),f(e)}else f(o);gf(e,t,o,n)}else l.isCollapsed()&&Fm(a)&&!um(e).length?ov(e,t,n,r):(Em(e,(()=>vm(e,f)),(o=>Fm(a)&&Gb(e,t,n,o))),e.nodeChanged()),((e,t,n)=>{"removeformat"===t?q(gv(e.selection),(t=>{q(dv,(n=>e.dom.setStyle(t,n,""))),Dv(e.dom,t)})):cv(e.formatter,t).each((t=>{q(gv(e.selection),(o=>Lv(e.dom,o,t,n,null)))}))})(e,t,n),gf(e,t,o,n)})(e,t,n,o,r)},Uv=(e,t,n,o,r)=>Mv(e,t,n,o,r).fold(L,(t=>(e.dom.rename(o,t),!0)),M),zv=Dt.each,jv=Dt.each,Hv=(e,t,n,o)=>{if(jv(n.styles,((n,r)=>{e.setStyle(t,r,Am(n,o))})),n.styles){const n=e.getAttrib(t,"style");n&&e.setAttrib(t,"data-mce-style",n)}},$v=(e,t,n,o)=>{const r=e.formatter.get(t),s=r[0],a=!o&&e.selection.isCollapsed(),i=e.dom,l=e.selection,d=(e,t=s)=>{w(t.onformat)&&t.onformat(e,t,n,o),Hv(i,e,t,n),jv(t.attributes,((t,o)=>{i.setAttrib(e,o,Am(t,n))})),jv(t.classes,(t=>{const o=Am(t,n);i.hasClass(e,o)||i.addClass(e,o)}))},c=(e,t)=>{let n=!1;return jv(e,(e=>!(!Im(e)||("false"!==i.getContentEditable(t)||e.ceFalseOverride)&&(!C(e.collapsed)||e.collapsed===a)&&i.is(t,e.selector)&&!qu(t)&&(d(t,e),n=!0,1)))),n},u=e=>{if(m(e)){const t=i.create(e);return d(t),t}return null},f=(o,a,i)=>{const l=[];let m=!0;const f=s.inline||s.block,g=u(f);of(o,a,(a=>{let u;const p=a=>{let h=!1,b=m,v=!1;const y=a.parentNode,w=y.nodeName.toLowerCase(),E=o.getContentEditable(a);C(E)&&(b=m,m="true"===E,h=!0,v=Rm(e,a));const x=m&&!h;if(pr(a)&&!((e,t,n,o)=>{if(Td(e)&&Fm(t)&&n.parentNode){const t=Ms(e.schema),r=Ho(Cn(n),(e=>qu(e.dom)));return _e(t,o)&&Ar(e.schema,n.parentNode,{skipBogus:!1,includeZwsp:!0})&&!r}return!1})(e,s,a,w))return u=null,void(Mm(s)&&o.remove(a));if((o=>(e=>Mm(e)&&!0===e.wrapper)(s)&&Yb(e,o,t,n))(a))u=null;else{if(((t,n,o)=>{const r=(e=>Mm(e)&&!0!==e.wrapper)(s)&&_m(e.schema,t)&&Sm(e,n,f);return o&&r})(a,w,x)){const e=o.rename(a,f);return d(e),l.push(e),void(u=null)}if(Im(s)){let e=c(r,a);if(!e&&C(y)&&Um(s)&&(e=c(r,y)),!Fm(s)||e)return void(u=null)}C(g)&&((t,n,r,a)=>{const l=t.nodeName.toLowerCase(),d=Sm(e,f,l)&&Sm(e,n,f),c=!i&&dr(t)&&Ja(t.data),u=qu(t),m=!Fm(s)||!o.isBlock(t);return(r||a)&&d&&!c&&!u&&m})(a,w,x,v)?(u||(u=o.clone(g,!1),y.insertBefore(u,a),l.push(u)),v&&h&&(m=b),u.appendChild(a)):(u=null,q(ce(a.childNodes),p),h&&(m=b),u=null)}};q(a,p)})),!0===s.links&&q(l,(e=>{const t=e=>{"A"===e.nodeName&&d(e,s),q(ce(e.childNodes),t)};t(e)})),q(l,(a=>{const i=(e=>{let t=0;return q(e.childNodes,(e=>{(e=>C(e)&&dr(e)&&0===e.length)(e)||rm(e)||t++})),t})(a);!(l.length>1)&&o.isBlock(a)||0!==i?(Fm(s)||Mm(s)&&s.wrapper)&&(s.exact||1!==i||(a=(e=>{const t=Q(e.childNodes,wm).filter((e=>"false"!==o.getContentEditable(e)&&Wb(o,e,s)));return t.map((t=>{const n=o.clone(t,!1);return d(n),o.replace(n,e,!0),o.remove(t,!0),n})).getOr(e)})(a)),((e,t,n,o)=>{zv(t,(t=>{Fm(t)&&zv(e.dom.select(t.inline,o),(o=>{hv(o)&&Uv(e,t,n,o,t.exact?o:null)})),((e,t,n)=>{if(t.clear_child_styles){const o=t.links?"*:not(a)":"*";pv(e.select(o,n),(n=>{hv(n)&&e.isEditable(n)&&pv(t.styles,((t,o)=>{e.setStyle(n,o,"")}))}))}})(e.dom,t,o)}))})(e,r,n,a),((e,t,n,o,r)=>{const s=r.parentNode;Yb(e,s,n,o)&&Uv(e,t,o,r)||t.merge_with_parents&&s&&e.dom.getParent(s,(s=>!!Yb(e,s,n,o)&&(Uv(e,t,o,r),!0)))})(e,s,t,n,a),((e,t,n,o)=>{if(t.styles&&t.styles.backgroundColor){const r=wv(e,"fontSize");Cv(o,(t=>r(t)&&e.isEditable(t)),Ev(e,"backgroundColor",Am(t.styles.backgroundColor,n)))}})(o,s,n,a),((e,t,n,o)=>{const r=t=>{if(tr(t)&&er(t.parentNode)&&e.isEditable(t)){const n=Pm(e,t.parentNode);e.getStyle(t,"color")&&n?e.setStyle(t,"text-decoration",n):e.getStyle(t,"text-decoration")===n&&e.setStyle(t,"text-decoration",null)}};t.styles&&(t.styles.color||t.styles.textDecoration)&&(Dt.walk(o,r,"childNodes"),r(o))})(o,s,0,a),((e,t,n,o)=>{if(Fm(t)&&("sub"===t.inline||"sup"===t.inline)){const n=wv(e,"fontSize");Cv(o,(t=>n(t)&&e.isEditable(t)),Ev(e,"fontSize",""));const r=Y(e.select("sup"===t.inline?"sub":"sup",o),e.isEditable);e.remove(r,!0)}})(o,s,0,a),yv(e,s,0,a)):o.remove(a,!0)}))},g=Cm(o)?o:l.getNode();if("false"===i.getContentEditable(g)&&!Rm(e,g))return c(r,o=g),void ff(e,t,o,n);if(s){if(o)if(Cm(o)){if(!c(r,o)){const e=i.createRng();e.setStartBefore(o),e.setEndAfter(o),f(i,nf(i,e,r),!0)}}else f(i,o,!0);else a&&Fm(s)&&!um(e).length?((e,t,n)=>{let o;const r=e.selection,s=e.formatter.get(t);if(!s)return;const a=r.getRng();let i=a.startOffset;const l=a.startContainer.nodeValue;o=Wu(e.getBody(),r.getStart());const d=/[^\s\u00a0\u00ad\u200b\ufeff]/;if(l&&i>0&&i<l.length&&d.test(l.charAt(i))&&d.test(l.charAt(i-1))){const o=r.getBookmark();a.collapse(!0);let i=nf(e.dom,a,s);i=Xf(i),e.formatter.apply(t,n,i),r.moveToBookmark(o)}else{let s=o?Zb(o):null;o&&(null==s?void 0:s.data)===Xb||(c=e.getDoc(),u=Qb(!0).dom,o=c.importNode(u,!0),s=o.firstChild,a.insertNode(o),i=1),e.formatter.apply(t,n,o),r.setCursorLocation(s,i)}var c,u})(e,t,n):(l.setRng(Tb(l.getRng())),Em(e,(()=>{vm(e,((e,t)=>{const n=t?e:nf(i,e,r);f(i,n,!1)}))}),M),e.nodeChanged()),cv(e.formatter,t).each((t=>{q((e=>Y((e=>{const t=e.getSelectedBlocks(),n=e.getRng();if(e.isCollapsed())return[];if(1===t.length)return uv(n,t[0])&&mv(n,t[0])?t:[];{const e=le(t).filter((e=>uv(n,e))).toArray(),o=de(t).filter((e=>mv(n,e))).toArray(),r=t.slice(1,-1);return e.concat(r).concat(o)}})(e),fv(e.dom)))(e.selection),(e=>Hv(i,e,t,n)))}));((e,t)=>{ke(iv,e)&&q(iv[e],(e=>{e(t)}))})(t,e)}ff(e,t,o,n)},Vv=(e,t,n,o)=>{(o||e.selection.isEditable())&&$v(e,t,n,o)},qv=e=>ke(e,"vars"),Wv=e=>e.selection.getStart(),Kv=(e,t,n,o,r)=>Z(t,(t=>{const s=e.formatter.matchNode(t,n,null!=r?r:{},o);return!v(s)}),(t=>!!Vb(e,t,n)||!o&&C(e.formatter.matchNode(t,n,r,!0)))),Yv=(e,t)=>{const n=null!=t?t:Wv(e);return Y(Dm(e.dom,n),(e=>er(e)&&!sr(e)))},Gv=(e,t,n)=>{const o=Yv(e,t);pe(n,((n,r)=>{const s=n=>{const s=Kv(e,o,r,n.similar,qv(n)?n.vars:void 0),a=s.isSome();if(n.state.get()!==a){n.state.set(a);const e=s.getOr(t);qv(n)?n.callback(a,{node:e,format:r,parents:o}):q(n.callbacks,(t=>t(a,{node:e,format:r,parents:o})))}};q([n.withSimilar,n.withoutSimilar],s),q(n.withVars,s)}))},Xv=Dt.explode,Zv=()=>{const e={};return{addFilter:(t,n)=>{q(Xv(t),(t=>{ke(e,t)||(e[t]={name:t,callbacks:[]}),e[t].callbacks.push(n)}))},getFilters:()=>Ee(e),removeFilter:(t,n)=>{q(Xv(t),(t=>{if(ke(e,t))if(C(n)){const o=e[t],r=Y(o.callbacks,(e=>e!==n));r.length>0?o.callbacks=r:delete e[t]}else delete e[t]}))}}},Qv=(e,t,n)=>{var o;const r=Ks();t.convert_fonts_to_spans&&((e,t,n)=>{e.addNodeFilter("font",(e=>{q(e,(e=>{const o=t.parse(e.attr("style")),r=e.attr("color"),s=e.attr("face"),a=e.attr("size");r&&(o.color=r),s&&(o["font-family"]=s),a&&Ze(a).each((e=>{o["font-size"]=n[e-1]})),e.name="span",e.attr("style",t.serialize(o)),((e,t)=>{q(["color","face","size"],(t=>{e.attr(t,null)}))})(e)}))}))})(e,r,Dt.explode(null!==(o=t.font_size_legacy_values)&&void 0!==o?o:"")),((e,t,n)=>{e.addNodeFilter("strike",(e=>{const o="html4"!==t.type;q(e,(e=>{if(o)e.name="s";else{const t=n.parse(e.attr("style"));t["text-decoration"]="line-through",e.name="span",e.attr("style",n.serialize(t))}}))}))})(e,n,r)},Jv=e=>{const[t,...n]=e.split(","),o=n.join(","),r=/data:([^/]+\/[^;]+)(;.+)?/.exec(t);if(r){const e=";base64"===r[2],t=e?(e=>{const t=/([a-z0-9+\/=\s]+)/i.exec(e);return t?t[1]:""})(o):decodeURIComponent(o);return I.some({type:r[1],data:t,base64Encoded:e})}return I.none()},ey=(e,t,n=!0)=>{let o=t;if(n)try{o=atob(t)}catch(e){return I.none()}const r=new Uint8Array(o.length);for(let e=0;e<r.length;e++)r[e]=o.charCodeAt(e);return I.some(new Blob([r],{type:e}))},ty=e=>new Promise(((t,n)=>{const o=new FileReader;o.onloadend=()=>{t(o.result)},o.onerror=()=>{var e;n(null===(e=o.error)||void 0===e?void 0:e.message)},o.readAsDataURL(e)}));let ny=0;const oy=(e,t,n)=>Jv(e).bind((({data:e,type:o,base64Encoded:r})=>{if(t&&!r)return I.none();{const t=r?e:btoa(e);return n(t,o)}})),ry=(e,t,n)=>{const o=e.create("blobid"+ny++,t,n);return e.add(o),o},sy=(e,t,n=!1)=>oy(t,n,((t,n)=>I.from(e.getByData(t,n)).orThunk((()=>ey(n,t).map((n=>ry(e,n,t))))))),ay=/^(?:(?:(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)([A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*))(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+)?)?)$/,iy=e=>I.from(e.match(ay)).bind((e=>ie(e,1))).map((e=>$e(e,"www.")?e.substring(4):e)),ly=(e,t)=>{I.from(e.attr("src")).bind(iy).forall((e=>!H(t,e)))&&e.attr("sandbox","")},dy=(e,t)=>$e(e,`${t}/`),{entries:cy,setPrototypeOf:uy,isFrozen:my,getPrototypeOf:fy,getOwnPropertyDescriptor:gy}=Object;let{freeze:py,seal:hy,create:by}=Object,{apply:vy,construct:yy}="undefined"!=typeof Reflect&&Reflect;vy||(vy=function(e,t,n){return e.apply(t,n)}),py||(py=function(e){return e}),hy||(hy=function(e){return e}),yy||(yy=function(e,t){return new e(...t)});const Cy=By(Array.prototype.forEach),wy=By(Array.prototype.pop),Ey=By(Array.prototype.push),xy=By(String.prototype.toLowerCase),ky=By(String.prototype.toString),_y=By(String.prototype.match),Sy=By(String.prototype.replace),Ny=By(String.prototype.indexOf),Ry=By(String.prototype.trim),Ay=By(RegExp.prototype.test),Ty=(Oy=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return yy(Oy,t)});var Oy;function By(e){return function(t){for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return vy(e,t,o)}}function Py(e,t,n){var o;n=null!==(o=n)&&void 0!==o?o:xy,uy&&uy(e,null);let r=t.length;for(;r--;){let o=t[r];if("string"==typeof o){const e=n(o);e!==o&&(my(t)||(t[r]=e),o=e)}e[o]=!0}return e}function Dy(e){const t=by(null);for(const[n,o]of cy(e))t[n]=o;return t}function Ly(e,t){for(;null!==e;){const n=gy(e,t);if(n){if(n.get)return By(n.get);if("function"==typeof n.value)return By(n.value)}e=fy(e)}return function(e){return console.warn("fallback value for",e),null}}const My=py(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),Iy=py(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),Fy=py(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),Uy=py(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),zy=py(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),jy=py(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Hy=py(["#text"]),$y=py(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","xmlns","slot"]),Vy=py(["accent-height","accumulate","additive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),qy=py(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),Wy=py(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),Ky=hy(/\{\{[\w\W]*|[\w\W]*\}\}/gm),Yy=hy(/<%[\w\W]*|[\w\W]*%>/gm),Gy=hy(/\${[\w\W]*}/gm),Xy=hy(/^data-[\-\w.\u00B7-\uFFFF]/),Zy=hy(/^aria-[\-\w]+$/),Qy=hy(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Jy=hy(/^(?:\w+script|data):/i),eC=hy(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),tC=hy(/^html$/i);var nC=Object.freeze({__proto__:null,MUSTACHE_EXPR:Ky,ERB_EXPR:Yy,TMPLIT_EXPR:Gy,DATA_ATTR:Xy,ARIA_ATTR:Zy,IS_ALLOWED_URI:Qy,IS_SCRIPT_OR_DATA:Jy,ATTR_WHITESPACE:eC,DOCTYPE_NAME:tC});const oC=()=>"undefined"==typeof window?null:window;var rC=function e(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:oC();const n=t=>e(t);if(n.version="3.0.5",n.removed=[],!t||!t.document||9!==t.document.nodeType)return n.isSupported=!1,n;const o=t.document,r=o.currentScript;let{document:s}=t;const{DocumentFragment:a,HTMLTemplateElement:i,Node:l,Element:d,NodeFilter:c,NamedNodeMap:u=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:m,DOMParser:f,trustedTypes:g}=t,p=d.prototype,h=Ly(p,"cloneNode"),b=Ly(p,"nextSibling"),v=Ly(p,"childNodes"),y=Ly(p,"parentNode");if("function"==typeof i){const e=s.createElement("template");e.content&&e.content.ownerDocument&&(s=e.content.ownerDocument)}let C,w="";const{implementation:E,createNodeIterator:x,createDocumentFragment:k,getElementsByTagName:_}=s,{importNode:S}=o;let N={};n.isSupported="function"==typeof cy&&"function"==typeof y&&E&&void 0!==E.createHTMLDocument;const{MUSTACHE_EXPR:R,ERB_EXPR:A,TMPLIT_EXPR:T,DATA_ATTR:O,ARIA_ATTR:B,IS_SCRIPT_OR_DATA:P,ATTR_WHITESPACE:D}=nC;let{IS_ALLOWED_URI:L}=nC,M=null;const I=Py({},[...My,...Iy,...Fy,...zy,...Hy]);let F=null;const U=Py({},[...$y,...Vy,...qy,...Wy]);let z=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),j=null,H=null,$=!0,V=!0,q=!1,W=!0,K=!1,Y=!1,G=!1,X=!1,Z=!1,Q=!1,J=!1,ee=!0,te=!1,ne=!0,oe=!1,re={},se=null;const ae=Py({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let ie=null;const le=Py({},["audio","video","img","source","image","track"]);let de=null;const ce=Py({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ue="http://www.w3.org/1998/Math/MathML",me="http://www.w3.org/2000/svg",fe="http://www.w3.org/1999/xhtml";let ge=fe,pe=!1,he=null;const be=Py({},[ue,me,fe],ky);let ve;const ye=["application/xhtml+xml","text/html"];let Ce,we=null;const Ee=s.createElement("form"),xe=function(e){return e instanceof RegExp||e instanceof Function},ke=function(e){if(!we||we!==e){if(e&&"object"==typeof e||(e={}),e=Dy(e),ve=ve=-1===ye.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,Ce="application/xhtml+xml"===ve?ky:xy,M="ALLOWED_TAGS"in e?Py({},e.ALLOWED_TAGS,Ce):I,F="ALLOWED_ATTR"in e?Py({},e.ALLOWED_ATTR,Ce):U,he="ALLOWED_NAMESPACES"in e?Py({},e.ALLOWED_NAMESPACES,ky):be,de="ADD_URI_SAFE_ATTR"in e?Py(Dy(ce),e.ADD_URI_SAFE_ATTR,Ce):ce,ie="ADD_DATA_URI_TAGS"in e?Py(Dy(le),e.ADD_DATA_URI_TAGS,Ce):le,se="FORBID_CONTENTS"in e?Py({},e.FORBID_CONTENTS,Ce):ae,j="FORBID_TAGS"in e?Py({},e.FORBID_TAGS,Ce):{},H="FORBID_ATTR"in e?Py({},e.FORBID_ATTR,Ce):{},re="USE_PROFILES"in e&&e.USE_PROFILES,$=!1!==e.ALLOW_ARIA_ATTR,V=!1!==e.ALLOW_DATA_ATTR,q=e.ALLOW_UNKNOWN_PROTOCOLS||!1,W=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,K=e.SAFE_FOR_TEMPLATES||!1,Y=e.WHOLE_DOCUMENT||!1,Z=e.RETURN_DOM||!1,Q=e.RETURN_DOM_FRAGMENT||!1,J=e.RETURN_TRUSTED_TYPE||!1,X=e.FORCE_BODY||!1,ee=!1!==e.SANITIZE_DOM,te=e.SANITIZE_NAMED_PROPS||!1,ne=!1!==e.KEEP_CONTENT,oe=e.IN_PLACE||!1,L=e.ALLOWED_URI_REGEXP||Qy,ge=e.NAMESPACE||fe,z=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&xe(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(z.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&xe(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(z.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(z.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),K&&(V=!1),Q&&(Z=!0),re&&(M=Py({},[...Hy]),F=[],!0===re.html&&(Py(M,My),Py(F,$y)),!0===re.svg&&(Py(M,Iy),Py(F,Vy),Py(F,Wy)),!0===re.svgFilters&&(Py(M,Fy),Py(F,Vy),Py(F,Wy)),!0===re.mathMl&&(Py(M,zy),Py(F,qy),Py(F,Wy))),e.ADD_TAGS&&(M===I&&(M=Dy(M)),Py(M,e.ADD_TAGS,Ce)),e.ADD_ATTR&&(F===U&&(F=Dy(F)),Py(F,e.ADD_ATTR,Ce)),e.ADD_URI_SAFE_ATTR&&Py(de,e.ADD_URI_SAFE_ATTR,Ce),e.FORBID_CONTENTS&&(se===ae&&(se=Dy(se)),Py(se,e.FORBID_CONTENTS,Ce)),ne&&(M["#text"]=!0),Y&&Py(M,["html","head","body"]),M.table&&(Py(M,["tbody"]),delete j.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw Ty('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw Ty('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');C=e.TRUSTED_TYPES_POLICY,w=C.createHTML("")}else void 0===C&&(C=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(g,r)),null!==C&&"string"==typeof w&&(w=C.createHTML(""));py&&py(e),we=e}},_e=Py({},["mi","mo","mn","ms","mtext"]),Se=Py({},["foreignobject","desc","title","annotation-xml"]),Ne=Py({},["title","style","font","a","script"]),Re=Py({},Iy);Py(Re,Fy),Py(Re,Uy);const Ae=Py({},zy);Py(Ae,jy);const Te=function(e){Ey(n.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){e.remove()}},Oe=function(e,t){try{Ey(n.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){Ey(n.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!F[e])if(Z||Q)try{Te(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Be=function(e){let t,n;if(X)e="<remove></remove>"+e;else{const t=_y(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===ve&&ge===fe&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=C?C.createHTML(e):e;if(ge===fe)try{t=(new f).parseFromString(o,ve)}catch(e){}if(!t||!t.documentElement){t=E.createDocument(ge,"template",null);try{t.documentElement.innerHTML=pe?w:o}catch(e){}}const r=t.body||t.documentElement;return e&&n&&r.insertBefore(s.createTextNode(n),r.childNodes[0]||null),ge===fe?_.call(t,Y?"html":"body")[0]:Y?t.documentElement:r},Pe=function(e){return x.call(e.ownerDocument||e,e,c.SHOW_ELEMENT|c.SHOW_COMMENT|c.SHOW_TEXT,null,!1)},De=function(e){return"object"==typeof l?e instanceof l:e&&"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},Le=function(e,t,o){N[e]&&Cy(N[e],(e=>{e.call(n,t,o,we)}))},Me=function(e){let t;if(Le("beforeSanitizeElements",e,null),(o=e)instanceof m&&("string"!=typeof o.nodeName||"string"!=typeof o.textContent||"function"!=typeof o.removeChild||!(o.attributes instanceof u)||"function"!=typeof o.removeAttribute||"function"!=typeof o.setAttribute||"string"!=typeof o.namespaceURI||"function"!=typeof o.insertBefore||"function"!=typeof o.hasChildNodes))return Te(e),!0;var o;const r=Ce(e.nodeName);if(Le("uponSanitizeElement",e,{tagName:r,allowedTags:M}),e.hasChildNodes()&&!De(e.firstElementChild)&&(!De(e.content)||!De(e.content.firstElementChild))&&Ay(/<[/\w]/g,e.innerHTML)&&Ay(/<[/\w]/g,e.textContent))return Te(e),!0;if(!M[r]||j[r]){if(!j[r]&&Fe(r)){if(z.tagNameCheck instanceof RegExp&&Ay(z.tagNameCheck,r))return!1;if(z.tagNameCheck instanceof Function&&z.tagNameCheck(r))return!1}if(ne&&!se[r]){const t=y(e)||e.parentNode,n=v(e)||e.childNodes;if(n&&t)for(let o=n.length-1;o>=0;--o)t.insertBefore(h(n[o],!0),b(e))}return Te(e),!0}return e instanceof d&&!function(e){let t=y(e);t&&t.tagName||(t={namespaceURI:ge,tagName:"template"});const n=xy(e.tagName),o=xy(t.tagName);return!!he[e.namespaceURI]&&(e.namespaceURI===me?t.namespaceURI===fe?"svg"===n:t.namespaceURI===ue?"svg"===n&&("annotation-xml"===o||_e[o]):Boolean(Re[n]):e.namespaceURI===ue?t.namespaceURI===fe?"math"===n:t.namespaceURI===me?"math"===n&&Se[o]:Boolean(Ae[n]):e.namespaceURI===fe?!(t.namespaceURI===me&&!Se[o])&&!(t.namespaceURI===ue&&!_e[o])&&!Ae[n]&&(Ne[n]||!Re[n]):!("application/xhtml+xml"!==ve||!he[e.namespaceURI]))}(e)?(Te(e),!0):"noscript"!==r&&"noembed"!==r&&"noframes"!==r||!Ay(/<\/no(script|embed|frames)/i,e.innerHTML)?(K&&3===e.nodeType&&(t=e.textContent,t=Sy(t,R," "),t=Sy(t,A," "),t=Sy(t,T," "),e.textContent!==t&&(Ey(n.removed,{element:e.cloneNode()}),e.textContent=t)),Le("afterSanitizeElements",e,null),!1):(Te(e),!0)},Ie=function(e,t,n){if(ee&&("id"===t||"name"===t)&&(n in s||n in Ee))return!1;if(V&&!H[t]&&Ay(O,t));else if($&&Ay(B,t));else if(!F[t]||H[t]){if(!(Fe(e)&&(z.tagNameCheck instanceof RegExp&&Ay(z.tagNameCheck,e)||z.tagNameCheck instanceof Function&&z.tagNameCheck(e))&&(z.attributeNameCheck instanceof RegExp&&Ay(z.attributeNameCheck,t)||z.attributeNameCheck instanceof Function&&z.attributeNameCheck(t))||"is"===t&&z.allowCustomizedBuiltInElements&&(z.tagNameCheck instanceof RegExp&&Ay(z.tagNameCheck,n)||z.tagNameCheck instanceof Function&&z.tagNameCheck(n))))return!1}else if(de[t]);else if(Ay(L,Sy(n,D,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==Ny(n,"data:")||!ie[e])if(q&&!Ay(P,Sy(n,D,"")));else if(n)return!1;return!0},Fe=function(e){return e.indexOf("-")>0},Ue=function(e){let t,n,o,r;Le("beforeSanitizeAttributes",e,null);const{attributes:s}=e;if(!s)return;const a={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:F};for(r=s.length;r--;){t=s[r];const{name:i,namespaceURI:l}=t;n="value"===i?t.value:Ry(t.value);const d=n;if(o=Ce(i),a.attrName=o,a.attrValue=n,a.keepAttr=!0,a.forceKeepAttr=void 0,Le("uponSanitizeAttribute",e,a),n=a.attrValue,a.forceKeepAttr)continue;if(!a.keepAttr){Oe(i,e);continue}if(!W&&Ay(/\/>/i,n)){Oe(i,e);continue}K&&(n=Sy(n,R," "),n=Sy(n,A," "),n=Sy(n,T," "));const c=Ce(e.nodeName);if(Ie(c,o,n)){if(!te||"id"!==o&&"name"!==o||(Oe(i,e),n="user-content-"+n),C&&"object"==typeof g&&"function"==typeof g.getAttributeType)if(l);else switch(g.getAttributeType(c,o)){case"TrustedHTML":n=C.createHTML(n);break;case"TrustedScriptURL":n=C.createScriptURL(n)}if(n!==d)try{l?e.setAttributeNS(l,i,n):e.setAttribute(i,n)}catch(t){Oe(i,e)}}else Oe(i,e)}Le("afterSanitizeAttributes",e,null)},ze=function e(t){let n;const o=Pe(t);for(Le("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)Le("uponSanitizeShadowNode",n,null),Me(n)||(n.content instanceof a&&e(n.content),Ue(n));Le("afterSanitizeShadowDOM",t,null)};return n.sanitize=function(e){let t,r,s,i,d=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(pe=!e,pe&&(e="\x3c!--\x3e"),"string"!=typeof e&&!De(e)){if("function"!=typeof e.toString)throw Ty("toString is not a function");if("string"!=typeof(e=e.toString()))throw Ty("dirty is not a string, aborting")}if(!n.isSupported)return e;if(G||ke(d),n.removed=[],"string"==typeof e&&(oe=!1),oe){if(e.nodeName){const t=Ce(e.nodeName);if(!M[t]||j[t])throw Ty("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof l)t=Be("\x3c!----\x3e"),r=t.ownerDocument.importNode(e,!0),1===r.nodeType&&"BODY"===r.nodeName||"HTML"===r.nodeName?t=r:t.appendChild(r);else{if(!Z&&!K&&!Y&&-1===e.indexOf("<"))return C&&J?C.createHTML(e):e;if(t=Be(e),!t)return Z?null:J?w:""}t&&X&&Te(t.firstChild);const c=Pe(oe?e:t);for(;s=c.nextNode();)Me(s)||(s.content instanceof a&&ze(s.content),Ue(s));if(oe)return e;if(Z){if(Q)for(i=k.call(t.ownerDocument);t.firstChild;)i.appendChild(t.firstChild);else i=t;return(F.shadowroot||F.shadowrootmode)&&(i=S.call(o,i,!0)),i}let u=Y?t.outerHTML:t.innerHTML;return Y&&M["!doctype"]&&t.ownerDocument&&t.ownerDocument.doctype&&t.ownerDocument.doctype.name&&Ay(tC,t.ownerDocument.doctype.name)&&(u="<!DOCTYPE "+t.ownerDocument.doctype.name+">\n"+u),K&&(u=Sy(u,R," "),u=Sy(u,A," "),u=Sy(u,T," ")),C&&J?C.createHTML(u):u},n.setConfig=function(e){ke(e),G=!0},n.clearConfig=function(){we=null,G=!1},n.isValidAttribute=function(e,t,n){we||ke({});const o=Ce(e),r=Ce(t);return Ie(o,r,n)},n.addHook=function(e,t){"function"==typeof t&&(N[e]=N[e]||[],Ey(N[e],t))},n.removeHook=function(e){if(N[e])return wy(N[e])},n.removeHooks=function(e){N[e]&&(N[e]=[])},n.removeAllHooks=function(){N={}},n}();const sC=Dt.each,aC=Dt.trim,iC=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],lC={ftp:21,http:80,https:443,mailto:25},dC=["img","video"],cC=(e,t,n)=>{const o=(e=>{try{return decodeURIComponent(e)}catch(t){return unescape(e)}})(t).replace(/\s/g,"");return!e.allow_script_urls&&(!!/((java|vb)script|mhtml):/i.test(o)||!e.allow_html_data_urls&&(/^data:image\//i.test(o)?((e,t)=>C(e)?!e:!C(t)||!H(dC,t))(e.allow_svg_data_urls,n)&&/^data:image\/svg\+xml/i.test(o):/^data:/i.test(o)))};class uC{static parseDataUri(e){let t;const n=decodeURIComponent(e).split(","),o=/data:([^;]+)/.exec(n[0]);return o&&(t=o[1]),{type:t,data:n[1]}}static isDomSafe(e,t,n={}){if(n.allow_script_urls)return!0;{const o=ws.decode(e).replace(/[\s\u0000-\u001F]+/g,"");return!cC(n,o,t)}}static getDocumentBaseUrl(e){var t;let n;return n=0!==e.protocol.indexOf("http")&&"file:"!==e.protocol?null!==(t=e.href)&&void 0!==t?t:"":e.protocol+"//"+e.host+e.pathname,/^[^:]+:\/\/\/?[^\/]+\//.test(n)&&(n=n.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(n)||(n+="/")),n}constructor(e,t={}){this.path="",this.directory="",e=aC(e),this.settings=t;const n=t.base_uri,o=this;if(/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e))return void(o.source=e);const r=0===e.indexOf("//");if(0!==e.indexOf("/")||r||(e=(n&&n.protocol||"http")+"://mce_host"+e),!/^[\w\-]*:?\/\//.test(e)){const t=n?n.path:new uC(document.location.href).directory;if(""===(null==n?void 0:n.protocol))e="//mce_host"+o.toAbsPath(t,e);else{const r=/([^#?]*)([#?]?.*)/.exec(e);r&&(e=(n&&n.protocol||"http")+"://mce_host"+o.toAbsPath(t,r[1])+r[2])}}e=e.replace(/@@/g,"(mce_at)");const s=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e);s&&sC(iC,((e,t)=>{let n=s[t];n&&(n=n.replace(/\(mce_at\)/g,"@@")),o[e]=n})),n&&(o.protocol||(o.protocol=n.protocol),o.userInfo||(o.userInfo=n.userInfo),o.port||"mce_host"!==o.host||(o.port=n.port),o.host&&"mce_host"!==o.host||(o.host=n.host),o.source=""),r&&(o.protocol="")}setPath(e){const t=/^(.*?)\/?(\w+)?$/.exec(e);t&&(this.path=t[0],this.directory=t[1],this.file=t[2]),this.source="",this.getURI()}toRelative(e){if("./"===e)return e;const t=new uC(e,{base_uri:this});if("mce_host"!==t.host&&this.host!==t.host&&t.host||this.port!==t.port||this.protocol!==t.protocol&&""!==t.protocol)return t.getURI();const n=this.getURI(),o=t.getURI();if(n===o||"/"===n.charAt(n.length-1)&&n.substr(0,n.length-1)===o)return n;let r=this.toRelPath(this.path,t.path);return t.query&&(r+="?"+t.query),t.anchor&&(r+="#"+t.anchor),r}toAbsolute(e,t){const n=new uC(e,{base_uri:this});return n.getURI(t&&this.isSameOrigin(n))}isSameOrigin(e){if(this.host==e.host&&this.protocol==e.protocol){if(this.port==e.port)return!0;const t=this.protocol?lC[this.protocol]:null;if(t&&(this.port||t)==(e.port||t))return!0}return!1}toRelPath(e,t){let n,o,r=0,s="";const a=e.substring(0,e.lastIndexOf("/")).split("/"),i=t.split("/");if(a.length>=i.length)for(n=0,o=a.length;n<o;n++)if(n>=i.length||a[n]!==i[n]){r=n+1;break}if(a.length<i.length)for(n=0,o=i.length;n<o;n++)if(n>=a.length||a[n]!==i[n]){r=n+1;break}if(1===r)return t;for(n=0,o=a.length-(r-1);n<o;n++)s+="../";for(n=r-1,o=i.length;n<o;n++)s+=n!==r-1?"/"+i[n]:i[n];return s}toAbsPath(e,t){let n=0;const o=/\/$/.test(t)?"/":"",r=e.split("/"),s=t.split("/"),a=[];sC(r,(e=>{e&&a.push(e)}));const i=[];for(let e=s.length-1;e>=0;e--)0!==s[e].length&&"."!==s[e]&&(".."!==s[e]?n>0?n--:i.push(s[e]):n++);const l=a.length-n;let d;return d=l<=0?oe(i).join("/"):a.slice(0,l).join("/")+"/"+oe(i).join("/"),0!==d.indexOf("/")&&(d="/"+d),o&&d.lastIndexOf("/")!==d.length-1&&(d+=o),d}getURI(e=!1){let t;return this.source&&!e||(t="",e||(this.protocol?t+=this.protocol+"://":t+="//",this.userInfo&&(t+=this.userInfo+"@"),this.host&&(t+=this.host),this.port&&(t+=":"+this.port)),this.path&&(t+=this.path),this.query&&(t+="?"+this.query),this.anchor&&(t+="#"+this.anchor),this.source=t),this.source}}const mC=Dt.makeMap("src,href,data,background,action,formaction,poster,xlink:href"),fC="data-mce-type";let gC=0;const pC=(e,t,n,o,r)=>{var s,a,i,l;const d=t.validate,c=n.getSpecialElements();8===e.nodeType&&!t.allow_conditional_comments&&/^\[if/i.test(null!==(s=e.nodeValue)&&void 0!==s?s:"")&&(e.nodeValue=" "+e.nodeValue);const u=null!==(a=null==r?void 0:r.tagName)&&void 0!==a?a:e.nodeName.toLowerCase();if("html"!==o&&n.isValid(o))return void(C(r)&&(r.allowedTags[u]=!0));if(1!==e.nodeType||"body"===u)return;const f=Cn(e),g=on(f,fC),p=tn(f,"data-mce-bogus");if(!g&&m(p))return void("all"===p?xo(f):ko(f));const h=n.getElementRule(u);if(!d||h){if(C(r)&&(r.allowedTags[u]=!0),d&&h&&!g){if(q(null!==(i=h.attributesForced)&&void 0!==i?i:[],(e=>{Jt(f,e.name,"{$uid}"===e.value?"mce_"+gC++:e.value)})),q(null!==(l=h.attributesDefault)&&void 0!==l?l:[],(e=>{on(f,e.name)||Jt(f,e.name,"{$uid}"===e.value?"mce_"+gC++:e.value)})),h.attributesRequired&&!$(h.attributesRequired,(e=>on(f,e))))return void ko(f);if(h.removeEmptyAttrs&&(e=>{const t=e.dom.attributes;return null==t||0===t.length})(f))return void ko(f);h.outputName&&h.outputName!==u&&((e,t)=>{const n=((e,t)=>{const n=vn(t),o=sn(e);return en(n,o),n})(e,t);bo(e,n);const o=In(e);wo(n,o),xo(e)})(f,h.outputName)}}else ke(c,u)?xo(f):ko(f)},hC=(e,t,n,o,r,s)=>"html"!==n&&!Mr(o)||!(r in mC&&cC(e,s,o))&&(!e.validate||t.isValid(o,r)||$e(r,"data-")||$e(r,"aria-")),bC=(e,t)=>e.hasAttribute(fC)&&("id"===t||"class"===t||"style"===t),vC=(e,t)=>e in t.getBoolAttrs(),yC=(e,t,n,o)=>{const{attributes:r}=e;for(let s=r.length-1;s>=0;s--){const a=r[s],i=a.name,l=a.value;hC(t,n,o,e.tagName.toLowerCase(),i,l)||bC(e,i)?vC(i,n)&&e.setAttribute(i,i):e.removeAttribute(i)}},CC=(e,t,n)=>{const o=rC();return o.addHook("uponSanitizeElement",((o,r)=>{pC(o,e,t,n.track(o),r)})),o.addHook("uponSanitizeAttribute",((o,r)=>{((e,t,n,o,r)=>{const s=e.tagName.toLowerCase(),{attrName:a,attrValue:i}=r;r.keepAttr=hC(t,n,o,s,a,i),r.keepAttr?(r.allowedAttributes[a]=!0,vC(a,n)&&(r.attrValue=a),t.allow_svg_data_urls&&$e(i,"data:image/svg+xml")&&(r.forceKeepAttr=!0)):bC(e,a)&&(r.forceKeepAttr=!0)})(o,e,t,n.current(),r)})),o},wC=e=>{const t=Fr(e);if("svg"===t){const t=["type","href","role","arcrole","title","show","actuate","label","from","to"].map((e=>`xlink:${e}`)),n={IN_PLACE:!0,USE_PROFILES:{html:!0,svg:!0,svgFilters:!0},ALLOWED_ATTR:t};rC().sanitize(e,n)}else{if("math"!==t)throw new Error("Not a namespace element");{const t={IN_PLACE:!0,USE_PROFILES:{mathMl:!0}};rC().sanitize(e,t)}}},EC=Dt.makeMap,xC=Dt.extend,kC=(e,t,n,o)=>{const r=e.name,s=r in n&&"title"!==r&&"textarea"!==r&&"noscript"!==r,a=t.childNodes;for(let t=0,r=a.length;t<r;t++){const r=a[t],i=new Jg(r.nodeName.toLowerCase(),r.nodeType);if(er(r)){const e=r.attributes;for(let t=0,n=e.length;t<n;t++){const n=e[t];i.attr(n.name,n.value)}Mr(i.name)&&(o(r),i.value=r.innerHTML)}else dr(r)?(i.value=r.data,s&&(i.raw=!0)):(mr(r)||cr(r)||ur(r))&&(i.value=r.data);Mr(i.name)||kC(i,r,n,o),e.append(i)}},_C=(e={},t=Fs())=>{const n=Zv(),o=Zv(),r={validate:!0,root_name:"body",sanitize:!0,...e},s=new DOMParser,a=((e,t)=>{const n=(()=>{const e=Dr(),t=()=>e.get().map(Fr).getOr("html");return{track:n=>(Ir(n)?e.set(n):e.get().exists((e=>!e.contains(n)))&&e.clear(),t()),current:t,reset:()=>{e.clear()}}})();if(e.sanitize){const o=CC(e,t,n),r=(t,r)=>{o.sanitize(t,((e,t)=>{const n={IN_PLACE:!0,ALLOW_UNKNOWN_PROTOCOLS:!0,ALLOWED_TAGS:["#comment","#cdata-section","body"],ALLOWED_ATTR:[]};return n.PARSER_MEDIA_TYPE=t,e.allow_script_urls?n.ALLOWED_URI_REGEXP=/.*/:e.allow_html_data_urls&&(n.ALLOWED_URI_REGEXP=/^(?!(\w+script|mhtml):)/i),n})(e,r)),o.removed=[],n.reset()};return{sanitizeHtmlElement:r,sanitizeNamespaceElement:wC}}return{sanitizeHtmlElement:(o,r)=>{const s=document.createNodeIterator(o,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT|NodeFilter.SHOW_TEXT);let a;for(;a=s.nextNode();){const o=n.track(a);pC(a,e,t,o),er(a)&&yC(a,e,t,o)}n.reset()},sanitizeNamespaceElement:k}})(r,t),i=n.addFilter,l=n.getFilters,d=n.removeFilter,c=o.addFilter,u=o.getFilters,f=o.removeFilter,g=(e,n)=>{const o=m(n.attr(fC)),r=1===n.type&&!ke(e,n.name)&&!Jr(t,n)&&!Mr(n.name);return 3===n.type||r&&!o},p={schema:t,addAttributeFilter:c,getAttributeFilters:u,removeAttributeFilter:f,addNodeFilter:i,getNodeFilters:l,removeNodeFilter:d,parse:(e,n={})=>{var o;const i=r.validate,d=null!==(o=n.context)&&void 0!==o?o:r.root_name,c=((e,n,o="html")=>{const r="xhtml"===o?"application/xhtml+xml":"text/html",i=ke(t.getSpecialElements(),n.toLowerCase()),l=i?`<${n}>${e}</${n}>`:e,d="xhtml"===o?`<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${l}</body></html>`:`<body>${l}</body>`,c=s.parseFromString(d,r).body;return a.sanitizeHtmlElement(c,r),i?c.firstChild:c})(e,d,n.format);Wr(t,c);const m=new Jg(d,11);kC(m,c,t.getSpecialElements(),a.sanitizeNamespaceElement),c.innerHTML="";const[f,p]=((e,t,n,o)=>{const r=n.validate,s=t.getNonEmptyElements(),a=t.getWhitespaceElements(),i=xC(EC("script,style,head,html,body,title,meta,param"),t.getBlockElements()),l=Ms(t),d=/[ \t\r\n]+/g,c=/^[ \t\r\n]+/,u=/[ \t\r\n]+$/,m=e=>{let t=e.parent;for(;C(t);){if(t.name in a)return!0;t=t.parent}return!1},f=n=>n.name in i||Jr(t,n)||Mr(n.name)&&n.parent===e,g=(t,n)=>{const r=n?t.prev:t.next;return!C(r)&&!y(t.parent)&&f(t.parent)&&(t.parent!==e||!0===o.isRootContent)};return[e=>{var t;if(3===e.type&&!m(e)){let n=null!==(t=e.value)&&void 0!==t?t:"";n=n.replace(d," "),(((e,t)=>C(e)&&(t(e)||"br"===e.name))(e.prev,f)||g(e,!0))&&(n=n.replace(c,"")),0===n.length?e.remove():e.value=n}},e=>{var i;if(1===e.type){const i=t.getElementRule(e.name);if(r&&i){const r=_b(t,s,a,e);i.paddInEmptyBlock&&r&&(e=>{let n=e;for(;C(n);){if(n.name in l)return _b(t,s,a,n);n=n.parent}return!1})(e)?xb(n,o,f,e):i.removeEmpty&&r?f(e)?e.remove():e.unwrap():i.paddEmpty&&(r||(e=>{var t;return kb(e,"#text")&&(null===(t=null==e?void 0:e.firstChild)||void 0===t?void 0:t.value)===Wo})(e))&&xb(n,o,f,e)}}else if(3===e.type&&!m(e)){let t=null!==(i=e.value)&&void 0!==i?i:"";(e.next&&f(e.next)||g(e,!1))&&(t=t.replace(u,"")),0===t.length?e.remove():e.value=t}}]})(m,t,r,n),h=[],b=i?e=>((e,n)=>{Ab(t,e)&&n.push(e)})(e,h):k,v={nodes:{},attributes:{}},w=e=>Cb(l(),u(),e,v);if(((e,t,n)=>{const o=[];for(let n=e,r=n;n;r=n,n=n.walk()){const s=n;q(t,(e=>e(s))),y(s.parent)&&s!==e?n=r:o.push(s)}for(let e=o.length-1;e>=0;e--){const t=o[e];q(n,(e=>e(t)))}})(m,[f,w],[p,b]),h.reverse(),i&&h.length>0)if(n.context){const{pass:e,fail:o}=K(h,(e=>e.parent===m));Rb(o,t,m,w),n.invalid=e.length>0}else Rb(h,t,m,w);const E=((e,t)=>{var n;const o=null!==(n=t.forced_root_block)&&void 0!==n?n:e.forced_root_block;return!1===o?"":!0===o?"p":o})(r,n);return E&&("body"===m.name||n.isRootContent)&&((e,n)=>{const o=xC(EC("script,style,head,html,body,title,meta,param"),t.getBlockElements()),s=/^[ \t\r\n]+/,a=/[ \t\r\n]+$/;let i=e.firstChild,l=null;const d=e=>{var t,n;e&&(i=e.firstChild,i&&3===i.type&&(i.value=null===(t=i.value)||void 0===t?void 0:t.replace(s,"")),i=e.lastChild,i&&3===i.type&&(i.value=null===(n=i.value)||void 0===n?void 0:n.replace(a,"")))};if(t.isValidChild(e.name,n.toLowerCase())){for(;i;){const t=i.next;g(o,i)?(l||(l=new Jg(n,1),l.attr(r.forced_root_block_attrs),e.insert(l,i)),l.append(i)):(d(l),l=null),i=t}d(l)}})(m,E),n.invalid||wb(v,n),m}};return((e,t)=>{var n,o;const r=e.schema;e.addAttributeFilter("href",(e=>{let n=e.length;const o=e=>{const t=e?Dt.trim(e):"";return/\b(noopener)\b/g.test(t)?t:(e=>e.split(" ").filter((e=>e.length>0)).concat(["noopener"]).sort().join(" "))(t)};if(!t.allow_unsafe_link_target)for(;n--;){const t=e[n];"a"===t.name&&"_blank"===t.attr("target")&&t.attr("rel",o(t.attr("rel")))}})),t.allow_html_in_named_anchor||e.addAttributeFilter("id,name",(e=>{let t,n,o,r,s=e.length;for(;s--;)if(r=e[s],"a"===r.name&&r.firstChild&&!r.attr("href"))for(o=r.parent,t=r.lastChild;t&&o;)n=t.prev,o.insert(t,r),t=n})),t.fix_list_elements&&e.addNodeFilter("ul,ol",(e=>{let t,n,o=e.length;for(;o--;)if(t=e[o],n=t.parent,n&&("ul"===n.name||"ol"===n.name))if(t.prev&&"li"===t.prev.name)t.prev.append(t);else{const e=new Jg("li",1);e.attr("style","list-style-type: none"),t.wrap(e)}}));const s=r.getValidClasses();t.validate&&s&&e.addAttributeFilter("class",(e=>{var t;let n=e.length;for(;n--;){const o=e[n],r=null!==(t=o.attr("class"))&&void 0!==t?t:"",a=Dt.explode(r," ");let i="";for(let e=0;e<a.length;e++){const t=a[e];let n=!1,r=s["*"];r&&r[t]&&(n=!0),r=s[o.name],!n&&r&&r[t]&&(n=!0),n&&(i&&(i+=" "),i+=t)}i.length||(i=null),o.attr("class",i)}})),((e,t)=>{const{blob_cache:n}=t;if(n){const t=e=>{const t=e.attr("src");(e=>e.attr("src")===Tt.transparentSrc||C(e.attr("data-mce-placeholder")))(e)||(e=>C(e.attr("data-mce-bogus")))(e)||y(t)||sy(n,t,!0).each((t=>{e.attr("src",t.blobUri())}))};e.addAttributeFilter("src",(e=>q(e,t)))}})(e,t);const a=null!==(n=t.sandbox_iframes)&&void 0!==n&&n,i=me(null!==(o=t.sandbox_iframes_exclusions)&&void 0!==o?o:[]);t.convert_unsafe_embeds&&e.addNodeFilter("object,embed",(e=>q(e,(e=>{e.replace((({type:e,src:t,width:n,height:o}={},r,s)=>{const a=(e=>v(e)?"iframe":dy(e,"image")?"img":dy(e,"video")?"video":dy(e,"audio")?"audio":"iframe")(e),i=new Jg(a,1);return i.attr("audio"===a?{src:t}:{src:t,width:n,height:o}),"audio"!==a&&"video"!==a||i.attr("controls",""),"iframe"===a&&r&&ly(i,s),i})({type:e.attr("type"),src:"object"===e.name?e.attr("data"):e.attr("src"),width:e.attr("width"),height:e.attr("height")},a,i))})))),a&&e.addNodeFilter("iframe",(e=>q(e,(e=>ly(e,i)))))})(p,r),((e,t,n)=>{t.inline_styles&&Qv(e,t,n)})(p,r,t),p},SC=(e,t,n)=>{const o=(e=>Ub(e)?vp({validate:!1}).serialize(e):e)(e),r=t(o);if(r.isDefaultPrevented())return r;if(Ub(e)){if(r.content!==o){const t=_C({validate:!1,forced_root_block:!1,...n}).parse(r.content,{context:e.name});return{...r,content:t}}return{...r,content:e}}return r},NC=e=>({sanitize:wc(e),sandbox_iframes:Nc(e),sandbox_iframes_exclusions:Rc(e)}),RC=(e,t)=>{if(t.no_events)return El.value(t);{const n=((e,t)=>e.dispatch("BeforeGetContent",t))(e,t);return n.isDefaultPrevented()?El.error(hf(e,{content:"",...n}).content):El.value(n)}},AC=(e,t,n)=>{if(n.no_events)return t;{const o=SC(t,(t=>hf(e,{...n,content:t})),NC(e));return o.content}},TC=(e,t)=>{if(t.no_events)return El.value(t);{const n=SC(t.content,(n=>((e,t)=>e.dispatch("BeforeSetContent",t))(e,{...t,content:n})),NC(e));return n.isDefaultPrevented()?(pf(e,n),El.error(void 0)):El.value(n)}},OC=(e,t,n)=>{n.no_events||pf(e,{...n,content:t})},BC=(e,t,n)=>({element:e,width:t,rows:n}),PC=(e,t)=>({element:e,cells:t}),DC=(e,t)=>({x:e,y:t}),LC=(e,t)=>nn(e,t).bind(Ze).getOr(1),MC=(e,t,n)=>{const o=e.rows;return!!(o[n]?o[n].cells:[])[t]},IC=e=>X(e,((e,t)=>t.cells.length>e?t.cells.length:e),0),FC=(e,t)=>{const n=e.rows;for(let e=0;e<n.length;e++){const o=n[e].cells;for(let n=0;n<o.length;n++)if(_n(o[n],t))return I.some(DC(n,e))}return I.none()},UC=(e,t,n,o,r)=>{const s=[],a=e.rows;for(let e=n;e<=r;e++){const n=a[e].cells,r=t<o?n.slice(t,o+1):n.slice(o,t+1);s.push(PC(a[e].element,r))}return s},zC=e=>((e,t)=>{const n=Ma(e.element),o=vn("tbody");return wo(o,t),yo(n,o),n})(e,(e=>V(e.rows,(e=>{const t=V(e.cells,(e=>{const t=Ia(e);return rn(t,"colspan"),rn(t,"rowspan"),t})),n=Ma(e.element);return wo(n,t),n})))(e)),jC=(e,t,n)=>{const o=Cn(t.commonAncestorContainer),r=zp(o,e),s=Y(r,(e=>n.isWrapper($t(e)))),a=((e,t)=>Q(e,(e=>"li"===$t(e)&&pm(e,t))).fold(N([]),(t=>(e=>Q(e,(e=>"ul"===$t(e)||"ol"===$t(e))))(e).map((e=>{const t=vn($t(e)),n=Ce(go(e),((e,t)=>$e(t,"list-style")));return co(t,n),[vn("li"),t]})).getOr([]))))(r,t),i=s.concat(a.length?a:(e=>Wa(e)?Tn(e).filter(qa).fold(N([]),(t=>[e,t])):qa(e)?[e]:[])(o));return V(i,Ma)},HC=()=>Ff([]),$C=(e,t)=>((e,t)=>to(t,"table",T(_n,e)))(e,t[0]).bind((e=>{const n=t[0],o=t[t.length-1],r=(e=>{const t=BC(Ma(e),0,[]);return q(zo(e,"tr"),((e,n)=>{q(zo(e,"td,th"),((o,r)=>{((e,t,n,o,r)=>{const s=LC(r,"rowspan"),a=LC(r,"colspan"),i=e.rows;for(let e=n;e<n+s;e++){i[e]||(i[e]=PC(Ia(o),[]));for(let o=t;o<t+a;o++)i[e].cells[o]=e===n&&o===t?r:Ma(r)}})(t,((e,t,n)=>{for(;MC(e,t,n);)t++;return t})(t,r,n),n,e,o)}))})),BC(t.element,IC(t.rows),t.rows)})(e);return((e,t,n)=>FC(e,t).bind((t=>FC(e,n).map((n=>((e,t,n)=>{const o=t.x,r=t.y,s=n.x,a=n.y,i=r<a?UC(e,o,r,s,a):UC(e,o,a,s,r);return BC(e.element,IC(i),i)})(e,t,n))))))(r,n,o).map((e=>Ff([zC(e)])))})).getOrThunk(HC),VC=(e,t,n)=>{const o=cm(t,e);return o.length>0?$C(e,o):((e,t,n)=>t.length>0&&t[0].collapsed?HC():((e,t,n)=>((e,t)=>{const n=X(t,((e,t)=>(yo(t,e),t)),e);return t.length>0?Ff([n]):n})(Cn(t.cloneContents()),jC(e,t,n)))(e,t[0],n))(e,t,n)},qC=(e,t)=>t>=0&&t<e.length&&im(e.charAt(t)),WC=e=>ei(e.innerText),KC=e=>er(e)?e.outerHTML:dr(e)?ws.encodeRaw(e.data,!1):mr(e)?"\x3c!--"+e.data+"--\x3e":"",YC=(e,t)=>(((e,t)=>{let n=0;q(e,(e=>{0===e[0]?n++:1===e[0]?(((e,t,n)=>{const o=(e=>{let t;const n=document.createElement("div"),o=document.createDocumentFragment();for(e&&(n.innerHTML=e);t=n.firstChild;)o.appendChild(t);return o})(t);if(e.hasChildNodes()&&n<e.childNodes.length){const t=e.childNodes[n];e.insertBefore(o,t)}else e.appendChild(o)})(t,e[1],n),n++):2===e[0]&&((e,t)=>{if(e.hasChildNodes()&&t<e.childNodes.length){const n=e.childNodes[t];e.removeChild(n)}})(t,n)}))})(((e,t)=>{const n=e.length+t.length+2,o=new Array(n),r=new Array(n),s=(n,o,r,a,l)=>{const d=i(n,o,r,a);if(null===d||d.start===o&&d.diag===o-a||d.end===n&&d.diag===n-r){let s=n,i=r;for(;s<o||i<a;)s<o&&i<a&&e[s]===t[i]?(l.push([0,e[s]]),++s,++i):o-n>a-r?(l.push([2,e[s]]),++s):(l.push([1,t[i]]),++i)}else{s(n,d.start,r,d.start-d.diag,l);for(let t=d.start;t<d.end;++t)l.push([0,e[t]]);s(d.end,o,d.end-d.diag,a,l)}},a=(n,o,r,s)=>{let a=n;for(;a-o<s&&a<r&&e[a]===t[a-o];)++a;return((e,t,n)=>({start:e,end:t,diag:n}))(n,a,o)},i=(n,s,i,l)=>{const d=s-n,c=l-i;if(0===d||0===c)return null;const u=d-c,m=c+d,f=(m%2==0?m:m+1)/2;let g,p,h,b,v;for(o[1+f]=n,r[1+f]=s+1,g=0;g<=f;++g){for(p=-g;p<=g;p+=2){for(h=p+f,p===-g||p!==g&&o[h-1]<o[h+1]?o[h]=o[h+1]:o[h]=o[h-1]+1,b=o[h],v=b-n+i-p;b<s&&v<l&&e[b]===t[v];)o[h]=++b,++v;if(u%2!=0&&u-g<=p&&p<=u+g&&r[h-u]<=o[h])return a(r[h-u],p+n-i,s,l)}for(p=u-g;p<=u+g;p+=2){for(h=p+f-u,p===u-g||p!==u+g&&r[h+1]<=r[h-1]?r[h]=r[h+1]-1:r[h]=r[h-1],b=r[h]-1,v=b-n+i-p;b>=n&&v>=i&&e[b]===t[v];)r[h]=b--,v--;if(u%2==0&&-g<=p&&p<=g&&r[h]<=o[h+u])return a(r[h],p+n-i,s,l)}}return null},l=[];return s(0,e.length,0,t.length,l),l})(V(ce(t.childNodes),KC),e),t),t),GC=Le((()=>document.implementation.createHTMLDocument("undo"))),XC=e=>{const t=e.serializer.getTempAttrs(),n=mp(e.getBody(),t);return(e=>null!==e.querySelector("iframe"))(n)?{type:"fragmented",fragments:Y(V(ce(n.childNodes),_(ei,KC)),(e=>e.length>0)),content:"",bookmark:null,beforeBookmark:null}:{type:"complete",fragments:null,content:ei(n.innerHTML),bookmark:null,beforeBookmark:null}},ZC=(e,t,n)=>{const o=n?t.beforeBookmark:t.bookmark;"fragmented"===t.type?YC(t.fragments,e.getBody()):e.setContent(t.content,{format:"raw",no_selection:!C(o)||!Yu(o)||!o.isFakeCaret}),o&&(e.selection.moveToBookmark(o),e.selection.scrollIntoView())},QC=e=>"fragmented"===e.type?e.fragments.join(""):e.content,JC=e=>{const t=vn("body",GC());return No(t,QC(e)),q(zo(t,"*[data-mce-bogus]"),ko),So(t)},ew=(e,t)=>!(!e||!t)&&(!!((e,t)=>QC(e)===QC(t))(e,t)||((e,t)=>JC(e)===JC(t))(e,t)),tw=e=>0===e.get(),nw=(e,t,n)=>{tw(n)&&(e.typing=t)},ow=(e,t)=>{e.typing&&(nw(e,!1,t),e.add())},rw=e=>({init:{bindEvents:k},undoManager:{beforeChange:(t,n)=>((e,t,n)=>{tw(t)&&n.set(yl(e.selection))})(e,t,n),add:(t,n,o,r,s,a)=>((e,t,n,o,r,s,a)=>{const i=XC(e),l=Dt.extend(s||{},i);if(!tw(o)||e.removed)return null;const d=t.data[n.get()];if(e.dispatch("BeforeAddUndo",{level:l,lastLevel:d,originalEvent:a}).isDefaultPrevented())return null;if(d&&ew(d,l))return null;t.data[n.get()]&&r.get().each((e=>{t.data[n.get()].beforeBookmark=e}));const c=Fd(e);if(c&&t.data.length>c){for(let e=0;e<t.data.length-1;e++)t.data[e]=t.data[e+1];t.data.length--,n.set(t.data.length)}l.bookmark=yl(e.selection),n.get()<t.data.length-1&&(t.data.length=n.get()+1),t.data.push(l),n.set(t.data.length-1);const u={level:l,lastLevel:d,originalEvent:a};return n.get()>0?(e.setDirty(!0),e.dispatch("AddUndo",u),e.dispatch("change",u)):e.dispatch("AddUndo",u),l})(e,t,n,o,r,s,a),undo:(t,n,o)=>((e,t,n,o)=>{let r;return t.typing&&(t.add(),t.typing=!1,nw(t,!1,n)),o.get()>0&&(o.set(o.get()-1),r=t.data[o.get()],ZC(e,r,!0),e.setDirty(!0),e.dispatch("Undo",{level:r})),r})(e,t,n,o),redo:(t,n)=>((e,t,n)=>{let o;return t.get()<n.length-1&&(t.set(t.get()+1),o=n[t.get()],ZC(e,o,!1),e.setDirty(!0),e.dispatch("Redo",{level:o})),o})(e,t,n),clear:(t,n)=>((e,t,n)=>{t.data=[],n.set(0),t.typing=!1,e.dispatch("ClearUndos")})(e,t,n),reset:e=>(e=>{e.clear(),e.add()})(e),hasUndo:(t,n)=>((e,t,n)=>n.get()>0||t.typing&&t.data[0]&&!ew(XC(e),t.data[0]))(e,t,n),hasRedo:(e,t)=>((e,t)=>t.get()<e.data.length-1&&!e.typing)(e,t),transact:(e,t,n)=>((e,t,n)=>(ow(e,t),e.beforeChange(),e.ignore(n),e.add()))(e,t,n),ignore:(e,t)=>((e,t)=>{try{e.set(e.get()+1),t()}finally{e.set(e.get()-1)}})(e,t),extra:(t,n,o,r)=>((e,t,n,o,r)=>{if(t.transact(o)){const o=t.data[n.get()].bookmark,s=t.data[n.get()-1];ZC(e,s,!0),t.transact(r)&&(t.data[n.get()-1].beforeBookmark=o)}})(e,t,n,o,r)},formatter:{match:(t,n,o,r)=>Gb(e,t,n,o,r),matchAll:(t,n)=>((e,t,n)=>{const o=[],r={},s=e.selection.getStart();return e.dom.getParent(s,(s=>{for(let a=0;a<t.length;a++){const i=t[a];!r[i]&&Yb(e,s,i,n)&&(r[i]=!0,o.push(i))}}),e.dom.getRoot()),o})(e,t,n),matchNode:(t,n,o,r)=>Yb(e,t,n,o,r),canApply:t=>((e,t)=>{const n=e.formatter.get(t),o=e.dom;if(n&&e.selection.isEditable()){const t=e.selection.getStart(),r=Dm(o,t);for(let e=n.length-1;e>=0;e--){const t=n[e];if(!Im(t))return!0;for(let e=r.length-1;e>=0;e--)if(o.is(r[e],t.selector))return!0}}return!1})(e,t),closest:t=>((e,t)=>{const n=t=>_n(t,Cn(e.getBody()));return I.from(e.selection.getStart(!0)).bind((o=>Hb(Cn(o),(n=>ue(t,(t=>((t,n)=>Yb(e,t.dom,n)?I.some(n):I.none())(n,t)))),n))).getOrNull()})(e,t),apply:(t,n,o)=>Vv(e,t,n,o),remove:(t,n,o,r)=>Fv(e,t,n,o,r),toggle:(t,n,o)=>((e,t,n,o)=>{const r=e.formatter.get(t);r&&(!Gb(e,t,n,o)||"toggle"in r[0]&&!r[0].toggle?Vv(e,t,n,o):Fv(e,t,n,o))})(e,t,n,o),formatChanged:(t,n,o,r,s)=>((e,t,n,o,r,s)=>(((e,t,n,o,r,s)=>{const a=t.get();q(n.split(","),(t=>{const n=xe(a,t).getOrThunk((()=>{const e={withSimilar:{state:Br(!1),similar:!0,callbacks:[]},withoutSimilar:{state:Br(!1),similar:!1,callbacks:[]},withVars:[]};return a[t]=e,e})),i=()=>{const n=Yv(e);return Kv(e,n,t,r,s).isSome()};if(v(s)){const e=r?n.withSimilar:n.withoutSimilar;e.callbacks.push(o),1===e.callbacks.length&&e.state.set(i())}else n.withVars.push({state:Br(i()),similar:r,vars:s,callback:o})})),t.set(a)})(e,t,n,o,r,s),{unbind:()=>((e,t,n)=>{const o=e.get();q(t.split(","),(e=>xe(o,e).each((t=>{o[e]={withSimilar:{...t.withSimilar,callbacks:Y(t.withSimilar.callbacks,(e=>e!==n))},withoutSimilar:{...t.withoutSimilar,callbacks:Y(t.withoutSimilar.callbacks,(e=>e!==n))},withVars:Y(t.withVars,(e=>e.callback!==n))}})))),e.set(o)})(t,n,o)}))(e,t,n,o,r,s)},editor:{getContent:t=>((e,t)=>I.from(e.getBody()).fold(N("tree"===t.format?new Jg("body",11):""),(n=>pp(e,t,n))))(e,t),setContent:(t,n)=>((e,t,n)=>I.from(e.getBody()).map((o=>Ub(t)?((e,t,n,o)=>{Eb(e.parser.getNodeFilters(),e.parser.getAttributeFilters(),n);const r=vp({validate:!1},e.schema).serialize(n),s=ei(Ga(Cn(t))?r:Dt.trim(r));return zb(e,s,o.no_selection),{content:n,html:s}})(e,o,t,n):((e,t,n,o)=>{if(0===(n=ei(n)).length||/^\s+$/.test(n)){const r='<br data-mce-bogus="1">';"TABLE"===t.nodeName?n="<tr><td>"+r+"</td></tr>":/^(UL|OL)$/.test(t.nodeName)&&(n="<li>"+r+"</li>");const s=ql(e);return e.schema.isValidChild(t.nodeName.toLowerCase(),s.toLowerCase())?(n=r,n=e.dom.createHTML(s,Wl(e),n)):n||(n=r),zb(e,n,o.no_selection),{content:n,html:n}}{"raw"!==o.format&&(n=vp({validate:!1},e.schema).serialize(e.parser.parse(n,{isRootContent:!0,insert:!0})));const r=Ga(Cn(t))?n:Dt.trim(n);return zb(e,r,o.no_selection),{content:r,html:r}}})(e,o,t,n))).getOr({content:t,html:Ub(n.content)?"":n.content}))(e,t,n),insertContent:(t,n)=>Fb(e,t,n),addVisual:t=>((e,t)=>{const n=e.dom,o=C(t)?t:e.getBody();q(n.select("table,a",o),(t=>{switch(t.nodeName){case"TABLE":const o=Kd(e),r=n.getAttrib(t,"border");r&&"0"!==r||!e.hasVisual?n.removeClass(t,o):n.addClass(t,o);break;case"A":if(!n.getAttrib(t,"href")){const o=n.getAttrib(t,"name")||t.id,r=Yd(e);o&&e.hasVisual?n.addClass(t,r):n.removeClass(t,r)}}})),e.dispatch("VisualAid",{element:t,hasVisual:e.hasVisual})})(e,t)},selection:{getContent:(t,n)=>((e,t,n={})=>{const o=((e,t)=>({...e,format:t,get:!0,selection:!0,getInner:!0}))(n,t);return RC(e,o).fold(R,(t=>{const n=((e,t)=>{if("text"===t.format)return(e=>I.from(e.selection.getRng()).map((t=>{var n;const o=I.from(e.dom.getParent(t.commonAncestorContainer,e.dom.isBlock)),r=e.getBody(),s=(e=>e.map((e=>e.nodeName)).getOr("div").toLowerCase())(o),a=Cn(t.cloneContents());fp(a),gp(a);const i=e.dom.add(r,s,{"data-mce-bogus":"all",style:"overflow: hidden; opacity: 0;"},a.dom),l=WC(i),d=ei(null!==(n=i.textContent)&&void 0!==n?n:"");if(e.dom.remove(i),qC(d,0)||qC(d,d.length-1)){const e=o.getOr(r),t=WC(e),n=t.indexOf(l);return-1===n?l:(qC(t,n-1)?" ":"")+l+(qC(t,n+l.length)?" ":"")}return l})).getOr(""))(e);{const n=((e,t)=>{const n=e.selection.getRng(),o=e.dom.create("body"),r=e.selection.getSel(),s=Yg(e,dm(r)),a=t.contextual?VC(Cn(e.getBody()),s,e.schema).dom:n.cloneContents();return a&&o.appendChild(a),e.selection.serializer.serialize(o,t)})(e,t);return"tree"===t.format?n:e.selection.isCollapsed()?"":n}})(e,t);return AC(e,n,t)}))})(e,t,n)},autocompleter:{addDecoration:k,removeDecoration:k},raw:{getModel:()=>I.none()}}),sw=e=>ke(e.plugins,"rtc"),aw=e=>e.rtcInstance?e.rtcInstance:rw(e),iw=e=>{const t=e.rtcInstance;if(t)return t;throw new Error("Failed to get RTC instance not yet initialized.")},lw=e=>iw(e).init.bindEvents(),dw=e=>0===e.dom.length?(xo(e),I.none()):I.some(e),cw=(e,t,n,o,r)=>{e.bind((e=>((o?vh:bh)(e.dom,o?e.dom.length:0,r),t.filter(Yt).map((t=>((e,t,n,o,r)=>{const s=e.dom,a=t.dom,i=o?s.length:a.length;o?(yh(s,a,r,!1,!o),n.setStart(a,i)):(yh(a,s,r,!1,!o),n.setEnd(a,i))})(e,t,n,o,r)))))).orThunk((()=>{const e=((e,t)=>e.filter((e=>cf.isBookmarkNode(e.dom))).bind(t?Dn:Pn))(t,o).or(t).filter(Yt);return e.map((e=>((e,t,n)=>{Tn(e).each((o=>{const r=e.dom;t&&lh(o,Qi(r,0),n)?bh(r,0,n):!t&&dh(o,Qi(r,r.length),n)&&vh(r,r.length,n)}))})(e,o,r)))}))},uw=(e,t,n)=>{if(ke(e,t)){const o=Y(e[t],(e=>e!==n));0===o.length?delete e[t]:e[t]=o}};const mw=e=>!(!e||!e.ownerDocument)&&Sn(Cn(e.ownerDocument),Cn(e)),fw=(e,t,n,o)=>{let r,s;const{selectorChangedWithUnbind:a}=((e,t)=>{let n,o;const r=(t,n)=>Q(n,(n=>e.is(n,t))),s=t=>e.getParents(t,void 0,e.getRoot());return{selectorChangedWithUnbind:(e,a)=>(n||(n={},o={},t.on("NodeChange",(e=>{const t=e.element,a=s(t),i={};pe(n,((e,t)=>{r(t,a).each((n=>{o[t]||(q(e,(e=>{e(!0,{node:n,selector:t,parents:a})})),o[t]=e),i[t]=e}))})),pe(o,((e,n)=>{i[n]||(delete o[n],q(e,(e=>{e(!1,{node:t,selector:n,parents:a})})))}))}))),n[e]||(n[e]=[]),n[e].push(a),r(e,s(t.selection.getStart())).each((()=>{o[e]=n[e]})),{unbind:()=>{uw(n,e,a),uw(o,e,a)}})}})(e,o),i=(e,t)=>((e,t,n={})=>{const o=((e,t)=>({format:"html",...e,set:!0,selection:!0,content:t}))(n,t);TC(e,o).each((t=>{const n=((e,t)=>{if("raw"!==t.format){const n=e.selection.getRng(),o=e.dom.getParent(n.commonAncestorContainer,e.dom.isBlock),r=o?{context:o.nodeName.toLowerCase()}:{},s=e.parser.parse(t.content,{forced_root_block:!1,...r,...t});return vp({validate:!1},e.schema).serialize(s)}return t.content})(e,t),o=e.selection.getRng();((e,t,n)=>{const o=I.from(t.firstChild).map(Cn),r=I.from(t.lastChild).map(Cn);e.deleteContents(),e.insertNode(t);const s=o.bind(Pn).filter(Yt).bind(dw),a=r.bind(Dn).filter(Yt).bind(dw);cw(s,o,e,!0,n),cw(a,r,e,!1,n),e.collapse(!1)})(o,o.createContextualFragment(n),e.schema),e.selection.setRng(o),bg(e,o),OC(e,n,t)}))})(o,e,t),l=e=>{const t=c();t.collapse(!!e),u(t)},d=()=>t.getSelection?t.getSelection():t.document.selection,c=()=>{let n;const a=(e,t,n)=>{try{return t.compareBoundaryPoints(e,n)}catch(e){return-1}},i=t.document;if(C(o.bookmark)&&!zg(o)){const e=Rg(o);if(e.isSome())return e.map((e=>Yg(o,[e])[0])).getOr(i.createRange())}try{const e=d();e&&!Jo(e.anchorNode)&&(n=e.rangeCount>0?e.getRangeAt(0):i.createRange(),n=Yg(o,[n])[0])}catch(e){}if(n||(n=i.createRange()),fr(n.startContainer)&&n.collapsed){const t=e.getRoot();n.setStart(t,0),n.setEnd(t,0)}return r&&s&&(0===a(n.START_TO_START,n,r)&&0===a(n.END_TO_END,n,r)?n=s:(r=null,s=null)),n},u=(e,t)=>{if(!(e=>!!e&&mw(e.startContainer)&&mw(e.endContainer))(e))return;const n=d();if(e=o.dispatch("SetSelectionRange",{range:e,forward:t}).range,n){s=e;try{n.removeAllRanges(),n.addRange(e)}catch(e){}!1===t&&n.extend&&(n.collapse(e.endContainer,e.endOffset),n.extend(e.startContainer,e.startOffset)),r=n.rangeCount>0?n.getRangeAt(0):null}if(!e.collapsed&&e.startContainer===e.endContainer&&(null==n?void 0:n.setBaseAndExtent)&&e.endOffset-e.startOffset<2&&e.startContainer.hasChildNodes()){const t=e.startContainer.childNodes[e.startOffset];t&&"IMG"===t.nodeName&&(n.setBaseAndExtent(e.startContainer,e.startOffset,e.endContainer,e.endOffset),n.anchorNode===e.startContainer&&n.focusNode===e.endContainer||n.setBaseAndExtent(t,0,t,1))}o.dispatch("AfterSetSelectionRange",{range:e,forward:t})},m=()=>{const t=d(),n=null==t?void 0:t.anchorNode,o=null==t?void 0:t.focusNode;if(!t||!n||!o||Jo(n)||Jo(o))return!0;const r=e.createRng(),s=e.createRng();try{r.setStart(n,t.anchorOffset),r.collapse(!0),s.setStart(o,t.focusOffset),s.collapse(!0)}catch(e){return!0}return r.compareBoundaryPoints(r.START_TO_START,s)<=0},f={dom:e,win:t,serializer:n,editor:o,expand:(t={type:"word"})=>u(Zf(e).expand(c(),t)),collapse:l,setCursorLocation:(t,n)=>{const r=e.createRng();C(t)&&C(n)?(r.setStart(t,n),r.setEnd(t,n),u(r),l(!1)):(hm(e,r,o.getBody(),!0),u(r))},getContent:e=>((e,t={})=>((e,t,n)=>iw(e).selection.getContent(t,n))(e,t.format?t.format:"html",t))(o,e),setContent:i,getBookmark:(e,t)=>g.getBookmark(e,t),moveToBookmark:e=>g.moveToBookmark(e),select:(t,n)=>(((e,t,n)=>I.from(t).bind((t=>I.from(t.parentNode).map((o=>{const r=e.nodeIndex(t),s=e.createRng();return s.setStart(o,r),s.setEnd(o,r+1),n&&(hm(e,s,t,!0),hm(e,s,t,!1)),s})))))(e,t,n).each(u),t),isCollapsed:()=>{const e=c(),t=d();return!(!e||e.item)&&(e.compareEndPoints?0===e.compareEndPoints("StartToEnd",e):!t||e.collapsed)},isEditable:()=>{const t=c(),n=o.getBody().querySelectorAll('[data-mce-selected="1"]');return n.length>0?ne(n,(t=>e.isEditable(t.parentElement))):$g(e,t)},isForward:m,setNode:t=>(i(e.getOuterHTML(t)),t),getNode:()=>((e,t)=>{if(!t)return e;let n=t.startContainer,o=t.endContainer;const r=t.startOffset,s=t.endOffset;let a=t.commonAncestorContainer;t.collapsed||(n===o&&s-r<2&&n.hasChildNodes()&&(a=n.childNodes[r]),dr(n)&&dr(o)&&(n=n.length===r?Kg(n.nextSibling,!0):n.parentNode,o=0===s?Kg(o.previousSibling,!1):o.parentNode,n&&n===o&&(a=n)));const i=dr(a)?a.parentNode:a;return tr(i)?i:e})(o.getBody(),c()),getSel:d,setRng:u,getRng:c,getStart:e=>qg(o.getBody(),c(),e),getEnd:e=>Wg(o.getBody(),c(),e),getSelectedBlocks:(t,n)=>((e,t,n,o)=>{const r=[],s=e.getRoot(),a=e.getParent(n||qg(s,t,t.collapsed),e.isBlock),i=e.getParent(o||Wg(s,t,t.collapsed),e.isBlock);if(a&&a!==s&&r.push(a),a&&i&&a!==i){let t;const n=new Vo(a,s);for(;(t=n.next())&&t!==i;)e.isBlock(t)&&r.push(t)}return i&&a!==i&&i!==s&&r.push(i),r})(e,c(),t,n),normalize:()=>{const t=c(),n=d();if(!(dm(n).length>1)&&bm(o)){const n=Yf(e,t);return n.each((e=>{u(e,m())})),n.getOr(t)}return t},selectorChanged:(e,t)=>(a(e,t),f),selectorChangedWithUnbind:a,getScrollContainer:()=>{let t,n=e.getRoot();for(;n&&"BODY"!==n.nodeName;){if(n.scrollHeight>n.clientHeight){t=n;break}n=n.parentNode}return t},scrollIntoView:(e,t)=>{C(e)?((e,t,n)=>{(e.inline?gg:hg)(e,t,n)})(o,e,t):bg(o,c(),t)},placeCaretAt:(e,t)=>u(zf(e,t,o.getDoc())),getBoundingClientRect:()=>{const e=c();return e.collapsed?Qi.fromRangeStart(e).getClientRects()[0]:e.getBoundingClientRect()},destroy:()=>{t=r=s=null,p.destroy()}},g=cf(f),p=kf(f,o);return f.bookmarkManager=g,f.controlSelection=p,f},gw=(e,t,n)=>{-1===Dt.inArray(t,n)&&(e.addAttributeFilter(n,((e,t)=>{let n=e.length;for(;n--;)e[n].attr(t,null)})),t.push(n))},pw=(e,t)=>{const n=["data-mce-selected"],o={entity_encoding:"named",remove_trailing_brs:!0,pad_empty_with_br:!1,...e},r=t&&t.dom?t.dom:ma.DOM,s=t&&t.schema?t.schema:Fs(o),a=_C(o,s);return((e,t,n)=>{e.addAttributeFilter("data-mce-tabindex",((e,t)=>{let n=e.length;for(;n--;){const o=e[n];o.attr("tabindex",o.attr("data-mce-tabindex")),o.attr(t,null)}})),e.addAttributeFilter("src,href,style",((e,o)=>{const r="data-mce-"+o,s=t.url_converter,a=t.url_converter_scope;let i=e.length;for(;i--;){const t=e[i];let l=t.attr(r);void 0!==l?(t.attr(o,l.length>0?l:null),t.attr(r,null)):(l=t.attr(o),"style"===o?l=n.serializeStyle(n.parseStyle(l),t.name):s&&(l=s.call(a,l,o,t.name)),t.attr(o,l.length>0?l:null))}})),e.addAttributeFilter("class",(e=>{let t=e.length;for(;t--;){const n=e[t];let o=n.attr("class");o&&(o=o.replace(/(?:^|\s)mce-item-\w+(?!\S)/g,""),n.attr("class",o.length>0?o:null))}})),e.addAttributeFilter("data-mce-type",((e,t,n)=>{let o=e.length;for(;o--;){const t=e[o];if("bookmark"===t.attr("data-mce-type")&&!n.cleanup){const e=I.from(t.firstChild).exists((e=>{var t;return!Ja(null!==(t=e.value)&&void 0!==t?t:"")}));e?t.unwrap():t.remove()}}})),e.addNodeFilter("script,style",((e,n)=>{var o;const r=e=>e.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"");let s=e.length;for(;s--;){const a=e[s],i=a.firstChild,l=null!==(o=null==i?void 0:i.value)&&void 0!==o?o:"";if("script"===n){const e=a.attr("type");e&&a.attr("type","mce-no/type"===e?null:e.replace(/^mce\-/,"")),"xhtml"===t.element_format&&i&&l.length>0&&(i.value="// <![CDATA[\n"+r(l)+"\n// ]]>")}else"xhtml"===t.element_format&&i&&l.length>0&&(i.value="\x3c!--\n"+r(l)+"\n--\x3e")}})),e.addNodeFilter("#comment",(e=>{let o=e.length;for(;o--;){const r=e[o],s=r.value;t.preserve_cdata&&0===(null==s?void 0:s.indexOf("[CDATA["))?(r.name="#cdata",r.type=4,r.value=n.decode(s.replace(/^\[CDATA\[|\]\]$/g,""))):0===(null==s?void 0:s.indexOf("mce:protected "))&&(r.name="#text",r.type=3,r.raw=!0,r.value=unescape(s).substr(14))}})),e.addNodeFilter("xml:namespace,input",((e,t)=>{let n=e.length;for(;n--;){const o=e[n];7===o.type?o.remove():1===o.type&&("input"!==t||o.attr("type")||o.attr("type","text"))}})),e.addAttributeFilter("data-mce-type",(t=>{q(t,(t=>{"format-caret"===t.attr("data-mce-type")&&(t.isEmpty(e.schema.getNonEmptyElements())?t.remove():t.unwrap())}))})),e.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected,data-mce-expando,data-mce-block,data-mce-type,data-mce-resize,data-mce-placeholder",((e,t)=>{let n=e.length;for(;n--;)e[n].attr(t,null)})),t.remove_trailing_brs&&((e,t,n)=>{t.addNodeFilter("br",((t,o,r)=>{const s=Dt.extend({},n.getBlockElements()),a=n.getNonEmptyElements(),i=n.getWhitespaceElements();s.body=1;const l=e=>e.name in s||Jr(n,e);for(let o=0,d=t.length;o<d;o++){let d=t[o],c=d.parent;if(c&&l(c)&&d===c.lastChild){let t=d.prev;for(;t;){const e=t.name;if("span"!==e||"bookmark"!==t.attr("data-mce-type")){"br"===e&&(d=null);break}t=t.prev}if(d&&(d.remove(),_b(n,a,i,c))){const t=n.getElementRule(c.name);t&&(t.removeEmpty?c.remove():t.paddEmpty&&xb(e,r,l,c))}}else{let e=d;for(;c&&c.firstChild===e&&c.lastChild===e&&(e=c,!s[c.name]);)c=c.parent;if(e===c){const e=new Jg("#text",3);e.value=Wo,d.replace(e)}}}}))})(t,e,e.schema)})(a,o,r),{schema:s,addNodeFilter:a.addNodeFilter,addAttributeFilter:a.addAttributeFilter,serialize:(e,n={})=>{const i={format:"html",...n},l=((e,t,n)=>((e,t)=>C(e)&&e.hasEventListeners("PreProcess")&&!t.no_events)(e,n)?((e,t,n)=>{let o;const r=e.dom;let s=t.cloneNode(!0);const a=document.implementation;if(a.createHTMLDocument){const e=a.createHTMLDocument("");Dt.each("BODY"===s.nodeName?s.childNodes:[s],(t=>{e.body.appendChild(e.importNode(t,!0))})),s="BODY"!==s.nodeName?e.body.firstChild:e.body,o=r.doc,r.doc=e}return((e,t)=>{e.dispatch("PreProcess",t)})(e,{...n,node:s}),o&&(r.doc=o),s})(e,t,n):t)(t,e,i),d=((e,t,n)=>{const o=ei(n.getInner?t.innerHTML:e.getOuterHTML(t));return n.selection||Ga(Cn(t))?o:Dt.trim(o)})(r,l,i),c=((e,t,n)=>{const o=n.selection?{forced_root_block:!1,...n}:n,r=e.parse(t,o);return(e=>{const t=e=>"br"===(null==e?void 0:e.name),n=e.lastChild;if(t(n)){const e=n.prev;t(e)&&(n.remove(),e.remove())}})(r),r})(a,d,i);return"tree"===i.format?c:((e,t,n,o,r)=>{const s=((e,t,n)=>vp(e,t).serialize(n))(t,n,o);return((e,t,n)=>{if(!t.no_events&&e){const o=((e,t)=>e.dispatch("PostProcess",t))(e,{...t,content:n});return o.content}return n})(e,r,s)})(t,o,s,c,i)},addRules:s.addValidElements,setRules:s.setValidElements,addTempAttr:T(gw,a,n),getTempAttrs:N(n),getNodeFilters:a.getNodeFilters,getAttributeFilters:a.getAttributeFilters,removeNodeFilter:a.removeNodeFilter,removeAttributeFilter:a.removeAttributeFilter}},hw=(e,t)=>{const n=pw(e,t);return{schema:n.schema,addNodeFilter:n.addNodeFilter,addAttributeFilter:n.addAttributeFilter,serialize:n.serialize,addRules:n.addRules,setRules:n.setRules,addTempAttr:n.addTempAttr,getTempAttrs:n.getTempAttrs,getNodeFilters:n.getNodeFilters,getAttributeFilters:n.getAttributeFilters,removeNodeFilter:n.removeNodeFilter,removeAttributeFilter:n.removeAttributeFilter}},bw=(e,t,n={})=>{const o=((e,t)=>({format:"html",...e,set:!0,content:t}))(n,t);return TC(e,o).map((t=>{const n=((e,t,n)=>aw(e).editor.setContent(t,n))(e,t.content,t);return OC(e,n.html,t),n.content})).getOr(t)},vw="autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists,template_cdate_classes,template_mdate_classes,template_selected_content_classes,template_preview_replace_values,template_replace_values,templates,template_cdate_format,template_mdate_format".split(","),yw=[],Cw="bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,template,textcolor,rtc".split(","),ww=[],Ew=(e,t)=>{const n=Y(t,(t=>ke(e,t)));return ae(n)},xw=e=>{const t=Ew(e,vw),n=e.forced_root_block;return!1!==n&&""!==n||t.push("forced_root_block (false only)"),ae(t)},kw=e=>Ew(e,yw),_w=(e,t)=>{const n=Dt.makeMap(e.plugins," "),o=Y(t,(e=>ke(n,e)));return ae(o)},Sw=e=>_w(e,Cw),Nw=e=>_w(e,ww.map((e=>e.name))),Rw=e=>Q(ww,(t=>t.name===e)).fold((()=>e),(t=>t.replacedWith?`${e}, replaced by ${t.replacedWith}`:e)),Aw=ma.DOM,Tw=e=>I.from(e).each((e=>e.destroy())),Ow=(()=>{const e={};return{add:(t,n)=>{e[t]=n},get:t=>e[t]?e[t]:{icons:{}},has:t=>ke(e,t)}})(),Bw=ya.ModelManager,Pw=(e,t)=>t.dom[e],Dw=(e,t)=>parseInt(uo(t,e),10),Lw=T(Pw,"clientWidth"),Mw=T(Pw,"clientHeight"),Iw=T(Dw,"margin-top"),Fw=T(Dw,"margin-left"),Uw=e=>{const t=[],n=()=>{const t=e.theme;return t&&t.getNotificationManagerImpl?t.getNotificationManagerImpl():(()=>{const e=()=>{throw new Error("Theme did not provide a NotificationManager implementation.")};return{open:e,close:e,getArgs:e}})()},o=()=>I.from(t[0]),r=()=>{o().each((e=>{e.reposition()}))},s=e=>{J(t,(t=>t===e)).each((e=>{t.splice(e,1)}))},a=(o,a=!0)=>e.removed||!(e=>{return(t=e.inline?e.getBody():e.getContentAreaContainer(),I.from(t).map(Cn)).map(Xn).getOr(!1);var t})(e)?{}:(a&&e.dispatch("BeforeOpenNotification",{notification:o}),Q(t,(e=>{return t=n().getArgs(e),r=o,!(t.type!==r.type||t.text!==r.text||t.progressBar||t.timeout||r.progressBar||r.timeout);var t,r})).getOrThunk((()=>{e.editorManager.setActive(e);const a=n().open(o,(()=>{s(a)}),(()=>jg(e)));return(e=>{t.push(e)})(a),r(),e.dispatch("OpenNotification",{notification:{...a}}),a}))),i=N(t);return(e=>{e.on("SkinLoaded",(()=>{const t=Ed(e);t&&a({text:t,type:"warning",timeout:0},!1),r()})),e.on("show ResizeEditor NodeChange",(()=>{requestAnimationFrame(r)})),e.on("remove",(()=>{q(t.slice(),(e=>{n().close(e)}))})),e.addShortcut("alt+F12","Focus to notification",(()=>o().map((e=>Cn(e.getEl()))).each((e=>vg(e)))))})(e),{open:a,close:()=>{o().each((e=>{n().close(e),s(e),r()}))},getNotifications:i}},zw=ya.PluginManager,jw=ya.ThemeManager,Hw=e=>{let t=[];const n=()=>{const t=e.theme;return t&&t.getWindowManagerImpl?t.getWindowManagerImpl():(()=>{const e=()=>{throw new Error("Theme did not provide a WindowManager implementation.")};return{open:e,openUrl:e,alert:e,confirm:e,close:e}})()},o=(e,t)=>(...n)=>t?t.apply(e,n):void 0,r=n=>{(t=>{e.dispatch("CloseWindow",{dialog:t})})(n),t=Y(t,(e=>e!==n)),0===t.length&&e.focus()},s=n=>{e.editorManager.setActive(e),Ng(e),e.ui.show();const o=n();return(n=>{t.push(n),(t=>{e.dispatch("OpenWindow",{dialog:t})})(n)})(o),o};return e.on("remove",(()=>{q(t,(e=>{n().close(e)}))})),{open:(e,t)=>s((()=>n().open(e,t,r))),openUrl:e=>s((()=>n().openUrl(e,r))),alert:(e,t,r)=>{const s=n();s.alert(e,o(r||s,t))},confirm:(e,t,r)=>{const s=n();s.confirm(e,o(r||s,t))},close:()=>{I.from(t[t.length-1]).each((e=>{n().close(e),r(e)}))}}},$w=(e,t)=>{e.notificationManager.open({type:"error",text:t})},Vw=(e,t)=>{e._skinLoaded?$w(e,t):e.on("SkinLoaded",(()=>{$w(e,t)}))},qw=(e,t,n)=>{mf(e,t,{message:n}),console.error(n)},Ww=(e,t,n)=>n?`Failed to load ${e}: ${n} from url ${t}`:`Failed to load ${e} url: ${t}`,Kw=(e,...t)=>{const n=window.console;n&&(n.error?n.error(e,...t):n.log(e,...t))},Yw=e=>"content/"+e+"/content.css",Gw=(e,t)=>{const n=e.editorManager.baseURL+"/skins/content",o=`content${e.editorManager.suffix}.css`;return V(t,(t=>(e=>tinymce.Resource.has(Yw(e)))(t)?t:(e=>/^[a-z0-9\-]+$/i.test(e))(t)&&!e.inline?`${n}/${t}/${o}`:e.documentBaseURI.toAbsolute(t)))},Xw=(e,t)=>{const n={};return{findAll:(o,r=M)=>{const s=Y((e=>e?ce(e.getElementsByTagName("img")):[])(o),(t=>{const n=t.src;return!t.hasAttribute("data-mce-bogus")&&!t.hasAttribute("data-mce-placeholder")&&!(!n||n===Tt.transparentSrc)&&($e(n,"blob:")?!e.isUploaded(n)&&r(t):!!$e(n,"data:")&&r(t))})),a=V(s,(e=>{const o=e.src;if(ke(n,o))return n[o].then((t=>m(t)?t:{image:e,blobInfo:t.blobInfo}));{const r=((e,t)=>{const n=()=>Promise.reject("Invalid data URI");if($e(t,"blob:")){const s=e.getByUri(t);return C(s)?Promise.resolve(s):(o=t,$e(o,"blob:")?(e=>fetch(e).then((e=>e.ok?e.blob():Promise.reject())).catch((()=>Promise.reject({message:`Cannot convert ${e} to Blob. Resource might not exist or is inaccessible.`,uriType:"blob"}))))(o):$e(o,"data:")?(r=o,new Promise(((e,t)=>{Jv(r).bind((({type:e,data:t,base64Encoded:n})=>ey(e,t,n))).fold((()=>t("Invalid data URI")),e)}))):Promise.reject("Unknown URI format")).then((t=>ty(t).then((o=>oy(o,!1,(n=>I.some(ry(e,t,n)))).getOrThunk(n)))))}var o,r;return $e(t,"data:")?sy(e,t).fold(n,(e=>Promise.resolve(e))):Promise.reject("Unknown image data format")})(t,o).then((t=>(delete n[o],{image:e,blobInfo:t}))).catch((e=>(delete n[o],e)));return n[o]=r,r}}));return Promise.all(a)}}},Zw=()=>{let e={};const t=(e,t)=>({status:e,resultUri:t}),n=t=>t in e;return{hasBlobUri:n,getResultUri:t=>{const n=e[t];return n?n.resultUri:null},isPending:t=>!!n(t)&&1===e[t].status,isUploaded:t=>!!n(t)&&2===e[t].status,markPending:n=>{e[n]=t(1,null)},markUploaded:(n,o)=>{e[n]=t(2,o)},removeFailed:t=>{delete e[t]},destroy:()=>{e={}}}};let Qw=0;const Jw=(e,t)=>{const n={},o=(e,n)=>new Promise(((o,r)=>{const s=new XMLHttpRequest;s.open("POST",t.url),s.withCredentials=t.credentials,s.upload.onprogress=e=>{n(e.loaded/e.total*100)},s.onerror=()=>{r("Image upload failed due to a XHR Transport error. Code: "+s.status)},s.onload=()=>{if(s.status<200||s.status>=300)return void r("HTTP Error: "+s.status);const e=JSON.parse(s.responseText);var n,a;e&&m(e.location)?o((n=t.basePath,a=e.location,n?n.replace(/\/$/,"")+"/"+a.replace(/^\//,""):a)):r("Invalid JSON: "+s.responseText)};const a=new FormData;a.append("file",e.blob(),e.filename()),s.send(a)})),r=w(t.handler)?t.handler:o,s=(e,t)=>({url:t,blobInfo:e,status:!0}),a=(e,t)=>({url:"",blobInfo:e,status:!1,error:t}),i=(e,t)=>{Dt.each(n[e],(e=>{e(t)})),delete n[e]};return{upload:(l,d)=>t.url||r!==o?((t,o)=>(t=Dt.grep(t,(t=>!e.isUploaded(t.blobUri()))),Promise.all(Dt.map(t,(t=>e.isPending(t.blobUri())?(e=>{const t=e.blobUri();return new Promise((e=>{n[t]=n[t]||[],n[t].push(e)}))})(t):((t,n,o)=>(e.markPending(t.blobUri()),new Promise((r=>{let l,d;try{const c=()=>{l&&(l.close(),d=k)},u=n=>{c(),e.markUploaded(t.blobUri(),n),i(t.blobUri(),s(t,n)),r(s(t,n))},f=n=>{c(),e.removeFailed(t.blobUri()),i(t.blobUri(),a(t,n)),r(a(t,n))};d=e=>{e<0||e>100||I.from(l).orThunk((()=>I.from(o).map(P))).each((t=>{l=t,t.progressBar.value(e)}))},n(t,d).then(u,(e=>{f(m(e)?{message:e}:e)}))}catch(e){r(a(t,e))}}))))(t,r,o))))))(l,d):new Promise((e=>{e([])}))}},eE=e=>()=>e.notificationManager.open({text:e.translate("Image uploading..."),type:"info",timeout:-1,progressBar:!0}),tE=(e,t)=>Jw(t,{url:od(e),basePath:rd(e),credentials:sd(e),handler:ad(e)}),nE=e=>{const t=(()=>{let e=[];const t=e=>{if(!e.blob||!e.base64)throw new Error("blob and base64 representations of the image are required for BlobInfo to be created");const t=e.id||"blobid"+Qw+++(()=>{const e=()=>Math.round(4294967295*Math.random()).toString(36);return"s"+(new Date).getTime().toString(36)+e()+e()+e()})(),n=e.name||t,o=e.blob;var r;return{id:N(t),name:N(n),filename:N(e.filename||n+"."+(r=o.type,{"image/jpeg":"jpg","image/jpg":"jpg","image/gif":"gif","image/png":"png","image/apng":"apng","image/avif":"avif","image/svg+xml":"svg","image/webp":"webp","image/bmp":"bmp","image/tiff":"tiff"}[r.toLowerCase()]||"dat")),blob:N(o),base64:N(e.base64),blobUri:N(e.blobUri||URL.createObjectURL(o)),uri:N(e.uri)}},n=t=>Q(e,t).getOrUndefined(),o=e=>n((t=>t.id()===e));return{create:(e,n,o,r,s)=>{if(m(e))return t({id:e,name:r,filename:s,blob:n,base64:o});if(f(e))return t(e);throw new Error("Unknown input type")},add:t=>{o(t.id())||e.push(t)},get:o,getByUri:e=>n((t=>t.blobUri()===e)),getByData:(e,t)=>n((n=>n.base64()===e&&n.blob().type===t)),findFirst:n,removeByUri:t=>{e=Y(e,(e=>e.blobUri()!==t||(URL.revokeObjectURL(e.blobUri()),!1)))},destroy:()=>{q(e,(e=>{URL.revokeObjectURL(e.blobUri())})),e=[]}}})();let n,o;const r=Zw(),s=[],a=t=>n=>e.selection?t(n):[],i=(e,t,n)=>{let o=0;do{o=e.indexOf(t,o),-1!==o&&(e=e.substring(0,o)+n+e.substr(o+t.length),o+=n.length-t.length+1)}while(-1!==o);return e},l=(e,t,n)=>{const o=`src="${n}"${n===Tt.transparentSrc?' data-mce-placeholder="1"':""}`;return e=i(e,`src="${t}"`,o),i(e,'data-mce-src="'+t+'"','data-mce-src="'+n+'"')},d=(t,n)=>{q(e.undoManager.data,(e=>{"fragmented"===e.type?e.fragments=V(e.fragments,(e=>l(e,t,n))):e.content=l(e.content,t,n)}))},c=()=>(n||(n=tE(e,r)),p().then(a((o=>{const r=V(o,(e=>e.blobInfo));return n.upload(r,eE(e)).then(a((n=>{const r=[];let s=!1;const a=V(n,((n,a)=>{const{blobInfo:i,image:l}=o[a];let c=!1;return n.status&&ed(e)?(n.url&&!He(l.src,n.url)&&(s=!0),t.removeByUri(l.src),sw(e)||((t,n)=>{const o=e.convertURL(n,"src");var r;d(t.src,n),en(Cn(t),{src:Jl(e)?(r=n,r+(-1===r.indexOf("?")?"?":"&")+(new Date).getTime()):n,"data-mce-src":o})})(l,n.url)):n.error&&(n.error.remove&&(d(l.src,Tt.transparentSrc),r.push(l),c=!0),((e,t)=>{Vw(e,va.translate(["Failed to upload image: {0}",t]))})(e,n.error.message)),{element:l,status:n.status,uploadUri:n.url,blobInfo:i,removed:c}}));return r.length>0&&!sw(e)?e.undoManager.transact((()=>{q(_o(r),(n=>{const o=Tn(n);xo(n),o.each((e=>t=>{((e,t)=>e.dom.isEmpty(t.dom)&&C(e.schema.getTextBlockElements()[$t(t)]))(e,t)&&yo(t,bn('<br data-mce-bogus="1" />'))})(e)),t.removeByUri(n.dom.src)}))})):s&&e.undoManager.dispatchChange(),a})))})))),u=()=>Ql(e)?c():Promise.resolve([]),g=e=>ne(s,(t=>t(e))),p=()=>(o||(o=Xw(r,t)),o.findAll(e.getBody(),g).then(a((t=>{const n=Y(t,(t=>m(t)?(Vw(e,t),!1):"blob"!==t.uriType));return sw(e)||q(n,(e=>{d(e.image.src,e.blobInfo.blobUri()),e.image.src=e.blobInfo.blobUri(),e.image.removeAttribute("data-mce-src")})),n})))),h=n=>n.replace(/src="(blob:[^"]+)"/g,((n,o)=>{const s=r.getResultUri(o);if(s)return'src="'+s+'"';let a=t.getByUri(o);return a||(a=X(e.editorManager.get(),((e,t)=>e||t.editorUpload&&t.editorUpload.blobCache.getByUri(o)),void 0)),a?'src="data:'+a.blob().type+";base64,"+a.base64()+'"':n}));return e.on("SetContent",(()=>{Ql(e)?u():p()})),e.on("RawSaveContent",(e=>{e.content=h(e.content)})),e.on("GetContent",(e=>{e.source_view||"raw"===e.format||"tree"===e.format||(e.content=h(e.content))})),e.on("PostRender",(()=>{e.parser.addNodeFilter("img",(e=>{q(e,(e=>{const n=e.attr("src");if(!n||t.getByUri(n))return;const o=r.getResultUri(n);o&&e.attr("src",o)}))}))})),{blobCache:t,addFilter:e=>{s.push(e)},uploadImages:c,uploadImagesAuto:u,scanForImages:p,destroy:()=>{t.destroy(),r.destroy(),o=n=null}}},oE={remove_similar:!0,inherit:!1},rE={selector:"td,th",...oE},sE={tablecellbackgroundcolor:{styles:{backgroundColor:"%value"},...rE},tablecellverticalalign:{styles:{"vertical-align":"%value"},...rE},tablecellbordercolor:{styles:{borderColor:"%value"},...rE},tablecellclass:{classes:["%value"],...rE},tableclass:{selector:"table",classes:["%value"],...oE},tablecellborderstyle:{styles:{borderStyle:"%value"},...rE},tablecellborderwidth:{styles:{borderWidth:"%value"},...rE}},aE=N(sE),iE=Dt.each,lE=ma.DOM,dE=e=>C(e)&&f(e),cE=(e,t)=>{const n=t&&t.schema||Fs({}),o=e=>{const t=m(e)?{name:e,classes:[],attrs:{}}:e,n=lE.create(t.name);return((e,t)=>{t.classes.length>0&&lE.addClass(e,t.classes.join(" ")),lE.setAttribs(e,t.attrs)})(n,t),n},r=(e,t,s)=>{let a;const i=t[0],l=dE(i)?i.name:void 0,d=((e,t)=>{const o=n.getElementRule(e.nodeName.toLowerCase()),r=null==o?void 0:o.parentsRequired;return!(!r||!r.length)&&(t&&H(r,t)?t:r[0])})(e,l);if(d)l===d?(a=i,t=t.slice(1)):a=d;else if(i)a=i,t=t.slice(1);else if(!s)return e;const c=a?o(a):lE.create("div");c.appendChild(e),s&&Dt.each(s,(t=>{const n=o(t);c.insertBefore(n,e)}));const u=dE(a)?a.siblings:void 0;return r(c,t,u)},s=lE.create("div");if(e.length>0){const t=e[0],n=o(t),a=dE(t)?t.siblings:void 0;s.appendChild(r(n,e.slice(1),a))}return s},uE=e=>{let t="div";const n={name:t,classes:[],attrs:{},selector:e=Dt.trim(e)};return"*"!==e&&(t=e.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g,((e,t,o,r,s)=>{switch(t){case"#":n.attrs.id=o;break;case".":n.classes.push(o);break;case":":-1!==Dt.inArray("checked disabled enabled read-only required".split(" "),o)&&(n.attrs[o]=o)}if("["===r){const e=s.match(/([\w\-]+)(?:\=\"([^\"]+))?/);e&&(n.attrs[e[1]]=e[2])}return""}))),n.name=t||"div",n},mE=(e,t)=>{let n="",o=Ad(e);if(""===o)return"";const r=e=>m(e)?e.replace(/%(\w+)/g,""):"",s=(t,n)=>lE.getStyle(null!=n?n:e.getBody(),t,!0);if(m(t)){const n=e.formatter.get(t);if(!n)return"";t=n[0]}if("preview"in t){const e=t.preview;if(!1===e)return"";o=e||o}let a,i=t.block||t.inline||"span";const l=(d=t.selector,m(d)?(d=(d=d.split(/\s*,\s*/)[0]).replace(/\s*(~\+|~|\+|>)\s*/g,"$1"),Dt.map(d.split(/(?:>|\s+(?![^\[\]]+\]))/),(e=>{const t=Dt.map(e.split(/(?:~\+|~|\+)/),uE),n=t.pop();return t.length&&(n.siblings=t),n})).reverse()):[]);var d;l.length>0?(l[0].name||(l[0].name=i),i=t.selector,a=cE(l,e)):a=cE([i],e);const c=lE.select(i,a)[0]||a.firstChild;iE(t.styles,((e,t)=>{const n=r(e);n&&lE.setStyle(c,t,n)})),iE(t.attributes,((e,t)=>{const n=r(e);n&&lE.setAttrib(c,t,n)})),iE(t.classes,(e=>{const t=r(e);lE.hasClass(c,t)||lE.addClass(c,t)})),e.dispatch("PreviewFormats"),lE.setStyles(a,{position:"absolute",left:-65535}),e.getBody().appendChild(a);const u=s("fontSize"),f=/px$/.test(u)?parseInt(u,10):0;return iE(o.split(" "),(e=>{let t=s(e,c);if(!("background-color"===e&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(t)&&(t=s(e),"#ffffff"===Ws(t).toLowerCase())||"color"===e&&"#000000"===Ws(t).toLowerCase())){if("font-size"===e&&/em|%$/.test(t)){if(0===f)return;t=parseFloat(t)/(/%$/.test(t)?100:1)*f+"px"}"border"===e&&t&&(n+="padding:0 2px;"),n+=e+":"+t+";"}})),e.dispatch("AfterPreviewFormats"),lE.remove(a),n},fE=e=>{const t=(e=>{const t={},n=(e,o)=>{e&&(m(e)?(p(o)||(o=[o]),q(o,(e=>{v(e.deep)&&(e.deep=!Im(e)),v(e.split)&&(e.split=!Im(e)||Fm(e)),v(e.remove)&&Im(e)&&!Fm(e)&&(e.remove="none"),Im(e)&&Fm(e)&&(e.mixed=!0,e.block_expand=!0),m(e.classes)&&(e.classes=e.classes.split(/\s+/))})),t[e]=o):pe(e,((e,t)=>{n(t,e)})))};return n((e=>{const t=e.dom,n=e.schema.type,o={valigntop:[{selector:"td,th",styles:{verticalAlign:"top"}}],valignmiddle:[{selector:"td,th",styles:{verticalAlign:"middle"}}],valignbottom:[{selector:"td,th",styles:{verticalAlign:"bottom"}}],alignleft:[{selector:"figure.image",collapsed:!1,classes:"align-left",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",styles:{textAlign:"left"},inherit:!1,preview:!1},{selector:"img,audio,video",collapsed:!1,styles:{float:"left"},preview:"font-family font-size"},{selector:"table",collapsed:!1,styles:{marginLeft:"0px",marginRight:"auto"},onformat:e=>{t.setStyle(e,"float",null)},preview:"font-family font-size"},{selector:".mce-preview-object,[data-ephox-embed-iri]",ceFalseOverride:!0,styles:{float:"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",styles:{textAlign:"center"},inherit:!1,preview:"font-family font-size"},{selector:"figure.image",collapsed:!1,classes:"align-center",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"img,audio,video",collapsed:!1,styles:{display:"block",marginLeft:"auto",marginRight:"auto"},preview:!1},{selector:"table",collapsed:!1,styles:{marginLeft:"auto",marginRight:"auto"},preview:"font-family font-size"},{selector:".mce-preview-object",ceFalseOverride:!0,styles:{display:"table",marginLeft:"auto",marginRight:"auto"},preview:!1},{selector:"[data-ephox-embed-iri]",ceFalseOverride:!0,styles:{marginLeft:"auto",marginRight:"auto"},preview:!1}],alignright:[{selector:"figure.image",collapsed:!1,classes:"align-right",ceFalseOverride:!0,preview:"font-family font-size"},{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",styles:{textAlign:"right"},inherit:!1,preview:"font-family font-size"},{selector:"img,audio,video",collapsed:!1,styles:{float:"right"},preview:"font-family font-size"},{selector:"table",collapsed:!1,styles:{marginRight:"0px",marginLeft:"auto"},onformat:e=>{t.setStyle(e,"float",null)},preview:"font-family font-size"},{selector:".mce-preview-object,[data-ephox-embed-iri]",ceFalseOverride:!0,styles:{float:"right"},preview:!1}],alignjustify:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",styles:{textAlign:"justify"},inherit:!1,preview:"font-family font-size"}],bold:[{inline:"strong",remove:"all",preserve_attributes:["class","style"]},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all",preserve_attributes:["class","style"]}],italic:[{inline:"em",remove:"all",preserve_attributes:["class","style"]},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all",preserve_attributes:["class","style"]}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:!0},{inline:"u",remove:"all",preserve_attributes:["class","style"]}],strikethrough:(()=>{const e={inline:"span",styles:{textDecoration:"line-through"},exact:!0},t={inline:"strike",remove:"all",preserve_attributes:["class","style"]},o={inline:"s",remove:"all",preserve_attributes:["class","style"]};return"html4"!==n?[o,e,t]:[e,o,t]})(),forecolor:{inline:"span",styles:{color:"%value"},links:!0,remove_similar:!0,clear_child_styles:!0},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},links:!0,remove_similar:!0,clear_child_styles:!0},fontname:{inline:"span",toggle:!1,styles:{fontFamily:"%value"},clear_child_styles:!0},fontsize:{inline:"span",toggle:!1,styles:{fontSize:"%value"},clear_child_styles:!0},lineheight:{selector:"h1,h2,h3,h4,h5,h6,p,li,td,th,div",styles:{lineHeight:"%value"}},fontsize_class:{inline:"span",attributes:{class:"%value"}},blockquote:{block:"blockquote",wrapper:!0,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},code:{inline:"code"},link:{inline:"a",selector:"a",remove:"all",split:!0,deep:!0,onmatch:(e,t,n)=>er(e)&&e.hasAttribute("href"),onformat:(e,n,o)=>{Dt.each(o,((n,o)=>{t.setAttrib(e,o,n)}))}},lang:{inline:"span",clear_child_styles:!0,remove_similar:!0,attributes:{lang:"%value","data-mce-lang":e=>{var t;return null!==(t=null==e?void 0:e.customValue)&&void 0!==t?t:null}}},removeformat:[{selector:"b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small",remove:"all",split:!0,expand:!1,block_expand:!0,deep:!0},{selector:"span",attributes:["style","class"],remove:"empty",split:!0,expand:!1,deep:!0},{selector:"*",attributes:["style","class"],split:!1,expand:!1,deep:!0}]};return Dt.each("p h1 h2 h3 h4 h5 h6 div address pre dt dd samp".split(/\s/),(e=>{o[e]={block:e,remove:"all"}})),o})(e)),n(aE()),n(Rd(e)),{get:e=>C(e)?t[e]:t,has:e=>ke(t,e),register:n,unregister:e=>(e&&t[e]&&delete t[e],t)}})(e),n=Br({});return(e=>{e.addShortcut("meta+b","","Bold"),e.addShortcut("meta+i","","Italic"),e.addShortcut("meta+u","","Underline");for(let t=1;t<=6;t++)e.addShortcut("access+"+t,"",["FormatBlock",!1,"h"+t]);e.addShortcut("access+7","",["FormatBlock",!1,"p"]),e.addShortcut("access+8","",["FormatBlock",!1,"div"]),e.addShortcut("access+9","",["FormatBlock",!1,"address"])})(e),(e=>{e.on("mouseup keydown",(t=>{var n;((e,t,n)=>{const o=e.selection,r=e.getBody();ev(e,null,n),8!==t&&46!==t||!o.isCollapsed()||o.getStart().innerHTML!==Xb||ev(e,Wu(r,o.getStart()),!0),37!==t&&39!==t||ev(e,Wu(r,o.getStart()),!0)})(e,t.keyCode,(n=e.selection.getRng().endContainer,dr(n)&&Ve(n.data,Wo)))}))})(e),sw(e)||((e,t)=>{e.set({}),t.on("NodeChange",(n=>{Gv(t,n.element,e.get())})),t.on("FormatApply FormatRemove",(n=>{const o=I.from(n.node).map((e=>Cm(e)?e:e.startContainer)).bind((e=>er(e)?I.some(e):I.from(e.parentElement))).getOrThunk((()=>Wv(t)));Gv(t,o,e.get())}))})(n,e),{get:t.get,has:t.has,register:t.register,unregister:t.unregister,apply:(t,n,o)=>{((e,t,n,o)=>{iw(e).formatter.apply(t,n,o)})(e,t,n,o)},remove:(t,n,o,r)=>{((e,t,n,o,r)=>{iw(e).formatter.remove(t,n,o,r)})(e,t,n,o,r)},toggle:(t,n,o)=>{((e,t,n,o)=>{iw(e).formatter.toggle(t,n,o)})(e,t,n,o)},match:(t,n,o,r)=>((e,t,n,o,r)=>iw(e).formatter.match(t,n,o,r))(e,t,n,o,r),closest:t=>((e,t)=>iw(e).formatter.closest(t))(e,t),matchAll:(t,n)=>((e,t,n)=>iw(e).formatter.matchAll(t,n))(e,t,n),matchNode:(t,n,o,r)=>((e,t,n,o,r)=>iw(e).formatter.matchNode(t,n,o,r))(e,t,n,o,r),canApply:t=>((e,t)=>iw(e).formatter.canApply(t))(e,t),formatChanged:(t,o,r,s)=>((e,t,n,o,r,s)=>iw(e).formatter.formatChanged(t,n,o,r,s))(e,n,t,o,r,s),getCssText:T(mE,e)}},gE=e=>{switch(e.toLowerCase()){case"undo":case"redo":case"mcefocus":return!0;default:return!1}},pE=e=>{const t=Dr(),n=Br(0),o=Br(0),r={data:[],typing:!1,beforeChange:()=>{((e,t,n)=>{iw(e).undoManager.beforeChange(t,n)})(e,n,t)},add:(s,a)=>((e,t,n,o,r,s,a)=>iw(e).undoManager.add(t,n,o,r,s,a))(e,r,o,n,t,s,a),dispatchChange:()=>{e.setDirty(!0);const t=XC(e);t.bookmark=yl(e.selection),e.dispatch("change",{level:t,lastLevel:ie(r.data,o.get()).getOrUndefined()})},undo:()=>((e,t,n,o)=>iw(e).undoManager.undo(t,n,o))(e,r,n,o),redo:()=>((e,t,n)=>iw(e).undoManager.redo(t,n))(e,o,r.data),clear:()=>{((e,t,n)=>{iw(e).undoManager.clear(t,n)})(e,r,o)},reset:()=>{((e,t)=>{iw(e).undoManager.reset(t)})(e,r)},hasUndo:()=>((e,t,n)=>iw(e).undoManager.hasUndo(t,n))(e,r,o),hasRedo:()=>((e,t,n)=>iw(e).undoManager.hasRedo(t,n))(e,r,o),transact:t=>((e,t,n,o)=>iw(e).undoManager.transact(t,n,o))(e,r,n,t),ignore:t=>{((e,t,n)=>{iw(e).undoManager.ignore(t,n)})(e,n,t)},extra:(t,n)=>{((e,t,n,o,r)=>{iw(e).undoManager.extra(t,n,o,r)})(e,r,o,t,n)}};return sw(e)||((e,t,n)=>{const o=Br(!1),r=e=>{nw(t,!1,n),t.add({},e)};e.on("init",(()=>{t.add()})),e.on("BeforeExecCommand",(e=>{const o=e.command;gE(o)||(ow(t,n),t.beforeChange())})),e.on("ExecCommand",(e=>{const t=e.command;gE(t)||r(e)})),e.on("ObjectResizeStart cut",(()=>{t.beforeChange()})),e.on("SaveContent ObjectResized blur",r),e.on("dragend",r),e.on("keyup",(n=>{const s=n.keyCode;if(n.isDefaultPrevented())return;const a=Tt.os.isMacOS()&&"Meta"===n.key;(s>=33&&s<=36||s>=37&&s<=40||45===s||n.ctrlKey||a)&&(r(),e.nodeChanged()),46!==s&&8!==s||e.nodeChanged(),o.get()&&t.typing&&!ew(XC(e),t.data[0])&&(e.isDirty()||e.setDirty(!0),e.dispatch("TypingUndo"),o.set(!1),e.nodeChanged())})),e.on("keydown",(e=>{const s=e.keyCode;if(e.isDefaultPrevented())return;if(s>=33&&s<=36||s>=37&&s<=40||45===s)return void(t.typing&&r(e));const a=e.ctrlKey&&!e.altKey||e.metaKey;if((s<16||s>20)&&224!==s&&91!==s&&!t.typing&&!a)return t.beforeChange(),nw(t,!0,n),t.add({},e),void o.set(!0);(Tt.os.isMacOS()?e.metaKey:e.ctrlKey&&!e.altKey)&&t.beforeChange()})),e.on("mousedown",(e=>{t.typing&&r(e)})),e.on("input",(e=>{var t;e.inputType&&("insertReplacementText"===e.inputType||"insertText"===(t=e).inputType&&null===t.data||(e=>"insertFromPaste"===e.inputType||"insertFromDrop"===e.inputType)(e))&&r(e)})),e.on("AddUndo Undo Redo ClearUndos",(t=>{t.isDefaultPrevented()||e.nodeChanged()}))})(e,r,n),(e=>{e.addShortcut("meta+z","","Undo"),e.addShortcut("meta+y,meta+shift+z","","Redo")})(e),r},hE=[9,27,yf.HOME,yf.END,19,20,44,144,145,33,34,45,16,17,18,91,92,93,yf.DOWN,yf.UP,yf.LEFT,yf.RIGHT].concat(Tt.browser.isFirefox()?[224]:[]),bE="data-mce-placeholder",vE=e=>"keydown"===e.type||"keyup"===e.type,yE=e=>{const t=e.keyCode;return t===yf.BACKSPACE||t===yf.DELETE},CE=(e,t)=>({from:e,to:t}),wE=(e,t)=>{const n=Cn(e),o=Cn(t.container());return Fh(n,o).map((e=>((e,t)=>({block:e,position:t}))(e,t)))},EE=(e,t)=>Jn(t,(e=>Ya(e)||br(e.dom)),(t=>_n(t,e))).filter(Kt).getOr(e),xE=(e,t,n)=>{const o=n?Ln(e).reverse():Mn(e),r=J(o,(e=>t.isBlock($t(e)))).fold(N(o),(e=>o.slice(0,e)));return n?r.reverse():r},kE=(e,t,n,o,r)=>{const s=((e,t,n,o,r)=>{if(r&&Sn(e,t))return xE(t,n,o);if(r&&Sn(t,e))return xE(e,n,o);{const e=In(t);return J(e,(e=>n.isBlock($t(e)))).fold(N(e),(t=>e.slice(0,t)))}})(e,t,n,o,r);return q(s,xo),s},_E=(e,t,n)=>{const o=zp(n,t);return Q(o.reverse(),(t=>Tr(e,t))).each(xo)},SE=(e,t,n,o,r,s)=>{if(Tr(o,n))return Za(n),Hu(n.dom);((e,t)=>0===Y(Ln(t),(t=>!Tr(e,t))).length)(o,s)&&Tr(o,t)&&ho(s,vn("br"));const a=ju(n.dom,Qi.before(s.dom));return q(kE(n,t,o,r,!1),(e=>{ho(s,e)})),_E(o,e,t),a},NE=(e,t,n,o,r)=>{if(Tr(o,n)){if(Tr(o,t)){const e=e=>{const t=(e,n)=>Un(e).fold((()=>n),(e=>((e,t)=>e.isInline($t(t)))(o,e)?t(e,n.concat(Ma(e))):n));return t(e,[])},r=G(e(n),((e,t)=>(Co(e,t),t)),Xa());Eo(t),yo(t,r)}return xo(n),Hu(t.dom)}const s=$u(n.dom);return q(kE(n,t,o,r,!0),(e=>{r&&Sn(t,n)?vo(n,e):yo(n,e)})),_E(o,e,t),s},RE=(e,t)=>{Uu(e,t.dom).bind((e=>I.from(e.getNode()))).map(Cn).filter($a).each(xo)},AE=(e,t,n,o,r)=>(RE(!0,t),RE(!1,n),((e,t)=>Sn(t,e)?((e,t)=>{const n=zp(t,e);return I.from(n[n.length-1])})(t,e):I.none())(t,n).fold(T(NE,e,t,n,o,r),T(SE,e,t,n,o,r))),TE=(e,t,n,o,r,s=!1)=>{if(s){if(Sn(o,n))return AE(e,o,n,r,!t);if(Sn(n,o))return AE(e,n,o,r,t)}return t?AE(e,o,n,r,t):AE(e,n,o,r,!t)},OE=(e,t)=>{const n=Cn(e.getBody()),o=((e,t,n,o)=>o.collapsed?((e,t,n,o)=>{const r=wE(t,Qi.fromRangeStart(o)),s=r.bind((o=>Mu(n,t,o.position).bind((o=>wE(t,o).map((o=>((e,t,n,o)=>pr(o.position.getNode())&&!Tr(e,o.block)?Uu(!1,o.block.dom).bind((e=>e.isEqual(o.position)?Mu(n,t,e).bind((e=>wE(t,e))):I.some(o))).getOr(o):o)(e,t,n,o)))))));return It(r,s,CE).filter((e=>(e=>!_n(e.from.block,e.to.block))(e)&&((e,t)=>{const n=Cn(e);return _n(EE(n,t.from.block),EE(n,t.to.block))})(t,e)&&(e=>!1===vr(e.from.block.dom)&&!1===vr(e.to.block.dom))(e)&&(e=>{const t=e=>Va(e)||Yr(e.dom)||Wa(e);return t(e.from.block)&&t(e.to.block)})(e)&&(e=>!(Sn(e.to.block,e.from.block)||Sn(e.from.block,e.to.block)))(e)))})(e,t,n,o):I.none())(e.schema,n.dom,t,e.selection.getRng()).map((o=>()=>{TE(n,t,o.from.block,o.to.block,e.schema,!0).each((t=>{e.selection.setRng(t.toRange())}))}));return o},BE=(e,t)=>{const n=Cn(t),o=T(_n,e);return Qn(n,Ya,o).isSome()},PE=e=>{const t=Cn(e.getBody());return((e,t)=>{const n=ju(e.dom,Qi.fromRangeStart(t)).isNone(),o=zu(e.dom,Qi.fromRangeEnd(t)).isNone();return!((e,t)=>BE(e,t.startContainer)||BE(e,t.endContainer))(e,t)&&n&&o})(t,e.selection.getRng())?(e=>I.some((()=>{e.setContent(""),e.selection.setCursorLocation()})))(e):((e,t,n)=>{const o=t.getRng();return It(Fh(e,Cn(o.startContainer)),Fh(e,Cn(o.endContainer)),((r,s)=>_n(r,s)?I.none():I.some((()=>{o.deleteContents(),TE(e,!0,r,s,n).each((e=>{t.setRng(e.toRange())}))})))).getOr(I.none())})(t,e.selection,e.schema)},DE=(e,t)=>e.selection.isCollapsed()?I.none():PE(e),LE=(e,t,n,o,r)=>I.from(t._selectionOverrides.showCaret(e,n,o,r)),ME=(e,t)=>e.dispatch("BeforeObjectSelected",{target:t}).isDefaultPrevented()?I.none():I.some((e=>{const t=e.ownerDocument.createRange();return t.selectNode(e),t})(t)),IE=(e,t,n)=>t.collapsed?((e,t,n)=>{const o=pu(1,e.getBody(),t),r=Qi.fromRangeStart(o),s=r.getNode();if(Wc(s))return LE(1,e,s,!r.isAtEnd(),!1);const a=r.getNode(!0);if(Wc(a))return LE(1,e,a,!1,!1);const i=pb(e.dom.getRoot(),r.getNode());return Wc(i)?LE(1,e,i,!1,n):I.none()})(e,t,n).getOr(t):t,FE=e=>Ip(e)||Pp(e),UE=e=>Fp(e)||Dp(e),zE=(e,t,n,o,r,s)=>{LE(o,e,s.getNode(!r),r,!0).each((n=>{if(t.collapsed){const e=t.cloneRange();r?e.setEnd(n.startContainer,n.startOffset):e.setStart(n.endContainer,n.endOffset),e.deleteContents()}else t.deleteContents();e.selection.setRng(n)})),((e,t)=>{dr(t)&&0===t.data.length&&e.remove(t)})(e.dom,n)},jE=(e,t)=>((e,t)=>{const n=e.selection.getRng();if(!dr(n.commonAncestorContainer))return I.none();const o=t?wu.Forwards:wu.Backwards,r=Bu(e.getBody()),s=T(yu,t?r.next:r.prev),a=t?FE:UE,i=bu(o,e.getBody(),n),l=s(i),d=l?Oh(t,l):l;if(!d||!Cu(i,d))return I.none();if(a(d))return I.some((()=>zE(e,n,i.getNode(),o,t,d)));const c=s(d);return c&&a(c)&&Cu(d,c)?I.some((()=>zE(e,n,i.getNode(),o,t,c))):I.none()})(e,t),HE=(e,t)=>{const n=e.getBody();return t?Hu(n).filter(Ip):$u(n).filter(Fp)},$E=e=>{const t=e.selection.getRng();return!t.collapsed&&(HE(e,!0).exists((e=>e.isEqual(Qi.fromRangeStart(t))))||HE(e,!1).exists((e=>e.isEqual(Qi.fromRangeEnd(t)))))},VE=xl([{remove:["element"]},{moveToElement:["element"]},{moveToPosition:["position"]}]),qE=(e,t,n,o)=>Mu(t,e,n).bind((r=>{return s=r.getNode(),C(s)&&(Ya(Cn(s))||Wa(Cn(s)))||((e,t,n,o,r)=>{const s=t=>r.isInline(t.nodeName.toLowerCase())&&!lu(n,o,e);return hu(!t,n).fold((()=>hu(t,o).fold(L,s)),s)})(e,t,n,r,o)?I.none():t&&vr(r.getNode())||!t&&vr(r.getNode(!0))?((e,t,n,o,r)=>{const s=r.getNode(!n);return Fh(Cn(t),Cn(o.getNode())).map((t=>Tr(e,t)?VE.remove(t.dom):VE.moveToElement(s))).orThunk((()=>I.some(VE.moveToElement(s))))})(o,e,t,n,r):t&&Fp(n)||!t&&Ip(n)?I.some(VE.moveToPosition(r)):I.none();var s})),WE=(e,t)=>I.from(pb(e.getBody(),t)),KE=(e,t)=>{const n=e.selection.getNode();return WE(e,n).filter(vr).fold((()=>((e,t,n,o)=>{const r=pu(t?1:-1,e,n),s=Qi.fromRangeStart(r),a=Cn(e);return!t&&Fp(s)?I.some(VE.remove(s.getNode(!0))):t&&Ip(s)?I.some(VE.remove(s.getNode())):!t&&Ip(s)&&Qp(a,s,o)?Jp(a,s,o).map((e=>VE.remove(e.getNode()))):t&&Fp(s)&&Zp(a,s,o)?eh(a,s,o).map((e=>VE.remove(e.getNode()))):((e,t,n,o)=>((e,t)=>{const n=t.getNode(!e),o=e?"after":"before";return er(n)&&n.getAttribute("data-mce-caret")===o})(t,n)?((e,t)=>y(t)?I.none():e&&vr(t.nextSibling)?I.some(VE.moveToElement(t.nextSibling)):!e&&vr(t.previousSibling)?I.some(VE.moveToElement(t.previousSibling)):I.none())(t,n.getNode(!t)).orThunk((()=>qE(e,t,n,o))):qE(e,t,n,o).bind((t=>((e,t,n)=>n.fold((e=>I.some(VE.remove(e))),(e=>I.some(VE.moveToElement(e))),(n=>lu(t,n,e)?I.none():I.some(VE.moveToPosition(n)))))(e,n,t))))(e,t,s,o)})(e.getBody(),t,e.selection.getRng(),e.schema).map((n=>()=>n.fold(((e,t)=>n=>(e._selectionOverrides.hideFakeCaret(),Sh(e,t,Cn(n)),!0))(e,t),((e,t)=>n=>{const o=t?Qi.before(n):Qi.after(n);return e.selection.setRng(o.toRange()),!0})(e,t),(e=>t=>(e.selection.setRng(t.toRange()),!0))(e))))),(()=>I.some(k)))},YE=e=>{const t=e.dom,n=e.selection,o=pb(e.getBody(),n.getNode());if(br(o)&&t.isBlock(o)&&t.isEmpty(o)){const e=t.create("br",{"data-mce-bogus":"1"});t.setHTML(o,""),o.appendChild(e),n.setRng(Qi.before(e).toRange())}return!0},GE=(e,t)=>e.selection.isCollapsed()?KE(e,t):((e,t)=>{const n=e.selection.getNode();return vr(n)&&!yr(n)?WE(e,n.parentNode).filter(vr).fold((()=>I.some((()=>{var n;n=Cn(e.getBody()),q(zo(n,".mce-offscreen-selection"),xo),Sh(e,t,Cn(e.selection.getNode())),Uh(e)}))),(()=>I.some(k))):$E(e)?I.some((()=>{Hh(e,e.selection.getRng(),Cn(e.getBody()))})):I.none()})(e,t),XE=e=>e.hasOwnProperty("text"),ZE=e=>e.hasOwnProperty("marker"),QE=(e,t)=>{const n=(e,n)=>{if(dr(e))return{text:e,offset:n};{const o=t(),r=e.childNodes;return n<r.length?(e.insertBefore(o,r[n]),{marker:o,before:!0}):(e.appendChild(o),{marker:o,before:!1})}},o=n(e.endContainer,e.endOffset);return{start:n(e.startContainer,e.startOffset),end:o}},JE=e=>{var t,n;const{start:o,end:r}=e,s=new window.Range;return XE(o)?s.setStart(o.text,o.offset):ZE(o)&&(o.before?s.setStartBefore(o.marker):s.setStartAfter(o.marker),null===(t=o.marker.parentNode)||void 0===t||t.removeChild(o.marker)),XE(r)?s.setEnd(r.text,r.offset):ZE(r)&&(r.before?s.setEndBefore(r.marker):s.setEndAfter(r.marker),null===(n=r.marker.parentNode)||void 0===n||n.removeChild(r.marker)),s},ex=(e,t)=>{var n;const o=e.dom,r=o.getParent(e.selection.getStart(),o.isBlock),s=o.getParent(e.selection.getEnd(),o.isBlock),a=e.getBody();if("div"===(null===(n=null==r?void 0:r.nodeName)||void 0===n?void 0:n.toLowerCase())&&r&&s&&r===a.firstChild&&s===a.lastChild&&!o.isEmpty(a)){const n=r.cloneNode(!1),o=()=>{if(t?Mh(e):Lh(e),a.firstChild!==r){const t=QE(e.selection.getRng(),(()=>document.createElement("span")));Array.from(a.childNodes).forEach((e=>n.appendChild(e))),a.appendChild(n),e.selection.setRng(JE(t))}};return I.some(o)}return I.none()},tx=(e,t)=>e.selection.isCollapsed()?((e,t)=>{const n=Qi.fromRangeStart(e.selection.getRng());return Mu(t,e.getBody(),n).filter((e=>t?Op(e):Bp(e))).bind((e=>du(t?0:-1,e))).map((t=>()=>e.selection.select(t)))})(e,t):I.none(),nx=dr,ox=e=>nx(e)&&e.data[0]===Qa,rx=e=>nx(e)&&e.data[e.data.length-1]===Qa,sx=e=>{var t;return(null!==(t=e.ownerDocument)&&void 0!==t?t:document).createTextNode(Qa)},ax=(e,t)=>e?(e=>{var t;if(nx(e.previousSibling))return rx(e.previousSibling)||e.previousSibling.appendData(Qa),e.previousSibling;if(nx(e))return ox(e)||e.insertData(0,Qa),e;{const n=sx(e);return null===(t=e.parentNode)||void 0===t||t.insertBefore(n,e),n}})(t):(e=>{var t,n;if(nx(e.nextSibling))return ox(e.nextSibling)||e.nextSibling.insertData(0,Qa),e.nextSibling;if(nx(e))return rx(e)||e.appendData(Qa),e;{const o=sx(e);return e.nextSibling?null===(t=e.parentNode)||void 0===t||t.insertBefore(o,e.nextSibling):null===(n=e.parentNode)||void 0===n||n.appendChild(o),o}})(t),ix=T(ax,!0),lx=T(ax,!1),dx=(e,t)=>dr(e.container())?ax(t,e.container()):ax(t,e.getNode()),cx=(e,t)=>{const n=t.get();return n&&e.container()===n&&ri(n)},ux=(e,t)=>t.fold((t=>{Uc(e.get());const n=ix(t);return e.set(n),I.some(Qi(n,n.length-1))}),(t=>Hu(t).map((t=>{if(cx(t,e)){const t=e.get();return Qi(t,1)}{Uc(e.get());const n=dx(t,!0);return e.set(n),Qi(n,1)}}))),(t=>$u(t).map((t=>{if(cx(t,e)){const t=e.get();return Qi(t,t.length-1)}{Uc(e.get());const n=dx(t,!1);return e.set(n),Qi(n,n.length-1)}}))),(t=>{Uc(e.get());const n=lx(t);return e.set(n),I.some(Qi(n,1))})),mx=(e,t)=>{for(let n=0;n<e.length;n++){const o=e[n].apply(null,t);if(o.isSome())return o}return I.none()},fx=xl([{before:["element"]},{start:["element"]},{end:["element"]},{after:["element"]}]),gx=(e,t)=>iu(t,e)||e,px=(e,t,n)=>{const o=Bh(n),r=gx(t,o.container());return Th(e,r,o).fold((()=>zu(r,o).bind(T(Th,e,r)).map((e=>fx.before(e)))),I.none)},hx=(e,t)=>null===Wu(e,t),bx=(e,t,n)=>Th(e,t,n).filter(T(hx,t)),vx=(e,t,n)=>{const o=Ph(n);return bx(e,t,o).bind((e=>ju(e,o).isNone()?I.some(fx.start(e)):I.none()))},yx=(e,t,n)=>{const o=Bh(n);return bx(e,t,o).bind((e=>zu(e,o).isNone()?I.some(fx.end(e)):I.none()))},Cx=(e,t,n)=>{const o=Ph(n),r=gx(t,o.container());return Th(e,r,o).fold((()=>ju(r,o).bind(T(Th,e,r)).map((e=>fx.after(e)))),I.none)},wx=e=>!Ah(xx(e)),Ex=(e,t,n)=>mx([px,vx,yx,Cx],[e,t,n]).filter(wx),xx=e=>e.fold(R,R,R,R),kx=e=>e.fold(N("before"),N("start"),N("end"),N("after")),_x=e=>e.fold(fx.before,fx.before,fx.after,fx.after),Sx=e=>e.fold(fx.start,fx.start,fx.end,fx.end),Nx=(e,t,n,o,r,s)=>It(Th(t,n,o),Th(t,n,r),((t,o)=>t!==o&&((e,t,n)=>{const o=iu(t,e),r=iu(n,e);return C(o)&&o===r})(n,t,o)?fx.after(e?t:o):s)).getOr(s),Rx=(e,t)=>e.fold(M,(e=>{return o=t,!(kx(n=e)===kx(o)&&xx(n)===xx(o));var n,o})),Ax=(e,t)=>e?t.fold(_(I.some,fx.start),I.none,_(I.some,fx.after),I.none):t.fold(I.none,_(I.some,fx.before),I.none,_(I.some,fx.end)),Tx=(e,t,n)=>{const o=e?1:-1;return t.setRng(Qi(n.container(),n.offset()+o).toRange()),t.getSel().modify("move",e?"forward":"backward","word"),!0};var Ox;!function(e){e[e.Br=0]="Br",e[e.Block=1]="Block",e[e.Wrap=2]="Wrap",e[e.Eol=3]="Eol"}(Ox||(Ox={}));const Bx=(e,t)=>e===wu.Backwards?oe(t):t,Px=(e,t,n)=>e===wu.Forwards?t.next(n):t.prev(n),Dx=(e,t,n,o)=>pr(o.getNode(t===wu.Forwards))?Ox.Br:!1===lu(n,o)?Ox.Block:Ox.Wrap,Lx=(e,t,n,o)=>{const r=Bu(n);let s=o;const a=[];for(;s;){const n=Px(t,r,s);if(!n)break;if(pr(n.getNode(!1)))return t===wu.Forwards?{positions:Bx(t,a).concat([n]),breakType:Ox.Br,breakAt:I.some(n)}:{positions:Bx(t,a),breakType:Ox.Br,breakAt:I.some(n)};if(n.isVisible()){if(e(s,n)){const e=Dx(0,t,s,n);return{positions:Bx(t,a),breakType:e,breakAt:I.some(n)}}a.push(n),s=n}else s=n}return{positions:Bx(t,a),breakType:Ox.Eol,breakAt:I.none()}},Mx=(e,t,n,o)=>t(n,o).breakAt.map((o=>{const r=t(n,o).positions;return e===wu.Backwards?r.concat(o):[o].concat(r)})).getOr([]),Ix=(e,t)=>X(e,((e,n)=>e.fold((()=>I.some(n)),(o=>It(le(o.getClientRects()),le(n.getClientRects()),((e,r)=>{const s=Math.abs(t-e.left);return Math.abs(t-r.left)<=s?n:o})).or(e)))),I.none()),Fx=(e,t)=>le(t.getClientRects()).bind((t=>Ix(e,t.left))),Ux=T(Lx,Qi.isAbove,-1),zx=T(Lx,Qi.isBelow,1),jx=T(Mx,-1,Ux),Hx=T(Mx,1,zx),$x=(e,t)=>Ux(e,t).breakAt.isNone(),Vx=(e,t)=>zx(e,t).breakAt.isNone(),qx=(e,t)=>Fx(jx(e,t),t),Wx=(e,t)=>Fx(Hx(e,t),t),Kx=vr,Yx=(e,t)=>Math.abs(e.left-t),Gx=(e,t)=>Math.abs(e.right-t),Xx=(e,t)=>Be(e,((e,n)=>{const o=Math.min(Yx(e,t),Gx(e,t)),r=Math.min(Yx(n,t),Gx(n,t));return r===o&&_e(n,"node")&&Kx(n.node)||r<o?n:e})),Zx=e=>{const t=t=>V(t,(t=>{const n=gi(t);return n.node=e,n}));if(er(e))return t(e.getClientRects());if(dr(e)){const n=e.ownerDocument.createRange();return n.setStart(e,0),n.setEnd(e,e.data.length),t(n.getClientRects())}return[]},Qx=e=>te(e,Zx);var Jx;!function(e){e[e.Up=-1]="Up",e[e.Down=1]="Down"}(Jx||(Jx={}));const ek=(e,t,n,o,r,s)=>{let a=0;const i=[],l=o=>{let s=Qx([o]);-1===e&&(s=s.reverse());for(let e=0;e<s.length;e++){const o=s[e];if(!n(o,d)){if(i.length>0&&t(o,De(i))&&a++,o.line=a,r(o))return!0;i.push(o)}}return!1},d=De(s.getClientRects());if(!d)return i;const c=s.getNode();return c&&(l(c),((e,t,n,o)=>{let r=o;for(;r=au(r,e,Di,t);)if(n(r))return})(e,o,l,c)),i},tk=T(ek,Jx.Up,bi,vi),nk=T(ek,Jx.Down,vi,bi),ok=e=>De(e.getClientRects()),rk=e=>t=>((e,t)=>t.line>e)(e,t),sk=e=>t=>((e,t)=>t.line===e)(e,t),ak=(e,t)=>{e.selection.setRng(t),bg(e,e.selection.getRng())},ik=(e,t,n)=>I.some(IE(e,t,n)),lk=(e,t,n,o,r,s)=>{const a=t===wu.Forwards,i=Bu(e.getBody()),l=T(yu,a?i.next:i.prev),d=a?o:r;if(!n.collapsed){const o=Ci(n);if(s(o))return LE(t,e,o,t===wu.Backwards,!1);if($E(e)){const e=n.cloneRange();return e.collapse(t===wu.Backwards),I.from(e)}}const c=bu(t,e.getBody(),n);if(d(c))return ME(e,c.getNode(!a));let u=l(c);const m=mi(n);if(!u)return m?I.some(n):I.none();if(u=Oh(a,u),d(u))return LE(t,e,u.getNode(!a),a,!1);const f=l(u);return f&&d(f)&&Cu(u,f)?LE(t,e,f.getNode(!a),a,!1):m?ik(e,u.toRange(),!1):I.none()},dk=(e,t,n,o,r,s)=>{const a=bu(t,e.getBody(),n),i=De(a.getClientRects()),l=t===Jx.Down,d=e.getBody();if(!i)return I.none();if($E(e)){const e=l?Qi.fromRangeEnd(n):Qi.fromRangeStart(n);return(l?Wx:qx)(d,e).orThunk((()=>I.from(e))).map((e=>e.toRange()))}const c=(l?nk:tk)(d,rk(1),a),u=Y(c,sk(1)),m=i.left,f=Xx(u,m);if(f&&s(f.node)){const n=Math.abs(m-f.left),o=Math.abs(m-f.right);return LE(t,e,f.node,n<o,!1)}let g;if(g=o(a)?a.getNode():r(a)?a.getNode(!0):Ci(n),g){const n=((e,t,n,o)=>{const r=Bu(t);let s,a,i,l;const d=[];let c=0;1===e?(s=r.next,a=vi,i=bi,l=Qi.after(o)):(s=r.prev,a=bi,i=vi,l=Qi.before(o));const u=ok(l);do{if(!l.isVisible())continue;const e=ok(l);if(i(e,u))continue;d.length>0&&a(e,De(d))&&c++;const t=gi(e);if(t.position=l,t.line=c,n(t))return d;d.push(t)}while(l=s(l));return d})(t,d,rk(1),g);let o=Xx(Y(n,sk(1)),m);if(o)return ik(e,o.position.toRange(),!1);if(o=De(Y(n,sk(0))),o)return ik(e,o.position.toRange(),!1)}return 0===u.length?ck(e,l).filter(l?r:o).map((t=>IE(e,t.toRange(),!1))):I.none()},ck=(e,t)=>{const n=e.selection.getRng(),o=t?Qi.fromRangeEnd(n):Qi.fromRangeStart(n),r=(s=o.container(),a=e.getBody(),Qn(Cn(s),(e=>Yc(e.dom)),(e=>e.dom===a)).map((e=>e.dom)).getOr(a));var s,a;if(t){const e=zx(r,o);return de(e.positions)}{const e=Ux(r,o);return le(e.positions)}},uk=(e,t,n)=>ck(e,t).filter(n).exists((t=>(e.selection.setRng(t.toRange()),!0))),mk=(e,t)=>{const n=e.dom.createRng();n.setStart(t.container(),t.offset()),n.setEnd(t.container(),t.offset()),e.selection.setRng(n)},fk=(e,t)=>{e?t.setAttribute("data-mce-selected","inline-boundary"):t.removeAttribute("data-mce-selected")},gk=(e,t,n)=>ux(t,n).map((t=>(mk(e,t),n))),pk=(e,t,n)=>{const o=e.getBody(),r=((e,t,n)=>{const o=Qi.fromRangeStart(e);if(e.collapsed)return o;{const r=Qi.fromRangeEnd(e);return n?ju(t,r).getOr(r):zu(t,o).getOr(o)}})(e.selection.getRng(),o,n);return((e,t,n,o)=>{const r=Oh(e,o),s=Ex(t,n,r);return Ex(t,n,r).bind(T(Ax,e)).orThunk((()=>((e,t,n,o,r)=>{const s=Oh(e,r);return Mu(e,n,s).map(T(Oh,e)).fold((()=>o.map(_x)),(r=>Ex(t,n,r).map(T(Nx,e,t,n,s,r)).filter(T(Rx,o)))).filter(wx)})(e,t,n,s,o)))})(n,T(Rh,e),o,r).bind((n=>gk(e,t,n)))},hk=(e,t,n)=>!!Nd(e)&&pk(e,t,n).isSome(),bk=(e,t,n)=>!!Nd(t)&&((e,t)=>{const n=t.selection.getRng(),o=e?Qi.fromRangeEnd(n):Qi.fromRangeStart(n);return!!(e=>w(e.selection.getSel().modify))(t)&&(e&&ii(o)?Tx(!0,t.selection,o):!(e||!li(o))&&Tx(!1,t.selection,o))})(e,t),vk=e=>{const t=Br(null),n=T(Rh,e);return e.on("NodeChange",(o=>{Nd(e)&&(((e,t,n)=>{const o=V(zo(Cn(t.getRoot()),'*[data-mce-selected="inline-boundary"]'),(e=>e.dom)),r=Y(o,e),s=Y(n,e);q(re(r,s),T(fk,!1)),q(re(s,r),T(fk,!0))})(n,e.dom,o.parents),((e,t)=>{const n=t.get();if(e.selection.isCollapsed()&&!e.composing&&n){const o=Qi.fromRangeStart(e.selection.getRng());Qi.isTextPosition(o)&&!(e=>ii(e)||li(e))(o)&&(mk(e,Fc(n,o)),t.set(null))}})(e,t),((e,t,n,o)=>{if(t.selection.isCollapsed()){const r=Y(o,e);q(r,(o=>{const r=Qi.fromRangeStart(t.selection.getRng());Ex(e,t.getBody(),r).bind((e=>gk(t,n,e)))}))}})(n,e,t,o.parents))})),t},yk=T(bk,!0),Ck=T(bk,!1),wk=(e,t,n)=>{if(Nd(e)){const o=ck(e,t).getOrThunk((()=>{const n=e.selection.getRng();return t?Qi.fromRangeEnd(n):Qi.fromRangeStart(n)}));return Ex(T(Rh,e),e.getBody(),o).exists((t=>{const o=_x(t);return ux(n,o).exists((t=>(mk(e,t),!0)))}))}return!1},Ek=(e,t)=>n=>ux(t,n).map((t=>()=>mk(e,t))),xk=(e,t,n,o)=>{const r=e.getBody(),s=T(Rh,e);e.undoManager.ignore((()=>{e.selection.setRng(((e,t)=>{const n=document.createRange();return n.setStart(e.container(),e.offset()),n.setEnd(t.container(),t.offset()),n})(n,o)),Lh(e),Ex(s,r,Qi.fromRangeStart(e.selection.getRng())).map(Sx).bind(Ek(e,t)).each(D)})),e.nodeChanged()},kk=(e,t,n)=>{if(e.selection.isCollapsed()&&Nd(e)){const o=Qi.fromRangeStart(e.selection.getRng());return((e,t,n,o)=>{const r=((e,t)=>iu(t,e)||e)(e.getBody(),o.container()),s=T(Rh,e),a=Ex(s,r,o);return a.bind((e=>n?e.fold(N(I.some(Sx(e))),I.none,N(I.some(_x(e))),I.none):e.fold(I.none,N(I.some(_x(e))),I.none,N(I.some(Sx(e)))))).map(Ek(e,t)).getOrThunk((()=>{const i=Iu(n,r,o),l=i.bind((e=>Ex(s,r,e)));return It(a,l,(()=>Th(s,r,o).bind((t=>(e=>It(Hu(e),$u(e),((t,n)=>{const o=Oh(!0,t),r=Oh(!1,n);return zu(e,o).forall((e=>e.isEqual(r)))})).getOr(!0))(t)?I.some((()=>{Sh(e,n,Cn(t))})):I.none())))).getOrThunk((()=>l.bind((()=>i.map((r=>()=>{n?xk(e,t,o,r):xk(e,t,r,o)}))))))}))})(e,t,n,o)}return I.none()},_k=(e,t)=>{const n=Cn(e.getBody()),o=Cn(e.selection.getStart()),r=zp(o,n);return J(r,t).fold(N(r),(e=>r.slice(0,e)))},Sk=e=>1===jn(e),Nk=(e,t)=>{const n=T(av,e);return te(t,(e=>n(e)?[e.dom]:[]))},Rk=e=>{const t=(e=>_k(e,(t=>e.schema.isBlock($t(t)))))(e);return Nk(e,t)},Ak=(e,t)=>{const n=Y((e=>_k(e,(t=>e.schema.isBlock($t(t))||(e=>jn(e)>1)(t))))(e),Sk);return de(n).bind((o=>{const r=Qi.fromRangeStart(e.selection.getRng());return zh(t,r,o.dom)&&!jm(o)?I.some((()=>((e,t,n,o)=>{const r=Nk(t,o);if(0===r.length)Sh(t,e,n);else{const e=sv(n.dom,r);t.selection.setRng(e.toRange())}})(t,e,o,n))):I.none()}))},Tk=(e,t)=>{const n=e.selection.getStart(),o=((e,t)=>{const n=t.parentElement;return pr(t)&&!h(n)&&e.dom.isEmpty(n)})(e,n)||jm(Cn(n))?sv(n,t):((e,t)=>{const{caretContainer:n,caretPosition:o}=rv(t);return e.insertNode(n.dom),o})(e.selection.getRng(),t);e.selection.setRng(o.toRange())},Ok=e=>dr(e.startContainer),Bk=e=>{const t=e.selection.getRng();return(e=>0===e.startOffset&&Ok(e))(t)&&((e,t)=>{const n=t.startContainer.parentElement;return!h(n)&&av(e,Cn(n))})(e,t)&&(e=>(e=>(e=>{const t=e.startContainer.parentNode,n=e.endContainer.parentNode;return!h(t)&&!h(n)&&t.isEqualNode(n)})(e)&&(e=>{const t=e.endContainer;return e.endOffset===(dr(t)?t.length:t.childNodes.length)})(e))(e)||(e=>!e.endContainer.isEqualNode(e.commonAncestorContainer))(e))(t)},Pk=(e,t)=>e.selection.isCollapsed()?Ak(e,t):(e=>{if(Bk(e)){const t=Rk(e);return I.some((()=>{Lh(e),((e,t)=>{const n=re(t,Rk(e));n.length>0&&Tk(e,n)})(e,t)}))}return I.none()})(e),Dk=e=>((e=>{const t=e.selection.getRng();return t.collapsed&&(Ok(t)||e.dom.isEmpty(t.startContainer))&&!(e=>{return t=Cn(e.selection.getStart()),n=e.schema,jo(t,(e=>qu(e.dom)),(e=>n.isBlock($t(e))));var t,n})(e)})(e)&&Tk(e,[]),!0),Lk=(e,t,n)=>C(n)?I.some((()=>{e._selectionOverrides.hideFakeCaret(),Sh(e,t,Cn(n))})):I.none(),Mk=(e,t)=>e.selection.isCollapsed()?((e,t)=>{const n=t?Pp:Dp,o=t?wu.Forwards:wu.Backwards,r=bu(o,e.getBody(),e.selection.getRng());return n(r)?Lk(e,t,r.getNode(!t)):I.from(Oh(t,r)).filter((e=>n(e)&&Cu(r,e))).bind((n=>Lk(e,t,n.getNode(!t))))})(e,t):((e,t)=>{const n=e.selection.getNode();return wr(n)?Lk(e,t,n):I.none()})(e,t),Ik=e=>Ze(null!=e?e:"").getOr(0),Fk=(e,t)=>(e||"table"===$t(t)?"margin":"padding")+("rtl"===uo(t,"direction")?"-right":"-left"),Uk=e=>{const t=jk(e);return!e.mode.isReadOnly()&&(t.length>1||((e,t)=>ne(t,(t=>{const n=Fk(ud(e),t),o=fo(t,n).map(Ik).getOr(0);return"false"!==e.dom.getContentEditable(t.dom)&&o>0})))(e,t))},zk=e=>qa(e)||Wa(e),jk=e=>Y(_o(e.selection.getSelectedBlocks()),(e=>!zk(e)&&!(e=>Tn(e).exists(zk))(e)&&Jn(e,(e=>br(e.dom)||vr(e.dom))).exists((e=>br(e.dom))))),Hk=(e,t)=>{var n,o;const{dom:r}=e,s=md(e),a=null!==(o=null===(n=/[a-z%]+$/i.exec(s))||void 0===n?void 0:n[0])&&void 0!==o?o:"px",i=Ik(s),l=ud(e);q(jk(e),(e=>{((e,t,n,o,r,s)=>{const a=Fk(n,Cn(s)),i=Ik(e.getStyle(s,a));if("outdent"===t){const t=Math.max(0,i-o);e.setStyle(s,a,t?t+r:"")}else{const t=i+o+r;e.setStyle(s,a,t)}})(r,t,l,i,a,e.dom)}))},$k=e=>Hk(e,"outdent"),Vk=e=>{if(e.selection.isCollapsed()&&Uk(e)){const t=e.dom,n=e.selection.getRng(),o=Qi.fromRangeStart(n),r=t.getParent(n.startContainer,t.isBlock);if(null!==r&&qp(Cn(r),o,e.schema))return I.some((()=>$k(e)))}return I.none()},qk=(e,t,n)=>ue([Vk,GE,jE,(e,n)=>kk(e,t,n),OE,gb,tx,Mk,DE,Pk,ex],(t=>t(e,n))).filter((t=>e.selection.isEditable())),Wk=e=>void 0===e.touches||1!==e.touches.length?I.none():I.some(e.touches[0]),Kk=(e,t)=>ke(e,t.nodeName),Yk=(e,t)=>!!dr(t)||!!er(t)&&!(Kk(e.getBlockElements(),t)||rm(t)||Zr(e,t)||Ir(t)),Gk=(e,t)=>{if(dr(t)){if(0===t.data.length)return!0;if(/^\s+$/.test(t.data))return!t.nextSibling||Kk(e,t.nextSibling)||Ir(t.nextSibling)}return!1},Xk=e=>e.dom.create(ql(e),Wl(e)),Zk=(e,t,n)=>{const o=Cn(Xk(e)),r=Xa();yo(o,r),n(t,o);const s=document.createRange();return s.setStartBefore(r.dom),s.setEndBefore(r.dom),s},Qk=e=>t=>-1!==(" "+t.attr("class")+" ").indexOf(e),Jk=(e,t,n)=>function(o){const r=arguments,s=r[r.length-2],a=s>0?t.charAt(s-1):"";if('"'===a)return o;if(">"===a){const e=t.lastIndexOf("<",s);if(-1!==e&&-1!==t.substring(e,s).indexOf('contenteditable="false"'))return o}return'<span class="'+n+'" data-mce-content="'+e.dom.encode(r[0])+'">'+e.dom.encode("string"==typeof r[1]?r[1]:r[0])+"</span>"},e_=(e,t)=>ne(e,(e=>{const n=t.match(e);return null!==n&&n[0].length===t.length})),t_=(e,t)=>{t.hasAttribute("data-mce-caret")&&(ui(t),e.selection.setRng(e.selection.getRng()),e.selection.scrollIntoView(t))},n_=(e,t)=>{const n=(e=>no(Cn(e.getBody()),"*[data-mce-caret]").map((e=>e.dom)).getOrNull())(e);if(n)return"compositionstart"===t.type?(t.preventDefault(),t.stopPropagation(),void t_(e,n)):void(ai(n)&&(t_(e,n),e.undoManager.add()))},o_=vr,r_=(e,t,n)=>{const o=Bu(e.getBody()),r=T(yu,1===t?o.next:o.prev);if(n.collapsed){const o=e.dom.getParent(n.startContainer,"PRE");if(!o)return;if(!r(Qi.fromRangeStart(n))){const n=Cn((e=>{const t=e.dom.create(ql(e));return t.innerHTML='<br data-mce-bogus="1">',t})(e));1===t?bo(Cn(o),n):ho(Cn(o),n),e.selection.select(n.dom,!0),e.selection.collapse()}}},s_=(e,t)=>((e,t)=>{const n=t?wu.Forwards:wu.Backwards,o=e.selection.getRng();return((e,t,n)=>lk(t,e,n,Ip,Fp,o_))(n,e,o).orThunk((()=>(r_(e,n,o),I.none())))})(e,((e,t)=>{const n=t?e.getEnd(!0):e.getStart(!0);return Ah(n)?!t:t})(e.selection,t)).exists((t=>(ak(e,t),!0))),a_=(e,t)=>((e,t)=>{const n=t?1:-1,o=e.selection.getRng();return((e,t,n)=>dk(t,e,n,(e=>Ip(e)||Lp(e)),(e=>Fp(e)||Mp(e)),o_))(n,e,o).orThunk((()=>(r_(e,n,o),I.none())))})(e,t).exists((t=>(ak(e,t),!0))),i_=(e,t)=>uk(e,t,t?Fp:Ip),l_=(e,t)=>HE(e,!t).map((n=>{const o=n.toRange(),r=e.selection.getRng();return t?o.setStart(r.startContainer,r.startOffset):o.setEnd(r.endContainer,r.endOffset),o})).exists((t=>(ak(e,t),!0))),d_=e=>H(["figcaption"],$t(e)),c_=(e,t)=>!!e.selection.isCollapsed()&&((e,t)=>{const n=Cn(e.getBody()),o=Qi.fromRangeStart(e.selection.getRng());return((e,t,n)=>{const o=T(_n,t);return Jn(Cn(e.container()),(e=>n.isBlock($t(e))),o).filter(d_)})(o,n,e.schema).exists((()=>{if(((e,t,n)=>t?Vx(e.dom,n):$x(e.dom,n))(n,t,o)){const o=Zk(e,n,t?yo:vo);return e.selection.setRng(o),!0}return!1}))})(e,t),u_=(e,t)=>((e,t)=>t?I.from(e.dom.getParent(e.selection.getNode(),"details")).map((t=>((e,t)=>{const n=e.selection.getRng(),o=Qi.fromRangeStart(n);return!(e.getBody().lastChild!==t||!Vx(t,o)||(e.execCommand("InsertNewBlockAfter"),0))})(e,t))).getOr(!1):I.from(e.dom.getParent(e.selection.getNode(),"summary")).bind((t=>I.from(e.dom.getParent(t,"details")).map((n=>((e,t,n)=>{const o=e.selection.getRng(),r=Qi.fromRangeStart(o);return!(e.getBody().firstChild!==t||!$x(n,r)||(e.execCommand("InsertNewBlockBefore"),0))})(e,n,t))))).getOr(!1))(e,t),m_={shiftKey:!1,altKey:!1,ctrlKey:!1,metaKey:!1,keyCode:0},f_=(e,t)=>t.keyCode===e.keyCode&&t.shiftKey===e.shiftKey&&t.altKey===e.altKey&&t.ctrlKey===e.ctrlKey&&t.metaKey===e.metaKey,g_=(e,...t)=>()=>e.apply(null,t),p_=(e,t)=>Q(((e,t)=>te((e=>V(e,(e=>({...m_,...e}))))(e),(e=>f_(e,t)?[e]:[])))(e,t),(e=>e.action())),h_=(e,t)=>ue(((e,t)=>te((e=>V(e,(e=>({...m_,...e}))))(e),(e=>f_(e,t)?[e]:[])))(e,t),(e=>e.action())),b_=(e,t)=>{const n=t?wu.Forwards:wu.Backwards,o=e.selection.getRng();return lk(e,n,o,Pp,Dp,wr).exists((t=>(ak(e,t),!0)))},v_=(e,t)=>{const n=t?1:-1,o=e.selection.getRng();return dk(e,n,o,Pp,Dp,wr).exists((t=>(ak(e,t),!0)))},y_=(e,t)=>uk(e,t,t?Dp:Pp),C_=xl([{none:["current"]},{first:["current"]},{middle:["current","target"]},{last:["current"]}]),w_={...C_,none:e=>C_.none(e)},E_=(e,t,n)=>te(In(e),(e=>xn(e,t)?n(e)?[e]:[]:E_(e,t,n))),x_=(e,t)=>oo(e,"table",t),k_=(e,t,n,o,r=M)=>{const s=1===o;if(!s&&n<=0)return w_.first(e[0]);if(s&&n>=e.length-1)return w_.last(e[e.length-1]);{const s=n+o,a=e[s];return r(a)?w_.middle(t,a):k_(e,t,s,o,r)}},__=(e,t)=>x_(e,t).bind((t=>{const n=E_(t,"th,td",M);return J(n,(t=>_n(e,t))).map((e=>({index:e,all:n})))})),S_=["img","br"],N_=e=>{return(t=e,za.getOption(t)).filter((e=>0!==e.trim().length||e.indexOf(Wo)>-1)).isSome()||H(S_,$t(e))||(e=>Wt(e)&&"false"===tn(e,"contenteditable"))(e);var t},R_=(e,t,n,o,r)=>{const s=zo(Cn(n),"td,th,caption").map((e=>e.dom)),a=Y(((e,t)=>te(t,(t=>{const n=((e,t)=>({left:e.left-t,top:e.top-t,right:e.right+-2,bottom:e.bottom+-2,width:e.width+t,height:e.height+t}))(gi(t.getBoundingClientRect()),-1);return[{x:n.left,y:e(n),cell:t},{x:n.right,y:e(n),cell:t}]})))(e,s),(e=>t(e,r)));return((e,t,n)=>X(e,((e,o)=>e.fold((()=>I.some(o)),(e=>{const r=Math.sqrt(Math.abs(e.x-t)+Math.abs(e.y-n)),s=Math.sqrt(Math.abs(o.x-t)+Math.abs(o.y-n));return I.some(s<r?o:e)}))),I.none()))(a,o,r).map((e=>e.cell))},A_=T(R_,(e=>e.bottom),((e,t)=>e.y<t)),T_=T(R_,(e=>e.top),((e,t)=>e.y>t)),O_=(e,t,n)=>{const o=e(t,n);return(e=>e.breakType===Ox.Wrap&&0===e.positions.length)(o)||!pr(n.getNode())&&(e=>e.breakType===Ox.Br&&1===e.positions.length)(o)?!((e,t,n)=>n.breakAt.exists((n=>e(t,n).breakAt.isSome())))(e,t,o):o.breakAt.isNone()},B_=T(O_,Ux),P_=T(O_,zx),D_=(e,t,n,o)=>{const r=e.selection.getRng(),s=t?1:-1;return!(!qc()||!((e,t,n)=>{const o=Qi.fromRangeStart(t);return Uu(!e,n).exists((e=>e.isEqual(o)))})(t,r,n)||(LE(s,e,n,!t,!1).each((t=>{ak(e,t)})),0))},L_=(e,t,n)=>{const o=((e,t)=>{const n=t.getNode(e);return ar(n)?I.some(n):I.none()})(!!t,n),r=!1===t;o.fold((()=>ak(e,n.toRange())),(o=>Uu(r,e.getBody()).filter((e=>e.isEqual(n))).fold((()=>ak(e,n.toRange())),(n=>((e,t,n)=>{t.undoManager.transact((()=>{const o=e?bo:ho,r=Zk(t,Cn(n),o);ak(t,r)}))})(t,e,o)))))},M_=(e,t,n,o)=>{const r=e.selection.getRng(),s=Qi.fromRangeStart(r),a=e.getBody();if(!t&&B_(o,s)){const o=((e,t,n)=>((e,t)=>le(t.getClientRects()).bind((t=>A_(e,t.left,t.top))).bind((e=>{return Fx($u(n=e).map((e=>Ux(n,e).positions.concat(e))).getOr([]),t);var n})))(t,n).orThunk((()=>le(n.getClientRects()).bind((n=>Ix(jx(e,Qi.before(t)),n.left))))).getOr(Qi.before(t)))(a,n,s);return L_(e,t,o),!0}if(t&&P_(o,s)){const o=((e,t,n)=>((e,t)=>de(t.getClientRects()).bind((t=>T_(e,t.left,t.top))).bind((e=>{return Fx(Hu(n=e).map((e=>[e].concat(zx(n,e).positions))).getOr([]),t);var n})))(t,n).orThunk((()=>le(n.getClientRects()).bind((n=>Ix(Hx(e,Qi.after(t)),n.left))))).getOr(Qi.after(t)))(a,n,s);return L_(e,t,o),!0}return!1},I_=(e,t,n)=>I.from(e.dom.getParent(e.selection.getNode(),"td,th")).bind((o=>I.from(e.dom.getParent(o,"table")).map((r=>n(e,t,r,o))))).getOr(!1),F_=(e,t)=>I_(e,t,D_),U_=(e,t)=>I_(e,t,M_),z_=(e,t,n)=>n.fold(I.none,I.none,((e,t)=>{return(n=t,eo(n,N_)).map((e=>(e=>{const t=Df.exact(e,0,e,0);return Uf(t)})(e)));var n}),(n=>(e.execCommand("mceTableInsertRowAfter"),j_(e,t,n)))),j_=(e,t,n)=>{return z_(e,t,(r=ro,__(o=n,void 0).fold((()=>w_.none(o)),(e=>k_(e.all,o,e.index,1,r)))));var o,r},H_=(e,t,n)=>{return z_(e,t,(r=ro,__(o=n,void 0).fold((()=>w_.none()),(e=>k_(e.all,o,e.index,-1,r)))));var o,r},$_=(e,t)=>{const n=["table","li","dl"],o=Cn(e.getBody()),r=e=>{const t=$t(e);return _n(e,o)||H(n,t)},s=e.selection.getRng();return((e,t)=>((e,t,n=L)=>n(t)?I.none():H(e,$t(t))?I.some(t):to(t,e.join(","),(e=>xn(e,"table")||n(e))))(["td","th"],e,t))(Cn(t?s.endContainer:s.startContainer),r).map((n=>(x_(n,r).each((t=>{e.model.table.clearSelectedCells(t.dom)})),e.selection.collapse(!t),(t?j_:H_)(e,r,n).each((t=>{e.selection.setRng(t)})),!0))).getOr(!1)},V_=(e,t)=>({container:e,offset:t}),q_=ma.DOM,W_=e=>t=>e===t?-1:0,K_=(e,t,n)=>{if(dr(e)&&t>=0)return I.some(V_(e,t));{const o=Ua(q_);return I.from(o.backwards(e,t,W_(e),n)).map((e=>V_(e.container,e.container.data.length)))}},Y_=(e,t,n)=>{if(!dr(e))return I.none();const o=e.data;if(t>=0&&t<=o.length)return I.some(V_(e,t));{const o=Ua(q_);return I.from(o.backwards(e,t,W_(e),n)).bind((e=>{const o=e.container.data;return Y_(e.container,t+o.length,n)}))}},G_=(e,t,n)=>{if(!dr(e))return I.none();const o=e.data;if(t<=o.length)return I.some(V_(e,t));{const r=Ua(q_);return I.from(r.forwards(e,t,W_(e),n)).bind((e=>G_(e.container,t-o.length,n)))}},X_=(e,t,n,o,r)=>{const s=Ua(e,(e=>t=>e.isBlock(t)||H(["BR","IMG","HR","INPUT"],t.nodeName)||"false"===e.getContentEditable(t))(e));return I.from(s.backwards(t,n,o,r))},Z_=e=>""!==e&&-1!==" \xa0\f\n\r\t\v".indexOf(e),Q_=(e,t)=>e.substring(t.length),J_=(e,t,n,o=!1)=>{if(!(r=t).collapsed||!dr(r.startContainer))return I.none();var r;const s={text:"",offset:0},a=e.getParent(t.startContainer,e.isBlock)||e.getRoot();return X_(e,t.startContainer,t.startOffset,((e,t,r)=>(s.text=r+s.text,s.offset+=t,((e,t,n,o=!1)=>{let r;const s=n.charAt(0);for(r=t-1;r>=0;r--){const a=e.charAt(r);if(!o&&Z_(a))return I.none();if(s===a&&He(e,n,r,t))break}return I.some(r)})(s.text,s.offset,n,o).getOr(t))),a).bind((e=>{const o=t.cloneRange();if(o.setStart(e.container,e.offset),o.setEnd(t.endContainer,t.endOffset),o.collapsed)return I.none();const r=(e=>ei(e.toString().replace(/\u00A0/g," ")))(o);return 0!==r.lastIndexOf(n)?I.none():I.some({text:Q_(r,n),range:o,trigger:n})}))},eS=e=>{if((e=>3===e.nodeType)(e))return V_(e,e.data.length);{const t=e.childNodes;return t.length>0?eS(t[t.length-1]):V_(e,t.length)}},tS=(e,t)=>{const n=e.childNodes;return n.length>0&&t<n.length?tS(n[t],0):n.length>0&&(e=>1===e.nodeType)(e)&&n.length===t?eS(n[n.length-1]):V_(e,t)},nS=(e,t,n,o={})=>{var r;const s=t(),a=null!==(r=e.selection.getRng().startContainer.nodeValue)&&void 0!==r?r:"",i=Y(s.lookupByTrigger(n.trigger),(t=>n.text.length>=t.minChars&&t.matches.getOrThunk((()=>(e=>t=>{const n=tS(t.startContainer,t.startOffset);return!((e,t)=>{var n;const o=null!==(n=e.getParent(t.container,e.isBlock))&&void 0!==n?n:e.getRoot();return X_(e,t.container,t.offset,((e,t)=>0===t?-1:t),o).filter((e=>{const t=e.container.data.charAt(e.offset-1);return!Z_(t)})).isSome()})(e,n)})(e.dom)))(n.range,a,n.text)));if(0===i.length)return I.none();const l=Promise.all(V(i,(e=>e.fetch(n.text,e.maxResults,o).then((t=>({matchText:n.text,items:t,columns:e.columns,onAction:e.onAction,highlightOn:e.highlightOn}))))));return I.some({lookupData:l,context:n})};var oS;!function(e){e[e.Error=0]="Error",e[e.Value=1]="Value"}(oS||(oS={}));const rS=(e,t,n)=>e.stype===oS.Error?t(e.serror):n(e.svalue),sS=e=>({stype:oS.Value,svalue:e}),aS=e=>({stype:oS.Error,serror:e}),iS=rS,lS=e=>f(e)&&fe(e).length>100?" removed due to size":JSON.stringify(e,null,2),dS=(e,t)=>aS([{path:e,getErrorInfo:t}]),cS=(e,t)=>({extract:(n,o)=>xe(o,e).fold((()=>((e,t)=>dS(e,(()=>'Choice schema did not contain choice key: "'+t+'"')))(n,e)),(e=>((e,t,n,o)=>xe(n,o).fold((()=>((e,t,n)=>dS(e,(()=>'The chosen schema: "'+n+'" did not exist in branches: '+lS(t))))(e,n,o)),(n=>n.extract(e.concat(["branch: "+o]),t))))(n,o,t,e))),toString:()=>"chooseOn("+e+"). Possible values: "+fe(t)}),uS=e=>(...t)=>{if(0===t.length)throw new Error("Can't merge zero objects");const n={};for(let o=0;o<t.length;o++){const r=t[o];for(const t in r)ke(r,t)&&(n[t]=e(n[t],r[t]))}return n},mS=uS(((e,t)=>g(e)&&g(t)?mS(e,t):t)),fS=uS(((e,t)=>t)),gS=e=>({tag:"defaultedThunk",process:N(e)}),pS=e=>{const t=(e=>{const t=[],n=[];return q(e,(e=>{rS(e,(e=>n.push(e)),(e=>t.push(e)))})),{values:t,errors:n}})(e);return t.errors.length>0?(n=t.errors,_(aS,ee)(n)):sS(t.values);var n},hS=(e,t,n)=>{switch(e.tag){case"field":return t(e.key,e.newKey,e.presence,e.prop);case"custom":return n(e.newKey,e.instantiator)}},bS=e=>({extract:(t,n)=>{return o=e(n),r=e=>((e,t)=>dS(e,N(t)))(t,e),o.stype===oS.Error?r(o.serror):o;var o,r},toString:N("val")}),vS=bS(sS),yS=(e,t,n,o)=>o(xe(e,t).getOrThunk((()=>n(e)))),CS=(e,t,n,o,r)=>{const s=e=>r.extract(t.concat([o]),e),a=e=>e.fold((()=>sS(I.none())),(e=>{const n=r.extract(t.concat([o]),e);return s=n,a=I.some,s.stype===oS.Value?{stype:oS.Value,svalue:a(s.svalue)}:s;var s,a}));switch(e.tag){case"required":return((e,t,n,o)=>xe(t,n).fold((()=>((e,t,n)=>dS(e,(()=>'Could not find valid *required* value for "'+t+'" in '+lS(n))))(e,n,t)),o))(t,n,o,s);case"defaultedThunk":return yS(n,o,e.process,s);case"option":return((e,t,n)=>n(xe(e,t)))(n,o,a);case"defaultedOptionThunk":return((e,t,n,o)=>o(xe(e,t).map((t=>!0===t?n(e):t))))(n,o,e.process,a);case"mergeWithThunk":return yS(n,o,N({}),(t=>{const o=mS(e.process(n),t);return s(o)}))}},wS=e=>({extract:(t,n)=>((e,t,n)=>{const o={},r=[];for(const s of n)hS(s,((n,s,a,i)=>{const l=CS(a,e,t,n,i);iS(l,(e=>{r.push(...e)}),(e=>{o[s]=e}))}),((e,n)=>{o[e]=n(t)}));return r.length>0?aS(r):sS(o)})(t,n,e),toString:()=>{const t=V(e,(e=>hS(e,((e,t,n,o)=>e+" -> "+o.toString()),((e,t)=>"state("+e+")"))));return"obj{\n"+t.join("\n")+"}"}}),ES=e=>({extract:(t,n)=>{const o=V(n,((n,o)=>e.extract(t.concat(["["+o+"]"]),n)));return pS(o)},toString:()=>"array("+e.toString()+")"}),xS=(e,t,n)=>{return o=((e,t,n)=>((e,t)=>e.stype===oS.Error?{stype:oS.Error,serror:t(e.serror)}:e)(t.extract([e],n),(e=>({input:n,errors:e}))))(e,t,n),rS(o,El.error,El.value);var o},kS=(e,t)=>cS(e,he(t,wS)),_S=N(vS),SS=(e,t)=>bS((n=>{const o=typeof n;return e(n)?sS(n):aS(`Expected type: ${t} but got: ${o}`)})),NS=SS(E,"number"),RS=SS(m,"string"),AS=SS(b,"boolean"),TS=SS(w,"function"),OS=(e,t,n,o)=>({tag:"field",key:e,newKey:t,presence:n,prop:o}),BS=(e,t)=>({tag:"custom",newKey:e,instantiator:t}),PS=(e,t)=>OS(e,e,{tag:"required",process:{}},t),DS=e=>PS(e,RS),LS=e=>PS(e,TS),MS=(e,t)=>OS(e,e,{tag:"option",process:{}},t),IS=e=>MS(e,RS),FS=(e,t,n)=>OS(e,e,gS(t),n),US=(e,t)=>FS(e,t,NS),zS=(e,t,n)=>FS(e,t,(e=>{return t=t=>H(e,t)?El.value(t):El.error(`Unsupported value: "${t}", choose one of "${e.join(", ")}".`),bS((e=>t(e).fold(aS,sS)));var t})(n)),jS=(e,t)=>FS(e,t,AS),HS=(e,t)=>FS(e,t,TS),$S=DS("type"),VS=LS("fetch"),qS=LS("onAction"),WS=HS("onSetup",(()=>k)),KS=IS("text"),YS=IS("icon"),GS=IS("tooltip"),XS=IS("label"),ZS=jS("active",!1),QS=jS("enabled",!0),JS=jS("primary",!1),eN=e=>((e,t)=>FS("type",t,RS))(0,e),tN=wS([$S,DS("trigger"),US("minChars",1),(1,((e,t)=>OS(e,e,gS(1),_S()))("columns")),US("maxResults",10),("matches",MS("matches",TS)),VS,qS,(nN=RS,FS("highlightOn",[],ES(nN)))]);var nN;const oN=[QS,GS,YS,KS,WS],rN=[ZS].concat(oN),sN=[HS("predicate",L),zS("scope","node",["node","editor"]),zS("position","selection",["node","selection","line"])],aN=oN.concat([eN("contextformbutton"),JS,qS,BS("original",R)]),iN=rN.concat([eN("contextformbutton"),JS,qS,BS("original",R)]),lN=oN.concat([eN("contextformbutton")]),dN=rN.concat([eN("contextformtogglebutton")]),cN=kS("type",{contextformbutton:aN,contextformtogglebutton:iN});wS([eN("contextform"),HS("initValue",N("")),XS,((e,t)=>OS(e,e,{tag:"required",process:{}},ES(t)))("commands",cN),MS("launch",kS("type",{contextformbutton:lN,contextformtogglebutton:dN}))].concat(sN));const uN=e=>{const t=e.ui.registry.getAll().popups,n=he(t,(e=>{return(t=e,xS("Autocompleter",tN,t)).fold((e=>{throw new Error("Errors: \n"+(e=>{const t=e.length>10?e.slice(0,10).concat([{path:[],getErrorInfo:N("... (only showing first ten failures)")}]):e;return V(t,(e=>"Failed path: ("+e.path.join(" > ")+")\n"+e.getErrorInfo()))})((t=e).errors).join("\n")+"\n\nInput object: "+lS(t.input));var t}),R);var t})),o=Se(we(n,(e=>e.trigger))),r=Ee(n);return{dataset:n,triggers:o,lookupByTrigger:e=>Y(r,(t=>t.trigger===e))}},mN=e=>{const t=Dr(),n=Br(!1),o=t.isSet,r=()=>{o()&&((e=>{e.dispatch("AutocompleterEnd")})(e),n.set(!1),t.clear())},s=Le((()=>uN(e))),a=a=>{(n=>t.get().map((t=>J_(e.dom,e.selection.getRng(),t.trigger,!0).bind((t=>nS(e,s,t,n))))).getOrThunk((()=>((e,t)=>{const n=t(),o=e.selection.getRng();return((e,t,n)=>ue(n.triggers,(n=>J_(e,t,n))))(e.dom,o,n).bind((n=>nS(e,t,n)))})(e,s))))(a).fold(r,(r=>{(e=>{o()||t.set({trigger:e.trigger,matchLength:e.text.length})})(r.context),r.lookupData.then((o=>{t.get().map((s=>{const a=r.context;s.trigger===a.trigger&&(t.set({...s,matchLength:a.text.length}),n.get()?(bf(e,{range:a.range}),((e,t)=>{e.dispatch("AutocompleterUpdate",t)})(e,{lookupData:o})):(n.set(!0),bf(e,{range:a.range}),((e,t)=>{e.dispatch("AutocompleterStart",t)})(e,{lookupData:o})))}))}))}))},i=()=>t.get().bind((({trigger:t})=>{const o=e.selection.getRng();return J_(e.dom,o,t,n.get()).filter((({range:e})=>((e,t)=>{const n=e.compareBoundaryPoints(window.Range.START_TO_START,t),o=e.compareBoundaryPoints(window.Range.END_TO_END,t);return n>=0&&o<=0})(o,e))).map((({range:e})=>e))}));e.addCommand("mceAutocompleterReload",((e,t)=>{const n=f(t)?t.fetchOptions:{};a(n)})),e.addCommand("mceAutocompleterClose",r),e.addCommand("mceAutocompleterRefreshActiveRange",(()=>{i().each((t=>{bf(e,{range:t})}))})),e.editorCommands.addQueryStateHandler("mceAutoCompleterInRange",(()=>i().isSome())),((e,t)=>{const n=wa(t.load,50);e.on("input",(t=>{("insertCompositionText"!==t.inputType||e.composing)&&n.throttle()})),e.on("keydown",(e=>{const o=e.which;8===o?n.throttle():27===o?(n.cancel(),t.cancelIfNecessary()):38!==o&&40!==o||n.cancel()}),!0),e.on("remove",n.cancel)})(e,{cancelIfNecessary:r,load:a})},fN=xt().browser.isSafari(),gN=e=>Za(Cn(e)),pN=(e,t)=>{var n;return 0===e.startOffset&&e.endOffset===(null===(n=t.textContent)||void 0===n?void 0:n.length)},hN=(e,t)=>I.from(e.getParent(t.container(),"details")),bN=(e,t)=>hN(e,t).isSome(),vN=(e,t)=>{const n=t.getNode();v(n)||e.selection.setCursorLocation(n,t.offset())},yN=(e,t,n)=>{const o=e.dom.getParent(t.container(),"details");if(o&&!o.open){const t=e.dom.select("summary",o)[0];t&&(n?Hu(t):$u(t)).each((t=>vN(e,t)))}else vN(e,t)},CN=(e,t,n)=>{const{dom:o,selection:r}=e,s=e.getBody();if("character"===n){const n=Qi.fromRangeStart(r.getRng()),a=o.getParent(n.container(),o.isBlock),i=hN(o,n),l=a&&o.isEmpty(a),d=h(null==a?void 0:a.previousSibling),c=h(null==a?void 0:a.nextSibling);return!!(l&&(t?c:d)&&Iu(!t,s,n).exists((e=>bN(o,e)&&!Mt(i,hN(o,e)))))||Iu(t,s,n).fold(L,(n=>{const r=hN(o,n);if(bN(o,n)&&!Mt(i,r)){if(t||yN(e,n,!1),a&&l){if(t&&d)return!0;if(!t&&c)return!0;yN(e,n,t),e.dom.remove(a)}return!0}return!1}))}return!1},wN=(e,t,n,o)=>{const r=e.selection.getRng(),s=Qi.fromRangeStart(r),a=e.getBody();return"selection"===o?((e,t)=>{const n=t.startSummary.exists((t=>t.contains(e.startContainer))),o=t.startSummary.exists((t=>t.contains(e.endContainer))),r=t.startDetails.forall((e=>t.endDetails.forall((t=>e!==t))));return(n||o)&&!(n&&o)||r})(r,t):n?((e,t)=>t.startSummary.exists((t=>((e,t)=>$u(t).exists((n=>pr(n.getNode())&&ju(t,n).exists((t=>t.isEqual(e)))||n.isEqual(e))))(e,t))))(s,t)||((e,t,n)=>n.startDetails.exists((n=>zu(e,t).forall((e=>!n.contains(e.container()))))))(a,s,t):((e,t)=>t.startSummary.exists((t=>((e,t)=>Hu(t).exists((t=>t.isEqual(e))))(e,t))))(s,t)||((e,t)=>t.startDetails.exists((n=>ju(n,e).forall((n=>t.startSummary.exists((t=>!t.contains(e.container())&&t.contains(n.container()))))))))(s,t)},EN=(e,t,n)=>((e,t,n)=>((e,t)=>{const n=I.from(e.getParent(t.startContainer,"details")),o=I.from(e.getParent(t.endContainer,"details"));if(n.isSome()||o.isSome()){const t=n.bind((t=>I.from(e.select("summary",t)[0])));return I.some({startSummary:t,startDetails:n,endDetails:o})}return I.none()})(e.dom,e.selection.getRng()).fold((()=>CN(e,t,n)),(o=>wN(e,o,t,n)||CN(e,t,n))))(e,t,n)||fN&&((e,t,n)=>{const o=e.selection,r=o.getNode(),s=o.getRng(),a=Qi.fromRangeStart(s);return!!kr(r)&&("selection"===n&&pN(s,r)||zh(t,a,r)?gN(r):e.undoManager.transact((()=>{const s=o.getSel();let{anchorNode:a,anchorOffset:i,focusNode:l,focusOffset:d}=null!=s?s:{};const c=()=>{C(a)&&C(i)&&C(l)&&C(d)&&(null==s||s.setBaseAndExtent(a,i,l,d))},u=(e,t)=>{q(e.childNodes,(e=>{Cm(e)&&t.appendChild(e)}))},m=e.dom.create("span",{"data-mce-bogus":"1"});u(r,m),r.appendChild(m),c(),"word"!==n&&"line"!==n||null==s||s.modify("extend",t?"right":"left",n),!o.isCollapsed()&&pN(o.getRng(),m)?gN(r):(e.execCommand(t?"ForwardDelete":"Delete"),a=null==s?void 0:s.anchorNode,i=null==s?void 0:s.anchorOffset,l=null==s?void 0:s.focusNode,d=null==s?void 0:s.focusOffset,u(m,r),c()),e.dom.remove(m)})),!0)})(e,t,n)?I.some(k):I.none(),xN=e=>(t,n,o={})=>{const r=t.getBody(),s={bubbles:!0,composed:!0,data:null,isComposing:!1,detail:0,view:null,target:r,currentTarget:r,eventPhase:Event.AT_TARGET,originalTarget:r,explicitOriginalTarget:r,isTrusted:!1,srcElement:r,cancelable:!1,preventDefault:k,inputType:n},a=Gs(new InputEvent(e));return t.dispatch(e,{...a,...s,...o})},kN=xN("input"),_N=xN("beforeinput"),SN=xt(),NN=SN.os,RN=NN.isMacOS()||NN.isiOS(),AN=SN.browser.isFirefox(),TN=(e,t)=>{const n=e.dom,o=e.schema.getMoveCaretBeforeOnEnterElements();if(!t)return;if(/^(LI|DT|DD)$/.test(t.nodeName)){const e=(e=>{for(;e;){if(er(e)||dr(e)&&e.data&&/[\r\n\s]/.test(e.data))return e;e=e.nextSibling}return null})(t.firstChild);e&&/^(UL|OL|DL)$/.test(e.nodeName)&&t.insertBefore(n.doc.createTextNode(Wo),t.firstChild)}const r=n.createRng();if(t.normalize(),t.hasChildNodes()){const e=new Vo(t,t);let n,s=t;for(;n=e.current();){if(dr(n)){r.setStart(n,0),r.setEnd(n,0);break}if(o[n.nodeName.toLowerCase()]){r.setStartBefore(n),r.setEndBefore(n);break}s=n,n=e.next()}n||(r.setStart(s,0),r.setEnd(s,0))}else pr(t)?t.nextSibling&&n.isBlock(t.nextSibling)?(r.setStartBefore(t),r.setEndBefore(t)):(r.setStartAfter(t),r.setEndAfter(t)):(r.setStart(t,0),r.setEnd(t,0));e.selection.setRng(r),bg(e,r)},ON=(e,t)=>{const n=e.getRoot();let o,r=t;for(;r!==n&&r&&"false"!==e.getContentEditable(r);){if("true"===e.getContentEditable(r)){o=r;break}r=r.parentNode}return r!==n?o:n},BN=e=>I.from(e.dom.getParent(e.selection.getStart(!0),e.dom.isBlock)),PN=e=>{e.innerHTML='<br data-mce-bogus="1">'},DN=(e,t)=>{ql(e).toLowerCase()===t.tagName.toLowerCase()&&((e,t,n)=>{const o=e.dom;I.from(n.style).map(o.parseStyle).each((e=>{const n={...go(Cn(t)),...e};o.setStyles(t,n)}));const r=I.from(n.class).map((e=>e.split(/\s+/))),s=I.from(t.className).map((e=>Y(e.split(/\s+/),(e=>""!==e))));It(r,s,((e,n)=>{const r=Y(n,(t=>!H(e,t))),s=[...e,...r];o.setAttrib(t,"class",s.join(" "))}));const a=["style","class"],i=Ce(n,((e,t)=>!H(a,t)));o.setAttribs(t,i)})(e,t,Wl(e))},LN=(e,t,n,o,r=!0,s,a)=>{const i=e.dom,l=e.schema,d=ql(e),c=n?n.nodeName.toUpperCase():"";let u=t;const m=l.getTextInlineElements();let f;f=s||"TABLE"===c||"HR"===c?i.create(s||d,a||{}):n.cloneNode(!1);let g=f;if(r){do{if(m[u.nodeName]){if(qu(u)||rm(u))continue;const e=u.cloneNode(!1);i.setAttrib(e,"id",""),f.hasChildNodes()?(e.appendChild(f.firstChild),f.appendChild(e)):(g=e,f.appendChild(e))}}while((u=u.parentNode)&&u!==o)}else i.setAttrib(f,"style",null),i.setAttrib(f,"class",null);return DN(e,f),PN(g),f},MN=(e,t)=>{const n=null==e?void 0:e.parentNode;return C(n)&&n.nodeName===t},IN=e=>C(e)&&/^(OL|UL|LI)$/.test(e.nodeName),FN=e=>C(e)&&/^(LI|DT|DD)$/.test(e.nodeName),UN=e=>{const t=e.parentNode;return FN(t)?t:e},zN=(e,t,n)=>{let o=e[n?"firstChild":"lastChild"];for(;o&&!er(o);)o=o[n?"nextSibling":"previousSibling"];return o===t},jN=e=>X(we(go(Cn(e)),((e,t)=>`${t}: ${e};`)),((e,t)=>e+t),""),HN=(e,t)=>t&&"A"===t.nodeName&&e.isEmpty(t),$N=(e,t)=>e.nodeName===t||e.previousSibling&&e.previousSibling.nodeName===t,VN=(e,t)=>C(t)&&e.isBlock(t)&&!/^(TD|TH|CAPTION|FORM)$/.test(t.nodeName)&&!/^(fixed|absolute)/i.test(t.style.position)&&e.isEditable(t.parentNode)&&"false"!==e.getContentEditable(t),qN=(e,t,n)=>dr(t)?e?1===n&&t.data.charAt(n-1)===Qa?0:n:n===t.data.length-1&&t.data.charAt(n)===Qa?t.data.length:n:n,WN={insert:(e,t)=>{let n,o,r,s,a=!1;const i=e.dom,l=e.schema.getNonEmptyElements(),d=e.selection.getRng(),c=ql(e),u=Cn(d.startContainer),f=Fn(u,d.startOffset),g=f.exists((e=>Wt(e)&&!ro(e))),p=d.collapsed&&g,b=(t,o)=>LN(e,n,_,k,Xl(e),t,o),v=e=>{const t=qN(e,n,o);if(dr(n)&&(e?t>0:t<n.data.length))return!1;if((n.parentNode===_||n===_)&&a&&!e)return!0;if(e&&er(n)&&n===_.firstChild)return!0;if($N(n,"TABLE")||$N(n,"HR"))return a&&!e||!a&&e;const r=new Vo(n,_);let s;for(dr(n)&&(e&&0===t?r.prev():e||t!==n.data.length||r.next());s=r.current();){if(er(s)){if(!s.getAttribute("data-mce-bogus")){const e=s.nodeName.toLowerCase();if(l[e]&&"br"!==e)return!1}}else if(dr(s)&&!Go(s.data))return!1;e?r.prev():r.next()}return!0},w=()=>{let t;return t=/^(H[1-6]|PRE|FIGURE)$/.test(r)&&"HGROUP"!==S?b(c):b(),((e,t)=>{const n=Zl(e);return!y(t)&&(m(n)?H(Dt.explode(n),t.nodeName.toLowerCase()):n)})(e,s)&&VN(i,s)&&i.isEmpty(_,void 0,{includeZwsp:!0})?t=i.split(s,_):i.insertAfter(t,_),TN(e,t),t};Yf(i,d).each((e=>{d.setStart(e.startContainer,e.startOffset),d.setEnd(e.endContainer,e.endOffset)})),n=d.startContainer,o=d.startOffset;const E=!(!t||!t.shiftKey),x=!(!t||!t.ctrlKey);er(n)&&n.hasChildNodes()&&!p&&(a=o>n.childNodes.length-1,n=n.childNodes[Math.min(o,n.childNodes.length-1)]||n,o=a&&dr(n)?n.data.length:0);const k=ON(i,n);if(!k||((e,t)=>{const n=e.dom.getParent(t,"ol,ul,dl");return null!==n&&"false"===e.dom.getContentEditableParent(n)})(e,n))return;E||(n=((e,t,n,o,r)=>{var s,a;const i=e.dom,l=null!==(s=ON(i,o))&&void 0!==s?s:i.getRoot();let d=i.getParent(o,i.isBlock);if(!d||!VN(i,d)){if(d=d||l,!d.hasChildNodes()){const o=i.create(t);return DN(e,o),d.appendChild(o),n.setStart(o,0),n.setEnd(o,0),o}let s,c=o;for(;c&&c.parentNode!==d;)c=c.parentNode;for(;c&&!i.isBlock(c);)s=c,c=c.previousSibling;const u=null===(a=null==s?void 0:s.parentElement)||void 0===a?void 0:a.nodeName;if(s&&u&&e.schema.isValidChild(u,t.toLowerCase())){const a=s.parentNode,l=i.create(t);for(DN(e,l),a.insertBefore(l,s),c=s;c&&!i.isBlock(c);){const e=c.nextSibling;l.appendChild(c),c=e}n.setStart(o,r),n.setEnd(o,r)}}return o})(e,c,d,n,o));let _=i.getParent(n,i.isBlock)||i.getRoot();s=C(null==_?void 0:_.parentNode)?i.getParent(_.parentNode,i.isBlock):null,r=_?_.nodeName.toUpperCase():"";const S=s?s.nodeName.toUpperCase():"";if("LI"!==S||x||(_=s,s=s.parentNode,r=S),er(s)&&((e,t,n)=>!t&&n.nodeName.toLowerCase()===ql(e)&&e.dom.isEmpty(n)&&((t,n,o)=>{let r=n;for(;r&&r!==t&&h(r.nextSibling);){const t=r.parentElement;if(!t||(s=t,!ke(e.schema.getTextBlockElements(),s.nodeName.toLowerCase())))return xr(t);r=t}var s;return!1})(e.getBody(),n))(e,E,_))return((e,t,n)=>{var o,r,s;const a=t(ql(e)),i=((e,t)=>e.dom.getParent(t,xr))(e,n);i&&(e.dom.insertAfter(a,i),TN(e,a),(null!==(s=null===(r=null===(o=n.parentElement)||void 0===o?void 0:o.childNodes)||void 0===r?void 0:r.length)&&void 0!==s?s:0)>1&&e.dom.remove(n))})(e,b,_);if(/^(LI|DT|DD)$/.test(r)&&er(s)&&i.isEmpty(_))return void((e,t,n,o,r)=>{const s=e.dom,a=e.selection.getRng(),i=n.parentNode;if(n===e.getBody()||!i)return;var l;IN(l=n)&&IN(l.parentNode)&&(r="LI");const d=FN(o)?jN(o):void 0;let c=FN(o)&&d?t(r,{style:jN(o)}):t(r);if(zN(n,o,!0)&&zN(n,o,!1))if(MN(n,"LI")){const e=UN(n);s.insertAfter(c,e),(e=>{var t;return(null===(t=e.parentNode)||void 0===t?void 0:t.firstChild)===e})(n)?s.remove(e):s.remove(n)}else s.replace(c,n);else if(zN(n,o,!0))MN(n,"LI")?(s.insertAfter(c,UN(n)),c.appendChild(s.doc.createTextNode(" ")),c.appendChild(n)):i.insertBefore(c,n),s.remove(o);else if(zN(n,o,!1))s.insertAfter(c,UN(n)),s.remove(o);else{n=UN(n);const e=a.cloneRange();e.setStartAfter(o),e.setEndAfter(n);const t=e.extractContents();if("LI"===r&&((e,t)=>e.firstChild&&"LI"===e.firstChild.nodeName)(t)){const e=Y(V(c.children,Cn),O(Zt("br")));c=t.firstChild,s.insertAfter(t,n),q(e,(e=>vo(Cn(c),e))),d&&c.setAttribute("style",d)}else s.insertAfter(t,n),s.insertAfter(c,n);s.remove(o)}TN(e,c)})(e,b,s,_,c);if(!(p||_!==e.getBody()&&VN(i,_)))return;const N=_.parentNode;let R;if(p)R=b(c),f.fold((()=>{yo(u,Cn(R))}),(e=>{ho(e,Cn(R))})),e.selection.setCursorLocation(R,0);else if(oi(_))R=ui(_),i.isEmpty(_)&&PN(_),DN(e,R),TN(e,R);else if(v(!1))R=w();else if(v(!0)&&N){const t=Qi.fromRangeStart(d),n=Mp(t),o=Cn(_),r=Qp(o,t,e.schema)?Jp(o,t,e.schema).bind((e=>I.from(e.getNode()))):I.none();R=N.insertBefore(b(),_);const s=$N(_,"HR")||n?R:r.getOr(_);TN(e,s)}else{const t=(e=>{const t=e.cloneRange();return t.setStart(e.startContainer,qN(!0,e.startContainer,e.startOffset)),t.setEnd(e.endContainer,qN(!1,e.endContainer,e.endOffset)),t})(d).cloneRange();t.setEndAfter(_);const n=t.extractContents();(e=>{q(Uo(Cn(e),Yt),(e=>{const t=e.dom;t.nodeValue=ei(t.data)}))})(n),(e=>{let t=e;do{dr(t)&&(t.data=t.data.replace(/^[\r\n]+/,"")),t=t.firstChild}while(t)})(n),R=n.firstChild,i.insertAfter(n,_),((e,t,n)=>{var o;const r=[];if(!n)return;let s=n;for(;s=s.firstChild;){if(e.isBlock(s))return;er(s)&&!t[s.nodeName.toLowerCase()]&&r.push(s)}let a=r.length;for(;a--;)s=r[a],(!s.hasChildNodes()||s.firstChild===s.lastChild&&""===(null===(o=s.firstChild)||void 0===o?void 0:o.nodeValue)||HN(e,s))&&e.remove(s)})(i,l,R),((e,t)=>{t.normalize();const n=t.lastChild;(!n||er(n)&&/^(left|right)$/gi.test(e.getStyle(n,"float",!0)))&&e.add(t,"br")})(i,_),i.isEmpty(_)&&PN(_),R.normalize(),i.isEmpty(R)?(i.remove(R),w()):(DN(e,R),TN(e,R))}i.setAttrib(R,"id",""),e.dispatch("NewBlock",{newBlock:R})},fakeEventName:"insertParagraph"},KN=(e,t,n)=>{const o=e.dom.createRng();n?(o.setStartBefore(t),o.setEndBefore(t)):(o.setStartAfter(t),o.setEndAfter(t)),e.selection.setRng(o),bg(e,o)},YN=(e,t)=>{const n=vn("br");ho(Cn(t),n),e.undoManager.add()},GN=(e,t)=>{XN(e.getBody(),t)||bo(Cn(t),vn("br"));const n=vn("br");bo(Cn(t),n),KN(e,n.dom,!1),e.undoManager.add()},XN=(e,t)=>{return n=Qi.after(t),!!pr(n.getNode())||zu(e,Qi.after(t)).map((e=>pr(e.getNode()))).getOr(!1);var n},ZN=e=>e&&"A"===e.nodeName&&"href"in e,QN=e=>e.fold(L,ZN,ZN,L),JN=(e,t)=>{t.fold(k,T(YN,e),T(GN,e),k)},eR={insert:(e,t)=>{const n=(e=>{const t=T(Rh,e),n=Qi.fromRangeStart(e.selection.getRng());return Ex(t,e.getBody(),n).filter(QN)})(e);n.isSome()?n.each(T(JN,e)):((e,t)=>{const n=e.selection,o=e.dom,r=n.getRng();let s,a=!1;Yf(o,r).each((e=>{r.setStart(e.startContainer,e.startOffset),r.setEnd(e.endContainer,e.endOffset)}));let i=r.startOffset,l=r.startContainer;if(er(l)&&l.hasChildNodes()){const e=i>l.childNodes.length-1;l=l.childNodes[Math.min(i,l.childNodes.length-1)]||l,i=e&&dr(l)?l.data.length:0}let d=o.getParent(l,o.isBlock);const c=d&&d.parentNode?o.getParent(d.parentNode,o.isBlock):null,u=c?c.nodeName.toUpperCase():"",m=!(!t||!t.ctrlKey);"LI"!==u||m||(d=c),dr(l)&&i>=l.data.length&&(((e,t,n)=>{const o=new Vo(t,n);let r;const s=e.getNonEmptyElements();for(;r=o.next();)if(s[r.nodeName.toLowerCase()]||dr(r)&&r.length>0)return!0;return!1})(e.schema,l,d||o.getRoot())||(s=o.create("br"),r.insertNode(s),r.setStartAfter(s),r.setEndAfter(s),a=!0)),s=o.create("br"),el(o,r,s),KN(e,s,a),e.undoManager.add()})(e,t)},fakeEventName:"insertLineBreak"},tR=(e,t)=>BN(e).filter((e=>t.length>0&&xn(Cn(e),t))).isSome(),nR=xl([{br:[]},{block:[]},{none:[]}]),oR=(e,t)=>(e=>tR(e,Gl(e)))(e),rR=e=>(t,n)=>(e=>BN(e).filter((e=>Wa(Cn(e)))).isSome())(t)===e,sR=(e,t)=>(n,o)=>{const r=(e=>BN(e).fold(N(""),(e=>e.nodeName.toUpperCase())))(n)===e.toUpperCase();return r===t},aR=e=>{const t=ON(e.dom,e.selection.getStart());return y(t)},iR=e=>sR("pre",e),lR=e=>(t,n)=>Vl(t)===e,dR=(e,t)=>(e=>tR(e,Yl(e)))(e),cR=(e,t)=>t,uR=e=>{const t=ql(e),n=ON(e.dom,e.selection.getStart());return C(n)&&e.schema.isValidChild(n.nodeName,t)},mR=e=>{const t=e.selection.getRng(),n=Cn(t.startContainer),o=Fn(n,t.startOffset).map((e=>Wt(e)&&!ro(e)));return t.collapsed&&o.getOr(!0)},fR=(e,t)=>(n,o)=>X(e,((e,t)=>e&&t(n,o)),!0)?I.some(t):I.none(),gR=(e,t,n)=>{t.selection.isCollapsed()||(e=>{e.execCommand("delete")})(t),C(n)&&_N(t,e.fakeEventName).isDefaultPrevented()||(e.insert(t,n),C(n)&&kN(t,e.fakeEventName))},pR=(e,t)=>{const n=()=>gR(eR,e,t),o=()=>gR(WN,e,t),r=((e,t)=>mx([fR([oR],nR.none()),fR([iR(!0),aR],nR.none()),fR([sR("summary",!0)],nR.br()),fR([iR(!0),lR(!1),cR],nR.br()),fR([iR(!0),lR(!1)],nR.block()),fR([iR(!0),lR(!0),cR],nR.block()),fR([iR(!0),lR(!0)],nR.br()),fR([rR(!0),cR],nR.br()),fR([rR(!0)],nR.block()),fR([dR],nR.br()),fR([cR],nR.br()),fR([uR],nR.block()),fR([mR],nR.block())],[e,!(!t||!t.shiftKey)]).getOr(nR.none()))(e,t);switch(Kl(e)){case"linebreak":r.fold(n,n,k);break;case"block":r.fold(o,o,k);break;case"invert":r.fold(o,n,k);break;default:r.fold(n,o,k)}},hR=xt(),bR=hR.os.isiOS()&&hR.browser.isSafari(),vR=(e,t)=>{var n;t.isDefaultPrevented()||(t.preventDefault(),(n=e.undoManager).typing&&(n.typing=!1,n.add()),e.undoManager.transact((()=>{pR(e,t)})))},yR=xt(),CR=e=>e.stopImmediatePropagation(),wR=e=>e.keyCode===yf.PAGE_UP||e.keyCode===yf.PAGE_DOWN,ER=(e,t,n)=>{n&&!e.get()?t.on("NodeChange",CR,!0):!n&&e.get()&&t.off("NodeChange",CR),e.set(n)},xR=(e,t)=>{const n=t.container(),o=t.offset();return dr(n)?(n.insertData(o,e),I.some(Qi(n,o+e.length))):vu(t).map((n=>{const o=yn(e);return t.isAtEnd()?bo(n,o):ho(n,o),Qi(o.dom,e.length)}))},kR=T(xR,Wo),_R=T(xR," "),SR=e=>t=>{e.selection.setRng(t.toRange()),e.nodeChanged()},NR=e=>{const t=Qi.fromRangeStart(e.selection.getRng()),n=Cn(e.getBody());if(e.selection.isCollapsed()){const o=T(Rh,e),r=Qi.fromRangeStart(e.selection.getRng());return Ex(o,e.getBody(),r).bind((e=>t=>t.fold((t=>ju(e.dom,Qi.before(t))),(e=>Hu(e)),(e=>$u(e)),(t=>zu(e.dom,Qi.after(t)))))(n)).map((o=>()=>((e,t,n)=>o=>ih(e,o,n)?kR(t):_R(t))(n,t,e.schema)(o).each(SR(e))))}return I.none()},RR=e=>{return Ft(Tt.browser.isFirefox()&&e.selection.isEditable()&&(t=e.dom,n=e.selection.getRng().startContainer,t.isEditable(t.getParent(n,"summary"))),(()=>{const t=Cn(e.getBody());e.selection.isCollapsed()||e.getDoc().execCommand("Delete"),((e,t,n)=>ih(e,t,n)?kR(t):_R(t))(t,Qi.fromRangeStart(e.selection.getRng()),e.schema).each(SR(e))}));var t,n},AR=e=>kc(e)?[{keyCode:yf.TAB,action:g_($_,e,!0)},{keyCode:yf.TAB,shiftKey:!0,action:g_($_,e,!1)}]:[],TR=e=>{if(e.addShortcut("Meta+P","","mcePrint"),mN(e),sw(e))return Br(null);{const t=vk(e);return(e=>{e.on("beforeinput",(t=>{e.selection.isEditable()&&!$(t.getTargetRanges(),(t=>!$g(e.dom,t)))||t.preventDefault()}))})(e),(e=>{e.on("keyup compositionstart",T(n_,e))})(e),((e,t)=>{e.on("keydown",(n=>{n.isDefaultPrevented()||((e,t,n)=>{const o=Tt.os.isMacOS()||Tt.os.isiOS();p_([{keyCode:yf.RIGHT,action:g_(s_,e,!0)},{keyCode:yf.LEFT,action:g_(s_,e,!1)},{keyCode:yf.UP,action:g_(a_,e,!1)},{keyCode:yf.DOWN,action:g_(a_,e,!0)},...o?[{keyCode:yf.UP,action:g_(l_,e,!1),metaKey:!0,shiftKey:!0},{keyCode:yf.DOWN,action:g_(l_,e,!0),metaKey:!0,shiftKey:!0}]:[],{keyCode:yf.RIGHT,action:g_(F_,e,!0)},{keyCode:yf.LEFT,action:g_(F_,e,!1)},{keyCode:yf.UP,action:g_(U_,e,!1)},{keyCode:yf.DOWN,action:g_(U_,e,!0)},{keyCode:yf.UP,action:g_(U_,e,!1)},{keyCode:yf.UP,action:g_(u_,e,!1)},{keyCode:yf.DOWN,action:g_(u_,e,!0)},{keyCode:yf.RIGHT,action:g_(b_,e,!0)},{keyCode:yf.LEFT,action:g_(b_,e,!1)},{keyCode:yf.UP,action:g_(v_,e,!1)},{keyCode:yf.DOWN,action:g_(v_,e,!0)},{keyCode:yf.RIGHT,action:g_(hk,e,t,!0)},{keyCode:yf.LEFT,action:g_(hk,e,t,!1)},{keyCode:yf.RIGHT,ctrlKey:!o,altKey:o,action:g_(yk,e,t)},{keyCode:yf.LEFT,ctrlKey:!o,altKey:o,action:g_(Ck,e,t)},{keyCode:yf.UP,action:g_(c_,e,!1)},{keyCode:yf.DOWN,action:g_(c_,e,!0)}],n).each((e=>{n.preventDefault()}))})(e,t,n)}))})(e,t),((e,t)=>{let n=!1;e.on("keydown",(o=>{n=o.keyCode===yf.BACKSPACE,o.isDefaultPrevented()||((e,t,n)=>{const o=n.keyCode===yf.BACKSPACE?"deleteContentBackward":"deleteContentForward",r=e.selection.isCollapsed(),s=r?"character":"selection",a=e=>r?e?"word":"line":"selection";h_([{keyCode:yf.BACKSPACE,action:g_(Vk,e)},{keyCode:yf.BACKSPACE,action:g_(GE,e,!1)},{keyCode:yf.DELETE,action:g_(GE,e,!0)},{keyCode:yf.BACKSPACE,action:g_(jE,e,!1)},{keyCode:yf.DELETE,action:g_(jE,e,!0)},{keyCode:yf.BACKSPACE,action:g_(kk,e,t,!1)},{keyCode:yf.DELETE,action:g_(kk,e,t,!0)},{keyCode:yf.BACKSPACE,action:g_(gb,e,!1)},{keyCode:yf.DELETE,action:g_(gb,e,!0)},{keyCode:yf.BACKSPACE,action:g_(EN,e,!1,s)},{keyCode:yf.DELETE,action:g_(EN,e,!0,s)},...RN?[{keyCode:yf.BACKSPACE,altKey:!0,action:g_(EN,e,!1,a(!0))},{keyCode:yf.DELETE,altKey:!0,action:g_(EN,e,!0,a(!0))},{keyCode:yf.BACKSPACE,metaKey:!0,action:g_(EN,e,!1,a(!1))}]:[{keyCode:yf.BACKSPACE,ctrlKey:!0,action:g_(EN,e,!1,a(!0))},{keyCode:yf.DELETE,ctrlKey:!0,action:g_(EN,e,!0,a(!0))}],{keyCode:yf.BACKSPACE,action:g_(tx,e,!1)},{keyCode:yf.DELETE,action:g_(tx,e,!0)},{keyCode:yf.BACKSPACE,action:g_(Mk,e,!1)},{keyCode:yf.DELETE,action:g_(Mk,e,!0)},{keyCode:yf.BACKSPACE,action:g_(DE,e,!1)},{keyCode:yf.DELETE,action:g_(DE,e,!0)},{keyCode:yf.BACKSPACE,action:g_(OE,e,!1)},{keyCode:yf.DELETE,action:g_(OE,e,!0)},{keyCode:yf.BACKSPACE,action:g_(Pk,e,!1)},{keyCode:yf.DELETE,action:g_(Pk,e,!0)},{keyCode:yf.BACKSPACE,action:g_(ex,e,!1)},{keyCode:yf.DELETE,action:g_(ex,e,!0)}],n).filter((t=>e.selection.isEditable())).each((t=>{n.preventDefault(),_N(e,o).isDefaultPrevented()||(t(),kN(e,o))}))})(e,t,o)})),e.on("keyup",(t=>{t.isDefaultPrevented()||((e,t,n)=>{p_([{keyCode:yf.BACKSPACE,action:g_(YE,e)},{keyCode:yf.DELETE,action:g_(YE,e)},...RN?[{keyCode:yf.BACKSPACE,altKey:!0,action:g_(Dk,e)},{keyCode:yf.DELETE,altKey:!0,action:g_(Dk,e)},...n?[{keyCode:AN?224:91,action:g_(Dk,e)}]:[]]:[{keyCode:yf.BACKSPACE,ctrlKey:!0,action:g_(Dk,e)},{keyCode:yf.DELETE,ctrlKey:!0,action:g_(Dk,e)}]],t)})(e,t,n),n=!1}))})(e,t),(e=>{let t=I.none();e.on("keydown",(n=>{n.keyCode===yf.ENTER&&(bR&&(e=>{if(!e.collapsed)return!1;const t=e.startContainer;if(dr(t)){const n=/^[\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF]$/,o=t.data.charAt(e.startOffset-1);return n.test(o)}return!1})(e.selection.getRng())?(e=>{t=I.some(e.selection.getBookmark()),e.undoManager.add()})(e):vR(e,n))})),e.on("keyup",(n=>{n.keyCode===yf.ENTER&&t.each((()=>((e,n)=>{e.undoManager.undo(),t.fold(k,(t=>e.selection.moveToBookmark(t))),vR(e,n),t=I.none()})(e,n)))}))})(e),(e=>{e.on("keydown",(t=>{t.isDefaultPrevented()||((e,t)=>{h_([{keyCode:yf.SPACEBAR,action:g_(NR,e)},{keyCode:yf.SPACEBAR,action:g_(RR,e)}],t).each((n=>{t.preventDefault(),_N(e,"insertText",{data:" "}).isDefaultPrevented()||(n(),kN(e,"insertText",{data:" "}))}))})(e,t)}))})(e),(e=>{e.on("input",(t=>{t.isComposing||(e=>{const t=Cn(e.getBody());e.selection.isCollapsed()&&ph(t,Qi.fromRangeStart(e.selection.getRng()),e.schema).each((t=>{e.selection.setRng(t.toRange())}))})(e)}))})(e),(e=>{e.on("keydown",(t=>{t.isDefaultPrevented()||((e,t)=>{p_([...AR(e)],t).each((e=>{t.preventDefault()}))})(e,t)}))})(e),((e,t)=>{e.on("keydown",(n=>{n.isDefaultPrevented()||((e,t,n)=>{const o=Tt.os.isMacOS()||Tt.os.isiOS();p_([{keyCode:yf.END,action:g_(i_,e,!0)},{keyCode:yf.HOME,action:g_(i_,e,!1)},...o?[]:[{keyCode:yf.HOME,action:g_(l_,e,!1),ctrlKey:!0,shiftKey:!0},{keyCode:yf.END,action:g_(l_,e,!0),ctrlKey:!0,shiftKey:!0}],{keyCode:yf.END,action:g_(y_,e,!0)},{keyCode:yf.HOME,action:g_(y_,e,!1)},{keyCode:yf.END,action:g_(wk,e,!0,t)},{keyCode:yf.HOME,action:g_(wk,e,!1,t)}],n).each((e=>{n.preventDefault()}))})(e,t,n)}))})(e,t),((e,t)=>{if(yR.os.isMacOS())return;const n=Br(!1);e.on("keydown",(t=>{wR(t)&&ER(n,e,!0)})),e.on("keyup",(o=>{o.isDefaultPrevented()||((e,t,n)=>{p_([{keyCode:yf.PAGE_UP,action:g_(wk,e,!1,t)},{keyCode:yf.PAGE_DOWN,action:g_(wk,e,!0,t)}],n)})(e,t,o),wR(o)&&n.get()&&(ER(n,e,!1),e.nodeChanged())}))})(e,t),t}};class OR{constructor(e){let t;this.lastPath=[],this.editor=e;const n=this;"onselectionchange"in e.getDoc()||e.on("NodeChange click mouseup keyup focus",(n=>{const o=e.selection.getRng(),r={startContainer:o.startContainer,startOffset:o.startOffset,endContainer:o.endContainer,endOffset:o.endOffset};"nodechange"!==n.type&&jf(r,t)||e.dispatch("SelectionChange"),t=r})),e.on("contextmenu",(()=>{Ng(e),e.dispatch("SelectionChange")})),e.on("SelectionChange",(()=>{const t=e.selection.getStart(!0);t&&bm(e)&&!n.isSameElementPath(t)&&e.dom.isChildOf(t,e.getBody())&&e.nodeChanged({selectionChange:!0})})),e.on("mouseup",(t=>{!t.isDefaultPrevented()&&bm(e)&&("IMG"===e.selection.getNode().nodeName?Tg.setEditorTimeout(e,(()=>{e.nodeChanged()})):e.nodeChanged())}))}nodeChanged(e={}){const t=this.editor.selection;let n;if(this.editor.initialized&&t&&!Ud(this.editor)&&!this.editor.mode.isReadOnly()){const o=this.editor.getBody();n=t.getStart(!0)||o,n.ownerDocument===this.editor.getDoc()&&this.editor.dom.isChildOf(n,o)||(n=o);const r=[];this.editor.dom.getParent(n,(e=>e===o||(r.push(e),!1))),this.editor.dispatch("NodeChange",{...e,element:n,parents:r})}}isSameElementPath(e){let t;const n=this.editor,o=oe(n.dom.getParents(e,M,n.getBody()));if(o.length===this.lastPath.length){for(t=o.length;t>=0&&o[t]===this.lastPath[t];t--);if(-1===t)return this.lastPath=o,!0}return this.lastPath=o,!1}}const BR=Da("image"),PR=Da("event"),DR=e=>t=>{t[PR]=e},LR=DR(0),MR=DR(2),IR=DR(1),FR=(0,e=>{const t=e;return I.from(t[PR]).exists((e=>0===e))});const UR=Da("mode"),zR=e=>t=>{t[UR]=e},jR=(e,t)=>zR(t)(e),HR=zR(0),$R=zR(2),VR=zR(1),qR=e=>t=>{const n=t;return I.from(n[UR]).exists((t=>t===e))},WR=qR(0),KR=qR(1),YR=["none","copy","link","move"],GR=["none","copy","copyLink","copyMove","link","linkMove","move","all","uninitialized"],XR=()=>{const e=new window.DataTransfer;let t="move",n="all";const o={get dropEffect(){return t},set dropEffect(e){H(YR,e)&&(t=e)},get effectAllowed(){return n},set effectAllowed(e){FR(o)&&H(GR,e)&&(n=e)},get items(){return((e,t)=>({...t,get length(){return t.length},add:(n,o)=>{if(WR(e)){if(!m(n))return t.add(n);if(!v(o))return t.add(n,o)}return null},remove:n=>{WR(e)&&t.remove(n)},clear:()=>{WR(e)&&t.clear()}}))(o,e.items)},get files(){return KR(o)?Object.freeze({length:0,item:e=>null}):e.files},get types(){return e.types},setDragImage:(t,n,r)=>{var s;WR(o)&&(s={image:t,x:n,y:r},o[BR]=s,e.setDragImage(t,n,r))},getData:t=>KR(o)?"":e.getData(t),setData:(t,n)=>{WR(o)&&e.setData(t,n)},clearData:t=>{WR(o)&&e.clearData(t)}};return HR(o),o},ZR=(e,t)=>e.setData("text/html",t),QR="x-tinymce/html",JR=N(QR),eA="\x3c!-- "+QR+" --\x3e",tA=e=>eA+e,nA=e=>-1!==e.indexOf(eA),oA="%MCEPASTEBIN%",rA=e=>e.dom.get("mcepastebin"),sA=e=>C(e)&&"mcepastebin"===e.id,aA=e=>e===oA,iA=(e,t)=>(Dt.each(t,(t=>{e=u(t,RegExp)?e.replace(t,""):e.replace(t[0],t[1])})),e),lA=e=>iA(e,[/^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/gi,/<!--StartFragment-->|<!--EndFragment-->/g,[/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,(e,t,n)=>t||n?Wo:" "],/<br class="Apple-interchange-newline">/g,/<br>$/i]),dA=(e,t)=>({content:e,cancelled:t}),cA=(e,t)=>(e.insertContent(t,{merge:dc(e),paste:!0}),!0),uA=e=>/^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(e),mA=(e,t,n)=>!(e.selection.isCollapsed()||!uA(t))&&((e,t,n)=>(e.undoManager.extra((()=>{n(e,t)}),(()=>{e.execCommand("mceInsertLink",!1,t)})),!0))(e,t,n),fA=(e,t,n)=>!!((e,t)=>uA(t)&&$(xc(e),(e=>Ve(t.toLowerCase(),`.${e.toLowerCase()}`))))(e,t)&&((e,t,n)=>(e.undoManager.extra((()=>{n(e,t)}),(()=>{e.insertContent('<img src="'+t+'">')})),!0))(e,t,n),gA=(e=>{let t=0;return()=>"mceclip"+t++})(),pA=e=>{const t=XR();return ZR(t,e),$R(t),t},hA=(e,t,n,o,r)=>{const s=((e,t,n)=>((e,t,n)=>{const o=((e,t,n)=>e.dispatch("PastePreProcess",{content:t,internal:n}))(e,t,n),r=((e,t)=>{const n=_C({sanitize:wc(e),sandbox_iframes:Nc(e),sandbox_iframes_exclusions:Rc(e),convert_unsafe_embeds:Ac(e)},e.schema);n.addNodeFilter("meta",(e=>{Dt.each(e,(e=>{e.remove()}))}));const o=n.parse(t,{forced_root_block:!1,isRootContent:!0});return vp({validate:!0},e.schema).serialize(o)})(e,o.content);return e.hasEventListeners("PastePostProcess")&&!o.isDefaultPrevented()?((e,t,n)=>{const o=e.dom.create("div",{style:"display:none"},t),r=((e,t,n)=>e.dispatch("PastePostProcess",{node:t,internal:n}))(e,o,n);return dA(r.node.innerHTML,r.isDefaultPrevented())})(e,r,n):dA(r,o.isDefaultPrevented())})(e,t,n))(e,t,n);if(!s.cancelled){const t=s.content,n=()=>((e,t,n)=>{n||!cc(e)?cA(e,t):((e,t)=>{Dt.each([mA,fA,cA],(n=>!n(e,t,cA)))})(e,t)})(e,t,o);r?_N(e,"insertFromPaste",{dataTransfer:pA(t)}).isDefaultPrevented()||(n(),kN(e,"insertFromPaste")):n()}},bA=(e,t,n,o)=>{const r=n||nA(t);hA(e,(e=>e.replace(eA,""))(t),r,!1,o)},vA=(e,t,n)=>{const o=e.dom.encode(t).replace(/\r\n/g,"\n"),r=((e,t,n)=>{const o=e.split(/\n\n/),r=((e,t)=>{let n="<"+e;const o=we(t,((e,t)=>t+'="'+ws.encodeAllRaw(e)+'"'));return o.length&&(n+=" "+o.join(" ")),n+">"})(t,n),s="</"+t+">",a=V(o,(e=>e.split(/\n/).join("<br />")));return 1===a.length?a[0]:V(a,(e=>r+e+s)).join("")})(Zo(o,mc(e)),ql(e),Wl(e));hA(e,r,!1,!0,n)},yA=e=>{const t={};if(e&&e.types)for(let n=0;n<e.types.length;n++){const o=e.types[n];try{t[o]=e.getData(o)}catch(e){t[o]=""}}return t},CA=(e,t)=>t in e&&e[t].length>0,wA=e=>CA(e,"text/html")||CA(e,"text/plain"),EA=(e,t,n)=>{const o="paste"===t.type?t.clipboardData:t.dataTransfer;var r;if(oc(e)&&o){const s=((e,t)=>{const n=t.items?te(ce(t.items),(e=>"file"===e.kind?[e.getAsFile()]:[])):[],o=t.files?ce(t.files):[];return Y(n.length>0?n:o,(e=>{const t=xc(e);return e=>$e(e.type,"image/")&&$(t,(t=>(e=>{const t=e.toLowerCase(),n={jpg:"jpeg",jpe:"jpeg",jfi:"jpeg",jif:"jpeg",jfif:"jpeg",pjpeg:"jpeg",pjp:"jpeg",svg:"svg+xml"};return Dt.hasOwn(n,t)?"image/"+n[t]:"image/"+t})(t)===e.type))})(e))})(e,o);if(s.length>0)return t.preventDefault(),(r=s,Promise.all(V(r,(e=>ty(e).then((t=>({file:e,uri:t}))))))).then((t=>{n&&e.selection.setRng(n),q(t,(t=>{((e,t)=>{Jv(t.uri).each((({data:n,type:o,base64Encoded:r})=>{const s=r?n:btoa(n),a=t.file,i=e.editorUpload.blobCache,l=i.getByData(s,o),d=null!=l?l:((e,t,n,o)=>{const r=gA(),s=Jl(e)&&C(n.name),a=s?((e,t)=>{const n=t.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);return C(n)?e.dom.encode(n[1]):void 0})(e,n.name):r,i=s?n.name:void 0,l=t.create(r,n,o,a,i);return t.add(l),l})(e,i,a,s);bA(e,`<img src="${d.blobUri()}">`,!1,!0)}))})(e,t)}))})),!0}return!1},xA=(e,t,n,o,r)=>{let s=lA(n);const a=CA(t,JR())||nA(n),i=!a&&(e=>!/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(e))(s),l=uA(s);(aA(s)||!s.length||i&&!l)&&(o=!0),(o||l)&&(s=CA(t,"text/plain")&&i?t["text/plain"]:(e=>{const t=Fs(),n=_C({},t);let o="";const r=t.getVoidElements(),s=Dt.makeMap("script noscript style textarea video audio iframe object"," "),a=t.getBlockElements(),i=e=>{const n=e.name,l=e;if("br"!==n){if("wbr"!==n)if(r[n]&&(o+=" "),s[n])o+=" ";else{if(3===e.type&&(o+=e.value),!(e.name in t.getVoidElements())){let t=e.firstChild;if(t)do{i(t)}while(t=t.next)}a[n]&&l.next&&(o+="\n","p"===n&&(o+="\n"))}}else o+="\n"};return e=iA(e,[/<!\[[^\]]+\]>/g]),i(n.parse(e)),o})(s)),aA(s)||(o?vA(e,s,r):bA(e,s,a,r))},kA=(e,t,n)=>{((e,t,n)=>{let o;e.on("keydown",(e=>{(e=>yf.metaKeyPressed(e)&&86===e.keyCode||e.shiftKey&&45===e.keyCode)(e)&&!e.isDefaultPrevented()&&(o=e.shiftKey&&86===e.keyCode)})),e.on("paste",(r=>{if(r.isDefaultPrevented()||(e=>{var t,n;return Tt.os.isAndroid()&&0===(null===(n=null===(t=e.clipboardData)||void 0===t?void 0:t.items)||void 0===n?void 0:n.length)})(r))return;const s="text"===n.get()||o;o=!1;const a=yA(r.clipboardData);!wA(a)&&EA(e,r,t.getLastRng()||e.selection.getRng())||(CA(a,"text/html")?(r.preventDefault(),xA(e,a,a["text/html"],s,!0)):CA(a,"text/plain")&&CA(a,"text/uri-list")?(r.preventDefault(),xA(e,a,a["text/plain"],s,!0)):(t.create(),Tg.setEditorTimeout(e,(()=>{const n=t.getHtml();t.remove(),xA(e,a,n,s,!1)}),0)))}))})(e,t,n),(e=>{const t=e=>$e(e,"webkit-fake-url"),n=e=>$e(e,"data:");e.parser.addNodeFilter("img",((o,r,s)=>{if(!oc(e)&&(e=>{var t;return!0===(null===(t=e.data)||void 0===t?void 0:t.paste)})(s))for(const r of o){const o=r.attr("src");m(o)&&!r.attr("data-mce-object")&&o!==Tt.transparentSrc&&(t(o)||!fc(e)&&n(o))&&r.remove()}}))})(e)},_A=(e,t,n,o)=>{((e,t,n)=>{if(!e)return!1;try{return e.clearData(),e.setData("text/html",t),e.setData("text/plain",n),e.setData(JR(),t),!0}catch(e){return!1}})(e.clipboardData,t.html,t.text)?(e.preventDefault(),o()):n(t.html,o)},SA=e=>(t,n)=>{const{dom:o,selection:r}=e,s=o.create("div",{contenteditable:"false","data-mce-bogus":"all"}),a=o.create("div",{contenteditable:"true"},t);o.setStyles(s,{position:"fixed",top:"0",left:"-3000px",width:"1000px",overflow:"hidden"}),s.appendChild(a),o.add(e.getBody(),s);const i=r.getRng();a.focus();const l=o.createRng();l.selectNodeContents(a),r.setRng(l),Tg.setEditorTimeout(e,(()=>{r.setRng(i),o.remove(s),n()}),0)},NA=e=>({html:tA(e.selection.getContent({contextual:!0})),text:e.selection.getContent({format:"text"})}),RA=e=>!e.selection.isCollapsed()||(e=>!!e.dom.getParent(e.selection.getStart(),"td[data-mce-selected],th[data-mce-selected]",e.getBody()))(e),AA=(e,t)=>{var n,o;return Zf.getCaretRangeFromPoint(null!==(n=t.clientX)&&void 0!==n?n:0,null!==(o=t.clientY)&&void 0!==o?o:0,e.getDoc())},TA=(e,t)=>{e.focus(),t&&e.selection.setRng(t)},OA=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,BA=e=>Dt.trim(e).replace(OA,Ws).toLowerCase(),PA=(e,t,n)=>{const o=ic(e);if(n||"all"===o||!lc(e))return t;const r=o?o.split(/[, ]/):[];if(r&&"none"!==o){const n=e.dom,o=e.selection.getNode();t=t.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,((e,t,s,a)=>{const i=n.parseStyle(n.decode(s)),l={};for(let e=0;e<r.length;e++){const t=i[r[e]];let s=t,a=n.getStyle(o,r[e],!0);/color/.test(r[e])&&(s=BA(s),a=BA(a)),a!==s&&(l[r[e]]=t)}const d=n.serializeStyle(l,"span");return d?t+' style="'+d+'"'+a:t+a}))}else t=t.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi,"$1$3");return t=t.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi,((e,t,n,o)=>t+' style="'+n+'"'+o)),t},DA=e=>{const t=Br(!1),n=Br(uc(e)?"text":"html"),o=(e=>{const t=Br(null);return{create:()=>((e,t)=>{const{dom:n,selection:o}=e,r=e.getBody();t.set(o.getRng());const s=n.add(e.getBody(),"div",{id:"mcepastebin",class:"mce-pastebin",contentEditable:!0,"data-mce-bogus":"all",style:"position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0"},oA);Tt.browser.isFirefox()&&n.setStyle(s,"left","rtl"===n.getStyle(r,"direction",!0)?65535:-65535),n.bind(s,"beforedeactivate focusin focusout",(e=>{e.stopPropagation()})),s.focus(),o.select(s,!0)})(e,t),remove:()=>((e,t)=>{const n=e.dom;if(rA(e)){let o;const r=t.get();for(;o=rA(e);)n.remove(o),n.unbind(o);r&&e.selection.setRng(r)}t.set(null)})(e,t),getEl:()=>rA(e),getHtml:()=>(e=>{const t=e.dom,n=(e,n)=>{e.appendChild(n),t.remove(n,!0)},[o,...r]=Y(e.getBody().childNodes,sA);q(r,(e=>{n(o,e)}));const s=t.select("div[id=mcepastebin]",o);for(let e=s.length-1;e>=0;e--){const r=t.create("div");o.insertBefore(r,s[e]),n(r,s[e])}return o?o.innerHTML:""})(e),getLastRng:t.get}})(e);(e=>{(Tt.browser.isChromium()||Tt.browser.isSafari())&&((e,t)=>{e.on("PastePreProcess",(n=>{n.content=t(e,n.content,n.internal)}))})(e,PA)})(e),((e,t)=>{e.addCommand("mceTogglePlainTextPaste",(()=>{((e,t)=>{"text"===t.get()?(t.set("html"),vf(e,!1)):(t.set("text"),vf(e,!0)),e.focus()})(e,t)})),e.addCommand("mceInsertClipboardContent",((t,n)=>{n.html&&bA(e,n.html,n.internal,!1),n.text&&vA(e,n.text,!1)}))})(e,n),(e=>{const t=t=>n=>{t(e,n)},n=rc(e);w(n)&&e.on("PastePreProcess",t(n));const o=sc(e);w(o)&&e.on("PastePostProcess",t(o))})(e),e.addQueryStateHandler("mceTogglePlainTextPaste",(()=>"text"===n.get())),e.on("PreInit",(()=>{(e=>{e.on("cut",(e=>t=>{!t.isDefaultPrevented()&&RA(e)&&e.selection.isEditable()&&_A(t,NA(e),SA(e),(()=>{if(Tt.browser.isChromium()||Tt.browser.isFirefox()){const t=e.selection.getRng();Tg.setEditorTimeout(e,(()=>{e.selection.setRng(t),e.execCommand("Delete")}),0)}else e.execCommand("Delete")}))})(e)),e.on("copy",(e=>t=>{!t.isDefaultPrevented()&&RA(e)&&_A(t,NA(e),SA(e),k)})(e))})(e),((e,t)=>{nc(e)&&e.on("dragend dragover draggesture dragdrop drop drag",(e=>{e.preventDefault(),e.stopPropagation()})),oc(e)||e.on("drop",(e=>{const t=e.dataTransfer;t&&(e=>$(e.files,(e=>/^image\//.test(e.type))))(t)&&e.preventDefault()})),e.on("drop",(n=>{if(n.isDefaultPrevented())return;const o=AA(e,n);if(y(o))return;const r=yA(n.dataTransfer),s=CA(r,JR());if((!wA(r)||(e=>{const t=e["text/plain"];return!!t&&0===t.indexOf("file://")})(r))&&EA(e,n,o))return;const a=r[JR()],i=a||r["text/html"]||r["text/plain"],l=((e,t,n,o)=>{const r=e.getParent(n,(e=>Zr(t,e)));if(!h(e.getParent(n,"summary")))return!0;if(r&&ke(o,"text/html")){const e=(new DOMParser).parseFromString(o["text/html"],"text/html").body;return!h(e.querySelector(r.nodeName.toLowerCase()))}return!1})(e.dom,e.schema,o.startContainer,r),d=t.get();d&&!l||i&&(n.preventDefault(),Tg.setEditorTimeout(e,(()=>{e.undoManager.transact((()=>{(a||d&&l)&&e.execCommand("Delete"),TA(e,o);const t=lA(i);r["text/html"]?bA(e,t,s,!0):vA(e,t,!0)}))})))})),e.on("dragstart",(e=>{t.set(!0)})),e.on("dragover dragend",(n=>{oc(e)&&!t.get()&&(n.preventDefault(),TA(e,AA(e,n))),"dragend"===n.type&&t.set(!1)})),(e=>{e.on("input",(t=>{const n=e=>h(e.querySelector("summary"));if("deleteByDrag"===t.inputType){const t=Y(e.dom.select("details"),n);q(t,(t=>{pr(t.firstChild)&&t.firstChild.remove();const n=e.dom.create("summary");n.appendChild(Xa().dom),t.prepend(n)}))}}))})(e)})(e,t),kA(e,o,n)}))},LA=pr,MA=dr,IA=e=>vr(e.dom),FA=e=>t=>_n(Cn(e),t),UA=(e,t)=>Jn(Cn(e),IA,FA(t)),zA=(e,t,n)=>{const o=new Vo(e,t),r=n?o.next.bind(o):o.prev.bind(o);let s=e;for(let t=n?e:r();t&&!LA(t);t=r())Bi(t)&&(s=t);return s},jA=e=>{const t=((e,t,n)=>{const o=Qi.fromRangeStart(e).getNode(),r=((e,t,n)=>Jn(Cn(e),(e=>(e=>br(e.dom))(e)||n.isBlock($t(e))),FA(t)).getOr(Cn(t)).dom)(o,t,n),s=zA(o,r,!1),a=zA(o,r,!0),i=document.createRange();return UA(s,r).fold((()=>{MA(s)?i.setStart(s,0):i.setStartBefore(s)}),(e=>i.setStartBefore(e.dom))),UA(a,r).fold((()=>{MA(a)?i.setEnd(a,a.data.length):i.setEndAfter(a)}),(e=>i.setEndAfter(e.dom))),i})(e.selection.getRng(),e.getBody(),e.schema);e.selection.setRng(Tb(t))};var HA;!function(e){e.Before="before",e.After="after"}(HA||(HA={}));const $A=(e,t)=>Math.abs(e.left-t),VA=(e,t)=>Math.abs(e.right-t),qA=(e,t)=>(e=>X(e,((e,t)=>e.fold((()=>I.some(t)),(e=>{const n=Math.min(t.left,e.left),o=Math.min(t.top,e.top),r=Math.max(t.right,e.right),s=Math.max(t.bottom,e.bottom);return I.some({top:o,right:r,bottom:s,left:n,width:r-n,height:s-o})}))),I.none()))(Y(e,(e=>{return(n=t)>=(o=e).top&&n<=o.bottom;var n,o}))).fold((()=>[[],e]),(t=>{const{pass:n,fail:o}=K(e,(e=>((e,t)=>{const n=((e,t)=>Math.max(0,Math.min(e.bottom,t.bottom)-Math.max(e.top,t.top)))(e,t)/Math.min(e.height,t.height);return((e,t)=>e.top<t.bottom&&e.bottom>t.top)(e,t)&&n>.5})(e,t)));return[n,o]})),WA=(e,t,n)=>t>e.left&&t<e.right?0:Math.min(Math.abs(e.left-t),Math.abs(e.right-t)),KA=(e,t,n,o)=>{const r=e=>Bi(e.node)?I.some(e):er(e.node)?KA(ce(e.node.childNodes),t,n,!1):I.none(),s=(e,s)=>{const a=ae(e,((e,o)=>s(e,t,n)-s(o,t,n)));return ue(a,r).map((e=>o&&!dr(e.node)&&a.length>1?((e,o,s)=>r(o).filter((o=>Math.abs(s(e,t,n)-s(o,t,n))<2&&dr(o.node))))(e,a[1],s).getOr(e):e))},[a,i]=qA(Qx(e),n),{pass:l,fail:d}=K(i,(e=>e.top<n));return s(a,WA).orThunk((()=>s(d,yi))).orThunk((()=>s(l,yi)))},YA=(e,t,n)=>((e,t,n)=>{const o=Cn(e),r=Rn(o),s=wn(r,t,n).filter((e=>Sn(o,e))).getOr(o);return((e,t,n,o)=>{const r=(t,s)=>{const a=Y(t.dom.childNodes,O((e=>er(e)&&e.classList.contains("mce-drag-container"))));return s.fold((()=>KA(a,n,o,!0)),(e=>{const t=Y(a,(t=>t!==e.dom));return KA(t,n,o,!0)})).orThunk((()=>(_n(t,e)?I.none():On(t)).bind((e=>r(e,I.some(t))))))};return r(t,I.none())})(o,s,t,n)})(e,t,n).filter((e=>Kc(e.node))).map((e=>((e,t)=>({node:e.node,position:$A(e,t)<VA(e,t)?HA.Before:HA.After}))(e,t))),GA=e=>{var t,n;const o=e.getBoundingClientRect(),r=e.ownerDocument,s=r.documentElement,a=r.defaultView;return{top:o.top+(null!==(t=null==a?void 0:a.scrollY)&&void 0!==t?t:0)-s.clientTop,left:o.left+(null!==(n=null==a?void 0:a.scrollX)&&void 0!==n?n:0)-s.clientLeft}},XA=e=>({target:e,srcElement:e}),ZA=(e,t,n,o)=>{const r=((e,t)=>{const n=(e=>{const t=XR(),n=(e=>{const t=e;return I.from(t[UR])})(e);return $R(e),LR(t),t.dropEffect=e.dropEffect,t.effectAllowed=e.effectAllowed,(e=>{const t=e;return I.from(t[BR])})(e).each((e=>t.setDragImage(e.image,e.x,e.y))),q(e.types,(n=>{"Files"!==n&&t.setData(n,e.getData(n))})),q(e.files,(e=>t.items.add(e))),(e=>{const t=e;return I.from(t[PR])})(e).each((e=>{((e,t)=>{DR(t)(e)})(t,e)})),n.each((n=>{jR(e,n),jR(t,n)})),t})(e);return"dragstart"===t?(LR(n),HR(n)):"drop"===t?(MR(n),$R(n)):(IR(n),VR(n)),n})(n,e);return v(o)?((e,t,n)=>{const o=B("Function not supported on simulated event.");return{bubbles:!0,cancelBubble:!1,cancelable:!0,composed:!1,currentTarget:null,defaultPrevented:!1,eventPhase:0,isTrusted:!0,returnValue:!1,timeStamp:0,type:e,composedPath:o,initEvent:o,preventDefault:k,stopImmediatePropagation:k,stopPropagation:k,AT_TARGET:window.Event.AT_TARGET,BUBBLING_PHASE:window.Event.BUBBLING_PHASE,CAPTURING_PHASE:window.Event.CAPTURING_PHASE,NONE:window.Event.NONE,altKey:!1,button:0,buttons:0,clientX:0,clientY:0,ctrlKey:!1,metaKey:!1,movementX:0,movementY:0,offsetX:0,offsetY:0,pageX:0,pageY:0,relatedTarget:null,screenX:0,screenY:0,shiftKey:!1,x:0,y:0,detail:0,view:null,which:0,initUIEvent:o,initMouseEvent:o,getModifierState:o,dataTransfer:n,...XA(t)}})(e,t,r):((e,t,n,o)=>({...t,dataTransfer:o,type:e,...XA(n)}))(e,o,t,r)},QA=vr,JA=((...e)=>t=>{for(let n=0;n<e.length;n++)if(e[n](t))return!0;return!1})(QA,br),eT=(e,t,n,o)=>{const r=e.dom,s=t.cloneNode(!0);r.setStyles(s,{width:n,height:o}),r.setAttrib(s,"data-mce-selected",null);const a=r.create("div",{class:"mce-drag-container","data-mce-bogus":"all",unselectable:"on",contenteditable:"false"});return r.setStyles(a,{position:"absolute",opacity:.5,overflow:"hidden",border:0,padding:0,margin:0,width:n,height:o}),r.setStyles(s,{margin:0,boxSizing:"border-box"}),a.appendChild(s),a},tT=(e,t)=>n=>()=>{const o="left"===e?n.scrollX:n.scrollY;n.scroll({[e]:o+t,behavior:"smooth"})},nT=tT("left",-32),oT=tT("left",32),rT=tT("top",-32),sT=tT("top",32),aT=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)},iT=(e,t,n,o,r)=>{"dragstart"===t&&ZR(o,e.dom.getOuterHTML(n));const s=ZA(t,n,o,r);return e.dispatch(t,s)},lT=(e,t)=>{const n=Ca(((e,n)=>((e,t,n)=>{e._selectionOverrides.hideFakeCaret(),YA(e.getBody(),t,n).fold((()=>e.selection.placeCaretAt(t,n)),(o=>{const r=e._selectionOverrides.showCaret(1,o.node,o.position===HA.Before,!1);r?e.selection.setRng(r):e.selection.placeCaretAt(t,n)}))})(t,e,n)),0);t.on("remove",n.cancel);const o=e;return r=>e.on((e=>{const s=Math.max(Math.abs(r.screenX-e.screenX),Math.abs(r.screenY-e.screenY));if(!e.dragging&&s>10){const n=iT(t,"dragstart",e.element,e.dataTransfer,r);if(C(n.dataTransfer)&&(e.dataTransfer=n.dataTransfer),n.isDefaultPrevented())return;e.dragging=!0,t.focus()}if(e.dragging){const s=r.currentTarget===t.getDoc().documentElement,l=((e,t)=>({pageX:t.pageX-e.relX,pageY:t.pageY+5}))(e,((e,t)=>{return n=(e=>e.inline?GA(e.getBody()):{left:0,top:0})(e),o=(e=>{const t=e.getBody();return e.inline?{left:t.scrollLeft,top:t.scrollTop}:{left:0,top:0}})(e),r=((e,t)=>{if(t.target.ownerDocument!==e.getDoc()){const n=GA(e.getContentAreaContainer()),o=(e=>{const t=e.getBody(),n=e.getDoc().documentElement,o={left:t.scrollLeft,top:t.scrollTop},r={left:t.scrollLeft||n.scrollLeft,top:t.scrollTop||n.scrollTop};return e.inline?o:r})(e);return{left:t.pageX-n.left+o.left,top:t.pageY-n.top+o.top}}return{left:t.pageX,top:t.pageY}})(e,t),{pageX:r.left-n.left+o.left,pageY:r.top-n.top+o.top};var n,o,r})(t,r));a=e.ghost,i=t.getBody(),a.parentNode!==i&&i.appendChild(a),((e,t,n,o,r,s,a,i,l,d,c,u)=>{let m=0,f=0;e.style.left=t.pageX+"px",e.style.top=t.pageY+"px",t.pageX+n>r&&(m=t.pageX+n-r),t.pageY+o>s&&(f=t.pageY+o-s),e.style.width=n-m+"px",e.style.height=o-f+"px";const g=l.clientHeight,p=l.clientWidth,h=a+l.getBoundingClientRect().top,b=i+l.getBoundingClientRect().left;c.on((e=>{e.intervalId.clear(),e.dragging&&u&&(a+8>=g?e.intervalId.set(sT(d)):a-8<=0?e.intervalId.set(rT(d)):i+8>=p?e.intervalId.set(oT(d)):i-8<=0?e.intervalId.set(nT(d)):h+16>=window.innerHeight?e.intervalId.set(sT(window)):h-16<=0?e.intervalId.set(rT(window)):b+16>=window.innerWidth?e.intervalId.set(oT(window)):b-16<=0&&e.intervalId.set(nT(window)))}))})(e.ghost,l,e.width,e.height,e.maxX,e.maxY,r.clientY,r.clientX,t.getContentAreaContainer(),t.getWin(),o,s),n.throttle(r.clientX,r.clientY)}var a,i}))},dT=(e,t,n)=>{e.on((e=>{e.intervalId.clear(),e.dragging&&n.fold((()=>iT(t,"dragend",e.element,e.dataTransfer)),(n=>iT(t,"dragend",e.element,e.dataTransfer,n)))})),cT(e)},cT=e=>{e.on((e=>{e.intervalId.clear(),aT(e.ghost)})),e.clear()},uT=e=>{const t=Dr(),n=ma.DOM,o=document,r=((e,t)=>n=>{if((e=>0===e.button)(n)){const o=Q(t.dom.getParents(n.target),JA).getOr(null);if(C(o)&&((e,t,n)=>QA(n)&&n!==t&&e.isEditable(n.parentElement))(t.dom,t.getBody(),o)){const r=t.dom.getPos(o),s=t.getBody(),a=t.getDoc().documentElement;e.set({element:o,dataTransfer:XR(),dragging:!1,screenX:n.screenX,screenY:n.screenY,maxX:(t.inline?s.scrollWidth:a.offsetWidth)-2,maxY:(t.inline?s.scrollHeight:a.offsetHeight)-2,relX:n.pageX-r.x,relY:n.pageY-r.y,width:o.offsetWidth,height:o.offsetHeight,ghost:eT(t,o,o.offsetWidth,o.offsetHeight),intervalId:Pr(100)})}}})(t,e),s=lT(t,e),a=((e,t)=>n=>{e.on((e=>{var o;if(e.intervalId.clear(),e.dragging){if(((e,t,n)=>!y(t)&&t!==n&&!e.dom.isChildOf(t,n)&&e.dom.isEditable(t))(t,(e=>{const t=e.getSel();if(C(t)){const e=t.getRangeAt(0).startContainer;return dr(e)?e.parentNode:e}return null})(t.selection),e.element)){const r=null!==(o=t.getDoc().elementFromPoint(n.clientX,n.clientY))&&void 0!==o?o:t.getBody();iT(t,"drop",r,e.dataTransfer,n).isDefaultPrevented()||t.undoManager.transact((()=>{((e,t)=>{const n=e.getParent(t.parentNode,e.isBlock);aT(t),n&&n!==e.getRoot()&&e.isEmpty(n)&&Za(Cn(n))})(t.dom,e.element),(e=>{const t=e.getData("text/html");return""===t?I.none():I.some(t)})(e.dataTransfer).each((e=>t.insertContent(e))),t._selectionOverrides.hideFakeCaret()}))}iT(t,"dragend",t.getBody(),e.dataTransfer,n)}})),cT(e)})(t,e),i=((e,t)=>n=>dT(e,t,I.some(n)))(t,e);e.on("mousedown",r),e.on("mousemove",s),e.on("mouseup",a),n.bind(o,"mousemove",s),n.bind(o,"mouseup",i),e.on("remove",(()=>{n.unbind(o,"mousemove",s),n.unbind(o,"mouseup",i)})),e.on("keydown",(n=>{n.keyCode===yf.ESC&&dT(t,e,I.none())}))},mT=vr,fT=(e,t)=>pb(e.getBody(),t),gT=e=>{const t=e.selection,n=e.dom,o=e.getBody(),r=Vc(e,o,n.isBlock,(()=>zg(e))),s="sel-"+n.uniqueId(),a="data-mce-selected";let i;const l=e=>e!==o&&(mT(e)||wr(e))&&n.isChildOf(e,o)&&n.isEditable(e.parentNode),d=(n,o,s,a=!0)=>e.dispatch("ShowCaret",{target:o,direction:n,before:s}).isDefaultPrevented()?null:(a&&t.scrollIntoView(o,-1===n),r.show(s,o)),c=e=>si(e)||di(e)||ci(e),u=e=>c(e.startContainer)||c(e.endContainer),m=t=>{const o=e.schema.getVoidElements(),r=n.createRng(),s=t.startContainer,a=t.startOffset,i=t.endContainer,l=t.endOffset;return ke(o,s.nodeName.toLowerCase())?0===a?r.setStartBefore(s):r.setStartAfter(s):r.setStart(s,a),ke(o,i.nodeName.toLowerCase())?0===l?r.setEndBefore(i):r.setEndAfter(i):r.setEnd(i,l),r},f=(r,c)=>{if(!r)return null;if(r.collapsed){if(!u(r)){const e=c?1:-1,t=bu(e,o,r),s=t.getNode(!c);if(C(s)){if(Kc(s))return d(e,s,!!c&&!t.isAtEnd(),!1);if(ri(s)&&vr(s.nextSibling)){const e=n.createRng();return e.setStart(s,0),e.setEnd(s,0),e}}const a=t.getNode(c);if(C(a)){if(Kc(a))return d(e,a,!c&&!t.isAtEnd(),!1);if(ri(a)&&vr(a.previousSibling)){const e=n.createRng();return e.setStart(a,1),e.setEnd(a,1),e}}}return null}let m=r.startContainer,f=r.startOffset;const g=r.endOffset;if(dr(m)&&0===f&&mT(m.parentNode)&&(m=m.parentNode,f=n.nodeIndex(m),m=m.parentNode),!er(m))return null;if(g===f+1&&m===r.endContainer){const o=m.childNodes[f];if(l(o))return(o=>{const r=o.cloneNode(!0),l=e.dispatch("ObjectSelected",{target:o,targetClone:r});if(l.isDefaultPrevented())return null;const d=((o,r)=>{const a=Cn(e.getBody()),i=e.getDoc(),l=no(a,"#"+s).getOrThunk((()=>{const e=bn('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>',i);return Jt(e,"id",s),yo(a,e),e})),d=n.createRng();Eo(l),wo(l,[yn(Wo,i),Cn(r),yn(Wo,i)]),d.setStart(l.dom.firstChild,1),d.setEnd(l.dom.lastChild,0),co(l,{top:n.getPos(o,e.getBody()).y+"px"}),vg(l);const c=t.getSel();return c&&(c.removeAllRanges(),c.addRange(d)),d})(o,l.targetClone),c=Cn(o);return q(zo(Cn(e.getBody()),`*[${a}]`),(e=>{_n(c,e)||rn(e,a)})),n.getAttrib(o,a)||o.setAttribute(a,"1"),i=o,p(),d})(o)}return null},g=()=>{i&&i.removeAttribute(a),no(Cn(e.getBody()),"#"+s).each(xo),i=null},p=()=>{r.hide()};return sw(e)||(e.on("click",(t=>{n.isEditable(t.target)||(t.preventDefault(),e.focus())})),e.on("blur NewBlock",g),e.on("ResizeWindow FullscreenStateChanged",r.reposition),e.on("tap",(t=>{const n=t.target,o=fT(e,n);mT(o)?(t.preventDefault(),ME(e,o).each(f)):l(n)&&ME(e,n).each(f)}),!0),e.on("mousedown",(r=>{const s=r.target;if(s!==o&&"HTML"!==s.nodeName&&!n.isChildOf(s,o))return;if(!((e,t,n)=>{const o=Cn(e.getBody()),r=e.inline?o:Cn(Rn(o).dom.documentElement),s=((e,t,n,o)=>{const r=(e=>e.dom.getBoundingClientRect())(t);return{x:n-(e?r.left+t.dom.clientLeft+Fw(t):0),y:o-(e?r.top+t.dom.clientTop+Iw(t):0)}})(e.inline,r,t,n);return((e,t,n)=>{const o=Lw(e),r=Mw(e);return t>=0&&n>=0&&t<=o&&n<=r})(r,s.x,s.y)})(e,r.clientX,r.clientY))return;g(),p();const a=fT(e,s);mT(a)?(r.preventDefault(),ME(e,a).each(f)):YA(o,r.clientX,r.clientY).each((n=>{var o;r.preventDefault(),(o=d(1,n.node,n.position===HA.Before,!1))&&t.setRng(o),tr(a)?a.focus():e.getBody().focus()}))})),e.on("keypress",(e=>{yf.modifierPressed(e)||mT(t.getNode())&&e.preventDefault()})),e.on("GetSelectionRange",(e=>{let t=e.range;if(i){if(!i.parentNode)return void(i=null);t=t.cloneRange(),t.selectNode(i),e.range=t}})),e.on("SetSelectionRange",(e=>{e.range=m(e.range);const t=f(e.range,e.forward);t&&(e.range=t)})),e.on("AfterSetSelectionRange",(e=>{const t=e.range,o=t.startContainer.parentElement;var r;u(t)||er(r=o)&&"mcepastebin"===r.id||p(),(e=>C(e)&&n.hasClass(e,"mce-offscreen-selection"))(o)||g()})),(e=>{uT(e),qd(e)&&(e=>{const t=t=>{if(!t.isDefaultPrevented()){const n=t.dataTransfer;n&&(H(n.types,"Files")||n.files.length>0)&&(t.preventDefault(),"drop"===t.type&&Vw(e,"Dropped file type is not supported"))}},n=n=>{Dg(e,n.target)&&t(n)},o=()=>{const o=ma.DOM,r=e.dom,s=document,a=e.inline?e.getBody():e.getDoc(),i=["drop","dragover"];q(i,(e=>{o.bind(s,e,n),r.bind(a,e,t)})),e.on("remove",(()=>{q(i,(e=>{o.unbind(s,e,n),r.unbind(a,e,t)}))}))};e.on("init",(()=>{Tg.setEditorTimeout(e,o,0)}))})(e)})(e),(e=>{const t=Ca((()=>{if(!e.removed&&e.getBody().contains(document.activeElement)){const t=e.selection.getRng();if(t.collapsed){const n=IE(e,t,!1);e.selection.setRng(n)}}}),0);e.on("focus",(()=>{t.throttle()})),e.on("blur",(()=>{t.cancel()}))})(e),(e=>{e.on("init",(()=>{e.on("focusin",(t=>{const n=t.target;if(wr(n)){const t=pb(e.getBody(),n),o=vr(t)?t:n;e.selection.getNode()!==o&&ME(e,o).each((t=>e.selection.setRng(t)))}}))}))})(e)),{showCaret:d,showBlockCaretContainer:e=>{e.hasAttribute("data-mce-caret")&&(ui(e),t.scrollIntoView(e))},hideFakeCaret:p,destroy:()=>{r.destroy(),i=null}}},pT=(e,t)=>{let n=t;for(let t=e.previousSibling;dr(t);t=t.previousSibling)n+=t.data.length;return n},hT=(e,t,n,o,r)=>{if(dr(n)&&(o<0||o>n.data.length))return[];const s=r&&dr(n)?[pT(n,o)]:[o];let a=n;for(;a!==t&&a.parentNode;)s.push(e.nodeIndex(a,r)),a=a.parentNode;return a===t?s.reverse():[]},bT=(e,t,n,o,r,s,a=!1)=>({start:hT(e,t,n,o,a),end:hT(e,t,r,s,a)}),vT=(e,t)=>{const n=t.slice(),o=n.pop();return E(o)?X(n,((e,t)=>e.bind((e=>I.from(e.childNodes[t])))),I.some(e)).bind((e=>dr(e)&&(o<0||o>e.data.length)?I.none():I.some({node:e,offset:o}))):I.none()},yT=(e,t)=>vT(e,t.start).bind((({node:n,offset:o})=>vT(e,t.end).map((({node:e,offset:t})=>{const r=document.createRange();return r.setStart(n,o),r.setEnd(e,t),r})))),CT=(e,t,n)=>{if(t&&e.isEmpty(t)&&!n(t)){const o=t.parentNode;e.remove(t,dr(t.firstChild)&&Go(t.firstChild.data)),CT(e,o,n)}},wT=(e,t,n,o=!0)=>{const r=t.startContainer.parentNode,s=t.endContainer.parentNode;t.deleteContents(),o&&!n(t.startContainer)&&(dr(t.startContainer)&&0===t.startContainer.data.length&&e.remove(t.startContainer),dr(t.endContainer)&&0===t.endContainer.data.length&&e.remove(t.endContainer),CT(e,r,n),r!==s&&CT(e,s,n))},ET=(e,t)=>I.from(e.dom.getParent(t.startContainer,e.dom.isBlock)),xT=(e,t,n)=>{const o=e.dynamicPatternsLookup({text:n,block:t});return{...e,blockPatterns:Nl(o).concat(e.blockPatterns),inlinePatterns:Rl(o).concat(e.inlinePatterns)}},kT=(e,t,n,o)=>{const r=e.createRng();return r.setStart(t,0),r.setEnd(n,o),r.toString()},_T=(e,t)=>e.create("span",{"data-mce-type":"bookmark",id:t}),ST=(e,t)=>{const n=e.createRng();return n.setStartAfter(t.start),n.setEndBefore(t.end),n},NT=(e,t,n)=>{const o=yT(e.getRoot(),n).getOrDie("Unable to resolve path range"),r=o.startContainer,s=o.endContainer,a=0===o.endOffset?s:s.splitText(o.endOffset),i=0===o.startOffset?r:r.splitText(o.startOffset),l=i.parentNode;return{prefix:t,end:a.parentNode.insertBefore(_T(e,t+"-end"),a),start:l.insertBefore(_T(e,t+"-start"),i)}},RT=(e,t,n)=>{CT(e,e.get(t.prefix+"-end"),n),CT(e,e.get(t.prefix+"-start"),n)},AT=e=>0===e.start.length,TT=(e,t,n,o)=>{const r=t.start;var s;return X_(e,o.container,o.offset,(s=r,(e,t)=>{const n=e.data.substring(0,t),o=n.lastIndexOf(s.charAt(s.length-1)),r=n.lastIndexOf(s);return-1!==r?r+s.length:-1!==o?o+1:-1}),n).bind((o=>{var s,a;const i=null!==(a=null===(s=n.textContent)||void 0===s?void 0:s.indexOf(r))&&void 0!==a?a:-1;if(-1!==i&&o.offset>=i+r.length){const t=e.createRng();return t.setStart(o.container,o.offset-r.length),t.setEnd(o.container,o.offset),I.some(t)}{const s=o.offset-r.length;return Y_(o.container,s,n).map((t=>{const n=e.createRng();return n.setStart(t.container,t.offset),n.setEnd(o.container,o.offset),n})).filter((e=>e.toString()===r)).orThunk((()=>TT(e,t,n,V_(o.container,0))))}}))},OT=(e,t,n,o)=>{const r=e.dom,s=r.getRoot(),a=n.pattern,i=n.position.container,l=n.position.offset;return Y_(i,l-n.pattern.end.length,t).bind((d=>{const c=bT(r,s,d.container,d.offset,i,l,o);if(AT(a))return I.some({matches:[{pattern:a,startRng:c,endRng:c}],position:d});{const i=BT(e,n.remainingPatterns,d.container,d.offset,t,o),l=i.getOr({matches:[],position:d}),u=l.position,m=((e,t,n,o,r,s=!1)=>{if(0===t.start.length&&!s){const t=e.createRng();return t.setStart(n,o),t.setEnd(n,o),I.some(t)}return K_(n,o,r).bind((n=>TT(e,t,r,n).bind((e=>{var t;if(s){if(e.endContainer===n.container&&e.endOffset===n.offset)return I.none();if(0===n.offset&&(null===(t=e.endContainer.textContent)||void 0===t?void 0:t.length)===e.endOffset)return I.none()}return I.some(e)}))))})(r,a,u.container,u.offset,t,i.isNone());return m.map((e=>{const t=((e,t,n,o=!1)=>bT(e,t,n.startContainer,n.startOffset,n.endContainer,n.endOffset,o))(r,s,e,o);return{matches:l.matches.concat([{pattern:a,startRng:t,endRng:c}]),position:V_(e.startContainer,e.startOffset)}}))}}))},BT=(e,t,n,o,r,s)=>{const a=e.dom;return K_(n,o,a.getRoot()).bind((i=>{const l=kT(a,r,n,o);for(let a=0;a<t.length;a++){const d=t[a];if(!Ve(l,d.end))continue;const c=t.slice();c.splice(a,1);const u=OT(e,r,{pattern:d,remainingPatterns:c,position:i},s);if(u.isNone()&&o>0)return BT(e,t,n,o-1,r,s);if(u.isSome())return u}return I.none()}))},PT=(e,t,n)=>{e.selection.setRng(n),"inline-format"===t.type?q(t.format,(t=>{e.formatter.apply(t)})):e.execCommand(t.cmd,!1,t.value)},DT=(e,t,n,o,r,s)=>{var a;return((e,t)=>{const n=ne(e,(e=>$(t,(t=>e.pattern.start===t.pattern.start&&e.pattern.end===t.pattern.end))));return e.length===t.length?n?e:t:e.length>t.length?e:t})(BT(e,r.inlinePatterns,n,o,t,s).fold((()=>[]),(e=>e.matches)),BT(e,(a=r.inlinePatterns,ae(a,((e,t)=>t.end.length-e.end.length))),n,o,t,s).fold((()=>[]),(e=>e.matches)))},LT=(e,t)=>{if(0===t.length)return;const n=e.dom,o=e.selection.getBookmark(),r=((e,t)=>{const n=Da("mce_textpattern"),o=G(t,((t,o)=>{const r=NT(e,n+`_end${t.length}`,o.endRng);return t.concat([{...o,endMarker:r}])}),[]);return G(o,((t,r)=>{const s=o.length-t.length-1,a=AT(r.pattern)?r.endMarker:NT(e,n+`_start${s}`,r.startRng);return t.concat([{...r,startMarker:a}])}),[])})(n,t);q(r,(t=>{const o=n.getParent(t.startMarker.start,n.isBlock),r=e=>e===o;AT(t.pattern)?((e,t,n,o)=>{const r=ST(e.dom,n);wT(e.dom,r,o),PT(e,t,r)})(e,t.pattern,t.endMarker,r):((e,t,n,o,r)=>{const s=e.dom,a=ST(s,o),i=ST(s,n);wT(s,i,r),wT(s,a,r);const l={prefix:n.prefix,start:n.end,end:o.start},d=ST(s,l);PT(e,t,d)})(e,t.pattern,t.startMarker,t.endMarker,r),RT(n,t.endMarker,r),RT(n,t.startMarker,r)})),e.selection.moveToBookmark(o)},MT=(e,t,n)=>((e,t,n)=>{if(dr(e)&&0>=e.length)return I.some(V_(e,0));{const t=Ua(q_);return I.from(t.forwards(e,0,W_(e),n)).map((e=>V_(e.container,0)))}})(t,0,t).map((o=>{const r=o.container;return G_(r,n.start.length,t).each((n=>{const o=e.createRng();o.setStart(r,0),o.setEnd(n.container,n.offset),wT(e,o,(e=>e===t))})),r})),IT=e=>(t,n)=>{const o=t.dom,r=n.pattern,s=yT(o.getRoot(),n.range).getOrDie("Unable to resolve path range");return ET(t,s).each((n=>{"block-format"===r.type?((e,t)=>{const n=t.get(e);return p(n)&&le(n).exists((e=>ke(e,"block")))})(r.format,t.formatter)&&t.undoManager.transact((()=>{e(t.dom,n,r),t.formatter.apply(r.format)})):"block-command"===r.type&&t.undoManager.transact((()=>{e(t.dom,n,r),t.execCommand(r.cmd,!1,r.value)}))})),!0},FT=e=>(t,n)=>{const o=(e=>ae(e,((e,t)=>t.start.length-e.start.length)))(t),r=n.replace(Wo," ");return Q(o,(t=>e(t,n,r)))},UT=(e,t)=>(n,o,r,s,a)=>{var i;void 0===a&&(a=null!==(i=o.textContent)&&void 0!==i?i:"");const l=n.dom,d=ql(n);return l.is(o,d)?e(r.blockPatterns,a).map((e=>t&&Dt.trim(a).length===e.start.length?[]:[{pattern:e,range:bT(l,l.getRoot(),o,0,o,0,s)}])).getOr([]):[]},zT=IT(((e,t,n)=>{MT(e,t,n).each((e=>{const t=Cn(e),n=ja(t);/^\s[^\s]/.test(n)&&((e,t)=>{za.set(e,t)})(t,n.slice(1))}))})),jT=FT(((e,t,n)=>0===t.indexOf(e.start)||0===n.indexOf(e.start))),HT=UT(jT,!0),$T=IT(MT),VT=FT(((e,t,n)=>t===e.start||n===e.start)),qT=UT(VT,!1),WT=(e,t,n)=>{for(let o=0;o<e.length;o++)if(n(e[o],t))return!0;return!1},KT=e=>{const t=[",",".",";",":","!","?"],n=[32],o=()=>{return t=gc(e),n=pc(e),{inlinePatterns:Rl(t),blockPatterns:Nl(t),dynamicPatternsLookup:n};var t,n},r=()=>(e=>e.options.isSet("text_patterns_lookup"))(e);e.on("keydown",(t=>{if(13===t.keyCode&&!yf.modifierPressed(t)&&e.selection.isCollapsed()){const n=Al(o(),"enter");(n.inlinePatterns.length>0||n.blockPatterns.length>0||r())&&((e,t)=>((e,t)=>{const n=e.selection.getRng();return ET(e,n).map((o=>{var r;const s=Math.max(0,n.startOffset),a=xT(t,o,null!==(r=o.textContent)&&void 0!==r?r:"");return{inlineMatches:DT(e,o,n.startContainer,s,a,!0),blockMatches:HT(e,o,a,!0)}})).filter((({inlineMatches:e,blockMatches:t})=>t.length>0||e.length>0))})(e,t).fold(L,(({inlineMatches:t,blockMatches:n})=>(e.undoManager.add(),e.undoManager.extra((()=>{e.execCommand("mceInsertNewLine")}),(()=>{(e=>{e.insertContent(Qa,{preserve_zwsp:!0})})(e),LT(e,t),((e,t)=>{if(0===t.length)return;const n=e.selection.getBookmark();q(t,(t=>zT(e,t))),e.selection.moveToBookmark(n)})(e,n);const o=e.selection.getRng(),r=K_(o.startContainer,o.startOffset,e.dom.getRoot());e.execCommand("mceInsertNewLine"),r.each((t=>{const n=t.container;n.data.charAt(t.offset-1)===qo&&(n.deleteData(t.offset-1,1),CT(e.dom,n.parentNode,(t=>t===e.dom.getRoot())))}))})),!0))))(e,n)&&t.preventDefault()}}),!0),e.on("keydown",(t=>{if(32===t.keyCode&&e.selection.isCollapsed()){const n=Al(o(),"space");(n.blockPatterns.length>0||r())&&((e,t)=>((e,t)=>{const n=e.selection.getRng();return ET(e,n).map((o=>{const r=Math.max(0,n.startOffset),s=kT(e.dom,o,n.startContainer,r),a=xT(t,o,s);return qT(e,o,a,!1,s)})).filter((e=>e.length>0))})(e,t).fold(L,(t=>(e.undoManager.transact((()=>{((e,t)=>{q(t,(t=>$T(e,t)))})(e,t)})),!0))))(e,n)&&t.preventDefault()}}),!0);const s=()=>{if(e.selection.isCollapsed()){const t=Al(o(),"space");(t.inlinePatterns.length>0||r())&&((e,t)=>{const n=e.selection.getRng();ET(e,n).map((o=>{const r=Math.max(0,n.startOffset-1),s=kT(e.dom,o,n.startContainer,r),a=xT(t,o,s),i=DT(e,o,n.startContainer,r,a,!1);i.length>0&&e.undoManager.transact((()=>{LT(e,i)}))}))})(e,t)}};e.on("keyup",(e=>{WT(n,e,((e,t)=>e===t.keyCode&&!yf.modifierPressed(t)))&&s()})),e.on("keypress",(n=>{WT(t,n,((e,t)=>e.charCodeAt(0)===t.charCode))&&Tg.setEditorTimeout(e,s)}))},YT=e=>{const t=Dt.each,n=yf.BACKSPACE,o=yf.DELETE,r=e.dom,s=e.selection,a=e.parser,i=Tt.browser,l=i.isFirefox(),d=i.isChromium()||i.isSafari(),c=Tt.deviceType.isiPhone()||Tt.deviceType.isiPad(),u=Tt.os.isMacOS()||Tt.os.isiOS(),m=(t,n)=>{try{e.getDoc().execCommand(t,!1,String(n))}catch(e){}},f=e=>e.isDefaultPrevented(),g=()=>{e.shortcuts.add("meta+a",null,"SelectAll")},p=()=>{e.inline||r.bind(e.getDoc(),"mousedown mouseup",(t=>{let n;if(t.target===e.getDoc().documentElement)if(n=s.getRng(),e.getBody().focus(),"mousedown"===t.type){if(si(n.startContainer))return;s.placeCaretAt(t.clientX,t.clientY)}else s.setRng(n)}))},h=()=>{Range.prototype.getClientRects||e.on("mousedown",(t=>{if(!f(t)&&"HTML"===t.target.nodeName){const t=e.getBody();t.blur(),Tg.setEditorTimeout(e,(()=>{t.focus()}))}}))},b=()=>{const t=Yd(e);e.on("click",(n=>{const o=n.target;/^(IMG|HR)$/.test(o.nodeName)&&r.isEditable(o)&&(n.preventDefault(),e.selection.select(o),e.nodeChanged()),"A"===o.nodeName&&r.hasClass(o,t)&&0===o.childNodes.length&&r.isEditable(o.parentNode)&&(n.preventDefault(),s.select(o))}))},v=()=>{e.on("keydown",(e=>{if(!f(e)&&e.keyCode===n&&s.isCollapsed()&&0===s.getRng().startOffset){const t=s.getNode().previousSibling;if(t&&t.nodeName&&"table"===t.nodeName.toLowerCase())return e.preventDefault(),!1}return!0}))},y=()=>{zd(e)||e.on("BeforeExecCommand mousedown",(()=>{m("StyleWithCSS",!1),m("enableInlineTableEditing",!1),vd(e)||m("enableObjectResizing",!1)}))},C=()=>{e.contentStyles.push("img:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")},w=()=>{e.inline||e.on("keydown",(()=>{document.activeElement===document.body&&e.getWin().focus()}))},E=()=>{e.inline||(e.contentStyles.push("body {min-height: 150px}"),e.on("click",(t=>{let n;"HTML"===t.target.nodeName&&(n=e.selection.getRng(),e.getBody().focus(),e.selection.setRng(n),e.selection.normalize(),e.nodeChanged())})))},x=()=>{u&&e.on("keydown",(t=>{!yf.metaKeyPressed(t)||t.shiftKey||37!==t.keyCode&&39!==t.keyCode||(t.preventDefault(),e.selection.getSel().modify("move",37===t.keyCode?"backward":"forward","lineboundary"))}))},_=()=>{e.on("click",(e=>{let t=e.target;do{if("A"===t.tagName)return void e.preventDefault()}while(t=t.parentNode)})),e.contentStyles.push(".mce-content-body {-webkit-touch-callout: none}")},S=()=>{e.on("init",(()=>{e.dom.bind(e.getBody(),"submit",(e=>{e.preventDefault()}))}))},N=k;return sw(e)?(d&&(p(),b(),S(),g(),c&&(w(),E(),_())),l&&(h(),y(),C(),x())):(e.on("keydown",(t=>{if(f(t)||t.keyCode!==yf.BACKSPACE)return;let n=s.getRng();const o=n.startContainer,a=n.startOffset,i=r.getRoot();let l=o;if(n.collapsed&&0===a){for(;l.parentNode&&l.parentNode.firstChild===l&&l.parentNode!==i;)l=l.parentNode;"BLOCKQUOTE"===l.nodeName&&(e.formatter.toggle("blockquote",void 0,l),n=r.createRng(),n.setStart(o,0),n.setEnd(o,0),s.setRng(n))}})),(()=>{const t=e=>{const t=r.create("body"),n=e.cloneContents();return t.appendChild(n),s.serializer.serialize(t,{format:"html"})};e.on("keydown",(s=>{const a=s.keyCode;if(!f(s)&&(a===o||a===n)&&e.selection.isEditable()){const n=e.selection.isCollapsed(),o=e.getBody();if(n&&!Ar(e.schema,o))return;if(!n&&!(n=>{const o=t(n),s=r.createRng();return s.selectNode(e.getBody()),o===t(s)})(e.selection.getRng()))return;s.preventDefault(),e.setContent(""),o.firstChild&&r.isBlock(o.firstChild)?e.selection.setCursorLocation(o.firstChild,0):e.selection.setCursorLocation(o,0),e.nodeChanged()}}))})(),Tt.windowsPhone||e.on("keyup focusin mouseup",(t=>{yf.modifierPressed(t)||(e=>{const t=e.getBody(),n=e.selection.getRng();return n.startContainer===n.endContainer&&n.startContainer===t&&0===n.startOffset&&n.endOffset===t.childNodes.length})(e)||s.normalize()}),!0),d&&(p(),b(),e.on("init",(()=>{m("DefaultParagraphSeparator",ql(e))})),S(),v(),a.addNodeFilter("br",(e=>{let t=e.length;for(;t--;)"Apple-interchange-newline"===e[t].attr("class")&&e[t].remove()})),c?(w(),E(),_()):g()),l&&(e.on("keydown",(t=>{if(!f(t)&&t.keyCode===n){if(!e.getBody().getElementsByTagName("hr").length)return;if(s.isCollapsed()&&0===s.getRng().startOffset){const e=s.getNode(),n=e.previousSibling;if("HR"===e.nodeName)return r.remove(e),void t.preventDefault();n&&n.nodeName&&"hr"===n.nodeName.toLowerCase()&&(r.remove(n),t.preventDefault())}}})),h(),(()=>{const n=()=>{const n=r.getAttribs(s.getStart().cloneNode(!1));return()=>{const o=s.getStart();o!==e.getBody()&&(r.setAttrib(o,"style",null),t(n,(e=>{o.setAttributeNode(e.cloneNode(!0))})))}},o=()=>!s.isCollapsed()&&r.getParent(s.getStart(),r.isBlock)!==r.getParent(s.getEnd(),r.isBlock);e.on("keypress",(t=>{let r;return!(!(f(t)||8!==t.keyCode&&46!==t.keyCode)&&o()&&(r=n(),e.getDoc().execCommand("delete",!1),r(),t.preventDefault(),1))})),r.bind(e.getDoc(),"cut",(t=>{if(!f(t)&&o()){const t=n();Tg.setEditorTimeout(e,(()=>{t()}))}}))})(),y(),e.on("SetContent ExecCommand",(e=>{"setcontent"!==e.type&&"mceInsertLink"!==e.command||t(r.select("a:not([data-mce-block])"),(e=>{var t;let n=e.parentNode;const o=r.getRoot();if((null==n?void 0:n.lastChild)===e){for(;n&&!r.isBlock(n);){if((null===(t=n.parentNode)||void 0===t?void 0:t.lastChild)!==n||n===o)return;n=n.parentNode}r.add(n,"br",{"data-mce-bogus":1})}}))})),C(),x(),v())),{refreshContentEditable:N,isHidden:()=>{if(!l||e.removed)return!1;const t=e.selection.getSel();return!t||!t.rangeCount||0===t.rangeCount}}},GT=ma.DOM,XT=e=>e.inline?e.getElement().nodeName.toLowerCase():void 0,ZT=e=>Ce(e,(e=>!1===v(e))),QT=e=>{const t=e.options.get,n=e.editorUpload.blobCache;return ZT({allow_conditional_comments:t("allow_conditional_comments"),allow_html_data_urls:t("allow_html_data_urls"),allow_svg_data_urls:t("allow_svg_data_urls"),allow_html_in_named_anchor:t("allow_html_in_named_anchor"),allow_script_urls:t("allow_script_urls"),allow_unsafe_link_target:t("allow_unsafe_link_target"),convert_unsafe_embeds:t("convert_unsafe_embeds"),convert_fonts_to_spans:t("convert_fonts_to_spans"),fix_list_elements:t("fix_list_elements"),font_size_legacy_values:t("font_size_legacy_values"),forced_root_block:t("forced_root_block"),forced_root_block_attrs:t("forced_root_block_attrs"),preserve_cdata:t("preserve_cdata"),inline_styles:t("inline_styles"),root_name:XT(e),sandbox_iframes:t("sandbox_iframes"),sandbox_iframes_exclusions:Rc(e),sanitize:t("xss_sanitization"),validate:!0,blob_cache:n,document:e.getDoc()})},JT=e=>{const t=e.options.get;return ZT({custom_elements:t("custom_elements"),extended_valid_elements:t("extended_valid_elements"),invalid_elements:t("invalid_elements"),invalid_styles:t("invalid_styles"),schema:t("schema"),valid_children:t("valid_children"),valid_classes:t("valid_classes"),valid_elements:t("valid_elements"),valid_styles:t("valid_styles"),verify_html:t("verify_html"),padd_empty_block_inline_children:t("format_empty_lines")})},eO=e=>e.inline?e.ui.styleSheetLoader:e.dom.styleSheetLoader,tO=e=>{const t=eO(e),n=pd(e),o=e.contentCSS,r=()=>{t.unloadAll(o),e.inline||e.ui.styleSheetLoader.unloadAll(n)},s=()=>{e.removed?r():e.on("remove",r)};if(e.contentStyles.length>0){let t="";Dt.each(e.contentStyles,(e=>{t+=e+"\r\n"})),e.dom.addStyle(t)}const a=Promise.all(((e,t,n)=>{const{pass:o,fail:r}=K(t,(e=>tinymce.Resource.has(Yw(e)))),s=o.map((t=>{const n=tinymce.Resource.get(Yw(t));return m(n)?Promise.resolve(eO(e).loadRawCss(t,n)):Promise.resolve()})),a=[...s,eO(e).loadAll(r)];return e.inline?a:a.concat([e.ui.styleSheetLoader.loadAll(n)])})(e,o,n)).then(s).catch(s),i=gd(e);return i&&((e,t)=>{const n=Cn(e.getBody()),o=Wn(qn(n)),r=vn("style");Jt(r,"type","text/css"),yo(r,yn(t)),yo(o,r),e.on("remove",(()=>{xo(r)}))})(e,i),a},nO=e=>{!0!==e.removed&&((e=>{sw(e)||e.load({initial:!0,format:"html"}),e.startContent=e.getContent({format:"raw"})})(e),(e=>{e.bindPendingEventDelegates(),e.initialized=!0,(e=>{e.dispatch("Init")})(e),e.focus(!0),(e=>{const t=e.dom.getRoot();e.inline||bm(e)&&e.selection.getStart(!0)!==t||Hu(t).each((t=>{const n=t.getNode(),o=ar(n)?Hu(n).getOr(t):t;e.selection.setRng(o.toRange())}))})(e),e.nodeChanged({initial:!0});const t=Zd(e);w(t)&&t.call(e,e),(e=>{const t=Jd(e);t&&Tg.setEditorTimeout(e,(()=>{let n;n=!0===t?e:e.editorManager.get(t),n&&!n.destroyed&&(n.focus(),n.selection.scrollIntoView())}),100)})(e)})(e))},oO=e=>{const t=e.getElement();let n=e.getDoc();e.inline&&(GT.addClass(t,"mce-content-body"),e.contentDocument=n=document,e.contentWindow=window,e.bodyElement=t,e.contentAreaContainer=t);const o=e.getBody();o.disabled=!0,e.readonly=zd(e),e._editableRoot=jd(e),!e.readonly&&e.hasEditableRoot()&&(e.inline&&"static"===GT.getStyle(o,"position",!0)&&(o.style.position="relative"),o.contentEditable="true"),o.disabled=!1,e.editorUpload=nE(e),e.schema=Fs(JT(e)),e.dom=ma(n,{keep_values:!0,url_converter:e.convertURL,url_converter_scope:e,update_styles:!0,root_element:e.inline?e.getBody():null,collect:e.inline,schema:e.schema,contentCssCors:id(e),referrerPolicy:ld(e),onSetAttrib:t=>{e.dispatch("SetAttrib",t)}}),e.parser=(e=>{const t=_C(QT(e),e.schema);return t.addAttributeFilter("src,href,style,tabindex",((t,n)=>{const o=e.dom,r="data-mce-"+n;let s=t.length;for(;s--;){const a=t[s];let i=a.attr(n);if(i&&!a.attr(r)){if(0===i.indexOf("data:")||0===i.indexOf("blob:"))continue;"style"===n?(i=o.serializeStyle(o.parseStyle(i),a.name),i.length||(i=null),a.attr(r,i),a.attr(n,i)):"tabindex"===n?(a.attr(r,i),a.attr(n,null)):a.attr(r,e.convertURL(i,n,a.name))}}})),t.addNodeFilter("script",(e=>{let t=e.length;for(;t--;){const n=e[t],o=n.attr("type")||"no/type";0!==o.indexOf("mce-")&&n.attr("type","mce-"+o)}})),yc(e)&&t.addNodeFilter("#cdata",(t=>{var n;let o=t.length;for(;o--;){const r=t[o];r.type=8,r.name="#comment",r.value="[CDATA["+e.dom.encode(null!==(n=r.value)&&void 0!==n?n:"")+"]]"}})),t.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",(t=>{let n=t.length;const o=e.schema.getNonEmptyElements();for(;n--;){const e=t[n];e.isEmpty(o)&&0===e.getAll("br").length&&e.append(new Jg("br",1))}})),t})(e),e.serializer=hw((e=>{const t=e.options.get;return{...QT(e),...JT(e),...ZT({remove_trailing_brs:t("remove_trailing_brs"),pad_empty_with_br:t("pad_empty_with_br"),url_converter:t("url_converter"),url_converter_scope:t("url_converter_scope"),element_format:t("element_format"),entities:t("entities"),entity_encoding:t("entity_encoding"),indent:t("indent"),indent_after:t("indent_after"),indent_before:t("indent_before")})}})(e),e),e.selection=fw(e.dom,e.getWin(),e.serializer,e),e.annotator=df(e),e.formatter=fE(e),e.undoManager=pE(e),e._nodeChangeDispatcher=new OR(e),e._selectionOverrides=gT(e),(e=>{const t=Dr(),n=Br(!1),o=wa((t=>{e.dispatch("longpress",{...t,type:"longpress"}),n.set(!0)}),400);e.on("touchstart",(e=>{Wk(e).each((r=>{o.cancel();const s={x:r.clientX,y:r.clientY,target:e.target};o.throttle(e),n.set(!1),t.set(s)}))}),!0),e.on("touchmove",(r=>{o.cancel(),Wk(r).each((o=>{t.on((r=>{((e,t)=>{const n=Math.abs(e.clientX-t.x),o=Math.abs(e.clientY-t.y);return n>5||o>5})(o,r)&&(t.clear(),n.set(!1),e.dispatch("longpresscancel"))}))}))}),!0),e.on("touchend touchcancel",(r=>{o.cancel(),"touchcancel"!==r.type&&t.get().filter((e=>e.target.isEqualNode(r.target))).each((()=>{n.get()?r.preventDefault():e.dispatch("tap",{...r,type:"tap"})}))}),!0)})(e),(e=>{(e=>{e.on("click",(t=>{e.dom.getParent(t.target,"details")&&t.preventDefault()}))})(e),(e=>{e.parser.addNodeFilter("details",(t=>{const n=_c(e);q(t,(e=>{"expanded"===n?e.attr("open","open"):"collapsed"===n&&e.attr("open",null)}))})),e.serializer.addNodeFilter("details",(t=>{const n=Sc(e);q(t,(e=>{"expanded"===n?e.attr("open","open"):"collapsed"===n&&e.attr("open",null)}))}))})(e)})(e),(e=>{const t="contenteditable",n=" "+Dt.trim(bc(e))+" ",o=" "+Dt.trim(hc(e))+" ",r=Qk(n),s=Qk(o),a=vc(e);a.length>0&&e.on("BeforeSetContent",(t=>{((e,t,n)=>{let o=t.length,r=n.content;if("raw"!==n.format){for(;o--;)r=r.replace(t[o],Jk(e,r,hc(e)));n.content=r}})(e,a,t)})),e.parser.addAttributeFilter("class",(e=>{let n=e.length;for(;n--;){const o=e[n];r(o)?o.attr(t,"true"):s(o)&&o.attr(t,"false")}})),e.serializer.addAttributeFilter(t,(e=>{let n=e.length;for(;n--;){const o=e[n];if(!r(o)&&!s(o))continue;const i=o.attr("data-mce-content");a.length>0&&i?e_(a,i)?(o.name="#text",o.type=3,o.raw=!0,o.value=i):o.remove():o.attr(t,null)}}))})(e),sw(e)||((e=>{e.on("mousedown",(t=>{t.detail>=3&&(t.preventDefault(),jA(e))}))})(e),(e=>{KT(e)})(e));const r=TR(e);((e,t)=>{e.addCommand("delete",(()=>{((e,t)=>{qk(e,t,!1).fold((()=>{e.selection.isEditable()&&(Lh(e),Uh(e))}),D)})(e,t)})),e.addCommand("forwardDelete",(()=>{((e,t)=>{qk(e,t,!0).fold((()=>{e.selection.isEditable()&&Mh(e)}),D)})(e,t)}))})(e,r),(e=>{e.on("NodeChange",(()=>(e=>{const t=e.dom,n=e.selection,o=e.schema,r=o.getBlockElements(),s=n.getStart(),a=e.getBody();let i,l,d=null;const c=ql(e);if(!s||!er(s))return;const u=a.nodeName.toLowerCase();if(!o.isValidChild(u,c.toLowerCase())||((e,t,n)=>$(Up(Cn(n),Cn(t)),(t=>Kk(e,t.dom))))(r,a,s))return;if(a.firstChild===a.lastChild&&pr(a.firstChild))return i=Xk(e),i.appendChild(Xa().dom),a.replaceChild(i,a.firstChild),e.selection.setCursorLocation(i,0),void e.nodeChanged();let m=a.firstChild;for(;m;)if(er(m)&&Kr(o,m),Yk(o,m)){if(Gk(r,m)){l=m,m=m.nextSibling,t.remove(l);continue}if(!i){if(!d&&e.hasFocus()&&(d=QE(e.selection.getRng(),(()=>document.createElement("span")))),!m.parentNode){m=null;break}i=Xk(e),a.insertBefore(i,m)}l=m,m=m.nextSibling,i.appendChild(l)}else i=null,m=m.nextSibling;d&&(e.selection.setRng(JE(d)),e.nodeChanged())})(e)))})(e),(e=>{var t;const n=e.dom,o=ql(e),r=null!==(t=Cd(e))&&void 0!==t?t:"",s=(t,a)=>{if((e=>{if(vE(e)){const t=e.keyCode;return!yE(e)&&(yf.metaKeyPressed(e)||e.altKey||t>=112&&t<=123||H(hE,t))}return!1})(t))return;const i=e.getBody(),l=!(e=>vE(e)&&!(yE(e)||"keyup"===e.type&&229===e.keyCode))(t)&&((e,t,n)=>{if(e.isEmpty(t,void 0,{skipBogus:!1,includeZwsp:!0})){const o=t.firstElementChild;return!o||!e.getStyle(t.firstElementChild,"padding-left")&&!e.getStyle(t.firstElementChild,"padding-right")&&n===o.nodeName.toLowerCase()}return!1})(n,i,o);(""!==n.getAttrib(i,bE)!==l||a)&&(n.setAttrib(i,bE,l?r:null),((e,t)=>{e.dispatch("PlaceholderToggle",{state:t})})(e,l),e.on(l?"keydown":"keyup",s),e.off(l?"keyup":"keydown",s))};Ge(r)&&e.on("init",(t=>{s(t,!0),e.on("change SetContent ExecCommand",s),e.on("paste",(t=>Tg.setEditorTimeout(e,(()=>s(t)))))}))})(e),DA(e);const s=(e=>{const t=e;return(e=>xe(e.plugins,"rtc").bind((e=>I.from(e.setup))))(e).fold((()=>(t.rtcInstance=rw(e),I.none())),(e=>(t.rtcInstance=(()=>{const e=N(null),t=N("");return{init:{bindEvents:k},undoManager:{beforeChange:k,add:e,undo:e,redo:e,clear:k,reset:k,hasUndo:L,hasRedo:L,transact:e,ignore:k,extra:k},formatter:{match:L,matchAll:N([]),matchNode:N(void 0),canApply:L,closest:t,apply:k,remove:k,toggle:k,formatChanged:N({unbind:k})},editor:{getContent:t,setContent:N({content:"",html:""}),insertContent:N(""),addVisual:k},selection:{getContent:t},autocompleter:{addDecoration:k,removeDecoration:k},raw:{getModel:N(I.none())}}})(),I.some((()=>e().then((e=>(t.rtcInstance=(e=>{const t=e=>f(e)?e:{},{init:n,undoManager:o,formatter:r,editor:s,selection:a,autocompleter:i,raw:l}=e;return{init:{bindEvents:n.bindEvents},undoManager:{beforeChange:o.beforeChange,add:o.add,undo:o.undo,redo:o.redo,clear:o.clear,reset:o.reset,hasUndo:o.hasUndo,hasRedo:o.hasRedo,transact:(e,t,n)=>o.transact(n),ignore:(e,t)=>o.ignore(t),extra:(e,t,n,r)=>o.extra(n,r)},formatter:{match:(e,n,o,s)=>r.match(e,t(n),s),matchAll:r.matchAll,matchNode:r.matchNode,canApply:e=>r.canApply(e),closest:e=>r.closest(e),apply:(e,n,o)=>r.apply(e,t(n)),remove:(e,n,o,s)=>r.remove(e,t(n)),toggle:(e,n,o)=>r.toggle(e,t(n)),formatChanged:(e,t,n,o,s)=>r.formatChanged(t,n,o,s)},editor:{getContent:e=>s.getContent(e),setContent:(e,t)=>({content:s.setContent(e,t),html:""}),insertContent:(e,t)=>(s.insertContent(e),""),addVisual:s.addVisual},selection:{getContent:(e,t)=>a.getContent(t)},autocompleter:{addDecoration:i.addDecoration,removeDecoration:i.removeDecoration},raw:{getModel:()=>I.some(l.getRawModel())}}})(e),e.rtc.isRemote))))))))})(e);(e=>{const t=e.getDoc(),n=e.getBody();(e=>{e.dispatch("PreInit")})(e),ec(e)||(t.body.spellcheck=!1,GT.setAttrib(n,"spellcheck","false")),e.quirks=YT(e),(e=>{e.dispatch("PostRender")})(e);const o=hd(e);void 0!==o&&(n.dir=o);const r=tc(e);r&&e.on("BeforeSetContent",(e=>{Dt.each(r,(t=>{e.content=e.content.replace(t,(e=>"\x3c!--mce:protected "+escape(e)+"--\x3e"))}))})),e.on("SetContent",(()=>{e.addVisual(e.getBody())})),e.on("compositionstart compositionend",(t=>{e.composing="compositionstart"===t.type}))})(e),(e=>{const t=Tc(e);m(Oc(e))||!v(t)&&"INVALID"!==(e=>(e=>"gpl"===e.toLowerCase())(e)||(e=>e.length>=64&&e.length<=255)(e)?"VALID":"INVALID")(t)||console.warn("TinyMCE is running in evaluation mode. Provide a valid license key or add license_key: 'gpl' to the init config to agree to the open source license terms. Read more at https://www.tiny.cloud/license-key/")})(e),s.fold((()=>{const t=(e=>{let t=!1;const n=setTimeout((()=>{t||e.setProgressState(!0)}),500);return()=>{clearTimeout(n),t=!0,e.setProgressState(!1)}})(e);tO(e).then((()=>{nO(e),t()}))}),(t=>{e.setProgressState(!0),tO(e).then((()=>{t().then((t=>{e.setProgressState(!1),nO(e),lw(e)}),(t=>{e.notificationManager.open({type:"error",text:String(t)}),nO(e),lw(e)}))}))}))},rO=M,sO=ma.DOM,aO=ma.DOM,iO=(e,t)=>({editorContainer:e,iframeContainer:t,api:{}}),lO=e=>{const t=e.getElement();return e.inline?iO(null):(e=>{const t=aO.create("div");return aO.insertAfter(t,e),iO(t,t)})(t)},dO=async e=>{e.dispatch("ScriptsLoaded"),(e=>{const t=Dt.trim(td(e)),n=e.ui.registry.getAll().icons,o={...Ow.get("default").icons,...Ow.get(t).icons};pe(o,((t,o)=>{ke(n,o)||e.ui.registry.addIcon(o,t)}))})(e),(e=>{const t=xd(e);if(m(t)){const n=jw.get(t);e.theme=n(e,jw.urls[t])||{},w(e.theme.init)&&e.theme.init(e,jw.urls[t]||e.documentBaseUrl.replace(/\/$/,""))}else e.theme={}})(e),(e=>{const t=_d(e),n=Bw.get(t);e.model=n(e,Bw.urls[t])})(e),(e=>{const t=[];q($d(e),(n=>{((e,t,n)=>{const o=zw.get(n),r=zw.urls[n]||e.documentBaseUrl.replace(/\/$/,"");if(n=Dt.trim(n),o&&-1===Dt.inArray(t,n)){if(e.plugins[n])return;try{const s=o(e,r)||{};e.plugins[n]=s,w(s.init)&&(s.init(e,r),t.push(n))}catch(t){((e,t,n)=>{const o=va.translate(["Failed to initialize plugin: {0}",t]);mf(e,"PluginLoadError",{message:o}),Kw(o,n),Vw(e,o)})(e,n,t)}}})(e,t,(e=>e.replace(/^\-/,""))(n))}))})(e);const t=await(e=>{const t=e.getElement();return e.orgDisplay=t.style.display,m(xd(e))?(e=>{const t=e.theme.renderUI;return t?t():lO(e)})(e):w(xd(e))?(e=>{const t=e.getElement(),n=xd(e)(e,t);return n.editorContainer.nodeType&&(n.editorContainer.id=n.editorContainer.id||e.id+"_parent"),n.iframeContainer&&n.iframeContainer.nodeType&&(n.iframeContainer.id=n.iframeContainer.id||e.id+"_iframecontainer"),n.height=n.iframeHeight?n.iframeHeight:t.offsetHeight,n})(e):lO(e)})(e);((e,t)=>{const n={show:I.from(t.show).getOr(k),hide:I.from(t.hide).getOr(k),isEnabled:I.from(t.isEnabled).getOr(M),setEnabled:n=>{e.mode.isReadOnly()||I.from(t.setEnabled).each((e=>e(n)))}};e.ui={...e.ui,...n}})(e,I.from(t.api).getOr({})),e.editorContainer=t.editorContainer,(e=>{e.contentCSS=e.contentCSS.concat((e=>Gw(e,fd(e)))(e),(e=>Gw(e,pd(e)))(e))})(e),e.inline?oO(e):((e,t)=>{((e,t)=>{const n=Tt.browser.isFirefox()?Gd(e):"Rich Text Area",o=e.translate(n),r=nn(Cn(e.getElement()),"tabindex").bind(Ze),s=((e,t,n,o)=>{const r=vn("iframe");return o.each((e=>Jt(r,"tabindex",e))),en(r,n),en(r,{id:e+"_ifr",frameBorder:"0",allowTransparency:"true",title:t}),mn(r,"tox-edit-area__iframe"),r})(e.id,o,Fl(e),r).dom;s.onload=()=>{s.onload=null,e.dispatch("load")},e.contentAreaContainer=t.iframeContainer,e.iframeElement=s,e.iframeHTML=(e=>{let t=Ul(e)+"<html><head>";zl(e)!==e.documentBaseUrl&&(t+='<base href="'+e.documentBaseURI.getURI()+'" />'),t+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';const n=jl(e),o=Hl(e),r=e.translate(Gd(e));return $l(e)&&(t+='<meta http-equiv="Content-Security-Policy" content="'+$l(e)+'" />'),t+=`</head><body id="${n}" class="mce-content-body ${o}" data-id="${e.id}" aria-label="${r}"><br></body></html>`,t})(e),sO.add(t.iframeContainer,s)})(e,t),t.editorContainer&&(t.editorContainer.style.display=e.orgDisplay,e.hidden=sO.isHidden(t.editorContainer)),e.getElement().style.display="none",sO.setAttrib(e.id,"aria-hidden","true"),e.getElement().style.visibility=e.orgVisibility,(e=>{const t=e.iframeElement,n=()=>{e.contentDocument=t.contentDocument,oO(e)};if(Ec(e)||Tt.browser.isFirefox()){const t=e.getDoc();t.open(),t.write(e.iframeHTML),t.close(),n()}else{const r=(o=Cn(t),Ro(o,"load",rO,(()=>{r.unbind(),n()})));t.srcdoc=e.iframeHTML}var o})(e)})(e,{editorContainer:t.editorContainer,iframeContainer:t.iframeContainer})},cO=ma.DOM,uO=e=>"-"===e.charAt(0),mO=(e,t,n)=>I.from(t).filter((e=>Ge(e)&&!Ow.has(e))).map((t=>({url:`${e.editorManager.baseURL}/icons/${t}/icons${n}.js`,name:I.some(t)}))),fO=(e,t)=>{const n=ga.ScriptLoader,o=()=>{!e.removed&&(e=>{const t=xd(e);return!m(t)||C(jw.get(t))})(e)&&(e=>{const t=_d(e);return C(Bw.get(t))})(e)&&dO(e)};((e,t)=>{const n=xd(e);if(m(n)&&!uO(n)&&!ke(jw.urls,n)){const o=kd(e),r=o?e.documentBaseURI.toAbsolute(o):`themes/${n}/theme${t}.js`;jw.load(n,r).catch((()=>{((e,t,n)=>{qw(e,"ThemeLoadError",Ww("theme",t,n))})(e,r,n)}))}})(e,t),((e,t)=>{const n=_d(e);if("plugin"!==n&&!ke(Bw.urls,n)){const o=Sd(e),r=m(o)?e.documentBaseURI.toAbsolute(o):`models/${n}/model${t}.js`;Bw.load(n,r).catch((()=>{((e,t,n)=>{qw(e,"ModelLoadError",Ww("model",t,n))})(e,r,n)}))}})(e,t),((e,t)=>{const n=dd(t),o=cd(t);if(!va.hasCode(n)&&"en"!==n){const r=Ge(o)?o:`${t.editorManager.baseURL}/langs/${n}.js`;e.add(r).catch((()=>{((e,t,n)=>{qw(e,"LanguageLoadError",Ww("language",t,n))})(t,r,n)}))}})(n,e),((e,t,n)=>{const o=mO(t,"default",n),r=(e=>I.from(nd(e)).filter(Ge).map((e=>({url:e,name:I.none()}))))(t).orThunk((()=>mO(t,td(t),"")));q((e=>{const t=[],n=e=>{t.push(e)};for(let t=0;t<e.length;t++)e[t].each(n);return t})([o,r]),(n=>{e.add(n.url).catch((()=>{((e,t,n)=>{qw(e,"IconsLoadError",Ww("icons",t,n))})(t,n.url,n.name.getOrUndefined())}))}))})(n,e,t),((e,t)=>{const n=(t,n)=>{zw.load(t,n).catch((()=>{((e,t,n)=>{qw(e,"PluginLoadError",Ww("plugin",t,n))})(e,n,t)}))};pe(Vd(e),((t,o)=>{n(o,t),e.options.set("plugins",$d(e).concat(o))})),q($d(e),(e=>{!(e=Dt.trim(e))||zw.urls[e]||uO(e)||n(e,`plugins/${e}/plugin${t}.js`)}))})(e,t),n.loadQueue().then(o,o)},gO=xt().deviceType,pO=gO.isPhone(),hO=gO.isTablet(),bO=e=>{if(y(e))return[];{const t=p(e)?e:e.split(/[ ,]/),n=V(t,We);return Y(n,Ge)}},vO=(e,t)=>{const n=((t,n)=>{const o={},r={};return ye(t,((t,n)=>H(e,n)),ve(o),ve(r)),{t:o,f:r}})(t);return o=n.t,r=n.f,{sections:N(o),options:N(r)};var o,r},yO=(e,t)=>ke(e.sections(),t),CO=(e,t)=>({table_grid:!1,object_resizing:!1,resize:!1,toolbar_mode:xe(e,"toolbar_mode").getOr("scrolling"),toolbar_sticky:!1,...t?{menubar:!1}:{}}),wO=(e,t)=>{var n;const o=null!==(n=t.external_plugins)&&void 0!==n?n:{};return e&&e.external_plugins?Dt.extend({},e.external_plugins,o):o},EO=(e,t,n,o,r)=>{var s;const a=e?{mobile:CO(null!==(s=r.mobile)&&void 0!==s?s:{},t)}:{},i=vO(["mobile"],mS(a,r)),l=Dt.extend(n,o,i.options(),((e,t)=>e&&yO(t,"mobile"))(e,i)?((e,t,n={})=>{const o=e.sections(),r=xe(o,t).getOr({});return Dt.extend({},n,r)})(i,"mobile"):{},{external_plugins:wO(o,i.options())});return((e,t,n,o)=>{const r=bO(n.forced_plugins),s=bO(o.plugins),a=((e,t)=>yO(e,t)?e.sections()[t]:{})(t,"mobile"),i=((e,t,n,o)=>e&&yO(t,"mobile")?o:n)(e,t,s,a.plugins?bO(a.plugins):s),l=((e,t)=>[...bO(e),...bO(t)])(r,i);return Dt.extend(o,{forced_plugins:r,plugins:l})})(e,i,o,l)},xO=e=>{(e=>{const t=t=>()=>{q("left,center,right,justify".split(","),(n=>{t!==n&&e.formatter.remove("align"+n)})),"none"!==t&&((t,n)=>{e.formatter.toggle(t,void 0),e.nodeChanged()})("align"+t)};e.editorCommands.addCommands({JustifyLeft:t("left"),JustifyCenter:t("center"),JustifyRight:t("right"),JustifyFull:t("justify"),JustifyNone:t("none")})})(e),(e=>{const t=t=>()=>{const n=e.selection,o=n.isCollapsed()?[e.dom.getParent(n.getNode(),e.dom.isBlock)]:n.getSelectedBlocks();return $(o,(n=>C(e.formatter.matchNode(n,t))))};e.editorCommands.addCommands({JustifyLeft:t("alignleft"),JustifyCenter:t("aligncenter"),JustifyRight:t("alignright"),JustifyFull:t("alignjustify")},"state")})(e)},kO=(e,t)=>{const n=e.selection,o=e.dom;return/^ | $/.test(t)?((e,t,n,o)=>{const r=Cn(e.getRoot());return n=lh(r,Qi.fromRangeStart(t),o)?n.replace(/^ /,"&nbsp;"):n.replace(/^&nbsp;/," "),dh(r,Qi.fromRangeEnd(t),o)?n.replace(/(&nbsp;| )(<br( \/)>)?$/,"&nbsp;"):n.replace(/&nbsp;(<br( \/)?>)?$/," ")})(o,n.getRng(),t,e.schema):t},_O=(e,t)=>{if(e.selection.isEditable()){const{content:n,details:o}=(e=>{if("string"!=typeof e){const t=Dt.extend({paste:e.paste,data:{paste:e.paste}},e);return{content:e.content,details:t}}return{content:e,details:{}}})(t);TC(e,{...o,content:kO(e,n),format:"html",set:!1,selection:!0}).each((t=>{const n=((e,t,n)=>aw(e).editor.insertContent(t,n))(e,t.content,o);OC(e,n,t),e.addVisual()}))}},SO={"font-size":"size","font-family":"face"},NO=Zt("font"),RO=e=>(t,n)=>I.from(n).map(Cn).filter(Kt).bind((n=>((e,t,n)=>Hb(Cn(n),(t=>(t=>fo(t,e).orThunk((()=>NO(t)?xe(SO,e).bind((e=>nn(t,e))):I.none())))(t)),(e=>_n(Cn(t),e))))(e,t,n.dom).or(((e,t)=>I.from(ma.DOM.getStyle(t,e,!0)))(e,n.dom)))).getOr(""),AO=RO("font-size"),TO=_((e=>e.replace(/[\'\"\\]/g,"").replace(/,\s+/g,",")),RO("font-family")),OO=e=>Hu(e.getBody()).bind((e=>{const t=e.container();return I.from(dr(t)?t.parentNode:t)})),BO=(e,t)=>((e,t)=>(e=>I.from(e.selection.getRng()).bind((t=>{const n=e.getBody();return t.startContainer===n&&0===t.startOffset?I.none():I.from(e.selection.getStart(!0))})))(e).orThunk(T(OO,e)).map(Cn).filter(Kt).bind(t))(e,S(I.some,t)),PO=(e,t)=>{if(/^[0-9.]+$/.test(t)){const n=parseInt(t,10);if(n>=1&&n<=7){const o=(e=>Dt.explode(e.options.get("font_size_style_values")))(e),r=(e=>Dt.explode(e.options.get("font_size_classes")))(e);return r.length>0?r[n-1]||t:o[n-1]||t}return t}return t},DO=e=>{const t=e.split(/\s*,\s*/);return V(t,(e=>-1===e.indexOf(" ")||$e(e,'"')||$e(e,"'")?e:`'${e}'`)).join(",")},LO=(e,t)=>{const n=e.dom,o=e.selection.getRng(),r=t?e.selection.getStart():e.selection.getEnd(),s=t?o.startContainer:o.endContainer,a=ON(n,s);if(!a||!a.isContentEditable)return;const i=t?ho:bo,l=ql(e);((e,t,n,o)=>{const r=e.dom,s=e=>r.isBlock(e)&&e.parentElement===n,a=s(t)?t:r.getParent(o,s,n);return I.from(a).map(Cn)})(e,r,a,s).each((t=>{const n=LN(e,s,t.dom,a,!1,l);i(t,Cn(n)),e.selection.setCursorLocation(n,0),e.dispatch("NewBlock",{newBlock:n}),kN(e,"insertParagraph")}))},MO=e=>{xO(e),(e=>{e.editorCommands.addCommands({"Cut,Copy,Paste":t=>{const n=e.getDoc();let o;try{n.execCommand(t)}catch(e){o=!0}if("paste"!==t||n.queryCommandEnabled(t)||(o=!0),o||!n.queryCommandSupported(t)){let t=e.translate("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.");(Tt.os.isMacOS()||Tt.os.isiOS())&&(t=t.replace(/Ctrl\+/g,"\u2318+")),e.notificationManager.open({text:t,type:"error"})}}})})(e),(e=>{e.editorCommands.addCommands({mceAddUndoLevel:()=>{e.undoManager.add()},mceEndUndoLevel:()=>{e.undoManager.add()},Undo:()=>{e.undoManager.undo()},Redo:()=>{e.undoManager.redo()}})})(e),(e=>{e.editorCommands.addCommands({mceSelectNodeDepth:(t,n,o)=>{let r=0;e.dom.getParent(e.selection.getNode(),(t=>!er(t)||r++!==o||(e.selection.select(t),!1)),e.getBody())},mceSelectNode:(t,n,o)=>{e.selection.select(o)},selectAll:()=>{const t=e.dom.getParent(e.selection.getStart(),br);if(t){const n=e.dom.createRng();n.selectNodeContents(t),e.selection.setRng(n)}}})})(e),(e=>{e.editorCommands.addCommands({mceCleanup:()=>{const t=e.selection.getBookmark();e.setContent(e.getContent()),e.selection.moveToBookmark(t)},insertImage:(t,n,o)=>{_O(e,e.dom.createHTML("img",{src:o}))},insertHorizontalRule:()=>{e.execCommand("mceInsertContent",!1,"<hr>")},insertText:(t,n,o)=>{_O(e,e.dom.encode(o))},insertHTML:(t,n,o)=>{_O(e,o)},mceInsertContent:(t,n,o)=>{_O(e,o)},mceSetContent:(t,n,o)=>{e.setContent(o)},mceReplaceContent:(t,n,o)=>{e.execCommand("mceInsertContent",!1,o.replace(/\{\$selection\}/g,e.selection.getContent({format:"text"})))},mceNewDocument:()=>{e.setContent(ac(e))}})})(e),(e=>{const t=(t,n,o)=>{const r=m(o)?{href:o}:o,s=e.dom.getParent(e.selection.getNode(),"a");f(r)&&m(r.href)&&(r.href=r.href.replace(/ /g,"%20"),s&&r.href||e.formatter.remove("link"),r.href&&e.formatter.apply("link",r,s))};e.editorCommands.addCommands({unlink:()=>{if(e.selection.isEditable()){if(e.selection.isCollapsed()){const t=e.dom.getParent(e.selection.getStart(),"a");return void(t&&e.dom.remove(t,!0))}e.formatter.remove("link")}},mceInsertLink:t,createLink:t})})(e),(e=>{e.editorCommands.addCommands({Indent:()=>{(e=>{Hk(e,"indent")})(e)},Outdent:()=>{$k(e)}}),e.editorCommands.addCommands({Outdent:()=>Uk(e)},"state")})(e),(e=>{e.editorCommands.addCommands({InsertNewBlockBefore:()=>{(e=>{LO(e,!0)})(e)},InsertNewBlockAfter:()=>{(e=>{LO(e,!1)})(e)}})})(e),(e=>{e.editorCommands.addCommands({insertParagraph:()=>{gR(WN,e)},mceInsertNewLine:(t,n,o)=>{pR(e,o)},InsertLineBreak:(t,n,o)=>{gR(eR,e)}})})(e),(e=>{(e=>{const t=(t,n)=>{e.formatter.toggle(t,n),e.nodeChanged()};e.editorCommands.addCommands({"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":e=>{t(e)},"ForeColor,HiliteColor":(e,n,o)=>{t(e,{value:o})},BackColor:(e,n,o)=>{t("hilitecolor",{value:o})},FontName:(t,n,o)=>{((e,t)=>{const n=PO(e,t);e.formatter.toggle("fontname",{value:DO(n)}),e.nodeChanged()})(e,o)},FontSize:(t,n,o)=>{((e,t)=>{e.formatter.toggle("fontsize",{value:PO(e,t)}),e.nodeChanged()})(e,o)},LineHeight:(t,n,o)=>{((e,t)=>{e.formatter.toggle("lineheight",{value:String(t)}),e.nodeChanged()})(e,o)},Lang:(e,n,o)=>{var r;t(e,{value:o.code,customValue:null!==(r=o.customCode)&&void 0!==r?r:null})},RemoveFormat:t=>{e.formatter.remove(t)},mceBlockQuote:()=>{t("blockquote")},FormatBlock:(e,n,o)=>{t(m(o)?o:"p")},mceToggleFormat:(e,n,o)=>{t(o)}})})(e),(e=>{const t=t=>e.formatter.match(t);e.editorCommands.addCommands({"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":e=>t(e),mceBlockQuote:()=>t("blockquote")},"state"),e.editorCommands.addQueryValueHandler("FontName",(()=>(e=>BO(e,(t=>TO(e.getBody(),t.dom))).getOr(""))(e))),e.editorCommands.addQueryValueHandler("FontSize",(()=>(e=>BO(e,(t=>AO(e.getBody(),t.dom))).getOr(""))(e))),e.editorCommands.addQueryValueHandler("LineHeight",(()=>(e=>BO(e,(t=>{const n=Cn(e.getBody()),o=Hb(t,(e=>fo(e,"line-height")),T(_n,n));return o.getOrThunk((()=>{const e=parseFloat(uo(t,"line-height")),n=parseFloat(uo(t,"font-size"));return String(e/n)}))})).getOr(""))(e)))})(e)})(e),(e=>{e.editorCommands.addCommands({mceRemoveNode:(t,n,o)=>{const r=null!=o?o:e.selection.getNode();if(r!==e.getBody()){const t=e.selection.getBookmark();e.dom.remove(r,!0),e.selection.moveToBookmark(t)}},mcePrint:()=>{e.getWin().print()},mceFocus:(t,n,o)=>{((e,t)=>{e.removed||(t?Hg(e):(e=>{const t=e.selection,n=e.getBody();let o=t.getRng();e.quirks.refreshContentEditable();const r=e=>{Rg(e).each((t=>{e.selection.setRng(t),o=t}))};!zg(e)&&e.hasEditableRoot()&&r(e);const s=((e,t)=>e.dom.getParent(t,(t=>"true"===e.dom.getContentEditable(t))))(e,t.getNode());if(s&&e.dom.isChildOf(s,n))return Ug(s),e.hasEditableRoot()||r(e),Fg(e,o),void Hg(e);e.inline||(Tt.browser.isOpera()||Ug(n),e.getWin().focus()),(Tt.browser.isFirefox()||e.inline)&&(Ug(n),Fg(e,o)),Hg(e)})(e))})(e,!0===o)},mceToggleVisualAid:()=>{e.hasVisual=!e.hasVisual,e.addVisual()}})})(e)},IO=["toggleview"],FO=e=>H(IO,e.toLowerCase());class UO{constructor(e){this.commands={state:{},exec:{},value:{}},this.editor=e}execCommand(e,t=!1,n,o){const r=this.editor,s=e.toLowerCase(),a=null==o?void 0:o.skip_focus;if(r.removed)return!1;if("mcefocus"!==s&&(/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(s)||a?(e=>{Rg(e).each((t=>e.selection.setRng(t)))})(r):r.focus()),r.dispatch("BeforeExecCommand",{command:e,ui:t,value:n}).isDefaultPrevented())return!1;const i=this.commands.exec[s];return!!w(i)&&(i(s,t,n),r.dispatch("ExecCommand",{command:e,ui:t,value:n}),!0)}queryCommandState(e){if(!FO(e)&&this.editor.quirks.isHidden()||this.editor.removed)return!1;const t=e.toLowerCase(),n=this.commands.state[t];return!!w(n)&&n(t)}queryCommandValue(e){if(!FO(e)&&this.editor.quirks.isHidden()||this.editor.removed)return"";const t=e.toLowerCase(),n=this.commands.value[t];return w(n)?n(t):""}addCommands(e,t="exec"){const n=this.commands;pe(e,((e,o)=>{q(o.toLowerCase().split(","),(o=>{n[t][o]=e}))}))}addCommand(e,t,n){const o=e.toLowerCase();this.commands.exec[o]=(e,o,r)=>t.call(null!=n?n:this.editor,o,r)}queryCommandSupported(e){const t=e.toLowerCase();return!!this.commands.exec[t]}addQueryStateHandler(e,t,n){this.commands.state[e.toLowerCase()]=()=>t.call(null!=n?n:this.editor)}addQueryValueHandler(e,t,n){this.commands.value[e.toLowerCase()]=()=>t.call(null!=n?n:this.editor)}}const zO="data-mce-contenteditable",jO=(e,t,n)=>{try{e.getDoc().execCommand(t,!1,String(n))}catch(e){}},HO=(e,t)=>{e.dom.contentEditable=t?"true":"false"},$O=e=>e.readonly,VO=e=>{e.parser.addAttributeFilter("contenteditable",(t=>{$O(e)&&q(t,(e=>{e.attr(zO,e.attr("contenteditable")),e.attr("contenteditable","false")}))})),e.serializer.addAttributeFilter(zO,(t=>{$O(e)&&q(t,(e=>{e.attr("contenteditable",e.attr(zO))}))})),e.serializer.addTempAttr(zO)},qO=["copy"],WO=Dt.makeMap("focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover draggesture dragdrop drop drag submit compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel"," ");class KO{static isNative(e){return!!WO[e.toLowerCase()]}constructor(e){this.bindings={},this.settings=e||{},this.scope=this.settings.scope||this,this.toggleEvent=this.settings.toggleEvent||L}fire(e,t){return this.dispatch(e,t)}dispatch(e,t){const n=e.toLowerCase(),o=Xs(n,null!=t?t:{},this.scope);this.settings.beforeFire&&this.settings.beforeFire(o);const r=this.bindings[n];if(r)for(let e=0,t=r.length;e<t;e++){const t=r[e];if(!t.removed){if(t.once&&this.off(n,t.func),o.isImmediatePropagationStopped())return o;if(!1===t.func.call(this.scope,o))return o.preventDefault(),o}}return o}on(e,t,n,o){if(!1===t&&(t=L),t){const r={func:t,removed:!1};o&&Dt.extend(r,o);const s=e.toLowerCase().split(" ");let a=s.length;for(;a--;){const e=s[a];let t=this.bindings[e];t||(t=[],this.toggleEvent(e,!0)),t=n?[r,...t]:[...t,r],this.bindings[e]=t}}return this}off(e,t){if(e){const n=e.toLowerCase().split(" ");let o=n.length;for(;o--;){const r=n[o];let s=this.bindings[r];if(!r)return pe(this.bindings,((e,t)=>{this.toggleEvent(t,!1),delete this.bindings[t]})),this;if(s){if(t){const e=K(s,(e=>e.func===t));s=e.fail,this.bindings[r]=s,q(e.pass,(e=>{e.removed=!0}))}else s.length=0;s.length||(this.toggleEvent(e,!1),delete this.bindings[r])}}}else pe(this.bindings,((e,t)=>{this.toggleEvent(t,!1)})),this.bindings={};return this}once(e,t,n){return this.on(e,t,n,{once:!0})}has(e){e=e.toLowerCase();const t=this.bindings[e];return!(!t||0===t.length)}}const YO=e=>(e._eventDispatcher||(e._eventDispatcher=new KO({scope:e,toggleEvent:(t,n)=>{KO.isNative(t)&&e.toggleNativeEvent&&e.toggleNativeEvent(t,n)}})),e._eventDispatcher),GO={fire(e,t,n){return this.dispatch(e,t,n)},dispatch(e,t,n){const o=this;if(o.removed&&"remove"!==e&&"detach"!==e)return Xs(e.toLowerCase(),null!=t?t:{},o);const r=YO(o).dispatch(e,t);if(!1!==n&&o.parent){let t=o.parent();for(;t&&!r.isPropagationStopped();)t.dispatch(e,r,!1),t=t.parent?t.parent():void 0}return r},on(e,t,n){return YO(this).on(e,t,n)},off(e,t){return YO(this).off(e,t)},once(e,t){return YO(this).once(e,t)},hasEventListeners(e){return YO(this).has(e)}},XO=ma.DOM;let ZO;const QO=(e,t)=>{if("selectionchange"===t)return e.getDoc();if(!e.inline&&/^(?:mouse|touch|click|contextmenu|drop|dragover|dragend)/.test(t))return e.getDoc().documentElement;const n=wd(e);return n?(e.eventRoot||(e.eventRoot=XO.select(n)[0]),e.eventRoot):e.getBody()},JO=(e,t,n)=>{(e=>!e.hidden&&!$O(e))(e)?e.dispatch(t,n):$O(e)&&((e,t)=>{if((e=>"click"===e.type)(t)&&!yf.metaKeyPressed(t)){const n=Cn(t.target);((e,t)=>oo(t,"a",(t=>_n(t,Cn(e.getBody())))).bind((e=>nn(e,"href"))))(e,n).each((n=>{if(t.preventDefault(),/^#/.test(n)){const t=e.dom.select(`${n},[name="${je(n,"#")}"]`);t.length&&e.selection.scrollIntoView(t[0],!0)}else window.open(n,"_blank","rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes")}))}else(e=>H(qO,e.type))(t)&&e.dispatch(t.type,t)})(e,n)},eB=(e,t)=>{if(e.delegates||(e.delegates={}),e.delegates[t]||e.removed)return;const n=QO(e,t);if(wd(e)){if(ZO||(ZO={},e.editorManager.on("removeEditor",(()=>{e.editorManager.activeEditor||ZO&&(pe(ZO,((t,n)=>{e.dom.unbind(QO(e,n))})),ZO=null)}))),ZO[t])return;const o=n=>{const o=n.target,r=e.editorManager.get();let s=r.length;for(;s--;){const e=r[s].getBody();(e===o||XO.isChildOf(o,e))&&JO(r[s],t,n)}};ZO[t]=o,XO.bind(n,t,o)}else{const o=n=>{JO(e,t,n)};XO.bind(n,t,o),e.delegates[t]=o}},tB={...GO,bindPendingEventDelegates(){const e=this;Dt.each(e._pendingNativeEvents,(t=>{eB(e,t)}))},toggleNativeEvent(e,t){const n=this;"focus"!==e&&"blur"!==e&&(n.removed||(t?n.initialized?eB(n,e):n._pendingNativeEvents?n._pendingNativeEvents.push(e):n._pendingNativeEvents=[e]:n.initialized&&n.delegates&&(n.dom.unbind(QO(n,e),e,n.delegates[e]),delete n.delegates[e])))},unbindAllNativeEvents(){const e=this,t=e.getBody(),n=e.dom;e.delegates&&(pe(e.delegates,((t,n)=>{e.dom.unbind(QO(e,n),n,t)})),delete e.delegates),!e.inline&&t&&n&&(t.onload=null,n.unbind(e.getWin()),n.unbind(e.getDoc())),n&&(n.unbind(t),n.unbind(e.getContainer()))}},nB=e=>m(e)?{value:e.split(/[ ,]/),valid:!0}:x(e,m)?{value:e,valid:!0}:{valid:!1,message:"The value must be a string[] or a comma/space separated string."},oB=(e,t)=>e+(Xe(t.message)?"":`. ${t.message}`),rB=e=>e.valid,sB=(e,t,n="")=>{const o=t(e);return b(o)?o?{value:e,valid:!0}:{valid:!1,message:n}:o},aB=["design","readonly"],iB=(e,t,n,o)=>{const r=n[t.get()],s=n[o];try{s.activate()}catch(e){return void console.error(`problem while activating editor mode ${o}:`,e)}r.deactivate(),r.editorReadOnly!==s.editorReadOnly&&((e,t)=>{const n=Cn(e.getBody());((e,t,n)=>{pn(e,t)&&!n?gn(e,t):n&&mn(e,t)})(n,"mce-content-readonly",t),t?(e.selection.controlSelection.hideResizeRect(),e._selectionOverrides.hideFakeCaret(),(e=>{I.from(e.selection.getNode()).each((e=>{e.removeAttribute("data-mce-selected")}))})(e),e.readonly=!0,HO(n,!1),q(zo(n,'*[contenteditable="true"]'),(e=>{Jt(e,zO,"true"),HO(e,!1)}))):(e.readonly=!1,e.hasEditableRoot()&&HO(n,!0),q(zo(n,`*[${zO}="true"]`),(e=>{rn(e,zO),HO(e,!0)})),jO(e,"StyleWithCSS",!1),jO(e,"enableInlineTableEditing",!1),jO(e,"enableObjectResizing",!1),jg(e)&&e.focus(),(e=>{e.selection.setRng(e.selection.getRng())})(e),e.nodeChanged())})(e,s.editorReadOnly),t.set(o),((e,t)=>{e.dispatch("SwitchMode",{mode:t})})(e,o)},lB=Dt.each,dB=Dt.explode,cB={f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},uB=Dt.makeMap("alt,ctrl,shift,meta,access"),mB=e=>{const t={},n=Tt.os.isMacOS()||Tt.os.isiOS();lB(dB(e.toLowerCase(),"+"),(e=>{(e=>e in uB)(e)?t[e]=!0:/^[0-9]{2,}$/.test(e)?t.keyCode=parseInt(e,10):(t.charCode=e.charCodeAt(0),t.keyCode=cB[e]||e.toUpperCase().charCodeAt(0))}));const o=[t.keyCode];let r;for(r in uB)t[r]?o.push(r):t[r]=!1;return t.id=o.join(","),t.access&&(t.alt=!0,n?t.ctrl=!0:t.shift=!0),t.meta&&(n?t.meta=!0:(t.ctrl=!0,t.meta=!1)),t};class fB{constructor(e){this.shortcuts={},this.pendingPatterns=[],this.editor=e;const t=this;e.on("keyup keypress keydown",(e=>{!t.hasModifier(e)&&!t.isFunctionKey(e)||e.isDefaultPrevented()||(lB(t.shortcuts,(n=>{t.matchShortcut(e,n)&&(t.pendingPatterns=n.subpatterns.slice(0),"keydown"===e.type&&t.executeShortcutAction(n))})),t.matchShortcut(e,t.pendingPatterns[0])&&(1===t.pendingPatterns.length&&"keydown"===e.type&&t.executeShortcutAction(t.pendingPatterns[0]),t.pendingPatterns.shift()))}))}add(e,t,n,o){const r=this,s=r.normalizeCommandFunc(n);return lB(dB(Dt.trim(e)),(e=>{const n=r.createShortcut(e,t,s,o);r.shortcuts[n.id]=n})),!0}remove(e){const t=this.createShortcut(e);return!!this.shortcuts[t.id]&&(delete this.shortcuts[t.id],!0)}normalizeCommandFunc(e){const t=this,n=e;return"string"==typeof n?()=>{t.editor.execCommand(n,!1,null)}:Dt.isArray(n)?()=>{t.editor.execCommand(n[0],n[1],n[2])}:n}createShortcut(e,t,n,o){const r=Dt.map(dB(e,">"),mB);return r[r.length-1]=Dt.extend(r[r.length-1],{func:n,scope:o||this.editor}),Dt.extend(r[0],{desc:this.editor.translate(t),subpatterns:r.slice(1)})}hasModifier(e){return e.altKey||e.ctrlKey||e.metaKey}isFunctionKey(e){return"keydown"===e.type&&e.keyCode>=112&&e.keyCode<=123}matchShortcut(e,t){return!!t&&t.ctrl===e.ctrlKey&&t.meta===e.metaKey&&t.alt===e.altKey&&t.shift===e.shiftKey&&!!(e.keyCode===t.keyCode||e.charCode&&e.charCode===t.charCode)&&(e.preventDefault(),!0)}executeShortcutAction(e){return e.func?e.func.call(e.scope):null}}const gB=()=>{const e=(()=>{const e={},t={},n={},o={},r={},s={},a={},i={},l=(e,t)=>(n,o)=>{e[n.toLowerCase()]={...o,type:t}};return{addButton:l(e,"button"),addGroupToolbarButton:l(e,"grouptoolbarbutton"),addToggleButton:l(e,"togglebutton"),addMenuButton:l(e,"menubutton"),addSplitButton:l(e,"splitbutton"),addMenuItem:l(t,"menuitem"),addNestedMenuItem:l(t,"nestedmenuitem"),addToggleMenuItem:l(t,"togglemenuitem"),addAutocompleter:l(n,"autocompleter"),addContextMenu:l(r,"contextmenu"),addContextToolbar:l(s,"contexttoolbar"),addContextForm:l(s,"contextform"),addSidebar:l(a,"sidebar"),addView:l(i,"views"),addIcon:(e,t)=>o[e.toLowerCase()]=t,getAll:()=>({buttons:e,menuItems:t,icons:o,popups:n,contextMenus:r,contextToolbars:s,sidebars:a,views:i})}})();return{addAutocompleter:e.addAutocompleter,addButton:e.addButton,addContextForm:e.addContextForm,addContextMenu:e.addContextMenu,addContextToolbar:e.addContextToolbar,addIcon:e.addIcon,addMenuButton:e.addMenuButton,addMenuItem:e.addMenuItem,addNestedMenuItem:e.addNestedMenuItem,addSidebar:e.addSidebar,addSplitButton:e.addSplitButton,addToggleButton:e.addToggleButton,addGroupToolbarButton:e.addGroupToolbarButton,addToggleMenuItem:e.addToggleMenuItem,addView:e.addView,getAll:e.getAll}},pB=ma.DOM,hB=Dt.extend,bB=Dt.each;class vB{constructor(e,t,n){this.plugins={},this.contentCSS=[],this.contentStyles=[],this.loadedCSS={},this.isNotDirty=!1,this.composing=!1,this.destroyed=!1,this.hasHiddenInput=!1,this.iframeElement=null,this.initialized=!1,this.readonly=!1,this.removed=!1,this.startContent="",this._pendingNativeEvents=[],this._skinLoaded=!1,this._editableRoot=!0,this.editorManager=n,this.documentBaseUrl=n.documentBaseURL,hB(this,tB);const o=this;this.id=e,this.hidden=!1;const r=((e,t)=>{const n=fS(t);return EO(pO||hO,pO,n,e,n)})(n.defaultOptions,t);this.options=((e,t,n=t)=>{const o={},r={},s=(e,t,n)=>{const o=sB(t,n);return rB(o)?(r[e]=o.value,!0):(console.warn(oB(`Invalid value passed for the ${e} option`,o)),!1)},a=e=>ke(o,e);return{register:(e,n)=>{const a=(e=>m(e.processor))(n)?(e=>{const t=(()=>{switch(e){case"array":return p;case"boolean":return b;case"function":return w;case"number":return E;case"object":return f;case"string":return m;case"string[]":return nB;case"object[]":return e=>x(e,f);case"regexp":return e=>u(e,RegExp);default:return M}})();return n=>sB(n,t,`The value must be a ${e}.`)})(n.processor):n.processor,i=((e,t,n)=>{if(!v(t)){const o=sB(t,n);if(rB(o))return o.value;console.error(oB(`Invalid default value passed for the "${e}" option`,o))}})(e,n.default,a);o[e]={...n,default:i,processor:a},xe(r,e).orThunk((()=>xe(t,e))).each((t=>s(e,t,a)))},isRegistered:a,get:e=>xe(r,e).orThunk((()=>xe(o,e).map((e=>e.default)))).getOrUndefined(),set:(e,t)=>{if(a(e)){const n=o[e];return n.immutable?(console.error(`"${e}" is an immutable option and cannot be updated`),!1):s(e,t,n.processor)}return console.warn(`"${e}" is not a registered option. Ensure the option has been registered before setting a value.`),!1},unset:e=>{const t=a(e);return t&&delete r[e],t},isSet:e=>ke(r,e),debug:()=>{try{console.log(JSON.parse(JSON.stringify(n,((e,t)=>b(t)||E(t)||m(t)||h(t)||p(t)||g(t)?t:Object.prototype.toString.call(t)))))}catch(e){console.error(e)}}}})(0,r,t),(e=>{const t=e.options.register;t("id",{processor:"string",default:e.id}),t("selector",{processor:"string"}),t("target",{processor:"object"}),t("suffix",{processor:"string"}),t("cache_suffix",{processor:"string"}),t("base_url",{processor:"string"}),t("referrer_policy",{processor:"string",default:""}),t("language_load",{processor:"boolean",default:!0}),t("inline",{processor:"boolean",default:!1}),t("iframe_attrs",{processor:"object",default:{}}),t("doctype",{processor:"string",default:"<!DOCTYPE html>"}),t("document_base_url",{processor:"string",default:e.documentBaseUrl}),t("body_id",{processor:Il(e,"tinymce"),default:"tinymce"}),t("body_class",{processor:Il(e),default:""}),t("content_security_policy",{processor:"string",default:""}),t("br_in_pre",{processor:"boolean",default:!0}),t("forced_root_block",{processor:e=>{const t=m(e)&&Ge(e);return t?{value:e,valid:t}:{valid:!1,message:"Must be a non-empty string."}},default:"p"}),t("forced_root_block_attrs",{processor:"object",default:{}}),t("newline_behavior",{processor:e=>{const t=H(["block","linebreak","invert","default"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: block, linebreak, invert or default."}},default:"default"}),t("br_newline_selector",{processor:"string",default:".mce-toc h2,figcaption,caption"}),t("no_newline_selector",{processor:"string",default:""}),t("keep_styles",{processor:"boolean",default:!0}),t("end_container_on_empty_block",{processor:e=>b(e)||m(e)?{valid:!0,value:e}:{valid:!1,message:"Must be boolean or a string"},default:"blockquote"}),t("font_size_style_values",{processor:"string",default:"xx-small,x-small,small,medium,large,x-large,xx-large"}),t("font_size_legacy_values",{processor:"string",default:"xx-small,small,medium,large,x-large,xx-large,300%"}),t("font_size_classes",{processor:"string",default:""}),t("automatic_uploads",{processor:"boolean",default:!0}),t("images_reuse_filename",{processor:"boolean",default:!1}),t("images_replace_blob_uris",{processor:"boolean",default:!0}),t("icons",{processor:"string",default:""}),t("icons_url",{processor:"string",default:""}),t("images_upload_url",{processor:"string",default:""}),t("images_upload_base_path",{processor:"string",default:""}),t("images_upload_credentials",{processor:"boolean",default:!1}),t("images_upload_handler",{processor:"function"}),t("language",{processor:"string",default:"en"}),t("language_url",{processor:"string",default:""}),t("entity_encoding",{processor:"string",default:"named"}),t("indent",{processor:"boolean",default:!0}),t("indent_before",{processor:"string",default:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist"}),t("indent_after",{processor:"string",default:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,details,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist"}),t("indent_use_margin",{processor:"boolean",default:!1}),t("indentation",{processor:"string",default:"40px"}),t("content_css",{processor:e=>{const t=!1===e||m(e)||x(e,m);return t?m(e)?{value:V(e.split(","),We),valid:t}:p(e)?{value:e,valid:t}:!1===e?{value:[],valid:t}:{value:e,valid:t}:{valid:!1,message:"Must be false, a string or an array of strings."}},default:Pd(e)?[]:["default"]}),t("content_style",{processor:"string"}),t("content_css_cors",{processor:"boolean",default:!1}),t("font_css",{processor:e=>{const t=m(e)||x(e,m);return t?{value:p(e)?e:V(e.split(","),We),valid:t}:{valid:!1,message:"Must be a string or an array of strings."}},default:[]}),t("inline_boundaries",{processor:"boolean",default:!0}),t("inline_boundaries_selector",{processor:"string",default:"a[href],code,span.mce-annotation"}),t("object_resizing",{processor:e=>{const t=b(e)||m(e);return t?!1===e||Ol.isiPhone()||Ol.isiPad()?{value:"",valid:t}:{value:!0===e?"table,img,figure.image,div,video,iframe":e,valid:t}:{valid:!1,message:"Must be boolean or a string"}},default:!Bl}),t("resize_img_proportional",{processor:"boolean",default:!0}),t("event_root",{processor:"string"}),t("service_message",{processor:"string"}),t("theme",{processor:e=>!1===e||m(e)||w(e),default:"silver"}),t("theme_url",{processor:"string"}),t("formats",{processor:"object"}),t("format_empty_lines",{processor:"boolean",default:!1}),t("format_noneditable_selector",{processor:"string",default:""}),t("preview_styles",{processor:e=>{const t=!1===e||m(e);return t?{value:!1===e?"":e,valid:t}:{valid:!1,message:"Must be false or a string"}},default:"font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow"}),t("custom_ui_selector",{processor:"string",default:""}),t("hidden_input",{processor:"boolean",default:!0}),t("submit_patch",{processor:"boolean",default:!0}),t("encoding",{processor:"string"}),t("add_form_submit_trigger",{processor:"boolean",default:!0}),t("add_unload_trigger",{processor:"boolean",default:!0}),t("custom_undo_redo_levels",{processor:"number",default:0}),t("disable_nodechange",{processor:"boolean",default:!1}),t("readonly",{processor:"boolean",default:!1}),t("editable_root",{processor:"boolean",default:!0}),t("plugins",{processor:"string[]",default:[]}),t("external_plugins",{processor:"object"}),t("forced_plugins",{processor:"string[]"}),t("model",{processor:"string",default:e.hasPlugin("rtc")?"plugin":"dom"}),t("model_url",{processor:"string"}),t("block_unsupported_drop",{processor:"boolean",default:!0}),t("visual",{processor:"boolean",default:!0}),t("visual_table_class",{processor:"string",default:"mce-item-table"}),t("visual_anchor_class",{processor:"string",default:"mce-item-anchor"}),t("iframe_aria_text",{processor:"string",default:"Rich Text Area. Press ALT-0 for help."}),t("setup",{processor:"function"}),t("init_instance_callback",{processor:"function"}),t("url_converter",{processor:"function",default:e.convertURL}),t("url_converter_scope",{processor:"object",default:e}),t("urlconverter_callback",{processor:"function"}),t("allow_conditional_comments",{processor:"boolean",default:!1}),t("allow_html_data_urls",{processor:"boolean",default:!1}),t("allow_svg_data_urls",{processor:"boolean"}),t("allow_html_in_named_anchor",{processor:"boolean",default:!1}),t("allow_script_urls",{processor:"boolean",default:!1}),t("allow_unsafe_link_target",{processor:"boolean",default:!1}),t("convert_fonts_to_spans",{processor:"boolean",default:!0,deprecated:!0}),t("fix_list_elements",{processor:"boolean",default:!1}),t("preserve_cdata",{processor:"boolean",default:!1}),t("remove_trailing_brs",{processor:"boolean",default:!0}),t("pad_empty_with_br",{processor:"boolean",default:!1}),t("inline_styles",{processor:"boolean",default:!0,deprecated:!0}),t("element_format",{processor:"string",default:"html"}),t("entities",{processor:"string"}),t("schema",{processor:"string",default:"html5"}),t("convert_urls",{processor:"boolean",default:!0}),t("relative_urls",{processor:"boolean",default:!0}),t("remove_script_host",{processor:"boolean",default:!0}),t("custom_elements",{processor:Ml}),t("extended_valid_elements",{processor:"string"}),t("invalid_elements",{processor:"string"}),t("invalid_styles",{processor:Ml}),t("valid_children",{processor:"string"}),t("valid_classes",{processor:Ml}),t("valid_elements",{processor:"string"}),t("valid_styles",{processor:Ml}),t("verify_html",{processor:"boolean",default:!0}),t("auto_focus",{processor:e=>m(e)||!0===e}),t("browser_spellcheck",{processor:"boolean",default:!1}),t("protect",{processor:"array"}),t("images_file_types",{processor:"string",default:"jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp"}),t("deprecation_warnings",{processor:"boolean",default:!0}),t("a11y_advanced_options",{processor:"boolean",default:!1}),t("api_key",{processor:"string"}),t("license_key",{processor:"string"}),t("paste_block_drop",{processor:"boolean",default:!1}),t("paste_data_images",{processor:"boolean",default:!0}),t("paste_preprocess",{processor:"function"}),t("paste_postprocess",{processor:"function"}),t("paste_webkit_styles",{processor:"string",default:"none"}),t("paste_remove_styles_if_webkit",{processor:"boolean",default:!0}),t("paste_merge_formats",{processor:"boolean",default:!0}),t("smart_paste",{processor:"boolean",default:!0}),t("paste_as_text",{processor:"boolean",default:!1}),t("paste_tab_spaces",{processor:"number",default:4}),t("text_patterns",{processor:e=>x(e,f)||!1===e?{value:Tl(!1===e?[]:e),valid:!0}:{valid:!1,message:"Must be an array of objects or false."},default:[{start:"*",end:"*",format:"italic"},{start:"**",end:"**",format:"bold"},{start:"#",format:"h1",trigger:"space"},{start:"##",format:"h2",trigger:"space"},{start:"###",format:"h3",trigger:"space"},{start:"####",format:"h4",trigger:"space"},{start:"#####",format:"h5",trigger:"space"},{start:"######",format:"h6",trigger:"space"},{start:"1.",cmd:"InsertOrderedList",trigger:"space"},{start:"*",cmd:"InsertUnorderedList",trigger:"space"},{start:"-",cmd:"InsertUnorderedList",trigger:"space"},{start:">",cmd:"mceBlockQuote",trigger:"space"},{start:"---",cmd:"InsertHorizontalRule",trigger:"space"}]}),t("text_patterns_lookup",{processor:e=>{return w(e)?{value:(t=e,e=>{const n=t(e);return Tl(n)}),valid:!0}:{valid:!1,message:"Must be a single function"};var t},default:e=>[]}),t("noneditable_class",{processor:"string",default:"mceNonEditable"}),t("editable_class",{processor:"string",default:"mceEditable"}),t("noneditable_regexp",{processor:e=>x(e,Dl)?{value:e,valid:!0}:Dl(e)?{value:[e],valid:!0}:{valid:!1,message:"Must be a RegExp or an array of RegExp."},default:[]}),t("table_tab_navigation",{processor:"boolean",default:!0}),t("highlight_on_focus",{processor:"boolean",default:!0}),t("xss_sanitization",{processor:"boolean",default:!0}),t("details_initial_state",{processor:e=>{const t=H(["inherited","collapsed","expanded"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: inherited, collapsed, or expanded."}},default:"inherited"}),t("details_serialized_state",{processor:e=>{const t=H(["inherited","collapsed","expanded"],e);return t?{value:e,valid:t}:{valid:!1,message:"Must be one of: inherited, collapsed, or expanded."}},default:"inherited"}),t("init_content_sync",{processor:"boolean",default:!1}),t("newdocument_content",{processor:"string",default:""}),t("sandbox_iframes",{processor:"boolean",default:!0}),t("sandbox_iframes_exclusions",{processor:"string[]",default:["youtube.com","youtu.be","vimeo.com","player.vimeo.com","dailymotion.com","embed.music.apple.com","open.spotify.com","giphy.com","dai.ly","codepen.io"]}),t("convert_unsafe_embeds",{processor:"boolean",default:!0}),e.on("ScriptsLoaded",(()=>{t("directionality",{processor:"string",default:va.isRtl()?"rtl":void 0}),t("placeholder",{processor:"string",default:Pl.getAttrib(e.getElement(),"placeholder")})}))})(o);const s=this.options.get;s("deprecation_warnings")&&((e,t)=>{((e,t)=>{const n=xw(e),o=Sw(t),r=o.length>0,s=n.length>0,a="mobile"===t.theme;if(r||s||a){const e="\n- ",t=a?`\n\nThemes:${e}mobile`:"",i=r?`\n\nPlugins:${e}${o.join(e)}`:"",l=s?`\n\nOptions:${e}${n.join(e)}`:"";console.warn("The following deprecated features are currently enabled and have been removed in TinyMCE 7.0. These features will no longer work and should be removed from the TinyMCE configuration. See https://www.tiny.cloud/docs/tinymce/7/migration-from-6x/ for more information."+t+i+l)}})(e,t),((e,t)=>{const n=kw(e),o=Nw(t),r=o.length>0,s=n.length>0;if(r||s){const e="\n- ",t=r?`\n\nPlugins:${e}${o.map(Rw).join(e)}`:"",a=s?`\n\nOptions:${e}${n.join(e)}`:"";console.warn("The following deprecated features are currently enabled but will be removed soon."+t+a)}})(e,t)})(t,r);const a=s("suffix");a&&(n.suffix=a),this.suffix=n.suffix;const i=s("base_url");i&&n._setBaseUrl(i),this.baseUri=n.baseURI;const l=ld(o);l&&(ga.ScriptLoader._setReferrerPolicy(l),ma.DOM.styleSheetLoader._setReferrerPolicy(l));const d=Hd(o);C(d)&&ma.DOM.styleSheetLoader._setContentCssCors(d),ya.languageLoad=s("language_load"),ya.baseURL=n.baseURL,this.setDirty(!1),this.documentBaseURI=new uC(zl(o),{base_uri:this.baseUri}),this.baseURI=this.baseUri,this.inline=Pd(o),this.hasVisual=Wd(o),this.shortcuts=new fB(this),this.editorCommands=new UO(this),MO(this);const c=s("cache_suffix");c&&(Tt.cacheSuffix=c.replace(/^[\?\&]+/,"")),this.ui={registry:gB(),styleSheetLoader:void 0,show:k,hide:k,setEnabled:k,isEnabled:M},this.mode=(e=>{const t=Br("design"),n=Br({design:{activate:k,deactivate:k,editorReadOnly:!1},readonly:{activate:k,deactivate:k,editorReadOnly:!0}});return(e=>{e.serializer?VO(e):e.on("PreInit",(()=>{VO(e)}))})(e),(e=>{e.on("ShowCaret",(t=>{$O(e)&&t.preventDefault()})),e.on("ObjectSelected",(t=>{$O(e)&&t.preventDefault()}))})(e),{isReadOnly:()=>$O(e),set:o=>((e,t,n,o)=>{if(o!==n.get()){if(!ke(t,o))throw new Error(`Editor mode '${o}' is invalid`);e.initialized?iB(e,n,t,o):e.on("init",(()=>iB(e,n,t,o)))}})(e,n.get(),t,o),get:()=>t.get(),register:(e,t)=>{n.set(((e,t,n)=>{if(H(aB,t))throw new Error(`Cannot override default mode ${t}`);return{...e,[t]:{...n,deactivate:()=>{try{n.deactivate()}catch(e){console.error(`problem while deactivating editor mode ${t}:`,e)}}}}})(n.get(),e,t))}}})(o),n.dispatch("SetupEditor",{editor:this});const y=Xd(o);w(y)&&y.call(o,o)}render(){(e=>{const t=e.id;va.setCode(dd(e));const n=()=>{cO.unbind(window,"ready",n),e.render()};if(!na.Event.domLoaded)return void cO.bind(window,"ready",n);if(!e.getElement())return;const o=Cn(e.getElement()),r=sn(o);e.on("remove",(()=>{W(o.dom.attributes,(e=>rn(o,e.name))),en(o,r)})),e.ui.styleSheetLoader=((e,t)=>rs.forElement(e,{contentCssCors:Hd(t),referrerPolicy:ld(t)}))(o,e),Pd(e)?e.inline=!0:(e.orgVisibility=e.getElement().style.visibility,e.getElement().style.visibility="hidden");const s=e.getElement().form||cO.getParent(t,"form");s&&(e.formElement=s,Dd(e)&&!lr(e.getElement())&&(cO.insertAfter(cO.create("input",{type:"hidden",name:t}),t),e.hasHiddenInput=!0),e.formEventDelegate=t=>{e.dispatch(t.type,t)},cO.bind(s,"submit reset",e.formEventDelegate),e.on("reset",(()=>{e.resetContent()})),!Ld(e)||s.submit.nodeType||s.submit.length||s._mceOldSubmit||(s._mceOldSubmit=s.submit,s.submit=()=>(e.editorManager.triggerSave(),e.setDirty(!1),s._mceOldSubmit(s)))),e.windowManager=Hw(e),e.notificationManager=Uw(e),(e=>"xml"===e.options.get("encoding"))(e)&&e.on("GetContent",(e=>{e.save&&(e.content=cO.encode(e.content))})),Md(e)&&e.on("submit",(()=>{e.initialized&&e.save()})),Id(e)&&(e._beforeUnload=()=>{!e.initialized||e.destroyed||e.isHidden()||e.save({format:"raw",no_events:!0,set_dirty:!1})},e.editorManager.on("BeforeUnload",e._beforeUnload)),e.editorManager.add(e),fO(e,e.suffix)})(this)}focus(e){this.execCommand("mceFocus",!1,e)}hasFocus(){return zg(this)}translate(e){return va.translate(e)}getParam(e,t,n){const o=this.options;return o.isRegistered(e)||(C(n)?o.register(e,{processor:n,default:t}):o.register(e,{processor:M,default:t})),o.isSet(e)||v(t)?o.get(e):t}hasPlugin(e,t){return!(!H($d(this),e)||t&&void 0===zw.get(e))}nodeChanged(e){this._nodeChangeDispatcher.nodeChanged(e)}addCommand(e,t,n){this.editorCommands.addCommand(e,t,n)}addQueryStateHandler(e,t,n){this.editorCommands.addQueryStateHandler(e,t,n)}addQueryValueHandler(e,t,n){this.editorCommands.addQueryValueHandler(e,t,n)}addShortcut(e,t,n,o){this.shortcuts.add(e,t,n,o)}execCommand(e,t,n,o){return this.editorCommands.execCommand(e,t,n,o)}queryCommandState(e){return this.editorCommands.queryCommandState(e)}queryCommandValue(e){return this.editorCommands.queryCommandValue(e)}queryCommandSupported(e){return this.editorCommands.queryCommandSupported(e)}show(){const e=this;e.hidden&&(e.hidden=!1,e.inline?e.getBody().contentEditable="true":(pB.show(e.getContainer()),pB.hide(e.id)),e.load(),e.dispatch("show"))}hide(){const e=this;e.hidden||(e.save(),e.inline?(e.getBody().contentEditable="false",e===e.editorManager.focusedEditor&&(e.editorManager.focusedEditor=null)):(pB.hide(e.getContainer()),pB.setStyle(e.id,"display",e.orgDisplay)),e.hidden=!0,e.dispatch("hide"))}isHidden(){return this.hidden}setProgressState(e,t){this.dispatch("ProgressState",{state:e,time:t})}load(e={}){const t=this,n=t.getElement();if(t.removed)return"";if(n){const o={...e,load:!0},r=lr(n)?n.value:n.innerHTML,s=t.setContent(r,o);return o.no_events||t.dispatch("LoadContent",{...o,element:n}),s}return""}save(e={}){const t=this;let n=t.getElement();if(!n||!t.initialized||t.removed)return"";const o={...e,save:!0,element:n};let r=t.getContent(o);const s={...o,content:r};if(s.no_events||t.dispatch("SaveContent",s),"raw"===s.format&&t.dispatch("RawSaveContent",s),r=s.content,lr(n))n.value=r;else{!e.is_removing&&t.inline||(n.innerHTML=r);const o=pB.getParent(t.id,"form");o&&bB(o.elements,(e=>e.name!==t.id||(e.value=r,!1)))}return s.element=o.element=n=null,!1!==s.set_dirty&&t.setDirty(!1),r}setContent(e,t){return bw(this,e,t)}getContent(e){return((e,t={})=>{const n=((e,t)=>({...e,format:t,get:!0,getInner:!0}))(t,t.format?t.format:"html");return RC(e,n).fold(R,(t=>{const n=((e,t)=>aw(e).editor.getContent(t))(e,t);return AC(e,n,t)}))})(this,e)}insertContent(e,t){t&&(e=hB({content:e},t)),this.execCommand("mceInsertContent",!1,e)}resetContent(e){void 0===e?bw(this,this.startContent,{format:"raw"}):bw(this,e),this.undoManager.reset(),this.setDirty(!1),this.nodeChanged()}isDirty(){return!this.isNotDirty}setDirty(e){const t=!this.isNotDirty;this.isNotDirty=!e,e&&e!==t&&this.dispatch("dirty")}getContainer(){const e=this;return e.container||(e.container=e.editorContainer||pB.get(e.id+"_parent")),e.container}getContentAreaContainer(){return this.contentAreaContainer}getElement(){return this.targetElm||(this.targetElm=pB.get(this.id)),this.targetElm}getWin(){const e=this;if(!e.contentWindow){const t=e.iframeElement;t&&(e.contentWindow=t.contentWindow)}return e.contentWindow}getDoc(){const e=this;if(!e.contentDocument){const t=e.getWin();t&&(e.contentDocument=t.document)}return e.contentDocument}getBody(){var e,t;const n=this.getDoc();return null!==(t=null!==(e=this.bodyElement)&&void 0!==e?e:null==n?void 0:n.body)&&void 0!==t?t:null}convertURL(e,t,n){const o=this,r=o.options.get,s=Qd(o);if(w(s))return s.call(o,e,n,!0,t);if(!r("convert_urls")||"link"===n||f(n)&&"LINK"===n.nodeName||0===e.indexOf("file:")||0===e.length)return e;const a=new uC(e);return"http"!==a.protocol&&"https"!==a.protocol&&""!==a.protocol?e:r("relative_urls")?o.documentBaseURI.toRelative(e):e=o.documentBaseURI.toAbsolute(e,r("remove_script_host"))}addVisual(e){((e,t)=>{((e,t)=>{iw(e).editor.addVisual(t)})(e,t)})(this,e)}setEditableRoot(e){((e,t)=>{e._editableRoot!==t&&(e._editableRoot=t,e.readonly||(e.getBody().contentEditable=String(e.hasEditableRoot()),e.nodeChanged()),((e,t)=>{e.dispatch("EditableRootStateChange",{state:t})})(e,t))})(this,e)}hasEditableRoot(){return this._editableRoot}remove(){(e=>{if(!e.removed){const{_selectionOverrides:t,editorUpload:n}=e,o=e.getBody(),r=e.getElement();o&&e.save({is_removing:!0}),e.removed=!0,e.unbindAllNativeEvents(),e.hasHiddenInput&&C(null==r?void 0:r.nextSibling)&&Aw.remove(r.nextSibling),(e=>{e.dispatch("remove")})(e),e.editorManager.remove(e),!e.inline&&o&&(e=>{Aw.setStyle(e.id,"display",e.orgDisplay)})(e),(e=>{e.dispatch("detach")})(e),Aw.remove(e.getContainer()),Tw(t),Tw(n),e.destroy()}})(this)}destroy(e){((e,t)=>{const{selection:n,dom:o}=e;e.destroyed||(t||e.removed?(t||(e.editorManager.off("beforeunload",e._beforeUnload),e.theme&&e.theme.destroy&&e.theme.destroy(),Tw(n),Tw(o)),(e=>{const t=e.formElement;t&&(t._mceOldSubmit&&(t.submit=t._mceOldSubmit,delete t._mceOldSubmit),Aw.unbind(t,"submit reset",e.formEventDelegate))})(e),(e=>{const t=e;t.contentAreaContainer=t.formElement=t.container=t.editorContainer=null,t.bodyElement=t.contentDocument=t.contentWindow=null,t.iframeElement=t.targetElm=null;const n=e.selection;if(n){const e=n.dom;t.selection=n.win=n.dom=e.doc=null}})(e),e.destroyed=!0):e.remove())})(this,e)}uploadImages(){return this.editorUpload.uploadImages()}_scanForImages(){return this.editorUpload.scanForImages()}}const yB=ma.DOM,CB=Dt.each;let wB,EB=!1,xB=[];const kB=e=>{const t=e.type;CB(RB.get(),(n=>{switch(t){case"scroll":n.dispatch("ScrollWindow",e);break;case"resize":n.dispatch("ResizeWindow",e)}}))},_B=e=>{if(e!==EB){const t=ma.DOM;e?(t.bind(window,"resize",kB),t.bind(window,"scroll",kB)):(t.unbind(window,"resize",kB),t.unbind(window,"scroll",kB)),EB=e}},SB=e=>{const t=xB;return xB=Y(xB,(t=>e!==t)),RB.activeEditor===e&&(RB.activeEditor=xB.length>0?xB[0]:null),RB.focusedEditor===e&&(RB.focusedEditor=null),t.length!==xB.length},NB="CSS1Compat"!==document.compatMode,RB={...GO,baseURI:null,baseURL:null,defaultOptions:{},documentBaseURL:null,suffix:null,majorVersion:"7",minorVersion:"2.1",releaseDate:"2024-07-03",i18n:va,activeEditor:null,focusedEditor:null,setup(){const e=this;let t="",n="",o=uC.getDocumentBaseUrl(document.location);/^[^:]+:\/\/\/?[^\/]+\//.test(o)&&(o=o.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(o)||(o+="/"));const r=window.tinymce||window.tinyMCEPreInit;if(r)t=r.base||r.baseURL,n=r.suffix;else{const e=document.getElementsByTagName("script");for(let o=0;o<e.length;o++){const r=e[o].src||"";if(""===r)continue;const s=r.substring(r.lastIndexOf("/"));if(/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(r)){-1!==s.indexOf(".min")&&(n=".min"),t=r.substring(0,r.lastIndexOf("/"));break}}if(!t&&document.currentScript){const e=document.currentScript.src;-1!==e.indexOf(".min")&&(n=".min"),t=e.substring(0,e.lastIndexOf("/"))}}var s;e.baseURL=new uC(o).toAbsolute(t),e.documentBaseURL=o,e.baseURI=new uC(e.baseURL),e.suffix=n,(s=e).on("AddEditor",T(Mg,s)),s.on("RemoveEditor",T(Ig,s))},overrideDefaults(e){const t=e.base_url;t&&this._setBaseUrl(t);const n=e.suffix;n&&(this.suffix=n),this.defaultOptions=e;const o=e.plugin_base_urls;void 0!==o&&pe(o,((e,t)=>{ya.PluginManager.urls[t]=e}))},init(e){const t=this;let n;const o=Dt.makeMap("area base basefont br col frame hr img input isindex link meta param embed source wbr track colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu"," ");let r=e=>{n=e};const s=()=>{let n=0;const a=[];let i;yB.unbind(window,"ready",s),(n=>{const o=e.onpageload;o&&o.apply(t,[])})(),i=me((e=>Tt.browser.isIE()||Tt.browser.isEdge()?(Kw("TinyMCE does not support the browser you are using. For a list of supported browsers please see: https://www.tiny.cloud/docs/tinymce/7/support/#supportedwebbrowsers"),[]):NB?(Kw("Failed to initialize the editor as the document is not in standards mode. TinyMCE requires standards mode."),[]):m(e.selector)?yB.select(e.selector):C(e.target)?[e.target]:[])(e)),Dt.each(i,(e=>{var n;(n=t.get(e.id))&&n.initialized&&!(n.getContainer()||n.getBody()).parentNode&&(SB(n),n.unbindAllNativeEvents(),n.destroy(!0),n.removed=!0)})),i=Dt.grep(i,(e=>!t.get(e.id))),0===i.length?r([]):CB(i,(s=>{((e,t)=>e.inline&&t.tagName.toLowerCase()in o)(e,s)?Kw("Could not initialize inline editor on invalid inline target element",s):((e,o,s)=>{const l=new vB(e,o,t);a.push(l),l.on("init",(()=>{++n===i.length&&r(a)})),l.targetElm=l.targetElm||s,l.render()})((e=>{let t=e.id;return t||(t=xe(e,"name").filter((e=>!yB.get(e))).getOrThunk(yB.uniqueId),e.setAttribute("id",t)),t})(s),e,s)}))};return yB.bind(window,"ready",s),new Promise((e=>{n?e(n):r=t=>{e(t)}}))},get(e){return 0===arguments.length?xB.slice(0):m(e)?Q(xB,(t=>t.id===e)).getOr(null):E(e)&&xB[e]?xB[e]:null},add(e){const t=this,n=t.get(e.id);return n===e||(null===n&&xB.push(e),_B(!0),t.activeEditor=e,t.dispatch("AddEditor",{editor:e}),wB||(wB=e=>{const n=t.dispatch("BeforeUnload");if(n.returnValue)return e.preventDefault(),e.returnValue=n.returnValue,n.returnValue},window.addEventListener("beforeunload",wB))),e},createEditor(e,t){return this.add(new vB(e,t,this))},remove(e){const t=this;let n;if(e){if(!m(e))return n=e,h(t.get(n.id))?null:(SB(n)&&t.dispatch("RemoveEditor",{editor:n}),0===xB.length&&window.removeEventListener("beforeunload",wB),n.remove(),_B(xB.length>0),n);CB(yB.select(e),(e=>{n=t.get(e.id),n&&t.remove(n)}))}else for(let e=xB.length-1;e>=0;e--)t.remove(xB[e])},execCommand(e,t,n){var o;const r=this,s=f(n)?null!==(o=n.id)&&void 0!==o?o:n.index:n;switch(e){case"mceAddEditor":if(!r.get(s)){const e=n.options;new vB(s,e,r).render()}return!0;case"mceRemoveEditor":{const e=r.get(s);return e&&e.remove(),!0}case"mceToggleEditor":{const e=r.get(s);return e?(e.isHidden()?e.show():e.hide(),!0):(r.execCommand("mceAddEditor",!1,n),!0)}}return!!r.activeEditor&&r.activeEditor.execCommand(e,t,n)},triggerSave:()=>{CB(xB,(e=>{e.save()}))},addI18n:(e,t)=>{va.add(e,t)},translate:e=>va.translate(e),setActive(e){const t=this.activeEditor;this.activeEditor!==e&&(t&&t.dispatch("deactivate",{relatedTarget:e}),e.dispatch("activate",{relatedTarget:t})),this.activeEditor=e},_setBaseUrl(e){this.baseURL=new uC(this.documentBaseURL).toAbsolute(e.replace(/\/+$/,"")),this.baseURI=new uC(this.baseURL)}};RB.setup();const AB=(()=>{const e=Dr();return{FakeClipboardItem:e=>({items:e,types:fe(e),getType:t=>xe(e,t).getOrUndefined()}),write:t=>{e.set(t)},read:()=>e.get().getOrUndefined(),clear:e.clear}})(),TB=Math.min,OB=Math.max,BB=Math.round,PB=(e,t,n)=>{let o=t.x,r=t.y;const s=e.w,a=e.h,i=t.w,l=t.h,d=(n||"").split("");return"b"===d[0]&&(r+=l),"r"===d[1]&&(o+=i),"c"===d[0]&&(r+=BB(l/2)),"c"===d[1]&&(o+=BB(i/2)),"b"===d[3]&&(r-=a),"r"===d[4]&&(o-=s),"c"===d[3]&&(r-=BB(a/2)),"c"===d[4]&&(o-=BB(s/2)),DB(o,r,s,a)},DB=(e,t,n,o)=>({x:e,y:t,w:n,h:o}),LB={inflate:(e,t,n)=>DB(e.x-t,e.y-n,e.w+2*t,e.h+2*n),relativePosition:PB,findBestRelativePosition:(e,t,n,o)=>{for(let r=0;r<o.length;r++){const s=PB(e,t,o[r]);if(s.x>=n.x&&s.x+s.w<=n.w+n.x&&s.y>=n.y&&s.y+s.h<=n.h+n.y)return o[r]}return null},intersect:(e,t)=>{const n=OB(e.x,t.x),o=OB(e.y,t.y),r=TB(e.x+e.w,t.x+t.w),s=TB(e.y+e.h,t.y+t.h);return r-n<0||s-o<0?null:DB(n,o,r-n,s-o)},clamp:(e,t,n)=>{let o=e.x,r=e.y,s=e.x+e.w,a=e.y+e.h;const i=t.x+t.w,l=t.y+t.h,d=OB(0,t.x-o),c=OB(0,t.y-r),u=OB(0,s-i),m=OB(0,a-l);return o+=d,r+=c,n&&(s+=d,a+=c,o-=u,r-=m),s-=u,a-=m,DB(o,r,s-o,a-r)},create:DB,fromClientRect:e=>DB(e.left,e.top,e.width,e.height)},MB=(()=>{const e={},t={},n={};return{load:(n,o)=>{const r=`Script at URL "${o}" failed to load`,s=`Script at URL "${o}" did not call \`tinymce.Resource.add('${n}', data)\` within 1 second`;if(void 0!==e[n])return e[n];{const a=new Promise(((e,a)=>{const i=((e,t,n=1e3)=>{let o=!1,r=null;const s=e=>(...t)=>{o||(o=!0,null!==r&&(clearTimeout(r),r=null),e.apply(null,t))},a=s(e),i=s(t);return{start:(...e)=>{o||null!==r||(r=setTimeout((()=>i.apply(null,e)),n))},resolve:a,reject:i}})(e,a);t[n]=i.resolve,ga.ScriptLoader.loadScript(o).then((()=>i.start(s)),(()=>i.reject(r)))}));return e[n]=a,a}},add:(o,r)=>{void 0!==t[o]&&(t[o](r),delete t[o]),e[o]=Promise.resolve(r),n[o]=r},has:e=>e in n,get:e=>n[e],unload:t=>{delete e[t],delete n[t]}}})();let IB;try{const e="__storage_test__";IB=window.localStorage,IB.setItem(e,e),IB.removeItem(e)}catch(e){IB=(()=>{let e={},t=[];const n={getItem:t=>e[t]||null,setItem:(n,o)=>{t.push(n),e[n]=String(o)},key:e=>t[e],removeItem:n=>{t=t.filter((e=>e===n)),delete e[n]},clear:()=>{t=[],e={}},length:0};return Object.defineProperty(n,"length",{get:()=>t.length,configurable:!1,enumerable:!1}),n})()}const FB={geom:{Rect:LB},util:{Delay:Tg,Tools:Dt,VK:yf,URI:uC,EventDispatcher:KO,Observable:GO,I18n:va,LocalStorage:IB,ImageUploader:e=>{const t=Zw(),n=tE(e,t);return{upload:(t,o=!0)=>n.upload(t,o?eE(e):void 0)}}},dom:{EventUtils:na,TreeWalker:Vo,TextSeeker:Ua,DOMUtils:ma,ScriptLoader:ga,RangeUtils:Zf,Serializer:hw,StyleSheetLoader:os,ControlSelection:kf,BookmarkManager:cf,Selection:fw,Event:na.Event},html:{Styles:Ks,Entities:ws,Node:Jg,Schema:Fs,DomParser:_C,Writer:bp,Serializer:vp},Env:Tt,AddOnManager:ya,Annotator:df,Formatter:fE,UndoManager:pE,EditorCommands:UO,WindowManager:Hw,NotificationManager:Uw,EditorObservable:tB,Shortcuts:fB,Editor:vB,FocusManager:Ag,EditorManager:RB,DOM:ma.DOM,ScriptLoader:ga.ScriptLoader,PluginManager:zw,ThemeManager:jw,ModelManager:Bw,IconManager:Ow,Resource:MB,FakeClipboard:AB,trim:Dt.trim,isArray:Dt.isArray,is:Dt.is,toArray:Dt.toArray,makeMap:Dt.makeMap,each:Dt.each,map:Dt.map,grep:Dt.grep,inArray:Dt.inArray,extend:Dt.extend,walk:Dt.walk,resolve:Dt.resolve,explode:Dt.explode,_addCacheSuffix:Dt._addCacheSuffix},UB=Dt.extend(RB,FB);(e=>{window.tinymce=e,window.tinyMCE=e})(UB),(e=>{if("object"==typeof module)try{module.exports=e}catch(e){}})(UB)}();
\ No newline at end of file
diff --git a/eims-ui/apps/web-antd/src/adapter/component/index.ts b/eims-ui/apps/web-antd/src/adapter/component/index.ts
new file mode 100644
index 0000000..370bcdf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/adapter/component/index.ts
@@ -0,0 +1,177 @@
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  AutoComplete,
+  Button,
+  Checkbox,
+  CheckboxGroup,
+  DatePicker,
+  Divider,
+  Input,
+  InputNumber,
+  InputPassword,
+  Mentions,
+  notification,
+  Radio,
+  RadioGroup,
+  RangePicker,
+  Rate,
+  Select,
+  Space,
+  Switch,
+  Textarea,
+  TimePicker,
+  TreeSelect,
+  Upload,
+} from 'ant-design-vue';
+
+import { Tinymce as RichTextarea } from '#/components/tinymce';
+import { FileUpload, ImageUpload } from '#/components/upload';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'ApiSelect'
+  | 'ApiTreeSelect'
+  | 'AutoComplete'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'DefaultButton'
+  | 'Divider'
+  | 'FileUpload'
+  | 'IconPicker'
+  | 'ImageUpload'
+  | 'Input'
+  | 'InputNumber'
+  | 'InputPassword'
+  | 'Mentions'
+  | 'PrimaryButton'
+  | 'Radio'
+  | 'RadioGroup'
+  | 'RangePicker'
+  | 'Rate'
+  | 'RichTextarea'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'Textarea'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+    ApiSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: Select,
+          loadingSlot: 'suffixIcon',
+          visibleEvent: 'onDropdownVisibleChange',
+          modelPropName: 'value',
+        },
+        slots,
+      );
+    },
+    ApiTreeSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: TreeSelect,
+          fieldNames: { label: 'label', value: 'value', children: 'children' },
+          loadingSlot: 'suffixIcon',
+          modelPropName: 'value',
+          optionsPropName: 'treeData',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    AutoComplete,
+    Checkbox,
+    CheckboxGroup,
+    DatePicker,
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'default' }, slots);
+    },
+    Divider,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs },
+        slots,
+      );
+    },
+    Input: withDefaultPlaceholder(Input, 'input'),
+    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+    Mentions: withDefaultPlaceholder(Mentions, 'input'),
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Radio,
+    RadioGroup,
+    RangePicker,
+    Rate,
+    Select: withDefaultPlaceholder(Select, 'select'),
+    Space,
+    Switch,
+    Textarea: withDefaultPlaceholder(Textarea, 'input'),
+    TimePicker,
+    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+    Upload,
+    ImageUpload,
+    FileUpload,
+    RichTextarea,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      notification.success({
+        description: content,
+        message: title,
+        placement: 'bottomRight',
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
diff --git a/eims-ui/apps/web-antd/src/adapter/form.ts b/eims-ui/apps/web-antd/src/adapter/form.ts
new file mode 100644
index 0000000..fca6abe
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/adapter/form.ts
@@ -0,0 +1,54 @@
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { isArray } from 'lodash-es';
+
+setupVbenForm<ComponentType>({
+  config: {
+    // ant design vue缁勪欢搴撻粯璁ら兘鏄� v-model:value
+    baseModelPropName: 'value',
+
+    // 涓�浜涚粍浠舵槸 v-model:checked 鎴栬�� v-model:fileList
+    modelPropNameMap: {
+      Checkbox: 'checked',
+      Radio: 'checked',
+      RichTextarea: 'modelValue',
+      Switch: 'checked',
+      Upload: 'fileList',
+    },
+  },
+  defineRules: {
+    // 杈撳叆椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    // 閫夋嫨椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    selectRequired: (value, _params, ctx) => {
+      if (
+        [false, null, undefined].includes(value) ||
+        (isArray(value) && value.length === 0)
+      ) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
+export type FormSchemaGetter = () => VbenFormSchema[];
diff --git a/eims-ui/apps/web-antd/src/adapter/vxe-table.ts b/eims-ui/apps/web-antd/src/adapter/vxe-table.ts
new file mode 100644
index 0000000..a5b92f2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/adapter/vxe-table.ts
@@ -0,0 +1,153 @@
+import { h, type Ref } from 'vue';
+
+import {
+  setupVbenVxeTable,
+  useVbenVxeGrid,
+  type VxeGridDefines,
+} from '@vben/plugins/vxe-table';
+
+import { Button, Image } from 'ant-design-vue';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+  configVxeTable: (vxeUI) => {
+    vxeUI.setConfig({
+      grid: {
+        align: 'center',
+        border: false,
+        minHeight: 180,
+        formConfig: {
+          // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+          enabled: false,
+        },
+        proxyConfig: {
+          autoLoad: true,
+          response: {
+            result: 'rows',
+            total: 'total',
+            list: 'rows',
+          },
+          showActiveMsg: true,
+          showResponseMsg: false,
+        },
+        // 婧㈠嚭灞曠ず褰㈠紡
+        showOverflow: true,
+        pagerConfig: {
+          // 榛樿鏉℃暟
+          pageSize: 10,
+          // 鍒嗛〉鍙�夋潯鏁�
+          pageSizes: [10, 20, 30, 40, 50],
+        },
+        rowConfig: {
+          // 榧犳爣绉诲叆琛屾樉绀� hover 鏍峰紡
+          isHover: true,
+          // 鐐瑰嚮琛岄珮浜�
+          isCurrent: true,
+        },
+        columnConfig: {
+          // 鍙嫋鎷藉垪瀹�
+          resizable: true,
+        },
+        // 鍙充笂瑙掑伐鍏锋爮
+        toolbarConfig: {
+          // 鑷畾涔夊垪
+          custom: {
+            icon: 'vxe-icon-setting',
+          },
+          // 鏈�澶у寲
+          zoom: true,
+          // 鍒锋柊
+          refresh: {
+            // 榛樿涓簉eload 淇敼涓哄湪褰撳墠椤靛埛鏂�
+            code: 'query',
+          },
+        },
+        // 鍦嗚鎸夐挳
+        round: true,
+        // 琛ㄦ牸灏哄
+        size: 'medium',
+        customConfig: {
+          // 琛ㄦ牸鍙充笂瑙掕嚜瀹氫箟鍒楅厤缃� 鏄惁淇濆瓨鍒發ocalStorage
+          // 蹇呴』瀛樺湪id鍙傛暟鎵嶈兘浣跨敤
+          storage: true,
+        },
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+    vxeUI.renderer.add('CellImage', {
+      renderTableDefault(_renderOpts, params) {
+        const { column, row } = params;
+        return h(Image, { src: row[column.field] });
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+    vxeUI.renderer.add('CellLink', {
+      renderTableDefault(renderOpts) {
+        const { props } = renderOpts;
+        return h(
+          Button,
+          { size: 'small', type: 'link' },
+          { default: () => props?.text },
+        );
+      },
+    });
+
+    // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+    // vxeUI.formats.add
+  },
+  useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
+
+/**
+ * 閫氱敤鐨勮〃鏍煎閫夋鏄惁閫変腑浜嬩欢
+ * @deprecated 浣跨敤vxeCheckboxChecked浠f浛
+ * @param checked 鏄惁閫変腑
+ * @returns function
+ */
+export function tableCheckboxEvent(checked: Ref<boolean>) {
+  const event: (params: VxeGridDefines.CheckboxChangeEventParams) => void = (
+    params,
+  ) => {
+    checked.value = params.$table.getCheckboxRecords().length > 0;
+  };
+  return event;
+}
+
+/**
+ * 鍒ゆ柇vxe-table鐨勫閫夋鏄惁閫変腑
+ * @param tableApi api
+ * @returns boolean
+ */
+export function vxeCheckboxChecked(
+  tableApi: ReturnType<typeof useVbenVxeGrid>[1],
+) {
+  return tableApi?.grid?.getCheckboxRecords?.()?.length > 0;
+}
+
+/**
+ * 閫氱敤鐨剉xe-table鎺掑簭浜嬩欢 鏀寔鍗�/澶氬瓧娈垫帓搴�
+ * @param tableApi api
+ * @param sortParams 鎺掑簭鍙傛暟
+ */
+export function vxeSortEvent(
+  tableApi: ReturnType<typeof useVbenVxeGrid>[1],
+  sortParams: VxeGridDefines.SortChangeEventParams,
+) {
+  const { sortList } = sortParams;
+  // 杩欓噷鏄帓搴忓彇娑� length涓�0 灏变笉浼犲弬鏁颁簡
+  if (sortList.length === 0) {
+    tableApi.query();
+    return;
+  }
+  // 鏀寔鍗�/澶氬瓧娈垫帓搴�
+  const orderByColumn = sortList.map((item) => item.field).join(',');
+  const isAsc = sortList.map((item) => item.order).join(',');
+  tableApi.query({ orderByColumn, isAsc });
+}
diff --git a/eims-ui/apps/web-antd/src/api/common.d.ts b/eims-ui/apps/web-antd/src/api/common.d.ts
new file mode 100644
index 0000000..233f2aa
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/common.d.ts
@@ -0,0 +1,41 @@
+export type ID = number | string;
+export type IDS = (number | string)[];
+
+export interface BaseEntity {
+  createBy?: string;
+  createDept?: string;
+  createTime?: string;
+  updateBy?: string;
+  updateTime?: string;
+}
+
+/**
+ * 鍒嗛〉淇℃伅
+ * @param rows 缁撴灉闆�
+ * @param total 鎬绘暟
+ */
+export interface PageResult<T = any> {
+  rows: T[];
+  total: number;
+}
+
+/**
+ * 鍒嗛〉鏌ヨ鍙傛暟
+ *
+ * 鎺掑簭鏀寔鐨勭敤娉曞涓�:
+ * {isAsc:"asc",orderByColumn:"id"} order by id asc
+ * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
+ * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
+ * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
+ *
+ * @param pageNum 褰撳墠椤�
+ * @param pageSize 姣忛〉澶у皬
+ * @param orderByColumn 鎺掑簭瀛楁
+ * @param isAsc 鏄惁鍗囧簭
+ */
+export interface PageQuery {
+  isAsc?: string;
+  orderByColumn?: string;
+  pageNum?: number;
+  pageSize?: number;
+}
diff --git a/eims-ui/apps/web-antd/src/api/core/auth.ts b/eims-ui/apps/web-antd/src/api/core/auth.ts
new file mode 100644
index 0000000..989135b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/auth.ts
@@ -0,0 +1,175 @@
+import type { GrantType } from '@vben/common-ui';
+
+import { useAppConfig } from '@vben/hooks';
+
+import { requestClient } from '#/api/request';
+
+const { clientId, sseEnable } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+export namespace AuthApi {
+  /**
+   * @description: 鎵�鏈夌櫥褰曠被鍨嬮兘闇�瑕佺敤鍒扮殑
+   * @param clientId 瀹㈡埛绔疘D 杩欓噷涓哄繀濉」 浣嗘槸鍦╨oginApi鍐呴儴澶勭悊浜� 鎵�浠ヤ负鍙��
+   * @param grantType 鎺堟潈/鐧诲綍绫诲瀷
+   * @param tenantId 绉熸埛id
+   */
+  export interface BaseLoginParams {
+    clientId?: string;
+    grantType: GrantType;
+    tenantId: string;
+  }
+
+  /**
+   * @description: oauth鐧诲綍闇�瑕佺敤鍒扮殑鍙傛暟
+   * @param socialCode 绗笁鏂瑰弬鏁�
+   * @param socialState 绗笁鏂瑰弬鏁�
+   * @param source 涓庡悗绔殑 justauth.type.xxx鐨勫洖璋冨湴鍧�鐨剆ource瀵瑰簲
+   */
+  export interface OAuthLoginParams extends BaseLoginParams {
+    socialCode: string;
+    socialState: string;
+    source: string;
+  }
+
+  /**
+   * @description: 楠岃瘉鐮佺櫥褰曢渶瑕佺敤鍒扮殑鍙傛暟
+   * @param code 楠岃瘉鐮� 鍙��(鏈紑鍚獙璇佺爜鎯呭喌)
+   * @param uuid 楠岃瘉鐮両D 鍙��(鏈紑鍚獙璇佺爜鎯呭喌)
+   * @param username 鐢ㄦ埛鍚�
+   * @param password 瀵嗙爜
+   */
+  export interface SimpleLoginParams extends BaseLoginParams {
+    code?: string;
+    uuid?: string;
+    username: string;
+    password: string;
+  }
+
+  export type LoginParams = OAuthLoginParams | SimpleLoginParams;
+
+  // /** 鐧诲綍鎺ュ彛鍙傛暟 */
+  // export interface LoginParams {
+  //   code?: string;
+  //   grantType: string;
+  //   password: string;
+  //   tenantId: string;
+  //   username: string;
+  //   uuid?: string;
+  // }
+
+  /** 鐧诲綍鎺ュ彛杩斿洖鍊� */
+  export interface LoginResult {
+    access_token: string;
+    client_id: string;
+    expire_in: number;
+  }
+
+  export interface RefreshTokenResult {
+    data: string;
+    status: number;
+  }
+}
+
+/**
+ * 鐧诲綍
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+  return requestClient.post<AuthApi.LoginResult>(
+    '/auth/login',
+    { ...data, clientId },
+    {
+      encrypt: true,
+    },
+  );
+}
+
+/**
+ * 鐢ㄦ埛鐧诲嚭
+ * @returns void
+ */
+export function doLogout() {
+  return requestClient.post<void>('/auth/logout');
+}
+
+/**
+ * 鍏抽棴sse杩炴帴
+ * @returns void
+ */
+export function seeConnectionClose() {
+  /**
+   * 鏈紑鍚痵se 涓嶉渶瑕佸鐞�
+   */
+  if (!sseEnable) {
+    return;
+  }
+  return requestClient.get<void>('/resource/sse/close');
+}
+
+/**
+ * @param companyName 绉熸埛/鍏徃鍚嶇О
+ * @param domain 缁戝畾鍩熷悕(涓嶅甫http(s)://) 鍙��
+ * @param tenantId 绉熸埛id
+ */
+export interface TenantOption {
+  companyName: string;
+  domain?: string;
+  tenantId: string;
+}
+
+/**
+ * @param tenantEnabled 鏄惁鍚敤绉熸埛
+ * @param voList 绉熸埛鍒楄〃
+ */
+export interface TenantResp {
+  tenantEnabled: boolean;
+  voList: TenantOption[];
+}
+
+/**
+ * 鑾峰彇绉熸埛鍒楄〃 涓嬫媺妗嗕娇鐢�
+ */
+export function tenantList() {
+  return requestClient.get<TenantResp>('/auth/tenant/list');
+}
+
+/**
+ * vben鐨� 鍏堜笉鍒犻櫎
+ * @returns string[]
+ */
+export async function getAccessCodesApi() {
+  return requestClient.get<string[]>('/auth/codes');
+}
+
+/**
+ * 缁戝畾绗笁鏂硅处鍙�
+ * @param source 缁戝畾鐨勬潵婧�
+ * @returns 璺宠浆url
+ */
+export function authBinding(source: string, tenantId: string) {
+  return requestClient.get<string>(`/auth/binding/${source}`, {
+    params: {
+      domain: window.location.host,
+      tenantId,
+    },
+  });
+}
+
+/**
+ * 鍙栨秷缁戝畾
+ * @param id id
+ */
+export function authUnbinding(id: string) {
+  return requestClient.deleteWithMsg<void>(`/auth/unlock/${id}`);
+}
+
+/**
+ * oauth鎺堟潈鍥炶皟
+ * @param data oauth鎺堟潈
+ * @returns void
+ */
+export function authCallback(data: AuthApi.OAuthLoginParams) {
+  return requestClient.post<void>('/auth/social/callback', data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/core/captcha.ts b/eims-ui/apps/web-antd/src/api/core/captcha.ts
new file mode 100644
index 0000000..254e11b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/captcha.ts
@@ -0,0 +1,42 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * 鍙戦�佺煭淇¢獙璇佺爜
+ * @param phonenumber 鎵嬫満鍙�
+ * @returns void
+ */
+export function sendSmsCode(phonenumber: string) {
+  return requestClient.get<void>('/resource/sms/code', {
+    params: { phonenumber },
+  });
+}
+
+/**
+ * 鍙戦�侀偖浠堕獙璇佺爜
+ * @param email 閭
+ * @returns void
+ */
+export function sendEmailCode(email: string) {
+  return requestClient.get<void>('/resource/email/code', {
+    params: { email },
+  });
+}
+
+/**
+ * @param img 鍥剧墖楠岃瘉鐮� 闇�瑕佸拰base64鎷兼帴
+ * @param captchaEnabled 鏄惁寮�鍚�
+ * @param uuid 楠岃瘉鐮両D
+ */
+export interface CaptchaResponse {
+  captchaEnabled: boolean;
+  img: string;
+  uuid: string;
+}
+
+/**
+ * 鍥剧墖楠岃瘉鐮�
+ * @returns resp
+ */
+export function captchaImage() {
+  return requestClient.get<CaptchaResponse>('/auth/code');
+}
diff --git a/eims-ui/apps/web-antd/src/api/core/index.ts b/eims-ui/apps/web-antd/src/api/core/index.ts
new file mode 100644
index 0000000..0425686
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/index.ts
@@ -0,0 +1,4 @@
+export * from './auth';
+export * from './menu';
+export * from './upload';
+export * from './user';
diff --git a/eims-ui/apps/web-antd/src/api/core/menu.ts b/eims-ui/apps/web-antd/src/api/core/menu.ts
new file mode 100644
index 0000000..e4bef60
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/menu.ts
@@ -0,0 +1,45 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * @description: 鑿滃崟meta
+ * @param title 鑿滃崟鍚�
+ * @param icon 鑿滃崟鍥炬爣
+ * @param noCache 鏄惁涓嶇紦瀛�
+ * @param link 澶栭摼閾炬帴
+ */
+export interface MenuMeta {
+  icon: string;
+  link?: string;
+  noCache: boolean;
+  title: string;
+}
+
+/**
+ * @description: 鑿滃崟
+ * @param name 鑿滃崟鍚�
+ * @param path 鑿滃崟璺緞
+ * @param hidden 鏄惁闅愯棌
+ * @param component 缁勪欢鍚嶇О Laout
+ * @param alwaysShow 鎬绘槸鏄剧ず
+ * @param query 璺敱鍙傛暟(json褰㈠紡)
+ * @param meta 璺敱淇℃伅
+ * @param children 瀛愯矾鐢变俊鎭�
+ */
+export interface Menu {
+  alwaysShow?: boolean;
+  children: Menu[];
+  component: string;
+  hidden: boolean;
+  meta: MenuMeta;
+  name: string;
+  path: string;
+  query?: string;
+  redirect?: string;
+}
+
+/**
+ * 鑾峰彇鐢ㄦ埛鎵�鏈夎彍鍗�
+ */
+export async function getAllMenusApi() {
+  return requestClient.get<Menu[]>('/system/menu/getRouters');
+}
diff --git a/eims-ui/apps/web-antd/src/api/core/upload.ts b/eims-ui/apps/web-antd/src/api/core/upload.ts
new file mode 100644
index 0000000..32833b6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/upload.ts
@@ -0,0 +1,18 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * 閫氳繃鍗曟枃浠朵笂浼犳帴鍙�
+ * @param file 涓婁紶鐨勬枃浠�
+ * @returns 涓婁紶缁撴灉
+ */
+export function uploadApi(file: Blob | File) {
+  return requestClient.upload('/resource/oss/upload', { file });
+}
+/**
+ * 榛樿涓婁紶缁撴灉
+ */
+export interface UploadResult {
+  url: string;
+  fileName: string;
+  ossId: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/core/user.ts b/eims-ui/apps/web-antd/src/api/core/user.ts
new file mode 100644
index 0000000..6258760
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/core/user.ts
@@ -0,0 +1,46 @@
+import { requestClient } from '#/api/request';
+
+export interface Role {
+  dataScope: string;
+  flag: boolean;
+  roleId: number;
+  roleKey: string;
+  roleName: string;
+  roleSort: number;
+  status: string;
+  superAdmin: boolean;
+}
+
+export interface User {
+  avatar: string;
+  createTime: string;
+  deptId: number;
+  deptName: string;
+  email: string;
+  loginDate: string;
+  loginIp: string;
+  nickName: string;
+  phonenumber: string;
+  remark: string;
+  roles: Role[];
+  sex: string;
+  status: string;
+  tenantId: string;
+  userId: number;
+  userName: string;
+  userType: string;
+}
+
+export interface UserInfoResp {
+  permissions: string[];
+  roles: string[];
+  user: User;
+}
+
+/**
+ * 鑾峰彇鐢ㄦ埛淇℃伅
+ * 瀛樺湪杩斿洖null鐨勬儏鍐�(401) 涓嶄細鎶涘嚭寮傚父 闇�瑕佹墜鍔ㄦ姏寮傚父
+ */
+export async function getUserInfoApi() {
+  return requestClient.get<null | UserInfoResp>('/system/user/getInfo');
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/equ-type/index.ts b/eims-ui/apps/web-antd/src/api/eims/equ-type/index.ts
new file mode 100644
index 0000000..6ce755a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/equ-type/index.ts
@@ -0,0 +1,69 @@
+import type { EquTypeTree, EquTypeVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  equTypeExport = '/eims/equType/export',
+  equTypeList = '/eims/equType/list',
+  equTypeTree = '/eims/equType/tree',
+  root = '/eims/equType'
+}
+
+/**
+ * 鏌ヨ璁惧绫诲瀷鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export function listEquType(params?: any) {
+  return requestClient.get<EquTypeVO[]>(Api.equTypeList, { params });
+}
+
+/**
+ * 鑾峰彇璁惧绫诲瀷鏍�
+ * @returns 閮ㄩ棬鏍戞暟缁�
+ */
+export function getEquTypeTree() {
+  return requestClient.get<EquTypeTree[]>(Api.equTypeTree);
+}
+
+/**
+ * 鏌ヨ璁惧绫诲瀷璇︾粏
+ * @param equTypeId
+ */
+export function getEquType(equTypeId: ID) {
+  return requestClient.get<EquTypeVO>(`${Api.root}/${equTypeId}`);
+}
+
+/**
+ * 鏂板璁惧绫诲瀷
+ * @param data
+ */
+export function addEquType(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+/**
+ * 淇敼璁惧绫诲瀷
+ * @param data
+ */
+export function updateEquType(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎璁惧绫诲瀷
+ * @param equTypeId
+ */
+export function delEquType(equTypeId: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${equTypeId}`);
+}
+/**
+ * 瀵煎嚭
+ * @param
+ */
+export function equTypeExport(data: any) {
+  return commonExport(Api.equTypeExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/equ-type/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/equ-type/model.d.ts
new file mode 100644
index 0000000..1c0e5ae
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/equ-type/model.d.ts
@@ -0,0 +1,67 @@
+export interface EquTypeVO {
+  /**
+   * 绫诲瀷id
+   */
+  equTypeId: number | string;
+
+  /**
+   * 绫诲瀷鍚嶇О
+   */
+  typeName: string;
+
+  /**
+   * 绫诲瀷缂栫爜
+   */
+  typeCode: string;
+
+  /**
+   * 鐖秈d
+   */
+  parentId: number | string;
+
+  /**
+   * 鏄剧ず椤哄簭
+   */
+  orderNum: number;
+
+  /**
+   * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+   */
+  menuType: string;
+
+  /**
+   * 鑿滃崟鍥炬爣
+   */
+  icon: string;
+
+  /**
+   * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+   */
+  status: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+
+  /**
+   * 瀛愬璞�
+   */
+  children: EquTypeVO[];
+}
+
+/**
+ * @description: 璁惧绫诲瀷鏍�
+ */
+export interface EquTypeTree {
+  id: number;
+  /**
+   * antd缁勪欢蹇呴』瑕佽繖涓睘鎬� 瀹為檯鏄病鏈夎繖涓睘鎬х殑
+   */
+  key: string;
+  parentId: number;
+  label: string;
+  weight: number;
+  children?: EquTypeTree[];
+}
+
diff --git a/eims-ui/apps/web-antd/src/api/eims/equ/index.ts b/eims-ui/apps/web-antd/src/api/eims/equ/index.ts
new file mode 100644
index 0000000..fd95bcd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/equ/index.ts
@@ -0,0 +1,61 @@
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+import type { EquVO } from '#/api/eims/equ/model';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  equExport = '/eims/equ/export',
+  equList = '/eims/equ/list',
+  root = '/eims/equ'
+}
+
+/**
+ * 鏌ヨ銆愯澶囧彴璐︺�戝垪琛�
+ * @param query
+ * @returns {*}
+ */
+
+export function listEqu(params?: PageQuery) {
+  return requestClient.get<PageResult<EquVO>>(Api.equList, { params });
+}
+
+/**
+ * 鏌ヨ銆愯澶囧彴璐︺�戣缁�
+ * @param equId
+ */
+export function getEqu(equId: any) {
+  return requestClient.get<EquVO>(`${Api.root}/${equId}`);
+}
+
+/**
+ * 鏂板銆愯澶囧彴璐︺��
+ * @param data
+ */
+export function addEqu(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼銆愯澶囧彴璐︺��
+ * @param data
+ */
+export function updateEqu(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎銆愯澶囧彴璐︺��
+ * @param equIds
+ */
+export function delEqu(equIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${equIds}`);
+}
+
+/**
+ * 瀵煎嚭銆愯澶囧彴璐︺��
+ * @param data
+ */
+export function equExport(data: any) {
+  return commonExport(Api.equExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/equ/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/equ/model.d.ts
new file mode 100644
index 0000000..7807f19
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/equ/model.d.ts
@@ -0,0 +1,124 @@
+export interface EquVO {
+  /**
+   *
+   */
+  equId: number | string;
+
+  /**
+   * 璧勪骇缂栧彿
+   */
+  assetNo: string;
+  /**
+   * 璁惧缂栫爜
+   */
+  equCode: string;
+
+  /**
+   * 璁惧鍚嶇О
+
+   */
+  equName: string;
+  /**
+   * 璁惧绫诲瀷
+
+   */
+  equTypeName: string;
+
+  /**
+   * 鍨嬪彿
+   */
+  modelNo: string;
+
+  /**
+   * 鍒堕�犲晢
+   */
+  madeIn: string;
+
+  /**
+   * 棰濆害鍔熺巼
+   */
+  ratedPower: number;
+
+  /**
+   * 閾墝淇℃伅
+   */
+  plateInfo: string;
+
+  /**
+   * 閲囪喘鏃ユ湡
+   */
+  purchaseDate: string;
+
+  /**
+   * 鐘舵��
+   */
+  status: string;
+
+  /**
+   * 鎵�鍦ㄥ満鎵�
+   */
+  location: string;
+
+  /**
+   * 浣跨敤閮ㄩ棬锛堝叧鑱攊d锛�
+   */
+  deptUsed: number;
+  /**
+   * 浣跨敤閮ㄩ棬鍚嶇О
+   */
+  deptName: number;
+
+  /**
+   * 璐d换浜�(鍏宠仈id)
+   */
+  respPerson: number;
+  /**
+   * 璐d换浜�
+   */
+  respPersonName: string;
+
+  /**
+   * 鑱旂郴鐢佃瘽
+   */
+  contactPhone: string;
+
+  /**
+   * 姝e紡浣跨敤鏃ユ湡
+   */
+  deployDate: string;
+
+  /**
+   * 寮�濮嬭瘯鐢ㄦ棩鏈�
+   */
+  trialDate: string;
+
+  /**
+   * 璁″垝楠屾敹鏃ユ湡
+   */
+  planAcceptDate: string;
+
+  /**
+   * 瀹為檯楠屾敹鏃ユ湡
+   */
+  actualAcceptDate: string;
+
+  /**
+   * 瀵煎叆鐘舵�侊紙瀛楀吀锛�
+   */
+  importStatus: number;
+
+  /**
+   * 鐩樼偣鏍囧織
+   */
+  inventoryFlag: number;
+
+  /**
+   * 涓婃鐩樼偣鏃ユ湡
+   */
+  inventoryDate: string;
+
+  /**
+   * 浣跨敤骞撮檺
+   */
+  serviceLife: number;
+}
diff --git a/eims-ui/apps/web-antd/src/api/helper.ts b/eims-ui/apps/web-antd/src/api/helper.ts
new file mode 100644
index 0000000..88360d9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/helper.ts
@@ -0,0 +1,28 @@
+import { requestClient } from './request';
+
+/**
+ * @description:  contentType
+ */
+export enum ContentTypeEnum {
+  // form-data  upload
+  FORM_DATA = 'multipart/form-data;charset=UTF-8',
+  // form-data qs
+  FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
+  // json
+  JSON = 'application/json;charset=UTF-8',
+}
+
+/**
+ * 閫氱敤涓嬭浇鎺ュ彛 灏佽涓�灞�
+ * @param url 璇锋眰鍦板潃
+ * @param data  璇锋眰鍙傛暟
+ * @returns blob浜岃繘鍒�
+ */
+export function commonExport(url: string, data: Record<string, any>) {
+  return requestClient.post<Blob>(url, data, {
+    data,
+    headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
+    isTransformResponse: false,
+    responseType: 'blob',
+  });
+}
diff --git a/eims-ui/apps/web-antd/src/api/index.ts b/eims-ui/apps/web-antd/src/api/index.ts
new file mode 100644
index 0000000..4b0e041
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/index.ts
@@ -0,0 +1 @@
+export * from './core';
diff --git a/eims-ui/apps/web-antd/src/api/monitor/cache/index.ts b/eims-ui/apps/web-antd/src/api/monitor/cache/index.ts
new file mode 100644
index 0000000..1065d34
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/cache/index.ts
@@ -0,0 +1,24 @@
+import { requestClient } from '#/api/request';
+
+export interface CommandStats {
+  name: string;
+  value: string;
+}
+
+export interface RedisInfo {
+  [key: string]: string;
+}
+
+export interface CacheInfo {
+  commandStats: CommandStats[];
+  dbSize: number;
+  info: RedisInfo;
+}
+
+/**
+ *
+ * @returns redis淇℃伅
+ */
+export function redisCacheInfo() {
+  return requestClient.get<CacheInfo>('/monitor/cache');
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/logininfo/index.ts b/eims-ui/apps/web-antd/src/api/monitor/logininfo/index.ts
new file mode 100644
index 0000000..4ca071b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/logininfo/index.ts
@@ -0,0 +1,60 @@
+import type { LoginLog } from './model';
+
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  loginInfoClean = '/monitor/logininfor/clean',
+  loginInfoExport = '/monitor/logininfor/export',
+  loginInfoList = '/monitor/logininfor/list',
+  root = '/monitor/logininfor',
+  userUnlock = '/monitor/logininfor/unlock',
+}
+
+/**
+ * 鐧诲綍鏃ュ織鍒楄〃
+ * @param params 鏌ヨ鍙傛暟
+ * @returns list[]
+ */
+export function loginInfoList(params?: PageQuery) {
+  return requestClient.get<PageResult<LoginLog>>(Api.loginInfoList, { params });
+}
+
+/**
+ * 瀵煎嚭鐧诲綍鏃ュ織
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns excel
+ */
+export function loginInfoExport(data: any) {
+  return commonExport(Api.loginInfoExport, data);
+}
+
+/**
+ * 绉婚櫎鐧诲綍鏃ュ織
+ * @param infoIds 鐧诲綍鏃ュ織id鏁扮粍
+ * @returns void
+ */
+export function loginInfoRemove(infoIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${infoIds}`);
+}
+
+/**
+ * 璐﹀彿瑙i攣
+ * @param username 鐢ㄦ埛鍚�(璐﹀彿)
+ * @returns void
+ */
+export function userUnlock(username: string) {
+  return requestClient.get<void>(`${Api.userUnlock}/${username}`, {
+    successMessageMode: 'message',
+  });
+}
+
+/**
+ * 娓呯┖鍏ㄩ儴鐧诲綍鏃ュ織
+ * @returns void
+ */
+export function loginInfoClean() {
+  return requestClient.deleteWithMsg<void>(Api.loginInfoClean);
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/logininfo/model.d.ts b/eims-ui/apps/web-antd/src/api/monitor/logininfo/model.d.ts
new file mode 100644
index 0000000..93ab220
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/logininfo/model.d.ts
@@ -0,0 +1,12 @@
+export interface LoginLog {
+  infoId: string;
+  tenantId: string;
+  userName: string;
+  status: string;
+  ipaddr: string;
+  loginLocation: string;
+  browser: string;
+  os: string;
+  msg: string;
+  loginTime: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/online/index.ts b/eims-ui/apps/web-antd/src/api/monitor/online/index.ts
new file mode 100644
index 0000000..4d8224a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/online/index.ts
@@ -0,0 +1,40 @@
+import type { OnlineUser } from './model';
+
+import type { PageQuery, PageResult } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  onlineList = '/monitor/online/list',
+  root = '/monitor/online',
+}
+
+/**
+ * 褰撳墠璐﹀彿鐨勫湪绾胯澶� 涓汉涓績浣跨敤
+ * @returns OnlineUser[]
+ */
+export function onlineDeviceList() {
+  return requestClient.get<PageResult<OnlineUser>>(Api.root);
+}
+
+export function onlineList(params?: PageQuery) {
+  return requestClient.get<PageResult<OnlineUser>>(Api.onlineList, { params });
+}
+
+/**
+ * 寮哄埗涓嬬嚎
+ * @param tokenId 鐢ㄦ埛token
+ * @returns void
+ */
+export function forceLogout(tokenId: string) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${tokenId}`);
+}
+
+/**
+ * 涓汉涓績鐢ㄧ殑 璺熶笂闈㈢殑涓嶅悓鏄敤鐨凱ost
+ * @param tokenId 鐢ㄦ埛token
+ * @returns void
+ */
+export function forceLogout2(tokenId: string) {
+  return requestClient.postWithMsg<void>(`${Api.root}/${tokenId}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/online/model.d.ts b/eims-ui/apps/web-antd/src/api/monitor/online/model.d.ts
new file mode 100644
index 0000000..b93395f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/online/model.d.ts
@@ -0,0 +1,10 @@
+export interface OnlineUser {
+  tokenId: string;
+  deptName: string;
+  userName: string;
+  ipaddr: string;
+  loginLocation: string;
+  browser: string;
+  os: string;
+  loginTime: number;
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/operlog/index.ts b/eims-ui/apps/web-antd/src/api/monitor/operlog/index.ts
new file mode 100644
index 0000000..c061b44
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/operlog/index.ts
@@ -0,0 +1,31 @@
+import type { OperationLog } from './model';
+
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  operLogClean = '/monitor/operlog/clean',
+  operLogExport = '/monitor/operlog/export',
+  operLogList = '/monitor/operlog/list',
+  root = '/monitor/operlog',
+}
+
+export function operLogList(params?: PageQuery) {
+  return requestClient.get<PageResult<OperationLog>>(Api.operLogList, {
+    params,
+  });
+}
+
+export function operLogDelete(operIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${operIds}`);
+}
+
+export function operLogClean() {
+  return requestClient.deleteWithMsg<void>(Api.operLogClean);
+}
+
+export function operLogExport(data: any) {
+  return commonExport(Api.operLogExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/monitor/operlog/model.d.ts b/eims-ui/apps/web-antd/src/api/monitor/operlog/model.d.ts
new file mode 100644
index 0000000..42bc582
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/monitor/operlog/model.d.ts
@@ -0,0 +1,21 @@
+export interface OperationLog {
+  operId: string;
+  tenantId: string;
+  title: string;
+  businessType: number;
+  businessTypes?: any;
+  method: string;
+  requestMethod: string;
+  operatorType: number;
+  operName: string;
+  deptName: string;
+  operUrl: string;
+  operIp: string;
+  operLocation: string;
+  operParam: string;
+  jsonResult: string;
+  status: number;
+  errorMsg: string;
+  operTime: string;
+  costTime: number;
+}
diff --git a/eims-ui/apps/web-antd/src/api/request.ts b/eims-ui/apps/web-antd/src/api/request.ts
new file mode 100644
index 0000000..b3d8080
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/request.ts
@@ -0,0 +1,259 @@
+/**
+ * 璇ユ枃浠跺彲鑷鏍规嵁涓氬姟閫昏緫杩涜璋冩暣
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { $t } from '@vben/locales';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+  stringify,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message, Modal } from 'ant-design-vue';
+import { isEmpty, isNull } from 'lodash-es';
+
+import { useAuthStore } from '#/store';
+import {
+  decryptBase64,
+  decryptWithAes,
+  encryptBase64,
+  encryptWithAes,
+  generateAesKey,
+} from '#/utils/encryption/crypto';
+import * as encryptUtil from '#/utils/encryption/jsencrypt';
+
+const { apiURL, clientId, enableEncrypt } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+/**
+ * 鏄惁宸茬粡澶勫湪鐧诲嚭杩囩▼涓簡 涓�涓爣蹇椾綅
+ * 涓昏鏄槻姝竴涓〉闈細璇锋眰澶氫釜api 閮�401 浼氬鑷寸櫥鍑烘墽琛屽娆�
+ */
+let isLogoutProcessing = false;
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    // 鍚庣鍦板潃
+    baseURL,
+    // 娑堟伅鎻愮ず绫诲瀷
+    errorMessageMode: 'message',
+    // 鏄惁杩斿洖鍘熺敓鍝嶅簲 姣斿锛氶渶瑕佽幏鍙栧搷搴斿ご鏃朵娇鐢ㄨ灞炴��
+    isReturnNativeResponse: false,
+    // 闇�瑕佸杩斿洖鏁版嵁杩涜澶勭悊
+    isTransformResponse: true,
+  });
+
+  /**
+   * 閲嶆柊璁よ瘉閫昏緫
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (
+      preferences.app.loginExpiredMode === 'modal' &&
+      accessStore.isAccessChecked
+    ) {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * 鍒锋柊token閫昏緫
+   */
+  async function doRefreshToken() {
+    // 涓嶉渶瑕�
+    // 淇濈暀姝ゆ柟娉曞彧鏄负浜嗗悎骞舵柟渚�
+    return '';
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  client.addRequestInterceptor({
+    fulfilled: (config) => {
+      const accessStore = useAccessStore();
+      // 娣诲姞token
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      /**
+       * locale璺熷悗鍙颁笉涓�鑷� 闇�瑕佽浆鎹�
+       */
+      const language = preferences.app.locale.replace('-', '_');
+      config.headers['Accept-Language'] = language;
+      config.headers['Content-Language'] = language;
+      // 娣诲姞鍏ㄥ眬clientId
+      config.headers.clientId = clientId;
+
+      /**
+       * 鏍煎紡鍖杇et/delete鍙傛暟
+       * 濡傛灉鍖呭惈鑷畾涔夌殑paramsSerializer鍒欎笉璧版閫昏緫
+       */
+      if (
+        ['DELETE', 'GET'].includes(config.method?.toUpperCase() || '') &&
+        config.params &&
+        !config.paramsSerializer
+      ) {
+        /**
+         * 1. 鏍煎紡鍖栧弬鏁� 寰湇鍔″湪浼犻�掑尯闂存椂闂撮�夋嫨(鍚庣鐨刾arams Map绫诲瀷鍙傛暟)闇�瑕佹牸寮忓寲key 鍚﹀垯鎺ユ敹涓嶅埌
+         * 2. 鏁扮粍鍙傛暟闇�瑕佹牸寮忓寲 鍚庣鎵嶈兘姝e父鎺ユ敹 浼氬彉鎴恆rr=1&arr=2&arr=3鐨勬牸寮忔潵鎺ユ敹
+         */
+        config.paramsSerializer = (params) =>
+          stringify(params, { arrayFormat: 'repeat' });
+      }
+
+      const { encrypt } = config;
+      // 鍏ㄥ眬寮�鍚姹傚姞瀵嗗姛鑳� && 璇ヨ姹傚紑鍚� && 鏄痯ost/put璇锋眰
+      if (
+        enableEncrypt &&
+        encrypt &&
+        ['POST', 'PUT'].includes(config.method?.toUpperCase() || '')
+      ) {
+        const aesKey = generateAesKey();
+        config.headers['encrypt-key'] = encryptUtil.encrypt(
+          encryptBase64(aesKey),
+        );
+
+        config.data =
+          typeof config.data === 'object'
+            ? encryptWithAes(JSON.stringify(config.data), aesKey)
+            : encryptWithAes(config.data, aesKey);
+      }
+      return config;
+    },
+  });
+
+  // 閫氱敤鐨勯敊璇鐞�, 濡傛灉娌℃湁杩涘叆涓婇潰鐨勯敊璇鐞嗛�昏緫锛屽氨浼氳繘鍏ヨ繖閲�
+  // 涓昏澶勭悊http鐘舵�佺爜涓嶄负200鐨勬儏鍐� 蹇呴』鏀惧湪鍦ㄤ笅闈㈢殑鍝嶅簲鎷︽埅鍣ㄤ箣鍓�
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string) => message.error(msg)),
+  );
+
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const encryptKey = (response.headers || {})['encrypt-key'];
+      if (encryptKey) {
+        /** RSA绉侀挜瑙e瘑 鎷垮埌瑙e瘑绉橀挜鐨刡ase64 */
+        const base64Str = encryptUtil.decrypt(encryptKey);
+        /** base64 瑙g爜 寰楀埌璇锋眰澶寸殑 AES 绉橀挜 */
+        const aesSecret = decryptBase64(base64Str.toString());
+        /** 浣跨敤aesKey瑙e瘑 responseData */
+        const decryptData = decryptWithAes(
+          response.data as unknown as string,
+          aesSecret,
+        );
+        /** 璧嬪�� 闇�瑕佽浆涓哄璞� */
+        response.data = JSON.parse(decryptData);
+      }
+
+      const { isReturnNativeResponse, isTransformResponse } = response.config;
+      // 鏄惁杩斿洖鍘熺敓鍝嶅簲 姣斿锛氶渶瑕佽幏鍙栧搷搴旀椂浣跨敤璇ュ睘鎬�
+      if (isReturnNativeResponse) {
+        return response;
+      }
+      // 涓嶈繘琛屼换浣曞鐞嗭紝鐩存帴杩斿洖
+      // 鐢ㄤ簬椤甸潰浠g爜鍙兘闇�瑕佺洿鎺ヨ幏鍙朿ode锛宒ata锛宮essage杩欎簺淇℃伅鏃跺紑鍚�
+      if (!isTransformResponse) {
+        return response.data;
+      }
+
+      const axiosResponseData = response.data;
+      if (!axiosResponseData) {
+        throw new Error($t('fallback.http.apiRequestFailed'));
+      }
+
+      //  ruoyi-plus娌℃湁閲囩敤涓ユ牸鐨剓code, msg, data}妯″紡
+      const { code, data, msg, ...other } = axiosResponseData;
+
+      // 杩欓噷閫昏緫鍙互鏍规嵁椤圭洰杩涜淇敼
+      const hasSuccess = Reflect.has(axiosResponseData, 'code') && code === 200;
+      if (hasSuccess) {
+        let successMsg = msg;
+
+        if (isNull(successMsg) || isEmpty(successMsg)) {
+          successMsg = $t(`fallback.http.operationSuccess`);
+        }
+
+        if (response.config.successMessageMode === 'modal') {
+          Modal.success({
+            content: successMsg,
+            title: $t('fallback.http.successTip'),
+          });
+        } else if (response.config.successMessageMode === 'message') {
+          message.success(successMsg);
+        }
+        // 濡傛灉鏈塪ata 鐩存帴杩斿洖data 娌℃湁data灏嗗墿浣欏弬鏁�(...other)灏佽涓篸ata杩斿洖
+        // 闇�瑕佽�冭檻data涓簄ull鐨勬儏鍐�(姣斿鏌ヨ涓虹┖)
+        if (data !== undefined) {
+          return data;
+        }
+        return other;
+      }
+      // 鍦ㄦ澶勬牴鎹嚜宸遍」鐩殑瀹為檯鎯呭喌瀵逛笉鍚岀殑code鎵ц涓嶅悓鐨勬搷浣�
+      // 濡傛灉涓嶅笇鏈涗腑鏂綋鍓嶈姹傦紝璇穜eturn鏁版嵁锛屽惁鍒欑洿鎺ユ姏鍑哄紓甯稿嵆鍙�
+      let timeoutMsg = '';
+      switch (code) {
+        case 401: {
+          // 宸茬粡鍦ㄧ櫥鍑鸿繃绋嬩腑 涓嶅啀鎵ц
+          if (isLogoutProcessing) {
+            return;
+          }
+          isLogoutProcessing = true;
+          const _msg = '鐧诲綍瓒呮椂, 璇烽噸鏂扮櫥褰�';
+          const userStore = useAuthStore();
+          userStore.logout().finally(() => {
+            message.error(_msg);
+            isLogoutProcessing = false;
+          });
+          // 涓嶅啀鎵ц涓嬮潰閫昏緫
+          return;
+        }
+        default: {
+          if (msg) {
+            timeoutMsg = msg;
+          }
+        }
+      }
+
+      // errorMessageMode='modal'鐨勬椂鍊欎細鏄剧ずmodal閿欒寮圭獥锛岃�屼笉鏄秷鎭彁绀猴紝鐢ㄤ簬涓�浜涙瘮杈冮噸瑕佺殑閿欒
+      // errorMessageMode='none' 涓�鑸槸璋冪敤鏃舵槑纭〃绀轰笉甯屾湜鑷姩寮瑰嚭閿欒鎻愮ず
+      if (response.config.errorMessageMode === 'modal') {
+        Modal.error({
+          content: timeoutMsg,
+          title: $t('fallback.http.errorTip'),
+        });
+      } else if (response.config.errorMessageMode === 'message') {
+        message.error(timeoutMsg);
+      }
+
+      throw new Error(timeoutMsg || $t('fallback.http.apiRequestFailed'));
+    },
+  });
+
+  // token杩囨湡鐨勫鐞�
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
diff --git a/eims-ui/apps/web-antd/src/api/system/client/index.ts b/eims-ui/apps/web-antd/src/api/system/client/index.ts
new file mode 100644
index 0000000..354fab9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/client/index.ts
@@ -0,0 +1,41 @@
+import type { Client } from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  clientChangeStatus = '/system/client/changeStatus',
+  clientExport = '/system/client/export',
+  clientList = '/system/client/list',
+  root = '/system/client',
+}
+
+export function clientList(params?: PageQuery) {
+  return requestClient.get<PageResult<Client>>(Api.clientList, { params });
+}
+
+export function clientExport(data: any) {
+  return commonExport(Api.clientExport, data);
+}
+
+export function clientInfo(id: ID) {
+  return requestClient.get<Client>(`${Api.root}/${id}`);
+}
+
+export function clientAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function clientUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function clientChangeStatus(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function clientRemove(ids: IDS) {
+  return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/client/model.d.ts b/eims-ui/apps/web-antd/src/api/system/client/model.d.ts
new file mode 100644
index 0000000..62af21f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/client/model.d.ts
@@ -0,0 +1,12 @@
+export interface Client {
+  id: number;
+  clientId: string;
+  clientKey: string;
+  clientSecret: string;
+  grantTypeList: string[];
+  grantType: string;
+  deviceType: string;
+  activeTimeout: number;
+  timeout: number;
+  status: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/config/index.ts b/eims-ui/apps/web-antd/src/api/system/config/index.ts
new file mode 100644
index 0000000..588bb2b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/config/index.ts
@@ -0,0 +1,55 @@
+import type { Config } from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  configExport = '/system/config/export',
+  configInfoByKey = '/system/config/configKey',
+  configList = '/system/config/list',
+  configRefreshCache = '/system/config/refreshCache',
+  root = '/system/config',
+}
+
+export function configList(params?: PageQuery) {
+  return requestClient.get<PageResult<Config>>(Api.configList, { params });
+}
+
+export function configInfo(configId: ID) {
+  return requestClient.get<Config>(`${Api.root}/${configId}`);
+}
+
+export function configExport(data: any) {
+  return commonExport(Api.configExport, data);
+}
+
+/**
+ * 鍒锋柊缂撳瓨
+ * @returns void
+ */
+export function configRefreshCache() {
+  return requestClient.deleteWithMsg<void>(Api.configRefreshCache);
+}
+
+export function configUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function configAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function configRemove(configIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${configIds}`);
+}
+
+/**
+ * 鑾峰彇閰嶇疆淇℃伅
+ * @param configKey configKey
+ * @returns value
+ */
+export function configInfoByKey(configKey: string) {
+  return requestClient.get<string>(`${Api.configInfoByKey}/${configKey}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/config/model.d.ts b/eims-ui/apps/web-antd/src/api/system/config/model.d.ts
new file mode 100644
index 0000000..85afc55
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/config/model.d.ts
@@ -0,0 +1,9 @@
+export interface Config {
+  configId: number;
+  configName: string;
+  configKey: string;
+  configValue: string;
+  configType: string;
+  remark: string;
+  createTime: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dept/index.ts b/eims-ui/apps/web-antd/src/api/system/dept/index.ts
new file mode 100644
index 0000000..7557537
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dept/index.ts
@@ -0,0 +1,45 @@
+import type { Dept } from './model';
+
+import type { ID } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  deptList = '/system/dept/list',
+  deptNodeInfo = '/system/dept/list/exclude',
+  root = '/system/dept',
+}
+
+export function deptList(params?: any) {
+  return requestClient.get<Dept[]>(Api.deptList, { params });
+}
+
+/**
+ * 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
+ * @param deptId 閮ㄩ棬ID
+ * @returns void
+ */
+export function deptNodeList(deptId: ID) {
+  return requestClient.get<Dept[]>(`${Api.deptNodeInfo}/${deptId}`);
+}
+
+export function deptInfo(deptId: ID) {
+  return requestClient.get<Dept>(`${Api.root}/${deptId}`);
+}
+
+export function deptAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function deptUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 娉ㄦ剰杩欓噷鍙厑璁稿崟鍒犻櫎
+ * @param deptId ID
+ * @returns void
+ */
+export function deptRemove(deptId: ID) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${deptId}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dept/model.d.ts b/eims-ui/apps/web-antd/src/api/system/dept/model.d.ts
new file mode 100644
index 0000000..1aaaf24
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dept/model.d.ts
@@ -0,0 +1,19 @@
+export interface Dept {
+  createBy: string;
+  createTime: string;
+  updateBy?: string;
+  updateTime?: string;
+  remark?: string;
+  deptId: number;
+  parentId: number;
+  ancestors: string;
+  deptName: string;
+  orderNum: number;
+  leader: string;
+  phone: string;
+  email: string;
+  status: string;
+  delFlag: string;
+  parentName?: string;
+  children?: Dept[];
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dict/dict-data-model.d.ts b/eims-ui/apps/web-antd/src/api/system/dict/dict-data-model.d.ts
new file mode 100644
index 0000000..e46092f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dict/dict-data-model.d.ts
@@ -0,0 +1,17 @@
+export interface DictData {
+  createBy: string;
+  createTime: string;
+  cssClass: string;
+  default: boolean;
+  dictCode: number;
+  dictLabel: string;
+  dictSort: number;
+  dictType: string;
+  dictValue: string;
+  isDefault: string;
+  listClass: string;
+  remark: string;
+  status: string;
+  updateBy?: any;
+  updateTime?: any;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dict/dict-data.ts b/eims-ui/apps/web-antd/src/api/system/dict/dict-data.ts
new file mode 100644
index 0000000..a39ec39
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dict/dict-data.ts
@@ -0,0 +1,75 @@
+import type { DictData } from './dict-data-model';
+
+import type { ID, IDS, PageQuery } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  dictDataExport = '/system/dict/data/export',
+  dictDataList = '/system/dict/data/list',
+  root = '/system/dict/data',
+}
+
+/**
+ * 涓昏鏄疍ictTag缁勪欢浣跨敤
+ * @param dictType 瀛楀吀绫诲瀷
+ * @returns 瀛楀吀鏁版嵁
+ */
+export function dictDataInfo(dictType: string) {
+  return requestClient.get<DictData[]>(`${Api.root}/type/${dictType}`);
+}
+
+/**
+ * 瀛楀吀鏁版嵁
+ * @param params 鏌ヨ鍙傛暟
+ * @returns 瀛楀吀鏁版嵁鍒楄〃
+ */
+export function dictDataList(params?: PageQuery) {
+  return requestClient.get<DictData[]>(Api.dictDataList, { params });
+}
+
+/**
+ * 瀵煎嚭瀛楀吀鏁版嵁
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns blob
+ */
+export function dictDataExport(data: any) {
+  return commonExport(Api.dictDataExport, data);
+}
+
+/**
+ * 鍒犻櫎
+ * @param dictIds 瀛楀吀ID Array
+ * @returns void
+ */
+export function dictDataRemove(dictIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
+}
+
+/**
+ * 鏂板
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns void
+ */
+export function dictDataAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns void
+ */
+export function dictDataUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+ * @param dictCode 瀛楀吀缂栫爜
+ * @returns 瀛楀吀鏁版嵁
+ */
+export function dictDetailInfo(dictCode: ID) {
+  return requestClient.get<DictData>(`${Api.root}/${dictCode}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dict/dict-type-model.d.ts b/eims-ui/apps/web-antd/src/api/system/dict/dict-type-model.d.ts
new file mode 100644
index 0000000..b4bfcb8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dict/dict-type-model.d.ts
@@ -0,0 +1,8 @@
+export interface DictType {
+  createTime: string;
+  dictId: number;
+  dictName: string;
+  dictType: string;
+  remark: string;
+  status: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/dict/dict-type.ts b/eims-ui/apps/web-antd/src/api/system/dict/dict-type.ts
new file mode 100644
index 0000000..e3d4b29
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/dict/dict-type.ts
@@ -0,0 +1,84 @@
+import type { DictType } from './dict-type-model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  dictOptionSelectList = '/system/dict/type/optionselect',
+  dictTypeExport = '/system/dict/type/export',
+  dictTypeList = '/system/dict/type/list',
+  dictTypeRefreshCache = '/system/dict/type/refreshCache',
+  root = '/system/dict/type',
+}
+
+/**
+ * 鑾峰彇瀛楀吀绫诲瀷鍒楄〃
+ * @param params 璇锋眰鍙傛暟
+ * @returns list
+ */
+export function dictTypeList(params?: PageQuery) {
+  return requestClient.get<PageResult<DictType>>(Api.dictTypeList, { params });
+}
+
+/**
+ * 瀵煎嚭瀛楀吀绫诲瀷鍒楄〃
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns blob
+ */
+export function dictTypeExport(data: any) {
+  return commonExport(Api.dictTypeExport, data);
+}
+
+/**
+ * 鍒犻櫎瀛楀吀绫诲瀷
+ * @param dictIds 瀛楀吀绫诲瀷id鏁扮粍
+ * @returns void
+ */
+export function dictTypeRemove(dictIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${dictIds}`);
+}
+
+/**
+ * 鍒锋柊瀛楀吀缂撳瓨
+ * @returns void
+ */
+export function refreshDictTypeCache() {
+  return requestClient.deleteWithMsg<void>(Api.dictTypeRefreshCache);
+}
+
+/**
+ * 鏂板
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns void
+ */
+export function dictTypeAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼
+ * @param data 琛ㄥ崟鍙傛暟
+ * @returns void
+ */
+export function dictTypeUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鏌ヨ璇︽儏
+ * @param dictId 瀛楀吀绫诲瀷id
+ * @returns 淇℃伅
+ */
+export function dictTypeInfo(dictId: ID) {
+  return requestClient.get<DictType>(`${Api.root}/${dictId}`);
+}
+
+/**
+ * 涓嬫媺妗�  杩斿洖鍊煎拰list涓�鏍�
+ * @returns options
+ */
+export function dictOptionSelectList() {
+  return requestClient.get<DictType[]>(Api.dictOptionSelectList);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/menu/index.ts b/eims-ui/apps/web-antd/src/api/system/menu/index.ts
new file mode 100644
index 0000000..65c3b4f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/menu/index.ts
@@ -0,0 +1,61 @@
+import type { Menu, MenuOption, MenuResp } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  menuList = '/system/menu/list',
+  menuTreeSelect = '/system/menu/treeselect',
+  roleMenuTree = '/system/menu/roleMenuTreeselect',
+  root = '/system/menu',
+  tenantPackageMenuTreeselect = '/system/menu/tenantPackageMenuTreeselect',
+}
+
+export function menuList(params?: any) {
+  return requestClient.get<Menu[]>(Api.menuList, { params });
+}
+
+export function menuInfo(menuId: ID) {
+  return requestClient.get<Menu>(`${Api.root}/${menuId}`);
+}
+
+export function menuAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function menuUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function menuRemove(menuIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${menuIds}`);
+}
+
+/**
+ * 杩斿洖瀵瑰簲瑙掕壊鐨勮彍鍗�
+ * @param roleId id
+ * @returns resp
+ */
+export function roleMenuTreeSelect(roleId: ID) {
+  return requestClient.get<MenuResp>(`${Api.roleMenuTree}/${roleId}`);
+}
+
+/**
+ * 涓嬫媺妗嗕娇鐢�  杩斿洖鎵�鏈夌殑鑿滃崟
+ * @returns []
+ */
+export function menuTreeSelect() {
+  return requestClient.get<MenuOption[]>(Api.menuTreeSelect);
+}
+
+/**
+ * 绉熸埛濂楅浣跨敤
+ * @param packageId packageId
+ * @returns resp
+ */
+export function tenantPackageMenuTreeSelect(packageId: ID) {
+  return requestClient.get<MenuResp>(
+    `${Api.tenantPackageMenuTreeselect}/${packageId}`,
+  );
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/menu/model.d.ts b/eims-ui/apps/web-antd/src/api/system/menu/model.d.ts
new file mode 100644
index 0000000..0234425
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/menu/model.d.ts
@@ -0,0 +1,46 @@
+export interface Menu {
+  createBy?: any;
+  createTime: string;
+  updateBy?: any;
+  updateTime?: any;
+  remark?: any;
+  menuId: number;
+  menuName: string;
+  parentName?: string;
+  parentId: number;
+  orderNum: number;
+  path: string;
+  component?: string;
+  query: string;
+  isFrame: string;
+  isCache: string;
+  menuType: string;
+  visible: string;
+  status: string;
+  perms: string;
+  icon: string;
+  children: Menu[];
+}
+
+/**
+ * @description 鑿滃崟淇℃伅
+ * @param label 鑿滃崟鍚嶇О
+ */
+export interface MenuOption {
+  id: number;
+  parentId: number;
+  label: string;
+  weight: number;
+  children: MenuOption[];
+  key: string; // 瀹為檯涓婁笉瀛樺湪 ide鎶ラ敊
+}
+
+/**
+ * @description 鑿滃崟杩斿洖
+ * @param checkedKeys 閫変腑鐨勮彍鍗昳d
+ * @param menus 鑿滃崟淇℃伅
+ */
+export interface MenuResp {
+  checkedKeys: number[];
+  menus: MenuOption[];
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/notice/index.ts b/eims-ui/apps/web-antd/src/api/system/notice/index.ts
new file mode 100644
index 0000000..8287794
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/notice/index.ts
@@ -0,0 +1,30 @@
+import type { Notice } from './model';
+
+import type { ID, IDS, PageQuery } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  noticeList = '/system/notice/list',
+  root = '/system/notice',
+}
+
+export function noticeList(params?: PageQuery) {
+  return requestClient.get<Notice[]>(Api.noticeList, { params });
+}
+
+export function noticeInfo(noticeId: ID) {
+  return requestClient.get<Notice>(`${Api.root}/${noticeId}`);
+}
+
+export function noticeAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function noticeUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function noticeRemove(noticeIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${noticeIds}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/notice/model.d.ts b/eims-ui/apps/web-antd/src/api/system/notice/model.d.ts
new file mode 100644
index 0000000..992eb4f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/notice/model.d.ts
@@ -0,0 +1,11 @@
+export interface Notice {
+  noticeId: number;
+  noticeTitle: string;
+  noticeType: string;
+  noticeContent: string;
+  status: string;
+  remark: string;
+  createBy: number;
+  createByName: string;
+  createTime: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/oss-config/index.ts b/eims-ui/apps/web-antd/src/api/system/oss-config/index.ts
new file mode 100644
index 0000000..3774e8a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/oss-config/index.ts
@@ -0,0 +1,41 @@
+import type { OssConfig } from './model';
+
+import type { ID, IDS, PageQuery } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  ossConfigChangeStatus = '/resource/oss/config/changeStatus',
+  ossConfigList = '/resource/oss/config/list',
+  root = '/resource/oss/config',
+}
+
+// 鑾峰彇OSS閰嶇疆鍒楄〃
+export function ossConfigList(params?: PageQuery) {
+  return requestClient.get<OssConfig[]>(Api.ossConfigList, { params });
+}
+
+// 鑾峰彇OSS閰嶇疆鐨勪俊鎭�
+export function ossConfigInfo(ossConfigId: ID) {
+  return requestClient.get<OssConfig>(`${Api.root}/${ossConfigId}`);
+}
+
+// 娣诲姞鏂扮殑OSS閰嶇疆
+export function ossConfigAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+// 鏇存柊鐜版湁鐨凮SS閰嶇疆
+export function ossConfigUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+// 鍒犻櫎OSS閰嶇疆
+export function ossConfigRemove(ossConfigIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${ossConfigIds}`);
+}
+
+// 鏇存敼OSS閰嶇疆鐨勭姸鎬�
+export function ossConfigChangeStatus(data: any) {
+  return requestClient.putWithMsg(Api.ossConfigChangeStatus, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/oss-config/model.d.ts b/eims-ui/apps/web-antd/src/api/system/oss-config/model.d.ts
new file mode 100644
index 0000000..b80b210
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/oss-config/model.d.ts
@@ -0,0 +1,16 @@
+export interface OssConfig {
+  ossConfigId: number;
+  configKey: string;
+  accessKey: string;
+  secretKey: string;
+  bucketName: string;
+  prefix: string;
+  endpoint: string;
+  domain: string;
+  isHttps: string;
+  region: string;
+  status: string;
+  ext1: string;
+  remark: string;
+  accessPolicy: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/oss/index.ts b/eims-ui/apps/web-antd/src/api/system/oss/index.ts
new file mode 100644
index 0000000..139b926
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/oss/index.ts
@@ -0,0 +1,53 @@
+import type { OssFile } from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { ContentTypeEnum } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  ossDownload = '/resource/oss/download',
+  ossInfo = '/resource/oss/listByIds',
+  ossList = '/resource/oss/list',
+  ossUpload = '/resource/oss/upload',
+  root = '/resource/oss',
+}
+
+export function ossList(params?: PageQuery) {
+  return requestClient.get<PageResult<OssFile>>(Api.ossList, { params });
+}
+
+export function ossInfo(ossIds: IDS) {
+  return requestClient.get<OssFile>(`${Api.ossInfo}/${ossIds}`);
+}
+
+/**
+ * @deprecated
+ * @param file 鏂囦欢
+ * @returns void
+ */
+export function ossUpload(file: any) {
+  const formData = new FormData();
+  formData.append('file', file);
+  return requestClient.postWithMsg(Api.ossUpload, formData, {
+    headers: { 'Content-Type': ContentTypeEnum.FORM_DATA },
+    timeout: 30 * 1000,
+  });
+}
+
+/**
+ * 涓嬭浇鏂囦欢  杩斿洖涓轰簩杩涘埗
+ * @param ossId ossId
+ * @returns blob
+ */
+export function ossDownload(ossId: ID) {
+  return requestClient.get<Blob>(`${Api.ossDownload}/${ossId}`, {
+    responseType: 'blob',
+    timeout: 30 * 1000,
+    isTransformResponse: false,
+  });
+}
+
+export function ossRemove(ossIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${ossIds}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/oss/model.d.ts b/eims-ui/apps/web-antd/src/api/system/oss/model.d.ts
new file mode 100644
index 0000000..6eb4f37
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/oss/model.d.ts
@@ -0,0 +1,28 @@
+export interface OssFile {
+  ossId: string;
+  fileName: string;
+  originalName: string;
+  fileSuffix: string;
+  url: string;
+  createTime: string;
+  createBy: number;
+  createByName: string;
+  service: string;
+}
+
+export interface OssConfig {
+  ossConfigId: number;
+  configKey: string;
+  accessKey: string;
+  secretKey: string;
+  bucketName: string;
+  prefix: string;
+  endpoint: string;
+  domain: string;
+  isHttps: string;
+  region: string;
+  status: string;
+  ext1: string;
+  remark: string;
+  accessPolicy: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/post/index.ts b/eims-ui/apps/web-antd/src/api/system/post/index.ts
new file mode 100644
index 0000000..61c5c3e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/post/index.ts
@@ -0,0 +1,46 @@
+import type { Post } from './model';
+
+import type { ID, IDS, PageQuery } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  postExport = '/system/post/export',
+  postList = '/system/post/list',
+  postSelect = '/system/post/optionselect',
+  root = '/system/post',
+}
+
+/**
+ * 鑾峰彇宀椾綅鍒楄〃
+ * @param params 鍙傛暟
+ * @returns Post[]
+ */
+export function postList(params?: PageQuery) {
+  return requestClient.get<Post[]>(Api.postList, { params });
+}
+
+export function postExport(data: any) {
+  return commonExport(Api.postExport, data);
+}
+
+export function postInfo(postId: ID) {
+  return requestClient.get<Post>(`${Api.root}/${postId}`);
+}
+
+export function postAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function postUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function postRemove(postIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${postIds}`);
+}
+
+export function postOptionSelect(deptId: ID) {
+  return requestClient.get<Post[]>(Api.postSelect, { params: { deptId } });
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/post/model.d.ts b/eims-ui/apps/web-antd/src/api/system/post/model.d.ts
new file mode 100644
index 0000000..b75f3c0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/post/model.d.ts
@@ -0,0 +1,12 @@
+/**
+ * @description: Post interface
+ */
+export interface Post {
+  postId: number;
+  postCode: string;
+  postName: string;
+  postSort: number;
+  status: string;
+  remark: string;
+  createTime: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/profile/index.ts b/eims-ui/apps/web-antd/src/api/system/profile/index.ts
new file mode 100644
index 0000000..4eb3f01
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/profile/index.ts
@@ -0,0 +1,65 @@
+import type { FileCallBack, UpdatePasswordParam, UserProfile } from './model';
+
+import { buildUUID } from '@vben/utils';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/system/user/profile',
+  updateAvatar = '/system/user/profile/avatar',
+  updatePassword = '/system/user/profile/updatePwd',
+}
+
+/**
+ * 鐢ㄦ埛涓汉涓婚〉淇℃伅
+ * @returns userInformation
+ */
+export function userProfile() {
+  return requestClient.get<UserProfile>(Api.root);
+}
+
+/**
+ * 鏇存柊鐢ㄦ埛涓汉涓婚〉淇℃伅
+ * @param data
+ * @returns void
+ */
+export function userProfileUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鐢ㄦ埛淇敼瀵嗙爜 (闇�瑕佸姞瀵�)
+ * @param data
+ * @returns void
+ */
+export function userUpdatePassword(data: UpdatePasswordParam) {
+  return requestClient.putWithMsg<void>(Api.updatePassword, data, {
+    encrypt: true,
+  });
+}
+
+/**
+ * 鐢ㄦ埛鏇存柊涓汉澶村儚
+ * @param fileCallback data
+ * @returns void
+ */
+export function userUpdateAvatar(fileCallback: FileCallBack) {
+  /** 鐩存帴鐐瑰嚮澶村儚涓婁紶 filename涓虹┖ 鐢变簬鍚庡彴閫氳繃鎷撳睍鍚嶅垽鏂�(榛樿鏂囦欢鍚峛lob) 浼氫笂浼犲け璐� */
+  let { file } = fileCallback;
+  const { filename } = fileCallback;
+  /**
+   * Blob杞現ile绫诲瀷
+   * 1. 鍦ㄧ洿鎺ョ偣鍑荤‘璁� filename涓虹┖ 鍙杣uid浣滀负鏂囦欢鍚�
+   * 2. 閫夋嫨涓婁紶蹇呴』杞负File绫诲瀷 Blob绫诲瀷涓婁紶鍚庡彴鑾峰彇鏂囦欢鍚嶄负绌�
+   */
+  file = filename
+    ? new File([file], filename)
+    : new File([file], `${buildUUID()}.png`);
+  return requestClient.post(
+    Api.updateAvatar,
+    {
+      avatarfile: file,
+    },
+    { headers: { 'Content-Type': 'multipart/form-data' } },
+  );
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/profile/model.d.ts b/eims-ui/apps/web-antd/src/api/system/profile/model.d.ts
new file mode 100644
index 0000000..bb1e4b3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/profile/model.d.ts
@@ -0,0 +1,75 @@
+export interface Dept {
+  deptId: number;
+  parentId: number;
+  parentName?: any;
+  ancestors: string;
+  deptName: string;
+  orderNum: number;
+  leader: string;
+  phone?: any;
+  email: string;
+  status: string;
+  createTime?: any;
+}
+
+export interface Role {
+  roleId: number;
+  roleName: string;
+  roleKey: string;
+  roleSort: number;
+  dataScope: string;
+  menuCheckStrictly?: any;
+  deptCheckStrictly?: any;
+  status: string;
+  remark: string;
+  createTime?: any;
+  flag: boolean;
+  superAdmin: boolean;
+}
+
+export interface User {
+  userId: number;
+  tenantId: string;
+  deptId: number;
+  userName: string;
+  nickName: string;
+  userType: string;
+  email: string;
+  phonenumber: string;
+  sex: string;
+  avatar: string;
+  status: string;
+  loginIp: string;
+  loginDate: string;
+  remark: string;
+  createTime: string;
+  dept: Dept;
+  roles: Role[];
+  roleIds?: string[];
+  postIds?: string[];
+  roleId: number;
+  deptName: string;
+}
+
+/**
+ * @description 鐢ㄦ埛涓汉涓婚〉淇℃伅
+ * @param user 鐢ㄦ埛淇℃伅
+ * @param roleGroup 瑙掕壊鍚嶇О
+ * @param postGroup 宀椾綅鍚嶇О
+ */
+export interface UserProfile {
+  user: User;
+  roleGroup: string;
+  postGroup: string;
+}
+
+export interface UpdatePasswordParam {
+  oldPassword: string;
+  newPassword: string;
+}
+
+interface FileCallBack {
+  name: string;
+  file: Blob;
+  filename: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/role/index.ts b/eims-ui/apps/web-antd/src/api/system/role/index.ts
new file mode 100644
index 0000000..6382fa0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/role/index.ts
@@ -0,0 +1,123 @@
+import type { DeptResp, Role } from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  roleAllocatedList = '/system/role/authUser/allocatedList',
+  roleAuthCancel = '/system/role/authUser/cancel',
+  roleAuthCancelAll = '/system/role/authUser/cancelAll',
+  roleAuthSelectAll = '/system/role/authUser/selectAll',
+  roleChangeStatus = '/system/role/changeStatus',
+  roleDataScope = '/system/role/dataScope',
+  roleDeptTree = '/system/role/deptTree',
+  roleExport = '/system/role/export',
+  roleList = '/system/role/list',
+  roleOptionSelect = '/system/role/optionselect',
+  roleUnallocatedList = '/system/role/authUser/unallocatedList',
+  root = '/system/role',
+}
+
+export function roleList(params?: PageQuery) {
+  return requestClient.get<PageResult<Role>>(Api.roleList, { params });
+}
+
+export function roleExport(data: any) {
+  return commonExport(Api.roleExport, data);
+}
+
+export function roleInfo(roleId: ID) {
+  return requestClient.get<Role>(`${Api.root}/${roleId}`);
+}
+
+export function roleAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function roleUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function roleChangeStatus(data: any) {
+  return requestClient.putWithMsg<void>(Api.roleChangeStatus, data);
+}
+
+export function roleRemove(roleIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${roleIds}`);
+}
+
+/**
+ * 鏇存柊鏁版嵁鏉冮檺
+ * @param data
+ * @returns void
+ */
+export function roleDataScope(data: any) {
+  return requestClient.putWithMsg<void>(Api.roleDataScope, data);
+}
+
+export function roleOptionSelect(params?: any) {
+  return requestClient.get(Api.roleOptionSelect, { params });
+}
+
+export function roleAllocatedList(params: any) {
+  return requestClient.get(Api.roleAllocatedList, { params });
+}
+
+/**
+ * 鏈巿鏉冪殑鐢ㄦ埛
+ * @param params
+ * @returns void
+ */
+export function roleUnallocatedList(params: any) {
+  return requestClient.get(Api.roleUnallocatedList, { params });
+}
+
+/**
+ * 鍙栨秷鎺堟潈
+ * @param data {userId: 2, roleId: "2"}
+ * @returns void
+ */
+export function roleAuthCancel(data: any) {
+  return requestClient.putWithMsg<void>(Api.roleAuthCancel, data);
+}
+
+/**
+ * 鎵归噺鍙栨秷鎺堟潈
+ * @param roleId
+ * @param userIds
+ * @returns void
+ */
+export function roleAuthCancelAll(
+  roleId: number | string,
+  userIds: number[] | string[],
+) {
+  return requestClient.putWithMsg<void>(
+    `${Api.roleAuthCancelAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
+  );
+}
+
+/**
+ * 鎵归噺鎺堟潈鐢ㄦ埛
+ * @param roleId
+ * @param userIds
+ * @returns void
+ */
+export function roleSelectAll(
+  roleId: number | string,
+  userIds: number[] | string[],
+) {
+  return requestClient.putWithMsg<void>(
+    `${Api.roleAuthSelectAll}?roleId=${roleId}&userIds=${userIds.join(',')}`,
+  );
+}
+
+/**
+ * 閮ㄩ棬鏍�
+ * @param roleId 瑙掕壊id
+ * @returns DeptResp
+ */
+export function roleDeptTree(roleId: ID) {
+  return requestClient.get<DeptResp>(`${Api.roleDeptTree}/${roleId}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/role/model.d.ts b/eims-ui/apps/web-antd/src/api/system/role/model.d.ts
new file mode 100644
index 0000000..35aab96
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/role/model.d.ts
@@ -0,0 +1,29 @@
+export interface Role {
+  roleId: number;
+  roleName: string;
+  roleKey: string;
+  roleSort: number;
+  dataScope: string;
+  menuCheckStrictly: boolean;
+  deptCheckStrictly: boolean;
+  status: string;
+  remark: string;
+  createTime: string;
+  // 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦�
+  flag: boolean;
+  superAdmin: boolean;
+}
+
+export interface DeptOption {
+  id: number;
+  parentId: number;
+  label: string;
+  weight: number;
+  children: DeptOption[];
+  key: string; // 瀹為檯涓婁笉瀛樺湪 ide鎶ラ敊
+}
+
+export interface DeptResp {
+  checkedKeys: number[];
+  depts: DeptOption[];
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/social/index.ts b/eims-ui/apps/web-antd/src/api/system/social/index.ts
new file mode 100644
index 0000000..7c50ed3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/social/index.ts
@@ -0,0 +1,20 @@
+import type { SocialInfo } from './model';
+
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/system/social',
+  socialList = '/system/social/list',
+}
+
+/**
+ * 鑾峰彇缁戝畾鐨勭ぞ浜や俊鎭垪琛�
+ * @returns info
+ */
+export function socialList() {
+  return requestClient.get<SocialInfo[]>(Api.socialList);
+}
+
+export function socialInfo(id: number | string) {
+  return requestClient.get(`${Api.root}/${id}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/social/model.d.ts b/eims-ui/apps/web-antd/src/api/system/social/model.d.ts
new file mode 100644
index 0000000..1e3b015
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/social/model.d.ts
@@ -0,0 +1,26 @@
+export interface SocialInfo {
+  id: string;
+  userId: number;
+  tenantId: string;
+  authId: string;
+  source: string;
+  accessToken: string;
+  expireIn: number;
+  refreshToken: string;
+  openId: string;
+  userName: string;
+  nickName: string;
+  email: string;
+  avatar: string;
+  accessCode?: any;
+  unionId?: any;
+  scope: string;
+  tokenType: string;
+  idToken?: any;
+  macAlgorithm?: any;
+  macKey?: any;
+  code?: any;
+  oauthToken?: any;
+  oauthTokenSecret?: any;
+  createTime: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/tenant-package/index.ts b/eims-ui/apps/web-antd/src/api/system/tenant-package/index.ts
new file mode 100644
index 0000000..1851a7b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/tenant-package/index.ts
@@ -0,0 +1,49 @@
+import type { TenantPackage } from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  packageChangeStatus = '/system/tenant/package/changeStatus',
+  packageExport = '/system/tenant/package/export',
+  packageList = '/system/tenant/package/list',
+  packageSelectList = '/system/tenant/package/selectList',
+  root = '/system/tenant/package',
+}
+
+export function packageList(params?: PageQuery) {
+  return requestClient.get<PageResult<TenantPackage>>(Api.packageList, {
+    params,
+  });
+}
+
+// 涓嬫媺妗�
+export function packageSelectList() {
+  return requestClient.get<TenantPackage[]>(Api.packageSelectList);
+}
+
+export function packageExport(data: any) {
+  return commonExport(Api.packageExport, data);
+}
+
+export function packageInfo(id: ID) {
+  return requestClient.get<TenantPackage>(`${Api.root}/${id}`);
+}
+
+export function packageAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+export function packageUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function packageChangeStatus(data: any) {
+  return requestClient.putWithMsg(Api.packageChangeStatus, data);
+}
+
+export function packageRemove(ids: IDS) {
+  return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/tenant-package/model.d.ts b/eims-ui/apps/web-antd/src/api/system/tenant-package/model.d.ts
new file mode 100644
index 0000000..eb3af09
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/tenant-package/model.d.ts
@@ -0,0 +1,17 @@
+/**
+ * @description 绉熸埛濂楅
+ * @param packageId id
+ * @param packageName 鍚嶇О
+ * @param menuIds 鑿滃崟id  鏍煎紡涓篬1,2,3] 杩斿洖涓簊tring 鎻愪氦涓烘暟缁�
+ * @param remark 澶囨敞
+ * @param menuCheckStrictly 鏄惁鍏宠仈鐖惰妭鐐�
+ * @param status 鐘舵��
+ */
+export interface TenantPackage {
+  packageId: string;
+  packageName: string;
+  menuIds: number[] | string;
+  remark: string;
+  menuCheckStrictly: boolean;
+  status: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/tenant/index.ts b/eims-ui/apps/web-antd/src/api/system/tenant/index.ts
new file mode 100644
index 0000000..f5c6505
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/tenant/index.ts
@@ -0,0 +1,97 @@
+import type { Tenant } from './model';
+
+import type { ID, IDS, PageQuery } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  dictSync = '/system/tenant/syncTenantDict',
+  root = '/system/tenant',
+  tenantDynamic = '/system/tenant/dynamic',
+  tenantDynamicClear = '/system/tenant/dynamic/clear',
+  tenantExport = '/system/tenant/export',
+  tenantList = '/system/tenant/list',
+  tenantStatus = '/system/tenant/changeStatus',
+  tenantSyncPackage = '/system/tenant/syncTenantPackage',
+}
+
+export function tenantList(params?: PageQuery) {
+  return requestClient.get<Tenant[]>(Api.tenantList, { params });
+}
+
+export function tenantExport(data: any) {
+  return commonExport(Api.tenantExport, data);
+}
+
+export function tenantInfo(id: ID) {
+  return requestClient.get<Tenant>(`${Api.root}/${id}`);
+}
+
+/**
+ * 鏂板绉熸埛 蹇呴』寮�鍚姞瀵�
+ * @param data data
+ * @returns void
+ */
+export function tenantAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data, { encrypt: true });
+}
+
+export function tenantUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+export function tenantStatusChange(data: any) {
+  return requestClient.putWithMsg(Api.tenantStatus, data);
+}
+
+export function tenantRemove(ids: IDS) {
+  return requestClient.deleteWithMsg(`${Api.root}/${ids}`);
+}
+
+/**
+ * 鍔ㄦ�佸垏鎹㈢鎴�
+ * @param tenantId 绉熸埛ID
+ * @returns void
+ */
+export function tenantDynamicToggle(tenantId: string) {
+  return requestClient.get<void>(`${Api.tenantDynamic}/${tenantId}`);
+}
+
+/**
+ * 娓呴櫎 鍔ㄦ�佸垏鎹㈢鎴�
+ * @returns void
+ */
+export function tenantDynamicClear() {
+  return requestClient.get<void>(Api.tenantDynamicClear);
+}
+
+/**
+ * 绉熸埛濂楅鍚屾
+ * @param tenantId 绉熸埛id
+ * @param packageId 濂楅id
+ * @param showMsg 鏄惁鏄剧ず鎴愬姛淇℃伅
+ * @returns void
+ */
+export function tenantSyncPackage(
+  tenantId: string,
+  packageId: string,
+  showMsg = true,
+) {
+  return requestClient.get<void>(Api.tenantSyncPackage, {
+    params: { packageId, tenantId },
+    successMessageMode: showMsg ? 'message' : 'none',
+  });
+}
+
+/**
+ * 鍚屾绉熸埛瀛楀吀
+ * @param tenantId 绉熸埛ID
+ * @returns void
+ */
+export function dictSyncTenant(tenantId?: string) {
+  return requestClient.get<void>(Api.dictSync, {
+    params: { tenantId },
+    successMessageMode: 'message',
+  });
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/tenant/model.d.ts b/eims-ui/apps/web-antd/src/api/system/tenant/model.d.ts
new file mode 100644
index 0000000..309ad58
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/tenant/model.d.ts
@@ -0,0 +1,16 @@
+export interface Tenant {
+  accountCount: number;
+  address?: string;
+  companyName: string;
+  contactPhone: string;
+  contactUserName: string;
+  domain?: string;
+  expireTime?: string;
+  id: number;
+  intro: string;
+  licenseNumber?: any;
+  packageId?: string;
+  remark?: string;
+  status: string;
+  tenantId: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/user/index.ts b/eims-ui/apps/web-antd/src/api/system/user/index.ts
new file mode 100644
index 0000000..ff2a3d5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/user/index.ts
@@ -0,0 +1,167 @@
+import type {
+  DeptTree,
+  ResetPwdParam,
+  User,
+  UserImportParam,
+  UserInfoResponse,
+} from './model';
+
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
+
+import { commonExport, ContentTypeEnum } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  deptTree = '/system/user/deptTree',
+  listDeptUsers = '/system/user/list/dept',
+  root = '/system/user',
+  userAuthRole = '/system/user/authRole',
+  userExport = '/system/user/export',
+  userImport = '/system/user/importData',
+  userImportTemplate = '/system/user/importTemplate',
+  userList = '/system/user/list',
+  userResetPassword = '/system/user/resetPwd',
+  userStatusChange = '/system/user/changeStatus',
+}
+
+/**
+ *  鑾峰彇鐢ㄦ埛鍒楄〃
+ * @param params
+ * @returns User
+ */
+export function userList(params?: PageQuery) {
+  return requestClient.get<PageResult<User>>(Api.userList, { params });
+}
+
+/**
+ * 瀵煎嚭excel
+ * @param data data
+ * @returns blob
+ */
+export function userExport(data: any) {
+  return commonExport(Api.userExport, data);
+}
+
+/**
+ * 浠巈xcel瀵煎叆鐢ㄦ埛
+ * @param data
+ * @returns void
+ */
+export function userImportData(data: UserImportParam) {
+  return requestClient.post<{ code: number; msg: string }>(
+    Api.userImport,
+    data,
+    {
+      headers: {
+        'Content-Type': ContentTypeEnum.FORM_DATA,
+      },
+      isTransformResponse: false,
+    },
+  );
+}
+
+/**
+ * 涓嬭浇鐢ㄦ埛瀵煎叆妯℃澘
+ * @returns blob
+ */
+export function downloadImportTemplate() {
+  return requestClient.post<Blob>(
+    Api.userImportTemplate,
+    {},
+    {
+      isTransformResponse: false,
+      responseType: 'blob',
+    },
+  );
+}
+
+/**
+ * 鍙互涓嶄紶ID  杩斿洖閮ㄩ棬鍜岃鑹瞣ptions 闇�瑕佽幏寰楀師濮嬫暟鎹�
+ * 涓嶄紶ID鏃朵竴瀹氳甯︽渶鍚庣殑/
+ * @param userId 鐢ㄦ埛ID
+ * @returns 鐢ㄦ埛淇℃伅
+ */
+export function findUserInfo(userId?: ID) {
+  const url = userId ? `${Api.root}/${userId}` : `${Api.root}/`;
+  return requestClient.get<UserInfoResponse>(url);
+}
+
+/**
+ * 鏂板鐢ㄦ埛
+ * @param data data
+ * @returns void
+ */
+export function userAdd(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鏇存柊鐢ㄦ埛
+ * @param data data
+ * @returns void
+ */
+export function userUpdate(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鏇存柊鐢ㄦ埛鐘舵��
+ * @param data data
+ * @returns void
+ */
+export function userStatusChange(data: any) {
+  return requestClient.putWithMsg<void>(Api.userStatusChange, data);
+}
+
+/**
+ * 鍒犻櫎鐢ㄦ埛
+ * @param userIds 鐢ㄦ埛ID鏁扮粍
+ * @returns void
+ */
+export function userRemove(userIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${userIds}`);
+}
+
+/**
+ * 閲嶇疆鐢ㄦ埛瀵嗙爜 闇�瑕佸姞瀵�
+ * @param data
+ * @returns void
+ */
+export function userResetPassword(data: ResetPwdParam) {
+  return requestClient.putWithMsg<void>(Api.userResetPassword, data, {
+    encrypt: true,
+  });
+}
+
+/**
+ * 杩欎釜鏂规硶鏈皟鐢ㄨ繃
+ * @param userId
+ * @returns void
+ */
+export function getUserAuthRole(userId: ID) {
+  return requestClient.get(`${Api.userAuthRole}/${userId}`);
+}
+
+/**
+ * 杩欎釜鏂规硶鏈皟鐢ㄨ繃
+ * @param userId
+ * @returns void
+ */
+export function userAuthRoleUpdate(userId: ID, roleIds: number[]) {
+  return requestClient.putWithMsg(Api.userAuthRole, { roleIds, userId });
+}
+
+/**
+ * 鑾峰彇閮ㄩ棬鏍�
+ * @returns 閮ㄩ棬鏍戞暟缁�
+ */
+export function getDeptTree() {
+  return requestClient.get<DeptTree[]>(Api.deptTree);
+}
+
+/**
+ * 鑾峰彇閮ㄩ棬涓嬬殑鎵�鏈夌敤鎴蜂俊鎭�
+ */
+export function listUserByDeptId(deptId: ID) {
+  return requestClient.get<User[]>(`${Api.listDeptUsers}/${deptId}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/system/user/model.d.ts b/eims-ui/apps/web-antd/src/api/system/user/model.d.ts
new file mode 100644
index 0000000..273b106
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/system/user/model.d.ts
@@ -0,0 +1,116 @@
+/**
+ * @description: 鐢ㄦ埛瀵煎叆
+ * @param updateSupport 鏄惁瑕嗙洊鏁版嵁
+ * @param file excel鏂囦欢
+ */
+export interface UserImportParam {
+  updateSupport: boolean;
+  file: Blob | File;
+}
+
+/**
+ * @description: 閲嶇疆瀵嗙爜
+ */
+export interface ResetPwdParam {
+  userId: string;
+  password: string;
+}
+
+export interface Dept {
+  deptId: number;
+  parentId: number;
+  parentName?: string;
+  ancestors: string;
+  deptName: string;
+  orderNum: number;
+  leader: string;
+  phone?: string;
+  email?: string;
+  status: string;
+  createTime?: string;
+}
+
+export interface Role {
+  roleId: string;
+  roleName: string;
+  roleKey: string;
+  roleSort: number;
+  dataScope: string;
+  menuCheckStrictly?: boolean;
+  deptCheckStrictly?: boolean;
+  status: string;
+  remark: string;
+  createTime?: string;
+  flag: boolean;
+  superAdmin: boolean;
+}
+
+export interface User {
+  userId: string;
+  tenantId: string;
+  deptId: number;
+  userName: string;
+  nickName: string;
+  userType: string;
+  email: string;
+  phonenumber: string;
+  sex: string;
+  avatar?: string;
+  status: string;
+  loginIp: string;
+  loginDate: string;
+  remark: string;
+  createTime: string;
+  dept: Dept;
+  roles: Role[];
+  roleIds?: string[];
+  postIds?: number[];
+  roleId: string;
+}
+
+export interface Post {
+  postId: number;
+  postCode: string;
+  postName: string;
+  postSort: number;
+  status: string;
+  remark: string;
+  createTime: string;
+}
+
+/**
+ * @description 鐢ㄦ埛淇℃伅
+ * @param user 鐢ㄦ埛涓汉淇℃伅
+ * @param roleIds 瑙掕壊IDS 涓嶄紶id涓虹┖
+ * @param roles 鎵�鏈夌殑瑙掕壊
+ * @param postIds 宀椾綅IDS 涓嶄紶id涓虹┖
+ * @param posts 鎵�鏈夌殑宀椾綅
+ */
+export interface UserInfoResponse {
+  user?: User;
+  roleIds?: string[];
+  roles: Role[];
+  postIds?: number[];
+  posts?: Post[];
+}
+
+/**
+ * @description: 閮ㄩ棬鏍�
+ */
+export interface DeptTree {
+  id: number;
+  /**
+   * antd缁勪欢蹇呴』瑕佽繖涓睘鎬� 瀹為檯鏄病鏈夎繖涓睘鎬х殑
+   */
+  key: string;
+  parentId: number;
+  label: string;
+  weight: number;
+  children?: DeptTree[];
+}
+
+export interface DeptTreeData {
+  id: number;
+  label: string;
+  children?: DeptTreeData[];
+}
diff --git a/eims-ui/apps/web-antd/src/api/tool/gen/index.ts b/eims-ui/apps/web-antd/src/api/tool/gen/index.ts
new file mode 100644
index 0000000..0514d3e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/tool/gen/index.ts
@@ -0,0 +1,102 @@
+import type { GenInfo } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { ContentTypeEnum } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  batchGenCode = '/tool/gen/batchGenCode',
+  columnList = '/tool/gen/column',
+  dataSourceNames = '/tool/gen/getDataNames',
+  download = '/tool/gen/download',
+  genCode = '/tool/gen/genCode',
+  generatedList = '/tool/gen/list',
+  importTable = '/tool/gen/importTable',
+  preview = '/tool/gen/preview',
+  readyToGenList = '/tool/gen/db/list',
+  root = '/tool/gen',
+  syncDb = '/tool/gen/synchDb',
+}
+// 鏌ヨ浠g爜鐢熸垚鍒楄〃
+export function generatedList(params: any) {
+  return requestClient.get(Api.generatedList, { params });
+}
+
+// 淇敼浠g爜鐢熸垚涓氬姟
+export function genInfo(tableId: ID) {
+  return requestClient.get<GenInfo>(`${Api.root}/${tableId}`);
+}
+
+// 鏌ヨ鏁版嵁搴撳垪琛�
+export function readyToGenList(params: any) {
+  return requestClient.get(Api.readyToGenList, { params });
+}
+
+// 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
+export function columnList(tableId: ID) {
+  return requestClient.get(`${Api.columnList}/${tableId}`);
+}
+
+/**
+ * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
+ * @param tables table鍚嶇О鏁扮粍 濡俿ys_a, sys_b
+ * @param dataName 鏁版嵁婧愬悕绉�
+ * @returns ret
+ */
+export function importTable(tables: string | string[], dataName: string) {
+  return requestClient.postWithMsg(
+    Api.importTable,
+    { dataName, tables },
+    {
+      headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
+    },
+  );
+}
+
+// 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+export function editSave(data: any) {
+  return requestClient.putWithMsg(Api.root, data);
+}
+
+// 鍒犻櫎浠g爜鐢熸垚
+export function genRemove(tableIds: IDS) {
+  return requestClient.deleteWithMsg(`${Api.root}/${tableIds}`);
+}
+// 棰勮浠g爜
+export function previewCode(tableId: ID) {
+  return requestClient.get<{ [key: string]: string }>(
+    `${Api.preview}/${tableId}`,
+  );
+}
+
+// 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+export function genDownload(tableId: ID) {
+  return requestClient.get<Blob>(`${Api.download}/${tableId}`);
+}
+
+// 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+export function genDownloadWithPath(tableId: ID) {
+  return requestClient.get(`${Api.download}/${tableId}`);
+}
+
+// 鍚屾鏁版嵁搴�
+export function syncDb(tableId: ID) {
+  return requestClient.get(`${Api.syncDb}/${tableId}`, {
+    successMessageMode: 'message',
+  });
+}
+
+// 鎵归噺鐢熸垚浠g爜
+export function batchGenCode(tableIdStr: ID | IDS) {
+  return requestClient.get<Blob>(Api.batchGenCode, {
+    isTransformResponse: false,
+    params: { tableIdStr },
+    responseType: 'blob',
+  });
+}
+
+// 鏌ヨ鏁版嵁婧愬悕绉板垪琛�
+export function getDataSourceNames() {
+  return requestClient.get<string[]>(Api.dataSourceNames);
+}
diff --git a/eims-ui/apps/web-antd/src/api/tool/gen/model.d.ts b/eims-ui/apps/web-antd/src/api/tool/gen/model.d.ts
new file mode 100644
index 0000000..d5012c0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/tool/gen/model.d.ts
@@ -0,0 +1,186 @@
+export interface Column {
+  createDept?: any;
+  createBy?: any;
+  createTime?: any;
+  updateBy?: any;
+  updateTime?: any;
+  columnId: string;
+  tableId: string;
+  columnName: string;
+  columnComment: string;
+  columnType: string;
+  javaType: string;
+  javaField: string;
+  isPk: string;
+  isIncrement: string;
+  isRequired: string;
+  isInsert?: any;
+  isEdit: string;
+  isList: string;
+  isQuery?: any;
+  queryType: string;
+  htmlType: string;
+  dictType: string;
+  sort: number;
+  list: boolean;
+  required: boolean;
+  pk: boolean;
+  insert: boolean;
+  edit: boolean;
+  usableColumn: boolean;
+  superColumn: boolean;
+  increment: boolean;
+  query: boolean;
+  capJavaField: string;
+}
+
+export interface Table {
+  createDept?: any;
+  createBy?: any;
+  createTime?: any;
+  updateBy?: any;
+  updateTime?: any;
+  tableId: string;
+  dataName: string;
+  tableName: string;
+  tableComment: string;
+  subTableName?: any;
+  subTableFkName?: any;
+  className: string;
+  tplCategory: string;
+  packageName: string;
+  moduleName: string;
+  businessName: string;
+  functionName: string;
+  functionAuthor: string;
+  genType?: any;
+  genPath?: any;
+  pkColumn?: any;
+  columns: Column[];
+  options?: any;
+  remark?: any;
+  treeCode?: any;
+  treeParentCode?: any;
+  treeName?: any;
+  menuIds?: any;
+  parentMenuId?: any;
+  parentMenuName?: any;
+  tree: boolean;
+  crud: boolean;
+}
+
+export interface Row {
+  createDept: number;
+  createBy: number;
+  createTime: string;
+  updateBy: number;
+  updateTime: string;
+  columnId: string;
+  tableId: string;
+  columnName: string;
+  columnComment: string;
+  columnType: string;
+  javaType: string;
+  javaField: string;
+  isPk: string;
+  isIncrement: string;
+  isRequired: string;
+  isInsert?: any;
+  isEdit: string;
+  isList: string;
+  isQuery?: any;
+  queryType: string;
+  htmlType: string;
+  dictType: string;
+  sort: number;
+  list: boolean;
+  required: boolean;
+  pk: boolean;
+  insert: boolean;
+  edit: boolean;
+  usableColumn: boolean;
+  superColumn: boolean;
+  increment: boolean;
+  query: boolean;
+  capJavaField: string;
+}
+
+export interface Column {
+  createDept?: any;
+  createBy?: any;
+  createTime?: any;
+  updateBy?: any;
+  updateTime?: any;
+  columnId: string;
+  tableId: string;
+  columnName: string;
+  columnComment: string;
+  columnType: string;
+  javaType: string;
+  javaField: string;
+  isPk: string;
+  isIncrement: string;
+  isRequired: string;
+  isInsert?: any;
+  isEdit: string;
+  isList: string;
+  isQuery?: any;
+  queryType: string;
+  htmlType: string;
+  dictType: string;
+  sort: number;
+  list: boolean;
+  required: boolean;
+  pk: boolean;
+  insert: boolean;
+  edit: boolean;
+  usableColumn: boolean;
+  superColumn: boolean;
+  increment: boolean;
+  query: boolean;
+  capJavaField: string;
+}
+
+export interface Info {
+  createDept?: any;
+  createBy?: any;
+  createTime?: any;
+  updateBy?: any;
+  updateTime?: any;
+  tableId: string;
+  dataName: string;
+  tableName: string;
+  tableComment: string;
+  subTableName?: any;
+  subTableFkName?: any;
+  className: string;
+  tplCategory: string;
+  packageName: string;
+  moduleName: string;
+  businessName: string;
+  functionName: string;
+  functionAuthor: string;
+  genType: string;
+  genPath: string;
+  pkColumn?: any;
+  columns: Column[];
+  options?: any;
+  remark?: any;
+  treeCode?: any;
+  treeParentCode?: any;
+  treeName?: any;
+  menuIds?: any;
+  parentMenuId?: any;
+  parentMenuName?: any;
+  tree: boolean;
+  crud: boolean;
+  // 鏍戣〃闇�瑕佹坊鍔犳灞炴��
+  params?: any;
+  popupComponent?: string;
+}
+
+export interface GenInfo {
+  tables: Table[];
+  rows: Row[];
+  info: Info;
+}
diff --git a/eims-ui/apps/web-antd/src/api/workflow/category/index.ts b/eims-ui/apps/web-antd/src/api/workflow/category/index.ts
new file mode 100644
index 0000000..3497c74
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/workflow/category/index.ts
@@ -0,0 +1,50 @@
+import type { CategoryForm, CategoryQuery, CategoryVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
+ * @param params
+ * @returns 娴佺▼鍒嗙被鍒楄〃
+ */
+export function categoryList(params?: CategoryQuery) {
+  return requestClient.get<CategoryVO[]>(`/workflow/category/list`, { params });
+}
+
+/**
+ * 鏌ヨ娴佺▼鍒嗙被璇︽儏
+ * @param id id
+ * @returns 娴佺▼鍒嗙被璇︽儏
+ */
+export function categoryInfo(id: ID) {
+  return requestClient.get<CategoryVO>(`/workflow/category/${id}`);
+}
+
+/**
+ * 鏂板娴佺▼鍒嗙被
+ * @param data
+ * @returns void
+ */
+export function categoryAdd(data: CategoryForm) {
+  return requestClient.postWithMsg<void>('/workflow/category', data);
+}
+
+/**
+ * 鏇存柊娴佺▼鍒嗙被
+ * @param data
+ * @returns void
+ */
+export function categoryUpdate(data: CategoryForm) {
+  return requestClient.putWithMsg<void>('/workflow/category', data);
+}
+
+/**
+ * 鍒犻櫎娴佺▼鍒嗙被
+ * @param id id
+ * @returns void
+ */
+export function categoryRemove(id: ID | IDS) {
+  return requestClient.deleteWithMsg<void>(`/workflow/category/${id}`);
+}
diff --git a/eims-ui/apps/web-antd/src/api/workflow/category/model.d.ts b/eims-ui/apps/web-antd/src/api/workflow/category/model.d.ts
new file mode 100644
index 0000000..87937ec
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/workflow/category/model.d.ts
@@ -0,0 +1,87 @@
+import type { BaseEntity } from '#/api/common';
+
+export interface CategoryVO {
+  /**
+   * 涓婚敭
+   */
+  id: number | string;
+
+  /**
+   * 鍒嗙被鍚嶇О
+   */
+  categoryName: string;
+
+  /**
+   * 鍒嗙被缂栫爜
+   */
+  categoryCode: string;
+
+  /**
+   * 鐖剁骇id
+   */
+  parentId: number | string;
+
+  /**
+   * 鎺掑簭
+   */
+  sortNum: number;
+
+  /**
+   * 瀛愬璞�
+   */
+  children: CategoryVO[];
+}
+
+export interface CategoryForm extends BaseEntity {
+  /**
+   * 涓婚敭
+   */
+  id?: number | string;
+
+  /**
+   * 鍒嗙被鍚嶇О
+   */
+  categoryName?: string;
+
+  /**
+   * 鍒嗙被缂栫爜
+   */
+  categoryCode?: string;
+
+  /**
+   * 鐖剁骇id
+   */
+  parentId?: number | string;
+
+  /**
+   * 鎺掑簭
+   */
+  sortNum?: number;
+}
+
+export interface CategoryQuery {
+  /**
+   * 鍒嗙被鍚嶇О
+   */
+  categoryName?: string;
+
+  /**
+   * 鍒嗙被缂栫爜
+   */
+  categoryCode?: string;
+
+  /**
+   * 鐖剁骇id
+   */
+  parentId?: number | string;
+
+  /**
+   * 鎺掑簭
+   */
+  sortNum?: number;
+
+  /**
+   * 鏃ユ湡鑼冨洿鍙傛暟
+   */
+  params?: any;
+}
diff --git a/eims-ui/apps/web-antd/src/app.vue b/eims-ui/apps/web-antd/src/app.vue
new file mode 100644
index 0000000..bbaccce
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/app.vue
@@ -0,0 +1,39 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { useAntdDesignTokens } from '@vben/hooks';
+import { preferences, usePreferences } from '@vben/preferences';
+
+import { App, ConfigProvider, theme } from 'ant-design-vue';
+
+import { antdLocale } from '#/locales';
+
+defineOptions({ name: 'App' });
+
+const { isDark } = usePreferences();
+const { tokens } = useAntdDesignTokens();
+
+const tokenTheme = computed(() => {
+  const algorithm = isDark.value
+    ? [theme.darkAlgorithm]
+    : [theme.defaultAlgorithm];
+
+  // antd 绱у噾妯″紡绠楁硶
+  if (preferences.app.compact) {
+    algorithm.push(theme.compactAlgorithm);
+  }
+
+  return {
+    algorithm,
+    token: tokens,
+  };
+});
+</script>
+
+<template>
+  <ConfigProvider :locale="antdLocale" :theme="tokenTheme">
+    <App>
+      <RouterView />
+    </App>
+  </ConfigProvider>
+</template>
diff --git a/eims-ui/apps/web-antd/src/assets/img/img-lower-limit.png b/eims-ui/apps/web-antd/src/assets/img/img-lower-limit.png
new file mode 100644
index 0000000..9a53083
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/assets/img/img-lower-limit.png
Binary files differ
diff --git a/eims-ui/apps/web-antd/src/assets/img/img-up-limit.png b/eims-ui/apps/web-antd/src/assets/img/img-up-limit.png
new file mode 100644
index 0000000..cd260c9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/assets/img/img-up-limit.png
Binary files differ
diff --git a/eims-ui/apps/web-antd/src/assets/logo.png b/eims-ui/apps/web-antd/src/assets/logo.png
new file mode 100644
index 0000000..fd0c6ba
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/assets/logo.png
Binary files differ
diff --git a/eims-ui/apps/web-antd/src/bootstrap.ts b/eims-ui/apps/web-antd/src/bootstrap.ts
new file mode 100644
index 0000000..f842021
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/bootstrap.ts
@@ -0,0 +1,52 @@
+import { createApp, watchEffect } from 'vue';
+
+import { registerAccessDirective } from '@vben/access';
+import { preferences } from '@vben/preferences';
+import { initStores } from '@vben/stores';
+import '@vben/styles';
+import '@vben/styles/antd';
+
+import { useTitle } from '@vueuse/core';
+
+import { setupGlobalComponent } from '#/components/global';
+import { $t, setupI18n } from '#/locales';
+
+import { initComponentAdapter } from './adapter/component';
+import App from './app.vue';
+import { router } from './router';
+
+async function bootstrap(namespace: string) {
+  // 鍒濆鍖栫粍浠堕�傞厤鍣�
+  await initComponentAdapter();
+
+  const app = createApp(App);
+
+  // 鍏ㄥ眬缁勪欢
+  setupGlobalComponent(app);
+
+  // 鍥介檯鍖� i18n 閰嶇疆
+  await setupI18n(app);
+
+  // 閰嶇疆 pinia-tore
+  await initStores(app, { namespace });
+
+  // 瀹夎鏉冮檺鎸囦护
+  registerAccessDirective(app);
+
+  // 閰嶇疆璺敱鍙婅矾鐢卞畧鍗�
+  app.use(router);
+
+  // 鍔ㄦ�佹洿鏂版爣棰�
+  watchEffect(() => {
+    if (preferences.app.dynamicTitle) {
+      const routeTitle = router.currentRoute.value.meta?.title;
+      const pageTitle =
+        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
+      useTitle(pageTitle);
+    }
+  });
+
+  app.mount('#app');
+}
+
+export { bootstrap };
diff --git a/eims-ui/apps/web-antd/src/components/cropper/index.ts b/eims-ui/apps/web-antd/src/components/cropper/index.ts
new file mode 100644
index 0000000..b74a127
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/cropper/index.ts
@@ -0,0 +1,4 @@
+export { default as CropperImage } from './src/cropper.vue';
+
+export { default as CropperAvatar } from './src/cropper-avatar.vue';
+export type { Cropper } from './src/typing';
diff --git a/eims-ui/apps/web-antd/src/components/cropper/src/cropper-avatar.vue b/eims-ui/apps/web-antd/src/components/cropper/src/cropper-avatar.vue
new file mode 100644
index 0000000..5e17d2f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/cropper/src/cropper-avatar.vue
@@ -0,0 +1,174 @@
+<script lang="ts" setup>
+import {
+  computed,
+  type CSSProperties,
+  type PropType,
+  ref,
+  unref,
+  watch,
+  watchEffect,
+} from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t as t } from '@vben/locales';
+
+import { type ButtonProps, message } from 'ant-design-vue';
+
+import cropperModal from './cropper-modal.vue';
+
+defineOptions({ name: 'CropperAvatar' });
+
+const props = defineProps({
+  btnProps: { default: () => ({}), type: Object as PropType<ButtonProps> },
+  btnText: { default: '', type: String },
+  showBtn: { default: true, type: Boolean },
+  size: { default: 5, type: Number },
+  uploadApi: {
+    required: true,
+    type: Function as PropType<
+      ({
+        file,
+        filename,
+        name,
+      }: {
+        file: Blob;
+        filename: string;
+        name: string;
+      }) => Promise<any>
+    >,
+  },
+  value: { default: '', type: String },
+
+  width: { default: '200px', type: [String, Number] },
+});
+
+const emit = defineEmits(['update:value', 'change']);
+
+const sourceValue = ref(props.value || '');
+const prefixCls = 'cropper-avatar';
+const [CropperModal, modalApi] = useVbenModal({
+  connectedComponent: cropperModal,
+});
+
+const getClass = computed(() => [prefixCls]);
+
+const getWidth = computed(() => `${`${props.width}`.replace(/px/, '')}px`);
+
+const getIconWidth = computed(
+  () => `${Number.parseInt(`${props.width}`.replace(/px/, '')) / 2}px`,
+);
+
+const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
+
+const getImageWrapperStyle = computed(
+  (): CSSProperties => ({ height: unref(getWidth), width: unref(getWidth) }),
+);
+
+watchEffect(() => {
+  sourceValue.value = props.value || '';
+});
+
+watch(
+  () => sourceValue.value,
+  (v: string) => {
+    emit('update:value', v);
+  },
+);
+
+function handleUploadSuccess({ data, source }: any) {
+  sourceValue.value = source;
+  emit('change', { data, source });
+  message.success(t('component.cropper.uploadSuccess'));
+}
+
+const closeModal = () => modalApi.close();
+const openModal = () => modalApi.open();
+
+defineExpose({
+  closeModal,
+  openModal,
+});
+</script>
+<template>
+  <div :class="getClass" :style="getStyle">
+    <div
+      :class="`${prefixCls}-image-wrapper`"
+      :style="getImageWrapperStyle"
+      @click="openModal"
+    >
+      <div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
+        <span
+          :style="{
+            ...getImageWrapperStyle,
+            width: `${getIconWidth}`,
+            height: `${getIconWidth}`,
+            lineHeight: `${getIconWidth}`,
+          }"
+          class="icon-[ant-design--cloud-upload-outlined] text-[#d6d6d6]"
+        ></span>
+      </div>
+      <img v-if="sourceValue" :src="sourceValue" alt="avatar" />
+    </div>
+    <a-button
+      v-if="showBtn"
+      :class="`${prefixCls}-upload-btn`"
+      @click="openModal"
+      v-bind="btnProps"
+    >
+      {{ btnText ? btnText : t('component.cropper.selectImage') }}
+    </a-button>
+
+    <CropperModal
+      :size="size"
+      :src="sourceValue"
+      :upload-api="uploadApi"
+      @upload-success="handleUploadSuccess"
+    />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.cropper-avatar {
+  display: inline-block;
+  text-align: center;
+
+  &-image-wrapper {
+    overflow: hidden;
+    cursor: pointer;
+    background: #fff;
+    border: 1px solid #eee;
+    border-radius: 50%;
+
+    img {
+      width: 100%;
+    }
+  }
+
+  &-image-mask {
+    position: absolute;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: inherit;
+    height: inherit;
+    cursor: pointer;
+    background: rgb(0 0 0 / 40%);
+    border: inherit;
+    border-radius: inherit;
+    opacity: 0;
+    transition: opacity 0.4s;
+
+    ::v-deep(svg) {
+      margin: auto;
+    }
+  }
+
+  &-image-mask:hover {
+    opacity: 40;
+  }
+
+  &-upload-btn {
+    margin: 10px auto;
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/cropper/src/cropper-modal.vue b/eims-ui/apps/web-antd/src/components/cropper/src/cropper-modal.vue
new file mode 100644
index 0000000..8652da1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/cropper/src/cropper-modal.vue
@@ -0,0 +1,373 @@
+<script lang="ts" setup>
+import type { CropendResult, Cropper } from './typing';
+
+import { type PropType, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t as t } from '@vben/locales';
+
+import { Avatar, message, Space, Tooltip, Upload } from 'ant-design-vue';
+import { isFunction } from 'lodash-es';
+
+import { dataURLtoBlob } from '#/utils/file/base64Conver';
+
+import CropperImage from './cropper.vue';
+
+type apiFunParams = { file: Blob; filename: string; name: string };
+
+defineOptions({ name: 'CropperModal' });
+
+const props = defineProps({
+  circled: { default: true, type: Boolean },
+  size: { default: 0, type: Number },
+  src: { default: '', type: String },
+  uploadApi: {
+    required: true,
+    type: Function as PropType<(params: apiFunParams) => Promise<any>>,
+  },
+});
+
+const emit = defineEmits(['uploadSuccess', 'uploadError', 'register']);
+
+let filename = '';
+const src = ref(props.src || '');
+const previewSource = ref('');
+const cropper = ref<Cropper>();
+let scaleX = 1;
+let scaleY = 1;
+
+const prefixCls = 'cropper-am';
+const [BasicModal, modalApi] = useVbenModal({
+  onConfirm: handleOk,
+  onOpenChange(isOpen) {
+    // 鎵撳紑鐨勬椂鍊檒oading CropperImage缁勪欢鍔犺浇瀹屾瘯鍏抽棴loading
+    if (isOpen) {
+      modalLoading(true);
+    } else {
+      // 鍏抽棴鏃跺�欐竻绌哄彸渚ч瑙�
+      previewSource.value = '';
+      modalLoading(false);
+    }
+  },
+});
+
+function modalLoading(loading: boolean) {
+  modalApi.setState({ confirmLoading: loading, loading });
+}
+
+// Block upload
+function handleBeforeUpload(file: File) {
+  if (props.size > 0 && file.size > 1024 * 1024 * props.size) {
+    emit('uploadError', { msg: t('component.cropper.imageTooBig') });
+    return false;
+  }
+  const reader = new FileReader();
+  reader.readAsDataURL(file);
+  src.value = '';
+  previewSource.value = '';
+  reader.addEventListener('load', (e) => {
+    src.value = (e.target?.result as string) ?? '';
+    filename = file.name;
+  });
+  return false;
+}
+
+function handleCropend({ imgBase64 }: CropendResult) {
+  previewSource.value = imgBase64;
+}
+
+function handleReady(cropperInstance: Cropper) {
+  cropper.value = cropperInstance;
+  // 鐢诲竷鍔犺浇瀹屾瘯 鍏抽棴loading
+  modalLoading(false);
+}
+
+function handlerToolbar(event: string, arg?: number) {
+  if (event === 'scaleX') {
+    scaleX = arg = scaleX === -1 ? 1 : -1;
+  }
+  if (event === 'scaleY') {
+    scaleY = arg = scaleY === -1 ? 1 : -1;
+  }
+  (cropper?.value as any)?.[event]?.(arg);
+}
+
+async function handleOk() {
+  const uploadApi = props.uploadApi;
+  if (uploadApi && isFunction(uploadApi)) {
+    if (!previewSource.value) {
+      message.warn('鏈�夋嫨鍥剧墖');
+      return;
+    }
+    const blob = dataURLtoBlob(previewSource.value);
+    try {
+      modalLoading(true);
+      const result = await uploadApi({ file: blob, filename, name: 'file' });
+      emit('uploadSuccess', { data: result.url, source: previewSource.value });
+      modalApi.close();
+    } finally {
+      modalLoading(false);
+    }
+  }
+}
+</script>
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    :confirm-text="t('component.cropper.okText')"
+    :fullscreen-button="false"
+    :title="t('component.cropper.modalTitle')"
+    class="w-[800px]"
+  >
+    <div :class="prefixCls">
+      <div :class="`${prefixCls}-left`" class="w-full">
+        <div :class="`${prefixCls}-cropper`">
+          <CropperImage
+            v-if="src"
+            :circled="circled"
+            :src="src"
+            height="300px"
+            @cropend="handleCropend"
+            @ready="handleReady"
+          />
+        </div>
+
+        <div :class="`${prefixCls}-toolbar`">
+          <Upload
+            :before-upload="handleBeforeUpload"
+            :file-list="[]"
+            accept="image/*"
+          >
+            <Tooltip
+              :title="t('component.cropper.selectImage')"
+              placement="bottom"
+            >
+              <a-button size="small" type="primary">
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[ant-design--upload-outlined]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+          </Upload>
+          <Space>
+            <Tooltip
+              :title="t('component.cropper.btn_reset')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('reset')"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[ant-design--reload-outlined]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_rotate_left')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('rotate', -45)"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span
+                      class="icon-[ant-design--rotate-left-outlined]"
+                    ></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_rotate_right')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                pre-icon="ant-design:rotate-right-outlined"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('rotate', 45)"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span
+                      class="icon-[ant-design--rotate-right-outlined]"
+                    ></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_scale_x')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('scaleX')"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[vaadin--arrows-long-h]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_scale_y')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('scaleY')"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[vaadin--arrows-long-v]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_zoom_in')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('zoom', 0.1)"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[ant-design--zoom-in-outlined]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+            <Tooltip
+              :title="t('component.cropper.btn_zoom_out')"
+              placement="bottom"
+            >
+              <a-button
+                :disabled="!src"
+                size="small"
+                type="primary"
+                @click="handlerToolbar('zoom', -0.1)"
+              >
+                <template #icon>
+                  <div class="flex items-center justify-center">
+                    <span class="icon-[ant-design--zoom-out-outlined]"></span>
+                  </div>
+                </template>
+              </a-button>
+            </Tooltip>
+          </Space>
+        </div>
+      </div>
+      <div :class="`${prefixCls}-right`">
+        <div :class="`${prefixCls}-preview`">
+          <img
+            v-if="previewSource"
+            :alt="t('component.cropper.preview')"
+            :src="previewSource"
+          />
+        </div>
+        <template v-if="previewSource">
+          <div :class="`${prefixCls}-group`">
+            <Avatar :src="previewSource" size="large" />
+            <Avatar :size="48" :src="previewSource" />
+            <Avatar :size="64" :src="previewSource" />
+            <Avatar :size="80" :src="previewSource" />
+          </div>
+        </template>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+
+<style lang="scss">
+.cropper-am {
+  display: flex;
+
+  &-left,
+  &-right {
+    height: 340px;
+  }
+
+  &-left {
+    width: 55%;
+  }
+
+  &-right {
+    width: 45%;
+  }
+
+  &-cropper {
+    height: 300px;
+    background: #eee;
+    background-image: linear-gradient(
+        45deg,
+        rgb(0 0 0 / 25%) 25%,
+        transparent 0,
+        transparent 75%,
+        rgb(0 0 0 / 25%) 0
+      ),
+      linear-gradient(
+        45deg,
+        rgb(0 0 0 / 25%) 25%,
+        transparent 0,
+        transparent 75%,
+        rgb(0 0 0 / 25%) 0
+      );
+    background-position:
+      0 0,
+      12px 12px;
+    background-size: 24px 24px;
+  }
+
+  &-toolbar {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 10px;
+  }
+
+  &-preview {
+    width: 220px;
+    height: 220px;
+    margin: 0 auto;
+    overflow: hidden;
+    border: 1px solid #eee;
+    border-radius: 50%;
+
+    img {
+      width: 100%;
+      height: 100%;
+    }
+  }
+
+  &-group {
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+    padding-top: 8px;
+    margin-top: 8px;
+    border-top: 1px solid #eee;
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/cropper/src/cropper.vue b/eims-ui/apps/web-antd/src/components/cropper/src/cropper.vue
new file mode 100644
index 0000000..2e1c4b2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/cropper/src/cropper.vue
@@ -0,0 +1,195 @@
+<script lang="ts" setup>
+import type { CSSProperties, PropType } from 'vue';
+import { computed, onMounted, onUnmounted, ref, unref, useAttrs } from 'vue';
+
+import { useDebounceFn } from '@vueuse/core';
+import Cropper from 'cropperjs';
+
+import 'cropperjs/dist/cropper.css';
+
+type Options = Cropper.Options;
+
+defineOptions({ name: 'CropperImage' });
+
+const props = defineProps({
+  alt: { default: '', type: String },
+  circled: { default: false, type: Boolean },
+  crossorigin: {
+    default: undefined,
+    type: String as PropType<'' | 'anonymous' | 'use-credentials' | undefined>,
+  },
+  height: { default: '360px', type: [String, Number] },
+  imageStyle: { default: () => ({}), type: Object as PropType<CSSProperties> },
+  options: { default: () => ({}), type: Object as PropType<Options> },
+  realTimePreview: { default: true, type: Boolean },
+  src: { required: true, type: String },
+});
+
+const emit = defineEmits(['cropend', 'ready', 'cropendError']);
+
+const defaultOptions: Options = {
+  aspectRatio: 1,
+  autoCrop: true,
+  background: true,
+  center: true,
+  checkCrossOrigin: true,
+  checkOrientation: true,
+  cropBoxMovable: true,
+  cropBoxResizable: true,
+  guides: true,
+  highlight: true,
+  modal: true,
+  movable: true,
+  responsive: true,
+  restore: true,
+  rotatable: true,
+  scalable: true,
+  toggleDragModeOnDblclick: true,
+  zoomable: true,
+  zoomOnTouch: true,
+  zoomOnWheel: true,
+};
+
+const attrs = useAttrs();
+
+type ElRef<T extends HTMLElement = HTMLDivElement> = null | T;
+const imgElRef = ref<ElRef<HTMLImageElement>>();
+const cropper = ref<Cropper | null>();
+const isReady = ref(false);
+
+const prefixCls = 'cropper-image';
+const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80);
+
+const getImageStyle = computed((): CSSProperties => {
+  return {
+    height: props.height,
+    maxWidth: '100%',
+    ...props.imageStyle,
+  };
+});
+
+const getClass = computed(() => {
+  return [
+    prefixCls,
+    attrs.class,
+    {
+      [`${prefixCls}--circled`]: props.circled,
+    },
+  ];
+});
+
+const getWrapperStyle = computed((): CSSProperties => {
+  return { height: `${`${props.height}`.replace(/px/, '')}px` };
+});
+
+onMounted(init);
+
+onUnmounted(() => {
+  cropper.value?.destroy();
+});
+
+async function init() {
+  const imgEl = unref(imgElRef);
+  if (!imgEl) {
+    return;
+  }
+  cropper.value = new Cropper(imgEl, {
+    ...defaultOptions,
+    crop() {
+      debounceRealTimeCroppered();
+    },
+    cropmove() {
+      debounceRealTimeCroppered();
+    },
+    ready: () => {
+      isReady.value = true;
+      realTimeCroppered();
+      emit('ready', cropper.value);
+    },
+    zoom() {
+      debounceRealTimeCroppered();
+    },
+    ...props.options,
+  });
+}
+
+// Real-time display preview
+function realTimeCroppered() {
+  props.realTimePreview && croppered();
+}
+
+// event: return base64 and width and height information after cropping
+function croppered() {
+  if (!cropper.value) {
+    return;
+  }
+  const imgInfo = cropper.value.getData();
+  const canvas = props.circled
+    ? getRoundedCanvas()
+    : cropper.value.getCroppedCanvas();
+  canvas.toBlob((blob) => {
+    if (!blob) {
+      return;
+    }
+    const fileReader: FileReader = new FileReader();
+    fileReader.readAsDataURL(blob);
+    fileReader.onloadend = (e) => {
+      emit('cropend', {
+        imgBase64: e.target?.result ?? '',
+        imgInfo,
+      });
+    };
+    // eslint-disable-next-line unicorn/prefer-add-event-listener
+    fileReader.onerror = () => {
+      emit('cropendError');
+    };
+  }, 'image/png');
+}
+
+// Get a circular picture canvas
+function getRoundedCanvas() {
+  const sourceCanvas = cropper.value!.getCroppedCanvas();
+  const canvas = document.createElement('canvas');
+  const context = canvas.getContext('2d')!;
+  const width = sourceCanvas.width;
+  const height = sourceCanvas.height;
+  canvas.width = width;
+  canvas.height = height;
+  context.imageSmoothingEnabled = true;
+  context.drawImage(sourceCanvas, 0, 0, width, height);
+  context.globalCompositeOperation = 'destination-in';
+  context.beginPath();
+  context.arc(
+    width / 2,
+    height / 2,
+    Math.min(width, height) / 2,
+    0,
+    2 * Math.PI,
+    true,
+  );
+  context.fill();
+  return canvas;
+}
+</script>
+<template>
+  <div :class="getClass" :style="getWrapperStyle">
+    <img
+      v-show="isReady"
+      ref="imgElRef"
+      :alt="alt"
+      :crossorigin="crossorigin"
+      :src="src"
+      :style="getImageStyle"
+    />
+  </div>
+</template>
+<style lang="scss">
+.cropper-image {
+  &--circled {
+    .cropper-view-box,
+    .cropper-face {
+      border-radius: 50%;
+    }
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/cropper/src/typing.ts b/eims-ui/apps/web-antd/src/components/cropper/src/typing.ts
new file mode 100644
index 0000000..e76cc6f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/cropper/src/typing.ts
@@ -0,0 +1,8 @@
+import type Cropper from 'cropperjs';
+
+export interface CropendResult {
+  imgBase64: string;
+  imgInfo: Cropper.Data;
+}
+
+export type { Cropper };
diff --git a/eims-ui/apps/web-antd/src/components/description/index.ts b/eims-ui/apps/web-antd/src/components/description/index.ts
new file mode 100644
index 0000000..46a851f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/description/index.ts
@@ -0,0 +1,3 @@
+export { default as Description } from './src/description.vue';
+export * from './src/typing';
+export { useDescription } from './src/useDescription';
diff --git a/eims-ui/apps/web-antd/src/components/description/src/description.vue b/eims-ui/apps/web-antd/src/components/description/src/description.vue
new file mode 100644
index 0000000..e285069
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/description/src/description.vue
@@ -0,0 +1,210 @@
+<script lang="tsx">
+import type { CardSize } from 'ant-design-vue/es/card/Card';
+import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
+
+import type { DescInstance, DescItem, DescriptionProps } from './typing';
+
+import {
+  computed,
+  type CSSProperties,
+  defineComponent,
+  type PropType,
+  ref,
+  type Slots,
+  toRefs,
+  unref,
+  useAttrs,
+} from 'vue';
+
+import { Card, Descriptions } from 'ant-design-vue';
+import { get, isFunction } from 'lodash-es';
+
+const props = {
+  bordered: { default: true, type: Boolean },
+  column: {
+    default: () => {
+      return { lg: 3, md: 3, sm: 2, xl: 3, xs: 1, xxl: 4 };
+    },
+    type: [Number, Object],
+  },
+  data: { type: Object },
+  schema: {
+    default: () => [],
+    type: Array as PropType<DescItem[]>,
+  },
+  size: {
+    default: 'small',
+    type: String,
+    validator: (v: string) =>
+      ['default', 'middle', 'small', undefined].includes(v),
+  },
+  title: { default: '', type: String },
+  useCollapse: { default: true, type: Boolean },
+};
+
+export default defineComponent({
+  emits: ['register'],
+  // eslint-disable-next-line vue/order-in-components
+  name: 'Description',
+  // eslint-disable-next-line vue/order-in-components
+  props,
+  setup(props, { emit, slots }) {
+    const propsRef = ref<null | Partial<DescriptionProps>>(null);
+
+    const prefixCls = 'description';
+    const attrs = useAttrs();
+
+    // Custom title component: get title
+    const getMergeProps = computed(() => {
+      return {
+        ...props,
+        ...(unref(propsRef) as any),
+      } as DescriptionProps;
+    });
+
+    const getProps = computed(() => {
+      const opt = {
+        ...unref(getMergeProps),
+        title: undefined,
+      };
+      return opt as DescriptionProps;
+    });
+
+    /**
+     * @description: Whether to setting title
+     */
+    const useWrapper = computed(() => !!unref(getMergeProps).title);
+
+    const getDescriptionsProps = computed(() => {
+      return { ...unref(attrs), ...unref(getProps) } as DescriptionsProps;
+    });
+
+    /**
+     * @description:璁剧疆desc
+     */
+    function setDescProps(descProps: Partial<DescriptionProps>): void {
+      // Keep the last setDrawerProps
+      propsRef.value = {
+        ...(unref(propsRef) as Record<string, any>),
+        ...descProps,
+      } as Record<string, any>;
+    }
+
+    // Prevent line breaks
+    function renderLabel({ label, labelMinWidth, labelStyle }: DescItem) {
+      if (!labelStyle && !labelMinWidth) {
+        return label;
+      }
+
+      const labelStyles: CSSProperties = {
+        ...labelStyle,
+        minWidth: `${labelMinWidth}px `,
+      };
+      return <div style={labelStyles}>{label}</div>;
+    }
+
+    function renderItem() {
+      const { data, schema } = unref(getProps);
+      return unref(schema)
+        .map((item) => {
+          const { contentMinWidth, field, render, show, span } = item;
+
+          if (show && isFunction(show) && !show(data)) {
+            return null;
+          }
+
+          const getContent = () => {
+            const _data = unref(getProps)?.data;
+            if (!_data) {
+              return null;
+            }
+            const getField = get(_data, field);
+            // eslint-disable-next-line no-prototype-builtins
+            if (getField && !toRefs(_data).hasOwnProperty(field)) {
+              return isFunction(render) ? render!('', _data) : '';
+            }
+            return isFunction(render)
+              ? render!(getField, _data)
+              : (getField ?? '');
+          };
+
+          const width = contentMinWidth;
+          return (
+            <Descriptions.Item
+              key={field}
+              label={renderLabel(item)}
+              span={span}
+            >
+              {() => {
+                if (!contentMinWidth) {
+                  return getContent();
+                }
+                const style: CSSProperties = {
+                  minWidth: `${width}px`,
+                };
+                return <div style={style}>{getContent()}</div>;
+              }}
+            </Descriptions.Item>
+          );
+        })
+        .filter((item) => !!item);
+    }
+
+    const renderDesc = () => {
+      return (
+        <Descriptions
+          class={`${prefixCls}`}
+          {...(unref(getDescriptionsProps) as any)}
+        >
+          {renderItem()}
+        </Descriptions>
+      );
+    };
+
+    const renderContainer = () => {
+      const content = props.useCollapse ? (
+        renderDesc()
+      ) : (
+        <div>{renderDesc()}</div>
+      );
+      // Reduce the dom level
+      if (!props.useCollapse) {
+        return content;
+      }
+
+      // const { canExpand, helpMessage } = unref(getCollapseOptions);
+      const { title } = unref(getMergeProps);
+
+      function getSlot(slots: Slots, slot = 'default', data?: any) {
+        if (!slots || !Reflect.has(slots, slot)) {
+          return null;
+        }
+        if (!isFunction(slots[slot])) {
+          console.error(`${slot} is not a function!`);
+          return null;
+        }
+        const slotFn = slots[slot];
+        if (!slotFn) return null;
+        const params = { ...data };
+        return slotFn(params);
+      }
+
+      return (
+        <Card size={props.size as CardSize} title={title}>
+          {{
+            default: () => content,
+            extra: () => getSlot(slots, 'extra'),
+          }}
+        </Card>
+      );
+    };
+
+    const methods: DescInstance = {
+      setDescProps,
+    };
+
+    emit('register', methods);
+    return () => (unref(useWrapper) ? renderContainer() : renderDesc());
+  },
+});
+</script>
diff --git a/eims-ui/apps/web-antd/src/components/description/src/typing.ts b/eims-ui/apps/web-antd/src/components/description/src/typing.ts
new file mode 100644
index 0000000..e9de60b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/description/src/typing.ts
@@ -0,0 +1,47 @@
+import type { Recordable } from '@vben/types';
+import type { DescriptionsProps } from 'ant-design-vue/es/descriptions';
+import type { JSX } from 'vue/jsx-runtime';
+
+import type { CSSProperties, VNode } from 'vue';
+
+export interface DescItem {
+  labelMinWidth?: number;
+  contentMinWidth?: number;
+  labelStyle?: CSSProperties;
+  field: string;
+  label: JSX.Element | string | VNode;
+  // Merge column
+  span?: number;
+  show?: (...arg: any) => boolean;
+  // render
+  render?: (
+    val: any,
+    data: Recordable<any>,
+  ) => Element | JSX.Element | number | string | undefined | VNode;
+}
+
+export interface DescriptionProps extends DescriptionsProps {
+  // Whether to include the collapse component
+  useCollapse?: boolean;
+  /**
+   * item configuration
+   * @type DescItem
+   */
+  schema: DescItem[];
+  /**
+   * 鏁版嵁
+   * @type object
+   */
+  data: Recordable<any>;
+}
+
+export interface DescInstance {
+  setDescProps(descProps: Partial<DescriptionProps>, delay?: boolean): void;
+}
+
+export type Register = (descInstance: DescInstance) => void;
+
+/**
+ * @description:
+ */
+export type UseDescReturnType = [Register, DescInstance];
diff --git a/eims-ui/apps/web-antd/src/components/description/src/useDescription.ts b/eims-ui/apps/web-antd/src/components/description/src/useDescription.ts
new file mode 100644
index 0000000..477756b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/description/src/useDescription.ts
@@ -0,0 +1,44 @@
+import type {
+  DescInstance,
+  DescriptionProps,
+  UseDescReturnType,
+} from './typing';
+
+import { getCurrentInstance, ref, unref } from 'vue';
+
+export function useDescription(
+  props?: Partial<DescriptionProps>,
+): UseDescReturnType {
+  if (!getCurrentInstance()) {
+    throw new Error(
+      'useDescription() can only be used inside setup() or functional components!',
+    );
+  }
+  const desc = ref<DescInstance | null>(null);
+  const loaded = ref(false);
+
+  function register(instance: DescInstance) {
+    // if (unref(loaded) && import.meta.env.PROD) {
+    //   return;
+    // }
+    desc.value = instance;
+    props && instance.setDescProps(props);
+    loaded.value = true;
+  }
+
+  const methods: DescInstance = {
+    setDescProps: (
+      descProps: Partial<DescriptionProps>,
+      delay = false,
+    ): void => {
+      if (!delay) {
+        unref(desc)?.setDescProps(descProps);
+        return;
+      }
+      // 濂囨�殑闂 鍦╩odal涓渶瑕乻etTimeout鎵嶄細鐢熸晥
+      setTimeout(() => unref(desc)?.setDescProps(descProps));
+    },
+  };
+
+  return [register, methods];
+}
diff --git a/eims-ui/apps/web-antd/src/components/dict/index.ts b/eims-ui/apps/web-antd/src/components/dict/index.ts
new file mode 100644
index 0000000..08282cf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/dict/index.ts
@@ -0,0 +1,2 @@
+export { tagSelectOptions, tagTypes } from './src/data';
+export { default as DictTag } from './src/index.vue';
diff --git a/eims-ui/apps/web-antd/src/components/dict/src/data.tsx b/eims-ui/apps/web-antd/src/components/dict/src/data.tsx
new file mode 100644
index 0000000..68395f8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/dict/src/data.tsx
@@ -0,0 +1,44 @@
+import { type VNode } from 'vue';
+
+import { Tag } from 'ant-design-vue';
+
+interface TagType {
+  [key: string]: { color: string; label: string };
+}
+
+export const tagTypes: TagType = {
+  cyan: { color: 'cyan', label: 'cyan' },
+  danger: { color: 'error', label: '鍗遍櫓(danger)' },
+  /** 鐢变簬鍜宔lementUI涓嶅悓 鐢ㄤ簬鏇挎崲棰滆壊 */
+  default: { color: 'default', label: '榛樿(default)' },
+  green: { color: 'green', label: 'green' },
+  info: { color: 'default', label: '淇℃伅(info)' },
+  orange: { color: 'orange', label: 'orange' },
+  /** 鑷畾涔夐璁� color鍙互涓�16杩涘埗棰滆壊 */
+  pink: { color: 'pink', label: 'pink' },
+  primary: { color: 'processing', label: '涓昏(primary)' },
+  purple: { color: 'purple', label: 'purple' },
+  red: { color: 'red', label: 'red' },
+  success: { color: 'success', label: '鎴愬姛(success)' },
+  warning: { color: 'warning', label: '璀﹀憡(warning)' },
+};
+
+// 瀛楀吀閫夋嫨浣跨敤 { label: string; value: string }[]
+interface Options {
+  label: string | VNode;
+  value: string;
+}
+
+export function tagSelectOptions() {
+  const selectArray: Options[] = [];
+  Object.keys(tagTypes).forEach((key) => {
+    if (!tagTypes[key]) return;
+    const label = tagTypes[key].label;
+    const color = tagTypes[key].color;
+    selectArray.push({
+      label: <Tag color={color}>{label}</Tag>,
+      value: key,
+    });
+  });
+  return selectArray;
+}
diff --git a/eims-ui/apps/web-antd/src/components/dict/src/index.vue b/eims-ui/apps/web-antd/src/components/dict/src/index.vue
new file mode 100644
index 0000000..6889ef1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/dict/src/index.vue
@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import type { DictData } from '#/api/system/dict/dict-data-model';
+
+import { computed } from 'vue';
+
+import { Tag } from 'ant-design-vue';
+
+import { tagTypes } from './data';
+
+interface Props {
+  dicts: DictData[]; // dict鏁扮粍
+  value: number | string; // value
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  dicts: undefined,
+});
+
+const color = computed<string>(() => {
+  // eslint-disable-next-line eqeqeq
+  const current = props.dicts.find((item) => item.dictValue == props.value);
+  const listClass = current?.listClass ?? '';
+  // 鏄惁涓洪粯璁ょ殑棰滆壊
+  const isDefault = Reflect.has(tagTypes, listClass);
+  // 鍒ゆ柇鏄粯璁よ繕鏄嚜瀹氫箟棰滆壊
+  if (isDefault) {
+    // 杩欓噷鍋氫簡antd - element-plus鐨勫吋瀹�
+    return tagTypes[listClass]!.color;
+  }
+  return listClass;
+});
+
+const cssClass = computed<string>(() => {
+  // eslint-disable-next-line eqeqeq
+  const current = props.dicts.find((item) => item.dictValue == props.value);
+  return current?.cssClass ?? '';
+});
+
+const label = computed<number | string>(() => {
+  // eslint-disable-next-line eqeqeq
+  const current = props.dicts.find((item) => item.dictValue == props.value);
+  return current?.dictLabel ?? 'unknown';
+});
+
+const tagComponent = computed(() => (color.value ? Tag : 'div'));
+</script>
+
+<template>
+  <div>
+    <component :is="tagComponent" :class="cssClass" :color="color">
+      {{ label }}
+    </component>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/components/global/button.ts b/eims-ui/apps/web-antd/src/components/global/button.ts
new file mode 100644
index 0000000..397fdf6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/global/button.ts
@@ -0,0 +1,21 @@
+import { defineComponent, h } from 'vue';
+
+import { Button } from 'ant-design-vue';
+import buttonProps from 'ant-design-vue/es/button/buttonTypes';
+import { omit } from 'lodash-es';
+
+/**
+ * 琛ㄦ牸鎿嶄綔鍒楁寜閽笓鐢�
+ */
+export const GhostButton = defineComponent({
+  name: 'GhostButton',
+  props: omit(buttonProps(), ['type', 'ghost', 'size']),
+  setup(props, { attrs, slots }) {
+    return () =>
+      h(
+        Button,
+        { ...props, ...attrs, type: 'primary', ghost: true, size: 'small' },
+        slots,
+      );
+  },
+});
diff --git a/eims-ui/apps/web-antd/src/components/global/index.ts b/eims-ui/apps/web-antd/src/components/global/index.ts
new file mode 100644
index 0000000..ff07852
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/global/index.ts
@@ -0,0 +1,14 @@
+import type { App } from 'vue';
+
+import { Button as AButton } from 'ant-design-vue';
+
+import { GhostButton } from './button';
+
+/**
+ * 鍏ㄥ眬缁勪欢娉ㄥ唽
+ */
+export function setupGlobalComponent(app: App) {
+  app.use(AButton);
+  // 琛ㄦ牸鎿嶄綔鍒椾笓鐢ㄦ寜閽�
+  app.component('GhostButton', GhostButton);
+}
diff --git a/eims-ui/apps/web-antd/src/components/table/index.ts b/eims-ui/apps/web-antd/src/components/table/index.ts
new file mode 100644
index 0000000..28bd800
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/table/index.ts
@@ -0,0 +1 @@
+export { default as TableSwitch } from './src/table-switch.vue';
diff --git a/eims-ui/apps/web-antd/src/components/table/src/table-switch.vue b/eims-ui/apps/web-antd/src/components/table/src/table-switch.vue
new file mode 100644
index 0000000..036e984
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/table/src/table-switch.vue
@@ -0,0 +1,84 @@
+<script lang="ts">
+import { defineComponent } from 'vue';
+
+import { Switch } from 'ant-design-vue';
+import { isFunction } from 'lodash-es';
+
+export default defineComponent({
+  name: 'TableSwitch',
+  components: {
+    Switch,
+  },
+  inheritAttrs: false,
+  props: {
+    modelValue: {
+      type: [Boolean, String, Number],
+      default: false,
+    },
+    checkedText: {
+      type: String,
+      default: '鍚敤',
+    },
+    unCheckedText: {
+      type: String,
+      default: '绂佺敤',
+    },
+    // 浣跨敤涓ユ牸鐩哥瓑鍒ゆ柇  绫诲瀷瑕佹纭�
+    checkedValue: {
+      type: [Boolean, String, Number],
+      default: '0',
+    },
+    unCheckedValue: {
+      type: [Boolean, String, Number],
+      default: '1',
+    },
+    api: {
+      type: Function,
+      required: false,
+      default: null,
+    },
+    reload: {
+      type: Function,
+      required: false,
+      default: null,
+    },
+  },
+  emits: ['update:modelValue'],
+  setup(props, { emit }) {
+    type CheckedType = boolean | number | string;
+    async function onChange(checked: CheckedType, e: Event) {
+      // 闃绘浜嬩欢鍐掓场 鍚﹀垯浼氳窡琛岄�変腑鍐茬獊
+      e.stopPropagation();
+      const { checkedValue, unCheckedValue } = props;
+      // 鍘熸湰鐨勭姸鎬�
+      const lastStatus =
+        checked === checkedValue ? unCheckedValue : checkedValue;
+      // 鍒囨崲鐘舵��
+      emit('update:modelValue', checked);
+      const { api, reload } = props;
+      try {
+        isFunction(api) && (await api());
+        isFunction(reload) && (await reload());
+      } catch {
+        emit('update:modelValue', lastStatus);
+      }
+    }
+
+    return {
+      onChange,
+    };
+  },
+});
+</script>
+
+<template>
+  <Switch
+    v-bind="$attrs"
+    :checked="modelValue"
+    :checked-children="checkedText"
+    :checked-value="checkedValue"
+    :un-checked-children="unCheckedText"
+    :un-checked-value="unCheckedValue"
+    @change="onChange"
+  />
+</template>
diff --git a/eims-ui/apps/web-antd/src/components/tenant-toggle/index.ts b/eims-ui/apps/web-antd/src/components/tenant-toggle/index.ts
new file mode 100644
index 0000000..d82e602
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tenant-toggle/index.ts
@@ -0,0 +1 @@
+export { default as TenantToggle } from './src/index.vue';
diff --git a/eims-ui/apps/web-antd/src/components/tenant-toggle/src/index.vue b/eims-ui/apps/web-antd/src/components/tenant-toggle/src/index.vue
new file mode 100644
index 0000000..0a1569a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tenant-toggle/src/index.vue
@@ -0,0 +1,123 @@
+<script setup lang="ts">
+import type { SelectHandler } from 'ant-design-vue/es/vc-select/Select';
+
+import type { TenantOption } from '#/api';
+
+import { computed, onMounted, ref, unref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { useAccess } from '@vben/access';
+import { DEFAULT_HOME_PATH } from '@vben/constants';
+import { useTabs } from '@vben/hooks';
+import { $t } from '@vben/locales';
+
+import { message, Select } from 'ant-design-vue';
+import { storeToRefs } from 'pinia';
+
+import { tenantDynamicClear, tenantDynamicToggle } from '#/api/system/tenant';
+import { useDictStore } from '#/store/dict';
+import { useTenantStore } from '#/store/tenant';
+
+const { hasAccessByRoles } = useAccess();
+
+// 涓婁竴娆¢�夋嫨鐨勭鎴�
+const lastSelected = ref<string>();
+// 褰撳墠閫夋嫨绉熸埛鐨刬d
+const selected = ref<string>();
+
+const tenantStore = useTenantStore();
+const { initTenant, setChecked } = tenantStore;
+const { tenantEnable, tenantList } = storeToRefs(tenantStore);
+
+const showToggle = computed<boolean>(() => {
+  // 瓒呯骇绠$悊鍛� && 鍚敤绉熸埛
+  return hasAccessByRoles(['superadmin']) && unref(tenantEnable);
+});
+
+onMounted(async () => {
+  if (!hasAccessByRoles(['superadmin'])) {
+    return;
+  }
+  await initTenant();
+});
+
+const { closeAllTabs } = useTabs();
+const router = useRouter();
+function close(checked: boolean) {
+  // store璁剧疆鐘舵��
+  setChecked(checked);
+  // 闇�瑕佸叧闂叏閮ㄦ爣绛鹃〉
+  closeAllTabs();
+  // 鍒囨崲瀹屽姞杞介椤�
+  router.push(DEFAULT_HOME_PATH);
+}
+
+const dictStore = useDictStore();
+/**
+ * 閫変腑绉熸埛鐨勫鐞�
+ * @param tenantId tenantId
+ * @param option 褰撳墠option
+ */
+const onSelected: SelectHandler = async (tenantId: string, option: any) => {
+  if (unref(lastSelected) === tenantId) {
+    // createMessage.info('閫夋嫨涓�鑷�');
+    return;
+  }
+  await tenantDynamicToggle(tenantId);
+  lastSelected.value = tenantId;
+  message.success(
+    `${$t('component.tenantToggle.switch')} ${option.companyName}`,
+  );
+  close(true);
+  // 闇�瑕佹斁鍦ㄥ畯闃熷垪澶勭悊 鐩存帴娓呯┖椤甸潰鐢变簬娌℃湁瀛楀吀浼氭湁鏍峰紡闂(鏍囩鍙樻垚unknown)
+  setTimeout(() => dictStore.resetCache());
+};
+
+async function onDeselect() {
+  await tenantDynamicClear();
+  message.success($t('component.tenantToggle.reset'));
+  lastSelected.value = '';
+  close(false);
+  // 闇�瑕佹斁鍦ㄥ畯闃熷垪澶勭悊 鐩存帴娓呯┖椤甸潰鐢变簬娌℃湁瀛楀吀浼氭湁鏍峰紡闂(鏍囩鍙樻垚unknown)
+  setTimeout(() => dictStore.resetCache());
+}
+
+/**
+ * select鎼滅储浣跨敤
+ * @param input 杈撳叆鍐呭
+ * @param option 閫夐」
+ */
+function filterOption(input: string, option: TenantOption) {
+  return option.companyName.toLowerCase().includes(input.toLowerCase());
+}
+</script>
+
+<template>
+  <div v-if="showToggle" class="mr-[8px] hidden md:block">
+    <Select
+      v-model:value="selected"
+      :field-names="{ label: 'companyName', value: 'tenantId' }"
+      :filter-option="filterOption"
+      :options="tenantList"
+      :placeholder="$t('component.tenantToggle.placeholder')"
+      allow-clear
+      class="w-60"
+      show-search
+      @deselect="onDeselect"
+      @select="onSelected"
+    >
+      <template #suffixIcon>
+        <span class="icon-mdi--company"></span>
+      </template>
+    </Select>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+// 褰撻�変腑鏃� 娣诲姞border鏍峰紡
+:deep(.ant-select-selector) {
+  &:has(.ant-select-selection-item) {
+    box-shadow: 0 0 10px hsl(var(--primary));
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/tinymce/index.ts b/eims-ui/apps/web-antd/src/components/tinymce/index.ts
new file mode 100644
index 0000000..6fe8074
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tinymce/index.ts
@@ -0,0 +1 @@
+export { default as Tinymce } from './src/editor.vue';
diff --git a/eims-ui/apps/web-antd/src/components/tinymce/src/editor.vue b/eims-ui/apps/web-antd/src/components/tinymce/src/editor.vue
new file mode 100644
index 0000000..0595030
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tinymce/src/editor.vue
@@ -0,0 +1,370 @@
+<script lang="ts" setup>
+import type { IPropTypes } from '@tinymce/tinymce-vue/lib/cjs/main/ts/components/EditorPropTypes';
+import type { Editor as EditorType } from 'tinymce/tinymce';
+
+import {
+  computed,
+  nextTick,
+  onActivated,
+  onBeforeUnmount,
+  onDeactivated,
+  onMounted,
+  type PropType,
+  ref,
+  unref,
+  useAttrs,
+  watch,
+} from 'vue';
+
+import { preferences, usePreferences } from '@vben/preferences';
+import { buildShortUUID } from '@vben/utils';
+
+import Editor from '@tinymce/tinymce-vue';
+import { isNumber } from 'lodash-es';
+
+import { uploadApi, type UploadResult } from '#/api/core/upload';
+
+import { bindHandlers } from './helper';
+import ImgUpload from './img-upload.vue';
+import {
+  plugins as defaultPlugins,
+  toolbar as defaultToolbar,
+} from './tinymce';
+
+defineOptions({ inheritAttrs: false });
+
+const props = defineProps({
+  height: {
+    default: 400,
+    required: false,
+    type: [Number, String] as PropType<number | string>,
+  },
+  options: {
+    default: () => ({}),
+    // eslint-disable-next-line no-use-before-define
+    type: Object as PropType<Partial<InitOptions>>,
+  },
+
+  plugins: {
+    default: defaultPlugins,
+    type: String,
+  },
+  showImageUpload: {
+    default: true,
+    type: Boolean,
+  },
+  toolbar: {
+    default: defaultToolbar,
+    type: String,
+  },
+  width: {
+    default: 'auto',
+    required: false,
+    type: [Number, String] as PropType<number | string>,
+  },
+});
+
+const emit = defineEmits(['change']);
+
+type InitOptions = IPropTypes['init'];
+
+/**
+ * 澶栭儴浣跨敤 v-model 缁戝畾鍊�
+ */
+const modelValue = defineModel('modelValue', { default: '', type: String });
+/**
+ * https://www.jianshu.com/p/59a9c3802443
+ * 浣跨敤鑷墭绠℃柟妗堬紙鏈湴锛変唬鏇縞dn  娌℃湁key鐨勯檺鍒�
+ * 娉ㄦ剰publicPath瑕佷互/缁撳熬
+ */
+const tinymceScriptSrc = `${import.meta.env.VITE_BASE}tinymce/tinymce.min.js`;
+
+const attrs = useAttrs();
+const editorRef = ref<EditorType>();
+const fullscreen = ref(false);
+const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
+const elRef = ref<HTMLElement | null>(null);
+
+const containerWidth = computed(() => {
+  const width = props.width;
+  if (isNumber(width)) {
+    return `${width}px`;
+  }
+  return width;
+});
+
+const { isDark } = usePreferences();
+const skinName = computed(() => {
+  return isDark.value ? 'oxide-dark' : 'oxide';
+});
+
+const contentCss = computed(() => {
+  return isDark.value ? 'dark' : 'default';
+});
+
+/**
+ * 閫氳繃v-if鏉ユ寕杞�/鍗歌浇缁勪欢
+ * 鏉ュ畬鎴愪富棰樺垏鎹�/璇█鍒囨崲
+ */
+const init = ref(true);
+watch(
+  () => [preferences.theme.mode, preferences.app.locale],
+  () => {
+    if (!editorRef.value) {
+      return;
+    }
+    destroy();
+    init.value = false;
+    // 鏀惧湪涓嬩竴娆ick鏉ュ垏鎹�
+    // 闇�瑕佸厛鍔犺浇缁勪欢 涔熷氨鏄痸-if涓簍rue  鐒跺悗闇�瑕佹嬁鍒癳ditorRef 蹇呴』鏀惧湪setTimeout(鐩稿綋浜巓nMounted)
+    nextTick(() => {
+      init.value = true;
+      setTimeout(() => {
+        setEditorMode();
+      });
+    });
+  },
+);
+
+/**
+ * tinymce鏀寔 en zh_CN
+ */
+const langName = computed(() => {
+  const lang = preferences.app.locale.replace('-', '_');
+  if (lang.includes('en_US')) {
+    return 'en';
+  }
+  return 'zh_CN';
+});
+
+const initOptions = computed((): InitOptions => {
+  const { height, options, plugins, toolbar } = props;
+  return {
+    auto_focus: true,
+    branding: false, // 鏄剧ず鍙充笅瑙掔殑'浣跨敤 TinyMCE 鏋勫缓'
+    content_css: contentCss.value,
+    content_style:
+      'body { font-family:Helvetica,Arial,sans-serif; font-size:16px }',
+    contextmenu: 'link image table',
+    default_link_target: '_blank',
+    height,
+    image_advtab: true, // 鍥剧墖楂樼骇閫夐」
+    image_caption: true,
+    importcss_append: true,
+    language: langName.value,
+    link_title: false,
+    menubar: 'file edit view insert format tools table help',
+    noneditable_class: 'mceNonEditable',
+    /**
+     * 鍏佽绮樿创鍥剧墖 榛樿base64鏍煎紡
+     * images_upload_handler鍚敤鏃朵负涓婁紶
+     */
+    paste_data_images: true,
+    plugins,
+    quickbars_selection_toolbar:
+      'bold italic | quicklink h2 h3 blockquote quickimage quicktable',
+    skin: skinName.value,
+    toolbar,
+    toolbar_mode: 'sliding',
+    ...options,
+    /**
+     * 瑕嗙洊榛樿鐨刡ase64琛屼负
+     * @param blobInfo
+     * 澶у潙 涓嶈璋冪敤杩欎袱涓嚱鏁�  success failure:
+     * 浣跨敤resolve/reject浠f浛
+     */
+    images_upload_handler: (blobInfo) => {
+      return new Promise((resolve, reject) => {
+        const file = blobInfo.blob();
+        // const filename = blobInfo.filename();
+        uploadApi(file)
+          .then((response) => {
+            const { url } = response as unknown as UploadResult;
+            console.log('tinymce涓婁紶鍥剧墖:', url);
+            resolve(url);
+          })
+          .catch((error) => {
+            console.error('tinymce涓婁紶鍥剧墖澶辫触:', error);
+            reject(error.message);
+          });
+      });
+    },
+    setup: (editor) => {
+      editorRef.value = editor;
+      editor.on('init', (e) => initSetup(e));
+    },
+  };
+});
+
+/**
+ * 鐩戝惉options.readonly
+ */
+watch(
+  () => props.options,
+  (options) => {
+    const getDisabled = options && Reflect.get(options, 'readonly');
+    const editor = unref(editorRef);
+    if (editor) {
+      editor.mode.set(getDisabled ? 'readonly' : 'design');
+    }
+  },
+);
+
+onMounted(() => {
+  if (!initOptions.value.inline) {
+    tinymceId.value = buildShortUUID('tiny-vue');
+  }
+  nextTick(() => {
+    setTimeout(() => {
+      initEditor();
+      setEditorMode();
+    }, 30);
+  });
+});
+
+onBeforeUnmount(() => {
+  destroy();
+});
+
+onDeactivated(() => {
+  destroy();
+});
+
+onActivated(() => {
+  setEditorMode();
+});
+
+function setEditorMode() {
+  const editor = unref(editorRef);
+  if (editor) {
+    const mode = props.options.readonly ? 'readonly' : 'design';
+    editor.mode.set(mode);
+  }
+}
+
+function destroy() {
+  const editor = unref(editorRef);
+  editor?.destroy();
+}
+
+function initEditor() {
+  const el = unref(elRef);
+  if (el) {
+    el.style.visibility = '';
+  }
+}
+
+function initSetup(e: any) {
+  const editor = unref(editorRef);
+  if (!editor) {
+    return;
+  }
+  const value = modelValue.value || '';
+
+  editor.setContent(value);
+  bindModelHandlers(editor);
+  bindHandlers(e, attrs, unref(editorRef));
+}
+
+function setValue(editor: Record<string, any>, val?: string, prevVal?: string) {
+  if (
+    editor &&
+    typeof val === 'string' &&
+    val !== prevVal &&
+    val !== editor.getContent({ format: attrs.outputFormat })
+  ) {
+    editor.setContent(val);
+  }
+}
+
+function bindModelHandlers(editor: any) {
+  const modelEvents = attrs.modelEvents ?? null;
+  const normalizedEvents = Array.isArray(modelEvents)
+    ? modelEvents.join(' ')
+    : modelEvents;
+
+  watch(
+    () => modelValue.value,
+    (val, prevVal) => {
+      setValue(editor, val, prevVal);
+    },
+  );
+
+  editor.on(normalizedEvents || 'change keyup undo redo', () => {
+    const content = editor.getContent({ format: attrs.outputFormat });
+    emit('change', content);
+  });
+
+  editor.on('FullscreenStateChanged', (e: any) => {
+    fullscreen.value = e.state;
+  });
+}
+
+const disabled = computed(() => props.options.readonly ?? false);
+
+function getUploadingImgName(name: string) {
+  return `[uploading:${name}]`;
+}
+
+function handleImageUploading(name: string) {
+  const editor = unref(editorRef);
+  if (!editor) {
+    return;
+  }
+  editor.execCommand('mceInsertContent', false, getUploadingImgName(name));
+  const content = editor?.getContent() ?? '';
+  setValue(editor, content);
+}
+
+function handleDone(name: string, url: string) {
+  const editor = unref(editorRef);
+  if (!editor) {
+    return;
+  }
+  const content = editor?.getContent() ?? '';
+  const val =
+    content?.replace(getUploadingImgName(name), `<img src="${url}"/>`) ?? '';
+  setValue(editor, val);
+}
+</script>
+
+<template>
+  <div :style="{ width: containerWidth }" class="app-tinymce">
+    <ImgUpload
+      v-if="showImageUpload"
+      v-show="editorRef"
+      :disabled="disabled"
+      :fullscreen="fullscreen"
+      @done="handleDone"
+      @uploading="handleImageUploading"
+    />
+    <Editor
+      v-if="!initOptions.inline && init"
+      v-model="modelValue"
+      :init="initOptions"
+      :style="{ visibility: 'hidden' }"
+      :tinymce-script-src="tinymceScriptSrc"
+      license-key="gpl"
+    />
+    <slot v-else></slot>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+/**
+  闅愯棌鍙充笂瑙抲pgrade鎸夐挳
+  */
+:deep(.tox-promotion) {
+  display: none !important;
+}
+
+.app-tinymce {
+  position: relative;
+  line-height: normal;
+
+  :deep(.textarea) {
+    z-index: -1;
+    visibility: hidden;
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/tinymce/src/helper.ts b/eims-ui/apps/web-antd/src/components/tinymce/src/helper.ts
new file mode 100644
index 0000000..e169f50
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tinymce/src/helper.ts
@@ -0,0 +1,85 @@
+const validEvents = new Set([
+  'onActivate',
+  'onAddUndo',
+  'onBeforeAddUndo',
+  'onBeforeExecCommand',
+  'onBeforeGetContent',
+  'onBeforeRenderUI',
+  'onBeforeSetContent',
+  'onBeforePaste',
+  'onBlur',
+  'onChange',
+  'onClearUndos',
+  'onClick',
+  'onContextMenu',
+  'onCopy',
+  'onCut',
+  'onDblclick',
+  'onDeactivate',
+  'onDirty',
+  'onDrag',
+  'onDragDrop',
+  'onDragEnd',
+  'onDragGesture',
+  'onDragOver',
+  'onDrop',
+  'onExecCommand',
+  'onFocus',
+  'onFocusIn',
+  'onFocusOut',
+  'onGetContent',
+  'onHide',
+  'onInit',
+  'onKeyDown',
+  'onKeyPress',
+  'onKeyUp',
+  'onLoadContent',
+  'onMouseDown',
+  'onMouseEnter',
+  'onMouseLeave',
+  'onMouseMove',
+  'onMouseOut',
+  'onMouseOver',
+  'onMouseUp',
+  'onNodeChange',
+  'onObjectResizeStart',
+  'onObjectResized',
+  'onObjectSelected',
+  'onPaste',
+  'onPostProcess',
+  'onPostRender',
+  'onPreProcess',
+  'onProgressState',
+  'onRedo',
+  'onRemove',
+  'onReset',
+  'onSaveContent',
+  'onSelectionChange',
+  'onSetAttrib',
+  'onSetContent',
+  'onShow',
+  'onSubmit',
+  'onUndo',
+  'onVisualAid',
+]);
+
+const isValidKey = (key: string) => validEvents.has(key);
+
+export const bindHandlers = (
+  initEvent: Event,
+  listeners: any,
+  editor: any,
+): void => {
+  Object.keys(listeners)
+    .filter((element) => isValidKey(element))
+    .forEach((key: string) => {
+      const handler = listeners[key];
+      if (typeof handler === 'function') {
+        if (key === 'onInit') {
+          handler(initEvent, editor);
+        } else {
+          editor.on(key.slice(2), (e: any) => handler(e, editor));
+        }
+      }
+    });
+};
diff --git a/eims-ui/apps/web-antd/src/components/tinymce/src/img-upload.vue b/eims-ui/apps/web-antd/src/components/tinymce/src/img-upload.vue
new file mode 100644
index 0000000..0d7a2be
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tinymce/src/img-upload.vue
@@ -0,0 +1,115 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { useAppConfig } from '@vben/hooks';
+import { useAccessStore } from '@vben/stores';
+
+import { message, Upload } from 'ant-design-vue';
+
+defineOptions({ name: 'TinymceImageUpload' });
+
+const props = defineProps({
+  disabled: {
+    default: false,
+    type: Boolean,
+  },
+  fullscreen: {
+    type: Boolean,
+  },
+});
+
+const emit = defineEmits(['uploading', 'done', 'error']);
+
+let uploading = false;
+
+const { apiURL, clientId } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+const accessStore = useAccessStore();
+const uploadUrl = `${apiURL}/resource/oss/upload`;
+// 浣跨敤upload缁勪欢鍙兘杩欐牱涓婁紶
+const headers = {
+  Authorization: `Bearer ${accessStore.accessToken}`,
+  clientId,
+};
+
+const getButtonProps = computed(() => {
+  const { disabled } = props;
+  return {
+    disabled,
+  };
+});
+
+function handleChange(info: Record<string, any>) {
+  const file = info.file;
+  const status = file?.status;
+  // const url = file?.response?.data.url;
+  const name = file?.name;
+
+  switch (status) {
+    case 'done': {
+      // http 200浼氳蛋鍒拌繖閲�  闇�瑕佸啀娆″垽鏂�
+      const { response } = file;
+      const { code, data, msg = '鏈嶅姟鍣ㄩ敊璇�' } = response;
+      if (code === 200) {
+        const { url } = data;
+        emit('done', name, url);
+      } else {
+        message.error(msg);
+      }
+      // emit('done', name, url);
+      uploading = false;
+
+      break;
+    }
+    case 'error': {
+      emit('error');
+      uploading = false;
+
+      break;
+    }
+    case 'uploading': {
+      if (!uploading) {
+        emit('uploading', name);
+        uploading = true;
+      }
+
+      break;
+    }
+    // No default
+  }
+}
+</script>
+<template>
+  <div :class="[{ fullscreen }]" class="tinymce-image-upload">
+    <Upload
+      :action="uploadUrl"
+      :headers="headers"
+      :show-upload-list="false"
+      accept=".jpg,.jpeg,.gif,.png,.webp"
+      multiple
+      name="file"
+      @change="handleChange"
+    >
+      <!-- 杩欓噷瑕佹敼鎴恑18n -->
+      <a-button type="primary" v-bind="{ ...getButtonProps }">
+        鍥剧墖涓婁紶
+      </a-button>
+    </Upload>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.tinymce-image-upload {
+  position: absolute;
+  top: 4px;
+  right: 10px;
+  z-index: 20;
+
+  &.fullscreen {
+    position: fixed;
+    z-index: 10000;
+  }
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/tinymce/src/tinymce.ts b/eims-ui/apps/web-antd/src/components/tinymce/src/tinymce.ts
new file mode 100644
index 0000000..eb3964a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tinymce/src/tinymce.ts
@@ -0,0 +1,11 @@
+// Any plugins you want to setting has to be imported
+// Detail plugins list see https://www.tinymce.com/docs/plugins/
+// Custom builds see https://www.tinymce.com/download/custom-builds/
+// colorpicker/contextmenu/textcolor plugin is now built in to the core editor, please remove it from your editor configuration
+
+// quickbars 蹇嵎鏍�
+export const plugins =
+  'preview importcss searchreplace autolink autosave save directionality code visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap emoticons accordion';
+
+export const toolbar =
+  'undo redo | accordion accordionremove | blocks fontfamily fontsize | bold italic underline strikethrough | align numlist bullist | link image | table media | lineheight outdent indent| forecolor backcolor removeformat | charmap emoticons | code fullscreen preview | save print | pagebreak anchor codesample | ltr rtl';
diff --git a/eims-ui/apps/web-antd/src/components/tree/index.ts b/eims-ui/apps/web-antd/src/components/tree/index.ts
new file mode 100644
index 0000000..3dfcd39
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tree/index.ts
@@ -0,0 +1 @@
+export { default as TreeSelectPanel } from './src/tree-select-panel.vue';
diff --git a/eims-ui/apps/web-antd/src/components/tree/src/tree-select-panel.vue b/eims-ui/apps/web-antd/src/components/tree/src/tree-select-panel.vue
new file mode 100644
index 0000000..9a2a774
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/tree/src/tree-select-panel.vue
@@ -0,0 +1,217 @@
+<script setup lang="ts">
+import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface';
+import type { DataNode } from 'ant-design-vue/es/tree';
+import type { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
+
+import { computed, nextTick, onMounted, type PropType, ref, watch } from 'vue';
+
+import { findGroupParentIds, treeToList } from '@vben/utils';
+
+import { Checkbox, Tree } from 'ant-design-vue';
+import { uniq } from 'lodash-es';
+
+/** 闇�瑕佺姝㈤�忎紶 */
+defineOptions({ inheritAttrs: false });
+
+const props = defineProps({
+  checkStrictly: {
+    default: true,
+    type: Boolean,
+  },
+  expandAllOnInit: {
+    default: false,
+    type: Boolean,
+  },
+  fieldNames: {
+    default: () => ({ key: 'id', title: 'label' }),
+    type: Object as PropType<{ key: string; title: string }>,
+  },
+  /** 鐐瑰嚮鑺傜偣鍏宠仈/鐙珛鏃� 娓呯┖宸插嬀閫夌殑鑺傜偣 */
+  resetOnStrictlyChange: {
+    default: true,
+    type: Boolean,
+  },
+  treeData: {
+    default: () => [],
+    type: Array as PropType<DataNode[]>,
+  },
+});
+const emit = defineEmits<{ checkStrictlyChange: [boolean] }>();
+
+const expandStatus = ref(false);
+const selectAllStatus = ref(false);
+
+/**
+ * 鍚庡彴鐨勮繖涓瓧娈佃窡antd/ele鏄弽鐨�
+ * 缁勪欢搴撹繖涓瓧娈典唬琛ㄤ笉鍏宠仈
+ * 鍚庡彴杩欎釜浠h〃鍏宠仈
+ */
+const innerCheckedStrictly = computed(() => {
+  return !props.checkStrictly;
+});
+
+const associationText = computed(() => {
+  return props.checkStrictly ? '鐖跺瓙鑺傜偣鍏宠仈' : '鐖跺瓙鑺傜偣鐙珛';
+});
+
+/**
+ * 杩欎釜鍙敤浜庣晫闈㈡樉绀�
+ * 鍏宠仈鎯呭喌涓� 鍙細鏈夋渶鏈熬鐨勮妭鐐硅閫変腑
+ */
+const checkedKeys = defineModel('value', {
+  default: () => [],
+  type: Array as PropType<(number | string)[]>,
+});
+// 鎵�鏈夎妭鐐圭殑ID
+const allKeys = computed(() => {
+  const idField = props.fieldNames.key;
+  return treeToList(props.treeData).map((item: any) => item[idField]);
+});
+
+/** 宸茬粡閫夋嫨鐨勬墍鏈夎妭鐐�  鍖呮嫭瀛�/鐖惰妭鐐� 鐢ㄤ簬鎻愪氦 */
+const checkedRealKeys = ref<(number | string)[]>([]);
+
+/**
+ * 鍙栫涓�娆$殑menuTree id 璁剧疆鍒癱heckedMenuKeys
+ * 涓昏涓轰簡瑙e喅娌℃湁浠讳綍淇敼 鐩存帴鐐瑰嚮淇濆瓨鐨勬儏鍐�
+ *
+ * length涓�0鎯呭喌(鍗虫柊澧炴椂鍊欐病鏈夊嬀閫夎妭鐐�) 鍕鹃�夎繖閲屼細寤惰繜瑙﹀彂 鑺傜偣浼氭嫾鎺ヤ笂鐖惰妭鐐� 瀵艰嚧ID閲嶅
+ */
+const stop = watch([checkedKeys, () => props.treeData], () => {
+  if (
+    props.checkStrictly &&
+    checkedKeys.value.length > 0 &&
+    props.treeData.length > 0
+  ) {
+    /** 鎵惧埌鐖惰妭鐐� 娣诲姞涓� */
+    const parentIds = findGroupParentIds(
+      props.treeData,
+      checkedKeys.value as any,
+      { id: props.fieldNames.key },
+    );
+    /**
+     * uniq 瑙e喅涓婇潰鐨刬d閲嶅闂
+     */
+    checkedRealKeys.value = uniq([...parentIds, ...checkedKeys.value]);
+    stop();
+  }
+  if (!props.checkStrictly && checkedKeys.value.length > 0) {
+    /** 鑺傜偣鐙珛 杩欓噷鏄叏閮ㄧ殑鑺傜偣 */
+    checkedRealKeys.value = checkedKeys.value;
+    stop();
+  }
+});
+
+/**
+ *
+ * @param checkedStateKeys 宸茬粡閫変腑鐨勫瓙鑺傜偣鐨処D
+ * @param info info.halfCheckedKeys涓虹埗鑺傜偣鐨処D
+ */
+type CheckedState<T = number | string> =
+  | { checked: T[]; halfChecked: T[] }
+  | T[];
+function handleChecked(checkedStateKeys: CheckedState, info: CheckInfo) {
+  // 鏁扮粍鐨勮瘽涓鸿妭鐐瑰叧鑱�
+  if (Array.isArray(checkedStateKeys)) {
+    const halfCheckedKeys: number[] = (info.halfCheckedKeys || []) as number[];
+    checkedRealKeys.value = [...halfCheckedKeys, ...checkedStateKeys];
+  } else {
+    checkedRealKeys.value = [...checkedStateKeys.checked];
+    // fix: Invalid prop: type check failed for prop "value". Expected Array, got Object
+    checkedKeys.value = [...checkedStateKeys.checked];
+  }
+}
+
+function handleExpandChange(e: CheckboxChangeEvent) {
+  // 杩欎釜鐢ㄤ簬灞曠ず
+  checkedKeys.value = e.target.checked ? allKeys.value : [];
+  // 杩欎釜鐢ㄤ簬鎻愪氦
+  checkedRealKeys.value = e.target.checked ? allKeys.value : [];
+}
+
+const expandedKeys = ref<string[]>([]);
+function handleExpandOrCollapseAll(e: CheckboxChangeEvent) {
+  const expand = e.target.checked;
+  expandedKeys.value = expand ? allKeys.value : [];
+}
+
+function handleCheckStrictlyChange(e: CheckboxChangeEvent) {
+  emit('checkStrictlyChange', e.target.checked);
+  if (props.resetOnStrictlyChange) {
+    checkedKeys.value = [];
+    checkedRealKeys.value = [];
+  }
+}
+
+/**
+ * 鏆撮湶鏂规硶鏉ヨ幏鍙栫敤浜庢彁浜ょ殑鍏ㄩ儴鑺傜偣
+ * uniq鍘婚噸(淇濋櫓鏂规)
+ */
+defineExpose({
+  getCheckedKeys: () => uniq(checkedRealKeys.value),
+});
+
+onMounted(async () => {
+  if (props.expandAllOnInit) {
+    await nextTick();
+    expandedKeys.value = allKeys.value;
+  }
+});
+</script>
+
+<template>
+  <div class="bg-background w-full rounded-lg border-[1px] p-[12px]">
+    <div class="flex items-center justify-between gap-2 border-b-[1px] pb-2">
+      <div>
+        <span>鑺傜偣鐘舵��: </span>
+        <span :class="[props.checkStrictly ? 'text-primary' : 'text-red-500']">
+          {{ associationText }}
+        </span>
+      </div>
+      <div>
+        宸查�変腑
+        <span class="text-primary mx-1 font-semibold">
+          {{ checkedRealKeys.length }}
+        </span>
+        涓妭鐐�
+      </div>
+    </div>
+    <div
+      class="flex flex-wrap items-center justify-between border-b-[1px] py-2"
+    >
+      <Checkbox
+        v-model:checked="expandStatus"
+        @change="handleExpandOrCollapseAll"
+      >
+        灞曞紑/鎶樺彔鍏ㄩ儴
+      </Checkbox>
+      <Checkbox v-model:checked="selectAllStatus" @change="handleExpandChange">
+        鍏ㄩ��/鍙栨秷鍏ㄩ��
+      </Checkbox>
+      <Checkbox :checked="checkStrictly" @change="handleCheckStrictlyChange">
+        鐖跺瓙鑺傜偣鍏宠仈
+      </Checkbox>
+    </div>
+    <div class="py-2">
+      <Tree
+        v-if="treeData.length > 0"
+        v-model:check-strictly="innerCheckedStrictly"
+        v-model:checked-keys="checkedKeys"
+        v-model:expanded-keys="expandedKeys"
+        :checkable="true"
+        :field-names="fieldNames"
+        :selectable="false"
+        :tree-data="treeData"
+        @check="handleChecked"
+      >
+        <template
+          v-for="slotName in Object.keys($slots)"
+          :key="slotName"
+          #[slotName]="data"
+        >
+          <slot :name="slotName" v-bind="data ?? {}"></slot>
+        </template>
+      </Tree>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/components/upload/index.ts b/eims-ui/apps/web-antd/src/components/upload/index.ts
new file mode 100644
index 0000000..b86d495
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/index.ts
@@ -0,0 +1,2 @@
+export { default as FileUpload } from './src/file-upload.vue';
+export { default as ImageUpload } from './src/image-upload.vue';
diff --git a/eims-ui/apps/web-antd/src/components/upload/src/file-upload.vue b/eims-ui/apps/web-antd/src/components/upload/src/file-upload.vue
new file mode 100644
index 0000000..fbdae9c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/src/file-upload.vue
@@ -0,0 +1,216 @@
+<script lang="ts" setup>
+import type { UploadFile, UploadProps } from 'ant-design-vue';
+import type { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
+
+import { ref, toRefs, watch } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import { UploadOutlined } from '@ant-design/icons-vue';
+import { message, Upload } from 'ant-design-vue';
+import { isArray, isFunction, isObject, isString } from 'lodash-es';
+
+import { uploadApi } from '#/api';
+
+import { checkFileType } from './helper';
+import { UploadResultStatus } from './typing';
+import { useUploadType } from './use-upload';
+
+defineOptions({ name: 'FileUpload', inheritAttrs: false });
+
+const props = withDefaults(
+  defineProps<{
+    /**
+     * 寤鸿浣跨敤鎷撳睍鍚�(涓嶅甫.)
+     * 鎴栬�呮枃浠跺ご image/png绛�(娴嬭瘯鍒ゆ柇涓嶅噯纭�)  涓嶆敮鎸乮mage/*绫讳技鐨勫啓娉�
+     * 闇�鑷鏀归�� ./helper/checkFileType鏂规硶
+     */
+    accept?: string[];
+    api?: (...args: any[]) => Promise<any>;
+    disabled?: boolean;
+    helpText?: string;
+    // 鏈�澶ф暟閲忕殑鏂囦欢锛孖nfinity涓嶉檺鍒�
+    maxNumber?: number;
+    // 鏂囦欢鏈�澶у灏慚B
+    maxSize?: number;
+    // 鏄惁鏀寔澶氶��
+    multiple?: boolean;
+    // support xxx.xxx.xx
+    // 杩斿洖鐨勫瓧娈� 榛樿url
+    resultField?: 'fileName' | 'ossId' | 'url' | string;
+    value?: string[];
+  }>(),
+  {
+    value: () => [],
+    disabled: false,
+    helpText: '',
+    maxSize: 2,
+    maxNumber: 1,
+    accept: () => [],
+    multiple: false,
+    api: uploadApi,
+    resultField: '',
+  },
+);
+const emit = defineEmits(['change', 'update:value', 'delete']);
+const { accept, helpText, maxNumber, maxSize } = toRefs(props);
+const isInnerOperate = ref<boolean>(false);
+const { getStringAccept } = useUploadType({
+  acceptRef: accept,
+  helpTextRef: helpText,
+  maxNumberRef: maxNumber,
+  maxSizeRef: maxSize,
+});
+
+const fileList = ref<UploadProps['fileList']>([]);
+const isLtMsg = ref<boolean>(true);
+const isActMsg = ref<boolean>(true);
+const isFirstRender = ref<boolean>(true);
+
+watch(
+  () => props.value,
+  (v) => {
+    if (isInnerOperate.value) {
+      isInnerOperate.value = false;
+      return;
+    }
+    let value: string[] = [];
+    if (v) {
+      if (isArray(v)) {
+        value = v;
+      } else {
+        value.push(v);
+      }
+      fileList.value = value.map((item, i) => {
+        if (item && isString(item)) {
+          return {
+            uid: `${-i}`,
+            name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
+            status: 'done',
+            url: item,
+          };
+        } else if (item && isObject(item)) {
+          return item;
+        }
+        return null;
+      }) as UploadProps['fileList'];
+    }
+    if (!isFirstRender.value) {
+      emit('change', value);
+      isFirstRender.value = false;
+    }
+  },
+  {
+    immediate: true,
+    deep: true,
+  },
+);
+
+const handleRemove = async (file: UploadFile) => {
+  if (fileList.value) {
+    const index = fileList.value.findIndex((item) => item.uid === file.uid);
+    index !== -1 && fileList.value.splice(index, 1);
+    const value = getValue();
+    isInnerOperate.value = true;
+    emit('update:value', value);
+    emit('change', value);
+    emit('delete', file);
+  }
+};
+
+const beforeUpload = async (file: File) => {
+  const { maxSize, accept } = props;
+  const isAct = await checkFileType(file, accept);
+  if (!isAct) {
+    message.error($t('component.upload.acceptUpload', [accept]));
+    isActMsg.value = false;
+    // 闃叉寮瑰嚭澶氫釜閿欒鎻愮ず
+    setTimeout(() => (isActMsg.value = true), 1000);
+  }
+  const isLt = file.size / 1024 / 1024 > maxSize;
+  if (isLt) {
+    message.error($t('component.upload.maxSizeMultiple', [maxSize]));
+    isLtMsg.value = false;
+    // 闃叉寮瑰嚭澶氫釜閿欒鎻愮ず
+    setTimeout(() => (isLtMsg.value = true), 1000);
+  }
+  return (isAct && !isLt) || Upload.LIST_IGNORE;
+};
+
+async function customRequest(info: UploadRequestOption<any>) {
+  const { api } = props;
+  if (!api || !isFunction(api)) {
+    console.warn('upload api must exist and be a function');
+    return;
+  }
+  try {
+    const res = await api?.(info.file);
+    /**
+     * 鐢眊etValue澶勭悊 浼犲璞¤繃鍘�
+     * 鐩存帴浼爏tring(id)浼氳杞负Number
+     */
+    info.onSuccess!(res);
+    // 鑾峰彇
+    const value = getValue();
+    isInnerOperate.value = true;
+    emit('update:value', value);
+    emit('change', value);
+  } catch (error: any) {
+    console.error(error);
+    info.onError!(error);
+  }
+}
+
+function getValue() {
+  const list = (fileList.value || [])
+    .filter((item) => item?.status === UploadResultStatus.DONE)
+    .map((item: any) => {
+      if (item?.response && props?.resultField) {
+        return item?.response?.[props.resultField];
+      }
+      // 閫傜敤浜庡凡缁忔湁鍥剧墖 鍥炴樉鐨勬儏鍐� 浼氶粯璁ゅ湪init澶勭悊涓簕url: 'xx'}
+      if (item?.url) {
+        return item.url;
+      }
+      // 娉ㄦ剰杩欓噷鍙栫殑key涓� url
+      return item?.response?.url;
+    });
+  return list;
+}
+</script>
+
+<template>
+  <div>
+    <Upload
+      v-bind="$attrs"
+      v-model:file-list="fileList"
+      :accept="getStringAccept"
+      :before-upload="beforeUpload"
+      :custom-request="customRequest"
+      :disabled="disabled"
+      :max-count="maxNumber"
+      :multiple="multiple"
+      list-type="text"
+      @remove="handleRemove"
+    >
+      <div v-if="fileList && fileList.length < maxNumber">
+        <a-button>
+          <UploadOutlined />
+          {{ $t('component.upload.upload') }}
+        </a-button>
+      </div>
+    </Upload>
+  </div>
+</template>
+
+<style lang="less">
+.ant-upload-select-picture-card i {
+  color: #999;
+  font-size: 32px;
+}
+
+.ant-upload-select-picture-card .ant-upload-text {
+  margin-top: 8px;
+  color: #666;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/upload/src/helper.ts b/eims-ui/apps/web-antd/src/components/upload/src/helper.ts
new file mode 100644
index 0000000..ff70b41
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/src/helper.ts
@@ -0,0 +1,51 @@
+import { fileTypeFromBlob } from '@vben/utils';
+
+/**
+ * 涓嶆敮鎸乼xt鏂囦欢 @see https://github.com/sindresorhus/file-type/issues/55
+ * 闇�瑕佽嚜琛屼慨鏀�
+ * @param file file瀵硅薄
+ * @param accepts 鏂囦欢绫诲瀷鏁扮粍  鍖呮嫭鎷撳睍鍚�(涓嶅甫鐐�) 鏂囦欢澶�(image/png绛� 涓嶅寘鎷硾鍐欐硶鍗砳mage/*)
+ * @returns 鏄惁閫氳繃鏂囦欢绫诲瀷鏍¢獙
+ */
+export async function checkFileType(file: File, accepts: string[]) {
+  if (!accepts || accepts?.length === 0) {
+    return true;
+  }
+  console.log(file);
+  const fileType = await fileTypeFromBlob(file);
+  if (!fileType) {
+    console.error('鏃犳硶鑾峰彇鏂囦欢绫诲瀷');
+    return false;
+  }
+  console.log('鏂囦欢绫诲瀷', fileType);
+  // 鏄惁鏂囦欢鎷撳睍鍚�/鏂囦欢澶翠换鎰忔湁涓�涓尮閰�
+  return accepts.includes(fileType.ext) || accepts.includes(fileType.mime);
+}
+
+/**
+ * 榛樿鍥剧墖绫诲瀷
+ */
+export const defaultImageAccept = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+/**
+ * 鍒ゆ柇鏂囦欢绫诲瀷鏄惁绗﹀悎瑕佹眰
+ * @param file file瀵硅薄
+ * @param accepts 鏂囦欢绫诲瀷鏁扮粍  鍖呮嫭鎷撳睍鍚�(涓嶅甫鐐�) 鏂囦欢澶�(image/png绛� 涓嶅寘鎷硾鍐欐硶鍗砳mage/*)
+ * @returns 鏄惁閫氳繃鏂囦欢绫诲瀷鏍¢獙
+ */
+export async function checkImageFileType(file: File, accepts: string[]) {
+  // 绌虹殑accepts 浣跨敤榛樿瑙勫垯
+  if (!accepts || accepts.length === 0) {
+    accepts = defaultImageAccept;
+  }
+  const fileType = await fileTypeFromBlob(file);
+  if (!fileType) {
+    console.error('鏃犳硶鑾峰彇鏂囦欢绫诲瀷');
+    return false;
+  }
+  console.log('鏂囦欢绫诲瀷', fileType);
+  // 鏄惁鏂囦欢鎷撳睍鍚�/鏂囦欢澶翠换鎰忔湁涓�涓尮閰�
+  if (accepts.includes(fileType.ext) || accepts.includes(fileType.mime)) {
+    return true;
+  }
+  return false;
+}
diff --git a/eims-ui/apps/web-antd/src/components/upload/src/image-upload.vue b/eims-ui/apps/web-antd/src/components/upload/src/image-upload.vue
new file mode 100644
index 0000000..7548ea1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/src/image-upload.vue
@@ -0,0 +1,269 @@
+<script lang="ts" setup>
+import type { UploadFile, UploadProps } from 'ant-design-vue';
+import type { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
+
+import { ref, toRefs, watch } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import { PlusOutlined } from '@ant-design/icons-vue';
+import { message, Modal, Upload } from 'ant-design-vue';
+import { isArray, isFunction, isObject, isString } from 'lodash-es';
+
+import { uploadApi } from '#/api';
+
+import { checkImageFileType, defaultImageAccept } from './helper';
+import { UploadResultStatus } from './typing';
+import { useUploadType } from './use-upload';
+
+defineOptions({ name: 'ImageUpload', inheritAttrs: false });
+
+const props = withDefaults(
+  defineProps<{
+    /**
+     * 鍖呮嫭鎷撳睍鍚�(涓嶅甫鐐�) 鏂囦欢澶�(image/png绛� 涓嶅寘鎷硾鍐欐硶鍗砳mage/*)
+     */
+    accept?: string[];
+    api?: (...args: any[]) => Promise<any>;
+    disabled?: boolean;
+    helpText?: string;
+    // eslint-disable-next-line no-use-before-define
+    listType?: ListType;
+    // 鏈�澶ф暟閲忕殑鏂囦欢锛孖nfinity涓嶉檺鍒�
+    maxNumber?: number;
+    // 鏂囦欢鏈�澶у灏慚B
+    maxSize?: number;
+    // 鏄惁鏀寔澶氶��
+    multiple?: boolean;
+    // support xxx.xxx.xx
+    // 杩斿洖鐨勫瓧娈� 榛樿url
+    resultField?: 'fileName' | 'ossId' | 'url' | string;
+    value?: string | string[];
+  }>(),
+  {
+    value: () => [],
+    disabled: false,
+    listType: 'picture-card',
+    helpText: '',
+    maxSize: 2,
+    maxNumber: 1,
+    accept: () => defaultImageAccept,
+    multiple: false,
+    api: uploadApi,
+    resultField: '',
+  },
+);
+const emit = defineEmits(['change', 'update:value', 'delete']);
+type ListType = 'picture' | 'picture-card' | 'text';
+const { accept, helpText, maxNumber, maxSize } = toRefs(props);
+const isInnerOperate = ref<boolean>(false);
+const { getStringAccept } = useUploadType({
+  acceptRef: accept,
+  helpTextRef: helpText,
+  maxNumberRef: maxNumber,
+  maxSizeRef: maxSize,
+});
+const previewOpen = ref<boolean>(false);
+const previewImage = ref<string>('');
+const previewTitle = ref<string>('');
+
+const fileList = ref<UploadProps['fileList']>([]);
+const isLtMsg = ref<boolean>(true);
+const isActMsg = ref<boolean>(true);
+const isFirstRender = ref<boolean>(true);
+
+watch(
+  () => props.value,
+  (v) => {
+    if (isInnerOperate.value) {
+      isInnerOperate.value = false;
+      return;
+    }
+    let value: string | string[] = [];
+    if (v) {
+      const _fileList: string[] = [];
+      if (isString(v)) {
+        _fileList.push(v);
+      }
+      if (isArray(v)) {
+        _fileList.push(...v);
+      }
+      // 鐩存帴璧嬪�� 鍙兘涓簊tring | string[]
+      value = v;
+      fileList.value = _fileList.map((item, i) => {
+        if (item && isString(item)) {
+          return {
+            uid: `${-i}`,
+            name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
+            status: 'done',
+            url: item,
+          };
+        } else if (item && isObject(item)) {
+          return item;
+        }
+        return null;
+      }) as UploadProps['fileList'];
+    }
+    if (!isFirstRender.value) {
+      emit('change', value);
+      isFirstRender.value = false;
+    }
+  },
+  {
+    immediate: true,
+    deep: true,
+  },
+);
+
+function getBase64<T extends ArrayBuffer | null | string>(file: File) {
+  return new Promise<T>((resolve, reject) => {
+    const reader = new FileReader();
+    reader.readAsDataURL(file);
+    reader.addEventListener('load', () => {
+      resolve(reader.result as T);
+    });
+    reader.addEventListener('error', (error) => reject(error));
+  });
+}
+
+const handlePreview = async (file: UploadFile) => {
+  if (!file.url && !file.preview) {
+    file.preview = await getBase64<string>(file.originFileObj!);
+  }
+  previewImage.value = file.url || file.preview || '';
+  previewOpen.value = true;
+  previewTitle.value =
+    file.name ||
+    previewImage.value.slice(
+      Math.max(0, previewImage.value.lastIndexOf('/') + 1),
+    );
+};
+
+const handleRemove = async (file: UploadFile) => {
+  if (fileList.value) {
+    const index = fileList.value.findIndex((item) => item.uid === file.uid);
+    index !== -1 && fileList.value.splice(index, 1);
+    const value = getValue();
+    isInnerOperate.value = true;
+    emit('update:value', value);
+    emit('change', value);
+    emit('delete', file);
+  }
+};
+
+const handleCancel = () => {
+  previewOpen.value = false;
+  previewTitle.value = '';
+};
+
+const beforeUpload = async (file: File) => {
+  const { maxSize, accept } = props;
+  const isAct = await checkImageFileType(file, accept);
+  if (!isAct) {
+    message.error($t('component.upload.acceptUpload', [accept]));
+    isActMsg.value = false;
+    // 闃叉寮瑰嚭澶氫釜閿欒鎻愮ず
+    setTimeout(() => (isActMsg.value = true), 1000);
+  }
+  const isLt = file.size / 1024 / 1024 > maxSize;
+  if (isLt) {
+    message.error($t('component.upload.maxSizeMultiple', [maxSize]));
+    isLtMsg.value = false;
+    // 闃叉寮瑰嚭澶氫釜閿欒鎻愮ず
+    setTimeout(() => (isLtMsg.value = true), 1000);
+  }
+  return (isAct && !isLt) || Upload.LIST_IGNORE;
+};
+
+async function customRequest(info: UploadRequestOption<any>) {
+  const { api } = props;
+  if (!api || !isFunction(api)) {
+    console.warn('upload api must exist and be a function');
+    return;
+  }
+  try {
+    const res = await api?.(info.file);
+    /**
+     * 鐢眊etValue澶勭悊 浼犲璞¤繃鍘�
+     * 鐩存帴浼爏tring(id)浼氳杞负Number
+     */
+    info.onSuccess!(res);
+    // 鑾峰彇
+    const value = getValue();
+    isInnerOperate.value = true;
+    emit('update:value', value);
+    emit('change', value);
+  } catch (error: any) {
+    console.error(error);
+    info.onError!(error);
+  }
+}
+
+function getValue() {
+  const list = (fileList.value || [])
+    .filter((item) => item?.status === UploadResultStatus.DONE)
+    .map((item: any) => {
+      if (item?.response && props?.resultField) {
+        return item?.response?.[props.resultField];
+      }
+      // 閫傜敤浜庡凡缁忔湁鍥剧墖 鍥炴樉鐨勬儏鍐� 浼氶粯璁ゅ湪init澶勭悊涓簕url: 'xx'}
+      if (item?.url) {
+        return item.url;
+      }
+      // 娉ㄦ剰杩欓噷鍙栫殑key涓� url
+      return item?.response?.url;
+    });
+  // 鍙湁涓�寮犲浘鐗� 榛樿缁戝畾string鑰岄潪string[]
+  if (props.maxNumber === 1 && list.length === 1) {
+    return list[0];
+  }
+  // 鍙湁涓�寮犲浘鐗� && 鍒犻櫎鍥剧墖鏃� 鍙嚜琛屼慨鏀�
+  if (props.maxNumber === 1 && list.length === 0) {
+    return '';
+  }
+  return list;
+}
+</script>
+
+<template>
+  <div>
+    <Upload
+      v-bind="$attrs"
+      v-model:file-list="fileList"
+      :accept="getStringAccept"
+      :before-upload="beforeUpload"
+      :custom-request="customRequest"
+      :disabled="disabled"
+      :list-type="listType"
+      :max-count="maxNumber"
+      :multiple="multiple"
+      @preview="handlePreview"
+      @remove="handleRemove"
+    >
+      <div v-if="fileList && fileList.length < maxNumber">
+        <PlusOutlined />
+        <div style="margin-top: 8px">{{ $t('component.upload.upload') }}</div>
+      </div>
+    </Upload>
+    <Modal
+      :footer="null"
+      :open="previewOpen"
+      :title="previewTitle"
+      @cancel="handleCancel"
+    >
+      <img :src="previewImage" alt="" style="width: 100%" />
+    </Modal>
+  </div>
+</template>
+
+<style lang="less">
+.ant-upload-select-picture-card i {
+  color: #999;
+  font-size: 32px;
+}
+
+.ant-upload-select-picture-card .ant-upload-text {
+  margin-top: 8px;
+  color: #666;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/components/upload/src/typing.ts b/eims-ui/apps/web-antd/src/components/upload/src/typing.ts
new file mode 100644
index 0000000..8f87fe2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/src/typing.ts
@@ -0,0 +1,37 @@
+import type { Recordable } from '@vben/types';
+
+export enum UploadResultStatus {
+  DONE = 'done',
+  ERROR = 'error',
+  SUCCESS = 'success',
+  UPLOADING = 'uploading',
+}
+
+export interface FileItem {
+  thumbUrl?: string;
+  name: string;
+  size: number | string;
+  type?: string;
+  percent: number;
+  file: File;
+  status?: UploadResultStatus;
+  response?: { fileName: string; ossId: string; url: string } | Recordable<any>;
+  uuid: string;
+}
+
+export interface Wrapper {
+  record: FileItem;
+  uidKey: string;
+  valueKey: string;
+}
+
+export interface BaseFileItem {
+  uid: number | string;
+  url: string;
+  name?: string;
+}
+export interface PreviewFileItem {
+  url: string;
+  name: string;
+  type: string;
+}
diff --git a/eims-ui/apps/web-antd/src/components/upload/src/use-upload.ts b/eims-ui/apps/web-antd/src/components/upload/src/use-upload.ts
new file mode 100644
index 0000000..b8710f1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/components/upload/src/use-upload.ts
@@ -0,0 +1,60 @@
+import { computed, unref } from 'vue';
+import type { Ref } from 'vue';
+
+import { $t } from '@vben/locales';
+
+export function useUploadType({
+  acceptRef,
+  helpTextRef,
+  maxNumberRef,
+  maxSizeRef,
+}: {
+  acceptRef: Ref<string[]>;
+  helpTextRef: Ref<string>;
+  maxNumberRef: Ref<number>;
+  maxSizeRef: Ref<number>;
+}) {
+  // 鏂囦欢绫诲瀷闄愬埗
+  const getAccept = computed(() => {
+    const accept = unref(acceptRef);
+    if (accept && accept.length > 0) {
+      return accept;
+    }
+    return [];
+  });
+  const getStringAccept = computed(() => {
+    return unref(getAccept)
+      .map((item) => {
+        return item.indexOf('/') > 0 || item.startsWith('.')
+          ? item
+          : `.${item}`;
+      })
+      .join(',');
+  });
+
+  // 鏀寔jpg銆乯peg銆乸ng鏍煎紡锛屼笉瓒呰繃2M锛屾渶澶氬彲閫夋嫨10寮犲浘鐗囷紝銆�
+  const getHelpText = computed(() => {
+    const helpText = unref(helpTextRef);
+    if (helpText) {
+      return helpText;
+    }
+    const helpTexts: string[] = [];
+
+    const accept = unref(acceptRef);
+    if (accept.length > 0) {
+      helpTexts.push($t('component.upload.accept', [accept.join(',')]));
+    }
+
+    const maxSize = unref(maxSizeRef);
+    if (maxSize) {
+      helpTexts.push($t('component.upload.maxSize', [maxSize]));
+    }
+
+    const maxNumber = unref(maxNumberRef);
+    if (maxNumber && maxNumber !== Infinity) {
+      helpTexts.push($t('component.upload.maxNumber', [maxNumber]));
+    }
+    return helpTexts.join('锛�');
+  });
+  return { getAccept, getStringAccept, getHelpText };
+}
diff --git a/eims-ui/apps/web-antd/src/layouts/auth.vue b/eims-ui/apps/web-antd/src/layouts/auth.vue
new file mode 100644
index 0000000..18d415b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/layouts/auth.vue
@@ -0,0 +1,23 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { AuthPageLayout } from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+
+import { $t } from '#/locales';
+
+const appName = computed(() => preferences.app.name);
+const logo = computed(() => preferences.logo.source);
+</script>
+
+<template>
+  <AuthPageLayout
+    :app-name="appName"
+    :logo="logo"
+    :page-description="$t('authentication.pageDesc')"
+    :page-title="$t('authentication.pageTitle')"
+  >
+    <!-- 鑷畾涔夊伐鍏锋爮 -->
+    <!-- <template #toolbar></template> -->
+  </AuthPageLayout>
+</template>
diff --git a/eims-ui/apps/web-antd/src/layouts/basic.vue b/eims-ui/apps/web-antd/src/layouts/basic.vue
new file mode 100644
index 0000000..0a7dbef
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/layouts/basic.vue
@@ -0,0 +1,168 @@
+<script lang="ts" setup>
+import { computed, h, onMounted, watch } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
+import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
+import { useWatermark } from '@vben/hooks';
+import {
+  BookOpenText,
+  CircleHelp,
+  GiteeIcon,
+  GitHubOutlined,
+  UserOutlined,
+} from '@vben/icons';
+import {
+  BasicLayout,
+  LockScreen,
+  Notification,
+  UserDropdown,
+} from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import { message } from 'ant-design-vue';
+
+import { TenantToggle } from '#/components/tenant-toggle';
+import { $t } from '#/locales';
+import { resetRoutes } from '#/router';
+import { useAuthStore, useNotifyStore } from '#/store';
+import { useTenantStore } from '#/store/tenant';
+import LoginForm from '#/views/_core/authentication/login.vue';
+
+const userStore = useUserStore();
+const authStore = useAuthStore();
+const accessStore = useAccessStore();
+const router = useRouter();
+const { destroyWatermark, updateWatermark } = useWatermark();
+
+const tenantStore = useTenantStore();
+const menus = computed(() => {
+  const defaultMenus = [
+    {
+      handler: () => {
+        openWindow(VBEN_DOC_URL, {
+          target: '_blank',
+        });
+      },
+      icon: BookOpenText,
+      text: $t('ui.widgets.document'),
+    },
+    {
+      handler: () => {
+        router.push('/profile');
+      },
+      icon: UserOutlined,
+      text: $t('ui.widgets.profile'),
+    },
+    {
+      handler: () => {
+        openWindow('https://gitee.com/dapppp/ruoyi-plus-vben5', {
+          target: '_blank',
+        });
+      },
+      icon: () => h(GiteeIcon, { class: 'text-red-800' }),
+      text: 'Gitee椤圭洰鍦板潃',
+    },
+    {
+      handler: () => {
+        openWindow(VBEN_GITHUB_URL, {
+          target: '_blank',
+        });
+      },
+      icon: GitHubOutlined,
+      text: 'Vben瀹樻柟鍦板潃',
+    },
+    {
+      handler: () => {
+        openWindow(`${VBEN_GITHUB_URL}/issues`, {
+          target: '_blank',
+        });
+      },
+      icon: CircleHelp,
+      text: $t('ui.widgets.qa'),
+    },
+  ];
+  /**
+   * 绉熸埛閫変腑鐘舵�� 涓嶆樉绀轰釜浜轰腑蹇�
+   */
+  if (tenantStore.checked) {
+    defaultMenus.splice(1, 1);
+  }
+  return defaultMenus;
+});
+
+const avatar = computed(() => {
+  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
+});
+
+async function handleLogout() {
+  /**
+   * 涓诲姩鐧诲嚭涓嶉渶瑕佸甫璺宠浆鍦板潃
+   */
+  await authStore.logout(false);
+  resetRoutes();
+}
+
+const notifyStore = useNotifyStore();
+onMounted(() => notifyStore.startListeningMessage());
+
+function handleViewAll() {
+  message.warning('鏆傛湭寮�鏀�');
+}
+watch(
+  () => preferences.app.watermark,
+  async (enable) => {
+    if (enable) {
+      await updateWatermark({
+        content: `${userStore.userInfo?.username}`,
+      });
+    } else {
+      destroyWatermark();
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+</script>
+
+<template>
+  <BasicLayout @clear-preferences-and-logout="handleLogout">
+    <template #header-right-1>
+      <TenantToggle />
+    </template>
+    <template #user-dropdown>
+      <UserDropdown
+        :avatar
+        :menus
+        :text="userStore.userInfo?.realName"
+        description="shlanpu.cn"
+        tag-text="Pro"
+        @logout="handleLogout"
+      />
+    </template>
+    <template #notification>
+      <Notification
+        :dot="notifyStore.showDot"
+        :notifications="notifyStore.notifications"
+        @clear="notifyStore.clearAllMessage"
+        @make-all="notifyStore.setAllRead"
+        @read="notifyStore.setRead"
+        @view-all="handleViewAll"
+      />
+    </template>
+    <template #extra>
+      <AuthenticationLoginExpiredModal
+        v-model:open="accessStore.loginExpired"
+        :avatar
+      >
+        <LoginForm />
+      </AuthenticationLoginExpiredModal>
+    </template>
+    <template #lock-screen>
+      <LockScreen :avatar @to-login="handleLogout" />
+    </template>
+  </BasicLayout>
+</template>
diff --git a/eims-ui/apps/web-antd/src/layouts/index.ts b/eims-ui/apps/web-antd/src/layouts/index.ts
new file mode 100644
index 0000000..a432078
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/layouts/index.ts
@@ -0,0 +1,6 @@
+const BasicLayout = () => import('./basic.vue');
+const AuthPageLayout = () => import('./auth.vue');
+
+const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
+
+export { AuthPageLayout, BasicLayout, IFrameView };
diff --git a/eims-ui/apps/web-antd/src/locales/README.md b/eims-ui/apps/web-antd/src/locales/README.md
new file mode 100644
index 0000000..7b45103
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/README.md
@@ -0,0 +1,3 @@
+# locale
+
+姣忎釜app浣跨敤鐨勫浗闄呭寲鍙兘涓嶅悓锛岃繖閲岀敤浜庢墿灞曞浗闄呭寲鐨勫姛鑳斤紝渚嬪鎵╁睍 dayjs銆乤ntd缁勪欢搴撶殑澶氳瑷�鍒囨崲锛屼互鍙奱pp鏈韩鐨勫浗闄呭寲鏂囦欢銆�
diff --git a/eims-ui/apps/web-antd/src/locales/index.ts b/eims-ui/apps/web-antd/src/locales/index.ts
new file mode 100644
index 0000000..11fad68
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/index.ts
@@ -0,0 +1,100 @@
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+import type { Locale } from 'ant-design-vue/es/locale';
+
+import type { App } from 'vue';
+import { ref } from 'vue';
+
+import {
+  $t,
+  setupI18n as coreSetup,
+  loadLocalesMapFromDir,
+} from '@vben/locales';
+import { preferences } from '@vben/preferences';
+
+import antdEnLocale from 'ant-design-vue/es/locale/en_US';
+import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';
+import dayjs from 'dayjs';
+
+const antdLocale = ref<Locale>(antdDefaultLocale);
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
+/**
+ * 鍔犺浇搴旂敤鐗规湁鐨勮瑷�鍖�
+ * 杩欓噷涔熷彲浠ユ敼閫犱负浠庢湇鍔$鑾峰彇缈昏瘧鏁版嵁
+ * @param lang
+ */
+async function loadMessages(lang: SupportedLanguagesType) {
+  const [appLocaleMessages] = await Promise.all([
+    localesMap[lang](),
+    loadThirdPartyMessage(lang),
+  ]);
+  return appLocaleMessages.default;
+}
+
+/**
+ * 鍔犺浇绗笁鏂圭粍浠跺簱鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
+  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
+}
+
+/**
+ * 鍔犺浇dayjs鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    // 榛樿浣跨敤鑻辫
+    default: {
+      locale = await import('dayjs/locale/en');
+    }
+  }
+  if (locale) {
+    dayjs.locale(locale);
+  } else {
+    console.error(`Failed to load dayjs locale for ${lang}`);
+  }
+}
+
+/**
+ * 鍔犺浇antd鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadAntdLocale(lang: SupportedLanguagesType) {
+  switch (lang) {
+    case 'en-US': {
+      antdLocale.value = antdEnLocale;
+      break;
+    }
+    case 'zh-CN': {
+      antdLocale.value = antdDefaultLocale;
+      break;
+    }
+  }
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+  await coreSetup(app, {
+    defaultLocale: preferences.app.locale,
+    loadMessages,
+    missingWarn: !import.meta.env.PROD,
+    ...options,
+  });
+}
+
+export { $t, antdLocale, setupI18n };
diff --git a/eims-ui/apps/web-antd/src/locales/langs/en-US/component.json b/eims-ui/apps/web-antd/src/locales/langs/en-US/component.json
new file mode 100644
index 0000000..c8ebf68
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/en-US/component.json
@@ -0,0 +1,55 @@
+{
+  "cropper": {
+    "selectImage": "Select Image",
+    "uploadSuccess": "Uploaded success!",
+    "imageTooBig": "Image too big",
+    "modalTitle": "Avatar upload",
+    "okText": "Confirm and upload",
+    "btn_reset": "Reset",
+    "btn_rotate_left": "Counterclockwise rotation",
+    "btn_rotate_right": "Clockwise rotation",
+    "btn_scale_x": "Flip horizontal",
+    "btn_scale_y": "Flip vertical",
+    "btn_zoom_in": "Zoom in",
+    "btn_zoom_out": "Zoom out",
+    "preview": "Preview"
+  },
+  "tenantToggle": {
+    "placeholder": "Please select a tenant",
+    "switch": "Switch to tenant: ",
+    "reset": "Reset to default tenant"
+  },
+  "notice": {
+    "title": "Notice",
+    "received": "You have received a new message"
+  },
+  "upload": {
+    "save": "Save",
+    "upload": "Upload",
+    "imgUpload": "ImageUpload",
+    "uploaded": "Uploaded",
+    "operating": "Operating",
+    "del": "Delete",
+    "download": "download",
+    "saveWarn": "Please wait for the file to upload and save!",
+    "saveError": "There is no file successfully uploaded and cannot be saved!",
+    "preview": "Preview",
+    "choose": "Select the file",
+    "accept": "Support {0} format",
+    "acceptUpload": "Only upload files in {0} format",
+    "maxSize": "A single file does not exceed {0}MB ",
+    "maxSizeMultiple": "Only upload files up to {0}MB!",
+    "maxNumber": "Only upload up to {0} files",
+    "legend": "Legend",
+    "fileName": "File name",
+    "fileSize": "File size",
+    "fileStatue": "File status",
+    "pending": "Pending",
+    "startUpload": "Start upload",
+    "uploadSuccess": "Upload successfully",
+    "uploadError": "Upload failed",
+    "uploading": "Uploading",
+    "uploadWait": "Please wait for the file upload to finish",
+    "reUploadFailed": "Re-upload failed files"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/en-US/demos.json b/eims-ui/apps/web-antd/src/locales/langs/en-US/demos.json
new file mode 100644
index 0000000..0715643
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/en-US/demos.json
@@ -0,0 +1,12 @@
+{
+  "title": "Demos",
+  "antd": "Ant Design Vue",
+  "vben": {
+    "title": "Project",
+    "about": "About",
+    "document": "Document",
+    "antdv": "Ant Design Vue Version",
+    "naive-ui": "Naive UI Version",
+    "element-plus": "Element Plus Version"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/en-US/menu.json b/eims-ui/apps/web-antd/src/locales/langs/en-US/menu.json
new file mode 100644
index 0000000..ac93f71
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/en-US/menu.json
@@ -0,0 +1,55 @@
+{
+  "root": "Root",
+  "system": {
+    "root": "System",
+    "user": "User",
+    "role": "Role",
+    "menu": "Menu",
+    "dept": "Department",
+    "post": "Post",
+    "dict": "Dictionary",
+    "config": "Parameter Settings",
+    "notice": "Notifications",
+    "log": {
+      "root": "Log",
+      "operation": "Operation Log",
+      "login": "Login Log"
+    },
+    "oss": "File",
+    "client": "Client"
+  },
+  "tenant": {
+    "root": "Tenant",
+    "package": "Package"
+  },
+  "monitor": {
+    "root": "System Monitoring",
+    "online": "Online Users",
+    "cache": "Cache Monitoring",
+    "admin": "Admin Monitoring",
+    "job": "Task Scheduling Center"
+  },
+  "tool": {
+    "root": "System Tools",
+    "gen": "Code Generation"
+  },
+  "workflow": {
+    "root": "Workflow",
+    "category": "Process Category",
+    "model": "Model",
+    "define": "Process Definition",
+    "monitor": {
+      "root": "Process Monitoring",
+      "instance": "Process Instance",
+      "todo": "Pending Tasks"
+    },
+    "form": "Form"
+  },
+  "task": {
+    "root": "My Tasks",
+    "apply": "My Initiated Tasks",
+    "todo": "My Pending Tasks",
+    "done": "My Completed Tasks",
+    "cc": "My CC"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/en-US/page.json b/eims-ui/apps/web-antd/src/locales/langs/en-US/page.json
new file mode 100644
index 0000000..8fe0f0c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/en-US/page.json
@@ -0,0 +1,15 @@
+{
+  "auth": {
+    "login": "Login",
+    "register": "Register",
+    "codeLogin": "Code Login",
+    "qrcodeLogin": "Qr Code Login",
+    "forgetPassword": "Forget Password",
+    "oauthLogin": "Oauth Login"
+  },
+  "dashboard": {
+    "title": "Dashboard",
+    "analytics": "Analytics",
+    "workspace": "Workspace"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/en-US/pages.json b/eims-ui/apps/web-antd/src/locales/langs/en-US/pages.json
new file mode 100644
index 0000000..ea66e51
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/en-US/pages.json
@@ -0,0 +1,23 @@
+{
+  "common": {
+    "add": "Add",
+    "edit": "Edit",
+    "delete": "Delete",
+    "more": "More",
+    "search": "Search",
+    "reset": "Reset",
+    "import": "Import",
+    "export": "Export",
+    "expand": "Expand",
+    "collapse": "Collapse",
+    "info": "Info",
+    "clear": "Clear",
+    "unlock": "Unlock",
+    "download": "Download",
+    "sync": "Sync",
+    "refresh": "Refresh",
+    "generate": "Generate",
+    "downloadLoading": "Downloading... Please wait.",
+    "preview": "Preview"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/zh-CN/component.json b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/component.json
new file mode 100644
index 0000000..b0ef5a2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/component.json
@@ -0,0 +1,55 @@
+{
+  "cropper": {
+    "selectImage": "閫夋嫨鍥剧墖",
+    "uploadSuccess": "涓婁紶鎴愬姛",
+    "imageTooBig": "鍥剧墖瓒呴檺",
+    "modalTitle": "澶村儚涓婁紶",
+    "okText": "纭骞朵笂浼�",
+    "btn_reset": "閲嶇疆",
+    "btn_rotate_left": "閫嗘椂閽堟棆杞�",
+    "btn_rotate_right": "椤烘椂閽堟棆杞�",
+    "btn_scale_x": "姘村钩缈昏浆",
+    "btn_scale_y": "鍨傜洿缈昏浆",
+    "btn_zoom_in": "鏀惧ぇ",
+    "btn_zoom_out": "缂╁皬",
+    "preview": "棰勮"
+  },
+  "tenantToggle": {
+    "placeholder": "閫夋嫨绉熸埛",
+    "switch": "鍒囨崲褰撳墠绉熸埛涓�: ",
+    "reset": "杩樺師涓洪粯璁ょ鎴�"
+  },
+  "notice": {
+    "title": "娑堟伅",
+    "received": "鏀跺埌鏂版秷鎭�"
+  },
+  "upload": {
+    "save": "淇濆瓨",
+    "upload": "涓婁紶",
+    "imgUpload": "鍥剧墖涓婁紶",
+    "uploaded": "宸蹭笂浼�",
+    "operating": "鎿嶄綔",
+    "del": "鍒犻櫎",
+    "download": "涓嬭浇",
+    "saveWarn": "璇风瓑寰呮枃浠朵笂浼犲悗锛屼繚瀛�!",
+    "saveError": "娌℃湁涓婁紶鎴愬姛鐨勬枃浠讹紝鏃犳硶淇濆瓨!",
+    "preview": "棰勮",
+    "choose": "閫夋嫨鏂囦欢",
+    "accept": "鏀寔{0}鏍煎紡",
+    "acceptUpload": "鍙兘涓婁紶{0}鏍煎紡鏂囦欢",
+    "maxSize": "鍗曚釜鏂囦欢涓嶈秴杩噞0}MB",
+    "maxSizeMultiple": "鍙兘涓婁紶涓嶈秴杩噞0}MB鐨勬枃浠�!",
+    "maxNumber": "鏈�澶氬彧鑳戒笂浼爗0}涓枃浠�",
+    "legend": "鐣ョ缉鍥�",
+    "fileName": "鏂囦欢鍚�",
+    "fileSize": "鏂囦欢澶у皬",
+    "fileStatue": "鐘舵��",
+    "pending": "寰呬笂浼�",
+    "startUpload": "寮�濮嬩笂浼�",
+    "uploadSuccess": "涓婁紶鎴愬姛",
+    "uploadError": "涓婁紶澶辫触",
+    "uploading": "涓婁紶涓�",
+    "uploadWait": "璇风瓑寰呮枃浠朵笂浼犵粨鏉熷悗鎿嶄綔",
+    "reUploadFailed": "閲嶆柊涓婁紶澶辫触鏂囦欢"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/zh-CN/demos.json b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/demos.json
new file mode 100644
index 0000000..93ee722
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/demos.json
@@ -0,0 +1,12 @@
+{
+  "title": "婕旂ず",
+  "antd": "Ant Design Vue",
+  "vben": {
+    "title": "椤圭洰",
+    "about": "鍏充簬",
+    "document": "鏂囨。",
+    "antdv": "Ant Design Vue 鐗堟湰",
+    "naive-ui": "Naive UI 鐗堟湰",
+    "element-plus": "Element Plus 鐗堟湰"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/zh-CN/menu.json b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/menu.json
new file mode 100644
index 0000000..6772532
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/menu.json
@@ -0,0 +1,55 @@
+{
+  "root": "鏍圭洰褰�",
+  "system": {
+    "root": "绯荤粺绠$悊",
+    "user": "鐢ㄦ埛绠$悊",
+    "role": "瑙掕壊绠$悊",
+    "menu": "鑿滃崟绠$悊",
+    "dept": "閮ㄩ棬绠$悊",
+    "post": "宀椾綅绠$悊",
+    "dict": "瀛楀吀绠$悊",
+    "config": "鍙傛暟璁剧疆",
+    "notice": "閫氱煡鍏憡",
+    "log": {
+      "root": "鏃ュ織绠$悊",
+      "operation": "鎿嶄綔鏃ュ織",
+      "login": "鐧诲綍鏃ュ織"
+    },
+    "oss": "鏂囦欢绠$悊",
+    "client": "瀹㈡埛绔鐞�"
+  },
+  "tenant": {
+    "root": "绉熸埛绠$悊",
+    "package": "濂楅绠$悊"
+  },
+  "monitor": {
+    "root": "绯荤粺鐩戞帶",
+    "online": "鍦ㄧ嚎鐢ㄦ埛",
+    "cache": "缂撳瓨鐩戞帶",
+    "admin": "Admin鐩戞帶",
+    "job": "浠诲姟璋冨害涓績"
+  },
+  "tool": {
+    "root": "绯荤粺宸ュ叿",
+    "gen": "浠g爜鐢熸垚"
+  },
+  "workflow": {
+    "root": "宸ヤ綔娴�",
+    "category": "娴佺▼鍒嗙被",
+    "model": "妯″瀷绠$悊",
+    "define": "娴佺▼瀹氫箟",
+    "monitor": {
+      "root": "娴佺▼鐩戞帶",
+      "instance": "娴佺▼瀹炰緥",
+      "todo": "寰呭姙浠诲姟"
+    },
+    "form": "琛ㄥ崟绠$悊"
+  },
+  "task": {
+    "root": "鎴戠殑浠诲姟",
+    "apply": "鎴戝彂璧风殑",
+    "todo": "鎴戠殑寰呭姙",
+    "done": "鎴戠殑宸插姙",
+    "cc": "鎴戠殑鎶勯��"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/zh-CN/page.json b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/page.json
new file mode 100644
index 0000000..34a3c11
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/page.json
@@ -0,0 +1,18 @@
+{
+  "auth": {
+    "login": "鐧诲綍",
+    "register": "娉ㄥ唽",
+    "codeLogin": "楠岃瘉鐮佺櫥褰�",
+    "qrcodeLogin": "浜岀淮鐮佺櫥褰�",
+    "forgetPassword": "蹇樿瀵嗙爜",
+    "oauthLogin": "绗笁鏂圭櫥褰�"
+  },
+  "dashboard": {
+    "title": "姒傝",
+    "analytics": "鍒嗘瀽椤�",
+    "workspace": "宸ヤ綔鍙�"
+  },
+  "index": {
+    "title": "棣栭〉"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/locales/langs/zh-CN/pages.json b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/pages.json
new file mode 100644
index 0000000..1bff1bb
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/locales/langs/zh-CN/pages.json
@@ -0,0 +1,23 @@
+{
+  "common": {
+    "add": "鏂板",
+    "edit": "缂栬緫",
+    "delete": "鍒犻櫎",
+    "more": "鏇村",
+    "search": "鎼滅储",
+    "reset": "閲嶇疆",
+    "import": "瀵煎叆",
+    "export": "瀵煎嚭",
+    "expand": "灞曞紑",
+    "collapse": "鏀惰捣",
+    "info": "璇︽儏",
+    "clear": "娓呯┖",
+    "unlock": "瑙i攣",
+    "download": "涓嬭浇",
+    "sync": "鍚屾",
+    "refresh": "鍒锋柊",
+    "generate": "鐢熸垚",
+    "downloadLoading": "涓嬭浇涓�, 璇风◢鍚�...",
+    "preview": "棰勮"
+  }
+}
diff --git a/eims-ui/apps/web-antd/src/main.ts b/eims-ui/apps/web-antd/src/main.ts
new file mode 100644
index 0000000..5d728a0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/main.ts
@@ -0,0 +1,31 @@
+import { initPreferences } from '@vben/preferences';
+import { unmountGlobalLoading } from '@vben/utils';
+
+import { overridesPreferences } from './preferences';
+
+/**
+ * 搴旂敤鍒濆鍖栧畬鎴愪箣鍚庡啀杩涜椤甸潰鍔犺浇娓叉煋
+ */
+async function initApplication() {
+  // name鐢ㄤ簬鎸囧畾椤圭洰鍞竴鏍囪瘑
+  // 鐢ㄤ簬鍖哄垎涓嶅悓椤圭洰鐨勫亸濂借缃互鍙婂瓨鍌ㄦ暟鎹殑key鍓嶇紑浠ュ強鍏朵粬涓�浜涢渶瑕侀殧绂荤殑鏁版嵁
+  const env = import.meta.env.PROD ? 'prod' : 'dev';
+  const appVersion = import.meta.env.VITE_APP_VERSION;
+  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
+
+  // app鍋忓ソ璁剧疆鍒濆鍖�
+  await initPreferences({
+    namespace,
+    overrides: overridesPreferences,
+  });
+
+  // 鍚姩搴旂敤骞舵寕杞�
+  // vue搴旂敤涓昏閫昏緫鍙婅鍥�
+  const { bootstrap } = await import('./bootstrap');
+  await bootstrap(namespace);
+
+  // 绉婚櫎骞堕攢姣乴oading
+  unmountGlobalLoading();
+}
+
+initApplication();
diff --git a/eims-ui/apps/web-antd/src/preferences.ts b/eims-ui/apps/web-antd/src/preferences.ts
new file mode 100644
index 0000000..e85a5a4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/preferences.ts
@@ -0,0 +1,70 @@
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 椤圭洰閰嶇疆鏂囦欢
+ * 鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆
+ * !!! 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    /**
+     * 涓嶈鍔ㄨ繖閲�  鍚庣璺敱妯″紡
+     */
+    accessMode: 'backend',
+    /**
+     * 涓嶉渶瑕乺efresh token 鐢卞悗绔鐞�
+     */
+    enableRefreshToken: false,
+    /**
+     * 杩欓噷鍙互璁剧疆榛樿澶村儚 url閾炬帴鎴杤ite瀵煎叆鐨勫浘鐗囬摼鎺�
+     */
+    // defaultAvatar: '',
+    name: import.meta.env.VITE_APP_TITLE,
+    /**
+     * 涓嶆敮鎸乵odal妯″紡 闇�瑕佹敼鍔ㄧ殑鍦版柟澶
+     * 1. 姝e父閲嶆柊鐧诲綍鍚庝笉浼氬啀瑙﹀彂鎺ュ彛璇锋眰 鍗宠Е鍙戠櫥褰曡秴鏃剁殑椤甸潰涓虹┖鏁版嵁
+     * 2. 鍒囨崲绉熸埛鐧诲綍鍚庝笉浼氶噸鏂板姞杞借彍鍗�
+     */
+    // loginExpiredMode: 'modal',
+    layout: 'mixed-nav'
+  },
+  sidebar: {
+    'collapsed': false
+  },
+  footer: {
+    /**
+     * 涓嶆樉绀篺ooter
+     */
+    enable: false,
+  },
+  tabbar: {
+    /**
+     * 鏍囩tab 鎸佷箙鍖� 鍏抽棴
+     */
+    persist: false,
+    // styleType: 'card',
+  },
+  theme: {
+    /**
+     * 娴呰壊sidebar
+     */
+    semiDarkSidebar: false,
+  },
+  /**
+   * !!! 鏇存敼閰嶇疆鍚庤娓呯┖娴忚鍣ㄧ紦瀛�
+   * 鍦ㄨ繖閲屾洿鎹ogo
+   * source鍙�夊�硷細
+   * 1. 鏈湴public鐩綍涓嬬殑鍥剧墖 闇�瑕佸姞涓�/ 姣斿锛�/logo.png
+   * 2. 缃戠粶鍥剧墖閾炬帴
+   * 3. vite瀵煎叆鐨勫浘鐗� import xxx from 'xxx.png'
+   *
+   * !!! 鏇存敼閰嶇疆鍚庤娓呯┖娴忚鍣ㄧ紦瀛�
+   */
+  // logo: {
+  //   enable: true,
+  //   source: '',
+  // },
+});
+
+
diff --git a/eims-ui/apps/web-antd/src/router/access.ts b/eims-ui/apps/web-antd/src/router/access.ts
new file mode 100644
index 0000000..42769f5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/access.ts
@@ -0,0 +1,221 @@
+import type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+  RouteRecordStringComponent,
+} from '@vben/types';
+
+import { generateAccessible } from '@vben/access';
+import { preferences } from '@vben/preferences';
+
+import { message } from 'ant-design-vue';
+import { cloneDeep } from 'lodash-es';
+
+import { getAllMenusApi, type Menu } from '#/api';
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+import { localMenuList } from './routes/local';
+
+const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
+const NotFoundComponent = () => import('#/views/_core/fallback/not-found.vue');
+
+/**
+ * 鍚庡彴璺敱杞瑅ben璺敱
+ * @param menuList 鍚庡彴鑿滃崟
+ * @param parentPath 涓婄骇鐩綍
+ * @returns vben璺敱
+ */
+function backMenuToVbenMenu(
+  menuList: Menu[],
+  parentPath = '',
+): RouteRecordStringComponent[] {
+  const resultList: RouteRecordStringComponent[] = [];
+  menuList.forEach((menu) => {
+    // 鏍圭洰褰曚负鑿滃崟褰㈠紡
+    // 鍥哄畾鏈変竴涓猚hildren  children涓哄綋鍓嶈彍鍗�
+    if (menu.path === '/' && menu.children && menu.children.length === 1) {
+      if (!menu.children || !menu.children[0]) {
+        return;
+      }
+
+      // 闇�瑕佸鐞嗘牴鐩綍涓哄唴宓岀殑鎯呭喌 涓嶄細甯nnerLink
+      if (/^https?:\/\//.test(menu.children[0].path)) {
+        menu.children[0].component = 'InnerLink';
+        menu.children[0].path = menu.children[0].path
+          .replaceAll(/^https?:\/\//g, '')
+          .replaceAll('/#/', '')
+          .replaceAll('#', '')
+          .replaceAll(/[?&]/g, '');
+      }
+
+      // 鍙栧瓙璺緞浣滀负鐖剁骇璺緞
+      const path = menu.children[0].path;
+      // 鍙栧瓙鑿滃崟鐨刴eta浣滀负褰撳墠鑿滃崟鐨刴eta
+      menu.meta = menu.children[0].meta;
+      // 鐢变簬鍦ㄤ竴绾ц矾鐢� 鐖剁骇璺緞闇�瑕佸姞涓�/
+      menu.path = `/${path}`;
+      menu.component = 'RootMenu';
+      // 灏嗗瓙璺緞璁剧疆涓�''
+      menu.children[0].path = '';
+    }
+
+    // 澶栭摼: http寮�澶� & 缁勪欢涓篖ayout || ParentView
+    // 姝e垯鍒ゆ柇鏄惁涓篽ttp://鎴栬�卙ttps://寮�澶�
+    if (
+      /^https?:\/\//.test(menu.path) &&
+      (menu.component === 'Layout' || menu.component === 'ParentView')
+    ) {
+      menu.component = 'Link';
+    }
+
+    // 鍐呭祵iframe 缁勪欢涓篒nnerLink
+    if (menu.meta?.link && menu.component === 'InnerLink') {
+      menu.component = 'IFrameView';
+    }
+
+    /**
+     * 鎷兼帴path
+     * menu.path涓�''(鏍圭洰褰曡矾鐢�) 鍒欎笉鎷兼帴
+     */
+    if (parentPath && menu.path) {
+      menu.path = `${parentPath}/${menu.path}`;
+    }
+
+    // 鍒涘缓vben璺敱瀵硅薄
+    const vbenRoute: RouteRecordStringComponent = {
+      component: menu.component,
+      meta: {
+        // 褰撳墠璺敱涓嶅湪鑿滃崟鏄剧ず 浣嗘槸鍙互閫氳繃閾炬帴璁块棶
+        // 涓嶅彲璁块棶鐨勮矾鐢辩敱鍚庣鎺у埗闅愯棌(涓嶈繑鍥炲搴旇矾鐢�)
+        hideInMenu: menu.hidden,
+        icon: menu.meta?.icon,
+        keepAlive: !menu.meta?.noCache,
+        title: menu.meta?.title,
+      },
+      name: menu.name,
+      path: menu.path,
+    };
+
+    // 娣诲姞璺敱鍙傛暟淇℃伅
+    if (menu.query) {
+      try {
+        const query = JSON.parse(menu.query);
+        vbenRoute.meta && (vbenRoute.meta.query = query);
+      } catch {
+        console.error('閿欒鐨勮矾鐢卞弬鏁扮被鍨�, 蹇呴』涓篬json]鏍煎紡');
+      }
+    }
+
+    /**
+     * 澶勭悊涓嶅悓缁勪欢
+     */
+    switch (menu.component) {
+      /**
+       * iframe鍐呭祵
+       */
+      case 'IFrameView': {
+        vbenRoute.component = 'IFrameView';
+        if (vbenRoute.meta) {
+          vbenRoute.meta.iframeSrc = menu.meta.link;
+        }
+        /**
+         * 闇�瑕佸垽鏂壒娈婃儏鍐�  姣斿vue鐨刪ash鏄甫#鐨�
+         * 姣斿閾炬帴 aaa.com/#/bbb  path浼氳浆鎹负 aaa/com/#/bbb
+         * 姣斿閾炬帴 aaa.com/?bbb=xxx
+         * 闇�瑕佸幓闄�#  鍚﹀垯鏃犳硶琚坊鍔犲埌璺敱
+         */
+        vbenRoute.path = vbenRoute.path
+          // 鏇挎崲https:// 鎴栬�� http://
+          .replaceAll(/^https?:\/\//g, '')
+          .replaceAll('/#/', '')
+          .replaceAll('#', '')
+          .replaceAll(/[?&]/g, '');
+        break;
+      }
+      case 'Layout': {
+        vbenRoute.component = 'BasicLayout';
+        break;
+      }
+      /**
+       * 澶栭摼 鏂扮獥鍙f墦寮�
+       */
+      case 'Link': {
+        if (vbenRoute.meta) {
+          vbenRoute.meta.link = menu.meta.link;
+        }
+        vbenRoute.component = 'BasicLayout';
+        break;
+      }
+      /**
+       * 涓夌骇浠ヤ笂鑿滃崟 鐖剁骇component涓篜arentView
+       * 涓嶈兘涓簂ayout 浼氬涓ゅ眰BasicLayout
+       */
+      case 'ParentView': {
+        vbenRoute.component = '';
+        break;
+      }
+      /**
+       * 鏍圭洰褰曡彍鍗�
+       */
+      case 'RootMenu': {
+        if (vbenRoute.meta) {
+          vbenRoute.meta.hideChildrenInMenu = true;
+        }
+        vbenRoute.component = 'BasicLayout';
+        break;
+      }
+      /**
+       * 鍏朵粬鑷畾涔夌粍浠� 濡俿ystem/user/index 鎷兼帴/
+       */
+      default: {
+        vbenRoute.component = `/${menu.component}`;
+        break;
+      }
+    }
+
+    // children澶勭悊
+    if (menu.children && menu.children.length > 0) {
+      vbenRoute.children = backMenuToVbenMenu(menu.children, menu.path);
+    }
+    // 娣诲姞
+    resultList.push(vbenRoute);
+  });
+  return resultList;
+}
+
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
+
+  const layoutMap: ComponentRecordType = {
+    BasicLayout,
+    IFrameView,
+    NotFoundComponent,
+  };
+
+  return await generateAccessible(preferences.app.accessMode, {
+    ...options,
+    fetchMenuListAsync: async () => {
+      // 娓呴櫎浠ュ墠鐨刴essage
+      message.destroy();
+      message.loading({
+        content: `${$t('common.loadingMenu')}...`,
+        duration: 1,
+      });
+      // 鍚庡彴杩斿洖璺敱/鑿滃崟
+      const backMenuList = await getAllMenusApi();
+      // 杞崲涓簐ben鑳界敤鐨勮矾鐢�
+      const vbenMenuList = backMenuToVbenMenu(backMenuList);
+      // 鐗瑰埆娉ㄦ剰 杩欓噷瑕佹繁鎷疯礉
+      const menuList = [...cloneDeep(localMenuList), ...vbenMenuList];
+      // console.log('menuList', menuList);
+      return menuList;
+    },
+    // 鍙互鎸囧畾娌℃湁鏉冮檺璺宠浆403椤甸潰
+    forbiddenComponent,
+    // 濡傛灉 route.meta.menuVisibleWithForbidden = true
+    layoutMap,
+    pageMap,
+  });
+}
+
+export { generateAccess };
diff --git a/eims-ui/apps/web-antd/src/router/guard.ts b/eims-ui/apps/web-antd/src/router/guard.ts
new file mode 100644
index 0000000..fce5a89
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/guard.ts
@@ -0,0 +1,125 @@
+import type { Router } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { startProgress, stopProgress } from '@vben/utils';
+
+import { accessRoutes, coreRouteNames } from '#/router/routes';
+import { useAuthStore } from '#/store';
+
+import { generateAccess } from './access';
+
+/**
+ * 閫氱敤瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupCommonGuard(router: Router) {
+  // 璁板綍宸茬粡鍔犺浇鐨勯〉闈�
+  const loadedPaths = new Set<string>();
+
+  router.beforeEach(async (to) => {
+    to.meta.loaded = loadedPaths.has(to.path);
+
+    // 椤甸潰鍔犺浇杩涘害鏉�
+    if (!to.meta.loaded && preferences.transition.progress) {
+      startProgress();
+    }
+    return true;
+  });
+
+  router.afterEach((to) => {
+    // 璁板綍椤甸潰鏄惁鍔犺浇,濡傛灉宸茬粡鍔犺浇锛屽悗缁殑椤甸潰鍒囨崲鍔ㄧ敾绛夋晥鏋滀笉鍦ㄩ噸澶嶆墽琛�
+
+    loadedPaths.add(to.path);
+
+    // 鍏抽棴椤甸潰鍔犺浇杩涘害鏉�
+    if (preferences.transition.progress) {
+      stopProgress();
+    }
+  });
+}
+
+/**
+ * 鏉冮檺璁块棶瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupAccessGuard(router: Router) {
+  router.beforeEach(async (to, from) => {
+    const accessStore = useAccessStore();
+    const userStore = useUserStore();
+    const authStore = useAuthStore();
+
+    // 鍩烘湰璺敱锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴�
+    if (coreRouteNames.includes(to.name as string)) {
+      if (to.path === LOGIN_PATH && accessStore.accessToken) {
+        return decodeURIComponent(
+          (to.query?.redirect as string) || DEFAULT_HOME_PATH,
+        );
+      }
+      return true;
+    }
+
+    // accessToken 妫�鏌�
+    if (!accessStore.accessToken) {
+      // 鏄庣‘澹版槑蹇界暐鏉冮檺璁块棶鏉冮檺锛屽垯鍙互璁块棶
+      if (to.meta.ignoreAccess) {
+        return true;
+      }
+
+      // 娌℃湁璁块棶鏉冮檺锛岃烦杞櫥褰曢〉闈�
+      if (to.fullPath !== LOGIN_PATH) {
+        return {
+          path: LOGIN_PATH,
+          // 濡備笉闇�瑕侊紝鐩存帴鍒犻櫎 query
+          query: { redirect: encodeURIComponent(to.fullPath) },
+          // 鎼哄甫褰撳墠璺宠浆鐨勯〉闈紝鐧诲綍鍚庨噸鏂拌烦杞椤甸潰
+          replace: true,
+        };
+      }
+      return to;
+    }
+
+    // 鏄惁宸茬粡鐢熸垚杩囧姩鎬佽矾鐢�
+    if (accessStore.isAccessChecked) {
+      return true;
+    }
+
+    // 鐢熸垚璺敱琛�
+    // 褰撳墠鐧诲綍鐢ㄦ埛鎷ユ湁鐨勮鑹叉爣璇嗗垪琛�
+    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
+    const userRoles = userInfo.roles ?? [];
+
+    // 鐢熸垚鑿滃崟鍜岃矾鐢�
+    const { accessibleMenus, accessibleRoutes } = await generateAccess({
+      roles: userRoles,
+      router,
+      // 鍒欎細鍦ㄨ彍鍗曚腑鏄剧ず锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+      routes: accessRoutes,
+    });
+
+    // 淇濆瓨鑿滃崟淇℃伅鍜岃矾鐢变俊鎭�
+    accessStore.setAccessMenus(accessibleMenus);
+    accessStore.setAccessRoutes(accessibleRoutes);
+    accessStore.setIsAccessChecked(true);
+    const redirectPath = (from.query.redirect ?? to.fullPath) as string;
+
+    return {
+      ...router.resolve(decodeURIComponent(redirectPath)),
+      replace: true,
+    };
+  });
+}
+
+/**
+ * 椤圭洰瀹堝崼閰嶇疆
+ * @param router
+ */
+function createRouterGuard(router: Router) {
+  /** 閫氱敤 */
+  setupCommonGuard(router);
+  /** 鏉冮檺璁块棶 */
+  setupAccessGuard(router);
+}
+
+export { createRouterGuard };
diff --git a/eims-ui/apps/web-antd/src/router/index.ts b/eims-ui/apps/web-antd/src/router/index.ts
new file mode 100644
index 0000000..4840230
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/index.ts
@@ -0,0 +1,37 @@
+import {
+  createRouter,
+  createWebHashHistory,
+  createWebHistory,
+} from 'vue-router';
+
+import { resetStaticRoutes } from '@vben/utils';
+
+import { createRouterGuard } from './guard';
+import { routes } from './routes';
+
+/**
+ *  @zh_CN 鍒涘缓vue-router瀹炰緥
+ */
+const router = createRouter({
+  history:
+    import.meta.env.VITE_ROUTER_HISTORY === 'hash'
+      ? createWebHashHistory(import.meta.env.VITE_BASE)
+      : createWebHistory(import.meta.env.VITE_BASE),
+  // 搴旇娣诲姞鍒拌矾鐢辩殑鍒濆璺敱鍒楄〃銆�
+  routes,
+  scrollBehavior: (to, _from, savedPosition) => {
+    if (savedPosition) {
+      return savedPosition;
+    }
+    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
+  },
+  // 鏄惁搴旇绂佹灏鹃儴鏂滄潬銆�
+  // strict: true,
+});
+
+const resetRoutes = () => resetStaticRoutes(router, routes);
+
+// 鍒涘缓璺敱瀹堝崼
+createRouterGuard(router);
+
+export { resetRoutes, router };
diff --git a/eims-ui/apps/web-antd/src/router/routes/core.ts b/eims-ui/apps/web-antd/src/router/routes/core.ts
new file mode 100644
index 0000000..cb84714
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/core.ts
@@ -0,0 +1,96 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+
+import { AuthPageLayout } from '#/layouts';
+import { $t } from '#/locales';
+import Login from '#/views/_core/authentication/login.vue';
+
+/** 鍏ㄥ眬404椤甸潰 */
+const fallbackNotFoundRoute: RouteRecordRaw = {
+  component: () => import('#/views/_core/fallback/not-found.vue'),
+  meta: {
+    hideInBreadcrumb: true,
+    hideInMenu: true,
+    hideInTab: true,
+    title: '404',
+  },
+  name: 'FallbackNotFound',
+  path: '/:path(.*)*',
+};
+
+/** 鍩烘湰璺敱锛岃繖浜涜矾鐢辨槸蹇呴』瀛樺湪鐨� */
+const coreRoutes: RouteRecordRaw[] = [
+  {
+    meta: {
+      title: 'Root',
+    },
+    name: 'Root',
+    path: '/',
+    redirect: DEFAULT_HOME_PATH,
+  },
+  {
+    component: () => import('#/views/_core/social-callback/index.vue'),
+    meta: {
+      title: $t('page.auth.oauthLogin'),
+    },
+    name: 'OAuthRedirect',
+    path: '/social-callback',
+  },
+  {
+    component: AuthPageLayout,
+    meta: {
+      hideInTab: true,
+      title: 'Authentication',
+    },
+    name: 'Authentication',
+    path: '/auth',
+    redirect: LOGIN_PATH,
+    children: [
+      {
+        name: 'Login',
+        path: 'login',
+        component: Login,
+        meta: {
+          title: $t('page.auth.login'),
+        },
+      },
+      {
+        name: 'CodeLogin',
+        path: 'code-login',
+        component: () => import('#/views/_core/authentication/code-login.vue'),
+        meta: {
+          title: $t('page.auth.codeLogin'),
+        },
+      },
+      {
+        name: 'QrCodeLogin',
+        path: 'qrcode-login',
+        component: () =>
+          import('#/views/_core/authentication/qrcode-login.vue'),
+        meta: {
+          title: $t('page.auth.qrcodeLogin'),
+        },
+      },
+      {
+        name: 'ForgetPassword',
+        path: 'forget-password',
+        component: () =>
+          import('#/views/_core/authentication/forget-password.vue'),
+        meta: {
+          title: $t('page.auth.forgetPassword'),
+        },
+      },
+      {
+        name: 'Register',
+        path: 'register',
+        component: () => import('#/views/_core/authentication/register.vue'),
+        meta: {
+          title: $t('page.auth.register'),
+        },
+      },
+    ],
+  },
+];
+
+export { coreRoutes, fallbackNotFoundRoute };
diff --git a/eims-ui/apps/web-antd/src/router/routes/index.ts b/eims-ui/apps/web-antd/src/router/routes/index.ts
new file mode 100644
index 0000000..e6fb144
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/index.ts
@@ -0,0 +1,37 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
+
+import { coreRoutes, fallbackNotFoundRoute } from './core';
+
+const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
+  eager: true,
+});
+
+// 鏈夐渶瑕佸彲浠ヨ嚜琛屾墦寮�娉ㄩ噴锛屽苟鍒涘缓鏂囦欢澶�
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
+// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
+
+/** 鍔ㄦ�佽矾鐢� */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 澶栭儴璺敱鍒楄〃锛岃闂繖浜涢〉闈㈠彲浠ヤ笉闇�瑕丩ayout锛屽彲鑳界敤浜庡唴宓屽湪鍒殑绯荤粺(涓嶄細鏄剧ず鍦ㄨ彍鍗曚腑) */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
+// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
+const staticRoutes: RouteRecordRaw[] = [];
+const externalRoutes: RouteRecordRaw[] = [];
+
+/** 璺敱鍒楄〃锛岀敱鍩烘湰璺敱銆佸閮ㄨ矾鐢卞拰404鍏滃簳璺敱缁勬垚
+ *  鏃犻渶璧版潈闄愰獙璇侊紙浼氫竴鐩存樉绀哄湪鑿滃崟涓級 */
+const routes: RouteRecordRaw[] = [
+  ...coreRoutes,
+  ...externalRoutes,
+  fallbackNotFoundRoute,
+];
+
+/** 鍩烘湰璺敱鍒楄〃锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴� */
+const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
+
+/** 鏈夋潈闄愭牎楠岀殑璺敱鍒楄〃锛屽寘鍚姩鎬佽矾鐢卞拰闈欐�佽矾鐢� */
+const accessRoutes = [...dynamicRoutes, ...staticRoutes];
+export { accessRoutes, coreRouteNames, routes };
diff --git a/eims-ui/apps/web-antd/src/router/routes/local.ts b/eims-ui/apps/web-antd/src/router/routes/local.ts
new file mode 100644
index 0000000..f1883dd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/local.ts
@@ -0,0 +1,224 @@
+import type { RouteRecordStringComponent } from '@vben/types';
+
+import { $t } from '@vben/locales';
+
+/**
+ * 璇ユ枃浠舵斁闈炲悗鍙拌繑鍥炵殑璺敱 姣斿涓汉涓績 绛夐渶瑕佽烦杞樉绀虹殑椤甸潰
+ */
+
+/**
+ * 涓汉涓績
+ */
+const profileRoute: RouteRecordStringComponent[] = [
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      hideInMenu: true,
+      title: $t('ui.widgets.profile')
+    },
+    name: 'Profile',
+    path: '/',
+    redirect: '/profile',
+    children: [
+      {
+        component: '/_core/profile/index',
+        meta: {
+          icon: 'mingcute:profile-line',
+          keepAlive: true,
+          title: $t('ui.widgets.profile')
+        },
+        name: 'ProfileIndex',
+        path: '/profile'
+      }
+    ]
+  },
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      hideInMenu: true,
+      title: 'oss閰嶇疆'
+    },
+    name: 'OssConfig',
+    path: '/',
+    redirect: '/system/oss-config',
+    children: [
+      {
+        component: '/system/oss-config/index',
+        meta: {
+          activePath: '/system/oss',
+          icon: 'ant-design:setting-outlined',
+          keepAlive: true,
+          title: 'oss閰嶇疆'
+        },
+        name: 'OssConfigIndex',
+        path: '/system/oss-config'
+      }
+    ]
+  },
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      hideInMenu: true,
+      title: '淇敼鐢熸垚閰嶇疆'
+    },
+    name: 'GenConfig',
+    path: '/',
+    redirect: '/code-gen/edit',
+    children: [
+      {
+        component: '/tool/gen/edit-gen',
+        meta: {
+          activePath: '/tool/gen',
+          icon: 'tabler:code',
+          keepAlive: true,
+          title: '鐢熸垚閰嶇疆'
+        },
+        name: 'GenConfigIndex',
+        path: '/code-gen/edit/:tableId'
+      }
+    ]
+  },
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      hideInMenu: true,
+      title: '鍒嗛厤瑙掕壊'
+    },
+    name: 'RoleAssign',
+    path: '/',
+    redirect: '/system/role-assign',
+    children: [
+      {
+        component: '/system/role-assign/index',
+        meta: {
+          activePath: '/system/role',
+          icon: 'eos-icons:role-binding-outlined',
+          keepAlive: true,
+          title: '鍒嗛厤瑙掕壊'
+        },
+        name: 'RoleAssignIndex',
+        path: '/system/role-assign/:roleId'
+      }
+    ]
+  },
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      hideInMenu: true,
+      title: '璁惧璇︽儏'
+    },
+    name: 'EquDetail',
+    path: '/',
+    redirect: '/equ/detail',
+    children: [
+      {
+        component: '/eims/equ-detail/index',
+        meta: {
+          activePath: '/equ/ledger',
+          icon: 'eos-icons:role-binding-outlined',
+          keepAlive: true,
+          title: '璁惧璇︽儏'
+        },
+        name: 'EquDetailIndex',
+        path: '/equ/detail/:equId'
+      }
+    ]
+  },
+];
+
+/**
+ * 杩欓噷鏀炬湰鍦拌矾鐢�
+ */
+export const localMenuList: RouteRecordStringComponent[] = [
+  /*  {
+    component: 'BasicLayout',
+    meta: {
+      order: -1,
+      title: 'page.dashboard.title',
+    },
+    name: 'Dashboard',
+    path: '/',
+    redirect: '/analytics',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: '/dashboard/analytics/index',
+        meta: {
+          affixTab: true,
+          title: 'page.dashboard.analytics',
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: '/dashboard/workspace/index',
+        meta: {
+          title: 'page.dashboard.workspace',
+        },
+      },
+      {
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: 'IFrameView',
+        meta: {
+          icon: 'lucide:book-open-text',
+          iframeSrc: 'https://dapdap.top',
+          keepAlive: true,
+          title: $t('demos.vben.document'),
+        },
+      },
+    ],
+  },*/
+  {
+    component: 'BasicLayout',
+    meta: {
+      order: -1,
+      title: 'page.index.title',
+      hideChildrenInMenu: true,
+      icon: 'ic:sharp-menu',
+    },
+    name: 'Root',
+    path: '/',
+    redirect: '/index',
+    children: [
+      {
+        name: 'Index',
+        path: '/index',
+        component: '/index',
+        meta: {
+          affixTab: true,
+          title: 'page.index.title',
+          icon: 'ic:sharp-menu',
+        },
+      },
+    ],
+  },
+  {
+    component: 'BasicLayout',
+    meta: {
+      hideChildrenInMenu: true,
+      icon: 'lucide:copyright',
+      order: 9999,
+      title: $t('demos.vben.about')
+    },
+    name: 'About',
+    path: '/about',
+    children: [
+      {
+        component: '/_core/about/index',
+        meta: {
+          title: $t('demos.vben.about')
+        },
+        name: 'VbenAbout',
+        path: '/vben-admin/about'
+      }
+    ]
+  },
+  ...profileRoute
+];
diff --git a/eims-ui/apps/web-antd/src/router/routes/modules/dashboard.ts b/eims-ui/apps/web-antd/src/router/routes/modules/dashboard.ts
new file mode 100644
index 0000000..1bddab9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/modules/dashboard.ts
@@ -0,0 +1,40 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'lucide:layout-dashboard',
+      order: -1,
+      title: $t('page.dashboard.title'),
+    },
+    name: 'Dashboard',
+    path: '/',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: () => import('#/views/dashboard/analytics/index.vue'),
+        meta: {
+          affixTab: true,
+          icon: 'lucide:area-chart',
+          title: $t('page.dashboard.analytics'),
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: () => import('#/views/dashboard/workspace/index.vue'),
+        meta: {
+          icon: 'carbon:workspace',
+          title: $t('page.dashboard.workspace'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-antd/src/router/routes/modules/demos.ts b/eims-ui/apps/web-antd/src/router/routes/modules/demos.ts
new file mode 100644
index 0000000..32bb338
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/modules/demos.ts
@@ -0,0 +1,30 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    children: [
+      {
+        meta: {
+          title: $t('demos.antd'),
+        },
+        name: 'AntDesignDemos',
+        path: '/demos/ant-design',
+        component: () => import('#/views/demos/antd/index.vue'),
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-antd/src/router/routes/modules/vben.ts b/eims-ui/apps/web-antd/src/router/routes/modules/vben.ts
new file mode 100644
index 0000000..f149388
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/router/routes/modules/vben.ts
@@ -0,0 +1,81 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import {
+  VBEN_DOC_URL,
+  VBEN_ELE_PREVIEW_URL,
+  VBEN_GITHUB_URL,
+  VBEN_LOGO_URL,
+  VBEN_NAIVE_PREVIEW_URL,
+} from '@vben/constants';
+
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('demos.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          icon: 'lucide:copyright|offline',
+          title: $t('demos.vben.about'),
+        },
+      },
+      {
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: IFrameView,
+        meta: {
+          icon: 'lucide:book-open-text|offline',
+          link: VBEN_DOC_URL,
+          title: $t('demos.vben.document'),
+        },
+      },
+      {
+        name: 'VbenGithub',
+        path: '/vben-admin/github',
+        component: IFrameView,
+        meta: {
+          icon: 'mdi:github',
+          link: VBEN_GITHUB_URL,
+          title: 'Github',
+        },
+      },
+      {
+        name: 'VbenNaive',
+        path: '/vben-admin/naive',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:naiveui',
+          link: VBEN_NAIVE_PREVIEW_URL,
+          title: $t('demos.vben.naive-ui'),
+        },
+      },
+      {
+        name: 'VbenElementPlus',
+        path: '/vben-admin/ele',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:element',
+          link: VBEN_ELE_PREVIEW_URL,
+          title: $t('demos.vben.element-plus'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-antd/src/store/auth.ts b/eims-ui/apps/web-antd/src/store/auth.ts
new file mode 100644
index 0000000..7f678e5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/store/auth.ts
@@ -0,0 +1,140 @@
+import type { LoginAndRegisterParams } from '@vben/common-ui';
+import type { UserInfo } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
+
+import { notification } from 'ant-design-vue';
+import { defineStore } from 'pinia';
+
+import { doLogout, getUserInfoApi, loginApi, seeConnectionClose } from '#/api';
+import { $t } from '#/locales';
+
+import { useDictStore } from './dict';
+
+export const useAuthStore = defineStore('auth', () => {
+  const accessStore = useAccessStore();
+  const userStore = useUserStore();
+  const router = useRouter();
+
+  const loginLoading = ref(false);
+
+  /**
+   * 寮傛澶勭悊鐧诲綍鎿嶄綔
+   * Asynchronously handle the login process
+   * @param params 鐧诲綍琛ㄥ崟鏁版嵁
+   */
+  async function authLogin(
+    params: LoginAndRegisterParams,
+    onSuccess?: () => Promise<void> | void,
+  ) {
+    // 寮傛澶勭悊鐢ㄦ埛鐧诲綍鎿嶄綔骞惰幏鍙� accessToken
+    let userInfo: null | UserInfo = null;
+    try {
+      loginLoading.value = true;
+      const { access_token } = await loginApi(params);
+
+      // 灏� accessToken 瀛樺偍鍒� accessStore 涓�
+      accessStore.setAccessToken(access_token);
+      accessStore.setRefreshToken(access_token);
+
+      // 鑾峰彇鐢ㄦ埛淇℃伅骞跺瓨鍌ㄥ埌 accessStore 涓�
+      userInfo = await fetchUserInfo();
+      /**
+       * 璁剧疆鐢ㄦ埛淇℃伅
+       */
+      userStore.setUserInfo(userInfo);
+      /**
+       * 鍦ㄨ繖閲岃缃潈闄�
+       */
+      accessStore.setAccessCodes(userInfo.permissions);
+
+      if (accessStore.loginExpired) {
+        accessStore.setLoginExpired(false);
+      } else {
+        onSuccess ? await onSuccess?.() : await router.push(DEFAULT_HOME_PATH);
+      }
+
+      if (userInfo?.realName) {
+        notification.success({
+          description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
+          duration: 3,
+          message: $t('authentication.loginSuccess'),
+        });
+      }
+    } finally {
+      loginLoading.value = false;
+    }
+
+    return {
+      userInfo,
+    };
+  }
+
+  async function logout(redirect: boolean = true) {
+    try {
+      await seeConnectionClose();
+      await doLogout();
+    } catch (error) {
+      console.error(error);
+    } finally {
+      resetAllStores();
+      accessStore.setLoginExpired(false);
+
+      // 鍥炵櫥闄嗛〉甯︿笂褰撳墠璺敱鍦板潃
+      await router.replace({
+        path: LOGIN_PATH,
+        query: redirect
+          ? {
+              redirect: encodeURIComponent(router.currentRoute.value.fullPath),
+            }
+          : {},
+      });
+    }
+  }
+
+  async function fetchUserInfo() {
+    const backUserInfo = await getUserInfoApi();
+    /**
+     * 鐧诲綍瓒呮椂鐨勬儏鍐�
+     */
+    if (!backUserInfo) {
+      throw new Error('鑾峰彇鐢ㄦ埛淇℃伅澶辫触.');
+    }
+    const { permissions = [], roles = [], user } = backUserInfo;
+    /**
+     * 浠庡悗鍙皍ser -> vben user杞崲
+     */
+    const userInfo: UserInfo = {
+      avatar: user.avatar ?? '',
+      permissions,
+      realName: user.nickName,
+      roles,
+      userId: user.userId,
+      username: user.userName,
+    };
+    userStore.setUserInfo(userInfo);
+    /**
+     * 闇�瑕侀噸鏂板姞杞藉瓧鍏�
+     * 姣斿閫�鍑虹櫥褰曞垏鎹㈠埌鍏朵粬绉熸埛
+     */
+    const dictStore = useDictStore();
+    dictStore.resetCache();
+    return userInfo;
+  }
+
+  function $reset() {
+    loginLoading.value = false;
+  }
+
+  return {
+    $reset,
+    authLogin,
+    fetchUserInfo,
+    loginLoading,
+    logout,
+  };
+});
diff --git a/eims-ui/apps/web-antd/src/store/dict.ts b/eims-ui/apps/web-antd/src/store/dict.ts
new file mode 100644
index 0000000..891beb3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/store/dict.ts
@@ -0,0 +1,111 @@
+import type { DictData } from '#/api/system/dict/dict-data-model';
+
+import { reactive } from 'vue';
+
+import { defineStore } from 'pinia';
+
+/**
+ * antd浣跨敤 select鍜宺adio閫氱敤
+ */
+export interface Option {
+  disabled?: boolean;
+  label: string;
+  value: string;
+}
+
+export function dictToOptions(data: DictData[]): Option[] {
+  return data.map((item) => ({
+    label: item.dictLabel,
+    value: item.dictValue,
+  }));
+}
+
+export const useDictStore = defineStore('app-dict', () => {
+  /**
+   * 涓�鑸槸dictTag浣跨敤
+   */
+  const dictMap = reactive(new Map<string, DictData[]>());
+  /**
+   * select radio radioButton浣跨敤 鍙兘涓哄浐瀹氭牸寮�(Option)
+   */
+  const dictOptionsMap = reactive(new Map<string, Option[]>());
+  /**
+   * 娣诲姞涓�涓瓧鍏歌姹傜姸鎬佺殑缂撳瓨
+   *
+   * 涓昏瑙e喅澶氭璇锋眰閲嶅api鐨勯棶棰�(涓嶈兘鐢╝bortController 浼氬鑷撮櫎浜嗙涓�涓叾浠栫殑鑾峰彇鐨勫叏涓虹┖)
+   * 姣斿鍦ㄤ竴涓〉闈� index琛ㄥ崟 modal drawer鎬诲叡浼氳姹備笁娆� 浣嗘槸鑾峰彇鐨勯兘鏄竴鏍风殑鏁版嵁
+   * 鐩稿綋浜庡姞閿� 淇濊瘉鍙湁绗竴娆¤姹傜殑缁撴灉鑳芥嬁鍒�
+   */
+  const dictRequestCache = reactive(
+    new Map<string, Promise<DictData[] | void>>(),
+  );
+
+  function getDict(dictName: string): DictData[] {
+    if (!dictName) return [];
+    // 娌℃湁key 娣诲姞涓�涓┖鏁扮粍
+    if (!dictMap.has(dictName)) {
+      dictMap.set(dictName, reactive([]));
+    }
+    // 杩欓噷鎷垮埌鐨勫氨涓嶅彲鑳戒负绌轰簡
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    return dictMap.get(dictName)!;
+  }
+
+  function getDictOptions(dictName: string): Option[] {
+    if (!dictName) return [];
+    // 娌℃湁key 娣诲姞涓�涓┖鏁扮粍
+    if (!dictOptionsMap.has(dictName)) {
+      dictOptionsMap.set(dictName, []);
+    }
+    // 杩欓噷鎷垮埌鐨勫氨涓嶅彲鑳戒负绌轰簡
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    return dictOptionsMap.get(dictName)!;
+  }
+
+  function resetCache() {
+    dictMap.clear();
+    dictOptionsMap.clear();
+  }
+
+  /**
+   * 鏍稿績閫昏緫
+   *
+   * 涓嶈兘鐩存帴绮楁毚浣跨敤set 浼氬鑷翠箣鍓峳eturn鐨勭┖鏁扮粍璺熺幇鍦ㄧ殑鏁扮粍鎸囧悜涓嶆槸鍚屼竴涓湴鍧�  鏁版嵁涔熷氨涓虹┖浜�
+   *
+   * 鍒ゆ柇鏄惁宸茬粡瀛樺湪key 骞朵笖鏁扮粍闀垮害涓�0 璇存槑璇ユ瑕佸鐞嗙殑鏁版嵁鏄痳eturn鐨勭┖鏁扮粍 鐩存帴push(涓嶄慨鏀规寚鍚�)
+   * 鍚﹀垯 鐩存帴set
+   *
+   */
+  function setDictInfo(dictName: string, dictValue: DictData[]) {
+    if (dictMap.has(dictName) && dictMap.get(dictName)?.length === 0) {
+      dictMap.get(dictName)?.push(...dictValue);
+    } else {
+      dictMap.set(dictName, dictValue);
+    }
+    if (
+      dictOptionsMap.has(dictName) &&
+      dictOptionsMap.get(dictName)?.length === 0
+    ) {
+      dictOptionsMap.get(dictName)?.push(...dictToOptions(dictValue));
+    } else {
+      dictOptionsMap.set(dictName, dictToOptions(dictValue));
+    }
+  }
+
+  function $reset() {
+    /**
+     * doNothing
+     */
+  }
+
+  return {
+    $reset,
+    dictMap,
+    dictOptionsMap,
+    dictRequestCache,
+    getDict,
+    getDictOptions,
+    resetCache,
+    setDictInfo,
+  };
+});
diff --git a/eims-ui/apps/web-antd/src/store/index.ts b/eims-ui/apps/web-antd/src/store/index.ts
new file mode 100644
index 0000000..7750334
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/store/index.ts
@@ -0,0 +1,2 @@
+export * from './auth';
+export * from './notify';
diff --git a/eims-ui/apps/web-antd/src/store/notify.ts b/eims-ui/apps/web-antd/src/store/notify.ts
new file mode 100644
index 0000000..4fd0a95
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/store/notify.ts
@@ -0,0 +1,149 @@
+import type { NotificationItem } from '@vben/layouts';
+
+import { computed, ref, watch } from 'vue';
+
+import { useAppConfig } from '@vben/hooks';
+import { SvgMessageUrl } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { useAccessStore, useUserStore } from '@vben/stores';
+
+import { useEventSource } from '@vueuse/core';
+import { notification } from 'ant-design-vue';
+import dayjs from 'dayjs';
+import { defineStore } from 'pinia';
+
+const { apiURL, clientId, sseEnable } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+export const useNotifyStore = defineStore(
+  'app-notify',
+  () => {
+    /**
+     * return鎵嶄細琚寔涔呭寲 瀛樺偍鍏ㄩ儴娑堟伅
+     */
+    const notificationList = ref<NotificationItem[]>([]);
+
+    const userStore = useUserStore();
+    const userId = computed(() => {
+      return userStore.userInfo?.userId || '0';
+    });
+
+    const notifications = computed(() => {
+      return notificationList.value.filter(
+        (item) => item.userId === userId.value,
+      );
+    });
+
+    /**
+     * 寮�濮嬬洃鍚瑂se娑堟伅
+     */
+    function startListeningMessage() {
+      /**
+       * 鏈紑鍚� 涓嶇洃鍚�
+       */
+      if (!sseEnable) {
+        return;
+      }
+      const accessStore = useAccessStore();
+      const token = accessStore.accessToken;
+
+      const sseAddr = `${apiURL}/resource/sse?clientid=${clientId}&Authorization=Bearer ${token}`;
+
+      const { data } = useEventSource(sseAddr, [], {
+        autoReconnect: {
+          delay: 1000,
+          onFailed() {
+            console.error('sse閲嶈繛澶辫触.');
+          },
+          retries: 3,
+        },
+      });
+
+      watch(data, (message) => {
+        if (!message) return;
+        console.log(`鎺ユ敹鍒版秷鎭�: ${message}`);
+
+        notification.success({
+          description: message,
+          duration: 3,
+          message: $t('component.notice.received'),
+        });
+
+        notificationList.value.unshift({
+          // avatar: `https://api.multiavatar.com/${random(0, 10_000)}.png`, 闅忔満澶村儚
+          avatar: SvgMessageUrl,
+          date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+          isRead: false,
+          message,
+          title: $t('component.notice.title'),
+          userId: userId.value,
+        });
+
+        // 闇�瑕佹墜鍔ㄧ疆绌� vue3鍦ㄥ�肩浉鍚屾椂涓嶄細瑙﹀彂watch
+        data.value = null;
+      });
+    }
+
+    /**
+     * 璁剧疆鍏ㄩ儴宸茶
+     */
+    function setAllRead() {
+      notificationList.value
+        .filter((item) => item.userId === userId.value)
+        .forEach((item) => {
+          item.isRead = true;
+        });
+    }
+
+    /**
+     * 璁剧疆鍗曟潯娑堟伅宸茶
+     * @param item 閫氱煡
+     */
+    function setRead(item: NotificationItem) {
+      !item.isRead && (item.isRead = true);
+    }
+
+    /**
+     * 娓呯┖鍏ㄩ儴娑堟伅
+     */
+    function clearAllMessage() {
+      notificationList.value = notificationList.value.filter(
+        (item) => item.userId !== userId.value,
+      );
+    }
+
+    /**
+     * 鍙渶瑕佺┖瀹炵幇鍗冲彲
+     * 鍚﹀垯浼氬湪閫�鍑虹櫥褰曟竻绌烘墍鏈�
+     */
+    function $reset() {
+      // notificationList.value = [];
+    }
+    /**
+     * 鏄剧ず灏忓渾鐐�
+     */
+    const showDot = computed(() =>
+      notificationList.value
+        .filter((item) => item.userId === userId.value)
+        .some((item) => !item.isRead),
+    );
+
+    return {
+      $reset,
+      clearAllMessage,
+      notificationList,
+      notifications,
+      setAllRead,
+      setRead,
+      showDot,
+      startListeningMessage,
+    };
+  },
+  {
+    persist: {
+      pick: ['notificationList'],
+    },
+  },
+);
diff --git a/eims-ui/apps/web-antd/src/store/tenant.ts b/eims-ui/apps/web-antd/src/store/tenant.ts
new file mode 100644
index 0000000..34ab754
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/store/tenant.ts
@@ -0,0 +1,45 @@
+import { ref } from 'vue';
+
+import { defineStore } from 'pinia';
+
+import {
+  tenantList as tenantListApi,
+  type TenantOption,
+} from '#/api/core/auth';
+
+/**
+ * 鐢ㄤ簬瓒呯骇绠$悊鍛樺垏鎹㈢鎴�
+ */
+export const useTenantStore = defineStore('app-tenant', () => {
+  // 鏄惁宸茬粡閫変腑绉熸埛
+  const checked = ref(false);
+  // 鏄惁寮�鍚鎴峰姛鑳�
+  const tenantEnable = ref(true);
+  const tenantList = ref<TenantOption[]>([]);
+
+  // 鍒濆鍖� 鑾峰彇绉熸埛淇℃伅
+  async function initTenant() {
+    const { tenantEnabled, voList } = await tenantListApi();
+    tenantEnable.value = tenantEnabled;
+    tenantList.value = voList;
+  }
+
+  async function setChecked(_checked: boolean) {
+    checked.value = _checked;
+  }
+
+  function $reset() {
+    checked.value = false;
+    tenantEnable.value = true;
+    tenantList.value = [];
+  }
+
+  return {
+    $reset,
+    checked,
+    initTenant,
+    setChecked,
+    tenantEnable,
+    tenantList,
+  };
+});
diff --git a/eims-ui/apps/web-antd/src/utils/dict.ts b/eims-ui/apps/web-antd/src/utils/dict.ts
new file mode 100644
index 0000000..ce108d1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/dict.ts
@@ -0,0 +1,64 @@
+import type { DictData } from '#/api/system/dict/dict-data-model';
+
+import { dictDataInfo } from '#/api/system/dict/dict-data';
+import { type Option, useDictStore } from '#/store/dict';
+
+// todo 閲嶅浠g爜鐨勫皝瑁�
+export function getDict(dictName: string): DictData[] {
+  const { dictRequestCache, getDict, setDictInfo } = useDictStore();
+  // 杩欓噷鎷垮埌
+  const dictList = getDict(dictName);
+  // 妫�鏌ヨ姹傜姸鎬佺紦瀛�
+  if (dictList.length === 0 && !dictRequestCache.has(dictName)) {
+    dictRequestCache.set(
+      dictName,
+      dictDataInfo(dictName)
+        .then((resp) => {
+          // 缂撳瓨鍒皊tore 杩欐牱灏变笉鐢ㄩ噸澶嶈幏鍙栦簡
+          // 鍐呴儴澶勭悊浜唒ush鐨勯�昏緫 杩欓噷涓嶇敤push
+          setDictInfo(dictName, resp);
+        })
+        .finally(() => {
+          // 绉婚櫎璇锋眰鐘舵�佺紦瀛�
+          /**
+           * 杩欓噷涓昏鍒ゆ柇瀛楀吀item涓虹┖鐨勬儏鍐�(鏃犲鍏煎 涓嶇粰瀛楀吀item鏈潵灏辨槸閿欒鐢ㄦ硶)
+           * 浼氬鑷磇f涓�鐩磋繘鍏ラ�昏緫瀵艰嚧鎺ュ彛鏃犻檺鍒锋柊
+           * 鍦ㄨ繖閲宒ictList涓虹┖鏃� 涓嶅垹闄ょ紦瀛�
+           */
+          if (dictList.length > 0) {
+            dictRequestCache.delete(dictName);
+          }
+        }),
+    );
+  }
+  return dictList;
+}
+
+export function getDictOptions(dictName: string): Option[] {
+  const { dictRequestCache, getDictOptions, setDictInfo } = useDictStore();
+  const dictOptionList = getDictOptions(dictName);
+  // 妫�鏌ヨ姹傜姸鎬佺紦瀛�
+  if (dictOptionList.length === 0 && !dictRequestCache.has(dictName)) {
+    dictRequestCache.set(
+      dictName,
+      dictDataInfo(dictName)
+        .then((resp) => {
+          // 缂撳瓨鍒皊tore 杩欐牱灏变笉鐢ㄩ噸澶嶈幏鍙栦簡
+          // 鍐呴儴澶勭悊浜唒ush鐨勯�昏緫 杩欓噷涓嶇敤push
+          setDictInfo(dictName, resp);
+        })
+        .finally(() => {
+          // 绉婚櫎璇锋眰鐘舵�佺紦瀛�
+          /**
+           * 杩欓噷涓昏鍒ゆ柇瀛楀吀item涓虹┖鐨勬儏鍐�(鏃犲鍏煎 涓嶇粰瀛楀吀item鏈潵灏辨槸閿欒鐢ㄦ硶)
+           * 浼氬鑷磇f涓�鐩磋繘鍏ラ�昏緫瀵艰嚧鎺ュ彛浜旂嚎鍒锋柊
+           * 鍦ㄨ繖閲宒ictList涓虹┖鏃� 涓嶅垹闄ょ紦瀛�
+           */
+          if (dictOptionList.length > 0) {
+            dictRequestCache.delete(dictName);
+          }
+        }),
+    );
+  }
+  return dictOptionList;
+}
diff --git a/eims-ui/apps/web-antd/src/utils/encryption/crypto.ts b/eims-ui/apps/web-antd/src/utils/encryption/crypto.ts
new file mode 100644
index 0000000..34696d1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/encryption/crypto.ts
@@ -0,0 +1,80 @@
+import CryptoJS from 'crypto-js';
+
+function randomUUID() {
+  const chars = [
+    ...'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
+  ];
+  const uuid = Array.from({ length: 36 });
+  let rnd = 0;
+  let r: number;
+  for (let i = 0; i < 36; i++) {
+    if (i === 8 || i === 13 || i === 18 || i === 23) {
+      uuid[i] = '-';
+    } else if (i === 14) {
+      uuid[i] = '4';
+    } else {
+      if (rnd <= 0x02)
+        rnd = Math.trunc(0x2_00_00_00 + Math.random() * 0x1_00_00_00);
+      r = rnd & 16;
+      rnd = rnd >> 4;
+      uuid[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r];
+    }
+  }
+  return uuid.join('').replaceAll('-', '').toLowerCase();
+}
+
+/**
+ * 闅忔満鐢熸垚aes 瀵嗛挜
+ *
+ * @returns aes 瀵嗛挜
+ */
+export function generateAesKey() {
+  return CryptoJS.enc.Utf8.parse(randomUUID());
+}
+
+/**
+ * base64缂栫爜
+ * @param str
+ * @returns base64缂栫爜
+ */
+export function encryptBase64(str: CryptoJS.lib.WordArray) {
+  return CryptoJS.enc.Base64.stringify(str);
+}
+
+/**
+ * 浣跨敤鍏挜鍔犲瘑
+ * @param message 鍔犲瘑鍐呭
+ * @param aesKey aesKey
+ * @returns 浣跨敤鍏挜鍔犲瘑
+ */
+export function encryptWithAes(
+  message: string,
+  aesKey: CryptoJS.lib.WordArray,
+) {
+  const encrypted = CryptoJS.AES.encrypt(message, aesKey, {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7,
+  });
+  return encrypted.toString();
+}
+
+/**
+ * 瑙e瘑base64
+ */
+export function decryptBase64(str: string) {
+  return CryptoJS.enc.Base64.parse(str);
+}
+
+/**
+ * 浣跨敤瀵嗛挜瀵规暟鎹繘琛岃В瀵�
+ */
+export function decryptWithAes(
+  message: string,
+  aesKey: CryptoJS.lib.WordArray,
+) {
+  const decrypted = CryptoJS.AES.decrypt(message, aesKey, {
+    mode: CryptoJS.mode.ECB,
+    padding: CryptoJS.pad.Pkcs7,
+  });
+  return decrypted.toString(CryptoJS.enc.Utf8);
+}
diff --git a/eims-ui/apps/web-antd/src/utils/encryption/jsencrypt.ts b/eims-ui/apps/web-antd/src/utils/encryption/jsencrypt.ts
new file mode 100644
index 0000000..2e1e6a6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/encryption/jsencrypt.ts
@@ -0,0 +1,31 @@
+// 瀵嗛挜瀵圭敓鎴� http://web.chacuo.net/netrsakeypair
+import { useAppConfig } from '@vben/hooks';
+
+import JSEncrypt from 'jsencrypt';
+
+const { rsaPrivateKey, rsaPublicKey } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+/**
+ * 鍔犲瘑
+ * @param txt 闇�瑕佸姞瀵嗙殑鏁版嵁
+ * @returns 鍔犲瘑鍚庣殑鏁版嵁
+ */
+export function encrypt(txt: string) {
+  const instance = new JSEncrypt();
+  instance.setPublicKey(rsaPublicKey);
+  return instance.encrypt(txt);
+}
+
+/**
+ * 瑙e瘑
+ * @param txt 闇�瑕佽В瀵嗙殑鏁版嵁
+ * @returns 瑙e瘑鍚庣殑鏁版嵁
+ */
+export function decrypt(txt: string) {
+  const instance = new JSEncrypt();
+  instance.setPrivateKey(rsaPrivateKey);
+  return instance.decrypt(txt);
+}
diff --git a/eims-ui/apps/web-antd/src/utils/file/base64Conver.ts b/eims-ui/apps/web-antd/src/utils/file/base64Conver.ts
new file mode 100644
index 0000000..3a487c3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/file/base64Conver.ts
@@ -0,0 +1,46 @@
+/**
+ * @description: base64 to blob
+ */
+export function dataURLtoBlob(base64Buf: string): Blob {
+  const arr = base64Buf.split(',');
+  const typeItem = arr[0];
+  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+  const mime = typeItem!.match(/:(.*?);/)![1];
+  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+  const bstr = window.atob(arr[1]!);
+  let n = bstr.length;
+  const u8arr = new Uint8Array(n);
+  while (n--) {
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    u8arr[n] = bstr.codePointAt(n)!;
+  }
+  return new Blob([u8arr], { type: mime });
+}
+
+/**
+ * img url to base64
+ * @param url
+ */
+export function urlToBase64(url: string, mineType?: string): Promise<string> {
+  return new Promise((resolve, reject) => {
+    let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null;
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const ctx = canvas!.getContext('2d');
+
+    const img = new Image();
+    img.crossOrigin = '';
+    img.addEventListener('load', () => {
+      if (!canvas || !ctx) {
+        // eslint-disable-next-line prefer-promise-reject-errors
+        return reject();
+      }
+      canvas.height = img.height;
+      canvas.width = img.width;
+      ctx.drawImage(img, 0, 0);
+      const dataURL = canvas.toDataURL(mineType || 'image/png');
+      canvas = null;
+      resolve(dataURL);
+    });
+    img.src = url;
+  });
+}
diff --git a/eims-ui/apps/web-antd/src/utils/file/download.ts b/eims-ui/apps/web-antd/src/utils/file/download.ts
new file mode 100644
index 0000000..1d7b428
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/file/download.ts
@@ -0,0 +1,262 @@
+import type { VbenFormProps } from '#/adapter/form';
+
+import { $t } from '@vben/locales';
+import { cloneDeep, formatDate } from '@vben/utils';
+
+import { message } from 'ant-design-vue';
+
+import { dataURLtoBlob, urlToBase64 } from './base64Conver';
+
+/**
+ *
+ * @deprecated 鏃犳硶澶勭悊鍖洪棿閫夋嫨鍣ㄦ暟鎹� 璇蜂娇鐢╟ommonDownloadExcel
+ *
+ * 涓嬭浇excel鏂囦欢
+ * @param [func] axios鍑芥暟
+ * @param [fileName] 鏂囦欢鍚嶇О 涓嶉渶瑕佸甫xlsx鍚庣紑
+ * @param [requestData] 璇锋眰鍙傛暟
+ * @param [withRandomName] 鏄惁甯﹂殢鏈烘枃浠跺悕
+ *
+ * @return void
+ */
+export async function downloadExcel(
+  func: (data?: any) => Promise<Blob>,
+  fileName: string,
+  requestData: any = {},
+  withRandomName = true,
+) {
+  const hideLoading = message.loading($t('pages.common.downloadLoading'), 0);
+  try {
+    const data = await func(requestData);
+    downloadExcelFile(data, fileName, withRandomName);
+  } catch (error) {
+    console.error(error);
+  } finally {
+    hideLoading();
+  }
+}
+
+/**
+ * 婧愮爜鍚宲ackages\@core\ui-kit\form-ui\src\components\form-actions.vue
+ * @param values 琛ㄥ崟鍊�
+ * @param fieldMappingTime 鍖洪棿閫夋嫨鍣� 瀛楁鏄犲皠
+ * @returns 鏍煎紡鍖栧悗鐨勫��
+ */
+function handleRangeTimeValue(
+  values: Record<string, any>,
+  fieldMappingTime: VbenFormProps['fieldMappingTime'],
+) {
+  // 闇�瑕佹繁鎷疯礉 鍙兘鏄痳eadonly鐨�
+  values = cloneDeep(values);
+  if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
+    return values;
+  }
+
+  fieldMappingTime.forEach(
+    ([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {
+      if (
+        values[field] === null &&
+        values[startTimeKey] &&
+        values[endTimeKey]
+      ) {
+        Reflect.deleteProperty(values, startTimeKey);
+        Reflect.deleteProperty(values, endTimeKey);
+        return;
+      }
+
+      if (!values[field]) {
+        Reflect.deleteProperty(values, field);
+        return;
+      }
+
+      const [startTime, endTime] = values[field];
+      const [startTimeFormat, endTimeFormat] = Array.isArray(format)
+        ? format
+        : [format, format];
+
+      values[startTimeKey] = startTime
+        ? formatDate(startTime, startTimeFormat)
+        : undefined;
+      values[endTimeKey] = endTime
+        ? formatDate(endTime, endTimeFormat)
+        : undefined;
+
+      Reflect.deleteProperty(values, field);
+    },
+  );
+
+  return values;
+}
+
+export interface DownloadExcelOptions {
+  // 鏄惁闅忔満鏂囦欢鍚�(甯︽椂闂存埑)
+  withRandomName?: boolean;
+  // 鍖洪棿閫夋嫨鍣� 瀛楁鏄犲皠
+  fieldMappingTime?: VbenFormProps['fieldMappingTime'];
+}
+
+/**
+ * 閫氱敤涓嬭浇excel鏂规硶
+ * @param api 鍚庣涓嬭浇鎺ュ彛
+ * @param fileName 鏂囦欢鍚� 涓嶅甫鎷撳睍鍚�
+ * @param requestData 璇锋眰鍙傛暟
+ * @param options 涓嬭浇閫夐」
+ */
+export async function commonDownloadExcel(
+  api: (data?: any) => Promise<Blob>,
+  fileName: string,
+  requestData: any = {},
+  options: DownloadExcelOptions = {},
+) {
+  const hideLoading = message.loading($t('pages.common.downloadLoading'), 0);
+  try {
+    const { withRandomName = true, fieldMappingTime } = options;
+    // 闇�瑕佸鐞嗘椂闂村瓧娈垫槧灏�
+    const data = await api(handleRangeTimeValue(requestData, fieldMappingTime));
+    downloadExcelFile(data, fileName, withRandomName);
+  } catch (error) {
+    console.error(error);
+  } finally {
+    hideLoading();
+  }
+}
+
+export function downloadExcelFile(
+  data: BlobPart,
+  filename: string,
+  withRandomName = true,
+) {
+  let realFileName = filename;
+  if (withRandomName) {
+    realFileName = `${filename}-${Date.now()}.xlsx`;
+  }
+  downloadByData(data, realFileName);
+}
+
+/**
+ * Download online pictures
+ * @param url
+ * @param filename
+ * @param mime
+ * @param bom
+ */
+export function downloadByOnlineUrl(
+  url: string,
+  filename: string,
+  mime?: string,
+  bom?: BlobPart,
+) {
+  urlToBase64(url).then((base64) => {
+    downloadByBase64(base64, filename, mime, bom);
+  });
+}
+
+/**
+ * Download pictures based on base64
+ * @param buf
+ * @param filename
+ * @param mime
+ * @param bom
+ */
+export function downloadByBase64(
+  buf: string,
+  filename: string,
+  mime?: string,
+  bom?: BlobPart,
+) {
+  const base64Buf = dataURLtoBlob(buf);
+  downloadByData(base64Buf, filename, mime, bom);
+}
+
+/**
+ * Download according to the background interface file stream
+ * @param {*} data
+ * @param {*} filename
+ * @param {*} mime
+ * @param {*} bom
+ */
+export function downloadByData(
+  data: BlobPart,
+  filename: string,
+  mime?: string,
+  bom?: BlobPart,
+) {
+  const blobData = bom === undefined ? [data] : [bom, data];
+  const blob = new Blob(blobData, { type: mime || 'application/octet-stream' });
+
+  const blobURL = window.URL.createObjectURL(blob);
+  const tempLink = document.createElement('a');
+  tempLink.style.display = 'none';
+  tempLink.href = blobURL;
+  tempLink.setAttribute('download', filename);
+  if (tempLink.download === undefined) {
+    tempLink.setAttribute('target', '_blank');
+  }
+  document.body.append(tempLink);
+  tempLink.click();
+  tempLink.remove();
+  window.URL.revokeObjectURL(blobURL);
+}
+
+export function openWindow(
+  url: string,
+  opt?: {
+    noopener?: boolean;
+    noreferrer?: boolean;
+    target?: '_blank' | '_self' | string;
+  },
+) {
+  const { noopener = true, noreferrer = true, target = '__blank' } = opt || {};
+  const feature: string[] = [];
+
+  noopener && feature.push('noopener=yes');
+  noreferrer && feature.push('noreferrer=yes');
+
+  window.open(url, target, feature.join(','));
+}
+
+/**
+ * Download file according to file address
+ * @param {*} sUrl
+ */
+export function downloadByUrl({
+  fileName,
+  target = '_blank',
+  url,
+}: {
+  fileName?: string;
+  target?: '_blank' | '_self';
+  url: string;
+}): boolean {
+  const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');
+  const isSafari = window.navigator.userAgent.toLowerCase().includes('safari');
+
+  if (/iP/.test(window.navigator.userAgent)) {
+    console.error('Your browser does not support download!');
+    return false;
+  }
+  if (isChrome || isSafari) {
+    const link = document.createElement('a');
+    link.href = url;
+    link.target = target;
+
+    if (link.download !== undefined) {
+      link.download =
+        // eslint-disable-next-line unicorn/prefer-string-slice
+        fileName || url.substring(url.lastIndexOf('/') + 1, url.length);
+    }
+
+    if (document.createEvent) {
+      const e = document.createEvent('MouseEvents');
+      e.initEvent('click', true, true);
+      link.dispatchEvent(e);
+      return true;
+    }
+  }
+  if (!url.includes('?')) {
+    url += '?download';
+  }
+
+  openWindow(url, { target });
+  return true;
+}
diff --git a/eims-ui/apps/web-antd/src/utils/modal.tsx b/eims-ui/apps/web-antd/src/utils/modal.tsx
new file mode 100644
index 0000000..4473093
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/modal.tsx
@@ -0,0 +1,63 @@
+import type { Rule } from 'ant-design-vue/es/form';
+
+import { reactive } from 'vue';
+
+import { Alert, Form, Input, Modal, type ModalFuncProps } from 'ant-design-vue';
+import { isFunction } from 'lodash-es';
+
+export interface ConfirmModalProps extends Omit<ModalFuncProps, 'visible'> {
+  confirmText?: string;
+  placeholder?: string;
+  onValidated?: () => Promise<void>;
+}
+
+export function confirmDeleteModal(props: ConfirmModalProps) {
+  const placeholder = props.placeholder || `杈撳叆'纭鍒犻櫎'`;
+  const confirmText = props.confirmText || '纭鍒犻櫎';
+
+  const formValue = reactive({
+    content: '',
+  });
+  const rulesRef = reactive<{ [key: string]: Rule[] }>({
+    content: [
+      {
+        message: '鏍¢獙涓嶉�氳繃',
+        required: true,
+        trigger: 'change',
+        validator(_, value) {
+          if (value !== confirmText) {
+            return Promise.reject(new Error('鏍¢獙涓嶉�氳繃'));
+          }
+          return Promise.resolve();
+        },
+      },
+    ],
+  });
+  const useForm = Form.useForm;
+  const { validate, validateInfos } = useForm(formValue, rulesRef);
+
+  Modal.confirm({
+    ...props,
+    centered: true,
+    content: (
+      <div class="flex flex-col gap-[8px]">
+        <Alert message={'纭鍒犻櫎鍚庡皢鏃犳硶鎭㈠锛岃璋ㄦ厧鎿嶄綔锛�'} type="error" />
+        <Form layout="vertical" model={formValue}>
+          <Form.Item {...validateInfos.content}>
+            <Input
+              placeholder={placeholder}
+              v-model:value={formValue.content}
+            />
+          </Form.Item>
+        </Form>
+      </div>
+    ),
+    okButtonProps: { danger: true, type: 'primary' },
+    onOk: async () => {
+      await validate();
+      isFunction(props.onValidated) && props.onValidated();
+    },
+    title: '鎻愮ず',
+    type: 'warning',
+  });
+}
diff --git a/eims-ui/apps/web-antd/src/utils/render.tsx b/eims-ui/apps/web-antd/src/utils/render.tsx
new file mode 100644
index 0000000..fcc9102
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/utils/render.tsx
@@ -0,0 +1,229 @@
+import type { DictData } from '#/api/system/dict/dict-data-model';
+
+import { type Component as ComponentType, h } from 'vue';
+
+import { JsonPreview } from '@vben/common-ui';
+import {
+  AndroidIcon,
+  BaiduIcon,
+  ChromeIcon,
+  DefaultBrowserIcon,
+  DefaultOsIcon,
+  DingtalkIcon,
+  EdgeIcon,
+  FirefoxIcon,
+  IconifyIcon,
+  IPhoneIcon,
+  LinuxIcon,
+  MicromessengerIcon,
+  OperaIcon,
+  OSXIcon,
+  QQIcon,
+  QuarkIcon,
+  SafariIcon,
+  UcIcon,
+  WindowsIcon,
+} from '@vben/icons';
+
+import { Tag } from 'ant-design-vue';
+
+import { DictTag } from '#/components/dict';
+
+import { getDict } from './dict';
+
+/**
+ * 娓叉煋鏍囩
+ * @param text 鏂囧瓧
+ * @param color 棰滆壊
+ * @returns render
+ */
+function renderTag(text: string, color?: string) {
+  return <Tag color={color}>{text}</Tag>;
+}
+
+/**
+ *
+ * @param tags 鏍囩list
+ * @param wrap 鏄惁鎹㈣鏄剧ず
+ * @param [gap] 闂撮殧
+ * @returns render
+ */
+export function renderTags(tags: string[], wrap = false, gap = 1) {
+  return (
+    <div class={['flex', `gap-${gap}`, wrap ? 'flex-col' : 'flex-row']}>
+      {tags.map((tag, index) => {
+        return <div key={index}>{renderTag(tag)}</div>;
+      })}
+    </div>
+  );
+}
+
+/**
+ *
+ * @param json json瀵硅薄 鎺ュ彈object/string绫诲瀷
+ * @returns json棰勮
+ */
+export function renderJsonPreview(json: any) {
+  if (typeof json !== 'object' && typeof json !== 'string') {
+    return <span>{json}</span>;
+  }
+  if (typeof json === 'object') {
+    return <JsonPreview class="break-normal" data={json} />;
+  }
+  try {
+    const obj = JSON.parse(json);
+    // 鍩烘湰鏁版嵁绫诲瀷鍙互琚浆涓簀son
+    if (typeof obj !== 'object') {
+      return <span>{obj}</span>;
+    }
+    return <JsonPreview class="break-normal" data={obj} />;
+  } catch {
+    return <span>{json}</span>;
+  }
+}
+
+/**
+ * iconify鍥炬爣
+ * @param icon icon鍚嶇О
+ * @returns render
+ */
+export function renderIcon(icon: string) {
+  return <IconifyIcon icon={icon}></IconifyIcon>;
+}
+
+/**
+ * httpMethod鏍囩
+ * @param type method绫诲瀷
+ * @returns render
+ */
+export function renderHttpMethodTag(type: string) {
+  const method = type.toUpperCase();
+  const colors: { [key: string]: string } = {
+    DELETE: 'red',
+    GET: 'green',
+    POST: 'blue',
+    PUT: 'orange',
+  };
+
+  const color = colors[method] ?? 'default';
+  const title = `${method}璇锋眰`;
+
+  return <Tag color={color}>{title}</Tag>;
+}
+
+export function renderDictTag(value: string, dicts: DictData[]) {
+  return <DictTag dicts={dicts} value={value}></DictTag>;
+}
+
+/**
+ * render澶氫釜dictTag
+ * @param value key鏁扮粍 string[]绫诲瀷
+ * @param dicts 瀛楀吀鏁扮粍
+ * @param wrap 鏄惁闇�瑕佹崲琛屾樉绀�
+ * @param [gap] 闂撮殧
+ * @returns render
+ */
+export function renderDictTags(
+  value: string[],
+  dicts: DictData[],
+  wrap = true,
+  gap = 1,
+) {
+  if (!Array.isArray(value)) {
+    return <div>{value}</div>;
+  }
+  return (
+    <div class={['flex', `gap-${gap}`, wrap ? 'flex-col' : 'flex-row']}>
+      {value.map((item, index) => {
+        return <div key={index}>{renderDictTag(item, dicts)}</div>;
+      })}
+    </div>
+  );
+}
+
+/**
+ * 鏄剧ず瀛楀吀鏍囩 涓�鑸槸table浣跨敤
+ * @param value 鍊�
+ * @param dictName dictName
+ * @returns tag
+ */
+export function renderDict(value: string, dictName: string) {
+  const dictInfo = getDict(dictName);
+  return renderDictTag(value, dictInfo);
+}
+export function renderIconSpan(
+  icon: ComponentType,
+  value: string,
+  center = false,
+  marginLeft = '2px',
+) {
+  const justifyCenter = center ? 'justify-center' : '';
+
+  return (
+    <span class={['flex', 'items-center', justifyCenter]}>
+      {h(icon)}
+      <span style={{ marginLeft }}>{value}</span>
+    </span>
+  );
+}
+
+const osOptions = [
+  { icon: WindowsIcon, value: 'windows' },
+  { icon: LinuxIcon, value: 'linux' },
+  { icon: OSXIcon, value: 'osx' },
+  { icon: AndroidIcon, value: 'android' },
+  { icon: IPhoneIcon, value: 'iphone' },
+];
+
+/**
+ * 娴忚鍣ㄥ浘鏍�
+ * cn.hutool.http.useragent -> browers
+ */
+const browserOptions = [
+  { icon: ChromeIcon, value: 'chrome' },
+  { icon: EdgeIcon, value: 'edge' },
+  { icon: FirefoxIcon, value: 'firefox' },
+  { icon: OperaIcon, value: 'opera' },
+  { icon: SafariIcon, value: 'safari' },
+  { icon: MicromessengerIcon, value: 'micromessenger' },
+  { icon: QuarkIcon, value: 'quark' },
+  { icon: MicromessengerIcon, value: 'wxwork' },
+  { icon: QQIcon, value: 'qq' },
+  { icon: DingtalkIcon, value: 'dingtalk' },
+  { icon: UcIcon, value: 'uc' },
+  { icon: BaiduIcon, value: 'baidu' },
+];
+
+export function renderOsIcon(os: string, center = false) {
+  if (!os) {
+    return;
+  }
+  let current = osOptions.find((item) =>
+    os.toLocaleLowerCase().includes(item.value),
+  );
+  // windows瑕佺壒娈婂鐞�
+  if (os.toLocaleLowerCase().includes('windows')) {
+    current = osOptions[0];
+  }
+  if (current) {
+    return renderIconSpan(current.icon, os, center, '5px');
+  }
+  // 杩斿洖榛樿
+  const defaultIcon = DefaultOsIcon;
+  return renderIconSpan(defaultIcon, os, center, '5px');
+}
+
+export function renderBrowserIcon(browser: string, center = false) {
+  if (!browser) {
+    return;
+  }
+  const current = browserOptions.find((item) =>
+    browser.toLocaleLowerCase().includes(item.value),
+  );
+  if (current) {
+    return renderIconSpan(current.icon, browser, center, '5px');
+  }
+  // 杩斿洖榛樿
+  const defaultIcon = DefaultBrowserIcon;
+  return renderIconSpan(defaultIcon, browser, center, '5px');
+}
diff --git a/eims-ui/apps/web-antd/src/views/_core/README.md b/eims-ui/apps/web-antd/src/views/_core/README.md
new file mode 100644
index 0000000..8248afe
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/README.md
@@ -0,0 +1,3 @@
+# \_core
+
+姝ょ洰褰曞寘鍚簲鐢ㄧ▼搴忔甯歌繍琛屾墍闇�鐨勫熀鏈鍥俱�傝繖浜涜鍥炬槸搴旂敤绋嬪簭甯冨眬涓娇鐢ㄧ殑瑙嗗浘銆�
diff --git a/eims-ui/apps/web-antd/src/views/_core/about/index.vue b/eims-ui/apps/web-antd/src/views/_core/about/index.vue
new file mode 100644
index 0000000..0ee5243
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/about/index.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { About } from '@vben/common-ui';
+
+defineOptions({ name: 'About' });
+</script>
+
+<template>
+  <About />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/code-login.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/code-login.vue
new file mode 100644
index 0000000..dfada34
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/code-login.vue
@@ -0,0 +1,138 @@
+<script lang="ts" setup>
+import type { LoginCodeParams, VbenFormSchema } from '@vben/common-ui';
+
+import { computed, onMounted, ref, useTemplateRef } from 'vue';
+
+import { AuthenticationCodeLogin, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { Alert, message } from 'ant-design-vue';
+
+import { tenantList, type TenantResp } from '#/api';
+import { sendSmsCode } from '#/api/core/captcha';
+import { useAuthStore } from '#/store';
+
+defineOptions({ name: 'CodeLogin' });
+
+const loading = ref(false);
+
+const tenantInfo = ref<TenantResp>({
+  tenantEnabled: false,
+  voList: [],
+});
+
+const codeLoginRef = useTemplateRef('codeLoginRef');
+async function loadTenant() {
+  const resp = await tenantList();
+  tenantInfo.value = resp;
+  // 閫変腑绗竴涓鎴�
+  if (resp.tenantEnabled && resp.voList.length > 0) {
+    const firstTenantId = resp.voList[0]!.tenantId;
+    codeLoginRef.value?.getFormApi().setFieldValue('tenantId', firstTenantId);
+  }
+}
+
+onMounted(loadTenant);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenSelect',
+      componentProps: {
+        class: 'bg-background h-[40px] focus:border-primary',
+        contentClass: 'max-h-[256px] overflow-y-auto',
+        options: tenantInfo.value.voList?.map((item) => ({
+          label: item.companyName,
+          value: item.tenantId,
+        })),
+        placeholder: $t('authentication.selectAccount'),
+      },
+      defaultValue: '000000',
+      dependencies: {
+        if: () => tenantInfo.value.tenantEnabled,
+        triggerFields: [''],
+      },
+      fieldName: 'tenantId',
+      label: $t('authentication.selectAccount'),
+      rules: z.string().min(1, { message: $t('authentication.selectAccount') }),
+    },
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.mobile'),
+      },
+      fieldName: 'phoneNumber',
+      label: $t('authentication.mobile'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.mobileTip') })
+        .refine((v) => /^\d{11}$/.test(v), {
+          message: $t('authentication.mobileErrortip'),
+        }),
+    },
+    {
+      component: 'VbenPinInput',
+      componentProps(_, form) {
+        return {
+          createText: (countdown: number) => {
+            const text =
+              countdown > 0
+                ? $t('authentication.sendText', [countdown])
+                : $t('authentication.sendCode');
+            return text;
+          },
+          // 楠岃瘉鐮侀暱搴� 鍦ㄨ繖璁剧疆
+          codeLength: 4,
+          placeholder: $t('authentication.code'),
+          handleSendCode: async () => {
+            const { valid, value } = await form.validateField('phoneNumber');
+            if (!valid) {
+              // 蹇呴』鎶涘紓甯� 涓嶈兘鐩存帴return
+              throw new Error('鏈~鍐欐墜鏈哄彿');
+            }
+            // 璋冪敤鎺ュ彛鍙戦��
+            await sendSmsCode(value);
+            message.success('楠岃瘉鐮佸彂閫佹垚鍔�');
+          },
+        };
+      },
+      fieldName: 'code',
+      label: $t('authentication.code'),
+      rules: z.string().min(1, { message: $t('authentication.codeTip') }),
+    },
+  ];
+});
+
+const authStore = useAuthStore();
+async function handleLogin(values: LoginCodeParams) {
+  try {
+    const requestParams: any = {
+      tenantId: values.tenantId,
+      phonenumber: values.phoneNumber,
+      smsCode: values.code,
+      grantType: 'sms',
+    };
+    console.log('login params', requestParams);
+    await authStore.authLogin(requestParams);
+  } catch (error) {
+    console.error(error);
+  }
+}
+</script>
+
+<template>
+  <div>
+    <Alert
+      class="mb-4"
+      how-icon
+      message="娴嬭瘯鎵嬫満鍙�: 15888888888 姝g‘楠岃瘉鐮�: 1234 婕旂ず浣跨敤 涓嶄細鐪熺殑鍙戦��"
+      type="info"
+    />
+    <AuthenticationCodeLogin
+      ref="codeLoginRef"
+      :form-schema="formSchema"
+      :loading="loading"
+      @submit="handleLogin"
+    />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/forget-password.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/forget-password.vue
new file mode 100644
index 0000000..0958e89
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/forget-password.vue
@@ -0,0 +1,42 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationForgetPassword, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'ForgetPassword' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: 'example@example.com',
+      },
+      fieldName: 'email',
+      label: $t('authentication.email'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.emailTip') })
+        .email($t('authentication.emailValidErrorTip')),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('reset email:', value);
+}
+</script>
+
+<template>
+  <AuthenticationForgetPassword
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/login.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/login.vue
new file mode 100644
index 0000000..d68624c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/login.vue
@@ -0,0 +1,163 @@
+<script lang="ts" setup>
+import type { LoginAndRegisterParams, VbenFormSchema } from '@vben/common-ui';
+
+import { computed, onMounted, ref, useTemplateRef } from 'vue';
+
+import { AuthenticationLogin, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { omit } from 'lodash-es';
+
+import { tenantList, type TenantResp } from '#/api';
+import { captchaImage, type CaptchaResponse } from '#/api/core/captcha';
+import { useAuthStore } from '#/store';
+
+import OAuthLogin from './oauth-login.vue';
+
+defineOptions({ name: 'Login' });
+
+const authStore = useAuthStore();
+
+const loginFormRef = useTemplateRef('loginFormRef');
+
+const captchaInfo = ref<CaptchaResponse>({
+  captchaEnabled: false,
+  img: '',
+  uuid: '',
+});
+
+async function loadCaptcha() {
+  const resp = await captchaImage();
+  if (resp.captchaEnabled) {
+    resp.img = `data:image/png;base64,${resp.img}`;
+  }
+  captchaInfo.value = resp;
+}
+
+const tenantInfo = ref<TenantResp>({
+  tenantEnabled: false,
+  voList: [],
+});
+
+async function loadTenant() {
+  const resp = await tenantList();
+  tenantInfo.value = resp;
+  // 閫変腑绗竴涓鎴�
+  if (resp.tenantEnabled && resp.voList.length > 0) {
+    const firstTenantId = resp.voList[0]!.tenantId;
+    loginFormRef.value?.getFormApi().setFieldValue('tenantId', firstTenantId);
+  }
+}
+
+onMounted(async () => {
+  await Promise.all([loadCaptcha(), loadTenant()]);
+});
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenSelect',
+      componentProps: {
+        class: 'bg-background h-[40px] focus:border-primary',
+        contentClass: 'max-h-[256px] overflow-y-auto',
+        options: tenantInfo.value.voList?.map((item) => ({
+          label: item.companyName,
+          value: item.tenantId,
+        })),
+        placeholder: $t('authentication.selectAccount'),
+      },
+      defaultValue: '000000',
+      dependencies: {
+        if: () => tenantInfo.value.tenantEnabled,
+        // 杩欓噷澶ц嚧涓婃槸watch鐨勪竴涓晥鏋�
+        componentProps: (model) => {
+          localStorage.setItem(
+            '__oauth_tenant_id',
+            model?.tenantId ?? '000000',
+          );
+          return {};
+        },
+        triggerFields: ['', 'tenantId'],
+      },
+      fieldName: 'tenantId',
+      label: $t('authentication.selectAccount'),
+      rules: z.string().min(1, { message: $t('authentication.selectAccount') }),
+    },
+    {
+      component: 'VbenInput',
+      componentProps: {
+        class: 'focus:border-primary',
+        placeholder: $t('authentication.usernameTip'),
+      },
+      defaultValue: 'admin',
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        class: 'focus:border-primary',
+        placeholder: $t('authentication.password'),
+      },
+      defaultValue: 'admin123',
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      rules: z.string().min(5, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: 'VbenInputCaptcha',
+      componentProps: {
+        captcha: captchaInfo.value.img,
+        class: 'focus:border-primary',
+        onCaptchaClick: loadCaptcha,
+        placeholder: $t('authentication.code'),
+      },
+      dependencies: {
+        if: () => captchaInfo.value.captchaEnabled,
+        triggerFields: [''],
+      },
+      fieldName: 'code',
+      label: $t('authentication.code'),
+      rules: z.string().min(1, { message: $t('authentication.codeTip') }),
+    },
+  ];
+});
+
+async function handleAccountLogin(values: LoginAndRegisterParams) {
+  try {
+    const requestParam: any = omit(values, ['code']);
+    // 楠岃瘉鐮�
+    if (captchaInfo.value.captchaEnabled) {
+      requestParam.code = values.code;
+      requestParam.uuid = captchaInfo.value.uuid;
+    }
+    // 鐧诲綍
+    await authStore.authLogin(requestParam);
+  } catch (error) {
+    console.error(error);
+    // 澶勭悊楠岃瘉鐮侀敊璇�
+    if (error instanceof Error) {
+      // 鍒锋柊楠岃瘉鐮�
+      loginFormRef.value?.getFormApi().setFieldValue('code', '');
+      await loadCaptcha();
+    }
+  }
+}
+</script>
+
+<template>
+  <AuthenticationLogin
+    ref="loginFormRef"
+    :form-schema="formSchema"
+    :loading="authStore.loginLoading"
+    :show-register="false"
+    :show-third-party-login="true"
+    @submit="handleAccountLogin"
+  >
+    <!-- 鍙�氳繃show-third-party-login鎺у埗鏄惁鏄剧ず绗笁鏂圭櫥褰� -->
+    <template #third-party-login>
+      <OAuthLogin />
+    </template>
+  </AuthenticationLogin>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/oauth-login.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/oauth-login.vue
new file mode 100644
index 0000000..0c359ec
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/oauth-login.vue
@@ -0,0 +1,44 @@
+<script setup lang="ts">
+import { $t } from '@vben/locales';
+
+import { Col, Row, Tooltip } from 'ant-design-vue';
+
+import { accountBindList } from '../oauth-common';
+
+defineOptions({
+  name: 'OAuthLogin',
+});
+
+/**
+ * 鏈塧ction鏂规硶鎵嶄細鏄剧ず
+ */
+const clientList = accountBindList.filter((item) => item.action);
+</script>
+
+<template>
+  <div class="w-full sm:mx-auto md:max-w-md">
+    <div class="mt-4 flex items-center justify-between">
+      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
+      <span class="text-muted-foreground text-center text-xs uppercase">
+        {{ $t('authentication.thirdPartyLogin') }}
+      </span>
+      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
+    </div>
+    <Row class="enter-x flex items-center justify-evenly">
+      <!-- todo 杩欓噷鍦ㄧ偣鍑荤櫥褰曟椂瑕乨isabled -->
+      <Col v-for="item in clientList" :key="item.key" :span="4" class="my-2">
+        <Tooltip :title="`${item.title}鐧诲綍`">
+          <span class="flex cursor-pointer items-center justify-center">
+            <component
+              :is="item.avatar"
+              v-if="item.avatar"
+              :style="{ color: item.color }"
+              class="size-[24px]"
+              @click="item.action"
+            />
+          </span>
+        </Tooltip>
+      </Col>
+    </Row>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/qrcode-login.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/qrcode-login.vue
new file mode 100644
index 0000000..23f5f2d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/qrcode-login.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+import { AuthenticationQrCodeLogin } from '@vben/common-ui';
+import { LOGIN_PATH } from '@vben/constants';
+
+defineOptions({ name: 'QrCodeLogin' });
+</script>
+
+<template>
+  <AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/authentication/register.vue b/eims-ui/apps/web-antd/src/views/_core/authentication/register.vue
new file mode 100644
index 0000000..f264c46
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/authentication/register.vue
@@ -0,0 +1,95 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, h, ref } from 'vue';
+
+import { AuthenticationRegister, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'Register' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        passwordStrength: true,
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      renderComponentContent() {
+        return {
+          strengthText: () => $t('authentication.passwordStrength'),
+        };
+      },
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.confirmPassword'),
+      },
+      dependencies: {
+        rules(values) {
+          const { password } = values;
+          return z
+            .string({ required_error: $t('authentication.passwordTip') })
+            .min(1, { message: $t('authentication.passwordTip') })
+            .refine((value) => value === password, {
+              message: $t('authentication.confirmPasswordTip'),
+            });
+        },
+        triggerFields: ['password'],
+      },
+      fieldName: 'confirmPassword',
+      label: $t('authentication.confirmPassword'),
+    },
+    {
+      component: 'VbenCheckbox',
+      fieldName: 'agreePolicy',
+      renderComponentContent: () => ({
+        default: () =>
+          h('span', [
+            $t('authentication.agree'),
+            h(
+              'a',
+              {
+                class: 'vben-link ml-1 ',
+                href: '',
+              },
+              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,
+            ),
+          ]),
+      }),
+      rules: z.boolean().refine((value) => !!value, {
+        message: $t('authentication.agreeTip'),
+      }),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('register submit:', value);
+}
+</script>
+
+<template>
+  <AuthenticationRegister
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/fallback/coming-soon.vue b/eims-ui/apps/web-antd/src/views/_core/fallback/coming-soon.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/fallback/coming-soon.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/fallback/forbidden.vue b/eims-ui/apps/web-antd/src/views/_core/fallback/forbidden.vue
new file mode 100644
index 0000000..8ea65fe
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/fallback/forbidden.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback403Demo' });
+</script>
+
+<template>
+  <Fallback status="403" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/fallback/internal-error.vue b/eims-ui/apps/web-antd/src/views/_core/fallback/internal-error.vue
new file mode 100644
index 0000000..819a47d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/fallback/internal-error.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback500Demo' });
+</script>
+
+<template>
+  <Fallback status="500" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/fallback/not-found.vue b/eims-ui/apps/web-antd/src/views/_core/fallback/not-found.vue
new file mode 100644
index 0000000..4d178e9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/fallback/not-found.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback404Demo' });
+</script>
+
+<template>
+  <Fallback status="404" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/fallback/offline.vue b/eims-ui/apps/web-antd/src/views/_core/fallback/offline.vue
new file mode 100644
index 0000000..5de4a88
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/fallback/offline.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'FallbackOfflineDemo' });
+</script>
+
+<template>
+  <Fallback status="offline" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/oauth-common.ts b/eims-ui/apps/web-antd/src/views/_core/oauth-common.ts
new file mode 100644
index 0000000..6627442
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/oauth-common.ts
@@ -0,0 +1,104 @@
+import type { Component } from 'vue';
+
+import {
+  AlipayIcon,
+  DingdingIcon,
+  GiteeIcon,
+  GithubOAuthIcon,
+  TaobaoIcon,
+} from '@vben/icons';
+
+import { authBinding } from '#/api/core/auth';
+/**
+ * @description: 鑿滃崟
+ * @param key key
+ * @param title 鏍囬
+ * @param description 鎻忚堪
+ * @param extra 鎸夐挳鏂囧瓧
+ * @param avatar 鍥炬爣
+ * @param color 鍥炬爣棰滆壊鍙洿鎺ュ啓鑻辨枃棰滆壊/hex
+ */
+export interface ListItem {
+  key: string;
+  title: string;
+  description: string;
+  extra?: string;
+  avatar?: Component;
+  color?: string;
+}
+
+/**
+ * @description: 缁戝畾璐﹀彿
+ * @param source 鏉ユ簮 濡俫itee github 涓庡悗绔殑social-callback?source=xxx瀵瑰簲
+ * @param bound 鏄惁宸茬粡缁戝畾
+ * @param action 璐﹀彿缁戝畾鍥炶皟
+ */
+export interface BindItem extends ListItem {
+  source: string;
+  bound?: boolean;
+  action?: (source: string) => Promise<any>;
+}
+
+/**
+ * todo tenantId
+ * 缁戝畾鎺堟潈浠巙serStore.userInfo鑾峰彇
+ * 鐧诲綍浠巐ocalStorage鑾峰彇
+ * @param source
+ */
+async function handleAuthBinding(source: string) {
+  const tenantId = localStorage.getItem('__oauth_tenant_id') ?? '000000';
+  // 杩欓噷杩斿洖鎵撳紑鎺堟潈椤甸潰鐨勯摼鎺�
+  const href = await authBinding(source, tenantId);
+  window.location.href = href;
+}
+
+/**
+ * 璐﹀彿缁戝畾 list
+ * 娣诲姞璐﹀彿缁戝畾鍙渶瑕佸湪杩欓噷澧炲姞鍗冲彲
+ * 娣诲姞杩囩殑椤圭洰浼氬湪涓汉涓婚〉-缁戝畾璐﹀彿涓樉绀�
+ * action涓嶄负绌虹殑浼氬湪鐧诲綍椤垫樉绀�
+ */
+export const accountBindList: BindItem[] = [
+  {
+    avatar: TaobaoIcon,
+    color: '#ff4000',
+    description: '缁戝畾娣樺疂璐﹀彿',
+    key: '1',
+    source: 'taobao',
+    title: '娣樺疂',
+  },
+  {
+    avatar: AlipayIcon,
+    color: '#2eabff',
+    description: '缁戝畾鏀粯瀹濊处鍙�',
+    key: '2',
+    source: 'alipay',
+    title: '鏀粯瀹�',
+  },
+  {
+    avatar: DingdingIcon,
+    color: '#2eabff',
+    description: '缁戝畾閽夐拤璐﹀彿',
+    key: '3',
+    source: 'ding',
+    title: '閽夐拤',
+  },
+  {
+    action: () => handleAuthBinding('gitee'),
+    avatar: GiteeIcon,
+    color: '#c71d23',
+    description: '缁戝畾GITEE璐﹀彿',
+    key: '4',
+    source: 'gitee',
+    title: 'GITEE',
+  },
+  {
+    action: () => handleAuthBinding('github'),
+    avatar: GithubOAuthIcon,
+    color: '',
+    description: '缁戝畾GITHUB璐﹀彿',
+    key: '5',
+    source: 'github',
+    title: 'GITHUB',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/components/account-bind.vue b/eims-ui/apps/web-antd/src/views/_core/profile/components/account-bind.vue
new file mode 100644
index 0000000..ac3fc92
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/components/account-bind.vue
@@ -0,0 +1,210 @@
+<script setup lang="tsx">
+import { computed, ref, unref } from 'vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '@vben/plugins/vxe-table';
+
+import {
+  Alert,
+  Avatar,
+  Card,
+  List,
+  ListItem,
+  message,
+  Modal,
+} from 'ant-design-vue';
+
+import { authUnbinding } from '#/api';
+import { socialList } from '#/api/system/social';
+
+import { accountBindList, type BindItem } from '../../oauth-common';
+
+/**
+ * 娌℃湁浼犻�抋ction浜嬩欢鍒欎笉鏀寔缁戝畾 寮瑰嚭榛樿鎻愮ず
+ */
+function defaultTip(title: string) {
+  message.info({ content: `鏆備笉鏀寔缁戝畾${title}` });
+}
+
+function buttonText(item: BindItem) {
+  return item.bound ? '宸茬粦瀹�' : '缁戝畾';
+}
+
+/**
+ * 宸茬粡缁戝畾鐨勫钩鍙�
+ */
+const boundPlatformsList = ref<string[]>([]);
+const bindList = computed<BindItem[]>(() => {
+  const list = [...accountBindList];
+  list.forEach((item) => {
+    item.bound = !!unref(boundPlatformsList).includes(item.source);
+  });
+  return list;
+});
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+  },
+  columns: [
+    {
+      field: 'source',
+      title: '缁戝畾骞冲彴',
+    },
+    {
+      slots: {
+        default: ({ row }) => {
+          return <Avatar src={row.avatar} />;
+        },
+      },
+      field: 'avatar',
+      title: '澶村儚',
+    },
+    {
+      align: 'center',
+      field: 'userName',
+      title: '璐﹀彿',
+    },
+    {
+      align: 'center',
+      slots: {
+        default: 'action',
+      },
+      title: '鎿嶄綔',
+    },
+  ],
+  height: 220,
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  toolbarConfig: {
+    custom: false,
+    zoom: false,
+    refresh: false,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async () => {
+        const resp = await socialList();
+        /**
+         * 骞冲彴杞皬鍐�
+         * 宸茬粡缁戝畾鐨勫钩鍙�
+         */
+        boundPlatformsList.value = resp.map((item) =>
+          item.source.toLowerCase(),
+        );
+        return {
+          rows: resp,
+        };
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    isCurrent: false,
+    keyField: 'id',
+  },
+  id: 'profile-bind-table',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  gridOptions,
+});
+
+/**
+ * 瑙g粦璐﹀彿
+ */
+function handleUnbind(record: Record<string, any>) {
+  Modal.confirm({
+    content: `纭畾瑙g粦[${record.source}]骞冲彴鐨刐${record.userName}]璐﹀彿鍚楋紵`,
+    async onOk() {
+      await authUnbinding(record.id);
+      await tableApi.reload();
+    },
+    title: '鎻愮ず',
+    type: 'warning',
+  });
+}
+</script>
+
+<template>
+  <div class="flex flex-col gap-[16px]">
+    <BasicTable>
+      <template #action="{ row }">
+        <a-button type="link" @click="handleUnbind(row)">瑙g粦</a-button>
+      </template>
+    </BasicTable>
+    <div class="pb-3">
+      <List
+        :data-source="bindList"
+        :grid="{ gutter: 8, xs: 1, sm: 1, md: 2, lg: 3, xl: 3, xxl: 3 }"
+      >
+        <template #renderItem="{ item }">
+          <ListItem>
+            <Card>
+              <div class="flex w-full items-center gap-4">
+                <div>
+                  <component
+                    :is="item.avatar"
+                    v-if="item.avatar"
+                    :style="{ color: item.color }"
+                    class="size-[40px]"
+                  />
+                </div>
+                <div class="flex flex-1 items-center justify-between">
+                  <div class="flex flex-col">
+                    <h4
+                      class="mb-[4px] text-[14px] text-black/85 dark:text-white/85"
+                    >
+                      {{ item.title }}
+                    </h4>
+                    <span class="text-black/45 dark:text-white/45">
+                      {{ item.description }}
+                    </span>
+                  </div>
+                  <a-button
+                    :disabled="item.bound"
+                    size="small"
+                    type="link"
+                    @click="
+                      item.action ? item.action() : defaultTip(item.title)
+                    "
+                  >
+                    {{ buttonText(item) }}
+                  </a-button>
+                </div>
+              </div>
+            </Card>
+          </ListItem>
+        </template>
+      </List>
+      <Alert message="璇存槑" type="info">
+        <template #description>
+          <p>
+            闇�瑕佹坊鍔犵涓夋柟璐﹀彿鍦�
+            <span class="font-bold">
+              apps\web-antd\src\views\_core\oauth-common.ts
+            </span>
+            涓璦ccountBindList鎸夋ā鏉挎坊鍔�
+          </p>
+          <p>
+            娣诲姞瀵瑰簲妯℃澘鍚庝細鍦ㄦ澶勬樉绀虹粦瀹�, 浣嗗彧鏈�
+            <span class="font-bold">瀹炵幇浜哸ction鎵嶈兘鍦ㄧ櫥褰曢〉鏄剧ず</span>
+          </p>
+        </template>
+      </Alert>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+/**
+list item 闂磋窛
+*/
+:deep(.ant-list-item) {
+  padding: 6px;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/components/base-setting.vue b/eims-ui/apps/web-antd/src/views/_core/profile/components/base-setting.vue
new file mode 100644
index 0000000..1801b23
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/components/base-setting.vue
@@ -0,0 +1,120 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import type { UserProfile } from '#/api/system/profile/model';
+
+import { onMounted } from 'vue';
+
+import { DictEnum } from '@vben/constants';
+import { useUserStore } from '@vben/stores';
+
+import { pick } from 'lodash-es';
+
+import { useVbenForm, z } from '#/adapter/form';
+import { userProfileUpdate } from '#/api/system/profile';
+import { useAuthStore } from '#/store';
+import { getDictOptions } from '#/utils/dict';
+
+import { emitter } from '../mitt';
+
+const props = defineProps<{ profile: UserProfile }>();
+
+const userStore = useUserStore();
+const authStore = useAuthStore();
+
+const [BasicForm, formApi] = useVbenForm({
+  actionWrapperClass: 'text-left ml-[68px] mb-[16px]',
+  commonConfig: {
+    labelWidth: 60,
+  },
+  handleSubmit,
+  resetButtonOptions: {
+    show: false,
+  },
+  schema: [
+    {
+      component: 'Input',
+      dependencies: {
+        show: () => false,
+        triggerFields: [''],
+      },
+      fieldName: 'userId',
+      label: '鐢ㄦ埛ID',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      fieldName: 'nickName',
+      label: '鏄电О',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      fieldName: 'email',
+      label: '閭',
+      rules: z.string().email('璇疯緭鍏ユ纭殑閭'),
+    },
+    {
+      component: 'RadioGroup',
+      componentProps: {
+        buttonStyle: 'solid',
+        options: getDictOptions(DictEnum.SYS_USER_SEX),
+        optionType: 'button',
+      },
+      defaultValue: '0',
+      fieldName: 'sex',
+      label: '鎬у埆',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      fieldName: 'phonenumber',
+      label: '鐢佃瘽',
+      rules: z.string().regex(/^1[3-9]\d{9}$/, '璇疯緭鍏ユ纭殑鐢佃瘽'),
+    },
+  ],
+  submitButtonOptions: {
+    content: '鏇存柊淇℃伅',
+  },
+});
+
+function buttonLoading(loading: boolean) {
+  formApi.setState((prev) => ({
+    ...prev,
+    submitButtonOptions: { ...prev.submitButtonOptions, loading },
+  }));
+}
+
+async function handleSubmit(values: Recordable<any>) {
+  try {
+    buttonLoading(true);
+    await userProfileUpdate(values);
+    // 鏇存柊store
+    const userInfo = await authStore.fetchUserInfo();
+    userStore.setUserInfo(userInfo);
+    // 宸﹁竟reload
+    emitter.emit('updateProfile');
+  } catch (error) {
+    console.error(error);
+  } finally {
+    buttonLoading(false);
+  }
+}
+
+onMounted(() => {
+  const data = pick(props.profile.user, [
+    'userId',
+    'nickName',
+    'email',
+    'phonenumber',
+    'sex',
+  ]);
+  formApi.setValues(data);
+});
+</script>
+
+<template>
+  <div class="mt-[16px] md:w-full lg:w-1/2 2xl:w-2/5">
+    <BasicForm />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/components/online-device.vue b/eims-ui/apps/web-antd/src/views/_core/profile/components/online-device.vue
new file mode 100644
index 0000000..45ceae6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/components/online-device.vue
@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Popconfirm } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { forceLogout2, onlineDeviceList } from '#/api/monitor/online';
+import { columns } from '#/views/monitor/online/data';
+
+const gridOptions: VxeGridProps = {
+  columns,
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async () => {
+        return await onlineDeviceList();
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'tokenId',
+  },
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ gridOptions });
+
+async function handleForceOffline(row: Recordable<any>) {
+  await forceLogout2(row.tokenId);
+  await tableApi.query();
+}
+</script>
+
+<template>
+  <div>
+    <BasicTable table-title="鎴戠殑鍦ㄧ嚎璁惧">
+      <template #action="{ row }">
+        <Popconfirm
+          :title="`纭寮哄埗涓嬬嚎[${row.userName}]?`"
+          placement="left"
+          @confirm="handleForceOffline(row)"
+        >
+          <a-button danger size="small" type="link">寮哄埗涓嬬嚎</a-button>
+        </Popconfirm>
+      </template>
+    </BasicTable>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/components/secure-setting.vue b/eims-ui/apps/web-antd/src/views/_core/profile/components/secure-setting.vue
new file mode 100644
index 0000000..5858307
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/components/secure-setting.vue
@@ -0,0 +1,106 @@
+<script setup lang="ts">
+import type { UpdatePasswordParam } from '#/api/system/profile/model';
+
+import { Modal } from 'ant-design-vue';
+import { omit } from 'lodash-es';
+
+import { useVbenForm, z } from '#/adapter/form';
+import { userUpdatePassword } from '#/api/system/profile';
+import { useAuthStore } from '#/store';
+
+const [BasicForm, formApi] = useVbenForm({
+  actionWrapperClass: 'text-left mb-[16px] ml-[96px]',
+  commonConfig: {
+    labelWidth: 90,
+  },
+  handleSubmit,
+  resetButtonOptions: {
+    show: false,
+  },
+  schema: [
+    {
+      component: 'InputPassword',
+      fieldName: 'oldPassword',
+      label: '鏃у瘑鐮�',
+      rules: z
+        .string({ message: '璇疯緭鍏ュ瘑鐮�' })
+        .min(5, '瀵嗙爜闀垮害涓嶈兘灏戜簬5涓瓧绗�')
+        .max(20, '瀵嗙爜闀垮害涓嶈兘瓒呰繃20涓瓧绗�'),
+    },
+    {
+      component: 'InputPassword',
+      dependencies: {
+        rules(values) {
+          return z
+            .string({ message: '璇疯緭鍏ユ柊瀵嗙爜' })
+            .min(5, '瀵嗙爜闀垮害涓嶈兘灏戜簬5涓瓧绗�')
+            .max(20, '瀵嗙爜闀垮害涓嶈兘瓒呰繃20涓瓧绗�')
+            .refine(
+              (value) => value !== values.oldPassword,
+              '鏂版棫瀵嗙爜涓嶈兘鐩稿悓',
+            );
+        },
+        triggerFields: ['newPassword', 'oldPassword'],
+      },
+      fieldName: 'newPassword',
+      label: '鏂板瘑鐮�',
+      rules: 'required',
+    },
+    {
+      component: 'InputPassword',
+      dependencies: {
+        rules(values) {
+          return z
+            .string({ message: '璇疯緭鍏ョ‘璁ゅ瘑鐮�' })
+            .min(5, '瀵嗙爜闀垮害涓嶈兘灏戜簬5涓瓧绗�')
+            .max(20, '瀵嗙爜闀垮害涓嶈兘瓒呰繃20涓瓧绗�')
+            .refine(
+              (value) => value === values.newPassword,
+              '鏂板瘑鐮佸拰纭瀵嗙爜涓嶄竴鑷�',
+            );
+        },
+        triggerFields: ['newPassword', 'confirmPassword'],
+      },
+      fieldName: 'confirmPassword',
+      label: '纭瀵嗙爜',
+      rules: 'required',
+    },
+  ],
+  submitButtonOptions: {
+    content: '淇敼瀵嗙爜',
+  },
+});
+
+function buttonLoading(loading: boolean) {
+  formApi.setState((prev) => ({
+    ...prev,
+    submitButtonOptions: { ...prev.submitButtonOptions, loading },
+  }));
+}
+
+const authStore = useAuthStore();
+function handleSubmit(values: any) {
+  Modal.confirm({
+    content: '纭淇敼瀵嗙爜鍚楋紵',
+    onOk: async () => {
+      try {
+        buttonLoading(true);
+        const data = omit(values, ['confirmPassword']) as UpdatePasswordParam;
+        await userUpdatePassword(data);
+        await authStore.logout(true);
+      } catch (error) {
+        console.error(error);
+      } finally {
+        buttonLoading(false);
+      }
+    },
+    title: '鎻愮ず',
+  });
+}
+</script>
+
+<template>
+  <div class="mt-[16px] md:w-full lg:w-1/2 2xl:w-2/5">
+    <BasicForm />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/index.vue b/eims-ui/apps/web-antd/src/views/_core/profile/index.vue
new file mode 100644
index 0000000..a3af56c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/index.vue
@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import type { UserProfile } from '#/api/system/profile/model';
+
+import { onMounted, onUnmounted, ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+import { useUserStore } from '@vben/stores';
+
+import { userProfile } from '#/api/system/profile';
+import { useAuthStore } from '#/store';
+
+import { emitter } from './mitt';
+import ProfilePanel from './profile-panel.vue';
+import SettingPanel from './setting-panel.vue';
+
+const profile = ref<UserProfile>();
+async function loadProfile() {
+  const resp = await userProfile();
+  profile.value = resp;
+}
+
+onMounted(loadProfile);
+
+const authStore = useAuthStore();
+const userStore = useUserStore();
+/**
+ * ToDo 鎺ュ彛閲嶅
+ */
+async function handleUploadFinish() {
+  // 閲嶆柊鍔犺浇鐢ㄦ埛淇℃伅
+  await loadProfile();
+  // 鏇存柊store
+  const userInfo = await authStore.fetchUserInfo();
+  userStore.setUserInfo(userInfo);
+}
+
+onMounted(() => emitter.on('updateProfile', loadProfile));
+onUnmounted(() => emitter.off('updateProfile'));
+</script>
+
+<template>
+  <Page>
+    <div class="flex flex-col gap-[16px] lg:flex-row">
+      <!-- 宸︿晶 -->
+      <ProfilePanel :profile="profile" @upload-finish="handleUploadFinish" />
+      <!-- 鍙充晶 -->
+      <SettingPanel
+        v-if="profile"
+        :profile="profile"
+        class="flex-1 overflow-hidden"
+      />
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/mitt.ts b/eims-ui/apps/web-antd/src/views/_core/profile/mitt.ts
new file mode 100644
index 0000000..9499b91
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/mitt.ts
@@ -0,0 +1,7 @@
+import { mitt } from '@vben/utils';
+
+type Events = {
+  updateProfile: void;
+};
+
+export const emitter = mitt<Events>();
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/profile-panel.vue b/eims-ui/apps/web-antd/src/views/_core/profile/profile-panel.vue
new file mode 100644
index 0000000..6501d0a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/profile-panel.vue
@@ -0,0 +1,84 @@
+<script setup lang="ts">
+import type { UserProfile } from '#/api/system/profile/model';
+
+import { computed } from 'vue';
+
+import { preferences, usePreferences } from '@vben/preferences';
+
+import {
+  Card,
+  Descriptions,
+  DescriptionsItem,
+  Tag,
+  Tooltip,
+} from 'ant-design-vue';
+
+import { userUpdateAvatar } from '#/api/system/profile';
+import { CropperAvatar } from '#/components/cropper';
+
+const props = defineProps<{ profile?: UserProfile }>();
+
+defineEmits<{
+  // 澶村儚涓婁紶瀹屾瘯
+  uploadFinish: [];
+}>();
+
+const avatar = computed(
+  () => props.profile?.user.avatar ?? preferences.app.defaultAvatar,
+);
+
+const { isDark } = usePreferences();
+const poetrySrc = computed(() => {
+  const color = isDark.value ? 'white' : 'gray';
+  return `https://v2.jinrishici.com/one.svg?font-size=12&color=${color}`;
+});
+</script>
+
+<template>
+  <Card :loading="!profile" class="h-full lg:w-1/3">
+    <div v-if="profile" class="flex flex-col items-center gap-[24px]">
+      <div class="flex flex-col items-center gap-[20px]">
+        <Tooltip title="鐐瑰嚮涓婁紶澶村儚">
+          <CropperAvatar
+            :show-btn="false"
+            :upload-api="userUpdateAvatar"
+            :value="avatar"
+            width="120"
+            @change="$emit('uploadFinish')"
+          />
+        </Tooltip>
+        <div class="flex flex-col items-center gap-[8px]">
+          <span class="text-foreground text-xl font-bold">
+            {{ profile.user.nickName ?? '鏈煡' }}
+          </span>
+          <!-- https://www.jinrishici.com/doc/#image -->
+          <img :src="poetrySrc" />
+        </div>
+      </div>
+      <div class="px-[24px]">
+        <Descriptions :column="1">
+          <DescriptionsItem label="璐﹀彿">
+            {{ profile.user.userName }}
+          </DescriptionsItem>
+          <DescriptionsItem label="鎵嬫満鍙风爜">
+            {{ profile.user.phonenumber || '鏈粦瀹氭墜鏈哄彿' }}
+          </DescriptionsItem>
+          <DescriptionsItem label="閭">
+            {{ profile.user.email || '鏈粦瀹氶偖绠�' }}
+          </DescriptionsItem>
+          <DescriptionsItem label="閮ㄩ棬">
+            <Tag color="processing">
+              {{ profile.user.deptName ?? '鏈垎閰嶉儴闂�' }}
+            </Tag>
+            <Tag v-if="profile.postGroup" color="processing">
+              {{ profile.postGroup }}
+            </Tag>
+          </DescriptionsItem>
+          <DescriptionsItem label="涓婃鐧诲綍">
+            {{ profile.user.loginDate }}
+          </DescriptionsItem>
+        </Descriptions>
+      </div>
+    </div>
+  </Card>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/profile/setting-panel.vue b/eims-ui/apps/web-antd/src/views/_core/profile/setting-panel.vue
new file mode 100644
index 0000000..4fb8085
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/profile/setting-panel.vue
@@ -0,0 +1,59 @@
+<script lang="ts">
+import { defineComponent } from 'vue';
+
+import { TabPane, Tabs } from 'ant-design-vue';
+
+import AccountBind from './components/account-bind.vue';
+import BaseSetting from './components/base-setting.vue';
+import OnlineDevice from './components/online-device.vue';
+import SecureSetting from './components/secure-setting.vue';
+
+export default defineComponent({
+  components: {
+    AccountBind,
+    BaseSetting,
+    OnlineDevice,
+    SecureSetting,
+    TabPane,
+    Tabs,
+  },
+  setup() {
+    const settingList = [
+      {
+        component: 'BaseSetting',
+        key: '1',
+        name: '鍩烘湰璁剧疆',
+      },
+      {
+        component: 'SecureSetting',
+        key: '2',
+        name: '瀹夊叏璁剧疆',
+      },
+      {
+        component: 'AccountBind',
+        key: '3',
+        name: '璐﹀彿缁戝畾',
+      },
+      {
+        component: 'OnlineDevice',
+        key: '4',
+        name: '鍦ㄧ嚎璁惧',
+      },
+    ];
+
+    return {
+      settingList,
+    };
+  },
+});
+</script>
+
+<template>
+  <Tabs class="bg-background rounded-[var(--radius)] px-[16px] lg:flex-1">
+    <template v-for="item in settingList" :key="item.key">
+      <TabPane :tab="item.name">
+        <component :is="item.component" v-bind="$attrs" />
+      </TabPane>
+    </template>
+  </Tabs>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/_core/social-callback/index.vue b/eims-ui/apps/web-antd/src/views/_core/social-callback/index.vue
new file mode 100644
index 0000000..ad7135f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/_core/social-callback/index.vue
@@ -0,0 +1,81 @@
+<script setup lang="ts">
+import { onMounted } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+import { DEFAULT_HOME_PATH } from '@vben/constants';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'ant-design-vue';
+
+import { type AuthApi, authCallback } from '#/api';
+import { useAuthStore } from '#/store';
+
+import { accountBindList } from '../oauth-common';
+
+const route = useRoute();
+
+const code = route.query.code as string;
+const state = route.query.state as string;
+const stateJson = JSON.parse(atob(state));
+// 鏉ユ簮
+const source = route.query.source as string;
+// 绉熸埛ID
+const defaultTenantId = '000000';
+const tenantId = (stateJson.tenantId as string) ?? defaultTenantId;
+const domain = stateJson.domain as string;
+
+const accessStore = useAccessStore();
+const authStore = useAuthStore();
+
+const router = useRouter();
+
+onMounted(async () => {
+  // 濡傛灉鍩熷悕涓嶇浉绛� 鍒欓噸瀹氬悜澶勭悊
+  const host = window.location.host;
+  if (domain !== host) {
+    const urlFull = new URL(window.location.href);
+    urlFull.host = domain;
+    window.location.href = urlFull.toString();
+    return;
+  }
+
+  try {
+    // 宸茬粡瀹炵幇鐨勫钩鍙�
+    const currentClient = accountBindList.find(
+      (item) => item.source === source && item.action,
+    );
+    if (!currentClient) {
+      message.error({ content: `鏈壘鍒�${source}骞冲彴` });
+      return;
+    }
+    const data: AuthApi.OAuthLoginParams = {
+      grantType: 'social',
+      socialCode: code,
+      socialState: state,
+      source,
+      tenantId,
+    };
+    // 娌℃湁token涓虹櫥褰� 鏈塼oken鏄巿鏉�
+    if (accessStore.accessToken) {
+      await authCallback(data);
+      message.success(`${source}鎺堟潈鎴愬姛`);
+    } else {
+      // todo
+      await authStore.authLogin(data as any);
+      message.success(`${source}鐧诲綍鎴愬姛`);
+    }
+  } catch {
+    // 500 浣犺繕娌℃湁缁戝畾绗笁鏂硅处鍙凤紝缁戝畾鍚庢墠鍙互鐧诲綍锛�
+  } finally {
+    setTimeout(() => {
+      router.push(DEFAULT_HOME_PATH);
+    }, 1500);
+  }
+});
+</script>
+
+<template>
+  <div></div>
+</template>
+
+<style scoped></style>
diff --git a/eims-ui/apps/web-antd/src/views/common.tsx b/eims-ui/apps/web-antd/src/views/common.tsx
new file mode 100644
index 0000000..2e257da
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/common.tsx
@@ -0,0 +1,18 @@
+import { defineComponent } from 'vue';
+
+import { Fallback } from '@vben/common-ui';
+
+export default defineComponent({
+  name: 'CommonSkeleton',
+  setup() {
+    return () => (
+      <div class="flex h-[600px] w-full items-center justify-center">
+        <Fallback
+          description="绛夊緟鍚庣閲嶆瀯宸ヤ綔娴佸悗寮�鍙�"
+          status="coming-soon"
+          title="绛夊緟寮�鍙�"
+        />
+      </div>
+    );
+  },
+});
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue
new file mode 100644
index 0000000..fadfc91
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue
@@ -0,0 +1,100 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        areaStyle: {},
+        data: [
+          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,
+          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,
+          111,
+        ],
+        itemStyle: {
+          color: '#5ab1ef',
+        },
+        smooth: true,
+        type: 'line',
+      },
+      {
+        areaStyle: {},
+        data: [
+          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,
+          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,
+        ],
+        itemStyle: {
+          color: '#019680',
+        },
+        smooth: true,
+        type: 'line',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          color: '#019680',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    // xAxis: {
+    //   axisTick: {
+    //     show: false,
+    //   },
+    //   boundaryGap: false,
+    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+    //   type: 'category',
+    // },
+    xAxis: {
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: false,
+      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+      splitLine: {
+        lineStyle: {
+          type: 'solid',
+          width: 1,
+        },
+        show: true,
+      },
+      type: 'category',
+    },
+    yAxis: [
+      {
+        axisTick: {
+          show: false,
+        },
+        max: 80_000,
+        splitArea: {
+          show: true,
+        },
+        splitNumber: 4,
+        type: 'value',
+      },
+    ],
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue
new file mode 100644
index 0000000..30c4265
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue
@@ -0,0 +1,84 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: 0,
+      data: ['璁块棶', '瓒嬪娍'],
+    },
+    radar: {
+      indicator: [
+        {
+          name: '缃戦〉',
+        },
+        {
+          name: '绉诲姩绔�',
+        },
+        {
+          name: 'Ipad',
+        },
+        {
+          name: '瀹㈡埛绔�',
+        },
+        {
+          name: '绗笁鏂�',
+        },
+        {
+          name: '鍏跺畠',
+        },
+      ],
+      radius: '60%',
+      splitNumber: 8,
+    },
+    series: [
+      {
+        areaStyle: {
+          opacity: 1,
+          shadowBlur: 0,
+          shadowColor: 'rgba(0,0,0,.2)',
+          shadowOffsetX: 0,
+          shadowOffsetY: 10,
+        },
+        data: [
+          {
+            itemStyle: {
+              color: '#b6a2de',
+            },
+            name: '璁块棶',
+            value: [90, 50, 86, 40, 50, 20],
+          },
+          {
+            itemStyle: {
+              color: '#5ab1ef',
+            },
+            name: '瓒嬪娍',
+            value: [70, 75, 70, 76, 20, 85],
+          },
+        ],
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        symbolSize: 0,
+        type: 'radar',
+      },
+    ],
+    tooltip: {},
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue
new file mode 100644
index 0000000..260520b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue
@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 400;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        center: ['50%', '50%'],
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '澶栧寘', value: 500 },
+          { name: '瀹氬埗', value: 310 },
+          { name: '鎶�鏈敮鎸�', value: 274 },
+          { name: '杩滅▼', value: 400 },
+        ].sort((a, b) => {
+          return a.value - b.value;
+        }),
+        name: '鍟嗕笟鍗犳瘮',
+        radius: '80%',
+        roseType: 'radius',
+        type: 'pie',
+      },
+    ],
+
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue
new file mode 100644
index 0000000..e0d0aab
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue
@@ -0,0 +1,67 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: '2%',
+      left: 'center',
+    },
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 100;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        avoidLabelOverlap: false,
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '鎼滅储寮曟搸', value: 1048 },
+          { name: '鐩存帴璁块棶', value: 735 },
+          { name: '閭欢钀ラ攢', value: 580 },
+          { name: '鑱旂洘骞垮憡', value: 484 },
+        ],
+        emphasis: {
+          label: {
+            fontSize: '12',
+            fontWeight: 'bold',
+            show: true,
+          },
+        },
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        label: {
+          position: 'center',
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        name: '璁块棶鏉ユ簮',
+        radius: ['40%', '65%'],
+        type: 'pie',
+      },
+    ],
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue
new file mode 100644
index 0000000..7e1f14e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue
@@ -0,0 +1,57 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        barMaxWidth: 80,
+        // color: '#4f69fd',
+        data: [
+          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,
+          3200, 4800,
+        ],
+        type: 'bar',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          // color: '#4f69fd',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    xAxis: {
+      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}鏈坄),
+      type: 'category',
+    },
+    yAxis: {
+      max: 8000,
+      splitNumber: 4,
+      type: 'value',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/analytics/index.vue b/eims-ui/apps/web-antd/src/views/dashboard/analytics/index.vue
new file mode 100644
index 0000000..00b34df
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/analytics/index.vue
@@ -0,0 +1,90 @@
+<script lang="ts" setup>
+import type { AnalysisOverviewItem } from '@vben/common-ui';
+import type { TabOption } from '@vben/types';
+
+import {
+  AnalysisChartCard,
+  AnalysisChartsTabs,
+  AnalysisOverview,
+} from '@vben/common-ui';
+import {
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+} from '@vben/icons';
+
+import AnalyticsTrends from './analytics-trends.vue';
+import AnalyticsVisits from './analytics-visits.vue';
+import AnalyticsVisitsData from './analytics-visits-data.vue';
+import AnalyticsVisitsSales from './analytics-visits-sales.vue';
+import AnalyticsVisitsSource from './analytics-visits-source.vue';
+
+const overviewItems: AnalysisOverviewItem[] = [
+  {
+    icon: SvgCardIcon,
+    title: '鐢ㄦ埛閲�',
+    totalTitle: '鎬荤敤鎴烽噺',
+    totalValue: 120_000,
+    value: 2000,
+  },
+  {
+    icon: SvgCakeIcon,
+    title: '璁块棶閲�',
+    totalTitle: '鎬昏闂噺',
+    totalValue: 500_000,
+    value: 20_000,
+  },
+  {
+    icon: SvgDownloadIcon,
+    title: '涓嬭浇閲�',
+    totalTitle: '鎬讳笅杞介噺',
+    totalValue: 120_000,
+    value: 8000,
+  },
+  {
+    icon: SvgBellIcon,
+    title: '浣跨敤閲�',
+    totalTitle: '鎬讳娇鐢ㄩ噺',
+    totalValue: 50_000,
+    value: 5000,
+  },
+];
+
+const chartTabs: TabOption[] = [
+  {
+    label: '娴侀噺瓒嬪娍',
+    value: 'trends',
+  },
+  {
+    label: '鏈堣闂噺',
+    value: 'visits',
+  },
+];
+</script>
+
+<template>
+  <div class="p-5">
+    <AnalysisOverview :items="overviewItems" />
+    <AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
+      <template #trends>
+        <AnalyticsTrends />
+      </template>
+      <template #visits>
+        <AnalyticsVisits />
+      </template>
+    </AnalysisChartsTabs>
+
+    <div class="mt-5 w-full md:flex">
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏁伴噺">
+        <AnalyticsVisitsData />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSource />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSales />
+      </AnalysisChartCard>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/dashboard/workspace/index.vue b/eims-ui/apps/web-antd/src/views/dashboard/workspace/index.vue
new file mode 100644
index 0000000..b95d613
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/dashboard/workspace/index.vue
@@ -0,0 +1,266 @@
+<script lang="ts" setup>
+import type {
+  WorkbenchProjectItem,
+  WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
+} from '@vben/common-ui';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import {
+  AnalysisChartCard,
+  WorkbenchHeader,
+  WorkbenchProject,
+  WorkbenchQuickNav,
+  WorkbenchTodo,
+  WorkbenchTrends,
+} from '@vben/common-ui';
+import { preferences } from '@vben/preferences';
+import { useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';
+
+const userStore = useUserStore();
+
+// 杩欐槸涓�涓ず渚嬫暟鎹紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// url 涔熷彲浠ユ槸鍐呴儴璺敱锛屽湪 navTo 鏂规硶涓瘑鍒鐞嗭紝杩涜鍐呴儴璺宠浆
+// 渚嬪锛歶rl: /dashboard/workspace
+const projectItems: WorkbenchProjectItem[] = [
+  {
+    color: '',
+    content: '涓嶈绛夊緟鏈轰細锛岃�岃鍒涢�犳満浼氥��',
+    date: '2021-04-01',
+    group: '寮�婧愮粍',
+    icon: 'carbon:logo-github',
+    title: 'Github',
+    url: 'https://github.com',
+  },
+  {
+    color: '#3fb27f',
+    content: '鐜板湪鐨勪綘鍐冲畾灏嗘潵鐨勪綘銆�',
+    date: '2021-04-01',
+    group: '绠楁硶缁�',
+    icon: 'ion:logo-vue',
+    title: 'Vue',
+    url: 'https://vuejs.org',
+  },
+  {
+    color: '#e18525',
+    content: '娌℃湁浠�涔堟墠鑳芥瘮鍔姏鏇撮噸瑕併��',
+    date: '2021-04-01',
+    group: '涓婄彮鎽搁奔',
+    icon: 'ion:logo-html5',
+    title: 'Html5',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',
+  },
+  {
+    color: '#bf0c2c',
+    content: '鐑儏鍜屾鏈涘彲浠ョ獊鐮翠竴鍒囬毦鍏炽��',
+    date: '2021-04-01',
+    group: 'UI',
+    icon: 'ion:logo-angular',
+    title: 'Angular',
+    url: 'https://angular.io',
+  },
+  {
+    color: '#00d8ff',
+    content: '鍋ュ悍鐨勮韩浣撴槸瀹炵幇鐩爣鐨勫熀鐭炽��',
+    date: '2021-04-01',
+    group: '鎶�鏈墰',
+    icon: 'bx:bxl-react',
+    title: 'React',
+    url: 'https://reactjs.org',
+  },
+  {
+    color: '#EBD94E',
+    content: '璺槸璧板嚭鏉ョ殑锛岃�屼笉鏄┖鎯冲嚭鏉ョ殑銆�',
+    date: '2021-04-01',
+    group: '鏋舵瀯缁�',
+    icon: 'ion:logo-javascript',
+    title: 'Js',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',
+  },
+];
+
+// 鍚屾牱锛岃繖閲岀殑 url 涔熷彲浠ヤ娇鐢ㄤ互 http 寮�澶寸殑澶栭儴閾炬帴
+const quickNavItems: WorkbenchQuickNavItem[] = [
+  {
+    color: '#1fdaca',
+    icon: 'ion:home-outline',
+    title: '棣栭〉',
+    url: '/',
+  },
+  {
+    color: '#bf0c2c',
+    icon: 'ion:grid-outline',
+    title: '浠〃鐩�',
+    url: '/dashboard',
+  },
+  {
+    color: '#e18525',
+    icon: 'ion:layers-outline',
+    title: '缁勪欢',
+    url: '/demos/features/icons',
+  },
+  {
+    color: '#3fb27f',
+    icon: 'ion:settings-outline',
+    title: '绯荤粺绠$悊',
+    url: '/demos/features/login-expired', // 杩欓噷鐨� URL 鏄ず渚嬶紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+  },
+  {
+    color: '#4daf1bc9',
+    icon: 'ion:key-outline',
+    title: '鏉冮檺绠$悊',
+    url: '/demos/access/page-control',
+  },
+  {
+    color: '#00d8ff',
+    icon: 'ion:bar-chart-outline',
+    title: '鍥捐〃',
+    url: '/analytics',
+  },
+];
+
+const todoItems = ref<WorkbenchTodoItem[]>([
+  {
+    completed: false,
+    content: `瀹℃煡鏈�杩戞彁浜ゅ埌Git浠撳簱鐨勫墠绔唬鐮侊紝纭繚浠g爜璐ㄩ噺鍜岃鑼冦�俙,
+    date: '2024-07-30 11:00:00',
+    title: '瀹℃煡鍓嶇浠g爜鎻愪氦',
+  },
+  {
+    completed: true,
+    content: `妫�鏌ュ苟浼樺寲绯荤粺鎬ц兘锛岄檷浣嶤PU浣跨敤鐜囥�俙,
+    date: '2024-07-30 11:00:00',
+    title: '绯荤粺鎬ц兘浼樺寲',
+  },
+  {
+    completed: false,
+    content: `杩涜绯荤粺瀹夊叏妫�鏌ワ紝纭繚娌℃湁瀹夊叏婕忔礊鎴栨湭鎺堟潈鐨勮闂�� `,
+    date: '2024-07-30 11:00:00',
+    title: '瀹夊叏妫�鏌�',
+  },
+  {
+    completed: false,
+    content: `鏇存柊椤圭洰涓殑鎵�鏈塶pm渚濊禆鍖咃紝纭繚浣跨敤鏈�鏂扮増鏈�俙,
+    date: '2024-07-30 11:00:00',
+    title: '鏇存柊椤圭洰渚濊禆',
+  },
+  {
+    completed: false,
+    content: `淇鐢ㄦ埛鎶ュ憡鐨勯〉闈I鏄剧ず闂锛岀‘淇濆湪涓嶅悓娴忚鍣ㄤ腑鏄剧ず涓�鑷淬�� `,
+    date: '2024-07-30 11:00:00',
+    title: '淇UI鏄剧ず闂',
+  },
+]);
+const trendItems: WorkbenchTrendItem[] = [
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍦� <a>寮�婧愮粍</a> 鍒涘缓浜嗛」鐩� <a>Vue</a>`,
+    date: '鍒氬垰',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏虫敞浜� <a>濞佸粔</a> `,
+    date: '1涓皬鏃跺墠',
+    title: '鑹炬枃',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1澶╁墠',
+    title: '鍏嬮噷鏂�',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓涓�涓猇ite鎻掍欢</a> `,
+    date: '2澶╁墠',
+    title: 'Vben',
+  },
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍥炲浜� <a>鏉板厠</a> 鐨勯棶棰� <a>濡備綍杩涜椤圭洰浼樺寲锛�</a>`,
+    date: '3澶╁墠',
+    title: '鐨壒',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏抽棴浜嗛棶棰� <a>濡備綍杩愯椤圭洰</a> `,
+    date: '1鍛ㄥ墠',
+    title: '鏉板厠',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1鍛ㄥ墠',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鎺ㄩ�佷簡浠g爜鍒� <a>Github</a>`,
+    date: '2021-04-01 20:00',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓浣跨敤 Admin Vben</a> `,
+    date: '2021-03-01 20:00',
+    title: 'Vben',
+  },
+];
+
+const router = useRouter();
+
+// 杩欐槸涓�涓ず渚嬫柟娉曪紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// This is a sample method, adjust according to the actual project requirements
+function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {
+  if (nav.url?.startsWith('http')) {
+    openWindow(nav.url);
+    return;
+  }
+  if (nav.url?.startsWith('/')) {
+    router.push(nav.url).catch((error) => {
+      console.error('Navigation failed:', error);
+    });
+  } else {
+    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);
+  }
+}
+</script>
+
+<template>
+  <div class="p-5">
+    <WorkbenchHeader
+      :avatar="userStore.userInfo?.avatar || preferences.app.defaultAvatar"
+    >
+      <template #title>
+        鏃╁畨, {{ userStore.userInfo?.realName }}, 寮�濮嬫偍涓�澶╃殑宸ヤ綔鍚э紒
+      </template>
+      <template #description> 浠婃棩鏅达紝20鈩� - 32鈩冿紒 </template>
+    </WorkbenchHeader>
+
+    <div class="mt-5 flex flex-col lg:flex-row">
+      <div class="mr-4 w-full lg:w-3/5">
+        <WorkbenchProject :items="projectItems" title="椤圭洰" @click="navTo" />
+        <WorkbenchTrends :items="trendItems" class="mt-5" title="鏈�鏂板姩鎬�" />
+      </div>
+      <div class="w-full lg:w-2/5">
+        <WorkbenchQuickNav
+          :items="quickNavItems"
+          class="mt-5 lg:mt-0"
+          title="蹇嵎瀵艰埅"
+          @click="navTo"
+        />
+        <WorkbenchTodo :items="todoItems" class="mt-5" title="寰呭姙浜嬮」" />
+        <AnalysisChartCard class="mt-5" title="璁块棶鏉ユ簮">
+          <AnalyticsVisitsSource />
+        </AnalysisChartCard>
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/demo/demo/api/index.ts b/eims-ui/apps/web-antd/src/views/demo/demo/api/index.ts
new file mode 100755
index 0000000..4590457
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/demo/api/index.ts
@@ -0,0 +1,60 @@
+import type { DemoForm, DemoQuery, DemoVO } from './model';
+
+import type { ID, IDS, PageResult } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+/**
+ * 鏌ヨ娴嬭瘯鍗曡〃鍒楄〃
+ * @param params
+ * @returns 娴嬭瘯鍗曡〃鍒楄〃
+ */
+export function demoList(params?: DemoQuery) {
+  return requestClient.get<PageResult<DemoVO>>('/demo/demo/list', { params });
+}
+
+/**
+ * 瀵煎嚭娴嬭瘯鍗曡〃鍒楄〃
+ * @param params
+ * @returns 娴嬭瘯鍗曡〃鍒楄〃
+ */
+export function demoExport(params?: DemoQuery) {
+  return commonExport('/demo/demo/export', params ?? {});
+}
+
+/**
+ * 鏌ヨ娴嬭瘯鍗曡〃璇︽儏
+ * @param id id
+ * @returns 娴嬭瘯鍗曡〃璇︽儏
+ */
+export function demoInfo(id: ID) {
+  return requestClient.get<DemoVO>(`/demo/demo/${id}`);
+}
+
+/**
+ * 鏂板娴嬭瘯鍗曡〃
+ * @param data
+ * @returns void
+ */
+export function demoAdd(data: DemoForm) {
+  return requestClient.postWithMsg<void>('/demo/demo', data);
+}
+
+/**
+ * 鏇存柊娴嬭瘯鍗曡〃
+ * @param data
+ * @returns void
+ */
+export function demoUpdate(data: DemoForm) {
+  return requestClient.putWithMsg<void>('/demo/demo', data);
+}
+
+/**
+ * 鍒犻櫎娴嬭瘯鍗曡〃
+ * @param id id
+ * @returns void
+ */
+export function demoRemove(id: ID | IDS) {
+  return requestClient.deleteWithMsg<void>(`/demo/demo/${id}`);
+}
diff --git a/eims-ui/apps/web-antd/src/views/demo/demo/api/model.d.ts b/eims-ui/apps/web-antd/src/views/demo/demo/api/model.d.ts
new file mode 100755
index 0000000..e7f69c4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/demo/api/model.d.ts
@@ -0,0 +1,82 @@
+import type { BaseEntity, PageQuery } from '#/api/common';
+
+export interface DemoVO {
+  /**
+   * 涓婚敭
+   */
+  id: number | string;
+
+  /**
+   * 鎺掑簭鍙�
+   */
+  orderNum: number;
+
+  /**
+   * key閿�
+   */
+  testKey: string;
+
+  /**
+   * 鍊�
+   */
+  value: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version: number;
+}
+
+export interface DemoForm extends BaseEntity {
+  /**
+   * 涓婚敭
+   */
+  id?: number | string;
+
+  /**
+   * 鎺掑簭鍙�
+   */
+  orderNum?: number;
+
+  /**
+   * key閿�
+   */
+  testKey?: string;
+
+  /**
+   * 鍊�
+   */
+  value?: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version?: number;
+}
+
+export interface DemoQuery extends PageQuery {
+  /**
+   * 鎺掑簭鍙�
+   */
+  orderNum?: number;
+
+  /**
+   * key閿�
+   */
+  testKey?: string;
+
+  /**
+   * 鍊�
+   */
+  value?: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version?: number;
+
+  /**
+   * 鏃ユ湡鑼冨洿鍙傛暟
+   */
+  params?: any;
+}
diff --git a/eims-ui/apps/web-antd/src/views/demo/demo/data.ts b/eims-ui/apps/web-antd/src/views/demo/demo/data.ts
new file mode 100755
index 0000000..81c90c3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/demo/data.ts
@@ -0,0 +1,92 @@
+import type { FormSchemaGetter } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'orderNum',
+    label: '鎺掑簭鍙�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'testKey',
+    label: 'key閿�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'value',
+    label: '鍊�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'version',
+    label: '鐗堟湰',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '涓婚敭',
+    field: 'id',
+  },
+  {
+    title: '鎺掑簭鍙�',
+    field: 'orderNum',
+  },
+  {
+    title: 'key閿�',
+    field: 'testKey',
+  },
+  {
+    title: '鍊�',
+    field: 'value',
+  },
+  {
+    title: '鐗堟湰',
+    field: 'version',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    label: '涓婚敭',
+    fieldName: 'id',
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+  },
+  {
+    label: '鎺掑簭鍙�',
+    fieldName: 'orderNum',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: 'key閿�',
+    fieldName: 'testKey',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: '鍊�',
+    fieldName: 'value',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: '鐗堟湰',
+    fieldName: 'version',
+    component: 'Input',
+    rules: 'required',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/demo/demo/demo-modal.vue b/eims-ui/apps/web-antd/src/views/demo/demo/demo-modal.vue
new file mode 100755
index 0000000..8126362
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/demo/demo-modal.vue
@@ -0,0 +1,87 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+
+import { demoAdd, demoInfo, demoUpdate } from './api';
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    // 榛樿鍗犳弧涓ゅ垪
+    formItemClass: 'col-span-2',
+    // 榛樿label瀹藉害 px
+    labelWidth: 80,
+    // 閫氱敤閰嶇疆椤� 浼氬奖鍝嶅埌鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { id } = modalApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+
+    if (isUpdate.value && id) {
+      const record = await demoInfo(id);
+      await formApi.setValues(record);
+    }
+
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // getValues鑾峰彇涓轰竴涓猺eadonly鐨勫璞� 闇�瑕佷慨鏀瑰繀椤诲厛娣辨嫹璐濅竴娆�
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? demoUpdate(data) : demoAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :close-on-click-modal="false" :title="title" class="w-[550px]">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/demo/demo/index.vue b/eims-ui/apps/web-antd/src/views/demo/demo/index.vue
new file mode 100644
index 0000000..9581610
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/demo/index.vue
@@ -0,0 +1,170 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getPopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  tableCheckboxEvent,
+  useVbenVxeGrid,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import { downloadExcel } from '#/utils/file/download';
+
+import { demoExport, demoList, demoRemove } from './api';
+import { columns, querySchema } from './data';
+import demoModal from './demo-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await demoList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id',
+  },
+};
+
+const checked = ref(false);
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    checkboxChange: tableCheckboxEvent(checked),
+    checkboxAll: tableCheckboxEvent(checked),
+  },
+});
+
+const [DemoModal, modalApi] = useVbenModal({
+  connectedComponent: demoModal,
+});
+
+function handleAdd() {
+  modalApi.setData({});
+  modalApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  modalApi.setData({ id: record.id });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await demoRemove(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await demoRemove(ids);
+      await tableApi.query();
+      checked.value = false;
+    },
+  });
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable>
+      <template #toolbar-actions>
+        <span class="pl-[7px] text-[16px]">娴嬭瘯鍗曞垪琛�</span>
+      </template>
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:demo:export']"
+            @click="
+              downloadExcel(
+                demoExport,
+                '娴嬭瘯鍗曟暟鎹�',
+                tableApi.formApi.form.values,
+              )
+            "
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!checked"
+            danger
+            type="primary"
+            v-access:code="['system:demo:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:demo:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:demo:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getPopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:demo:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <DemoModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/demo/tree/api/index.ts b/eims-ui/apps/web-antd/src/views/demo/tree/api/index.ts
new file mode 100755
index 0000000..3df12a2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/tree/api/index.ts
@@ -0,0 +1,50 @@
+import type { TreeForm, TreeQuery, TreeVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鏌ヨ娴嬭瘯鏍戝垪琛�
+ * @param params
+ * @returns 娴嬭瘯鏍戝垪琛�
+ */
+export function treeList(params?: TreeQuery) {
+  return requestClient.get<TreeVO[]>('/demo/tree/list', { params });
+}
+
+/**
+ * 鏌ヨ娴嬭瘯鏍戣鎯�
+ * @param id id
+ * @returns 娴嬭瘯鏍戣鎯�
+ */
+export function treeInfo(id: ID) {
+  return requestClient.get<TreeVO>(`/demo/tree/${id}`);
+}
+
+/**
+ * 鏂板娴嬭瘯鏍�
+ * @param data
+ * @returns void
+ */
+export function treeAdd(data: TreeForm) {
+  return requestClient.postWithMsg<void>('/demo/tree', data);
+}
+
+/**
+ * 鏇存柊娴嬭瘯鏍�
+ * @param data
+ * @returns void
+ */
+export function treeUpdate(data: TreeForm) {
+  return requestClient.putWithMsg<void>('/demo/tree', data);
+}
+
+/**
+ * 鍒犻櫎娴嬭瘯鏍�
+ * @param id id
+ * @returns void
+ */
+export function treeRemove(id: ID | IDS) {
+  return requestClient.deleteWithMsg<void>(`/demo/tree/${id}`);
+}
diff --git a/eims-ui/apps/web-antd/src/views/demo/tree/api/model.d.ts b/eims-ui/apps/web-antd/src/views/demo/tree/api/model.d.ts
new file mode 100755
index 0000000..87ba83d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/tree/api/model.d.ts
@@ -0,0 +1,102 @@
+import type { BaseEntity } from '#/api/common';
+
+export interface TreeVO {
+  /**
+   * 涓婚敭
+   */
+  id: number | string;
+
+  /**
+   * 鐖秈d
+   */
+  parentId: number | string;
+
+  /**
+   * 閮ㄩ棬id
+   */
+  deptId: number | string;
+
+  /**
+   * 鐢ㄦ埛id
+   */
+  userId: number | string;
+
+  /**
+   * 鍊�
+   */
+  treeName: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version: number;
+
+  /**
+   * 瀛愬璞�
+   */
+  children: TreeVO[];
+}
+
+export interface TreeForm extends BaseEntity {
+  /**
+   * 涓婚敭
+   */
+  id?: number | string;
+
+  /**
+   * 鐖秈d
+   */
+  parentId?: number | string;
+
+  /**
+   * 閮ㄩ棬id
+   */
+  deptId?: number | string;
+
+  /**
+   * 鐢ㄦ埛id
+   */
+  userId?: number | string;
+
+  /**
+   * 鍊�
+   */
+  treeName?: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version?: number;
+}
+
+export interface TreeQuery {
+  /**
+   * 鐖秈d
+   */
+  parentId?: number | string;
+
+  /**
+   * 閮ㄩ棬id
+   */
+  deptId?: number | string;
+
+  /**
+   * 鐢ㄦ埛id
+   */
+  userId?: number | string;
+
+  /**
+   * 鍊�
+   */
+  treeName?: string;
+
+  /**
+   * 鐗堟湰
+   */
+  version?: number;
+
+  /**
+   * 鏃ユ湡鑼冨洿鍙傛暟
+   */
+  params?: any;
+}
diff --git a/eims-ui/apps/web-antd/src/views/demo/tree/data.ts b/eims-ui/apps/web-antd/src/views/demo/tree/data.ts
new file mode 100755
index 0000000..a6984f6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/tree/data.ts
@@ -0,0 +1,107 @@
+import type { FormSchemaGetter } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'parentId',
+    label: '鐖秈d',
+  },
+  {
+    component: 'Input',
+    fieldName: 'deptId',
+    label: '閮ㄩ棬id',
+  },
+  {
+    component: 'Input',
+    fieldName: 'userId',
+    label: '鐢ㄦ埛id',
+  },
+  {
+    component: 'Input',
+    fieldName: 'treeName',
+    label: '鍊�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'version',
+    label: '鐗堟湰',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  {
+    title: '涓婚敭',
+    field: 'id',
+    treeNode: true,
+  },
+  {
+    title: '鐖秈d',
+    field: 'parentId',
+  },
+  {
+    title: '閮ㄩ棬id',
+    field: 'deptId',
+  },
+  {
+    title: '鐢ㄦ埛id',
+    field: 'userId',
+  },
+  {
+    title: '鍊�',
+    field: 'treeName',
+  },
+  {
+    title: '鐗堟湰',
+    field: 'version',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    label: '涓婚敭',
+    fieldName: 'id',
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+  },
+  {
+    label: '鐖秈d',
+    fieldName: 'parentId',
+    component: 'TreeSelect',
+    rules: 'required',
+  },
+  {
+    label: '閮ㄩ棬id',
+    fieldName: 'deptId',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: '鐢ㄦ埛id',
+    fieldName: 'userId',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: '鍊�',
+    fieldName: 'treeName',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    label: '鐗堟湰',
+    fieldName: 'version',
+    component: 'Input',
+    rules: 'required',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/demo/tree/index.vue b/eims-ui/apps/web-antd/src/views/demo/tree/index.vue
new file mode 100644
index 0000000..d5829b1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/tree/index.vue
@@ -0,0 +1,144 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { nextTick } from 'vue';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getPopupContainer, listToTree } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+
+import { treeList, treeRemove } from './api';
+import { columns, querySchema } from './data';
+import treeModal from './tree-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await treeList({
+          ...formValues,
+        });
+        const treeData = listToTree(resp, {
+          id: 'id',
+          pid: 'parentId',
+          children: 'children',
+        });
+        return { rows: treeData };
+      },
+      // 榛樿璇锋眰鎺ュ彛鍚庡睍寮�鍏ㄩ儴 涓嶉渶瑕佸彲浠ュ垹闄よ繖娈�
+      querySuccess: () => {
+        nextTick(() => {
+          expandAll();
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id',
+  },
+
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    transform: false,
+  },
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ formOptions, gridOptions });
+const [TreeModal, modalApi] = useVbenModal({
+  connectedComponent: treeModal,
+});
+
+function handleAdd() {
+  modalApi.setData({ update: false });
+  modalApi.open();
+}
+
+async function handleEdit(row: Recordable<any>) {
+  modalApi.setData({ id: row.id, update: true });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await treeRemove(row.id);
+  await tableApi.query();
+}
+
+function expandAll() {
+  tableApi.grid?.setAllTreeExpand(true);
+}
+
+function collapseAll() {
+  tableApi.grid?.setAllTreeExpand(false);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable>
+      <template #toolbar-actions>
+        <span class="pl-[7px] text-[16px]">娴嬭瘯鏍戝垪琛�</span>
+      </template>
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="collapseAll">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="expandAll">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:tree:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:tree:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getPopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:tree:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <TreeModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/demo/tree/tree-modal.vue b/eims-ui/apps/web-antd/src/views/demo/tree/tree-modal.vue
new file mode 100755
index 0000000..bfe628c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demo/tree/tree-modal.vue
@@ -0,0 +1,104 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+
+import { treeAdd, treeInfo, treeList, treeUpdate } from './api';
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    // 榛樿鍗犳弧涓ゅ垪
+    formItemClass: 'col-span-2',
+    // 榛樿label瀹藉害 px
+    labelWidth: 80,
+    // 閫氱敤閰嶇疆椤� 浼氬奖鍝嶅埌鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupTreeSelect() {
+  const listData = await treeList();
+  const treeData = listToTree(listData, { id: 'id', pid: 'parentId' });
+  formApi.updateSchema([
+    {
+      fieldName: 'parentId',
+      componentProps: {
+        treeData,
+        treeLine: { showLeafIcon: false },
+        fieldNames: { label: 'treeName', value: 'id' },
+        treeDefaultExpandAll: true,
+      },
+    },
+  ]);
+}
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { id } = modalApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+
+    if (isUpdate.value && id) {
+      const record = await treeInfo(id);
+      await formApi.setValues(record);
+    }
+    await setupTreeSelect();
+
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // getValues鑾峰彇涓轰竴涓猺eadonly鐨勫璞� 闇�瑕佷慨鏀瑰繀椤诲厛娣辨嫹璐濅竴娆�
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? treeUpdate(data) : treeAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :close-on-click-modal="false" :title="title" class="w-[550px]">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/demos/antd/index.vue b/eims-ui/apps/web-antd/src/views/demos/antd/index.vue
new file mode 100644
index 0000000..b3b05cc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/demos/antd/index.vue
@@ -0,0 +1,66 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message, notification, Space } from 'ant-design-vue';
+
+type NotificationType = 'error' | 'info' | 'success' | 'warning';
+
+function info() {
+  message.info('How many roads must a man walk down');
+}
+
+function error() {
+  message.error({
+    content: 'Once upon a time you dressed so fine',
+    duration: 2500,
+  });
+}
+
+function warning() {
+  message.warning('How many roads must a man walk down');
+}
+function success() {
+  message.success('Cause you walked hand in hand With another man in my place');
+}
+
+function notify(type: NotificationType) {
+  notification[type]({
+    duration: 2500,
+    message: '璇寸偣鍟ュ憿',
+    type,
+  });
+}
+</script>
+
+<template>
+  <Page
+    description="鏀寔澶氳瑷�锛屼富棰樺姛鑳介泦鎴愬垏鎹㈢瓑"
+    title="Ant Design Vue缁勪欢浣跨敤婕旂ず"
+  >
+    <Card class="mb-5" title="鎸夐挳">
+      <Space>
+        <Button>Default</Button>
+        <Button type="primary"> Primary </Button>
+        <Button> Info </Button>
+        <Button danger> Error </Button>
+      </Space>
+    </Card>
+    <Card class="mb-5" title="Message">
+      <Space>
+        <Button @click="info"> 淇℃伅 </Button>
+        <Button danger @click="error"> 閿欒 </Button>
+        <Button @click="warning"> 璀﹀憡 </Button>
+        <Button @click="success"> 鎴愬姛 </Button>
+      </Space>
+    </Card>
+
+    <Card class="mb-5" title="Notification">
+      <Space>
+        <Button @click="notify('info')"> 淇℃伅 </Button>
+        <Button danger @click="notify('error')"> 閿欒 </Button>
+        <Button @click="notify('warning')"> 璀﹀憡 </Button>
+        <Button @click="notify('success')"> 鎴愬姛 </Button>
+      </Space>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ-detail/index.vue b/eims-ui/apps/web-antd/src/views/eims/equ-detail/index.vue
new file mode 100644
index 0000000..5f4bda5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ-detail/index.vue
@@ -0,0 +1,141 @@
+<script setup lang="ts">
+import type { EquVO } from '#/api/eims/equ/model';
+
+import { onMounted, ref } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { Page, useVbenDrawer } from '@vben/common-ui';
+
+import { HomeTwoTone, RightOutlined } from '@ant-design/icons-vue';
+import { Badge, Card, Descriptions, DescriptionsItem, Divider, Image, ImagePreviewGroup, TabPane, Tabs, Tag } from 'ant-design-vue';
+
+import { getEqu } from '#/api/eims/equ';
+import equDrawer from '#/views/eims/equ/equ-drawer.vue';
+
+const route = useRoute();
+const equId = route.params.equId as string;
+
+const equVo = ref<EquVO>();
+
+onMounted(async () => {
+  await loadData();
+});
+
+async function loadData() {
+  equVo.value = await getEqu(equId);
+}
+
+const [EquDrawer, equDrawerApi] = useVbenDrawer({
+  connectedComponent: equDrawer
+});
+
+async function handleEdit() {
+  equDrawerApi.setData({ id: equId, typeDisable: true });
+  equDrawerApi.open();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true" :padding="false" class="p-0" content-class="flex w-full gap-[8px]">
+    <div class="w-full h-fit p-4">
+      <Card class="w-full rounded-b-none overflow-hidden">
+        <div class="flex gap-[8px]">
+          <div class="w-1/4 min-w-56">
+            <div class="flex w-full h-8 justify-between items-center">
+              <span class="font-bold text-lg">{{ equVo?.equName }} </span>
+              <span class="text-gray-400">2025骞村害 <RightOutlined /> </span>
+            </div>
+            <Tag v-if="!equVo?.status" class="mt-2">鍏跺畠</Tag>
+            <Tag v-else-if="equVo?.status === '0'" class="mt-2" color="cyan">璇曠敤</Tag>
+            <Tag v-else-if="equVo?.status === '1'" class="mt-2" color="green">鍏ュ浐</Tag>
+            <Tag v-else-if="equVo?.status === '2'" class="mt-2" color="orange">杩佺Щ</Tag>
+            <Tag v-else-if="equVo?.status === '3'" class="mt-2" color="red">鎶ュ簾</Tag>
+            <Divider class="my-4" type="horizontal" />
+            <HomeTwoTone />
+            <span class="ml-2 text-gray-500">{{ equVo?.location }}</span>
+          </div>
+
+          <div class="w-3/4 min-w-[640px] flex align-center justify-around">
+            <Divider class="h-full" type="vertical" />
+            <div class="flex w-1/4 h-full cursor-pointer items-center justify-center rounded-sm hover:bg-gray-100"
+                 style="background: #f2f6fe">
+              <Image :preview="false" :width="40" src="/src/assets/logo.png" />
+              <div class="flex flex-col ml-6 mr-2">
+                <span class="text-xl font-bold">100%</span>
+                <span class="mt-5 text-gray-500">璁惧鍋ュ悍搴�</span>
+              </div>
+            </div>
+            <div class="flex w-1/4 h-full cursor-pointer items-center justify-center rounded-sm hover:bg-gray-100"
+                 style="background: #fcf8ee">
+              <Image :preview="false" :width="40" src="/src/assets/logo.png" />
+              <div class="flex flex-col ml-6 mr-2">
+                <span class="text-xl font-bold">86.6h</span>
+                <span class="mt-5 text-gray-500">骞冲潎鏁呴殰鏃堕棿</span>
+              </div>
+            </div>
+            <div class="flex w-1/4 h-full cursor-pointer items-center justify-center rounded-sm hover:bg-gray-100"
+                 style="background: #ecf5de">
+              <Image :preview="false" :width="40" src="/src/assets/logo.png" />
+              <div class="flex flex-col ml-6 mr-2">
+                <span class="text-xl font-bold">0鍏�</span>
+                <span class="mt-5 text-gray-500">缁翠繚鎬昏垂鐢�</span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </Card>
+      <Card class="w-full rounded-t-none mt-2">
+        <Tabs>
+          <TabPane key="1" tab="鍩烘湰淇℃伅">
+            <Descriptions bordered title="鍩烘湰淇℃伅">
+              <template #extra>
+                <a-button type="primary" @click="handleEdit">缂栬緫</a-button>
+              </template>
+              <DescriptionsItem label="浣跨敤鐘跺喌">
+                <Badge status="processing" text="鍦ㄧ敤" />
+              </DescriptionsItem>
+              <DescriptionsItem label="璁惧鍚嶇О">{{ equVo?.equName }}</DescriptionsItem>
+              <DescriptionsItem label="璁惧缂栫爜">{{ equVo?.equCode }}</DescriptionsItem>
+              <DescriptionsItem label="璁惧绫诲瀷">{{ equVo?.equTypeName }}</DescriptionsItem>
+              <DescriptionsItem label="璧勪骇缂栧彿">{{ equVo?.assetNo }}</DescriptionsItem>
+              <DescriptionsItem label="棰濆畾鍔熺巼">{{ equVo?.ratedPower }}</DescriptionsItem>
+              <DescriptionsItem label="閾墝淇℃伅">{{ equVo?.plateInfo }}</DescriptionsItem>
+              <DescriptionsItem label="鎵�鍦ㄤ綅缃�">{{ equVo?.location }}</DescriptionsItem>
+              <DescriptionsItem label="鍒堕�犲晢">{{ equVo?.madeIn }}</DescriptionsItem>
+              <DescriptionsItem label="浣跨敤骞撮檺">{{ equVo?.serviceLife }}</DescriptionsItem>
+              <DescriptionsItem label="浣跨敤閮ㄩ棬">{{ equVo?.deptName }}</DescriptionsItem>
+              <DescriptionsItem label="璐d换浜�">{{ equVo?.respPersonName }}</DescriptionsItem>
+              <DescriptionsItem label="鑱旂郴鐢佃瘽">{{ equVo?.contactPhone }}</DescriptionsItem>
+              <DescriptionsItem label="閲囪喘鏃ユ湡">{{ equVo?.purchaseDate }}</DescriptionsItem>
+              <DescriptionsItem label="璇曠敤鏃ユ湡">{{ equVo?.trialDate }}</DescriptionsItem>
+              <DescriptionsItem label="浣跨敤鏃ユ湡">{{ equVo?.deployDate }}</DescriptionsItem>
+              <DescriptionsItem label="璁¢獙鏃ユ湡">{{ equVo?.planAcceptDate }}</DescriptionsItem>
+              <DescriptionsItem label="瀹為獙鏃ユ湡">{{ equVo?.actualAcceptDate }}</DescriptionsItem>
+            </Descriptions>
+            <Descriptions class="mt-3" size="small" title="璁惧鍥剧墖">
+              <DescriptionsItem>
+                <ImagePreviewGroup>
+                  <Image :width="200"
+                         src="https://shlanpu.cn/uploads/images/202404/ebb24dc0610cf8e83a19fb0f568bf530.png" />
+                  <Image :width="200"
+                         src="https://shlanpu.cn/uploads/images/202404/c2212b8fc38bdd20e9d1cf79da40698d.jpg" />
+                </ImagePreviewGroup>
+              </DescriptionsItem>
+            </Descriptions>
+          </TabPane>
+          <TabPane key="2" tab="缁翠慨">Content of Tab Pane 2</TabPane>
+          <TabPane key="3" tab="淇濆吇">Content of Tab Pane 3</TabPane>
+          <TabPane key="4" tab="鐐规">Content of Tab Pane 3</TabPane>
+          <TabPane key="5" tab="澶囦欢">Content of Tab Pane 3</TabPane>
+          <TabPane key="5" tab="闄勪欢">Content of Tab Pane 3</TabPane>
+          <TabPane key="6" tab="璁惧灞ュ巻">Content of Tab Pane 3</TabPane>
+          <TabPane key="7" tab="璇曚骇璁板綍">Content of Tab Pane 3</TabPane>
+          <TabPane key="8" tab="鐘舵�佽褰�">Content of Tab Pane 3</TabPane>
+        </Tabs>
+      </Card>
+    </div>
+    <EquDrawer @reload="loadData" />
+  </Page>
+</template>
+
+<style scoped></style>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ-type/data.tsx b/eims-ui/apps/web-antd/src/views/eims/equ-type/data.tsx
new file mode 100644
index 0000000..4e21931
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ-type/data.tsx
@@ -0,0 +1,196 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { h } from 'vue';
+
+import { DictEnum } from '@vben/constants';
+import { FolderIcon, MenuIcon, VbenIcon } from '@vben/icons';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'typeName',
+    label: '绫诲瀷鍚嶇О '
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE)
+    },
+    fieldName: 'status',
+    label: '绫诲瀷鐘舵�� '
+  }
+];
+
+// 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+export const equTypeOptions = [
+  { label: '璁惧鐩綍', value: 'M' },
+  { label: '璁惧绫诲瀷', value: 'C' }
+];
+
+export const yesNoOptions = [
+  { label: '鏄�', value: '0' },
+  { label: '鍚�', value: '1' }
+];
+
+// 锛圡鐩綍 C鑿滃崟锛�
+const menuTypes = {
+  M: { icon: FolderIcon, value: '璁惧鐩綍' },
+  C: { icon: MenuIcon, value: '璁惧绫诲瀷' }
+};
+export const columns: VxeGridProps['columns'] = [
+  {
+    title: '绫诲瀷鍚嶇О',
+    field: 'typeName',
+    treeNode: true,
+    width: 200
+  },
+  {
+    title: '绫诲瀷缂栫爜',
+    field: 'typeCode',
+    width: 200
+  },
+  {
+    title: '鍥炬爣',
+    field: 'icon',
+    width: 80,
+    slots: {
+      default: ({ row }) => {
+        if (row?.icon === '#') {
+          return '';
+        }
+        return (
+          <span class={'flex justify-center'}>
+            <VbenIcon icon={row.icon} />
+          </span>
+        );
+      }
+    }
+  },
+  {
+    title: '鎺掑簭',
+    field: 'orderNum',
+    width: 120
+  },
+  {
+    title: '鑺傜偣绫诲瀷',
+    field: 'menuType',
+    width: 150,
+    slots: {
+      default: ({ row }) => {
+        const current = menuTypes[row.menuType as 'C' | 'M'];
+        if (!current) {
+          return '鏈煡';
+        }
+        return (
+          <span class="flex items-center justify-center gap-1">
+            {h(current.icon, { class: 'size-[18px]' })}
+            <span>{current.value}</span>
+          </span>
+        );
+      }
+    }
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    width: 100,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NORMAL_DISABLE);
+      }
+    }
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime'
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'equTypeId'
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: 0,
+    fieldName: 'parentId',
+    label: '涓婄骇鑿滃崟',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: equTypeOptions,
+      optionType: 'button'
+    },
+    defaultValue: 'M',
+    dependencies: {
+      componentProps: (_, api) => {
+        // 鍒囨崲鏃舵竻绌烘牎楠�
+        // 鐩存帴鎶勭殑婧愮爜 娌℃湁娓呯┖鏍¢獙鐨勬柟娉�
+        Object.keys(api.errors.value).forEach((key) => {
+          api.setFieldError(key, undefined);
+        });
+        return {};
+      },
+      triggerFields: ['menuType']
+    },
+    fieldName: 'menuType',
+    label: '鑺傜偣绫诲瀷'
+  },
+  {
+    component: 'Input',
+    fieldName: 'typeName',
+    label: '绫诲瀷鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'typeCode',
+    label: '绫诲瀷缂栫爜',
+    rules: 'required'
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'orderNum',
+    help: '鎺掑簭, 鏁板瓧瓒婂皬瓒婇潬鍓�',
+    label: '鏄剧ず鎺掑簭',
+    rules: 'required'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType']
+    },
+    fieldName: 'status',
+    help: '鍋滅敤鍚庝笉浼氬嚭鐜板湪鍒楄〃',
+    label: '绫诲瀷鐘舵��'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ-type/equ-type-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/equ-type/equ-type-drawer.vue
new file mode 100644
index 0000000..ca35412
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ-type/equ-type-drawer.vue
@@ -0,0 +1,137 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import {
+  addFullName,
+  cloneDeep,
+  getPopupContainer,
+  listToTree,
+} from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addEquType, getEquType, listEquType, updateEquType } from '#/api/eims/equ-type';
+
+import { drawerSchema } from './data';
+
+interface ModalProps {
+  id?: number | string;
+  update: boolean;
+}
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+    formItemClass: 'col-span-2',
+    labelWidth: 90,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupEquTypeSelect() {
+  // menu
+  const menuArray = await listEquType({status:'0'});
+  // support i18n
+  menuArray.forEach((item) => {
+    item.typeName = $t(item.typeName);
+  });
+  // const folderArray = menuArray.filter((item) => item.menuType === 'M');
+  const menuTree = listToTree(menuArray, { id: 'equTypeId', pid: 'parentId' });
+  const fullMenuTree = [
+    {
+      equTypeId: 0,
+      typeName: $t('menu.root'),
+      children: menuTree,
+    },
+  ];
+  addFullName(fullMenuTree, 'typeName', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'typeName',
+          value: 'equTypeId',
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullMenuTree,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'typeName',
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'parentId',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id, update } = drawerApi.getData() as ModalProps;
+    isUpdate.value = update;
+
+    // 鍔犺浇璁惧绫诲瀷鏍戦�夋嫨
+    await setupEquTypeSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (update) {
+        const record = await getEquType(id);
+        await formApi.setValues(record);
+      }
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateEquType(data) : addEquType(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue b/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue
new file mode 100644
index 0000000..cafb9e6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue
@@ -0,0 +1,169 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { eachTree, getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { delEquType, equTypeExport, listEquType } from '#/api/eims/equ-type';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import equTypeDrawer from './equ-type-drawer.vue';
+
+/**
+ * 涓嶈闂负浠�涔堟湁涓や釜鏍硅妭鐐� v-if浼氭帶鍒跺彧浼氭覆鏌撲竴涓�
+ */
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await listEquType({
+          ...formValues
+        });
+        return { rows: resp };
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'equTypeId'
+  },
+  /**
+   * 寮�鍚櫄鎷熸粴鍔�
+   * 鏁版嵁閲忓皬鍙互閫夋嫨鍏抽棴
+   * 濡傛灉閬囧埌鏍峰紡闂(绌虹櫧銆侀敊浣� 婊氬姩绛�)鍙互閫夋嫨鍏抽棴铏氭嫙婊氬姩
+   */
+  scrollY: {
+    enabled: true,
+    gt: 0
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'equTypeId',
+    // 鑷姩杞崲涓簍ree 鐢眝xe澶勭悊 鏃犻渶鎵嬪姩杞崲
+    transform: true
+  },
+  id: 'equ-type-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    cellDblclick: (e: any) => {
+      const { row = {} } = e;
+      if (!row?.children) {
+        return;
+      }
+      const isExpanded = row?.expand;
+      tableApi.grid.setTreeExpand(row, !isExpanded);
+      row.expand = !isExpanded;
+    },
+    // 闇�瑕佺洃鍚娇鐢ㄧ澶村睍寮�鐨勬儏鍐� 鍚﹀垯灞曞紑/鎶樺彔鐨勬暟鎹笉涓�鑷�
+    toggleTreeExpand: (e: any) => {
+      const { row = {}, expanded } = e;
+      row.expand = expanded;
+    }
+  }
+});
+const [EquTypeDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: equTypeDrawer
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+function handleSubAdd(row: Recordable<any>) {
+  const { equTypeId } = row;
+  drawerApi.setData({ id: equTypeId, update: false });
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.equTypeId, update: true });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delEquType(row.equTypeId);
+  await tableApi.query();
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(equTypeExport, '璁惧绫诲瀷', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+/**
+ * 鍏ㄩ儴灞曞紑/鎶樺彔
+ * @param expand 鏄惁灞曞紑
+ */
+function setExpandOrCollapse(expand: boolean) {
+  eachTree(tableApi.grid.getData(), (item) => (item.expand = expand));
+  tableApi.grid?.setAllTreeExpand(expand);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="鑿滃崟鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="setExpandOrCollapse(false)">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="setExpandOrCollapse(true)">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button v-access:code="['eims:equType:export']" @click="handleDownloadExcel">
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button type="primary" v-access:code="['eims:equType:add']" @click="handleAdd">
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button v-access:code="['eims:equType:edit']" @click="handleEdit(row)">
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <!-- '鎸夐挳绫诲瀷'鏃犳硶鍐嶆坊鍔犲瓙鑿滃崟 -->
+          <ghost-button v-if="row.menuType !== 'F'" class="btn-success" v-access:code="['eims:equType:add']" @click="handleSubAdd(row)">
+            {{ $t('pages.common.add') }}
+          </ghost-button>
+          <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+            <ghost-button danger v-access:code="['eims:equType:remove']" @click.stop="">
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <EquTypeDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/data.tsx b/eims-ui/apps/web-antd/src/views/eims/equ/data.tsx
new file mode 100644
index 0000000..1dcafcf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/data.tsx
@@ -0,0 +1,389 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { Tag } from 'ant-design-vue';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'equName',
+    label: '璁惧鍚嶇О'
+  },
+  {
+    component: 'Input',
+    fieldName: 'assetNo',
+    label: '璧勪骇缂栧彿'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_EQU_STATUS)
+    },
+    fieldName: 'status',
+    label: '鐘舵��'
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '浣跨敤鏃ユ湡'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '璁惧鍚嶇О',
+    field: 'equName',
+    minWidth: 100,
+    fixed: 'left',
+    slots: { default: 'equName' }
+  },
+
+  {
+    title: '鐘舵��',
+    field: 'status',
+    slots: {
+      default: ({ row }) => {
+        const statu = row.status;
+        switch (statu) {
+          case '0': {
+            return <Tag color="cyan">璇曠敤</Tag>;
+          }
+          case '1': {
+            return <Tag color="green">鍏ュ浐</Tag>;
+          }
+          case '2': {
+            return <Tag color="orange">杩佺Щ</Tag>;
+          }
+          case '3': {
+            return <Tag color="red">鎶ュ簾</Tag>;
+          }
+          case null: {
+            return '';
+          }
+          // No default
+        }
+        return '';
+      }
+    },
+    minWidth: 80,
+    fixed: 'left'
+  },
+  {
+    title: '璧勪骇缂栧彿',
+    field: 'assetNo',
+    minWidth: 100,
+    fixed: 'left'
+  },
+  {
+    title: '璁惧缂栧彿',
+    field: 'equCode',
+    minWidth: 100
+  },
+  {
+    title: '璁惧绫诲瀷',
+    field: 'equTypeName',
+    minWidth: 100
+  },
+  {
+    title: '鍨嬪彿',
+    field: 'modelNo',
+    minWidth: 100
+  },
+  {
+    title: '鍒堕�犲晢',
+    field: 'madeIn',
+    minWidth: 100
+  },
+  {
+    title: '棰濆畾鍔熺巼',
+    field: 'ratedPower',
+    minWidth: 100
+  },
+  {
+    title: '閾墝淇℃伅',
+    field: 'plateInfo',
+    minWidth: 100
+  },
+  {
+    title: '鎵�鍦ㄥ満鎵�',
+    field: 'location',
+    minWidth: 100
+  },
+  {
+    title: '鎵�鍦ㄩ儴闂�',
+    field: 'deptName',
+    minWidth: 100
+  },
+  {
+    title: '璐d换浜�',
+    field: 'respPersonName',
+    minWidth: 100
+  },
+  {
+    title: '鑱旂郴鐢佃瘽',
+    field: 'contactPhone',
+    minWidth: 120
+  },
+  {
+    title: '閲囪喘鏃ユ湡',
+    field: 'purchaseDate',
+    minWidth: 120
+  },
+  {
+    title: '寮�濮嬭瘯鐢ㄦ棩鏈�',
+    field: 'trialDate',
+    minWidth: 120
+  },
+  {
+    title: '姝e紡浣跨敤鏃ユ湡',
+    field: 'deployDate',
+    minWidth: 120
+  },
+  {
+    title: '璁″垝楠屾敹鏃ユ湡',
+    field: 'planAcceptDate',
+    minWidth: 120
+  },
+  {
+    title: '瀹為檯楠屾敹鏃ユ湡',
+    field: 'actualAcceptDate',
+    minWidth: 120
+  },
+  {
+    title: '瀵煎叆鐘舵��',
+    field: 'importStatus',
+    minWidth: 100
+  },
+  {
+    title: '鐩樼偣鏍囧織',
+    field: 'inventoryFlag',
+    minWidth: 100
+  },
+  {
+    title: '涓婃鐩樼偣鏃ユ湡',
+    field: 'inventoryDate',
+    minWidth: 120
+  },
+  {
+    title: '浣跨敤骞撮檺',
+    field: 'serviceLife',
+    minWidth: 100
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+    minWidth: 100
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'equId'
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: 0,
+    fieldName: 'equTypeId',
+    label: '璁惧绫诲瀷',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Input',
+    fieldName: 'equName',
+    label: '璁惧鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'equCode',
+    label: '璁惧缂栫爜',
+    help: '璁惧鍞竴缂栫爜'
+  },
+  {
+    component: 'Input',
+    fieldName: 'assetNo',
+    label: '璧勪骇缂栧彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'modelNo',
+    label: '鍨嬪彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'madeIn',
+    label: '鍒堕�犲晢'
+  },
+  {
+    component: 'Input',
+    fieldName: 'ratedPower',
+    label: '棰濆畾鍔熺巼'
+  },
+  {
+    component: 'Input',
+    fieldName: 'plateInfo',
+    label: '閾墝淇℃伅'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'purchaseDate',
+    label: '閲囪喘鏃ユ湡'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_EQU_STATUS),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '鐘舵��'
+  },
+  {
+    component: 'Input',
+    fieldName: 'location',
+    label: '鎵�鍦ㄥ満鎵�',
+    help: `璁惧瀹為檯鎽嗘斁鍦烘墍`
+  },
+
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'deptUsed',
+    label: '浣跨敤閮ㄩ棬'
+    // rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      // 閫変腑浜嗗氨鍙兘淇敼 涓嶈兘閲嶇疆涓烘棤璐熻矗浜�
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'respPerson',
+    label: '璐d换浜�',
+    help: `璁惧璐熻矗浜猴紝绠$悊浜哄憳`
+  },
+  {
+    component: 'Input',
+    fieldName: 'contactPhone',
+    label: '鑱旂郴鐢佃瘽',
+    defaultValue: undefined,
+    rules: z
+      .string()
+      .regex(/^1[3-9]\d{9}$/, '璇疯緭鍏ユ纭殑鎵嬫満鍙风爜')
+      .optional()
+      .or(z.literal(''))
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'deployDate',
+    label: '姝e紡浣跨敤鏃ユ湡'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'trialDate',
+    label: '寮�濮嬭瘯鐢ㄦ棩鏈�'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'planAcceptDate',
+    label: '璁″垝楠屾敹鏃ユ湡'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'actualAcceptDate',
+    label: '瀹為檯楠屾敹鏃ユ湡'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    fieldName: 'importStatus',
+    formItemClass: 'col-span-2 lg:col-span-1',
+    label: '瀵煎叆鐘舵��'
+  },
+
+  {
+    component: 'Input',
+    fieldName: 'serviceLife',
+    label: '浣跨敤骞撮檺'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    fieldName: 'inventoryFlag',
+    formItemClass: 'col-span-2 lg:col-span-1',
+    label: '鐩樼偣鏍囧織'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'inventoryDate',
+    label: '涓婃鐩樼偣鏃ユ湡'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/equ-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/equ/equ-drawer.vue
new file mode 100644
index 0000000..560c9bc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/equ-drawer.vue
@@ -0,0 +1,206 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addEqu, getEqu, updateEqu } from '#/api/eims/equ';
+import { getEquType, listEquType } from '#/api/eims/equ-type';
+import { getDeptTree, userList } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+const typeDisabled = ref(false);
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    const { typeDisable } = drawerApi.getData() as { typeDisable?: boolean };
+    typeDisabled.value = !!typeDisable;
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getEqu(id);
+      await formApi.setValues(record);
+      if(isUpdate.value && record.deptUsed){
+        await setupUserOptions(record.deptUsed)
+      }
+
+    }
+
+    // 鍔犺浇璁惧绫诲瀷鏍戦�夋嫨
+    await setupEquTypeSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (isUpdate.value && id) {
+        const record = await getEquType(id);
+        await formApi.setValues(record);
+      }
+    }
+    drawerApi.drawerLoading(false);
+  }
+});
+
+
+async function setupEquTypeSelect() {
+  // status-0 鍙煡璇㈡湭鍋滅敤璁惧
+  const equArray = await listEquType({ status: 0 });
+  // support i18n
+  equArray.forEach((item) => {
+    item.typeName = $t(item.typeName);
+  });
+  const equTree = listToTree(equArray, { id: 'equTypeId', pid: 'parentId' });
+  const fullEquTree = [
+    {
+      equTypeId: 0,
+      typeName: $t('menu.root'),
+      children: equTree,
+    },
+  ];
+  addFullName(fullEquTree, 'typeName', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'typeName',
+          value: 'equTypeId',
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullEquTree,
+        disabled: typeDisabled.value,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'typeName',
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'equTypeId',
+    },
+  ]);
+}
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  formApi.updateSchema([
+    {
+      componentProps: { options, placeholder },
+      fieldName: 'respPerson'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.respPerson = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'deptUsed'
+    }
+  ]);
+}
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateEqu(data) : addEqu(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue b/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue
new file mode 100644
index 0000000..0dd28c0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue
@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import type { DeptTree } from '#/api/system/user/model';
+
+import { onMounted, type PropType, ref } from 'vue';
+
+import { SyncOutlined } from '@ant-design/icons-vue';
+import { Empty, InputSearch, Skeleton, Tree } from 'ant-design-vue';
+
+import { getEquTypeTree } from '#/api/eims/equ-type';
+
+defineOptions({ inheritAttrs: false });
+
+const emit = defineEmits<{
+  /**
+   * 鐐瑰嚮鍒锋柊鎸夐挳鐨勪簨浠�
+   */
+  reload: [];
+  /**
+   * 鐐瑰嚮鑺傜偣鐨勪簨浠�
+   */
+  select: [];
+}>();
+
+const selectDeptId = defineModel('selectDeptId', {
+  required: true,
+  type: Array as PropType<string[]>,
+});
+
+const searchValue = defineModel('searchValue', {
+  type: String,
+  default: '',
+});
+
+/** 閮ㄩ棬鏁版嵁婧� */
+type DeptTreeArray = DeptTree[];
+const deptTreeArray = ref<DeptTreeArray>([]);
+/** 楠ㄦ灦灞忓姞杞� */
+const showTreeSkeleton = ref<boolean>(true);
+
+async function loadTree() {
+  showTreeSkeleton.value = true;
+  searchValue.value = '';
+  selectDeptId.value = [];
+
+  const ret = await getEquTypeTree();
+
+  deptTreeArray.value = ret;
+  showTreeSkeleton.value = false;
+}
+
+async function handleReload() {
+  await loadTree();
+  emit('reload');
+}
+
+onMounted(loadTree);
+</script>
+
+<template>
+  <div :class="$attrs.class">
+    <Skeleton
+      :loading="showTreeSkeleton"
+      :paragraph="{ rows: 8 }"
+      active
+      class="p-[8px]"
+    >
+      <div
+        class="bg-background flex h-full flex-col overflow-y-auto rounded-lg"
+      >
+        <!-- 鍥哄畾鍦ㄩ《閮� 蹇呴』鍔犱笂bg-background鑳屾櫙鑹� 鍚﹀垯浼氫骇鐢�'绌块��'鏁堟灉 -->
+        <div class="bg-background z-100 sticky left-0 top-0 p-[8px]">
+          <InputSearch
+            v-model:value="searchValue"
+            :placeholder="$t('pages.common.search')"
+            size="small"
+          >
+            <template #enterButton>
+              <a-button @click="handleReload">
+                <SyncOutlined class="text-primary" />
+              </a-button>
+            </template>
+          </InputSearch>
+        </div>
+        <div class="h-full overflow-x-hidden px-[8px]">
+          <Tree
+            v-bind="$attrs"
+            v-if="deptTreeArray.length > 0"
+            v-model:selected-keys="selectDeptId"
+            :class="$attrs.class"
+            :field-names="{ title: 'label', key: 'id' }"
+            :show-line="{ showLeafIcon: false }"
+            :tree-data="deptTreeArray"
+            :virtual="false"
+            default-expand-all
+            @select="$emit('select')"
+          >
+            <template #title="{ label }">
+              <span v-if="label.indexOf(searchValue) > -1">
+                {{ label.substring(0, label.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{
+                  label.substring(
+                    label.indexOf(searchValue) + searchValue.length,
+                  )
+                }}
+              </span>
+              <span v-else>{{ label }}</span>
+            </template>
+          </Tree>
+          <!-- 浠呮湰浜烘暟鎹潈闄� 鍙互鑰冭檻鐩存帴涓嶆樉绀� -->
+          <div v-else class="mt-5">
+            <Empty
+              :image="Empty.PRESENTED_IMAGE_SIMPLE"
+              description="鏃犻儴闂ㄦ暟鎹�"
+            />
+          </div>
+        </div>
+      </div>
+    </Skeleton>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/index.vue b/eims-ui/apps/web-antd/src/views/eims/equ/index.vue
new file mode 100644
index 0000000..5a5a5ea
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/index.vue
@@ -0,0 +1,198 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Dropdown, Menu, MenuItem, Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps } from '#/adapter/vxe-table';
+import { delEqu, equExport, listEqu } from '#/api/eims/equ';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import equDrawer from './equ-drawer.vue';
+import EquTypeTree from './equ-type-tree.vue';
+
+// 宸﹁竟閮ㄩ棬鐢�
+const selectDeptId = ref<string[]>([]);
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  handleReset: async () => {
+    selectDeptId.value = [];
+    // eslint-disable-next-line no-use-before-define
+    const { formApi, reload } = tableApi;
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    await reload(formValues);
+  },
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [['deployDate', ['params[beginTime]', 'params[endTime]'], ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']]]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectDeptId.value.length === 1) {
+          formValues.equTypeId = selectDeptId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'equTypeId');
+        }
+        return await listEqu({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'equId'
+  },
+  id: 'eims-equ-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions
+});
+
+const [EquDrawer, equDrawerApi] = useVbenDrawer({
+  connectedComponent: equDrawer
+});
+
+
+
+function handleAdd() {
+  equDrawerApi.setData({});
+  equDrawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  equDrawerApi.setData({ id: record.equId });
+  equDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delEqu(row.equId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.equId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delEqu(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(equExport, '璁惧鍙拌处', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+
+
+const router = useRouter();
+function handleDetail(record: Recordable<any>) {
+  router.push(`/equ/detail/${record.equId}`);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <EquTypeTree
+        v-model:select-dept-id="selectDeptId"
+        class="w-[260px]"
+        @reload="() => tableApi.reload()"
+        @select="() => tableApi.reload()"
+      />
+      <BasicTable class="flex-1 overflow-hidden" table-title="璁惧鍒楄〃">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:equ:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:equ:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:equ:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #equName="{ row }">
+          <Space>
+            <a-button type="link" @click="handleDetail(row)"> {{ row.equName }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['system:role:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['system:role:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+          <Dropdown :get-popup-container="getVxePopupContainer" placement="bottomRight">
+            <template #overlay>
+              <Menu>
+                <MenuItem key="1" @click="handleDetail(row)"> 璇︽儏 </MenuItem>
+              </Menu>
+            </template>
+            <a-button size="small" type="link">
+              {{ $t('pages.common.more') }}
+            </a-button>
+          </Dropdown>
+        </template>
+      </BasicTable>
+    </div>
+    <EquDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/index.vue b/eims-ui/apps/web-antd/src/views/index.vue
new file mode 100644
index 0000000..71c466a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/index.vue
@@ -0,0 +1,662 @@
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+
+import { EchartsUI, type EchartsUIType, useEcharts } from '@vben/plugins/echarts';
+
+import { AlertTwoTone, NotificationTwoTone, TagTwoTone } from '@ant-design/icons-vue';
+import { Avatar, Card, Col, Image, Row } from 'ant-design-vue';
+
+const instChart = ref<EchartsUIType>();
+const { renderEcharts: renderInstChart } = useEcharts(instChart);
+const useStatuChart = ref<EchartsUIType>();
+const { renderEcharts: renderUseChart } = useEcharts(useStatuChart);
+const repairChart = ref<EchartsUIType>();
+const { renderEcharts: renderRepairChart } = useEcharts(repairChart);
+const faultChart = ref<EchartsUIType>();
+const { renderEcharts: renderFaultChart } = useEcharts(faultChart);
+const maintenChart = ref<EchartsUIType>();
+const { renderEcharts: renderMaintenChart } = useEcharts(maintenChart);
+
+const todoItems = ref<any>([
+  {
+    completed: false,
+    content: `瀹℃煡鏈�杩戞彁浜ゅ埌Git浠撳簱鐨勫墠绔唬鐮侊紝纭繚浠g爜璐ㄩ噺鍜岃鑼冦�俙,
+    date: '2024-07-30 11:00:00',
+    title: '瀹℃煡鍓嶇浠g爜鎻愪氦'
+  },
+  {
+    completed: true,
+    content: `妫�鏌ュ苟浼樺寲绯荤粺鎬ц兘锛岄檷浣嶤PU浣跨敤鐜囥�俙,
+    date: '2024-07-30 11:00:00',
+    title: '绯荤粺鎬ц兘浼樺寲'
+  },
+  {
+    completed: false,
+    content: `杩涜绯荤粺瀹夊叏妫�鏌ワ紝纭繚娌℃湁瀹夊叏婕忔礊鎴栨湭鎺堟潈鐨勮闂�� `,
+    date: '2024-07-30 11:00:00',
+    title: '瀹夊叏妫�鏌�'
+  },
+
+  {
+    completed: false,
+    content: `淇鐢ㄦ埛鎶ュ憡鐨勯〉闈I鏄剧ず闂锛岀‘淇濆湪涓嶅悓娴忚鍣ㄤ腑鏄剧ず涓�鑷淬�� `,
+    date: '2024-07-30 11:00:00',
+    title: '淇UI鏄剧ず闂'
+  }
+]);
+
+onMounted(() => {
+  renderInstChart({
+    series: [
+      {
+        type: 'gauge',
+        startAngle: 180,
+        endAngle: 0,
+        center: ['50%', '75%'],
+        radius: '90%',
+        min: 0,
+        max: 1,
+        splitNumber: 8,
+        axisLine: {
+          lineStyle: {
+            width: 6,
+            color: [
+              [0.25, '#FF6E76'],
+              [0.5, '#FDDD60'],
+              [0.75, '#58D9F9'],
+              [1, '#7CFFB2']
+            ]
+          }
+        },
+        pointer: {
+          icon: 'path://M12.8,0.7l12,40.1H0.7L12.8,0.7z',
+          length: '12%',
+          width: 20,
+          offsetCenter: [0, '-60%'],
+          itemStyle: {
+            color: 'auto'
+          }
+        },
+        axisTick: {
+          length: 12,
+          lineStyle: {
+            color: 'auto',
+            width: 2
+          }
+        },
+        splitLine: {
+          length: 20,
+          lineStyle: {
+            color: 'auto',
+            width: 5
+          }
+        },
+        axisLabel: {
+          color: '#464646',
+          fontSize: 20,
+          distance: -60,
+          rotate: 'tangential',
+          formatter(value: number) {
+            switch (value) {
+              case 0.125: {
+                return 'Grade D';
+              }
+              case 0.375: {
+                return 'Grade C';
+              }
+              case 0.625: {
+                return 'Grade B';
+              }
+              case 0.875: {
+                return 'Grade A';
+              }
+              // No default
+            }
+            return '';
+          }
+        },
+        title: {
+          offsetCenter: [0, '-10%'],
+          fontSize: 20
+        },
+        detail: {
+          fontSize: 30,
+          offsetCenter: [0, '-35%'],
+          valueAnimation: true,
+          formatter(value: number) {
+            return `${Math.round(value * 100)}%`;
+          },
+          color: 'inherit'
+        },
+        data: [
+          {
+            value: 0.95,
+            name: '姝e父璁惧鍗犳瘮'
+          }
+        ]
+      }
+    ],
+    tooltip: {
+      trigger: 'item'
+    }
+  });
+  renderUseChart({
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow'
+      }
+    },
+    legend: {
+      show: false
+    },
+    grid: {
+      show: false
+    },
+    xAxis: {
+      type: 'value',
+      boundaryGap: [0, 0.01],
+      splitLine: { show: false }, // 闅愯棌缃戞牸绾�
+      axisTick: { show: false } // 闅愯棌鍒诲害绾�
+    },
+    yAxis: {
+      type: 'category',
+      data: ['寰呮', '鍦ㄧ敤', '鍋滅敤', '鍏朵粬', '鎶ュ簾']
+    },
+    series: [
+      {
+        name: '2012',
+        type: 'bar',
+        data: [10, 63, 21, 91, 8],
+        label: {
+          show: true,
+          position: 'right'
+        },
+        barWidth: 20
+      }
+    ]
+  });
+  renderRepairChart({
+    tooltip: {
+      trigger: 'item'
+    },
+    title: {
+      left: '18%', // 鍩轰簬瀹瑰櫒瀹藉害鐨�50%
+      top: '35%',
+      text: `{a|10涓獇\n{b|鏈慨澶峿\n{c|浠婃棩鏂板 +1}`,
+      textStyle: {
+        rich: {
+          a: {
+            color: '#4E5766',
+            fontSize: 20,
+            lineHeight: 30,
+            align: 'center'
+          },
+          b: {
+            color: '#1C2029',
+            fontSize: 18,
+            lineHeight: 30,
+            align: 'center'
+          },
+          c: {
+            color: '#ef6666',
+            fontSize: 15,
+            lineHeight: 30,
+            align: 'center'
+          }
+        }
+      }
+    },
+    legend: {
+      orient: 'vertical',
+      top: 'center',
+      right: 'right',
+      left: '70%'
+    },
+    series: [
+      {
+        name: 'Access From',
+        type: 'pie',
+        radius: ['40%', '65%'], // 璋冩暣鍐呭鍗婂緞
+        center: ['30%', '50%'], // 灏嗛ゼ鍥句腑蹇冨悜宸︾Щ涓�鐐�
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 10,
+          borderColor: '#fff',
+          borderWidth: 2
+        },
+        label: {
+          show: false,
+          position: 'center'
+        },
+        emphasis: {
+          label: {
+            show: false,
+            fontSize: 40,
+            fontWeight: 'bold'
+          }
+        },
+        labelLine: {
+          show: false
+        },
+        data: [
+          { value: 10, name: '寰呮帴鍗�' },
+          { value: 8, name: '寰呯淮淇�' },
+          { value: 9, name: '缁翠慨涓�' },
+          { value: 16, name: '瀹℃牳涓�' },
+          { value: 8, name: '鍏朵粬' }
+        ]
+      }
+    ]
+  });
+  renderFaultChart({
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow'
+      }
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true
+    },
+    xAxis: [
+      {
+        type: 'category',
+        data: ['smt', '璐寸墖鏈�', '娉ㄨ兌鏈�'],
+        axisTick: {
+          alignWithLabel: true
+        }
+      }
+    ],
+    yAxis: [
+      {
+        type: 'value'
+      }
+    ],
+    series: [
+      {
+        name: 'Direct',
+        type: 'bar',
+        barWidth: 20,
+        data: [10, 8, 12],
+        label: {
+          show: true,
+          position: 'top'
+        }
+      }
+    ]
+  });
+  renderMaintenChart({
+    tooltip: {
+      trigger: 'item'
+    },
+    title: {
+      left: '21%', // 鍩轰簬瀹瑰櫒瀹藉害鐨�50%
+      top: '40%',
+      text: `{a|鎬诲彴鏁皚\n{b|20}`,
+      textStyle: {
+        rich: {
+          a: {
+            color: '#4E5766',
+            fontSize: 20,
+            lineHeight: 30,
+            align: 'center'
+          },
+          b: {
+            color: '#1C2029',
+            fontSize: 18,
+            lineHeight: 30,
+            align: 'center'
+          }
+        }
+      }
+    },
+    legend: {
+      orient: 'vertical',
+      top: 'center',
+      right: 'right',
+      left: '70%'
+    },
+    series: [
+      {
+        name: 'Access From',
+        type: 'pie',
+        radius: ['40%', '65%'], // 璋冩暣鍐呭鍗婂緞
+        center: ['30%', '50%'], // 灏嗛ゼ鍥句腑蹇冨悜宸︾Щ涓�鐐�
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 10,
+          borderColor: '#fff',
+          borderWidth: 2
+        },
+        label: {
+          show: false,
+          position: 'center'
+        },
+        emphasis: {
+          label: {
+            show: false,
+            fontSize: 40,
+            fontWeight: 'bold'
+          }
+        },
+        labelLine: {
+          show: false
+        },
+        data: [
+          { value: 10, name: '鏈繚鍏�' },
+          { value: 8, name: '寰呬繚鍏�' },
+          { value: 9, name: '淇濆吇涓�' },
+          { value: 16, name: '寰呮帴鍗�' }
+        ]
+      }
+    ]
+  });
+});
+</script>
+
+<template>
+  <div class="main flex justify-center p-2">
+    <div class="mr-2 w-1/3">
+      <Card :bordered="false" class="section-height rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <label class="ml-2">甯哥敤鍔熻兘</label>
+        </template>
+        <Row>
+          <Col v-for="i in 9" :span="8" class="flex cursor-pointer flex-col items-center justify-center py-6 hover:bg-gray-100">
+            <Avatar size="large" src="/src/assets/logo.png">
+              <!--            <template #icon>
+                          <UserOutlined />
+                        </template>-->
+            </Avatar>
+            <label class="mt-1">璁惧鍙拌处{{ i }}</label>
+          </Col>
+        </Row>
+      </Card>
+
+      <Card :bordered="false" class="section-height mt-2 rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <span class="ml-2">浣跨敤鐘舵��</span>
+        </template>
+
+        <EchartsUI ref="useStatuChart" height="400px" />
+      </Card>
+
+      <Card :bordered="false" class="section-height mt-2 rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <span class="ml-2">璁惧缁翠慨</span>
+        </template>
+        <div class="flex w-full flex-col justify-center items-center">
+          <div class="flex w-full py-3">
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">3</span>
+              <span>鍝嶅簲瓒呮椂</span>
+            </div>
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">1</span>
+              <span>缁翠慨瓒呮椂</span>
+            </div>
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">0</span>
+              <span>鍋滄満瓒呮椂</span>
+            </div>
+          </div>
+
+          <EchartsUI ref="repairChart" height="300px" width="400px" />
+        </div>
+      </Card>
+    </div>
+
+    <div class="mr-2 w-1/3">
+      <Card :bordered="false" class="section-height flex justify-center rounded-none p-0">
+        <div class="w-full">
+          <EchartsUI ref="instChart" width="400px" />
+
+          <div class="flex justify-around pb-5">
+            <div>
+              <div class="text-center text-4xl">100<label class="ml-1 text-xl font-bold">鍙�</label></div>
+              <div class="text-center font-bold">璁惧鎬绘暟</div>
+            </div>
+
+            <div>
+              <div class="text-center text-4xl text-red-500">5<label class="ml-1 text-xl font-bold">鍙�</label></div>
+              <div class="text-center font-bold">鏁呴殰鎬绘暟</div>
+            </div>
+          </div>
+        </div>
+      </Card>
+      <Card :bordered="false" class="section-height mt-2 rounded-none">
+        <template #title>
+          <NotificationTwoTone />
+          <span class="ml-2">鍏憡</span>
+        </template>
+        <template #extra>
+          <a-button type="link">鏌ョ湅鏇村 ></a-button>
+        </template>
+
+        <div>
+          <ul class="divide-border w-full divide-y" role="list">
+            <li
+              v-for="item in todoItems"
+              :key="item.title"
+              :class="{
+                'select-none line-through opacity-60': item.completed
+              }"
+              class="flex cursor-pointer justify-between gap-x-6 py-5"
+            >
+              <div class="flex min-w-0 items-center gap-x-4">
+                <div class="min-w-0 flex-auto">
+                  <p class="text-foreground text-sm font-semibold leading-6">
+                    {{ item.title }}
+                  </p>
+                  <!-- eslint-disable vue/no-v-html -->
+                  <p class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5" v-html="item.content"></p>
+                </div>
+              </div>
+              <div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
+                <span class="text-foreground/80 mt-6 text-xs leading-6">
+                  {{ item.date }}
+                </span>
+              </div>
+            </li>
+          </ul>
+        </div>
+      </Card>
+
+      <Card :bordered="false" class="section-height mt-2 rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <span class="ml-2">鏁呴殰缁熻</span>
+        </template>
+        <span class="text-gray-500 text-xs ml-3">鏁呴殰娆℃暟:10</span>
+        <EchartsUI  ref="faultChart"  height="360px" />
+      </Card>
+
+    </div>
+
+    <div class="w-1/3">
+      <div class="flex h-14 items-center justify-around rounded-none bg-white p-0">
+        <div class="flex h-10 w-28 cursor-pointer items-center justify-around rounded-sm hover:bg-gray-100" style="background: #eaf3fe">
+          <Image :preview="false" :width="20" src="/src/assets/logo.png" />
+          <span class="mr-2 font-bold" style="color: #2d83f4">鏁呴殰鐭ヨ瘑搴�</span>
+        </div>
+        <div class="flex h-10 w-28 cursor-pointer items-center justify-around rounded-sm hover:bg-gray-100" style="background: #eaeafe">
+          <Image :preview="false" :width="20" src="/src/assets/logo.png" />
+          <span class="mr-2 font-bold" style="color: #5070e0">鏅鸿兘鎼滅储</span>
+        </div>
+        <div class="flex h-10 w-28 cursor-pointer items-center justify-around rounded-sm hover:bg-gray-100" style="background: #ebf8f7">
+          <Image :preview="false" :width="20" src="/src/assets/logo.png" />
+          <span class="mr-2 font-bold" style="color: #32b9af">甯姪涓績</span>
+        </div>
+      </div>
+      <Card :bordered="false" class="todo-height mt-2 rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <span class="ml-2">寰呭姙浜嬮」</span>
+        </template>
+
+        <div class="todo-title mt-5">璁惧绠$悊</div>
+        <div class="flex w-full flex-wrap justify-between">
+          <div
+            v-for="index in 12"
+            :class="{
+              'justify-center': index % 3 == 2,
+              'justify-end': index % 3 == 0,
+              'mt-2': index > 3
+            }"
+            class="flex w-1/3"
+          >
+            <div class="todo-box cursor-pointer hover:bg-gray-100">
+              <Image :preview="false" :width="20" src="/src/assets/logo.png" />
+              <span>鏁呴殰瀹℃牳</span>
+              <span>{{ index }}</span>
+            </div>
+          </div>
+        </div>
+
+        <div class="todo-title mt-20">澶囦欢绠$悊</div>
+        <div class="flex w-full flex-wrap justify-between">
+          <div
+            v-for="index in 3"
+            :class="{
+              'justify-center': index % 3 == 2,
+              'justify-end': index % 3 == 0
+            }"
+            class="flex w-1/3"
+          >
+            <div class="todo-box border-gray-100">
+              <Image :preview="false" :width="20" src="/src/assets/logo.png" />
+              <span>鏁呴殰瀹℃牳</span>
+              <span>{{ index }}</span>
+            </div>
+          </div>
+        </div>
+      </Card>
+
+      <Card :bordered="false" class="early-warn-height mt-2 rounded-none">
+        <template #title>
+          <AlertTwoTone two-tone-color="red" />
+          <span class="ml-2">棰勮绠$悊</span>
+        </template>
+        <div class="flex h-full items-center">
+          <div class="up-info-box w-1/2 flex h-40">
+            <div class="w-1/2 flex items-center h-full justify-center flex-col">
+              <div class="w-16">
+                <span class="text-xl text-green-600">7</span>
+                <span class="ml-1">绉�</span>
+              </div>
+              <div class="w-16">楂樹簬涓婇檺</div>
+            </div>
+            <div class="w-1/2 h-full flex items-center justify-center">
+              <Image :preview="false" src="/src/assets/img/img-up-limit.png" />
+            </div>
+          </div>
+          <div class="low-info-box w-1/2 flex h-40">
+            <div class="w-1/2 flex items-center h-full justify-center flex-col">
+              <div class="w-16">
+                <span class="text-xl text-red-600">10</span>
+                <span class="ml-1">绉�</span>
+              </div>
+              <div class="w-16">浣庝簬涓嬮檺</div>
+            </div>
+            <div class="w-1/2 h-full flex items-center justify-center">
+              <Image :preview="false" src="/src/assets/img/img-lower-limit.png" />
+            </div>
+          </div>
+        </div>
+      </Card>
+
+      <Card :bordered="false" class="section-height mt-2 rounded-none">
+        <template #title>
+          <TagTwoTone />
+          <span class="ml-2">璁惧淇濆吇</span>
+        </template>
+        <div class="flex w-full flex-col justify-center items-center">
+          <div class="flex w-full py-3">
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">3</span>
+              <span>鏈繚鍏�</span>
+            </div>
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">1</span>
+              <span>鏈湀鍒版湡</span>
+            </div>
+            <div class="flex flex-col justify-center items-center w-1/3">
+              <span class="font-bold text-xl">0</span>
+              <span>涓嬫湀鍒版湡</span>
+            </div>
+          </div>
+
+          <EchartsUI ref="maintenChart" height="300px" width="400px" />
+        </div>
+      </Card>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.main {
+  height: 2000px;
+}
+
+.section-height {
+  height: 484px;
+}
+
+.todo-height {
+  height: 644px;
+}
+
+.early-warn-height {
+  height: 260px;
+
+  :deep(.ant-card-body) {
+    height: calc(100% - 56px);
+  }
+
+  .up-info-box {
+    background: #f2faff;
+  }
+
+  .low-info-box {
+    background: #fff5eb;
+  }
+}
+
+.todo-title {
+  width: 100px;
+  height: 30px;
+  background: #ecf3fe;
+  border-left: 2px solid #2c83f4;
+  line-height: 30px;
+  text-align: center;
+  color: #2d83f4;
+  clip-path: polygon(0 0, 100% 0, 90% 100%, 0% 100%);
+  border-bottom-right-radius: 15px;
+  border-top-right-radius: 5px;
+}
+
+.todo-box {
+  width: 120px;
+  height: 42px;
+  background: #f5f6f7;
+  padding: 10px;
+  display: flex;
+  flex-wrap: nowrap;
+  overflow: hidden;
+  align-content: center;
+  justify-content: space-around;
+  margin-top: 20px;
+  cursor: pointer;
+}
+
+.todo-box:hover {
+  background: #eaf3fe;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/admin/index.vue b/eims-ui/apps/web-antd/src/views/monitor/admin/index.vue
new file mode 100644
index 0000000..2c38579
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/admin/index.vue
@@ -0,0 +1,6 @@
+<template>
+  <iframe
+    class="size-full"
+    src="http://localhost:9090/admin/applications"
+  ></iframe>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/cache/components/command-chart.vue b/eims-ui/apps/web-antd/src/views/monitor/cache/components/command-chart.vue
new file mode 100644
index 0000000..06ccf98
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/cache/components/command-chart.vue
@@ -0,0 +1,75 @@
+<script lang="ts">
+import type { EChartsOption } from 'echarts';
+
+import { defineComponent, onActivated, onMounted, ref, watch } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+export default defineComponent({
+  components: { EchartsUI },
+  props: {
+    data: {
+      default: () => [],
+      type: Array,
+    },
+  },
+  setup(props, { expose }) {
+    expose({});
+
+    const chartRef = ref<EchartsUIType>();
+    const { renderEcharts, resize } = useEcharts(chartRef);
+
+    watch(
+      () => props.data,
+      () => {
+        if (!chartRef.value) return;
+        setEchartsOption(props.data);
+      },
+      { immediate: true },
+    );
+
+    onMounted(() => {
+      setEchartsOption(props.data);
+    });
+    /**
+     * 浠庡叾浠栭〉闈㈠垏鎹㈠洖鏉ヤ細鏈変竴涓鎬殑鍔ㄧ敾鏁堟灉 闇�瑕佽皟鐢╮esize
+     * 璇ラゼ鍥剧粍浠堕渶瑕佸叧闂璦nimation
+     */
+    onActivated(() => resize(false));
+
+    function setEchartsOption(data: any[]) {
+      const option: EChartsOption = {
+        series: [
+          {
+            animationDuration: 1000,
+            animationEasing: 'cubicInOut',
+            center: ['50%', '50%'],
+            data,
+            name: '鍛戒护',
+            radius: [15, 95],
+            roseType: 'radius',
+            type: 'pie',
+          },
+        ],
+        tooltip: {
+          formatter: '{a} <br/>{b} : {c} ({d}%)',
+          trigger: 'item',
+        },
+      };
+      renderEcharts(option);
+    }
+
+    return {
+      chartRef,
+    };
+  },
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" height="400px" width="100%" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/cache/components/index.ts b/eims-ui/apps/web-antd/src/views/monitor/cache/components/index.ts
new file mode 100644
index 0000000..1978212
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/cache/components/index.ts
@@ -0,0 +1,3 @@
+export { default as CommandChart } from './command-chart.vue';
+export { default as MemoryChart } from './memory-chart.vue';
+export { default as RedisDescription } from './redis-description.vue';
diff --git a/eims-ui/apps/web-antd/src/views/monitor/cache/components/memory-chart.vue b/eims-ui/apps/web-antd/src/views/monitor/cache/components/memory-chart.vue
new file mode 100644
index 0000000..6eba744
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/cache/components/memory-chart.vue
@@ -0,0 +1,94 @@
+<script lang="ts">
+import type { EChartsOption } from 'echarts';
+
+import { defineComponent, onActivated, onMounted, ref, watch } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+export default defineComponent({
+  components: { EchartsUI },
+  props: {
+    data: {
+      default: '0',
+      type: String,
+    },
+  },
+  setup(props, { expose }) {
+    expose({});
+
+    const memoryHtmlRef = ref<EchartsUIType>();
+    const { renderEcharts, resize } = useEcharts(memoryHtmlRef);
+
+    watch(
+      () => props.data,
+      () => {
+        if (!memoryHtmlRef.value) return;
+        setEchartsOption(props.data);
+      },
+      { immediate: true },
+    );
+
+    onMounted(() => {
+      setEchartsOption(props.data);
+    });
+    // 浠庡叾浠栭〉闈㈠垏鎹㈠洖鏉ヤ細鏈変竴涓鎬殑鍔ㄧ敾鏁堟灉 闇�瑕佽皟鐢╮esize
+    onActivated(resize);
+
+    function getNearestPowerOfTen(num: number) {
+      let power = 10;
+      while (power <= num) {
+        power *= 10;
+      }
+      return power;
+    }
+
+    function setEchartsOption(value: string) {
+      // x10
+      const formattedValue = Math.floor(Number.parseFloat(value));
+      // 鏈�澶у�� 10浠ュ唴鍙�10  100浠ュ唴鍙�100 浠ユ绫绘帹
+      const max = getNearestPowerOfTen(formattedValue);
+      const options: EChartsOption = {
+        series: [
+          {
+            animation: true,
+            animationDuration: 1000,
+            data: [
+              {
+                name: '鍐呭瓨娑堣��',
+                value: Number.parseFloat(value),
+              },
+            ],
+            detail: {
+              formatter: `${value}M`,
+              valueAnimation: true,
+            },
+            max,
+            min: 0,
+            name: '宄板��',
+            progress: {
+              show: true,
+            },
+            type: 'gauge',
+          },
+        ],
+        tooltip: {
+          formatter: `{b} <br/>{a} : ${value}M`,
+        },
+      };
+      renderEcharts(options);
+    }
+
+    return {
+      memoryHtmlRef,
+    };
+  },
+});
+</script>
+
+<template>
+  <EchartsUI ref="memoryHtmlRef" height="400px" width="100%" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/cache/components/redis-description.vue b/eims-ui/apps/web-antd/src/views/monitor/cache/components/redis-description.vue
new file mode 100644
index 0000000..fcc75d0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/cache/components/redis-description.vue
@@ -0,0 +1,104 @@
+<script setup lang="ts">
+import type { RedisInfo } from '#/api/monitor/cache';
+
+import { onMounted, type PropType, watch } from 'vue';
+
+import {
+  type DescItem,
+  Description,
+  useDescription,
+} from '#/components/description';
+
+interface IRedisInfo extends RedisInfo {
+  dbSize: string;
+}
+
+const props = defineProps({
+  data: {
+    required: true,
+    type: Object as PropType<IRedisInfo>,
+  },
+});
+
+const descSchemas: DescItem[] = [
+  { field: 'redis_version', label: 'redis鐗堟湰' },
+  {
+    field: 'redis_mode',
+    label: 'redis妯″紡',
+    render(value) {
+      return value === 'standalone' ? '鍗曟満妯″紡' : '闆嗙兢妯″紡';
+    },
+  },
+  {
+    field: 'tcp_port',
+    label: 'tcp绔彛',
+  },
+  {
+    field: 'connected_clients',
+    label: '瀹㈡埛绔暟',
+  },
+  {
+    field: 'uptime_in_days',
+    label: '杩愯鏃堕棿',
+    render(value) {
+      return `${value}澶ー;
+    },
+  },
+  {
+    field: 'used_memory_human',
+    label: '浣跨敤鍐呭瓨',
+  },
+  {
+    field: 'used_cpu_user_children',
+    label: '浣跨敤CPU',
+    render(value) {
+      return Number.parseFloat(value).toFixed(2);
+    },
+  },
+  {
+    field: 'maxmemory_human',
+    label: '鍐呭瓨閰嶇疆',
+  },
+  {
+    field: 'aof_enabled',
+    label: 'AOF鏄惁寮�鍚�',
+    render(value) {
+      return value === '0' ? '鍚�' : '鏄�';
+    },
+  },
+  {
+    field: 'rdb_last_bgsave_status',
+    label: 'RDB鏄惁鎴愬姛',
+  },
+  {
+    field: 'dbSize',
+    label: 'Key鏁伴噺',
+  },
+  {
+    field: 'instantaneous_input_kbps',
+    label: '缃戠粶鍏ュ彛/鍑哄彛',
+    render(_, data) {
+      const { instantaneous_input_kbps, instantaneous_output_kbps } = data;
+      return `${instantaneous_input_kbps}kps/${instantaneous_output_kbps}kps`;
+    },
+  },
+];
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: { lg: 4, md: 3, sm: 1, xl: 4, xs: 1 },
+  schema: descSchemas,
+});
+
+onMounted(() => setDescProps({ data: props.data }));
+
+watch(
+  () => props.data,
+  (data) => {
+    setDescProps({ data });
+  },
+);
+</script>
+
+<template>
+  <Description @register="registerDescription" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/cache/index.vue b/eims-ui/apps/web-antd/src/views/monitor/cache/index.vue
new file mode 100644
index 0000000..7b892ca
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/cache/index.vue
@@ -0,0 +1,101 @@
+<script setup lang="ts">
+import { onMounted, reactive, ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+import { CommandLineIcon, MemoryIcon, RedisIcon } from '@vben/icons';
+
+import { Button, Card, Col, Row } from 'ant-design-vue';
+
+import { redisCacheInfo, type RedisInfo } from '#/api/monitor/cache';
+
+import { CommandChart, MemoryChart, RedisDescription } from './components';
+
+const baseSpan = { lg: 12, md: 24, sm: 24, xl: 12, xs: 24 };
+
+const chartData = reactive<{ command: any[]; memory: string }>({
+  command: [],
+  memory: '0',
+});
+
+interface IRedisInfo extends RedisInfo {
+  dbSize: string;
+}
+const redisInfo = ref<IRedisInfo>();
+
+onMounted(async () => {
+  await loadInfo();
+});
+
+async function loadInfo() {
+  try {
+    const ret = await redisCacheInfo();
+
+    // 鍗曚綅MB 淇濈暀涓や綅灏忔暟
+    const usedMemory = (
+      Number.parseInt(ret.info.used_memory!) /
+      1024 /
+      1024
+    ).toFixed(2);
+    chartData.memory = usedMemory;
+    // 鍛戒护缁熻
+    chartData.command = ret.commandStats;
+    // redis淇℃伅
+    redisInfo.value = { ...ret.info, dbSize: String(ret.dbSize) };
+  } catch (error) {
+    console.warn(error);
+  }
+}
+</script>
+
+<template>
+  <Page>
+    <Row :gutter="[15, 15]">
+      <Col :span="24">
+        <Card size="small">
+          <template #title>
+            <div class="flex items-center justify-start gap-[6px]">
+              <RedisIcon class="size-[16px]" />
+              <span>redis淇℃伅</span>
+            </div>
+          </template>
+          <template #extra>
+            <Button size="small" @click="loadInfo">
+              <div class="flex">
+                <span class="icon-[charm--refresh]"></span>
+              </div>
+            </Button>
+          </template>
+          <RedisDescription v-if="redisInfo" :data="redisInfo" />
+        </Card>
+      </Col>
+      <Col v-bind="baseSpan">
+        <Card size="small">
+          <template #title>
+            <div class="flex items-center gap-[6px]">
+              <CommandLineIcon class="size-[16px]" />
+              <span>鍛戒护缁熻</span>
+            </div>
+          </template>
+          <CommandChart
+            v-if="chartData.command.length > 0"
+            :data="chartData.command"
+          />
+        </Card>
+      </Col>
+      <Col v-bind="baseSpan">
+        <Card size="small">
+          <template #title>
+            <div class="flex items-center justify-start gap-[6px]">
+              <MemoryIcon class="size-[16px]" />
+              <span>鍐呭瓨鍗犵敤</span>
+            </div>
+          </template>
+          <MemoryChart
+            v-if="chartData.memory !== '0'"
+            :data="chartData.memory"
+          />
+        </Card>
+      </Col>
+    </Row>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/logininfor/data.tsx b/eims-ui/apps/web-antd/src/views/monitor/logininfor/data.tsx
new file mode 100644
index 0000000..7307dec
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/logininfor/data.tsx
@@ -0,0 +1,166 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+import type { DescItem } from '#/components/description';
+
+import type { VNode } from 'vue';
+
+import { DictEnum } from '@vben/constants';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderBrowserIcon, renderDict, renderOsIcon } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'ipaddr',
+    label: 'IP鍦板潃',
+  },
+  {
+    component: 'Input',
+    fieldName: 'userName',
+    label: '鐢ㄦ埛璐﹀彿',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_COMMON_STATUS),
+    },
+    fieldName: 'status',
+    label: '鐧诲綍鐘舵��',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'dateTime',
+    label: '鐧诲綍鏃ユ湡',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '鐢ㄦ埛璐﹀彿',
+    field: 'userName',
+  },
+  {
+    title: '鐧诲綍骞冲彴',
+    field: 'clientKey',
+  },
+  {
+    title: 'IP鍦板潃',
+    field: 'ipaddr',
+  },
+  {
+    title: 'IP鍦扮偣',
+    field: 'loginLocation',
+    width: 200,
+  },
+  {
+    title: '娴忚鍣�',
+    field: 'browser',
+    slots: {
+      default: ({ row }) => {
+        return renderBrowserIcon(row.browser, true) as VNode;
+      },
+    },
+  },
+  {
+    title: '绯荤粺',
+    field: 'os',
+    slots: {
+      default: ({ row }) => {
+        // Windows 10 or Windows Server 2016 澶暱浜� 鍒嗗壊涓�涓� 璇︽儏渚濇棫鑳界湅鍒拌缁嗙殑
+        let value = row.os;
+        if (value) {
+          const split = value.split(' or ');
+          if (split.length === 2) {
+            value = split[0];
+          }
+        }
+        return renderOsIcon(value, true) as VNode;
+      },
+    },
+  },
+  {
+    title: '鐧诲綍缁撴灉',
+    field: 'status',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_COMMON_STATUS);
+      },
+    },
+  },
+  {
+    title: '淇℃伅',
+    field: 'msg',
+  },
+  {
+    title: '鏃ユ湡',
+    field: 'loginTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 150,
+  },
+];
+
+export const modalSchema: () => DescItem[] = () => [
+  {
+    field: 'status',
+    label: '鐧诲綍鐘舵��',
+    labelMinWidth: 80,
+    render(value) {
+      return renderDict(value, DictEnum.SYS_COMMON_STATUS);
+    },
+  },
+  {
+    field: 'clientKey',
+    label: '鐧诲綍骞冲彴',
+    render(value) {
+      if (value) {
+        return value.toUpperCase();
+      }
+      return '';
+    },
+  },
+  {
+    field: 'ipaddr',
+    label: '璐﹀彿淇℃伅',
+    render(_, data) {
+      const { ipaddr, loginLocation, userName } = data;
+      return `璐﹀彿: ${userName} / ${ipaddr} / ${loginLocation}`;
+    },
+  },
+  {
+    field: 'loginTime',
+    label: '鐧诲綍鏃堕棿',
+  },
+  {
+    field: 'msg',
+    label: '鐧诲綍淇℃伅',
+    render(_, data: any) {
+      const { msg, status } = data;
+      return (
+        <span class={['font-bold', status === '0' ? '' : 'text-red-500']}>
+          {msg}
+        </span>
+      );
+    },
+  },
+  {
+    field: 'os',
+    label: '鐧诲綍璁惧',
+    render(value) {
+      return renderOsIcon(value);
+    },
+  },
+  {
+    field: 'browser',
+    label: '娴忚鍣�',
+    render(value) {
+      return renderBrowserIcon(value);
+    },
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/monitor/logininfor/index.vue b/eims-ui/apps/web-antd/src/views/monitor/logininfor/index.vue
new file mode 100644
index 0000000..4923f96
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/logininfor/index.vue
@@ -0,0 +1,213 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridDefines,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  loginInfoClean,
+  loginInfoExport,
+  loginInfoList,
+  loginInfoRemove,
+  userUnlock,
+} from '#/api/monitor/logininfo';
+import { commonDownloadExcel } from '#/utils/file/download';
+import { confirmDeleteModal } from '#/utils/modal';
+
+import { columns, querySchema } from './data';
+import loginInfoModal from './login-info-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'dateTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await loginInfoList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'infoId',
+  },
+  id: 'monitor-logininfo-index',
+};
+
+const canUnlock = ref(false);
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    checkboxChange: (e: VxeGridDefines.CheckboxChangeEventParams) => {
+      const records = e.$grid.getCheckboxRecords();
+      canUnlock.value = records.length === 1 && records[0]?.status === '1';
+    },
+  },
+});
+
+const [LoginInfoModal, modalApi] = useVbenModal({
+  connectedComponent: loginInfoModal,
+});
+
+function handlePreview(record: Recordable<any>) {
+  modalApi.setData(record);
+  modalApi.open();
+}
+
+function handleClear() {
+  confirmDeleteModal({
+    onValidated: async () => {
+      await loginInfoClean();
+      await tableApi.reload();
+    },
+  });
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await loginInfoRemove(row.infoId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.infoId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await loginInfoRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+async function handleUnlock() {
+  const records = tableApi.grid.getCheckboxRecords();
+  if (records.length !== 1) {
+    return;
+  }
+  const { userName } = records[0];
+  await userUnlock(userName);
+  await tableApi.query();
+  canUnlock.value = false;
+  tableApi.grid.clearCheckboxRow();
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(
+    loginInfoExport,
+    '鐧诲綍鏃ュ織',
+    tableApi.formApi.form.values,
+    {
+      fieldMappingTime: formOptions.fieldMappingTime,
+    },
+  );
+}
+</script>
+
+<template>
+  <Page auto-content-height>
+    <BasicTable table-title="鐧诲綍鏃ュ織鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['monitor:logininfor:remove']"
+            @click="handleClear"
+          >
+            {{ $t('pages.common.clear') }}
+          </a-button>
+          <a-button
+            v-access:code="['monitor:logininfor:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['monitor:logininfor:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            :disabled="!canUnlock"
+            type="primary"
+            v-access:code="['monitor:logininfor:unlock']"
+            @click="handleUnlock"
+          >
+            {{ $t('pages.common.unlock') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button @click.stop="handlePreview(row)">
+            {{ $t('pages.common.info') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎?"
+            @confirm="() => handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['monitor:logininfor:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <LoginInfoModal />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue b/eims-ui/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue
new file mode 100644
index 0000000..9f9eadc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { useVbenModal } from '@vben/common-ui';
+
+import { Description, useDescription } from '#/components/description';
+
+import { modalSchema } from './data';
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: 1,
+  schema: modalSchema(),
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  onOpenChange: (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    const data = modalApi.getData();
+    setDescProps({ data }, true);
+  },
+});
+</script>
+
+<template>
+  <BasicModal
+    :footer="false"
+    :fullscreen-button="false"
+    class="w-[550px]"
+    title="鐧诲綍鏃ュ織"
+  >
+    <Description @register="registerDescription" />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/online/data.ts b/eims-ui/apps/web-antd/src/views/monitor/online/data.ts
new file mode 100644
index 0000000..efd1024
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/online/data.ts
@@ -0,0 +1,84 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import type { VNode } from 'vue';
+
+import dayjs from 'dayjs';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { renderBrowserIcon, renderOsIcon } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'ipaddr',
+    label: 'IP鍦板潃',
+  },
+  {
+    component: 'Input',
+    fieldName: 'userName',
+    label: '鐢ㄦ埛璐﹀彿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  {
+    title: '鐧诲綍骞冲彴',
+    field: 'deviceType',
+  },
+  {
+    title: '鐧诲綍璐﹀彿',
+    field: 'userName',
+  },
+  {
+    title: '閮ㄩ棬鍚嶇О',
+    field: 'deptName',
+  },
+  {
+    title: 'IP鍦板潃',
+    field: 'ipaddr',
+  },
+  {
+    title: '鐧诲綍鍦板潃',
+    field: 'loginLocation',
+  },
+  {
+    title: '娴忚鍣�',
+    field: 'browser',
+    slots: {
+      default: ({ row }) => {
+        return renderBrowserIcon(row.browser, true) as VNode;
+      },
+    },
+  },
+  {
+    title: '绯荤粺',
+    field: 'os',
+    slots: {
+      default: ({ row }) => {
+        // Windows 10 or Windows Server 2016 澶暱浜� 鍒嗗壊涓�涓� 璇︽儏渚濇棫鑳界湅鍒拌缁嗙殑
+        let value = row.os;
+        if (value) {
+          const split = value.split(' or ');
+          if (split.length === 2) {
+            value = split[0];
+          }
+        }
+        return renderOsIcon(value, true) as VNode;
+      },
+    },
+  },
+  {
+    title: '鐧诲綍鏃堕棿',
+    field: 'loginTime',
+    formatter: ({ cellValue }) => {
+      return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss');
+    },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 120,
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/monitor/online/index.vue b/eims-ui/apps/web-antd/src/views/monitor/online/index.vue
new file mode 100644
index 0000000..43d9c32
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/online/index.vue
@@ -0,0 +1,71 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Page, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { forceLogout, onlineList } from '#/api/monitor/online';
+
+import { columns, querySchema } from './data';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues) => {
+        return await onlineList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'tokenId',
+  },
+  id: 'monitor-online-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ formOptions, gridOptions });
+
+async function handleForceOffline(row: Recordable<any>) {
+  await forceLogout(row.tokenId);
+  await tableApi.query();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="鍦ㄧ嚎鐢ㄦ埛鍒楄〃">
+      <template #action="{ row }">
+        <Popconfirm
+          :get-popup-container="getVxePopupContainer"
+          :title="`纭寮哄埗涓嬬嚎[${row.userName}]?`"
+          placement="left"
+          @confirm="handleForceOffline(row)"
+        >
+          <ghost-button danger>寮哄埗涓嬬嚎</ghost-button>
+        </Popconfirm>
+      </template>
+    </BasicTable>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/operlog/data.tsx b/eims-ui/apps/web-antd/src/views/monitor/operlog/data.tsx
new file mode 100644
index 0000000..1faf87f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/operlog/data.tsx
@@ -0,0 +1,199 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+import type { DescItem } from '#/components/description';
+
+import { DictEnum } from '@vben/constants';
+
+import { Tag } from 'ant-design-vue';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import {
+  renderDict,
+  renderHttpMethodTag,
+  renderJsonPreview,
+} from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'title',
+    label: '绯荤粺妯″潡',
+  },
+  {
+    component: 'Input',
+    fieldName: 'operName',
+    label: '鎿嶄綔浜哄憳',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_OPER_TYPE),
+    },
+    fieldName: 'businessType',
+    label: '鎿嶄綔绫诲瀷',
+  },
+  {
+    component: 'Input',
+    fieldName: 'operIp',
+    label: '鎿嶄綔IP',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_COMMON_STATUS),
+    },
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鎿嶄綔鏃堕棿',
+    componentProps: {
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+    },
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  { field: 'title', title: '绯荤粺妯″潡' },
+  {
+    title: '鎿嶄綔绫诲瀷',
+    field: 'businessType',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.businessType, DictEnum.SYS_OPER_TYPE);
+      },
+    },
+  },
+  { field: 'operName', title: '鎿嶄綔浜哄憳' },
+  { field: 'operIp', title: 'IP鍦板潃' },
+  { field: 'operLocation', title: 'IP淇℃伅' },
+  {
+    field: 'status',
+    title: '鎿嶄綔鐘舵��',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_COMMON_STATUS);
+      },
+    },
+  },
+  { field: 'operTime', title: '鎿嶄綔鏃ユ湡', sortable: true },
+  {
+    field: 'costTime',
+    title: '鎿嶄綔鑰楁椂',
+    sortable: true,
+    formatter({ cellValue }) {
+      return `${cellValue} ms`;
+    },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 120,
+  },
+];
+
+export const descSchema: DescItem[] = [
+  {
+    field: 'operId',
+    label: '鏃ュ織缂栧彿',
+  },
+  {
+    field: 'status',
+    label: '鎿嶄綔缁撴灉',
+    render(value) {
+      return renderDict(value, DictEnum.SYS_COMMON_STATUS);
+    },
+  },
+  {
+    field: 'title',
+    label: '鎿嶄綔妯″潡',
+    labelMinWidth: 80,
+    render(value, { businessType }) {
+      const operType = renderDict(businessType, DictEnum.SYS_OPER_TYPE);
+      return (
+        <div class="flex items-center">
+          <Tag>{value}</Tag>
+          {operType}
+        </div>
+      );
+    },
+  },
+  {
+    field: 'operIp',
+    label: '鎿嶄綔淇℃伅',
+    render(_, data) {
+      return `璐﹀彿: ${data.operName} / ${data.deptName} / ${data.operIp} / ${data.operLocation}`;
+    },
+  },
+  {
+    field: 'operUrl',
+    label: '璇锋眰淇℃伅',
+    render(_, data) {
+      const { operUrl, requestMethod } = data;
+      const methodTag = renderHttpMethodTag(requestMethod);
+      return (
+        <span>
+          {methodTag} {operUrl}
+        </span>
+      );
+    },
+  },
+  {
+    field: 'errorMsg',
+    label: '寮傚父淇℃伅',
+    render(value) {
+      return <span class="font-bold text-red-600">{value}</span>;
+    },
+    show: (data) => {
+      return data && data.errorMsg !== '';
+    },
+  },
+  {
+    field: 'method',
+    label: '鏂规硶',
+  },
+  /**
+   * 榛樿word-break: break-word;浼氬鑷磈son棰勮鏍峰紡寮傚父
+   */
+  {
+    field: 'operParam',
+    label: '璇锋眰鍙傛暟',
+    render(value) {
+      return (
+        <div class="max-h-[300px] w-full overflow-y-auto">
+          {renderJsonPreview(value)}
+        </div>
+      );
+    },
+  },
+  {
+    field: 'jsonResult',
+    label: '鍝嶅簲鍙傛暟',
+    render(value) {
+      return (
+        <div class="max-h-[300px] w-full overflow-y-auto">
+          {renderJsonPreview(value)}
+        </div>
+      );
+    },
+    show(data) {
+      return data && data.jsonResult;
+    },
+  },
+  {
+    field: 'costTime',
+    label: '鑰楁椂',
+    render(value) {
+      return `${value} ms`;
+    },
+  },
+  {
+    field: 'operTime',
+    label: '鎿嶄綔鏃堕棿',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/monitor/operlog/index.vue b/eims-ui/apps/web-antd/src/views/monitor/operlog/index.vue
new file mode 100644
index 0000000..74c34dd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/operlog/index.vue
@@ -0,0 +1,181 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import type { OperationLog } from '#/api/monitor/operlog/model';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { Modal, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+  vxeSortEvent,
+} from '#/adapter/vxe-table';
+import {
+  operLogClean,
+  operLogDelete,
+  operLogExport,
+  operLogList,
+} from '#/api/monitor/operlog';
+import { commonDownloadExcel } from '#/utils/file/download';
+import { confirmDeleteModal } from '#/utils/modal';
+
+import { columns, querySchema } from './data';
+import operationPreviewDrawer from './operation-preview-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps<OperationLog> = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        const params: any = {
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        };
+        return await operLogList(params);
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'operId',
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true,
+  },
+  id: 'monitor-operlog-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+  },
+});
+
+const [OperationPreviewDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: operationPreviewDrawer,
+});
+
+/**
+ * 棰勮
+ * @param record 鎿嶄綔鏃ュ織璁板綍
+ */
+function handlePreview(record: Recordable<any>) {
+  drawerApi.setData({ record });
+  drawerApi.open();
+}
+
+/**
+ * 娓呯┖鍏ㄩ儴鏃ュ織
+ */
+function handleClear() {
+  confirmDeleteModal({
+    onValidated: async () => {
+      await operLogClean();
+      await tableApi.reload();
+    },
+  });
+}
+/**
+ * 鍒犻櫎鏃ュ織
+ */
+async function handleDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.operId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉℃搷浣滄棩蹇楀悧锛焋,
+    onOk: async () => {
+      await operLogDelete(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(operLogExport, '鎿嶄綔鏃ュ織', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime,
+  });
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="鎿嶄綔鏃ュ織鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['monitor:operlog:remove']"
+            @click="handleClear"
+          >
+            {{ $t('pages.common.clear') }}
+          </a-button>
+          <a-button
+            v-access:code="['monitor:operlog:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['monitor:operlog:remove']"
+            @click="handleDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <ghost-button
+          v-access:code="['monitor:operlog:list']"
+          @click.stop="handlePreview(row)"
+        >
+          {{ $t('pages.common.preview') }}
+        </ghost-button>
+      </template>
+    </BasicTable>
+    <OperationPreviewDrawer />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/operlog/operation-preview-drawer.vue b/eims-ui/apps/web-antd/src/views/monitor/operlog/operation-preview-drawer.vue
new file mode 100644
index 0000000..07f98c3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/operlog/operation-preview-drawer.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { Description, useDescription } from '#/components/description';
+
+import { descSchema } from './data';
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onOpenChange: handleOpenChange,
+});
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: 1,
+  schema: descSchema,
+});
+
+function handleOpenChange(open: boolean) {
+  if (!open) {
+    return null;
+  }
+  const { record } = drawerApi.getData() as { record: Recordable<any> };
+  setDescProps({ data: record }, true);
+}
+</script>
+
+<template>
+  <BasicDrawer :footer="false" class="w-[600px]" title="鏌ョ湅鏃ュ織">
+    <Description @register="registerDescription" />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/monitor/snailjob/index.vue b/eims-ui/apps/web-antd/src/views/monitor/snailjob/index.vue
new file mode 100644
index 0000000..6b40353
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/monitor/snailjob/index.vue
@@ -0,0 +1,3 @@
+<template>
+  <iframe class="size-full" src="http://localhost:8800/snail-job"></iframe>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/client/client-drawer.vue b/eims-ui/apps/web-antd/src/views/system/client/client-drawer.vue
new file mode 100644
index 0000000..6ba88e6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/client/client-drawer.vue
@@ -0,0 +1,129 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { clientAdd, clientInfo, clientUpdate } from '#/api/system/client';
+
+import { drawerSchema } from './data';
+import SecretInput from './secret-input.vue';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  layout: 'vertical',
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2 gap-x-4',
+});
+
+function setupForm(update: boolean) {
+  formApi.updateSchema([
+    {
+      dependencies: {
+        show: () => update,
+        triggerFields: [''],
+      },
+      fieldName: 'clientId',
+    },
+    {
+      componentProps: {
+        disabled: update,
+      },
+      fieldName: 'clientKey',
+    },
+    {
+      componentProps: {
+        disabled: update,
+      },
+      fieldName: 'clientSecret',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    setupForm(isUpdate.value);
+    if (isUpdate.value && id) {
+      const record = await clientInfo(id);
+      // 涓嶈兘绂佺敤id涓�1鐨勮褰�
+      formApi.updateSchema([
+        {
+          componentProps: {
+            disabled: record.id === 1,
+          },
+          fieldName: 'status',
+        },
+      ]);
+      await formApi.setValues(record);
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? clientUpdate(data) : clientAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #clientSecret="slotProps">
+        <SecretInput v-bind="slotProps" :disabled="isUpdate" />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
+
+<style lang="scss" scoped>
+/**
+鑷畾涔夌粍浠舵牎楠屽け璐ユ牱寮�
+*/
+:deep(.form-valid-error .ant-input[name='clientSecret']) {
+  border-color: hsl(var(--destructive));
+  box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/system/client/data.tsx b/eims-ui/apps/web-antd/src/views/system/client/data.tsx
new file mode 100644
index 0000000..6240e9c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/client/data.tsx
@@ -0,0 +1,193 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDict, getDictOptions } from '#/utils/dict';
+import { renderDict, renderDictTags } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'clientKey',
+    label: '瀹㈡埛绔痥ey',
+  },
+  {
+    component: 'Input',
+    fieldName: 'clientSecret',
+    label: '瀹㈡埛绔瘑閽�',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '瀹㈡埛绔疘D',
+    field: 'clientId',
+    showOverflow: true,
+  },
+  {
+    title: '瀹㈡埛绔痥ey',
+    field: 'clientKey',
+  },
+  {
+    title: '瀹㈡埛绔瘑閽�',
+    field: 'clientSecret',
+  },
+  {
+    title: '鎺堟潈绫诲瀷',
+    field: 'grantTypeList',
+    slots: {
+      default: ({ row }) => {
+        if (!row.grantTypeList) {
+          return '鏃�';
+        }
+        return renderDictTags(
+          row.grantTypeList,
+          getDict(DictEnum.SYS_GRANT_TYPE),
+        );
+      },
+    },
+  },
+  {
+    title: '璁惧绫诲瀷',
+    field: 'deviceType',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.deviceType, DictEnum.SYS_DEVICE_TYPE);
+      },
+    },
+  },
+  {
+    title: 'token娲昏穬鏃堕棿',
+    field: 'activeTimeout',
+    formatter({ row }) {
+      return `${row.activeTimeout}绉抈;
+    },
+  },
+  {
+    title: 'token瓒呮椂鏃堕棿',
+    field: 'timeout',
+    formatter({ row }) {
+      return `${row.timeout}绉抈;
+    },
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    slots: {
+      default: 'status',
+    },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'id',
+    label: 'id',
+  },
+  {
+    component: 'Input',
+    componentProps: {
+      disabled: true,
+    },
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'clientId',
+    label: '瀹㈡埛绔疘D',
+  },
+  {
+    component: 'Input',
+    fieldName: 'clientKey',
+    label: '瀹㈡埛绔痥ey',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'clientSecret',
+    label: '瀹㈡埛绔瘑閽�',
+    rules: 'required',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      mode: 'multiple',
+      optionFilterProp: 'label',
+      options: getDictOptions(DictEnum.SYS_GRANT_TYPE),
+    },
+    fieldName: 'grantTypeList',
+    label: '鎺堟潈绫诲瀷',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_DEVICE_TYPE),
+    },
+    fieldName: 'deviceType',
+    label: '璁惧绫诲瀷',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'InputNumber',
+    componentProps: {
+      addonAfter: '绉�',
+      placeholder: '璇疯緭鍏�',
+    },
+    defaultValue: 1800,
+    fieldName: 'activeTimeout',
+    formItemClass: 'col-span-2 lg:col-span-1',
+    help: '鎸囧畾鏃堕棿鏃犳搷浣滃垯杩囨湡(鍗曚綅锛氱), 榛樿30鍒嗛挓(1800绉�)',
+    label: 'Token娲昏穬瓒呮椂鏃堕棿',
+    rules: 'required',
+  },
+  {
+    component: 'InputNumber',
+    componentProps: {
+      addonAfter: '绉�',
+    },
+    defaultValue: 604_800,
+    fieldName: 'timeout',
+    formItemClass: 'col-span-2 lg:col-span-1 ',
+    help: '鎸囧畾鏃堕棿蹇呭畾杩囨湡(鍗曚綅锛氱)锛岄粯璁や竷澶�(604800绉�)',
+    label: 'Token鍥哄畾瓒呮椂鏃堕棿',
+    rules: 'required',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/client/index.vue b/eims-ui/apps/web-antd/src/views/system/client/index.vue
new file mode 100644
index 0000000..1ba490f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/client/index.vue
@@ -0,0 +1,184 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { useAccess } from '@vben/access';
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  clientChangeStatus,
+  clientExport,
+  clientList,
+  clientRemove,
+} from '#/api/system/client';
+import { TableSwitch } from '#/components/table';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import clientDrawer from './client-drawer.vue';
+import { columns, querySchema } from './data';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+    checkMethod: (row: any) => row?.id !== 1,
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await clientList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id',
+    height: 90,
+  },
+  id: 'system-client-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [ClientDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: clientDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.id });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await clientRemove(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await clientRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(clientExport, '瀹㈡埛绔暟鎹�', tableApi.formApi.form.values);
+}
+
+const { hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="瀹㈡埛绔垪琛�">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:client:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:client:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:client:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #status="{ row }">
+        <!-- pc涓嶅厑璁哥鐢� 绂佺敤浜嗙洿鎺ョ櫥褰曚笉浜� 搴旇璁剧疆disabled -->
+        <!-- 鐧诲綍鎻愮ず: 璁よ瘉鏉冮檺绫诲瀷宸茬鐢� -->
+        <TableSwitch
+          v-model="row.status"
+          :api="() => clientChangeStatus(row)"
+          :disabled="row.id === 1 || !hasAccessByCodes(['system:client:edit'])"
+          :reload="() => tableApi.query()"
+        />
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:client:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :disabled="row.id === 1"
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              :disabled="row.id === 1"
+              danger
+              v-access:code="['system:client:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <ClientDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/client/secret-input.vue b/eims-ui/apps/web-antd/src/views/system/client/secret-input.vue
new file mode 100644
index 0000000..cc278cf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/client/secret-input.vue
@@ -0,0 +1,59 @@
+<script setup lang="ts">
+import { IconifyIcon } from '@vben/icons';
+import { buildUUID } from '@vben/utils';
+
+import { Input } from 'ant-design-vue';
+
+defineOptions({ name: 'SecretInput' });
+
+defineProps({
+  disabled: {
+    default: false,
+    type: Boolean,
+  },
+  placeholder: {
+    default: '璇疯緭鍏ュ瘑閽ユ垨闅忔満鐢熸垚',
+    type: String,
+  },
+});
+
+const value = defineModel<string>('value', {
+  required: false,
+  type: String,
+});
+
+function refreshSecret() {
+  value.value = buildUUID();
+}
+
+/**
+ * 涓囦竴瑕佸湪姣忔鏂板鏃舵墦寮�Drawer鍒锋柊
+ * 闇�瑕佽皟鐢ㄥ疄渚嬫柟娉�
+ */
+defineExpose({ refreshSecret });
+</script>
+
+<template>
+  <Input v-model:value="value" :disabled="disabled" :placeholder="placeholder">
+    <template v-if="!disabled" #addonAfter>
+      <a-button type="primary" @click="refreshSecret">
+        <div class="flex items-center gap-[4px]">
+          <IconifyIcon icon="charm:refresh" />
+          <span>闅忔満鐢熸垚</span>
+        </div>
+      </a-button>
+    </template>
+  </Input>
+</template>
+
+<style lang="scss" scoped>
+:deep(.ant-input-group-addon) {
+  padding: 0;
+  border: none;
+}
+
+:deep(.ant-btn-primary) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/system/config/config-modal.vue b/eims-ui/apps/web-antd/src/views/system/config/config-modal.vue
new file mode 100644
index 0000000..9569f0c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/config/config-modal.vue
@@ -0,0 +1,78 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { configAdd, configInfo, configUpdate } from '#/api/system/config';
+
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    labelWidth: 80,
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { id } = modalApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+
+    if (isUpdate.value && id) {
+      const record = await configInfo(id);
+      await formApi.setValues(record);
+    }
+
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? configUpdate(data) : configAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :close-on-click-modal="false" :title="title" class="w-[550px]">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/config/data.ts b/eims-ui/apps/web-antd/src/views/system/config/data.ts
new file mode 100644
index 0000000..8a27731
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/config/data.ts
@@ -0,0 +1,125 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'configName',
+    label: '鍙傛暟鍚嶇О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'configKey',
+    label: '鍙傛暟閿悕',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_YES_NO),
+    },
+    fieldName: 'configType',
+    label: '绯荤粺鍐呯疆',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '鍙傛暟鍚嶇О',
+    field: 'configName',
+  },
+  {
+    title: '鍙傛暟KEY',
+    field: 'configKey',
+  },
+  {
+    title: '鍙傛暟Value',
+    field: 'configValue',
+  },
+  {
+    title: '绯荤粺鍐呯疆',
+    field: 'configType',
+    width: 120,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.configType, DictEnum.SYS_YES_NO);
+      },
+    },
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'configId',
+    label: '鍙傛暟涓婚敭',
+  },
+  {
+    component: 'Input',
+    fieldName: 'configName',
+    label: '鍙傛暟鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'configKey',
+    label: '鍙傛暟閿悕',
+    rules: 'required',
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'configValue',
+    label: '鍙傛暟閿��',
+    rules: 'required',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_YES_NO),
+      optionType: 'button',
+    },
+    defaultValue: 'N',
+    fieldName: 'configType',
+    label: '鏄惁鍐呯疆',
+    rules: 'required',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/config/index.vue b/eims-ui/apps/web-antd/src/views/system/config/index.vue
new file mode 100644
index 0000000..25c68b8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/config/index.vue
@@ -0,0 +1,179 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  configExport,
+  configList,
+  configRefreshCache,
+  configRemove,
+} from '#/api/system/config';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import configModal from './config-modal.vue';
+import { columns, querySchema } from './data';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await configList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'configId',
+  },
+  id: 'system-config-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+const [ConfigModal, modalApi] = useVbenModal({
+  connectedComponent: configModal,
+});
+
+function handleAdd() {
+  modalApi.setData({});
+  modalApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  modalApi.setData({ id: record.configId });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await configRemove(row.configId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.configId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await configRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(configExport, '鍙傛暟閰嶇疆', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime,
+  });
+}
+
+async function handleRefreshCache() {
+  await configRefreshCache();
+  await tableApi.query();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="鍙傛暟鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="handleRefreshCache"> 鍒锋柊缂撳瓨 </a-button>
+          <a-button
+            v-access:code="['system:config:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:config:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:config:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:config:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:config:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <ConfigModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dept/data.ts b/eims-ui/apps/web-antd/src/views/system/dept/data.ts
new file mode 100644
index 0000000..5febdea
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dept/data.ts
@@ -0,0 +1,146 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'deptName',
+    label: '閮ㄩ棬鍚嶇О',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '閮ㄩ棬鐘舵��',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  {
+    field: 'deptName',
+    title: '閮ㄩ棬鍚嶇О',
+    treeNode: true,
+    width: 200,
+  },
+  {
+    field: 'deptCategory',
+    title: '绫诲埆缂栫爜',
+  },
+  {
+    field: 'orderNum',
+    title: '鎺掑簭',
+    width: 180,
+  },
+  {
+    field: 'status',
+    width: 180,
+    title: '鐘舵��',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NORMAL_DISABLE);
+      },
+    },
+  },
+  {
+    field: 'createTime',
+    title: '鍒涘缓鏃堕棿',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'deptId',
+  },
+  {
+    component: 'TreeSelect',
+    componentProps: {
+      getPopupContainer,
+    },
+    dependencies: {
+      show: (model) => model.parentId !== 0,
+      triggerFields: ['parentId'],
+    },
+    fieldName: 'parentId',
+    label: '涓婄骇閮ㄩ棬',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Input',
+    fieldName: 'deptName',
+    label: '閮ㄩ棬鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'orderNum',
+    label: '鏄剧ず鎺掑簭',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'deptCategory',
+    label: '绫诲埆缂栫爜',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      // 閫変腑浜嗗氨鍙兘淇敼 涓嶈兘閲嶇疆涓烘棤璐熻矗浜�
+      allowClear: false,
+      getPopupContainer,
+    },
+    fieldName: 'leader',
+    label: '璐熻矗浜�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'phone',
+    label: '鑱旂郴鐢佃瘽',
+    rules: z
+      .string()
+      .regex(/^1[3,4578]\d{9}$/, { message: '璇疯緭鍏ユ纭殑鎵嬫満鍙�' })
+      .optional()
+      .or(z.literal('')),
+  },
+  {
+    component: 'Input',
+    fieldName: 'email',
+    label: '閭',
+    rules: z
+      .string()
+      .email({ message: '璇疯緭鍏ユ纭殑閭' })
+      .optional()
+      .or(z.literal('')),
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/dept/dept-drawer.vue b/eims-ui/apps/web-antd/src/views/system/dept/dept-drawer.vue
new file mode 100644
index 0000000..3bf9e04
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dept/dept-drawer.vue
@@ -0,0 +1,164 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  deptAdd,
+  deptInfo,
+  deptList,
+  deptNodeList,
+  deptUpdate,
+} from '#/api/system/dept';
+import { listUserByDeptId } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+interface DrawerProps {
+  id?: number | string;
+  update: boolean;
+}
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+    formItemClass: 'col-span-2',
+    labelWidth: 80,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function getDeptTree(deptId?: number | string, exclude = false) {
+  let ret: any[] = [];
+  ret = await (!deptId || exclude ? deptList({}) : deptNodeList(deptId));
+  const treeData = listToTree(ret, { id: 'deptId', pid: 'parentId' });
+  // 娣诲姞閮ㄩ棬鍚嶇О 濡� xx-xx-xx
+  addFullName(treeData, 'deptName', ' / ');
+  return treeData;
+}
+
+async function initDeptSelect(deptId?: number | string) {
+  // 闇�瑕佸姩鎬佹洿鏂癟reeSelect缁勪欢 杩欓噷鍏佽涓虹┖
+  const treeData = await getDeptTree(deptId, !isUpdate.value);
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: { label: 'deptName', value: 'deptId' },
+        showSearch: true,
+        treeData,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'parentId',
+    },
+  ]);
+}
+
+/**
+ * 閮ㄩ棬绠$悊鍛樹笅鎷夋 鏇存柊鏃舵墠浼歟nable
+ * @param deptId
+ */
+async function initDeptUsers(deptId: number | string) {
+  const ret = await listUserByDeptId(deptId);
+  const options = ret.map((user) => ({
+    label: `${user.userName} | ${user.nickName}`,
+    value: user.userId,
+  }));
+  formApi.updateSchema([
+    {
+      componentProps: {
+        disabled: ret.length === 0,
+        options,
+        placeholder: ret.length === 0 ? '璇ラ儴闂ㄦ殏鏃犵敤鎴�' : '璇烽�夋嫨閮ㄩ棬璐熻矗浜�',
+      },
+      fieldName: 'leader',
+    },
+  ]);
+}
+
+async function setLeaderOptions() {
+  formApi.updateSchema([
+    {
+      componentProps: {
+        disabled: true,
+        options: [],
+        placeholder: '浠呭湪鏇存柊鏃跺彲閫夐儴闂ㄨ礋璐d汉',
+      },
+      fieldName: 'leader',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+
+    const { id, update } = drawerApi.getData() as DrawerProps;
+    isUpdate.value = update;
+
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (update) {
+        const record = await deptInfo(id);
+        await formApi.setValues(record);
+      }
+    }
+
+    await (update && id ? initDeptUsers(id) : setLeaderOptions());
+    /** 閮ㄩ棬閫夋嫨 涓嬫媺妗� */
+    await initDeptSelect(id);
+
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? deptUpdate(data) : deptAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dept/index.vue b/eims-ui/apps/web-antd/src/views/system/dept/index.vue
new file mode 100644
index 0000000..69ebeb0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dept/index.vue
@@ -0,0 +1,182 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { nextTick } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { eachTree, getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { deptList, deptRemove } from '#/api/system/dept';
+
+import { columns, querySchema } from './data';
+import deptDrawer from './dept-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await deptList({
+          ...formValues,
+        });
+        return { rows: resp };
+      },
+      // 榛樿璇锋眰鎺ュ彛鍚庡睍寮�鍏ㄩ儴 涓嶉渶瑕佸彲浠ュ垹闄よ繖娈�
+      querySuccess: () => {
+        // 榛樿灞曞紑 闇�瑕佸姞涓婃爣璁�
+        // eslint-disable-next-line no-use-before-define
+        eachTree(tableApi.grid.getData(), (item) => (item.expand = true));
+        nextTick(() => {
+          setExpandOrCollapse(true);
+        });
+      },
+    },
+  },
+  /**
+   * 铏氭嫙婊氬姩  榛樿鍏抽棴
+   */
+  scrollY: {
+    enabled: false,
+    gt: 0,
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'deptId',
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'deptId',
+    transform: true,
+  },
+  id: 'system-dept-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    cellDblclick: (e: any) => {
+      const { row = {} } = e;
+      if (!row?.children) {
+        return;
+      }
+      const isExpanded = row?.expand;
+      tableApi.grid.setTreeExpand(row, !isExpanded);
+      row.expand = !isExpanded;
+    },
+    // 闇�瑕佺洃鍚娇鐢ㄧ澶村睍寮�鐨勬儏鍐� 鍚﹀垯灞曞紑/鎶樺彔鐨勬暟鎹笉涓�鑷�
+    toggleTreeExpand: (e: any) => {
+      const { row = {}, expanded } = e;
+      row.expand = expanded;
+    },
+  },
+});
+const [DeptDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: deptDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({ update: false });
+  drawerApi.open();
+}
+
+function handleSubAdd(row: Recordable<any>) {
+  const { deptId } = row;
+  drawerApi.setData({ id: deptId, update: false });
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.deptId, update: true });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await deptRemove(row.deptId);
+  await tableApi.query();
+}
+
+/**
+ * 鍏ㄩ儴灞曞紑/鎶樺彔
+ * @param expand 鏄惁灞曞紑
+ */
+function setExpandOrCollapse(expand: boolean) {
+  eachTree(tableApi.grid.getData(), (item) => (item.expand = expand));
+  tableApi.grid?.setAllTreeExpand(expand);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="閮ㄩ棬鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="setExpandOrCollapse(false)">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="setExpandOrCollapse(true)">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:dept:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:dept:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <ghost-button
+            class="btn-success"
+            v-access:code="['system:dept:add']"
+            @click="handleSubAdd(row)"
+          >
+            {{ $t('pages.common.add') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:dept:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <DeptDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/data/data.ts b/eims-ui/apps/web-antd/src/views/system/dict/data/data.ts
new file mode 100644
index 0000000..b88f1bb
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/data/data.ts
@@ -0,0 +1,107 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { renderDictTag } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'dictLabel',
+    label: '瀛楀吀鏍囩',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '瀛楀吀鏍囩',
+    field: 'cssClass',
+    slots: {
+      default: ({ row }) => {
+        const { dictValue } = row;
+        return renderDictTag(dictValue, [row as any]);
+      },
+    },
+  },
+  {
+    title: '瀛楀吀閿��',
+    field: 'dictValue',
+  },
+  {
+    title: '瀛楀吀鎺掑簭',
+    field: 'dictSort',
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'dictCode',
+  },
+  {
+    component: 'Input',
+    componentProps: {
+      disabled: true,
+    },
+    fieldName: 'dictType',
+    label: '瀛楀吀绫诲瀷',
+  },
+  {
+    component: 'Input',
+    fieldName: 'listClass',
+    label: '鏍囩鏍峰紡',
+  },
+  {
+    component: 'Input',
+    fieldName: 'dictLabel',
+    label: '鏁版嵁鏍囩',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'dictValue',
+    label: '鏁版嵁閿��',
+    rules: 'required',
+  },
+  {
+    component: 'Textarea',
+    componentProps: {
+      placeholder: '鍙娇鐢╰ailwind绫诲悕 濡俠g-blue w-full h-full绛�',
+    },
+    fieldName: 'cssClass',
+    formItemClass: 'items-baseline',
+    help: '鏍囩鐨刢ss鏍峰紡, 鍙坊鍔犲凡缁忕紪璇戠殑css绫诲悕',
+    label: 'css绫诲悕',
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'dictSort',
+    label: '鏄剧ず鎺掑簭',
+    rules: 'required',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue b/eims-ui/apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue
new file mode 100644
index 0000000..74c29f9
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/data/dict-data-drawer.vue
@@ -0,0 +1,127 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  dictDataAdd,
+  dictDataUpdate,
+  dictDetailInfo,
+} from '#/api/system/dict/dict-data';
+import { tagTypes } from '#/components/dict';
+
+import { drawerSchema } from './data';
+import TagStylePicker from './tag-style-picker.vue';
+
+const emit = defineEmits<{ reload: [] }>();
+
+interface DrawerProps {
+  dictCode?: number | string;
+  dictType: string;
+}
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+    formItemClass: 'col-span-2',
+    labelWidth: 80,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+/**
+ * 鏍囩鏍峰紡閫夋嫨鍣�
+ * default: 棰勮鏍囩鏍峰紡
+ * custom: 鑷畾涔夋爣绛炬牱寮�
+ */
+const selectType = ref('default');
+/**
+ * 鏍规嵁鏍囩鏍峰紡鍒ゆ柇鏄嚜瀹氫箟杩樻槸榛樿
+ * @param listClass 鏍囩鏍峰紡
+ */
+function setupSelectType(listClass: string) {
+  // 鍒ゆ柇鏄嚜瀹氫箟杩樻槸棰勮
+  const isDefault = Reflect.has(tagTypes, listClass);
+  selectType.value = isDefault ? 'default' : 'custom';
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+
+    const { dictCode, dictType } = drawerApi.getData() as DrawerProps;
+    isUpdate.value = !!dictCode;
+    formApi.setFieldValue('dictType', dictType);
+
+    if (dictCode && isUpdate.value) {
+      const record = await dictDetailInfo(dictCode);
+      setupSelectType(record.listClass);
+      await formApi.setValues(record);
+    }
+
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? dictDataUpdate(data) : dictDataAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+  selectType.value = 'default';
+}
+
+/**
+ * 鍙栨秷鏍囩閫変腑 蹇呴』璁剧疆涓簎ndefined鎵嶈
+ */
+async function handleDeSelect() {
+  await formApi.setFieldValue('listClass', undefined);
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #listClass="slotProps">
+        <TagStylePicker
+          v-bind="slotProps"
+          v-model:select-type="selectType"
+          @deselect="handleDeSelect"
+        />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/data/index.vue b/eims-ui/apps/web-antd/src/views/system/dict/data/index.vue
new file mode 100644
index 0000000..d095f32
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/data/index.vue
@@ -0,0 +1,186 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  dictDataExport,
+  dictDataList,
+  dictDataRemove,
+} from '#/api/system/dict/dict-data';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { emitter } from '../mitt';
+import { columns, querySchema } from './data';
+import dictDataDrawer from './dict-data-drawer.vue';
+
+const dictType = ref('');
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        const params: any = {
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        };
+        if (dictType.value) {
+          params.dictType = dictType.value;
+        }
+
+        return await dictDataList(params);
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'dictCode',
+  },
+  id: 'system-dict-data-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [DictDataDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: dictDataDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({ dictType: dictType.value });
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({
+    dictType: dictType.value,
+    dictCode: record.dictCode,
+  });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await dictDataRemove(row.dictCode);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.dictCode);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await dictDataRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(dictDataExport, '瀛楀吀鏁版嵁', tableApi.formApi.form.values);
+}
+
+emitter.on('rowClick', async (value) => {
+  dictType.value = value;
+  await tableApi.query();
+});
+</script>
+
+<template>
+  <div>
+    <BasicTable id="dict-data" table-title="瀛楀吀鏁版嵁鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:dict:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:dict:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            :disabled="dictType === ''"
+            type="primary"
+            v-access:code="['system:dict:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:dict:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="
+              (node) => getVxePopupContainer(node, 'dict-data')
+            "
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:dict:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <DictDataDrawer @reload="tableApi.query()" />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/data/tag-style-picker.vue b/eims-ui/apps/web-antd/src/views/system/dict/data/tag-style-picker.vue
new file mode 100644
index 0000000..754b52f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/data/tag-style-picker.vue
@@ -0,0 +1,84 @@
+<script setup lang="ts">
+import { computed, type PropType } from 'vue';
+
+import {
+  Input,
+  type RadioChangeEvent,
+  RadioGroup,
+  Select,
+} from 'ant-design-vue';
+
+import { tagSelectOptions } from '#/components/dict';
+
+/**
+ * 闇�瑕佺姝㈤�忎紶
+ * 涓嶇姝細鏈夊鎬殑bug 浼氱粦瀹氬埌selectType涓�
+ * TODO: 鏈煡鍘熷洜 鏈夊緟鐮旂┒
+ */
+defineOptions({ inheritAttrs: false });
+
+defineEmits<{ deselect: [] }>();
+
+const options = [
+  { label: '榛樿棰滆壊', value: 'default' },
+  { label: '鑷畾涔夐鑹�', value: 'custom' },
+] as const;
+
+/**
+ * 涓昏鏄姞浜哻onst鎶ラ敊
+ */
+const computedOptions = computed(
+  () => options as unknown as { label: string; value: string }[],
+);
+
+type SelectType = (typeof options)[number]['value'];
+
+const selectType = defineModel('selectType', {
+  default: 'default',
+  type: String as PropType<SelectType>,
+});
+
+/**
+ * color蹇呴』涓篽ex棰滆壊鎴栬�卽ndefined
+ */
+const color = defineModel('value', {
+  default: undefined,
+  type: String as PropType<string | undefined>,
+});
+
+function handleSelectTypeChange(e: RadioChangeEvent) {
+  // 蹇呴』缁欓粯璁ex棰滆壊 涓嶈兘涓虹┖瀛楃涓�
+  color.value = e.target.value === 'custom' ? '#000000' : undefined;
+}
+</script>
+
+<template>
+  <div class="flex flex-1 items-center gap-[6px]">
+    <RadioGroup
+      v-model:value="selectType"
+      :options="computedOptions"
+      button-style="solid"
+      option-type="button"
+      @change="handleSelectTypeChange"
+    />
+    <Select
+      v-if="selectType === 'default'"
+      v-model:value="color"
+      :allow-clear="true"
+      :options="tagSelectOptions()"
+      class="flex-1"
+      placeholder="璇烽�夋嫨鏍囩鏍峰紡"
+      @deselect="$emit('deselect')"
+    />
+    <Input
+      v-if="selectType === 'custom'"
+      v-model:value="color"
+      class="flex-1"
+      disabled
+    >
+      <template #addonAfter>
+        <input v-model="color" class="rounded-lg" type="color" />
+      </template>
+    </Input>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/index.vue b/eims-ui/apps/web-antd/src/views/system/dict/index.vue
new file mode 100644
index 0000000..220039e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/index.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import { onUnmounted } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import DictDataPanel from './data/index.vue';
+import { emitter } from './mitt';
+import DictTypePanel from './type/index.vue';
+
+onUnmounted(() => emitter.off('rowClick'));
+</script>
+
+<template>
+  <Page
+    :auto-content-height="true"
+    content-class="flex flex-col lg:flex-row gap-4"
+  >
+    <DictTypePanel class="flex-1 overflow-hidden" />
+    <DictDataPanel class="flex-1 overflow-hidden" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/mitt.ts b/eims-ui/apps/web-antd/src/views/system/dict/mitt.ts
new file mode 100644
index 0000000..f81c6f5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/mitt.ts
@@ -0,0 +1,10 @@
+import { mitt } from '@vben/utils';
+
+/**
+ * dictType: string
+ */
+type Events = {
+  rowClick: string;
+};
+
+export const emitter = mitt<Events>();
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/type/data.ts b/eims-ui/apps/web-antd/src/views/system/dict/type/data.ts
new file mode 100644
index 0000000..3caa45e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/type/data.ts
@@ -0,0 +1,76 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'dictName',
+    label: '瀛楀吀鍚嶇О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'dictType',
+    label: '瀛楀吀绫诲瀷',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '瀛楀吀鍚嶇О',
+    field: 'dictName',
+  },
+  {
+    title: '瀛楀吀绫诲瀷',
+    field: 'dictType',
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'dictId',
+    label: 'dictId',
+  },
+  {
+    component: 'Input',
+    fieldName: 'dictName',
+    label: '瀛楀吀鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'dictType',
+    help: '浣跨敤鑻辨枃/涓嬪垝绾垮懡鍚�, 濡�:sys_normal_disable',
+    label: '瀛楀吀绫诲瀷',
+    rules: z
+      .string()
+      .regex(/^[a-z_]+$/i, { message: '瀛楀吀绫诲瀷鍙兘浣跨敤鑻辨枃/涓嬪垝绾垮懡鍚�' }),
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/type/dict-type-modal.vue b/eims-ui/apps/web-antd/src/views/system/dict/type/dict-type-modal.vue
new file mode 100644
index 0000000..1c43ba1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/type/dict-type-modal.vue
@@ -0,0 +1,79 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  dictTypeAdd,
+  dictTypeInfo,
+  dictTypeUpdate,
+} from '#/api/system/dict/dict-type';
+
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    labelWidth: 100,
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+    const { id } = modalApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    if (isUpdate.value && id) {
+      const record = await dictTypeInfo(id);
+      await formApi.setValues(record);
+    }
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? dictTypeUpdate(data) : dictTypeAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :close-on-click-modal="false" :title="title">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/dict/type/index.vue b/eims-ui/apps/web-antd/src/views/system/dict/type/index.vue
new file mode 100644
index 0000000..4c90029
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/dict/type/index.vue
@@ -0,0 +1,197 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  dictTypeExport,
+  dictTypeList,
+  dictTypeRemove,
+  refreshDictTypeCache,
+} from '#/api/system/dict/dict-type';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { emitter } from '../mitt';
+import { columns, querySchema } from './data';
+import dictTypeModal from './dict-type-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 70,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await dictTypeList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'dictId',
+  },
+  id: 'system-dict-type-index',
+};
+
+const lastDictType = ref('');
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    cellClick: (e: any) => {
+      const { row } = e;
+      if (lastDictType.value === row.dictType) {
+        return;
+      }
+      emitter.emit('rowClick', row.dictType);
+      lastDictType.value = row.dictType;
+    },
+  },
+});
+const [DictTypeModal, modalApi] = useVbenModal({
+  connectedComponent: dictTypeModal,
+});
+
+function handleAdd() {
+  modalApi.setData({});
+  modalApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  modalApi.setData({ id: record.dictId });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await dictTypeRemove(row.dictId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.dictId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await dictTypeRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+async function handleRefreshCache() {
+  await refreshDictTypeCache();
+  await tableApi.query();
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(
+    dictTypeExport,
+    '瀛楀吀绫诲瀷鏁版嵁',
+    tableApi.formApi.form.values,
+  );
+}
+</script>
+
+<template>
+  <div>
+    <BasicTable id="dict-type" table-title="瀛楀吀绫诲瀷鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:dict:edit']"
+            @click="handleRefreshCache"
+          >
+            鍒锋柊缂撳瓨
+          </a-button>
+          <a-button
+            v-access:code="['system:dict:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:dict:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:dict:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:dict:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="
+              (node) => getVxePopupContainer(node, 'dict-type')
+            "
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:dict:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <DictTypeModal @reload="tableApi.query()" />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/menu/data.tsx b/eims-ui/apps/web-antd/src/views/system/menu/data.tsx
new file mode 100644
index 0000000..fcb9842
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/menu/data.tsx
@@ -0,0 +1,381 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { h } from 'vue';
+
+import { DictEnum } from '@vben/constants';
+import { FolderIcon, MenuIcon, OkButtonIcon, VbenIcon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'menuName',
+    label: '鑿滃崟鍚嶇О ',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '鑿滃崟鐘舵�� ',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_SHOW_HIDE),
+    },
+    fieldName: 'visible',
+    label: '鏄剧ず鐘舵��',
+  },
+];
+
+// 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+export const menuTypeOptions = [
+  { label: '鐩綍', value: 'M' },
+  { label: '鑿滃崟', value: 'C' },
+  { label: '鎸夐挳', value: 'F' },
+];
+
+export const yesNoOptions = [
+  { label: '鏄�', value: '0' },
+  { label: '鍚�', value: '1' },
+];
+
+// 锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+const menuTypes = {
+  C: { icon: MenuIcon, value: '鑿滃崟' },
+  F: { icon: OkButtonIcon, value: '鎸夐挳' },
+  M: { icon: FolderIcon, value: '鐩綍' },
+};
+export const columns: VxeGridProps['columns'] = [
+  {
+    title: '鑿滃崟鍚嶇О',
+    field: 'menuName',
+    treeNode: true,
+    width: 200,
+    slots: {
+      // 闇�瑕乮18n鏀寔 鍚﹀垯杩斿洖鍘熷鍊�
+      default: ({ row }) => $t(row.menuName),
+    },
+  },
+  {
+    title: '鍥炬爣',
+    field: 'icon',
+    width: 80,
+    slots: {
+      default: ({ row }) => {
+        if (row?.icon === '#') {
+          return '';
+        }
+        return (
+          <span class={'flex justify-center'}>
+            <VbenIcon icon={row.icon} />
+          </span>
+        );
+      },
+    },
+  },
+  {
+    title: '鎺掑簭',
+    field: 'orderNum',
+    width: 120,
+  },
+  {
+    title: '缁勪欢绫诲瀷',
+    field: 'menuType',
+    width: 150,
+    slots: {
+      default: ({ row }) => {
+        const current = menuTypes[row.menuType as 'C' | 'F' | 'M'];
+        if (!current) {
+          return '鏈煡';
+        }
+        return (
+          <span class="flex items-center justify-center gap-1">
+            {h(current.icon, { class: 'size-[18px]' })}
+            <span>{current.value}</span>
+          </span>
+        );
+      },
+    },
+  },
+  {
+    title: '鏉冮檺鏍囪瘑',
+    field: 'perms',
+  },
+  {
+    title: '缁勪欢璺緞',
+    field: 'component',
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    width: 100,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NORMAL_DISABLE);
+      },
+    },
+  },
+  {
+    title: '鏄剧ず',
+    field: 'visible',
+    width: 100,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.visible, DictEnum.SYS_SHOW_HIDE);
+      },
+    },
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'menuId',
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: 0,
+    fieldName: 'parentId',
+    label: '涓婄骇鑿滃崟',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: menuTypeOptions,
+      optionType: 'button',
+    },
+    defaultValue: 'M',
+    dependencies: {
+      componentProps: (_, api) => {
+        // 鍒囨崲鏃舵竻绌烘牎楠�
+        // 鐩存帴鎶勭殑婧愮爜 娌℃湁娓呯┖鏍¢獙鐨勬柟娉�
+        Object.keys(api.errors.value).forEach((key) => {
+          api.setFieldError(key, undefined);
+        });
+        return {};
+      },
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'menuType',
+    label: '鑿滃崟绫诲瀷',
+  },
+  {
+    component: 'Input',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType'],
+    },
+    renderComponentContent: (model) => ({
+      addonBefore: () => <VbenIcon icon={model.icon} />,
+      addonAfter: () => (
+        <a href="https://icon-sets.iconify.design/" target="_blank">
+          鎼滅储鍥炬爣
+        </a>
+      ),
+    }),
+    fieldName: 'icon',
+    help: '鐐瑰嚮鎼滅储鍥炬爣璺宠浆鍒癷conify & 绮樿创',
+    label: '鑿滃崟鍥炬爣',
+  },
+  {
+    component: 'Input',
+    fieldName: 'menuName',
+    label: '鑿滃崟鍚嶇О',
+    help: '鏀寔i18n鍐欐硶, 濡�: menu.system.user',
+    rules: 'required',
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'orderNum',
+    help: '鎺掑簭, 鏁板瓧瓒婂皬瓒婇潬鍓�',
+    label: '鏄剧ず鎺掑簭',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    componentProps: (model) => {
+      const placeholder =
+        model.isFrame === '0'
+          ? '濉啓閾炬帴鍦板潃http(s)://  浣跨敤鏂伴〉闈㈡墦寮�'
+          : '濉啓`璺敱鍦板潃`鎴栬�卄閾炬帴鍦板潃`  閾炬帴榛樿浣跨敤鍐呴儴iframe鍐呭祵鎵撳紑';
+      return {
+        placeholder,
+      };
+    },
+    dependencies: {
+      rules: (model) => {
+        if (model.isFrame !== '0') {
+          return z
+            .string({ message: '璇疯緭鍏ヨ矾鐢卞湴鍧�' })
+            .refine((val) => !val.startsWith('/'), {
+              message: '璺敱鍦板潃涓嶉渶瑕佸甫/',
+            });
+        }
+        // 涓洪摼鎺�
+        return z
+          .string({ message: '璇疯緭鍏ラ摼鎺ュ湴鍧�' })
+          .regex(/^https?:\/\//, { message: '璇疯緭鍏ユ纭殑閾炬帴鍦板潃' });
+      },
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values?.menuType !== 'F',
+      triggerFields: ['isFrame', 'menuType'],
+    },
+    fieldName: 'path',
+    help: `璺敱鍦板潃涓嶅甫/, 濡�: menu, user\n 閾炬帴涓篽ttp(s)://寮�澶碶n 閾炬帴榛樿浣跨敤鍐呴儴iframe鎵撳紑, 鍙�氳繃{鏄惁澶栭摼}鎺у埗鎵撳紑鏂瑰紡`,
+    label: '璺敱鍦板潃',
+  },
+  {
+    component: 'Input',
+    componentProps: (model) => {
+      return {
+        // 涓洪摼鎺ユ椂缁勪欢disabled
+        disabled: model.isFrame === '0',
+      };
+    },
+    defaultValue: '',
+    dependencies: {
+      rules: (model) => {
+        // 闈為摼鎺ユ椂涓哄繀濉」
+        if (model.path && !/^https?:\/\//.test(model.path)) {
+          return z
+            .string()
+            .min(1, { message: '闈為摼鎺ユ椂蹇呭~缁勪欢璺緞' })
+            .refine((val) => !val.startsWith('/') && !val.endsWith('/'), {
+              message: '缁勪欢璺緞寮�澶�/鏈熬涓嶉渶瑕佸甫/',
+            });
+        }
+        // 涓洪摼鎺ユ椂闈炲繀濉�
+        return z.string().optional();
+      },
+      // 绫诲瀷涓鸿彍鍗曟椂鏄剧ず
+      show: (values) => values.menuType === 'C',
+      triggerFields: ['menuType', 'path'],
+    },
+    fieldName: 'component',
+    help: '濉啓./src/views涓嬬殑缁勪欢璺緞, 濡俿ystem/menu/index',
+    label: '缁勪欢璺緞',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: yesNoOptions,
+      optionType: 'button',
+    },
+    defaultValue: '1',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'isFrame',
+    help: '澶栭摼涓篽ttp(s)://寮�澶碶n 閫夋嫨鍚︽椂, 浣跨敤iframe浠庡唴閮ㄦ墦寮�椤甸潰, 鍚﹀垯鏂扮獥鍙f墦寮�',
+    label: '鏄惁澶栭摼',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_SHOW_HIDE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'visible',
+    help: '闅愯棌鍚庝笉浼氬嚭鐜板湪鑿滃崟鏍�, 浣嗕粛鐒跺彲浠ヨ闂�',
+    label: '鏄惁鏄剧ず',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'status',
+    help: '鍋滅敤鍚庝笉浼氬嚭鐜板湪鑿滃崟鏍�, 涔熸棤娉曡闂�',
+    label: '鑿滃崟鐘舵��',
+  },
+  {
+    component: 'Input',
+    dependencies: {
+      // 绫诲瀷涓鸿彍鍗�/鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'M',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'perms',
+    help: `鎺у埗鍣ㄤ腑瀹氫箟鐨勬潈闄愬瓧绗n 濡�: @SaCheckPermission("system:user:import")`,
+    label: '鏉冮檺鏍囪瘑',
+  },
+  {
+    component: 'Input',
+    componentProps: (model) => ({
+      // 涓洪摼鎺ユ椂缁勪欢disabled
+      disabled: model.isFrame === '0',
+      placeholder: '蹇呴』涓簀son瀛楃涓叉牸寮�',
+    }),
+    dependencies: {
+      // 绫诲瀷涓鸿彍鍗曟椂鏄剧ず
+      show: (values) => values.menuType === 'C',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'queryParam',
+    help: 'vue-router涓殑query灞炴�n 濡倇"name": "xxx", "age": 16}',
+    label: '璺敱鍙傛暟',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: yesNoOptions,
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    dependencies: {
+      // 绫诲瀷涓鸿彍鍗曟椂鏄剧ず
+      show: (values) => values.menuType === 'C',
+      triggerFields: ['menuType'],
+    },
+    fieldName: 'isCache',
+    help: '璺敱鐨刱eepAlive灞炴��',
+    label: '鏄惁缂撳瓨',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/menu/index.vue b/eims-ui/apps/web-antd/src/views/system/menu/index.vue
new file mode 100644
index 0000000..86875bd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/menu/index.vue
@@ -0,0 +1,194 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { useAccess } from '@vben/access';
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { Fallback } from '@vben/common-ui';
+import { eachTree, getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { menuList, menuRemove } from '#/api/system/menu';
+
+import { columns, querySchema } from './data';
+import menuDrawer from './menu-drawer.vue';
+
+/**
+ * 涓嶈闂负浠�涔堟湁涓や釜鏍硅妭鐐� v-if浼氭帶鍒跺彧浼氭覆鏌撲竴涓�
+ */
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await menuList({
+          ...formValues,
+        });
+        return { rows: resp };
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'menuId',
+  },
+  /**
+   * 寮�鍚櫄鎷熸粴鍔�
+   * 鏁版嵁閲忓皬鍙互閫夋嫨鍏抽棴
+   * 濡傛灉閬囧埌鏍峰紡闂(绌虹櫧銆侀敊浣� 婊氬姩绛�)鍙互閫夋嫨鍏抽棴铏氭嫙婊氬姩
+   */
+  scrollY: {
+    enabled: true,
+    gt: 0,
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'menuId',
+    // 鑷姩杞崲涓簍ree 鐢眝xe澶勭悊 鏃犻渶鎵嬪姩杞崲
+    transform: true,
+  },
+  id: 'system-menu-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    cellDblclick: (e: any) => {
+      const { row = {} } = e;
+      if (!row?.children) {
+        return;
+      }
+      const isExpanded = row?.expand;
+      tableApi.grid.setTreeExpand(row, !isExpanded);
+      row.expand = !isExpanded;
+    },
+    // 闇�瑕佺洃鍚娇鐢ㄧ澶村睍寮�鐨勬儏鍐� 鍚﹀垯灞曞紑/鎶樺彔鐨勬暟鎹笉涓�鑷�
+    toggleTreeExpand: (e: any) => {
+      const { row = {}, expanded } = e;
+      row.expand = expanded;
+    },
+  },
+});
+const [MenuDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: menuDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+function handleSubAdd(row: Recordable<any>) {
+  const { menuId } = row;
+  drawerApi.setData({ id: menuId, update: false });
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.menuId, update: true });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await menuRemove(row.menuId);
+  await tableApi.query();
+}
+
+/**
+ * 鍏ㄩ儴灞曞紑/鎶樺彔
+ * @param expand 鏄惁灞曞紑
+ */
+function setExpandOrCollapse(expand: boolean) {
+  eachTree(tableApi.grid.getData(), (item) => (item.expand = expand));
+  tableApi.grid?.setAllTreeExpand(expand);
+}
+
+/**
+ * 涓庡悗鍙伴�昏緫鐩稿悓
+ * 鍙湁绉熸埛绠$悊鍜岃秴绾х鐞嗚兘璁块棶鑿滃崟绠$悊
+ */
+const { hasAccessByRoles } = useAccess();
+const isAdmin = computed(() => {
+  return hasAccessByRoles(['admin', 'superadmin']);
+});
+</script>
+
+<template>
+  <Page v-if="isAdmin" :auto-content-height="true">
+    <BasicTable table-title="鑿滃崟鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="setExpandOrCollapse(false)">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="setExpandOrCollapse(true)">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:menu:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:menu:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <!-- '鎸夐挳绫诲瀷'鏃犳硶鍐嶆坊鍔犲瓙鑿滃崟 -->
+          <ghost-button
+            v-if="row.menuType !== 'F'"
+            class="btn-success"
+            v-access:code="['system:menu:add']"
+            @click="handleSubAdd(row)"
+          >
+            {{ $t('pages.common.add') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:menu:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <MenuDrawer @reload="tableApi.query()" />
+  </Page>
+  <Fallback v-else description="鎮ㄦ病鏈夎彍鍗曠鐞嗙殑璁块棶鏉冮檺" status="403" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/menu/menu-drawer.vue b/eims-ui/apps/web-antd/src/views/system/menu/menu-drawer.vue
new file mode 100644
index 0000000..2234169
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/menu/menu-drawer.vue
@@ -0,0 +1,138 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import {
+  addFullName,
+  cloneDeep,
+  getPopupContainer,
+  listToTree,
+} from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { menuAdd, menuInfo, menuList, menuUpdate } from '#/api/system/menu';
+
+import { drawerSchema } from './data';
+
+interface ModalProps {
+  id?: number | string;
+  update: boolean;
+}
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+    formItemClass: 'col-span-2',
+    labelWidth: 90,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupMenuSelect() {
+  // menu
+  const menuArray = await menuList();
+  // support i18n
+  menuArray.forEach((item) => {
+    item.menuName = $t(item.menuName);
+  });
+  // const folderArray = menuArray.filter((item) => item.menuType === 'M');
+  const menuTree = listToTree(menuArray, { id: 'menuId', pid: 'parentId' });
+  const fullMenuTree = [
+    {
+      menuId: 0,
+      menuName: $t('menu.root'),
+      children: menuTree,
+    },
+  ];
+  addFullName(fullMenuTree, 'menuName', ' / ');
+
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'menuName',
+          value: 'menuId',
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullMenuTree,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'menuName',
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'parentId',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id, update } = drawerApi.getData() as ModalProps;
+    isUpdate.value = update;
+
+    // 鍔犺浇鑿滃崟鏍戦�夋嫨
+    await setupMenuSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (update) {
+        const record = await menuInfo(id);
+        await formApi.setValues(record);
+      }
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? menuUpdate(data) : menuAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/notice/data.ts b/eims-ui/apps/web-antd/src/views/system/notice/data.ts
new file mode 100644
index 0000000..f814c3c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/notice/data.ts
@@ -0,0 +1,127 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'noticeTitle',
+    label: '鍏憡鏍囬',
+  },
+  {
+    component: 'Input',
+    fieldName: 'createBy',
+    label: '鍒涘缓浜�',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NOTICE_TYPE),
+    },
+    fieldName: 'noticeType',
+    label: '鍏憡绫诲瀷',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '鍏憡鏍囬',
+    field: 'noticeTitle',
+  },
+  {
+    title: '鍏憡绫诲瀷',
+    field: 'noticeType',
+    width: 120,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.noticeType, DictEnum.SYS_NOTICE_TYPE);
+      },
+    },
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    width: 120,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NOTICE_STATUS);
+      },
+    },
+  },
+  {
+    title: '鍒涘缓浜�',
+    field: 'createByName',
+    width: 150,
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'noticeId',
+    label: '涓婚敭',
+  },
+  {
+    component: 'Input',
+    fieldName: 'noticeTitle',
+    label: '鍏憡鏍囬',
+    rules: 'required',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NOTICE_STATUS),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '鍏憡鐘舵��',
+    rules: 'required',
+    formItemClass: 'col-span-1',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NOTICE_TYPE),
+      optionType: 'button',
+    },
+    defaultValue: '1',
+    fieldName: 'noticeType',
+    label: '鍏憡绫诲瀷',
+    rules: 'required',
+    formItemClass: 'col-span-1',
+  },
+  {
+    component: 'RichTextarea',
+    componentProps: {
+      width: '100%',
+    },
+    fieldName: 'noticeContent',
+    label: '鍏憡鍐呭',
+    rules: 'required',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/notice/index.vue b/eims-ui/apps/web-antd/src/views/system/notice/index.vue
new file mode 100644
index 0000000..6d4f09d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/notice/index.vue
@@ -0,0 +1,150 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import { noticeList, noticeRemove } from '#/api/system/notice';
+
+import { columns, querySchema } from './data';
+import noticeModal from './notice-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await noticeList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'noticeId',
+  },
+  id: 'system-notice-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [NoticeModal, modalApi] = useVbenModal({
+  connectedComponent: noticeModal,
+});
+
+function handleAdd() {
+  modalApi.setData({});
+  modalApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  modalApi.setData({ id: record.noticeId });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await noticeRemove(row.noticeId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.noticeId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await noticeRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="閫氱煡鍏憡鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:notice:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:notice:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:notice:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:notice:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <NoticeModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/notice/notice-modal.vue b/eims-ui/apps/web-antd/src/views/system/notice/notice-modal.vue
new file mode 100644
index 0000000..d502f69
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/notice/notice-modal.vue
@@ -0,0 +1,78 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { noticeAdd, noticeInfo, noticeUpdate } from '#/api/system/notice';
+
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  layout: 'vertical',
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    labelWidth: 100,
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+    const { id } = modalApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    if (isUpdate.value && id) {
+      const record = await noticeInfo(id);
+      await formApi.setValues(record);
+    }
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? noticeUpdate(data) : noticeAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :fullscreen-button="true" :title="title" class="w-[800px]">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/oss-config/data.tsx b/eims-ui/apps/web-antd/src/views/system/oss-config/data.tsx
new file mode 100644
index 0000000..7fcc1bf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss-config/data.tsx
@@ -0,0 +1,212 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+
+import { Tag } from 'ant-design-vue';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+const accessPolicyOptions = [
+  { color: 'orange', label: '绉佹湁', value: '0' },
+  { color: 'green', label: '鍏紑', value: '1' },
+  { color: 'blue', label: '鑷畾涔�', value: '2' },
+];
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'configKey',
+    label: '閰嶇疆鍚嶇О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'bucketName',
+    label: '妗跺悕绉�',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_YES_NO),
+    },
+    fieldName: 'status',
+    label: '鏄惁榛樿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '閰嶇疆鍚嶇О',
+    field: 'configKey',
+  },
+  {
+    title: '璁块棶绔欑偣',
+    field: 'endpoint',
+    showOverflow: true,
+  },
+  {
+    title: '妗跺悕绉�',
+    field: 'bucketName',
+  },
+  {
+    title: '鍩�',
+    field: 'region',
+  },
+  {
+    title: '鏉冮檺妗剁被鍨�',
+    field: 'accessPolicy',
+    slots: {
+      default: ({ row }) => {
+        const current = accessPolicyOptions.find(
+          (item) => item.value === row.accessPolicy,
+        );
+        if (current) {
+          return <Tag color={current.color}>{current.label}</Tag>;
+        }
+        return '鏈煡绫诲瀷';
+      },
+    },
+  },
+  {
+    title: '鏄惁榛樿',
+    field: 'status',
+    slots: {
+      default: 'status',
+    },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'ossConfigId',
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider1',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '鍩烘湰淇℃伅',
+    }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'configKey',
+    label: '閰嶇疆鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'endpoint',
+    label: '鏈嶅姟鍦板潃',
+    renderComponentContent: (formModel) => ({
+      addonBefore: () => (formModel.isHttps === 'Y' ? 'https://' : 'http://'),
+    }),
+    rules: z
+      .string()
+      .refine((domain) => domain && !/^https?:\/\/.*/.test(domain), {
+        message: '璇疯緭鍏ユ纭殑鍩熷悕, 涓嶉渶瑕乭ttp(s)',
+      }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'domain',
+    label: '鑷畾涔夊煙鍚�',
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider2',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '璁よ瘉淇℃伅',
+    }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'accessKey',
+    label: 'accessKey',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'secretKey',
+    label: 'secretKey',
+    rules: 'required',
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider3',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '鍏朵粬淇℃伅',
+    }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'bucketName',
+    label: '妗跺悕绉�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'prefix',
+    label: '鍓嶇紑',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: accessPolicyOptions,
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'accessPolicy',
+    formItemClass: 'col-span-3 lg:col-span-2',
+    label: '鏉冮檺妗剁被鍨�',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_YES_NO),
+      optionType: 'button',
+    },
+    defaultValue: 'N',
+    fieldName: 'isHttps',
+    formItemClass: 'col-span-3 lg:col-span-1',
+    label: '鏄惁https',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'region',
+    label: '鍖哄煙',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/oss-config/index.vue b/eims-ui/apps/web-antd/src/views/system/oss-config/index.vue
new file mode 100644
index 0000000..fb32a3d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss-config/index.vue
@@ -0,0 +1,166 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { useAccess } from '@vben/access';
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  ossConfigChangeStatus,
+  ossConfigList,
+  ossConfigRemove,
+} from '#/api/system/oss-config';
+import { TableSwitch } from '#/components/table';
+
+import { columns, querySchema } from './data';
+import ossConfigDrawer from './oss-config-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  schema: querySchema(),
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await ossConfigList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'ossConfigId',
+  },
+  id: 'system-oss-config-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [OssConfigDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: ossConfigDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.ossConfigId });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await ossConfigRemove(row.ossConfigId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.ossConfigId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await ossConfigRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+const { hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="oss閰嶇疆鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:ossConfig:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:ossConfig:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #status="{ row }">
+        <TableSwitch
+          v-model="row.status"
+          :api="() => ossConfigChangeStatus(row)"
+          :disabled="!hasAccessByCodes(['system:ossConfig:edit'])"
+          :reload="() => tableApi.query()"
+        />
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:ossConfig:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:ossConfig:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <OssConfigDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/oss-config/oss-config-drawer.vue b/eims-ui/apps/web-antd/src/views/system/oss-config/oss-config-drawer.vue
new file mode 100644
index 0000000..3ec5f38
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss-config/oss-config-drawer.vue
@@ -0,0 +1,90 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  ossConfigAdd,
+  ossConfigInfo,
+  ossConfigUpdate,
+} from '#/api/system/oss-config';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-3',
+    labelWidth: 100,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-3',
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    if (isUpdate.value && id) {
+      const record = await ossConfigInfo(id);
+      await formApi.setValues(record);
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    /**
+     * 杩欓噷瑙f瀯鍑烘潵鐨剉alues鍙兘鑾峰彇鍒拌嚜瀹氫箟鏍¢獙鍙傛暟鐨勫��
+     * 闇�瑕佽嚜琛岃皟鐢╢ormApi.getValues()鑾峰彇琛ㄥ崟鍊�
+     */
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? ossConfigUpdate(data) : ossConfigAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[650px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
+
+<style lang="scss" scoped>
+:deep(.ant-divider) {
+  margin: 8px 0;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/system/oss/data.tsx b/eims-ui/apps/web-antd/src/views/system/oss/data.tsx
new file mode 100644
index 0000000..d1d7590
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss/data.tsx
@@ -0,0 +1,75 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'fileName',
+    label: '鏂囦欢鍚�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'originalName',
+    label: '鍘熷悕',
+  },
+  {
+    component: 'Input',
+    fieldName: 'fileSuffix',
+    label: '鎷撳睍鍚�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'service',
+    label: '鏈嶅姟鍟�',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '鏂囦欢鍚�',
+    field: 'fileName',
+    showOverflow: true,
+  },
+  {
+    title: '鏂囦欢鍘熷悕',
+    field: 'originalName',
+    showOverflow: true,
+  },
+  {
+    title: '鏂囦欢鎷撳睍鍚�',
+    field: 'fileSuffix',
+  },
+  {
+    title: '鏂囦欢棰勮',
+    field: 'url',
+    showOverflow: true,
+    slots: { default: 'url' },
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+    sortable: true,
+  },
+  {
+    title: '涓婁紶浜�',
+    field: 'createByName',
+  },
+  {
+    title: '鏈嶅姟鍟�',
+    field: 'service',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/oss/file-upload-modal.vue b/eims-ui/apps/web-antd/src/views/system/oss/file-upload-modal.vue
new file mode 100644
index 0000000..242ce17
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss/file-upload-modal.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { Alert } from 'ant-design-vue';
+
+import { FileUpload } from '#/components/upload';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const fileList = ref<string[]>([]);
+const [BasicModal, modalApi] = useVbenModal({
+  onOpenChange: (isOpen) => {
+    if (isOpen) {
+      return null;
+    }
+    if (fileList.value.length > 0) {
+      fileList.value = [];
+      emit('reload');
+      modalApi.close();
+      return null;
+    }
+  },
+});
+
+const accept = ref(['xlsx', 'word', 'pdf']);
+const maxNumber = ref(3);
+
+const message = computed(() => {
+  return `鏀寔 [${accept.value.join(', ')}] 鏍煎紡锛屾渶澶氫笂浼� ${maxNumber.value} 涓枃浠禶;
+});
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :footer="false"
+    :fullscreen-button="false"
+    title="鏂囦欢涓婁紶"
+  >
+    <div class="flex flex-col gap-4">
+      <Alert :message="message" show-icon type="info">aaa</Alert>
+      <FileUpload
+        v-model:value="fileList"
+        :accept="accept"
+        :max-number="maxNumber"
+      />
+    </div>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/oss/image-upload-modal.vue b/eims-ui/apps/web-antd/src/views/system/oss/image-upload-modal.vue
new file mode 100644
index 0000000..87f0145
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss/image-upload-modal.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { Alert } from 'ant-design-vue';
+
+import { ImageUpload } from '#/components/upload';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const fileList = ref<string[]>([]);
+const [BasicModal, modalApi] = useVbenModal({
+  onOpenChange: (isOpen) => {
+    if (isOpen) {
+      return null;
+    }
+    if (fileList.value.length > 0) {
+      fileList.value = [];
+      emit('reload');
+      modalApi.close();
+      return null;
+    }
+  },
+});
+
+const accept = ref(['jpg', 'jpeg', 'png', 'gif', 'webp']);
+const maxNumber = ref(3);
+
+const message = computed(() => {
+  return `鏀寔 [${accept.value.join(', ')}] 鏍煎紡锛屾渶澶氫笂浼� ${maxNumber.value} 寮犲浘鐗嘸;
+});
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :footer="false"
+    :fullscreen-button="false"
+    title="鍥剧墖涓婁紶"
+  >
+    <div class="flex flex-col gap-4">
+      <Alert :message="message" show-icon type="info">aaa</Alert>
+      <ImageUpload
+        v-model:value="fileList"
+        :accept="accept"
+        :max-number="maxNumber"
+      />
+    </div>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/oss/index.vue b/eims-ui/apps/web-antd/src/views/system/oss/index.vue
new file mode 100644
index 0000000..eebcced
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/oss/index.vue
@@ -0,0 +1,227 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { getVxePopupContainer } from '@vben/utils';
+
+import {
+  Image,
+  message,
+  Modal,
+  Popconfirm,
+  Space,
+  Switch,
+  Tooltip,
+} from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+  vxeSortEvent,
+} from '#/adapter/vxe-table';
+import { configInfoByKey } from '#/api/system/config';
+import { ossDownload, ossList, ossRemove } from '#/api/system/oss';
+import { downloadByData } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import fileUploadModal from './file-upload-modal.vue';
+import imageUploadModal from './image-upload-modal.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginCreateTime]', 'params[endCreateTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        const params: any = {
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        };
+        return await ossList(params);
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'ossId',
+    height: 65,
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: false,
+  },
+  id: 'system-oss-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+  },
+});
+
+async function handleDownload(row: Recordable<any>) {
+  const hideLoading = message.loading($t('pages.common.downloadLoading'), 0);
+  try {
+    const data = await ossDownload(row.ossId);
+    downloadByData(data, row.originalName);
+  } finally {
+    hideLoading();
+  }
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await ossRemove(row.ossId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.ossId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await ossRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+const router = useRouter();
+function handleToSettings() {
+  router.push('/system/oss-config');
+}
+
+const preview = ref(false);
+onMounted(async () => {
+  const resp = await configInfoByKey('sys.oss.previewListResource');
+  preview.value = Boolean(resp);
+});
+
+function isImageFile(ext: string) {
+  const supportList = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+  return supportList.some((item) => ext.toLocaleLowerCase().includes(item));
+}
+const [ImageUploadModal, imageUploadApi] = useVbenModal({
+  connectedComponent: imageUploadModal,
+});
+
+const [FileUploadModal, fileUploadApi] = useVbenModal({
+  connectedComponent: fileUploadModal,
+});
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="鏂囦欢鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <Tooltip title="棰勮鍥剧墖">
+            <Switch v-model:checked="preview" />
+          </Tooltip>
+          <a-button
+            v-access:code="['system:ossConfig:list']"
+            @click="handleToSettings"
+          >
+            閰嶇疆绠$悊
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:oss:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            v-access:code="['system:oss:upload']"
+            @click="fileUploadApi.open"
+          >
+            鏂囦欢涓婁紶
+          </a-button>
+          <a-button
+            v-access:code="['system:oss:upload']"
+            @click="imageUploadApi.open"
+          >
+            鍥剧墖涓婁紶
+          </a-button>
+        </Space>
+      </template>
+      <template #url="{ row }">
+        <Image
+          v-if="preview && isImageFile(row.url)"
+          :src="row.url"
+          height="50px"
+        />
+        <span v-else>{{ row.url }}</span>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:oss:download']"
+            @click="handleDownload(row)"
+          >
+            {{ $t('pages.common.download') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:oss:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <ImageUploadModal @reload="tableApi.query" />
+    <FileUploadModal @reload="tableApi.query" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/post/data.ts b/eims-ui/apps/web-antd/src/views/system/post/data.ts
new file mode 100644
index 0000000..8e92e08
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/post/data.ts
@@ -0,0 +1,132 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'postCode',
+    label: '宀椾綅缂栫爜',
+  },
+  {
+    component: 'Input',
+    fieldName: 'postName',
+    label: '宀椾綅鍚嶇О',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '宀椾綅缂栫爜',
+    field: 'postCode',
+  },
+  {
+    title: '绫诲埆缂栫爜',
+    field: 'postCategory',
+  },
+  {
+    title: '宀椾綅鍚嶇О',
+    field: 'postName',
+  },
+  {
+    title: '鎺掑簭',
+    field: 'postSort',
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NORMAL_DISABLE);
+      },
+    },
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'postId',
+    label: 'postId',
+  },
+  {
+    component: 'TreeSelect',
+    componentProps: {
+      getPopupContainer,
+    },
+    fieldName: 'deptId',
+    label: '鎵�灞為儴闂�',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Input',
+    fieldName: 'postName',
+    label: '宀椾綅鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'postCode',
+    label: '宀椾綅缂栫爜',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'postCategory',
+    label: '绫诲埆缂栫爜',
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'postSort',
+    label: '宀椾綅鎺掑簭',
+    rules: 'required',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '宀椾綅鐘舵��',
+    rules: 'required',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/post/index.vue b/eims-ui/apps/web-antd/src/views/system/post/index.vue
new file mode 100644
index 0000000..4404655
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/post/index.vue
@@ -0,0 +1,187 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import { postExport, postList, postRemove } from '#/api/system/post';
+import { commonDownloadExcel } from '#/utils/file/download';
+import DeptTree from '#/views/system/user/dept-tree.vue';
+
+import { columns, querySchema } from './data';
+import postDrawer from './post-drawer.vue';
+
+// 宸﹁竟閮ㄩ棬鐢�
+const selectDeptId = ref<string[]>([]);
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  handleReset: async () => {
+    selectDeptId.value = [];
+    // eslint-disable-next-line no-use-before-define
+    const { formApi, reload } = tableApi;
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    await reload(formValues);
+  },
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    trigger: 'cell',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectDeptId.value.length === 1) {
+          formValues.belongDeptId = selectDeptId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'belongDeptId');
+        }
+
+        return await postList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'postId',
+  },
+  id: 'system-post-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [PostDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: postDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.postId });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await postRemove(row.postId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.postId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await postRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(postExport, '宀椾綅淇℃伅', tableApi.formApi.form.values);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true" content-class="flex gap-[8px] w-full">
+    <DeptTree
+      v-model:select-dept-id="selectDeptId"
+      class="w-[260px]"
+      @reload="() => tableApi.reload()"
+      @select="() => tableApi.reload()"
+    />
+    <BasicTable class="flex-1 overflow-hidden" table-title="宀椾綅鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:post:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:post:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:post:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <GhostButton
+            v-access:code="['system:post:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </GhostButton>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <GhostButton
+              danger
+              v-access:code="['system:post:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </GhostButton>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <PostDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/post/post-drawer.vue b/eims-ui/apps/web-antd/src/views/system/post/post-drawer.vue
new file mode 100644
index 0000000..100e8d0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/post/post-drawer.vue
@@ -0,0 +1,102 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { postAdd, postInfo, postUpdate } from '#/api/system/post';
+import { getDeptTree } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full',
+    },
+    labelWidth: 80,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupDeptSelect() {
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: { label: 'label', value: 'id' },
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'deptId',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await postInfo(id);
+      await formApi.setValues(record);
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? postUpdate(data) : postAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/role-assign/data.tsx b/eims-ui/apps/web-antd/src/views/system/role-assign/data.tsx
new file mode 100644
index 0000000..be0de70
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role-assign/data.tsx
@@ -0,0 +1,43 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'userName',
+    label: '鐢ㄦ埛璐﹀彿',
+  },
+  {
+    component: 'Input',
+    fieldName: 'phonenumber',
+    label: '鎵嬫満鍙风爜',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '鐢ㄦ埛璐﹀彿',
+    field: 'userName',
+  },
+  {
+    title: '鐢ㄦ埛鏄电О',
+    field: 'nickName',
+  },
+  {
+    title: '閭',
+    field: 'email',
+  },
+  {
+    title: '鎵嬫満鍙�',
+    field: 'phonenumber',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/role-assign/index.vue b/eims-ui/apps/web-antd/src/views/system/role-assign/index.vue
new file mode 100644
index 0000000..3aa7393
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role-assign/index.vue
@@ -0,0 +1,154 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { useRoute } from 'vue-router';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  roleAllocatedList,
+  roleAuthCancel,
+  roleAuthCancelAll,
+} from '#/api/system/role';
+
+import { columns, querySchema } from './data';
+import roleAssignDrawer from './role-assign-drawer.vue';
+
+const route = useRoute();
+const roleId = route.params.roleId as string;
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await roleAllocatedList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          roleId,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'userId',
+  },
+  id: 'system-role-assign-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [RoleAssignDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: roleAssignDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+/**
+ * 鍙栨秷鎺堟潈 涓�鏉¤褰�
+ */
+async function handleAuthCancel(record: Recordable<any>) {
+  await roleAuthCancel({ userId: record.userId, roleId });
+  await tableApi.query();
+}
+
+/**
+ * 鎵归噺鍙栨秷鎺堟潈
+ */
+function handleMultipleAuthCancel() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.userId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍙栨秷閫変腑鐨�${ids.length}鏉℃巿鏉冭褰曞悧锛焋,
+    onOk: async () => {
+      await roleAuthCancelAll(roleId, ids);
+      await tableApi.query();
+      tableApi.grid.clearCheckboxRow();
+    },
+  });
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="宸插垎閰嶇殑鐢ㄦ埛鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:role:remove']"
+            @click="handleMultipleAuthCancel"
+          >
+            鍙栨秷鎺堟潈
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:role:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Popconfirm
+          :get-popup-container="getVxePopupContainer"
+          :title="`鏄惁鍙栨秷鎺堟潈鐢ㄦ埛[${row.userName} - ${row.nickName}]?`"
+          placement="left"
+          @confirm="handleAuthCancel(row)"
+        >
+          <ghost-button
+            danger
+            v-access:code="['system:role:remove']"
+            @click.stop=""
+          >
+            鍙栨秷鎺堟潈
+          </ghost-button>
+        </Popconfirm>
+      </template>
+    </BasicTable>
+    <RoleAssignDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/role-assign/role-assign-drawer.vue b/eims-ui/apps/web-antd/src/views/system/role-assign/role-assign-drawer.vue
new file mode 100644
index 0000000..c5ee043
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role-assign/role-assign-drawer.vue
@@ -0,0 +1,84 @@
+<script setup lang="ts">
+import { useRoute } from 'vue-router';
+
+import { useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { roleSelectAll, roleUnallocatedList } from '#/api/system/role';
+
+import { columns, querySchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onConfirm: handleSubmit,
+  onCancel: handleReset,
+});
+
+const route = useRoute();
+const roleId = route.params.roleId as string;
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    trigger: 'row',
+  },
+  columns: columns?.filter((item) => item.field !== 'action'),
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await roleUnallocatedList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          roleId,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'userId',
+  },
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+async function handleSubmit() {
+  const records = tableApi.grid.getCheckboxRecords();
+  const userIds = records.map((item) => item.userId);
+  if (userIds.length > 0) {
+    await roleSelectAll(roleId, userIds);
+  }
+  handleReset();
+  emit('reload');
+}
+
+function handleReset() {
+  drawerApi.close();
+}
+</script>
+
+<template>
+  <BasicDrawer class="w-[800px]" title="閫夋嫨鐢ㄦ埛">
+    <BasicTable />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/role/data.tsx b/eims-ui/apps/web-antd/src/views/system/role/data.tsx
new file mode 100644
index 0000000..0e982bf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role/data.tsx
@@ -0,0 +1,225 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { Tag } from 'ant-design-vue';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+/**
+ * authScopeOptions user涔熶細鐢ㄥ埌
+ */
+export const authScopeOptions = [
+  { color: 'green', label: '鍏ㄩ儴鏁版嵁鏉冮檺', value: '1' },
+  { color: 'default', label: '鑷畾鏁版嵁鏉冮檺', value: '2' },
+  { color: 'orange', label: '鏈儴闂ㄦ暟鎹潈闄�', value: '3' },
+  { color: 'cyan', label: '鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺', value: '4' },
+  { color: 'error', label: '浠呮湰浜烘暟鎹潈闄�', value: '5' },
+];
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'roleName',
+    label: '瑙掕壊鍚嶇О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'roleKey',
+    label: '鏉冮檺瀛楃',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '鐘舵��',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '瑙掕壊鍚嶇О',
+    field: 'roleName',
+  },
+  {
+    title: '鏉冮檺瀛楃',
+    field: 'roleKey',
+    slots: {
+      default: ({ row }) => {
+        return <Tag color="processing">{row.roleKey}</Tag>;
+      },
+    },
+  },
+  {
+    title: '鏁版嵁鏉冮檺',
+    field: 'dataScope',
+    slots: {
+      default: ({ row }) => {
+        const found = authScopeOptions.find(
+          (item) => item.value === row.dataScope,
+        );
+        if (found) {
+          return <Tag color={found.color}>{found.label}</Tag>;
+        }
+        return <Tag>{row.dataScope}</Tag>;
+      },
+    },
+  },
+  {
+    title: '鎺掑簭',
+    field: 'roleSort',
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    slots: { default: 'status' },
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'roleId',
+    label: '瑙掕壊ID',
+  },
+  {
+    component: 'Input',
+    fieldName: 'roleName',
+    label: '瑙掕壊鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'roleKey',
+    help: '濡�: test simpleUser绛�',
+    label: '鏉冮檺鏍囪瘑',
+    rules: 'required',
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'roleSort',
+    label: '瑙掕壊鎺掑簭',
+    rules: 'required',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      getPopupContainer,
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    help: '淇敼鍚�, 鎷ユ湁璇ヨ鑹茬殑鐢ㄦ埛灏嗚嚜鍔ㄤ笅绾�.',
+    label: '瑙掕壊鐘舵��',
+    rules: 'required',
+  },
+  {
+    component: 'Radio',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'menuCheckStrictly',
+    label: '鑿滃崟鏉冮檺',
+  },
+  {
+    component: 'Input',
+    defaultValue: [],
+    fieldName: 'menuIds',
+    label: '鑿滃崟鏉冮檺',
+    formItemClass: 'col-span-2',
+  },
+  {
+    component: 'Textarea',
+    defaultValue: '',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline col-span-2',
+    label: '澶囨敞',
+  },
+];
+
+export const authModalSchemas: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'roleId',
+    label: '瑙掕壊ID',
+  },
+  {
+    component: 'Radio',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'deptCheckStrictly',
+    label: 'deptCheckStrictly',
+  },
+  {
+    component: 'Input',
+    componentProps: {
+      disabled: true,
+    },
+    fieldName: 'roleName',
+    label: '瑙掕壊鍚嶇О',
+  },
+  {
+    component: 'Input',
+    componentProps: {
+      disabled: true,
+    },
+    fieldName: 'roleKey',
+    label: '鏉冮檺鏍囪瘑',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+      getPopupContainer,
+      options: authScopeOptions,
+    },
+    fieldName: 'dataScope',
+    help: '鏇存敼鍚庨渶瑕佺敤鎴烽噸鏂扮櫥褰曟墠鑳界敓鏁�',
+    label: '鏉冮檺鑼冨洿',
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: [],
+    dependencies: {
+      show: (values) => values.dataScope === '2',
+      triggerFields: ['dataScope'],
+    },
+    fieldName: 'deptIds',
+    formItemClass: 'items-baseline',
+    help: '鏇存敼鍚庣珛鍗崇敓鏁�',
+    label: '閮ㄩ棬鏉冮檺',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/role/index.vue b/eims-ui/apps/web-antd/src/views/system/role/index.vue
new file mode 100644
index 0000000..3b280a6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role/index.vue
@@ -0,0 +1,249 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { computed } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { useAccess } from '@vben/access';
+import {
+  Page,
+  useVbenDrawer,
+  useVbenModal,
+  type VbenFormProps,
+} from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import {
+  Dropdown,
+  Menu,
+  MenuItem,
+  Modal,
+  Popconfirm,
+  Space,
+} from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  roleChangeStatus,
+  roleExport,
+  roleList,
+  roleRemove,
+} from '#/api/system/role';
+import { TableSwitch } from '#/components/table';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import roleAuthModal from './role-auth-modal.vue';
+import roleDrawer from './role-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+    checkMethod: ({ row }) => row.roleId !== 1,
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await roleList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'roleId',
+  },
+  id: 'system-role-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+const [RoleDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: roleDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.roleId });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await roleRemove(row.roleId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.roleId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await roleRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(roleExport, '瑙掕壊鏁版嵁', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime,
+  });
+}
+
+const { hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+const isSuperAdmin = computed(() => hasAccessByRoles(['superadmin']));
+
+const [RoleAuthModal, authModalApi] = useVbenModal({
+  connectedComponent: roleAuthModal,
+});
+
+function handleAuthEdit(record: Recordable<any>) {
+  authModalApi.setData({ id: record.roleId });
+  authModalApi.open();
+}
+
+const router = useRouter();
+function handleAssignRole(record: Recordable<any>) {
+  router.push(`/system/role-assign/${record.roleId}`);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="瑙掕壊鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:role:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:role:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:role:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #status="{ row }">
+        <TableSwitch
+          v-model="row.status"
+          :api="() => roleChangeStatus(row)"
+          :disabled="
+            row.roleId === 1 ||
+            row.roleKey === 'admin' ||
+            !hasAccessByCodes(['system:role:edit'])
+          "
+          :reload="() => tableApi.query()"
+        />
+      </template>
+      <template #action="{ row }">
+        <!-- 绉熸埛绠$悊鍛樹笉鍙慨鏀筧dmin瑙掕壊 闃叉璇搷浣� -->
+        <!-- 瓒呯骇绠$悊鍛樺彲閫氳繃绉熸埛鍒囨崲鏉ユ搷浣滅鎴风鐞嗗憳瑙掕壊 -->
+        <template
+          v-if="!row.superAdmin && (row.roleKey !== 'admin' || isSuperAdmin)"
+        >
+          <Space>
+            <ghost-button
+              v-access:code="['system:role:edit']"
+              @click.stop="handleEdit(row)"
+            >
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm
+              :get-popup-container="getVxePopupContainer"
+              placement="left"
+              title="纭鍒犻櫎锛�"
+              @confirm="handleDelete(row)"
+            >
+              <ghost-button
+                danger
+                v-access:code="['system:role:remove']"
+                @click.stop=""
+              >
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+          <Dropdown
+            :get-popup-container="getVxePopupContainer"
+            placement="bottomRight"
+          >
+            <template #overlay>
+              <Menu>
+                <MenuItem key="1" @click="handleAuthEdit(row)">
+                  鏁版嵁鏉冮檺
+                </MenuItem>
+                <MenuItem key="2" @click="handleAssignRole(row)">
+                  鍒嗛厤鐢ㄦ埛
+                </MenuItem>
+              </Menu>
+            </template>
+            <a-button size="small" type="link">
+              {{ $t('pages.common.more') }}
+            </a-button>
+          </Dropdown>
+        </template>
+      </template>
+    </BasicTable>
+    <RoleDrawer @reload="tableApi.query()" />
+    <RoleAuthModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/role/role-auth-modal.vue b/eims-ui/apps/web-antd/src/views/system/role/role-auth-modal.vue
new file mode 100644
index 0000000..c3e7a60
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role/role-auth-modal.vue
@@ -0,0 +1,118 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { roleDataScope, roleDeptTree, roleInfo } from '#/api/system/role';
+import { TreeSelectPanel } from '#/components/tree';
+
+import { authModalSchemas } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  layout: 'vertical',
+  schema: authModalSchemas(),
+  showDefaultActions: false,
+});
+
+const deptTree = ref<any[]>([]);
+async function setupDeptTree(id: number | string) {
+  const resp = await roleDeptTree(id);
+  formApi.setFieldValue('deptIds', resp.checkedKeys);
+  // 璁剧疆鑿滃崟淇℃伅
+  deptTree.value = resp.depts;
+}
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { id } = modalApi.getData() as { id: number | string };
+
+    setupDeptTree(id);
+    const record = await roleInfo(id);
+    await formApi.setValues(record);
+
+    modalApi.modalLoading(false);
+  },
+});
+
+/**
+ * 杩欓噷鎷垮埌鐨勬槸涓�涓暟缁剅ef
+ */
+const deptSelectRef = ref();
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // formApi.getValues鎷垮埌鐨勬槸涓�涓猺eadonly瀵硅薄锛屼笉鑳界洿鎺ヤ慨鏀癸紝闇�瑕乧loneDeep
+    const data = cloneDeep(await formApi.getValues());
+    // 涓嶄负鑷畾涔夋潈闄愮殑璇� 鍒犻櫎閮ㄩ棬id
+    if (data.dataScope === '2') {
+      const deptIds = deptSelectRef.value?.[0]?.getCheckedKeys() ?? [];
+      data.deptIds = deptIds;
+    } else {
+      data.deptIds = [];
+    }
+    await roleDataScope(data);
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+
+/**
+ * 閫氳繃鍥炶皟鏇存柊 鏃犳硶閫氳繃v-model
+ * @param value 鑿滃崟閫夋嫨鏄惁涓ユ牸妯″紡
+ */
+function handleCheckStrictlyChange(value: boolean) {
+  formApi.setFieldValue('deptCheckStrictly', value);
+}
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    class="min-h-[600px] w-[550px]"
+    title="鍒嗛厤鏉冮檺"
+  >
+    <BasicForm>
+      <template #deptIds="slotProps">
+        <TreeSelectPanel
+          ref="deptSelectRef"
+          v-bind="slotProps"
+          :check-strictly="formApi.form.values.deptCheckStrictly"
+          :expand-all-on-init="true"
+          :tree-data="deptTree"
+          @check-strictly-change="handleCheckStrictlyChange"
+        />
+      </template>
+    </BasicForm>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/role/role-drawer.vue b/eims-ui/apps/web-antd/src/views/system/role/role-drawer.vue
new file mode 100644
index 0000000..340966c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/role/role-drawer.vue
@@ -0,0 +1,137 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep, eachTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { menuTreeSelect, roleMenuTreeSelect } from '#/api/system/menu';
+import { roleAdd, roleInfo, roleUpdate } from '#/api/system/role';
+import { TreeSelectPanel } from '#/components/tree';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+    formItemClass: 'col-span-1',
+  },
+  layout: 'vertical',
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2 gap-x-4',
+});
+
+const menuTree = ref<any[]>([]);
+async function setupMenuTree(id?: number | string) {
+  if (id) {
+    const resp = await roleMenuTreeSelect(id);
+    formApi.setFieldValue('menuIds', resp.checkedKeys);
+    const menus = resp.menus;
+    // i18n澶勭悊
+    eachTree(menus, (node) => {
+      node.label = $t(node.label);
+    });
+    // 璁剧疆鑿滃崟淇℃伅
+    menuTree.value = resp.menus;
+  } else {
+    const resp = await menuTreeSelect();
+    formApi.setFieldValue('menuIds', []);
+    // i18n澶勭悊
+    eachTree(resp, (node) => {
+      node.label = $t(node.label);
+    });
+    // 璁剧疆鑿滃崟淇℃伅
+    menuTree.value = resp;
+  }
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+
+    if (isUpdate.value && id) {
+      const record = await roleInfo(id);
+      await formApi.setValues(record);
+    }
+    // init鑿滃崟 娉ㄦ剰椤哄簭瑕佹斁鍦ㄨ祴鍊紃ecord涔嬪悗 鍐呴儴watch浼氫緷璧杛ecord
+    await setupMenuTree(id);
+
+    drawerApi.drawerLoading(false);
+  },
+});
+
+/**
+ * 杩欓噷鎷垮埌鐨勬槸涓�涓暟缁剅ef
+ */
+const menuSelectRef = ref();
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // 杩欎釜鐢ㄤ簬鎻愪氦
+    const menuIds = menuSelectRef.value?.[0]?.getCheckedKeys() ?? [];
+    // formApi.getValues鎷垮埌鐨勬槸涓�涓猺eadonly瀵硅薄锛屼笉鑳界洿鎺ヤ慨鏀癸紝闇�瑕乧loneDeep
+    const data = cloneDeep(await formApi.getValues());
+    data.menuIds = menuIds;
+    await (isUpdate.value ? roleUpdate(data) : roleAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+
+/**
+ * 閫氳繃鍥炶皟鏇存柊 鏃犳硶閫氳繃v-model
+ * @param value 鑿滃崟閫夋嫨鏄惁涓ユ牸妯″紡
+ */
+function handleMenuCheckStrictlyChange(value: boolean) {
+  formApi.setFieldValue('menuCheckStrictly', value);
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #menuIds="slotProps">
+        <!-- check-strictly涓簉eadonly 涓嶈兘閫氳繃v-model缁戝畾 -->
+        <TreeSelectPanel
+          ref="menuSelectRef"
+          v-bind="slotProps"
+          :check-strictly="formApi.form.values.menuCheckStrictly"
+          :tree-data="menuTree"
+          @check-strictly-change="handleMenuCheckStrictlyChange"
+        />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/tenant/data.tsx b/eims-ui/apps/web-antd/src/views/system/tenant/data.tsx
new file mode 100644
index 0000000..0168948
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenant/data.tsx
@@ -0,0 +1,266 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { getPopupContainer } from '@vben/utils';
+
+import dayjs from 'dayjs';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'tenantId',
+    label: '绉熸埛缂栧彿',
+  },
+  {
+    component: 'Input',
+    fieldName: 'companyName',
+    label: '绉熸埛鍚嶇О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'contactUserName',
+    label: '鑱旂郴浜�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'contactPhone',
+    label: '鑱旂郴鐢佃瘽',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '绉熸埛缂栧彿',
+    field: 'tenantId',
+  },
+  {
+    title: '绉熸埛鍚嶇О',
+    field: 'companyName',
+  },
+  {
+    title: '鑱旂郴浜�',
+    field: 'contactUserName',
+  },
+  {
+    title: '鑱旂郴鐢佃瘽',
+    field: 'contactPhone',
+  },
+  {
+    title: '鍒版湡鏃堕棿',
+    field: 'expireTime',
+    formatter: ({ cellValue }) => {
+      if (!cellValue) {
+        return '鏃犳湡闄�';
+      }
+      return cellValue;
+    },
+  },
+  {
+    title: '绉熸埛鐘舵��',
+    field: 'status',
+    slots: { default: 'status' },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200,
+  },
+];
+
+const defaultExpireTime = dayjs()
+  .add(365, 'days')
+  .startOf('day')
+  .format('YYYY-MM-DD HH:mm:ss');
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'id',
+    label: 'id',
+  },
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'tenantId',
+    label: 'tenantId',
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider1',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '鍩烘湰淇℃伅',
+    }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'companyName',
+    label: '浼佷笟鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'contactUserName',
+    label: '鑱旂郴浜�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'contactPhone',
+    label: '鑱旂郴鐢佃瘽',
+    rules: z
+      .string()
+      .regex(/^1[3-9]\d{9}$/, { message: '璇疯緭鍏ユ纭殑鑱旂郴鐢佃瘽' }),
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider2',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '绠$悊鍛樹俊鎭�',
+    }),
+    dependencies: {
+      if: (values) => !values?.tenantId,
+      triggerFields: ['tenantId'],
+    },
+  },
+  {
+    component: 'Input',
+    fieldName: 'username',
+    label: '鐢ㄦ埛璐﹀彿',
+    rules: 'required',
+    dependencies: {
+      if: (values) => !values?.tenantId,
+      triggerFields: ['tenantId'],
+    },
+  },
+  {
+    component: 'InputPassword',
+    fieldName: 'password',
+    label: '鐢ㄦ埛瀵嗙爜',
+    rules: 'required',
+    dependencies: {
+      if: (values) => !values?.tenantId,
+      triggerFields: ['tenantId'],
+    },
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider3',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '绉熸埛璁剧疆',
+    }),
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+    },
+    fieldName: 'packageId',
+    label: '绉熸埛濂楅',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD HH:mm:ss',
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      getPopupContainer,
+    },
+    defaultValue: defaultExpireTime,
+    fieldName: 'expireTime',
+    help: `宸茬粡璁剧疆杩囨湡鏃堕棿涓嶅厑璁搁噸缃负'鏃犳湡闄�'\n鍗冲湪寮�閫氭椂鏈缃棤鏈熼檺 浠ュ悗閮戒笉鍏佽璁剧疆`,
+    label: '杩囨湡鏃堕棿',
+  },
+  {
+    component: 'InputNumber',
+    componentProps: {
+      min: -1,
+    },
+    defaultValue: -1,
+    fieldName: 'accountCount',
+    help: '-1涓嶉檺鍒剁敤鎴锋暟閲�',
+    label: '鐢ㄦ埛鏁伴噺',
+    renderComponentContent(model) {
+      return {
+        addonBefore: () =>
+          model.accountCount === -1 ? '涓嶉檺鍒舵暟閲�' : '杈撳叆鏁伴噺',
+      };
+    },
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'domain',
+    help: '鍙~鍐欏煙鍚�/绔彛 濉啓鍩熷悕濡�: www.test.com 鎴栬�� www.test.com:8080 濉啓ip:绔彛濡�: 127.0.0.1:8080',
+    label: '缁戝畾鍩熷悕',
+    renderComponentContent() {
+      return {
+        addonBefore: () => 'http(s)://',
+      };
+    },
+    rules: z
+      .string()
+      .refine(
+        (domain) =>
+          !(domain.startsWith('http://') || domain.startsWith('https://')),
+        { message: '璇疯緭鍏ユ纭殑鍩熷悕, 涓嶉渶瑕乭ttp(s)' },
+      )
+      .optional(),
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'center',
+    },
+    fieldName: 'divider4',
+    hideLabel: true,
+    renderComponentContent: () => ({
+      default: () => '浼佷笟淇℃伅',
+    }),
+  },
+  {
+    component: 'Input',
+    fieldName: 'address',
+    label: '浼佷笟鍦板潃',
+  },
+  {
+    component: 'Input',
+    fieldName: 'licenseNumber',
+    label: '浼佷笟浠g爜',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'intro',
+    formItemClass: 'items-baseline',
+    label: '浼佷笟浠嬬粛',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/tenant/index.vue b/eims-ui/apps/web-antd/src/views/system/tenant/index.vue
new file mode 100644
index 0000000..8e0869f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenant/index.vue
@@ -0,0 +1,236 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { useAccess } from '@vben/access';
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { Fallback } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  dictSyncTenant,
+  tenantExport,
+  tenantList,
+  tenantRemove,
+  tenantStatusChange,
+  tenantSyncPackage,
+} from '#/api/system/tenant';
+import { TableSwitch } from '#/components/table';
+import { useTenantStore } from '#/store/tenant';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import tenantDrawer from './tenant-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+    checkMethod: ({ row }) => row?.id !== 1,
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await tenantList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id',
+  },
+  id: 'system-tenant-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [TenantDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: tenantDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.id });
+  drawerApi.open();
+}
+
+async function handleSync(record: Recordable<any>) {
+  const { tenantId, packageId } = record;
+  await tenantSyncPackage(tenantId, packageId);
+  await tableApi.query();
+}
+
+const tenantStore = useTenantStore();
+async function handleDelete(row: Recordable<any>) {
+  await tenantRemove(row.id);
+  await tableApi.query();
+  // 閲嶆柊鍔犺浇绉熸埛淇℃伅
+  tenantStore.initTenant();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await tenantRemove(ids);
+      await tableApi.query();
+      // 閲嶆柊鍔犺浇绉熸埛淇℃伅
+      tenantStore.initTenant();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(tenantExport, '绉熸埛鏁版嵁', tableApi.formApi.form.values);
+}
+
+/**
+ * 涓庡悗鍙伴�昏緫鐩稿悓
+ * 鍙湁瓒呯骇绠$悊鍛樿兘璁块棶绉熸埛鐩稿叧
+ */
+const { hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+const isSuperAdmin = computed(() => {
+  return hasAccessByRoles(['superadmin']);
+});
+
+function handleSyncTenantDict() {
+  Modal.confirm({
+    title: '鎻愮ず',
+    iconType: 'warning',
+    content: '纭鍚屾绉熸埛瀛楀吀锛�',
+    onOk: async () => {
+      await dictSyncTenant();
+      await tableApi.query();
+    },
+  });
+}
+</script>
+
+<template>
+  <Page v-if="isSuperAdmin" :auto-content-height="true">
+    <BasicTable table-title="绉熸埛鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:tenant:edit']"
+            @click="handleSyncTenantDict"
+          >
+            鍚屾绉熸埛瀛楀吀
+          </a-button>
+          <a-button
+            v-access:code="['system:tenant:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:tenant:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:tenant:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #status="{ row }">
+        <TableSwitch
+          v-model="row.status"
+          :api="() => tenantStatusChange(row)"
+          :disabled="row.id === 1 || !hasAccessByCodes(['system:tenant:edit'])"
+          :reload="() => tableApi.query()"
+        />
+      </template>
+      <template #action="{ row }">
+        <Space v-if="row.id !== 1">
+          <ghost-button
+            v-access:code="['system:tenant:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            :title="`纭鍚屾[${row.companyName}]鐨勫椁愬悧?`"
+            placement="left"
+            @confirm="handleSync(row)"
+          >
+            <ghost-button
+              class="btn-success"
+              v-access:code="['system:tenant:edit']"
+            >
+              {{ $t('pages.common.sync') }}
+            </ghost-button>
+          </Popconfirm>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:tenant:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <TenantDrawer @reload="tableApi.query()" />
+  </Page>
+  <Fallback v-else description="鎮ㄦ病鏈夌鎴风殑璁块棶鏉冮檺" status="403" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/tenant/tenant-drawer.vue b/eims-ui/apps/web-antd/src/views/system/tenant/tenant-drawer.vue
new file mode 100644
index 0000000..679b876
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenant/tenant-drawer.vue
@@ -0,0 +1,119 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { tenantAdd, tenantInfo, tenantUpdate } from '#/api/system/tenant';
+import { packageSelectList } from '#/api/system/tenant-package';
+import { useTenantStore } from '#/store/tenant';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    labelWidth: 100,
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupPackageSelect() {
+  const tenantPackageList = await packageSelectList();
+  const options = tenantPackageList.map((item) => ({
+    label: item.packageName,
+    value: item.packageId,
+  }));
+  formApi.updateSchema([
+    {
+      componentProps: {
+        optionFilterProp: 'label',
+        optionLabelProp: 'label',
+        options,
+        showSearch: true,
+      },
+      fieldName: 'packageId',
+    },
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupPackageSelect();
+    if (isUpdate.value && id) {
+      const record = await tenantInfo(id);
+      await formApi.setValues(record);
+    }
+    formApi.updateSchema([
+      {
+        fieldName: 'packageId',
+        componentProps: {
+          disabled: isUpdate.value,
+        },
+      },
+    ]);
+    drawerApi.drawerLoading(false);
+  },
+});
+
+const tenantStore = useTenantStore();
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? tenantUpdate(data) : tenantAdd(data));
+    emit('reload');
+    await handleCancel();
+    // 閲嶆柊鍔犺浇绉熸埛淇℃伅
+    tenantStore.initTenant();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
+
+<style lang="scss" scoped>
+:deep(.ant-divider) {
+  margin: 8px 0;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/system/tenantPackage/data.ts b/eims-ui/apps/web-antd/src/views/system/tenantPackage/data.ts
new file mode 100644
index 0000000..127f8f4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenantPackage/data.ts
@@ -0,0 +1,77 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'packageName',
+    label: '濂楅鍚嶇О',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    title: '濂楅鍚嶇О',
+    field: 'packageName',
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    slots: { default: 'status' },
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'packageId',
+  },
+  {
+    component: 'Radio',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'menuCheckStrictly',
+  },
+  {
+    component: 'Input',
+    fieldName: 'packageName',
+    label: '濂楅鍚嶇О',
+    rules: 'required',
+  },
+  {
+    component: 'menuIds',
+    defaultValue: [],
+    fieldName: 'menuIds',
+    label: '鍏宠仈鑿滃崟',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
+
+// 绉熸埛绠$悊 涓嶅彲鍒嗛厤  鍙湁superadmin鏈夋潈闄愭搷浣� 鍒嗛厤浜嗕篃娌$敤
+export const excludeIds = [
+  6, 121, 122, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615,
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/tenantPackage/index.vue b/eims-ui/apps/web-antd/src/views/system/tenantPackage/index.vue
new file mode 100644
index 0000000..a37699d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenantPackage/index.vue
@@ -0,0 +1,194 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { useAccess } from '@vben/access';
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { Fallback } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  packageChangeStatus,
+  packageExport,
+  packageList,
+  packageRemove,
+} from '#/api/system/tenant-package';
+import { TableSwitch } from '#/components/table';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import tenantPackageDrawer from './tenant-package-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await packageList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'packageId',
+  },
+  id: 'system-tenant-package-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [TenantPackageDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: tenantPackageDrawer,
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.packageId });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await packageRemove(row.packageId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.packageId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await packageRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(
+    packageExport,
+    '绉熸埛濂楅鏁版嵁',
+    tableApi.formApi.form.values,
+  );
+}
+
+/**
+ * 涓庡悗鍙伴�昏緫鐩稿悓
+ * 鍙湁瓒呯骇绠$悊鍛樿兘璁块棶绉熸埛鐩稿叧
+ */
+const { hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+const isSuperAdmin = computed(() => {
+  return hasAccessByRoles(['superadmin']);
+});
+</script>
+
+<template>
+  <Page v-if="isSuperAdmin" :auto-content-height="true">
+    <BasicTable table-title="绉熸埛濂楅鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button
+            v-access:code="['system:tenantPackage:export']"
+            @click="handleDownloadExcel"
+          >
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['system:tenantPackage:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['system:tenantPackage:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #status="{ row }">
+        <TableSwitch
+          v-model="row.status"
+          :api="() => packageChangeStatus(row)"
+          :disabled="!hasAccessByCodes(['system:tenantPackage:edit'])"
+          :reload="() => tableApi.query()"
+        />
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['system:tenantPackage:edit']"
+            @click="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['system:tenantPackage:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <TenantPackageDrawer @reload="tableApi.query()" />
+  </Page>
+  <Fallback v-else description="鎮ㄦ病鏈夌鎴风殑璁块棶鏉冮檺" status="403" />
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/tenantPackage/tenant-package-drawer.vue b/eims-ui/apps/web-antd/src/views/system/tenantPackage/tenant-package-drawer.vue
new file mode 100644
index 0000000..fd4edbb
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenantPackage/tenant-package-drawer.vue
@@ -0,0 +1,145 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep, eachTree, listToTree } from '@vben/utils';
+
+import { omit } from 'lodash-es';
+
+import { useVbenForm } from '#/adapter/form';
+import { menuList, tenantPackageMenuTreeSelect } from '#/api/system/menu';
+import {
+  packageAdd,
+  packageInfo,
+  packageUpdate,
+} from '#/api/system/tenant-package';
+import { TreeSelectPanel } from '#/components/tree';
+
+import { drawerSchema } from './data';
+import TreeItem from './tree-item';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+  },
+  layout: 'vertical',
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupMenuTreeSelect(id?: number | string) {
+  if (id) {
+    const resp = await tenantPackageMenuTreeSelect(id);
+    await formApi.setFieldValue('menuIds', resp.checkedKeys);
+  }
+}
+
+const menuTree = ref<any[]>([]);
+async function setupMenuTree() {
+  const resp = await menuList();
+  const treeData = listToTree(resp, { id: 'menuId' });
+  // i18n澶勭悊
+  eachTree(treeData, (node) => {
+    node.menuName = $t(node.menuName);
+  });
+  // 璁剧疆鑿滃崟淇℃伅
+  menuTree.value = treeData;
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    if (isUpdate.value && id) {
+      const record = await packageInfo(id);
+      // 闇�瑕佹帓闄enuIds menuIds涓簊tring
+      // 閫氳繃setupMenuTreeSelect璁剧疆
+      await formApi.setValues(omit(record, ['menuIds']));
+    }
+    /**
+     * 鍔犺浇鑿滃崟鏍戝拰宸插嬀閫夎彍鍗�
+     */
+    await Promise.all([setupMenuTree(), setupMenuTreeSelect(id)]);
+
+    drawerApi.drawerLoading(false);
+  },
+});
+
+/**
+ * 杩欓噷鎷垮埌鐨勬槸涓�涓暟缁剅ef
+ */
+const menuSelectRef = ref();
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // 杩欎釜鐢ㄤ簬鎻愪氦
+    const menuIds = menuSelectRef.value?.[0]?.getCheckedKeys() ?? [];
+    // formApi.getValues鎷垮埌鐨勬槸涓�涓猺eadonly瀵硅薄锛屼笉鑳界洿鎺ヤ慨鏀癸紝闇�瑕乧loneDeep
+    const data = cloneDeep(await formApi.getValues());
+    data.menuIds = menuIds;
+    await (isUpdate.value ? packageUpdate(data) : packageAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+
+/**
+ * 閫氳繃鍥炶皟鏇存柊 鏃犳硶閫氳繃v-model
+ * @param value 鑿滃崟閫夋嫨鏄惁涓ユ牸妯″紡
+ */
+function handleMenuCheckStrictlyChange(value: boolean) {
+  formApi.setFieldValue('menuCheckStrictly', value);
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #menuIds="slotProps">
+        <TreeSelectPanel
+          ref="menuSelectRef"
+          v-bind="slotProps"
+          :check-strictly="formApi.form.values.menuCheckStrictly"
+          :expand-all-on-init="false"
+          :field-names="{ title: 'menuName', key: 'menuId' }"
+          :tree-data="menuTree"
+          @check-strictly-change="handleMenuCheckStrictlyChange"
+        >
+          <template #title="data">
+            <TreeItem :data="data" />
+          </template>
+        </TreeSelectPanel>
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/tenantPackage/tree-item.tsx b/eims-ui/apps/web-antd/src/views/system/tenantPackage/tree-item.tsx
new file mode 100644
index 0000000..cf1b268
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/tenantPackage/tree-item.tsx
@@ -0,0 +1,42 @@
+import type { Menu } from '#/api/system/menu/model';
+
+import { computed, defineComponent, type PropType } from 'vue';
+
+import { Tag } from 'ant-design-vue';
+
+export default defineComponent({
+  name: 'TreeItem',
+  props: {
+    data: {
+      required: true,
+      type: Object as PropType<Menu>,
+    },
+  },
+  setup(props, { expose }) {
+    expose();
+
+    interface TagProp {
+      color: string;
+      text: string;
+    }
+
+    const menuTagProp = computed<TagProp>(() => {
+      // 姝e垯鍒ゆ柇鏄惁涓洪摼鎺�
+      if (/^https?:\/\/[^\s/$.?#].\S*$/i.test(props.data.path)) {
+        return { color: 'pink', text: '澶栭摼' };
+      }
+      const type = props.data.menuType;
+      if (type === 'M') return { color: 'green', text: '鐩綍' };
+      if (type === 'C') return { color: 'blue', text: '鑿滃崟' };
+      if (type === 'F') return { color: '', text: '鎸夐挳' };
+      return { color: 'error', text: '鏈煡' };
+    });
+
+    return () => (
+      <div class="flex gap-[6px]">
+        <span>{props.data.menuName}</span>
+        <Tag color={menuTagProp.value.color}>{menuTagProp.value.text}</Tag>
+      </div>
+    );
+  },
+});
diff --git a/eims-ui/apps/web-antd/src/views/system/user/data.tsx b/eims-ui/apps/web-antd/src/views/system/user/data.tsx
new file mode 100644
index 0000000..75c510c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/data.tsx
@@ -0,0 +1,206 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'userName',
+    label: '鐢ㄦ埛璐﹀彿',
+  },
+  {
+    component: 'Input',
+    fieldName: 'nickName',
+    label: '鐢ㄦ埛鏄电О',
+  },
+  {
+    component: 'Input',
+    fieldName: 'phonenumber',
+    label: '鎵嬫満鍙风爜',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+    },
+    fieldName: 'status',
+    label: '鐢ㄦ埛鐘舵��',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    field: 'userName',
+    title: '鍚嶇О',
+    minWidth: 80,
+  },
+  {
+    field: 'nickName',
+    title: '鏄电О',
+    minWidth: 130,
+  },
+  {
+    field: 'avatar',
+    title: '澶村儚',
+    slots: { default: 'avatar' },
+    minWidth: 80,
+  },
+  {
+    field: 'deptName',
+    title: '閮ㄩ棬',
+    minWidth: 120,
+  },
+  {
+    field: 'phonenumber',
+    title: '鎵嬫満鍙�',
+    formatter({ cellValue }) {
+      return cellValue || '鏆傛棤';
+    },
+    minWidth: 120,
+  },
+  {
+    field: 'status',
+    title: '鐘舵��',
+    slots: { default: 'status' },
+    minWidth: 100,
+  },
+  {
+    field: 'createTime',
+    title: '鍒涘缓鏃堕棿',
+    minWidth: 150,
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    resizable: false,
+    width: 180,
+  },
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+    fieldName: 'userId',
+  },
+  {
+    component: 'Input',
+    fieldName: 'userName',
+    label: '鐢ㄦ埛璐﹀彿',
+    rules: 'required',
+  },
+  {
+    component: 'InputPassword',
+    fieldName: 'password',
+    label: '鐢ㄦ埛瀵嗙爜',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'nickName',
+    label: '鐢ㄦ埛鏄电О',
+    rules: 'required',
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'deptId',
+    label: '鎵�灞為儴闂�',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Input',
+    fieldName: 'phonenumber',
+    label: '鎵嬫満鍙风爜',
+    defaultValue: undefined,
+    rules: z
+      .string()
+      .regex(/^1[3-9]\d{9}$/, '璇疯緭鍏ユ纭殑鎵嬫満鍙风爜')
+      .optional()
+      .or(z.literal('')),
+  },
+  {
+    component: 'Input',
+    fieldName: 'email',
+    defaultValue: undefined,
+    label: '閭',
+    /**
+     * z.literal 鏄� Zod 涓殑涓�绉嶇被鍨嬶紝鐢ㄤ簬瀹氫箟涓�涓壒瀹氱殑瀛楅潰閲忓�笺��
+     * 瀹冨彲浠ョ敤浜庣‘淇濊緭鍏ョ殑鍊间笌鎸囧畾鐨勫瓧闈㈤噺瀹屽叏鍖归厤銆�
+     * 渚嬪锛屼綘鍙互浣跨敤 z.literal 鏉ョ‘淇濇煇涓瓧娈电殑鍊煎彧鑳芥槸鐗瑰畾鐨勫瓧绗︿覆銆佹暟瀛椼�佸竷灏斿�肩瓑銆�
+     * 鍗崇┖瀛楃涓蹭篃鍙�氳繃鏍¢獙
+     */
+    rules: z.string().email('璇疯緭鍏ユ纭殑閭').optional().or(z.literal('')),
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_USER_SEX),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'sex',
+    formItemClass: 'col-span-2 lg:col-span-1',
+    label: '鎬у埆',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    formItemClass: 'col-span-2 lg:col-span-1',
+    label: '鐘舵��',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      mode: 'multiple',
+      optionFilterProp: 'label',
+      optionLabelProp: 'label',
+      placeholder: '璇峰厛閫夋嫨閮ㄩ棬',
+    },
+    fieldName: 'postIds',
+    help: '閫夋嫨閮ㄩ棬鍚�, 灏嗚嚜鍔ㄥ姞杞借閮ㄩ棬涓嬫墍鏈夌殑宀椾綅',
+    label: '宀椾綅',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      mode: 'multiple',
+      optionFilterProp: 'title',
+      optionLabelProp: 'title',
+    },
+    fieldName: 'roleIds',
+    label: '瑙掕壊',
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/user/dept-tree.vue b/eims-ui/apps/web-antd/src/views/system/user/dept-tree.vue
new file mode 100644
index 0000000..ad7ba42
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/dept-tree.vue
@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import type { DeptTree } from '#/api/system/user/model';
+
+import { onMounted, type PropType, ref } from 'vue';
+
+import { SyncOutlined } from '@ant-design/icons-vue';
+import { Empty, InputSearch, Skeleton, Tree } from 'ant-design-vue';
+
+import { getDeptTree } from '#/api/system/user';
+
+defineOptions({ inheritAttrs: false });
+
+const emit = defineEmits<{
+  /**
+   * 鐐瑰嚮鍒锋柊鎸夐挳鐨勪簨浠�
+   */
+  reload: [];
+  /**
+   * 鐐瑰嚮鑺傜偣鐨勪簨浠�
+   */
+  select: [];
+}>();
+
+const selectDeptId = defineModel('selectDeptId', {
+  required: true,
+  type: Array as PropType<string[]>,
+});
+
+const searchValue = defineModel('searchValue', {
+  type: String,
+  default: '',
+});
+
+/** 閮ㄩ棬鏁版嵁婧� */
+type DeptTreeArray = DeptTree[];
+const deptTreeArray = ref<DeptTreeArray>([]);
+/** 楠ㄦ灦灞忓姞杞� */
+const showTreeSkeleton = ref<boolean>(true);
+
+async function loadTree() {
+  showTreeSkeleton.value = true;
+  searchValue.value = '';
+  selectDeptId.value = [];
+
+  const ret = await getDeptTree();
+
+  deptTreeArray.value = ret;
+  showTreeSkeleton.value = false;
+}
+
+async function handleReload() {
+  await loadTree();
+  emit('reload');
+}
+
+onMounted(loadTree);
+</script>
+
+<template>
+  <div :class="$attrs.class">
+    <Skeleton
+      :loading="showTreeSkeleton"
+      :paragraph="{ rows: 8 }"
+      active
+      class="p-[8px]"
+    >
+      <div
+        class="bg-background flex h-full flex-col overflow-y-auto rounded-lg"
+      >
+        <!-- 鍥哄畾鍦ㄩ《閮� 蹇呴』鍔犱笂bg-background鑳屾櫙鑹� 鍚﹀垯浼氫骇鐢�'绌块��'鏁堟灉 -->
+        <div class="bg-background z-100 sticky left-0 top-0 p-[8px]">
+          <InputSearch
+            v-model:value="searchValue"
+            :placeholder="$t('pages.common.search')"
+            size="small"
+          >
+            <template #enterButton>
+              <a-button @click="handleReload">
+                <SyncOutlined class="text-primary" />
+              </a-button>
+            </template>
+          </InputSearch>
+        </div>
+        <div class="h-full overflow-x-hidden px-[8px]">
+          <Tree
+            v-bind="$attrs"
+            v-if="deptTreeArray.length > 0"
+            v-model:selected-keys="selectDeptId"
+            :class="$attrs.class"
+            :field-names="{ title: 'label', key: 'id' }"
+            :show-line="{ showLeafIcon: false }"
+            :tree-data="deptTreeArray"
+            :virtual="false"
+            default-expand-all
+            @select="$emit('select')"
+          >
+            <template #title="{ label }">
+              <span v-if="label.indexOf(searchValue) > -1">
+                {{ label.substring(0, label.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{
+                  label.substring(
+                    label.indexOf(searchValue) + searchValue.length,
+                  )
+                }}
+              </span>
+              <span v-else>{{ label }}</span>
+            </template>
+          </Tree>
+          <!-- 浠呮湰浜烘暟鎹潈闄� 鍙互鑰冭檻鐩存帴涓嶆樉绀� -->
+          <div v-else class="mt-5">
+            <Empty
+              :image="Empty.PRESENTED_IMAGE_SIMPLE"
+              description="鏃犻儴闂ㄦ暟鎹�"
+            />
+          </div>
+        </div>
+      </div>
+    </Skeleton>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/user/index.vue b/eims-ui/apps/web-antd/src/views/system/user/index.vue
new file mode 100644
index 0000000..24b0ed1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/index.vue
@@ -0,0 +1,299 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+
+import { useAccess } from '@vben/access';
+import {
+  Page,
+  useVbenDrawer,
+  useVbenModal,
+  type VbenFormProps,
+} from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { preferences } from '@vben/preferences';
+import { getVxePopupContainer } from '@vben/utils';
+
+import {
+  Avatar,
+  Dropdown,
+  Menu,
+  MenuItem,
+  Modal,
+  Popconfirm,
+  Space,
+} from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { vxeCheckboxChecked } from '#/adapter/vxe-table';
+import {
+  userExport,
+  userList,
+  userRemove,
+  userStatusChange,
+} from '#/api/system/user';
+import { TableSwitch } from '#/components/table';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import DeptTree from './dept-tree.vue';
+import userDrawer from './user-drawer.vue';
+import userImportModal from './user-import-modal.vue';
+import userInfoModal from './user-info-modal.vue';
+import userResetPwdModal from './user-reset-pwd-modal.vue';
+
+/**
+ * 瀵煎叆
+ */
+const [UserImpotModal, userImportModalApi] = useVbenModal({
+  connectedComponent: userImportModal,
+});
+
+function handleImport() {
+  userImportModalApi.open();
+}
+
+// 宸﹁竟閮ㄩ棬鐢�
+const selectDeptId = ref<string[]>([]);
+
+const formOptions: VbenFormProps = {
+  schema: querySchema(),
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  handleReset: async () => {
+    selectDeptId.value = [];
+    // eslint-disable-next-line no-use-before-define
+    const { formApi, reload } = tableApi;
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    await reload(formValues);
+  },
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    trigger: 'default',
+    checkMethod: ({ row }) => row?.userId !== 1,
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectDeptId.value.length === 1) {
+          formValues.deptId = selectDeptId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'deptId');
+        }
+
+        return await userList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'userId',
+    height: 48,
+  },
+  id: 'system-user-index',
+};
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+const [UserDrawer, userDrawerApi] = useVbenDrawer({
+  connectedComponent: userDrawer,
+});
+
+function handleAdd() {
+  userDrawerApi.setData({});
+  userDrawerApi.open();
+}
+
+function handleEdit(row: Recordable<any>) {
+  userDrawerApi.setData({ id: row.userId });
+  userDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await userRemove(row.userId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.userId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await userRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(userExport, '鐢ㄦ埛绠$悊', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime,
+  });
+}
+
+const [UserInfoModal, userInfoModalApi] = useVbenModal({
+  connectedComponent: userInfoModal,
+});
+function handleUserInfo(row: Recordable<any>) {
+  userInfoModalApi.setData({ userId: row.userId });
+  userInfoModalApi.open();
+}
+
+const [UserResetPwdModal, userResetPwdModalApi] = useVbenModal({
+  connectedComponent: userResetPwdModal,
+});
+
+function handleResetPwd(record: Recordable<any>) {
+  userResetPwdModalApi.setData({ record });
+  userResetPwdModalApi.open();
+}
+
+const { hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <DeptTree
+        v-model:select-dept-id="selectDeptId"
+        class="w-[260px]"
+        @reload="() => tableApi.reload()"
+        @select="() => tableApi.reload()"
+      />
+      <BasicTable class="flex-1 overflow-hidden" table-title="鐢ㄦ埛鍒楄〃">
+        <template #toolbar-tools>
+          <Space>
+            <a-button
+              v-access:code="['system:user:export']"
+              @click="handleDownloadExcel"
+            >
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              v-access:code="['system:user:import']"
+              @click="handleImport"
+            >
+              {{ $t('pages.common.import') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['system:user:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button
+              type="primary"
+              v-access:code="['system:user:add']"
+              @click="handleAdd"
+            >
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+        <template #avatar="{ row }">
+          <!-- 鍙兘瑕佸垽鏂┖瀛楃涓叉儏鍐� 鎵�浠ユ病鏈変娇鐢�?? -->
+          <Avatar :src="row.avatar || preferences.app.defaultAvatar" />
+        </template>
+        <template #status="{ row }">
+          <TableSwitch
+            v-model="row.status"
+            :api="() => userStatusChange(row)"
+            :disabled="
+              row.userId === 1 || !hasAccessByCodes(['system:user:edit'])
+            "
+            :reload="() => tableApi.query()"
+          />
+        </template>
+        <template #action="{ row }">
+          <template v-if="row.userId !== 1">
+            <Space>
+              <ghost-button
+                v-access:code="['system:user:edit']"
+                @click.stop="handleEdit(row)"
+              >
+                {{ $t('pages.common.edit') }}
+              </ghost-button>
+              <Popconfirm
+                :get-popup-container="getVxePopupContainer"
+                placement="left"
+                title="纭鍒犻櫎锛�"
+                @confirm="handleDelete(row)"
+              >
+                <ghost-button
+                  danger
+                  v-access:code="['system:user:remove']"
+                  @click.stop=""
+                >
+                  {{ $t('pages.common.delete') }}
+                </ghost-button>
+              </Popconfirm>
+            </Space>
+            <Dropdown
+              :get-popup-container="getVxePopupContainer"
+              placement="bottomRight"
+            >
+              <template #overlay>
+                <Menu>
+                  <MenuItem key="1" @click="handleUserInfo(row)">
+                    鐢ㄦ埛淇℃伅
+                  </MenuItem>
+                  <span v-access:code="['system:user:resetPwd']">
+                    <MenuItem key="2" @click="handleResetPwd(row)">
+                      閲嶇疆瀵嗙爜
+                    </MenuItem>
+                  </span>
+                </Menu>
+              </template>
+              <a-button size="small" type="link">
+                {{ $t('pages.common.more') }}
+              </a-button>
+            </Dropdown>
+          </template>
+        </template>
+      </BasicTable>
+    </div>
+    <UserImpotModal @reload="tableApi.query()" />
+    <UserDrawer @reload="tableApi.query()" />
+    <UserInfoModal />
+    <UserResetPwdModal />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/user/info.tsx b/eims-ui/apps/web-antd/src/views/system/user/info.tsx
new file mode 100644
index 0000000..cd00bb8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/info.tsx
@@ -0,0 +1,129 @@
+import type { DescItem } from '#/components/description';
+
+import { DictEnum } from '@vben/constants';
+
+import { Tag } from 'ant-design-vue';
+import dayjs from 'dayjs';
+import duration from 'dayjs/plugin/duration';
+import relativeTime from 'dayjs/plugin/relativeTime';
+
+import { renderDict } from '#/utils/render';
+
+dayjs.extend(duration);
+dayjs.extend(relativeTime);
+
+function renderTags(list: string[]) {
+  return (
+    <div class="flex flex-row flex-wrap gap-0.5">
+      {list.map((item) => (
+        <Tag key={item}>{item}</Tag>
+      ))}
+    </div>
+  );
+}
+
+export const descSchema: DescItem[] = [
+  {
+    field: 'userId',
+    label: '鐢ㄦ埛ID',
+  },
+  {
+    field: 'status',
+    label: '鐢ㄦ埛鐘舵��',
+    render(value) {
+      return renderDict(value, DictEnum.SYS_NORMAL_DISABLE);
+    },
+  },
+  {
+    field: 'nickName',
+    label: '鐢ㄦ埛淇℃伅',
+    render(_, data) {
+      const { deptName = '鏆傛棤閮ㄩ棬淇℃伅', nickName, userName } = data;
+      // 涓轰簡鍏煎鏂扮増鏈拰鏃х増鏈�
+      let currentDept = deptName;
+      if (data.dept && data.dept.deptName) {
+        currentDept = data.dept.deptName;
+      }
+      return `${userName} / ${nickName} / ${currentDept}`;
+    },
+  },
+  {
+    field: 'phonenumber',
+    label: '鎵嬫満鍙�',
+    render(value) {
+      return value || '鏈缃墜鏈哄彿鐮�';
+    },
+  },
+  {
+    field: 'email',
+    label: '閭',
+    render(value) {
+      return value || '鏈缃偖绠卞湴鍧�';
+    },
+  },
+  {
+    field: 'postNames',
+    label: '宀椾綅',
+    render(value) {
+      if (Array.isArray(value) && value.length === 0) {
+        return '鏆傛棤淇℃伅';
+      }
+      return renderTags(value);
+    },
+  },
+  {
+    field: 'roleNames',
+    label: '鏉冮檺',
+    render(value) {
+      if (Array.isArray(value) && value.length === 0) {
+        return '鏆傛棤淇℃伅';
+      }
+      return renderTags(value);
+    },
+  },
+  {
+    field: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+  {
+    field: 'loginIp',
+    label: '涓婃鐧诲綍IP',
+    render(value) {
+      return value || <span class="text-orange-500">浠庢湭鐧诲綍杩�</span>;
+    },
+  },
+  {
+    field: 'loginDate',
+    label: '涓婃鐧诲綍鏃堕棿',
+    render(value) {
+      if (!value) {
+        return <span class="text-orange-500">浠庢湭鐧诲綍杩�</span>;
+      }
+      // 榛樿en鏄剧ず
+      dayjs.locale('zh-cn');
+      // 璁$畻鐩稿樊绉掓暟
+      const diffSeconds = dayjs().diff(dayjs(value), 'second');
+      /**
+       * 杞负鏃堕棿鏄剧ず(x鏈� x澶�)
+       * https://dayjs.fenxianglu.cn/category/duration.html#%E4%BA%BA%E6%80%A7%E5%8C%96
+       *
+       */
+      const diffText = dayjs.duration(diffSeconds, 'seconds').humanize();
+      return (
+        <div class="flex gap-2">
+          {value}
+          <Tag bordered={false} color="cyan">
+            {diffText}鍓�
+          </Tag>
+        </div>
+      );
+    },
+  },
+  {
+    field: 'remark',
+    label: '澶囨敞',
+    render(value) {
+      return value || '鏃�';
+    },
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/system/user/user-drawer.vue b/eims-ui/apps/web-antd/src/views/system/user/user-drawer.vue
new file mode 100644
index 0000000..0b37459
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/user-drawer.vue
@@ -0,0 +1,227 @@
+<script setup lang="ts">
+import type { Role } from '#/api/system/user/model';
+
+import { computed, h, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
+
+import { Tag } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+import { configInfoByKey } from '#/api/system/config';
+import { postOptionSelect } from '#/api/system/post';
+import {
+  findUserInfo,
+  getDeptTree,
+  userAdd,
+  userUpdate,
+} from '#/api/system/user';
+import { authScopeOptions } from '#/views/system/role/data';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full',
+    },
+    labelWidth: 80,
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+/**
+ * 鐢熸垚瑙掕壊鐨勮嚜瀹氫箟label
+ * 涔熷彲浠ョ敤option鎻掓Ы鏉ュ仛
+ * renderComponentContent: () => ({
+    option: ({value, label, [disabled, key, title]}) => '',
+  }),
+ */
+function genRoleOptionlabel(role: Role) {
+  const found = authScopeOptions.find((item) => item.value === role.dataScope);
+  if (!found) {
+    return role.roleName;
+  }
+  return h('div', { class: 'flex items-center gap-[6px]' }, [
+    h('span', null, role.roleName),
+    h(Tag, { color: found.color }, () => found.label),
+  ]);
+}
+
+/**
+ * 宀椾綅鐨勫姞杞�
+ */
+async function setupPostOptions(deptId: number | string) {
+  const postListResp = await postOptionSelect(deptId);
+  const options = postListResp.map((item) => ({
+    label: item.postName,
+    value: item.postId,
+  }));
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤宀椾綅';
+  formApi.updateSchema([
+    {
+      componentProps: { options, placeholder },
+      fieldName: 'postIds',
+    },
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children',
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇宀椾綅 */
+          await setupPostOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨宀椾綅 */
+          formModel.postIds = [];
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName',
+      }),
+      fieldName: 'deptId',
+    },
+  ]);
+}
+
+/**
+ * 鏂板鏃跺�� 浠庡弬鏁拌缃幏鍙栭粯璁ゅ瘑鐮�
+ */
+async function loadDefaultPassword(update: boolean) {
+  if (!update) {
+    const defaultPassword = await configInfoByKey('sys.user.initPassword');
+    defaultPassword && formApi.setFieldValue('password', defaultPassword);
+  }
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      // 闇�瑕侀噸缃矖浣嶉�夋嫨
+      formApi.updateSchema([
+        {
+          componentProps: { options: [], placeholder: '璇峰厛閫夋嫨閮ㄩ棬' },
+          fieldName: 'postIds',
+        },
+      ]);
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    /** update鏃� 绂佺敤鐢ㄦ埛鍚嶄慨鏀� 涓嶆樉绀哄瘑鐮佹 */
+    formApi.updateSchema([
+      { componentProps: { disabled: isUpdate.value }, fieldName: 'userName' },
+      {
+        dependencies: { show: () => !isUpdate.value, triggerFields: ['id'] },
+        fieldName: 'password',
+      },
+    ]);
+    // 鏇存柊 && 璧嬪��
+    const { postIds, posts, roleIds, roles, user } = await findUserInfo(id);
+    const postOptions = (posts ?? []).map((item) => ({
+      label: item.postName,
+      value: item.postId,
+    }));
+    formApi.updateSchema([
+      {
+        componentProps: {
+          // title鐢ㄤ簬閫変腑鍚庡洖濉埌杈撳叆妗� 榛樿涓簂abel
+          optionLabelProp: 'title',
+          options: roles.map((item) => ({
+            label: genRoleOptionlabel(item),
+            // title鐢ㄤ簬閫変腑鍚庡洖濉埌杈撳叆妗� 榛樿涓簂abel
+            title: item.roleName,
+            value: item.roleId,
+          })),
+        },
+        fieldName: 'roleIds',
+      },
+      {
+        componentProps: {
+          options: postOptions,
+        },
+        fieldName: 'postIds',
+      },
+    ]);
+    // 閮ㄩ棬閫夋嫨 && 鍒濆瀵嗙爜
+    await Promise.all([setupDeptSelect(), loadDefaultPassword(isUpdate.value)]);
+    if (user) {
+      await Promise.all([
+        // 娣诲姞鍩虹淇℃伅
+        formApi.setValues(user),
+        // 娣诲姞瑙掕壊鍜屽矖浣�
+        formApi.setFieldValue('postIds', postIds),
+        formApi.setFieldValue('roleIds', roleIds),
+        // 鏇存柊鏃朵笉浼氳Е鍙憃nSelect 闇�瑕佹墜鍔ㄨ皟鐢�
+        setupPostOptions(user.deptId),
+      ]);
+    }
+    drawerApi.drawerLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? userUpdate(data) : userAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/user/user-import-modal.vue b/eims-ui/apps/web-antd/src/views/system/user/user-import-modal.vue
new file mode 100644
index 0000000..fe81465
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/user-import-modal.vue
@@ -0,0 +1,108 @@
+<script setup lang="ts">
+import type { UploadFile } from 'ant-design-vue/es/upload/interface';
+
+import { h, ref, unref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { ExcelIcon, InBoxIcon } from '@vben/icons';
+
+import { Modal, Switch, Upload } from 'ant-design-vue';
+
+import { downloadImportTemplate, userImportData } from '#/api/system/user';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const UploadDragger = Upload.Dragger;
+
+const [BasicModal, modalApi] = useVbenModal({
+  onCancel: handleCancel,
+  onConfirm: handleSubmit,
+});
+
+const fileList = ref<UploadFile[]>([]);
+const checked = ref(false);
+
+async function handleSubmit() {
+  try {
+    modalApi.modalLoading(true);
+    if (fileList.value.length !== 1) {
+      handleCancel();
+      return;
+    }
+    const data = {
+      file: fileList.value[0]!.originFileObj as Blob,
+      updateSupport: unref(checked),
+    };
+    const { code, msg } = await userImportData(data);
+    let modal = Modal.success;
+    if (code === 200) {
+      emit('reload');
+    } else {
+      modal = Modal.error;
+    }
+    handleCancel();
+    modal({
+      content: h('div', {
+        class: 'max-h-[260px] overflow-y-auto',
+        innerHTML: msg, // 鍚庡彴宸茬粡澶勭悊xss闂
+      }),
+      title: '鎻愮ず',
+    });
+  } catch (error) {
+    console.warn(error);
+    modalApi.close();
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+function handleCancel() {
+  modalApi.close();
+  fileList.value = [];
+  checked.value = false;
+}
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :fullscreen-button="false"
+    title="鐢ㄦ埛瀵煎叆"
+  >
+    <!-- z-index涓嶈缃細閬尅妯℃澘涓嬭浇loading -->
+    <!-- 鎵嬪姩澶勭悊 鑰屼笉鏄斁鍏ユ枃浠跺氨涓婁紶 -->
+    <UploadDragger
+      v-model:file-list="fileList"
+      :before-upload="() => false"
+      :max-count="1"
+      :show-upload-list="true"
+      accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
+    >
+      <p class="ant-upload-drag-icon flex items-center justify-center">
+        <InBoxIcon class="text-primary size-[48px]" />
+      </p>
+      <p class="ant-upload-text">鐐瑰嚮鎴栬�呮嫋鎷藉埌姝ゅ涓婁紶鏂囦欢</p>
+    </UploadDragger>
+    <div class="mt-2 flex flex-col gap-2">
+      <div class="flex items-center gap-2">
+        <span>鍏佽瀵煎叆xlsx, xls鏂囦欢</span>
+        <a-button
+          type="link"
+          @click="commonDownloadExcel(downloadImportTemplate, '鐢ㄦ埛瀵煎叆妯℃澘')"
+        >
+          <div class="flex items-center gap-[4px]">
+            <ExcelIcon />
+            <span>涓嬭浇妯℃澘</span>
+          </div>
+        </a-button>
+      </div>
+      <div class="flex items-center gap-2">
+        <span :class="{ 'text-red-500': checked }">
+          鏄惁鏇存柊/瑕嗙洊宸插瓨鍦ㄧ殑鐢ㄦ埛鏁版嵁
+        </span>
+        <Switch v-model:checked="checked" />
+      </div>
+    </div>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/user/user-info-modal.vue b/eims-ui/apps/web-antd/src/views/system/user/user-info-modal.vue
new file mode 100644
index 0000000..80a917e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/user-info-modal.vue
@@ -0,0 +1,56 @@
+<script setup lang="ts">
+import { useVbenModal } from '@vben/common-ui';
+
+import { findUserInfo } from '#/api/system/user';
+import { Description, useDescription } from '#/components/description';
+
+import { descSchema } from './info';
+
+const [BasicModal, modalApi] = useVbenModal({
+  onOpenChange: handleOpenChange,
+});
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: 1,
+  labelStyle: {
+    minWidth: '150px',
+    width: '150px',
+  },
+  schema: descSchema,
+});
+
+async function handleOpenChange(open: boolean) {
+  if (!open) {
+    return null;
+  }
+  modalApi.modalLoading(true);
+
+  const { userId } = modalApi.getData() as { userId: number | string };
+  const response = await findUserInfo(userId);
+  // 澶栭儴鐨剅oleIds postIds鎵嶆槸鐪熸瀵瑰簲鐨�  鏂板鏃朵负绌�
+  // posts鏈変负Null鐨勬儏鍐� 闇�瑕佺粰榛樿鍊�
+  const { postIds = [], posts = [], roleIds = [], roles = [], user } = response;
+
+  const postNames = posts
+    .filter((item) => postIds.includes(item.postId))
+    .map((item) => item.postName);
+
+  const roleNames = roles
+    .filter((item) => roleIds.includes(item.roleId))
+    .map((item) => item.roleName);
+
+  (user as any).postNames = postNames;
+  (user as any).roleNames = roleNames;
+
+  // 璧嬪��
+  setDescProps({ data: user });
+
+  modalApi.modalLoading(false);
+}
+</script>
+
+<template>
+  <BasicModal :footer="false" :fullscreen-button="false" title="鐢ㄦ埛淇℃伅">
+    <Description @register="registerDescription" />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/system/user/user-reset-pwd-modal.vue b/eims-ui/apps/web-antd/src/views/system/user/user-reset-pwd-modal.vue
new file mode 100644
index 0000000..f0e55fc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/system/user/user-reset-pwd-modal.vue
@@ -0,0 +1,111 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { useVbenModal, z } from '@vben/common-ui';
+
+import { useVbenForm } from '#/adapter/form';
+import { userResetPassword } from '#/api/system/user';
+import { Description, useDescription } from '#/components/description';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const [BasicModal, modalApi] = useVbenModal({
+  onCancel: handleCancel,
+  onConfirm: handleSubmit,
+  onOpenChange: handleOpenChange,
+});
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: 1,
+  schema: [
+    {
+      field: 'userId',
+      label: '鐢ㄦ埛ID',
+    },
+    {
+      field: 'userName',
+      label: '鐢ㄦ埛鍚�',
+    },
+    {
+      field: 'nickName',
+      label: '鏄电О',
+    },
+  ],
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  schema: [
+    {
+      component: 'Input',
+      dependencies: {
+        show: () => false,
+        triggerFields: [''],
+      },
+      fieldName: 'userId',
+      label: '鐢ㄦ埛ID',
+      rules: 'required',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏ユ柊鐨勫瘑鐮�, 瀵嗙爜闀垮害涓�5 - 20',
+      },
+      fieldName: 'password',
+      label: '鏂扮殑瀵嗙爜',
+      rules: z
+        .string()
+        .min(5, { message: '瀵嗙爜闀垮害涓�5 - 20' })
+        .max(20, { message: '瀵嗙爜闀垮害涓�5 - 20' }),
+    },
+  ],
+  showDefaultActions: false,
+  commonConfig: {
+    labelWidth: 80,
+  },
+});
+
+async function handleOpenChange(open: boolean) {
+  if (!open) {
+    return null;
+  }
+  const { record } = modalApi.getData() as { record: Recordable<any> };
+  setDescProps({ data: record }, true);
+  await formApi.setValues({ userId: record.userId });
+}
+
+async function handleSubmit() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = await formApi.getValues();
+    await userResetPassword(data as any);
+    emit('reload');
+    handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :fullscreen-button="false"
+    title="閲嶇疆瀵嗙爜"
+  >
+    <div class="flex flex-col gap-[12px]">
+      <Description @register="registerDescription" />
+      <BasicForm />
+    </div>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/code-preview-modal.vue b/eims-ui/apps/web-antd/src/views/tool/gen/code-preview-modal.vue
new file mode 100644
index 0000000..aaaa333
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/code-preview-modal.vue
@@ -0,0 +1,213 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+import type { Key } from 'ant-design-vue/es/vc-tree/interface';
+
+import { type Component, markRaw, ref } from 'vue';
+
+import {
+  CodeMirror,
+  type LanguageSupport,
+  useVbenModal,
+} from '@vben/common-ui';
+import {
+  DefaultFileIcon,
+  FolderIcon,
+  JavaIcon,
+  SqlIcon,
+  TsIcon,
+  VueIcon,
+  XmlIcon,
+} from '@vben/icons';
+
+import { useClipboard } from '@vueuse/core';
+import { Skeleton, Tree } from 'ant-design-vue';
+
+import { previewCode } from '#/api/tool/gen';
+
+interface TreeNode {
+  children: TreeNode[];
+  title: string;
+  key: string;
+  icon: Component; // 鏍戝乏杈瑰浘鏍�
+}
+
+const treeData = ref<TreeNode[]>([]);
+/** modal鏍囬 */
+const modalTitle = ref('浠g爜棰勮');
+/** 浠g爜鍐呭 */
+const codeContent = ref('鐐瑰嚮宸︿晶鏍戣妭鐐规煡鐪嬩唬鐮�');
+/** code */
+const currentCodeData = ref<null | Recordable<any>>(null);
+
+const [BasicModal, modalApi] = useVbenModal({
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      handleClose();
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { tableId } = modalApi.getData() as { tableId: string };
+    const data = await previewCode(tableId);
+    currentCodeData.value = data;
+    const tree = convertToTree(Object.keys(data));
+    treeData.value = tree;
+
+    modalApi.modalLoading(false);
+  },
+});
+
+/**
+ * 鏂囦欢璺緞鏁扮粍杞爲缁撴瀯
+ * @param paths 鏂囦欢璺緞鏁扮粍
+ */
+function convertToTree(paths: string[]): TreeNode[] {
+  const tree: TreeNode[] = [];
+
+  for (const path of paths) {
+    const segments = path.split('/');
+    let currentNode = tree;
+    let currentPath = '';
+
+    for (let i = 0; i < segments.length; i++) {
+      const segment = segments[i];
+      currentPath += `${segment}`;
+      if (i !== segments.length - 1) {
+        currentPath += '/';
+      }
+
+      const existingNode = currentNode.find((node) => node.title === segment);
+
+      if (existingNode) {
+        currentNode = existingNode.children || [];
+      } else {
+        const title = (segment ?? '').replace('.vm', '');
+        const newNode: TreeNode = {
+          icon: findIcon(currentPath),
+          key: currentPath,
+          title,
+          children: [],
+        };
+        currentNode.push(newNode);
+        currentNode = newNode.children;
+      }
+    }
+  }
+
+  return tree;
+}
+
+const iconMap = [
+  { key: 'java', value: markRaw(JavaIcon) },
+  { key: 'xml', value: markRaw(XmlIcon) },
+  { key: 'sql', value: markRaw(SqlIcon) },
+  { key: 'ts', value: markRaw(TsIcon) },
+  { key: 'vue', value: markRaw(VueIcon) },
+  { key: 'folder', value: markRaw(FolderIcon) },
+];
+function findIcon(path: string) {
+  const defaultFileIcon = DefaultFileIcon;
+  const defaultFolderIcon = FolderIcon;
+  if (path.endsWith('.vm')) {
+    const realPath = path.slice(0, -3);
+    // 鏄惁涓烘寚瀹氭嫇灞曞悕
+    const icon = iconMap.find((item) => realPath.endsWith(item.key));
+    if (icon) {
+      return icon.value;
+    }
+    return defaultFileIcon;
+  }
+  // 鍏朵粬鐨勪负鏂囦欢澶�
+  return defaultFolderIcon;
+}
+
+const language = ref<LanguageSupport>('html');
+function changeLanguageType(filename: string) {
+  const typeList: { language: LanguageSupport; type: string }[] = [
+    { language: 'ts', type: '.ts' },
+    { language: 'java', type: '.java' },
+    { language: 'xml', type: '.xml' },
+    { language: 'sql', type: 'sql' },
+    { language: 'vue', type: '.vue' },
+  ];
+  const type = typeList.find((item) => filename.includes(item.type));
+  language.value = type ? type.language : 'html';
+}
+
+function handleSelect(selectedKeys: Key[]) {
+  const [currentFile = ''] = selectedKeys as string[];
+  if (!currentCodeData.value) {
+    return;
+  }
+  const currentCode =
+    currentCodeData.value[currentFile as keyof typeof currentCodeData.value];
+  if (currentCode) {
+    // 璁剧疆浠g爜type
+    changeLanguageType(currentFile);
+    // 鍐呭
+    codeContent.value = currentCode;
+    // 淇敼鏍囬
+    modalTitle.value = `浠g爜棰勮: ${currentFile.replace('.vm', '')}`;
+  }
+}
+
+function handleClose() {
+  currentCodeData.value = null;
+  codeContent.value = '鐐瑰嚮宸︿晶鏍戣妭鐐规煡鐪嬩唬鐮�';
+  modalTitle.value = '浠g爜棰勮';
+  language.value = 'html';
+}
+
+const { copy } = useClipboard({ legacy: true });
+</script>
+
+<template>
+  <BasicModal
+    :footer="false"
+    :fullscreen="true"
+    :fullscreen-button="false"
+    :title="modalTitle"
+  >
+    <div v-if="currentCodeData" class="flex gap-[8px]">
+      <div class="h-[calc(100vh-80px)] w-[300px] overflow-y-scroll">
+        <Tree
+          v-if="treeData.length > 0"
+          :show-line="{ showLeafIcon: false }"
+          :tree-data="treeData"
+          :virtual="false"
+          default-expand-all
+          @select="handleSelect"
+        >
+          <template #title="{ title, icon }">
+            <div class="flex items-center gap-[16px]">
+              <component :is="icon" />
+              <span>{{ title }}</span>
+            </div>
+          </template>
+        </Tree>
+      </div>
+      <CodeMirror
+        v-model="codeContent"
+        :language="language"
+        class="h-[calc(100vh-80px)] w-full overflow-y-scroll text-[16px]"
+        readonly
+      />
+      <div class="fixed right-20 top-20">
+        <a-button @click="copy(codeContent)">澶嶅埗</a-button>
+      </div>
+    </div>
+    <Skeleton v-if="!currentCodeData" active />
+  </BasicModal>
+</template>
+
+<style lang="scss" scoped>
+:deep(.ant-tree .ant-tree-switcher) {
+  display: flex;
+  align-items: center;
+}
+
+/** codeMirror 鍗犳弧瀹瑰櫒楂樺害 鍗砪alc璁$畻鐨勯珮搴� */
+:deep(.cm-editor) {
+  height: 100%;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/data.tsx b/eims-ui/apps/web-antd/src/views/tool/gen/data.tsx
new file mode 100644
index 0000000..ecb25e2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/data.tsx
@@ -0,0 +1,61 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Select',
+    fieldName: 'dataName',
+    label: '鏁版嵁婧�',
+    defaultValue: '',
+    componentProps: {
+      allowClear: false,
+    },
+  },
+  {
+    component: 'Input',
+    fieldName: 'tableName',
+    label: '琛ㄥ悕绉�',
+  },
+  {
+    component: 'Input',
+    fieldName: 'tableComment',
+    label: '琛ㄦ弿杩�',
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'createTime',
+    label: '鍒涘缓鏃堕棿',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60 },
+  {
+    field: 'tableName',
+    title: '琛ㄥ悕绉�',
+  },
+  {
+    field: 'tableComment',
+    title: '琛ㄦ弿杩�',
+  },
+  {
+    field: 'className',
+    title: '瀹炰綋绫�',
+  },
+  {
+    field: 'createTime',
+    title: '鍒涘缓鏃堕棿',
+  },
+  {
+    field: 'updateTime',
+    title: '鏇存柊鏃堕棿',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 300,
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-gen.vue b/eims-ui/apps/web-antd/src/views/tool/gen/edit-gen.vue
new file mode 100644
index 0000000..6045def
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-gen.vue
@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import type { GenInfo } from '#/api/tool/gen/model';
+
+import { onMounted, provide, ref } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { Page } from '@vben/common-ui';
+import { useTabs } from '@vben/hooks';
+import { safeParseNumber } from '@vben/utils';
+
+import { Skeleton, Step, Steps } from 'ant-design-vue';
+
+import { genInfo } from '#/api/tool/gen';
+
+import { BasicSetting, GenConfig, GenSuccess } from './edit-steps';
+import { emitter } from './mitt';
+
+const current = ref(0);
+
+const { setTabTitle } = useTabs();
+const routes = useRoute();
+// 鑾峰彇璺敱鍙傛暟
+const tableId = routes.params.tableId as string;
+
+const genInfoData = ref<GenInfo['info']>();
+
+provide('genInfoData', genInfoData);
+
+onMounted(async () => {
+  const resp = await genInfo(tableId);
+  // 闇�瑕佸仛鑿滃崟杞崲 涓ユ牸鐩哥瓑 鎵嶈兘閫変腑鍥炴樉
+  resp.info.parentMenuId = safeParseNumber(resp.info.parentMenuId);
+  genInfoData.value = resp.info;
+  setTabTitle(`鐢熸垚閰嶇疆: ${resp.info.tableName}`);
+});
+
+/**
+ * 浜嬩欢鎬荤嚎 鐩戝惉鍒囨崲姝ラ
+ */
+emitter.on('to', (step: number) => {
+  current.value = step;
+});
+</script>
+
+<template>
+  <Page content-class="bg-background p-5 rounded-lg">
+    <div class="flex items-center justify-center">
+      <Steps :current="current" class="w-fit">
+        <Step title="鐢熸垚淇℃伅" />
+        <Step disabled title="瀛楁淇℃伅" />
+        <Step disabled title="瀹屾垚" />
+      </Steps>
+    </div>
+    <!-- content -->
+    <div v-if="genInfoData">
+      <BasicSetting v-if="current === 0" />
+      <GenConfig v-if="current === 1" />
+      <GenSuccess v-if="current === 2" />
+    </div>
+    <Skeleton v-else :active="true" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic-setting.vue b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic-setting.vue
new file mode 100644
index 0000000..76bef79
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic-setting.vue
@@ -0,0 +1,143 @@
+<script setup lang="ts">
+import type { Column, GenInfo } from '#/api/tool/gen/model';
+
+import { inject, onMounted, type Ref } from 'vue';
+
+import { useVbenForm } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, listToTree } from '@vben/utils';
+
+import { Col, Row } from 'ant-design-vue';
+
+import { menuList } from '#/api/system/menu';
+
+import { toCurrentStep } from '../mitt';
+import { formSchema } from './basic';
+
+/**
+ * 浠庣埗缁勪欢娉ㄥ叆
+ */
+const genInfoData = inject('genInfoData') as Ref<GenInfo['info']>;
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+      formItemClass: 'col-span-1',
+    },
+    labelWidth: 150,
+  },
+  schema: formSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+/**
+ * 鏍戣〃闇�瑕佺敤鍒扮殑鏁版嵁
+ */
+async function initTreeSelect(columns: Column[]) {
+  const options = columns.map((item) => {
+    const label = `${item.columnName} | ${item.columnComment}`;
+    return { label, value: item.columnName };
+  });
+  formApi.updateSchema([
+    {
+      componentProps: {
+        options,
+      },
+      fieldName: 'treeCode',
+    },
+    {
+      componentProps: {
+        options,
+      },
+      fieldName: 'treeParentCode',
+    },
+    {
+      componentProps: {
+        options,
+      },
+      fieldName: 'treeName',
+    },
+  ]);
+}
+
+/**
+ * 鍔犺浇鑿滃崟閫夋嫨
+ */
+async function initMenuSelect() {
+  const list = await menuList();
+  // support i18n
+  list.forEach((item) => {
+    item.menuName = $t(item.menuName);
+  });
+  const tree = listToTree(list, { id: 'menuId', pid: 'parentId' });
+  const treeData = [
+    {
+      fullName: $t('menu.root'),
+      menuId: 0,
+      menuName: $t('menu.root'),
+      children: tree,
+    },
+  ];
+  addFullName(treeData, 'menuName', ' / ');
+
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'menuName',
+          value: 'menuId',
+        },
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        treeData,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        treeNodeLabelProp: 'fullName',
+      },
+      fieldName: 'parentMenuId',
+    },
+  ]);
+}
+
+onMounted(async () => {
+  const info = genInfoData.value;
+  await formApi.setValues(info);
+  // 寮瑰嚭妗嗙被鍨嬮渶瑕佹墜鍔ㄨ祴鍊�
+  if (info.options) {
+    const popupComponent = JSON.parse(info.options)?.popupComponent;
+    if (popupComponent) {
+      await formApi.setFieldValue('popupComponent', popupComponent);
+    }
+  }
+  await Promise.all([initTreeSelect(info.columns), initMenuSelect()]);
+});
+
+async function handleNext() {
+  try {
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return null;
+    }
+    const data = await formApi.getValues();
+    Object.assign(genInfoData.value, data);
+    toCurrentStep(1);
+  } catch (error) {
+    console.error(error);
+  }
+}
+</script>
+
+<template>
+  <Row justify="center">
+    <Col v-bind="{ xs: 24, sm: 24, md: 20, lg: 16, xl: 16 }">
+      <BasicForm />
+      <div class="flex justify-center">
+        <a-button type="primary" @click="handleNext">涓嬩竴姝�</a-button>
+      </div>
+    </Col>
+  </Row>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic.tsx b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic.tsx
new file mode 100644
index 0000000..60a9d41
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/basic.tsx
@@ -0,0 +1,195 @@
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter, z } from '#/adapter/form';
+
+export const formSchema: FormSchemaGetter = () => [
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'left',
+    },
+    fieldName: 'divider1',
+    formItemClass: 'col-span-2',
+    label: '鍩烘湰淇℃伅',
+  },
+  {
+    component: 'Input',
+    fieldName: 'tableName',
+    label: '琛ㄥ悕绉�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'tableComment',
+    label: '琛ㄦ弿杩�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'className',
+    label: '瀹炰綋绫诲悕绉�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'functionAuthor',
+    label: '浣滆��',
+    rules: 'required',
+  },
+  {
+    component: 'Divider',
+    componentProps: {
+      orientation: 'left',
+    },
+    fieldName: 'divider2',
+    formItemClass: 'col-span-2',
+    label: '鐢熸垚淇℃伅',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+      getPopupContainer,
+      options: [
+        { label: '鍗曡〃(澧炲垹鏀规煡)', value: 'crud' },
+        { label: '鏍戣〃(澧炲垹鏀规煡)', value: 'tree' },
+      ],
+    },
+    defaultValue: 'crud',
+    fieldName: 'tplCategory',
+    label: '妯℃澘绫诲瀷',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+    },
+    dependencies: {
+      show: (values) => values.tplCategory === 'tree',
+      triggerFields: ['tplCategory'],
+    },
+    fieldName: 'treeCode',
+    helpMessage: '鏍戣妭鐐规樉绀虹殑缂栫爜瀛楁鍚嶏紝 濡�: dept_id (鐩稿綋浜巌d)',
+    label: '鏍戠紪鐮佸瓧娈�',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+    },
+    dependencies: {
+      show: (values) => values.tplCategory === 'tree',
+      triggerFields: ['tplCategory'],
+    },
+    fieldName: 'treeParentCode',
+    help: '鏍戣妭鐐规樉绀虹殑鐖剁紪鐮佸瓧娈靛悕锛� 濡�: parent_Id (鐩稿綋浜巔arentId)',
+    label: '鏍戠埗缂栫爜瀛楁',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      allowClear: false,
+    },
+    dependencies: {
+      show: (values) => values.tplCategory === 'tree',
+      triggerFields: ['tplCategory'],
+    },
+    fieldName: 'treeName',
+    help: '鏍戣妭鐐圭殑鏄剧ず鍚嶇О瀛楁鍚嶏紝 濡�: dept_name (鐩稿綋浜巐abel)',
+    label: '鏍戝悕绉板瓧娈�',
+    rules: 'selectRequired',
+  },
+  {
+    component: 'Input',
+    fieldName: 'packageName',
+    help: '鐢熸垚鍦ㄥ摢涓猨ava鍖呬笅, 渚嬪 com.ruoyi.system',
+    label: '鐢熸垚鍖呰矾寰�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'moduleName',
+    help: '鍙悊瑙d负瀛愮郴缁熷悕锛屼緥濡� system',
+    label: '鐢熸垚妯″潡鍚�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'businessName',
+    help: '鍙悊瑙d负鍔熻兘鑻辨枃鍚嶏紝渚嬪 user',
+    label: '鐢熸垚涓氬姟鍚�',
+    rules: 'required',
+  },
+  {
+    component: 'Input',
+    fieldName: 'functionName',
+    help: '鐢ㄤ綔绫绘弿杩帮紝渚嬪 鐢ㄦ埛',
+    label: '鐢熸垚鍔熻兘鍚�',
+    rules: 'required',
+  },
+  {
+    component: 'TreeSelect',
+    componentProps: {
+      allowClear: false,
+      getPopupContainer,
+    },
+    defaultValue: 0,
+    fieldName: 'parentMenuId',
+    label: '涓婄骇鑿滃崟',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: [
+        { label: 'modal寮圭獥', value: 'modal' },
+        { label: 'drawer鎶藉眽', value: 'drawer' },
+      ],
+      optionType: 'button',
+    },
+    help: '鑷畾涔夊姛鑳�, 闇�瑕佸悗绔敮鎸�',
+    defaultValue: 'modal',
+    fieldName: 'popupComponent',
+    label: '寮圭獥缁勪欢绫诲瀷',
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: [
+        { label: 'zip鍘嬬缉鍖�', value: '0' },
+        { label: '鑷畾涔夎矾寰�', value: '1' },
+      ],
+      optionType: 'button',
+    },
+    defaultValue: '0',
+    fieldName: 'genType',
+    help: '榛樿涓簔ip鍘嬬缉鍖呬笅杞�, 涔熷彲浠ヨ嚜瀹氫箟鐢熸垚璺緞',
+    label: '鐢熸垚浠g爜鏂瑰紡',
+  },
+  {
+    component: 'Input',
+    defaultValue: '/',
+    dependencies: {
+      show: (model) => model.genType === '1',
+      triggerFields: ['genType'],
+    },
+    fieldName: 'genPath',
+    help: '杈撳叆缁濆璺緞, 涓嶆敮鎸�"./"鐩稿璺緞',
+    label: '浠g爜鐢熸垚璺緞',
+    rules: z
+      .string()
+      .regex(/^(?:[a-z]:)?(?:\/|(?:\\|\/)[^\\/:*?"<>|\r\n]+)*(?:\\|\/)?$/i, {
+        message: '璇疯緭鍏ュ悎娉曠殑璺緞',
+      }),
+  },
+  {
+    component: 'Textarea',
+    fieldName: 'remark',
+    formItemClass: 'col-span-2 items-baseline',
+    label: '澶囨敞',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-config.vue b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-config.vue
new file mode 100644
index 0000000..fa36e74
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-config.vue
@@ -0,0 +1,108 @@
+<script setup lang="ts">
+import type { GenInfo } from '#/api/tool/gen/model';
+
+import { inject, type Ref, unref } from 'vue';
+
+import { message, Space } from 'ant-design-vue';
+import { cloneDeep } from 'lodash-es';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { editSave } from '#/api/tool/gen';
+
+import { toCurrentStep } from '../mitt';
+import { validRules, vxeTableColumns } from './gen-data';
+
+/**
+ * 浠庣埗缁勪欢娉ㄥ叆
+ */
+const genInfoData = inject('genInfoData') as Ref<GenInfo['info']>;
+
+const gridOptions: VxeGridProps = {
+  columns: vxeTableColumns,
+  keepSource: true,
+  editConfig: { trigger: 'click', mode: 'cell', showStatus: true },
+  editRules: validRules,
+  rowConfig: {
+    isHover: true,
+    keyField: 'id',
+    isCurrent: true, // 楂樹寒褰撳墠琛�
+  },
+  columnConfig: {
+    resizable: true,
+  },
+  proxyConfig: {
+    enabled: true,
+  },
+  toolbarConfig: {
+    refresh: false,
+    zoom: false,
+    custom: false,
+  },
+  height: 'auto',
+  pagerConfig: {
+    enabled: false,
+  },
+  data: genInfoData.value.columns,
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ gridOptions });
+
+async function handleSubmit() {
+  try {
+    const hasError = await tableApi.grid.validate();
+    if (hasError) {
+      message.error('鏍¢獙鏈�氳繃');
+      return;
+    }
+    const requestData = cloneDeep(unref(genInfoData));
+    // 浠庤〃鏍艰幏鍙栨渶鏂扮殑
+    requestData.columns = tableApi.grid.getData();
+    // 鏍戣〃闇�瑕佹坊鍔犺繖涓弬鏁�
+    if (requestData && requestData.tplCategory === 'tree') {
+      const { treeCode, treeName, treeParentCode } = requestData;
+      requestData.params = {
+        treeCode,
+        treeName,
+        treeParentCode,
+      };
+    }
+    // 闇�瑕佽繘琛屽弬鏁拌浆鍖�
+    if (requestData) {
+      const transform = (ret: boolean) => (ret ? '1' : '0');
+      requestData.columns.forEach((column) => {
+        const { edit, insert, query, required, list } = column;
+        column.isInsert = transform(insert);
+        column.isEdit = transform(edit);
+        column.isList = transform(list);
+        column.isQuery = transform(query);
+        column.isRequired = transform(required);
+      });
+      // 闇�瑕佹墜鍔ㄦ坊鍔犵埗绾ц彍鍗� 寮圭獥绫诲瀷
+      requestData.params = {
+        ...requestData.params,
+        parentMenuId: requestData.parentMenuId,
+        popupComponent: requestData.popupComponent,
+      };
+    }
+    await editSave(requestData);
+    // 璺宠浆鍒版垚鍔熼〉闈�
+    toCurrentStep(2);
+  } catch (error: unknown) {
+    console.error(error);
+  }
+}
+</script>
+
+<template>
+  <div class="flex flex-col gap-[16px] p-[12px]">
+    <div class="h-[calc(100vh-235px)] overflow-y-hidden">
+      <BasicTable />
+    </div>
+    <div class="flex justify-center">
+      <Space>
+        <a-button @click="toCurrentStep(0)">涓婁竴姝�</a-button>
+        <a-button type="primary" @click="handleSubmit">涓嬩竴姝�</a-button>
+      </Space>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-data.tsx b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-data.tsx
new file mode 100644
index 0000000..28684fc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-data.tsx
@@ -0,0 +1,326 @@
+import type { Recordable } from '@vben/types';
+
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { reactive } from 'vue';
+
+import { getPopupContainer } from '@vben/utils';
+
+import { Checkbox, Input, Select } from 'ant-design-vue';
+
+import { dictOptionSelectList } from '#/api/system/dict/dict-type';
+
+const JavaTypes: string[] = [
+  'Long',
+  'String',
+  'Integer',
+  'Double',
+  'BigDecimal',
+  'Date',
+  'Boolean',
+  'LocalDate',
+  'LocalDateTime',
+];
+
+const queryTypeOptions = [
+  { label: '=', value: 'EQ' },
+  { label: '!=', value: 'NE' },
+  { label: '>', value: 'GT' },
+  { label: '>=', value: 'GE' },
+  { label: '<', value: 'LT' },
+  { label: '<=', value: 'LE' },
+  { label: 'LIKE', value: 'LIKE' },
+  { label: 'BETWEEN', value: 'BETWEEN' },
+];
+
+const componentsOptions = [
+  { label: '鏂囨湰妗�', value: 'input' },
+  { label: '鏂囨湰鍩�', value: 'textarea' },
+  { label: '涓嬫媺妗�', value: 'select' },
+  { label: '鍗曢�夋', value: 'radio' },
+  { label: '澶嶉�夋', value: 'checkbox' },
+  { label: '鏃ユ湡鎺т欢', value: 'datetime' },
+  { label: '鍥剧墖涓婁紶', value: 'imageUpload' },
+  { label: '鏂囦欢涓婁紶', value: 'fileUpload' },
+  { label: '瀵屾枃鏈�', value: 'editor' },
+];
+
+const dictOptions = reactive<{ label: string; value: string }[]>([
+  { label: '鏈缃�', value: '' },
+]);
+/**
+ * 鍦ㄨ繖閲屽垵濮嬪寲瀛楀吀涓嬫媺妗�
+ */
+(async function init() {
+  const ret = await dictOptionSelectList();
+
+  ret.forEach((dict) => {
+    const option = {
+      label: `${dict.dictName} | ${dict.dictType}`,
+      value: dict.dictType,
+    };
+    dictOptions.push(option);
+  });
+})();
+
+function renderBooleanTag(row: Recordable<any>, field: string) {
+  const value = row[field] ? '鏄�' : '鍚�';
+  const className = row[field] ? 'text-green-500' : 'text-red-500';
+  return <span class={className}>{value}</span>;
+}
+
+function renderBooleanCheckbox(row: Recordable<any>, field: string) {
+  return <Checkbox v-model:checked={row[field]}></Checkbox>;
+}
+
+export const validRules: VxeGridProps['editRules'] = {
+  columnComment: [{ required: true, message: '璇疯緭鍏�' }],
+  javaField: [{ required: true, message: '璇疯緭鍏�' }],
+};
+
+export const vxeTableColumns: VxeGridProps['columns'] = [
+  {
+    title: '搴忓彿',
+    type: 'seq',
+    fixed: 'left',
+    width: '50',
+    align: 'center',
+  },
+  {
+    title: '瀛楁鍒楀悕',
+    field: 'columnName',
+    showOverflow: 'tooltip',
+    fixed: 'left',
+    minWidth: 150,
+  },
+  {
+    title: '瀛楁鎻忚堪',
+    field: 'columnComment',
+    minWidth: 150,
+    slots: {
+      edit: ({ row }) => {
+        return <Input v-model:value={row.columnComment}></Input>;
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: 'db绫诲瀷',
+    field: 'columnType',
+    minWidth: 120,
+    showOverflow: 'tooltip',
+  },
+  {
+    title: 'Java绫诲瀷',
+    field: 'javaType',
+    minWidth: 150,
+    slots: {
+      edit: ({ row }) => {
+        const javaTypeOptions = JavaTypes.map((type) => ({
+          label: type,
+          value: type,
+        }));
+        return (
+          <Select
+            class="w-full"
+            getPopupContainer={getPopupContainer}
+            options={javaTypeOptions}
+            v-model:value={row.javaType}
+          ></Select>
+        );
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: 'Java灞炴�у悕',
+    field: 'javaField',
+    minWidth: 150,
+    showOverflow: 'tooltip',
+    slots: {
+      edit: ({ row }) => {
+        return <Input v-model:value={row.javaField}></Input>;
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '鎻掑叆',
+    field: 'insert',
+    minWidth: 80,
+    showOverflow: 'tooltip',
+    align: 'center',
+    slots: {
+      default: ({ row }) => {
+        return renderBooleanTag(row, 'insert');
+      },
+      edit: ({ row }) => {
+        return renderBooleanCheckbox(row, 'insert');
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '缂栬緫',
+    field: 'edit',
+    showOverflow: 'tooltip',
+    align: 'center',
+    minWidth: 80,
+    slots: {
+      default: ({ row }) => {
+        return renderBooleanTag(row, 'edit');
+      },
+      edit: ({ row }) => {
+        return renderBooleanCheckbox(row, 'edit');
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '鍒楄〃',
+    field: 'list',
+    showOverflow: 'tooltip',
+    align: 'center',
+    minWidth: 80,
+    slots: {
+      default: ({ row }) => {
+        return renderBooleanTag(row, 'list');
+      },
+      edit: ({ row }) => {
+        return renderBooleanCheckbox(row, 'list');
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '鏌ヨ',
+    field: 'query',
+    showOverflow: 'tooltip',
+    align: 'center',
+    minWidth: 80,
+    slots: {
+      default: ({ row }) => {
+        return renderBooleanTag(row, 'query');
+      },
+      edit: ({ row }) => {
+        return renderBooleanCheckbox(row, 'query');
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '鏌ヨ鏂瑰紡',
+    field: 'queryType',
+    showOverflow: 'tooltip',
+    align: 'center',
+    minWidth: 150,
+    slots: {
+      default: ({ row }) => {
+        const queryType = row.queryType;
+        const found = queryTypeOptions.find((item) => item.value === queryType);
+        if (found) {
+          return found.label;
+        }
+        return queryType;
+      },
+      edit: ({ row }) => {
+        return (
+          <Select
+            class="w-full"
+            getPopupContainer={getPopupContainer}
+            options={queryTypeOptions}
+            v-model:value={row.queryType}
+          ></Select>
+        );
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '蹇呭~',
+    field: 'required',
+    showOverflow: 'tooltip',
+    align: 'center',
+    minWidth: 80,
+    slots: {
+      default: ({ row }) => {
+        return renderBooleanTag(row, 'required');
+      },
+      edit: ({ row }) => {
+        return renderBooleanCheckbox(row, 'required');
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '鏄剧ず绫诲瀷',
+    field: 'htmlType',
+    showOverflow: 'tooltip',
+    minWidth: 150,
+    align: 'center',
+    slots: {
+      default: ({ row }) => {
+        const htmlType = row.htmlType;
+        const found = componentsOptions.find((item) => item.value === htmlType);
+        if (found) {
+          return found.label;
+        }
+        return htmlType;
+      },
+      edit: ({ row }) => {
+        return (
+          <Select
+            class="w-full"
+            getPopupContainer={getPopupContainer}
+            options={componentsOptions}
+            v-model:value={row.htmlType}
+          ></Select>
+        );
+      },
+    },
+    editRender: {},
+  },
+  {
+    title: '瀛楀吀绫诲瀷',
+    field: 'dictType',
+    showOverflow: 'tooltip',
+    minWidth: 230,
+    align: 'center',
+    titlePrefix: {
+      message: `浠�'涓嬫媺妗�', '鍗曢�夋', '澶嶉�夋'鏀寔瀛楀吀绫诲瀷`,
+    },
+    slots: {
+      default: ({ row }) => {
+        const dictType = row.dictType;
+        const found = dictOptions.find((item) => item.value === dictType);
+        if (found) {
+          return found.label;
+        }
+        return dictType;
+      },
+      edit: ({ row }) => {
+        // 娓呴櫎鐨勫洖璋� 闇�瑕佽缃负绌哄瓧绗︿覆 鍚﹀垯涓嶄細鎻愪氦
+        const onDeselect = () => {
+          row.dictType = '';
+        };
+        const disabled =
+          row.htmlType !== 'select' &&
+          row.htmlType !== 'radio' &&
+          row.htmlType !== 'checkbox';
+        return (
+          <Select
+            allowClear={true}
+            class="w-full"
+            disabled={disabled}
+            getPopupContainer={getPopupContainer}
+            onDeselect={onDeselect}
+            options={dictOptions}
+            placeholder="璇烽�夋嫨瀛楀吀绫诲瀷"
+            v-model:value={row.dictType}
+          ></Select>
+        );
+      },
+    },
+    editRender: {},
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-success.vue b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-success.vue
new file mode 100644
index 0000000..50c7212
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/gen-success.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { useRouter } from 'vue-router';
+
+import { useTabs } from '@vben/hooks';
+
+import { Result } from 'ant-design-vue';
+
+const { closeCurrentTab } = useTabs();
+
+const router = useRouter();
+async function handleClose() {
+  await closeCurrentTab();
+  router.push({ path: '/tool/gen', replace: true });
+}
+</script>
+
+<template>
+  <Result status="success" title="淇敼鎴愬姛">
+    <template #extra>
+      <a-button type="primary" @click="handleClose"> 鍏抽棴 </a-button>
+    </template>
+  </Result>
+</template>
+
+<style scoped></style>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/index.ts b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/index.ts
new file mode 100644
index 0000000..11e7796
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/edit-steps/index.ts
@@ -0,0 +1,3 @@
+export { default as BasicSetting } from './basic-setting.vue';
+export { default as GenConfig } from './gen-config.vue';
+export { default as GenSuccess } from './gen-success.vue';
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/index.vue b/eims-ui/apps/web-antd/src/views/tool/gen/index.vue
new file mode 100644
index 0000000..7df58a8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/index.vue
@@ -0,0 +1,285 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { message, Modal, Popconfirm, Space } from 'ant-design-vue';
+import dayjs from 'dayjs';
+
+import {
+  useVbenVxeGrid,
+  vxeCheckboxChecked,
+  type VxeGridProps,
+} from '#/adapter/vxe-table';
+import {
+  batchGenCode,
+  generatedList,
+  genRemove,
+  getDataSourceNames,
+  syncDb,
+} from '#/api/tool/gen';
+import { downloadByData } from '#/utils/file/download';
+
+import codePreviewModal from './code-preview-modal.vue';
+import { columns, querySchema } from './data';
+import tableImportModal from './table-import-modal.vue';
+
+const formOptions: VbenFormProps = {
+  schema: querySchema(),
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    [
+      'createTime',
+      ['params[beginTime]', 'params[endTime]'],
+      ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'],
+    ],
+  ],
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true,
+    // 鐐瑰嚮琛岄�変腑
+    trigger: 'row',
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await generatedList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'tableId',
+  },
+  id: 'tool-gen-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+});
+
+onMounted(async () => {
+  // 鑾峰彇鏁版嵁婧�
+  const ret = await getDataSourceNames();
+  const dataSourceOptions = [{ label: '鍏ㄩ儴', value: '' }];
+  const transOptions = ret.map((item) => ({ label: item, value: item }));
+  dataSourceOptions.push(...transOptions);
+  // 鏇存柊selectOptions
+  tableApi.formApi.updateSchema([
+    {
+      fieldName: 'dataName',
+      componentProps: {
+        options: dataSourceOptions,
+      },
+    },
+  ]);
+});
+
+const [CodePreviewModal, previewModalApi] = useVbenModal({
+  connectedComponent: codePreviewModal,
+});
+
+function handlePreview(record: Recordable<any>) {
+  previewModalApi.setData({ tableId: record.tableId });
+  previewModalApi.open();
+}
+
+const router = useRouter();
+function handleEdit(record: Recordable<any>) {
+  router.push(`/code-gen/edit/${record.tableId}`);
+}
+
+async function handleSync(record: Recordable<any>) {
+  await syncDb(record.tableId);
+  await tableApi.query();
+}
+
+/**
+ * 鎵归噺鐢熸垚浠g爜
+ */
+async function handleBatchGen() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.tableId);
+  if (ids.length === 0) {
+    message.info('璇烽�夋嫨闇�瑕佺敓鎴愪唬鐮佺殑琛�');
+    return;
+  }
+  const hideLoading = message.loading('涓嬭浇涓�...');
+  try {
+    const params = ids.join(',');
+    const data = await batchGenCode(params);
+    const timestamp = Date.now();
+    downloadByData(data, `鎵归噺浠g爜鐢熸垚_${timestamp}.zip`);
+  } finally {
+    hideLoading();
+  }
+}
+
+async function handleDownload(record: Recordable<any>) {
+  const hideLoading = message.loading('涓嬭浇涓�...');
+  try {
+    const blob = await batchGenCode(record.tableId);
+    const filename = `浠g爜鐢熸垚_${record.tableName}_${dayjs().valueOf()}.zip`;
+    downloadByData(blob, filename);
+  } catch (error) {
+    console.error(error);
+  } finally {
+    hideLoading();
+  }
+}
+
+/**
+ * 鍒犻櫎
+ * @param record
+ */
+async function handleDelete(record: Recordable<any>) {
+  await genRemove(record.tableId);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.tableId);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await genRemove(ids);
+      await tableApi.query();
+    },
+  });
+}
+
+const [TableImportModal, tableImportModalApi] = useVbenModal({
+  connectedComponent: tableImportModal,
+});
+
+function handleImport() {
+  tableImportModalApi.open();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="浠g爜鐢熸垚鍒楄〃">
+      <template #toolbar-tools>
+        <a
+          class="text-primary mr-2"
+          href="https://dapdap.top/other/template.html"
+          target="_blank"
+          >馃憠鍏充簬浠g爜鐢熸垚妯℃澘
+        </a>
+        <Space>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            danger
+            type="primary"
+            v-access:code="['tool:gen:remove']"
+            @click="handleMultiDelete"
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+          <a-button
+            :disabled="!vxeCheckboxChecked(tableApi)"
+            v-access:code="['tool:gen:code']"
+            @click="handleBatchGen"
+          >
+            {{ $t('pages.common.generate') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['tool:gen:import']"
+            @click="handleImport"
+          >
+            {{ $t('pages.common.import') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <a-button
+          size="small"
+          type="link"
+          v-access:code="['tool:gen:preview']"
+          @click.stop="handlePreview(row)"
+        >
+          {{ $t('pages.common.preview') }}
+        </a-button>
+        <a-button
+          size="small"
+          type="link"
+          v-access:code="['tool:gen:edit']"
+          @click.stop="handleEdit(row)"
+        >
+          {{ $t('pages.common.edit') }}
+        </a-button>
+        <Popconfirm
+          :get-popup-container="getVxePopupContainer"
+          :title="`纭鍚屾[${row.tableName}]?`"
+          placement="left"
+          @confirm="handleSync(row)"
+        >
+          <a-button
+            size="small"
+            type="link"
+            v-access:code="['tool:gen:edit']"
+            @click.stop=""
+          >
+            {{ $t('pages.common.sync') }}
+          </a-button>
+        </Popconfirm>
+        <a-button
+          size="small"
+          type="link"
+          v-access:code="['tool:gen:code']"
+          @click.stop="handleDownload(row)"
+        >
+          鐢熸垚浠g爜
+        </a-button>
+        <Popconfirm
+          :get-popup-container="getVxePopupContainer"
+          :title="`纭鍒犻櫎[${row.tableName}]?`"
+          placement="left"
+          @confirm="handleDelete(row)"
+        >
+          <a-button
+            danger
+            size="small"
+            type="link"
+            v-access:code="['tool:gen:remove']"
+            @click.stop=""
+          >
+            {{ $t('pages.common.delete') }}
+          </a-button>
+        </Popconfirm>
+      </template>
+    </BasicTable>
+    <CodePreviewModal />
+    <TableImportModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/mitt.ts b/eims-ui/apps/web-antd/src/views/tool/gen/mitt.ts
new file mode 100644
index 0000000..5cb4951
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/mitt.ts
@@ -0,0 +1,15 @@
+import { mitt } from '@vben/utils';
+
+type Events = {
+  to: number;
+};
+
+export const emitter = mitt<Events>();
+
+/**
+ * 璺宠浆鍒版寚瀹氭楠�
+ * @param step 姝ラ
+ */
+export function toCurrentStep(step: number) {
+  emitter.emit('to', step);
+}
diff --git a/eims-ui/apps/web-antd/src/views/tool/gen/table-import-modal.vue b/eims-ui/apps/web-antd/src/views/tool/gen/table-import-modal.vue
new file mode 100644
index 0000000..7fa40fa
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/tool/gen/table-import-modal.vue
@@ -0,0 +1,141 @@
+<script setup lang="ts">
+import { useVbenModal, type VbenFormProps } from '@vben/common-ui';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import {
+  getDataSourceNames,
+  importTable,
+  readyToGenList,
+} from '#/api/tool/gen';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const formOptions: VbenFormProps = {
+  schema: [
+    {
+      label: '鏁版嵁婧�',
+      fieldName: 'dataName',
+      component: 'Select',
+      defaultValue: 'master',
+    },
+    {
+      label: '琛ㄥ悕绉�',
+      fieldName: 'tableName',
+      component: 'Input',
+    },
+    {
+      label: '琛ㄦ弿杩�',
+      fieldName: 'tableComment',
+      component: 'Input',
+    },
+  ],
+  commonConfig: {
+    labelWidth: 60,
+  },
+  showCollapseButton: false,
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    highlight: true,
+    reserve: true,
+    trigger: 'row',
+  },
+  columns: [
+    {
+      type: 'checkbox',
+      width: 60,
+    },
+    {
+      title: '琛ㄥ悕绉�',
+      field: 'tableName',
+      align: 'left',
+    },
+    {
+      title: '琛ㄦ弿杩�',
+      field: 'tableComment',
+    },
+    {
+      title: '鍒涘缓鏃堕棿',
+      field: 'createTime',
+    },
+    {
+      title: '鏇存柊鏃堕棿',
+      field: 'updateTime',
+    },
+  ],
+  keepSource: true,
+  size: 'small',
+  minHeight: 400,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await readyToGenList({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'tableId',
+  },
+  toolbarConfig: {
+    refresh: false,
+    zoom: false,
+    custom: false,
+  },
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ formOptions, gridOptions });
+
+const [BasicModal, modalApi] = useVbenModal({
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      tableApi.grid.clearCheckboxRow();
+      return null;
+    }
+    const ret = await getDataSourceNames();
+    const dataSourceOptions = ret.map((item) => ({ label: item, value: item }));
+    tableApi.formApi.updateSchema([
+      {
+        fieldName: 'dataName',
+        componentProps: {
+          options: dataSourceOptions,
+        },
+      },
+    ]);
+  },
+  onConfirm: handleSubmit,
+});
+
+async function handleSubmit() {
+  try {
+    const records = tableApi.grid.getCheckboxRecords();
+    const tables = records.map((item) => item.tableName);
+    if (tables.length === 0) {
+      modalApi.close();
+      return;
+    }
+    modalApi.modalLoading(true);
+    const { dataName } = await tableApi.formApi.getValues();
+    await importTable(tables.join(','), dataName);
+    emit('reload');
+    modalApi.close();
+  } catch (error) {
+    console.warn(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+</script>
+
+<template>
+  <BasicModal class="w-[800px]" title="瀵煎叆琛�">
+    <BasicTable />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/category/category-modal.vue b/eims-ui/apps/web-antd/src/views/workflow/category/category-modal.vue
new file mode 100644
index 0000000..a5ee049
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/category/category-modal.vue
@@ -0,0 +1,126 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep, getPopupContainer, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import {
+  categoryAdd,
+  categoryInfo,
+  categoryList,
+  categoryUpdate,
+} from '#/api/workflow/category';
+
+import { modalSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    // 榛樿鍗犳弧涓ゅ垪
+    formItemClass: 'col-span-2',
+    // 榛樿label瀹藉害 px
+    labelWidth: 80,
+    // 閫氱敤閰嶇疆椤� 浼氬奖鍝嶅埌鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  schema: modalSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function setupCategorySelect() {
+  const listData = await categoryList();
+  let treeData = listToTree(listData, {
+    id: 'id',
+    pid: 'parentId',
+  });
+  treeData = [
+    {
+      categoryName: '鏍圭洰褰�',
+      id: 0,
+      children: treeData,
+    },
+  ];
+  formApi.updateSchema([
+    {
+      fieldName: 'parentId',
+      componentProps: {
+        treeData,
+        treeLine: { showLeafIcon: false },
+        fieldNames: { label: 'categoryName', value: 'id' },
+        treeDefaultExpandAll: true,
+        getPopupContainer,
+      },
+    },
+  ]);
+}
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  onOpenChange: async (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    modalApi.modalLoading(true);
+
+    const { id, parentId } = modalApi.getData() as {
+      id?: number | string;
+      parentId?: number | string;
+    };
+    isUpdate.value = !!id;
+
+    if (isUpdate.value && id) {
+      const record = await categoryInfo(id);
+      await formApi.setValues(record);
+    }
+    if (parentId) {
+      await formApi.setValues({ parentId });
+    }
+    await setupCategorySelect();
+
+    modalApi.modalLoading(false);
+  },
+});
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    // getValues鑾峰彇涓轰竴涓猺eadonly鐨勫璞� 闇�瑕佷慨鏀瑰繀椤诲厛娣辨嫹璐濅竴娆�
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? categoryUpdate(data) : categoryAdd(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicModal :close-on-click-modal="false" :title="title">
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/category/data.ts b/eims-ui/apps/web-antd/src/views/workflow/category/data.ts
new file mode 100644
index 0000000..b9b757a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/category/data.ts
@@ -0,0 +1,75 @@
+import type { FormSchemaGetter } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    fieldName: 'categoryName',
+    label: '鍒嗙被鍚嶇О',
+    component: 'Input',
+  },
+  {
+    fieldName: 'categoryCode',
+    label: '鍒嗙被缂栫爜',
+    component: 'Input',
+  },
+];
+
+export const columns: VxeGridProps['columns'] = [
+  {
+    field: 'categoryName',
+    title: '鍒嗙被鍚嶇О',
+    treeNode: true,
+  },
+  {
+    field: 'categoryCode',
+    title: '鍒嗙被缂栫爜',
+  },
+  {
+    field: 'sortNum',
+    title: '鎺掑簭',
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200,
+  },
+];
+
+export const modalSchema: FormSchemaGetter = () => [
+  {
+    label: 'id',
+    fieldName: 'id',
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: [''],
+    },
+  },
+  {
+    fieldName: 'parentId',
+    label: '鐖剁骇鍒嗙被',
+    rules: 'required',
+    defaultValue: 0,
+    component: 'TreeSelect',
+  },
+  {
+    fieldName: 'categoryName',
+    label: '鍒嗙被鍚嶇О',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    fieldName: 'categoryCode',
+    label: '鍒嗙被缂栫爜',
+    component: 'Input',
+    rules: 'required',
+  },
+  {
+    fieldName: 'sortNum',
+    label: '鎺掑簭',
+    component: 'InputNumber',
+    rules: 'required',
+  },
+];
diff --git a/eims-ui/apps/web-antd/src/views/workflow/category/index.vue b/eims-ui/apps/web-antd/src/views/workflow/category/index.vue
new file mode 100644
index 0000000..ab5869e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/category/index.vue
@@ -0,0 +1,153 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { nextTick } from 'vue';
+
+import { Page, useVbenModal, type VbenFormProps } from '@vben/common-ui';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { categoryList, categoryRemove } from '#/api/workflow/category';
+
+import categoryModal from './category-modal.vue';
+import { columns, querySchema } from './data';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true,
+    },
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await categoryList({
+          ...formValues,
+        });
+        return { rows: resp };
+      },
+      // 榛樿璇锋眰鎺ュ彛鍚庡睍寮�鍏ㄩ儴 涓嶉渶瑕佸彲浠ュ垹闄よ繖娈�
+      querySuccess: () => {
+        nextTick(() => {
+          expandAll();
+        });
+      },
+    },
+  },
+  /**
+   * 铏氭嫙婊氬姩  榛樿鍏抽棴
+   */
+  scrollY: {
+    enabled: false,
+    gt: 0,
+  },
+  rowConfig: {
+    keyField: 'id',
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    transform: true,
+  },
+  // 琛ㄦ牸鍏ㄥ眬鍞竴琛ㄧず 淇濆瓨鍒楅厤缃渶瑕佺敤鍒�
+  id: 'workflow-category-index',
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({ formOptions, gridOptions });
+const [CategoryModal, modalApi] = useVbenModal({
+  connectedComponent: categoryModal,
+});
+
+function handleAdd(row?: Recordable<any>) {
+  modalApi.setData({ parentId: row?.id });
+  modalApi.open();
+}
+
+async function handleEdit(row: Recordable<any>) {
+  modalApi.setData({ id: row.id });
+  modalApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await categoryRemove(row.id);
+  await tableApi.query();
+}
+
+function expandAll() {
+  tableApi.grid?.setAllTreeExpand(true);
+}
+
+function collapseAll() {
+  tableApi.grid?.setAllTreeExpand(false);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="娴佺▼鍒嗙被鍒楄〃">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="collapseAll">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="expandAll">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button
+            type="primary"
+            v-access:code="['workflow:category:add']"
+            @click="handleAdd"
+          >
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button
+            v-access:code="['workflow:category:edit']"
+            @click.stop="handleEdit(row)"
+          >
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <ghost-button
+            class="btn-success"
+            v-access:code="['workflow:category:edit']"
+            @click.stop="handleAdd(row)"
+          >
+            {{ $t('pages.common.add') }}
+          </ghost-button>
+          <Popconfirm
+            :get-popup-container="getVxePopupContainer"
+            placement="left"
+            title="纭鍒犻櫎锛�"
+            @confirm="handleDelete(row)"
+          >
+            <ghost-button
+              danger
+              v-access:code="['workflow:category:remove']"
+              @click.stop=""
+            >
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <CategoryModal @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/components/approval-card.vue b/eims-ui/apps/web-antd/src/views/workflow/components/approval-card.vue
new file mode 100644
index 0000000..1587f31
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/components/approval-card.vue
@@ -0,0 +1,61 @@
+<script setup lang="ts">
+import { Avatar, Descriptions, DescriptionsItem, Tag } from 'ant-design-vue';
+
+interface Props {
+  id: string;
+  endTime: string;
+  startTime: string;
+  title: string;
+  desc: string;
+  status: string;
+  active: boolean;
+}
+
+const props = withDefaults(defineProps<{ info: Props }>(), {});
+
+const emit = defineEmits<{ click: [string] }>();
+
+function handleClick() {
+  emit('click', props.info.id);
+}
+</script>
+
+<template>
+  <div
+    :class="{
+      'border-primary': info.active,
+      'border-[2px]': info.active,
+    }"
+    class="cursor-pointer rounded-lg border-[1px] border-solid p-3 transition-shadow duration-300 ease-in-out hover:shadow-lg"
+    @click.stop="handleClick"
+  >
+    <Descriptions :column="1" :title="info.title" size="middle">
+      <template #extra>
+        <Tag color="warning">瀹℃壒涓�</Tag>
+      </template>
+      <DescriptionsItem label="鎻忚堪">{{ info.desc }}</DescriptionsItem>
+      <DescriptionsItem label="寮�濮嬫椂闂�">{{ info.startTime }}</DescriptionsItem>
+      <DescriptionsItem label="缁撴潫鏃堕棿">{{ info.endTime }}</DescriptionsItem>
+    </Descriptions>
+    <div class="flex items-center justify-between text-[14px]">
+      <div class="flex items-center gap-1">
+        <Avatar
+          size="small"
+          src="https://plus.dapdap.top/minio-server/plus/2024/11/21/925ed278e2d441beb7f695b41e13c4dd.jpg"
+        />
+        <span class="opacity-50">鐤媯鐨勭墰瀛怢i</span>
+      </div>
+      <div class="opacity-50">澶勭悊鏃堕棿: 2022-01-01</div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+:deep(.ant-descriptions .ant-descriptions-header) {
+  margin-bottom: 12px !important;
+}
+
+:deep(.ant-descriptions-item) {
+  padding-bottom: 8px !important;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/components/approval-timeline.vue b/eims-ui/apps/web-antd/src/views/workflow/components/approval-timeline.vue
new file mode 100644
index 0000000..68f34f3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/components/approval-timeline.vue
@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import { Timeline, TimelineItem } from 'ant-design-vue';
+
+/**
+ * TODO: 浠呬负demo 鍚庢湡浼氭浛鎹�
+ */
+import { VbenAvatar } from '../../../../../../packages/@core/ui-kit/shadcn-ui/src/components';
+
+interface ApprovalItem {
+  id: string;
+  name: string;
+  status: string;
+  remark?: string;
+  time: string;
+}
+
+const props = defineProps<{
+  list: ApprovalItem[];
+}>();
+</script>
+
+<template>
+  <Timeline>
+    <TimelineItem v-for="item in props.list" :key="item.id">
+      <template #dot>
+        <div class="relative rounded-full border">
+          <VbenAvatar
+            class="size-[36px]"
+            src="https://plus.dapdap.top/minio-server/plus/2024/11/21/925ed278e2d441beb7f695b41e13c4dd.jpg"
+          />
+          <div
+            class="border-background absolute bottom-0 right-0 size-[16px] rounded-full border-2 bg-green-500 content-['']"
+          >
+            <div class="flex items-center justify-center">
+              <span class="icon-[mdi--success-bold] text-white"></span>
+            </div>
+          </div>
+        </div>
+      </template>
+      <div class="ml-2 flex flex-col">
+        <div>鍙戣捣浜�</div>
+        <div>鐤媯鐨勭墰瀛怢i</div>
+        <div>2022-01-01 12:00:00</div>
+        <div class="rounded-lg border p-1">
+          <span class="opacity-70">杩欓噷鏄娉ㄤ俊鎭�</span>
+        </div>
+      </div>
+    </TimelineItem>
+  </Timeline>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/components/index.ts b/eims-ui/apps/web-antd/src/views/workflow/components/index.ts
new file mode 100644
index 0000000..c169438
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/components/index.ts
@@ -0,0 +1,2 @@
+export { default as ApprovalCard } from './approval-card.vue';
+export { default as ApprovalTimeline } from './approval-timeline.vue';
diff --git a/eims-ui/apps/web-antd/src/views/workflow/components/rejection.png b/eims-ui/apps/web-antd/src/views/workflow/components/rejection.png
new file mode 100644
index 0000000..7ed9220
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/components/rejection.png
Binary files differ
diff --git a/eims-ui/apps/web-antd/src/views/workflow/formManage/index.vue b/eims-ui/apps/web-antd/src/views/workflow/formManage/index.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/formManage/index.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/leave/index.vue b/eims-ui/apps/web-antd/src/views/workflow/leave/index.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/leave/index.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/model/index.vue b/eims-ui/apps/web-antd/src/views/workflow/model/index.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/model/index.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/processDefinition/index.vue b/eims-ui/apps/web-antd/src/views/workflow/processDefinition/index.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/processDefinition/index.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/processInstance/index.vue b/eims-ui/apps/web-antd/src/views/workflow/processInstance/index.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/processInstance/index.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/task/allTaskWaiting.vue b/eims-ui/apps/web-antd/src/views/workflow/task/allTaskWaiting.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/task/allTaskWaiting.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/task/myDocument.vue b/eims-ui/apps/web-antd/src/views/workflow/task/myDocument.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/task/myDocument.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/task/taskCopyList.vue b/eims-ui/apps/web-antd/src/views/workflow/task/taskCopyList.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/task/taskCopyList.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/task/taskFinish.vue b/eims-ui/apps/web-antd/src/views/workflow/task/taskFinish.vue
new file mode 100644
index 0000000..06372a1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/task/taskFinish.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import CommonSkeleton from '#/views/common';
+</script>
+
+<template>
+  <div>
+    <CommonSkeleton />
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/workflow/task/taskWaiting.vue b/eims-ui/apps/web-antd/src/views/workflow/task/taskWaiting.vue
new file mode 100644
index 0000000..e8d75ad
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/workflow/task/taskWaiting.vue
@@ -0,0 +1,172 @@
+<script setup lang="ts">
+import { reactive, ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import {
+  Alert,
+  Avatar,
+  Card,
+  Divider,
+  InputSearch,
+  Space,
+  TabPane,
+  Tabs,
+  Tag,
+} from 'ant-design-vue';
+import { debounce, uniqueId } from 'lodash-es';
+
+import { ApprovalCard, ApprovalTimeline } from '../components';
+import RejectionPng from '../components/rejection.png';
+
+const handleScroll = debounce((e: Event) => {
+  if (!e.target) {
+    return;
+  }
+  // e.target.scrollTop 鏄厓绱犻《閮ㄥ埌褰撳墠鍙鍖哄煙椤堕儴鐨勮窛绂伙紝鍗冲凡婊氬姩鐨勯珮搴︺��
+  // e.target.clientHeight 鏄厓绱犵殑鍙楂樺害銆�
+  // e.target.scrollHeight 鏄厓绱犵殑鎬婚珮搴︺��
+  const { scrollTop, clientHeight, scrollHeight } = e.target as HTMLElement;
+  // 鍒ゆ柇鏄惁婊氬姩鍒板簳閮�
+  const isBottom = scrollTop + clientHeight >= scrollHeight;
+  console.log(isBottom);
+  // console.log(scrollTop + clientHeight);
+  // console.log(scrollHeight);
+}, 200);
+
+const data = reactive(
+  Array.from({ length: 10 }).map(() => ({
+    id: uniqueId(),
+    startTime: '2022-01-01',
+    endTime: '2022-01-02',
+    title: '瀹℃壒浠诲姟',
+    desc: '瀹℃壒浠诲姟鎻忚堪',
+    status: '瀹℃壒涓�',
+    active: false,
+  })),
+);
+
+const timeLine = Array.from({ length: 5 }).map(() => ({
+  id: uniqueId(),
+  name: '寮犱笁',
+  status: '瀹℃壒涓�',
+  remark: '瀹℃壒浠诲姟鎻忚堪',
+  time: '2022-01-01',
+}));
+
+const lastSelectId = ref('');
+function handleCardClick(id: string) {
+  // 鐐瑰嚮鐨勬槸鍚屼竴涓�
+  if (lastSelectId.value === id) {
+    return;
+  }
+  // 鍙嶉�夌姸鎬� & 濡傛灉宸茬粡鐐瑰嚮浜� 涓嶅彉 & 淇濇寔鍙兘鏈変竴涓�変腑
+  data.forEach((item) => {
+    item.active = item.id === id;
+  });
+  lastSelectId.value = id;
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-2">
+      <div class="bg-background flex h-full w-[320px] flex-col rounded-lg">
+        <!-- 鎼滅储鏉′欢 -->
+        <div
+          class="bg-background z-100 sticky left-0 top-0 w-full rounded-t-lg border-b-[1px] border-solid p-2"
+        >
+          <InputSearch placeholder="鎼滅储" />
+        </div>
+        <div
+          class="thin-scrollbar flex flex-1 flex-col gap-2 overflow-y-auto py-3"
+          @scroll="handleScroll"
+        >
+          <ApprovalCard
+            v-for="item in data"
+            :key="item.id"
+            :info="item"
+            class="mx-2"
+            @click="handleCardClick"
+          />
+        </div>
+        <!-- total鏄剧ず -->
+        <div
+          class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2"
+        >
+          <div class="flex items-center justify-center">
+            鍏� {{ data.length }} 鏉¤褰�
+          </div>
+        </div>
+      </div>
+      <Card
+        :body-style="{ overflowY: 'auto', height: '100%' }"
+        class="thin-scrollbar flex-1 overflow-y-hidden"
+        size="small"
+        title="缂栧彿: 1234567890123456789012"
+      >
+        <div class="flex flex-col gap-5 p-4">
+          <div class="flex flex-col gap-3">
+            <div class="flex items-center gap-2">
+              <div class="text-2xl font-bold">鎶ラ攢鐢宠</div>
+              <div>
+                <Tag color="warning">鐢宠涓�</Tag>
+              </div>
+            </div>
+            <div class="flex items-center gap-2">
+              <Avatar
+                size="small"
+                src="https://plus.dapdap.top/minio-server/plus/2024/11/21/925ed278e2d441beb7f695b41e13c4dd.jpg"
+              />
+              <span>鐤媯鐨勭墰瀛怢i</span>
+              <div class="flex items-center opacity-50">
+                <span>XXXX鏈夐檺鍏徃</span>
+                <Divider type="vertical" />
+                <span>鎻愪氦浜�: 2022-01-01 12:00:00</span>
+              </div>
+            </div>
+            <!-- 鍙充晶鍥炬爣 -->
+            <div class="z-100 absolute right-3 top-3">
+              <img :src="RejectionPng" class="size-[96px]" />
+            </div>
+          </div>
+          <Tabs class="flex-1">
+            <TabPane key="1" tab="瀹℃壒璇︽儏">
+              <div class="h-fulloverflow-y-auto">
+                <Alert message="璇ラ〉闈粎涓洪潤鎬侀〉 鍚庢湡鍙兘浼氱敤鍒�!" type="info" />
+                <Divider />
+                <ApprovalTimeline :list="timeLine" />
+              </div>
+            </TabPane>
+            <TabPane key="2" tab="瀹℃壒璁板綍">瀹℃壒璁板綍</TabPane>
+            <TabPane key="3" tab="鍏ㄦ枃璇勮(999+)">鍏ㄦ枃璇勮</TabPane>
+          </Tabs>
+        </div>
+        <!-- 鍥哄畾搴曢儴 -->
+        <div
+          class="border-t-solid bg-background absolute bottom-0 left-0 w-full border-t-[1px] p-3"
+        >
+          <div class="flex justify-end">
+            <Space>
+              <a-button type="primary">閫氳繃</a-button>
+              <a-button danger type="primary">椹冲洖</a-button>
+              <a-button>鍏朵粬</a-button>
+            </Space>
+          </div>
+        </div>
+      </Card>
+    </div>
+  </Page>
+</template>
+
+<style lang="scss" scoped>
+.thin-scrollbar {
+  &::-webkit-scrollbar {
+    width: 5px;
+  }
+}
+
+:deep(.ant-card-body) {
+  @apply thin-scrollbar;
+}
+</style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/changelog/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/changelog/index.vue"
new file mode 100644
index 0000000..bd01034
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/changelog/index.vue"
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { MarkdownPreviewer, Page } from '@vben/common-ui';
+
+import { Skeleton } from 'ant-design-vue';
+
+import changelog from '../../../../../../CHANGELOG.md?raw';
+
+const content = ref(changelog);
+
+const loading = ref(true);
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <Skeleton v-show="loading" active />
+    <MarkdownPreviewer
+      v-model:value="content"
+      height="100%"
+      @mounted="loading = false"
+    />
+  </Page>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/query/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/query/index.vue"
new file mode 100644
index 0000000..6213f29
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/query/index.vue"
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import { useRoute } from 'vue-router';
+
+import { JsonPreview, Page } from '@vben/common-ui';
+
+const route = useRoute();
+const query = route.query;
+</script>
+
+<template>
+  <Page>
+    <div class="bg-background rounded-lg p-4">
+      <span>褰撳墠鍙傛暟:</span>
+      <JsonPreview :data="query" />
+    </div>
+  </Page>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/api.ts" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/api.ts"
new file mode 100644
index 0000000..3e5a882
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/api.ts"
@@ -0,0 +1,26 @@
+import { requestClient } from '#/api/request';
+
+enum Api {
+  list = '/system/sse/list',
+  send = '/system/sse/send',
+  sendAll = '/system/sse/sendAll',
+  status = '/system/sse/status',
+}
+
+export function sseStatus() {
+  return requestClient.get<boolean>(Api.status);
+}
+
+export function sseSendAll(message: string) {
+  return requestClient.postWithMsg<void>(`${Api.sendAll}?message=${message}`);
+}
+
+export function sseSendByUserId(userId: string, message: string) {
+  return requestClient.postWithMsg<void>(
+    `${Api.send}/${userId}?message=${message}`,
+  );
+}
+
+export function sseList() {
+  return requestClient.get<any>(Api.list);
+}
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/index.vue"
new file mode 100644
index 0000000..220cfa8
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/index.vue"
@@ -0,0 +1,100 @@
+<script setup lang="ts">
+import { Page, useVbenModal } from '@vben/common-ui';
+
+import { Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+
+import { sseList } from './api';
+import sendMsgModal from './send-msg-modal.vue';
+
+const gridOptions: VxeGridProps = {
+  columns: [
+    {
+      title: '鐢ㄦ埛ID',
+      field: 'userId',
+    },
+    {
+      title: '鐢ㄦ埛璐﹀彿',
+      field: 'userName',
+    },
+    {
+      title: '鐢ㄦ埛鏄电О',
+      field: 'nickName',
+    },
+    {
+      title: '鐢ㄦ埛閮ㄩ棬',
+      field: 'deptName',
+    },
+    {
+      field: 'action',
+      fixed: 'right',
+      slots: { default: 'action' },
+      title: '鎿嶄綔',
+      width: 180,
+    },
+  ],
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async () => {
+        const list = await sseList();
+        return {
+          rows: list,
+        };
+      },
+    },
+  },
+  rowConfig: {
+    isHover: false,
+    keyField: 'userId',
+    height: 48,
+  },
+  id: 'sse-index',
+};
+
+const [BasicTable] = useVbenVxeGrid({
+  gridOptions,
+});
+
+const [SendMsgModal, modalApi] = useVbenModal({
+  connectedComponent: sendMsgModal,
+});
+
+function handleSendAll() {
+  modalApi.setData({});
+  modalApi.open();
+}
+
+function handleSendSingle(userId: string) {
+  modalApi.setData({ userId });
+  modalApi.open();
+}
+</script>
+
+<template>
+  <Page
+    :auto-content-height="true"
+    description="杩欒繖閲屽彲浠ヨ繘琛孾Server-sent events]娴嬭瘯 闈炲畼鏂瑰姛鑳�"
+    title="SSE娴嬭瘯"
+  >
+    <BasicTable>
+      <template #toolbar-actions>
+        <span class="pl-[7px] text-[16px]">鍦ㄧ嚎鐢ㄦ埛鍒楄〃</span>
+      </template>
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="handleSendAll">鍙戦�佸叏浣撴秷鎭�</a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <ghost-button @click="handleSendSingle(row.userId)">
+          鍙戦�佹秷鎭�
+        </ghost-button>
+      </template>
+    </BasicTable>
+    <SendMsgModal />
+  </Page>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/send-msg-modal.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/send-msg-modal.vue"
new file mode 100644
index 0000000..1dccb0c
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/sse/send-msg-modal.vue"
@@ -0,0 +1,77 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { useVbenForm } from '#/adapter/form';
+
+import { sseSendAll, sseSendByUserId } from './api';
+
+const currentUserId = ref<string | undefined>(undefined);
+const title = computed(() => {
+  return currentUserId.value ? '鍙戦�佹寚瀹氭秷鎭�' : '鍙戦�佸叏浣撴秷鎭�';
+});
+
+const [BasicModal, modalApi] = useVbenModal({
+  onConfirm: handleSubmit,
+  onOpenChange: (isOpen) => {
+    if (!isOpen) {
+      return null;
+    }
+    const data = modalApi.getData() as { userId: string | undefined };
+    currentUserId.value = data.userId;
+  },
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  layout: 'vertical',
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full',
+    },
+    labelWidth: 80,
+  },
+  schema: [
+    {
+      component: 'Textarea',
+      label: '娑堟伅鍐呭',
+      fieldName: 'content',
+      rules: 'required',
+    },
+  ],
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2',
+});
+
+async function handleSubmit() {
+  try {
+    modalApi.modalLoading(true);
+
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const { content } = await formApi.getValues();
+
+    await (currentUserId.value
+      ? sseSendByUserId(currentUserId.value, content)
+      : sseSendAll(content));
+    modalApi.close();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :fullscreen-button="false"
+    :title="title"
+  >
+    <BasicForm />
+  </BasicModal>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/tinymce/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/tinymce/index.vue"
new file mode 100644
index 0000000..ec59c57
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/tinymce/index.vue"
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Switch } from 'ant-design-vue';
+
+import { Tinymce } from '#/components/tinymce';
+
+const readonly = ref(false);
+const content = ref('');
+</script>
+
+<template>
+  <Page title="Tinymce瀵屾枃鏈�">
+    <div class="flex flex-col gap-[16px]">
+      <div class="flex items-center gap-[16px]">
+        <span>鍙</span>
+        <Switch v-model:checked="readonly" />
+      </div>
+      <Tinymce v-model="content" :height="800" :options="{ readonly }" />
+    </div>
+  </Page>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/upload/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/upload/index.vue"
new file mode 100644
index 0000000..c555666
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/upload/index.vue"
@@ -0,0 +1,64 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { JsonPreview, Page } from '@vben/common-ui';
+
+import { Alert, RadioGroup } from 'ant-design-vue';
+
+import { FileUpload, ImageUpload } from '#/components/upload';
+
+const resultField = ref<'ossId' | 'url'>('ossId');
+
+const imageList = ref([]);
+const fileList = ref(['111', '2222']);
+const fieldOptions = [
+  { label: 'ossId', value: 'ossId' },
+  { label: '閾炬帴鍦板潃', value: 'url' },
+];
+const fileAccept = ['xlsx', 'word', 'pdf'];
+
+const signleImage = ref<string>('');
+</script>
+
+<template>
+  <Page content-class="flex flex-col gap-[12px]">
+    <div class="bg-background flex flex-col gap-[12px] rounded-lg p-6">
+      <Alert
+        :show-icon="true"
+        message="鏂扮壒鎬�: 璁剧疆max-number涓�1鏃�, 浼氳缁戝畾涓簊tring鑰岄潪string[]绫诲瀷 鐪佸幓鎵嬪姩杞崲"
+      />
+      <ImageUpload v-model:value="signleImage" :max-number="1" />
+      <JsonPreview :data="signleImage" />
+    </div>
+    <div class="bg-background flex flex-col gap-[12px] rounded-lg p-6">
+      <div class="flex gap-[8px]">
+        <span>杩斿洖瀛楁: </span>
+        <RadioGroup v-model:value="resultField" :options="fieldOptions" />
+      </div>
+      <ImageUpload
+        v-model:value="imageList"
+        :max-number="3"
+        :result-field="resultField"
+      />
+      <JsonPreview :data="imageList" />
+    </div>
+    <div class="bg-background flex flex-col gap-[12px] rounded-lg p-6">
+      <div class="flex gap-[8px]">
+        <span>杩斿洖瀛楁: </span>
+        <RadioGroup v-model:value="resultField" :options="fieldOptions" />
+      </div>
+      <Alert
+        :message="`鏀寔鐨勬枃浠剁被鍨嬶細${fileAccept.join(', ')}`"
+        :show-icon="true"
+        type="info"
+      />
+      <FileUpload
+        v-model:value="fileList"
+        :accept="fileAccept"
+        :max-number="3"
+        :result-field="resultField"
+      />
+      <JsonPreview :data="fileList" />
+    </div>
+  </Page>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/api.ts" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/api.ts"
new file mode 100644
index 0000000..bd3e4b1
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/api.ts"
@@ -0,0 +1,32 @@
+import { requestClient } from '#/api/request';
+
+export interface Temp {
+  name: string;
+  value: number;
+}
+
+export function visitList() {
+  return requestClient.get<Temp[]>('/monitor/logininfor/visitsMap');
+}
+
+export function deviceInfoList() {
+  return requestClient.get<Temp[]>('/monitor/logininfor/deviceInfoList');
+}
+
+export function browserInfoList() {
+  return requestClient.get<Temp[]>('/monitor/logininfor/browserInfoList');
+}
+
+export function ispInfoList() {
+  return requestClient.get<Temp[]>('/monitor/logininfor/ispInfoList');
+}
+
+export interface LoginLineResp {
+  date: string[];
+  fail: number[];
+  success: number[];
+}
+
+export function loginLine() {
+  return requestClient.get<LoginLineResp>('/monitor/logininfor/loginLine');
+}
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/china.json" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/china.json"
new file mode 100644
index 0000000..15826b2
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/china.json"
@@ -0,0 +1,103310 @@
+{
+  "type": "FeatureCollection",
+  "features": [
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 110000,
+        "name": "鍖椾含甯�",
+        "center": [
+          116.405285,
+          39.904989
+        ],
+        "centroid": [
+          116.41995,
+          40.18994
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 0,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                117.348611,
+                40.581141
+              ],
+              [
+                117.389879,
+                40.561593
+              ],
+              [
+                117.429915,
+                40.576141
+              ],
+              [
+                117.412669,
+                40.605226
+              ],
+              [
+                117.467487,
+                40.649738
+              ],
+              [
+                117.467487,
+                40.649738
+              ],
+              [
+                117.501364,
+                40.636569
+              ],
+              [
+                117.514914,
+                40.660181
+              ],
+              [
+                117.493973,
+                40.675161
+              ],
+              [
+                117.408973,
+                40.686961
+              ],
+              [
+                117.342451,
+                40.673799
+              ],
+              [
+                117.319662,
+                40.657911
+              ],
+              [
+                117.278394,
+                40.664267
+              ],
+              [
+                117.208177,
+                40.694675
+              ],
+              [
+                117.117018,
+                40.70012
+              ],
+              [
+                117.11209,
+                40.707379
+              ],
+              [
+                117.012308,
+                40.693767
+              ],
+              [
+                116.964881,
+                40.709647
+              ],
+              [
+                116.926692,
+                40.745022
+              ],
+              [
+                116.924229,
+                40.773581
+              ],
+              [
+                116.848468,
+                40.839264
+              ],
+              [
+                116.81336,
+                40.848319
+              ],
+              [
+                116.759773,
+                40.889954
+              ],
+              [
+                116.713577,
+                40.909858
+              ],
+              [
+                116.722201,
+                40.927495
+              ],
+              [
+                116.677853,
+                40.970888
+              ],
+              [
+                116.698795,
+                41.021477
+              ],
+              [
+                116.688324,
+                41.044501
+              ],
+              [
+                116.647672,
+                41.059394
+              ],
+              [
+                116.615643,
+                41.053076
+              ],
+              [
+                116.623034,
+                41.021026
+              ],
+              [
+                116.598397,
+                40.974503
+              ],
+              [
+                116.5676,
+                40.992574
+              ],
+              [
+                116.519557,
+                40.98128
+              ],
+              [
+                116.519557,
+                40.98128
+              ],
+              [
+                116.455499,
+                40.980828
+              ],
+              [
+                116.447492,
+                40.953715
+              ],
+              [
+                116.477057,
+                40.899907
+              ],
+              [
+                116.398216,
+                40.90624
+              ],
+              [
+                116.370499,
+                40.94377
+              ],
+              [
+                116.339702,
+                40.929303
+              ],
+              [
+                116.334159,
+                40.90443
+              ],
+              [
+                116.438253,
+                40.81934
+              ],
+              [
+                116.46597,
+                40.774487
+              ],
+              [
+                116.453651,
+                40.765876
+              ],
+              [
+                116.316912,
+                40.772221
+              ],
+              [
+                116.311369,
+                40.754996
+              ],
+              [
+                116.273181,
+                40.762703
+              ],
+              [
+                116.247311,
+                40.791707
+              ],
+              [
+                116.22021,
+                40.744115
+              ],
+              [
+                116.204812,
+                40.740035
+              ],
+              [
+                116.171551,
+                40.695582
+              ],
+              [
+                116.162928,
+                40.662451
+              ],
+              [
+                116.133979,
+                40.666536
+              ],
+              [
+                116.09887,
+                40.630665
+              ],
+              [
+                116.005247,
+                40.583868
+              ],
+              [
+                115.982457,
+                40.578868
+              ],
+              [
+                115.971986,
+                40.6025
+              ],
+              [
+                115.907929,
+                40.617493
+              ],
+              [
+                115.885139,
+                40.595229
+              ],
+              [
+                115.827857,
+                40.587504
+              ],
+              [
+                115.819849,
+                40.55932
+              ],
+              [
+                115.784741,
+                40.55841
+              ],
+              [
+                115.755176,
+                40.540221
+              ],
+              [
+                115.736082,
+                40.503372
+              ],
+              [
+                115.781045,
+                40.49336
+              ],
+              [
+                115.771806,
+                40.443734
+              ],
+              [
+                115.864197,
+                40.359422
+              ],
+              [
+                115.917784,
+                40.354405
+              ],
+              [
+                115.95166,
+                40.281852
+              ],
+              [
+                115.968907,
+                40.264045
+              ],
+              [
+                115.89869,
+                40.234354
+              ],
+              [
+                115.870356,
+                40.185909
+              ],
+              [
+                115.855574,
+                40.188652
+              ],
+              [
+                115.847567,
+                40.147036
+              ],
+              [
+                115.806299,
+                40.15344
+              ],
+              [
+                115.773654,
+                40.176307
+              ],
+              [
+                115.75456,
+                40.145663
+              ],
+              [
+                115.75456,
+                40.145663
+              ],
+              [
+                115.599959,
+                40.119583
+              ],
+              [
+                115.59072,
+                40.096239
+              ],
+              [
+                115.527278,
+                40.076092
+              ],
+              [
+                115.485394,
+                40.040364
+              ],
+              [
+                115.454597,
+                40.029825
+              ],
+              [
+                115.450286,
+                39.992697
+              ],
+              [
+                115.428728,
+                39.984443
+              ],
+              [
+                115.426264,
+                39.950502
+              ],
+              [
+                115.481083,
+                39.935819
+              ],
+              [
+                115.522967,
+                39.899099
+              ],
+              [
+                115.515575,
+                39.892212
+              ],
+              [
+                115.515575,
+                39.892212
+              ],
+              [
+                115.526046,
+                39.87568
+              ],
+              [
+                115.514344,
+                39.837549
+              ],
+              [
+                115.567314,
+                39.816407
+              ],
+              [
+                115.552532,
+                39.794799
+              ],
+              [
+                115.50572,
+                39.784222
+              ],
+              [
+                115.483547,
+                39.798477
+              ],
+              [
+                115.483547,
+                39.798477
+              ],
+              [
+                115.443511,
+                39.785601
+              ],
+              [
+                115.439815,
+                39.752022
+              ],
+              [
+                115.486626,
+                39.741899
+              ],
+              [
+                115.491554,
+                39.670074
+              ],
+              [
+                115.478619,
+                39.650723
+              ],
+              [
+                115.478619,
+                39.650723
+              ],
+              [
+                115.522351,
+                39.640124
+              ],
+              [
+                115.518039,
+                39.597252
+              ],
+              [
+                115.545756,
+                39.618922
+              ],
+              [
+                115.587024,
+                39.589873
+              ],
+              [
+                115.633836,
+                39.599557
+              ],
+              [
+                115.633836,
+                39.599557
+              ],
+              [
+                115.667712,
+                39.615234
+              ],
+              [
+                115.698509,
+                39.577881
+              ],
+              [
+                115.698509,
+                39.577881
+              ],
+              [
+                115.699125,
+                39.570039
+              ],
+              [
+                115.699125,
+                39.570039
+              ],
+              [
+                115.716988,
+                39.56035
+              ],
+              [
+                115.716988,
+                39.56035
+              ],
+              [
+                115.718835,
+                39.553891
+              ],
+              [
+                115.718835,
+                39.553891
+              ],
+              [
+                115.720683,
+                39.551122
+              ],
+              [
+                115.720683,
+                39.551122
+              ],
+              [
+                115.722531,
+                39.5442
+              ],
+              [
+                115.721299,
+                39.543738
+              ],
+              [
+                115.722531,
+                39.5442
+              ],
+              [
+                115.722531,
+                39.543738
+              ],
+              [
+                115.721299,
+                39.543738
+              ],
+              [
+                115.722531,
+                39.543738
+              ],
+              [
+                115.724995,
+                39.5442
+              ],
+              [
+                115.724995,
+                39.5442
+              ],
+              [
+                115.738545,
+                39.540046
+              ],
+              [
+                115.738545,
+                39.539585
+              ],
+              [
+                115.738545,
+                39.540046
+              ],
+              [
+                115.738545,
+                39.539585
+              ],
+              [
+                115.752712,
+                39.515581
+              ],
+              [
+                115.806299,
+                39.510041
+              ],
+              [
+                115.806299,
+                39.510041
+              ],
+              [
+                115.821081,
+                39.522968
+              ],
+              [
+                115.821081,
+                39.522968
+              ],
+              [
+                115.828473,
+                39.541431
+              ],
+              [
+                115.867893,
+                39.546507
+              ],
+              [
+                115.867893,
+                39.546507
+              ],
+              [
+                115.91532,
+                39.582955
+              ],
+              [
+                115.91532,
+                39.582955
+              ],
+              [
+                115.910393,
+                39.600479
+              ],
+              [
+                115.910393,
+                39.600479
+              ],
+              [
+                115.957204,
+                39.560812
+              ],
+              [
+                115.978146,
+                39.595868
+              ],
+              [
+                115.995392,
+                39.576958
+              ],
+              [
+                116.026189,
+                39.587567
+              ],
+              [
+                116.036044,
+                39.571884
+              ],
+              [
+                116.09887,
+                39.575113
+              ],
+              [
+                116.130283,
+                39.567732
+              ],
+              [
+                116.151841,
+                39.583416
+              ],
+              [
+                116.198652,
+                39.589412
+              ],
+              [
+                116.240536,
+                39.564041
+              ],
+              [
+                116.257782,
+                39.500344
+              ],
+              [
+                116.307057,
+                39.488337
+              ],
+              [
+                116.337854,
+                39.455536
+              ],
+              [
+                116.361876,
+                39.455074
+              ],
+              [
+                116.361876,
+                39.455074
+              ],
+              [
+                116.434557,
+                39.442597
+              ],
+              [
+                116.454883,
+                39.453226
+              ],
+              [
+                116.444412,
+                39.482332
+              ],
+              [
+                116.411767,
+                39.482794
+              ],
+              [
+                116.401912,
+                39.528046
+              ],
+              [
+                116.443796,
+                39.510041
+              ],
+              [
+                116.437637,
+                39.526661
+              ],
+              [
+                116.478289,
+                39.535431
+              ],
+              [
+                116.473361,
+                39.552968
+              ],
+              [
+                116.50847,
+                39.551122
+              ],
+              [
+                116.524484,
+                39.596329
+              ],
+              [
+                116.592237,
+                39.621227
+              ],
+              [
+                116.592237,
+                39.621227
+              ],
+              [
+                116.620571,
+                39.601863
+              ],
+              [
+                116.664918,
+                39.605552
+              ],
+              [
+                116.723432,
+                39.59264
+              ],
+              [
+                116.724048,
+                39.59264
+              ],
+              [
+                116.723432,
+                39.59264
+              ],
+              [
+                116.724048,
+                39.59264
+              ],
+              [
+                116.726512,
+                39.595407
+              ],
+              [
+                116.726512,
+                39.595407
+              ],
+              [
+                116.709266,
+                39.618
+              ],
+              [
+                116.748686,
+                39.619844
+              ],
+              [
+                116.79057,
+                39.595868
+              ],
+              [
+                116.812128,
+                39.615695
+              ],
+              [
+                116.8497,
+                39.66777
+              ],
+              [
+                116.906366,
+                39.677444
+              ],
+              [
+                116.90575,
+                39.688037
+              ],
+              [
+                116.889736,
+                39.687576
+              ],
+              [
+                116.887272,
+                39.72533
+              ],
+              [
+                116.916837,
+                39.731314
+              ],
+              [
+                116.902055,
+                39.763523
+              ],
+              [
+                116.949482,
+                39.778703
+              ],
+              [
+                116.918069,
+                39.84628
+              ],
+              [
+                116.907598,
+                39.832494
+              ],
+              [
+                116.865714,
+                39.843982
+              ],
+              [
+                116.812128,
+                39.889916
+              ],
+              [
+                116.78441,
+                39.891294
+              ],
+              [
+                116.782563,
+                39.947749
+              ],
+              [
+                116.757925,
+                39.967934
+              ],
+              [
+                116.781331,
+                40.034866
+              ],
+              [
+                116.820135,
+                40.02845
+              ],
+              [
+                116.831222,
+                40.051359
+              ],
+              [
+                116.867562,
+                40.041739
+              ],
+              [
+                116.927924,
+                40.055024
+              ],
+              [
+                116.945171,
+                40.04128
+              ],
+              [
+                117.025243,
+                40.030283
+              ],
+              [
+                117.051728,
+                40.059605
+              ],
+              [
+                117.105315,
+                40.074261
+              ],
+              [
+                117.105315,
+                40.074261
+              ],
+              [
+                117.140423,
+                40.064185
+              ],
+              [
+                117.159517,
+                40.077008
+              ],
+              [
+                117.204481,
+                40.069681
+              ],
+              [
+                117.210024,
+                40.082045
+              ],
+              [
+                117.224191,
+                40.094865
+              ],
+              [
+                117.224191,
+                40.094865
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.274082,
+                40.105852
+              ],
+              [
+                117.307343,
+                40.136971
+              ],
+              [
+                117.349227,
+                40.136513
+              ],
+              [
+                117.367089,
+                40.172649
+              ],
+              [
+                117.367089,
+                40.173106
+              ],
+              [
+                117.367089,
+                40.173106
+              ],
+              [
+                117.367089,
+                40.172649
+              ],
+              [
+                117.383719,
+                40.188195
+              ],
+              [
+                117.389879,
+                40.227958
+              ],
+              [
+                117.351075,
+                40.229786
+              ],
+              [
+                117.331365,
+                40.289613
+              ],
+              [
+                117.295024,
+                40.2782
+              ],
+              [
+                117.271618,
+                40.325211
+              ],
+              [
+                117.271618,
+                40.325211
+              ],
+              [
+                117.243285,
+                40.369453
+              ],
+              [
+                117.226039,
+                40.368997
+              ],
+              [
+                117.234046,
+                40.417312
+              ],
+              [
+                117.263611,
+                40.442367
+              ],
+              [
+                117.208793,
+                40.501552
+              ],
+              [
+                117.262995,
+                40.512927
+              ],
+              [
+                117.247597,
+                40.539766
+              ],
+              [
+                117.269771,
+                40.560684
+              ],
+              [
+                117.348611,
+                40.581141
+              ],
+              [
+                117.348611,
+                40.581141
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 120000,
+        "name": "澶╂触甯�",
+        "center": [
+          117.190182,
+          39.125596
+        ],
+        "centroid": [
+          117.347043,
+          39.288036
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 1,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                117.765602,
+                39.400527
+              ],
+              [
+                117.846906,
+                39.407926
+              ],
+              [
+                117.871543,
+                39.411625
+              ],
+              [
+                117.870311,
+                39.455074
+              ],
+              [
+                117.899877,
+                39.474479
+              ],
+              [
+                117.912195,
+                39.517428
+              ],
+              [
+                117.912195,
+                39.517428
+              ],
+              [
+                117.904804,
+                39.533585
+              ],
+              [
+                117.933753,
+                39.574191
+              ],
+              [
+                117.868464,
+                39.59679
+              ],
+              [
+                117.829659,
+                39.589873
+              ],
+              [
+                117.766834,
+                39.598635
+              ],
+              [
+                117.753899,
+                39.579726
+              ],
+              [
+                117.753899,
+                39.579726
+              ],
+              [
+                117.745276,
+                39.547892
+              ],
+              [
+                117.715711,
+                39.529892
+              ],
+              [
+                117.707088,
+                39.576036
+              ],
+              [
+                117.684914,
+                39.58895
+              ],
+              [
+                117.654117,
+                39.575113
+              ],
+              [
+                117.637486,
+                39.603246
+              ],
+              [
+                117.66274,
+                39.636437
+              ],
+              [
+                117.668899,
+                39.666849
+              ],
+              [
+                117.627015,
+                39.703693
+              ],
+              [
+                117.57774,
+                39.726711
+              ],
+              [
+                117.595603,
+                39.74604
+              ],
+              [
+                117.56111,
+                39.754782
+              ],
+              [
+                117.546327,
+                39.775943
+              ],
+              [
+                117.561726,
+                39.799856
+              ],
+              [
+                117.529081,
+                39.859144
+              ],
+              [
+                117.529081,
+                39.859144
+              ],
+              [
+                117.508139,
+                39.901854
+              ],
+              [
+                117.508139,
+                39.901854
+              ],
+              [
+                117.512451,
+                39.90874
+              ],
+              [
+                117.512451,
+                39.90874
+              ],
+              [
+                117.513067,
+                39.910576
+              ],
+              [
+                117.513067,
+                39.910576
+              ],
+              [
+                117.514914,
+                39.946832
+              ],
+              [
+                117.534625,
+                39.954631
+              ],
+              [
+                117.546327,
+                39.999116
+              ],
+              [
+                117.594987,
+                39.994531
+              ],
+              [
+                117.594987,
+                39.994531
+              ],
+              [
+                117.614697,
+                39.97252
+              ],
+              [
+                117.671363,
+                39.973896
+              ],
+              [
+                117.691073,
+                39.984902
+              ],
+              [
+                117.756363,
+                39.965181
+              ],
+              [
+                117.781616,
+                39.966558
+              ],
+              [
+                117.781616,
+                39.966558
+              ],
+              [
+                117.795167,
+                39.996823
+              ],
+              [
+                117.795167,
+                39.996823
+              ],
+              [
+                117.793319,
+                40.005534
+              ],
+              [
+                117.793319,
+                40.005534
+              ],
+              [
+                117.768681,
+                40.022034
+              ],
+              [
+                117.768681,
+                40.022034
+              ],
+              [
+                117.744044,
+                40.018368
+              ],
+              [
+                117.74774,
+                40.047236
+              ],
+              [
+                117.776073,
+                40.059605
+              ],
+              [
+                117.752667,
+                40.081588
+              ],
+              [
+                117.71879,
+                40.082045
+              ],
+              [
+                117.71879,
+                40.082045
+              ],
+              [
+                117.675059,
+                40.082045
+              ],
+              [
+                117.655965,
+                40.109514
+              ],
+              [
+                117.655965,
+                40.109514
+              ],
+              [
+                117.654117,
+                40.114548
+              ],
+              [
+                117.654117,
+                40.114548
+              ],
+              [
+                117.651653,
+                40.122786
+              ],
+              [
+                117.651653,
+                40.122786
+              ],
+              [
+                117.613465,
+                40.158014
+              ],
+              [
+                117.613465,
+                40.158014
+              ],
+              [
+                117.609769,
+                40.160301
+              ],
+              [
+                117.609769,
+                40.160301
+              ],
+              [
+                117.576508,
+                40.178593
+              ],
+              [
+                117.571581,
+                40.219276
+              ],
+              [
+                117.548791,
+                40.232527
+              ],
+              [
+                117.505059,
+                40.227044
+              ],
+              [
+                117.450241,
+                40.252627
+              ],
+              [
+                117.415748,
+                40.248973
+              ],
+              [
+                117.389879,
+                40.227958
+              ],
+              [
+                117.383719,
+                40.188195
+              ],
+              [
+                117.367089,
+                40.172649
+              ],
+              [
+                117.367089,
+                40.173106
+              ],
+              [
+                117.367089,
+                40.173106
+              ],
+              [
+                117.367089,
+                40.172649
+              ],
+              [
+                117.349227,
+                40.136513
+              ],
+              [
+                117.307343,
+                40.136971
+              ],
+              [
+                117.274082,
+                40.105852
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.254988,
+                40.114548
+              ],
+              [
+                117.224191,
+                40.094865
+              ],
+              [
+                117.224191,
+                40.094865
+              ],
+              [
+                117.210024,
+                40.082045
+              ],
+              [
+                117.192162,
+                40.066475
+              ],
+              [
+                117.198322,
+                39.992697
+              ],
+              [
+                117.150894,
+                39.944996
+              ],
+              [
+                117.162597,
+                39.876598
+              ],
+              [
+                117.162597,
+                39.876598
+              ],
+              [
+                117.227887,
+                39.852712
+              ],
+              [
+                117.247597,
+                39.860981
+              ],
+              [
+                117.251908,
+                39.834332
+              ],
+              [
+                117.192162,
+                39.832953
+              ],
+              [
+                117.156438,
+                39.817326
+              ],
+              [
+                117.15767,
+                39.796638
+              ],
+              [
+                117.205713,
+                39.763984
+              ],
+              [
+                117.161981,
+                39.748801
+              ],
+              [
+                117.165061,
+                39.718886
+              ],
+              [
+                117.165061,
+                39.718886
+              ],
+              [
+                117.177996,
+                39.645194
+              ],
+              [
+                117.152742,
+                39.623532
+              ],
+              [
+                117.10901,
+                39.625375
+              ],
+              [
+                117.10901,
+                39.625375
+              ],
+              [
+                117.016004,
+                39.653949
+              ],
+              [
+                116.983359,
+                39.638742
+              ],
+              [
+                116.983359,
+                39.638742
+              ],
+              [
+                116.964265,
+                39.64335
+              ],
+              [
+                116.948866,
+                39.680668
+              ],
+              [
+                116.948866,
+                39.680668
+              ],
+              [
+                116.944555,
+                39.695405
+              ],
+              [
+                116.944555,
+                39.695405
+              ],
+              [
+                116.932236,
+                39.706456
+              ],
+              [
+                116.932236,
+                39.706456
+              ],
+              [
+                116.90575,
+                39.688037
+              ],
+              [
+                116.906366,
+                39.677444
+              ],
+              [
+                116.8497,
+                39.66777
+              ],
+              [
+                116.812128,
+                39.615695
+              ],
+              [
+                116.808432,
+                39.576497
+              ],
+              [
+                116.78749,
+                39.554352
+              ],
+              [
+                116.819519,
+                39.528507
+              ],
+              [
+                116.820751,
+                39.482332
+              ],
+              [
+                116.785026,
+                39.465702
+              ],
+              [
+                116.832454,
+                39.435664
+              ],
+              [
+                116.876185,
+                39.43474
+              ],
+              [
+                116.839845,
+                39.413474
+              ],
+              [
+                116.840461,
+                39.378326
+              ],
+              [
+                116.818287,
+                39.3737
+              ],
+              [
+                116.829374,
+                39.338994
+              ],
+              [
+                116.870642,
+                39.357506
+              ],
+              [
+                116.889736,
+                39.338068
+              ],
+              [
+                116.87249,
+                39.291304
+              ],
+              [
+                116.881729,
+                39.225966
+              ],
+              [
+                116.881729,
+                39.225966
+              ],
+              [
+                116.855859,
+                39.215766
+              ],
+              [
+                116.870026,
+                39.153607
+              ],
+              [
+                116.909446,
+                39.150822
+              ],
+              [
+                116.912526,
+                39.110898
+              ],
+              [
+                116.91191,
+                39.111362
+              ],
+              [
+                116.91191,
+                39.111362
+              ],
+              [
+                116.912526,
+                39.110898
+              ],
+              [
+                116.871874,
+                39.054688
+              ],
+              [
+                116.812744,
+                39.05097
+              ],
+              [
+                116.812744,
+                39.05097
+              ],
+              [
+                116.783179,
+                39.05097
+              ],
+              [
+                116.783179,
+                39.05097
+              ],
+              [
+                116.754229,
+                39.034701
+              ],
+              [
+                116.754229,
+                39.034701
+              ],
+              [
+                116.754845,
+                39.003084
+              ],
+              [
+                116.72836,
+                38.975174
+              ],
+              [
+                116.708034,
+                38.931892
+              ],
+              [
+                116.722201,
+                38.896968
+              ],
+              [
+                116.723432,
+                38.852706
+              ],
+              [
+                116.75115,
+                38.831264
+              ],
+              [
+                116.737599,
+                38.784629
+              ],
+              [
+                116.746222,
+                38.754299
+              ],
+              [
+                116.794265,
+                38.744498
+              ],
+              [
+                116.794265,
+                38.744498
+              ],
+              [
+                116.858939,
+                38.741231
+              ],
+              [
+                116.877417,
+                38.680522
+              ],
+              [
+                116.948866,
+                38.689398
+              ],
+              [
+                116.950714,
+                38.689398
+              ],
+              [
+                116.95133,
+                38.689398
+              ],
+              [
+                116.950714,
+                38.689398
+              ],
+              [
+                116.948866,
+                38.689398
+              ],
+              [
+                116.95133,
+                38.689398
+              ],
+              [
+                117.038793,
+                38.688464
+              ],
+              [
+                117.068358,
+                38.680522
+              ],
+              [
+                117.055424,
+                38.639398
+              ],
+              [
+                117.070822,
+                38.608072
+              ],
+              [
+                117.109626,
+                38.584685
+              ],
+              [
+                117.150894,
+                38.617892
+              ],
+              [
+                117.183539,
+                38.61836
+              ],
+              [
+                117.183539,
+                38.61836
+              ],
+              [
+                117.213104,
+                38.639866
+              ],
+              [
+                117.213104,
+                38.639866
+              ],
+              [
+                117.258684,
+                38.608072
+              ],
+              [
+                117.258684,
+                38.608072
+              ],
+              [
+                117.238358,
+                38.580943
+              ],
+              [
+                117.25314,
+                38.556143
+              ],
+              [
+                117.368937,
+                38.564566
+              ],
+              [
+                117.432379,
+                38.601524
+              ],
+              [
+                117.47919,
+                38.616489
+              ],
+              [
+                117.55803,
+                38.613683
+              ],
+              [
+                117.639334,
+                38.626776
+              ],
+              [
+                117.65658,
+                38.66043
+              ],
+              [
+                117.729261,
+                38.680055
+              ],
+              [
+                117.740964,
+                38.700141
+              ],
+              [
+                117.740964,
+                38.753833
+              ],
+              [
+                117.671363,
+                38.772032
+              ],
+              [
+                117.646725,
+                38.788827
+              ],
+              [
+                117.64611,
+                38.828933
+              ],
+              [
+                117.752051,
+                38.847579
+              ],
+              [
+                117.778536,
+                38.869016
+              ],
+              [
+                117.847522,
+                38.855502
+              ],
+              [
+                117.875855,
+                38.920252
+              ],
+              [
+                117.898029,
+                38.948649
+              ],
+              [
+                117.855529,
+                38.957492
+              ],
+              [
+                117.837667,
+                39.057011
+              ],
+              [
+                117.871543,
+                39.122506
+              ],
+              [
+                117.96455,
+                39.172631
+              ],
+              [
+                117.977485,
+                39.206028
+              ],
+              [
+                118.032919,
+                39.219939
+              ],
+              [
+                118.034767,
+                39.218548
+              ],
+              [
+                118.064948,
+                39.231065
+              ],
+              [
+                118.064948,
+                39.256094
+              ],
+              [
+                118.036615,
+                39.264898
+              ],
+              [
+                118.024296,
+                39.289451
+              ],
+              [
+                118.024296,
+                39.289451
+              ],
+              [
+                117.982412,
+                39.298714
+              ],
+              [
+                117.982412,
+                39.298714
+              ],
+              [
+                117.979333,
+                39.300566
+              ],
+              [
+                117.979333,
+                39.300566
+              ],
+              [
+                117.973173,
+                39.312143
+              ],
+              [
+                117.973173,
+                39.312143
+              ],
+              [
+                117.965782,
+                39.314921
+              ],
+              [
+                117.965782,
+                39.314921
+              ],
+              [
+                117.919587,
+                39.318162
+              ],
+              [
+                117.919587,
+                39.318162
+              ],
+              [
+                117.88879,
+                39.332051
+              ],
+              [
+                117.854913,
+                39.328348
+              ],
+              [
+                117.854297,
+                39.328348
+              ],
+              [
+                117.854913,
+                39.328348
+              ],
+              [
+                117.854297,
+                39.328348
+              ],
+              [
+                117.850601,
+                39.363984
+              ],
+              [
+                117.850601,
+                39.363984
+              ],
+              [
+                117.810565,
+                39.354729
+              ],
+              [
+                117.805022,
+                39.373237
+              ],
+              [
+                117.784696,
+                39.376938
+              ],
+              [
+                117.74466,
+                39.354729
+              ],
+              [
+                117.670747,
+                39.357969
+              ],
+              [
+                117.669515,
+                39.322792
+              ],
+              [
+                117.594987,
+                39.349176
+              ],
+              [
+                117.536472,
+                39.338068
+              ],
+              [
+                117.521074,
+                39.357043
+              ],
+              [
+                117.570965,
+                39.404689
+              ],
+              [
+                117.601146,
+                39.419485
+              ],
+              [
+                117.614081,
+                39.407001
+              ],
+              [
+                117.668899,
+                39.412087
+              ],
+              [
+                117.673211,
+                39.386652
+              ],
+              [
+                117.699696,
+                39.407463
+              ],
+              [
+                117.765602,
+                39.400527
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.805022,
+                39.373237
+              ],
+              [
+                117.852449,
+                39.380639
+              ],
+              [
+                117.846906,
+                39.407926
+              ],
+              [
+                117.765602,
+                39.400527
+              ],
+              [
+                117.784696,
+                39.376938
+              ],
+              [
+                117.805022,
+                39.373237
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 130000,
+        "name": "娌冲寳鐪�",
+        "center": [
+          114.502461,
+          38.045474
+        ],
+        "childrenNum": 11,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 2,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                117.467487,
+                40.649738
+              ],
+              [
+                117.412669,
+                40.605226
+              ],
+              [
+                117.429915,
+                40.576141
+              ],
+              [
+                117.389879,
+                40.561593
+              ],
+              [
+                117.348611,
+                40.581141
+              ],
+              [
+                117.348611,
+                40.581141
+              ],
+              [
+                117.269771,
+                40.560684
+              ],
+              [
+                117.247597,
+                40.539766
+              ],
+              [
+                117.262995,
+                40.512927
+              ],
+              [
+                117.208793,
+                40.501552
+              ],
+              [
+                117.263611,
+                40.442367
+              ],
+              [
+                117.234046,
+                40.417312
+              ],
+              [
+                117.226039,
+                40.368997
+              ],
+              [
+                117.243285,
+                40.369453
+              ],
+              [
+                117.271618,
+                40.325211
+              ],
+              [
+                117.271618,
+                40.325211
+              ],
+              [
+                117.295024,
+                40.2782
+              ],
+              [
+                117.331365,
+                40.289613
+              ],
+              [
+                117.351075,
+                40.229786
+              ],
+              [
+                117.389879,
+                40.227958
+              ],
+              [
+                117.415748,
+                40.248973
+              ],
+              [
+                117.450241,
+                40.252627
+              ],
+              [
+                117.505059,
+                40.227044
+              ],
+              [
+                117.548791,
+                40.232527
+              ],
+              [
+                117.571581,
+                40.219276
+              ],
+              [
+                117.576508,
+                40.178593
+              ],
+              [
+                117.609769,
+                40.160301
+              ],
+              [
+                117.609769,
+                40.160301
+              ],
+              [
+                117.613465,
+                40.158014
+              ],
+              [
+                117.613465,
+                40.158014
+              ],
+              [
+                117.651653,
+                40.122786
+              ],
+              [
+                117.651653,
+                40.122786
+              ],
+              [
+                117.654117,
+                40.114548
+              ],
+              [
+                117.654117,
+                40.114548
+              ],
+              [
+                117.655965,
+                40.109514
+              ],
+              [
+                117.655965,
+                40.109514
+              ],
+              [
+                117.675059,
+                40.082045
+              ],
+              [
+                117.71879,
+                40.082045
+              ],
+              [
+                117.71879,
+                40.082045
+              ],
+              [
+                117.752667,
+                40.081588
+              ],
+              [
+                117.776073,
+                40.059605
+              ],
+              [
+                117.74774,
+                40.047236
+              ],
+              [
+                117.744044,
+                40.018368
+              ],
+              [
+                117.768681,
+                40.022034
+              ],
+              [
+                117.768681,
+                40.022034
+              ],
+              [
+                117.793319,
+                40.005534
+              ],
+              [
+                117.793319,
+                40.005534
+              ],
+              [
+                117.795167,
+                39.996823
+              ],
+              [
+                117.795167,
+                39.996823
+              ],
+              [
+                117.781616,
+                39.966558
+              ],
+              [
+                117.781616,
+                39.966558
+              ],
+              [
+                117.756363,
+                39.965181
+              ],
+              [
+                117.691073,
+                39.984902
+              ],
+              [
+                117.671363,
+                39.973896
+              ],
+              [
+                117.614697,
+                39.97252
+              ],
+              [
+                117.594987,
+                39.994531
+              ],
+              [
+                117.594987,
+                39.994531
+              ],
+              [
+                117.546327,
+                39.999116
+              ],
+              [
+                117.534625,
+                39.954631
+              ],
+              [
+                117.514914,
+                39.946832
+              ],
+              [
+                117.513067,
+                39.910576
+              ],
+              [
+                117.513067,
+                39.910576
+              ],
+              [
+                117.512451,
+                39.90874
+              ],
+              [
+                117.512451,
+                39.90874
+              ],
+              [
+                117.508139,
+                39.901854
+              ],
+              [
+                117.508139,
+                39.901854
+              ],
+              [
+                117.529081,
+                39.859144
+              ],
+              [
+                117.529081,
+                39.859144
+              ],
+              [
+                117.561726,
+                39.799856
+              ],
+              [
+                117.546327,
+                39.775943
+              ],
+              [
+                117.56111,
+                39.754782
+              ],
+              [
+                117.595603,
+                39.74604
+              ],
+              [
+                117.57774,
+                39.726711
+              ],
+              [
+                117.627015,
+                39.703693
+              ],
+              [
+                117.668899,
+                39.666849
+              ],
+              [
+                117.66274,
+                39.636437
+              ],
+              [
+                117.637486,
+                39.603246
+              ],
+              [
+                117.654117,
+                39.575113
+              ],
+              [
+                117.684914,
+                39.58895
+              ],
+              [
+                117.707088,
+                39.576036
+              ],
+              [
+                117.715711,
+                39.529892
+              ],
+              [
+                117.745276,
+                39.547892
+              ],
+              [
+                117.753899,
+                39.579726
+              ],
+              [
+                117.753899,
+                39.579726
+              ],
+              [
+                117.766834,
+                39.598635
+              ],
+              [
+                117.829659,
+                39.589873
+              ],
+              [
+                117.868464,
+                39.59679
+              ],
+              [
+                117.933753,
+                39.574191
+              ],
+              [
+                117.904804,
+                39.533585
+              ],
+              [
+                117.912195,
+                39.517428
+              ],
+              [
+                117.912195,
+                39.517428
+              ],
+              [
+                117.899877,
+                39.474479
+              ],
+              [
+                117.870311,
+                39.455074
+              ],
+              [
+                117.871543,
+                39.411625
+              ],
+              [
+                117.846906,
+                39.407926
+              ],
+              [
+                117.852449,
+                39.380639
+              ],
+              [
+                117.805022,
+                39.373237
+              ],
+              [
+                117.810565,
+                39.354729
+              ],
+              [
+                117.850601,
+                39.363984
+              ],
+              [
+                117.850601,
+                39.363984
+              ],
+              [
+                117.854297,
+                39.328348
+              ],
+              [
+                117.854913,
+                39.328348
+              ],
+              [
+                117.854297,
+                39.328348
+              ],
+              [
+                117.854913,
+                39.328348
+              ],
+              [
+                117.88879,
+                39.332051
+              ],
+              [
+                117.919587,
+                39.318162
+              ],
+              [
+                117.919587,
+                39.318162
+              ],
+              [
+                117.965782,
+                39.314921
+              ],
+              [
+                117.965782,
+                39.314921
+              ],
+              [
+                117.973173,
+                39.312143
+              ],
+              [
+                117.973173,
+                39.312143
+              ],
+              [
+                117.979333,
+                39.300566
+              ],
+              [
+                117.979333,
+                39.300566
+              ],
+              [
+                117.982412,
+                39.298714
+              ],
+              [
+                117.982412,
+                39.298714
+              ],
+              [
+                118.024296,
+                39.289451
+              ],
+              [
+                118.024296,
+                39.289451
+              ],
+              [
+                118.036615,
+                39.264898
+              ],
+              [
+                118.064948,
+                39.256094
+              ],
+              [
+                118.064948,
+                39.231065
+              ],
+              [
+                118.034767,
+                39.218548
+              ],
+              [
+                118.026144,
+                39.201854
+              ],
+              [
+                118.070492,
+                39.213911
+              ],
+              [
+                118.077883,
+                39.201854
+              ],
+              [
+                118.12531,
+                39.182838
+              ],
+              [
+                118.162883,
+                39.136433
+              ],
+              [
+                118.1906,
+                39.080708
+              ],
+              [
+                118.225092,
+                39.034701
+              ],
+              [
+                118.319331,
+                39.009594
+              ],
+              [
+                118.366143,
+                39.016104
+              ],
+              [
+                118.377845,
+                38.971917
+              ],
+              [
+                118.491178,
+                38.909077
+              ],
+              [
+                118.539837,
+                38.910008
+              ],
+              [
+                118.604511,
+                38.971452
+              ],
+              [
+                118.570634,
+                38.999363
+              ],
+              [
+                118.533062,
+                39.090928
+              ],
+              [
+                118.588497,
+                39.107648
+              ],
+              [
+                118.578642,
+                39.130863
+              ],
+              [
+                118.637156,
+                39.157319
+              ],
+              [
+                118.76096,
+                39.133648
+              ],
+              [
+                118.814546,
+                39.138754
+              ],
+              [
+                118.857662,
+                39.162888
+              ],
+              [
+                118.897082,
+                39.151286
+              ],
+              [
+                118.920488,
+                39.171703
+              ],
+              [
+                118.951285,
+                39.178662
+              ],
+              [
+                118.896466,
+                39.139683
+              ],
+              [
+                118.890307,
+                39.118792
+              ],
+              [
+                118.926031,
+                39.123435
+              ],
+              [
+                118.97777,
+                39.163352
+              ],
+              [
+                119.023966,
+                39.187012
+              ],
+              [
+                119.038132,
+                39.211593
+              ],
+              [
+                119.096031,
+                39.24219
+              ],
+              [
+                119.121284,
+                39.281576
+              ],
+              [
+                119.185342,
+                39.342234
+              ],
+              [
+                119.272805,
+                39.363521
+              ],
+              [
+                119.317153,
+                39.4107
+              ],
+              [
+                119.316537,
+                39.437051
+              ],
+              [
+                119.269726,
+                39.498497
+              ],
+              [
+                119.366428,
+                39.734996
+              ],
+              [
+                119.474217,
+                39.813189
+              ],
+              [
+                119.536427,
+                39.809052
+              ],
+              [
+                119.520413,
+                39.840306
+              ],
+              [
+                119.540739,
+                39.888079
+              ],
+              [
+                119.588166,
+                39.910576
+              ],
+              [
+                119.620195,
+                39.904609
+              ],
+              [
+                119.642369,
+                39.925264
+              ],
+              [
+                119.681789,
+                39.922511
+              ],
+              [
+                119.726137,
+                39.940867
+              ],
+              [
+                119.787115,
+                39.950502
+              ],
+              [
+                119.820375,
+                39.979399
+              ],
+              [
+                119.842549,
+                39.956007
+              ],
+              [
+                119.872114,
+                39.960594
+              ],
+              [
+                119.854252,
+                39.98857
+              ],
+              [
+                119.845629,
+                40.000949
+              ],
+              [
+                119.845629,
+                40.000949
+              ],
+              [
+                119.854252,
+                40.033033
+              ],
+              [
+                119.81668,
+                40.050443
+              ],
+              [
+                119.81668,
+                40.050443
+              ],
+              [
+                119.787115,
+                40.041739
+              ],
+              [
+                119.787115,
+                40.041739
+              ],
+              [
+                119.783419,
+                40.046778
+              ],
+              [
+                119.783419,
+                40.046778
+              ],
+              [
+                119.772332,
+                40.08113
+              ],
+              [
+                119.736608,
+                40.104936
+              ],
+              [
+                119.760629,
+                40.136056
+              ],
+              [
+                119.745847,
+                40.207851
+              ],
+              [
+                119.716898,
+                40.195966
+              ],
+              [
+                119.671934,
+                40.23938
+              ],
+              [
+                119.639289,
+                40.231613
+              ],
+              [
+                119.639289,
+                40.231613
+              ],
+              [
+                119.651608,
+                40.271808
+              ],
+              [
+                119.598021,
+                40.334335
+              ],
+              [
+                119.586934,
+                40.375381
+              ],
+              [
+                119.604797,
+                40.455119
+              ],
+              [
+                119.553674,
+                40.502007
+              ],
+              [
+                119.572152,
+                40.523846
+              ],
+              [
+                119.559217,
+                40.547952
+              ],
+              [
+                119.503783,
+                40.553864
+              ],
+              [
+                119.477913,
+                40.533399
+              ],
+              [
+                119.429254,
+                40.540221
+              ],
+              [
+                119.30237,
+                40.530215
+              ],
+              [
+                119.256175,
+                40.543404
+              ],
+              [
+                119.22045,
+                40.569322
+              ],
+              [
+                119.230921,
+                40.603863
+              ],
+              [
+                119.177951,
+                40.609315
+              ],
+              [
+                119.162552,
+                40.600228
+              ],
+              [
+                119.14469,
+                40.632482
+              ],
+              [
+                119.184726,
+                40.680153
+              ],
+              [
+                119.165632,
+                40.69286
+              ],
+              [
+                119.115125,
+                40.666536
+              ],
+              [
+                119.054763,
+                40.664721
+              ],
+              [
+                119.028277,
+                40.692406
+              ],
+              [
+                119.011031,
+                40.687414
+              ],
+              [
+                118.96114,
+                40.72008
+              ],
+              [
+                118.950053,
+                40.747743
+              ],
+              [
+                118.895234,
+                40.75409
+              ],
+              [
+                118.907553,
+                40.775394
+              ],
+              [
+                118.878604,
+                40.783098
+              ],
+              [
+                118.845959,
+                40.822057
+              ],
+              [
+                118.873061,
+                40.847866
+              ],
+              [
+                118.90201,
+                40.960946
+              ],
+              [
+                118.916792,
+                40.969984
+              ],
+              [
+                118.977154,
+                40.959138
+              ],
+              [
+                118.977154,
+                40.959138
+              ],
+              [
+                119.00056,
+                40.967273
+              ],
+              [
+                119.013495,
+                41.007479
+              ],
+              [
+                118.951901,
+                41.018317
+              ],
+              [
+                118.937118,
+                41.052625
+              ],
+              [
+                118.964836,
+                41.079246
+              ],
+              [
+                119.037516,
+                41.067516
+              ],
+              [
+                119.080632,
+                41.095936
+              ],
+              [
+                119.081248,
+                41.131555
+              ],
+              [
+                119.126212,
+                41.138767
+              ],
+              [
+                119.189038,
+                41.198234
+              ],
+              [
+                119.169943,
+                41.222996
+              ],
+              [
+                119.204436,
+                41.222546
+              ],
+              [
+                119.209364,
+                41.244599
+              ],
+              [
+                119.2494,
+                41.279689
+              ],
+              [
+                119.239545,
+                41.31431
+              ],
+              [
+                119.211827,
+                41.308016
+              ],
+              [
+                119.197661,
+                41.282837
+              ],
+              [
+                119.168712,
+                41.294978
+              ],
+              [
+                119.092951,
+                41.293629
+              ],
+              [
+                118.980234,
+                41.305769
+              ],
+              [
+                118.949437,
+                41.317906
+              ],
+              [
+                118.890923,
+                41.300823
+              ],
+              [
+                118.844727,
+                41.342622
+              ],
+              [
+                118.843496,
+                41.374516
+              ],
+              [
+                118.770199,
+                41.352956
+              ],
+              [
+                118.741866,
+                41.324198
+              ],
+              [
+                118.677192,
+                41.35026
+              ],
+              [
+                118.629765,
+                41.346666
+              ],
+              [
+                118.528135,
+                41.355202
+              ],
+              [
+                118.412338,
+                41.331838
+              ],
+              [
+                118.380309,
+                41.312062
+              ],
+              [
+                118.348896,
+                41.342622
+              ],
+              [
+                118.361215,
+                41.384844
+              ],
+              [
+                118.348896,
+                41.428384
+              ],
+              [
+                118.327338,
+                41.450816
+              ],
+              [
+                118.271904,
+                41.471446
+              ],
+              [
+                118.315636,
+                41.512688
+              ],
+              [
+                118.302701,
+                41.55256
+              ],
+              [
+                118.215237,
+                41.59554
+              ],
+              [
+                118.206614,
+                41.650566
+              ],
+              [
+                118.159187,
+                41.67605
+              ],
+              [
+                118.155491,
+                41.712694
+              ],
+              [
+                118.132702,
+                41.733241
+              ],
+              [
+                118.140093,
+                41.784134
+              ],
+              [
+                118.178281,
+                41.814917
+              ],
+              [
+                118.236179,
+                41.80778
+              ],
+              [
+                118.247266,
+                41.773869
+              ],
+              [
+                118.29223,
+                41.772976
+              ],
+              [
+                118.335346,
+                41.845241
+              ],
+              [
+                118.340273,
+                41.87243
+              ],
+              [
+                118.268824,
+                41.930336
+              ],
+              [
+                118.306396,
+                41.940131
+              ],
+              [
+                118.313788,
+                41.98819
+              ],
+              [
+                118.291614,
+                42.007759
+              ],
+              [
+                118.239875,
+                42.024655
+              ],
+              [
+                118.286686,
+                42.033991
+              ],
+              [
+                118.296541,
+                42.057545
+              ],
+              [
+                118.27252,
+                42.083312
+              ],
+              [
+                118.239259,
+                42.092639
+              ],
+              [
+                118.212774,
+                42.081091
+              ],
+              [
+                118.220165,
+                42.058434
+              ],
+              [
+                118.194296,
+                42.031324
+              ],
+              [
+                118.116687,
+                42.037102
+              ],
+              [
+                118.155491,
+                42.081091
+              ],
+              [
+                118.097593,
+                42.105072
+              ],
+              [
+                118.089586,
+                42.12283
+              ],
+              [
+                118.106216,
+                42.172082
+              ],
+              [
+                118.033535,
+                42.199132
+              ],
+              [
+                117.977485,
+                42.229716
+              ],
+              [
+                117.974405,
+                42.25054
+              ],
+              [
+                118.047702,
+                42.280656
+              ],
+              [
+                118.060021,
+                42.298364
+              ],
+              [
+                118.008898,
+                42.346595
+              ],
+              [
+                118.024296,
+                42.385064
+              ],
+              [
+                117.997811,
+                42.416884
+              ],
+              [
+                117.874007,
+                42.510038
+              ],
+              [
+                117.856761,
+                42.539148
+              ],
+              [
+                117.797631,
+                42.585431
+              ],
+              [
+                117.801326,
+                42.612744
+              ],
+              [
+                117.779768,
+                42.61847
+              ],
+              [
+                117.708935,
+                42.588515
+              ],
+              [
+                117.667051,
+                42.582347
+              ],
+              [
+                117.60053,
+                42.603054
+              ],
+              [
+                117.537088,
+                42.603054
+              ],
+              [
+                117.530313,
+                42.590278
+              ],
+              [
+                117.475494,
+                42.602613
+              ],
+              [
+                117.435458,
+                42.585431
+              ],
+              [
+                117.434226,
+                42.557224
+              ],
+              [
+                117.387415,
+                42.517537
+              ],
+              [
+                117.387415,
+                42.517537
+              ],
+              [
+                117.410205,
+                42.519743
+              ],
+              [
+                117.413284,
+                42.471645
+              ],
+              [
+                117.390495,
+                42.461933
+              ],
+              [
+                117.332596,
+                42.46105
+              ],
+              [
+                117.332596,
+                42.46105
+              ],
+              [
+                117.275314,
+                42.481797
+              ],
+              [
+                117.275314,
+                42.481797
+              ],
+              [
+                117.188467,
+                42.468114
+              ],
+              [
+                117.188467,
+                42.468114
+              ],
+              [
+                117.135496,
+                42.468996
+              ],
+              [
+                117.09546,
+                42.484004
+              ],
+              [
+                117.080061,
+                42.463699
+              ],
+              [
+                117.080061,
+                42.463699
+              ],
+              [
+                117.01662,
+                42.456193
+              ],
+              [
+                117.01662,
+                42.456193
+              ],
+              [
+                117.009228,
+                42.44957
+              ],
+              [
+                117.009228,
+                42.44957
+              ],
+              [
+                117.005533,
+                42.43367
+              ],
+              [
+                117.005533,
+                42.43367
+              ],
+              [
+                116.99075,
+                42.425719
+              ],
+              [
+                116.99075,
+                42.425719
+              ],
+              [
+                116.974736,
+                42.426603
+              ],
+              [
+                116.974736,
+                42.426603
+              ],
+              [
+                116.97104,
+                42.427486
+              ],
+              [
+                116.97104,
+                42.427486
+              ],
+              [
+                116.944555,
+                42.415116
+              ],
+              [
+                116.944555,
+                42.415116
+              ],
+              [
+                116.936547,
+                42.410256
+              ],
+              [
+                116.936547,
+                42.410256
+              ],
+              [
+                116.921765,
+                42.403628
+              ],
+              [
+                116.921765,
+                42.403628
+              ],
+              [
+                116.910062,
+                42.395231
+              ],
+              [
+                116.910062,
+                42.395231
+              ],
+              [
+                116.910678,
+                42.394789
+              ],
+              [
+                116.910678,
+                42.394789
+              ],
+              [
+                116.886656,
+                42.366496
+              ],
+              [
+                116.897743,
+                42.297479
+              ],
+              [
+                116.918685,
+                42.229716
+              ],
+              [
+                116.903287,
+                42.190708
+              ],
+              [
+                116.789338,
+                42.200462
+              ],
+              [
+                116.825062,
+                42.155669
+              ],
+              [
+                116.850316,
+                42.156556
+              ],
+              [
+                116.890352,
+                42.092639
+              ],
+              [
+                116.879881,
+                42.018431
+              ],
+              [
+                116.796113,
+                41.977958
+              ],
+              [
+                116.748686,
+                41.984186
+              ],
+              [
+                116.727744,
+                41.951259
+              ],
+              [
+                116.66923,
+                41.947698
+              ],
+              [
+                116.639049,
+                41.929891
+              ],
+              [
+                116.597165,
+                41.935679
+              ],
+              [
+                116.553433,
+                41.928555
+              ],
+              [
+                116.510933,
+                41.974399
+              ],
+              [
+                116.4826,
+                41.975734
+              ],
+              [
+                116.453651,
+                41.945917
+              ],
+              [
+                116.393289,
+                41.942802
+              ],
+              [
+                116.414231,
+                41.982407
+              ],
+              [
+                116.373579,
+                42.009983
+              ],
+              [
+                116.310137,
+                41.997086
+              ],
+              [
+                116.298434,
+                41.96817
+              ],
+              [
+                116.223906,
+                41.932562
+              ],
+              [
+                116.212819,
+                41.885352
+              ],
+              [
+                116.194341,
+                41.861734
+              ],
+              [
+                116.122892,
+                41.861734
+              ],
+              [
+                116.106877,
+                41.831419
+              ],
+              [
+                116.129051,
+                41.805996
+              ],
+              [
+                116.09887,
+                41.776547
+              ],
+              [
+                116.034196,
+                41.782795
+              ],
+              [
+                116.007095,
+                41.79752
+              ],
+              [
+                116.007095,
+                41.797966
+              ],
+              [
+                116.007095,
+                41.79752
+              ],
+              [
+                116.007095,
+                41.797966
+              ],
+              [
+                115.994776,
+                41.828743
+              ],
+              [
+                115.954124,
+                41.874213
+              ],
+              [
+                115.916552,
+                41.945027
+              ],
+              [
+                115.85311,
+                41.927665
+              ],
+              [
+                115.834632,
+                41.93835
+              ],
+              [
+                115.811226,
+                41.912525
+              ],
+              [
+                115.726227,
+                41.870202
+              ],
+              [
+                115.688038,
+                41.867528
+              ],
+              [
+                115.654162,
+                41.829189
+              ],
+              [
+                115.57409,
+                41.80555
+              ],
+              [
+                115.519887,
+                41.76762
+              ],
+              [
+                115.488474,
+                41.760924
+              ],
+              [
+                115.42996,
+                41.728775
+              ],
+              [
+                115.346808,
+                41.712247
+              ],
+              [
+                115.319091,
+                41.691693
+              ],
+              [
+                115.360975,
+                41.661297
+              ],
+              [
+                115.345576,
+                41.635807
+              ],
+              [
+                115.377605,
+                41.603148
+              ],
+              [
+                115.310468,
+                41.592854
+              ],
+              [
+                115.290142,
+                41.622835
+              ],
+              [
+                115.26612,
+                41.616124
+              ],
+              [
+                115.256881,
+                41.580768
+              ],
+              [
+                115.20391,
+                41.571367
+              ],
+              [
+                115.195287,
+                41.602253
+              ],
+              [
+                115.0992,
+                41.62373
+              ],
+              [
+                115.056085,
+                41.602253
+              ],
+              [
+                115.016049,
+                41.615229
+              ],
+              [
+                114.860832,
+                41.60091
+              ],
+              [
+                114.895325,
+                41.636255
+              ],
+              [
+                114.902716,
+                41.695715
+              ],
+              [
+                114.89594,
+                41.76762
+              ],
+              [
+                114.868839,
+                41.813579
+              ],
+              [
+                114.922426,
+                41.825175
+              ],
+              [
+                114.939056,
+                41.846132
+              ],
+              [
+                114.923658,
+                41.871093
+              ],
+              [
+                114.915035,
+                41.960605
+              ],
+              [
+                114.9021,
+                42.015763
+              ],
+              [
+                114.860832,
+                42.054879
+              ],
+              [
+                114.86268,
+                42.097967
+              ],
+              [
+                114.825723,
+                42.139695
+              ],
+              [
+                114.79431,
+                42.149457
+              ],
+              [
+                114.789383,
+                42.130819
+              ],
+              [
+                114.75489,
+                42.115727
+              ],
+              [
+                114.675434,
+                42.12061
+              ],
+              [
+                114.647717,
+                42.109512
+              ],
+              [
+                114.560254,
+                42.132595
+              ],
+              [
+                114.510978,
+                42.110844
+              ],
+              [
+                114.502355,
+                42.06732
+              ],
+              [
+                114.480181,
+                42.064654
+              ],
+              [
+                114.467863,
+                42.025989
+              ],
+              [
+                114.511594,
+                41.981962
+              ],
+              [
+                114.478334,
+                41.951704
+              ],
+              [
+                114.419203,
+                41.942356
+              ],
+              [
+                114.352066,
+                41.953484
+              ],
+              [
+                114.343443,
+                41.926774
+              ],
+              [
+                114.282465,
+                41.863517
+              ],
+              [
+                114.200545,
+                41.789934
+              ],
+              [
+                114.215328,
+                41.75646
+              ],
+              [
+                114.206704,
+                41.7386
+              ],
+              [
+                114.237501,
+                41.698843
+              ],
+              [
+                114.215328,
+                41.68499
+              ],
+              [
+                114.259059,
+                41.623282
+              ],
+              [
+                114.226414,
+                41.616572
+              ],
+              [
+                114.221487,
+                41.582111
+              ],
+              [
+                114.230726,
+                41.513584
+              ],
+              [
+                114.101379,
+                41.537779
+              ],
+              [
+                114.032394,
+                41.529715
+              ],
+              [
+                113.976959,
+                41.505966
+              ],
+              [
+                113.953553,
+                41.483553
+              ],
+              [
+                113.933227,
+                41.487139
+              ],
+              [
+                113.919677,
+                41.454404
+              ],
+              [
+                113.877793,
+                41.431076
+              ],
+              [
+                113.871017,
+                41.413126
+              ],
+              [
+                113.94493,
+                41.392477
+              ],
+              [
+                113.92522,
+                41.325546
+              ],
+              [
+                113.899351,
+                41.316108
+              ],
+              [
+                113.914749,
+                41.294529
+              ],
+              [
+                113.95109,
+                41.282837
+              ],
+              [
+                113.971416,
+                41.239649
+              ],
+              [
+                113.992357,
+                41.269794
+              ],
+              [
+                114.016379,
+                41.231999
+              ],
+              [
+                113.996669,
+                41.19238
+              ],
+              [
+                113.960945,
+                41.171211
+              ],
+              [
+                113.920293,
+                41.172112
+              ],
+              [
+                113.877793,
+                41.115777
+              ],
+              [
+                113.819279,
+                41.09774
+              ],
+              [
+                113.868554,
+                41.06887
+              ],
+              [
+                113.973263,
+                40.983087
+              ],
+              [
+                113.994821,
+                40.938798
+              ],
+              [
+                114.057647,
+                40.925234
+              ],
+              [
+                114.041633,
+                40.917546
+              ],
+              [
+                114.055183,
+                40.867782
+              ],
+              [
+                114.073661,
+                40.857372
+              ],
+              [
+                114.044712,
+                40.830661
+              ],
+              [
+                114.080437,
+                40.790348
+              ],
+              [
+                114.104458,
+                40.797597
+              ],
+              [
+                114.103227,
+                40.770861
+              ],
+              [
+                114.134639,
+                40.737314
+              ],
+              [
+                114.162357,
+                40.71373
+              ],
+              [
+                114.183299,
+                40.67153
+              ],
+              [
+                114.236269,
+                40.607043
+              ],
+              [
+                114.283081,
+                40.590685
+              ],
+              [
+                114.273842,
+                40.552954
+              ],
+              [
+                114.293552,
+                40.55159
+              ],
+              [
+                114.282465,
+                40.494725
+              ],
+              [
+                114.267066,
+                40.474242
+              ],
+              [
+                114.299711,
+                40.44009
+              ],
+              [
+                114.286161,
+                40.425057
+              ],
+              [
+                114.31203,
+                40.372645
+              ],
+              [
+                114.381015,
+                40.36307
+              ],
+              [
+                114.390254,
+                40.351213
+              ],
+              [
+                114.438914,
+                40.371733
+              ],
+              [
+                114.481413,
+                40.34802
+              ],
+              [
+                114.530688,
+                40.345283
+              ],
+              [
+                114.510978,
+                40.302851
+              ],
+              [
+                114.46971,
+                40.268155
+              ],
+              [
+                114.406269,
+                40.246232
+              ],
+              [
+                114.362537,
+                40.249886
+              ],
+              [
+                114.292936,
+                40.230242
+              ],
+              [
+                114.255364,
+                40.236182
+              ],
+              [
+                114.235654,
+                40.198252
+              ],
+              [
+                114.180219,
+                40.191395
+              ],
+              [
+                114.135871,
+                40.175392
+              ],
+              [
+                114.097683,
+                40.193681
+              ],
+              [
+                114.073046,
+                40.168533
+              ],
+              [
+                114.073046,
+                40.168533
+              ],
+              [
+                114.101995,
+                40.099901
+              ],
+              [
+                114.086596,
+                40.071513
+              ],
+              [
+                114.045944,
+                40.056856
+              ],
+              [
+                114.018227,
+                40.103563
+              ],
+              [
+                113.989278,
+                40.11226
+              ],
+              [
+                113.959097,
+                40.033491
+              ],
+              [
+                113.910438,
+                40.015618
+              ],
+              [
+                114.029314,
+                39.985819
+              ],
+              [
+                114.028082,
+                39.959218
+              ],
+              [
+                114.047176,
+                39.916085
+              ],
+              [
+                114.067502,
+                39.922511
+              ],
+              [
+                114.17406,
+                39.897722
+              ],
+              [
+                114.212248,
+                39.918839
+              ],
+              [
+                114.229494,
+                39.899558
+              ],
+              [
+                114.204241,
+                39.885324
+              ],
+              [
+                114.215943,
+                39.8619
+              ],
+              [
+                114.286776,
+                39.871087
+              ],
+              [
+                114.285545,
+                39.858225
+              ],
+              [
+                114.395182,
+                39.867412
+              ],
+              [
+                114.406885,
+                39.833413
+              ],
+              [
+                114.390254,
+                39.819165
+              ],
+              [
+                114.41674,
+                39.775943
+              ],
+              [
+                114.409964,
+                39.761683
+              ],
+              [
+                114.408117,
+                39.652106
+              ],
+              [
+                114.431522,
+                39.613851
+              ],
+              [
+                114.49558,
+                39.608318
+              ],
+              [
+                114.51529,
+                39.564964
+              ],
+              [
+                114.568877,
+                39.573729
+              ],
+              [
+                114.532536,
+                39.486027
+              ],
+              [
+                114.501739,
+                39.476789
+              ],
+              [
+                114.496812,
+                39.438437
+              ],
+              [
+                114.469095,
+                39.400989
+              ],
+              [
+                114.466631,
+                39.329736
+              ],
+              [
+                114.430906,
+                39.307513
+              ],
+              [
+                114.437066,
+                39.259337
+              ],
+              [
+                114.416124,
+                39.242654
+              ],
+              [
+                114.47587,
+                39.21623
+              ],
+              [
+                114.443841,
+                39.174023
+              ],
+              [
+                114.388406,
+                39.176807
+              ],
+              [
+                114.360689,
+                39.134112
+              ],
+              [
+                114.369928,
+                39.107648
+              ],
+              [
+                114.345907,
+                39.075133
+              ],
+              [
+                114.252284,
+                39.073739
+              ],
+              [
+                114.180835,
+                39.049111
+              ],
+              [
+                114.157429,
+                39.061194
+              ],
+              [
+                114.10877,
+                39.052364
+              ],
+              [
+                114.082901,
+                39.09325
+              ],
+              [
+                114.082901,
+                39.09325
+              ],
+              [
+                114.064422,
+                39.094179
+              ],
+              [
+                114.050872,
+                39.135969
+              ],
+              [
+                114.006524,
+                39.122971
+              ],
+              [
+                113.994821,
+                39.095572
+              ],
+              [
+                113.961561,
+                39.100681
+              ],
+              [
+                113.930148,
+                39.063517
+              ],
+              [
+                113.898119,
+                39.067699
+              ],
+              [
+                113.80696,
+                38.989595
+              ],
+              [
+                113.776779,
+                38.986804
+              ],
+              [
+                113.76754,
+                38.959819
+              ],
+              [
+                113.776163,
+                38.885788
+              ],
+              [
+                113.795257,
+                38.860628
+              ],
+              [
+                113.855619,
+                38.828933
+              ],
+              [
+                113.836525,
+                38.795824
+              ],
+              [
+                113.839605,
+                38.7585
+              ],
+              [
+                113.802648,
+                38.763166
+              ],
+              [
+                113.775547,
+                38.709949
+              ],
+              [
+                113.720728,
+                38.713218
+              ],
+              [
+                113.70225,
+                38.651551
+              ],
+              [
+                113.612939,
+                38.645942
+              ],
+              [
+                113.603084,
+                38.587024
+              ],
+              [
+                113.561816,
+                38.558483
+              ],
+              [
+                113.546417,
+                38.492936
+              ],
+              [
+                113.583374,
+                38.459671
+              ],
+              [
+                113.537794,
+                38.417952
+              ],
+              [
+                113.525475,
+                38.383245
+              ],
+              [
+                113.557504,
+                38.343359
+              ],
+              [
+                113.54457,
+                38.270569
+              ],
+              [
+                113.570439,
+                38.237202
+              ],
+              [
+                113.598772,
+                38.22733
+              ],
+              [
+                113.64312,
+                38.232031
+              ],
+              [
+                113.678844,
+                38.20523
+              ],
+              [
+                113.711489,
+                38.213695
+              ],
+              [
+                113.720728,
+                38.174656
+              ],
+              [
+                113.797105,
+                38.162894
+              ],
+              [
+                113.831597,
+                38.16854
+              ],
+              [
+                113.811271,
+                38.117707
+              ],
+              [
+                113.876561,
+                38.055059
+              ],
+              [
+                113.872249,
+                37.990471
+              ],
+              [
+                113.901198,
+                37.984811
+              ],
+              [
+                113.936307,
+                37.922993
+              ],
+              [
+                113.959097,
+                37.906468
+              ],
+              [
+                113.976959,
+                37.816696
+              ],
+              [
+                114.006524,
+                37.813386
+              ],
+              [
+                114.044712,
+                37.761834
+              ],
+              [
+                113.996669,
+                37.730128
+              ],
+              [
+                113.993589,
+                37.706932
+              ],
+              [
+                114.068118,
+                37.721608
+              ],
+              [
+                114.12848,
+                37.698409
+              ],
+              [
+                114.139567,
+                37.675676
+              ],
+              [
+                114.115545,
+                37.619761
+              ],
+              [
+                114.118625,
+                37.59084
+              ],
+              [
+                114.036705,
+                37.494037
+              ],
+              [
+                114.014531,
+                37.42468
+              ],
+              [
+                113.973879,
+                37.40329
+              ],
+              [
+                113.962792,
+                37.355734
+              ],
+              [
+                113.90243,
+                37.310052
+              ],
+              [
+                113.886416,
+                37.239095
+              ],
+              [
+                113.853155,
+                37.215269
+              ],
+              [
+                113.832213,
+                37.167594
+              ],
+              [
+                113.773083,
+                37.151855
+              ],
+              [
+                113.773699,
+                37.107004
+              ],
+              [
+                113.758301,
+                37.075497
+              ],
+              [
+                113.788482,
+                37.059739
+              ],
+              [
+                113.771851,
+                37.016745
+              ],
+              [
+                113.791561,
+                36.98759
+              ],
+              [
+                113.76138,
+                36.956034
+              ],
+              [
+                113.792793,
+                36.894796
+              ],
+              [
+                113.773083,
+                36.85506
+              ],
+              [
+                113.731815,
+                36.858891
+              ],
+              [
+                113.731815,
+                36.878521
+              ],
+              [
+                113.696707,
+                36.882351
+              ],
+              [
+                113.676381,
+                36.855539
+              ],
+              [
+                113.680692,
+                36.789907
+              ],
+              [
+                113.600004,
+                36.752995
+              ],
+              [
+                113.549497,
+                36.752515
+              ],
+              [
+                113.535946,
+                36.732373
+              ],
+              [
+                113.499606,
+                36.740527
+              ],
+              [
+                113.465113,
+                36.707908
+              ],
+              [
+                113.506997,
+                36.705029
+              ],
+              [
+                113.476816,
+                36.655114
+              ],
+              [
+                113.486671,
+                36.635427
+              ],
+              [
+                113.54457,
+                36.62342
+              ],
+              [
+                113.539642,
+                36.594116
+              ],
+              [
+                113.569823,
+                36.585947
+              ],
+              [
+                113.588917,
+                36.547974
+              ],
+              [
+                113.559968,
+                36.528741
+              ],
+              [
+                113.554425,
+                36.494589
+              ],
+              [
+                113.587069,
+                36.460904
+              ],
+              [
+                113.635729,
+                36.451277
+              ],
+              [
+                113.670221,
+                36.425278
+              ],
+              [
+                113.708409,
+                36.423352
+              ],
+              [
+                113.731199,
+                36.363135
+              ],
+              [
+                113.755221,
+                36.366026
+              ],
+              [
+                113.813119,
+                36.332285
+              ],
+              [
+                113.856851,
+                36.329392
+              ],
+              [
+                113.84946,
+                36.347711
+              ],
+              [
+                113.882104,
+                36.353977
+              ],
+              [
+                113.911054,
+                36.314927
+              ],
+              [
+                113.962792,
+                36.353977
+              ],
+              [
+                113.981887,
+                36.31782
+              ],
+              [
+                114.002828,
+                36.334214
+              ],
+              [
+                114.056415,
+                36.329392
+              ],
+              [
+                114.04348,
+                36.303353
+              ],
+              [
+                114.080437,
+                36.269585
+              ],
+              [
+                114.129096,
+                36.280199
+              ],
+              [
+                114.175907,
+                36.264759
+              ],
+              [
+                114.170364,
+                36.245938
+              ],
+              [
+                114.170364,
+                36.245938
+              ],
+              [
+                114.203009,
+                36.245456
+              ],
+              [
+                114.2104,
+                36.272962
+              ],
+              [
+                114.241197,
+                36.251247
+              ],
+              [
+                114.257827,
+                36.263794
+              ],
+              [
+                114.299095,
+                36.245938
+              ],
+              [
+                114.345291,
+                36.255591
+              ],
+              [
+                114.356378,
+                36.230492
+              ],
+              [
+                114.408117,
+                36.224699
+              ],
+              [
+                114.417356,
+                36.205868
+              ],
+              [
+                114.466015,
+                36.197658
+              ],
+              [
+                114.480181,
+                36.177855
+              ],
+              [
+                114.533152,
+                36.171575
+              ],
+              [
+                114.586739,
+                36.141133
+              ],
+              [
+                114.588587,
+                36.118414
+              ],
+              [
+                114.640326,
+                36.137266
+              ],
+              [
+                114.720398,
+                36.140166
+              ],
+              [
+                114.734564,
+                36.15563
+              ],
+              [
+                114.771521,
+                36.124699
+              ],
+              [
+                114.857752,
+                36.127599
+              ],
+              [
+                114.858368,
+                36.144516
+              ],
+              [
+                114.912571,
+                36.140649
+              ],
+              [
+                114.926737,
+                36.089403
+              ],
+              [
+                114.914419,
+                36.052155
+              ],
+              [
+                114.998186,
+                36.069572
+              ],
+              [
+                115.04623,
+                36.112613
+              ],
+              [
+                115.048693,
+                36.161912
+              ],
+              [
+                115.06286,
+                36.178338
+              ],
+              [
+                115.104744,
+                36.172058
+              ],
+              [
+                115.12507,
+                36.209731
+              ],
+              [
+                115.1842,
+                36.193312
+              ],
+              [
+                115.201446,
+                36.210214
+              ],
+              [
+                115.201446,
+                36.210214
+              ],
+              [
+                115.202678,
+                36.209248
+              ],
+              [
+                115.202678,
+                36.209248
+              ],
+              [
+                115.202678,
+                36.208765
+              ],
+              [
+                115.202678,
+                36.208765
+              ],
+              [
+                115.242098,
+                36.19138
+              ],
+              [
+                115.279055,
+                36.13775
+              ],
+              [
+                115.30246,
+                36.127599
+              ],
+              [
+                115.312931,
+                36.088436
+              ],
+              [
+                115.365902,
+                36.099074
+              ],
+              [
+                115.376989,
+                36.128083
+              ],
+              [
+                115.450902,
+                36.152248
+              ],
+              [
+                115.465068,
+                36.170125
+              ],
+              [
+                115.483547,
+                36.148865
+              ],
+              [
+                115.474923,
+                36.248352
+              ],
+              [
+                115.466916,
+                36.258969
+              ],
+              [
+                115.466916,
+                36.258969
+              ],
+              [
+                115.462605,
+                36.276339
+              ],
+              [
+                115.417025,
+                36.292742
+              ],
+              [
+                115.423185,
+                36.32216
+              ],
+              [
+                115.366518,
+                36.30914
+              ],
+              [
+                115.368982,
+                36.342409
+              ],
+              [
+                115.340033,
+                36.398307
+              ],
+              [
+                115.297533,
+                36.413239
+              ],
+              [
+                115.317243,
+                36.454166
+              ],
+              [
+                115.291374,
+                36.460423
+              ],
+              [
+                115.272895,
+                36.497476
+              ],
+              [
+                115.33141,
+                36.550378
+              ],
+              [
+                115.355431,
+                36.627262
+              ],
+              [
+                115.365902,
+                36.621979
+              ],
+              [
+                115.420105,
+                36.686795
+              ],
+              [
+                115.451518,
+                36.702151
+              ],
+              [
+                115.479851,
+                36.760187
+              ],
+              [
+                115.524815,
+                36.763543
+              ],
+              [
+                115.683727,
+                36.808117
+              ],
+              [
+                115.71206,
+                36.883308
+              ],
+              [
+                115.75764,
+                36.902453
+              ],
+              [
+                115.79706,
+                36.968945
+              ],
+              [
+                115.776734,
+                36.992848
+              ],
+              [
+                115.85619,
+                37.060694
+              ],
+              [
+                115.888219,
+                37.112254
+              ],
+              [
+                115.879596,
+                37.150901
+              ],
+              [
+                115.91224,
+                37.177132
+              ],
+              [
+                115.909777,
+                37.20669
+              ],
+              [
+                115.969523,
+                37.239572
+              ],
+              [
+                115.975682,
+                37.337179
+              ],
+              [
+                116.024341,
+                37.360015
+              ],
+              [
+                116.085935,
+                37.373809
+              ],
+              [
+                116.106261,
+                37.368577
+              ],
+              [
+                116.169087,
+                37.384271
+              ],
+              [
+                116.193109,
+                37.365723
+              ],
+              [
+                116.236224,
+                37.361442
+              ],
+              [
+                116.2855,
+                37.404241
+              ],
+              [
+                116.226369,
+                37.428007
+              ],
+              [
+                116.243,
+                37.447965
+              ],
+              [
+                116.224522,
+                37.479791
+              ],
+              [
+                116.240536,
+                37.489764
+              ],
+              [
+                116.240536,
+                37.489764
+              ],
+              [
+                116.27626,
+                37.466967
+              ],
+              [
+                116.290427,
+                37.484065
+              ],
+              [
+                116.278724,
+                37.524895
+              ],
+              [
+                116.295355,
+                37.554316
+              ],
+              [
+                116.336007,
+                37.581355
+              ],
+              [
+                116.36742,
+                37.566177
+              ],
+              [
+                116.379738,
+                37.522047
+              ],
+              [
+                116.38097,
+                37.522522
+              ],
+              [
+                116.379738,
+                37.522047
+              ],
+              [
+                116.38097,
+                37.522522
+              ],
+              [
+                116.433941,
+                37.473142
+              ],
+              [
+                116.448108,
+                37.503059
+              ],
+              [
+                116.4826,
+                37.521573
+              ],
+              [
+                116.575607,
+                37.610754
+              ],
+              [
+                116.604556,
+                37.624975
+              ],
+              [
+                116.66307,
+                37.686096
+              ],
+              [
+                116.679085,
+                37.728708
+              ],
+              [
+                116.724664,
+                37.744327
+              ],
+              [
+                116.753613,
+                37.77035
+              ],
+              [
+                116.753613,
+                37.793054
+              ],
+              [
+                116.804736,
+                37.848837
+              ],
+              [
+                116.837997,
+                37.835132
+              ],
+              [
+                116.919301,
+                37.846002
+              ],
+              [
+                117.027091,
+                37.832296
+              ],
+              [
+                117.074518,
+                37.848837
+              ],
+              [
+                117.150278,
+                37.839385
+              ],
+              [
+                117.185387,
+                37.849783
+              ],
+              [
+                117.271618,
+                37.839858
+              ],
+              [
+                117.320278,
+                37.861596
+              ],
+              [
+                117.400966,
+                37.844584
+              ],
+              [
+                117.438538,
+                37.854035
+              ],
+              [
+                117.481038,
+                37.914967
+              ],
+              [
+                117.513067,
+                37.94329
+              ],
+              [
+                117.524154,
+                37.989527
+              ],
+              [
+                117.557414,
+                38.046105
+              ],
+              [
+                117.557414,
+                38.046105
+              ],
+              [
+                117.586979,
+                38.071551
+              ],
+              [
+                117.704624,
+                38.076262
+              ],
+              [
+                117.746508,
+                38.12524
+              ],
+              [
+                117.771145,
+                38.134655
+              ],
+              [
+                117.766834,
+                38.158658
+              ],
+              [
+                117.789007,
+                38.180772
+              ],
+              [
+                117.808718,
+                38.22827
+              ],
+              [
+                117.848754,
+                38.255062
+              ],
+              [
+                117.895565,
+                38.301572
+              ],
+              [
+                117.948536,
+                38.346644
+              ],
+              [
+                117.957775,
+                38.376208
+              ],
+              [
+                117.937449,
+                38.387936
+              ],
+              [
+                117.84629,
+                38.368232
+              ],
+              [
+                117.781,
+                38.373862
+              ],
+              [
+                117.730493,
+                38.424985
+              ],
+              [
+                117.72495,
+                38.457328
+              ],
+              [
+                117.678754,
+                38.477008
+              ],
+              [
+                117.644878,
+                38.52759
+              ],
+              [
+                117.68553,
+                38.539293
+              ],
+              [
+                117.638102,
+                38.54491
+              ],
+              [
+                117.639334,
+                38.626776
+              ],
+              [
+                117.55803,
+                38.613683
+              ],
+              [
+                117.47919,
+                38.616489
+              ],
+              [
+                117.432379,
+                38.601524
+              ],
+              [
+                117.368937,
+                38.564566
+              ],
+              [
+                117.25314,
+                38.556143
+              ],
+              [
+                117.238358,
+                38.580943
+              ],
+              [
+                117.258684,
+                38.608072
+              ],
+              [
+                117.258684,
+                38.608072
+              ],
+              [
+                117.213104,
+                38.639866
+              ],
+              [
+                117.213104,
+                38.639866
+              ],
+              [
+                117.183539,
+                38.61836
+              ],
+              [
+                117.183539,
+                38.61836
+              ],
+              [
+                117.150894,
+                38.617892
+              ],
+              [
+                117.109626,
+                38.584685
+              ],
+              [
+                117.070822,
+                38.608072
+              ],
+              [
+                117.055424,
+                38.639398
+              ],
+              [
+                117.068358,
+                38.680522
+              ],
+              [
+                117.038793,
+                38.688464
+              ],
+              [
+                116.95133,
+                38.689398
+              ],
+              [
+                116.948866,
+                38.689398
+              ],
+              [
+                116.950714,
+                38.689398
+              ],
+              [
+                116.95133,
+                38.689398
+              ],
+              [
+                116.950714,
+                38.689398
+              ],
+              [
+                116.948866,
+                38.689398
+              ],
+              [
+                116.877417,
+                38.680522
+              ],
+              [
+                116.858939,
+                38.741231
+              ],
+              [
+                116.794265,
+                38.744498
+              ],
+              [
+                116.794265,
+                38.744498
+              ],
+              [
+                116.746222,
+                38.754299
+              ],
+              [
+                116.737599,
+                38.784629
+              ],
+              [
+                116.75115,
+                38.831264
+              ],
+              [
+                116.723432,
+                38.852706
+              ],
+              [
+                116.722201,
+                38.896968
+              ],
+              [
+                116.708034,
+                38.931892
+              ],
+              [
+                116.72836,
+                38.975174
+              ],
+              [
+                116.754845,
+                39.003084
+              ],
+              [
+                116.754229,
+                39.034701
+              ],
+              [
+                116.754229,
+                39.034701
+              ],
+              [
+                116.783179,
+                39.05097
+              ],
+              [
+                116.783179,
+                39.05097
+              ],
+              [
+                116.812744,
+                39.05097
+              ],
+              [
+                116.812744,
+                39.05097
+              ],
+              [
+                116.871874,
+                39.054688
+              ],
+              [
+                116.912526,
+                39.110898
+              ],
+              [
+                116.91191,
+                39.111362
+              ],
+              [
+                116.91191,
+                39.111362
+              ],
+              [
+                116.912526,
+                39.110898
+              ],
+              [
+                116.909446,
+                39.150822
+              ],
+              [
+                116.870026,
+                39.153607
+              ],
+              [
+                116.855859,
+                39.215766
+              ],
+              [
+                116.881729,
+                39.225966
+              ],
+              [
+                116.881729,
+                39.225966
+              ],
+              [
+                116.87249,
+                39.291304
+              ],
+              [
+                116.889736,
+                39.338068
+              ],
+              [
+                116.870642,
+                39.357506
+              ],
+              [
+                116.829374,
+                39.338994
+              ],
+              [
+                116.818287,
+                39.3737
+              ],
+              [
+                116.840461,
+                39.378326
+              ],
+              [
+                116.839845,
+                39.413474
+              ],
+              [
+                116.876185,
+                39.43474
+              ],
+              [
+                116.832454,
+                39.435664
+              ],
+              [
+                116.785026,
+                39.465702
+              ],
+              [
+                116.820751,
+                39.482332
+              ],
+              [
+                116.819519,
+                39.528507
+              ],
+              [
+                116.78749,
+                39.554352
+              ],
+              [
+                116.808432,
+                39.576497
+              ],
+              [
+                116.812128,
+                39.615695
+              ],
+              [
+                116.79057,
+                39.595868
+              ],
+              [
+                116.748686,
+                39.619844
+              ],
+              [
+                116.709266,
+                39.618
+              ],
+              [
+                116.726512,
+                39.595407
+              ],
+              [
+                116.726512,
+                39.595407
+              ],
+              [
+                116.724048,
+                39.59264
+              ],
+              [
+                116.723432,
+                39.59264
+              ],
+              [
+                116.724048,
+                39.59264
+              ],
+              [
+                116.723432,
+                39.59264
+              ],
+              [
+                116.664918,
+                39.605552
+              ],
+              [
+                116.620571,
+                39.601863
+              ],
+              [
+                116.592237,
+                39.621227
+              ],
+              [
+                116.592237,
+                39.621227
+              ],
+              [
+                116.524484,
+                39.596329
+              ],
+              [
+                116.50847,
+                39.551122
+              ],
+              [
+                116.473361,
+                39.552968
+              ],
+              [
+                116.478289,
+                39.535431
+              ],
+              [
+                116.437637,
+                39.526661
+              ],
+              [
+                116.443796,
+                39.510041
+              ],
+              [
+                116.401912,
+                39.528046
+              ],
+              [
+                116.411767,
+                39.482794
+              ],
+              [
+                116.444412,
+                39.482332
+              ],
+              [
+                116.454883,
+                39.453226
+              ],
+              [
+                116.434557,
+                39.442597
+              ],
+              [
+                116.361876,
+                39.455074
+              ],
+              [
+                116.361876,
+                39.455074
+              ],
+              [
+                116.337854,
+                39.455536
+              ],
+              [
+                116.307057,
+                39.488337
+              ],
+              [
+                116.257782,
+                39.500344
+              ],
+              [
+                116.240536,
+                39.564041
+              ],
+              [
+                116.198652,
+                39.589412
+              ],
+              [
+                116.151841,
+                39.583416
+              ],
+              [
+                116.130283,
+                39.567732
+              ],
+              [
+                116.09887,
+                39.575113
+              ],
+              [
+                116.036044,
+                39.571884
+              ],
+              [
+                116.026189,
+                39.587567
+              ],
+              [
+                115.995392,
+                39.576958
+              ],
+              [
+                115.978146,
+                39.595868
+              ],
+              [
+                115.957204,
+                39.560812
+              ],
+              [
+                115.910393,
+                39.600479
+              ],
+              [
+                115.910393,
+                39.600479
+              ],
+              [
+                115.91532,
+                39.582955
+              ],
+              [
+                115.91532,
+                39.582955
+              ],
+              [
+                115.867893,
+                39.546507
+              ],
+              [
+                115.867893,
+                39.546507
+              ],
+              [
+                115.828473,
+                39.541431
+              ],
+              [
+                115.821081,
+                39.522968
+              ],
+              [
+                115.821081,
+                39.522968
+              ],
+              [
+                115.806299,
+                39.510041
+              ],
+              [
+                115.806299,
+                39.510041
+              ],
+              [
+                115.752712,
+                39.515581
+              ],
+              [
+                115.738545,
+                39.539585
+              ],
+              [
+                115.738545,
+                39.540046
+              ],
+              [
+                115.738545,
+                39.539585
+              ],
+              [
+                115.738545,
+                39.540046
+              ],
+              [
+                115.724995,
+                39.5442
+              ],
+              [
+                115.724995,
+                39.5442
+              ],
+              [
+                115.722531,
+                39.543738
+              ],
+              [
+                115.721299,
+                39.543738
+              ],
+              [
+                115.722531,
+                39.543738
+              ],
+              [
+                115.722531,
+                39.5442
+              ],
+              [
+                115.721299,
+                39.543738
+              ],
+              [
+                115.722531,
+                39.5442
+              ],
+              [
+                115.720683,
+                39.551122
+              ],
+              [
+                115.720683,
+                39.551122
+              ],
+              [
+                115.718835,
+                39.553891
+              ],
+              [
+                115.718835,
+                39.553891
+              ],
+              [
+                115.716988,
+                39.56035
+              ],
+              [
+                115.716988,
+                39.56035
+              ],
+              [
+                115.699125,
+                39.570039
+              ],
+              [
+                115.699125,
+                39.570039
+              ],
+              [
+                115.698509,
+                39.577881
+              ],
+              [
+                115.698509,
+                39.577881
+              ],
+              [
+                115.667712,
+                39.615234
+              ],
+              [
+                115.633836,
+                39.599557
+              ],
+              [
+                115.633836,
+                39.599557
+              ],
+              [
+                115.587024,
+                39.589873
+              ],
+              [
+                115.545756,
+                39.618922
+              ],
+              [
+                115.518039,
+                39.597252
+              ],
+              [
+                115.522351,
+                39.640124
+              ],
+              [
+                115.478619,
+                39.650723
+              ],
+              [
+                115.478619,
+                39.650723
+              ],
+              [
+                115.491554,
+                39.670074
+              ],
+              [
+                115.486626,
+                39.741899
+              ],
+              [
+                115.439815,
+                39.752022
+              ],
+              [
+                115.443511,
+                39.785601
+              ],
+              [
+                115.483547,
+                39.798477
+              ],
+              [
+                115.483547,
+                39.798477
+              ],
+              [
+                115.50572,
+                39.784222
+              ],
+              [
+                115.552532,
+                39.794799
+              ],
+              [
+                115.567314,
+                39.816407
+              ],
+              [
+                115.514344,
+                39.837549
+              ],
+              [
+                115.526046,
+                39.87568
+              ],
+              [
+                115.515575,
+                39.892212
+              ],
+              [
+                115.515575,
+                39.892212
+              ],
+              [
+                115.522967,
+                39.899099
+              ],
+              [
+                115.481083,
+                39.935819
+              ],
+              [
+                115.426264,
+                39.950502
+              ],
+              [
+                115.428728,
+                39.984443
+              ],
+              [
+                115.450286,
+                39.992697
+              ],
+              [
+                115.454597,
+                40.029825
+              ],
+              [
+                115.485394,
+                40.040364
+              ],
+              [
+                115.527278,
+                40.076092
+              ],
+              [
+                115.59072,
+                40.096239
+              ],
+              [
+                115.599959,
+                40.119583
+              ],
+              [
+                115.75456,
+                40.145663
+              ],
+              [
+                115.75456,
+                40.145663
+              ],
+              [
+                115.773654,
+                40.176307
+              ],
+              [
+                115.806299,
+                40.15344
+              ],
+              [
+                115.847567,
+                40.147036
+              ],
+              [
+                115.855574,
+                40.188652
+              ],
+              [
+                115.870356,
+                40.185909
+              ],
+              [
+                115.89869,
+                40.234354
+              ],
+              [
+                115.968907,
+                40.264045
+              ],
+              [
+                115.95166,
+                40.281852
+              ],
+              [
+                115.917784,
+                40.354405
+              ],
+              [
+                115.864197,
+                40.359422
+              ],
+              [
+                115.771806,
+                40.443734
+              ],
+              [
+                115.781045,
+                40.49336
+              ],
+              [
+                115.736082,
+                40.503372
+              ],
+              [
+                115.755176,
+                40.540221
+              ],
+              [
+                115.784741,
+                40.55841
+              ],
+              [
+                115.819849,
+                40.55932
+              ],
+              [
+                115.827857,
+                40.587504
+              ],
+              [
+                115.885139,
+                40.595229
+              ],
+              [
+                115.907929,
+                40.617493
+              ],
+              [
+                115.971986,
+                40.6025
+              ],
+              [
+                115.982457,
+                40.578868
+              ],
+              [
+                116.005247,
+                40.583868
+              ],
+              [
+                116.09887,
+                40.630665
+              ],
+              [
+                116.133979,
+                40.666536
+              ],
+              [
+                116.162928,
+                40.662451
+              ],
+              [
+                116.171551,
+                40.695582
+              ],
+              [
+                116.204812,
+                40.740035
+              ],
+              [
+                116.22021,
+                40.744115
+              ],
+              [
+                116.247311,
+                40.791707
+              ],
+              [
+                116.273181,
+                40.762703
+              ],
+              [
+                116.311369,
+                40.754996
+              ],
+              [
+                116.316912,
+                40.772221
+              ],
+              [
+                116.453651,
+                40.765876
+              ],
+              [
+                116.46597,
+                40.774487
+              ],
+              [
+                116.438253,
+                40.81934
+              ],
+              [
+                116.334159,
+                40.90443
+              ],
+              [
+                116.339702,
+                40.929303
+              ],
+              [
+                116.370499,
+                40.94377
+              ],
+              [
+                116.398216,
+                40.90624
+              ],
+              [
+                116.477057,
+                40.899907
+              ],
+              [
+                116.447492,
+                40.953715
+              ],
+              [
+                116.455499,
+                40.980828
+              ],
+              [
+                116.519557,
+                40.98128
+              ],
+              [
+                116.519557,
+                40.98128
+              ],
+              [
+                116.5676,
+                40.992574
+              ],
+              [
+                116.598397,
+                40.974503
+              ],
+              [
+                116.623034,
+                41.021026
+              ],
+              [
+                116.615643,
+                41.053076
+              ],
+              [
+                116.647672,
+                41.059394
+              ],
+              [
+                116.688324,
+                41.044501
+              ],
+              [
+                116.698795,
+                41.021477
+              ],
+              [
+                116.677853,
+                40.970888
+              ],
+              [
+                116.722201,
+                40.927495
+              ],
+              [
+                116.713577,
+                40.909858
+              ],
+              [
+                116.759773,
+                40.889954
+              ],
+              [
+                116.81336,
+                40.848319
+              ],
+              [
+                116.848468,
+                40.839264
+              ],
+              [
+                116.924229,
+                40.773581
+              ],
+              [
+                116.926692,
+                40.745022
+              ],
+              [
+                116.964881,
+                40.709647
+              ],
+              [
+                117.012308,
+                40.693767
+              ],
+              [
+                117.11209,
+                40.707379
+              ],
+              [
+                117.117018,
+                40.70012
+              ],
+              [
+                117.208177,
+                40.694675
+              ],
+              [
+                117.278394,
+                40.664267
+              ],
+              [
+                117.319662,
+                40.657911
+              ],
+              [
+                117.342451,
+                40.673799
+              ],
+              [
+                117.408973,
+                40.686961
+              ],
+              [
+                117.493973,
+                40.675161
+              ],
+              [
+                117.514914,
+                40.660181
+              ],
+              [
+                117.501364,
+                40.636569
+              ],
+              [
+                117.467487,
+                40.649738
+              ],
+              [
+                117.467487,
+                40.649738
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.210024,
+                40.082045
+              ],
+              [
+                117.204481,
+                40.069681
+              ],
+              [
+                117.159517,
+                40.077008
+              ],
+              [
+                117.140423,
+                40.064185
+              ],
+              [
+                117.105315,
+                40.074261
+              ],
+              [
+                117.105315,
+                40.074261
+              ],
+              [
+                117.051728,
+                40.059605
+              ],
+              [
+                117.025243,
+                40.030283
+              ],
+              [
+                116.945171,
+                40.04128
+              ],
+              [
+                116.927924,
+                40.055024
+              ],
+              [
+                116.867562,
+                40.041739
+              ],
+              [
+                116.831222,
+                40.051359
+              ],
+              [
+                116.820135,
+                40.02845
+              ],
+              [
+                116.781331,
+                40.034866
+              ],
+              [
+                116.757925,
+                39.967934
+              ],
+              [
+                116.782563,
+                39.947749
+              ],
+              [
+                116.78441,
+                39.891294
+              ],
+              [
+                116.812128,
+                39.889916
+              ],
+              [
+                116.865714,
+                39.843982
+              ],
+              [
+                116.907598,
+                39.832494
+              ],
+              [
+                116.918069,
+                39.84628
+              ],
+              [
+                116.949482,
+                39.778703
+              ],
+              [
+                116.902055,
+                39.763523
+              ],
+              [
+                116.916837,
+                39.731314
+              ],
+              [
+                116.887272,
+                39.72533
+              ],
+              [
+                116.889736,
+                39.687576
+              ],
+              [
+                116.90575,
+                39.688037
+              ],
+              [
+                116.932236,
+                39.706456
+              ],
+              [
+                116.932236,
+                39.706456
+              ],
+              [
+                116.944555,
+                39.695405
+              ],
+              [
+                116.944555,
+                39.695405
+              ],
+              [
+                116.948866,
+                39.680668
+              ],
+              [
+                116.948866,
+                39.680668
+              ],
+              [
+                116.964265,
+                39.64335
+              ],
+              [
+                116.983359,
+                39.638742
+              ],
+              [
+                116.983359,
+                39.638742
+              ],
+              [
+                117.016004,
+                39.653949
+              ],
+              [
+                117.10901,
+                39.625375
+              ],
+              [
+                117.10901,
+                39.625375
+              ],
+              [
+                117.152742,
+                39.623532
+              ],
+              [
+                117.177996,
+                39.645194
+              ],
+              [
+                117.165061,
+                39.718886
+              ],
+              [
+                117.165061,
+                39.718886
+              ],
+              [
+                117.161981,
+                39.748801
+              ],
+              [
+                117.205713,
+                39.763984
+              ],
+              [
+                117.15767,
+                39.796638
+              ],
+              [
+                117.156438,
+                39.817326
+              ],
+              [
+                117.192162,
+                39.832953
+              ],
+              [
+                117.251908,
+                39.834332
+              ],
+              [
+                117.247597,
+                39.860981
+              ],
+              [
+                117.227887,
+                39.852712
+              ],
+              [
+                117.162597,
+                39.876598
+              ],
+              [
+                117.162597,
+                39.876598
+              ],
+              [
+                117.150894,
+                39.944996
+              ],
+              [
+                117.198322,
+                39.992697
+              ],
+              [
+                117.192162,
+                40.066475
+              ],
+              [
+                117.210024,
+                40.082045
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.784696,
+                39.376938
+              ],
+              [
+                117.765602,
+                39.400527
+              ],
+              [
+                117.699696,
+                39.407463
+              ],
+              [
+                117.673211,
+                39.386652
+              ],
+              [
+                117.668899,
+                39.412087
+              ],
+              [
+                117.614081,
+                39.407001
+              ],
+              [
+                117.601146,
+                39.419485
+              ],
+              [
+                117.570965,
+                39.404689
+              ],
+              [
+                117.521074,
+                39.357043
+              ],
+              [
+                117.536472,
+                39.338068
+              ],
+              [
+                117.594987,
+                39.349176
+              ],
+              [
+                117.669515,
+                39.322792
+              ],
+              [
+                117.670747,
+                39.357969
+              ],
+              [
+                117.74466,
+                39.354729
+              ],
+              [
+                117.784696,
+                39.376938
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.869365,
+                39.142932
+              ],
+              [
+                118.82009,
+                39.108576
+              ],
+              [
+                118.857662,
+                39.098824
+              ],
+              [
+                118.869365,
+                39.142932
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 140000,
+        "name": "灞辫タ鐪�",
+        "center": [
+          112.549248,
+          37.857014
+        ],
+        "centroid": [
+          112.304436,
+          37.618179
+        ],
+        "childrenNum": 11,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 3,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                110.379257,
+                34.600612
+              ],
+              [
+                110.424837,
+                34.588295
+              ],
+              [
+                110.488279,
+                34.610956
+              ],
+              [
+                110.533242,
+                34.583368
+              ],
+              [
+                110.610851,
+                34.607508
+              ],
+              [
+                110.710017,
+                34.605045
+              ],
+              [
+                110.749437,
+                34.65232
+              ],
+              [
+                110.791937,
+                34.649858
+              ],
+              [
+                110.824582,
+                34.615881
+              ],
+              [
+                110.883712,
+                34.64395
+              ],
+              [
+                110.903422,
+                34.669056
+              ],
+              [
+                110.920052,
+                34.730068
+              ],
+              [
+                110.976103,
+                34.706456
+              ],
+              [
+                111.035233,
+                34.740887
+              ],
+              [
+                111.118385,
+                34.756623
+              ],
+              [
+                111.148566,
+                34.807742
+              ],
+              [
+                111.232949,
+                34.789559
+              ],
+              [
+                111.255123,
+                34.819535
+              ],
+              [
+                111.29208,
+                34.806759
+              ],
+              [
+                111.345666,
+                34.831816
+              ],
+              [
+                111.389398,
+                34.815113
+              ],
+              [
+                111.439289,
+                34.838202
+              ],
+              [
+                111.502731,
+                34.829851
+              ],
+              [
+                111.543999,
+                34.853428
+              ],
+              [
+                111.570484,
+                34.843114
+              ],
+              [
+                111.592042,
+                34.881416
+              ],
+              [
+                111.617911,
+                34.894671
+              ],
+              [
+                111.646861,
+                34.938836
+              ],
+              [
+                111.681969,
+                34.9511
+              ],
+              [
+                111.664107,
+                34.984449
+              ],
+              [
+                111.740483,
+                35.00455
+              ],
+              [
+                111.807005,
+                35.032977
+              ],
+              [
+                111.810084,
+                35.062374
+              ],
+              [
+                111.933272,
+                35.083435
+              ],
+              [
+                111.97762,
+                35.067272
+              ],
+              [
+                112.018888,
+                35.068742
+              ],
+              [
+                112.039214,
+                35.045717
+              ],
+              [
+                112.062004,
+                35.056005
+              ],
+              [
+                112.05646,
+                35.098615
+              ],
+              [
+                112.066315,
+                35.153437
+              ],
+              [
+                112.03983,
+                35.194039
+              ],
+              [
+                112.078634,
+                35.219467
+              ],
+              [
+                112.058924,
+                35.280069
+              ],
+              [
+                112.13838,
+                35.271275
+              ],
+              [
+                112.21722,
+                35.253195
+              ],
+              [
+                112.242474,
+                35.234622
+              ],
+              [
+                112.304684,
+                35.251728
+              ],
+              [
+                112.288053,
+                35.219956
+              ],
+              [
+                112.36751,
+                35.219956
+              ],
+              [
+                112.390915,
+                35.239021
+              ],
+              [
+                112.513487,
+                35.218489
+              ],
+              [
+                112.637291,
+                35.225822
+              ],
+              [
+                112.628052,
+                35.263457
+              ],
+              [
+                112.720443,
+                35.206265
+              ],
+              [
+                112.772798,
+                35.207732
+              ],
+              [
+                112.822073,
+                35.258082
+              ],
+              [
+                112.884283,
+                35.243909
+              ],
+              [
+                112.934174,
+                35.262968
+              ],
+              [
+                112.936022,
+                35.284466
+              ],
+              [
+                112.992072,
+                35.29619
+              ],
+              [
+                112.985913,
+                35.33965
+              ],
+              [
+                112.996384,
+                35.362104
+              ],
+              [
+                113.067217,
+                35.353806
+              ],
+              [
+                113.126347,
+                35.332327
+              ],
+              [
+                113.149137,
+                35.350878
+              ],
+              [
+                113.165151,
+                35.412845
+              ],
+              [
+                113.185477,
+                35.409431
+              ],
+              [
+                113.189789,
+                35.44893
+              ],
+              [
+                113.243375,
+                35.449418
+              ],
+              [
+                113.304353,
+                35.426989
+              ],
+              [
+                113.31236,
+                35.481101
+              ],
+              [
+                113.348085,
+                35.468429
+              ],
+              [
+                113.391817,
+                35.506925
+              ],
+              [
+                113.439244,
+                35.507412
+              ],
+              [
+                113.49899,
+                35.532254
+              ],
+              [
+                113.513773,
+                35.57364
+              ],
+              [
+                113.55812,
+                35.621816
+              ],
+              [
+                113.547649,
+                35.656835
+              ],
+              [
+                113.578446,
+                35.633491
+              ],
+              [
+                113.625258,
+                35.632518
+              ],
+              [
+                113.622794,
+                35.674825
+              ],
+              [
+                113.592613,
+                35.691838
+              ],
+              [
+                113.587685,
+                35.736542
+              ],
+              [
+                113.604932,
+                35.797727
+              ],
+              [
+                113.582758,
+                35.818111
+              ],
+              [
+                113.660982,
+                35.837035
+              ],
+              [
+                113.637576,
+                35.870019
+              ],
+              [
+                113.654207,
+                35.931586
+              ],
+              [
+                113.648663,
+                35.994073
+              ],
+              [
+                113.678844,
+                35.985841
+              ],
+              [
+                113.694859,
+                36.026991
+              ],
+              [
+                113.660366,
+                36.034735
+              ],
+              [
+                113.68562,
+                36.056026
+              ],
+              [
+                113.671453,
+                36.115514
+              ],
+              [
+                113.655439,
+                36.125182
+              ],
+              [
+                113.712721,
+                36.129533
+              ],
+              [
+                113.705946,
+                36.148865
+              ],
+              [
+                113.651127,
+                36.174473
+              ],
+              [
+                113.697939,
+                36.181719
+              ],
+              [
+                113.681924,
+                36.216491
+              ],
+              [
+                113.716417,
+                36.262347
+              ],
+              [
+                113.712105,
+                36.303353
+              ],
+              [
+                113.736127,
+                36.324571
+              ],
+              [
+                113.731199,
+                36.363135
+              ],
+              [
+                113.708409,
+                36.423352
+              ],
+              [
+                113.670221,
+                36.425278
+              ],
+              [
+                113.635729,
+                36.451277
+              ],
+              [
+                113.587069,
+                36.460904
+              ],
+              [
+                113.554425,
+                36.494589
+              ],
+              [
+                113.559968,
+                36.528741
+              ],
+              [
+                113.588917,
+                36.547974
+              ],
+              [
+                113.569823,
+                36.585947
+              ],
+              [
+                113.539642,
+                36.594116
+              ],
+              [
+                113.54457,
+                36.62342
+              ],
+              [
+                113.486671,
+                36.635427
+              ],
+              [
+                113.476816,
+                36.655114
+              ],
+              [
+                113.506997,
+                36.705029
+              ],
+              [
+                113.465113,
+                36.707908
+              ],
+              [
+                113.499606,
+                36.740527
+              ],
+              [
+                113.535946,
+                36.732373
+              ],
+              [
+                113.549497,
+                36.752515
+              ],
+              [
+                113.600004,
+                36.752995
+              ],
+              [
+                113.680692,
+                36.789907
+              ],
+              [
+                113.676381,
+                36.855539
+              ],
+              [
+                113.696707,
+                36.882351
+              ],
+              [
+                113.731815,
+                36.878521
+              ],
+              [
+                113.731815,
+                36.858891
+              ],
+              [
+                113.773083,
+                36.85506
+              ],
+              [
+                113.792793,
+                36.894796
+              ],
+              [
+                113.76138,
+                36.956034
+              ],
+              [
+                113.791561,
+                36.98759
+              ],
+              [
+                113.771851,
+                37.016745
+              ],
+              [
+                113.788482,
+                37.059739
+              ],
+              [
+                113.758301,
+                37.075497
+              ],
+              [
+                113.773699,
+                37.107004
+              ],
+              [
+                113.773083,
+                37.151855
+              ],
+              [
+                113.832213,
+                37.167594
+              ],
+              [
+                113.853155,
+                37.215269
+              ],
+              [
+                113.886416,
+                37.239095
+              ],
+              [
+                113.90243,
+                37.310052
+              ],
+              [
+                113.962792,
+                37.355734
+              ],
+              [
+                113.973879,
+                37.40329
+              ],
+              [
+                114.014531,
+                37.42468
+              ],
+              [
+                114.036705,
+                37.494037
+              ],
+              [
+                114.118625,
+                37.59084
+              ],
+              [
+                114.115545,
+                37.619761
+              ],
+              [
+                114.139567,
+                37.675676
+              ],
+              [
+                114.12848,
+                37.698409
+              ],
+              [
+                114.068118,
+                37.721608
+              ],
+              [
+                113.993589,
+                37.706932
+              ],
+              [
+                113.996669,
+                37.730128
+              ],
+              [
+                114.044712,
+                37.761834
+              ],
+              [
+                114.006524,
+                37.813386
+              ],
+              [
+                113.976959,
+                37.816696
+              ],
+              [
+                113.959097,
+                37.906468
+              ],
+              [
+                113.936307,
+                37.922993
+              ],
+              [
+                113.901198,
+                37.984811
+              ],
+              [
+                113.872249,
+                37.990471
+              ],
+              [
+                113.876561,
+                38.055059
+              ],
+              [
+                113.811271,
+                38.117707
+              ],
+              [
+                113.831597,
+                38.16854
+              ],
+              [
+                113.797105,
+                38.162894
+              ],
+              [
+                113.720728,
+                38.174656
+              ],
+              [
+                113.711489,
+                38.213695
+              ],
+              [
+                113.678844,
+                38.20523
+              ],
+              [
+                113.64312,
+                38.232031
+              ],
+              [
+                113.598772,
+                38.22733
+              ],
+              [
+                113.570439,
+                38.237202
+              ],
+              [
+                113.54457,
+                38.270569
+              ],
+              [
+                113.557504,
+                38.343359
+              ],
+              [
+                113.525475,
+                38.383245
+              ],
+              [
+                113.537794,
+                38.417952
+              ],
+              [
+                113.583374,
+                38.459671
+              ],
+              [
+                113.546417,
+                38.492936
+              ],
+              [
+                113.561816,
+                38.558483
+              ],
+              [
+                113.603084,
+                38.587024
+              ],
+              [
+                113.612939,
+                38.645942
+              ],
+              [
+                113.70225,
+                38.651551
+              ],
+              [
+                113.720728,
+                38.713218
+              ],
+              [
+                113.775547,
+                38.709949
+              ],
+              [
+                113.802648,
+                38.763166
+              ],
+              [
+                113.839605,
+                38.7585
+              ],
+              [
+                113.836525,
+                38.795824
+              ],
+              [
+                113.855619,
+                38.828933
+              ],
+              [
+                113.795257,
+                38.860628
+              ],
+              [
+                113.776163,
+                38.885788
+              ],
+              [
+                113.76754,
+                38.959819
+              ],
+              [
+                113.776779,
+                38.986804
+              ],
+              [
+                113.80696,
+                38.989595
+              ],
+              [
+                113.898119,
+                39.067699
+              ],
+              [
+                113.930148,
+                39.063517
+              ],
+              [
+                113.961561,
+                39.100681
+              ],
+              [
+                113.994821,
+                39.095572
+              ],
+              [
+                114.006524,
+                39.122971
+              ],
+              [
+                114.050872,
+                39.135969
+              ],
+              [
+                114.064422,
+                39.094179
+              ],
+              [
+                114.082901,
+                39.09325
+              ],
+              [
+                114.082901,
+                39.09325
+              ],
+              [
+                114.10877,
+                39.052364
+              ],
+              [
+                114.157429,
+                39.061194
+              ],
+              [
+                114.180835,
+                39.049111
+              ],
+              [
+                114.252284,
+                39.073739
+              ],
+              [
+                114.345907,
+                39.075133
+              ],
+              [
+                114.369928,
+                39.107648
+              ],
+              [
+                114.360689,
+                39.134112
+              ],
+              [
+                114.388406,
+                39.176807
+              ],
+              [
+                114.443841,
+                39.174023
+              ],
+              [
+                114.47587,
+                39.21623
+              ],
+              [
+                114.416124,
+                39.242654
+              ],
+              [
+                114.437066,
+                39.259337
+              ],
+              [
+                114.430906,
+                39.307513
+              ],
+              [
+                114.466631,
+                39.329736
+              ],
+              [
+                114.469095,
+                39.400989
+              ],
+              [
+                114.496812,
+                39.438437
+              ],
+              [
+                114.501739,
+                39.476789
+              ],
+              [
+                114.532536,
+                39.486027
+              ],
+              [
+                114.568877,
+                39.573729
+              ],
+              [
+                114.51529,
+                39.564964
+              ],
+              [
+                114.49558,
+                39.608318
+              ],
+              [
+                114.431522,
+                39.613851
+              ],
+              [
+                114.408117,
+                39.652106
+              ],
+              [
+                114.409964,
+                39.761683
+              ],
+              [
+                114.41674,
+                39.775943
+              ],
+              [
+                114.390254,
+                39.819165
+              ],
+              [
+                114.406885,
+                39.833413
+              ],
+              [
+                114.395182,
+                39.867412
+              ],
+              [
+                114.285545,
+                39.858225
+              ],
+              [
+                114.286776,
+                39.871087
+              ],
+              [
+                114.215943,
+                39.8619
+              ],
+              [
+                114.204241,
+                39.885324
+              ],
+              [
+                114.229494,
+                39.899558
+              ],
+              [
+                114.212248,
+                39.918839
+              ],
+              [
+                114.17406,
+                39.897722
+              ],
+              [
+                114.067502,
+                39.922511
+              ],
+              [
+                114.047176,
+                39.916085
+              ],
+              [
+                114.028082,
+                39.959218
+              ],
+              [
+                114.029314,
+                39.985819
+              ],
+              [
+                113.910438,
+                40.015618
+              ],
+              [
+                113.959097,
+                40.033491
+              ],
+              [
+                113.989278,
+                40.11226
+              ],
+              [
+                114.018227,
+                40.103563
+              ],
+              [
+                114.045944,
+                40.056856
+              ],
+              [
+                114.086596,
+                40.071513
+              ],
+              [
+                114.101995,
+                40.099901
+              ],
+              [
+                114.073046,
+                40.168533
+              ],
+              [
+                114.073046,
+                40.168533
+              ],
+              [
+                114.097683,
+                40.193681
+              ],
+              [
+                114.135871,
+                40.175392
+              ],
+              [
+                114.180219,
+                40.191395
+              ],
+              [
+                114.235654,
+                40.198252
+              ],
+              [
+                114.255364,
+                40.236182
+              ],
+              [
+                114.292936,
+                40.230242
+              ],
+              [
+                114.362537,
+                40.249886
+              ],
+              [
+                114.406269,
+                40.246232
+              ],
+              [
+                114.46971,
+                40.268155
+              ],
+              [
+                114.510978,
+                40.302851
+              ],
+              [
+                114.530688,
+                40.345283
+              ],
+              [
+                114.481413,
+                40.34802
+              ],
+              [
+                114.438914,
+                40.371733
+              ],
+              [
+                114.390254,
+                40.351213
+              ],
+              [
+                114.381015,
+                40.36307
+              ],
+              [
+                114.31203,
+                40.372645
+              ],
+              [
+                114.286161,
+                40.425057
+              ],
+              [
+                114.299711,
+                40.44009
+              ],
+              [
+                114.267066,
+                40.474242
+              ],
+              [
+                114.282465,
+                40.494725
+              ],
+              [
+                114.293552,
+                40.55159
+              ],
+              [
+                114.273842,
+                40.552954
+              ],
+              [
+                114.283081,
+                40.590685
+              ],
+              [
+                114.236269,
+                40.607043
+              ],
+              [
+                114.183299,
+                40.67153
+              ],
+              [
+                114.162357,
+                40.71373
+              ],
+              [
+                114.134639,
+                40.737314
+              ],
+              [
+                114.084748,
+                40.729605
+              ],
+              [
+                114.063806,
+                40.706925
+              ],
+              [
+                114.07243,
+                40.679246
+              ],
+              [
+                114.041633,
+                40.608861
+              ],
+              [
+                114.076741,
+                40.575686
+              ],
+              [
+                114.080437,
+                40.547952
+              ],
+              [
+                114.061959,
+                40.52885
+              ],
+              [
+                114.011452,
+                40.515657
+              ],
+              [
+                113.948626,
+                40.514747
+              ],
+              [
+                113.890112,
+                40.466503
+              ],
+              [
+                113.850691,
+                40.460583
+              ],
+              [
+                113.794641,
+                40.517932
+              ],
+              [
+                113.763228,
+                40.473787
+              ],
+              [
+                113.688699,
+                40.448288
+              ],
+              [
+                113.559968,
+                40.348476
+              ],
+              [
+                113.500222,
+                40.334335
+              ],
+              [
+                113.387505,
+                40.319279
+              ],
+              [
+                113.316672,
+                40.319736
+              ],
+              [
+                113.27602,
+                40.388601
+              ],
+              [
+                113.251382,
+                40.413211
+              ],
+              [
+                113.083231,
+                40.374925
+              ],
+              [
+                113.03334,
+                40.368997
+              ],
+              [
+                112.898449,
+                40.329317
+              ],
+              [
+                112.848558,
+                40.206937
+              ],
+              [
+                112.744464,
+                40.167161
+              ],
+              [
+                112.712436,
+                40.178593
+              ],
+              [
+                112.6299,
+                40.235725
+              ],
+              [
+                112.511639,
+                40.269068
+              ],
+              [
+                112.456205,
+                40.300112
+              ],
+              [
+                112.418017,
+                40.295091
+              ],
+              [
+                112.349031,
+                40.257194
+              ],
+              [
+                112.310227,
+                40.256281
+              ],
+              [
+                112.299756,
+                40.21105
+              ],
+              [
+                112.232619,
+                40.169905
+              ],
+              [
+                112.232003,
+                40.133311
+              ],
+              [
+                112.183344,
+                40.083877
+              ],
+              [
+                112.182112,
+                40.061437
+              ],
+              [
+                112.142076,
+                40.027076
+              ],
+              [
+                112.133453,
+                40.001866
+              ],
+              [
+                112.07617,
+                39.919298
+              ],
+              [
+                112.042294,
+                39.886243
+              ],
+              [
+                112.012729,
+                39.827438
+              ],
+              [
+                111.970229,
+                39.796638
+              ],
+              [
+                111.959758,
+                39.692642
+              ],
+              [
+                111.925265,
+                39.66731
+              ],
+              [
+                111.9382,
+                39.623071
+              ],
+              [
+                111.87907,
+                39.606013
+              ],
+              [
+                111.842729,
+                39.620305
+              ],
+              [
+                111.783599,
+                39.58895
+              ],
+              [
+                111.722621,
+                39.606013
+              ],
+              [
+                111.659179,
+                39.641507
+              ],
+              [
+                111.625303,
+                39.633672
+              ],
+              [
+                111.525521,
+                39.662242
+              ],
+              [
+                111.497187,
+                39.661781
+              ],
+              [
+                111.445448,
+                39.640124
+              ],
+              [
+                111.460847,
+                39.606935
+              ],
+              [
+                111.441137,
+                39.59679
+              ],
+              [
+                111.422043,
+                39.539123
+              ],
+              [
+                111.431282,
+                39.508656
+              ],
+              [
+                111.372152,
+                39.479099
+              ],
+              [
+                111.358601,
+                39.432428
+              ],
+              [
+                111.337043,
+                39.420872
+              ],
+              [
+                111.171971,
+                39.423183
+              ],
+              [
+                111.143022,
+                39.407926
+              ],
+              [
+                111.125776,
+                39.366297
+              ],
+              [
+                111.159037,
+                39.362596
+              ],
+              [
+                111.155341,
+                39.338531
+              ],
+              [
+                111.186138,
+                39.35149
+              ],
+              [
+                111.179363,
+                39.326959
+              ],
+              [
+                111.202152,
+                39.305197
+              ],
+              [
+                111.247732,
+                39.302419
+              ],
+              [
+                111.213239,
+                39.257021
+              ],
+              [
+                111.219399,
+                39.244044
+              ],
+              [
+                111.163348,
+                39.152678
+              ],
+              [
+                111.173819,
+                39.135041
+              ],
+              [
+                111.147334,
+                39.100681
+              ],
+              [
+                111.138095,
+                39.064447
+              ],
+              [
+                111.094363,
+                39.030053
+              ],
+              [
+                111.038313,
+                39.020289
+              ],
+              [
+                110.998276,
+                38.998433
+              ],
+              [
+                110.980414,
+                38.970056
+              ],
+              [
+                111.009979,
+                38.932823
+              ],
+              [
+                111.016755,
+                38.889981
+              ],
+              [
+                110.995813,
+                38.868084
+              ],
+              [
+                111.009363,
+                38.847579
+              ],
+              [
+                110.965016,
+                38.755699
+              ],
+              [
+                110.915125,
+                38.704345
+              ],
+              [
+                110.916357,
+                38.673981
+              ],
+              [
+                110.880632,
+                38.626776
+              ],
+              [
+                110.898494,
+                38.587024
+              ],
+              [
+                110.920052,
+                38.581878
+              ],
+              [
+                110.907733,
+                38.521035
+              ],
+              [
+                110.870777,
+                38.510265
+              ],
+              [
+                110.874473,
+                38.453579
+              ],
+              [
+                110.840596,
+                38.439986
+              ],
+              [
+                110.796864,
+                38.453579
+              ],
+              [
+                110.77777,
+                38.440924
+              ],
+              [
+                110.746973,
+                38.366355
+              ],
+              [
+                110.701394,
+                38.353215
+              ],
+              [
+                110.661358,
+                38.308617
+              ],
+              [
+                110.601612,
+                38.308147
+              ],
+              [
+                110.57759,
+                38.297345
+              ],
+              [
+                110.565887,
+                38.215105
+              ],
+              [
+                110.528315,
+                38.211814
+              ],
+              [
+                110.509221,
+                38.192061
+              ],
+              [
+                110.519692,
+                38.130889
+              ],
+              [
+                110.501829,
+                38.097929
+              ],
+              [
+                110.507989,
+                38.013107
+              ],
+              [
+                110.528315,
+                37.990471
+              ],
+              [
+                110.522771,
+                37.955088
+              ],
+              [
+                110.59422,
+                37.922049
+              ],
+              [
+                110.680452,
+                37.790216
+              ],
+              [
+                110.735886,
+                37.77035
+              ],
+              [
+                110.750669,
+                37.736281
+              ],
+              [
+                110.716792,
+                37.728708
+              ],
+              [
+                110.706321,
+                37.705511
+              ],
+              [
+                110.775306,
+                37.680886
+              ],
+              [
+                110.793169,
+                37.650567
+              ],
+              [
+                110.763604,
+                37.639668
+              ],
+              [
+                110.771611,
+                37.594634
+              ],
+              [
+                110.795017,
+                37.558586
+              ],
+              [
+                110.770995,
+                37.538184
+              ],
+              [
+                110.759292,
+                37.474567
+              ],
+              [
+                110.740198,
+                37.44939
+              ],
+              [
+                110.644111,
+                37.435135
+              ],
+              [
+                110.630561,
+                37.372858
+              ],
+              [
+                110.641648,
+                37.360015
+              ],
+              [
+                110.695234,
+                37.34955
+              ],
+              [
+                110.678604,
+                37.317668
+              ],
+              [
+                110.690307,
+                37.287201
+              ],
+              [
+                110.661974,
+                37.281963
+              ],
+              [
+                110.651503,
+                37.256722
+              ],
+              [
+                110.590525,
+                37.187145
+              ],
+              [
+                110.53509,
+                37.138021
+              ],
+              [
+                110.535706,
+                37.115118
+              ],
+              [
+                110.49567,
+                37.086956
+              ],
+              [
+                110.460561,
+                37.044932
+              ],
+              [
+                110.417446,
+                37.027257
+              ],
+              [
+                110.426685,
+                37.008621
+              ],
+              [
+                110.382953,
+                37.022001
+              ],
+              [
+                110.381721,
+                37.002408
+              ],
+              [
+                110.424221,
+                36.963685
+              ],
+              [
+                110.408823,
+                36.892403
+              ],
+              [
+                110.376178,
+                36.882351
+              ],
+              [
+                110.424221,
+                36.855539
+              ],
+              [
+                110.406975,
+                36.824886
+              ],
+              [
+                110.423605,
+                36.818179
+              ],
+              [
+                110.407591,
+                36.776007
+              ],
+              [
+                110.447011,
+                36.737649
+              ],
+              [
+                110.438388,
+                36.685835
+              ],
+              [
+                110.402663,
+                36.697352
+              ],
+              [
+                110.394656,
+                36.676716
+              ],
+              [
+                110.426685,
+                36.657514
+              ],
+              [
+                110.447627,
+                36.621018
+              ],
+              [
+                110.496902,
+                36.582102
+              ],
+              [
+                110.488895,
+                36.556628
+              ],
+              [
+                110.503677,
+                36.488335
+              ],
+              [
+                110.47288,
+                36.453203
+              ],
+              [
+                110.489511,
+                36.430094
+              ],
+              [
+                110.487047,
+                36.393972
+              ],
+              [
+                110.459946,
+                36.327946
+              ],
+              [
+                110.474112,
+                36.306729
+              ],
+              [
+                110.474112,
+                36.248352
+              ],
+              [
+                110.45625,
+                36.22663
+              ],
+              [
+                110.447011,
+                36.164328
+              ],
+              [
+                110.467953,
+                36.074893
+              ],
+              [
+                110.491974,
+                36.034735
+              ],
+              [
+                110.49259,
+                35.994073
+              ],
+              [
+                110.516612,
+                35.971796
+              ],
+              [
+                110.502445,
+                35.947575
+              ],
+              [
+                110.516612,
+                35.918501
+              ],
+              [
+                110.511684,
+                35.879718
+              ],
+              [
+                110.549257,
+                35.877778
+              ],
+              [
+                110.550489,
+                35.838005
+              ],
+              [
+                110.571431,
+                35.800639
+              ],
+              [
+                110.57759,
+                35.701559
+              ],
+              [
+                110.609619,
+                35.632031
+              ],
+              [
+                110.589293,
+                35.602355
+              ],
+              [
+                110.567735,
+                35.539559
+              ],
+              [
+                110.531394,
+                35.511309
+              ],
+              [
+                110.477808,
+                35.413821
+              ],
+              [
+                110.45009,
+                35.327933
+              ],
+              [
+                110.374946,
+                35.251728
+              ],
+              [
+                110.378642,
+                35.210666
+              ],
+              [
+                110.364475,
+                35.197952
+              ],
+              [
+                110.373714,
+                35.134351
+              ],
+              [
+                110.320743,
+                35.00504
+              ],
+              [
+                110.262229,
+                34.944233
+              ],
+              [
+                110.230816,
+                34.880925
+              ],
+              [
+                110.246831,
+                34.789068
+              ],
+              [
+                110.243135,
+                34.725641
+              ],
+              [
+                110.229584,
+                34.692679
+              ],
+              [
+                110.269004,
+                34.629671
+              ],
+              [
+                110.29549,
+                34.610956
+              ],
+              [
+                110.379257,
+                34.600612
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 150000,
+        "name": "鍐呰挋鍙よ嚜娌诲尯",
+        "center": [
+          111.670801,
+          40.818311
+        ],
+        "centroid": [
+          114.077429,
+          44.331087
+        ],
+        "childrenNum": 12,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 4,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "Polygon",
+        "coordinates": [
+          [
+            [
+              97.172903,
+              42.795257
+            ],
+            [
+              97.371235,
+              42.457076
+            ],
+            [
+              97.500582,
+              42.243894
+            ],
+            [
+              97.653335,
+              41.986856
+            ],
+            [
+              97.84674,
+              41.656379
+            ],
+            [
+              97.613915,
+              41.477276
+            ],
+            [
+              97.629314,
+              41.440498
+            ],
+            [
+              97.903407,
+              41.168057
+            ],
+            [
+              97.971776,
+              41.09774
+            ],
+            [
+              98.142391,
+              41.001607
+            ],
+            [
+              98.184891,
+              40.988056
+            ],
+            [
+              98.25018,
+              40.93925
+            ],
+            [
+              98.333332,
+              40.918903
+            ],
+            [
+              98.344419,
+              40.568413
+            ],
+            [
+              98.627751,
+              40.677884
+            ],
+            [
+              98.569853,
+              40.746836
+            ],
+            [
+              98.668403,
+              40.773128
+            ],
+            [
+              98.689345,
+              40.691952
+            ],
+            [
+              98.72199,
+              40.657911
+            ],
+            [
+              98.762642,
+              40.639748
+            ],
+            [
+              98.802678,
+              40.607043
+            ],
+            [
+              98.80699,
+              40.660181
+            ],
+            [
+              98.790975,
+              40.705564
+            ],
+            [
+              98.984996,
+              40.782644
+            ],
+            [
+              99.041662,
+              40.693767
+            ],
+            [
+              99.102025,
+              40.676522
+            ],
+            [
+              99.12543,
+              40.715091
+            ],
+            [
+              99.172858,
+              40.747289
+            ],
+            [
+              99.174705,
+              40.858278
+            ],
+            [
+              99.565827,
+              40.846961
+            ],
+            [
+              99.673,
+              40.93292
+            ],
+            [
+              99.985897,
+              40.909858
+            ],
+            [
+              100.057346,
+              40.908049
+            ],
+            [
+              100.107853,
+              40.875475
+            ],
+            [
+              100.224882,
+              40.727337
+            ],
+            [
+              100.237201,
+              40.716905
+            ],
+            [
+              100.242744,
+              40.618855
+            ],
+            [
+              100.169447,
+              40.541131
+            ],
+            [
+              100.169447,
+              40.277743
+            ],
+            [
+              100.007455,
+              40.20008
+            ],
+            [
+              99.955716,
+              40.150695
+            ],
+            [
+              99.927383,
+              40.063727
+            ],
+            [
+              99.841152,
+              40.013326
+            ],
+            [
+              99.751225,
+              40.006909
+            ],
+            [
+              99.714268,
+              39.972061
+            ],
+            [
+              99.533182,
+              39.891753
+            ],
+            [
+              99.491298,
+              39.884406
+            ],
+            [
+              99.459885,
+              39.898181
+            ],
+            [
+              99.440791,
+              39.885783
+            ],
+            [
+              99.469124,
+              39.875221
+            ],
+            [
+              99.672384,
+              39.888079
+            ],
+            [
+              99.822058,
+              39.860063
+            ],
+            [
+              99.904593,
+              39.785601
+            ],
+            [
+              99.958796,
+              39.769504
+            ],
+            [
+              100.040716,
+              39.757083
+            ],
+            [
+              100.128179,
+              39.702312
+            ],
+            [
+              100.250135,
+              39.685274
+            ],
+            [
+              100.314193,
+              39.606935
+            ],
+            [
+              100.301258,
+              39.572345
+            ],
+            [
+              100.326512,
+              39.509118
+            ],
+            [
+              100.44354,
+              39.485565
+            ],
+            [
+              100.500823,
+              39.481408
+            ],
+            [
+              100.498975,
+              39.400527
+            ],
+            [
+              100.606764,
+              39.387577
+            ],
+            [
+              100.707778,
+              39.404689
+            ],
+            [
+              100.842053,
+              39.405614
+            ],
+            [
+              100.842669,
+              39.199999
+            ],
+            [
+              100.864227,
+              39.106719
+            ],
+            [
+              100.829118,
+              39.075133
+            ],
+            [
+              100.835278,
+              39.025869
+            ],
+            [
+              100.875314,
+              39.002619
+            ],
+            [
+              100.901799,
+              39.030053
+            ],
+            [
+              100.961545,
+              39.005874
+            ],
+            [
+              100.969553,
+              38.946788
+            ],
+            [
+              101.117378,
+              38.975174
+            ],
+            [
+              101.228863,
+              39.020754
+            ],
+            [
+              101.198682,
+              38.943064
+            ],
+            [
+              101.237486,
+              38.907214
+            ],
+            [
+              101.24303,
+              38.860628
+            ],
+            [
+              101.33542,
+              38.847113
+            ],
+            [
+              101.34158,
+              38.822406
+            ],
+            [
+              101.307087,
+              38.80282
+            ],
+            [
+              101.331109,
+              38.777164
+            ],
+            [
+              101.412413,
+              38.764099
+            ],
+            [
+              101.562702,
+              38.713218
+            ],
+            [
+              101.601506,
+              38.65529
+            ],
+            [
+              101.672955,
+              38.6908
+            ],
+            [
+              101.777049,
+              38.66043
+            ],
+            [
+              101.873751,
+              38.733761
+            ],
+            [
+              101.941505,
+              38.808883
+            ],
+            [
+              102.075164,
+              38.891378
+            ],
+            [
+              102.045599,
+              38.904885
+            ],
+            [
+              101.955055,
+              38.985874
+            ],
+            [
+              101.926106,
+              39.000758
+            ],
+            [
+              101.833715,
+              39.08907
+            ],
+            [
+              101.902701,
+              39.111827
+            ],
+            [
+              102.012338,
+              39.127149
+            ],
+            [
+              102.050526,
+              39.141075
+            ],
+            [
+              102.276576,
+              39.188868
+            ],
+            [
+              102.3548,
+              39.231993
+            ],
+            [
+              102.45335,
+              39.255167
+            ],
+            [
+              102.579002,
+              39.183301
+            ],
+            [
+              102.616574,
+              39.171703
+            ],
+            [
+              102.883892,
+              39.120649
+            ],
+            [
+              103.007696,
+              39.099753
+            ],
+            [
+              103.133347,
+              39.192579
+            ],
+            [
+              103.188166,
+              39.215302
+            ],
+            [
+              103.259615,
+              39.263971
+            ],
+            [
+              103.344615,
+              39.331588
+            ],
+            [
+              103.428998,
+              39.353341
+            ],
+            [
+              103.595302,
+              39.386652
+            ],
+            [
+              103.728961,
+              39.430117
+            ],
+            [
+              103.85338,
+              39.461543
+            ],
+            [
+              103.955626,
+              39.456923
+            ],
+            [
+              104.089901,
+              39.419947
+            ],
+            [
+              104.073271,
+              39.351953
+            ],
+            [
+              104.047401,
+              39.297788
+            ],
+            [
+              104.171205,
+              39.160567
+            ],
+            [
+              104.207546,
+              39.083495
+            ],
+            [
+              104.190915,
+              39.042139
+            ],
+            [
+              104.196459,
+              38.9882
+            ],
+            [
+              104.173053,
+              38.94446
+            ],
+            [
+              104.044322,
+              38.895105
+            ],
+            [
+              104.011677,
+              38.85923
+            ],
+            [
+              103.85954,
+              38.64454
+            ],
+            [
+              103.416063,
+              38.404821
+            ],
+            [
+              103.465339,
+              38.353215
+            ],
+            [
+              103.507838,
+              38.280905
+            ],
+            [
+              103.53494,
+              38.156776
+            ],
+            [
+              103.368636,
+              38.08898
+            ],
+            [
+              103.362477,
+              38.037621
+            ],
+            [
+              103.40744,
+              37.860651
+            ],
+            [
+              103.627947,
+              37.797783
+            ],
+            [
+              103.683381,
+              37.777919
+            ],
+            [
+              103.841062,
+              37.64725
+            ],
+            [
+              103.874938,
+              37.604117
+            ],
+            [
+              103.935916,
+              37.572818
+            ],
+            [
+              104.089285,
+              37.465067
+            ],
+            [
+              104.183524,
+              37.406618
+            ],
+            [
+              104.237727,
+              37.411847
+            ],
+            [
+              104.287002,
+              37.428007
+            ],
+            [
+              104.322726,
+              37.44844
+            ],
+            [
+              104.407726,
+              37.464592
+            ],
+            [
+              104.419429,
+              37.511604
+            ],
+            [
+              104.433595,
+              37.515402
+            ],
+            [
+              104.623305,
+              37.522522
+            ],
+            [
+              104.805007,
+              37.539133
+            ],
+            [
+              104.866601,
+              37.566651
+            ],
+            [
+              105.027977,
+              37.580881
+            ],
+            [
+              105.111128,
+              37.633981
+            ],
+            [
+              105.187505,
+              37.657674
+            ],
+            [
+              105.221998,
+              37.677097
+            ],
+            [
+              105.315004,
+              37.702197
+            ],
+            [
+              105.4037,
+              37.710246
+            ],
+            [
+              105.467141,
+              37.695094
+            ],
+            [
+              105.598952,
+              37.699356
+            ],
+            [
+              105.616199,
+              37.722555
+            ],
+            [
+              105.622358,
+              37.777919
+            ],
+            [
+              105.677177,
+              37.771769
+            ],
+            [
+              105.760944,
+              37.799674
+            ],
+            [
+              105.80406,
+              37.862068
+            ],
+            [
+              105.799749,
+              37.939986
+            ],
+            [
+              105.840401,
+              38.004147
+            ],
+            [
+              105.780655,
+              38.084741
+            ],
+            [
+              105.76772,
+              38.121474
+            ],
+            [
+              105.775111,
+              38.186887
+            ],
+            [
+              105.802828,
+              38.220277
+            ],
+            [
+              105.842248,
+              38.240962
+            ],
+            [
+              105.86627,
+              38.296406
+            ],
+            [
+              105.821307,
+              38.366824
+            ],
+            [
+              105.835473,
+              38.387467
+            ],
+            [
+              105.827466,
+              38.432486
+            ],
+            [
+              105.850872,
+              38.443736
+            ],
+            [
+              105.836705,
+              38.476071
+            ],
+            [
+              105.863806,
+              38.53508
+            ],
+            [
+              105.856415,
+              38.569714
+            ],
+            [
+              105.874277,
+              38.593105
+            ],
+            [
+              105.852719,
+              38.641735
+            ],
+            [
+              105.894603,
+              38.696405
+            ],
+            [
+              105.88598,
+              38.716953
+            ],
+            [
+              105.908154,
+              38.737496
+            ],
+            [
+              105.909386,
+              38.791159
+            ],
+            [
+              105.992538,
+              38.857366
+            ],
+            [
+              105.97098,
+              38.909077
+            ],
+            [
+              106.021487,
+              38.953769
+            ],
+            [
+              106.060907,
+              38.96866
+            ],
+            [
+              106.087392,
+              39.006339
+            ],
+            [
+              106.078153,
+              39.026333
+            ],
+            [
+              106.096631,
+              39.084889
+            ],
+            [
+              106.145907,
+              39.153142
+            ],
+            [
+              106.170544,
+              39.163352
+            ],
+            [
+              106.192718,
+              39.142932
+            ],
+            [
+              106.251232,
+              39.131327
+            ],
+            [
+              106.285109,
+              39.146181
+            ],
+            [
+              106.29558,
+              39.167992
+            ],
+            [
+              106.280181,
+              39.262118
+            ],
+            [
+              106.402753,
+              39.291767
+            ],
+            [
+              106.511774,
+              39.272311
+            ],
+            [
+              106.525325,
+              39.308439
+            ],
+            [
+              106.556122,
+              39.322329
+            ],
+            [
+              106.602318,
+              39.37555
+            ],
+            [
+              106.643586,
+              39.357969
+            ],
+            [
+              106.683622,
+              39.357506
+            ],
+            [
+              106.751375,
+              39.381564
+            ],
+            [
+              106.781556,
+              39.371849
+            ],
+            [
+              106.806809,
+              39.318625
+            ],
+            [
+              106.806193,
+              39.277407
+            ],
+            [
+              106.790795,
+              39.241263
+            ],
+            [
+              106.795723,
+              39.214375
+            ],
+            [
+              106.825288,
+              39.19397
+            ],
+            [
+              106.859164,
+              39.107648
+            ],
+            [
+              106.878874,
+              39.091392
+            ],
+            [
+              106.933693,
+              39.076527
+            ],
+            [
+              106.96757,
+              39.054688
+            ],
+            [
+              106.971881,
+              39.026333
+            ],
+            [
+              106.954019,
+              38.941202
+            ],
+            [
+              106.837606,
+              38.847579
+            ],
+            [
+              106.756302,
+              38.748699
+            ],
+            [
+              106.709491,
+              38.718821
+            ],
+            [
+              106.66268,
+              38.601524
+            ],
+            [
+              106.647897,
+              38.470917
+            ],
+            [
+              106.599854,
+              38.389812
+            ],
+            [
+              106.482209,
+              38.319417
+            ],
+            [
+              106.555506,
+              38.263521
+            ],
+            [
+              106.627571,
+              38.232501
+            ],
+            [
+              106.654672,
+              38.22921
+            ],
+            [
+              106.737824,
+              38.197706
+            ],
+            [
+              106.779092,
+              38.171833
+            ],
+            [
+              106.858548,
+              38.156306
+            ],
+            [
+              106.942316,
+              38.132302
+            ],
+            [
+              107.010069,
+              38.120532
+            ],
+            [
+              107.051337,
+              38.122886
+            ],
+            [
+              107.071047,
+              38.138892
+            ],
+            [
+              107.119091,
+              38.134185
+            ],
+            [
+              107.138801,
+              38.161011
+            ],
+            [
+              107.19054,
+              38.153953
+            ],
+            [
+              107.240431,
+              38.111586
+            ],
+            [
+              107.33159,
+              38.086625
+            ],
+            [
+              107.3938,
+              38.014993
+            ],
+            [
+              107.440611,
+              37.995659
+            ],
+            [
+              107.411662,
+              37.948009
+            ],
+            [
+              107.448618,
+              37.933378
+            ],
+            [
+              107.49235,
+              37.944706
+            ],
+            [
+              107.560719,
+              37.893717
+            ],
+            [
+              107.65003,
+              37.86443
+            ],
+            [
+              107.684523,
+              37.888522
+            ],
+            [
+              107.732566,
+              37.84931
+            ],
+            [
+              107.842819,
+              37.828987
+            ],
+            [
+              107.884703,
+              37.808186
+            ],
+            [
+              107.982022,
+              37.787378
+            ],
+            [
+              107.993109,
+              37.735335
+            ],
+            [
+              108.025753,
+              37.696041
+            ],
+            [
+              108.012819,
+              37.66857
+            ],
+            [
+              108.025137,
+              37.649619
+            ],
+            [
+              108.055318,
+              37.652462
+            ],
+            [
+              108.134159,
+              37.622131
+            ],
+            [
+              108.193905,
+              37.638246
+            ],
+            [
+              108.205608,
+              37.655779
+            ],
+            [
+              108.24626,
+              37.665728
+            ],
+            [
+              108.293071,
+              37.656726
+            ],
+            [
+              108.301078,
+              37.640616
+            ],
+            [
+              108.422418,
+              37.648672
+            ],
+            [
+              108.485244,
+              37.678044
+            ],
+            [
+              108.532671,
+              37.690832
+            ],
+            [
+              108.628142,
+              37.651988
+            ],
+            [
+              108.699591,
+              37.669518
+            ],
+            [
+              108.720533,
+              37.683728
+            ],
+            [
+              108.777815,
+              37.683728
+            ],
+            [
+              108.791982,
+              37.700303
+            ],
+            [
+              108.784591,
+              37.764673
+            ],
+            [
+              108.799989,
+              37.784068
+            ],
+            [
+              108.791982,
+              37.872934
+            ],
+            [
+              108.798141,
+              37.93385
+            ],
+            [
+              108.82709,
+              37.989056
+            ],
+            [
+              108.797525,
+              38.04799
+            ],
+            [
+              108.830786,
+              38.049875
+            ],
+            [
+              108.883141,
+              38.01405
+            ],
+            [
+              108.893612,
+              37.978207
+            ],
+            [
+              108.93488,
+              37.922521
+            ],
+            [
+              108.9743,
+              37.931962
+            ],
+            [
+              108.982923,
+              37.964053
+            ],
+            [
+              109.018648,
+              37.971602
+            ],
+            [
+              109.037742,
+              38.021593
+            ],
+            [
+              109.06977,
+              38.023008
+            ],
+            [
+              109.050676,
+              38.055059
+            ],
+            [
+              109.069155,
+              38.091336
+            ],
+            [
+              108.964445,
+              38.154894
+            ],
+            [
+              108.938575,
+              38.207582
+            ],
+            [
+              108.976148,
+              38.245192
+            ],
+            [
+              108.961981,
+              38.26493
+            ],
+            [
+              109.007561,
+              38.359316
+            ],
+            [
+              109.051292,
+              38.385122
+            ],
+            [
+              109.054372,
+              38.433892
+            ],
+            [
+              109.128901,
+              38.480288
+            ],
+            [
+              109.175712,
+              38.518694
+            ],
+            [
+              109.196654,
+              38.552867
+            ],
+            [
+              109.276726,
+              38.623035
+            ],
+            [
+              109.331545,
+              38.597783
+            ],
+            [
+              109.367269,
+              38.627711
+            ],
+            [
+              109.329081,
+              38.66043
+            ],
+            [
+              109.338936,
+              38.701542
+            ],
+            [
+              109.404226,
+              38.720689
+            ],
+            [
+              109.444262,
+              38.782763
+            ],
+            [
+              109.511399,
+              38.833595
+            ],
+            [
+              109.549587,
+              38.805618
+            ],
+            [
+              109.624116,
+              38.85457
+            ],
+            [
+              109.672159,
+              38.928167
+            ],
+            [
+              109.685094,
+              38.968195
+            ],
+            [
+              109.665384,
+              38.981687
+            ],
+            [
+              109.72513,
+              39.018429
+            ],
+            [
+              109.762086,
+              39.057476
+            ],
+            [
+              109.793499,
+              39.074204
+            ],
+            [
+              109.851397,
+              39.122971
+            ],
+            [
+              109.890818,
+              39.103932
+            ],
+            [
+              109.92223,
+              39.107183
+            ],
+            [
+              109.893897,
+              39.141075
+            ],
+            [
+              109.961035,
+              39.191651
+            ],
+            [
+              109.871723,
+              39.243581
+            ],
+            [
+              109.90252,
+              39.271848
+            ],
+            [
+              109.962267,
+              39.212056
+            ],
+            [
+              110.041107,
+              39.21623
+            ],
+            [
+              110.109476,
+              39.249606
+            ],
+            [
+              110.217881,
+              39.281113
+            ],
+            [
+              110.184005,
+              39.355192
+            ],
+            [
+              110.161831,
+              39.387115
+            ],
+            [
+              110.136577,
+              39.39174
+            ],
+            [
+              110.12549,
+              39.432891
+            ],
+            [
+              110.152592,
+              39.45415
+            ],
+            [
+              110.243751,
+              39.423645
+            ],
+            [
+              110.257917,
+              39.407001
+            ],
+            [
+              110.385417,
+              39.310291
+            ],
+            [
+              110.429764,
+              39.341308
+            ],
+            [
+              110.434692,
+              39.381101
+            ],
+            [
+              110.482735,
+              39.360745
+            ],
+            [
+              110.524003,
+              39.382952
+            ],
+            [
+              110.559728,
+              39.351027
+            ],
+            [
+              110.566503,
+              39.320014
+            ],
+            [
+              110.596684,
+              39.282966
+            ],
+            [
+              110.626249,
+              39.266751
+            ],
+            [
+              110.702626,
+              39.273701
+            ],
+            [
+              110.731575,
+              39.30705
+            ],
+            [
+              110.73835,
+              39.348713
+            ],
+            [
+              110.782698,
+              39.38804
+            ],
+            [
+              110.869545,
+              39.494341
+            ],
+            [
+              110.891103,
+              39.509118
+            ],
+            [
+              110.958856,
+              39.519275
+            ],
+            [
+              111.017371,
+              39.552045
+            ],
+            [
+              111.101138,
+              39.559428
+            ],
+            [
+              111.136863,
+              39.587106
+            ],
+            [
+              111.154725,
+              39.569116
+            ],
+            [
+              111.148566,
+              39.531277
+            ],
+            [
+              111.10545,
+              39.497573
+            ],
+            [
+              111.10545,
+              39.472631
+            ],
+            [
+              111.058639,
+              39.447681
+            ],
+            [
+              111.064182,
+              39.400989
+            ],
+            [
+              111.098059,
+              39.401914
+            ],
+            [
+              111.087588,
+              39.376013
+            ],
+            [
+              111.125776,
+              39.366297
+            ],
+            [
+              111.143022,
+              39.407926
+            ],
+            [
+              111.171971,
+              39.423183
+            ],
+            [
+              111.337043,
+              39.420872
+            ],
+            [
+              111.358601,
+              39.432428
+            ],
+            [
+              111.372152,
+              39.479099
+            ],
+            [
+              111.431282,
+              39.508656
+            ],
+            [
+              111.422043,
+              39.539123
+            ],
+            [
+              111.441137,
+              39.59679
+            ],
+            [
+              111.460847,
+              39.606935
+            ],
+            [
+              111.445448,
+              39.640124
+            ],
+            [
+              111.497187,
+              39.661781
+            ],
+            [
+              111.525521,
+              39.662242
+            ],
+            [
+              111.625303,
+              39.633672
+            ],
+            [
+              111.659179,
+              39.641507
+            ],
+            [
+              111.722621,
+              39.606013
+            ],
+            [
+              111.783599,
+              39.58895
+            ],
+            [
+              111.842729,
+              39.620305
+            ],
+            [
+              111.87907,
+              39.606013
+            ],
+            [
+              111.9382,
+              39.623071
+            ],
+            [
+              111.925265,
+              39.66731
+            ],
+            [
+              111.959758,
+              39.692642
+            ],
+            [
+              111.970229,
+              39.796638
+            ],
+            [
+              112.012729,
+              39.827438
+            ],
+            [
+              112.042294,
+              39.886243
+            ],
+            [
+              112.07617,
+              39.919298
+            ],
+            [
+              112.133453,
+              40.001866
+            ],
+            [
+              112.142076,
+              40.027076
+            ],
+            [
+              112.182112,
+              40.061437
+            ],
+            [
+              112.183344,
+              40.083877
+            ],
+            [
+              112.232003,
+              40.133311
+            ],
+            [
+              112.232619,
+              40.169905
+            ],
+            [
+              112.299756,
+              40.21105
+            ],
+            [
+              112.310227,
+              40.256281
+            ],
+            [
+              112.349031,
+              40.257194
+            ],
+            [
+              112.418017,
+              40.295091
+            ],
+            [
+              112.456205,
+              40.300112
+            ],
+            [
+              112.511639,
+              40.269068
+            ],
+            [
+              112.6299,
+              40.235725
+            ],
+            [
+              112.712436,
+              40.178593
+            ],
+            [
+              112.744464,
+              40.167161
+            ],
+            [
+              112.848558,
+              40.206937
+            ],
+            [
+              112.898449,
+              40.329317
+            ],
+            [
+              113.03334,
+              40.368997
+            ],
+            [
+              113.083231,
+              40.374925
+            ],
+            [
+              113.251382,
+              40.413211
+            ],
+            [
+              113.27602,
+              40.388601
+            ],
+            [
+              113.316672,
+              40.319736
+            ],
+            [
+              113.387505,
+              40.319279
+            ],
+            [
+              113.500222,
+              40.334335
+            ],
+            [
+              113.559968,
+              40.348476
+            ],
+            [
+              113.688699,
+              40.448288
+            ],
+            [
+              113.763228,
+              40.473787
+            ],
+            [
+              113.794641,
+              40.517932
+            ],
+            [
+              113.850691,
+              40.460583
+            ],
+            [
+              113.890112,
+              40.466503
+            ],
+            [
+              113.948626,
+              40.514747
+            ],
+            [
+              114.011452,
+              40.515657
+            ],
+            [
+              114.061959,
+              40.52885
+            ],
+            [
+              114.080437,
+              40.547952
+            ],
+            [
+              114.076741,
+              40.575686
+            ],
+            [
+              114.041633,
+              40.608861
+            ],
+            [
+              114.07243,
+              40.679246
+            ],
+            [
+              114.063806,
+              40.706925
+            ],
+            [
+              114.084748,
+              40.729605
+            ],
+            [
+              114.134639,
+              40.737314
+            ],
+            [
+              114.103227,
+              40.770861
+            ],
+            [
+              114.104458,
+              40.797597
+            ],
+            [
+              114.080437,
+              40.790348
+            ],
+            [
+              114.044712,
+              40.830661
+            ],
+            [
+              114.073661,
+              40.857372
+            ],
+            [
+              114.055183,
+              40.867782
+            ],
+            [
+              114.041633,
+              40.917546
+            ],
+            [
+              114.057647,
+              40.925234
+            ],
+            [
+              113.994821,
+              40.938798
+            ],
+            [
+              113.973263,
+              40.983087
+            ],
+            [
+              113.868554,
+              41.06887
+            ],
+            [
+              113.819279,
+              41.09774
+            ],
+            [
+              113.877793,
+              41.115777
+            ],
+            [
+              113.920293,
+              41.172112
+            ],
+            [
+              113.960945,
+              41.171211
+            ],
+            [
+              113.996669,
+              41.19238
+            ],
+            [
+              114.016379,
+              41.231999
+            ],
+            [
+              113.992357,
+              41.269794
+            ],
+            [
+              113.971416,
+              41.239649
+            ],
+            [
+              113.95109,
+              41.282837
+            ],
+            [
+              113.914749,
+              41.294529
+            ],
+            [
+              113.899351,
+              41.316108
+            ],
+            [
+              113.92522,
+              41.325546
+            ],
+            [
+              113.94493,
+              41.392477
+            ],
+            [
+              113.871017,
+              41.413126
+            ],
+            [
+              113.877793,
+              41.431076
+            ],
+            [
+              113.919677,
+              41.454404
+            ],
+            [
+              113.933227,
+              41.487139
+            ],
+            [
+              113.953553,
+              41.483553
+            ],
+            [
+              113.976959,
+              41.505966
+            ],
+            [
+              114.032394,
+              41.529715
+            ],
+            [
+              114.101379,
+              41.537779
+            ],
+            [
+              114.230726,
+              41.513584
+            ],
+            [
+              114.221487,
+              41.582111
+            ],
+            [
+              114.226414,
+              41.616572
+            ],
+            [
+              114.259059,
+              41.623282
+            ],
+            [
+              114.215328,
+              41.68499
+            ],
+            [
+              114.237501,
+              41.698843
+            ],
+            [
+              114.206704,
+              41.7386
+            ],
+            [
+              114.215328,
+              41.75646
+            ],
+            [
+              114.200545,
+              41.789934
+            ],
+            [
+              114.282465,
+              41.863517
+            ],
+            [
+              114.343443,
+              41.926774
+            ],
+            [
+              114.352066,
+              41.953484
+            ],
+            [
+              114.419203,
+              41.942356
+            ],
+            [
+              114.478334,
+              41.951704
+            ],
+            [
+              114.511594,
+              41.981962
+            ],
+            [
+              114.467863,
+              42.025989
+            ],
+            [
+              114.480181,
+              42.064654
+            ],
+            [
+              114.502355,
+              42.06732
+            ],
+            [
+              114.510978,
+              42.110844
+            ],
+            [
+              114.560254,
+              42.132595
+            ],
+            [
+              114.647717,
+              42.109512
+            ],
+            [
+              114.675434,
+              42.12061
+            ],
+            [
+              114.75489,
+              42.115727
+            ],
+            [
+              114.789383,
+              42.130819
+            ],
+            [
+              114.79431,
+              42.149457
+            ],
+            [
+              114.825723,
+              42.139695
+            ],
+            [
+              114.86268,
+              42.097967
+            ],
+            [
+              114.860832,
+              42.054879
+            ],
+            [
+              114.9021,
+              42.015763
+            ],
+            [
+              114.915035,
+              41.960605
+            ],
+            [
+              114.923658,
+              41.871093
+            ],
+            [
+              114.939056,
+              41.846132
+            ],
+            [
+              114.922426,
+              41.825175
+            ],
+            [
+              114.868839,
+              41.813579
+            ],
+            [
+              114.89594,
+              41.76762
+            ],
+            [
+              114.902716,
+              41.695715
+            ],
+            [
+              114.895325,
+              41.636255
+            ],
+            [
+              114.860832,
+              41.60091
+            ],
+            [
+              115.016049,
+              41.615229
+            ],
+            [
+              115.056085,
+              41.602253
+            ],
+            [
+              115.0992,
+              41.62373
+            ],
+            [
+              115.195287,
+              41.602253
+            ],
+            [
+              115.20391,
+              41.571367
+            ],
+            [
+              115.256881,
+              41.580768
+            ],
+            [
+              115.26612,
+              41.616124
+            ],
+            [
+              115.290142,
+              41.622835
+            ],
+            [
+              115.310468,
+              41.592854
+            ],
+            [
+              115.377605,
+              41.603148
+            ],
+            [
+              115.345576,
+              41.635807
+            ],
+            [
+              115.360975,
+              41.661297
+            ],
+            [
+              115.319091,
+              41.691693
+            ],
+            [
+              115.346808,
+              41.712247
+            ],
+            [
+              115.42996,
+              41.728775
+            ],
+            [
+              115.488474,
+              41.760924
+            ],
+            [
+              115.519887,
+              41.76762
+            ],
+            [
+              115.57409,
+              41.80555
+            ],
+            [
+              115.654162,
+              41.829189
+            ],
+            [
+              115.688038,
+              41.867528
+            ],
+            [
+              115.726227,
+              41.870202
+            ],
+            [
+              115.811226,
+              41.912525
+            ],
+            [
+              115.834632,
+              41.93835
+            ],
+            [
+              115.85311,
+              41.927665
+            ],
+            [
+              115.916552,
+              41.945027
+            ],
+            [
+              115.954124,
+              41.874213
+            ],
+            [
+              115.994776,
+              41.828743
+            ],
+            [
+              116.007095,
+              41.797966
+            ],
+            [
+              116.007095,
+              41.79752
+            ],
+            [
+              116.034196,
+              41.782795
+            ],
+            [
+              116.09887,
+              41.776547
+            ],
+            [
+              116.129051,
+              41.805996
+            ],
+            [
+              116.106877,
+              41.831419
+            ],
+            [
+              116.122892,
+              41.861734
+            ],
+            [
+              116.194341,
+              41.861734
+            ],
+            [
+              116.212819,
+              41.885352
+            ],
+            [
+              116.223906,
+              41.932562
+            ],
+            [
+              116.298434,
+              41.96817
+            ],
+            [
+              116.310137,
+              41.997086
+            ],
+            [
+              116.373579,
+              42.009983
+            ],
+            [
+              116.414231,
+              41.982407
+            ],
+            [
+              116.393289,
+              41.942802
+            ],
+            [
+              116.453651,
+              41.945917
+            ],
+            [
+              116.4826,
+              41.975734
+            ],
+            [
+              116.510933,
+              41.974399
+            ],
+            [
+              116.553433,
+              41.928555
+            ],
+            [
+              116.597165,
+              41.935679
+            ],
+            [
+              116.639049,
+              41.929891
+            ],
+            [
+              116.66923,
+              41.947698
+            ],
+            [
+              116.727744,
+              41.951259
+            ],
+            [
+              116.748686,
+              41.984186
+            ],
+            [
+              116.796113,
+              41.977958
+            ],
+            [
+              116.879881,
+              42.018431
+            ],
+            [
+              116.890352,
+              42.092639
+            ],
+            [
+              116.850316,
+              42.156556
+            ],
+            [
+              116.825062,
+              42.155669
+            ],
+            [
+              116.789338,
+              42.200462
+            ],
+            [
+              116.903287,
+              42.190708
+            ],
+            [
+              116.918685,
+              42.229716
+            ],
+            [
+              116.897743,
+              42.297479
+            ],
+            [
+              116.886656,
+              42.366496
+            ],
+            [
+              116.910678,
+              42.394789
+            ],
+            [
+              116.910062,
+              42.395231
+            ],
+            [
+              116.921765,
+              42.403628
+            ],
+            [
+              116.936547,
+              42.410256
+            ],
+            [
+              116.944555,
+              42.415116
+            ],
+            [
+              116.97104,
+              42.427486
+            ],
+            [
+              116.974736,
+              42.426603
+            ],
+            [
+              116.99075,
+              42.425719
+            ],
+            [
+              117.005533,
+              42.43367
+            ],
+            [
+              117.009228,
+              42.44957
+            ],
+            [
+              117.01662,
+              42.456193
+            ],
+            [
+              117.080061,
+              42.463699
+            ],
+            [
+              117.09546,
+              42.484004
+            ],
+            [
+              117.135496,
+              42.468996
+            ],
+            [
+              117.188467,
+              42.468114
+            ],
+            [
+              117.275314,
+              42.481797
+            ],
+            [
+              117.332596,
+              42.46105
+            ],
+            [
+              117.390495,
+              42.461933
+            ],
+            [
+              117.413284,
+              42.471645
+            ],
+            [
+              117.410205,
+              42.519743
+            ],
+            [
+              117.387415,
+              42.517537
+            ],
+            [
+              117.434226,
+              42.557224
+            ],
+            [
+              117.435458,
+              42.585431
+            ],
+            [
+              117.475494,
+              42.602613
+            ],
+            [
+              117.530313,
+              42.590278
+            ],
+            [
+              117.537088,
+              42.603054
+            ],
+            [
+              117.60053,
+              42.603054
+            ],
+            [
+              117.667051,
+              42.582347
+            ],
+            [
+              117.708935,
+              42.588515
+            ],
+            [
+              117.779768,
+              42.61847
+            ],
+            [
+              117.801326,
+              42.612744
+            ],
+            [
+              117.797631,
+              42.585431
+            ],
+            [
+              117.856761,
+              42.539148
+            ],
+            [
+              117.874007,
+              42.510038
+            ],
+            [
+              117.997811,
+              42.416884
+            ],
+            [
+              118.024296,
+              42.385064
+            ],
+            [
+              118.008898,
+              42.346595
+            ],
+            [
+              118.060021,
+              42.298364
+            ],
+            [
+              118.047702,
+              42.280656
+            ],
+            [
+              117.974405,
+              42.25054
+            ],
+            [
+              117.977485,
+              42.229716
+            ],
+            [
+              118.033535,
+              42.199132
+            ],
+            [
+              118.106216,
+              42.172082
+            ],
+            [
+              118.089586,
+              42.12283
+            ],
+            [
+              118.097593,
+              42.105072
+            ],
+            [
+              118.155491,
+              42.081091
+            ],
+            [
+              118.116687,
+              42.037102
+            ],
+            [
+              118.194296,
+              42.031324
+            ],
+            [
+              118.220165,
+              42.058434
+            ],
+            [
+              118.212774,
+              42.081091
+            ],
+            [
+              118.239259,
+              42.092639
+            ],
+            [
+              118.27252,
+              42.083312
+            ],
+            [
+              118.296541,
+              42.057545
+            ],
+            [
+              118.286686,
+              42.033991
+            ],
+            [
+              118.239875,
+              42.024655
+            ],
+            [
+              118.291614,
+              42.007759
+            ],
+            [
+              118.313788,
+              41.98819
+            ],
+            [
+              118.306396,
+              41.940131
+            ],
+            [
+              118.268824,
+              41.930336
+            ],
+            [
+              118.340273,
+              41.87243
+            ],
+            [
+              118.335346,
+              41.845241
+            ],
+            [
+              118.29223,
+              41.772976
+            ],
+            [
+              118.247266,
+              41.773869
+            ],
+            [
+              118.236179,
+              41.80778
+            ],
+            [
+              118.178281,
+              41.814917
+            ],
+            [
+              118.140093,
+              41.784134
+            ],
+            [
+              118.132702,
+              41.733241
+            ],
+            [
+              118.155491,
+              41.712694
+            ],
+            [
+              118.159187,
+              41.67605
+            ],
+            [
+              118.206614,
+              41.650566
+            ],
+            [
+              118.215237,
+              41.59554
+            ],
+            [
+              118.302701,
+              41.55256
+            ],
+            [
+              118.315636,
+              41.512688
+            ],
+            [
+              118.271904,
+              41.471446
+            ],
+            [
+              118.327338,
+              41.450816
+            ],
+            [
+              118.348896,
+              41.428384
+            ],
+            [
+              118.361215,
+              41.384844
+            ],
+            [
+              118.348896,
+              41.342622
+            ],
+            [
+              118.380309,
+              41.312062
+            ],
+            [
+              118.412338,
+              41.331838
+            ],
+            [
+              118.528135,
+              41.355202
+            ],
+            [
+              118.629765,
+              41.346666
+            ],
+            [
+              118.677192,
+              41.35026
+            ],
+            [
+              118.741866,
+              41.324198
+            ],
+            [
+              118.770199,
+              41.352956
+            ],
+            [
+              118.843496,
+              41.374516
+            ],
+            [
+              118.844727,
+              41.342622
+            ],
+            [
+              118.890923,
+              41.300823
+            ],
+            [
+              118.949437,
+              41.317906
+            ],
+            [
+              118.980234,
+              41.305769
+            ],
+            [
+              119.092951,
+              41.293629
+            ],
+            [
+              119.168712,
+              41.294978
+            ],
+            [
+              119.197661,
+              41.282837
+            ],
+            [
+              119.211827,
+              41.308016
+            ],
+            [
+              119.239545,
+              41.31431
+            ],
+            [
+              119.296211,
+              41.325097
+            ],
+            [
+              119.330704,
+              41.385293
+            ],
+            [
+              119.309762,
+              41.405944
+            ],
+            [
+              119.376283,
+              41.422102
+            ],
+            [
+              119.378131,
+              41.459787
+            ],
+            [
+              119.401537,
+              41.472343
+            ],
+            [
+              119.406464,
+              41.503276
+            ],
+            [
+              119.361501,
+              41.545841
+            ],
+            [
+              119.362116,
+              41.566442
+            ],
+            [
+              119.420015,
+              41.567785
+            ],
+            [
+              119.415703,
+              41.590169
+            ],
+            [
+              119.342406,
+              41.617914
+            ],
+            [
+              119.307914,
+              41.657273
+            ],
+            [
+              119.299907,
+              41.705545
+            ],
+            [
+              119.319001,
+              41.727435
+            ],
+            [
+              119.317769,
+              41.764049
+            ],
+            [
+              119.292515,
+              41.790827
+            ],
+            [
+              119.312841,
+              41.80555
+            ],
+            [
+              119.334399,
+              41.871539
+            ],
+            [
+              119.323312,
+              41.889807
+            ],
+            [
+              119.340559,
+              41.926774
+            ],
+            [
+              119.323928,
+              41.937014
+            ],
+            [
+              119.324544,
+              41.969505
+            ],
+            [
+              119.375667,
+              42.023322
+            ],
+            [
+              119.384906,
+              42.08953
+            ],
+            [
+              119.352261,
+              42.118391
+            ],
+            [
+              119.314689,
+              42.119723
+            ],
+            [
+              119.30853,
+              42.147239
+            ],
+            [
+              119.286972,
+              42.154781
+            ],
+            [
+              119.277733,
+              42.185387
+            ],
+            [
+              119.237697,
+              42.200905
+            ],
+            [
+              119.274037,
+              42.239021
+            ],
+            [
+              119.280197,
+              42.260728
+            ],
+            [
+              119.34795,
+              42.300578
+            ],
+            [
+              119.432949,
+              42.317396
+            ],
+            [
+              119.482841,
+              42.347037
+            ],
+            [
+              119.502551,
+              42.388159
+            ],
+            [
+              119.540123,
+              42.363401
+            ],
+            [
+              119.572152,
+              42.359421
+            ],
+            [
+              119.571536,
+              42.335536
+            ],
+            [
+              119.539507,
+              42.297922
+            ],
+            [
+              119.557985,
+              42.289068
+            ],
+            [
+              119.609108,
+              42.276671
+            ],
+            [
+              119.617115,
+              42.252755
+            ],
+            [
+              119.679941,
+              42.240793
+            ],
+            [
+              119.744615,
+              42.211545
+            ],
+            [
+              119.841933,
+              42.215534
+            ],
+            [
+              119.854868,
+              42.170308
+            ],
+            [
+              119.837622,
+              42.135257
+            ],
+            [
+              119.845629,
+              42.097079
+            ],
+            [
+              119.87581,
+              42.077982
+            ],
+            [
+              119.897368,
+              42.030879
+            ],
+            [
+              119.921389,
+              42.014429
+            ],
+            [
+              119.924469,
+              41.98908
+            ],
+            [
+              119.950954,
+              41.974399
+            ],
+            [
+              119.954034,
+              41.923212
+            ],
+            [
+              119.989759,
+              41.899163
+            ],
+            [
+              120.023019,
+              41.816701
+            ],
+            [
+              120.041498,
+              41.818932
+            ],
+            [
+              120.050737,
+              41.776101
+            ],
+            [
+              120.024867,
+              41.737707
+            ],
+            [
+              120.035954,
+              41.708226
+            ],
+            [
+              120.096316,
+              41.697056
+            ],
+            [
+              120.1382,
+              41.729221
+            ],
+            [
+              120.127113,
+              41.77253
+            ],
+            [
+              120.183164,
+              41.826513
+            ],
+            [
+              120.188707,
+              41.848361
+            ],
+            [
+              120.215808,
+              41.853265
+            ],
+            [
+              120.251533,
+              41.884016
+            ],
+            [
+              120.286641,
+              41.880005
+            ],
+            [
+              120.290337,
+              41.897381
+            ],
+            [
+              120.260156,
+              41.904062
+            ],
+            [
+              120.271859,
+              41.925439
+            ],
+            [
+              120.318054,
+              41.93746
+            ],
+            [
+              120.309431,
+              41.951704
+            ],
+            [
+              120.373489,
+              41.994862
+            ],
+            [
+              120.399358,
+              41.984631
+            ],
+            [
+              120.456641,
+              42.016208
+            ],
+            [
+              120.450481,
+              42.057101
+            ],
+            [
+              120.493597,
+              42.073539
+            ],
+            [
+              120.466496,
+              42.105516
+            ],
+            [
+              120.56751,
+              42.152119
+            ],
+            [
+              120.58414,
+              42.167203
+            ],
+            [
+              120.624792,
+              42.154338
+            ],
+            [
+              120.72211,
+              42.203565
+            ],
+            [
+              120.745516,
+              42.223512
+            ],
+            [
+              120.79048,
+              42.218636
+            ],
+            [
+              120.820661,
+              42.227943
+            ],
+            [
+              120.8299,
+              42.252755
+            ],
+            [
+              120.883487,
+              42.242565
+            ],
+            [
+              120.883487,
+              42.269585
+            ],
+            [
+              120.933994,
+              42.27977
+            ],
+            [
+              120.992508,
+              42.264714
+            ],
+            [
+              121.028848,
+              42.242565
+            ],
+            [
+              121.070732,
+              42.254083
+            ],
+            [
+              121.087978,
+              42.278885
+            ],
+            [
+              121.120623,
+              42.280656
+            ],
+            [
+              121.133558,
+              42.300135
+            ],
+            [
+              121.184681,
+              42.333324
+            ],
+            [
+              121.218558,
+              42.371802
+            ],
+            [
+              121.285079,
+              42.387717
+            ],
+            [
+              121.314644,
+              42.42837
+            ],
+            [
+              121.304789,
+              42.435879
+            ],
+            [
+              121.386093,
+              42.474294
+            ],
+            [
+              121.434752,
+              42.475176
+            ],
+            [
+              121.4791,
+              42.49636
+            ],
+            [
+              121.506201,
+              42.482239
+            ],
+            [
+              121.570875,
+              42.487093
+            ],
+            [
+              121.607831,
+              42.516214
+            ],
+            [
+              121.604136,
+              42.495037
+            ],
+            [
+              121.66573,
+              42.437204
+            ],
+            [
+              121.69899,
+              42.438529
+            ],
+            [
+              121.747649,
+              42.484887
+            ],
+            [
+              121.803084,
+              42.514891
+            ],
+            [
+              121.817867,
+              42.504303
+            ],
+            [
+              121.831417,
+              42.533856
+            ],
+            [
+              121.844352,
+              42.522389
+            ],
+            [
+              121.889931,
+              42.556784
+            ],
+            [
+              121.921344,
+              42.605697
+            ],
+            [
+              121.915801,
+              42.656332
+            ],
+            [
+              121.94167,
+              42.666014
+            ],
+            [
+              121.939207,
+              42.688453
+            ],
+            [
+              122.018663,
+              42.69901
+            ],
+            [
+              122.062394,
+              42.723635
+            ],
+            [
+              122.072865,
+              42.710444
+            ],
+            [
+              122.160945,
+              42.684934
+            ],
+            [
+              122.204676,
+              42.685374
+            ],
+            [
+              122.204676,
+              42.732867
+            ],
+            [
+              122.261343,
+              42.695931
+            ],
+            [
+              122.324785,
+              42.684934
+            ],
+            [
+              122.338951,
+              42.669975
+            ],
+            [
+              122.396234,
+              42.684054
+            ],
+            [
+              122.396234,
+              42.707366
+            ],
+            [
+              122.460907,
+              42.755282
+            ],
+            [
+              122.439349,
+              42.770221
+            ],
+            [
+              122.371596,
+              42.776371
+            ],
+            [
+              122.35127,
+              42.830378
+            ],
+            [
+              122.436886,
+              42.843105
+            ],
+            [
+              122.556378,
+              42.827745
+            ],
+            [
+              122.576088,
+              42.819405
+            ],
+            [
+              122.580399,
+              42.789987
+            ],
+            [
+              122.624747,
+              42.773296
+            ],
+            [
+              122.653696,
+              42.78252
+            ],
+            [
+              122.733152,
+              42.786034
+            ],
+            [
+              122.73808,
+              42.77066
+            ],
+            [
+              122.786123,
+              42.757479
+            ],
+            [
+              122.848949,
+              42.712203
+            ],
+            [
+              122.883442,
+              42.751766
+            ],
+            [
+              122.887137,
+              42.770221
+            ],
+            [
+              122.925941,
+              42.772417
+            ],
+            [
+              122.945651,
+              42.753524
+            ],
+            [
+              122.980144,
+              42.777689
+            ],
+            [
+              123.058368,
+              42.768903
+            ],
+            [
+              123.118114,
+              42.801405
+            ],
+            [
+              123.227752,
+              42.831695
+            ],
+            [
+              123.169853,
+              42.859777
+            ],
+            [
+              123.188947,
+              42.895739
+            ],
+            [
+              123.18402,
+              42.925983
+            ],
+            [
+              123.259165,
+              42.993431
+            ],
+            [
+              123.323222,
+              43.000872
+            ],
+            [
+              123.434707,
+              43.027565
+            ],
+            [
+              123.474743,
+              43.042438
+            ],
+            [
+              123.536337,
+              43.007
+            ],
+            [
+              123.572678,
+              43.003498
+            ],
+            [
+              123.580685,
+              43.036314
+            ],
+            [
+              123.631192,
+              43.088346
+            ],
+            [
+              123.636119,
+              43.141644
+            ],
+            [
+              123.666916,
+              43.179623
+            ],
+            [
+              123.645974,
+              43.208855
+            ],
+            [
+              123.676771,
+              43.223684
+            ],
+            [
+              123.664453,
+              43.264663
+            ],
+            [
+              123.698329,
+              43.272071
+            ],
+            [
+              123.703873,
+              43.37047
+            ],
+            [
+              123.608402,
+              43.366119
+            ],
+            [
+              123.54496,
+              43.415262
+            ],
+            [
+              123.519707,
+              43.402219
+            ],
+            [
+              123.486446,
+              43.44525
+            ],
+            [
+              123.442098,
+              43.437863
+            ],
+            [
+              123.419925,
+              43.410046
+            ],
+            [
+              123.382968,
+              43.469143
+            ],
+            [
+              123.36449,
+              43.483475
+            ],
+            [
+              123.315831,
+              43.492159
+            ],
+            [
+              123.329998,
+              43.519071
+            ],
+            [
+              123.304744,
+              43.550742
+            ],
+            [
+              123.360179,
+              43.567223
+            ],
+            [
+              123.452569,
+              43.545971
+            ],
+            [
+              123.461193,
+              43.568523
+            ],
+            [
+              123.434091,
+              43.575461
+            ],
+            [
+              123.421157,
+              43.598435
+            ],
+            [
+              123.5117,
+              43.592801
+            ],
+            [
+              123.510468,
+              43.624867
+            ],
+            [
+              123.536953,
+              43.633964
+            ],
+            [
+              123.518475,
+              43.682024
+            ],
+            [
+              123.520323,
+              43.708419
+            ],
+            [
+              123.48275,
+              43.737396
+            ],
+            [
+              123.498149,
+              43.771114
+            ],
+            [
+              123.461809,
+              43.822518
+            ],
+            [
+              123.467968,
+              43.853599
+            ],
+            [
+              123.397135,
+              43.954929
+            ],
+            [
+              123.37065,
+              43.970006
+            ],
+            [
+              123.400831,
+              43.979481
+            ],
+            [
+              123.365722,
+              44.013922
+            ],
+            [
+              123.331229,
+              44.028984
+            ],
+            [
+              123.32815,
+              44.084035
+            ],
+            [
+              123.350939,
+              44.092633
+            ],
+            [
+              123.362642,
+              44.133452
+            ],
+            [
+              123.386664,
+              44.161794
+            ],
+            [
+              123.323838,
+              44.179823
+            ],
+            [
+              123.286882,
+              44.211574
+            ],
+            [
+              123.277027,
+              44.25274
+            ],
+            [
+              123.196955,
+              44.34483
+            ],
+            [
+              123.128585,
+              44.367081
+            ],
+            [
+              123.114419,
+              44.40258
+            ],
+            [
+              123.142136,
+              44.428228
+            ],
+            [
+              123.125506,
+              44.455147
+            ],
+            [
+              123.137209,
+              44.486322
+            ],
+            [
+              123.12489,
+              44.5098
+            ],
+            [
+              123.06576,
+              44.505959
+            ],
+            [
+              123.025108,
+              44.493153
+            ],
+            [
+              122.85634,
+              44.398304
+            ],
+            [
+              122.76087,
+              44.369648
+            ],
+            [
+              122.702971,
+              44.319145
+            ],
+            [
+              122.675254,
+              44.285738
+            ],
+            [
+              122.641993,
+              44.283595
+            ],
+            [
+              122.515726,
+              44.251025
+            ],
+            [
+              122.483081,
+              44.236877
+            ],
+            [
+              122.319241,
+              44.233018
+            ],
+            [
+              122.271198,
+              44.255741
+            ],
+            [
+              122.291524,
+              44.310152
+            ],
+            [
+              122.294604,
+              44.41113
+            ],
+            [
+              122.28598,
+              44.477783
+            ],
+            [
+              122.228082,
+              44.480345
+            ],
+            [
+              122.224386,
+              44.526016
+            ],
+            [
+              122.196053,
+              44.559712
+            ],
+            [
+              122.13138,
+              44.577619
+            ],
+            [
+              122.113517,
+              44.615546
+            ],
+            [
+              122.103046,
+              44.67388
+            ],
+            [
+              122.117213,
+              44.701961
+            ],
+            [
+              122.161561,
+              44.728328
+            ],
+            [
+              122.152322,
+              44.744057
+            ],
+            [
+              122.10243,
+              44.736406
+            ],
+            [
+              122.110438,
+              44.767856
+            ],
+            [
+              122.142467,
+              44.753833
+            ],
+            [
+              122.168952,
+              44.770405
+            ],
+            [
+              122.099967,
+              44.7823
+            ],
+            [
+              122.098119,
+              44.81882
+            ],
+            [
+              122.04946,
+              44.912985
+            ],
+            [
+              122.079025,
+              44.914256
+            ],
+            [
+              122.087032,
+              44.95281
+            ],
+            [
+              122.074713,
+              45.006573
+            ],
+            [
+              122.098735,
+              45.02138
+            ],
+            [
+              122.119677,
+              45.068739
+            ],
+            [
+              122.109822,
+              45.142236
+            ],
+            [
+              122.143082,
+              45.183167
+            ],
+            [
+              122.192358,
+              45.180636
+            ],
+            [
+              122.22993,
+              45.206784
+            ],
+            [
+              122.239169,
+              45.276313
+            ],
+            [
+              122.147394,
+              45.295682
+            ],
+            [
+              122.146778,
+              45.374352
+            ],
+            [
+              122.180039,
+              45.409655
+            ],
+            [
+              122.168336,
+              45.439897
+            ],
+            [
+              122.064242,
+              45.472641
+            ],
+            [
+              122.002648,
+              45.507882
+            ],
+            [
+              121.993409,
+              45.552741
+            ],
+            [
+              121.966308,
+              45.596308
+            ],
+            [
+              121.995873,
+              45.59882
+            ],
+            [
+              122.003264,
+              45.623102
+            ],
+            [
+              121.970004,
+              45.692956
+            ],
+            [
+              121.934279,
+              45.71051
+            ],
+            [
+              121.867142,
+              45.719703
+            ],
+            [
+              121.812323,
+              45.704659
+            ],
+            [
+              121.811091,
+              45.687103
+            ],
+            [
+              121.713773,
+              45.701734
+            ],
+            [
+              121.666345,
+              45.727641
+            ],
+            [
+              121.644172,
+              45.752284
+            ],
+            [
+              121.657106,
+              45.770238
+            ],
+            [
+              121.697142,
+              45.76314
+            ],
+            [
+              121.754425,
+              45.794862
+            ],
+            [
+              121.766744,
+              45.830318
+            ],
+            [
+              121.769823,
+              45.84366
+            ],
+            [
+              121.817251,
+              45.875336
+            ],
+            [
+              121.805548,
+              45.900746
+            ],
+            [
+              121.821562,
+              45.918235
+            ],
+            [
+              121.809243,
+              45.961102
+            ],
+            [
+              121.761816,
+              45.998947
+            ],
+            [
+              121.819098,
+              46.023054
+            ],
+            [
+              121.843736,
+              46.024301
+            ],
+            [
+              121.864062,
+              46.002272
+            ],
+            [
+              121.923808,
+              46.004767
+            ],
+            [
+              121.92812,
+              45.988552
+            ],
+            [
+              122.040221,
+              45.959022
+            ],
+            [
+              122.085184,
+              45.912406
+            ],
+            [
+              122.091344,
+              45.882002
+            ],
+            [
+              122.200981,
+              45.857
+            ],
+            [
+              122.236705,
+              45.831569
+            ],
+            [
+              122.253952,
+              45.7982
+            ],
+            [
+              122.301379,
+              45.813218
+            ],
+            [
+              122.337719,
+              45.859917
+            ],
+            [
+              122.372828,
+              45.856166
+            ],
+            [
+              122.362357,
+              45.917403
+            ],
+            [
+              122.446125,
+              45.916986
+            ],
+            [
+              122.496016,
+              45.85825
+            ],
+            [
+              122.504639,
+              45.786933
+            ],
+            [
+              122.522501,
+              45.786933
+            ],
+            [
+              122.556378,
+              45.82156
+            ],
+            [
+              122.603189,
+              45.778169
+            ],
+            [
+              122.640761,
+              45.771072
+            ],
+            [
+              122.650001,
+              45.731401
+            ],
+            [
+              122.671558,
+              45.70048
+            ],
+            [
+              122.741775,
+              45.705077
+            ],
+            [
+              122.751015,
+              45.735996
+            ],
+            [
+              122.792283,
+              45.766063
+            ],
+            [
+              122.752246,
+              45.834905
+            ],
+            [
+              122.772572,
+              45.856583
+            ],
+            [
+              122.80029,
+              45.856583
+            ],
+            [
+              122.828623,
+              45.912406
+            ],
+            [
+              122.792898,
+              46.073313
+            ],
+            [
+              123.04605,
+              46.099878
+            ],
+            [
+              123.070071,
+              46.123527
+            ],
+            [
+              123.112571,
+              46.130163
+            ],
+            [
+              123.102716,
+              46.172037
+            ],
+            [
+              123.127354,
+              46.174523
+            ],
+            [
+              123.128585,
+              46.210565
+            ],
+            [
+              123.178476,
+              46.248239
+            ],
+            [
+              123.142136,
+              46.298293
+            ],
+            [
+              123.089781,
+              46.347888
+            ],
+            [
+              123.011557,
+              46.434984
+            ],
+            [
+              123.010325,
+              46.524823
+            ],
+            [
+              123.002318,
+              46.574624
+            ],
+            [
+              123.052825,
+              46.579972
+            ],
+            [
+              123.04605,
+              46.617803
+            ],
+            [
+              123.077462,
+              46.622324
+            ],
+            [
+              123.098404,
+              46.603002
+            ],
+            [
+              123.18094,
+              46.614103
+            ],
+            [
+              123.228368,
+              46.588198
+            ],
+            [
+              123.279491,
+              46.616981
+            ],
+            [
+              123.276411,
+              46.660947
+            ],
+            [
+              123.318295,
+              46.662179
+            ],
+            [
+              123.366338,
+              46.677784
+            ],
+            [
+              123.474743,
+              46.686817
+            ],
+            [
+              123.603475,
+              46.68928
+            ],
+            [
+              123.631808,
+              46.728675
+            ],
+            [
+              123.629344,
+              46.813524
+            ],
+            [
+              123.580069,
+              46.827447
+            ],
+            [
+              123.625648,
+              46.847508
+            ],
+            [
+              123.599163,
+              46.868378
+            ],
+            [
+              123.605322,
+              46.891286
+            ],
+            [
+              123.576989,
+              46.891286
+            ],
+            [
+              123.575757,
+              46.845461
+            ],
+            [
+              123.562823,
+              46.82581
+            ],
+            [
+              123.506772,
+              46.827038
+            ],
+            [
+              123.483366,
+              46.84587
+            ],
+            [
+              123.52833,
+              46.944836
+            ],
+            [
+              123.487678,
+              46.959951
+            ],
+            [
+              123.42362,
+              46.934212
+            ],
+            [
+              123.337389,
+              46.988943
+            ],
+            [
+              123.301664,
+              46.999965
+            ],
+            [
+              123.304128,
+              46.964852
+            ],
+            [
+              123.360179,
+              46.970978
+            ],
+            [
+              123.404526,
+              46.935438
+            ],
+            [
+              123.40699,
+              46.906416
+            ],
+            [
+              123.374345,
+              46.837683
+            ],
+            [
+              123.341084,
+              46.826628
+            ],
+            [
+              123.295505,
+              46.865105
+            ],
+            [
+              123.221592,
+              46.850373
+            ],
+            [
+              123.22344,
+              46.821305
+            ],
+            [
+              123.198802,
+              46.803283
+            ],
+            [
+              123.163694,
+              46.74016
+            ],
+            [
+              123.103332,
+              46.734828
+            ],
+            [
+              123.076846,
+              46.745082
+            ],
+            [
+              123.026339,
+              46.718829
+            ],
+            [
+              123.00355,
+              46.730726
+            ],
+            [
+              122.996774,
+              46.761483
+            ],
+            [
+              122.906847,
+              46.80738
+            ],
+            [
+              122.893913,
+              46.895376
+            ],
+            [
+              122.895144,
+              46.960359
+            ],
+            [
+              122.83971,
+              46.937072
+            ],
+            [
+              122.791051,
+              46.941567
+            ],
+            [
+              122.798442,
+              46.9575
+            ],
+            [
+              122.77442,
+              46.973837
+            ],
+            [
+              122.778116,
+              47.002822
+            ],
+            [
+              122.845869,
+              47.046881
+            ],
+            [
+              122.852645,
+              47.072158
+            ],
+            [
+              122.821232,
+              47.065636
+            ],
+            [
+              122.710363,
+              47.093349
+            ],
+            [
+              122.679566,
+              47.094164
+            ],
+            [
+              122.615508,
+              47.124306
+            ],
+            [
+              122.582863,
+              47.158092
+            ],
+            [
+              122.531124,
+              47.198771
+            ],
+            [
+              122.498479,
+              47.255262
+            ],
+            [
+              122.462755,
+              47.27841
+            ],
+            [
+              122.441197,
+              47.310476
+            ],
+            [
+              122.418407,
+              47.350632
+            ],
+            [
+              122.507103,
+              47.401291
+            ],
+            [
+              122.543443,
+              47.495589
+            ],
+            [
+              122.59395,
+              47.54732
+            ],
+            [
+              122.765181,
+              47.614333
+            ],
+            [
+              122.848949,
+              47.67441
+            ],
+            [
+              122.926557,
+              47.697777
+            ],
+            [
+              123.041122,
+              47.746492
+            ],
+            [
+              123.161846,
+              47.781892
+            ],
+            [
+              123.214201,
+              47.824502
+            ],
+            [
+              123.256085,
+              47.876711
+            ],
+            [
+              123.300432,
+              47.953723
+            ],
+            [
+              123.537569,
+              48.021816
+            ],
+            [
+              123.579453,
+              48.045427
+            ],
+            [
+              123.705105,
+              48.152142
+            ],
+            [
+              123.746373,
+              48.197638
+            ],
+            [
+              123.862785,
+              48.271782
+            ],
+            [
+              124.019234,
+              48.39313
+            ],
+            [
+              124.07898,
+              48.43603
+            ],
+            [
+              124.136878,
+              48.463023
+            ],
+            [
+              124.25945,
+              48.536385
+            ],
+            [
+              124.314269,
+              48.503881
+            ],
+            [
+              124.302566,
+              48.456673
+            ],
+            [
+              124.330283,
+              48.435633
+            ],
+            [
+              124.309957,
+              48.413393
+            ],
+            [
+              124.331515,
+              48.380015
+            ],
+            [
+              124.317964,
+              48.35099
+            ],
+            [
+              124.353689,
+              48.315978
+            ],
+            [
+              124.365392,
+              48.283731
+            ],
+            [
+              124.422058,
+              48.245884
+            ],
+            [
+              124.412819,
+              48.219175
+            ],
+            [
+              124.418978,
+              48.181679
+            ],
+            [
+              124.475029,
+              48.173698
+            ],
+            [
+              124.471333,
+              48.133373
+            ],
+            [
+              124.430065,
+              48.12099
+            ],
+            [
+              124.415899,
+              48.08782
+            ],
+            [
+              124.46579,
+              48.098213
+            ],
+            [
+              124.478108,
+              48.123387
+            ],
+            [
+              124.505826,
+              48.124985
+            ],
+            [
+              124.529847,
+              48.146951
+            ],
+            [
+              124.512601,
+              48.164518
+            ],
+            [
+              124.547094,
+              48.200829
+            ],
+            [
+              124.579122,
+              48.262221
+            ],
+            [
+              124.558796,
+              48.268197
+            ],
+            [
+              124.579738,
+              48.297269
+            ],
+            [
+              124.540934,
+              48.335476
+            ],
+            [
+              124.547094,
+              48.35775
+            ],
+            [
+              124.51876,
+              48.378027
+            ],
+            [
+              124.52492,
+              48.426897
+            ],
+            [
+              124.507674,
+              48.445558
+            ],
+            [
+              124.555717,
+              48.467784
+            ],
+            [
+              124.533543,
+              48.515379
+            ],
+            [
+              124.548941,
+              48.535593
+            ],
+            [
+              124.520608,
+              48.556195
+            ],
+            [
+              124.579122,
+              48.596582
+            ],
+            [
+              124.601912,
+              48.632587
+            ],
+            [
+              124.624702,
+              48.701755
+            ],
+            [
+              124.612383,
+              48.747945
+            ],
+            [
+              124.656115,
+              48.783842
+            ],
+            [
+              124.644412,
+              48.80789
+            ],
+            [
+              124.654267,
+              48.83429
+            ],
+            [
+              124.697383,
+              48.841775
+            ],
+            [
+              124.715861,
+              48.885475
+            ],
+            [
+              124.709086,
+              48.920487
+            ],
+            [
+              124.744194,
+              48.920487
+            ],
+            [
+              124.756513,
+              48.967262
+            ],
+            [
+              124.808252,
+              49.020666
+            ],
+            [
+              124.828578,
+              49.077933
+            ],
+            [
+              124.809484,
+              49.115943
+            ],
+            [
+              124.847672,
+              49.129651
+            ],
+            [
+              124.860607,
+              49.166448
+            ],
+            [
+              124.906802,
+              49.184054
+            ],
+            [
+              124.983179,
+              49.162535
+            ],
+            [
+              125.039845,
+              49.17623
+            ],
+            [
+              125.034302,
+              49.157056
+            ],
+            [
+              125.117453,
+              49.126127
+            ],
+            [
+              125.158721,
+              49.144921
+            ],
+            [
+              125.187671,
+              49.186792
+            ],
+            [
+              125.219699,
+              49.189139
+            ],
+            [
+              125.227707,
+              49.248947
+            ],
+            [
+              125.214772,
+              49.277066
+            ],
+            [
+              125.261583,
+              49.322336
+            ],
+            [
+              125.256656,
+              49.359769
+            ],
+            [
+              125.277598,
+              49.379644
+            ],
+            [
+              125.25604,
+              49.395227
+            ],
+            [
+              125.256656,
+              49.437275
+            ],
+            [
+              125.270822,
+              49.454395
+            ],
+            [
+              125.228323,
+              49.487063
+            ],
+            [
+              125.211076,
+              49.539908
+            ],
+            [
+              125.233866,
+              49.536801
+            ],
+            [
+              125.23017,
+              49.595411
+            ],
+            [
+              125.205533,
+              49.593859
+            ],
+            [
+              125.16796,
+              49.629923
+            ],
+            [
+              125.15441,
+              49.616741
+            ],
+            [
+              125.127308,
+              49.655113
+            ],
+            [
+              125.132236,
+              49.672157
+            ],
+            [
+              125.164881,
+              49.669446
+            ],
+            [
+              125.189518,
+              49.652401
+            ],
+            [
+              125.185207,
+              49.634574
+            ],
+            [
+              125.219699,
+              49.669058
+            ],
+            [
+              125.225243,
+              49.726349
+            ],
+            [
+              125.204301,
+              49.734086
+            ],
+            [
+              125.221547,
+              49.754969
+            ],
+            [
+              125.222779,
+              49.799026
+            ],
+            [
+              125.177815,
+              49.829533
+            ],
+            [
+              125.239409,
+              49.844587
+            ],
+            [
+              125.225243,
+              49.867351
+            ],
+            [
+              125.245569,
+              49.87198
+            ],
+            [
+              125.212924,
+              49.907452
+            ],
+            [
+              125.225859,
+              49.922481
+            ],
+            [
+              125.199373,
+              49.935194
+            ],
+            [
+              125.190134,
+              49.959841
+            ],
+            [
+              125.231402,
+              49.957531
+            ],
+            [
+              125.241873,
+              49.987938
+            ],
+            [
+              125.278214,
+              49.996402
+            ],
+            [
+              125.297924,
+              50.014481
+            ],
+            [
+              125.283757,
+              50.036012
+            ],
+            [
+              125.25296,
+              50.041393
+            ],
+            [
+              125.289916,
+              50.057917
+            ],
+            [
+              125.315786,
+              50.04562
+            ],
+            [
+              125.328105,
+              50.065985
+            ],
+            [
+              125.283757,
+              50.070211
+            ],
+            [
+              125.287453,
+              50.093636
+            ],
+            [
+              125.258504,
+              50.103618
+            ],
+            [
+              125.27883,
+              50.127411
+            ],
+            [
+              125.311474,
+              50.140453
+            ],
+            [
+              125.376148,
+              50.137385
+            ],
+            [
+              125.335496,
+              50.161161
+            ],
+            [
+              125.382923,
+              50.172278
+            ],
+            [
+              125.39093,
+              50.199868
+            ],
+            [
+              125.417416,
+              50.195654
+            ],
+            [
+              125.448829,
+              50.216338
+            ],
+            [
+              125.442053,
+              50.260357
+            ],
+            [
+              125.466075,
+              50.266861
+            ],
+            [
+              125.463611,
+              50.295925
+            ],
+            [
+              125.530749,
+              50.331085
+            ],
+            [
+              125.520278,
+              50.3498
+            ],
+            [
+              125.546763,
+              50.358965
+            ],
+            [
+              125.522126,
+              50.404759
+            ],
+            [
+              125.536292,
+              50.420014
+            ],
+            [
+              125.567089,
+              50.402852
+            ],
+            [
+              125.583104,
+              50.409717
+            ],
+            [
+              125.562162,
+              50.438314
+            ],
+            [
+              125.580024,
+              50.449366
+            ],
+            [
+              125.627451,
+              50.443268
+            ],
+            [
+              125.654553,
+              50.471082
+            ],
+            [
+              125.699516,
+              50.487078
+            ],
+            [
+              125.740784,
+              50.523237
+            ],
+            [
+              125.754335,
+              50.506874
+            ],
+            [
+              125.770349,
+              50.531227
+            ],
+            [
+              125.794987,
+              50.532748
+            ],
+            [
+              125.829479,
+              50.56165
+            ],
+            [
+              125.807921,
+              50.60383
+            ],
+            [
+              125.814697,
+              50.62092
+            ],
+            [
+              125.793139,
+              50.643316
+            ],
+            [
+              125.804226,
+              50.658874
+            ],
+            [
+              125.789443,
+              50.679735
+            ],
+            [
+              125.825784,
+              50.70362
+            ],
+            [
+              125.78082,
+              50.725598
+            ],
+            [
+              125.795603,
+              50.738856
+            ],
+            [
+              125.758646,
+              50.746809
+            ],
+            [
+              125.804226,
+              50.773309
+            ],
+            [
+              125.828863,
+              50.756654
+            ],
+            [
+              125.846726,
+              50.769524
+            ],
+            [
+              125.836255,
+              50.793363
+            ],
+            [
+              125.890457,
+              50.805845
+            ],
+            [
+              125.878138,
+              50.816812
+            ],
+            [
+              125.913247,
+              50.825885
+            ],
+            [
+              125.939732,
+              50.85423
+            ],
+            [
+              125.961906,
+              50.901054
+            ],
+            [
+              125.997631,
+              50.872738
+            ],
+            [
+              125.996399,
+              50.906715
+            ],
+            [
+              126.02042,
+              50.927466
+            ],
+            [
+              126.042594,
+              50.92558
+            ],
+            [
+              126.068464,
+              50.967434
+            ],
+            [
+              126.041978,
+              50.981753
+            ],
+            [
+              126.033971,
+              51.011132
+            ],
+            [
+              126.059225,
+              51.043503
+            ],
+            [
+              125.976073,
+              51.084498
+            ],
+            [
+              125.993935,
+              51.119072
+            ],
+            [
+              125.970529,
+              51.123955
+            ],
+            [
+              125.946508,
+              51.108176
+            ],
+            [
+              125.909551,
+              51.138977
+            ],
+            [
+              125.864588,
+              51.146487
+            ],
+            [
+              125.850421,
+              51.21364
+            ],
+            [
+              125.819008,
+              51.227134
+            ],
+            [
+              125.761726,
+              51.226385
+            ],
+            [
+              125.76111,
+              51.261976
+            ],
+            [
+              125.740784,
+              51.27583
+            ],
+            [
+              125.700132,
+              51.327465
+            ],
+            [
+              125.626219,
+              51.380163
+            ],
+            [
+              125.623756,
+              51.387633
+            ],
+            [
+              125.62314,
+              51.398089
+            ],
+            [
+              125.600966,
+              51.410409
+            ],
+            [
+              125.60035,
+              51.413396
+            ],
+            [
+              125.595422,
+              51.416755
+            ],
+            [
+              125.559082,
+              51.461521
+            ],
+            [
+              125.528285,
+              51.488359
+            ],
+            [
+              125.424807,
+              51.562827
+            ],
+            [
+              125.38046,
+              51.585516
+            ],
+            [
+              125.35151,
+              51.623801
+            ],
+            [
+              125.316402,
+              51.610052
+            ],
+            [
+              125.289301,
+              51.633831
+            ],
+            [
+              125.228938,
+              51.640517
+            ],
+            [
+              125.214772,
+              51.627888
+            ],
+            [
+              125.175968,
+              51.639403
+            ],
+            [
+              125.130388,
+              51.635317
+            ],
+            [
+              125.12854,
+              51.659083
+            ],
+            [
+              125.098975,
+              51.658341
+            ],
+            [
+              125.060171,
+              51.59667
+            ],
+            [
+              125.073106,
+              51.553526
+            ],
+            [
+              125.047236,
+              51.529704
+            ],
+            [
+              125.004737,
+              51.529332
+            ],
+            [
+              124.983795,
+              51.508478
+            ],
+            [
+              124.928976,
+              51.498419
+            ],
+            [
+              124.917889,
+              51.474196
+            ],
+            [
+              124.942527,
+              51.447349
+            ],
+            [
+              124.885244,
+              51.40817
+            ],
+            [
+              124.864302,
+              51.37979
+            ],
+            [
+              124.783614,
+              51.392115
+            ],
+            [
+              124.76452,
+              51.38726
+            ],
+            [
+              124.752817,
+              51.35812
+            ],
+            [
+              124.693687,
+              51.3327
+            ],
+            [
+              124.62655,
+              51.327465
+            ],
+            [
+              124.58713,
+              51.363725
+            ],
+            [
+              124.555717,
+              51.375307
+            ],
+            [
+              124.490427,
+              51.380537
+            ],
+            [
+              124.478108,
+              51.36223
+            ],
+            [
+              124.443616,
+              51.35812
+            ],
+            [
+              124.426985,
+              51.331953
+            ],
+            [
+              124.430065,
+              51.301281
+            ],
+            [
+              124.406659,
+              51.272086
+            ],
+            [
+              124.339522,
+              51.293422
+            ],
+            [
+              124.297638,
+              51.298661
+            ],
+            [
+              124.271769,
+              51.308389
+            ],
+            [
+              124.239124,
+              51.344664
+            ],
+            [
+              124.192313,
+              51.33943
+            ],
+            [
+              124.128255,
+              51.347281
+            ],
+            [
+              124.090067,
+              51.3413
+            ],
+            [
+              124.071588,
+              51.320734
+            ],
+            [
+              123.994596,
+              51.322604
+            ],
+            [
+              123.939777,
+              51.313253
+            ],
+            [
+              123.926227,
+              51.300532
+            ],
+            [
+              123.887423,
+              51.320734
+            ],
+            [
+              123.842459,
+              51.367462
+            ],
+            [
+              123.794416,
+              51.361109
+            ],
+            [
+              123.711264,
+              51.398089
+            ],
+            [
+              123.660141,
+              51.342795
+            ],
+            [
+              123.661989,
+              51.319237
+            ],
+            [
+              123.582533,
+              51.306893
+            ],
+            [
+              123.582533,
+              51.294545
+            ],
+            [
+              123.46304,
+              51.286686
+            ],
+            [
+              123.440251,
+              51.270963
+            ],
+            [
+              123.414381,
+              51.278825
+            ],
+            [
+              123.376809,
+              51.266844
+            ],
+            [
+              123.339853,
+              51.27246
+            ],
+            [
+              123.294273,
+              51.254111
+            ],
+            [
+              123.231447,
+              51.268716
+            ],
+            [
+              123.231447,
+              51.279199
+            ],
+            [
+              123.127969,
+              51.297913
+            ],
+            [
+              123.069455,
+              51.321108
+            ],
+            [
+              123.002934,
+              51.31213
+            ],
+            [
+              122.965977,
+              51.345786
+            ],
+            [
+              122.965977,
+              51.386886
+            ],
+            [
+              122.946267,
+              51.405183
+            ],
+            [
+              122.903768,
+              51.415262
+            ],
+            [
+              122.900072,
+              51.445112
+            ],
+            [
+              122.871123,
+              51.455181
+            ],
+            [
+              122.854492,
+              51.477551
+            ],
+            [
+              122.880362,
+              51.511085
+            ],
+            [
+              122.858804,
+              51.524864
+            ],
+            [
+              122.880362,
+              51.537894
+            ],
+            [
+              122.874202,
+              51.561339
+            ],
+            [
+              122.832935,
+              51.581797
+            ],
+            [
+              122.85634,
+              51.606707
+            ],
+            [
+              122.820616,
+              51.633088
+            ],
+            [
+              122.816304,
+              51.655371
+            ],
+            [
+              122.778732,
+              51.698048
+            ],
+            [
+              122.749167,
+              51.746613
+            ],
+            [
+              122.771957,
+              51.779579
+            ],
+            [
+              122.732536,
+              51.832495
+            ],
+            [
+              122.725761,
+              51.87833
+            ],
+            [
+              122.706051,
+              51.890151
+            ],
+            [
+              122.729457,
+              51.919321
+            ],
+            [
+              122.726377,
+              51.978709
+            ],
+            [
+              122.683877,
+              51.974654
+            ],
+            [
+              122.664783,
+              51.99861
+            ],
+            [
+              122.650616,
+              52.058997
+            ],
+            [
+              122.625363,
+              52.067459
+            ],
+            [
+              122.643841,
+              52.111585
+            ],
+            [
+              122.629059,
+              52.13657
+            ],
+            [
+              122.690653,
+              52.140243
+            ],
+            [
+              122.73808,
+              52.153464
+            ],
+            [
+              122.769493,
+              52.179893
+            ],
+            [
+              122.766413,
+              52.232705
+            ],
+            [
+              122.787355,
+              52.252494
+            ],
+            [
+              122.76087,
+              52.26678
+            ],
+            [
+              122.710979,
+              52.256157
+            ],
+            [
+              122.67895,
+              52.276667
+            ],
+            [
+              122.585943,
+              52.266413
+            ],
+            [
+              122.560689,
+              52.282526
+            ],
+            [
+              122.478153,
+              52.29607
+            ],
+            [
+              122.484313,
+              52.341432
+            ],
+            [
+              122.447356,
+              52.394052
+            ],
+            [
+              122.419023,
+              52.375057
+            ],
+            [
+              122.378987,
+              52.395512
+            ],
+            [
+              122.367284,
+              52.413768
+            ],
+            [
+              122.342031,
+              52.414133
+            ],
+            [
+              122.326016,
+              52.459374
+            ],
+            [
+              122.310618,
+              52.475416
+            ],
+            [
+              122.207756,
+              52.469218
+            ],
+            [
+              122.178191,
+              52.48963
+            ],
+            [
+              122.168952,
+              52.513674
+            ],
+            [
+              122.140003,
+              52.510032
+            ],
+            [
+              122.142467,
+              52.495096
+            ],
+            [
+              122.107358,
+              52.452445
+            ],
+            [
+              122.080873,
+              52.440407
+            ],
+            [
+              122.091344,
+              52.427272
+            ],
+            [
+              122.040837,
+              52.413038
+            ],
+            [
+              122.035909,
+              52.377615
+            ],
+            [
+              121.976779,
+              52.343626
+            ],
+            [
+              121.94783,
+              52.298266
+            ],
+            [
+              121.901018,
+              52.280695
+            ],
+            [
+              121.841272,
+              52.282526
+            ],
+            [
+              121.769207,
+              52.308147
+            ],
+            [
+              121.714389,
+              52.318025
+            ],
+            [
+              121.715621,
+              52.342894
+            ],
+            [
+              121.658338,
+              52.3904
+            ],
+            [
+              121.678664,
+              52.419973
+            ],
+            [
+              121.63986,
+              52.44442
+            ],
+            [
+              121.590585,
+              52.443326
+            ],
+            [
+              121.565331,
+              52.460468
+            ],
+            [
+              121.519136,
+              52.456821
+            ],
+            [
+              121.495114,
+              52.484892
+            ],
+            [
+              121.474172,
+              52.482706
+            ],
+            [
+              121.416274,
+              52.499468
+            ],
+            [
+              121.411963,
+              52.52205
+            ],
+            [
+              121.353448,
+              52.534793
+            ],
+            [
+              121.323883,
+              52.573727
+            ],
+            [
+              121.280151,
+              52.586819
+            ],
+            [
+              121.225333,
+              52.577364
+            ],
+            [
+              121.182217,
+              52.59918
+            ],
+            [
+              121.237036,
+              52.619167
+            ],
+            [
+              121.29247,
+              52.651855
+            ],
+            [
+              121.309717,
+              52.676173
+            ],
+            [
+              121.373158,
+              52.683067
+            ],
+            [
+              121.455078,
+              52.73528
+            ],
+            [
+              121.476636,
+              52.772225
+            ],
+            [
+              121.511129,
+              52.779104
+            ],
+            [
+              121.537614,
+              52.801542
+            ],
+            [
+              121.591201,
+              52.824693
+            ],
+            [
+              121.620766,
+              52.853251
+            ],
+            [
+              121.604136,
+              52.872401
+            ],
+            [
+              121.610295,
+              52.892264
+            ],
+            [
+              121.66265,
+              52.912478
+            ],
+            [
+              121.677432,
+              52.948192
+            ],
+            [
+              121.715621,
+              52.997926
+            ],
+            [
+              121.785838,
+              53.018451
+            ],
+            [
+              121.817867,
+              53.061631
+            ],
+            [
+              121.775367,
+              53.089674
+            ],
+            [
+              121.784606,
+              53.104408
+            ],
+            [
+              121.753193,
+              53.147501
+            ],
+            [
+              121.722396,
+              53.145706
+            ],
+            [
+              121.665114,
+              53.170467
+            ],
+            [
+              121.660186,
+              53.195213
+            ],
+            [
+              121.67928,
+              53.199515
+            ],
+            [
+              121.679896,
+              53.240722
+            ],
+            [
+              121.642324,
+              53.262564
+            ],
+            [
+              121.615222,
+              53.258984
+            ],
+            [
+              121.575802,
+              53.29155
+            ],
+            [
+              121.504969,
+              53.323018
+            ],
+            [
+              121.499426,
+              53.337314
+            ],
+            [
+              121.416274,
+              53.319443
+            ],
+            [
+              121.336818,
+              53.325877
+            ],
+            [
+              121.308485,
+              53.301565
+            ],
+            [
+              121.227797,
+              53.280459
+            ],
+            [
+              121.155732,
+              53.285468
+            ],
+            [
+              121.129246,
+              53.277238
+            ],
+            [
+              121.098449,
+              53.306929
+            ],
+            [
+              121.055334,
+              53.29155
+            ],
+            [
+              120.950624,
+              53.29763
+            ],
+            [
+              120.936457,
+              53.28833
+            ],
+            [
+              120.882871,
+              53.294411
+            ],
+            [
+              120.867472,
+              53.278669
+            ],
+            [
+              120.820661,
+              53.269007
+            ],
+            [
+              120.838523,
+              53.239648
+            ],
+            [
+              120.821893,
+              53.241797
+            ],
+            [
+              120.736277,
+              53.204892
+            ],
+            [
+              120.690698,
+              53.174771
+            ],
+            [
+              120.687002,
+              53.142476
+            ],
+            [
+              120.659901,
+              53.137091
+            ],
+            [
+              120.643886,
+              53.106923
+            ],
+            [
+              120.562582,
+              53.082845
+            ],
+            [
+              120.529321,
+              53.045803
+            ],
+            [
+              120.452945,
+              53.01017
+            ],
+            [
+              120.411061,
+              52.957927
+            ],
+            [
+              120.363018,
+              52.94134
+            ],
+            [
+              120.350699,
+              52.906343
+            ],
+            [
+              120.295265,
+              52.891542
+            ],
+            [
+              120.297112,
+              52.869872
+            ],
+            [
+              120.222584,
+              52.84277
+            ],
+            [
+              120.181316,
+              52.806969
+            ],
+            [
+              120.14128,
+              52.813119
+            ],
+            [
+              120.101244,
+              52.788877
+            ],
+            [
+              120.031642,
+              52.773674
+            ],
+            [
+              120.071063,
+              52.70628
+            ],
+            [
+              120.035338,
+              52.646409
+            ],
+            [
+              120.049505,
+              52.598453
+            ],
+            [
+              120.07599,
+              52.586092
+            ],
+            [
+              120.125265,
+              52.586819
+            ],
+            [
+              120.194866,
+              52.578819
+            ],
+            [
+              120.289721,
+              52.623527
+            ],
+            [
+              120.396895,
+              52.616261
+            ],
+            [
+              120.462184,
+              52.64532
+            ],
+            [
+              120.483742,
+              52.630066
+            ],
+            [
+              120.56135,
+              52.595544
+            ],
+            [
+              120.605082,
+              52.589364
+            ],
+            [
+              120.62664,
+              52.570818
+            ],
+            [
+              120.658669,
+              52.56718
+            ],
+            [
+              120.690698,
+              52.547532
+            ],
+            [
+              120.734429,
+              52.536977
+            ],
+            [
+              120.687002,
+              52.511489
+            ],
+            [
+              120.706712,
+              52.492909
+            ],
+            [
+              120.68269,
+              52.464479
+            ],
+            [
+              120.688234,
+              52.427637
+            ],
+            [
+              120.64943,
+              52.3904
+            ],
+            [
+              120.653741,
+              52.371038
+            ],
+            [
+              120.62356,
+              52.361172
+            ],
+            [
+              120.627256,
+              52.323878
+            ],
+            [
+              120.653741,
+              52.302658
+            ],
+            [
+              120.695625,
+              52.290214
+            ],
+            [
+              120.715951,
+              52.261286
+            ],
+            [
+              120.755371,
+              52.258355
+            ],
+            [
+              120.745516,
+              52.20594
+            ],
+            [
+              120.786784,
+              52.15787
+            ],
+            [
+              120.760299,
+              52.136937
+            ],
+            [
+              120.76769,
+              52.10938
+            ],
+            [
+              120.753523,
+              52.085483
+            ],
+            [
+              120.717183,
+              52.072978
+            ],
+            [
+              120.690698,
+              52.047221
+            ],
+            [
+              120.691929,
+              52.026973
+            ],
+            [
+              120.717799,
+              52.015556
+            ],
+            [
+              120.704864,
+              51.983501
+            ],
+            [
+              120.66298,
+              51.958061
+            ],
+            [
+              120.656821,
+              51.926333
+            ],
+            [
+              120.548416,
+              51.907877
+            ],
+            [
+              120.549032,
+              51.882394
+            ],
+            [
+              120.481278,
+              51.885719
+            ],
+            [
+              120.480046,
+              51.855049
+            ],
+            [
+              120.40059,
+              51.833605
+            ],
+            [
+              120.40675,
+              51.81659
+            ],
+            [
+              120.363634,
+              51.789945
+            ],
+            [
+              120.317438,
+              51.785873
+            ],
+            [
+              120.294649,
+              51.752171
+            ],
+            [
+              120.226279,
+              51.717703
+            ],
+            [
+              120.172693,
+              51.679868
+            ],
+            [
+              120.087077,
+              51.678013
+            ],
+            [
+              120.100628,
+              51.649058
+            ],
+            [
+              120.05936,
+              51.634203
+            ],
+            [
+              120.035954,
+              51.583657
+            ],
+            [
+              120.052584,
+              51.560967
+            ],
+            [
+              120.017476,
+              51.52114
+            ],
+            [
+              119.985447,
+              51.505125
+            ],
+            [
+              119.982367,
+              51.482396
+            ],
+            [
+              120.002693,
+              51.459283
+            ],
+            [
+              119.982983,
+              51.445112
+            ],
+            [
+              119.97128,
+              51.40033
+            ],
+            [
+              119.910918,
+              51.390994
+            ],
+            [
+              119.914614,
+              51.374187
+            ],
+            [
+              119.946643,
+              51.360736
+            ],
+            [
+              119.883817,
+              51.336813
+            ],
+            [
+              119.885049,
+              51.302777
+            ],
+            [
+              119.811136,
+              51.281071
+            ],
+            [
+              119.828383,
+              51.263099
+            ],
+            [
+              119.797586,
+              51.243622
+            ],
+            [
+              119.821607,
+              51.21439
+            ],
+            [
+              119.784035,
+              51.22601
+            ],
+            [
+              119.760629,
+              51.212516
+            ],
+            [
+              119.788346,
+              51.174636
+            ],
+            [
+              119.771716,
+              51.124331
+            ],
+            [
+              119.752622,
+              51.117193
+            ],
+            [
+              119.764325,
+              51.092017
+            ],
+            [
+              119.719361,
+              51.075099
+            ],
+            [
+              119.726753,
+              51.051028
+            ],
+            [
+              119.678093,
+              51.016404
+            ],
+            [
+              119.630666,
+              51.00925
+            ],
+            [
+              119.598637,
+              50.984767
+            ],
+            [
+              119.569688,
+              50.933879
+            ],
+            [
+              119.491464,
+              50.87878
+            ],
+            [
+              119.498855,
+              50.827776
+            ],
+            [
+              119.515485,
+              50.814165
+            ],
+            [
+              119.496391,
+              50.771795
+            ],
+            [
+              119.506862,
+              50.763846
+            ],
+            [
+              119.450196,
+              50.695281
+            ],
+            [
+              119.430486,
+              50.684286
+            ],
+            [
+              119.385522,
+              50.682769
+            ],
+            [
+              119.394145,
+              50.667219
+            ],
+            [
+              119.361501,
+              50.632689
+            ],
+            [
+              119.298059,
+              50.616743
+            ],
+            [
+              119.281428,
+              50.601551
+            ],
+            [
+              119.295595,
+              50.573814
+            ],
+            [
+              119.264182,
+              50.536933
+            ],
+            [
+              119.262334,
+              50.490124
+            ],
+            [
+              119.250631,
+              50.448604
+            ],
+            [
+              119.22353,
+              50.441363
+            ],
+            [
+              119.217371,
+              50.414675
+            ],
+            [
+              119.165016,
+              50.422683
+            ],
+            [
+              119.125596,
+              50.389118
+            ],
+            [
+              119.176719,
+              50.378814
+            ],
+            [
+              119.155777,
+              50.364691
+            ],
+            [
+              119.188422,
+              50.347509
+            ],
+            [
+              119.232153,
+              50.365455
+            ],
+            [
+              119.259871,
+              50.345218
+            ],
+            [
+              119.277117,
+              50.366218
+            ],
+            [
+              119.322696,
+              50.352474
+            ],
+            [
+              119.358421,
+              50.358965
+            ],
+            [
+              119.381827,
+              50.324208
+            ],
+            [
+              119.35103,
+              50.303953
+            ],
+            [
+              119.339943,
+              50.244668
+            ],
+            [
+              119.319001,
+              50.220933
+            ],
+            [
+              119.358421,
+              50.197953
+            ],
+            [
+              119.339327,
+              50.192206
+            ],
+            [
+              119.350414,
+              50.166145
+            ],
+            [
+              119.309762,
+              50.161161
+            ],
+            [
+              119.290052,
+              50.121655
+            ],
+            [
+              119.236465,
+              50.075204
+            ],
+            [
+              119.190269,
+              50.087877
+            ],
+            [
+              119.193965,
+              50.069826
+            ],
+            [
+              119.163168,
+              50.027554
+            ],
+            [
+              119.12498,
+              50.019095
+            ],
+            [
+              119.090487,
+              49.985629
+            ],
+            [
+              118.982082,
+              49.979087
+            ],
+            [
+              118.964836,
+              49.988708
+            ],
+            [
+              118.791757,
+              49.955606
+            ],
+            [
+              118.761576,
+              49.959456
+            ],
+            [
+              118.739402,
+              49.946364
+            ],
+            [
+              118.672264,
+              49.955991
+            ],
+            [
+              118.605127,
+              49.926719
+            ],
+            [
+              118.574946,
+              49.931342
+            ],
+            [
+              118.531214,
+              49.887791
+            ],
+            [
+              118.485019,
+              49.866194
+            ],
+            [
+              118.483787,
+              49.830691
+            ],
+            [
+              118.443751,
+              49.835709
+            ],
+            [
+              118.385853,
+              49.827217
+            ],
+            [
+              118.398787,
+              49.802502
+            ],
+            [
+              118.384005,
+              49.783958
+            ],
+            [
+              118.315636,
+              49.766953
+            ],
+            [
+              118.284223,
+              49.743755
+            ],
+            [
+              118.220781,
+              49.729831
+            ],
+            [
+              118.211542,
+              49.690744
+            ],
+            [
+              118.156723,
+              49.660149
+            ],
+            [
+              118.129622,
+              49.669446
+            ],
+            [
+              118.082811,
+              49.616741
+            ],
+            [
+              118.011362,
+              49.614803
+            ],
+            [
+              117.995963,
+              49.623332
+            ],
+            [
+              117.950999,
+              49.596187
+            ],
+            [
+              117.866,
+              49.591532
+            ],
+            [
+              117.849369,
+              49.551557
+            ],
+            [
+              117.809333,
+              49.521263
+            ],
+            [
+              117.638102,
+              49.574847
+            ],
+            [
+              117.485349,
+              49.633024
+            ],
+            [
+              117.278394,
+              49.636512
+            ],
+            [
+              117.068974,
+              49.695389
+            ],
+            [
+              116.736367,
+              49.847674
+            ],
+            [
+              116.717889,
+              49.847288
+            ],
+            [
+              116.428397,
+              49.430659
+            ],
+            [
+              116.048363,
+              48.873274
+            ],
+            [
+              116.077928,
+              48.822471
+            ],
+            [
+              116.069305,
+              48.811437
+            ],
+            [
+              115.83032,
+              48.560156
+            ],
+            [
+              115.799523,
+              48.514982
+            ],
+            [
+              115.822929,
+              48.259432
+            ],
+            [
+              115.81061,
+              48.257042
+            ],
+            [
+              115.529126,
+              48.155336
+            ],
+            [
+              115.545141,
+              48.134971
+            ],
+            [
+              115.539597,
+              48.104607
+            ],
+            [
+              115.580249,
+              47.921649
+            ],
+            [
+              115.939342,
+              47.683275
+            ],
+            [
+              115.968291,
+              47.689721
+            ],
+            [
+              116.111189,
+              47.811642
+            ],
+            [
+              116.130283,
+              47.823296
+            ],
+            [
+              116.26579,
+              47.876711
+            ],
+            [
+              116.453035,
+              47.837358
+            ],
+            [
+              116.669846,
+              47.890758
+            ],
+            [
+              116.791186,
+              47.89758
+            ],
+            [
+              116.879265,
+              47.893968
+            ],
+            [
+              117.094844,
+              47.8241
+            ],
+            [
+              117.384335,
+              47.641356
+            ],
+            [
+              117.493357,
+              47.758563
+            ],
+            [
+              117.519226,
+              47.761782
+            ],
+            [
+              117.529081,
+              47.782697
+            ],
+            [
+              117.813645,
+              48.016212
+            ],
+            [
+              117.886942,
+              48.025418
+            ],
+            [
+              117.96147,
+              48.011007
+            ],
+            [
+              118.052014,
+              48.01421
+            ],
+            [
+              118.107448,
+              48.031021
+            ],
+            [
+              118.124694,
+              48.047427
+            ],
+            [
+              118.150564,
+              48.036224
+            ],
+            [
+              118.238643,
+              48.041826
+            ],
+            [
+              118.238027,
+              48.031422
+            ],
+            [
+              118.284839,
+              48.011007
+            ],
+            [
+              118.351976,
+              48.006203
+            ],
+            [
+              118.37415,
+              48.016612
+            ],
+            [
+              118.422193,
+              48.01461
+            ],
+            [
+              118.441903,
+              47.995791
+            ],
+            [
+              118.568171,
+              47.992187
+            ],
+            [
+              118.773278,
+              47.771034
+            ],
+            [
+              119.134219,
+              47.664335
+            ],
+            [
+              119.152081,
+              47.540453
+            ],
+            [
+              119.205052,
+              47.520249
+            ],
+            [
+              119.365812,
+              47.47739
+            ],
+            [
+              119.32208,
+              47.42721
+            ],
+            [
+              119.365812,
+              47.423161
+            ],
+            [
+              119.386138,
+              47.397645
+            ],
+            [
+              119.437877,
+              47.378602
+            ],
+            [
+              119.450812,
+              47.353065
+            ],
+            [
+              119.559217,
+              47.303172
+            ],
+            [
+              119.56784,
+              47.248357
+            ],
+            [
+              119.627586,
+              47.247544
+            ],
+            [
+              119.716282,
+              47.195518
+            ],
+            [
+              119.763093,
+              47.13082
+            ],
+            [
+              119.806825,
+              47.055037
+            ],
+            [
+              119.79081,
+              47.04525
+            ],
+            [
+              119.795122,
+              47.013024
+            ],
+            [
+              119.845013,
+              46.964852
+            ],
+            [
+              119.859795,
+              46.917046
+            ],
+            [
+              119.926933,
+              46.903963
+            ],
+            [
+              119.920157,
+              46.853238
+            ],
+            [
+              119.936172,
+              46.790173
+            ],
+            [
+              119.917078,
+              46.758203
+            ],
+            [
+              119.93494,
+              46.712674
+            ],
+            [
+              119.911534,
+              46.669572
+            ],
+            [
+              119.859179,
+              46.669572
+            ],
+            [
+              119.804361,
+              46.68189
+            ],
+            [
+              119.8136,
+              46.66834
+            ],
+            [
+              119.783419,
+              46.626023
+            ],
+            [
+              119.739687,
+              46.615336
+            ],
+            [
+              119.677477,
+              46.584908
+            ],
+            [
+              119.682405,
+              46.605058
+            ],
+            [
+              119.656535,
+              46.625612
+            ],
+            [
+              119.598637,
+              46.618214
+            ],
+            [
+              119.557985,
+              46.633832
+            ],
+            [
+              119.491464,
+              46.629311
+            ],
+            [
+              119.431718,
+              46.638763
+            ],
+            [
+              119.374435,
+              46.603414
+            ],
+            [
+              119.357805,
+              46.619447
+            ],
+            [
+              119.325776,
+              46.608759
+            ],
+            [
+              119.26295,
+              46.649034
+            ],
+            [
+              119.20074,
+              46.648213
+            ],
+            [
+              119.152081,
+              46.658072
+            ],
+            [
+              119.123132,
+              46.642872
+            ],
+            [
+              119.073857,
+              46.676552
+            ],
+            [
+              119.011647,
+              46.745902
+            ],
+            [
+              118.951285,
+              46.722111
+            ],
+            [
+              118.912481,
+              46.733188
+            ],
+            [
+              118.914329,
+              46.77501
+            ],
+            [
+              118.845343,
+              46.771731
+            ],
+            [
+              118.788061,
+              46.717598
+            ],
+            [
+              118.788061,
+              46.687227
+            ],
+            [
+              118.677192,
+              46.6979
+            ],
+            [
+              118.639004,
+              46.721291
+            ],
+            [
+              118.586033,
+              46.692975
+            ],
+            [
+              118.446831,
+              46.704467
+            ],
+            [
+              118.41049,
+              46.728265
+            ],
+            [
+              118.316252,
+              46.73934
+            ],
+            [
+              118.274984,
+              46.715957
+            ],
+            [
+              118.238643,
+              46.709392
+            ],
+            [
+              118.192448,
+              46.682711
+            ],
+            [
+              118.124078,
+              46.678195
+            ],
+            [
+              118.04647,
+              46.631366
+            ],
+            [
+              117.992883,
+              46.631366
+            ],
+            [
+              117.982412,
+              46.614925
+            ],
+            [
+              117.914659,
+              46.607936
+            ],
+            [
+              117.868464,
+              46.575447
+            ],
+            [
+              117.870927,
+              46.549935
+            ],
+            [
+              117.813645,
+              46.530588
+            ],
+            [
+              117.769913,
+              46.537586
+            ],
+            [
+              117.748355,
+              46.521941
+            ],
+            [
+              117.704008,
+              46.516587
+            ],
+            [
+              117.641182,
+              46.558166
+            ],
+            [
+              117.622704,
+              46.596012
+            ],
+            [
+              117.596218,
+              46.603414
+            ],
+            [
+              117.49582,
+              46.600535
+            ],
+            [
+              117.42006,
+              46.582029
+            ],
+            [
+              117.447777,
+              46.528117
+            ],
+            [
+              117.392343,
+              46.463023
+            ],
+            [
+              117.375712,
+              46.416421
+            ],
+            [
+              117.383719,
+              46.394962
+            ],
+            [
+              117.372017,
+              46.36028
+            ],
+            [
+              117.247597,
+              46.366888
+            ],
+            [
+              117.097308,
+              46.356976
+            ],
+            [
+              116.876801,
+              46.375559
+            ],
+            [
+              116.834302,
+              46.384229
+            ],
+            [
+              116.81336,
+              46.355737
+            ],
+            [
+              116.745606,
+              46.327642
+            ],
+            [
+              116.673541,
+              46.325163
+            ],
+            [
+              116.585462,
+              46.292504
+            ],
+            [
+              116.573143,
+              46.258998
+            ],
+            [
+              116.536187,
+              46.23251
+            ],
+            [
+              116.439484,
+              46.137628
+            ],
+            [
+              116.414231,
+              46.133896
+            ],
+            [
+              116.271949,
+              45.966926
+            ],
+            [
+              116.243,
+              45.876169
+            ],
+            [
+              116.288579,
+              45.839074
+            ],
+            [
+              116.278108,
+              45.831152
+            ],
+            [
+              116.286731,
+              45.775247
+            ],
+            [
+              116.260862,
+              45.776082
+            ],
+            [
+              116.22329,
+              45.747273
+            ],
+            [
+              116.217746,
+              45.72221
+            ],
+            [
+              116.17463,
+              45.688775
+            ],
+            [
+              116.1155,
+              45.679577
+            ],
+            [
+              116.035428,
+              45.685013
+            ],
+            [
+              116.026805,
+              45.661177
+            ],
+            [
+              115.936878,
+              45.632727
+            ],
+            [
+              115.864197,
+              45.572853
+            ],
+            [
+              115.699741,
+              45.45963
+            ],
+            [
+              115.586408,
+              45.440317
+            ],
+            [
+              115.36467,
+              45.392427
+            ],
+            [
+              115.178041,
+              45.396209
+            ],
+            [
+              114.983404,
+              45.379397
+            ],
+            [
+              114.920578,
+              45.386122
+            ],
+            [
+              114.745035,
+              45.438217
+            ],
+            [
+              114.600906,
+              45.403773
+            ],
+            [
+              114.551014,
+              45.387383
+            ],
+            [
+              114.539928,
+              45.325985
+            ],
+            [
+              114.519602,
+              45.283893
+            ],
+            [
+              114.459855,
+              45.21353
+            ],
+            [
+              114.409348,
+              45.179371
+            ],
+            [
+              114.347139,
+              45.119436
+            ],
+            [
+              114.313262,
+              45.107189
+            ],
+            [
+              114.19069,
+              45.036607
+            ],
+            [
+              114.158045,
+              44.994301
+            ],
+            [
+              114.116777,
+              44.957045
+            ],
+            [
+              114.065038,
+              44.931206
+            ],
+            [
+              113.907358,
+              44.915104
+            ],
+            [
+              113.861778,
+              44.863377
+            ],
+            [
+              113.798953,
+              44.849377
+            ],
+            [
+              113.712105,
+              44.788247
+            ],
+            [
+              113.631417,
+              44.745333
+            ],
+            [
+              113.540874,
+              44.759358
+            ],
+            [
+              113.503918,
+              44.777628
+            ],
+            [
+              113.11526,
+              44.799714
+            ],
+            [
+              113.037652,
+              44.822641
+            ],
+            [
+              112.937869,
+              44.840042
+            ],
+            [
+              112.850406,
+              44.840466
+            ],
+            [
+              112.712436,
+              44.879494
+            ],
+            [
+              112.599719,
+              44.930783
+            ],
+            [
+              112.540589,
+              45.001072
+            ],
+            [
+              112.438959,
+              45.071697
+            ],
+            [
+              112.396459,
+              45.064512
+            ],
+            [
+              112.113743,
+              45.072965
+            ],
+            [
+              112.071243,
+              45.096206
+            ],
+            [
+              112.002874,
+              45.090713
+            ],
+            [
+              111.903707,
+              45.052252
+            ],
+            [
+              111.764505,
+              44.969325
+            ],
+            [
+              111.69244,
+              44.859983
+            ],
+            [
+              111.624687,
+              44.778477
+            ],
+            [
+              111.585267,
+              44.705789
+            ],
+            [
+              111.560629,
+              44.647062
+            ],
+            [
+              111.569868,
+              44.57634
+            ],
+            [
+              111.530448,
+              44.55033
+            ],
+            [
+              111.514434,
+              44.507666
+            ],
+            [
+              111.478709,
+              44.488884
+            ],
+            [
+              111.427586,
+              44.394455
+            ],
+            [
+              111.415883,
+              44.35724
+            ],
+            [
+              111.428818,
+              44.319573
+            ],
+            [
+              111.507042,
+              44.294305
+            ],
+            [
+              111.534144,
+              44.26217
+            ],
+            [
+              111.541535,
+              44.206855
+            ],
+            [
+              111.559397,
+              44.171238
+            ],
+            [
+              111.662875,
+              44.061247
+            ],
+            [
+              111.702295,
+              44.034147
+            ],
+            [
+              111.773128,
+              44.010479
+            ],
+            [
+              111.870447,
+              43.940279
+            ],
+            [
+              111.959758,
+              43.823382
+            ],
+            [
+              111.970845,
+              43.748205
+            ],
+            [
+              111.951135,
+              43.693275
+            ],
+            [
+              111.891388,
+              43.6738
+            ],
+            [
+              111.79407,
+              43.672068
+            ],
+            [
+              111.606209,
+              43.513863
+            ],
+            [
+              111.564325,
+              43.490422
+            ],
+            [
+              111.456535,
+              43.494329
+            ],
+            [
+              111.400485,
+              43.472618
+            ],
+            [
+              111.354289,
+              43.436125
+            ],
+            [
+              111.183674,
+              43.396132
+            ],
+            [
+              111.151029,
+              43.38004
+            ],
+            [
+              111.069725,
+              43.357852
+            ],
+            [
+              111.02045,
+              43.329998
+            ],
+            [
+              110.82027,
+              43.149067
+            ],
+            [
+              110.769763,
+              43.099272
+            ],
+            [
+              110.736502,
+              43.089657
+            ],
+            [
+              110.687227,
+              43.036314
+            ],
+            [
+              110.689691,
+              43.02144
+            ],
+            [
+              110.631177,
+              42.936061
+            ],
+            [
+              110.469801,
+              42.839156
+            ],
+            [
+              110.437156,
+              42.781203
+            ],
+            [
+              110.34846,
+              42.742098
+            ],
+            [
+              110.139657,
+              42.674815
+            ],
+            [
+              110.108244,
+              42.642687
+            ],
+            [
+              109.906216,
+              42.635643
+            ],
+            [
+              109.733753,
+              42.579262
+            ],
+            [
+              109.683862,
+              42.558988
+            ],
+            [
+              109.544044,
+              42.472528
+            ],
+            [
+              109.486761,
+              42.458842
+            ],
+            [
+              109.291509,
+              42.435879
+            ],
+            [
+              109.026039,
+              42.458401
+            ],
+            [
+              108.983539,
+              42.449128
+            ],
+            [
+              108.845569,
+              42.395673
+            ],
+            [
+              108.798757,
+              42.415116
+            ],
+            [
+              108.705134,
+              42.413349
+            ],
+            [
+              108.532671,
+              42.442945
+            ],
+            [
+              108.298614,
+              42.438529
+            ],
+            [
+              108.238252,
+              42.460167
+            ],
+            [
+              108.089195,
+              42.436321
+            ],
+            [
+              108.022058,
+              42.433229
+            ],
+            [
+              107.986949,
+              42.413349
+            ],
+            [
+              107.939522,
+              42.403628
+            ],
+            [
+              107.736262,
+              42.415116
+            ],
+            [
+              107.57427,
+              42.412907
+            ],
+            [
+              107.501589,
+              42.456635
+            ],
+            [
+              107.46648,
+              42.458842
+            ],
+            [
+              107.303872,
+              42.412465
+            ],
+            [
+              107.271844,
+              42.364285
+            ],
+            [
+              107.051337,
+              42.319166
+            ],
+            [
+              106.785867,
+              42.291281
+            ],
+            [
+              106.612789,
+              42.241679
+            ],
+            [
+              106.372572,
+              42.161436
+            ],
+            [
+              106.344855,
+              42.149457
+            ],
+            [
+              106.01348,
+              42.032213
+            ],
+            [
+              105.74185,
+              41.949033
+            ],
+            [
+              105.589713,
+              41.888471
+            ],
+            [
+              105.385221,
+              41.797073
+            ],
+            [
+              105.291599,
+              41.749763
+            ],
+            [
+              105.230621,
+              41.751103
+            ],
+            [
+              105.009498,
+              41.583007
+            ],
+            [
+              104.923267,
+              41.654143
+            ],
+            [
+              104.803775,
+              41.652355
+            ],
+            [
+              104.68921,
+              41.6452
+            ],
+            [
+              104.524138,
+              41.661745
+            ],
+            [
+              104.530298,
+              41.875104
+            ],
+            [
+              104.418813,
+              41.860397
+            ],
+            [
+              104.30856,
+              41.840782
+            ],
+            [
+              104.080046,
+              41.805104
+            ],
+            [
+              103.868779,
+              41.802427
+            ],
+            [
+              103.454868,
+              41.877332
+            ],
+            [
+              103.418527,
+              41.882233
+            ],
+            [
+              103.20726,
+              41.96283
+            ],
+            [
+              103.021862,
+              42.028212
+            ],
+            [
+              102.712045,
+              42.153007
+            ],
+            [
+              102.621502,
+              42.154338
+            ],
+            [
+              102.540814,
+              42.162323
+            ],
+            [
+              102.449039,
+              42.144133
+            ],
+            [
+              102.093642,
+              42.223512
+            ],
+            [
+              102.070236,
+              42.232374
+            ],
+            [
+              101.877447,
+              42.432345
+            ],
+            [
+              101.803534,
+              42.503861
+            ],
+            [
+              101.770274,
+              42.509597
+            ],
+            [
+              101.557775,
+              42.529887
+            ],
+            [
+              101.291689,
+              42.586312
+            ],
+            [
+              100.862995,
+              42.671295
+            ],
+            [
+              100.826655,
+              42.675255
+            ],
+            [
+              100.32528,
+              42.690213
+            ],
+            [
+              100.272309,
+              42.636523
+            ],
+            [
+              100.004376,
+              42.648849
+            ],
+            [
+              99.969267,
+              42.647969
+            ],
+            [
+              99.51224,
+              42.568244
+            ],
+            [
+              98.962822,
+              42.607018
+            ],
+            [
+              98.546447,
+              42.638284
+            ],
+            [
+              98.195362,
+              42.653251
+            ],
+            [
+              97.831958,
+              42.706047
+            ],
+            [
+              97.28254,
+              42.782081
+            ],
+            [
+              97.172903,
+              42.795257
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 210000,
+        "name": "杈藉畞鐪�",
+        "center": [
+          123.429096,
+          41.796767
+        ],
+        "centroid": [
+          122.604994,
+          41.299712
+        ],
+        "childrenNum": 14,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 5,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                123.534489,
+                39.788361
+              ],
+              [
+                123.546808,
+                39.756163
+              ],
+              [
+                123.579453,
+                39.781002
+              ],
+              [
+                123.612714,
+                39.775023
+              ],
+              [
+                123.642279,
+                39.796178
+              ],
+              [
+                123.645358,
+                39.823761
+              ],
+              [
+                123.674924,
+                39.826979
+              ],
+              [
+                123.687858,
+                39.808132
+              ],
+              [
+                123.795032,
+                39.822842
+              ],
+              [
+                123.812278,
+                39.831115
+              ],
+              [
+                123.95148,
+                39.817786
+              ],
+              [
+                124.002603,
+                39.800316
+              ],
+              [
+                124.103001,
+                39.823302
+              ],
+              [
+                124.099306,
+                39.777323
+              ],
+              [
+                124.151045,
+                39.74558
+              ],
+              [
+                124.173218,
+                39.841225
+              ],
+              [
+                124.214486,
+                39.865116
+              ],
+              [
+                124.215102,
+                39.883487
+              ],
+              [
+                124.21695,
+                39.894049
+              ],
+              [
+                124.218182,
+                39.895885
+              ],
+              [
+                124.219414,
+                39.899099
+              ],
+              [
+                124.241588,
+                39.928477
+              ],
+              [
+                124.286551,
+                39.931689
+              ],
+              [
+                124.288399,
+                39.962888
+              ],
+              [
+                124.349377,
+                39.989029
+              ],
+              [
+                124.372167,
+                40.021576
+              ],
+              [
+                124.336442,
+                40.049985
+              ],
+              [
+                124.346913,
+                40.079756
+              ],
+              [
+                124.428217,
+                40.144291
+              ],
+              [
+                124.457782,
+                40.177679
+              ],
+              [
+                124.490427,
+                40.18408
+              ],
+              [
+                124.513833,
+                40.218362
+              ],
+              [
+                124.515065,
+                40.22019
+              ],
+              [
+                124.62655,
+                40.291896
+              ],
+              [
+                124.722636,
+                40.321561
+              ],
+              [
+                124.739267,
+                40.371733
+              ],
+              [
+                124.834121,
+                40.423235
+              ],
+              [
+                124.913578,
+                40.481981
+              ],
+              [
+                124.945606,
+                40.45603
+              ],
+              [
+                124.985642,
+                40.475153
+              ],
+              [
+                125.044157,
+                40.466503
+              ],
+              [
+                125.042925,
+                40.483802
+              ],
+              [
+                125.004737,
+                40.496091
+              ],
+              [
+                125.015823,
+                40.533853
+              ],
+              [
+                125.076801,
+                40.562048
+              ],
+              [
+                125.113758,
+                40.569322
+              ],
+              [
+                125.181511,
+                40.611132
+              ],
+              [
+                125.262815,
+                40.620218
+              ],
+              [
+                125.279445,
+                40.655187
+              ],
+              [
+                125.305315,
+                40.661089
+              ],
+              [
+                125.329337,
+                40.643835
+              ],
+              [
+                125.375532,
+                40.658365
+              ],
+              [
+                125.422343,
+                40.635661
+              ],
+              [
+                125.418648,
+                40.673345
+              ],
+              [
+                125.453756,
+                40.676522
+              ],
+              [
+                125.459916,
+                40.707379
+              ],
+              [
+                125.49564,
+                40.728697
+              ],
+              [
+                125.544915,
+                40.729605
+              ],
+              [
+                125.551075,
+                40.761796
+              ],
+              [
+                125.585567,
+                40.788535
+              ],
+              [
+                125.61698,
+                40.763609
+              ],
+              [
+                125.685349,
+                40.769048
+              ],
+              [
+                125.67611,
+                40.788082
+              ],
+              [
+                125.641002,
+                40.798503
+              ],
+              [
+                125.648393,
+                40.826133
+              ],
+              [
+                125.707523,
+                40.866877
+              ],
+              [
+                125.687813,
+                40.897645
+              ],
+              [
+                125.652089,
+                40.91619
+              ],
+              [
+                125.584335,
+                40.891764
+              ],
+              [
+                125.589263,
+                40.931112
+              ],
+              [
+                125.635458,
+                40.94151
+              ],
+              [
+                125.650241,
+                40.970888
+              ],
+              [
+                125.674879,
+                40.974503
+              ],
+              [
+                125.684118,
+                41.021929
+              ],
+              [
+                125.726617,
+                41.055332
+              ],
+              [
+                125.739552,
+                41.08917
+              ],
+              [
+                125.712451,
+                41.095485
+              ],
+              [
+                125.734009,
+                41.125695
+              ],
+              [
+                125.759878,
+                41.132908
+              ],
+              [
+                125.791291,
+                41.167607
+              ],
+              [
+                125.73832,
+                41.178418
+              ],
+              [
+                125.758646,
+                41.232449
+              ],
+              [
+                125.749407,
+                41.245499
+              ],
+              [
+                125.695205,
+                41.244599
+              ],
+              [
+                125.685349,
+                41.273842
+              ],
+              [
+                125.646545,
+                41.264396
+              ],
+              [
+                125.642234,
+                41.296327
+              ],
+              [
+                125.62006,
+                41.318355
+              ],
+              [
+                125.637306,
+                41.34442
+              ],
+              [
+                125.610205,
+                41.365084
+              ],
+              [
+                125.589879,
+                41.359245
+              ],
+              [
+                125.581256,
+                41.396517
+              ],
+              [
+                125.547995,
+                41.401006
+              ],
+              [
+                125.534444,
+                41.428833
+              ],
+              [
+                125.533212,
+                41.479069
+              ],
+              [
+                125.493176,
+                41.509103
+              ],
+              [
+                125.507343,
+                41.534195
+              ],
+              [
+                125.479626,
+                41.544946
+              ],
+              [
+                125.450061,
+                41.597777
+              ],
+              [
+                125.461148,
+                41.642516
+              ],
+              [
+                125.446981,
+                41.67605
+              ],
+              [
+                125.412488,
+                41.691246
+              ],
+              [
+                125.344119,
+                41.672474
+              ],
+              [
+                125.317018,
+                41.676944
+              ],
+              [
+                125.332416,
+                41.711354
+              ],
+              [
+                125.336112,
+                41.768067
+              ],
+              [
+                125.336112,
+                41.768067
+              ],
+              [
+                125.323177,
+                41.771191
+              ],
+              [
+                125.323177,
+                41.771191
+              ],
+              [
+                125.319482,
+                41.776993
+              ],
+              [
+                125.319482,
+                41.776993
+              ],
+              [
+                125.294844,
+                41.822945
+              ],
+              [
+                125.307779,
+                41.924548
+              ],
+              [
+                125.35151,
+                41.92811
+              ],
+              [
+                125.291764,
+                41.958825
+              ],
+              [
+                125.29854,
+                41.974399
+              ],
+              [
+                125.369989,
+                42.002868
+              ],
+              [
+                125.363213,
+                42.017097
+              ],
+              [
+                125.416184,
+                42.063766
+              ],
+              [
+                125.414336,
+                42.101964
+              ],
+              [
+                125.446365,
+                42.098411
+              ],
+              [
+                125.490097,
+                42.136145
+              ],
+              [
+                125.458068,
+                42.160105
+              ],
+              [
+                125.458068,
+                42.160105
+              ],
+              [
+                125.41372,
+                42.156112
+              ],
+              [
+                125.368141,
+                42.182726
+              ],
+              [
+                125.357054,
+                42.145464
+              ],
+              [
+                125.305931,
+                42.146351
+              ],
+              [
+                125.312706,
+                42.197359
+              ],
+              [
+                125.280677,
+                42.175187
+              ],
+              [
+                125.312706,
+                42.219966
+              ],
+              [
+                125.27575,
+                42.231045
+              ],
+              [
+                125.27575,
+                42.266928
+              ],
+              [
+                125.299156,
+                42.289953
+              ],
+              [
+                125.264047,
+                42.312528
+              ],
+              [
+                125.224011,
+                42.30102
+              ],
+              [
+                125.175352,
+                42.308102
+              ],
+              [
+                125.167345,
+                42.351903
+              ],
+              [
+                125.203685,
+                42.366938
+              ],
+              [
+                125.185823,
+                42.38197
+              ],
+              [
+                125.186439,
+                42.427928
+              ],
+              [
+                125.140243,
+                42.44692
+              ],
+              [
+                125.150098,
+                42.458842
+              ],
+              [
+                125.105135,
+                42.490624
+              ],
+              [
+                125.068794,
+                42.499449
+              ],
+              [
+                125.090968,
+                42.515773
+              ],
+              [
+                125.066946,
+                42.534738
+              ],
+              [
+                125.089736,
+                42.567803
+              ],
+              [
+                125.082961,
+                42.591159
+              ],
+              [
+                125.097127,
+                42.622433
+              ],
+              [
+                125.038613,
+                42.615387
+              ],
+              [
+                125.010896,
+                42.63212
+              ],
+              [
+                125.014592,
+                42.666014
+              ],
+              [
+                124.99057,
+                42.677455
+              ],
+              [
+                124.968396,
+                42.722756
+              ],
+              [
+                124.996729,
+                42.745174
+              ],
+              [
+                124.975171,
+                42.802722
+              ],
+              [
+                124.92836,
+                42.819844
+              ],
+              [
+                124.897563,
+                42.787791
+              ],
+              [
+                124.874157,
+                42.789987
+              ],
+              [
+                124.856911,
+                42.824234
+              ],
+              [
+                124.84952,
+                42.882585
+              ],
+              [
+                124.87231,
+                42.962344
+              ],
+              [
+                124.869846,
+                42.988178
+              ],
+              [
+                124.840897,
+                43.032377
+              ],
+              [
+                124.88894,
+                43.074796
+              ],
+              [
+                124.882781,
+                43.13422
+              ],
+              [
+                124.785462,
+                43.117185
+              ],
+              [
+                124.755281,
+                43.074359
+              ],
+              [
+                124.719557,
+                43.069987
+              ],
+              [
+                124.686912,
+                43.051185
+              ],
+              [
+                124.677673,
+                43.002185
+              ],
+              [
+                124.658579,
+                42.972854
+              ],
+              [
+                124.635173,
+                42.972854
+              ],
+              [
+                124.632093,
+                42.949642
+              ],
+              [
+                124.607456,
+                42.937376
+              ],
+              [
+                124.586514,
+                42.905384
+              ],
+              [
+                124.466406,
+                42.847054
+              ],
+              [
+                124.435609,
+                42.880831
+              ],
+              [
+                124.371551,
+                42.880831
+              ],
+              [
+                124.38079,
+                42.912835
+              ],
+              [
+                124.431913,
+                42.930803
+              ],
+              [
+                124.442384,
+                42.958841
+              ],
+              [
+                124.42329,
+                42.975482
+              ],
+              [
+                124.369703,
+                42.972854
+              ],
+              [
+                124.333363,
+                42.997371
+              ],
+              [
+                124.425754,
+                43.076107
+              ],
+              [
+                124.366007,
+                43.121554
+              ],
+              [
+                124.273617,
+                43.17875
+              ],
+              [
+                124.287167,
+                43.207983
+              ],
+              [
+                124.27608,
+                43.233278
+              ],
+              [
+                124.228653,
+                43.235022
+              ],
+              [
+                124.215102,
+                43.255947
+              ],
+              [
+                124.168291,
+                43.244177
+              ],
+              [
+                124.114088,
+                43.247229
+              ],
+              [
+                124.117168,
+                43.2773
+              ],
+              [
+                124.099306,
+                43.292983
+              ],
+              [
+                124.032784,
+                43.280786
+              ],
+              [
+                123.964415,
+                43.34088
+              ],
+              [
+                123.896046,
+                43.361333
+              ],
+              [
+                123.881263,
+                43.392218
+              ],
+              [
+                123.881263,
+                43.392218
+              ],
+              [
+                123.852314,
+                43.406133
+              ],
+              [
+                123.857858,
+                43.459153
+              ],
+              [
+                123.857858,
+                43.459153
+              ],
+              [
+                123.79688,
+                43.489988
+              ],
+              [
+                123.747604,
+                43.472184
+              ],
+              [
+                123.749452,
+                43.439167
+              ],
+              [
+                123.710032,
+                43.417001
+              ],
+              [
+                123.703873,
+                43.37047
+              ],
+              [
+                123.698329,
+                43.272071
+              ],
+              [
+                123.664453,
+                43.264663
+              ],
+              [
+                123.676771,
+                43.223684
+              ],
+              [
+                123.645974,
+                43.208855
+              ],
+              [
+                123.666916,
+                43.179623
+              ],
+              [
+                123.636119,
+                43.141644
+              ],
+              [
+                123.631192,
+                43.088346
+              ],
+              [
+                123.580685,
+                43.036314
+              ],
+              [
+                123.572678,
+                43.003498
+              ],
+              [
+                123.536337,
+                43.007
+              ],
+              [
+                123.474743,
+                43.042438
+              ],
+              [
+                123.434707,
+                43.027565
+              ],
+              [
+                123.323222,
+                43.000872
+              ],
+              [
+                123.259165,
+                42.993431
+              ],
+              [
+                123.18402,
+                42.925983
+              ],
+              [
+                123.188947,
+                42.895739
+              ],
+              [
+                123.169853,
+                42.859777
+              ],
+              [
+                123.227752,
+                42.831695
+              ],
+              [
+                123.118114,
+                42.801405
+              ],
+              [
+                123.058368,
+                42.768903
+              ],
+              [
+                122.980144,
+                42.777689
+              ],
+              [
+                122.945651,
+                42.753524
+              ],
+              [
+                122.925941,
+                42.772417
+              ],
+              [
+                122.887137,
+                42.770221
+              ],
+              [
+                122.883442,
+                42.751766
+              ],
+              [
+                122.883442,
+                42.751766
+              ],
+              [
+                122.848949,
+                42.712203
+              ],
+              [
+                122.848949,
+                42.712203
+              ],
+              [
+                122.786123,
+                42.757479
+              ],
+              [
+                122.73808,
+                42.77066
+              ],
+              [
+                122.733152,
+                42.786034
+              ],
+              [
+                122.653696,
+                42.78252
+              ],
+              [
+                122.624747,
+                42.773296
+              ],
+              [
+                122.580399,
+                42.789987
+              ],
+              [
+                122.576088,
+                42.819405
+              ],
+              [
+                122.556378,
+                42.827745
+              ],
+              [
+                122.436886,
+                42.843105
+              ],
+              [
+                122.35127,
+                42.830378
+              ],
+              [
+                122.371596,
+                42.776371
+              ],
+              [
+                122.439349,
+                42.770221
+              ],
+              [
+                122.460907,
+                42.755282
+              ],
+              [
+                122.396234,
+                42.707366
+              ],
+              [
+                122.396234,
+                42.684054
+              ],
+              [
+                122.338951,
+                42.669975
+              ],
+              [
+                122.324785,
+                42.684934
+              ],
+              [
+                122.261343,
+                42.695931
+              ],
+              [
+                122.204676,
+                42.732867
+              ],
+              [
+                122.204676,
+                42.685374
+              ],
+              [
+                122.160945,
+                42.684934
+              ],
+              [
+                122.072865,
+                42.710444
+              ],
+              [
+                122.062394,
+                42.723635
+              ],
+              [
+                122.018663,
+                42.69901
+              ],
+              [
+                121.939207,
+                42.688453
+              ],
+              [
+                121.94167,
+                42.666014
+              ],
+              [
+                121.915801,
+                42.656332
+              ],
+              [
+                121.921344,
+                42.605697
+              ],
+              [
+                121.889931,
+                42.556784
+              ],
+              [
+                121.844352,
+                42.522389
+              ],
+              [
+                121.831417,
+                42.533856
+              ],
+              [
+                121.817867,
+                42.504303
+              ],
+              [
+                121.803084,
+                42.514891
+              ],
+              [
+                121.747649,
+                42.484887
+              ],
+              [
+                121.69899,
+                42.438529
+              ],
+              [
+                121.66573,
+                42.437204
+              ],
+              [
+                121.604136,
+                42.495037
+              ],
+              [
+                121.607831,
+                42.516214
+              ],
+              [
+                121.570875,
+                42.487093
+              ],
+              [
+                121.506201,
+                42.482239
+              ],
+              [
+                121.4791,
+                42.49636
+              ],
+              [
+                121.434752,
+                42.475176
+              ],
+              [
+                121.386093,
+                42.474294
+              ],
+              [
+                121.304789,
+                42.435879
+              ],
+              [
+                121.314644,
+                42.42837
+              ],
+              [
+                121.285079,
+                42.387717
+              ],
+              [
+                121.218558,
+                42.371802
+              ],
+              [
+                121.184681,
+                42.333324
+              ],
+              [
+                121.133558,
+                42.300135
+              ],
+              [
+                121.120623,
+                42.280656
+              ],
+              [
+                121.087978,
+                42.278885
+              ],
+              [
+                121.070732,
+                42.254083
+              ],
+              [
+                121.028848,
+                42.242565
+              ],
+              [
+                120.992508,
+                42.264714
+              ],
+              [
+                120.933994,
+                42.27977
+              ],
+              [
+                120.883487,
+                42.269585
+              ],
+              [
+                120.883487,
+                42.269585
+              ],
+              [
+                120.883487,
+                42.242565
+              ],
+              [
+                120.8299,
+                42.252755
+              ],
+              [
+                120.820661,
+                42.227943
+              ],
+              [
+                120.79048,
+                42.218636
+              ],
+              [
+                120.745516,
+                42.223512
+              ],
+              [
+                120.72211,
+                42.203565
+              ],
+              [
+                120.624792,
+                42.154338
+              ],
+              [
+                120.58414,
+                42.167203
+              ],
+              [
+                120.56751,
+                42.152119
+              ],
+              [
+                120.466496,
+                42.105516
+              ],
+              [
+                120.493597,
+                42.073539
+              ],
+              [
+                120.450481,
+                42.057101
+              ],
+              [
+                120.456641,
+                42.016208
+              ],
+              [
+                120.399358,
+                41.984631
+              ],
+              [
+                120.373489,
+                41.994862
+              ],
+              [
+                120.309431,
+                41.951704
+              ],
+              [
+                120.318054,
+                41.93746
+              ],
+              [
+                120.271859,
+                41.925439
+              ],
+              [
+                120.260156,
+                41.904062
+              ],
+              [
+                120.290337,
+                41.897381
+              ],
+              [
+                120.286641,
+                41.880005
+              ],
+              [
+                120.251533,
+                41.884016
+              ],
+              [
+                120.215808,
+                41.853265
+              ],
+              [
+                120.188707,
+                41.848361
+              ],
+              [
+                120.183164,
+                41.826513
+              ],
+              [
+                120.127113,
+                41.77253
+              ],
+              [
+                120.1382,
+                41.729221
+              ],
+              [
+                120.096316,
+                41.697056
+              ],
+              [
+                120.035954,
+                41.708226
+              ],
+              [
+                120.024867,
+                41.737707
+              ],
+              [
+                120.050737,
+                41.776101
+              ],
+              [
+                120.041498,
+                41.818932
+              ],
+              [
+                120.023019,
+                41.816701
+              ],
+              [
+                119.989759,
+                41.899163
+              ],
+              [
+                119.954034,
+                41.923212
+              ],
+              [
+                119.950954,
+                41.974399
+              ],
+              [
+                119.924469,
+                41.98908
+              ],
+              [
+                119.921389,
+                42.014429
+              ],
+              [
+                119.897368,
+                42.030879
+              ],
+              [
+                119.87581,
+                42.077982
+              ],
+              [
+                119.845629,
+                42.097079
+              ],
+              [
+                119.837622,
+                42.135257
+              ],
+              [
+                119.854868,
+                42.170308
+              ],
+              [
+                119.841933,
+                42.215534
+              ],
+              [
+                119.744615,
+                42.211545
+              ],
+              [
+                119.679941,
+                42.240793
+              ],
+              [
+                119.617115,
+                42.252755
+              ],
+              [
+                119.609108,
+                42.276671
+              ],
+              [
+                119.557985,
+                42.289068
+              ],
+              [
+                119.557985,
+                42.289068
+              ],
+              [
+                119.539507,
+                42.297922
+              ],
+              [
+                119.571536,
+                42.335536
+              ],
+              [
+                119.572152,
+                42.359421
+              ],
+              [
+                119.540123,
+                42.363401
+              ],
+              [
+                119.502551,
+                42.388159
+              ],
+              [
+                119.482841,
+                42.347037
+              ],
+              [
+                119.432949,
+                42.317396
+              ],
+              [
+                119.34795,
+                42.300578
+              ],
+              [
+                119.280197,
+                42.260728
+              ],
+              [
+                119.274037,
+                42.239021
+              ],
+              [
+                119.237697,
+                42.200905
+              ],
+              [
+                119.277733,
+                42.185387
+              ],
+              [
+                119.286972,
+                42.154781
+              ],
+              [
+                119.30853,
+                42.147239
+              ],
+              [
+                119.314689,
+                42.119723
+              ],
+              [
+                119.352261,
+                42.118391
+              ],
+              [
+                119.384906,
+                42.08953
+              ],
+              [
+                119.375667,
+                42.023322
+              ],
+              [
+                119.324544,
+                41.969505
+              ],
+              [
+                119.323928,
+                41.937014
+              ],
+              [
+                119.340559,
+                41.926774
+              ],
+              [
+                119.323312,
+                41.889807
+              ],
+              [
+                119.334399,
+                41.871539
+              ],
+              [
+                119.312841,
+                41.80555
+              ],
+              [
+                119.292515,
+                41.790827
+              ],
+              [
+                119.317769,
+                41.764049
+              ],
+              [
+                119.319001,
+                41.727435
+              ],
+              [
+                119.299907,
+                41.705545
+              ],
+              [
+                119.307914,
+                41.657273
+              ],
+              [
+                119.342406,
+                41.617914
+              ],
+              [
+                119.415703,
+                41.590169
+              ],
+              [
+                119.420015,
+                41.567785
+              ],
+              [
+                119.362116,
+                41.566442
+              ],
+              [
+                119.361501,
+                41.545841
+              ],
+              [
+                119.406464,
+                41.503276
+              ],
+              [
+                119.401537,
+                41.472343
+              ],
+              [
+                119.378131,
+                41.459787
+              ],
+              [
+                119.376283,
+                41.422102
+              ],
+              [
+                119.309762,
+                41.405944
+              ],
+              [
+                119.330704,
+                41.385293
+              ],
+              [
+                119.296211,
+                41.325097
+              ],
+              [
+                119.239545,
+                41.31431
+              ],
+              [
+                119.2494,
+                41.279689
+              ],
+              [
+                119.209364,
+                41.244599
+              ],
+              [
+                119.204436,
+                41.222546
+              ],
+              [
+                119.169943,
+                41.222996
+              ],
+              [
+                119.189038,
+                41.198234
+              ],
+              [
+                119.126212,
+                41.138767
+              ],
+              [
+                119.081248,
+                41.131555
+              ],
+              [
+                119.080632,
+                41.095936
+              ],
+              [
+                119.037516,
+                41.067516
+              ],
+              [
+                118.964836,
+                41.079246
+              ],
+              [
+                118.937118,
+                41.052625
+              ],
+              [
+                118.951901,
+                41.018317
+              ],
+              [
+                119.013495,
+                41.007479
+              ],
+              [
+                119.00056,
+                40.967273
+              ],
+              [
+                118.977154,
+                40.959138
+              ],
+              [
+                118.977154,
+                40.959138
+              ],
+              [
+                118.916792,
+                40.969984
+              ],
+              [
+                118.90201,
+                40.960946
+              ],
+              [
+                118.873061,
+                40.847866
+              ],
+              [
+                118.845959,
+                40.822057
+              ],
+              [
+                118.878604,
+                40.783098
+              ],
+              [
+                118.907553,
+                40.775394
+              ],
+              [
+                118.895234,
+                40.75409
+              ],
+              [
+                118.950053,
+                40.747743
+              ],
+              [
+                118.96114,
+                40.72008
+              ],
+              [
+                119.011031,
+                40.687414
+              ],
+              [
+                119.028277,
+                40.692406
+              ],
+              [
+                119.054763,
+                40.664721
+              ],
+              [
+                119.115125,
+                40.666536
+              ],
+              [
+                119.165632,
+                40.69286
+              ],
+              [
+                119.184726,
+                40.680153
+              ],
+              [
+                119.14469,
+                40.632482
+              ],
+              [
+                119.162552,
+                40.600228
+              ],
+              [
+                119.177951,
+                40.609315
+              ],
+              [
+                119.230921,
+                40.603863
+              ],
+              [
+                119.22045,
+                40.569322
+              ],
+              [
+                119.256175,
+                40.543404
+              ],
+              [
+                119.30237,
+                40.530215
+              ],
+              [
+                119.429254,
+                40.540221
+              ],
+              [
+                119.477913,
+                40.533399
+              ],
+              [
+                119.503783,
+                40.553864
+              ],
+              [
+                119.559217,
+                40.547952
+              ],
+              [
+                119.572152,
+                40.523846
+              ],
+              [
+                119.553674,
+                40.502007
+              ],
+              [
+                119.604797,
+                40.455119
+              ],
+              [
+                119.586934,
+                40.375381
+              ],
+              [
+                119.598021,
+                40.334335
+              ],
+              [
+                119.651608,
+                40.271808
+              ],
+              [
+                119.639289,
+                40.231613
+              ],
+              [
+                119.639289,
+                40.231613
+              ],
+              [
+                119.671934,
+                40.23938
+              ],
+              [
+                119.716898,
+                40.195966
+              ],
+              [
+                119.745847,
+                40.207851
+              ],
+              [
+                119.760629,
+                40.136056
+              ],
+              [
+                119.736608,
+                40.104936
+              ],
+              [
+                119.772332,
+                40.08113
+              ],
+              [
+                119.783419,
+                40.046778
+              ],
+              [
+                119.783419,
+                40.046778
+              ],
+              [
+                119.787115,
+                40.041739
+              ],
+              [
+                119.787115,
+                40.041739
+              ],
+              [
+                119.81668,
+                40.050443
+              ],
+              [
+                119.81668,
+                40.050443
+              ],
+              [
+                119.854252,
+                40.033033
+              ],
+              [
+                119.845629,
+                40.000949
+              ],
+              [
+                119.845629,
+                40.000949
+              ],
+              [
+                119.854252,
+                39.98857
+              ],
+              [
+                119.91831,
+                39.989946
+              ],
+              [
+                119.941715,
+                40.009659
+              ],
+              [
+                119.947259,
+                40.040364
+              ],
+              [
+                120.092005,
+                40.077466
+              ],
+              [
+                120.134504,
+                40.074719
+              ],
+              [
+                120.161606,
+                40.096239
+              ],
+              [
+                120.273091,
+                40.127362
+              ],
+              [
+                120.371641,
+                40.174478
+              ],
+              [
+                120.451097,
+                40.177679
+              ],
+              [
+                120.491749,
+                40.20008
+              ],
+              [
+                120.523778,
+                40.256737
+              ],
+              [
+                120.52193,
+                40.304676
+              ],
+              [
+                120.537329,
+                40.325211
+              ],
+              [
+                120.602618,
+                40.36079
+              ],
+              [
+                120.596459,
+                40.399084
+              ],
+              [
+                120.617401,
+                40.41959
+              ],
+              [
+                120.616169,
+                40.444645
+              ],
+              [
+                120.619249,
+                40.460128
+              ],
+              [
+                120.666676,
+                40.467413
+              ],
+              [
+                120.693777,
+                40.505647
+              ],
+              [
+                120.72211,
+                40.515657
+              ],
+              [
+                120.72827,
+                40.539311
+              ],
+              [
+                120.822509,
+                40.59432
+              ],
+              [
+                120.837291,
+                40.644289
+              ],
+              [
+                120.8299,
+                40.671076
+              ],
+              [
+                120.861313,
+                40.684692
+              ],
+              [
+                120.939537,
+                40.686507
+              ],
+              [
+                120.983269,
+                40.712822
+              ],
+              [
+                121.032544,
+                40.709193
+              ],
+              [
+                121.028848,
+                40.746382
+              ],
+              [
+                120.991276,
+                40.744115
+              ],
+              [
+                120.980189,
+                40.766329
+              ],
+              [
+                120.994356,
+                40.790801
+              ],
+              [
+                120.971566,
+                40.805751
+              ],
+              [
+                121.00729,
+                40.807563
+              ],
+              [
+                121.010986,
+                40.784457
+              ],
+              [
+                121.086747,
+                40.79805
+              ],
+              [
+                121.076892,
+                40.815716
+              ],
+              [
+                121.096602,
+                40.839717
+              ],
+              [
+                121.126167,
+                40.86914
+              ],
+              [
+                121.177906,
+                40.873665
+              ],
+              [
+                121.23642,
+                40.851035
+              ],
+              [
+                121.290622,
+                40.851488
+              ],
+              [
+                121.439064,
+                40.830208
+              ],
+              [
+                121.440296,
+                40.88181
+              ],
+              [
+                121.499426,
+                40.880001
+              ],
+              [
+                121.526527,
+                40.85194
+              ],
+              [
+                121.55486,
+                40.849677
+              ],
+              [
+                121.553013,
+                40.817528
+              ],
+              [
+                121.576418,
+                40.837906
+              ],
+              [
+                121.626309,
+                40.844244
+              ],
+              [
+                121.682976,
+                40.829755
+              ],
+              [
+                121.732251,
+                40.846961
+              ],
+              [
+                121.735331,
+                40.862351
+              ],
+              [
+                121.778446,
+                40.886787
+              ],
+              [
+                121.816019,
+                40.894931
+              ],
+              [
+                121.84312,
+                40.831567
+              ],
+              [
+                121.883772,
+                40.802127
+              ],
+              [
+                121.934279,
+                40.79805
+              ],
+              [
+                121.936127,
+                40.711462
+              ],
+              [
+                121.951525,
+                40.680607
+              ],
+              [
+                122.025438,
+                40.674253
+              ],
+              [
+                122.06609,
+                40.64883
+              ],
+              [
+                122.122141,
+                40.657457
+              ],
+              [
+                122.148626,
+                40.671983
+              ],
+              [
+                122.133843,
+                40.614313
+              ],
+              [
+                122.150474,
+                40.588413
+              ],
+              [
+                122.245944,
+                40.519752
+              ],
+              [
+                122.231162,
+                40.505192
+              ],
+              [
+                122.265038,
+                40.48016
+              ],
+              [
+                122.221923,
+                40.481071
+              ],
+              [
+                122.240401,
+                40.461039
+              ],
+              [
+                122.250872,
+                40.445555
+              ],
+              [
+                122.229314,
+                40.424146
+              ],
+              [
+                122.186814,
+                40.422779
+              ],
+              [
+                122.198517,
+                40.382219
+              ],
+              [
+                122.152322,
+                40.357597
+              ],
+              [
+                122.135691,
+                40.374925
+              ],
+              [
+                122.111054,
+                40.348932
+              ],
+              [
+                122.138155,
+                40.338897
+              ],
+              [
+                122.110438,
+                40.315629
+              ],
+              [
+                122.079641,
+                40.332967
+              ],
+              [
+                122.040221,
+                40.322017
+              ],
+              [
+                122.039605,
+                40.260391
+              ],
+              [
+                122.02667,
+                40.244862
+              ],
+              [
+                121.940438,
+                40.242121
+              ],
+              [
+                121.950293,
+                40.204194
+              ],
+              [
+                121.98109,
+                40.173106
+              ],
+              [
+                122.003264,
+                40.172191
+              ],
+              [
+                121.995257,
+                40.128277
+              ],
+              [
+                121.956453,
+                40.133311
+              ],
+              [
+                121.910257,
+                40.072887
+              ],
+              [
+                121.824642,
+                40.025701
+              ],
+              [
+                121.796309,
+                39.999116
+              ],
+              [
+                121.779062,
+                39.942702
+              ],
+              [
+                121.76428,
+                39.933525
+              ],
+              [
+                121.699606,
+                39.937196
+              ],
+              [
+                121.626925,
+                39.882569
+              ],
+              [
+                121.572107,
+                39.865116
+              ],
+              [
+                121.541926,
+                39.874302
+              ],
+              [
+                121.530223,
+                39.851334
+              ],
+              [
+                121.472325,
+                39.802155
+              ],
+              [
+                121.487107,
+                39.760303
+              ],
+              [
+                121.45939,
+                39.747881
+              ],
+              [
+                121.502506,
+                39.703233
+              ],
+              [
+                121.482796,
+                39.659478
+              ],
+              [
+                121.451999,
+                39.658095
+              ],
+              [
+                121.450151,
+                39.624914
+              ],
+              [
+                121.325731,
+                39.601402
+              ],
+              [
+                121.299246,
+                39.606013
+              ],
+              [
+                121.263521,
+                39.589873
+              ],
+              [
+                121.226565,
+                39.554814
+              ],
+              [
+                121.224717,
+                39.519275
+              ],
+              [
+                121.268449,
+                39.482794
+              ],
+              [
+                121.286927,
+                39.507271
+              ],
+              [
+                121.301709,
+                39.476327
+              ],
+              [
+                121.245659,
+                39.456923
+              ],
+              [
+                121.270296,
+                39.434277
+              ],
+              [
+                121.246891,
+                39.421334
+              ],
+              [
+                121.245659,
+                39.389427
+              ],
+              [
+                121.270296,
+                39.374162
+              ],
+              [
+                121.307869,
+                39.391277
+              ],
+              [
+                121.324499,
+                39.371386
+              ],
+              [
+                121.35468,
+                39.377863
+              ],
+              [
+                121.432904,
+                39.357506
+              ],
+              [
+                121.435984,
+                39.329736
+              ],
+              [
+                121.466781,
+                39.320014
+              ],
+              [
+                121.474788,
+                39.296398
+              ],
+              [
+                121.508665,
+                39.29223
+              ],
+              [
+                121.51544,
+                39.286672
+              ],
+              [
+                121.562252,
+                39.322792
+              ],
+              [
+                121.621382,
+                39.326033
+              ],
+              [
+                121.72486,
+                39.364447
+              ],
+              [
+                121.711925,
+                39.33992
+              ],
+              [
+                121.7187,
+                39.320477
+              ],
+              [
+                121.667577,
+                39.310754
+              ],
+              [
+                121.672505,
+                39.275554
+              ],
+              [
+                121.623846,
+                39.285745
+              ],
+              [
+                121.589353,
+                39.263044
+              ],
+              [
+                121.631237,
+                39.22643
+              ],
+              [
+                121.591201,
+                39.228748
+              ],
+              [
+                121.586889,
+                39.193506
+              ],
+              [
+                121.604136,
+                39.166136
+              ],
+              [
+                121.639244,
+                39.166136
+              ],
+              [
+                121.68236,
+                39.117863
+              ],
+              [
+                121.631853,
+                39.077921
+              ],
+              [
+                121.605983,
+                39.080708
+              ],
+              [
+                121.642324,
+                39.11972
+              ],
+              [
+                121.590585,
+                39.154999
+              ],
+              [
+                121.562252,
+                39.127149
+              ],
+              [
+                121.599208,
+                39.098824
+              ],
+              [
+                121.581962,
+                39.075598
+              ],
+              [
+                121.508049,
+                39.034237
+              ],
+              [
+                121.431057,
+                39.027263
+              ],
+              [
+                121.370695,
+                39.060264
+              ],
+              [
+                121.317108,
+                39.012384
+              ],
+              [
+                121.341129,
+                38.980757
+              ],
+              [
+                121.275224,
+                38.971917
+              ],
+              [
+                121.204391,
+                38.941202
+              ],
+              [
+                121.180369,
+                38.959819
+              ],
+              [
+                121.128014,
+                38.958888
+              ],
+              [
+                121.08921,
+                38.922115
+              ],
+              [
+                121.094138,
+                38.894173
+              ],
+              [
+                121.129862,
+                38.879266
+              ],
+              [
+                121.110768,
+                38.862026
+              ],
+              [
+                121.12863,
+                38.799089
+              ],
+              [
+                121.112,
+                38.776231
+              ],
+              [
+                121.13787,
+                38.723023
+              ],
+              [
+                121.198848,
+                38.721623
+              ],
+              [
+                121.259825,
+                38.786495
+              ],
+              [
+                121.280767,
+                38.786961
+              ],
+              [
+                121.288775,
+                38.78976
+              ],
+              [
+                121.315876,
+                38.793958
+              ],
+              [
+                121.359608,
+                38.822406
+              ],
+              [
+                121.399028,
+                38.812613
+              ],
+              [
+                121.509897,
+                38.817743
+              ],
+              [
+                121.564715,
+                38.874607
+              ],
+              [
+                121.618302,
+                38.862492
+              ],
+              [
+                121.675585,
+                38.86156
+              ],
+              [
+                121.708845,
+                38.872744
+              ],
+              [
+                121.719316,
+                38.920252
+              ],
+              [
+                121.655874,
+                38.946788
+              ],
+              [
+                121.618918,
+                38.950046
+              ],
+              [
+                121.66265,
+                38.966333
+              ],
+              [
+                121.671273,
+                39.010059
+              ],
+              [
+                121.73841,
+                38.998898
+              ],
+              [
+                121.756889,
+                39.025869
+              ],
+              [
+                121.790149,
+                39.022614
+              ],
+              [
+                121.804932,
+                38.970986
+              ],
+              [
+                121.863446,
+                38.942598
+              ],
+              [
+                121.920728,
+                38.969591
+              ],
+              [
+                121.905946,
+                38.997503
+              ],
+              [
+                121.852975,
+                39.035631
+              ],
+              [
+                121.8887,
+                39.027263
+              ],
+              [
+                121.929352,
+                39.024939
+              ],
+              [
+                121.907178,
+                39.055617
+              ],
+              [
+                121.923192,
+                39.053758
+              ],
+              [
+                121.963228,
+                39.030053
+              ],
+              [
+                122.013735,
+                39.073275
+              ],
+              [
+                122.061778,
+                39.060264
+              ],
+              [
+                122.071634,
+                39.074204
+              ],
+              [
+                122.048228,
+                39.101146
+              ],
+              [
+                122.088264,
+                39.112291
+              ],
+              [
+                122.127684,
+                39.144788
+              ],
+              [
+                122.167104,
+                39.158711
+              ],
+              [
+                122.123988,
+                39.172631
+              ],
+              [
+                122.117213,
+                39.213911
+              ],
+              [
+                122.160329,
+                39.238019
+              ],
+              [
+                122.242865,
+                39.267678
+              ],
+              [
+                122.274893,
+                39.322329
+              ],
+              [
+                122.30877,
+                39.346399
+              ],
+              [
+                122.366053,
+                39.370461
+              ],
+              [
+                122.412864,
+                39.411625
+              ],
+              [
+                122.455364,
+                39.408388
+              ],
+              [
+                122.467682,
+                39.403301
+              ],
+              [
+                122.51203,
+                39.413474
+              ],
+              [
+                122.532972,
+                39.419947
+              ],
+              [
+                122.581631,
+                39.464316
+              ],
+              [
+                122.637066,
+                39.488799
+              ],
+              [
+                122.649385,
+                39.516505
+              ],
+              [
+                122.682645,
+                39.514658
+              ],
+              [
+                122.808913,
+                39.559889
+              ],
+              [
+                122.847101,
+                39.581571
+              ],
+              [
+                122.860652,
+                39.604629
+              ],
+              [
+                122.941956,
+                39.604629
+              ],
+              [
+                122.972753,
+                39.594946
+              ],
+              [
+                122.978912,
+                39.616156
+              ],
+              [
+                123.021412,
+                39.64335
+              ],
+              [
+                123.010941,
+                39.655331
+              ],
+              [
+                123.103332,
+                39.676983
+              ],
+              [
+                123.146448,
+                39.647037
+              ],
+              [
+                123.166774,
+                39.674219
+              ],
+              [
+                123.212969,
+                39.665928
+              ],
+              [
+                123.215433,
+                39.696786
+              ],
+              [
+                123.253005,
+                39.689879
+              ],
+              [
+                123.286882,
+                39.704154
+              ],
+              [
+                123.270251,
+                39.714743
+              ],
+              [
+                123.274563,
+                39.753862
+              ],
+              [
+                123.350939,
+                39.750641
+              ],
+              [
+                123.388512,
+                39.74742
+              ],
+              [
+                123.392823,
+                39.723949
+              ],
+              [
+                123.477823,
+                39.74696
+              ],
+              [
+                123.521555,
+                39.772724
+              ],
+              [
+                123.534489,
+                39.788361
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.63953,
+                39.286209
+              ],
+              [
+                122.593334,
+                39.278334
+              ],
+              [
+                122.539131,
+                39.308439
+              ],
+              [
+                122.50895,
+                39.290377
+              ],
+              [
+                122.57732,
+                39.269994
+              ],
+              [
+                122.67895,
+                39.268605
+              ],
+              [
+                122.673406,
+                39.269531
+              ],
+              [
+                122.662935,
+                39.273701
+              ],
+              [
+                122.655544,
+                39.277407
+              ],
+              [
+                122.640761,
+                39.288061
+              ],
+              [
+                122.63953,
+                39.286209
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.318625,
+                39.170775
+              ],
+              [
+                122.345111,
+                39.144788
+              ],
+              [
+                122.366053,
+                39.174951
+              ],
+              [
+                122.398697,
+                39.16196
+              ],
+              [
+                122.383299,
+                39.190723
+              ],
+              [
+                122.393154,
+                39.213448
+              ],
+              [
+                122.343263,
+                39.203246
+              ],
+              [
+                122.322321,
+                39.177271
+              ],
+              [
+                122.322937,
+                39.174487
+              ],
+              [
+                122.319241,
+                39.172167
+              ],
+              [
+                122.318625,
+                39.170775
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.691884,
+                39.23292
+              ],
+              [
+                122.696812,
+                39.206492
+              ],
+              [
+                122.751631,
+                39.229675
+              ],
+              [
+                122.740544,
+                39.248679
+              ],
+              [
+                122.635834,
+                39.241727
+              ],
+              [
+                122.628443,
+                39.231993
+              ],
+              [
+                122.690037,
+                39.234774
+              ],
+              [
+                122.691268,
+                39.23431
+              ],
+              [
+                122.691884,
+                39.23292
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.738696,
+                39.034701
+              ],
+              [
+                122.704819,
+                39.044463
+              ],
+              [
+                122.733152,
+                39.014244
+              ],
+              [
+                122.75779,
+                39.009594
+              ],
+              [
+                122.739312,
+                39.036561
+              ],
+              [
+                122.738696,
+                39.034701
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.022644,
+                39.546507
+              ],
+              [
+                122.96105,
+                39.551122
+              ],
+              [
+                122.945035,
+                39.520198
+              ],
+              [
+                122.995542,
+                39.495264
+              ],
+              [
+                123.036194,
+                39.533123
+              ],
+              [
+                123.022644,
+                39.546507
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.503407,
+                39.241263
+              ],
+              [
+                122.502175,
+                39.224112
+              ],
+              [
+                122.547755,
+                39.229211
+              ],
+              [
+                122.503407,
+                39.241263
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.786784,
+                40.473787
+              ],
+              [
+                120.83298,
+                40.491995
+              ],
+              [
+                120.8299,
+                40.516112
+              ],
+              [
+                120.805262,
+                40.525666
+              ],
+              [
+                120.774465,
+                40.48016
+              ],
+              [
+                120.786784,
+                40.473787
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.086702,
+                39.426881
+              ],
+              [
+                123.090397,
+                39.450915
+              ],
+              [
+                123.054057,
+                39.457847
+              ],
+              [
+                123.086702,
+                39.426881
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.160614,
+                39.025404
+              ],
+              [
+                123.205578,
+                39.057011
+              ],
+              [
+                123.20065,
+                39.077921
+              ],
+              [
+                123.145832,
+                39.091857
+              ],
+              [
+                123.143984,
+                39.038885
+              ],
+              [
+                123.160614,
+                39.025404
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.716807,
+                39.74512
+              ],
+              [
+                123.756843,
+                39.754322
+              ],
+              [
+                123.719887,
+                39.763063
+              ],
+              [
+                123.716807,
+                39.74512
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 220000,
+        "name": "鍚夋灄鐪�",
+        "center": [
+          125.3245,
+          43.886841
+        ],
+        "centroid": [
+          126.171208,
+          43.703954
+        ],
+        "childrenNum": 9,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 6,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                129.601492,
+                42.415116
+              ],
+              [
+                129.601492,
+                42.422627
+              ],
+              [
+                129.591021,
+                42.447803
+              ],
+              [
+                129.627361,
+                42.462816
+              ],
+              [
+                129.651999,
+                42.426603
+              ],
+              [
+                129.704354,
+                42.427045
+              ],
+              [
+                129.748701,
+                42.471204
+              ],
+              [
+                129.738846,
+                42.500332
+              ],
+              [
+                129.749933,
+                42.546644
+              ],
+              [
+                129.746237,
+                42.58455
+              ],
+              [
+                129.786889,
+                42.615387
+              ],
+              [
+                129.754245,
+                42.645768
+              ],
+              [
+                129.796744,
+                42.681854
+              ],
+              [
+                129.767179,
+                42.707806
+              ],
+              [
+                129.78381,
+                42.762752
+              ],
+              [
+                129.810911,
+                42.795257
+              ],
+              [
+                129.816454,
+                42.851003
+              ],
+              [
+                129.835549,
+                42.866796
+              ],
+              [
+                129.846636,
+                42.918533
+              ],
+              [
+                129.874969,
+                42.923792
+              ],
+              [
+                129.856491,
+                42.951833
+              ],
+              [
+                129.868193,
+                42.97373
+              ],
+              [
+                129.903918,
+                42.968475
+              ],
+              [
+                129.897143,
+                43.001748
+              ],
+              [
+                129.954425,
+                43.010938
+              ],
+              [
+                129.963664,
+                42.978547
+              ],
+              [
+                130.002468,
+                42.981174
+              ],
+              [
+                130.027106,
+                42.9676
+              ],
+              [
+                130.072685,
+                42.971541
+              ],
+              [
+                130.10841,
+                42.989929
+              ],
+              [
+                130.144134,
+                42.976357
+              ],
+              [
+                130.120729,
+                42.954461
+              ],
+              [
+                130.127504,
+                42.932556
+              ],
+              [
+                130.10225,
+                42.922916
+              ],
+              [
+                130.136127,
+                42.90363
+              ],
+              [
+                130.17062,
+                42.912397
+              ],
+              [
+                130.21004,
+                42.902315
+              ],
+              [
+                130.258083,
+                42.90626
+              ],
+              [
+                130.277793,
+                42.892232
+              ],
+              [
+                130.258083,
+                42.860655
+              ],
+              [
+                130.245148,
+                42.799209
+              ],
+              [
+                130.242069,
+                42.738582
+              ],
+              [
+                130.257467,
+                42.710884
+              ],
+              [
+                130.290112,
+                42.702968
+              ],
+              [
+                130.333228,
+                42.64973
+              ],
+              [
+                130.373264,
+                42.630799
+              ],
+              [
+                130.388046,
+                42.603054
+              ],
+              [
+                130.420691,
+                42.617148
+              ],
+              [
+                130.44656,
+                42.607459
+              ],
+              [
+                130.423771,
+                42.574855
+              ],
+              [
+                130.435474,
+                42.553257
+              ],
+              [
+                130.476125,
+                42.570007
+              ],
+              [
+                130.459495,
+                42.588075
+              ],
+              [
+                130.482285,
+                42.626837
+              ],
+              [
+                130.522937,
+                42.622433
+              ],
+              [
+                130.520473,
+                42.593362
+              ],
+              [
+                130.558661,
+                42.495919
+              ],
+              [
+                130.585763,
+                42.485328
+              ],
+              [
+                130.581451,
+                42.435437
+              ],
+              [
+                130.645509,
+                42.426603
+              ],
+              [
+                130.600545,
+                42.450453
+              ],
+              [
+                130.599929,
+                42.486211
+              ],
+              [
+                130.565437,
+                42.506509
+              ],
+              [
+                130.570364,
+                42.557224
+              ],
+              [
+                130.622719,
+                42.573092
+              ],
+              [
+                130.633806,
+                42.603494
+              ],
+              [
+                130.592538,
+                42.671295
+              ],
+              [
+                130.521089,
+                42.702089
+              ],
+              [
+                130.464423,
+                42.688453
+              ],
+              [
+                130.425003,
+                42.706926
+              ],
+              [
+                130.40714,
+                42.731548
+              ],
+              [
+                130.46627,
+                42.772417
+              ],
+              [
+                130.532792,
+                42.787352
+              ],
+              [
+                130.562357,
+                42.815015
+              ],
+              [
+                130.603625,
+                42.819405
+              ],
+              [
+                130.665835,
+                42.847932
+              ],
+              [
+                130.708335,
+                42.846615
+              ],
+              [
+                130.719422,
+                42.831695
+              ],
+              [
+                130.75453,
+                42.845738
+              ],
+              [
+                130.784095,
+                42.842227
+              ],
+              [
+                130.801957,
+                42.879515
+              ],
+              [
+                130.845073,
+                42.881269
+              ],
+              [
+                130.890653,
+                42.852758
+              ],
+              [
+                130.912826,
+                42.870744
+              ],
+              [
+                130.949783,
+                42.876884
+              ],
+              [
+                130.981812,
+                42.857145
+              ],
+              [
+                131.043406,
+                42.862848
+              ],
+              [
+                131.017536,
+                42.915027
+              ],
+              [
+                131.034167,
+                42.929051
+              ],
+              [
+                131.114855,
+                42.915027
+              ],
+              [
+                131.145652,
+                42.9365
+              ],
+              [
+                131.151195,
+                42.968475
+              ],
+              [
+                131.115471,
+                42.975482
+              ],
+              [
+                131.11855,
+                43.007875
+              ],
+              [
+                131.102536,
+                43.021002
+              ],
+              [
+                131.120398,
+                43.068238
+              ],
+              [
+                131.171521,
+                43.06955
+              ],
+              [
+                131.173985,
+                43.111506
+              ],
+              [
+                131.207861,
+                43.1316
+              ],
+              [
+                131.218948,
+                43.191405
+              ],
+              [
+                131.201086,
+                43.203185
+              ],
+              [
+                131.206014,
+                43.237202
+              ],
+              [
+                131.255289,
+                43.265099
+              ],
+              [
+                131.269455,
+                43.297775
+              ],
+              [
+                131.275615,
+                43.369165
+              ],
+              [
+                131.314419,
+                43.392653
+              ],
+              [
+                131.295941,
+                43.441774
+              ],
+              [
+                131.314419,
+                43.461325
+              ],
+              [
+                131.31873,
+                43.499539
+              ],
+              [
+                131.304564,
+                43.502144
+              ],
+              [
+                131.294093,
+                43.470012
+              ],
+              [
+                131.234963,
+                43.475224
+              ],
+              [
+                131.201086,
+                43.442209
+              ],
+              [
+                131.175217,
+                43.444816
+              ],
+              [
+                131.142572,
+                43.425695
+              ],
+              [
+                131.026775,
+                43.508655
+              ],
+              [
+                130.959638,
+                43.48608
+              ],
+              [
+                130.907283,
+                43.434387
+              ],
+              [
+                130.864167,
+                43.437863
+              ],
+              [
+                130.841378,
+                43.454374
+              ],
+              [
+                130.822899,
+                43.503446
+              ],
+              [
+                130.776704,
+                43.52341
+              ],
+              [
+                130.727429,
+                43.560284
+              ],
+              [
+                130.671378,
+                43.565054
+              ],
+              [
+                130.665835,
+                43.583698
+              ],
+              [
+                130.623335,
+                43.589767
+              ],
+              [
+                130.630726,
+                43.622268
+              ],
+              [
+                130.57098,
+                43.626167
+              ],
+              [
+                130.57098,
+                43.626167
+              ],
+              [
+                130.501995,
+                43.636563
+              ],
+              [
+                130.488444,
+                43.65605
+              ],
+              [
+                130.437937,
+                43.646091
+              ],
+              [
+                130.412684,
+                43.652586
+              ],
+              [
+                130.394206,
+                43.703227
+              ],
+              [
+                130.423155,
+                43.745179
+              ],
+              [
+                130.382503,
+                43.777164
+              ],
+              [
+                130.381887,
+                43.817768
+              ],
+              [
+                130.362793,
+                43.844967
+              ],
+              [
+                130.386198,
+                43.85403
+              ],
+              [
+                130.368336,
+                43.894151
+              ],
+              [
+                130.381887,
+                43.910106
+              ],
+              [
+                130.338155,
+                43.963975
+              ],
+              [
+                130.364025,
+                43.992399
+              ],
+              [
+                130.365256,
+                44.044042
+              ],
+              [
+                130.319061,
+                44.03974
+              ],
+              [
+                130.307358,
+                44.002731
+              ],
+              [
+                130.27225,
+                43.981634
+              ],
+              [
+                130.262395,
+                43.949328
+              ],
+              [
+                130.208192,
+                43.948466
+              ],
+              [
+                130.153373,
+                43.915711
+              ],
+              [
+                130.143518,
+                43.878624
+              ],
+              [
+                130.116417,
+                43.878192
+              ],
+              [
+                130.110873,
+                43.852735
+              ],
+              [
+                130.079461,
+                43.835039
+              ],
+              [
+                130.027722,
+                43.851872
+              ],
+              [
+                130.009243,
+                43.889407
+              ],
+              [
+                130.022794,
+                43.917866
+              ],
+              [
+                130.017867,
+                43.961821
+              ],
+              [
+                129.979062,
+                44.015644
+              ],
+              [
+                129.951345,
+                44.027263
+              ],
+              [
+                129.907614,
+                44.023821
+              ],
+              [
+                129.881128,
+                44.000148
+              ],
+              [
+                129.868193,
+                44.012631
+              ],
+              [
+                129.802904,
+                43.964837
+              ],
+              [
+                129.780114,
+                43.892857
+              ],
+              [
+                129.739462,
+                43.895876
+              ],
+              [
+                129.743158,
+                43.876035
+              ],
+              [
+                129.699426,
+                43.8838
+              ],
+              [
+                129.650767,
+                43.873016
+              ],
+              [
+                129.529427,
+                43.870427
+              ],
+              [
+                129.467833,
+                43.874741
+              ],
+              [
+                129.449971,
+                43.850578
+              ],
+              [
+                129.417942,
+                43.843672
+              ],
+              [
+                129.406855,
+                43.819496
+              ],
+              [
+                129.348341,
+                43.798333
+              ],
+              [
+                129.30892,
+                43.812155
+              ],
+              [
+                129.289826,
+                43.797038
+              ],
+              [
+                129.254718,
+                43.819496
+              ],
+              [
+                129.211602,
+                43.784509
+              ],
+              [
+                129.232544,
+                43.709284
+              ],
+              [
+                129.214066,
+                43.695006
+              ],
+              [
+                129.217146,
+                43.648689
+              ],
+              [
+                129.232544,
+                43.635263
+              ],
+              [
+                129.23008,
+                43.593234
+              ],
+              [
+                129.169102,
+                43.561585
+              ],
+              [
+                129.145081,
+                43.570258
+              ],
+              [
+                129.093958,
+                43.547706
+              ],
+              [
+                129.037907,
+                43.540332
+              ],
+              [
+                129.013886,
+                43.522976
+              ],
+              [
+                128.962763,
+                43.53903
+              ],
+              [
+                128.949828,
+                43.553779
+              ],
+              [
+                128.878379,
+                43.539898
+              ],
+              [
+                128.834647,
+                43.587599
+              ],
+              [
+                128.821097,
+                43.637429
+              ],
+              [
+                128.78722,
+                43.686784
+              ],
+              [
+                128.768126,
+                43.732207
+              ],
+              [
+                128.729322,
+                43.736964
+              ],
+              [
+                128.760119,
+                43.755554
+              ],
+              [
+                128.739177,
+                43.806972
+              ],
+              [
+                128.719467,
+                43.816905
+              ],
+              [
+                128.760734,
+                43.857482
+              ],
+              [
+                128.729938,
+                43.889838
+              ],
+              [
+                128.696061,
+                43.903207
+              ],
+              [
+                128.636315,
+                43.891132
+              ],
+              [
+                128.64001,
+                43.948035
+              ],
+              [
+                128.610445,
+                43.960529
+              ],
+              [
+                128.584576,
+                43.990246
+              ],
+              [
+                128.574721,
+                44.047914
+              ],
+              [
+                128.529141,
+                44.112401
+              ],
+              [
+                128.471859,
+                44.157501
+              ],
+              [
+                128.450301,
+                44.203423
+              ],
+              [
+                128.471859,
+                44.247596
+              ],
+              [
+                128.453997,
+                44.257884
+              ],
+              [
+                128.472475,
+                44.320001
+              ],
+              [
+                128.446605,
+                44.339694
+              ],
+              [
+                128.475555,
+                44.346114
+              ],
+              [
+                128.481714,
+                44.375637
+              ],
+              [
+                128.457076,
+                44.409848
+              ],
+              [
+                128.463236,
+                44.431647
+              ],
+              [
+                128.427511,
+                44.473512
+              ],
+              [
+                128.397946,
+                44.483761
+              ],
+              [
+                128.372693,
+                44.514495
+              ],
+              [
+                128.295084,
+                44.480772
+              ],
+              [
+                128.293237,
+                44.467961
+              ],
+              [
+                128.228563,
+                44.445748
+              ],
+              [
+                128.211317,
+                44.431647
+              ],
+              [
+                128.172512,
+                44.34697
+              ],
+              [
+                128.137404,
+                44.357668
+              ],
+              [
+                128.094904,
+                44.354673
+              ],
+              [
+                128.074578,
+                44.370075
+              ],
+              [
+                128.049941,
+                44.349965
+              ],
+              [
+                128.065339,
+                44.307155
+              ],
+              [
+                128.101679,
+                44.293449
+              ],
+              [
+                128.064107,
+                44.251454
+              ],
+              [
+                128.104143,
+                44.230017
+              ],
+              [
+                128.09244,
+                44.181539
+              ],
+              [
+                128.060411,
+                44.168663
+              ],
+              [
+                128.088129,
+                44.158359
+              ],
+              [
+                128.091208,
+                44.133022
+              ],
+              [
+                128.042549,
+                44.103807
+              ],
+              [
+                127.950158,
+                44.088334
+              ],
+              [
+                127.912586,
+                44.064687
+              ],
+              [
+                127.862695,
+                44.062967
+              ],
+              [
+                127.846065,
+                44.081886
+              ],
+              [
+                127.808492,
+                44.086615
+              ],
+              [
+                127.783239,
+                44.071997
+              ],
+              [
+                127.729036,
+                44.09908
+              ],
+              [
+                127.735811,
+                44.11412
+              ],
+              [
+                127.712406,
+                44.199133
+              ],
+              [
+                127.681609,
+                44.166946
+              ],
+              [
+                127.641573,
+                44.193555
+              ],
+              [
+                127.626174,
+                44.187977
+              ],
+              [
+                127.59045,
+                44.227872
+              ],
+              [
+                127.623711,
+                44.278025
+              ],
+              [
+                127.579363,
+                44.310581
+              ],
+              [
+                127.486356,
+                44.410275
+              ],
+              [
+                127.50853,
+                44.437202
+              ],
+              [
+                127.463566,
+                44.484615
+              ],
+              [
+                127.465414,
+                44.516628
+              ],
+              [
+                127.485124,
+                44.528576
+              ],
+              [
+                127.536247,
+                44.522176
+              ],
+              [
+                127.570124,
+                44.55033
+              ],
+              [
+                127.557189,
+                44.575488
+              ],
+              [
+                127.392733,
+                44.632158
+              ],
+              [
+                127.275705,
+                44.640249
+              ],
+              [
+                127.261538,
+                44.61299
+              ],
+              [
+                127.214111,
+                44.624917
+              ],
+              [
+                127.228893,
+                44.642804
+              ],
+              [
+                127.182082,
+                44.644507
+              ],
+              [
+                127.138966,
+                44.607451
+              ],
+              [
+                127.094619,
+                44.615972
+              ],
+              [
+                127.089691,
+                44.593816
+              ],
+              [
+                127.049655,
+                44.566961
+              ],
+              [
+                127.041648,
+                44.591258
+              ],
+              [
+                127.044112,
+                44.653874
+              ],
+              [
+                127.030561,
+                44.673454
+              ],
+              [
+                127.041032,
+                44.712169
+              ],
+              [
+                126.9973,
+                44.764882
+              ],
+              [
+                126.984366,
+                44.823914
+              ],
+              [
+                126.999764,
+                44.87398
+              ],
+              [
+                127.021938,
+                44.898997
+              ],
+              [
+                127.073061,
+                44.907051
+              ],
+              [
+                127.092771,
+                44.94688
+              ],
+              [
+                127.050271,
+                45.004034
+              ],
+              [
+                127.018242,
+                45.024341
+              ],
+              [
+                126.984981,
+                45.067893
+              ],
+              [
+                126.970815,
+                45.070852
+              ],
+              [
+                126.96404,
+                45.132104
+              ],
+              [
+                126.85625,
+                45.145613
+              ],
+              [
+                126.792808,
+                45.135481
+              ],
+              [
+                126.787265,
+                45.159118
+              ],
+              [
+                126.732446,
+                45.187385
+              ],
+              [
+                126.685635,
+                45.187807
+              ],
+              [
+                126.640055,
+                45.214373
+              ],
+              [
+                126.644983,
+                45.225334
+              ],
+              [
+                126.569222,
+                45.252725
+              ],
+              [
+                126.540273,
+                45.23882
+              ],
+              [
+                126.519331,
+                45.248091
+              ],
+              [
+                126.402919,
+                45.222805
+              ],
+              [
+                126.356107,
+                45.185698
+              ],
+              [
+                126.293282,
+                45.180214
+              ],
+              [
+                126.285274,
+                45.162494
+              ],
+              [
+                126.235383,
+                45.140125
+              ],
+              [
+                126.225528,
+                45.154054
+              ],
+              [
+                126.166398,
+                45.13337
+              ],
+              [
+                126.142992,
+                45.147723
+              ],
+              [
+                126.091869,
+                45.149411
+              ],
+              [
+                126.047522,
+                45.170933
+              ],
+              [
+                125.998247,
+                45.162072
+              ],
+              [
+                125.992703,
+                45.192447
+              ],
+              [
+                125.957595,
+                45.201303
+              ],
+              [
+                125.915095,
+                45.196664
+              ],
+              [
+                125.849805,
+                45.23882
+              ],
+              [
+                125.823936,
+                45.237978
+              ],
+              [
+                125.815929,
+                45.264942
+              ],
+              [
+                125.761726,
+                45.291472
+              ],
+              [
+                125.726001,
+                45.336503
+              ],
+              [
+                125.695205,
+                45.352066
+              ],
+              [
+                125.712451,
+                45.389485
+              ],
+              [
+                125.711835,
+                45.477677
+              ],
+              [
+                125.687813,
+                45.514173
+              ],
+              [
+                125.660096,
+                45.507043
+              ],
+              [
+                125.61698,
+                45.517947
+              ],
+              [
+                125.583104,
+                45.491942
+              ],
+              [
+                125.497488,
+                45.469283
+              ],
+              [
+                125.480242,
+                45.486488
+              ],
+              [
+                125.424807,
+                45.485649
+              ],
+              [
+                125.434662,
+                45.462988
+              ],
+              [
+                125.398322,
+                45.416797
+              ],
+              [
+                125.361981,
+                45.392847
+              ],
+              [
+                125.319482,
+                45.422678
+              ],
+              [
+                125.301619,
+                45.402092
+              ],
+              [
+                125.248649,
+                45.417637
+              ],
+              [
+                125.189518,
+                45.39915
+              ],
+              [
+                125.137779,
+                45.409655
+              ],
+              [
+                125.097127,
+                45.38276
+              ],
+              [
+                125.06633,
+                45.39915
+              ],
+              [
+                125.08912,
+                45.420998
+              ],
+              [
+                125.0497,
+                45.428558
+              ],
+              [
+                125.025678,
+                45.493201
+              ],
+              [
+                124.961005,
+                45.495299
+              ],
+              [
+                124.936983,
+                45.53388
+              ],
+              [
+                124.911114,
+                45.535976
+              ],
+              [
+                124.884628,
+                45.495299
+              ],
+              [
+                124.886476,
+                45.442836
+              ],
+              [
+                124.839665,
+                45.455852
+              ],
+              [
+                124.792853,
+                45.436958
+              ],
+              [
+                124.776223,
+                45.468024
+              ],
+              [
+                124.729412,
+                45.444096
+              ],
+              [
+                124.690607,
+                45.452493
+              ],
+              [
+                124.625318,
+                45.437377
+              ],
+              [
+                124.575427,
+                45.451234
+              ],
+              [
+                124.579738,
+                45.424358
+              ],
+              [
+                124.544014,
+                45.411756
+              ],
+              [
+                124.507058,
+                45.424778
+              ],
+              [
+                124.480572,
+                45.456271
+              ],
+              [
+                124.398652,
+                45.440737
+              ],
+              [
+                124.374015,
+                45.45795
+              ],
+              [
+                124.352457,
+                45.496557
+              ],
+              [
+                124.369087,
+                45.512915
+              ],
+              [
+                124.348761,
+                45.546874
+              ],
+              [
+                124.287783,
+                45.539329
+              ],
+              [
+                124.264377,
+                45.555256
+              ],
+              [
+                124.273001,
+                45.584163
+              ],
+              [
+                124.238508,
+                45.591702
+              ],
+              [
+                124.226805,
+                45.633564
+              ],
+              [
+                124.162132,
+                45.616404
+              ],
+              [
+                124.128255,
+                45.641933
+              ],
+              [
+                124.147349,
+                45.665359
+              ],
+              [
+                124.122096,
+                45.669123
+              ],
+              [
+                124.13503,
+                45.690448
+              ],
+              [
+                124.10177,
+                45.700898
+              ],
+              [
+                124.098074,
+                45.722628
+              ],
+              [
+                124.054342,
+                45.751449
+              ],
+              [
+                124.014922,
+                45.749779
+              ],
+              [
+                124.001987,
+                45.770655
+              ],
+              [
+                124.064197,
+                45.802372
+              ],
+              [
+                124.03648,
+                45.83824
+              ],
+              [
+                124.067277,
+                45.840325
+              ],
+              [
+                124.061118,
+                45.886168
+              ],
+              [
+                123.996444,
+                45.906993
+              ],
+              [
+                123.968727,
+                45.936551
+              ],
+              [
+                123.973654,
+                45.973997
+              ],
+              [
+                124.011842,
+                45.981899
+              ],
+              [
+                123.989053,
+                46.011833
+              ],
+              [
+                124.040176,
+                46.01973
+              ],
+              [
+                124.034016,
+                46.045074
+              ],
+              [
+                124.009995,
+                46.057534
+              ],
+              [
+                124.015538,
+                46.088257
+              ],
+              [
+                123.99398,
+                46.101123
+              ],
+              [
+                124.01677,
+                46.118549
+              ],
+              [
+                123.991516,
+                46.143019
+              ],
+              [
+                124.001987,
+                46.166649
+              ],
+              [
+                123.971806,
+                46.170379
+              ],
+              [
+                123.956408,
+                46.206009
+              ],
+              [
+                123.979814,
+                46.228784
+              ],
+              [
+                123.952096,
+                46.256516
+              ],
+              [
+                123.960103,
+                46.288369
+              ],
+              [
+                123.936082,
+                46.286715
+              ],
+              [
+                123.917604,
+                46.25693
+              ],
+              [
+                123.896046,
+                46.303668
+              ],
+              [
+                123.84985,
+                46.302428
+              ],
+              [
+                123.775938,
+                46.263136
+              ],
+              [
+                123.726047,
+                46.255688
+              ],
+              [
+                123.673692,
+                46.258585
+              ],
+              [
+                123.604706,
+                46.251964
+              ],
+              [
+                123.569598,
+                46.223816
+              ],
+              [
+                123.569598,
+                46.223816
+              ],
+              [
+                123.499381,
+                46.259826
+              ],
+              [
+                123.452569,
+                46.233338
+              ],
+              [
+                123.430396,
+                46.243687
+              ],
+              [
+                123.357099,
+                46.232096
+              ],
+              [
+                123.357099,
+                46.232096
+              ],
+              [
+                123.320758,
+                46.254447
+              ],
+              [
+                123.286266,
+                46.250308
+              ],
+              [
+                123.248078,
+                46.273065
+              ],
+              [
+                123.178476,
+                46.248239
+              ],
+              [
+                123.128585,
+                46.210565
+              ],
+              [
+                123.127354,
+                46.174523
+              ],
+              [
+                123.102716,
+                46.172037
+              ],
+              [
+                123.112571,
+                46.130163
+              ],
+              [
+                123.070071,
+                46.123527
+              ],
+              [
+                123.04605,
+                46.099878
+              ],
+              [
+                122.792898,
+                46.073313
+              ],
+              [
+                122.828623,
+                45.912406
+              ],
+              [
+                122.80029,
+                45.856583
+              ],
+              [
+                122.772572,
+                45.856583
+              ],
+              [
+                122.752246,
+                45.834905
+              ],
+              [
+                122.792283,
+                45.766063
+              ],
+              [
+                122.751015,
+                45.735996
+              ],
+              [
+                122.741775,
+                45.705077
+              ],
+              [
+                122.671558,
+                45.70048
+              ],
+              [
+                122.650001,
+                45.731401
+              ],
+              [
+                122.640761,
+                45.771072
+              ],
+              [
+                122.603189,
+                45.778169
+              ],
+              [
+                122.556378,
+                45.82156
+              ],
+              [
+                122.522501,
+                45.786933
+              ],
+              [
+                122.504639,
+                45.786933
+              ],
+              [
+                122.496016,
+                45.85825
+              ],
+              [
+                122.446125,
+                45.916986
+              ],
+              [
+                122.362357,
+                45.917403
+              ],
+              [
+                122.372828,
+                45.856166
+              ],
+              [
+                122.337719,
+                45.859917
+              ],
+              [
+                122.301379,
+                45.813218
+              ],
+              [
+                122.253952,
+                45.7982
+              ],
+              [
+                122.236705,
+                45.831569
+              ],
+              [
+                122.200981,
+                45.857
+              ],
+              [
+                122.091344,
+                45.882002
+              ],
+              [
+                122.085184,
+                45.912406
+              ],
+              [
+                122.040221,
+                45.959022
+              ],
+              [
+                121.92812,
+                45.988552
+              ],
+              [
+                121.923808,
+                46.004767
+              ],
+              [
+                121.864062,
+                46.002272
+              ],
+              [
+                121.843736,
+                46.024301
+              ],
+              [
+                121.819098,
+                46.023054
+              ],
+              [
+                121.761816,
+                45.998947
+              ],
+              [
+                121.809243,
+                45.961102
+              ],
+              [
+                121.821562,
+                45.918235
+              ],
+              [
+                121.805548,
+                45.900746
+              ],
+              [
+                121.817251,
+                45.875336
+              ],
+              [
+                121.769823,
+                45.84366
+              ],
+              [
+                121.766744,
+                45.830318
+              ],
+              [
+                121.766744,
+                45.830318
+              ],
+              [
+                121.754425,
+                45.794862
+              ],
+              [
+                121.697142,
+                45.76314
+              ],
+              [
+                121.657106,
+                45.770238
+              ],
+              [
+                121.644172,
+                45.752284
+              ],
+              [
+                121.666345,
+                45.727641
+              ],
+              [
+                121.713773,
+                45.701734
+              ],
+              [
+                121.811091,
+                45.687103
+              ],
+              [
+                121.812323,
+                45.704659
+              ],
+              [
+                121.867142,
+                45.719703
+              ],
+              [
+                121.934279,
+                45.71051
+              ],
+              [
+                121.970004,
+                45.692956
+              ],
+              [
+                122.003264,
+                45.623102
+              ],
+              [
+                121.995873,
+                45.59882
+              ],
+              [
+                121.966308,
+                45.596308
+              ],
+              [
+                121.993409,
+                45.552741
+              ],
+              [
+                122.002648,
+                45.507882
+              ],
+              [
+                122.064242,
+                45.472641
+              ],
+              [
+                122.168336,
+                45.439897
+              ],
+              [
+                122.180039,
+                45.409655
+              ],
+              [
+                122.146778,
+                45.374352
+              ],
+              [
+                122.147394,
+                45.295682
+              ],
+              [
+                122.239169,
+                45.276313
+              ],
+              [
+                122.22993,
+                45.206784
+              ],
+              [
+                122.192358,
+                45.180636
+              ],
+              [
+                122.143082,
+                45.183167
+              ],
+              [
+                122.109822,
+                45.142236
+              ],
+              [
+                122.119677,
+                45.068739
+              ],
+              [
+                122.098735,
+                45.02138
+              ],
+              [
+                122.074713,
+                45.006573
+              ],
+              [
+                122.087032,
+                44.95281
+              ],
+              [
+                122.079025,
+                44.914256
+              ],
+              [
+                122.04946,
+                44.912985
+              ],
+              [
+                122.098119,
+                44.81882
+              ],
+              [
+                122.099967,
+                44.7823
+              ],
+              [
+                122.168952,
+                44.770405
+              ],
+              [
+                122.142467,
+                44.753833
+              ],
+              [
+                122.110438,
+                44.767856
+              ],
+              [
+                122.10243,
+                44.736406
+              ],
+              [
+                122.152322,
+                44.744057
+              ],
+              [
+                122.161561,
+                44.728328
+              ],
+              [
+                122.117213,
+                44.701961
+              ],
+              [
+                122.103046,
+                44.67388
+              ],
+              [
+                122.113517,
+                44.615546
+              ],
+              [
+                122.13138,
+                44.577619
+              ],
+              [
+                122.196053,
+                44.559712
+              ],
+              [
+                122.224386,
+                44.526016
+              ],
+              [
+                122.228082,
+                44.480345
+              ],
+              [
+                122.28598,
+                44.477783
+              ],
+              [
+                122.294604,
+                44.41113
+              ],
+              [
+                122.291524,
+                44.310152
+              ],
+              [
+                122.271198,
+                44.255741
+              ],
+              [
+                122.319241,
+                44.233018
+              ],
+              [
+                122.483081,
+                44.236877
+              ],
+              [
+                122.515726,
+                44.251025
+              ],
+              [
+                122.641993,
+                44.283595
+              ],
+              [
+                122.675254,
+                44.285738
+              ],
+              [
+                122.702971,
+                44.319145
+              ],
+              [
+                122.76087,
+                44.369648
+              ],
+              [
+                122.85634,
+                44.398304
+              ],
+              [
+                123.025108,
+                44.493153
+              ],
+              [
+                123.06576,
+                44.505959
+              ],
+              [
+                123.12489,
+                44.5098
+              ],
+              [
+                123.137209,
+                44.486322
+              ],
+              [
+                123.125506,
+                44.455147
+              ],
+              [
+                123.142136,
+                44.428228
+              ],
+              [
+                123.114419,
+                44.40258
+              ],
+              [
+                123.128585,
+                44.367081
+              ],
+              [
+                123.196955,
+                44.34483
+              ],
+              [
+                123.277027,
+                44.25274
+              ],
+              [
+                123.286882,
+                44.211574
+              ],
+              [
+                123.323838,
+                44.179823
+              ],
+              [
+                123.386664,
+                44.161794
+              ],
+              [
+                123.362642,
+                44.133452
+              ],
+              [
+                123.350939,
+                44.092633
+              ],
+              [
+                123.32815,
+                44.084035
+              ],
+              [
+                123.331229,
+                44.028984
+              ],
+              [
+                123.365722,
+                44.013922
+              ],
+              [
+                123.400831,
+                43.979481
+              ],
+              [
+                123.37065,
+                43.970006
+              ],
+              [
+                123.397135,
+                43.954929
+              ],
+              [
+                123.467968,
+                43.853599
+              ],
+              [
+                123.461809,
+                43.822518
+              ],
+              [
+                123.498149,
+                43.771114
+              ],
+              [
+                123.48275,
+                43.737396
+              ],
+              [
+                123.520323,
+                43.708419
+              ],
+              [
+                123.518475,
+                43.682024
+              ],
+              [
+                123.536953,
+                43.633964
+              ],
+              [
+                123.510468,
+                43.624867
+              ],
+              [
+                123.5117,
+                43.592801
+              ],
+              [
+                123.421157,
+                43.598435
+              ],
+              [
+                123.434091,
+                43.575461
+              ],
+              [
+                123.461193,
+                43.568523
+              ],
+              [
+                123.452569,
+                43.545971
+              ],
+              [
+                123.452569,
+                43.545971
+              ],
+              [
+                123.360179,
+                43.567223
+              ],
+              [
+                123.304744,
+                43.550742
+              ],
+              [
+                123.329998,
+                43.519071
+              ],
+              [
+                123.315831,
+                43.492159
+              ],
+              [
+                123.36449,
+                43.483475
+              ],
+              [
+                123.382968,
+                43.469143
+              ],
+              [
+                123.419925,
+                43.410046
+              ],
+              [
+                123.442098,
+                43.437863
+              ],
+              [
+                123.486446,
+                43.44525
+              ],
+              [
+                123.519707,
+                43.402219
+              ],
+              [
+                123.54496,
+                43.415262
+              ],
+              [
+                123.608402,
+                43.366119
+              ],
+              [
+                123.703873,
+                43.37047
+              ],
+              [
+                123.710032,
+                43.417001
+              ],
+              [
+                123.749452,
+                43.439167
+              ],
+              [
+                123.747604,
+                43.472184
+              ],
+              [
+                123.79688,
+                43.489988
+              ],
+              [
+                123.857858,
+                43.459153
+              ],
+              [
+                123.857858,
+                43.459153
+              ],
+              [
+                123.852314,
+                43.406133
+              ],
+              [
+                123.881263,
+                43.392218
+              ],
+              [
+                123.881263,
+                43.392218
+              ],
+              [
+                123.896046,
+                43.361333
+              ],
+              [
+                123.964415,
+                43.34088
+              ],
+              [
+                124.032784,
+                43.280786
+              ],
+              [
+                124.099306,
+                43.292983
+              ],
+              [
+                124.117168,
+                43.2773
+              ],
+              [
+                124.114088,
+                43.247229
+              ],
+              [
+                124.168291,
+                43.244177
+              ],
+              [
+                124.215102,
+                43.255947
+              ],
+              [
+                124.228653,
+                43.235022
+              ],
+              [
+                124.27608,
+                43.233278
+              ],
+              [
+                124.287167,
+                43.207983
+              ],
+              [
+                124.273617,
+                43.17875
+              ],
+              [
+                124.366007,
+                43.121554
+              ],
+              [
+                124.425754,
+                43.076107
+              ],
+              [
+                124.333363,
+                42.997371
+              ],
+              [
+                124.369703,
+                42.972854
+              ],
+              [
+                124.42329,
+                42.975482
+              ],
+              [
+                124.442384,
+                42.958841
+              ],
+              [
+                124.431913,
+                42.930803
+              ],
+              [
+                124.38079,
+                42.912835
+              ],
+              [
+                124.371551,
+                42.880831
+              ],
+              [
+                124.435609,
+                42.880831
+              ],
+              [
+                124.466406,
+                42.847054
+              ],
+              [
+                124.586514,
+                42.905384
+              ],
+              [
+                124.607456,
+                42.937376
+              ],
+              [
+                124.632093,
+                42.949642
+              ],
+              [
+                124.635173,
+                42.972854
+              ],
+              [
+                124.658579,
+                42.972854
+              ],
+              [
+                124.677673,
+                43.002185
+              ],
+              [
+                124.686912,
+                43.051185
+              ],
+              [
+                124.719557,
+                43.069987
+              ],
+              [
+                124.755281,
+                43.074359
+              ],
+              [
+                124.785462,
+                43.117185
+              ],
+              [
+                124.882781,
+                43.13422
+              ],
+              [
+                124.88894,
+                43.074796
+              ],
+              [
+                124.840897,
+                43.032377
+              ],
+              [
+                124.869846,
+                42.988178
+              ],
+              [
+                124.87231,
+                42.962344
+              ],
+              [
+                124.84952,
+                42.882585
+              ],
+              [
+                124.856911,
+                42.824234
+              ],
+              [
+                124.874157,
+                42.789987
+              ],
+              [
+                124.897563,
+                42.787791
+              ],
+              [
+                124.92836,
+                42.819844
+              ],
+              [
+                124.975171,
+                42.802722
+              ],
+              [
+                124.996729,
+                42.745174
+              ],
+              [
+                124.968396,
+                42.722756
+              ],
+              [
+                124.99057,
+                42.677455
+              ],
+              [
+                125.014592,
+                42.666014
+              ],
+              [
+                125.010896,
+                42.63212
+              ],
+              [
+                125.038613,
+                42.615387
+              ],
+              [
+                125.097127,
+                42.622433
+              ],
+              [
+                125.082961,
+                42.591159
+              ],
+              [
+                125.089736,
+                42.567803
+              ],
+              [
+                125.066946,
+                42.534738
+              ],
+              [
+                125.090968,
+                42.515773
+              ],
+              [
+                125.068794,
+                42.499449
+              ],
+              [
+                125.105135,
+                42.490624
+              ],
+              [
+                125.150098,
+                42.458842
+              ],
+              [
+                125.140243,
+                42.44692
+              ],
+              [
+                125.186439,
+                42.427928
+              ],
+              [
+                125.185823,
+                42.38197
+              ],
+              [
+                125.203685,
+                42.366938
+              ],
+              [
+                125.167345,
+                42.351903
+              ],
+              [
+                125.175352,
+                42.308102
+              ],
+              [
+                125.224011,
+                42.30102
+              ],
+              [
+                125.264047,
+                42.312528
+              ],
+              [
+                125.299156,
+                42.289953
+              ],
+              [
+                125.27575,
+                42.266928
+              ],
+              [
+                125.27575,
+                42.231045
+              ],
+              [
+                125.312706,
+                42.219966
+              ],
+              [
+                125.280677,
+                42.175187
+              ],
+              [
+                125.312706,
+                42.197359
+              ],
+              [
+                125.305931,
+                42.146351
+              ],
+              [
+                125.357054,
+                42.145464
+              ],
+              [
+                125.368141,
+                42.182726
+              ],
+              [
+                125.41372,
+                42.156112
+              ],
+              [
+                125.458068,
+                42.160105
+              ],
+              [
+                125.458068,
+                42.160105
+              ],
+              [
+                125.490097,
+                42.136145
+              ],
+              [
+                125.446365,
+                42.098411
+              ],
+              [
+                125.414336,
+                42.101964
+              ],
+              [
+                125.416184,
+                42.063766
+              ],
+              [
+                125.363213,
+                42.017097
+              ],
+              [
+                125.369989,
+                42.002868
+              ],
+              [
+                125.29854,
+                41.974399
+              ],
+              [
+                125.291764,
+                41.958825
+              ],
+              [
+                125.35151,
+                41.92811
+              ],
+              [
+                125.307779,
+                41.924548
+              ],
+              [
+                125.294844,
+                41.822945
+              ],
+              [
+                125.319482,
+                41.776993
+              ],
+              [
+                125.319482,
+                41.776993
+              ],
+              [
+                125.323177,
+                41.771191
+              ],
+              [
+                125.323177,
+                41.771191
+              ],
+              [
+                125.336112,
+                41.768067
+              ],
+              [
+                125.336112,
+                41.768067
+              ],
+              [
+                125.332416,
+                41.711354
+              ],
+              [
+                125.317018,
+                41.676944
+              ],
+              [
+                125.344119,
+                41.672474
+              ],
+              [
+                125.412488,
+                41.691246
+              ],
+              [
+                125.446981,
+                41.67605
+              ],
+              [
+                125.461148,
+                41.642516
+              ],
+              [
+                125.450061,
+                41.597777
+              ],
+              [
+                125.479626,
+                41.544946
+              ],
+              [
+                125.507343,
+                41.534195
+              ],
+              [
+                125.493176,
+                41.509103
+              ],
+              [
+                125.533212,
+                41.479069
+              ],
+              [
+                125.534444,
+                41.428833
+              ],
+              [
+                125.547995,
+                41.401006
+              ],
+              [
+                125.581256,
+                41.396517
+              ],
+              [
+                125.589879,
+                41.359245
+              ],
+              [
+                125.610205,
+                41.365084
+              ],
+              [
+                125.637306,
+                41.34442
+              ],
+              [
+                125.62006,
+                41.318355
+              ],
+              [
+                125.642234,
+                41.296327
+              ],
+              [
+                125.646545,
+                41.264396
+              ],
+              [
+                125.685349,
+                41.273842
+              ],
+              [
+                125.695205,
+                41.244599
+              ],
+              [
+                125.749407,
+                41.245499
+              ],
+              [
+                125.758646,
+                41.232449
+              ],
+              [
+                125.73832,
+                41.178418
+              ],
+              [
+                125.791291,
+                41.167607
+              ],
+              [
+                125.759878,
+                41.132908
+              ],
+              [
+                125.734009,
+                41.125695
+              ],
+              [
+                125.712451,
+                41.095485
+              ],
+              [
+                125.739552,
+                41.08917
+              ],
+              [
+                125.726617,
+                41.055332
+              ],
+              [
+                125.684118,
+                41.021929
+              ],
+              [
+                125.674879,
+                40.974503
+              ],
+              [
+                125.650241,
+                40.970888
+              ],
+              [
+                125.635458,
+                40.94151
+              ],
+              [
+                125.589263,
+                40.931112
+              ],
+              [
+                125.584335,
+                40.891764
+              ],
+              [
+                125.652089,
+                40.91619
+              ],
+              [
+                125.687813,
+                40.897645
+              ],
+              [
+                125.707523,
+                40.866877
+              ],
+              [
+                125.778356,
+                40.897645
+              ],
+              [
+                125.817161,
+                40.866877
+              ],
+              [
+                125.860892,
+                40.888597
+              ],
+              [
+                125.875059,
+                40.908501
+              ],
+              [
+                125.921254,
+                40.882715
+              ],
+              [
+                125.959442,
+                40.88181
+              ],
+              [
+                126.008102,
+                40.936537
+              ],
+              [
+                126.041362,
+                40.928851
+              ],
+              [
+                126.051833,
+                40.96185
+              ],
+              [
+                126.08263,
+                40.976762
+              ],
+              [
+                126.066,
+                40.997542
+              ],
+              [
+                126.1085,
+                41.011995
+              ],
+              [
+                126.099877,
+                41.036376
+              ],
+              [
+                126.133753,
+                41.063906
+              ],
+              [
+                126.124514,
+                41.092327
+              ],
+              [
+                126.16763,
+                41.094583
+              ],
+              [
+                126.187956,
+                41.113072
+              ],
+              [
+                126.188572,
+                41.114875
+              ],
+              [
+                126.295129,
+                41.171661
+              ],
+              [
+                126.332086,
+                41.236949
+              ],
+              [
+                126.35426,
+                41.244599
+              ],
+              [
+                126.373354,
+                41.289133
+              ],
+              [
+                126.437411,
+                41.353405
+              ],
+              [
+                126.497158,
+                41.374965
+              ],
+              [
+                126.524259,
+                41.349362
+              ],
+              [
+                126.539041,
+                41.366881
+              ],
+              [
+                126.497158,
+                41.406842
+              ],
+              [
+                126.559983,
+                41.548081
+              ],
+              [
+                126.582773,
+                41.563307
+              ],
+              [
+                126.564295,
+                41.608965
+              ],
+              [
+                126.592628,
+                41.624624
+              ],
+              [
+                126.608027,
+                41.669345
+              ],
+              [
+                126.644983,
+                41.661297
+              ],
+              [
+                126.688099,
+                41.674262
+              ],
+              [
+                126.724439,
+                41.710907
+              ],
+              [
+                126.690562,
+                41.728328
+              ],
+              [
+                126.694874,
+                41.751103
+              ],
+              [
+                126.723207,
+                41.753335
+              ],
+              [
+                126.8002,
+                41.702865
+              ],
+              [
+                126.809439,
+                41.749317
+              ],
+              [
+                126.848243,
+                41.734134
+              ],
+              [
+                126.85625,
+                41.760031
+              ],
+              [
+                126.887047,
+                41.791719
+              ],
+              [
+                126.931395,
+                41.812687
+              ],
+              [
+                126.952953,
+                41.804212
+              ],
+              [
+                126.940018,
+                41.773423
+              ],
+              [
+                126.979438,
+                41.776993
+              ],
+              [
+                127.005923,
+                41.749317
+              ],
+              [
+                127.050887,
+                41.744852
+              ],
+              [
+                127.057662,
+                41.703758
+              ],
+              [
+                127.037952,
+                41.676944
+              ],
+              [
+                127.103242,
+                41.647883
+              ],
+              [
+                127.093387,
+                41.629993
+              ],
+              [
+                127.127263,
+                41.622388
+              ],
+              [
+                127.135887,
+                41.600463
+              ],
+              [
+                127.178386,
+                41.600015
+              ],
+              [
+                127.125416,
+                41.566442
+              ],
+              [
+                127.11864,
+                41.540018
+              ],
+              [
+                127.164836,
+                41.542706
+              ],
+              [
+                127.188241,
+                41.527475
+              ],
+              [
+                127.241212,
+                41.520754
+              ],
+              [
+                127.28864,
+                41.501932
+              ],
+              [
+                127.253531,
+                41.486691
+              ],
+              [
+                127.296031,
+                41.486243
+              ],
+              [
+                127.360704,
+                41.466065
+              ],
+              [
+                127.360088,
+                41.479518
+              ],
+              [
+                127.405668,
+                41.478621
+              ],
+              [
+                127.419835,
+                41.460235
+              ],
+              [
+                127.459255,
+                41.461581
+              ],
+              [
+                127.465414,
+                41.479069
+              ],
+              [
+                127.526392,
+                41.467859
+              ],
+              [
+                127.547334,
+                41.477276
+              ],
+              [
+                127.563964,
+                41.432871
+              ],
+              [
+                127.618783,
+                41.432871
+              ],
+              [
+                127.636645,
+                41.413575
+              ],
+              [
+                127.684073,
+                41.422999
+              ],
+              [
+                127.780159,
+                41.427038
+              ],
+              [
+                127.854688,
+                41.420755
+              ],
+              [
+                127.86947,
+                41.4037
+              ],
+              [
+                127.882405,
+                41.448124
+              ],
+              [
+                127.909506,
+                41.42973
+              ],
+              [
+                127.93168,
+                41.444984
+              ],
+              [
+                127.970484,
+                41.438704
+              ],
+              [
+                127.991426,
+                41.421204
+              ],
+              [
+                128.000049,
+                41.442741
+              ],
+              [
+                128.040085,
+                41.393375
+              ],
+              [
+                128.110919,
+                41.393375
+              ],
+              [
+                128.090593,
+                41.374516
+              ],
+              [
+                128.114614,
+                41.364186
+              ],
+              [
+                128.169433,
+                41.404149
+              ],
+              [
+                128.203925,
+                41.410882
+              ],
+              [
+                128.243345,
+                41.477276
+              ],
+              [
+                128.238418,
+                41.497898
+              ],
+              [
+                128.301244,
+                41.540018
+              ],
+              [
+                128.317874,
+                41.575844
+              ],
+              [
+                128.30186,
+                41.627756
+              ],
+              [
+                128.248889,
+                41.681414
+              ],
+              [
+                128.208853,
+                41.688565
+              ],
+              [
+                128.163889,
+                41.721628
+              ],
+              [
+                128.147875,
+                41.78101
+              ],
+              [
+                128.112766,
+                41.793504
+              ],
+              [
+                128.104143,
+                41.843457
+              ],
+              [
+                128.115846,
+                41.896935
+              ],
+              [
+                128.106607,
+                41.949923
+              ],
+              [
+                128.033926,
+                42.000199
+              ],
+              [
+                128.090593,
+                42.022877
+              ],
+              [
+                128.294468,
+                42.026434
+              ],
+              [
+                128.405338,
+                42.018876
+              ],
+              [
+                128.466316,
+                42.020654
+              ],
+              [
+                128.49896,
+                42.000644
+              ],
+              [
+                128.598127,
+                42.007315
+              ],
+              [
+                128.60675,
+                42.02999
+              ],
+              [
+                128.637547,
+                42.035324
+              ],
+              [
+                128.658489,
+                42.018876
+              ],
+              [
+                128.70222,
+                42.02021
+              ],
+              [
+                128.737945,
+                42.050435
+              ],
+              [
+                128.779213,
+                42.033546
+              ],
+              [
+                128.795227,
+                42.042436
+              ],
+              [
+                128.898089,
+                42.016653
+              ],
+              [
+                128.952908,
+                42.025545
+              ],
+              [
+                128.954755,
+                42.083756
+              ],
+              [
+                128.971386,
+                42.097079
+              ],
+              [
+                129.008958,
+                42.09175
+              ],
+              [
+                129.039139,
+                42.107736
+              ],
+              [
+                129.048378,
+                42.137476
+              ],
+              [
+                129.113668,
+                42.140583
+              ],
+              [
+                129.166639,
+                42.188047
+              ],
+              [
+                129.215914,
+                42.208442
+              ],
+              [
+                129.209138,
+                42.237692
+              ],
+              [
+                129.181421,
+                42.242122
+              ],
+              [
+                129.183269,
+                42.262056
+              ],
+              [
+                129.215914,
+                42.265157
+              ],
+              [
+                129.231312,
+                42.283755
+              ],
+              [
+                129.208522,
+                42.293052
+              ],
+              [
+                129.260261,
+                42.335536
+              ],
+              [
+                129.231312,
+                42.356325
+              ],
+              [
+                129.240551,
+                42.376223
+              ],
+              [
+                129.326167,
+                42.389927
+              ],
+              [
+                129.30892,
+                42.403628
+              ],
+              [
+                129.331094,
+                42.429695
+              ],
+              [
+                129.356348,
+                42.427045
+              ],
+              [
+                129.342181,
+                42.441179
+              ],
+              [
+                129.368051,
+                42.459284
+              ],
+              [
+                129.366203,
+                42.428811
+              ],
+              [
+                129.392688,
+                42.42837
+              ],
+              [
+                129.400695,
+                42.449128
+              ],
+              [
+                129.452434,
+                42.441179
+              ],
+              [
+                129.49863,
+                42.412023
+              ],
+              [
+                129.546057,
+                42.361632
+              ],
+              [
+                129.578086,
+                42.380202
+              ],
+              [
+                129.569463,
+                42.399208
+              ],
+              [
+                129.601492,
+                42.415116
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 230000,
+        "name": "榛戦緳姹熺渷",
+        "center": [
+          126.642464,
+          45.756967
+        ],
+        "centroid": [
+          127.693027,
+          48.040465
+        ],
+        "childrenNum": 13,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 7,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                123.569598,
+                46.223816
+              ],
+              [
+                123.604706,
+                46.251964
+              ],
+              [
+                123.673692,
+                46.258585
+              ],
+              [
+                123.726047,
+                46.255688
+              ],
+              [
+                123.775938,
+                46.263136
+              ],
+              [
+                123.84985,
+                46.302428
+              ],
+              [
+                123.896046,
+                46.303668
+              ],
+              [
+                123.917604,
+                46.25693
+              ],
+              [
+                123.936082,
+                46.286715
+              ],
+              [
+                123.960103,
+                46.288369
+              ],
+              [
+                123.952096,
+                46.256516
+              ],
+              [
+                123.979814,
+                46.228784
+              ],
+              [
+                123.956408,
+                46.206009
+              ],
+              [
+                123.971806,
+                46.170379
+              ],
+              [
+                124.001987,
+                46.166649
+              ],
+              [
+                123.991516,
+                46.143019
+              ],
+              [
+                124.01677,
+                46.118549
+              ],
+              [
+                123.99398,
+                46.101123
+              ],
+              [
+                124.015538,
+                46.088257
+              ],
+              [
+                124.009995,
+                46.057534
+              ],
+              [
+                124.034016,
+                46.045074
+              ],
+              [
+                124.040176,
+                46.01973
+              ],
+              [
+                123.989053,
+                46.011833
+              ],
+              [
+                124.011842,
+                45.981899
+              ],
+              [
+                123.973654,
+                45.973997
+              ],
+              [
+                123.968727,
+                45.936551
+              ],
+              [
+                123.996444,
+                45.906993
+              ],
+              [
+                124.061118,
+                45.886168
+              ],
+              [
+                124.067277,
+                45.840325
+              ],
+              [
+                124.03648,
+                45.83824
+              ],
+              [
+                124.064197,
+                45.802372
+              ],
+              [
+                124.001987,
+                45.770655
+              ],
+              [
+                124.014922,
+                45.749779
+              ],
+              [
+                124.054342,
+                45.751449
+              ],
+              [
+                124.098074,
+                45.722628
+              ],
+              [
+                124.10177,
+                45.700898
+              ],
+              [
+                124.13503,
+                45.690448
+              ],
+              [
+                124.122096,
+                45.669123
+              ],
+              [
+                124.147349,
+                45.665359
+              ],
+              [
+                124.128255,
+                45.641933
+              ],
+              [
+                124.162132,
+                45.616404
+              ],
+              [
+                124.226805,
+                45.633564
+              ],
+              [
+                124.238508,
+                45.591702
+              ],
+              [
+                124.273001,
+                45.584163
+              ],
+              [
+                124.264377,
+                45.555256
+              ],
+              [
+                124.287783,
+                45.539329
+              ],
+              [
+                124.348761,
+                45.546874
+              ],
+              [
+                124.369087,
+                45.512915
+              ],
+              [
+                124.352457,
+                45.496557
+              ],
+              [
+                124.374015,
+                45.45795
+              ],
+              [
+                124.398652,
+                45.440737
+              ],
+              [
+                124.480572,
+                45.456271
+              ],
+              [
+                124.507058,
+                45.424778
+              ],
+              [
+                124.544014,
+                45.411756
+              ],
+              [
+                124.579738,
+                45.424358
+              ],
+              [
+                124.575427,
+                45.451234
+              ],
+              [
+                124.625318,
+                45.437377
+              ],
+              [
+                124.690607,
+                45.452493
+              ],
+              [
+                124.729412,
+                45.444096
+              ],
+              [
+                124.776223,
+                45.468024
+              ],
+              [
+                124.792853,
+                45.436958
+              ],
+              [
+                124.839665,
+                45.455852
+              ],
+              [
+                124.886476,
+                45.442836
+              ],
+              [
+                124.884628,
+                45.495299
+              ],
+              [
+                124.911114,
+                45.535976
+              ],
+              [
+                124.936983,
+                45.53388
+              ],
+              [
+                124.961005,
+                45.495299
+              ],
+              [
+                125.025678,
+                45.493201
+              ],
+              [
+                125.0497,
+                45.428558
+              ],
+              [
+                125.08912,
+                45.420998
+              ],
+              [
+                125.06633,
+                45.39915
+              ],
+              [
+                125.097127,
+                45.38276
+              ],
+              [
+                125.137779,
+                45.409655
+              ],
+              [
+                125.189518,
+                45.39915
+              ],
+              [
+                125.248649,
+                45.417637
+              ],
+              [
+                125.301619,
+                45.402092
+              ],
+              [
+                125.319482,
+                45.422678
+              ],
+              [
+                125.361981,
+                45.392847
+              ],
+              [
+                125.398322,
+                45.416797
+              ],
+              [
+                125.434662,
+                45.462988
+              ],
+              [
+                125.424807,
+                45.485649
+              ],
+              [
+                125.480242,
+                45.486488
+              ],
+              [
+                125.497488,
+                45.469283
+              ],
+              [
+                125.583104,
+                45.491942
+              ],
+              [
+                125.61698,
+                45.517947
+              ],
+              [
+                125.660096,
+                45.507043
+              ],
+              [
+                125.687813,
+                45.514173
+              ],
+              [
+                125.711835,
+                45.477677
+              ],
+              [
+                125.712451,
+                45.389485
+              ],
+              [
+                125.695205,
+                45.352066
+              ],
+              [
+                125.726001,
+                45.336503
+              ],
+              [
+                125.761726,
+                45.291472
+              ],
+              [
+                125.815929,
+                45.264942
+              ],
+              [
+                125.823936,
+                45.237978
+              ],
+              [
+                125.849805,
+                45.23882
+              ],
+              [
+                125.915095,
+                45.196664
+              ],
+              [
+                125.957595,
+                45.201303
+              ],
+              [
+                125.992703,
+                45.192447
+              ],
+              [
+                125.998247,
+                45.162072
+              ],
+              [
+                126.047522,
+                45.170933
+              ],
+              [
+                126.091869,
+                45.149411
+              ],
+              [
+                126.142992,
+                45.147723
+              ],
+              [
+                126.166398,
+                45.13337
+              ],
+              [
+                126.225528,
+                45.154054
+              ],
+              [
+                126.235383,
+                45.140125
+              ],
+              [
+                126.285274,
+                45.162494
+              ],
+              [
+                126.293282,
+                45.180214
+              ],
+              [
+                126.356107,
+                45.185698
+              ],
+              [
+                126.402919,
+                45.222805
+              ],
+              [
+                126.519331,
+                45.248091
+              ],
+              [
+                126.540273,
+                45.23882
+              ],
+              [
+                126.569222,
+                45.252725
+              ],
+              [
+                126.644983,
+                45.225334
+              ],
+              [
+                126.640055,
+                45.214373
+              ],
+              [
+                126.685635,
+                45.187807
+              ],
+              [
+                126.732446,
+                45.187385
+              ],
+              [
+                126.787265,
+                45.159118
+              ],
+              [
+                126.792808,
+                45.135481
+              ],
+              [
+                126.85625,
+                45.145613
+              ],
+              [
+                126.96404,
+                45.132104
+              ],
+              [
+                126.970815,
+                45.070852
+              ],
+              [
+                126.984981,
+                45.067893
+              ],
+              [
+                127.018242,
+                45.024341
+              ],
+              [
+                127.050271,
+                45.004034
+              ],
+              [
+                127.092771,
+                44.94688
+              ],
+              [
+                127.073061,
+                44.907051
+              ],
+              [
+                127.021938,
+                44.898997
+              ],
+              [
+                126.999764,
+                44.87398
+              ],
+              [
+                126.984366,
+                44.823914
+              ],
+              [
+                126.9973,
+                44.764882
+              ],
+              [
+                127.041032,
+                44.712169
+              ],
+              [
+                127.030561,
+                44.673454
+              ],
+              [
+                127.044112,
+                44.653874
+              ],
+              [
+                127.041648,
+                44.591258
+              ],
+              [
+                127.049655,
+                44.566961
+              ],
+              [
+                127.089691,
+                44.593816
+              ],
+              [
+                127.094619,
+                44.615972
+              ],
+              [
+                127.138966,
+                44.607451
+              ],
+              [
+                127.182082,
+                44.644507
+              ],
+              [
+                127.228893,
+                44.642804
+              ],
+              [
+                127.214111,
+                44.624917
+              ],
+              [
+                127.261538,
+                44.61299
+              ],
+              [
+                127.275705,
+                44.640249
+              ],
+              [
+                127.392733,
+                44.632158
+              ],
+              [
+                127.557189,
+                44.575488
+              ],
+              [
+                127.570124,
+                44.55033
+              ],
+              [
+                127.536247,
+                44.522176
+              ],
+              [
+                127.485124,
+                44.528576
+              ],
+              [
+                127.465414,
+                44.516628
+              ],
+              [
+                127.463566,
+                44.484615
+              ],
+              [
+                127.50853,
+                44.437202
+              ],
+              [
+                127.486356,
+                44.410275
+              ],
+              [
+                127.579363,
+                44.310581
+              ],
+              [
+                127.623711,
+                44.278025
+              ],
+              [
+                127.59045,
+                44.227872
+              ],
+              [
+                127.626174,
+                44.187977
+              ],
+              [
+                127.641573,
+                44.193555
+              ],
+              [
+                127.681609,
+                44.166946
+              ],
+              [
+                127.712406,
+                44.199133
+              ],
+              [
+                127.735811,
+                44.11412
+              ],
+              [
+                127.729036,
+                44.09908
+              ],
+              [
+                127.783239,
+                44.071997
+              ],
+              [
+                127.808492,
+                44.086615
+              ],
+              [
+                127.846065,
+                44.081886
+              ],
+              [
+                127.862695,
+                44.062967
+              ],
+              [
+                127.912586,
+                44.064687
+              ],
+              [
+                127.950158,
+                44.088334
+              ],
+              [
+                128.042549,
+                44.103807
+              ],
+              [
+                128.091208,
+                44.133022
+              ],
+              [
+                128.088129,
+                44.158359
+              ],
+              [
+                128.060411,
+                44.168663
+              ],
+              [
+                128.09244,
+                44.181539
+              ],
+              [
+                128.104143,
+                44.230017
+              ],
+              [
+                128.064107,
+                44.251454
+              ],
+              [
+                128.101679,
+                44.293449
+              ],
+              [
+                128.065339,
+                44.307155
+              ],
+              [
+                128.049941,
+                44.349965
+              ],
+              [
+                128.074578,
+                44.370075
+              ],
+              [
+                128.094904,
+                44.354673
+              ],
+              [
+                128.137404,
+                44.357668
+              ],
+              [
+                128.172512,
+                44.34697
+              ],
+              [
+                128.211317,
+                44.431647
+              ],
+              [
+                128.228563,
+                44.445748
+              ],
+              [
+                128.293237,
+                44.467961
+              ],
+              [
+                128.295084,
+                44.480772
+              ],
+              [
+                128.372693,
+                44.514495
+              ],
+              [
+                128.397946,
+                44.483761
+              ],
+              [
+                128.427511,
+                44.473512
+              ],
+              [
+                128.463236,
+                44.431647
+              ],
+              [
+                128.457076,
+                44.409848
+              ],
+              [
+                128.481714,
+                44.375637
+              ],
+              [
+                128.475555,
+                44.346114
+              ],
+              [
+                128.446605,
+                44.339694
+              ],
+              [
+                128.472475,
+                44.320001
+              ],
+              [
+                128.453997,
+                44.257884
+              ],
+              [
+                128.471859,
+                44.247596
+              ],
+              [
+                128.450301,
+                44.203423
+              ],
+              [
+                128.471859,
+                44.157501
+              ],
+              [
+                128.529141,
+                44.112401
+              ],
+              [
+                128.574721,
+                44.047914
+              ],
+              [
+                128.584576,
+                43.990246
+              ],
+              [
+                128.610445,
+                43.960529
+              ],
+              [
+                128.64001,
+                43.948035
+              ],
+              [
+                128.636315,
+                43.891132
+              ],
+              [
+                128.696061,
+                43.903207
+              ],
+              [
+                128.729938,
+                43.889838
+              ],
+              [
+                128.760734,
+                43.857482
+              ],
+              [
+                128.719467,
+                43.816905
+              ],
+              [
+                128.739177,
+                43.806972
+              ],
+              [
+                128.760119,
+                43.755554
+              ],
+              [
+                128.729322,
+                43.736964
+              ],
+              [
+                128.768126,
+                43.732207
+              ],
+              [
+                128.78722,
+                43.686784
+              ],
+              [
+                128.821097,
+                43.637429
+              ],
+              [
+                128.834647,
+                43.587599
+              ],
+              [
+                128.878379,
+                43.539898
+              ],
+              [
+                128.949828,
+                43.553779
+              ],
+              [
+                128.962763,
+                43.53903
+              ],
+              [
+                129.013886,
+                43.522976
+              ],
+              [
+                129.037907,
+                43.540332
+              ],
+              [
+                129.093958,
+                43.547706
+              ],
+              [
+                129.145081,
+                43.570258
+              ],
+              [
+                129.169102,
+                43.561585
+              ],
+              [
+                129.23008,
+                43.593234
+              ],
+              [
+                129.232544,
+                43.635263
+              ],
+              [
+                129.217146,
+                43.648689
+              ],
+              [
+                129.214066,
+                43.695006
+              ],
+              [
+                129.232544,
+                43.709284
+              ],
+              [
+                129.211602,
+                43.784509
+              ],
+              [
+                129.254718,
+                43.819496
+              ],
+              [
+                129.289826,
+                43.797038
+              ],
+              [
+                129.30892,
+                43.812155
+              ],
+              [
+                129.348341,
+                43.798333
+              ],
+              [
+                129.406855,
+                43.819496
+              ],
+              [
+                129.417942,
+                43.843672
+              ],
+              [
+                129.449971,
+                43.850578
+              ],
+              [
+                129.467833,
+                43.874741
+              ],
+              [
+                129.529427,
+                43.870427
+              ],
+              [
+                129.650767,
+                43.873016
+              ],
+              [
+                129.699426,
+                43.8838
+              ],
+              [
+                129.743158,
+                43.876035
+              ],
+              [
+                129.739462,
+                43.895876
+              ],
+              [
+                129.780114,
+                43.892857
+              ],
+              [
+                129.802904,
+                43.964837
+              ],
+              [
+                129.868193,
+                44.012631
+              ],
+              [
+                129.881128,
+                44.000148
+              ],
+              [
+                129.907614,
+                44.023821
+              ],
+              [
+                129.951345,
+                44.027263
+              ],
+              [
+                129.979062,
+                44.015644
+              ],
+              [
+                130.017867,
+                43.961821
+              ],
+              [
+                130.022794,
+                43.917866
+              ],
+              [
+                130.009243,
+                43.889407
+              ],
+              [
+                130.027722,
+                43.851872
+              ],
+              [
+                130.079461,
+                43.835039
+              ],
+              [
+                130.110873,
+                43.852735
+              ],
+              [
+                130.116417,
+                43.878192
+              ],
+              [
+                130.143518,
+                43.878624
+              ],
+              [
+                130.153373,
+                43.915711
+              ],
+              [
+                130.208192,
+                43.948466
+              ],
+              [
+                130.262395,
+                43.949328
+              ],
+              [
+                130.27225,
+                43.981634
+              ],
+              [
+                130.307358,
+                44.002731
+              ],
+              [
+                130.319061,
+                44.03974
+              ],
+              [
+                130.365256,
+                44.044042
+              ],
+              [
+                130.364025,
+                43.992399
+              ],
+              [
+                130.338155,
+                43.963975
+              ],
+              [
+                130.381887,
+                43.910106
+              ],
+              [
+                130.368336,
+                43.894151
+              ],
+              [
+                130.386198,
+                43.85403
+              ],
+              [
+                130.362793,
+                43.844967
+              ],
+              [
+                130.381887,
+                43.817768
+              ],
+              [
+                130.382503,
+                43.777164
+              ],
+              [
+                130.423155,
+                43.745179
+              ],
+              [
+                130.394206,
+                43.703227
+              ],
+              [
+                130.412684,
+                43.652586
+              ],
+              [
+                130.437937,
+                43.646091
+              ],
+              [
+                130.488444,
+                43.65605
+              ],
+              [
+                130.501995,
+                43.636563
+              ],
+              [
+                130.57098,
+                43.626167
+              ],
+              [
+                130.57098,
+                43.626167
+              ],
+              [
+                130.630726,
+                43.622268
+              ],
+              [
+                130.623335,
+                43.589767
+              ],
+              [
+                130.665835,
+                43.583698
+              ],
+              [
+                130.671378,
+                43.565054
+              ],
+              [
+                130.727429,
+                43.560284
+              ],
+              [
+                130.776704,
+                43.52341
+              ],
+              [
+                130.822899,
+                43.503446
+              ],
+              [
+                130.841378,
+                43.454374
+              ],
+              [
+                130.864167,
+                43.437863
+              ],
+              [
+                130.907283,
+                43.434387
+              ],
+              [
+                130.959638,
+                43.48608
+              ],
+              [
+                131.026775,
+                43.508655
+              ],
+              [
+                131.142572,
+                43.425695
+              ],
+              [
+                131.175217,
+                43.444816
+              ],
+              [
+                131.201086,
+                43.442209
+              ],
+              [
+                131.234963,
+                43.475224
+              ],
+              [
+                131.294093,
+                43.470012
+              ],
+              [
+                131.304564,
+                43.502144
+              ],
+              [
+                131.276847,
+                43.495632
+              ],
+              [
+                131.20047,
+                43.532089
+              ],
+              [
+                131.222028,
+                43.593234
+              ],
+              [
+                131.216485,
+                43.613169
+              ],
+              [
+                131.239274,
+                43.670337
+              ],
+              [
+                131.221412,
+                43.682024
+              ],
+              [
+                131.215869,
+                43.72745
+              ],
+              [
+                131.232499,
+                43.742585
+              ],
+              [
+                131.213405,
+                43.801357
+              ],
+              [
+                131.2171,
+                43.836334
+              ],
+              [
+                131.254057,
+                43.893289
+              ],
+              [
+                131.26268,
+                43.948897
+              ],
+              [
+                131.245434,
+                43.95579
+              ],
+              [
+                131.26576,
+                44.034578
+              ],
+              [
+                131.28239,
+                44.035868
+              ],
+              [
+                131.287318,
+                44.03802
+              ],
+              [
+                131.293477,
+                44.043182
+              ],
+              [
+                131.310723,
+                44.046623
+              ],
+              [
+                131.111775,
+                44.710042
+              ],
+              [
+                131.090833,
+                44.717272
+              ],
+              [
+                131.093297,
+                44.746183
+              ],
+              [
+                131.069275,
+                44.759783
+              ],
+              [
+                131.064348,
+                44.786973
+              ],
+              [
+                131.016304,
+                44.789521
+              ],
+              [
+                131.015688,
+                44.814999
+              ],
+              [
+                130.972573,
+                44.820094
+              ],
+              [
+                130.965181,
+                44.85065
+              ],
+              [
+                131.07913,
+                44.881614
+              ],
+              [
+                131.10192,
+                44.898997
+              ],
+              [
+                131.090217,
+                44.924427
+              ],
+              [
+                131.16105,
+                44.948151
+              ],
+              [
+                131.20355,
+                44.932901
+              ],
+              [
+                131.207861,
+                44.913833
+              ],
+              [
+                131.263296,
+                44.929935
+              ],
+              [
+                131.274999,
+                44.919766
+              ],
+              [
+                131.313803,
+                44.950692
+              ],
+              [
+                131.313803,
+                44.965938
+              ],
+              [
+                131.355071,
+                44.990068
+              ],
+              [
+                131.380324,
+                44.978216
+              ],
+              [
+                131.409889,
+                44.985836
+              ],
+              [
+                131.464708,
+                44.963397
+              ],
+              [
+                131.501664,
+                44.977793
+              ],
+              [
+                131.484418,
+                44.99557
+              ],
+              [
+                131.529382,
+                45.012073
+              ],
+              [
+                131.566338,
+                45.045487
+              ],
+              [
+                131.63286,
+                45.075078
+              ],
+              [
+                131.695685,
+                45.132104
+              ],
+              [
+                131.687678,
+                45.1511
+              ],
+              [
+                131.650722,
+                45.159962
+              ],
+              [
+                131.681519,
+                45.215217
+              ],
+              [
+                131.721555,
+                45.234606
+              ],
+              [
+                131.759127,
+                45.213952
+              ],
+              [
+                131.79362,
+                45.211844
+              ],
+              [
+                131.788692,
+                45.245984
+              ],
+              [
+                131.825649,
+                45.291472
+              ],
+              [
+                131.82996,
+                45.311677
+              ],
+              [
+                131.887858,
+                45.342393
+              ],
+              [
+                131.917423,
+                45.339448
+              ],
+              [
+                131.93159,
+                45.287683
+              ],
+              [
+                131.976554,
+                45.277156
+              ],
+              [
+                132.003655,
+                45.25441
+              ],
+              [
+                132.17427,
+                45.216903
+              ],
+              [
+                132.394161,
+                45.16376
+              ],
+              [
+                132.76434,
+                45.081417
+              ],
+              [
+                132.867202,
+                45.061976
+              ],
+              [
+                132.916477,
+                45.031109
+              ],
+              [
+                132.954049,
+                45.023072
+              ],
+              [
+                132.98731,
+                45.043373
+              ],
+              [
+                133.035969,
+                45.054366
+              ],
+              [
+                133.070462,
+                45.097051
+              ],
+              [
+                133.089556,
+                45.097473
+              ],
+              [
+                133.107418,
+                45.124504
+              ],
+              [
+                133.139447,
+                45.127459
+              ],
+              [
+                133.129592,
+                45.211422
+              ],
+              [
+                133.095715,
+                45.246827
+              ],
+              [
+                133.110498,
+                45.266627
+              ],
+              [
+                133.097563,
+                45.284735
+              ],
+              [
+                133.128976,
+                45.336924
+              ],
+              [
+                133.119121,
+                45.352908
+              ],
+              [
+                133.144991,
+                45.367205
+              ],
+              [
+                133.143759,
+                45.430658
+              ],
+              [
+                133.164701,
+                45.437377
+              ],
+              [
+                133.170244,
+                45.465506
+              ],
+              [
+                133.203505,
+                45.516689
+              ],
+              [
+                133.246005,
+                45.517528
+              ],
+              [
+                133.333468,
+                45.562379
+              ],
+              [
+                133.342707,
+                45.554836
+              ],
+              [
+                133.393214,
+                45.580393
+              ],
+              [
+                133.423395,
+                45.584163
+              ],
+              [
+                133.412924,
+                45.618079
+              ],
+              [
+                133.471438,
+                45.631053
+              ],
+              [
+                133.448649,
+                45.647372
+              ],
+              [
+                133.485605,
+                45.658667
+              ],
+              [
+                133.484989,
+                45.691702
+              ],
+              [
+                133.445569,
+                45.705077
+              ],
+              [
+                133.454192,
+                45.731819
+              ],
+              [
+                133.486837,
+                45.740173
+              ],
+              [
+                133.469591,
+                45.777751
+              ],
+              [
+                133.505315,
+                45.785681
+              ],
+              [
+                133.469591,
+                45.799451
+              ],
+              [
+                133.467743,
+                45.834905
+              ],
+              [
+                133.494228,
+                45.840325
+              ],
+              [
+                133.491764,
+                45.867002
+              ],
+              [
+                133.51209,
+                45.887001
+              ],
+              [
+                133.55459,
+                45.893249
+              ],
+              [
+                133.583539,
+                45.868669
+              ],
+              [
+                133.618032,
+                45.903662
+              ],
+              [
+                133.614952,
+                45.942794
+              ],
+              [
+                133.676546,
+                45.94321
+              ],
+              [
+                133.681474,
+                45.986473
+              ],
+              [
+                133.740604,
+                46.048812
+              ],
+              [
+                133.745531,
+                46.075389
+              ],
+              [
+                133.690713,
+                46.133896
+              ],
+              [
+                133.706111,
+                46.163333
+              ],
+              [
+                133.764626,
+                46.17328
+              ],
+              [
+                133.794807,
+                46.193583
+              ],
+              [
+                133.814517,
+                46.230854
+              ],
+              [
+                133.849625,
+                46.203939
+              ],
+              [
+                133.87919,
+                46.233752
+              ],
+              [
+                133.867487,
+                46.250722
+              ],
+              [
+                133.909987,
+                46.254447
+              ],
+              [
+                133.91861,
+                46.280924
+              ],
+              [
+                133.908139,
+                46.308216
+              ],
+              [
+                133.922922,
+                46.330948
+              ],
+              [
+                133.869335,
+                46.338386
+              ],
+              [
+                133.876726,
+                46.362345
+              ],
+              [
+                133.940784,
+                46.38134
+              ],
+              [
+                133.948791,
+                46.401153
+              ],
+              [
+                133.902596,
+                46.446119
+              ],
+              [
+                133.852089,
+                46.450242
+              ],
+              [
+                133.849625,
+                46.475389
+              ],
+              [
+                133.890893,
+                46.525235
+              ],
+              [
+                133.919842,
+                46.596012
+              ],
+              [
+                134.011001,
+                46.637941
+              ],
+              [
+                134.030711,
+                46.708981
+              ],
+              [
+                134.033175,
+                46.759023
+              ],
+              [
+                134.052885,
+                46.779928
+              ],
+              [
+                134.025168,
+                46.810657
+              ],
+              [
+                134.041182,
+                46.848326
+              ],
+              [
+                134.042414,
+                46.886787
+              ],
+              [
+                134.076291,
+                46.938298
+              ],
+              [
+                134.063972,
+                46.979962
+              ],
+              [
+                134.10216,
+                47.005678
+              ],
+              [
+                134.118175,
+                47.061968
+              ],
+              [
+                134.142812,
+                47.093349
+              ],
+              [
+                134.222268,
+                47.105164
+              ],
+              [
+                134.232739,
+                47.134892
+              ],
+              [
+                134.230276,
+                47.182097
+              ],
+              [
+                134.210566,
+                47.210155
+              ],
+              [
+                134.156979,
+                47.248357
+              ],
+              [
+                134.177305,
+                47.326299
+              ],
+              [
+                134.203174,
+                47.347389
+              ],
+              [
+                134.263536,
+                47.371307
+              ],
+              [
+                134.266616,
+                47.391974
+              ],
+              [
+                134.307268,
+                47.428829
+              ],
+              [
+                134.339297,
+                47.439759
+              ],
+              [
+                134.490202,
+                47.446235
+              ],
+              [
+                134.522847,
+                47.468086
+              ],
+              [
+                134.568426,
+                47.478199
+              ],
+              [
+                134.576434,
+                47.519036
+              ],
+              [
+                134.627556,
+                47.546512
+              ],
+              [
+                134.678064,
+                47.588507
+              ],
+              [
+                134.689766,
+                47.63813
+              ],
+              [
+                134.779694,
+                47.7159
+              ],
+              [
+                134.772918,
+                47.763391
+              ],
+              [
+                134.678679,
+                47.819278
+              ],
+              [
+                134.670056,
+                47.864667
+              ],
+              [
+                134.677448,
+                47.884738
+              ],
+              [
+                134.658969,
+                47.901191
+              ],
+              [
+                134.607846,
+                47.909214
+              ],
+              [
+                134.599839,
+                47.947711
+              ],
+              [
+                134.55426,
+                47.982173
+              ],
+              [
+                134.551796,
+                48.032622
+              ],
+              [
+                134.632484,
+                48.099412
+              ],
+              [
+                134.67252,
+                48.170505
+              ],
+              [
+                134.679295,
+                48.256245
+              ],
+              [
+                134.77107,
+                48.288908
+              ],
+              [
+                134.864077,
+                48.332293
+              ],
+              [
+                135.009439,
+                48.365703
+              ],
+              [
+                135.090743,
+                48.403461
+              ],
+              [
+                135.09567,
+                48.437618
+              ],
+              [
+                135.068569,
+                48.459451
+              ],
+              [
+                135.035924,
+                48.440795
+              ],
+              [
+                134.996504,
+                48.439603
+              ],
+              [
+                134.927519,
+                48.451513
+              ],
+              [
+                134.886867,
+                48.437618
+              ],
+              [
+                134.848679,
+                48.393925
+              ],
+              [
+                134.820961,
+                48.37604
+              ],
+              [
+                134.764295,
+                48.370076
+              ],
+              [
+                134.704549,
+                48.405448
+              ],
+              [
+                134.640491,
+                48.409818
+              ],
+              [
+                134.578281,
+                48.405448
+              ],
+              [
+                134.501905,
+                48.418954
+              ],
+              [
+                134.438463,
+                48.405448
+              ],
+              [
+                134.369478,
+                48.382797
+              ],
+              [
+                134.20379,
+                48.3824
+              ],
+              [
+                134.150819,
+                48.346217
+              ],
+              [
+                134.116327,
+                48.333089
+              ],
+              [
+                134.0689,
+                48.338659
+              ],
+              [
+                134.029479,
+                48.327519
+              ],
+              [
+                133.995603,
+                48.303639
+              ],
+              [
+                133.940784,
+                48.302047
+              ],
+              [
+                133.876111,
+                48.282536
+              ],
+              [
+                133.824372,
+                48.277359
+              ],
+              [
+                133.791111,
+                48.261026
+              ],
+              [
+                133.740604,
+                48.254651
+              ],
+              [
+                133.693177,
+                48.186866
+              ],
+              [
+                133.667307,
+                48.183275
+              ],
+              [
+                133.59709,
+                48.194846
+              ],
+              [
+                133.573068,
+                48.182078
+              ],
+              [
+                133.545967,
+                48.121389
+              ],
+              [
+                133.451728,
+                48.112999
+              ],
+              [
+                133.407997,
+                48.124585
+              ],
+              [
+                133.302055,
+                48.103009
+              ],
+              [
+                133.239845,
+                48.126583
+              ],
+              [
+                133.182563,
+                48.135769
+              ],
+              [
+                133.130208,
+                48.134971
+              ],
+              [
+                133.053216,
+                48.110202
+              ],
+              [
+                133.02673,
+                48.085421
+              ],
+              [
+                133.016259,
+                48.054228
+              ],
+              [
+                132.992238,
+                48.035424
+              ],
+              [
+                132.883216,
+                48.002599
+              ],
+              [
+                132.819159,
+                47.936887
+              ],
+              [
+                132.769268,
+                47.93849
+              ],
+              [
+                132.723072,
+                47.962941
+              ],
+              [
+                132.691043,
+                47.962941
+              ],
+              [
+                132.661478,
+                47.944905
+              ],
+              [
+                132.662094,
+                47.922451
+              ],
+              [
+                132.687348,
+                47.88514
+              ],
+              [
+                132.662094,
+                47.854227
+              ],
+              [
+                132.621442,
+                47.82852
+              ],
+              [
+                132.599268,
+                47.792347
+              ],
+              [
+                132.6005,
+                47.740858
+              ],
+              [
+                132.558,
+                47.718316
+              ],
+              [
+                132.469305,
+                47.726368
+              ],
+              [
+                132.371987,
+                47.765402
+              ],
+              [
+                132.325175,
+                47.762184
+              ],
+              [
+                132.288835,
+                47.742065
+              ],
+              [
+                132.272205,
+                47.718718
+              ],
+              [
+                132.242639,
+                47.70986
+              ],
+              [
+                132.19706,
+                47.714289
+              ],
+              [
+                132.157024,
+                47.70543
+              ],
+              [
+                132.086191,
+                47.703013
+              ],
+              [
+                132.000575,
+                47.712276
+              ],
+              [
+                131.976554,
+                47.673201
+              ],
+              [
+                131.900793,
+                47.685692
+              ],
+              [
+                131.825649,
+                47.677231
+              ],
+              [
+                131.741881,
+                47.706638
+              ],
+              [
+                131.690142,
+                47.707041
+              ],
+              [
+                131.641483,
+                47.663932
+              ],
+              [
+                131.59036,
+                47.660707
+              ],
+              [
+                131.568186,
+                47.682469
+              ],
+              [
+                131.559563,
+                47.724757
+              ],
+              [
+                131.543548,
+                47.736028
+              ],
+              [
+                131.456085,
+                47.747297
+              ],
+              [
+                131.359998,
+                47.730796
+              ],
+              [
+                131.273767,
+                47.738846
+              ],
+              [
+                131.236811,
+                47.733211
+              ],
+              [
+                131.183224,
+                47.702611
+              ],
+              [
+                131.115471,
+                47.689721
+              ],
+              [
+                131.029855,
+                47.694555
+              ],
+              [
+                130.983659,
+                47.713081
+              ],
+              [
+                130.966413,
+                47.733211
+              ],
+              [
+                130.961486,
+                47.828118
+              ],
+              [
+                130.891269,
+                47.927263
+              ],
+              [
+                130.870943,
+                47.943301
+              ],
+              [
+                130.770544,
+                47.998194
+              ],
+              [
+                130.737284,
+                48.034223
+              ],
+              [
+                130.699711,
+                48.044227
+              ],
+              [
+                130.666451,
+                48.105007
+              ],
+              [
+                130.673842,
+                48.12818
+              ],
+              [
+                130.765617,
+                48.18926
+              ],
+              [
+                130.769313,
+                48.231136
+              ],
+              [
+                130.787791,
+                48.256643
+              ],
+              [
+                130.817972,
+                48.265409
+              ],
+              [
+                130.845073,
+                48.296473
+              ],
+              [
+                130.81982,
+                48.341444
+              ],
+              [
+                130.785327,
+                48.357353
+              ],
+              [
+                130.747755,
+                48.404256
+              ],
+              [
+                130.745907,
+                48.449131
+              ],
+              [
+                130.776704,
+                48.480084
+              ],
+              [
+                130.767465,
+                48.507846
+              ],
+              [
+                130.711414,
+                48.511414
+              ],
+              [
+                130.647357,
+                48.484844
+              ],
+              [
+                130.620871,
+                48.49595
+              ],
+              [
+                130.615944,
+                48.575601
+              ],
+              [
+                130.605473,
+                48.594207
+              ],
+              [
+                130.538335,
+                48.612016
+              ],
+              [
+                130.538951,
+                48.635751
+              ],
+              [
+                130.576524,
+                48.688719
+              ],
+              [
+                130.622103,
+                48.783842
+              ],
+              [
+                130.689856,
+                48.849651
+              ],
+              [
+                130.680617,
+                48.881146
+              ],
+              [
+                130.609168,
+                48.881146
+              ],
+              [
+                130.559277,
+                48.861071
+              ],
+              [
+                130.501995,
+                48.865795
+              ],
+              [
+                130.471198,
+                48.905541
+              ],
+              [
+                130.412068,
+                48.905148
+              ],
+              [
+                130.279641,
+                48.866976
+              ],
+              [
+                130.237757,
+                48.868551
+              ],
+              [
+                130.219895,
+                48.893739
+              ],
+              [
+                130.113337,
+                48.956653
+              ],
+              [
+                130.059135,
+                48.979047
+              ],
+              [
+                130.020946,
+                49.021058
+              ],
+              [
+                129.937179,
+                49.040285
+              ],
+              [
+                129.9187,
+                49.060681
+              ],
+              [
+                129.934715,
+                49.078717
+              ],
+              [
+                129.913157,
+                49.1085
+              ],
+              [
+                129.866962,
+                49.113985
+              ],
+              [
+                129.855259,
+                49.133567
+              ],
+              [
+                129.864498,
+                49.158621
+              ],
+              [
+                129.847867,
+                49.181316
+              ],
+              [
+                129.784426,
+                49.184054
+              ],
+              [
+                129.753629,
+                49.208692
+              ],
+              [
+                129.761636,
+                49.25754
+              ],
+              [
+                129.730223,
+                49.288387
+              ],
+              [
+                129.696962,
+                49.298535
+              ],
+              [
+                129.604571,
+                49.279018
+              ],
+              [
+                129.562687,
+                49.299706
+              ],
+              [
+                129.546057,
+                49.395227
+              ],
+              [
+                129.51834,
+                49.423652
+              ],
+              [
+                129.448739,
+                49.441167
+              ],
+              [
+                129.390224,
+                49.432605
+              ],
+              [
+                129.374826,
+                49.414309
+              ],
+              [
+                129.379138,
+                49.367175
+              ],
+              [
+                129.358196,
+                49.355871
+              ],
+              [
+                129.320623,
+                49.3586
+              ],
+              [
+                129.266421,
+                49.396006
+              ],
+              [
+                129.215298,
+                49.399122
+              ],
+              [
+                129.180805,
+                49.386657
+              ],
+              [
+                129.143849,
+                49.357431
+              ],
+              [
+                129.084719,
+                49.359769
+              ],
+              [
+                129.061929,
+                49.374189
+              ],
+              [
+                129.013886,
+                49.457119
+              ],
+              [
+                128.932582,
+                49.46801
+              ],
+              [
+                128.871604,
+                49.492506
+              ],
+              [
+                128.792147,
+                49.473065
+              ],
+              [
+                128.76135,
+                49.482009
+              ],
+              [
+                128.763198,
+                49.515824
+              ],
+              [
+                128.813089,
+                49.558157
+              ],
+              [
+                128.802618,
+                49.58222
+              ],
+              [
+                128.744104,
+                49.595023
+              ],
+              [
+                128.715155,
+                49.564756
+              ],
+              [
+                128.656025,
+                49.577564
+              ],
+              [
+                128.619684,
+                49.593471
+              ],
+              [
+                128.537764,
+                49.604332
+              ],
+              [
+                128.500192,
+                49.593859
+              ],
+              [
+                128.389939,
+                49.58998
+              ],
+              [
+                128.343128,
+                49.544956
+              ],
+              [
+                128.287077,
+                49.566309
+              ],
+              [
+                128.243345,
+                49.563203
+              ],
+              [
+                128.185447,
+                49.53952
+              ],
+              [
+                128.122005,
+                49.55311
+              ],
+              [
+                128.070882,
+                49.556604
+              ],
+              [
+                128.001281,
+                49.592307
+              ],
+              [
+                127.949542,
+                49.596187
+              ],
+              [
+                127.897804,
+                49.579116
+              ],
+              [
+                127.815268,
+                49.593859
+              ],
+              [
+                127.782007,
+                49.630698
+              ],
+              [
+                127.705015,
+                49.665185
+              ],
+              [
+                127.677913,
+                49.697712
+              ],
+              [
+                127.674833,
+                49.764247
+              ],
+              [
+                127.653892,
+                49.780094
+              ],
+              [
+                127.583059,
+                49.786277
+              ],
+              [
+                127.531936,
+                49.826059
+              ],
+              [
+                127.529472,
+                49.864265
+              ],
+              [
+                127.547334,
+                49.928645
+              ],
+              [
+                127.543638,
+                49.944438
+              ],
+              [
+                127.495595,
+                49.994479
+              ],
+              [
+                127.501755,
+                50.056764
+              ],
+              [
+                127.58737,
+                50.137768
+              ],
+              [
+                127.60708,
+                50.178794
+              ],
+              [
+                127.603385,
+                50.239309
+              ],
+              [
+                127.44632,
+                50.270686
+              ],
+              [
+                127.371791,
+                50.29669
+              ],
+              [
+                127.332371,
+                50.340634
+              ],
+              [
+                127.369944,
+                50.403996
+              ],
+              [
+                127.3644,
+                50.438314
+              ],
+              [
+                127.30527,
+                50.45432
+              ],
+              [
+                127.293567,
+                50.46575
+              ],
+              [
+                127.323132,
+                50.52552
+              ],
+              [
+                127.36132,
+                50.547582
+              ],
+              [
+                127.370559,
+                50.581415
+              ],
+              [
+                127.294799,
+                50.663426
+              ],
+              [
+                127.28864,
+                50.699451
+              ],
+              [
+                127.305886,
+                50.733932
+              ],
+              [
+                127.295415,
+                50.755139
+              ],
+              [
+                127.236285,
+                50.781256
+              ],
+              [
+                127.143894,
+                50.910111
+              ],
+              [
+                127.113713,
+                50.93765
+              ],
+              [
+                127.052119,
+                50.962911
+              ],
+              [
+                126.985597,
+                51.029202
+              ],
+              [
+                126.922772,
+                51.061937
+              ],
+              [
+                126.917844,
+                51.138977
+              ],
+              [
+                126.899982,
+                51.200518
+              ],
+              [
+                126.926467,
+                51.246244
+              ],
+              [
+                126.976358,
+                51.291551
+              ],
+              [
+                126.98375,
+                51.318863
+              ],
+              [
+                126.970815,
+                51.332327
+              ],
+              [
+                126.887047,
+                51.321856
+              ],
+              [
+                126.877808,
+                51.300906
+              ],
+              [
+                126.908605,
+                51.283691
+              ],
+              [
+                126.92154,
+                51.259729
+              ],
+              [
+                126.908605,
+                51.246619
+              ],
+              [
+                126.863025,
+                51.248492
+              ],
+              [
+                126.820526,
+                51.281071
+              ],
+              [
+                126.813134,
+                51.311756
+              ],
+              [
+                126.837156,
+                51.345038
+              ],
+              [
+                126.904293,
+                51.340552
+              ],
+              [
+                126.930163,
+                51.359241
+              ],
+              [
+                126.908605,
+                51.407423
+              ],
+              [
+                126.835308,
+                51.413769
+              ],
+              [
+                126.791577,
+                51.432428
+              ],
+              [
+                126.784185,
+                51.448095
+              ],
+              [
+                126.812518,
+                51.493948
+              ],
+              [
+                126.843931,
+                51.521885
+              ],
+              [
+                126.837156,
+                51.536033
+              ],
+              [
+                126.69549,
+                51.57845
+              ],
+              [
+                126.67886,
+                51.602246
+              ],
+              [
+                126.741069,
+                51.642374
+              ],
+              [
+                126.723823,
+                51.679126
+              ],
+              [
+                126.734294,
+                51.711399
+              ],
+              [
+                126.724439,
+                51.7266
+              ],
+              [
+                126.6727,
+                51.73179
+              ],
+              [
+                126.658534,
+                51.762544
+              ],
+              [
+                126.622809,
+                51.777357
+              ],
+              [
+                126.580925,
+                51.824728
+              ],
+              [
+                126.555056,
+                51.874266
+              ],
+              [
+                126.510092,
+                51.922274
+              ],
+              [
+                126.462665,
+                51.948471
+              ],
+              [
+                126.468208,
+                51.982395
+              ],
+              [
+                126.447882,
+                52.009294
+              ],
+              [
+                126.450962,
+                52.027709
+              ],
+              [
+                126.487918,
+                52.041699
+              ],
+              [
+                126.514404,
+                52.037282
+              ],
+              [
+                126.563679,
+                52.119302
+              ],
+              [
+                126.556288,
+                52.136203
+              ],
+              [
+                126.499005,
+                52.16044
+              ],
+              [
+                126.457121,
+                52.165212
+              ],
+              [
+                126.403535,
+                52.185031
+              ],
+              [
+                126.34502,
+                52.192002
+              ],
+              [
+                126.306832,
+                52.205574
+              ],
+              [
+                126.312992,
+                52.235271
+              ],
+              [
+                126.357955,
+                52.264216
+              ],
+              [
+                126.401071,
+                52.279597
+              ],
+              [
+                126.436795,
+                52.277034
+              ],
+              [
+                126.4331,
+                52.298632
+              ],
+              [
+                126.327774,
+                52.310342
+              ],
+              [
+                126.320999,
+                52.342163
+              ],
+              [
+                126.348716,
+                52.357882
+              ],
+              [
+                126.353644,
+                52.389304
+              ],
+              [
+                126.326542,
+                52.424353
+              ],
+              [
+                126.268644,
+                52.475051
+              ],
+              [
+                126.205202,
+                52.466302
+              ],
+              [
+                126.192883,
+                52.492181
+              ],
+              [
+                126.213209,
+                52.525327
+              ],
+              [
+                126.147304,
+                52.573
+              ],
+              [
+                126.066616,
+                52.603905
+              ],
+              [
+                126.055529,
+                52.582455
+              ],
+              [
+                126.030891,
+                52.576273
+              ],
+              [
+                125.989008,
+                52.603178
+              ],
+              [
+                125.968682,
+                52.630429
+              ],
+              [
+                125.971145,
+                52.654033
+              ],
+              [
+                125.995783,
+                52.675085
+              ],
+              [
+                126.061688,
+                52.673271
+              ],
+              [
+                126.072775,
+                52.691048
+              ],
+              [
+                126.044442,
+                52.739628
+              ],
+              [
+                126.112195,
+                52.757016
+              ],
+              [
+                126.116507,
+                52.768243
+              ],
+              [
+                126.052449,
+                52.800095
+              ],
+              [
+                126.02042,
+                52.795753
+              ],
+              [
+                125.985312,
+                52.758465
+              ],
+              [
+                125.966834,
+                52.759914
+              ],
+              [
+                125.937269,
+                52.786705
+              ],
+              [
+                125.923718,
+                52.815651
+              ],
+              [
+                125.855349,
+                52.866259
+              ],
+              [
+                125.854117,
+                52.891542
+              ],
+              [
+                125.827631,
+                52.899123
+              ],
+              [
+                125.772197,
+                52.89804
+              ],
+              [
+                125.751255,
+                52.88143
+              ],
+              [
+                125.722306,
+                52.880347
+              ],
+              [
+                125.678574,
+                52.86084
+              ],
+              [
+                125.666871,
+                52.869872
+              ],
+              [
+                125.665023,
+                52.913561
+              ],
+              [
+                125.737088,
+                52.943504
+              ],
+              [
+                125.742632,
+                52.993964
+              ],
+              [
+                125.684118,
+                53.00801
+              ],
+              [
+                125.643466,
+                53.039686
+              ],
+              [
+                125.640386,
+                53.06199
+              ],
+              [
+                125.613901,
+                53.083564
+              ],
+              [
+                125.588647,
+                53.081047
+              ],
+              [
+                125.530749,
+                53.0512
+              ],
+              [
+                125.504263,
+                53.061271
+              ],
+              [
+                125.503647,
+                53.095424
+              ],
+              [
+                125.452524,
+                53.107641
+              ],
+              [
+                125.343503,
+                53.14463
+              ],
+              [
+                125.315786,
+                53.144989
+              ],
+              [
+                125.252344,
+                53.18051
+              ],
+              [
+                125.195062,
+                53.198439
+              ],
+              [
+                125.142091,
+                53.204175
+              ],
+              [
+                125.038613,
+                53.202741
+              ],
+              [
+                124.970244,
+                53.194137
+              ],
+              [
+                124.887708,
+                53.164368
+              ],
+              [
+                124.909266,
+                53.118059
+              ],
+              [
+                124.87231,
+                53.099018
+              ],
+              [
+                124.832889,
+                53.145347
+              ],
+              [
+                124.787926,
+                53.140681
+              ],
+              [
+                124.734339,
+                53.146783
+              ],
+              [
+                124.712165,
+                53.162574
+              ],
+              [
+                124.720789,
+                53.192344
+              ],
+              [
+                124.678905,
+                53.207043
+              ],
+              [
+                124.590209,
+                53.208476
+              ],
+              [
+                124.563108,
+                53.201666
+              ],
+              [
+                124.496587,
+                53.207759
+              ],
+              [
+                124.487348,
+                53.217436
+              ],
+              [
+                124.435609,
+                53.223886
+              ],
+              [
+                124.412203,
+                53.248601
+              ],
+              [
+                124.375863,
+                53.258984
+              ],
+              [
+                124.327819,
+                53.331954
+              ],
+              [
+                124.239124,
+                53.379817
+              ],
+              [
+                124.19416,
+                53.37339
+              ],
+              [
+                124.125791,
+                53.348033
+              ],
+              [
+                124.058038,
+                53.404085
+              ],
+              [
+                124.01369,
+                53.403371
+              ],
+              [
+                123.985973,
+                53.434401
+              ],
+              [
+                123.865249,
+                53.489627
+              ],
+              [
+                123.797495,
+                53.489983
+              ],
+              [
+                123.746373,
+                53.500308
+              ],
+              [
+                123.698329,
+                53.498528
+              ],
+              [
+                123.668764,
+                53.533756
+              ],
+              [
+                123.620721,
+                53.550115
+              ],
+              [
+                123.58746,
+                53.546915
+              ],
+              [
+                123.569598,
+                53.505291
+              ],
+              [
+                123.53141,
+                53.507071
+              ],
+              [
+                123.557895,
+                53.531978
+              ],
+              [
+                123.546808,
+                53.551537
+              ],
+              [
+                123.517243,
+                53.558292
+              ],
+              [
+                123.490758,
+                53.542648
+              ],
+              [
+                123.510468,
+                53.509206
+              ],
+              [
+                123.499381,
+                53.497816
+              ],
+              [
+                123.47228,
+                53.509206
+              ],
+              [
+                123.454417,
+                53.536602
+              ],
+              [
+                123.394055,
+                53.538024
+              ],
+              [
+                123.309672,
+                53.56078
+              ],
+              [
+                123.274563,
+                53.563269
+              ],
+              [
+                123.231447,
+                53.549404
+              ],
+              [
+                123.179092,
+                53.509918
+              ],
+              [
+                123.137209,
+                53.498172
+              ],
+              [
+                123.093477,
+                53.508138
+              ],
+              [
+                123.052209,
+                53.506715
+              ],
+              [
+                122.943804,
+                53.483929
+              ],
+              [
+                122.894528,
+                53.462914
+              ],
+              [
+                122.826775,
+                53.457213
+              ],
+              [
+                122.763949,
+                53.463626
+              ],
+              [
+                122.673406,
+                53.459351
+              ],
+              [
+                122.608117,
+                53.465408
+              ],
+              [
+                122.5379,
+                53.453293
+              ],
+              [
+                122.496016,
+                53.458638
+              ],
+              [
+                122.435038,
+                53.444739
+              ],
+              [
+                122.37406,
+                53.47467
+              ],
+              [
+                122.350038,
+                53.505647
+              ],
+              [
+                122.266886,
+                53.470039
+              ],
+              [
+                122.227466,
+                53.461845
+              ],
+              [
+                122.161561,
+                53.468614
+              ],
+              [
+                122.111054,
+                53.426913
+              ],
+              [
+                122.077177,
+                53.422277
+              ],
+              [
+                122.026054,
+                53.428339
+              ],
+              [
+                121.875765,
+                53.426556
+              ],
+              [
+                121.816019,
+                53.41336
+              ],
+              [
+                121.754425,
+                53.389454
+              ],
+              [
+                121.697758,
+                53.392666
+              ],
+              [
+                121.589969,
+                53.350891
+              ],
+              [
+                121.499426,
+                53.337314
+              ],
+              [
+                121.504969,
+                53.323018
+              ],
+              [
+                121.575802,
+                53.29155
+              ],
+              [
+                121.615222,
+                53.258984
+              ],
+              [
+                121.642324,
+                53.262564
+              ],
+              [
+                121.679896,
+                53.240722
+              ],
+              [
+                121.67928,
+                53.199515
+              ],
+              [
+                121.660186,
+                53.195213
+              ],
+              [
+                121.665114,
+                53.170467
+              ],
+              [
+                121.722396,
+                53.145706
+              ],
+              [
+                121.753193,
+                53.147501
+              ],
+              [
+                121.784606,
+                53.104408
+              ],
+              [
+                121.775367,
+                53.089674
+              ],
+              [
+                121.817867,
+                53.061631
+              ],
+              [
+                121.785838,
+                53.018451
+              ],
+              [
+                121.715621,
+                52.997926
+              ],
+              [
+                121.677432,
+                52.948192
+              ],
+              [
+                121.66265,
+                52.912478
+              ],
+              [
+                121.610295,
+                52.892264
+              ],
+              [
+                121.604136,
+                52.872401
+              ],
+              [
+                121.620766,
+                52.853251
+              ],
+              [
+                121.591201,
+                52.824693
+              ],
+              [
+                121.537614,
+                52.801542
+              ],
+              [
+                121.511129,
+                52.779104
+              ],
+              [
+                121.476636,
+                52.772225
+              ],
+              [
+                121.455078,
+                52.73528
+              ],
+              [
+                121.373158,
+                52.683067
+              ],
+              [
+                121.309717,
+                52.676173
+              ],
+              [
+                121.29247,
+                52.651855
+              ],
+              [
+                121.237036,
+                52.619167
+              ],
+              [
+                121.182217,
+                52.59918
+              ],
+              [
+                121.225333,
+                52.577364
+              ],
+              [
+                121.280151,
+                52.586819
+              ],
+              [
+                121.323883,
+                52.573727
+              ],
+              [
+                121.353448,
+                52.534793
+              ],
+              [
+                121.411963,
+                52.52205
+              ],
+              [
+                121.416274,
+                52.499468
+              ],
+              [
+                121.474172,
+                52.482706
+              ],
+              [
+                121.495114,
+                52.484892
+              ],
+              [
+                121.519136,
+                52.456821
+              ],
+              [
+                121.565331,
+                52.460468
+              ],
+              [
+                121.590585,
+                52.443326
+              ],
+              [
+                121.63986,
+                52.44442
+              ],
+              [
+                121.678664,
+                52.419973
+              ],
+              [
+                121.658338,
+                52.3904
+              ],
+              [
+                121.715621,
+                52.342894
+              ],
+              [
+                121.714389,
+                52.318025
+              ],
+              [
+                121.769207,
+                52.308147
+              ],
+              [
+                121.841272,
+                52.282526
+              ],
+              [
+                121.901018,
+                52.280695
+              ],
+              [
+                121.94783,
+                52.298266
+              ],
+              [
+                121.976779,
+                52.343626
+              ],
+              [
+                122.035909,
+                52.377615
+              ],
+              [
+                122.040837,
+                52.413038
+              ],
+              [
+                122.091344,
+                52.427272
+              ],
+              [
+                122.080873,
+                52.440407
+              ],
+              [
+                122.107358,
+                52.452445
+              ],
+              [
+                122.142467,
+                52.495096
+              ],
+              [
+                122.140003,
+                52.510032
+              ],
+              [
+                122.168952,
+                52.513674
+              ],
+              [
+                122.178191,
+                52.48963
+              ],
+              [
+                122.207756,
+                52.469218
+              ],
+              [
+                122.310618,
+                52.475416
+              ],
+              [
+                122.326016,
+                52.459374
+              ],
+              [
+                122.342031,
+                52.414133
+              ],
+              [
+                122.367284,
+                52.413768
+              ],
+              [
+                122.378987,
+                52.395512
+              ],
+              [
+                122.419023,
+                52.375057
+              ],
+              [
+                122.447356,
+                52.394052
+              ],
+              [
+                122.484313,
+                52.341432
+              ],
+              [
+                122.478153,
+                52.29607
+              ],
+              [
+                122.560689,
+                52.282526
+              ],
+              [
+                122.585943,
+                52.266413
+              ],
+              [
+                122.67895,
+                52.276667
+              ],
+              [
+                122.710979,
+                52.256157
+              ],
+              [
+                122.76087,
+                52.26678
+              ],
+              [
+                122.787355,
+                52.252494
+              ],
+              [
+                122.766413,
+                52.232705
+              ],
+              [
+                122.769493,
+                52.179893
+              ],
+              [
+                122.73808,
+                52.153464
+              ],
+              [
+                122.690653,
+                52.140243
+              ],
+              [
+                122.629059,
+                52.13657
+              ],
+              [
+                122.643841,
+                52.111585
+              ],
+              [
+                122.625363,
+                52.067459
+              ],
+              [
+                122.650616,
+                52.058997
+              ],
+              [
+                122.664783,
+                51.99861
+              ],
+              [
+                122.683877,
+                51.974654
+              ],
+              [
+                122.726377,
+                51.978709
+              ],
+              [
+                122.729457,
+                51.919321
+              ],
+              [
+                122.706051,
+                51.890151
+              ],
+              [
+                122.725761,
+                51.87833
+              ],
+              [
+                122.732536,
+                51.832495
+              ],
+              [
+                122.771957,
+                51.779579
+              ],
+              [
+                122.749167,
+                51.746613
+              ],
+              [
+                122.778732,
+                51.698048
+              ],
+              [
+                122.816304,
+                51.655371
+              ],
+              [
+                122.820616,
+                51.633088
+              ],
+              [
+                122.85634,
+                51.606707
+              ],
+              [
+                122.832935,
+                51.581797
+              ],
+              [
+                122.874202,
+                51.561339
+              ],
+              [
+                122.880362,
+                51.537894
+              ],
+              [
+                122.858804,
+                51.524864
+              ],
+              [
+                122.880362,
+                51.511085
+              ],
+              [
+                122.854492,
+                51.477551
+              ],
+              [
+                122.871123,
+                51.455181
+              ],
+              [
+                122.900072,
+                51.445112
+              ],
+              [
+                122.903768,
+                51.415262
+              ],
+              [
+                122.946267,
+                51.405183
+              ],
+              [
+                122.965977,
+                51.386886
+              ],
+              [
+                122.965977,
+                51.345786
+              ],
+              [
+                123.002934,
+                51.31213
+              ],
+              [
+                123.069455,
+                51.321108
+              ],
+              [
+                123.127969,
+                51.297913
+              ],
+              [
+                123.231447,
+                51.279199
+              ],
+              [
+                123.231447,
+                51.268716
+              ],
+              [
+                123.294273,
+                51.254111
+              ],
+              [
+                123.339853,
+                51.27246
+              ],
+              [
+                123.376809,
+                51.266844
+              ],
+              [
+                123.414381,
+                51.278825
+              ],
+              [
+                123.440251,
+                51.270963
+              ],
+              [
+                123.46304,
+                51.286686
+              ],
+              [
+                123.582533,
+                51.294545
+              ],
+              [
+                123.582533,
+                51.306893
+              ],
+              [
+                123.661989,
+                51.319237
+              ],
+              [
+                123.660141,
+                51.342795
+              ],
+              [
+                123.711264,
+                51.398089
+              ],
+              [
+                123.794416,
+                51.361109
+              ],
+              [
+                123.842459,
+                51.367462
+              ],
+              [
+                123.887423,
+                51.320734
+              ],
+              [
+                123.926227,
+                51.300532
+              ],
+              [
+                123.939777,
+                51.313253
+              ],
+              [
+                123.994596,
+                51.322604
+              ],
+              [
+                124.071588,
+                51.320734
+              ],
+              [
+                124.090067,
+                51.3413
+              ],
+              [
+                124.128255,
+                51.347281
+              ],
+              [
+                124.192313,
+                51.33943
+              ],
+              [
+                124.239124,
+                51.344664
+              ],
+              [
+                124.271769,
+                51.308389
+              ],
+              [
+                124.297638,
+                51.298661
+              ],
+              [
+                124.339522,
+                51.293422
+              ],
+              [
+                124.406659,
+                51.272086
+              ],
+              [
+                124.430065,
+                51.301281
+              ],
+              [
+                124.426985,
+                51.331953
+              ],
+              [
+                124.443616,
+                51.35812
+              ],
+              [
+                124.478108,
+                51.36223
+              ],
+              [
+                124.490427,
+                51.380537
+              ],
+              [
+                124.555717,
+                51.375307
+              ],
+              [
+                124.58713,
+                51.363725
+              ],
+              [
+                124.62655,
+                51.327465
+              ],
+              [
+                124.693687,
+                51.3327
+              ],
+              [
+                124.752817,
+                51.35812
+              ],
+              [
+                124.76452,
+                51.38726
+              ],
+              [
+                124.783614,
+                51.392115
+              ],
+              [
+                124.864302,
+                51.37979
+              ],
+              [
+                124.885244,
+                51.40817
+              ],
+              [
+                124.942527,
+                51.447349
+              ],
+              [
+                124.917889,
+                51.474196
+              ],
+              [
+                124.928976,
+                51.498419
+              ],
+              [
+                124.983795,
+                51.508478
+              ],
+              [
+                125.004737,
+                51.529332
+              ],
+              [
+                125.047236,
+                51.529704
+              ],
+              [
+                125.073106,
+                51.553526
+              ],
+              [
+                125.060171,
+                51.59667
+              ],
+              [
+                125.098975,
+                51.658341
+              ],
+              [
+                125.12854,
+                51.659083
+              ],
+              [
+                125.130388,
+                51.635317
+              ],
+              [
+                125.175968,
+                51.639403
+              ],
+              [
+                125.214772,
+                51.627888
+              ],
+              [
+                125.228938,
+                51.640517
+              ],
+              [
+                125.289301,
+                51.633831
+              ],
+              [
+                125.316402,
+                51.610052
+              ],
+              [
+                125.35151,
+                51.623801
+              ],
+              [
+                125.38046,
+                51.585516
+              ],
+              [
+                125.424807,
+                51.562827
+              ],
+              [
+                125.528285,
+                51.488359
+              ],
+              [
+                125.559082,
+                51.461521
+              ],
+              [
+                125.559082,
+                51.461521
+              ],
+              [
+                125.595422,
+                51.416755
+              ],
+              [
+                125.595422,
+                51.416755
+              ],
+              [
+                125.60035,
+                51.413396
+              ],
+              [
+                125.60035,
+                51.413396
+              ],
+              [
+                125.600966,
+                51.410409
+              ],
+              [
+                125.600966,
+                51.410409
+              ],
+              [
+                125.62314,
+                51.398089
+              ],
+              [
+                125.62314,
+                51.398089
+              ],
+              [
+                125.623756,
+                51.387633
+              ],
+              [
+                125.623756,
+                51.387633
+              ],
+              [
+                125.626219,
+                51.380163
+              ],
+              [
+                125.626219,
+                51.380163
+              ],
+              [
+                125.700132,
+                51.327465
+              ],
+              [
+                125.700132,
+                51.327465
+              ],
+              [
+                125.740784,
+                51.27583
+              ],
+              [
+                125.740784,
+                51.27583
+              ],
+              [
+                125.76111,
+                51.261976
+              ],
+              [
+                125.76111,
+                51.261976
+              ],
+              [
+                125.761726,
+                51.226385
+              ],
+              [
+                125.819008,
+                51.227134
+              ],
+              [
+                125.850421,
+                51.21364
+              ],
+              [
+                125.864588,
+                51.146487
+              ],
+              [
+                125.909551,
+                51.138977
+              ],
+              [
+                125.946508,
+                51.108176
+              ],
+              [
+                125.970529,
+                51.123955
+              ],
+              [
+                125.993935,
+                51.119072
+              ],
+              [
+                125.976073,
+                51.084498
+              ],
+              [
+                126.059225,
+                51.043503
+              ],
+              [
+                126.033971,
+                51.011132
+              ],
+              [
+                126.041978,
+                50.981753
+              ],
+              [
+                126.068464,
+                50.967434
+              ],
+              [
+                126.042594,
+                50.92558
+              ],
+              [
+                126.02042,
+                50.927466
+              ],
+              [
+                125.996399,
+                50.906715
+              ],
+              [
+                125.997631,
+                50.872738
+              ],
+              [
+                125.961906,
+                50.901054
+              ],
+              [
+                125.939732,
+                50.85423
+              ],
+              [
+                125.913247,
+                50.825885
+              ],
+              [
+                125.878138,
+                50.816812
+              ],
+              [
+                125.890457,
+                50.805845
+              ],
+              [
+                125.836255,
+                50.793363
+              ],
+              [
+                125.846726,
+                50.769524
+              ],
+              [
+                125.828863,
+                50.756654
+              ],
+              [
+                125.804226,
+                50.773309
+              ],
+              [
+                125.758646,
+                50.746809
+              ],
+              [
+                125.795603,
+                50.738856
+              ],
+              [
+                125.78082,
+                50.725598
+              ],
+              [
+                125.825784,
+                50.70362
+              ],
+              [
+                125.789443,
+                50.679735
+              ],
+              [
+                125.804226,
+                50.658874
+              ],
+              [
+                125.793139,
+                50.643316
+              ],
+              [
+                125.814697,
+                50.62092
+              ],
+              [
+                125.807921,
+                50.60383
+              ],
+              [
+                125.829479,
+                50.56165
+              ],
+              [
+                125.794987,
+                50.532748
+              ],
+              [
+                125.770349,
+                50.531227
+              ],
+              [
+                125.754335,
+                50.506874
+              ],
+              [
+                125.740784,
+                50.523237
+              ],
+              [
+                125.699516,
+                50.487078
+              ],
+              [
+                125.654553,
+                50.471082
+              ],
+              [
+                125.627451,
+                50.443268
+              ],
+              [
+                125.580024,
+                50.449366
+              ],
+              [
+                125.562162,
+                50.438314
+              ],
+              [
+                125.583104,
+                50.409717
+              ],
+              [
+                125.567089,
+                50.402852
+              ],
+              [
+                125.536292,
+                50.420014
+              ],
+              [
+                125.522126,
+                50.404759
+              ],
+              [
+                125.546763,
+                50.358965
+              ],
+              [
+                125.520278,
+                50.3498
+              ],
+              [
+                125.530749,
+                50.331085
+              ],
+              [
+                125.463611,
+                50.295925
+              ],
+              [
+                125.466075,
+                50.266861
+              ],
+              [
+                125.442053,
+                50.260357
+              ],
+              [
+                125.448829,
+                50.216338
+              ],
+              [
+                125.417416,
+                50.195654
+              ],
+              [
+                125.39093,
+                50.199868
+              ],
+              [
+                125.382923,
+                50.172278
+              ],
+              [
+                125.335496,
+                50.161161
+              ],
+              [
+                125.376148,
+                50.137385
+              ],
+              [
+                125.311474,
+                50.140453
+              ],
+              [
+                125.27883,
+                50.127411
+              ],
+              [
+                125.258504,
+                50.103618
+              ],
+              [
+                125.287453,
+                50.093636
+              ],
+              [
+                125.283757,
+                50.070211
+              ],
+              [
+                125.328105,
+                50.065985
+              ],
+              [
+                125.315786,
+                50.04562
+              ],
+              [
+                125.289916,
+                50.057917
+              ],
+              [
+                125.25296,
+                50.041393
+              ],
+              [
+                125.283757,
+                50.036012
+              ],
+              [
+                125.297924,
+                50.014481
+              ],
+              [
+                125.278214,
+                49.996402
+              ],
+              [
+                125.241873,
+                49.987938
+              ],
+              [
+                125.231402,
+                49.957531
+              ],
+              [
+                125.190134,
+                49.959841
+              ],
+              [
+                125.199373,
+                49.935194
+              ],
+              [
+                125.225859,
+                49.922481
+              ],
+              [
+                125.212924,
+                49.907452
+              ],
+              [
+                125.245569,
+                49.87198
+              ],
+              [
+                125.225243,
+                49.867351
+              ],
+              [
+                125.239409,
+                49.844587
+              ],
+              [
+                125.177815,
+                49.829533
+              ],
+              [
+                125.222779,
+                49.799026
+              ],
+              [
+                125.221547,
+                49.754969
+              ],
+              [
+                125.204301,
+                49.734086
+              ],
+              [
+                125.225243,
+                49.726349
+              ],
+              [
+                125.219699,
+                49.669058
+              ],
+              [
+                125.185207,
+                49.634574
+              ],
+              [
+                125.189518,
+                49.652401
+              ],
+              [
+                125.164881,
+                49.669446
+              ],
+              [
+                125.132236,
+                49.672157
+              ],
+              [
+                125.127308,
+                49.655113
+              ],
+              [
+                125.15441,
+                49.616741
+              ],
+              [
+                125.16796,
+                49.629923
+              ],
+              [
+                125.205533,
+                49.593859
+              ],
+              [
+                125.23017,
+                49.595411
+              ],
+              [
+                125.233866,
+                49.536801
+              ],
+              [
+                125.211076,
+                49.539908
+              ],
+              [
+                125.228323,
+                49.487063
+              ],
+              [
+                125.270822,
+                49.454395
+              ],
+              [
+                125.256656,
+                49.437275
+              ],
+              [
+                125.25604,
+                49.395227
+              ],
+              [
+                125.277598,
+                49.379644
+              ],
+              [
+                125.256656,
+                49.359769
+              ],
+              [
+                125.261583,
+                49.322336
+              ],
+              [
+                125.214772,
+                49.277066
+              ],
+              [
+                125.227707,
+                49.248947
+              ],
+              [
+                125.219699,
+                49.189139
+              ],
+              [
+                125.187671,
+                49.186792
+              ],
+              [
+                125.158721,
+                49.144921
+              ],
+              [
+                125.117453,
+                49.126127
+              ],
+              [
+                125.034302,
+                49.157056
+              ],
+              [
+                125.039845,
+                49.17623
+              ],
+              [
+                124.983179,
+                49.162535
+              ],
+              [
+                124.906802,
+                49.184054
+              ],
+              [
+                124.860607,
+                49.166448
+              ],
+              [
+                124.847672,
+                49.129651
+              ],
+              [
+                124.809484,
+                49.115943
+              ],
+              [
+                124.828578,
+                49.077933
+              ],
+              [
+                124.808252,
+                49.020666
+              ],
+              [
+                124.756513,
+                48.967262
+              ],
+              [
+                124.744194,
+                48.920487
+              ],
+              [
+                124.709086,
+                48.920487
+              ],
+              [
+                124.715861,
+                48.885475
+              ],
+              [
+                124.697383,
+                48.841775
+              ],
+              [
+                124.654267,
+                48.83429
+              ],
+              [
+                124.644412,
+                48.80789
+              ],
+              [
+                124.656115,
+                48.783842
+              ],
+              [
+                124.612383,
+                48.747945
+              ],
+              [
+                124.624702,
+                48.701755
+              ],
+              [
+                124.601912,
+                48.632587
+              ],
+              [
+                124.579122,
+                48.596582
+              ],
+              [
+                124.520608,
+                48.556195
+              ],
+              [
+                124.548941,
+                48.535593
+              ],
+              [
+                124.533543,
+                48.515379
+              ],
+              [
+                124.555717,
+                48.467784
+              ],
+              [
+                124.507674,
+                48.445558
+              ],
+              [
+                124.52492,
+                48.426897
+              ],
+              [
+                124.51876,
+                48.378027
+              ],
+              [
+                124.547094,
+                48.35775
+              ],
+              [
+                124.540934,
+                48.335476
+              ],
+              [
+                124.579738,
+                48.297269
+              ],
+              [
+                124.558796,
+                48.268197
+              ],
+              [
+                124.579122,
+                48.262221
+              ],
+              [
+                124.547094,
+                48.200829
+              ],
+              [
+                124.512601,
+                48.164518
+              ],
+              [
+                124.529847,
+                48.146951
+              ],
+              [
+                124.505826,
+                48.124985
+              ],
+              [
+                124.478108,
+                48.123387
+              ],
+              [
+                124.46579,
+                48.098213
+              ],
+              [
+                124.415899,
+                48.08782
+              ],
+              [
+                124.430065,
+                48.12099
+              ],
+              [
+                124.471333,
+                48.133373
+              ],
+              [
+                124.475029,
+                48.173698
+              ],
+              [
+                124.418978,
+                48.181679
+              ],
+              [
+                124.412819,
+                48.219175
+              ],
+              [
+                124.422058,
+                48.245884
+              ],
+              [
+                124.365392,
+                48.283731
+              ],
+              [
+                124.353689,
+                48.315978
+              ],
+              [
+                124.317964,
+                48.35099
+              ],
+              [
+                124.331515,
+                48.380015
+              ],
+              [
+                124.309957,
+                48.413393
+              ],
+              [
+                124.330283,
+                48.435633
+              ],
+              [
+                124.302566,
+                48.456673
+              ],
+              [
+                124.314269,
+                48.503881
+              ],
+              [
+                124.25945,
+                48.536385
+              ],
+              [
+                124.25945,
+                48.536385
+              ],
+              [
+                124.136878,
+                48.463023
+              ],
+              [
+                124.07898,
+                48.43603
+              ],
+              [
+                124.019234,
+                48.39313
+              ],
+              [
+                123.862785,
+                48.271782
+              ],
+              [
+                123.746373,
+                48.197638
+              ],
+              [
+                123.705105,
+                48.152142
+              ],
+              [
+                123.579453,
+                48.045427
+              ],
+              [
+                123.537569,
+                48.021816
+              ],
+              [
+                123.300432,
+                47.953723
+              ],
+              [
+                123.256085,
+                47.876711
+              ],
+              [
+                123.214201,
+                47.824502
+              ],
+              [
+                123.161846,
+                47.781892
+              ],
+              [
+                123.041122,
+                47.746492
+              ],
+              [
+                122.926557,
+                47.697777
+              ],
+              [
+                122.848949,
+                47.67441
+              ],
+              [
+                122.765181,
+                47.614333
+              ],
+              [
+                122.59395,
+                47.54732
+              ],
+              [
+                122.543443,
+                47.495589
+              ],
+              [
+                122.507103,
+                47.401291
+              ],
+              [
+                122.418407,
+                47.350632
+              ],
+              [
+                122.441197,
+                47.310476
+              ],
+              [
+                122.441197,
+                47.310476
+              ],
+              [
+                122.462755,
+                47.27841
+              ],
+              [
+                122.498479,
+                47.255262
+              ],
+              [
+                122.531124,
+                47.198771
+              ],
+              [
+                122.582863,
+                47.158092
+              ],
+              [
+                122.582863,
+                47.158092
+              ],
+              [
+                122.615508,
+                47.124306
+              ],
+              [
+                122.679566,
+                47.094164
+              ],
+              [
+                122.710363,
+                47.093349
+              ],
+              [
+                122.710363,
+                47.093349
+              ],
+              [
+                122.821232,
+                47.065636
+              ],
+              [
+                122.852645,
+                47.072158
+              ],
+              [
+                122.845869,
+                47.046881
+              ],
+              [
+                122.778116,
+                47.002822
+              ],
+              [
+                122.77442,
+                46.973837
+              ],
+              [
+                122.798442,
+                46.9575
+              ],
+              [
+                122.791051,
+                46.941567
+              ],
+              [
+                122.83971,
+                46.937072
+              ],
+              [
+                122.895144,
+                46.960359
+              ],
+              [
+                122.893913,
+                46.895376
+              ],
+              [
+                122.906847,
+                46.80738
+              ],
+              [
+                122.996774,
+                46.761483
+              ],
+              [
+                123.00355,
+                46.730726
+              ],
+              [
+                123.026339,
+                46.718829
+              ],
+              [
+                123.076846,
+                46.745082
+              ],
+              [
+                123.103332,
+                46.734828
+              ],
+              [
+                123.163694,
+                46.74016
+              ],
+              [
+                123.198802,
+                46.803283
+              ],
+              [
+                123.22344,
+                46.821305
+              ],
+              [
+                123.221592,
+                46.850373
+              ],
+              [
+                123.295505,
+                46.865105
+              ],
+              [
+                123.341084,
+                46.826628
+              ],
+              [
+                123.374345,
+                46.837683
+              ],
+              [
+                123.40699,
+                46.906416
+              ],
+              [
+                123.404526,
+                46.935438
+              ],
+              [
+                123.360179,
+                46.970978
+              ],
+              [
+                123.304128,
+                46.964852
+              ],
+              [
+                123.301664,
+                46.999965
+              ],
+              [
+                123.337389,
+                46.988943
+              ],
+              [
+                123.42362,
+                46.934212
+              ],
+              [
+                123.487678,
+                46.959951
+              ],
+              [
+                123.52833,
+                46.944836
+              ],
+              [
+                123.483366,
+                46.84587
+              ],
+              [
+                123.506772,
+                46.827038
+              ],
+              [
+                123.562823,
+                46.82581
+              ],
+              [
+                123.575757,
+                46.845461
+              ],
+              [
+                123.576989,
+                46.891286
+              ],
+              [
+                123.605322,
+                46.891286
+              ],
+              [
+                123.599163,
+                46.868378
+              ],
+              [
+                123.625648,
+                46.847508
+              ],
+              [
+                123.580069,
+                46.827447
+              ],
+              [
+                123.629344,
+                46.813524
+              ],
+              [
+                123.631808,
+                46.728675
+              ],
+              [
+                123.603475,
+                46.68928
+              ],
+              [
+                123.474743,
+                46.686817
+              ],
+              [
+                123.366338,
+                46.677784
+              ],
+              [
+                123.318295,
+                46.662179
+              ],
+              [
+                123.276411,
+                46.660947
+              ],
+              [
+                123.279491,
+                46.616981
+              ],
+              [
+                123.228368,
+                46.588198
+              ],
+              [
+                123.18094,
+                46.614103
+              ],
+              [
+                123.098404,
+                46.603002
+              ],
+              [
+                123.077462,
+                46.622324
+              ],
+              [
+                123.04605,
+                46.617803
+              ],
+              [
+                123.052825,
+                46.579972
+              ],
+              [
+                123.002318,
+                46.574624
+              ],
+              [
+                123.010325,
+                46.524823
+              ],
+              [
+                123.011557,
+                46.434984
+              ],
+              [
+                123.089781,
+                46.347888
+              ],
+              [
+                123.142136,
+                46.298293
+              ],
+              [
+                123.178476,
+                46.248239
+              ],
+              [
+                123.248078,
+                46.273065
+              ],
+              [
+                123.286266,
+                46.250308
+              ],
+              [
+                123.320758,
+                46.254447
+              ],
+              [
+                123.357099,
+                46.232096
+              ],
+              [
+                123.357099,
+                46.232096
+              ],
+              [
+                123.430396,
+                46.243687
+              ],
+              [
+                123.452569,
+                46.233338
+              ],
+              [
+                123.499381,
+                46.259826
+              ],
+              [
+                123.569598,
+                46.223816
+              ],
+              [
+                123.569598,
+                46.223816
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 310000,
+        "name": "涓婃捣甯�",
+        "center": [
+          121.472644,
+          31.231706
+        ],
+        "centroid": [
+          121.438737,
+          31.072559
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 8,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                120.901349,
+                31.017327
+              ],
+              [
+                120.940153,
+                31.010146
+              ],
+              [
+                120.949392,
+                31.030148
+              ],
+              [
+                120.989428,
+                31.01425
+              ],
+              [
+                121.000515,
+                30.938309
+              ],
+              [
+                120.993124,
+                30.889532
+              ],
+              [
+                121.020225,
+                30.872069
+              ],
+              [
+                120.991892,
+                30.837133
+              ],
+              [
+                121.038087,
+                30.814007
+              ],
+              [
+                121.060261,
+                30.845354
+              ],
+              [
+                121.097833,
+                30.857171
+              ],
+              [
+                121.13787,
+                30.826342
+              ],
+              [
+                121.123087,
+                30.77905
+              ],
+              [
+                121.174826,
+                30.771851
+              ],
+              [
+                121.21671,
+                30.785734
+              ],
+              [
+                121.232108,
+                30.755909
+              ],
+              [
+                121.272144,
+                30.723504
+              ],
+              [
+                121.274608,
+                30.677191
+              ],
+              [
+                121.362071,
+                30.679764
+              ],
+              [
+                121.426129,
+                30.730192
+              ],
+              [
+                121.517288,
+                30.775451
+              ],
+              [
+                121.601056,
+                30.805269
+              ],
+              [
+                121.681128,
+                30.818633
+              ],
+              [
+                121.904714,
+                30.814007
+              ],
+              [
+                121.943518,
+                30.776993
+              ],
+              [
+                121.970004,
+                30.789333
+              ],
+              [
+                121.954605,
+                30.825828
+              ],
+              [
+                121.994025,
+                30.862823
+              ],
+              [
+                121.990945,
+                30.96859
+              ],
+              [
+                121.977395,
+                31.016301
+              ],
+              [
+                121.946598,
+                31.066039
+              ],
+              [
+                121.809859,
+                31.196669
+              ],
+              [
+                121.722396,
+                31.3036
+              ],
+              [
+                121.599208,
+                31.37465
+              ],
+              [
+                121.520984,
+                31.394575
+              ],
+              [
+                121.404571,
+                31.479337
+              ],
+              [
+                121.343593,
+                31.511996
+              ],
+              [
+                121.301093,
+                31.49873
+              ],
+              [
+                121.301093,
+                31.49873
+              ],
+              [
+                121.247507,
+                31.476785
+              ],
+              [
+                121.241963,
+                31.493117
+              ],
+              [
+                121.174826,
+                31.44922
+              ],
+              [
+                121.143413,
+                31.392021
+              ],
+              [
+                121.113848,
+                31.37465
+              ],
+              [
+                121.130478,
+                31.343987
+              ],
+              [
+                121.142797,
+                31.275472
+              ],
+              [
+                121.090442,
+                31.291838
+              ],
+              [
+                121.060261,
+                31.245289
+              ],
+              [
+                121.076892,
+                31.158267
+              ],
+              [
+                121.018377,
+                31.134194
+              ],
+              [
+                120.930298,
+                31.141365
+              ],
+              [
+                120.881023,
+                31.134706
+              ],
+              [
+                120.859465,
+                31.100379
+              ],
+              [
+                120.890878,
+                31.094229
+              ],
+              [
+                120.901349,
+                31.017327
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.974931,
+                31.61704
+              ],
+              [
+                121.715005,
+                31.673592
+              ],
+              [
+                121.64294,
+                31.697527
+              ],
+              [
+                121.599824,
+                31.703128
+              ],
+              [
+                121.49881,
+                31.753012
+              ],
+              [
+                121.431673,
+                31.769295
+              ],
+              [
+                121.384861,
+                31.833382
+              ],
+              [
+                121.323267,
+                31.868458
+              ],
+              [
+                121.265369,
+                31.863883
+              ],
+              [
+                121.200079,
+                31.834907
+              ],
+              [
+                121.118775,
+                31.759119
+              ],
+              [
+                121.145261,
+                31.75403
+              ],
+              [
+                121.289391,
+                31.61653
+              ],
+              [
+                121.371926,
+                31.553314
+              ],
+              [
+                121.395332,
+                31.585437
+              ],
+              [
+                121.434136,
+                31.590535
+              ],
+              [
+                121.547469,
+                31.531382
+              ],
+              [
+                121.625693,
+                31.501792
+              ],
+              [
+                121.682976,
+                31.491075
+              ],
+              [
+                121.819098,
+                31.437987
+              ],
+              [
+                121.890547,
+                31.428795
+              ],
+              [
+                121.981706,
+                31.464024
+              ],
+              [
+                121.995873,
+                31.493117
+              ],
+              [
+                121.974931,
+                31.61704
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.795693,
+                31.330186
+              ],
+              [
+                121.792613,
+                31.363408
+              ],
+              [
+                121.742106,
+                31.407345
+              ],
+              [
+                121.585657,
+                31.454836
+              ],
+              [
+                121.567179,
+                31.48342
+              ],
+              [
+                121.520984,
+                31.494137
+              ],
+              [
+                121.509897,
+                31.4824
+              ],
+              [
+                121.572107,
+                31.435944
+              ],
+              [
+                121.727939,
+                31.35472
+              ],
+              [
+                121.76428,
+                31.31536
+              ],
+              [
+                121.785222,
+                31.31127
+              ],
+              [
+                121.795693,
+                31.330186
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.801852,
+                31.356765
+              ],
+              [
+                121.8037,
+                31.328652
+              ],
+              [
+                121.840656,
+                31.295418
+              ],
+              [
+                121.932431,
+                31.283144
+              ],
+              [
+                122.016199,
+                31.282121
+              ],
+              [
+                122.097503,
+                31.255522
+              ],
+              [
+                122.122756,
+                31.307179
+              ],
+              [
+                122.116597,
+                31.320984
+              ],
+              [
+                122.040837,
+                31.324051
+              ],
+              [
+                121.951525,
+                31.337343
+              ],
+              [
+                121.845584,
+                31.37465
+              ],
+              [
+                121.792613,
+                31.377715
+              ],
+              [
+                121.801852,
+                31.356765
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.626925,
+                31.445135
+              ],
+              [
+                121.631853,
+                31.456878
+              ],
+              [
+                121.579498,
+                31.479848
+              ],
+              [
+                121.626925,
+                31.445135
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.943518,
+                31.215608
+              ],
+              [
+                121.959533,
+                31.159291
+              ],
+              [
+                121.995873,
+                31.160828
+              ],
+              [
+                122.008808,
+                31.221238
+              ],
+              [
+                121.950909,
+                31.228915
+              ],
+              [
+                121.943518,
+                31.215608
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.88254,
+                31.240684
+              ],
+              [
+                121.909026,
+                31.195133
+              ],
+              [
+                121.923808,
+                31.234032
+              ],
+              [
+                121.88254,
+                31.240684
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 320000,
+        "name": "姹熻嫃鐪�",
+        "center": [
+          118.767413,
+          32.041544
+        ],
+        "centroid": [
+          119.486506,
+          32.983991
+        ],
+        "childrenNum": 13,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 9,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                117.311654,
+                34.561686
+              ],
+              [
+                117.27285,
+                34.556757
+              ],
+              [
+                117.303647,
+                34.542463
+              ],
+              [
+                117.267923,
+                34.532603
+              ],
+              [
+                117.27285,
+                34.499565
+              ],
+              [
+                117.252524,
+                34.48674
+              ],
+              [
+                117.248213,
+                34.451216
+              ],
+              [
+                117.166293,
+                34.434435
+              ],
+              [
+                117.139191,
+                34.526687
+              ],
+              [
+                117.15151,
+                34.559222
+              ],
+              [
+                117.104083,
+                34.648874
+              ],
+              [
+                117.073286,
+                34.639026
+              ],
+              [
+                117.061583,
+                34.675947
+              ],
+              [
+                117.070206,
+                34.713835
+              ],
+              [
+                117.022163,
+                34.759081
+              ],
+              [
+                116.969192,
+                34.771864
+              ],
+              [
+                116.95133,
+                34.81069
+              ],
+              [
+                116.979047,
+                34.815113
+              ],
+              [
+                116.966113,
+                34.844588
+              ],
+              [
+                116.929156,
+                34.843114
+              ],
+              [
+                116.922381,
+                34.894671
+              ],
+              [
+                116.858323,
+                34.928533
+              ],
+              [
+                116.821983,
+                34.929515
+              ],
+              [
+                116.815823,
+                34.965324
+              ],
+              [
+                116.789338,
+                34.975133
+              ],
+              [
+                116.781331,
+                34.916757
+              ],
+              [
+                116.677853,
+                34.939327
+              ],
+              [
+                116.622418,
+                34.939818
+              ],
+              [
+                116.613795,
+                34.922645
+              ],
+              [
+                116.557745,
+                34.908905
+              ],
+              [
+                116.445028,
+                34.895652
+              ],
+              [
+                116.408071,
+                34.850972
+              ],
+              [
+                116.403144,
+                34.756131
+              ],
+              [
+                116.369267,
+                34.749247
+              ],
+              [
+                116.363724,
+                34.715311
+              ],
+              [
+                116.392057,
+                34.710391
+              ],
+              [
+                116.374195,
+                34.640011
+              ],
+              [
+                116.430245,
+                34.650843
+              ],
+              [
+                116.432709,
+                34.630163
+              ],
+              [
+                116.477057,
+                34.614896
+              ],
+              [
+                116.490607,
+                34.573513
+              ],
+              [
+                116.594085,
+                34.511894
+              ],
+              [
+                116.592237,
+                34.493646
+              ],
+              [
+                116.662454,
+                34.472927
+              ],
+              [
+                116.722816,
+                34.472434
+              ],
+              [
+                116.773939,
+                34.453683
+              ],
+              [
+                116.782563,
+                34.429993
+              ],
+              [
+                116.828142,
+                34.389012
+              ],
+              [
+                116.909446,
+                34.408271
+              ],
+              [
+                116.969192,
+                34.389012
+              ],
+              [
+                116.960569,
+                34.363821
+              ],
+              [
+                116.983359,
+                34.348011
+              ],
+              [
+                116.969192,
+                34.283753
+              ],
+              [
+                117.051112,
+                34.221425
+              ],
+              [
+                117.025243,
+                34.167469
+              ],
+              [
+                117.046801,
+                34.151622
+              ],
+              [
+                117.123793,
+                34.128342
+              ],
+              [
+                117.130568,
+                34.101586
+              ],
+              [
+                117.192162,
+                34.068873
+              ],
+              [
+                117.257452,
+                34.065899
+              ],
+              [
+                117.277162,
+                34.078787
+              ],
+              [
+                117.311654,
+                34.067882
+              ],
+              [
+                117.357234,
+                34.088205
+              ],
+              [
+                117.404045,
+                34.03218
+              ],
+              [
+                117.435458,
+                34.028212
+              ],
+              [
+                117.514914,
+                34.060941
+              ],
+              [
+                117.543248,
+                34.038627
+              ],
+              [
+                117.569117,
+                33.985051
+              ],
+              [
+                117.612849,
+                34.000433
+              ],
+              [
+                117.629479,
+                34.028708
+              ],
+              [
+                117.671363,
+                33.992494
+              ],
+              [
+                117.672595,
+                33.934916
+              ],
+              [
+                117.715095,
+                33.879287
+              ],
+              [
+                117.753899,
+                33.891211
+              ],
+              [
+                117.759442,
+                33.874318
+              ],
+              [
+                117.739732,
+                33.758467
+              ],
+              [
+                117.72495,
+                33.74951
+              ],
+              [
+                117.750203,
+                33.710688
+              ],
+              [
+                117.791471,
+                33.733585
+              ],
+              [
+                117.843826,
+                33.736074
+              ],
+              [
+                117.901724,
+                33.720146
+              ],
+              [
+                117.972557,
+                33.74951
+              ],
+              [
+                118.019985,
+                33.738562
+              ],
+              [
+                118.065564,
+                33.76593
+              ],
+              [
+                118.117919,
+                33.766427
+              ],
+              [
+                118.161035,
+                33.735576
+              ],
+              [
+                118.16781,
+                33.663381
+              ],
+              [
+                118.112376,
+                33.617045
+              ],
+              [
+                118.117919,
+                33.594615
+              ],
+              [
+                118.107448,
+                33.475391
+              ],
+              [
+                118.050782,
+                33.491863
+              ],
+              [
+                118.027376,
+                33.455421
+              ],
+              [
+                118.016905,
+                33.402978
+              ],
+              [
+                118.029224,
+                33.374995
+              ],
+              [
+                117.992883,
+                33.333005
+              ],
+              [
+                117.974405,
+                33.279487
+              ],
+              [
+                117.939297,
+                33.262475
+              ],
+              [
+                117.942376,
+                33.224936
+              ],
+              [
+                117.977485,
+                33.226437
+              ],
+              [
+                117.988572,
+                33.180869
+              ],
+              [
+                118.037231,
+                33.152314
+              ],
+              [
+                118.038463,
+                33.134776
+              ],
+              [
+                118.149332,
+                33.169348
+              ],
+              [
+                118.178281,
+                33.217926
+              ],
+              [
+                118.217085,
+                33.191888
+              ],
+              [
+                118.219549,
+                33.114227
+              ],
+              [
+                118.243571,
+                33.027967
+              ],
+              [
+                118.244803,
+                32.998359
+              ],
+              [
+                118.26944,
+                32.969242
+              ],
+              [
+                118.303933,
+                32.96874
+              ],
+              [
+                118.291614,
+                32.946143
+              ],
+              [
+                118.252194,
+                32.936601
+              ],
+              [
+                118.2331,
+                32.914498
+              ],
+              [
+                118.250346,
+                32.848157
+              ],
+              [
+                118.301469,
+                32.846145
+              ],
+              [
+                118.300237,
+                32.783275
+              ],
+              [
+                118.334114,
+                32.761637
+              ],
+              [
+                118.363063,
+                32.770695
+              ],
+              [
+                118.375382,
+                32.718849
+              ],
+              [
+                118.411106,
+                32.715828
+              ],
+              [
+                118.450526,
+                32.743518
+              ],
+              [
+                118.483787,
+                32.721367
+              ],
+              [
+                118.560163,
+                32.729926
+              ],
+              [
+                118.572482,
+                32.719856
+              ],
+              [
+                118.642699,
+                32.744525
+              ],
+              [
+                118.707373,
+                32.72036
+              ],
+              [
+                118.756648,
+                32.737477
+              ],
+              [
+                118.73817,
+                32.772708
+              ],
+              [
+                118.743097,
+                32.853184
+              ],
+              [
+                118.743097,
+                32.853184
+              ],
+              [
+                118.810235,
+                32.853687
+              ],
+              [
+                118.821322,
+                32.920527
+              ],
+              [
+                118.846575,
+                32.922034
+              ],
+              [
+                118.849039,
+                32.956689
+              ],
+              [
+                118.89585,
+                32.957694
+              ],
+              [
+                118.89585,
+                32.957694
+              ],
+              [
+                118.892771,
+                32.941121
+              ],
+              [
+                118.934039,
+                32.93861
+              ],
+              [
+                118.993169,
+                32.958196
+              ],
+              [
+                119.020886,
+                32.955685
+              ],
+              [
+                119.054763,
+                32.8748
+              ],
+              [
+                119.113277,
+                32.823014
+              ],
+              [
+                119.184726,
+                32.825529
+              ],
+              [
+                119.211827,
+                32.708275
+              ],
+              [
+                119.208748,
+                32.641276
+              ],
+              [
+                119.230921,
+                32.607001
+              ],
+              [
+                119.22045,
+                32.576748
+              ],
+              [
+                119.152697,
+                32.557582
+              ],
+              [
+                119.168096,
+                32.536394
+              ],
+              [
+                119.142226,
+                32.499556
+              ],
+              [
+                119.084944,
+                32.452602
+              ],
+              [
+                119.041212,
+                32.515201
+              ],
+              [
+                118.975923,
+                32.505108
+              ],
+              [
+                118.922336,
+                32.557078
+              ],
+              [
+                118.92172,
+                32.557078
+              ],
+              [
+                118.922336,
+                32.557078
+              ],
+              [
+                118.92172,
+                32.557078
+              ],
+              [
+                118.890923,
+                32.553042
+              ],
+              [
+                118.908169,
+                32.59238
+              ],
+              [
+                118.84288,
+                32.56767
+              ],
+              [
+                118.820706,
+                32.60448
+              ],
+              [
+                118.784981,
+                32.582295
+              ],
+              [
+                118.757264,
+                32.603976
+              ],
+              [
+                118.73509,
+                32.58885
+              ],
+              [
+                118.719076,
+                32.614059
+              ],
+              [
+                118.719076,
+                32.614059
+              ],
+              [
+                118.688895,
+                32.588346
+              ],
+              [
+                118.658714,
+                32.594397
+              ],
+              [
+                118.632844,
+                32.578261
+              ],
+              [
+                118.59712,
+                32.600951
+              ],
+              [
+                118.568787,
+                32.585825
+              ],
+              [
+                118.564475,
+                32.562122
+              ],
+              [
+                118.608823,
+                32.536899
+              ],
+              [
+                118.592192,
+                32.481383
+              ],
+              [
+                118.628533,
+                32.467751
+              ],
+              [
+                118.691359,
+                32.472295
+              ],
+              [
+                118.685199,
+                32.403604
+              ],
+              [
+                118.703061,
+                32.328792
+              ],
+              [
+                118.657482,
+                32.30148
+              ],
+              [
+                118.674728,
+                32.250375
+              ],
+              [
+                118.643931,
+                32.209875
+              ],
+              [
+                118.510888,
+                32.194176
+              ],
+              [
+                118.49549,
+                32.165304
+              ],
+              [
+                118.501033,
+                32.121726
+              ],
+              [
+                118.433896,
+                32.086746
+              ],
+              [
+                118.394476,
+                32.076098
+              ],
+              [
+                118.389548,
+                31.985281
+              ],
+              [
+                118.363679,
+                31.930443
+              ],
+              [
+                118.472084,
+                31.879639
+              ],
+              [
+                118.466541,
+                31.857784
+              ],
+              [
+                118.504729,
+                31.841516
+              ],
+              [
+                118.481939,
+                31.778453
+              ],
+              [
+                118.533678,
+                31.76726
+              ],
+              [
+                118.521975,
+                31.743343
+              ],
+              [
+                118.5577,
+                31.73011
+              ],
+              [
+                118.571866,
+                31.746397
+              ],
+              [
+                118.641467,
+                31.75861
+              ],
+              [
+                118.653786,
+                31.73011
+              ],
+              [
+                118.697518,
+                31.709747
+              ],
+              [
+                118.643315,
+                31.671555
+              ],
+              [
+                118.643315,
+                31.649651
+              ],
+              [
+                118.736322,
+                31.633347
+              ],
+              [
+                118.748025,
+                31.675629
+              ],
+              [
+                118.773894,
+                31.682759
+              ],
+              [
+                118.802844,
+                31.619078
+              ],
+              [
+                118.858894,
+                31.623665
+              ],
+              [
+                118.881684,
+                31.564023
+              ],
+              [
+                118.885995,
+                31.519139
+              ],
+              [
+                118.883532,
+                31.500261
+              ],
+              [
+                118.852119,
+                31.393553
+              ],
+              [
+                118.824401,
+                31.375672
+              ],
+              [
+                118.767735,
+                31.363919
+              ],
+              [
+                118.745561,
+                31.372606
+              ],
+              [
+                118.720924,
+                31.322518
+              ],
+              [
+                118.726467,
+                31.282121
+              ],
+              [
+                118.756648,
+                31.279564
+              ],
+              [
+                118.794836,
+                31.229426
+              ],
+              [
+                118.870597,
+                31.242219
+              ],
+              [
+                118.984546,
+                31.237102
+              ],
+              [
+                119.014727,
+                31.241707
+              ],
+              [
+                119.10527,
+                31.235055
+              ],
+              [
+                119.107118,
+                31.250917
+              ],
+              [
+                119.158241,
+                31.294907
+              ],
+              [
+                119.197661,
+                31.295418
+              ],
+              [
+                119.198277,
+                31.270357
+              ],
+              [
+                119.266646,
+                31.250405
+              ],
+              [
+                119.294363,
+                31.263195
+              ],
+              [
+                119.338095,
+                31.259103
+              ],
+              [
+                119.350414,
+                31.301043
+              ],
+              [
+                119.374435,
+                31.258591
+              ],
+              [
+                119.360269,
+                31.213049
+              ],
+              [
+                119.391682,
+                31.174142
+              ],
+              [
+                119.439109,
+                31.177214
+              ],
+              [
+                119.461283,
+                31.156219
+              ],
+              [
+                119.532732,
+                31.159291
+              ],
+              [
+                119.599869,
+                31.10909
+              ],
+              [
+                119.623891,
+                31.130096
+              ],
+              [
+                119.678093,
+                31.167997
+              ],
+              [
+                119.705811,
+                31.152634
+              ],
+              [
+                119.715666,
+                31.169533
+              ],
+              [
+                119.779723,
+                31.17875
+              ],
+              [
+                119.809904,
+                31.148536
+              ],
+              [
+                119.827151,
+                31.174142
+              ],
+              [
+                119.878274,
+                31.160828
+              ],
+              [
+                119.921389,
+                31.170045
+              ],
+              [
+                119.946027,
+                31.106016
+              ],
+              [
+                119.988527,
+                31.059375
+              ],
+              [
+                120.001461,
+                31.027071
+              ],
+              [
+                120.052584,
+                31.00553
+              ],
+              [
+                120.111099,
+                30.955761
+              ],
+              [
+                120.149903,
+                30.937283
+              ],
+              [
+                120.223816,
+                30.926502
+              ],
+              [
+                120.316206,
+                30.933689
+              ],
+              [
+                120.371025,
+                30.948575
+              ],
+              [
+                120.35809,
+                30.886964
+              ],
+              [
+                120.42338,
+                30.902884
+              ],
+              [
+                120.435083,
+                30.920855
+              ],
+              [
+                120.441858,
+                30.860768
+              ],
+              [
+                120.460336,
+                30.839702
+              ],
+              [
+                120.489285,
+                30.763624
+              ],
+              [
+                120.504684,
+                30.757967
+              ],
+              [
+                120.563814,
+                30.835592
+              ],
+              [
+                120.589684,
+                30.854089
+              ],
+              [
+                120.654973,
+                30.846896
+              ],
+              [
+                120.68269,
+                30.882342
+              ],
+              [
+                120.713487,
+                30.88491
+              ],
+              [
+                120.709176,
+                30.933176
+              ],
+              [
+                120.684538,
+                30.955247
+              ],
+              [
+                120.698089,
+                30.970643
+              ],
+              [
+                120.746132,
+                30.962432
+              ],
+              [
+                120.770154,
+                30.996809
+              ],
+              [
+                120.820661,
+                31.006556
+              ],
+              [
+                120.865624,
+                30.989627
+              ],
+              [
+                120.901349,
+                31.017327
+              ],
+              [
+                120.890878,
+                31.094229
+              ],
+              [
+                120.859465,
+                31.100379
+              ],
+              [
+                120.881023,
+                31.134706
+              ],
+              [
+                120.930298,
+                31.141365
+              ],
+              [
+                121.018377,
+                31.134194
+              ],
+              [
+                121.076892,
+                31.158267
+              ],
+              [
+                121.060261,
+                31.245289
+              ],
+              [
+                121.090442,
+                31.291838
+              ],
+              [
+                121.142797,
+                31.275472
+              ],
+              [
+                121.130478,
+                31.343987
+              ],
+              [
+                121.113848,
+                31.37465
+              ],
+              [
+                121.143413,
+                31.392021
+              ],
+              [
+                121.174826,
+                31.44922
+              ],
+              [
+                121.241963,
+                31.493117
+              ],
+              [
+                121.247507,
+                31.476785
+              ],
+              [
+                121.301093,
+                31.49873
+              ],
+              [
+                121.301093,
+                31.49873
+              ],
+              [
+                121.343593,
+                31.511996
+              ],
+              [
+                121.371926,
+                31.553314
+              ],
+              [
+                121.289391,
+                31.61653
+              ],
+              [
+                121.145261,
+                31.75403
+              ],
+              [
+                121.118775,
+                31.759119
+              ],
+              [
+                121.200079,
+                31.834907
+              ],
+              [
+                121.265369,
+                31.863883
+              ],
+              [
+                121.323267,
+                31.868458
+              ],
+              [
+                121.384861,
+                31.833382
+              ],
+              [
+                121.431673,
+                31.769295
+              ],
+              [
+                121.49881,
+                31.753012
+              ],
+              [
+                121.599824,
+                31.703128
+              ],
+              [
+                121.64294,
+                31.697527
+              ],
+              [
+                121.715005,
+                31.673592
+              ],
+              [
+                121.974931,
+                31.61704
+              ],
+              [
+                121.970004,
+                31.718911
+              ],
+              [
+                121.889315,
+                31.866425
+              ],
+              [
+                121.856055,
+                31.955328
+              ],
+              [
+                121.772287,
+                32.032984
+              ],
+              [
+                121.759352,
+                32.059362
+              ],
+              [
+                121.525295,
+                32.136423
+              ],
+              [
+                121.542542,
+                32.152132
+              ],
+              [
+                121.458774,
+                32.177462
+              ],
+              [
+                121.499426,
+                32.211394
+              ],
+              [
+                121.493882,
+                32.263533
+              ],
+              [
+                121.450151,
+                32.282256
+              ],
+              [
+                121.425513,
+                32.430885
+              ],
+              [
+                121.390405,
+                32.460682
+              ],
+              [
+                121.352216,
+                32.474315
+              ],
+              [
+                121.269681,
+                32.483402
+              ],
+              [
+                121.153268,
+                32.52933
+              ],
+              [
+                121.121855,
+                32.569183
+              ],
+              [
+                121.076892,
+                32.576243
+              ],
+              [
+                121.020225,
+                32.605489
+              ],
+              [
+                120.961711,
+                32.612042
+              ],
+              [
+                120.979573,
+                32.636236
+              ],
+              [
+                120.963559,
+                32.68259
+              ],
+              [
+                120.916131,
+                32.701225
+              ],
+              [
+                120.953088,
+                32.714318
+              ],
+              [
+                120.972182,
+                32.761134
+              ],
+              [
+                120.981421,
+                32.85972
+              ],
+              [
+                120.957399,
+                32.893395
+              ],
+              [
+                120.932762,
+                33.005887
+              ],
+              [
+                120.917979,
+                33.02596
+              ],
+              [
+                120.871784,
+                33.047032
+              ],
+              [
+                120.874247,
+                33.093672
+              ],
+              [
+                120.843451,
+                33.209915
+              ],
+              [
+                120.819429,
+                33.237951
+              ],
+              [
+                120.833595,
+                33.274984
+              ],
+              [
+                120.813885,
+                33.303499
+              ],
+              [
+                120.769538,
+                33.307
+              ],
+              [
+                120.741205,
+                33.337505
+              ],
+              [
+                120.717183,
+                33.436945
+              ],
+              [
+                120.680227,
+                33.520306
+              ],
+              [
+                120.622944,
+                33.615051
+              ],
+              [
+                120.611241,
+                33.627012
+              ],
+              [
+                120.583524,
+                33.668362
+              ],
+              [
+                120.534249,
+                33.782346
+              ],
+              [
+                120.48559,
+                33.859411
+              ],
+              [
+                120.367329,
+                34.091674
+              ],
+              [
+                120.347619,
+                34.179352
+              ],
+              [
+                120.314359,
+                34.255563
+              ],
+              [
+                120.311895,
+                34.306991
+              ],
+              [
+                120.103707,
+                34.391481
+              ],
+              [
+                119.962657,
+                34.459112
+              ],
+              [
+                119.811752,
+                34.485754
+              ],
+              [
+                119.781571,
+                34.515839
+              ],
+              [
+                119.641137,
+                34.569078
+              ],
+              [
+                119.610956,
+                34.592729
+              ],
+              [
+                119.569072,
+                34.615389
+              ],
+              [
+                119.465594,
+                34.672994
+              ],
+              [
+                119.525956,
+                34.73351
+              ],
+              [
+                119.456971,
+                34.748264
+              ],
+              [
+                119.381827,
+                34.752198
+              ],
+              [
+                119.494543,
+                34.754656
+              ],
+              [
+                119.497007,
+                34.754164
+              ],
+              [
+                119.439725,
+                34.785136
+              ],
+              [
+                119.440957,
+                34.769406
+              ],
+              [
+                119.378747,
+                34.764489
+              ],
+              [
+                119.312841,
+                34.774813
+              ],
+              [
+                119.272189,
+                34.797914
+              ],
+              [
+                119.238313,
+                34.799388
+              ],
+              [
+                119.217371,
+                34.827886
+              ],
+              [
+                119.202588,
+                34.890253
+              ],
+              [
+                119.214907,
+                34.925589
+              ],
+              [
+                119.211211,
+                34.981507
+              ],
+              [
+                119.238313,
+                35.048657
+              ],
+              [
+                119.285124,
+                35.068252
+              ],
+              [
+                119.291899,
+                35.028567
+              ],
+              [
+                119.307298,
+                35.032977
+              ],
+              [
+                119.292515,
+                35.068742
+              ],
+              [
+                119.306066,
+                35.076578
+              ],
+              [
+                119.286972,
+                35.115261
+              ],
+              [
+                119.250016,
+                35.124562
+              ],
+              [
+                119.217371,
+                35.106939
+              ],
+              [
+                119.137915,
+                35.096167
+              ],
+              [
+                119.114509,
+                35.055026
+              ],
+              [
+                119.027045,
+                35.055516
+              ],
+              [
+                118.942662,
+                35.040817
+              ],
+              [
+                118.928495,
+                35.051106
+              ],
+              [
+                118.86259,
+                35.025626
+              ],
+              [
+                118.860742,
+                34.944233
+              ],
+              [
+                118.805307,
+                34.87307
+              ],
+              [
+                118.80038,
+                34.843114
+              ],
+              [
+                118.772047,
+                34.794474
+              ],
+              [
+                118.739402,
+                34.792508
+              ],
+              [
+                118.719076,
+                34.745313
+              ],
+              [
+                118.764039,
+                34.740396
+              ],
+              [
+                118.783749,
+                34.723181
+              ],
+              [
+                118.739402,
+                34.693663
+              ],
+              [
+                118.690127,
+                34.678408
+              ],
+              [
+                118.664257,
+                34.693663
+              ],
+              [
+                118.607591,
+                34.694155
+              ],
+              [
+                118.601431,
+                34.714327
+              ],
+              [
+                118.545997,
+                34.705964
+              ],
+              [
+                118.460997,
+                34.656258
+              ],
+              [
+                118.473932,
+                34.623269
+              ],
+              [
+                118.439439,
+                34.626223
+              ],
+              [
+                118.424657,
+                34.595193
+              ],
+              [
+                118.439439,
+                34.507949
+              ],
+              [
+                118.416034,
+                34.473914
+              ],
+              [
+                118.404947,
+                34.427525
+              ],
+              [
+                118.379693,
+                34.415183
+              ],
+              [
+                118.290382,
+                34.424563
+              ],
+              [
+                118.277447,
+                34.404814
+              ],
+              [
+                118.220165,
+                34.405802
+              ],
+              [
+                118.217701,
+                34.379134
+              ],
+              [
+                118.179513,
+                34.379628
+              ],
+              [
+                118.177665,
+                34.45319
+              ],
+              [
+                118.132702,
+                34.483287
+              ],
+              [
+                118.16473,
+                34.50499
+              ],
+              [
+                118.185056,
+                34.543942
+              ],
+              [
+                118.079115,
+                34.569571
+              ],
+              [
+                118.114839,
+                34.614404
+              ],
+              [
+                118.084042,
+                34.655766
+              ],
+              [
+                118.053861,
+                34.650843
+              ],
+              [
+                117.951615,
+                34.678408
+              ],
+              [
+                117.909732,
+                34.670533
+              ],
+              [
+                117.902956,
+                34.644443
+              ],
+              [
+                117.793935,
+                34.651827
+              ],
+              [
+                117.791471,
+                34.583368
+              ],
+              [
+                117.801942,
+                34.518798
+              ],
+              [
+                117.684298,
+                34.547392
+              ],
+              [
+                117.659044,
+                34.501044
+              ],
+              [
+                117.609769,
+                34.490686
+              ],
+              [
+                117.592523,
+                34.462566
+              ],
+              [
+                117.53832,
+                34.467006
+              ],
+              [
+                117.465023,
+                34.484767
+              ],
+              [
+                117.402813,
+                34.550843
+              ],
+              [
+                117.402813,
+                34.569571
+              ],
+              [
+                117.370785,
+                34.584846
+              ],
+              [
+                117.325205,
+                34.573021
+              ],
+              [
+                117.325205,
+                34.573021
+              ],
+              [
+                117.32151,
+                34.566614
+              ],
+              [
+                117.32151,
+                34.566614
+              ],
+              [
+                117.311654,
+                34.561686
+              ],
+              [
+                117.311654,
+                34.561686
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 330000,
+        "name": "娴欐睙鐪�",
+        "center": [
+          120.153576,
+          30.287459
+        ],
+        "centroid": [
+          120.109913,
+          29.181466
+        ],
+        "childrenNum": 11,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 10,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                118.433896,
+                28.288335
+              ],
+              [
+                118.444367,
+                28.253548
+              ],
+              [
+                118.490562,
+                28.238259
+              ],
+              [
+                118.493026,
+                28.262509
+              ],
+              [
+                118.588497,
+                28.282538
+              ],
+              [
+                118.595272,
+                28.258292
+              ],
+              [
+                118.651322,
+                28.277267
+              ],
+              [
+                118.674728,
+                28.27147
+              ],
+              [
+                118.699366,
+                28.309939
+              ],
+              [
+                118.719692,
+                28.312047
+              ],
+              [
+                118.756032,
+                28.252493
+              ],
+              [
+                118.802228,
+                28.240368
+              ],
+              [
+                118.804075,
+                28.207675
+              ],
+              [
+                118.771431,
+                28.188687
+              ],
+              [
+                118.805923,
+                28.154923
+              ],
+              [
+                118.802228,
+                28.117453
+              ],
+              [
+                118.767735,
+                28.10584
+              ],
+              [
+                118.719076,
+                28.063601
+              ],
+              [
+                118.733858,
+                28.027684
+              ],
+              [
+                118.730163,
+                27.970615
+              ],
+              [
+                118.753568,
+                27.947885
+              ],
+              [
+                118.818242,
+                27.916689
+              ],
+              [
+                118.829329,
+                27.847921
+              ],
+              [
+                118.873677,
+                27.733563
+              ],
+              [
+                118.879836,
+                27.667859
+              ],
+              [
+                118.913713,
+                27.619616
+              ],
+              [
+                118.909401,
+                27.568168
+              ],
+              [
+                118.869365,
+                27.540047
+              ],
+              [
+                118.907553,
+                27.460952
+              ],
+              [
+                118.955597,
+                27.4498
+              ],
+              [
+                118.986393,
+                27.47582
+              ],
+              [
+                118.983314,
+                27.498649
+              ],
+              [
+                119.020886,
+                27.498118
+              ],
+              [
+                119.03998,
+                27.478475
+              ],
+              [
+                119.092335,
+                27.466262
+              ],
+              [
+                119.129907,
+                27.475289
+              ],
+              [
+                119.121284,
+                27.438115
+              ],
+              [
+                119.14777,
+                27.424836
+              ],
+              [
+                119.224146,
+                27.416868
+              ],
+              [
+                119.26911,
+                27.42218
+              ],
+              [
+                119.285124,
+                27.457766
+              ],
+              [
+                119.334399,
+                27.480067
+              ],
+              [
+                119.360269,
+                27.524657
+              ],
+              [
+                119.416935,
+                27.539517
+              ],
+              [
+                119.438493,
+                27.508734
+              ],
+              [
+                119.466826,
+                27.526249
+              ],
+              [
+                119.501935,
+                27.610601
+              ],
+              [
+                119.501319,
+                27.649837
+              ],
+              [
+                119.541971,
+                27.666799
+              ],
+              [
+                119.606028,
+                27.674749
+              ],
+              [
+                119.644217,
+                27.663619
+              ],
+              [
+                119.626354,
+                27.620676
+              ],
+              [
+                119.630666,
+                27.582491
+              ],
+              [
+                119.675014,
+                27.574534
+              ],
+              [
+                119.659615,
+                27.540578
+              ],
+              [
+                119.690412,
+                27.537394
+              ],
+              [
+                119.70889,
+                27.514042
+              ],
+              [
+                119.703347,
+                27.446613
+              ],
+              [
+                119.685485,
+                27.438646
+              ],
+              [
+                119.711354,
+                27.403054
+              ],
+              [
+                119.750774,
+                27.373829
+              ],
+              [
+                119.739687,
+                27.362668
+              ],
+              [
+                119.782187,
+                27.330241
+              ],
+              [
+                119.768636,
+                27.307909
+              ],
+              [
+                119.843165,
+                27.300464
+              ],
+              [
+                119.938636,
+                27.329709
+              ],
+              [
+                119.960194,
+                27.365857
+              ],
+              [
+                120.008237,
+                27.375423
+              ],
+              [
+                120.026099,
+                27.344063
+              ],
+              [
+                120.052584,
+                27.338747
+              ],
+              [
+                120.096316,
+                27.390302
+              ],
+              [
+                120.136968,
+                27.402523
+              ],
+              [
+                120.134504,
+                27.420055
+              ],
+              [
+                120.221352,
+                27.420055
+              ],
+              [
+                120.26262,
+                27.432804
+              ],
+              [
+                120.273091,
+                27.38924
+              ],
+              [
+                120.340844,
+                27.399867
+              ],
+              [
+                120.343924,
+                27.363199
+              ],
+              [
+                120.430155,
+                27.258976
+              ],
+              [
+                120.401822,
+                27.250996
+              ],
+              [
+                120.404286,
+                27.204166
+              ],
+              [
+                120.461568,
+                27.142407
+              ],
+              [
+                120.492365,
+                27.136016
+              ],
+              [
+                120.545952,
+                27.156785
+              ],
+              [
+                120.574901,
+                27.234501
+              ],
+              [
+                120.554575,
+                27.25206
+              ],
+              [
+                120.580444,
+                27.321203
+              ],
+              [
+                120.665444,
+                27.357884
+              ],
+              [
+                120.673451,
+                27.420055
+              ],
+              [
+                120.703016,
+                27.478475
+              ],
+              [
+                120.637111,
+                27.561271
+              ],
+              [
+                120.634647,
+                27.577186
+              ],
+              [
+                120.685154,
+                27.622797
+              ],
+              [
+                120.709176,
+                27.682699
+              ],
+              [
+                120.771386,
+                27.734623
+              ],
+              [
+                120.777545,
+                27.774873
+              ],
+              [
+                120.809574,
+                27.775402
+              ],
+              [
+                120.840371,
+                27.758986
+              ],
+              [
+                120.910588,
+                27.864852
+              ],
+              [
+                120.942001,
+                27.896592
+              ],
+              [
+                120.97403,
+                27.887071
+              ],
+              [
+                121.027616,
+                27.832574
+              ],
+              [
+                121.070116,
+                27.834162
+              ],
+              [
+                121.107688,
+                27.81352
+              ],
+              [
+                121.152036,
+                27.815638
+              ],
+              [
+                121.134174,
+                27.787051
+              ],
+              [
+                121.13479,
+                27.787051
+              ],
+              [
+                121.149572,
+                27.801345
+              ],
+              [
+                121.149572,
+                27.801875
+              ],
+              [
+                121.153268,
+                27.809815
+              ],
+              [
+                121.152652,
+                27.810344
+              ],
+              [
+                121.192072,
+                27.822518
+              ],
+              [
+                121.193304,
+                27.872259
+              ],
+              [
+                121.162507,
+                27.879136
+              ],
+              [
+                121.162507,
+                27.90717
+              ],
+              [
+                121.099681,
+                27.895005
+              ],
+              [
+                121.05595,
+                27.900294
+              ],
+              [
+                120.991892,
+                27.95
+              ],
+              [
+                121.015298,
+                27.981714
+              ],
+              [
+                121.059029,
+                28.096338
+              ],
+              [
+                121.108304,
+                28.139092
+              ],
+              [
+                121.121239,
+                28.12537
+              ],
+              [
+                121.140949,
+                28.031382
+              ],
+              [
+                121.176058,
+                28.022401
+              ],
+              [
+                121.261057,
+                28.034551
+              ],
+              [
+                121.299862,
+                28.067297
+              ],
+              [
+                121.328195,
+                28.134343
+              ],
+              [
+                121.373774,
+                28.133287
+              ],
+              [
+                121.402107,
+                28.197127
+              ],
+              [
+                121.45631,
+                28.250385
+              ],
+              [
+                121.488955,
+                28.301509
+              ],
+              [
+                121.538846,
+                28.299401
+              ],
+              [
+                121.571491,
+                28.279376
+              ],
+              [
+                121.580114,
+                28.240368
+              ],
+              [
+                121.627541,
+                28.251966
+              ],
+              [
+                121.669425,
+                28.33312
+              ],
+              [
+                121.660186,
+                28.355768
+              ],
+              [
+                121.634317,
+                28.347868
+              ],
+              [
+                121.658954,
+                28.392628
+              ],
+              [
+                121.692831,
+                28.407368
+              ],
+              [
+                121.671273,
+                28.472621
+              ],
+              [
+                121.646019,
+                28.511544
+              ],
+              [
+                121.634317,
+                28.562542
+              ],
+              [
+                121.596128,
+                28.575156
+              ],
+              [
+                121.557324,
+                28.645033
+              ],
+              [
+                121.540694,
+                28.655537
+              ],
+              [
+                121.646019,
+                28.682842
+              ],
+              [
+                121.689135,
+                28.719062
+              ],
+              [
+                121.704534,
+                28.804577
+              ],
+              [
+                121.687287,
+                28.863294
+              ],
+              [
+                121.774751,
+                28.863818
+              ],
+              [
+                121.772287,
+                28.898404
+              ],
+              [
+                121.743338,
+                28.954451
+              ],
+              [
+                121.711309,
+                28.985865
+              ],
+              [
+                121.712541,
+                29.028783
+              ],
+              [
+                121.658954,
+                29.058606
+              ],
+              [
+                121.660186,
+                29.118226
+              ],
+              [
+                121.616454,
+                29.143318
+              ],
+              [
+                121.608447,
+                29.168927
+              ],
+              [
+                121.715621,
+                29.125022
+              ],
+              [
+                121.750113,
+                29.136523
+              ],
+              [
+                121.767975,
+                29.166837
+              ],
+              [
+                121.780294,
+                29.10986
+              ],
+              [
+                121.811091,
+                29.10986
+              ],
+              [
+                121.85975,
+                29.086328
+              ],
+              [
+                121.884388,
+                29.105677
+              ],
+              [
+                121.966308,
+                29.052852
+              ],
+              [
+                121.970004,
+                29.092604
+              ],
+              [
+                121.988482,
+                29.110906
+              ],
+              [
+                121.986634,
+                29.154817
+              ],
+              [
+                121.948446,
+                29.193485
+              ],
+              [
+                121.971851,
+                29.193485
+              ],
+              [
+                121.966924,
+                29.249894
+              ],
+              [
+                122.002032,
+                29.260336
+              ],
+              [
+                122.000185,
+                29.278608
+              ],
+              [
+                121.94475,
+                29.28435
+              ],
+              [
+                121.958301,
+                29.334448
+              ],
+              [
+                121.936127,
+                29.348012
+              ],
+              [
+                121.937975,
+                29.384
+              ],
+              [
+                121.975547,
+                29.411113
+              ],
+              [
+                121.993409,
+                29.45229
+              ],
+              [
+                121.973083,
+                29.477821
+              ],
+              [
+                121.968772,
+                29.515846
+              ],
+              [
+                121.995257,
+                29.545007
+              ],
+              [
+                122.000185,
+                29.582486
+              ],
+              [
+                121.966308,
+                29.636078
+              ],
+              [
+                121.909641,
+                29.650122
+              ],
+              [
+                121.872685,
+                29.632437
+              ],
+              [
+                121.833265,
+                29.653242
+              ],
+              [
+                121.937359,
+                29.748373
+              ],
+              [
+                122.003264,
+                29.762401
+              ],
+              [
+                122.043916,
+                29.822647
+              ],
+              [
+                122.10243,
+                29.859504
+              ],
+              [
+                122.143082,
+                29.877668
+              ],
+              [
+                122.140003,
+                29.901535
+              ],
+              [
+                122.00696,
+                29.891678
+              ],
+              [
+                122.00388,
+                29.92021
+              ],
+              [
+                121.971235,
+                29.955476
+              ],
+              [
+                121.919497,
+                29.920729
+              ],
+              [
+                121.835113,
+                29.958068
+              ],
+              [
+                121.78399,
+                29.99332
+              ],
+              [
+                121.721164,
+                29.992802
+              ],
+              [
+                121.699606,
+                30.007832
+              ],
+              [
+                121.652795,
+                30.071037
+              ],
+              [
+                121.635548,
+                30.070002
+              ],
+              [
+                121.561636,
+                30.184395
+              ],
+              [
+                121.497578,
+                30.258861
+              ],
+              [
+                121.395332,
+                30.338435
+              ],
+              [
+                121.371926,
+                30.37097
+              ],
+              [
+                121.328195,
+                30.397299
+              ],
+              [
+                121.225333,
+                30.404526
+              ],
+              [
+                121.183449,
+                30.434458
+              ],
+              [
+                121.092906,
+                30.515952
+              ],
+              [
+                121.058413,
+                30.563888
+              ],
+              [
+                121.148956,
+                30.599953
+              ],
+              [
+                121.188992,
+                30.632916
+              ],
+              [
+                121.239499,
+                30.648878
+              ],
+              [
+                121.274608,
+                30.677191
+              ],
+              [
+                121.272144,
+                30.723504
+              ],
+              [
+                121.232108,
+                30.755909
+              ],
+              [
+                121.21671,
+                30.785734
+              ],
+              [
+                121.174826,
+                30.771851
+              ],
+              [
+                121.123087,
+                30.77905
+              ],
+              [
+                121.13787,
+                30.826342
+              ],
+              [
+                121.097833,
+                30.857171
+              ],
+              [
+                121.060261,
+                30.845354
+              ],
+              [
+                121.038087,
+                30.814007
+              ],
+              [
+                120.991892,
+                30.837133
+              ],
+              [
+                121.020225,
+                30.872069
+              ],
+              [
+                120.993124,
+                30.889532
+              ],
+              [
+                121.000515,
+                30.938309
+              ],
+              [
+                120.989428,
+                31.01425
+              ],
+              [
+                120.949392,
+                31.030148
+              ],
+              [
+                120.940153,
+                31.010146
+              ],
+              [
+                120.901349,
+                31.017327
+              ],
+              [
+                120.865624,
+                30.989627
+              ],
+              [
+                120.820661,
+                31.006556
+              ],
+              [
+                120.770154,
+                30.996809
+              ],
+              [
+                120.746132,
+                30.962432
+              ],
+              [
+                120.698089,
+                30.970643
+              ],
+              [
+                120.684538,
+                30.955247
+              ],
+              [
+                120.709176,
+                30.933176
+              ],
+              [
+                120.713487,
+                30.88491
+              ],
+              [
+                120.68269,
+                30.882342
+              ],
+              [
+                120.654973,
+                30.846896
+              ],
+              [
+                120.589684,
+                30.854089
+              ],
+              [
+                120.563814,
+                30.835592
+              ],
+              [
+                120.504684,
+                30.757967
+              ],
+              [
+                120.489285,
+                30.763624
+              ],
+              [
+                120.460336,
+                30.839702
+              ],
+              [
+                120.441858,
+                30.860768
+              ],
+              [
+                120.435083,
+                30.920855
+              ],
+              [
+                120.42338,
+                30.902884
+              ],
+              [
+                120.35809,
+                30.886964
+              ],
+              [
+                120.371025,
+                30.948575
+              ],
+              [
+                120.316206,
+                30.933689
+              ],
+              [
+                120.223816,
+                30.926502
+              ],
+              [
+                120.149903,
+                30.937283
+              ],
+              [
+                120.111099,
+                30.955761
+              ],
+              [
+                120.052584,
+                31.00553
+              ],
+              [
+                120.001461,
+                31.027071
+              ],
+              [
+                119.988527,
+                31.059375
+              ],
+              [
+                119.946027,
+                31.106016
+              ],
+              [
+                119.921389,
+                31.170045
+              ],
+              [
+                119.878274,
+                31.160828
+              ],
+              [
+                119.827151,
+                31.174142
+              ],
+              [
+                119.809904,
+                31.148536
+              ],
+              [
+                119.779723,
+                31.17875
+              ],
+              [
+                119.715666,
+                31.169533
+              ],
+              [
+                119.705811,
+                31.152634
+              ],
+              [
+                119.678093,
+                31.167997
+              ],
+              [
+                119.623891,
+                31.130096
+              ],
+              [
+                119.649144,
+                31.104991
+              ],
+              [
+                119.629434,
+                31.085517
+              ],
+              [
+                119.633746,
+                31.019379
+              ],
+              [
+                119.580159,
+                30.967051
+              ],
+              [
+                119.582007,
+                30.932149
+              ],
+              [
+                119.563529,
+                30.919315
+              ],
+              [
+                119.557369,
+                30.874124
+              ],
+              [
+                119.575847,
+                30.829939
+              ],
+              [
+                119.55429,
+                30.825828
+              ],
+              [
+                119.527188,
+                30.77905
+              ],
+              [
+                119.479761,
+                30.772365
+              ],
+              [
+                119.482841,
+                30.704467
+              ],
+              [
+                119.444652,
+                30.650422
+              ],
+              [
+                119.408312,
+                30.645274
+              ],
+              [
+                119.39045,
+                30.685941
+              ],
+              [
+                119.343022,
+                30.664322
+              ],
+              [
+                119.323312,
+                30.630341
+              ],
+              [
+                119.238929,
+                30.609225
+              ],
+              [
+                119.265414,
+                30.574709
+              ],
+              [
+                119.237081,
+                30.546881
+              ],
+              [
+                119.272189,
+                30.510281
+              ],
+              [
+                119.326392,
+                30.532964
+              ],
+              [
+                119.336247,
+                30.508734
+              ],
+              [
+                119.335015,
+                30.448389
+              ],
+              [
+                119.36766,
+                30.38491
+              ],
+              [
+                119.402768,
+                30.374584
+              ],
+              [
+                119.349182,
+                30.349281
+              ],
+              [
+                119.326392,
+                30.372002
+              ],
+              [
+                119.277117,
+                30.341018
+              ],
+              [
+                119.246936,
+                30.341018
+              ],
+              [
+                119.236465,
+                30.297106
+              ],
+              [
+                119.201356,
+                30.290905
+              ],
+              [
+                119.126828,
+                30.304856
+              ],
+              [
+                119.091719,
+                30.323972
+              ],
+              [
+                119.06277,
+                30.304856
+              ],
+              [
+                118.988857,
+                30.332237
+              ],
+              [
+                118.954365,
+                30.360126
+              ],
+              [
+                118.880452,
+                30.31519
+              ],
+              [
+                118.877988,
+                30.282637
+              ],
+              [
+                118.905089,
+                30.216464
+              ],
+              [
+                118.929727,
+                30.2025
+              ],
+              [
+                118.852735,
+                30.166805
+              ],
+              [
+                118.852119,
+                30.149729
+              ],
+              [
+                118.895234,
+                30.148694
+              ],
+              [
+                118.873677,
+                30.11505
+              ],
+              [
+                118.878604,
+                30.064822
+              ],
+              [
+                118.902626,
+                30.029078
+              ],
+              [
+                118.894619,
+                29.937845
+              ],
+              [
+                118.838568,
+                29.934733
+              ],
+              [
+                118.841032,
+                29.891159
+              ],
+              [
+                118.740634,
+                29.814859
+              ],
+              [
+                118.744945,
+                29.73902
+              ],
+              [
+                118.700598,
+                29.706277
+              ],
+              [
+                118.647011,
+                29.64336
+              ],
+              [
+                118.61991,
+                29.654282
+              ],
+              [
+                118.573714,
+                29.638159
+              ],
+              [
+                118.532446,
+                29.588731
+              ],
+              [
+                118.500417,
+                29.57572
+              ],
+              [
+                118.496106,
+                29.519492
+              ],
+              [
+                118.381541,
+                29.504909
+              ],
+              [
+                118.347664,
+                29.474174
+              ],
+              [
+                118.329802,
+                29.495012
+              ],
+              [
+                118.306396,
+                29.479384
+              ],
+              [
+                118.316252,
+                29.422581
+              ],
+              [
+                118.248498,
+                29.431443
+              ],
+              [
+                118.193064,
+                29.395472
+              ],
+              [
+                118.205382,
+                29.343839
+              ],
+              [
+                118.166578,
+                29.314099
+              ],
+              [
+                118.178281,
+                29.297921
+              ],
+              [
+                118.138861,
+                29.283828
+              ],
+              [
+                118.077883,
+                29.290614
+              ],
+              [
+                118.073571,
+                29.216993
+              ],
+              [
+                118.042159,
+                29.210202
+              ],
+              [
+                118.027992,
+                29.167882
+              ],
+              [
+                118.045238,
+                29.149068
+              ],
+              [
+                118.037847,
+                29.102017
+              ],
+              [
+                118.076035,
+                29.074822
+              ],
+              [
+                118.066796,
+                29.053898
+              ],
+              [
+                118.097593,
+                28.998952
+              ],
+              [
+                118.115455,
+                29.009944
+              ],
+              [
+                118.115455,
+                29.009944
+              ],
+              [
+                118.133933,
+                28.983771
+              ],
+              [
+                118.165346,
+                28.986912
+              ],
+              [
+                118.227556,
+                28.942406
+              ],
+              [
+                118.195527,
+                28.904167
+              ],
+              [
+                118.270056,
+                28.918836
+              ],
+              [
+                118.300237,
+                28.826075
+              ],
+              [
+                118.364295,
+                28.813491
+              ],
+              [
+                118.403099,
+                28.702791
+              ],
+              [
+                118.428352,
+                28.681267
+              ],
+              [
+                118.428352,
+                28.617193
+              ],
+              [
+                118.428352,
+                28.617193
+              ],
+              [
+                118.412338,
+                28.55676
+              ],
+              [
+                118.4302,
+                28.515225
+              ],
+              [
+                118.414802,
+                28.497344
+              ],
+              [
+                118.474548,
+                28.478934
+              ],
+              [
+                118.456686,
+                28.424738
+              ],
+              [
+                118.432048,
+                28.402104
+              ],
+              [
+                118.455454,
+                28.384204
+              ],
+              [
+                118.480091,
+                28.327325
+              ],
+              [
+                118.433896,
+                28.288335
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.163408,
+                29.988137
+              ],
+              [
+                122.239785,
+                29.962735
+              ],
+              [
+                122.279205,
+                29.937326
+              ],
+              [
+                122.322321,
+                29.940438
+              ],
+              [
+                122.341415,
+                29.976733
+              ],
+              [
+                122.343879,
+                30.020269
+              ],
+              [
+                122.310002,
+                30.039958
+              ],
+              [
+                122.290908,
+                30.074663
+              ],
+              [
+                122.301379,
+                30.086574
+              ],
+              [
+                122.293988,
+                30.100554
+              ],
+              [
+                122.152938,
+                30.113497
+              ],
+              [
+                122.095655,
+                30.158008
+              ],
+              [
+                122.048844,
+                30.147141
+              ],
+              [
+                121.955221,
+                30.183878
+              ],
+              [
+                121.934895,
+                30.161631
+              ],
+              [
+                121.983554,
+                30.100554
+              ],
+              [
+                121.989714,
+                30.077252
+              ],
+              [
+                121.978011,
+                30.059125
+              ],
+              [
+                122.027902,
+                29.991247
+              ],
+              [
+                122.106742,
+                30.005759
+              ],
+              [
+                122.118445,
+                29.986582
+              ],
+              [
+                122.163408,
+                29.988137
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.213915,
+                30.186464
+              ],
+              [
+                122.178807,
+                30.199396
+              ],
+              [
+                122.152938,
+                30.19112
+              ],
+              [
+                122.143698,
+                30.163183
+              ],
+              [
+                122.168336,
+                30.138343
+              ],
+              [
+                122.213915,
+                30.186464
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.229314,
+                29.711995
+              ],
+              [
+                122.210836,
+                29.700559
+              ],
+              [
+                122.269966,
+                29.685482
+              ],
+              [
+                122.231162,
+                29.710435
+              ],
+              [
+                122.229314,
+                29.711995
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.427646,
+                30.738422
+              ],
+              [
+                122.427031,
+                30.697777
+              ],
+              [
+                122.532972,
+                30.696748
+              ],
+              [
+                122.528045,
+                30.725047
+              ],
+              [
+                122.475074,
+                30.714243
+              ],
+              [
+                122.445509,
+                30.745109
+              ],
+              [
+                122.427646,
+                30.738422
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.162793,
+                30.329654
+              ],
+              [
+                122.058083,
+                30.291938
+              ],
+              [
+                122.154169,
+                30.244903
+              ],
+              [
+                122.231778,
+                30.234562
+              ],
+              [
+                122.247176,
+                30.30124
+              ],
+              [
+                122.228082,
+                30.329654
+              ],
+              [
+                122.191126,
+                30.329654
+              ],
+              [
+                122.176343,
+                30.351863
+              ],
+              [
+                122.162793,
+                30.329654
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.317393,
+                30.249556
+              ],
+              [
+                122.277973,
+                30.242835
+              ],
+              [
+                122.358661,
+                30.236113
+              ],
+              [
+                122.365437,
+                30.255242
+              ],
+              [
+                122.417175,
+                30.238699
+              ],
+              [
+                122.40732,
+                30.272817
+              ],
+              [
+                122.333408,
+                30.272817
+              ],
+              [
+                122.317393,
+                30.249556
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.026054,
+                29.178333
+              ],
+              [
+                122.013119,
+                29.151681
+              ],
+              [
+                122.056851,
+                29.158476
+              ],
+              [
+                122.075945,
+                29.176243
+              ],
+              [
+                122.036525,
+                29.20759
+              ],
+              [
+                122.026054,
+                29.178333
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.372212,
+                29.893234
+              ],
+              [
+                122.386379,
+                29.834069
+              ],
+              [
+                122.415944,
+                29.828877
+              ],
+              [
+                122.401777,
+                29.869884
+              ],
+              [
+                122.433806,
+                29.883376
+              ],
+              [
+                122.43319,
+                29.919173
+              ],
+              [
+                122.411632,
+                29.951846
+              ],
+              [
+                122.398081,
+                29.9394
+              ],
+              [
+                122.351886,
+                29.959105
+              ],
+              [
+                122.330944,
+                29.937845
+              ],
+              [
+                122.338951,
+                29.911911
+              ],
+              [
+                122.353734,
+                29.89946
+              ],
+              [
+                122.362973,
+                29.894272
+              ],
+              [
+                122.372212,
+                29.893234
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.43011,
+                30.408655
+              ],
+              [
+                122.432574,
+                30.445294
+              ],
+              [
+                122.37406,
+                30.461802
+              ],
+              [
+                122.277973,
+                30.471603
+              ],
+              [
+                122.281669,
+                30.418461
+              ],
+              [
+                122.318625,
+                30.407106
+              ],
+              [
+                122.352502,
+                30.422074
+              ],
+              [
+                122.43011,
+                30.408655
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.837577,
+                28.770484
+              ],
+              [
+                121.86283,
+                28.782024
+              ],
+              [
+                121.861598,
+                28.814016
+              ],
+              [
+                121.837577,
+                28.770484
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.265038,
+                29.84549
+              ],
+              [
+                122.221307,
+                29.832512
+              ],
+              [
+                122.248408,
+                29.804473
+              ],
+              [
+                122.310002,
+                29.766557
+              ],
+              [
+                122.325401,
+                29.781621
+              ],
+              [
+                122.299531,
+                29.819532
+              ],
+              [
+                122.319241,
+                29.829397
+              ],
+              [
+                122.265038,
+                29.84549
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.790765,
+                29.082144
+              ],
+              [
+                121.832649,
+                29.050236
+              ],
+              [
+                121.84312,
+                29.082144
+              ],
+              [
+                121.82033,
+                29.099402
+              ],
+              [
+                121.790765,
+                29.082144
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.201311,
+                27.623328
+              ],
+              [
+                121.197616,
+                27.618025
+              ],
+              [
+                121.198848,
+                27.616964
+              ],
+              [
+                121.203775,
+                27.625979
+              ],
+              [
+                121.201311,
+                27.623328
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.943518,
+                30.776993
+              ],
+              [
+                121.968156,
+                30.688514
+              ],
+              [
+                121.997105,
+                30.658659
+              ],
+              [
+                122.087032,
+                30.602014
+              ],
+              [
+                122.133227,
+                30.595317
+              ],
+              [
+                122.075329,
+                30.647848
+              ],
+              [
+                122.011271,
+                30.66947
+              ],
+              [
+                121.992793,
+                30.695204
+              ],
+              [
+                121.987866,
+                30.753338
+              ],
+              [
+                121.970004,
+                30.789333
+              ],
+              [
+                121.943518,
+                30.776993
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.889315,
+                28.471569
+              ],
+              [
+                121.918881,
+                28.497344
+              ],
+              [
+                121.881924,
+                28.502603
+              ],
+              [
+                121.889315,
+                28.471569
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.182503,
+                29.650642
+              ],
+              [
+                122.211452,
+                29.692241
+              ],
+              [
+                122.200365,
+                29.712515
+              ],
+              [
+                122.146778,
+                29.749412
+              ],
+              [
+                122.13138,
+                29.788893
+              ],
+              [
+                122.083952,
+                29.78318
+              ],
+              [
+                122.047612,
+                29.719791
+              ],
+              [
+                122.074097,
+                29.701599
+              ],
+              [
+                122.095655,
+                29.716673
+              ],
+              [
+                122.138155,
+                29.662083
+              ],
+              [
+                122.182503,
+                29.650642
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.461523,
+                29.944068
+              ],
+              [
+                122.459675,
+                29.944586
+              ],
+              [
+                122.460291,
+                29.947179
+              ],
+              [
+                122.451668,
+                29.943031
+              ],
+              [
+                122.451052,
+                29.940956
+              ],
+              [
+                122.450436,
+                29.940956
+              ],
+              [
+                122.449204,
+                29.9394
+              ],
+              [
+                122.4529,
+                29.936807
+              ],
+              [
+                122.452284,
+                29.935252
+              ],
+              [
+                122.45598,
+                29.926435
+              ],
+              [
+                122.457827,
+                29.927472
+              ],
+              [
+                122.462755,
+                29.927991
+              ],
+              [
+                122.467067,
+                29.928509
+              ],
+              [
+                122.459059,
+                29.938882
+              ],
+              [
+                122.461523,
+                29.944068
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.570544,
+                30.644244
+              ],
+              [
+                122.559457,
+                30.679764
+              ],
+              [
+                122.546523,
+                30.651967
+              ],
+              [
+                122.570544,
+                30.644244
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.869605,
+                28.423685
+              ],
+              [
+                121.910873,
+                28.44
+              ],
+              [
+                121.889931,
+                28.45105
+              ],
+              [
+                121.869605,
+                28.423685
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.065474,
+                30.179739
+              ],
+              [
+                122.055619,
+                30.200431
+              ],
+              [
+                122.017431,
+                30.186464
+              ],
+              [
+                122.025438,
+                30.161631
+              ],
+              [
+                122.065474,
+                30.179739
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.391306,
+                29.970512
+              ],
+              [
+                122.411632,
+                30.025969
+              ],
+              [
+                122.378371,
+                30.023896
+              ],
+              [
+                122.3679,
+                29.980361
+              ],
+              [
+                122.391306,
+                29.970512
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.850511,
+                29.977251
+              ],
+              [
+                121.874533,
+                29.964809
+              ],
+              [
+                121.933047,
+                29.994875
+              ],
+              [
+                121.924424,
+                30.052391
+              ],
+              [
+                121.88562,
+                30.094859
+              ],
+              [
+                121.848663,
+                30.101072
+              ],
+              [
+                121.84004,
+                30.047211
+              ],
+              [
+                121.844968,
+                29.982953
+              ],
+              [
+                121.850511,
+                29.977251
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.066421,
+                27.478475
+              ],
+              [
+                121.066421,
+                27.461483
+              ],
+              [
+                121.107073,
+                27.443958
+              ],
+              [
+                121.067036,
+                27.478475
+              ],
+              [
+                121.066421,
+                27.478475
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.952141,
+                29.187738
+              ],
+              [
+                121.979243,
+                29.160043
+              ],
+              [
+                121.976779,
+                29.191918
+              ],
+              [
+                121.952141,
+                29.187738
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.038373,
+                29.759284
+              ],
+              [
+                122.011271,
+                29.746294
+              ],
+              [
+                122.02975,
+                29.716673
+              ],
+              [
+                122.038373,
+                29.759284
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.940438,
+                30.114533
+              ],
+              [
+                121.910257,
+                30.089163
+              ],
+              [
+                121.945982,
+                30.064304
+              ],
+              [
+                121.962612,
+                30.106249
+              ],
+              [
+                121.940438,
+                30.114533
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.957685,
+                30.287804
+              ],
+              [
+                122.0008,
+                30.308473
+              ],
+              [
+                121.989098,
+                30.339985
+              ],
+              [
+                121.94167,
+                30.33327
+              ],
+              [
+                121.921344,
+                30.30744
+              ],
+              [
+                121.957685,
+                30.287804
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.192974,
+                29.965327
+              ],
+              [
+                122.163408,
+                29.988137
+              ],
+              [
+                122.152322,
+                29.97103
+              ],
+              [
+                122.154169,
+                29.97103
+              ],
+              [
+                122.155401,
+                29.970512
+              ],
+              [
+                122.18435,
+                29.955476
+              ],
+              [
+                122.192974,
+                29.965327
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.287828,
+                29.723949
+              ],
+              [
+                122.301379,
+                29.748373
+              ],
+              [
+                122.258263,
+                29.753569
+              ],
+              [
+                122.241633,
+                29.784738
+              ],
+              [
+                122.2133,
+                29.771752
+              ],
+              [
+                122.251488,
+                29.731225
+              ],
+              [
+                122.287828,
+                29.723949
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.134174,
+                27.787051
+              ],
+              [
+                121.134174,
+                27.785992
+              ],
+              [
+                121.13479,
+                27.787051
+              ],
+              [
+                121.134174,
+                27.787051
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.760254,
+                30.141966
+              ],
+              [
+                122.784275,
+                30.130062
+              ],
+              [
+                122.781196,
+                30.13265
+              ],
+              [
+                122.778116,
+                30.13679
+              ],
+              [
+                122.770725,
+                30.138861
+              ],
+              [
+                122.763333,
+                30.141966
+              ],
+              [
+                122.762101,
+                30.142484
+              ],
+              [
+                122.760254,
+                30.141966
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.264423,
+                30.269716
+              ],
+              [
+                122.253952,
+                30.237147
+              ],
+              [
+                122.315545,
+                30.250073
+              ],
+              [
+                122.300147,
+                30.271266
+              ],
+              [
+                122.264423,
+                30.269716
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.282901,
+                29.860542
+              ],
+              [
+                122.30877,
+                29.849642
+              ],
+              [
+                122.343263,
+                29.860542
+              ],
+              [
+                122.343263,
+                29.882857
+              ],
+              [
+                122.301379,
+                29.883895
+              ],
+              [
+                122.282901,
+                29.860542
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.781196,
+                30.694175
+              ],
+              [
+                122.799674,
+                30.716301
+              ],
+              [
+                122.778732,
+                30.729677
+              ],
+              [
+                122.757174,
+                30.713728
+              ],
+              [
+                122.781196,
+                30.694175
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.098449,
+                27.937311
+              ],
+              [
+                121.152652,
+                27.961629
+              ],
+              [
+                121.120623,
+                27.986471
+              ],
+              [
+                121.0695,
+                27.984357
+              ],
+              [
+                121.038087,
+                27.948942
+              ],
+              [
+                121.098449,
+                27.937311
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.185913,
+                27.963215
+              ],
+              [
+                121.237652,
+                27.988056
+              ],
+              [
+                121.197616,
+                28.000739
+              ],
+              [
+                121.17113,
+                27.978543
+              ],
+              [
+                121.185913,
+                27.963215
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.454132,
+                29.956513
+              ],
+              [
+                122.447972,
+                29.955994
+              ],
+              [
+                122.445509,
+                29.952365
+              ],
+              [
+                122.446741,
+                29.951327
+              ],
+              [
+                122.447972,
+                29.947698
+              ],
+              [
+                122.459059,
+                29.950809
+              ],
+              [
+                122.458443,
+                29.951846
+              ],
+              [
+                122.455364,
+                29.955994
+              ],
+              [
+                122.454132,
+                29.956513
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.836014,
+                30.698806
+              ],
+              [
+                122.831087,
+                30.728648
+              ],
+              [
+                122.807681,
+                30.714243
+              ],
+              [
+                122.836014,
+                30.698806
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.200365,
+                29.969475
+              ],
+              [
+                122.233626,
+                29.946661
+              ],
+              [
+                122.273662,
+                29.93214
+              ],
+              [
+                122.239785,
+                29.960142
+              ],
+              [
+                122.200365,
+                29.969475
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.029134,
+                29.954957
+              ],
+              [
+                122.043916,
+                29.930584
+              ],
+              [
+                122.058699,
+                29.955994
+              ],
+              [
+                122.029134,
+                29.954957
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.044247,
+                27.979072
+              ],
+              [
+                121.089826,
+                27.998625
+              ],
+              [
+                121.073812,
+                28.007608
+              ],
+              [
+                121.044247,
+                27.979072
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.471378,
+                29.927472
+              ],
+              [
+                122.470762,
+                29.925916
+              ],
+              [
+                122.473226,
+                29.925397
+              ],
+              [
+                122.47261,
+                29.927472
+              ],
+              [
+                122.471378,
+                29.927472
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.152322,
+                29.97103
+              ],
+              [
+                122.155401,
+                29.970512
+              ],
+              [
+                122.154169,
+                29.97103
+              ],
+              [
+                122.152322,
+                29.97103
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 340000,
+        "name": "瀹夊窘鐪�",
+        "center": [
+          117.283042,
+          31.86119
+        ],
+        "centroid": [
+          117.226884,
+          31.849254
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 11,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                116.599629,
+                34.014324
+              ],
+              [
+                116.641512,
+                33.978103
+              ],
+              [
+                116.64336,
+                33.896675
+              ],
+              [
+                116.631042,
+                33.887733
+              ],
+              [
+                116.566984,
+                33.9081
+              ],
+              [
+                116.558361,
+                33.881274
+              ],
+              [
+                116.486296,
+                33.869846
+              ],
+              [
+                116.437637,
+                33.846489
+              ],
+              [
+                116.437021,
+                33.801246
+              ],
+              [
+                116.408071,
+                33.805721
+              ],
+              [
+                116.393905,
+                33.782843
+              ],
+              [
+                116.316912,
+                33.771402
+              ],
+              [
+                116.263326,
+                33.730101
+              ],
+              [
+                116.230065,
+                33.735078
+              ],
+              [
+                116.155536,
+                33.709693
+              ],
+              [
+                116.132747,
+                33.751501
+              ],
+              [
+                116.100102,
+                33.782843
+              ],
+              [
+                116.074232,
+                33.781351
+              ],
+              [
+                116.055754,
+                33.804727
+              ],
+              [
+                116.05945,
+                33.860902
+              ],
+              [
+                115.982457,
+                33.917039
+              ],
+              [
+                116.00032,
+                33.965199
+              ],
+              [
+                115.95782,
+                34.007875
+              ],
+              [
+                115.904233,
+                34.009859
+              ],
+              [
+                115.876516,
+                34.028708
+              ],
+              [
+                115.877132,
+                34.002913
+              ],
+              [
+                115.85003,
+                34.004898
+              ],
+              [
+                115.846335,
+                34.028708
+              ],
+              [
+                115.809378,
+                34.062428
+              ],
+              [
+                115.768726,
+                34.061932
+              ],
+              [
+                115.736082,
+                34.076805
+              ],
+              [
+                115.705901,
+                34.059949
+              ],
+              [
+                115.658473,
+                34.061437
+              ],
+              [
+                115.642459,
+                34.03218
+              ],
+              [
+                115.60735,
+                34.030196
+              ],
+              [
+                115.579017,
+                33.974133
+              ],
+              [
+                115.577785,
+                33.950307
+              ],
+              [
+                115.547604,
+                33.874815
+              ],
+              [
+                115.631988,
+                33.869846
+              ],
+              [
+                115.614126,
+                33.775879
+              ],
+              [
+                115.576553,
+                33.787817
+              ],
+              [
+                115.563003,
+                33.772895
+              ],
+              [
+                115.601807,
+                33.718653
+              ],
+              [
+                115.601191,
+                33.658898
+              ],
+              [
+                115.639995,
+                33.585143
+              ],
+              [
+                115.564851,
+                33.576169
+              ],
+              [
+                115.511264,
+                33.55323
+              ],
+              [
+                115.463837,
+                33.567193
+              ],
+              [
+                115.422569,
+                33.557219
+              ],
+              [
+                115.394851,
+                33.506335
+              ],
+              [
+                115.366518,
+                33.5233
+              ],
+              [
+                115.345576,
+                33.502842
+              ],
+              [
+                115.345576,
+                33.449928
+              ],
+              [
+                115.324634,
+                33.457418
+              ],
+              [
+                115.315395,
+                33.431451
+              ],
+              [
+                115.328946,
+                33.403477
+              ],
+              [
+                115.313547,
+                33.376994
+              ],
+              [
+                115.341881,
+                33.370997
+              ],
+              [
+                115.365286,
+                33.336005
+              ],
+              [
+                115.361591,
+                33.298497
+              ],
+              [
+                115.335105,
+                33.297997
+              ],
+              [
+                115.340033,
+                33.260973
+              ],
+              [
+                115.300613,
+                33.204407
+              ],
+              [
+                115.303692,
+                33.149809
+              ],
+              [
+                115.289526,
+                33.131769
+              ],
+              [
+                115.245178,
+                33.135778
+              ],
+              [
+                115.194671,
+                33.120743
+              ],
+              [
+                115.168186,
+                33.088658
+              ],
+              [
+                115.041302,
+                33.086653
+              ],
+              [
+                114.990795,
+                33.102195
+              ],
+              [
+                114.966158,
+                33.147304
+              ],
+              [
+                114.932897,
+                33.153817
+              ],
+              [
+                114.902716,
+                33.129764
+              ],
+              [
+                114.897172,
+                33.086653
+              ],
+              [
+                114.913187,
+                33.083143
+              ],
+              [
+                114.925506,
+                33.016928
+              ],
+              [
+                114.891629,
+                33.020441
+              ],
+              [
+                114.883006,
+                32.990328
+              ],
+              [
+                114.916266,
+                32.971251
+              ],
+              [
+                114.943368,
+                32.935094
+              ],
+              [
+                115.009273,
+                32.940117
+              ],
+              [
+                115.035143,
+                32.932582
+              ],
+              [
+                115.029599,
+                32.906962
+              ],
+              [
+                115.139237,
+                32.897917
+              ],
+              [
+                115.155867,
+                32.864747
+              ],
+              [
+                115.197135,
+                32.856201
+              ],
+              [
+                115.189744,
+                32.812452
+              ],
+              [
+                115.211301,
+                32.785791
+              ],
+              [
+                115.189744,
+                32.770695
+              ],
+              [
+                115.179273,
+                32.726402
+              ],
+              [
+                115.182968,
+                32.666973
+              ],
+              [
+                115.20083,
+                32.591876
+              ],
+              [
+                115.24333,
+                32.593388
+              ],
+              [
+                115.267352,
+                32.578261
+              ],
+              [
+                115.30554,
+                32.583303
+              ],
+              [
+                115.304924,
+                32.553042
+              ],
+              [
+                115.411482,
+                32.575235
+              ],
+              [
+                115.409018,
+                32.549007
+              ],
+              [
+                115.497713,
+                32.492489
+              ],
+              [
+                115.5088,
+                32.468761
+              ],
+              [
+                115.510648,
+                32.468761
+              ],
+              [
+                115.510648,
+                32.468256
+              ],
+              [
+                115.510648,
+                32.467751
+              ],
+              [
+                115.509416,
+                32.466741
+              ],
+              [
+                115.522967,
+                32.441997
+              ],
+              [
+                115.57101,
+                32.419266
+              ],
+              [
+                115.604271,
+                32.425833
+              ],
+              [
+                115.626445,
+                32.40512
+              ],
+              [
+                115.657857,
+                32.428864
+              ],
+              [
+                115.667712,
+                32.409667
+              ],
+              [
+                115.704669,
+                32.495013
+              ],
+              [
+                115.742241,
+                32.476335
+              ],
+              [
+                115.771806,
+                32.505108
+              ],
+              [
+                115.789052,
+                32.468761
+              ],
+              [
+                115.861117,
+                32.537403
+              ],
+              [
+                115.891298,
+                32.576243
+              ],
+              [
+                115.910393,
+                32.567165
+              ],
+              [
+                115.8759,
+                32.542448
+              ],
+              [
+                115.845719,
+                32.501575
+              ],
+              [
+                115.883291,
+                32.487946
+              ],
+              [
+                115.865429,
+                32.458662
+              ],
+              [
+                115.899306,
+                32.390971
+              ],
+              [
+                115.912856,
+                32.227596
+              ],
+              [
+                115.941805,
+                32.166318
+              ],
+              [
+                115.922095,
+                32.049725
+              ],
+              [
+                115.928871,
+                32.003046
+              ],
+              [
+                115.909161,
+                31.94314
+              ],
+              [
+                115.920248,
+                31.920285
+              ],
+              [
+                115.894994,
+                31.8649
+              ],
+              [
+                115.893762,
+                31.832365
+              ],
+              [
+                115.914704,
+                31.814567
+              ],
+              [
+                115.886371,
+                31.776418
+              ],
+              [
+                115.851878,
+                31.786593
+              ],
+              [
+                115.808147,
+                31.770313
+              ],
+              [
+                115.808147,
+                31.770313
+              ],
+              [
+                115.767495,
+                31.78761
+              ],
+              [
+                115.731154,
+                31.76726
+              ],
+              [
+                115.676336,
+                31.778453
+              ],
+              [
+                115.553764,
+                31.69549
+              ],
+              [
+                115.534054,
+                31.698545
+              ],
+              [
+                115.495249,
+                31.673083
+              ],
+              [
+                115.476771,
+                31.643028
+              ],
+              [
+                115.485394,
+                31.608885
+              ],
+              [
+                115.439815,
+                31.588496
+              ],
+              [
+                115.415793,
+                31.525771
+              ],
+              [
+                115.371446,
+                31.495668
+              ],
+              [
+                115.389924,
+                31.450241
+              ],
+              [
+                115.373909,
+                31.405813
+              ],
+              [
+                115.393004,
+                31.389977
+              ],
+              [
+                115.372062,
+                31.349098
+              ],
+              [
+                115.40717,
+                31.337854
+              ],
+              [
+                115.443511,
+                31.344498
+              ],
+              [
+                115.473076,
+                31.265242
+              ],
+              [
+                115.507568,
+                31.267799
+              ],
+              [
+                115.539597,
+                31.231985
+              ],
+              [
+                115.540213,
+                31.194621
+              ],
+              [
+                115.585793,
+                31.143926
+              ],
+              [
+                115.603655,
+                31.17363
+              ],
+              [
+                115.655394,
+                31.211002
+              ],
+              [
+                115.700973,
+                31.201276
+              ],
+              [
+                115.778582,
+                31.112164
+              ],
+              [
+                115.797676,
+                31.128047
+              ],
+              [
+                115.837712,
+                31.127022
+              ],
+              [
+                115.867277,
+                31.147512
+              ],
+              [
+                115.887603,
+                31.10909
+              ],
+              [
+                115.939958,
+                31.071678
+              ],
+              [
+                115.938726,
+                31.04707
+              ],
+              [
+                116.006479,
+                31.034764
+              ],
+              [
+                116.015102,
+                31.011685
+              ],
+              [
+                116.058834,
+                31.012711
+              ],
+              [
+                116.071769,
+                30.956787
+              ],
+              [
+                116.03974,
+                30.957813
+              ],
+              [
+                115.976298,
+                30.931636
+              ],
+              [
+                115.932566,
+                30.889532
+              ],
+              [
+                115.865429,
+                30.864364
+              ],
+              [
+                115.848799,
+                30.828397
+              ],
+              [
+                115.863581,
+                30.815549
+              ],
+              [
+                115.851262,
+                30.756938
+              ],
+              [
+                115.782893,
+                30.751795
+              ],
+              [
+                115.762567,
+                30.685426
+              ],
+              [
+                115.81369,
+                30.637035
+              ],
+              [
+                115.819234,
+                30.597893
+              ],
+              [
+                115.848799,
+                30.602014
+              ],
+              [
+                115.876516,
+                30.582438
+              ],
+              [
+                115.887603,
+                30.542758
+              ],
+              [
+                115.910393,
+                30.519046
+              ],
+              [
+                115.894994,
+                30.452517
+              ],
+              [
+                115.921479,
+                30.416397
+              ],
+              [
+                115.885139,
+                30.379747
+              ],
+              [
+                115.91532,
+                30.337919
+              ],
+              [
+                115.903001,
+                30.31364
+              ],
+              [
+                115.985537,
+                30.290905
+              ],
+              [
+                115.997856,
+                30.252657
+              ],
+              [
+                116.065609,
+                30.204569
+              ],
+              [
+                116.055754,
+                30.180774
+              ],
+              [
+                116.088399,
+                30.110391
+              ],
+              [
+                116.078544,
+                30.062233
+              ],
+              [
+                116.091479,
+                30.036331
+              ],
+              [
+                116.073616,
+                29.969993
+              ],
+              [
+                116.128435,
+                29.897904
+              ],
+              [
+                116.13521,
+                29.819532
+              ],
+              [
+                116.172783,
+                29.828358
+              ],
+              [
+                116.227601,
+                29.816936
+              ],
+              [
+                116.250391,
+                29.785777
+              ],
+              [
+                116.280572,
+                29.788893
+              ],
+              [
+                116.342782,
+                29.835626
+              ],
+              [
+                116.467818,
+                29.896347
+              ],
+              [
+                116.525716,
+                29.897385
+              ],
+              [
+                116.552201,
+                29.909836
+              ],
+              [
+                116.585462,
+                30.045657
+              ],
+              [
+                116.620571,
+                30.073109
+              ],
+              [
+                116.666766,
+                30.076734
+              ],
+              [
+                116.720353,
+                30.053945
+              ],
+              [
+                116.747454,
+                30.057053
+              ],
+              [
+                116.783794,
+                30.030632
+              ],
+              [
+                116.802889,
+                29.99643
+              ],
+              [
+                116.830606,
+                30.004723
+              ],
+              [
+                116.83307,
+                29.95755
+              ],
+              [
+                116.868794,
+                29.980361
+              ],
+              [
+                116.900207,
+                29.949253
+              ],
+              [
+                116.882961,
+                29.893753
+              ],
+              [
+                116.780715,
+                29.792529
+              ],
+              [
+                116.762237,
+                29.802396
+              ],
+              [
+                116.673541,
+                29.709916
+              ],
+              [
+                116.698795,
+                29.707836
+              ],
+              [
+                116.70557,
+                29.69692
+              ],
+              [
+                116.706802,
+                29.6964
+              ],
+              [
+                116.704954,
+                29.688602
+              ],
+              [
+                116.680317,
+                29.681323
+              ],
+              [
+                116.651983,
+                29.637118
+              ],
+              [
+                116.716657,
+                29.590813
+              ],
+              [
+                116.721585,
+                29.564789
+              ],
+              [
+                116.760389,
+                29.599139
+              ],
+              [
+                116.780715,
+                29.569994
+              ],
+              [
+                116.849084,
+                29.57624
+              ],
+              [
+                116.873722,
+                29.609546
+              ],
+              [
+                116.939627,
+                29.648561
+              ],
+              [
+                116.974736,
+                29.657403
+              ],
+              [
+                116.996294,
+                29.683403
+              ],
+              [
+                117.041873,
+                29.680803
+              ],
+              [
+                117.112706,
+                29.711995
+              ],
+              [
+                117.108395,
+                29.75201
+              ],
+              [
+                117.136728,
+                29.775388
+              ],
+              [
+                117.123177,
+                29.798761
+              ],
+              [
+                117.073286,
+                29.831992
+              ],
+              [
+                117.127489,
+                29.86158
+              ],
+              [
+                117.129952,
+                29.89946
+              ],
+              [
+                117.171836,
+                29.920729
+              ],
+              [
+                117.2168,
+                29.926953
+              ],
+              [
+                117.246365,
+                29.915023
+              ],
+              [
+                117.261763,
+                29.880781
+              ],
+              [
+                117.25314,
+                29.834588
+              ],
+              [
+                117.29256,
+                29.822647
+              ],
+              [
+                117.338756,
+                29.848085
+              ],
+              [
+                117.359082,
+                29.812782
+              ],
+              [
+                117.382487,
+                29.840818
+              ],
+              [
+                117.415132,
+                29.85068
+              ],
+              [
+                117.408973,
+                29.802396
+              ],
+              [
+                117.455168,
+                29.749412
+              ],
+              [
+                117.453936,
+                29.688082
+              ],
+              [
+                117.490277,
+                29.660003
+              ],
+              [
+                117.530313,
+                29.654282
+              ],
+              [
+                117.523538,
+                29.630356
+              ],
+              [
+                117.543248,
+                29.588731
+              ],
+              [
+                117.608537,
+                29.591333
+              ],
+              [
+                117.647957,
+                29.614749
+              ],
+              [
+                117.678754,
+                29.595496
+              ],
+              [
+                117.690457,
+                29.555939
+              ],
+              [
+                117.729877,
+                29.550213
+              ],
+              [
+                117.795167,
+                29.570515
+              ],
+              [
+                117.872775,
+                29.54761
+              ],
+              [
+                117.933753,
+                29.549172
+              ],
+              [
+                118.00397,
+                29.578322
+              ],
+              [
+                118.042774,
+                29.566351
+              ],
+              [
+                118.050782,
+                29.542924
+              ],
+              [
+                118.095129,
+                29.534072
+              ],
+              [
+                118.143788,
+                29.489803
+              ],
+              [
+                118.127774,
+                29.47209
+              ],
+              [
+                118.136397,
+                29.418932
+              ],
+              [
+                118.193064,
+                29.395472
+              ],
+              [
+                118.248498,
+                29.431443
+              ],
+              [
+                118.316252,
+                29.422581
+              ],
+              [
+                118.306396,
+                29.479384
+              ],
+              [
+                118.329802,
+                29.495012
+              ],
+              [
+                118.347664,
+                29.474174
+              ],
+              [
+                118.381541,
+                29.504909
+              ],
+              [
+                118.496106,
+                29.519492
+              ],
+              [
+                118.500417,
+                29.57572
+              ],
+              [
+                118.532446,
+                29.588731
+              ],
+              [
+                118.573714,
+                29.638159
+              ],
+              [
+                118.61991,
+                29.654282
+              ],
+              [
+                118.647011,
+                29.64336
+              ],
+              [
+                118.700598,
+                29.706277
+              ],
+              [
+                118.744945,
+                29.73902
+              ],
+              [
+                118.740634,
+                29.814859
+              ],
+              [
+                118.841032,
+                29.891159
+              ],
+              [
+                118.838568,
+                29.934733
+              ],
+              [
+                118.894619,
+                29.937845
+              ],
+              [
+                118.902626,
+                30.029078
+              ],
+              [
+                118.878604,
+                30.064822
+              ],
+              [
+                118.873677,
+                30.11505
+              ],
+              [
+                118.895234,
+                30.148694
+              ],
+              [
+                118.852119,
+                30.149729
+              ],
+              [
+                118.852735,
+                30.166805
+              ],
+              [
+                118.929727,
+                30.2025
+              ],
+              [
+                118.905089,
+                30.216464
+              ],
+              [
+                118.877988,
+                30.282637
+              ],
+              [
+                118.880452,
+                30.31519
+              ],
+              [
+                118.954365,
+                30.360126
+              ],
+              [
+                118.988857,
+                30.332237
+              ],
+              [
+                119.06277,
+                30.304856
+              ],
+              [
+                119.091719,
+                30.323972
+              ],
+              [
+                119.126828,
+                30.304856
+              ],
+              [
+                119.201356,
+                30.290905
+              ],
+              [
+                119.236465,
+                30.297106
+              ],
+              [
+                119.246936,
+                30.341018
+              ],
+              [
+                119.277117,
+                30.341018
+              ],
+              [
+                119.326392,
+                30.372002
+              ],
+              [
+                119.349182,
+                30.349281
+              ],
+              [
+                119.402768,
+                30.374584
+              ],
+              [
+                119.36766,
+                30.38491
+              ],
+              [
+                119.335015,
+                30.448389
+              ],
+              [
+                119.336247,
+                30.508734
+              ],
+              [
+                119.326392,
+                30.532964
+              ],
+              [
+                119.272189,
+                30.510281
+              ],
+              [
+                119.237081,
+                30.546881
+              ],
+              [
+                119.265414,
+                30.574709
+              ],
+              [
+                119.238929,
+                30.609225
+              ],
+              [
+                119.323312,
+                30.630341
+              ],
+              [
+                119.343022,
+                30.664322
+              ],
+              [
+                119.39045,
+                30.685941
+              ],
+              [
+                119.408312,
+                30.645274
+              ],
+              [
+                119.444652,
+                30.650422
+              ],
+              [
+                119.482841,
+                30.704467
+              ],
+              [
+                119.479761,
+                30.772365
+              ],
+              [
+                119.527188,
+                30.77905
+              ],
+              [
+                119.55429,
+                30.825828
+              ],
+              [
+                119.575847,
+                30.829939
+              ],
+              [
+                119.557369,
+                30.874124
+              ],
+              [
+                119.563529,
+                30.919315
+              ],
+              [
+                119.582007,
+                30.932149
+              ],
+              [
+                119.580159,
+                30.967051
+              ],
+              [
+                119.633746,
+                31.019379
+              ],
+              [
+                119.629434,
+                31.085517
+              ],
+              [
+                119.649144,
+                31.104991
+              ],
+              [
+                119.623891,
+                31.130096
+              ],
+              [
+                119.599869,
+                31.10909
+              ],
+              [
+                119.532732,
+                31.159291
+              ],
+              [
+                119.461283,
+                31.156219
+              ],
+              [
+                119.439109,
+                31.177214
+              ],
+              [
+                119.391682,
+                31.174142
+              ],
+              [
+                119.360269,
+                31.213049
+              ],
+              [
+                119.374435,
+                31.258591
+              ],
+              [
+                119.350414,
+                31.301043
+              ],
+              [
+                119.338095,
+                31.259103
+              ],
+              [
+                119.294363,
+                31.263195
+              ],
+              [
+                119.266646,
+                31.250405
+              ],
+              [
+                119.198277,
+                31.270357
+              ],
+              [
+                119.197661,
+                31.295418
+              ],
+              [
+                119.158241,
+                31.294907
+              ],
+              [
+                119.107118,
+                31.250917
+              ],
+              [
+                119.10527,
+                31.235055
+              ],
+              [
+                119.014727,
+                31.241707
+              ],
+              [
+                118.984546,
+                31.237102
+              ],
+              [
+                118.870597,
+                31.242219
+              ],
+              [
+                118.794836,
+                31.229426
+              ],
+              [
+                118.756648,
+                31.279564
+              ],
+              [
+                118.726467,
+                31.282121
+              ],
+              [
+                118.720924,
+                31.322518
+              ],
+              [
+                118.745561,
+                31.372606
+              ],
+              [
+                118.767735,
+                31.363919
+              ],
+              [
+                118.824401,
+                31.375672
+              ],
+              [
+                118.852119,
+                31.393553
+              ],
+              [
+                118.883532,
+                31.500261
+              ],
+              [
+                118.857046,
+                31.506384
+              ],
+              [
+                118.865669,
+                31.519139
+              ],
+              [
+                118.885995,
+                31.519139
+              ],
+              [
+                118.881684,
+                31.564023
+              ],
+              [
+                118.858894,
+                31.623665
+              ],
+              [
+                118.802844,
+                31.619078
+              ],
+              [
+                118.773894,
+                31.682759
+              ],
+              [
+                118.748025,
+                31.675629
+              ],
+              [
+                118.736322,
+                31.633347
+              ],
+              [
+                118.643315,
+                31.649651
+              ],
+              [
+                118.643315,
+                31.671555
+              ],
+              [
+                118.697518,
+                31.709747
+              ],
+              [
+                118.653786,
+                31.73011
+              ],
+              [
+                118.641467,
+                31.75861
+              ],
+              [
+                118.571866,
+                31.746397
+              ],
+              [
+                118.5577,
+                31.73011
+              ],
+              [
+                118.521975,
+                31.743343
+              ],
+              [
+                118.533678,
+                31.76726
+              ],
+              [
+                118.481939,
+                31.778453
+              ],
+              [
+                118.504729,
+                31.841516
+              ],
+              [
+                118.466541,
+                31.857784
+              ],
+              [
+                118.472084,
+                31.879639
+              ],
+              [
+                118.363679,
+                31.930443
+              ],
+              [
+                118.389548,
+                31.985281
+              ],
+              [
+                118.394476,
+                32.076098
+              ],
+              [
+                118.433896,
+                32.086746
+              ],
+              [
+                118.501033,
+                32.121726
+              ],
+              [
+                118.49549,
+                32.165304
+              ],
+              [
+                118.510888,
+                32.194176
+              ],
+              [
+                118.643931,
+                32.209875
+              ],
+              [
+                118.674728,
+                32.250375
+              ],
+              [
+                118.657482,
+                32.30148
+              ],
+              [
+                118.703061,
+                32.328792
+              ],
+              [
+                118.685199,
+                32.403604
+              ],
+              [
+                118.691359,
+                32.472295
+              ],
+              [
+                118.628533,
+                32.467751
+              ],
+              [
+                118.592192,
+                32.481383
+              ],
+              [
+                118.608823,
+                32.536899
+              ],
+              [
+                118.564475,
+                32.562122
+              ],
+              [
+                118.568787,
+                32.585825
+              ],
+              [
+                118.59712,
+                32.600951
+              ],
+              [
+                118.632844,
+                32.578261
+              ],
+              [
+                118.658714,
+                32.594397
+              ],
+              [
+                118.688895,
+                32.588346
+              ],
+              [
+                118.719076,
+                32.614059
+              ],
+              [
+                118.719076,
+                32.614059
+              ],
+              [
+                118.73509,
+                32.58885
+              ],
+              [
+                118.757264,
+                32.603976
+              ],
+              [
+                118.784981,
+                32.582295
+              ],
+              [
+                118.820706,
+                32.60448
+              ],
+              [
+                118.84288,
+                32.56767
+              ],
+              [
+                118.908169,
+                32.59238
+              ],
+              [
+                118.890923,
+                32.553042
+              ],
+              [
+                118.92172,
+                32.557078
+              ],
+              [
+                118.922336,
+                32.557078
+              ],
+              [
+                118.92172,
+                32.557078
+              ],
+              [
+                118.922336,
+                32.557078
+              ],
+              [
+                118.975923,
+                32.505108
+              ],
+              [
+                119.041212,
+                32.515201
+              ],
+              [
+                119.084944,
+                32.452602
+              ],
+              [
+                119.142226,
+                32.499556
+              ],
+              [
+                119.168096,
+                32.536394
+              ],
+              [
+                119.152697,
+                32.557582
+              ],
+              [
+                119.22045,
+                32.576748
+              ],
+              [
+                119.230921,
+                32.607001
+              ],
+              [
+                119.208748,
+                32.641276
+              ],
+              [
+                119.211827,
+                32.708275
+              ],
+              [
+                119.184726,
+                32.825529
+              ],
+              [
+                119.113277,
+                32.823014
+              ],
+              [
+                119.054763,
+                32.8748
+              ],
+              [
+                119.020886,
+                32.955685
+              ],
+              [
+                118.993169,
+                32.958196
+              ],
+              [
+                118.934039,
+                32.93861
+              ],
+              [
+                118.892771,
+                32.941121
+              ],
+              [
+                118.89585,
+                32.957694
+              ],
+              [
+                118.89585,
+                32.957694
+              ],
+              [
+                118.849039,
+                32.956689
+              ],
+              [
+                118.846575,
+                32.922034
+              ],
+              [
+                118.821322,
+                32.920527
+              ],
+              [
+                118.810235,
+                32.853687
+              ],
+              [
+                118.743097,
+                32.853184
+              ],
+              [
+                118.743097,
+                32.853184
+              ],
+              [
+                118.73817,
+                32.772708
+              ],
+              [
+                118.756648,
+                32.737477
+              ],
+              [
+                118.707373,
+                32.72036
+              ],
+              [
+                118.642699,
+                32.744525
+              ],
+              [
+                118.572482,
+                32.719856
+              ],
+              [
+                118.560163,
+                32.729926
+              ],
+              [
+                118.483787,
+                32.721367
+              ],
+              [
+                118.450526,
+                32.743518
+              ],
+              [
+                118.411106,
+                32.715828
+              ],
+              [
+                118.375382,
+                32.718849
+              ],
+              [
+                118.363063,
+                32.770695
+              ],
+              [
+                118.334114,
+                32.761637
+              ],
+              [
+                118.300237,
+                32.783275
+              ],
+              [
+                118.301469,
+                32.846145
+              ],
+              [
+                118.250346,
+                32.848157
+              ],
+              [
+                118.2331,
+                32.914498
+              ],
+              [
+                118.252194,
+                32.936601
+              ],
+              [
+                118.291614,
+                32.946143
+              ],
+              [
+                118.303933,
+                32.96874
+              ],
+              [
+                118.26944,
+                32.969242
+              ],
+              [
+                118.244803,
+                32.998359
+              ],
+              [
+                118.243571,
+                33.027967
+              ],
+              [
+                118.219549,
+                33.114227
+              ],
+              [
+                118.217085,
+                33.191888
+              ],
+              [
+                118.178281,
+                33.217926
+              ],
+              [
+                118.149332,
+                33.169348
+              ],
+              [
+                118.038463,
+                33.134776
+              ],
+              [
+                118.037231,
+                33.152314
+              ],
+              [
+                117.988572,
+                33.180869
+              ],
+              [
+                117.977485,
+                33.226437
+              ],
+              [
+                117.942376,
+                33.224936
+              ],
+              [
+                117.939297,
+                33.262475
+              ],
+              [
+                117.974405,
+                33.279487
+              ],
+              [
+                117.992883,
+                33.333005
+              ],
+              [
+                118.029224,
+                33.374995
+              ],
+              [
+                118.016905,
+                33.402978
+              ],
+              [
+                118.027376,
+                33.455421
+              ],
+              [
+                118.050782,
+                33.491863
+              ],
+              [
+                118.107448,
+                33.475391
+              ],
+              [
+                118.117919,
+                33.594615
+              ],
+              [
+                118.112376,
+                33.617045
+              ],
+              [
+                118.16781,
+                33.663381
+              ],
+              [
+                118.161035,
+                33.735576
+              ],
+              [
+                118.117919,
+                33.766427
+              ],
+              [
+                118.065564,
+                33.76593
+              ],
+              [
+                118.019985,
+                33.738562
+              ],
+              [
+                117.972557,
+                33.74951
+              ],
+              [
+                117.901724,
+                33.720146
+              ],
+              [
+                117.843826,
+                33.736074
+              ],
+              [
+                117.791471,
+                33.733585
+              ],
+              [
+                117.750203,
+                33.710688
+              ],
+              [
+                117.72495,
+                33.74951
+              ],
+              [
+                117.739732,
+                33.758467
+              ],
+              [
+                117.759442,
+                33.874318
+              ],
+              [
+                117.753899,
+                33.891211
+              ],
+              [
+                117.715095,
+                33.879287
+              ],
+              [
+                117.672595,
+                33.934916
+              ],
+              [
+                117.671363,
+                33.992494
+              ],
+              [
+                117.629479,
+                34.028708
+              ],
+              [
+                117.612849,
+                34.000433
+              ],
+              [
+                117.569117,
+                33.985051
+              ],
+              [
+                117.543248,
+                34.038627
+              ],
+              [
+                117.514914,
+                34.060941
+              ],
+              [
+                117.435458,
+                34.028212
+              ],
+              [
+                117.404045,
+                34.03218
+              ],
+              [
+                117.357234,
+                34.088205
+              ],
+              [
+                117.311654,
+                34.067882
+              ],
+              [
+                117.277162,
+                34.078787
+              ],
+              [
+                117.257452,
+                34.065899
+              ],
+              [
+                117.192162,
+                34.068873
+              ],
+              [
+                117.130568,
+                34.101586
+              ],
+              [
+                117.123793,
+                34.128342
+              ],
+              [
+                117.046801,
+                34.151622
+              ],
+              [
+                117.025243,
+                34.167469
+              ],
+              [
+                117.051112,
+                34.221425
+              ],
+              [
+                116.969192,
+                34.283753
+              ],
+              [
+                116.983359,
+                34.348011
+              ],
+              [
+                116.960569,
+                34.363821
+              ],
+              [
+                116.969192,
+                34.389012
+              ],
+              [
+                116.909446,
+                34.408271
+              ],
+              [
+                116.828142,
+                34.389012
+              ],
+              [
+                116.782563,
+                34.429993
+              ],
+              [
+                116.773939,
+                34.453683
+              ],
+              [
+                116.722816,
+                34.472434
+              ],
+              [
+                116.662454,
+                34.472927
+              ],
+              [
+                116.592237,
+                34.493646
+              ],
+              [
+                116.594085,
+                34.511894
+              ],
+              [
+                116.490607,
+                34.573513
+              ],
+              [
+                116.477057,
+                34.614896
+              ],
+              [
+                116.432709,
+                34.630163
+              ],
+              [
+                116.430245,
+                34.650843
+              ],
+              [
+                116.374195,
+                34.640011
+              ],
+              [
+                116.334159,
+                34.620806
+              ],
+              [
+                116.32492,
+                34.601104
+              ],
+              [
+                116.286116,
+                34.608986
+              ],
+              [
+                116.247927,
+                34.551829
+              ],
+              [
+                116.196804,
+                34.575977
+              ],
+              [
+                116.191261,
+                34.535561
+              ],
+              [
+                116.204196,
+                34.508442
+              ],
+              [
+                116.178326,
+                34.496112
+              ],
+              [
+                116.162312,
+                34.459605
+              ],
+              [
+                116.178942,
+                34.430487
+              ],
+              [
+                116.215898,
+                34.403333
+              ],
+              [
+                116.213435,
+                34.382098
+              ],
+              [
+                116.255934,
+                34.376665
+              ],
+              [
+                116.301514,
+                34.342082
+              ],
+              [
+                116.357564,
+                34.319843
+              ],
+              [
+                116.372347,
+                34.26595
+              ],
+              [
+                116.409303,
+                34.273863
+              ],
+              [
+                116.409303,
+                34.273863
+              ],
+              [
+                116.456731,
+                34.268917
+              ],
+              [
+                116.516477,
+                34.296114
+              ],
+              [
+                116.562056,
+                34.285731
+              ],
+              [
+                116.582382,
+                34.266444
+              ],
+              [
+                116.545426,
+                34.241711
+              ],
+              [
+                116.542962,
+                34.203608
+              ],
+              [
+                116.565752,
+                34.16945
+              ],
+              [
+                116.536187,
+                34.151127
+              ],
+              [
+                116.52818,
+                34.122892
+              ],
+              [
+                116.576223,
+                34.068873
+              ],
+              [
+                116.576223,
+                34.068873
+              ],
+              [
+                116.599629,
+                34.014324
+              ],
+              [
+                116.599629,
+                34.014324
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.865669,
+                31.519139
+              ],
+              [
+                118.857046,
+                31.506384
+              ],
+              [
+                118.883532,
+                31.500261
+              ],
+              [
+                118.885995,
+                31.519139
+              ],
+              [
+                118.865669,
+                31.519139
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.698795,
+                29.707836
+              ],
+              [
+                116.673541,
+                29.709916
+              ],
+              [
+                116.653831,
+                29.694841
+              ],
+              [
+                116.680317,
+                29.681323
+              ],
+              [
+                116.704954,
+                29.688602
+              ],
+              [
+                116.706802,
+                29.6964
+              ],
+              [
+                116.70557,
+                29.69692
+              ],
+              [
+                116.698795,
+                29.707836
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.5088,
+                32.468761
+              ],
+              [
+                115.509416,
+                32.466741
+              ],
+              [
+                115.510648,
+                32.467751
+              ],
+              [
+                115.510648,
+                32.468256
+              ],
+              [
+                115.510648,
+                32.468761
+              ],
+              [
+                115.5088,
+                32.468761
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 350000,
+        "name": "绂忓缓鐪�",
+        "center": [
+          119.306239,
+          26.075302
+        ],
+        "centroid": [
+          118.006468,
+          26.069925
+        ],
+        "childrenNum": 9,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 12,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                119.004872,
+                24.970009
+              ],
+              [
+                118.989473,
+                24.973807
+              ],
+              [
+                119.023966,
+                25.04377
+              ],
+              [
+                119.016575,
+                25.058409
+              ],
+              [
+                118.974691,
+                25.024792
+              ],
+              [
+                118.945126,
+                25.028588
+              ],
+              [
+                118.892155,
+                25.092558
+              ],
+              [
+                118.974691,
+                25.115319
+              ],
+              [
+                118.951901,
+                25.15162
+              ],
+              [
+                118.985162,
+                25.168954
+              ],
+              [
+                118.985162,
+                25.19495
+              ],
+              [
+                118.942046,
+                25.211195
+              ],
+              [
+                118.940198,
+                25.21715
+              ],
+              [
+                118.943278,
+                25.221482
+              ],
+              [
+                118.903242,
+                25.239347
+              ],
+              [
+                118.900162,
+                25.242595
+              ],
+              [
+                118.919256,
+                25.248008
+              ],
+              [
+                118.91556,
+                25.256668
+              ],
+              [
+                118.918024,
+                25.25721
+              ],
+              [
+                118.956212,
+                25.272905
+              ],
+              [
+                118.996864,
+                25.266411
+              ],
+              [
+                118.975307,
+                25.237723
+              ],
+              [
+                118.990089,
+                25.20199
+              ],
+              [
+                119.055379,
+                25.219316
+              ],
+              [
+                119.074473,
+                25.211195
+              ],
+              [
+                119.054147,
+                25.168412
+              ],
+              [
+                119.032589,
+                25.17437
+              ],
+              [
+                119.028893,
+                25.139702
+              ],
+              [
+                119.06585,
+                25.102855
+              ],
+              [
+                119.075705,
+                25.099604
+              ],
+              [
+                119.134219,
+                25.106107
+              ],
+              [
+                119.107118,
+                25.075214
+              ],
+              [
+                119.119436,
+                25.012861
+              ],
+              [
+                119.146538,
+                25.056782
+              ],
+              [
+                119.165632,
+                25.145661
+              ],
+              [
+                119.137299,
+                25.15487
+              ],
+              [
+                119.108349,
+                25.193867
+              ],
+              [
+                119.131755,
+                25.223106
+              ],
+              [
+                119.190269,
+                25.175995
+              ],
+              [
+                119.231537,
+                25.188993
+              ],
+              [
+                119.26911,
+                25.159746
+              ],
+              [
+                119.314689,
+                25.190076
+              ],
+              [
+                119.294979,
+                25.237182
+              ],
+              [
+                119.331935,
+                25.230685
+              ],
+              [
+                119.380595,
+                25.250173
+              ],
+              [
+                119.333167,
+                25.287516
+              ],
+              [
+                119.299291,
+                25.328634
+              ],
+              [
+                119.247552,
+                25.333502
+              ],
+              [
+                119.240776,
+                25.316733
+              ],
+              [
+                119.218603,
+                25.368115
+              ],
+              [
+                119.14469,
+                25.388121
+              ],
+              [
+                119.151465,
+                25.426503
+              ],
+              [
+                119.191501,
+                25.424341
+              ],
+              [
+                119.232153,
+                25.442176
+              ],
+              [
+                119.219834,
+                25.468654
+              ],
+              [
+                119.256175,
+                25.488643
+              ],
+              [
+                119.275269,
+                25.476758
+              ],
+              [
+                119.26295,
+                25.428124
+              ],
+              [
+                119.288204,
+                25.410827
+              ],
+              [
+                119.353493,
+                25.411908
+              ],
+              [
+                119.343638,
+                25.472436
+              ],
+              [
+                119.359037,
+                25.521592
+              ],
+              [
+                119.400921,
+                25.493505
+              ],
+              [
+                119.45266,
+                25.493505
+              ],
+              [
+                119.438493,
+                25.412449
+              ],
+              [
+                119.463131,
+                25.448661
+              ],
+              [
+                119.491464,
+                25.443257
+              ],
+              [
+                119.48592,
+                25.418935
+              ],
+              [
+                119.507478,
+                25.396231
+              ],
+              [
+                119.486536,
+                25.369737
+              ],
+              [
+                119.548746,
+                25.365952
+              ],
+              [
+                119.578927,
+                25.400556
+              ],
+              [
+                119.555521,
+                25.429205
+              ],
+              [
+                119.577695,
+                25.445959
+              ],
+              [
+                119.59063,
+                25.398394
+              ],
+              [
+                119.582623,
+                25.374063
+              ],
+              [
+                119.597405,
+                25.334584
+              ],
+              [
+                119.649144,
+                25.342697
+              ],
+              [
+                119.665159,
+                25.3719
+              ],
+              [
+                119.656535,
+                25.396772
+              ],
+              [
+                119.670086,
+                25.435691
+              ],
+              [
+                119.622659,
+                25.434069
+              ],
+              [
+                119.675014,
+                25.468113
+              ],
+              [
+                119.682405,
+                25.445959
+              ],
+              [
+                119.688564,
+                25.441095
+              ],
+              [
+                119.773564,
+                25.395691
+              ],
+              [
+                119.764325,
+                25.433529
+              ],
+              [
+                119.804977,
+                25.457847
+              ],
+              [
+                119.866571,
+                25.455145
+              ],
+              [
+                119.864107,
+                25.469734
+              ],
+              [
+                119.862875,
+                25.474597
+              ],
+              [
+                119.811136,
+                25.507009
+              ],
+              [
+                119.81668,
+                25.532393
+              ],
+              [
+                119.861027,
+                25.531313
+              ],
+              [
+                119.883817,
+                25.546432
+              ],
+              [
+                119.831462,
+                25.579905
+              ],
+              [
+                119.843165,
+                25.597717
+              ],
+              [
+                119.790194,
+                25.614447
+              ],
+              [
+                119.785883,
+                25.66786
+              ],
+              [
+                119.700267,
+                25.616606
+              ],
+              [
+                119.683637,
+                25.592859
+              ],
+              [
+                119.716898,
+                25.551292
+              ],
+              [
+                119.715666,
+                25.51187
+              ],
+              [
+                119.680557,
+                25.497827
+              ],
+              [
+                119.675014,
+                25.475137
+              ],
+              [
+                119.634362,
+                25.475137
+              ],
+              [
+                119.611572,
+                25.519972
+              ],
+              [
+                119.616499,
+                25.556691
+              ],
+              [
+                119.586934,
+                25.59232
+              ],
+              [
+                119.534579,
+                25.585303
+              ],
+              [
+                119.541355,
+                25.6247
+              ],
+              [
+                119.478529,
+                25.631715
+              ],
+              [
+                119.472986,
+                25.662466
+              ],
+              [
+                119.543819,
+                25.684581
+              ],
+              [
+                119.602949,
+                25.68512
+              ],
+              [
+                119.602949,
+                25.714779
+              ],
+              [
+                119.626354,
+                25.723406
+              ],
+              [
+                119.628202,
+                25.87212
+              ],
+              [
+                119.638057,
+                25.889888
+              ],
+              [
+                119.69534,
+                25.904424
+              ],
+              [
+                119.723673,
+                26.011503
+              ],
+              [
+                119.700267,
+                26.032477
+              ],
+              [
+                119.668854,
+                26.026024
+              ],
+              [
+                119.654688,
+                26.090002
+              ],
+              [
+                119.618963,
+                26.11956
+              ],
+              [
+                119.604181,
+                26.168985
+              ],
+              [
+                119.664543,
+                26.202282
+              ],
+              [
+                119.676246,
+                26.262943
+              ],
+              [
+                119.7711,
+                26.285481
+              ],
+              [
+                119.802513,
+                26.268846
+              ],
+              [
+                119.806825,
+                26.307479
+              ],
+              [
+                119.845013,
+                26.323036
+              ],
+              [
+                119.862875,
+                26.307479
+              ],
+              [
+                119.904143,
+                26.308552
+              ],
+              [
+                119.95465,
+                26.352534
+              ],
+              [
+                119.946027,
+                26.374519
+              ],
+              [
+                119.893672,
+                26.355752
+              ],
+              [
+                119.835774,
+                26.434019
+              ],
+              [
+                119.83639,
+                26.454381
+              ],
+              [
+                119.788346,
+                26.583435
+              ],
+              [
+                119.740303,
+                26.610727
+              ],
+              [
+                119.670086,
+                26.618218
+              ],
+              [
+                119.605412,
+                26.595744
+              ],
+              [
+                119.577695,
+                26.622498
+              ],
+              [
+                119.619579,
+                26.649246
+              ],
+              [
+                119.637441,
+                26.703256
+              ],
+              [
+                119.664543,
+                26.726243
+              ],
+              [
+                119.711354,
+                26.686681
+              ],
+              [
+                119.833926,
+                26.690959
+              ],
+              [
+                119.864107,
+                26.671174
+              ],
+              [
+                119.873962,
+                26.642827
+              ],
+              [
+                119.908455,
+                26.661547
+              ],
+              [
+                119.899216,
+                26.693098
+              ],
+              [
+                119.938636,
+                26.747088
+              ],
+              [
+                119.942947,
+                26.784492
+              ],
+              [
+                120.052584,
+                26.786629
+              ],
+              [
+                120.061824,
+                26.768997
+              ],
+              [
+                119.99407,
+                26.720363
+              ],
+              [
+                119.969433,
+                26.686681
+              ],
+              [
+                119.972512,
+                26.654594
+              ],
+              [
+                119.949107,
+                26.624638
+              ],
+              [
+                119.901679,
+                26.624638
+              ],
+              [
+                119.851788,
+                26.595209
+              ],
+              [
+                119.828383,
+                26.524013
+              ],
+              [
+                119.867187,
+                26.509019
+              ],
+              [
+                119.947875,
+                26.56042
+              ],
+              [
+                119.93802,
+                26.576478
+              ],
+              [
+                119.967585,
+                26.597885
+              ],
+              [
+                120.007621,
+                26.595744
+              ],
+              [
+                120.063671,
+                26.627848
+              ],
+              [
+                120.093852,
+                26.613938
+              ],
+              [
+                120.1382,
+                26.638012
+              ],
+              [
+                120.110483,
+                26.692563
+              ],
+              [
+                120.162222,
+                26.717691
+              ],
+              [
+                120.151135,
+                26.750829
+              ],
+              [
+                120.106787,
+                26.752966
+              ],
+              [
+                120.136352,
+                26.797847
+              ],
+              [
+                120.103707,
+                26.794642
+              ],
+              [
+                120.102476,
+                26.82669
+              ],
+              [
+                120.073526,
+                26.823485
+              ],
+              [
+                120.054432,
+                26.863533
+              ],
+              [
+                120.117874,
+                26.882751
+              ],
+              [
+                120.126497,
+                26.920644
+              ],
+              [
+                120.130193,
+                26.917976
+              ],
+              [
+                120.1807,
+                26.920644
+              ],
+              [
+                120.233055,
+                26.907837
+              ],
+              [
+                120.25954,
+                26.982526
+              ],
+              [
+                120.279866,
+                26.987326
+              ],
+              [
+                120.275554,
+                27.027315
+              ],
+              [
+                120.29588,
+                27.035845
+              ],
+              [
+                120.282946,
+                27.089671
+              ],
+              [
+                120.391967,
+                27.081146
+              ],
+              [
+                120.403054,
+                27.10086
+              ],
+              [
+                120.461568,
+                27.142407
+              ],
+              [
+                120.404286,
+                27.204166
+              ],
+              [
+                120.401822,
+                27.250996
+              ],
+              [
+                120.430155,
+                27.258976
+              ],
+              [
+                120.343924,
+                27.363199
+              ],
+              [
+                120.340844,
+                27.399867
+              ],
+              [
+                120.273091,
+                27.38924
+              ],
+              [
+                120.26262,
+                27.432804
+              ],
+              [
+                120.221352,
+                27.420055
+              ],
+              [
+                120.134504,
+                27.420055
+              ],
+              [
+                120.136968,
+                27.402523
+              ],
+              [
+                120.096316,
+                27.390302
+              ],
+              [
+                120.052584,
+                27.338747
+              ],
+              [
+                120.026099,
+                27.344063
+              ],
+              [
+                120.008237,
+                27.375423
+              ],
+              [
+                119.960194,
+                27.365857
+              ],
+              [
+                119.938636,
+                27.329709
+              ],
+              [
+                119.843165,
+                27.300464
+              ],
+              [
+                119.768636,
+                27.307909
+              ],
+              [
+                119.782187,
+                27.330241
+              ],
+              [
+                119.739687,
+                27.362668
+              ],
+              [
+                119.750774,
+                27.373829
+              ],
+              [
+                119.711354,
+                27.403054
+              ],
+              [
+                119.685485,
+                27.438646
+              ],
+              [
+                119.703347,
+                27.446613
+              ],
+              [
+                119.70889,
+                27.514042
+              ],
+              [
+                119.690412,
+                27.537394
+              ],
+              [
+                119.659615,
+                27.540578
+              ],
+              [
+                119.675014,
+                27.574534
+              ],
+              [
+                119.630666,
+                27.582491
+              ],
+              [
+                119.626354,
+                27.620676
+              ],
+              [
+                119.644217,
+                27.663619
+              ],
+              [
+                119.606028,
+                27.674749
+              ],
+              [
+                119.541971,
+                27.666799
+              ],
+              [
+                119.501319,
+                27.649837
+              ],
+              [
+                119.501935,
+                27.610601
+              ],
+              [
+                119.466826,
+                27.526249
+              ],
+              [
+                119.438493,
+                27.508734
+              ],
+              [
+                119.416935,
+                27.539517
+              ],
+              [
+                119.360269,
+                27.524657
+              ],
+              [
+                119.334399,
+                27.480067
+              ],
+              [
+                119.285124,
+                27.457766
+              ],
+              [
+                119.26911,
+                27.42218
+              ],
+              [
+                119.224146,
+                27.416868
+              ],
+              [
+                119.14777,
+                27.424836
+              ],
+              [
+                119.121284,
+                27.438115
+              ],
+              [
+                119.129907,
+                27.475289
+              ],
+              [
+                119.092335,
+                27.466262
+              ],
+              [
+                119.03998,
+                27.478475
+              ],
+              [
+                119.020886,
+                27.498118
+              ],
+              [
+                118.983314,
+                27.498649
+              ],
+              [
+                118.986393,
+                27.47582
+              ],
+              [
+                118.955597,
+                27.4498
+              ],
+              [
+                118.907553,
+                27.460952
+              ],
+              [
+                118.869365,
+                27.540047
+              ],
+              [
+                118.909401,
+                27.568168
+              ],
+              [
+                118.913713,
+                27.619616
+              ],
+              [
+                118.879836,
+                27.667859
+              ],
+              [
+                118.873677,
+                27.733563
+              ],
+              [
+                118.829329,
+                27.847921
+              ],
+              [
+                118.818242,
+                27.916689
+              ],
+              [
+                118.753568,
+                27.947885
+              ],
+              [
+                118.730163,
+                27.970615
+              ],
+              [
+                118.733858,
+                28.027684
+              ],
+              [
+                118.719076,
+                28.063601
+              ],
+              [
+                118.767735,
+                28.10584
+              ],
+              [
+                118.802228,
+                28.117453
+              ],
+              [
+                118.805923,
+                28.154923
+              ],
+              [
+                118.771431,
+                28.188687
+              ],
+              [
+                118.804075,
+                28.207675
+              ],
+              [
+                118.802228,
+                28.240368
+              ],
+              [
+                118.756032,
+                28.252493
+              ],
+              [
+                118.719692,
+                28.312047
+              ],
+              [
+                118.699366,
+                28.309939
+              ],
+              [
+                118.674728,
+                28.27147
+              ],
+              [
+                118.651322,
+                28.277267
+              ],
+              [
+                118.595272,
+                28.258292
+              ],
+              [
+                118.588497,
+                28.282538
+              ],
+              [
+                118.493026,
+                28.262509
+              ],
+              [
+                118.490562,
+                28.238259
+              ],
+              [
+                118.444367,
+                28.253548
+              ],
+              [
+                118.433896,
+                28.288335
+              ],
+              [
+                118.424041,
+                28.291497
+              ],
+              [
+                118.314404,
+                28.221913
+              ],
+              [
+                118.339041,
+                28.193962
+              ],
+              [
+                118.375382,
+                28.186577
+              ],
+              [
+                118.361215,
+                28.155978
+              ],
+              [
+                118.356288,
+                28.091586
+              ],
+              [
+                118.242339,
+                28.075746
+              ],
+              [
+                118.199839,
+                28.049869
+              ],
+              [
+                118.153644,
+                28.062016
+              ],
+              [
+                118.120999,
+                28.041946
+              ],
+              [
+                118.129006,
+                28.017118
+              ],
+              [
+                118.094513,
+                28.003909
+              ],
+              [
+                118.096977,
+                27.970615
+              ],
+              [
+                117.999043,
+                27.991227
+              ],
+              [
+                117.965166,
+                27.962687
+              ],
+              [
+                117.942992,
+                27.974315
+              ],
+              [
+                117.910963,
+                27.949471
+              ],
+              [
+                117.856145,
+                27.94577
+              ],
+              [
+                117.78716,
+                27.896063
+              ],
+              [
+                117.788392,
+                27.855858
+              ],
+              [
+                117.740348,
+                27.800286
+              ],
+              [
+                117.704624,
+                27.834162
+              ],
+              [
+                117.68245,
+                27.823577
+              ],
+              [
+                117.649805,
+                27.851625
+              ],
+              [
+                117.609769,
+                27.863265
+              ],
+              [
+                117.556182,
+                27.966387
+              ],
+              [
+                117.52169,
+                27.982243
+              ],
+              [
+                117.477958,
+                27.930966
+              ],
+              [
+                117.453936,
+                27.939955
+              ],
+              [
+                117.407741,
+                27.893948
+              ],
+              [
+                117.366473,
+                27.88231
+              ],
+              [
+                117.341836,
+                27.855858
+              ],
+              [
+                117.334444,
+                27.8876
+              ],
+              [
+                117.280242,
+                27.871201
+              ],
+              [
+                117.276546,
+                27.847921
+              ],
+              [
+                117.303031,
+                27.833103
+              ],
+              [
+                117.296256,
+                27.764282
+              ],
+              [
+                117.245133,
+                27.71926
+              ],
+              [
+                117.205097,
+                27.714492
+              ],
+              [
+                117.204481,
+                27.683759
+              ],
+              [
+                117.174916,
+                27.677399
+              ],
+              [
+                117.114554,
+                27.692238
+              ],
+              [
+                117.096076,
+                27.667329
+              ],
+              [
+                117.11209,
+                27.645596
+              ],
+              [
+                117.094228,
+                27.627569
+              ],
+              [
+                117.065279,
+                27.665739
+              ],
+              [
+                117.040641,
+                27.669979
+              ],
+              [
+                117.003685,
+                27.625449
+              ],
+              [
+                117.024627,
+                27.592569
+              ],
+              [
+                117.01662,
+                27.563393
+              ],
+              [
+                117.054808,
+                27.5427
+              ],
+              [
+                117.076982,
+                27.566046
+              ],
+              [
+                117.103467,
+                27.533149
+              ],
+              [
+                117.110242,
+                27.458828
+              ],
+              [
+                117.133032,
+                27.42218
+              ],
+              [
+                117.107163,
+                27.393491
+              ],
+              [
+                117.104699,
+                27.330773
+              ],
+              [
+                117.140423,
+                27.322798
+              ],
+              [
+                117.136728,
+                27.303123
+              ],
+              [
+                117.171836,
+                27.29036
+              ],
+              [
+                117.149662,
+                27.241419
+              ],
+              [
+                117.044953,
+                27.146667
+              ],
+              [
+                117.05296,
+                27.100327
+              ],
+              [
+                116.967344,
+                27.061962
+              ],
+              [
+                116.936547,
+                27.019319
+              ],
+              [
+                116.910062,
+                27.034779
+              ],
+              [
+                116.851548,
+                27.009188
+              ],
+              [
+                116.817671,
+                27.018252
+              ],
+              [
+                116.679085,
+                26.978259
+              ],
+              [
+                116.632889,
+                26.933984
+              ],
+              [
+                116.602092,
+                26.888623
+              ],
+              [
+                116.548506,
+                26.84004
+              ],
+              [
+                116.543578,
+                26.803723
+              ],
+              [
+                116.557745,
+                26.773806
+              ],
+              [
+                116.515245,
+                26.720898
+              ],
+              [
+                116.520172,
+                26.684543
+              ],
+              [
+                116.566368,
+                26.650315
+              ],
+              [
+                116.553433,
+                26.575942
+              ],
+              [
+                116.539267,
+                26.559349
+              ],
+              [
+                116.597165,
+                26.512768
+              ],
+              [
+                116.610716,
+                26.476882
+              ],
+              [
+                116.638433,
+                26.477418
+              ],
+              [
+                116.608252,
+                26.429732
+              ],
+              [
+                116.601476,
+                26.372911
+              ],
+              [
+                116.553433,
+                26.365404
+              ],
+              [
+                116.553433,
+                26.400253
+              ],
+              [
+                116.519557,
+                26.410437
+              ],
+              [
+                116.499846,
+                26.361651
+              ],
+              [
+                116.459194,
+                26.345026
+              ],
+              [
+                116.437021,
+                26.308016
+              ],
+              [
+                116.412999,
+                26.297822
+              ],
+              [
+                116.385282,
+                26.238253
+              ],
+              [
+                116.400064,
+                26.202819
+              ],
+              [
+                116.392057,
+                26.171133
+              ],
+              [
+                116.435789,
+                26.159854
+              ],
+              [
+                116.476441,
+                26.172745
+              ],
+              [
+                116.489375,
+                26.113649
+              ],
+              [
+                116.384666,
+                26.030864
+              ],
+              [
+                116.360028,
+                25.991601
+              ],
+              [
+                116.369883,
+                25.963088
+              ],
+              [
+                116.326152,
+                25.956631
+              ],
+              [
+                116.303362,
+                25.924341
+              ],
+              [
+                116.258398,
+                25.902809
+              ],
+              [
+                116.225138,
+                25.908731
+              ],
+              [
+                116.17771,
+                25.894195
+              ],
+              [
+                116.132131,
+                25.860273
+              ],
+              [
+                116.131515,
+                25.824185
+              ],
+              [
+                116.18079,
+                25.778926
+              ],
+              [
+                116.129667,
+                25.758985
+              ],
+              [
+                116.106877,
+                25.701299
+              ],
+              [
+                116.067457,
+                25.703995
+              ],
+              [
+                116.068689,
+                25.646282
+              ],
+              [
+                116.041588,
+                25.62416
+              ],
+              [
+                116.063145,
+                25.56317
+              ],
+              [
+                116.040356,
+                25.548052
+              ],
+              [
+                116.03666,
+                25.514571
+              ],
+              [
+                116.005247,
+                25.490264
+              ],
+              [
+                116.023109,
+                25.435691
+              ],
+              [
+                115.992928,
+                25.374063
+              ],
+              [
+                116.008327,
+                25.319437
+              ],
+              [
+                115.987385,
+                25.290221
+              ],
+              [
+                115.949813,
+                25.292386
+              ],
+              [
+                115.930719,
+                25.236099
+              ],
+              [
+                115.855574,
+                25.20957
+              ],
+              [
+                115.860501,
+                25.165704
+              ],
+              [
+                115.888219,
+                25.128866
+              ],
+              [
+                115.880212,
+                25.092016
+              ],
+              [
+                115.908545,
+                25.084428
+              ],
+              [
+                115.928255,
+                25.050276
+              ],
+              [
+                115.873436,
+                25.019911
+              ],
+              [
+                115.925175,
+                24.960786
+              ],
+              [
+                115.870356,
+                24.959701
+              ],
+              [
+                115.89253,
+                24.936911
+              ],
+              [
+                115.907929,
+                24.923343
+              ],
+              [
+                115.985537,
+                24.899461
+              ],
+              [
+                116.015102,
+                24.905975
+              ],
+              [
+                116.068073,
+                24.850053
+              ],
+              [
+                116.153073,
+                24.846795
+              ],
+              [
+                116.191877,
+                24.877203
+              ],
+              [
+                116.221442,
+                24.829959
+              ],
+              [
+                116.251007,
+                24.82507
+              ],
+              [
+                116.244232,
+                24.793563
+              ],
+              [
+                116.297202,
+                24.801712
+              ],
+              [
+                116.345862,
+                24.828872
+              ],
+              [
+                116.363724,
+                24.87123
+              ],
+              [
+                116.395137,
+                24.877746
+              ],
+              [
+                116.417927,
+                24.840821
+              ],
+              [
+                116.381586,
+                24.82507
+              ],
+              [
+                116.375427,
+                24.803885
+              ],
+              [
+                116.419158,
+                24.767482
+              ],
+              [
+                116.416079,
+                24.744113
+              ],
+              [
+                116.44626,
+                24.714216
+              ],
+              [
+                116.485064,
+                24.720196
+              ],
+              [
+                116.517709,
+                24.652225
+              ],
+              [
+                116.506622,
+                24.621218
+              ],
+              [
+                116.530027,
+                24.604895
+              ],
+              [
+                116.570679,
+                24.621762
+              ],
+              [
+                116.600861,
+                24.654401
+              ],
+              [
+                116.623034,
+                24.64189
+              ],
+              [
+                116.667382,
+                24.658752
+              ],
+              [
+                116.777635,
+                24.679418
+              ],
+              [
+                116.815207,
+                24.654944
+              ],
+              [
+                116.761005,
+                24.583128
+              ],
+              [
+                116.759157,
+                24.545572
+              ],
+              [
+                116.796729,
+                24.502014
+              ],
+              [
+                116.83307,
+                24.496568
+              ],
+              [
+                116.860787,
+                24.460075
+              ],
+              [
+                116.839229,
+                24.442097
+              ],
+              [
+                116.903903,
+                24.369614
+              ],
+              [
+                116.895895,
+                24.350533
+              ],
+              [
+                116.919301,
+                24.321087
+              ],
+              [
+                116.914374,
+                24.287817
+              ],
+              [
+                116.938395,
+                24.28127
+              ],
+              [
+                116.933468,
+                24.220157
+              ],
+              [
+                116.956257,
+                24.216883
+              ],
+              [
+                116.998757,
+                24.179217
+              ],
+              [
+                116.9347,
+                24.126794
+              ],
+              [
+                116.930388,
+                24.064514
+              ],
+              [
+                116.953178,
+                24.008218
+              ],
+              [
+                116.981511,
+                23.999471
+              ],
+              [
+                116.976583,
+                23.931659
+              ],
+              [
+                116.955642,
+                23.922359
+              ],
+              [
+                116.981511,
+                23.855602
+              ],
+              [
+                117.012308,
+                23.855054
+              ],
+              [
+                117.019083,
+                23.801952
+              ],
+              [
+                117.048032,
+                23.758687
+              ],
+              [
+                117.055424,
+                23.694038
+              ],
+              [
+                117.123793,
+                23.647448
+              ],
+              [
+                117.147199,
+                23.654027
+              ],
+              [
+                117.192778,
+                23.629356
+              ],
+              [
+                117.192778,
+                23.5619
+              ],
+              [
+                117.291328,
+                23.571225
+              ],
+              [
+                117.302415,
+                23.550379
+              ],
+              [
+                117.387415,
+                23.555317
+              ],
+              [
+                117.463791,
+                23.584937
+              ],
+              [
+                117.454552,
+                23.628259
+              ],
+              [
+                117.493357,
+                23.642514
+              ],
+              [
+                117.501364,
+                23.70445
+              ],
+              [
+                117.54448,
+                23.715956
+              ],
+              [
+                117.601762,
+                23.70171
+              ],
+              [
+                117.660276,
+                23.789357
+              ],
+              [
+                117.651653,
+                23.815093
+              ],
+              [
+                117.671979,
+                23.878041
+              ],
+              [
+                117.691073,
+                23.888985
+              ],
+              [
+                117.762522,
+                23.886796
+              ],
+              [
+                117.792703,
+                23.906494
+              ],
+              [
+                117.807486,
+                23.947521
+              ],
+              [
+                117.864768,
+                24.004938
+              ],
+              [
+                117.910347,
+                24.012045
+              ],
+              [
+                117.927594,
+                24.039922
+              ],
+              [
+                117.936217,
+                24.100029
+              ],
+              [
+                118.000275,
+                24.152462
+              ],
+              [
+                118.019369,
+                24.197232
+              ],
+              [
+                118.074803,
+                24.225615
+              ],
+              [
+                118.115455,
+                24.229435
+              ],
+              [
+                118.158571,
+                24.269814
+              ],
+              [
+                118.112376,
+                24.357075
+              ],
+              [
+                118.081579,
+                24.35653
+              ],
+              [
+                118.088354,
+                24.408858
+              ],
+              [
+                118.048934,
+                24.418122
+              ],
+              [
+                118.084042,
+                24.528695
+              ],
+              [
+                118.121615,
+                24.570067
+              ],
+              [
+                118.150564,
+                24.583673
+              ],
+              [
+                118.169042,
+                24.559725
+              ],
+              [
+                118.242955,
+                24.51236
+              ],
+              [
+                118.375382,
+                24.536317
+              ],
+              [
+                118.363679,
+                24.567889
+              ],
+              [
+                118.444367,
+                24.614689
+              ],
+              [
+                118.512736,
+                24.60816
+              ],
+              [
+                118.557084,
+                24.572788
+              ],
+              [
+                118.558316,
+                24.51236
+              ],
+              [
+                118.614366,
+                24.521617
+              ],
+              [
+                118.680272,
+                24.58204
+              ],
+              [
+                118.687047,
+                24.63373
+              ],
+              [
+                118.661178,
+                24.622306
+              ],
+              [
+                118.652554,
+                24.653857
+              ],
+              [
+                118.670417,
+                24.679962
+              ],
+              [
+                118.703677,
+                24.665278
+              ],
+              [
+                118.778822,
+                24.743569
+              ],
+              [
+                118.786213,
+                24.77672
+              ],
+              [
+                118.650707,
+                24.808774
+              ],
+              [
+                118.647627,
+                24.843536
+              ],
+              [
+                118.702445,
+                24.865258
+              ],
+              [
+                118.69875,
+                24.848967
+              ],
+              [
+                118.748641,
+                24.84245
+              ],
+              [
+                118.807771,
+                24.870687
+              ],
+              [
+                118.834256,
+                24.854397
+              ],
+              [
+                118.864437,
+                24.887518
+              ],
+              [
+                118.933423,
+                24.870687
+              ],
+              [
+                118.988857,
+                24.878831
+              ],
+              [
+                118.987009,
+                24.898375
+              ],
+              [
+                118.932807,
+                24.906518
+              ],
+              [
+                118.91864,
+                24.932569
+              ],
+              [
+                118.945741,
+                24.954275
+              ],
+              [
+                119.014111,
+                24.941252
+              ],
+              [
+                119.032589,
+                24.961328
+              ],
+              [
+                119.032589,
+                24.961871
+              ],
+              [
+                119.007335,
+                24.963499
+              ],
+              [
+                119.004872,
+                24.970009
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.412338,
+                24.514538
+              ],
+              [
+                118.374766,
+                24.458986
+              ],
+              [
+                118.318715,
+                24.486765
+              ],
+              [
+                118.298389,
+                24.477506
+              ],
+              [
+                118.31194,
+                24.424661
+              ],
+              [
+                118.282375,
+                24.413218
+              ],
+              [
+                118.329802,
+                24.382152
+              ],
+              [
+                118.353208,
+                24.415398
+              ],
+              [
+                118.405563,
+                24.427931
+              ],
+              [
+                118.457918,
+                24.412128
+              ],
+              [
+                118.477012,
+                24.437738
+              ],
+              [
+                118.451758,
+                24.506915
+              ],
+              [
+                118.412338,
+                24.514538
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.471138,
+                25.197116
+              ],
+              [
+                119.507478,
+                25.183036
+              ],
+              [
+                119.52534,
+                25.157579
+              ],
+              [
+                119.549362,
+                25.161912
+              ],
+              [
+                119.566608,
+                25.210112
+              ],
+              [
+                119.540739,
+                25.20199
+              ],
+              [
+                119.501319,
+                25.21715
+              ],
+              [
+                119.473601,
+                25.259916
+              ],
+              [
+                119.44342,
+                25.238806
+              ],
+              [
+                119.444036,
+                25.20199
+              ],
+              [
+                119.471138,
+                25.197116
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.580159,
+                25.627398
+              ],
+              [
+                119.611572,
+                25.669479
+              ],
+              [
+                119.580775,
+                25.650059
+              ],
+              [
+                119.580159,
+                25.627398
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.976824,
+                26.191005
+              ],
+              [
+                120.016244,
+                26.217316
+              ],
+              [
+                119.998998,
+                26.235569
+              ],
+              [
+                119.970665,
+                26.217852
+              ],
+              [
+                119.976824,
+                26.191005
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.230636,
+                24.401228
+              ],
+              [
+                118.273752,
+                24.441007
+              ],
+              [
+                118.233716,
+                24.445911
+              ],
+              [
+                118.230636,
+                24.401228
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.906607,
+                26.68989
+              ],
+              [
+                119.926933,
+                26.664756
+              ],
+              [
+                119.950954,
+                26.692563
+              ],
+              [
+                119.906607,
+                26.68989
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.204151,
+                24.504737
+              ],
+              [
+                118.191832,
+                24.536861
+              ],
+              [
+                118.14502,
+                24.560814
+              ],
+              [
+                118.093281,
+                24.540672
+              ],
+              [
+                118.068644,
+                24.463344
+              ],
+              [
+                118.084042,
+                24.435559
+              ],
+              [
+                118.143173,
+                24.420847
+              ],
+              [
+                118.19368,
+                24.463344
+              ],
+              [
+                118.204151,
+                24.504737
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.929397,
+                26.134067
+              ],
+              [
+                119.960194,
+                26.146961
+              ],
+              [
+                119.919542,
+                26.172208
+              ],
+              [
+                119.929397,
+                26.134067
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.642985,
+                26.129231
+              ],
+              [
+                119.665159,
+                26.155556
+              ],
+              [
+                119.62697,
+                26.173282
+              ],
+              [
+                119.606028,
+                26.15287
+              ],
+              [
+                119.642985,
+                26.129231
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.034106,
+                26.488667
+              ],
+              [
+                120.066751,
+                26.498308
+              ],
+              [
+                120.071679,
+                26.521336
+              ],
+              [
+                120.035954,
+                26.515981
+              ],
+              [
+                120.034106,
+                26.488667
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.662079,
+                25.646822
+              ],
+              [
+                119.673782,
+                25.632794
+              ],
+              [
+                119.718745,
+                25.634952
+              ],
+              [
+                119.716898,
+                25.664624
+              ],
+              [
+                119.662079,
+                25.646822
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.760629,
+                26.613402
+              ],
+              [
+                119.776644,
+                26.600025
+              ],
+              [
+                119.818527,
+                26.616613
+              ],
+              [
+                119.796354,
+                26.630523
+              ],
+              [
+                119.760629,
+                26.613402
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.135736,
+                26.550784
+              ],
+              [
+                120.167149,
+                26.571661
+              ],
+              [
+                120.153598,
+                26.604841
+              ],
+              [
+                120.117874,
+                26.568984
+              ],
+              [
+                120.135736,
+                26.550784
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.360554,
+                26.916909
+              ],
+              [
+                120.394431,
+                26.933984
+              ],
+              [
+                120.363018,
+                26.967592
+              ],
+              [
+                120.327909,
+                26.963858
+              ],
+              [
+                120.319286,
+                26.944654
+              ],
+              [
+                120.360554,
+                26.916909
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.150519,
+                26.798916
+              ],
+              [
+                120.140048,
+                26.795176
+              ],
+              [
+                120.163454,
+                26.798381
+              ],
+              [
+                120.161606,
+                26.803189
+              ],
+              [
+                120.150519,
+                26.798916
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.668238,
+                26.628383
+              ],
+              [
+                119.720593,
+                26.635873
+              ],
+              [
+                119.758781,
+                26.659408
+              ],
+              [
+                119.748926,
+                26.681334
+              ],
+              [
+                119.712586,
+                26.6685
+              ],
+              [
+                119.673782,
+                26.680799
+              ],
+              [
+                119.651608,
+                26.657269
+              ],
+              [
+                119.668238,
+                26.628383
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 360000,
+        "name": "姹熻タ鐪�",
+        "center": [
+          115.892151,
+          28.676493
+        ],
+        "centroid": [
+          115.732975,
+          27.636112
+        ],
+        "childrenNum": 11,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 13,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                118.193064,
+                29.395472
+              ],
+              [
+                118.136397,
+                29.418932
+              ],
+              [
+                118.127774,
+                29.47209
+              ],
+              [
+                118.143788,
+                29.489803
+              ],
+              [
+                118.095129,
+                29.534072
+              ],
+              [
+                118.050782,
+                29.542924
+              ],
+              [
+                118.042774,
+                29.566351
+              ],
+              [
+                118.00397,
+                29.578322
+              ],
+              [
+                117.933753,
+                29.549172
+              ],
+              [
+                117.872775,
+                29.54761
+              ],
+              [
+                117.795167,
+                29.570515
+              ],
+              [
+                117.729877,
+                29.550213
+              ],
+              [
+                117.690457,
+                29.555939
+              ],
+              [
+                117.678754,
+                29.595496
+              ],
+              [
+                117.647957,
+                29.614749
+              ],
+              [
+                117.608537,
+                29.591333
+              ],
+              [
+                117.543248,
+                29.588731
+              ],
+              [
+                117.523538,
+                29.630356
+              ],
+              [
+                117.530313,
+                29.654282
+              ],
+              [
+                117.490277,
+                29.660003
+              ],
+              [
+                117.453936,
+                29.688082
+              ],
+              [
+                117.455168,
+                29.749412
+              ],
+              [
+                117.408973,
+                29.802396
+              ],
+              [
+                117.415132,
+                29.85068
+              ],
+              [
+                117.382487,
+                29.840818
+              ],
+              [
+                117.359082,
+                29.812782
+              ],
+              [
+                117.338756,
+                29.848085
+              ],
+              [
+                117.29256,
+                29.822647
+              ],
+              [
+                117.25314,
+                29.834588
+              ],
+              [
+                117.261763,
+                29.880781
+              ],
+              [
+                117.246365,
+                29.915023
+              ],
+              [
+                117.2168,
+                29.926953
+              ],
+              [
+                117.171836,
+                29.920729
+              ],
+              [
+                117.129952,
+                29.89946
+              ],
+              [
+                117.127489,
+                29.86158
+              ],
+              [
+                117.073286,
+                29.831992
+              ],
+              [
+                117.123177,
+                29.798761
+              ],
+              [
+                117.136728,
+                29.775388
+              ],
+              [
+                117.108395,
+                29.75201
+              ],
+              [
+                117.112706,
+                29.711995
+              ],
+              [
+                117.041873,
+                29.680803
+              ],
+              [
+                116.996294,
+                29.683403
+              ],
+              [
+                116.974736,
+                29.657403
+              ],
+              [
+                116.939627,
+                29.648561
+              ],
+              [
+                116.873722,
+                29.609546
+              ],
+              [
+                116.849084,
+                29.57624
+              ],
+              [
+                116.780715,
+                29.569994
+              ],
+              [
+                116.760389,
+                29.599139
+              ],
+              [
+                116.721585,
+                29.564789
+              ],
+              [
+                116.716657,
+                29.590813
+              ],
+              [
+                116.651983,
+                29.637118
+              ],
+              [
+                116.680317,
+                29.681323
+              ],
+              [
+                116.653831,
+                29.694841
+              ],
+              [
+                116.673541,
+                29.709916
+              ],
+              [
+                116.762237,
+                29.802396
+              ],
+              [
+                116.780715,
+                29.792529
+              ],
+              [
+                116.882961,
+                29.893753
+              ],
+              [
+                116.900207,
+                29.949253
+              ],
+              [
+                116.868794,
+                29.980361
+              ],
+              [
+                116.83307,
+                29.95755
+              ],
+              [
+                116.830606,
+                30.004723
+              ],
+              [
+                116.802889,
+                29.99643
+              ],
+              [
+                116.783794,
+                30.030632
+              ],
+              [
+                116.747454,
+                30.057053
+              ],
+              [
+                116.720353,
+                30.053945
+              ],
+              [
+                116.666766,
+                30.076734
+              ],
+              [
+                116.620571,
+                30.073109
+              ],
+              [
+                116.585462,
+                30.045657
+              ],
+              [
+                116.552201,
+                29.909836
+              ],
+              [
+                116.525716,
+                29.897385
+              ],
+              [
+                116.467818,
+                29.896347
+              ],
+              [
+                116.342782,
+                29.835626
+              ],
+              [
+                116.280572,
+                29.788893
+              ],
+              [
+                116.250391,
+                29.785777
+              ],
+              [
+                116.227601,
+                29.816936
+              ],
+              [
+                116.172783,
+                29.828358
+              ],
+              [
+                116.13521,
+                29.819532
+              ],
+              [
+                116.087167,
+                29.795125
+              ],
+              [
+                116.049595,
+                29.761881
+              ],
+              [
+                115.965827,
+                29.724469
+              ],
+              [
+                115.909777,
+                29.723949
+              ],
+              [
+                115.837096,
+                29.748373
+              ],
+              [
+                115.762567,
+                29.793048
+              ],
+              [
+                115.706517,
+                29.837703
+              ],
+              [
+                115.667712,
+                29.850161
+              ],
+              [
+                115.611662,
+                29.841337
+              ],
+              [
+                115.51188,
+                29.840299
+              ],
+              [
+                115.479235,
+                29.811224
+              ],
+              [
+                115.470612,
+                29.739539
+              ],
+              [
+                115.412714,
+                29.688602
+              ],
+              [
+                115.355431,
+                29.649602
+              ],
+              [
+                115.304924,
+                29.637118
+              ],
+              [
+                115.28583,
+                29.618391
+              ],
+              [
+                115.250722,
+                29.660003
+              ],
+              [
+                115.176809,
+                29.654803
+              ],
+              [
+                115.113367,
+                29.684963
+              ],
+              [
+                115.117679,
+                29.655843
+              ],
+              [
+                115.143548,
+                29.645961
+              ],
+              [
+                115.120142,
+                29.597578
+              ],
+              [
+                115.157099,
+                29.584568
+              ],
+              [
+                115.154019,
+                29.510117
+              ],
+              [
+                115.086266,
+                29.525741
+              ],
+              [
+                115.087498,
+                29.560104
+              ],
+              [
+                115.033295,
+                29.546568
+              ],
+              [
+                115.00065,
+                29.572076
+              ],
+              [
+                114.947679,
+                29.542924
+              ],
+              [
+                114.966773,
+                29.522096
+              ],
+              [
+                114.940288,
+                29.493971
+              ],
+              [
+                114.900868,
+                29.505951
+              ],
+              [
+                114.860216,
+                29.476258
+              ],
+              [
+                114.888549,
+                29.436134
+              ],
+              [
+                114.918114,
+                29.454374
+              ],
+              [
+                114.90518,
+                29.473132
+              ],
+              [
+                114.935977,
+                29.486678
+              ],
+              [
+                114.947063,
+                29.465317
+              ],
+              [
+                114.931049,
+                29.422581
+              ],
+              [
+                114.895325,
+                29.397557
+              ],
+              [
+                114.866375,
+                29.404335
+              ],
+              [
+                114.812173,
+                29.383478
+              ],
+              [
+                114.784455,
+                29.386086
+              ],
+              [
+                114.759818,
+                29.363139
+              ],
+              [
+                114.740724,
+                29.386607
+              ],
+              [
+                114.67297,
+                29.395993
+              ],
+              [
+                114.621847,
+                29.379828
+              ],
+              [
+                114.589819,
+                29.352707
+              ],
+              [
+                114.519602,
+                29.325578
+              ],
+              [
+                114.466015,
+                29.324013
+              ],
+              [
+                114.440145,
+                29.341752
+              ],
+              [
+                114.376088,
+                29.322969
+              ],
+              [
+                114.341595,
+                29.327665
+              ],
+              [
+                114.307102,
+                29.365225
+              ],
+              [
+                114.259059,
+                29.343839
+              ],
+              [
+                114.252284,
+                29.23475
+              ],
+              [
+                114.169748,
+                29.216993
+              ],
+              [
+                114.063191,
+                29.204978
+              ],
+              [
+                114.034857,
+                29.152204
+              ],
+              [
+                113.98743,
+                29.126068
+              ],
+              [
+                113.952321,
+                29.092604
+              ],
+              [
+                113.94185,
+                29.047097
+              ],
+              [
+                113.961561,
+                28.999476
+              ],
+              [
+                113.955401,
+                28.978536
+              ],
+              [
+                113.973879,
+                28.937692
+              ],
+              [
+                114.008988,
+                28.955498
+              ],
+              [
+                114.005292,
+                28.917788
+              ],
+              [
+                114.028082,
+                28.891069
+              ],
+              [
+                114.060111,
+                28.902596
+              ],
+              [
+                114.056415,
+                28.872204
+              ],
+              [
+                114.076741,
+                28.834464
+              ],
+              [
+                114.124784,
+                28.843376
+              ],
+              [
+                114.153734,
+                28.829221
+              ],
+              [
+                114.137719,
+                28.779926
+              ],
+              [
+                114.157429,
+                28.761566
+              ],
+              [
+                114.122321,
+                28.623497
+              ],
+              [
+                114.132176,
+                28.607211
+              ],
+              [
+                114.08598,
+                28.558337
+              ],
+              [
+                114.138335,
+                28.533629
+              ],
+              [
+                114.15435,
+                28.507337
+              ],
+              [
+                114.218407,
+                28.48472
+              ],
+              [
+                114.217175,
+                28.466308
+              ],
+              [
+                114.172212,
+                28.432632
+              ],
+              [
+                114.214712,
+                28.403157
+              ],
+              [
+                114.252284,
+                28.395787
+              ],
+              [
+                114.2529,
+                28.319423
+              ],
+              [
+                114.198081,
+                28.29097
+              ],
+              [
+                114.182067,
+                28.249858
+              ],
+              [
+                114.143879,
+                28.246694
+              ],
+              [
+                114.109386,
+                28.205038
+              ],
+              [
+                114.107538,
+                28.182885
+              ],
+              [
+                114.068734,
+                28.171806
+              ],
+              [
+                114.012068,
+                28.174972
+              ],
+              [
+                113.992357,
+                28.161255
+              ],
+              [
+                114.025002,
+                28.080499
+              ],
+              [
+                114.047176,
+                28.057263
+              ],
+              [
+                114.025618,
+                28.031382
+              ],
+              [
+                113.970184,
+                28.041418
+              ],
+              [
+                113.966488,
+                28.017646
+              ],
+              [
+                113.936307,
+                28.018703
+              ],
+              [
+                113.914133,
+                27.991227
+              ],
+              [
+                113.864242,
+                28.004966
+              ],
+              [
+                113.845148,
+                27.971672
+              ],
+              [
+                113.822974,
+                27.982243
+              ],
+              [
+                113.752141,
+                27.93361
+              ],
+              [
+                113.72812,
+                27.874904
+              ],
+              [
+                113.756453,
+                27.860091
+              ],
+              [
+                113.763228,
+                27.799228
+              ],
+              [
+                113.69917,
+                27.740979
+              ],
+              [
+                113.696707,
+                27.71979
+              ],
+              [
+                113.652359,
+                27.663619
+              ],
+              [
+                113.607395,
+                27.625449
+              ],
+              [
+                113.608627,
+                27.585143
+              ],
+              [
+                113.579062,
+                27.545354
+              ],
+              [
+                113.583374,
+                27.524657
+              ],
+              [
+                113.627105,
+                27.49971
+              ],
+              [
+                113.591381,
+                27.467855
+              ],
+              [
+                113.59754,
+                27.428554
+              ],
+              [
+                113.632033,
+                27.40518
+              ],
+              [
+                113.605548,
+                27.38924
+              ],
+              [
+                113.616635,
+                27.345658
+              ],
+              [
+                113.657902,
+                27.347253
+              ],
+              [
+                113.699786,
+                27.331836
+              ],
+              [
+                113.72812,
+                27.350442
+              ],
+              [
+                113.872865,
+                27.384988
+              ],
+              [
+                113.872865,
+                27.346721
+              ],
+              [
+                113.854387,
+                27.30525
+              ],
+              [
+                113.872865,
+                27.289828
+              ],
+              [
+                113.846996,
+                27.222262
+              ],
+              [
+                113.779242,
+                27.137081
+              ],
+              [
+                113.771851,
+                27.096598
+              ],
+              [
+                113.803264,
+                27.099261
+              ],
+              [
+                113.824206,
+                27.036378
+              ],
+              [
+                113.86301,
+                27.018252
+              ],
+              [
+                113.892575,
+                26.964925
+              ],
+              [
+                113.927068,
+                26.948922
+              ],
+              [
+                113.890112,
+                26.895562
+              ],
+              [
+                113.877177,
+                26.859262
+              ],
+              [
+                113.835909,
+                26.806394
+              ],
+              [
+                113.853771,
+                26.769532
+              ],
+              [
+                113.860546,
+                26.664221
+              ],
+              [
+                113.912901,
+                26.613938
+              ],
+              [
+                113.996669,
+                26.615543
+              ],
+              [
+                114.019459,
+                26.587182
+              ],
+              [
+                114.10877,
+                26.56952
+              ],
+              [
+                114.07243,
+                26.480096
+              ],
+              [
+                114.110002,
+                26.482775
+              ],
+              [
+                114.090292,
+                26.455988
+              ],
+              [
+                114.085364,
+                26.406149
+              ],
+              [
+                114.062575,
+                26.406149
+              ],
+              [
+                114.030546,
+                26.376664
+              ],
+              [
+                114.047792,
+                26.337518
+              ],
+              [
+                114.021307,
+                26.288701
+              ],
+              [
+                114.029314,
+                26.266163
+              ],
+              [
+                113.978807,
+                26.237716
+              ],
+              [
+                113.972647,
+                26.20604
+              ],
+              [
+                113.949242,
+                26.192616
+              ],
+              [
+                113.962792,
+                26.150722
+              ],
+              [
+                114.013299,
+                26.184023
+              ],
+              [
+                114.088444,
+                26.168448
+              ],
+              [
+                114.102611,
+                26.187783
+              ],
+              [
+                114.181451,
+                26.214631
+              ],
+              [
+                114.216559,
+                26.203355
+              ],
+              [
+                114.237501,
+                26.152333
+              ],
+              [
+                114.188842,
+                26.121172
+              ],
+              [
+                114.10569,
+                26.097526
+              ],
+              [
+                114.121089,
+                26.085702
+              ],
+              [
+                114.087828,
+                26.06635
+              ],
+              [
+                114.044096,
+                26.076564
+              ],
+              [
+                114.008372,
+                26.015806
+              ],
+              [
+                114.028082,
+                25.98138
+              ],
+              [
+                114.028082,
+                25.893119
+              ],
+              [
+                113.971416,
+                25.836036
+              ],
+              [
+                113.961561,
+                25.77731
+              ],
+              [
+                113.920293,
+                25.741197
+              ],
+              [
+                113.913517,
+                25.701299
+              ],
+              [
+                113.957249,
+                25.611749
+              ],
+              [
+                113.983118,
+                25.599336
+              ],
+              [
+                113.986198,
+                25.529153
+              ],
+              [
+                113.962792,
+                25.528072
+              ],
+              [
+                113.94493,
+                25.441635
+              ],
+              [
+                114.003444,
+                25.442716
+              ],
+              [
+                113.983118,
+                25.415152
+              ],
+              [
+                114.050256,
+                25.36433
+              ],
+              [
+                114.029314,
+                25.328093
+              ],
+              [
+                114.017611,
+                25.273987
+              ],
+              [
+                114.039785,
+                25.250714
+              ],
+              [
+                114.055799,
+                25.277775
+              ],
+              [
+                114.083517,
+                25.275611
+              ],
+              [
+                114.115545,
+                25.302125
+              ],
+              [
+                114.190074,
+                25.316733
+              ],
+              [
+                114.204857,
+                25.29942
+              ],
+              [
+                114.260291,
+                25.291845
+              ],
+              [
+                114.2954,
+                25.299961
+              ],
+              [
+                114.31511,
+                25.33837
+              ],
+              [
+                114.382863,
+                25.317274
+              ],
+              [
+                114.43029,
+                25.343779
+              ],
+              [
+                114.438914,
+                25.376226
+              ],
+              [
+                114.477718,
+                25.37136
+              ],
+              [
+                114.541159,
+                25.416773
+              ],
+              [
+                114.599674,
+                25.385959
+              ],
+              [
+                114.63663,
+                25.324306
+              ],
+              [
+                114.714238,
+                25.315651
+              ],
+              [
+                114.743188,
+                25.274528
+              ],
+              [
+                114.73518,
+                25.225813
+              ],
+              [
+                114.693912,
+                25.213902
+              ],
+              [
+                114.685905,
+                25.173287
+              ],
+              [
+                114.73518,
+                25.155954
+              ],
+              [
+                114.735796,
+                25.121822
+              ],
+              [
+                114.664963,
+                25.10123
+              ],
+              [
+                114.640326,
+                25.074129
+              ],
+              [
+                114.604601,
+                25.083886
+              ],
+              [
+                114.561485,
+                25.077382
+              ],
+              [
+                114.532536,
+                25.022623
+              ],
+              [
+                114.506051,
+                24.999844
+              ],
+              [
+                114.45616,
+                24.99659
+              ],
+              [
+                114.454928,
+                24.977062
+              ],
+              [
+                114.395798,
+                24.951019
+              ],
+              [
+                114.403189,
+                24.877746
+              ],
+              [
+                114.378551,
+                24.861457
+              ],
+              [
+                114.342211,
+                24.807145
+              ],
+              [
+                114.336052,
+                24.749004
+              ],
+              [
+                114.281849,
+                24.724001
+              ],
+              [
+                114.27261,
+                24.700624
+              ],
+              [
+                114.169132,
+                24.689749
+              ],
+              [
+                114.19069,
+                24.656576
+              ],
+              [
+                114.258443,
+                24.641346
+              ],
+              [
+                114.289856,
+                24.619042
+              ],
+              [
+                114.300943,
+                24.578775
+              ],
+              [
+                114.363769,
+                24.582584
+              ],
+              [
+                114.391486,
+                24.563535
+              ],
+              [
+                114.403189,
+                24.497657
+              ],
+              [
+                114.429058,
+                24.48622
+              ],
+              [
+                114.534384,
+                24.559181
+              ],
+              [
+                114.589819,
+                24.537406
+              ],
+              [
+                114.627391,
+                24.576598
+              ],
+              [
+                114.664963,
+                24.583673
+              ],
+              [
+                114.704999,
+                24.525973
+              ],
+              [
+                114.73826,
+                24.565168
+              ],
+              [
+                114.729637,
+                24.608704
+              ],
+              [
+                114.781376,
+                24.613057
+              ],
+              [
+                114.827571,
+                24.588026
+              ],
+              [
+                114.846665,
+                24.602719
+              ],
+              [
+                114.868839,
+                24.562446
+              ],
+              [
+                114.893477,
+                24.582584
+              ],
+              [
+                114.909491,
+                24.661471
+              ],
+              [
+                114.940288,
+                24.650049
+              ],
+              [
+                115.00373,
+                24.679418
+              ],
+              [
+                115.024672,
+                24.669085
+              ],
+              [
+                115.057317,
+                24.703343
+              ],
+              [
+                115.083802,
+                24.699537
+              ],
+              [
+                115.104744,
+                24.667997
+              ],
+              [
+                115.1842,
+                24.711498
+              ],
+              [
+                115.258729,
+                24.728894
+              ],
+              [
+                115.269816,
+                24.749548
+              ],
+              [
+                115.306772,
+                24.758787
+              ],
+              [
+                115.358511,
+                24.735416
+              ],
+              [
+                115.372678,
+                24.774546
+              ],
+              [
+                115.412714,
+                24.79302
+              ],
+              [
+                115.476771,
+                24.762591
+              ],
+              [
+                115.522967,
+                24.702799
+              ],
+              [
+                115.555611,
+                24.683768
+              ],
+              [
+                115.569778,
+                24.622306
+              ],
+              [
+                115.605503,
+                24.62557
+              ],
+              [
+                115.671408,
+                24.604895
+              ],
+              [
+                115.68927,
+                24.545027
+              ],
+              [
+                115.752712,
+                24.546116
+              ],
+              [
+                115.785357,
+                24.567345
+              ],
+              [
+                115.843871,
+                24.562446
+              ],
+              [
+                115.840791,
+                24.584217
+              ],
+              [
+                115.797676,
+                24.628834
+              ],
+              [
+                115.780429,
+                24.663103
+              ],
+              [
+                115.801371,
+                24.705517
+              ],
+              [
+                115.769342,
+                24.708236
+              ],
+              [
+                115.756408,
+                24.749004
+              ],
+              [
+                115.776734,
+                24.774546
+              ],
+              [
+                115.764415,
+                24.791933
+              ],
+              [
+                115.790284,
+                24.856027
+              ],
+              [
+                115.807531,
+                24.862543
+              ],
+              [
+                115.824161,
+                24.909232
+              ],
+              [
+                115.863581,
+                24.891318
+              ],
+              [
+                115.861733,
+                24.863629
+              ],
+              [
+                115.907313,
+                24.879917
+              ],
+              [
+                115.885139,
+                24.898918
+              ],
+              [
+                115.89253,
+                24.936911
+              ],
+              [
+                115.870356,
+                24.959701
+              ],
+              [
+                115.925175,
+                24.960786
+              ],
+              [
+                115.873436,
+                25.019911
+              ],
+              [
+                115.928255,
+                25.050276
+              ],
+              [
+                115.908545,
+                25.084428
+              ],
+              [
+                115.880212,
+                25.092016
+              ],
+              [
+                115.888219,
+                25.128866
+              ],
+              [
+                115.860501,
+                25.165704
+              ],
+              [
+                115.855574,
+                25.20957
+              ],
+              [
+                115.930719,
+                25.236099
+              ],
+              [
+                115.949813,
+                25.292386
+              ],
+              [
+                115.987385,
+                25.290221
+              ],
+              [
+                116.008327,
+                25.319437
+              ],
+              [
+                115.992928,
+                25.374063
+              ],
+              [
+                116.023109,
+                25.435691
+              ],
+              [
+                116.005247,
+                25.490264
+              ],
+              [
+                116.03666,
+                25.514571
+              ],
+              [
+                116.040356,
+                25.548052
+              ],
+              [
+                116.063145,
+                25.56317
+              ],
+              [
+                116.041588,
+                25.62416
+              ],
+              [
+                116.068689,
+                25.646282
+              ],
+              [
+                116.067457,
+                25.703995
+              ],
+              [
+                116.106877,
+                25.701299
+              ],
+              [
+                116.129667,
+                25.758985
+              ],
+              [
+                116.18079,
+                25.778926
+              ],
+              [
+                116.131515,
+                25.824185
+              ],
+              [
+                116.132131,
+                25.860273
+              ],
+              [
+                116.17771,
+                25.894195
+              ],
+              [
+                116.225138,
+                25.908731
+              ],
+              [
+                116.258398,
+                25.902809
+              ],
+              [
+                116.303362,
+                25.924341
+              ],
+              [
+                116.326152,
+                25.956631
+              ],
+              [
+                116.369883,
+                25.963088
+              ],
+              [
+                116.360028,
+                25.991601
+              ],
+              [
+                116.384666,
+                26.030864
+              ],
+              [
+                116.489375,
+                26.113649
+              ],
+              [
+                116.476441,
+                26.172745
+              ],
+              [
+                116.435789,
+                26.159854
+              ],
+              [
+                116.392057,
+                26.171133
+              ],
+              [
+                116.400064,
+                26.202819
+              ],
+              [
+                116.385282,
+                26.238253
+              ],
+              [
+                116.412999,
+                26.297822
+              ],
+              [
+                116.437021,
+                26.308016
+              ],
+              [
+                116.459194,
+                26.345026
+              ],
+              [
+                116.499846,
+                26.361651
+              ],
+              [
+                116.519557,
+                26.410437
+              ],
+              [
+                116.553433,
+                26.400253
+              ],
+              [
+                116.553433,
+                26.365404
+              ],
+              [
+                116.601476,
+                26.372911
+              ],
+              [
+                116.608252,
+                26.429732
+              ],
+              [
+                116.638433,
+                26.477418
+              ],
+              [
+                116.610716,
+                26.476882
+              ],
+              [
+                116.597165,
+                26.512768
+              ],
+              [
+                116.539267,
+                26.559349
+              ],
+              [
+                116.553433,
+                26.575942
+              ],
+              [
+                116.566368,
+                26.650315
+              ],
+              [
+                116.520172,
+                26.684543
+              ],
+              [
+                116.515245,
+                26.720898
+              ],
+              [
+                116.557745,
+                26.773806
+              ],
+              [
+                116.543578,
+                26.803723
+              ],
+              [
+                116.548506,
+                26.84004
+              ],
+              [
+                116.602092,
+                26.888623
+              ],
+              [
+                116.632889,
+                26.933984
+              ],
+              [
+                116.679085,
+                26.978259
+              ],
+              [
+                116.817671,
+                27.018252
+              ],
+              [
+                116.851548,
+                27.009188
+              ],
+              [
+                116.910062,
+                27.034779
+              ],
+              [
+                116.936547,
+                27.019319
+              ],
+              [
+                116.967344,
+                27.061962
+              ],
+              [
+                117.05296,
+                27.100327
+              ],
+              [
+                117.044953,
+                27.146667
+              ],
+              [
+                117.149662,
+                27.241419
+              ],
+              [
+                117.171836,
+                27.29036
+              ],
+              [
+                117.136728,
+                27.303123
+              ],
+              [
+                117.140423,
+                27.322798
+              ],
+              [
+                117.104699,
+                27.330773
+              ],
+              [
+                117.107163,
+                27.393491
+              ],
+              [
+                117.133032,
+                27.42218
+              ],
+              [
+                117.110242,
+                27.458828
+              ],
+              [
+                117.103467,
+                27.533149
+              ],
+              [
+                117.076982,
+                27.566046
+              ],
+              [
+                117.054808,
+                27.5427
+              ],
+              [
+                117.01662,
+                27.563393
+              ],
+              [
+                117.024627,
+                27.592569
+              ],
+              [
+                117.003685,
+                27.625449
+              ],
+              [
+                117.040641,
+                27.669979
+              ],
+              [
+                117.065279,
+                27.665739
+              ],
+              [
+                117.094228,
+                27.627569
+              ],
+              [
+                117.11209,
+                27.645596
+              ],
+              [
+                117.096076,
+                27.667329
+              ],
+              [
+                117.114554,
+                27.692238
+              ],
+              [
+                117.174916,
+                27.677399
+              ],
+              [
+                117.204481,
+                27.683759
+              ],
+              [
+                117.205097,
+                27.714492
+              ],
+              [
+                117.245133,
+                27.71926
+              ],
+              [
+                117.296256,
+                27.764282
+              ],
+              [
+                117.303031,
+                27.833103
+              ],
+              [
+                117.276546,
+                27.847921
+              ],
+              [
+                117.280242,
+                27.871201
+              ],
+              [
+                117.334444,
+                27.8876
+              ],
+              [
+                117.341836,
+                27.855858
+              ],
+              [
+                117.366473,
+                27.88231
+              ],
+              [
+                117.407741,
+                27.893948
+              ],
+              [
+                117.453936,
+                27.939955
+              ],
+              [
+                117.477958,
+                27.930966
+              ],
+              [
+                117.52169,
+                27.982243
+              ],
+              [
+                117.556182,
+                27.966387
+              ],
+              [
+                117.609769,
+                27.863265
+              ],
+              [
+                117.649805,
+                27.851625
+              ],
+              [
+                117.68245,
+                27.823577
+              ],
+              [
+                117.704624,
+                27.834162
+              ],
+              [
+                117.740348,
+                27.800286
+              ],
+              [
+                117.788392,
+                27.855858
+              ],
+              [
+                117.78716,
+                27.896063
+              ],
+              [
+                117.856145,
+                27.94577
+              ],
+              [
+                117.910963,
+                27.949471
+              ],
+              [
+                117.942992,
+                27.974315
+              ],
+              [
+                117.965166,
+                27.962687
+              ],
+              [
+                117.999043,
+                27.991227
+              ],
+              [
+                118.096977,
+                27.970615
+              ],
+              [
+                118.094513,
+                28.003909
+              ],
+              [
+                118.129006,
+                28.017118
+              ],
+              [
+                118.120999,
+                28.041946
+              ],
+              [
+                118.153644,
+                28.062016
+              ],
+              [
+                118.199839,
+                28.049869
+              ],
+              [
+                118.242339,
+                28.075746
+              ],
+              [
+                118.356288,
+                28.091586
+              ],
+              [
+                118.361215,
+                28.155978
+              ],
+              [
+                118.375382,
+                28.186577
+              ],
+              [
+                118.339041,
+                28.193962
+              ],
+              [
+                118.314404,
+                28.221913
+              ],
+              [
+                118.424041,
+                28.291497
+              ],
+              [
+                118.433896,
+                28.288335
+              ],
+              [
+                118.480091,
+                28.327325
+              ],
+              [
+                118.455454,
+                28.384204
+              ],
+              [
+                118.432048,
+                28.402104
+              ],
+              [
+                118.456686,
+                28.424738
+              ],
+              [
+                118.474548,
+                28.478934
+              ],
+              [
+                118.414802,
+                28.497344
+              ],
+              [
+                118.4302,
+                28.515225
+              ],
+              [
+                118.412338,
+                28.55676
+              ],
+              [
+                118.428352,
+                28.617193
+              ],
+              [
+                118.428352,
+                28.617193
+              ],
+              [
+                118.428352,
+                28.681267
+              ],
+              [
+                118.403099,
+                28.702791
+              ],
+              [
+                118.364295,
+                28.813491
+              ],
+              [
+                118.300237,
+                28.826075
+              ],
+              [
+                118.270056,
+                28.918836
+              ],
+              [
+                118.195527,
+                28.904167
+              ],
+              [
+                118.227556,
+                28.942406
+              ],
+              [
+                118.165346,
+                28.986912
+              ],
+              [
+                118.133933,
+                28.983771
+              ],
+              [
+                118.115455,
+                29.009944
+              ],
+              [
+                118.115455,
+                29.009944
+              ],
+              [
+                118.097593,
+                28.998952
+              ],
+              [
+                118.066796,
+                29.053898
+              ],
+              [
+                118.076035,
+                29.074822
+              ],
+              [
+                118.037847,
+                29.102017
+              ],
+              [
+                118.045238,
+                29.149068
+              ],
+              [
+                118.027992,
+                29.167882
+              ],
+              [
+                118.042159,
+                29.210202
+              ],
+              [
+                118.073571,
+                29.216993
+              ],
+              [
+                118.077883,
+                29.290614
+              ],
+              [
+                118.138861,
+                29.283828
+              ],
+              [
+                118.178281,
+                29.297921
+              ],
+              [
+                118.166578,
+                29.314099
+              ],
+              [
+                118.205382,
+                29.343839
+              ],
+              [
+                118.193064,
+                29.395472
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 370000,
+        "name": "灞变笢鐪�",
+        "center": [
+          117.000923,
+          36.675807
+        ],
+        "centroid": [
+          118.187759,
+          36.376092
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 14,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                116.374195,
+                34.640011
+              ],
+              [
+                116.392057,
+                34.710391
+              ],
+              [
+                116.363724,
+                34.715311
+              ],
+              [
+                116.369267,
+                34.749247
+              ],
+              [
+                116.403144,
+                34.756131
+              ],
+              [
+                116.408071,
+                34.850972
+              ],
+              [
+                116.445028,
+                34.895652
+              ],
+              [
+                116.557745,
+                34.908905
+              ],
+              [
+                116.613795,
+                34.922645
+              ],
+              [
+                116.622418,
+                34.939818
+              ],
+              [
+                116.677853,
+                34.939327
+              ],
+              [
+                116.781331,
+                34.916757
+              ],
+              [
+                116.789338,
+                34.975133
+              ],
+              [
+                116.815823,
+                34.965324
+              ],
+              [
+                116.821983,
+                34.929515
+              ],
+              [
+                116.858323,
+                34.928533
+              ],
+              [
+                116.922381,
+                34.894671
+              ],
+              [
+                116.929156,
+                34.843114
+              ],
+              [
+                116.966113,
+                34.844588
+              ],
+              [
+                116.979047,
+                34.815113
+              ],
+              [
+                116.95133,
+                34.81069
+              ],
+              [
+                116.969192,
+                34.771864
+              ],
+              [
+                117.022163,
+                34.759081
+              ],
+              [
+                117.070206,
+                34.713835
+              ],
+              [
+                117.061583,
+                34.675947
+              ],
+              [
+                117.073286,
+                34.639026
+              ],
+              [
+                117.104083,
+                34.648874
+              ],
+              [
+                117.15151,
+                34.559222
+              ],
+              [
+                117.139191,
+                34.526687
+              ],
+              [
+                117.166293,
+                34.434435
+              ],
+              [
+                117.248213,
+                34.451216
+              ],
+              [
+                117.252524,
+                34.48674
+              ],
+              [
+                117.27285,
+                34.499565
+              ],
+              [
+                117.267923,
+                34.532603
+              ],
+              [
+                117.303647,
+                34.542463
+              ],
+              [
+                117.27285,
+                34.556757
+              ],
+              [
+                117.311654,
+                34.561686
+              ],
+              [
+                117.311654,
+                34.561686
+              ],
+              [
+                117.32151,
+                34.566614
+              ],
+              [
+                117.32151,
+                34.566614
+              ],
+              [
+                117.325205,
+                34.573021
+              ],
+              [
+                117.325205,
+                34.573021
+              ],
+              [
+                117.370785,
+                34.584846
+              ],
+              [
+                117.402813,
+                34.569571
+              ],
+              [
+                117.402813,
+                34.550843
+              ],
+              [
+                117.465023,
+                34.484767
+              ],
+              [
+                117.53832,
+                34.467006
+              ],
+              [
+                117.592523,
+                34.462566
+              ],
+              [
+                117.609769,
+                34.490686
+              ],
+              [
+                117.659044,
+                34.501044
+              ],
+              [
+                117.684298,
+                34.547392
+              ],
+              [
+                117.801942,
+                34.518798
+              ],
+              [
+                117.791471,
+                34.583368
+              ],
+              [
+                117.793935,
+                34.651827
+              ],
+              [
+                117.902956,
+                34.644443
+              ],
+              [
+                117.909732,
+                34.670533
+              ],
+              [
+                117.951615,
+                34.678408
+              ],
+              [
+                118.053861,
+                34.650843
+              ],
+              [
+                118.084042,
+                34.655766
+              ],
+              [
+                118.114839,
+                34.614404
+              ],
+              [
+                118.079115,
+                34.569571
+              ],
+              [
+                118.185056,
+                34.543942
+              ],
+              [
+                118.16473,
+                34.50499
+              ],
+              [
+                118.132702,
+                34.483287
+              ],
+              [
+                118.177665,
+                34.45319
+              ],
+              [
+                118.179513,
+                34.379628
+              ],
+              [
+                118.217701,
+                34.379134
+              ],
+              [
+                118.220165,
+                34.405802
+              ],
+              [
+                118.277447,
+                34.404814
+              ],
+              [
+                118.290382,
+                34.424563
+              ],
+              [
+                118.379693,
+                34.415183
+              ],
+              [
+                118.404947,
+                34.427525
+              ],
+              [
+                118.416034,
+                34.473914
+              ],
+              [
+                118.439439,
+                34.507949
+              ],
+              [
+                118.424657,
+                34.595193
+              ],
+              [
+                118.439439,
+                34.626223
+              ],
+              [
+                118.473932,
+                34.623269
+              ],
+              [
+                118.460997,
+                34.656258
+              ],
+              [
+                118.545997,
+                34.705964
+              ],
+              [
+                118.601431,
+                34.714327
+              ],
+              [
+                118.607591,
+                34.694155
+              ],
+              [
+                118.664257,
+                34.693663
+              ],
+              [
+                118.690127,
+                34.678408
+              ],
+              [
+                118.739402,
+                34.693663
+              ],
+              [
+                118.783749,
+                34.723181
+              ],
+              [
+                118.764039,
+                34.740396
+              ],
+              [
+                118.719076,
+                34.745313
+              ],
+              [
+                118.739402,
+                34.792508
+              ],
+              [
+                118.772047,
+                34.794474
+              ],
+              [
+                118.80038,
+                34.843114
+              ],
+              [
+                118.805307,
+                34.87307
+              ],
+              [
+                118.860742,
+                34.944233
+              ],
+              [
+                118.86259,
+                35.025626
+              ],
+              [
+                118.928495,
+                35.051106
+              ],
+              [
+                118.942662,
+                35.040817
+              ],
+              [
+                119.027045,
+                35.055516
+              ],
+              [
+                119.114509,
+                35.055026
+              ],
+              [
+                119.137915,
+                35.096167
+              ],
+              [
+                119.217371,
+                35.106939
+              ],
+              [
+                119.250016,
+                35.124562
+              ],
+              [
+                119.286972,
+                35.115261
+              ],
+              [
+                119.306066,
+                35.076578
+              ],
+              [
+                119.354109,
+                35.080007
+              ],
+              [
+                119.373819,
+                35.078538
+              ],
+              [
+                119.428022,
+                35.121136
+              ],
+              [
+                119.397841,
+                35.137777
+              ],
+              [
+                119.411392,
+                35.231689
+              ],
+              [
+                119.450812,
+                35.285443
+              ],
+              [
+                119.493312,
+                35.318655
+              ],
+              [
+                119.538275,
+                35.296678
+              ],
+              [
+                119.543819,
+                35.347949
+              ],
+              [
+                119.590014,
+                35.37284
+              ],
+              [
+                119.579543,
+                35.406504
+              ],
+              [
+                119.618963,
+                35.459655
+              ],
+              [
+                119.663311,
+                35.562931
+              ],
+              [
+                119.662079,
+                35.589215
+              ],
+              [
+                119.718129,
+                35.615492
+              ],
+              [
+                119.75139,
+                35.617924
+              ],
+              [
+                119.772332,
+                35.578995
+              ],
+              [
+                119.780339,
+                35.584835
+              ],
+              [
+                119.792658,
+                35.615492
+              ],
+              [
+                119.824071,
+                35.646136
+              ],
+              [
+                119.83023,
+                35.620357
+              ],
+              [
+                119.868419,
+                35.60868
+              ],
+              [
+                119.925085,
+                35.637382
+              ],
+              [
+                119.91215,
+                35.660725
+              ],
+              [
+                119.950339,
+                35.729741
+              ],
+              [
+                119.920157,
+                35.739943
+              ],
+              [
+                119.926317,
+                35.759856
+              ],
+              [
+                119.958346,
+                35.760342
+              ],
+              [
+                120.01378,
+                35.714193
+              ],
+              [
+                120.049505,
+                35.786562
+              ],
+              [
+                120.032258,
+                35.812288
+              ],
+              [
+                120.064287,
+                35.873414
+              ],
+              [
+                120.112331,
+                35.885052
+              ],
+              [
+                120.125265,
+                35.906868
+              ],
+              [
+                120.152983,
+                35.907353
+              ],
+              [
+                120.207801,
+                35.947575
+              ],
+              [
+                120.169613,
+                35.888446
+              ],
+              [
+                120.202258,
+                35.89184
+              ],
+              [
+                120.209033,
+                35.917531
+              ],
+              [
+                120.265699,
+                35.966468
+              ],
+              [
+                120.30512,
+                35.971796
+              ],
+              [
+                120.316206,
+                36.002304
+              ],
+              [
+                120.289721,
+                36.017311
+              ],
+              [
+                120.285409,
+                36.01247
+              ],
+              [
+                120.249069,
+                35.992136
+              ],
+              [
+                120.257076,
+                36.025055
+              ],
+              [
+                120.198562,
+                35.995525
+              ],
+              [
+                120.234902,
+                36.030863
+              ],
+              [
+                120.239214,
+                36.062316
+              ],
+              [
+                120.181316,
+                36.066669
+              ],
+              [
+                120.152367,
+                36.095206
+              ],
+              [
+                120.116642,
+                36.102943
+              ],
+              [
+                120.108635,
+                36.127599
+              ],
+              [
+                120.142512,
+                36.143549
+              ],
+              [
+                120.140664,
+                36.173507
+              ],
+              [
+                120.181316,
+                36.203936
+              ],
+              [
+                120.22012,
+                36.209248
+              ],
+              [
+                120.224432,
+                36.19138
+              ],
+              [
+                120.260772,
+                36.198624
+              ],
+              [
+                120.263236,
+                36.182202
+              ],
+              [
+                120.310047,
+                36.185101
+              ],
+              [
+                120.297112,
+                36.225664
+              ],
+              [
+                120.319902,
+                36.232423
+              ],
+              [
+                120.362402,
+                36.196209
+              ],
+              [
+                120.35809,
+                36.174956
+              ],
+              [
+                120.286025,
+                36.047317
+              ],
+              [
+                120.337764,
+                36.055058
+              ],
+              [
+                120.429539,
+                36.056994
+              ],
+              [
+                120.468959,
+                36.087952
+              ],
+              [
+                120.546568,
+                36.091821
+              ],
+              [
+                120.546568,
+                36.107778
+              ],
+              [
+                120.593995,
+                36.100525
+              ],
+              [
+                120.615553,
+                36.120348
+              ],
+              [
+                120.64327,
+                36.114547
+              ],
+              [
+                120.672835,
+                36.130016
+              ],
+              [
+                120.712255,
+                36.126632
+              ],
+              [
+                120.696857,
+                36.15563
+              ],
+              [
+                120.696857,
+                36.203936
+              ],
+              [
+                120.680843,
+                36.238698
+              ],
+              [
+                120.686386,
+                36.279234
+              ],
+              [
+                120.657437,
+                36.276339
+              ],
+              [
+                120.66298,
+                36.331803
+              ],
+              [
+                120.744284,
+                36.327946
+              ],
+              [
+                120.694393,
+                36.390118
+              ],
+              [
+                120.759683,
+                36.46283
+              ],
+              [
+                120.828668,
+                36.46668
+              ],
+              [
+                120.837291,
+                36.459942
+              ],
+              [
+                120.858849,
+                36.424797
+              ],
+              [
+                120.848994,
+                36.403124
+              ],
+              [
+                120.871784,
+                36.36699
+              ],
+              [
+                120.911204,
+                36.412276
+              ],
+              [
+                120.917979,
+                36.417573
+              ],
+              [
+                120.90874,
+                36.450315
+              ],
+              [
+                120.938305,
+                36.447908
+              ],
+              [
+                120.965407,
+                36.466199
+              ],
+              [
+                120.95432,
+                36.507578
+              ],
+              [
+                120.983269,
+                36.546051
+              ],
+              [
+                120.962327,
+                36.562877
+              ],
+              [
+                120.909972,
+                36.568645
+              ],
+              [
+                120.884718,
+                36.601323
+              ],
+              [
+                120.847146,
+                36.618617
+              ],
+              [
+                120.882255,
+                36.627262
+              ],
+              [
+                120.926602,
+                36.611892
+              ],
+              [
+                120.955551,
+                36.575855
+              ],
+              [
+                121.028848,
+                36.572971
+              ],
+              [
+                121.078123,
+                36.607568
+              ],
+              [
+                121.161275,
+                36.651273
+              ],
+              [
+                121.251818,
+                36.671436
+              ],
+              [
+                121.29863,
+                36.702151
+              ],
+              [
+                121.31218,
+                36.702151
+              ],
+              [
+                121.35776,
+                36.713186
+              ],
+              [
+                121.400876,
+                36.701191
+              ],
+              [
+                121.3941,
+                36.738129
+              ],
+              [
+                121.454462,
+                36.752515
+              ],
+              [
+                121.496962,
+                36.795179
+              ],
+              [
+                121.506817,
+                36.803805
+              ],
+              [
+                121.565331,
+                36.830635
+              ],
+              [
+                121.548701,
+                36.807638
+              ],
+              [
+                121.485259,
+                36.786073
+              ],
+              [
+                121.532071,
+                36.73621
+              ],
+              [
+                121.575186,
+                36.740047
+              ],
+              [
+                121.556092,
+                36.764502
+              ],
+              [
+                121.651563,
+                36.723739
+              ],
+              [
+                121.631853,
+                36.80093
+              ],
+              [
+                121.6762,
+                36.819137
+              ],
+              [
+                121.726092,
+                36.826323
+              ],
+              [
+                121.762432,
+                36.84644
+              ],
+              [
+                121.767975,
+                36.874691
+              ],
+              [
+                121.927504,
+                36.932597
+              ],
+              [
+                121.965076,
+                36.938337
+              ],
+              [
+                122.008808,
+                36.96225
+              ],
+              [
+                122.042684,
+                36.871819
+              ],
+              [
+                122.051923,
+                36.904846
+              ],
+              [
+                122.093191,
+                36.913938
+              ],
+              [
+                122.115981,
+                36.94025
+              ],
+              [
+                122.124604,
+                36.944077
+              ],
+              [
+                122.141235,
+                36.938337
+              ],
+              [
+                122.119677,
+                36.891924
+              ],
+              [
+                122.175727,
+                36.894317
+              ],
+              [
+                122.188662,
+                36.866073
+              ],
+              [
+                122.174495,
+                36.842609
+              ],
+              [
+                122.220691,
+                36.848835
+              ],
+              [
+                122.275509,
+                36.83734
+              ],
+              [
+                122.280437,
+                36.835904
+              ],
+              [
+                122.344495,
+                36.828239
+              ],
+              [
+                122.378371,
+                36.844525
+              ],
+              [
+                122.383915,
+                36.865595
+              ],
+              [
+                122.415944,
+                36.85937
+              ],
+              [
+                122.454748,
+                36.879
+              ],
+              [
+                122.452284,
+                36.88618
+              ],
+              [
+                122.434422,
+                36.914416
+              ],
+              [
+                122.483081,
+                36.913938
+              ],
+              [
+                122.48924,
+                36.886659
+              ],
+              [
+                122.532356,
+                36.901496
+              ],
+              [
+                122.55761,
+                36.968467
+              ],
+              [
+                122.544675,
+                37.004797
+              ],
+              [
+                122.583479,
+                37.037289
+              ],
+              [
+                122.575472,
+                37.054485
+              ],
+              [
+                122.494168,
+                37.033945
+              ],
+              [
+                122.467067,
+                37.037289
+              ],
+              [
+                122.478769,
+                37.058784
+              ],
+              [
+                122.484313,
+                37.128956
+              ],
+              [
+                122.533588,
+                37.153286
+              ],
+              [
+                122.581015,
+                37.147562
+              ],
+              [
+                122.573624,
+                37.176178
+              ],
+              [
+                122.624131,
+                37.190959
+              ],
+              [
+                122.592718,
+                37.261485
+              ],
+              [
+                122.567465,
+                37.25958
+              ],
+              [
+                122.573624,
+                37.296247
+              ],
+              [
+                122.611196,
+                37.339558
+              ],
+              [
+                122.607501,
+                37.364296
+              ],
+              [
+                122.650616,
+                37.388551
+              ],
+              [
+                122.6925,
+                37.373809
+              ],
+              [
+                122.714058,
+                37.392355
+              ],
+              [
+                122.701739,
+                37.418501
+              ],
+              [
+                122.67587,
+                37.413273
+              ],
+              [
+                122.641377,
+                37.428482
+              ],
+              [
+                122.553914,
+                37.407093
+              ],
+              [
+                122.4954,
+                37.413748
+              ],
+              [
+                122.487393,
+                37.43466
+              ],
+              [
+                122.41656,
+                37.414699
+              ],
+              [
+                122.337103,
+                37.414223
+              ],
+              [
+                122.281053,
+                37.430858
+              ],
+              [
+                122.287212,
+                37.445114
+              ],
+              [
+                122.25272,
+                37.467917
+              ],
+              [
+                122.194205,
+                37.456041
+              ],
+              [
+                122.166488,
+                37.438937
+              ],
+              [
+                122.131996,
+                37.49926
+              ],
+              [
+                122.163408,
+                37.519199
+              ],
+              [
+                122.150474,
+                37.557163
+              ],
+              [
+                122.08888,
+                37.554316
+              ],
+              [
+                122.075329,
+                37.540556
+              ],
+              [
+                122.017431,
+                37.531065
+              ],
+              [
+                121.997721,
+                37.494512
+              ],
+              [
+                121.923808,
+                37.473142
+              ],
+              [
+                121.772903,
+                37.466492
+              ],
+              [
+                121.66573,
+                37.473617
+              ],
+              [
+                121.635548,
+                37.494037
+              ],
+              [
+                121.575802,
+                37.460317
+              ],
+              [
+                121.571491,
+                37.441313
+              ],
+              [
+                121.477252,
+                37.475992
+              ],
+              [
+                121.460006,
+                37.522522
+              ],
+              [
+                121.400876,
+                37.557638
+              ],
+              [
+                121.395948,
+                37.589891
+              ],
+              [
+                121.435368,
+                37.592737
+              ],
+              [
+                121.391021,
+                37.625449
+              ],
+              [
+                121.349137,
+                37.635403
+              ],
+              [
+                121.358376,
+                37.597479
+              ],
+              [
+                121.304789,
+                37.582778
+              ],
+              [
+                121.217326,
+                37.582778
+              ],
+              [
+                121.17421,
+                37.597479
+              ],
+              [
+                121.148956,
+                37.626397
+              ],
+              [
+                121.161891,
+                37.646302
+              ],
+              [
+                121.142797,
+                37.661464
+              ],
+              [
+                121.160043,
+                37.698882
+              ],
+              [
+                121.136022,
+                37.723501
+              ],
+              [
+                121.037471,
+                37.718767
+              ],
+              [
+                120.994356,
+                37.759468
+              ],
+              [
+                120.943233,
+                37.785486
+              ],
+              [
+                120.940769,
+                37.819533
+              ],
+              [
+                120.874863,
+                37.833241
+              ],
+              [
+                120.845298,
+                37.826623
+              ],
+              [
+                120.839139,
+                37.82426
+              ],
+              [
+                120.733197,
+                37.833714
+              ],
+              [
+                120.656821,
+                37.793054
+              ],
+              [
+                120.634031,
+                37.796364
+              ],
+              [
+                120.590915,
+                37.7642
+              ],
+              [
+                120.517619,
+                37.750005
+              ],
+              [
+                120.454793,
+                37.757576
+              ],
+              [
+                120.367945,
+                37.697935
+              ],
+              [
+                120.227511,
+                37.693673
+              ],
+              [
+                120.22012,
+                37.671886
+              ],
+              [
+                120.269395,
+                37.658622
+              ],
+              [
+                120.272475,
+                37.636824
+              ],
+              [
+                120.215192,
+                37.621183
+              ],
+              [
+                120.208417,
+                37.588469
+              ],
+              [
+                120.246605,
+                37.556689
+              ],
+              [
+                120.222584,
+                37.532963
+              ],
+              [
+                120.144359,
+                37.481691
+              ],
+              [
+                120.086461,
+                37.465067
+              ],
+              [
+                120.064903,
+                37.448915
+              ],
+              [
+                120.010085,
+                37.442263
+              ],
+              [
+                119.949723,
+                37.419927
+              ],
+              [
+                119.926933,
+                37.386649
+              ],
+              [
+                119.843781,
+                37.376662
+              ],
+              [
+                119.837006,
+                37.346695
+              ],
+              [
+                119.883201,
+                37.311004
+              ],
+              [
+                119.89244,
+                37.263866
+              ],
+              [
+                119.865339,
+                37.233854
+              ],
+              [
+                119.83023,
+                37.225754
+              ],
+              [
+                119.808057,
+                37.196203
+              ],
+              [
+                119.740303,
+                37.133727
+              ],
+              [
+                119.687332,
+                37.143746
+              ],
+              [
+                119.678709,
+                37.158056
+              ],
+              [
+                119.576463,
+                37.127524
+              ],
+              [
+                119.489616,
+                37.134681
+              ],
+              [
+                119.428022,
+                37.125616
+              ],
+              [
+                119.361501,
+                37.125616
+              ],
+              [
+                119.327624,
+                37.115595
+              ],
+              [
+                119.301138,
+                37.139452
+              ],
+              [
+                119.298675,
+                37.197156
+              ],
+              [
+                119.2069,
+                37.223371
+              ],
+              [
+                119.190885,
+                37.25958
+              ],
+              [
+                119.204436,
+                37.280058
+              ],
+              [
+                119.136683,
+                37.230995
+              ],
+              [
+                119.12806,
+                37.254816
+              ],
+              [
+                119.091103,
+                37.257674
+              ],
+              [
+                119.084328,
+                37.239572
+              ],
+              [
+                119.054147,
+                37.254816
+              ],
+              [
+                119.03998,
+                37.30434
+              ],
+              [
+                119.001176,
+                37.31862
+              ],
+              [
+                118.942662,
+                37.497361
+              ],
+              [
+                118.939582,
+                37.527268
+              ],
+              [
+                118.988857,
+                37.620709
+              ],
+              [
+                119.023966,
+                37.642037
+              ],
+              [
+                119.153313,
+                37.655305
+              ],
+              [
+                119.236465,
+                37.651988
+              ],
+              [
+                119.262334,
+                37.660517
+              ],
+              [
+                119.280197,
+                37.692726
+              ],
+              [
+                119.309146,
+                37.805349
+              ],
+              [
+                119.291899,
+                37.869627
+              ],
+              [
+                119.24016,
+                37.878131
+              ],
+              [
+                119.212443,
+                37.838913
+              ],
+              [
+                119.16132,
+                37.81906
+              ],
+              [
+                119.12806,
+                37.847892
+              ],
+              [
+                119.110813,
+                37.921577
+              ],
+              [
+                119.001792,
+                37.99613
+              ],
+              [
+                118.974075,
+                38.094162
+              ],
+              [
+                118.908169,
+                38.139362
+              ],
+              [
+                118.811467,
+                38.157717
+              ],
+              [
+                118.703677,
+                38.151129
+              ],
+              [
+                118.626069,
+                38.138421
+              ],
+              [
+                118.607591,
+                38.129006
+              ],
+              [
+                118.597736,
+                38.079088
+              ],
+              [
+                118.552156,
+                38.05553
+              ],
+              [
+                118.534294,
+                38.063541
+              ],
+              [
+                118.517048,
+                38.088509
+              ],
+              [
+                118.504729,
+                38.11394
+              ],
+              [
+                118.44991,
+                38.124299
+              ],
+              [
+                118.431432,
+                38.106406
+              ],
+              [
+                118.404331,
+                38.121003
+              ],
+              [
+                118.331034,
+                38.12524
+              ],
+              [
+                118.217085,
+                38.146893
+              ],
+              [
+                118.177665,
+                38.186417
+              ],
+              [
+                118.112376,
+                38.210403
+              ],
+              [
+                118.045238,
+                38.214165
+              ],
+              [
+                118.018753,
+                38.202409
+              ],
+              [
+                117.896797,
+                38.279495
+              ],
+              [
+                117.895565,
+                38.301572
+              ],
+              [
+                117.848754,
+                38.255062
+              ],
+              [
+                117.808718,
+                38.22827
+              ],
+              [
+                117.789007,
+                38.180772
+              ],
+              [
+                117.766834,
+                38.158658
+              ],
+              [
+                117.771145,
+                38.134655
+              ],
+              [
+                117.746508,
+                38.12524
+              ],
+              [
+                117.704624,
+                38.076262
+              ],
+              [
+                117.586979,
+                38.071551
+              ],
+              [
+                117.557414,
+                38.046105
+              ],
+              [
+                117.557414,
+                38.046105
+              ],
+              [
+                117.524154,
+                37.989527
+              ],
+              [
+                117.513067,
+                37.94329
+              ],
+              [
+                117.481038,
+                37.914967
+              ],
+              [
+                117.438538,
+                37.854035
+              ],
+              [
+                117.400966,
+                37.844584
+              ],
+              [
+                117.320278,
+                37.861596
+              ],
+              [
+                117.271618,
+                37.839858
+              ],
+              [
+                117.185387,
+                37.849783
+              ],
+              [
+                117.150278,
+                37.839385
+              ],
+              [
+                117.074518,
+                37.848837
+              ],
+              [
+                117.027091,
+                37.832296
+              ],
+              [
+                116.919301,
+                37.846002
+              ],
+              [
+                116.837997,
+                37.835132
+              ],
+              [
+                116.804736,
+                37.848837
+              ],
+              [
+                116.753613,
+                37.793054
+              ],
+              [
+                116.753613,
+                37.77035
+              ],
+              [
+                116.724664,
+                37.744327
+              ],
+              [
+                116.679085,
+                37.728708
+              ],
+              [
+                116.66307,
+                37.686096
+              ],
+              [
+                116.604556,
+                37.624975
+              ],
+              [
+                116.575607,
+                37.610754
+              ],
+              [
+                116.4826,
+                37.521573
+              ],
+              [
+                116.448108,
+                37.503059
+              ],
+              [
+                116.433941,
+                37.473142
+              ],
+              [
+                116.38097,
+                37.522522
+              ],
+              [
+                116.379738,
+                37.522047
+              ],
+              [
+                116.38097,
+                37.522522
+              ],
+              [
+                116.379738,
+                37.522047
+              ],
+              [
+                116.36742,
+                37.566177
+              ],
+              [
+                116.336007,
+                37.581355
+              ],
+              [
+                116.295355,
+                37.554316
+              ],
+              [
+                116.278724,
+                37.524895
+              ],
+              [
+                116.290427,
+                37.484065
+              ],
+              [
+                116.27626,
+                37.466967
+              ],
+              [
+                116.240536,
+                37.489764
+              ],
+              [
+                116.240536,
+                37.489764
+              ],
+              [
+                116.224522,
+                37.479791
+              ],
+              [
+                116.243,
+                37.447965
+              ],
+              [
+                116.226369,
+                37.428007
+              ],
+              [
+                116.2855,
+                37.404241
+              ],
+              [
+                116.236224,
+                37.361442
+              ],
+              [
+                116.193109,
+                37.365723
+              ],
+              [
+                116.169087,
+                37.384271
+              ],
+              [
+                116.106261,
+                37.368577
+              ],
+              [
+                116.085935,
+                37.373809
+              ],
+              [
+                116.024341,
+                37.360015
+              ],
+              [
+                115.975682,
+                37.337179
+              ],
+              [
+                115.969523,
+                37.239572
+              ],
+              [
+                115.909777,
+                37.20669
+              ],
+              [
+                115.91224,
+                37.177132
+              ],
+              [
+                115.879596,
+                37.150901
+              ],
+              [
+                115.888219,
+                37.112254
+              ],
+              [
+                115.85619,
+                37.060694
+              ],
+              [
+                115.776734,
+                36.992848
+              ],
+              [
+                115.79706,
+                36.968945
+              ],
+              [
+                115.75764,
+                36.902453
+              ],
+              [
+                115.71206,
+                36.883308
+              ],
+              [
+                115.683727,
+                36.808117
+              ],
+              [
+                115.524815,
+                36.763543
+              ],
+              [
+                115.479851,
+                36.760187
+              ],
+              [
+                115.451518,
+                36.702151
+              ],
+              [
+                115.420105,
+                36.686795
+              ],
+              [
+                115.365902,
+                36.621979
+              ],
+              [
+                115.355431,
+                36.627262
+              ],
+              [
+                115.33141,
+                36.550378
+              ],
+              [
+                115.272895,
+                36.497476
+              ],
+              [
+                115.291374,
+                36.460423
+              ],
+              [
+                115.317243,
+                36.454166
+              ],
+              [
+                115.297533,
+                36.413239
+              ],
+              [
+                115.340033,
+                36.398307
+              ],
+              [
+                115.368982,
+                36.342409
+              ],
+              [
+                115.366518,
+                36.30914
+              ],
+              [
+                115.423185,
+                36.32216
+              ],
+              [
+                115.417025,
+                36.292742
+              ],
+              [
+                115.462605,
+                36.276339
+              ],
+              [
+                115.466916,
+                36.258969
+              ],
+              [
+                115.466916,
+                36.258969
+              ],
+              [
+                115.474923,
+                36.248352
+              ],
+              [
+                115.483547,
+                36.148865
+              ],
+              [
+                115.484163,
+                36.125666
+              ],
+              [
+                115.449054,
+                36.047317
+              ],
+              [
+                115.447822,
+                36.01247
+              ],
+              [
+                115.362822,
+                35.971796
+              ],
+              [
+                115.353583,
+                35.938854
+              ],
+              [
+                115.364054,
+                35.894264
+              ],
+              [
+                115.335105,
+                35.796756
+              ],
+              [
+                115.363438,
+                35.779765
+              ],
+              [
+                115.407786,
+                35.80889
+              ],
+              [
+                115.460141,
+                35.867594
+              ],
+              [
+                115.487858,
+                35.880688
+              ],
+              [
+                115.495249,
+                35.896203
+              ],
+              [
+                115.505104,
+                35.899112
+              ],
+              [
+                115.513112,
+                35.890385
+              ],
+              [
+                115.583945,
+                35.921893
+              ],
+              [
+                115.648618,
+                35.922863
+              ],
+              [
+                115.699125,
+                35.966468
+              ],
+              [
+                115.774886,
+                35.974702
+              ],
+              [
+                115.779813,
+                35.993588
+              ],
+              [
+                115.817386,
+                36.012954
+              ],
+              [
+                115.859886,
+                36.003756
+              ],
+              [
+                115.89869,
+                36.026507
+              ],
+              [
+                115.989849,
+                36.045381
+              ],
+              [
+                116.057602,
+                36.104877
+              ],
+              [
+                116.099486,
+                36.112129
+              ],
+              [
+                116.063145,
+                36.028927
+              ],
+              [
+                116.048979,
+                35.970343
+              ],
+              [
+                115.984921,
+                35.974218
+              ],
+              [
+                115.911624,
+                35.960171
+              ],
+              [
+                115.907929,
+                35.92674
+              ],
+              [
+                115.873436,
+                35.918985
+              ],
+              [
+                115.882675,
+                35.879718
+              ],
+              [
+                115.859886,
+                35.857894
+              ],
+              [
+                115.81677,
+                35.844312
+              ],
+              [
+                115.773654,
+                35.854014
+              ],
+              [
+                115.73485,
+                35.833154
+              ],
+              [
+                115.696046,
+                35.788989
+              ],
+              [
+                115.693582,
+                35.754028
+              ],
+              [
+                115.622749,
+                35.739457
+              ],
+              [
+                115.52851,
+                35.733628
+              ],
+              [
+                115.48601,
+                35.710306
+              ],
+              [
+                115.383148,
+                35.568772
+              ],
+              [
+                115.34496,
+                35.55368
+              ],
+              [
+                115.356047,
+                35.490359
+              ],
+              [
+                115.307388,
+                35.480126
+              ],
+              [
+                115.237171,
+                35.423087
+              ],
+              [
+                115.172497,
+                35.426501
+              ],
+              [
+                115.126302,
+                35.41821
+              ],
+              [
+                115.117679,
+                35.400163
+              ],
+              [
+                115.091809,
+                35.416259
+              ],
+              [
+                115.073947,
+                35.374304
+              ],
+              [
+                115.04315,
+                35.376744
+              ],
+              [
+                114.957534,
+                35.261014
+              ],
+              [
+                114.929201,
+                35.244886
+              ],
+              [
+                114.932281,
+                35.198441
+              ],
+              [
+                114.861448,
+                35.182301
+              ],
+              [
+                114.841738,
+                35.15099
+              ],
+              [
+                114.883006,
+                35.098615
+              ],
+              [
+                114.835578,
+                35.076578
+              ],
+              [
+                114.818948,
+                35.051596
+              ],
+              [
+                114.852209,
+                35.041797
+              ],
+              [
+                114.824492,
+                35.012393
+              ],
+              [
+                114.880542,
+                35.00357
+              ],
+              [
+                114.923658,
+                34.968757
+              ],
+              [
+                114.950759,
+                34.989843
+              ],
+              [
+                115.008041,
+                34.988372
+              ],
+              [
+                115.028983,
+                34.9717
+              ],
+              [
+                115.075179,
+                35.000628
+              ],
+              [
+                115.12815,
+                35.00455
+              ],
+              [
+                115.157099,
+                34.957968
+              ],
+              [
+                115.219309,
+                34.96042
+              ],
+              [
+                115.205142,
+                34.914303
+              ],
+              [
+                115.251953,
+                34.906451
+              ],
+              [
+                115.239019,
+                34.87798
+              ],
+              [
+                115.256265,
+                34.845079
+              ],
+              [
+                115.317243,
+                34.859321
+              ],
+              [
+                115.42688,
+                34.805285
+              ],
+              [
+                115.449054,
+                34.74433
+              ],
+              [
+                115.433655,
+                34.725149
+              ],
+              [
+                115.461373,
+                34.637057
+              ],
+              [
+                115.515575,
+                34.582383
+              ],
+              [
+                115.553148,
+                34.568586
+              ],
+              [
+                115.622749,
+                34.574499
+              ],
+              [
+                115.685575,
+                34.556265
+              ],
+              [
+                115.697278,
+                34.594207
+              ],
+              [
+                115.787821,
+                34.580905
+              ],
+              [
+                115.827241,
+                34.558236
+              ],
+              [
+                115.838328,
+                34.5676
+              ],
+              [
+                115.984305,
+                34.589281
+              ],
+              [
+                115.991081,
+                34.615389
+              ],
+              [
+                116.037276,
+                34.593222
+              ],
+              [
+                116.101334,
+                34.60603
+              ],
+              [
+                116.134594,
+                34.559715
+              ],
+              [
+                116.156768,
+                34.5538
+              ],
+              [
+                116.196804,
+                34.575977
+              ],
+              [
+                116.247927,
+                34.551829
+              ],
+              [
+                116.286116,
+                34.608986
+              ],
+              [
+                116.32492,
+                34.601104
+              ],
+              [
+                116.334159,
+                34.620806
+              ],
+              [
+                116.374195,
+                34.640011
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.729502,
+                37.947065
+              ],
+              [
+                120.721495,
+                37.917328
+              ],
+              [
+                120.76461,
+                37.895134
+              ],
+              [
+                120.76461,
+                37.923937
+              ],
+              [
+                120.729502,
+                37.947065
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.692545,
+                37.983867
+              ],
+              [
+                120.732581,
+                37.961694
+              ],
+              [
+                120.724574,
+                37.987641
+              ],
+              [
+                120.692545,
+                37.983867
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.990044,
+                36.413239
+              ],
+              [
+                120.978341,
+                36.428649
+              ],
+              [
+                120.950624,
+                36.414684
+              ],
+              [
+                120.990044,
+                36.413239
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.750444,
+                38.150188
+              ],
+              [
+                120.7874,
+                38.158658
+              ],
+              [
+                120.742436,
+                38.199116
+              ],
+              [
+                120.750444,
+                38.150188
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.918595,
+                38.345236
+              ],
+              [
+                120.914899,
+                38.373393
+              ],
+              [
+                120.895189,
+                38.36307
+              ],
+              [
+                120.918595,
+                38.345236
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.159142,
+                35.765198
+              ],
+              [
+                120.169613,
+                35.740428
+              ],
+              [
+                120.193019,
+                35.756942
+              ],
+              [
+                120.172077,
+                35.785591
+              ],
+              [
+                120.159142,
+                35.765198
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.62664,
+                37.94565
+              ],
+              [
+                120.631567,
+                37.981037
+              ],
+              [
+                120.602002,
+                37.978678
+              ],
+              [
+                120.62664,
+                37.94565
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.802183,
+                38.284193
+              ],
+              [
+                120.848378,
+                38.305799
+              ],
+              [
+                120.816349,
+                38.318008
+              ],
+              [
+                120.802183,
+                38.284193
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.489571,
+                37.577086
+              ],
+              [
+                121.489571,
+                37.577561
+              ],
+              [
+                121.489571,
+                37.578509
+              ],
+              [
+                121.488955,
+                37.578035
+              ],
+              [
+                121.489571,
+                37.577086
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.485875,
+                37.578509
+              ],
+              [
+                121.487723,
+                37.578035
+              ],
+              [
+                121.487723,
+                37.578509
+              ],
+              [
+                121.485875,
+                37.578509
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.487723,
+                37.578509
+              ],
+              [
+                121.487723,
+                37.577561
+              ],
+              [
+                121.488955,
+                37.578035
+              ],
+              [
+                121.488955,
+                37.578509
+              ],
+              [
+                121.488339,
+                37.578509
+              ],
+              [
+                121.487723,
+                37.578509
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.495249,
+                35.896203
+              ],
+              [
+                115.487858,
+                35.880688
+              ],
+              [
+                115.513112,
+                35.890385
+              ],
+              [
+                115.505104,
+                35.899112
+              ],
+              [
+                115.495249,
+                35.896203
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 410000,
+        "name": "娌冲崡鐪�",
+        "center": [
+          113.665412,
+          34.757975
+        ],
+        "centroid": [
+          113.619717,
+          33.902648
+        ],
+        "childrenNum": 18,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 15,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                112.716747,
+                32.357612
+              ],
+              [
+                112.735841,
+                32.356095
+              ],
+              [
+                112.776493,
+                32.358623
+              ],
+              [
+                112.860877,
+                32.396024
+              ],
+              [
+                112.888594,
+                32.37682
+              ],
+              [
+                112.912,
+                32.390971
+              ],
+              [
+                112.992072,
+                32.378336
+              ],
+              [
+                113.000695,
+                32.41674
+              ],
+              [
+                113.025949,
+                32.425328
+              ],
+              [
+                113.078919,
+                32.394508
+              ],
+              [
+                113.107869,
+                32.398551
+              ],
+              [
+                113.118956,
+                32.375809
+              ],
+              [
+                113.155912,
+                32.380863
+              ],
+              [
+                113.158992,
+                32.410677
+              ],
+              [
+                113.211962,
+                32.431895
+              ],
+              [
+                113.2366,
+                32.407141
+              ],
+              [
+                113.333918,
+                32.336377
+              ],
+              [
+                113.317904,
+                32.327275
+              ],
+              [
+                113.353628,
+                32.294904
+              ],
+              [
+                113.376418,
+                32.298445
+              ],
+              [
+                113.428773,
+                32.270618
+              ],
+              [
+                113.511925,
+                32.316654
+              ],
+              [
+                113.624642,
+                32.36115
+              ],
+              [
+                113.650511,
+                32.412698
+              ],
+              [
+                113.700402,
+                32.420782
+              ],
+              [
+                113.735511,
+                32.410677
+              ],
+              [
+                113.76754,
+                32.370249
+              ],
+              [
+                113.753989,
+                32.328286
+              ],
+              [
+                113.768772,
+                32.30148
+              ],
+              [
+                113.768156,
+                32.284279
+              ],
+              [
+                113.758301,
+                32.27669
+              ],
+              [
+                113.749061,
+                32.272642
+              ],
+              [
+                113.73859,
+                32.255942
+              ],
+              [
+                113.752757,
+                32.215951
+              ],
+              [
+                113.782322,
+                32.184553
+              ],
+              [
+                113.750293,
+                32.11615
+              ],
+              [
+                113.722576,
+                32.12426
+              ],
+              [
+                113.728735,
+                32.083197
+              ],
+              [
+                113.791561,
+                32.036028
+              ],
+              [
+                113.757685,
+                31.98985
+              ],
+              [
+                113.817431,
+                31.964467
+              ],
+              [
+                113.805728,
+                31.929428
+              ],
+              [
+                113.832213,
+                31.918761
+              ],
+              [
+                113.830981,
+                31.87913
+              ],
+              [
+                113.854387,
+                31.843042
+              ],
+              [
+                113.893807,
+                31.847109
+              ],
+              [
+                113.914749,
+                31.877098
+              ],
+              [
+                113.957865,
+                31.852701
+              ],
+              [
+                113.952321,
+                31.793714
+              ],
+              [
+                113.988662,
+                31.749959
+              ],
+              [
+                114.017611,
+                31.770822
+              ],
+              [
+                114.086596,
+                31.782014
+              ],
+              [
+                114.121705,
+                31.809482
+              ],
+              [
+                114.134024,
+                31.843042
+              ],
+              [
+                114.191922,
+                31.852192
+              ],
+              [
+                114.235654,
+                31.833382
+              ],
+              [
+                114.292936,
+                31.752503
+              ],
+              [
+                114.350218,
+                31.755557
+              ],
+              [
+                114.403189,
+                31.746906
+              ],
+              [
+                114.443841,
+                31.728074
+              ],
+              [
+                114.530688,
+                31.742834
+              ],
+              [
+                114.549783,
+                31.766751
+              ],
+              [
+                114.586123,
+                31.762172
+              ],
+              [
+                114.57134,
+                31.660858
+              ],
+              [
+                114.547935,
+                31.623665
+              ],
+              [
+                114.560869,
+                31.560963
+              ],
+              [
+                114.572572,
+                31.553824
+              ],
+              [
+                114.61692,
+                31.585437
+              ],
+              [
+                114.641558,
+                31.582378
+              ],
+              [
+                114.696376,
+                31.525771
+              ],
+              [
+                114.778912,
+                31.520669
+              ],
+              [
+                114.789383,
+                31.480358
+              ],
+              [
+                114.830035,
+                31.45892
+              ],
+              [
+                114.870071,
+                31.479337
+              ],
+              [
+                114.884238,
+                31.469129
+              ],
+              [
+                114.962462,
+                31.494648
+              ],
+              [
+                114.995107,
+                31.471171
+              ],
+              [
+                115.022824,
+                31.527811
+              ],
+              [
+                115.096121,
+                31.508425
+              ],
+              [
+                115.114599,
+                31.530362
+              ],
+              [
+                115.106592,
+                31.567592
+              ],
+              [
+                115.12507,
+                31.599201
+              ],
+              [
+                115.16449,
+                31.604808
+              ],
+              [
+                115.212533,
+                31.555354
+              ],
+              [
+                115.235939,
+                31.555354
+              ],
+              [
+                115.218077,
+                31.515057
+              ],
+              [
+                115.211301,
+                31.442072
+              ],
+              [
+                115.252569,
+                31.421646
+              ],
+              [
+                115.250722,
+                31.392021
+              ],
+              [
+                115.301229,
+                31.383846
+              ],
+              [
+                115.338801,
+                31.40428
+              ],
+              [
+                115.373909,
+                31.405813
+              ],
+              [
+                115.389924,
+                31.450241
+              ],
+              [
+                115.371446,
+                31.495668
+              ],
+              [
+                115.415793,
+                31.525771
+              ],
+              [
+                115.439815,
+                31.588496
+              ],
+              [
+                115.485394,
+                31.608885
+              ],
+              [
+                115.476771,
+                31.643028
+              ],
+              [
+                115.495249,
+                31.673083
+              ],
+              [
+                115.534054,
+                31.698545
+              ],
+              [
+                115.553764,
+                31.69549
+              ],
+              [
+                115.676336,
+                31.778453
+              ],
+              [
+                115.731154,
+                31.76726
+              ],
+              [
+                115.767495,
+                31.78761
+              ],
+              [
+                115.808147,
+                31.770313
+              ],
+              [
+                115.808147,
+                31.770313
+              ],
+              [
+                115.851878,
+                31.786593
+              ],
+              [
+                115.886371,
+                31.776418
+              ],
+              [
+                115.914704,
+                31.814567
+              ],
+              [
+                115.893762,
+                31.832365
+              ],
+              [
+                115.894994,
+                31.8649
+              ],
+              [
+                115.920248,
+                31.920285
+              ],
+              [
+                115.909161,
+                31.94314
+              ],
+              [
+                115.928871,
+                32.003046
+              ],
+              [
+                115.922095,
+                32.049725
+              ],
+              [
+                115.941805,
+                32.166318
+              ],
+              [
+                115.912856,
+                32.227596
+              ],
+              [
+                115.899306,
+                32.390971
+              ],
+              [
+                115.865429,
+                32.458662
+              ],
+              [
+                115.883291,
+                32.487946
+              ],
+              [
+                115.845719,
+                32.501575
+              ],
+              [
+                115.8759,
+                32.542448
+              ],
+              [
+                115.910393,
+                32.567165
+              ],
+              [
+                115.891298,
+                32.576243
+              ],
+              [
+                115.861117,
+                32.537403
+              ],
+              [
+                115.789052,
+                32.468761
+              ],
+              [
+                115.771806,
+                32.505108
+              ],
+              [
+                115.742241,
+                32.476335
+              ],
+              [
+                115.704669,
+                32.495013
+              ],
+              [
+                115.667712,
+                32.409667
+              ],
+              [
+                115.657857,
+                32.428864
+              ],
+              [
+                115.626445,
+                32.40512
+              ],
+              [
+                115.604271,
+                32.425833
+              ],
+              [
+                115.57101,
+                32.419266
+              ],
+              [
+                115.522967,
+                32.441997
+              ],
+              [
+                115.509416,
+                32.466741
+              ],
+              [
+                115.5088,
+                32.468761
+              ],
+              [
+                115.497713,
+                32.492489
+              ],
+              [
+                115.409018,
+                32.549007
+              ],
+              [
+                115.411482,
+                32.575235
+              ],
+              [
+                115.304924,
+                32.553042
+              ],
+              [
+                115.30554,
+                32.583303
+              ],
+              [
+                115.267352,
+                32.578261
+              ],
+              [
+                115.24333,
+                32.593388
+              ],
+              [
+                115.20083,
+                32.591876
+              ],
+              [
+                115.182968,
+                32.666973
+              ],
+              [
+                115.179273,
+                32.726402
+              ],
+              [
+                115.189744,
+                32.770695
+              ],
+              [
+                115.211301,
+                32.785791
+              ],
+              [
+                115.189744,
+                32.812452
+              ],
+              [
+                115.197135,
+                32.856201
+              ],
+              [
+                115.155867,
+                32.864747
+              ],
+              [
+                115.139237,
+                32.897917
+              ],
+              [
+                115.029599,
+                32.906962
+              ],
+              [
+                115.035143,
+                32.932582
+              ],
+              [
+                115.009273,
+                32.940117
+              ],
+              [
+                114.943368,
+                32.935094
+              ],
+              [
+                114.916266,
+                32.971251
+              ],
+              [
+                114.883006,
+                32.990328
+              ],
+              [
+                114.891629,
+                33.020441
+              ],
+              [
+                114.925506,
+                33.016928
+              ],
+              [
+                114.913187,
+                33.083143
+              ],
+              [
+                114.897172,
+                33.086653
+              ],
+              [
+                114.902716,
+                33.129764
+              ],
+              [
+                114.932897,
+                33.153817
+              ],
+              [
+                114.966158,
+                33.147304
+              ],
+              [
+                114.990795,
+                33.102195
+              ],
+              [
+                115.041302,
+                33.086653
+              ],
+              [
+                115.168186,
+                33.088658
+              ],
+              [
+                115.194671,
+                33.120743
+              ],
+              [
+                115.245178,
+                33.135778
+              ],
+              [
+                115.289526,
+                33.131769
+              ],
+              [
+                115.303692,
+                33.149809
+              ],
+              [
+                115.300613,
+                33.204407
+              ],
+              [
+                115.340033,
+                33.260973
+              ],
+              [
+                115.335105,
+                33.297997
+              ],
+              [
+                115.361591,
+                33.298497
+              ],
+              [
+                115.365286,
+                33.336005
+              ],
+              [
+                115.341881,
+                33.370997
+              ],
+              [
+                115.313547,
+                33.376994
+              ],
+              [
+                115.328946,
+                33.403477
+              ],
+              [
+                115.315395,
+                33.431451
+              ],
+              [
+                115.324634,
+                33.457418
+              ],
+              [
+                115.345576,
+                33.449928
+              ],
+              [
+                115.345576,
+                33.502842
+              ],
+              [
+                115.366518,
+                33.5233
+              ],
+              [
+                115.394851,
+                33.506335
+              ],
+              [
+                115.422569,
+                33.557219
+              ],
+              [
+                115.463837,
+                33.567193
+              ],
+              [
+                115.511264,
+                33.55323
+              ],
+              [
+                115.564851,
+                33.576169
+              ],
+              [
+                115.639995,
+                33.585143
+              ],
+              [
+                115.601191,
+                33.658898
+              ],
+              [
+                115.601807,
+                33.718653
+              ],
+              [
+                115.563003,
+                33.772895
+              ],
+              [
+                115.576553,
+                33.787817
+              ],
+              [
+                115.614126,
+                33.775879
+              ],
+              [
+                115.631988,
+                33.869846
+              ],
+              [
+                115.547604,
+                33.874815
+              ],
+              [
+                115.577785,
+                33.950307
+              ],
+              [
+                115.579017,
+                33.974133
+              ],
+              [
+                115.60735,
+                34.030196
+              ],
+              [
+                115.642459,
+                34.03218
+              ],
+              [
+                115.658473,
+                34.061437
+              ],
+              [
+                115.705901,
+                34.059949
+              ],
+              [
+                115.736082,
+                34.076805
+              ],
+              [
+                115.768726,
+                34.061932
+              ],
+              [
+                115.809378,
+                34.062428
+              ],
+              [
+                115.846335,
+                34.028708
+              ],
+              [
+                115.85003,
+                34.004898
+              ],
+              [
+                115.877132,
+                34.002913
+              ],
+              [
+                115.876516,
+                34.028708
+              ],
+              [
+                115.904233,
+                34.009859
+              ],
+              [
+                115.95782,
+                34.007875
+              ],
+              [
+                116.00032,
+                33.965199
+              ],
+              [
+                115.982457,
+                33.917039
+              ],
+              [
+                116.05945,
+                33.860902
+              ],
+              [
+                116.055754,
+                33.804727
+              ],
+              [
+                116.074232,
+                33.781351
+              ],
+              [
+                116.100102,
+                33.782843
+              ],
+              [
+                116.132747,
+                33.751501
+              ],
+              [
+                116.155536,
+                33.709693
+              ],
+              [
+                116.230065,
+                33.735078
+              ],
+              [
+                116.263326,
+                33.730101
+              ],
+              [
+                116.316912,
+                33.771402
+              ],
+              [
+                116.393905,
+                33.782843
+              ],
+              [
+                116.408071,
+                33.805721
+              ],
+              [
+                116.437021,
+                33.801246
+              ],
+              [
+                116.437637,
+                33.846489
+              ],
+              [
+                116.486296,
+                33.869846
+              ],
+              [
+                116.558361,
+                33.881274
+              ],
+              [
+                116.566984,
+                33.9081
+              ],
+              [
+                116.631042,
+                33.887733
+              ],
+              [
+                116.64336,
+                33.896675
+              ],
+              [
+                116.641512,
+                33.978103
+              ],
+              [
+                116.599629,
+                34.014324
+              ],
+              [
+                116.599629,
+                34.014324
+              ],
+              [
+                116.576223,
+                34.068873
+              ],
+              [
+                116.576223,
+                34.068873
+              ],
+              [
+                116.52818,
+                34.122892
+              ],
+              [
+                116.536187,
+                34.151127
+              ],
+              [
+                116.565752,
+                34.16945
+              ],
+              [
+                116.542962,
+                34.203608
+              ],
+              [
+                116.545426,
+                34.241711
+              ],
+              [
+                116.582382,
+                34.266444
+              ],
+              [
+                116.562056,
+                34.285731
+              ],
+              [
+                116.516477,
+                34.296114
+              ],
+              [
+                116.456731,
+                34.268917
+              ],
+              [
+                116.409303,
+                34.273863
+              ],
+              [
+                116.409303,
+                34.273863
+              ],
+              [
+                116.372347,
+                34.26595
+              ],
+              [
+                116.357564,
+                34.319843
+              ],
+              [
+                116.301514,
+                34.342082
+              ],
+              [
+                116.255934,
+                34.376665
+              ],
+              [
+                116.213435,
+                34.382098
+              ],
+              [
+                116.215898,
+                34.403333
+              ],
+              [
+                116.178942,
+                34.430487
+              ],
+              [
+                116.162312,
+                34.459605
+              ],
+              [
+                116.178326,
+                34.496112
+              ],
+              [
+                116.204196,
+                34.508442
+              ],
+              [
+                116.191261,
+                34.535561
+              ],
+              [
+                116.196804,
+                34.575977
+              ],
+              [
+                116.156768,
+                34.5538
+              ],
+              [
+                116.134594,
+                34.559715
+              ],
+              [
+                116.101334,
+                34.60603
+              ],
+              [
+                116.037276,
+                34.593222
+              ],
+              [
+                115.991081,
+                34.615389
+              ],
+              [
+                115.984305,
+                34.589281
+              ],
+              [
+                115.838328,
+                34.5676
+              ],
+              [
+                115.827241,
+                34.558236
+              ],
+              [
+                115.787821,
+                34.580905
+              ],
+              [
+                115.697278,
+                34.594207
+              ],
+              [
+                115.685575,
+                34.556265
+              ],
+              [
+                115.622749,
+                34.574499
+              ],
+              [
+                115.553148,
+                34.568586
+              ],
+              [
+                115.515575,
+                34.582383
+              ],
+              [
+                115.461373,
+                34.637057
+              ],
+              [
+                115.433655,
+                34.725149
+              ],
+              [
+                115.449054,
+                34.74433
+              ],
+              [
+                115.42688,
+                34.805285
+              ],
+              [
+                115.317243,
+                34.859321
+              ],
+              [
+                115.256265,
+                34.845079
+              ],
+              [
+                115.239019,
+                34.87798
+              ],
+              [
+                115.251953,
+                34.906451
+              ],
+              [
+                115.205142,
+                34.914303
+              ],
+              [
+                115.219309,
+                34.96042
+              ],
+              [
+                115.157099,
+                34.957968
+              ],
+              [
+                115.12815,
+                35.00455
+              ],
+              [
+                115.075179,
+                35.000628
+              ],
+              [
+                115.028983,
+                34.9717
+              ],
+              [
+                115.008041,
+                34.988372
+              ],
+              [
+                114.950759,
+                34.989843
+              ],
+              [
+                114.923658,
+                34.968757
+              ],
+              [
+                114.880542,
+                35.00357
+              ],
+              [
+                114.824492,
+                35.012393
+              ],
+              [
+                114.852209,
+                35.041797
+              ],
+              [
+                114.818948,
+                35.051596
+              ],
+              [
+                114.835578,
+                35.076578
+              ],
+              [
+                114.883006,
+                35.098615
+              ],
+              [
+                114.841738,
+                35.15099
+              ],
+              [
+                114.861448,
+                35.182301
+              ],
+              [
+                114.932281,
+                35.198441
+              ],
+              [
+                114.929201,
+                35.244886
+              ],
+              [
+                114.957534,
+                35.261014
+              ],
+              [
+                115.04315,
+                35.376744
+              ],
+              [
+                115.073947,
+                35.374304
+              ],
+              [
+                115.091809,
+                35.416259
+              ],
+              [
+                115.117679,
+                35.400163
+              ],
+              [
+                115.126302,
+                35.41821
+              ],
+              [
+                115.172497,
+                35.426501
+              ],
+              [
+                115.237171,
+                35.423087
+              ],
+              [
+                115.307388,
+                35.480126
+              ],
+              [
+                115.356047,
+                35.490359
+              ],
+              [
+                115.34496,
+                35.55368
+              ],
+              [
+                115.383148,
+                35.568772
+              ],
+              [
+                115.48601,
+                35.710306
+              ],
+              [
+                115.52851,
+                35.733628
+              ],
+              [
+                115.622749,
+                35.739457
+              ],
+              [
+                115.693582,
+                35.754028
+              ],
+              [
+                115.696046,
+                35.788989
+              ],
+              [
+                115.73485,
+                35.833154
+              ],
+              [
+                115.773654,
+                35.854014
+              ],
+              [
+                115.81677,
+                35.844312
+              ],
+              [
+                115.859886,
+                35.857894
+              ],
+              [
+                115.882675,
+                35.879718
+              ],
+              [
+                115.873436,
+                35.918985
+              ],
+              [
+                115.907929,
+                35.92674
+              ],
+              [
+                115.911624,
+                35.960171
+              ],
+              [
+                115.984921,
+                35.974218
+              ],
+              [
+                116.048979,
+                35.970343
+              ],
+              [
+                116.063145,
+                36.028927
+              ],
+              [
+                116.099486,
+                36.112129
+              ],
+              [
+                116.057602,
+                36.104877
+              ],
+              [
+                115.989849,
+                36.045381
+              ],
+              [
+                115.89869,
+                36.026507
+              ],
+              [
+                115.859886,
+                36.003756
+              ],
+              [
+                115.817386,
+                36.012954
+              ],
+              [
+                115.779813,
+                35.993588
+              ],
+              [
+                115.774886,
+                35.974702
+              ],
+              [
+                115.699125,
+                35.966468
+              ],
+              [
+                115.648618,
+                35.922863
+              ],
+              [
+                115.583945,
+                35.921893
+              ],
+              [
+                115.513112,
+                35.890385
+              ],
+              [
+                115.487858,
+                35.880688
+              ],
+              [
+                115.460141,
+                35.867594
+              ],
+              [
+                115.407786,
+                35.80889
+              ],
+              [
+                115.363438,
+                35.779765
+              ],
+              [
+                115.335105,
+                35.796756
+              ],
+              [
+                115.364054,
+                35.894264
+              ],
+              [
+                115.353583,
+                35.938854
+              ],
+              [
+                115.362822,
+                35.971796
+              ],
+              [
+                115.447822,
+                36.01247
+              ],
+              [
+                115.449054,
+                36.047317
+              ],
+              [
+                115.484163,
+                36.125666
+              ],
+              [
+                115.483547,
+                36.148865
+              ],
+              [
+                115.465068,
+                36.170125
+              ],
+              [
+                115.450902,
+                36.152248
+              ],
+              [
+                115.376989,
+                36.128083
+              ],
+              [
+                115.365902,
+                36.099074
+              ],
+              [
+                115.312931,
+                36.088436
+              ],
+              [
+                115.30246,
+                36.127599
+              ],
+              [
+                115.279055,
+                36.13775
+              ],
+              [
+                115.242098,
+                36.19138
+              ],
+              [
+                115.202678,
+                36.208765
+              ],
+              [
+                115.202678,
+                36.208765
+              ],
+              [
+                115.202678,
+                36.209248
+              ],
+              [
+                115.202678,
+                36.209248
+              ],
+              [
+                115.201446,
+                36.210214
+              ],
+              [
+                115.201446,
+                36.210214
+              ],
+              [
+                115.1842,
+                36.193312
+              ],
+              [
+                115.12507,
+                36.209731
+              ],
+              [
+                115.104744,
+                36.172058
+              ],
+              [
+                115.06286,
+                36.178338
+              ],
+              [
+                115.048693,
+                36.161912
+              ],
+              [
+                115.04623,
+                36.112613
+              ],
+              [
+                114.998186,
+                36.069572
+              ],
+              [
+                114.914419,
+                36.052155
+              ],
+              [
+                114.926737,
+                36.089403
+              ],
+              [
+                114.912571,
+                36.140649
+              ],
+              [
+                114.858368,
+                36.144516
+              ],
+              [
+                114.857752,
+                36.127599
+              ],
+              [
+                114.771521,
+                36.124699
+              ],
+              [
+                114.734564,
+                36.15563
+              ],
+              [
+                114.720398,
+                36.140166
+              ],
+              [
+                114.640326,
+                36.137266
+              ],
+              [
+                114.588587,
+                36.118414
+              ],
+              [
+                114.586739,
+                36.141133
+              ],
+              [
+                114.533152,
+                36.171575
+              ],
+              [
+                114.480181,
+                36.177855
+              ],
+              [
+                114.466015,
+                36.197658
+              ],
+              [
+                114.417356,
+                36.205868
+              ],
+              [
+                114.408117,
+                36.224699
+              ],
+              [
+                114.356378,
+                36.230492
+              ],
+              [
+                114.345291,
+                36.255591
+              ],
+              [
+                114.299095,
+                36.245938
+              ],
+              [
+                114.257827,
+                36.263794
+              ],
+              [
+                114.241197,
+                36.251247
+              ],
+              [
+                114.2104,
+                36.272962
+              ],
+              [
+                114.203009,
+                36.245456
+              ],
+              [
+                114.170364,
+                36.245938
+              ],
+              [
+                114.170364,
+                36.245938
+              ],
+              [
+                114.175907,
+                36.264759
+              ],
+              [
+                114.129096,
+                36.280199
+              ],
+              [
+                114.080437,
+                36.269585
+              ],
+              [
+                114.04348,
+                36.303353
+              ],
+              [
+                114.056415,
+                36.329392
+              ],
+              [
+                114.002828,
+                36.334214
+              ],
+              [
+                113.981887,
+                36.31782
+              ],
+              [
+                113.962792,
+                36.353977
+              ],
+              [
+                113.911054,
+                36.314927
+              ],
+              [
+                113.882104,
+                36.353977
+              ],
+              [
+                113.84946,
+                36.347711
+              ],
+              [
+                113.856851,
+                36.329392
+              ],
+              [
+                113.813119,
+                36.332285
+              ],
+              [
+                113.755221,
+                36.366026
+              ],
+              [
+                113.731199,
+                36.363135
+              ],
+              [
+                113.736127,
+                36.324571
+              ],
+              [
+                113.712105,
+                36.303353
+              ],
+              [
+                113.716417,
+                36.262347
+              ],
+              [
+                113.681924,
+                36.216491
+              ],
+              [
+                113.697939,
+                36.181719
+              ],
+              [
+                113.651127,
+                36.174473
+              ],
+              [
+                113.705946,
+                36.148865
+              ],
+              [
+                113.712721,
+                36.129533
+              ],
+              [
+                113.655439,
+                36.125182
+              ],
+              [
+                113.671453,
+                36.115514
+              ],
+              [
+                113.68562,
+                36.056026
+              ],
+              [
+                113.660366,
+                36.034735
+              ],
+              [
+                113.694859,
+                36.026991
+              ],
+              [
+                113.678844,
+                35.985841
+              ],
+              [
+                113.648663,
+                35.994073
+              ],
+              [
+                113.654207,
+                35.931586
+              ],
+              [
+                113.637576,
+                35.870019
+              ],
+              [
+                113.660982,
+                35.837035
+              ],
+              [
+                113.582758,
+                35.818111
+              ],
+              [
+                113.604932,
+                35.797727
+              ],
+              [
+                113.587685,
+                35.736542
+              ],
+              [
+                113.592613,
+                35.691838
+              ],
+              [
+                113.622794,
+                35.674825
+              ],
+              [
+                113.625258,
+                35.632518
+              ],
+              [
+                113.578446,
+                35.633491
+              ],
+              [
+                113.547649,
+                35.656835
+              ],
+              [
+                113.55812,
+                35.621816
+              ],
+              [
+                113.513773,
+                35.57364
+              ],
+              [
+                113.49899,
+                35.532254
+              ],
+              [
+                113.439244,
+                35.507412
+              ],
+              [
+                113.391817,
+                35.506925
+              ],
+              [
+                113.348085,
+                35.468429
+              ],
+              [
+                113.31236,
+                35.481101
+              ],
+              [
+                113.304353,
+                35.426989
+              ],
+              [
+                113.243375,
+                35.449418
+              ],
+              [
+                113.189789,
+                35.44893
+              ],
+              [
+                113.185477,
+                35.409431
+              ],
+              [
+                113.165151,
+                35.412845
+              ],
+              [
+                113.149137,
+                35.350878
+              ],
+              [
+                113.126347,
+                35.332327
+              ],
+              [
+                113.067217,
+                35.353806
+              ],
+              [
+                112.996384,
+                35.362104
+              ],
+              [
+                112.985913,
+                35.33965
+              ],
+              [
+                112.992072,
+                35.29619
+              ],
+              [
+                112.936022,
+                35.284466
+              ],
+              [
+                112.934174,
+                35.262968
+              ],
+              [
+                112.884283,
+                35.243909
+              ],
+              [
+                112.822073,
+                35.258082
+              ],
+              [
+                112.772798,
+                35.207732
+              ],
+              [
+                112.720443,
+                35.206265
+              ],
+              [
+                112.628052,
+                35.263457
+              ],
+              [
+                112.637291,
+                35.225822
+              ],
+              [
+                112.513487,
+                35.218489
+              ],
+              [
+                112.390915,
+                35.239021
+              ],
+              [
+                112.36751,
+                35.219956
+              ],
+              [
+                112.288053,
+                35.219956
+              ],
+              [
+                112.304684,
+                35.251728
+              ],
+              [
+                112.242474,
+                35.234622
+              ],
+              [
+                112.21722,
+                35.253195
+              ],
+              [
+                112.13838,
+                35.271275
+              ],
+              [
+                112.058924,
+                35.280069
+              ],
+              [
+                112.078634,
+                35.219467
+              ],
+              [
+                112.03983,
+                35.194039
+              ],
+              [
+                112.066315,
+                35.153437
+              ],
+              [
+                112.05646,
+                35.098615
+              ],
+              [
+                112.062004,
+                35.056005
+              ],
+              [
+                112.039214,
+                35.045717
+              ],
+              [
+                112.018888,
+                35.068742
+              ],
+              [
+                111.97762,
+                35.067272
+              ],
+              [
+                111.933272,
+                35.083435
+              ],
+              [
+                111.810084,
+                35.062374
+              ],
+              [
+                111.807005,
+                35.032977
+              ],
+              [
+                111.740483,
+                35.00455
+              ],
+              [
+                111.664107,
+                34.984449
+              ],
+              [
+                111.681969,
+                34.9511
+              ],
+              [
+                111.646861,
+                34.938836
+              ],
+              [
+                111.617911,
+                34.894671
+              ],
+              [
+                111.592042,
+                34.881416
+              ],
+              [
+                111.570484,
+                34.843114
+              ],
+              [
+                111.543999,
+                34.853428
+              ],
+              [
+                111.502731,
+                34.829851
+              ],
+              [
+                111.439289,
+                34.838202
+              ],
+              [
+                111.389398,
+                34.815113
+              ],
+              [
+                111.345666,
+                34.831816
+              ],
+              [
+                111.29208,
+                34.806759
+              ],
+              [
+                111.255123,
+                34.819535
+              ],
+              [
+                111.232949,
+                34.789559
+              ],
+              [
+                111.148566,
+                34.807742
+              ],
+              [
+                111.118385,
+                34.756623
+              ],
+              [
+                111.035233,
+                34.740887
+              ],
+              [
+                110.976103,
+                34.706456
+              ],
+              [
+                110.920052,
+                34.730068
+              ],
+              [
+                110.903422,
+                34.669056
+              ],
+              [
+                110.883712,
+                34.64395
+              ],
+              [
+                110.824582,
+                34.615881
+              ],
+              [
+                110.791937,
+                34.649858
+              ],
+              [
+                110.749437,
+                34.65232
+              ],
+              [
+                110.710017,
+                34.605045
+              ],
+              [
+                110.610851,
+                34.607508
+              ],
+              [
+                110.533242,
+                34.583368
+              ],
+              [
+                110.488279,
+                34.610956
+              ],
+              [
+                110.424837,
+                34.588295
+              ],
+              [
+                110.379257,
+                34.600612
+              ],
+              [
+                110.366939,
+                34.566614
+              ],
+              [
+                110.404511,
+                34.557743
+              ],
+              [
+                110.372482,
+                34.544435
+              ],
+              [
+                110.360779,
+                34.516825
+              ],
+              [
+                110.403279,
+                34.433448
+              ],
+              [
+                110.403279,
+                34.433448
+              ],
+              [
+                110.473496,
+                34.393457
+              ],
+              [
+                110.503677,
+                34.33714
+              ],
+              [
+                110.451938,
+                34.292653
+              ],
+              [
+                110.428533,
+                34.288203
+              ],
+              [
+                110.43962,
+                34.243196
+              ],
+              [
+                110.507989,
+                34.217466
+              ],
+              [
+                110.55172,
+                34.213012
+              ],
+              [
+                110.55788,
+                34.193214
+              ],
+              [
+                110.621938,
+                34.177372
+              ],
+              [
+                110.642264,
+                34.161032
+              ],
+              [
+                110.61393,
+                34.113478
+              ],
+              [
+                110.591757,
+                34.101586
+              ],
+              [
+                110.587445,
+                34.023252
+              ],
+              [
+                110.620706,
+                34.035652
+              ],
+              [
+                110.671213,
+                33.966192
+              ],
+              [
+                110.665669,
+                33.937895
+              ],
+              [
+                110.627481,
+                33.925482
+              ],
+              [
+                110.628713,
+                33.910086
+              ],
+              [
+                110.587445,
+                33.887733
+              ],
+              [
+                110.612083,
+                33.852453
+              ],
+              [
+                110.66259,
+                33.85295
+              ],
+              [
+                110.712481,
+                33.833564
+              ],
+              [
+                110.74143,
+                33.798759
+              ],
+              [
+                110.782082,
+                33.796272
+              ],
+              [
+                110.81719,
+                33.751003
+              ],
+              [
+                110.831973,
+                33.713675
+              ],
+              [
+                110.823966,
+                33.685793
+              ],
+              [
+                110.878784,
+                33.634486
+              ],
+              [
+                110.966864,
+                33.609071
+              ],
+              [
+                111.00382,
+                33.578662
+              ],
+              [
+                111.002588,
+                33.535772
+              ],
+              [
+                111.02661,
+                33.478386
+              ],
+              [
+                111.02661,
+                33.467903
+              ],
+              [
+                110.996429,
+                33.435946
+              ],
+              [
+                111.025994,
+                33.375495
+              ],
+              [
+                111.025994,
+                33.330504
+              ],
+              [
+                110.984726,
+                33.255469
+              ],
+              [
+                111.046936,
+                33.202905
+              ],
+              [
+                111.045704,
+                33.169849
+              ],
+              [
+                111.08882,
+                33.181871
+              ],
+              [
+                111.12824,
+                33.15532
+              ],
+              [
+                111.146102,
+                33.12375
+              ],
+              [
+                111.179363,
+                33.115229
+              ],
+              [
+                111.192913,
+                33.071609
+              ],
+              [
+                111.152877,
+                33.039507
+              ],
+              [
+                111.221862,
+                33.042517
+              ],
+              [
+                111.258819,
+                33.006389
+              ],
+              [
+                111.273601,
+                32.971753
+              ],
+              [
+                111.242804,
+                32.930573
+              ],
+              [
+                111.255123,
+                32.883846
+              ],
+              [
+                111.276065,
+                32.903445
+              ],
+              [
+                111.293311,
+                32.859217
+              ],
+              [
+                111.380159,
+                32.829049
+              ],
+              [
+                111.41342,
+                32.757108
+              ],
+              [
+                111.475629,
+                32.760127
+              ],
+              [
+                111.458383,
+                32.726402
+              ],
+              [
+                111.513202,
+                32.674026
+              ],
+              [
+                111.530448,
+                32.628172
+              ],
+              [
+                111.577875,
+                32.593388
+              ],
+              [
+                111.640701,
+                32.634724
+              ],
+              [
+                111.646245,
+                32.605993
+              ],
+              [
+                111.713382,
+                32.606497
+              ],
+              [
+                111.808853,
+                32.536899
+              ],
+              [
+                111.858128,
+                32.528826
+              ],
+              [
+                111.890157,
+                32.503089
+              ],
+              [
+                111.948671,
+                32.51722
+              ],
+              [
+                111.975772,
+                32.471791
+              ],
+              [
+                112.014576,
+                32.450077
+              ],
+              [
+                112.063851,
+                32.474315
+              ],
+              [
+                112.081098,
+                32.425833
+              ],
+              [
+                112.155626,
+                32.377326
+              ],
+              [
+                112.150083,
+                32.411688
+              ],
+              [
+                112.172873,
+                32.385412
+              ],
+              [
+                112.206133,
+                32.392992
+              ],
+              [
+                112.328089,
+                32.321712
+              ],
+              [
+                112.360118,
+                32.3657
+              ],
+              [
+                112.390915,
+                32.37126
+              ],
+              [
+                112.448814,
+                32.34295
+              ],
+              [
+                112.477147,
+                32.380863
+              ],
+              [
+                112.530733,
+                32.37682
+              ],
+              [
+                112.545516,
+                32.404109
+              ],
+              [
+                112.589248,
+                32.381369
+              ],
+              [
+                112.612037,
+                32.386928
+              ],
+              [
+                112.645298,
+                32.368227
+              ],
+              [
+                112.716747,
+                32.357612
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.768156,
+                32.284279
+              ],
+              [
+                113.768772,
+                32.30148
+              ],
+              [
+                113.749061,
+                32.272642
+              ],
+              [
+                113.758301,
+                32.27669
+              ],
+              [
+                113.768156,
+                32.284279
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 420000,
+        "name": "婀栧寳鐪�",
+        "center": [
+          114.298572,
+          30.584355
+        ],
+        "centroid": [
+          112.271301,
+          30.987527
+        ],
+        "childrenNum": 17,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 16,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                111.045704,
+                33.169849
+              ],
+              [
+                111.034001,
+                33.177864
+              ],
+              [
+                111.035849,
+                33.187881
+              ],
+              [
+                111.046936,
+                33.202905
+              ],
+              [
+                110.984726,
+                33.255469
+              ],
+              [
+                110.960704,
+                33.253967
+              ],
+              [
+                110.9219,
+                33.203907
+              ],
+              [
+                110.865234,
+                33.213921
+              ],
+              [
+                110.828893,
+                33.201403
+              ],
+              [
+                110.824582,
+                33.158327
+              ],
+              [
+                110.753133,
+                33.15031
+              ],
+              [
+                110.702626,
+                33.097182
+              ],
+              [
+                110.650887,
+                33.157324
+              ],
+              [
+                110.623785,
+                33.143796
+              ],
+              [
+                110.59422,
+                33.168346
+              ],
+              [
+                110.57759,
+                33.250464
+              ],
+              [
+                110.54125,
+                33.255469
+              ],
+              [
+                110.471032,
+                33.171352
+              ],
+              [
+                110.398352,
+                33.176862
+              ],
+              [
+                110.398352,
+                33.176862
+              ],
+              [
+                110.372482,
+                33.186379
+              ],
+              [
+                110.33799,
+                33.160331
+              ],
+              [
+                110.285635,
+                33.171352
+              ],
+              [
+                110.218497,
+                33.163336
+              ],
+              [
+                110.164911,
+                33.209415
+              ],
+              [
+                110.031252,
+                33.191888
+              ],
+              [
+                109.999223,
+                33.212419
+              ],
+              [
+                109.973353,
+                33.203907
+              ],
+              [
+                109.916687,
+                33.229942
+              ],
+              [
+                109.852013,
+                33.247961
+              ],
+              [
+                109.813209,
+                33.236449
+              ],
+              [
+                109.732521,
+                33.231443
+              ],
+              [
+                109.693101,
+                33.254468
+              ],
+              [
+                109.649985,
+                33.251465
+              ],
+              [
+                109.619804,
+                33.275484
+              ],
+              [
+                109.60687,
+                33.235949
+              ],
+              [
+                109.514479,
+                33.237951
+              ],
+              [
+                109.498464,
+                33.207412
+              ],
+              [
+                109.438718,
+                33.152314
+              ],
+              [
+                109.468283,
+                33.140288
+              ],
+              [
+                109.522486,
+                33.138785
+              ],
+              [
+                109.576073,
+                33.110216
+              ],
+              [
+                109.688174,
+                33.116733
+              ],
+              [
+                109.704188,
+                33.101694
+              ],
+              [
+                109.794731,
+                33.067095
+              ],
+              [
+                109.785492,
+                32.987316
+              ],
+              [
+                109.76455,
+                32.909474
+              ],
+              [
+                109.789804,
+                32.882339
+              ],
+              [
+                109.847702,
+                32.893395
+              ],
+              [
+                109.856941,
+                32.910479
+              ],
+              [
+                109.907448,
+                32.903947
+              ],
+              [
+                109.927158,
+                32.887364
+              ],
+              [
+                109.988752,
+                32.886359
+              ],
+              [
+                110.051578,
+                32.851676
+              ],
+              [
+                110.105164,
+                32.832569
+              ],
+              [
+                110.142121,
+                32.802895
+              ],
+              [
+                110.127338,
+                32.77774
+              ],
+              [
+                110.159367,
+                32.767173
+              ],
+              [
+                110.156903,
+                32.683093
+              ],
+              [
+                110.206179,
+                32.633212
+              ],
+              [
+                110.153824,
+                32.593388
+              ],
+              [
+                110.124259,
+                32.616579
+              ],
+              [
+                110.090382,
+                32.617083
+              ],
+              [
+                110.084223,
+                32.580782
+              ],
+              [
+                110.017701,
+                32.546989
+              ],
+              [
+                109.97089,
+                32.577756
+              ],
+              [
+                109.910528,
+                32.592884
+              ],
+              [
+                109.816905,
+                32.577252
+              ],
+              [
+                109.746072,
+                32.594901
+              ],
+              [
+                109.726978,
+                32.608513
+              ],
+              [
+                109.631507,
+                32.599943
+              ],
+              [
+                109.619804,
+                32.56767
+              ],
+              [
+                109.637051,
+                32.540935
+              ],
+              [
+                109.575457,
+                32.506622
+              ],
+              [
+                109.526797,
+                32.43341
+              ],
+              [
+                109.529877,
+                32.405625
+              ],
+              [
+                109.502776,
+                32.38895
+              ],
+              [
+                109.513247,
+                32.342444
+              ],
+              [
+                109.495385,
+                32.300468
+              ],
+              [
+                109.528645,
+                32.270112
+              ],
+              [
+                109.550203,
+                32.225065
+              ],
+              [
+                109.592703,
+                32.219495
+              ],
+              [
+                109.604406,
+                32.199241
+              ],
+              [
+                109.58716,
+                32.161251
+              ],
+              [
+                109.621652,
+                32.106519
+              ],
+              [
+                109.590855,
+                32.047696
+              ],
+              [
+                109.590855,
+                32.012688
+              ],
+              [
+                109.631507,
+                31.962436
+              ],
+              [
+                109.62042,
+                31.928412
+              ],
+              [
+                109.584696,
+                31.900472
+              ],
+              [
+                109.60379,
+                31.885737
+              ],
+              [
+                109.633971,
+                31.824738
+              ],
+              [
+                109.633971,
+                31.804396
+              ],
+              [
+                109.592087,
+                31.789136
+              ],
+              [
+                109.585928,
+                31.726546
+              ],
+              [
+                109.622268,
+                31.711783
+              ],
+              [
+                109.683246,
+                31.719929
+              ],
+              [
+                109.731289,
+                31.700582
+              ],
+              [
+                109.737449,
+                31.628761
+              ],
+              [
+                109.76455,
+                31.602769
+              ],
+              [
+                109.745456,
+                31.598182
+              ],
+              [
+                109.727594,
+                31.548214
+              ],
+              [
+                109.837847,
+                31.555354
+              ],
+              [
+                109.894513,
+                31.519139
+              ],
+              [
+                109.969658,
+                31.508935
+              ],
+              [
+                109.94502,
+                31.47066
+              ],
+              [
+                109.98752,
+                31.474744
+              ],
+              [
+                110.036795,
+                31.436966
+              ],
+              [
+                110.054042,
+                31.410921
+              ],
+              [
+                110.118715,
+                31.409899
+              ],
+              [
+                110.161831,
+                31.314338
+              ],
+              [
+                110.155671,
+                31.279564
+              ],
+              [
+                110.180309,
+                31.179774
+              ],
+              [
+                110.200019,
+                31.158779
+              ],
+              [
+                110.180309,
+                31.121899
+              ],
+              [
+                110.147048,
+                31.116776
+              ],
+              [
+                110.119947,
+                31.088592
+              ],
+              [
+                110.120563,
+                31.0322
+              ],
+              [
+                110.140273,
+                31.030661
+              ],
+              [
+                110.140889,
+                30.987062
+              ],
+              [
+                110.172918,
+                30.978853
+              ],
+              [
+                110.153824,
+                30.953708
+              ],
+              [
+                110.151976,
+                30.911613
+              ],
+              [
+                110.082375,
+                30.799614
+              ],
+              [
+                110.048498,
+                30.800642
+              ],
+              [
+                110.019549,
+                30.829425
+              ],
+              [
+                110.008462,
+                30.883369
+              ],
+              [
+                109.943788,
+                30.878746
+              ],
+              [
+                109.894513,
+                30.899803
+              ],
+              [
+                109.828608,
+                30.864364
+              ],
+              [
+                109.780564,
+                30.848437
+              ],
+              [
+                109.701724,
+                30.783677
+              ],
+              [
+                109.656761,
+                30.760538
+              ],
+              [
+                109.661072,
+                30.738936
+              ],
+              [
+                109.625348,
+                30.702923
+              ],
+              [
+                109.590855,
+                30.69366
+              ],
+              [
+                109.574225,
+                30.646818
+              ],
+              [
+                109.543428,
+                30.63961
+              ],
+              [
+                109.535421,
+                30.664837
+              ],
+              [
+                109.435638,
+                30.595832
+              ],
+              [
+                109.418392,
+                30.559766
+              ],
+              [
+                109.35495,
+                30.487076
+              ],
+              [
+                109.337088,
+                30.521623
+              ],
+              [
+                109.36111,
+                30.551004
+              ],
+              [
+                109.314298,
+                30.599953
+              ],
+              [
+                109.299516,
+                30.630341
+              ],
+              [
+                109.245313,
+                30.580892
+              ],
+              [
+                109.191726,
+                30.545851
+              ],
+              [
+                109.191726,
+                30.545851
+              ],
+              [
+                109.143683,
+                30.521108
+              ],
+              [
+                109.103647,
+                30.565949
+              ],
+              [
+                109.09256,
+                30.578831
+              ],
+              [
+                109.106111,
+                30.61077
+              ],
+              [
+                109.111654,
+                30.646303
+              ],
+              [
+                109.071002,
+                30.640125
+              ],
+              [
+                109.042669,
+                30.655571
+              ],
+              [
+                109.006329,
+                30.626736
+              ],
+              [
+                108.971836,
+                30.627766
+              ],
+              [
+                108.893612,
+                30.565434
+              ],
+              [
+                108.838793,
+                30.503062
+              ],
+              [
+                108.808612,
+                30.491202
+              ],
+              [
+                108.789518,
+                30.513374
+              ],
+              [
+                108.743939,
+                30.494812
+              ],
+              [
+                108.698975,
+                30.54482
+              ],
+              [
+                108.688504,
+                30.58759
+              ],
+              [
+                108.642925,
+                30.578831
+              ],
+              [
+                108.6497,
+                30.53915
+              ],
+              [
+                108.56778,
+                30.468508
+              ],
+              [
+                108.556077,
+                30.487592
+              ],
+              [
+                108.512961,
+                30.501515
+              ],
+              [
+                108.472925,
+                30.487076
+              ],
+              [
+                108.42673,
+                30.492233
+              ],
+              [
+                108.411331,
+                30.438586
+              ],
+              [
+                108.430425,
+                30.416397
+              ],
+              [
+                108.402092,
+                30.376649
+              ],
+              [
+                108.431041,
+                30.354446
+              ],
+              [
+                108.460606,
+                30.35961
+              ],
+              [
+                108.501258,
+                30.314673
+              ],
+              [
+                108.524048,
+                30.309506
+              ],
+              [
+                108.54499,
+                30.269716
+              ],
+              [
+                108.581947,
+                30.255759
+              ],
+              [
+                108.551766,
+                30.1637
+              ],
+              [
+                108.56778,
+                30.157491
+              ],
+              [
+                108.546222,
+                30.104178
+              ],
+              [
+                108.513577,
+                30.057571
+              ],
+              [
+                108.532055,
+                30.051873
+              ],
+              [
+                108.536367,
+                29.983472
+              ],
+              [
+                108.517889,
+                29.9394
+              ],
+              [
+                108.516041,
+                29.885451
+              ],
+              [
+                108.467998,
+                29.864175
+              ],
+              [
+                108.433505,
+                29.880262
+              ],
+              [
+                108.371295,
+                29.841337
+              ],
+              [
+                108.424266,
+                29.815897
+              ],
+              [
+                108.422418,
+                29.772791
+              ],
+              [
+                108.442744,
+                29.778505
+              ],
+              [
+                108.437201,
+                29.741098
+              ],
+              [
+                108.460606,
+                29.741098
+              ],
+              [
+                108.504338,
+                29.707836
+              ],
+              [
+                108.504954,
+                29.728626
+              ],
+              [
+                108.548686,
+                29.749412
+              ],
+              [
+                108.52528,
+                29.770713
+              ],
+              [
+                108.556077,
+                29.818493
+              ],
+              [
+                108.601041,
+                29.863656
+              ],
+              [
+                108.658939,
+                29.854833
+              ],
+              [
+                108.680497,
+                29.800319
+              ],
+              [
+                108.676801,
+                29.749412
+              ],
+              [
+                108.690968,
+                29.689642
+              ],
+              [
+                108.752562,
+                29.649082
+              ],
+              [
+                108.786438,
+                29.691721
+              ],
+              [
+                108.797525,
+                29.660003
+              ],
+              [
+                108.781511,
+                29.635558
+              ],
+              [
+                108.844337,
+                29.658443
+              ],
+              [
+                108.888068,
+                29.628795
+              ],
+              [
+                108.870206,
+                29.596537
+              ],
+              [
+                108.901003,
+                29.604863
+              ],
+              [
+                108.913322,
+                29.574679
+              ],
+              [
+                108.878213,
+                29.539279
+              ],
+              [
+                108.888684,
+                29.502305
+              ],
+              [
+                108.866511,
+                29.470527
+              ],
+              [
+                108.884373,
+                29.440824
+              ],
+              [
+                108.927488,
+                29.435612
+              ],
+              [
+                108.934264,
+                29.399643
+              ],
+              [
+                108.919481,
+                29.3261
+              ],
+              [
+                108.983539,
+                29.332883
+              ],
+              [
+                108.999553,
+                29.36366
+              ],
+              [
+                109.034662,
+                29.360531
+              ],
+              [
+                109.060531,
+                29.403292
+              ],
+              [
+                109.11227,
+                29.361053
+              ],
+              [
+                109.106727,
+                29.288526
+              ],
+              [
+                109.141835,
+                29.270256
+              ],
+              [
+                109.110422,
+                29.21647
+              ],
+              [
+                109.139372,
+                29.168927
+              ],
+              [
+                109.162777,
+                29.180946
+              ],
+              [
+                109.215748,
+                29.145409
+              ],
+              [
+                109.232378,
+                29.119271
+              ],
+              [
+                109.274262,
+                29.121885
+              ],
+              [
+                109.261328,
+                29.161089
+              ],
+              [
+                109.275494,
+                29.202366
+              ],
+              [
+                109.257632,
+                29.222738
+              ],
+              [
+                109.312451,
+                29.25146
+              ],
+              [
+                109.352487,
+                29.284872
+              ],
+              [
+                109.343863,
+                29.369398
+              ],
+              [
+                109.391291,
+                29.372005
+              ],
+              [
+                109.368501,
+                29.413719
+              ],
+              [
+                109.418392,
+                29.453332
+              ],
+              [
+                109.415928,
+                29.497617
+              ],
+              [
+                109.436254,
+                29.488761
+              ],
+              [
+                109.433791,
+                29.530948
+              ],
+              [
+                109.458428,
+                29.513242
+              ],
+              [
+                109.467051,
+                29.560104
+              ],
+              [
+                109.488609,
+                29.553336
+              ],
+              [
+                109.516326,
+                29.626194
+              ],
+              [
+                109.558826,
+                29.606944
+              ],
+              [
+                109.578536,
+                29.629836
+              ],
+              [
+                109.651833,
+                29.625674
+              ],
+              [
+                109.664768,
+                29.599659
+              ],
+              [
+                109.717739,
+                29.615269
+              ],
+              [
+                109.701108,
+                29.636078
+              ],
+              [
+                109.714659,
+                29.673524
+              ],
+              [
+                109.760238,
+                29.689122
+              ],
+              [
+                109.755311,
+                29.733304
+              ],
+              [
+                109.779333,
+                29.757725
+              ],
+              [
+                109.869876,
+                29.774869
+              ],
+              [
+                109.908064,
+                29.763959
+              ],
+              [
+                109.941325,
+                29.774349
+              ],
+              [
+                110.02386,
+                29.769674
+              ],
+              [
+                110.113788,
+                29.789932
+              ],
+              [
+                110.160599,
+                29.753569
+              ],
+              [
+                110.219729,
+                29.746814
+              ],
+              [
+                110.289946,
+                29.6964
+              ],
+              [
+                110.302265,
+                29.661563
+              ],
+              [
+                110.339221,
+                29.668324
+              ],
+              [
+                110.372482,
+                29.633477
+              ],
+              [
+                110.447011,
+                29.664684
+              ],
+              [
+                110.467337,
+                29.713034
+              ],
+              [
+                110.507373,
+                29.692241
+              ],
+              [
+                110.562807,
+                29.712515
+              ],
+              [
+                110.642879,
+                29.775907
+              ],
+              [
+                110.60038,
+                29.839779
+              ],
+              [
+                110.549873,
+                29.848085
+              ],
+              [
+                110.538786,
+                29.895828
+              ],
+              [
+                110.49875,
+                29.91243
+              ],
+              [
+                110.517228,
+                29.961179
+              ],
+              [
+                110.557264,
+                29.988137
+              ],
+              [
+                110.491358,
+                30.019751
+              ],
+              [
+                110.497518,
+                30.055499
+              ],
+              [
+                110.531394,
+                30.061197
+              ],
+              [
+                110.600996,
+                30.054463
+              ],
+              [
+                110.650887,
+                30.07777
+              ],
+              [
+                110.712481,
+                30.033223
+              ],
+              [
+                110.756212,
+                30.054463
+              ],
+              [
+                110.746973,
+                30.112979
+              ],
+              [
+                110.851067,
+                30.126439
+              ],
+              [
+                110.924364,
+                30.111426
+              ],
+              [
+                110.929907,
+                30.063268
+              ],
+              [
+                111.031537,
+                30.048765
+              ],
+              [
+                111.242188,
+                30.040476
+              ],
+              [
+                111.266826,
+                30.01146
+              ],
+              [
+                111.3315,
+                29.970512
+              ],
+              [
+                111.342587,
+                29.944586
+              ],
+              [
+                111.382623,
+                29.95029
+              ],
+              [
+                111.394325,
+                29.912948
+              ],
+              [
+                111.436825,
+                29.930065
+              ],
+              [
+                111.475629,
+                29.918654
+              ],
+              [
+                111.527368,
+                29.925916
+              ],
+              [
+                111.553854,
+                29.894272
+              ],
+              [
+                111.669034,
+                29.888565
+              ],
+              [
+                111.669034,
+                29.888565
+              ],
+              [
+                111.705375,
+                29.890121
+              ],
+              [
+                111.723853,
+                29.909317
+              ],
+              [
+                111.723853,
+                29.909317
+              ],
+              [
+                111.75773,
+                29.92021
+              ],
+              [
+                111.8107,
+                29.901017
+              ],
+              [
+                111.861207,
+                29.856909
+              ],
+              [
+                111.899396,
+                29.855871
+              ],
+              [
+                111.899396,
+                29.855871
+              ],
+              [
+                111.925881,
+                29.836665
+              ],
+              [
+                111.965917,
+                29.832512
+              ],
+              [
+                111.95483,
+                29.796683
+              ],
+              [
+                112.008417,
+                29.778505
+              ],
+              [
+                112.07617,
+                29.743696
+              ],
+              [
+                112.065699,
+                29.681323
+              ],
+              [
+                112.089721,
+                29.685482
+              ],
+              [
+                112.111279,
+                29.659483
+              ],
+              [
+                112.178416,
+                29.656883
+              ],
+              [
+                112.202438,
+                29.633997
+              ],
+              [
+                112.244322,
+                29.659483
+              ],
+              [
+                112.233851,
+                29.61631
+              ],
+              [
+                112.303452,
+                29.585609
+              ],
+              [
+                112.281278,
+                29.536676
+              ],
+              [
+                112.291133,
+                29.517409
+              ],
+              [
+                112.333017,
+                29.545007
+              ],
+              [
+                112.368741,
+                29.541362
+              ],
+              [
+                112.424792,
+                29.598619
+              ],
+              [
+                112.439574,
+                29.633997
+              ],
+              [
+                112.499321,
+                29.629316
+              ],
+              [
+                112.54182,
+                29.60122
+              ],
+              [
+                112.572001,
+                29.624113
+              ],
+              [
+                112.640371,
+                29.607985
+              ],
+              [
+                112.650842,
+                29.592374
+              ],
+              [
+                112.693957,
+                29.601741
+              ],
+              [
+                112.714283,
+                29.648561
+              ],
+              [
+                112.733378,
+                29.645441
+              ],
+              [
+                112.788812,
+                29.681323
+              ],
+              [
+                112.79374,
+                29.735902
+              ],
+              [
+                112.861493,
+                29.78318
+              ],
+              [
+                112.894138,
+                29.783699
+              ],
+              [
+                112.902145,
+                29.79149
+              ],
+              [
+                112.929246,
+                29.77383
+              ],
+              [
+                112.923703,
+                29.766557
+              ],
+              [
+                112.926782,
+                29.692241
+              ],
+              [
+                112.944645,
+                29.682883
+              ],
+              [
+                112.974826,
+                29.732784
+              ],
+              [
+                113.025949,
+                29.772791
+              ],
+              [
+                113.005007,
+                29.693801
+              ],
+              [
+                112.915696,
+                29.620992
+              ],
+              [
+                112.912,
+                29.606944
+              ],
+              [
+                112.950188,
+                29.473132
+              ],
+              [
+                113.034572,
+                29.523658
+              ],
+              [
+                113.057362,
+                29.522616
+              ],
+              [
+                113.078304,
+                29.438218
+              ],
+              [
+                113.099861,
+                29.459585
+              ],
+              [
+                113.145441,
+                29.449163
+              ],
+              [
+                113.181781,
+                29.485636
+              ],
+              [
+                113.222433,
+                29.543965
+              ],
+              [
+                113.277252,
+                29.594976
+              ],
+              [
+                113.37765,
+                29.703158
+              ],
+              [
+                113.571671,
+                29.849123
+              ],
+              [
+                113.575367,
+                29.809147
+              ],
+              [
+                113.550729,
+                29.768115
+              ],
+              [
+                113.558736,
+                29.727067
+              ],
+              [
+                113.540258,
+                29.699519
+              ],
+              [
+                113.547033,
+                29.675603
+              ],
+              [
+                113.606164,
+                29.666764
+              ],
+              [
+                113.663446,
+                29.684443
+              ],
+              [
+                113.680692,
+                29.64336
+              ],
+              [
+                113.704098,
+                29.634518
+              ],
+              [
+                113.73859,
+                29.579363
+              ],
+              [
+                113.710257,
+                29.555419
+              ],
+              [
+                113.630801,
+                29.523137
+              ],
+              [
+                113.677613,
+                29.513763
+              ],
+              [
+                113.755221,
+                29.446557
+              ],
+              [
+                113.731199,
+                29.393907
+              ],
+              [
+                113.674533,
+                29.388172
+              ],
+              [
+                113.660982,
+                29.333405
+              ],
+              [
+                113.632033,
+                29.316186
+              ],
+              [
+                113.609859,
+                29.25146
+              ],
+              [
+                113.651743,
+                29.225872
+              ],
+              [
+                113.693011,
+                29.226394
+              ],
+              [
+                113.691779,
+                29.19662
+              ],
+              [
+                113.66283,
+                29.16945
+              ],
+              [
+                113.690547,
+                29.114566
+              ],
+              [
+                113.696091,
+                29.077437
+              ],
+              [
+                113.722576,
+                29.104631
+              ],
+              [
+                113.749677,
+                29.060699
+              ],
+              [
+                113.775547,
+                29.095219
+              ],
+              [
+                113.816199,
+                29.105154
+              ],
+              [
+                113.852539,
+                29.058606
+              ],
+              [
+                113.882104,
+                29.065407
+              ],
+              [
+                113.876561,
+                29.038202
+              ],
+              [
+                113.898119,
+                29.029307
+              ],
+              [
+                113.94185,
+                29.047097
+              ],
+              [
+                113.952321,
+                29.092604
+              ],
+              [
+                113.98743,
+                29.126068
+              ],
+              [
+                114.034857,
+                29.152204
+              ],
+              [
+                114.063191,
+                29.204978
+              ],
+              [
+                114.169748,
+                29.216993
+              ],
+              [
+                114.252284,
+                29.23475
+              ],
+              [
+                114.259059,
+                29.343839
+              ],
+              [
+                114.307102,
+                29.365225
+              ],
+              [
+                114.341595,
+                29.327665
+              ],
+              [
+                114.376088,
+                29.322969
+              ],
+              [
+                114.440145,
+                29.341752
+              ],
+              [
+                114.466015,
+                29.324013
+              ],
+              [
+                114.519602,
+                29.325578
+              ],
+              [
+                114.589819,
+                29.352707
+              ],
+              [
+                114.621847,
+                29.379828
+              ],
+              [
+                114.67297,
+                29.395993
+              ],
+              [
+                114.740724,
+                29.386607
+              ],
+              [
+                114.759818,
+                29.363139
+              ],
+              [
+                114.784455,
+                29.386086
+              ],
+              [
+                114.812173,
+                29.383478
+              ],
+              [
+                114.866375,
+                29.404335
+              ],
+              [
+                114.895325,
+                29.397557
+              ],
+              [
+                114.931049,
+                29.422581
+              ],
+              [
+                114.947063,
+                29.465317
+              ],
+              [
+                114.935977,
+                29.486678
+              ],
+              [
+                114.90518,
+                29.473132
+              ],
+              [
+                114.918114,
+                29.454374
+              ],
+              [
+                114.888549,
+                29.436134
+              ],
+              [
+                114.860216,
+                29.476258
+              ],
+              [
+                114.900868,
+                29.505951
+              ],
+              [
+                114.940288,
+                29.493971
+              ],
+              [
+                114.966773,
+                29.522096
+              ],
+              [
+                114.947679,
+                29.542924
+              ],
+              [
+                115.00065,
+                29.572076
+              ],
+              [
+                115.033295,
+                29.546568
+              ],
+              [
+                115.087498,
+                29.560104
+              ],
+              [
+                115.086266,
+                29.525741
+              ],
+              [
+                115.154019,
+                29.510117
+              ],
+              [
+                115.157099,
+                29.584568
+              ],
+              [
+                115.120142,
+                29.597578
+              ],
+              [
+                115.143548,
+                29.645961
+              ],
+              [
+                115.117679,
+                29.655843
+              ],
+              [
+                115.113367,
+                29.684963
+              ],
+              [
+                115.176809,
+                29.654803
+              ],
+              [
+                115.250722,
+                29.660003
+              ],
+              [
+                115.28583,
+                29.618391
+              ],
+              [
+                115.304924,
+                29.637118
+              ],
+              [
+                115.355431,
+                29.649602
+              ],
+              [
+                115.412714,
+                29.688602
+              ],
+              [
+                115.470612,
+                29.739539
+              ],
+              [
+                115.479235,
+                29.811224
+              ],
+              [
+                115.51188,
+                29.840299
+              ],
+              [
+                115.611662,
+                29.841337
+              ],
+              [
+                115.667712,
+                29.850161
+              ],
+              [
+                115.706517,
+                29.837703
+              ],
+              [
+                115.762567,
+                29.793048
+              ],
+              [
+                115.837096,
+                29.748373
+              ],
+              [
+                115.909777,
+                29.723949
+              ],
+              [
+                115.965827,
+                29.724469
+              ],
+              [
+                116.049595,
+                29.761881
+              ],
+              [
+                116.087167,
+                29.795125
+              ],
+              [
+                116.13521,
+                29.819532
+              ],
+              [
+                116.128435,
+                29.897904
+              ],
+              [
+                116.073616,
+                29.969993
+              ],
+              [
+                116.091479,
+                30.036331
+              ],
+              [
+                116.078544,
+                30.062233
+              ],
+              [
+                116.088399,
+                30.110391
+              ],
+              [
+                116.055754,
+                30.180774
+              ],
+              [
+                116.065609,
+                30.204569
+              ],
+              [
+                115.997856,
+                30.252657
+              ],
+              [
+                115.985537,
+                30.290905
+              ],
+              [
+                115.903001,
+                30.31364
+              ],
+              [
+                115.91532,
+                30.337919
+              ],
+              [
+                115.885139,
+                30.379747
+              ],
+              [
+                115.921479,
+                30.416397
+              ],
+              [
+                115.894994,
+                30.452517
+              ],
+              [
+                115.910393,
+                30.519046
+              ],
+              [
+                115.887603,
+                30.542758
+              ],
+              [
+                115.876516,
+                30.582438
+              ],
+              [
+                115.848799,
+                30.602014
+              ],
+              [
+                115.819234,
+                30.597893
+              ],
+              [
+                115.81369,
+                30.637035
+              ],
+              [
+                115.762567,
+                30.685426
+              ],
+              [
+                115.782893,
+                30.751795
+              ],
+              [
+                115.851262,
+                30.756938
+              ],
+              [
+                115.863581,
+                30.815549
+              ],
+              [
+                115.848799,
+                30.828397
+              ],
+              [
+                115.865429,
+                30.864364
+              ],
+              [
+                115.932566,
+                30.889532
+              ],
+              [
+                115.976298,
+                30.931636
+              ],
+              [
+                116.03974,
+                30.957813
+              ],
+              [
+                116.071769,
+                30.956787
+              ],
+              [
+                116.058834,
+                31.012711
+              ],
+              [
+                116.015102,
+                31.011685
+              ],
+              [
+                116.006479,
+                31.034764
+              ],
+              [
+                115.938726,
+                31.04707
+              ],
+              [
+                115.939958,
+                31.071678
+              ],
+              [
+                115.887603,
+                31.10909
+              ],
+              [
+                115.867277,
+                31.147512
+              ],
+              [
+                115.837712,
+                31.127022
+              ],
+              [
+                115.797676,
+                31.128047
+              ],
+              [
+                115.778582,
+                31.112164
+              ],
+              [
+                115.700973,
+                31.201276
+              ],
+              [
+                115.655394,
+                31.211002
+              ],
+              [
+                115.603655,
+                31.17363
+              ],
+              [
+                115.585793,
+                31.143926
+              ],
+              [
+                115.540213,
+                31.194621
+              ],
+              [
+                115.539597,
+                31.231985
+              ],
+              [
+                115.507568,
+                31.267799
+              ],
+              [
+                115.473076,
+                31.265242
+              ],
+              [
+                115.443511,
+                31.344498
+              ],
+              [
+                115.40717,
+                31.337854
+              ],
+              [
+                115.372062,
+                31.349098
+              ],
+              [
+                115.393004,
+                31.389977
+              ],
+              [
+                115.373909,
+                31.405813
+              ],
+              [
+                115.338801,
+                31.40428
+              ],
+              [
+                115.301229,
+                31.383846
+              ],
+              [
+                115.250722,
+                31.392021
+              ],
+              [
+                115.252569,
+                31.421646
+              ],
+              [
+                115.211301,
+                31.442072
+              ],
+              [
+                115.218077,
+                31.515057
+              ],
+              [
+                115.235939,
+                31.555354
+              ],
+              [
+                115.212533,
+                31.555354
+              ],
+              [
+                115.16449,
+                31.604808
+              ],
+              [
+                115.12507,
+                31.599201
+              ],
+              [
+                115.106592,
+                31.567592
+              ],
+              [
+                115.114599,
+                31.530362
+              ],
+              [
+                115.096121,
+                31.508425
+              ],
+              [
+                115.022824,
+                31.527811
+              ],
+              [
+                114.995107,
+                31.471171
+              ],
+              [
+                114.962462,
+                31.494648
+              ],
+              [
+                114.884238,
+                31.469129
+              ],
+              [
+                114.870071,
+                31.479337
+              ],
+              [
+                114.830035,
+                31.45892
+              ],
+              [
+                114.789383,
+                31.480358
+              ],
+              [
+                114.778912,
+                31.520669
+              ],
+              [
+                114.696376,
+                31.525771
+              ],
+              [
+                114.641558,
+                31.582378
+              ],
+              [
+                114.61692,
+                31.585437
+              ],
+              [
+                114.572572,
+                31.553824
+              ],
+              [
+                114.560869,
+                31.560963
+              ],
+              [
+                114.547935,
+                31.623665
+              ],
+              [
+                114.57134,
+                31.660858
+              ],
+              [
+                114.586123,
+                31.762172
+              ],
+              [
+                114.549783,
+                31.766751
+              ],
+              [
+                114.530688,
+                31.742834
+              ],
+              [
+                114.443841,
+                31.728074
+              ],
+              [
+                114.403189,
+                31.746906
+              ],
+              [
+                114.350218,
+                31.755557
+              ],
+              [
+                114.292936,
+                31.752503
+              ],
+              [
+                114.235654,
+                31.833382
+              ],
+              [
+                114.191922,
+                31.852192
+              ],
+              [
+                114.134024,
+                31.843042
+              ],
+              [
+                114.121705,
+                31.809482
+              ],
+              [
+                114.086596,
+                31.782014
+              ],
+              [
+                114.017611,
+                31.770822
+              ],
+              [
+                113.988662,
+                31.749959
+              ],
+              [
+                113.952321,
+                31.793714
+              ],
+              [
+                113.957865,
+                31.852701
+              ],
+              [
+                113.914749,
+                31.877098
+              ],
+              [
+                113.893807,
+                31.847109
+              ],
+              [
+                113.854387,
+                31.843042
+              ],
+              [
+                113.830981,
+                31.87913
+              ],
+              [
+                113.832213,
+                31.918761
+              ],
+              [
+                113.805728,
+                31.929428
+              ],
+              [
+                113.817431,
+                31.964467
+              ],
+              [
+                113.757685,
+                31.98985
+              ],
+              [
+                113.791561,
+                32.036028
+              ],
+              [
+                113.728735,
+                32.083197
+              ],
+              [
+                113.722576,
+                32.12426
+              ],
+              [
+                113.750293,
+                32.11615
+              ],
+              [
+                113.782322,
+                32.184553
+              ],
+              [
+                113.752757,
+                32.215951
+              ],
+              [
+                113.73859,
+                32.255942
+              ],
+              [
+                113.749061,
+                32.272642
+              ],
+              [
+                113.768772,
+                32.30148
+              ],
+              [
+                113.753989,
+                32.328286
+              ],
+              [
+                113.76754,
+                32.370249
+              ],
+              [
+                113.735511,
+                32.410677
+              ],
+              [
+                113.700402,
+                32.420782
+              ],
+              [
+                113.650511,
+                32.412698
+              ],
+              [
+                113.624642,
+                32.36115
+              ],
+              [
+                113.511925,
+                32.316654
+              ],
+              [
+                113.428773,
+                32.270618
+              ],
+              [
+                113.376418,
+                32.298445
+              ],
+              [
+                113.353628,
+                32.294904
+              ],
+              [
+                113.317904,
+                32.327275
+              ],
+              [
+                113.333918,
+                32.336377
+              ],
+              [
+                113.2366,
+                32.407141
+              ],
+              [
+                113.211962,
+                32.431895
+              ],
+              [
+                113.158992,
+                32.410677
+              ],
+              [
+                113.155912,
+                32.380863
+              ],
+              [
+                113.118956,
+                32.375809
+              ],
+              [
+                113.107869,
+                32.398551
+              ],
+              [
+                113.078919,
+                32.394508
+              ],
+              [
+                113.025949,
+                32.425328
+              ],
+              [
+                113.000695,
+                32.41674
+              ],
+              [
+                112.992072,
+                32.378336
+              ],
+              [
+                112.912,
+                32.390971
+              ],
+              [
+                112.888594,
+                32.37682
+              ],
+              [
+                112.860877,
+                32.396024
+              ],
+              [
+                112.776493,
+                32.358623
+              ],
+              [
+                112.735841,
+                32.356095
+              ],
+              [
+                112.733993,
+                32.356601
+              ],
+              [
+                112.724138,
+                32.358623
+              ],
+              [
+                112.716747,
+                32.357612
+              ],
+              [
+                112.645298,
+                32.368227
+              ],
+              [
+                112.612037,
+                32.386928
+              ],
+              [
+                112.589248,
+                32.381369
+              ],
+              [
+                112.545516,
+                32.404109
+              ],
+              [
+                112.530733,
+                32.37682
+              ],
+              [
+                112.477147,
+                32.380863
+              ],
+              [
+                112.448814,
+                32.34295
+              ],
+              [
+                112.390915,
+                32.37126
+              ],
+              [
+                112.360118,
+                32.3657
+              ],
+              [
+                112.328089,
+                32.321712
+              ],
+              [
+                112.206133,
+                32.392992
+              ],
+              [
+                112.172873,
+                32.385412
+              ],
+              [
+                112.150083,
+                32.411688
+              ],
+              [
+                112.155626,
+                32.377326
+              ],
+              [
+                112.081098,
+                32.425833
+              ],
+              [
+                112.063851,
+                32.474315
+              ],
+              [
+                112.014576,
+                32.450077
+              ],
+              [
+                111.975772,
+                32.471791
+              ],
+              [
+                111.948671,
+                32.51722
+              ],
+              [
+                111.890157,
+                32.503089
+              ],
+              [
+                111.858128,
+                32.528826
+              ],
+              [
+                111.808853,
+                32.536899
+              ],
+              [
+                111.713382,
+                32.606497
+              ],
+              [
+                111.646245,
+                32.605993
+              ],
+              [
+                111.640701,
+                32.634724
+              ],
+              [
+                111.577875,
+                32.593388
+              ],
+              [
+                111.530448,
+                32.628172
+              ],
+              [
+                111.513202,
+                32.674026
+              ],
+              [
+                111.458383,
+                32.726402
+              ],
+              [
+                111.475629,
+                32.760127
+              ],
+              [
+                111.41342,
+                32.757108
+              ],
+              [
+                111.380159,
+                32.829049
+              ],
+              [
+                111.293311,
+                32.859217
+              ],
+              [
+                111.276065,
+                32.903445
+              ],
+              [
+                111.255123,
+                32.883846
+              ],
+              [
+                111.242804,
+                32.930573
+              ],
+              [
+                111.273601,
+                32.971753
+              ],
+              [
+                111.258819,
+                33.006389
+              ],
+              [
+                111.221862,
+                33.042517
+              ],
+              [
+                111.152877,
+                33.039507
+              ],
+              [
+                111.192913,
+                33.071609
+              ],
+              [
+                111.179363,
+                33.115229
+              ],
+              [
+                111.146102,
+                33.12375
+              ],
+              [
+                111.12824,
+                33.15532
+              ],
+              [
+                111.08882,
+                33.181871
+              ],
+              [
+                111.045704,
+                33.169849
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.106111,
+                30.570587
+              ],
+              [
+                109.101183,
+                30.579346
+              ],
+              [
+                109.09872,
+                30.579346
+              ],
+              [
+                109.106111,
+                30.570587
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.046936,
+                33.202905
+              ],
+              [
+                111.035849,
+                33.187881
+              ],
+              [
+                111.034001,
+                33.177864
+              ],
+              [
+                111.045704,
+                33.169849
+              ],
+              [
+                111.046936,
+                33.202905
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.716747,
+                32.357612
+              ],
+              [
+                112.735841,
+                32.356095
+              ],
+              [
+                112.733993,
+                32.356601
+              ],
+              [
+                112.724138,
+                32.358623
+              ],
+              [
+                112.716747,
+                32.357612
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.902145,
+                29.79149
+              ],
+              [
+                112.894138,
+                29.783699
+              ],
+              [
+                112.923703,
+                29.766557
+              ],
+              [
+                112.929246,
+                29.77383
+              ],
+              [
+                112.902145,
+                29.79149
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 430000,
+        "name": "婀栧崡鐪�",
+        "center": [
+          112.982279,
+          28.19409
+        ],
+        "centroid": [
+          111.711649,
+          27.629216
+        ],
+        "childrenNum": 14,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 17,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                112.024431,
+                24.740308
+              ],
+              [
+                112.03367,
+                24.771286
+              ],
+              [
+                112.124214,
+                24.841364
+              ],
+              [
+                112.149467,
+                24.837019
+              ],
+              [
+                112.167329,
+                24.859828
+              ],
+              [
+                112.175337,
+                24.927685
+              ],
+              [
+                112.119902,
+                24.963499
+              ],
+              [
+                112.12175,
+                24.989538
+              ],
+              [
+                112.155626,
+                25.026419
+              ],
+              [
+                112.151931,
+                25.055698
+              ],
+              [
+                112.177184,
+                25.106649
+              ],
+              [
+                112.187039,
+                25.182494
+              ],
+              [
+                112.246785,
+                25.185202
+              ],
+              [
+                112.256025,
+                25.159204
+              ],
+              [
+                112.302836,
+                25.157037
+              ],
+              [
+                112.315771,
+                25.175453
+              ],
+              [
+                112.365046,
+                25.191701
+              ],
+              [
+                112.414937,
+                25.14241
+              ],
+              [
+                112.44327,
+                25.185744
+              ],
+              [
+                112.458053,
+                25.152162
+              ],
+              [
+                112.562762,
+                25.124531
+              ],
+              [
+                112.628052,
+                25.140785
+              ],
+              [
+                112.660081,
+                25.132658
+              ],
+              [
+                112.712436,
+                25.083344
+              ],
+              [
+                112.714899,
+                25.025876
+              ],
+              [
+                112.742001,
+                24.99876
+              ],
+              [
+                112.743233,
+                24.959701
+              ],
+              [
+                112.778341,
+                24.947764
+              ],
+              [
+                112.780805,
+                24.896747
+              ],
+              [
+                112.873812,
+                24.896747
+              ],
+              [
+                112.904609,
+                24.921715
+              ],
+              [
+                112.941565,
+                24.915745
+              ],
+              [
+                112.994536,
+                24.927142
+              ],
+              [
+                113.009934,
+                24.977604
+              ],
+              [
+                112.979137,
+                25.03401
+              ],
+              [
+                113.004391,
+                25.089306
+              ],
+              [
+                112.96805,
+                25.141869
+              ],
+              [
+                112.97421,
+                25.168412
+              ],
+              [
+                113.034572,
+                25.198199
+              ],
+              [
+                112.992688,
+                25.247467
+              ],
+              [
+                112.958195,
+                25.254503
+              ],
+              [
+                112.897833,
+                25.238264
+              ],
+              [
+                112.867036,
+                25.249632
+              ],
+              [
+                112.854718,
+                25.337829
+              ],
+              [
+                112.891058,
+                25.339993
+              ],
+              [
+                112.924319,
+                25.296714
+              ],
+              [
+                112.93479,
+                25.325929
+              ],
+              [
+                112.969898,
+                25.350269
+              ],
+              [
+                113.013014,
+                25.352432
+              ],
+              [
+                113.078304,
+                25.382174
+              ],
+              [
+                113.096782,
+                25.412449
+              ],
+              [
+                113.131274,
+                25.414611
+              ],
+              [
+                113.11834,
+                25.445418
+              ],
+              [
+                113.176854,
+                25.471355
+              ],
+              [
+                113.226129,
+                25.50971
+              ],
+              [
+                113.248919,
+                25.514031
+              ],
+              [
+                113.311129,
+                25.490264
+              ],
+              [
+                113.314208,
+                25.442716
+              ],
+              [
+                113.341926,
+                25.448661
+              ],
+              [
+                113.373338,
+                25.402719
+              ],
+              [
+                113.407215,
+                25.401637
+              ],
+              [
+                113.449715,
+                25.359463
+              ],
+              [
+                113.479896,
+                25.375145
+              ],
+              [
+                113.535946,
+                25.368656
+              ],
+              [
+                113.579062,
+                25.34432
+              ],
+              [
+                113.584606,
+                25.306453
+              ],
+              [
+                113.611707,
+                25.327552
+              ],
+              [
+                113.680076,
+                25.334584
+              ],
+              [
+                113.686852,
+                25.351891
+              ],
+              [
+                113.753373,
+                25.362707
+              ],
+              [
+                113.76446,
+                25.333502
+              ],
+              [
+                113.814967,
+                25.328634
+              ],
+              [
+                113.839605,
+                25.363248
+              ],
+              [
+                113.877177,
+                25.380552
+              ],
+              [
+                113.887032,
+                25.436772
+              ],
+              [
+                113.94493,
+                25.441635
+              ],
+              [
+                113.962792,
+                25.528072
+              ],
+              [
+                113.986198,
+                25.529153
+              ],
+              [
+                113.983118,
+                25.599336
+              ],
+              [
+                113.957249,
+                25.611749
+              ],
+              [
+                113.913517,
+                25.701299
+              ],
+              [
+                113.920293,
+                25.741197
+              ],
+              [
+                113.961561,
+                25.77731
+              ],
+              [
+                113.971416,
+                25.836036
+              ],
+              [
+                114.028082,
+                25.893119
+              ],
+              [
+                114.028082,
+                25.98138
+              ],
+              [
+                114.008372,
+                26.015806
+              ],
+              [
+                114.044096,
+                26.076564
+              ],
+              [
+                114.087828,
+                26.06635
+              ],
+              [
+                114.121089,
+                26.085702
+              ],
+              [
+                114.10569,
+                26.097526
+              ],
+              [
+                114.188842,
+                26.121172
+              ],
+              [
+                114.237501,
+                26.152333
+              ],
+              [
+                114.216559,
+                26.203355
+              ],
+              [
+                114.181451,
+                26.214631
+              ],
+              [
+                114.102611,
+                26.187783
+              ],
+              [
+                114.088444,
+                26.168448
+              ],
+              [
+                114.013299,
+                26.184023
+              ],
+              [
+                113.962792,
+                26.150722
+              ],
+              [
+                113.949242,
+                26.192616
+              ],
+              [
+                113.972647,
+                26.20604
+              ],
+              [
+                113.978807,
+                26.237716
+              ],
+              [
+                114.029314,
+                26.266163
+              ],
+              [
+                114.021307,
+                26.288701
+              ],
+              [
+                114.047792,
+                26.337518
+              ],
+              [
+                114.030546,
+                26.376664
+              ],
+              [
+                114.062575,
+                26.406149
+              ],
+              [
+                114.085364,
+                26.406149
+              ],
+              [
+                114.090292,
+                26.455988
+              ],
+              [
+                114.110002,
+                26.482775
+              ],
+              [
+                114.07243,
+                26.480096
+              ],
+              [
+                114.10877,
+                26.56952
+              ],
+              [
+                114.019459,
+                26.587182
+              ],
+              [
+                113.996669,
+                26.615543
+              ],
+              [
+                113.912901,
+                26.613938
+              ],
+              [
+                113.860546,
+                26.664221
+              ],
+              [
+                113.853771,
+                26.769532
+              ],
+              [
+                113.835909,
+                26.806394
+              ],
+              [
+                113.877177,
+                26.859262
+              ],
+              [
+                113.890112,
+                26.895562
+              ],
+              [
+                113.927068,
+                26.948922
+              ],
+              [
+                113.892575,
+                26.964925
+              ],
+              [
+                113.86301,
+                27.018252
+              ],
+              [
+                113.824206,
+                27.036378
+              ],
+              [
+                113.803264,
+                27.099261
+              ],
+              [
+                113.771851,
+                27.096598
+              ],
+              [
+                113.779242,
+                27.137081
+              ],
+              [
+                113.846996,
+                27.222262
+              ],
+              [
+                113.872865,
+                27.289828
+              ],
+              [
+                113.854387,
+                27.30525
+              ],
+              [
+                113.872865,
+                27.346721
+              ],
+              [
+                113.872865,
+                27.384988
+              ],
+              [
+                113.72812,
+                27.350442
+              ],
+              [
+                113.699786,
+                27.331836
+              ],
+              [
+                113.657902,
+                27.347253
+              ],
+              [
+                113.616635,
+                27.345658
+              ],
+              [
+                113.605548,
+                27.38924
+              ],
+              [
+                113.632033,
+                27.40518
+              ],
+              [
+                113.59754,
+                27.428554
+              ],
+              [
+                113.591381,
+                27.467855
+              ],
+              [
+                113.627105,
+                27.49971
+              ],
+              [
+                113.583374,
+                27.524657
+              ],
+              [
+                113.579062,
+                27.545354
+              ],
+              [
+                113.608627,
+                27.585143
+              ],
+              [
+                113.607395,
+                27.625449
+              ],
+              [
+                113.652359,
+                27.663619
+              ],
+              [
+                113.696707,
+                27.71979
+              ],
+              [
+                113.69917,
+                27.740979
+              ],
+              [
+                113.763228,
+                27.799228
+              ],
+              [
+                113.756453,
+                27.860091
+              ],
+              [
+                113.72812,
+                27.874904
+              ],
+              [
+                113.752141,
+                27.93361
+              ],
+              [
+                113.822974,
+                27.982243
+              ],
+              [
+                113.845148,
+                27.971672
+              ],
+              [
+                113.864242,
+                28.004966
+              ],
+              [
+                113.914133,
+                27.991227
+              ],
+              [
+                113.936307,
+                28.018703
+              ],
+              [
+                113.966488,
+                28.017646
+              ],
+              [
+                113.970184,
+                28.041418
+              ],
+              [
+                114.025618,
+                28.031382
+              ],
+              [
+                114.047176,
+                28.057263
+              ],
+              [
+                114.025002,
+                28.080499
+              ],
+              [
+                113.992357,
+                28.161255
+              ],
+              [
+                114.012068,
+                28.174972
+              ],
+              [
+                114.068734,
+                28.171806
+              ],
+              [
+                114.107538,
+                28.182885
+              ],
+              [
+                114.109386,
+                28.205038
+              ],
+              [
+                114.143879,
+                28.246694
+              ],
+              [
+                114.182067,
+                28.249858
+              ],
+              [
+                114.198081,
+                28.29097
+              ],
+              [
+                114.2529,
+                28.319423
+              ],
+              [
+                114.252284,
+                28.395787
+              ],
+              [
+                114.214712,
+                28.403157
+              ],
+              [
+                114.172212,
+                28.432632
+              ],
+              [
+                114.217175,
+                28.466308
+              ],
+              [
+                114.218407,
+                28.48472
+              ],
+              [
+                114.15435,
+                28.507337
+              ],
+              [
+                114.138335,
+                28.533629
+              ],
+              [
+                114.08598,
+                28.558337
+              ],
+              [
+                114.132176,
+                28.607211
+              ],
+              [
+                114.122321,
+                28.623497
+              ],
+              [
+                114.157429,
+                28.761566
+              ],
+              [
+                114.137719,
+                28.779926
+              ],
+              [
+                114.153734,
+                28.829221
+              ],
+              [
+                114.124784,
+                28.843376
+              ],
+              [
+                114.076741,
+                28.834464
+              ],
+              [
+                114.056415,
+                28.872204
+              ],
+              [
+                114.060111,
+                28.902596
+              ],
+              [
+                114.028082,
+                28.891069
+              ],
+              [
+                114.005292,
+                28.917788
+              ],
+              [
+                114.008988,
+                28.955498
+              ],
+              [
+                113.973879,
+                28.937692
+              ],
+              [
+                113.955401,
+                28.978536
+              ],
+              [
+                113.961561,
+                28.999476
+              ],
+              [
+                113.94185,
+                29.047097
+              ],
+              [
+                113.898119,
+                29.029307
+              ],
+              [
+                113.876561,
+                29.038202
+              ],
+              [
+                113.882104,
+                29.065407
+              ],
+              [
+                113.852539,
+                29.058606
+              ],
+              [
+                113.816199,
+                29.105154
+              ],
+              [
+                113.775547,
+                29.095219
+              ],
+              [
+                113.749677,
+                29.060699
+              ],
+              [
+                113.722576,
+                29.104631
+              ],
+              [
+                113.696091,
+                29.077437
+              ],
+              [
+                113.690547,
+                29.114566
+              ],
+              [
+                113.66283,
+                29.16945
+              ],
+              [
+                113.691779,
+                29.19662
+              ],
+              [
+                113.693011,
+                29.226394
+              ],
+              [
+                113.651743,
+                29.225872
+              ],
+              [
+                113.609859,
+                29.25146
+              ],
+              [
+                113.632033,
+                29.316186
+              ],
+              [
+                113.660982,
+                29.333405
+              ],
+              [
+                113.674533,
+                29.388172
+              ],
+              [
+                113.731199,
+                29.393907
+              ],
+              [
+                113.755221,
+                29.446557
+              ],
+              [
+                113.677613,
+                29.513763
+              ],
+              [
+                113.630801,
+                29.523137
+              ],
+              [
+                113.710257,
+                29.555419
+              ],
+              [
+                113.73859,
+                29.579363
+              ],
+              [
+                113.704098,
+                29.634518
+              ],
+              [
+                113.680692,
+                29.64336
+              ],
+              [
+                113.663446,
+                29.684443
+              ],
+              [
+                113.606164,
+                29.666764
+              ],
+              [
+                113.547033,
+                29.675603
+              ],
+              [
+                113.540258,
+                29.699519
+              ],
+              [
+                113.558736,
+                29.727067
+              ],
+              [
+                113.550729,
+                29.768115
+              ],
+              [
+                113.575367,
+                29.809147
+              ],
+              [
+                113.571671,
+                29.849123
+              ],
+              [
+                113.37765,
+                29.703158
+              ],
+              [
+                113.277252,
+                29.594976
+              ],
+              [
+                113.222433,
+                29.543965
+              ],
+              [
+                113.181781,
+                29.485636
+              ],
+              [
+                113.145441,
+                29.449163
+              ],
+              [
+                113.099861,
+                29.459585
+              ],
+              [
+                113.078304,
+                29.438218
+              ],
+              [
+                113.057362,
+                29.522616
+              ],
+              [
+                113.034572,
+                29.523658
+              ],
+              [
+                112.950188,
+                29.473132
+              ],
+              [
+                112.912,
+                29.606944
+              ],
+              [
+                112.915696,
+                29.620992
+              ],
+              [
+                113.005007,
+                29.693801
+              ],
+              [
+                113.025949,
+                29.772791
+              ],
+              [
+                112.974826,
+                29.732784
+              ],
+              [
+                112.944645,
+                29.682883
+              ],
+              [
+                112.926782,
+                29.692241
+              ],
+              [
+                112.923703,
+                29.766557
+              ],
+              [
+                112.894138,
+                29.783699
+              ],
+              [
+                112.861493,
+                29.78318
+              ],
+              [
+                112.79374,
+                29.735902
+              ],
+              [
+                112.788812,
+                29.681323
+              ],
+              [
+                112.733378,
+                29.645441
+              ],
+              [
+                112.714283,
+                29.648561
+              ],
+              [
+                112.693957,
+                29.601741
+              ],
+              [
+                112.650842,
+                29.592374
+              ],
+              [
+                112.640371,
+                29.607985
+              ],
+              [
+                112.572001,
+                29.624113
+              ],
+              [
+                112.54182,
+                29.60122
+              ],
+              [
+                112.499321,
+                29.629316
+              ],
+              [
+                112.439574,
+                29.633997
+              ],
+              [
+                112.424792,
+                29.598619
+              ],
+              [
+                112.368741,
+                29.541362
+              ],
+              [
+                112.333017,
+                29.545007
+              ],
+              [
+                112.291133,
+                29.517409
+              ],
+              [
+                112.281278,
+                29.536676
+              ],
+              [
+                112.303452,
+                29.585609
+              ],
+              [
+                112.233851,
+                29.61631
+              ],
+              [
+                112.244322,
+                29.659483
+              ],
+              [
+                112.202438,
+                29.633997
+              ],
+              [
+                112.178416,
+                29.656883
+              ],
+              [
+                112.111279,
+                29.659483
+              ],
+              [
+                112.089721,
+                29.685482
+              ],
+              [
+                112.065699,
+                29.681323
+              ],
+              [
+                112.07617,
+                29.743696
+              ],
+              [
+                112.008417,
+                29.778505
+              ],
+              [
+                111.95483,
+                29.796683
+              ],
+              [
+                111.965917,
+                29.832512
+              ],
+              [
+                111.925881,
+                29.836665
+              ],
+              [
+                111.899396,
+                29.855871
+              ],
+              [
+                111.899396,
+                29.855871
+              ],
+              [
+                111.861207,
+                29.856909
+              ],
+              [
+                111.8107,
+                29.901017
+              ],
+              [
+                111.75773,
+                29.92021
+              ],
+              [
+                111.723853,
+                29.909317
+              ],
+              [
+                111.723853,
+                29.909317
+              ],
+              [
+                111.705375,
+                29.890121
+              ],
+              [
+                111.669034,
+                29.888565
+              ],
+              [
+                111.669034,
+                29.888565
+              ],
+              [
+                111.553854,
+                29.894272
+              ],
+              [
+                111.527368,
+                29.925916
+              ],
+              [
+                111.475629,
+                29.918654
+              ],
+              [
+                111.436825,
+                29.930065
+              ],
+              [
+                111.394325,
+                29.912948
+              ],
+              [
+                111.382623,
+                29.95029
+              ],
+              [
+                111.342587,
+                29.944586
+              ],
+              [
+                111.3315,
+                29.970512
+              ],
+              [
+                111.266826,
+                30.01146
+              ],
+              [
+                111.242188,
+                30.040476
+              ],
+              [
+                111.031537,
+                30.048765
+              ],
+              [
+                110.929907,
+                30.063268
+              ],
+              [
+                110.924364,
+                30.111426
+              ],
+              [
+                110.851067,
+                30.126439
+              ],
+              [
+                110.746973,
+                30.112979
+              ],
+              [
+                110.756212,
+                30.054463
+              ],
+              [
+                110.712481,
+                30.033223
+              ],
+              [
+                110.650887,
+                30.07777
+              ],
+              [
+                110.600996,
+                30.054463
+              ],
+              [
+                110.531394,
+                30.061197
+              ],
+              [
+                110.497518,
+                30.055499
+              ],
+              [
+                110.491358,
+                30.019751
+              ],
+              [
+                110.557264,
+                29.988137
+              ],
+              [
+                110.517228,
+                29.961179
+              ],
+              [
+                110.49875,
+                29.91243
+              ],
+              [
+                110.538786,
+                29.895828
+              ],
+              [
+                110.549873,
+                29.848085
+              ],
+              [
+                110.60038,
+                29.839779
+              ],
+              [
+                110.642879,
+                29.775907
+              ],
+              [
+                110.562807,
+                29.712515
+              ],
+              [
+                110.507373,
+                29.692241
+              ],
+              [
+                110.467337,
+                29.713034
+              ],
+              [
+                110.447011,
+                29.664684
+              ],
+              [
+                110.372482,
+                29.633477
+              ],
+              [
+                110.339221,
+                29.668324
+              ],
+              [
+                110.302265,
+                29.661563
+              ],
+              [
+                110.289946,
+                29.6964
+              ],
+              [
+                110.219729,
+                29.746814
+              ],
+              [
+                110.160599,
+                29.753569
+              ],
+              [
+                110.113788,
+                29.789932
+              ],
+              [
+                110.02386,
+                29.769674
+              ],
+              [
+                109.941325,
+                29.774349
+              ],
+              [
+                109.908064,
+                29.763959
+              ],
+              [
+                109.869876,
+                29.774869
+              ],
+              [
+                109.779333,
+                29.757725
+              ],
+              [
+                109.755311,
+                29.733304
+              ],
+              [
+                109.760238,
+                29.689122
+              ],
+              [
+                109.714659,
+                29.673524
+              ],
+              [
+                109.701108,
+                29.636078
+              ],
+              [
+                109.717739,
+                29.615269
+              ],
+              [
+                109.664768,
+                29.599659
+              ],
+              [
+                109.651833,
+                29.625674
+              ],
+              [
+                109.578536,
+                29.629836
+              ],
+              [
+                109.558826,
+                29.606944
+              ],
+              [
+                109.516326,
+                29.626194
+              ],
+              [
+                109.488609,
+                29.553336
+              ],
+              [
+                109.467051,
+                29.560104
+              ],
+              [
+                109.458428,
+                29.513242
+              ],
+              [
+                109.433791,
+                29.530948
+              ],
+              [
+                109.436254,
+                29.488761
+              ],
+              [
+                109.415928,
+                29.497617
+              ],
+              [
+                109.418392,
+                29.453332
+              ],
+              [
+                109.368501,
+                29.413719
+              ],
+              [
+                109.391291,
+                29.372005
+              ],
+              [
+                109.343863,
+                29.369398
+              ],
+              [
+                109.352487,
+                29.284872
+              ],
+              [
+                109.312451,
+                29.25146
+              ],
+              [
+                109.257632,
+                29.222738
+              ],
+              [
+                109.275494,
+                29.202366
+              ],
+              [
+                109.261328,
+                29.161089
+              ],
+              [
+                109.274262,
+                29.121885
+              ],
+              [
+                109.232378,
+                29.119271
+              ],
+              [
+                109.240386,
+                29.086328
+              ],
+              [
+                109.312451,
+                29.066453
+              ],
+              [
+                109.319842,
+                29.042388
+              ],
+              [
+                109.294588,
+                29.015177
+              ],
+              [
+                109.292741,
+                28.987436
+              ],
+              [
+                109.261328,
+                28.952356
+              ],
+              [
+                109.235458,
+                28.882161
+              ],
+              [
+                109.246545,
+                28.80143
+              ],
+              [
+                109.241002,
+                28.776779
+              ],
+              [
+                109.2989,
+                28.7474
+              ],
+              [
+                109.294588,
+                28.722211
+              ],
+              [
+                109.252704,
+                28.691767
+              ],
+              [
+                109.271183,
+                28.671816
+              ],
+              [
+                109.192958,
+                28.636104
+              ],
+              [
+                109.201581,
+                28.597753
+              ],
+              [
+                109.235458,
+                28.61982
+              ],
+              [
+                109.252089,
+                28.606685
+              ],
+              [
+                109.306907,
+                28.62087
+              ],
+              [
+                109.319842,
+                28.579886
+              ],
+              [
+                109.273646,
+                28.53836
+              ],
+              [
+                109.274262,
+                28.494714
+              ],
+              [
+                109.260712,
+                28.46473
+              ],
+              [
+                109.264407,
+                28.392628
+              ],
+              [
+                109.289045,
+                28.373673
+              ],
+              [
+                109.268719,
+                28.33786
+              ],
+              [
+                109.275494,
+                28.313101
+              ],
+              [
+                109.317994,
+                28.277795
+              ],
+              [
+                109.33524,
+                28.293605
+              ],
+              [
+                109.388211,
+                28.268307
+              ],
+              [
+                109.367885,
+                28.254602
+              ],
+              [
+                109.340168,
+                28.19027
+              ],
+              [
+                109.33832,
+                28.141731
+              ],
+              [
+                109.314298,
+                28.103729
+              ],
+              [
+                109.298284,
+                28.036136
+              ],
+              [
+                109.335856,
+                28.063073
+              ],
+              [
+                109.378972,
+                28.034551
+              ],
+              [
+                109.362342,
+                28.007608
+              ],
+              [
+                109.319842,
+                27.988585
+              ],
+              [
+                109.30198,
+                27.956343
+              ],
+              [
+                109.32169,
+                27.868027
+              ],
+              [
+                109.346943,
+                27.838396
+              ],
+              [
+                109.332777,
+                27.782815
+              ],
+              [
+                109.37774,
+                27.736741
+              ],
+              [
+                109.366653,
+                27.721909
+              ],
+              [
+                109.414081,
+                27.725087
+              ],
+              [
+                109.470747,
+                27.680049
+              ],
+              [
+                109.45658,
+                27.673689
+              ],
+              [
+                109.470131,
+                27.62863
+              ],
+              [
+                109.451037,
+                27.586204
+              ],
+              [
+                109.461508,
+                27.567637
+              ],
+              [
+                109.404841,
+                27.55066
+              ],
+              [
+                109.303211,
+                27.47582
+              ],
+              [
+                109.300132,
+                27.423774
+              ],
+              [
+                109.245313,
+                27.41793
+              ],
+              [
+                109.202197,
+                27.450331
+              ],
+              [
+                109.167089,
+                27.41793
+              ],
+              [
+                109.141835,
+                27.448207
+              ],
+              [
+                109.142451,
+                27.418461
+              ],
+              [
+                109.103647,
+                27.336621
+              ],
+              [
+                109.044517,
+                27.331304
+              ],
+              [
+                109.053756,
+                27.293551
+              ],
+              [
+                108.983539,
+                27.26802
+              ],
+              [
+                108.963213,
+                27.235565
+              ],
+              [
+                108.907778,
+                27.204699
+              ],
+              [
+                108.926873,
+                27.160512
+              ],
+              [
+                108.878829,
+                27.106187
+              ],
+              [
+                108.79075,
+                27.084343
+              ],
+              [
+                108.877597,
+                27.01612
+              ],
+              [
+                108.942887,
+                27.017186
+              ],
+              [
+                108.942887,
+                27.017186
+              ],
+              [
+                108.940423,
+                27.044907
+              ],
+              [
+                109.007561,
+                27.08008
+              ],
+              [
+                109.032814,
+                27.104056
+              ],
+              [
+                109.128901,
+                27.122701
+              ],
+              [
+                109.101183,
+                27.06889
+              ],
+              [
+                109.165857,
+                27.066758
+              ],
+              [
+                109.21698,
+                27.114711
+              ],
+              [
+                109.239154,
+                27.14933
+              ],
+              [
+                109.264407,
+                27.131755
+              ],
+              [
+                109.33524,
+                27.139212
+              ],
+              [
+                109.358646,
+                27.153058
+              ],
+              [
+                109.415312,
+                27.154123
+              ],
+              [
+                109.441182,
+                27.117907
+              ],
+              [
+                109.472595,
+                27.134951
+              ],
+              [
+                109.454733,
+                27.069423
+              ],
+              [
+                109.486761,
+                27.053968
+              ],
+              [
+                109.497848,
+                27.079548
+              ],
+              [
+                109.520022,
+                27.058764
+              ],
+              [
+                109.555131,
+                26.946788
+              ],
+              [
+                109.436254,
+                26.892359
+              ],
+              [
+                109.452885,
+                26.861932
+              ],
+              [
+                109.486761,
+                26.895562
+              ],
+              [
+                109.509551,
+                26.877947
+              ],
+              [
+                109.513247,
+                26.84004
+              ],
+              [
+                109.497232,
+                26.815474
+              ],
+              [
+                109.522486,
+                26.749226
+              ],
+              [
+                109.528645,
+                26.743881
+              ],
+              [
+                109.554515,
+                26.73533
+              ],
+              [
+                109.597015,
+                26.756173
+              ],
+              [
+                109.568065,
+                26.726243
+              ],
+              [
+                109.528645,
+                26.743881
+              ],
+              [
+                109.52187,
+                26.749226
+              ],
+              [
+                109.486761,
+                26.759913
+              ],
+              [
+                109.447957,
+                26.759913
+              ],
+              [
+                109.407305,
+                26.719829
+              ],
+              [
+                109.35495,
+                26.693098
+              ],
+              [
+                109.283501,
+                26.698445
+              ],
+              [
+                109.306291,
+                26.661012
+              ],
+              [
+                109.334008,
+                26.646036
+              ],
+              [
+                109.35495,
+                26.658873
+              ],
+              [
+                109.390675,
+                26.598955
+              ],
+              [
+                109.407305,
+                26.533116
+              ],
+              [
+                109.381436,
+                26.518659
+              ],
+              [
+                109.385747,
+                26.493487
+              ],
+              [
+                109.362342,
+                26.472061
+              ],
+              [
+                109.38082,
+                26.454381
+              ],
+              [
+                109.319842,
+                26.418477
+              ],
+              [
+                109.29582,
+                26.350389
+              ],
+              [
+                109.271183,
+                26.327863
+              ],
+              [
+                109.285965,
+                26.295676
+              ],
+              [
+                109.325385,
+                26.29031
+              ],
+              [
+                109.351255,
+                26.264016
+              ],
+              [
+                109.369733,
+                26.277432
+              ],
+              [
+                109.442414,
+                26.289774
+              ],
+              [
+                109.467051,
+                26.313917
+              ],
+              [
+                109.439334,
+                26.238789
+              ],
+              [
+                109.47629,
+                26.148035
+              ],
+              [
+                109.513863,
+                26.128157
+              ],
+              [
+                109.502776,
+                26.096451
+              ],
+              [
+                109.449805,
+                26.101826
+              ],
+              [
+                109.452885,
+                26.055598
+              ],
+              [
+                109.48245,
+                26.029788
+              ],
+              [
+                109.513247,
+                25.998056
+              ],
+              [
+                109.560058,
+                26.021184
+              ],
+              [
+                109.588391,
+                26.019571
+              ],
+              [
+                109.635203,
+                26.047533
+              ],
+              [
+                109.649369,
+                26.016882
+              ],
+              [
+                109.730057,
+                25.989988
+              ],
+              [
+                109.710963,
+                25.954478
+              ],
+              [
+                109.693717,
+                25.959321
+              ],
+              [
+                109.67955,
+                25.921649
+              ],
+              [
+                109.685094,
+                25.880197
+              ],
+              [
+                109.768246,
+                25.890427
+              ],
+              [
+                109.779333,
+                25.866196
+              ],
+              [
+                109.811361,
+                25.877504
+              ],
+              [
+                109.826144,
+                25.911422
+              ],
+              [
+                109.806434,
+                25.973848
+              ],
+              [
+                109.782412,
+                25.996981
+              ],
+              [
+                109.814441,
+                26.041081
+              ],
+              [
+                109.864332,
+                26.027637
+              ],
+              [
+                109.898825,
+                26.095377
+              ],
+              [
+                109.904368,
+                26.135679
+              ],
+              [
+                109.970274,
+                26.195301
+              ],
+              [
+                110.03002,
+                26.166299
+              ],
+              [
+                110.099005,
+                26.168985
+              ],
+              [
+                110.100853,
+                26.132455
+              ],
+              [
+                110.065128,
+                26.050221
+              ],
+              [
+                110.100853,
+                26.020108
+              ],
+              [
+                110.168606,
+                26.028713
+              ],
+              [
+                110.181541,
+                26.060437
+              ],
+              [
+                110.24991,
+                26.010965
+              ],
+              [
+                110.257301,
+                25.961473
+              ],
+              [
+                110.325671,
+                25.975462
+              ],
+              [
+                110.373098,
+                26.088927
+              ],
+              [
+                110.437772,
+                26.153945
+              ],
+              [
+                110.477808,
+                26.179727
+              ],
+              [
+                110.495054,
+                26.166299
+              ],
+              [
+                110.546793,
+                26.233421
+              ],
+              [
+                110.552952,
+                26.283335
+              ],
+              [
+                110.584365,
+                26.296749
+              ],
+              [
+                110.612083,
+                26.333764
+              ],
+              [
+                110.643495,
+                26.308552
+              ],
+              [
+                110.673676,
+                26.317135
+              ],
+              [
+                110.721104,
+                26.294066
+              ],
+              [
+                110.742046,
+                26.313917
+              ],
+              [
+                110.73527,
+                26.270993
+              ],
+              [
+                110.759292,
+                26.248451
+              ],
+              [
+                110.836284,
+                26.255966
+              ],
+              [
+                110.939762,
+                26.286554
+              ],
+              [
+                110.926212,
+                26.320354
+              ],
+              [
+                110.944074,
+                26.326791
+              ],
+              [
+                110.94469,
+                26.373447
+              ],
+              [
+                110.974255,
+                26.385778
+              ],
+              [
+                111.008747,
+                26.35897
+              ],
+              [
+                111.008132,
+                26.336982
+              ],
+              [
+                111.090667,
+                26.308016
+              ],
+              [
+                111.208928,
+                26.30426
+              ],
+              [
+                111.204616,
+                26.276359
+              ],
+              [
+                111.228022,
+                26.261333
+              ],
+              [
+                111.277913,
+                26.272066
+              ],
+              [
+                111.293311,
+                26.222148
+              ],
+              [
+                111.271754,
+                26.217316
+              ],
+              [
+                111.274833,
+                26.183486
+              ],
+              [
+                111.258203,
+                26.151796
+              ],
+              [
+                111.26621,
+                26.095914
+              ],
+              [
+                111.244652,
+                26.078177
+              ],
+              [
+                111.267442,
+                26.058824
+              ],
+              [
+                111.235413,
+                26.048071
+              ],
+              [
+                111.189834,
+                25.953402
+              ],
+              [
+                111.230486,
+                25.916267
+              ],
+              [
+                111.251428,
+                25.864581
+              ],
+              [
+                111.29208,
+                25.854349
+              ],
+              [
+                111.297007,
+                25.874274
+              ],
+              [
+                111.346282,
+                25.906577
+              ],
+              [
+                111.376463,
+                25.906039
+              ],
+              [
+                111.383239,
+                25.881812
+              ],
+              [
+                111.460231,
+                25.885042
+              ],
+              [
+                111.4861,
+                25.859196
+              ],
+              [
+                111.43313,
+                25.84627
+              ],
+              [
+                111.442369,
+                25.77192
+              ],
+              [
+                111.399869,
+                25.744431
+              ],
+              [
+                111.30871,
+                25.720171
+              ],
+              [
+                111.309942,
+                25.645203
+              ],
+              [
+                111.343202,
+                25.602574
+              ],
+              [
+                111.324724,
+                25.564249
+              ],
+              [
+                111.32842,
+                25.521592
+              ],
+              [
+                111.279145,
+                25.42326
+              ],
+              [
+                111.210776,
+                25.363248
+              ],
+              [
+                111.184906,
+                25.367034
+              ],
+              [
+                111.138711,
+                25.303748
+              ],
+              [
+                111.103602,
+                25.285351
+              ],
+              [
+                111.112841,
+                25.21715
+              ],
+              [
+                110.998892,
+                25.161371
+              ],
+              [
+                110.98411,
+                25.101772
+              ],
+              [
+                110.951465,
+                25.04377
+              ],
+              [
+                110.968711,
+                24.975434
+              ],
+              [
+                111.009363,
+                24.921172
+              ],
+              [
+                111.100522,
+                24.945593
+              ],
+              [
+                111.101754,
+                25.035095
+              ],
+              [
+                111.139943,
+                25.042144
+              ],
+              [
+                111.200921,
+                25.074672
+              ],
+              [
+                111.221862,
+                25.106649
+              ],
+              [
+                111.274833,
+                25.151078
+              ],
+              [
+                111.321645,
+                25.105023
+              ],
+              [
+                111.36784,
+                25.108817
+              ],
+              [
+                111.375231,
+                25.128324
+              ],
+              [
+                111.435593,
+                25.093642
+              ],
+              [
+                111.416499,
+                25.047566
+              ],
+              [
+                111.467622,
+                25.02208
+              ],
+              [
+                111.460231,
+                24.992793
+              ],
+              [
+                111.43313,
+                24.979774
+              ],
+              [
+                111.434977,
+                24.951562
+              ],
+              [
+                111.470086,
+                24.92877
+              ],
+              [
+                111.447296,
+                24.892947
+              ],
+              [
+                111.449144,
+                24.857113
+              ],
+              [
+                111.479325,
+                24.797366
+              ],
+              [
+                111.461463,
+                24.728894
+              ],
+              [
+                111.431282,
+                24.687574
+              ],
+              [
+                111.451608,
+                24.665822
+              ],
+              [
+                111.499035,
+                24.667997
+              ],
+              [
+                111.526752,
+                24.637538
+              ],
+              [
+                111.570484,
+                24.64461
+              ],
+              [
+                111.588962,
+                24.690837
+              ],
+              [
+                111.641933,
+                24.684856
+              ],
+              [
+                111.637621,
+                24.715303
+              ],
+              [
+                111.666571,
+                24.760961
+              ],
+              [
+                111.708455,
+                24.788673
+              ],
+              [
+                111.783599,
+                24.785957
+              ],
+              [
+                111.814396,
+                24.770199
+              ],
+              [
+                111.868599,
+                24.771829
+              ],
+              [
+                111.875374,
+                24.756613
+              ],
+              [
+                111.929577,
+                24.75607
+              ],
+              [
+                111.951135,
+                24.769655
+              ],
+              [
+                112.024431,
+                24.740308
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.528645,
+                26.743881
+              ],
+              [
+                109.522486,
+                26.749226
+              ],
+              [
+                109.52187,
+                26.749226
+              ],
+              [
+                109.528645,
+                26.743881
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 440000,
+        "name": "骞夸笢鐪�",
+        "center": [
+          113.280637,
+          23.125178
+        ],
+        "centroid": [
+          113.429919,
+          23.334643
+        ],
+        "childrenNum": 21,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 18,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                113.558736,
+                22.212244
+              ],
+              [
+                113.594461,
+                22.228864
+              ],
+              [
+                113.595693,
+                22.304186
+              ],
+              [
+                113.617866,
+                22.315259
+              ],
+              [
+                113.604932,
+                22.339617
+              ],
+              [
+                113.627721,
+                22.349027
+              ],
+              [
+                113.669605,
+                22.416539
+              ],
+              [
+                113.66591,
+                22.438667
+              ],
+              [
+                113.624642,
+                22.443092
+              ],
+              [
+                113.608627,
+                22.408793
+              ],
+              [
+                113.573519,
+                22.41156
+              ],
+              [
+                113.631417,
+                22.475723
+              ],
+              [
+                113.668373,
+                22.4807
+              ],
+              [
+                113.691779,
+                22.514981
+              ],
+              [
+                113.740438,
+                22.534329
+              ],
+              [
+                113.717033,
+                22.645391
+              ],
+              [
+                113.678228,
+                22.726007
+              ],
+              [
+                113.733663,
+                22.736494
+              ],
+              [
+                113.758301,
+                22.683496
+              ],
+              [
+                113.765692,
+                22.665825
+              ],
+              [
+                113.803264,
+                22.593463
+              ],
+              [
+                113.856851,
+                22.539857
+              ],
+              [
+                113.869786,
+                22.459685
+              ],
+              [
+                113.893807,
+                22.442539
+              ],
+              [
+                113.952937,
+                22.486783
+              ],
+              [
+                113.954785,
+                22.491206
+              ],
+              [
+                113.976343,
+                22.510558
+              ],
+              [
+                114.031778,
+                22.503923
+              ],
+              [
+                114.082285,
+                22.512216
+              ],
+              [
+                114.095219,
+                22.534329
+              ],
+              [
+                114.156813,
+                22.543726
+              ],
+              [
+                114.166052,
+                22.559201
+              ],
+              [
+                114.222719,
+                22.553122
+              ],
+              [
+                114.232574,
+                22.539857
+              ],
+              [
+                114.294784,
+                22.563623
+              ],
+              [
+                114.321885,
+                22.587385
+              ],
+              [
+                114.381631,
+                22.60175
+              ],
+              [
+                114.427211,
+                22.589042
+              ],
+              [
+                114.472174,
+                22.522168
+              ],
+              [
+                114.476486,
+                22.459132
+              ],
+              [
+                114.506667,
+                22.438667
+              ],
+              [
+                114.549167,
+                22.465769
+              ],
+              [
+                114.611377,
+                22.481806
+              ],
+              [
+                114.628623,
+                22.513875
+              ],
+              [
+                114.614456,
+                22.545384
+              ],
+              [
+                114.568261,
+                22.560859
+              ],
+              [
+                114.559022,
+                22.583517
+              ],
+              [
+                114.603369,
+                22.638763
+              ],
+              [
+                114.579964,
+                22.661407
+              ],
+              [
+                114.51529,
+                22.655332
+              ],
+              [
+                114.567029,
+                22.685705
+              ],
+              [
+                114.591666,
+                22.690122
+              ],
+              [
+                114.601521,
+                22.730975
+              ],
+              [
+                114.689601,
+                22.7674
+              ],
+              [
+                114.709927,
+                22.787817
+              ],
+              [
+                114.749963,
+                22.764089
+              ],
+              [
+                114.73518,
+                22.724351
+              ],
+              [
+                114.728405,
+                22.651466
+              ],
+              [
+                114.743803,
+                22.632687
+              ],
+              [
+                114.746267,
+                22.581859
+              ],
+              [
+                114.866375,
+                22.591805
+              ],
+              [
+                114.88547,
+                22.538751
+              ],
+              [
+                114.922426,
+                22.549253
+              ],
+              [
+                114.927969,
+                22.621639
+              ],
+              [
+                114.945216,
+                22.645391
+              ],
+              [
+                115.039454,
+                22.713862
+              ],
+              [
+                115.02344,
+                22.726007
+              ],
+              [
+                115.053621,
+                22.747533
+              ],
+              [
+                115.076411,
+                22.788368
+              ],
+              [
+                115.154635,
+                22.80161
+              ],
+              [
+                115.190975,
+                22.77347
+              ],
+              [
+                115.190359,
+                22.818711
+              ],
+              [
+                115.236555,
+                22.82533
+              ],
+              [
+                115.230396,
+                22.776781
+              ],
+              [
+                115.319091,
+                22.783402
+              ],
+              [
+                115.338185,
+                22.776781
+              ],
+              [
+                115.349272,
+                22.712206
+              ],
+              [
+                115.381301,
+                22.684048
+              ],
+              [
+                115.430576,
+                22.684048
+              ],
+              [
+                115.471844,
+                22.697852
+              ],
+              [
+                115.575322,
+                22.650914
+              ],
+              [
+                115.565467,
+                22.684048
+              ],
+              [
+                115.609198,
+                22.753052
+              ],
+              [
+                115.541445,
+                22.755259
+              ],
+              [
+                115.570394,
+                22.786713
+              ],
+              [
+                115.583945,
+                22.82864
+              ],
+              [
+                115.654162,
+                22.865591
+              ],
+              [
+                115.696046,
+                22.84298
+              ],
+              [
+                115.760103,
+                22.834707
+              ],
+              [
+                115.788437,
+                22.809885
+              ],
+              [
+                115.796444,
+                22.739254
+              ],
+              [
+                115.829089,
+                22.734838
+              ],
+              [
+                115.883291,
+                22.78561
+              ],
+              [
+                115.931334,
+                22.802713
+              ],
+              [
+                115.965211,
+                22.800506
+              ],
+              [
+                115.99724,
+                22.826985
+              ],
+              [
+                116.05637,
+                22.844635
+              ],
+              [
+                116.104413,
+                22.816505
+              ],
+              [
+                116.14137,
+                22.835259
+              ],
+              [
+                116.239304,
+                22.921275
+              ],
+              [
+                116.259014,
+                22.932298
+              ],
+              [
+                116.302746,
+                22.951588
+              ],
+              [
+                116.382818,
+                22.91907
+              ],
+              [
+                116.449955,
+                22.936707
+              ],
+              [
+                116.50539,
+                22.930645
+              ],
+              [
+                116.544194,
+                22.996769
+              ],
+              [
+                116.576839,
+                23.014397
+              ],
+              [
+                116.557129,
+                23.056253
+              ],
+              [
+                116.566368,
+                23.088738
+              ],
+              [
+                116.550969,
+                23.109656
+              ],
+              [
+                116.566368,
+                23.134424
+              ],
+              [
+                116.665534,
+                23.158086
+              ],
+              [
+                116.701259,
+                23.198248
+              ],
+              [
+                116.74499,
+                23.215299
+              ],
+              [
+                116.806584,
+                23.200998
+              ],
+              [
+                116.821367,
+                23.240597
+              ],
+              [
+                116.798577,
+                23.244996
+              ],
+              [
+                116.782563,
+                23.313714
+              ],
+              [
+                116.871874,
+                23.4159
+              ],
+              [
+                116.871258,
+                23.416449
+              ],
+              [
+                116.874338,
+                23.447199
+              ],
+              [
+                116.874953,
+                23.447748
+              ],
+              [
+                116.895895,
+                23.476295
+              ],
+              [
+                116.888504,
+                23.501543
+              ],
+              [
+                116.92854,
+                23.530079
+              ],
+              [
+                116.963649,
+                23.507031
+              ],
+              [
+                117.01046,
+                23.502641
+              ],
+              [
+                117.044953,
+                23.539955
+              ],
+              [
+                117.085605,
+                23.536663
+              ],
+              [
+                117.192778,
+                23.5619
+              ],
+              [
+                117.192778,
+                23.629356
+              ],
+              [
+                117.147199,
+                23.654027
+              ],
+              [
+                117.123793,
+                23.647448
+              ],
+              [
+                117.055424,
+                23.694038
+              ],
+              [
+                117.048032,
+                23.758687
+              ],
+              [
+                117.019083,
+                23.801952
+              ],
+              [
+                117.012308,
+                23.855054
+              ],
+              [
+                116.981511,
+                23.855602
+              ],
+              [
+                116.955642,
+                23.922359
+              ],
+              [
+                116.976583,
+                23.931659
+              ],
+              [
+                116.981511,
+                23.999471
+              ],
+              [
+                116.953178,
+                24.008218
+              ],
+              [
+                116.930388,
+                24.064514
+              ],
+              [
+                116.9347,
+                24.126794
+              ],
+              [
+                116.998757,
+                24.179217
+              ],
+              [
+                116.956257,
+                24.216883
+              ],
+              [
+                116.933468,
+                24.220157
+              ],
+              [
+                116.938395,
+                24.28127
+              ],
+              [
+                116.914374,
+                24.287817
+              ],
+              [
+                116.919301,
+                24.321087
+              ],
+              [
+                116.895895,
+                24.350533
+              ],
+              [
+                116.903903,
+                24.369614
+              ],
+              [
+                116.839229,
+                24.442097
+              ],
+              [
+                116.860787,
+                24.460075
+              ],
+              [
+                116.83307,
+                24.496568
+              ],
+              [
+                116.796729,
+                24.502014
+              ],
+              [
+                116.759157,
+                24.545572
+              ],
+              [
+                116.761005,
+                24.583128
+              ],
+              [
+                116.815207,
+                24.654944
+              ],
+              [
+                116.777635,
+                24.679418
+              ],
+              [
+                116.667382,
+                24.658752
+              ],
+              [
+                116.623034,
+                24.64189
+              ],
+              [
+                116.600861,
+                24.654401
+              ],
+              [
+                116.570679,
+                24.621762
+              ],
+              [
+                116.530027,
+                24.604895
+              ],
+              [
+                116.506622,
+                24.621218
+              ],
+              [
+                116.517709,
+                24.652225
+              ],
+              [
+                116.485064,
+                24.720196
+              ],
+              [
+                116.44626,
+                24.714216
+              ],
+              [
+                116.416079,
+                24.744113
+              ],
+              [
+                116.419158,
+                24.767482
+              ],
+              [
+                116.375427,
+                24.803885
+              ],
+              [
+                116.381586,
+                24.82507
+              ],
+              [
+                116.417927,
+                24.840821
+              ],
+              [
+                116.395137,
+                24.877746
+              ],
+              [
+                116.363724,
+                24.87123
+              ],
+              [
+                116.345862,
+                24.828872
+              ],
+              [
+                116.297202,
+                24.801712
+              ],
+              [
+                116.244232,
+                24.793563
+              ],
+              [
+                116.251007,
+                24.82507
+              ],
+              [
+                116.221442,
+                24.829959
+              ],
+              [
+                116.191877,
+                24.877203
+              ],
+              [
+                116.153073,
+                24.846795
+              ],
+              [
+                116.068073,
+                24.850053
+              ],
+              [
+                116.015102,
+                24.905975
+              ],
+              [
+                115.985537,
+                24.899461
+              ],
+              [
+                115.907929,
+                24.923343
+              ],
+              [
+                115.89253,
+                24.936911
+              ],
+              [
+                115.885139,
+                24.898918
+              ],
+              [
+                115.907313,
+                24.879917
+              ],
+              [
+                115.861733,
+                24.863629
+              ],
+              [
+                115.863581,
+                24.891318
+              ],
+              [
+                115.824161,
+                24.909232
+              ],
+              [
+                115.807531,
+                24.862543
+              ],
+              [
+                115.790284,
+                24.856027
+              ],
+              [
+                115.764415,
+                24.791933
+              ],
+              [
+                115.776734,
+                24.774546
+              ],
+              [
+                115.756408,
+                24.749004
+              ],
+              [
+                115.769342,
+                24.708236
+              ],
+              [
+                115.801371,
+                24.705517
+              ],
+              [
+                115.780429,
+                24.663103
+              ],
+              [
+                115.797676,
+                24.628834
+              ],
+              [
+                115.840791,
+                24.584217
+              ],
+              [
+                115.843871,
+                24.562446
+              ],
+              [
+                115.785357,
+                24.567345
+              ],
+              [
+                115.752712,
+                24.546116
+              ],
+              [
+                115.68927,
+                24.545027
+              ],
+              [
+                115.671408,
+                24.604895
+              ],
+              [
+                115.605503,
+                24.62557
+              ],
+              [
+                115.569778,
+                24.622306
+              ],
+              [
+                115.555611,
+                24.683768
+              ],
+              [
+                115.522967,
+                24.702799
+              ],
+              [
+                115.476771,
+                24.762591
+              ],
+              [
+                115.412714,
+                24.79302
+              ],
+              [
+                115.372678,
+                24.774546
+              ],
+              [
+                115.358511,
+                24.735416
+              ],
+              [
+                115.306772,
+                24.758787
+              ],
+              [
+                115.269816,
+                24.749548
+              ],
+              [
+                115.258729,
+                24.728894
+              ],
+              [
+                115.1842,
+                24.711498
+              ],
+              [
+                115.104744,
+                24.667997
+              ],
+              [
+                115.083802,
+                24.699537
+              ],
+              [
+                115.057317,
+                24.703343
+              ],
+              [
+                115.024672,
+                24.669085
+              ],
+              [
+                115.00373,
+                24.679418
+              ],
+              [
+                114.940288,
+                24.650049
+              ],
+              [
+                114.909491,
+                24.661471
+              ],
+              [
+                114.893477,
+                24.582584
+              ],
+              [
+                114.868839,
+                24.562446
+              ],
+              [
+                114.846665,
+                24.602719
+              ],
+              [
+                114.827571,
+                24.588026
+              ],
+              [
+                114.781376,
+                24.613057
+              ],
+              [
+                114.729637,
+                24.608704
+              ],
+              [
+                114.73826,
+                24.565168
+              ],
+              [
+                114.704999,
+                24.525973
+              ],
+              [
+                114.664963,
+                24.583673
+              ],
+              [
+                114.627391,
+                24.576598
+              ],
+              [
+                114.589819,
+                24.537406
+              ],
+              [
+                114.534384,
+                24.559181
+              ],
+              [
+                114.429058,
+                24.48622
+              ],
+              [
+                114.403189,
+                24.497657
+              ],
+              [
+                114.391486,
+                24.563535
+              ],
+              [
+                114.363769,
+                24.582584
+              ],
+              [
+                114.300943,
+                24.578775
+              ],
+              [
+                114.289856,
+                24.619042
+              ],
+              [
+                114.258443,
+                24.641346
+              ],
+              [
+                114.19069,
+                24.656576
+              ],
+              [
+                114.169132,
+                24.689749
+              ],
+              [
+                114.27261,
+                24.700624
+              ],
+              [
+                114.281849,
+                24.724001
+              ],
+              [
+                114.336052,
+                24.749004
+              ],
+              [
+                114.342211,
+                24.807145
+              ],
+              [
+                114.378551,
+                24.861457
+              ],
+              [
+                114.403189,
+                24.877746
+              ],
+              [
+                114.395798,
+                24.951019
+              ],
+              [
+                114.454928,
+                24.977062
+              ],
+              [
+                114.45616,
+                24.99659
+              ],
+              [
+                114.506051,
+                24.999844
+              ],
+              [
+                114.532536,
+                25.022623
+              ],
+              [
+                114.561485,
+                25.077382
+              ],
+              [
+                114.604601,
+                25.083886
+              ],
+              [
+                114.640326,
+                25.074129
+              ],
+              [
+                114.664963,
+                25.10123
+              ],
+              [
+                114.735796,
+                25.121822
+              ],
+              [
+                114.73518,
+                25.155954
+              ],
+              [
+                114.685905,
+                25.173287
+              ],
+              [
+                114.693912,
+                25.213902
+              ],
+              [
+                114.73518,
+                25.225813
+              ],
+              [
+                114.743188,
+                25.274528
+              ],
+              [
+                114.714238,
+                25.315651
+              ],
+              [
+                114.63663,
+                25.324306
+              ],
+              [
+                114.599674,
+                25.385959
+              ],
+              [
+                114.541159,
+                25.416773
+              ],
+              [
+                114.477718,
+                25.37136
+              ],
+              [
+                114.438914,
+                25.376226
+              ],
+              [
+                114.43029,
+                25.343779
+              ],
+              [
+                114.382863,
+                25.317274
+              ],
+              [
+                114.31511,
+                25.33837
+              ],
+              [
+                114.2954,
+                25.299961
+              ],
+              [
+                114.260291,
+                25.291845
+              ],
+              [
+                114.204857,
+                25.29942
+              ],
+              [
+                114.190074,
+                25.316733
+              ],
+              [
+                114.115545,
+                25.302125
+              ],
+              [
+                114.083517,
+                25.275611
+              ],
+              [
+                114.055799,
+                25.277775
+              ],
+              [
+                114.039785,
+                25.250714
+              ],
+              [
+                114.017611,
+                25.273987
+              ],
+              [
+                114.029314,
+                25.328093
+              ],
+              [
+                114.050256,
+                25.36433
+              ],
+              [
+                113.983118,
+                25.415152
+              ],
+              [
+                114.003444,
+                25.442716
+              ],
+              [
+                113.94493,
+                25.441635
+              ],
+              [
+                113.887032,
+                25.436772
+              ],
+              [
+                113.877177,
+                25.380552
+              ],
+              [
+                113.839605,
+                25.363248
+              ],
+              [
+                113.814967,
+                25.328634
+              ],
+              [
+                113.76446,
+                25.333502
+              ],
+              [
+                113.753373,
+                25.362707
+              ],
+              [
+                113.686852,
+                25.351891
+              ],
+              [
+                113.680076,
+                25.334584
+              ],
+              [
+                113.611707,
+                25.327552
+              ],
+              [
+                113.584606,
+                25.306453
+              ],
+              [
+                113.579062,
+                25.34432
+              ],
+              [
+                113.535946,
+                25.368656
+              ],
+              [
+                113.479896,
+                25.375145
+              ],
+              [
+                113.449715,
+                25.359463
+              ],
+              [
+                113.407215,
+                25.401637
+              ],
+              [
+                113.373338,
+                25.402719
+              ],
+              [
+                113.341926,
+                25.448661
+              ],
+              [
+                113.314208,
+                25.442716
+              ],
+              [
+                113.311129,
+                25.490264
+              ],
+              [
+                113.248919,
+                25.514031
+              ],
+              [
+                113.226129,
+                25.50971
+              ],
+              [
+                113.176854,
+                25.471355
+              ],
+              [
+                113.11834,
+                25.445418
+              ],
+              [
+                113.131274,
+                25.414611
+              ],
+              [
+                113.096782,
+                25.412449
+              ],
+              [
+                113.078304,
+                25.382174
+              ],
+              [
+                113.013014,
+                25.352432
+              ],
+              [
+                112.969898,
+                25.350269
+              ],
+              [
+                112.93479,
+                25.325929
+              ],
+              [
+                112.924319,
+                25.296714
+              ],
+              [
+                112.891058,
+                25.339993
+              ],
+              [
+                112.854718,
+                25.337829
+              ],
+              [
+                112.867036,
+                25.249632
+              ],
+              [
+                112.897833,
+                25.238264
+              ],
+              [
+                112.958195,
+                25.254503
+              ],
+              [
+                112.992688,
+                25.247467
+              ],
+              [
+                113.034572,
+                25.198199
+              ],
+              [
+                112.97421,
+                25.168412
+              ],
+              [
+                112.96805,
+                25.141869
+              ],
+              [
+                113.004391,
+                25.089306
+              ],
+              [
+                112.979137,
+                25.03401
+              ],
+              [
+                113.009934,
+                24.977604
+              ],
+              [
+                112.994536,
+                24.927142
+              ],
+              [
+                112.941565,
+                24.915745
+              ],
+              [
+                112.904609,
+                24.921715
+              ],
+              [
+                112.873812,
+                24.896747
+              ],
+              [
+                112.780805,
+                24.896747
+              ],
+              [
+                112.778341,
+                24.947764
+              ],
+              [
+                112.743233,
+                24.959701
+              ],
+              [
+                112.742001,
+                24.99876
+              ],
+              [
+                112.714899,
+                25.025876
+              ],
+              [
+                112.712436,
+                25.083344
+              ],
+              [
+                112.660081,
+                25.132658
+              ],
+              [
+                112.628052,
+                25.140785
+              ],
+              [
+                112.562762,
+                25.124531
+              ],
+              [
+                112.458053,
+                25.152162
+              ],
+              [
+                112.44327,
+                25.185744
+              ],
+              [
+                112.414937,
+                25.14241
+              ],
+              [
+                112.365046,
+                25.191701
+              ],
+              [
+                112.315771,
+                25.175453
+              ],
+              [
+                112.302836,
+                25.157037
+              ],
+              [
+                112.256025,
+                25.159204
+              ],
+              [
+                112.246785,
+                25.185202
+              ],
+              [
+                112.187039,
+                25.182494
+              ],
+              [
+                112.177184,
+                25.106649
+              ],
+              [
+                112.151931,
+                25.055698
+              ],
+              [
+                112.155626,
+                25.026419
+              ],
+              [
+                112.12175,
+                24.989538
+              ],
+              [
+                112.119902,
+                24.963499
+              ],
+              [
+                112.175337,
+                24.927685
+              ],
+              [
+                112.167329,
+                24.859828
+              ],
+              [
+                112.149467,
+                24.837019
+              ],
+              [
+                112.124214,
+                24.841364
+              ],
+              [
+                112.03367,
+                24.771286
+              ],
+              [
+                112.024431,
+                24.740308
+              ],
+              [
+                111.961606,
+                24.721283
+              ],
+              [
+                111.939432,
+                24.686487
+              ],
+              [
+                111.953598,
+                24.64733
+              ],
+              [
+                111.927729,
+                24.629378
+              ],
+              [
+                111.936968,
+                24.595645
+              ],
+              [
+                111.972077,
+                24.578775
+              ],
+              [
+                112.007185,
+                24.534684
+              ],
+              [
+                112.009649,
+                24.503103
+              ],
+              [
+                111.985011,
+                24.467701
+              ],
+              [
+                112.025047,
+                24.438828
+              ],
+              [
+                112.057692,
+                24.387057
+              ],
+              [
+                112.05954,
+                24.339628
+              ],
+              [
+                112.026279,
+                24.294908
+              ],
+              [
+                111.990555,
+                24.279634
+              ],
+              [
+                111.986243,
+                24.25672
+              ],
+              [
+                111.958526,
+                24.263813
+              ],
+              [
+                111.912946,
+                24.221795
+              ],
+              [
+                111.877222,
+                24.227252
+              ],
+              [
+                111.871062,
+                24.176487
+              ],
+              [
+                111.886461,
+                24.163929
+              ],
+              [
+                111.878454,
+                24.109862
+              ],
+              [
+                111.92157,
+                24.012045
+              ],
+              [
+                111.940664,
+                23.987989
+              ],
+              [
+                111.911714,
+                23.943693
+              ],
+              [
+                111.854432,
+                23.947521
+              ],
+              [
+                111.845809,
+                23.904305
+              ],
+              [
+                111.812548,
+                23.887343
+              ],
+              [
+                111.824867,
+                23.832612
+              ],
+              [
+                111.8107,
+                23.80688
+              ],
+              [
+                111.722621,
+                23.823305
+              ],
+              [
+                111.683201,
+                23.822758
+              ],
+              [
+                111.683201,
+                23.822758
+              ],
+              [
+                111.654868,
+                23.833159
+              ],
+              [
+                111.627766,
+                23.78881
+              ],
+              [
+                111.621607,
+                23.725819
+              ],
+              [
+                111.666571,
+                23.718696
+              ],
+              [
+                111.614832,
+                23.65896
+              ],
+              [
+                111.615448,
+                23.639225
+              ],
+              [
+                111.555702,
+                23.64087
+              ],
+              [
+                111.487332,
+                23.626615
+              ],
+              [
+                111.479941,
+                23.532822
+              ],
+              [
+                111.428818,
+                23.466414
+              ],
+              [
+                111.399869,
+                23.469159
+              ],
+              [
+                111.383239,
+                23.399423
+              ],
+              [
+                111.389398,
+                23.375804
+              ],
+              [
+                111.363528,
+                23.340641
+              ],
+              [
+                111.376463,
+                23.30437
+              ],
+              [
+                111.353058,
+                23.284582
+              ],
+              [
+                111.36476,
+                23.240047
+              ],
+              [
+                111.388782,
+                23.210349
+              ],
+              [
+                111.38447,
+                23.16744
+              ],
+              [
+                111.365992,
+                23.14488
+              ],
+              [
+                111.377695,
+                23.082132
+              ],
+              [
+                111.402333,
+                23.066165
+              ],
+              [
+                111.43313,
+                23.073322
+              ],
+              [
+                111.433746,
+                23.036428
+              ],
+              [
+                111.389398,
+                23.005583
+              ],
+              [
+                111.403565,
+                22.99126
+              ],
+              [
+                111.362913,
+                22.967568
+              ],
+              [
+                111.374615,
+                22.938361
+              ],
+              [
+                111.358601,
+                22.889301
+              ],
+              [
+                111.218167,
+                22.748085
+              ],
+              [
+                111.185522,
+                22.735942
+              ],
+              [
+                111.118385,
+                22.744773
+              ],
+              [
+                111.058023,
+                22.729871
+              ],
+              [
+                111.089435,
+                22.695643
+              ],
+              [
+                111.055559,
+                22.648705
+              ],
+              [
+                110.997045,
+                22.631582
+              ],
+              [
+                110.958856,
+                22.636553
+              ],
+              [
+                110.950233,
+                22.61059
+              ],
+              [
+                110.896031,
+                22.613352
+              ],
+              [
+                110.897878,
+                22.591805
+              ],
+              [
+                110.812263,
+                22.576333
+              ],
+              [
+                110.778386,
+                22.585174
+              ],
+              [
+                110.749437,
+                22.556991
+              ],
+              [
+                110.762988,
+                22.518298
+              ],
+              [
+                110.740198,
+                22.498947
+              ],
+              [
+                110.74143,
+                22.464109
+              ],
+              [
+                110.688459,
+                22.477935
+              ],
+              [
+                110.712481,
+                22.440879
+              ],
+              [
+                110.711249,
+                22.369506
+              ],
+              [
+                110.74143,
+                22.361757
+              ],
+              [
+                110.749437,
+                22.329653
+              ],
+              [
+                110.787009,
+                22.28259
+              ],
+              [
+                110.759292,
+                22.274837
+              ],
+              [
+                110.725415,
+                22.29588
+              ],
+              [
+                110.687843,
+                22.249914
+              ],
+              [
+                110.646575,
+                22.220554
+              ],
+              [
+                110.678604,
+                22.172901
+              ],
+              [
+                110.629329,
+                22.149068
+              ],
+              [
+                110.598532,
+                22.162924
+              ],
+              [
+                110.602843,
+                22.18343
+              ],
+              [
+                110.55788,
+                22.196175
+              ],
+              [
+                110.505525,
+                22.14297
+              ],
+              [
+                110.456866,
+                22.189526
+              ],
+              [
+                110.414366,
+                22.208365
+              ],
+              [
+                110.378026,
+                22.164587
+              ],
+              [
+                110.34846,
+                22.195621
+              ],
+              [
+                110.326287,
+                22.152393
+              ],
+              [
+                110.364475,
+                22.125785
+              ],
+              [
+                110.35154,
+                22.097508
+              ],
+              [
+                110.359547,
+                22.015973
+              ],
+              [
+                110.352772,
+                21.97602
+              ],
+              [
+                110.374946,
+                21.967695
+              ],
+              [
+                110.374946,
+                21.967695
+              ],
+              [
+                110.378642,
+                21.939942
+              ],
+              [
+                110.378642,
+                21.939942
+              ],
+              [
+                110.391576,
+                21.89386
+              ],
+              [
+                110.337374,
+                21.887751
+              ],
+              [
+                110.290562,
+                21.917736
+              ],
+              [
+                110.283787,
+                21.892194
+              ],
+              [
+                110.224041,
+                21.882198
+              ],
+              [
+                110.224041,
+                21.882198
+              ],
+              [
+                110.212338,
+                21.886085
+              ],
+              [
+                110.212338,
+                21.886085
+              ],
+              [
+                110.196323,
+                21.899968
+              ],
+              [
+                110.12857,
+                21.902744
+              ],
+              [
+                110.101469,
+                21.86998
+              ],
+              [
+                110.050962,
+                21.857205
+              ],
+              [
+                109.999839,
+                21.881643
+              ],
+              [
+                109.94502,
+                21.84443
+              ],
+              [
+                109.940093,
+                21.769419
+              ],
+              [
+                109.916071,
+                21.668787
+              ],
+              [
+                109.888354,
+                21.652101
+              ],
+              [
+                109.888354,
+                21.652101
+              ],
+              [
+                109.839695,
+                21.636525
+              ],
+              [
+                109.786108,
+                21.637638
+              ],
+              [
+                109.778101,
+                21.670455
+              ],
+              [
+                109.742992,
+                21.616497
+              ],
+              [
+                109.754695,
+                21.556396
+              ],
+              [
+                109.788572,
+                21.490702
+              ],
+              [
+                109.785492,
+                21.45673
+              ],
+              [
+                109.819369,
+                21.445033
+              ],
+              [
+                109.894513,
+                21.442248
+              ],
+              [
+                109.904368,
+                21.429992
+              ],
+              [
+                109.868644,
+                21.365913
+              ],
+              [
+                109.770709,
+                21.359783
+              ],
+              [
+                109.757775,
+                21.346963
+              ],
+              [
+                109.763934,
+                21.226514
+              ],
+              [
+                109.674623,
+                21.136671
+              ],
+              [
+                109.674007,
+                21.067997
+              ],
+              [
+                109.655529,
+                20.929435
+              ],
+              [
+                109.664768,
+                20.862343
+              ],
+              [
+                109.711579,
+                20.774519
+              ],
+              [
+                109.730057,
+                20.719673
+              ],
+              [
+                109.74484,
+                20.621124
+              ],
+              [
+                109.793499,
+                20.615522
+              ],
+              [
+                109.813825,
+                20.574627
+              ],
+              [
+                109.811977,
+                20.541566
+              ],
+              [
+                109.839695,
+                20.489439
+              ],
+              [
+                109.888354,
+                20.475423
+              ],
+              [
+                109.895745,
+                20.42776
+              ],
+              [
+                109.864948,
+                20.40196
+              ],
+              [
+                109.861252,
+                20.376717
+              ],
+              [
+                109.916071,
+                20.316677
+              ],
+              [
+                109.909296,
+                20.236961
+              ],
+              [
+                109.929006,
+                20.211691
+              ],
+              [
+                109.993679,
+                20.254368
+              ],
+              [
+                110.082375,
+                20.258859
+              ],
+              [
+                110.118099,
+                20.219553
+              ],
+              [
+                110.168606,
+                20.219553
+              ],
+              [
+                110.220345,
+                20.25156
+              ],
+              [
+                110.296722,
+                20.249314
+              ],
+              [
+                110.349076,
+                20.258859
+              ],
+              [
+                110.384185,
+                20.293103
+              ],
+              [
+                110.425453,
+                20.291419
+              ],
+              [
+                110.452554,
+                20.311064
+              ],
+              [
+                110.491358,
+                20.373912
+              ],
+              [
+                110.54125,
+                20.42047
+              ],
+              [
+                110.550489,
+                20.47262
+              ],
+              [
+                110.499982,
+                20.572386
+              ],
+              [
+                110.487047,
+                20.640167
+              ],
+              [
+                110.466105,
+                20.680485
+              ],
+              [
+                110.411286,
+                20.670966
+              ],
+              [
+                110.392192,
+                20.682724
+              ],
+              [
+                110.407591,
+                20.731987
+              ],
+              [
+                110.393424,
+                20.816479
+              ],
+              [
+                110.350924,
+                20.84165
+              ],
+              [
+                110.327519,
+                20.847802
+              ],
+              [
+                110.269004,
+                20.839972
+              ],
+              [
+                110.209874,
+                20.860106
+              ],
+              [
+                110.184005,
+                20.891979
+              ],
+              [
+                110.180925,
+                20.98197
+              ],
+              [
+                110.204947,
+                21.003202
+              ],
+              [
+                110.208642,
+                21.050684
+              ],
+              [
+                110.241903,
+                21.016051
+              ],
+              [
+                110.24991,
+                21.045098
+              ],
+              [
+                110.296722,
+                21.093684
+              ],
+              [
+                110.39096,
+                21.124949
+              ],
+              [
+                110.422373,
+                21.190807
+              ],
+              [
+                110.451322,
+                21.186343
+              ],
+              [
+                110.501213,
+                21.217588
+              ],
+              [
+                110.534474,
+                21.204198
+              ],
+              [
+                110.626249,
+                21.215915
+              ],
+              [
+                110.65951,
+                21.239902
+              ],
+              [
+                110.713097,
+                21.3124
+              ],
+              [
+                110.768531,
+                21.364799
+              ],
+              [
+                110.796248,
+                21.37483
+              ],
+              [
+                110.888639,
+                21.367585
+              ],
+              [
+                110.929291,
+                21.375945
+              ],
+              [
+                111.034617,
+                21.438906
+              ],
+              [
+                111.103602,
+                21.455616
+              ],
+              [
+                111.171355,
+                21.458401
+              ],
+              [
+                111.28284,
+                21.485691
+              ],
+              [
+                111.276065,
+                21.443362
+              ],
+              [
+                111.250196,
+                21.45116
+              ],
+              [
+                111.257587,
+                21.41495
+              ],
+              [
+                111.28592,
+                21.41885
+              ],
+              [
+                111.353058,
+                21.464528
+              ],
+              [
+                111.382623,
+                21.495714
+              ],
+              [
+                111.444217,
+                21.514088
+              ],
+              [
+                111.494724,
+                21.501282
+              ],
+              [
+                111.521825,
+                21.517429
+              ],
+              [
+                111.560629,
+                21.50518
+              ],
+              [
+                111.609904,
+                21.530234
+              ],
+              [
+                111.650556,
+                21.512418
+              ],
+              [
+                111.677658,
+                21.529677
+              ],
+              [
+                111.693672,
+                21.590345
+              ],
+              [
+                111.736788,
+                21.609821
+              ],
+              [
+                111.794686,
+                21.61149
+              ],
+              [
+                111.832258,
+                21.578659
+              ],
+              [
+                111.810084,
+                21.555283
+              ],
+              [
+                111.887693,
+                21.578659
+              ],
+              [
+                111.941896,
+                21.607039
+              ],
+              [
+                111.972692,
+                21.603144
+              ],
+              [
+                112.026895,
+                21.633744
+              ],
+              [
+                111.997946,
+                21.657107
+              ],
+              [
+                111.954214,
+                21.667674
+              ],
+              [
+                111.956062,
+                21.710494
+              ],
+              [
+                112.036134,
+                21.761637
+              ],
+              [
+                112.136532,
+                21.793871
+              ],
+              [
+                112.192583,
+                21.789425
+              ],
+              [
+                112.196894,
+                21.736624
+              ],
+              [
+                112.236315,
+                21.727173
+              ],
+              [
+                112.238778,
+                21.702153
+              ],
+              [
+                112.353343,
+                21.707157
+              ],
+              [
+                112.415553,
+                21.734956
+              ],
+              [
+                112.427256,
+                21.789981
+              ],
+              [
+                112.445734,
+                21.803317
+              ],
+              [
+                112.497473,
+                21.785535
+              ],
+              [
+                112.535661,
+                21.753856
+              ],
+              [
+                112.647146,
+                21.758302
+              ],
+              [
+                112.68595,
+                21.810541
+              ],
+              [
+                112.792508,
+                21.921067
+              ],
+              [
+                112.841167,
+                21.920512
+              ],
+              [
+                112.893522,
+                21.84443
+              ],
+              [
+                112.929862,
+                21.838875
+              ],
+              [
+                112.989608,
+                21.869424
+              ],
+              [
+                113.047507,
+                21.956595
+              ],
+              [
+                113.053666,
+                22.012089
+              ],
+              [
+                113.032108,
+                22.04593
+              ],
+              [
+                113.045659,
+                22.088636
+              ],
+              [
+                113.086927,
+                22.12634
+              ],
+              [
+                113.091854,
+                22.065344
+              ],
+              [
+                113.142977,
+                22.012089
+              ],
+              [
+                113.1516,
+                21.979905
+              ],
+              [
+                113.235368,
+                21.887751
+              ],
+              [
+                113.266781,
+                21.871646
+              ],
+              [
+                113.319752,
+                21.909407
+              ],
+              [
+                113.330223,
+                21.96159
+              ],
+              [
+                113.442324,
+                22.009315
+              ],
+              [
+                113.45957,
+                22.043711
+              ],
+              [
+                113.527939,
+                22.073663
+              ],
+              [
+                113.567359,
+                22.075327
+              ],
+              [
+                113.554425,
+                22.107489
+              ],
+              [
+                113.554425,
+                22.142416
+              ],
+              [
+                113.534715,
+                22.174009
+              ],
+              [
+                113.53841,
+                22.209473
+              ],
+              [
+                113.558736,
+                22.212244
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.024627,
+                23.437865
+              ],
+              [
+                116.982743,
+                23.460924
+              ],
+              [
+                116.944555,
+                23.440061
+              ],
+              [
+                116.951946,
+                23.419744
+              ],
+              [
+                117.027091,
+                23.41535
+              ],
+              [
+                117.050496,
+                23.400522
+              ],
+              [
+                117.081909,
+                23.409309
+              ],
+              [
+                117.124409,
+                23.389537
+              ],
+              [
+                117.142887,
+                23.400522
+              ],
+              [
+                117.142887,
+                23.459826
+              ],
+              [
+                117.129336,
+                23.483431
+              ],
+              [
+                117.093612,
+                23.459277
+              ],
+              [
+                117.058503,
+                23.47355
+              ],
+              [
+                117.029554,
+                23.443356
+              ],
+              [
+                117.024627,
+                23.437865
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.853486,
+                21.740515
+              ],
+              [
+                112.876275,
+                21.772753
+              ],
+              [
+                112.840551,
+                21.776644
+              ],
+              [
+                112.782653,
+                21.739959
+              ],
+              [
+                112.724138,
+                21.719945
+              ],
+              [
+                112.70566,
+                21.679354
+              ],
+              [
+                112.734609,
+                21.666562
+              ],
+              [
+                112.780189,
+                21.671568
+              ],
+              [
+                112.730914,
+                21.613715
+              ],
+              [
+                112.775261,
+                21.564189
+              ],
+              [
+                112.817145,
+                21.590345
+              ],
+              [
+                112.798667,
+                21.610933
+              ],
+              [
+                112.821457,
+                21.655994
+              ],
+              [
+                112.804826,
+                21.686583
+              ],
+              [
+                112.83316,
+                21.736624
+              ],
+              [
+                112.853486,
+                21.740515
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.530733,
+                21.583667
+              ],
+              [
+                112.563378,
+                21.591458
+              ],
+              [
+                112.571385,
+                21.619835
+              ],
+              [
+                112.621277,
+                21.606482
+              ],
+              [
+                112.665624,
+                21.642644
+              ],
+              [
+                112.639139,
+                21.67268
+              ],
+              [
+                112.66624,
+                21.683803
+              ],
+              [
+                112.663776,
+                21.714386
+              ],
+              [
+                112.592327,
+                21.693256
+              ],
+              [
+                112.560299,
+                21.666562
+              ],
+              [
+                112.57077,
+                21.645982
+              ],
+              [
+                112.535045,
+                21.628737
+              ],
+              [
+                112.530733,
+                21.583667
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.231342,
+                22.016528
+              ],
+              [
+                114.311414,
+                22.041493
+              ],
+              [
+                114.302791,
+                22.050368
+              ],
+              [
+                114.239965,
+                22.03539
+              ],
+              [
+                114.231342,
+                22.016528
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.43346,
+                21.171276
+              ],
+              [
+                110.489511,
+                21.138904
+              ],
+              [
+                110.508605,
+                21.140579
+              ],
+              [
+                110.544945,
+                21.083633
+              ],
+              [
+                110.582517,
+                21.094801
+              ],
+              [
+                110.632409,
+                21.210893
+              ],
+              [
+                110.589293,
+                21.194713
+              ],
+              [
+                110.525235,
+                21.190249
+              ],
+              [
+                110.499366,
+                21.213125
+              ],
+              [
+                110.445163,
+                21.184669
+              ],
+              [
+                110.431612,
+                21.180763
+              ],
+              [
+                110.43346,
+                21.171276
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.435263,
+                21.663781
+              ],
+              [
+                112.456205,
+                21.648763
+              ],
+              [
+                112.458669,
+                21.68992
+              ],
+              [
+                112.435263,
+                21.663781
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.517844,
+                21.079166
+              ],
+              [
+                110.459946,
+                21.062971
+              ],
+              [
+                110.398352,
+                21.096476
+              ],
+              [
+                110.352772,
+                21.079724
+              ],
+              [
+                110.305961,
+                21.0881
+              ],
+              [
+                110.27578,
+                21.033369
+              ],
+              [
+                110.211106,
+                20.986999
+              ],
+              [
+                110.201251,
+                20.938378
+              ],
+              [
+                110.309656,
+                20.963529
+              ],
+              [
+                110.347845,
+                20.984763
+              ],
+              [
+                110.407591,
+                20.990351
+              ],
+              [
+                110.47288,
+                20.983087
+              ],
+              [
+                110.511684,
+                20.916578
+              ],
+              [
+                110.535706,
+                20.922727
+              ],
+              [
+                110.539402,
+                20.987557
+              ],
+              [
+                110.560344,
+                21.061295
+              ],
+              [
+                110.517844,
+                21.079166
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.765076,
+                21.962145
+              ],
+              [
+                113.774315,
+                21.998218
+              ],
+              [
+                113.74167,
+                21.991559
+              ],
+              [
+                113.765076,
+                21.962145
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.723192,
+                21.922177
+              ],
+              [
+                113.742902,
+                21.950489
+              ],
+              [
+                113.71888,
+                21.951599
+              ],
+              [
+                113.723192,
+                21.922177
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.142977,
+                21.831653
+              ],
+              [
+                113.162071,
+                21.853873
+              ],
+              [
+                113.203955,
+                21.861093
+              ],
+              [
+                113.167615,
+                21.876644
+              ],
+              [
+                113.136818,
+                21.868869
+              ],
+              [
+                113.142977,
+                21.831653
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.819894,
+                22.396068
+              ],
+              [
+                113.813735,
+                22.419858
+              ],
+              [
+                113.786634,
+                22.413773
+              ],
+              [
+                113.819894,
+                22.396068
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.190074,
+                21.986564
+              ],
+              [
+                114.229494,
+                21.995443
+              ],
+              [
+                114.180835,
+                22.00987
+              ],
+              [
+                114.190074,
+                21.986564
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.153734,
+                21.97491
+              ],
+              [
+                114.171596,
+                22.000437
+              ],
+              [
+                114.124169,
+                21.985455
+              ],
+              [
+                114.153734,
+                21.97491
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.769628,
+                20.771721
+              ],
+              [
+                116.761005,
+                20.750456
+              ],
+              [
+                116.87249,
+                20.738143
+              ],
+              [
+                116.889736,
+                20.683284
+              ],
+              [
+                116.849084,
+                20.628405
+              ],
+              [
+                116.749302,
+                20.600958
+              ],
+              [
+                116.796113,
+                20.582471
+              ],
+              [
+                116.862635,
+                20.588633
+              ],
+              [
+                116.905135,
+                20.619443
+              ],
+              [
+                116.934084,
+                20.676565
+              ],
+              [
+                116.925461,
+                20.726949
+              ],
+              [
+                116.88604,
+                20.775638
+              ],
+              [
+                116.820135,
+                20.780674
+              ],
+              [
+                116.769628,
+                20.771721
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.025333,
+                21.847762
+              ],
+              [
+                113.045659,
+                21.882753
+              ],
+              [
+                113.007471,
+                21.869424
+              ],
+              [
+                113.025333,
+                21.847762
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.405127,
+                20.678245
+              ],
+              [
+                110.437772,
+                20.677685
+              ],
+              [
+                110.414366,
+                20.710157
+              ],
+              [
+                110.405127,
+                20.678245
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.644727,
+                20.935584
+              ],
+              [
+                110.584365,
+                20.948998
+              ],
+              [
+                110.548641,
+                20.908752
+              ],
+              [
+                110.562807,
+                20.861224
+              ],
+              [
+                110.611467,
+                20.860106
+              ],
+              [
+                110.646575,
+                20.917137
+              ],
+              [
+                110.644727,
+                20.935584
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.556648,
+                20.32734
+              ],
+              [
+                110.593604,
+                20.360447
+              ],
+              [
+                110.586213,
+                20.381205
+              ],
+              [
+                110.556648,
+                20.32734
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.943037,
+                21.097592
+              ],
+              [
+                115.953508,
+                21.064088
+              ],
+              [
+                115.989233,
+                21.035603
+              ],
+              [
+                116.040356,
+                21.02052
+              ],
+              [
+                116.067457,
+                21.04063
+              ],
+              [
+                116.044051,
+                21.110434
+              ],
+              [
+                116.024341,
+                21.12439
+              ],
+              [
+                115.965211,
+                21.123832
+              ],
+              [
+                115.943037,
+                21.097592
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.926407,
+                20.981411
+              ],
+              [
+                115.939342,
+                20.945644
+              ],
+              [
+                115.970139,
+                20.919373
+              ],
+              [
+                115.999088,
+                20.922727
+              ],
+              [
+                116.000936,
+                20.948439
+              ],
+              [
+                115.954124,
+                20.99985
+              ],
+              [
+                115.926407,
+                20.981411
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.834632,
+                22.722695
+              ],
+              [
+                115.834632,
+                22.722143
+              ],
+              [
+                115.835248,
+                22.722695
+              ],
+              [
+                115.834632,
+                22.722695
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.834632,
+                22.723247
+              ],
+              [
+                115.834632,
+                22.722695
+              ],
+              [
+                115.835248,
+                22.722695
+              ],
+              [
+                115.834632,
+                22.723247
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 450000,
+        "name": "骞胯タ澹棌鑷不鍖�",
+        "center": [
+          108.320004,
+          22.82402
+        ],
+        "centroid": [
+          108.7944,
+          23.833381
+        ],
+        "childrenNum": 14,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 19,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                109.48245,
+                26.029788
+              ],
+              [
+                109.473211,
+                26.006663
+              ],
+              [
+                109.408537,
+                25.967392
+              ],
+              [
+                109.435022,
+                25.93349
+              ],
+              [
+                109.396834,
+                25.900117
+              ],
+              [
+                109.359262,
+                25.836036
+              ],
+              [
+                109.339552,
+                25.83442
+              ],
+              [
+                109.327849,
+                25.76168
+              ],
+              [
+                109.340168,
+                25.731493
+              ],
+              [
+                109.296436,
+                25.71424
+              ],
+              [
+                109.207125,
+                25.740119
+              ],
+              [
+                109.206509,
+                25.788087
+              ],
+              [
+                109.147995,
+                25.741736
+              ],
+              [
+                109.13198,
+                25.762758
+              ],
+              [
+                109.143683,
+                25.795092
+              ],
+              [
+                109.095024,
+                25.80533
+              ],
+              [
+                109.077778,
+                25.776771
+              ],
+              [
+                109.048213,
+                25.790781
+              ],
+              [
+                108.989698,
+                25.778926
+              ],
+              [
+                108.999553,
+                25.765453
+              ],
+              [
+                108.963829,
+                25.732572
+              ],
+              [
+                108.940423,
+                25.740119
+              ],
+              [
+                108.896076,
+                25.71424
+              ],
+              [
+                108.900387,
+                25.682423
+              ],
+              [
+                108.953974,
+                25.686738
+              ],
+              [
+                108.953974,
+                25.686738
+              ],
+              [
+                109.007561,
+                25.734728
+              ],
+              [
+                109.043285,
+                25.738502
+              ],
+              [
+                109.07901,
+                25.72071
+              ],
+              [
+                109.075314,
+                25.693749
+              ],
+              [
+                109.030966,
+                25.629556
+              ],
+              [
+                109.051908,
+                25.566949
+              ],
+              [
+                109.088249,
+                25.550752
+              ],
+              [
+                109.024807,
+                25.51241
+              ],
+              [
+                108.949046,
+                25.557231
+              ],
+              [
+                108.8893,
+                25.543193
+              ],
+              [
+                108.890532,
+                25.556151
+              ],
+              [
+                108.826474,
+                25.550212
+              ],
+              [
+                108.814772,
+                25.526992
+              ],
+              [
+                108.781511,
+                25.554531
+              ],
+              [
+                108.799989,
+                25.576666
+              ],
+              [
+                108.783975,
+                25.628477
+              ],
+              [
+                108.724844,
+                25.634952
+              ],
+              [
+                108.68912,
+                25.623081
+              ],
+              [
+                108.68604,
+                25.587462
+              ],
+              [
+                108.660787,
+                25.584763
+              ],
+              [
+                108.658323,
+                25.550212
+              ],
+              [
+                108.68912,
+                25.533473
+              ],
+              [
+                108.634917,
+                25.520512
+              ],
+              [
+                108.6072,
+                25.491885
+              ],
+              [
+                108.600425,
+                25.432448
+              ],
+              [
+                108.62999,
+                25.335666
+              ],
+              [
+                108.625062,
+                25.308076
+              ],
+              [
+                108.589338,
+                25.335125
+              ],
+              [
+                108.585642,
+                25.365952
+              ],
+              [
+                108.471693,
+                25.458928
+              ],
+              [
+                108.418723,
+                25.443257
+              ],
+              [
+                108.400244,
+                25.491344
+              ],
+              [
+                108.359592,
+                25.513491
+              ],
+              [
+                108.348506,
+                25.536173
+              ],
+              [
+                108.308469,
+                25.525912
+              ],
+              [
+                108.280752,
+                25.48
+              ],
+              [
+                108.241332,
+                25.46217
+              ],
+              [
+                108.251803,
+                25.430286
+              ],
+              [
+                108.192673,
+                25.458928
+              ],
+              [
+                108.162492,
+                25.444878
+              ],
+              [
+                108.193289,
+                25.405421
+              ],
+              [
+                108.142782,
+                25.390825
+              ],
+              [
+                108.152021,
+                25.324306
+              ],
+              [
+                108.143398,
+                25.269658
+              ],
+              [
+                108.115065,
+                25.210112
+              ],
+              [
+                108.080572,
+                25.193867
+              ],
+              [
+                108.001732,
+                25.196574
+              ],
+              [
+                107.928435,
+                25.155954
+              ],
+              [
+                107.872384,
+                25.141327
+              ],
+              [
+                107.839124,
+                25.115861
+              ],
+              [
+                107.762747,
+                25.125073
+              ],
+              [
+                107.789233,
+                25.15487
+              ],
+              [
+                107.760283,
+                25.188451
+              ],
+              [
+                107.762131,
+                25.229061
+              ],
+              [
+                107.741805,
+                25.24043
+              ],
+              [
+                107.700537,
+                25.194408
+              ],
+              [
+                107.696226,
+                25.219858
+              ],
+              [
+                107.661733,
+                25.258833
+              ],
+              [
+                107.659885,
+                25.316192
+              ],
+              [
+                107.632168,
+                25.310241
+              ],
+              [
+                107.599523,
+                25.250714
+              ],
+              [
+                107.576734,
+                25.256668
+              ],
+              [
+                107.512676,
+                25.209029
+              ],
+              [
+                107.472024,
+                25.213902
+              ],
+              [
+                107.489886,
+                25.276693
+              ],
+              [
+                107.481263,
+                25.299961
+              ],
+              [
+                107.432604,
+                25.289139
+              ],
+              [
+                107.409198,
+                25.347024
+              ],
+              [
+                107.420901,
+                25.392987
+              ],
+              [
+                107.375937,
+                25.411908
+              ],
+              [
+                107.358691,
+                25.393528
+              ],
+              [
+                107.318039,
+                25.401637
+              ],
+              [
+                107.308184,
+                25.432988
+              ],
+              [
+                107.336517,
+                25.461089
+              ],
+              [
+                107.263836,
+                25.543193
+              ],
+              [
+                107.232423,
+                25.556691
+              ],
+              [
+                107.228728,
+                25.604733
+              ],
+              [
+                107.205322,
+                25.607971
+              ],
+              [
+                107.185612,
+                25.578825
+              ],
+              [
+                107.064272,
+                25.559391
+              ],
+              [
+                107.066736,
+                25.50917
+              ],
+              [
+                107.015613,
+                25.495666
+              ],
+              [
+                106.996519,
+                25.442716
+              ],
+              [
+                106.963874,
+                25.437852
+              ],
+              [
+                106.987896,
+                25.358922
+              ],
+              [
+                107.012533,
+                25.352973
+              ],
+              [
+                107.013765,
+                25.275611
+              ],
+              [
+                106.975577,
+                25.232851
+              ],
+              [
+                106.933077,
+                25.250714
+              ],
+              [
+                106.904128,
+                25.231768
+              ],
+              [
+                106.888113,
+                25.181953
+              ],
+              [
+                106.853005,
+                25.186827
+              ],
+              [
+                106.787715,
+                25.17112
+              ],
+              [
+                106.764926,
+                25.183036
+              ],
+              [
+                106.732281,
+                25.162454
+              ],
+              [
+                106.691013,
+                25.179245
+              ],
+              [
+                106.644817,
+                25.164621
+              ],
+              [
+                106.63989,
+                25.132658
+              ],
+              [
+                106.590615,
+                25.08768
+              ],
+              [
+                106.551195,
+                25.082802
+              ],
+              [
+                106.519782,
+                25.054072
+              ],
+              [
+                106.450181,
+                25.033468
+              ],
+              [
+                106.442173,
+                25.019369
+              ],
+              [
+                106.332536,
+                24.988454
+              ],
+              [
+                106.304819,
+                24.973807
+              ],
+              [
+                106.253696,
+                24.971094
+              ],
+              [
+                106.215508,
+                24.981944
+              ],
+              [
+                106.191486,
+                24.95319
+              ],
+              [
+                106.145291,
+                24.954275
+              ],
+              [
+                106.197645,
+                24.885889
+              ],
+              [
+                106.206269,
+                24.851139
+              ],
+              [
+                106.173008,
+                24.760417
+              ],
+              [
+                106.150218,
+                24.762591
+              ],
+              [
+                106.113878,
+                24.714216
+              ],
+              [
+                106.047356,
+                24.684312
+              ],
+              [
+                106.024566,
+                24.633186
+              ],
+              [
+                105.961741,
+                24.677786
+              ],
+              [
+                105.942031,
+                24.725088
+              ],
+              [
+                105.863806,
+                24.729437
+              ],
+              [
+                105.827466,
+                24.702799
+              ],
+              [
+                105.767104,
+                24.719109
+              ],
+              [
+                105.70551,
+                24.768569
+              ],
+              [
+                105.617431,
+                24.78161
+              ],
+              [
+                105.607576,
+                24.803885
+              ],
+              [
+                105.573083,
+                24.797366
+              ],
+              [
+                105.497322,
+                24.809318
+              ],
+              [
+                105.493011,
+                24.833217
+              ],
+              [
+                105.457286,
+                24.87123
+              ],
+              [
+                105.428337,
+                24.930941
+              ],
+              [
+                105.365511,
+                24.943423
+              ],
+              [
+                105.334099,
+                24.9266
+              ],
+              [
+                105.267577,
+                24.929313
+              ],
+              [
+                105.251563,
+                24.967296
+              ],
+              [
+                105.212758,
+                24.995505
+              ],
+              [
+                105.178266,
+                24.985199
+              ],
+              [
+                105.157324,
+                24.958616
+              ],
+              [
+                105.131454,
+                24.959701
+              ],
+              [
+                105.09573,
+                24.92877
+              ],
+              [
+                105.096346,
+                24.928228
+              ],
+              [
+                105.082179,
+                24.915745
+              ],
+              [
+                105.077868,
+                24.918459
+              ],
+              [
+                105.039064,
+                24.872859
+              ],
+              [
+                105.026745,
+                24.815836
+              ],
+              [
+                105.03352,
+                24.787586
+              ],
+              [
+                104.899245,
+                24.752809
+              ],
+              [
+                104.865985,
+                24.730524
+              ],
+              [
+                104.841963,
+                24.676155
+              ],
+              [
+                104.771746,
+                24.659839
+              ],
+              [
+                104.729246,
+                24.617953
+              ],
+              [
+                104.703377,
+                24.645698
+              ],
+              [
+                104.628848,
+                24.660927
+              ],
+              [
+                104.595587,
+                24.709323
+              ],
+              [
+                104.529682,
+                24.731611
+              ],
+              [
+                104.489646,
+                24.653313
+              ],
+              [
+                104.520443,
+                24.535228
+              ],
+              [
+                104.550008,
+                24.518894
+              ],
+              [
+                104.575877,
+                24.424661
+              ],
+              [
+                104.616529,
+                24.421937
+              ],
+              [
+                104.63008,
+                24.397958
+              ],
+              [
+                104.610986,
+                24.377246
+              ],
+              [
+                104.641783,
+                24.367979
+              ],
+              [
+                104.70892,
+                24.321087
+              ],
+              [
+                104.721239,
+                24.340173
+              ],
+              [
+                104.703377,
+                24.419757
+              ],
+              [
+                104.715695,
+                24.441552
+              ],
+              [
+                104.74834,
+                24.435559
+              ],
+              [
+                104.765587,
+                24.45953
+              ],
+              [
+                104.784681,
+                24.443732
+              ],
+              [
+                104.83642,
+                24.446456
+              ],
+              [
+                104.914028,
+                24.426296
+              ],
+              [
+                104.930042,
+                24.411038
+              ],
+              [
+                104.979933,
+                24.412673
+              ],
+              [
+                105.042759,
+                24.442097
+              ],
+              [
+                105.106817,
+                24.414853
+              ],
+              [
+                105.111744,
+                24.37234
+              ],
+              [
+                105.138846,
+                24.376701
+              ],
+              [
+                105.188121,
+                24.347261
+              ],
+              [
+                105.196744,
+                24.326541
+              ],
+              [
+                105.164715,
+                24.288362
+              ],
+              [
+                105.215222,
+                24.214699
+              ],
+              [
+                105.24294,
+                24.208695
+              ],
+              [
+                105.229389,
+                24.165567
+              ],
+              [
+                105.182577,
+                24.167205
+              ],
+              [
+                105.20044,
+                24.105491
+              ],
+              [
+                105.260186,
+                24.061236
+              ],
+              [
+                105.292831,
+                24.074896
+              ],
+              [
+                105.273121,
+                24.092927
+              ],
+              [
+                105.320548,
+                24.116416
+              ],
+              [
+                105.334099,
+                24.094566
+              ],
+              [
+                105.395692,
+                24.065607
+              ],
+              [
+                105.406163,
+                24.043748
+              ],
+              [
+                105.493011,
+                24.016965
+              ],
+              [
+                105.533663,
+                24.130071
+              ],
+              [
+                105.594641,
+                24.137718
+              ],
+              [
+                105.628518,
+                24.126794
+              ],
+              [
+                105.649459,
+                24.032816
+              ],
+              [
+                105.704278,
+                24.0667
+              ],
+              [
+                105.739387,
+                24.059596
+              ],
+              [
+                105.765256,
+                24.073804
+              ],
+              [
+                105.802212,
+                24.051945
+              ],
+              [
+                105.796669,
+                24.023524
+              ],
+              [
+                105.841633,
+                24.03063
+              ],
+              [
+                105.859495,
+                24.056864
+              ],
+              [
+                105.89214,
+                24.040468
+              ],
+              [
+                105.908154,
+                24.069432
+              ],
+              [
+                105.901995,
+                24.099482
+              ],
+              [
+                105.919241,
+                24.122425
+              ],
+              [
+                105.963589,
+                24.110954
+              ],
+              [
+                105.998081,
+                24.120786
+              ],
+              [
+                106.011632,
+                24.099482
+              ],
+              [
+                106.04982,
+                24.089649
+              ],
+              [
+                106.053516,
+                24.051399
+              ],
+              [
+                106.096631,
+                24.018058
+              ],
+              [
+                106.091088,
+                23.998924
+              ],
+              [
+                106.128044,
+                23.956819
+              ],
+              [
+                106.157609,
+                23.891174
+              ],
+              [
+                106.192718,
+                23.879135
+              ],
+              [
+                106.173008,
+                23.861622
+              ],
+              [
+                106.192102,
+                23.824947
+              ],
+              [
+                106.136667,
+                23.795381
+              ],
+              [
+                106.157609,
+                23.724175
+              ],
+              [
+                106.149602,
+                23.665538
+              ],
+              [
+                106.120653,
+                23.605229
+              ],
+              [
+                106.141595,
+                23.569579
+              ],
+              [
+                106.08616,
+                23.524043
+              ],
+              [
+                106.071994,
+                23.495506
+              ],
+              [
+                106.039965,
+                23.484529
+              ],
+              [
+                105.999929,
+                23.447748
+              ],
+              [
+                105.986378,
+                23.489469
+              ],
+              [
+                105.935871,
+                23.508678
+              ],
+              [
+                105.913081,
+                23.499348
+              ],
+              [
+                105.89214,
+                23.52514
+              ],
+              [
+                105.852103,
+                23.526786
+              ],
+              [
+                105.815763,
+                23.507031
+              ],
+              [
+                105.805908,
+                23.467512
+              ],
+              [
+                105.758481,
+                23.459826
+              ],
+              [
+                105.699966,
+                23.40162
+              ],
+              [
+                105.637757,
+                23.404366
+              ],
+              [
+                105.694423,
+                23.363168
+              ],
+              [
+                105.699966,
+                23.327453
+              ],
+              [
+                105.649459,
+                23.346136
+              ],
+              [
+                105.593409,
+                23.312614
+              ],
+              [
+                105.560148,
+                23.257093
+              ],
+              [
+                105.526272,
+                23.234548
+              ],
+              [
+                105.542902,
+                23.184495
+              ],
+              [
+                105.558916,
+                23.177893
+              ],
+              [
+                105.574931,
+                23.066165
+              ],
+              [
+                105.625438,
+                23.064513
+              ],
+              [
+                105.648844,
+                23.078828
+              ],
+              [
+                105.724604,
+                23.06231
+              ],
+              [
+                105.74185,
+                23.030921
+              ],
+              [
+                105.780039,
+                23.022659
+              ],
+              [
+                105.805908,
+                22.994565
+              ],
+              [
+                105.839169,
+                22.987403
+              ],
+              [
+                105.879205,
+                22.916865
+              ],
+              [
+                105.893987,
+                22.936707
+              ],
+              [
+                105.959277,
+                22.948832
+              ],
+              [
+                105.994385,
+                22.93781
+              ],
+              [
+                106.019639,
+                22.990709
+              ],
+              [
+                106.08616,
+                22.996218
+              ],
+              [
+                106.106486,
+                22.980792
+              ],
+              [
+                106.153914,
+                22.988505
+              ],
+              [
+                106.206885,
+                22.978588
+              ],
+              [
+                106.270326,
+                22.907494
+              ],
+              [
+                106.258007,
+                22.889852
+              ],
+              [
+                106.286957,
+                22.867245
+              ],
+              [
+                106.366413,
+                22.857871
+              ],
+              [
+                106.37134,
+                22.878273
+              ],
+              [
+                106.41384,
+                22.877171
+              ],
+              [
+                106.504383,
+                22.91025
+              ],
+              [
+                106.525941,
+                22.946628
+              ],
+              [
+                106.562282,
+                22.923479
+              ],
+              [
+                106.606013,
+                22.925684
+              ],
+              [
+                106.631267,
+                22.88103
+              ],
+              [
+                106.657136,
+                22.863385
+              ],
+              [
+                106.674998,
+                22.891506
+              ],
+              [
+                106.716882,
+                22.881582
+              ],
+              [
+                106.709491,
+                22.866142
+              ],
+              [
+                106.774781,
+                22.812643
+              ],
+              [
+                106.776012,
+                22.813746
+              ],
+              [
+                106.778476,
+                22.814298
+              ],
+              [
+                106.779092,
+                22.813746
+              ],
+              [
+                106.779708,
+                22.813195
+              ],
+              [
+                106.78094,
+                22.813195
+              ],
+              [
+                106.784636,
+                22.812643
+              ],
+              [
+                106.796338,
+                22.812091
+              ],
+              [
+                106.801882,
+                22.815401
+              ],
+              [
+                106.804346,
+                22.816505
+              ],
+              [
+                106.808657,
+                22.817608
+              ],
+              [
+                106.813585,
+                22.817608
+              ],
+              [
+                106.838838,
+                22.803265
+              ],
+              [
+                106.820976,
+                22.768504
+              ],
+              [
+                106.768621,
+                22.739254
+              ],
+              [
+                106.780324,
+                22.708894
+              ],
+              [
+                106.756302,
+                22.68957
+              ],
+              [
+                106.711955,
+                22.575228
+              ],
+              [
+                106.650361,
+                22.575228
+              ],
+              [
+                106.61402,
+                22.602303
+              ],
+              [
+                106.585071,
+                22.517192
+              ],
+              [
+                106.588151,
+                22.472958
+              ],
+              [
+                106.560434,
+                22.455813
+              ],
+              [
+                106.588767,
+                22.374486
+              ],
+              [
+                106.562897,
+                22.345706
+              ],
+              [
+                106.663296,
+                22.33076
+              ],
+              [
+                106.670071,
+                22.283144
+              ],
+              [
+                106.688549,
+                22.260438
+              ],
+              [
+                106.7021,
+                22.207257
+              ],
+              [
+                106.673151,
+                22.182322
+              ],
+              [
+                106.706411,
+                22.160707
+              ],
+              [
+                106.691629,
+                22.13521
+              ],
+              [
+                106.71565,
+                22.089745
+              ],
+              [
+                106.706411,
+                22.021521
+              ],
+              [
+                106.683006,
+                21.999882
+              ],
+              [
+                106.698404,
+                21.959925
+              ],
+              [
+                106.73844,
+                22.008205
+              ],
+              [
+                106.790179,
+                22.004876
+              ],
+              [
+                106.802498,
+                21.98157
+              ],
+              [
+                106.859164,
+                21.986009
+              ],
+              [
+                106.926302,
+                21.967695
+              ],
+              [
+                106.935541,
+                21.933836
+              ],
+              [
+                106.974345,
+                21.923288
+              ],
+              [
+                106.999598,
+                21.947714
+              ],
+              [
+                107.05996,
+                21.914959
+              ],
+              [
+                107.058729,
+                21.887196
+              ],
+              [
+                107.018693,
+                21.859427
+              ],
+              [
+                107.018077,
+                21.81943
+              ],
+              [
+                107.093837,
+                21.803317
+              ],
+              [
+                107.148656,
+                21.758858
+              ],
+              [
+                107.194851,
+                21.736624
+              ],
+              [
+                107.199163,
+                21.718833
+              ],
+              [
+                107.242279,
+                21.703265
+              ],
+              [
+                107.271844,
+                21.727173
+              ],
+              [
+                107.310648,
+                21.733844
+              ],
+              [
+                107.356843,
+                21.667674
+              ],
+              [
+                107.363619,
+                21.602031
+              ],
+              [
+                107.388256,
+                21.594241
+              ],
+              [
+                107.431372,
+                21.642088
+              ],
+              [
+                107.477567,
+                21.659888
+              ],
+              [
+                107.500973,
+                21.613715
+              ],
+              [
+                107.486806,
+                21.59591
+              ],
+              [
+                107.547168,
+                21.58645
+              ],
+              [
+                107.584741,
+                21.614828
+              ],
+              [
+                107.603219,
+                21.597579
+              ],
+              [
+                107.712856,
+                21.616497
+              ],
+              [
+                107.807711,
+                21.655438
+              ],
+              [
+                107.837892,
+                21.640419
+              ],
+              [
+                107.863761,
+                21.650988
+              ],
+              [
+                107.892095,
+                21.622617
+              ],
+              [
+                107.893942,
+                21.596466
+              ],
+              [
+                107.929051,
+                21.585893
+              ],
+              [
+                107.958,
+                21.534131
+              ],
+              [
+                108.034376,
+                21.545821
+              ],
+              [
+                108.108289,
+                21.508521
+              ],
+              [
+                108.193905,
+                21.519656
+              ],
+              [
+                108.156332,
+                21.55083
+              ],
+              [
+                108.205608,
+                21.597579
+              ],
+              [
+                108.241332,
+                21.599805
+              ],
+              [
+                108.249955,
+                21.561406
+              ],
+              [
+                108.210535,
+                21.505737
+              ],
+              [
+                108.230245,
+                21.491259
+              ],
+              [
+                108.330027,
+                21.540254
+              ],
+              [
+                108.397781,
+                21.533017
+              ],
+              [
+                108.492635,
+                21.554727
+              ],
+              [
+                108.591802,
+                21.677129
+              ],
+              [
+                108.626294,
+                21.67991
+              ],
+              [
+                108.658939,
+                21.643757
+              ],
+              [
+                108.678033,
+                21.659331
+              ],
+              [
+                108.735931,
+                21.628181
+              ],
+              [
+                108.734084,
+                21.626512
+              ],
+              [
+                108.745786,
+                21.602587
+              ],
+              [
+                108.801837,
+                21.626512
+              ],
+              [
+                108.83325,
+                21.610933
+              ],
+              [
+                108.881293,
+                21.627068
+              ],
+              [
+                108.937959,
+                21.589789
+              ],
+              [
+                109.093792,
+                21.579215
+              ],
+              [
+                109.09872,
+                21.571424
+              ],
+              [
+                109.110422,
+                21.568085
+              ],
+              [
+                109.138756,
+                21.567528
+              ],
+              [
+                109.142451,
+                21.511861
+              ],
+              [
+                109.074698,
+                21.489589
+              ],
+              [
+                109.039589,
+                21.457844
+              ],
+              [
+                109.046365,
+                21.424421
+              ],
+              [
+                109.095024,
+                21.419407
+              ],
+              [
+                109.138756,
+                21.388762
+              ],
+              [
+                109.186183,
+                21.390991
+              ],
+              [
+                109.245929,
+                21.425536
+              ],
+              [
+                109.41716,
+                21.438906
+              ],
+              [
+                109.484914,
+                21.453388
+              ],
+              [
+                109.529877,
+                21.437234
+              ],
+              [
+                109.540964,
+                21.466199
+              ],
+              [
+                109.576689,
+                21.493487
+              ],
+              [
+                109.604406,
+                21.523553
+              ],
+              [
+                109.612413,
+                21.556953
+              ],
+              [
+                109.654913,
+                21.493487
+              ],
+              [
+                109.704188,
+                21.462857
+              ],
+              [
+                109.785492,
+                21.45673
+              ],
+              [
+                109.788572,
+                21.490702
+              ],
+              [
+                109.754695,
+                21.556396
+              ],
+              [
+                109.742992,
+                21.616497
+              ],
+              [
+                109.778101,
+                21.670455
+              ],
+              [
+                109.786108,
+                21.637638
+              ],
+              [
+                109.839695,
+                21.636525
+              ],
+              [
+                109.888354,
+                21.652101
+              ],
+              [
+                109.888354,
+                21.652101
+              ],
+              [
+                109.916071,
+                21.668787
+              ],
+              [
+                109.940093,
+                21.769419
+              ],
+              [
+                109.94502,
+                21.84443
+              ],
+              [
+                109.999839,
+                21.881643
+              ],
+              [
+                110.050962,
+                21.857205
+              ],
+              [
+                110.101469,
+                21.86998
+              ],
+              [
+                110.12857,
+                21.902744
+              ],
+              [
+                110.196323,
+                21.899968
+              ],
+              [
+                110.212338,
+                21.886085
+              ],
+              [
+                110.212338,
+                21.886085
+              ],
+              [
+                110.224041,
+                21.882198
+              ],
+              [
+                110.224041,
+                21.882198
+              ],
+              [
+                110.283787,
+                21.892194
+              ],
+              [
+                110.290562,
+                21.917736
+              ],
+              [
+                110.337374,
+                21.887751
+              ],
+              [
+                110.391576,
+                21.89386
+              ],
+              [
+                110.378642,
+                21.939942
+              ],
+              [
+                110.378642,
+                21.939942
+              ],
+              [
+                110.374946,
+                21.967695
+              ],
+              [
+                110.374946,
+                21.967695
+              ],
+              [
+                110.352772,
+                21.97602
+              ],
+              [
+                110.359547,
+                22.015973
+              ],
+              [
+                110.35154,
+                22.097508
+              ],
+              [
+                110.364475,
+                22.125785
+              ],
+              [
+                110.326287,
+                22.152393
+              ],
+              [
+                110.34846,
+                22.195621
+              ],
+              [
+                110.378026,
+                22.164587
+              ],
+              [
+                110.414366,
+                22.208365
+              ],
+              [
+                110.456866,
+                22.189526
+              ],
+              [
+                110.505525,
+                22.14297
+              ],
+              [
+                110.55788,
+                22.196175
+              ],
+              [
+                110.602843,
+                22.18343
+              ],
+              [
+                110.598532,
+                22.162924
+              ],
+              [
+                110.629329,
+                22.149068
+              ],
+              [
+                110.678604,
+                22.172901
+              ],
+              [
+                110.646575,
+                22.220554
+              ],
+              [
+                110.687843,
+                22.249914
+              ],
+              [
+                110.725415,
+                22.29588
+              ],
+              [
+                110.759292,
+                22.274837
+              ],
+              [
+                110.787009,
+                22.28259
+              ],
+              [
+                110.749437,
+                22.329653
+              ],
+              [
+                110.74143,
+                22.361757
+              ],
+              [
+                110.711249,
+                22.369506
+              ],
+              [
+                110.712481,
+                22.440879
+              ],
+              [
+                110.688459,
+                22.477935
+              ],
+              [
+                110.74143,
+                22.464109
+              ],
+              [
+                110.740198,
+                22.498947
+              ],
+              [
+                110.762988,
+                22.518298
+              ],
+              [
+                110.749437,
+                22.556991
+              ],
+              [
+                110.778386,
+                22.585174
+              ],
+              [
+                110.812263,
+                22.576333
+              ],
+              [
+                110.897878,
+                22.591805
+              ],
+              [
+                110.896031,
+                22.613352
+              ],
+              [
+                110.950233,
+                22.61059
+              ],
+              [
+                110.958856,
+                22.636553
+              ],
+              [
+                110.997045,
+                22.631582
+              ],
+              [
+                111.055559,
+                22.648705
+              ],
+              [
+                111.089435,
+                22.695643
+              ],
+              [
+                111.058023,
+                22.729871
+              ],
+              [
+                111.118385,
+                22.744773
+              ],
+              [
+                111.185522,
+                22.735942
+              ],
+              [
+                111.218167,
+                22.748085
+              ],
+              [
+                111.358601,
+                22.889301
+              ],
+              [
+                111.374615,
+                22.938361
+              ],
+              [
+                111.362913,
+                22.967568
+              ],
+              [
+                111.403565,
+                22.99126
+              ],
+              [
+                111.389398,
+                23.005583
+              ],
+              [
+                111.433746,
+                23.036428
+              ],
+              [
+                111.43313,
+                23.073322
+              ],
+              [
+                111.402333,
+                23.066165
+              ],
+              [
+                111.377695,
+                23.082132
+              ],
+              [
+                111.365992,
+                23.14488
+              ],
+              [
+                111.38447,
+                23.16744
+              ],
+              [
+                111.388782,
+                23.210349
+              ],
+              [
+                111.36476,
+                23.240047
+              ],
+              [
+                111.353058,
+                23.284582
+              ],
+              [
+                111.376463,
+                23.30437
+              ],
+              [
+                111.363528,
+                23.340641
+              ],
+              [
+                111.389398,
+                23.375804
+              ],
+              [
+                111.383239,
+                23.399423
+              ],
+              [
+                111.399869,
+                23.469159
+              ],
+              [
+                111.428818,
+                23.466414
+              ],
+              [
+                111.479941,
+                23.532822
+              ],
+              [
+                111.487332,
+                23.626615
+              ],
+              [
+                111.555702,
+                23.64087
+              ],
+              [
+                111.615448,
+                23.639225
+              ],
+              [
+                111.614832,
+                23.65896
+              ],
+              [
+                111.666571,
+                23.718696
+              ],
+              [
+                111.621607,
+                23.725819
+              ],
+              [
+                111.627766,
+                23.78881
+              ],
+              [
+                111.654868,
+                23.833159
+              ],
+              [
+                111.683201,
+                23.822758
+              ],
+              [
+                111.683201,
+                23.822758
+              ],
+              [
+                111.722621,
+                23.823305
+              ],
+              [
+                111.8107,
+                23.80688
+              ],
+              [
+                111.824867,
+                23.832612
+              ],
+              [
+                111.812548,
+                23.887343
+              ],
+              [
+                111.845809,
+                23.904305
+              ],
+              [
+                111.854432,
+                23.947521
+              ],
+              [
+                111.911714,
+                23.943693
+              ],
+              [
+                111.940664,
+                23.987989
+              ],
+              [
+                111.92157,
+                24.012045
+              ],
+              [
+                111.878454,
+                24.109862
+              ],
+              [
+                111.886461,
+                24.163929
+              ],
+              [
+                111.871062,
+                24.176487
+              ],
+              [
+                111.877222,
+                24.227252
+              ],
+              [
+                111.912946,
+                24.221795
+              ],
+              [
+                111.958526,
+                24.263813
+              ],
+              [
+                111.986243,
+                24.25672
+              ],
+              [
+                111.990555,
+                24.279634
+              ],
+              [
+                112.026279,
+                24.294908
+              ],
+              [
+                112.05954,
+                24.339628
+              ],
+              [
+                112.057692,
+                24.387057
+              ],
+              [
+                112.025047,
+                24.438828
+              ],
+              [
+                111.985011,
+                24.467701
+              ],
+              [
+                112.009649,
+                24.503103
+              ],
+              [
+                112.007185,
+                24.534684
+              ],
+              [
+                111.972077,
+                24.578775
+              ],
+              [
+                111.936968,
+                24.595645
+              ],
+              [
+                111.927729,
+                24.629378
+              ],
+              [
+                111.953598,
+                24.64733
+              ],
+              [
+                111.939432,
+                24.686487
+              ],
+              [
+                111.961606,
+                24.721283
+              ],
+              [
+                112.024431,
+                24.740308
+              ],
+              [
+                111.951135,
+                24.769655
+              ],
+              [
+                111.929577,
+                24.75607
+              ],
+              [
+                111.875374,
+                24.756613
+              ],
+              [
+                111.868599,
+                24.771829
+              ],
+              [
+                111.814396,
+                24.770199
+              ],
+              [
+                111.783599,
+                24.785957
+              ],
+              [
+                111.708455,
+                24.788673
+              ],
+              [
+                111.666571,
+                24.760961
+              ],
+              [
+                111.637621,
+                24.715303
+              ],
+              [
+                111.641933,
+                24.684856
+              ],
+              [
+                111.588962,
+                24.690837
+              ],
+              [
+                111.570484,
+                24.64461
+              ],
+              [
+                111.526752,
+                24.637538
+              ],
+              [
+                111.499035,
+                24.667997
+              ],
+              [
+                111.451608,
+                24.665822
+              ],
+              [
+                111.431282,
+                24.687574
+              ],
+              [
+                111.461463,
+                24.728894
+              ],
+              [
+                111.479325,
+                24.797366
+              ],
+              [
+                111.449144,
+                24.857113
+              ],
+              [
+                111.447296,
+                24.892947
+              ],
+              [
+                111.470086,
+                24.92877
+              ],
+              [
+                111.434977,
+                24.951562
+              ],
+              [
+                111.43313,
+                24.979774
+              ],
+              [
+                111.460231,
+                24.992793
+              ],
+              [
+                111.467622,
+                25.02208
+              ],
+              [
+                111.416499,
+                25.047566
+              ],
+              [
+                111.435593,
+                25.093642
+              ],
+              [
+                111.375231,
+                25.128324
+              ],
+              [
+                111.36784,
+                25.108817
+              ],
+              [
+                111.321645,
+                25.105023
+              ],
+              [
+                111.274833,
+                25.151078
+              ],
+              [
+                111.221862,
+                25.106649
+              ],
+              [
+                111.200921,
+                25.074672
+              ],
+              [
+                111.139943,
+                25.042144
+              ],
+              [
+                111.101754,
+                25.035095
+              ],
+              [
+                111.100522,
+                24.945593
+              ],
+              [
+                111.009363,
+                24.921172
+              ],
+              [
+                110.968711,
+                24.975434
+              ],
+              [
+                110.951465,
+                25.04377
+              ],
+              [
+                110.98411,
+                25.101772
+              ],
+              [
+                110.998892,
+                25.161371
+              ],
+              [
+                111.112841,
+                25.21715
+              ],
+              [
+                111.103602,
+                25.285351
+              ],
+              [
+                111.138711,
+                25.303748
+              ],
+              [
+                111.184906,
+                25.367034
+              ],
+              [
+                111.210776,
+                25.363248
+              ],
+              [
+                111.279145,
+                25.42326
+              ],
+              [
+                111.32842,
+                25.521592
+              ],
+              [
+                111.324724,
+                25.564249
+              ],
+              [
+                111.343202,
+                25.602574
+              ],
+              [
+                111.309942,
+                25.645203
+              ],
+              [
+                111.30871,
+                25.720171
+              ],
+              [
+                111.399869,
+                25.744431
+              ],
+              [
+                111.442369,
+                25.77192
+              ],
+              [
+                111.43313,
+                25.84627
+              ],
+              [
+                111.4861,
+                25.859196
+              ],
+              [
+                111.460231,
+                25.885042
+              ],
+              [
+                111.383239,
+                25.881812
+              ],
+              [
+                111.376463,
+                25.906039
+              ],
+              [
+                111.346282,
+                25.906577
+              ],
+              [
+                111.297007,
+                25.874274
+              ],
+              [
+                111.29208,
+                25.854349
+              ],
+              [
+                111.251428,
+                25.864581
+              ],
+              [
+                111.230486,
+                25.916267
+              ],
+              [
+                111.189834,
+                25.953402
+              ],
+              [
+                111.235413,
+                26.048071
+              ],
+              [
+                111.267442,
+                26.058824
+              ],
+              [
+                111.244652,
+                26.078177
+              ],
+              [
+                111.26621,
+                26.095914
+              ],
+              [
+                111.258203,
+                26.151796
+              ],
+              [
+                111.274833,
+                26.183486
+              ],
+              [
+                111.271754,
+                26.217316
+              ],
+              [
+                111.293311,
+                26.222148
+              ],
+              [
+                111.277913,
+                26.272066
+              ],
+              [
+                111.228022,
+                26.261333
+              ],
+              [
+                111.204616,
+                26.276359
+              ],
+              [
+                111.208928,
+                26.30426
+              ],
+              [
+                111.090667,
+                26.308016
+              ],
+              [
+                111.008132,
+                26.336982
+              ],
+              [
+                111.008747,
+                26.35897
+              ],
+              [
+                110.974255,
+                26.385778
+              ],
+              [
+                110.94469,
+                26.373447
+              ],
+              [
+                110.944074,
+                26.326791
+              ],
+              [
+                110.926212,
+                26.320354
+              ],
+              [
+                110.939762,
+                26.286554
+              ],
+              [
+                110.836284,
+                26.255966
+              ],
+              [
+                110.759292,
+                26.248451
+              ],
+              [
+                110.73527,
+                26.270993
+              ],
+              [
+                110.742046,
+                26.313917
+              ],
+              [
+                110.721104,
+                26.294066
+              ],
+              [
+                110.673676,
+                26.317135
+              ],
+              [
+                110.643495,
+                26.308552
+              ],
+              [
+                110.612083,
+                26.333764
+              ],
+              [
+                110.584365,
+                26.296749
+              ],
+              [
+                110.552952,
+                26.283335
+              ],
+              [
+                110.546793,
+                26.233421
+              ],
+              [
+                110.495054,
+                26.166299
+              ],
+              [
+                110.477808,
+                26.179727
+              ],
+              [
+                110.437772,
+                26.153945
+              ],
+              [
+                110.373098,
+                26.088927
+              ],
+              [
+                110.325671,
+                25.975462
+              ],
+              [
+                110.257301,
+                25.961473
+              ],
+              [
+                110.24991,
+                26.010965
+              ],
+              [
+                110.181541,
+                26.060437
+              ],
+              [
+                110.168606,
+                26.028713
+              ],
+              [
+                110.100853,
+                26.020108
+              ],
+              [
+                110.065128,
+                26.050221
+              ],
+              [
+                110.100853,
+                26.132455
+              ],
+              [
+                110.099005,
+                26.168985
+              ],
+              [
+                110.03002,
+                26.166299
+              ],
+              [
+                109.970274,
+                26.195301
+              ],
+              [
+                109.904368,
+                26.135679
+              ],
+              [
+                109.898825,
+                26.095377
+              ],
+              [
+                109.864332,
+                26.027637
+              ],
+              [
+                109.814441,
+                26.041081
+              ],
+              [
+                109.782412,
+                25.996981
+              ],
+              [
+                109.806434,
+                25.973848
+              ],
+              [
+                109.826144,
+                25.911422
+              ],
+              [
+                109.811361,
+                25.877504
+              ],
+              [
+                109.779333,
+                25.866196
+              ],
+              [
+                109.768246,
+                25.890427
+              ],
+              [
+                109.685094,
+                25.880197
+              ],
+              [
+                109.67955,
+                25.921649
+              ],
+              [
+                109.693717,
+                25.959321
+              ],
+              [
+                109.710963,
+                25.954478
+              ],
+              [
+                109.730057,
+                25.989988
+              ],
+              [
+                109.649369,
+                26.016882
+              ],
+              [
+                109.635203,
+                26.047533
+              ],
+              [
+                109.588391,
+                26.019571
+              ],
+              [
+                109.560058,
+                26.021184
+              ],
+              [
+                109.513247,
+                25.998056
+              ],
+              [
+                109.48245,
+                26.029788
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                105.096346,
+                24.928228
+              ],
+              [
+                105.09573,
+                24.92877
+              ],
+              [
+                105.077868,
+                24.918459
+              ],
+              [
+                105.082179,
+                24.915745
+              ],
+              [
+                105.096346,
+                24.928228
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.088249,
+                21.014934
+              ],
+              [
+                109.11227,
+                21.02499
+              ],
+              [
+                109.117814,
+                21.017727
+              ],
+              [
+                109.144299,
+                21.041189
+              ],
+              [
+                109.138756,
+                21.067439
+              ],
+              [
+                109.09256,
+                21.057386
+              ],
+              [
+                109.088865,
+                21.031134
+              ],
+              [
+                109.088249,
+                21.014934
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 460000,
+        "name": "娴峰崡鐪�",
+        "center": [
+          110.33119,
+          20.031971
+        ],
+        "centroid": [
+          109.754859,
+          19.189767
+        ],
+        "childrenNum": 19,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 20,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                110.106396,
+                20.026812
+              ],
+              [
+                110.042339,
+                19.991384
+              ],
+              [
+                109.997375,
+                19.980136
+              ],
+              [
+                109.965346,
+                19.993634
+              ],
+              [
+                109.898825,
+                19.994196
+              ],
+              [
+                109.855093,
+                19.984073
+              ],
+              [
+                109.814441,
+                19.993072
+              ],
+              [
+                109.76147,
+                19.981261
+              ],
+              [
+                109.712195,
+                20.017253
+              ],
+              [
+                109.657993,
+                20.01163
+              ],
+              [
+                109.585312,
+                19.98801
+              ],
+              [
+                109.526797,
+                19.943573
+              ],
+              [
+                109.498464,
+                19.873236
+              ],
+              [
+                109.411001,
+                19.895184
+              ],
+              [
+                109.349407,
+                19.898561
+              ],
+              [
+                109.300748,
+                19.917693
+              ],
+              [
+                109.25948,
+                19.898561
+              ],
+              [
+                109.255784,
+                19.867045
+              ],
+              [
+                109.231147,
+                19.863105
+              ],
+              [
+                109.159082,
+                19.79048
+              ],
+              [
+                109.169553,
+                19.736411
+              ],
+              [
+                109.147379,
+                19.704863
+              ],
+              [
+                109.093792,
+                19.68965
+              ],
+              [
+                109.048829,
+                19.619764
+              ],
+              [
+                108.993394,
+                19.587065
+              ],
+              [
+                108.92872,
+                19.524468
+              ],
+              [
+                108.855424,
+                19.469182
+              ],
+              [
+                108.806148,
+                19.450561
+              ],
+              [
+                108.765496,
+                19.400894
+              ],
+              [
+                108.694047,
+                19.387346
+              ],
+              [
+                108.644772,
+                19.349518
+              ],
+              [
+                108.609048,
+                19.276661
+              ],
+              [
+                108.591186,
+                19.141592
+              ],
+              [
+                108.598577,
+                19.055633
+              ],
+              [
+                108.630606,
+                19.003017
+              ],
+              [
+                108.637997,
+                18.924346
+              ],
+              [
+                108.595497,
+                18.872256
+              ],
+              [
+                108.593033,
+                18.809386
+              ],
+              [
+                108.65278,
+                18.740258
+              ],
+              [
+                108.663866,
+                18.67337
+              ],
+              [
+                108.641077,
+                18.565614
+              ],
+              [
+                108.644772,
+                18.486738
+              ],
+              [
+                108.68912,
+                18.447571
+              ],
+              [
+                108.776583,
+                18.441894
+              ],
+              [
+                108.881293,
+                18.416344
+              ],
+              [
+                108.905315,
+                18.389087
+              ],
+              [
+                108.944735,
+                18.314107
+              ],
+              [
+                109.006329,
+                18.323198
+              ],
+              [
+                109.108575,
+                18.323766
+              ],
+              [
+                109.138756,
+                18.268081
+              ],
+              [
+                109.17448,
+                18.260125
+              ],
+              [
+                109.287813,
+                18.264671
+              ],
+              [
+                109.355566,
+                18.215221
+              ],
+              [
+                109.441182,
+                18.199303
+              ],
+              [
+                109.467051,
+                18.173718
+              ],
+              [
+                109.527413,
+                18.169169
+              ],
+              [
+                109.584696,
+                18.143579
+              ],
+              [
+                109.661688,
+                18.175424
+              ],
+              [
+                109.726362,
+                18.177698
+              ],
+              [
+                109.749767,
+                18.193618
+              ],
+              [
+                109.785492,
+                18.339672
+              ],
+              [
+                109.919767,
+                18.375457
+              ],
+              [
+                110.022629,
+                18.360121
+              ],
+              [
+                110.070672,
+                18.376025
+              ],
+              [
+                110.090382,
+                18.399309
+              ],
+              [
+                110.116867,
+                18.506602
+              ],
+              [
+                110.214186,
+                18.578662
+              ],
+              [
+                110.246215,
+                18.609859
+              ],
+              [
+                110.329366,
+                18.642185
+              ],
+              [
+                110.367555,
+                18.631977
+              ],
+              [
+                110.499366,
+                18.651824
+              ],
+              [
+                110.499366,
+                18.751592
+              ],
+              [
+                110.578206,
+                18.784458
+              ],
+              [
+                110.590525,
+                18.838841
+              ],
+              [
+                110.585597,
+                18.88075
+              ],
+              [
+                110.619474,
+                19.152334
+              ],
+              [
+                110.676756,
+                19.286264
+              ],
+              [
+                110.706321,
+                19.320153
+              ],
+              [
+                110.729727,
+                19.378878
+              ],
+              [
+                110.787009,
+                19.399765
+              ],
+              [
+                110.844292,
+                19.449996
+              ],
+              [
+                110.888023,
+                19.518827
+              ],
+              [
+                110.920668,
+                19.552668
+              ],
+              [
+                111.008747,
+                19.60398
+              ],
+              [
+                111.061718,
+                19.612436
+              ],
+              [
+                111.071573,
+                19.628784
+              ],
+              [
+                111.043856,
+                19.763448
+              ],
+              [
+                111.013675,
+                19.850159
+              ],
+              [
+                110.966248,
+                20.018377
+              ],
+              [
+                110.940994,
+                20.028499
+              ],
+              [
+                110.871393,
+                20.01163
+              ],
+              [
+                110.808567,
+                20.035808
+              ],
+              [
+                110.778386,
+                20.068415
+              ],
+              [
+                110.744509,
+                20.074036
+              ],
+              [
+                110.717408,
+                20.148778
+              ],
+              [
+                110.687843,
+                20.163947
+              ],
+              [
+                110.655814,
+                20.134169
+              ],
+              [
+                110.562191,
+                20.110006
+              ],
+              [
+                110.526467,
+                20.07516
+              ],
+              [
+                110.495054,
+                20.077408
+              ],
+              [
+                110.387265,
+                20.113378
+              ],
+              [
+                110.318279,
+                20.108882
+              ],
+              [
+                110.28933,
+                20.056047
+              ],
+              [
+                110.243135,
+                20.077408
+              ],
+              [
+                110.144585,
+                20.074598
+              ],
+              [
+                110.106396,
+                20.026812
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.208597,
+                3.876129
+              ],
+              [
+                112.241858,
+                3.845677
+              ],
+              [
+                112.280046,
+                3.86777
+              ],
+              [
+                112.260336,
+                3.917925
+              ],
+              [
+                112.219068,
+                3.908969
+              ],
+              [
+                112.208597,
+                3.876129
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.266165,
+                8.125929
+              ],
+              [
+                113.311129,
+                8.177469
+              ],
+              [
+                113.343157,
+                8.193463
+              ],
+              [
+                113.288955,
+                8.119412
+              ],
+              [
+                113.349933,
+                8.172137
+              ],
+              [
+                113.386273,
+                8.238479
+              ],
+              [
+                113.386273,
+                8.289412
+              ],
+              [
+                113.354244,
+                8.304217
+              ],
+              [
+                113.353628,
+                8.237887
+              ],
+              [
+                113.293882,
+                8.176284
+              ],
+              [
+                113.266165,
+                8.125929
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.99733,
+                3.848065
+              ],
+              [
+                112.015192,
+                3.823583
+              ],
+              [
+                112.064467,
+                3.830152
+              ],
+              [
+                112.073707,
+                3.865979
+              ],
+              [
+                112.03367,
+                3.892251
+              ],
+              [
+                111.99733,
+                3.848065
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.463311,
+                17.077491
+              ],
+              [
+                111.536607,
+                17.104949
+              ],
+              [
+                111.4861,
+                17.058039
+              ],
+              [
+                111.559397,
+                17.087788
+              ],
+              [
+                111.542151,
+                17.11982
+              ],
+              [
+                111.452224,
+                17.092936
+              ],
+              [
+                111.463311,
+                17.077491
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.708319,
+                15.182712
+              ],
+              [
+                117.712631,
+                15.118592
+              ],
+              [
+                117.726798,
+                15.105303
+              ],
+              [
+                117.827812,
+                15.111659
+              ],
+              [
+                117.72495,
+                15.131302
+              ],
+              [
+                117.720638,
+                15.195418
+              ],
+              [
+                117.74466,
+                15.217941
+              ],
+              [
+                117.784696,
+                15.16885
+              ],
+              [
+                117.838899,
+                15.15903
+              ],
+              [
+                117.782848,
+                15.187333
+              ],
+              [
+                117.748355,
+                15.230068
+              ],
+              [
+                117.715095,
+                15.222561
+              ],
+              [
+                117.708319,
+                15.182712
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.241858,
+                3.942404
+              ],
+              [
+                112.292365,
+                3.946583
+              ],
+              [
+                112.288053,
+                3.97345
+              ],
+              [
+                112.254177,
+                3.97942
+              ],
+              [
+                112.241858,
+                3.942404
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.734324,
+                16.19732
+              ],
+              [
+                111.779903,
+                16.19732
+              ],
+              [
+                111.81686,
+                16.224329
+              ],
+              [
+                111.813164,
+                16.261676
+              ],
+              [
+                111.782367,
+                16.273741
+              ],
+              [
+                111.716462,
+                16.249036
+              ],
+              [
+                111.789758,
+                16.250186
+              ],
+              [
+                111.790374,
+                16.220307
+              ],
+              [
+                111.734324,
+                16.19732
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.649324,
+                16.255931
+              ],
+              [
+                111.577875,
+                16.208239
+              ],
+              [
+                111.56802,
+                16.162834
+              ],
+              [
+                111.611136,
+                16.156511
+              ],
+              [
+                111.690592,
+                16.211112
+              ],
+              [
+                111.606825,
+                16.177779
+              ],
+              [
+                111.598817,
+                16.198469
+              ],
+              [
+                111.681353,
+                16.262251
+              ],
+              [
+                111.649324,
+                16.255931
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.896887,
+                7.607204
+              ],
+              [
+                113.919677,
+                7.566865
+              ],
+              [
+                113.98743,
+                7.536014
+              ],
+              [
+                114.058879,
+                7.537794
+              ],
+              [
+                114.157429,
+                7.561525
+              ],
+              [
+                114.289856,
+                7.617288
+              ],
+              [
+                114.368696,
+                7.638642
+              ],
+              [
+                114.407501,
+                7.683126
+              ],
+              [
+                114.419819,
+                7.765557
+              ],
+              [
+                114.464167,
+                7.814771
+              ],
+              [
+                114.540543,
+                7.862201
+              ],
+              [
+                114.555326,
+                7.891249
+              ],
+              [
+                114.540543,
+                7.945783
+              ],
+              [
+                114.511594,
+                7.966527
+              ],
+              [
+                114.47279,
+                7.968898
+              ],
+              [
+                114.414892,
+                7.952895
+              ],
+              [
+                114.268298,
+                7.870501
+              ],
+              [
+                114.211632,
+                7.786904
+              ],
+              [
+                114.095219,
+                7.721082
+              ],
+              [
+                114.029314,
+                7.670078
+              ],
+              [
+                113.921524,
+                7.639235
+              ],
+              [
+                113.896887,
+                7.607204
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.976959,
+                8.872888
+              ],
+              [
+                114.013299,
+                8.836817
+              ],
+              [
+                114.035473,
+                8.783591
+              ],
+              [
+                114.060111,
+                8.816119
+              ],
+              [
+                114.041017,
+                8.843913
+              ],
+              [
+                113.989894,
+                8.878801
+              ],
+              [
+                113.976959,
+                8.872888
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.956017,
+                8.840365
+              ],
+              [
+                113.975111,
+                8.793054
+              ],
+              [
+                114.012068,
+                8.798376
+              ],
+              [
+                113.977575,
+                8.841548
+              ],
+              [
+                113.956017,
+                8.840365
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.97454,
+                16.323715
+              ],
+              [
+                112.002258,
+                16.306484
+              ],
+              [
+                112.07617,
+                16.323715
+              ],
+              [
+                112.074938,
+                16.349558
+              ],
+              [
+                112.047221,
+                16.360469
+              ],
+              [
+                112.002874,
+                16.350707
+              ],
+              [
+                111.97454,
+                16.323715
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.739251,
+                16.452898
+              ],
+              [
+                111.766969,
+                16.470116
+              ],
+              [
+                111.786679,
+                16.520039
+              ],
+              [
+                111.759577,
+                16.545857
+              ],
+              [
+                111.765737,
+                16.495366
+              ],
+              [
+                111.739251,
+                16.452898
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.216604,
+                8.866383
+              ],
+              [
+                112.206133,
+                8.88767
+              ],
+              [
+                112.180264,
+                8.862244
+              ],
+              [
+                112.216604,
+                8.866383
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.792177,
+                7.373422
+              ],
+              [
+                113.828518,
+                7.362145
+              ],
+              [
+                113.829134,
+                7.383511
+              ],
+              [
+                113.792177,
+                7.373422
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.194386,
+                8.764664
+              ],
+              [
+                114.201161,
+                8.727991
+              ],
+              [
+                114.248588,
+                8.724442
+              ],
+              [
+                114.222103,
+                8.784773
+              ],
+              [
+                114.194386,
+                8.764664
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.232619,
+                16.996239
+              ],
+              [
+                112.207981,
+                16.987081
+              ],
+              [
+                112.222764,
+                16.960751
+              ],
+              [
+                112.292981,
+                16.96762
+              ],
+              [
+                112.266496,
+                16.993949
+              ],
+              [
+                112.232619,
+                16.996239
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.689601,
+                10.345648
+              ],
+              [
+                114.702536,
+                10.312677
+              ],
+              [
+                114.725941,
+                10.319154
+              ],
+              [
+                114.747499,
+                10.37214
+              ],
+              [
+                114.717318,
+                10.380381
+              ],
+              [
+                114.689601,
+                10.345648
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.837712,
+                9.709775
+              ],
+              [
+                115.861117,
+                9.694438
+              ],
+              [
+                115.867277,
+                9.650191
+              ],
+              [
+                115.901153,
+                9.67084
+              ],
+              [
+                115.925791,
+                9.781734
+              ],
+              [
+                115.901153,
+                9.795888
+              ],
+              [
+                115.870972,
+                9.778785
+              ],
+              [
+                115.837712,
+                9.709775
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.617536,
+                9.965688
+              ],
+              [
+                114.642173,
+                9.917351
+              ],
+              [
+                114.672355,
+                9.927963
+              ],
+              [
+                114.685905,
+                9.979245
+              ],
+              [
+                114.617536,
+                9.965688
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.769387,
+                7.636862
+              ],
+              [
+                113.773699,
+                7.601865
+              ],
+              [
+                113.814967,
+                7.603051
+              ],
+              [
+                113.831597,
+                7.644573
+              ],
+              [
+                113.769387,
+                7.636862
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.463972,
+                7.344339
+              ],
+              [
+                109.463972,
+                7.315254
+              ],
+              [
+                109.513247,
+                7.320002
+              ],
+              [
+                109.571761,
+                7.373422
+              ],
+              [
+                109.654297,
+                7.479648
+              ],
+              [
+                109.709115,
+                7.511095
+              ],
+              [
+                109.791651,
+                7.524742
+              ],
+              [
+                109.938861,
+                7.504569
+              ],
+              [
+                109.948716,
+                7.522962
+              ],
+              [
+                109.904984,
+                7.55144
+              ],
+              [
+                109.816289,
+                7.572797
+              ],
+              [
+                109.72205,
+                7.575763
+              ],
+              [
+                109.653065,
+                7.559745
+              ],
+              [
+                109.536037,
+                7.448792
+              ],
+              [
+                109.463972,
+                7.344339
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.273181,
+                8.879392
+              ],
+              [
+                116.294123,
+                8.858105
+              ],
+              [
+                116.332311,
+                8.901269
+              ],
+              [
+                116.305826,
+                8.917233
+              ],
+              [
+                116.273181,
+                8.879392
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.476531,
+                16.001247
+              ],
+              [
+                112.570154,
+                16.011027
+              ],
+              [
+                112.612037,
+                16.039212
+              ],
+              [
+                112.588016,
+                16.070844
+              ],
+              [
+                112.462364,
+                16.043813
+              ],
+              [
+                112.448814,
+                16.005274
+              ],
+              [
+                112.476531,
+                16.001247
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.537509,
+                8.846278
+              ],
+              [
+                112.57077,
+                8.815527
+              ],
+              [
+                112.639755,
+                8.818484
+              ],
+              [
+                112.598487,
+                8.859288
+              ],
+              [
+                112.537509,
+                8.846278
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.469095,
+                10.836261
+              ],
+              [
+                114.475254,
+                10.814512
+              ],
+              [
+                114.513442,
+                10.848605
+              ],
+              [
+                114.565181,
+                10.836261
+              ],
+              [
+                114.593514,
+                10.856245
+              ],
+              [
+                114.587355,
+                10.909138
+              ],
+              [
+                114.55471,
+                10.900911
+              ],
+              [
+                114.469095,
+                10.836261
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.409393,
+                16.294996
+              ],
+              [
+                112.383524,
+                16.265698
+              ],
+              [
+                112.411241,
+                16.2634
+              ],
+              [
+                112.475915,
+                16.288677
+              ],
+              [
+                112.531349,
+                16.285805
+              ],
+              [
+                112.536893,
+                16.312228
+              ],
+              [
+                112.509176,
+                16.317397
+              ],
+              [
+                112.409393,
+                16.294996
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.48876,
+                10.395686
+              ],
+              [
+                116.461658,
+                10.34918
+              ],
+              [
+                116.467202,
+                10.309144
+              ],
+              [
+                116.511549,
+                10.297957
+              ],
+              [
+                116.566368,
+                10.304434
+              ],
+              [
+                116.644592,
+                10.335051
+              ],
+              [
+                116.637817,
+                10.365076
+              ],
+              [
+                116.514629,
+                10.34918
+              ],
+              [
+                116.542346,
+                10.41982
+              ],
+              [
+                116.526332,
+                10.426883
+              ],
+              [
+                116.48876,
+                10.395686
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.349031,
+                16.912088
+              ],
+              [
+                112.360734,
+                16.925257
+              ],
+              [
+                112.334249,
+                16.962469
+              ],
+              [
+                112.30222,
+                16.963041
+              ],
+              [
+                112.349031,
+                16.912088
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.500267,
+                16.45175
+              ],
+              [
+                111.49534,
+                16.4374
+              ],
+              [
+                111.545847,
+                16.43453
+              ],
+              [
+                111.538455,
+                16.461507
+              ],
+              [
+                111.500267,
+                16.45175
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.500177,
+                9.897897
+              ],
+              [
+                115.54822,
+                9.869007
+              ],
+              [
+                115.585177,
+                9.896128
+              ],
+              [
+                115.581481,
+                9.917351
+              ],
+              [
+                115.518039,
+                9.933857
+              ],
+              [
+                115.500177,
+                9.897897
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.669891,
+                8.210048
+              ],
+              [
+                114.691449,
+                8.18517
+              ],
+              [
+                114.74134,
+                8.189316
+              ],
+              [
+                114.726557,
+                8.21064
+              ],
+              [
+                114.669891,
+                8.210048
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.507899,
+                8.120004
+              ],
+              [
+                114.530073,
+                8.103415
+              ],
+              [
+                114.595978,
+                8.120596
+              ],
+              [
+                114.624311,
+                8.149626
+              ],
+              [
+                114.595978,
+                8.15792
+              ],
+              [
+                114.507899,
+                8.120004
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.16757,
+                8.386523
+              ],
+              [
+                115.18112,
+                8.345668
+              ],
+              [
+                115.235939,
+                8.321982
+              ],
+              [
+                115.285214,
+                8.314876
+              ],
+              [
+                115.315395,
+                8.356326
+              ],
+              [
+                115.299381,
+                8.370537
+              ],
+              [
+                115.202678,
+                8.395403
+              ],
+              [
+                115.16757,
+                8.386523
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.895039,
+                8.00505
+              ],
+              [
+                113.904894,
+                7.963564
+              ],
+              [
+                113.9708,
+                7.944597
+              ],
+              [
+                113.969568,
+                7.974825
+              ],
+              [
+                113.940003,
+                8.018088
+              ],
+              [
+                113.895039,
+                8.00505
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.436119,
+                9.393447
+              ],
+              [
+                115.450286,
+                9.345028
+              ],
+              [
+                115.469996,
+                9.3592
+              ],
+              [
+                115.456445,
+                9.417064
+              ],
+              [
+                115.436119,
+                9.393447
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.457347,
+                9.174326
+              ],
+              [
+                116.477057,
+                9.137103
+              ],
+              [
+                116.500462,
+                9.164282
+              ],
+              [
+                116.457347,
+                9.174326
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.638192,
+                8.976942
+              ],
+              [
+                113.654823,
+                8.962163
+              ],
+              [
+                113.730583,
+                9.004133
+              ],
+              [
+                113.719496,
+                9.020092
+              ],
+              [
+                113.644968,
+                8.989355
+              ],
+              [
+                113.638192,
+                8.976942
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.696992,
+                11.004322
+              ],
+              [
+                114.710543,
+                11.001972
+              ],
+              [
+                114.793079,
+                11.07657
+              ],
+              [
+                114.799854,
+                11.10476
+              ],
+              [
+                114.766593,
+                11.110045
+              ],
+              [
+                114.710543,
+                11.039567
+              ],
+              [
+                114.696992,
+                11.004322
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.62,
+                11.432264
+              ],
+              [
+                114.652644,
+                11.436957
+              ],
+              [
+                114.661884,
+                11.522584
+              ],
+              [
+                114.621232,
+                11.518479
+              ],
+              [
+                114.62,
+                11.432264
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.910723,
+                10.863298
+              ],
+              [
+                114.931049,
+                10.841551
+              ],
+              [
+                114.959998,
+                10.902087
+              ],
+              [
+                114.934129,
+                10.902674
+              ],
+              [
+                114.910723,
+                10.863298
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.572948,
+                16.470116
+              ],
+              [
+                111.578491,
+                16.447158
+              ],
+              [
+                111.614216,
+                16.44027
+              ],
+              [
+                111.592658,
+                16.490775
+              ],
+              [
+                111.572948,
+                16.470116
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.939387,
+                8.875253
+              ],
+              [
+                113.912285,
+                8.888853
+              ],
+              [
+                113.893807,
+                8.862836
+              ],
+              [
+                113.916597,
+                8.837999
+              ],
+              [
+                113.939387,
+                8.875253
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.936397,
+                7.848566
+              ],
+              [
+                109.936397,
+                7.823665
+              ],
+              [
+                109.988136,
+                7.8124
+              ],
+              [
+                110.050346,
+                7.846194
+              ],
+              [
+                110.082991,
+                7.896584
+              ],
+              [
+                110.078063,
+                7.949339
+              ],
+              [
+                110.0331,
+                7.944597
+              ],
+              [
+                109.953027,
+                7.888878
+              ],
+              [
+                109.936397,
+                7.848566
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.727128,
+                11.501473
+              ],
+              [
+                116.765316,
+                11.430504
+              ],
+              [
+                116.772092,
+                11.445755
+              ],
+              [
+                116.738215,
+                11.514961
+              ],
+              [
+                116.727128,
+                11.501473
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.690592,
+                16.587731
+              ],
+              [
+                111.724469,
+                16.560198
+              ],
+              [
+                111.717078,
+                16.59404
+              ],
+              [
+                111.690592,
+                16.587731
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.507328,
+                16.466098
+              ],
+              [
+                112.586784,
+                16.525777
+              ],
+              [
+                112.575081,
+                16.537251
+              ],
+              [
+                112.499321,
+                16.493645
+              ],
+              [
+                112.507328,
+                16.466098
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.761425,
+                16.061642
+              ],
+              [
+                111.791606,
+                16.028859
+              ],
+              [
+                111.828563,
+                16.049565
+              ],
+              [
+                111.829795,
+                16.070844
+              ],
+              [
+                111.761425,
+                16.061642
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.845764,
+                10.018733
+              ],
+              [
+                113.865474,
+                10.00341
+              ],
+              [
+                113.872249,
+                10.123029
+              ],
+              [
+                113.856851,
+                10.12185
+              ],
+              [
+                113.845764,
+                10.018733
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.791847,
+                8.160882
+              ],
+              [
+                114.777064,
+                8.114079
+              ],
+              [
+                114.812173,
+                8.110524
+              ],
+              [
+                114.818332,
+                8.141332
+              ],
+              [
+                114.791847,
+                8.160882
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.557129,
+                9.745167
+              ],
+              [
+                116.566368,
+                9.718623
+              ],
+              [
+                116.593469,
+                9.723932
+              ],
+              [
+                116.557129,
+                9.745167
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.28275,
+                10.191951
+              ],
+              [
+                115.288294,
+                10.172513
+              ],
+              [
+                115.333257,
+                10.200198
+              ],
+              [
+                115.28891,
+                10.211388
+              ],
+              [
+                115.28275,
+                10.191951
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.832454,
+                10.476908
+              ],
+              [
+                116.855243,
+                10.468669
+              ],
+              [
+                116.868794,
+                10.495739
+              ],
+              [
+                116.832454,
+                10.476908
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.703151,
+                16.170307
+              ],
+              [
+                114.816484,
+                16.198469
+              ],
+              [
+                114.802934,
+                16.215135
+              ],
+              [
+                114.704383,
+                16.199044
+              ],
+              [
+                114.703151,
+                16.170307
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.97753,
+                9.321997
+              ],
+              [
+                115.926407,
+                9.311366
+              ],
+              [
+                115.943037,
+                9.269433
+              ],
+              [
+                115.976298,
+                9.268252
+              ],
+              [
+                115.999088,
+                9.293649
+              ],
+              [
+                115.97753,
+                9.321997
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.660366,
+                9.231039
+              ],
+              [
+                113.676997,
+                9.202683
+              ],
+              [
+                113.697323,
+                9.225722
+              ],
+              [
+                113.660366,
+                9.231039
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.665579,
+                7.590001
+              ],
+              [
+                114.671739,
+                7.563898
+              ],
+              [
+                114.72163,
+                7.59178
+              ],
+              [
+                114.703767,
+                7.614915
+              ],
+              [
+                114.665579,
+                7.590001
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.493116,
+                10.717504
+              ],
+              [
+                114.513442,
+                10.722208
+              ],
+              [
+                114.562717,
+                10.778064
+              ],
+              [
+                114.539312,
+                10.793349
+              ],
+              [
+                114.493116,
+                10.717504
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.770529,
+                10.773361
+              ],
+              [
+                117.798862,
+                10.753371
+              ],
+              [
+                117.835819,
+                10.803931
+              ],
+              [
+                117.831507,
+                10.838612
+              ],
+              [
+                117.801942,
+                10.839788
+              ],
+              [
+                117.775457,
+                10.809222
+              ],
+              [
+                117.770529,
+                10.773361
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.242429,
+                10.242014
+              ],
+              [
+                114.263371,
+                10.239658
+              ],
+              [
+                114.326197,
+                10.284414
+              ],
+              [
+                114.312646,
+                10.300901
+              ],
+              [
+                114.265219,
+                10.275581
+              ],
+              [
+                114.242429,
+                10.242014
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.688985,
+                11.469217
+              ],
+              [
+                114.722246,
+                11.429331
+              ],
+              [
+                114.737644,
+                11.463938
+              ],
+              [
+                114.720398,
+                11.49209
+              ],
+              [
+                114.688985,
+                11.469217
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.638433,
+                10.503977
+              ],
+              [
+                116.653215,
+                10.491031
+              ],
+              [
+                116.70865,
+                10.492797
+              ],
+              [
+                116.699411,
+                10.517511
+              ],
+              [
+                116.638433,
+                10.503977
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.459946,
+                8.116449
+              ],
+              [
+                110.471032,
+                8.072012
+              ],
+              [
+                110.554184,
+                8.093935
+              ],
+              [
+                110.599764,
+                8.156735
+              ],
+              [
+                110.568351,
+                8.17273
+              ],
+              [
+                110.461793,
+                8.128298
+              ],
+              [
+                110.459946,
+                8.116449
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.463311,
+                8.52504
+              ],
+              [
+                111.497187,
+                8.523857
+              ],
+              [
+                111.509506,
+                8.550489
+              ],
+              [
+                111.463311,
+                8.52504
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.258113,
+                8.509652
+              ],
+              [
+                115.271048,
+                8.477098
+              ],
+              [
+                115.296301,
+                8.510836
+              ],
+              [
+                115.258113,
+                8.509652
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.221817,
+                8.073789
+              ],
+              [
+                113.235984,
+                8.068456
+              ],
+              [
+                113.283411,
+                8.111117
+              ],
+              [
+                113.269861,
+                8.120004
+              ],
+              [
+                113.221817,
+                8.073789
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.074893,
+                10.929118
+              ],
+              [
+                114.064422,
+                10.904437
+              ],
+              [
+                114.110002,
+                10.918541
+              ],
+              [
+                114.096451,
+                10.947921
+              ],
+              [
+                114.074893,
+                10.929118
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.258068,
+                10.320331
+              ],
+              [
+                117.299336,
+                10.313855
+              ],
+              [
+                117.299952,
+                10.343293
+              ],
+              [
+                117.274698,
+                10.358011
+              ],
+              [
+                117.258068,
+                10.320331
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.212864,
+                16.040937
+              ],
+              [
+                114.31203,
+                16.034611
+              ],
+              [
+                114.306487,
+                16.057616
+              ],
+              [
+                114.268914,
+                16.059342
+              ],
+              [
+                114.212864,
+                16.040937
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.609003,
+                8.010976
+              ],
+              [
+                110.642879,
+                7.989049
+              ],
+              [
+                110.641648,
+                8.031125
+              ],
+              [
+                110.622553,
+                8.041199
+              ],
+              [
+                110.609003,
+                8.010976
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.509416,
+                8.490712
+              ],
+              [
+                115.521735,
+                8.460523
+              ],
+              [
+                115.55438,
+                8.461115
+              ],
+              [
+                115.569162,
+                8.49012
+              ],
+              [
+                115.558691,
+                8.523265
+              ],
+              [
+                115.514344,
+                8.519122
+              ],
+              [
+                115.509416,
+                8.490712
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.539071,
+                7.54432
+              ],
+              [
+                111.542767,
+                7.524742
+              ],
+              [
+                111.583419,
+                7.543134
+              ],
+              [
+                111.612368,
+                7.592374
+              ],
+              [
+                111.566788,
+                7.606017
+              ],
+              [
+                111.539071,
+                7.54432
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.657947,
+                8.672974
+              ],
+              [
+                111.665955,
+                8.622683
+              ],
+              [
+                111.717694,
+                8.6499
+              ],
+              [
+                111.697368,
+                8.67889
+              ],
+              [
+                111.657947,
+                8.672974
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.460561,
+                7.799948
+              ],
+              [
+                110.487663,
+                7.783346
+              ],
+              [
+                110.511684,
+                7.805878
+              ],
+              [
+                110.485199,
+                7.827815
+              ],
+              [
+                110.460561,
+                7.799948
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.345952,
+                8.926101
+              ],
+              [
+                112.392763,
+                8.919598
+              ],
+              [
+                112.384756,
+                8.946793
+              ],
+              [
+                112.345952,
+                8.926101
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.469665,
+                9.810041
+              ],
+              [
+                116.47952,
+                9.785272
+              ],
+              [
+                116.50847,
+                9.79117
+              ],
+              [
+                116.490607,
+                9.821246
+              ],
+              [
+                116.469665,
+                9.810041
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.925265,
+                8.070827
+              ],
+              [
+                111.949287,
+                8.05068
+              ],
+              [
+                111.994866,
+                8.047125
+              ],
+              [
+                112.018888,
+                8.065494
+              ],
+              [
+                112.013344,
+                8.093342
+              ],
+              [
+                111.95483,
+                8.106377
+              ],
+              [
+                111.925265,
+                8.070827
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.457392,
+                15.599305
+              ],
+              [
+                114.466631,
+                15.576823
+              ],
+              [
+                114.491884,
+                15.59354
+              ],
+              [
+                114.457392,
+                15.599305
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.985252,
+                11.078332
+              ],
+              [
+                115.013585,
+                11.063062
+              ],
+              [
+                115.021592,
+                11.085967
+              ],
+              [
+                114.985252,
+                11.078332
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.10569,
+                16.004124
+              ],
+              [
+                114.110618,
+                15.978235
+              ],
+              [
+                114.132176,
+                16.007575
+              ],
+              [
+                114.10569,
+                16.004124
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.045283,
+                10.095338
+              ],
+              [
+                116.067457,
+                10.065876
+              ],
+              [
+                116.09579,
+                10.09357
+              ],
+              [
+                116.070537,
+                10.12892
+              ],
+              [
+                116.045283,
+                10.095338
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.266691,
+                10.69163
+              ],
+              [
+                117.348611,
+                10.672811
+              ],
+              [
+                117.404661,
+                10.671047
+              ],
+              [
+                117.418212,
+                10.702803
+              ],
+              [
+                117.369553,
+                10.7422
+              ],
+              [
+                117.293176,
+                10.735144
+              ],
+              [
+                117.266691,
+                10.69163
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.854057,
+                7.244611
+              ],
+              [
+                114.819564,
+                7.192957
+              ],
+              [
+                114.869455,
+                7.198895
+              ],
+              [
+                114.854057,
+                7.244611
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.823305,
+                8.910729
+              ],
+              [
+                112.859645,
+                8.889444
+              ],
+              [
+                112.873196,
+                8.908364
+              ],
+              [
+                112.823305,
+                8.910729
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.670266,
+                7.651098
+              ],
+              [
+                111.707223,
+                7.648725
+              ],
+              [
+                111.749722,
+                7.703884
+              ],
+              [
+                111.726317,
+                7.729977
+              ],
+              [
+                111.691208,
+                7.711593
+              ],
+              [
+                111.670266,
+                7.651098
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.207981,
+                8.835634
+              ],
+              [
+                112.235699,
+                8.827355
+              ],
+              [
+                112.241242,
+                8.852783
+              ],
+              [
+                112.207981,
+                8.835634
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.527654,
+                5.79444
+              ],
+              [
+                112.531965,
+                5.766455
+              ],
+              [
+                112.562762,
+                5.75931
+              ],
+              [
+                112.562146,
+                5.820637
+              ],
+              [
+                112.527654,
+                5.79444
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.599058,
+                8.846278
+              ],
+              [
+                114.645869,
+                8.844504
+              ],
+              [
+                114.68221,
+                8.881166
+              ],
+              [
+                114.665579,
+                8.900087
+              ],
+              [
+                114.61692,
+                8.881166
+              ],
+              [
+                114.599058,
+                8.846278
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.868223,
+                7.983715
+              ],
+              [
+                114.907643,
+                7.951117
+              ],
+              [
+                114.914419,
+                8.00742
+              ],
+              [
+                114.883006,
+                8.011569
+              ],
+              [
+                114.868223,
+                7.983715
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.945261,
+                8.410204
+              ],
+              [
+                112.985297,
+                8.429149
+              ],
+              [
+                112.949572,
+                8.432701
+              ],
+              [
+                112.945261,
+                8.410204
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.600004,
+                6.961929
+              ],
+              [
+                113.580294,
+                6.920344
+              ],
+              [
+                113.62341,
+                6.942325
+              ],
+              [
+                113.600004,
+                6.961929
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.695099,
+                16.345538
+              ],
+              [
+                116.708034,
+                16.299591
+              ],
+              [
+                116.738831,
+                16.303612
+              ],
+              [
+                116.747454,
+                16.360469
+              ],
+              [
+                116.717889,
+                16.373676
+              ],
+              [
+                116.695099,
+                16.345538
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.347995,
+                10.090624
+              ],
+              [
+                117.354154,
+                10.06293
+              ],
+              [
+                117.385567,
+                10.063519
+              ],
+              [
+                117.373864,
+                10.106532
+              ],
+              [
+                117.347995,
+                10.090624
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.993304,
+                19.472003
+              ],
+              [
+                113.038883,
+                19.480466
+              ],
+              [
+                113.048123,
+                19.506417
+              ],
+              [
+                113.029028,
+                19.52898
+              ],
+              [
+                112.993304,
+                19.52616
+              ],
+              [
+                112.980369,
+                19.496263
+              ],
+              [
+                112.993304,
+                19.472003
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.448153,
+                16.034035
+              ],
+              [
+                114.485109,
+                16.034611
+              ],
+              [
+                114.521449,
+                16.056466
+              ],
+              [
+                114.465399,
+                16.067393
+              ],
+              [
+                114.448153,
+                16.034035
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.832213,
+                19.158552
+              ],
+              [
+                113.874097,
+                19.151203
+              ],
+              [
+                113.914749,
+                19.172119
+              ],
+              [
+                113.920293,
+                19.223551
+              ],
+              [
+                113.875945,
+                19.237113
+              ],
+              [
+                113.80696,
+                19.222986
+              ],
+              [
+                113.799568,
+                19.19925
+              ],
+              [
+                113.832213,
+                19.158552
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.650842,
+                5.106941
+              ],
+              [
+                112.655769,
+                5.055676
+              ],
+              [
+                112.682871,
+                5.048522
+              ],
+              [
+                112.719211,
+                5.075944
+              ],
+              [
+                112.678559,
+                5.121247
+              ],
+              [
+                112.650842,
+                5.106941
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.638853,
+                7.907254
+              ],
+              [
+                111.665339,
+                7.887099
+              ],
+              [
+                111.712766,
+                7.887099
+              ],
+              [
+                111.713382,
+                7.927408
+              ],
+              [
+                111.651788,
+                7.932743
+              ],
+              [
+                111.638853,
+                7.907254
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.244322,
+                8.874662
+              ],
+              [
+                112.281278,
+                8.855148
+              ],
+              [
+                112.288669,
+                8.885896
+              ],
+              [
+                112.244322,
+                8.874662
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.89229,
+                7.844416
+              ],
+              [
+                112.929862,
+                7.827815
+              ],
+              [
+                112.93171,
+                7.867537
+              ],
+              [
+                112.89229,
+                7.844416
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.583088,
+                5.56159
+              ],
+              [
+                112.606494,
+                5.51751
+              ],
+              [
+                112.614501,
+                5.465683
+              ],
+              [
+                112.642834,
+                5.489512
+              ],
+              [
+                112.616349,
+                5.568737
+              ],
+              [
+                112.583088,
+                5.56159
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.523342,
+                5.656289
+              ],
+              [
+                112.5449,
+                5.616386
+              ],
+              [
+                112.565842,
+                5.63068
+              ],
+              [
+                112.56153,
+                5.677133
+              ],
+              [
+                112.528886,
+                5.687257
+              ],
+              [
+                112.523342,
+                5.656289
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.361591,
+                13.948985
+              ],
+              [
+                115.397315,
+                13.92517
+              ],
+              [
+                115.438583,
+                13.943757
+              ],
+              [
+                115.423185,
+                13.977443
+              ],
+              [
+                115.377605,
+                13.968732
+              ],
+              [
+                115.361591,
+                13.948985
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.596924,
+                10.240836
+              ],
+              [
+                113.617866,
+                10.22199
+              ],
+              [
+                113.638192,
+                10.243192
+              ],
+              [
+                113.596924,
+                10.240836
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.860546,
+                15.477068
+              ],
+              [
+                113.893807,
+                15.463802
+              ],
+              [
+                113.890112,
+                15.490909
+              ],
+              [
+                113.860546,
+                15.477068
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.907072,
+                4.993079
+              ],
+              [
+                112.943413,
+                4.991887
+              ],
+              [
+                112.952652,
+                5.047926
+              ],
+              [
+                112.910768,
+                5.038388
+              ],
+              [
+                112.907072,
+                4.993079
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.557219,
+                5.109326
+              ],
+              [
+                112.568922,
+                5.071771
+              ],
+              [
+                112.610806,
+                5.091443
+              ],
+              [
+                112.601567,
+                5.120055
+              ],
+              [
+                112.557219,
+                5.109326
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.350263,
+                5.621747
+              ],
+              [
+                112.385988,
+                5.615791
+              ],
+              [
+                112.385372,
+                5.643187
+              ],
+              [
+                112.350263,
+                5.621747
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.226459,
+                16.759147
+              ],
+              [
+                112.254177,
+                16.751698
+              ],
+              [
+                112.262184,
+                16.778057
+              ],
+              [
+                112.211061,
+                16.795819
+              ],
+              [
+                112.226459,
+                16.759147
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.233851,
+                15.69612
+              ],
+              [
+                112.25972,
+                15.734718
+              ],
+              [
+                112.240626,
+                15.741055
+              ],
+              [
+                112.20367,
+                15.71398
+              ],
+              [
+                112.233851,
+                15.69612
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.612037,
+                5.367973
+              ],
+              [
+                112.640371,
+                5.347715
+              ],
+              [
+                112.685334,
+                5.371548
+              ],
+              [
+                112.690878,
+                5.406702
+              ],
+              [
+                112.62374,
+                5.401935
+              ],
+              [
+                112.612037,
+                5.367973
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.472219,
+                5.73966
+              ],
+              [
+                112.496857,
+                5.736683
+              ],
+              [
+                112.498089,
+                5.775387
+              ],
+              [
+                112.472219,
+                5.73966
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.217506,
+                6.306249
+              ],
+              [
+                113.230441,
+                6.285429
+              ],
+              [
+                113.243991,
+                6.325878
+              ],
+              [
+                113.217506,
+                6.306249
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.152457,
+                9.579384
+              ],
+              [
+                116.189413,
+                9.565221
+              ],
+              [
+                116.187565,
+                9.595317
+              ],
+              [
+                116.152457,
+                9.579384
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.948911,
+                7.508722
+              ],
+              [
+                114.960614,
+                7.484988
+              ],
+              [
+                115.012353,
+                7.484988
+              ],
+              [
+                115.013585,
+                7.525928
+              ],
+              [
+                114.948911,
+                7.508722
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.553854,
+                7.807656
+              ],
+              [
+                111.585267,
+                7.771487
+              ],
+              [
+                111.619759,
+                7.840265
+              ],
+              [
+                111.603745,
+                7.861608
+              ],
+              [
+                111.553854,
+                7.807656
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.938771,
+                15.8355
+              ],
+              [
+                113.973263,
+                15.805558
+              ],
+              [
+                113.9708,
+                15.83953
+              ],
+              [
+                113.938771,
+                15.8355
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.926122,
+                16.036911
+              ],
+              [
+                114.895325,
+                16.036336
+              ],
+              [
+                114.910723,
+                16.001823
+              ],
+              [
+                114.926122,
+                16.036911
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                116.749302,
+                9.056736
+              ],
+              [
+                116.699411,
+                9.049053
+              ],
+              [
+                116.70865,
+                9.024229
+              ],
+              [
+                116.740679,
+                9.028367
+              ],
+              [
+                116.749302,
+                9.056736
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.64653,
+                16.385733
+              ],
+              [
+                112.681639,
+                16.400661
+              ],
+              [
+                112.660081,
+                16.426494
+              ],
+              [
+                112.64653,
+                16.385733
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.203384,
+                19.92557
+              ],
+              [
+                111.203384,
+                19.925007
+              ],
+              [
+                111.204,
+                19.92557
+              ],
+              [
+                111.204,
+                19.926132
+              ],
+              [
+                111.203384,
+                19.92557
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.758256,
+                10.461018
+              ],
+              [
+                115.776118,
+                10.434534
+              ],
+              [
+                115.801987,
+                10.463372
+              ],
+              [
+                115.758256,
+                10.461018
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.21372,
+                10.735144
+              ],
+              [
+                117.187235,
+                10.741612
+              ],
+              [
+                117.206945,
+                10.707507
+              ],
+              [
+                117.21372,
+                10.735144
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.671784,
+                16.331755
+              ],
+              [
+                112.701349,
+                16.331755
+              ],
+              [
+                112.677943,
+                16.35932
+              ],
+              [
+                112.671784,
+                16.331755
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.782277,
+                10.541046
+              ],
+              [
+                115.795212,
+                10.499858
+              ],
+              [
+                115.805067,
+                10.524571
+              ],
+              [
+                115.782277,
+                10.541046
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.512255,
+                9.544566
+              ],
+              [
+                112.50856,
+                9.525679
+              ],
+              [
+                112.568922,
+                9.516826
+              ],
+              [
+                112.567074,
+                9.554008
+              ],
+              [
+                112.512255,
+                9.544566
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.610145,
+                15.649447
+              ],
+              [
+                114.581195,
+                15.625242
+              ],
+              [
+                114.610761,
+                15.615444
+              ],
+              [
+                114.610145,
+                15.649447
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.299336,
+                11.077745
+              ],
+              [
+                117.264227,
+                11.063062
+              ],
+              [
+                117.284553,
+                11.02547
+              ],
+              [
+                117.304263,
+                11.027232
+              ],
+              [
+                117.299336,
+                11.077745
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                117.691073,
+                11.048965
+              ],
+              [
+                117.653501,
+                11.046029
+              ],
+              [
+                117.655965,
+                11.024882
+              ],
+              [
+                117.690457,
+                11.016658
+              ],
+              [
+                117.691073,
+                11.048965
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.166668,
+                9.38459
+              ],
+              [
+                114.175291,
+                9.342075
+              ],
+              [
+                114.195617,
+                9.350933
+              ],
+              [
+                114.194386,
+                9.391676
+              ],
+              [
+                114.166668,
+                9.38459
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.714854,
+                9.736909
+              ],
+              [
+                114.693296,
+                9.741038
+              ],
+              [
+                114.680978,
+                9.707416
+              ],
+              [
+                114.704999,
+                9.700337
+              ],
+              [
+                114.714854,
+                9.736909
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.554139,
+                5.97839
+              ],
+              [
+                112.553523,
+                5.942676
+              ],
+              [
+                112.575697,
+                5.971247
+              ],
+              [
+                112.554139,
+                5.97839
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 500000,
+        "name": "閲嶅簡甯�",
+        "center": [
+          106.504962,
+          29.533155
+        ],
+        "centroid": [
+          107.8839,
+          30.067297
+        ],
+        "childrenNum": 38,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 21,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                106.37442,
+                28.525742
+              ],
+              [
+                106.403369,
+                28.569901
+              ],
+              [
+                106.477282,
+                28.530474
+              ],
+              [
+                106.504999,
+                28.544669
+              ],
+              [
+                106.466811,
+                28.586193
+              ],
+              [
+                106.49268,
+                28.591448
+              ],
+              [
+                106.502535,
+                28.661313
+              ],
+              [
+                106.528405,
+                28.677591
+              ],
+              [
+                106.492064,
+                28.742153
+              ],
+              [
+                106.461883,
+                28.761041
+              ],
+              [
+                106.45326,
+                28.817162
+              ],
+              [
+                106.474202,
+                28.832891
+              ],
+              [
+                106.561666,
+                28.756319
+              ],
+              [
+                106.56105,
+                28.719062
+              ],
+              [
+                106.587535,
+                28.691767
+              ],
+              [
+                106.6171,
+                28.691242
+              ],
+              [
+                106.617716,
+                28.66709
+              ],
+              [
+                106.651593,
+                28.649235
+              ],
+              [
+                106.618332,
+                28.645033
+              ],
+              [
+                106.63681,
+                28.622972
+              ],
+              [
+                106.606629,
+                28.593024
+              ],
+              [
+                106.615252,
+                28.549401
+              ],
+              [
+                106.567825,
+                28.523638
+              ],
+              [
+                106.564745,
+                28.485247
+              ],
+              [
+                106.632499,
+                28.503655
+              ],
+              [
+                106.697788,
+                28.47683
+              ],
+              [
+                106.708259,
+                28.450524
+              ],
+              [
+                106.747063,
+                28.467361
+              ],
+              [
+                106.726121,
+                28.51838
+              ],
+              [
+                106.73844,
+                28.554657
+              ],
+              [
+                106.77786,
+                28.563068
+              ],
+              [
+                106.756918,
+                28.607211
+              ],
+              [
+                106.784636,
+                28.626649
+              ],
+              [
+                106.807425,
+                28.589346
+              ],
+              [
+                106.830831,
+                28.623497
+              ],
+              [
+                106.866556,
+                28.624548
+              ],
+              [
+                106.889345,
+                28.695966
+              ],
+              [
+                106.86594,
+                28.690192
+              ],
+              [
+                106.824056,
+                28.756319
+              ],
+              [
+                106.845614,
+                28.780975
+              ],
+              [
+                106.872099,
+                28.777304
+              ],
+              [
+                106.923222,
+                28.809821
+              ],
+              [
+                106.951555,
+                28.766812
+              ],
+              [
+                106.988512,
+                28.776254
+              ],
+              [
+                106.983584,
+                28.851239
+              ],
+              [
+                107.019308,
+                28.861722
+              ],
+              [
+                107.016229,
+                28.882685
+              ],
+              [
+                107.14188,
+                28.887925
+              ],
+              [
+                107.206554,
+                28.868535
+              ],
+              [
+                107.194851,
+                28.838134
+              ],
+              [
+                107.227496,
+                28.836037
+              ],
+              [
+                107.210866,
+                28.817686
+              ],
+              [
+                107.219489,
+                28.772582
+              ],
+              [
+                107.24659,
+                28.76209
+              ],
+              [
+                107.261373,
+                28.792514
+              ],
+              [
+                107.327894,
+                28.810869
+              ],
+              [
+                107.339597,
+                28.845997
+              ],
+              [
+                107.383945,
+                28.848618
+              ],
+              [
+                107.41351,
+                28.911502
+              ],
+              [
+                107.441227,
+                28.943977
+              ],
+              [
+                107.412894,
+                28.960211
+              ],
+              [
+                107.396879,
+                28.993718
+              ],
+              [
+                107.364235,
+                29.00942
+              ],
+              [
+                107.395647,
+                29.041341
+              ],
+              [
+                107.369778,
+                29.091558
+              ],
+              [
+                107.412278,
+                29.094696
+              ],
+              [
+                107.427676,
+                29.128682
+              ],
+              [
+                107.408582,
+                29.138091
+              ],
+              [
+                107.401807,
+                29.184603
+              ],
+              [
+                107.441227,
+                29.203934
+              ],
+              [
+                107.486806,
+                29.174153
+              ],
+              [
+                107.570574,
+                29.218037
+              ],
+              [
+                107.589052,
+                29.150113
+              ],
+              [
+                107.605683,
+                29.164747
+              ],
+              [
+                107.659885,
+                29.162656
+              ],
+              [
+                107.700537,
+                29.141228
+              ],
+              [
+                107.749197,
+                29.199754
+              ],
+              [
+                107.810791,
+                29.139137
+              ],
+              [
+                107.784921,
+                29.048143
+              ],
+              [
+                107.823725,
+                29.034016
+              ],
+              [
+                107.810175,
+                28.984295
+              ],
+              [
+                107.867457,
+                28.960211
+              ],
+              [
+                107.882855,
+                29.00628
+              ],
+              [
+                107.908725,
+                29.007327
+              ],
+              [
+                107.925971,
+                29.032446
+              ],
+              [
+                108.026369,
+                29.039772
+              ],
+              [
+                108.070717,
+                29.086328
+              ],
+              [
+                108.150173,
+                29.053375
+              ],
+              [
+                108.193289,
+                29.072207
+              ],
+              [
+                108.256115,
+                29.040295
+              ],
+              [
+                108.277673,
+                29.091558
+              ],
+              [
+                108.306622,
+                29.079006
+              ],
+              [
+                108.297999,
+                29.045527
+              ],
+              [
+                108.319556,
+                28.961258
+              ],
+              [
+                108.345426,
+                28.943453
+              ],
+              [
+                108.357745,
+                28.893165
+              ],
+              [
+                108.346658,
+                28.859625
+              ],
+              [
+                108.352817,
+                28.815589
+              ],
+              [
+                108.386078,
+                28.803003
+              ],
+              [
+                108.385462,
+                28.772058
+              ],
+              [
+                108.347274,
+                28.736381
+              ],
+              [
+                108.332491,
+                28.679166
+              ],
+              [
+                108.439049,
+                28.634003
+              ],
+              [
+                108.501258,
+                28.626649
+              ],
+              [
+                108.50249,
+                28.63768
+              ],
+              [
+                108.575787,
+                28.659738
+              ],
+              [
+                108.636149,
+                28.621396
+              ],
+              [
+                108.604736,
+                28.590922
+              ],
+              [
+                108.610896,
+                28.539412
+              ],
+              [
+                108.573939,
+                28.531
+              ],
+              [
+                108.586874,
+                28.463678
+              ],
+              [
+                108.609664,
+                28.43579
+              ],
+              [
+                108.609048,
+                28.407368
+              ],
+              [
+                108.576403,
+                28.38631
+              ],
+              [
+                108.580099,
+                28.343128
+              ],
+              [
+                108.611512,
+                28.324691
+              ],
+              [
+                108.667562,
+                28.334173
+              ],
+              [
+                108.656475,
+                28.359981
+              ],
+              [
+                108.697127,
+                28.401051
+              ],
+              [
+                108.688504,
+                28.422106
+              ],
+              [
+                108.640461,
+                28.456838
+              ],
+              [
+                108.657091,
+                28.47683
+              ],
+              [
+                108.700207,
+                28.48209
+              ],
+              [
+                108.709446,
+                28.501026
+              ],
+              [
+                108.746402,
+                28.45105
+              ],
+              [
+                108.780279,
+                28.42579
+              ],
+              [
+                108.759953,
+                28.389995
+              ],
+              [
+                108.783359,
+                28.380518
+              ],
+              [
+                108.761801,
+                28.304143
+              ],
+              [
+                108.726692,
+                28.282011
+              ],
+              [
+                108.738395,
+                28.228241
+              ],
+              [
+                108.772888,
+                28.212949
+              ],
+              [
+                108.821547,
+                28.245113
+              ],
+              [
+                108.855424,
+                28.199764
+              ],
+              [
+                108.89546,
+                28.219804
+              ],
+              [
+                108.923793,
+                28.217167
+              ],
+              [
+                108.929952,
+                28.19027
+              ],
+              [
+                109.005713,
+                28.162837
+              ],
+              [
+                109.026655,
+                28.220331
+              ],
+              [
+                109.086401,
+                28.184467
+              ],
+              [
+                109.101799,
+                28.202401
+              ],
+              [
+                109.081473,
+                28.247749
+              ],
+              [
+                109.117198,
+                28.277795
+              ],
+              [
+                109.152306,
+                28.349975
+              ],
+              [
+                109.153538,
+                28.417369
+              ],
+              [
+                109.191726,
+                28.471043
+              ],
+              [
+                109.23361,
+                28.474726
+              ],
+              [
+                109.274262,
+                28.494714
+              ],
+              [
+                109.273646,
+                28.53836
+              ],
+              [
+                109.319842,
+                28.579886
+              ],
+              [
+                109.306907,
+                28.62087
+              ],
+              [
+                109.252089,
+                28.606685
+              ],
+              [
+                109.235458,
+                28.61982
+              ],
+              [
+                109.201581,
+                28.597753
+              ],
+              [
+                109.192958,
+                28.636104
+              ],
+              [
+                109.271183,
+                28.671816
+              ],
+              [
+                109.252704,
+                28.691767
+              ],
+              [
+                109.294588,
+                28.722211
+              ],
+              [
+                109.2989,
+                28.7474
+              ],
+              [
+                109.241002,
+                28.776779
+              ],
+              [
+                109.246545,
+                28.80143
+              ],
+              [
+                109.235458,
+                28.882161
+              ],
+              [
+                109.261328,
+                28.952356
+              ],
+              [
+                109.292741,
+                28.987436
+              ],
+              [
+                109.294588,
+                29.015177
+              ],
+              [
+                109.319842,
+                29.042388
+              ],
+              [
+                109.312451,
+                29.066453
+              ],
+              [
+                109.240386,
+                29.086328
+              ],
+              [
+                109.232378,
+                29.119271
+              ],
+              [
+                109.215748,
+                29.145409
+              ],
+              [
+                109.162777,
+                29.180946
+              ],
+              [
+                109.139372,
+                29.168927
+              ],
+              [
+                109.110422,
+                29.21647
+              ],
+              [
+                109.141835,
+                29.270256
+              ],
+              [
+                109.106727,
+                29.288526
+              ],
+              [
+                109.11227,
+                29.361053
+              ],
+              [
+                109.060531,
+                29.403292
+              ],
+              [
+                109.034662,
+                29.360531
+              ],
+              [
+                108.999553,
+                29.36366
+              ],
+              [
+                108.983539,
+                29.332883
+              ],
+              [
+                108.919481,
+                29.3261
+              ],
+              [
+                108.934264,
+                29.399643
+              ],
+              [
+                108.927488,
+                29.435612
+              ],
+              [
+                108.884373,
+                29.440824
+              ],
+              [
+                108.866511,
+                29.470527
+              ],
+              [
+                108.888684,
+                29.502305
+              ],
+              [
+                108.878213,
+                29.539279
+              ],
+              [
+                108.913322,
+                29.574679
+              ],
+              [
+                108.901003,
+                29.604863
+              ],
+              [
+                108.870206,
+                29.596537
+              ],
+              [
+                108.888068,
+                29.628795
+              ],
+              [
+                108.844337,
+                29.658443
+              ],
+              [
+                108.781511,
+                29.635558
+              ],
+              [
+                108.797525,
+                29.660003
+              ],
+              [
+                108.786438,
+                29.691721
+              ],
+              [
+                108.752562,
+                29.649082
+              ],
+              [
+                108.690968,
+                29.689642
+              ],
+              [
+                108.676801,
+                29.749412
+              ],
+              [
+                108.680497,
+                29.800319
+              ],
+              [
+                108.658939,
+                29.854833
+              ],
+              [
+                108.601041,
+                29.863656
+              ],
+              [
+                108.556077,
+                29.818493
+              ],
+              [
+                108.52528,
+                29.770713
+              ],
+              [
+                108.548686,
+                29.749412
+              ],
+              [
+                108.504954,
+                29.728626
+              ],
+              [
+                108.504338,
+                29.707836
+              ],
+              [
+                108.460606,
+                29.741098
+              ],
+              [
+                108.437201,
+                29.741098
+              ],
+              [
+                108.442744,
+                29.778505
+              ],
+              [
+                108.422418,
+                29.772791
+              ],
+              [
+                108.424266,
+                29.815897
+              ],
+              [
+                108.371295,
+                29.841337
+              ],
+              [
+                108.433505,
+                29.880262
+              ],
+              [
+                108.467998,
+                29.864175
+              ],
+              [
+                108.516041,
+                29.885451
+              ],
+              [
+                108.517889,
+                29.9394
+              ],
+              [
+                108.536367,
+                29.983472
+              ],
+              [
+                108.532055,
+                30.051873
+              ],
+              [
+                108.513577,
+                30.057571
+              ],
+              [
+                108.546222,
+                30.104178
+              ],
+              [
+                108.56778,
+                30.157491
+              ],
+              [
+                108.551766,
+                30.1637
+              ],
+              [
+                108.581947,
+                30.255759
+              ],
+              [
+                108.54499,
+                30.269716
+              ],
+              [
+                108.524048,
+                30.309506
+              ],
+              [
+                108.501258,
+                30.314673
+              ],
+              [
+                108.460606,
+                30.35961
+              ],
+              [
+                108.431041,
+                30.354446
+              ],
+              [
+                108.402092,
+                30.376649
+              ],
+              [
+                108.430425,
+                30.416397
+              ],
+              [
+                108.411331,
+                30.438586
+              ],
+              [
+                108.42673,
+                30.492233
+              ],
+              [
+                108.472925,
+                30.487076
+              ],
+              [
+                108.512961,
+                30.501515
+              ],
+              [
+                108.556077,
+                30.487592
+              ],
+              [
+                108.56778,
+                30.468508
+              ],
+              [
+                108.6497,
+                30.53915
+              ],
+              [
+                108.642925,
+                30.578831
+              ],
+              [
+                108.688504,
+                30.58759
+              ],
+              [
+                108.698975,
+                30.54482
+              ],
+              [
+                108.743939,
+                30.494812
+              ],
+              [
+                108.789518,
+                30.513374
+              ],
+              [
+                108.808612,
+                30.491202
+              ],
+              [
+                108.838793,
+                30.503062
+              ],
+              [
+                108.893612,
+                30.565434
+              ],
+              [
+                108.971836,
+                30.627766
+              ],
+              [
+                109.006329,
+                30.626736
+              ],
+              [
+                109.042669,
+                30.655571
+              ],
+              [
+                109.071002,
+                30.640125
+              ],
+              [
+                109.111654,
+                30.646303
+              ],
+              [
+                109.106111,
+                30.61077
+              ],
+              [
+                109.105495,
+                30.585529
+              ],
+              [
+                109.102415,
+                30.580377
+              ],
+              [
+                109.101183,
+                30.579346
+              ],
+              [
+                109.106111,
+                30.570587
+              ],
+              [
+                109.103647,
+                30.565949
+              ],
+              [
+                109.143683,
+                30.521108
+              ],
+              [
+                109.191726,
+                30.545851
+              ],
+              [
+                109.191726,
+                30.545851
+              ],
+              [
+                109.245313,
+                30.580892
+              ],
+              [
+                109.299516,
+                30.630341
+              ],
+              [
+                109.314298,
+                30.599953
+              ],
+              [
+                109.36111,
+                30.551004
+              ],
+              [
+                109.337088,
+                30.521623
+              ],
+              [
+                109.35495,
+                30.487076
+              ],
+              [
+                109.418392,
+                30.559766
+              ],
+              [
+                109.435638,
+                30.595832
+              ],
+              [
+                109.535421,
+                30.664837
+              ],
+              [
+                109.543428,
+                30.63961
+              ],
+              [
+                109.574225,
+                30.646818
+              ],
+              [
+                109.590855,
+                30.69366
+              ],
+              [
+                109.625348,
+                30.702923
+              ],
+              [
+                109.661072,
+                30.738936
+              ],
+              [
+                109.656761,
+                30.760538
+              ],
+              [
+                109.701724,
+                30.783677
+              ],
+              [
+                109.780564,
+                30.848437
+              ],
+              [
+                109.828608,
+                30.864364
+              ],
+              [
+                109.894513,
+                30.899803
+              ],
+              [
+                109.943788,
+                30.878746
+              ],
+              [
+                110.008462,
+                30.883369
+              ],
+              [
+                110.019549,
+                30.829425
+              ],
+              [
+                110.048498,
+                30.800642
+              ],
+              [
+                110.082375,
+                30.799614
+              ],
+              [
+                110.151976,
+                30.911613
+              ],
+              [
+                110.153824,
+                30.953708
+              ],
+              [
+                110.172918,
+                30.978853
+              ],
+              [
+                110.140889,
+                30.987062
+              ],
+              [
+                110.140273,
+                31.030661
+              ],
+              [
+                110.120563,
+                31.0322
+              ],
+              [
+                110.119947,
+                31.088592
+              ],
+              [
+                110.147048,
+                31.116776
+              ],
+              [
+                110.180309,
+                31.121899
+              ],
+              [
+                110.200019,
+                31.158779
+              ],
+              [
+                110.180309,
+                31.179774
+              ],
+              [
+                110.155671,
+                31.279564
+              ],
+              [
+                110.161831,
+                31.314338
+              ],
+              [
+                110.118715,
+                31.409899
+              ],
+              [
+                110.054042,
+                31.410921
+              ],
+              [
+                110.036795,
+                31.436966
+              ],
+              [
+                109.98752,
+                31.474744
+              ],
+              [
+                109.94502,
+                31.47066
+              ],
+              [
+                109.969658,
+                31.508935
+              ],
+              [
+                109.894513,
+                31.519139
+              ],
+              [
+                109.837847,
+                31.555354
+              ],
+              [
+                109.727594,
+                31.548214
+              ],
+              [
+                109.745456,
+                31.598182
+              ],
+              [
+                109.76455,
+                31.602769
+              ],
+              [
+                109.737449,
+                31.628761
+              ],
+              [
+                109.731289,
+                31.700582
+              ],
+              [
+                109.683246,
+                31.719929
+              ],
+              [
+                109.622268,
+                31.711783
+              ],
+              [
+                109.585928,
+                31.726546
+              ],
+              [
+                109.549587,
+                31.73011
+              ],
+              [
+                109.502776,
+                31.716365
+              ],
+              [
+                109.446109,
+                31.722983
+              ],
+              [
+                109.381436,
+                31.705165
+              ],
+              [
+                109.281654,
+                31.716874
+              ],
+              [
+                109.282885,
+                31.743343
+              ],
+              [
+                109.253936,
+                31.759628
+              ],
+              [
+                109.279806,
+                31.776418
+              ],
+              [
+                109.27611,
+                31.79931
+              ],
+              [
+                109.195422,
+                31.817618
+              ],
+              [
+                109.191111,
+                31.85575
+              ],
+              [
+                109.123357,
+                31.892851
+              ],
+              [
+                109.085785,
+                31.929428
+              ],
+              [
+                108.986619,
+                31.980205
+              ],
+              [
+                108.902235,
+                31.984774
+              ],
+              [
+                108.837561,
+                32.039072
+              ],
+              [
+                108.78767,
+                32.04871
+              ],
+              [
+                108.75133,
+                32.076098
+              ],
+              [
+                108.734084,
+                32.106519
+              ],
+              [
+                108.676801,
+                32.10297
+              ],
+              [
+                108.585026,
+                32.17189
+              ],
+              [
+                108.543758,
+                32.177969
+              ],
+              [
+                108.509882,
+                32.201266
+              ],
+              [
+                108.480317,
+                32.182527
+              ],
+              [
+                108.399013,
+                32.194176
+              ],
+              [
+                108.370063,
+                32.172397
+              ],
+              [
+                108.379918,
+                32.154158
+              ],
+              [
+                108.379918,
+                32.154158
+              ],
+              [
+                108.379303,
+                32.153652
+              ],
+              [
+                108.379303,
+                32.153652
+              ],
+              [
+                108.399628,
+                32.147065
+              ],
+              [
+                108.452599,
+                32.090296
+              ],
+              [
+                108.42981,
+                32.061391
+              ],
+              [
+                108.372527,
+                32.077112
+              ],
+              [
+                108.344194,
+                32.067477
+              ],
+              [
+                108.362056,
+                32.035521
+              ],
+              [
+                108.329411,
+                32.020299
+              ],
+              [
+                108.370063,
+                31.988835
+              ],
+              [
+                108.351585,
+                31.971575
+              ],
+              [
+                108.307238,
+                31.997463
+              ],
+              [
+                108.259194,
+                31.967006
+              ],
+              [
+                108.343578,
+                31.860834
+              ],
+              [
+                108.386078,
+                31.854226
+              ],
+              [
+                108.391005,
+                31.829822
+              ],
+              [
+                108.429194,
+                31.809482
+              ],
+              [
+                108.455063,
+                31.814059
+              ],
+              [
+                108.462454,
+                31.780488
+              ],
+              [
+                108.535135,
+                31.757592
+              ],
+              [
+                108.50557,
+                31.734182
+              ],
+              [
+                108.514809,
+                31.693963
+              ],
+              [
+                108.546838,
+                31.665442
+              ],
+              [
+                108.519121,
+                31.665952
+              ],
+              [
+                108.468614,
+                31.636404
+              ],
+              [
+                108.442744,
+                31.633856
+              ],
+              [
+                108.390389,
+                31.591555
+              ],
+              [
+                108.386078,
+                31.544134
+              ],
+              [
+                108.339266,
+                31.539033
+              ],
+              [
+                108.344194,
+                31.512506
+              ],
+              [
+                108.254883,
+                31.49873
+              ],
+              [
+                108.233941,
+                31.506894
+              ],
+              [
+                108.191441,
+                31.492096
+              ],
+              [
+                108.193289,
+                31.467598
+              ],
+              [
+                108.224086,
+                31.464024
+              ],
+              [
+                108.216079,
+                31.41041
+              ],
+              [
+                108.153869,
+                31.371073
+              ],
+              [
+                108.185898,
+                31.336831
+              ],
+              [
+                108.095354,
+                31.268311
+              ],
+              [
+                108.038688,
+                31.252964
+              ],
+              [
+                108.031297,
+                31.217144
+              ],
+              [
+                108.07626,
+                31.231985
+              ],
+              [
+                108.089811,
+                31.204859
+              ],
+              [
+                108.025753,
+                31.116263
+              ],
+              [
+                108.009123,
+                31.109602
+              ],
+              [
+                108.026985,
+                31.061938
+              ],
+              [
+                108.060246,
+                31.052197
+              ],
+              [
+                108.00358,
+                31.025533
+              ],
+              [
+                107.983254,
+                30.983983
+              ],
+              [
+                107.942602,
+                30.989114
+              ],
+              [
+                107.948145,
+                30.918802
+              ],
+              [
+                107.994956,
+                30.908533
+              ],
+              [
+                107.956152,
+                30.882855
+              ],
+              [
+                107.851443,
+                30.792931
+              ],
+              [
+                107.788001,
+                30.81966
+              ],
+              [
+                107.763979,
+                30.817091
+              ],
+              [
+                107.760899,
+                30.862823
+              ],
+              [
+                107.739957,
+                30.884396
+              ],
+              [
+                107.693146,
+                30.875665
+              ],
+              [
+                107.645103,
+                30.821202
+              ],
+              [
+                107.57735,
+                30.847924
+              ],
+              [
+                107.515756,
+                30.854603
+              ],
+              [
+                107.483111,
+                30.838675
+              ],
+              [
+                107.498509,
+                30.809381
+              ],
+              [
+                107.454162,
+                30.771851
+              ],
+              [
+                107.454162,
+                30.771851
+              ],
+              [
+                107.424597,
+                30.74048
+              ],
+              [
+                107.458473,
+                30.704981
+              ],
+              [
+                107.477567,
+                30.664837
+              ],
+              [
+                107.516987,
+                30.644759
+              ],
+              [
+                107.485575,
+                30.598408
+              ],
+              [
+                107.427676,
+                30.547397
+              ],
+              [
+                107.443075,
+                30.53348
+              ],
+              [
+                107.408582,
+                30.521623
+              ],
+              [
+                107.368546,
+                30.468508
+              ],
+              [
+                107.338981,
+                30.386459
+              ],
+              [
+                107.288474,
+                30.337402
+              ],
+              [
+                107.257677,
+                30.267131
+              ],
+              [
+                107.221337,
+                30.213878
+              ],
+              [
+                107.103076,
+                30.090198
+              ],
+              [
+                107.080286,
+                30.094341
+              ],
+              [
+                107.084598,
+                30.063786
+              ],
+              [
+                107.058113,
+                30.043066
+              ],
+              [
+                107.055649,
+                30.040476
+              ],
+              [
+                107.054417,
+                30.040994
+              ],
+              [
+                107.053801,
+                30.043584
+              ],
+              [
+                107.02054,
+                30.036849
+              ],
+              [
+                106.981736,
+                30.08502
+              ],
+              [
+                106.976193,
+                30.083467
+              ],
+              [
+                106.94478,
+                30.037367
+              ],
+              [
+                106.913367,
+                30.025451
+              ],
+              [
+                106.862244,
+                30.033223
+              ],
+              [
+                106.83699,
+                30.049801
+              ],
+              [
+                106.825904,
+                30.03115
+              ],
+              [
+                106.825904,
+                30.03115
+              ],
+              [
+                106.785252,
+                30.01716
+              ],
+              [
+                106.732281,
+                30.027005
+              ],
+              [
+                106.724274,
+                30.058607
+              ],
+              [
+                106.699636,
+                30.074145
+              ],
+              [
+                106.700252,
+                30.111944
+              ],
+              [
+                106.672535,
+                30.122297
+              ],
+              [
+                106.677462,
+                30.156974
+              ],
+              [
+                106.631883,
+                30.186464
+              ],
+              [
+                106.611557,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.611557,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.612789,
+                30.235596
+              ],
+              [
+                106.612789,
+                30.235596
+              ],
+              [
+                106.642354,
+                30.246454
+              ],
+              [
+                106.611557,
+                30.292455
+              ],
+              [
+                106.560434,
+                30.31519
+              ],
+              [
+                106.545035,
+                30.296589
+              ],
+              [
+                106.49884,
+                30.295556
+              ],
+              [
+                106.43971,
+                30.308473
+              ],
+              [
+                106.428623,
+                30.254725
+              ],
+              [
+                106.401521,
+                30.242318
+              ],
+              [
+                106.349167,
+                30.24542
+              ],
+              [
+                106.334384,
+                30.225772
+              ],
+              [
+                106.306667,
+                30.238182
+              ],
+              [
+                106.296196,
+                30.205603
+              ],
+              [
+                106.264167,
+                30.20974
+              ],
+              [
+                106.260471,
+                30.19681
+              ],
+              [
+                106.232754,
+                30.185947
+              ],
+              [
+                106.180399,
+                30.233011
+              ],
+              [
+                106.168696,
+                30.303823
+              ],
+              [
+                106.132356,
+                30.323972
+              ],
+              [
+                106.132972,
+                30.30279
+              ],
+              [
+                106.07261,
+                30.333786
+              ],
+              [
+                106.031958,
+                30.373551
+              ],
+              [
+                105.943263,
+                30.372002
+              ],
+              [
+                105.900763,
+                30.405042
+              ],
+              [
+                105.84656,
+                30.410203
+              ],
+              [
+                105.825618,
+                30.436006
+              ],
+              [
+                105.792357,
+                30.427234
+              ],
+              [
+                105.760329,
+                30.384393
+              ],
+              [
+                105.754785,
+                30.342567
+              ],
+              [
+                105.714749,
+                30.322939
+              ],
+              [
+                105.720292,
+                30.252657
+              ],
+              [
+                105.720292,
+                30.252657
+              ],
+              [
+                105.670401,
+                30.254208
+              ],
+              [
+                105.624822,
+                30.275918
+              ],
+              [
+                105.619894,
+                30.234045
+              ],
+              [
+                105.662394,
+                30.210258
+              ],
+              [
+                105.642684,
+                30.186464
+              ],
+              [
+                105.56138,
+                30.183878
+              ],
+              [
+                105.550909,
+                30.179222
+              ],
+              [
+                105.536127,
+                30.152834
+              ],
+              [
+                105.596489,
+                30.159043
+              ],
+              [
+                105.574315,
+                30.130579
+              ],
+              [
+                105.580474,
+                30.129544
+              ],
+              [
+                105.582938,
+                30.127474
+              ],
+              [
+                105.582938,
+                30.12385
+              ],
+              [
+                105.642068,
+                30.101072
+              ],
+              [
+                105.638988,
+                30.076216
+              ],
+              [
+                105.676561,
+                30.06793
+              ],
+              [
+                105.687032,
+                30.038922
+              ],
+              [
+                105.719677,
+                30.042548
+              ],
+              [
+                105.753553,
+                30.018196
+              ],
+              [
+                105.723372,
+                29.975177
+              ],
+              [
+                105.730763,
+                29.95755
+              ],
+              [
+                105.70243,
+                29.924879
+              ],
+              [
+                105.717213,
+                29.893753
+              ],
+              [
+                105.738771,
+                29.891159
+              ],
+              [
+                105.707974,
+                29.840818
+              ],
+              [
+                105.610655,
+                29.837184
+              ],
+              [
+                105.582938,
+                29.819013
+              ],
+              [
+                105.574931,
+                29.744216
+              ],
+              [
+                105.529351,
+                29.707836
+              ],
+              [
+                105.481924,
+                29.718232
+              ],
+              [
+                105.476996,
+                29.674564
+              ],
+              [
+                105.419714,
+                29.688082
+              ],
+              [
+                105.38091,
+                29.628275
+              ],
+              [
+                105.347649,
+                29.621512
+              ],
+              [
+                105.332867,
+                29.592374
+              ],
+              [
+                105.296526,
+                29.571035
+              ],
+              [
+                105.305149,
+                29.53199
+              ],
+              [
+                105.337794,
+                29.459064
+              ],
+              [
+                105.334099,
+                29.441345
+              ],
+              [
+                105.387069,
+                29.455416
+              ],
+              [
+                105.387069,
+                29.455416
+              ],
+              [
+                105.399388,
+                29.43874
+              ],
+              [
+                105.372903,
+                29.421018
+              ],
+              [
+                105.426489,
+                29.419454
+              ],
+              [
+                105.441888,
+                29.400686
+              ],
+              [
+                105.418482,
+                29.352185
+              ],
+              [
+                105.42033,
+                29.31149
+              ],
+              [
+                105.465294,
+                29.322969
+              ],
+              [
+                105.459134,
+                29.288526
+              ],
+              [
+                105.513337,
+                29.283306
+              ],
+              [
+                105.521344,
+                29.264513
+              ],
+              [
+                105.557684,
+                29.278608
+              ],
+              [
+                105.631597,
+                29.280174
+              ],
+              [
+                105.647612,
+                29.253027
+              ],
+              [
+                105.695039,
+                29.287482
+              ],
+              [
+                105.712285,
+                29.219082
+              ],
+              [
+                105.703662,
+                29.176766
+              ],
+              [
+                105.728916,
+                29.134432
+              ],
+              [
+                105.752321,
+                29.129727
+              ],
+              [
+                105.728916,
+                29.1062
+              ],
+              [
+                105.757865,
+                29.069068
+              ],
+              [
+                105.74185,
+                29.039249
+              ],
+              [
+                105.766488,
+                29.013607
+              ],
+              [
+                105.762176,
+                28.9911
+              ],
+              [
+                105.801596,
+                28.958116
+              ],
+              [
+                105.797285,
+                28.936121
+              ],
+              [
+                105.830546,
+                28.944501
+              ],
+              [
+                105.852719,
+                28.927217
+              ],
+              [
+                105.910002,
+                28.920407
+              ],
+              [
+                105.969132,
+                28.965971
+              ],
+              [
+                106.001161,
+                28.973824
+              ],
+              [
+                106.040581,
+                28.955498
+              ],
+              [
+                106.049204,
+                28.906263
+              ],
+              [
+                106.070762,
+                28.919884
+              ],
+              [
+                106.101559,
+                28.898928
+              ],
+              [
+                106.14837,
+                28.901548
+              ],
+              [
+                106.173008,
+                28.920407
+              ],
+              [
+                106.206885,
+                28.904691
+              ],
+              [
+                106.264783,
+                28.845997
+              ],
+              [
+                106.245689,
+                28.817686
+              ],
+              [
+                106.267863,
+                28.779402
+              ],
+              [
+                106.274022,
+                28.739004
+              ],
+              [
+                106.305435,
+                28.704365
+              ],
+              [
+                106.304203,
+                28.64976
+              ],
+              [
+                106.346703,
+                28.583565
+              ],
+              [
+                106.33192,
+                28.55308
+              ],
+              [
+                106.37442,
+                28.525742
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.105495,
+                30.585529
+              ],
+              [
+                109.106111,
+                30.61077
+              ],
+              [
+                109.09256,
+                30.578831
+              ],
+              [
+                109.09872,
+                30.579346
+              ],
+              [
+                109.101183,
+                30.579346
+              ],
+              [
+                109.102415,
+                30.580377
+              ],
+              [
+                109.105495,
+                30.585529
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                105.582938,
+                30.12385
+              ],
+              [
+                105.582938,
+                30.127474
+              ],
+              [
+                105.580474,
+                30.129544
+              ],
+              [
+                105.574315,
+                30.130579
+              ],
+              [
+                105.582938,
+                30.12385
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.09872,
+                30.579346
+              ],
+              [
+                109.09256,
+                30.578831
+              ],
+              [
+                109.103647,
+                30.565949
+              ],
+              [
+                109.106111,
+                30.570587
+              ],
+              [
+                109.09872,
+                30.579346
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                107.058113,
+                30.043066
+              ],
+              [
+                107.053801,
+                30.043584
+              ],
+              [
+                107.054417,
+                30.040994
+              ],
+              [
+                107.055649,
+                30.040476
+              ],
+              [
+                107.058113,
+                30.043066
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 510000,
+        "name": "鍥涘窛鐪�",
+        "center": [
+          104.065735,
+          30.659462
+        ],
+        "centroid": [
+          102.693453,
+          30.674545
+        ],
+        "childrenNum": 21,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 22,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                101.167885,
+                27.198311
+              ],
+              [
+                101.170349,
+                27.175421
+              ],
+              [
+                101.145095,
+                27.103523
+              ],
+              [
+                101.157414,
+                27.094999
+              ],
+              [
+                101.136472,
+                27.023584
+              ],
+              [
+                101.228863,
+                26.981992
+              ],
+              [
+                101.227015,
+                26.959057
+              ],
+              [
+                101.264587,
+                26.955323
+              ],
+              [
+                101.267667,
+                26.903034
+              ],
+              [
+                101.311399,
+                26.903034
+              ],
+              [
+                101.365602,
+                26.883819
+              ],
+              [
+                101.399478,
+                26.841642
+              ],
+              [
+                101.358826,
+                26.771669
+              ],
+              [
+                101.387159,
+                26.753501
+              ],
+              [
+                101.389623,
+                26.723036
+              ],
+              [
+                101.435819,
+                26.740675
+              ],
+              [
+                101.458608,
+                26.731054
+              ],
+              [
+                101.445674,
+                26.77434
+              ],
+              [
+                101.466,
+                26.786629
+              ],
+              [
+                101.513427,
+                26.768463
+              ],
+              [
+                101.453065,
+                26.692563
+              ],
+              [
+                101.481398,
+                26.673313
+              ],
+              [
+                101.461072,
+                26.640687
+              ],
+              [
+                101.461688,
+                26.606447
+              ],
+              [
+                101.402558,
+                26.604841
+              ],
+              [
+                101.395783,
+                26.591998
+              ],
+              [
+                101.422884,
+                26.53151
+              ],
+              [
+                101.458608,
+                26.49563
+              ],
+              [
+                101.506652,
+                26.499915
+              ],
+              [
+                101.530057,
+                26.467239
+              ],
+              [
+                101.565782,
+                26.454381
+              ],
+              [
+                101.637847,
+                26.388995
+              ],
+              [
+                101.635383,
+                26.357361
+              ],
+              [
+                101.660636,
+                26.346635
+              ],
+              [
+                101.64031,
+                26.318745
+              ],
+              [
+                101.597195,
+                26.303187
+              ],
+              [
+                101.586108,
+                26.279579
+              ],
+              [
+                101.630455,
+                26.224832
+              ],
+              [
+                101.690202,
+                26.241473
+              ],
+              [
+                101.737013,
+                26.219463
+              ],
+              [
+                101.773353,
+                26.168448
+              ],
+              [
+                101.807846,
+                26.156093
+              ],
+              [
+                101.796759,
+                26.114723
+              ],
+              [
+                101.839875,
+                26.082477
+              ],
+              [
+                101.835563,
+                26.04592
+              ],
+              [
+                101.857737,
+                26.049146
+              ],
+              [
+                101.899621,
+                26.099139
+              ],
+              [
+                101.929186,
+                26.105588
+              ],
+              [
+                101.954439,
+                26.084627
+              ],
+              [
+                102.020961,
+                26.096451
+              ],
+              [
+                102.080091,
+                26.065275
+              ],
+              [
+                102.107808,
+                26.068501
+              ],
+              [
+                102.152156,
+                26.10935
+              ],
+              [
+                102.174946,
+                26.146961
+              ],
+              [
+                102.242699,
+                26.190468
+              ],
+              [
+                102.245163,
+                26.212483
+              ],
+              [
+                102.349257,
+                26.244694
+              ],
+              [
+                102.392372,
+                26.296749
+              ],
+              [
+                102.440416,
+                26.300505
+              ],
+              [
+                102.542046,
+                26.338591
+              ],
+              [
+                102.570995,
+                26.362723
+              ],
+              [
+                102.629509,
+                26.336982
+              ],
+              [
+                102.638748,
+                26.307479
+              ],
+              [
+                102.60056,
+                26.250598
+              ],
+              [
+                102.659074,
+                26.221611
+              ],
+              [
+                102.709581,
+                26.210336
+              ],
+              [
+                102.739762,
+                26.268846
+              ],
+              [
+                102.785342,
+                26.298895
+              ],
+              [
+                102.833385,
+                26.306406
+              ],
+              [
+                102.878964,
+                26.364332
+              ],
+              [
+                102.893131,
+                26.338591
+              ],
+              [
+                102.975667,
+                26.340736
+              ],
+              [
+                102.998457,
+                26.371839
+              ],
+              [
+                102.988602,
+                26.413117
+              ],
+              [
+                102.989833,
+                26.482775
+              ],
+              [
+                103.030485,
+                26.485989
+              ],
+              [
+                103.052659,
+                26.514374
+              ],
+              [
+                103.052659,
+                26.555602
+              ],
+              [
+                103.035413,
+                26.556673
+              ],
+              [
+                103.026174,
+                26.664221
+              ],
+              [
+                103.005232,
+                26.679195
+              ],
+              [
+                103.008312,
+                26.710741
+              ],
+              [
+                102.983674,
+                26.76686
+              ],
+              [
+                102.991681,
+                26.775409
+              ],
+              [
+                102.966428,
+                26.837904
+              ],
+              [
+                102.949181,
+                26.843244
+              ],
+              [
+                102.896211,
+                26.91264
+              ],
+              [
+                102.894979,
+                27.001724
+              ],
+              [
+                102.870957,
+                27.026782
+              ],
+              [
+                102.913457,
+                27.133886
+              ],
+              [
+                102.904218,
+                27.227584
+              ],
+              [
+                102.883276,
+                27.258444
+              ],
+              [
+                102.883892,
+                27.299401
+              ],
+              [
+                102.899906,
+                27.317481
+              ],
+              [
+                102.941174,
+                27.405711
+              ],
+              [
+                102.989833,
+                27.367983
+              ],
+              [
+                103.055739,
+                27.40943
+              ],
+              [
+                103.080992,
+                27.396679
+              ],
+              [
+                103.141355,
+                27.420586
+              ],
+              [
+                103.144434,
+                27.450331
+              ],
+              [
+                103.19063,
+                27.523596
+              ],
+              [
+                103.232514,
+                27.56976
+              ],
+              [
+                103.2861,
+                27.561802
+              ],
+              [
+                103.29226,
+                27.632872
+              ],
+              [
+                103.349542,
+                27.678459
+              ],
+              [
+                103.369868,
+                27.708664
+              ],
+              [
+                103.393274,
+                27.709194
+              ],
+              [
+                103.461027,
+                27.779638
+              ],
+              [
+                103.487512,
+                27.794992
+              ],
+              [
+                103.509686,
+                27.843687
+              ],
+              [
+                103.502295,
+                27.910343
+              ],
+              [
+                103.55465,
+                27.978543
+              ],
+              [
+                103.515846,
+                27.965329
+              ],
+              [
+                103.486281,
+                28.033495
+              ],
+              [
+                103.459179,
+                28.021345
+              ],
+              [
+                103.430846,
+                28.044587
+              ],
+              [
+                103.470266,
+                28.122204
+              ],
+              [
+                103.533092,
+                28.168641
+              ],
+              [
+                103.573128,
+                28.230877
+              ],
+              [
+                103.643961,
+                28.260401
+              ],
+              [
+                103.692004,
+                28.232459
+              ],
+              [
+                103.701859,
+                28.198709
+              ],
+              [
+                103.740048,
+                28.23615
+              ],
+              [
+                103.770845,
+                28.233514
+              ],
+              [
+                103.828743,
+                28.285173
+              ],
+              [
+                103.877402,
+                28.316262
+              ],
+              [
+                103.85338,
+                28.356822
+              ],
+              [
+                103.860156,
+                28.383677
+              ],
+              [
+                103.828743,
+                28.44
+              ],
+              [
+                103.829975,
+                28.459995
+              ],
+              [
+                103.781931,
+                28.525216
+              ],
+              [
+                103.802873,
+                28.563068
+              ],
+              [
+                103.838598,
+                28.587244
+              ],
+              [
+                103.833054,
+                28.605109
+              ],
+              [
+                103.850917,
+                28.66709
+              ],
+              [
+                103.887873,
+                28.61982
+              ],
+              [
+                103.910047,
+                28.631377
+              ],
+              [
+                103.953779,
+                28.600906
+              ],
+              [
+                104.05972,
+                28.6277
+              ],
+              [
+                104.09606,
+                28.603533
+              ],
+              [
+                104.117618,
+                28.634003
+              ],
+              [
+                104.170589,
+                28.642932
+              ],
+              [
+                104.230951,
+                28.635579
+              ],
+              [
+                104.252509,
+                28.660788
+              ],
+              [
+                104.277147,
+                28.631902
+              ],
+              [
+                104.314719,
+                28.615617
+              ],
+              [
+                104.372617,
+                28.649235
+              ],
+              [
+                104.425588,
+                28.626649
+              ],
+              [
+                104.417581,
+                28.598279
+              ],
+              [
+                104.375697,
+                28.5946
+              ],
+              [
+                104.355987,
+                28.555183
+              ],
+              [
+                104.323342,
+                28.540989
+              ],
+              [
+                104.260516,
+                28.536257
+              ],
+              [
+                104.267908,
+                28.499448
+              ],
+              [
+                104.254357,
+                28.403683
+              ],
+              [
+                104.282074,
+                28.343128
+              ],
+              [
+                104.314103,
+                28.306778
+              ],
+              [
+                104.343052,
+                28.334173
+              ],
+              [
+                104.384936,
+                28.329959
+              ],
+              [
+                104.392943,
+                28.291497
+              ],
+              [
+                104.420045,
+                28.269889
+              ],
+              [
+                104.44961,
+                28.269889
+              ],
+              [
+                104.462544,
+                28.241422
+              ],
+              [
+                104.442834,
+                28.211366
+              ],
+              [
+                104.402182,
+                28.202928
+              ],
+              [
+                104.406494,
+                28.173389
+              ],
+              [
+                104.444682,
+                28.16231
+              ],
+              [
+                104.448994,
+                28.113758
+              ],
+              [
+                104.40095,
+                28.091586
+              ],
+              [
+                104.373233,
+                28.051454
+              ],
+              [
+                104.304248,
+                28.050926
+              ],
+              [
+                104.30856,
+                28.036136
+              ],
+              [
+                104.362762,
+                28.012891
+              ],
+              [
+                104.40095,
+                27.952114
+              ],
+              [
+                104.44961,
+                27.927794
+              ],
+              [
+                104.508124,
+                27.878078
+              ],
+              [
+                104.52537,
+                27.889187
+              ],
+              [
+                104.573413,
+                27.840512
+              ],
+              [
+                104.607906,
+                27.857974
+              ],
+              [
+                104.63316,
+                27.850567
+              ],
+              [
+                104.676275,
+                27.880723
+              ],
+              [
+                104.743413,
+                27.901881
+              ],
+              [
+                104.761891,
+                27.884426
+              ],
+              [
+                104.796999,
+                27.901352
+              ],
+              [
+                104.842579,
+                27.900294
+              ],
+              [
+                104.888158,
+                27.914574
+              ],
+              [
+                104.918339,
+                27.938897
+              ],
+              [
+                104.903557,
+                27.962158
+              ],
+              [
+                104.975006,
+                28.020816
+              ],
+              [
+                104.980549,
+                28.063073
+              ],
+              [
+                105.002107,
+                28.064129
+              ],
+              [
+                105.061853,
+                28.096866
+              ],
+              [
+                105.119752,
+                28.07205
+              ],
+              [
+                105.168411,
+                28.071522
+              ],
+              [
+                105.186889,
+                28.054623
+              ],
+              [
+                105.167795,
+                28.021345
+              ],
+              [
+                105.186273,
+                27.995454
+              ],
+              [
+                105.218302,
+                27.990698
+              ],
+              [
+                105.247867,
+                28.009193
+              ],
+              [
+                105.270657,
+                27.99704
+              ],
+              [
+                105.284823,
+                27.935725
+              ],
+              [
+                105.233084,
+                27.895534
+              ],
+              [
+                105.25957,
+                27.827811
+              ],
+              [
+                105.313157,
+                27.810874
+              ],
+              [
+                105.273736,
+                27.794992
+              ],
+              [
+                105.293447,
+                27.770637
+              ],
+              [
+                105.290367,
+                27.712373
+              ],
+              [
+                105.308229,
+                27.704955
+              ],
+              [
+                105.353809,
+                27.748924
+              ],
+              [
+                105.44004,
+                27.775402
+              ],
+              [
+                105.508409,
+                27.769048
+              ],
+              [
+                105.560148,
+                27.71979
+              ],
+              [
+                105.605112,
+                27.715552
+              ],
+              [
+                105.62359,
+                27.666269
+              ],
+              [
+                105.664242,
+                27.683759
+              ],
+              [
+                105.720292,
+                27.683759
+              ],
+              [
+                105.722756,
+                27.706015
+              ],
+              [
+                105.76772,
+                27.7182
+              ],
+              [
+                105.848408,
+                27.707074
+              ],
+              [
+                105.868118,
+                27.732504
+              ],
+              [
+                105.922937,
+                27.746805
+              ],
+              [
+                105.92848,
+                27.729855
+              ],
+              [
+                105.985146,
+                27.749983
+              ],
+              [
+                106.023335,
+                27.746805
+              ],
+              [
+                106.063987,
+                27.776991
+              ],
+              [
+                106.120653,
+                27.779638
+              ],
+              [
+                106.193334,
+                27.75422
+              ],
+              [
+                106.242609,
+                27.767459
+              ],
+              [
+                106.306667,
+                27.808756
+              ],
+              [
+                106.337464,
+                27.859033
+              ],
+              [
+                106.325145,
+                27.898708
+              ],
+              [
+                106.304819,
+                27.899237
+              ],
+              [
+                106.307899,
+                27.936782
+              ],
+              [
+                106.328225,
+                27.952643
+              ],
+              [
+                106.286341,
+                28.007079
+              ],
+              [
+                106.246305,
+                28.011835
+              ],
+              [
+                106.266631,
+                28.066769
+              ],
+              [
+                106.206885,
+                28.134343
+              ],
+              [
+                106.145291,
+                28.162837
+              ],
+              [
+                106.093552,
+                28.162837
+              ],
+              [
+                105.975907,
+                28.107952
+              ],
+              [
+                105.943878,
+                28.143314
+              ],
+              [
+                105.895219,
+                28.119565
+              ],
+              [
+                105.860727,
+                28.159672
+              ],
+              [
+                105.889676,
+                28.237732
+              ],
+              [
+                105.848408,
+                28.255656
+              ],
+              [
+                105.824386,
+                28.306251
+              ],
+              [
+                105.78743,
+                28.335753
+              ],
+              [
+                105.76464,
+                28.308359
+              ],
+              [
+                105.76464,
+                28.308359
+              ],
+              [
+                105.737539,
+                28.30309
+              ],
+              [
+                105.730147,
+                28.271997
+              ],
+              [
+                105.68888,
+                28.284119
+              ],
+              [
+                105.639604,
+                28.324164
+              ],
+              [
+                105.655003,
+                28.362615
+              ],
+              [
+                105.643916,
+                28.431053
+              ],
+              [
+                105.612503,
+                28.438947
+              ],
+              [
+                105.62359,
+                28.517854
+              ],
+              [
+                105.68272,
+                28.534154
+              ],
+              [
+                105.693191,
+                28.58882
+              ],
+              [
+                105.712901,
+                28.586718
+              ],
+              [
+                105.74493,
+                28.616668
+              ],
+              [
+                105.757249,
+                28.590397
+              ],
+              [
+                105.78435,
+                28.610889
+              ],
+              [
+                105.808372,
+                28.599855
+              ],
+              [
+                105.884748,
+                28.595126
+              ],
+              [
+                105.889676,
+                28.670765
+              ],
+              [
+                105.937719,
+                28.686517
+              ],
+              [
+                105.966668,
+                28.761041
+              ],
+              [
+                106.001161,
+                28.743727
+              ],
+              [
+                106.030726,
+                28.694917
+              ],
+              [
+                106.085544,
+                28.681792
+              ],
+              [
+                106.103407,
+                28.636104
+              ],
+              [
+                106.14837,
+                28.642932
+              ],
+              [
+                106.17116,
+                28.629275
+              ],
+              [
+                106.184711,
+                28.58882
+              ],
+              [
+                106.254928,
+                28.539412
+              ],
+              [
+                106.2925,
+                28.537309
+              ],
+              [
+                106.304819,
+                28.505233
+              ],
+              [
+                106.349167,
+                28.473674
+              ],
+              [
+                106.379348,
+                28.479986
+              ],
+              [
+                106.37442,
+                28.525742
+              ],
+              [
+                106.33192,
+                28.55308
+              ],
+              [
+                106.346703,
+                28.583565
+              ],
+              [
+                106.304203,
+                28.64976
+              ],
+              [
+                106.305435,
+                28.704365
+              ],
+              [
+                106.274022,
+                28.739004
+              ],
+              [
+                106.267863,
+                28.779402
+              ],
+              [
+                106.245689,
+                28.817686
+              ],
+              [
+                106.264783,
+                28.845997
+              ],
+              [
+                106.206885,
+                28.904691
+              ],
+              [
+                106.173008,
+                28.920407
+              ],
+              [
+                106.14837,
+                28.901548
+              ],
+              [
+                106.101559,
+                28.898928
+              ],
+              [
+                106.070762,
+                28.919884
+              ],
+              [
+                106.049204,
+                28.906263
+              ],
+              [
+                106.040581,
+                28.955498
+              ],
+              [
+                106.001161,
+                28.973824
+              ],
+              [
+                105.969132,
+                28.965971
+              ],
+              [
+                105.910002,
+                28.920407
+              ],
+              [
+                105.852719,
+                28.927217
+              ],
+              [
+                105.830546,
+                28.944501
+              ],
+              [
+                105.797285,
+                28.936121
+              ],
+              [
+                105.801596,
+                28.958116
+              ],
+              [
+                105.762176,
+                28.9911
+              ],
+              [
+                105.766488,
+                29.013607
+              ],
+              [
+                105.74185,
+                29.039249
+              ],
+              [
+                105.757865,
+                29.069068
+              ],
+              [
+                105.728916,
+                29.1062
+              ],
+              [
+                105.752321,
+                29.129727
+              ],
+              [
+                105.728916,
+                29.134432
+              ],
+              [
+                105.703662,
+                29.176766
+              ],
+              [
+                105.712285,
+                29.219082
+              ],
+              [
+                105.695039,
+                29.287482
+              ],
+              [
+                105.647612,
+                29.253027
+              ],
+              [
+                105.631597,
+                29.280174
+              ],
+              [
+                105.557684,
+                29.278608
+              ],
+              [
+                105.521344,
+                29.264513
+              ],
+              [
+                105.513337,
+                29.283306
+              ],
+              [
+                105.459134,
+                29.288526
+              ],
+              [
+                105.465294,
+                29.322969
+              ],
+              [
+                105.42033,
+                29.31149
+              ],
+              [
+                105.418482,
+                29.352185
+              ],
+              [
+                105.441888,
+                29.400686
+              ],
+              [
+                105.426489,
+                29.419454
+              ],
+              [
+                105.372903,
+                29.421018
+              ],
+              [
+                105.399388,
+                29.43874
+              ],
+              [
+                105.387069,
+                29.455416
+              ],
+              [
+                105.387069,
+                29.455416
+              ],
+              [
+                105.334099,
+                29.441345
+              ],
+              [
+                105.337794,
+                29.459064
+              ],
+              [
+                105.305149,
+                29.53199
+              ],
+              [
+                105.296526,
+                29.571035
+              ],
+              [
+                105.332867,
+                29.592374
+              ],
+              [
+                105.347649,
+                29.621512
+              ],
+              [
+                105.38091,
+                29.628275
+              ],
+              [
+                105.419714,
+                29.688082
+              ],
+              [
+                105.476996,
+                29.674564
+              ],
+              [
+                105.481924,
+                29.718232
+              ],
+              [
+                105.529351,
+                29.707836
+              ],
+              [
+                105.574931,
+                29.744216
+              ],
+              [
+                105.582938,
+                29.819013
+              ],
+              [
+                105.610655,
+                29.837184
+              ],
+              [
+                105.707974,
+                29.840818
+              ],
+              [
+                105.738771,
+                29.891159
+              ],
+              [
+                105.717213,
+                29.893753
+              ],
+              [
+                105.70243,
+                29.924879
+              ],
+              [
+                105.730763,
+                29.95755
+              ],
+              [
+                105.723372,
+                29.975177
+              ],
+              [
+                105.753553,
+                30.018196
+              ],
+              [
+                105.719677,
+                30.042548
+              ],
+              [
+                105.687032,
+                30.038922
+              ],
+              [
+                105.676561,
+                30.06793
+              ],
+              [
+                105.638988,
+                30.076216
+              ],
+              [
+                105.642068,
+                30.101072
+              ],
+              [
+                105.582938,
+                30.12385
+              ],
+              [
+                105.574315,
+                30.130579
+              ],
+              [
+                105.596489,
+                30.159043
+              ],
+              [
+                105.536127,
+                30.152834
+              ],
+              [
+                105.550909,
+                30.179222
+              ],
+              [
+                105.556453,
+                30.187499
+              ],
+              [
+                105.558916,
+                30.18543
+              ],
+              [
+                105.56138,
+                30.183878
+              ],
+              [
+                105.642684,
+                30.186464
+              ],
+              [
+                105.662394,
+                30.210258
+              ],
+              [
+                105.619894,
+                30.234045
+              ],
+              [
+                105.624822,
+                30.275918
+              ],
+              [
+                105.670401,
+                30.254208
+              ],
+              [
+                105.720292,
+                30.252657
+              ],
+              [
+                105.720292,
+                30.252657
+              ],
+              [
+                105.714749,
+                30.322939
+              ],
+              [
+                105.754785,
+                30.342567
+              ],
+              [
+                105.760329,
+                30.384393
+              ],
+              [
+                105.792357,
+                30.427234
+              ],
+              [
+                105.825618,
+                30.436006
+              ],
+              [
+                105.84656,
+                30.410203
+              ],
+              [
+                105.900763,
+                30.405042
+              ],
+              [
+                105.943263,
+                30.372002
+              ],
+              [
+                106.031958,
+                30.373551
+              ],
+              [
+                106.07261,
+                30.333786
+              ],
+              [
+                106.132972,
+                30.30279
+              ],
+              [
+                106.132356,
+                30.323972
+              ],
+              [
+                106.168696,
+                30.303823
+              ],
+              [
+                106.180399,
+                30.233011
+              ],
+              [
+                106.232754,
+                30.185947
+              ],
+              [
+                106.260471,
+                30.19681
+              ],
+              [
+                106.260471,
+                30.204051
+              ],
+              [
+                106.260471,
+                30.207672
+              ],
+              [
+                106.264167,
+                30.20974
+              ],
+              [
+                106.296196,
+                30.205603
+              ],
+              [
+                106.306667,
+                30.238182
+              ],
+              [
+                106.334384,
+                30.225772
+              ],
+              [
+                106.349167,
+                30.24542
+              ],
+              [
+                106.401521,
+                30.242318
+              ],
+              [
+                106.428623,
+                30.254725
+              ],
+              [
+                106.43971,
+                30.308473
+              ],
+              [
+                106.49884,
+                30.295556
+              ],
+              [
+                106.545035,
+                30.296589
+              ],
+              [
+                106.560434,
+                30.31519
+              ],
+              [
+                106.611557,
+                30.292455
+              ],
+              [
+                106.642354,
+                30.246454
+              ],
+              [
+                106.612789,
+                30.235596
+              ],
+              [
+                106.612789,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.611557,
+                30.235596
+              ],
+              [
+                106.612173,
+                30.235596
+              ],
+              [
+                106.611557,
+                30.235596
+              ],
+              [
+                106.631883,
+                30.186464
+              ],
+              [
+                106.677462,
+                30.156974
+              ],
+              [
+                106.672535,
+                30.122297
+              ],
+              [
+                106.700252,
+                30.111944
+              ],
+              [
+                106.699636,
+                30.074145
+              ],
+              [
+                106.724274,
+                30.058607
+              ],
+              [
+                106.732281,
+                30.027005
+              ],
+              [
+                106.785252,
+                30.01716
+              ],
+              [
+                106.825904,
+                30.03115
+              ],
+              [
+                106.825904,
+                30.03115
+              ],
+              [
+                106.83699,
+                30.049801
+              ],
+              [
+                106.862244,
+                30.033223
+              ],
+              [
+                106.913367,
+                30.025451
+              ],
+              [
+                106.94478,
+                30.037367
+              ],
+              [
+                106.976193,
+                30.083467
+              ],
+              [
+                106.975577,
+                30.088127
+              ],
+              [
+                106.976809,
+                30.088127
+              ],
+              [
+                106.977425,
+                30.087609
+              ],
+              [
+                106.978656,
+                30.087609
+              ],
+              [
+                106.979888,
+                30.088127
+              ],
+              [
+                106.980504,
+                30.087609
+              ],
+              [
+                106.981736,
+                30.08502
+              ],
+              [
+                107.02054,
+                30.036849
+              ],
+              [
+                107.053801,
+                30.043584
+              ],
+              [
+                107.058113,
+                30.043066
+              ],
+              [
+                107.084598,
+                30.063786
+              ],
+              [
+                107.080286,
+                30.094341
+              ],
+              [
+                107.103076,
+                30.090198
+              ],
+              [
+                107.221337,
+                30.213878
+              ],
+              [
+                107.257677,
+                30.267131
+              ],
+              [
+                107.288474,
+                30.337402
+              ],
+              [
+                107.338981,
+                30.386459
+              ],
+              [
+                107.368546,
+                30.468508
+              ],
+              [
+                107.408582,
+                30.521623
+              ],
+              [
+                107.443075,
+                30.53348
+              ],
+              [
+                107.427676,
+                30.547397
+              ],
+              [
+                107.485575,
+                30.598408
+              ],
+              [
+                107.516987,
+                30.644759
+              ],
+              [
+                107.477567,
+                30.664837
+              ],
+              [
+                107.458473,
+                30.704981
+              ],
+              [
+                107.424597,
+                30.74048
+              ],
+              [
+                107.454162,
+                30.771851
+              ],
+              [
+                107.454162,
+                30.771851
+              ],
+              [
+                107.498509,
+                30.809381
+              ],
+              [
+                107.483111,
+                30.838675
+              ],
+              [
+                107.515756,
+                30.854603
+              ],
+              [
+                107.57735,
+                30.847924
+              ],
+              [
+                107.645103,
+                30.821202
+              ],
+              [
+                107.693146,
+                30.875665
+              ],
+              [
+                107.739957,
+                30.884396
+              ],
+              [
+                107.760899,
+                30.862823
+              ],
+              [
+                107.763979,
+                30.817091
+              ],
+              [
+                107.788001,
+                30.81966
+              ],
+              [
+                107.851443,
+                30.792931
+              ],
+              [
+                107.956152,
+                30.882855
+              ],
+              [
+                107.994956,
+                30.908533
+              ],
+              [
+                107.948145,
+                30.918802
+              ],
+              [
+                107.942602,
+                30.989114
+              ],
+              [
+                107.983254,
+                30.983983
+              ],
+              [
+                108.00358,
+                31.025533
+              ],
+              [
+                108.060246,
+                31.052197
+              ],
+              [
+                108.026985,
+                31.061938
+              ],
+              [
+                108.009123,
+                31.109602
+              ],
+              [
+                108.025753,
+                31.116263
+              ],
+              [
+                108.089811,
+                31.204859
+              ],
+              [
+                108.07626,
+                31.231985
+              ],
+              [
+                108.031297,
+                31.217144
+              ],
+              [
+                108.038688,
+                31.252964
+              ],
+              [
+                108.095354,
+                31.268311
+              ],
+              [
+                108.185898,
+                31.336831
+              ],
+              [
+                108.153869,
+                31.371073
+              ],
+              [
+                108.216079,
+                31.41041
+              ],
+              [
+                108.224086,
+                31.464024
+              ],
+              [
+                108.193289,
+                31.467598
+              ],
+              [
+                108.191441,
+                31.492096
+              ],
+              [
+                108.233941,
+                31.506894
+              ],
+              [
+                108.254883,
+                31.49873
+              ],
+              [
+                108.344194,
+                31.512506
+              ],
+              [
+                108.339266,
+                31.539033
+              ],
+              [
+                108.386078,
+                31.544134
+              ],
+              [
+                108.390389,
+                31.591555
+              ],
+              [
+                108.442744,
+                31.633856
+              ],
+              [
+                108.468614,
+                31.636404
+              ],
+              [
+                108.519121,
+                31.665952
+              ],
+              [
+                108.546838,
+                31.665442
+              ],
+              [
+                108.514809,
+                31.693963
+              ],
+              [
+                108.50557,
+                31.734182
+              ],
+              [
+                108.535135,
+                31.757592
+              ],
+              [
+                108.462454,
+                31.780488
+              ],
+              [
+                108.455063,
+                31.814059
+              ],
+              [
+                108.429194,
+                31.809482
+              ],
+              [
+                108.391005,
+                31.829822
+              ],
+              [
+                108.386078,
+                31.854226
+              ],
+              [
+                108.343578,
+                31.860834
+              ],
+              [
+                108.259194,
+                31.967006
+              ],
+              [
+                108.307238,
+                31.997463
+              ],
+              [
+                108.351585,
+                31.971575
+              ],
+              [
+                108.370063,
+                31.988835
+              ],
+              [
+                108.329411,
+                32.020299
+              ],
+              [
+                108.362056,
+                32.035521
+              ],
+              [
+                108.344194,
+                32.067477
+              ],
+              [
+                108.372527,
+                32.077112
+              ],
+              [
+                108.42981,
+                32.061391
+              ],
+              [
+                108.452599,
+                32.090296
+              ],
+              [
+                108.399628,
+                32.147065
+              ],
+              [
+                108.379303,
+                32.153652
+              ],
+              [
+                108.379303,
+                32.153652
+              ],
+              [
+                108.379918,
+                32.154158
+              ],
+              [
+                108.379918,
+                32.154158
+              ],
+              [
+                108.370063,
+                32.172397
+              ],
+              [
+                108.399013,
+                32.194176
+              ],
+              [
+                108.480317,
+                32.182527
+              ],
+              [
+                108.509882,
+                32.201266
+              ],
+              [
+                108.507418,
+                32.245819
+              ],
+              [
+                108.469846,
+                32.270618
+              ],
+              [
+                108.414411,
+                32.252399
+              ],
+              [
+                108.389773,
+                32.263533
+              ],
+              [
+                108.310933,
+                32.232152
+              ],
+              [
+                108.240716,
+                32.274666
+              ],
+              [
+                108.179738,
+                32.221521
+              ],
+              [
+                108.156948,
+                32.239239
+              ],
+              [
+                108.143398,
+                32.219495
+              ],
+              [
+                108.086731,
+                32.233165
+              ],
+              [
+                108.018362,
+                32.2119
+              ],
+              [
+                108.024521,
+                32.177462
+              ],
+              [
+                107.979558,
+                32.146051
+              ],
+              [
+                107.924739,
+                32.197215
+              ],
+              [
+                107.890247,
+                32.214432
+              ],
+              [
+                107.864377,
+                32.201266
+              ],
+              [
+                107.812022,
+                32.247844
+              ],
+              [
+                107.753508,
+                32.338399
+              ],
+              [
+                107.707929,
+                32.331826
+              ],
+              [
+                107.680827,
+                32.397035
+              ],
+              [
+                107.648183,
+                32.413709
+              ],
+              [
+                107.598291,
+                32.411688
+              ],
+              [
+                107.527458,
+                32.38238
+              ],
+              [
+                107.489886,
+                32.425328
+              ],
+              [
+                107.456625,
+                32.41775
+              ],
+              [
+                107.460937,
+                32.453612
+              ],
+              [
+                107.438763,
+                32.465732
+              ],
+              [
+                107.436299,
+                32.529835
+              ],
+              [
+                107.382097,
+                32.54043
+              ],
+              [
+                107.356843,
+                32.506622
+              ],
+              [
+                107.313727,
+                32.489965
+              ],
+              [
+                107.287858,
+                32.457147
+              ],
+              [
+                107.263836,
+                32.403099
+              ],
+              [
+                107.212097,
+                32.428864
+              ],
+              [
+                107.189924,
+                32.468256
+              ],
+              [
+                107.127098,
+                32.482393
+              ],
+              [
+                107.080286,
+                32.542448
+              ],
+              [
+                107.108004,
+                32.600951
+              ],
+              [
+                107.098765,
+                32.649338
+              ],
+              [
+                107.05996,
+                32.686115
+              ],
+              [
+                107.066736,
+                32.708779
+              ],
+              [
+                107.012533,
+                32.721367
+              ],
+              [
+                106.912751,
+                32.704247
+              ],
+              [
+                106.903512,
+                32.721367
+              ],
+              [
+                106.854853,
+                32.724388
+              ],
+              [
+                106.82344,
+                32.705254
+              ],
+              [
+                106.793259,
+                32.712807
+              ],
+              [
+                106.783404,
+                32.735967
+              ],
+              [
+                106.733513,
+                32.739491
+              ],
+              [
+                106.670071,
+                32.694678
+              ],
+              [
+                106.626955,
+                32.682086
+              ],
+              [
+                106.585687,
+                32.68813
+              ],
+              [
+                106.517934,
+                32.668485
+              ],
+              [
+                106.498224,
+                32.649338
+              ],
+              [
+                106.451412,
+                32.65992
+              ],
+              [
+                106.421231,
+                32.616579
+              ],
+              [
+                106.389203,
+                32.62666
+              ],
+              [
+                106.347935,
+                32.671003
+              ],
+              [
+                106.301123,
+                32.680071
+              ],
+              [
+                106.267863,
+                32.673522
+              ],
+              [
+                106.254928,
+                32.693671
+              ],
+              [
+                106.17424,
+                32.6977
+              ],
+              [
+                106.120037,
+                32.719856
+              ],
+              [
+                106.071378,
+                32.758114
+              ],
+              [
+                106.07261,
+                32.76365
+              ],
+              [
+                106.093552,
+                32.82402
+              ],
+              [
+                106.071378,
+                32.828546
+              ],
+              [
+                106.044277,
+                32.864747
+              ],
+              [
+                106.011632,
+                32.829552
+              ],
+              [
+                105.969132,
+                32.849162
+              ],
+              [
+                105.93156,
+                32.826032
+              ],
+              [
+                105.893371,
+                32.838603
+              ],
+              [
+                105.849024,
+                32.817985
+              ],
+              [
+                105.825002,
+                32.824523
+              ],
+              [
+                105.822538,
+                32.770192
+              ],
+              [
+                105.779423,
+                32.750061
+              ],
+              [
+                105.768952,
+                32.767676
+              ],
+              [
+                105.719061,
+                32.759624
+              ],
+              [
+                105.677793,
+                32.726402
+              ],
+              [
+                105.596489,
+                32.69921
+              ],
+              [
+                105.585402,
+                32.728919
+              ],
+              [
+                105.563844,
+                32.724891
+              ],
+              [
+                105.555221,
+                32.794343
+              ],
+              [
+                105.534279,
+                32.790822
+              ],
+              [
+                105.524424,
+                32.847654
+              ],
+              [
+                105.495475,
+                32.873292
+              ],
+              [
+                105.49917,
+                32.911986
+              ],
+              [
+                105.467757,
+                32.930071
+              ],
+              [
+                105.414171,
+                32.922034
+              ],
+              [
+                105.408011,
+                32.885857
+              ],
+              [
+                105.38091,
+                32.876307
+              ],
+              [
+                105.396308,
+                32.85067
+              ],
+              [
+                105.396308,
+                32.85067
+              ],
+              [
+                105.427721,
+                32.784281
+              ],
+              [
+                105.454207,
+                32.767173
+              ],
+              [
+                105.448663,
+                32.732946
+              ],
+              [
+                105.368591,
+                32.712807
+              ],
+              [
+                105.347033,
+                32.68259
+              ],
+              [
+                105.297758,
+                32.656897
+              ],
+              [
+                105.263265,
+                32.652362
+              ],
+              [
+                105.219534,
+                32.666469
+              ],
+              [
+                105.215222,
+                32.63674
+              ],
+              [
+                105.185041,
+                32.617587
+              ],
+              [
+                105.111128,
+                32.593893
+              ],
+              [
+                105.0791,
+                32.637244
+              ],
+              [
+                105.026745,
+                32.650346
+              ],
+              [
+                104.925115,
+                32.607505
+              ],
+              [
+                104.881999,
+                32.600951
+              ],
+              [
+                104.845659,
+                32.653873
+              ],
+              [
+                104.820405,
+                32.662943
+              ],
+              [
+                104.795768,
+                32.643292
+              ],
+              [
+                104.739717,
+                32.635228
+              ],
+              [
+                104.696601,
+                32.673522
+              ],
+              [
+                104.643015,
+                32.661935
+              ],
+              [
+                104.592508,
+                32.695685
+              ],
+              [
+                104.582653,
+                32.722374
+              ],
+              [
+                104.526602,
+                32.728416
+              ],
+              [
+                104.51182,
+                32.753585
+              ],
+              [
+                104.458849,
+                32.748551
+              ],
+              [
+                104.363994,
+                32.822511
+              ],
+              [
+                104.294393,
+                32.835586
+              ],
+              [
+                104.277147,
+                32.90244
+              ],
+              [
+                104.288234,
+                32.942628
+              ],
+              [
+                104.345516,
+                32.940117
+              ],
+              [
+                104.378161,
+                32.953174
+              ],
+              [
+                104.383704,
+                32.994343
+              ],
+              [
+                104.426204,
+                33.010906
+              ],
+              [
+                104.391711,
+                33.035493
+              ],
+              [
+                104.337509,
+                33.038002
+              ],
+              [
+                104.378161,
+                33.109214
+              ],
+              [
+                104.351059,
+                33.158828
+              ],
+              [
+                104.32827,
+                33.223934
+              ],
+              [
+                104.323958,
+                33.26898
+              ],
+              [
+                104.303632,
+                33.304499
+              ],
+              [
+                104.333813,
+                33.315502
+              ],
+              [
+                104.386168,
+                33.298497
+              ],
+              [
+                104.420045,
+                33.327004
+              ],
+              [
+                104.373849,
+                33.345004
+              ],
+              [
+                104.292545,
+                33.336505
+              ],
+              [
+                104.272219,
+                33.391486
+              ],
+              [
+                104.22048,
+                33.404477
+              ],
+              [
+                104.213089,
+                33.446932
+              ],
+              [
+                104.180444,
+                33.472895
+              ],
+              [
+                104.155191,
+                33.542755
+              ],
+              [
+                104.176749,
+                33.5996
+              ],
+              [
+                104.103452,
+                33.663381
+              ],
+              [
+                104.046169,
+                33.686291
+              ],
+              [
+                103.980264,
+                33.670852
+              ],
+              [
+                103.861388,
+                33.682307
+              ],
+              [
+                103.778236,
+                33.658898
+              ],
+              [
+                103.690772,
+                33.69376
+              ],
+              [
+                103.667983,
+                33.685793
+              ],
+              [
+                103.645809,
+                33.708697
+              ],
+              [
+                103.593454,
+                33.716164
+              ],
+              [
+                103.563889,
+                33.699735
+              ],
+              [
+                103.552186,
+                33.671351
+              ],
+              [
+                103.520157,
+                33.678323
+              ],
+              [
+                103.545411,
+                33.719649
+              ],
+              [
+                103.518309,
+                33.807213
+              ],
+              [
+                103.464723,
+                33.80224
+              ],
+              [
+                103.434542,
+                33.752993
+              ],
+              [
+                103.35447,
+                33.743539
+              ],
+              [
+                103.278709,
+                33.774387
+              ],
+              [
+                103.284868,
+                33.80224
+              ],
+              [
+                103.24976,
+                33.814175
+              ],
+              [
+                103.228202,
+                33.79478
+              ],
+              [
+                103.165376,
+                33.805721
+              ],
+              [
+                103.153673,
+                33.819147
+              ],
+              [
+                103.181391,
+                33.900649
+              ],
+              [
+                103.16476,
+                33.929454
+              ],
+              [
+                103.1315,
+                33.931937
+              ],
+              [
+                103.120413,
+                33.953286
+              ],
+              [
+                103.157369,
+                33.998944
+              ],
+              [
+                103.147514,
+                34.036644
+              ],
+              [
+                103.119797,
+                34.03466
+              ],
+              [
+                103.129652,
+                34.065899
+              ],
+              [
+                103.178927,
+                34.079779
+              ],
+              [
+                103.121644,
+                34.112487
+              ],
+              [
+                103.124108,
+                34.162022
+              ],
+              [
+                103.100087,
+                34.181828
+              ],
+              [
+                103.052043,
+                34.195194
+              ],
+              [
+                103.005848,
+                34.184798
+              ],
+              [
+                102.973203,
+                34.205588
+              ],
+              [
+                102.977515,
+                34.252595
+              ],
+              [
+                102.949181,
+                34.292159
+              ],
+              [
+                102.911609,
+                34.312923
+              ],
+              [
+                102.85987,
+                34.301058
+              ],
+              [
+                102.856791,
+                34.270895
+              ],
+              [
+                102.798276,
+                34.272874
+              ],
+              [
+                102.779798,
+                34.236764
+              ],
+              [
+                102.728675,
+                34.235774
+              ],
+              [
+                102.694799,
+                34.198659
+              ],
+              [
+                102.664002,
+                34.192719
+              ],
+              [
+                102.651067,
+                34.165983
+              ],
+              [
+                102.598712,
+                34.14766
+              ],
+              [
+                102.655994,
+                34.113478
+              ],
+              [
+                102.649219,
+                34.080275
+              ],
+              [
+                102.615958,
+                34.099604
+              ],
+              [
+                102.511865,
+                34.086222
+              ],
+              [
+                102.471213,
+                34.072839
+              ],
+              [
+                102.437336,
+                34.087214
+              ],
+              [
+                102.406539,
+                34.033172
+              ],
+              [
+                102.392372,
+                33.971651
+              ],
+              [
+                102.345561,
+                33.969666
+              ],
+              [
+                102.315996,
+                33.993983
+              ],
+              [
+                102.287047,
+                33.977607
+              ],
+              [
+                102.248858,
+                33.98654
+              ],
+              [
+                102.226069,
+                33.963214
+              ],
+              [
+                102.16817,
+                33.983066
+              ],
+              [
+                102.136142,
+                33.965199
+              ],
+              [
+                102.25317,
+                33.861399
+              ],
+              [
+                102.261177,
+                33.821136
+              ],
+              [
+                102.243315,
+                33.786823
+              ],
+              [
+                102.296286,
+                33.783838
+              ],
+              [
+                102.324619,
+                33.754486
+              ],
+              [
+                102.284583,
+                33.719151
+              ],
+              [
+                102.342481,
+                33.725622
+              ],
+              [
+                102.31538,
+                33.665374
+              ],
+              [
+                102.346793,
+                33.605582
+              ],
+              [
+                102.440416,
+                33.574673
+              ],
+              [
+                102.477988,
+                33.543254
+              ],
+              [
+                102.446575,
+                33.53228
+              ],
+              [
+                102.461358,
+                33.501345
+              ],
+              [
+                102.462589,
+                33.449429
+              ],
+              [
+                102.447807,
+                33.454922
+              ],
+              [
+                102.392988,
+                33.404477
+              ],
+              [
+                102.368967,
+                33.41247
+              ],
+              [
+                102.310452,
+                33.397982
+              ],
+              [
+                102.296286,
+                33.413969
+              ],
+              [
+                102.258098,
+                33.409472
+              ],
+              [
+                102.218062,
+                33.349503
+              ],
+              [
+                102.192192,
+                33.337005
+              ],
+              [
+                102.217446,
+                33.247961
+              ],
+              [
+                102.200815,
+                33.223434
+              ],
+              [
+                102.160163,
+                33.242956
+              ],
+              [
+                102.144765,
+                33.273983
+              ],
+              [
+                102.117047,
+                33.288492
+              ],
+              [
+                102.08933,
+                33.227439
+              ],
+              [
+                102.08933,
+                33.204908
+              ],
+              [
+                102.054838,
+                33.189884
+              ],
+              [
+                101.99386,
+                33.1999
+              ],
+              [
+                101.935345,
+                33.186879
+              ],
+              [
+                101.921795,
+                33.153817
+              ],
+              [
+                101.887302,
+                33.135778
+              ],
+              [
+                101.865744,
+                33.103198
+              ],
+              [
+                101.825708,
+                33.119239
+              ],
+              [
+                101.841723,
+                33.184876
+              ],
+              [
+                101.83002,
+                33.213921
+              ],
+              [
+                101.770274,
+                33.248962
+              ],
+              [
+                101.769658,
+                33.26898
+              ],
+              [
+                101.877447,
+                33.314502
+              ],
+              [
+                101.887302,
+                33.383991
+              ],
+              [
+                101.915635,
+                33.425957
+              ],
+              [
+                101.946432,
+                33.442937
+              ],
+              [
+                101.906396,
+                33.48188
+              ],
+              [
+                101.907012,
+                33.539264
+              ],
+              [
+                101.884222,
+                33.578163
+              ],
+              [
+                101.844186,
+                33.602591
+              ],
+              [
+                101.831252,
+                33.554726
+              ],
+              [
+                101.783208,
+                33.556721
+              ],
+              [
+                101.769042,
+                33.538765
+              ],
+              [
+                101.777665,
+                33.533776
+              ],
+              [
+                101.769042,
+                33.45592
+              ],
+              [
+                101.695745,
+                33.433948
+              ],
+              [
+                101.663716,
+                33.383991
+              ],
+              [
+                101.64955,
+                33.323004
+              ],
+              [
+                101.677883,
+                33.297497
+              ],
+              [
+                101.735781,
+                33.279987
+              ],
+              [
+                101.709912,
+                33.21292
+              ],
+              [
+                101.653861,
+                33.162835
+              ],
+              [
+                101.661252,
+                33.135778
+              ],
+              [
+                101.633535,
+                33.101193
+              ],
+              [
+                101.557775,
+                33.167344
+              ],
+              [
+                101.515275,
+                33.192889
+              ],
+              [
+                101.487557,
+                33.226938
+              ],
+              [
+                101.403174,
+                33.225436
+              ],
+              [
+                101.386543,
+                33.207412
+              ],
+              [
+                101.393935,
+                33.157826
+              ],
+              [
+                101.381616,
+                33.153316
+              ],
+              [
+                101.297232,
+                33.262475
+              ],
+              [
+                101.217776,
+                33.256469
+              ],
+              [
+                101.182668,
+                33.26948
+              ],
+              [
+                101.156798,
+                33.236449
+              ],
+              [
+                101.124769,
+                33.221431
+              ],
+              [
+                101.11553,
+                33.194893
+              ],
+              [
+                101.169733,
+                33.10019
+              ],
+              [
+                101.143863,
+                33.086151
+              ],
+              [
+                101.146327,
+                33.056563
+              ],
+              [
+                101.184515,
+                33.041514
+              ],
+              [
+                101.171581,
+                33.009902
+              ],
+              [
+                101.183899,
+                32.984304
+              ],
+              [
+                101.129081,
+                32.989324
+              ],
+              [
+                101.134624,
+                32.95217
+              ],
+              [
+                101.124153,
+                32.909976
+              ],
+              [
+                101.178356,
+                32.892892
+              ],
+              [
+                101.223935,
+                32.855698
+              ],
+              [
+                101.237486,
+                32.825026
+              ],
+              [
+                101.22332,
+                32.725898
+              ],
+              [
+                101.157414,
+                32.661431
+              ],
+              [
+                101.124769,
+                32.658408
+              ],
+              [
+                101.077342,
+                32.68259
+              ],
+              [
+                101.030531,
+                32.660424
+              ],
+              [
+                100.99727,
+                32.627668
+              ],
+              [
+                100.956618,
+                32.621116
+              ],
+              [
+                100.93198,
+                32.600447
+              ],
+              [
+                100.887633,
+                32.632708
+              ],
+              [
+                100.834046,
+                32.648835
+              ],
+              [
+                100.77122,
+                32.643795
+              ],
+              [
+                100.690532,
+                32.678056
+              ],
+              [
+                100.71209,
+                32.645307
+              ],
+              [
+                100.710242,
+                32.610026
+              ],
+              [
+                100.673286,
+                32.628172
+              ],
+              [
+                100.661583,
+                32.616075
+              ],
+              [
+                100.657887,
+                32.546484
+              ],
+              [
+                100.645568,
+                32.526303
+              ],
+              [
+                100.603069,
+                32.553547
+              ],
+              [
+                100.54517,
+                32.569687
+              ],
+              [
+                100.516837,
+                32.632204
+              ],
+              [
+                100.470026,
+                32.694678
+              ],
+              [
+                100.450932,
+                32.694678
+              ],
+              [
+                100.420135,
+                32.73194
+              ],
+              [
+                100.378251,
+                32.698707
+              ],
+              [
+                100.399193,
+                32.756101
+              ],
+              [
+                100.339447,
+                32.719353
+              ],
+              [
+                100.258759,
+                32.742511
+              ],
+              [
+                100.231041,
+                32.696189
+              ],
+              [
+                100.229809,
+                32.650346
+              ],
+              [
+                100.208252,
+                32.606497
+              ],
+              [
+                100.189773,
+                32.630692
+              ],
+              [
+                100.109701,
+                32.640268
+              ],
+              [
+                100.088143,
+                32.668988
+              ],
+              [
+                100.139266,
+                32.724388
+              ],
+              [
+                100.117093,
+                32.802392
+              ],
+              [
+                100.123252,
+                32.837095
+              ],
+              [
+                100.064738,
+                32.895907
+              ],
+              [
+                100.029629,
+                32.895907
+              ],
+              [
+                100.038252,
+                32.929066
+              ],
+              [
+                99.956332,
+                32.948152
+              ],
+              [
+                99.947709,
+                32.986814
+              ],
+              [
+                99.877492,
+                33.045527
+              ],
+              [
+                99.877492,
+                32.993339
+              ],
+              [
+                99.851007,
+                32.941623
+              ],
+              [
+                99.805427,
+                32.940619
+              ],
+              [
+                99.788181,
+                32.956689
+              ],
+              [
+                99.764159,
+                32.924545
+              ],
+              [
+                99.791877,
+                32.883344
+              ],
+              [
+                99.766623,
+                32.826032
+              ],
+              [
+                99.760464,
+                32.769689
+              ],
+              [
+                99.717964,
+                32.732443
+              ],
+              [
+                99.700718,
+                32.76667
+              ],
+              [
+                99.646515,
+                32.774721
+              ],
+              [
+                99.640355,
+                32.790822
+              ],
+              [
+                99.589233,
+                32.789312
+              ],
+              [
+                99.558436,
+                32.839106
+              ],
+              [
+                99.45311,
+                32.862233
+              ],
+              [
+                99.376118,
+                32.899927
+              ],
+              [
+                99.353944,
+                32.885354
+              ],
+              [
+                99.268944,
+                32.878318
+              ],
+              [
+                99.24677,
+                32.924043
+              ],
+              [
+                99.235067,
+                32.982296
+              ],
+              [
+                99.214741,
+                32.991332
+              ],
+              [
+                99.196263,
+                33.035493
+              ],
+              [
+                99.124814,
+                33.046028
+              ],
+              [
+                99.090322,
+                33.079131
+              ],
+              [
+                99.024416,
+                33.094675
+              ],
+              [
+                99.014561,
+                33.081137
+              ],
+              [
+                98.971445,
+                33.098185
+              ],
+              [
+                98.967134,
+                33.115229
+              ],
+              [
+                98.92217,
+                33.118738
+              ],
+              [
+                98.858728,
+                33.150811
+              ],
+              [
+                98.804526,
+                33.219428
+              ],
+              [
+                98.802062,
+                33.270481
+              ],
+              [
+                98.759562,
+                33.276985
+              ],
+              [
+                98.779888,
+                33.370497
+              ],
+              [
+                98.736157,
+                33.406975
+              ],
+              [
+                98.742316,
+                33.477887
+              ],
+              [
+                98.725686,
+                33.503341
+              ],
+              [
+                98.678258,
+                33.522801
+              ],
+              [
+                98.648077,
+                33.548741
+              ],
+              [
+                98.652389,
+                33.595114
+              ],
+              [
+                98.622824,
+                33.610067
+              ],
+              [
+                98.61728,
+                33.637476
+              ],
+              [
+                98.6567,
+                33.64744
+              ],
+              [
+                98.610505,
+                33.682805
+              ],
+              [
+                98.582788,
+                33.731595
+              ],
+              [
+                98.539672,
+                33.746525
+              ],
+              [
+                98.51873,
+                33.77389
+              ],
+              [
+                98.494092,
+                33.768915
+              ],
+              [
+                98.492861,
+                33.796272
+              ],
+              [
+                98.463295,
+                33.848477
+              ],
+              [
+                98.434962,
+                33.843009
+              ],
+              [
+                98.407245,
+                33.867362
+              ],
+              [
+                98.425723,
+                33.913066
+              ],
+              [
+                98.415252,
+                33.956761
+              ],
+              [
+                98.440506,
+                33.981577
+              ],
+              [
+                98.428187,
+                34.029204
+              ],
+              [
+                98.396774,
+                34.053008
+              ],
+              [
+                98.399854,
+                34.085231
+              ],
+              [
+                98.344419,
+                34.094648
+              ],
+              [
+                98.258188,
+                34.083249
+              ],
+              [
+                98.206449,
+                34.08424
+              ],
+              [
+                98.158405,
+                34.107037
+              ],
+              [
+                98.098043,
+                34.122892
+              ],
+              [
+                98.028442,
+                34.122892
+              ],
+              [
+                97.95453,
+                34.190739
+              ],
+              [
+                97.898479,
+                34.209548
+              ],
+              [
+                97.8104,
+                34.207568
+              ],
+              [
+                97.796849,
+                34.199154
+              ],
+              [
+                97.796849,
+                34.199154
+              ],
+              [
+                97.789458,
+                34.182818
+              ],
+              [
+                97.789458,
+                34.182818
+              ],
+              [
+                97.766668,
+                34.158555
+              ],
+              [
+                97.665654,
+                34.126855
+              ],
+              [
+                97.70261,
+                34.036644
+              ],
+              [
+                97.652719,
+                33.998448
+              ],
+              [
+                97.660111,
+                33.956264
+              ],
+              [
+                97.629314,
+                33.919523
+              ],
+              [
+                97.601596,
+                33.929951
+              ],
+              [
+                97.52214,
+                33.903133
+              ],
+              [
+                97.503662,
+                33.912073
+              ],
+              [
+                97.460546,
+                33.887236
+              ],
+              [
+                97.395257,
+                33.889224
+              ],
+              [
+                97.398336,
+                33.848477
+              ],
+              [
+                97.371851,
+                33.842015
+              ],
+              [
+                97.373083,
+                33.817655
+              ],
+              [
+                97.406344,
+                33.795278
+              ],
+              [
+                97.422974,
+                33.754984
+              ],
+              [
+                97.418046,
+                33.728608
+              ],
+              [
+                97.435293,
+                33.682307
+              ],
+              [
+                97.415583,
+                33.605582
+              ],
+              [
+                97.450075,
+                33.582152
+              ],
+              [
+                97.523372,
+                33.577166
+              ],
+              [
+                97.511669,
+                33.520805
+              ],
+              [
+                97.552321,
+                33.465906
+              ],
+              [
+                97.625618,
+                33.461412
+              ],
+              [
+                97.674893,
+                33.432949
+              ],
+              [
+                97.754349,
+                33.409972
+              ],
+              [
+                97.676125,
+                33.341004
+              ],
+              [
+                97.622538,
+                33.337005
+              ],
+              [
+                97.607756,
+                33.263976
+              ],
+              [
+                97.548626,
+                33.203907
+              ],
+              [
+                97.487648,
+                33.168346
+              ],
+              [
+                97.498119,
+                33.137783
+              ],
+              [
+                97.487032,
+                33.107209
+              ],
+              [
+                97.517213,
+                33.097683
+              ],
+              [
+                97.542466,
+                33.035995
+              ],
+              [
+                97.499966,
+                33.011408
+              ],
+              [
+                97.523988,
+                32.988822
+              ],
+              [
+                97.438372,
+                32.976271
+              ],
+              [
+                97.375547,
+                32.956689
+              ],
+              [
+                97.347829,
+                32.895907
+              ],
+              [
+                97.376163,
+                32.886359
+              ],
+              [
+                97.392793,
+                32.828546
+              ],
+              [
+                97.386018,
+                32.77925
+              ],
+              [
+                97.429133,
+                32.714318
+              ],
+              [
+                97.42359,
+                32.70475
+              ],
+              [
+                97.48272,
+                32.654377
+              ],
+              [
+                97.535075,
+                32.638252
+              ],
+              [
+                97.543698,
+                32.62162
+              ],
+              [
+                97.607756,
+                32.614059
+              ],
+              [
+                97.616995,
+                32.586329
+              ],
+              [
+                97.700763,
+                32.53488
+              ],
+              [
+                97.730944,
+                32.527312
+              ],
+              [
+                97.795617,
+                32.521257
+              ],
+              [
+                97.80732,
+                32.50006
+              ],
+              [
+                97.863986,
+                32.499051
+              ],
+              [
+                97.880001,
+                32.486431
+              ],
+              [
+                97.940363,
+                32.482393
+              ],
+              [
+                98.079565,
+                32.415224
+              ],
+              [
+                98.107283,
+                32.391476
+              ],
+              [
+                98.125145,
+                32.401077
+              ],
+              [
+                98.218768,
+                32.342444
+              ],
+              [
+                98.208913,
+                32.318171
+              ],
+              [
+                98.23047,
+                32.262521
+              ],
+              [
+                98.218768,
+                32.234683
+              ],
+              [
+                98.260035,
+                32.208862
+              ],
+              [
+                98.303151,
+                32.121726
+              ],
+              [
+                98.357354,
+                32.087253
+              ],
+              [
+                98.404781,
+                32.045159
+              ],
+              [
+                98.402933,
+                32.026896
+              ],
+              [
+                98.434962,
+                32.007613
+              ],
+              [
+                98.432498,
+                31.922825
+              ],
+              [
+                98.399238,
+                31.895899
+              ],
+              [
+                98.426339,
+                31.856767
+              ],
+              [
+                98.414636,
+                31.832365
+              ],
+              [
+                98.461448,
+                31.800327
+              ],
+              [
+                98.508875,
+                31.751995
+              ],
+              [
+                98.516882,
+                31.717383
+              ],
+              [
+                98.545831,
+                31.717383
+              ],
+              [
+                98.553839,
+                31.660349
+              ],
+              [
+                98.619128,
+                31.591555
+              ],
+              [
+                98.651157,
+                31.57881
+              ],
+              [
+                98.696736,
+                31.538523
+              ],
+              [
+                98.714599,
+                31.508935
+              ],
+              [
+                98.844562,
+                31.429817
+              ],
+              [
+                98.84333,
+                31.416028
+              ],
+              [
+                98.887062,
+                31.37465
+              ],
+              [
+                98.810685,
+                31.306668
+              ],
+              [
+                98.805758,
+                31.279052
+              ],
+              [
+                98.773113,
+                31.249382
+              ],
+              [
+                98.691809,
+                31.333253
+              ],
+              [
+                98.643766,
+                31.338876
+              ],
+              [
+                98.616048,
+                31.3036
+              ],
+              [
+                98.60373,
+                31.257568
+              ],
+              [
+                98.62344,
+                31.221238
+              ],
+              [
+                98.602498,
+                31.192062
+              ],
+              [
+                98.675179,
+                31.15417
+              ],
+              [
+                98.710287,
+                31.1178
+              ],
+              [
+                98.712135,
+                31.082954
+              ],
+              [
+                98.736772,
+                31.049121
+              ],
+              [
+                98.774961,
+                31.031174
+              ],
+              [
+                98.806374,
+                30.995783
+              ],
+              [
+                98.797135,
+                30.948575
+              ],
+              [
+                98.774345,
+                30.908019
+              ],
+              [
+                98.797135,
+                30.87926
+              ],
+              [
+                98.850105,
+                30.849465
+              ],
+              [
+                98.904924,
+                30.782649
+              ],
+              [
+                98.957895,
+                30.765166
+              ],
+              [
+                98.963438,
+                30.728134
+              ],
+              [
+                98.907388,
+                30.698292
+              ],
+              [
+                98.92217,
+                30.609225
+              ],
+              [
+                98.939417,
+                30.598923
+              ],
+              [
+                98.926482,
+                30.569556
+              ],
+              [
+                98.932025,
+                30.521623
+              ],
+              [
+                98.965286,
+                30.449937
+              ],
+              [
+                98.967134,
+                30.33482
+              ],
+              [
+                98.986844,
+                30.280569
+              ],
+              [
+                98.970829,
+                30.260928
+              ],
+              [
+                98.993003,
+                30.215429
+              ],
+              [
+                98.9813,
+                30.182843
+              ],
+              [
+                98.989308,
+                30.151799
+              ],
+              [
+                99.044742,
+                30.079842
+              ],
+              [
+                99.036735,
+                30.053945
+              ],
+              [
+                99.055213,
+                29.958587
+              ],
+              [
+                99.068148,
+                29.931621
+              ],
+              [
+                99.0238,
+                29.846009
+              ],
+              [
+                99.018873,
+                29.792009
+              ],
+              [
+                98.992387,
+                29.677163
+              ],
+              [
+                99.014561,
+                29.607464
+              ],
+              [
+                99.052133,
+                29.563748
+              ],
+              [
+                99.044742,
+                29.520013
+              ],
+              [
+                99.066916,
+                29.421018
+              ],
+              [
+                99.058909,
+                29.417368
+              ],
+              [
+                99.075539,
+                29.316186
+              ],
+              [
+                99.114343,
+                29.243628
+              ],
+              [
+                99.113727,
+                29.221171
+              ],
+              [
+                99.105104,
+                29.162656
+              ],
+              [
+                99.118039,
+                29.100971
+              ],
+              [
+                99.113727,
+                29.07273
+              ],
+              [
+                99.132206,
+                28.94869
+              ],
+              [
+                99.123582,
+                28.890021
+              ],
+              [
+                99.103872,
+                28.841803
+              ],
+              [
+                99.114343,
+                28.765763
+              ],
+              [
+                99.134053,
+                28.734806
+              ],
+              [
+                99.126662,
+                28.698066
+              ],
+              [
+                99.147604,
+                28.640831
+              ],
+              [
+                99.183944,
+                28.58882
+              ],
+              [
+                99.170394,
+                28.566221
+              ],
+              [
+                99.191952,
+                28.494714
+              ],
+              [
+                99.187024,
+                28.44
+              ],
+              [
+                99.16485,
+                28.425264
+              ],
+              [
+                99.200575,
+                28.365774
+              ],
+              [
+                99.229524,
+                28.350502
+              ],
+              [
+                99.237531,
+                28.317842
+              ],
+              [
+                99.28927,
+                28.286227
+              ],
+              [
+                99.306516,
+                28.227714
+              ],
+              [
+                99.374886,
+                28.18183
+              ],
+              [
+                99.412458,
+                28.295186
+              ],
+              [
+                99.392748,
+                28.318369
+              ],
+              [
+                99.437095,
+                28.398419
+              ],
+              [
+                99.404451,
+                28.44421
+              ],
+              [
+                99.426625,
+                28.454207
+              ],
+              [
+                99.396444,
+                28.491032
+              ],
+              [
+                99.403219,
+                28.546246
+              ],
+              [
+                99.463581,
+                28.549401
+              ],
+              [
+                99.466045,
+                28.579886
+              ],
+              [
+                99.504233,
+                28.619294
+              ],
+              [
+                99.540573,
+                28.623497
+              ],
+              [
+                99.53195,
+                28.677591
+              ],
+              [
+                99.553508,
+                28.710664
+              ],
+              [
+                99.614486,
+                28.740054
+              ],
+              [
+                99.609559,
+                28.784122
+              ],
+              [
+                99.625573,
+                28.81454
+              ],
+              [
+                99.676696,
+                28.810345
+              ],
+              [
+                99.717964,
+                28.846521
+              ],
+              [
+                99.722275,
+                28.757369
+              ],
+              [
+                99.755536,
+                28.701216
+              ],
+              [
+                99.79434,
+                28.699116
+              ],
+              [
+                99.834992,
+                28.660788
+              ],
+              [
+                99.834376,
+                28.628225
+              ],
+              [
+                99.873181,
+                28.631902
+              ],
+              [
+                99.875644,
+                28.611939
+              ],
+              [
+                99.91876,
+                28.599329
+              ],
+              [
+                99.985281,
+                28.529422
+              ],
+              [
+                99.990209,
+                28.47683
+              ],
+              [
+                100.073977,
+                28.426317
+              ],
+              [
+                100.057346,
+                28.368934
+              ],
+              [
+                100.136803,
+                28.349975
+              ],
+              [
+                100.176223,
+                28.325218
+              ],
+              [
+                100.147274,
+                28.288862
+              ],
+              [
+                100.188541,
+                28.252493
+              ],
+              [
+                100.153433,
+                28.208202
+              ],
+              [
+                100.102926,
+                28.201873
+              ],
+              [
+                100.091223,
+                28.181302
+              ],
+              [
+                100.062274,
+                28.193962
+              ],
+              [
+                100.033325,
+                28.184467
+              ],
+              [
+                100.021006,
+                28.147008
+              ],
+              [
+                100.05673,
+                28.097922
+              ],
+              [
+                100.088759,
+                28.029269
+              ],
+              [
+                100.120788,
+                28.018703
+              ],
+              [
+                100.196549,
+                27.936254
+              ],
+              [
+                100.170063,
+                27.907699
+              ],
+              [
+                100.210715,
+                27.87702
+              ],
+              [
+                100.30865,
+                27.861149
+              ],
+              [
+                100.30865,
+                27.830457
+              ],
+              [
+                100.28586,
+                27.80611
+              ],
+              [
+                100.304954,
+                27.788639
+              ],
+              [
+                100.311729,
+                27.724028
+              ],
+              [
+                100.327744,
+                27.72032
+              ],
+              [
+                100.350534,
+                27.755809
+              ],
+              [
+                100.412127,
+                27.816167
+              ],
+              [
+                100.442924,
+                27.86644
+              ],
+              [
+                100.504518,
+                27.852154
+              ],
+              [
+                100.511294,
+                27.827811
+              ],
+              [
+                100.54517,
+                27.809286
+              ],
+              [
+                100.609228,
+                27.859033
+              ],
+              [
+                100.634482,
+                27.915631
+              ],
+              [
+                100.681293,
+                27.923035
+              ],
+              [
+                100.719481,
+                27.858503
+              ],
+              [
+                100.707162,
+                27.800816
+              ],
+              [
+                100.757053,
+                27.770107
+              ],
+              [
+                100.775532,
+                27.743098
+              ],
+              [
+                100.782307,
+                27.691708
+              ],
+              [
+                100.848212,
+                27.672099
+              ],
+              [
+                100.827886,
+                27.615904
+              ],
+              [
+                100.854988,
+                27.623858
+              ],
+              [
+                100.91227,
+                27.521473
+              ],
+              [
+                100.901183,
+                27.453517
+              ],
+              [
+                100.936908,
+                27.469448
+              ],
+              [
+                100.95169,
+                27.426961
+              ],
+              [
+                101.021907,
+                27.332899
+              ],
+              [
+                101.026219,
+                27.270679
+              ],
+              [
+                101.042233,
+                27.22173
+              ],
+              [
+                101.071798,
+                27.194585
+              ],
+              [
+                101.119226,
+                27.208957
+              ],
+              [
+                101.167885,
+                27.198311
+              ],
+              [
+                101.167885,
+                27.198311
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.264167,
+                30.20974
+              ],
+              [
+                106.260471,
+                30.207672
+              ],
+              [
+                106.260471,
+                30.204051
+              ],
+              [
+                106.260471,
+                30.19681
+              ],
+              [
+                106.264167,
+                30.20974
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.976809,
+                30.088127
+              ],
+              [
+                106.975577,
+                30.088127
+              ],
+              [
+                106.976193,
+                30.083467
+              ],
+              [
+                106.981736,
+                30.08502
+              ],
+              [
+                106.980504,
+                30.087609
+              ],
+              [
+                106.979888,
+                30.088127
+              ],
+              [
+                106.978656,
+                30.087609
+              ],
+              [
+                106.977425,
+                30.087609
+              ],
+              [
+                106.976809,
+                30.088127
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                105.558916,
+                30.18543
+              ],
+              [
+                105.556453,
+                30.187499
+              ],
+              [
+                105.550909,
+                30.179222
+              ],
+              [
+                105.56138,
+                30.183878
+              ],
+              [
+                105.558916,
+                30.18543
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 520000,
+        "name": "璐靛窞鐪�",
+        "center": [
+          106.713478,
+          26.578343
+        ],
+        "centroid": [
+          106.880455,
+          26.826368
+        ],
+        "childrenNum": 9,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 23,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                109.274262,
+                28.494714
+              ],
+              [
+                109.23361,
+                28.474726
+              ],
+              [
+                109.191726,
+                28.471043
+              ],
+              [
+                109.153538,
+                28.417369
+              ],
+              [
+                109.152306,
+                28.349975
+              ],
+              [
+                109.117198,
+                28.277795
+              ],
+              [
+                109.081473,
+                28.247749
+              ],
+              [
+                109.101799,
+                28.202401
+              ],
+              [
+                109.086401,
+                28.184467
+              ],
+              [
+                109.026655,
+                28.220331
+              ],
+              [
+                109.005713,
+                28.162837
+              ],
+              [
+                108.929952,
+                28.19027
+              ],
+              [
+                108.923793,
+                28.217167
+              ],
+              [
+                108.89546,
+                28.219804
+              ],
+              [
+                108.855424,
+                28.199764
+              ],
+              [
+                108.821547,
+                28.245113
+              ],
+              [
+                108.772888,
+                28.212949
+              ],
+              [
+                108.738395,
+                28.228241
+              ],
+              [
+                108.726692,
+                28.282011
+              ],
+              [
+                108.761801,
+                28.304143
+              ],
+              [
+                108.783359,
+                28.380518
+              ],
+              [
+                108.759953,
+                28.389995
+              ],
+              [
+                108.780279,
+                28.42579
+              ],
+              [
+                108.746402,
+                28.45105
+              ],
+              [
+                108.709446,
+                28.501026
+              ],
+              [
+                108.700207,
+                28.48209
+              ],
+              [
+                108.657091,
+                28.47683
+              ],
+              [
+                108.640461,
+                28.456838
+              ],
+              [
+                108.688504,
+                28.422106
+              ],
+              [
+                108.697127,
+                28.401051
+              ],
+              [
+                108.656475,
+                28.359981
+              ],
+              [
+                108.667562,
+                28.334173
+              ],
+              [
+                108.611512,
+                28.324691
+              ],
+              [
+                108.580099,
+                28.343128
+              ],
+              [
+                108.576403,
+                28.38631
+              ],
+              [
+                108.609048,
+                28.407368
+              ],
+              [
+                108.609664,
+                28.43579
+              ],
+              [
+                108.586874,
+                28.463678
+              ],
+              [
+                108.573939,
+                28.531
+              ],
+              [
+                108.610896,
+                28.539412
+              ],
+              [
+                108.604736,
+                28.590922
+              ],
+              [
+                108.636149,
+                28.621396
+              ],
+              [
+                108.575787,
+                28.659738
+              ],
+              [
+                108.50249,
+                28.63768
+              ],
+              [
+                108.501258,
+                28.626649
+              ],
+              [
+                108.439049,
+                28.634003
+              ],
+              [
+                108.332491,
+                28.679166
+              ],
+              [
+                108.347274,
+                28.736381
+              ],
+              [
+                108.385462,
+                28.772058
+              ],
+              [
+                108.386078,
+                28.803003
+              ],
+              [
+                108.352817,
+                28.815589
+              ],
+              [
+                108.346658,
+                28.859625
+              ],
+              [
+                108.357745,
+                28.893165
+              ],
+              [
+                108.345426,
+                28.943453
+              ],
+              [
+                108.319556,
+                28.961258
+              ],
+              [
+                108.297999,
+                29.045527
+              ],
+              [
+                108.306622,
+                29.079006
+              ],
+              [
+                108.277673,
+                29.091558
+              ],
+              [
+                108.256115,
+                29.040295
+              ],
+              [
+                108.193289,
+                29.072207
+              ],
+              [
+                108.150173,
+                29.053375
+              ],
+              [
+                108.070717,
+                29.086328
+              ],
+              [
+                108.026369,
+                29.039772
+              ],
+              [
+                107.925971,
+                29.032446
+              ],
+              [
+                107.908725,
+                29.007327
+              ],
+              [
+                107.882855,
+                29.00628
+              ],
+              [
+                107.867457,
+                28.960211
+              ],
+              [
+                107.810175,
+                28.984295
+              ],
+              [
+                107.823725,
+                29.034016
+              ],
+              [
+                107.784921,
+                29.048143
+              ],
+              [
+                107.810791,
+                29.139137
+              ],
+              [
+                107.749197,
+                29.199754
+              ],
+              [
+                107.700537,
+                29.141228
+              ],
+              [
+                107.659885,
+                29.162656
+              ],
+              [
+                107.605683,
+                29.164747
+              ],
+              [
+                107.589052,
+                29.150113
+              ],
+              [
+                107.570574,
+                29.218037
+              ],
+              [
+                107.486806,
+                29.174153
+              ],
+              [
+                107.441227,
+                29.203934
+              ],
+              [
+                107.401807,
+                29.184603
+              ],
+              [
+                107.408582,
+                29.138091
+              ],
+              [
+                107.427676,
+                29.128682
+              ],
+              [
+                107.412278,
+                29.094696
+              ],
+              [
+                107.369778,
+                29.091558
+              ],
+              [
+                107.395647,
+                29.041341
+              ],
+              [
+                107.364235,
+                29.00942
+              ],
+              [
+                107.396879,
+                28.993718
+              ],
+              [
+                107.412894,
+                28.960211
+              ],
+              [
+                107.441227,
+                28.943977
+              ],
+              [
+                107.41351,
+                28.911502
+              ],
+              [
+                107.383945,
+                28.848618
+              ],
+              [
+                107.339597,
+                28.845997
+              ],
+              [
+                107.327894,
+                28.810869
+              ],
+              [
+                107.261373,
+                28.792514
+              ],
+              [
+                107.24659,
+                28.76209
+              ],
+              [
+                107.219489,
+                28.772582
+              ],
+              [
+                107.210866,
+                28.817686
+              ],
+              [
+                107.227496,
+                28.836037
+              ],
+              [
+                107.194851,
+                28.838134
+              ],
+              [
+                107.206554,
+                28.868535
+              ],
+              [
+                107.14188,
+                28.887925
+              ],
+              [
+                107.016229,
+                28.882685
+              ],
+              [
+                107.019308,
+                28.861722
+              ],
+              [
+                106.983584,
+                28.851239
+              ],
+              [
+                106.988512,
+                28.776254
+              ],
+              [
+                106.951555,
+                28.766812
+              ],
+              [
+                106.923222,
+                28.809821
+              ],
+              [
+                106.872099,
+                28.777304
+              ],
+              [
+                106.845614,
+                28.780975
+              ],
+              [
+                106.824056,
+                28.756319
+              ],
+              [
+                106.86594,
+                28.690192
+              ],
+              [
+                106.889345,
+                28.695966
+              ],
+              [
+                106.866556,
+                28.624548
+              ],
+              [
+                106.830831,
+                28.623497
+              ],
+              [
+                106.807425,
+                28.589346
+              ],
+              [
+                106.784636,
+                28.626649
+              ],
+              [
+                106.756918,
+                28.607211
+              ],
+              [
+                106.77786,
+                28.563068
+              ],
+              [
+                106.73844,
+                28.554657
+              ],
+              [
+                106.726121,
+                28.51838
+              ],
+              [
+                106.747063,
+                28.467361
+              ],
+              [
+                106.708259,
+                28.450524
+              ],
+              [
+                106.697788,
+                28.47683
+              ],
+              [
+                106.632499,
+                28.503655
+              ],
+              [
+                106.564745,
+                28.485247
+              ],
+              [
+                106.567825,
+                28.523638
+              ],
+              [
+                106.615252,
+                28.549401
+              ],
+              [
+                106.606629,
+                28.593024
+              ],
+              [
+                106.63681,
+                28.622972
+              ],
+              [
+                106.618332,
+                28.645033
+              ],
+              [
+                106.651593,
+                28.649235
+              ],
+              [
+                106.617716,
+                28.66709
+              ],
+              [
+                106.6171,
+                28.691242
+              ],
+              [
+                106.587535,
+                28.691767
+              ],
+              [
+                106.56105,
+                28.719062
+              ],
+              [
+                106.561666,
+                28.756319
+              ],
+              [
+                106.474202,
+                28.832891
+              ],
+              [
+                106.45326,
+                28.817162
+              ],
+              [
+                106.461883,
+                28.761041
+              ],
+              [
+                106.492064,
+                28.742153
+              ],
+              [
+                106.528405,
+                28.677591
+              ],
+              [
+                106.502535,
+                28.661313
+              ],
+              [
+                106.49268,
+                28.591448
+              ],
+              [
+                106.466811,
+                28.586193
+              ],
+              [
+                106.504999,
+                28.544669
+              ],
+              [
+                106.477282,
+                28.530474
+              ],
+              [
+                106.403369,
+                28.569901
+              ],
+              [
+                106.37442,
+                28.525742
+              ],
+              [
+                106.379348,
+                28.479986
+              ],
+              [
+                106.349167,
+                28.473674
+              ],
+              [
+                106.304819,
+                28.505233
+              ],
+              [
+                106.2925,
+                28.537309
+              ],
+              [
+                106.254928,
+                28.539412
+              ],
+              [
+                106.184711,
+                28.58882
+              ],
+              [
+                106.17116,
+                28.629275
+              ],
+              [
+                106.14837,
+                28.642932
+              ],
+              [
+                106.103407,
+                28.636104
+              ],
+              [
+                106.085544,
+                28.681792
+              ],
+              [
+                106.030726,
+                28.694917
+              ],
+              [
+                106.001161,
+                28.743727
+              ],
+              [
+                105.966668,
+                28.761041
+              ],
+              [
+                105.937719,
+                28.686517
+              ],
+              [
+                105.889676,
+                28.670765
+              ],
+              [
+                105.884748,
+                28.595126
+              ],
+              [
+                105.808372,
+                28.599855
+              ],
+              [
+                105.78435,
+                28.610889
+              ],
+              [
+                105.757249,
+                28.590397
+              ],
+              [
+                105.74493,
+                28.616668
+              ],
+              [
+                105.712901,
+                28.586718
+              ],
+              [
+                105.693191,
+                28.58882
+              ],
+              [
+                105.68272,
+                28.534154
+              ],
+              [
+                105.62359,
+                28.517854
+              ],
+              [
+                105.612503,
+                28.438947
+              ],
+              [
+                105.643916,
+                28.431053
+              ],
+              [
+                105.655003,
+                28.362615
+              ],
+              [
+                105.639604,
+                28.324164
+              ],
+              [
+                105.68888,
+                28.284119
+              ],
+              [
+                105.730147,
+                28.271997
+              ],
+              [
+                105.737539,
+                28.30309
+              ],
+              [
+                105.76464,
+                28.308359
+              ],
+              [
+                105.76464,
+                28.308359
+              ],
+              [
+                105.78743,
+                28.335753
+              ],
+              [
+                105.824386,
+                28.306251
+              ],
+              [
+                105.848408,
+                28.255656
+              ],
+              [
+                105.889676,
+                28.237732
+              ],
+              [
+                105.860727,
+                28.159672
+              ],
+              [
+                105.895219,
+                28.119565
+              ],
+              [
+                105.943878,
+                28.143314
+              ],
+              [
+                105.975907,
+                28.107952
+              ],
+              [
+                106.093552,
+                28.162837
+              ],
+              [
+                106.145291,
+                28.162837
+              ],
+              [
+                106.206885,
+                28.134343
+              ],
+              [
+                106.266631,
+                28.066769
+              ],
+              [
+                106.246305,
+                28.011835
+              ],
+              [
+                106.286341,
+                28.007079
+              ],
+              [
+                106.328225,
+                27.952643
+              ],
+              [
+                106.307899,
+                27.936782
+              ],
+              [
+                106.304819,
+                27.899237
+              ],
+              [
+                106.325145,
+                27.898708
+              ],
+              [
+                106.337464,
+                27.859033
+              ],
+              [
+                106.306667,
+                27.808756
+              ],
+              [
+                106.242609,
+                27.767459
+              ],
+              [
+                106.193334,
+                27.75422
+              ],
+              [
+                106.120653,
+                27.779638
+              ],
+              [
+                106.063987,
+                27.776991
+              ],
+              [
+                106.023335,
+                27.746805
+              ],
+              [
+                105.985146,
+                27.749983
+              ],
+              [
+                105.92848,
+                27.729855
+              ],
+              [
+                105.922937,
+                27.746805
+              ],
+              [
+                105.868118,
+                27.732504
+              ],
+              [
+                105.848408,
+                27.707074
+              ],
+              [
+                105.76772,
+                27.7182
+              ],
+              [
+                105.722756,
+                27.706015
+              ],
+              [
+                105.720292,
+                27.683759
+              ],
+              [
+                105.664242,
+                27.683759
+              ],
+              [
+                105.62359,
+                27.666269
+              ],
+              [
+                105.605112,
+                27.715552
+              ],
+              [
+                105.560148,
+                27.71979
+              ],
+              [
+                105.508409,
+                27.769048
+              ],
+              [
+                105.44004,
+                27.775402
+              ],
+              [
+                105.353809,
+                27.748924
+              ],
+              [
+                105.308229,
+                27.704955
+              ],
+              [
+                105.29591,
+                27.631811
+              ],
+              [
+                105.304533,
+                27.611661
+              ],
+              [
+                105.25649,
+                27.582491
+              ],
+              [
+                105.232469,
+                27.546945
+              ],
+              [
+                105.260186,
+                27.514573
+              ],
+              [
+                105.234316,
+                27.489093
+              ],
+              [
+                105.233084,
+                27.436522
+              ],
+              [
+                105.182577,
+                27.367451
+              ],
+              [
+                105.184425,
+                27.392959
+              ],
+              [
+                105.120984,
+                27.418461
+              ],
+              [
+                105.068013,
+                27.418461
+              ],
+              [
+                105.01073,
+                27.379143
+              ],
+              [
+                104.913412,
+                27.327051
+              ],
+              [
+                104.871528,
+                27.290891
+              ],
+              [
+                104.851818,
+                27.299401
+              ],
+              [
+                104.856746,
+                27.332368
+              ],
+              [
+                104.824717,
+                27.3531
+              ],
+              [
+                104.77113,
+                27.317481
+              ],
+              [
+                104.7545,
+                27.345658
+              ],
+              [
+                104.611602,
+                27.306846
+              ],
+              [
+                104.570334,
+                27.331836
+              ],
+              [
+                104.539537,
+                27.327583
+              ],
+              [
+                104.497037,
+                27.414743
+              ],
+              [
+                104.467472,
+                27.414211
+              ],
+              [
+                104.363378,
+                27.467855
+              ],
+              [
+                104.30856,
+                27.407305
+              ],
+              [
+                104.295625,
+                27.37436
+              ],
+              [
+                104.247582,
+                27.336621
+              ],
+              [
+                104.248813,
+                27.291955
+              ],
+              [
+                104.210625,
+                27.297273
+              ],
+              [
+                104.173053,
+                27.263232
+              ],
+              [
+                104.113923,
+                27.338216
+              ],
+              [
+                104.084358,
+                27.330773
+              ],
+              [
+                104.01722,
+                27.383926
+              ],
+              [
+                104.015372,
+                27.429086
+              ],
+              [
+                103.956242,
+                27.425367
+              ],
+              [
+                103.932221,
+                27.443958
+              ],
+              [
+                103.905119,
+                27.38552
+              ],
+              [
+                103.903271,
+                27.347785
+              ],
+              [
+                103.874322,
+                27.331304
+              ],
+              [
+                103.865699,
+                27.28185
+              ],
+              [
+                103.80041,
+                27.26536
+              ],
+              [
+                103.801641,
+                27.250464
+              ],
+              [
+                103.748671,
+                27.210021
+              ],
+              [
+                103.696316,
+                27.126429
+              ],
+              [
+                103.63349,
+                27.12057
+              ],
+              [
+                103.620555,
+                27.096598
+              ],
+              [
+                103.652584,
+                27.092868
+              ],
+              [
+                103.659975,
+                27.065692
+              ],
+              [
+                103.614396,
+                27.079548
+              ],
+              [
+                103.601461,
+                27.061962
+              ],
+              [
+                103.623635,
+                27.035312
+              ],
+              [
+                103.623019,
+                27.007056
+              ],
+              [
+                103.675374,
+                27.051836
+              ],
+              [
+                103.704939,
+                27.049171
+              ],
+              [
+                103.73204,
+                27.018785
+              ],
+              [
+                103.753598,
+                26.963858
+              ],
+              [
+                103.775156,
+                26.951056
+              ],
+              [
+                103.763453,
+                26.905702
+              ],
+              [
+                103.779468,
+                26.87421
+              ],
+              [
+                103.722185,
+                26.851253
+              ],
+              [
+                103.705555,
+                26.794642
+              ],
+              [
+                103.725265,
+                26.742812
+              ],
+              [
+                103.773308,
+                26.716621
+              ],
+              [
+                103.759142,
+                26.689355
+              ],
+              [
+                103.748671,
+                26.623568
+              ],
+              [
+                103.763453,
+                26.585041
+              ],
+              [
+                103.815808,
+                26.55239
+              ],
+              [
+                103.819504,
+                26.529903
+              ],
+              [
+                103.865699,
+                26.512232
+              ],
+              [
+                103.953163,
+                26.521336
+              ],
+              [
+                104.008597,
+                26.511697
+              ],
+              [
+                104.067727,
+                26.51491
+              ],
+              [
+                104.068343,
+                26.573266
+              ],
+              [
+                104.121314,
+                26.638012
+              ],
+              [
+                104.160734,
+                26.646571
+              ],
+              [
+                104.222328,
+                26.620358
+              ],
+              [
+                104.268524,
+                26.617683
+              ],
+              [
+                104.274683,
+                26.633733
+              ],
+              [
+                104.313487,
+                26.612867
+              ],
+              [
+                104.353523,
+                26.620893
+              ],
+              [
+                104.398487,
+                26.686147
+              ],
+              [
+                104.424356,
+                26.709137
+              ],
+              [
+                104.468088,
+                26.644431
+              ],
+              [
+                104.459465,
+                26.602701
+              ],
+              [
+                104.488414,
+                26.579689
+              ],
+              [
+                104.556783,
+                26.590393
+              ],
+              [
+                104.579573,
+                26.568449
+              ],
+              [
+                104.57095,
+                26.524549
+              ],
+              [
+                104.598667,
+                26.520801
+              ],
+              [
+                104.638703,
+                26.477954
+              ],
+              [
+                104.631928,
+                26.451702
+              ],
+              [
+                104.665804,
+                26.434019
+              ],
+              [
+                104.664572,
+                26.397572
+              ],
+              [
+                104.684283,
+                26.3772
+              ],
+              [
+                104.659645,
+                26.335373
+              ],
+              [
+                104.592508,
+                26.317672
+              ],
+              [
+                104.542616,
+                26.253282
+              ],
+              [
+                104.548776,
+                26.226979
+              ],
+              [
+                104.518595,
+                26.165762
+              ],
+              [
+                104.52845,
+                26.114186
+              ],
+              [
+                104.499501,
+                26.070651
+              ],
+              [
+                104.460081,
+                26.085702
+              ],
+              [
+                104.470552,
+                26.009352
+              ],
+              [
+                104.438523,
+                25.92757
+              ],
+              [
+                104.414501,
+                25.909807
+              ],
+              [
+                104.441602,
+                25.868889
+              ],
+              [
+                104.42374,
+                25.841961
+              ],
+              [
+                104.397871,
+                25.76168
+              ],
+              [
+                104.370769,
+                25.730415
+              ],
+              [
+                104.328886,
+                25.760602
+              ],
+              [
+                104.310407,
+                25.647901
+              ],
+              [
+                104.332581,
+                25.598796
+              ],
+              [
+                104.389248,
+                25.595558
+              ],
+              [
+                104.428668,
+                25.576126
+              ],
+              [
+                104.436059,
+                25.520512
+              ],
+              [
+                104.418813,
+                25.499447
+              ],
+              [
+                104.434827,
+                25.472436
+              ],
+              [
+                104.44961,
+                25.495126
+              ],
+              [
+                104.483486,
+                25.494585
+              ],
+              [
+                104.524138,
+                25.526992
+              ],
+              [
+                104.556783,
+                25.524832
+              ],
+              [
+                104.543232,
+                25.400556
+              ],
+              [
+                104.566638,
+                25.402719
+              ],
+              [
+                104.615913,
+                25.364871
+              ],
+              [
+                104.646094,
+                25.356759
+              ],
+              [
+                104.639935,
+                25.295632
+              ],
+              [
+                104.689826,
+                25.296173
+              ],
+              [
+                104.736021,
+                25.268034
+              ],
+              [
+                104.816094,
+                25.262622
+              ],
+              [
+                104.826565,
+                25.235558
+              ],
+              [
+                104.806854,
+                25.224189
+              ],
+              [
+                104.822869,
+                25.170037
+              ],
+              [
+                104.801927,
+                25.163537
+              ],
+              [
+                104.753884,
+                25.214443
+              ],
+              [
+                104.724319,
+                25.195491
+              ],
+              [
+                104.732326,
+                25.167871
+              ],
+              [
+                104.695369,
+                25.122364
+              ],
+              [
+                104.685514,
+                25.078466
+              ],
+              [
+                104.619609,
+                25.060577
+              ],
+              [
+                104.684898,
+                25.054072
+              ],
+              [
+                104.713232,
+                24.996048
+              ],
+              [
+                104.663957,
+                24.964584
+              ],
+              [
+                104.635623,
+                24.903803
+              ],
+              [
+                104.586964,
+                24.872859
+              ],
+              [
+                104.539537,
+                24.813663
+              ],
+              [
+                104.542616,
+                24.75607
+              ],
+              [
+                104.529682,
+                24.731611
+              ],
+              [
+                104.595587,
+                24.709323
+              ],
+              [
+                104.628848,
+                24.660927
+              ],
+              [
+                104.703377,
+                24.645698
+              ],
+              [
+                104.729246,
+                24.617953
+              ],
+              [
+                104.771746,
+                24.659839
+              ],
+              [
+                104.841963,
+                24.676155
+              ],
+              [
+                104.865985,
+                24.730524
+              ],
+              [
+                104.899245,
+                24.752809
+              ],
+              [
+                105.03352,
+                24.787586
+              ],
+              [
+                105.026745,
+                24.815836
+              ],
+              [
+                105.039064,
+                24.872859
+              ],
+              [
+                105.077868,
+                24.918459
+              ],
+              [
+                105.09573,
+                24.92877
+              ],
+              [
+                105.131454,
+                24.959701
+              ],
+              [
+                105.157324,
+                24.958616
+              ],
+              [
+                105.178266,
+                24.985199
+              ],
+              [
+                105.212758,
+                24.995505
+              ],
+              [
+                105.251563,
+                24.967296
+              ],
+              [
+                105.267577,
+                24.929313
+              ],
+              [
+                105.334099,
+                24.9266
+              ],
+              [
+                105.365511,
+                24.943423
+              ],
+              [
+                105.428337,
+                24.930941
+              ],
+              [
+                105.457286,
+                24.87123
+              ],
+              [
+                105.493011,
+                24.833217
+              ],
+              [
+                105.497322,
+                24.809318
+              ],
+              [
+                105.573083,
+                24.797366
+              ],
+              [
+                105.607576,
+                24.803885
+              ],
+              [
+                105.617431,
+                24.78161
+              ],
+              [
+                105.70551,
+                24.768569
+              ],
+              [
+                105.767104,
+                24.719109
+              ],
+              [
+                105.827466,
+                24.702799
+              ],
+              [
+                105.863806,
+                24.729437
+              ],
+              [
+                105.942031,
+                24.725088
+              ],
+              [
+                105.961741,
+                24.677786
+              ],
+              [
+                106.024566,
+                24.633186
+              ],
+              [
+                106.047356,
+                24.684312
+              ],
+              [
+                106.113878,
+                24.714216
+              ],
+              [
+                106.150218,
+                24.762591
+              ],
+              [
+                106.173008,
+                24.760417
+              ],
+              [
+                106.206269,
+                24.851139
+              ],
+              [
+                106.197645,
+                24.885889
+              ],
+              [
+                106.145291,
+                24.954275
+              ],
+              [
+                106.191486,
+                24.95319
+              ],
+              [
+                106.215508,
+                24.981944
+              ],
+              [
+                106.253696,
+                24.971094
+              ],
+              [
+                106.304819,
+                24.973807
+              ],
+              [
+                106.332536,
+                24.988454
+              ],
+              [
+                106.442173,
+                25.019369
+              ],
+              [
+                106.450181,
+                25.033468
+              ],
+              [
+                106.519782,
+                25.054072
+              ],
+              [
+                106.551195,
+                25.082802
+              ],
+              [
+                106.590615,
+                25.08768
+              ],
+              [
+                106.63989,
+                25.132658
+              ],
+              [
+                106.644817,
+                25.164621
+              ],
+              [
+                106.691013,
+                25.179245
+              ],
+              [
+                106.732281,
+                25.162454
+              ],
+              [
+                106.764926,
+                25.183036
+              ],
+              [
+                106.787715,
+                25.17112
+              ],
+              [
+                106.853005,
+                25.186827
+              ],
+              [
+                106.888113,
+                25.181953
+              ],
+              [
+                106.904128,
+                25.231768
+              ],
+              [
+                106.933077,
+                25.250714
+              ],
+              [
+                106.975577,
+                25.232851
+              ],
+              [
+                107.013765,
+                25.275611
+              ],
+              [
+                107.012533,
+                25.352973
+              ],
+              [
+                106.987896,
+                25.358922
+              ],
+              [
+                106.963874,
+                25.437852
+              ],
+              [
+                106.996519,
+                25.442716
+              ],
+              [
+                107.015613,
+                25.495666
+              ],
+              [
+                107.066736,
+                25.50917
+              ],
+              [
+                107.064272,
+                25.559391
+              ],
+              [
+                107.185612,
+                25.578825
+              ],
+              [
+                107.205322,
+                25.607971
+              ],
+              [
+                107.228728,
+                25.604733
+              ],
+              [
+                107.232423,
+                25.556691
+              ],
+              [
+                107.263836,
+                25.543193
+              ],
+              [
+                107.336517,
+                25.461089
+              ],
+              [
+                107.308184,
+                25.432988
+              ],
+              [
+                107.318039,
+                25.401637
+              ],
+              [
+                107.358691,
+                25.393528
+              ],
+              [
+                107.375937,
+                25.411908
+              ],
+              [
+                107.420901,
+                25.392987
+              ],
+              [
+                107.409198,
+                25.347024
+              ],
+              [
+                107.432604,
+                25.289139
+              ],
+              [
+                107.481263,
+                25.299961
+              ],
+              [
+                107.489886,
+                25.276693
+              ],
+              [
+                107.472024,
+                25.213902
+              ],
+              [
+                107.512676,
+                25.209029
+              ],
+              [
+                107.576734,
+                25.256668
+              ],
+              [
+                107.599523,
+                25.250714
+              ],
+              [
+                107.632168,
+                25.310241
+              ],
+              [
+                107.659885,
+                25.316192
+              ],
+              [
+                107.661733,
+                25.258833
+              ],
+              [
+                107.696226,
+                25.219858
+              ],
+              [
+                107.700537,
+                25.194408
+              ],
+              [
+                107.741805,
+                25.24043
+              ],
+              [
+                107.762131,
+                25.229061
+              ],
+              [
+                107.760283,
+                25.188451
+              ],
+              [
+                107.789233,
+                25.15487
+              ],
+              [
+                107.762747,
+                25.125073
+              ],
+              [
+                107.839124,
+                25.115861
+              ],
+              [
+                107.872384,
+                25.141327
+              ],
+              [
+                107.928435,
+                25.155954
+              ],
+              [
+                108.001732,
+                25.196574
+              ],
+              [
+                108.080572,
+                25.193867
+              ],
+              [
+                108.115065,
+                25.210112
+              ],
+              [
+                108.143398,
+                25.269658
+              ],
+              [
+                108.152021,
+                25.324306
+              ],
+              [
+                108.142782,
+                25.390825
+              ],
+              [
+                108.193289,
+                25.405421
+              ],
+              [
+                108.162492,
+                25.444878
+              ],
+              [
+                108.192673,
+                25.458928
+              ],
+              [
+                108.251803,
+                25.430286
+              ],
+              [
+                108.241332,
+                25.46217
+              ],
+              [
+                108.280752,
+                25.48
+              ],
+              [
+                108.308469,
+                25.525912
+              ],
+              [
+                108.348506,
+                25.536173
+              ],
+              [
+                108.359592,
+                25.513491
+              ],
+              [
+                108.400244,
+                25.491344
+              ],
+              [
+                108.418723,
+                25.443257
+              ],
+              [
+                108.471693,
+                25.458928
+              ],
+              [
+                108.585642,
+                25.365952
+              ],
+              [
+                108.589338,
+                25.335125
+              ],
+              [
+                108.625062,
+                25.308076
+              ],
+              [
+                108.62999,
+                25.335666
+              ],
+              [
+                108.600425,
+                25.432448
+              ],
+              [
+                108.6072,
+                25.491885
+              ],
+              [
+                108.634917,
+                25.520512
+              ],
+              [
+                108.68912,
+                25.533473
+              ],
+              [
+                108.658323,
+                25.550212
+              ],
+              [
+                108.660787,
+                25.584763
+              ],
+              [
+                108.68604,
+                25.587462
+              ],
+              [
+                108.68912,
+                25.623081
+              ],
+              [
+                108.724844,
+                25.634952
+              ],
+              [
+                108.783975,
+                25.628477
+              ],
+              [
+                108.799989,
+                25.576666
+              ],
+              [
+                108.781511,
+                25.554531
+              ],
+              [
+                108.814772,
+                25.526992
+              ],
+              [
+                108.826474,
+                25.550212
+              ],
+              [
+                108.890532,
+                25.556151
+              ],
+              [
+                108.8893,
+                25.543193
+              ],
+              [
+                108.949046,
+                25.557231
+              ],
+              [
+                109.024807,
+                25.51241
+              ],
+              [
+                109.088249,
+                25.550752
+              ],
+              [
+                109.051908,
+                25.566949
+              ],
+              [
+                109.030966,
+                25.629556
+              ],
+              [
+                109.075314,
+                25.693749
+              ],
+              [
+                109.07901,
+                25.72071
+              ],
+              [
+                109.043285,
+                25.738502
+              ],
+              [
+                109.007561,
+                25.734728
+              ],
+              [
+                108.953974,
+                25.686738
+              ],
+              [
+                108.953974,
+                25.686738
+              ],
+              [
+                108.900387,
+                25.682423
+              ],
+              [
+                108.896076,
+                25.71424
+              ],
+              [
+                108.940423,
+                25.740119
+              ],
+              [
+                108.963829,
+                25.732572
+              ],
+              [
+                108.999553,
+                25.765453
+              ],
+              [
+                108.989698,
+                25.778926
+              ],
+              [
+                109.048213,
+                25.790781
+              ],
+              [
+                109.077778,
+                25.776771
+              ],
+              [
+                109.095024,
+                25.80533
+              ],
+              [
+                109.143683,
+                25.795092
+              ],
+              [
+                109.13198,
+                25.762758
+              ],
+              [
+                109.147995,
+                25.741736
+              ],
+              [
+                109.206509,
+                25.788087
+              ],
+              [
+                109.207125,
+                25.740119
+              ],
+              [
+                109.296436,
+                25.71424
+              ],
+              [
+                109.340168,
+                25.731493
+              ],
+              [
+                109.327849,
+                25.76168
+              ],
+              [
+                109.339552,
+                25.83442
+              ],
+              [
+                109.359262,
+                25.836036
+              ],
+              [
+                109.396834,
+                25.900117
+              ],
+              [
+                109.435022,
+                25.93349
+              ],
+              [
+                109.408537,
+                25.967392
+              ],
+              [
+                109.473211,
+                26.006663
+              ],
+              [
+                109.48245,
+                26.029788
+              ],
+              [
+                109.452885,
+                26.055598
+              ],
+              [
+                109.449805,
+                26.101826
+              ],
+              [
+                109.502776,
+                26.096451
+              ],
+              [
+                109.513863,
+                26.128157
+              ],
+              [
+                109.47629,
+                26.148035
+              ],
+              [
+                109.439334,
+                26.238789
+              ],
+              [
+                109.467051,
+                26.313917
+              ],
+              [
+                109.442414,
+                26.289774
+              ],
+              [
+                109.369733,
+                26.277432
+              ],
+              [
+                109.351255,
+                26.264016
+              ],
+              [
+                109.325385,
+                26.29031
+              ],
+              [
+                109.285965,
+                26.295676
+              ],
+              [
+                109.271183,
+                26.327863
+              ],
+              [
+                109.29582,
+                26.350389
+              ],
+              [
+                109.319842,
+                26.418477
+              ],
+              [
+                109.38082,
+                26.454381
+              ],
+              [
+                109.362342,
+                26.472061
+              ],
+              [
+                109.385747,
+                26.493487
+              ],
+              [
+                109.381436,
+                26.518659
+              ],
+              [
+                109.407305,
+                26.533116
+              ],
+              [
+                109.390675,
+                26.598955
+              ],
+              [
+                109.35495,
+                26.658873
+              ],
+              [
+                109.334008,
+                26.646036
+              ],
+              [
+                109.306291,
+                26.661012
+              ],
+              [
+                109.283501,
+                26.698445
+              ],
+              [
+                109.35495,
+                26.693098
+              ],
+              [
+                109.407305,
+                26.719829
+              ],
+              [
+                109.447957,
+                26.759913
+              ],
+              [
+                109.486761,
+                26.759913
+              ],
+              [
+                109.47629,
+                26.829894
+              ],
+              [
+                109.467051,
+                26.83203
+              ],
+              [
+                109.452885,
+                26.861932
+              ],
+              [
+                109.436254,
+                26.892359
+              ],
+              [
+                109.555131,
+                26.946788
+              ],
+              [
+                109.520022,
+                27.058764
+              ],
+              [
+                109.497848,
+                27.079548
+              ],
+              [
+                109.486761,
+                27.053968
+              ],
+              [
+                109.454733,
+                27.069423
+              ],
+              [
+                109.472595,
+                27.134951
+              ],
+              [
+                109.441182,
+                27.117907
+              ],
+              [
+                109.415312,
+                27.154123
+              ],
+              [
+                109.358646,
+                27.153058
+              ],
+              [
+                109.33524,
+                27.139212
+              ],
+              [
+                109.264407,
+                27.131755
+              ],
+              [
+                109.239154,
+                27.14933
+              ],
+              [
+                109.21698,
+                27.114711
+              ],
+              [
+                109.165857,
+                27.066758
+              ],
+              [
+                109.101183,
+                27.06889
+              ],
+              [
+                109.128901,
+                27.122701
+              ],
+              [
+                109.032814,
+                27.104056
+              ],
+              [
+                109.007561,
+                27.08008
+              ],
+              [
+                108.940423,
+                27.044907
+              ],
+              [
+                108.942887,
+                27.017186
+              ],
+              [
+                108.942887,
+                27.017186
+              ],
+              [
+                108.877597,
+                27.01612
+              ],
+              [
+                108.79075,
+                27.084343
+              ],
+              [
+                108.878829,
+                27.106187
+              ],
+              [
+                108.926873,
+                27.160512
+              ],
+              [
+                108.907778,
+                27.204699
+              ],
+              [
+                108.963213,
+                27.235565
+              ],
+              [
+                108.983539,
+                27.26802
+              ],
+              [
+                109.053756,
+                27.293551
+              ],
+              [
+                109.044517,
+                27.331304
+              ],
+              [
+                109.103647,
+                27.336621
+              ],
+              [
+                109.142451,
+                27.418461
+              ],
+              [
+                109.141835,
+                27.448207
+              ],
+              [
+                109.167089,
+                27.41793
+              ],
+              [
+                109.202197,
+                27.450331
+              ],
+              [
+                109.245313,
+                27.41793
+              ],
+              [
+                109.300132,
+                27.423774
+              ],
+              [
+                109.303211,
+                27.47582
+              ],
+              [
+                109.404841,
+                27.55066
+              ],
+              [
+                109.461508,
+                27.567637
+              ],
+              [
+                109.451037,
+                27.586204
+              ],
+              [
+                109.470131,
+                27.62863
+              ],
+              [
+                109.45658,
+                27.673689
+              ],
+              [
+                109.470747,
+                27.680049
+              ],
+              [
+                109.414081,
+                27.725087
+              ],
+              [
+                109.366653,
+                27.721909
+              ],
+              [
+                109.37774,
+                27.736741
+              ],
+              [
+                109.332777,
+                27.782815
+              ],
+              [
+                109.346943,
+                27.838396
+              ],
+              [
+                109.32169,
+                27.868027
+              ],
+              [
+                109.30198,
+                27.956343
+              ],
+              [
+                109.319842,
+                27.988585
+              ],
+              [
+                109.362342,
+                28.007608
+              ],
+              [
+                109.378972,
+                28.034551
+              ],
+              [
+                109.335856,
+                28.063073
+              ],
+              [
+                109.298284,
+                28.036136
+              ],
+              [
+                109.314298,
+                28.103729
+              ],
+              [
+                109.33832,
+                28.141731
+              ],
+              [
+                109.340168,
+                28.19027
+              ],
+              [
+                109.367885,
+                28.254602
+              ],
+              [
+                109.388211,
+                28.268307
+              ],
+              [
+                109.33524,
+                28.293605
+              ],
+              [
+                109.317994,
+                28.277795
+              ],
+              [
+                109.275494,
+                28.313101
+              ],
+              [
+                109.268719,
+                28.33786
+              ],
+              [
+                109.289045,
+                28.373673
+              ],
+              [
+                109.264407,
+                28.392628
+              ],
+              [
+                109.260712,
+                28.46473
+              ],
+              [
+                109.274262,
+                28.494714
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.47629,
+                26.829894
+              ],
+              [
+                109.486761,
+                26.759913
+              ],
+              [
+                109.52187,
+                26.749226
+              ],
+              [
+                109.522486,
+                26.749226
+              ],
+              [
+                109.497232,
+                26.815474
+              ],
+              [
+                109.513247,
+                26.84004
+              ],
+              [
+                109.509551,
+                26.877947
+              ],
+              [
+                109.486761,
+                26.895562
+              ],
+              [
+                109.452885,
+                26.861932
+              ],
+              [
+                109.467051,
+                26.83203
+              ],
+              [
+                109.47629,
+                26.829894
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.528645,
+                26.743881
+              ],
+              [
+                109.568065,
+                26.726243
+              ],
+              [
+                109.597015,
+                26.756173
+              ],
+              [
+                109.554515,
+                26.73533
+              ],
+              [
+                109.528645,
+                26.743881
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 530000,
+        "name": "浜戝崡鐪�",
+        "center": [
+          102.712251,
+          25.040609
+        ],
+        "centroid": [
+          101.485106,
+          25.008643
+        ],
+        "childrenNum": 16,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 24,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                105.308229,
+                27.704955
+              ],
+              [
+                105.290367,
+                27.712373
+              ],
+              [
+                105.293447,
+                27.770637
+              ],
+              [
+                105.273736,
+                27.794992
+              ],
+              [
+                105.313157,
+                27.810874
+              ],
+              [
+                105.25957,
+                27.827811
+              ],
+              [
+                105.233084,
+                27.895534
+              ],
+              [
+                105.284823,
+                27.935725
+              ],
+              [
+                105.270657,
+                27.99704
+              ],
+              [
+                105.247867,
+                28.009193
+              ],
+              [
+                105.218302,
+                27.990698
+              ],
+              [
+                105.186273,
+                27.995454
+              ],
+              [
+                105.167795,
+                28.021345
+              ],
+              [
+                105.186889,
+                28.054623
+              ],
+              [
+                105.168411,
+                28.071522
+              ],
+              [
+                105.119752,
+                28.07205
+              ],
+              [
+                105.061853,
+                28.096866
+              ],
+              [
+                105.002107,
+                28.064129
+              ],
+              [
+                104.980549,
+                28.063073
+              ],
+              [
+                104.975006,
+                28.020816
+              ],
+              [
+                104.903557,
+                27.962158
+              ],
+              [
+                104.918339,
+                27.938897
+              ],
+              [
+                104.888158,
+                27.914574
+              ],
+              [
+                104.842579,
+                27.900294
+              ],
+              [
+                104.796999,
+                27.901352
+              ],
+              [
+                104.761891,
+                27.884426
+              ],
+              [
+                104.743413,
+                27.901881
+              ],
+              [
+                104.676275,
+                27.880723
+              ],
+              [
+                104.63316,
+                27.850567
+              ],
+              [
+                104.607906,
+                27.857974
+              ],
+              [
+                104.573413,
+                27.840512
+              ],
+              [
+                104.52537,
+                27.889187
+              ],
+              [
+                104.508124,
+                27.878078
+              ],
+              [
+                104.44961,
+                27.927794
+              ],
+              [
+                104.40095,
+                27.952114
+              ],
+              [
+                104.362762,
+                28.012891
+              ],
+              [
+                104.30856,
+                28.036136
+              ],
+              [
+                104.304248,
+                28.050926
+              ],
+              [
+                104.373233,
+                28.051454
+              ],
+              [
+                104.40095,
+                28.091586
+              ],
+              [
+                104.448994,
+                28.113758
+              ],
+              [
+                104.444682,
+                28.16231
+              ],
+              [
+                104.406494,
+                28.173389
+              ],
+              [
+                104.402182,
+                28.202928
+              ],
+              [
+                104.442834,
+                28.211366
+              ],
+              [
+                104.462544,
+                28.241422
+              ],
+              [
+                104.44961,
+                28.269889
+              ],
+              [
+                104.420045,
+                28.269889
+              ],
+              [
+                104.392943,
+                28.291497
+              ],
+              [
+                104.384936,
+                28.329959
+              ],
+              [
+                104.343052,
+                28.334173
+              ],
+              [
+                104.314103,
+                28.306778
+              ],
+              [
+                104.282074,
+                28.343128
+              ],
+              [
+                104.254357,
+                28.403683
+              ],
+              [
+                104.267908,
+                28.499448
+              ],
+              [
+                104.260516,
+                28.536257
+              ],
+              [
+                104.323342,
+                28.540989
+              ],
+              [
+                104.355987,
+                28.555183
+              ],
+              [
+                104.375697,
+                28.5946
+              ],
+              [
+                104.417581,
+                28.598279
+              ],
+              [
+                104.425588,
+                28.626649
+              ],
+              [
+                104.372617,
+                28.649235
+              ],
+              [
+                104.314719,
+                28.615617
+              ],
+              [
+                104.277147,
+                28.631902
+              ],
+              [
+                104.252509,
+                28.660788
+              ],
+              [
+                104.230951,
+                28.635579
+              ],
+              [
+                104.170589,
+                28.642932
+              ],
+              [
+                104.117618,
+                28.634003
+              ],
+              [
+                104.09606,
+                28.603533
+              ],
+              [
+                104.05972,
+                28.6277
+              ],
+              [
+                103.953779,
+                28.600906
+              ],
+              [
+                103.910047,
+                28.631377
+              ],
+              [
+                103.887873,
+                28.61982
+              ],
+              [
+                103.850917,
+                28.66709
+              ],
+              [
+                103.833054,
+                28.605109
+              ],
+              [
+                103.838598,
+                28.587244
+              ],
+              [
+                103.802873,
+                28.563068
+              ],
+              [
+                103.781931,
+                28.525216
+              ],
+              [
+                103.829975,
+                28.459995
+              ],
+              [
+                103.828743,
+                28.44
+              ],
+              [
+                103.860156,
+                28.383677
+              ],
+              [
+                103.85338,
+                28.356822
+              ],
+              [
+                103.877402,
+                28.316262
+              ],
+              [
+                103.828743,
+                28.285173
+              ],
+              [
+                103.770845,
+                28.233514
+              ],
+              [
+                103.740048,
+                28.23615
+              ],
+              [
+                103.701859,
+                28.198709
+              ],
+              [
+                103.692004,
+                28.232459
+              ],
+              [
+                103.643961,
+                28.260401
+              ],
+              [
+                103.573128,
+                28.230877
+              ],
+              [
+                103.533092,
+                28.168641
+              ],
+              [
+                103.470266,
+                28.122204
+              ],
+              [
+                103.430846,
+                28.044587
+              ],
+              [
+                103.459179,
+                28.021345
+              ],
+              [
+                103.486281,
+                28.033495
+              ],
+              [
+                103.515846,
+                27.965329
+              ],
+              [
+                103.55465,
+                27.978543
+              ],
+              [
+                103.502295,
+                27.910343
+              ],
+              [
+                103.509686,
+                27.843687
+              ],
+              [
+                103.487512,
+                27.794992
+              ],
+              [
+                103.461027,
+                27.779638
+              ],
+              [
+                103.393274,
+                27.709194
+              ],
+              [
+                103.369868,
+                27.708664
+              ],
+              [
+                103.349542,
+                27.678459
+              ],
+              [
+                103.29226,
+                27.632872
+              ],
+              [
+                103.2861,
+                27.561802
+              ],
+              [
+                103.232514,
+                27.56976
+              ],
+              [
+                103.19063,
+                27.523596
+              ],
+              [
+                103.144434,
+                27.450331
+              ],
+              [
+                103.141355,
+                27.420586
+              ],
+              [
+                103.080992,
+                27.396679
+              ],
+              [
+                103.055739,
+                27.40943
+              ],
+              [
+                102.989833,
+                27.367983
+              ],
+              [
+                102.941174,
+                27.405711
+              ],
+              [
+                102.899906,
+                27.317481
+              ],
+              [
+                102.883892,
+                27.299401
+              ],
+              [
+                102.883276,
+                27.258444
+              ],
+              [
+                102.904218,
+                27.227584
+              ],
+              [
+                102.913457,
+                27.133886
+              ],
+              [
+                102.870957,
+                27.026782
+              ],
+              [
+                102.894979,
+                27.001724
+              ],
+              [
+                102.896211,
+                26.91264
+              ],
+              [
+                102.949181,
+                26.843244
+              ],
+              [
+                102.966428,
+                26.837904
+              ],
+              [
+                102.991681,
+                26.775409
+              ],
+              [
+                102.983674,
+                26.76686
+              ],
+              [
+                103.008312,
+                26.710741
+              ],
+              [
+                103.005232,
+                26.679195
+              ],
+              [
+                103.026174,
+                26.664221
+              ],
+              [
+                103.035413,
+                26.556673
+              ],
+              [
+                103.052659,
+                26.555602
+              ],
+              [
+                103.052659,
+                26.514374
+              ],
+              [
+                103.030485,
+                26.485989
+              ],
+              [
+                102.989833,
+                26.482775
+              ],
+              [
+                102.988602,
+                26.413117
+              ],
+              [
+                102.998457,
+                26.371839
+              ],
+              [
+                102.975667,
+                26.340736
+              ],
+              [
+                102.893131,
+                26.338591
+              ],
+              [
+                102.878964,
+                26.364332
+              ],
+              [
+                102.833385,
+                26.306406
+              ],
+              [
+                102.785342,
+                26.298895
+              ],
+              [
+                102.739762,
+                26.268846
+              ],
+              [
+                102.709581,
+                26.210336
+              ],
+              [
+                102.659074,
+                26.221611
+              ],
+              [
+                102.60056,
+                26.250598
+              ],
+              [
+                102.638748,
+                26.307479
+              ],
+              [
+                102.629509,
+                26.336982
+              ],
+              [
+                102.570995,
+                26.362723
+              ],
+              [
+                102.542046,
+                26.338591
+              ],
+              [
+                102.440416,
+                26.300505
+              ],
+              [
+                102.392372,
+                26.296749
+              ],
+              [
+                102.349257,
+                26.244694
+              ],
+              [
+                102.245163,
+                26.212483
+              ],
+              [
+                102.242699,
+                26.190468
+              ],
+              [
+                102.174946,
+                26.146961
+              ],
+              [
+                102.152156,
+                26.10935
+              ],
+              [
+                102.107808,
+                26.068501
+              ],
+              [
+                102.080091,
+                26.065275
+              ],
+              [
+                102.020961,
+                26.096451
+              ],
+              [
+                101.954439,
+                26.084627
+              ],
+              [
+                101.929186,
+                26.105588
+              ],
+              [
+                101.899621,
+                26.099139
+              ],
+              [
+                101.857737,
+                26.049146
+              ],
+              [
+                101.835563,
+                26.04592
+              ],
+              [
+                101.839875,
+                26.082477
+              ],
+              [
+                101.796759,
+                26.114723
+              ],
+              [
+                101.807846,
+                26.156093
+              ],
+              [
+                101.773353,
+                26.168448
+              ],
+              [
+                101.737013,
+                26.219463
+              ],
+              [
+                101.690202,
+                26.241473
+              ],
+              [
+                101.630455,
+                26.224832
+              ],
+              [
+                101.586108,
+                26.279579
+              ],
+              [
+                101.597195,
+                26.303187
+              ],
+              [
+                101.64031,
+                26.318745
+              ],
+              [
+                101.660636,
+                26.346635
+              ],
+              [
+                101.635383,
+                26.357361
+              ],
+              [
+                101.637847,
+                26.388995
+              ],
+              [
+                101.565782,
+                26.454381
+              ],
+              [
+                101.530057,
+                26.467239
+              ],
+              [
+                101.506652,
+                26.499915
+              ],
+              [
+                101.458608,
+                26.49563
+              ],
+              [
+                101.422884,
+                26.53151
+              ],
+              [
+                101.395783,
+                26.591998
+              ],
+              [
+                101.402558,
+                26.604841
+              ],
+              [
+                101.461688,
+                26.606447
+              ],
+              [
+                101.461072,
+                26.640687
+              ],
+              [
+                101.481398,
+                26.673313
+              ],
+              [
+                101.453065,
+                26.692563
+              ],
+              [
+                101.513427,
+                26.768463
+              ],
+              [
+                101.466,
+                26.786629
+              ],
+              [
+                101.445674,
+                26.77434
+              ],
+              [
+                101.458608,
+                26.731054
+              ],
+              [
+                101.435819,
+                26.740675
+              ],
+              [
+                101.389623,
+                26.723036
+              ],
+              [
+                101.387159,
+                26.753501
+              ],
+              [
+                101.358826,
+                26.771669
+              ],
+              [
+                101.399478,
+                26.841642
+              ],
+              [
+                101.365602,
+                26.883819
+              ],
+              [
+                101.311399,
+                26.903034
+              ],
+              [
+                101.267667,
+                26.903034
+              ],
+              [
+                101.264587,
+                26.955323
+              ],
+              [
+                101.227015,
+                26.959057
+              ],
+              [
+                101.228863,
+                26.981992
+              ],
+              [
+                101.136472,
+                27.023584
+              ],
+              [
+                101.157414,
+                27.094999
+              ],
+              [
+                101.145095,
+                27.103523
+              ],
+              [
+                101.170349,
+                27.175421
+              ],
+              [
+                101.167885,
+                27.198311
+              ],
+              [
+                101.167885,
+                27.198311
+              ],
+              [
+                101.119226,
+                27.208957
+              ],
+              [
+                101.071798,
+                27.194585
+              ],
+              [
+                101.042233,
+                27.22173
+              ],
+              [
+                101.026219,
+                27.270679
+              ],
+              [
+                101.021907,
+                27.332899
+              ],
+              [
+                100.95169,
+                27.426961
+              ],
+              [
+                100.936908,
+                27.469448
+              ],
+              [
+                100.901183,
+                27.453517
+              ],
+              [
+                100.91227,
+                27.521473
+              ],
+              [
+                100.854988,
+                27.623858
+              ],
+              [
+                100.827886,
+                27.615904
+              ],
+              [
+                100.848212,
+                27.672099
+              ],
+              [
+                100.782307,
+                27.691708
+              ],
+              [
+                100.775532,
+                27.743098
+              ],
+              [
+                100.757053,
+                27.770107
+              ],
+              [
+                100.707162,
+                27.800816
+              ],
+              [
+                100.719481,
+                27.858503
+              ],
+              [
+                100.681293,
+                27.923035
+              ],
+              [
+                100.634482,
+                27.915631
+              ],
+              [
+                100.609228,
+                27.859033
+              ],
+              [
+                100.54517,
+                27.809286
+              ],
+              [
+                100.511294,
+                27.827811
+              ],
+              [
+                100.504518,
+                27.852154
+              ],
+              [
+                100.442924,
+                27.86644
+              ],
+              [
+                100.412127,
+                27.816167
+              ],
+              [
+                100.350534,
+                27.755809
+              ],
+              [
+                100.327744,
+                27.72032
+              ],
+              [
+                100.311729,
+                27.724028
+              ],
+              [
+                100.304954,
+                27.788639
+              ],
+              [
+                100.28586,
+                27.80611
+              ],
+              [
+                100.30865,
+                27.830457
+              ],
+              [
+                100.30865,
+                27.861149
+              ],
+              [
+                100.210715,
+                27.87702
+              ],
+              [
+                100.170063,
+                27.907699
+              ],
+              [
+                100.196549,
+                27.936254
+              ],
+              [
+                100.120788,
+                28.018703
+              ],
+              [
+                100.088759,
+                28.029269
+              ],
+              [
+                100.05673,
+                28.097922
+              ],
+              [
+                100.021006,
+                28.147008
+              ],
+              [
+                100.033325,
+                28.184467
+              ],
+              [
+                100.062274,
+                28.193962
+              ],
+              [
+                100.091223,
+                28.181302
+              ],
+              [
+                100.102926,
+                28.201873
+              ],
+              [
+                100.153433,
+                28.208202
+              ],
+              [
+                100.188541,
+                28.252493
+              ],
+              [
+                100.147274,
+                28.288862
+              ],
+              [
+                100.176223,
+                28.325218
+              ],
+              [
+                100.136803,
+                28.349975
+              ],
+              [
+                100.057346,
+                28.368934
+              ],
+              [
+                100.073977,
+                28.426317
+              ],
+              [
+                99.990209,
+                28.47683
+              ],
+              [
+                99.985281,
+                28.529422
+              ],
+              [
+                99.91876,
+                28.599329
+              ],
+              [
+                99.875644,
+                28.611939
+              ],
+              [
+                99.873181,
+                28.631902
+              ],
+              [
+                99.834376,
+                28.628225
+              ],
+              [
+                99.834992,
+                28.660788
+              ],
+              [
+                99.79434,
+                28.699116
+              ],
+              [
+                99.755536,
+                28.701216
+              ],
+              [
+                99.722275,
+                28.757369
+              ],
+              [
+                99.717964,
+                28.846521
+              ],
+              [
+                99.676696,
+                28.810345
+              ],
+              [
+                99.625573,
+                28.81454
+              ],
+              [
+                99.609559,
+                28.784122
+              ],
+              [
+                99.614486,
+                28.740054
+              ],
+              [
+                99.553508,
+                28.710664
+              ],
+              [
+                99.53195,
+                28.677591
+              ],
+              [
+                99.540573,
+                28.623497
+              ],
+              [
+                99.504233,
+                28.619294
+              ],
+              [
+                99.466045,
+                28.579886
+              ],
+              [
+                99.463581,
+                28.549401
+              ],
+              [
+                99.403219,
+                28.546246
+              ],
+              [
+                99.396444,
+                28.491032
+              ],
+              [
+                99.426625,
+                28.454207
+              ],
+              [
+                99.404451,
+                28.44421
+              ],
+              [
+                99.437095,
+                28.398419
+              ],
+              [
+                99.392748,
+                28.318369
+              ],
+              [
+                99.412458,
+                28.295186
+              ],
+              [
+                99.374886,
+                28.18183
+              ],
+              [
+                99.306516,
+                28.227714
+              ],
+              [
+                99.28927,
+                28.286227
+              ],
+              [
+                99.237531,
+                28.317842
+              ],
+              [
+                99.229524,
+                28.350502
+              ],
+              [
+                99.200575,
+                28.365774
+              ],
+              [
+                99.16485,
+                28.425264
+              ],
+              [
+                99.187024,
+                28.44
+              ],
+              [
+                99.191952,
+                28.494714
+              ],
+              [
+                99.170394,
+                28.566221
+              ],
+              [
+                99.183944,
+                28.58882
+              ],
+              [
+                99.147604,
+                28.640831
+              ],
+              [
+                99.126662,
+                28.698066
+              ],
+              [
+                99.134053,
+                28.734806
+              ],
+              [
+                99.114343,
+                28.765763
+              ],
+              [
+                99.103872,
+                28.841803
+              ],
+              [
+                99.123582,
+                28.890021
+              ],
+              [
+                99.132206,
+                28.94869
+              ],
+              [
+                99.113727,
+                29.07273
+              ],
+              [
+                99.118039,
+                29.100971
+              ],
+              [
+                99.105104,
+                29.162656
+              ],
+              [
+                99.113727,
+                29.221171
+              ],
+              [
+                99.037351,
+                29.20759
+              ],
+              [
+                99.024416,
+                29.188783
+              ],
+              [
+                98.9813,
+                29.204978
+              ],
+              [
+                98.960974,
+                29.165792
+              ],
+              [
+                98.967134,
+                29.128159
+              ],
+              [
+                98.991771,
+                29.105677
+              ],
+              [
+                99.013329,
+                29.036632
+              ],
+              [
+                98.925866,
+                28.978536
+              ],
+              [
+                98.917859,
+                28.886877
+              ],
+              [
+                98.973909,
+                28.864867
+              ],
+              [
+                98.972677,
+                28.832367
+              ],
+              [
+                98.922786,
+                28.823978
+              ],
+              [
+                98.912931,
+                28.800906
+              ],
+              [
+                98.852569,
+                28.798283
+              ],
+              [
+                98.827932,
+                28.821356
+              ],
+              [
+                98.821772,
+                28.920931
+              ],
+              [
+                98.786048,
+                28.998952
+              ],
+              [
+                98.757714,
+                29.004186
+              ],
+              [
+                98.70228,
+                28.9644
+              ],
+              [
+                98.655469,
+                28.976966
+              ],
+              [
+                98.624056,
+                28.95864
+              ],
+              [
+                98.6567,
+                28.910454
+              ],
+              [
+                98.643766,
+                28.895261
+              ],
+              [
+                98.668403,
+                28.843376
+              ],
+              [
+                98.652389,
+                28.817162
+              ],
+              [
+                98.683802,
+                28.740054
+              ],
+              [
+                98.666555,
+                28.712239
+              ],
+              [
+                98.594491,
+                28.667615
+              ],
+              [
+                98.637606,
+                28.552029
+              ],
+              [
+                98.619128,
+                28.50944
+              ],
+              [
+                98.625903,
+                28.489455
+              ],
+              [
+                98.673947,
+                28.478934
+              ],
+              [
+                98.693041,
+                28.43158
+              ],
+              [
+                98.740468,
+                28.348395
+              ],
+              [
+                98.746628,
+                28.321003
+              ],
+              [
+                98.710287,
+                28.288862
+              ],
+              [
+                98.712135,
+                28.229296
+              ],
+              [
+                98.649925,
+                28.200291
+              ],
+              [
+                98.625903,
+                28.165475
+              ],
+              [
+                98.559382,
+                28.182885
+              ],
+              [
+                98.494092,
+                28.141203
+              ],
+              [
+                98.464527,
+                28.151229
+              ],
+              [
+                98.428803,
+                28.104785
+              ],
+              [
+                98.389383,
+                28.114814
+              ],
+              [
+                98.389999,
+                28.16442
+              ],
+              [
+                98.370289,
+                28.18394
+              ],
+              [
+                98.37768,
+                28.246167
+              ],
+              [
+                98.353042,
+                28.293078
+              ],
+              [
+                98.317934,
+                28.324691
+              ],
+              [
+                98.301303,
+                28.384204
+              ],
+              [
+                98.208913,
+                28.358401
+              ],
+              [
+                98.207681,
+                28.330486
+              ],
+              [
+                98.231702,
+                28.314681
+              ],
+              [
+                98.266811,
+                28.242477
+              ],
+              [
+                98.21692,
+                28.212949
+              ],
+              [
+                98.169492,
+                28.206093
+              ],
+              [
+                98.17442,
+                28.163365
+              ],
+              [
+                98.139311,
+                28.142259
+              ],
+              [
+                98.160253,
+                28.101089
+              ],
+              [
+                98.133152,
+                27.990698
+              ],
+              [
+                98.143007,
+                27.948942
+              ],
+              [
+                98.187355,
+                27.939426
+              ],
+              [
+                98.205217,
+                27.889716
+              ],
+              [
+                98.169492,
+                27.851096
+              ],
+              [
+                98.215688,
+                27.810874
+              ],
+              [
+                98.234166,
+                27.690648
+              ],
+              [
+                98.283441,
+                27.654608
+              ],
+              [
+                98.310542,
+                27.583552
+              ],
+              [
+                98.317318,
+                27.51935
+              ],
+              [
+                98.337644,
+                27.508734
+              ],
+              [
+                98.388767,
+                27.515104
+              ],
+              [
+                98.429419,
+                27.549068
+              ],
+              [
+                98.430035,
+                27.653547
+              ],
+              [
+                98.444201,
+                27.665209
+              ],
+              [
+                98.474998,
+                27.634462
+              ],
+              [
+                98.53536,
+                27.620676
+              ],
+              [
+                98.554454,
+                27.646126
+              ],
+              [
+                98.587099,
+                27.587265
+              ],
+              [
+                98.583404,
+                27.571351
+              ],
+              [
+                98.650541,
+                27.567637
+              ],
+              [
+                98.662244,
+                27.586734
+              ],
+              [
+                98.706591,
+                27.553313
+              ],
+              [
+                98.685034,
+                27.484315
+              ],
+              [
+                98.704744,
+                27.462014
+              ],
+              [
+                98.686881,
+                27.425367
+              ],
+              [
+                98.702896,
+                27.412618
+              ],
+              [
+                98.706591,
+                27.362136
+              ],
+              [
+                98.741084,
+                27.330241
+              ],
+              [
+                98.734925,
+                27.287168
+              ],
+              [
+                98.717062,
+                27.271211
+              ],
+              [
+                98.723222,
+                27.221198
+              ],
+              [
+                98.696121,
+                27.211086
+              ],
+              [
+                98.713983,
+                27.139744
+              ],
+              [
+                98.712751,
+                27.075817
+              ],
+              [
+                98.765722,
+                27.05077
+              ],
+              [
+                98.762642,
+                27.018252
+              ],
+              [
+                98.732461,
+                27.002257
+              ],
+              [
+                98.757098,
+                26.877947
+              ],
+              [
+                98.730613,
+                26.851253
+              ],
+              [
+                98.762026,
+                26.798916
+              ],
+              [
+                98.746012,
+                26.696841
+              ],
+              [
+                98.770033,
+                26.690424
+              ],
+              [
+                98.762642,
+                26.660478
+              ],
+              [
+                98.781736,
+                26.620893
+              ],
+              [
+                98.773113,
+                26.578083
+              ],
+              [
+                98.753403,
+                26.559349
+              ],
+              [
+                98.757098,
+                26.491881
+              ],
+              [
+                98.741084,
+                26.432947
+              ],
+              [
+                98.750323,
+                26.424372
+              ],
+              [
+                98.733693,
+                26.350926
+              ],
+              [
+                98.681338,
+                26.308016
+              ],
+              [
+                98.672715,
+                26.239863
+              ],
+              [
+                98.713367,
+                26.231274
+              ],
+              [
+                98.735541,
+                26.185097
+              ],
+              [
+                98.712751,
+                26.156093
+              ],
+              [
+                98.720142,
+                26.127082
+              ],
+              [
+                98.661012,
+                26.087852
+              ],
+              [
+                98.656084,
+                26.139977
+              ],
+              [
+                98.632679,
+                26.145887
+              ],
+              [
+                98.575396,
+                26.118485
+              ],
+              [
+                98.602498,
+                26.054523
+              ],
+              [
+                98.614201,
+                25.968468
+              ],
+              [
+                98.637606,
+                25.971696
+              ],
+              [
+                98.686881,
+                25.925955
+              ],
+              [
+                98.705976,
+                25.855426
+              ],
+              [
+                98.677642,
+                25.816105
+              ],
+              [
+                98.640686,
+                25.798864
+              ],
+              [
+                98.553839,
+                25.845731
+              ],
+              [
+                98.529201,
+                25.840884
+              ],
+              [
+                98.476846,
+                25.77731
+              ],
+              [
+                98.461448,
+                25.735267
+              ],
+              [
+                98.457752,
+                25.682963
+              ],
+              [
+                98.409709,
+                25.664084
+              ],
+              [
+                98.402317,
+                25.593939
+              ],
+              [
+                98.326557,
+                25.566409
+              ],
+              [
+                98.314854,
+                25.543193
+              ],
+              [
+                98.247717,
+                25.607971
+              ],
+              [
+                98.170724,
+                25.620383
+              ],
+              [
+                98.189818,
+                25.569108
+              ],
+              [
+                98.163949,
+                25.524292
+              ],
+              [
+                98.131304,
+                25.51025
+              ],
+              [
+                98.15779,
+                25.457307
+              ],
+              [
+                98.137464,
+                25.381633
+              ],
+              [
+                98.101123,
+                25.388662
+              ],
+              [
+                98.099891,
+                25.354055
+              ],
+              [
+                98.06971,
+                25.311864
+              ],
+              [
+                98.006884,
+                25.298338
+              ],
+              [
+                98.0075,
+                25.279399
+              ],
+              [
+                97.940363,
+                25.214985
+              ],
+              [
+                97.904023,
+                25.216609
+              ],
+              [
+                97.875689,
+                25.25721
+              ],
+              [
+                97.839349,
+                25.27074
+              ],
+              [
+                97.796233,
+                25.155954
+              ],
+              [
+                97.743262,
+                25.078466
+              ],
+              [
+                97.719857,
+                25.080634
+              ],
+              [
+                97.727864,
+                25.04377
+              ],
+              [
+                97.716777,
+                24.978147
+              ],
+              [
+                97.729712,
+                24.908689
+              ],
+              [
+                97.785762,
+                24.876117
+              ],
+              [
+                97.797465,
+                24.845709
+              ],
+              [
+                97.765436,
+                24.823984
+              ],
+              [
+                97.680437,
+                24.827243
+              ],
+              [
+                97.652103,
+                24.790846
+              ],
+              [
+                97.569567,
+                24.765852
+              ],
+              [
+                97.547394,
+                24.739221
+              ],
+              [
+                97.569567,
+                24.708236
+              ],
+              [
+                97.570799,
+                24.602719
+              ],
+              [
+                97.554785,
+                24.490577
+              ],
+              [
+                97.530147,
+                24.443187
+              ],
+              [
+                97.588662,
+                24.435559
+              ],
+              [
+                97.669966,
+                24.452993
+              ],
+              [
+                97.679821,
+                24.401228
+              ],
+              [
+                97.716161,
+                24.358711
+              ],
+              [
+                97.662574,
+                24.339083
+              ],
+              [
+                97.665038,
+                24.296544
+              ],
+              [
+                97.721089,
+                24.295999
+              ],
+              [
+                97.767284,
+                24.258357
+              ],
+              [
+                97.729712,
+                24.227252
+              ],
+              [
+                97.72848,
+                24.183585
+              ],
+              [
+                97.754349,
+                24.163929
+              ],
+              [
+                97.748806,
+                24.160653
+              ],
+              [
+                97.743262,
+                24.159561
+              ],
+              [
+                97.730944,
+                24.113685
+              ],
+              [
+                97.700763,
+                24.093473
+              ],
+              [
+                97.697067,
+                24.092927
+              ],
+              [
+                97.637321,
+                24.04812
+              ],
+              [
+                97.628698,
+                24.004938
+              ],
+              [
+                97.572647,
+                23.983068
+              ],
+              [
+                97.529531,
+                23.943146
+              ],
+              [
+                97.5283,
+                23.926736
+              ],
+              [
+                97.618227,
+                23.888438
+              ],
+              [
+                97.640401,
+                23.866001
+              ],
+              [
+                97.647176,
+                23.840823
+              ],
+              [
+                97.684132,
+                23.876946
+              ],
+              [
+                97.718009,
+                23.867643
+              ],
+              [
+                97.72848,
+                23.895551
+              ],
+              [
+                97.763588,
+                23.907041
+              ],
+              [
+                97.795617,
+                23.951897
+              ],
+              [
+                97.8104,
+                23.943146
+              ],
+              [
+                97.863371,
+                23.978693
+              ],
+              [
+                97.896015,
+                23.974319
+              ],
+              [
+                97.902175,
+                24.014231
+              ],
+              [
+                97.984095,
+                24.031177
+              ],
+              [
+                97.995182,
+                24.04648
+              ],
+              [
+                98.091268,
+                24.085824
+              ],
+              [
+                98.096196,
+                24.08637
+              ],
+              [
+                98.123297,
+                24.092927
+              ],
+              [
+                98.125761,
+                24.092927
+              ],
+              [
+                98.132536,
+                24.09238
+              ],
+              [
+                98.19721,
+                24.09839
+              ],
+              [
+                98.219999,
+                24.113685
+              ],
+              [
+                98.343187,
+                24.098936
+              ],
+              [
+                98.37768,
+                24.114232
+              ],
+              [
+                98.48239,
+                24.122425
+              ],
+              [
+                98.487933,
+                24.123517
+              ],
+              [
+                98.547063,
+                24.128433
+              ],
+              [
+                98.593875,
+                24.08036
+              ],
+              [
+                98.646229,
+                24.106038
+              ],
+              [
+                98.681954,
+                24.100029
+              ],
+              [
+                98.71891,
+                24.127887
+              ],
+              [
+                98.818692,
+                24.133348
+              ],
+              [
+                98.841482,
+                24.126794
+              ],
+              [
+                98.876591,
+                24.15137
+              ],
+              [
+                98.895069,
+                24.098936
+              ],
+              [
+                98.807606,
+                24.025164
+              ],
+              [
+                98.773729,
+                24.022431
+              ],
+              [
+                98.727533,
+                23.970491
+              ],
+              [
+                98.701048,
+                23.981427
+              ],
+              [
+                98.673331,
+                23.960647
+              ],
+              [
+                98.701048,
+                23.946427
+              ],
+              [
+                98.68565,
+                23.90157
+              ],
+              [
+                98.701664,
+                23.834254
+              ],
+              [
+                98.669019,
+                23.800857
+              ],
+              [
+                98.696121,
+                23.784429
+              ],
+              [
+                98.784816,
+                23.781691
+              ],
+              [
+                98.824236,
+                23.727462
+              ],
+              [
+                98.811917,
+                23.703354
+              ],
+              [
+                98.835939,
+                23.683625
+              ],
+              [
+                98.847026,
+                23.632097
+              ],
+              [
+                98.882134,
+                23.620035
+              ],
+              [
+                98.882134,
+                23.595358
+              ],
+              [
+                98.844562,
+                23.578904
+              ],
+              [
+                98.80391,
+                23.540504
+              ],
+              [
+                98.826084,
+                23.470257
+              ],
+              [
+                98.874743,
+                23.483431
+              ],
+              [
+                98.912315,
+                23.426333
+              ],
+              [
+                98.920938,
+                23.360971
+              ],
+              [
+                98.872895,
+                23.329651
+              ],
+              [
+                98.906772,
+                23.331849
+              ],
+              [
+                98.936953,
+                23.309866
+              ],
+              [
+                98.928946,
+                23.26589
+              ],
+              [
+                98.889525,
+                23.209249
+              ],
+              [
+                98.906772,
+                23.185595
+              ],
+              [
+                99.002242,
+                23.160287
+              ],
+              [
+                99.057677,
+                23.164689
+              ],
+              [
+                99.048438,
+                23.11461
+              ],
+              [
+                99.106336,
+                23.086536
+              ],
+              [
+                99.187024,
+                23.100299
+              ],
+              [
+                99.255393,
+                23.077727
+              ],
+              [
+                99.281879,
+                23.101399
+              ],
+              [
+                99.3484,
+                23.12892
+              ],
+              [
+                99.380429,
+                23.099748
+              ],
+              [
+                99.440791,
+                23.079379
+              ],
+              [
+                99.477747,
+                23.083233
+              ],
+              [
+                99.528255,
+                23.065614
+              ],
+              [
+                99.517168,
+                23.006685
+              ],
+              [
+                99.533798,
+                22.961507
+              ],
+              [
+                99.563363,
+                22.925684
+              ],
+              [
+                99.531334,
+                22.897019
+              ],
+              [
+                99.446951,
+                22.934503
+              ],
+              [
+                99.43648,
+                22.913557
+              ],
+              [
+                99.462965,
+                22.844635
+              ],
+              [
+                99.401371,
+                22.826434
+              ],
+              [
+                99.385357,
+                22.761882
+              ],
+              [
+                99.326842,
+                22.751396
+              ],
+              [
+                99.31514,
+                22.737598
+              ],
+              [
+                99.339777,
+                22.708894
+              ],
+              [
+                99.385973,
+                22.57136
+              ],
+              [
+                99.359487,
+                22.535435
+              ],
+              [
+                99.382277,
+                22.493418
+              ],
+              [
+                99.297277,
+                22.41156
+              ],
+              [
+                99.251698,
+                22.393301
+              ],
+              [
+                99.278183,
+                22.34626
+              ],
+              [
+                99.233836,
+                22.296434
+              ],
+              [
+                99.235683,
+                22.250468
+              ],
+              [
+                99.207966,
+                22.232188
+              ],
+              [
+                99.175321,
+                22.185647
+              ],
+              [
+                99.188256,
+                22.162924
+              ],
+              [
+                99.156227,
+                22.159599
+              ],
+              [
+                99.219669,
+                22.110816
+              ],
+              [
+                99.294814,
+                22.109152
+              ],
+              [
+                99.35456,
+                22.095845
+              ],
+              [
+                99.400139,
+                22.100281
+              ],
+              [
+                99.486987,
+                22.128557
+              ],
+              [
+                99.516552,
+                22.099726
+              ],
+              [
+                99.562747,
+                22.113034
+              ],
+              [
+                99.578762,
+                22.098617
+              ],
+              [
+                99.581841,
+                22.103053
+              ],
+              [
+                99.648979,
+                22.100835
+              ],
+              [
+                99.696406,
+                22.067562
+              ],
+              [
+                99.762927,
+                22.068117
+              ],
+              [
+                99.870101,
+                22.029288
+              ],
+              [
+                99.871333,
+                22.067007
+              ],
+              [
+                99.972347,
+                22.053141
+              ],
+              [
+                99.965571,
+                22.014309
+              ],
+              [
+                100.000064,
+                21.973245
+              ],
+              [
+                99.982202,
+                21.919401
+              ],
+              [
+                99.960028,
+                21.907186
+              ],
+              [
+                99.944014,
+                21.821097
+              ],
+              [
+                99.991441,
+                21.703821
+              ],
+              [
+                100.049339,
+                21.669899
+              ],
+              [
+                100.094303,
+                21.702709
+              ],
+              [
+                100.131875,
+                21.699929
+              ],
+              [
+                100.169447,
+                21.663225
+              ],
+              [
+                100.107853,
+                21.585337
+              ],
+              [
+                100.123252,
+                21.565302
+              ],
+              [
+                100.131259,
+                21.504066
+              ],
+              [
+                100.168831,
+                21.482906
+              ],
+              [
+                100.184846,
+                21.516315
+              ],
+              [
+                100.206404,
+                21.509634
+              ],
+              [
+                100.235353,
+                21.466756
+              ],
+              [
+                100.298795,
+                21.477894
+              ],
+              [
+                100.349302,
+                21.528564
+              ],
+              [
+                100.437381,
+                21.533017
+              ],
+              [
+                100.48296,
+                21.458958
+              ],
+              [
+                100.526692,
+                21.471211
+              ],
+              [
+                100.579047,
+                21.451717
+              ],
+              [
+                100.691764,
+                21.510748
+              ],
+              [
+                100.730568,
+                21.518542
+              ],
+              [
+                100.753358,
+                21.555283
+              ],
+              [
+                100.789082,
+                21.570867
+              ],
+              [
+                100.804481,
+                21.609821
+              ],
+              [
+                100.847597,
+                21.634856
+              ],
+              [
+                100.870386,
+                21.67268
+              ],
+              [
+                100.896872,
+                21.68269
+              ],
+              [
+                100.899335,
+                21.684915
+              ],
+              [
+                100.936292,
+                21.694368
+              ],
+              [
+                100.937524,
+                21.693812
+              ],
+              [
+                101.015132,
+                21.707157
+              ],
+              [
+                101.089661,
+                21.773865
+              ],
+              [
+                101.123537,
+                21.771642
+              ],
+              [
+                101.111835,
+                21.746074
+              ],
+              [
+                101.116762,
+                21.691032
+              ],
+              [
+                101.153102,
+                21.669343
+              ],
+              [
+                101.169117,
+                21.590345
+              ],
+              [
+                101.146943,
+                21.560293
+              ],
+              [
+                101.209153,
+                21.55751
+              ],
+              [
+                101.210385,
+                21.509077
+              ],
+              [
+                101.225167,
+                21.499055
+              ],
+              [
+                101.193138,
+                21.473996
+              ],
+              [
+                101.194986,
+                21.424979
+              ],
+              [
+                101.142631,
+                21.409379
+              ],
+              [
+                101.183899,
+                21.334699
+              ],
+              [
+                101.244877,
+                21.302364
+              ],
+              [
+                101.246725,
+                21.275598
+              ],
+              [
+                101.222088,
+                21.234324
+              ],
+              [
+                101.290457,
+                21.17853
+              ],
+              [
+                101.387775,
+                21.225956
+              ],
+              [
+                101.439514,
+                21.227072
+              ],
+              [
+                101.532521,
+                21.252174
+              ],
+              [
+                101.601506,
+                21.233208
+              ],
+              [
+                101.588572,
+                21.191365
+              ],
+              [
+                101.605818,
+                21.172392
+              ],
+              [
+                101.672339,
+                21.194713
+              ],
+              [
+                101.703136,
+                21.14616
+              ],
+              [
+                101.76473,
+                21.147835
+              ],
+              [
+                101.794911,
+                21.208104
+              ],
+              [
+                101.834331,
+                21.204756
+              ],
+              [
+                101.833715,
+                21.252731
+              ],
+              [
+                101.791832,
+                21.285636
+              ],
+              [
+                101.745636,
+                21.297345
+              ],
+              [
+                101.730238,
+                21.336929
+              ],
+              [
+                101.749948,
+                21.409379
+              ],
+              [
+                101.741324,
+                21.482906
+              ],
+              [
+                101.772737,
+                21.512975
+              ],
+              [
+                101.755491,
+                21.538027
+              ],
+              [
+                101.754875,
+                21.58478
+              ],
+              [
+                101.804766,
+                21.577546
+              ],
+              [
+                101.828788,
+                21.617054
+              ],
+              [
+                101.807846,
+                21.644313
+              ],
+              [
+                101.780129,
+                21.640975
+              ],
+              [
+                101.76781,
+                21.716054
+              ],
+              [
+                101.747484,
+                21.729953
+              ],
+              [
+                101.771506,
+                21.833319
+              ],
+              [
+                101.740093,
+                21.845541
+              ],
+              [
+                101.735165,
+                21.875534
+              ],
+              [
+                101.700057,
+                21.897191
+              ],
+              [
+                101.701288,
+                21.938832
+              ],
+              [
+                101.666796,
+                21.934391
+              ],
+              [
+                101.606434,
+                21.967695
+              ],
+              [
+                101.626144,
+                22.005986
+              ],
+              [
+                101.573789,
+                22.115251
+              ],
+              [
+                101.602738,
+                22.131883
+              ],
+              [
+                101.596579,
+                22.161262
+              ],
+              [
+                101.547304,
+                22.238282
+              ],
+              [
+                101.56455,
+                22.269299
+              ],
+              [
+                101.625528,
+                22.28259
+              ],
+              [
+                101.671723,
+                22.372826
+              ],
+              [
+                101.648318,
+                22.400494
+              ],
+              [
+                101.672339,
+                22.47517
+              ],
+              [
+                101.715455,
+                22.477935
+              ],
+              [
+                101.774585,
+                22.506135
+              ],
+              [
+                101.824476,
+                22.45692
+              ],
+              [
+                101.823244,
+                22.42705
+              ],
+              [
+                101.862665,
+                22.389427
+              ],
+              [
+                101.901469,
+                22.384447
+              ],
+              [
+                101.907628,
+                22.437007
+              ],
+              [
+                101.978461,
+                22.427603
+              ],
+              [
+                102.046214,
+                22.458026
+              ],
+              [
+                102.131214,
+                22.430922
+              ],
+              [
+                102.145381,
+                22.397727
+              ],
+              [
+                102.179257,
+                22.430369
+              ],
+              [
+                102.270416,
+                22.419858
+              ],
+              [
+                102.25625,
+                22.457473
+              ],
+              [
+                102.322771,
+                22.554227
+              ],
+              [
+                102.356648,
+                22.563623
+              ],
+              [
+                102.404691,
+                22.629925
+              ],
+              [
+                102.384365,
+                22.679631
+              ],
+              [
+                102.43672,
+                22.699508
+              ],
+              [
+                102.45951,
+                22.762986
+              ],
+              [
+                102.510633,
+                22.774574
+              ],
+              [
+                102.551285,
+                22.743669
+              ],
+              [
+                102.569763,
+                22.701164
+              ],
+              [
+                102.607335,
+                22.730975
+              ],
+              [
+                102.657226,
+                22.687913
+              ],
+              [
+                102.688639,
+                22.70006
+              ],
+              [
+                102.80074,
+                22.620534
+              ],
+              [
+                102.82353,
+                22.623296
+              ],
+              [
+                102.880196,
+                22.586832
+              ],
+              [
+                102.892515,
+                22.533223
+              ],
+              [
+                102.930703,
+                22.482359
+              ],
+              [
+                102.986754,
+                22.477935
+              ],
+              [
+                103.030485,
+                22.441432
+              ],
+              [
+                103.081608,
+                22.454154
+              ],
+              [
+                103.071753,
+                22.488441
+              ],
+              [
+                103.183238,
+                22.558649
+              ],
+              [
+                103.161065,
+                22.590147
+              ],
+              [
+                103.195557,
+                22.648153
+              ],
+              [
+                103.220195,
+                22.643734
+              ],
+              [
+                103.283021,
+                22.678526
+              ],
+              [
+                103.288564,
+                22.732078
+              ],
+              [
+                103.321209,
+                22.777885
+              ],
+              [
+                103.323057,
+                22.807678
+              ],
+              [
+                103.375411,
+                22.794989
+              ],
+              [
+                103.441317,
+                22.753052
+              ],
+              [
+                103.436389,
+                22.6973
+              ],
+              [
+                103.457947,
+                22.658646
+              ],
+              [
+                103.50907,
+                22.601198
+              ],
+              [
+                103.529396,
+                22.59291
+              ],
+              [
+                103.580519,
+                22.66693
+              ],
+              [
+                103.567585,
+                22.701164
+              ],
+              [
+                103.642113,
+                22.794989
+              ],
+              [
+                103.740048,
+                22.709446
+              ],
+              [
+                103.743127,
+                22.697852
+              ],
+              [
+                103.766533,
+                22.688465
+              ],
+              [
+                103.825047,
+                22.615562
+              ],
+              [
+                103.863851,
+                22.584069
+              ],
+              [
+                103.875554,
+                22.565833
+              ],
+              [
+                103.894032,
+                22.564728
+              ],
+              [
+                103.964865,
+                22.502265
+              ],
+              [
+                104.009213,
+                22.517745
+              ],
+              [
+                104.009213,
+                22.575228
+              ],
+              [
+                104.022148,
+                22.593463
+              ],
+              [
+                104.04309,
+                22.67687
+              ],
+              [
+                104.045553,
+                22.728215
+              ],
+              [
+                104.089901,
+                22.768504
+              ],
+              [
+                104.117618,
+                22.808781
+              ],
+              [
+                104.224176,
+                22.826434
+              ],
+              [
+                104.261748,
+                22.841877
+              ],
+              [
+                104.274067,
+                22.828088
+              ],
+              [
+                104.256821,
+                22.77347
+              ],
+              [
+                104.272835,
+                22.73815
+              ],
+              [
+                104.323342,
+                22.728767
+              ],
+              [
+                104.375697,
+                22.690122
+              ],
+              [
+                104.422508,
+                22.734838
+              ],
+              [
+                104.498885,
+                22.774574
+              ],
+              [
+                104.527834,
+                22.814298
+              ],
+              [
+                104.596203,
+                22.846289
+              ],
+              [
+                104.674428,
+                22.817056
+              ],
+              [
+                104.737869,
+                22.825882
+              ],
+              [
+                104.732942,
+                22.852356
+              ],
+              [
+                104.760659,
+                22.862282
+              ],
+              [
+                104.772362,
+                22.893711
+              ],
+              [
+                104.846275,
+                22.926235
+              ],
+              [
+                104.860441,
+                22.970874
+              ],
+              [
+                104.821021,
+                23.032022
+              ],
+              [
+                104.804391,
+                23.110207
+              ],
+              [
+                104.874608,
+                23.123417
+              ],
+              [
+                104.882615,
+                23.163589
+              ],
+              [
+                104.912796,
+                23.175693
+              ],
+              [
+                104.949136,
+                23.152033
+              ],
+              [
+                104.958991,
+                23.188896
+              ],
+              [
+                105.093266,
+                23.260942
+              ],
+              [
+                105.122215,
+                23.247745
+              ],
+              [
+                105.181962,
+                23.279084
+              ],
+              [
+                105.238012,
+                23.26424
+              ],
+              [
+                105.260186,
+                23.31811
+              ],
+              [
+                105.325475,
+                23.390086
+              ],
+              [
+                105.353809,
+                23.362069
+              ],
+              [
+                105.372903,
+                23.317561
+              ],
+              [
+                105.416018,
+                23.283482
+              ],
+              [
+                105.445584,
+                23.292827
+              ],
+              [
+                105.50225,
+                23.202648
+              ],
+              [
+                105.542902,
+                23.184495
+              ],
+              [
+                105.526272,
+                23.234548
+              ],
+              [
+                105.560148,
+                23.257093
+              ],
+              [
+                105.593409,
+                23.312614
+              ],
+              [
+                105.649459,
+                23.346136
+              ],
+              [
+                105.699966,
+                23.327453
+              ],
+              [
+                105.694423,
+                23.363168
+              ],
+              [
+                105.637757,
+                23.404366
+              ],
+              [
+                105.699966,
+                23.40162
+              ],
+              [
+                105.758481,
+                23.459826
+              ],
+              [
+                105.805908,
+                23.467512
+              ],
+              [
+                105.815763,
+                23.507031
+              ],
+              [
+                105.852103,
+                23.526786
+              ],
+              [
+                105.89214,
+                23.52514
+              ],
+              [
+                105.913081,
+                23.499348
+              ],
+              [
+                105.935871,
+                23.508678
+              ],
+              [
+                105.986378,
+                23.489469
+              ],
+              [
+                105.999929,
+                23.447748
+              ],
+              [
+                106.039965,
+                23.484529
+              ],
+              [
+                106.071994,
+                23.495506
+              ],
+              [
+                106.08616,
+                23.524043
+              ],
+              [
+                106.141595,
+                23.569579
+              ],
+              [
+                106.120653,
+                23.605229
+              ],
+              [
+                106.149602,
+                23.665538
+              ],
+              [
+                106.157609,
+                23.724175
+              ],
+              [
+                106.136667,
+                23.795381
+              ],
+              [
+                106.192102,
+                23.824947
+              ],
+              [
+                106.173008,
+                23.861622
+              ],
+              [
+                106.192718,
+                23.879135
+              ],
+              [
+                106.157609,
+                23.891174
+              ],
+              [
+                106.128044,
+                23.956819
+              ],
+              [
+                106.091088,
+                23.998924
+              ],
+              [
+                106.096631,
+                24.018058
+              ],
+              [
+                106.053516,
+                24.051399
+              ],
+              [
+                106.04982,
+                24.089649
+              ],
+              [
+                106.011632,
+                24.099482
+              ],
+              [
+                105.998081,
+                24.120786
+              ],
+              [
+                105.963589,
+                24.110954
+              ],
+              [
+                105.919241,
+                24.122425
+              ],
+              [
+                105.901995,
+                24.099482
+              ],
+              [
+                105.908154,
+                24.069432
+              ],
+              [
+                105.89214,
+                24.040468
+              ],
+              [
+                105.859495,
+                24.056864
+              ],
+              [
+                105.841633,
+                24.03063
+              ],
+              [
+                105.796669,
+                24.023524
+              ],
+              [
+                105.802212,
+                24.051945
+              ],
+              [
+                105.765256,
+                24.073804
+              ],
+              [
+                105.739387,
+                24.059596
+              ],
+              [
+                105.704278,
+                24.0667
+              ],
+              [
+                105.649459,
+                24.032816
+              ],
+              [
+                105.628518,
+                24.126794
+              ],
+              [
+                105.594641,
+                24.137718
+              ],
+              [
+                105.533663,
+                24.130071
+              ],
+              [
+                105.493011,
+                24.016965
+              ],
+              [
+                105.406163,
+                24.043748
+              ],
+              [
+                105.395692,
+                24.065607
+              ],
+              [
+                105.334099,
+                24.094566
+              ],
+              [
+                105.320548,
+                24.116416
+              ],
+              [
+                105.273121,
+                24.092927
+              ],
+              [
+                105.292831,
+                24.074896
+              ],
+              [
+                105.260186,
+                24.061236
+              ],
+              [
+                105.20044,
+                24.105491
+              ],
+              [
+                105.182577,
+                24.167205
+              ],
+              [
+                105.229389,
+                24.165567
+              ],
+              [
+                105.24294,
+                24.208695
+              ],
+              [
+                105.215222,
+                24.214699
+              ],
+              [
+                105.164715,
+                24.288362
+              ],
+              [
+                105.196744,
+                24.326541
+              ],
+              [
+                105.188121,
+                24.347261
+              ],
+              [
+                105.138846,
+                24.376701
+              ],
+              [
+                105.111744,
+                24.37234
+              ],
+              [
+                105.106817,
+                24.414853
+              ],
+              [
+                105.042759,
+                24.442097
+              ],
+              [
+                104.979933,
+                24.412673
+              ],
+              [
+                104.930042,
+                24.411038
+              ],
+              [
+                104.914028,
+                24.426296
+              ],
+              [
+                104.83642,
+                24.446456
+              ],
+              [
+                104.784681,
+                24.443732
+              ],
+              [
+                104.765587,
+                24.45953
+              ],
+              [
+                104.74834,
+                24.435559
+              ],
+              [
+                104.715695,
+                24.441552
+              ],
+              [
+                104.703377,
+                24.419757
+              ],
+              [
+                104.721239,
+                24.340173
+              ],
+              [
+                104.70892,
+                24.321087
+              ],
+              [
+                104.641783,
+                24.367979
+              ],
+              [
+                104.610986,
+                24.377246
+              ],
+              [
+                104.63008,
+                24.397958
+              ],
+              [
+                104.616529,
+                24.421937
+              ],
+              [
+                104.575877,
+                24.424661
+              ],
+              [
+                104.550008,
+                24.518894
+              ],
+              [
+                104.520443,
+                24.535228
+              ],
+              [
+                104.489646,
+                24.653313
+              ],
+              [
+                104.529682,
+                24.731611
+              ],
+              [
+                104.542616,
+                24.75607
+              ],
+              [
+                104.539537,
+                24.813663
+              ],
+              [
+                104.586964,
+                24.872859
+              ],
+              [
+                104.635623,
+                24.903803
+              ],
+              [
+                104.663957,
+                24.964584
+              ],
+              [
+                104.713232,
+                24.996048
+              ],
+              [
+                104.684898,
+                25.054072
+              ],
+              [
+                104.619609,
+                25.060577
+              ],
+              [
+                104.685514,
+                25.078466
+              ],
+              [
+                104.695369,
+                25.122364
+              ],
+              [
+                104.732326,
+                25.167871
+              ],
+              [
+                104.724319,
+                25.195491
+              ],
+              [
+                104.753884,
+                25.214443
+              ],
+              [
+                104.801927,
+                25.163537
+              ],
+              [
+                104.822869,
+                25.170037
+              ],
+              [
+                104.806854,
+                25.224189
+              ],
+              [
+                104.826565,
+                25.235558
+              ],
+              [
+                104.816094,
+                25.262622
+              ],
+              [
+                104.736021,
+                25.268034
+              ],
+              [
+                104.689826,
+                25.296173
+              ],
+              [
+                104.639935,
+                25.295632
+              ],
+              [
+                104.646094,
+                25.356759
+              ],
+              [
+                104.615913,
+                25.364871
+              ],
+              [
+                104.566638,
+                25.402719
+              ],
+              [
+                104.543232,
+                25.400556
+              ],
+              [
+                104.556783,
+                25.524832
+              ],
+              [
+                104.524138,
+                25.526992
+              ],
+              [
+                104.483486,
+                25.494585
+              ],
+              [
+                104.44961,
+                25.495126
+              ],
+              [
+                104.434827,
+                25.472436
+              ],
+              [
+                104.418813,
+                25.499447
+              ],
+              [
+                104.436059,
+                25.520512
+              ],
+              [
+                104.428668,
+                25.576126
+              ],
+              [
+                104.389248,
+                25.595558
+              ],
+              [
+                104.332581,
+                25.598796
+              ],
+              [
+                104.310407,
+                25.647901
+              ],
+              [
+                104.328886,
+                25.760602
+              ],
+              [
+                104.370769,
+                25.730415
+              ],
+              [
+                104.397871,
+                25.76168
+              ],
+              [
+                104.42374,
+                25.841961
+              ],
+              [
+                104.441602,
+                25.868889
+              ],
+              [
+                104.414501,
+                25.909807
+              ],
+              [
+                104.438523,
+                25.92757
+              ],
+              [
+                104.470552,
+                26.009352
+              ],
+              [
+                104.460081,
+                26.085702
+              ],
+              [
+                104.499501,
+                26.070651
+              ],
+              [
+                104.52845,
+                26.114186
+              ],
+              [
+                104.518595,
+                26.165762
+              ],
+              [
+                104.548776,
+                26.226979
+              ],
+              [
+                104.542616,
+                26.253282
+              ],
+              [
+                104.592508,
+                26.317672
+              ],
+              [
+                104.659645,
+                26.335373
+              ],
+              [
+                104.684283,
+                26.3772
+              ],
+              [
+                104.664572,
+                26.397572
+              ],
+              [
+                104.665804,
+                26.434019
+              ],
+              [
+                104.631928,
+                26.451702
+              ],
+              [
+                104.638703,
+                26.477954
+              ],
+              [
+                104.598667,
+                26.520801
+              ],
+              [
+                104.57095,
+                26.524549
+              ],
+              [
+                104.579573,
+                26.568449
+              ],
+              [
+                104.556783,
+                26.590393
+              ],
+              [
+                104.488414,
+                26.579689
+              ],
+              [
+                104.459465,
+                26.602701
+              ],
+              [
+                104.468088,
+                26.644431
+              ],
+              [
+                104.424356,
+                26.709137
+              ],
+              [
+                104.398487,
+                26.686147
+              ],
+              [
+                104.353523,
+                26.620893
+              ],
+              [
+                104.313487,
+                26.612867
+              ],
+              [
+                104.274683,
+                26.633733
+              ],
+              [
+                104.268524,
+                26.617683
+              ],
+              [
+                104.222328,
+                26.620358
+              ],
+              [
+                104.160734,
+                26.646571
+              ],
+              [
+                104.121314,
+                26.638012
+              ],
+              [
+                104.068343,
+                26.573266
+              ],
+              [
+                104.067727,
+                26.51491
+              ],
+              [
+                104.008597,
+                26.511697
+              ],
+              [
+                103.953163,
+                26.521336
+              ],
+              [
+                103.865699,
+                26.512232
+              ],
+              [
+                103.819504,
+                26.529903
+              ],
+              [
+                103.815808,
+                26.55239
+              ],
+              [
+                103.763453,
+                26.585041
+              ],
+              [
+                103.748671,
+                26.623568
+              ],
+              [
+                103.759142,
+                26.689355
+              ],
+              [
+                103.773308,
+                26.716621
+              ],
+              [
+                103.725265,
+                26.742812
+              ],
+              [
+                103.705555,
+                26.794642
+              ],
+              [
+                103.722185,
+                26.851253
+              ],
+              [
+                103.779468,
+                26.87421
+              ],
+              [
+                103.763453,
+                26.905702
+              ],
+              [
+                103.775156,
+                26.951056
+              ],
+              [
+                103.753598,
+                26.963858
+              ],
+              [
+                103.73204,
+                27.018785
+              ],
+              [
+                103.704939,
+                27.049171
+              ],
+              [
+                103.675374,
+                27.051836
+              ],
+              [
+                103.623019,
+                27.007056
+              ],
+              [
+                103.623635,
+                27.035312
+              ],
+              [
+                103.601461,
+                27.061962
+              ],
+              [
+                103.614396,
+                27.079548
+              ],
+              [
+                103.659975,
+                27.065692
+              ],
+              [
+                103.652584,
+                27.092868
+              ],
+              [
+                103.620555,
+                27.096598
+              ],
+              [
+                103.63349,
+                27.12057
+              ],
+              [
+                103.696316,
+                27.126429
+              ],
+              [
+                103.748671,
+                27.210021
+              ],
+              [
+                103.801641,
+                27.250464
+              ],
+              [
+                103.80041,
+                27.26536
+              ],
+              [
+                103.865699,
+                27.28185
+              ],
+              [
+                103.874322,
+                27.331304
+              ],
+              [
+                103.903271,
+                27.347785
+              ],
+              [
+                103.905119,
+                27.38552
+              ],
+              [
+                103.932221,
+                27.443958
+              ],
+              [
+                103.956242,
+                27.425367
+              ],
+              [
+                104.015372,
+                27.429086
+              ],
+              [
+                104.01722,
+                27.383926
+              ],
+              [
+                104.084358,
+                27.330773
+              ],
+              [
+                104.113923,
+                27.338216
+              ],
+              [
+                104.173053,
+                27.263232
+              ],
+              [
+                104.210625,
+                27.297273
+              ],
+              [
+                104.248813,
+                27.291955
+              ],
+              [
+                104.247582,
+                27.336621
+              ],
+              [
+                104.295625,
+                27.37436
+              ],
+              [
+                104.30856,
+                27.407305
+              ],
+              [
+                104.363378,
+                27.467855
+              ],
+              [
+                104.467472,
+                27.414211
+              ],
+              [
+                104.497037,
+                27.414743
+              ],
+              [
+                104.539537,
+                27.327583
+              ],
+              [
+                104.570334,
+                27.331836
+              ],
+              [
+                104.611602,
+                27.306846
+              ],
+              [
+                104.7545,
+                27.345658
+              ],
+              [
+                104.77113,
+                27.317481
+              ],
+              [
+                104.824717,
+                27.3531
+              ],
+              [
+                104.856746,
+                27.332368
+              ],
+              [
+                104.851818,
+                27.299401
+              ],
+              [
+                104.871528,
+                27.290891
+              ],
+              [
+                104.913412,
+                27.327051
+              ],
+              [
+                105.01073,
+                27.379143
+              ],
+              [
+                105.068013,
+                27.418461
+              ],
+              [
+                105.120984,
+                27.418461
+              ],
+              [
+                105.184425,
+                27.392959
+              ],
+              [
+                105.182577,
+                27.367451
+              ],
+              [
+                105.233084,
+                27.436522
+              ],
+              [
+                105.234316,
+                27.489093
+              ],
+              [
+                105.260186,
+                27.514573
+              ],
+              [
+                105.232469,
+                27.546945
+              ],
+              [
+                105.25649,
+                27.582491
+              ],
+              [
+                105.304533,
+                27.611661
+              ],
+              [
+                105.29591,
+                27.631811
+              ],
+              [
+                105.308229,
+                27.704955
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 540000,
+        "name": "瑗胯棌鑷不鍖�",
+        "center": [
+          91.132212,
+          29.660361
+        ],
+        "centroid": [
+          88.388277,
+          31.56375
+        ],
+        "childrenNum": 7,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 25,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                89.711414,
+                36.093272
+              ],
+              [
+                89.614711,
+                36.109712
+              ],
+              [
+                89.594385,
+                36.126632
+              ],
+              [
+                89.490291,
+                36.151281
+              ],
+              [
+                89.375727,
+                36.228078
+              ],
+              [
+                89.335075,
+                36.23725
+              ],
+              [
+                89.292575,
+                36.231457
+              ],
+              [
+                89.232213,
+                36.295636
+              ],
+              [
+                89.198952,
+                36.260417
+              ],
+              [
+                89.126887,
+                36.254626
+              ],
+              [
+                89.10225,
+                36.281164
+              ],
+              [
+                89.054822,
+                36.291777
+              ],
+              [
+                89.013554,
+                36.315409
+              ],
+              [
+                88.964279,
+                36.318785
+              ],
+              [
+                88.926091,
+                36.36458
+              ],
+              [
+                88.870657,
+                36.348193
+              ],
+              [
+                88.838628,
+                36.353496
+              ],
+              [
+                88.802903,
+                36.33807
+              ],
+              [
+                88.783809,
+                36.291777
+              ],
+              [
+                88.766563,
+                36.292259
+              ],
+              [
+                88.690186,
+                36.367954
+              ],
+              [
+                88.623665,
+                36.389636
+              ],
+              [
+                88.618121,
+                36.428168
+              ],
+              [
+                88.573158,
+                36.461386
+              ],
+              [
+                88.498629,
+                36.446463
+              ],
+              [
+                88.470912,
+                36.48208
+              ],
+              [
+                88.41055,
+                36.473418
+              ],
+              [
+                88.356963,
+                36.477268
+              ],
+              [
+                88.366202,
+                36.458016
+              ],
+              [
+                88.282434,
+                36.470049
+              ],
+              [
+                88.241782,
+                36.468605
+              ],
+              [
+                88.222688,
+                36.447426
+              ],
+              [
+                88.182652,
+                36.452721
+              ],
+              [
+                88.134609,
+                36.427205
+              ],
+              [
+                88.092109,
+                36.43539
+              ],
+              [
+                88.006494,
+                36.430575
+              ],
+              [
+                87.983088,
+                36.437797
+              ],
+              [
+                87.95845,
+                36.408423
+              ],
+              [
+                87.919646,
+                36.39349
+              ],
+              [
+                87.838342,
+                36.383855
+              ],
+              [
+                87.826023,
+                36.391563
+              ],
+              [
+                87.767509,
+                36.3747
+              ],
+              [
+                87.731785,
+                36.384818
+              ],
+              [
+                87.6203,
+                36.360243
+              ],
+              [
+                87.570409,
+                36.342409
+              ],
+              [
+                87.470626,
+                36.354459
+              ],
+              [
+                87.460155,
+                36.409868
+              ],
+              [
+                87.426895,
+                36.42576
+              ],
+              [
+                87.386859,
+                36.412757
+              ],
+              [
+                87.363453,
+                36.420463
+              ],
+              [
+                87.348055,
+                36.393008
+              ],
+              [
+                87.292004,
+                36.358797
+              ],
+              [
+                87.193454,
+                36.349158
+              ],
+              [
+                87.161425,
+                36.325535
+              ],
+              [
+                87.149106,
+                36.297565
+              ],
+              [
+                87.08628,
+                36.310587
+              ],
+              [
+                87.051788,
+                36.2966
+              ],
+              [
+                86.996353,
+                36.308658
+              ],
+              [
+                86.943998,
+                36.284058
+              ],
+              [
+                86.931064,
+                36.265242
+              ],
+              [
+                86.887332,
+                36.262829
+              ],
+              [
+                86.86331,
+                36.299977
+              ],
+              [
+                86.836209,
+                36.291294
+              ],
+              [
+                86.746282,
+                36.291777
+              ],
+              [
+                86.69947,
+                36.24449
+              ],
+              [
+                86.599072,
+                36.222285
+              ],
+              [
+                86.531935,
+                36.227113
+              ],
+              [
+                86.515305,
+                36.205385
+              ],
+              [
+                86.454943,
+                36.221319
+              ],
+              [
+                86.392733,
+                36.206834
+              ],
+              [
+                86.35824,
+                36.168676
+              ],
+              [
+                86.2794,
+                36.170608
+              ],
+              [
+                86.248603,
+                36.141616
+              ],
+              [
+                86.187625,
+                36.130983
+              ],
+              [
+                86.182081,
+                36.064734
+              ],
+              [
+                86.199944,
+                36.047801
+              ],
+              [
+                86.173458,
+                36.008113
+              ],
+              [
+                86.150668,
+                36.00424
+              ],
+              [
+                86.129111,
+                35.941761
+              ],
+              [
+                86.093386,
+                35.906868
+              ],
+              [
+                86.090306,
+                35.876809
+              ],
+              [
+                86.05335,
+                35.842857
+              ],
+              [
+                86.035488,
+                35.846738
+              ],
+              [
+                85.949256,
+                35.778794
+              ],
+              [
+                85.903677,
+                35.78462
+              ],
+              [
+                85.835308,
+                35.771996
+              ],
+              [
+                85.811286,
+                35.778794
+              ],
+              [
+                85.691178,
+                35.751114
+              ],
+              [
+                85.65299,
+                35.731199
+              ],
+              [
+                85.612953,
+                35.651486
+              ],
+              [
+                85.566142,
+                35.6403
+              ],
+              [
+                85.518715,
+                35.680658
+              ],
+              [
+                85.373969,
+                35.700101
+              ],
+              [
+                85.341324,
+                35.753543
+              ],
+              [
+                85.271107,
+                35.788989
+              ],
+              [
+                85.146071,
+                35.742371
+              ],
+              [
+                85.053065,
+                35.752086
+              ],
+              [
+                84.99455,
+                35.737028
+              ],
+              [
+                84.973608,
+                35.709334
+              ],
+              [
+                84.920022,
+                35.696213
+              ],
+              [
+                84.798066,
+                35.647595
+              ],
+              [
+                84.729081,
+                35.613546
+              ],
+              [
+                84.704443,
+                35.616951
+              ],
+              [
+                84.628067,
+                35.595055
+              ],
+              [
+                84.570168,
+                35.588242
+              ],
+              [
+                84.513502,
+                35.564391
+              ],
+              [
+                84.448828,
+                35.550272
+              ],
+              [
+                84.475929,
+                35.516181
+              ],
+              [
+                84.45314,
+                35.473303
+              ],
+              [
+                84.424191,
+                35.466479
+              ],
+              [
+                84.333032,
+                35.413821
+              ],
+              [
+                84.274517,
+                35.404065
+              ],
+              [
+                84.200605,
+                35.381135
+              ],
+              [
+                84.160569,
+                35.359663
+              ],
+              [
+                84.140859,
+                35.379184
+              ],
+              [
+                84.095895,
+                35.362592
+              ],
+              [
+                84.077417,
+                35.400163
+              ],
+              [
+                84.005968,
+                35.422599
+              ],
+              [
+                83.906186,
+                35.40309
+              ],
+              [
+                83.885244,
+                35.367472
+              ],
+              [
+                83.79778,
+                35.354783
+              ],
+              [
+                83.785462,
+                35.36308
+              ],
+              [
+                83.677672,
+                35.361128
+              ],
+              [
+                83.622238,
+                35.335256
+              ],
+              [
+                83.599448,
+                35.351366
+              ],
+              [
+                83.54155,
+                35.341603
+              ],
+              [
+                83.540318,
+                35.364056
+              ],
+              [
+                83.502745,
+                35.360639
+              ],
+              [
+                83.449159,
+                35.382111
+              ],
+              [
+                83.405427,
+                35.380648
+              ],
+              [
+                83.333978,
+                35.397236
+              ],
+              [
+                83.280391,
+                35.401138
+              ],
+              [
+                83.251442,
+                35.417722
+              ],
+              [
+                83.178145,
+                35.38943
+              ],
+              [
+                83.127022,
+                35.398699
+              ],
+              [
+                83.088834,
+                35.425526
+              ],
+              [
+                83.067892,
+                35.46258
+              ],
+              [
+                82.998907,
+                35.484512
+              ],
+              [
+                82.971806,
+                35.548324
+              ],
+              [
+                82.981661,
+                35.599922
+              ],
+              [
+                82.956407,
+                35.636409
+              ],
+              [
+                82.967494,
+                35.667532
+              ],
+              [
+                82.894813,
+                35.673852
+              ],
+              [
+                82.873871,
+                35.688922
+              ],
+              [
+                82.795031,
+                35.688436
+              ],
+              [
+                82.780249,
+                35.666073
+              ],
+              [
+                82.731589,
+                35.637868
+              ],
+              [
+                82.652133,
+                35.67288
+              ],
+              [
+                82.628727,
+                35.692324
+              ],
+              [
+                82.546192,
+                35.708362
+              ],
+              [
+                82.501844,
+                35.701073
+              ],
+              [
+                82.468583,
+                35.717595
+              ],
+              [
+                82.424852,
+                35.712736
+              ],
+              [
+                82.392823,
+                35.656349
+              ],
+              [
+                82.336156,
+                35.651486
+              ],
+              [
+                82.350323,
+                35.611113
+              ],
+              [
+                82.328149,
+                35.559523
+              ],
+              [
+                82.2992,
+                35.544916
+              ],
+              [
+                82.263475,
+                35.547837
+              ],
+              [
+                82.234526,
+                35.520565
+              ],
+              [
+                82.189563,
+                35.513258
+              ],
+              [
+                82.164925,
+                35.495719
+              ],
+              [
+                82.086701,
+                35.467454
+              ],
+              [
+                82.071302,
+                35.450393
+              ],
+              [
+                82.034346,
+                35.451855
+              ],
+              [
+                82.029419,
+                35.426013
+              ],
+              [
+                82.05344,
+                35.35039
+              ],
+              [
+                82.030034,
+                35.321585
+              ],
+              [
+                81.99123,
+                35.30547
+              ],
+              [
+                81.955506,
+                35.307423
+              ],
+              [
+                81.927789,
+                35.271275
+              ],
+              [
+                81.853876,
+                35.25857
+              ],
+              [
+                81.804601,
+                35.270786
+              ],
+              [
+                81.736847,
+                35.26248
+              ],
+              [
+                81.68634,
+                35.235599
+              ],
+              [
+                81.513261,
+                35.23511
+              ],
+              [
+                81.504638,
+                35.279092
+              ],
+              [
+                81.447972,
+                35.318167
+              ],
+              [
+                81.441196,
+                35.333303
+              ],
+              [
+                81.385762,
+                35.335256
+              ],
+              [
+                81.363588,
+                35.354783
+              ],
+              [
+                81.314313,
+                35.337209
+              ],
+              [
+                81.285364,
+                35.345508
+              ],
+              [
+                81.26627,
+                35.322562
+              ],
+              [
+                81.219458,
+                35.319144
+              ],
+              [
+                81.191741,
+                35.36552
+              ],
+              [
+                81.142466,
+                35.365032
+              ],
+              [
+                81.103662,
+                35.386015
+              ],
+              [
+                81.09935,
+                35.40748
+              ],
+              [
+                81.054387,
+                35.402602
+              ],
+              [
+                81.031597,
+                35.380648
+              ],
+              [
+                81.030981,
+                35.337209
+              ],
+              [
+                81.002648,
+                35.334768
+              ],
+              [
+                81.026053,
+                35.31133
+              ],
+              [
+                80.963844,
+                35.310842
+              ],
+              [
+                80.924423,
+                35.330862
+              ],
+              [
+                80.894242,
+                35.324027
+              ],
+              [
+                80.844351,
+                35.345508
+              ],
+              [
+                80.759968,
+                35.334768
+              ],
+              [
+                80.689135,
+                35.339162
+              ],
+              [
+                80.690982,
+                35.364544
+              ],
+              [
+                80.65649,
+                35.393821
+              ],
+              [
+                80.599823,
+                35.409431
+              ],
+              [
+                80.56841,
+                35.391381
+              ],
+              [
+                80.532686,
+                35.404553
+              ],
+              [
+                80.514824,
+                35.391869
+              ],
+              [
+                80.444607,
+                35.417235
+              ],
+              [
+                80.432904,
+                35.449418
+              ],
+              [
+                80.375006,
+                35.387966
+              ],
+              [
+                80.321419,
+                35.38699
+              ],
+              [
+                80.286926,
+                35.35283
+              ],
+              [
+                80.267832,
+                35.295701
+              ],
+              [
+                80.362687,
+                35.20871
+              ],
+              [
+                80.257977,
+                35.203331
+              ],
+              [
+                80.223484,
+                35.177409
+              ],
+              [
+                80.23026,
+                35.147565
+              ],
+              [
+                80.118159,
+                35.066293
+              ],
+              [
+                80.078123,
+                35.076578
+              ],
+              [
+                80.031311,
+                35.034447
+              ],
+              [
+                80.04363,
+                35.022196
+              ],
+              [
+                80.02392,
+                34.971209
+              ],
+              [
+                80.041782,
+                34.943252
+              ],
+              [
+                80.034391,
+                34.902033
+              ],
+              [
+                80.003594,
+                34.895162
+              ],
+              [
+                79.996819,
+                34.856375
+              ],
+              [
+                79.961094,
+                34.862759
+              ],
+              [
+                79.926602,
+                34.849499
+              ],
+              [
+                79.947544,
+                34.821008
+              ],
+              [
+                79.898268,
+                34.732035
+              ],
+              [
+                79.906892,
+                34.683821
+              ],
+              [
+                79.866856,
+                34.671517
+              ],
+              [
+                79.88595,
+                34.642965
+              ],
+              [
+                79.84345,
+                34.55725
+              ],
+              [
+                79.861312,
+                34.528166
+              ],
+              [
+                79.801566,
+                34.478847
+              ],
+              [
+                79.735661,
+                34.471447
+              ],
+              [
+                79.699936,
+                34.477861
+              ],
+              [
+                79.675914,
+                34.451216
+              ],
+              [
+                79.58106,
+                34.456151
+              ],
+              [
+                79.545335,
+                34.476381
+              ],
+              [
+                79.504683,
+                34.45467
+              ],
+              [
+                79.435082,
+                34.447761
+              ],
+              [
+                79.363017,
+                34.428018
+              ],
+              [
+                79.326677,
+                34.44332
+              ],
+              [
+                79.274322,
+                34.435916
+              ],
+              [
+                79.241677,
+                34.415183
+              ],
+              [
+                79.179467,
+                34.422588
+              ],
+              [
+                79.161605,
+                34.441345
+              ],
+              [
+                79.072294,
+                34.412714
+              ],
+              [
+                79.039033,
+                34.421601
+              ],
+              [
+                79.0107,
+                34.399877
+              ],
+              [
+                79.048888,
+                34.348506
+              ],
+              [
+                79.039649,
+                34.33467
+              ],
+              [
+                79.019939,
+                34.313417
+              ],
+              [
+                78.981751,
+                34.31836
+              ],
+              [
+                78.958345,
+                34.230827
+              ],
+              [
+                78.941099,
+                34.212022
+              ],
+              [
+                78.9257,
+                34.155584
+              ],
+              [
+                78.910302,
+                34.143202
+              ],
+              [
+                78.878273,
+                34.163012
+              ],
+              [
+                78.828998,
+                34.125369
+              ],
+              [
+                78.801897,
+                34.137258
+              ],
+              [
+                78.737223,
+                34.089692
+              ],
+              [
+                78.661462,
+                34.086718
+              ],
+              [
+                78.656535,
+                34.030196
+              ],
+              [
+                78.736607,
+                33.999937
+              ],
+              [
+                78.744614,
+                33.980585
+              ],
+              [
+                78.734143,
+                33.918529
+              ],
+              [
+                78.762476,
+                33.90959
+              ],
+              [
+                78.756317,
+                33.8773
+              ],
+              [
+                78.766172,
+                33.823124
+              ],
+              [
+                78.758165,
+                33.790802
+              ],
+              [
+                78.779723,
+                33.73259
+              ],
+              [
+                78.692259,
+                33.676331
+              ],
+              [
+                78.684868,
+                33.654415
+              ],
+              [
+                78.713201,
+                33.623025
+              ],
+              [
+                78.755085,
+                33.623025
+              ],
+              [
+                78.74215,
+                33.55323
+              ],
+              [
+                78.816679,
+                33.480882
+              ],
+              [
+                78.84994,
+                33.419963
+              ],
+              [
+                78.896751,
+                33.41247
+              ],
+              [
+                78.949722,
+                33.376495
+              ],
+              [
+                78.9682,
+                33.334505
+              ],
+              [
+                79.022403,
+                33.323504
+              ],
+              [
+                79.041497,
+                33.268479
+              ],
+              [
+                79.083997,
+                33.245459
+              ],
+              [
+                79.072294,
+                33.22844
+              ],
+              [
+                79.10925,
+                33.200401
+              ],
+              [
+                79.152366,
+                33.184375
+              ],
+              [
+                79.162221,
+                33.165841
+              ],
+              [
+                79.139431,
+                33.117735
+              ],
+              [
+                79.162837,
+                33.01191
+              ],
+              [
+                79.204721,
+                32.964724
+              ],
+              [
+                79.255844,
+                32.942628
+              ],
+              [
+                79.227511,
+                32.89038
+              ],
+              [
+                79.237982,
+                32.846145
+              ],
+              [
+                79.225047,
+                32.784281
+              ],
+              [
+                79.275554,
+                32.778746
+              ],
+              [
+                79.301423,
+                32.728919
+              ],
+              [
+                79.27309,
+                32.678056
+              ],
+              [
+                79.299575,
+                32.637244
+              ],
+              [
+                79.308199,
+                32.596918
+              ],
+              [
+                79.272474,
+                32.561113
+              ],
+              [
+                79.252148,
+                32.516715
+              ],
+              [
+                79.190554,
+                32.511669
+              ],
+              [
+                79.180083,
+                32.492994
+              ],
+              [
+                79.135736,
+                32.472295
+              ],
+              [
+                79.124649,
+                32.416235
+              ],
+              [
+                79.103091,
+                32.369744
+              ],
+              [
+                79.067982,
+                32.380863
+              ],
+              [
+                79.005772,
+                32.375304
+              ],
+              [
+                78.970664,
+                32.331826
+              ],
+              [
+                78.904142,
+                32.374798
+              ],
+              [
+                78.87273,
+                32.40512
+              ],
+              [
+                78.81052,
+                32.436441
+              ],
+              [
+                78.782186,
+                32.480373
+              ],
+              [
+                78.760629,
+                32.563635
+              ],
+              [
+                78.781571,
+                32.608009
+              ],
+              [
+                78.74215,
+                32.654881
+              ],
+              [
+                78.741534,
+                32.703743
+              ],
+              [
+                78.6861,
+                32.680071
+              ],
+              [
+                78.675013,
+                32.658408
+              ],
+              [
+                78.628202,
+                32.630188
+              ],
+              [
+                78.588782,
+                32.637748
+              ],
+              [
+                78.577695,
+                32.615067
+              ],
+              [
+                78.518564,
+                32.605993
+              ],
+              [
+                78.500086,
+                32.580782
+              ],
+              [
+                78.424942,
+                32.565652
+              ],
+              [
+                78.395377,
+                32.530339
+              ],
+              [
+                78.426174,
+                32.502584
+              ],
+              [
+                78.472985,
+                32.435431
+              ],
+              [
+                78.458818,
+                32.379853
+              ],
+              [
+                78.483456,
+                32.357106
+              ],
+              [
+                78.480992,
+                32.329297
+              ],
+              [
+                78.508709,
+                32.297939
+              ],
+              [
+                78.475449,
+                32.236708
+              ],
+              [
+                78.430485,
+                32.212407
+              ],
+              [
+                78.429869,
+                32.194683
+              ],
+              [
+                78.469905,
+                32.127808
+              ],
+              [
+                78.509941,
+                32.147065
+              ],
+              [
+                78.527188,
+                32.11463
+              ],
+              [
+                78.609107,
+                32.052768
+              ],
+              [
+                78.60726,
+                32.023851
+              ],
+              [
+                78.705194,
+                31.988835
+              ],
+              [
+                78.762476,
+                31.947203
+              ],
+              [
+                78.768636,
+                31.92638
+              ],
+              [
+                78.739687,
+                31.885228
+              ],
+              [
+                78.665158,
+                31.851684
+              ],
+              [
+                78.654687,
+                31.819144
+              ],
+              [
+                78.706426,
+                31.778453
+              ],
+              [
+                78.763092,
+                31.668499
+              ],
+              [
+                78.798817,
+                31.675629
+              ],
+              [
+                78.806824,
+                31.64099
+              ],
+              [
+                78.845628,
+                31.609905
+              ],
+              [
+                78.833925,
+                31.584927
+              ],
+              [
+                78.779723,
+                31.545154
+              ],
+              [
+                78.740303,
+                31.532912
+              ],
+              [
+                78.729832,
+                31.478316
+              ],
+              [
+                78.755701,
+                31.478316
+              ],
+              [
+                78.792041,
+                31.435944
+              ],
+              [
+                78.760013,
+                31.392531
+              ],
+              [
+                78.755085,
+                31.355742
+              ],
+              [
+                78.795121,
+                31.301043
+              ],
+              [
+                78.859179,
+                31.289281
+              ],
+              [
+                78.865338,
+                31.312804
+              ],
+              [
+                78.884432,
+                31.277006
+              ],
+              [
+                78.923852,
+                31.246824
+              ],
+              [
+                78.930628,
+                31.220726
+              ],
+              [
+                78.997765,
+                31.158779
+              ],
+              [
+                78.97436,
+                31.115751
+              ],
+              [
+                79.010084,
+                31.043994
+              ],
+              [
+                79.059359,
+                31.028097
+              ],
+              [
+                79.096931,
+                30.992192
+              ],
+              [
+                79.181931,
+                31.015788
+              ],
+              [
+                79.205953,
+                31.0004
+              ],
+              [
+                79.227511,
+                30.949088
+              ],
+              [
+                79.33222,
+                30.969103
+              ],
+              [
+                79.316206,
+                31.01784
+              ],
+              [
+                79.35809,
+                31.031174
+              ],
+              [
+                79.404901,
+                31.071678
+              ],
+              [
+                79.424611,
+                31.061425
+              ],
+              [
+                79.427075,
+                31.018353
+              ],
+              [
+                79.505915,
+                31.027584
+              ],
+              [
+                79.550879,
+                30.957813
+              ],
+              [
+                79.59769,
+                30.925989
+              ],
+              [
+                79.660516,
+                30.956787
+              ],
+              [
+                79.668523,
+                30.980392
+              ],
+              [
+                79.729501,
+                30.941389
+              ],
+              [
+                79.75845,
+                30.936769
+              ],
+              [
+                79.835443,
+                30.851006
+              ],
+              [
+                79.890877,
+                30.855116
+              ],
+              [
+                79.913051,
+                30.833022
+              ],
+              [
+                79.900732,
+                30.7991
+              ],
+              [
+                79.961094,
+                30.771337
+              ],
+              [
+                79.955551,
+                30.738422
+              ],
+              [
+                79.970333,
+                30.685941
+              ],
+              [
+                80.014065,
+                30.661748
+              ],
+              [
+                80.04363,
+                30.603559
+              ],
+              [
+                80.143412,
+                30.55822
+              ],
+              [
+                80.214245,
+                30.586044
+              ],
+              [
+                80.261673,
+                30.566465
+              ],
+              [
+                80.322035,
+                30.564403
+              ],
+              [
+                80.357759,
+                30.520592
+              ],
+              [
+                80.43044,
+                30.515952
+              ],
+              [
+                80.446454,
+                30.495327
+              ],
+              [
+                80.504969,
+                30.483466
+              ],
+              [
+                80.549316,
+                30.448905
+              ],
+              [
+                80.585041,
+                30.463866
+              ],
+              [
+                80.633084,
+                30.458707
+              ],
+              [
+                80.692214,
+                30.416913
+              ],
+              [
+                80.719316,
+                30.414848
+              ],
+              [
+                80.81725,
+                30.321389
+              ],
+              [
+                80.910873,
+                30.30279
+              ],
+              [
+                80.933662,
+                30.266614
+              ],
+              [
+                80.996488,
+                30.267648
+              ],
+              [
+                81.034677,
+                30.246971
+              ],
+              [
+                81.038372,
+                30.205086
+              ],
+              [
+                81.082104,
+                30.151281
+              ],
+              [
+                81.085799,
+                30.100554
+              ],
+              [
+                81.110437,
+                30.085538
+              ],
+              [
+                81.09627,
+                30.052909
+              ],
+              [
+                81.131995,
+                30.016124
+              ],
+              [
+                81.225618,
+                30.005759
+              ],
+              [
+                81.256415,
+                30.011978
+              ],
+              [
+                81.247792,
+                30.032705
+              ],
+              [
+                81.2829,
+                30.061197
+              ],
+              [
+                81.293371,
+                30.094859
+              ],
+              [
+                81.269349,
+                30.153351
+              ],
+              [
+                81.335871,
+                30.149729
+              ],
+              [
+                81.393769,
+                30.199396
+              ],
+              [
+                81.397465,
+                30.240767
+              ],
+              [
+                81.419023,
+                30.270232
+              ],
+              [
+                81.406088,
+                30.291938
+              ],
+              [
+                81.427646,
+                30.305373
+              ],
+              [
+                81.399929,
+                30.319323
+              ],
+              [
+                81.406088,
+                30.369421
+              ],
+              [
+                81.432573,
+                30.379231
+              ],
+              [
+                81.406704,
+                30.40401
+              ],
+              [
+                81.418407,
+                30.420525
+              ],
+              [
+                81.454131,
+                30.412268
+              ],
+              [
+                81.494783,
+                30.381296
+              ],
+              [
+                81.555761,
+                30.369421
+              ],
+              [
+                81.566232,
+                30.428782
+              ],
+              [
+                81.613044,
+                30.412784
+              ],
+              [
+                81.63029,
+                30.446842
+              ],
+              [
+                81.723913,
+                30.407623
+              ],
+              [
+                81.759021,
+                30.385426
+              ],
+              [
+                81.872354,
+                30.373035
+              ],
+              [
+                81.939491,
+                30.344633
+              ],
+              [
+                81.954274,
+                30.355995
+              ],
+              [
+                81.99123,
+                30.322939
+              ],
+              [
+                82.022027,
+                30.339468
+              ],
+              [
+                82.060215,
+                30.332237
+              ],
+              [
+                82.104563,
+                30.346182
+              ],
+              [
+                82.132896,
+                30.30434
+              ],
+              [
+                82.11873,
+                30.279019
+              ],
+              [
+                82.114418,
+                30.226806
+              ],
+              [
+                82.142135,
+                30.200948
+              ],
+              [
+                82.188947,
+                30.18543
+              ],
+              [
+                82.207425,
+                30.143519
+              ],
+              [
+                82.183403,
+                30.12178
+              ],
+              [
+                82.17786,
+                30.06793
+              ],
+              [
+                82.246845,
+                30.071555
+              ],
+              [
+                82.311519,
+                30.035813
+              ],
+              [
+                82.333693,
+                30.045138
+              ],
+              [
+                82.368185,
+                30.014051
+              ],
+              [
+                82.412533,
+                30.011978
+              ],
+              [
+                82.431011,
+                29.989692
+              ],
+              [
+                82.474743,
+                29.973622
+              ],
+              [
+                82.498148,
+                29.947698
+              ],
+              [
+                82.560974,
+                29.955476
+              ],
+              [
+                82.609017,
+                29.886489
+              ],
+              [
+                82.64351,
+                29.868846
+              ],
+              [
+                82.6238,
+                29.834588
+              ],
+              [
+                82.703872,
+                29.847566
+              ],
+              [
+                82.737749,
+                29.80655
+              ],
+              [
+                82.691553,
+                29.766037
+              ],
+              [
+                82.757459,
+                29.761881
+              ],
+              [
+                82.774089,
+                29.726548
+              ],
+              [
+                82.816589,
+                29.717192
+              ],
+              [
+                82.830756,
+                29.687562
+              ],
+              [
+                82.885574,
+                29.689122
+              ],
+              [
+                82.9484,
+                29.704718
+              ],
+              [
+                82.966878,
+                29.658963
+              ],
+              [
+                83.011226,
+                29.667804
+              ],
+              [
+                83.088834,
+                29.604863
+              ],
+              [
+                83.12887,
+                29.623593
+              ],
+              [
+                83.159667,
+                29.61735
+              ],
+              [
+                83.164595,
+                29.595496
+              ],
+              [
+                83.217565,
+                29.60018
+              ],
+              [
+                83.266841,
+                29.571035
+              ],
+              [
+                83.27608,
+                29.505951
+              ],
+              [
+                83.325355,
+                29.502826
+              ],
+              [
+                83.383253,
+                29.42206
+              ],
+              [
+                83.415898,
+                29.420496
+              ],
+              [
+                83.423289,
+                29.361053
+              ],
+              [
+                83.450391,
+                29.332883
+              ],
+              [
+                83.463941,
+                29.285916
+              ],
+              [
+                83.492274,
+                29.280174
+              ],
+              [
+                83.548941,
+                29.201322
+              ],
+              [
+                83.57789,
+                29.203934
+              ],
+              [
+                83.596368,
+                29.174153
+              ],
+              [
+                83.656114,
+                29.16736
+              ],
+              [
+                83.667201,
+                29.200277
+              ],
+              [
+                83.727563,
+                29.244672
+              ],
+              [
+                83.800244,
+                29.249372
+              ],
+              [
+                83.82057,
+                29.294267
+              ],
+              [
+                83.851367,
+                29.294789
+              ],
+              [
+                83.911729,
+                29.323491
+              ],
+              [
+                83.949301,
+                29.312533
+              ],
+              [
+                83.986874,
+                29.325057
+              ],
+              [
+                84.002272,
+                29.291658
+              ],
+              [
+                84.052163,
+                29.296877
+              ],
+              [
+                84.116837,
+                29.286438
+              ],
+              [
+                84.130388,
+                29.239972
+              ],
+              [
+                84.203068,
+                29.239972
+              ],
+              [
+                84.197525,
+                29.210202
+              ],
+              [
+                84.17104,
+                29.19453
+              ],
+              [
+                84.176583,
+                29.133909
+              ],
+              [
+                84.20738,
+                29.118749
+              ],
+              [
+                84.192597,
+                29.084236
+              ],
+              [
+                84.194445,
+                29.045004
+              ],
+              [
+                84.224626,
+                29.049189
+              ],
+              [
+                84.248648,
+                29.030353
+              ],
+              [
+                84.228322,
+                28.949738
+              ],
+              [
+                84.234481,
+                28.889497
+              ],
+              [
+                84.268358,
+                28.895261
+              ],
+              [
+                84.330568,
+                28.859101
+              ],
+              [
+                84.340423,
+                28.866963
+              ],
+              [
+                84.408176,
+                28.85386
+              ],
+              [
+                84.404481,
+                28.828173
+              ],
+              [
+                84.434046,
+                28.823978
+              ],
+              [
+                84.445133,
+                28.764189
+              ],
+              [
+                84.483321,
+                28.735331
+              ],
+              [
+                84.557233,
+                28.74635
+              ],
+              [
+                84.620059,
+                28.732182
+              ],
+              [
+                84.650856,
+                28.714338
+              ],
+              [
+                84.669334,
+                28.680742
+              ],
+              [
+                84.699515,
+                28.671816
+              ],
+              [
+                84.698284,
+                28.633478
+              ],
+              [
+                84.773428,
+                28.610363
+              ],
+              [
+                84.857196,
+                28.567798
+              ],
+              [
+                84.896616,
+                28.587244
+              ],
+              [
+                84.981616,
+                28.586193
+              ],
+              [
+                84.995782,
+                28.611414
+              ],
+              [
+                85.05676,
+                28.674441
+              ],
+              [
+                85.126361,
+                28.676016
+              ],
+              [
+                85.155926,
+                28.643983
+              ],
+              [
+                85.195963,
+                28.624022
+              ],
+              [
+                85.18426,
+                28.587244
+              ],
+              [
+                85.189803,
+                28.544669
+              ],
+              [
+                85.160238,
+                28.49261
+              ],
+              [
+                85.108499,
+                28.461047
+              ],
+              [
+                85.129441,
+                28.377885
+              ],
+              [
+                85.113427,
+                28.344708
+              ],
+              [
+                85.179948,
+                28.324164
+              ],
+              [
+                85.209513,
+                28.338914
+              ],
+              [
+                85.272339,
+                28.282538
+              ],
+              [
+                85.349947,
+                28.298347
+              ],
+              [
+                85.379512,
+                28.274105
+              ],
+              [
+                85.415853,
+                28.321003
+              ],
+              [
+                85.458969,
+                28.332593
+              ],
+              [
+                85.520563,
+                28.326798
+              ],
+              [
+                85.602483,
+                28.295712
+              ],
+              [
+                85.601251,
+                28.254075
+              ],
+              [
+                85.650526,
+                28.283592
+              ],
+              [
+                85.682555,
+                28.375779
+              ],
+              [
+                85.720743,
+                28.372093
+              ],
+              [
+                85.753388,
+                28.227714
+              ],
+              [
+                85.791576,
+                28.195544
+              ],
+              [
+                85.854402,
+                28.172334
+              ],
+              [
+                85.871648,
+                28.124843
+              ],
+              [
+                85.898749,
+                28.101617
+              ],
+              [
+                85.901213,
+                28.053566
+              ],
+              [
+                85.980053,
+                27.984357
+              ],
+              [
+                85.949256,
+                27.937311
+              ],
+              [
+                86.002227,
+                27.90717
+              ],
+              [
+                86.053966,
+                27.900823
+              ],
+              [
+                86.125415,
+                27.923035
+              ],
+              [
+                86.082915,
+                28.018175
+              ],
+              [
+                86.086611,
+                28.090002
+              ],
+              [
+                86.128495,
+                28.086835
+              ],
+              [
+                86.140198,
+                28.114814
+              ],
+              [
+                86.19132,
+                28.167058
+              ],
+              [
+                86.223965,
+                28.092642
+              ],
+              [
+                86.206103,
+                28.084195
+              ],
+              [
+                86.231972,
+                27.974315
+              ],
+              [
+                86.27324,
+                27.976958
+              ],
+              [
+                86.308965,
+                27.950528
+              ],
+              [
+                86.393349,
+                27.926736
+              ],
+              [
+                86.414906,
+                27.904526
+              ],
+              [
+                86.450015,
+                27.908757
+              ],
+              [
+                86.475884,
+                27.944713
+              ],
+              [
+                86.514689,
+                27.954757
+              ],
+              [
+                86.513457,
+                27.996511
+              ],
+              [
+                86.537478,
+                28.044587
+              ],
+              [
+                86.55842,
+                28.047757
+              ],
+              [
+                86.568891,
+                28.103201
+              ],
+              [
+                86.60092,
+                28.097922
+              ],
+              [
+                86.611391,
+                28.069938
+              ],
+              [
+                86.647732,
+                28.06941
+              ],
+              [
+                86.662514,
+                28.092114
+              ],
+              [
+                86.700086,
+                28.101617
+              ],
+              [
+                86.74813,
+                28.089474
+              ],
+              [
+                86.768456,
+                28.06941
+              ],
+              [
+                86.756753,
+                28.032967
+              ],
+              [
+                86.827586,
+                28.012363
+              ],
+              [
+                86.864542,
+                28.022401
+              ],
+              [
+                86.885484,
+                27.995983
+              ],
+              [
+                86.926752,
+                27.985942
+              ],
+              [
+                86.935375,
+                27.955286
+              ],
+              [
+                87.035157,
+                27.946299
+              ],
+              [
+                87.080737,
+                27.910872
+              ],
+              [
+                87.118309,
+                27.840512
+              ],
+              [
+                87.173744,
+                27.818284
+              ],
+              [
+                87.227946,
+                27.812991
+              ],
+              [
+                87.249504,
+                27.839454
+              ],
+              [
+                87.280917,
+                27.845275
+              ],
+              [
+                87.317258,
+                27.826753
+              ],
+              [
+                87.364069,
+                27.824106
+              ],
+              [
+                87.421967,
+                27.856916
+              ],
+              [
+                87.418272,
+                27.825694
+              ],
+              [
+                87.45954,
+                27.820931
+              ],
+              [
+                87.58088,
+                27.859562
+              ],
+              [
+                87.598126,
+                27.814579
+              ],
+              [
+                87.670191,
+                27.832045
+              ],
+              [
+                87.668343,
+                27.809815
+              ],
+              [
+                87.727473,
+                27.802933
+              ],
+              [
+                87.77798,
+                27.860091
+              ],
+              [
+                87.782292,
+                27.890774
+              ],
+              [
+                87.826639,
+                27.927794
+              ],
+              [
+                87.930733,
+                27.909285
+              ],
+              [
+                87.982472,
+                27.884426
+              ],
+              [
+                88.037291,
+                27.901881
+              ],
+              [
+                88.090877,
+                27.885484
+              ],
+              [
+                88.111819,
+                27.864852
+              ],
+              [
+                88.137689,
+                27.878607
+              ],
+              [
+                88.120442,
+                27.915103
+              ],
+              [
+                88.156783,
+                27.957929
+              ],
+              [
+                88.203594,
+                27.943127
+              ],
+              [
+                88.242398,
+                27.967444
+              ],
+              [
+                88.254101,
+                27.939426
+              ],
+              [
+                88.357579,
+                27.986471
+              ],
+              [
+                88.401311,
+                27.976958
+              ],
+              [
+                88.43334,
+                28.002852
+              ],
+              [
+                88.469064,
+                28.009721
+              ],
+              [
+                88.498013,
+                28.04089
+              ],
+              [
+                88.554064,
+                28.027684
+              ],
+              [
+                88.565151,
+                28.083139
+              ],
+              [
+                88.620585,
+                28.091586
+              ],
+              [
+                88.645223,
+                28.111119
+              ],
+              [
+                88.67602,
+                28.068353
+              ],
+              [
+                88.764099,
+                28.068353
+              ],
+              [
+                88.812142,
+                28.018175
+              ],
+              [
+                88.842939,
+                28.006023
+              ],
+              [
+                88.846635,
+                27.921448
+              ],
+              [
+                88.864497,
+                27.921448
+              ],
+              [
+                88.888519,
+                27.846863
+              ],
+              [
+                88.863265,
+                27.811932
+              ],
+              [
+                88.870657,
+                27.743098
+              ],
+              [
+                88.850331,
+                27.710783
+              ],
+              [
+                88.852178,
+                27.671039
+              ],
+              [
+                88.816454,
+                27.641354
+              ],
+              [
+                88.813374,
+                27.606889
+              ],
+              [
+                88.770874,
+                27.563924
+              ],
+              [
+                88.797976,
+                27.521473
+              ],
+              [
+                88.783193,
+                27.467324
+              ],
+              [
+                88.809063,
+                27.405711
+              ],
+              [
+                88.838012,
+                27.37808
+              ],
+              [
+                88.867577,
+                27.3818
+              ],
+              [
+                88.901453,
+                27.327583
+              ],
+              [
+                88.920548,
+                27.325456
+              ],
+              [
+                88.911924,
+                27.272807
+              ],
+              [
+                88.942105,
+                27.261636
+              ],
+              [
+                88.984605,
+                27.208957
+              ],
+              [
+                89.067757,
+                27.240354
+              ],
+              [
+                89.077612,
+                27.287168
+              ],
+              [
+                89.152757,
+                27.319076
+              ],
+              [
+                89.182938,
+                27.373829
+              ],
+              [
+                89.132431,
+                27.441302
+              ],
+              [
+                89.095474,
+                27.471572
+              ],
+              [
+                89.109025,
+                27.537925
+              ],
+              [
+                89.163228,
+                27.574534
+              ],
+              [
+                89.128735,
+                27.611131
+              ],
+              [
+                89.131815,
+                27.633402
+              ],
+              [
+                89.184786,
+                27.673689
+              ],
+              [
+                89.238988,
+                27.796581
+              ],
+              [
+                89.295655,
+                27.84845
+              ],
+              [
+                89.375727,
+                27.875962
+              ],
+              [
+                89.44348,
+                27.968501
+              ],
+              [
+                89.461958,
+                28.03191
+              ],
+              [
+                89.511233,
+                28.086307
+              ],
+              [
+                89.541414,
+                28.088418
+              ],
+              [
+                89.605472,
+                28.161782
+              ],
+              [
+                89.720037,
+                28.170224
+              ],
+              [
+                89.779167,
+                28.197127
+              ],
+              [
+                89.789638,
+                28.240895
+              ],
+              [
+                89.869094,
+                28.221386
+              ],
+              [
+                89.901739,
+                28.18183
+              ],
+              [
+                89.976268,
+                28.189215
+              ],
+              [
+                90.017536,
+                28.162837
+              ],
+              [
+                90.03355,
+                28.136981
+              ],
+              [
+                90.07297,
+                28.155451
+              ],
+              [
+                90.103151,
+                28.141731
+              ],
+              [
+                90.124709,
+                28.190797
+              ],
+              [
+                90.166593,
+                28.187632
+              ],
+              [
+                90.189999,
+                28.161782
+              ],
+              [
+                90.231882,
+                28.144897
+              ],
+              [
+                90.297172,
+                28.153868
+              ],
+              [
+                90.367389,
+                28.088946
+              ],
+              [
+                90.384019,
+                28.06096
+              ],
+              [
+                90.43699,
+                28.063073
+              ],
+              [
+                90.47949,
+                28.044587
+              ],
+              [
+                90.513983,
+                28.062016
+              ],
+              [
+                90.569417,
+                28.044059
+              ],
+              [
+                90.591591,
+                28.021345
+              ],
+              [
+                90.701844,
+                28.076274
+              ],
+              [
+                90.741264,
+                28.053038
+              ],
+              [
+                90.802242,
+                28.040362
+              ],
+              [
+                90.806554,
+                28.015005
+              ],
+              [
+                90.853365,
+                27.969029
+              ],
+              [
+                90.896481,
+                27.946299
+              ],
+              [
+                90.96177,
+                27.9537
+              ],
+              [
+                90.976553,
+                27.935725
+              ],
+              [
+                90.96485,
+                27.900294
+              ],
+              [
+                91.025828,
+                27.857445
+              ],
+              [
+                91.113292,
+                27.846333
+              ],
+              [
+                91.155175,
+                27.894476
+              ],
+              [
+                91.147784,
+                27.927794
+              ],
+              [
+                91.162567,
+                27.968501
+              ],
+              [
+                91.216153,
+                27.989113
+              ],
+              [
+                91.251878,
+                27.970615
+              ],
+              [
+                91.309776,
+                28.057791
+              ],
+              [
+                91.464993,
+                28.002852
+              ],
+              [
+                91.490246,
+                27.971672
+              ],
+              [
+                91.486551,
+                27.937311
+              ],
+              [
+                91.552456,
+                27.90717
+              ],
+              [
+                91.611586,
+                27.891303
+              ],
+              [
+                91.618978,
+                27.856916
+              ],
+              [
+                91.561079,
+                27.855329
+              ],
+              [
+                91.544449,
+                27.820401
+              ],
+              [
+                91.610355,
+                27.819343
+              ],
+              [
+                91.642383,
+                27.7664
+              ],
+              [
+                91.622673,
+                27.692238
+              ],
+              [
+                91.570934,
+                27.650897
+              ],
+              [
+                91.562311,
+                27.627569
+              ],
+              [
+                91.582637,
+                27.598933
+              ],
+              [
+                91.564775,
+                27.58196
+              ],
+              [
+                91.585101,
+                27.540578
+              ],
+              [
+                91.626985,
+                27.509265
+              ],
+              [
+                91.663325,
+                27.507142
+              ],
+              [
+                91.71876,
+                27.467324
+              ],
+              [
+                91.753868,
+                27.462545
+              ],
+              [
+                91.839484,
+                27.489624
+              ],
+              [
+                91.946657,
+                27.464138
+              ],
+              [
+                92.010715,
+                27.474758
+              ],
+              [
+                92.021802,
+                27.444489
+              ],
+              [
+                92.064918,
+                27.391365
+              ],
+              [
+                92.125896,
+                27.273339
+              ],
+              [
+                92.091403,
+                27.264296
+              ],
+              [
+                92.071077,
+                27.237694
+              ],
+              [
+                92.061222,
+                27.190327
+              ],
+              [
+                92.032273,
+                27.167967
+              ],
+              [
+                92.02673,
+                27.108318
+              ],
+              [
+                92.043976,
+                27.052902
+              ],
+              [
+                92.076005,
+                27.041175
+              ],
+              [
+                92.124664,
+                26.960124
+              ],
+              [
+                92.109265,
+                26.854991
+              ],
+              [
+                92.197961,
+                26.86994
+              ],
+              [
+                92.28604,
+                26.892359
+              ],
+              [
+                92.404916,
+                26.9025
+              ],
+              [
+                92.496691,
+                26.921711
+              ],
+              [
+                92.549046,
+                26.941453
+              ],
+              [
+                92.64698,
+                26.952656
+              ],
+              [
+                92.682089,
+                26.947855
+              ],
+              [
+                92.802813,
+                26.895028
+              ],
+              [
+                92.909371,
+                26.914241
+              ],
+              [
+                93.050421,
+                26.883819
+              ],
+              [
+                93.111399,
+                26.880082
+              ],
+              [
+                93.232739,
+                26.906769
+              ],
+              [
+                93.56781,
+                26.938252
+              ],
+              [
+                93.625092,
+                26.955323
+              ],
+              [
+                93.747048,
+                27.015587
+              ],
+              [
+                93.817265,
+                27.025183
+              ],
+              [
+                93.841903,
+                27.045973
+              ],
+              [
+                93.849294,
+                27.168499
+              ],
+              [
+                93.970634,
+                27.30525
+              ],
+              [
+                94.056866,
+                27.375423
+              ],
+              [
+                94.147409,
+                27.458297
+              ],
+              [
+                94.220705,
+                27.536333
+              ],
+              [
+                94.277372,
+                27.58143
+              ],
+              [
+                94.353132,
+                27.578778
+              ],
+              [
+                94.399944,
+                27.589386
+              ],
+              [
+                94.443675,
+                27.585143
+              ],
+              [
+                94.478168,
+                27.602116
+              ],
+              [
+                94.524979,
+                27.596282
+              ],
+              [
+                94.660486,
+                27.650367
+              ],
+              [
+                94.722696,
+                27.683759
+              ],
+              [
+                94.78121,
+                27.699127
+              ],
+              [
+                94.836645,
+                27.728796
+              ],
+              [
+                94.88592,
+                27.743098
+              ],
+              [
+                94.947514,
+                27.792345
+              ],
+              [
+                95.015267,
+                27.82887
+              ],
+              [
+                95.067006,
+                27.840512
+              ],
+              [
+                95.28628,
+                27.939955
+              ],
+              [
+                95.32878,
+                28.017646
+              ],
+              [
+                95.352802,
+                28.04089
+              ],
+              [
+                95.371896,
+                28.110063
+              ],
+              [
+                95.39715,
+                28.142259
+              ],
+              [
+                95.437802,
+                28.161782
+              ],
+              [
+                95.528345,
+                28.182885
+              ],
+              [
+                95.674322,
+                28.254075
+              ],
+              [
+                95.740228,
+                28.275159
+              ],
+              [
+                95.787655,
+                28.270416
+              ],
+              [
+                95.832003,
+                28.295186
+              ],
+              [
+                95.874502,
+                28.29782
+              ],
+              [
+                95.899756,
+                28.278322
+              ],
+              [
+                95.907763,
+                28.241422
+              ],
+              [
+                95.936096,
+                28.240368
+              ],
+              [
+                95.989067,
+                28.198181
+              ],
+              [
+                96.074683,
+                28.193434
+              ],
+              [
+                96.098088,
+                28.212421
+              ],
+              [
+                96.194175,
+                28.212949
+              ],
+              [
+                96.275479,
+                28.228241
+              ],
+              [
+                96.298269,
+                28.140148
+              ],
+              [
+                96.367254,
+                28.118509
+              ],
+              [
+                96.398667,
+                28.118509
+              ],
+              [
+                96.395587,
+                28.143842
+              ],
+              [
+                96.426384,
+                28.161782
+              ],
+              [
+                96.46334,
+                28.143314
+              ],
+              [
+                96.499681,
+                28.067297
+              ],
+              [
+                96.538485,
+                28.075218
+              ],
+              [
+                96.623485,
+                28.024514
+              ],
+              [
+                96.635188,
+                27.994926
+              ],
+              [
+                96.690622,
+                27.948942
+              ],
+              [
+                96.711564,
+                27.9574
+              ],
+              [
+                96.784245,
+                27.931495
+              ],
+              [
+                96.810114,
+                27.890245
+              ],
+              [
+                96.849534,
+                27.874375
+              ],
+              [
+                96.908049,
+                27.884426
+              ],
+              [
+                96.972722,
+                27.861149
+              ],
+              [
+                97.008447,
+                27.807698
+              ],
+              [
+                97.049099,
+                27.81405
+              ],
+              [
+                97.062649,
+                27.742568
+              ],
+              [
+                97.097758,
+                27.740979
+              ],
+              [
+                97.103301,
+                27.780697
+              ],
+              [
+                97.167975,
+                27.811932
+              ],
+              [
+                97.253591,
+                27.891832
+              ],
+              [
+                97.303482,
+                27.913516
+              ],
+              [
+                97.324424,
+                27.880723
+              ],
+              [
+                97.386634,
+                27.882839
+              ],
+              [
+                97.372467,
+                27.907699
+              ],
+              [
+                97.379242,
+                27.970087
+              ],
+              [
+                97.413119,
+                28.01342
+              ],
+              [
+                97.378626,
+                28.031382
+              ],
+              [
+                97.375547,
+                28.062545
+              ],
+              [
+                97.320728,
+                28.054095
+              ],
+              [
+                97.305945,
+                28.071522
+              ],
+              [
+                97.340438,
+                28.104785
+              ],
+              [
+                97.326887,
+                28.132759
+              ],
+              [
+                97.352757,
+                28.149646
+              ],
+              [
+                97.362612,
+                28.199236
+              ],
+              [
+                97.349677,
+                28.235623
+              ],
+              [
+                97.398336,
+                28.238786
+              ],
+              [
+                97.402032,
+                28.279903
+              ],
+              [
+                97.422358,
+                28.297293
+              ],
+              [
+                97.461162,
+                28.26778
+              ],
+              [
+                97.469169,
+                28.30309
+              ],
+              [
+                97.518445,
+                28.327852
+              ],
+              [
+                97.488879,
+                28.347341
+              ],
+              [
+                97.485184,
+                28.38631
+              ],
+              [
+                97.499966,
+                28.428948
+              ],
+              [
+                97.521524,
+                28.444736
+              ],
+              [
+                97.507974,
+                28.46473
+              ],
+              [
+                97.521524,
+                28.495766
+              ],
+              [
+                97.569567,
+                28.541515
+              ],
+              [
+                97.60406,
+                28.515225
+              ],
+              [
+                97.634857,
+                28.532051
+              ],
+              [
+                97.68598,
+                28.519958
+              ],
+              [
+                97.737103,
+                28.465782
+              ],
+              [
+                97.738335,
+                28.396313
+              ],
+              [
+                97.769748,
+                28.3742
+              ],
+              [
+                97.801161,
+                28.326798
+              ],
+              [
+                97.842429,
+                28.326798
+              ],
+              [
+                97.871378,
+                28.361561
+              ],
+              [
+                97.907718,
+                28.363141
+              ],
+              [
+                98.020435,
+                28.253548
+              ],
+              [
+                98.008116,
+                28.214003
+              ],
+              [
+                98.03337,
+                28.187105
+              ],
+              [
+                98.056775,
+                28.202401
+              ],
+              [
+                98.090036,
+                28.195544
+              ],
+              [
+                98.097427,
+                28.166531
+              ],
+              [
+                98.139311,
+                28.142259
+              ],
+              [
+                98.17442,
+                28.163365
+              ],
+              [
+                98.169492,
+                28.206093
+              ],
+              [
+                98.21692,
+                28.212949
+              ],
+              [
+                98.266811,
+                28.242477
+              ],
+              [
+                98.231702,
+                28.314681
+              ],
+              [
+                98.207681,
+                28.330486
+              ],
+              [
+                98.208913,
+                28.358401
+              ],
+              [
+                98.301303,
+                28.384204
+              ],
+              [
+                98.317934,
+                28.324691
+              ],
+              [
+                98.353042,
+                28.293078
+              ],
+              [
+                98.37768,
+                28.246167
+              ],
+              [
+                98.370289,
+                28.18394
+              ],
+              [
+                98.389999,
+                28.16442
+              ],
+              [
+                98.389383,
+                28.114814
+              ],
+              [
+                98.428803,
+                28.104785
+              ],
+              [
+                98.464527,
+                28.151229
+              ],
+              [
+                98.494092,
+                28.141203
+              ],
+              [
+                98.559382,
+                28.182885
+              ],
+              [
+                98.625903,
+                28.165475
+              ],
+              [
+                98.649925,
+                28.200291
+              ],
+              [
+                98.712135,
+                28.229296
+              ],
+              [
+                98.710287,
+                28.288862
+              ],
+              [
+                98.746628,
+                28.321003
+              ],
+              [
+                98.740468,
+                28.348395
+              ],
+              [
+                98.693041,
+                28.43158
+              ],
+              [
+                98.673947,
+                28.478934
+              ],
+              [
+                98.625903,
+                28.489455
+              ],
+              [
+                98.619128,
+                28.50944
+              ],
+              [
+                98.637606,
+                28.552029
+              ],
+              [
+                98.594491,
+                28.667615
+              ],
+              [
+                98.666555,
+                28.712239
+              ],
+              [
+                98.683802,
+                28.740054
+              ],
+              [
+                98.652389,
+                28.817162
+              ],
+              [
+                98.668403,
+                28.843376
+              ],
+              [
+                98.643766,
+                28.895261
+              ],
+              [
+                98.6567,
+                28.910454
+              ],
+              [
+                98.624056,
+                28.95864
+              ],
+              [
+                98.655469,
+                28.976966
+              ],
+              [
+                98.70228,
+                28.9644
+              ],
+              [
+                98.757714,
+                29.004186
+              ],
+              [
+                98.786048,
+                28.998952
+              ],
+              [
+                98.821772,
+                28.920931
+              ],
+              [
+                98.827932,
+                28.821356
+              ],
+              [
+                98.852569,
+                28.798283
+              ],
+              [
+                98.912931,
+                28.800906
+              ],
+              [
+                98.922786,
+                28.823978
+              ],
+              [
+                98.972677,
+                28.832367
+              ],
+              [
+                98.973909,
+                28.864867
+              ],
+              [
+                98.917859,
+                28.886877
+              ],
+              [
+                98.925866,
+                28.978536
+              ],
+              [
+                99.013329,
+                29.036632
+              ],
+              [
+                98.991771,
+                29.105677
+              ],
+              [
+                98.967134,
+                29.128159
+              ],
+              [
+                98.960974,
+                29.165792
+              ],
+              [
+                98.9813,
+                29.204978
+              ],
+              [
+                99.024416,
+                29.188783
+              ],
+              [
+                99.037351,
+                29.20759
+              ],
+              [
+                99.113727,
+                29.221171
+              ],
+              [
+                99.114343,
+                29.243628
+              ],
+              [
+                99.075539,
+                29.316186
+              ],
+              [
+                99.058909,
+                29.417368
+              ],
+              [
+                99.066916,
+                29.421018
+              ],
+              [
+                99.044742,
+                29.520013
+              ],
+              [
+                99.052133,
+                29.563748
+              ],
+              [
+                99.014561,
+                29.607464
+              ],
+              [
+                98.992387,
+                29.677163
+              ],
+              [
+                99.018873,
+                29.792009
+              ],
+              [
+                99.0238,
+                29.846009
+              ],
+              [
+                99.068148,
+                29.931621
+              ],
+              [
+                99.055213,
+                29.958587
+              ],
+              [
+                99.036735,
+                30.053945
+              ],
+              [
+                99.044742,
+                30.079842
+              ],
+              [
+                98.989308,
+                30.151799
+              ],
+              [
+                98.9813,
+                30.182843
+              ],
+              [
+                98.993003,
+                30.215429
+              ],
+              [
+                98.970829,
+                30.260928
+              ],
+              [
+                98.986844,
+                30.280569
+              ],
+              [
+                98.967134,
+                30.33482
+              ],
+              [
+                98.965286,
+                30.449937
+              ],
+              [
+                98.932025,
+                30.521623
+              ],
+              [
+                98.926482,
+                30.569556
+              ],
+              [
+                98.939417,
+                30.598923
+              ],
+              [
+                98.92217,
+                30.609225
+              ],
+              [
+                98.907388,
+                30.698292
+              ],
+              [
+                98.963438,
+                30.728134
+              ],
+              [
+                98.957895,
+                30.765166
+              ],
+              [
+                98.904924,
+                30.782649
+              ],
+              [
+                98.850105,
+                30.849465
+              ],
+              [
+                98.797135,
+                30.87926
+              ],
+              [
+                98.774345,
+                30.908019
+              ],
+              [
+                98.797135,
+                30.948575
+              ],
+              [
+                98.806374,
+                30.995783
+              ],
+              [
+                98.774961,
+                31.031174
+              ],
+              [
+                98.736772,
+                31.049121
+              ],
+              [
+                98.712135,
+                31.082954
+              ],
+              [
+                98.710287,
+                31.1178
+              ],
+              [
+                98.675179,
+                31.15417
+              ],
+              [
+                98.602498,
+                31.192062
+              ],
+              [
+                98.62344,
+                31.221238
+              ],
+              [
+                98.60373,
+                31.257568
+              ],
+              [
+                98.616048,
+                31.3036
+              ],
+              [
+                98.643766,
+                31.338876
+              ],
+              [
+                98.691809,
+                31.333253
+              ],
+              [
+                98.773113,
+                31.249382
+              ],
+              [
+                98.805758,
+                31.279052
+              ],
+              [
+                98.810685,
+                31.306668
+              ],
+              [
+                98.887062,
+                31.37465
+              ],
+              [
+                98.84333,
+                31.416028
+              ],
+              [
+                98.844562,
+                31.429817
+              ],
+              [
+                98.714599,
+                31.508935
+              ],
+              [
+                98.696736,
+                31.538523
+              ],
+              [
+                98.651157,
+                31.57881
+              ],
+              [
+                98.619128,
+                31.591555
+              ],
+              [
+                98.553839,
+                31.660349
+              ],
+              [
+                98.545831,
+                31.717383
+              ],
+              [
+                98.516882,
+                31.717383
+              ],
+              [
+                98.508875,
+                31.751995
+              ],
+              [
+                98.461448,
+                31.800327
+              ],
+              [
+                98.414636,
+                31.832365
+              ],
+              [
+                98.426339,
+                31.856767
+              ],
+              [
+                98.399238,
+                31.895899
+              ],
+              [
+                98.432498,
+                31.922825
+              ],
+              [
+                98.434962,
+                32.007613
+              ],
+              [
+                98.402933,
+                32.026896
+              ],
+              [
+                98.404781,
+                32.045159
+              ],
+              [
+                98.357354,
+                32.087253
+              ],
+              [
+                98.303151,
+                32.121726
+              ],
+              [
+                98.260035,
+                32.208862
+              ],
+              [
+                98.218768,
+                32.234683
+              ],
+              [
+                98.23047,
+                32.262521
+              ],
+              [
+                98.208913,
+                32.318171
+              ],
+              [
+                98.218768,
+                32.342444
+              ],
+              [
+                98.125145,
+                32.401077
+              ],
+              [
+                98.107283,
+                32.391476
+              ],
+              [
+                98.079565,
+                32.415224
+              ],
+              [
+                97.940363,
+                32.482393
+              ],
+              [
+                97.880001,
+                32.486431
+              ],
+              [
+                97.863986,
+                32.499051
+              ],
+              [
+                97.80732,
+                32.50006
+              ],
+              [
+                97.795617,
+                32.521257
+              ],
+              [
+                97.730944,
+                32.527312
+              ],
+              [
+                97.684132,
+                32.530339
+              ],
+              [
+                97.670582,
+                32.51722
+              ],
+              [
+                97.540618,
+                32.536899
+              ],
+              [
+                97.50243,
+                32.530844
+              ],
+              [
+                97.463626,
+                32.55506
+              ],
+              [
+                97.448843,
+                32.586833
+              ],
+              [
+                97.411887,
+                32.575235
+              ],
+              [
+                97.374315,
+                32.546484
+              ],
+              [
+                97.3583,
+                32.563635
+              ],
+              [
+                97.332431,
+                32.542448
+              ],
+              [
+                97.334895,
+                32.514192
+              ],
+              [
+                97.388481,
+                32.501575
+              ],
+              [
+                97.341054,
+                32.440987
+              ],
+              [
+                97.387865,
+                32.427349
+              ],
+              [
+                97.424822,
+                32.322723
+              ],
+              [
+                97.415583,
+                32.296421
+              ],
+              [
+                97.371235,
+                32.273148
+              ],
+              [
+                97.32196,
+                32.303503
+              ],
+              [
+                97.299786,
+                32.294904
+              ],
+              [
+                97.264062,
+                32.182527
+              ],
+              [
+                97.271453,
+                32.139971
+              ],
+              [
+                97.313953,
+                32.130342
+              ],
+              [
+                97.293011,
+                32.096887
+              ],
+              [
+                97.308409,
+                32.076605
+              ],
+              [
+                97.258518,
+                32.072041
+              ],
+              [
+                97.219714,
+                32.109054
+              ],
+              [
+                97.201852,
+                32.090296
+              ],
+              [
+                97.233881,
+                32.063927
+              ],
+              [
+                97.214786,
+                32.042623
+              ],
+              [
+                97.188301,
+                32.055304
+              ],
+              [
+                97.169823,
+                32.032984
+              ],
+              [
+                97.127323,
+                32.044145
+              ],
+              [
+                97.028773,
+                32.04871
+              ],
+              [
+                97.006599,
+                32.067984
+              ],
+              [
+                96.935766,
+                32.048203
+              ],
+              [
+                96.965947,
+                32.008628
+              ],
+              [
+                96.941925,
+                31.986297
+              ],
+              [
+                96.894498,
+                32.013703
+              ],
+              [
+                96.863085,
+                31.996448
+              ],
+              [
+                96.868629,
+                31.964975
+              ],
+              [
+                96.824281,
+                32.007613
+              ],
+              [
+                96.722651,
+                32.013195
+              ],
+              [
+                96.742977,
+                32.001016
+              ],
+              [
+                96.753448,
+                31.944156
+              ],
+              [
+                96.776238,
+                31.935015
+              ],
+              [
+                96.81073,
+                31.894375
+              ],
+              [
+                96.794716,
+                31.869474
+              ],
+              [
+                96.760223,
+                31.860325
+              ],
+              [
+                96.765767,
+                31.819144
+              ],
+              [
+                96.799027,
+                31.792188
+              ],
+              [
+                96.840295,
+                31.720438
+              ],
+              [
+                96.790404,
+                31.698545
+              ],
+              [
+                96.778701,
+                31.675629
+              ],
+              [
+                96.722651,
+                31.686833
+              ],
+              [
+                96.691854,
+                31.722474
+              ],
+              [
+                96.661057,
+                31.705674
+              ],
+              [
+                96.615477,
+                31.737236
+              ],
+              [
+                96.56805,
+                31.711783
+              ],
+              [
+                96.519391,
+                31.74945
+              ],
+              [
+                96.468884,
+                31.769804
+              ],
+              [
+                96.435623,
+                31.796258
+              ],
+              [
+                96.407906,
+                31.845583
+              ],
+              [
+                96.389428,
+                31.919777
+              ],
+              [
+                96.288414,
+                31.919777
+              ],
+              [
+                96.253305,
+                31.929936
+              ],
+              [
+                96.220044,
+                31.905553
+              ],
+              [
+                96.188632,
+                31.904028
+              ],
+              [
+                96.214501,
+                31.876589
+              ],
+              [
+                96.202798,
+                31.841008
+              ],
+              [
+                96.183088,
+                31.835924
+              ],
+              [
+                96.178161,
+                31.775401
+              ],
+              [
+                96.231131,
+                31.749959
+              ],
+              [
+                96.222508,
+                31.733164
+              ],
+              [
+                96.252073,
+                31.697527
+              ],
+              [
+                96.245298,
+                31.657802
+              ],
+              [
+                96.221892,
+                31.647613
+              ],
+              [
+                96.207726,
+                31.598691
+              ],
+              [
+                96.156603,
+                31.602769
+              ],
+              [
+                96.148595,
+                31.686324
+              ],
+              [
+                96.135661,
+                31.70211
+              ],
+              [
+                96.064828,
+                31.720438
+              ],
+              [
+                95.989067,
+                31.78761
+              ],
+              [
+                95.983524,
+                31.816601
+              ],
+              [
+                95.89914,
+                31.81711
+              ],
+              [
+                95.846169,
+                31.736218
+              ],
+              [
+                95.853561,
+                31.714329
+              ],
+              [
+                95.823995,
+                31.68225
+              ],
+              [
+                95.779648,
+                31.748941
+              ],
+              [
+                95.634286,
+                31.782523
+              ],
+              [
+                95.580083,
+                31.76726
+              ],
+              [
+                95.546823,
+                31.73978
+              ],
+              [
+                95.511714,
+                31.750468
+              ],
+              [
+                95.480301,
+                31.795749
+              ],
+              [
+                95.456896,
+                31.801853
+              ],
+              [
+                95.406389,
+                31.896915
+              ],
+              [
+                95.408852,
+                31.918761
+              ],
+              [
+                95.3682,
+                31.92892
+              ],
+              [
+                95.360809,
+                31.95939
+              ],
+              [
+                95.395918,
+                32.001523
+              ],
+              [
+                95.454432,
+                32.007613
+              ],
+              [
+                95.421171,
+                32.033999
+              ],
+              [
+                95.454432,
+                32.061898
+              ],
+              [
+                95.440265,
+                32.157705
+              ],
+              [
+                95.406389,
+                32.182021
+              ],
+              [
+                95.367584,
+                32.178982
+              ],
+              [
+                95.366968,
+                32.151118
+              ],
+              [
+                95.31523,
+                32.148585
+              ],
+              [
+                95.270266,
+                32.194683
+              ],
+              [
+                95.270266,
+                32.194683
+              ],
+              [
+                95.239469,
+                32.287315
+              ],
+              [
+                95.241317,
+                32.3207
+              ],
+              [
+                95.214216,
+                32.321712
+              ],
+              [
+                95.20744,
+                32.297433
+              ],
+              [
+                95.10581,
+                32.258979
+              ],
+              [
+                95.079325,
+                32.279726
+              ],
+              [
+                95.096571,
+                32.322217
+              ],
+              [
+                95.193274,
+                32.332331
+              ],
+              [
+                95.261643,
+                32.348006
+              ],
+              [
+                95.228382,
+                32.363678
+              ],
+              [
+                95.218527,
+                32.397035
+              ],
+              [
+                95.153853,
+                32.386423
+              ],
+              [
+                95.081789,
+                32.384907
+              ],
+              [
+                95.075013,
+                32.376315
+              ],
+              [
+                95.075013,
+                32.376315
+              ],
+              [
+                95.057151,
+                32.395014
+              ],
+              [
+                94.988166,
+                32.422802
+              ],
+              [
+                94.944434,
+                32.404109
+              ],
+              [
+                94.912405,
+                32.41573
+              ],
+              [
+                94.889616,
+                32.472295
+              ],
+              [
+                94.852043,
+                32.463712
+              ],
+              [
+                94.80708,
+                32.486431
+              ],
+              [
+                94.78737,
+                32.522266
+              ],
+              [
+                94.762116,
+                32.526303
+              ],
+              [
+                94.737479,
+                32.587338
+              ],
+              [
+                94.638312,
+                32.645307
+              ],
+              [
+                94.614291,
+                32.673522
+              ],
+              [
+                94.591501,
+                32.640772
+              ],
+              [
+                94.522516,
+                32.595909
+              ],
+              [
+                94.459074,
+                32.599439
+              ],
+              [
+                94.463386,
+                32.572209
+              ],
+              [
+                94.435052,
+                32.562626
+              ],
+              [
+                94.395016,
+                32.594397
+              ],
+              [
+                94.371611,
+                32.524789
+              ],
+              [
+                94.350053,
+                32.533871
+              ],
+              [
+                94.294002,
+                32.519743
+              ],
+              [
+                94.292154,
+                32.502584
+              ],
+              [
+                94.250886,
+                32.51722
+              ],
+              [
+                94.196684,
+                32.51621
+              ],
+              [
+                94.176974,
+                32.454117
+              ],
+              [
+                94.137554,
+                32.433915
+              ],
+              [
+                94.091974,
+                32.463207
+              ],
+              [
+                94.049474,
+                32.469771
+              ],
+              [
+                94.03038,
+                32.448057
+              ],
+              [
+                93.978641,
+                32.459672
+              ],
+              [
+                93.960163,
+                32.484917
+              ],
+              [
+                93.90904,
+                32.463207
+              ],
+              [
+                93.861613,
+                32.466237
+              ],
+              [
+                93.851142,
+                32.50965
+              ],
+              [
+                93.820345,
+                32.549511
+              ],
+              [
+                93.75136,
+                32.56313
+              ],
+              [
+                93.721795,
+                32.578261
+              ],
+              [
+                93.651577,
+                32.571705
+              ],
+              [
+                93.618933,
+                32.522771
+              ],
+              [
+                93.516687,
+                32.47583
+              ],
+              [
+                93.501904,
+                32.503593
+              ],
+              [
+                93.476651,
+                32.504603
+              ],
+              [
+                93.4631,
+                32.556069
+              ],
+              [
+                93.411977,
+                32.558086
+              ],
+              [
+                93.385492,
+                32.525294
+              ],
+              [
+                93.33868,
+                32.5712
+              ],
+              [
+                93.308499,
+                32.580278
+              ],
+              [
+                93.300492,
+                32.619604
+              ],
+              [
+                93.260456,
+                32.62666
+              ],
+              [
+                93.239514,
+                32.662439
+              ],
+              [
+                93.210565,
+                32.655385
+              ],
+              [
+                93.176688,
+                32.6705
+              ],
+              [
+                93.159442,
+                32.644803
+              ],
+              [
+                93.087993,
+                32.63674
+              ],
+              [
+                93.069515,
+                32.626156
+              ],
+              [
+                93.023935,
+                32.703239
+              ],
+              [
+                93.019624,
+                32.737477
+              ],
+              [
+                93.00053,
+                32.741001
+              ],
+              [
+                92.964189,
+                32.714821
+              ],
+              [
+                92.933392,
+                32.719353
+              ],
+              [
+                92.866871,
+                32.698203
+              ],
+              [
+                92.822523,
+                32.729926
+              ],
+              [
+                92.789262,
+                32.719856
+              ],
+              [
+                92.756618,
+                32.743014
+              ],
+              [
+                92.686401,
+                32.76516
+              ],
+              [
+                92.667922,
+                32.73194
+              ],
+              [
+                92.634662,
+                32.720863
+              ],
+              [
+                92.574916,
+                32.741001
+              ],
+              [
+                92.56814,
+                32.73194
+              ],
+              [
+                92.484372,
+                32.745028
+              ],
+              [
+                92.459119,
+                32.76365
+              ],
+              [
+                92.411076,
+                32.748048
+              ],
+              [
+                92.355641,
+                32.764657
+              ],
+              [
+                92.343938,
+                32.738484
+              ],
+              [
+                92.310062,
+                32.751571
+              ],
+              [
+                92.255243,
+                32.720863
+              ],
+              [
+                92.198577,
+                32.754591
+              ],
+              [
+                92.211511,
+                32.788306
+              ],
+              [
+                92.193649,
+                32.801889
+              ],
+              [
+                92.227526,
+                32.821003
+              ],
+              [
+                92.205352,
+                32.866255
+              ],
+              [
+                92.145606,
+                32.885857
+              ],
+              [
+                92.101874,
+                32.860222
+              ],
+              [
+                92.038432,
+                32.860725
+              ],
+              [
+                92.018722,
+                32.829552
+              ],
+              [
+                91.955897,
+                32.8205
+              ],
+              [
+                91.896766,
+                32.907967
+              ],
+              [
+                91.857962,
+                32.90244
+              ],
+              [
+                91.839484,
+                32.948152
+              ],
+              [
+                91.799448,
+                32.942126
+              ],
+              [
+                91.752637,
+                32.969242
+              ],
+              [
+                91.685499,
+                32.989324
+              ],
+              [
+                91.664557,
+                33.012913
+              ],
+              [
+                91.583253,
+                33.0375
+              ],
+              [
+                91.55492,
+                33.060074
+              ],
+              [
+                91.535826,
+                33.10019
+              ],
+              [
+                91.49579,
+                33.109214
+              ],
+              [
+                91.436044,
+                33.066092
+              ],
+              [
+                91.370138,
+                33.100691
+              ],
+              [
+                91.311624,
+                33.108211
+              ],
+              [
+                91.261733,
+                33.141291
+              ],
+              [
+                91.226624,
+                33.141792
+              ],
+              [
+                91.18782,
+                33.106206
+              ],
+              [
+                91.161335,
+                33.108712
+              ],
+              [
+                91.147784,
+                33.07211
+              ],
+              [
+                91.072024,
+                33.113224
+              ],
+              [
+                91.037531,
+                33.098686
+              ],
+              [
+                91.001807,
+                33.11573
+              ],
+              [
+                90.927894,
+                33.120241
+              ],
+              [
+                90.902024,
+                33.083143
+              ],
+              [
+                90.88293,
+                33.120241
+              ],
+              [
+                90.803474,
+                33.114227
+              ],
+              [
+                90.740032,
+                33.142293
+              ],
+              [
+                90.704308,
+                33.135778
+              ],
+              [
+                90.627315,
+                33.180368
+              ],
+              [
+                90.562642,
+                33.229441
+              ],
+              [
+                90.490577,
+                33.264977
+              ],
+              [
+                90.405577,
+                33.260473
+              ],
+              [
+                90.363077,
+                33.279487
+              ],
+              [
+                90.332896,
+                33.310501
+              ],
+              [
+                90.246665,
+                33.423959
+              ],
+              [
+                90.22018,
+                33.437943
+              ],
+              [
+                90.107463,
+                33.460913
+              ],
+              [
+                90.088984,
+                33.478885
+              ],
+              [
+                90.083441,
+                33.525295
+              ],
+              [
+                90.01076,
+                33.553728
+              ],
+              [
+                89.984275,
+                33.612061
+              ],
+              [
+                90.008296,
+                33.687785
+              ],
+              [
+                89.981195,
+                33.70322
+              ],
+              [
+                89.983659,
+                33.725622
+              ],
+              [
+                89.907282,
+                33.741051
+              ],
+              [
+                89.902355,
+                33.758467
+              ],
+              [
+                89.942391,
+                33.801246
+              ],
+              [
+                89.899891,
+                33.80771
+              ],
+              [
+                89.837065,
+                33.868853
+              ],
+              [
+                89.795181,
+                33.865374
+              ],
+              [
+                89.73174,
+                33.921509
+              ],
+              [
+                89.718805,
+                33.946832
+              ],
+              [
+                89.688008,
+                33.959739
+              ],
+              [
+                89.684928,
+                33.990013
+              ],
+              [
+                89.635037,
+                34.049537
+              ],
+              [
+                89.656595,
+                34.057966
+              ],
+              [
+                89.655979,
+                34.097126
+              ],
+              [
+                89.71203,
+                34.131809
+              ],
+              [
+                89.756993,
+                34.124874
+              ],
+              [
+                89.760073,
+                34.152613
+              ],
+              [
+                89.789638,
+                34.150632
+              ],
+              [
+                89.816739,
+                34.16945
+              ],
+              [
+                89.838297,
+                34.263477
+              ],
+              [
+                89.825362,
+                34.293642
+              ],
+              [
+                89.86663,
+                34.324785
+              ],
+              [
+                89.858623,
+                34.359375
+              ],
+              [
+                89.820435,
+                34.369255
+              ],
+              [
+                89.799493,
+                34.39642
+              ],
+              [
+                89.819819,
+                34.420614
+              ],
+              [
+                89.823515,
+                34.455657
+              ],
+              [
+                89.814891,
+                34.548871
+              ],
+              [
+                89.777935,
+                34.574499
+              ],
+              [
+                89.798877,
+                34.628686
+              ],
+              [
+                89.74837,
+                34.641981
+              ],
+              [
+                89.72558,
+                34.660689
+              ],
+              [
+                89.732356,
+                34.732035
+              ],
+              [
+                89.799493,
+                34.743838
+              ],
+              [
+                89.825978,
+                34.796931
+              ],
+              [
+                89.867862,
+                34.81069
+              ],
+              [
+                89.838913,
+                34.865705
+              ],
+              [
+                89.814891,
+                34.86816
+              ],
+              [
+                89.821051,
+                34.902033
+              ],
+              [
+                89.78779,
+                34.921664
+              ],
+              [
+                89.747138,
+                34.903506
+              ],
+              [
+                89.707102,
+                34.919701
+              ],
+              [
+                89.670146,
+                34.887798
+              ],
+              [
+                89.578987,
+                34.895162
+              ],
+              [
+                89.560509,
+                34.938836
+              ],
+              [
+                89.59069,
+                35.057965
+              ],
+              [
+                89.593153,
+                35.104491
+              ],
+              [
+                89.579603,
+                35.118688
+              ],
+              [
+                89.519241,
+                35.133862
+              ],
+              [
+                89.46935,
+                35.214577
+              ],
+              [
+                89.450255,
+                35.223867
+              ],
+              [
+                89.48598,
+                35.256616
+              ],
+              [
+                89.531559,
+                35.276161
+              ],
+              [
+                89.494603,
+                35.298632
+              ],
+              [
+                89.516161,
+                35.330862
+              ],
+              [
+                89.497067,
+                35.361128
+              ],
+              [
+                89.58761,
+                35.383575
+              ],
+              [
+                89.619639,
+                35.412357
+              ],
+              [
+                89.658443,
+                35.425526
+              ],
+              [
+                89.685544,
+                35.416259
+              ],
+              [
+                89.739131,
+                35.468429
+              ],
+              [
+                89.765,
+                35.482563
+              ],
+              [
+                89.740979,
+                35.507412
+              ],
+              [
+                89.720037,
+                35.501566
+              ],
+              [
+                89.699711,
+                35.544916
+              ],
+              [
+                89.71203,
+                35.581915
+              ],
+              [
+                89.75145,
+                35.580942
+              ],
+              [
+                89.765616,
+                35.599922
+              ],
+              [
+                89.726196,
+                35.648082
+              ],
+              [
+                89.748986,
+                35.66267
+              ],
+              [
+                89.747138,
+                35.7516
+              ],
+              [
+                89.782863,
+                35.773453
+              ],
+              [
+                89.767464,
+                35.799183
+              ],
+              [
+                89.801957,
+                35.848193
+              ],
+              [
+                89.778551,
+                35.861775
+              ],
+              [
+                89.707718,
+                35.849163
+              ],
+              [
+                89.654747,
+                35.848193
+              ],
+              [
+                89.62395,
+                35.859349
+              ],
+              [
+                89.550654,
+                35.856924
+              ],
+              [
+                89.554965,
+                35.873414
+              ],
+              [
+                89.489676,
+                35.903475
+              ],
+              [
+                89.428082,
+                35.917531
+              ],
+              [
+                89.434857,
+                35.992136
+              ],
+              [
+                89.404676,
+                36.016827
+              ],
+              [
+                89.417611,
+                36.044897
+              ],
+              [
+                89.474893,
+                36.022151
+              ],
+              [
+                89.605472,
+                36.038123
+              ],
+              [
+                89.688624,
+                36.091337
+              ],
+              [
+                89.711414,
+                36.093272
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 610000,
+        "name": "闄曡タ鐪�",
+        "center": [
+          108.948024,
+          34.263161
+        ],
+        "centroid": [
+          108.887114,
+          35.263661
+        ],
+        "childrenNum": 10,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 26,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                110.379257,
+                34.600612
+              ],
+              [
+                110.29549,
+                34.610956
+              ],
+              [
+                110.269004,
+                34.629671
+              ],
+              [
+                110.229584,
+                34.692679
+              ],
+              [
+                110.243135,
+                34.725641
+              ],
+              [
+                110.246831,
+                34.789068
+              ],
+              [
+                110.230816,
+                34.880925
+              ],
+              [
+                110.262229,
+                34.944233
+              ],
+              [
+                110.320743,
+                35.00504
+              ],
+              [
+                110.373714,
+                35.134351
+              ],
+              [
+                110.364475,
+                35.197952
+              ],
+              [
+                110.378642,
+                35.210666
+              ],
+              [
+                110.374946,
+                35.251728
+              ],
+              [
+                110.45009,
+                35.327933
+              ],
+              [
+                110.477808,
+                35.413821
+              ],
+              [
+                110.531394,
+                35.511309
+              ],
+              [
+                110.567735,
+                35.539559
+              ],
+              [
+                110.589293,
+                35.602355
+              ],
+              [
+                110.609619,
+                35.632031
+              ],
+              [
+                110.57759,
+                35.701559
+              ],
+              [
+                110.571431,
+                35.800639
+              ],
+              [
+                110.550489,
+                35.838005
+              ],
+              [
+                110.549257,
+                35.877778
+              ],
+              [
+                110.511684,
+                35.879718
+              ],
+              [
+                110.516612,
+                35.918501
+              ],
+              [
+                110.502445,
+                35.947575
+              ],
+              [
+                110.516612,
+                35.971796
+              ],
+              [
+                110.49259,
+                35.994073
+              ],
+              [
+                110.491974,
+                36.034735
+              ],
+              [
+                110.467953,
+                36.074893
+              ],
+              [
+                110.447011,
+                36.164328
+              ],
+              [
+                110.45625,
+                36.22663
+              ],
+              [
+                110.474112,
+                36.248352
+              ],
+              [
+                110.474112,
+                36.306729
+              ],
+              [
+                110.459946,
+                36.327946
+              ],
+              [
+                110.487047,
+                36.393972
+              ],
+              [
+                110.489511,
+                36.430094
+              ],
+              [
+                110.47288,
+                36.453203
+              ],
+              [
+                110.503677,
+                36.488335
+              ],
+              [
+                110.488895,
+                36.556628
+              ],
+              [
+                110.496902,
+                36.582102
+              ],
+              [
+                110.447627,
+                36.621018
+              ],
+              [
+                110.426685,
+                36.657514
+              ],
+              [
+                110.394656,
+                36.676716
+              ],
+              [
+                110.402663,
+                36.697352
+              ],
+              [
+                110.438388,
+                36.685835
+              ],
+              [
+                110.447011,
+                36.737649
+              ],
+              [
+                110.407591,
+                36.776007
+              ],
+              [
+                110.423605,
+                36.818179
+              ],
+              [
+                110.406975,
+                36.824886
+              ],
+              [
+                110.424221,
+                36.855539
+              ],
+              [
+                110.376178,
+                36.882351
+              ],
+              [
+                110.408823,
+                36.892403
+              ],
+              [
+                110.424221,
+                36.963685
+              ],
+              [
+                110.381721,
+                37.002408
+              ],
+              [
+                110.382953,
+                37.022001
+              ],
+              [
+                110.426685,
+                37.008621
+              ],
+              [
+                110.417446,
+                37.027257
+              ],
+              [
+                110.460561,
+                37.044932
+              ],
+              [
+                110.49567,
+                37.086956
+              ],
+              [
+                110.535706,
+                37.115118
+              ],
+              [
+                110.53509,
+                37.138021
+              ],
+              [
+                110.590525,
+                37.187145
+              ],
+              [
+                110.651503,
+                37.256722
+              ],
+              [
+                110.661974,
+                37.281963
+              ],
+              [
+                110.690307,
+                37.287201
+              ],
+              [
+                110.678604,
+                37.317668
+              ],
+              [
+                110.695234,
+                37.34955
+              ],
+              [
+                110.641648,
+                37.360015
+              ],
+              [
+                110.630561,
+                37.372858
+              ],
+              [
+                110.644111,
+                37.435135
+              ],
+              [
+                110.740198,
+                37.44939
+              ],
+              [
+                110.759292,
+                37.474567
+              ],
+              [
+                110.770995,
+                37.538184
+              ],
+              [
+                110.795017,
+                37.558586
+              ],
+              [
+                110.771611,
+                37.594634
+              ],
+              [
+                110.763604,
+                37.639668
+              ],
+              [
+                110.793169,
+                37.650567
+              ],
+              [
+                110.775306,
+                37.680886
+              ],
+              [
+                110.706321,
+                37.705511
+              ],
+              [
+                110.716792,
+                37.728708
+              ],
+              [
+                110.750669,
+                37.736281
+              ],
+              [
+                110.735886,
+                37.77035
+              ],
+              [
+                110.680452,
+                37.790216
+              ],
+              [
+                110.59422,
+                37.922049
+              ],
+              [
+                110.522771,
+                37.955088
+              ],
+              [
+                110.528315,
+                37.990471
+              ],
+              [
+                110.507989,
+                38.013107
+              ],
+              [
+                110.501829,
+                38.097929
+              ],
+              [
+                110.519692,
+                38.130889
+              ],
+              [
+                110.509221,
+                38.192061
+              ],
+              [
+                110.528315,
+                38.211814
+              ],
+              [
+                110.565887,
+                38.215105
+              ],
+              [
+                110.57759,
+                38.297345
+              ],
+              [
+                110.601612,
+                38.308147
+              ],
+              [
+                110.661358,
+                38.308617
+              ],
+              [
+                110.701394,
+                38.353215
+              ],
+              [
+                110.746973,
+                38.366355
+              ],
+              [
+                110.77777,
+                38.440924
+              ],
+              [
+                110.796864,
+                38.453579
+              ],
+              [
+                110.840596,
+                38.439986
+              ],
+              [
+                110.874473,
+                38.453579
+              ],
+              [
+                110.870777,
+                38.510265
+              ],
+              [
+                110.907733,
+                38.521035
+              ],
+              [
+                110.920052,
+                38.581878
+              ],
+              [
+                110.898494,
+                38.587024
+              ],
+              [
+                110.880632,
+                38.626776
+              ],
+              [
+                110.916357,
+                38.673981
+              ],
+              [
+                110.915125,
+                38.704345
+              ],
+              [
+                110.965016,
+                38.755699
+              ],
+              [
+                111.009363,
+                38.847579
+              ],
+              [
+                110.995813,
+                38.868084
+              ],
+              [
+                111.016755,
+                38.889981
+              ],
+              [
+                111.009979,
+                38.932823
+              ],
+              [
+                110.980414,
+                38.970056
+              ],
+              [
+                110.998276,
+                38.998433
+              ],
+              [
+                111.038313,
+                39.020289
+              ],
+              [
+                111.094363,
+                39.030053
+              ],
+              [
+                111.138095,
+                39.064447
+              ],
+              [
+                111.147334,
+                39.100681
+              ],
+              [
+                111.173819,
+                39.135041
+              ],
+              [
+                111.163348,
+                39.152678
+              ],
+              [
+                111.219399,
+                39.244044
+              ],
+              [
+                111.213239,
+                39.257021
+              ],
+              [
+                111.247732,
+                39.302419
+              ],
+              [
+                111.202152,
+                39.305197
+              ],
+              [
+                111.179363,
+                39.326959
+              ],
+              [
+                111.186138,
+                39.35149
+              ],
+              [
+                111.155341,
+                39.338531
+              ],
+              [
+                111.159037,
+                39.362596
+              ],
+              [
+                111.125776,
+                39.366297
+              ],
+              [
+                111.087588,
+                39.376013
+              ],
+              [
+                111.098059,
+                39.401914
+              ],
+              [
+                111.064182,
+                39.400989
+              ],
+              [
+                111.058639,
+                39.447681
+              ],
+              [
+                111.10545,
+                39.472631
+              ],
+              [
+                111.10545,
+                39.497573
+              ],
+              [
+                111.148566,
+                39.531277
+              ],
+              [
+                111.154725,
+                39.569116
+              ],
+              [
+                111.136863,
+                39.587106
+              ],
+              [
+                111.101138,
+                39.559428
+              ],
+              [
+                111.017371,
+                39.552045
+              ],
+              [
+                110.958856,
+                39.519275
+              ],
+              [
+                110.891103,
+                39.509118
+              ],
+              [
+                110.869545,
+                39.494341
+              ],
+              [
+                110.782698,
+                39.38804
+              ],
+              [
+                110.73835,
+                39.348713
+              ],
+              [
+                110.731575,
+                39.30705
+              ],
+              [
+                110.702626,
+                39.273701
+              ],
+              [
+                110.626249,
+                39.266751
+              ],
+              [
+                110.596684,
+                39.282966
+              ],
+              [
+                110.566503,
+                39.320014
+              ],
+              [
+                110.559728,
+                39.351027
+              ],
+              [
+                110.524003,
+                39.382952
+              ],
+              [
+                110.482735,
+                39.360745
+              ],
+              [
+                110.434692,
+                39.381101
+              ],
+              [
+                110.429764,
+                39.341308
+              ],
+              [
+                110.385417,
+                39.310291
+              ],
+              [
+                110.257917,
+                39.407001
+              ],
+              [
+                110.243751,
+                39.423645
+              ],
+              [
+                110.152592,
+                39.45415
+              ],
+              [
+                110.12549,
+                39.432891
+              ],
+              [
+                110.136577,
+                39.39174
+              ],
+              [
+                110.161831,
+                39.387115
+              ],
+              [
+                110.184005,
+                39.355192
+              ],
+              [
+                110.217881,
+                39.281113
+              ],
+              [
+                110.109476,
+                39.249606
+              ],
+              [
+                110.041107,
+                39.21623
+              ],
+              [
+                109.962267,
+                39.212056
+              ],
+              [
+                109.90252,
+                39.271848
+              ],
+              [
+                109.871723,
+                39.243581
+              ],
+              [
+                109.961035,
+                39.191651
+              ],
+              [
+                109.893897,
+                39.141075
+              ],
+              [
+                109.92223,
+                39.107183
+              ],
+              [
+                109.890818,
+                39.103932
+              ],
+              [
+                109.851397,
+                39.122971
+              ],
+              [
+                109.793499,
+                39.074204
+              ],
+              [
+                109.762086,
+                39.057476
+              ],
+              [
+                109.72513,
+                39.018429
+              ],
+              [
+                109.665384,
+                38.981687
+              ],
+              [
+                109.685094,
+                38.968195
+              ],
+              [
+                109.672159,
+                38.928167
+              ],
+              [
+                109.624116,
+                38.85457
+              ],
+              [
+                109.549587,
+                38.805618
+              ],
+              [
+                109.511399,
+                38.833595
+              ],
+              [
+                109.444262,
+                38.782763
+              ],
+              [
+                109.404226,
+                38.720689
+              ],
+              [
+                109.338936,
+                38.701542
+              ],
+              [
+                109.329081,
+                38.66043
+              ],
+              [
+                109.367269,
+                38.627711
+              ],
+              [
+                109.331545,
+                38.597783
+              ],
+              [
+                109.276726,
+                38.623035
+              ],
+              [
+                109.196654,
+                38.552867
+              ],
+              [
+                109.175712,
+                38.518694
+              ],
+              [
+                109.128901,
+                38.480288
+              ],
+              [
+                109.054372,
+                38.433892
+              ],
+              [
+                109.051292,
+                38.385122
+              ],
+              [
+                109.007561,
+                38.359316
+              ],
+              [
+                108.961981,
+                38.26493
+              ],
+              [
+                108.976148,
+                38.245192
+              ],
+              [
+                108.938575,
+                38.207582
+              ],
+              [
+                108.964445,
+                38.154894
+              ],
+              [
+                109.069155,
+                38.091336
+              ],
+              [
+                109.050676,
+                38.055059
+              ],
+              [
+                109.06977,
+                38.023008
+              ],
+              [
+                109.037742,
+                38.021593
+              ],
+              [
+                109.018648,
+                37.971602
+              ],
+              [
+                108.982923,
+                37.964053
+              ],
+              [
+                108.9743,
+                37.931962
+              ],
+              [
+                108.93488,
+                37.922521
+              ],
+              [
+                108.893612,
+                37.978207
+              ],
+              [
+                108.883141,
+                38.01405
+              ],
+              [
+                108.830786,
+                38.049875
+              ],
+              [
+                108.797525,
+                38.04799
+              ],
+              [
+                108.82709,
+                37.989056
+              ],
+              [
+                108.798141,
+                37.93385
+              ],
+              [
+                108.791982,
+                37.872934
+              ],
+              [
+                108.799989,
+                37.784068
+              ],
+              [
+                108.784591,
+                37.764673
+              ],
+              [
+                108.791982,
+                37.700303
+              ],
+              [
+                108.777815,
+                37.683728
+              ],
+              [
+                108.720533,
+                37.683728
+              ],
+              [
+                108.699591,
+                37.669518
+              ],
+              [
+                108.628142,
+                37.651988
+              ],
+              [
+                108.532671,
+                37.690832
+              ],
+              [
+                108.485244,
+                37.678044
+              ],
+              [
+                108.422418,
+                37.648672
+              ],
+              [
+                108.301078,
+                37.640616
+              ],
+              [
+                108.293071,
+                37.656726
+              ],
+              [
+                108.24626,
+                37.665728
+              ],
+              [
+                108.205608,
+                37.655779
+              ],
+              [
+                108.193905,
+                37.638246
+              ],
+              [
+                108.134159,
+                37.622131
+              ],
+              [
+                108.055318,
+                37.652462
+              ],
+              [
+                108.025137,
+                37.649619
+              ],
+              [
+                108.012819,
+                37.66857
+              ],
+              [
+                108.025753,
+                37.696041
+              ],
+              [
+                107.993109,
+                37.735335
+              ],
+              [
+                107.982022,
+                37.787378
+              ],
+              [
+                107.884703,
+                37.808186
+              ],
+              [
+                107.842819,
+                37.828987
+              ],
+              [
+                107.732566,
+                37.84931
+              ],
+              [
+                107.684523,
+                37.888522
+              ],
+              [
+                107.65003,
+                37.86443
+              ],
+              [
+                107.659269,
+                37.844112
+              ],
+              [
+                107.646335,
+                37.805349
+              ],
+              [
+                107.620465,
+                37.776026
+              ],
+              [
+                107.599523,
+                37.791162
+              ],
+              [
+                107.57119,
+                37.776499
+              ],
+              [
+                107.499125,
+                37.765619
+              ],
+              [
+                107.484959,
+                37.706458
+              ],
+              [
+                107.425828,
+                37.684201
+              ],
+              [
+                107.387024,
+                37.691305
+              ],
+              [
+                107.389488,
+                37.671413
+              ],
+              [
+                107.422133,
+                37.665254
+              ],
+              [
+                107.361155,
+                37.613125
+              ],
+              [
+                107.311264,
+                37.609806
+              ],
+              [
+                107.330358,
+                37.584201
+              ],
+              [
+                107.369162,
+                37.58752
+              ],
+              [
+                107.345756,
+                37.518725
+              ],
+              [
+                107.284162,
+                37.481691
+              ],
+              [
+                107.282931,
+                37.437036
+              ],
+              [
+                107.257677,
+                37.337179
+              ],
+              [
+                107.273075,
+                37.29101
+              ],
+              [
+                107.309416,
+                37.239095
+              ],
+              [
+                107.270612,
+                37.229089
+              ],
+              [
+                107.317423,
+                37.200017
+              ],
+              [
+                107.336517,
+                37.165687
+              ],
+              [
+                107.334669,
+                37.138975
+              ],
+              [
+                107.306952,
+                37.100799
+              ],
+              [
+                107.281083,
+                37.127047
+              ],
+              [
+                107.268764,
+                37.099367
+              ],
+              [
+                107.28601,
+                37.054963
+              ],
+              [
+                107.288474,
+                37.008143
+              ],
+              [
+                107.288474,
+                37.008143
+              ],
+              [
+                107.291554,
+                36.979463
+              ],
+              [
+                107.291554,
+                36.979463
+              ],
+              [
+                107.310032,
+                36.912502
+              ],
+              [
+                107.336517,
+                36.925899
+              ],
+              [
+                107.365466,
+                36.905324
+              ],
+              [
+                107.478183,
+                36.908196
+              ],
+              [
+                107.533618,
+                36.867031
+              ],
+              [
+                107.540393,
+                36.828718
+              ],
+              [
+                107.5909,
+                36.836382
+              ],
+              [
+                107.642023,
+                36.819137
+              ],
+              [
+                107.670356,
+                36.83303
+              ],
+              [
+                107.722095,
+                36.802367
+              ],
+              [
+                107.742421,
+                36.811951
+              ],
+              [
+                107.768291,
+                36.792783
+              ],
+              [
+                107.866841,
+                36.766899
+              ],
+              [
+                107.907493,
+                36.750118
+              ],
+              [
+                107.914268,
+                36.720861
+              ],
+              [
+                107.940754,
+                36.694953
+              ],
+              [
+                107.938906,
+                36.655594
+              ],
+              [
+                108.006659,
+                36.683435
+              ],
+              [
+                108.02329,
+                36.647912
+              ],
+              [
+                108.001732,
+                36.639269
+              ],
+              [
+                108.060862,
+                36.592194
+              ],
+              [
+                108.079956,
+                36.614294
+              ],
+              [
+                108.092891,
+                36.587388
+              ],
+              [
+                108.163724,
+                36.563839
+              ],
+              [
+                108.1976,
+                36.630144
+              ],
+              [
+                108.222854,
+                36.631105
+              ],
+              [
+                108.204992,
+                36.606607
+              ],
+              [
+                108.204992,
+                36.606607
+              ],
+              [
+                108.210535,
+                36.577296
+              ],
+              [
+                108.245644,
+                36.571048
+              ],
+              [
+                108.262274,
+                36.549417
+              ],
+              [
+                108.340498,
+                36.559032
+              ],
+              [
+                108.365136,
+                36.519603
+              ],
+              [
+                108.391621,
+                36.505654
+              ],
+              [
+                108.408252,
+                36.45946
+              ],
+              [
+                108.460606,
+                36.422871
+              ],
+              [
+                108.495099,
+                36.422389
+              ],
+              [
+                108.514809,
+                36.445501
+              ],
+              [
+                108.510498,
+                36.47438
+              ],
+              [
+                108.562852,
+                36.43876
+              ],
+              [
+                108.618903,
+                36.433946
+              ],
+              [
+                108.651548,
+                36.384818
+              ],
+              [
+                108.641693,
+                36.359279
+              ],
+              [
+                108.646004,
+                36.254143
+              ],
+              [
+                108.712526,
+                36.138716
+              ],
+              [
+                108.682345,
+                36.062316
+              ],
+              [
+                108.688504,
+                36.021183
+              ],
+              [
+                108.659555,
+                35.990683
+              ],
+              [
+                108.652164,
+                35.94806
+              ],
+              [
+                108.593649,
+                35.950967
+              ],
+              [
+                108.562852,
+                35.921409
+              ],
+              [
+                108.518505,
+                35.905414
+              ],
+              [
+                108.499411,
+                35.872444
+              ],
+              [
+                108.527744,
+                35.82442
+              ],
+              [
+                108.533903,
+                35.746257
+              ],
+              [
+                108.517889,
+                35.699615
+              ],
+              [
+                108.539447,
+                35.605761
+              ],
+              [
+                108.618287,
+                35.557088
+              ],
+              [
+                108.625678,
+                35.537124
+              ],
+              [
+                108.605968,
+                35.503028
+              ],
+              [
+                108.631222,
+                35.418698
+              ],
+              [
+                108.61028,
+                35.355271
+              ],
+              [
+                108.614591,
+                35.328909
+              ],
+              [
+                108.583178,
+                35.294724
+              ],
+              [
+                108.547454,
+                35.304981
+              ],
+              [
+                108.48894,
+                35.275184
+              ],
+              [
+                108.36144,
+                35.279581
+              ],
+              [
+                108.345426,
+                35.300586
+              ],
+              [
+                108.296767,
+                35.267855
+              ],
+              [
+                108.239484,
+                35.256127
+              ],
+              [
+                108.221622,
+                35.296678
+              ],
+              [
+                108.174811,
+                35.304981
+              ],
+              [
+                108.094739,
+                35.280069
+              ],
+              [
+                108.049159,
+                35.253683
+              ],
+              [
+                107.949993,
+                35.245375
+              ],
+              [
+                107.960464,
+                35.263457
+              ],
+              [
+                107.867457,
+                35.256127
+              ],
+              [
+                107.841587,
+                35.276649
+              ],
+              [
+                107.745501,
+                35.311819
+              ],
+              [
+                107.737494,
+                35.267366
+              ],
+              [
+                107.667277,
+                35.257104
+              ],
+              [
+                107.652494,
+                35.244886
+              ],
+              [
+                107.686371,
+                35.218
+              ],
+              [
+                107.715936,
+                35.168114
+              ],
+              [
+                107.727639,
+                35.120157
+              ],
+              [
+                107.769523,
+                35.064333
+              ],
+              [
+                107.769523,
+                35.064333
+              ],
+              [
+                107.773218,
+                35.060904
+              ],
+              [
+                107.773218,
+                35.060904
+              ],
+              [
+                107.814486,
+                35.024646
+              ],
+              [
+                107.846515,
+                35.024646
+              ],
+              [
+                107.863145,
+                34.999158
+              ],
+              [
+                107.842203,
+                34.979056
+              ],
+              [
+                107.741805,
+                34.953553
+              ],
+              [
+                107.675284,
+                34.9511
+              ],
+              [
+                107.638943,
+                34.935402
+              ],
+              [
+                107.619849,
+                34.964834
+              ],
+              [
+                107.564415,
+                34.968757
+              ],
+              [
+                107.523763,
+                34.909886
+              ],
+              [
+                107.455394,
+                34.916757
+              ],
+              [
+                107.400575,
+                34.932949
+              ],
+              [
+                107.369162,
+                34.917738
+              ],
+              [
+                107.350068,
+                34.93393
+              ],
+              [
+                107.286626,
+                34.931968
+              ],
+              [
+                107.252749,
+                34.880925
+              ],
+              [
+                107.189308,
+                34.893198
+              ],
+              [
+                107.162206,
+                34.944233
+              ],
+              [
+                107.119707,
+                34.950119
+              ],
+              [
+                107.089526,
+                34.976604
+              ],
+              [
+                107.08275,
+                35.024156
+              ],
+              [
+                107.012533,
+                35.029547
+              ],
+              [
+                106.990975,
+                35.068252
+              ],
+              [
+                106.950323,
+                35.066782
+              ],
+              [
+                106.901664,
+                35.094698
+              ],
+              [
+                106.838222,
+                35.080007
+              ],
+              [
+                106.710723,
+                35.100574
+              ],
+              [
+                106.706411,
+                35.081966
+              ],
+              [
+                106.615252,
+                35.071191
+              ],
+              [
+                106.577064,
+                35.089312
+              ],
+              [
+                106.541956,
+                35.083925
+              ],
+              [
+                106.52163,
+                35.027587
+              ],
+              [
+                106.494528,
+                35.006021
+              ],
+              [
+                106.494528,
+                35.006021
+              ],
+              [
+                106.484673,
+                34.983959
+              ],
+              [
+                106.493296,
+                34.941289
+              ],
+              [
+                106.527789,
+                34.876507
+              ],
+              [
+                106.556122,
+                34.861285
+              ],
+              [
+                106.550579,
+                34.82936
+              ],
+              [
+                106.575216,
+                34.769897
+              ],
+              [
+                106.539492,
+                34.745805
+              ],
+              [
+                106.505615,
+                34.746789
+              ],
+              [
+                106.487137,
+                34.715311
+              ],
+              [
+                106.456956,
+                34.703996
+              ],
+              [
+                106.442173,
+                34.675455
+              ],
+              [
+                106.471122,
+                34.634102
+              ],
+              [
+                106.419384,
+                34.643458
+              ],
+              [
+                106.314058,
+                34.578934
+              ],
+              [
+                106.341159,
+                34.568093
+              ],
+              [
+                106.334384,
+                34.517811
+              ],
+              [
+                106.455108,
+                34.531617
+              ],
+              [
+                106.514238,
+                34.511894
+              ],
+              [
+                106.513622,
+                34.498085
+              ],
+              [
+                106.558586,
+                34.48822
+              ],
+              [
+                106.610941,
+                34.454177
+              ],
+              [
+                106.638042,
+                34.391481
+              ],
+              [
+                106.717498,
+                34.369255
+              ],
+              [
+                106.691013,
+                34.337635
+              ],
+              [
+                106.705179,
+                34.299575
+              ],
+              [
+                106.68239,
+                34.256057
+              ],
+              [
+                106.652825,
+                34.24369
+              ],
+              [
+                106.63373,
+                34.260014
+              ],
+              [
+                106.589383,
+                34.253584
+              ],
+              [
+                106.577064,
+                34.280786
+              ],
+              [
+                106.526557,
+                34.292159
+              ],
+              [
+                106.496376,
+                34.238248
+              ],
+              [
+                106.5321,
+                34.254079
+              ],
+              [
+                106.55797,
+                34.229837
+              ],
+              [
+                106.585071,
+                34.149641
+              ],
+              [
+                106.560434,
+                34.109514
+              ],
+              [
+                106.501919,
+                34.105055
+              ],
+              [
+                106.505615,
+                34.056479
+              ],
+              [
+                106.471738,
+                34.024244
+              ],
+              [
+                106.474202,
+                33.970659
+              ],
+              [
+                106.41076,
+                33.909093
+              ],
+              [
+                106.428007,
+                33.866368
+              ],
+              [
+                106.475434,
+                33.875809
+              ],
+              [
+                106.491448,
+                33.834559
+              ],
+              [
+                106.461883,
+                33.789807
+              ],
+              [
+                106.488369,
+                33.757969
+              ],
+              [
+                106.482825,
+                33.707203
+              ],
+              [
+                106.534564,
+                33.695254
+              ],
+              [
+                106.575832,
+                33.631497
+              ],
+              [
+                106.58076,
+                33.576169
+              ],
+              [
+                106.540108,
+                33.512822
+              ],
+              [
+                106.456956,
+                33.532779
+              ],
+              [
+                106.447101,
+                33.613058
+              ],
+              [
+                106.384891,
+                33.612061
+              ],
+              [
+                106.35163,
+                33.587137
+              ],
+              [
+                106.303587,
+                33.604585
+              ],
+              [
+                106.237681,
+                33.564201
+              ],
+              [
+                106.187174,
+                33.546746
+              ],
+              [
+                106.108334,
+                33.569686
+              ],
+              [
+                106.117573,
+                33.602591
+              ],
+              [
+                106.086776,
+                33.617045
+              ],
+              [
+                106.047356,
+                33.610067
+              ],
+              [
+                105.971596,
+                33.613058
+              ],
+              [
+                105.940183,
+                33.570684
+              ],
+              [
+                105.902611,
+                33.556222
+              ],
+              [
+                105.871198,
+                33.511325
+              ],
+              [
+                105.842248,
+                33.489866
+              ],
+              [
+                105.831162,
+                33.451926
+              ],
+              [
+                105.837937,
+                33.410971
+              ],
+              [
+                105.827466,
+                33.379993
+              ],
+              [
+                105.709822,
+                33.382991
+              ],
+              [
+                105.755401,
+                33.329004
+              ],
+              [
+                105.752937,
+                33.291994
+              ],
+              [
+                105.791741,
+                33.278486
+              ],
+              [
+                105.799133,
+                33.258471
+              ],
+              [
+                105.862574,
+                33.234447
+              ],
+              [
+                105.917393,
+                33.237951
+              ],
+              [
+                105.965436,
+                33.204407
+              ],
+              [
+                105.968516,
+                33.154318
+              ],
+              [
+                105.93156,
+                33.178365
+              ],
+              [
+                105.897067,
+                33.146803
+              ],
+              [
+                105.923552,
+                33.147805
+              ],
+              [
+                105.934639,
+                33.112221
+              ],
+              [
+                105.914929,
+                33.066092
+              ],
+              [
+                105.926632,
+                33.042517
+              ],
+              [
+                105.917393,
+                32.993841
+              ],
+              [
+                105.861959,
+                32.939112
+              ],
+              [
+                105.82685,
+                32.950663
+              ],
+              [
+                105.735691,
+                32.905454
+              ],
+              [
+                105.656851,
+                32.895405
+              ],
+              [
+                105.638373,
+                32.879323
+              ],
+              [
+                105.590329,
+                32.87681
+              ],
+              [
+                105.565692,
+                32.906962
+              ],
+              [
+                105.528119,
+                32.919019
+              ],
+              [
+                105.49917,
+                32.911986
+              ],
+              [
+                105.495475,
+                32.873292
+              ],
+              [
+                105.524424,
+                32.847654
+              ],
+              [
+                105.534279,
+                32.790822
+              ],
+              [
+                105.555221,
+                32.794343
+              ],
+              [
+                105.563844,
+                32.724891
+              ],
+              [
+                105.585402,
+                32.728919
+              ],
+              [
+                105.596489,
+                32.69921
+              ],
+              [
+                105.677793,
+                32.726402
+              ],
+              [
+                105.719061,
+                32.759624
+              ],
+              [
+                105.768952,
+                32.767676
+              ],
+              [
+                105.779423,
+                32.750061
+              ],
+              [
+                105.822538,
+                32.770192
+              ],
+              [
+                105.825002,
+                32.824523
+              ],
+              [
+                105.849024,
+                32.817985
+              ],
+              [
+                105.893371,
+                32.838603
+              ],
+              [
+                105.93156,
+                32.826032
+              ],
+              [
+                105.969132,
+                32.849162
+              ],
+              [
+                106.011632,
+                32.829552
+              ],
+              [
+                106.044277,
+                32.864747
+              ],
+              [
+                106.071378,
+                32.828546
+              ],
+              [
+                106.093552,
+                32.82402
+              ],
+              [
+                106.07261,
+                32.76365
+              ],
+              [
+                106.076921,
+                32.76365
+              ],
+              [
+                106.076305,
+                32.759121
+              ],
+              [
+                106.071378,
+                32.758114
+              ],
+              [
+                106.120037,
+                32.719856
+              ],
+              [
+                106.17424,
+                32.6977
+              ],
+              [
+                106.254928,
+                32.693671
+              ],
+              [
+                106.267863,
+                32.673522
+              ],
+              [
+                106.301123,
+                32.680071
+              ],
+              [
+                106.347935,
+                32.671003
+              ],
+              [
+                106.389203,
+                32.62666
+              ],
+              [
+                106.421231,
+                32.616579
+              ],
+              [
+                106.451412,
+                32.65992
+              ],
+              [
+                106.498224,
+                32.649338
+              ],
+              [
+                106.517934,
+                32.668485
+              ],
+              [
+                106.585687,
+                32.68813
+              ],
+              [
+                106.626955,
+                32.682086
+              ],
+              [
+                106.670071,
+                32.694678
+              ],
+              [
+                106.733513,
+                32.739491
+              ],
+              [
+                106.783404,
+                32.735967
+              ],
+              [
+                106.793259,
+                32.712807
+              ],
+              [
+                106.82344,
+                32.705254
+              ],
+              [
+                106.854853,
+                32.724388
+              ],
+              [
+                106.903512,
+                32.721367
+              ],
+              [
+                106.912751,
+                32.704247
+              ],
+              [
+                107.012533,
+                32.721367
+              ],
+              [
+                107.066736,
+                32.708779
+              ],
+              [
+                107.05996,
+                32.686115
+              ],
+              [
+                107.098765,
+                32.649338
+              ],
+              [
+                107.108004,
+                32.600951
+              ],
+              [
+                107.080286,
+                32.542448
+              ],
+              [
+                107.127098,
+                32.482393
+              ],
+              [
+                107.189924,
+                32.468256
+              ],
+              [
+                107.212097,
+                32.428864
+              ],
+              [
+                107.263836,
+                32.403099
+              ],
+              [
+                107.287858,
+                32.457147
+              ],
+              [
+                107.313727,
+                32.489965
+              ],
+              [
+                107.356843,
+                32.506622
+              ],
+              [
+                107.382097,
+                32.54043
+              ],
+              [
+                107.436299,
+                32.529835
+              ],
+              [
+                107.438763,
+                32.465732
+              ],
+              [
+                107.460937,
+                32.453612
+              ],
+              [
+                107.456625,
+                32.41775
+              ],
+              [
+                107.489886,
+                32.425328
+              ],
+              [
+                107.527458,
+                32.38238
+              ],
+              [
+                107.598291,
+                32.411688
+              ],
+              [
+                107.648183,
+                32.413709
+              ],
+              [
+                107.680827,
+                32.397035
+              ],
+              [
+                107.707929,
+                32.331826
+              ],
+              [
+                107.753508,
+                32.338399
+              ],
+              [
+                107.812022,
+                32.247844
+              ],
+              [
+                107.864377,
+                32.201266
+              ],
+              [
+                107.890247,
+                32.214432
+              ],
+              [
+                107.924739,
+                32.197215
+              ],
+              [
+                107.979558,
+                32.146051
+              ],
+              [
+                108.024521,
+                32.177462
+              ],
+              [
+                108.018362,
+                32.2119
+              ],
+              [
+                108.086731,
+                32.233165
+              ],
+              [
+                108.143398,
+                32.219495
+              ],
+              [
+                108.156948,
+                32.239239
+              ],
+              [
+                108.179738,
+                32.221521
+              ],
+              [
+                108.240716,
+                32.274666
+              ],
+              [
+                108.310933,
+                32.232152
+              ],
+              [
+                108.389773,
+                32.263533
+              ],
+              [
+                108.414411,
+                32.252399
+              ],
+              [
+                108.469846,
+                32.270618
+              ],
+              [
+                108.507418,
+                32.245819
+              ],
+              [
+                108.509882,
+                32.201266
+              ],
+              [
+                108.543758,
+                32.177969
+              ],
+              [
+                108.585026,
+                32.17189
+              ],
+              [
+                108.676801,
+                32.10297
+              ],
+              [
+                108.734084,
+                32.106519
+              ],
+              [
+                108.75133,
+                32.076098
+              ],
+              [
+                108.78767,
+                32.04871
+              ],
+              [
+                108.837561,
+                32.039072
+              ],
+              [
+                108.902235,
+                31.984774
+              ],
+              [
+                108.986619,
+                31.980205
+              ],
+              [
+                109.085785,
+                31.929428
+              ],
+              [
+                109.123357,
+                31.892851
+              ],
+              [
+                109.191111,
+                31.85575
+              ],
+              [
+                109.195422,
+                31.817618
+              ],
+              [
+                109.27611,
+                31.79931
+              ],
+              [
+                109.279806,
+                31.776418
+              ],
+              [
+                109.253936,
+                31.759628
+              ],
+              [
+                109.282885,
+                31.743343
+              ],
+              [
+                109.281654,
+                31.716874
+              ],
+              [
+                109.381436,
+                31.705165
+              ],
+              [
+                109.446109,
+                31.722983
+              ],
+              [
+                109.502776,
+                31.716365
+              ],
+              [
+                109.549587,
+                31.73011
+              ],
+              [
+                109.585928,
+                31.726546
+              ],
+              [
+                109.592087,
+                31.789136
+              ],
+              [
+                109.633971,
+                31.804396
+              ],
+              [
+                109.633971,
+                31.824738
+              ],
+              [
+                109.60379,
+                31.885737
+              ],
+              [
+                109.584696,
+                31.900472
+              ],
+              [
+                109.62042,
+                31.928412
+              ],
+              [
+                109.631507,
+                31.962436
+              ],
+              [
+                109.590855,
+                32.012688
+              ],
+              [
+                109.590855,
+                32.047696
+              ],
+              [
+                109.621652,
+                32.106519
+              ],
+              [
+                109.58716,
+                32.161251
+              ],
+              [
+                109.604406,
+                32.199241
+              ],
+              [
+                109.592703,
+                32.219495
+              ],
+              [
+                109.550203,
+                32.225065
+              ],
+              [
+                109.528645,
+                32.270112
+              ],
+              [
+                109.495385,
+                32.300468
+              ],
+              [
+                109.513247,
+                32.342444
+              ],
+              [
+                109.502776,
+                32.38895
+              ],
+              [
+                109.529877,
+                32.405625
+              ],
+              [
+                109.526797,
+                32.43341
+              ],
+              [
+                109.575457,
+                32.506622
+              ],
+              [
+                109.637051,
+                32.540935
+              ],
+              [
+                109.619804,
+                32.56767
+              ],
+              [
+                109.631507,
+                32.599943
+              ],
+              [
+                109.726978,
+                32.608513
+              ],
+              [
+                109.746072,
+                32.594901
+              ],
+              [
+                109.816905,
+                32.577252
+              ],
+              [
+                109.910528,
+                32.592884
+              ],
+              [
+                109.97089,
+                32.577756
+              ],
+              [
+                110.017701,
+                32.546989
+              ],
+              [
+                110.084223,
+                32.580782
+              ],
+              [
+                110.090382,
+                32.617083
+              ],
+              [
+                110.124259,
+                32.616579
+              ],
+              [
+                110.153824,
+                32.593388
+              ],
+              [
+                110.206179,
+                32.633212
+              ],
+              [
+                110.156903,
+                32.683093
+              ],
+              [
+                110.159367,
+                32.767173
+              ],
+              [
+                110.127338,
+                32.77774
+              ],
+              [
+                110.142121,
+                32.802895
+              ],
+              [
+                110.105164,
+                32.832569
+              ],
+              [
+                110.051578,
+                32.851676
+              ],
+              [
+                109.988752,
+                32.886359
+              ],
+              [
+                109.927158,
+                32.887364
+              ],
+              [
+                109.907448,
+                32.903947
+              ],
+              [
+                109.856941,
+                32.910479
+              ],
+              [
+                109.847702,
+                32.893395
+              ],
+              [
+                109.789804,
+                32.882339
+              ],
+              [
+                109.76455,
+                32.909474
+              ],
+              [
+                109.785492,
+                32.987316
+              ],
+              [
+                109.794731,
+                33.067095
+              ],
+              [
+                109.704188,
+                33.101694
+              ],
+              [
+                109.688174,
+                33.116733
+              ],
+              [
+                109.576073,
+                33.110216
+              ],
+              [
+                109.522486,
+                33.138785
+              ],
+              [
+                109.468283,
+                33.140288
+              ],
+              [
+                109.438718,
+                33.152314
+              ],
+              [
+                109.498464,
+                33.207412
+              ],
+              [
+                109.514479,
+                33.237951
+              ],
+              [
+                109.60687,
+                33.235949
+              ],
+              [
+                109.619804,
+                33.275484
+              ],
+              [
+                109.649985,
+                33.251465
+              ],
+              [
+                109.693101,
+                33.254468
+              ],
+              [
+                109.732521,
+                33.231443
+              ],
+              [
+                109.813209,
+                33.236449
+              ],
+              [
+                109.852013,
+                33.247961
+              ],
+              [
+                109.916687,
+                33.229942
+              ],
+              [
+                109.973353,
+                33.203907
+              ],
+              [
+                109.999223,
+                33.212419
+              ],
+              [
+                110.031252,
+                33.191888
+              ],
+              [
+                110.164911,
+                33.209415
+              ],
+              [
+                110.218497,
+                33.163336
+              ],
+              [
+                110.285635,
+                33.171352
+              ],
+              [
+                110.33799,
+                33.160331
+              ],
+              [
+                110.372482,
+                33.186379
+              ],
+              [
+                110.398352,
+                33.176862
+              ],
+              [
+                110.398352,
+                33.176862
+              ],
+              [
+                110.471032,
+                33.171352
+              ],
+              [
+                110.54125,
+                33.255469
+              ],
+              [
+                110.57759,
+                33.250464
+              ],
+              [
+                110.59422,
+                33.168346
+              ],
+              [
+                110.623785,
+                33.143796
+              ],
+              [
+                110.650887,
+                33.157324
+              ],
+              [
+                110.702626,
+                33.097182
+              ],
+              [
+                110.753133,
+                33.15031
+              ],
+              [
+                110.824582,
+                33.158327
+              ],
+              [
+                110.828893,
+                33.201403
+              ],
+              [
+                110.865234,
+                33.213921
+              ],
+              [
+                110.9219,
+                33.203907
+              ],
+              [
+                110.960704,
+                33.253967
+              ],
+              [
+                110.984726,
+                33.255469
+              ],
+              [
+                111.025994,
+                33.330504
+              ],
+              [
+                111.025994,
+                33.375495
+              ],
+              [
+                110.996429,
+                33.435946
+              ],
+              [
+                111.02661,
+                33.467903
+              ],
+              [
+                111.021066,
+                33.471397
+              ],
+              [
+                111.021682,
+                33.476389
+              ],
+              [
+                111.02661,
+                33.478386
+              ],
+              [
+                111.002588,
+                33.535772
+              ],
+              [
+                111.00382,
+                33.578662
+              ],
+              [
+                110.966864,
+                33.609071
+              ],
+              [
+                110.878784,
+                33.634486
+              ],
+              [
+                110.823966,
+                33.685793
+              ],
+              [
+                110.831973,
+                33.713675
+              ],
+              [
+                110.81719,
+                33.751003
+              ],
+              [
+                110.782082,
+                33.796272
+              ],
+              [
+                110.74143,
+                33.798759
+              ],
+              [
+                110.712481,
+                33.833564
+              ],
+              [
+                110.66259,
+                33.85295
+              ],
+              [
+                110.612083,
+                33.852453
+              ],
+              [
+                110.587445,
+                33.887733
+              ],
+              [
+                110.628713,
+                33.910086
+              ],
+              [
+                110.627481,
+                33.925482
+              ],
+              [
+                110.665669,
+                33.937895
+              ],
+              [
+                110.671213,
+                33.966192
+              ],
+              [
+                110.620706,
+                34.035652
+              ],
+              [
+                110.587445,
+                34.023252
+              ],
+              [
+                110.591757,
+                34.101586
+              ],
+              [
+                110.61393,
+                34.113478
+              ],
+              [
+                110.642264,
+                34.161032
+              ],
+              [
+                110.621938,
+                34.177372
+              ],
+              [
+                110.55788,
+                34.193214
+              ],
+              [
+                110.55172,
+                34.213012
+              ],
+              [
+                110.507989,
+                34.217466
+              ],
+              [
+                110.43962,
+                34.243196
+              ],
+              [
+                110.428533,
+                34.288203
+              ],
+              [
+                110.451938,
+                34.292653
+              ],
+              [
+                110.503677,
+                34.33714
+              ],
+              [
+                110.473496,
+                34.393457
+              ],
+              [
+                110.403279,
+                34.433448
+              ],
+              [
+                110.403279,
+                34.433448
+              ],
+              [
+                110.360779,
+                34.516825
+              ],
+              [
+                110.372482,
+                34.544435
+              ],
+              [
+                110.404511,
+                34.557743
+              ],
+              [
+                110.366939,
+                34.566614
+              ],
+              [
+                110.379257,
+                34.600612
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                111.02661,
+                33.478386
+              ],
+              [
+                111.021682,
+                33.476389
+              ],
+              [
+                111.021066,
+                33.471397
+              ],
+              [
+                111.02661,
+                33.467903
+              ],
+              [
+                111.02661,
+                33.478386
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.076921,
+                32.76365
+              ],
+              [
+                106.07261,
+                32.76365
+              ],
+              [
+                106.071378,
+                32.758114
+              ],
+              [
+                106.076305,
+                32.759121
+              ],
+              [
+                106.076921,
+                32.76365
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 620000,
+        "name": "鐢樿們鐪�",
+        "center": [
+          103.823557,
+          36.058039
+        ],
+        "childrenNum": 14,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 27,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                106.506231,
+                35.737514
+              ],
+              [
+                106.504383,
+                35.736057
+              ],
+              [
+                106.498224,
+                35.732656
+              ],
+              [
+                106.49268,
+                35.732656
+              ],
+              [
+                106.434782,
+                35.688436
+              ],
+              [
+                106.460036,
+                35.643705
+              ],
+              [
+                106.47913,
+                35.575101
+              ],
+              [
+                106.460036,
+                35.578995
+              ],
+              [
+                106.440941,
+                35.52641
+              ],
+              [
+                106.465579,
+                35.481101
+              ],
+              [
+                106.490217,
+                35.480613
+              ],
+              [
+                106.483441,
+                35.450393
+              ],
+              [
+                106.503767,
+                35.415284
+              ],
+              [
+                106.501304,
+                35.364056
+              ],
+              [
+                106.472354,
+                35.310842
+              ],
+              [
+                106.415688,
+                35.276161
+              ],
+              [
+                106.368261,
+                35.273718
+              ],
+              [
+                106.363333,
+                35.238532
+              ],
+              [
+                106.319601,
+                35.265411
+              ],
+              [
+                106.241377,
+                35.358687
+              ],
+              [
+                106.237681,
+                35.409431
+              ],
+              [
+                106.196414,
+                35.409919
+              ],
+              [
+                106.173008,
+                35.437716
+              ],
+              [
+                106.129892,
+                35.393333
+              ],
+              [
+                106.113262,
+                35.361616
+              ],
+              [
+                106.083081,
+                35.421624
+              ],
+              [
+                106.073226,
+                35.420649
+              ],
+              [
+                106.067682,
+                35.436254
+              ],
+              [
+                106.073226,
+                35.447468
+              ],
+              [
+                106.071378,
+                35.449418
+              ],
+              [
+                106.06953,
+                35.458193
+              ],
+              [
+                106.071994,
+                35.463555
+              ],
+              [
+                106.054132,
+                35.45478
+              ],
+              [
+                106.034422,
+                35.469404
+              ],
+              [
+                106.002393,
+                35.438692
+              ],
+              [
+                105.894603,
+                35.413821
+              ],
+              [
+                105.897683,
+                35.451368
+              ],
+              [
+                106.048588,
+                35.488898
+              ],
+              [
+                106.047356,
+                35.498155
+              ],
+              [
+                106.023335,
+                35.49377
+              ],
+              [
+                106.017175,
+                35.519103
+              ],
+              [
+                105.900147,
+                35.54735
+              ],
+              [
+                105.868734,
+                35.540046
+              ],
+              [
+                105.847176,
+                35.490359
+              ],
+              [
+                105.816379,
+                35.575101
+              ],
+              [
+                105.800365,
+                35.564878
+              ],
+              [
+                105.762176,
+                35.602841
+              ],
+              [
+                105.759097,
+                35.634464
+              ],
+              [
+                105.713517,
+                35.650513
+              ],
+              [
+                105.722756,
+                35.673366
+              ],
+              [
+                105.690727,
+                35.698643
+              ],
+              [
+                105.723988,
+                35.725854
+              ],
+              [
+                105.740618,
+                35.698643
+              ],
+              [
+                105.759097,
+                35.724883
+              ],
+              [
+                105.70243,
+                35.733142
+              ],
+              [
+                105.667322,
+                35.749657
+              ],
+              [
+                105.595873,
+                35.715651
+              ],
+              [
+                105.481924,
+                35.727312
+              ],
+              [
+                105.457286,
+                35.771511
+              ],
+              [
+                105.432033,
+                35.787533
+              ],
+              [
+                105.428953,
+                35.819082
+              ],
+              [
+                105.408627,
+                35.822479
+              ],
+              [
+                105.38091,
+                35.792873
+              ],
+              [
+                105.371055,
+                35.844312
+              ],
+              [
+                105.39754,
+                35.857409
+              ],
+              [
+                105.350113,
+                35.875839
+              ],
+              [
+                105.324859,
+                35.941761
+              ],
+              [
+                105.343954,
+                36.033767
+              ],
+              [
+                105.406163,
+                36.074409
+              ],
+              [
+                105.430801,
+                36.10391
+              ],
+              [
+                105.491163,
+                36.101009
+              ],
+              [
+                105.515185,
+                36.147415
+              ],
+              [
+                105.478844,
+                36.213111
+              ],
+              [
+                105.460366,
+                36.223733
+              ],
+              [
+                105.45975,
+                36.268137
+              ],
+              [
+                105.476381,
+                36.293224
+              ],
+              [
+                105.455439,
+                36.321678
+              ],
+              [
+                105.425873,
+                36.330357
+              ],
+              [
+                105.401236,
+                36.369881
+              ],
+              [
+                105.398156,
+                36.430575
+              ],
+              [
+                105.363048,
+                36.443093
+              ],
+              [
+                105.362432,
+                36.496514
+              ],
+              [
+                105.322396,
+                36.535954
+              ],
+              [
+                105.281744,
+                36.522489
+              ],
+              [
+                105.252179,
+                36.553263
+              ],
+              [
+                105.2762,
+                36.563358
+              ],
+              [
+                105.261418,
+                36.602764
+              ],
+              [
+                105.22015,
+                36.631105
+              ],
+              [
+                105.225693,
+                36.664716
+              ],
+              [
+                105.201056,
+                36.700711
+              ],
+              [
+                105.218302,
+                36.730455
+              ],
+              [
+                105.272505,
+                36.739567
+              ],
+              [
+                105.275584,
+                36.752515
+              ],
+              [
+                105.319932,
+                36.742924
+              ],
+              [
+                105.340874,
+                36.764502
+              ],
+              [
+                105.334714,
+                36.80093
+              ],
+              [
+                105.303302,
+                36.820575
+              ],
+              [
+                105.279896,
+                36.86751
+              ],
+              [
+                105.244787,
+                36.894796
+              ],
+              [
+                105.178882,
+                36.892403
+              ],
+              [
+                105.185657,
+                36.942164
+              ],
+              [
+                105.165331,
+                36.99476
+              ],
+              [
+                105.128991,
+                36.996194
+              ],
+              [
+                105.05939,
+                37.022956
+              ],
+              [
+                105.03968,
+                37.007187
+              ],
+              [
+                105.004571,
+                37.035378
+              ],
+              [
+                104.95468,
+                37.040156
+              ],
+              [
+                104.954064,
+                37.077407
+              ],
+              [
+                104.914644,
+                37.097935
+              ],
+              [
+                104.888158,
+                37.15901
+              ],
+              [
+                104.864753,
+                37.17284
+              ],
+              [
+                104.85613,
+                37.211933
+              ],
+              [
+                104.776673,
+                37.246718
+              ],
+              [
+                104.717543,
+                37.208597
+              ],
+              [
+                104.638087,
+                37.201923
+              ],
+              [
+                104.600515,
+                37.242907
+              ],
+              [
+                104.624536,
+                37.298627
+              ],
+              [
+                104.651022,
+                37.290534
+              ],
+              [
+                104.673812,
+                37.317668
+              ],
+              [
+                104.713848,
+                37.329566
+              ],
+              [
+                104.662109,
+                37.367626
+              ],
+              [
+                104.679971,
+                37.408044
+              ],
+              [
+                104.521059,
+                37.43466
+              ],
+              [
+                104.499501,
+                37.421353
+              ],
+              [
+                104.448994,
+                37.42468
+              ],
+              [
+                104.437907,
+                37.445589
+              ],
+              [
+                104.365226,
+                37.418026
+              ],
+              [
+                104.298705,
+                37.414223
+              ],
+              [
+                104.287002,
+                37.428007
+              ],
+              [
+                104.237727,
+                37.411847
+              ],
+              [
+                104.183524,
+                37.406618
+              ],
+              [
+                104.089285,
+                37.465067
+              ],
+              [
+                103.935916,
+                37.572818
+              ],
+              [
+                103.874938,
+                37.604117
+              ],
+              [
+                103.841062,
+                37.64725
+              ],
+              [
+                103.683381,
+                37.777919
+              ],
+              [
+                103.627947,
+                37.797783
+              ],
+              [
+                103.40744,
+                37.860651
+              ],
+              [
+                103.362477,
+                38.037621
+              ],
+              [
+                103.368636,
+                38.08898
+              ],
+              [
+                103.53494,
+                38.156776
+              ],
+              [
+                103.507838,
+                38.280905
+              ],
+              [
+                103.465339,
+                38.353215
+              ],
+              [
+                103.416063,
+                38.404821
+              ],
+              [
+                103.85954,
+                38.64454
+              ],
+              [
+                104.011677,
+                38.85923
+              ],
+              [
+                104.044322,
+                38.895105
+              ],
+              [
+                104.173053,
+                38.94446
+              ],
+              [
+                104.196459,
+                38.9882
+              ],
+              [
+                104.190915,
+                39.042139
+              ],
+              [
+                104.207546,
+                39.083495
+              ],
+              [
+                104.171205,
+                39.160567
+              ],
+              [
+                104.047401,
+                39.297788
+              ],
+              [
+                104.073271,
+                39.351953
+              ],
+              [
+                104.089901,
+                39.419947
+              ],
+              [
+                103.955626,
+                39.456923
+              ],
+              [
+                103.85338,
+                39.461543
+              ],
+              [
+                103.728961,
+                39.430117
+              ],
+              [
+                103.595302,
+                39.386652
+              ],
+              [
+                103.428998,
+                39.353341
+              ],
+              [
+                103.344615,
+                39.331588
+              ],
+              [
+                103.259615,
+                39.263971
+              ],
+              [
+                103.188166,
+                39.215302
+              ],
+              [
+                103.133347,
+                39.192579
+              ],
+              [
+                103.007696,
+                39.099753
+              ],
+              [
+                102.883892,
+                39.120649
+              ],
+              [
+                102.616574,
+                39.171703
+              ],
+              [
+                102.579002,
+                39.183301
+              ],
+              [
+                102.45335,
+                39.255167
+              ],
+              [
+                102.3548,
+                39.231993
+              ],
+              [
+                102.276576,
+                39.188868
+              ],
+              [
+                102.050526,
+                39.141075
+              ],
+              [
+                102.012338,
+                39.127149
+              ],
+              [
+                101.902701,
+                39.111827
+              ],
+              [
+                101.833715,
+                39.08907
+              ],
+              [
+                101.926106,
+                39.000758
+              ],
+              [
+                101.955055,
+                38.985874
+              ],
+              [
+                102.045599,
+                38.904885
+              ],
+              [
+                102.075164,
+                38.891378
+              ],
+              [
+                101.941505,
+                38.808883
+              ],
+              [
+                101.873751,
+                38.733761
+              ],
+              [
+                101.777049,
+                38.66043
+              ],
+              [
+                101.672955,
+                38.6908
+              ],
+              [
+                101.601506,
+                38.65529
+              ],
+              [
+                101.562702,
+                38.713218
+              ],
+              [
+                101.412413,
+                38.764099
+              ],
+              [
+                101.331109,
+                38.777164
+              ],
+              [
+                101.307087,
+                38.80282
+              ],
+              [
+                101.34158,
+                38.822406
+              ],
+              [
+                101.33542,
+                38.847113
+              ],
+              [
+                101.24303,
+                38.860628
+              ],
+              [
+                101.237486,
+                38.907214
+              ],
+              [
+                101.198682,
+                38.943064
+              ],
+              [
+                101.228863,
+                39.020754
+              ],
+              [
+                101.117378,
+                38.975174
+              ],
+              [
+                100.969553,
+                38.946788
+              ],
+              [
+                100.961545,
+                39.005874
+              ],
+              [
+                100.901799,
+                39.030053
+              ],
+              [
+                100.875314,
+                39.002619
+              ],
+              [
+                100.835278,
+                39.025869
+              ],
+              [
+                100.829118,
+                39.075133
+              ],
+              [
+                100.864227,
+                39.106719
+              ],
+              [
+                100.842669,
+                39.199999
+              ],
+              [
+                100.842053,
+                39.405614
+              ],
+              [
+                100.707778,
+                39.404689
+              ],
+              [
+                100.606764,
+                39.387577
+              ],
+              [
+                100.498975,
+                39.400527
+              ],
+              [
+                100.500823,
+                39.481408
+              ],
+              [
+                100.44354,
+                39.485565
+              ],
+              [
+                100.326512,
+                39.509118
+              ],
+              [
+                100.301258,
+                39.572345
+              ],
+              [
+                100.314193,
+                39.606935
+              ],
+              [
+                100.250135,
+                39.685274
+              ],
+              [
+                100.128179,
+                39.702312
+              ],
+              [
+                100.040716,
+                39.757083
+              ],
+              [
+                99.958796,
+                39.769504
+              ],
+              [
+                99.904593,
+                39.785601
+              ],
+              [
+                99.822058,
+                39.860063
+              ],
+              [
+                99.672384,
+                39.888079
+              ],
+              [
+                99.469124,
+                39.875221
+              ],
+              [
+                99.440791,
+                39.885783
+              ],
+              [
+                99.459885,
+                39.898181
+              ],
+              [
+                99.491298,
+                39.884406
+              ],
+              [
+                99.533182,
+                39.891753
+              ],
+              [
+                99.714268,
+                39.972061
+              ],
+              [
+                99.751225,
+                40.006909
+              ],
+              [
+                99.841152,
+                40.013326
+              ],
+              [
+                99.927383,
+                40.063727
+              ],
+              [
+                99.955716,
+                40.150695
+              ],
+              [
+                100.007455,
+                40.20008
+              ],
+              [
+                100.169447,
+                40.277743
+              ],
+              [
+                100.169447,
+                40.541131
+              ],
+              [
+                100.242744,
+                40.618855
+              ],
+              [
+                100.237201,
+                40.716905
+              ],
+              [
+                100.224882,
+                40.727337
+              ],
+              [
+                100.107853,
+                40.875475
+              ],
+              [
+                100.057346,
+                40.908049
+              ],
+              [
+                99.985897,
+                40.909858
+              ],
+              [
+                99.673,
+                40.93292
+              ],
+              [
+                99.565827,
+                40.846961
+              ],
+              [
+                99.174705,
+                40.858278
+              ],
+              [
+                99.172858,
+                40.747289
+              ],
+              [
+                99.12543,
+                40.715091
+              ],
+              [
+                99.102025,
+                40.676522
+              ],
+              [
+                99.041662,
+                40.693767
+              ],
+              [
+                98.984996,
+                40.782644
+              ],
+              [
+                98.790975,
+                40.705564
+              ],
+              [
+                98.80699,
+                40.660181
+              ],
+              [
+                98.802678,
+                40.607043
+              ],
+              [
+                98.762642,
+                40.639748
+              ],
+              [
+                98.72199,
+                40.657911
+              ],
+              [
+                98.689345,
+                40.691952
+              ],
+              [
+                98.668403,
+                40.773128
+              ],
+              [
+                98.569853,
+                40.746836
+              ],
+              [
+                98.627751,
+                40.677884
+              ],
+              [
+                98.344419,
+                40.568413
+              ],
+              [
+                98.333332,
+                40.918903
+              ],
+              [
+                98.25018,
+                40.93925
+              ],
+              [
+                98.184891,
+                40.988056
+              ],
+              [
+                98.142391,
+                41.001607
+              ],
+              [
+                97.971776,
+                41.09774
+              ],
+              [
+                97.903407,
+                41.168057
+              ],
+              [
+                97.629314,
+                41.440498
+              ],
+              [
+                97.613915,
+                41.477276
+              ],
+              [
+                97.84674,
+                41.656379
+              ],
+              [
+                97.653335,
+                41.986856
+              ],
+              [
+                97.500582,
+                42.243894
+              ],
+              [
+                97.371235,
+                42.457076
+              ],
+              [
+                97.172903,
+                42.795257
+              ],
+              [
+                96.968411,
+                42.756161
+              ],
+              [
+                96.742361,
+                42.75704
+              ],
+              [
+                96.386348,
+                42.727592
+              ],
+              [
+                96.166458,
+                42.623314
+              ],
+              [
+                96.103632,
+                42.604375
+              ],
+              [
+                96.072219,
+                42.569566
+              ],
+              [
+                96.02356,
+                42.542675
+              ],
+              [
+                96.0174,
+                42.482239
+              ],
+              [
+                95.978596,
+                42.436762
+              ],
+              [
+                96.06606,
+                42.414674
+              ],
+              [
+                96.042038,
+                42.352787
+              ],
+              [
+                96.040806,
+                42.326688
+              ],
+              [
+                96.178161,
+                42.21775
+              ],
+              [
+                96.077147,
+                42.149457
+              ],
+              [
+                96.13874,
+                42.05399
+              ],
+              [
+                96.137509,
+                42.019765
+              ],
+              [
+                96.117183,
+                41.985966
+              ],
+              [
+                96.054973,
+                41.936124
+              ],
+              [
+                95.998306,
+                41.906289
+              ],
+              [
+                95.855408,
+                41.849699
+              ],
+              [
+                95.801206,
+                41.848361
+              ],
+              [
+                95.759322,
+                41.835878
+              ],
+              [
+                95.65646,
+                41.826067
+              ],
+              [
+                95.57146,
+                41.796181
+              ],
+              [
+                95.445193,
+                41.719841
+              ],
+              [
+                95.39407,
+                41.693481
+              ],
+              [
+                95.335556,
+                41.644305
+              ],
+              [
+                95.299831,
+                41.565994
+              ],
+              [
+                95.247476,
+                41.61344
+              ],
+              [
+                95.194505,
+                41.694821
+              ],
+              [
+                95.199433,
+                41.719395
+              ],
+              [
+                95.16494,
+                41.735474
+              ],
+              [
+                95.135991,
+                41.772976
+              ],
+              [
+                95.110738,
+                41.768513
+              ],
+              [
+                95.011572,
+                41.726541
+              ],
+              [
+                94.969072,
+                41.718948
+              ],
+              [
+                94.861898,
+                41.668451
+              ],
+              [
+                94.809543,
+                41.619256
+              ],
+              [
+                94.750413,
+                41.538227
+              ],
+              [
+                94.534219,
+                41.505966
+              ],
+              [
+                94.184365,
+                41.268444
+              ],
+              [
+                94.01067,
+                41.114875
+              ],
+              [
+                93.908424,
+                40.983539
+              ],
+              [
+                93.809874,
+                40.879548
+              ],
+              [
+                93.820961,
+                40.793519
+              ],
+              [
+                93.760599,
+                40.664721
+              ],
+              [
+                93.506216,
+                40.648376
+              ],
+              [
+                92.928465,
+                40.572504
+              ],
+              [
+                92.920458,
+                40.391792
+              ],
+              [
+                92.906907,
+                40.310609
+              ],
+              [
+                92.796654,
+                40.153897
+              ],
+              [
+                92.745531,
+                39.868331
+              ],
+              [
+                92.687632,
+                39.657174
+              ],
+              [
+                92.639589,
+                39.514196
+              ],
+              [
+                92.52564,
+                39.368611
+              ],
+              [
+                92.378431,
+                39.258411
+              ],
+              [
+                92.339011,
+                39.236628
+              ],
+              [
+                92.343938,
+                39.146181
+              ],
+              [
+                92.366112,
+                39.096037
+              ],
+              [
+                92.366728,
+                39.059335
+              ],
+              [
+                92.41046,
+                39.03842
+              ],
+              [
+                92.459119,
+                39.042604
+              ],
+              [
+                92.459119,
+                39.063982
+              ],
+              [
+                92.489916,
+                39.099753
+              ],
+              [
+                92.545966,
+                39.111362
+              ],
+              [
+                92.659299,
+                39.109969
+              ],
+              [
+                92.765857,
+                39.136898
+              ],
+              [
+                92.866871,
+                39.138754
+              ],
+              [
+                92.889045,
+                39.160103
+              ],
+              [
+                92.938936,
+                39.169848
+              ],
+              [
+                92.978356,
+                39.143396
+              ],
+              [
+                93.043029,
+                39.146645
+              ],
+              [
+                93.115094,
+                39.17959
+              ],
+              [
+                93.142196,
+                39.160567
+              ],
+              [
+                93.131725,
+                39.108112
+              ],
+              [
+                93.165601,
+                39.090928
+              ],
+              [
+                93.198246,
+                39.045857
+              ],
+              [
+                93.179152,
+                38.923977
+              ],
+              [
+                93.237666,
+                38.916062
+              ],
+              [
+                93.274007,
+                38.896036
+              ],
+              [
+                93.453245,
+                38.915596
+              ],
+              [
+                93.729186,
+                38.924443
+              ],
+              [
+                93.834511,
+                38.867618
+              ],
+              [
+                93.884403,
+                38.867618
+              ],
+              [
+                93.884403,
+                38.826136
+              ],
+              [
+                93.769838,
+                38.821007
+              ],
+              [
+                93.756287,
+                38.807484
+              ],
+              [
+                93.773533,
+                38.771099
+              ],
+              [
+                93.800019,
+                38.750566
+              ],
+              [
+                93.885018,
+                38.720689
+              ],
+              [
+                93.95154,
+                38.715086
+              ],
+              [
+                93.973098,
+                38.724891
+              ],
+              [
+                94.281067,
+                38.7599
+              ],
+              [
+                94.370379,
+                38.7627
+              ],
+              [
+                94.511429,
+                38.445142
+              ],
+              [
+                94.527443,
+                38.425922
+              ],
+              [
+                94.527443,
+                38.365416
+              ],
+              [
+                94.56132,
+                38.351807
+              ],
+              [
+                94.582878,
+                38.36917
+              ],
+              [
+                94.672805,
+                38.386998
+              ],
+              [
+                94.812623,
+                38.385591
+              ],
+              [
+                94.861282,
+                38.393565
+              ],
+              [
+                94.884072,
+                38.414669
+              ],
+              [
+                94.973999,
+                38.430142
+              ],
+              [
+                95.045448,
+                38.418889
+              ],
+              [
+                95.072549,
+                38.402476
+              ],
+              [
+                95.122441,
+                38.417014
+              ],
+              [
+                95.140919,
+                38.392158
+              ],
+              [
+                95.185266,
+                38.379492
+              ],
+              [
+                95.209904,
+                38.327868
+              ],
+              [
+                95.229614,
+                38.330685
+              ],
+              [
+                95.259179,
+                38.302981
+              ],
+              [
+                95.315846,
+                38.318947
+              ],
+              [
+                95.408236,
+                38.300163
+              ],
+              [
+                95.440881,
+                38.310965
+              ],
+              [
+                95.455664,
+                38.291709
+              ],
+              [
+                95.487693,
+                38.314721
+              ],
+              [
+                95.51849,
+                38.294997
+              ],
+              [
+                95.585011,
+                38.343359
+              ],
+              [
+                95.608417,
+                38.339134
+              ],
+              [
+                95.671858,
+                38.388405
+              ],
+              [
+                95.703887,
+                38.400131
+              ],
+              [
+                95.723597,
+                38.378554
+              ],
+              [
+                95.775952,
+                38.356031
+              ],
+              [
+                95.83693,
+                38.344298
+              ],
+              [
+                95.852945,
+                38.287481
+              ],
+              [
+                95.89606,
+                38.2903
+              ],
+              [
+                95.932401,
+                38.259291
+              ],
+              [
+                95.93856,
+                38.237202
+              ],
+              [
+                96.006929,
+                38.207582
+              ],
+              [
+                96.06606,
+                38.173245
+              ],
+              [
+                96.109175,
+                38.187358
+              ],
+              [
+                96.221892,
+                38.149246
+              ],
+              [
+                96.252689,
+                38.167599
+              ],
+              [
+                96.264392,
+                38.145952
+              ],
+              [
+                96.313051,
+                38.161952
+              ],
+              [
+                96.301964,
+                38.183124
+              ],
+              [
+                96.335841,
+                38.246132
+              ],
+              [
+                96.378341,
+                38.277146
+              ],
+              [
+                96.46334,
+                38.277616
+              ],
+              [
+                96.665369,
+                38.23015
+              ],
+              [
+                96.655514,
+                38.295936
+              ],
+              [
+                96.638883,
+                38.307208
+              ],
+              [
+                96.626564,
+                38.356031
+              ],
+              [
+                96.698013,
+                38.422172
+              ],
+              [
+                96.707868,
+                38.459203
+              ],
+              [
+                96.6666,
+                38.483567
+              ],
+              [
+                96.706637,
+                38.505582
+              ],
+              [
+                96.780549,
+                38.504177
+              ],
+              [
+                96.800259,
+                38.52759
+              ],
+              [
+                96.767614,
+                38.552399
+              ],
+              [
+                96.808882,
+                38.582346
+              ],
+              [
+                96.7941,
+                38.608072
+              ],
+              [
+                96.847071,
+                38.599186
+              ],
+              [
+                96.876636,
+                38.580475
+              ],
+              [
+                96.961019,
+                38.558015
+              ],
+              [
+                97.055874,
+                38.594508
+              ],
+              [
+                97.047251,
+                38.653888
+              ],
+              [
+                97.057722,
+                38.67258
+              ],
+              [
+                97.009063,
+                38.702477
+              ],
+              [
+                97.023229,
+                38.755699
+              ],
+              [
+                97.00044,
+                38.7613
+              ],
+              [
+                96.987505,
+                38.793025
+              ],
+              [
+                96.993664,
+                38.834993
+              ],
+              [
+                96.983809,
+                38.869016
+              ],
+              [
+                96.940693,
+                38.90768
+              ],
+              [
+                96.938846,
+                38.95563
+              ],
+              [
+                96.965331,
+                39.017034
+              ],
+              [
+                96.95794,
+                39.041674
+              ],
+              [
+                96.969643,
+                39.097895
+              ],
+              [
+                97.012142,
+                39.142004
+              ],
+              [
+                96.962251,
+                39.198144
+              ],
+              [
+                97.017686,
+                39.208347
+              ],
+              [
+                97.060186,
+                39.19768
+              ],
+              [
+                97.14149,
+                39.199999
+              ],
+              [
+                97.220946,
+                39.193042
+              ],
+              [
+                97.315185,
+                39.164744
+              ],
+              [
+                97.347213,
+                39.167528
+              ],
+              [
+                97.371235,
+                39.140611
+              ],
+              [
+                97.401416,
+                39.146645
+              ],
+              [
+                97.458698,
+                39.117863
+              ],
+              [
+                97.504894,
+                39.076527
+              ],
+              [
+                97.58127,
+                39.052364
+              ],
+              [
+                97.679205,
+                39.010524
+              ],
+              [
+                97.701379,
+                38.963076
+              ],
+              [
+                97.828878,
+                38.93003
+              ],
+              [
+                97.875689,
+                38.898365
+              ],
+              [
+                98.009348,
+                38.85923
+              ],
+              [
+                98.029058,
+                38.834061
+              ],
+              [
+                98.068478,
+                38.816344
+              ],
+              [
+                98.091884,
+                38.786495
+              ],
+              [
+                98.167645,
+                38.840121
+              ],
+              [
+                98.242173,
+                38.880664
+              ],
+              [
+                98.235398,
+                38.918855
+              ],
+              [
+                98.276666,
+                38.963541
+              ],
+              [
+                98.287753,
+                38.992386
+              ],
+              [
+                98.280977,
+                39.027263
+              ],
+              [
+                98.316702,
+                39.040744
+              ],
+              [
+                98.383839,
+                39.029588
+              ],
+              [
+                98.401086,
+                39.001688
+              ],
+              [
+                98.432498,
+                38.996107
+              ],
+              [
+                98.428187,
+                38.976104
+              ],
+              [
+                98.457752,
+                38.952838
+              ],
+              [
+                98.526737,
+                38.95563
+              ],
+              [
+                98.584635,
+                38.93003
+              ],
+              [
+                98.624056,
+                38.959353
+              ],
+              [
+                98.612353,
+                38.977035
+              ],
+              [
+                98.661628,
+                38.993782
+              ],
+              [
+                98.70536,
+                39.043533
+              ],
+              [
+                98.730613,
+                39.057011
+              ],
+              [
+                98.743548,
+                39.086747
+              ],
+              [
+                98.816845,
+                39.085818
+              ],
+              [
+                98.818076,
+                39.064911
+              ],
+              [
+                98.886446,
+                39.040744
+              ],
+              [
+                98.903076,
+                39.012384
+              ],
+              [
+                98.951735,
+                38.987735
+              ],
+              [
+                99.054597,
+                38.97657
+              ],
+              [
+                99.107568,
+                38.951907
+              ],
+              [
+                99.071843,
+                38.921184
+              ],
+              [
+                99.068764,
+                38.896968
+              ],
+              [
+                99.141445,
+                38.852706
+              ],
+              [
+                99.222133,
+                38.788827
+              ],
+              [
+                99.291118,
+                38.765966
+              ],
+              [
+                99.361951,
+                38.718354
+              ],
+              [
+                99.375502,
+                38.684727
+              ],
+              [
+                99.412458,
+                38.665571
+              ],
+              [
+                99.450646,
+                38.60433
+              ],
+              [
+                99.501769,
+                38.612281
+              ],
+              [
+                99.52887,
+                38.546314
+              ],
+              [
+                99.585537,
+                38.498556
+              ],
+              [
+                99.63974,
+                38.474666
+              ],
+              [
+                99.65945,
+                38.449361
+              ],
+              [
+                99.727203,
+                38.415607
+              ],
+              [
+                99.758,
+                38.410449
+              ],
+              [
+                99.826985,
+                38.370109
+              ],
+              [
+                99.960028,
+                38.320825
+              ],
+              [
+                100.001912,
+                38.315191
+              ],
+              [
+                100.049955,
+                38.283254
+              ],
+              [
+                100.071513,
+                38.284663
+              ],
+              [
+                100.117093,
+                38.253652
+              ],
+              [
+                100.126332,
+                38.231561
+              ],
+              [
+                100.182998,
+                38.222158
+              ],
+              [
+                100.159592,
+                38.291239
+              ],
+              [
+                100.163904,
+                38.328337
+              ],
+              [
+                100.136803,
+                38.33444
+              ],
+              [
+                100.093071,
+                38.407166
+              ],
+              [
+                100.022238,
+                38.432017
+              ],
+              [
+                100.001296,
+                38.467169
+              ],
+              [
+                100.025933,
+                38.507923
+              ],
+              [
+                100.064122,
+                38.518694
+              ],
+              [
+                100.086911,
+                38.492936
+              ],
+              [
+                100.113397,
+                38.497151
+              ],
+              [
+                100.163288,
+                38.461546
+              ],
+              [
+                100.24028,
+                38.441861
+              ],
+              [
+                100.259374,
+                38.366355
+              ],
+              [
+                100.301874,
+                38.388405
+              ],
+              [
+                100.331439,
+                38.337257
+              ],
+              [
+                100.318505,
+                38.329276
+              ],
+              [
+                100.396729,
+                38.293118
+              ],
+              [
+                100.424446,
+                38.307208
+              ],
+              [
+                100.432453,
+                38.275267
+              ],
+              [
+                100.459555,
+                38.2654
+              ],
+              [
+                100.474953,
+                38.288891
+              ],
+              [
+                100.516837,
+                38.272448
+              ],
+              [
+                100.545786,
+                38.247072
+              ],
+              [
+                100.595061,
+                38.242372
+              ],
+              [
+                100.619083,
+                38.26587
+              ],
+              [
+                100.71517,
+                38.253652
+              ],
+              [
+                100.752126,
+                38.238612
+              ],
+              [
+                100.825423,
+                38.158658
+              ],
+              [
+                100.860531,
+                38.148305
+              ],
+              [
+                100.913502,
+                38.17889
+              ],
+              [
+                100.93814,
+                38.16007
+              ],
+              [
+                100.91843,
+                38.129006
+              ],
+              [
+                100.922125,
+                38.084741
+              ],
+              [
+                100.888864,
+                38.056001
+              ],
+              [
+                100.895024,
+                38.013107
+              ],
+              [
+                100.91843,
+                37.999432
+              ],
+              [
+                100.964009,
+                38.011221
+              ],
+              [
+                101.077342,
+                37.941874
+              ],
+              [
+                101.103211,
+                37.946593
+              ],
+              [
+                101.114298,
+                37.92016
+              ],
+              [
+                101.152486,
+                37.891356
+              ],
+              [
+                101.159262,
+                37.86821
+              ],
+              [
+                101.202994,
+                37.84742
+              ],
+              [
+                101.276906,
+                37.83655
+              ],
+              [
+                101.362522,
+                37.791162
+              ],
+              [
+                101.382848,
+                37.822369
+              ],
+              [
+                101.459224,
+                37.86632
+              ],
+              [
+                101.551615,
+                37.835604
+              ],
+              [
+                101.598427,
+                37.827569
+              ],
+              [
+                101.670491,
+                37.754264
+              ],
+              [
+                101.659405,
+                37.733441
+              ],
+              [
+                101.791832,
+                37.696041
+              ],
+              [
+                101.815853,
+                37.654357
+              ],
+              [
+                101.854657,
+                37.664781
+              ],
+              [
+                101.873135,
+                37.686569
+              ],
+              [
+                101.946432,
+                37.728235
+              ],
+              [
+                101.998787,
+                37.724921
+              ],
+              [
+                102.036359,
+                37.685149
+              ],
+              [
+                102.048678,
+                37.651515
+              ],
+              [
+                102.035128,
+                37.627819
+              ],
+              [
+                102.102265,
+                37.582304
+              ],
+              [
+                102.131214,
+                37.54625
+              ],
+              [
+                102.103497,
+                37.482641
+              ],
+              [
+                102.125055,
+                37.48549
+              ],
+              [
+                102.176794,
+                37.458892
+              ],
+              [
+                102.19712,
+                37.420403
+              ],
+              [
+                102.299981,
+                37.391404
+              ],
+              [
+                102.29875,
+                37.370004
+              ],
+              [
+                102.368351,
+                37.327662
+              ],
+              [
+                102.428097,
+                37.308624
+              ],
+              [
+                102.419474,
+                37.294343
+              ],
+              [
+                102.45335,
+                37.271487
+              ],
+              [
+                102.457662,
+                37.248147
+              ],
+              [
+                102.490307,
+                37.223371
+              ],
+              [
+                102.533422,
+                37.217176
+              ],
+              [
+                102.578386,
+                37.17284
+              ],
+              [
+                102.599944,
+                37.174748
+              ],
+              [
+                102.642444,
+                37.099845
+              ],
+              [
+                102.583314,
+                37.104618
+              ],
+              [
+                102.488459,
+                37.078362
+              ],
+              [
+                102.506321,
+                37.019134
+              ],
+              [
+                102.450271,
+                36.968467
+              ],
+              [
+                102.499546,
+                36.954599
+              ],
+              [
+                102.526031,
+                36.928291
+              ],
+              [
+                102.56114,
+                36.91968
+              ],
+              [
+                102.587009,
+                36.869904
+              ],
+              [
+                102.639364,
+                36.852666
+              ],
+              [
+                102.720052,
+                36.767858
+              ],
+              [
+                102.692335,
+                36.775528
+              ],
+              [
+                102.639364,
+                36.732853
+              ],
+              [
+                102.612879,
+                36.738129
+              ],
+              [
+                102.601176,
+                36.710307
+              ],
+              [
+                102.630741,
+                36.650793
+              ],
+              [
+                102.684328,
+                36.619097
+              ],
+              [
+                102.724364,
+                36.613813
+              ],
+              [
+                102.714509,
+                36.599401
+              ],
+              [
+                102.761936,
+                36.568645
+              ],
+              [
+                102.734219,
+                36.562396
+              ],
+              [
+                102.753313,
+                36.525855
+              ],
+              [
+                102.793349,
+                36.497957
+              ],
+              [
+                102.771791,
+                36.47438
+              ],
+              [
+                102.829689,
+                36.365544
+              ],
+              [
+                102.831537,
+                36.365544
+              ],
+              [
+                102.838928,
+                36.345783
+              ],
+              [
+                102.836465,
+                36.344819
+              ],
+              [
+                102.845704,
+                36.331803
+              ],
+              [
+                102.896827,
+                36.331803
+              ],
+              [
+                102.922696,
+                36.298047
+              ],
+              [
+                103.024942,
+                36.256556
+              ],
+              [
+                103.021246,
+                36.232906
+              ],
+              [
+                103.066826,
+                36.216974
+              ],
+              [
+                103.048964,
+                36.199107
+              ],
+              [
+                102.986754,
+                36.193312
+              ],
+              [
+                102.965812,
+                36.151765
+              ],
+              [
+                102.948566,
+                36.150798
+              ],
+              [
+                102.941174,
+                36.104877
+              ],
+              [
+                102.882044,
+                36.082632
+              ],
+              [
+                102.932551,
+                36.048285
+              ],
+              [
+                102.968276,
+                36.044414
+              ],
+              [
+                102.951645,
+                36.021667
+              ],
+              [
+                102.971971,
+                35.995525
+              ],
+              [
+                102.942406,
+                35.92674
+              ],
+              [
+                102.954725,
+                35.858864
+              ],
+              [
+                102.94487,
+                35.829757
+              ],
+              [
+                102.914073,
+                35.845282
+              ],
+              [
+                102.81737,
+                35.850133
+              ],
+              [
+                102.787189,
+                35.862745
+              ],
+              [
+                102.739146,
+                35.821023
+              ],
+              [
+                102.715125,
+                35.815685
+              ],
+              [
+                102.686175,
+                35.771996
+              ],
+              [
+                102.707733,
+                35.70496
+              ],
+              [
+                102.744074,
+                35.657807
+              ],
+              [
+                102.7644,
+                35.653431
+              ],
+              [
+                102.763168,
+                35.612086
+              ],
+              [
+                102.808747,
+                35.560496
+              ],
+              [
+                102.746537,
+                35.545403
+              ],
+              [
+                102.729291,
+                35.523487
+              ],
+              [
+                102.782878,
+                35.527871
+              ],
+              [
+                102.743458,
+                35.494745
+              ],
+              [
+                102.695414,
+                35.528358
+              ],
+              [
+                102.570995,
+                35.548324
+              ],
+              [
+                102.531575,
+                35.580455
+              ],
+              [
+                102.503241,
+                35.585322
+              ],
+              [
+                102.49893,
+                35.545403
+              ],
+              [
+                102.437952,
+                35.455268
+              ],
+              [
+                102.447807,
+                35.437229
+              ],
+              [
+                102.408387,
+                35.409431
+              ],
+              [
+                102.314764,
+                35.434303
+              ],
+              [
+                102.293822,
+                35.424063
+              ],
+              [
+                102.287663,
+                35.36552
+              ],
+              [
+                102.317844,
+                35.343067
+              ],
+              [
+                102.311684,
+                35.31426
+              ],
+              [
+                102.280887,
+                35.303028
+              ],
+              [
+                102.3123,
+                35.282512
+              ],
+              [
+                102.370199,
+                35.263946
+              ],
+              [
+                102.365887,
+                35.235599
+              ],
+              [
+                102.404075,
+                35.179366
+              ],
+              [
+                102.346793,
+                35.164201
+              ],
+              [
+                102.310452,
+                35.128967
+              ],
+              [
+                102.29567,
+                35.071681
+              ],
+              [
+                102.252554,
+                35.048657
+              ],
+              [
+                102.218062,
+                35.057475
+              ],
+              [
+                102.211286,
+                35.034937
+              ],
+              [
+                102.176178,
+                35.032977
+              ],
+              [
+                102.157699,
+                35.010923
+              ],
+              [
+                102.133678,
+                35.014844
+              ],
+              [
+                102.094874,
+                34.986901
+              ],
+              [
+                102.048062,
+                34.910868
+              ],
+              [
+                102.068388,
+                34.887798
+              ],
+              [
+                101.985852,
+                34.90007
+              ],
+              [
+                101.916867,
+                34.873561
+              ],
+              [
+                101.923027,
+                34.835746
+              ],
+              [
+                101.917483,
+                34.705964
+              ],
+              [
+                101.919947,
+                34.621791
+              ],
+              [
+                101.934729,
+                34.58731
+              ],
+              [
+                101.956287,
+                34.582876
+              ],
+              [
+                101.97415,
+                34.548871
+              ],
+              [
+                102.001867,
+                34.538519
+              ],
+              [
+                102.093026,
+                34.536547
+              ],
+              [
+                102.139837,
+                34.50351
+              ],
+              [
+                102.155852,
+                34.507456
+              ],
+              [
+                102.169402,
+                34.457631
+              ],
+              [
+                102.205743,
+                34.407777
+              ],
+              [
+                102.259329,
+                34.355917
+              ],
+              [
+                102.237156,
+                34.34307
+              ],
+              [
+                102.237156,
+                34.34307
+              ],
+              [
+                102.186649,
+                34.352952
+              ],
+              [
+                102.149692,
+                34.271885
+              ],
+              [
+                102.067772,
+                34.293642
+              ],
+              [
+                102.062229,
+                34.227858
+              ],
+              [
+                102.01357,
+                34.218456
+              ],
+              [
+                102.030816,
+                34.190739
+              ],
+              [
+                102.003099,
+                34.162022
+              ],
+              [
+                101.965526,
+                34.167469
+              ],
+              [
+                101.955055,
+                34.109514
+              ],
+              [
+                101.897773,
+                34.133791
+              ],
+              [
+                101.874367,
+                34.130323
+              ],
+              [
+                101.851578,
+                34.153108
+              ],
+              [
+                101.836795,
+                34.124378
+              ],
+              [
+                101.788136,
+                34.131809
+              ],
+              [
+                101.764114,
+                34.122892
+              ],
+              [
+                101.736397,
+                34.080275
+              ],
+              [
+                101.718535,
+                34.083249
+              ],
+              [
+                101.703136,
+                34.119424
+              ],
+              [
+                101.674187,
+                34.110506
+              ],
+              [
+                101.6206,
+                34.178857
+              ],
+              [
+                101.53868,
+                34.212022
+              ],
+              [
+                101.492485,
+                34.195689
+              ],
+              [
+                101.482014,
+                34.218951
+              ],
+              [
+                101.417956,
+                34.227858
+              ],
+              [
+                101.369913,
+                34.248143
+              ],
+              [
+                101.327413,
+                34.24468
+              ],
+              [
+                101.325565,
+                34.268423
+              ],
+              [
+                101.268899,
+                34.278808
+              ],
+              [
+                101.228863,
+                34.298586
+              ],
+              [
+                101.235022,
+                34.325279
+              ],
+              [
+                101.193754,
+                34.336646
+              ],
+              [
+                101.178356,
+                34.320831
+              ],
+              [
+                101.098284,
+                34.329233
+              ],
+              [
+                101.054552,
+                34.322808
+              ],
+              [
+                100.986799,
+                34.374689
+              ],
+              [
+                100.951074,
+                34.38358
+              ],
+              [
+                100.895024,
+                34.375183
+              ],
+              [
+                100.868538,
+                34.332693
+              ],
+              [
+                100.821727,
+                34.317371
+              ],
+              [
+                100.798321,
+                34.260014
+              ],
+              [
+                100.809408,
+                34.247153
+              ],
+              [
+                100.764445,
+                34.178857
+              ],
+              [
+                100.806329,
+                34.155584
+              ],
+              [
+                100.848828,
+                34.089692
+              ],
+              [
+                100.870386,
+                34.083744
+              ],
+              [
+                100.880857,
+                34.036644
+              ],
+              [
+                100.93506,
+                33.990013
+              ],
+              [
+                100.927669,
+                33.975126
+              ],
+              [
+                100.965857,
+                33.946832
+              ],
+              [
+                100.994806,
+                33.891707
+              ],
+              [
+                101.023139,
+                33.896178
+              ],
+              [
+                101.054552,
+                33.863386
+              ],
+              [
+                101.153718,
+                33.8445
+              ],
+              [
+                101.153102,
+                33.823124
+              ],
+              [
+                101.190675,
+                33.791796
+              ],
+              [
+                101.186363,
+                33.741051
+              ],
+              [
+                101.162957,
+                33.719649
+              ],
+              [
+                101.177124,
+                33.685295
+              ],
+              [
+                101.166653,
+                33.659894
+              ],
+              [
+                101.217776,
+                33.669856
+              ],
+              [
+                101.23687,
+                33.685793
+              ],
+              [
+                101.302776,
+                33.657902
+              ],
+              [
+                101.385312,
+                33.644949
+              ],
+              [
+                101.424732,
+                33.655411
+              ],
+              [
+                101.428427,
+                33.680315
+              ],
+              [
+                101.501724,
+                33.702723
+              ],
+              [
+                101.58426,
+                33.674339
+              ],
+              [
+                101.585492,
+                33.645448
+              ],
+              [
+                101.616905,
+                33.598603
+              ],
+              [
+                101.611977,
+                33.565199
+              ],
+              [
+                101.622448,
+                33.502343
+              ],
+              [
+                101.718535,
+                33.494857
+              ],
+              [
+                101.748716,
+                33.505337
+              ],
+              [
+                101.769042,
+                33.538765
+              ],
+              [
+                101.783208,
+                33.556721
+              ],
+              [
+                101.831252,
+                33.554726
+              ],
+              [
+                101.844186,
+                33.602591
+              ],
+              [
+                101.884222,
+                33.578163
+              ],
+              [
+                101.907012,
+                33.539264
+              ],
+              [
+                101.906396,
+                33.48188
+              ],
+              [
+                101.946432,
+                33.442937
+              ],
+              [
+                101.915635,
+                33.425957
+              ],
+              [
+                101.887302,
+                33.383991
+              ],
+              [
+                101.877447,
+                33.314502
+              ],
+              [
+                101.769658,
+                33.26898
+              ],
+              [
+                101.770274,
+                33.248962
+              ],
+              [
+                101.83002,
+                33.213921
+              ],
+              [
+                101.841723,
+                33.184876
+              ],
+              [
+                101.825708,
+                33.119239
+              ],
+              [
+                101.865744,
+                33.103198
+              ],
+              [
+                101.887302,
+                33.135778
+              ],
+              [
+                101.921795,
+                33.153817
+              ],
+              [
+                101.935345,
+                33.186879
+              ],
+              [
+                101.99386,
+                33.1999
+              ],
+              [
+                102.054838,
+                33.189884
+              ],
+              [
+                102.08933,
+                33.204908
+              ],
+              [
+                102.08933,
+                33.227439
+              ],
+              [
+                102.117047,
+                33.288492
+              ],
+              [
+                102.144765,
+                33.273983
+              ],
+              [
+                102.160163,
+                33.242956
+              ],
+              [
+                102.200815,
+                33.223434
+              ],
+              [
+                102.217446,
+                33.247961
+              ],
+              [
+                102.192192,
+                33.337005
+              ],
+              [
+                102.218062,
+                33.349503
+              ],
+              [
+                102.258098,
+                33.409472
+              ],
+              [
+                102.296286,
+                33.413969
+              ],
+              [
+                102.310452,
+                33.397982
+              ],
+              [
+                102.368967,
+                33.41247
+              ],
+              [
+                102.392988,
+                33.404477
+              ],
+              [
+                102.447807,
+                33.454922
+              ],
+              [
+                102.462589,
+                33.449429
+              ],
+              [
+                102.461358,
+                33.501345
+              ],
+              [
+                102.446575,
+                33.53228
+              ],
+              [
+                102.477988,
+                33.543254
+              ],
+              [
+                102.440416,
+                33.574673
+              ],
+              [
+                102.346793,
+                33.605582
+              ],
+              [
+                102.31538,
+                33.665374
+              ],
+              [
+                102.342481,
+                33.725622
+              ],
+              [
+                102.284583,
+                33.719151
+              ],
+              [
+                102.324619,
+                33.754486
+              ],
+              [
+                102.296286,
+                33.783838
+              ],
+              [
+                102.243315,
+                33.786823
+              ],
+              [
+                102.261177,
+                33.821136
+              ],
+              [
+                102.25317,
+                33.861399
+              ],
+              [
+                102.136142,
+                33.965199
+              ],
+              [
+                102.16817,
+                33.983066
+              ],
+              [
+                102.226069,
+                33.963214
+              ],
+              [
+                102.248858,
+                33.98654
+              ],
+              [
+                102.287047,
+                33.977607
+              ],
+              [
+                102.315996,
+                33.993983
+              ],
+              [
+                102.345561,
+                33.969666
+              ],
+              [
+                102.392372,
+                33.971651
+              ],
+              [
+                102.406539,
+                34.033172
+              ],
+              [
+                102.437336,
+                34.087214
+              ],
+              [
+                102.471213,
+                34.072839
+              ],
+              [
+                102.511865,
+                34.086222
+              ],
+              [
+                102.615958,
+                34.099604
+              ],
+              [
+                102.649219,
+                34.080275
+              ],
+              [
+                102.655994,
+                34.113478
+              ],
+              [
+                102.598712,
+                34.14766
+              ],
+              [
+                102.651067,
+                34.165983
+              ],
+              [
+                102.664002,
+                34.192719
+              ],
+              [
+                102.694799,
+                34.198659
+              ],
+              [
+                102.728675,
+                34.235774
+              ],
+              [
+                102.779798,
+                34.236764
+              ],
+              [
+                102.798276,
+                34.272874
+              ],
+              [
+                102.856791,
+                34.270895
+              ],
+              [
+                102.85987,
+                34.301058
+              ],
+              [
+                102.911609,
+                34.312923
+              ],
+              [
+                102.949181,
+                34.292159
+              ],
+              [
+                102.977515,
+                34.252595
+              ],
+              [
+                102.973203,
+                34.205588
+              ],
+              [
+                103.005848,
+                34.184798
+              ],
+              [
+                103.052043,
+                34.195194
+              ],
+              [
+                103.100087,
+                34.181828
+              ],
+              [
+                103.124108,
+                34.162022
+              ],
+              [
+                103.121644,
+                34.112487
+              ],
+              [
+                103.178927,
+                34.079779
+              ],
+              [
+                103.129652,
+                34.065899
+              ],
+              [
+                103.119797,
+                34.03466
+              ],
+              [
+                103.147514,
+                34.036644
+              ],
+              [
+                103.157369,
+                33.998944
+              ],
+              [
+                103.120413,
+                33.953286
+              ],
+              [
+                103.1315,
+                33.931937
+              ],
+              [
+                103.16476,
+                33.929454
+              ],
+              [
+                103.181391,
+                33.900649
+              ],
+              [
+                103.153673,
+                33.819147
+              ],
+              [
+                103.165376,
+                33.805721
+              ],
+              [
+                103.228202,
+                33.79478
+              ],
+              [
+                103.24976,
+                33.814175
+              ],
+              [
+                103.284868,
+                33.80224
+              ],
+              [
+                103.278709,
+                33.774387
+              ],
+              [
+                103.35447,
+                33.743539
+              ],
+              [
+                103.434542,
+                33.752993
+              ],
+              [
+                103.464723,
+                33.80224
+              ],
+              [
+                103.518309,
+                33.807213
+              ],
+              [
+                103.545411,
+                33.719649
+              ],
+              [
+                103.520157,
+                33.678323
+              ],
+              [
+                103.552186,
+                33.671351
+              ],
+              [
+                103.563889,
+                33.699735
+              ],
+              [
+                103.593454,
+                33.716164
+              ],
+              [
+                103.645809,
+                33.708697
+              ],
+              [
+                103.667983,
+                33.685793
+              ],
+              [
+                103.690772,
+                33.69376
+              ],
+              [
+                103.778236,
+                33.658898
+              ],
+              [
+                103.861388,
+                33.682307
+              ],
+              [
+                103.980264,
+                33.670852
+              ],
+              [
+                104.046169,
+                33.686291
+              ],
+              [
+                104.103452,
+                33.663381
+              ],
+              [
+                104.176749,
+                33.5996
+              ],
+              [
+                104.155191,
+                33.542755
+              ],
+              [
+                104.180444,
+                33.472895
+              ],
+              [
+                104.213089,
+                33.446932
+              ],
+              [
+                104.22048,
+                33.404477
+              ],
+              [
+                104.272219,
+                33.391486
+              ],
+              [
+                104.292545,
+                33.336505
+              ],
+              [
+                104.373849,
+                33.345004
+              ],
+              [
+                104.420045,
+                33.327004
+              ],
+              [
+                104.386168,
+                33.298497
+              ],
+              [
+                104.333813,
+                33.315502
+              ],
+              [
+                104.303632,
+                33.304499
+              ],
+              [
+                104.323958,
+                33.26898
+              ],
+              [
+                104.32827,
+                33.223934
+              ],
+              [
+                104.351059,
+                33.158828
+              ],
+              [
+                104.378161,
+                33.109214
+              ],
+              [
+                104.337509,
+                33.038002
+              ],
+              [
+                104.391711,
+                33.035493
+              ],
+              [
+                104.426204,
+                33.010906
+              ],
+              [
+                104.383704,
+                32.994343
+              ],
+              [
+                104.378161,
+                32.953174
+              ],
+              [
+                104.345516,
+                32.940117
+              ],
+              [
+                104.288234,
+                32.942628
+              ],
+              [
+                104.277147,
+                32.90244
+              ],
+              [
+                104.294393,
+                32.835586
+              ],
+              [
+                104.363994,
+                32.822511
+              ],
+              [
+                104.458849,
+                32.748551
+              ],
+              [
+                104.51182,
+                32.753585
+              ],
+              [
+                104.526602,
+                32.728416
+              ],
+              [
+                104.582653,
+                32.722374
+              ],
+              [
+                104.592508,
+                32.695685
+              ],
+              [
+                104.643015,
+                32.661935
+              ],
+              [
+                104.696601,
+                32.673522
+              ],
+              [
+                104.739717,
+                32.635228
+              ],
+              [
+                104.795768,
+                32.643292
+              ],
+              [
+                104.820405,
+                32.662943
+              ],
+              [
+                104.845659,
+                32.653873
+              ],
+              [
+                104.881999,
+                32.600951
+              ],
+              [
+                104.925115,
+                32.607505
+              ],
+              [
+                105.026745,
+                32.650346
+              ],
+              [
+                105.0791,
+                32.637244
+              ],
+              [
+                105.111128,
+                32.593893
+              ],
+              [
+                105.185041,
+                32.617587
+              ],
+              [
+                105.215222,
+                32.63674
+              ],
+              [
+                105.219534,
+                32.666469
+              ],
+              [
+                105.263265,
+                32.652362
+              ],
+              [
+                105.297758,
+                32.656897
+              ],
+              [
+                105.347033,
+                32.68259
+              ],
+              [
+                105.368591,
+                32.712807
+              ],
+              [
+                105.448663,
+                32.732946
+              ],
+              [
+                105.454207,
+                32.767173
+              ],
+              [
+                105.427721,
+                32.784281
+              ],
+              [
+                105.396308,
+                32.85067
+              ],
+              [
+                105.396308,
+                32.85067
+              ],
+              [
+                105.38091,
+                32.876307
+              ],
+              [
+                105.408011,
+                32.885857
+              ],
+              [
+                105.414171,
+                32.922034
+              ],
+              [
+                105.467757,
+                32.930071
+              ],
+              [
+                105.49917,
+                32.911986
+              ],
+              [
+                105.528119,
+                32.919019
+              ],
+              [
+                105.565692,
+                32.906962
+              ],
+              [
+                105.590329,
+                32.87681
+              ],
+              [
+                105.638373,
+                32.879323
+              ],
+              [
+                105.656851,
+                32.895405
+              ],
+              [
+                105.735691,
+                32.905454
+              ],
+              [
+                105.82685,
+                32.950663
+              ],
+              [
+                105.861959,
+                32.939112
+              ],
+              [
+                105.917393,
+                32.993841
+              ],
+              [
+                105.926632,
+                33.042517
+              ],
+              [
+                105.914929,
+                33.066092
+              ],
+              [
+                105.934639,
+                33.112221
+              ],
+              [
+                105.923552,
+                33.147805
+              ],
+              [
+                105.897067,
+                33.146803
+              ],
+              [
+                105.93156,
+                33.178365
+              ],
+              [
+                105.968516,
+                33.154318
+              ],
+              [
+                105.965436,
+                33.204407
+              ],
+              [
+                105.917393,
+                33.237951
+              ],
+              [
+                105.862574,
+                33.234447
+              ],
+              [
+                105.799133,
+                33.258471
+              ],
+              [
+                105.791741,
+                33.278486
+              ],
+              [
+                105.752937,
+                33.291994
+              ],
+              [
+                105.755401,
+                33.329004
+              ],
+              [
+                105.709822,
+                33.382991
+              ],
+              [
+                105.827466,
+                33.379993
+              ],
+              [
+                105.837937,
+                33.410971
+              ],
+              [
+                105.831162,
+                33.451926
+              ],
+              [
+                105.842248,
+                33.489866
+              ],
+              [
+                105.871198,
+                33.511325
+              ],
+              [
+                105.902611,
+                33.556222
+              ],
+              [
+                105.940183,
+                33.570684
+              ],
+              [
+                105.971596,
+                33.613058
+              ],
+              [
+                106.047356,
+                33.610067
+              ],
+              [
+                106.086776,
+                33.617045
+              ],
+              [
+                106.117573,
+                33.602591
+              ],
+              [
+                106.108334,
+                33.569686
+              ],
+              [
+                106.187174,
+                33.546746
+              ],
+              [
+                106.237681,
+                33.564201
+              ],
+              [
+                106.303587,
+                33.604585
+              ],
+              [
+                106.35163,
+                33.587137
+              ],
+              [
+                106.384891,
+                33.612061
+              ],
+              [
+                106.447101,
+                33.613058
+              ],
+              [
+                106.456956,
+                33.532779
+              ],
+              [
+                106.540108,
+                33.512822
+              ],
+              [
+                106.58076,
+                33.576169
+              ],
+              [
+                106.575832,
+                33.631497
+              ],
+              [
+                106.534564,
+                33.695254
+              ],
+              [
+                106.482825,
+                33.707203
+              ],
+              [
+                106.488369,
+                33.757969
+              ],
+              [
+                106.461883,
+                33.789807
+              ],
+              [
+                106.491448,
+                33.834559
+              ],
+              [
+                106.475434,
+                33.875809
+              ],
+              [
+                106.428007,
+                33.866368
+              ],
+              [
+                106.41076,
+                33.909093
+              ],
+              [
+                106.474202,
+                33.970659
+              ],
+              [
+                106.471738,
+                34.024244
+              ],
+              [
+                106.505615,
+                34.056479
+              ],
+              [
+                106.501919,
+                34.105055
+              ],
+              [
+                106.560434,
+                34.109514
+              ],
+              [
+                106.585071,
+                34.149641
+              ],
+              [
+                106.55797,
+                34.229837
+              ],
+              [
+                106.5321,
+                34.254079
+              ],
+              [
+                106.496376,
+                34.238248
+              ],
+              [
+                106.526557,
+                34.292159
+              ],
+              [
+                106.577064,
+                34.280786
+              ],
+              [
+                106.589383,
+                34.253584
+              ],
+              [
+                106.63373,
+                34.260014
+              ],
+              [
+                106.652825,
+                34.24369
+              ],
+              [
+                106.68239,
+                34.256057
+              ],
+              [
+                106.705179,
+                34.299575
+              ],
+              [
+                106.691013,
+                34.337635
+              ],
+              [
+                106.717498,
+                34.369255
+              ],
+              [
+                106.638042,
+                34.391481
+              ],
+              [
+                106.610941,
+                34.454177
+              ],
+              [
+                106.558586,
+                34.48822
+              ],
+              [
+                106.513622,
+                34.498085
+              ],
+              [
+                106.514238,
+                34.511894
+              ],
+              [
+                106.455108,
+                34.531617
+              ],
+              [
+                106.334384,
+                34.517811
+              ],
+              [
+                106.341159,
+                34.568093
+              ],
+              [
+                106.314058,
+                34.578934
+              ],
+              [
+                106.419384,
+                34.643458
+              ],
+              [
+                106.471122,
+                34.634102
+              ],
+              [
+                106.442173,
+                34.675455
+              ],
+              [
+                106.456956,
+                34.703996
+              ],
+              [
+                106.487137,
+                34.715311
+              ],
+              [
+                106.505615,
+                34.746789
+              ],
+              [
+                106.539492,
+                34.745805
+              ],
+              [
+                106.575216,
+                34.769897
+              ],
+              [
+                106.550579,
+                34.82936
+              ],
+              [
+                106.556122,
+                34.861285
+              ],
+              [
+                106.527789,
+                34.876507
+              ],
+              [
+                106.493296,
+                34.941289
+              ],
+              [
+                106.484673,
+                34.983959
+              ],
+              [
+                106.494528,
+                35.006021
+              ],
+              [
+                106.494528,
+                35.006021
+              ],
+              [
+                106.52163,
+                35.027587
+              ],
+              [
+                106.541956,
+                35.083925
+              ],
+              [
+                106.577064,
+                35.089312
+              ],
+              [
+                106.615252,
+                35.071191
+              ],
+              [
+                106.706411,
+                35.081966
+              ],
+              [
+                106.710723,
+                35.100574
+              ],
+              [
+                106.838222,
+                35.080007
+              ],
+              [
+                106.901664,
+                35.094698
+              ],
+              [
+                106.950323,
+                35.066782
+              ],
+              [
+                106.990975,
+                35.068252
+              ],
+              [
+                107.012533,
+                35.029547
+              ],
+              [
+                107.08275,
+                35.024156
+              ],
+              [
+                107.089526,
+                34.976604
+              ],
+              [
+                107.119707,
+                34.950119
+              ],
+              [
+                107.162206,
+                34.944233
+              ],
+              [
+                107.189308,
+                34.893198
+              ],
+              [
+                107.252749,
+                34.880925
+              ],
+              [
+                107.286626,
+                34.931968
+              ],
+              [
+                107.350068,
+                34.93393
+              ],
+              [
+                107.369162,
+                34.917738
+              ],
+              [
+                107.400575,
+                34.932949
+              ],
+              [
+                107.455394,
+                34.916757
+              ],
+              [
+                107.523763,
+                34.909886
+              ],
+              [
+                107.564415,
+                34.968757
+              ],
+              [
+                107.619849,
+                34.964834
+              ],
+              [
+                107.638943,
+                34.935402
+              ],
+              [
+                107.675284,
+                34.9511
+              ],
+              [
+                107.741805,
+                34.953553
+              ],
+              [
+                107.842203,
+                34.979056
+              ],
+              [
+                107.863145,
+                34.999158
+              ],
+              [
+                107.846515,
+                35.024646
+              ],
+              [
+                107.814486,
+                35.024646
+              ],
+              [
+                107.773218,
+                35.060904
+              ],
+              [
+                107.773218,
+                35.060904
+              ],
+              [
+                107.769523,
+                35.064333
+              ],
+              [
+                107.769523,
+                35.064333
+              ],
+              [
+                107.727639,
+                35.120157
+              ],
+              [
+                107.715936,
+                35.168114
+              ],
+              [
+                107.686371,
+                35.218
+              ],
+              [
+                107.652494,
+                35.244886
+              ],
+              [
+                107.667277,
+                35.257104
+              ],
+              [
+                107.737494,
+                35.267366
+              ],
+              [
+                107.745501,
+                35.311819
+              ],
+              [
+                107.841587,
+                35.276649
+              ],
+              [
+                107.867457,
+                35.256127
+              ],
+              [
+                107.960464,
+                35.263457
+              ],
+              [
+                107.949993,
+                35.245375
+              ],
+              [
+                108.049159,
+                35.253683
+              ],
+              [
+                108.094739,
+                35.280069
+              ],
+              [
+                108.174811,
+                35.304981
+              ],
+              [
+                108.221622,
+                35.296678
+              ],
+              [
+                108.239484,
+                35.256127
+              ],
+              [
+                108.296767,
+                35.267855
+              ],
+              [
+                108.345426,
+                35.300586
+              ],
+              [
+                108.36144,
+                35.279581
+              ],
+              [
+                108.48894,
+                35.275184
+              ],
+              [
+                108.547454,
+                35.304981
+              ],
+              [
+                108.583178,
+                35.294724
+              ],
+              [
+                108.614591,
+                35.328909
+              ],
+              [
+                108.61028,
+                35.355271
+              ],
+              [
+                108.631222,
+                35.418698
+              ],
+              [
+                108.605968,
+                35.503028
+              ],
+              [
+                108.625678,
+                35.537124
+              ],
+              [
+                108.618287,
+                35.557088
+              ],
+              [
+                108.539447,
+                35.605761
+              ],
+              [
+                108.517889,
+                35.699615
+              ],
+              [
+                108.533903,
+                35.746257
+              ],
+              [
+                108.527744,
+                35.82442
+              ],
+              [
+                108.499411,
+                35.872444
+              ],
+              [
+                108.518505,
+                35.905414
+              ],
+              [
+                108.562852,
+                35.921409
+              ],
+              [
+                108.593649,
+                35.950967
+              ],
+              [
+                108.652164,
+                35.94806
+              ],
+              [
+                108.659555,
+                35.990683
+              ],
+              [
+                108.688504,
+                36.021183
+              ],
+              [
+                108.682345,
+                36.062316
+              ],
+              [
+                108.712526,
+                36.138716
+              ],
+              [
+                108.646004,
+                36.254143
+              ],
+              [
+                108.641693,
+                36.359279
+              ],
+              [
+                108.651548,
+                36.384818
+              ],
+              [
+                108.618903,
+                36.433946
+              ],
+              [
+                108.562852,
+                36.43876
+              ],
+              [
+                108.510498,
+                36.47438
+              ],
+              [
+                108.514809,
+                36.445501
+              ],
+              [
+                108.495099,
+                36.422389
+              ],
+              [
+                108.460606,
+                36.422871
+              ],
+              [
+                108.408252,
+                36.45946
+              ],
+              [
+                108.391621,
+                36.505654
+              ],
+              [
+                108.365136,
+                36.519603
+              ],
+              [
+                108.340498,
+                36.559032
+              ],
+              [
+                108.262274,
+                36.549417
+              ],
+              [
+                108.245644,
+                36.571048
+              ],
+              [
+                108.210535,
+                36.577296
+              ],
+              [
+                108.204992,
+                36.606607
+              ],
+              [
+                108.204992,
+                36.606607
+              ],
+              [
+                108.222854,
+                36.631105
+              ],
+              [
+                108.1976,
+                36.630144
+              ],
+              [
+                108.163724,
+                36.563839
+              ],
+              [
+                108.092891,
+                36.587388
+              ],
+              [
+                108.079956,
+                36.614294
+              ],
+              [
+                108.060862,
+                36.592194
+              ],
+              [
+                108.001732,
+                36.639269
+              ],
+              [
+                108.02329,
+                36.647912
+              ],
+              [
+                108.006659,
+                36.683435
+              ],
+              [
+                107.938906,
+                36.655594
+              ],
+              [
+                107.940754,
+                36.694953
+              ],
+              [
+                107.914268,
+                36.720861
+              ],
+              [
+                107.907493,
+                36.750118
+              ],
+              [
+                107.866841,
+                36.766899
+              ],
+              [
+                107.768291,
+                36.792783
+              ],
+              [
+                107.742421,
+                36.811951
+              ],
+              [
+                107.722095,
+                36.802367
+              ],
+              [
+                107.670356,
+                36.83303
+              ],
+              [
+                107.642023,
+                36.819137
+              ],
+              [
+                107.5909,
+                36.836382
+              ],
+              [
+                107.540393,
+                36.828718
+              ],
+              [
+                107.533618,
+                36.867031
+              ],
+              [
+                107.478183,
+                36.908196
+              ],
+              [
+                107.365466,
+                36.905324
+              ],
+              [
+                107.336517,
+                36.925899
+              ],
+              [
+                107.310032,
+                36.912502
+              ],
+              [
+                107.291554,
+                36.979463
+              ],
+              [
+                107.291554,
+                36.979463
+              ],
+              [
+                107.288474,
+                37.008143
+              ],
+              [
+                107.288474,
+                37.008143
+              ],
+              [
+                107.28601,
+                37.054963
+              ],
+              [
+                107.268764,
+                37.099367
+              ],
+              [
+                107.234887,
+                37.096503
+              ],
+              [
+                107.181916,
+                37.143269
+              ],
+              [
+                107.133873,
+                37.134681
+              ],
+              [
+                107.095685,
+                37.115595
+              ],
+              [
+                107.030395,
+                37.140883
+              ],
+              [
+                107.031011,
+                37.108436
+              ],
+              [
+                106.998367,
+                37.106527
+              ],
+              [
+                106.905976,
+                37.151378
+              ],
+              [
+                106.912135,
+                37.110345
+              ],
+              [
+                106.891193,
+                37.098413
+              ],
+              [
+                106.818512,
+                37.141838
+              ],
+              [
+                106.776012,
+                37.158056
+              ],
+              [
+                106.772933,
+                37.120367
+              ],
+              [
+                106.750143,
+                37.09889
+              ],
+              [
+                106.728585,
+                37.121321
+              ],
+              [
+                106.687933,
+                37.12991
+              ],
+              [
+                106.673151,
+                37.1113
+              ],
+              [
+                106.6171,
+                37.135158
+              ],
+              [
+                106.605397,
+                37.127524
+              ],
+              [
+                106.645433,
+                37.064992
+              ],
+              [
+                106.666991,
+                37.016745
+              ],
+              [
+                106.646665,
+                37.000496
+              ],
+              [
+                106.64297,
+                36.962729
+              ],
+              [
+                106.594926,
+                36.967988
+              ],
+              [
+                106.595542,
+                36.94025
+              ],
+              [
+                106.540108,
+                36.984244
+              ],
+              [
+                106.549347,
+                36.941685
+              ],
+              [
+                106.601702,
+                36.918244
+              ],
+              [
+                106.609709,
+                36.878521
+              ],
+              [
+                106.609709,
+                36.878521
+              ],
+              [
+                106.626955,
+                36.892403
+              ],
+              [
+                106.637426,
+                36.867031
+              ],
+              [
+                106.637426,
+                36.867031
+              ],
+              [
+                106.657752,
+                36.820575
+              ],
+              [
+                106.627571,
+                36.752995
+              ],
+              [
+                106.644817,
+                36.72278
+              ],
+              [
+                106.59431,
+                36.750118
+              ],
+              [
+                106.514238,
+                36.715584
+              ],
+              [
+                106.519782,
+                36.708868
+              ],
+              [
+                106.519782,
+                36.708868
+              ],
+              [
+                106.530869,
+                36.690154
+              ],
+              [
+                106.490833,
+                36.685835
+              ],
+              [
+                106.491448,
+                36.628703
+              ],
+              [
+                106.444637,
+                36.624861
+              ],
+              [
+                106.465579,
+                36.583063
+              ],
+              [
+                106.444637,
+                36.557109
+              ],
+              [
+                106.397826,
+                36.576816
+              ],
+              [
+                106.392282,
+                36.556628
+              ],
+              [
+                106.363949,
+                36.577296
+              ],
+              [
+                106.37134,
+                36.549417
+              ],
+              [
+                106.39721,
+                36.548455
+              ],
+              [
+                106.455724,
+                36.496995
+              ],
+              [
+                106.494528,
+                36.494589
+              ],
+              [
+                106.523477,
+                36.468605
+              ],
+              [
+                106.492064,
+                36.422389
+              ],
+              [
+                106.510543,
+                36.379037
+              ],
+              [
+                106.497608,
+                36.31348
+              ],
+              [
+                106.470507,
+                36.306246
+              ],
+              [
+                106.504383,
+                36.266207
+              ],
+              [
+                106.54134,
+                36.25366
+              ],
+              [
+                106.559202,
+                36.292259
+              ],
+              [
+                106.647897,
+                36.259451
+              ],
+              [
+                106.685469,
+                36.273445
+              ],
+              [
+                106.698404,
+                36.244008
+              ],
+              [
+                106.735976,
+                36.23725
+              ],
+              [
+                106.772933,
+                36.212628
+              ],
+              [
+                106.808657,
+                36.21118
+              ],
+              [
+                106.833295,
+                36.229044
+              ],
+              [
+                106.858548,
+                36.206834
+              ],
+              [
+                106.858548,
+                36.206834
+              ],
+              [
+                106.873947,
+                36.178338
+              ],
+              [
+                106.873947,
+                36.178338
+              ],
+              [
+                106.930613,
+                36.138716
+              ],
+              [
+                106.925686,
+                36.115997
+              ],
+              [
+                106.957715,
+                36.091337
+              ],
+              [
+                106.940468,
+                36.064734
+              ],
+              [
+                106.928149,
+                36.011502
+              ],
+              [
+                106.94786,
+                35.988262
+              ],
+              [
+                106.90228,
+                35.943699
+              ],
+              [
+                106.93862,
+                35.952905
+              ],
+              [
+                106.940468,
+                35.931101
+              ],
+              [
+                106.912751,
+                35.93207
+              ],
+              [
+                106.849925,
+                35.887476
+              ],
+              [
+                106.927534,
+                35.810346
+              ],
+              [
+                106.897353,
+                35.759856
+              ],
+              [
+                106.868403,
+                35.771996
+              ],
+              [
+                106.867171,
+                35.738485
+              ],
+              [
+                106.819128,
+                35.7448
+              ],
+              [
+                106.806193,
+                35.70982
+              ],
+              [
+                106.750759,
+                35.725369
+              ],
+              [
+                106.750759,
+                35.689408
+              ],
+              [
+                106.674998,
+                35.728284
+              ],
+              [
+                106.66268,
+                35.70739
+              ],
+              [
+                106.633115,
+                35.714679
+              ],
+              [
+                106.620796,
+                35.743829
+              ],
+              [
+                106.595542,
+                35.727312
+              ],
+              [
+                106.566593,
+                35.738971
+              ],
+              [
+                106.506231,
+                35.737514
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.047356,
+                35.498155
+              ],
+              [
+                106.048588,
+                35.488898
+              ],
+              [
+                106.054132,
+                35.45478
+              ],
+              [
+                106.071994,
+                35.463555
+              ],
+              [
+                106.078769,
+                35.509848
+              ],
+              [
+                106.047356,
+                35.498155
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                102.831537,
+                36.365544
+              ],
+              [
+                102.829689,
+                36.365544
+              ],
+              [
+                102.836465,
+                36.344819
+              ],
+              [
+                102.838928,
+                36.345783
+              ],
+              [
+                102.831537,
+                36.365544
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.073226,
+                35.447468
+              ],
+              [
+                106.067682,
+                35.436254
+              ],
+              [
+                106.073226,
+                35.420649
+              ],
+              [
+                106.083081,
+                35.421624
+              ],
+              [
+                106.073226,
+                35.447468
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.504383,
+                35.736057
+              ],
+              [
+                106.506231,
+                35.737514
+              ],
+              [
+                106.49268,
+                35.732656
+              ],
+              [
+                106.498224,
+                35.732656
+              ],
+              [
+                106.504383,
+                35.736057
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 630000,
+        "name": "闈掓捣鐪�",
+        "center": [
+          101.778916,
+          36.623178
+        ],
+        "centroid": [
+          96.043533,
+          35.726403
+        ],
+        "childrenNum": 8,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 28,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                102.829689,
+                36.365544
+              ],
+              [
+                102.771791,
+                36.47438
+              ],
+              [
+                102.793349,
+                36.497957
+              ],
+              [
+                102.753313,
+                36.525855
+              ],
+              [
+                102.734219,
+                36.562396
+              ],
+              [
+                102.761936,
+                36.568645
+              ],
+              [
+                102.714509,
+                36.599401
+              ],
+              [
+                102.724364,
+                36.613813
+              ],
+              [
+                102.684328,
+                36.619097
+              ],
+              [
+                102.630741,
+                36.650793
+              ],
+              [
+                102.601176,
+                36.710307
+              ],
+              [
+                102.612879,
+                36.738129
+              ],
+              [
+                102.639364,
+                36.732853
+              ],
+              [
+                102.692335,
+                36.775528
+              ],
+              [
+                102.720052,
+                36.767858
+              ],
+              [
+                102.639364,
+                36.852666
+              ],
+              [
+                102.587009,
+                36.869904
+              ],
+              [
+                102.56114,
+                36.91968
+              ],
+              [
+                102.526031,
+                36.928291
+              ],
+              [
+                102.499546,
+                36.954599
+              ],
+              [
+                102.450271,
+                36.968467
+              ],
+              [
+                102.506321,
+                37.019134
+              ],
+              [
+                102.488459,
+                37.078362
+              ],
+              [
+                102.583314,
+                37.104618
+              ],
+              [
+                102.642444,
+                37.099845
+              ],
+              [
+                102.599944,
+                37.174748
+              ],
+              [
+                102.578386,
+                37.17284
+              ],
+              [
+                102.533422,
+                37.217176
+              ],
+              [
+                102.490307,
+                37.223371
+              ],
+              [
+                102.457662,
+                37.248147
+              ],
+              [
+                102.45335,
+                37.271487
+              ],
+              [
+                102.419474,
+                37.294343
+              ],
+              [
+                102.428097,
+                37.308624
+              ],
+              [
+                102.368351,
+                37.327662
+              ],
+              [
+                102.29875,
+                37.370004
+              ],
+              [
+                102.299981,
+                37.391404
+              ],
+              [
+                102.19712,
+                37.420403
+              ],
+              [
+                102.176794,
+                37.458892
+              ],
+              [
+                102.125055,
+                37.48549
+              ],
+              [
+                102.103497,
+                37.482641
+              ],
+              [
+                102.131214,
+                37.54625
+              ],
+              [
+                102.102265,
+                37.582304
+              ],
+              [
+                102.035128,
+                37.627819
+              ],
+              [
+                102.048678,
+                37.651515
+              ],
+              [
+                102.036359,
+                37.685149
+              ],
+              [
+                101.998787,
+                37.724921
+              ],
+              [
+                101.946432,
+                37.728235
+              ],
+              [
+                101.873135,
+                37.686569
+              ],
+              [
+                101.854657,
+                37.664781
+              ],
+              [
+                101.815853,
+                37.654357
+              ],
+              [
+                101.791832,
+                37.696041
+              ],
+              [
+                101.659405,
+                37.733441
+              ],
+              [
+                101.670491,
+                37.754264
+              ],
+              [
+                101.598427,
+                37.827569
+              ],
+              [
+                101.551615,
+                37.835604
+              ],
+              [
+                101.459224,
+                37.86632
+              ],
+              [
+                101.382848,
+                37.822369
+              ],
+              [
+                101.362522,
+                37.791162
+              ],
+              [
+                101.276906,
+                37.83655
+              ],
+              [
+                101.202994,
+                37.84742
+              ],
+              [
+                101.159262,
+                37.86821
+              ],
+              [
+                101.152486,
+                37.891356
+              ],
+              [
+                101.114298,
+                37.92016
+              ],
+              [
+                101.103211,
+                37.946593
+              ],
+              [
+                101.077342,
+                37.941874
+              ],
+              [
+                100.964009,
+                38.011221
+              ],
+              [
+                100.91843,
+                37.999432
+              ],
+              [
+                100.895024,
+                38.013107
+              ],
+              [
+                100.888864,
+                38.056001
+              ],
+              [
+                100.922125,
+                38.084741
+              ],
+              [
+                100.91843,
+                38.129006
+              ],
+              [
+                100.93814,
+                38.16007
+              ],
+              [
+                100.913502,
+                38.17889
+              ],
+              [
+                100.860531,
+                38.148305
+              ],
+              [
+                100.825423,
+                38.158658
+              ],
+              [
+                100.752126,
+                38.238612
+              ],
+              [
+                100.71517,
+                38.253652
+              ],
+              [
+                100.619083,
+                38.26587
+              ],
+              [
+                100.595061,
+                38.242372
+              ],
+              [
+                100.545786,
+                38.247072
+              ],
+              [
+                100.516837,
+                38.272448
+              ],
+              [
+                100.474953,
+                38.288891
+              ],
+              [
+                100.459555,
+                38.2654
+              ],
+              [
+                100.432453,
+                38.275267
+              ],
+              [
+                100.424446,
+                38.307208
+              ],
+              [
+                100.396729,
+                38.293118
+              ],
+              [
+                100.318505,
+                38.329276
+              ],
+              [
+                100.331439,
+                38.337257
+              ],
+              [
+                100.301874,
+                38.388405
+              ],
+              [
+                100.259374,
+                38.366355
+              ],
+              [
+                100.24028,
+                38.441861
+              ],
+              [
+                100.163288,
+                38.461546
+              ],
+              [
+                100.113397,
+                38.497151
+              ],
+              [
+                100.086911,
+                38.492936
+              ],
+              [
+                100.064122,
+                38.518694
+              ],
+              [
+                100.025933,
+                38.507923
+              ],
+              [
+                100.001296,
+                38.467169
+              ],
+              [
+                100.022238,
+                38.432017
+              ],
+              [
+                100.093071,
+                38.407166
+              ],
+              [
+                100.136803,
+                38.33444
+              ],
+              [
+                100.163904,
+                38.328337
+              ],
+              [
+                100.159592,
+                38.291239
+              ],
+              [
+                100.182998,
+                38.222158
+              ],
+              [
+                100.126332,
+                38.231561
+              ],
+              [
+                100.117093,
+                38.253652
+              ],
+              [
+                100.071513,
+                38.284663
+              ],
+              [
+                100.049955,
+                38.283254
+              ],
+              [
+                100.001912,
+                38.315191
+              ],
+              [
+                99.960028,
+                38.320825
+              ],
+              [
+                99.826985,
+                38.370109
+              ],
+              [
+                99.758,
+                38.410449
+              ],
+              [
+                99.727203,
+                38.415607
+              ],
+              [
+                99.65945,
+                38.449361
+              ],
+              [
+                99.63974,
+                38.474666
+              ],
+              [
+                99.585537,
+                38.498556
+              ],
+              [
+                99.52887,
+                38.546314
+              ],
+              [
+                99.501769,
+                38.612281
+              ],
+              [
+                99.450646,
+                38.60433
+              ],
+              [
+                99.412458,
+                38.665571
+              ],
+              [
+                99.375502,
+                38.684727
+              ],
+              [
+                99.361951,
+                38.718354
+              ],
+              [
+                99.291118,
+                38.765966
+              ],
+              [
+                99.222133,
+                38.788827
+              ],
+              [
+                99.141445,
+                38.852706
+              ],
+              [
+                99.068764,
+                38.896968
+              ],
+              [
+                99.071843,
+                38.921184
+              ],
+              [
+                99.107568,
+                38.951907
+              ],
+              [
+                99.054597,
+                38.97657
+              ],
+              [
+                98.951735,
+                38.987735
+              ],
+              [
+                98.903076,
+                39.012384
+              ],
+              [
+                98.886446,
+                39.040744
+              ],
+              [
+                98.818076,
+                39.064911
+              ],
+              [
+                98.816845,
+                39.085818
+              ],
+              [
+                98.743548,
+                39.086747
+              ],
+              [
+                98.730613,
+                39.057011
+              ],
+              [
+                98.70536,
+                39.043533
+              ],
+              [
+                98.661628,
+                38.993782
+              ],
+              [
+                98.612353,
+                38.977035
+              ],
+              [
+                98.624056,
+                38.959353
+              ],
+              [
+                98.584635,
+                38.93003
+              ],
+              [
+                98.526737,
+                38.95563
+              ],
+              [
+                98.457752,
+                38.952838
+              ],
+              [
+                98.428187,
+                38.976104
+              ],
+              [
+                98.432498,
+                38.996107
+              ],
+              [
+                98.401086,
+                39.001688
+              ],
+              [
+                98.383839,
+                39.029588
+              ],
+              [
+                98.316702,
+                39.040744
+              ],
+              [
+                98.280977,
+                39.027263
+              ],
+              [
+                98.287753,
+                38.992386
+              ],
+              [
+                98.276666,
+                38.963541
+              ],
+              [
+                98.235398,
+                38.918855
+              ],
+              [
+                98.242173,
+                38.880664
+              ],
+              [
+                98.167645,
+                38.840121
+              ],
+              [
+                98.091884,
+                38.786495
+              ],
+              [
+                98.068478,
+                38.816344
+              ],
+              [
+                98.029058,
+                38.834061
+              ],
+              [
+                98.009348,
+                38.85923
+              ],
+              [
+                97.875689,
+                38.898365
+              ],
+              [
+                97.828878,
+                38.93003
+              ],
+              [
+                97.701379,
+                38.963076
+              ],
+              [
+                97.679205,
+                39.010524
+              ],
+              [
+                97.58127,
+                39.052364
+              ],
+              [
+                97.504894,
+                39.076527
+              ],
+              [
+                97.458698,
+                39.117863
+              ],
+              [
+                97.401416,
+                39.146645
+              ],
+              [
+                97.371235,
+                39.140611
+              ],
+              [
+                97.347213,
+                39.167528
+              ],
+              [
+                97.315185,
+                39.164744
+              ],
+              [
+                97.220946,
+                39.193042
+              ],
+              [
+                97.14149,
+                39.199999
+              ],
+              [
+                97.060186,
+                39.19768
+              ],
+              [
+                97.017686,
+                39.208347
+              ],
+              [
+                96.962251,
+                39.198144
+              ],
+              [
+                97.012142,
+                39.142004
+              ],
+              [
+                96.969643,
+                39.097895
+              ],
+              [
+                96.95794,
+                39.041674
+              ],
+              [
+                96.965331,
+                39.017034
+              ],
+              [
+                96.938846,
+                38.95563
+              ],
+              [
+                96.940693,
+                38.90768
+              ],
+              [
+                96.983809,
+                38.869016
+              ],
+              [
+                96.993664,
+                38.834993
+              ],
+              [
+                96.987505,
+                38.793025
+              ],
+              [
+                97.00044,
+                38.7613
+              ],
+              [
+                97.023229,
+                38.755699
+              ],
+              [
+                97.009063,
+                38.702477
+              ],
+              [
+                97.057722,
+                38.67258
+              ],
+              [
+                97.047251,
+                38.653888
+              ],
+              [
+                97.055874,
+                38.594508
+              ],
+              [
+                96.961019,
+                38.558015
+              ],
+              [
+                96.876636,
+                38.580475
+              ],
+              [
+                96.847071,
+                38.599186
+              ],
+              [
+                96.7941,
+                38.608072
+              ],
+              [
+                96.808882,
+                38.582346
+              ],
+              [
+                96.767614,
+                38.552399
+              ],
+              [
+                96.800259,
+                38.52759
+              ],
+              [
+                96.780549,
+                38.504177
+              ],
+              [
+                96.706637,
+                38.505582
+              ],
+              [
+                96.6666,
+                38.483567
+              ],
+              [
+                96.707868,
+                38.459203
+              ],
+              [
+                96.698013,
+                38.422172
+              ],
+              [
+                96.626564,
+                38.356031
+              ],
+              [
+                96.638883,
+                38.307208
+              ],
+              [
+                96.655514,
+                38.295936
+              ],
+              [
+                96.665369,
+                38.23015
+              ],
+              [
+                96.46334,
+                38.277616
+              ],
+              [
+                96.378341,
+                38.277146
+              ],
+              [
+                96.335841,
+                38.246132
+              ],
+              [
+                96.301964,
+                38.183124
+              ],
+              [
+                96.313051,
+                38.161952
+              ],
+              [
+                96.264392,
+                38.145952
+              ],
+              [
+                96.252689,
+                38.167599
+              ],
+              [
+                96.221892,
+                38.149246
+              ],
+              [
+                96.109175,
+                38.187358
+              ],
+              [
+                96.06606,
+                38.173245
+              ],
+              [
+                96.006929,
+                38.207582
+              ],
+              [
+                95.93856,
+                38.237202
+              ],
+              [
+                95.932401,
+                38.259291
+              ],
+              [
+                95.89606,
+                38.2903
+              ],
+              [
+                95.852945,
+                38.287481
+              ],
+              [
+                95.83693,
+                38.344298
+              ],
+              [
+                95.775952,
+                38.356031
+              ],
+              [
+                95.723597,
+                38.378554
+              ],
+              [
+                95.703887,
+                38.400131
+              ],
+              [
+                95.671858,
+                38.388405
+              ],
+              [
+                95.608417,
+                38.339134
+              ],
+              [
+                95.585011,
+                38.343359
+              ],
+              [
+                95.51849,
+                38.294997
+              ],
+              [
+                95.487693,
+                38.314721
+              ],
+              [
+                95.455664,
+                38.291709
+              ],
+              [
+                95.440881,
+                38.310965
+              ],
+              [
+                95.408236,
+                38.300163
+              ],
+              [
+                95.315846,
+                38.318947
+              ],
+              [
+                95.259179,
+                38.302981
+              ],
+              [
+                95.229614,
+                38.330685
+              ],
+              [
+                95.209904,
+                38.327868
+              ],
+              [
+                95.185266,
+                38.379492
+              ],
+              [
+                95.140919,
+                38.392158
+              ],
+              [
+                95.122441,
+                38.417014
+              ],
+              [
+                95.072549,
+                38.402476
+              ],
+              [
+                95.045448,
+                38.418889
+              ],
+              [
+                94.973999,
+                38.430142
+              ],
+              [
+                94.884072,
+                38.414669
+              ],
+              [
+                94.861282,
+                38.393565
+              ],
+              [
+                94.812623,
+                38.385591
+              ],
+              [
+                94.672805,
+                38.386998
+              ],
+              [
+                94.582878,
+                38.36917
+              ],
+              [
+                94.56132,
+                38.351807
+              ],
+              [
+                94.527443,
+                38.365416
+              ],
+              [
+                94.527443,
+                38.425922
+              ],
+              [
+                94.511429,
+                38.445142
+              ],
+              [
+                94.370379,
+                38.7627
+              ],
+              [
+                94.281067,
+                38.7599
+              ],
+              [
+                93.973098,
+                38.724891
+              ],
+              [
+                93.95154,
+                38.715086
+              ],
+              [
+                93.885018,
+                38.720689
+              ],
+              [
+                93.800019,
+                38.750566
+              ],
+              [
+                93.773533,
+                38.771099
+              ],
+              [
+                93.756287,
+                38.807484
+              ],
+              [
+                93.769838,
+                38.821007
+              ],
+              [
+                93.884403,
+                38.826136
+              ],
+              [
+                93.884403,
+                38.867618
+              ],
+              [
+                93.834511,
+                38.867618
+              ],
+              [
+                93.729186,
+                38.924443
+              ],
+              [
+                93.453245,
+                38.915596
+              ],
+              [
+                93.274007,
+                38.896036
+              ],
+              [
+                93.237666,
+                38.916062
+              ],
+              [
+                93.179152,
+                38.923977
+              ],
+              [
+                93.198246,
+                39.045857
+              ],
+              [
+                93.165601,
+                39.090928
+              ],
+              [
+                93.131725,
+                39.108112
+              ],
+              [
+                93.142196,
+                39.160567
+              ],
+              [
+                93.115094,
+                39.17959
+              ],
+              [
+                93.043029,
+                39.146645
+              ],
+              [
+                92.978356,
+                39.143396
+              ],
+              [
+                92.938936,
+                39.169848
+              ],
+              [
+                92.889045,
+                39.160103
+              ],
+              [
+                92.866871,
+                39.138754
+              ],
+              [
+                92.765857,
+                39.136898
+              ],
+              [
+                92.659299,
+                39.109969
+              ],
+              [
+                92.545966,
+                39.111362
+              ],
+              [
+                92.489916,
+                39.099753
+              ],
+              [
+                92.459119,
+                39.063982
+              ],
+              [
+                92.459119,
+                39.042604
+              ],
+              [
+                92.41046,
+                39.03842
+              ],
+              [
+                92.416003,
+                39.010524
+              ],
+              [
+                92.380279,
+                38.999828
+              ],
+              [
+                92.263866,
+                39.002153
+              ],
+              [
+                92.197961,
+                38.983548
+              ],
+              [
+                92.173323,
+                38.960749
+              ],
+              [
+                92.10865,
+                38.963541
+              ],
+              [
+                91.966368,
+                38.930961
+              ],
+              [
+                91.880752,
+                38.899297
+              ],
+              [
+                91.87952,
+                38.884391
+              ],
+              [
+                91.806223,
+                38.872744
+              ],
+              [
+                91.694738,
+                38.86622
+              ],
+              [
+                91.681188,
+                38.852706
+              ],
+              [
+                91.501333,
+                38.815411
+              ],
+              [
+                91.446515,
+                38.813546
+              ],
+              [
+                91.298689,
+                38.746365
+              ],
+              [
+                91.242639,
+                38.752433
+              ],
+              [
+                91.188436,
+                38.73096
+              ],
+              [
+                90.992567,
+                38.695003
+              ],
+              [
+                90.970394,
+                38.697806
+              ],
+              [
+                90.899561,
+                38.679588
+              ],
+              [
+                90.724634,
+                38.658094
+              ],
+              [
+                90.65996,
+                38.674449
+              ],
+              [
+                90.619308,
+                38.664636
+              ],
+              [
+                90.645794,
+                38.635191
+              ],
+              [
+                90.606374,
+                38.610878
+              ],
+              [
+                90.608837,
+                38.594508
+              ],
+              [
+                90.560794,
+                38.593573
+              ],
+              [
+                90.525685,
+                38.561291
+              ],
+              [
+                90.463476,
+                38.556611
+              ],
+              [
+                90.465323,
+                38.521971
+              ],
+              [
+                90.427135,
+                38.493873
+              ],
+              [
+                90.353222,
+                38.482162
+              ],
+              [
+                90.315034,
+                38.501835
+              ],
+              [
+                90.248513,
+                38.491531
+              ],
+              [
+                90.130868,
+                38.494341
+              ],
+              [
+                90.111774,
+                38.477945
+              ],
+              [
+                90.111774,
+                38.418889
+              ],
+              [
+                90.129636,
+                38.400131
+              ],
+              [
+                90.179528,
+                38.396848
+              ],
+              [
+                90.137644,
+                38.340543
+              ],
+              [
+                90.280542,
+                38.238142
+              ],
+              [
+                90.352607,
+                38.233441
+              ],
+              [
+                90.361846,
+                38.300163
+              ],
+              [
+                90.401882,
+                38.311434
+              ],
+              [
+                90.531229,
+                38.319886
+              ],
+              [
+                90.516446,
+                38.207111
+              ],
+              [
+                90.519526,
+                37.730601
+              ],
+              [
+                90.579272,
+                37.720661
+              ],
+              [
+                90.586663,
+                37.703144
+              ],
+              [
+                90.643946,
+                37.696988
+              ],
+              [
+                90.777605,
+                37.648672
+              ],
+              [
+                90.820104,
+                37.613599
+              ],
+              [
+                90.854597,
+                37.604117
+              ],
+              [
+                90.882314,
+                37.575664
+              ],
+              [
+                90.865684,
+                37.53059
+              ],
+              [
+                90.911879,
+                37.519674
+              ],
+              [
+                90.958075,
+                37.477891
+              ],
+              [
+                91.019669,
+                37.493088
+              ],
+              [
+                91.073256,
+                37.475992
+              ],
+              [
+                91.099741,
+                37.447965
+              ],
+              [
+                91.113292,
+                37.387124
+              ],
+              [
+                91.136081,
+                37.355734
+              ],
+              [
+                91.134849,
+                37.324331
+              ],
+              [
+                91.194596,
+                37.273868
+              ],
+              [
+                91.1909,
+                37.205737
+              ],
+              [
+                91.280211,
+                37.163779
+              ],
+              [
+                91.286371,
+                37.105095
+              ],
+              [
+                91.303617,
+                37.083136
+              ],
+              [
+                91.291298,
+                37.042544
+              ],
+              [
+                91.303617,
+                37.012444
+              ],
+              [
+                91.216153,
+                37.010054
+              ],
+              [
+                91.181045,
+                37.025345
+              ],
+              [
+                91.133618,
+                37.007665
+              ],
+              [
+                91.126842,
+                36.978507
+              ],
+              [
+                91.051698,
+                36.96751
+              ],
+              [
+                91.036915,
+                36.929727
+              ],
+              [
+                90.983944,
+                36.913459
+              ],
+              [
+                90.924198,
+                36.921115
+              ],
+              [
+                90.853981,
+                36.915373
+              ],
+              [
+                90.758511,
+                36.825844
+              ],
+              [
+                90.732025,
+                36.825844
+              ],
+              [
+                90.727098,
+                36.755872
+              ],
+              [
+                90.754815,
+                36.721341
+              ],
+              [
+                90.720938,
+                36.708868
+              ],
+              [
+                90.706156,
+                36.658955
+              ],
+              [
+                90.730793,
+                36.655594
+              ],
+              [
+                90.72217,
+                36.620058
+              ],
+              [
+                90.741264,
+                36.585947
+              ],
+              [
+                90.810865,
+                36.585466
+              ],
+              [
+                90.831191,
+                36.55807
+              ],
+              [
+                90.905104,
+                36.560474
+              ],
+              [
+                91.011662,
+                36.539801
+              ],
+              [
+                91.035683,
+                36.529703
+              ],
+              [
+                91.039995,
+                36.474861
+              ],
+              [
+                91.028292,
+                36.443093
+              ],
+              [
+                91.051698,
+                36.433946
+              ],
+              [
+                91.026444,
+                36.323607
+              ],
+              [
+                91.07264,
+                36.299012
+              ],
+              [
+                91.051698,
+                36.238215
+              ],
+              [
+                91.096045,
+                36.219871
+              ],
+              [
+                91.09235,
+                36.163844
+              ],
+              [
+                91.124994,
+                36.115514
+              ],
+              [
+                91.081263,
+                36.088436
+              ],
+              [
+                90.979017,
+                36.106811
+              ],
+              [
+                90.922966,
+                36.028927
+              ],
+              [
+                90.850285,
+                36.016827
+              ],
+              [
+                90.815793,
+                36.035703
+              ],
+              [
+                90.776373,
+                36.086501
+              ],
+              [
+                90.659344,
+                36.13485
+              ],
+              [
+                90.613149,
+                36.126632
+              ],
+              [
+                90.534925,
+                36.147899
+              ],
+              [
+                90.478258,
+                36.13195
+              ],
+              [
+                90.424055,
+                36.133883
+              ],
+              [
+                90.325505,
+                36.159496
+              ],
+              [
+                90.23681,
+                36.160462
+              ],
+              [
+                90.198006,
+                36.187516
+              ],
+              [
+                90.130252,
+                36.2078
+              ],
+              [
+                90.145651,
+                36.239181
+              ],
+              [
+                90.058188,
+                36.255591
+              ],
+              [
+                90.043405,
+                36.276822
+              ],
+              [
+                90.003369,
+                36.278752
+              ],
+              [
+                90.028006,
+                36.258486
+              ],
+              [
+                90.019999,
+                36.213594
+              ],
+              [
+                89.997825,
+                36.168193
+              ],
+              [
+                89.944855,
+                36.140649
+              ],
+              [
+                89.941159,
+                36.067637
+              ],
+              [
+                89.914058,
+                36.079246
+              ],
+              [
+                89.819819,
+                36.080697
+              ],
+              [
+                89.766848,
+                36.073925
+              ],
+              [
+                89.711414,
+                36.093272
+              ],
+              [
+                89.688624,
+                36.091337
+              ],
+              [
+                89.605472,
+                36.038123
+              ],
+              [
+                89.474893,
+                36.022151
+              ],
+              [
+                89.417611,
+                36.044897
+              ],
+              [
+                89.404676,
+                36.016827
+              ],
+              [
+                89.434857,
+                35.992136
+              ],
+              [
+                89.428082,
+                35.917531
+              ],
+              [
+                89.489676,
+                35.903475
+              ],
+              [
+                89.554965,
+                35.873414
+              ],
+              [
+                89.550654,
+                35.856924
+              ],
+              [
+                89.62395,
+                35.859349
+              ],
+              [
+                89.654747,
+                35.848193
+              ],
+              [
+                89.707718,
+                35.849163
+              ],
+              [
+                89.778551,
+                35.861775
+              ],
+              [
+                89.801957,
+                35.848193
+              ],
+              [
+                89.767464,
+                35.799183
+              ],
+              [
+                89.782863,
+                35.773453
+              ],
+              [
+                89.747138,
+                35.7516
+              ],
+              [
+                89.748986,
+                35.66267
+              ],
+              [
+                89.726196,
+                35.648082
+              ],
+              [
+                89.765616,
+                35.599922
+              ],
+              [
+                89.75145,
+                35.580942
+              ],
+              [
+                89.71203,
+                35.581915
+              ],
+              [
+                89.699711,
+                35.544916
+              ],
+              [
+                89.720037,
+                35.501566
+              ],
+              [
+                89.740979,
+                35.507412
+              ],
+              [
+                89.765,
+                35.482563
+              ],
+              [
+                89.739131,
+                35.468429
+              ],
+              [
+                89.685544,
+                35.416259
+              ],
+              [
+                89.658443,
+                35.425526
+              ],
+              [
+                89.619639,
+                35.412357
+              ],
+              [
+                89.58761,
+                35.383575
+              ],
+              [
+                89.497067,
+                35.361128
+              ],
+              [
+                89.516161,
+                35.330862
+              ],
+              [
+                89.494603,
+                35.298632
+              ],
+              [
+                89.531559,
+                35.276161
+              ],
+              [
+                89.48598,
+                35.256616
+              ],
+              [
+                89.450255,
+                35.223867
+              ],
+              [
+                89.46935,
+                35.214577
+              ],
+              [
+                89.519241,
+                35.133862
+              ],
+              [
+                89.579603,
+                35.118688
+              ],
+              [
+                89.593153,
+                35.104491
+              ],
+              [
+                89.59069,
+                35.057965
+              ],
+              [
+                89.560509,
+                34.938836
+              ],
+              [
+                89.578987,
+                34.895162
+              ],
+              [
+                89.670146,
+                34.887798
+              ],
+              [
+                89.707102,
+                34.919701
+              ],
+              [
+                89.747138,
+                34.903506
+              ],
+              [
+                89.78779,
+                34.921664
+              ],
+              [
+                89.821051,
+                34.902033
+              ],
+              [
+                89.814891,
+                34.86816
+              ],
+              [
+                89.838913,
+                34.865705
+              ],
+              [
+                89.867862,
+                34.81069
+              ],
+              [
+                89.825978,
+                34.796931
+              ],
+              [
+                89.799493,
+                34.743838
+              ],
+              [
+                89.732356,
+                34.732035
+              ],
+              [
+                89.72558,
+                34.660689
+              ],
+              [
+                89.74837,
+                34.641981
+              ],
+              [
+                89.798877,
+                34.628686
+              ],
+              [
+                89.777935,
+                34.574499
+              ],
+              [
+                89.814891,
+                34.548871
+              ],
+              [
+                89.823515,
+                34.455657
+              ],
+              [
+                89.819819,
+                34.420614
+              ],
+              [
+                89.799493,
+                34.39642
+              ],
+              [
+                89.820435,
+                34.369255
+              ],
+              [
+                89.858623,
+                34.359375
+              ],
+              [
+                89.86663,
+                34.324785
+              ],
+              [
+                89.825362,
+                34.293642
+              ],
+              [
+                89.838297,
+                34.263477
+              ],
+              [
+                89.816739,
+                34.16945
+              ],
+              [
+                89.789638,
+                34.150632
+              ],
+              [
+                89.760073,
+                34.152613
+              ],
+              [
+                89.756993,
+                34.124874
+              ],
+              [
+                89.71203,
+                34.131809
+              ],
+              [
+                89.655979,
+                34.097126
+              ],
+              [
+                89.656595,
+                34.057966
+              ],
+              [
+                89.635037,
+                34.049537
+              ],
+              [
+                89.684928,
+                33.990013
+              ],
+              [
+                89.688008,
+                33.959739
+              ],
+              [
+                89.718805,
+                33.946832
+              ],
+              [
+                89.73174,
+                33.921509
+              ],
+              [
+                89.795181,
+                33.865374
+              ],
+              [
+                89.837065,
+                33.868853
+              ],
+              [
+                89.899891,
+                33.80771
+              ],
+              [
+                89.942391,
+                33.801246
+              ],
+              [
+                89.902355,
+                33.758467
+              ],
+              [
+                89.907282,
+                33.741051
+              ],
+              [
+                89.983659,
+                33.725622
+              ],
+              [
+                89.981195,
+                33.70322
+              ],
+              [
+                90.008296,
+                33.687785
+              ],
+              [
+                89.984275,
+                33.612061
+              ],
+              [
+                90.01076,
+                33.553728
+              ],
+              [
+                90.083441,
+                33.525295
+              ],
+              [
+                90.088984,
+                33.478885
+              ],
+              [
+                90.107463,
+                33.460913
+              ],
+              [
+                90.22018,
+                33.437943
+              ],
+              [
+                90.246665,
+                33.423959
+              ],
+              [
+                90.332896,
+                33.310501
+              ],
+              [
+                90.363077,
+                33.279487
+              ],
+              [
+                90.405577,
+                33.260473
+              ],
+              [
+                90.490577,
+                33.264977
+              ],
+              [
+                90.562642,
+                33.229441
+              ],
+              [
+                90.627315,
+                33.180368
+              ],
+              [
+                90.704308,
+                33.135778
+              ],
+              [
+                90.740032,
+                33.142293
+              ],
+              [
+                90.803474,
+                33.114227
+              ],
+              [
+                90.88293,
+                33.120241
+              ],
+              [
+                90.902024,
+                33.083143
+              ],
+              [
+                90.927894,
+                33.120241
+              ],
+              [
+                91.001807,
+                33.11573
+              ],
+              [
+                91.037531,
+                33.098686
+              ],
+              [
+                91.072024,
+                33.113224
+              ],
+              [
+                91.147784,
+                33.07211
+              ],
+              [
+                91.161335,
+                33.108712
+              ],
+              [
+                91.18782,
+                33.106206
+              ],
+              [
+                91.226624,
+                33.141792
+              ],
+              [
+                91.261733,
+                33.141291
+              ],
+              [
+                91.311624,
+                33.108211
+              ],
+              [
+                91.370138,
+                33.100691
+              ],
+              [
+                91.436044,
+                33.066092
+              ],
+              [
+                91.49579,
+                33.109214
+              ],
+              [
+                91.535826,
+                33.10019
+              ],
+              [
+                91.55492,
+                33.060074
+              ],
+              [
+                91.583253,
+                33.0375
+              ],
+              [
+                91.664557,
+                33.012913
+              ],
+              [
+                91.685499,
+                32.989324
+              ],
+              [
+                91.752637,
+                32.969242
+              ],
+              [
+                91.799448,
+                32.942126
+              ],
+              [
+                91.839484,
+                32.948152
+              ],
+              [
+                91.857962,
+                32.90244
+              ],
+              [
+                91.896766,
+                32.907967
+              ],
+              [
+                91.955897,
+                32.8205
+              ],
+              [
+                92.018722,
+                32.829552
+              ],
+              [
+                92.038432,
+                32.860725
+              ],
+              [
+                92.101874,
+                32.860222
+              ],
+              [
+                92.145606,
+                32.885857
+              ],
+              [
+                92.205352,
+                32.866255
+              ],
+              [
+                92.227526,
+                32.821003
+              ],
+              [
+                92.193649,
+                32.801889
+              ],
+              [
+                92.211511,
+                32.788306
+              ],
+              [
+                92.198577,
+                32.754591
+              ],
+              [
+                92.255243,
+                32.720863
+              ],
+              [
+                92.310062,
+                32.751571
+              ],
+              [
+                92.343938,
+                32.738484
+              ],
+              [
+                92.355641,
+                32.764657
+              ],
+              [
+                92.411076,
+                32.748048
+              ],
+              [
+                92.459119,
+                32.76365
+              ],
+              [
+                92.484372,
+                32.745028
+              ],
+              [
+                92.56814,
+                32.73194
+              ],
+              [
+                92.574916,
+                32.741001
+              ],
+              [
+                92.634662,
+                32.720863
+              ],
+              [
+                92.667922,
+                32.73194
+              ],
+              [
+                92.686401,
+                32.76516
+              ],
+              [
+                92.756618,
+                32.743014
+              ],
+              [
+                92.789262,
+                32.719856
+              ],
+              [
+                92.822523,
+                32.729926
+              ],
+              [
+                92.866871,
+                32.698203
+              ],
+              [
+                92.933392,
+                32.719353
+              ],
+              [
+                92.964189,
+                32.714821
+              ],
+              [
+                93.00053,
+                32.741001
+              ],
+              [
+                93.019624,
+                32.737477
+              ],
+              [
+                93.023935,
+                32.703239
+              ],
+              [
+                93.069515,
+                32.626156
+              ],
+              [
+                93.087993,
+                32.63674
+              ],
+              [
+                93.159442,
+                32.644803
+              ],
+              [
+                93.176688,
+                32.6705
+              ],
+              [
+                93.210565,
+                32.655385
+              ],
+              [
+                93.239514,
+                32.662439
+              ],
+              [
+                93.260456,
+                32.62666
+              ],
+              [
+                93.300492,
+                32.619604
+              ],
+              [
+                93.308499,
+                32.580278
+              ],
+              [
+                93.33868,
+                32.5712
+              ],
+              [
+                93.385492,
+                32.525294
+              ],
+              [
+                93.411977,
+                32.558086
+              ],
+              [
+                93.4631,
+                32.556069
+              ],
+              [
+                93.476651,
+                32.504603
+              ],
+              [
+                93.501904,
+                32.503593
+              ],
+              [
+                93.516687,
+                32.47583
+              ],
+              [
+                93.618933,
+                32.522771
+              ],
+              [
+                93.651577,
+                32.571705
+              ],
+              [
+                93.721795,
+                32.578261
+              ],
+              [
+                93.75136,
+                32.56313
+              ],
+              [
+                93.820345,
+                32.549511
+              ],
+              [
+                93.851142,
+                32.50965
+              ],
+              [
+                93.861613,
+                32.466237
+              ],
+              [
+                93.90904,
+                32.463207
+              ],
+              [
+                93.960163,
+                32.484917
+              ],
+              [
+                93.978641,
+                32.459672
+              ],
+              [
+                94.03038,
+                32.448057
+              ],
+              [
+                94.049474,
+                32.469771
+              ],
+              [
+                94.091974,
+                32.463207
+              ],
+              [
+                94.137554,
+                32.433915
+              ],
+              [
+                94.176974,
+                32.454117
+              ],
+              [
+                94.196684,
+                32.51621
+              ],
+              [
+                94.250886,
+                32.51722
+              ],
+              [
+                94.292154,
+                32.502584
+              ],
+              [
+                94.294002,
+                32.519743
+              ],
+              [
+                94.350053,
+                32.533871
+              ],
+              [
+                94.371611,
+                32.524789
+              ],
+              [
+                94.395016,
+                32.594397
+              ],
+              [
+                94.435052,
+                32.562626
+              ],
+              [
+                94.463386,
+                32.572209
+              ],
+              [
+                94.459074,
+                32.599439
+              ],
+              [
+                94.522516,
+                32.595909
+              ],
+              [
+                94.591501,
+                32.640772
+              ],
+              [
+                94.614291,
+                32.673522
+              ],
+              [
+                94.638312,
+                32.645307
+              ],
+              [
+                94.737479,
+                32.587338
+              ],
+              [
+                94.762116,
+                32.526303
+              ],
+              [
+                94.78737,
+                32.522266
+              ],
+              [
+                94.80708,
+                32.486431
+              ],
+              [
+                94.852043,
+                32.463712
+              ],
+              [
+                94.889616,
+                32.472295
+              ],
+              [
+                94.912405,
+                32.41573
+              ],
+              [
+                94.944434,
+                32.404109
+              ],
+              [
+                94.988166,
+                32.422802
+              ],
+              [
+                95.057151,
+                32.395014
+              ],
+              [
+                95.075013,
+                32.376315
+              ],
+              [
+                95.075013,
+                32.376315
+              ],
+              [
+                95.081789,
+                32.384907
+              ],
+              [
+                95.153853,
+                32.386423
+              ],
+              [
+                95.218527,
+                32.397035
+              ],
+              [
+                95.228382,
+                32.363678
+              ],
+              [
+                95.261643,
+                32.348006
+              ],
+              [
+                95.193274,
+                32.332331
+              ],
+              [
+                95.096571,
+                32.322217
+              ],
+              [
+                95.079325,
+                32.279726
+              ],
+              [
+                95.10581,
+                32.258979
+              ],
+              [
+                95.20744,
+                32.297433
+              ],
+              [
+                95.214216,
+                32.321712
+              ],
+              [
+                95.241317,
+                32.3207
+              ],
+              [
+                95.239469,
+                32.287315
+              ],
+              [
+                95.270266,
+                32.194683
+              ],
+              [
+                95.270266,
+                32.194683
+              ],
+              [
+                95.31523,
+                32.148585
+              ],
+              [
+                95.366968,
+                32.151118
+              ],
+              [
+                95.367584,
+                32.178982
+              ],
+              [
+                95.406389,
+                32.182021
+              ],
+              [
+                95.440265,
+                32.157705
+              ],
+              [
+                95.454432,
+                32.061898
+              ],
+              [
+                95.421171,
+                32.033999
+              ],
+              [
+                95.454432,
+                32.007613
+              ],
+              [
+                95.395918,
+                32.001523
+              ],
+              [
+                95.360809,
+                31.95939
+              ],
+              [
+                95.3682,
+                31.92892
+              ],
+              [
+                95.408852,
+                31.918761
+              ],
+              [
+                95.406389,
+                31.896915
+              ],
+              [
+                95.456896,
+                31.801853
+              ],
+              [
+                95.480301,
+                31.795749
+              ],
+              [
+                95.511714,
+                31.750468
+              ],
+              [
+                95.546823,
+                31.73978
+              ],
+              [
+                95.580083,
+                31.76726
+              ],
+              [
+                95.634286,
+                31.782523
+              ],
+              [
+                95.779648,
+                31.748941
+              ],
+              [
+                95.823995,
+                31.68225
+              ],
+              [
+                95.853561,
+                31.714329
+              ],
+              [
+                95.846169,
+                31.736218
+              ],
+              [
+                95.89914,
+                31.81711
+              ],
+              [
+                95.983524,
+                31.816601
+              ],
+              [
+                95.989067,
+                31.78761
+              ],
+              [
+                96.064828,
+                31.720438
+              ],
+              [
+                96.135661,
+                31.70211
+              ],
+              [
+                96.148595,
+                31.686324
+              ],
+              [
+                96.156603,
+                31.602769
+              ],
+              [
+                96.207726,
+                31.598691
+              ],
+              [
+                96.221892,
+                31.647613
+              ],
+              [
+                96.245298,
+                31.657802
+              ],
+              [
+                96.252073,
+                31.697527
+              ],
+              [
+                96.222508,
+                31.733164
+              ],
+              [
+                96.231131,
+                31.749959
+              ],
+              [
+                96.178161,
+                31.775401
+              ],
+              [
+                96.183088,
+                31.835924
+              ],
+              [
+                96.202798,
+                31.841008
+              ],
+              [
+                96.214501,
+                31.876589
+              ],
+              [
+                96.188632,
+                31.904028
+              ],
+              [
+                96.220044,
+                31.905553
+              ],
+              [
+                96.253305,
+                31.929936
+              ],
+              [
+                96.288414,
+                31.919777
+              ],
+              [
+                96.389428,
+                31.919777
+              ],
+              [
+                96.407906,
+                31.845583
+              ],
+              [
+                96.435623,
+                31.796258
+              ],
+              [
+                96.468884,
+                31.769804
+              ],
+              [
+                96.519391,
+                31.74945
+              ],
+              [
+                96.56805,
+                31.711783
+              ],
+              [
+                96.615477,
+                31.737236
+              ],
+              [
+                96.661057,
+                31.705674
+              ],
+              [
+                96.691854,
+                31.722474
+              ],
+              [
+                96.722651,
+                31.686833
+              ],
+              [
+                96.778701,
+                31.675629
+              ],
+              [
+                96.790404,
+                31.698545
+              ],
+              [
+                96.840295,
+                31.720438
+              ],
+              [
+                96.799027,
+                31.792188
+              ],
+              [
+                96.765767,
+                31.819144
+              ],
+              [
+                96.760223,
+                31.860325
+              ],
+              [
+                96.794716,
+                31.869474
+              ],
+              [
+                96.81073,
+                31.894375
+              ],
+              [
+                96.776238,
+                31.935015
+              ],
+              [
+                96.753448,
+                31.944156
+              ],
+              [
+                96.742977,
+                32.001016
+              ],
+              [
+                96.722651,
+                32.013195
+              ],
+              [
+                96.824281,
+                32.007613
+              ],
+              [
+                96.868629,
+                31.964975
+              ],
+              [
+                96.863085,
+                31.996448
+              ],
+              [
+                96.894498,
+                32.013703
+              ],
+              [
+                96.941925,
+                31.986297
+              ],
+              [
+                96.965947,
+                32.008628
+              ],
+              [
+                96.935766,
+                32.048203
+              ],
+              [
+                97.006599,
+                32.067984
+              ],
+              [
+                97.028773,
+                32.04871
+              ],
+              [
+                97.127323,
+                32.044145
+              ],
+              [
+                97.169823,
+                32.032984
+              ],
+              [
+                97.188301,
+                32.055304
+              ],
+              [
+                97.214786,
+                32.042623
+              ],
+              [
+                97.233881,
+                32.063927
+              ],
+              [
+                97.201852,
+                32.090296
+              ],
+              [
+                97.219714,
+                32.109054
+              ],
+              [
+                97.258518,
+                32.072041
+              ],
+              [
+                97.308409,
+                32.076605
+              ],
+              [
+                97.293011,
+                32.096887
+              ],
+              [
+                97.313953,
+                32.130342
+              ],
+              [
+                97.271453,
+                32.139971
+              ],
+              [
+                97.264062,
+                32.182527
+              ],
+              [
+                97.299786,
+                32.294904
+              ],
+              [
+                97.32196,
+                32.303503
+              ],
+              [
+                97.371235,
+                32.273148
+              ],
+              [
+                97.415583,
+                32.296421
+              ],
+              [
+                97.424822,
+                32.322723
+              ],
+              [
+                97.387865,
+                32.427349
+              ],
+              [
+                97.341054,
+                32.440987
+              ],
+              [
+                97.388481,
+                32.501575
+              ],
+              [
+                97.334895,
+                32.514192
+              ],
+              [
+                97.332431,
+                32.542448
+              ],
+              [
+                97.3583,
+                32.563635
+              ],
+              [
+                97.374315,
+                32.546484
+              ],
+              [
+                97.411887,
+                32.575235
+              ],
+              [
+                97.448843,
+                32.586833
+              ],
+              [
+                97.463626,
+                32.55506
+              ],
+              [
+                97.50243,
+                32.530844
+              ],
+              [
+                97.540618,
+                32.536899
+              ],
+              [
+                97.670582,
+                32.51722
+              ],
+              [
+                97.684132,
+                32.530339
+              ],
+              [
+                97.730944,
+                32.527312
+              ],
+              [
+                97.700763,
+                32.53488
+              ],
+              [
+                97.616995,
+                32.586329
+              ],
+              [
+                97.607756,
+                32.614059
+              ],
+              [
+                97.543698,
+                32.62162
+              ],
+              [
+                97.535075,
+                32.638252
+              ],
+              [
+                97.48272,
+                32.654377
+              ],
+              [
+                97.42359,
+                32.70475
+              ],
+              [
+                97.429133,
+                32.714318
+              ],
+              [
+                97.386018,
+                32.77925
+              ],
+              [
+                97.392793,
+                32.828546
+              ],
+              [
+                97.376163,
+                32.886359
+              ],
+              [
+                97.347829,
+                32.895907
+              ],
+              [
+                97.375547,
+                32.956689
+              ],
+              [
+                97.438372,
+                32.976271
+              ],
+              [
+                97.523988,
+                32.988822
+              ],
+              [
+                97.499966,
+                33.011408
+              ],
+              [
+                97.542466,
+                33.035995
+              ],
+              [
+                97.517213,
+                33.097683
+              ],
+              [
+                97.487032,
+                33.107209
+              ],
+              [
+                97.498119,
+                33.137783
+              ],
+              [
+                97.487648,
+                33.168346
+              ],
+              [
+                97.548626,
+                33.203907
+              ],
+              [
+                97.607756,
+                33.263976
+              ],
+              [
+                97.622538,
+                33.337005
+              ],
+              [
+                97.676125,
+                33.341004
+              ],
+              [
+                97.754349,
+                33.409972
+              ],
+              [
+                97.674893,
+                33.432949
+              ],
+              [
+                97.625618,
+                33.461412
+              ],
+              [
+                97.552321,
+                33.465906
+              ],
+              [
+                97.511669,
+                33.520805
+              ],
+              [
+                97.523372,
+                33.577166
+              ],
+              [
+                97.450075,
+                33.582152
+              ],
+              [
+                97.415583,
+                33.605582
+              ],
+              [
+                97.435293,
+                33.682307
+              ],
+              [
+                97.418046,
+                33.728608
+              ],
+              [
+                97.422974,
+                33.754984
+              ],
+              [
+                97.406344,
+                33.795278
+              ],
+              [
+                97.373083,
+                33.817655
+              ],
+              [
+                97.371851,
+                33.842015
+              ],
+              [
+                97.398336,
+                33.848477
+              ],
+              [
+                97.395257,
+                33.889224
+              ],
+              [
+                97.460546,
+                33.887236
+              ],
+              [
+                97.503662,
+                33.912073
+              ],
+              [
+                97.52214,
+                33.903133
+              ],
+              [
+                97.601596,
+                33.929951
+              ],
+              [
+                97.629314,
+                33.919523
+              ],
+              [
+                97.660111,
+                33.956264
+              ],
+              [
+                97.652719,
+                33.998448
+              ],
+              [
+                97.70261,
+                34.036644
+              ],
+              [
+                97.665654,
+                34.126855
+              ],
+              [
+                97.766668,
+                34.158555
+              ],
+              [
+                97.789458,
+                34.182818
+              ],
+              [
+                97.789458,
+                34.182818
+              ],
+              [
+                97.796849,
+                34.199154
+              ],
+              [
+                97.796849,
+                34.199154
+              ],
+              [
+                97.8104,
+                34.207568
+              ],
+              [
+                97.898479,
+                34.209548
+              ],
+              [
+                97.95453,
+                34.190739
+              ],
+              [
+                98.028442,
+                34.122892
+              ],
+              [
+                98.098043,
+                34.122892
+              ],
+              [
+                98.158405,
+                34.107037
+              ],
+              [
+                98.206449,
+                34.08424
+              ],
+              [
+                98.258188,
+                34.083249
+              ],
+              [
+                98.344419,
+                34.094648
+              ],
+              [
+                98.399854,
+                34.085231
+              ],
+              [
+                98.396774,
+                34.053008
+              ],
+              [
+                98.428187,
+                34.029204
+              ],
+              [
+                98.440506,
+                33.981577
+              ],
+              [
+                98.415252,
+                33.956761
+              ],
+              [
+                98.425723,
+                33.913066
+              ],
+              [
+                98.407245,
+                33.867362
+              ],
+              [
+                98.434962,
+                33.843009
+              ],
+              [
+                98.463295,
+                33.848477
+              ],
+              [
+                98.492861,
+                33.796272
+              ],
+              [
+                98.494092,
+                33.768915
+              ],
+              [
+                98.51873,
+                33.77389
+              ],
+              [
+                98.539672,
+                33.746525
+              ],
+              [
+                98.582788,
+                33.731595
+              ],
+              [
+                98.610505,
+                33.682805
+              ],
+              [
+                98.6567,
+                33.64744
+              ],
+              [
+                98.61728,
+                33.637476
+              ],
+              [
+                98.622824,
+                33.610067
+              ],
+              [
+                98.652389,
+                33.595114
+              ],
+              [
+                98.648077,
+                33.548741
+              ],
+              [
+                98.678258,
+                33.522801
+              ],
+              [
+                98.725686,
+                33.503341
+              ],
+              [
+                98.742316,
+                33.477887
+              ],
+              [
+                98.736157,
+                33.406975
+              ],
+              [
+                98.779888,
+                33.370497
+              ],
+              [
+                98.759562,
+                33.276985
+              ],
+              [
+                98.802062,
+                33.270481
+              ],
+              [
+                98.804526,
+                33.219428
+              ],
+              [
+                98.858728,
+                33.150811
+              ],
+              [
+                98.92217,
+                33.118738
+              ],
+              [
+                98.967134,
+                33.115229
+              ],
+              [
+                98.971445,
+                33.098185
+              ],
+              [
+                99.014561,
+                33.081137
+              ],
+              [
+                99.024416,
+                33.094675
+              ],
+              [
+                99.090322,
+                33.079131
+              ],
+              [
+                99.124814,
+                33.046028
+              ],
+              [
+                99.196263,
+                33.035493
+              ],
+              [
+                99.214741,
+                32.991332
+              ],
+              [
+                99.235067,
+                32.982296
+              ],
+              [
+                99.24677,
+                32.924043
+              ],
+              [
+                99.268944,
+                32.878318
+              ],
+              [
+                99.353944,
+                32.885354
+              ],
+              [
+                99.376118,
+                32.899927
+              ],
+              [
+                99.45311,
+                32.862233
+              ],
+              [
+                99.558436,
+                32.839106
+              ],
+              [
+                99.589233,
+                32.789312
+              ],
+              [
+                99.640355,
+                32.790822
+              ],
+              [
+                99.646515,
+                32.774721
+              ],
+              [
+                99.700718,
+                32.76667
+              ],
+              [
+                99.717964,
+                32.732443
+              ],
+              [
+                99.760464,
+                32.769689
+              ],
+              [
+                99.766623,
+                32.826032
+              ],
+              [
+                99.791877,
+                32.883344
+              ],
+              [
+                99.764159,
+                32.924545
+              ],
+              [
+                99.788181,
+                32.956689
+              ],
+              [
+                99.805427,
+                32.940619
+              ],
+              [
+                99.851007,
+                32.941623
+              ],
+              [
+                99.877492,
+                32.993339
+              ],
+              [
+                99.877492,
+                33.045527
+              ],
+              [
+                99.947709,
+                32.986814
+              ],
+              [
+                99.956332,
+                32.948152
+              ],
+              [
+                100.038252,
+                32.929066
+              ],
+              [
+                100.029629,
+                32.895907
+              ],
+              [
+                100.064738,
+                32.895907
+              ],
+              [
+                100.123252,
+                32.837095
+              ],
+              [
+                100.117093,
+                32.802392
+              ],
+              [
+                100.139266,
+                32.724388
+              ],
+              [
+                100.088143,
+                32.668988
+              ],
+              [
+                100.109701,
+                32.640268
+              ],
+              [
+                100.189773,
+                32.630692
+              ],
+              [
+                100.208252,
+                32.606497
+              ],
+              [
+                100.229809,
+                32.650346
+              ],
+              [
+                100.231041,
+                32.696189
+              ],
+              [
+                100.258759,
+                32.742511
+              ],
+              [
+                100.339447,
+                32.719353
+              ],
+              [
+                100.399193,
+                32.756101
+              ],
+              [
+                100.378251,
+                32.698707
+              ],
+              [
+                100.420135,
+                32.73194
+              ],
+              [
+                100.450932,
+                32.694678
+              ],
+              [
+                100.470026,
+                32.694678
+              ],
+              [
+                100.516837,
+                32.632204
+              ],
+              [
+                100.54517,
+                32.569687
+              ],
+              [
+                100.603069,
+                32.553547
+              ],
+              [
+                100.645568,
+                32.526303
+              ],
+              [
+                100.657887,
+                32.546484
+              ],
+              [
+                100.661583,
+                32.616075
+              ],
+              [
+                100.673286,
+                32.628172
+              ],
+              [
+                100.710242,
+                32.610026
+              ],
+              [
+                100.71209,
+                32.645307
+              ],
+              [
+                100.690532,
+                32.678056
+              ],
+              [
+                100.77122,
+                32.643795
+              ],
+              [
+                100.834046,
+                32.648835
+              ],
+              [
+                100.887633,
+                32.632708
+              ],
+              [
+                100.93198,
+                32.600447
+              ],
+              [
+                100.956618,
+                32.621116
+              ],
+              [
+                100.99727,
+                32.627668
+              ],
+              [
+                101.030531,
+                32.660424
+              ],
+              [
+                101.077342,
+                32.68259
+              ],
+              [
+                101.124769,
+                32.658408
+              ],
+              [
+                101.157414,
+                32.661431
+              ],
+              [
+                101.22332,
+                32.725898
+              ],
+              [
+                101.237486,
+                32.825026
+              ],
+              [
+                101.223935,
+                32.855698
+              ],
+              [
+                101.178356,
+                32.892892
+              ],
+              [
+                101.124153,
+                32.909976
+              ],
+              [
+                101.134624,
+                32.95217
+              ],
+              [
+                101.129081,
+                32.989324
+              ],
+              [
+                101.183899,
+                32.984304
+              ],
+              [
+                101.171581,
+                33.009902
+              ],
+              [
+                101.184515,
+                33.041514
+              ],
+              [
+                101.146327,
+                33.056563
+              ],
+              [
+                101.143863,
+                33.086151
+              ],
+              [
+                101.169733,
+                33.10019
+              ],
+              [
+                101.11553,
+                33.194893
+              ],
+              [
+                101.124769,
+                33.221431
+              ],
+              [
+                101.156798,
+                33.236449
+              ],
+              [
+                101.182668,
+                33.26948
+              ],
+              [
+                101.217776,
+                33.256469
+              ],
+              [
+                101.297232,
+                33.262475
+              ],
+              [
+                101.381616,
+                33.153316
+              ],
+              [
+                101.393935,
+                33.157826
+              ],
+              [
+                101.386543,
+                33.207412
+              ],
+              [
+                101.403174,
+                33.225436
+              ],
+              [
+                101.487557,
+                33.226938
+              ],
+              [
+                101.515275,
+                33.192889
+              ],
+              [
+                101.557775,
+                33.167344
+              ],
+              [
+                101.633535,
+                33.101193
+              ],
+              [
+                101.661252,
+                33.135778
+              ],
+              [
+                101.653861,
+                33.162835
+              ],
+              [
+                101.709912,
+                33.21292
+              ],
+              [
+                101.735781,
+                33.279987
+              ],
+              [
+                101.677883,
+                33.297497
+              ],
+              [
+                101.64955,
+                33.323004
+              ],
+              [
+                101.663716,
+                33.383991
+              ],
+              [
+                101.695745,
+                33.433948
+              ],
+              [
+                101.769042,
+                33.45592
+              ],
+              [
+                101.777665,
+                33.533776
+              ],
+              [
+                101.769042,
+                33.538765
+              ],
+              [
+                101.748716,
+                33.505337
+              ],
+              [
+                101.718535,
+                33.494857
+              ],
+              [
+                101.622448,
+                33.502343
+              ],
+              [
+                101.611977,
+                33.565199
+              ],
+              [
+                101.616905,
+                33.598603
+              ],
+              [
+                101.585492,
+                33.645448
+              ],
+              [
+                101.58426,
+                33.674339
+              ],
+              [
+                101.501724,
+                33.702723
+              ],
+              [
+                101.428427,
+                33.680315
+              ],
+              [
+                101.424732,
+                33.655411
+              ],
+              [
+                101.385312,
+                33.644949
+              ],
+              [
+                101.302776,
+                33.657902
+              ],
+              [
+                101.23687,
+                33.685793
+              ],
+              [
+                101.217776,
+                33.669856
+              ],
+              [
+                101.166653,
+                33.659894
+              ],
+              [
+                101.177124,
+                33.685295
+              ],
+              [
+                101.162957,
+                33.719649
+              ],
+              [
+                101.186363,
+                33.741051
+              ],
+              [
+                101.190675,
+                33.791796
+              ],
+              [
+                101.153102,
+                33.823124
+              ],
+              [
+                101.153718,
+                33.8445
+              ],
+              [
+                101.054552,
+                33.863386
+              ],
+              [
+                101.023139,
+                33.896178
+              ],
+              [
+                100.994806,
+                33.891707
+              ],
+              [
+                100.965857,
+                33.946832
+              ],
+              [
+                100.927669,
+                33.975126
+              ],
+              [
+                100.93506,
+                33.990013
+              ],
+              [
+                100.880857,
+                34.036644
+              ],
+              [
+                100.870386,
+                34.083744
+              ],
+              [
+                100.848828,
+                34.089692
+              ],
+              [
+                100.806329,
+                34.155584
+              ],
+              [
+                100.764445,
+                34.178857
+              ],
+              [
+                100.809408,
+                34.247153
+              ],
+              [
+                100.798321,
+                34.260014
+              ],
+              [
+                100.821727,
+                34.317371
+              ],
+              [
+                100.868538,
+                34.332693
+              ],
+              [
+                100.895024,
+                34.375183
+              ],
+              [
+                100.951074,
+                34.38358
+              ],
+              [
+                100.986799,
+                34.374689
+              ],
+              [
+                101.054552,
+                34.322808
+              ],
+              [
+                101.098284,
+                34.329233
+              ],
+              [
+                101.178356,
+                34.320831
+              ],
+              [
+                101.193754,
+                34.336646
+              ],
+              [
+                101.235022,
+                34.325279
+              ],
+              [
+                101.228863,
+                34.298586
+              ],
+              [
+                101.268899,
+                34.278808
+              ],
+              [
+                101.325565,
+                34.268423
+              ],
+              [
+                101.327413,
+                34.24468
+              ],
+              [
+                101.369913,
+                34.248143
+              ],
+              [
+                101.417956,
+                34.227858
+              ],
+              [
+                101.482014,
+                34.218951
+              ],
+              [
+                101.492485,
+                34.195689
+              ],
+              [
+                101.53868,
+                34.212022
+              ],
+              [
+                101.6206,
+                34.178857
+              ],
+              [
+                101.674187,
+                34.110506
+              ],
+              [
+                101.703136,
+                34.119424
+              ],
+              [
+                101.718535,
+                34.083249
+              ],
+              [
+                101.736397,
+                34.080275
+              ],
+              [
+                101.764114,
+                34.122892
+              ],
+              [
+                101.788136,
+                34.131809
+              ],
+              [
+                101.836795,
+                34.124378
+              ],
+              [
+                101.851578,
+                34.153108
+              ],
+              [
+                101.874367,
+                34.130323
+              ],
+              [
+                101.897773,
+                34.133791
+              ],
+              [
+                101.955055,
+                34.109514
+              ],
+              [
+                101.965526,
+                34.167469
+              ],
+              [
+                102.003099,
+                34.162022
+              ],
+              [
+                102.030816,
+                34.190739
+              ],
+              [
+                102.01357,
+                34.218456
+              ],
+              [
+                102.062229,
+                34.227858
+              ],
+              [
+                102.067772,
+                34.293642
+              ],
+              [
+                102.149692,
+                34.271885
+              ],
+              [
+                102.186649,
+                34.352952
+              ],
+              [
+                102.237156,
+                34.34307
+              ],
+              [
+                102.237156,
+                34.34307
+              ],
+              [
+                102.259329,
+                34.355917
+              ],
+              [
+                102.205743,
+                34.407777
+              ],
+              [
+                102.169402,
+                34.457631
+              ],
+              [
+                102.155852,
+                34.507456
+              ],
+              [
+                102.139837,
+                34.50351
+              ],
+              [
+                102.093026,
+                34.536547
+              ],
+              [
+                102.001867,
+                34.538519
+              ],
+              [
+                101.97415,
+                34.548871
+              ],
+              [
+                101.956287,
+                34.582876
+              ],
+              [
+                101.934729,
+                34.58731
+              ],
+              [
+                101.919947,
+                34.621791
+              ],
+              [
+                101.917483,
+                34.705964
+              ],
+              [
+                101.923027,
+                34.835746
+              ],
+              [
+                101.916867,
+                34.873561
+              ],
+              [
+                101.985852,
+                34.90007
+              ],
+              [
+                102.068388,
+                34.887798
+              ],
+              [
+                102.048062,
+                34.910868
+              ],
+              [
+                102.094874,
+                34.986901
+              ],
+              [
+                102.133678,
+                35.014844
+              ],
+              [
+                102.157699,
+                35.010923
+              ],
+              [
+                102.176178,
+                35.032977
+              ],
+              [
+                102.211286,
+                35.034937
+              ],
+              [
+                102.218062,
+                35.057475
+              ],
+              [
+                102.252554,
+                35.048657
+              ],
+              [
+                102.29567,
+                35.071681
+              ],
+              [
+                102.310452,
+                35.128967
+              ],
+              [
+                102.346793,
+                35.164201
+              ],
+              [
+                102.404075,
+                35.179366
+              ],
+              [
+                102.365887,
+                35.235599
+              ],
+              [
+                102.370199,
+                35.263946
+              ],
+              [
+                102.3123,
+                35.282512
+              ],
+              [
+                102.280887,
+                35.303028
+              ],
+              [
+                102.311684,
+                35.31426
+              ],
+              [
+                102.317844,
+                35.343067
+              ],
+              [
+                102.287663,
+                35.36552
+              ],
+              [
+                102.293822,
+                35.424063
+              ],
+              [
+                102.314764,
+                35.434303
+              ],
+              [
+                102.408387,
+                35.409431
+              ],
+              [
+                102.447807,
+                35.437229
+              ],
+              [
+                102.437952,
+                35.455268
+              ],
+              [
+                102.49893,
+                35.545403
+              ],
+              [
+                102.503241,
+                35.585322
+              ],
+              [
+                102.531575,
+                35.580455
+              ],
+              [
+                102.570995,
+                35.548324
+              ],
+              [
+                102.695414,
+                35.528358
+              ],
+              [
+                102.743458,
+                35.494745
+              ],
+              [
+                102.782878,
+                35.527871
+              ],
+              [
+                102.729291,
+                35.523487
+              ],
+              [
+                102.746537,
+                35.545403
+              ],
+              [
+                102.808747,
+                35.560496
+              ],
+              [
+                102.763168,
+                35.612086
+              ],
+              [
+                102.7644,
+                35.653431
+              ],
+              [
+                102.744074,
+                35.657807
+              ],
+              [
+                102.707733,
+                35.70496
+              ],
+              [
+                102.686175,
+                35.771996
+              ],
+              [
+                102.715125,
+                35.815685
+              ],
+              [
+                102.739146,
+                35.821023
+              ],
+              [
+                102.787189,
+                35.862745
+              ],
+              [
+                102.81737,
+                35.850133
+              ],
+              [
+                102.914073,
+                35.845282
+              ],
+              [
+                102.94487,
+                35.829757
+              ],
+              [
+                102.954725,
+                35.858864
+              ],
+              [
+                102.942406,
+                35.92674
+              ],
+              [
+                102.971971,
+                35.995525
+              ],
+              [
+                102.951645,
+                36.021667
+              ],
+              [
+                102.968276,
+                36.044414
+              ],
+              [
+                102.932551,
+                36.048285
+              ],
+              [
+                102.882044,
+                36.082632
+              ],
+              [
+                102.941174,
+                36.104877
+              ],
+              [
+                102.948566,
+                36.150798
+              ],
+              [
+                102.965812,
+                36.151765
+              ],
+              [
+                102.986754,
+                36.193312
+              ],
+              [
+                103.048964,
+                36.199107
+              ],
+              [
+                103.066826,
+                36.216974
+              ],
+              [
+                103.021246,
+                36.232906
+              ],
+              [
+                103.024942,
+                36.256556
+              ],
+              [
+                102.922696,
+                36.298047
+              ],
+              [
+                102.896827,
+                36.331803
+              ],
+              [
+                102.845704,
+                36.331803
+              ],
+              [
+                102.836465,
+                36.344819
+              ],
+              [
+                102.829689,
+                36.365544
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 640000,
+        "name": "瀹佸鍥炴棌鑷不鍖�",
+        "center": [
+          106.278179,
+          38.46637
+        ],
+        "centroid": [
+          106.169866,
+          37.291332
+        ],
+        "childrenNum": 5,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 29,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                107.268764,
+                37.099367
+              ],
+              [
+                107.281083,
+                37.127047
+              ],
+              [
+                107.306952,
+                37.100799
+              ],
+              [
+                107.334669,
+                37.138975
+              ],
+              [
+                107.336517,
+                37.165687
+              ],
+              [
+                107.317423,
+                37.200017
+              ],
+              [
+                107.270612,
+                37.229089
+              ],
+              [
+                107.309416,
+                37.239095
+              ],
+              [
+                107.273075,
+                37.29101
+              ],
+              [
+                107.257677,
+                37.337179
+              ],
+              [
+                107.282931,
+                37.437036
+              ],
+              [
+                107.284162,
+                37.481691
+              ],
+              [
+                107.345756,
+                37.518725
+              ],
+              [
+                107.369162,
+                37.58752
+              ],
+              [
+                107.330358,
+                37.584201
+              ],
+              [
+                107.311264,
+                37.609806
+              ],
+              [
+                107.361155,
+                37.613125
+              ],
+              [
+                107.422133,
+                37.665254
+              ],
+              [
+                107.389488,
+                37.671413
+              ],
+              [
+                107.387024,
+                37.691305
+              ],
+              [
+                107.425828,
+                37.684201
+              ],
+              [
+                107.484959,
+                37.706458
+              ],
+              [
+                107.499125,
+                37.765619
+              ],
+              [
+                107.57119,
+                37.776499
+              ],
+              [
+                107.599523,
+                37.791162
+              ],
+              [
+                107.620465,
+                37.776026
+              ],
+              [
+                107.646335,
+                37.805349
+              ],
+              [
+                107.659269,
+                37.844112
+              ],
+              [
+                107.65003,
+                37.86443
+              ],
+              [
+                107.560719,
+                37.893717
+              ],
+              [
+                107.49235,
+                37.944706
+              ],
+              [
+                107.448618,
+                37.933378
+              ],
+              [
+                107.411662,
+                37.948009
+              ],
+              [
+                107.440611,
+                37.995659
+              ],
+              [
+                107.3938,
+                38.014993
+              ],
+              [
+                107.33159,
+                38.086625
+              ],
+              [
+                107.240431,
+                38.111586
+              ],
+              [
+                107.19054,
+                38.153953
+              ],
+              [
+                107.138801,
+                38.161011
+              ],
+              [
+                107.119091,
+                38.134185
+              ],
+              [
+                107.071047,
+                38.138892
+              ],
+              [
+                107.051337,
+                38.122886
+              ],
+              [
+                107.010069,
+                38.120532
+              ],
+              [
+                106.942316,
+                38.132302
+              ],
+              [
+                106.858548,
+                38.156306
+              ],
+              [
+                106.779092,
+                38.171833
+              ],
+              [
+                106.737824,
+                38.197706
+              ],
+              [
+                106.654672,
+                38.22921
+              ],
+              [
+                106.627571,
+                38.232501
+              ],
+              [
+                106.555506,
+                38.263521
+              ],
+              [
+                106.482209,
+                38.319417
+              ],
+              [
+                106.599854,
+                38.389812
+              ],
+              [
+                106.647897,
+                38.470917
+              ],
+              [
+                106.66268,
+                38.601524
+              ],
+              [
+                106.709491,
+                38.718821
+              ],
+              [
+                106.756302,
+                38.748699
+              ],
+              [
+                106.837606,
+                38.847579
+              ],
+              [
+                106.954019,
+                38.941202
+              ],
+              [
+                106.971881,
+                39.026333
+              ],
+              [
+                106.96757,
+                39.054688
+              ],
+              [
+                106.933693,
+                39.076527
+              ],
+              [
+                106.878874,
+                39.091392
+              ],
+              [
+                106.859164,
+                39.107648
+              ],
+              [
+                106.825288,
+                39.19397
+              ],
+              [
+                106.795723,
+                39.214375
+              ],
+              [
+                106.790795,
+                39.241263
+              ],
+              [
+                106.806193,
+                39.277407
+              ],
+              [
+                106.806809,
+                39.318625
+              ],
+              [
+                106.781556,
+                39.371849
+              ],
+              [
+                106.751375,
+                39.381564
+              ],
+              [
+                106.683622,
+                39.357506
+              ],
+              [
+                106.643586,
+                39.357969
+              ],
+              [
+                106.602318,
+                39.37555
+              ],
+              [
+                106.556122,
+                39.322329
+              ],
+              [
+                106.525325,
+                39.308439
+              ],
+              [
+                106.511774,
+                39.272311
+              ],
+              [
+                106.402753,
+                39.291767
+              ],
+              [
+                106.280181,
+                39.262118
+              ],
+              [
+                106.29558,
+                39.167992
+              ],
+              [
+                106.285109,
+                39.146181
+              ],
+              [
+                106.251232,
+                39.131327
+              ],
+              [
+                106.192718,
+                39.142932
+              ],
+              [
+                106.170544,
+                39.163352
+              ],
+              [
+                106.145907,
+                39.153142
+              ],
+              [
+                106.096631,
+                39.084889
+              ],
+              [
+                106.078153,
+                39.026333
+              ],
+              [
+                106.087392,
+                39.006339
+              ],
+              [
+                106.060907,
+                38.96866
+              ],
+              [
+                106.021487,
+                38.953769
+              ],
+              [
+                105.97098,
+                38.909077
+              ],
+              [
+                105.992538,
+                38.857366
+              ],
+              [
+                105.909386,
+                38.791159
+              ],
+              [
+                105.908154,
+                38.737496
+              ],
+              [
+                105.88598,
+                38.716953
+              ],
+              [
+                105.894603,
+                38.696405
+              ],
+              [
+                105.852719,
+                38.641735
+              ],
+              [
+                105.874277,
+                38.593105
+              ],
+              [
+                105.856415,
+                38.569714
+              ],
+              [
+                105.863806,
+                38.53508
+              ],
+              [
+                105.836705,
+                38.476071
+              ],
+              [
+                105.850872,
+                38.443736
+              ],
+              [
+                105.827466,
+                38.432486
+              ],
+              [
+                105.835473,
+                38.387467
+              ],
+              [
+                105.821307,
+                38.366824
+              ],
+              [
+                105.86627,
+                38.296406
+              ],
+              [
+                105.842248,
+                38.240962
+              ],
+              [
+                105.802828,
+                38.220277
+              ],
+              [
+                105.775111,
+                38.186887
+              ],
+              [
+                105.76772,
+                38.121474
+              ],
+              [
+                105.780655,
+                38.084741
+              ],
+              [
+                105.840401,
+                38.004147
+              ],
+              [
+                105.799749,
+                37.939986
+              ],
+              [
+                105.80406,
+                37.862068
+              ],
+              [
+                105.760944,
+                37.799674
+              ],
+              [
+                105.677177,
+                37.771769
+              ],
+              [
+                105.622358,
+                37.777919
+              ],
+              [
+                105.616199,
+                37.722555
+              ],
+              [
+                105.598952,
+                37.699356
+              ],
+              [
+                105.467141,
+                37.695094
+              ],
+              [
+                105.4037,
+                37.710246
+              ],
+              [
+                105.315004,
+                37.702197
+              ],
+              [
+                105.221998,
+                37.677097
+              ],
+              [
+                105.187505,
+                37.657674
+              ],
+              [
+                105.111128,
+                37.633981
+              ],
+              [
+                105.027977,
+                37.580881
+              ],
+              [
+                104.866601,
+                37.566651
+              ],
+              [
+                104.805007,
+                37.539133
+              ],
+              [
+                104.623305,
+                37.522522
+              ],
+              [
+                104.433595,
+                37.515402
+              ],
+              [
+                104.419429,
+                37.511604
+              ],
+              [
+                104.407726,
+                37.464592
+              ],
+              [
+                104.322726,
+                37.44844
+              ],
+              [
+                104.287002,
+                37.428007
+              ],
+              [
+                104.298705,
+                37.414223
+              ],
+              [
+                104.365226,
+                37.418026
+              ],
+              [
+                104.437907,
+                37.445589
+              ],
+              [
+                104.448994,
+                37.42468
+              ],
+              [
+                104.499501,
+                37.421353
+              ],
+              [
+                104.521059,
+                37.43466
+              ],
+              [
+                104.679971,
+                37.408044
+              ],
+              [
+                104.662109,
+                37.367626
+              ],
+              [
+                104.713848,
+                37.329566
+              ],
+              [
+                104.673812,
+                37.317668
+              ],
+              [
+                104.651022,
+                37.290534
+              ],
+              [
+                104.624536,
+                37.298627
+              ],
+              [
+                104.600515,
+                37.242907
+              ],
+              [
+                104.638087,
+                37.201923
+              ],
+              [
+                104.717543,
+                37.208597
+              ],
+              [
+                104.776673,
+                37.246718
+              ],
+              [
+                104.85613,
+                37.211933
+              ],
+              [
+                104.864753,
+                37.17284
+              ],
+              [
+                104.888158,
+                37.15901
+              ],
+              [
+                104.914644,
+                37.097935
+              ],
+              [
+                104.954064,
+                37.077407
+              ],
+              [
+                104.95468,
+                37.040156
+              ],
+              [
+                105.004571,
+                37.035378
+              ],
+              [
+                105.03968,
+                37.007187
+              ],
+              [
+                105.05939,
+                37.022956
+              ],
+              [
+                105.128991,
+                36.996194
+              ],
+              [
+                105.165331,
+                36.99476
+              ],
+              [
+                105.185657,
+                36.942164
+              ],
+              [
+                105.178882,
+                36.892403
+              ],
+              [
+                105.244787,
+                36.894796
+              ],
+              [
+                105.279896,
+                36.86751
+              ],
+              [
+                105.303302,
+                36.820575
+              ],
+              [
+                105.334714,
+                36.80093
+              ],
+              [
+                105.340874,
+                36.764502
+              ],
+              [
+                105.319932,
+                36.742924
+              ],
+              [
+                105.275584,
+                36.752515
+              ],
+              [
+                105.272505,
+                36.739567
+              ],
+              [
+                105.218302,
+                36.730455
+              ],
+              [
+                105.201056,
+                36.700711
+              ],
+              [
+                105.225693,
+                36.664716
+              ],
+              [
+                105.22015,
+                36.631105
+              ],
+              [
+                105.261418,
+                36.602764
+              ],
+              [
+                105.2762,
+                36.563358
+              ],
+              [
+                105.252179,
+                36.553263
+              ],
+              [
+                105.281744,
+                36.522489
+              ],
+              [
+                105.322396,
+                36.535954
+              ],
+              [
+                105.362432,
+                36.496514
+              ],
+              [
+                105.363048,
+                36.443093
+              ],
+              [
+                105.398156,
+                36.430575
+              ],
+              [
+                105.401236,
+                36.369881
+              ],
+              [
+                105.425873,
+                36.330357
+              ],
+              [
+                105.455439,
+                36.321678
+              ],
+              [
+                105.476381,
+                36.293224
+              ],
+              [
+                105.45975,
+                36.268137
+              ],
+              [
+                105.460366,
+                36.223733
+              ],
+              [
+                105.478844,
+                36.213111
+              ],
+              [
+                105.515185,
+                36.147415
+              ],
+              [
+                105.491163,
+                36.101009
+              ],
+              [
+                105.430801,
+                36.10391
+              ],
+              [
+                105.406163,
+                36.074409
+              ],
+              [
+                105.343954,
+                36.033767
+              ],
+              [
+                105.324859,
+                35.941761
+              ],
+              [
+                105.350113,
+                35.875839
+              ],
+              [
+                105.39754,
+                35.857409
+              ],
+              [
+                105.371055,
+                35.844312
+              ],
+              [
+                105.38091,
+                35.792873
+              ],
+              [
+                105.408627,
+                35.822479
+              ],
+              [
+                105.428953,
+                35.819082
+              ],
+              [
+                105.432033,
+                35.787533
+              ],
+              [
+                105.457286,
+                35.771511
+              ],
+              [
+                105.481924,
+                35.727312
+              ],
+              [
+                105.595873,
+                35.715651
+              ],
+              [
+                105.667322,
+                35.749657
+              ],
+              [
+                105.70243,
+                35.733142
+              ],
+              [
+                105.759097,
+                35.724883
+              ],
+              [
+                105.740618,
+                35.698643
+              ],
+              [
+                105.723988,
+                35.725854
+              ],
+              [
+                105.690727,
+                35.698643
+              ],
+              [
+                105.722756,
+                35.673366
+              ],
+              [
+                105.713517,
+                35.650513
+              ],
+              [
+                105.759097,
+                35.634464
+              ],
+              [
+                105.762176,
+                35.602841
+              ],
+              [
+                105.800365,
+                35.564878
+              ],
+              [
+                105.816379,
+                35.575101
+              ],
+              [
+                105.847176,
+                35.490359
+              ],
+              [
+                105.868734,
+                35.540046
+              ],
+              [
+                105.900147,
+                35.54735
+              ],
+              [
+                106.017175,
+                35.519103
+              ],
+              [
+                106.023335,
+                35.49377
+              ],
+              [
+                106.047356,
+                35.498155
+              ],
+              [
+                106.078769,
+                35.509848
+              ],
+              [
+                106.071994,
+                35.463555
+              ],
+              [
+                106.06953,
+                35.458193
+              ],
+              [
+                106.073842,
+                35.45478
+              ],
+              [
+                106.073226,
+                35.450393
+              ],
+              [
+                106.071378,
+                35.449418
+              ],
+              [
+                106.073226,
+                35.447468
+              ],
+              [
+                106.083081,
+                35.421624
+              ],
+              [
+                106.113262,
+                35.361616
+              ],
+              [
+                106.129892,
+                35.393333
+              ],
+              [
+                106.173008,
+                35.437716
+              ],
+              [
+                106.196414,
+                35.409919
+              ],
+              [
+                106.237681,
+                35.409431
+              ],
+              [
+                106.241377,
+                35.358687
+              ],
+              [
+                106.319601,
+                35.265411
+              ],
+              [
+                106.363333,
+                35.238532
+              ],
+              [
+                106.368261,
+                35.273718
+              ],
+              [
+                106.415688,
+                35.276161
+              ],
+              [
+                106.472354,
+                35.310842
+              ],
+              [
+                106.501304,
+                35.364056
+              ],
+              [
+                106.503767,
+                35.415284
+              ],
+              [
+                106.483441,
+                35.450393
+              ],
+              [
+                106.490217,
+                35.480613
+              ],
+              [
+                106.465579,
+                35.481101
+              ],
+              [
+                106.440941,
+                35.52641
+              ],
+              [
+                106.460036,
+                35.578995
+              ],
+              [
+                106.47913,
+                35.575101
+              ],
+              [
+                106.460036,
+                35.643705
+              ],
+              [
+                106.434782,
+                35.688436
+              ],
+              [
+                106.49268,
+                35.732656
+              ],
+              [
+                106.506231,
+                35.737514
+              ],
+              [
+                106.566593,
+                35.738971
+              ],
+              [
+                106.595542,
+                35.727312
+              ],
+              [
+                106.620796,
+                35.743829
+              ],
+              [
+                106.633115,
+                35.714679
+              ],
+              [
+                106.66268,
+                35.70739
+              ],
+              [
+                106.674998,
+                35.728284
+              ],
+              [
+                106.750759,
+                35.689408
+              ],
+              [
+                106.750759,
+                35.725369
+              ],
+              [
+                106.806193,
+                35.70982
+              ],
+              [
+                106.819128,
+                35.7448
+              ],
+              [
+                106.867171,
+                35.738485
+              ],
+              [
+                106.868403,
+                35.771996
+              ],
+              [
+                106.897353,
+                35.759856
+              ],
+              [
+                106.927534,
+                35.810346
+              ],
+              [
+                106.849925,
+                35.887476
+              ],
+              [
+                106.912751,
+                35.93207
+              ],
+              [
+                106.940468,
+                35.931101
+              ],
+              [
+                106.93862,
+                35.952905
+              ],
+              [
+                106.90228,
+                35.943699
+              ],
+              [
+                106.94786,
+                35.988262
+              ],
+              [
+                106.928149,
+                36.011502
+              ],
+              [
+                106.940468,
+                36.064734
+              ],
+              [
+                106.957715,
+                36.091337
+              ],
+              [
+                106.925686,
+                36.115997
+              ],
+              [
+                106.930613,
+                36.138716
+              ],
+              [
+                106.873947,
+                36.178338
+              ],
+              [
+                106.873947,
+                36.178338
+              ],
+              [
+                106.858548,
+                36.206834
+              ],
+              [
+                106.858548,
+                36.206834
+              ],
+              [
+                106.833295,
+                36.229044
+              ],
+              [
+                106.808657,
+                36.21118
+              ],
+              [
+                106.772933,
+                36.212628
+              ],
+              [
+                106.735976,
+                36.23725
+              ],
+              [
+                106.698404,
+                36.244008
+              ],
+              [
+                106.685469,
+                36.273445
+              ],
+              [
+                106.647897,
+                36.259451
+              ],
+              [
+                106.559202,
+                36.292259
+              ],
+              [
+                106.54134,
+                36.25366
+              ],
+              [
+                106.504383,
+                36.266207
+              ],
+              [
+                106.470507,
+                36.306246
+              ],
+              [
+                106.497608,
+                36.31348
+              ],
+              [
+                106.510543,
+                36.379037
+              ],
+              [
+                106.492064,
+                36.422389
+              ],
+              [
+                106.523477,
+                36.468605
+              ],
+              [
+                106.494528,
+                36.494589
+              ],
+              [
+                106.455724,
+                36.496995
+              ],
+              [
+                106.39721,
+                36.548455
+              ],
+              [
+                106.37134,
+                36.549417
+              ],
+              [
+                106.363949,
+                36.577296
+              ],
+              [
+                106.392282,
+                36.556628
+              ],
+              [
+                106.397826,
+                36.576816
+              ],
+              [
+                106.444637,
+                36.557109
+              ],
+              [
+                106.465579,
+                36.583063
+              ],
+              [
+                106.444637,
+                36.624861
+              ],
+              [
+                106.491448,
+                36.628703
+              ],
+              [
+                106.490833,
+                36.685835
+              ],
+              [
+                106.530869,
+                36.690154
+              ],
+              [
+                106.519782,
+                36.708868
+              ],
+              [
+                106.519782,
+                36.708868
+              ],
+              [
+                106.514238,
+                36.715584
+              ],
+              [
+                106.59431,
+                36.750118
+              ],
+              [
+                106.644817,
+                36.72278
+              ],
+              [
+                106.627571,
+                36.752995
+              ],
+              [
+                106.657752,
+                36.820575
+              ],
+              [
+                106.637426,
+                36.867031
+              ],
+              [
+                106.637426,
+                36.867031
+              ],
+              [
+                106.626955,
+                36.892403
+              ],
+              [
+                106.609709,
+                36.878521
+              ],
+              [
+                106.609709,
+                36.878521
+              ],
+              [
+                106.601702,
+                36.918244
+              ],
+              [
+                106.549347,
+                36.941685
+              ],
+              [
+                106.540108,
+                36.984244
+              ],
+              [
+                106.595542,
+                36.94025
+              ],
+              [
+                106.594926,
+                36.967988
+              ],
+              [
+                106.64297,
+                36.962729
+              ],
+              [
+                106.646665,
+                37.000496
+              ],
+              [
+                106.666991,
+                37.016745
+              ],
+              [
+                106.645433,
+                37.064992
+              ],
+              [
+                106.605397,
+                37.127524
+              ],
+              [
+                106.6171,
+                37.135158
+              ],
+              [
+                106.673151,
+                37.1113
+              ],
+              [
+                106.687933,
+                37.12991
+              ],
+              [
+                106.728585,
+                37.121321
+              ],
+              [
+                106.750143,
+                37.09889
+              ],
+              [
+                106.772933,
+                37.120367
+              ],
+              [
+                106.776012,
+                37.158056
+              ],
+              [
+                106.818512,
+                37.141838
+              ],
+              [
+                106.891193,
+                37.098413
+              ],
+              [
+                106.912135,
+                37.110345
+              ],
+              [
+                106.905976,
+                37.151378
+              ],
+              [
+                106.998367,
+                37.106527
+              ],
+              [
+                107.031011,
+                37.108436
+              ],
+              [
+                107.030395,
+                37.140883
+              ],
+              [
+                107.095685,
+                37.115595
+              ],
+              [
+                107.133873,
+                37.134681
+              ],
+              [
+                107.181916,
+                37.143269
+              ],
+              [
+                107.234887,
+                37.096503
+              ],
+              [
+                107.268764,
+                37.099367
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.048588,
+                35.488898
+              ],
+              [
+                105.897683,
+                35.451368
+              ],
+              [
+                105.894603,
+                35.413821
+              ],
+              [
+                106.002393,
+                35.438692
+              ],
+              [
+                106.034422,
+                35.469404
+              ],
+              [
+                106.054132,
+                35.45478
+              ],
+              [
+                106.048588,
+                35.488898
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                106.073842,
+                35.45478
+              ],
+              [
+                106.06953,
+                35.458193
+              ],
+              [
+                106.071378,
+                35.449418
+              ],
+              [
+                106.073226,
+                35.450393
+              ],
+              [
+                106.073842,
+                35.45478
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 650000,
+        "name": "鏂扮枂缁村惥灏旇嚜娌诲尯",
+        "center": [
+          87.617733,
+          43.792818
+        ],
+        "centroid": [
+          85.294711,
+          41.371801
+        ],
+        "childrenNum": 24,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 30,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                96.386348,
+                42.727592
+              ],
+              [
+                96.363558,
+                42.900562
+              ],
+              [
+                95.921314,
+                43.229789
+              ],
+              [
+                95.880046,
+                43.28035
+              ],
+              [
+                95.857872,
+                43.417436
+              ],
+              [
+                95.735916,
+                43.597569
+              ],
+              [
+                95.705735,
+                43.67077
+              ],
+              [
+                95.645373,
+                43.787966
+              ],
+              [
+                95.623199,
+                43.855756
+              ],
+              [
+                95.527113,
+                44.007466
+              ],
+              [
+                95.426099,
+                44.009618
+              ],
+              [
+                95.377439,
+                44.025972
+              ],
+              [
+                95.326932,
+                44.028554
+              ],
+              [
+                95.35157,
+                44.090054
+              ],
+              [
+                95.355882,
+                44.166087
+              ],
+              [
+                95.376208,
+                44.227444
+              ],
+              [
+                95.4107,
+                44.245024
+              ],
+              [
+                95.43041,
+                44.281882
+              ],
+              [
+                95.41378,
+                44.298589
+              ],
+              [
+                95.238853,
+                44.277169
+              ],
+              [
+                95.1286,
+                44.269884
+              ],
+              [
+                94.998637,
+                44.253169
+              ],
+              [
+                94.945666,
+                44.292592
+              ],
+              [
+                94.826174,
+                44.320001
+              ],
+              [
+                94.768275,
+                44.34055
+              ],
+              [
+                94.722696,
+                44.34055
+              ],
+              [
+                94.673421,
+                44.397021
+              ],
+              [
+                94.606283,
+                44.448311
+              ],
+              [
+                94.557008,
+                44.462408
+              ],
+              [
+                94.470777,
+                44.509373
+              ],
+              [
+                94.390705,
+                44.521749
+              ],
+              [
+                94.359292,
+                44.515775
+              ],
+              [
+                94.329727,
+                44.582734
+              ],
+              [
+                94.279836,
+                44.603617
+              ],
+              [
+                94.227481,
+                44.645785
+              ],
+              [
+                94.215162,
+                44.667921
+              ],
+              [
+                94.152336,
+                44.684944
+              ],
+              [
+                94.066105,
+                44.732154
+              ],
+              [
+                93.723642,
+                44.865498
+              ],
+              [
+                93.716251,
+                44.894334
+              ],
+              [
+                93.613389,
+                44.926546
+              ],
+              [
+                93.509296,
+                44.968055
+              ],
+              [
+                93.434767,
+                44.955351
+              ],
+              [
+                93.376869,
+                44.985412
+              ],
+              [
+                93.314659,
+                44.995147
+              ],
+              [
+                93.314043,
+                44.980333
+              ],
+              [
+                93.252449,
+                44.991761
+              ],
+              [
+                93.174225,
+                45.015458
+              ],
+              [
+                93.100312,
+                45.007419
+              ],
+              [
+                93.062124,
+                45.018419
+              ],
+              [
+                93.002377,
+                45.009958
+              ],
+              [
+                92.932776,
+                45.017573
+              ],
+              [
+                92.922921,
+                45.03703
+              ],
+              [
+                92.884117,
+                45.046756
+              ],
+              [
+                92.847777,
+                45.038721
+              ],
+              [
+                92.779407,
+                45.050561
+              ],
+              [
+                92.683937,
+                45.02561
+              ],
+              [
+                92.547814,
+                45.018419
+              ],
+              [
+                92.501003,
+                45.001072
+              ],
+              [
+                92.414155,
+                45.018419
+              ],
+              [
+                92.348866,
+                45.014188
+              ],
+              [
+                92.315605,
+                45.028994
+              ],
+              [
+                92.240461,
+                45.015881
+              ],
+              [
+                92.100026,
+                45.081417
+              ],
+              [
+                92.056911,
+                45.086911
+              ],
+              [
+                91.885679,
+                45.078882
+              ],
+              [
+                91.803144,
+                45.082685
+              ],
+              [
+                91.694738,
+                45.065357
+              ],
+              [
+                91.561695,
+                45.075501
+              ],
+              [
+                91.500101,
+                45.103809
+              ],
+              [
+                91.448978,
+                45.156586
+              ],
+              [
+                91.429268,
+                45.156586
+              ],
+              [
+                91.37753,
+                45.11099
+              ],
+              [
+                91.33503,
+                45.129571
+              ],
+              [
+                91.242023,
+                45.13717
+              ],
+              [
+                91.230936,
+                45.153632
+              ],
+              [
+                91.195827,
+                45.159118
+              ],
+              [
+                91.17119,
+                45.199616
+              ],
+              [
+                91.129922,
+                45.21606
+              ],
+              [
+                91.050466,
+                45.208892
+              ],
+              [
+                91.007966,
+                45.218589
+              ],
+              [
+                90.96177,
+                45.201303
+              ],
+              [
+                90.881698,
+                45.192025
+              ],
+              [
+                90.866916,
+                45.209314
+              ],
+              [
+                90.897713,
+                45.249776
+              ],
+              [
+                90.877387,
+                45.280946
+              ],
+              [
+                90.831807,
+                45.300313
+              ],
+              [
+                90.804706,
+                45.29484
+              ],
+              [
+                90.813329,
+                45.32851
+              ],
+              [
+                90.773909,
+                45.405874
+              ],
+              [
+                90.772677,
+                45.432338
+              ],
+              [
+                90.723402,
+                45.464667
+              ],
+              [
+                90.671047,
+                45.487747
+              ],
+              [
+                90.676591,
+                45.582488
+              ],
+              [
+                90.714779,
+                45.728895
+              ],
+              [
+                90.799778,
+                45.834905
+              ],
+              [
+                90.890937,
+                45.921566
+              ],
+              [
+                91.028292,
+                46.023054
+              ],
+              [
+                91.014741,
+                46.06667
+              ],
+              [
+                91.021517,
+                46.121038
+              ],
+              [
+                90.98456,
+                46.160431
+              ],
+              [
+                90.94822,
+                46.219262
+              ],
+              [
+                90.955611,
+                46.233752
+              ],
+              [
+                90.900177,
+                46.31235
+              ],
+              [
+                90.983328,
+                46.374734
+              ],
+              [
+                90.996263,
+                46.419309
+              ],
+              [
+                91.025828,
+                46.444057
+              ],
+              [
+                91.038147,
+                46.500936
+              ],
+              [
+                91.060937,
+                46.516999
+              ],
+              [
+                91.079415,
+                46.558989
+              ],
+              [
+                91.068328,
+                46.579149
+              ],
+              [
+                91.017821,
+                46.58244
+              ],
+              [
+                91.036299,
+                46.670393
+              ],
+              [
+                91.054161,
+                46.717598
+              ],
+              [
+                91.019053,
+                46.766402
+              ],
+              [
+                90.992567,
+                46.769682
+              ],
+              [
+                90.992567,
+                46.790583
+              ],
+              [
+                90.942676,
+                46.82581
+              ],
+              [
+                90.958075,
+                46.879425
+              ],
+              [
+                90.929742,
+                46.893331
+              ],
+              [
+                90.92235,
+                46.938707
+              ],
+              [
+                90.901408,
+                46.960768
+              ],
+              [
+                90.830575,
+                46.995883
+              ],
+              [
+                90.767134,
+                46.992617
+              ],
+              [
+                90.691989,
+                47.080717
+              ],
+              [
+                90.653801,
+                47.111681
+              ],
+              [
+                90.579888,
+                47.198364
+              ],
+              [
+                90.56141,
+                47.206903
+              ],
+              [
+                90.521374,
+                47.2845
+              ],
+              [
+                90.488113,
+                47.317374
+              ],
+              [
+                90.526301,
+                47.379007
+              ],
+              [
+                90.507823,
+                47.400076
+              ],
+              [
+                90.468403,
+                47.404937
+              ],
+              [
+                90.459164,
+                47.43895
+              ],
+              [
+                90.474562,
+                47.462422
+              ],
+              [
+                90.468403,
+                47.497611
+              ],
+              [
+                90.398186,
+                47.547724
+              ],
+              [
+                90.376012,
+                47.603036
+              ],
+              [
+                90.346447,
+                47.637324
+              ],
+              [
+                90.384635,
+                47.644179
+              ],
+              [
+                90.331665,
+                47.681663
+              ],
+              [
+                90.216484,
+                47.70543
+              ],
+              [
+                90.180144,
+                47.72516
+              ],
+              [
+                90.13518,
+                47.723147
+              ],
+              [
+                90.07605,
+                47.777469
+              ],
+              [
+                90.070506,
+                47.820483
+              ],
+              [
+                90.086521,
+                47.86547
+              ],
+              [
+                90.066195,
+                47.883534
+              ],
+              [
+                90.040941,
+                47.874704
+              ],
+              [
+                89.960253,
+                47.885942
+              ],
+              [
+                89.957789,
+                47.842982
+              ],
+              [
+                89.86971,
+                47.834144
+              ],
+              [
+                89.761921,
+                47.835751
+              ],
+              [
+                89.735435,
+                47.89758
+              ],
+              [
+                89.651052,
+                47.913627
+              ],
+              [
+                89.645508,
+                47.947711
+              ],
+              [
+                89.595617,
+                47.973359
+              ],
+              [
+                89.599313,
+                48.015811
+              ],
+              [
+                89.569132,
+                48.037825
+              ],
+              [
+                89.498299,
+                48.02822
+              ],
+              [
+                89.38127,
+                48.046227
+              ],
+              [
+                89.359712,
+                48.026219
+              ],
+              [
+                89.308589,
+                48.021816
+              ],
+              [
+                89.282104,
+                47.994189
+              ],
+              [
+                89.231597,
+                47.98017
+              ],
+              [
+                89.156452,
+                47.996992
+              ],
+              [
+                89.078228,
+                47.98698
+              ],
+              [
+                89.044967,
+                48.009806
+              ],
+              [
+                89.027105,
+                48.051028
+              ],
+              [
+                88.953808,
+                48.090618
+              ],
+              [
+                88.939026,
+                48.115396
+              ],
+              [
+                88.824461,
+                48.107005
+              ],
+              [
+                88.79736,
+                48.133772
+              ],
+              [
+                88.721599,
+                48.160526
+              ],
+              [
+                88.700657,
+                48.180881
+              ],
+              [
+                88.668628,
+                48.171303
+              ],
+              [
+                88.638447,
+                48.183674
+              ],
+              [
+                88.601491,
+                48.221567
+              ],
+              [
+                88.594716,
+                48.259831
+              ],
+              [
+                88.575006,
+                48.277757
+              ],
+              [
+                88.605803,
+                48.337863
+              ],
+              [
+                88.573774,
+                48.351785
+              ],
+              [
+                88.573158,
+                48.369679
+              ],
+              [
+                88.535586,
+                48.368884
+              ],
+              [
+                88.523267,
+                48.403461
+              ],
+              [
+                88.503557,
+                48.412996
+              ],
+              [
+                88.462289,
+                48.392335
+              ],
+              [
+                88.438267,
+                48.393528
+              ],
+              [
+                88.360659,
+                48.433251
+              ],
+              [
+                88.363123,
+                48.460641
+              ],
+              [
+                88.318159,
+                48.478497
+              ],
+              [
+                88.229464,
+                48.498329
+              ],
+              [
+                88.196819,
+                48.493967
+              ],
+              [
+                88.151855,
+                48.526478
+              ],
+              [
+                88.130297,
+                48.521721
+              ],
+              [
+                88.10874,
+                48.545895
+              ],
+              [
+                88.041602,
+                48.548272
+              ],
+              [
+                87.973233,
+                48.575997
+              ],
+              [
+                87.96153,
+                48.599353
+              ],
+              [
+                88.010805,
+                48.618742
+              ],
+              [
+                88.02682,
+                48.65315
+              ],
+              [
+                88.089645,
+                48.69504
+              ],
+              [
+                88.090877,
+                48.71992
+              ],
+              [
+                88.064392,
+                48.712813
+              ],
+              [
+                88.029283,
+                48.750313
+              ],
+              [
+                87.96153,
+                48.773588
+              ],
+              [
+                87.93874,
+                48.757809
+              ],
+              [
+                87.872219,
+                48.799612
+              ],
+              [
+                87.826639,
+                48.800795
+              ],
+              [
+                87.803234,
+                48.824835
+              ],
+              [
+                87.829103,
+                48.825623
+              ],
+              [
+                87.792147,
+                48.849258
+              ],
+              [
+                87.78106,
+                48.872094
+              ],
+              [
+                87.742256,
+                48.881146
+              ],
+              [
+                87.760118,
+                48.925992
+              ],
+              [
+                87.793995,
+                48.927565
+              ],
+              [
+                87.814321,
+                48.945256
+              ],
+              [
+                87.87653,
+                48.949186
+              ],
+              [
+                87.871603,
+                48.963726
+              ],
+              [
+                87.911639,
+                48.979833
+              ],
+              [
+                87.883922,
+                48.993971
+              ],
+              [
+                87.883306,
+                49.023806
+              ],
+              [
+                87.835263,
+                49.054406
+              ],
+              [
+                87.858052,
+                49.07362
+              ],
+              [
+                87.844502,
+                49.090084
+              ],
+              [
+                87.867291,
+                49.108892
+              ],
+              [
+                87.845733,
+                49.146096
+              ],
+              [
+                87.82048,
+                49.148445
+              ],
+              [
+                87.821096,
+                49.173883
+              ],
+              [
+                87.793379,
+                49.18249
+              ],
+              [
+                87.762582,
+                49.172709
+              ],
+              [
+                87.700372,
+                49.175839
+              ],
+              [
+                87.67635,
+                49.15549
+              ],
+              [
+                87.602437,
+                49.152359
+              ],
+              [
+                87.563017,
+                49.142572
+              ],
+              [
+                87.517438,
+                49.145704
+              ],
+              [
+                87.49588,
+                49.132001
+              ],
+              [
+                87.511894,
+                49.10184
+              ],
+              [
+                87.43675,
+                49.075188
+              ],
+              [
+                87.388707,
+                49.097921
+              ],
+              [
+                87.304939,
+                49.112418
+              ],
+              [
+                87.239033,
+                49.114376
+              ],
+              [
+                87.211932,
+                49.140615
+              ],
+              [
+                87.112766,
+                49.15549
+              ],
+              [
+                87.088128,
+                49.133567
+              ],
+              [
+                87.000049,
+                49.142572
+              ],
+              [
+                86.953853,
+                49.131218
+              ],
+              [
+                86.887948,
+                49.132001
+              ],
+              [
+                86.854071,
+                49.109284
+              ],
+              [
+                86.84976,
+                49.066563
+              ],
+              [
+                86.836209,
+                49.051269
+              ],
+              [
+                86.772151,
+                49.02773
+              ],
+              [
+                86.732115,
+                48.994757
+              ],
+              [
+                86.730267,
+                48.959797
+              ],
+              [
+                86.757985,
+                48.894919
+              ],
+              [
+                86.782006,
+                48.887049
+              ],
+              [
+                86.821426,
+                48.850439
+              ],
+              [
+                86.818963,
+                48.831139
+              ],
+              [
+                86.770303,
+                48.810255
+              ],
+              [
+                86.754289,
+                48.78463
+              ],
+              [
+                86.780774,
+                48.731369
+              ],
+              [
+                86.771535,
+                48.717156
+              ],
+              [
+                86.70255,
+                48.666195
+              ],
+              [
+                86.693311,
+                48.64366
+              ],
+              [
+                86.640956,
+                48.629027
+              ],
+              [
+                86.635413,
+                48.612016
+              ],
+              [
+                86.594761,
+                48.576789
+              ],
+              [
+                86.579978,
+                48.538763
+              ],
+              [
+                86.416138,
+                48.481671
+              ],
+              [
+                86.38103,
+                48.49357
+              ],
+              [
+                86.305269,
+                48.491984
+              ],
+              [
+                86.270161,
+                48.452307
+              ],
+              [
+                86.225813,
+                48.432456
+              ],
+              [
+                86.053966,
+                48.441192
+              ],
+              [
+                85.916612,
+                48.438015
+              ],
+              [
+                85.791576,
+                48.418954
+              ],
+              [
+                85.758315,
+                48.403064
+              ],
+              [
+                85.695489,
+                48.335078
+              ],
+              [
+                85.695489,
+                48.302445
+              ],
+              [
+                85.678243,
+                48.266205
+              ],
+              [
+                85.633895,
+                48.232731
+              ],
+              [
+                85.622193,
+                48.202824
+              ],
+              [
+                85.587084,
+                48.191654
+              ],
+              [
+                85.576613,
+                48.15853
+              ],
+              [
+                85.55136,
+                48.127781
+              ],
+              [
+                85.551975,
+                48.081423
+              ],
+              [
+                85.531649,
+                48.046227
+              ],
+              [
+                85.547048,
+                48.008205
+              ],
+              [
+                85.617881,
+                47.550552
+              ],
+              [
+                85.614801,
+                47.498015
+              ],
+              [
+                85.685018,
+                47.428829
+              ],
+              [
+                85.701649,
+                47.384275
+              ],
+              [
+                85.675779,
+                47.321837
+              ],
+              [
+                85.701033,
+                47.28856
+              ],
+              [
+                85.682555,
+                47.249982
+              ],
+              [
+                85.682555,
+                47.222757
+              ],
+              [
+                85.641903,
+                47.18413
+              ],
+              [
+                85.582772,
+                47.142626
+              ],
+              [
+                85.547048,
+                47.096609
+              ],
+              [
+                85.545816,
+                47.057891
+              ],
+              [
+                85.441106,
+                47.063191
+              ],
+              [
+                85.355491,
+                47.054629
+              ],
+              [
+                85.325926,
+                47.044842
+              ],
+              [
+                85.276651,
+                47.068898
+              ],
+              [
+                85.213825,
+                47.041172
+              ],
+              [
+                85.175637,
+                46.997924
+              ],
+              [
+                85.102956,
+                46.968936
+              ],
+              [
+                85.082014,
+                46.939933
+              ],
+              [
+                84.987159,
+                46.918272
+              ],
+              [
+                84.979768,
+                46.883106
+              ],
+              [
+                84.95513,
+                46.861013
+              ],
+              [
+                84.934188,
+                46.863878
+              ],
+              [
+                84.867051,
+                46.927673
+              ],
+              [
+                84.849189,
+                46.957092
+              ],
+              [
+                84.781435,
+                46.979962
+              ],
+              [
+                84.748175,
+                47.009759
+              ],
+              [
+                84.699515,
+                47.008535
+              ],
+              [
+                84.668718,
+                46.995067
+              ],
+              [
+                84.563393,
+                46.991801
+              ],
+              [
+                84.506726,
+                46.97302
+              ],
+              [
+                84.425422,
+                47.008943
+              ],
+              [
+                84.37122,
+                46.993434
+              ],
+              [
+                84.336727,
+                47.00527
+              ],
+              [
+                84.2893,
+                46.994658
+              ],
+              [
+                84.195061,
+                47.003638
+              ],
+              [
+                84.150098,
+                46.977512
+              ],
+              [
+                84.086656,
+                46.965261
+              ],
+              [
+                84.038613,
+                46.973428
+              ],
+              [
+                84.002888,
+                46.990576
+              ],
+              [
+                83.951765,
+                46.98731
+              ],
+              [
+                83.932671,
+                46.970161
+              ],
+              [
+                83.88586,
+                46.982003
+              ],
+              [
+                83.766367,
+                47.026896
+              ],
+              [
+                83.69923,
+                47.015472
+              ],
+              [
+                83.700462,
+                47.032199
+              ],
+              [
+                83.576042,
+                47.059114
+              ],
+              [
+                83.566803,
+                47.080717
+              ],
+              [
+                83.53847,
+                47.083977
+              ],
+              [
+                83.463325,
+                47.132042
+              ],
+              [
+                83.418978,
+                47.119012
+              ],
+              [
+                83.370318,
+                47.178436
+              ],
+              [
+                83.324739,
+                47.167858
+              ],
+              [
+                83.306261,
+                47.179656
+              ],
+              [
+                83.257602,
+                47.173147
+              ],
+              [
+                83.221877,
+                47.186977
+              ],
+              [
+                83.207094,
+                47.213814
+              ],
+              [
+                83.17445,
+                47.218286
+              ],
+              [
+                83.15474,
+                47.236168
+              ],
+              [
+                83.108544,
+                47.221944
+              ],
+              [
+                83.02724,
+                47.21544
+              ],
+              [
+                83.031552,
+                47.168265
+              ],
+              [
+                82.993364,
+                47.065229
+              ],
+              [
+                82.937929,
+                47.014248
+              ],
+              [
+                82.923762,
+                46.932169
+              ],
+              [
+                82.876335,
+                46.823762
+              ],
+              [
+                82.878183,
+                46.797138
+              ],
+              [
+                82.829524,
+                46.772551
+              ],
+              [
+                82.788872,
+                46.677784
+              ],
+              [
+                82.774089,
+                46.600124
+              ],
+              [
+                82.726662,
+                46.494756
+              ],
+              [
+                82.609017,
+                46.294985
+              ],
+              [
+                82.518474,
+                46.153798
+              ],
+              [
+                82.461808,
+                45.97982
+              ],
+              [
+                82.401446,
+                45.972333
+              ],
+              [
+                82.342932,
+                45.935303
+              ],
+              [
+                82.336156,
+                45.882418
+              ],
+              [
+                82.349707,
+                45.822811
+              ],
+              [
+                82.340468,
+                45.772742
+              ],
+              [
+                82.289961,
+                45.71636
+              ],
+              [
+                82.288729,
+                45.655321
+              ],
+              [
+                82.266555,
+                45.620172
+              ],
+              [
+                82.281954,
+                45.53891
+              ],
+              [
+                82.448257,
+                45.461309
+              ],
+              [
+                82.546808,
+                45.426038
+              ],
+              [
+                82.60101,
+                45.346178
+              ],
+              [
+                82.58746,
+                45.224069
+              ],
+              [
+                82.562822,
+                45.204676
+              ],
+              [
+                82.487061,
+                45.181058
+              ],
+              [
+                82.344779,
+                45.219011
+              ],
+              [
+                82.294272,
+                45.247669
+              ],
+              [
+                82.206809,
+                45.236713
+              ],
+              [
+                82.109491,
+                45.211422
+              ],
+              [
+                82.091012,
+                45.222383
+              ],
+              [
+                82.09594,
+                45.249776
+              ],
+              [
+                82.052824,
+                45.255674
+              ],
+              [
+                81.993078,
+                45.237978
+              ],
+              [
+                81.921013,
+                45.233342
+              ],
+              [
+                81.879745,
+                45.284314
+              ],
+              [
+                81.832318,
+                45.319673
+              ],
+              [
+                81.78797,
+                45.3836
+              ],
+              [
+                81.677101,
+                45.35459
+              ],
+              [
+                81.645072,
+                45.359216
+              ],
+              [
+                81.582863,
+                45.336503
+              ],
+              [
+                81.575471,
+                45.30789
+              ],
+              [
+                81.536667,
+                45.304101
+              ],
+              [
+                81.52866,
+                45.285999
+              ],
+              [
+                81.462754,
+                45.264099
+              ],
+              [
+                81.437501,
+                45.28263
+              ],
+              [
+                81.398697,
+                45.275471
+              ],
+              [
+                81.382066,
+                45.257781
+              ],
+              [
+                81.327864,
+                45.260729
+              ],
+              [
+                81.284748,
+                45.23882
+              ],
+              [
+                81.236705,
+                45.247248
+              ],
+              [
+                81.175111,
+                45.227863
+              ],
+              [
+                81.170183,
+                45.211001
+              ],
+              [
+                81.111669,
+                45.218168
+              ],
+              [
+                81.080872,
+                45.182745
+              ],
+              [
+                81.024821,
+                45.162916
+              ],
+              [
+                80.966307,
+                45.168402
+              ],
+              [
+                80.93551,
+                45.160384
+              ],
+              [
+                80.897938,
+                45.127459
+              ],
+              [
+                80.862214,
+                45.127037
+              ],
+              [
+                80.816634,
+                45.152788
+              ],
+              [
+                80.731634,
+                45.156164
+              ],
+              [
+                80.686055,
+                45.129148
+              ],
+              [
+                80.599207,
+                45.105921
+              ],
+              [
+                80.519135,
+                45.108878
+              ],
+              [
+                80.493882,
+                45.127037
+              ],
+              [
+                80.445839,
+                45.097895
+              ],
+              [
+                80.443991,
+                45.077614
+              ],
+              [
+                80.404571,
+                45.049293
+              ],
+              [
+                80.358375,
+                45.040836
+              ],
+              [
+                80.328194,
+                45.070007
+              ],
+              [
+                80.291854,
+                45.06578
+              ],
+              [
+                80.24381,
+                45.031532
+              ],
+              [
+                80.195767,
+                45.030686
+              ],
+              [
+                80.144644,
+                45.059017
+              ],
+              [
+                80.136021,
+                45.041259
+              ],
+              [
+                80.111999,
+                45.052675
+              ],
+              [
+                80.060876,
+                45.026033
+              ],
+              [
+                80.056565,
+                45.011227
+              ],
+              [
+                79.98142,
+                44.964244
+              ],
+              [
+                79.951855,
+                44.957892
+              ],
+              [
+                79.944464,
+                44.937985
+              ],
+              [
+                79.887798,
+                44.90917
+              ],
+              [
+                79.969102,
+                44.877797
+              ],
+              [
+                79.953703,
+                44.849377
+              ],
+              [
+                79.991891,
+                44.830281
+              ],
+              [
+                79.999283,
+                44.793768
+              ],
+              [
+                80.087978,
+                44.817122
+              ],
+              [
+                80.115695,
+                44.815424
+              ],
+              [
+                80.169898,
+                44.84471
+              ],
+              [
+                80.18776,
+                44.825612
+              ],
+              [
+                80.178521,
+                44.796741
+              ],
+              [
+                80.200695,
+                44.756808
+              ],
+              [
+                80.238883,
+                44.7228
+              ],
+              [
+                80.313412,
+                44.704938
+              ],
+              [
+                80.400259,
+                44.628751
+              ],
+              [
+                80.411962,
+                44.605321
+              ],
+              [
+                80.350368,
+                44.484615
+              ],
+              [
+                80.383013,
+                44.401297
+              ],
+              [
+                80.399027,
+                44.30587
+              ],
+              [
+                80.413194,
+                44.264741
+              ],
+              [
+                80.400875,
+                44.198704
+              ],
+              [
+                80.407034,
+                44.149772
+              ],
+              [
+                80.3941,
+                44.127009
+              ],
+              [
+                80.449534,
+                44.078017
+              ],
+              [
+                80.458773,
+                44.047054
+              ],
+              [
+                80.457541,
+                43.981203
+              ],
+              [
+                80.485259,
+                43.95579
+              ],
+              [
+                80.475404,
+                43.938124
+              ],
+              [
+                80.511128,
+                43.906657
+              ],
+              [
+                80.522215,
+                43.816473
+              ],
+              [
+                80.75504,
+                43.494329
+              ],
+              [
+                80.761199,
+                43.446554
+              ],
+              [
+                80.746417,
+                43.439167
+              ],
+              [
+                80.735946,
+                43.389609
+              ],
+              [
+                80.686055,
+                43.333916
+              ],
+              [
+                80.69283,
+                43.32042
+              ],
+              [
+                80.777214,
+                43.308227
+              ],
+              [
+                80.769207,
+                43.265535
+              ],
+              [
+                80.788917,
+                43.242433
+              ],
+              [
+                80.789533,
+                43.201876
+              ],
+              [
+                80.804315,
+                43.178314
+              ],
+              [
+                80.79446,
+                43.137277
+              ],
+              [
+                80.752576,
+                43.148194
+              ],
+              [
+                80.73225,
+                43.131163
+              ],
+              [
+                80.706997,
+                43.143828
+              ],
+              [
+                80.650946,
+                43.147321
+              ],
+              [
+                80.593048,
+                43.133347
+              ],
+              [
+                80.556092,
+                43.104515
+              ],
+              [
+                80.482795,
+                43.06955
+              ],
+              [
+                80.416889,
+                43.05687
+              ],
+              [
+                80.378701,
+                43.031502
+              ],
+              [
+                80.397795,
+                42.996933
+              ],
+              [
+                80.487106,
+                42.948766
+              ],
+              [
+                80.5912,
+                42.923354
+              ],
+              [
+                80.602903,
+                42.894424
+              ],
+              [
+                80.503737,
+                42.882146
+              ],
+              [
+                80.450766,
+                42.861971
+              ],
+              [
+                80.407034,
+                42.834767
+              ],
+              [
+                80.338049,
+                42.831695
+              ],
+              [
+                80.280151,
+                42.838278
+              ],
+              [
+                80.262289,
+                42.828623
+              ],
+              [
+                80.259209,
+                42.790865
+              ],
+              [
+                80.225948,
+                42.713083
+              ],
+              [
+                80.228412,
+                42.692852
+              ],
+              [
+                80.179753,
+                42.670415
+              ],
+              [
+                80.163738,
+                42.629919
+              ],
+              [
+                80.180985,
+                42.590718
+              ],
+              [
+                80.221637,
+                42.533415
+              ],
+              [
+                80.265368,
+                42.502097
+              ],
+              [
+                80.225948,
+                42.485769
+              ],
+              [
+                80.206238,
+                42.431462
+              ],
+              [
+                80.239499,
+                42.389927
+              ],
+              [
+                80.229028,
+                42.358536
+              ],
+              [
+                80.283847,
+                42.320493
+              ],
+              [
+                80.272144,
+                42.281984
+              ],
+              [
+                80.29247,
+                42.259842
+              ],
+              [
+                80.28631,
+                42.233261
+              ],
+              [
+                80.233339,
+                42.210215
+              ],
+              [
+                80.168666,
+                42.200462
+              ],
+              [
+                80.163738,
+                42.152563
+              ],
+              [
+                80.139717,
+                42.151232
+              ],
+              [
+                80.16805,
+                42.096635
+              ],
+              [
+                80.193303,
+                42.081535
+              ],
+              [
+                80.14218,
+                42.03488
+              ],
+              [
+                80.089826,
+                42.047325
+              ],
+              [
+                79.923522,
+                42.042436
+              ],
+              [
+                79.852689,
+                42.015319
+              ],
+              [
+                79.854537,
+                41.984186
+              ],
+              [
+                79.822508,
+                41.963275
+              ],
+              [
+                79.776313,
+                41.89248
+              ],
+              [
+                79.724574,
+                41.896935
+              ],
+              [
+                79.640806,
+                41.884907
+              ],
+              [
+                79.616784,
+                41.856385
+              ],
+              [
+                79.550879,
+                41.834094
+              ],
+              [
+                79.500988,
+                41.835432
+              ],
+              [
+                79.457256,
+                41.847915
+              ],
+              [
+                79.415372,
+                41.836769
+              ],
+              [
+                79.356242,
+                41.795735
+              ],
+              [
+                79.326061,
+                41.809565
+              ],
+              [
+                79.276786,
+                41.78101
+              ],
+              [
+                79.271858,
+                41.767174
+              ],
+              [
+                79.21704,
+                41.725648
+              ],
+              [
+                79.138199,
+                41.722968
+              ],
+              [
+                79.10925,
+                41.697503
+              ],
+              [
+                79.043345,
+                41.681414
+              ],
+              [
+                79.021787,
+                41.657273
+              ],
+              [
+                78.99407,
+                41.664427
+              ],
+              [
+                78.957729,
+                41.65146
+              ],
+              [
+                78.891824,
+                41.597777
+              ],
+              [
+                78.86657,
+                41.593749
+              ],
+              [
+                78.825302,
+                41.560173
+              ],
+              [
+                78.739071,
+                41.555695
+              ],
+              [
+                78.696571,
+                41.54181
+              ],
+              [
+                78.707042,
+                41.522098
+              ],
+              [
+                78.675629,
+                41.50238
+              ],
+              [
+                78.650375,
+                41.467411
+              ],
+              [
+                78.580774,
+                41.481759
+              ],
+              [
+                78.527188,
+                41.440947
+              ],
+              [
+                78.454507,
+                41.412228
+              ],
+              [
+                78.391681,
+                41.408189
+              ],
+              [
+                78.385522,
+                41.394721
+              ],
+              [
+                78.338094,
+                41.397415
+              ],
+              [
+                78.324544,
+                41.384395
+              ],
+              [
+                78.235232,
+                41.399211
+              ],
+              [
+                78.163783,
+                41.383497
+              ],
+              [
+                78.149617,
+                41.368228
+              ],
+              [
+                78.165015,
+                41.340825
+              ],
+              [
+                78.136682,
+                41.279239
+              ],
+              [
+                78.129291,
+                41.228398
+              ],
+              [
+                78.094798,
+                41.224347
+              ],
+              [
+                77.972842,
+                41.173013
+              ],
+              [
+                77.905089,
+                41.185174
+              ],
+              [
+                77.836104,
+                41.153189
+              ],
+              [
+                77.814546,
+                41.13426
+              ],
+              [
+                77.807155,
+                41.091876
+              ],
+              [
+                77.829328,
+                41.059394
+              ],
+              [
+                77.796068,
+                41.049014
+              ],
+              [
+                77.780669,
+                41.022832
+              ],
+              [
+                77.737553,
+                41.032313
+              ],
+              [
+                77.684583,
+                41.00793
+              ],
+              [
+                77.654402,
+                41.016059
+              ],
+              [
+                77.597119,
+                41.005221
+              ],
+              [
+                77.591576,
+                40.992122
+              ],
+              [
+                77.540453,
+                41.006575
+              ],
+              [
+                77.476395,
+                40.999349
+              ],
+              [
+                77.473931,
+                41.022832
+              ],
+              [
+                77.415417,
+                41.038633
+              ],
+              [
+                77.363062,
+                41.04089
+              ],
+              [
+                77.296541,
+                41.004769
+              ],
+              [
+                77.236795,
+                41.027798
+              ],
+              [
+                77.169041,
+                41.009285
+              ],
+              [
+                77.108063,
+                41.038181
+              ],
+              [
+                77.091433,
+                41.062553
+              ],
+              [
+                77.023064,
+                41.059394
+              ],
+              [
+                77.002122,
+                41.073381
+              ],
+              [
+                76.940528,
+                41.028701
+              ],
+              [
+                76.885709,
+                41.027347
+              ],
+              [
+                76.85368,
+                40.97631
+              ],
+              [
+                76.817956,
+                40.975406
+              ],
+              [
+                76.761905,
+                40.954167
+              ],
+              [
+                76.741579,
+                40.912119
+              ],
+              [
+                76.731724,
+                40.818887
+              ],
+              [
+                76.693536,
+                40.779472
+              ],
+              [
+                76.646725,
+                40.759983
+              ],
+              [
+                76.646725,
+                40.73686
+              ],
+              [
+                76.676906,
+                40.696036
+              ],
+              [
+                76.654732,
+                40.652917
+              ],
+              [
+                76.657196,
+                40.620218
+              ],
+              [
+                76.611,
+                40.601591
+              ],
+              [
+                76.601145,
+                40.578868
+              ],
+              [
+                76.556798,
+                40.542495
+              ],
+              [
+                76.543247,
+                40.513837
+              ],
+              [
+                76.539551,
+                40.464226
+              ],
+              [
+                76.508754,
+                40.429613
+              ],
+              [
+                76.470566,
+                40.422779
+              ],
+              [
+                76.442233,
+                40.391336
+              ],
+              [
+                76.390494,
+                40.37766
+              ],
+              [
+                76.381871,
+                40.39088
+              ],
+              [
+                76.333212,
+                40.343459
+              ],
+              [
+                76.327668,
+                40.391336
+              ],
+              [
+                76.283321,
+                40.415034
+              ],
+              [
+                76.279625,
+                40.439179
+              ],
+              [
+                76.22419,
+                40.401819
+              ],
+              [
+                76.176147,
+                40.381307
+              ],
+              [
+                76.144118,
+                40.393615
+              ],
+              [
+                76.081293,
+                40.39635
+              ],
+              [
+                76.048648,
+                40.388601
+              ],
+              [
+                76.048648,
+                40.357141
+              ],
+              [
+                76.026474,
+                40.355317
+              ],
+              [
+                75.986438,
+                40.381763
+              ],
+              [
+                75.932235,
+                40.339353
+              ],
+              [
+                75.921764,
+                40.291439
+              ],
+              [
+                75.890351,
+                40.30924
+              ],
+              [
+                75.84046,
+                40.312434
+              ],
+              [
+                75.831221,
+                40.327492
+              ],
+              [
+                75.785642,
+                40.301025
+              ],
+              [
+                75.739446,
+                40.299199
+              ],
+              [
+                75.709265,
+                40.280939
+              ],
+              [
+                75.688323,
+                40.343915
+              ],
+              [
+                75.669845,
+                40.363982
+              ],
+              [
+                75.686475,
+                40.418223
+              ],
+              [
+                75.717272,
+                40.443278
+              ],
+              [
+                75.733287,
+                40.474242
+              ],
+              [
+                75.646439,
+                40.516567
+              ],
+              [
+                75.631041,
+                40.548862
+              ],
+              [
+                75.627345,
+                40.605226
+              ],
+              [
+                75.636584,
+                40.624306
+              ],
+              [
+                75.599628,
+                40.659727
+              ],
+              [
+                75.550353,
+                40.64883
+              ],
+              [
+                75.467817,
+                40.599773
+              ],
+              [
+                75.432093,
+                40.563412
+              ],
+              [
+                75.355716,
+                40.537947
+              ],
+              [
+                75.292274,
+                40.483802
+              ],
+              [
+                75.268869,
+                40.483802
+              ],
+              [
+                75.242383,
+                40.448743
+              ],
+              [
+                75.206659,
+                40.447833
+              ],
+              [
+                75.13521,
+                40.463315
+              ],
+              [
+                75.102565,
+                40.44009
+              ],
+              [
+                75.051442,
+                40.449654
+              ],
+              [
+                75.021877,
+                40.466958
+              ],
+              [
+                74.995392,
+                40.455119
+              ],
+              [
+                74.963363,
+                40.464681
+              ],
+              [
+                74.891914,
+                40.507467
+              ],
+              [
+                74.844486,
+                40.521117
+              ],
+              [
+                74.819233,
+                40.505647
+              ],
+              [
+                74.814921,
+                40.461039
+              ],
+              [
+                74.795211,
+                40.443278
+              ],
+              [
+                74.908544,
+                40.338897
+              ],
+              [
+                74.862965,
+                40.32658
+              ],
+              [
+                74.824776,
+                40.344371
+              ],
+              [
+                74.700357,
+                40.346195
+              ],
+              [
+                74.697893,
+                40.310153
+              ],
+              [
+                74.673255,
+                40.278656
+              ],
+              [
+                74.618437,
+                40.27957
+              ],
+              [
+                74.577169,
+                40.260391
+              ],
+              [
+                74.534669,
+                40.207851
+              ],
+              [
+                74.485394,
+                40.182251
+              ],
+              [
+                74.433039,
+                40.13148
+              ],
+              [
+                74.356662,
+                40.089371
+              ],
+              [
+                74.316626,
+                40.106767
+              ],
+              [
+                74.280902,
+                40.09807
+              ],
+              [
+                74.26304,
+                40.125074
+              ],
+              [
+                74.126301,
+                40.104479
+              ],
+              [
+                74.113366,
+                40.086624
+              ],
+              [
+                74.023439,
+                40.085251
+              ],
+              [
+                74.008041,
+                40.050901
+              ],
+              [
+                73.943367,
+                40.016076
+              ],
+              [
+                73.980324,
+                40.004617
+              ],
+              [
+                73.910722,
+                39.934443
+              ],
+              [
+                73.907027,
+                39.873843
+              ],
+              [
+                73.845433,
+                39.831115
+              ],
+              [
+                73.841737,
+                39.756163
+              ],
+              [
+                73.905795,
+                39.741899
+              ],
+              [
+                73.924273,
+                39.722108
+              ],
+              [
+                73.953838,
+                39.600018
+              ],
+              [
+                73.916266,
+                39.586644
+              ],
+              [
+                73.914418,
+                39.564041
+              ],
+              [
+                73.883621,
+                39.540969
+              ],
+              [
+                73.893476,
+                39.528046
+              ],
+              [
+                73.868223,
+                39.482794
+              ],
+              [
+                73.836194,
+                39.472169
+              ],
+              [
+                73.745651,
+                39.462005
+              ],
+              [
+                73.6471,
+                39.474479
+              ],
+              [
+                73.61076,
+                39.465702
+              ],
+              [
+                73.592898,
+                39.412087
+              ],
+              [
+                73.502355,
+                39.383877
+              ],
+              [
+                73.554094,
+                39.350102
+              ],
+              [
+                73.554709,
+                39.295935
+              ],
+              [
+                73.542391,
+                39.269531
+              ],
+              [
+                73.564564,
+                39.266288
+              ],
+              [
+                73.580579,
+                39.237555
+              ],
+              [
+                73.623079,
+                39.235237
+              ],
+              [
+                73.639709,
+                39.220402
+              ],
+              [
+                73.657571,
+                39.166136
+              ],
+              [
+                73.688368,
+                39.154999
+              ],
+              [
+                73.719781,
+                39.108112
+              ],
+              [
+                73.720397,
+                39.071881
+              ],
+              [
+                73.743187,
+                39.029588
+              ],
+              [
+                73.780143,
+                39.026798
+              ],
+              [
+                73.820179,
+                39.041674
+              ],
+              [
+                73.839889,
+                39.008199
+              ],
+              [
+                73.846665,
+                38.962145
+              ],
+              [
+                73.826339,
+                38.916993
+              ],
+              [
+                73.767824,
+                38.941202
+              ],
+              [
+                73.742571,
+                38.933754
+              ],
+              [
+                73.70931,
+                38.893241
+              ],
+              [
+                73.699455,
+                38.857832
+              ],
+              [
+                73.729636,
+                38.837324
+              ],
+              [
+                73.769056,
+                38.775765
+              ],
+              [
+                73.757353,
+                38.719755
+              ],
+              [
+                73.809092,
+                38.634256
+              ],
+              [
+                73.799237,
+                38.610878
+              ],
+              [
+                73.852208,
+                38.584217
+              ],
+              [
+                73.89902,
+                38.579071
+              ],
+              [
+                73.926121,
+                38.536016
+              ],
+              [
+                74.011736,
+                38.52478
+              ],
+              [
+                74.034526,
+                38.541634
+              ],
+              [
+                74.090577,
+                38.542102
+              ],
+              [
+                74.068403,
+                38.585621
+              ],
+              [
+                74.088113,
+                38.610878
+              ],
+              [
+                74.11275,
+                38.611345
+              ],
+              [
+                74.147859,
+                38.676785
+              ],
+              [
+                74.229779,
+                38.656224
+              ],
+              [
+                74.353583,
+                38.655757
+              ],
+              [
+                74.421952,
+                38.647812
+              ],
+              [
+                74.455829,
+                38.632853
+              ],
+              [
+                74.506336,
+                38.637528
+              ],
+              [
+                74.546988,
+                38.607604
+              ],
+              [
+                74.613509,
+                38.593105
+              ],
+              [
+                74.639995,
+                38.599653
+              ],
+              [
+                74.717603,
+                38.542102
+              ],
+              [
+                74.78474,
+                38.538357
+              ],
+              [
+                74.821697,
+                38.491062
+              ],
+              [
+                74.862965,
+                38.484035
+              ],
+              [
+                74.868508,
+                38.403883
+              ],
+              [
+                74.834015,
+                38.361193
+              ],
+              [
+                74.789668,
+                38.324581
+              ],
+              [
+                74.806914,
+                38.285602
+              ],
+              [
+                74.793363,
+                38.271039
+              ],
+              [
+                74.816769,
+                38.215576
+              ],
+              [
+                74.80445,
+                38.167128
+              ],
+              [
+                74.821697,
+                38.10311
+              ],
+              [
+                74.879595,
+                38.021122
+              ],
+              [
+                74.92579,
+                38.01735
+              ],
+              [
+                74.911008,
+                37.966884
+              ],
+              [
+                74.919015,
+                37.908357
+              ],
+              [
+                74.936877,
+                37.876241
+              ],
+              [
+                74.917167,
+                37.845057
+              ],
+              [
+                74.989848,
+                37.797783
+              ],
+              [
+                75.006478,
+                37.770823
+              ],
+              [
+                74.949196,
+                37.725395
+              ],
+              [
+                74.923327,
+                37.717347
+              ],
+              [
+                74.920863,
+                37.684675
+              ],
+              [
+                74.891914,
+                37.668097
+              ],
+              [
+                74.940573,
+                37.559061
+              ],
+              [
+                75.000935,
+                37.53059
+              ],
+              [
+                75.002167,
+                37.511604
+              ],
+              [
+                75.035428,
+                37.500685
+              ],
+              [
+                75.078543,
+                37.511129
+              ],
+              [
+                75.090862,
+                37.486915
+              ],
+              [
+                75.129666,
+                37.459367
+              ],
+              [
+                75.153072,
+                37.414223
+              ],
+              [
+                75.125971,
+                37.388075
+              ],
+              [
+                75.140137,
+                37.355258
+              ],
+              [
+                75.125971,
+                37.322427
+              ],
+              [
+                75.078543,
+                37.318144
+              ],
+              [
+                75.018181,
+                37.293867
+              ],
+              [
+                74.927022,
+                37.277678
+              ],
+              [
+                74.911008,
+                37.233378
+              ],
+              [
+                74.816153,
+                37.216699
+              ],
+              [
+                74.800139,
+                37.248147
+              ],
+              [
+                74.753943,
+                37.281011
+              ],
+              [
+                74.727458,
+                37.282916
+              ],
+              [
+                74.665864,
+                37.23576
+              ],
+              [
+                74.642458,
+                37.261485
+              ],
+              [
+                74.598727,
+                37.258151
+              ],
+              [
+                74.578401,
+                37.231472
+              ],
+              [
+                74.54514,
+                37.2491
+              ],
+              [
+                74.511263,
+                37.240048
+              ],
+              [
+                74.477387,
+                37.19954
+              ],
+              [
+                74.487858,
+                37.161871
+              ],
+              [
+                74.465068,
+                37.147085
+              ],
+              [
+                74.496481,
+                37.116072
+              ],
+              [
+                74.498944,
+                37.072155
+              ],
+              [
+                74.530357,
+                37.082182
+              ],
+              [
+                74.56793,
+                37.032512
+              ],
+              [
+                74.617205,
+                37.043499
+              ],
+              [
+                74.632603,
+                37.066425
+              ],
+              [
+                74.70898,
+                37.084569
+              ],
+              [
+                74.739161,
+                37.028212
+              ],
+              [
+                74.792747,
+                37.027257
+              ],
+              [
+                74.806914,
+                37.054485
+              ],
+              [
+                74.84695,
+                37.056873
+              ],
+              [
+                74.84387,
+                37.0134
+              ],
+              [
+                74.86974,
+                36.990458
+              ],
+              [
+                74.893762,
+                36.939772
+              ],
+              [
+                74.938725,
+                36.94312
+              ],
+              [
+                74.927638,
+                36.978029
+              ],
+              [
+                75.005862,
+                36.99476
+              ],
+              [
+                75.032348,
+                37.016745
+              ],
+              [
+                75.063145,
+                37.006231
+              ],
+              [
+                75.172166,
+                37.013877
+              ],
+              [
+                75.16847,
+                36.991892
+              ],
+              [
+                75.244847,
+                36.963207
+              ],
+              [
+                75.288579,
+                36.974682
+              ],
+              [
+                75.345861,
+                36.960816
+              ],
+              [
+                75.413614,
+                36.954599
+              ],
+              [
+                75.396368,
+                36.904367
+              ],
+              [
+                75.430245,
+                36.873255
+              ],
+              [
+                75.434556,
+                36.83303
+              ],
+              [
+                75.425933,
+                36.778883
+              ],
+              [
+                75.458578,
+                36.720861
+              ],
+              [
+                75.504773,
+                36.743404
+              ],
+              [
+                75.536802,
+                36.729975
+              ],
+              [
+                75.537418,
+                36.773131
+              ],
+              [
+                75.588541,
+                36.762584
+              ],
+              [
+                75.634121,
+                36.771693
+              ],
+              [
+                75.724048,
+                36.750597
+              ],
+              [
+                75.8072,
+                36.707908
+              ],
+              [
+                75.871257,
+                36.666636
+              ],
+              [
+                75.947018,
+                36.590752
+              ],
+              [
+                75.924228,
+                36.566242
+              ],
+              [
+                75.991981,
+                36.505654
+              ],
+              [
+                76.035097,
+                36.409386
+              ],
+              [
+                75.991365,
+                36.35205
+              ],
+              [
+                75.998757,
+                36.312034
+              ],
+              [
+                76.055423,
+                36.252695
+              ],
+              [
+                76.060967,
+                36.225182
+              ],
+              [
+                76.011691,
+                36.229044
+              ],
+              [
+                76.016619,
+                36.165294
+              ],
+              [
+                75.96796,
+                36.159013
+              ],
+              [
+                75.936547,
+                36.13485
+              ],
+              [
+                75.949482,
+                36.070056
+              ],
+              [
+                75.982742,
+                36.031347
+              ],
+              [
+                76.028322,
+                36.016827
+              ],
+              [
+                76.044336,
+                36.026991
+              ],
+              [
+                76.097307,
+                36.022635
+              ],
+              [
+                76.117017,
+                35.975186
+              ],
+              [
+                76.16506,
+                35.908807
+              ],
+              [
+                76.146582,
+                35.839946
+              ],
+              [
+                76.160133,
+                35.82442
+              ],
+              [
+                76.221727,
+                35.823449
+              ],
+              [
+                76.228502,
+                35.837035
+              ],
+              [
+                76.298719,
+                35.841401
+              ],
+              [
+                76.365857,
+                35.82442
+              ],
+              [
+                76.369552,
+                35.86323
+              ],
+              [
+                76.431762,
+                35.851589
+              ],
+              [
+                76.471798,
+                35.886021
+              ],
+              [
+                76.51553,
+                35.881173
+              ],
+              [
+                76.55803,
+                35.923347
+              ],
+              [
+                76.59745,
+                35.895718
+              ],
+              [
+                76.579587,
+                35.866625
+              ],
+              [
+                76.587595,
+                35.840431
+              ],
+              [
+                76.566037,
+                35.819082
+              ],
+              [
+                76.593754,
+                35.771996
+              ],
+              [
+                76.69292,
+                35.747714
+              ],
+              [
+                76.769297,
+                35.653917
+              ],
+              [
+                76.848753,
+                35.668018
+              ],
+              [
+                76.906651,
+                35.615005
+              ],
+              [
+                76.967013,
+                35.591649
+              ],
+              [
+                76.99781,
+                35.611113
+              ],
+              [
+                77.072339,
+                35.591162
+              ],
+              [
+                77.093281,
+                35.569746
+              ],
+              [
+                77.195527,
+                35.519103
+              ],
+              [
+                77.307628,
+                35.540533
+              ],
+              [
+                77.331649,
+                35.530793
+              ],
+              [
+                77.355055,
+                35.494257
+              ],
+              [
+                77.396939,
+                35.467942
+              ],
+              [
+                77.451758,
+                35.46063
+              ],
+              [
+                77.518895,
+                35.482075
+              ],
+              [
+                77.578025,
+                35.47574
+              ],
+              [
+                77.590344,
+                35.460143
+              ],
+              [
+                77.639619,
+                35.45478
+              ],
+              [
+                77.657481,
+                35.477689
+              ],
+              [
+                77.690742,
+                35.448443
+              ],
+              [
+                77.735706,
+                35.461605
+              ],
+              [
+                77.757879,
+                35.497181
+              ],
+              [
+                77.797299,
+                35.491334
+              ],
+              [
+                77.816394,
+                35.518616
+              ],
+              [
+                77.85643,
+                35.487436
+              ],
+              [
+                77.870596,
+                35.495232
+              ],
+              [
+                77.914944,
+                35.465017
+              ],
+              [
+                77.917408,
+                35.490847
+              ],
+              [
+                77.951284,
+                35.478664
+              ],
+              [
+                78.009799,
+                35.491821
+              ],
+              [
+                78.029509,
+                35.469404
+              ],
+              [
+                78.048603,
+                35.491334
+              ],
+              [
+                78.140378,
+                35.494745
+              ],
+              [
+                78.113892,
+                35.466967
+              ],
+              [
+                78.107117,
+                35.437229
+              ],
+              [
+                78.046755,
+                35.384063
+              ],
+              [
+                78.013494,
+                35.366008
+              ],
+              [
+                78.020885,
+                35.315237
+              ],
+              [
+                78.01719,
+                35.228267
+              ],
+              [
+                78.060306,
+                35.180344
+              ],
+              [
+                78.062769,
+                35.114772
+              ],
+              [
+                78.078784,
+                35.100084
+              ],
+              [
+                78.124979,
+                35.108407
+              ],
+              [
+                78.150849,
+                35.069721
+              ],
+              [
+                78.123131,
+                35.036897
+              ],
+              [
+                78.160704,
+                34.990823
+              ],
+              [
+                78.201972,
+                34.974642
+              ],
+              [
+                78.182262,
+                34.936874
+              ],
+              [
+                78.206283,
+                34.891726
+              ],
+              [
+                78.237696,
+                34.882398
+              ],
+              [
+                78.230921,
+                34.776288
+              ],
+              [
+                78.21429,
+                34.760556
+              ],
+              [
+                78.213059,
+                34.717771
+              ],
+              [
+                78.267261,
+                34.705472
+              ],
+              [
+                78.265413,
+                34.651335
+              ],
+              [
+                78.280812,
+                34.623269
+              ],
+              [
+                78.346101,
+                34.60406
+              ],
+              [
+                78.397224,
+                34.605538
+              ],
+              [
+                78.427405,
+                34.594207
+              ],
+              [
+                78.436029,
+                34.543942
+              ],
+              [
+                78.492695,
+                34.578441
+              ],
+              [
+                78.542586,
+                34.574499
+              ],
+              [
+                78.559832,
+                34.55725
+              ],
+              [
+                78.562912,
+                34.51288
+              ],
+              [
+                78.58139,
+                34.505483
+              ],
+              [
+                78.634977,
+                34.538026
+              ],
+              [
+                78.708274,
+                34.522249
+              ],
+              [
+                78.715049,
+                34.502031
+              ],
+              [
+                78.758781,
+                34.481807
+              ],
+              [
+                78.742766,
+                34.45467
+              ],
+              [
+                78.809288,
+                34.432955
+              ],
+              [
+                78.878273,
+                34.391481
+              ],
+              [
+                78.899831,
+                34.354929
+              ],
+              [
+                78.958961,
+                34.386049
+              ],
+              [
+                78.973128,
+                34.362833
+              ],
+              [
+                79.039649,
+                34.33467
+              ],
+              [
+                79.048888,
+                34.348506
+              ],
+              [
+                79.0107,
+                34.399877
+              ],
+              [
+                79.039033,
+                34.421601
+              ],
+              [
+                79.072294,
+                34.412714
+              ],
+              [
+                79.161605,
+                34.441345
+              ],
+              [
+                79.179467,
+                34.422588
+              ],
+              [
+                79.241677,
+                34.415183
+              ],
+              [
+                79.274322,
+                34.435916
+              ],
+              [
+                79.326677,
+                34.44332
+              ],
+              [
+                79.363017,
+                34.428018
+              ],
+              [
+                79.435082,
+                34.447761
+              ],
+              [
+                79.504683,
+                34.45467
+              ],
+              [
+                79.545335,
+                34.476381
+              ],
+              [
+                79.58106,
+                34.456151
+              ],
+              [
+                79.675914,
+                34.451216
+              ],
+              [
+                79.699936,
+                34.477861
+              ],
+              [
+                79.735661,
+                34.471447
+              ],
+              [
+                79.801566,
+                34.478847
+              ],
+              [
+                79.861312,
+                34.528166
+              ],
+              [
+                79.84345,
+                34.55725
+              ],
+              [
+                79.88595,
+                34.642965
+              ],
+              [
+                79.866856,
+                34.671517
+              ],
+              [
+                79.906892,
+                34.683821
+              ],
+              [
+                79.898268,
+                34.732035
+              ],
+              [
+                79.947544,
+                34.821008
+              ],
+              [
+                79.926602,
+                34.849499
+              ],
+              [
+                79.961094,
+                34.862759
+              ],
+              [
+                79.996819,
+                34.856375
+              ],
+              [
+                80.003594,
+                34.895162
+              ],
+              [
+                80.034391,
+                34.902033
+              ],
+              [
+                80.041782,
+                34.943252
+              ],
+              [
+                80.02392,
+                34.971209
+              ],
+              [
+                80.04363,
+                35.022196
+              ],
+              [
+                80.031311,
+                35.034447
+              ],
+              [
+                80.078123,
+                35.076578
+              ],
+              [
+                80.118159,
+                35.066293
+              ],
+              [
+                80.23026,
+                35.147565
+              ],
+              [
+                80.223484,
+                35.177409
+              ],
+              [
+                80.257977,
+                35.203331
+              ],
+              [
+                80.362687,
+                35.20871
+              ],
+              [
+                80.267832,
+                35.295701
+              ],
+              [
+                80.286926,
+                35.35283
+              ],
+              [
+                80.321419,
+                35.38699
+              ],
+              [
+                80.375006,
+                35.387966
+              ],
+              [
+                80.432904,
+                35.449418
+              ],
+              [
+                80.444607,
+                35.417235
+              ],
+              [
+                80.514824,
+                35.391869
+              ],
+              [
+                80.532686,
+                35.404553
+              ],
+              [
+                80.56841,
+                35.391381
+              ],
+              [
+                80.599823,
+                35.409431
+              ],
+              [
+                80.65649,
+                35.393821
+              ],
+              [
+                80.690982,
+                35.364544
+              ],
+              [
+                80.689135,
+                35.339162
+              ],
+              [
+                80.759968,
+                35.334768
+              ],
+              [
+                80.844351,
+                35.345508
+              ],
+              [
+                80.894242,
+                35.324027
+              ],
+              [
+                80.924423,
+                35.330862
+              ],
+              [
+                80.963844,
+                35.310842
+              ],
+              [
+                81.026053,
+                35.31133
+              ],
+              [
+                81.002648,
+                35.334768
+              ],
+              [
+                81.030981,
+                35.337209
+              ],
+              [
+                81.031597,
+                35.380648
+              ],
+              [
+                81.054387,
+                35.402602
+              ],
+              [
+                81.09935,
+                35.40748
+              ],
+              [
+                81.103662,
+                35.386015
+              ],
+              [
+                81.142466,
+                35.365032
+              ],
+              [
+                81.191741,
+                35.36552
+              ],
+              [
+                81.219458,
+                35.319144
+              ],
+              [
+                81.26627,
+                35.322562
+              ],
+              [
+                81.285364,
+                35.345508
+              ],
+              [
+                81.314313,
+                35.337209
+              ],
+              [
+                81.363588,
+                35.354783
+              ],
+              [
+                81.385762,
+                35.335256
+              ],
+              [
+                81.441196,
+                35.333303
+              ],
+              [
+                81.447972,
+                35.318167
+              ],
+              [
+                81.504638,
+                35.279092
+              ],
+              [
+                81.513261,
+                35.23511
+              ],
+              [
+                81.68634,
+                35.235599
+              ],
+              [
+                81.736847,
+                35.26248
+              ],
+              [
+                81.804601,
+                35.270786
+              ],
+              [
+                81.853876,
+                35.25857
+              ],
+              [
+                81.927789,
+                35.271275
+              ],
+              [
+                81.955506,
+                35.307423
+              ],
+              [
+                81.99123,
+                35.30547
+              ],
+              [
+                82.030034,
+                35.321585
+              ],
+              [
+                82.05344,
+                35.35039
+              ],
+              [
+                82.029419,
+                35.426013
+              ],
+              [
+                82.034346,
+                35.451855
+              ],
+              [
+                82.071302,
+                35.450393
+              ],
+              [
+                82.086701,
+                35.467454
+              ],
+              [
+                82.164925,
+                35.495719
+              ],
+              [
+                82.189563,
+                35.513258
+              ],
+              [
+                82.234526,
+                35.520565
+              ],
+              [
+                82.263475,
+                35.547837
+              ],
+              [
+                82.2992,
+                35.544916
+              ],
+              [
+                82.328149,
+                35.559523
+              ],
+              [
+                82.350323,
+                35.611113
+              ],
+              [
+                82.336156,
+                35.651486
+              ],
+              [
+                82.392823,
+                35.656349
+              ],
+              [
+                82.424852,
+                35.712736
+              ],
+              [
+                82.468583,
+                35.717595
+              ],
+              [
+                82.501844,
+                35.701073
+              ],
+              [
+                82.546192,
+                35.708362
+              ],
+              [
+                82.628727,
+                35.692324
+              ],
+              [
+                82.652133,
+                35.67288
+              ],
+              [
+                82.731589,
+                35.637868
+              ],
+              [
+                82.780249,
+                35.666073
+              ],
+              [
+                82.795031,
+                35.688436
+              ],
+              [
+                82.873871,
+                35.688922
+              ],
+              [
+                82.894813,
+                35.673852
+              ],
+              [
+                82.967494,
+                35.667532
+              ],
+              [
+                82.956407,
+                35.636409
+              ],
+              [
+                82.981661,
+                35.599922
+              ],
+              [
+                82.971806,
+                35.548324
+              ],
+              [
+                82.998907,
+                35.484512
+              ],
+              [
+                83.067892,
+                35.46258
+              ],
+              [
+                83.088834,
+                35.425526
+              ],
+              [
+                83.127022,
+                35.398699
+              ],
+              [
+                83.178145,
+                35.38943
+              ],
+              [
+                83.251442,
+                35.417722
+              ],
+              [
+                83.280391,
+                35.401138
+              ],
+              [
+                83.333978,
+                35.397236
+              ],
+              [
+                83.405427,
+                35.380648
+              ],
+              [
+                83.449159,
+                35.382111
+              ],
+              [
+                83.502745,
+                35.360639
+              ],
+              [
+                83.540318,
+                35.364056
+              ],
+              [
+                83.54155,
+                35.341603
+              ],
+              [
+                83.599448,
+                35.351366
+              ],
+              [
+                83.622238,
+                35.335256
+              ],
+              [
+                83.677672,
+                35.361128
+              ],
+              [
+                83.785462,
+                35.36308
+              ],
+              [
+                83.79778,
+                35.354783
+              ],
+              [
+                83.885244,
+                35.367472
+              ],
+              [
+                83.906186,
+                35.40309
+              ],
+              [
+                84.005968,
+                35.422599
+              ],
+              [
+                84.077417,
+                35.400163
+              ],
+              [
+                84.095895,
+                35.362592
+              ],
+              [
+                84.140859,
+                35.379184
+              ],
+              [
+                84.160569,
+                35.359663
+              ],
+              [
+                84.200605,
+                35.381135
+              ],
+              [
+                84.274517,
+                35.404065
+              ],
+              [
+                84.333032,
+                35.413821
+              ],
+              [
+                84.424191,
+                35.466479
+              ],
+              [
+                84.45314,
+                35.473303
+              ],
+              [
+                84.475929,
+                35.516181
+              ],
+              [
+                84.448828,
+                35.550272
+              ],
+              [
+                84.513502,
+                35.564391
+              ],
+              [
+                84.570168,
+                35.588242
+              ],
+              [
+                84.628067,
+                35.595055
+              ],
+              [
+                84.704443,
+                35.616951
+              ],
+              [
+                84.729081,
+                35.613546
+              ],
+              [
+                84.798066,
+                35.647595
+              ],
+              [
+                84.920022,
+                35.696213
+              ],
+              [
+                84.973608,
+                35.709334
+              ],
+              [
+                84.99455,
+                35.737028
+              ],
+              [
+                85.053065,
+                35.752086
+              ],
+              [
+                85.146071,
+                35.742371
+              ],
+              [
+                85.271107,
+                35.788989
+              ],
+              [
+                85.341324,
+                35.753543
+              ],
+              [
+                85.373969,
+                35.700101
+              ],
+              [
+                85.518715,
+                35.680658
+              ],
+              [
+                85.566142,
+                35.6403
+              ],
+              [
+                85.612953,
+                35.651486
+              ],
+              [
+                85.65299,
+                35.731199
+              ],
+              [
+                85.691178,
+                35.751114
+              ],
+              [
+                85.811286,
+                35.778794
+              ],
+              [
+                85.835308,
+                35.771996
+              ],
+              [
+                85.903677,
+                35.78462
+              ],
+              [
+                85.949256,
+                35.778794
+              ],
+              [
+                86.035488,
+                35.846738
+              ],
+              [
+                86.05335,
+                35.842857
+              ],
+              [
+                86.090306,
+                35.876809
+              ],
+              [
+                86.093386,
+                35.906868
+              ],
+              [
+                86.129111,
+                35.941761
+              ],
+              [
+                86.150668,
+                36.00424
+              ],
+              [
+                86.173458,
+                36.008113
+              ],
+              [
+                86.199944,
+                36.047801
+              ],
+              [
+                86.182081,
+                36.064734
+              ],
+              [
+                86.187625,
+                36.130983
+              ],
+              [
+                86.248603,
+                36.141616
+              ],
+              [
+                86.2794,
+                36.170608
+              ],
+              [
+                86.35824,
+                36.168676
+              ],
+              [
+                86.392733,
+                36.206834
+              ],
+              [
+                86.454943,
+                36.221319
+              ],
+              [
+                86.515305,
+                36.205385
+              ],
+              [
+                86.531935,
+                36.227113
+              ],
+              [
+                86.599072,
+                36.222285
+              ],
+              [
+                86.69947,
+                36.24449
+              ],
+              [
+                86.746282,
+                36.291777
+              ],
+              [
+                86.836209,
+                36.291294
+              ],
+              [
+                86.86331,
+                36.299977
+              ],
+              [
+                86.887332,
+                36.262829
+              ],
+              [
+                86.931064,
+                36.265242
+              ],
+              [
+                86.943998,
+                36.284058
+              ],
+              [
+                86.996353,
+                36.308658
+              ],
+              [
+                87.051788,
+                36.2966
+              ],
+              [
+                87.08628,
+                36.310587
+              ],
+              [
+                87.149106,
+                36.297565
+              ],
+              [
+                87.161425,
+                36.325535
+              ],
+              [
+                87.193454,
+                36.349158
+              ],
+              [
+                87.292004,
+                36.358797
+              ],
+              [
+                87.348055,
+                36.393008
+              ],
+              [
+                87.363453,
+                36.420463
+              ],
+              [
+                87.386859,
+                36.412757
+              ],
+              [
+                87.426895,
+                36.42576
+              ],
+              [
+                87.460155,
+                36.409868
+              ],
+              [
+                87.470626,
+                36.354459
+              ],
+              [
+                87.570409,
+                36.342409
+              ],
+              [
+                87.6203,
+                36.360243
+              ],
+              [
+                87.731785,
+                36.384818
+              ],
+              [
+                87.767509,
+                36.3747
+              ],
+              [
+                87.826023,
+                36.391563
+              ],
+              [
+                87.838342,
+                36.383855
+              ],
+              [
+                87.919646,
+                36.39349
+              ],
+              [
+                87.95845,
+                36.408423
+              ],
+              [
+                87.983088,
+                36.437797
+              ],
+              [
+                88.006494,
+                36.430575
+              ],
+              [
+                88.092109,
+                36.43539
+              ],
+              [
+                88.134609,
+                36.427205
+              ],
+              [
+                88.182652,
+                36.452721
+              ],
+              [
+                88.222688,
+                36.447426
+              ],
+              [
+                88.241782,
+                36.468605
+              ],
+              [
+                88.282434,
+                36.470049
+              ],
+              [
+                88.366202,
+                36.458016
+              ],
+              [
+                88.356963,
+                36.477268
+              ],
+              [
+                88.41055,
+                36.473418
+              ],
+              [
+                88.470912,
+                36.48208
+              ],
+              [
+                88.498629,
+                36.446463
+              ],
+              [
+                88.573158,
+                36.461386
+              ],
+              [
+                88.618121,
+                36.428168
+              ],
+              [
+                88.623665,
+                36.389636
+              ],
+              [
+                88.690186,
+                36.367954
+              ],
+              [
+                88.766563,
+                36.292259
+              ],
+              [
+                88.783809,
+                36.291777
+              ],
+              [
+                88.802903,
+                36.33807
+              ],
+              [
+                88.838628,
+                36.353496
+              ],
+              [
+                88.870657,
+                36.348193
+              ],
+              [
+                88.926091,
+                36.36458
+              ],
+              [
+                88.964279,
+                36.318785
+              ],
+              [
+                89.013554,
+                36.315409
+              ],
+              [
+                89.054822,
+                36.291777
+              ],
+              [
+                89.10225,
+                36.281164
+              ],
+              [
+                89.126887,
+                36.254626
+              ],
+              [
+                89.198952,
+                36.260417
+              ],
+              [
+                89.232213,
+                36.295636
+              ],
+              [
+                89.292575,
+                36.231457
+              ],
+              [
+                89.335075,
+                36.23725
+              ],
+              [
+                89.375727,
+                36.228078
+              ],
+              [
+                89.490291,
+                36.151281
+              ],
+              [
+                89.594385,
+                36.126632
+              ],
+              [
+                89.614711,
+                36.109712
+              ],
+              [
+                89.711414,
+                36.093272
+              ],
+              [
+                89.766848,
+                36.073925
+              ],
+              [
+                89.819819,
+                36.080697
+              ],
+              [
+                89.914058,
+                36.079246
+              ],
+              [
+                89.941159,
+                36.067637
+              ],
+              [
+                89.944855,
+                36.140649
+              ],
+              [
+                89.997825,
+                36.168193
+              ],
+              [
+                90.019999,
+                36.213594
+              ],
+              [
+                90.028006,
+                36.258486
+              ],
+              [
+                90.003369,
+                36.278752
+              ],
+              [
+                90.043405,
+                36.276822
+              ],
+              [
+                90.058188,
+                36.255591
+              ],
+              [
+                90.145651,
+                36.239181
+              ],
+              [
+                90.130252,
+                36.2078
+              ],
+              [
+                90.198006,
+                36.187516
+              ],
+              [
+                90.23681,
+                36.160462
+              ],
+              [
+                90.325505,
+                36.159496
+              ],
+              [
+                90.424055,
+                36.133883
+              ],
+              [
+                90.478258,
+                36.13195
+              ],
+              [
+                90.534925,
+                36.147899
+              ],
+              [
+                90.613149,
+                36.126632
+              ],
+              [
+                90.659344,
+                36.13485
+              ],
+              [
+                90.776373,
+                36.086501
+              ],
+              [
+                90.815793,
+                36.035703
+              ],
+              [
+                90.850285,
+                36.016827
+              ],
+              [
+                90.922966,
+                36.028927
+              ],
+              [
+                90.979017,
+                36.106811
+              ],
+              [
+                91.081263,
+                36.088436
+              ],
+              [
+                91.124994,
+                36.115514
+              ],
+              [
+                91.09235,
+                36.163844
+              ],
+              [
+                91.096045,
+                36.219871
+              ],
+              [
+                91.051698,
+                36.238215
+              ],
+              [
+                91.07264,
+                36.299012
+              ],
+              [
+                91.026444,
+                36.323607
+              ],
+              [
+                91.051698,
+                36.433946
+              ],
+              [
+                91.028292,
+                36.443093
+              ],
+              [
+                91.039995,
+                36.474861
+              ],
+              [
+                91.035683,
+                36.529703
+              ],
+              [
+                91.011662,
+                36.539801
+              ],
+              [
+                90.905104,
+                36.560474
+              ],
+              [
+                90.831191,
+                36.55807
+              ],
+              [
+                90.810865,
+                36.585466
+              ],
+              [
+                90.741264,
+                36.585947
+              ],
+              [
+                90.72217,
+                36.620058
+              ],
+              [
+                90.730793,
+                36.655594
+              ],
+              [
+                90.706156,
+                36.658955
+              ],
+              [
+                90.720938,
+                36.708868
+              ],
+              [
+                90.754815,
+                36.721341
+              ],
+              [
+                90.727098,
+                36.755872
+              ],
+              [
+                90.732025,
+                36.825844
+              ],
+              [
+                90.758511,
+                36.825844
+              ],
+              [
+                90.853981,
+                36.915373
+              ],
+              [
+                90.924198,
+                36.921115
+              ],
+              [
+                90.983944,
+                36.913459
+              ],
+              [
+                91.036915,
+                36.929727
+              ],
+              [
+                91.051698,
+                36.96751
+              ],
+              [
+                91.126842,
+                36.978507
+              ],
+              [
+                91.133618,
+                37.007665
+              ],
+              [
+                91.181045,
+                37.025345
+              ],
+              [
+                91.216153,
+                37.010054
+              ],
+              [
+                91.303617,
+                37.012444
+              ],
+              [
+                91.291298,
+                37.042544
+              ],
+              [
+                91.303617,
+                37.083136
+              ],
+              [
+                91.286371,
+                37.105095
+              ],
+              [
+                91.280211,
+                37.163779
+              ],
+              [
+                91.1909,
+                37.205737
+              ],
+              [
+                91.194596,
+                37.273868
+              ],
+              [
+                91.134849,
+                37.324331
+              ],
+              [
+                91.136081,
+                37.355734
+              ],
+              [
+                91.113292,
+                37.387124
+              ],
+              [
+                91.099741,
+                37.447965
+              ],
+              [
+                91.073256,
+                37.475992
+              ],
+              [
+                91.019669,
+                37.493088
+              ],
+              [
+                90.958075,
+                37.477891
+              ],
+              [
+                90.911879,
+                37.519674
+              ],
+              [
+                90.865684,
+                37.53059
+              ],
+              [
+                90.882314,
+                37.575664
+              ],
+              [
+                90.854597,
+                37.604117
+              ],
+              [
+                90.820104,
+                37.613599
+              ],
+              [
+                90.777605,
+                37.648672
+              ],
+              [
+                90.643946,
+                37.696988
+              ],
+              [
+                90.586663,
+                37.703144
+              ],
+              [
+                90.579272,
+                37.720661
+              ],
+              [
+                90.519526,
+                37.730601
+              ],
+              [
+                90.516446,
+                38.207111
+              ],
+              [
+                90.531229,
+                38.319886
+              ],
+              [
+                90.401882,
+                38.311434
+              ],
+              [
+                90.361846,
+                38.300163
+              ],
+              [
+                90.352607,
+                38.233441
+              ],
+              [
+                90.280542,
+                38.238142
+              ],
+              [
+                90.137644,
+                38.340543
+              ],
+              [
+                90.179528,
+                38.396848
+              ],
+              [
+                90.129636,
+                38.400131
+              ],
+              [
+                90.111774,
+                38.418889
+              ],
+              [
+                90.111774,
+                38.477945
+              ],
+              [
+                90.130868,
+                38.494341
+              ],
+              [
+                90.248513,
+                38.491531
+              ],
+              [
+                90.315034,
+                38.501835
+              ],
+              [
+                90.353222,
+                38.482162
+              ],
+              [
+                90.427135,
+                38.493873
+              ],
+              [
+                90.465323,
+                38.521971
+              ],
+              [
+                90.463476,
+                38.556611
+              ],
+              [
+                90.525685,
+                38.561291
+              ],
+              [
+                90.560794,
+                38.593573
+              ],
+              [
+                90.608837,
+                38.594508
+              ],
+              [
+                90.606374,
+                38.610878
+              ],
+              [
+                90.645794,
+                38.635191
+              ],
+              [
+                90.619308,
+                38.664636
+              ],
+              [
+                90.65996,
+                38.674449
+              ],
+              [
+                90.724634,
+                38.658094
+              ],
+              [
+                90.899561,
+                38.679588
+              ],
+              [
+                90.970394,
+                38.697806
+              ],
+              [
+                90.992567,
+                38.695003
+              ],
+              [
+                91.188436,
+                38.73096
+              ],
+              [
+                91.242639,
+                38.752433
+              ],
+              [
+                91.298689,
+                38.746365
+              ],
+              [
+                91.446515,
+                38.813546
+              ],
+              [
+                91.501333,
+                38.815411
+              ],
+              [
+                91.681188,
+                38.852706
+              ],
+              [
+                91.694738,
+                38.86622
+              ],
+              [
+                91.806223,
+                38.872744
+              ],
+              [
+                91.87952,
+                38.884391
+              ],
+              [
+                91.880752,
+                38.899297
+              ],
+              [
+                91.966368,
+                38.930961
+              ],
+              [
+                92.10865,
+                38.963541
+              ],
+              [
+                92.173323,
+                38.960749
+              ],
+              [
+                92.197961,
+                38.983548
+              ],
+              [
+                92.263866,
+                39.002153
+              ],
+              [
+                92.380279,
+                38.999828
+              ],
+              [
+                92.416003,
+                39.010524
+              ],
+              [
+                92.41046,
+                39.03842
+              ],
+              [
+                92.366728,
+                39.059335
+              ],
+              [
+                92.366112,
+                39.096037
+              ],
+              [
+                92.343938,
+                39.146181
+              ],
+              [
+                92.339011,
+                39.236628
+              ],
+              [
+                92.378431,
+                39.258411
+              ],
+              [
+                92.52564,
+                39.368611
+              ],
+              [
+                92.639589,
+                39.514196
+              ],
+              [
+                92.687632,
+                39.657174
+              ],
+              [
+                92.745531,
+                39.868331
+              ],
+              [
+                92.796654,
+                40.153897
+              ],
+              [
+                92.906907,
+                40.310609
+              ],
+              [
+                92.920458,
+                40.391792
+              ],
+              [
+                92.928465,
+                40.572504
+              ],
+              [
+                93.506216,
+                40.648376
+              ],
+              [
+                93.760599,
+                40.664721
+              ],
+              [
+                93.820961,
+                40.793519
+              ],
+              [
+                93.809874,
+                40.879548
+              ],
+              [
+                93.908424,
+                40.983539
+              ],
+              [
+                94.01067,
+                41.114875
+              ],
+              [
+                94.184365,
+                41.268444
+              ],
+              [
+                94.534219,
+                41.505966
+              ],
+              [
+                94.750413,
+                41.538227
+              ],
+              [
+                94.809543,
+                41.619256
+              ],
+              [
+                94.861898,
+                41.668451
+              ],
+              [
+                94.969072,
+                41.718948
+              ],
+              [
+                95.011572,
+                41.726541
+              ],
+              [
+                95.110738,
+                41.768513
+              ],
+              [
+                95.135991,
+                41.772976
+              ],
+              [
+                95.16494,
+                41.735474
+              ],
+              [
+                95.199433,
+                41.719395
+              ],
+              [
+                95.194505,
+                41.694821
+              ],
+              [
+                95.247476,
+                41.61344
+              ],
+              [
+                95.299831,
+                41.565994
+              ],
+              [
+                95.335556,
+                41.644305
+              ],
+              [
+                95.39407,
+                41.693481
+              ],
+              [
+                95.445193,
+                41.719841
+              ],
+              [
+                95.57146,
+                41.796181
+              ],
+              [
+                95.65646,
+                41.826067
+              ],
+              [
+                95.759322,
+                41.835878
+              ],
+              [
+                95.801206,
+                41.848361
+              ],
+              [
+                95.855408,
+                41.849699
+              ],
+              [
+                95.998306,
+                41.906289
+              ],
+              [
+                96.054973,
+                41.936124
+              ],
+              [
+                96.117183,
+                41.985966
+              ],
+              [
+                96.137509,
+                42.019765
+              ],
+              [
+                96.13874,
+                42.05399
+              ],
+              [
+                96.077147,
+                42.149457
+              ],
+              [
+                96.178161,
+                42.21775
+              ],
+              [
+                96.040806,
+                42.326688
+              ],
+              [
+                96.042038,
+                42.352787
+              ],
+              [
+                96.06606,
+                42.414674
+              ],
+              [
+                95.978596,
+                42.436762
+              ],
+              [
+                96.0174,
+                42.482239
+              ],
+              [
+                96.02356,
+                42.542675
+              ],
+              [
+                96.072219,
+                42.569566
+              ],
+              [
+                96.103632,
+                42.604375
+              ],
+              [
+                96.166458,
+                42.623314
+              ],
+              [
+                96.386348,
+                42.727592
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 710000,
+        "name": "鍙版咕鐪�",
+        "center": [
+          121.509062,
+          25.044332
+        ],
+        "centroid": [
+          120.971485,
+          23.749452
+        ],
+        "childrenNum": 0,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 31,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                120.443706,
+                22.441432
+              ],
+              [
+                120.517619,
+                22.408793
+              ],
+              [
+                120.569973,
+                22.361757
+              ],
+              [
+                120.640806,
+                22.241605
+              ],
+              [
+                120.659285,
+                22.154056
+              ],
+              [
+                120.661748,
+                22.067007
+              ],
+              [
+                120.651277,
+                22.033171
+              ],
+              [
+                120.667908,
+                21.983235
+              ],
+              [
+                120.701784,
+                21.927174
+              ],
+              [
+                120.743052,
+                21.915515
+              ],
+              [
+                120.781857,
+                21.923843
+              ],
+              [
+                120.854537,
+                21.883309
+              ],
+              [
+                120.873016,
+                21.897191
+              ],
+              [
+                120.86624,
+                21.984345
+              ],
+              [
+                120.907508,
+                22.033171
+              ],
+              [
+                120.912436,
+                22.086418
+              ],
+              [
+                120.903197,
+                22.12634
+              ],
+              [
+                120.914899,
+                22.302525
+              ],
+              [
+                120.981421,
+                22.528248
+              ],
+              [
+                121.014682,
+                22.584069
+              ],
+              [
+                121.03316,
+                22.650914
+              ],
+              [
+                121.078739,
+                22.669691
+              ],
+              [
+                121.170514,
+                22.723247
+              ],
+              [
+                121.21055,
+                22.770711
+              ],
+              [
+                121.237652,
+                22.836362
+              ],
+              [
+                121.276456,
+                22.877171
+              ],
+              [
+                121.324499,
+                22.945526
+              ],
+              [
+                121.35468,
+                23.00999
+              ],
+              [
+                121.370695,
+                23.084334
+              ],
+              [
+                121.409499,
+                23.1025
+              ],
+              [
+                121.430441,
+                23.137175
+              ],
+              [
+                121.415042,
+                23.196047
+              ],
+              [
+                121.440296,
+                23.271937
+              ],
+              [
+                121.479716,
+                23.322507
+              ],
+              [
+                121.497578,
+                23.419744
+              ],
+              [
+                121.5216,
+                23.483431
+              ],
+              [
+                121.522832,
+                23.538858
+              ],
+              [
+                121.587505,
+                23.760878
+              ],
+              [
+                121.621382,
+                23.920718
+              ],
+              [
+                121.65957,
+                24.007125
+              ],
+              [
+                121.63986,
+                24.064514
+              ],
+              [
+                121.643556,
+                24.097843
+              ],
+              [
+                121.678048,
+                24.133895
+              ],
+              [
+                121.689135,
+                24.174303
+              ],
+              [
+                121.809243,
+                24.339083
+              ],
+              [
+                121.82649,
+                24.423572
+              ],
+              [
+                121.867758,
+                24.47914
+              ],
+              [
+                121.88562,
+                24.529784
+              ],
+              [
+                121.892395,
+                24.617953
+              ],
+              [
+                121.86283,
+                24.671261
+              ],
+              [
+                121.841272,
+                24.734329
+              ],
+              [
+                121.844968,
+                24.836476
+              ],
+              [
+                121.933047,
+                24.938539
+              ],
+              [
+                122.012503,
+                25.001471
+              ],
+              [
+                121.98109,
+                25.030757
+              ],
+              [
+                121.947214,
+                25.031841
+              ],
+              [
+                121.917033,
+                25.138076
+              ],
+              [
+                121.841888,
+                25.135367
+              ],
+              [
+                121.782142,
+                25.160287
+              ],
+              [
+                121.745186,
+                25.161912
+              ],
+              [
+                121.707613,
+                25.191701
+              ],
+              [
+                121.700222,
+                25.226896
+              ],
+              [
+                121.655259,
+                25.242054
+              ],
+              [
+                121.62323,
+                25.29455
+              ],
+              [
+                121.585041,
+                25.309159
+              ],
+              [
+                121.53515,
+                25.307535
+              ],
+              [
+                121.444607,
+                25.27074
+              ],
+              [
+                121.413194,
+                25.238806
+              ],
+              [
+                121.371926,
+                25.159746
+              ],
+              [
+                121.319572,
+                25.140785
+              ],
+              [
+                121.209318,
+                25.12724
+              ],
+              [
+                121.132942,
+                25.078466
+              ],
+              [
+                121.102145,
+                25.075214
+              ],
+              [
+                121.024537,
+                25.040517
+              ],
+              [
+                121.009754,
+                24.993878
+              ],
+              [
+                120.961095,
+                24.940167
+              ],
+              [
+                120.914899,
+                24.864715
+              ],
+              [
+                120.89211,
+                24.767482
+              ],
+              [
+                120.82374,
+                24.688118
+              ],
+              [
+                120.762147,
+                24.658208
+              ],
+              [
+                120.68885,
+                24.600542
+              ],
+              [
+                120.642654,
+                24.490033
+              ],
+              [
+                120.589068,
+                24.43229
+              ],
+              [
+                120.546568,
+                24.370159
+              ],
+              [
+                120.520698,
+                24.311816
+              ],
+              [
+                120.470807,
+                24.242533
+              ],
+              [
+                120.451713,
+                24.182493
+              ],
+              [
+                120.391967,
+                24.118055
+              ],
+              [
+                120.316206,
+                23.984708
+              ],
+              [
+                120.278018,
+                23.92783
+              ],
+              [
+                120.245989,
+                23.840276
+              ],
+              [
+                120.175156,
+                23.807427
+              ],
+              [
+                120.102476,
+                23.701162
+              ],
+              [
+                120.095084,
+                23.58768
+              ],
+              [
+                120.12157,
+                23.504836
+              ],
+              [
+                120.108019,
+                23.341191
+              ],
+              [
+                120.081534,
+                23.291728
+              ],
+              [
+                120.018708,
+                23.073322
+              ],
+              [
+                120.029795,
+                23.048544
+              ],
+              [
+                120.133272,
+                23.000625
+              ],
+              [
+                120.149287,
+                22.896468
+              ],
+              [
+                120.20041,
+                22.721039
+              ],
+              [
+                120.274323,
+                22.560307
+              ],
+              [
+                120.297112,
+                22.531565
+              ],
+              [
+                120.443706,
+                22.441432
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                124.542782,
+                25.903886
+              ],
+              [
+                124.584666,
+                25.908731
+              ],
+              [
+                124.566804,
+                25.941563
+              ],
+              [
+                124.542782,
+                25.903886
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.445178,
+                25.726102
+              ],
+              [
+                123.469816,
+                25.712623
+              ],
+              [
+                123.50862,
+                25.722867
+              ],
+              [
+                123.512316,
+                25.755212
+              ],
+              [
+                123.479055,
+                25.768687
+              ],
+              [
+                123.445794,
+                25.749822
+              ],
+              [
+                123.445178,
+                25.726102
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.646064,
+                23.550928
+              ],
+              [
+                119.691028,
+                23.547087
+              ],
+              [
+                119.678093,
+                23.600294
+              ],
+              [
+                119.61034,
+                23.604132
+              ],
+              [
+                119.601717,
+                23.575613
+              ],
+              [
+                119.566608,
+                23.584937
+              ],
+              [
+                119.562297,
+                23.530627
+              ],
+              [
+                119.578927,
+                23.502641
+              ],
+              [
+                119.609108,
+                23.503738
+              ],
+              [
+                119.646064,
+                23.550928
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                123.666916,
+                25.914114
+              ],
+              [
+                123.706952,
+                25.91519
+              ],
+              [
+                123.689706,
+                25.939949
+              ],
+              [
+                123.666916,
+                25.914114
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.506246,
+                23.625518
+              ],
+              [
+                119.506246,
+                23.577259
+              ],
+              [
+                119.47237,
+                23.556962
+              ],
+              [
+                119.519181,
+                23.559705
+              ],
+              [
+                119.52534,
+                23.62497
+              ],
+              [
+                119.506246,
+                23.625518
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.497623,
+                23.38679
+              ],
+              [
+                119.495159,
+                23.349982
+              ],
+              [
+                119.516717,
+                23.349982
+              ],
+              [
+                119.497623,
+                23.38679
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.557369,
+                23.666634
+              ],
+              [
+                119.608492,
+                23.620035
+              ],
+              [
+                119.615268,
+                23.661153
+              ],
+              [
+                119.586318,
+                23.675952
+              ],
+              [
+                119.557369,
+                23.666634
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.066706,
+                25.6247
+              ],
+              [
+                122.087032,
+                25.61067
+              ],
+              [
+                122.092575,
+                25.639268
+              ],
+              [
+                122.066706,
+                25.6247
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.468013,
+                22.67687
+              ],
+              [
+                121.474788,
+                22.643734
+              ],
+              [
+                121.513592,
+                22.631582
+              ],
+              [
+                121.514824,
+                22.676318
+              ],
+              [
+                121.468013,
+                22.67687
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.510513,
+                22.086972
+              ],
+              [
+                121.507433,
+                22.048704
+              ],
+              [
+                121.533918,
+                22.022076
+              ],
+              [
+                121.594281,
+                21.995443
+              ],
+              [
+                121.604752,
+                22.022631
+              ],
+              [
+                121.575186,
+                22.037055
+              ],
+              [
+                121.575802,
+                22.0842
+              ],
+              [
+                121.510513,
+                22.086972
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                122.097503,
+                25.499987
+              ],
+              [
+                122.110438,
+                25.465952
+              ],
+              [
+                122.122141,
+                25.495666
+              ],
+              [
+                122.097503,
+                25.499987
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.421247,
+                23.216949
+              ],
+              [
+                119.436029,
+                23.186146
+              ],
+              [
+                119.453275,
+                23.216399
+              ],
+              [
+                119.421247,
+                23.216949
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                120.355011,
+                22.327439
+              ],
+              [
+                120.395663,
+                22.342385
+              ],
+              [
+                120.383344,
+                22.355669
+              ],
+              [
+                120.355011,
+                22.327439
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 810000,
+        "name": "棣欐腐鐗瑰埆琛屾斂鍖�",
+        "center": [
+          114.173355,
+          22.320048
+        ],
+        "centroid": [
+          114.134357,
+          22.377366
+        ],
+        "childrenNum": 18,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 32,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                114.031778,
+                22.503923
+              ],
+              [
+                114.000981,
+                22.491206
+              ],
+              [
+                113.977575,
+                22.45692
+              ],
+              [
+                113.918445,
+                22.418199
+              ],
+              [
+                113.920293,
+                22.367845
+              ],
+              [
+                113.951706,
+                22.355116
+              ],
+              [
+                113.956633,
+                22.359543
+              ],
+              [
+                113.980039,
+                22.366185
+              ],
+              [
+                114.026234,
+                22.34792
+              ],
+              [
+                113.955401,
+                22.298649
+              ],
+              [
+                113.969568,
+                22.321349
+              ],
+              [
+                113.898119,
+                22.308615
+              ],
+              [
+                113.889496,
+                22.271514
+              ],
+              [
+                113.8433,
+                22.229418
+              ],
+              [
+                113.84946,
+                22.191188
+              ],
+              [
+                113.899351,
+                22.215568
+              ],
+              [
+                113.935691,
+                22.205041
+              ],
+              [
+                113.981271,
+                22.229972
+              ],
+              [
+                113.996669,
+                22.206149
+              ],
+              [
+                114.026234,
+                22.229418
+              ],
+              [
+                114.004676,
+                22.239389
+              ],
+              [
+                114.02993,
+                22.263207
+              ],
+              [
+                114.034857,
+                22.300864
+              ],
+              [
+                114.069966,
+                22.326885
+              ],
+              [
+                114.121089,
+                22.320795
+              ],
+              [
+                114.145726,
+                22.300864
+              ],
+              [
+                114.120473,
+                22.272068
+              ],
+              [
+                114.164821,
+                22.226648
+              ],
+              [
+                114.200545,
+                22.232188
+              ],
+              [
+                114.203009,
+                22.206703
+              ],
+              [
+                114.265835,
+                22.200608
+              ],
+              [
+                114.248588,
+                22.274837
+              ],
+              [
+                114.262139,
+                22.294773
+              ],
+              [
+                114.284929,
+                22.263761
+              ],
+              [
+                114.313262,
+                22.264315
+              ],
+              [
+                114.315726,
+                22.299203
+              ],
+              [
+                114.315726,
+                22.299756
+              ],
+              [
+                114.278153,
+                22.328546
+              ],
+              [
+                114.283081,
+                22.386661
+              ],
+              [
+                114.322501,
+                22.385554
+              ],
+              [
+                114.323117,
+                22.385554
+              ],
+              [
+                114.323733,
+                22.385001
+              ],
+              [
+                114.323733,
+                22.384447
+              ],
+              [
+                114.356994,
+                22.340171
+              ],
+              [
+                114.394566,
+                22.361757
+              ],
+              [
+                114.385327,
+                22.41156
+              ],
+              [
+                114.406269,
+                22.432582
+              ],
+              [
+                114.406269,
+                22.433688
+              ],
+              [
+                114.376088,
+                22.436454
+              ],
+              [
+                114.325581,
+                22.479041
+              ],
+              [
+                114.278769,
+                22.435901
+              ],
+              [
+                114.220255,
+                22.427603
+              ],
+              [
+                114.205473,
+                22.449729
+              ],
+              [
+                114.23319,
+                22.466875
+              ],
+              [
+                114.2529,
+                22.445304
+              ],
+              [
+                114.340979,
+                22.50337
+              ],
+              [
+                114.309566,
+                22.497288
+              ],
+              [
+                114.28924,
+                22.52272
+              ],
+              [
+                114.263987,
+                22.541515
+              ],
+              [
+                114.263371,
+                22.541515
+              ],
+              [
+                114.260291,
+                22.547595
+              ],
+              [
+                114.232574,
+                22.528801
+              ],
+              [
+                114.232574,
+                22.539857
+              ],
+              [
+                114.222719,
+                22.553122
+              ],
+              [
+                114.166052,
+                22.559201
+              ],
+              [
+                114.156813,
+                22.543726
+              ],
+              [
+                114.095219,
+                22.534329
+              ],
+              [
+                114.082285,
+                22.512216
+              ],
+              [
+                114.031778,
+                22.503923
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.142647,
+                22.213906
+              ],
+              [
+                114.123553,
+                22.238836
+              ],
+              [
+                114.120473,
+                22.177888
+              ],
+              [
+                114.154965,
+                22.177888
+              ],
+              [
+                114.166668,
+                22.205041
+              ],
+              [
+                114.142647,
+                22.213906
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.305871,
+                22.372273
+              ],
+              [
+                114.313878,
+                22.340724
+              ],
+              [
+                114.332972,
+                22.353455
+              ],
+              [
+                114.305255,
+                22.372826
+              ],
+              [
+                114.305871,
+                22.372273
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.320037,
+                22.381127
+              ],
+              [
+                114.323733,
+                22.384447
+              ],
+              [
+                114.323733,
+                22.385001
+              ],
+              [
+                114.323117,
+                22.385554
+              ],
+              [
+                114.322501,
+                22.385554
+              ],
+              [
+                114.319421,
+                22.382234
+              ],
+              [
+                114.320037,
+                22.38168
+              ],
+              [
+                114.320037,
+                22.381127
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.305871,
+                22.369506
+              ],
+              [
+                114.305871,
+                22.372273
+              ],
+              [
+                114.305255,
+                22.372826
+              ],
+              [
+                114.305871,
+                22.369506
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.315726,
+                22.299203
+              ],
+              [
+                114.316958,
+                22.298649
+              ],
+              [
+                114.316342,
+                22.30031
+              ],
+              [
+                114.315726,
+                22.299756
+              ],
+              [
+                114.315726,
+                22.299203
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.319421,
+                22.382234
+              ],
+              [
+                114.320037,
+                22.381127
+              ],
+              [
+                114.320037,
+                22.38168
+              ],
+              [
+                114.319421,
+                22.382234
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.372392,
+                22.32301
+              ],
+              [
+                114.373008,
+                22.323564
+              ],
+              [
+                114.372392,
+                22.323564
+              ],
+              [
+                114.372392,
+                22.32301
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                114.323733,
+                22.297541
+              ],
+              [
+                114.324349,
+                22.297541
+              ],
+              [
+                114.323733,
+                22.298095
+              ],
+              [
+                114.323733,
+                22.297541
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "adcode": 820000,
+        "name": "婢抽棬鐗瑰埆琛屾斂鍖�",
+        "center": [
+          113.54909,
+          22.198951
+        ],
+        "centroid": [
+          113.566988,
+          22.159307
+        ],
+        "childrenNum": 8,
+        "level": "province",
+        "parent": {
+          "adcode": 100000
+        },
+        "subFeatureIndex": 33,
+        "acroutes": [
+          100000
+        ]
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                113.554425,
+                22.107489
+              ],
+              [
+                113.6037,
+                22.132438
+              ],
+              [
+                113.575983,
+                22.194513
+              ],
+              [
+                113.558736,
+                22.212244
+              ],
+              [
+                113.53841,
+                22.209473
+              ],
+              [
+                113.534715,
+                22.174009
+              ],
+              [
+                113.554425,
+                22.142416
+              ],
+              [
+                113.554425,
+                22.107489
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                113.586453,
+                22.201162
+              ],
+              [
+                113.575983,
+                22.201162
+              ],
+              [
+                113.575983,
+                22.194513
+              ],
+              [
+                113.586453,
+                22.201162
+              ]
+            ]
+          ]
+        ]
+      }
+    },
+    {
+      "type": "Feature",
+      "properties": {
+        "name": "",
+        "adchar": "JD",
+        "adcode": "100000_JD"
+      },
+      "geometry": {
+        "type": "MultiPolygon",
+        "coordinates": [
+          [
+            [
+              [
+                122.51865306,
+                23.46078502
+              ],
+              [
+                122.79861399,
+                24.57367379
+              ],
+              [
+                122.79889322,
+                24.57678999
+              ],
+              [
+                122.79819583,
+                24.57983997
+              ],
+              [
+                122.79659008,
+                24.58252516
+              ],
+              [
+                122.79423315,
+                24.58458272
+              ],
+              [
+                122.79135575,
+                24.58581125
+              ],
+              [
+                122.78823955,
+                24.58609049
+              ],
+              [
+                122.78518957,
+                24.5853931
+              ],
+              [
+                122.78250438,
+                24.58378734
+              ],
+              [
+                122.78044682,
+                24.58143041
+              ],
+              [
+                122.77921829,
+                24.57855302
+              ],
+              [
+                122.49925737,
+                23.46566424
+              ],
+              [
+                122.49897813,
+                23.46254804
+              ],
+              [
+                122.49967552,
+                23.45949807
+              ],
+              [
+                122.50128127,
+                23.45681287
+              ],
+              [
+                122.5036382,
+                23.45475531
+              ],
+              [
+                122.5065156,
+                23.45352678
+              ],
+              [
+                122.50963181,
+                23.45324755
+              ],
+              [
+                122.51268178,
+                23.45394494
+              ],
+              [
+                122.51536697,
+                23.45555069
+              ],
+              [
+                122.51742454,
+                23.45790762
+              ],
+              [
+                122.51865306,
+                23.46078502
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                121.17202617,
+                20.8054593
+              ],
+              [
+                121.90938804,
+                21.68743347
+              ],
+              [
+                121.9109946,
+                21.69011818
+              ],
+              [
+                121.91169291,
+                21.69316794
+              ],
+              [
+                121.91141462,
+                21.69628423
+              ],
+              [
+                121.91018696,
+                21.699162
+              ],
+              [
+                121.9081301,
+                21.70151955
+              ],
+              [
+                121.9054454,
+                21.70312611
+              ],
+              [
+                121.90239563,
+                21.70382443
+              ],
+              [
+                121.89927934,
+                21.70354613
+              ],
+              [
+                121.89640158,
+                21.70231847
+              ],
+              [
+                121.89404403,
+                21.70026162
+              ],
+              [
+                121.15668216,
+                20.81828744
+              ],
+              [
+                121.1550756,
+                20.81560273
+              ],
+              [
+                121.15437729,
+                20.81255297
+              ],
+              [
+                121.15465558,
+                20.80943668
+              ],
+              [
+                121.15588324,
+                20.80655891
+              ],
+              [
+                121.1579401,
+                20.80420136
+              ],
+              [
+                121.1606248,
+                20.8025948
+              ],
+              [
+                121.16367457,
+                20.80189649
+              ],
+              [
+                121.16679085,
+                20.80217478
+              ],
+              [
+                121.16966862,
+                20.80340244
+              ],
+              [
+                121.17202617,
+                20.8054593
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.47366172,
+                18.00707291
+              ],
+              [
+                120.02569734,
+                19.02403788
+              ],
+              [
+                120.02674143,
+                19.02698721
+              ],
+              [
+                120.02682302,
+                19.03011484
+              ],
+              [
+                120.02593412,
+                19.0331146
+              ],
+              [
+                120.02416175,
+                19.03569286
+              ],
+              [
+                120.02167941,
+                19.03759723
+              ],
+              [
+                120.01873007,
+                19.03864132
+              ],
+              [
+                120.01560245,
+                19.03872291
+              ],
+              [
+                120.01260269,
+                19.03783401
+              ],
+              [
+                120.01002443,
+                19.03606165
+              ],
+              [
+                120.00812005,
+                19.0335793
+              ],
+              [
+                119.45608443,
+                18.01661433
+              ],
+              [
+                119.45504035,
+                18.01366499
+              ],
+              [
+                119.45495876,
+                18.01053737
+              ],
+              [
+                119.45584765,
+                18.00753761
+              ],
+              [
+                119.45762002,
+                18.00495935
+              ],
+              [
+                119.46010237,
+                18.00305497
+              ],
+              [
+                119.4630517,
+                18.00201089
+              ],
+              [
+                119.46617933,
+                18.0019293
+              ],
+              [
+                119.46917909,
+                18.0028182
+              ],
+              [
+                119.47175735,
+                18.00459056
+              ],
+              [
+                119.47366172,
+                18.00707291
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                119.0726757,
+                15.04098494
+              ],
+              [
+                119.0726757,
+                16.04388528
+              ],
+              [
+                119.07218626,
+                16.04697545
+              ],
+              [
+                119.07076587,
+                16.04976313
+              ],
+              [
+                119.06855355,
+                16.05197545
+              ],
+              [
+                119.06576587,
+                16.05339584
+              ],
+              [
+                119.0626757,
+                16.05388528
+              ],
+              [
+                119.05958553,
+                16.05339584
+              ],
+              [
+                119.05679784,
+                16.05197545
+              ],
+              [
+                119.05458553,
+                16.04976313
+              ],
+              [
+                119.05316513,
+                16.04697545
+              ],
+              [
+                119.0526757,
+                16.04388528
+              ],
+              [
+                119.0526757,
+                15.04105889
+              ],
+              [
+                119.0521839,
+                15.00781004
+              ],
+              [
+                119.05262758,
+                15.00471297
+              ],
+              [
+                119.05400659,
+                15.00190458
+              ],
+              [
+                119.05618595,
+                14.99965979
+              ],
+              [
+                119.05895232,
+                14.99819832
+              ],
+              [
+                119.06203491,
+                14.99766324
+              ],
+              [
+                119.06513198,
+                14.99810691
+              ],
+              [
+                119.06794036,
+                14.99948592
+              ],
+              [
+                119.07018516,
+                15.00166528
+              ],
+              [
+                119.07164663,
+                15.00443165
+              ],
+              [
+                119.07218171,
+                15.00751424
+              ],
+              [
+                119.0726746,
+                15.04083704
+              ],
+              [
+                119.0726757,
+                15.04098494
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                118.68646749,
+                11.18959191
+              ],
+              [
+                118.52518702,
+                10.91547751
+              ],
+              [
+                118.52404181,
+                10.91256595
+              ],
+              [
+                118.52385237,
+                10.909443
+              ],
+              [
+                118.52463726,
+                10.90641436
+              ],
+              [
+                118.52631962,
+                10.9037765
+              ],
+              [
+                118.5287348,
+                10.90178762
+              ],
+              [
+                118.53164636,
+                10.90064241
+              ],
+              [
+                118.53476931,
+                10.90045298
+              ],
+              [
+                118.53779795,
+                10.90123786
+              ],
+              [
+                118.54043581,
+                10.90292022
+              ],
+              [
+                118.54242469,
+                10.9053354
+              ],
+              [
+                118.70409227,
+                11.18010771
+              ],
+              [
+                118.70476212,
+                11.18147468
+              ],
+              [
+                118.87431591,
+                11.606662
+              ],
+              [
+                118.87459939,
+                11.60747236
+              ],
+              [
+                118.98894963,
+                11.98573108
+              ],
+              [
+                118.98937534,
+                11.98883067
+              ],
+              [
+                118.9888224,
+                11.99191011
+              ],
+              [
+                118.98734492,
+                11.99466796
+              ],
+              [
+                118.98508753,
+                11.99683427
+              ],
+              [
+                118.98227119,
+                11.99819697
+              ],
+              [
+                118.9791716,
+                11.99862269
+              ],
+              [
+                118.97609216,
+                11.99806975
+              ],
+              [
+                118.97333431,
+                11.99659227
+              ],
+              [
+                118.97116801,
+                11.99433487
+              ],
+              [
+                118.9698053,
+                11.99151854
+              ],
+              [
+                118.85557939,
+                11.6136711
+              ],
+              [
+                118.68646749,
+                11.18959191
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                115.54466883,
+                7.14672265
+              ],
+              [
+                116.2504858,
+                7.979279
+              ],
+              [
+                116.25211077,
+                7.98195261
+              ],
+              [
+                116.25283001,
+                7.9849975
+              ],
+              [
+                116.25257312,
+                7.98811563
+              ],
+              [
+                116.25136525,
+                7.99100176
+              ],
+              [
+                116.24932463,
+                7.99337338
+              ],
+              [
+                116.24665102,
+                7.99499834
+              ],
+              [
+                116.24360613,
+                7.99571758
+              ],
+              [
+                116.240488,
+                7.99546069
+              ],
+              [
+                116.23760187,
+                7.99425282
+              ],
+              [
+                116.23523025,
+                7.99221221
+              ],
+              [
+                115.52941328,
+                7.15965587
+              ],
+              [
+                115.52778832,
+                7.15698226
+              ],
+              [
+                115.52706908,
+                7.15393736
+              ],
+              [
+                115.52732596,
+                7.15081924
+              ],
+              [
+                115.52853383,
+                7.1479331
+              ],
+              [
+                115.53057445,
+                7.14556148
+              ],
+              [
+                115.53324806,
+                7.14393652
+              ],
+              [
+                115.53629295,
+                7.14321728
+              ],
+              [
+                115.53941108,
+                7.14347417
+              ],
+              [
+                115.54229721,
+                7.14468204
+              ],
+              [
+                115.54466883,
+                7.14672265
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                112.30705249,
+                3.53487257
+              ],
+              [
+                111.78690114,
+                3.41687263
+              ],
+              [
+                111.78399583,
+                3.41571167
+              ],
+              [
+                111.78159146,
+                3.41370973
+              ],
+              [
+                111.77992341,
+                3.41106279
+              ],
+              [
+                111.77915495,
+                3.40802995
+              ],
+              [
+                111.77936129,
+                3.40490807
+              ],
+              [
+                111.78052226,
+                3.40200275
+              ],
+              [
+                111.78252419,
+                3.39959839
+              ],
+              [
+                111.78517113,
+                3.39793033
+              ],
+              [
+                111.78820398,
+                3.39716187
+              ],
+              [
+                111.79132585,
+                3.39736822
+              ],
+              [
+                112.31181658,
+                3.51544515
+              ],
+              [
+                112.31248917,
+                3.51562254
+              ],
+              [
+                112.52147408,
+                3.5785908
+              ],
+              [
+                112.52281386,
+                3.57910186
+              ],
+              [
+                112.85206367,
+                3.73256867
+              ],
+              [
+                112.85465776,
+                3.7343178
+              ],
+              [
+                112.85658437,
+                3.73678292
+              ],
+              [
+                112.85765492,
+                3.73972276
+              ],
+              [
+                112.85776462,
+                3.74284952
+              ],
+              [
+                112.85690272,
+                3.74585715
+              ],
+              [
+                112.8551536,
+                3.74845124
+              ],
+              [
+                112.85268847,
+                3.75037785
+              ],
+              [
+                112.84974864,
+                3.7514484
+              ],
+              [
+                112.84662187,
+                3.75155809
+              ],
+              [
+                112.84361424,
+                3.7506962
+              ],
+              [
+                112.51501594,
+                3.59753306
+              ],
+              [
+                112.30705249,
+                3.53487257
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                108.26055972,
+                6.08912451
+              ],
+              [
+                108.29013305,
+                6.01266273
+              ],
+              [
+                108.29170425,
+                6.00995718
+              ],
+              [
+                108.29403462,
+                6.00786957
+              ],
+              [
+                108.29689603,
+                6.00660426
+              ],
+              [
+                108.3000084,
+                6.00628511
+              ],
+              [
+                108.30306706,
+                6.00694335
+              ],
+              [
+                108.30577262,
+                6.00851455
+              ],
+              [
+                108.30786022,
+                6.01084492
+              ],
+              [
+                108.30912553,
+                6.01370633
+              ],
+              [
+                108.30944469,
+                6.0168187
+              ],
+              [
+                108.30878645,
+                6.01987736
+              ],
+              [
+                108.279563,
+                6.09543449
+              ],
+              [
+                108.25611734,
+                6.22752625
+              ],
+              [
+                108.21679964,
+                6.53816468
+              ],
+              [
+                108.21876335,
+                6.94964057
+              ],
+              [
+                108.24419535,
+                7.07390742
+              ],
+              [
+                108.24433543,
+                7.07703297
+              ],
+              [
+                108.24350281,
+                7.08004883
+              ],
+              [
+                108.24177899,
+                7.0826598
+              ],
+              [
+                108.2393327,
+                7.08461028
+              ],
+              [
+                108.23640341,
+                7.08570936
+              ],
+              [
+                108.23327786,
+                7.08584944
+              ],
+              [
+                108.230262,
+                7.08501682
+              ],
+              [
+                108.22765103,
+                7.083293
+              ],
+              [
+                108.22570055,
+                7.08084671
+              ],
+              [
+                108.22460147,
+                7.07791743
+              ],
+              [
+                108.19897125,
+                6.95268198
+              ],
+              [
+                108.1987683,
+                6.95072469
+              ],
+              [
+                108.19679674,
+                6.53760583
+              ],
+              [
+                108.19687578,
+                6.53630242
+              ],
+              [
+                108.23630689,
+                6.22476797
+              ],
+              [
+                108.23638164,
+                6.22427602
+              ],
+              [
+                108.26004031,
+                6.09098419
+              ],
+              [
+                108.26055972,
+                6.08912451
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                110.12822847,
+                11.36894451
+              ],
+              [
+                110.05553696,
+                11.25335394
+              ],
+              [
+                110.05430621,
+                11.25047749
+              ],
+              [
+                110.05402458,
+                11.2473615
+              ],
+              [
+                110.05471962,
+                11.24431099
+              ],
+              [
+                110.05632331,
+                11.24162456
+              ],
+              [
+                110.05867865,
+                11.23956519
+              ],
+              [
+                110.0615551,
+                11.23833444
+              ],
+              [
+                110.06467109,
+                11.23805281
+              ],
+              [
+                110.0677216,
+                11.23874785
+              ],
+              [
+                110.07040803,
+                11.24035153
+              ],
+              [
+                110.07246741,
+                11.24270688
+              ],
+              [
+                110.14541497,
+                11.35870461
+              ],
+              [
+                110.14588682,
+                11.35954163
+              ],
+              [
+                110.20700505,
+                11.48128846
+              ],
+              [
+                110.20728377,
+                11.48189306
+              ],
+              [
+                110.25854422,
+                11.60358735
+              ],
+              [
+                110.25901765,
+                11.60499559
+              ],
+              [
+                110.30436343,
+                11.7826124
+              ],
+              [
+                110.30456934,
+                11.78364161
+              ],
+              [
+                110.32822801,
+                11.94571326
+              ],
+              [
+                110.32832827,
+                11.94685414
+              ],
+              [
+                110.33424294,
+                12.14159753
+              ],
+              [
+                110.33424553,
+                12.14210167
+              ],
+              [
+                110.33227398,
+                12.24038351
+              ],
+              [
+                110.33172267,
+                12.24346324
+              ],
+              [
+                110.33024665,
+                12.24622187
+              ],
+              [
+                110.3279904,
+                12.24838938
+              ],
+              [
+                110.32517479,
+                12.24975358
+              ],
+              [
+                110.32207543,
+                12.25018094
+              ],
+              [
+                110.3189957,
+                12.24962962
+              ],
+              [
+                110.31623706,
+                12.2481536
+              ],
+              [
+                110.31406956,
+                12.24589736
+              ],
+              [
+                110.31270536,
+                12.24308175
+              ],
+              [
+                110.312278,
+                12.23998238
+              ],
+              [
+                110.3142445,
+                12.14195265
+              ],
+              [
+                110.3083549,
+                11.94803461
+              ],
+              [
+                110.28485499,
+                11.78705054
+              ],
+              [
+                110.23982347,
+                11.61066468
+              ],
+              [
+                110.18898148,
+                11.48996382
+              ],
+              [
+                110.12822847,
+                11.36894451
+              ]
+            ]
+          ],
+          [
+            [
+              [
+                109.82951587,
+                15.22896754
+              ],
+              [
+                109.84522534,
+                15.15316562
+              ],
+              [
+                109.84633168,
+                15.15023907
+              ],
+              [
+                109.84828823,
+                15.14779763
+              ],
+              [
+                109.85090347,
+                15.14608029
+              ],
+              [
+                109.85392139,
+                15.14525516
+              ],
+              [
+                109.85704658,
+                15.145403
+              ],
+              [
+                109.85997314,
+                15.14650935
+              ],
+              [
+                109.86241457,
+                15.1484659
+              ],
+              [
+                109.86413191,
+                15.15108113
+              ],
+              [
+                109.86495704,
+                15.15409906
+              ],
+              [
+                109.8648092,
+                15.15722425
+              ],
+              [
+                109.84903675,
+                15.23333003
+              ],
+              [
+                109.84889209,
+                15.23393326
+              ],
+              [
+                109.78974541,
+                15.45068337
+              ],
+              [
+                109.7892391,
+                15.45210582
+              ],
+              [
+                109.69066131,
+                15.67432448
+              ],
+              [
+                109.6900529,
+                15.67548445
+              ],
+              [
+                109.59147511,
+                15.83677407
+              ],
+              [
+                109.59116145,
+                15.8372556
+              ],
+              [
+                109.53201478,
+                15.92259221
+              ],
+              [
+                109.53166592,
+                15.92306523
+              ],
+              [
+                109.30888011,
+                16.20725797
+              ],
+              [
+                109.30658844,
+                16.20938798
+              ],
+              [
+                109.30375073,
+                16.21070558
+              ],
+              [
+                109.30064474,
+                16.21108179
+              ],
+              [
+                109.29757451,
+                16.21047978
+              ],
+              [
+                109.29484059,
+                16.20895848
+              ],
+              [
+                109.29271057,
+                16.20666681
+              ],
+              [
+                109.29139298,
+                16.2038291
+              ],
+              [
+                109.29101677,
+                16.20072311
+              ],
+              [
+                109.29161878,
+                16.19765288
+              ],
+              [
+                109.29314007,
+                16.19491896
+              ],
+              [
+                109.51574449,
+                15.91095759
+              ],
+              [
+                109.57455994,
+                15.82609887
+              ],
+              [
+                109.67264555,
+                15.66561455
+              ],
+              [
+                109.77065019,
+                15.44468789
+              ],
+              [
+                109.82951587,
+                15.22896754
+              ]
+            ]
+          ]
+        ]
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/index.vue"
new file mode 100644
index 0000000..73c263c
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/index.vue"
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Tabs } from 'ant-design-vue';
+
+import Browser from './pages/browser.vue';
+import Device from './pages/device.vue';
+import Isp from './pages/isp.vue';
+import LoginLine from './pages/loginLine.vue';
+import VisitMap from './pages/map.vue';
+
+const TabPane = Tabs.TabPane;
+
+const activeKey = ref<number>(1);
+</script>
+<template>
+  <div class="pt-[16px]">
+    <Tabs v-model:activeKey="activeKey" class="h-full" tab-position="left">
+      <TabPane :key="1" tab="璁块棶閲忔暟鎹�"> <VisitMap /> </TabPane>
+      <TabPane :key="2" tab="浣跨敤璁惧"><Device /></TabPane>
+      <TabPane :key="3" tab="浣跨敤娴忚鍣�"><Browser /></TabPane>
+      <TabPane :key="4" tab="鐧诲綍閲�"><LoginLine /></TabPane>
+      <TabPane :key="5" tab="杩愯惀鍟嗗崰姣�"><Isp /></TabPane>
+    </Tabs>
+  </div>
+</template>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/browser.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/browser.vue"
new file mode 100644
index 0000000..f4ccdd8
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/browser.vue"
@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts';
+
+// import * as echarts from 'echarts';
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+import { browserInfoList } from '../api';
+
+defineOptions({ name: 'Browser' });
+
+const browserRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(browserRef);
+
+onMounted(async () => {
+  const data = await browserInfoList();
+  const options: EChartsOption = {
+    legend: {
+      left: 'left',
+      orient: 'vertical',
+    },
+    series: [
+      {
+        data,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowColor: 'rgba(0, 0, 0, 0.5)',
+            shadowOffsetX: 0,
+          },
+        },
+        // 鐧惧垎姣�
+        label: {
+          formatter: '{b}: {c} - ({d}%)', // 鑷畾涔夋樉绀烘牸寮�(b:name, c:value, d:鐧惧垎姣�)
+          show: true,
+        },
+        radius: '50%',
+        type: 'pie',
+      },
+    ],
+    title: {
+      left: 'center',
+      text: '浣跨敤娴忚鍣ㄥ崰姣�',
+    },
+    tooltip: {
+      trigger: 'item',
+    },
+  };
+  renderEcharts(options);
+});
+</script>
+
+<template>
+  <EchartsUI ref="browserRef" height="720px" width="100%" />
+</template>
+
+<style scoped></style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/device.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/device.vue"
new file mode 100644
index 0000000..3132399
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/device.vue"
@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts';
+
+// import * as echarts from 'echarts';
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+import { deviceInfoList } from '../api';
+
+defineOptions({ name: 'Device' });
+
+const deviceRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(deviceRef);
+
+onMounted(async () => {
+  const data = await deviceInfoList();
+  const options: EChartsOption = {
+    legend: {
+      left: 'left',
+      orient: 'vertical',
+    },
+    series: [
+      {
+        data,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowColor: 'rgba(0, 0, 0, 0.5)',
+            shadowOffsetX: 0,
+          },
+        },
+        // 鐧惧垎姣�
+        label: {
+          formatter: '{b}: {c} - ({d}%)', // 鑷畾涔夋樉绀烘牸寮�(b:name, c:value, d:鐧惧垎姣�)
+          show: true,
+        },
+        radius: '50%',
+        type: 'pie',
+      },
+    ],
+    title: {
+      left: 'center',
+      text: '浣跨敤璁惧鍗犳瘮',
+    },
+    tooltip: {
+      trigger: 'item',
+    },
+  };
+  renderEcharts(options);
+});
+</script>
+
+<template>
+  <EchartsUI ref="deviceRef" height="720px" width="100%" />
+</template>
+
+<style scoped></style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/isp.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/isp.vue"
new file mode 100644
index 0000000..bf61cea
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/isp.vue"
@@ -0,0 +1,62 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts';
+
+// import * as echarts from 'echarts';
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+import { ispInfoList } from '../api';
+
+defineOptions({ name: 'Isp' });
+
+const ispRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(ispRef);
+
+onMounted(async () => {
+  const data = await ispInfoList();
+  const options: EChartsOption = {
+    legend: {
+      left: 'left',
+      orient: 'vertical',
+    },
+    series: [
+      {
+        data,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowColor: 'rgba(0, 0, 0, 0.5)',
+            shadowOffsetX: 0,
+          },
+        },
+        // 鐧惧垎姣�
+        label: {
+          formatter: '{b}: {c} - ({d}%)', // 鑷畾涔夋樉绀烘牸寮�(b:name, c:value, d:鐧惧垎姣�)
+          show: true,
+        },
+        radius: '50%',
+        type: 'pie',
+      },
+    ],
+    title: {
+      left: 'center',
+      text: '缃戠粶杩愯惀鍟嗗崰姣�',
+    },
+    tooltip: {
+      trigger: 'item',
+    },
+  };
+  renderEcharts(options);
+});
+</script>
+
+<template>
+  <EchartsUI ref="ispRef" height="720px" width="100%" />
+</template>
+
+<style scoped></style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/loginLine.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/loginLine.vue"
new file mode 100644
index 0000000..012d5f6
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/loginLine.vue"
@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts';
+
+// import * as echarts from 'echarts';
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+import { loginLine } from '../api';
+
+defineOptions({ name: 'LoginLine' });
+
+const loginLineRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(loginLineRef);
+
+onMounted(async () => {
+  const data = await loginLine();
+  console.log(data);
+  const options: EChartsOption = {
+    legend: {},
+    series: [
+      {
+        data: data.success,
+        itemStyle: {
+          color: '#3399CC',
+        },
+        lineStyle: {
+          color: '#3399CC',
+        },
+        name: '鐧诲綍鎴愬姛',
+        type: 'line',
+      },
+      {
+        data: data.fail,
+        itemStyle: {
+          color: '#CC6633',
+        },
+        lineStyle: {
+          color: '#CC6633',
+        },
+        name: '鐧诲綍澶辫触',
+        type: 'line',
+      },
+    ],
+    title: {
+      text: '杩戜竴鏈堢櫥褰曢噺缁熻',
+    },
+    toolbox: {
+      feature: {
+        dataView: { readOnly: true },
+        dataZoom: {
+          yAxisIndex: 'none',
+        },
+        magicType: { type: ['line', 'bar'] },
+        saveAsImage: {},
+      },
+      show: true,
+    },
+    tooltip: {
+      trigger: 'axis',
+    },
+    xAxis: {
+      boundaryGap: false,
+      data: data.date,
+      type: 'category',
+    },
+    yAxis: {
+      type: 'value',
+    },
+  };
+  renderEcharts(options);
+});
+</script>
+
+<template>
+  <EchartsUI ref="loginLineRef" height="720px" width="100%" />
+</template>
+
+<style scoped></style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/map.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/map.vue"
new file mode 100644
index 0000000..d616c42
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/visit/pages/map.vue"
@@ -0,0 +1,111 @@
+<script setup lang="ts">
+import type { EChartsOption } from 'echarts';
+
+// import * as echarts from 'echarts';
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+import * as echarts from 'echarts/core';
+
+import { type Temp, visitList } from '../api';
+import * as chinaMap from '../china.json';
+
+defineOptions({ name: 'VisitMap' });
+
+const mapRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(mapRef);
+
+function transformData(data: Temp[]) {
+  const nameList: string[] = chinaMap.features.map(
+    (item) => item.properties.name,
+  );
+  // eslint-disable-next-line unicorn/prefer-set-has
+  const dataNameList: string[] = data.map((item) => item.name);
+  // 宸泦
+  const diff = nameList.filter(
+    (item) => !dataNameList.includes(item) && item.trim() !== '',
+  );
+  diff.forEach((name) => {
+    data.push({
+      name,
+      value: 0,
+    });
+  });
+}
+
+onMounted(async () => {
+  echarts.registerMap('china', chinaMap as any);
+  const data = await visitList();
+  transformData(data);
+  const max = Math.max.apply(
+    null,
+    data.map((item) => item.value),
+  );
+  const options: EChartsOption = {
+    series: [
+      {
+        data,
+        emphasis: {
+          label: {
+            show: true,
+          },
+        },
+        label: {
+          // formatter: '{b}\n{c}',
+          formatter: '{c}',
+          position: 'inside',
+          show: true,
+        },
+        map: 'china',
+        roam: true,
+        // 鐢变簬缂╂斁  杩欓噷鍔犱笂鍋忕Щ
+        top: 200,
+        type: 'map',
+        zoom: 1.5,
+      },
+    ],
+    title: {
+      left: 'right',
+      text: '鐢ㄦ埛璁块棶閲忔暟鎹�',
+    },
+    toolbox: {
+      feature: {
+        dataView: { readOnly: true },
+        saveAsImage: {},
+      },
+      // orient: 'vertical',
+      left: 'left',
+      show: true,
+      top: 'top',
+    },
+    tooltip: {
+      formatter: '{b}<br/>{c}',
+      showDelay: 0,
+      transitionDuration: 0.2,
+      trigger: 'item',
+    },
+    visualMap: {
+      calculable: true,
+      inRange: {
+        color: ['#ffffff', '#00FF66', '#00CCFF', '#CC6600'],
+      },
+      left: 'left',
+      max,
+      min: 0,
+      text: ['鏈�楂�', '鏈�浣�'],
+    },
+  };
+  renderEcharts(options);
+});
+</script>
+
+<template>
+  <EchartsUI ref="mapRef" height="720px" width="100%" />
+</template>
+
+<style scoped></style>
diff --git "a/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/wechat/index.vue" "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/wechat/index.vue"
new file mode 100644
index 0000000..7267512
--- /dev/null
+++ "b/eims-ui/apps/web-antd/src/views/\346\274\224\347\244\272\344\275\277\347\224\250\350\207\252\350\241\214\345\210\240\351\231\244/wechat/index.vue"
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { onMounted, ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Alert, Image } from 'ant-design-vue';
+
+import { requestClient } from '#/api/request';
+
+const currentImage = ref('');
+onMounted(async () => {
+  const resp = await requestClient.get<string>('/currentGroupImgBase64');
+  console.log(resp);
+  currentImage.value = resp;
+});
+</script>
+
+<template>
+  <Page>
+    <div class="flex w-[360px] flex-col gap-2">
+      <Alert :show-icon="true" message="浜烘暟宸叉弧锛岄渶瑕佹墜鍔ㄦ媺浜�" type="info" />
+      <Alert
+        :show-icon="true"
+        message="杩涚兢璁ㄨ/鑾峰彇寮�鍙戣繘搴� 娣诲姞澶囨敞: vben5"
+        type="info"
+      />
+      <div>
+        <Image
+          :preview="false"
+          :src="`data:image/png;base64,${currentImage}`"
+          :width="240"
+          fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="
+        />
+      </div>
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/tailwind.config.mjs b/eims-ui/apps/web-antd/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/apps/web-antd/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/apps/web-antd/tsconfig.json b/eims-ui/apps/web-antd/tsconfig.json
new file mode 100644
index 0000000..9d43c92
--- /dev/null
+++ b/eims-ui/apps/web-antd/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web-app.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["./src/*"]
+    }
+  },
+  "references": [{ "path": "./tsconfig.node.json" }],
+  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*.d.ts"]
+}
diff --git a/eims-ui/apps/web-antd/tsconfig.node.json b/eims-ui/apps/web-antd/tsconfig.node.json
new file mode 100644
index 0000000..c2f0d86
--- /dev/null
+++ b/eims-ui/apps/web-antd/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "compilerOptions": {
+    "composite": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "noEmit": false
+  },
+  "include": ["vite.config.mts"]
+}
diff --git a/eims-ui/apps/web-antd/types/directive.d.ts b/eims-ui/apps/web-antd/types/directive.d.ts
new file mode 100644
index 0000000..f9ea833
--- /dev/null
+++ b/eims-ui/apps/web-antd/types/directive.d.ts
@@ -0,0 +1,12 @@
+import type { Directive } from 'vue';
+
+declare module 'vue' {
+  export interface ComponentCustomProperties {
+    /**
+     * 鍒ゆ柇鏉冮檺: v-access:code=""
+     * 鍒ゆ柇瑙掕壊  v-access:role=""
+     * 闇�瑕乂ueOfficial鎻掍欢鐗堟湰 >= 2.1.8
+     */
+    vAccess: Directive<Element, string | string[], string, 'code' | 'role'>;
+  }
+}
diff --git a/eims-ui/apps/web-antd/types/global-components.d.ts b/eims-ui/apps/web-antd/types/global-components.d.ts
new file mode 100644
index 0000000..7c94560
--- /dev/null
+++ b/eims-ui/apps/web-antd/types/global-components.d.ts
@@ -0,0 +1,9 @@
+export {};
+
+/* prettier-ignore */
+declare module 'vue' {
+  export interface GlobalComponents {
+    AButton: typeof import('ant-design-vue/es/button')['default'];
+    GhostButton: typeof import('#/components/global/button')['GhostButton']
+  }
+}
diff --git a/eims-ui/apps/web-antd/vite.config.mts b/eims-ui/apps/web-antd/vite.config.mts
new file mode 100644
index 0000000..ed01d81
--- /dev/null
+++ b/eims-ui/apps/web-antd/vite.config.mts
@@ -0,0 +1,46 @@
+import { defineConfig } from '@vben/vite-config';
+
+// 鑷鍙栨秷娉ㄩ噴鏉ュ惎鐢ㄦ寜闇�瀵煎叆鍔熻兘
+// import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
+// import Components from 'unplugin-vue-components/vite';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    vite: {
+      optimizeDeps: {
+        include: [
+          'ant-design-vue/es/locale/zh_CN',
+          'ant-design-vue/es/locale/en_US',
+        ],
+      },
+      plugins: [
+        // Components({
+        //   dirs: [], // 榛樿浼氬鍏rc/components鐩綍涓嬫墍鏈夌粍浠� 涓嶉渶瑕�
+        //   dts: './types/components.d.ts', // 杈撳嚭绫诲瀷鏂囦欢
+        //   resolvers: [
+        //     AntDesignVueResolver({
+        //       // 闇�瑕佹帓闄utton缁勪欢 鍏ㄥ眬宸茬粡榛樿瀵煎叆浜�
+        //       exclude: ['Button'],
+        //       importStyle: false, // css in js
+        //     }),
+        //   ],
+        // }),
+      ],
+      server: {
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock浠g悊鐩爣鍦板潃
+            target: 'http://localhost:8080',
+            ws: true,
+          },
+        },
+        warmup: {
+          clientFiles: ['./index.html', './src/{views,components}/*'],
+        },
+      },
+    },
+  };
+});
diff --git a/eims-ui/apps/web-ele/.env b/eims-ui/apps/web-ele/.env
new file mode 100644
index 0000000..87cb3df
--- /dev/null
+++ b/eims-ui/apps/web-ele/.env
@@ -0,0 +1,5 @@
+# 搴旂敤鏍囬
+VITE_APP_TITLE=Vben Admin Ele
+
+# 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
+VITE_APP_NAMESPACE=vben-web-ele
diff --git a/eims-ui/apps/web-ele/.env.analyze b/eims-ui/apps/web-ele/.env.analyze
new file mode 100644
index 0000000..ffafa8d
--- /dev/null
+++ b/eims-ui/apps/web-ele/.env.analyze
@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true
diff --git a/eims-ui/apps/web-ele/.env.development b/eims-ui/apps/web-ele/.env.development
new file mode 100644
index 0000000..8bcb432
--- /dev/null
+++ b/eims-ui/apps/web-ele/.env.development
@@ -0,0 +1,16 @@
+# 绔彛鍙�
+VITE_PORT=5777
+
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=/api
+
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=true
+
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=false
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
diff --git a/eims-ui/apps/web-ele/.env.production b/eims-ui/apps/web-ele/.env.production
new file mode 100644
index 0000000..5375847
--- /dev/null
+++ b/eims-ui/apps/web-ele/.env.production
@@ -0,0 +1,19 @@
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+
+# 鏄惁寮�鍚帇缂╋紝鍙互璁剧疆涓� none, brotli, gzip
+VITE_COMPRESS=none
+
+# 鏄惁寮�鍚� PWA
+VITE_PWA=false
+
+# vue-router 鐨勬ā寮�
+VITE_ROUTER_HISTORY=hash
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鎵撳寘鍚庢槸鍚︾敓鎴恉ist.zip
+VITE_ARCHIVER=true
diff --git a/eims-ui/apps/web-ele/index.html b/eims-ui/apps/web-ele/index.html
new file mode 100644
index 0000000..2b59b8d
--- /dev/null
+++ b/eims-ui/apps/web-ele/index.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang="zh">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta name="description" content="A Modern Back-end Management System" />
+    <meta name="keywords" content="Vben Admin Vue3 Vite" />
+    <meta name="author" content="Vben" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <!-- 鐢� vite 娉ㄥ叆 VITE_APP_TITLE 鍙橀噺锛屽湪 .env 鏂囦欢鍐呴厤缃� -->
+    <title><%= VITE_APP_TITLE %></title>
+    <link rel="icon" href="/favicon.ico" />
+    <script>
+      // 鐢熶骇鐜涓嬫敞鍏ョ櫨搴︾粺璁�
+      if (window._VBEN_ADMIN_PRO_APP_CONF_) {
+        var _hmt = _hmt || [];
+        (function () {
+          var hm = document.createElement('script');
+          hm.src =
+            'https://hm.baidu.com/hm.js?97352b16ed2df8c3860cf5a1a65fb4dd';
+          var s = document.getElementsByTagName('script')[0];
+          s.parentNode.insertBefore(hm, s);
+        })();
+      }
+    </script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>
diff --git a/eims-ui/apps/web-ele/package.json b/eims-ui/apps/web-ele/package.json
new file mode 100644
index 0000000..9828c52
--- /dev/null
+++ b/eims-ui/apps/web-ele/package.json
@@ -0,0 +1,53 @@
+{
+  "name": "@vben/web-ele",
+  "version": "5.5.0",
+  "homepage": "https://vben.pro",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "apps/web-ele"
+  },
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build --mode production",
+    "build:analyze": "pnpm vite build --mode analyze",
+    "dev": "pnpm vite --mode development",
+    "preview": "vite preview",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck"
+  },
+  "imports": {
+    "#/*": "./src/*"
+  },
+  "dependencies": {
+    "@vben/access": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/layouts": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/request": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "dayjs": "catalog:",
+    "element-plus": "catalog:",
+    "pinia": "catalog:",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  },
+  "devDependencies": {
+    "unplugin-element-plus": "catalog:"
+  }
+}
diff --git a/eims-ui/apps/web-ele/postcss.config.mjs b/eims-ui/apps/web-ele/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/apps/web-ele/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/apps/web-ele/public/favicon.ico b/eims-ui/apps/web-ele/public/favicon.ico
new file mode 100644
index 0000000..fcf9818
--- /dev/null
+++ b/eims-ui/apps/web-ele/public/favicon.ico
Binary files differ
diff --git a/eims-ui/apps/web-ele/src/adapter/component/index.ts b/eims-ui/apps/web-ele/src/adapter/component/index.ts
new file mode 100644
index 0000000..818c8c4
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/adapter/component/index.ts
@@ -0,0 +1,234 @@
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  ElButton,
+  ElCheckbox,
+  ElCheckboxButton,
+  ElCheckboxGroup,
+  ElDatePicker,
+  ElDivider,
+  ElInput,
+  ElInputNumber,
+  ElNotification,
+  ElRadio,
+  ElRadioButton,
+  ElRadioGroup,
+  ElSelectV2,
+  ElSpace,
+  ElSwitch,
+  ElTimePicker,
+  ElTreeSelect,
+  ElUpload,
+} from 'element-plus';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'ApiSelect'
+  | 'ApiTreeSelect'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'Divider'
+  | 'IconPicker'
+  | 'Input'
+  | 'InputNumber'
+  | 'RadioGroup'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+    ApiSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: ElSelectV2,
+          loadingSlot: 'loading',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    ApiTreeSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: ElTreeSelect,
+          props: { label: 'label', children: 'children' },
+          nodeKey: 'value',
+          loadingSlot: 'loading',
+          optionsPropName: 'data',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    Checkbox: ElCheckbox,
+    CheckboxGroup: (props, { attrs, slots }) => {
+      let defaultSlot;
+      if (Reflect.has(slots, 'default')) {
+        defaultSlot = slots.default;
+      } else {
+        const { options, isButton } = attrs;
+        if (Array.isArray(options)) {
+          defaultSlot = () =>
+            options.map((option) =>
+              h(isButton ? ElCheckboxButton : ElCheckbox, option),
+            );
+        }
+      }
+      return h(
+        ElCheckboxGroup,
+        { ...props, ...attrs },
+        { ...slots, default: defaultSlot },
+      );
+    },
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(ElButton, { ...props, attrs, type: 'info' }, slots);
+    },
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Divider: ElDivider,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        {
+          iconSlot: 'append',
+          modelValueProp: 'model-value',
+          inputComponent: ElInput,
+          ...props,
+          ...attrs,
+        },
+        slots,
+      );
+    },
+    Input: withDefaultPlaceholder(ElInput, 'input'),
+    InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
+    RadioGroup: (props, { attrs, slots }) => {
+      let defaultSlot;
+      if (Reflect.has(slots, 'default')) {
+        defaultSlot = slots.default;
+      } else {
+        const { options } = attrs;
+        if (Array.isArray(options)) {
+          defaultSlot = () =>
+            options.map((option) =>
+              h(attrs.isButton ? ElRadioButton : ElRadio, option),
+            );
+        }
+      }
+      return h(
+        ElRadioGroup,
+        { ...props, ...attrs },
+        { ...slots, default: defaultSlot },
+      );
+    },
+    Select: (props, { attrs, slots }) => {
+      return h(ElSelectV2, { ...props, attrs }, slots);
+    },
+    Space: ElSpace,
+    Switch: ElSwitch,
+    TimePicker: (props, { attrs, slots }) => {
+      const { name, id, isRange } = props;
+      const extraProps: Recordable<any> = {};
+      if (isRange) {
+        if (name && !Array.isArray(name)) {
+          extraProps.name = [name, `${name}_end`];
+        }
+        if (id && !Array.isArray(id)) {
+          extraProps.id = [id, `${id}_end`];
+        }
+      }
+      return h(
+        ElTimePicker,
+        {
+          ...props,
+          ...attrs,
+          ...extraProps,
+        },
+        slots,
+      );
+    },
+    DatePicker: (props, { attrs, slots }) => {
+      const { name, id, type } = props;
+      const extraProps: Recordable<any> = {};
+      if (type && type.includes('range')) {
+        if (name && !Array.isArray(name)) {
+          extraProps.name = [name, `${name}_end`];
+        }
+        if (id && !Array.isArray(id)) {
+          extraProps.id = [id, `${id}_end`];
+        }
+      }
+      return h(
+        ElDatePicker,
+        {
+          ...props,
+          ...attrs,
+          ...extraProps,
+        },
+        slots,
+      );
+    },
+    TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
+    Upload: ElUpload,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      ElNotification({
+        title,
+        message: content,
+        position: 'bottom-right',
+        duration: 0,
+        type: 'success',
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
diff --git a/eims-ui/apps/web-ele/src/adapter/form.ts b/eims-ui/apps/web-ele/src/adapter/form.ts
new file mode 100644
index 0000000..13ae9c4
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/adapter/form.ts
@@ -0,0 +1,39 @@
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+setupVbenForm<ComponentType>({
+  config: {
+    modelPropNameMap: {
+      Upload: 'fileList',
+      CheckboxGroup: 'model-value',
+    },
+  },
+  defineRules: {
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    selectRequired: (value, _params, ctx) => {
+      if (value === undefined || value === null) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
diff --git a/eims-ui/apps/web-ele/src/adapter/vxe-table.ts b/eims-ui/apps/web-ele/src/adapter/vxe-table.ts
new file mode 100644
index 0000000..44b31ea
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/adapter/vxe-table.ts
@@ -0,0 +1,68 @@
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { ElButton, ElImage } from 'element-plus';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+  configVxeTable: (vxeUI) => {
+    vxeUI.setConfig({
+      grid: {
+        align: 'center',
+        border: false,
+        columnConfig: {
+          resizable: true,
+        },
+        minHeight: 180,
+        formConfig: {
+          // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+          enabled: false,
+        },
+        proxyConfig: {
+          autoLoad: true,
+          response: {
+            result: 'items',
+            total: 'total',
+            list: 'items',
+          },
+          showActiveMsg: true,
+          showResponseMsg: false,
+        },
+        round: true,
+        showOverflow: true,
+        size: 'small',
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+    vxeUI.renderer.add('CellImage', {
+      renderTableDefault(_renderOpts, params) {
+        const { column, row } = params;
+        const src = row[column.field];
+        return h(ElImage, { src, previewSrcList: [src] });
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+    vxeUI.renderer.add('CellLink', {
+      renderTableDefault(renderOpts) {
+        const { props } = renderOpts;
+        return h(
+          ElButton,
+          { size: 'small', link: true },
+          { default: () => props?.text },
+        );
+      },
+    });
+
+    // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+    // vxeUI.formats.add
+  },
+  useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
diff --git a/eims-ui/apps/web-ele/src/api/core/auth.ts b/eims-ui/apps/web-ele/src/api/core/auth.ts
new file mode 100644
index 0000000..71d9f99
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/core/auth.ts
@@ -0,0 +1,51 @@
+import { baseRequestClient, requestClient } from '#/api/request';
+
+export namespace AuthApi {
+  /** 鐧诲綍鎺ュ彛鍙傛暟 */
+  export interface LoginParams {
+    password?: string;
+    username?: string;
+  }
+
+  /** 鐧诲綍鎺ュ彛杩斿洖鍊� */
+  export interface LoginResult {
+    accessToken: string;
+  }
+
+  export interface RefreshTokenResult {
+    data: string;
+    status: number;
+  }
+}
+
+/**
+ * 鐧诲綍
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
+}
+
+/**
+ * 鍒锋柊accessToken
+ */
+export async function refreshTokenApi() {
+  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 閫�鍑虹櫥褰�
+ */
+export async function logoutApi() {
+  return baseRequestClient.post('/auth/logout', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 鑾峰彇鐢ㄦ埛鏉冮檺鐮�
+ */
+export async function getAccessCodesApi() {
+  return requestClient.get<string[]>('/auth/codes');
+}
diff --git a/eims-ui/apps/web-ele/src/api/core/index.ts b/eims-ui/apps/web-ele/src/api/core/index.ts
new file mode 100644
index 0000000..28a5aef
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/core/index.ts
@@ -0,0 +1,3 @@
+export * from './auth';
+export * from './menu';
+export * from './user';
diff --git a/eims-ui/apps/web-ele/src/api/core/menu.ts b/eims-ui/apps/web-ele/src/api/core/menu.ts
new file mode 100644
index 0000000..9ef60b1
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/core/menu.ts
@@ -0,0 +1,10 @@
+import type { RouteRecordStringComponent } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛鎵�鏈夎彍鍗�
+ */
+export async function getAllMenusApi() {
+  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
+}
diff --git a/eims-ui/apps/web-ele/src/api/core/user.ts b/eims-ui/apps/web-ele/src/api/core/user.ts
new file mode 100644
index 0000000..7e28ea8
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/core/user.ts
@@ -0,0 +1,10 @@
+import type { UserInfo } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛淇℃伅
+ */
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
diff --git a/eims-ui/apps/web-ele/src/api/index.ts b/eims-ui/apps/web-ele/src/api/index.ts
new file mode 100644
index 0000000..4b0e041
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/index.ts
@@ -0,0 +1 @@
+export * from './core';
diff --git a/eims-ui/apps/web-ele/src/api/request.ts b/eims-ui/apps/web-ele/src/api/request.ts
new file mode 100644
index 0000000..a9514c8
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/api/request.ts
@@ -0,0 +1,113 @@
+/**
+ * 璇ユ枃浠跺彲鑷鏍规嵁涓氬姟閫昏緫杩涜璋冩暣
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { ElMessage } from 'element-plus';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    baseURL,
+  });
+
+  /**
+   * 閲嶆柊璁よ瘉閫昏緫
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (
+      preferences.app.loginExpiredMode === 'modal' &&
+      accessStore.isAccessChecked
+    ) {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * 鍒锋柊token閫昏緫
+   */
+  async function doRefreshToken() {
+    const accessStore = useAccessStore();
+    const resp = await refreshTokenApi();
+    const newToken = resp.data;
+    accessStore.setAccessToken(newToken);
+    return newToken;
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  // 璇锋眰澶村鐞�
+  client.addRequestInterceptor({
+    fulfilled: async (config) => {
+      const accessStore = useAccessStore();
+
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      config.headers['Accept-Language'] = preferences.app.locale;
+      return config;
+    },
+  });
+
+  // response鏁版嵁瑙f瀯
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const { data: responseData, status } = response;
+
+      const { code, data } = responseData;
+      if (status >= 200 && status < 400 && code === 0) {
+        return data;
+      }
+      throw Object.assign({}, response, { response });
+    },
+  });
+
+  // token杩囨湡鐨勫鐞�
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  // 閫氱敤鐨勯敊璇鐞�,濡傛灉娌℃湁杩涘叆涓婇潰鐨勯敊璇鐞嗛�昏緫锛屽氨浼氳繘鍏ヨ繖閲�
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string, error) => {
+      // 杩欓噷鍙互鏍规嵁涓氬姟杩涜瀹氬埗,浣犲彲浠ユ嬁鍒� error 鍐呯殑淇℃伅杩涜瀹氬埗鍖栧鐞嗭紝鏍规嵁涓嶅悓鐨� code 鍋氫笉鍚岀殑鎻愮ず锛岃�屼笉鏄洿鎺ヤ娇鐢� message.error 鎻愮ず msg
+      // 褰撳墠mock鎺ュ彛杩斿洖鐨勯敊璇瓧娈垫槸 error 鎴栬�� message
+      const responseData = error?.response?.data ?? {};
+      const errorMessage = responseData?.error ?? responseData?.message ?? '';
+      // 濡傛灉娌℃湁閿欒淇℃伅锛屽垯浼氭牴鎹姸鎬佺爜杩涜鎻愮ず
+      ElMessage.error(errorMessage || msg);
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
diff --git a/eims-ui/apps/web-ele/src/app.vue b/eims-ui/apps/web-ele/src/app.vue
new file mode 100644
index 0000000..1217658
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/app.vue
@@ -0,0 +1,17 @@
+<script lang="ts" setup>
+import { useElementPlusDesignTokens } from '@vben/hooks';
+
+import { ElConfigProvider } from 'element-plus';
+
+import { elementLocale } from '#/locales';
+
+defineOptions({ name: 'App' });
+
+useElementPlusDesignTokens();
+</script>
+
+<template>
+  <ElConfigProvider :locale="elementLocale">
+    <RouterView />
+  </ElConfigProvider>
+</template>
diff --git a/eims-ui/apps/web-ele/src/bootstrap.ts b/eims-ui/apps/web-ele/src/bootstrap.ts
new file mode 100644
index 0000000..ad1dce0
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/bootstrap.ts
@@ -0,0 +1,51 @@
+import { createApp, watchEffect } from 'vue';
+
+import { registerAccessDirective } from '@vben/access';
+import { preferences } from '@vben/preferences';
+import { initStores } from '@vben/stores';
+import '@vben/styles';
+import '@vben/styles/ele';
+
+import { useTitle } from '@vueuse/core';
+import { ElLoading } from 'element-plus';
+
+import { $t, setupI18n } from '#/locales';
+
+import { initComponentAdapter } from './adapter/component';
+import App from './app.vue';
+import { router } from './router';
+
+async function bootstrap(namespace: string) {
+  // 鍒濆鍖栫粍浠堕�傞厤鍣�
+  await initComponentAdapter();
+  const app = createApp(App);
+
+  // 娉ㄥ唽Element Plus鎻愪緵鐨剉-loading鎸囦护
+  app.directive('loading', ElLoading.directive);
+
+  // 鍥介檯鍖� i18n 閰嶇疆
+  await setupI18n(app);
+
+  // 閰嶇疆 pinia-tore
+  await initStores(app, { namespace });
+
+  // 瀹夎鏉冮檺鎸囦护
+  registerAccessDirective(app);
+
+  // 閰嶇疆璺敱鍙婅矾鐢卞畧鍗�
+  app.use(router);
+
+  // 鍔ㄦ�佹洿鏂版爣棰�
+  watchEffect(() => {
+    if (preferences.app.dynamicTitle) {
+      const routeTitle = router.currentRoute.value.meta?.title;
+      const pageTitle =
+        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
+      useTitle(pageTitle);
+    }
+  });
+
+  app.mount('#app');
+}
+
+export { bootstrap };
diff --git a/eims-ui/apps/web-ele/src/layouts/auth.vue b/eims-ui/apps/web-ele/src/layouts/auth.vue
new file mode 100644
index 0000000..18d415b
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/layouts/auth.vue
@@ -0,0 +1,23 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { AuthPageLayout } from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+
+import { $t } from '#/locales';
+
+const appName = computed(() => preferences.app.name);
+const logo = computed(() => preferences.logo.source);
+</script>
+
+<template>
+  <AuthPageLayout
+    :app-name="appName"
+    :logo="logo"
+    :page-description="$t('authentication.pageDesc')"
+    :page-title="$t('authentication.pageTitle')"
+  >
+    <!-- 鑷畾涔夊伐鍏锋爮 -->
+    <!-- <template #toolbar></template> -->
+  </AuthPageLayout>
+</template>
diff --git a/eims-ui/apps/web-ele/src/layouts/basic.vue b/eims-ui/apps/web-ele/src/layouts/basic.vue
new file mode 100644
index 0000000..5141295
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/layouts/basic.vue
@@ -0,0 +1,157 @@
+<script lang="ts" setup>
+import type { NotificationItem } from '@vben/layouts';
+
+import { computed, ref, watch } from 'vue';
+
+import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
+import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
+import { useWatermark } from '@vben/hooks';
+import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
+import {
+  BasicLayout,
+  LockScreen,
+  Notification,
+  UserDropdown,
+} from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import { $t } from '#/locales';
+import { useAuthStore } from '#/store';
+import LoginForm from '#/views/_core/authentication/login.vue';
+
+const notifications = ref<NotificationItem[]>([
+  {
+    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
+    date: '3灏忔椂鍓�',
+    isRead: true,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏀跺埌浜� 14 浠芥柊鍛ㄦ姤',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '鍒氬垰',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏈卞亸鍙� 鍥炲浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '2024-01-01',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏇蹭附涓� 璇勮浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1澶╁墠',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '浠e姙鎻愰啋',
+  },
+]);
+
+const userStore = useUserStore();
+const authStore = useAuthStore();
+const accessStore = useAccessStore();
+const { destroyWatermark, updateWatermark } = useWatermark();
+const showDot = computed(() =>
+  notifications.value.some((item) => !item.isRead),
+);
+
+const menus = computed(() => [
+  {
+    handler: () => {
+      openWindow(VBEN_DOC_URL, {
+        target: '_blank',
+      });
+    },
+    icon: BookOpenText,
+    text: $t('ui.widgets.document'),
+  },
+  {
+    handler: () => {
+      openWindow(VBEN_GITHUB_URL, {
+        target: '_blank',
+      });
+    },
+    icon: MdiGithub,
+    text: 'GitHub',
+  },
+  {
+    handler: () => {
+      openWindow(`${VBEN_GITHUB_URL}/issues`, {
+        target: '_blank',
+      });
+    },
+    icon: CircleHelp,
+    text: $t('ui.widgets.qa'),
+  },
+]);
+
+const avatar = computed(() => {
+  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
+});
+
+async function handleLogout() {
+  await authStore.logout(false);
+}
+
+function handleNoticeClear() {
+  notifications.value = [];
+}
+
+function handleMakeAll() {
+  notifications.value.forEach((item) => (item.isRead = true));
+}
+watch(
+  () => preferences.app.watermark,
+  async (enable) => {
+    if (enable) {
+      await updateWatermark({
+        content: `${userStore.userInfo?.username}`,
+      });
+    } else {
+      destroyWatermark();
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+</script>
+
+<template>
+  <BasicLayout @clear-preferences-and-logout="handleLogout">
+    <template #user-dropdown>
+      <UserDropdown
+        :avatar
+        :menus
+        :text="userStore.userInfo?.realName"
+        description="ann.vben@gmail.com"
+        tag-text="Pro"
+        @logout="handleLogout"
+      />
+    </template>
+    <template #notification>
+      <Notification
+        :dot="showDot"
+        :notifications="notifications"
+        @clear="handleNoticeClear"
+        @make-all="handleMakeAll"
+      />
+    </template>
+    <template #extra>
+      <AuthenticationLoginExpiredModal
+        v-model:open="accessStore.loginExpired"
+        :avatar
+      >
+        <LoginForm />
+      </AuthenticationLoginExpiredModal>
+    </template>
+    <template #lock-screen>
+      <LockScreen :avatar @to-login="handleLogout" />
+    </template>
+  </BasicLayout>
+</template>
diff --git a/eims-ui/apps/web-ele/src/layouts/index.ts b/eims-ui/apps/web-ele/src/layouts/index.ts
new file mode 100644
index 0000000..a432078
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/layouts/index.ts
@@ -0,0 +1,6 @@
+const BasicLayout = () => import('./basic.vue');
+const AuthPageLayout = () => import('./auth.vue');
+
+const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
+
+export { AuthPageLayout, BasicLayout, IFrameView };
diff --git a/eims-ui/apps/web-ele/src/locales/README.md b/eims-ui/apps/web-ele/src/locales/README.md
new file mode 100644
index 0000000..7b45103
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/README.md
@@ -0,0 +1,3 @@
+# locale
+
+姣忎釜app浣跨敤鐨勫浗闄呭寲鍙兘涓嶅悓锛岃繖閲岀敤浜庢墿灞曞浗闄呭寲鐨勫姛鑳斤紝渚嬪鎵╁睍 dayjs銆乤ntd缁勪欢搴撶殑澶氳瑷�鍒囨崲锛屼互鍙奱pp鏈韩鐨勫浗闄呭寲鏂囦欢銆�
diff --git a/eims-ui/apps/web-ele/src/locales/index.ts b/eims-ui/apps/web-ele/src/locales/index.ts
new file mode 100644
index 0000000..1f3e22c
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/index.ts
@@ -0,0 +1,100 @@
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+import type { Language } from 'element-plus/es/locale';
+
+import type { App } from 'vue';
+import { ref } from 'vue';
+
+import {
+  $t,
+  setupI18n as coreSetup,
+  loadLocalesMapFromDir,
+} from '@vben/locales';
+import { preferences } from '@vben/preferences';
+
+import dayjs from 'dayjs';
+import enLocale from 'element-plus/es/locale/lang/en';
+import defaultLocale from 'element-plus/es/locale/lang/zh-cn';
+
+const elementLocale = ref<Language>(defaultLocale);
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
+/**
+ * 鍔犺浇搴旂敤鐗规湁鐨勮瑷�鍖�
+ * 杩欓噷涔熷彲浠ユ敼閫犱负浠庢湇鍔$鑾峰彇缈昏瘧鏁版嵁
+ * @param lang
+ */
+async function loadMessages(lang: SupportedLanguagesType) {
+  const [appLocaleMessages] = await Promise.all([
+    localesMap[lang]?.(),
+    loadThirdPartyMessage(lang),
+  ]);
+  return appLocaleMessages?.default;
+}
+
+/**
+ * 鍔犺浇绗笁鏂圭粍浠跺簱鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
+  await Promise.all([loadElementLocale(lang), loadDayjsLocale(lang)]);
+}
+
+/**
+ * 鍔犺浇dayjs鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    // 榛樿浣跨敤鑻辫
+    default: {
+      locale = await import('dayjs/locale/en');
+    }
+  }
+  if (locale) {
+    dayjs.locale(locale);
+  } else {
+    console.error(`Failed to load dayjs locale for ${lang}`);
+  }
+}
+
+/**
+ * 鍔犺浇element-plus鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadElementLocale(lang: SupportedLanguagesType) {
+  switch (lang) {
+    case 'en-US': {
+      elementLocale.value = enLocale;
+      break;
+    }
+    case 'zh-CN': {
+      elementLocale.value = defaultLocale;
+      break;
+    }
+  }
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+  await coreSetup(app, {
+    defaultLocale: preferences.app.locale,
+    loadMessages,
+    missingWarn: !import.meta.env.PROD,
+    ...options,
+  });
+}
+
+export { $t, elementLocale, setupI18n };
diff --git a/eims-ui/apps/web-ele/src/locales/langs/en-US/demos.json b/eims-ui/apps/web-ele/src/locales/langs/en-US/demos.json
new file mode 100644
index 0000000..6eddebb
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/langs/en-US/demos.json
@@ -0,0 +1,13 @@
+{
+  "title": "Demos",
+  "elementPlus": "Element Plus",
+  "form": "Form",
+  "vben": {
+    "title": "Project",
+    "about": "About",
+    "document": "Document",
+    "antdv": "Ant Design Vue Version",
+    "naive-ui": "Naive UI Version",
+    "element-plus": "Element Plus Version"
+  }
+}
diff --git a/eims-ui/apps/web-ele/src/locales/langs/en-US/page.json b/eims-ui/apps/web-ele/src/locales/langs/en-US/page.json
new file mode 100644
index 0000000..618a258
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/langs/en-US/page.json
@@ -0,0 +1,14 @@
+{
+  "auth": {
+    "login": "Login",
+    "register": "Register",
+    "codeLogin": "Code Login",
+    "qrcodeLogin": "Qr Code Login",
+    "forgetPassword": "Forget Password"
+  },
+  "dashboard": {
+    "title": "Dashboard",
+    "analytics": "Analytics",
+    "workspace": "Workspace"
+  }
+}
diff --git a/eims-ui/apps/web-ele/src/locales/langs/zh-CN/demos.json b/eims-ui/apps/web-ele/src/locales/langs/zh-CN/demos.json
new file mode 100644
index 0000000..ba6d6cc
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/langs/zh-CN/demos.json
@@ -0,0 +1,13 @@
+{
+  "title": "婕旂ず",
+  "elementPlus": "Element Plus",
+  "form": "琛ㄥ崟婕旂ず",
+  "vben": {
+    "title": "椤圭洰",
+    "about": "鍏充簬",
+    "document": "鏂囨。",
+    "antdv": "Ant Design Vue 鐗堟湰",
+    "naive-ui": "Naive UI 鐗堟湰",
+    "element-plus": "Element Plus 鐗堟湰"
+  }
+}
diff --git a/eims-ui/apps/web-ele/src/locales/langs/zh-CN/page.json b/eims-ui/apps/web-ele/src/locales/langs/zh-CN/page.json
new file mode 100644
index 0000000..4cb6708
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/locales/langs/zh-CN/page.json
@@ -0,0 +1,14 @@
+{
+  "auth": {
+    "login": "鐧诲綍",
+    "register": "娉ㄥ唽",
+    "codeLogin": "楠岃瘉鐮佺櫥褰�",
+    "qrcodeLogin": "浜岀淮鐮佺櫥褰�",
+    "forgetPassword": "蹇樿瀵嗙爜"
+  },
+  "dashboard": {
+    "title": "姒傝",
+    "analytics": "鍒嗘瀽椤�",
+    "workspace": "宸ヤ綔鍙�"
+  }
+}
diff --git a/eims-ui/apps/web-ele/src/main.ts b/eims-ui/apps/web-ele/src/main.ts
new file mode 100644
index 0000000..5d728a0
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/main.ts
@@ -0,0 +1,31 @@
+import { initPreferences } from '@vben/preferences';
+import { unmountGlobalLoading } from '@vben/utils';
+
+import { overridesPreferences } from './preferences';
+
+/**
+ * 搴旂敤鍒濆鍖栧畬鎴愪箣鍚庡啀杩涜椤甸潰鍔犺浇娓叉煋
+ */
+async function initApplication() {
+  // name鐢ㄤ簬鎸囧畾椤圭洰鍞竴鏍囪瘑
+  // 鐢ㄤ簬鍖哄垎涓嶅悓椤圭洰鐨勫亸濂借缃互鍙婂瓨鍌ㄦ暟鎹殑key鍓嶇紑浠ュ強鍏朵粬涓�浜涢渶瑕侀殧绂荤殑鏁版嵁
+  const env = import.meta.env.PROD ? 'prod' : 'dev';
+  const appVersion = import.meta.env.VITE_APP_VERSION;
+  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
+
+  // app鍋忓ソ璁剧疆鍒濆鍖�
+  await initPreferences({
+    namespace,
+    overrides: overridesPreferences,
+  });
+
+  // 鍚姩搴旂敤骞舵寕杞�
+  // vue搴旂敤涓昏閫昏緫鍙婅鍥�
+  const { bootstrap } = await import('./bootstrap');
+  await bootstrap(namespace);
+
+  // 绉婚櫎骞堕攢姣乴oading
+  unmountGlobalLoading();
+}
+
+initApplication();
diff --git a/eims-ui/apps/web-ele/src/preferences.ts b/eims-ui/apps/web-ele/src/preferences.ts
new file mode 100644
index 0000000..b2e9ace
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/preferences.ts
@@ -0,0 +1,13 @@
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 椤圭洰閰嶇疆鏂囦欢
+ * 鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆
+ * !!! 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    name: import.meta.env.VITE_APP_TITLE,
+  },
+});
diff --git a/eims-ui/apps/web-ele/src/router/access.ts b/eims-ui/apps/web-ele/src/router/access.ts
new file mode 100644
index 0000000..2d07c89
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/access.ts
@@ -0,0 +1,42 @@
+import type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+} from '@vben/types';
+
+import { generateAccessible } from '@vben/access';
+import { preferences } from '@vben/preferences';
+
+import { ElMessage } from 'element-plus';
+
+import { getAllMenusApi } from '#/api';
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
+
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
+
+  const layoutMap: ComponentRecordType = {
+    BasicLayout,
+    IFrameView,
+  };
+
+  return await generateAccessible(preferences.app.accessMode, {
+    ...options,
+    fetchMenuListAsync: async () => {
+      ElMessage({
+        duration: 1500,
+        message: `${$t('common.loadingMenu')}...`,
+      });
+      return await getAllMenusApi();
+    },
+    // 鍙互鎸囧畾娌℃湁鏉冮檺璺宠浆403椤甸潰
+    forbiddenComponent,
+    // 濡傛灉 route.meta.menuVisibleWithForbidden = true
+    layoutMap,
+    pageMap,
+  });
+}
+
+export { generateAccess };
diff --git a/eims-ui/apps/web-ele/src/router/guard.ts b/eims-ui/apps/web-ele/src/router/guard.ts
new file mode 100644
index 0000000..fce5a89
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/guard.ts
@@ -0,0 +1,125 @@
+import type { Router } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { startProgress, stopProgress } from '@vben/utils';
+
+import { accessRoutes, coreRouteNames } from '#/router/routes';
+import { useAuthStore } from '#/store';
+
+import { generateAccess } from './access';
+
+/**
+ * 閫氱敤瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupCommonGuard(router: Router) {
+  // 璁板綍宸茬粡鍔犺浇鐨勯〉闈�
+  const loadedPaths = new Set<string>();
+
+  router.beforeEach(async (to) => {
+    to.meta.loaded = loadedPaths.has(to.path);
+
+    // 椤甸潰鍔犺浇杩涘害鏉�
+    if (!to.meta.loaded && preferences.transition.progress) {
+      startProgress();
+    }
+    return true;
+  });
+
+  router.afterEach((to) => {
+    // 璁板綍椤甸潰鏄惁鍔犺浇,濡傛灉宸茬粡鍔犺浇锛屽悗缁殑椤甸潰鍒囨崲鍔ㄧ敾绛夋晥鏋滀笉鍦ㄩ噸澶嶆墽琛�
+
+    loadedPaths.add(to.path);
+
+    // 鍏抽棴椤甸潰鍔犺浇杩涘害鏉�
+    if (preferences.transition.progress) {
+      stopProgress();
+    }
+  });
+}
+
+/**
+ * 鏉冮檺璁块棶瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupAccessGuard(router: Router) {
+  router.beforeEach(async (to, from) => {
+    const accessStore = useAccessStore();
+    const userStore = useUserStore();
+    const authStore = useAuthStore();
+
+    // 鍩烘湰璺敱锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴�
+    if (coreRouteNames.includes(to.name as string)) {
+      if (to.path === LOGIN_PATH && accessStore.accessToken) {
+        return decodeURIComponent(
+          (to.query?.redirect as string) || DEFAULT_HOME_PATH,
+        );
+      }
+      return true;
+    }
+
+    // accessToken 妫�鏌�
+    if (!accessStore.accessToken) {
+      // 鏄庣‘澹版槑蹇界暐鏉冮檺璁块棶鏉冮檺锛屽垯鍙互璁块棶
+      if (to.meta.ignoreAccess) {
+        return true;
+      }
+
+      // 娌℃湁璁块棶鏉冮檺锛岃烦杞櫥褰曢〉闈�
+      if (to.fullPath !== LOGIN_PATH) {
+        return {
+          path: LOGIN_PATH,
+          // 濡備笉闇�瑕侊紝鐩存帴鍒犻櫎 query
+          query: { redirect: encodeURIComponent(to.fullPath) },
+          // 鎼哄甫褰撳墠璺宠浆鐨勯〉闈紝鐧诲綍鍚庨噸鏂拌烦杞椤甸潰
+          replace: true,
+        };
+      }
+      return to;
+    }
+
+    // 鏄惁宸茬粡鐢熸垚杩囧姩鎬佽矾鐢�
+    if (accessStore.isAccessChecked) {
+      return true;
+    }
+
+    // 鐢熸垚璺敱琛�
+    // 褰撳墠鐧诲綍鐢ㄦ埛鎷ユ湁鐨勮鑹叉爣璇嗗垪琛�
+    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
+    const userRoles = userInfo.roles ?? [];
+
+    // 鐢熸垚鑿滃崟鍜岃矾鐢�
+    const { accessibleMenus, accessibleRoutes } = await generateAccess({
+      roles: userRoles,
+      router,
+      // 鍒欎細鍦ㄨ彍鍗曚腑鏄剧ず锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+      routes: accessRoutes,
+    });
+
+    // 淇濆瓨鑿滃崟淇℃伅鍜岃矾鐢变俊鎭�
+    accessStore.setAccessMenus(accessibleMenus);
+    accessStore.setAccessRoutes(accessibleRoutes);
+    accessStore.setIsAccessChecked(true);
+    const redirectPath = (from.query.redirect ?? to.fullPath) as string;
+
+    return {
+      ...router.resolve(decodeURIComponent(redirectPath)),
+      replace: true,
+    };
+  });
+}
+
+/**
+ * 椤圭洰瀹堝崼閰嶇疆
+ * @param router
+ */
+function createRouterGuard(router: Router) {
+  /** 閫氱敤 */
+  setupCommonGuard(router);
+  /** 鏉冮檺璁块棶 */
+  setupAccessGuard(router);
+}
+
+export { createRouterGuard };
diff --git a/eims-ui/apps/web-ele/src/router/index.ts b/eims-ui/apps/web-ele/src/router/index.ts
new file mode 100644
index 0000000..4840230
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/index.ts
@@ -0,0 +1,37 @@
+import {
+  createRouter,
+  createWebHashHistory,
+  createWebHistory,
+} from 'vue-router';
+
+import { resetStaticRoutes } from '@vben/utils';
+
+import { createRouterGuard } from './guard';
+import { routes } from './routes';
+
+/**
+ *  @zh_CN 鍒涘缓vue-router瀹炰緥
+ */
+const router = createRouter({
+  history:
+    import.meta.env.VITE_ROUTER_HISTORY === 'hash'
+      ? createWebHashHistory(import.meta.env.VITE_BASE)
+      : createWebHistory(import.meta.env.VITE_BASE),
+  // 搴旇娣诲姞鍒拌矾鐢辩殑鍒濆璺敱鍒楄〃銆�
+  routes,
+  scrollBehavior: (to, _from, savedPosition) => {
+    if (savedPosition) {
+      return savedPosition;
+    }
+    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
+  },
+  // 鏄惁搴旇绂佹灏鹃儴鏂滄潬銆�
+  // strict: true,
+});
+
+const resetRoutes = () => resetStaticRoutes(router, routes);
+
+// 鍒涘缓璺敱瀹堝崼
+createRouterGuard(router);
+
+export { resetRoutes, router };
diff --git a/eims-ui/apps/web-ele/src/router/routes/core.ts b/eims-ui/apps/web-ele/src/router/routes/core.ts
new file mode 100644
index 0000000..fe030a9
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/routes/core.ts
@@ -0,0 +1,88 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+
+import { AuthPageLayout } from '#/layouts';
+import { $t } from '#/locales';
+import Login from '#/views/_core/authentication/login.vue';
+
+/** 鍏ㄥ眬404椤甸潰 */
+const fallbackNotFoundRoute: RouteRecordRaw = {
+  component: () => import('#/views/_core/fallback/not-found.vue'),
+  meta: {
+    hideInBreadcrumb: true,
+    hideInMenu: true,
+    hideInTab: true,
+    title: '404',
+  },
+  name: 'FallbackNotFound',
+  path: '/:path(.*)*',
+};
+
+/** 鍩烘湰璺敱锛岃繖浜涜矾鐢辨槸蹇呴』瀛樺湪鐨� */
+const coreRoutes: RouteRecordRaw[] = [
+  {
+    meta: {
+      title: 'Root',
+    },
+    name: 'Root',
+    path: '/',
+    redirect: DEFAULT_HOME_PATH,
+  },
+  {
+    component: AuthPageLayout,
+    meta: {
+      hideInTab: true,
+      title: 'Authentication',
+    },
+    name: 'Authentication',
+    path: '/auth',
+    redirect: LOGIN_PATH,
+    children: [
+      {
+        name: 'Login',
+        path: 'login',
+        component: Login,
+        meta: {
+          title: $t('page.auth.login'),
+        },
+      },
+      {
+        name: 'CodeLogin',
+        path: 'code-login',
+        component: () => import('#/views/_core/authentication/code-login.vue'),
+        meta: {
+          title: $t('page.auth.codeLogin'),
+        },
+      },
+      {
+        name: 'QrCodeLogin',
+        path: 'qrcode-login',
+        component: () =>
+          import('#/views/_core/authentication/qrcode-login.vue'),
+        meta: {
+          title: $t('page.auth.qrcodeLogin'),
+        },
+      },
+      {
+        name: 'ForgetPassword',
+        path: 'forget-password',
+        component: () =>
+          import('#/views/_core/authentication/forget-password.vue'),
+        meta: {
+          title: $t('page.auth.forgetPassword'),
+        },
+      },
+      {
+        name: 'Register',
+        path: 'register',
+        component: () => import('#/views/_core/authentication/register.vue'),
+        meta: {
+          title: $t('page.auth.register'),
+        },
+      },
+    ],
+  },
+];
+
+export { coreRoutes, fallbackNotFoundRoute };
diff --git a/eims-ui/apps/web-ele/src/router/routes/index.ts b/eims-ui/apps/web-ele/src/router/routes/index.ts
new file mode 100644
index 0000000..e6fb144
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/routes/index.ts
@@ -0,0 +1,37 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
+
+import { coreRoutes, fallbackNotFoundRoute } from './core';
+
+const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
+  eager: true,
+});
+
+// 鏈夐渶瑕佸彲浠ヨ嚜琛屾墦寮�娉ㄩ噴锛屽苟鍒涘缓鏂囦欢澶�
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
+// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
+
+/** 鍔ㄦ�佽矾鐢� */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 澶栭儴璺敱鍒楄〃锛岃闂繖浜涢〉闈㈠彲浠ヤ笉闇�瑕丩ayout锛屽彲鑳界敤浜庡唴宓屽湪鍒殑绯荤粺(涓嶄細鏄剧ず鍦ㄨ彍鍗曚腑) */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
+// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
+const staticRoutes: RouteRecordRaw[] = [];
+const externalRoutes: RouteRecordRaw[] = [];
+
+/** 璺敱鍒楄〃锛岀敱鍩烘湰璺敱銆佸閮ㄨ矾鐢卞拰404鍏滃簳璺敱缁勬垚
+ *  鏃犻渶璧版潈闄愰獙璇侊紙浼氫竴鐩存樉绀哄湪鑿滃崟涓級 */
+const routes: RouteRecordRaw[] = [
+  ...coreRoutes,
+  ...externalRoutes,
+  fallbackNotFoundRoute,
+];
+
+/** 鍩烘湰璺敱鍒楄〃锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴� */
+const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
+
+/** 鏈夋潈闄愭牎楠岀殑璺敱鍒楄〃锛屽寘鍚姩鎬佽矾鐢卞拰闈欐�佽矾鐢� */
+const accessRoutes = [...dynamicRoutes, ...staticRoutes];
+export { accessRoutes, coreRouteNames, routes };
diff --git a/eims-ui/apps/web-ele/src/router/routes/modules/dashboard.ts b/eims-ui/apps/web-ele/src/router/routes/modules/dashboard.ts
new file mode 100644
index 0000000..1bddab9
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/routes/modules/dashboard.ts
@@ -0,0 +1,40 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'lucide:layout-dashboard',
+      order: -1,
+      title: $t('page.dashboard.title'),
+    },
+    name: 'Dashboard',
+    path: '/',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: () => import('#/views/dashboard/analytics/index.vue'),
+        meta: {
+          affixTab: true,
+          icon: 'lucide:area-chart',
+          title: $t('page.dashboard.analytics'),
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: () => import('#/views/dashboard/workspace/index.vue'),
+        meta: {
+          icon: 'carbon:workspace',
+          title: $t('page.dashboard.workspace'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-ele/src/router/routes/modules/demos.ts b/eims-ui/apps/web-ele/src/router/routes/modules/demos.ts
new file mode 100644
index 0000000..90cc2f1
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/routes/modules/demos.ts
@@ -0,0 +1,38 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    children: [
+      {
+        meta: {
+          title: $t('demos.elementPlus'),
+        },
+        name: 'NaiveDemos',
+        path: '/demos/element',
+        component: () => import('#/views/demos/element/index.vue'),
+      },
+      {
+        meta: {
+          title: $t('demos.form'),
+        },
+        name: 'BasicForm',
+        path: '/demos/form',
+        component: () => import('#/views/demos/form/basic.vue'),
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-ele/src/router/routes/modules/vben.ts b/eims-ui/apps/web-ele/src/router/routes/modules/vben.ts
new file mode 100644
index 0000000..2cfef54
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/router/routes/modules/vben.ts
@@ -0,0 +1,82 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import {
+  VBEN_ANT_PREVIEW_URL,
+  VBEN_DOC_URL,
+  VBEN_GITHUB_URL,
+  VBEN_LOGO_URL,
+  VBEN_NAIVE_PREVIEW_URL,
+} from '@vben/constants';
+import { SvgAntdvLogoIcon } from '@vben/icons';
+
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('demos.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          icon: 'lucide:copyright',
+          title: $t('demos.vben.about'),
+        },
+      },
+      {
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: IFrameView,
+        meta: {
+          icon: 'lucide:book-open-text',
+          link: VBEN_DOC_URL,
+          title: $t('demos.vben.document'),
+        },
+      },
+      {
+        name: 'VbenGithub',
+        path: '/vben-admin/github',
+        component: IFrameView,
+        meta: {
+          icon: 'mdi:github',
+          link: VBEN_GITHUB_URL,
+          title: 'Github',
+        },
+      },
+      {
+        name: 'VbenNaive',
+        path: '/vben-admin/naive',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:naiveui',
+          link: VBEN_NAIVE_PREVIEW_URL,
+          title: $t('demos.vben.naive-ui'),
+        },
+      },
+      {
+        name: 'VbenAntd',
+        path: '/vben-admin/antd',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: SvgAntdvLogoIcon,
+          link: VBEN_ANT_PREVIEW_URL,
+          title: $t('demos.vben.antdv'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-ele/src/store/auth.ts b/eims-ui/apps/web-ele/src/store/auth.ts
new file mode 100644
index 0000000..639fb03
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/store/auth.ts
@@ -0,0 +1,116 @@
+import type { Recordable, UserInfo } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
+
+import { ElNotification } from 'element-plus';
+import { defineStore } from 'pinia';
+
+import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
+import { $t } from '#/locales';
+
+export const useAuthStore = defineStore('auth', () => {
+  const accessStore = useAccessStore();
+  const userStore = useUserStore();
+  const router = useRouter();
+
+  const loginLoading = ref(false);
+
+  /**
+   * 寮傛澶勭悊鐧诲綍鎿嶄綔
+   * Asynchronously handle the login process
+   * @param params 鐧诲綍琛ㄥ崟鏁版嵁
+   */
+  async function authLogin(
+    params: Recordable<any>,
+    onSuccess?: () => Promise<void> | void,
+  ) {
+    // 寮傛澶勭悊鐢ㄦ埛鐧诲綍鎿嶄綔骞惰幏鍙� accessToken
+    let userInfo: null | UserInfo = null;
+    try {
+      loginLoading.value = true;
+      const { accessToken } = await loginApi(params);
+
+      // 濡傛灉鎴愬姛鑾峰彇鍒� accessToken
+      if (accessToken) {
+        // 灏� accessToken 瀛樺偍鍒� accessStore 涓�
+        accessStore.setAccessToken(accessToken);
+
+        // 鑾峰彇鐢ㄦ埛淇℃伅骞跺瓨鍌ㄥ埌 accessStore 涓�
+        const [fetchUserInfoResult, accessCodes] = await Promise.all([
+          fetchUserInfo(),
+          getAccessCodesApi(),
+        ]);
+
+        userInfo = fetchUserInfoResult;
+
+        userStore.setUserInfo(userInfo);
+        accessStore.setAccessCodes(accessCodes);
+
+        if (accessStore.loginExpired) {
+          accessStore.setLoginExpired(false);
+        } else {
+          onSuccess
+            ? await onSuccess?.()
+            : await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
+        }
+
+        if (userInfo?.realName) {
+          ElNotification({
+            message: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
+            title: $t('authentication.loginSuccess'),
+            type: 'success',
+          });
+        }
+      }
+    } finally {
+      loginLoading.value = false;
+    }
+
+    return {
+      userInfo,
+    };
+  }
+
+  async function logout(redirect: boolean = true) {
+    try {
+      await logoutApi();
+    } catch {
+      // 涓嶅仛浠讳綍澶勭悊
+    }
+    resetAllStores();
+    accessStore.setLoginExpired(false);
+
+    // 鍥炵櫥褰曢〉甯︿笂褰撳墠璺敱鍦板潃
+    await router.replace({
+      path: LOGIN_PATH,
+      query: redirect
+        ? {
+            redirect: encodeURIComponent(router.currentRoute.value.fullPath),
+          }
+        : {},
+    });
+  }
+
+  async function fetchUserInfo() {
+    let userInfo: null | UserInfo = null;
+    userInfo = await getUserInfoApi();
+    userStore.setUserInfo(userInfo);
+    return userInfo;
+  }
+
+  function $reset() {
+    loginLoading.value = false;
+  }
+
+  return {
+    $reset,
+    authLogin,
+    fetchUserInfo,
+    loginLoading,
+    logout,
+  };
+});
diff --git a/eims-ui/apps/web-ele/src/store/index.ts b/eims-ui/apps/web-ele/src/store/index.ts
new file mode 100644
index 0000000..269586e
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/store/index.ts
@@ -0,0 +1 @@
+export * from './auth';
diff --git a/eims-ui/apps/web-ele/src/views/_core/README.md b/eims-ui/apps/web-ele/src/views/_core/README.md
new file mode 100644
index 0000000..8248afe
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/README.md
@@ -0,0 +1,3 @@
+# \_core
+
+姝ょ洰褰曞寘鍚簲鐢ㄧ▼搴忔甯歌繍琛屾墍闇�鐨勫熀鏈鍥俱�傝繖浜涜鍥炬槸搴旂敤绋嬪簭甯冨眬涓娇鐢ㄧ殑瑙嗗浘銆�
diff --git a/eims-ui/apps/web-ele/src/views/_core/about/index.vue b/eims-ui/apps/web-ele/src/views/_core/about/index.vue
new file mode 100644
index 0000000..0ee5243
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/about/index.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { About } from '@vben/common-ui';
+
+defineOptions({ name: 'About' });
+</script>
+
+<template>
+  <About />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/authentication/code-login.vue b/eims-ui/apps/web-ele/src/views/_core/authentication/code-login.vue
new file mode 100644
index 0000000..1fc15e1
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/authentication/code-login.vue
@@ -0,0 +1,64 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationCodeLogin, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'CodeLogin' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.mobile'),
+      },
+      fieldName: 'phoneNumber',
+      label: $t('authentication.mobile'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.mobileTip') })
+        .refine((v) => /^\d{11}$/.test(v), {
+          message: $t('authentication.mobileErrortip'),
+        }),
+    },
+    {
+      component: 'VbenPinInput',
+      componentProps: {
+        createText: (countdown: number) => {
+          const text =
+            countdown > 0
+              ? $t('authentication.sendText', [countdown])
+              : $t('authentication.sendCode');
+          return text;
+        },
+        placeholder: $t('authentication.code'),
+      },
+      fieldName: 'code',
+      label: $t('authentication.code'),
+      rules: z.string().min(1, { message: $t('authentication.codeTip') }),
+    },
+  ];
+});
+/**
+ * 寮傛澶勭悊鐧诲綍鎿嶄綔
+ * Asynchronously handle the login process
+ * @param values 鐧诲綍琛ㄥ崟鏁版嵁
+ */
+async function handleLogin(values: Recordable<any>) {
+  console.log(values);
+}
+</script>
+
+<template>
+  <AuthenticationCodeLogin
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleLogin"
+  />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/authentication/forget-password.vue b/eims-ui/apps/web-ele/src/views/_core/authentication/forget-password.vue
new file mode 100644
index 0000000..0958e89
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/authentication/forget-password.vue
@@ -0,0 +1,42 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationForgetPassword, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'ForgetPassword' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: 'example@example.com',
+      },
+      fieldName: 'email',
+      label: $t('authentication.email'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.emailTip') })
+        .email($t('authentication.emailValidErrorTip')),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('reset email:', value);
+}
+</script>
+
+<template>
+  <AuthenticationForgetPassword
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/authentication/login.vue b/eims-ui/apps/web-ele/src/views/_core/authentication/login.vue
new file mode 100644
index 0000000..099e4c8
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/authentication/login.vue
@@ -0,0 +1,98 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { BasicOption } from '@vben/types';
+
+import { computed, markRaw } from 'vue';
+
+import { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { useAuthStore } from '#/store';
+
+defineOptions({ name: 'Login' });
+
+const authStore = useAuthStore();
+
+const MOCK_USER_OPTIONS: BasicOption[] = [
+  {
+    label: 'Super',
+    value: 'vben',
+  },
+  {
+    label: 'Admin',
+    value: 'admin',
+  },
+  {
+    label: 'User',
+    value: 'jack',
+  },
+];
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenSelect',
+      componentProps: {
+        options: MOCK_USER_OPTIONS,
+        placeholder: $t('authentication.selectAccount'),
+      },
+      fieldName: 'selectAccount',
+      label: $t('authentication.selectAccount'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.selectAccount') })
+        .optional()
+        .default('vben'),
+    },
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      dependencies: {
+        trigger(values, form) {
+          if (values.selectAccount) {
+            const findUser = MOCK_USER_OPTIONS.find(
+              (item) => item.value === values.selectAccount,
+            );
+            if (findUser) {
+              form.setValues({
+                password: '123456',
+                username: findUser.value,
+              });
+            }
+          }
+        },
+        triggerFields: ['selectAccount'],
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: markRaw(SliderCaptcha),
+      fieldName: 'captcha',
+      rules: z.boolean().refine((value) => value, {
+        message: $t('authentication.verifyRequiredTip'),
+      }),
+    },
+  ];
+});
+</script>
+
+<template>
+  <AuthenticationLogin
+    :form-schema="formSchema"
+    :loading="authStore.loginLoading"
+    @submit="authStore.authLogin"
+  />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/authentication/qrcode-login.vue b/eims-ui/apps/web-ele/src/views/_core/authentication/qrcode-login.vue
new file mode 100644
index 0000000..23f5f2d
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/authentication/qrcode-login.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+import { AuthenticationQrCodeLogin } from '@vben/common-ui';
+import { LOGIN_PATH } from '@vben/constants';
+
+defineOptions({ name: 'QrCodeLogin' });
+</script>
+
+<template>
+  <AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/authentication/register.vue b/eims-ui/apps/web-ele/src/views/_core/authentication/register.vue
new file mode 100644
index 0000000..f264c46
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/authentication/register.vue
@@ -0,0 +1,95 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, h, ref } from 'vue';
+
+import { AuthenticationRegister, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'Register' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        passwordStrength: true,
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      renderComponentContent() {
+        return {
+          strengthText: () => $t('authentication.passwordStrength'),
+        };
+      },
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.confirmPassword'),
+      },
+      dependencies: {
+        rules(values) {
+          const { password } = values;
+          return z
+            .string({ required_error: $t('authentication.passwordTip') })
+            .min(1, { message: $t('authentication.passwordTip') })
+            .refine((value) => value === password, {
+              message: $t('authentication.confirmPasswordTip'),
+            });
+        },
+        triggerFields: ['password'],
+      },
+      fieldName: 'confirmPassword',
+      label: $t('authentication.confirmPassword'),
+    },
+    {
+      component: 'VbenCheckbox',
+      fieldName: 'agreePolicy',
+      renderComponentContent: () => ({
+        default: () =>
+          h('span', [
+            $t('authentication.agree'),
+            h(
+              'a',
+              {
+                class: 'vben-link ml-1 ',
+                href: '',
+              },
+              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,
+            ),
+          ]),
+      }),
+      rules: z.boolean().refine((value) => !!value, {
+        message: $t('authentication.agreeTip'),
+      }),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('register submit:', value);
+}
+</script>
+
+<template>
+  <AuthenticationRegister
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/fallback/coming-soon.vue b/eims-ui/apps/web-ele/src/views/_core/fallback/coming-soon.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/fallback/coming-soon.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/fallback/forbidden.vue b/eims-ui/apps/web-ele/src/views/_core/fallback/forbidden.vue
new file mode 100644
index 0000000..8ea65fe
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/fallback/forbidden.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback403Demo' });
+</script>
+
+<template>
+  <Fallback status="403" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/fallback/internal-error.vue b/eims-ui/apps/web-ele/src/views/_core/fallback/internal-error.vue
new file mode 100644
index 0000000..819a47d
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/fallback/internal-error.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback500Demo' });
+</script>
+
+<template>
+  <Fallback status="500" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/fallback/not-found.vue b/eims-ui/apps/web-ele/src/views/_core/fallback/not-found.vue
new file mode 100644
index 0000000..4d178e9
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/fallback/not-found.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback404Demo' });
+</script>
+
+<template>
+  <Fallback status="404" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/_core/fallback/offline.vue b/eims-ui/apps/web-ele/src/views/_core/fallback/offline.vue
new file mode 100644
index 0000000..5de4a88
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/_core/fallback/offline.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'FallbackOfflineDemo' });
+</script>
+
+<template>
+  <Fallback status="offline" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue
new file mode 100644
index 0000000..fadfc91
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-trends.vue
@@ -0,0 +1,100 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        areaStyle: {},
+        data: [
+          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,
+          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,
+          111,
+        ],
+        itemStyle: {
+          color: '#5ab1ef',
+        },
+        smooth: true,
+        type: 'line',
+      },
+      {
+        areaStyle: {},
+        data: [
+          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,
+          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,
+        ],
+        itemStyle: {
+          color: '#019680',
+        },
+        smooth: true,
+        type: 'line',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          color: '#019680',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    // xAxis: {
+    //   axisTick: {
+    //     show: false,
+    //   },
+    //   boundaryGap: false,
+    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+    //   type: 'category',
+    // },
+    xAxis: {
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: false,
+      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+      splitLine: {
+        lineStyle: {
+          type: 'solid',
+          width: 1,
+        },
+        show: true,
+      },
+      type: 'category',
+    },
+    yAxis: [
+      {
+        axisTick: {
+          show: false,
+        },
+        max: 80_000,
+        splitArea: {
+          show: true,
+        },
+        splitNumber: 4,
+        type: 'value',
+      },
+    ],
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue
new file mode 100644
index 0000000..30c4265
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-data.vue
@@ -0,0 +1,84 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: 0,
+      data: ['璁块棶', '瓒嬪娍'],
+    },
+    radar: {
+      indicator: [
+        {
+          name: '缃戦〉',
+        },
+        {
+          name: '绉诲姩绔�',
+        },
+        {
+          name: 'Ipad',
+        },
+        {
+          name: '瀹㈡埛绔�',
+        },
+        {
+          name: '绗笁鏂�',
+        },
+        {
+          name: '鍏跺畠',
+        },
+      ],
+      radius: '60%',
+      splitNumber: 8,
+    },
+    series: [
+      {
+        areaStyle: {
+          opacity: 1,
+          shadowBlur: 0,
+          shadowColor: 'rgba(0,0,0,.2)',
+          shadowOffsetX: 0,
+          shadowOffsetY: 10,
+        },
+        data: [
+          {
+            itemStyle: {
+              color: '#b6a2de',
+            },
+            name: '璁块棶',
+            value: [90, 50, 86, 40, 50, 20],
+          },
+          {
+            itemStyle: {
+              color: '#5ab1ef',
+            },
+            name: '瓒嬪娍',
+            value: [70, 75, 70, 76, 20, 85],
+          },
+        ],
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        symbolSize: 0,
+        type: 'radar',
+      },
+    ],
+    tooltip: {},
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue
new file mode 100644
index 0000000..260520b
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-sales.vue
@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 400;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        center: ['50%', '50%'],
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '澶栧寘', value: 500 },
+          { name: '瀹氬埗', value: 310 },
+          { name: '鎶�鏈敮鎸�', value: 274 },
+          { name: '杩滅▼', value: 400 },
+        ].sort((a, b) => {
+          return a.value - b.value;
+        }),
+        name: '鍟嗕笟鍗犳瘮',
+        radius: '80%',
+        roseType: 'radius',
+        type: 'pie',
+      },
+    ],
+
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue
new file mode 100644
index 0000000..e0d0aab
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits-source.vue
@@ -0,0 +1,67 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: '2%',
+      left: 'center',
+    },
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 100;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        avoidLabelOverlap: false,
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '鎼滅储寮曟搸', value: 1048 },
+          { name: '鐩存帴璁块棶', value: 735 },
+          { name: '閭欢钀ラ攢', value: 580 },
+          { name: '鑱旂洘骞垮憡', value: 484 },
+        ],
+        emphasis: {
+          label: {
+            fontSize: '12',
+            fontWeight: 'bold',
+            show: true,
+          },
+        },
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        label: {
+          position: 'center',
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        name: '璁块棶鏉ユ簮',
+        radius: ['40%', '65%'],
+        type: 'pie',
+      },
+    ],
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue
new file mode 100644
index 0000000..7e1f14e
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/analytics-visits.vue
@@ -0,0 +1,57 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        barMaxWidth: 80,
+        // color: '#4f69fd',
+        data: [
+          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,
+          3200, 4800,
+        ],
+        type: 'bar',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          // color: '#4f69fd',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    xAxis: {
+      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}鏈坄),
+      type: 'category',
+    },
+    yAxis: {
+      max: 8000,
+      splitNumber: 4,
+      type: 'value',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/analytics/index.vue b/eims-ui/apps/web-ele/src/views/dashboard/analytics/index.vue
new file mode 100644
index 0000000..00b34df
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/analytics/index.vue
@@ -0,0 +1,90 @@
+<script lang="ts" setup>
+import type { AnalysisOverviewItem } from '@vben/common-ui';
+import type { TabOption } from '@vben/types';
+
+import {
+  AnalysisChartCard,
+  AnalysisChartsTabs,
+  AnalysisOverview,
+} from '@vben/common-ui';
+import {
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+} from '@vben/icons';
+
+import AnalyticsTrends from './analytics-trends.vue';
+import AnalyticsVisits from './analytics-visits.vue';
+import AnalyticsVisitsData from './analytics-visits-data.vue';
+import AnalyticsVisitsSales from './analytics-visits-sales.vue';
+import AnalyticsVisitsSource from './analytics-visits-source.vue';
+
+const overviewItems: AnalysisOverviewItem[] = [
+  {
+    icon: SvgCardIcon,
+    title: '鐢ㄦ埛閲�',
+    totalTitle: '鎬荤敤鎴烽噺',
+    totalValue: 120_000,
+    value: 2000,
+  },
+  {
+    icon: SvgCakeIcon,
+    title: '璁块棶閲�',
+    totalTitle: '鎬昏闂噺',
+    totalValue: 500_000,
+    value: 20_000,
+  },
+  {
+    icon: SvgDownloadIcon,
+    title: '涓嬭浇閲�',
+    totalTitle: '鎬讳笅杞介噺',
+    totalValue: 120_000,
+    value: 8000,
+  },
+  {
+    icon: SvgBellIcon,
+    title: '浣跨敤閲�',
+    totalTitle: '鎬讳娇鐢ㄩ噺',
+    totalValue: 50_000,
+    value: 5000,
+  },
+];
+
+const chartTabs: TabOption[] = [
+  {
+    label: '娴侀噺瓒嬪娍',
+    value: 'trends',
+  },
+  {
+    label: '鏈堣闂噺',
+    value: 'visits',
+  },
+];
+</script>
+
+<template>
+  <div class="p-5">
+    <AnalysisOverview :items="overviewItems" />
+    <AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
+      <template #trends>
+        <AnalyticsTrends />
+      </template>
+      <template #visits>
+        <AnalyticsVisits />
+      </template>
+    </AnalysisChartsTabs>
+
+    <div class="mt-5 w-full md:flex">
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏁伴噺">
+        <AnalyticsVisitsData />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSource />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSales />
+      </AnalysisChartCard>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/dashboard/workspace/index.vue b/eims-ui/apps/web-ele/src/views/dashboard/workspace/index.vue
new file mode 100644
index 0000000..b95d613
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/dashboard/workspace/index.vue
@@ -0,0 +1,266 @@
+<script lang="ts" setup>
+import type {
+  WorkbenchProjectItem,
+  WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
+} from '@vben/common-ui';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import {
+  AnalysisChartCard,
+  WorkbenchHeader,
+  WorkbenchProject,
+  WorkbenchQuickNav,
+  WorkbenchTodo,
+  WorkbenchTrends,
+} from '@vben/common-ui';
+import { preferences } from '@vben/preferences';
+import { useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';
+
+const userStore = useUserStore();
+
+// 杩欐槸涓�涓ず渚嬫暟鎹紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// url 涔熷彲浠ユ槸鍐呴儴璺敱锛屽湪 navTo 鏂规硶涓瘑鍒鐞嗭紝杩涜鍐呴儴璺宠浆
+// 渚嬪锛歶rl: /dashboard/workspace
+const projectItems: WorkbenchProjectItem[] = [
+  {
+    color: '',
+    content: '涓嶈绛夊緟鏈轰細锛岃�岃鍒涢�犳満浼氥��',
+    date: '2021-04-01',
+    group: '寮�婧愮粍',
+    icon: 'carbon:logo-github',
+    title: 'Github',
+    url: 'https://github.com',
+  },
+  {
+    color: '#3fb27f',
+    content: '鐜板湪鐨勪綘鍐冲畾灏嗘潵鐨勪綘銆�',
+    date: '2021-04-01',
+    group: '绠楁硶缁�',
+    icon: 'ion:logo-vue',
+    title: 'Vue',
+    url: 'https://vuejs.org',
+  },
+  {
+    color: '#e18525',
+    content: '娌℃湁浠�涔堟墠鑳芥瘮鍔姏鏇撮噸瑕併��',
+    date: '2021-04-01',
+    group: '涓婄彮鎽搁奔',
+    icon: 'ion:logo-html5',
+    title: 'Html5',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',
+  },
+  {
+    color: '#bf0c2c',
+    content: '鐑儏鍜屾鏈涘彲浠ョ獊鐮翠竴鍒囬毦鍏炽��',
+    date: '2021-04-01',
+    group: 'UI',
+    icon: 'ion:logo-angular',
+    title: 'Angular',
+    url: 'https://angular.io',
+  },
+  {
+    color: '#00d8ff',
+    content: '鍋ュ悍鐨勮韩浣撴槸瀹炵幇鐩爣鐨勫熀鐭炽��',
+    date: '2021-04-01',
+    group: '鎶�鏈墰',
+    icon: 'bx:bxl-react',
+    title: 'React',
+    url: 'https://reactjs.org',
+  },
+  {
+    color: '#EBD94E',
+    content: '璺槸璧板嚭鏉ョ殑锛岃�屼笉鏄┖鎯冲嚭鏉ョ殑銆�',
+    date: '2021-04-01',
+    group: '鏋舵瀯缁�',
+    icon: 'ion:logo-javascript',
+    title: 'Js',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',
+  },
+];
+
+// 鍚屾牱锛岃繖閲岀殑 url 涔熷彲浠ヤ娇鐢ㄤ互 http 寮�澶寸殑澶栭儴閾炬帴
+const quickNavItems: WorkbenchQuickNavItem[] = [
+  {
+    color: '#1fdaca',
+    icon: 'ion:home-outline',
+    title: '棣栭〉',
+    url: '/',
+  },
+  {
+    color: '#bf0c2c',
+    icon: 'ion:grid-outline',
+    title: '浠〃鐩�',
+    url: '/dashboard',
+  },
+  {
+    color: '#e18525',
+    icon: 'ion:layers-outline',
+    title: '缁勪欢',
+    url: '/demos/features/icons',
+  },
+  {
+    color: '#3fb27f',
+    icon: 'ion:settings-outline',
+    title: '绯荤粺绠$悊',
+    url: '/demos/features/login-expired', // 杩欓噷鐨� URL 鏄ず渚嬶紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+  },
+  {
+    color: '#4daf1bc9',
+    icon: 'ion:key-outline',
+    title: '鏉冮檺绠$悊',
+    url: '/demos/access/page-control',
+  },
+  {
+    color: '#00d8ff',
+    icon: 'ion:bar-chart-outline',
+    title: '鍥捐〃',
+    url: '/analytics',
+  },
+];
+
+const todoItems = ref<WorkbenchTodoItem[]>([
+  {
+    completed: false,
+    content: `瀹℃煡鏈�杩戞彁浜ゅ埌Git浠撳簱鐨勫墠绔唬鐮侊紝纭繚浠g爜璐ㄩ噺鍜岃鑼冦�俙,
+    date: '2024-07-30 11:00:00',
+    title: '瀹℃煡鍓嶇浠g爜鎻愪氦',
+  },
+  {
+    completed: true,
+    content: `妫�鏌ュ苟浼樺寲绯荤粺鎬ц兘锛岄檷浣嶤PU浣跨敤鐜囥�俙,
+    date: '2024-07-30 11:00:00',
+    title: '绯荤粺鎬ц兘浼樺寲',
+  },
+  {
+    completed: false,
+    content: `杩涜绯荤粺瀹夊叏妫�鏌ワ紝纭繚娌℃湁瀹夊叏婕忔礊鎴栨湭鎺堟潈鐨勮闂�� `,
+    date: '2024-07-30 11:00:00',
+    title: '瀹夊叏妫�鏌�',
+  },
+  {
+    completed: false,
+    content: `鏇存柊椤圭洰涓殑鎵�鏈塶pm渚濊禆鍖咃紝纭繚浣跨敤鏈�鏂扮増鏈�俙,
+    date: '2024-07-30 11:00:00',
+    title: '鏇存柊椤圭洰渚濊禆',
+  },
+  {
+    completed: false,
+    content: `淇鐢ㄦ埛鎶ュ憡鐨勯〉闈I鏄剧ず闂锛岀‘淇濆湪涓嶅悓娴忚鍣ㄤ腑鏄剧ず涓�鑷淬�� `,
+    date: '2024-07-30 11:00:00',
+    title: '淇UI鏄剧ず闂',
+  },
+]);
+const trendItems: WorkbenchTrendItem[] = [
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍦� <a>寮�婧愮粍</a> 鍒涘缓浜嗛」鐩� <a>Vue</a>`,
+    date: '鍒氬垰',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏虫敞浜� <a>濞佸粔</a> `,
+    date: '1涓皬鏃跺墠',
+    title: '鑹炬枃',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1澶╁墠',
+    title: '鍏嬮噷鏂�',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓涓�涓猇ite鎻掍欢</a> `,
+    date: '2澶╁墠',
+    title: 'Vben',
+  },
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍥炲浜� <a>鏉板厠</a> 鐨勯棶棰� <a>濡備綍杩涜椤圭洰浼樺寲锛�</a>`,
+    date: '3澶╁墠',
+    title: '鐨壒',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏抽棴浜嗛棶棰� <a>濡備綍杩愯椤圭洰</a> `,
+    date: '1鍛ㄥ墠',
+    title: '鏉板厠',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1鍛ㄥ墠',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鎺ㄩ�佷簡浠g爜鍒� <a>Github</a>`,
+    date: '2021-04-01 20:00',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓浣跨敤 Admin Vben</a> `,
+    date: '2021-03-01 20:00',
+    title: 'Vben',
+  },
+];
+
+const router = useRouter();
+
+// 杩欐槸涓�涓ず渚嬫柟娉曪紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// This is a sample method, adjust according to the actual project requirements
+function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {
+  if (nav.url?.startsWith('http')) {
+    openWindow(nav.url);
+    return;
+  }
+  if (nav.url?.startsWith('/')) {
+    router.push(nav.url).catch((error) => {
+      console.error('Navigation failed:', error);
+    });
+  } else {
+    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);
+  }
+}
+</script>
+
+<template>
+  <div class="p-5">
+    <WorkbenchHeader
+      :avatar="userStore.userInfo?.avatar || preferences.app.defaultAvatar"
+    >
+      <template #title>
+        鏃╁畨, {{ userStore.userInfo?.realName }}, 寮�濮嬫偍涓�澶╃殑宸ヤ綔鍚э紒
+      </template>
+      <template #description> 浠婃棩鏅达紝20鈩� - 32鈩冿紒 </template>
+    </WorkbenchHeader>
+
+    <div class="mt-5 flex flex-col lg:flex-row">
+      <div class="mr-4 w-full lg:w-3/5">
+        <WorkbenchProject :items="projectItems" title="椤圭洰" @click="navTo" />
+        <WorkbenchTrends :items="trendItems" class="mt-5" title="鏈�鏂板姩鎬�" />
+      </div>
+      <div class="w-full lg:w-2/5">
+        <WorkbenchQuickNav
+          :items="quickNavItems"
+          class="mt-5 lg:mt-0"
+          title="蹇嵎瀵艰埅"
+          @click="navTo"
+        />
+        <WorkbenchTodo :items="todoItems" class="mt-5" title="寰呭姙浜嬮」" />
+        <AnalysisChartCard class="mt-5" title="璁块棶鏉ユ簮">
+          <AnalyticsVisitsSource />
+        </AnalysisChartCard>
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/demos/element/index.vue b/eims-ui/apps/web-ele/src/views/demos/element/index.vue
new file mode 100644
index 0000000..0a7012d
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/demos/element/index.vue
@@ -0,0 +1,117 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import {
+  ElButton,
+  ElCard,
+  ElMessage,
+  ElNotification,
+  ElSegmented,
+  ElSpace,
+  ElTable,
+} from 'element-plus';
+
+type NotificationType = 'error' | 'info' | 'success' | 'warning';
+
+function info() {
+  ElMessage.info('How many roads must a man walk down');
+}
+
+function error() {
+  ElMessage.error({
+    duration: 2500,
+    message: 'Once upon a time you dressed so fine',
+  });
+}
+
+function warning() {
+  ElMessage.warning('How many roads must a man walk down');
+}
+function success() {
+  ElMessage.success(
+    'Cause you walked hand in hand With another man in my place',
+  );
+}
+
+function notify(type: NotificationType) {
+  ElNotification({
+    duration: 2500,
+    message: '璇寸偣鍟ュ憿',
+    type,
+  });
+}
+const tableData = [
+  { prop1: '1', prop2: 'A' },
+  { prop1: '2', prop2: 'B' },
+  { prop1: '3', prop2: 'C' },
+  { prop1: '4', prop2: 'D' },
+  { prop1: '5', prop2: 'E' },
+  { prop1: '6', prop2: 'F' },
+];
+
+const segmentedValue = ref('Mon');
+
+const segmentedOptions = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
+</script>
+
+<template>
+  <Page
+    description="鏀寔澶氳瑷�锛屼富棰樺姛鑳介泦鎴愬垏鎹㈢瓑"
+    title="Element Plus缁勪欢浣跨敤婕旂ず"
+  >
+    <div class="flex flex-wrap gap-5">
+      <ElCard class="mb-5 w-auto">
+        <template #header> 鎸夐挳 </template>
+        <ElSpace>
+          <ElButton text>Text</ElButton>
+          <ElButton>Default</ElButton>
+          <ElButton type="primary"> Primary </ElButton>
+          <ElButton type="info"> Info </ElButton>
+          <ElButton type="success"> Success </ElButton>
+          <ElButton type="warning"> Warning </ElButton>
+          <ElButton type="danger"> Error </ElButton>
+        </ElSpace>
+      </ElCard>
+      <ElCard class="mb-5 w-80">
+        <template #header> Message </template>
+        <ElSpace>
+          <ElButton type="info" @click="info"> 淇℃伅 </ElButton>
+          <ElButton type="danger" @click="error"> 閿欒 </ElButton>
+          <ElButton type="warning" @click="warning"> 璀﹀憡 </ElButton>
+          <ElButton type="success" @click="success"> 鎴愬姛 </ElButton>
+        </ElSpace>
+      </ElCard>
+      <ElCard class="mb-5 w-80">
+        <template #header> Notification </template>
+        <ElSpace>
+          <ElButton type="info" @click="notify('info')"> 淇℃伅 </ElButton>
+          <ElButton type="danger" @click="notify('error')"> 閿欒 </ElButton>
+          <ElButton type="warning" @click="notify('warning')"> 璀﹀憡 </ElButton>
+          <ElButton type="success" @click="notify('success')"> 鎴愬姛 </ElButton>
+        </ElSpace>
+      </ElCard>
+      <ElCard class="mb-5 w-auto">
+        <template #header> Segmented </template>
+        <ElSegmented
+          v-model="segmentedValue"
+          :options="segmentedOptions"
+          size="large"
+        />
+      </ElCard>
+      <ElCard class="mb-5 w-80">
+        <template #header> V-Loading </template>
+        <div class="flex size-72 items-center justify-center" v-loading="true">
+          涓�浜涙紨绀虹殑鍐呭
+        </div>
+      </ElCard>
+      <ElCard class="mb-5 w-80">
+        <ElTable :data="tableData" stripe>
+          <ElTable.TableColumn label="娴嬭瘯鍒�1" prop="prop1" />
+          <ElTable.TableColumn label="娴嬭瘯鍒�2" prop="prop2" />
+        </ElTable>
+      </ElCard>
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-ele/src/views/demos/form/basic.vue b/eims-ui/apps/web-ele/src/views/demos/form/basic.vue
new file mode 100644
index 0000000..90aacce
--- /dev/null
+++ b/eims-ui/apps/web-ele/src/views/demos/form/basic.vue
@@ -0,0 +1,180 @@
+<script lang="ts" setup>
+import { h } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { ElButton, ElCard, ElCheckbox, ElMessage } from 'element-plus';
+
+import { useVbenForm } from '#/adapter/form';
+import { getAllMenusApi } from '#/api';
+
+const [Form, formApi] = useVbenForm({
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  layout: 'horizontal',
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+  handleSubmit: (values) => {
+    ElMessage.success(`琛ㄥ崟鏁版嵁锛�${JSON.stringify(values)}`);
+  },
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'ApiSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        afterFetch: (data: { name: string; path: string }[]) => {
+          return data.map((item: any) => ({
+            label: item.name,
+            value: item.path,
+          }));
+        },
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+      },
+      // 瀛楁鍚�
+      fieldName: 'api',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiSelect',
+    },
+    {
+      component: 'ApiTreeSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+        childrenField: 'children',
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        labelField: 'name',
+        valueField: 'path',
+      },
+      // 瀛楁鍚�
+      fieldName: 'apiTree',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiTreeSelect',
+    },
+    {
+      component: 'Input',
+      fieldName: 'string',
+      label: 'String',
+    },
+    {
+      component: 'InputNumber',
+      fieldName: 'number',
+      label: 'Number',
+    },
+    {
+      component: 'RadioGroup',
+      fieldName: 'radio',
+      label: 'Radio',
+      componentProps: {
+        options: [
+          { value: 'A', label: 'A' },
+          { value: 'B', label: 'B' },
+          { value: 'C', label: 'C' },
+          { value: 'D', label: 'D' },
+          { value: 'E', label: 'E' },
+        ],
+      },
+    },
+    {
+      component: 'RadioGroup',
+      fieldName: 'radioButton',
+      label: 'RadioButton',
+      componentProps: {
+        isButton: true,
+        options: ['A', 'B', 'C', 'D', 'E', 'F'].map((v) => ({
+          value: v,
+          label: `閫夐」${v}`,
+        })),
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      fieldName: 'checkbox',
+      label: 'Checkbox',
+      componentProps: {
+        options: ['A', 'B', 'C'].map((v) => ({ value: v, label: `閫夐」${v}` })),
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      fieldName: 'checkbox1',
+      label: 'Checkbox1',
+      renderComponentContent: () => {
+        return {
+          default: () => {
+            return ['A', 'B', 'C', 'D'].map((v) =>
+              h(ElCheckbox, { label: v, value: v }),
+            );
+          },
+        };
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      fieldName: 'checkbotton',
+      label: 'CheckBotton',
+      componentProps: {
+        isButton: true,
+        options: [
+          { value: 'A', label: '閫夐」A' },
+          { value: 'B', label: '閫夐」B' },
+          { value: 'C', label: '閫夐」C' },
+        ],
+      },
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'date',
+      label: 'Date',
+    },
+    {
+      component: 'Select',
+      fieldName: 'select',
+      label: 'Select',
+      componentProps: {
+        options: [
+          { value: 'A', label: '閫夐」A' },
+          { value: 'B', label: '閫夐」B' },
+          { value: 'C', label: '閫夐」C' },
+        ],
+      },
+    },
+  ],
+});
+function setFormValues() {
+  formApi.setValues({
+    string: 'string',
+    number: 123,
+    radio: 'B',
+    radioButton: 'C',
+    checkbox: ['A', 'C'],
+    checkbotton: ['B', 'C'],
+    checkbox1: ['A', 'B'],
+    date: new Date(),
+    select: 'B',
+  });
+}
+</script>
+<template>
+  <Page
+    description="鎴戜滑閲嶆柊鍖呰浜咰heckboxGroup銆丷adioGroup銆丼elect锛屽彲浠ラ�氳繃options灞炴�т紶鍏ラ�夐」灞炴�ф暟缁勪互鑷姩鐢熸垚閫夐」"
+    title="琛ㄥ崟婕旂ず"
+  >
+    <ElCard>
+      <template #header>
+        <div class="flex items-center">
+          <span class="flex-auto">鍩虹琛ㄥ崟婕旂ず</span>
+          <ElButton type="primary" @click="setFormValues">璁剧疆琛ㄥ崟鍊�</ElButton>
+        </div>
+      </template>
+      <Form />
+    </ElCard>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-ele/tailwind.config.mjs b/eims-ui/apps/web-ele/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/apps/web-ele/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/apps/web-ele/tsconfig.json b/eims-ui/apps/web-ele/tsconfig.json
new file mode 100644
index 0000000..02c287f
--- /dev/null
+++ b/eims-ui/apps/web-ele/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web-app.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["./src/*"]
+    }
+  },
+  "references": [{ "path": "./tsconfig.node.json" }],
+  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/eims-ui/apps/web-ele/tsconfig.node.json b/eims-ui/apps/web-ele/tsconfig.node.json
new file mode 100644
index 0000000..c2f0d86
--- /dev/null
+++ b/eims-ui/apps/web-ele/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "compilerOptions": {
+    "composite": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "noEmit": false
+  },
+  "include": ["vite.config.mts"]
+}
diff --git a/eims-ui/apps/web-ele/vite.config.mts b/eims-ui/apps/web-ele/vite.config.mts
new file mode 100644
index 0000000..9f1e723
--- /dev/null
+++ b/eims-ui/apps/web-ele/vite.config.mts
@@ -0,0 +1,27 @@
+import { defineConfig } from '@vben/vite-config';
+
+import ElementPlus from 'unplugin-element-plus/vite';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    vite: {
+      plugins: [
+        ElementPlus({
+          format: 'esm',
+        }),
+      ],
+      server: {
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock浠g悊鐩爣鍦板潃
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
diff --git a/eims-ui/apps/web-naive/.env b/eims-ui/apps/web-naive/.env
new file mode 100644
index 0000000..350660c
--- /dev/null
+++ b/eims-ui/apps/web-naive/.env
@@ -0,0 +1,5 @@
+# 搴旂敤鏍囬
+VITE_APP_TITLE=Vben Admin Naive
+
+# 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
+VITE_APP_NAMESPACE=vben-web-naive
diff --git a/eims-ui/apps/web-naive/.env.analyze b/eims-ui/apps/web-naive/.env.analyze
new file mode 100644
index 0000000..ffafa8d
--- /dev/null
+++ b/eims-ui/apps/web-naive/.env.analyze
@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true
diff --git a/eims-ui/apps/web-naive/.env.development b/eims-ui/apps/web-naive/.env.development
new file mode 100644
index 0000000..11c5254
--- /dev/null
+++ b/eims-ui/apps/web-naive/.env.development
@@ -0,0 +1,16 @@
+# 绔彛鍙�
+VITE_PORT=5888
+
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=/api
+
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=true
+
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=false
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
diff --git a/eims-ui/apps/web-naive/.env.production b/eims-ui/apps/web-naive/.env.production
new file mode 100644
index 0000000..5375847
--- /dev/null
+++ b/eims-ui/apps/web-naive/.env.production
@@ -0,0 +1,19 @@
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+
+# 鏄惁寮�鍚帇缂╋紝鍙互璁剧疆涓� none, brotli, gzip
+VITE_COMPRESS=none
+
+# 鏄惁寮�鍚� PWA
+VITE_PWA=false
+
+# vue-router 鐨勬ā寮�
+VITE_ROUTER_HISTORY=hash
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鎵撳寘鍚庢槸鍚︾敓鎴恉ist.zip
+VITE_ARCHIVER=true
diff --git a/eims-ui/apps/web-naive/index.html b/eims-ui/apps/web-naive/index.html
new file mode 100644
index 0000000..7ea6384
--- /dev/null
+++ b/eims-ui/apps/web-naive/index.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang="zh">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta name="description" content="A Modern Back-end Management System" />
+    <meta name="keywords" content="Vben Admin Vue3 Vite" />
+    <meta name="author" content="Vben" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <!-- 鐢� vite 娉ㄥ叆 VITE_APP_TITLE 鍙橀噺锛屽湪 .env 鏂囦欢鍐呴厤缃� -->
+    <title><%= VITE_APP_TITLE %></title>
+    <link rel="icon" href="/favicon.ico" />
+    <script>
+      // 鐢熶骇鐜涓嬫敞鍏ョ櫨搴︾粺璁�
+      if (window._VBEN_ADMIN_PRO_APP_CONF_) {
+        var _hmt = _hmt || [];
+        (function () {
+          var hm = document.createElement('script');
+          hm.src =
+            'https://hm.baidu.com/hm.js?24bb3eb91dfe4ebfcbcee6952a107cb6';
+          var s = document.getElementsByTagName('script')[0];
+          s.parentNode.insertBefore(hm, s);
+        })();
+      }
+    </script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>
diff --git a/eims-ui/apps/web-naive/package.json b/eims-ui/apps/web-naive/package.json
new file mode 100644
index 0000000..180b569
--- /dev/null
+++ b/eims-ui/apps/web-naive/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "@vben/web-naive",
+  "version": "5.5.0",
+  "homepage": "https://vben.pro",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "apps/web-naive"
+  },
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build --mode production",
+    "build:analyze": "pnpm vite build --mode analyze",
+    "dev": "pnpm vite --mode development",
+    "preview": "vite preview",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck"
+  },
+  "imports": {
+    "#/*": "./src/*"
+  },
+  "dependencies": {
+    "@vben/access": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/layouts": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/request": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "naive-ui": "catalog:",
+    "pinia": "catalog:",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/apps/web-naive/postcss.config.mjs b/eims-ui/apps/web-naive/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/apps/web-naive/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/apps/web-naive/public/favicon.ico b/eims-ui/apps/web-naive/public/favicon.ico
new file mode 100644
index 0000000..fcf9818
--- /dev/null
+++ b/eims-ui/apps/web-naive/public/favicon.ico
Binary files differ
diff --git a/eims-ui/apps/web-naive/src/adapter/component/index.ts b/eims-ui/apps/web-naive/src/adapter/component/index.ts
new file mode 100644
index 0000000..545a619
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/adapter/component/index.ts
@@ -0,0 +1,182 @@
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  NButton,
+  NCheckbox,
+  NCheckboxGroup,
+  NDatePicker,
+  NDivider,
+  NInput,
+  NInputNumber,
+  NRadio,
+  NRadioButton,
+  NRadioGroup,
+  NSelect,
+  NSpace,
+  NSwitch,
+  NTimePicker,
+  NTreeSelect,
+  NUpload,
+} from 'naive-ui';
+
+import { message } from '#/adapter/naive';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'ApiSelect'
+  | 'ApiTreeSelect'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'Divider'
+  | 'IconPicker'
+  | 'Input'
+  | 'InputNumber'
+  | 'RadioGroup'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+
+    ApiSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: NSelect,
+          modelPropName: 'value',
+        },
+        slots,
+      );
+    },
+    ApiTreeSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: NTreeSelect,
+          nodeKey: 'value',
+          loadingSlot: 'arrow',
+          keyField: 'value',
+          modelPropName: 'value',
+          optionsPropName: 'options',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    Checkbox: NCheckbox,
+    CheckboxGroup: (props, { attrs, slots }) => {
+      let defaultSlot;
+      if (Reflect.has(slots, 'default')) {
+        defaultSlot = slots.default;
+      } else {
+        const { options } = attrs;
+        if (Array.isArray(options)) {
+          defaultSlot = () => options.map((option) => h(NCheckbox, option));
+        }
+      }
+      return h(
+        NCheckboxGroup,
+        { ...props, ...attrs },
+        { default: defaultSlot },
+      );
+    },
+    DatePicker: NDatePicker,
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(NButton, { ...props, attrs, type: 'default' }, slots);
+    },
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(NButton, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Divider: NDivider,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'suffix', inputComponent: NInput, ...props, ...attrs },
+        slots,
+      );
+    },
+    Input: withDefaultPlaceholder(NInput, 'input'),
+    InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
+    RadioGroup: (props, { attrs, slots }) => {
+      let defaultSlot;
+      if (Reflect.has(slots, 'default')) {
+        defaultSlot = slots.default;
+      } else {
+        const { options } = attrs;
+        if (Array.isArray(options)) {
+          defaultSlot = () =>
+            options.map((option) =>
+              h(attrs.isButton ? NRadioButton : NRadio, option),
+            );
+        }
+      }
+      const groupRender = h(
+        NRadioGroup,
+        { ...props, ...attrs },
+        { default: defaultSlot },
+      );
+      return attrs.isButton
+        ? h(NSpace, { vertical: true }, () => groupRender)
+        : groupRender;
+    },
+    Select: withDefaultPlaceholder(NSelect, 'select'),
+    Space: NSpace,
+    Switch: NSwitch,
+    TimePicker: NTimePicker,
+    TreeSelect: withDefaultPlaceholder(NTreeSelect, 'select'),
+    Upload: NUpload,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      message.success(content || title, {
+        duration: 0,
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
diff --git a/eims-ui/apps/web-naive/src/adapter/form.ts b/eims-ui/apps/web-naive/src/adapter/form.ts
new file mode 100644
index 0000000..2c3cee8
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/adapter/form.ts
@@ -0,0 +1,45 @@
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+setupVbenForm<ComponentType>({
+  config: {
+    // naive-ui缁勪欢涓嶆帴鍙梠nChang浜嬩欢锛屾墍浠ラ渶瑕佺鐢�
+    disabledOnChangeListener: true,
+    // naive-ui缁勪欢鐨勭┖鍊间负null,涓嶈兘鏄痷ndefined锛屽惁鍒欓噸缃〃鍗曟椂涓嶇敓鏁�
+    emptyStateValue: null,
+    baseModelPropName: 'value',
+    modelPropNameMap: {
+      Checkbox: 'checked',
+      Radio: 'checked',
+      Upload: 'fileList',
+    },
+  },
+  defineRules: {
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    selectRequired: (value, _params, ctx) => {
+      if (value === undefined || value === null) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
diff --git a/eims-ui/apps/web-naive/src/adapter/naive.ts b/eims-ui/apps/web-naive/src/adapter/naive.ts
new file mode 100644
index 0000000..1eb7b7b
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/adapter/naive.ts
@@ -0,0 +1,25 @@
+import { computed } from 'vue';
+
+import { preferences } from '@vben/preferences';
+import '@vben/styles';
+
+import { createDiscreteApi, darkTheme, lightTheme } from 'naive-ui';
+
+const themeOverridesProviderProps = computed(() => ({
+  themeOverrides: preferences.theme.mode === 'light' ? lightTheme : darkTheme,
+}));
+
+const themeProviderProps = computed(() => ({
+  theme: preferences.theme.mode === 'light' ? lightTheme : darkTheme,
+}));
+
+export const { dialog, loadingBar, message, modal, notification } =
+  createDiscreteApi(
+    ['message', 'dialog', 'notification', 'loadingBar', 'modal'],
+    {
+      configProviderProps: themeProviderProps,
+      loadingBarProviderProps: themeOverridesProviderProps,
+      messageProviderProps: themeOverridesProviderProps,
+      notificationProviderProps: themeOverridesProviderProps,
+    },
+  );
diff --git a/eims-ui/apps/web-naive/src/adapter/vxe-table.ts b/eims-ui/apps/web-naive/src/adapter/vxe-table.ts
new file mode 100644
index 0000000..081cfb2
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/adapter/vxe-table.ts
@@ -0,0 +1,67 @@
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { NButton, NImage } from 'naive-ui';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+  configVxeTable: (vxeUI) => {
+    vxeUI.setConfig({
+      grid: {
+        align: 'center',
+        border: false,
+        columnConfig: {
+          resizable: true,
+        },
+        minHeight: 180,
+        formConfig: {
+          // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+          enabled: false,
+        },
+        proxyConfig: {
+          autoLoad: true,
+          response: {
+            result: 'items',
+            total: 'total',
+            list: 'items',
+          },
+          showActiveMsg: true,
+          showResponseMsg: false,
+        },
+        round: true,
+        showOverflow: true,
+        size: 'small',
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+    vxeUI.renderer.add('CellImage', {
+      renderTableDefault(_renderOpts, params) {
+        const { column, row } = params;
+        return h(NImage, { src: row[column.field] });
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+    vxeUI.renderer.add('CellLink', {
+      renderTableDefault(renderOpts) {
+        const { props } = renderOpts;
+        return h(
+          NButton,
+          { size: 'small', type: 'primary', quaternary: true },
+          { default: () => props?.text },
+        );
+      },
+    });
+
+    // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+    // vxeUI.formats.add
+  },
+  useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
diff --git a/eims-ui/apps/web-naive/src/api/core/auth.ts b/eims-ui/apps/web-naive/src/api/core/auth.ts
new file mode 100644
index 0000000..71d9f99
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/core/auth.ts
@@ -0,0 +1,51 @@
+import { baseRequestClient, requestClient } from '#/api/request';
+
+export namespace AuthApi {
+  /** 鐧诲綍鎺ュ彛鍙傛暟 */
+  export interface LoginParams {
+    password?: string;
+    username?: string;
+  }
+
+  /** 鐧诲綍鎺ュ彛杩斿洖鍊� */
+  export interface LoginResult {
+    accessToken: string;
+  }
+
+  export interface RefreshTokenResult {
+    data: string;
+    status: number;
+  }
+}
+
+/**
+ * 鐧诲綍
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
+}
+
+/**
+ * 鍒锋柊accessToken
+ */
+export async function refreshTokenApi() {
+  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 閫�鍑虹櫥褰�
+ */
+export async function logoutApi() {
+  return baseRequestClient.post('/auth/logout', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 鑾峰彇鐢ㄦ埛鏉冮檺鐮�
+ */
+export async function getAccessCodesApi() {
+  return requestClient.get<string[]>('/auth/codes');
+}
diff --git a/eims-ui/apps/web-naive/src/api/core/index.ts b/eims-ui/apps/web-naive/src/api/core/index.ts
new file mode 100644
index 0000000..28a5aef
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/core/index.ts
@@ -0,0 +1,3 @@
+export * from './auth';
+export * from './menu';
+export * from './user';
diff --git a/eims-ui/apps/web-naive/src/api/core/menu.ts b/eims-ui/apps/web-naive/src/api/core/menu.ts
new file mode 100644
index 0000000..9ef60b1
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/core/menu.ts
@@ -0,0 +1,10 @@
+import type { RouteRecordStringComponent } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛鎵�鏈夎彍鍗�
+ */
+export async function getAllMenusApi() {
+  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
+}
diff --git a/eims-ui/apps/web-naive/src/api/core/user.ts b/eims-ui/apps/web-naive/src/api/core/user.ts
new file mode 100644
index 0000000..7e28ea8
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/core/user.ts
@@ -0,0 +1,10 @@
+import type { UserInfo } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛淇℃伅
+ */
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
diff --git a/eims-ui/apps/web-naive/src/api/index.ts b/eims-ui/apps/web-naive/src/api/index.ts
new file mode 100644
index 0000000..4b0e041
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/index.ts
@@ -0,0 +1 @@
+export * from './core';
diff --git a/eims-ui/apps/web-naive/src/api/request.ts b/eims-ui/apps/web-naive/src/api/request.ts
new file mode 100644
index 0000000..72056e1
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/api/request.ts
@@ -0,0 +1,112 @@
+/**
+ * 璇ユ枃浠跺彲鑷鏍规嵁涓氬姟閫昏緫杩涜璋冩暣
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from '#/adapter/naive';
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    baseURL,
+  });
+
+  /**
+   * 閲嶆柊璁よ瘉閫昏緫
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (
+      preferences.app.loginExpiredMode === 'modal' &&
+      accessStore.isAccessChecked
+    ) {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * 鍒锋柊token閫昏緫
+   */
+  async function doRefreshToken() {
+    const accessStore = useAccessStore();
+    const resp = await refreshTokenApi();
+    const newToken = resp.data;
+    accessStore.setAccessToken(newToken);
+    return newToken;
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  // 璇锋眰澶村鐞�
+  client.addRequestInterceptor({
+    fulfilled: async (config) => {
+      const accessStore = useAccessStore();
+
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      config.headers['Accept-Language'] = preferences.app.locale;
+      return config;
+    },
+  });
+
+  // response鏁版嵁瑙f瀯
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const { data: responseData, status } = response;
+
+      const { code, data } = responseData;
+      if (status >= 200 && status < 400 && code === 0) {
+        return data;
+      }
+      throw Object.assign({}, response, { response });
+    },
+  });
+
+  // token杩囨湡鐨勫鐞�
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  // 閫氱敤鐨勯敊璇鐞�,濡傛灉娌℃湁杩涘叆涓婇潰鐨勯敊璇鐞嗛�昏緫锛屽氨浼氳繘鍏ヨ繖閲�
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string, error) => {
+      // 杩欓噷鍙互鏍规嵁涓氬姟杩涜瀹氬埗,浣犲彲浠ユ嬁鍒� error 鍐呯殑淇℃伅杩涜瀹氬埗鍖栧鐞嗭紝鏍规嵁涓嶅悓鐨� code 鍋氫笉鍚岀殑鎻愮ず锛岃�屼笉鏄洿鎺ヤ娇鐢� message.error 鎻愮ず msg
+      // 褰撳墠mock鎺ュ彛杩斿洖鐨勯敊璇瓧娈垫槸 error 鎴栬�� message
+      const responseData = error?.response?.data ?? {};
+      const errorMessage = responseData?.error ?? responseData?.message ?? '';
+      // 濡傛灉娌℃湁閿欒淇℃伅锛屽垯浼氭牴鎹姸鎬佺爜杩涜鎻愮ず
+      message.error(errorMessage || msg);
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
diff --git a/eims-ui/apps/web-naive/src/app.vue b/eims-ui/apps/web-naive/src/app.vue
new file mode 100644
index 0000000..23983c5
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/app.vue
@@ -0,0 +1,56 @@
+<script lang="ts" setup>
+import type { GlobalThemeOverrides } from 'naive-ui';
+
+import { computed } from 'vue';
+
+import { useNaiveDesignTokens } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+
+import {
+  darkTheme,
+  dateEnUS,
+  dateZhCN,
+  enUS,
+  lightTheme,
+  NConfigProvider,
+  NMessageProvider,
+  NNotificationProvider,
+  zhCN,
+} from 'naive-ui';
+
+defineOptions({ name: 'App' });
+
+const { commonTokens } = useNaiveDesignTokens();
+
+const tokenLocale = computed(() =>
+  preferences.app.locale === 'zh-CN' ? zhCN : enUS,
+);
+const tokenDateLocale = computed(() =>
+  preferences.app.locale === 'zh-CN' ? dateZhCN : dateEnUS,
+);
+const tokenTheme = computed(() =>
+  preferences.theme.mode === 'dark' ? darkTheme : lightTheme,
+);
+
+const themeOverrides = computed((): GlobalThemeOverrides => {
+  return {
+    common: commonTokens,
+  };
+});
+</script>
+
+<template>
+  <NConfigProvider
+    :date-locale="tokenDateLocale"
+    :locale="tokenLocale"
+    :theme="tokenTheme"
+    :theme-overrides="themeOverrides"
+    class="h-full"
+  >
+    <NNotificationProvider>
+      <NMessageProvider>
+        <RouterView />
+      </NMessageProvider>
+    </NNotificationProvider>
+  </NConfigProvider>
+</template>
diff --git a/eims-ui/apps/web-naive/src/bootstrap.ts b/eims-ui/apps/web-naive/src/bootstrap.ts
new file mode 100644
index 0000000..fc7f961
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/bootstrap.ts
@@ -0,0 +1,46 @@
+import { createApp, watchEffect } from 'vue';
+
+import { registerAccessDirective } from '@vben/access';
+import { preferences } from '@vben/preferences';
+import { initStores } from '@vben/stores';
+import '@vben/styles';
+
+import { useTitle } from '@vueuse/core';
+
+import { $t, setupI18n } from '#/locales';
+
+import { initComponentAdapter } from './adapter/component';
+import App from './app.vue';
+import { router } from './router';
+
+async function bootstrap(namespace: string) {
+  // 鍒濆鍖栫粍浠堕�傞厤鍣�
+  initComponentAdapter();
+  const app = createApp(App);
+
+  // 鍥介檯鍖� i18n 閰嶇疆
+  await setupI18n(app);
+
+  // 閰嶇疆 pinia-tore
+  await initStores(app, { namespace });
+
+  // 瀹夎鏉冮檺鎸囦护
+  registerAccessDirective(app);
+
+  // 閰嶇疆璺敱鍙婅矾鐢卞畧鍗�
+  app.use(router);
+
+  // 鍔ㄦ�佹洿鏂版爣棰�
+  watchEffect(() => {
+    if (preferences.app.dynamicTitle) {
+      const routeTitle = router.currentRoute.value.meta?.title;
+      const pageTitle =
+        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
+      useTitle(pageTitle);
+    }
+  });
+
+  app.mount('#app');
+}
+
+export { bootstrap };
diff --git a/eims-ui/apps/web-naive/src/layouts/auth.vue b/eims-ui/apps/web-naive/src/layouts/auth.vue
new file mode 100644
index 0000000..18d415b
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/layouts/auth.vue
@@ -0,0 +1,23 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { AuthPageLayout } from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+
+import { $t } from '#/locales';
+
+const appName = computed(() => preferences.app.name);
+const logo = computed(() => preferences.logo.source);
+</script>
+
+<template>
+  <AuthPageLayout
+    :app-name="appName"
+    :logo="logo"
+    :page-description="$t('authentication.pageDesc')"
+    :page-title="$t('authentication.pageTitle')"
+  >
+    <!-- 鑷畾涔夊伐鍏锋爮 -->
+    <!-- <template #toolbar></template> -->
+  </AuthPageLayout>
+</template>
diff --git a/eims-ui/apps/web-naive/src/layouts/basic.vue b/eims-ui/apps/web-naive/src/layouts/basic.vue
new file mode 100644
index 0000000..f75b3dd
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/layouts/basic.vue
@@ -0,0 +1,158 @@
+<script lang="ts" setup>
+import type { NotificationItem } from '@vben/layouts';
+
+import { computed, ref, watch } from 'vue';
+
+import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
+import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
+import { useWatermark } from '@vben/hooks';
+import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
+import {
+  BasicLayout,
+  LockScreen,
+  Notification,
+  UserDropdown,
+} from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import { $t } from '#/locales';
+import { useAuthStore } from '#/store';
+import LoginForm from '#/views/_core/authentication/login.vue';
+
+const notifications = ref<NotificationItem[]>([
+  {
+    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
+    date: '3灏忔椂鍓�',
+    isRead: true,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏀跺埌浜� 14 浠芥柊鍛ㄦ姤',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '鍒氬垰',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏈卞亸鍙� 鍥炲浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '2024-01-01',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏇蹭附涓� 璇勮浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1澶╁墠',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '浠e姙鎻愰啋',
+  },
+]);
+
+const userStore = useUserStore();
+const authStore = useAuthStore();
+const accessStore = useAccessStore();
+const { destroyWatermark, updateWatermark } = useWatermark();
+const showDot = computed(() =>
+  notifications.value.some((item) => !item.isRead),
+);
+
+const menus = computed(() => [
+  {
+    handler: () => {
+      openWindow(VBEN_DOC_URL, {
+        target: '_blank',
+      });
+    },
+    icon: BookOpenText,
+    text: $t('ui.widgets.document'),
+  },
+  {
+    handler: () => {
+      openWindow(VBEN_GITHUB_URL, {
+        target: '_blank',
+      });
+    },
+    icon: MdiGithub,
+    text: 'GitHub',
+  },
+  {
+    handler: () => {
+      openWindow(`${VBEN_GITHUB_URL}/issues`, {
+        target: '_blank',
+      });
+    },
+    icon: CircleHelp,
+    text: $t('ui.widgets.qa'),
+  },
+]);
+
+const avatar = computed(() => {
+  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
+});
+
+async function handleLogout() {
+  await authStore.logout(false);
+}
+
+function handleNoticeClear() {
+  notifications.value = [];
+}
+
+function handleMakeAll() {
+  notifications.value.forEach((item) => (item.isRead = true));
+}
+
+watch(
+  () => preferences.app.watermark,
+  async (enable) => {
+    if (enable) {
+      await updateWatermark({
+        content: `${userStore.userInfo?.username}`,
+      });
+    } else {
+      destroyWatermark();
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+</script>
+
+<template>
+  <BasicLayout @clear-preferences-and-logout="handleLogout">
+    <template #user-dropdown>
+      <UserDropdown
+        :avatar
+        :menus
+        :text="userStore.userInfo?.realName"
+        description="ann.vben@gmail.com"
+        tag-text="Pro"
+        @logout="handleLogout"
+      />
+    </template>
+    <template #notification>
+      <Notification
+        :dot="showDot"
+        :notifications="notifications"
+        @clear="handleNoticeClear"
+        @make-all="handleMakeAll"
+      />
+    </template>
+    <template #extra>
+      <AuthenticationLoginExpiredModal
+        v-model:open="accessStore.loginExpired"
+        :avatar
+      >
+        <LoginForm />
+      </AuthenticationLoginExpiredModal>
+    </template>
+    <template #lock-screen>
+      <LockScreen :avatar @to-login="handleLogout" />
+    </template>
+  </BasicLayout>
+</template>
diff --git a/eims-ui/apps/web-naive/src/layouts/index.ts b/eims-ui/apps/web-naive/src/layouts/index.ts
new file mode 100644
index 0000000..a432078
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/layouts/index.ts
@@ -0,0 +1,6 @@
+const BasicLayout = () => import('./basic.vue');
+const AuthPageLayout = () => import('./auth.vue');
+
+const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
+
+export { AuthPageLayout, BasicLayout, IFrameView };
diff --git a/eims-ui/apps/web-naive/src/locales/README.md b/eims-ui/apps/web-naive/src/locales/README.md
new file mode 100644
index 0000000..7b45103
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/README.md
@@ -0,0 +1,3 @@
+# locale
+
+姣忎釜app浣跨敤鐨勫浗闄呭寲鍙兘涓嶅悓锛岃繖閲岀敤浜庢墿灞曞浗闄呭寲鐨勫姛鑳斤紝渚嬪鎵╁睍 dayjs銆乤ntd缁勪欢搴撶殑澶氳瑷�鍒囨崲锛屼互鍙奱pp鏈韩鐨勫浗闄呭寲鏂囦欢銆�
diff --git a/eims-ui/apps/web-naive/src/locales/index.ts b/eims-ui/apps/web-naive/src/locales/index.ts
new file mode 100644
index 0000000..3d77913
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/index.ts
@@ -0,0 +1,38 @@
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+
+import type { App } from 'vue';
+
+import {
+  $t,
+  setupI18n as coreSetup,
+  loadLocalesMapFromDir,
+} from '@vben/locales';
+import { preferences } from '@vben/preferences';
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
+
+/**
+ * 鍔犺浇搴旂敤鐗规湁鐨勮瑷�鍖�
+ * 杩欓噷涔熷彲浠ユ敼閫犱负浠庢湇鍔$鑾峰彇缈昏瘧鏁版嵁
+ * @param lang
+ */
+async function loadMessages(lang: SupportedLanguagesType) {
+  const appLocaleMessages = await localesMap[lang]?.();
+  return appLocaleMessages?.default;
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+  await coreSetup(app, {
+    defaultLocale: preferences.app.locale,
+    loadMessages,
+    missingWarn: !import.meta.env.PROD,
+    ...options,
+  });
+}
+
+export { $t, setupI18n };
diff --git a/eims-ui/apps/web-naive/src/locales/langs/en-US/demos.json b/eims-ui/apps/web-naive/src/locales/langs/en-US/demos.json
new file mode 100644
index 0000000..839fc2e
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/langs/en-US/demos.json
@@ -0,0 +1,14 @@
+{
+  "title": "Demos",
+  "naive": "Naive UI",
+  "table": "Table",
+  "form": "Form",
+  "vben": {
+    "title": "Project",
+    "about": "About",
+    "document": "Document",
+    "antdv": "Ant Design Vue Version",
+    "naive-ui": "Naive UI Version",
+    "element-plus": "Element Plus Version"
+  }
+}
diff --git a/eims-ui/apps/web-naive/src/locales/langs/en-US/page.json b/eims-ui/apps/web-naive/src/locales/langs/en-US/page.json
new file mode 100644
index 0000000..f021341
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/langs/en-US/page.json
@@ -0,0 +1,15 @@
+{
+  "auth": {
+    "login": "Login",
+    "register": "Register",
+    "codeLogin": "Code Login",
+    "qrcodeLogin": "Qr Code Login",
+    "forgetPassword": "Forget Password",
+    "oauthLogin": "OAuth Login"
+  },
+  "dashboard": {
+    "title": "Dashboard",
+    "analytics": "Analytics",
+    "workspace": "Workspace"
+  }
+}
diff --git a/eims-ui/apps/web-naive/src/locales/langs/zh-CN/demos.json b/eims-ui/apps/web-naive/src/locales/langs/zh-CN/demos.json
new file mode 100644
index 0000000..e0d7e61
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/langs/zh-CN/demos.json
@@ -0,0 +1,14 @@
+{
+  "title": "婕旂ず",
+  "naive": "Naive UI",
+  "table": "Table",
+  "form": "琛ㄥ崟",
+  "vben": {
+    "title": "椤圭洰",
+    "about": "鍏充簬",
+    "document": "鏂囨。",
+    "antdv": "Ant Design Vue 鐗堟湰",
+    "naive-ui": "Naive UI 鐗堟湰",
+    "element-plus": "Element Plus 鐗堟湰"
+  }
+}
diff --git a/eims-ui/apps/web-naive/src/locales/langs/zh-CN/page.json b/eims-ui/apps/web-naive/src/locales/langs/zh-CN/page.json
new file mode 100644
index 0000000..6fa681e
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/locales/langs/zh-CN/page.json
@@ -0,0 +1,15 @@
+{
+  "auth": {
+    "login": "鐧诲綍",
+    "register": "娉ㄥ唽",
+    "codeLogin": "楠岃瘉鐮佺櫥闄�",
+    "qrcodeLogin": "浜岀淮鐮佺櫥闄�",
+    "forgetPassword": "蹇樿瀵嗙爜",
+    "oauthLogin": "绗笁鏂圭櫥褰�"
+  },
+  "dashboard": {
+    "title": "姒傝",
+    "analytics": "鍒嗘瀽椤�",
+    "workspace": "宸ヤ綔鍙�"
+  }
+}
diff --git a/eims-ui/apps/web-naive/src/main.ts b/eims-ui/apps/web-naive/src/main.ts
new file mode 100644
index 0000000..5d728a0
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/main.ts
@@ -0,0 +1,31 @@
+import { initPreferences } from '@vben/preferences';
+import { unmountGlobalLoading } from '@vben/utils';
+
+import { overridesPreferences } from './preferences';
+
+/**
+ * 搴旂敤鍒濆鍖栧畬鎴愪箣鍚庡啀杩涜椤甸潰鍔犺浇娓叉煋
+ */
+async function initApplication() {
+  // name鐢ㄤ簬鎸囧畾椤圭洰鍞竴鏍囪瘑
+  // 鐢ㄤ簬鍖哄垎涓嶅悓椤圭洰鐨勫亸濂借缃互鍙婂瓨鍌ㄦ暟鎹殑key鍓嶇紑浠ュ強鍏朵粬涓�浜涢渶瑕侀殧绂荤殑鏁版嵁
+  const env = import.meta.env.PROD ? 'prod' : 'dev';
+  const appVersion = import.meta.env.VITE_APP_VERSION;
+  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
+
+  // app鍋忓ソ璁剧疆鍒濆鍖�
+  await initPreferences({
+    namespace,
+    overrides: overridesPreferences,
+  });
+
+  // 鍚姩搴旂敤骞舵寕杞�
+  // vue搴旂敤涓昏閫昏緫鍙婅鍥�
+  const { bootstrap } = await import('./bootstrap');
+  await bootstrap(namespace);
+
+  // 绉婚櫎骞堕攢姣乴oading
+  unmountGlobalLoading();
+}
+
+initApplication();
diff --git a/eims-ui/apps/web-naive/src/preferences.ts b/eims-ui/apps/web-naive/src/preferences.ts
new file mode 100644
index 0000000..b2e9ace
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/preferences.ts
@@ -0,0 +1,13 @@
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 椤圭洰閰嶇疆鏂囦欢
+ * 鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆
+ * !!! 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    name: import.meta.env.VITE_APP_TITLE,
+  },
+});
diff --git a/eims-ui/apps/web-naive/src/router/access.ts b/eims-ui/apps/web-naive/src/router/access.ts
new file mode 100644
index 0000000..7a80bac
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/access.ts
@@ -0,0 +1,40 @@
+import type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+} from '@vben/types';
+
+import { generateAccessible } from '@vben/access';
+import { preferences } from '@vben/preferences';
+
+import { message } from '#/adapter/naive';
+import { getAllMenusApi } from '#/api';
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
+
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
+
+  const layoutMap: ComponentRecordType = {
+    BasicLayout,
+    IFrameView,
+  };
+
+  return await generateAccessible(preferences.app.accessMode, {
+    ...options,
+    fetchMenuListAsync: async () => {
+      message.loading(`${$t('common.loadingMenu')}...`, {
+        duration: 1.5,
+      });
+      return await getAllMenusApi();
+    },
+    // 鍙互鎸囧畾娌℃湁鏉冮檺璺宠浆403椤甸潰
+    forbiddenComponent,
+    // 濡傛灉 route.meta.menuVisibleWithForbidden = true
+    layoutMap,
+    pageMap,
+  });
+}
+
+export { generateAccess };
diff --git a/eims-ui/apps/web-naive/src/router/guard.ts b/eims-ui/apps/web-naive/src/router/guard.ts
new file mode 100644
index 0000000..c95d994
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/guard.ts
@@ -0,0 +1,124 @@
+import type { Router } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { startProgress, stopProgress } from '@vben/utils';
+
+import { accessRoutes, coreRouteNames } from '#/router/routes';
+import { useAuthStore } from '#/store';
+
+import { generateAccess } from './access';
+
+/**
+ * 閫氱敤瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupCommonGuard(router: Router) {
+  // 璁板綍宸茬粡鍔犺浇鐨勯〉闈�
+  const loadedPaths = new Set<string>();
+
+  router.beforeEach(async (to) => {
+    to.meta.loaded = loadedPaths.has(to.path);
+
+    // 椤甸潰鍔犺浇杩涘害鏉�
+    if (!to.meta.loaded && preferences.transition.progress) {
+      startProgress();
+    }
+    return true;
+  });
+
+  router.afterEach((to) => {
+    // 璁板綍椤甸潰鏄惁鍔犺浇,濡傛灉宸茬粡鍔犺浇锛屽悗缁殑椤甸潰鍒囨崲鍔ㄧ敾绛夋晥鏋滀笉鍦ㄩ噸澶嶆墽琛�
+
+    loadedPaths.add(to.path);
+
+    // 鍏抽棴椤甸潰鍔犺浇杩涘害鏉�
+    if (preferences.transition.progress) {
+      stopProgress();
+    }
+  });
+}
+
+/**
+ * 鏉冮檺璁块棶瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupAccessGuard(router: Router) {
+  router.beforeEach(async (to, from) => {
+    const accessStore = useAccessStore();
+    const userStore = useUserStore();
+    const authStore = useAuthStore();
+
+    // 鍩烘湰璺敱锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴�
+    if (coreRouteNames.includes(to.name as string)) {
+      if (to.path === LOGIN_PATH && accessStore.accessToken) {
+        return decodeURIComponent(
+          (to.query?.redirect as string) || DEFAULT_HOME_PATH,
+        );
+      }
+      return true;
+    }
+
+    // accessToken 妫�鏌�
+    if (!accessStore.accessToken) {
+      // 鏄庣‘澹版槑蹇界暐鏉冮檺璁块棶鏉冮檺锛屽垯鍙互璁块棶
+      if (to.meta.ignoreAccess) {
+        return true;
+      }
+
+      // 娌℃湁璁块棶鏉冮檺锛岃烦杞櫥褰曢〉闈�
+      if (to.fullPath !== LOGIN_PATH) {
+        return {
+          path: LOGIN_PATH,
+          // 濡備笉闇�瑕侊紝鐩存帴鍒犻櫎 query
+          query: { redirect: encodeURIComponent(to.fullPath) },
+          // 鎼哄甫褰撳墠璺宠浆鐨勯〉闈紝鐧诲綍鍚庨噸鏂拌烦杞椤甸潰
+          replace: true,
+        };
+      }
+      return to;
+    }
+
+    // 鏄惁宸茬粡鐢熸垚杩囧姩鎬佽矾鐢�
+    if (accessStore.isAccessChecked) {
+      return true;
+    }
+    // 鐢熸垚璺敱琛�
+    // 褰撳墠鐧诲綍鐢ㄦ埛鎷ユ湁鐨勮鑹叉爣璇嗗垪琛�
+    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
+    const userRoles = userInfo.roles ?? [];
+
+    // 鐢熸垚鑿滃崟鍜岃矾鐢�
+    const { accessibleMenus, accessibleRoutes } = await generateAccess({
+      roles: userRoles,
+      router,
+      // 鍒欎細鍦ㄨ彍鍗曚腑鏄剧ず锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+      routes: accessRoutes,
+    });
+
+    // 淇濆瓨鑿滃崟淇℃伅鍜岃矾鐢变俊鎭�
+    accessStore.setAccessMenus(accessibleMenus);
+    accessStore.setAccessRoutes(accessibleRoutes);
+    accessStore.setIsAccessChecked(true);
+    const redirectPath = (from.query.redirect ?? to.fullPath) as string;
+
+    return {
+      ...router.resolve(decodeURIComponent(redirectPath)),
+      replace: true,
+    };
+  });
+}
+
+/**
+ * 椤圭洰瀹堝崼閰嶇疆
+ * @param router
+ */
+function createRouterGuard(router: Router) {
+  /** 閫氱敤 */
+  setupCommonGuard(router);
+  /** 鏉冮檺璁块棶 */
+  setupAccessGuard(router);
+}
+
+export { createRouterGuard };
diff --git a/eims-ui/apps/web-naive/src/router/index.ts b/eims-ui/apps/web-naive/src/router/index.ts
new file mode 100644
index 0000000..4840230
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/index.ts
@@ -0,0 +1,37 @@
+import {
+  createRouter,
+  createWebHashHistory,
+  createWebHistory,
+} from 'vue-router';
+
+import { resetStaticRoutes } from '@vben/utils';
+
+import { createRouterGuard } from './guard';
+import { routes } from './routes';
+
+/**
+ *  @zh_CN 鍒涘缓vue-router瀹炰緥
+ */
+const router = createRouter({
+  history:
+    import.meta.env.VITE_ROUTER_HISTORY === 'hash'
+      ? createWebHashHistory(import.meta.env.VITE_BASE)
+      : createWebHistory(import.meta.env.VITE_BASE),
+  // 搴旇娣诲姞鍒拌矾鐢辩殑鍒濆璺敱鍒楄〃銆�
+  routes,
+  scrollBehavior: (to, _from, savedPosition) => {
+    if (savedPosition) {
+      return savedPosition;
+    }
+    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
+  },
+  // 鏄惁搴旇绂佹灏鹃儴鏂滄潬銆�
+  // strict: true,
+});
+
+const resetRoutes = () => resetStaticRoutes(router, routes);
+
+// 鍒涘缓璺敱瀹堝崼
+createRouterGuard(router);
+
+export { resetRoutes, router };
diff --git a/eims-ui/apps/web-naive/src/router/routes/core.ts b/eims-ui/apps/web-naive/src/router/routes/core.ts
new file mode 100644
index 0000000..fe030a9
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/routes/core.ts
@@ -0,0 +1,88 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+
+import { AuthPageLayout } from '#/layouts';
+import { $t } from '#/locales';
+import Login from '#/views/_core/authentication/login.vue';
+
+/** 鍏ㄥ眬404椤甸潰 */
+const fallbackNotFoundRoute: RouteRecordRaw = {
+  component: () => import('#/views/_core/fallback/not-found.vue'),
+  meta: {
+    hideInBreadcrumb: true,
+    hideInMenu: true,
+    hideInTab: true,
+    title: '404',
+  },
+  name: 'FallbackNotFound',
+  path: '/:path(.*)*',
+};
+
+/** 鍩烘湰璺敱锛岃繖浜涜矾鐢辨槸蹇呴』瀛樺湪鐨� */
+const coreRoutes: RouteRecordRaw[] = [
+  {
+    meta: {
+      title: 'Root',
+    },
+    name: 'Root',
+    path: '/',
+    redirect: DEFAULT_HOME_PATH,
+  },
+  {
+    component: AuthPageLayout,
+    meta: {
+      hideInTab: true,
+      title: 'Authentication',
+    },
+    name: 'Authentication',
+    path: '/auth',
+    redirect: LOGIN_PATH,
+    children: [
+      {
+        name: 'Login',
+        path: 'login',
+        component: Login,
+        meta: {
+          title: $t('page.auth.login'),
+        },
+      },
+      {
+        name: 'CodeLogin',
+        path: 'code-login',
+        component: () => import('#/views/_core/authentication/code-login.vue'),
+        meta: {
+          title: $t('page.auth.codeLogin'),
+        },
+      },
+      {
+        name: 'QrCodeLogin',
+        path: 'qrcode-login',
+        component: () =>
+          import('#/views/_core/authentication/qrcode-login.vue'),
+        meta: {
+          title: $t('page.auth.qrcodeLogin'),
+        },
+      },
+      {
+        name: 'ForgetPassword',
+        path: 'forget-password',
+        component: () =>
+          import('#/views/_core/authentication/forget-password.vue'),
+        meta: {
+          title: $t('page.auth.forgetPassword'),
+        },
+      },
+      {
+        name: 'Register',
+        path: 'register',
+        component: () => import('#/views/_core/authentication/register.vue'),
+        meta: {
+          title: $t('page.auth.register'),
+        },
+      },
+    ],
+  },
+];
+
+export { coreRoutes, fallbackNotFoundRoute };
diff --git a/eims-ui/apps/web-naive/src/router/routes/index.ts b/eims-ui/apps/web-naive/src/router/routes/index.ts
new file mode 100644
index 0000000..e6fb144
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/routes/index.ts
@@ -0,0 +1,37 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
+
+import { coreRoutes, fallbackNotFoundRoute } from './core';
+
+const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
+  eager: true,
+});
+
+// 鏈夐渶瑕佸彲浠ヨ嚜琛屾墦寮�娉ㄩ噴锛屽苟鍒涘缓鏂囦欢澶�
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
+// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
+
+/** 鍔ㄦ�佽矾鐢� */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 澶栭儴璺敱鍒楄〃锛岃闂繖浜涢〉闈㈠彲浠ヤ笉闇�瑕丩ayout锛屽彲鑳界敤浜庡唴宓屽湪鍒殑绯荤粺(涓嶄細鏄剧ず鍦ㄨ彍鍗曚腑) */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
+// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
+const staticRoutes: RouteRecordRaw[] = [];
+const externalRoutes: RouteRecordRaw[] = [];
+
+/** 璺敱鍒楄〃锛岀敱鍩烘湰璺敱銆佸閮ㄨ矾鐢卞拰404鍏滃簳璺敱缁勬垚
+ *  鏃犻渶璧版潈闄愰獙璇侊紙浼氫竴鐩存樉绀哄湪鑿滃崟涓級 */
+const routes: RouteRecordRaw[] = [
+  ...coreRoutes,
+  ...externalRoutes,
+  fallbackNotFoundRoute,
+];
+
+/** 鍩烘湰璺敱鍒楄〃锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴� */
+const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
+
+/** 鏈夋潈闄愭牎楠岀殑璺敱鍒楄〃锛屽寘鍚姩鎬佽矾鐢卞拰闈欐�佽矾鐢� */
+const accessRoutes = [...dynamicRoutes, ...staticRoutes];
+export { accessRoutes, coreRouteNames, routes };
diff --git a/eims-ui/apps/web-naive/src/router/routes/modules/dashboard.ts b/eims-ui/apps/web-naive/src/router/routes/modules/dashboard.ts
new file mode 100644
index 0000000..1bddab9
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/routes/modules/dashboard.ts
@@ -0,0 +1,40 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'lucide:layout-dashboard',
+      order: -1,
+      title: $t('page.dashboard.title'),
+    },
+    name: 'Dashboard',
+    path: '/',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: () => import('#/views/dashboard/analytics/index.vue'),
+        meta: {
+          affixTab: true,
+          icon: 'lucide:area-chart',
+          title: $t('page.dashboard.analytics'),
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: () => import('#/views/dashboard/workspace/index.vue'),
+        meta: {
+          icon: 'carbon:workspace',
+          title: $t('page.dashboard.workspace'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-naive/src/router/routes/modules/demos.ts b/eims-ui/apps/web-naive/src/router/routes/modules/demos.ts
new file mode 100644
index 0000000..d0631cb
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/routes/modules/demos.ts
@@ -0,0 +1,46 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    children: [
+      {
+        meta: {
+          title: $t('demos.naive'),
+        },
+        name: 'NaiveDemos',
+        path: '/demos/naive',
+        component: () => import('#/views/demos/naive/index.vue'),
+      },
+      {
+        meta: {
+          title: $t('demos.table'),
+        },
+        name: 'Table',
+        path: '/demos/table',
+        component: () => import('#/views/demos/table/index.vue'),
+      },
+      {
+        meta: {
+          title: $t('demos.form'),
+        },
+        name: 'Form',
+        path: '/demos/form',
+        component: () => import('#/views/demos/form/basic.vue'),
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-naive/src/router/routes/modules/vben.ts b/eims-ui/apps/web-naive/src/router/routes/modules/vben.ts
new file mode 100644
index 0000000..44461a7
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/router/routes/modules/vben.ts
@@ -0,0 +1,82 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import {
+  VBEN_ANT_PREVIEW_URL,
+  VBEN_DOC_URL,
+  VBEN_ELE_PREVIEW_URL,
+  VBEN_GITHUB_URL,
+  VBEN_LOGO_URL,
+} from '@vben/constants';
+import { SvgAntdvLogoIcon } from '@vben/icons';
+
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('demos.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          icon: 'lucide:copyright',
+          title: $t('demos.vben.about'),
+        },
+      },
+      {
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: IFrameView,
+        meta: {
+          icon: 'lucide:book-open-text',
+          link: VBEN_DOC_URL,
+          title: $t('demos.vben.document'),
+        },
+      },
+      {
+        name: 'VbenGithub',
+        path: '/vben-admin/github',
+        component: IFrameView,
+        meta: {
+          icon: 'mdi:github',
+          link: VBEN_GITHUB_URL,
+          title: 'Github',
+        },
+      },
+      {
+        name: 'VbenAntd',
+        path: '/vben-admin/antd',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: SvgAntdvLogoIcon,
+          link: VBEN_ANT_PREVIEW_URL,
+          title: $t('demos.vben.antdv'),
+        },
+      },
+      {
+        name: 'VbenElementPlus',
+        path: '/vben-admin/ele',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:element',
+          link: VBEN_ELE_PREVIEW_URL,
+          title: $t('demos.vben.element-plus'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/apps/web-naive/src/store/auth.ts b/eims-ui/apps/web-naive/src/store/auth.ts
new file mode 100644
index 0000000..20aac56
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/store/auth.ts
@@ -0,0 +1,116 @@
+import type { Recordable, UserInfo } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
+
+import { defineStore } from 'pinia';
+
+import { notification } from '#/adapter/naive';
+import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
+import { $t } from '#/locales';
+
+export const useAuthStore = defineStore('auth', () => {
+  const accessStore = useAccessStore();
+  const userStore = useUserStore();
+  const router = useRouter();
+
+  const loginLoading = ref(false);
+
+  /**
+   * 寮傛澶勭悊鐧诲綍鎿嶄綔
+   * Asynchronously handle the login process
+   * @param params 鐧诲綍琛ㄥ崟鏁版嵁
+   */
+  async function authLogin(
+    params: Recordable<any>,
+    onSuccess?: () => Promise<void> | void,
+  ) {
+    // 寮傛澶勭悊鐢ㄦ埛鐧诲綍鎿嶄綔骞惰幏鍙� accessToken
+    let userInfo: null | UserInfo = null;
+    try {
+      loginLoading.value = true;
+      const { accessToken } = await loginApi(params);
+
+      // 濡傛灉鎴愬姛鑾峰彇鍒� accessToken
+      if (accessToken) {
+        // 灏� accessToken 瀛樺偍鍒� accessStore 涓�
+        accessStore.setAccessToken(accessToken);
+
+        // 鑾峰彇鐢ㄦ埛淇℃伅骞跺瓨鍌ㄥ埌 accessStore 涓�
+        const [fetchUserInfoResult, accessCodes] = await Promise.all([
+          fetchUserInfo(),
+          getAccessCodesApi(),
+        ]);
+
+        userInfo = fetchUserInfoResult;
+
+        userStore.setUserInfo(userInfo);
+        accessStore.setAccessCodes(accessCodes);
+
+        if (accessStore.loginExpired) {
+          accessStore.setLoginExpired(false);
+        } else {
+          onSuccess
+            ? await onSuccess?.()
+            : await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
+        }
+
+        if (userInfo?.realName) {
+          notification.success({
+            content: $t('authentication.loginSuccess'),
+            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
+            duration: 3000,
+          });
+        }
+      }
+    } finally {
+      loginLoading.value = false;
+    }
+
+    return {
+      userInfo,
+    };
+  }
+
+  async function logout(redirect: boolean = true) {
+    try {
+      await logoutApi();
+    } catch {
+      // 涓嶅仛浠讳綍澶勭悊
+    }
+    resetAllStores();
+    accessStore.setLoginExpired(false);
+
+    // 鍥炵櫥褰曢〉甯︿笂褰撳墠璺敱鍦板潃
+    await router.replace({
+      path: LOGIN_PATH,
+      query: redirect
+        ? {
+            redirect: encodeURIComponent(router.currentRoute.value.fullPath),
+          }
+        : {},
+    });
+  }
+
+  async function fetchUserInfo() {
+    let userInfo: null | UserInfo = null;
+    userInfo = await getUserInfoApi();
+    userStore.setUserInfo(userInfo);
+    return userInfo;
+  }
+
+  function $reset() {
+    loginLoading.value = false;
+  }
+
+  return {
+    $reset,
+    authLogin,
+    fetchUserInfo,
+    loginLoading,
+    logout,
+  };
+});
diff --git a/eims-ui/apps/web-naive/src/store/index.ts b/eims-ui/apps/web-naive/src/store/index.ts
new file mode 100644
index 0000000..269586e
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/store/index.ts
@@ -0,0 +1 @@
+export * from './auth';
diff --git a/eims-ui/apps/web-naive/src/views/_core/README.md b/eims-ui/apps/web-naive/src/views/_core/README.md
new file mode 100644
index 0000000..8248afe
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/README.md
@@ -0,0 +1,3 @@
+# \_core
+
+姝ょ洰褰曞寘鍚簲鐢ㄧ▼搴忔甯歌繍琛屾墍闇�鐨勫熀鏈鍥俱�傝繖浜涜鍥炬槸搴旂敤绋嬪簭甯冨眬涓娇鐢ㄧ殑瑙嗗浘銆�
diff --git a/eims-ui/apps/web-naive/src/views/_core/about/index.vue b/eims-ui/apps/web-naive/src/views/_core/about/index.vue
new file mode 100644
index 0000000..0ee5243
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/about/index.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { About } from '@vben/common-ui';
+
+defineOptions({ name: 'About' });
+</script>
+
+<template>
+  <About />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/authentication/code-login.vue b/eims-ui/apps/web-naive/src/views/_core/authentication/code-login.vue
new file mode 100644
index 0000000..1fc15e1
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/authentication/code-login.vue
@@ -0,0 +1,64 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationCodeLogin, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'CodeLogin' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.mobile'),
+      },
+      fieldName: 'phoneNumber',
+      label: $t('authentication.mobile'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.mobileTip') })
+        .refine((v) => /^\d{11}$/.test(v), {
+          message: $t('authentication.mobileErrortip'),
+        }),
+    },
+    {
+      component: 'VbenPinInput',
+      componentProps: {
+        createText: (countdown: number) => {
+          const text =
+            countdown > 0
+              ? $t('authentication.sendText', [countdown])
+              : $t('authentication.sendCode');
+          return text;
+        },
+        placeholder: $t('authentication.code'),
+      },
+      fieldName: 'code',
+      label: $t('authentication.code'),
+      rules: z.string().min(1, { message: $t('authentication.codeTip') }),
+    },
+  ];
+});
+/**
+ * 寮傛澶勭悊鐧诲綍鎿嶄綔
+ * Asynchronously handle the login process
+ * @param values 鐧诲綍琛ㄥ崟鏁版嵁
+ */
+async function handleLogin(values: Recordable<any>) {
+  console.log(values);
+}
+</script>
+
+<template>
+  <AuthenticationCodeLogin
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleLogin"
+  />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/authentication/forget-password.vue b/eims-ui/apps/web-naive/src/views/_core/authentication/forget-password.vue
new file mode 100644
index 0000000..0958e89
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/authentication/forget-password.vue
@@ -0,0 +1,42 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationForgetPassword, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'ForgetPassword' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: 'example@example.com',
+      },
+      fieldName: 'email',
+      label: $t('authentication.email'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.emailTip') })
+        .email($t('authentication.emailValidErrorTip')),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('reset email:', value);
+}
+</script>
+
+<template>
+  <AuthenticationForgetPassword
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/authentication/login.vue b/eims-ui/apps/web-naive/src/views/_core/authentication/login.vue
new file mode 100644
index 0000000..099e4c8
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/authentication/login.vue
@@ -0,0 +1,98 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { BasicOption } from '@vben/types';
+
+import { computed, markRaw } from 'vue';
+
+import { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { useAuthStore } from '#/store';
+
+defineOptions({ name: 'Login' });
+
+const authStore = useAuthStore();
+
+const MOCK_USER_OPTIONS: BasicOption[] = [
+  {
+    label: 'Super',
+    value: 'vben',
+  },
+  {
+    label: 'Admin',
+    value: 'admin',
+  },
+  {
+    label: 'User',
+    value: 'jack',
+  },
+];
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenSelect',
+      componentProps: {
+        options: MOCK_USER_OPTIONS,
+        placeholder: $t('authentication.selectAccount'),
+      },
+      fieldName: 'selectAccount',
+      label: $t('authentication.selectAccount'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.selectAccount') })
+        .optional()
+        .default('vben'),
+    },
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      dependencies: {
+        trigger(values, form) {
+          if (values.selectAccount) {
+            const findUser = MOCK_USER_OPTIONS.find(
+              (item) => item.value === values.selectAccount,
+            );
+            if (findUser) {
+              form.setValues({
+                password: '123456',
+                username: findUser.value,
+              });
+            }
+          }
+        },
+        triggerFields: ['selectAccount'],
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: markRaw(SliderCaptcha),
+      fieldName: 'captcha',
+      rules: z.boolean().refine((value) => value, {
+        message: $t('authentication.verifyRequiredTip'),
+      }),
+    },
+  ];
+});
+</script>
+
+<template>
+  <AuthenticationLogin
+    :form-schema="formSchema"
+    :loading="authStore.loginLoading"
+    @submit="authStore.authLogin"
+  />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/authentication/qrcode-login.vue b/eims-ui/apps/web-naive/src/views/_core/authentication/qrcode-login.vue
new file mode 100644
index 0000000..23f5f2d
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/authentication/qrcode-login.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+import { AuthenticationQrCodeLogin } from '@vben/common-ui';
+import { LOGIN_PATH } from '@vben/constants';
+
+defineOptions({ name: 'QrCodeLogin' });
+</script>
+
+<template>
+  <AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/authentication/register.vue b/eims-ui/apps/web-naive/src/views/_core/authentication/register.vue
new file mode 100644
index 0000000..e68a88f
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/authentication/register.vue
@@ -0,0 +1,95 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, h, ref } from 'vue';
+
+import { AuthenticationRegister, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'Register' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        passwordStrength: true,
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      renderComponentContent() {
+        return {
+          strengthText: () => $t('authentication.passwordStrength'),
+        };
+      },
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.confirmPassword'),
+      },
+      dependencies: {
+        rules(values) {
+          const { password } = values;
+          return z
+            .string({ required_error: $t('authentication.passwordTip') })
+            .min(1, { message: $t('authentication.passwordTip') })
+            .refine((value) => value === password, {
+              message: $t('authentication.confirmPasswordTip'),
+            });
+        },
+        triggerFields: ['password'],
+      },
+      fieldName: 'confirmPassword',
+      label: $t('authentication.confirmPassword'),
+    },
+    {
+      component: 'VbenCheckbox',
+      fieldName: 'agreePolicy',
+      renderComponentContent: () => ({
+        default: () =>
+          h('span', [
+            $t('authentication.agree'),
+            h(
+              'a',
+              {
+                class: 'vben-link ml-1',
+                href: '',
+              },
+              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,
+            ),
+          ]),
+      }),
+      rules: z.boolean().refine((value) => !!value, {
+        message: $t('authentication.agreeTip'),
+      }),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  console.log('register submit:', value);
+}
+</script>
+
+<template>
+  <AuthenticationRegister
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/fallback/coming-soon.vue b/eims-ui/apps/web-naive/src/views/_core/fallback/coming-soon.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/fallback/coming-soon.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/fallback/forbidden.vue b/eims-ui/apps/web-naive/src/views/_core/fallback/forbidden.vue
new file mode 100644
index 0000000..8ea65fe
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/fallback/forbidden.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback403Demo' });
+</script>
+
+<template>
+  <Fallback status="403" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/fallback/internal-error.vue b/eims-ui/apps/web-naive/src/views/_core/fallback/internal-error.vue
new file mode 100644
index 0000000..819a47d
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/fallback/internal-error.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback500Demo' });
+</script>
+
+<template>
+  <Fallback status="500" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/fallback/not-found.vue b/eims-ui/apps/web-naive/src/views/_core/fallback/not-found.vue
new file mode 100644
index 0000000..4d178e9
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/fallback/not-found.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback404Demo' });
+</script>
+
+<template>
+  <Fallback status="404" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/_core/fallback/offline.vue b/eims-ui/apps/web-naive/src/views/_core/fallback/offline.vue
new file mode 100644
index 0000000..5de4a88
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/_core/fallback/offline.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'FallbackOfflineDemo' });
+</script>
+
+<template>
+  <Fallback status="offline" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue
new file mode 100644
index 0000000..fadfc91
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-trends.vue
@@ -0,0 +1,100 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        areaStyle: {},
+        data: [
+          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,
+          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,
+          111,
+        ],
+        itemStyle: {
+          color: '#5ab1ef',
+        },
+        smooth: true,
+        type: 'line',
+      },
+      {
+        areaStyle: {},
+        data: [
+          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,
+          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,
+        ],
+        itemStyle: {
+          color: '#019680',
+        },
+        smooth: true,
+        type: 'line',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          color: '#019680',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    // xAxis: {
+    //   axisTick: {
+    //     show: false,
+    //   },
+    //   boundaryGap: false,
+    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+    //   type: 'category',
+    // },
+    xAxis: {
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: false,
+      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+      splitLine: {
+        lineStyle: {
+          type: 'solid',
+          width: 1,
+        },
+        show: true,
+      },
+      type: 'category',
+    },
+    yAxis: [
+      {
+        axisTick: {
+          show: false,
+        },
+        max: 80_000,
+        splitArea: {
+          show: true,
+        },
+        splitNumber: 4,
+        type: 'value',
+      },
+    ],
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue
new file mode 100644
index 0000000..30c4265
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-data.vue
@@ -0,0 +1,84 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: 0,
+      data: ['璁块棶', '瓒嬪娍'],
+    },
+    radar: {
+      indicator: [
+        {
+          name: '缃戦〉',
+        },
+        {
+          name: '绉诲姩绔�',
+        },
+        {
+          name: 'Ipad',
+        },
+        {
+          name: '瀹㈡埛绔�',
+        },
+        {
+          name: '绗笁鏂�',
+        },
+        {
+          name: '鍏跺畠',
+        },
+      ],
+      radius: '60%',
+      splitNumber: 8,
+    },
+    series: [
+      {
+        areaStyle: {
+          opacity: 1,
+          shadowBlur: 0,
+          shadowColor: 'rgba(0,0,0,.2)',
+          shadowOffsetX: 0,
+          shadowOffsetY: 10,
+        },
+        data: [
+          {
+            itemStyle: {
+              color: '#b6a2de',
+            },
+            name: '璁块棶',
+            value: [90, 50, 86, 40, 50, 20],
+          },
+          {
+            itemStyle: {
+              color: '#5ab1ef',
+            },
+            name: '瓒嬪娍',
+            value: [70, 75, 70, 76, 20, 85],
+          },
+        ],
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        symbolSize: 0,
+        type: 'radar',
+      },
+    ],
+    tooltip: {},
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue
new file mode 100644
index 0000000..260520b
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-sales.vue
@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 400;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        center: ['50%', '50%'],
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '澶栧寘', value: 500 },
+          { name: '瀹氬埗', value: 310 },
+          { name: '鎶�鏈敮鎸�', value: 274 },
+          { name: '杩滅▼', value: 400 },
+        ].sort((a, b) => {
+          return a.value - b.value;
+        }),
+        name: '鍟嗕笟鍗犳瘮',
+        radius: '80%',
+        roseType: 'radius',
+        type: 'pie',
+      },
+    ],
+
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue
new file mode 100644
index 0000000..e0d0aab
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits-source.vue
@@ -0,0 +1,67 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: '2%',
+      left: 'center',
+    },
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 100;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        avoidLabelOverlap: false,
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '鎼滅储寮曟搸', value: 1048 },
+          { name: '鐩存帴璁块棶', value: 735 },
+          { name: '閭欢钀ラ攢', value: 580 },
+          { name: '鑱旂洘骞垮憡', value: 484 },
+        ],
+        emphasis: {
+          label: {
+            fontSize: '12',
+            fontWeight: 'bold',
+            show: true,
+          },
+        },
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        label: {
+          position: 'center',
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        name: '璁块棶鏉ユ簮',
+        radius: ['40%', '65%'],
+        type: 'pie',
+      },
+    ],
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue
new file mode 100644
index 0000000..7e1f14e
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/analytics-visits.vue
@@ -0,0 +1,57 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        barMaxWidth: 80,
+        // color: '#4f69fd',
+        data: [
+          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,
+          3200, 4800,
+        ],
+        type: 'bar',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          // color: '#4f69fd',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    xAxis: {
+      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}鏈坄),
+      type: 'category',
+    },
+    yAxis: {
+      max: 8000,
+      splitNumber: 4,
+      type: 'value',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/analytics/index.vue b/eims-ui/apps/web-naive/src/views/dashboard/analytics/index.vue
new file mode 100644
index 0000000..00b34df
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/analytics/index.vue
@@ -0,0 +1,90 @@
+<script lang="ts" setup>
+import type { AnalysisOverviewItem } from '@vben/common-ui';
+import type { TabOption } from '@vben/types';
+
+import {
+  AnalysisChartCard,
+  AnalysisChartsTabs,
+  AnalysisOverview,
+} from '@vben/common-ui';
+import {
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+} from '@vben/icons';
+
+import AnalyticsTrends from './analytics-trends.vue';
+import AnalyticsVisits from './analytics-visits.vue';
+import AnalyticsVisitsData from './analytics-visits-data.vue';
+import AnalyticsVisitsSales from './analytics-visits-sales.vue';
+import AnalyticsVisitsSource from './analytics-visits-source.vue';
+
+const overviewItems: AnalysisOverviewItem[] = [
+  {
+    icon: SvgCardIcon,
+    title: '鐢ㄦ埛閲�',
+    totalTitle: '鎬荤敤鎴烽噺',
+    totalValue: 120_000,
+    value: 2000,
+  },
+  {
+    icon: SvgCakeIcon,
+    title: '璁块棶閲�',
+    totalTitle: '鎬昏闂噺',
+    totalValue: 500_000,
+    value: 20_000,
+  },
+  {
+    icon: SvgDownloadIcon,
+    title: '涓嬭浇閲�',
+    totalTitle: '鎬讳笅杞介噺',
+    totalValue: 120_000,
+    value: 8000,
+  },
+  {
+    icon: SvgBellIcon,
+    title: '浣跨敤閲�',
+    totalTitle: '鎬讳娇鐢ㄩ噺',
+    totalValue: 50_000,
+    value: 5000,
+  },
+];
+
+const chartTabs: TabOption[] = [
+  {
+    label: '娴侀噺瓒嬪娍',
+    value: 'trends',
+  },
+  {
+    label: '鏈堣闂噺',
+    value: 'visits',
+  },
+];
+</script>
+
+<template>
+  <div class="p-5">
+    <AnalysisOverview :items="overviewItems" />
+    <AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
+      <template #trends>
+        <AnalyticsTrends />
+      </template>
+      <template #visits>
+        <AnalyticsVisits />
+      </template>
+    </AnalysisChartsTabs>
+
+    <div class="mt-5 w-full md:flex">
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏁伴噺">
+        <AnalyticsVisitsData />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSource />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSales />
+      </AnalysisChartCard>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/dashboard/workspace/index.vue b/eims-ui/apps/web-naive/src/views/dashboard/workspace/index.vue
new file mode 100644
index 0000000..b95d613
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/dashboard/workspace/index.vue
@@ -0,0 +1,266 @@
+<script lang="ts" setup>
+import type {
+  WorkbenchProjectItem,
+  WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
+} from '@vben/common-ui';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import {
+  AnalysisChartCard,
+  WorkbenchHeader,
+  WorkbenchProject,
+  WorkbenchQuickNav,
+  WorkbenchTodo,
+  WorkbenchTrends,
+} from '@vben/common-ui';
+import { preferences } from '@vben/preferences';
+import { useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';
+
+const userStore = useUserStore();
+
+// 杩欐槸涓�涓ず渚嬫暟鎹紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// url 涔熷彲浠ユ槸鍐呴儴璺敱锛屽湪 navTo 鏂规硶涓瘑鍒鐞嗭紝杩涜鍐呴儴璺宠浆
+// 渚嬪锛歶rl: /dashboard/workspace
+const projectItems: WorkbenchProjectItem[] = [
+  {
+    color: '',
+    content: '涓嶈绛夊緟鏈轰細锛岃�岃鍒涢�犳満浼氥��',
+    date: '2021-04-01',
+    group: '寮�婧愮粍',
+    icon: 'carbon:logo-github',
+    title: 'Github',
+    url: 'https://github.com',
+  },
+  {
+    color: '#3fb27f',
+    content: '鐜板湪鐨勪綘鍐冲畾灏嗘潵鐨勪綘銆�',
+    date: '2021-04-01',
+    group: '绠楁硶缁�',
+    icon: 'ion:logo-vue',
+    title: 'Vue',
+    url: 'https://vuejs.org',
+  },
+  {
+    color: '#e18525',
+    content: '娌℃湁浠�涔堟墠鑳芥瘮鍔姏鏇撮噸瑕併��',
+    date: '2021-04-01',
+    group: '涓婄彮鎽搁奔',
+    icon: 'ion:logo-html5',
+    title: 'Html5',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',
+  },
+  {
+    color: '#bf0c2c',
+    content: '鐑儏鍜屾鏈涘彲浠ョ獊鐮翠竴鍒囬毦鍏炽��',
+    date: '2021-04-01',
+    group: 'UI',
+    icon: 'ion:logo-angular',
+    title: 'Angular',
+    url: 'https://angular.io',
+  },
+  {
+    color: '#00d8ff',
+    content: '鍋ュ悍鐨勮韩浣撴槸瀹炵幇鐩爣鐨勫熀鐭炽��',
+    date: '2021-04-01',
+    group: '鎶�鏈墰',
+    icon: 'bx:bxl-react',
+    title: 'React',
+    url: 'https://reactjs.org',
+  },
+  {
+    color: '#EBD94E',
+    content: '璺槸璧板嚭鏉ョ殑锛岃�屼笉鏄┖鎯冲嚭鏉ョ殑銆�',
+    date: '2021-04-01',
+    group: '鏋舵瀯缁�',
+    icon: 'ion:logo-javascript',
+    title: 'Js',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',
+  },
+];
+
+// 鍚屾牱锛岃繖閲岀殑 url 涔熷彲浠ヤ娇鐢ㄤ互 http 寮�澶寸殑澶栭儴閾炬帴
+const quickNavItems: WorkbenchQuickNavItem[] = [
+  {
+    color: '#1fdaca',
+    icon: 'ion:home-outline',
+    title: '棣栭〉',
+    url: '/',
+  },
+  {
+    color: '#bf0c2c',
+    icon: 'ion:grid-outline',
+    title: '浠〃鐩�',
+    url: '/dashboard',
+  },
+  {
+    color: '#e18525',
+    icon: 'ion:layers-outline',
+    title: '缁勪欢',
+    url: '/demos/features/icons',
+  },
+  {
+    color: '#3fb27f',
+    icon: 'ion:settings-outline',
+    title: '绯荤粺绠$悊',
+    url: '/demos/features/login-expired', // 杩欓噷鐨� URL 鏄ず渚嬶紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+  },
+  {
+    color: '#4daf1bc9',
+    icon: 'ion:key-outline',
+    title: '鏉冮檺绠$悊',
+    url: '/demos/access/page-control',
+  },
+  {
+    color: '#00d8ff',
+    icon: 'ion:bar-chart-outline',
+    title: '鍥捐〃',
+    url: '/analytics',
+  },
+];
+
+const todoItems = ref<WorkbenchTodoItem[]>([
+  {
+    completed: false,
+    content: `瀹℃煡鏈�杩戞彁浜ゅ埌Git浠撳簱鐨勫墠绔唬鐮侊紝纭繚浠g爜璐ㄩ噺鍜岃鑼冦�俙,
+    date: '2024-07-30 11:00:00',
+    title: '瀹℃煡鍓嶇浠g爜鎻愪氦',
+  },
+  {
+    completed: true,
+    content: `妫�鏌ュ苟浼樺寲绯荤粺鎬ц兘锛岄檷浣嶤PU浣跨敤鐜囥�俙,
+    date: '2024-07-30 11:00:00',
+    title: '绯荤粺鎬ц兘浼樺寲',
+  },
+  {
+    completed: false,
+    content: `杩涜绯荤粺瀹夊叏妫�鏌ワ紝纭繚娌℃湁瀹夊叏婕忔礊鎴栨湭鎺堟潈鐨勮闂�� `,
+    date: '2024-07-30 11:00:00',
+    title: '瀹夊叏妫�鏌�',
+  },
+  {
+    completed: false,
+    content: `鏇存柊椤圭洰涓殑鎵�鏈塶pm渚濊禆鍖咃紝纭繚浣跨敤鏈�鏂扮増鏈�俙,
+    date: '2024-07-30 11:00:00',
+    title: '鏇存柊椤圭洰渚濊禆',
+  },
+  {
+    completed: false,
+    content: `淇鐢ㄦ埛鎶ュ憡鐨勯〉闈I鏄剧ず闂锛岀‘淇濆湪涓嶅悓娴忚鍣ㄤ腑鏄剧ず涓�鑷淬�� `,
+    date: '2024-07-30 11:00:00',
+    title: '淇UI鏄剧ず闂',
+  },
+]);
+const trendItems: WorkbenchTrendItem[] = [
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍦� <a>寮�婧愮粍</a> 鍒涘缓浜嗛」鐩� <a>Vue</a>`,
+    date: '鍒氬垰',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏虫敞浜� <a>濞佸粔</a> `,
+    date: '1涓皬鏃跺墠',
+    title: '鑹炬枃',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1澶╁墠',
+    title: '鍏嬮噷鏂�',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓涓�涓猇ite鎻掍欢</a> `,
+    date: '2澶╁墠',
+    title: 'Vben',
+  },
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍥炲浜� <a>鏉板厠</a> 鐨勯棶棰� <a>濡備綍杩涜椤圭洰浼樺寲锛�</a>`,
+    date: '3澶╁墠',
+    title: '鐨壒',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏抽棴浜嗛棶棰� <a>濡備綍杩愯椤圭洰</a> `,
+    date: '1鍛ㄥ墠',
+    title: '鏉板厠',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1鍛ㄥ墠',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鎺ㄩ�佷簡浠g爜鍒� <a>Github</a>`,
+    date: '2021-04-01 20:00',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓浣跨敤 Admin Vben</a> `,
+    date: '2021-03-01 20:00',
+    title: 'Vben',
+  },
+];
+
+const router = useRouter();
+
+// 杩欐槸涓�涓ず渚嬫柟娉曪紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// This is a sample method, adjust according to the actual project requirements
+function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {
+  if (nav.url?.startsWith('http')) {
+    openWindow(nav.url);
+    return;
+  }
+  if (nav.url?.startsWith('/')) {
+    router.push(nav.url).catch((error) => {
+      console.error('Navigation failed:', error);
+    });
+  } else {
+    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);
+  }
+}
+</script>
+
+<template>
+  <div class="p-5">
+    <WorkbenchHeader
+      :avatar="userStore.userInfo?.avatar || preferences.app.defaultAvatar"
+    >
+      <template #title>
+        鏃╁畨, {{ userStore.userInfo?.realName }}, 寮�濮嬫偍涓�澶╃殑宸ヤ綔鍚э紒
+      </template>
+      <template #description> 浠婃棩鏅达紝20鈩� - 32鈩冿紒 </template>
+    </WorkbenchHeader>
+
+    <div class="mt-5 flex flex-col lg:flex-row">
+      <div class="mr-4 w-full lg:w-3/5">
+        <WorkbenchProject :items="projectItems" title="椤圭洰" @click="navTo" />
+        <WorkbenchTrends :items="trendItems" class="mt-5" title="鏈�鏂板姩鎬�" />
+      </div>
+      <div class="w-full lg:w-2/5">
+        <WorkbenchQuickNav
+          :items="quickNavItems"
+          class="mt-5 lg:mt-0"
+          title="蹇嵎瀵艰埅"
+          @click="navTo"
+        />
+        <WorkbenchTodo :items="todoItems" class="mt-5" title="寰呭姙浜嬮」" />
+        <AnalysisChartCard class="mt-5" title="璁块棶鏉ユ簮">
+          <AnalyticsVisitsSource />
+        </AnalysisChartCard>
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/demos/form/basic.vue b/eims-ui/apps/web-naive/src/views/demos/form/basic.vue
new file mode 100644
index 0000000..7d04ff4
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/demos/form/basic.vue
@@ -0,0 +1,143 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { NButton, NCard, useMessage } from 'naive-ui';
+
+import { useVbenForm } from '#/adapter/form';
+import { getAllMenusApi } from '#/api';
+
+const message = useMessage();
+const [Form, formApi] = useVbenForm({
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  layout: 'horizontal',
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+  handleSubmit: (values) => {
+    message.success(`琛ㄥ崟鏁版嵁锛�${JSON.stringify(values)}`);
+  },
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'ApiSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        afterFetch: (data: { name: string; path: string }[]) => {
+          return data.map((item: any) => ({
+            label: item.name,
+            value: item.path,
+          }));
+        },
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+      },
+      // 瀛楁鍚�
+      fieldName: 'api',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiSelect',
+    },
+    {
+      component: 'ApiTreeSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+        childrenField: 'children',
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        labelField: 'name',
+        valueField: 'path',
+      },
+      // 瀛楁鍚�
+      fieldName: 'apiTree',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiTreeSelect',
+    },
+    {
+      component: 'Input',
+      fieldName: 'string',
+      label: 'String',
+    },
+    {
+      component: 'InputNumber',
+      fieldName: 'number',
+      label: 'Number',
+    },
+    {
+      component: 'RadioGroup',
+      fieldName: 'radio',
+      label: 'Radio',
+      componentProps: {
+        options: [
+          { value: 'A', label: 'A' },
+          { value: 'B', label: 'B' },
+          { value: 'C', label: 'C' },
+          { value: 'D', label: 'D' },
+          { value: 'E', label: 'E' },
+        ],
+      },
+    },
+    {
+      component: 'RadioGroup',
+      fieldName: 'radioButton',
+      label: 'RadioButton',
+      componentProps: {
+        isButton: true,
+        class: 'flex flex-wrap', // 濡傛灉閫夐」杩囧锛屽彲浠ユ坊鍔燾lass鏉ヨ嚜鍔ㄦ姌鍙�
+        options: [
+          { value: 'A', label: '閫夐」A' },
+          { value: 'B', label: '閫夐」B' },
+          { value: 'C', label: '閫夐」C' },
+          { value: 'D', label: '閫夐」D' },
+          { value: 'E', label: '閫夐」E' },
+          { value: 'F', label: '閫夐」F' },
+        ],
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      fieldName: 'checkbox',
+      label: 'Checkbox',
+      componentProps: {
+        options: [
+          { value: 'A', label: '閫夐」A' },
+          { value: 'B', label: '閫夐」B' },
+          { value: 'C', label: '閫夐」C' },
+        ],
+      },
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'date',
+      label: 'Date',
+    },
+  ],
+});
+function setFormValues() {
+  formApi.setValues({
+    string: 'string',
+    number: 123,
+    radio: 'B',
+    radioButton: 'C',
+    checkbox: ['A', 'C'],
+    date: Date.now(),
+  });
+}
+</script>
+<template>
+  <Page
+    description="琛ㄥ崟閫傞厤鍣ㄩ噸鏂板寘瑁呬簡CheckboxGroup鍜孯adioGroup锛屽彲浠ラ�氳繃options灞炴�т紶閫掗�夐」鏁版嵁锛堥�夐」鏁版嵁灏嗕綔涓哄瓙缁勪欢鐨勫睘鎬э級"
+    title="琛ㄥ崟婕旂ず"
+  >
+    <NCard title="鍩虹琛ㄥ崟">
+      <template #header-extra>
+        <NButton type="primary" @click="setFormValues">璁剧疆琛ㄥ崟鍊�</NButton>
+      </template>
+      <Form />
+    </NCard>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/demos/naive/index.vue b/eims-ui/apps/web-naive/src/views/demos/naive/index.vue
new file mode 100644
index 0000000..41d5510
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/demos/naive/index.vue
@@ -0,0 +1,68 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { type NotificationType } from 'naive-ui';
+import { NButton, NCard, NSpace, useMessage, useNotification } from 'naive-ui';
+
+const notification = useNotification();
+
+const message = useMessage();
+function error() {
+  message.error('Once upon a time you dressed so fine');
+}
+
+function warning() {
+  message.warning('How many roads must a man walk down');
+}
+function success() {
+  message.success('Cause you walked hand in hand With another man in my place');
+}
+function loading() {
+  message.loading(
+    'If I were you, I will realize that I love you more than any other guy',
+  );
+}
+
+function notify(type: NotificationType) {
+  notification[type]({
+    content: '璇寸偣鍟ュ憿',
+    duration: 2500,
+    keepAliveOnHover: true,
+    meta: '鎯充笉鍑烘潵',
+  });
+}
+</script>
+
+<template>
+  <Page description="鏀寔澶氳瑷�锛屼富棰樺姛鑳介泦鎴愬垏鎹㈢瓑" title="naive缁勪欢浣跨敤婕旂ず">
+    <NCard class="mb-5" title="鎸夐挳">
+      <NSpace>
+        <NButton>Default</NButton>
+        <NButton type="tertiary"> Tertiary </NButton>
+        <NButton type="primary"> Primary </NButton>
+        <NButton type="info"> Info </NButton>
+        <NButton type="success"> Success </NButton>
+        <NButton type="warning"> Warning </NButton>
+        <NButton type="error"> Error </NButton>
+      </NSpace>
+    </NCard>
+
+    <NCard class="mb-5" title="Message">
+      <NSpace>
+        <NButton type="error" @click="error"> 閿欒 </NButton>
+        <NButton type="warning" @click="warning"> 璀﹀憡 </NButton>
+        <NButton type="success" @click="success"> 鎴愬姛 </NButton>
+        <NButton type="primary" @click="loading"> 鍔犺浇涓� </NButton>
+      </NSpace>
+    </NCard>
+
+    <NCard class="mb-5" title="Notification">
+      <NSpace>
+        <NButton type="error" @click="notify('error')"> 閿欒 </NButton>
+        <NButton type="warning" @click="notify('warning')"> 璀﹀憡 </NButton>
+        <NButton type="success" @click="notify('success')"> 鎴愬姛 </NButton>
+        <NButton type="primary" @click="notify('info')"> 鍔犺浇涓� </NButton>
+      </NSpace>
+    </NCard>
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-naive/src/views/demos/table/index.vue b/eims-ui/apps/web-naive/src/views/demos/table/index.vue
new file mode 100644
index 0000000..ddc958b
--- /dev/null
+++ b/eims-ui/apps/web-naive/src/views/demos/table/index.vue
@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { NDataTable } from 'naive-ui';
+
+const columns = ref([
+  {
+    key: 'no',
+    title: 'No',
+  },
+  {
+    key: 'title',
+    title: 'Title',
+  },
+  {
+    key: 'length',
+    title: 'Length',
+  },
+]);
+const data = [
+  { length: '4:18', no: 3, title: 'Wonderwall' },
+  { length: '4:48', no: 4, title: "Don't Look Back in Anger" },
+  { length: '7:27', no: 12, title: 'Champagne Supernova' },
+];
+</script>
+
+<template>
+  <Page
+    description="琛ㄥ崟椤电敤浜庡悜鐢ㄦ埛鏀堕泦鎴栭獙璇佷俊鎭紝鍩虹琛ㄥ崟甯歌浜庢暟鎹」杈冨皯鐨勮〃鍗曞満鏅��"
+    title="NDataTable"
+  >
+    <NDataTable :columns="columns" :data="data" />
+  </Page>
+</template>
+
+<style scoped></style>
diff --git a/eims-ui/apps/web-naive/tailwind.config.mjs b/eims-ui/apps/web-naive/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/apps/web-naive/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/apps/web-naive/tsconfig.json b/eims-ui/apps/web-naive/tsconfig.json
new file mode 100644
index 0000000..02c287f
--- /dev/null
+++ b/eims-ui/apps/web-naive/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web-app.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["./src/*"]
+    }
+  },
+  "references": [{ "path": "./tsconfig.node.json" }],
+  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/eims-ui/apps/web-naive/tsconfig.node.json b/eims-ui/apps/web-naive/tsconfig.node.json
new file mode 100644
index 0000000..c2f0d86
--- /dev/null
+++ b/eims-ui/apps/web-naive/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "compilerOptions": {
+    "composite": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "noEmit": false
+  },
+  "include": ["vite.config.mts"]
+}
diff --git a/eims-ui/apps/web-naive/vite.config.mts b/eims-ui/apps/web-naive/vite.config.mts
new file mode 100644
index 0000000..b6360f1
--- /dev/null
+++ b/eims-ui/apps/web-naive/vite.config.mts
@@ -0,0 +1,20 @@
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    vite: {
+      server: {
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock浠g悊鐩爣鍦板潃
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
diff --git a/eims-ui/cspell.json b/eims-ui/cspell.json
new file mode 100644
index 0000000..2baadf8
--- /dev/null
+++ b/eims-ui/cspell.json
@@ -0,0 +1,74 @@
+{
+  "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json",
+  "version": "0.2",
+  "language": "en,en-US",
+  "allowCompoundWords": true,
+  "words": [
+    "acmr",
+    "antd",
+    "antdv",
+    "astro",
+    "brotli",
+    "clsx",
+    "defu",
+    "demi",
+    "echarts",
+    "ependencies",
+    "esno",
+    "etag",
+    "execa",
+    "Gitee",
+    "iconify",
+    "iconoir",
+    "intlify",
+    "ipaddr",
+    "lockb",
+    "logininfor",
+    "lucide",
+    "minh",
+    "minw",
+    "mkdist",
+    "mockjs",
+    "naiveui",
+    "nocheck",
+    "noopener",
+    "noreferrer",
+    "nprogress",
+    "nuxt",
+    "oper",
+    "operlog",
+    "pinia",
+    "prefixs",
+    "publint",
+    "Qqchat",
+    "qrcode",
+    "shadcn",
+    "sonner",
+    "sortablejs",
+    "styl",
+    "taze",
+    "ui-kit",
+    "uicons",
+    "unplugin",
+    "unref",
+    "vben",
+    "vbenjs",
+    "vite",
+    "vitejs",
+    "vitepress",
+    "vnode",
+    "vueuse",
+    "yxxx"
+  ],
+  "ignorePaths": [
+    "**/node_modules/**",
+    "**/dist/**",
+    "**/*-dist/**",
+    "**/icons/**",
+    "pnpm-lock.yaml",
+    "**/*.log",
+    "**/*.test.ts",
+    "**/*.spec.ts",
+    "**/__tests__/**"
+  ]
+}
diff --git a/eims-ui/docs/.vitepress/components/demo-preview.vue b/eims-ui/docs/.vitepress/components/demo-preview.vue
new file mode 100644
index 0000000..4c8829f
--- /dev/null
+++ b/eims-ui/docs/.vitepress/components/demo-preview.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import PreviewGroup from './preview-group.vue';
+
+interface Props {
+  files?: string;
+}
+
+const props = withDefaults(defineProps<Props>(), { files: '() => []' });
+
+const parsedFiles = computed(() => {
+  try {
+    return JSON.parse(decodeURIComponent(props.files ?? ''));
+  } catch {
+    return [];
+  }
+});
+</script>
+
+<template>
+  <div class="border-border shadow-float relative rounded-xl border">
+    <div
+      class="not-prose relative w-full overflow-x-auto rounded-t-lg px-4 py-6"
+    >
+      <div class="flex w-full max-w-[700px] px-2">
+        <ClientOnly>
+          <slot v-if="parsedFiles.length > 0"></slot>
+          <div v-else class="text-destructive text-sm">
+            <span class="bg-destructive text-foreground rounded-sm px-1 py-1">
+              ERROR:
+            </span>
+            The preview directory does not exist. Please check the 'dir'
+            parameter.
+          </div>
+        </ClientOnly>
+      </div>
+    </div>
+    <PreviewGroup v-if="parsedFiles.length > 0" :files="parsedFiles">
+      <template v-for="file in parsedFiles" #[file]>
+        <slot :name="file"></slot>
+      </template>
+    </PreviewGroup>
+  </div>
+</template>
diff --git a/eims-ui/docs/.vitepress/components/index.ts b/eims-ui/docs/.vitepress/components/index.ts
new file mode 100644
index 0000000..9430871
--- /dev/null
+++ b/eims-ui/docs/.vitepress/components/index.ts
@@ -0,0 +1 @@
+export { default as DemoPreview } from './demo-preview.vue';
diff --git a/eims-ui/docs/.vitepress/components/preview-group.vue b/eims-ui/docs/.vitepress/components/preview-group.vue
new file mode 100644
index 0000000..c8c6e83
--- /dev/null
+++ b/eims-ui/docs/.vitepress/components/preview-group.vue
@@ -0,0 +1,108 @@
+<script setup lang="ts">
+import { computed, ref, useSlots } from 'vue';
+
+import { VbenTooltip } from '@vben-core/shadcn-ui';
+
+import { Code } from 'lucide-vue-next';
+import {
+  TabsContent,
+  TabsIndicator,
+  TabsList,
+  TabsRoot,
+  TabsTrigger,
+} from 'radix-vue';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(
+  defineProps<{
+    files?: string[];
+  }>(),
+  { files: () => [] },
+);
+
+const open = ref(false);
+
+const slots = useSlots();
+
+const tabs = computed(() => {
+  return props.files.map((file) => {
+    return {
+      component: slots[file],
+      label: file,
+    };
+  });
+});
+
+const currentTab = ref('index.vue');
+
+const toggleOpen = () => {
+  open.value = !open.value;
+};
+</script>
+
+<template>
+  <TabsRoot
+    v-model="currentTab"
+    class="bg-background-deep border-border overflow-hidden rounded-b-xl border-t"
+    @update:model-value="open = true"
+  >
+    <div class="border-border bg-background flex border-b-2 pr-2">
+      <div class="flex w-full items-center justify-between text-[13px]">
+        <TabsList class="relative flex">
+          <template v-if="open">
+            <TabsIndicator
+              class="absolute bottom-0 left-0 h-[2px] w-[--radix-tabs-indicator-size] translate-x-[--radix-tabs-indicator-position] rounded-full transition-[width,transform] duration-300"
+            >
+              <div class="size-full bg-[var(--vp-c-indigo-1)]"></div>
+            </TabsIndicator>
+            <TabsTrigger
+              v-for="(tab, index) in tabs"
+              :key="index"
+              :value="tab.label"
+              class="border-box text-foreground px-4 py-3 data-[state=active]:text-[var(--vp-c-indigo-1)]"
+              tabindex="-1"
+            >
+              {{ tab.label }}
+            </TabsTrigger>
+          </template>
+        </TabsList>
+
+        <div
+          :class="{
+            'py-2': !open,
+          }"
+          class="flex items-center"
+        >
+          <VbenTooltip side="top">
+            <template #trigger>
+              <Code
+                class="hover:bg-accent size-7 cursor-pointer rounded-full p-1.5"
+                @click="toggleOpen"
+              />
+            </template>
+            {{ open ? 'Collapse code' : 'Expand code' }}
+          </VbenTooltip>
+        </div>
+      </div>
+    </div>
+    <div
+      :class="`${open ? 'h-[unset] max-h-[80vh]' : 'h-0'}`"
+      class="block overflow-y-scroll bg-[var(--vp-code-block-bg)] transition-all duration-300"
+    >
+      <TabsContent
+        v-for="tab in tabs"
+        :key="tab.label"
+        :value="tab.label"
+        as-child
+        class="rounded-xl"
+      >
+        <div class="text-foreground relative rounded-xl">
+          <component :is="tab.component" class="border-0" />
+        </div>
+      </TabsContent>
+    </div>
+  </TabsRoot>
+</template>
diff --git a/eims-ui/docs/.vitepress/config/en.mts b/eims-ui/docs/.vitepress/config/en.mts
new file mode 100644
index 0000000..3f7dd4f
--- /dev/null
+++ b/eims-ui/docs/.vitepress/config/en.mts
@@ -0,0 +1,229 @@
+import { type DefaultTheme, defineConfig } from 'vitepress';
+
+import { version } from '../../../package.json';
+
+export const en = defineConfig({
+  description: 'Vben Admin & Enterprise level management system framework',
+  lang: 'en-US',
+  themeConfig: {
+    darkModeSwitchLabel: 'Theme',
+    darkModeSwitchTitle: 'Switch to Dark Mode',
+    docFooter: {
+      next: 'Next Page',
+      prev: 'Previous Page',
+    },
+    editLink: {
+      pattern:
+        'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/src/:path',
+      text: 'Edit this page on GitHub',
+    },
+    footer: {
+      copyright: `Copyright 漏 2020-${new Date().getFullYear()} Vben`,
+      message: 'Released under the MIT License.',
+    },
+    langMenuLabel: 'Language',
+    lastUpdated: {
+      formatOptions: {
+        dateStyle: 'short',
+        timeStyle: 'medium',
+      },
+      text: 'Last updated on',
+    },
+    lightModeSwitchTitle: 'Switch to Light Mode',
+    nav: nav(),
+    outline: {
+      label: 'Navigate',
+    },
+    returnToTopLabel: 'Back to top',
+    sidebar: {
+      '/en/commercial/': {
+        base: '/en/commercial/',
+        items: sidebarCommercial(),
+      },
+      '/en/guide/': { base: '/en/guide/', items: sidebarGuide() },
+    },
+  },
+});
+
+function sidebarGuide(): DefaultTheme.SidebarItem[] {
+  return [
+    {
+      collapsed: false,
+      text: 'Introduction',
+      items: [
+        {
+          link: 'introduction/vben',
+          text: 'About Vben Admin',
+        },
+        {
+          link: 'introduction/why',
+          text: 'Why Choose Us?',
+        },
+        { link: 'introduction/quick-start', text: 'Quick Start' },
+        { link: 'introduction/thin', text: 'Lite Version' },
+      ],
+    },
+    {
+      text: 'Basics',
+      items: [
+        { link: 'essentials/concept', text: 'Basic Concepts' },
+        { link: 'essentials/development', text: 'Local Development' },
+        { link: 'essentials/route', text: 'Routing and Menu' },
+        { link: 'essentials/settings', text: 'Configuration' },
+        { link: 'essentials/icons', text: 'Icons' },
+        { link: 'essentials/styles', text: 'Styles' },
+        { link: 'essentials/external-module', text: 'External Modules' },
+        { link: 'essentials/build', text: 'Build and Deployment' },
+        { link: 'essentials/server', text: 'Server Interaction and Data Mock' },
+      ],
+    },
+    {
+      text: 'Advanced',
+      items: [
+        { link: 'in-depth/login', text: 'Login' },
+        { link: 'in-depth/theme', text: 'Theme' },
+        { link: 'in-depth/access', text: 'Access Control' },
+        { link: 'in-depth/locale', text: 'Internationalization' },
+        { link: 'in-depth/features', text: 'Common Features' },
+        { link: 'in-depth/check-updates', text: 'Check Updates' },
+        { link: 'in-depth/loading', text: 'Global Loading' },
+        { link: 'in-depth/ui-framework', text: 'UI Framework Switching' },
+      ],
+    },
+    {
+      text: 'Engineering',
+      items: [
+        { link: 'project/standard', text: 'Standards' },
+        { link: 'project/cli', text: 'CLI' },
+        { link: 'project/dir', text: 'Directory Explanation' },
+        { link: 'project/test', text: 'Unit Testing' },
+        { link: 'project/tailwindcss', text: 'Tailwind CSS' },
+        { link: 'project/changeset', text: 'Changeset' },
+        { link: 'project/vite', text: 'Vite Config' },
+      ],
+    },
+    {
+      text: 'Others',
+      items: [
+        { link: 'other/project-update', text: 'Project Update' },
+        { link: 'other/remove-code', text: 'Remove Code' },
+        { link: 'other/faq', text: 'FAQ' },
+      ],
+    },
+  ];
+}
+
+function sidebarCommercial(): DefaultTheme.SidebarItem[] {
+  return [
+    {
+      link: 'community',
+      text: 'Community',
+    },
+    {
+      link: 'technical-support',
+      text: 'Technical-support',
+    },
+    {
+      link: 'customized',
+      text: 'Customized',
+    },
+  ];
+}
+
+function nav(): DefaultTheme.NavItem[] {
+  return [
+    {
+      activeMatch: '^/en/(guide|components)/',
+      text: 'Doc',
+      items: [
+        {
+          activeMatch: '^/en/guide/',
+          link: '/en/guide/introduction/vben',
+          text: 'Guide',
+        },
+        // {
+        //   activeMatch: '^/en/components/',
+        //   link: '/en/components/introduction',
+        //   text: 'Components',
+        // },
+        {
+          text: 'Historical Versions',
+          items: [
+            {
+              link: 'https://doc.vvbin.cn',
+              text: '2.x Version Documentation',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      text: 'Demo',
+      items: [
+        {
+          text: 'Vben Admin',
+          items: [
+            {
+              link: 'https://www.vben.pro',
+              text: 'Demo Version',
+            },
+            {
+              link: 'https://ant.vben.pro',
+              text: 'Ant Design Vue Version',
+            },
+            {
+              link: 'https://naive.vben.pro',
+              text: 'Naive Version',
+            },
+            {
+              link: 'https://ele.vben.pro',
+              text: 'Element Plus Version',
+            },
+          ],
+        },
+        {
+          text: 'Others',
+          items: [
+            {
+              link: 'https://vben.vvbin.cn',
+              text: 'Vben Admin 2.x',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      text: version,
+      items: [
+        {
+          link: 'https://github.com/vbenjs/vue-vben-admin/releases',
+          text: 'Changelog',
+        },
+        {
+          link: 'https://github.com/orgs/vbenjs/projects/5',
+          text: 'Roadmap',
+        },
+        {
+          link: 'https://github.com/vbenjs/vue-vben-admin/blob/main/.github/contributing.md',
+          text: 'Contribution',
+        },
+      ],
+    },
+    {
+      link: '/commercial/technical-support',
+      text: '馃 Tech Support',
+    },
+    {
+      link: '/sponsor/personal',
+      text: '鉁� Sponsor',
+    },
+    {
+      link: '/commercial/community',
+      text: '馃懆鈥嶐煈︹�嶐煈� Community',
+    },
+    // {
+    //   link: '/friend-links/',
+    //   text: '馃 Friend Links',
+    // },
+  ];
+}
diff --git a/eims-ui/docs/.vitepress/config/index.mts b/eims-ui/docs/.vitepress/config/index.mts
new file mode 100644
index 0000000..6b8cb81
--- /dev/null
+++ b/eims-ui/docs/.vitepress/config/index.mts
@@ -0,0 +1,25 @@
+import { withPwa } from '@vite-pwa/vitepress';
+import { defineConfigWithTheme } from 'vitepress';
+
+import { en } from './en.mts';
+import { shared } from './shared.mts';
+import { zh } from './zh.mts';
+
+export default withPwa(
+  defineConfigWithTheme({
+    ...shared,
+    locales: {
+      en: {
+        label: 'English',
+        lang: 'en',
+        link: '/en/',
+        ...en,
+      },
+      root: {
+        label: '绠�浣撲腑鏂�',
+        lang: 'zh-CN',
+        ...zh,
+      },
+    },
+  }),
+);
diff --git a/eims-ui/docs/.vitepress/config/plugins/demo-preview.ts b/eims-ui/docs/.vitepress/config/plugins/demo-preview.ts
new file mode 100644
index 0000000..03b1698
--- /dev/null
+++ b/eims-ui/docs/.vitepress/config/plugins/demo-preview.ts
@@ -0,0 +1,143 @@
+import type { MarkdownEnv, MarkdownRenderer } from 'vitepress';
+
+import crypto from 'node:crypto';
+import { readdirSync } from 'node:fs';
+import { join } from 'node:path';
+
+export const rawPathRegexp =
+  // eslint-disable-next-line regexp/no-super-linear-backtracking, regexp/strict
+  /^(.+?(?:\.([\da-z]+))?)(#[\w-]+)?(?: ?{(\d+(?:[,-]\d+)*)? ?(\S+)?})? ?(?:\[(.+)])?$/;
+
+function rawPathToToken(rawPath: string) {
+  const [
+    filepath = '',
+    extension = '',
+    region = '',
+    lines = '',
+    lang = '',
+    rawTitle = '',
+  ] = (rawPathRegexp.exec(rawPath) || []).slice(1);
+
+  const title = rawTitle || filepath.split('/').pop() || '';
+
+  return { extension, filepath, lang, lines, region, title };
+}
+
+export const demoPreviewPlugin = (md: MarkdownRenderer) => {
+  md.core.ruler.after('inline', 'demo-preview', (state) => {
+    const insertComponentImport = (importString: string) => {
+      const index = state.tokens.findIndex(
+        (i) => i.type === 'html_block' && i.content.match(/<script setup>/g),
+      );
+      if (index === -1) {
+        const importComponent = new state.Token('html_block', '', 0);
+        importComponent.content = `<script setup>\n${importString}\n</script>\n`;
+        state.tokens.splice(0, 0, importComponent);
+      } else {
+        if (state.tokens[index]) {
+          const content = state.tokens[index].content;
+          state.tokens[index].content = content.replace(
+            '</script>',
+            `${importString}\n</script>`,
+          );
+        }
+      }
+    };
+    // Define the regular expression to match the desired pattern
+    const regex = /<DemoPreview[^>]*\sdir="([^"]*)"/g;
+    // Iterate through the Markdown content and replace the pattern
+    state.src = state.src.replaceAll(regex, (_match, dir) => {
+      const componentDir = join(process.cwd(), 'src', dir).replaceAll(
+        '\\',
+        '/',
+      );
+
+      let childFiles: string[] = [];
+      let dirExists = true;
+
+      try {
+        childFiles =
+          readdirSync(componentDir, {
+            encoding: 'utf8',
+            recursive: false,
+            withFileTypes: false,
+          }) || [];
+      } catch {
+        dirExists = false;
+      }
+
+      if (!dirExists) {
+        return '';
+      }
+
+      const uniqueWord = generateContentHash(componentDir);
+
+      const ComponentName = `DemoComponent_${uniqueWord}`;
+      insertComponentImport(
+        `import ${ComponentName} from '${componentDir}/index.vue'`,
+      );
+      const { path: _path } = state.env as MarkdownEnv;
+
+      const index = state.tokens.findIndex((i) => i.content.match(regex));
+
+      if (!state.tokens[index]) {
+        return '';
+      }
+      const firstString = 'index.vue';
+      childFiles = childFiles.sort((a, b) => {
+        if (a === firstString) return -1;
+        if (b === firstString) return 1;
+        return a.localeCompare(b, 'en', { sensitivity: 'base' });
+      });
+      state.tokens[index].content =
+        `<DemoPreview files="${encodeURIComponent(JSON.stringify(childFiles))}" ><${ComponentName}/>
+        `;
+
+      const _dummyToken = new state.Token('', '', 0);
+      const tokenArray: Array<typeof _dummyToken> = [];
+      childFiles.forEach((filename) => {
+        // const slotName = filename.replace(extname(filename), '');
+
+        const templateStart = new state.Token('html_inline', '', 0);
+        templateStart.content = `<template #${filename}>`;
+        tokenArray.push(templateStart);
+
+        const resolvedPath = join(componentDir, filename);
+
+        const { extension, filepath, lang, lines, title } =
+          rawPathToToken(resolvedPath);
+        // Add code tokens for each line
+        const token = new state.Token('fence', 'code', 0);
+        token.info = `${lang || extension}${lines ? `{${lines}}` : ''}${
+          title ? `[${title}]` : ''
+        }`;
+
+        token.content = `<<< ${filepath}`;
+        (token as any).src = [resolvedPath];
+        tokenArray.push(token);
+
+        const templateEnd = new state.Token('html_inline', '', 0);
+        templateEnd.content = '</template>';
+        tokenArray.push(templateEnd);
+      });
+      const endTag = new state.Token('html_inline', '', 0);
+      endTag.content = '</DemoPreview>';
+      tokenArray.push(endTag);
+
+      state.tokens.splice(index + 1, 0, ...tokenArray);
+
+      // console.log(
+      //   state.md.renderer.render(state.tokens, state?.options ?? [], state.env),
+      // );
+      return '';
+    });
+  });
+};
+
+function generateContentHash(input: string, length: number = 10): string {
+  // 浣跨敤 SHA-256 鐢熸垚鍝堝笇鍊�
+  const hash = crypto.createHash('sha256').update(input).digest('hex');
+
+  // 灏嗗搱甯屽�艰浆鎹负 Base36 缂栫爜锛屽苟鍙栨寚瀹氶暱搴︾殑瀛楃浣滀负缁撴灉
+  return Number.parseInt(hash, 16).toString(36).slice(0, length);
+}
diff --git a/eims-ui/docs/.vitepress/config/shared.mts b/eims-ui/docs/.vitepress/config/shared.mts
new file mode 100644
index 0000000..c48cc60
--- /dev/null
+++ b/eims-ui/docs/.vitepress/config/shared.mts
@@ -0,0 +1,172 @@
+import type { PwaOptions } from '@vite-pwa/vitepress';
+import type { HeadConfig } from 'vitepress';
+
+import { resolve } from 'node:path';
+
+import {
+  viteArchiverPlugin,
+  viteVxeTableImportsPlugin,
+} from '@vben/vite-config';
+
+import {
+  GitChangelog,
+  GitChangelogMarkdownSection,
+} from '@nolebase/vitepress-plugin-git-changelog/vite';
+import tailwind from 'tailwindcss';
+import { defineConfig, postcssIsolateStyles } from 'vitepress';
+import {
+  groupIconMdPlugin,
+  groupIconVitePlugin,
+} from 'vitepress-plugin-group-icons';
+
+import { demoPreviewPlugin } from './plugins/demo-preview';
+import { search as zhSearch } from './zh.mts';
+
+export const shared = defineConfig({
+  appearance: 'dark',
+  head: head(),
+  markdown: {
+    preConfig(md) {
+      md.use(demoPreviewPlugin);
+      md.use(groupIconMdPlugin);
+    },
+  },
+  pwa: pwa(),
+  srcDir: 'src',
+  themeConfig: {
+    i18nRouting: true,
+    logo: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+    search: {
+      options: {
+        locales: {
+          ...zhSearch,
+        },
+      },
+      provider: 'local',
+    },
+    siteTitle: 'Vben Admin',
+    socialLinks: [
+      { icon: 'github', link: 'https://github.com/vbenjs/vue-vben-admin' },
+    ],
+  },
+  title: 'Vben Admin',
+  vite: {
+    build: {
+      chunkSizeWarningLimit: Infinity,
+      minify: 'terser',
+    },
+    css: {
+      postcss: {
+        plugins: [
+          tailwind(),
+          postcssIsolateStyles({ includeFiles: [/vp-doc\.css/] }),
+        ],
+      },
+      preprocessorOptions: {
+        scss: {
+          api: 'modern',
+        },
+      },
+    },
+    json: {
+      stringify: true,
+    },
+    plugins: [
+      GitChangelog({
+        mapAuthors: [
+          {
+            mapByNameAliases: ['Vben'],
+            name: 'vben',
+            username: 'anncwb',
+          },
+          {
+            name: 'vince',
+            username: 'vince292007',
+          },
+          {
+            name: 'Li Kui',
+            username: 'likui628',
+          },
+        ],
+        repoURL: () => 'https://github.com/vbenjs/vue-vben-admin',
+      }),
+      GitChangelogMarkdownSection(),
+      viteArchiverPlugin({ outputDir: '.vitepress' }),
+      groupIconVitePlugin(),
+      await viteVxeTableImportsPlugin(),
+    ],
+    server: {
+      fs: {
+        allow: ['../..'],
+      },
+      host: true,
+      port: 6173,
+    },
+
+    ssr: {
+      external: ['@vue/repl'],
+    },
+  },
+});
+
+function head(): HeadConfig[] {
+  return [
+    ['meta', { content: 'Vbenjs Team', name: 'author' }],
+    [
+      'meta',
+      {
+        content: 'vben, vitejs, vite, shacdn-ui, vue',
+        name: 'keywords',
+      },
+    ],
+    ['link', { href: '/favicon.ico', rel: 'icon', type: 'image/svg+xml' }],
+    [
+      'meta',
+      {
+        content:
+          'width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no',
+        name: 'viewport',
+      },
+    ],
+    ['meta', { content: 'vben admin docs', name: 'keywords' }],
+    ['link', { href: '/favicon.ico', rel: 'icon' }],
+    // [
+    //   'script',
+    //   {
+    //     src: 'https://cdn.tailwindcss.com',
+    //   },
+    // ],
+  ];
+}
+
+function pwa(): PwaOptions {
+  return {
+    includeManifestIcons: false,
+    manifest: {
+      description:
+        'Vben Admin is a modern admin dashboard template based on Vue 3. ',
+      icons: [
+        {
+          sizes: '192x192',
+          src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-192.png',
+          type: 'image/png',
+        },
+        {
+          sizes: '512x512',
+          src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-512.png',
+          type: 'image/png',
+        },
+      ],
+      id: '/',
+      name: 'Vben Admin Doc',
+      short_name: 'vben_admin_doc',
+      theme_color: '#ffffff',
+    },
+    outDir: resolve(process.cwd(), '.vitepress/dist'),
+    registerType: 'autoUpdate',
+    workbox: {
+      globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],
+      maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
+    },
+  };
+}
diff --git a/eims-ui/docs/.vitepress/config/zh.mts b/eims-ui/docs/.vitepress/config/zh.mts
new file mode 100644
index 0000000..25e93ce
--- /dev/null
+++ b/eims-ui/docs/.vitepress/config/zh.mts
@@ -0,0 +1,348 @@
+import { type DefaultTheme, defineConfig } from 'vitepress';
+
+import { version } from '../../../package.json';
+
+export const zh = defineConfig({
+  description: 'Vben Admin & 浼佷笟绾х鐞嗙郴缁熸鏋�',
+  lang: 'zh-Hans',
+  themeConfig: {
+    darkModeSwitchLabel: '涓婚',
+    darkModeSwitchTitle: '鍒囨崲鍒版繁鑹叉ā寮�',
+    docFooter: {
+      next: '涓嬩竴椤�',
+      prev: '涓婁竴椤�',
+    },
+    editLink: {
+      pattern:
+        'https://github.com/vbenjs/vue-vben-admin/edit/main/docs/src/:path',
+      text: '鍦� GitHub 涓婄紪杈戞椤甸潰',
+    },
+    footer: {
+      copyright: `Copyright 漏 2020-${new Date().getFullYear()} Vben`,
+      message: '鍩轰簬 MIT 璁稿彲鍙戝竷.',
+    },
+    langMenuLabel: '澶氳瑷�',
+    lastUpdated: {
+      formatOptions: {
+        dateStyle: 'short',
+        timeStyle: 'medium',
+      },
+      text: '鏈�鍚庢洿鏂颁簬',
+    },
+    lightModeSwitchTitle: '鍒囨崲鍒版祬鑹叉ā寮�',
+    nav: nav(),
+
+    outline: {
+      label: '椤甸潰瀵艰埅',
+    },
+    returnToTopLabel: '鍥炲埌椤堕儴',
+
+    sidebar: {
+      '/commercial/': { base: '/commercial/', items: sidebarCommercial() },
+      '/components/': { base: '/components/', items: sidebarComponents() },
+      '/guide/': { base: '/guide/', items: sidebarGuide() },
+    },
+    sidebarMenuLabel: '鑿滃崟',
+  },
+});
+
+function sidebarGuide(): DefaultTheme.SidebarItem[] {
+  return [
+    {
+      collapsed: false,
+      text: '绠�浠�',
+      items: [
+        {
+          link: 'introduction/vben',
+          text: '鍏充簬 Vben Admin',
+        },
+        {
+          link: 'introduction/why',
+          text: '涓轰粈涔堥�夋嫨鎴戜滑?',
+        },
+        { link: 'introduction/quick-start', text: '蹇�熷紑濮�' },
+        { link: 'introduction/thin', text: '绮剧畝鐗堟湰' },
+        {
+          base: '/',
+          link: 'components/introduction',
+          text: '缁勪欢鏂囨。',
+        },
+      ],
+    },
+    {
+      text: '鍩虹',
+      items: [
+        { link: 'essentials/concept', text: '鍩虹姒傚康' },
+        { link: 'essentials/development', text: '鏈湴寮�鍙�' },
+        { link: 'essentials/route', text: '璺敱鍜岃彍鍗�' },
+        { link: 'essentials/settings', text: '閰嶇疆' },
+        { link: 'essentials/icons', text: '鍥炬爣' },
+        { link: 'essentials/styles', text: '鏍峰紡' },
+        { link: 'essentials/external-module', text: '澶栭儴妯″潡' },
+        { link: 'essentials/build', text: '鏋勫缓涓庨儴缃�' },
+        { link: 'essentials/server', text: '鏈嶅姟绔氦浜掍笌鏁版嵁Mock' },
+      ],
+    },
+    {
+      text: '娣卞叆',
+      items: [
+        { link: 'in-depth/login', text: '鐧诲綍' },
+        // { link: 'in-depth/layout', text: '甯冨眬' },
+        { link: 'in-depth/theme', text: '涓婚' },
+        { link: 'in-depth/access', text: '鏉冮檺' },
+        { link: 'in-depth/locale', text: '鍥介檯鍖�' },
+        { link: 'in-depth/features', text: '甯哥敤鍔熻兘' },
+        { link: 'in-depth/check-updates', text: '妫�鏌ユ洿鏂�' },
+        { link: 'in-depth/loading', text: '鍏ㄥ眬loading' },
+        { link: 'in-depth/ui-framework', text: '缁勪欢搴撳垏鎹�' },
+      ],
+    },
+    {
+      text: '宸ョ▼',
+      items: [
+        { link: 'project/standard', text: '瑙勮寖' },
+        { link: 'project/cli', text: 'CLI' },
+        { link: 'project/dir', text: '鐩綍璇存槑' },
+        { link: 'project/test', text: '鍗曞厓娴嬭瘯' },
+        { link: 'project/tailwindcss', text: 'Tailwind CSS' },
+        { link: 'project/changeset', text: 'Changeset' },
+        { link: 'project/vite', text: 'Vite Config' },
+      ],
+    },
+    {
+      text: '鍏朵粬',
+      items: [
+        { link: 'other/project-update', text: '椤圭洰鏇存柊' },
+        { link: 'other/remove-code', text: '绉婚櫎浠g爜' },
+        { link: 'other/faq', text: '甯歌闂' },
+      ],
+    },
+  ];
+}
+
+function sidebarCommercial(): DefaultTheme.SidebarItem[] {
+  return [
+    {
+      link: 'community',
+      text: '浜ゆ祦缇�',
+    },
+    {
+      link: 'technical-support',
+      text: '鎶�鏈敮鎸�',
+    },
+    {
+      link: 'customized',
+      text: '瀹氬埗寮�鍙�',
+    },
+  ];
+}
+
+function sidebarComponents(): DefaultTheme.SidebarItem[] {
+  return [
+    {
+      text: '缁勪欢',
+      items: [
+        {
+          link: 'introduction',
+          text: '浠嬬粛',
+        },
+      ],
+    },
+    {
+      collapsed: false,
+      text: '甯冨眬缁勪欢',
+      items: [
+        {
+          link: 'layout-ui/page',
+          text: 'Page 椤甸潰',
+        },
+      ],
+    },
+    {
+      collapsed: false,
+      text: '閫氱敤缁勪欢',
+      items: [
+        {
+          link: 'common-ui/vben-api-component',
+          text: 'ApiComponent Api缁勪欢鍖呰鍣�',
+        },
+        {
+          link: 'common-ui/vben-modal',
+          text: 'Modal 妯℃�佹',
+        },
+        {
+          link: 'common-ui/vben-drawer',
+          text: 'Drawer 鎶藉眽',
+        },
+        {
+          link: 'common-ui/vben-form',
+          text: 'Form 琛ㄥ崟',
+        },
+        {
+          link: 'common-ui/vben-vxe-table',
+          text: 'Vxe Table 琛ㄦ牸',
+        },
+        {
+          link: 'common-ui/vben-count-to-animator',
+          text: 'CountToAnimator 鏁板瓧鍔ㄧ敾',
+        },
+      ],
+    },
+  ];
+}
+
+function nav(): DefaultTheme.NavItem[] {
+  return [
+    {
+      activeMatch: '^/(guide|components)/',
+      text: '鏂囨。',
+      items: [
+        {
+          activeMatch: '^/guide/',
+          link: '/guide/introduction/vben',
+          text: '鎸囧崡',
+        },
+        {
+          activeMatch: '^/components/',
+          link: '/components/introduction',
+          text: '缁勪欢',
+        },
+        {
+          text: '鍘嗗彶鐗堟湰',
+          items: [
+            {
+              link: 'https://doc.vvbin.cn',
+              text: '2.x鐗堟湰鏂囨。',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      text: '婕旂ず',
+      items: [
+        {
+          text: 'Vben Admin',
+          items: [
+            {
+              link: 'https://www.vben.pro',
+              text: '婕旂ず鐗堟湰',
+            },
+            {
+              link: 'https://ant.vben.pro',
+              text: 'Ant Design Vue 鐗堟湰',
+            },
+            {
+              link: 'https://naive.vben.pro',
+              text: 'Naive 鐗堟湰',
+            },
+            {
+              link: 'https://ele.vben.pro',
+              text: 'Element Plus鐗堟湰',
+            },
+          ],
+        },
+        {
+          text: '鍏朵粬',
+          items: [
+            {
+              link: 'https://vben.vvbin.cn',
+              text: 'Vben Admin 2.x',
+            },
+          ],
+        },
+      ],
+    },
+    {
+      text: version,
+      items: [
+        {
+          link: 'https://github.com/vbenjs/vue-vben-admin/releases',
+          text: '鏇存柊鏃ュ織',
+        },
+        {
+          link: 'https://github.com/orgs/vbenjs/projects/5',
+          text: '璺嚎鍥�',
+        },
+        {
+          link: 'https://github.com/vbenjs/vue-vben-admin/blob/main/.github/contributing.md',
+          text: '璐$尞',
+        },
+      ],
+    },
+    {
+      link: '/commercial/technical-support',
+      text: '馃 鎶�鏈敮鎸�',
+    },
+    {
+      link: '/sponsor/personal',
+      text: '鉁� 璧炲姪',
+    },
+    {
+      link: '/commercial/community',
+      text: '馃懆鈥嶐煈︹�嶐煈� 浜ゆ祦缇�',
+      // items: [
+      //   {
+      //     link: 'https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&appChannel=share&inviteCode=22ySzj7pKiw&businessType=9&from=246610&biz=ka&mainSourceId=share&subSourceId=others&jumpsource=shorturl#/pc',
+      //     text: 'QQ棰戦亾',
+      //   },
+      //   {
+      //     link: 'https://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=mjZmlhgVzzUxvdxllB6C1vHpX8O8QRL0&authKey=DBdFbBwERmfaKY95JvRWqLCJIRGJAmKyZbrpzZ41EKDMZ5SR6MfbjOBaaNRN73fr&noverify=0&group_code=4286109',
+      //     text: 'QQ缇�',
+      //   },
+      //   {
+      //     link: 'https://discord.gg/VU62jTecad',
+      //     text: 'Discord',
+      //   },
+      // ],
+    },
+    // {
+    //   link: '/friend-links/',
+    //   text: '馃 鍙嬫儏閾炬帴',
+    // },
+  ];
+}
+
+export const search: DefaultTheme.AlgoliaSearchOptions['locales'] = {
+  root: {
+    placeholder: '鎼滅储鏂囨。',
+    translations: {
+      button: {
+        buttonAriaLabel: '鎼滅储鏂囨。',
+        buttonText: '鎼滅储鏂囨。',
+      },
+      modal: {
+        errorScreen: {
+          helpText: '浣犲彲鑳介渶瑕佹鏌ヤ綘鐨勭綉缁滆繛鎺�',
+          titleText: '鏃犳硶鑾峰彇缁撴灉',
+        },
+        footer: {
+          closeText: '鍏抽棴',
+          navigateText: '鍒囨崲',
+          searchByText: '鎼滅储鎻愪緵鑰�',
+          selectText: '閫夋嫨',
+        },
+        noResultsScreen: {
+          noResultsText: '鏃犳硶鎵惧埌鐩稿叧缁撴灉',
+          reportMissingResultsLinkText: '鐐瑰嚮鍙嶉',
+          reportMissingResultsText: '浣犺涓鸿鏌ヨ搴旇鏈夌粨鏋滐紵',
+          suggestedQueryText: '浣犲彲浠ュ皾璇曟煡璇�',
+        },
+        searchBox: {
+          cancelButtonAriaLabel: '鍙栨秷',
+          cancelButtonText: '鍙栨秷',
+          resetButtonAriaLabel: '娓呴櫎鏌ヨ鏉′欢',
+          resetButtonTitle: '娓呴櫎鏌ヨ鏉′欢',
+        },
+        startScreen: {
+          favoriteSearchesTitle: '鏀惰棌',
+          noRecentSearchesText: '娌℃湁鎼滅储鍘嗗彶',
+          recentSearchesTitle: '鎼滅储鍘嗗彶',
+          removeFavoriteSearchButtonTitle: '浠庢敹钘忎腑绉婚櫎',
+          removeRecentSearchButtonTitle: '浠庢悳绱㈠巻鍙蹭腑绉婚櫎',
+          saveRecentSearchButtonTitle: '淇濆瓨鑷虫悳绱㈠巻鍙�',
+        },
+      },
+    },
+  },
+};
diff --git a/eims-ui/docs/.vitepress/theme/components/site-layout.vue b/eims-ui/docs/.vitepress/theme/components/site-layout.vue
new file mode 100644
index 0000000..d643cae
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/components/site-layout.vue
@@ -0,0 +1,97 @@
+<script lang="ts" setup>
+import {
+  computed,
+  nextTick,
+  onBeforeUnmount,
+  onMounted,
+  ref,
+  watch,
+} from 'vue';
+
+// import { useAntdDesignTokens } from '@vben/hooks';
+// import { initPreferences } from '@vben/preferences';
+
+import { ConfigProvider, theme } from 'ant-design-vue';
+import mediumZoom from 'medium-zoom';
+import { useRoute } from 'vitepress';
+import DefaultTheme from 'vitepress/theme';
+
+const { Layout } = DefaultTheme;
+const route = useRoute();
+// const { tokens } = useAntdDesignTokens();
+
+const initZoom = () => {
+  // mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' });
+  mediumZoom('.VPContent img', { background: 'var(--vp-c-bg)' });
+};
+
+const isDark = ref(true);
+
+watch(
+  () => route.path,
+  () => nextTick(() => initZoom()),
+);
+
+// initPreferences({
+//   namespace: 'docs',
+// });
+
+onMounted(() => {
+  initZoom();
+});
+
+// 浣跨敤璇ュ嚱鏁�
+const observer = watchDarkModeChange((dark) => {
+  isDark.value = dark;
+});
+
+onBeforeUnmount(() => {
+  observer?.disconnect();
+});
+
+function watchDarkModeChange(callback: (isDark: boolean) => void) {
+  if (typeof window === 'undefined') {
+    return;
+  }
+  const htmlElement = document.documentElement;
+
+  const observer = new MutationObserver(() => {
+    const isDark = htmlElement.classList.contains('dark');
+    callback(isDark);
+  });
+
+  observer.observe(htmlElement, {
+    attributeFilter: ['class'],
+    attributes: true,
+  });
+
+  const initialIsDark = htmlElement.classList.contains('dark');
+  callback(initialIsDark);
+
+  return observer;
+}
+
+const tokenTheme = computed(() => {
+  const algorithm = isDark.value
+    ? [theme.darkAlgorithm]
+    : [theme.defaultAlgorithm];
+
+  return {
+    algorithm,
+    // token: tokens,
+  };
+});
+</script>
+
+<template>
+  <ConfigProvider :theme="tokenTheme">
+    <Layout />
+  </ConfigProvider>
+</template>
+
+<style>
+.medium-zoom-overlay,
+.medium-zoom-image--opened {
+  z-index: 2147483647;
+}
+</style>
diff --git a/eims-ui/docs/.vitepress/theme/components/vben-contributors.vue b/eims-ui/docs/.vitepress/theme/components/vben-contributors.vue
new file mode 100644
index 0000000..9b887d9
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/components/vben-contributors.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="vp-doc vben-contributors">
+    <p>Contributors</p>
+    <a href="https://github.com/vbenjs/vue-vben-admin/graphs/contributors">
+      <img
+        alt="Contributors"
+        src="https://opencollective.com/vbenjs/contributors.svg?button=false"
+      />
+    </a>
+  </div>
+</template>
+
+<style scoped>
+.vben-contributors {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding-top: 60px;
+
+  p {
+    margin-bottom: 50px;
+    font-size: 30px;
+    font-weight: 700;
+  }
+}
+</style>
diff --git a/eims-ui/docs/.vitepress/theme/index.ts b/eims-ui/docs/.vitepress/theme/index.ts
new file mode 100644
index 0000000..7d4d3dc
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/index.ts
@@ -0,0 +1,29 @@
+// https://vitepress.dev/guide/custom-theme
+import type { EnhanceAppContext, Theme } from 'vitepress';
+
+import { NolebaseGitChangelogPlugin } from '@nolebase/vitepress-plugin-git-changelog/client';
+import DefaultTheme from 'vitepress/theme';
+
+import { DemoPreview } from '../components';
+import SiteLayout from './components/site-layout.vue';
+import VbenContributors from './components/vben-contributors.vue';
+import { initHmPlugin } from './plugins/hm';
+
+import './styles';
+
+import 'virtual:group-icons.css';
+import '@nolebase/vitepress-plugin-git-changelog/client/style.css';
+
+export default {
+  async enhanceApp(ctx: EnhanceAppContext) {
+    const { app } = ctx;
+    app.component('VbenContributors', VbenContributors);
+    app.component('DemoPreview', DemoPreview);
+    app.use(NolebaseGitChangelogPlugin);
+
+    // 鐧惧害缁熻
+    initHmPlugin();
+  },
+  extends: DefaultTheme,
+  Layout: SiteLayout,
+} satisfies Theme;
diff --git a/eims-ui/docs/.vitepress/theme/plugins/hm.ts b/eims-ui/docs/.vitepress/theme/plugins/hm.ts
new file mode 100644
index 0000000..5e0a931
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/plugins/hm.ts
@@ -0,0 +1,28 @@
+import { inBrowser } from 'vitepress';
+
+const SITE_ID = '2e443a834727c065877c01d89921545e';
+
+declare global {
+  interface Window {
+    _hmt: any;
+  }
+}
+
+function registerAnalytics() {
+  window._hmt = window._hmt || [];
+  const script = document.createElement('script');
+  script.innerHTML = `var _hmt = _hmt || [];
+      (function() {
+        var hm = document.createElement("script");
+        hm.src = "https://hm.baidu.com/hm.js?${SITE_ID}";
+        var s = document.getElementsByTagName("script")[0];
+        s.parentNode.insertBefore(hm, s);
+      })()`;
+  document.querySelector('head')?.append(script);
+}
+
+export function initHmPlugin() {
+  if (inBrowser && import.meta.env.PROD) {
+    registerAnalytics();
+  }
+}
diff --git a/eims-ui/docs/.vitepress/theme/styles/base.css b/eims-ui/docs/.vitepress/theme/styles/base.css
new file mode 100644
index 0000000..8eb423a
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/styles/base.css
@@ -0,0 +1,22 @@
+html.dark {
+  color-scheme: dark;
+}
+
+.dark .VPContent {
+  /* background-color: #14161a; */
+}
+
+.form-valid-error p {
+  margin: 0;
+}
+
+/* 椤堕儴瀵艰埅鏍忛�変腑椤规牱寮� */
+.VPNavBarMenuLink,
+.VPNavBarMenuGroup {
+  border-bottom: 1px solid transparent;
+}
+
+.VPNavBarMenuLink.active,
+.VPNavBarMenuGroup.active {
+  border-bottom-color: var(--vp-c-brand-1);
+}
diff --git a/eims-ui/docs/.vitepress/theme/styles/index.ts b/eims-ui/docs/.vitepress/theme/styles/index.ts
new file mode 100644
index 0000000..566e63f
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/styles/index.ts
@@ -0,0 +1,4 @@
+import '@vben/styles';
+
+import './variables.css';
+import './base.css';
diff --git a/eims-ui/docs/.vitepress/theme/styles/variables.css b/eims-ui/docs/.vitepress/theme/styles/variables.css
new file mode 100644
index 0000000..d633803
--- /dev/null
+++ b/eims-ui/docs/.vitepress/theme/styles/variables.css
@@ -0,0 +1,127 @@
+/**
+ * Customize default theme styling by overriding CSS variables:
+ * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
+ */
+
+/**
+ * Colors
+ *
+ * Each colors have exact same color scale system with 3 levels of solid
+ * colors with different brightness, and 1 soft color.
+ *
+ * - `XXX-1`: The most solid color used mainly for colored text. It must
+ *   satisfy the contrast ratio against when used on top of `XXX-soft`.
+ *
+ * - `XXX-2`: The color used mainly for hover state of the button.
+ *
+ * - `XXX-3`: The color for solid background, such as bg color of the button.
+ *   It must satisfy the contrast ratio with pure white (#ffffff) text on
+ *   top of it.
+ *
+ * - `XXX-soft`: The color used for subtle background such as custom container
+ *   or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
+ *   on top of it.
+ *
+ *   The soft color must be semi transparent alpha channel. This is crucial
+ *   because it allows adding multiple "soft" colors on top of each other
+ *   to create a accent, such as when having inline code block inside
+ *   custom containers.
+ *
+ * - `default`: The color used purely for subtle indication without any
+ *   special meanings attched to it such as bg color for menu hover state.
+ *
+ * - `brand`: Used for primary brand colors, such as link text, button with
+ *   brand theme, etc.
+ *
+ * - `tip`: Used to indicate useful information. The default theme uses the
+ *   brand color for this by default.
+ *
+ * - `warning`: Used to indicate warning to the users. Used in custom
+ *   container, badges, etc.
+ *
+ * - `danger`: Used to show error, or dangerous message to the users. Used
+ *   in custom container, badges, etc.
+ * -------------------------------------------------------------------------- */
+
+:root {
+  /* --vp-c-indigo-1: #4f69fd; */
+  --vp-c-default-1: var(--vp-c-gray-1);
+  --vp-c-default-2: var(--vp-c-gray-2);
+  --vp-c-default-3: var(--vp-c-gray-3);
+  --vp-c-default-soft: var(--vp-c-gray-soft);
+  --vp-c-brand-1: var(--vp-c-indigo-1);
+  --vp-c-brand-2: var(--vp-c-indigo-2);
+  --vp-c-brand-3: var(--vp-c-indigo-3);
+  --vp-c-brand-soft: var(--vp-c-indigo-soft);
+  --vp-c-tip-1: var(--vp-c-brand-1);
+  --vp-c-tip-2: var(--vp-c-brand-2);
+  --vp-c-tip-3: var(--vp-c-brand-3);
+  --vp-c-tip-soft: var(--vp-c-brand-soft);
+  --vp-c-warning-1: var(--vp-c-yellow-1);
+  --vp-c-warning-2: var(--vp-c-yellow-2);
+  --vp-c-warning-3: var(--vp-c-yellow-3);
+  --vp-c-warning-soft: var(--vp-c-yellow-soft);
+  --vp-c-danger-1: var(--vp-c-red-1);
+  --vp-c-danger-2: var(--vp-c-red-2);
+  --vp-c-danger-3: var(--vp-c-red-3);
+  --vp-c-danger-soft: var(--vp-c-red-soft);
+
+  /**
+ * Component: Button
+ * -------------------------------------------------------------------------- */
+
+  --vp-button-brand-border: transparent;
+  --vp-button-brand-text: var(--vp-c-white);
+  --vp-button-brand-bg: var(--vp-c-brand-3);
+  --vp-button-brand-hover-border: transparent;
+  --vp-button-brand-hover-text: var(--vp-c-white);
+  --vp-button-brand-hover-bg: var(--vp-c-brand-2);
+  --vp-button-brand-active-border: transparent;
+  --vp-button-brand-active-text: var(--vp-c-white);
+  --vp-button-brand-active-bg: var(--vp-c-brand-1);
+
+  /**
+ * Component: Home
+ * -------------------------------------------------------------------------- */
+
+  --vp-home-hero-name-color: transparent;
+  --vp-home-hero-name-background: linear-gradient(
+    120deg,
+    var(--vp-c-indigo-1) 30%,
+    #18cefe
+  );
+  --vp-home-hero-image-background-image: linear-gradient(
+    -45deg,
+    #18cefe 50%,
+    #c279ed 50%
+  );
+  --vp-home-hero-image-filter: blur(44px);
+
+  /**
+ * Component: Custom Block
+ * -------------------------------------------------------------------------- */
+  --vp-custom-block-tip-border: transparent;
+  --vp-custom-block-tip-text: var(--vp-c-text-1);
+  --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
+  --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
+}
+
+@media (min-width: 640px) {
+  :root {
+    --vp-home-hero-image-filter: blur(56px);
+  }
+}
+
+@media (min-width: 960px) {
+  :root {
+    --vp-home-hero-image-filter: blur(68px);
+  }
+}
+
+/**
+ * Component: Algolia
+ * -------------------------------------------------------------------------- */
+
+.DocSearch {
+  --docsearch-primary-color: var(--vp-c-brand-1) !important;
+}
diff --git a/eims-ui/docs/package.json b/eims-ui/docs/package.json
new file mode 100644
index 0000000..e143506
--- /dev/null
+++ b/eims-ui/docs/package.json
@@ -0,0 +1,35 @@
+{
+  "name": "@vben/docs",
+  "version": "5.5.0",
+  "private": true,
+  "scripts": {
+    "build": "vitepress build",
+    "dev": "vitepress dev",
+    "docs:preview": "vitepress preview"
+  },
+  "imports": {
+    "#/*": {
+      "node": "./src/_env/node/*",
+      "default": "./src/_env/*"
+    }
+  },
+  "dependencies": {
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "ant-design-vue": "catalog:",
+    "lucide-vue-next": "catalog:",
+    "medium-zoom": "catalog:",
+    "radix-vue": "catalog:",
+    "vitepress-plugin-group-icons": "catalog:"
+  },
+  "devDependencies": {
+    "@nolebase/vitepress-plugin-git-changelog": "catalog:",
+    "@vben/vite-config": "workspace:*",
+    "@vite-pwa/vitepress": "catalog:",
+    "vitepress": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/docs/src/_env/adapter/component.ts b/eims-ui/docs/src/_env/adapter/component.ts
new file mode 100644
index 0000000..1afa621
--- /dev/null
+++ b/eims-ui/docs/src/_env/adapter/component.ts
@@ -0,0 +1,127 @@
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { globalShareState } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  AutoComplete,
+  Button,
+  Checkbox,
+  CheckboxGroup,
+  DatePicker,
+  Divider,
+  Input,
+  InputNumber,
+  InputPassword,
+  Mentions,
+  notification,
+  Radio,
+  RadioGroup,
+  RangePicker,
+  Rate,
+  Select,
+  Space,
+  Switch,
+  Textarea,
+  TimePicker,
+  TreeSelect,
+  Upload,
+} from 'ant-design-vue';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'AutoComplete'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'DefaultButton'
+  | 'Divider'
+  | 'Input'
+  | 'InputNumber'
+  | 'InputPassword'
+  | 'Mentions'
+  | 'PrimaryButton'
+  | 'Radio'
+  | 'RadioGroup'
+  | 'RangePicker'
+  | 'Rate'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'Textarea'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+
+    AutoComplete,
+    Checkbox,
+    CheckboxGroup,
+    DatePicker,
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'default' }, slots);
+    },
+    Divider,
+    Input: withDefaultPlaceholder(Input, 'input'),
+    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+    Mentions: withDefaultPlaceholder(Mentions, 'input'),
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Radio,
+    RadioGroup,
+    RangePicker,
+    Rate,
+    Select: withDefaultPlaceholder(Select, 'select'),
+    Space,
+    Switch,
+    Textarea: withDefaultPlaceholder(Textarea, 'input'),
+    TimePicker,
+    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+    Upload,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      notification.success({
+        description: content,
+        message: title,
+        placement: 'bottomRight',
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
diff --git a/eims-ui/docs/src/_env/adapter/form.ts b/eims-ui/docs/src/_env/adapter/form.ts
new file mode 100644
index 0000000..67e2483
--- /dev/null
+++ b/eims-ui/docs/src/_env/adapter/form.ts
@@ -0,0 +1,49 @@
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { initComponentAdapter } from './component';
+
+initComponentAdapter();
+setupVbenForm<ComponentType>({
+  config: {
+    baseModelPropName: 'value',
+    // naive-ui缁勪欢涓嶆帴鍙梠nChang浜嬩欢锛屾墍浠ラ渶瑕佺鐢�
+    disabledOnChangeListener: true,
+    // naive-ui缁勪欢鐨勭┖鍊间负null,涓嶈兘鏄痷ndefined锛屽惁鍒欓噸缃〃鍗曟椂涓嶇敓鏁�
+    emptyStateValue: null,
+    modelPropNameMap: {
+      Checkbox: 'checked',
+      Radio: 'checked',
+      Switch: 'checked',
+      Upload: 'fileList',
+    },
+  },
+  defineRules: {
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    selectRequired: (value, _params, ctx) => {
+      if (value === undefined || value === null) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
diff --git a/eims-ui/docs/src/_env/adapter/vxe-table.ts b/eims-ui/docs/src/_env/adapter/vxe-table.ts
new file mode 100644
index 0000000..bab7f3d
--- /dev/null
+++ b/eims-ui/docs/src/_env/adapter/vxe-table.ts
@@ -0,0 +1,70 @@
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { Button, Image } from 'ant-design-vue';
+
+import { useVbenForm } from './form';
+
+if (!import.meta.env.SSR) {
+  setupVbenVxeTable({
+    configVxeTable: (vxeUI) => {
+      vxeUI.setConfig({
+        grid: {
+          align: 'center',
+          border: false,
+          columnConfig: {
+            resizable: true,
+          },
+
+          formConfig: {
+            // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+            enabled: false,
+          },
+          minHeight: 180,
+          proxyConfig: {
+            autoLoad: true,
+            response: {
+              result: 'items',
+              total: 'total',
+              list: 'items',
+            },
+            showActiveMsg: true,
+            showResponseMsg: false,
+          },
+          round: true,
+          showOverflow: true,
+          size: 'small',
+        },
+      });
+
+      // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+      vxeUI.renderer.add('CellImage', {
+        renderTableDefault(_renderOpts, params) {
+          const { column, row } = params;
+          return h(Image, { src: row[column.field] });
+        },
+      });
+
+      // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+      vxeUI.renderer.add('CellLink', {
+        renderTableDefault(renderOpts) {
+          const { props } = renderOpts;
+          return h(
+            Button,
+            { size: 'small', type: 'link' },
+            { default: () => props?.text },
+          );
+        },
+      });
+
+      // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+      // vxeUI.formats.add
+    },
+    useVbenForm,
+  });
+}
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
diff --git a/eims-ui/docs/src/_env/node/adapter/form.ts b/eims-ui/docs/src/_env/node/adapter/form.ts
new file mode 100644
index 0000000..a206c0d
--- /dev/null
+++ b/eims-ui/docs/src/_env/node/adapter/form.ts
@@ -0,0 +1,4 @@
+export const useVbenForm = () => {};
+export const z = {};
+export type VbenFormSchema = any;
+export type VbenFormProps = any;
diff --git a/eims-ui/docs/src/_env/node/adapter/vxe-table.ts b/eims-ui/docs/src/_env/node/adapter/vxe-table.ts
new file mode 100644
index 0000000..5ec409f
--- /dev/null
+++ b/eims-ui/docs/src/_env/node/adapter/vxe-table.ts
@@ -0,0 +1,3 @@
+export type * from '@vben/plugins/vxe-table';
+
+export const useVbenVxeGrid = () => {};
diff --git a/eims-ui/docs/src/commercial/community.md b/eims-ui/docs/src/commercial/community.md
new file mode 100644
index 0000000..c5b7b7d
--- /dev/null
+++ b/eims-ui/docs/src/commercial/community.md
@@ -0,0 +1,30 @@
+# 绀惧尯浜ゆ祦
+
+绀惧尯浜ゆ祦缇や富瑕佹槸涓轰簡鏂逛究澶у浜ゆ祦锛屾彁闂紝瑙g瓟闂锛屽垎浜粡楠岀瓑銆傚亸鑷姪鏂瑰紡锛屽鏋滀綘鏈夐棶棰橈紝鍙互閫氳繃浠ヤ笅鏂瑰紡鍔犲叆绀惧尯浜ゆ祦缇わ細
+
+- [QQ棰戦亾](https://pd.qq.com/s/16p8lvvob)锛氭帹鑽愶紒锛侊紒涓昏鎻愪緵闂瑙g瓟锛屽垎浜粡楠岀瓑銆�
+- QQ缇わ細[澶х兢](https://qm.qq.com/q/MEmHoCLbG0)锛孾1缇(https://qm.qq.com/q/YacMHPYAMu)銆乕2缇(https://qm.qq.com/q/ajVKZvFICk)銆乕3缇(https://qm.qq.com/q/36zdwThP2E)锛孾4缇(https://qm.qq.com/q/sCzSlm3504)锛屼富瑕佷娇鐢ㄨ�呯殑浜ゆ祦缇ゃ��
+- [Discord](https://discord.com/invite/VU62jTecad): 涓昏鎻愪緵闂瑙g瓟锛屽垎浜粡楠岀瓑銆�
+
+::: tip
+
+鍏嶈垂QQ缇や汉鏁颁笂闄�200锛屽皢浼氫笉瀹氭湡娓呯悊銆傛帹鑽愬姞鍏Q棰戦亾杩涜浜ゆ祦
+
+:::
+
+## 寰俊缇�
+
+浣滆�呬富瑕侀�氳繃寰俊缇ゆ彁渚涘府鍔╋紝濡傛灉浣犳湁闂锛屽彲浠ラ�氳繃浠ヤ笅鏂瑰紡鍔犲叆寰俊缇ゃ��
+
+閫氳繃寰俊鑱旂郴浣滆�咃紝娉ㄦ槑鍔犵兢鏉ユ剰锛�
+
+::: tip
+
+鍥犱负寰俊缇や汉鏁版湁闄愬埗锛屽姞寰俊缇よ姹傦細
+
+- 閫氳繃[璧炲姪](../sponsor/personal.md)浠绘剰閲戦銆�
+- 鍙戦�佽禐鍔ー鎴浘`锛屽娉╜鍔犲叆寰俊缇鍗冲彲銆�
+
+:::
+
+<img src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg" style="width: 300px;"/>
diff --git a/eims-ui/docs/src/commercial/customized.md b/eims-ui/docs/src/commercial/customized.md
new file mode 100644
index 0000000..1f0bcec
--- /dev/null
+++ b/eims-ui/docs/src/commercial/customized.md
@@ -0,0 +1,12 @@
+# 瀹氬埗寮�鍙�
+
+鎴戜滑鎻愪緵鍩轰簬 Vben Admin 鐨勬妧鏈敮鎸佹湇鍔″強瀹氬埗寮�鍙戯紝鍩烘湰闇�姹傛垜浠兘鍙互婊¤冻銆�
+
+璇︾粏闇�姹傚彲娣诲姞浣滆�呬簡瑙o紝骞舵敞鏄庢潵鎰忥細
+
+- 閫氳繃閭鑱旂郴寮�鍙戣�咃細 [ann.vben@gmail.com](mailto:ann.vben@gmail.com)
+- 閫氳繃寰俊鑱旂郴寮�鍙戣�咃細
+
+ <img src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg" style="width: 300px;"/>
+
+鎴戜滑浼氬湪绗竴鏃堕棿鍥炲鎮紝瀹氬埗璐圭敤鏍规嵁闇�姹傝�屽畾銆�
diff --git a/eims-ui/docs/src/commercial/technical-support.md b/eims-ui/docs/src/commercial/technical-support.md
new file mode 100644
index 0000000..ded9bf2
--- /dev/null
+++ b/eims-ui/docs/src/commercial/technical-support.md
@@ -0,0 +1,8 @@
+# 鎶�鏈敮鎸�
+
+## 闂鍙嶉
+
+鍦ㄤ娇鐢ㄩ」鐩殑杩囩▼涓紝濡傛灉閬囧埌闂锛屼綘鍙互鍏堣缁嗛槄璇绘湰鏂囨。锛屾湭鎵惧埌瑙e喅鏂规鏃讹紝鍙互閫氳繃浠ヤ笅鏂瑰紡鑾峰彇鎶�鏈敮鎸侊細
+
+- 閫氳繃 [GitHub Issues](https://github.com/vbenjs/vue-vben-admin/issues)
+- 閫氳繃 [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)
diff --git a/eims-ui/docs/src/components/common-ui/vben-api-component.md b/eims-ui/docs/src/components/common-ui/vben-api-component.md
new file mode 100644
index 0000000..f9db74e
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-api-component.md
@@ -0,0 +1,150 @@
+---
+outline: deep
+---
+
+# Vben ApiComponent Api缁勪欢鍖呰鍣�
+
+妗嗘灦鎻愪緵鐨凙PI鈥滃寘瑁呭櫒鈥濓紝瀹冧竴鑸笉鐙珛浣跨敤锛屼富瑕佺敤浜庡寘瑁呭叾瀹冪粍浠讹紝涓虹洰鏍囩粍浠舵彁渚涜嚜鍔ㄨ幏鍙栬繙绋嬫暟鎹殑鑳藉姏锛屼絾浠嶇劧淇濇寔浜嗙洰鏍囩粍浠剁殑鍘熷鐢ㄦ硶銆�
+
+::: info 鍐欏湪鍓嶉潰
+
+鎴戜滑鍦ㄥ悇涓簲鐢ㄧ殑缁勪欢閫傞厤鍣ㄤ腑锛屼娇鐢ˋpiComponent鍖呰浜哠elect銆乀reeSelect缁勪欢锛屼娇寰楄繖浜涚粍浠跺彲浠ヨ嚜鍔ㄨ幏鍙栬繙绋嬫暟鎹苟鐢熸垚閫夐」銆傚叾瀹冪被浼肩殑缁勪欢锛堟瘮濡侰ascader锛夊鏈夐渶瑕佷篃鍙互鍙傝�冪ず渚嬩唬鐮佽嚜琛岃繘琛屽寘瑁呫��
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+閫氳繃 `component` 浼犲叆鍏跺畠缁勪欢鐨勫畾涔夛紝骞堕厤缃浉鍏崇殑鍏跺畠灞炴�э紙涓昏鏄竴浜涘悕绉版槧灏勶級銆傚寘瑁呯粍浠跺皢閫氳繃`api`鑾峰彇鏁版嵁锛坄beforerFetch`銆乣afterFetch`灏嗗垎鍒湪`api`杩愯鍓嶃�佽繍琛屽悗琚皟鐢級锛屼娇鐢╜resultField`浠庝腑鎻愬彇鏁扮粍锛屼娇鐢╜valueField`銆乣labelField`绛夋潵浠庢暟鎹腑鎻愬彇value鍜宭abel锛堝鏋滄彁渚涗簡`childrenField`锛屼細灏嗗叾浣滀负鏍戝舰缁撴瀯閫掑綊澶勭悊姣忎竴绾ф暟鎹級锛屼箣鍚庡皢澶勭悊濂界殑鏁版嵁閫氳繃`optionsPropName`鎸囧畾鐨勫睘鎬т紶閫掔粰鐩爣缁勪欢銆�
+
+::: details 鍖呰绾ц仈閫夋嫨鍣�,鐐瑰嚮涓嬫媺鏃跺紑濮嬪姞杞借繙绋嬫暟鎹�
+
+```vue
+<script lang="ts" setup>
+import { ApiComponent } from '@vben/common-ui';
+
+import { Cascader } from 'ant-design-vue';
+
+const treeData: Record<string, any> = [
+  {
+    label: '娴欐睙',
+    value: 'zhejiang',
+    children: [
+      {
+        value: 'hangzhou',
+        label: '鏉窞',
+        children: [
+          {
+            value: 'xihu',
+            label: '瑗挎箹',
+          },
+          {
+            value: 'sudi',
+            label: '鑻忓牑',
+          },
+        ],
+      },
+      {
+        value: 'jiaxing',
+        label: '鍢夊叴',
+        children: [
+          {
+            value: 'wuzhen',
+            label: '涔岄晣',
+          },
+          {
+            value: 'meihuazhou',
+            label: '姊呰姳娲�',
+          },
+        ],
+      },
+      {
+        value: 'zhoushan',
+        label: '鑸熷北',
+        children: [
+          {
+            value: 'putuoshan',
+            label: '鏅檧灞�',
+          },
+          {
+            value: 'taohuadao',
+            label: '妗冭姳宀�',
+          },
+        ],
+      },
+    ],
+  },
+  {
+    label: '姹熻嫃',
+    value: 'jiangsu',
+    children: [
+      {
+        value: 'nanjing',
+        label: '鍗椾含',
+        children: [
+          {
+            value: 'zhonghuamen',
+            label: '涓崕闂�',
+          },
+          {
+            value: 'zijinshan',
+            label: '绱噾灞�',
+          },
+          {
+            value: 'yuhuatai',
+            label: '闆ㄨ姳鍙�',
+          },
+        ],
+      },
+    ],
+  },
+];
+/**
+ * 妯℃嫙璇锋眰鎺ュ彛
+ */
+function fetchApi(): Promise<Record<string, any>> {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(treeData);
+    }, 1000);
+  });
+}
+</script>
+<template>
+  <ApiComponent
+    :api="fetchApi"
+    :component="Cascader"
+    :immediate="false"
+    children-field="children"
+    loading-slot="suffixIcon"
+    visible-event="onDropdownVisibleChange"
+  />
+</template>
+```
+
+:::
+
+### Props
+
+| 灞炴�у悕 | 鎻忚堪 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| component | 娆插寘瑁呯殑缁勪欢 | `Component` | - |
+| numberToString | 鏄惁灏唙alue浠庢暟瀛楄浆涓簊tring | `boolean` | `false` |
+| api | 鑾峰彇鏁版嵁鐨勫嚱鏁� | `(arg?: any) => Promise<OptionsItem[] \| Record<string, any>>` | - |
+| params | 浼犻�掔粰api鐨勫弬鏁� | `Record<string, any>` | - |
+| resultField | 浠巃pi杩斿洖鐨勭粨鏋滀腑鎻愬彇options鏁扮粍鐨勫瓧娈靛悕 | `string` | - |
+| labelField | label瀛楁鍚� | `string` | `label` |
+| childrenField | 瀛愮骇鏁版嵁瀛楁鍚嶏紝闇�瑕佸眰绾ф暟鎹殑缁勪欢鍙敤 | `string` | `` |
+| valueField | value瀛楁鍚� | `string` | `value` |
+| optionsPropName | 缁勪欢鎺ユ敹options鏁版嵁鐨勫睘鎬у悕绉� | `string` | `options` |
+| modelPropName | 缁勪欢鐨勫弻鍚戠粦瀹氬睘鎬у悕锛岄粯璁や负modelValue銆傞儴鍒嗙粍浠跺彲鑳戒负value | `string` | `modelValue` |
+| immediate | 鏄惁绔嬪嵆璋冪敤api | `boolean` | `true` |
+| alwaysLoad | 姣忔`visibleEvent`浜嬩欢鍙戠敓鏃堕兘閲嶆柊璇锋眰鏁版嵁 | `boolean` | `false` |
+| beforeFetch | 鍦╝pi璇锋眰涔嬪墠鐨勫洖璋冨嚱鏁� | `AnyPromiseFunction<any, any>` | - |
+| afterFetch | 鍦╝pi璇锋眰涔嬪悗鐨勫洖璋冨嚱鏁� | `AnyPromiseFunction<any, any>` | - |
+| options | 鐩存帴浼犲叆閫夐」鏁版嵁锛屼篃浣滀负api杩斿洖绌烘暟鎹椂鐨勫悗澶囨暟鎹� | `OptionsItem[]` | - |
+| visibleEvent | 瑙﹀彂閲嶆柊璇锋眰鏁版嵁鐨勪簨浠跺悕 | `string` | - |
+| loadingSlot | 缁勪欢鐨勬彃妲藉悕绉帮紝鐢ㄦ潵鏄剧ず涓�涓�"鍔犺浇涓�"鐨勫浘鏍� | `string` | - |
+
+```
+
+```
diff --git a/eims-ui/docs/src/components/common-ui/vben-count-to-animator.md b/eims-ui/docs/src/components/common-ui/vben-count-to-animator.md
new file mode 100644
index 0000000..301e1a4
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-count-to-animator.md
@@ -0,0 +1,52 @@
+---
+outline: deep
+---
+
+# Vben CountToAnimator 鏁板瓧鍔ㄧ敾
+
+妗嗘灦鎻愪緵鐨勬暟瀛楀姩鐢荤粍浠讹紝鏀寔鏁板瓧鍔ㄧ敾鏁堟灉銆�
+
+> 濡傛灉鏂囨。鍐呮病鏈夊弬鏁拌鏄庯紝鍙互灏濊瘯鍦ㄥ湪绾跨ず渚嬪唴瀵绘壘
+
+::: info 鍐欏湪鍓嶉潰
+
+濡傛灉浣犺寰楃幇鏈夌粍浠剁殑灏佽涓嶅鐞嗘兂锛屾垨鑰呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+閫氳繃 `start-val` 鍜� `end-val`璁剧疆鏁板瓧鍔ㄧ敾鐨勫紑濮嬪�煎拰缁撴潫鍊硷紝 鎸佺画鏃堕棿`3000`ms銆�
+
+<DemoPreview dir="demos/vben-count-to-animator/basic" />
+
+## 鑷畾涔夊墠缂�鍙婂垎闅旂
+
+閫氳繃 `prefix` 鍜� `separator` 璁剧疆鏁板瓧鍔ㄧ敾鐨勫墠缂�鍜屽垎闅旂銆�
+
+<DemoPreview dir="demos/vben-count-to-animator/custom" />
+
+### Props
+
+| 灞炴�у悕     | 鎻忚堪           | 绫诲瀷      | 榛樿鍊�   |
+| ---------- | -------------- | --------- | -------- |
+| startVal   | 璧峰鍊�         | `number`  | `0`      |
+| endVal     | 缁撴潫鍊�         | `number`  | `2021`   |
+| duration   | 鍔ㄧ敾鎸佺画鏃堕棿   | `number`  | `1500`   |
+| autoplay   | 鑷姩鎵ц       | `boolean` | `true`   |
+| prefix     | 鍓嶇紑           | `string`  | -        |
+| suffix     | 鍚庣紑           | `string`  | -        |
+| separator  | 鍒嗛殧绗�         | `string`  | `,`      |
+| color      | 瀛椾綋棰滆壊       | `string`  | -        |
+| useEasing  | 鏄惁寮�鍚姩鐢�   | `boolean` | `true`   |
+| transition | 鍔ㄧ敾鏁堟灉       | `string`  | `linear` |
+| decimals   | 淇濈暀灏忔暟鐐逛綅鏁� | `number`  | `0`      |
+
+### Methods
+
+浠ヤ笅浜嬩欢锛屽彧鏈夊湪 `useVbenModal({onCancel:()=>{}})` 涓紶鍏ユ墠浼氱敓鏁堛��
+
+| 浜嬩欢鍚� | 鎻忚堪         | 绫诲瀷       |
+| ------ | ------------ | ---------- |
+| start  | 寮�濮嬫墽琛屽姩鐢� | `()=>void` |
+| reset  | 閲嶇疆         | `()=>void` |
diff --git a/eims-ui/docs/src/components/common-ui/vben-drawer.md b/eims-ui/docs/src/components/common-ui/vben-drawer.md
new file mode 100644
index 0000000..7091570
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-drawer.md
@@ -0,0 +1,137 @@
+---
+outline: deep
+---
+
+# Vben Drawer 鎶藉眽
+
+妗嗘灦鎻愪緵鐨勬娊灞夌粍浠讹紝鏀寔`鑷姩楂樺害`銆乣loading`绛夊姛鑳姐��
+
+> 濡傛灉鏂囨。鍐呮病鏈夊弬鏁拌鏄庯紝鍙互灏濊瘯鍦ㄥ湪绾跨ず渚嬪唴瀵绘壘
+
+::: info 鍐欏湪鍓嶉潰
+
+濡傛灉浣犺寰楃幇鏈夌粍浠剁殑灏佽涓嶅鐞嗘兂锛屾垨鑰呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+::: tip README
+
+涓嬫柟绀轰緥浠g爜涓殑锛屽瓨鍦ㄤ竴浜涘浗闄呭寲銆佷富棰樿壊鏈�傞厤闂锛岃繖浜涢棶棰樺彧鍦ㄦ枃妗e唴浼氬嚭鐜帮紝瀹為檯浣跨敤骞朵笉浼氭湁杩欎簺闂锛屽彲蹇界暐锛屼笉蹇呯籂缁撱��
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+浣跨敤 `useVbenDrawer` 鍒涘缓鏈�鍩虹鐨勬ā鎬佹銆�
+
+<DemoPreview dir="demos/vben-drawer/basic" />
+
+## 缁勪欢鎶界
+
+Drawer 鍐呯殑鍐呭涓�鑸笟鍔′腑锛屼細姣旇緝澶嶆潅锛屾墍浠ユ垜浠彲浠ュ皢 drawer 鍐呯殑鍐呭鎶界鍑烘潵锛屼篃鏂逛究澶嶇敤銆傞�氳繃 `connectedComponent` 鍙傛暟锛屽彲浠ュ皢鍐呭缁勪欢杩涜杩炴帴锛岃�屼笉鐢ㄥ叾浠栦换浣曟搷浣溿��
+
+<DemoPreview dir="demos/vben-drawer/extra" />
+
+## 鑷姩璁$畻楂樺害
+
+寮圭獥浼氳嚜鍔ㄨ绠楀唴瀹归珮搴︼紝瓒呰繃涓�瀹氶珮搴︿細鍑虹幇婊氬姩鏉★紝鍚屾椂缁撳悎 `loading` 鏁堟灉浠ュ強浣跨敤 `prepend-footer` 鎻掓Ы銆�
+
+<DemoPreview dir="demos/vben-drawer/auto-height" />
+
+## 浣跨敤 Api
+
+閫氳繃 `drawerApi` 鍙互璋冪敤 drawer 鐨勬柟娉曚互鍙婁娇鐢� `setState` 鏇存柊 drawer 鐨勭姸鎬併��
+
+<DemoPreview dir="demos/vben-drawer/dynamic" />
+
+## 鏁版嵁鍏变韩
+
+濡傛灉浣犱娇鐢ㄤ簡 `connectedComponent` 鍙傛暟锛岄偅涔堝唴澶栫粍浠朵細鍏变韩鏁版嵁锛屾瘮濡備竴浜涜〃鍗曞洖濉瓑鎿嶄綔銆傚彲浠ョ敤 `drawerApi` 鏉ヨ幏鍙栨暟鎹拰璁剧疆鏁版嵁锛岄厤鍚� `onOpenChange`锛屽彲浠ユ弧瓒冲ぇ閮ㄥ垎鐨勯渶姹傘��
+
+<DemoPreview dir="demos/vben-drawer/shared-data" />
+
+::: info 娉ㄦ剰
+
+- `VbenDrawer` 缁勪欢瀵逛笌鍙傛暟鐨勫鐞嗕紭鍏堢骇鏄� `slot` > `props` > `state`(閫氳繃api鏇存柊鐨勭姸鎬佷互鍙妘seVbenDrawer鍙傛暟)銆傚鏋滀綘宸茬粡浼犲叆浜� `slot` 鎴栬�� `props`锛岄偅涔� `setState` 灏嗕笉浼氱敓鏁堬紝杩欑鎯呭喌涓嬩綘鍙互閫氳繃 `slot` 鎴栬�� `props` 鏉ユ洿鏂扮姸鎬併��
+- 濡傛灉浣犱娇鐢ㄥ埌浜� `connectedComponent` 鍙傛暟锛岄偅涔堜細瀛樺湪 2 涓猔useVbenDrawer`, 姝ゆ椂锛屽鏋滃悓鏃惰缃簡鐩稿悓鐨勫弬鏁帮紝閭d箞浠ュ唴閮ㄤ负鍑嗭紙涔熷氨鏄病鏈夎缃� connectedComponent 鐨勪唬鐮侊級銆傛瘮濡� 鍚屾椂璁剧疆浜� `onConfirm`锛岄偅涔堜互鍐呴儴鐨� `onConfirm` 涓哄噯銆俙onOpenChange`浜嬩欢闄ゅ锛屽唴澶栭兘浼氳Е鍙戙��
+
+:::
+
+## API
+
+```ts
+// Drawer 涓哄脊绐楃粍浠�
+// drawerApi 涓哄脊绐楃殑鏂规硶
+const [Drawer, drawerApi] = useVbenDrawer({
+  // 灞炴��
+  // 浜嬩欢
+});
+```
+
+### Props
+
+鎵�鏈夊睘鎬ч兘鍙互浼犲叆 `useVbenDrawer` 鐨勭涓�涓弬鏁颁腑銆�
+
+| 灞炴�у悕 | 鎻忚堪 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| appendToMain | 鏄惁鎸傝浇鍒板唴瀹瑰尯鍩燂紙榛樿鎸傝浇鍒癰ody锛� | `boolean` | `false` |
+| title | 鏍囬 | `string\|slot` | - |
+| titleTooltip | 鏍囬鎻愮ず淇℃伅 | `string\|slot` | - |
+| description | 鎻忚堪淇℃伅 | `string\|slot` | - |
+| isOpen | 寮圭獥鎵撳紑鐘舵�� | `boolean` | `false` |
+| loading | 寮圭獥鍔犺浇鐘舵�� | `boolean` | `false` |
+| closable | 鏄剧ず鍏抽棴鎸夐挳 | `boolean` | `true` |
+| modal | 鏄剧ず閬僵 | `boolean` | `true` |
+| header | 鏄剧ずheader | `boolean` | `true` |
+| footer | 鏄剧ずfooter | `boolean\|slot` | `true` |
+| confirmLoading | 纭鎸夐挳loading鐘舵�� | `boolean` | `false` |
+| closeOnClickModal | 鐐瑰嚮閬僵鍏抽棴寮圭獥 | `boolean` | `true` |
+| closeOnPressEscape | esc 鍏抽棴寮圭獥 | `boolean` | `true` |
+| confirmText | 纭鎸夐挳鏂囨湰 | `string\|slot` | `纭` |
+| cancelText | 鍙栨秷鎸夐挳鏂囨湰 | `string\|slot` | `鍙栨秷` |
+| placement | 鎶藉眽寮瑰嚭浣嶇疆 | `'left'\|'right'\|'top'\|'bottom'` | `right` |
+| showCancelButton | 鏄剧ず鍙栨秷鎸夐挳 | `boolean` | `true` |
+| showConfirmButton | 鏄剧ず纭鎸夐挳鏂囨湰 | `boolean` | `true` |
+| class | modal鐨刢lass锛屽搴﹂�氳繃杩欎釜閰嶇疆 | `string` | - |
+| contentClass | modal鍐呭鍖哄煙鐨刢lass | `string` | - |
+| footerClass | modal搴曢儴鍖哄煙鐨刢lass | `string` | - |
+| headerClass | modal椤堕儴鍖哄煙鐨刢lass | `string` | - |
+| zIndex | 鎶藉眽鐨刏Index灞傜骇 | `number` | `1000` |
+
+::: info appendToMain
+
+`appendToMain`鍙互鎸囧畾灏嗘娊灞夋寕杞藉埌鍐呭鍖哄煙锛屾墦寮�鎶藉眽鏃讹紝鍐呭鍖哄煙浠ュ鐨勯儴鍒嗭紙鏍囩鏍忋�佸鑸彍鍗曠瓑绛夛級涓嶄細琚伄鎸°�傞粯璁ゆ儏鍐典笅锛屾娊灞変細鎸傝浇鍒癰ody涓娿�備絾鏄細鎸傝浇鍒板唴瀹瑰尯鍩熸椂锛屼綔涓洪〉闈㈡牴瀹瑰櫒鐨刞Page`缁勪欢锛岄渶瑕佽缃甡auto-content-height`灞炴�э紝浠ヤ究鎶藉眽鑳藉姝g‘璁$畻楂樺害銆�
+
+:::
+
+### Event
+
+浠ヤ笅浜嬩欢锛屽彧鏈夊湪 `useVbenDrawer({onCancel:()=>{}})` 涓紶鍏ユ墠浼氱敓鏁堛��
+
+| 浜嬩欢鍚� | 鎻忚堪 | 绫诲瀷 |
+| --- | --- | --- |
+| onBeforeClose | 鍏抽棴鍓嶈Е鍙戯紝杩斿洖 `false`鍒欑姝㈠叧闂� | `()=>boolean` |
+| onCancel | 鐐瑰嚮鍙栨秷鎸夐挳瑙﹀彂 | `()=>void` |
+| onConfirm | 鐐瑰嚮纭鎸夐挳瑙﹀彂 | `()=>void` |
+| onOpenChange | 鍏抽棴鎴栬�呮墦寮�寮圭獥鏃惰Е鍙� | `(isOpen:boolean)=>void` |
+
+### Slots
+
+闄や簡涓婇潰鐨勫睘鎬х被鍨嬪寘鍚玚slot`锛岃繕鍙互閫氳繃鎻掓Ы鏉ヨ嚜瀹氫箟寮圭獥鐨勫唴瀹广��
+
+| 鎻掓Ы鍚�         | 鎻忚堪                |
+| -------------- | ------------------- |
+| default        | 榛樿鎻掓Ы - 寮圭獥鍐呭 |
+| prepend-footer | 鍙栨秷鎸夐挳宸︿晶        |
+| append-footer  | 鍙栨秷鎸夐挳鍙充晶        |
+
+### modalApi
+
+| 浜嬩欢鍚� | 鎻忚堪 | 绫诲瀷 |
+| --- | --- | --- |
+| setState | 鍔ㄦ�佽缃脊绐楃姸鎬佸睘鎬� | `setState(props) \| setState((prev)=>(props))` |
+| open | 鎵撳紑寮圭獥 | `()=>void` |
+| close | 鍏抽棴寮圭獥 | `()=>void` |
+| setData | 璁剧疆鍏变韩鏁版嵁 | `<T>(data:T)=>void` |
+| getData | 鑾峰彇鍏变韩鏁版嵁 | `<T>()=>T` |
+| useStore | 鑾峰彇鍙搷搴斿紡鐘舵�� | - |
diff --git a/eims-ui/docs/src/components/common-ui/vben-form.md b/eims-ui/docs/src/components/common-ui/vben-form.md
new file mode 100644
index 0000000..618e3d3
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-form.md
@@ -0,0 +1,524 @@
+---
+outline: deep
+---
+
+# Vben Form 琛ㄥ崟
+
+妗嗘灦鎻愪緵鐨勮〃鍗曠粍浠讹紝鍙�傞厤 `Element Plus`銆乣Ant Design Vue`銆乣Naive UI` 绛夋鏋躲��
+
+> 濡傛灉鏂囨。鍐呮病鏈夊弬鏁拌鏄庯紝鍙互灏濊瘯鍦ㄥ湪绾跨ず渚嬪唴瀵绘壘
+
+::: info 鍐欏湪鍓嶉潰
+
+濡傛灉浣犺寰楃幇鏈夌粍浠剁殑灏佽涓嶅鐞嗘兂锛屾垨鑰呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+## 閫傞厤鍣�
+
+琛ㄥ崟搴曞眰浣跨敤 [vee-validate](https://vee-validate.logaretm.com/v4/) 杩涜琛ㄥ崟楠岃瘉锛屾墍浠ヤ綘鍙互浣跨敤 `vee-validate` 鐨勬墍鏈夊姛鑳姐�傚浜庝笉鍚岀殑 UI 妗嗘灦锛屾垜浠彁渚涗簡閫傞厤鍣紝浠ヤ究鏇村ソ鐨勯�傞厤涓嶅悓鐨� UI 妗嗘灦銆�
+
+### 閫傞厤鍣ㄨ鏄�
+
+姣忎釜搴旂敤閮芥湁涓嶅悓鐨� UI 妗嗘灦锛屾墍浠ュ湪搴旂敤鐨� `src/adapter/form` 鍜� `src/adapter/component` 鍐呴儴锛屼綘鍙互鏍规嵁鑷繁鐨勯渶姹傦紝杩涜缁勪欢閫傞厤銆備笅闈㈡槸 `Ant Design Vue` 鐨勯�傞厤鍣ㄧず渚嬩唬鐮侊紝鍙牴鎹敞閲婃煡鐪嬭鏄庯細
+
+::: details ant design vue 琛ㄥ崟閫傞厤鍣�
+
+```ts
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+setupVbenForm<ComponentType>({
+  config: {
+    // ant design vue缁勪欢搴撻粯璁ら兘鏄� v-model:value
+    baseModelPropName: 'value',
+    // 涓�浜涚粍浠舵槸 v-model:checked 鎴栬�� v-model:fileList
+    modelPropNameMap: {
+      Checkbox: 'checked',
+      Radio: 'checked',
+      Switch: 'checked',
+      Upload: 'fileList',
+    },
+  },
+  defineRules: {
+    // 杈撳叆椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    // 閫夋嫨椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    selectRequired: (value, _params, ctx) => {
+      if (value === undefined || value === null) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
+```
+
+:::
+
+::: details ant design vue 缁勪欢閫傞厤鍣�
+
+```ts
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { globalShareState, IconPicker } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  AutoComplete,
+  Button,
+  Checkbox,
+  CheckboxGroup,
+  DatePicker,
+  Divider,
+  Input,
+  InputNumber,
+  InputPassword,
+  Mentions,
+  notification,
+  Radio,
+  RadioGroup,
+  RangePicker,
+  Rate,
+  Select,
+  Space,
+  Switch,
+  Textarea,
+  TimePicker,
+  TreeSelect,
+  Upload,
+} from 'ant-design-vue';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'AutoComplete'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'DefaultButton'
+  | 'Divider'
+  | 'Input'
+  | 'InputNumber'
+  | 'InputPassword'
+  | 'Mentions'
+  | 'PrimaryButton'
+  | 'Radio'
+  | 'RadioGroup'
+  | 'RangePicker'
+  | 'Rate'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'Textarea'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | 'IconPicker';
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+
+    AutoComplete,
+    Checkbox,
+    CheckboxGroup,
+    DatePicker,
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'default' }, slots);
+    },
+    Divider,
+    IconPicker,
+    Input: withDefaultPlaceholder(Input, 'input'),
+    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+    Mentions: withDefaultPlaceholder(Mentions, 'input'),
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Radio,
+    RadioGroup,
+    RangePicker,
+    Rate,
+    Select: withDefaultPlaceholder(Select, 'select'),
+    Space,
+    Switch,
+    Textarea: withDefaultPlaceholder(Textarea, 'input'),
+    TimePicker,
+    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+    Upload,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      notification.success({
+        description: content,
+        message: title,
+        placement: 'bottomRight',
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
+```
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+::: tip README
+
+涓嬫柟绀轰緥浠g爜涓殑锛屽瓨鍦ㄤ竴浜涘浗闄呭寲銆佷富棰樿壊鏈�傞厤闂锛岃繖浜涢棶棰樺彧鍦ㄦ枃妗e唴浼氬嚭鐜帮紝瀹為檯浣跨敤骞朵笉浼氭湁杩欎簺闂锛屽彲蹇界暐锛屼笉蹇呯籂缁撱��
+
+:::
+
+浣跨敤 `useVbenForm` 鍒涘缓鏈�鍩虹鐨勮〃鍗曘��
+
+<DemoPreview dir="demos/vben-form/basic" />
+
+## 鏌ヨ琛ㄥ崟
+
+鏌ヨ琛ㄥ崟鏄竴绉嶇壒娈婄殑琛ㄥ崟锛岀敤浜庢煡璇㈡暟鎹�傛煡璇㈣〃鍗曚笉浼氳Е鍙戣〃鍗曢獙璇侊紝鍙細瑙﹀彂鏌ヨ浜嬩欢銆�
+
+<DemoPreview dir="demos/vben-form/query" />
+
+## 琛ㄥ崟鏍¢獙
+
+琛ㄥ崟鏍¢獙鏄竴涓潪甯搁噸瑕佺殑鍔熻兘锛屽彲浠ラ�氳繃 `rules` 灞炴�ц繘琛屾牎楠屻��
+
+<DemoPreview dir="demos/vben-form/rules" />
+
+## 琛ㄥ崟鑱斿姩
+
+琛ㄥ崟鑱斿姩鏄竴涓潪甯稿父瑙佺殑鍔熻兘锛屽彲浠ラ�氳繃 `dependencies` 灞炴�ц繘琛岃仈鍔ㄣ��
+
+_娉ㄦ剰_ 闇�瑕佹寚瀹� `dependencies` 鐨� `triggerFields` 灞炴�э紝璁剧疆鐢辫皝鐨勬敼鍔ㄦ潵瑙﹀彂锛屼互渚胯〃鍗曠粍浠惰兘澶熸纭殑鑱斿姩銆�
+
+<DemoPreview dir="demos/vben-form/dynamic" />
+
+## 鑷畾涔夌粍浠�
+
+濡傛灉浣犵殑涓氬姟缁勪欢搴撴病鏈夋彁渚涙煇涓粍浠讹紝浣犲彲浠ヨ嚜琛屽皝瑁呬竴涓粍浠讹紝鐒跺悗鍔犲埌琛ㄥ崟鍐呴儴銆�
+
+<DemoPreview dir="demos/vben-form/custom" />
+
+## 鎿嶄綔
+
+涓�浜涘父瑙佺殑琛ㄥ崟鎿嶄綔銆�
+
+<DemoPreview dir="demos/vben-form/api" />
+
+## API
+
+`useVbenForm` 杩斿洖涓�涓暟缁勶紝绗竴涓厓绱犳槸琛ㄥ崟缁勪欢锛岀浜屼釜鍏冪礌鏄〃鍗曠殑鏂规硶銆�
+
+```vue
+<script setup lang="ts">
+import { useVbenForm } from '#/adapter/form';
+
+// Form 涓哄脊绐楃粍浠�
+// formApi 涓哄脊绐楃殑鏂规硶
+const [Form, formApi] = useVbenForm({
+  // 灞炴��
+  // 浜嬩欢
+});
+</script>
+
+<template>
+  <Form />
+</template>
+```
+
+### FormApi
+
+useVbenForm 杩斿洖鐨勭浜屼釜鍙傛暟锛屾槸涓�涓璞★紝鍖呭惈浜嗕竴浜涜〃鍗曠殑鏂规硶銆�
+
+| 鏂规硶鍚� | 鎻忚堪 | 绫诲瀷 |
+| --- | --- | --- |
+| submitForm | 鎻愪氦琛ㄥ崟 | `(e:Event)=>Promise<Record<string,any>>` |
+| validateAndSubmitForm | 鎻愪氦骞舵牎楠岃〃鍗� | `(e:Event)=>Promise<Record<string,any>>` |
+| resetForm | 閲嶇疆琛ㄥ崟 | `()=>Promise<void>` |
+| setValues | 璁剧疆琛ㄥ崟鍊�, 榛樿浼氳繃婊や笉鍦╯chema涓畾涔夌殑field, 鍙�氳繃filterFields褰㈠弬鍏抽棴杩囨护 | `(fields: Record<string, any>, filterFields?: boolean, shouldValidate?: boolean) => Promise<void>` |
+| getValues | 鑾峰彇琛ㄥ崟鍊� | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
+| validate | 琛ㄥ崟鏍¢獙 | `()=>Promise<void>` |
+| resetValidate | 閲嶇疆琛ㄥ崟鏍¢獙 | `()=>Promise<void>` |
+| updateSchema | 鏇存柊formSchema | `(schema:FormSchema[])=>void` |
+| setFieldValue | 璁剧疆瀛楁鍊� | `(field: string, value: any, shouldValidate?: boolean)=>Promise<void>` |
+| setState | 璁剧疆缁勪欢鐘舵�侊紙props锛� | `(stateOrFn:\| ((prev: VbenFormProps) => Partial<VbenFormProps>)\| Partial<VbenFormProps>)=>Promise<void>` |
+| getState | 鑾峰彇缁勪欢鐘舵�侊紙props锛� | `()=>Promise<VbenFormProps>` |
+| form | 琛ㄥ崟瀵硅薄瀹炰緥锛屽彲浠ユ搷浣滆〃鍗曪紝瑙� [useForm](https://vee-validate.logaretm.com/v4/api/use-form/) | - |
+
+## Props
+
+鎵�鏈夊睘鎬ч兘鍙互浼犲叆 `useVbenForm` 鐨勭涓�涓弬鏁颁腑銆�
+
+| 灞炴�у悕 | 鎻忚堪 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| layout | 琛ㄥ崟椤瑰竷灞� | `'horizontal' \| 'vertical'` | `horizontal` |
+| showCollapseButton | 鏄惁鏄剧ず鎶樺彔鎸夐挳 | `boolean` | `false` |
+| wrapperClass | 琛ㄥ崟鐨勫竷灞�锛屽熀浜巘ailwindcss | `any` | - |
+| actionWrapperClass | 琛ㄥ崟鎿嶄綔鍖哄煙class | `any` | - |
+| handleReset | 琛ㄥ崟閲嶇疆鍥炶皟 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
+| handleSubmit | 琛ㄥ崟鎻愪氦鍥炶皟 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
+| handleValuesChange | 琛ㄥ崟鍊煎彉鍖栧洖璋� | `(values: Record<string, any>,) => void` | - |
+| actionButtonsReverse | 璋冩崲鎿嶄綔鎸夐挳浣嶇疆 | `boolean` | `false` |
+| resetButtonOptions | 閲嶇疆鎸夐挳缁勪欢鍙傛暟 | `ActionButtonOptions` | - |
+| submitButtonOptions | 鎻愪氦鎸夐挳缁勪欢鍙傛暟 | `ActionButtonOptions` | - |
+| showDefaultActions | 鏄惁鏄剧ず榛樿鎿嶄綔鎸夐挳 | `boolean` | `true` |
+| collapsed | 鏄惁鎶樺彔锛屽湪`鏄惁灞曞紑锛屽湪showCollapseButton=true`鏃剁敓鏁� | `boolean` | `false` |
+| collapseTriggerResize | 鎶樺彔鏃讹紝瑙﹀彂`resize`浜嬩欢 | `boolean` | `false` |
+| collapsedRows | 鎶樺彔鏃朵繚鎸佺殑琛屾暟 | `number` | `1` |
+| fieldMappingTime | 鐢ㄤ簬灏嗚〃鍗曞唴鏃堕棿鍖哄煙鐨勫簲璁炬垚 2 涓瓧娈� | `[string, [string, string], string?][]` | - |
+| commonConfig | 琛ㄥ崟椤圭殑閫氱敤閰嶇疆锛屾瘡涓厤缃兘浼氫紶閫掑埌姣忎釜琛ㄥ崟椤癸紝琛ㄥ崟椤瑰彲瑕嗙洊 | `FormCommonConfig` | - |
+| schema | 琛ㄥ崟椤圭殑姣忎竴椤归厤缃� | `FormSchema` | - |
+| submitOnEnter | 鎸変笅鍥炶溅鍋ユ椂鎻愪氦琛ㄥ崟 | `boolean` | false |
+| submitOnChange | 瀛楁鍊兼敼鍙樻椂鎻愪氦琛ㄥ崟 | `boolean` | false |
+
+### TS 绫诲瀷璇存槑
+
+::: details ActionButtonOptions
+
+```ts
+export interface ActionButtonOptions {
+  /** 鏍峰紡 */
+  class?: ClassType;
+  /** 鏄惁绂佺敤 */
+  disabled?: boolean;
+  /** 鏄惁鍔犺浇涓� */
+  loading?: boolean;
+  /** 鎸夐挳澶у皬 */
+  size?: ButtonVariantSize;
+  /** 鎸夐挳绫诲瀷 */
+  variant?: ButtonVariants;
+  /** 鏄惁鏄剧ず */
+  show?: boolean;
+  /** 鎸夐挳鏂囨湰 */
+  text?: string;
+  /** 浠绘剰灞炴�� */
+  [key: string]: any;
+}
+```
+
+:::
+
+::: details FormCommonConfig
+
+```ts
+export interface FormCommonConfig {
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刾rops
+   */
+  componentProps?: ComponentProps;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬帶浠舵牱寮�
+   */
+  controlClass?: string;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勭鐢ㄧ姸鎬�
+   * @default false
+   */
+  disabled?: boolean;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬帶浠舵牱寮�
+   * @default {}
+   */
+  formFieldProps?: Partial<typeof Field>;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬爡鏍煎竷灞�
+   * @default ""
+   */
+  formItemClass?: string;
+  /**
+   * 闅愯棌鎵�鏈夎〃鍗曢」label
+   * @default false
+   */
+  hideLabel?: boolean;
+  /**
+   * 鏄惁闅愯棌蹇呭~鏍囪
+   * @default false
+   */
+  hideRequiredMark?: boolean;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刲abel鏍峰紡
+   * @default ""
+   */
+  labelClass?: string;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刲abel瀹藉害
+   */
+  labelWidth?: number;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨剋rapper鏍峰紡
+   */
+  wrapperClass?: string;
+}
+```
+
+:::
+
+::: details FormSchema
+
+```ts
+export interface FormSchema<
+  T extends BaseFormComponentType = BaseFormComponentType,
+> extends FormCommonConfig {
+  /** 缁勪欢 */
+  component: Component | T;
+  /** 缁勪欢鍙傛暟 */
+  componentProps?: ComponentProps;
+  /** 榛樿鍊� */
+  defaultValue?: any;
+  /** 渚濊禆 */
+  dependencies?: FormItemDependencies;
+  /** 鎻忚堪 */
+  description?: string;
+  /** 瀛楁鍚� */
+  fieldName: string;
+  /** 甯姪淇℃伅 */
+  help?: string;
+  /** 琛ㄥ崟椤� */
+  label?: string;
+  /** 鑷畾涔夌粍浠跺唴閮ㄦ覆鏌�  */
+  renderComponentContent?: RenderComponentContentType;
+  /** 瀛楁瑙勫垯 */
+  rules?: FormSchemaRuleType;
+  /** 鍚庣紑 */
+  suffix?: CustomRenderType;
+}
+```
+
+:::
+
+### 琛ㄥ崟鑱斿姩
+
+琛ㄥ崟鑱斿姩闇�瑕侀�氳繃 schema 鍐呯殑 `dependencies` 灞炴�ц繘琛岃仈鍔紝鍏佽鎮ㄦ坊鍔犲瓧娈典箣闂寸殑渚濊禆椤癸紝浠ユ牴鎹叾浠栧瓧娈电殑鍊兼帶鍒跺瓧娈点��
+
+```ts
+dependencies: {
+  // 鍙湁褰� name 瀛楁鐨勫�煎彉鍖栨椂锛屾墠浼氳Е鍙戣仈鍔�
+  triggerFields: ['name'],
+  // 鍔ㄦ�佸垽鏂綋鍓嶅瓧娈垫槸鍚﹂渶瑕佹樉绀猴紝涓嶆樉绀哄垯鐩存帴閿�姣�
+  if(values,formApi){},
+  // 鍔ㄦ�佸垽鏂綋鍓嶅瓧娈垫槸鍚﹂渶瑕佹樉绀猴紝涓嶆樉绀虹敤css闅愯棌
+  show(values,formApi){},
+  // 鍔ㄦ�佸垽鏂綋鍓嶅瓧娈垫槸鍚﹂渶瑕佺鐢�
+  disabled(values,formApi){},
+  // 瀛楁鍙樻洿鏃讹紝閮戒細瑙﹀彂璇ュ嚱鏁�
+  trigger(values,formApi){},
+  // 鍔ㄦ�乺ules
+  rules(values,formApi){},
+  // 鍔ㄦ�佸繀濉�
+  required(values,formApi){},
+  // 鍔ㄦ�佺粍浠跺弬鏁�
+  componentProps(values,formApi){},
+}
+```
+
+### 琛ㄥ崟鏍¢獙
+
+琛ㄥ崟鑱斿姩闇�瑕侀�氳繃 schema 鍐呯殑 `rules` 灞炴�ц繘琛岄厤缃��
+
+rules鐨勫�煎彲浠ユ槸涓�涓瓧绗︿覆锛屼篃鍙互鏄竴涓獄od鐨剆chema銆�
+
+#### 瀛楃涓�
+
+```ts
+// 琛ㄧず瀛楁蹇呭~锛岄粯璁や細鏍规嵁閫傞厤鍣ㄧ殑required杩涜鍥介檯鍖�
+{
+  rules: 'required';
+}
+
+// 琛ㄧず瀛楁蹇呭~锛岄粯璁や細鏍规嵁閫傞厤鍣ㄧ殑required杩涜鍥介檯鍖栵紝鐢ㄤ簬涓嬫媺閫夋嫨涔嬬被
+{
+  rules: 'selectRequired';
+}
+```
+
+#### zod
+
+rules涔熸敮鎸� zod 鐨� schema锛屽彲浠ヨ繘琛屾洿澶嶆潅鐨勬牎楠岋紝zod 鐨勪娇鐢ㄨ鏌ョ湅 [zod鏂囨。](https://zod.dev/)銆�
+
+```ts
+import { z } from '#/adapter/form';
+
+// 鍩虹绫诲瀷
+{
+  rules: z.string().min(1, { message: '璇疯緭鍏ュ瓧绗︿覆' });
+}
+
+// 鍙�夛紝骞朵笖鎼哄甫榛樿鍊�
+{
+   rules: z.string().default('榛樿鍊�').optional(),
+}
+
+// 澶嶆潅鏍¢獙
+{
+   z.string().min(1, { message: "璇疯緭鍏�" })
+            .refine((value) => value === "123", {
+              message: "鍊煎繀椤讳负123",
+            });
+}
+```
+
+## Slots
+
+鍙互浣跨敤浠ヤ笅鎻掓Ы鍦ㄨ〃鍗曚腑鎻掑叆鑷畾涔夌殑鍐呭
+
+| 鎻掓Ы鍚�        | 鎻忚堪               |
+| ------------- | ------------------ |
+| reset-before  | 閲嶇疆鎸夐挳涔嬪墠鐨勪綅缃� |
+| submit-before | 鎻愪氦鎸夐挳涔嬪墠鐨勪綅缃� |
+| expand-before | 灞曞紑鎸夐挳涔嬪墠鐨勪綅缃� |
+| expand-after  | 灞曞紑鎸夐挳涔嬪悗鐨勪綅缃� |
+
+::: tip 瀛楁鎻掓Ы
+
+闄や簡浠ヤ笂鍐呯疆鎻掓Ы涔嬪锛宍schema`灞炴�т腑姣忎釜瀛楁鐨刞fieldName`閮藉彲浠ヤ綔涓烘彃妲藉悕绉帮紝杩欎簺瀛楁鎻掓Ы鐨勪紭鍏堢骇楂樹簬`component`瀹氫箟鐨勭粍浠躲�備篃灏辨槸璇达紝褰撴彁渚涗簡涓巂fieldName`鍚屽悕鐨勬彃妲芥椂锛岃繖浜涙彃妲界殑鍐呭灏嗕細浣滀负杩欎簺瀛楁鐨勭粍浠讹紝姝ゆ椂`component`鐨勫�煎皢浼氳蹇界暐銆�
+
+:::
diff --git a/eims-ui/docs/src/components/common-ui/vben-modal.md b/eims-ui/docs/src/components/common-ui/vben-modal.md
new file mode 100644
index 0000000..d6e3ef4
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-modal.md
@@ -0,0 +1,150 @@
+---
+outline: deep
+---
+
+# Vben Modal 妯℃�佹
+
+妗嗘灦鎻愪緵鐨勬ā鎬佹缁勪欢锛屾敮鎸乣鎷栨嫿`銆乣鍏ㄥ睆`銆乣鑷姩楂樺害`銆乣loading`绛夊姛鑳姐��
+
+> 濡傛灉鏂囨。鍐呮病鏈夊弬鏁拌鏄庯紝鍙互灏濊瘯鍦ㄥ湪绾跨ず渚嬪唴瀵绘壘
+
+::: info 鍐欏湪鍓嶉潰
+
+濡傛灉浣犺寰楃幇鏈夌粍浠剁殑灏佽涓嶅鐞嗘兂锛屾垨鑰呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+::: tip README
+
+涓嬫柟绀轰緥浠g爜涓殑锛屽瓨鍦ㄤ竴浜涘浗闄呭寲銆佷富棰樿壊鏈�傞厤闂锛岃繖浜涢棶棰樺彧鍦ㄦ枃妗e唴浼氬嚭鐜帮紝瀹為檯浣跨敤骞朵笉浼氭湁杩欎簺闂锛屽彲蹇界暐锛屼笉蹇呯籂缁撱��
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+浣跨敤 `useVbenModal` 鍒涘缓鏈�鍩虹鐨勬ā鎬佹銆�
+
+<DemoPreview dir="demos/vben-modal/basic" />
+
+## 缁勪欢鎶界
+
+Modal 鍐呯殑鍐呭涓�鑸笟鍔′腑锛屼細姣旇緝澶嶆潅锛屾墍浠ユ垜浠彲浠ュ皢 modal 鍐呯殑鍐呭鎶界鍑烘潵锛屼篃鏂逛究澶嶇敤銆傞�氳繃 `connectedComponent` 鍙傛暟锛屽彲浠ュ皢鍐呭缁勪欢杩涜杩炴帴锛岃�屼笉鐢ㄥ叾浠栦换浣曟搷浣溿��
+
+<DemoPreview dir="demos/vben-modal/extra" />
+
+## 寮�鍚嫋鎷�
+
+閫氳繃 `draggable` 鍙傛暟锛屽彲寮�鍚嫋鎷藉姛鑳姐��
+
+<DemoPreview dir="demos/vben-modal/draggable" />
+
+## 鑷姩璁$畻楂樺害
+
+寮圭獥浼氳嚜鍔ㄨ绠楀唴瀹归珮搴︼紝瓒呰繃涓�瀹氶珮搴︿細鍑虹幇婊氬姩鏉★紝鍚屾椂缁撳悎 `loading` 鏁堟灉浠ュ強浣跨敤 `prepend-footer` 鎻掓Ы銆�
+
+<DemoPreview dir="demos/vben-modal/auto-height" />
+
+## 浣跨敤 Api
+
+閫氳繃 `modalApi` 鍙互璋冪敤 modal 鐨勬柟娉曚互鍙婁娇鐢� `setState` 鏇存柊 modal 鐨勭姸鎬併��
+
+<DemoPreview dir="demos/vben-modal/dynamic" />
+
+## 鏁版嵁鍏变韩
+
+濡傛灉浣犱娇鐢ㄤ簡 `connectedComponent` 鍙傛暟锛岄偅涔堝唴澶栫粍浠朵細鍏变韩鏁版嵁锛屾瘮濡備竴浜涜〃鍗曞洖濉瓑鎿嶄綔銆傚彲浠ョ敤 `modalApi` 鏉ヨ幏鍙栨暟鎹拰璁剧疆鏁版嵁锛岄厤鍚� `onOpenChange`锛屽彲浠ユ弧瓒冲ぇ閮ㄥ垎鐨勯渶姹傘��
+
+<DemoPreview dir="demos/vben-modal/shared-data" />
+
+::: info 娉ㄦ剰
+
+- `VbenModal` 缁勪欢瀵逛笌鍙傛暟鐨勫鐞嗕紭鍏堢骇鏄� `slot` > `props` > `state`(閫氳繃api鏇存柊鐨勭姸鎬佷互鍙妘seVbenModal鍙傛暟)銆傚鏋滀綘宸茬粡浼犲叆浜� `slot` 鎴栬�� `props`锛岄偅涔� `setState` 灏嗕笉浼氱敓鏁堬紝杩欑鎯呭喌涓嬩綘鍙互閫氳繃 `slot` 鎴栬�� `props` 鏉ユ洿鏂扮姸鎬併��
+- 濡傛灉浣犱娇鐢ㄥ埌浜� `connectedComponent` 鍙傛暟锛岄偅涔堜細瀛樺湪 2 涓猔useVbenModal`, 姝ゆ椂锛屽鏋滃悓鏃惰缃簡鐩稿悓鐨勫弬鏁帮紝閭d箞浠ュ唴閮ㄤ负鍑嗭紙涔熷氨鏄病鏈夎缃� connectedComponent 鐨勪唬鐮侊級銆傛瘮濡� 鍚屾椂璁剧疆浜� `onConfirm`锛岄偅涔堜互鍐呴儴鐨� `onConfirm` 涓哄噯銆俙onOpenChange`浜嬩欢闄ゅ锛屽唴澶栭兘浼氳Е鍙戙��
+
+:::
+
+## API
+
+```ts
+// Modal 涓哄脊绐楃粍浠�
+// modalApi 涓哄脊绐楃殑鏂规硶
+const [Modal, modalApi] = useVbenModal({
+  // 灞炴��
+  // 浜嬩欢
+});
+```
+
+### Props
+
+鎵�鏈夊睘鎬ч兘鍙互浼犲叆 `useVbenModal` 鐨勭涓�涓弬鏁颁腑銆�
+
+| 灞炴�у悕 | 鎻忚堪 | 绫诲瀷 | 榛樿鍊� |
+| --- | --- | --- | --- |
+| appendToMain | 鏄惁鎸傝浇鍒板唴瀹瑰尯鍩燂紙榛樿鎸傝浇鍒癰ody锛� | `boolean` | `false` |
+| title | 鏍囬 | `string\|slot` | - |
+| titleTooltip | 鏍囬鎻愮ず淇℃伅 | `string\|slot` | - |
+| description | 鎻忚堪淇℃伅 | `string\|slot` | - |
+| isOpen | 寮圭獥鎵撳紑鐘舵�� | `boolean` | `false` |
+| loading | 寮圭獥鍔犺浇鐘舵�� | `boolean` | `false` |
+| fullscreen | 鍏ㄥ睆鏄剧ず | `boolean` | `false` |
+| fullscreenButton | 鏄剧ず鍏ㄥ睆鎸夐挳 | `boolean` | `true` |
+| draggable | 鍙嫋鎷� | `boolean` | `false` |
+| closable | 鏄剧ず鍏抽棴鎸夐挳 | `boolean` | `true` |
+| centered | 灞呬腑鏄剧ず | `boolean` | `false` |
+| modal | 鏄剧ず閬僵 | `boolean` | `true` |
+| header | 鏄剧ずheader | `boolean` | `true` |
+| footer | 鏄剧ずfooter | `boolean\|slot` | `true` |
+| confirmDisabled | 绂佺敤纭鎸夐挳 | `boolean` | `false` |
+| confirmLoading | 纭鎸夐挳loading鐘舵�� | `boolean` | `false` |
+| closeOnClickModal | 鐐瑰嚮閬僵鍏抽棴寮圭獥 | `boolean` | `true` |
+| closeOnPressEscape | esc 鍏抽棴寮圭獥 | `boolean` | `true` |
+| confirmText | 纭鎸夐挳鏂囨湰 | `string\|slot` | `纭` |
+| cancelText | 鍙栨秷鎸夐挳鏂囨湰 | `string\|slot` | `鍙栨秷` |
+| showCancelButton | 鏄剧ず鍙栨秷鎸夐挳 | `boolean` | `true` |
+| showConfirmButton | 鏄剧ず纭鎸夐挳 | `boolean` | `true` |
+| class | modal鐨刢lass锛屽搴﹂�氳繃杩欎釜閰嶇疆 | `string` | - |
+| contentClass | modal鍐呭鍖哄煙鐨刢lass | `string` | - |
+| footerClass | modal搴曢儴鍖哄煙鐨刢lass | `string` | - |
+| headerClass | modal椤堕儴鍖哄煙鐨刢lass | `string` | - |
+| bordered | 鏄惁鏄剧ずborder | `boolean` | `false` |
+| zIndex | 寮圭獥鐨刏Index灞傜骇 | `number` | `1000` |
+
+::: info appendToMain
+
+`appendToMain`鍙互鎸囧畾灏嗗脊绐楁寕杞藉埌鍐呭鍖哄煙锛屾墦寮�杩欑寮圭獥鏃讹紝鍐呭鍖哄煙浠ュ鐨勯儴鍒嗭紙鏍囩鏍忋�佸鑸彍鍗曠瓑绛夛級涓嶄細琚伄鎸°�傞粯璁ゆ儏鍐典笅锛屽脊绐椾細鎸傝浇鍒癰ody涓娿�備絾鏄細鎸傝浇鍒板唴瀹瑰尯鍩熸椂锛屼綔涓洪〉闈㈡牴瀹瑰櫒鐨刞Page`缁勪欢锛岄渶瑕佽缃甡auto-content-height`灞炴�э紝浠ヤ究寮圭獥鑳藉姝g‘璁$畻楂樺害銆�
+
+:::
+
+### Event
+
+浠ヤ笅浜嬩欢锛屽彧鏈夊湪 `useVbenModal({onCancel:()=>{}})` 涓紶鍏ユ墠浼氱敓鏁堛��
+
+| 浜嬩欢鍚� | 鎻忚堪 | 绫诲瀷 | 鐗堟湰鍙� |
+| --- | --- | --- | --- |
+| onBeforeClose | 鍏抽棴鍓嶈Е鍙戯紝杩斿洖 `false`鍒欑姝㈠叧闂� | `()=>boolean` |  |
+| onCancel | 鐐瑰嚮鍙栨秷鎸夐挳瑙﹀彂 | `()=>void` |  |
+| onClosed | 鍏抽棴鍔ㄧ敾鎾斁瀹屾瘯鏃惰Е鍙� | `()=>void` | >5.4.3 |
+| onConfirm | 鐐瑰嚮纭鎸夐挳瑙﹀彂 | `()=>void` |  |
+| onOpenChange | 鍏抽棴鎴栬�呮墦寮�寮圭獥鏃惰Е鍙� | `(isOpen:boolean)=>void` |  |
+| onOpened | 鎵撳紑鍔ㄧ敾鎾斁瀹屾瘯鏃惰Е鍙� | `()=>void` | >5.4.3 |
+
+### Slots
+
+闄や簡涓婇潰鐨勫睘鎬х被鍨嬪寘鍚玚slot`锛岃繕鍙互閫氳繃鎻掓Ы鏉ヨ嚜瀹氫箟寮圭獥鐨勫唴瀹广��
+
+| 鎻掓Ы鍚�         | 鎻忚堪                |
+| -------------- | ------------------- |
+| default        | 榛樿鎻掓Ы - 寮圭獥鍐呭 |
+| prepend-footer | 鍙栨秷鎸夐挳宸︿晶        |
+| append-footer  | 鍙栨秷鎸夐挳鍙充晶        |
+
+### modalApi
+
+| 浜嬩欢鍚� | 鎻忚堪 | 绫诲瀷 |
+| --- | --- | --- |
+| setState | 鍔ㄦ�佽缃脊绐楃姸鎬佸睘鎬� | `setState(props) \| setState((prev)=>(props))` |
+| open | 鎵撳紑寮圭獥 | `()=>void` |
+| close | 鍏抽棴寮圭獥 | `()=>void` |
+| setData | 璁剧疆鍏变韩鏁版嵁 | `<T>(data:T)=>void` |
+| getData | 鑾峰彇鍏变韩鏁版嵁 | `<T>()=>T` |
+| useStore | 鑾峰彇鍙搷搴斿紡鐘舵�� | - |
diff --git a/eims-ui/docs/src/components/common-ui/vben-vxe-table.md b/eims-ui/docs/src/components/common-ui/vben-vxe-table.md
new file mode 100644
index 0000000..29f679f
--- /dev/null
+++ b/eims-ui/docs/src/components/common-ui/vben-vxe-table.md
@@ -0,0 +1,238 @@
+---
+outline: deep
+---
+
+# Vben Vxe Table 琛ㄦ牸
+
+妗嗘灦鎻愪緵鐨凾able 鍒楄〃缁勪欢鍩轰簬 [vxe-table](https://vxetable.cn/v4/#/grid/api?apiKey=grid)锛岀粨鍚坄Vben Form 琛ㄥ崟`杩涜浜嗕簩娆″皝瑁呫��
+
+鍏朵腑锛岃〃澶寸殑 **琛ㄥ崟鎼滅储** 閮ㄥ垎閲囩敤浜哷Vben Form琛ㄥ崟`锛岃〃鏍间富浣撻儴鍒嗕娇鐢ㄤ簡`vxe-grid`缁勪欢锛屾敮鎸佽〃鏍肩殑鍒嗛〉銆佹帓搴忋�佺瓫閫夌瓑鍔熻兘銆�
+
+> 濡傛灉鏂囨。鍐呮病鏈夊弬鏁拌鏄庯紝鍙互灏濊瘯鍦ㄥ湪绾跨ず渚嬫垨鑰呭湪 [vxe-grid 瀹樻柟API 鏂囨。](https://vxetable.cn/v4/#/grid/api?apiKey=grid) 鍐呭鎵�
+
+::: info 鍐欏湪鍓嶉潰
+
+濡傛灉浣犺寰楃幇鏈夌粍浠剁殑灏佽涓嶅鐞嗘兂锛屾垨鑰呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+## 閫傞厤鍣�
+
+琛ㄦ牸搴曞眰浣跨敤 [vxe-table](https://vxetable.cn/#/start/install) 杩涜瀹炵幇锛屾墍浠ヤ綘鍙互浣跨敤 `vxe-table` 鐨勬墍鏈夊姛鑳姐�傚浜庝笉鍚岀殑 UI 妗嗘灦锛屾垜浠彁渚涗簡閫傞厤鍣紝浠ヤ究鏇村ソ鐨勯�傞厤涓嶅悓鐨� UI 妗嗘灦銆�
+
+### 閫傞厤鍣ㄨ鏄�
+
+姣忎釜搴旂敤閮藉彲浠ヨ嚜宸遍厤缃甡vxe-table`鐨勯�傞厤鍣紝浣犲彲浠ユ牴鎹嚜宸辩殑闇�姹傘�備笅闈㈡槸涓�涓畝鍗曠殑閰嶇疆绀轰緥锛�
+
+::: details vxe-table 琛ㄦ牸閫傞厤鍣�
+
+```ts
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { Button, Image } from 'ant-design-vue';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+  configVxeTable: (vxeUI) => {
+    vxeUI.setConfig({
+      grid: {
+        align: 'center',
+        border: false,
+        columnConfig: {
+          resizable: true,
+        },
+        minHeight: 180,
+        formConfig: {
+          // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+          enabled: false,
+        },
+        proxyConfig: {
+          autoLoad: true,
+          response: {
+            result: 'items',
+            total: 'total',
+            list: 'items',
+          },
+          showActiveMsg: true,
+          showResponseMsg: false,
+        },
+        round: true,
+        showOverflow: true,
+        size: 'small',
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+    vxeUI.renderer.add('CellImage', {
+      renderTableDefault(_renderOpts, params) {
+        const { column, row } = params;
+        return h(Image, { src: row[column.field] });
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+    vxeUI.renderer.add('CellLink', {
+      renderTableDefault(renderOpts) {
+        const { props } = renderOpts;
+        return h(
+          Button,
+          { size: 'small', type: 'link' },
+          { default: () => props?.text },
+        );
+      },
+    });
+
+    // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+    // vxeUI.formats.add
+  },
+  useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
+```
+
+:::
+
+## 鍩虹琛ㄦ牸
+
+浣跨敤 `useVbenVxeGrid` 鍒涘缓鏈�鍩虹鐨勮〃鏍笺��
+
+<DemoPreview dir="demos/vben-vxe-table/basic" />
+
+## 杩滅▼鍔犺浇
+
+閫氳繃鎸囧畾 `proxyConfig.ajax` 鐨� `query` 鏂规硶锛屽彲浠ュ疄鐜拌繙绋嬪姞杞芥暟鎹��
+
+<DemoPreview dir="demos/vben-vxe-table/remote" />
+
+## 鏍戝舰琛ㄦ牸
+
+鏍戝舰琛ㄦ牸鐨勬暟鎹簮涓烘墎骞崇粨鏋勶紝鍙互鎸囧畾`treeConfig`閰嶇疆椤癸紝瀹炵幇鏍戝舰琛ㄦ牸銆�
+
+```typescript
+treeConfig: {
+  transform: true, // 鎸囧畾琛ㄦ牸涓烘爲褰㈣〃鏍�
+  parentField: 'parentId', // 鐖惰妭鐐瑰瓧娈靛悕
+  rowField: 'id', // 琛屾暟鎹瓧娈靛悕
+},
+```
+
+<DemoPreview dir="demos/vben-vxe-table/tree" />
+
+## 鍥哄畾琛ㄥご/鍒�
+
+鍒楀浐瀹氬彲閫夊弬鏁帮細 `'left' | 'right' | '' | null`
+
+<DemoPreview dir="demos/vben-vxe-table/fixed" />
+
+## 鑷畾涔夊崟鍏冩牸
+
+鑷畾涔夊崟鍏冩牸鏈変袱绉嶅疄鐜版柟寮�
+
+- 閫氳繃 `slots` 鎻掓Ы
+- 閫氳繃 `customCell` 鑷畾涔夊崟鍏冩牸锛屼絾鏄鍏堟坊鍔犳覆鏌撳櫒
+
+```typescript
+// 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+vxeUI.renderer.add('CellImage', {
+  renderDefault(_renderOpts, params) {
+    const { column, row } = params;
+    return h(Image, { src: row[column.field] } as any); // 娉ㄦ剰姝ゅ鐨処mage 缁勪欢锛屾潵婧愪簬Antd锛岄渶瑕佽嚜琛屽紩鍏�,鍚﹀垯浼氫娇鐢╦s鐨処mage绫�
+  },
+});
+
+// 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+vxeUI.renderer.add('CellLink', {
+  renderDefault(renderOpts) {
+    const { props } = renderOpts;
+    return h(
+      Button,
+      { size: 'small', type: 'link' },
+      { default: () => props?.text },
+    );
+  },
+});
+```
+
+<DemoPreview dir="demos/vben-vxe-table/custom-cell" />
+
+## 鎼滅储琛ㄥ崟
+
+**琛ㄥ崟鎼滅储** 閮ㄥ垎閲囩敤浜哷Vben Form 琛ㄥ崟`锛屽弬鑰� [Vben Form 琛ㄥ崟鏂囨。](/components/common-ui/vben-form)銆�
+
+<DemoPreview dir="demos/vben-vxe-table/form" />
+
+## 鍗曞厓鏍肩紪杈�
+
+閫氳繃鎸囧畾`editConfig.mode`涓篳cell`锛屽彲浠ュ疄鐜板崟鍏冩牸缂栬緫銆�
+
+<DemoPreview dir="demos/vben-vxe-table/edit-cell" />
+
+## 琛岀紪杈�
+
+閫氳繃鎸囧畾`editConfig.mode`涓篳row`锛屽彲浠ュ疄鐜拌缂栬緫銆�
+
+<DemoPreview dir="demos/vben-vxe-table/edit-row" />
+
+## 铏氭嫙婊氬姩
+
+閫氳繃 scroll-y.enabled 涓� scroll-y.gt 缁勫悎寮�鍚紝鍏朵腑 enabled 涓烘�诲紑鍏筹紝gt 鏄寚褰撴�昏鏁板ぇ浜庢寚瀹氳鏁版椂鑷姩寮�鍚��
+
+> 鍙傝�� [vxe-table 瀹樻柟鏂囨。 - 铏氭嫙婊氬姩](https://vxetable.cn/v4/#/component/grid/scroll/vertical)銆�
+
+<DemoPreview dir="demos/vben-vxe-table/virtual" />
+
+## API
+
+`useVbenVxeGrid` 杩斿洖涓�涓暟缁勶紝绗竴涓厓绱犳槸琛ㄦ牸缁勪欢锛岀浜屼釜鍏冪礌鏄〃鏍肩殑鏂规硶銆�
+
+```vue
+<script setup lang="ts">
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+// Grid 涓鸿〃鏍肩粍浠�
+// gridApi 涓鸿〃鏍肩殑鏂规硶
+const [Grid, gridApi] = useVbenVxeGrid({
+  gridOptions: {},
+  formOptions: {},
+  gridEvents: {},
+  // 灞炴��
+  // 浜嬩欢
+});
+</script>
+
+<template>
+  <Grid />
+</template>
+```
+
+### GridApi
+
+useVbenVxeGrid 杩斿洖鐨勭浜屼釜鍙傛暟锛屾槸涓�涓璞★紝鍖呭惈浜嗕竴浜涜〃鍗曠殑鏂规硶銆�
+
+| 鏂规硶鍚� | 鎻忚堪 | 绫诲瀷 |
+| --- | --- | --- |
+| setLoading | 璁剧疆loading鐘舵�� | `(loading)=>void` |
+| setGridOptions | 璁剧疆vxe-table grid缁勪欢鍙傛暟 | `(options: Partial<VxeGridProps['gridOptions'])=>void` |
+| reload | 閲嶈浇琛ㄦ牸锛屼細杩涜鍒濆鍖� | `(params:any)=>void` |
+| query | 閲嶈浇琛ㄦ牸锛屼細淇濈暀褰撳墠鍒嗛〉 | `(params:any)=>void` |
+| grid | vxe-table grid瀹炰緥 | `VxeGridInstance` |
+| formApi | vbenForm api瀹炰緥 | `FormApi` |
+
+## Props
+
+鎵�鏈夊睘鎬ч兘鍙互浼犲叆 `useVbenVxeGrid` 鐨勭涓�涓弬鏁颁腑銆�
+
+| 灞炴�у悕         | 鎻忚堪               | 绫诲瀷                |
+| -------------- | ------------------ | ------------------- |
+| tableTitle     | 琛ㄦ牸鏍囬           | `string`            |
+| tableTitleHelp | 琛ㄦ牸鏍囬甯姪淇℃伅   | `string`            |
+| gridClass      | grid缁勪欢鐨刢lass    | `string`            |
+| gridOptions    | grid缁勪欢鐨勫弬鏁�     | `VxeTableGridProps` |
+| gridEvents     | grid缁勪欢鐨勮Е鍙戠殑鈱氾笍 | `VxeGridListeners`  |
+| formOptions    | 琛ㄥ崟鍙傛暟           | `VbenFormProps`     |
diff --git a/eims-ui/docs/src/components/introduction.md b/eims-ui/docs/src/components/introduction.md
new file mode 100644
index 0000000..438470e
--- /dev/null
+++ b/eims-ui/docs/src/components/introduction.md
@@ -0,0 +1,15 @@
+# 浠嬬粛
+
+::: info README
+
+璇ユ枃妗d粙缁嶇殑鏄鏋剁粍浠剁殑浣跨敤鏂规硶銆佸睘鎬с�佷簨浠剁瓑銆傚鏋滀綘瑙夊緱鐜版湁缁勪欢鐨勫皝瑁呬笉澶熺悊鎯筹紝鎴栬�呬笉瀹屽叏绗﹀悎浣犵殑闇�姹傦紝澶у彲浠ョ洿鎺ヤ娇鐢ㄥ師鐢熺粍浠讹紝浜︽垨浜叉墜灏佽涓�涓�傚悎鐨勭粍浠躲�傛鏋舵彁渚涚殑缁勪欢骞堕潪鏉熺細锛屼娇鐢ㄤ笌鍚︼紝瀹屽叏鍙栧喅浜庝綘鐨勯渶姹備笌鑷敱銆�
+
+:::
+
+## 甯冨眬缁勪欢
+
+甯冨眬缁勪欢涓�鑸湪椤甸潰鍐呭鍖哄煙鐢ㄤ綔椤跺眰瀹瑰櫒缁勪欢锛屾彁渚涗竴浜涚粺涓�鐨勫竷灞�鏍峰紡鍜屽熀鏈姛鑳姐��
+
+## 閫氱敤缁勪欢
+
+閫氱敤缁勪欢鏄竴浜涘父鐢ㄧ殑缁勪欢锛屾瘮濡傚脊绐椼�佹娊灞夈�佽〃鍗曠瓑銆傚ぇ閮ㄥ垎鍩轰簬 `Tailwind CSS` 瀹炵幇锛屽彲閫傜敤浜庝笉鍚� UI 缁勪欢搴撶殑搴旂敤銆�
diff --git a/eims-ui/docs/src/components/layout-ui/page.md b/eims-ui/docs/src/components/layout-ui/page.md
new file mode 100644
index 0000000..29fbdd4
--- /dev/null
+++ b/eims-ui/docs/src/components/layout-ui/page.md
@@ -0,0 +1,44 @@
+---
+outline: deep
+---
+
+# Page 甯歌椤甸潰缁勪欢
+
+鎻愪緵涓�涓父瑙勯〉闈㈠竷灞�鐨勭粍浠讹紝鍖呮嫭澶撮儴銆佸唴瀹瑰尯鍩熴�佸簳閮ㄤ笁涓儴鍒嗐��
+
+::: info 鍐欏湪鍓嶉潰
+
+鏈粍浠舵槸涓�涓熀鏈竷灞�缁勪欢銆傚鏋滄湁鏇村鐨勯�氱敤椤甸潰甯冨眬闇�姹傦紙姣斿鍙屽垪甯冨眬绛夛級锛屽彲浠ユ牴鎹疄闄呴渶姹傝嚜琛屽皝瑁呫��
+
+:::
+
+## 鍩虹鐢ㄦ硶
+
+灏哷Page`浣滀负浣犵殑涓氬姟椤甸潰鐨勬牴缁勪欢鍗冲彲銆�
+
+### Props
+
+| 灞炴�у悕 | 鎻忚堪 | 绫诲瀷 | 榛樿鍊� | 璇存槑 |
+| --- | --- | --- | --- | --- |
+| title | 椤甸潰鏍囬 | `string\|slot` | - | - |
+| description | 椤甸潰鎻忚堪锛堟爣棰樹笅鐨勫唴瀹癸級 | `string\|slot` | - | - |
+| contentClass | 鍐呭鍖哄煙鐨刢lass | `string` | - | - |
+| headerClass | 澶撮儴鍖哄煙鐨刢lass | `string` | - | - |
+| footerClass | 搴曢儴鍖哄煙鐨刢lass | `string` | - | - |
+| autoContentHeight | 鑷姩璋冩暣鍐呭鍖哄煙鐨勯珮搴� | `boolean` | `false` | - |
+
+::: tip 娉ㄦ剰
+
+濡傛灉`title`銆乣description`銆乣extra`涓夎�呭潎鏈彁渚涙湁鏁堝唴瀹癸紙閫氳繃`props`鎴栬�卄slots`鍧囧彲锛夛紝鍒欓〉闈㈠ご閮ㄥ尯鍩熶笉浼氭覆鏌撱��
+
+:::
+
+### Slots
+
+| 鎻掓Ы鍚嶇О    | 鎻忚堪         |
+| ----------- | ------------ |
+| default     | 椤甸潰鍐呭     |
+| title       | 椤甸潰鏍囬     |
+| description | 椤甸潰鎻忚堪     |
+| extra       | 椤甸潰澶撮儴鍙充晶 |
+| footer      | 椤甸潰搴曢儴     |
diff --git a/eims-ui/docs/src/demos/vben-api-component/cascader/index.vue b/eims-ui/docs/src/demos/vben-api-component/cascader/index.vue
new file mode 100644
index 0000000..957964c
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-api-component/cascader/index.vue
@@ -0,0 +1,100 @@
+<script lang="ts" setup>
+import { ApiComponent } from '@vben/common-ui';
+
+import { Cascader } from 'ant-design-vue';
+
+const treeData: Record<string, any> = [
+  {
+    label: '娴欐睙',
+    value: 'zhejiang',
+    children: [
+      {
+        value: 'hangzhou',
+        label: '鏉窞',
+        children: [
+          {
+            value: 'xihu',
+            label: '瑗挎箹',
+          },
+          {
+            value: 'sudi',
+            label: '鑻忓牑',
+          },
+        ],
+      },
+      {
+        value: 'jiaxing',
+        label: '鍢夊叴',
+        children: [
+          {
+            value: 'wuzhen',
+            label: '涔岄晣',
+          },
+          {
+            value: 'meihuazhou',
+            label: '姊呰姳娲�',
+          },
+        ],
+      },
+      {
+        value: 'zhoushan',
+        label: '鑸熷北',
+        children: [
+          {
+            value: 'putuoshan',
+            label: '鏅檧灞�',
+          },
+          {
+            value: 'taohuadao',
+            label: '妗冭姳宀�',
+          },
+        ],
+      },
+    ],
+  },
+  {
+    label: '姹熻嫃',
+    value: 'jiangsu',
+    children: [
+      {
+        value: 'nanjing',
+        label: '鍗椾含',
+        children: [
+          {
+            value: 'zhonghuamen',
+            label: '涓崕闂�',
+          },
+          {
+            value: 'zijinshan',
+            label: '绱噾灞�',
+          },
+          {
+            value: 'yuhuatai',
+            label: '闆ㄨ姳鍙�',
+          },
+        ],
+      },
+    ],
+  },
+];
+/**
+ * 妯℃嫙璇锋眰鎺ュ彛
+ */
+function fetchApi(): Promise<Record<string, any>> {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(treeData);
+    }, 1000);
+  });
+}
+</script>
+<template>
+  <ApiComponent
+    :api="fetchApi"
+    :component="Cascader"
+    :immediate="false"
+    children-field="children"
+    loading-slot="suffixIcon"
+    visible-event="onDropdownVisibleChange"
+  />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-count-to-animator/basic/index.vue b/eims-ui/docs/src/demos/vben-count-to-animator/basic/index.vue
new file mode 100644
index 0000000..acc76ed
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-count-to-animator/basic/index.vue
@@ -0,0 +1,6 @@
+<script lang="ts" setup>
+import { VbenCountToAnimator } from '@vben/common-ui';
+</script>
+<template>
+  <VbenCountToAnimator :duration="3000" :end-val="30000" :start-val="1" />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-count-to-animator/custom/index.vue b/eims-ui/docs/src/demos/vben-count-to-animator/custom/index.vue
new file mode 100644
index 0000000..5a24340
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-count-to-animator/custom/index.vue
@@ -0,0 +1,12 @@
+<script lang="ts" setup>
+import { VbenCountToAnimator } from '@vben/common-ui';
+</script>
+<template>
+  <VbenCountToAnimator
+    :duration="3000"
+    :end-val="2000000"
+    :start-val="1"
+    prefix="$"
+    separator="/"
+  />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/auto-height/drawer.vue b/eims-ui/docs/src/demos/vben-drawer/auto-height/drawer.vue
new file mode 100644
index 0000000..9ab433c
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/auto-height/drawer.vue
@@ -0,0 +1,45 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+const list = ref<number[]>([]);
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    console.log('onConfirm');
+  },
+  onOpenChange(isOpen) {
+    if (isOpen) {
+      handleUpdate(10);
+    }
+  },
+});
+
+function handleUpdate(len: number) {
+  drawerApi.setState({ loading: true });
+  setTimeout(() => {
+    list.value = Array.from({ length: len }, (_v, k) => k + 1);
+    drawerApi.setState({ loading: false });
+  }, 2000);
+}
+</script>
+<template>
+  <Drawer title="鑷姩璁$畻楂樺害">
+    <div
+      v-for="item in list"
+      :key="item"
+      class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
+    >
+      {{ item }}
+    </div>
+    <template #prepend-footer>
+      <VbenButton type="link" @click="handleUpdate(6)">
+        鐐瑰嚮鏇存柊鏁版嵁
+      </VbenButton>
+    </template>
+  </Drawer>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/auto-height/index.vue b/eims-ui/docs/src/demos/vben-drawer/auto-height/index.vue
new file mode 100644
index 0000000..59294e5
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/auto-height/index.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+import ExtraDrawer from './drawer.vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraDrawer,
+});
+
+function open() {
+  drawerApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Drawer />
+    <VbenButton @click="open">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/basic/index.vue b/eims-ui/docs/src/demos/vben-drawer/basic/index.vue
new file mode 100644
index 0000000..bd7d927
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/basic/index.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+const [Drawer, drawerApi] = useVbenDrawer();
+</script>
+<template>
+  <div>
+    <VbenButton @click="() => drawerApi.open()">Open</VbenButton>
+    <Drawer class="w-[600px]" title="鍩虹绀轰緥"> drawer content </Drawer>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/dynamic/drawer.vue b/eims-ui/docs/src/demos/vben-drawer/dynamic/drawer.vue
new file mode 100644
index 0000000..50f6283
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/dynamic/drawer.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    console.info('onConfirm');
+  },
+  title: '鍔ㄦ�佷慨鏀归厤缃ず渚�',
+});
+
+function handleUpdateTitle() {
+  drawerApi.setState({ title: '鍐呴儴鍔ㄦ�佹爣棰�' });
+}
+</script>
+<template>
+  <Drawer>
+    <div class="flex-col-center">
+      <VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
+        鍐呴儴鍔ㄦ�佷慨鏀规爣棰�
+      </VbenButton>
+    </div>
+  </Drawer>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/dynamic/index.vue b/eims-ui/docs/src/demos/vben-drawer/dynamic/index.vue
new file mode 100644
index 0000000..ad7e656
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/dynamic/index.vue
@@ -0,0 +1,30 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+import ExtraDrawer from './drawer.vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraDrawer,
+});
+
+function open() {
+  drawerApi.open();
+}
+
+function handleUpdateTitle() {
+  drawerApi.setState({ title: '澶栭儴鍔ㄦ�佹爣棰�' });
+  drawerApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Drawer />
+
+    <VbenButton @click="open">Open</VbenButton>
+    <VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
+      浠庡閮ㄤ慨鏀规爣棰樺苟鎵撳紑
+    </VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/extra/drawer.vue b/eims-ui/docs/src/demos/vben-drawer/extra/drawer.vue
new file mode 100644
index 0000000..e84c193
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/extra/drawer.vue
@@ -0,0 +1,8 @@
+<script lang="ts" setup>
+import { useVbenDrawer } from '@vben/common-ui';
+
+const [Drawer] = useVbenDrawer();
+</script>
+<template>
+  <Drawer title="缁勪欢鎶界绀轰緥"> extra drawer content </Drawer>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/extra/index.vue b/eims-ui/docs/src/demos/vben-drawer/extra/index.vue
new file mode 100644
index 0000000..59294e5
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/extra/index.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+import ExtraDrawer from './drawer.vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraDrawer,
+});
+
+function open() {
+  drawerApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Drawer />
+    <VbenButton @click="open">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/shared-data/drawer.vue b/eims-ui/docs/src/demos/vben-drawer/shared-data/drawer.vue
new file mode 100644
index 0000000..629199b
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/shared-data/drawer.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+
+const data = ref();
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    console.info('onConfirm');
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      data.value = drawerApi.getData<Record<string, any>>();
+    }
+  },
+});
+</script>
+<template>
+  <Drawer title="鏁版嵁鍏变韩绀轰緥">
+    <div class="flex-col-center">澶栭儴浼犻�掓暟鎹細 {{ data }}</div>
+  </Drawer>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-drawer/shared-data/index.vue b/eims-ui/docs/src/demos/vben-drawer/shared-data/index.vue
new file mode 100644
index 0000000..04885f1
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-drawer/shared-data/index.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { useVbenDrawer, VbenButton } from '@vben/common-ui';
+
+import ExtraDrawer from './drawer.vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraDrawer,
+});
+
+function open() {
+  drawerApi.setData({
+    content: '澶栭儴浼犻�掔殑鏁版嵁 content',
+    payload: '澶栭儴浼犻�掔殑鏁版嵁 payload',
+  });
+  drawerApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Drawer />
+
+    <VbenButton @click="open">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/api/index.vue b/eims-ui/docs/src/demos/vben-form/api/index.vue
new file mode 100644
index 0000000..786dc89
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/api/index.vue
@@ -0,0 +1,236 @@
+<script lang="ts" setup>
+import { Button, message, Space } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [BaseForm, formApi] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 浣跨敤 tailwindcss grid甯冨眬
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  layout: 'horizontal',
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'field1',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'fieldOptions',
+      label: '涓嬫媺閫�',
+    },
+  ],
+  wrapperClass: 'grid-cols-1 md:grid-cols-2',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+
+function handleClick(
+  action:
+    | 'batchAddSchema'
+    | 'batchDeleteSchema'
+    | 'disabled'
+    | 'hiddenAction'
+    | 'hiddenResetButton'
+    | 'hiddenSubmitButton'
+    | 'labelWidth'
+    | 'resetDisabled'
+    | 'resetLabelWidth'
+    | 'showAction'
+    | 'showResetButton'
+    | 'showSubmitButton'
+    | 'updateActionAlign'
+    | 'updateResetButton'
+    | 'updateSchema'
+    | 'updateSubmitButton',
+) {
+  switch (action) {
+    case 'batchAddSchema': {
+      formApi.setState((prev) => {
+        const currentSchema = prev?.schema ?? [];
+        const newSchema = [];
+        for (let i = 0; i < 2; i++) {
+          newSchema.push({
+            component: 'Input',
+            componentProps: {
+              placeholder: '璇疯緭鍏�',
+            },
+            fieldName: `field${i}${Date.now()}`,
+            label: `field+`,
+          });
+        }
+        return {
+          schema: [...currentSchema, ...newSchema],
+        };
+      });
+      break;
+    }
+
+    case 'batchDeleteSchema': {
+      formApi.setState((prev) => {
+        const currentSchema = prev?.schema ?? [];
+        return {
+          schema: currentSchema.slice(0, -2),
+        };
+      });
+      break;
+    }
+    case 'disabled': {
+      formApi.setState({ commonConfig: { disabled: true } });
+      break;
+    }
+    case 'hiddenAction': {
+      formApi.setState({ showDefaultActions: false });
+      break;
+    }
+    case 'hiddenResetButton': {
+      formApi.setState({ resetButtonOptions: { show: false } });
+      break;
+    }
+    case 'hiddenSubmitButton': {
+      formApi.setState({ submitButtonOptions: { show: false } });
+      break;
+    }
+    case 'labelWidth': {
+      formApi.setState({
+        commonConfig: {
+          labelWidth: 150,
+        },
+      });
+      break;
+    }
+    case 'resetDisabled': {
+      formApi.setState({ commonConfig: { disabled: false } });
+      break;
+    }
+    case 'resetLabelWidth': {
+      formApi.setState({
+        commonConfig: {
+          labelWidth: 100,
+        },
+      });
+      break;
+    }
+    case 'showAction': {
+      formApi.setState({ showDefaultActions: true });
+      break;
+    }
+    case 'showResetButton': {
+      formApi.setState({ resetButtonOptions: { show: true } });
+      break;
+    }
+    case 'showSubmitButton': {
+      formApi.setState({ submitButtonOptions: { show: true } });
+      break;
+    }
+    case 'updateActionAlign': {
+      formApi.setState({
+        // 鍙互鑷璋冩暣class
+        actionWrapperClass: 'text-center',
+      });
+      break;
+    }
+    case 'updateResetButton': {
+      formApi.setState({
+        resetButtonOptions: { disabled: true },
+      });
+      break;
+    }
+    case 'updateSchema': {
+      formApi.updateSchema([
+        {
+          componentProps: {
+            options: [
+              {
+                label: '閫夐」1',
+                value: '1',
+              },
+              {
+                label: '閫夐」2',
+                value: '2',
+              },
+              {
+                label: '閫夐」3',
+                value: '3',
+              },
+            ],
+          },
+          fieldName: 'fieldOptions',
+        },
+      ]);
+      message.success('瀛楁 `fieldOptions` 涓嬫媺閫夐」鏇存柊鎴愬姛銆�');
+      break;
+    }
+    case 'updateSubmitButton': {
+      formApi.setState({
+        submitButtonOptions: { loading: true },
+      });
+      break;
+    }
+  }
+}
+</script>
+
+<template>
+  <div>
+    <Space class="mb-5 flex-wrap">
+      <Button @click="handleClick('updateSchema')">updateSchema</Button>
+      <Button @click="handleClick('labelWidth')">鏇存敼labelWidth</Button>
+      <Button @click="handleClick('resetLabelWidth')">杩樺師labelWidth</Button>
+      <Button @click="handleClick('disabled')">绂佺敤琛ㄥ崟</Button>
+      <Button @click="handleClick('resetDisabled')">瑙i櫎绂佺敤</Button>
+      <Button @click="handleClick('hiddenAction')">闅愯棌鎿嶄綔鎸夐挳</Button>
+      <Button @click="handleClick('showAction')">鏄剧ず鎿嶄綔鎸夐挳</Button>
+      <Button @click="handleClick('hiddenResetButton')">闅愯棌閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('showResetButton')">鏄剧ず閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('hiddenSubmitButton')">闅愯棌鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('showSubmitButton')">鏄剧ず鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('updateResetButton')">淇敼閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('updateSubmitButton')">淇敼鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('updateActionAlign')">
+        璋冩暣鎿嶄綔鎸夐挳浣嶇疆
+      </Button>
+      <Button @click="handleClick('batchAddSchema')"> 鎵归噺娣诲姞琛ㄥ崟椤� </Button>
+      <Button @click="handleClick('batchDeleteSchema')">
+        鎵归噺鍒犻櫎琛ㄥ崟椤�
+      </Button>
+    </Space>
+    <BaseForm />
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/basic/index.vue b/eims-ui/docs/src/demos/vben-form/basic/index.vue
new file mode 100644
index 0000000..88d0142
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/basic/index.vue
@@ -0,0 +1,231 @@
+<script lang="ts" setup>
+import { message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [BaseForm] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'username',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏ュ瘑鐮�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧(甯﹀悗缂�)',
+      suffix: () => '楼',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+    },
+    {
+      component: 'RadioGroup',
+      componentProps: {
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'radioGroup',
+      label: '鍗曢�夌粍',
+    },
+    {
+      component: 'Radio',
+      fieldName: 'radio',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['Radio'],
+        };
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      componentProps: {
+        name: 'cname',
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'checkboxGroup',
+      label: '澶氶�夌粍',
+    },
+    {
+      component: 'Checkbox',
+      fieldName: 'checkbox',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['鎴戝凡闃呰骞跺悓鎰�'],
+        };
+      },
+    },
+    {
+      component: 'Mentions',
+      componentProps: {
+        options: [
+          {
+            label: 'afc163',
+            value: 'afc163',
+          },
+          {
+            label: 'zombieJ',
+            value: 'zombieJ',
+          },
+        ],
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'mentions',
+      label: '鎻愬強',
+    },
+    {
+      component: 'Rate',
+      fieldName: 'rate',
+      label: '璇勫垎',
+    },
+    {
+      component: 'Switch',
+      componentProps: {
+        class: 'w-auto',
+      },
+      fieldName: 'switch',
+      label: '寮�鍏�',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+    },
+    {
+      component: 'RangePicker',
+      fieldName: 'rangePicker',
+      label: '鑼冨洿閫夋嫨鍣�',
+    },
+    {
+      component: 'TimePicker',
+      fieldName: 'timePicker',
+      label: '鏃堕棿閫夋嫨妗�',
+    },
+    {
+      component: 'TreeSelect',
+      componentProps: {
+        allowClear: true,
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: [
+          {
+            label: 'root 1',
+            value: 'root 1',
+            children: [
+              {
+                label: 'parent 1',
+                value: 'parent 1',
+                children: [
+                  {
+                    label: 'parent 1-0',
+                    value: 'parent 1-0',
+                    children: [
+                      {
+                        label: 'my leaf',
+                        value: 'leaf1',
+                      },
+                      {
+                        label: 'your leaf',
+                        value: 'leaf2',
+                      },
+                    ],
+                  },
+                  {
+                    label: 'parent 1-1',
+                    value: 'parent 1-1',
+                  },
+                ],
+              },
+              {
+                label: 'parent 2',
+                value: 'parent 2',
+              },
+            ],
+          },
+        ],
+        treeNodeFilterProp: 'label',
+      },
+      fieldName: 'treeSelect',
+      label: '鏍戦�夋嫨',
+    },
+  ],
+  wrapperClass: 'grid-cols-1',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <BaseForm />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/custom/index.vue b/eims-ui/docs/src/demos/vben-form/custom/index.vue
new file mode 100644
index 0000000..e4da38d
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/custom/index.vue
@@ -0,0 +1,68 @@
+<script lang="ts" setup>
+import { h } from 'vue';
+
+import { Input, message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [Form] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+    labelClass: 'w-2/6',
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      fieldName: 'field',
+      label: '鑷畾涔夊悗缂�',
+      suffix: () => h('span', { class: 'text-red-600' }, '鍏�'),
+    },
+    {
+      component: 'Input',
+      fieldName: 'field1',
+      label: '鑷畾涔夌粍浠秙lot',
+      renderComponentContent: () => ({
+        prefix: () => 'prefix',
+        suffix: () => 'suffix',
+      }),
+    },
+    {
+      component: h(Input, { placeholder: '璇疯緭鍏�' }),
+      fieldName: 'field2',
+      label: '鑷畾涔夌粍浠�',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field3',
+      label: '鑷畾涔夌粍浠�(slot)',
+      rules: 'required',
+    },
+  ],
+  wrapperClass: 'grid-cols-1',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Form>
+    <template #field3="slotProps">
+      <Input placeholder="璇疯緭鍏�" v-bind="slotProps" />
+    </template>
+  </Form>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/dynamic/index.vue b/eims-ui/docs/src/demos/vben-form/dynamic/index.vue
new file mode 100644
index 0000000..83d1a71
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/dynamic/index.vue
@@ -0,0 +1,168 @@
+<script lang="ts" setup>
+import { message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [Form] = useVbenForm({
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  schema: [
+    {
+      component: 'Input',
+      defaultValue: 'hidden value',
+      dependencies: {
+        show: false,
+        // 闅忔剰涓�涓瓧娈垫敼鍙樻椂锛岄兘浼氳Е鍙�
+        triggerFields: ['field1Switch'],
+      },
+      fieldName: 'hiddenField',
+      label: '闅愯棌瀛楁',
+    },
+    {
+      component: 'Switch',
+      defaultValue: true,
+      fieldName: 'field1Switch',
+      help: '閫氳繃Dom鎺у埗閿�姣�',
+      label: '鏄剧ず瀛楁1',
+    },
+    {
+      component: 'Switch',
+      defaultValue: true,
+      fieldName: 'field2Switch',
+      help: '閫氳繃css鎺у埗闅愯棌',
+      label: '鏄剧ず瀛楁2',
+    },
+    {
+      component: 'Switch',
+      fieldName: 'field3Switch',
+      label: '绂佺敤瀛楁3',
+    },
+    {
+      component: 'Switch',
+      fieldName: 'field4Switch',
+      label: '瀛楁4蹇呭~',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        if(values) {
+          return !!values.field1Switch;
+        },
+        // 鍙湁鎸囧畾鐨勫瓧娈垫敼鍙樻椂锛屾墠浼氳Е鍙�
+        triggerFields: ['field1Switch'],
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁1',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        show(values) {
+          return !!values.field2Switch;
+        },
+        triggerFields: ['field2Switch'],
+      },
+      fieldName: 'field2',
+      label: '瀛楁2',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        disabled(values) {
+          return !!values.field3Switch;
+        },
+        triggerFields: ['field3Switch'],
+      },
+      fieldName: 'field3',
+      label: '瀛楁3',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        required(values) {
+          return !!values.field4Switch;
+        },
+        triggerFields: ['field4Switch'],
+      },
+      fieldName: 'field4',
+      label: '瀛楁4',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        rules(values) {
+          if (values.field1 === '123') {
+            return 'required';
+          }
+          return null;
+        },
+        triggerFields: ['field1'],
+      },
+      fieldName: 'field5',
+      help: '褰撳瓧娈�1鐨勫�间负`123`鏃讹紝蹇呭~',
+      label: '鍔ㄦ�乺ules',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        class: 'w-full',
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      dependencies: {
+        componentProps(values) {
+          if (values.field2 === '123') {
+            return {
+              options: [
+                {
+                  label: '閫夐」1',
+                  value: '1',
+                },
+                {
+                  label: '閫夐」2',
+                  value: '2',
+                },
+                {
+                  label: '閫夐」3',
+                  value: '3',
+                },
+              ],
+            };
+          }
+          return {};
+        },
+        triggerFields: ['field2'],
+      },
+      fieldName: 'field6',
+      help: '褰撳瓧娈�2鐨勫�间负`123`鏃讹紝鏇存敼涓嬫媺閫夐」',
+      label: '鍔ㄦ�侀厤缃�',
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Form />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/query/index.vue b/eims-ui/docs/src/demos/vben-form/query/index.vue
new file mode 100644
index 0000000..a0b64f5
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/query/index.vue
@@ -0,0 +1,94 @@
+<script lang="ts" setup>
+import { message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [QueryForm] = useVbenForm({
+  // 榛樿灞曞紑
+  collapsed: false,
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'username',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏ュ瘑鐮�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧(甯﹀悗缂�)',
+      suffix: () => '楼',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+    },
+  ],
+  // 鏄惁鍙睍寮�
+  showCollapseButton: true,
+  submitButtonOptions: {
+    content: '鏌ヨ',
+  },
+  wrapperClass: 'grid-cols-1 md:grid-cols-2',
+});
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <QueryForm />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-form/rules/index.vue b/eims-ui/docs/src/demos/vben-form/rules/index.vue
new file mode 100644
index 0000000..7abcc6f
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-form/rules/index.vue
@@ -0,0 +1,189 @@
+<script lang="ts" setup>
+import { message } from 'ant-design-vue';
+
+import { useVbenForm, z } from '#/adapter/form';
+
+const [Form] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁1',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      defaultValue: '榛樿鍊�',
+      fieldName: 'field2',
+      label: '榛樿鍊�(蹇呭~)',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field3',
+      label: '榛樿鍊�(闈炲繀濉�)',
+      rules: z.string().default('榛樿鍊�').optional(),
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field31',
+      label: '鑷畾涔変俊鎭�',
+      rules: z.string().min(1, { message: '鏈�灏戣緭鍏�1涓瓧绗�' }),
+    },
+    {
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field4',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '閭',
+      rules: z.string().email('璇疯緭鍏ユ纭殑閭'),
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧',
+      rules: 'required',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      defaultValue: undefined,
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'RadioGroup',
+      componentProps: {
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'radioGroup',
+      label: '鍗曢�夌粍',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'CheckboxGroup',
+      componentProps: {
+        name: 'cname',
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'checkboxGroup',
+      label: '澶氶�夌粍',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'Checkbox',
+      fieldName: 'checkbox',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['鎴戝凡闃呰骞跺悓鎰�'],
+        };
+      },
+      rules: 'selectRequired',
+    },
+    {
+      component: 'DatePicker',
+      defaultValue: undefined,
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'RangePicker',
+      defaultValue: undefined,
+      fieldName: 'rangePicker',
+      label: '鍖洪棿閫夋嫨妗�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+      rules: 'required',
+    },
+  ],
+  wrapperClass: 'grid-cols-1',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Form />
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/auto-height/index.vue b/eims-ui/docs/src/demos/vben-modal/auto-height/index.vue
new file mode 100644
index 0000000..2addf2e
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/auto-height/index.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+import ExtraModal from './modal.vue';
+
+const [Modal, modalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraModal,
+});
+
+function openModal() {
+  modalApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Modal />
+    <VbenButton @click="openModal">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/auto-height/modal.vue b/eims-ui/docs/src/demos/vben-modal/auto-height/modal.vue
new file mode 100644
index 0000000..8757d5e
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/auto-height/modal.vue
@@ -0,0 +1,45 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+const list = ref<number[]>([]);
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    console.log('onConfirm');
+  },
+  onOpenChange(isOpen) {
+    if (isOpen) {
+      handleUpdate(10);
+    }
+  },
+});
+
+function handleUpdate(len: number) {
+  modalApi.setState({ loading: true });
+  setTimeout(() => {
+    list.value = Array.from({ length: len }, (_v, k) => k + 1);
+    modalApi.setState({ loading: false });
+  }, 2000);
+}
+</script>
+<template>
+  <Modal title="鑷姩璁$畻楂樺害">
+    <div
+      v-for="item in list"
+      :key="item"
+      class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
+    >
+      {{ item }}
+    </div>
+    <template #prepend-footer>
+      <VbenButton type="link" @click="handleUpdate(6)">
+        鐐瑰嚮鏇存柊鏁版嵁
+      </VbenButton>
+    </template>
+  </Modal>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/basic/index.vue b/eims-ui/docs/src/demos/vben-modal/basic/index.vue
new file mode 100644
index 0000000..9f89970
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/basic/index.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+const [Modal, modalApi] = useVbenModal();
+</script>
+<template>
+  <div>
+    <VbenButton @click="() => modalApi.open()">Open</VbenButton>
+    <Modal class="w-[600px]" title="鍩虹绀轰緥"> modal content </Modal>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/draggable/index.vue b/eims-ui/docs/src/demos/vben-modal/draggable/index.vue
new file mode 100644
index 0000000..2addf2e
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/draggable/index.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+import ExtraModal from './modal.vue';
+
+const [Modal, modalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraModal,
+});
+
+function openModal() {
+  modalApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Modal />
+    <VbenButton @click="openModal">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/draggable/modal.vue b/eims-ui/docs/src/demos/vben-modal/draggable/modal.vue
new file mode 100644
index 0000000..ecca497
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/draggable/modal.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+const [Modal] = useVbenModal({
+  draggable: true,
+});
+</script>
+<template>
+  <Modal title="鎷栨嫿绀轰緥"> modal content </Modal>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/dynamic/index.vue b/eims-ui/docs/src/demos/vben-modal/dynamic/index.vue
new file mode 100644
index 0000000..718e532
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/dynamic/index.vue
@@ -0,0 +1,30 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+import ExtraModal from './modal.vue';
+
+const [Modal, modalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraModal,
+});
+
+function openModal() {
+  modalApi.open();
+}
+
+function handleUpdateTitle() {
+  modalApi.setState({ title: '澶栭儴鍔ㄦ�佹爣棰�' });
+  modalApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Modal />
+
+    <VbenButton @click="openModal">Open</VbenButton>
+    <VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
+      浠庡閮ㄤ慨鏀规爣棰樺苟鎵撳紑
+    </VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/dynamic/modal.vue b/eims-ui/docs/src/demos/vben-modal/dynamic/modal.vue
new file mode 100644
index 0000000..d461289
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/dynamic/modal.vue
@@ -0,0 +1,38 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+const [Modal, modalApi] = useVbenModal({
+  draggable: true,
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    console.info('onConfirm');
+  },
+  title: '鍔ㄦ�佷慨鏀归厤缃ず渚�',
+});
+
+const state = modalApi.useStore();
+
+function handleUpdateTitle() {
+  modalApi.setState({ title: '鍐呴儴鍔ㄦ�佹爣棰�' });
+}
+
+function handleToggleFullscreen() {
+  modalApi.setState((prev) => {
+    return { ...prev, fullscreen: !prev.fullscreen };
+  });
+}
+</script>
+<template>
+  <Modal>
+    <div class="flex-col-center">
+      <VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
+        鍐呴儴鍔ㄦ�佷慨鏀规爣棰�
+      </VbenButton>
+      <VbenButton class="mb-3" @click="handleToggleFullscreen()">
+        {{ state.fullscreen ? '閫�鍑哄叏灞�' : '鎵撳紑鍏ㄥ睆' }}
+      </VbenButton>
+    </div>
+  </Modal>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/extra/index.vue b/eims-ui/docs/src/demos/vben-modal/extra/index.vue
new file mode 100644
index 0000000..2addf2e
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/extra/index.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+import ExtraModal from './modal.vue';
+
+const [Modal, modalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraModal,
+});
+
+function openModal() {
+  modalApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Modal />
+    <VbenButton @click="openModal">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/extra/modal.vue b/eims-ui/docs/src/demos/vben-modal/extra/modal.vue
new file mode 100644
index 0000000..488fd4a
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/extra/modal.vue
@@ -0,0 +1,8 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+const [Modal] = useVbenModal();
+</script>
+<template>
+  <Modal title="缁勪欢鎶界绀轰緥"> extra modal content </Modal>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/shared-data/index.vue b/eims-ui/docs/src/demos/vben-modal/shared-data/index.vue
new file mode 100644
index 0000000..58c35e2
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/shared-data/index.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { useVbenModal, VbenButton } from '@vben/common-ui';
+
+import ExtraModal from './modal.vue';
+
+const [Modal, modalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: ExtraModal,
+});
+
+function openModal() {
+  modalApi.setData({
+    content: '澶栭儴浼犻�掔殑鏁版嵁 content',
+    payload: '澶栭儴浼犻�掔殑鏁版嵁 payload',
+  });
+  modalApi.open();
+}
+</script>
+
+<template>
+  <div>
+    <Modal />
+
+    <VbenButton @click="openModal">Open</VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-modal/shared-data/modal.vue b/eims-ui/docs/src/demos/vben-modal/shared-data/modal.vue
new file mode 100644
index 0000000..806585d
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-modal/shared-data/modal.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+const data = ref();
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    console.info('onConfirm');
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      data.value = modalApi.getData<Record<string, any>>();
+    }
+  },
+});
+</script>
+<template>
+  <Modal title="鏁版嵁鍏变韩绀轰緥">
+    <div class="flex-col-center">澶栭儴浼犻�掓暟鎹細 {{ data }}</div>
+  </Modal>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/basic/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/basic/index.vue
new file mode 100644
index 0000000..4b6b5a6
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/basic/index.vue
@@ -0,0 +1,85 @@
+<script lang="ts" setup>
+import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button, message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { MOCK_TABLE_DATA } from '../table-data';
+
+interface RowType {
+  address: string;
+  age: number;
+  id: number;
+  name: string;
+  nickname: string;
+  role: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'name', title: 'Name' },
+    { field: 'age', sortable: true, title: 'Age' },
+    { field: 'nickname', title: 'Nickname' },
+    { field: 'role', title: 'Role' },
+    { field: 'address', showOverflow: true, title: 'Address' },
+  ],
+  data: MOCK_TABLE_DATA,
+  pagerConfig: {
+    enabled: false,
+  },
+  sortConfig: {
+    multiple: true,
+  },
+};
+
+const gridEvents: VxeGridListeners<RowType> = {
+  cellClick: ({ row }) => {
+    message.info(`cell-click: ${row.name}`);
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions });
+
+const showBorder = gridApi.useStore((state) => state.gridOptions?.border);
+const showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);
+
+function changeBorder() {
+  gridApi.setGridOptions({
+    border: !showBorder.value,
+  });
+}
+
+function changeStripe() {
+  gridApi.setGridOptions({
+    stripe: !showStripe.value,
+  });
+}
+
+function changeLoading() {
+  gridApi.setLoading(true);
+  setTimeout(() => {
+    gridApi.setLoading(false);
+  }, 2000);
+}
+</script>
+
+<template>
+  <!-- 姝ゅ鐨刞vp-raw` 鏄负浜嗛�傞厤鏂囨。鐨勫睍绀烘晥鏋滐紝瀹為檯浣跨敤鏃朵笉闇�瑕� -->
+  <div class="vp-raw w-full">
+    <Grid>
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="changeBorder">
+          {{ showBorder ? '闅愯棌' : '鏄剧ず' }}杈规
+        </Button>
+        <Button class="mr-2" type="primary" @click="changeLoading">
+          鏄剧ずloading
+        </Button>
+        <Button class="mr-2" type="primary" @click="changeStripe">
+          {{ showStripe ? '闅愯棌' : '鏄剧ず' }}鏂戦┈绾�
+        </Button>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/custom-cell/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/custom-cell/index.vue
new file mode 100644
index 0000000..517e73f
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/custom-cell/index.vue
@@ -0,0 +1,105 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button, Image, Switch, Tag } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { getExampleTableApi } from '../mock-api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  imageUrl: string;
+  open: boolean;
+  price: string;
+  productName: string;
+  releaseDate: string;
+  status: 'error' | 'success' | 'warning';
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'category', title: 'Category', width: 100 },
+    {
+      field: 'imageUrl',
+      slots: { default: 'image-url' },
+      title: 'Image',
+      width: 100,
+    },
+    {
+      cellRender: { name: 'CellImage' },
+      field: 'imageUrl2',
+      title: 'Render Image',
+      width: 130,
+    },
+    {
+      field: 'open',
+      slots: { default: 'open' },
+      title: 'Open',
+      width: 100,
+    },
+    {
+      field: 'status',
+      slots: { default: 'status' },
+      title: 'Status',
+      width: 100,
+    },
+    { field: 'color', title: 'Color', width: 100 },
+    { field: 'productName', title: 'Product Name', width: 200 },
+    { field: 'price', title: 'Price', width: 100 },
+    {
+      field: 'releaseDate',
+      formatter: 'formatDateTime',
+      title: 'Date',
+      width: 200,
+    },
+    {
+      cellRender: { name: 'CellLink', props: { text: '缂栬緫' } },
+      field: 'action',
+      fixed: 'right',
+      title: '鎿嶄綔',
+      width: 120,
+    },
+  ],
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid>
+      <template #image-url="{ row }">
+        <Image :src="row.imageUrl" height="30" width="30" />
+      </template>
+      <template #open="{ row }">
+        <Switch v-model:checked="row.open" />
+      </template>
+      <template #status="{ row }">
+        <Tag :color="row.color">{{ row.status }}</Tag>
+      </template>
+      <template #action>
+        <Button type="link">缂栬緫</Button>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/edit-cell/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/edit-cell/index.vue
new file mode 100644
index 0000000..711941d
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/edit-cell/index.vue
@@ -0,0 +1,55 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { getExampleTableApi } from '../mock-api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { editRender: { name: 'input' }, field: 'category', title: 'Category' },
+    { editRender: { name: 'input' }, field: 'color', title: 'Color' },
+    {
+      editRender: { name: 'input' },
+      field: 'productName',
+      title: 'Product Name',
+    },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+  ],
+  editConfig: {
+    mode: 'cell',
+    trigger: 'click',
+  },
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  showOverflow: true,
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid />
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/edit-row/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/edit-row/index.vue
new file mode 100644
index 0000000..f317f69
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/edit-row/index.vue
@@ -0,0 +1,92 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button, message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { getExampleTableApi } from '../mock-api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { editRender: { name: 'input' }, field: 'category', title: 'Category' },
+    { editRender: { name: 'input' }, field: 'color', title: 'Color' },
+    {
+      editRender: { name: 'input' },
+      field: 'productName',
+      title: 'Product Name',
+    },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+    { slots: { default: 'action' }, title: '鎿嶄綔' },
+  ],
+  editConfig: {
+    mode: 'row',
+    trigger: 'click',
+  },
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  showOverflow: true,
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+function hasEditStatus(row: RowType) {
+  return gridApi.grid?.isEditByRow(row);
+}
+
+function editRowEvent(row: RowType) {
+  gridApi.grid?.setEditRow(row);
+}
+
+async function saveRowEvent(row: RowType) {
+  await gridApi.grid?.clearEdit();
+
+  gridApi.setLoading(true);
+  setTimeout(() => {
+    gridApi.setLoading(false);
+    message.success({
+      content: `淇濆瓨鎴愬姛锛乧ategory=${row.category}`,
+    });
+  }, 600);
+}
+
+const cancelRowEvent = (_row: RowType) => {
+  gridApi.grid?.clearEdit();
+};
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid>
+      <template #action="{ row }">
+        <template v-if="hasEditStatus(row)">
+          <Button type="link" @click="saveRowEvent(row)">淇濆瓨</Button>
+          <Button type="link" @click="cancelRowEvent(row)">鍙栨秷</Button>
+        </template>
+        <template v-else>
+          <Button type="link" @click="editRowEvent(row)">缂栬緫</Button>
+        </template>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/fixed/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/fixed/index.vue
new file mode 100644
index 0000000..6067a5e
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/fixed/index.vue
@@ -0,0 +1,67 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { getExampleTableApi } from '../mock-api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { fixed: 'left', title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'category', title: 'Category', width: 300 },
+    { field: 'color', title: 'Color', width: 300 },
+    { field: 'productName', title: 'Product Name', width: 300 },
+    { field: 'price', title: 'Price', width: 300 },
+    {
+      field: 'releaseDate',
+      formatter: 'formatDateTime',
+      title: 'DateTime',
+      width: 500,
+    },
+    {
+      field: 'action',
+      fixed: 'right',
+      slots: { default: 'action' },
+      title: '鎿嶄綔',
+      width: 120,
+    },
+  ],
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid>
+      <template #action>
+        <Button type="link">缂栬緫</Button>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/form/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/form/index.vue
new file mode 100644
index 0000000..b5be6c6
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/form/index.vue
@@ -0,0 +1,122 @@
+<script lang="ts" setup>
+import type { VbenFormProps } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { getExampleTableApi } from '../mock-api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const formOptions: VbenFormProps = {
+  // 榛樿灞曞紑
+  collapsed: false,
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'Please enter category',
+      },
+      defaultValue: '1',
+      fieldName: 'category',
+      label: 'Category',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'Please enter productName',
+      },
+      fieldName: 'productName',
+      label: 'ProductName',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: 'Please enter price',
+      },
+      fieldName: 'price',
+      label: 'Price',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        options: [
+          {
+            label: 'Color1',
+            value: '1',
+          },
+          {
+            label: 'Color2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+      },
+      fieldName: 'color',
+      label: 'Color',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: 'Date',
+    },
+  ],
+  // 鎺у埗琛ㄥ崟鏄惁鏄剧ず鎶樺彔鎸夐挳
+  showCollapseButton: true,
+  submitButtonOptions: {
+    content: '鏌ヨ',
+  },
+  // 鏄惁鍦ㄥ瓧娈靛�兼敼鍙樻椂鎻愪氦琛ㄥ崟
+  submitOnChange: false,
+  // 鎸変笅鍥炶溅鏃舵槸鍚︽彁浜よ〃鍗�
+  submitOnEnter: false,
+};
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },
+    { field: 'category', title: 'Category' },
+    { field: 'color', title: 'Color' },
+    { field: 'productName', title: 'Product Name' },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+  ],
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues) => {
+        message.success(`Query params: ${JSON.stringify(formValues)}`);
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid />
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/mock-api.ts b/eims-ui/docs/src/demos/vben-vxe-table/mock-api.ts
new file mode 100644
index 0000000..e5c40b6
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/mock-api.ts
@@ -0,0 +1,36 @@
+import { MOCK_API_DATA } from './table-data';
+
+export namespace DemoTableApi {
+  export interface PageFetchParams {
+    [key: string]: any;
+    page: number;
+    pageSize: number;
+  }
+}
+
+export function sleep(time = 1000) {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(true);
+    }, time);
+  });
+}
+
+/**
+ * 鑾峰彇绀轰緥琛ㄦ牸鏁版嵁
+ */
+async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
+  return new Promise<{ items: any; total: number }>((resolve) => {
+    const { page, pageSize } = params;
+    const items = MOCK_API_DATA.slice((page - 1) * pageSize, page * pageSize);
+
+    sleep(1000).then(() => {
+      resolve({
+        total: items.length,
+        items,
+      });
+    });
+  });
+}
+
+export { getExampleTableApi };
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/remote/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/remote/index.vue
new file mode 100644
index 0000000..bc93d29
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/remote/index.vue
@@ -0,0 +1,112 @@
+<script lang="ts" setup>
+import type { DemoTableApi } from '../mock-api';
+
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { MOCK_API_DATA } from '../table-data';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+// 鏁版嵁瀹炰緥
+// const MOCK_TREE_TABLE_DATA = [
+//   {
+//     date: '2020-08-01',
+//     id: 10_000,
+//     name: 'Test1',
+//     parentId: null,
+//     size: 1024,
+//     type: 'mp3',
+//   },
+// ]
+
+const sleep = (time = 1000) => {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve(true);
+    }, time);
+  });
+};
+
+/**
+ * 鑾峰彇绀轰緥琛ㄦ牸鏁版嵁
+ */
+async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
+  return new Promise<{ items: any; total: number }>((resolve) => {
+    const { page, pageSize } = params;
+    const items = MOCK_API_DATA.slice((page - 1) * pageSize, page * pageSize);
+
+    sleep(1000).then(() => {
+      resolve({
+        total: items.length,
+        items,
+      });
+    });
+  });
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },
+    { field: 'category', title: 'Category' },
+    { field: 'color', title: 'Color' },
+    { field: 'productName', title: 'Product Name' },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
+  ],
+  exportConfig: {},
+  // height: 'auto', // 濡傛灉璁剧疆涓� auto锛屽垯蹇呴』纭繚瀛樺湪鐖惰妭鐐逛笖涓嶅厑璁稿瓨鍦ㄧ浉閭诲厓绱狅紝鍚﹀垯浼氬嚭鐜伴珮搴﹂棯鍔ㄩ棶棰�
+  keepSource: true,
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  toolbarConfig: {
+    custom: true,
+    export: true,
+    // import: true,
+    refresh: true,
+    zoom: true,
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  gridOptions,
+});
+</script>
+
+<template>
+  <div class="vp-raw w-full">
+    <Grid>
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="() => gridApi.query()">
+          鍒锋柊褰撳墠椤甸潰
+        </Button>
+        <Button type="primary" @click="() => gridApi.reload()">
+          鍒锋柊骞惰繑鍥炵涓�椤�
+        </Button>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/table-data.ts b/eims-ui/docs/src/demos/vben-vxe-table/table-data.ts
new file mode 100644
index 0000000..c37b88a
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/table-data.ts
@@ -0,0 +1,384 @@
+interface TableRowData {
+  address: string;
+  age: number;
+  id: number;
+  name: string;
+  nickname: string;
+  role: string;
+}
+
+const roles = ['User', 'Admin', 'Manager', 'Guest'];
+
+export const MOCK_TABLE_DATA: TableRowData[] = (() => {
+  const data: TableRowData[] = [];
+  for (let i = 0; i < 10; i++) {
+    data.push({
+      address: `New York${i}`,
+      age: i + 1,
+      id: i,
+      name: `Test${i}`,
+      nickname: `Test${i}`,
+      role: roles[Math.floor(Math.random() * roles.length)] as string,
+    });
+  }
+  return data;
+})();
+
+export const MOCK_TREE_TABLE_DATA = [
+  {
+    date: '2020-08-01',
+    id: 10_000,
+    name: 'Test1',
+    parentId: null,
+    size: 1024,
+    type: 'mp3',
+  },
+  {
+    date: '2021-04-01',
+    id: 10_050,
+    name: 'Test2',
+    parentId: null,
+    size: 0,
+    type: 'mp4',
+  },
+  {
+    date: '2020-03-01',
+    id: 24_300,
+    name: 'Test3',
+    parentId: 10_050,
+    size: 1024,
+    type: 'avi',
+  },
+  {
+    date: '2021-04-01',
+    id: 20_045,
+    name: 'Test4',
+    parentId: 24_300,
+    size: 600,
+    type: 'html',
+  },
+  {
+    date: '2021-04-01',
+    id: 10_053,
+    name: 'Test5',
+    parentId: 24_300,
+    size: 0,
+    type: 'avi',
+  },
+  {
+    date: '2021-10-01',
+    id: 24_330,
+    name: 'Test6',
+    parentId: 10_053,
+    size: 25,
+    type: 'txt',
+  },
+  {
+    date: '2020-01-01',
+    id: 21_011,
+    name: 'Test7',
+    parentId: 10_053,
+    size: 512,
+    type: 'pdf',
+  },
+  {
+    date: '2021-06-01',
+    id: 22_200,
+    name: 'Test8',
+    parentId: 10_053,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2020-11-01',
+    id: 23_666,
+    name: 'Test9',
+    parentId: null,
+    size: 2048,
+    type: 'xlsx',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_677,
+    name: 'Test10',
+    parentId: 23_666,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_671,
+    name: 'Test11',
+    parentId: 23_677,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_672,
+    name: 'Test12',
+    parentId: 23_677,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_688,
+    name: 'Test13',
+    parentId: 23_666,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_681,
+    name: 'Test14',
+    parentId: 23_688,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_682,
+    name: 'Test15',
+    parentId: 23_688,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2020-10-01',
+    id: 24_555,
+    name: 'Test16',
+    parentId: null,
+    size: 224,
+    type: 'avi',
+  },
+  {
+    date: '2021-06-01',
+    id: 24_566,
+    name: 'Test17',
+    parentId: 24_555,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 24_577,
+    name: 'Test18',
+    parentId: 24_555,
+    size: 1024,
+    type: 'js',
+  },
+];
+
+export const MOCK_API_DATA = [
+  {
+    available: true,
+    category: 'Computers',
+    color: 'purple',
+    currency: 'NAD',
+    description:
+      'Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support',
+    id: '45a613df-227a-4907-a89f-4a7f1252ca0c',
+    imageUrl: 'https://avatars.githubusercontent.com/u/62715097',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/75395683',
+    inProduction: false,
+    open: true,
+    price: '48.89',
+    productName: 'Handcrafted Steel Salad',
+    quantity: 70,
+    rating: 3.780_582_329_574_367,
+    releaseDate: '2024-09-09T04:06:57.793Z',
+    status: 'error',
+    tags: ['Bespoke', 'Handmade', 'Luxurious'],
+    weight: 1.031_015_671_912_002_5,
+  },
+  {
+    available: true,
+    category: 'Toys',
+    color: 'green',
+    currency: 'CZK',
+    description:
+      'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',
+    id: 'd02e5ee9-bc98-4de2-98fa-25a6567ecc19',
+    imageUrl: 'https://avatars.githubusercontent.com/u/51512330',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/58698113',
+    inProduction: false,
+    open: false,
+    price: '68.15',
+    productName: 'Generic Cotton Gloves',
+    quantity: 3,
+    rating: 1.681_749_367_682_703_3,
+    releaseDate: '2024-06-16T09:00:36.806Z',
+    status: 'warning',
+    tags: ['Rustic', 'Handcrafted', 'Recycled'],
+    weight: 9.601_076_149_300_575,
+  },
+  {
+    available: true,
+    category: 'Beauty',
+    color: 'teal',
+    currency: 'OMR',
+    description:
+      'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',
+    id: '2b72521c-225c-4e64-8030-611b76b10b37',
+    imageUrl: 'https://avatars.githubusercontent.com/u/50300075',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/36541691',
+    inProduction: true,
+    open: true,
+    price: '696.94',
+    productName: 'Gorgeous Soft Ball',
+    quantity: 50,
+    rating: 2.361_581_777_372_057_5,
+    releaseDate: '2024-06-03T13:24:19.809Z',
+    status: 'warning',
+    tags: ['Gorgeous', 'Ergonomic', 'Licensed'],
+    weight: 8.882_340_049_286_19,
+  },
+  {
+    available: true,
+    category: 'Games',
+    color: 'silver',
+    currency: 'SOS',
+    description:
+      'Carbonite web goalkeeper gloves are ergonomically designed to give easy fit',
+    id: 'bafab694-3801-452c-b102-9eb519bd1143',
+    imageUrl: 'https://avatars.githubusercontent.com/u/89827115',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/55952747',
+    inProduction: false,
+    open: false,
+    price: '553.84',
+    productName: 'Bespoke Soft Computer',
+    quantity: 29,
+    rating: 2.176_412_873_760_271_7,
+    releaseDate: '2024-09-17T12:16:27.034Z',
+    status: 'error',
+    tags: ['Elegant', 'Rustic', 'Recycled'],
+    weight: 9.653_285_869_978_038,
+  },
+  {
+    available: true,
+    category: 'Toys',
+    color: 'indigo',
+    currency: 'BIF',
+    description:
+      'Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals',
+    id: 'bf6dea6b-2a55-441d-8773-937e03d99389',
+    imageUrl: 'https://avatars.githubusercontent.com/u/21431092',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/3771350',
+    inProduction: true,
+    open: true,
+    price: '237.39',
+    productName: 'Handcrafted Cotton Mouse',
+    quantity: 54,
+    rating: 4.363_265_388_265_461,
+    releaseDate: '2023-10-23T13:42:34.947Z',
+    status: 'error',
+    tags: ['Unbranded', 'Handmade', 'Generic'],
+    weight: 9.513_203_612_535_571,
+  },
+  {
+    available: false,
+    category: 'Tools',
+    color: 'violet',
+    currency: 'TZS',
+    description:
+      'New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016',
+    id: '135ba6ab-32ee-4989-8189-5cfa658ef970',
+    imageUrl: 'https://avatars.githubusercontent.com/u/29946092',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/23842994',
+    inProduction: false,
+    open: false,
+    price: '825.25',
+    productName: 'Awesome Bronze Ball',
+    quantity: 94,
+    rating: 4.251_159_804_726_753,
+    releaseDate: '2023-12-30T07:31:43.464Z',
+    status: 'warning',
+    tags: ['Handmade', 'Elegant', 'Unbranded'],
+    weight: 2.247_473_385_732_636_8,
+  },
+  {
+    available: true,
+    category: 'Automotive',
+    color: 'teal',
+    currency: 'BOB',
+    description: 'The Football Is Good For Training And Recreational Purposes',
+    id: '652ef256-7d4e-48b7-976c-7afaa781ea92',
+    imageUrl: 'https://avatars.githubusercontent.com/u/2531904',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/15215990',
+    inProduction: false,
+    open: false,
+    price: '780.49',
+    productName: 'Oriental Rubber Pants',
+    quantity: 70,
+    rating: 2.636_323_417_377_916,
+    releaseDate: '2024-02-23T23:30:49.628Z',
+    status: 'success',
+    tags: ['Unbranded', 'Elegant', 'Unbranded'],
+    weight: 4.812_965_858_018_838,
+  },
+  {
+    available: false,
+    category: 'Garden',
+    color: 'plum',
+    currency: 'LRD',
+    description:
+      'The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality',
+    id: '3ea24798-6589-40cc-85f0-ab78752244a0',
+    imageUrl: 'https://avatars.githubusercontent.com/u/23165285',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/14595665',
+    inProduction: false,
+    open: true,
+    price: '583.85',
+    productName: 'Handcrafted Concrete Hat',
+    quantity: 15,
+    rating: 1.371_600_527_752_802_7,
+    releaseDate: '2024-03-02T19:40:50.255Z',
+    status: 'error',
+    tags: ['Rustic', 'Sleek', 'Ergonomic'],
+    weight: 4.926_949_366_405_728_4,
+  },
+  {
+    available: false,
+    category: 'Industrial',
+    color: 'salmon',
+    currency: 'AUD',
+    description:
+      'The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design',
+    id: '997113dd-f6e4-4acc-9790-ef554c7498d1',
+    imageUrl: 'https://avatars.githubusercontent.com/u/49021914',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/4690621',
+    inProduction: true,
+    open: false,
+    price: '67.99',
+    productName: 'Generic Rubber Bacon',
+    quantity: 68,
+    rating: 4.129_840_682_128_08,
+    releaseDate: '2023-12-17T01:40:25.415Z',
+    status: 'error',
+    tags: ['Oriental', 'Small', 'Handcrafted'],
+    weight: 1.080_114_331_801_906_4,
+  },
+  {
+    available: false,
+    category: 'Tools',
+    color: 'sky blue',
+    currency: 'NOK',
+    description:
+      'The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J',
+    id: 'f697a250-6cb2-46c8-b0f7-871ab1f2fa8d',
+    imageUrl: 'https://avatars.githubusercontent.com/u/95928385',
+    imageUrl2: 'https://avatars.githubusercontent.com/u/47588244',
+    inProduction: false,
+    open: false,
+    price: '613.89',
+    productName: 'Gorgeous Frozen Ball',
+    quantity: 55,
+    rating: 1.646_947_205_998_534_6,
+    releaseDate: '2024-10-13T12:31:04.929Z',
+    status: 'warning',
+    tags: ['Handmade', 'Unbranded', 'Unbranded'],
+    weight: 9.430_690_557_758_114,
+  },
+];
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/tree/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/tree/index.vue
new file mode 100644
index 0000000..0024765
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/tree/index.vue
@@ -0,0 +1,80 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { MOCK_TREE_TABLE_DATA } from '../table-data';
+
+interface RowType {
+  date: string;
+  id: number;
+  name: string;
+  parentId: null | number;
+  size: number;
+  type: string;
+}
+
+// 鏁版嵁瀹炰緥
+// const MOCK_TREE_TABLE_DATA = [
+//   {
+//     date: '2020-08-01',
+//     id: 10_000,
+//     name: 'Test1',
+//     parentId: null,
+//     size: 1024,
+//     type: 'mp3',
+//   },
+//   {
+//     date: '2021-04-01',
+//     id: 10_050,
+//     name: 'Test2',
+//     parentId: 10_000,
+//     size: 0,
+//     type: 'mp4',
+//   },
+// ];
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { type: 'seq', width: 70 },
+    { field: 'name', minWidth: 300, title: 'Name', treeNode: true },
+    { field: 'size', title: 'Size' },
+    { field: 'type', title: 'Type' },
+    { field: 'date', title: 'Date' },
+  ],
+  data: MOCK_TREE_TABLE_DATA,
+  pagerConfig: {
+    enabled: false,
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    transform: true,
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+const expandAll = () => {
+  gridApi.grid?.setAllTreeExpand(true);
+};
+
+const collapseAll = () => {
+  gridApi.grid?.setAllTreeExpand(false);
+};
+</script>
+
+<template>
+  <div class="vp-raw h-[300px] w-full">
+    <Grid>
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="expandAll">
+          灞曞紑鍏ㄩ儴
+        </Button>
+        <Button type="primary" @click="collapseAll"> 鎶樺彔鍏ㄩ儴 </Button>
+      </template>
+    </Grid>
+  </div>
+</template>
diff --git a/eims-ui/docs/src/demos/vben-vxe-table/virtual/index.vue b/eims-ui/docs/src/demos/vben-vxe-table/virtual/index.vue
new file mode 100644
index 0000000..81fa00a
--- /dev/null
+++ b/eims-ui/docs/src/demos/vben-vxe-table/virtual/index.vue
@@ -0,0 +1,64 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { onMounted } from 'vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+interface RowType {
+  id: number;
+  name: string;
+  role: string;
+  sex: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { type: 'seq', width: 70 },
+    { field: 'name', title: 'Name' },
+    { field: 'role', title: 'Role' },
+    { field: 'sex', title: 'Sex' },
+  ],
+  data: [],
+  height: 'auto',
+  pagerConfig: {
+    enabled: false,
+  },
+  scrollY: {
+    enabled: true,
+    gt: 0,
+  },
+  showOverflow: true,
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+// 妯℃嫙琛屾暟鎹�
+const loadList = (size = 200) => {
+  try {
+    const dataList: RowType[] = [];
+    for (let i = 0; i < size; i++) {
+      dataList.push({
+        id: 10_000 + i,
+        name: `Test${i}`,
+        role: 'Developer',
+        sex: '鐢�',
+      });
+    }
+    gridApi.setGridOptions({ data: dataList });
+  } catch (error) {
+    console.error('Failed to load data:', error);
+    // Implement user-friendly error handling
+  }
+};
+
+onMounted(() => {
+  loadList(1000);
+});
+</script>
+
+<template>
+  <div class="vp-raw h-[500px] w-full">
+    <Grid />
+  </div>
+</template>
diff --git a/eims-ui/docs/src/en/guide/essentials/build.md b/eims-ui/docs/src/en/guide/essentials/build.md
new file mode 100644
index 0000000..7f5c953
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/build.md
@@ -0,0 +1,243 @@
+# Build and Deployment
+
+::: tip Preface
+
+Since this is a demonstration project, the package size after building is relatively large. If there are plugins in the project that are not used, you can delete the corresponding files or routes. If they are not referenced, they will not be packaged.
+
+:::
+
+## Building
+
+After the project development is completed, execute the following command to build:
+
+**Note:** Please execute the following command in the project root directory.
+
+```bash
+pnpm build
+```
+
+After the build is successful, a `dist` folder for the corresponding application will be generated in the root directory, which contains the built and packaged files, for example: `apps/web-antd/dist/`
+
+## Preview
+
+Before publishing, you can preview it locally in several ways, here are two:
+
+- Using the project's custom command for preview (recommended)
+
+**Note锛�** Please execute the following command in the project root directory.
+
+```bash
+pnpm preview
+```
+
+After waiting for the build to succeed, visit `http://localhost:4173` to view the effect.
+
+- Local server preview
+
+You can globally install a `serve` service on your computer, such as `live-server`,
+
+```bash
+npm i -g live-server
+```
+
+Then execute the `live-server` command in the `dist` directory to view the effect locally.
+
+```bash
+cd apps/web-antd/dist
+# Local preview, default port 8080
+live-server
+# Specify port
+live-server --port 9000
+```
+
+## Compression
+
+### Enable `gzip` Compression
+
+To enable during the build process, change the `.env.production` configuration:
+
+```bash
+VITE_COMPRESS=gzip
+```
+
+### Enable `brotli` Compression
+
+To enable during the build process, change the `.env.production` configuration:
+
+```bash
+VITE_COMPRESS=brotli
+```
+
+### Enable Both `gzip` and `brotli` Compression
+
+To enable during the build process, change the `.env.production` configuration:
+
+```bash
+VITE_COMPRESS=gzip,brotli
+```
+
+::: tip Note
+
+Both `gzip` and `brotli` require specific modules to be installed for use.
+
+:::
+
+::: details gzip 涓� brotli 鍦� nginx 鍐呯殑閰嶇疆
+
+```bash
+http {
+  # Enable gzip
+  gzip on;
+  # Enable gzip_static
+  # After enabling gzip_static, there might be errors, requiring the installation of specific modules. The installation method can be researched independently.
+  # Only with this enabled, the .gz files packaged by vue files will be effective; otherwise, there is no need to enable gzip for packaging.
+  gzip_static on;
+  gzip_proxied any;
+  gzip_min_length 1k;
+  gzip_buffers 4 16k;
+  # If nginx uses multiple layers of proxy, this must be set to enable gzip.
+  gzip_http_version 1.0;
+  gzip_comp_level 2;
+  gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
+  gzip_vary off;
+  gzip_disable "MSIE [1-6]\.";
+
+  # Enable brotli compression
+  # Requires the installation of the corresponding nginx module, which can be researched independently.
+  # Can coexist with gzip without conflict.
+  brotli on;
+  brotli_comp_level 6;
+  brotli_buffers 16 8k;
+  brotli_min_length 20;
+  brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
+}
+```
+
+:::
+
+## Build Analysis
+
+If your build files are large, you can optimize your code by analyzing the code size with the built-in [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) plugin. Just execute the following command in the `root directory`:
+
+```bash
+pnpm run build:analyze
+```
+
+After running, you can see the specific distribution of sizes on the automatically opened page to analyze which dependencies are problematic.
+
+![Build analysis report](/guide/report.png)
+
+## Deployment
+
+A simple deployment only requires publishing the final static files, the static files in the dist folder, to your CDN or static server. It's important to note that the index.html is usually the entry page for your backend service. After determining the static js and css, you may need to change the page's import path.
+
+For example, to upload to an nginx server, you can upload the files under the dist folder to the server's `/srv/www/project/index.html` directory, and then access the configured domain name.
+
+```bash
+# nginx configuration
+location / {
+  # Do not cache html to prevent cache from continuing to be effective after program updates
+  if ($request_filename ~* .*\.(?:htm|html)$) {
+    add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
+    access_log on;
+  }
+  # This is the storage path for the files inside the vue packaged dist folder
+  root   /srv/www/project/;
+  index  index.html index.htm;
+}
+```
+
+If you find the resource path is incorrect during deployment, you just need to modify the `.env.production` file.
+
+```bash
+# Configure the change according to your own path
+# Note that it needs to start and end with /
+VITE_BASE=/
+VITE_BASE=/xxx/
+```
+
+### Integration of Frontend Routing and Server
+
+The project uses vue-router for frontend routing, so you can choose between two modes: history and hash.
+
+- `hash` mode will append `#` to the URL by default.
+- `history` mode will not, but `history` mode requires server-side support.
+
+You can modify the mode in `.env.production`:
+
+```bash
+VITE_ROUTER_HISTORY=hash
+```
+
+### Server Configuration for History Mode Routing
+
+Enabling `history` mode requires server configuration. For more details on server configuration, see [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode)
+
+Here is an example of `nginx` configuration:
+
+#### Deployment at the Root Directory
+
+```bash {5}
+server {
+  listen 80;
+  location / {
+    # For use with History mode
+    try_files $uri $uri/ /index.html;
+  }
+}
+```
+
+#### Deployment to a Non-root Directory
+
+- First, you need to change the `.env.production` configuration during packaging:
+
+```bash
+VITE_BASE = /sub/
+```
+
+- Then configure in the nginx configuration file
+
+```bash {8}
+server {
+    listen       80;
+    server_name  localhost;
+    location /sub/ {
+      # This is the path where the vue packaged dist files are stored
+      alias   /srv/www/project/;
+      index index.html index.htm;
+      try_files $uri $uri/ /sub/index.html;
+    }
+}
+```
+
+## Cross-Domain Handling
+
+Using nginx to handle cross-domain issues after project deployment
+
+1. Configure the frontend project API address in the `.env.production` file in the project directory:
+
+```bash
+VITE_GLOB_API_URL=/api
+```
+
+2. Configure nginx to forward requests to the backend
+
+```bash {10-11}
+server {
+  listen       8080;
+  server_name  localhost;
+  # API proxy for solving cross-domain issues
+  location /api {
+    proxy_set_header Host $host;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    # Backend API address
+    proxy_pass http://110.110.1.1:8080/api;
+    rewrite "^/api/(.*)$" /$1 break;
+    proxy_redirect default;
+    add_header Access-Control-Allow-Origin *;
+    add_header Access-Control-Allow-Headers X-Requested-With;
+    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
+  }
+}
+```
diff --git a/eims-ui/docs/src/en/guide/essentials/concept.md b/eims-ui/docs/src/en/guide/essentials/concept.md
new file mode 100644
index 0000000..8c940a9
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/concept.md
@@ -0,0 +1,70 @@
+# Basic Concepts
+
+In the new version, the entire project has been restructured. Now, we will introduce some basic concepts to help you better understand the entire document. Please make sure to read this section first.
+
+## Monorepo
+
+Monorepo refers to the repository of the entire project, which includes all code, packages, applications, standards, documentation, configurations, etc., that is, the entire content of a `Monorepo` directory.
+
+## Applications
+
+Applications refer to a complete project; a project can contain multiple applications, which can reuse the code, packages, standards, etc., within the monorepo. Applications are placed in the `apps` directory. Each application is independent and can be run, built, tested, and deployed separately; it can also include different component libraries, etc.
+
+::: tip
+
+Applications are not limited to front-end applications; they can also be back-end applications, mobile applications, etc. For example, `apps/backend-mock` is a back-end service.
+
+:::
+
+## Packages
+
+A package refers to an independent module, which can be a component, a tool, a library, etc. Packages can be referenced by multiple applications or other packages. Packages are placed in the `packages` directory.
+
+You can consider these packages as independent `npm` packages, and they are used in the same way as `npm` packages.
+
+### Package Import
+
+Importing a package in `package.json`:
+
+```json {3}
+{
+  "dependencies": {
+    "@vben/utils": "workspace:*"
+  }
+}
+```
+
+### Package Usage
+
+Importing a package in the code:
+
+```ts
+import { isString } from '@vben/utils';
+```
+
+## Aliases
+
+In the project, you can see some paths starting with `#`, such as `#/api`, `#/views`. These paths are aliases, used for quickly locating a certain directory. They are not implemented through `vite`'s `alias`, but through the principle of [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) in `Node.js` itself. You only need to configure the `imports` field in `package.json`.
+
+```json {3}
+{
+  "imports": {
+    "#/*": "./src/*"
+  }
+}
+```
+
+To make these aliases recognizable by the IDE, we also need to configure them in `tsconfig.json`:
+
+```json {5}
+{
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["src/*"]
+    }
+  }
+}
+```
+
+This way, you can use aliases in your code.
diff --git a/eims-ui/docs/src/en/guide/essentials/development.md b/eims-ui/docs/src/en/guide/essentials/development.md
new file mode 100644
index 0000000..da7cfd8
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/development.md
@@ -0,0 +1,188 @@
+# Local Development {#development}
+
+::: tip Code Acquisition
+
+If you haven't acquired the code yet, you can start by reading the documentation from [Quick Start](../introduction/quick-start.md).
+
+:::
+
+## Prerequisites
+
+For a better development experience, we provide some tool configurations and project descriptions to facilitate your development.
+
+### Required Basic Knowledge
+
+This project requires some basic frontend knowledge. Please ensure you are familiar with the basics of Vue to handle common issues. It is recommended to learn the following topics before development. Understanding these will be very helpful for the project:
+
+- [Vue3](https://vuejs.org/)
+- [Tailwind CSS](https://tailwindcss.com/)
+- [TypeScript](https://www.typescriptlang.org/)
+- [Vue Router](https://router.vuejs.org/)
+- [Vitejs](https://vitejs.dev/)
+- [Pnpm](https://pnpm.io/)
+- [Turbo](https://turbo.build/)
+
+### Tool Configuration
+
+If you are using [vscode](https://code.visualstudio.com/) (recommended) as your IDE, you can install the following tools to improve development efficiency and code formatting:
+
+- [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Official Vue plugin (essential).
+- [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwind CSS autocomplete plugin.
+- [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=vunguyentuan.vscode-css-variables) - CSS variable autocomplete plugin.
+- [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify icon plugin.
+- [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n plugin.
+- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code linting.
+- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting.
+- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting.
+- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Spelling checker.
+- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env file highlighting.
+
+## Npm Scripts
+
+Npm scripts are common configurations used in the project to perform common tasks such as starting the project, building the project, etc. The following scripts can be found in the `package.json` file at the root of the project.
+
+The execution command is: `pnpm run [script]` or `npm run [script]`.
+
+```json
+{
+  "scripts": {
+    // Build the project
+    "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
+    // Build the project with analysis
+    "build:analyze": "turbo build:analyze",
+    // Build a local Docker image
+    "build:docker": "./build-local-docker-image.sh",
+    // Build the web-antd application separately
+    "build:antd": "pnpm run build --filter=@vben/web-antd",
+    // Build the documentation separately
+    "build:docs": "pnpm run build --filter=@vben/docs",
+    // Build the web-ele application separately
+    "build:ele": "pnpm run build --filter=@vben/web-ele",
+    // Build the web-naive application separately
+    "build:naive": "pnpm run build --filter=@vben/naive",
+    // Build the playground application separately
+    "build:play": "pnpm run build --filter=@vben/playground",
+    // Changeset version management
+    "changeset": "pnpm exec changeset",
+    // Check for various issues in the project
+    "check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell",
+    // Check for circular dependencies
+    "check:circular": "vsh check-circular",
+    // Check spelling
+    "check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress"
+    // Check dependencies
+    "check:dep": "vsh check-dep",
+    // Check types
+    "check:type": "turbo run typecheck",
+    // Clean the project (delete node_modules, dist, .turbo, etc.)
+    "clean": "node ./scripts/clean.mjs",
+    // Commit code
+    "commit": "czg",
+    // Start the project (by default, the dev scripts of all packages in the entire repository will run)
+    "dev": "turbo-run dev",
+    // Start the web-antd application
+    "dev:antd": "pnpm -F @vben/web-antd run dev",
+    // Start the documentation
+    "dev:docs": "pnpm -F @vben/docs run dev",
+    // Start the web-ele application
+    "dev:ele": "pnpm -F @vben/web-ele run dev",
+    // Start the web-naive application
+    "dev:naive": "pnpm -F @vben/web-naive run dev",
+    // Start the playground application
+    "dev:play": "pnpm -F @vben/playground run dev",
+    // Format code
+    "format": "vsh lint --format",
+    // Lint code
+    "lint": "vsh lint",
+    // After installing dependencies, execute the stub script for all packages
+    "postinstall": "pnpm -r run stub --if-present",
+    // Only allow using pnpm
+    "preinstall": "npx only-allow pnpm",
+    // Install husky
+    "prepare": "is-ci || husky",
+    // Preview the application
+    "preview": "turbo-run preview",
+    // Package specification check
+    "publint": "vsh publint",
+    // Delete all node_modules, yarn.lock, package.lock.json, and reinstall dependencies
+    "reinstall": "pnpm clean --del-lock && pnpm install",
+    // Run vitest unit tests
+    "test:unit": "vitest run --dom",
+    // Update project dependencies
+    "update:deps": " pnpm update --latest --recursive",
+    // Changeset generation and versioning
+    "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
+  }
+}
+```
+
+## Running the Project Locally
+
+To run the documentation locally and make adjustments, you can execute the following command. This command allows you to select the application you want to develop:
+
+```bash
+pnpm dev
+```
+
+If you want to run a specific application directly, you can execute the following commands:
+
+To run the `web-antd` application:
+
+```bash
+pnpm dev:antd
+```
+
+To run the `web-naive` application:
+
+```bash
+pnpm dev:naive
+```
+
+To run the `web-ele` application:
+
+```bash
+pnpm dev:ele
+```
+
+To run the `docs` application:
+
+```bash
+pnpm dev:docs
+```
+
+## Public Static Resources
+
+If you need to use public static resources in the project, such as images, static HTML, etc., and you want to directly import them in the development process through `src="/xxx.png"`.
+
+You need to put the resource in the corresponding project's `public/static` directory. The import path for the resource should be `src="/static/xxx.png"`.
+
+## DevTools
+
+The project has a built-in [Vue DevTools](https://github.com/vuejs/devtools-next) plugin, which can be used during development. It is disabled by default, but can be enabled in the `.env.development` file. After enabling it, restart the project:
+
+```bash
+VITE_DEVTOOLS=true
+```
+
+Once enabled, a Vue DevTools icon will appear at the bottom of the page during project runtime. Click it to open the DevTools.
+
+![Vue DevTools](/guide/devtools.png)
+
+## Running Documentation Locally
+
+To run the documentation locally and make adjustments, you can execute the following command:
+
+```bash
+pnpm dev:docs
+```
+
+## Troubleshooting
+
+If you encounter dependency-related issues, you can try reinstalling the dependencies:
+
+```bash
+# Execute this command at the root of the project.
+# This command will delete all node_modules, yarn.lock, and package.lock.json files
+# and then reinstall dependencies (this process will be noticeably slower).
+pnpm reinstall
+```
diff --git a/eims-ui/docs/src/en/guide/essentials/external-module.md b/eims-ui/docs/src/en/guide/essentials/external-module.md
new file mode 100644
index 0000000..f0a6d6e
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/external-module.md
@@ -0,0 +1,58 @@
+# External Modules
+
+In addition to the external modules that are included by default in the project, sometimes we need to import other external modules. Let's take [ant-design-vue](https://antdv.com/components/overview) as an example:
+
+## Installing Dependencies
+
+::: tip Install dependencies into a specific package
+
+- Since the project uses [pnpm](https://pnpm.io/) as the package management tool, we need to use the `pnpm` command to install dependencies.
+- As the project is managed using a Monorepo module, we need to install dependencies under a specific package. Please make sure you have entered the specific package directory before installing dependencies.
+
+:::
+
+```bash
+# cd /path/to/your/package
+pnpm add ant-design-vue
+```
+
+## Usage
+
+### Global Import
+
+```ts
+import { createApp } from 'vue';
+import Antd from 'ant-design-vue';
+import App from './App';
+import 'ant-design-vue/dist/reset.css';
+
+const app = createApp(App);
+
+app.use(Antd).mount('#app');
+```
+
+#### Usage
+
+```vue
+<template>
+  <a-button>text</a-button>
+</template>
+```
+
+### Partial Import
+
+```vue
+<script setup lang="ts">
+import { Button } from 'ant-design-vue';
+</script>
+
+<template>
+  <Button>text</Button>
+</template>
+```
+
+::: warning Note
+
+- If the component depends on styles, you also need to import the style file.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/essentials/icons.md b/eims-ui/docs/src/en/guide/essentials/icons.md
new file mode 100644
index 0000000..0c1631f
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/icons.md
@@ -0,0 +1,78 @@
+# Icons
+
+::: tip About Icon Management
+
+- The icons in the project are mainly provided by the `@vben/icons` package. It is recommended to manage them within this package for unified management and maintenance.
+- If you are using `Vscode`, it is recommended to install the [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) plugin, which makes it easy to find and use icons.
+
+:::
+
+There are several ways to use icons in the project, you can choose according to the actual situation:
+
+## Iconify Icons <Badge text="Recommended" type="tip"/>
+
+Integrated with the [iconify](https://github.com/iconify/iconify) icon library
+
+### Adding New Icons
+
+You can add new icons in the `packages/icons/src/iconify` directory:
+
+```ts
+// packages/icons/src/iconify/index.ts
+import { createIconifyIcon } from '@vben-core/icons';
+
+export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
+```
+
+### Usage
+
+```vue
+<script setup lang="ts">
+import { MdiKeyboardEsc } from '@vben/icons';
+</script>
+
+<template>
+  <!-- An icon with a width and height of 20px -->
+  <MdiKeyboardEsc class="size-5" />
+</template>
+```
+
+## SVG Icons <Badge text="Recommended" type="tip"/>
+
+Instead of using Svg Sprite, SVG icons are directly imported,
+
+### Adding New Icons
+
+You can add new icon files `test.svg` in the `packages/icons/src/svg/icons` directory, and then import it in `packages/icons/src/svg/index.ts`:
+
+```ts
+// packages/icons/src/svg/index.ts
+import { createIconifyIcon } from '@vben-core/icons';
+
+const SvgTestIcon = createIconifyIcon('svg:test');
+
+export { SvgTestIcon };
+```
+
+### Usage
+
+```vue
+<script setup lang="ts">
+import { SvgTestIcon } from '@vben/icons';
+</script>
+
+<template>
+  <!-- An icon with a width and height of 20px -->
+  <SvgTestIcon class="size-5" />
+</template>
+```
+
+## Tailwind CSS Icons <Badge text="Not Recommended" type="danger"/>
+
+### Usage
+
+You can use the icons by directly adding the Tailwind CSS icon class names, which can be found on [iconify](https://github.com/iconify/iconify) 锛�
+
+```vue
+<span class="icon-[mdi--ab-testing]"></span>
+```
diff --git a/eims-ui/docs/src/en/guide/essentials/route.md b/eims-ui/docs/src/en/guide/essentials/route.md
new file mode 100644
index 0000000..bef40d6
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/route.md
@@ -0,0 +1,606 @@
+---
+outline: deep
+---
+
+# Routes and Menus
+
+::: info
+
+This page is translated by machine translation and may not be very accurate.
+
+:::
+
+In the project, the framework provides a basic routing system and **automatically generates the corresponding menu structure based on the routing files**.
+
+## Types of Routes
+
+Routes are divided into core routes, static routes, and dynamic routes. Core routes are built-in routes of the framework, including root routes, login routes, 404 routes, etc.; static routes are routes that are determined when the project starts; dynamic routes are generally generated dynamically based on the user's permissions after the user logs in.
+
+Both static and dynamic routes go through permission control, which can be controlled by configuring the `authority` field in the `meta` property of the route.
+
+### Core Routes
+
+Core routes are built-in routes of the framework, including root routes, login routes, 404 routes, etc. The configuration of core routes is in the `src/router/routes/core` directory under the application.
+
+::: tip
+
+Core routes are mainly used for the basic functions of the framework, so it is not recommended to put business-related routes in core routes. It is recommended to put business-related routes in static or dynamic routes.
+
+:::
+
+### Static Routes
+
+The configuration of static routes is in the `src/router/routes/index` directory under the application. Open the commented file content:
+
+::: tip
+
+Permission control is controlled by the `authority` field in the `meta` property of the route. If your page project does not require permission control, you can omit the `authority` field.
+
+:::
+
+```ts
+// Uncomment if needed and create the folder
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --]
+const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++]
+/** Dynamic routes */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** External route list, these pages can be accessed without Layout, possibly used for embedding in other systems */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --]
+const externalRoutes: RouteRecordRaw[] = []; // [!code --]
+const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++]
+```
+
+### Dynamic Routes
+
+The configuration of dynamic routes is in the `src/router/routes/modules` directory under the corresponding application. This directory contains all the route files. The content format of each file is consistent with the Vue Router route configuration format. Below is the configuration of secondary and multi-level routes.
+
+## Route Definition
+
+The configuration method of static routes and dynamic routes is the same. Below is the configuration of secondary and multi-level routes:
+
+### Secondary Routes
+
+::: details Secondary Route Example Code
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { VBEN_LOGO_URL } from '@vben/constants';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      badgeVariants: 'destructive',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('page.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    redirect: '/vben-admin/about',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          badgeType: 'dot',
+          badgeVariants: 'destructive',
+          icon: 'lucide:copyright',
+          title: $t('page.vben.about'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+:::
+
+### Multi-level Routes
+
+::: tip
+
+- The parent route of multi-level routes does not need to set the `component` property, just set the `children` property. Unless you really need to display content nested under the parent route.
+- In most cases, the `redirect` property of the parent route does not need to be specified, it will default to the first child route.
+
+:::
+
+::: details Multi-level Route Example Code
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    redirect: '/demos/access',
+    children: [
+      // Nested menu
+      {
+        meta: {
+          icon: 'ic:round-menu',
+          title: $t('demos.nested.title'),
+        },
+        name: 'NestedDemos',
+        path: '/demos/nested',
+        redirect: '/demos/nested/menu1',
+        children: [
+          {
+            name: 'Menu1Demo',
+            path: '/demos/nested/menu1',
+            component: () => import('#/views/demos/nested/menu-1.vue'),
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu1'),
+            },
+          },
+          {
+            name: 'Menu2Demo',
+            path: '/demos/nested/menu2',
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu2'),
+            },
+            redirect: '/demos/nested/menu2/menu2-1',
+            children: [
+              {
+                name: 'Menu21Demo',
+                path: '/demos/nested/menu2/menu2-1',
+                component: () => import('#/views/demos/nested/menu-2-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu2_1'),
+                },
+              },
+            ],
+          },
+          {
+            name: 'Menu3Demo',
+            path: '/demos/nested/menu3',
+            meta: {
+              icon: 'ic:round-menu',
+              title: $t('demos.nested.menu3'),
+            },
+            redirect: '/demos/nested/menu3/menu3-1',
+            children: [
+              {
+                name: 'Menu31Demo',
+                path: 'menu3-1',
+                component: () => import('#/views/demos/nested/menu-3-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu3_1'),
+                },
+              },
+              {
+                name: 'Menu32Demo',
+                path: 'menu3-2',
+                meta: {
+                  icon: 'ic:round-menu',
+                  title: $t('demos.nested.menu3_2'),
+                },
+                redirect: '/demos/nested/menu3/menu3-2/menu3-2-1',
+                children: [
+                  {
+                    name: 'Menu321Demo',
+                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',
+                    component: () =>
+                      import('#/views/demos/nested/menu-3-2-1.vue'),
+                    meta: {
+                      icon: 'ic:round-menu',
+                      keepAlive: true,
+                      title: $t('demos.nested.menu3_2_1'),
+                    },
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+:::
+
+## Adding a New Page
+
+To add a new page, you only need to add a route and the corresponding page component.
+
+### Adding a Route
+
+Add a route object in the corresponding route file, as follows:
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { VBEN_LOGO_URL } from '@vben/constants';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'mdi:home',
+      title: $t('page.home.title'),
+    },
+    name: 'Home',
+    path: '/home',
+    redirect: '/home/index',
+    children: [
+      {
+        name: 'HomeIndex',
+        path: '/home/index',
+        component: () => import('#/views/home/index.vue'),
+        meta: {
+          icon: 'mdi:home',
+          title: $t('page.home.index'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+### Adding a Page Component
+
+In `#/views/home/`, add a new `index.vue` file, as follows:
+
+```vue
+<template>
+  <div>
+    <h1>home page</h1>
+  </div>
+</template>
+```
+
+### Verification
+
+At this point, the page has been added. Visit `http://localhost:5555/home/index` to see the corresponding page.
+
+## Route Configuration
+
+The route configuration items are mainly in the `meta` property of the route object. The following are common configuration items:
+
+```ts {5-8}
+const routes = [
+  {
+    name: 'HomeIndex',
+    path: '/home/index',
+    meta: {
+      icon: 'mdi:home',
+      title: $t('page.home.index'),
+    },
+  },
+];
+```
+
+::: details Route Meta Configuration Type Definition
+
+```ts
+interface RouteMeta {
+  /**
+   * Active icon (menu)
+   */
+  activeIcon?: string;
+  /**
+   * The currently active menu, sometimes you don't want to activate the existing menu, use this to activate the parent menu
+   */
+  activePath?: string;
+  /**
+   * Whether to fix the tab
+   * @default false
+   */
+  affixTab?: boolean;
+  /**
+   * The order of fixed tabs
+   * @default 0
+   */
+  affixTabOrder?: number;
+  /**
+   * Specific roles required to access
+   * @default []
+   */
+  authority?: string[];
+  /**
+   * Badge
+   */
+  badge?: string;
+  /**
+   * Badge type
+   */
+  badgeType?: 'dot' | 'normal';
+  /**
+   * Badge color
+   */
+  badgeVariants?:
+    | 'default'
+    | 'destructive'
+    | 'primary'
+    | 'success'
+    | 'warning'
+    | string;
+  /**
+   * The children of the current route are not displayed in the menu
+   * @default false
+   */
+  hideChildrenInMenu?: boolean;
+  /**
+   * The current route is not displayed in the breadcrumb
+   * @default false
+   */
+  hideInBreadcrumb?: boolean;
+  /**
+   * The current route is not displayed in the menu
+   * @default false
+   */
+  hideInMenu?: boolean;
+  /**
+   * The current route is not displayed in the tab
+   * @default false
+   */
+  hideInTab?: boolean;
+  /**
+   * Icon (menu/tab)
+   */
+  icon?: string;
+  /**
+   * iframe address
+   */
+  iframeSrc?: string;
+  /**
+   * Ignore permissions, can be accessed directly
+   * @default false
+   */
+  ignoreAccess?: boolean;
+  /**
+   * Enable KeepAlive cache
+   */
+  keepAlive?: boolean;
+  /**
+   * External link - jump path
+   */
+  link?: string;
+  /**
+   * Whether the route has been loaded
+   */
+  loaded?: boolean;
+  /**
+   * Maximum number of open tabs
+   * @default false
+   */
+  maxNumOfOpenTab?: number;
+  /**
+   * The menu can be seen, but access will be redirected to 403
+   */
+  menuVisibleWithForbidden?: boolean;
+  /**
+   * Open in a new window
+   */
+  openInNewWindow?: boolean;
+  /**
+   * Used for route -> menu sorting
+   */
+  order?: number;
+  /**
+   * Parameters carried by the menu
+   */
+  query?: Recordable;
+  /**
+   * Title name
+   */
+  title: string;
+}
+```
+
+:::
+
+### title
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the title of the page, which will be displayed in the menu and tab. Generally used with internationalization.
+
+### icon
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the icon of the page, which will be displayed in the menu and tab. Generally used with an icon library, if it is an `http` link, the image will be loaded automatically.
+
+### activeIcon
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the active icon of the page, which will be displayed in the menu. Generally used with an icon library, if it is an `http` link, the image will be loaded automatically.
+
+### keepAlive
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page cache is enabled. When enabled, the page will be cached and will not reload, only effective when the tab is enabled.
+
+### hideInMenu
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page is hidden in the menu. When hidden, the page will not be displayed in the menu.
+
+### hideInTab
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page is hidden in the tab. When hidden, the page will not be displayed in the tab.
+
+### hideInBreadcrumb
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page is hidden in the breadcrumb. When hidden, the page will not be displayed in the breadcrumb.
+
+### hideChildrenInMenu
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the subpages of the page are hidden in the menu. When hidden, the subpages will not be displayed in the menu.
+
+### authority
+
+- Type: `string[]`
+- Default: `[]`
+
+Used to configure the permissions of the page. Only users with the corresponding permissions can access the page. If not configured, no permissions are required.
+
+### badge
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the badge of the page, which will be displayed in the menu.
+
+### badgeType
+
+- Type: `'dot' | 'normal'`
+- Default: `'normal'`
+
+Used to configure the badge type of the page. `dot` is a small red dot, `normal` is text.
+
+### badgeVariants
+
+- Type: `'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`
+- Default: `'success'`
+
+Used to configure the badge color of the page.
+
+### activePath
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the currently active menu. Sometimes the page is not displayed in the menu, and this is used to activate the parent menu.
+
+### affixTab
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page is fixed in the tab. When fixed, the page cannot be closed.
+
+### affixTabOrder
+
+- Type: `number`
+- Default: `0`
+
+Used to configure the order of fixed tabs, sorted in ascending order.
+
+### iframeSrc
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the `iframe` address of the embedded page. When set, the corresponding page will be embedded in the current page.
+
+### ignoreAccess
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page ignores permissions and can be accessed directly.
+
+### link
+
+- Type: `string`
+- Default: `''`
+
+Used to configure the external link jump path, which will open in a new window.
+
+### maxNumOfOpenTab
+
+- Type: `number`
+- Default: `-1`
+
+Used to configure the maximum number of open tabs. When set, the earliest opened tab will be automatically closed when opening a new tab (only effective when opening tabs with the same name).
+
+### menuVisibleWithForbidden
+
+- Type: `boolean`
+- Default: `false`
+
+Used to configure whether the page can be seen in the menu, but access will be redirected to 403.
+
+### openInNewWindow
+
+- Type: `boolean`
+- Default: `false`
+
+When set to `true`, the page will open in a new window.
+
+### order
+
+- Type: `number`
+- Default: `0`
+
+Used to configure the sorting of the page, used for route to menu sorting.
+
+_Note:_ Sorting is only effective for first-level menus. The sorting of second-level menus needs to be set in the corresponding first-level menu in code order.
+
+### query
+
+- Type: `Recordable`
+- Default: `{}`
+
+Used to configure the menu parameters of the page, which will be passed to the page in the menu.
+
+## Route Refresh
+
+The route refresh method is as follows:
+
+```vue
+<script setup lang="ts">
+import { useRefresh } from '@vben/hooks';
+
+const { refresh } = useRefresh();
+
+// Refresh the current route
+refresh();
+</script>
+```
diff --git a/eims-ui/docs/src/en/guide/essentials/server.md b/eims-ui/docs/src/en/guide/essentials/server.md
new file mode 100644
index 0000000..95d505c
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/server.md
@@ -0,0 +1,356 @@
+# Server Interaction and Data Mocking
+
+::: tip Note
+
+This document explains how to use Mock data and interact with the server in a development environment, involving technologies such as:
+
+- [Nitro](https://nitro.unjs.io/) A lightweight backend server that can be deployed anywhere, used as a Mock server in the project.
+- [axios](https://axios-http.com/docs/intro) Used to send HTTP requests to interact with the server.
+
+:::
+
+## Interaction in Development Environment
+
+If the frontend application and the backend API server are not running on the same host, you need to proxy the API requests to the API server in the development environment. If they are on the same host, you can directly request the specific API endpoint.
+
+### Local Development CORS Configuration
+
+::: tip Hint
+
+The CORS configuration for local development has already been set up. If you have other requirements, you can add or adjust the configuration as needed.
+
+:::
+
+#### Configuring Local Development API Endpoint
+
+Configure the API endpoint in the `.env.development` file at the project root directory, here it is set to `/api`:
+
+```bash
+VITE_GLOB_API_URL=/api
+```
+
+#### Configuring Development Server Proxy
+
+In the development environment, if you need to handle CORS, configure the API endpoint in the `vite.config.mts` file under the corresponding application directory:
+
+```ts{8-16}
+// apps/web-antd/vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    vite: {
+      server: {
+        proxy: {// [!code focus:11]
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock proxy
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
+```
+
+#### API Requests
+
+Based on the above configuration, we can use `/api` as the prefix for API requests in our frontend project, for example:
+
+```ts
+import axios from 'axios';
+
+axios.get('/api/user').then((res) => {
+  console.log(res);
+});
+```
+
+At this point, the request will be proxied to `http://localhost:5320/api/user`.
+
+::: warning Note
+
+From the browser's console Network tab, the request appears as `http://localhost:5555/api/user`. This is because the proxy configuration does not change the local request's URL.
+
+:::
+
+### Configuration Without CORS
+
+If there is no CORS issue, you can directly ignore the [Configure Development Server Proxy](./server.md#configure-development-server-proxy) settings and set the API endpoint directly in `VITE_GLOB_API_URL`.
+
+Configure the API endpoint in the `.env.development` file at the project root directory:
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+## Production Environment Interaction
+
+### API Endpoint Configuration
+
+Configure the API endpoint in the `.env.production` file at the project root directory:
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+::: tip How to Dynamically Modify API Endpoint in Production
+
+Variables starting with `VITE_GLOB_*` in the `.env` file are injected into the `_app.config.js` file during packaging. After packaging, you can modify the corresponding API addresses in `dist/_app.config.js` and refresh the page to apply the changes. This eliminates the need to package multiple times for different environments, allowing a single package to be deployed across multiple API environments.
+
+:::
+
+### Cross-Origin Resource Sharing (CORS) Handling
+
+In the production environment, if CORS issues arise, you can use `nginx` to proxy the API address or enable `cors` on the backend to handle it (refer to the mock service for examples).
+
+## API Request Configuration
+
+The project comes with a default basic request configuration based on `axios`, provided by the `@vben/request` package. The project does not overly complicate things but simply wraps some common configurations. If there are other requirements, you can add or adjust the configurations as needed. Depending on the app, different component libraries and `store` might be used, so under the `src/api/request.ts` folder in the application directory, there are corresponding request configuration files. For example, in the `web-antd` project, there's a `src/api/request.ts` file where you can configure according to your needs.
+
+### Request Examples
+
+#### GET Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
+```
+
+#### POST/PUT Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function saveUserApi(user: UserInfo) {
+  return requestClient.post<UserInfo>('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+  return requestClient.put<UserInfo>('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+  const url = user.id ? `/user/${user.id}` : '/user/';
+  return requestClient.request<UserInfo>(url, {
+    data: user,
+    // OR PUT
+    method: user.id ? 'PUT' : 'POST',
+  });
+}
+```
+
+#### DELETE Request
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function deleteUserApi(user: UserInfo) {
+  return requestClient.delete<boolean>(`/user/${user.id}`, user);
+}
+```
+
+### Request Configuration
+
+The `src/api/request.ts` within the application can be configured according to the needs of your application:
+
+```ts
+/**
+ * This file can be adjusted according to business logic
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    baseURL,
+  });
+
+  /**
+   * Re-authentication Logic
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (preferences.app.loginExpiredMode === 'modal') {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * Refresh token Logic
+   */
+  async function doRefreshToken() {
+    const accessStore = useAccessStore();
+    const resp = await refreshTokenApi();
+    const newToken = resp.data;
+    accessStore.setAccessToken(newToken);
+    return newToken;
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  // Request Header Processing
+  client.addRequestInterceptor({
+    fulfilled: async (config) => {
+      const accessStore = useAccessStore();
+
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      config.headers['Accept-Language'] = preferences.app.locale;
+      return config;
+    },
+  });
+
+  // Deal Response Data
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const { data: responseData, status } = response;
+
+      const { code, data } = responseData;
+
+      if (status >= 200 && status < 400 && code === 0) {
+        return data;
+      }
+      throw Object.assign({}, response, { response });
+    },
+  });
+
+  // Handling Token Expiration
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  // Generic error handling; if none of the above error handling logic is triggered, it will fall back to this.
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string, error) => {
+      // 杩欓噷鍙互鏍规嵁涓氬姟杩涜瀹氬埗,浣犲彲浠ユ嬁鍒� error 鍐呯殑淇℃伅杩涜瀹氬埗鍖栧鐞嗭紝鏍规嵁涓嶅悓鐨� code 鍋氫笉鍚岀殑鎻愮ず锛岃�屼笉鏄洿鎺ヤ娇鐢� message.error 鎻愮ず msg
+      // 褰撳墠mock鎺ュ彛杩斿洖鐨勯敊璇瓧娈垫槸 error 鎴栬�� message
+      const responseData = error?.response?.data ?? {};
+      const errorMessage = responseData?.error ?? responseData?.message ?? '';
+      // 濡傛灉娌℃湁閿欒淇℃伅锛屽垯浼氭牴鎹姸鎬佺爜杩涜鎻愮ず
+      message.error(errorMessage || msg);
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
+```
+
+### Multiple API Endpoints
+
+To handle multiple API endpoints, simply create multiple `requestClient` instances, as follows:
+
+```ts
+const { apiURL, otherApiURL } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+export const requestClient = createRequestClient(apiURL);
+
+export const otherRequestClient = createRequestClient(otherApiURL);
+```
+
+## Refresh Token
+
+The project provides a default logic for refreshing tokens. To enable it, follow the configuration below:
+
+- Ensure the refresh token feature is enabled
+
+Adjust the `preferences.ts` in the corresponding application directory to ensure `enableRefreshToken='true'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    enableRefreshToken: true,
+  },
+});
+```
+
+Configure the `doRefreshToken` method in `src/api/request.ts` as follows:
+
+```ts
+// Adjust this to your token format
+function formatToken(token: null | string) {
+  return token ? `Bearer ${token}` : null;
+}
+
+/**
+ * Refresh token logic
+ */
+async function doRefreshToken() {
+  const accessStore = useAccessStore();
+  // Adjust this to your refresh token API
+  const resp = await refreshTokenApi();
+  const newToken = resp.data;
+  accessStore.setAccessToken(newToken);
+  return newToken;
+}
+```
+
+## Data Mocking
+
+::: tip Production Environment Mock
+
+The new version no longer supports mock in the production environment. Please use real interfaces.
+
+:::
+
+Mock data is an indispensable part of frontend development, serving as a key link in separating frontend and backend development. By agreeing on interfaces with the server side in advance and simulating request data and even logic, frontend development can proceed independently, without being blocked by the backend development process.
+
+The project uses [Nitro](https://nitro.unjs.io/) for local mock data processing. The principle is to start an additional backend service locally, which is a real backend service that can handle requests and return data.
+
+### Using Nitro
+
+The mock service code is located in the `apps/backend-mock` directory. It does not need to be started manually and is already integrated into the project. You only need to run `pnpm dev` in the project root directory. After running successfully, the console will print `http://localhost:5320/api`, and you can access this address to view the mock service.
+
+[Nitro](https://nitro.unjs.io/) syntax is simple, and you can configure and develop according to your needs. For specific configurations, you can refer to the [Nitro documentation](https://nitro.unjs.io/).
+
+## Disabling Mock Service
+
+Since mock is essentially a real backend service, if you do not need the mock service, you can configure `VITE_NITRO_MOCK=false` in the `.env.development` file in the project root directory to disable the mock service.
+
+```bash
+# .env.development
+VITE_NITRO_MOCK=false
+```
diff --git a/eims-ui/docs/src/en/guide/essentials/settings.md b/eims-ui/docs/src/en/guide/essentials/settings.md
new file mode 100644
index 0000000..68fef3e
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/settings.md
@@ -0,0 +1,514 @@
+# Configuration
+
+## Environment Variable Configuration
+
+The project's environment variable configuration is located in the application directory under `.env`, `.env.development`, `.env.production`.
+
+The rules are consistent with [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html). The format is as follows:
+
+```bash
+.env                # Loaded in all environments
+.env.local          # Loaded in all environments, but ignored by git
+.env.[mode]         # Only loaded in the specified mode
+.env.[mode].local   # Only loaded in the specified mode, but ignored by git
+```
+
+::: tip
+
+- Only variables starting with `VITE_` will be embedded into the client-side package. You can access them in the project code like this:
+
+  ```ts
+  console.log(import.meta.env.VITE_PROT);
+  ```
+
+- Variables starting with `VITE_GLOB_*` will be added to the `_app.config.js` configuration file during packaging. :::
+
+:::
+
+## Environment Configuration Description
+
+::: code-group
+
+```bash [.env]
+# Application title
+VITE_APP_TITLE=Vben Admin
+
+# Application namespace, used as a prefix for caching, store, etc., to ensure isolation
+VITE_APP_NAMESPACE=vben-web-antd
+```
+
+```bash [.env.development]
+# Port Number
+VITE_PORT=5555
+
+# Public Path for Resources, must start and end with /
+VITE_BASE=/
+
+# API URL
+VITE_GLOB_API_URL=/api
+
+# Whether to enable Nitro Mock service, true to enable, false to disable
+VITE_NITRO_MOCK=true
+
+# Whether to open devtools, true to open, false to close
+VITE_DEVTOOLS=true
+
+# Whether to inject global loading
+VITE_INJECT_APP_LOADING=true
+
+# Whether to generate after packaging dist.zip
+VITE_ARCHIVER=true
+```
+
+:::
+
+## Dynamic Configuration in Production Environment
+
+When executing `pnpm build` in the root directory of the monorepo, a `dist/_app.config.js` file will be automatically generated in the corresponding application and inserted into `index.html`.
+
+`_app.config.js` is a dynamic configuration file that allows for modifications to the configuration dynamically based on different environments after the project has been built. The content is as follows:
+
+```ts
+window._VBEN_ADMIN_PRO_APP_CONF_ = {
+  VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',
+};
+Object.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);
+Object.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {
+  configurable: false,
+  writable: false,
+});
+```
+
+### Purpose
+
+`_app.config.js` is used for projects that need to dynamically modify configurations after packaging, such as API endpoints. There's no need to repackage; you can simply modify the variables in `/dist/_app.config.js` after packaging, and refresh to update the variables in the code. A `js` file is used to ensure that the configuration file is loaded early in the order.
+
+### Usage
+
+To access the variables inside `_app.config.js`, you need to use the `useAppConfig` method provided by `@vben/hooks`.
+
+```ts
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+### Adding New
+
+To add a new dynamically modifiable configuration item, simply follow the steps below:
+
+- First, add the variable that needs to be dynamically configurable in the `.env` file or the corresponding development environment configuration file. The variable must start with `VITE_GLOB_*`, for example:
+
+  ```bash
+  VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api
+  ```
+
+- In `packages/types/global.d.ts`, add the corresponding type definition, such as:
+
+  ```ts
+  export interface VbenAdminProAppConfigRaw {
+    VITE_GLOB_API_URL: string;
+    VITE_GLOB_OTHER_API_URL: string; // [!code ++]
+  }
+
+  export interface ApplicationConfig {
+    apiURL: string;
+    otherApiURL: string; // [!code ++]
+  }
+  ```
+
+At this point, you can use the `useAppConfig` method within the project to access the newly added configuration item.
+
+```ts
+const { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+::: warning Warning
+
+The `useAppConfig` method should only be used within the application and not be coupled with the internals of a package. The reason for passing `import.meta.env` and `import.meta.env.PROD` is to avoid such coupling. A pure package should avoid using variables specific to a particular build tool.
+
+:::
+
+## Preferences
+
+The project offers a wide range of preference settings for dynamically configuring various features of the project:
+
+![](/guide/preferences.png)
+
+If you cannot find documentation for a setting, you can try configuring it yourself and then click `Copy Preferences` to override the project defaults. The configuration file is located in the application directory under `preferences.ts`, where you can override the framework's default configurations to achieve custom settings.
+
+```ts
+import { useAppConfig } from '@vben/hooks';
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description Project configuration file
+ * Only a part of the configuration in the project needs to be covered, and unnecessary configurations do not need to be covered. The default configuration will be automatically used
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+});
+```
+
+### Framework default configuration
+
+::: details View the default configuration of the framework
+
+```ts
+const defaultPreferences: Preferences = {
+  app: {
+    accessMode: 'frontend',
+    authPageLayout: 'panel-right',
+    checkUpdatesInterval: 1,
+    colorGrayMode: false,
+    colorWeakMode: false,
+    compact: false,
+    contentCompact: 'wide',
+    defaultAvatar:
+      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',
+    dynamicTitle: true,
+    enableCheckUpdates: true,
+    enablePreferences: true,
+    enableRefreshToken: false,
+    isMobile: false,
+    layout: 'sidebar-nav',
+    locale: 'zh-CN',
+    loginExpiredMode: 'modal',
+    name: 'Vben Admin',
+    preferencesButtonPosition: 'auto',
+    watermark: false,
+  },
+  breadcrumb: {
+    enable: true,
+    hideOnlyOne: false,
+    showHome: false,
+    showIcon: true,
+    styleType: 'normal',
+  },
+  copyright: {
+    companyName: 'Vben',
+    companySiteLink: 'https://www.vben.pro',
+    date: '2024',
+    enable: true,
+    icp: '',
+    icpLink: '',
+  },
+  footer: {
+    enable: true,
+    fixed: false,
+  },
+  header: {
+    enable: true,
+    hidden: false,
+    mode: 'fixed',
+  },
+  logo: {
+    enable: true,
+    source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+  },
+  navigation: {
+    accordion: true,
+    split: true,
+    styleType: 'rounded',
+  },
+  shortcutKeys: {
+    enable: true,
+    globalLockScreen: true,
+    globalLogout: true,
+    globalPreferences: true,
+    globalSearch: true,
+  },
+  sidebar: {
+    collapsed: false,
+    collapsedShowTitle: false,
+    enable: true,
+    expandOnHover: true,
+    extraCollapse: true,
+    hidden: false,
+    width: 230,
+  },
+  tabbar: {
+    draggable: true,
+    enable: true,
+    height: 36,
+    keepAlive: true,
+    persist: true,
+    showIcon: true,
+    showMaximize: true,
+    showMore: true,
+    styleType: 'chrome',
+  },
+  theme: {
+    builtinType: 'default',
+    colorDestructive: 'hsl(348 100% 61%)',
+    colorPrimary: 'hsl(212 100% 45%)',
+    colorSuccess: 'hsl(144 57% 58%)',
+    colorWarning: 'hsl(42 84% 61%)',
+    mode: 'dark',
+    radius: '0.5',
+    semiDarkHeader: false,
+    semiDarkSidebar: true,
+  },
+  transition: {
+    enable: true,
+    loading: true,
+    name: 'fade-slide',
+    progress: true,
+  },
+  widget: {
+    fullscreen: true,
+    globalSearch: true,
+    languageToggle: true,
+    lockScreen: true,
+    notification: true,
+    sidebarToggle: true,
+    themeToggle: true,
+    refresh: true,
+  },
+};
+```
+
+:::
+
+::: details View the default configuration type of the framework
+
+```ts
+interface AppPreferences {
+  /** Permission mode */
+  accessMode: AccessModeType;
+  /** Layout of the login/registration page */
+  authPageLayout: AuthPageLayoutType;
+  /** Interval for checking updates */
+  checkUpdatesInterval: number;
+  /** Whether to enable gray mode */
+  colorGrayMode: boolean;
+  /** Whether to enable color weakness mode */
+  colorWeakMode: boolean;
+  /** Whether to enable compact mode */
+  compact: boolean;
+  /** Whether to enable content compact mode */
+  contentCompact: ContentCompactType;
+  // /** Default application avatar */
+  defaultAvatar: string;
+  // /** Enable dynamic title */
+  dynamicTitle: boolean;
+  /** Whether to enable update checks */
+  enableCheckUpdates: boolean;
+  /** Whether to display preferences */
+  enablePreferences: boolean;
+  /**
+   * @zh_CN Whether to enable refreshToken
+   */
+  enableRefreshToken: boolean;
+  /** Whether it's mobile */
+  isMobile: boolean;
+  /** Layout method */
+  layout: LayoutType;
+  /** Supported languages */
+  locale: SupportedLanguagesType;
+  /** Login expiration mode */
+  loginExpiredMode: LoginExpiredModeType;
+  /** Application name */
+  name: string;
+  /** Position of the preferences button */
+  preferencesButtonPosition: PreferencesButtonPositionType;
+  /**
+   * @zh_CN Whether to enable watermark
+   */
+  watermark: boolean;
+}
+interface BreadcrumbPreferences {
+  /** Whether breadcrumbs are enabled */
+  enable: boolean;
+  /** Whether to hide breadcrumbs when there is only one */
+  hideOnlyOne: boolean;
+  /** Whether the home icon in breadcrumbs is visible */
+  showHome: boolean;
+  /** Whether the icon in breadcrumbs is visible */
+  showIcon: boolean;
+  /** Breadcrumb style */
+  styleType: BreadcrumbStyleType;
+}
+
+interface CopyrightPreferences {
+  /** Copyright company name */
+  companyName: string;
+  /** Link to the copyright company's site */
+  companySiteLink: string;
+  /** Copyright date */
+  date: string;
+  /** Whether copyright is visible */
+  enable: boolean;
+  /** ICP number */
+  icp: string;
+  /** Link to the ICP */
+  icpLink: string;
+}
+
+interface FooterPreferences {
+  /** Whether the footer is visible */
+  enable: boolean;
+  /** Whether the footer is fixed */
+  fixed: boolean;
+}
+
+interface HeaderPreferences {
+  /** Whether the header is enabled */
+  enable: boolean;
+  /** Whether the header is hidden, css-hidden */
+  hidden: boolean;
+  /** Header display mode */
+  mode: LayoutHeaderModeType;
+}
+
+interface LogoPreferences {
+  /** Whether the logo is visible */
+  enable: boolean;
+  /** Logo URL */
+  source: string;
+}
+
+interface NavigationPreferences {
+  /** Navigation menu accordion mode */
+  accordion: boolean;
+  /** Whether the navigation menu is split, only effective in layout=mixed-nav */
+  split: boolean;
+  /** Navigation menu style */
+  styleType: NavigationStyleType;
+}
+interface SidebarPreferences {
+  /** Whether the sidebar is collapsed */
+  collapsed: boolean;
+  /** Whether to show title when sidebar is collapsed */
+  collapsedShowTitle: boolean;
+  /** Whether the sidebar is visible */
+  enable: boolean;
+  /** Menu auto-expand state */
+  expandOnHover: boolean;
+  /** Whether the sidebar extension area is collapsed */
+  extraCollapse: boolean;
+  /** Whether the sidebar is hidden - css */
+  hidden: boolean;
+  /** Sidebar width */
+  width: number;
+}
+
+interface ShortcutKeyPreferences {
+  /** Whether shortcut keys are enabled globally */
+  enable: boolean;
+  /** Whether the global lock screen shortcut is enabled */
+  globalLockScreen: boolean;
+  /** Whether the global logout shortcut is enabled */
+  globalLogout: boolean;
+  /** Whether the global preferences shortcut is enabled */
+  globalPreferences: boolean;
+  /** Whether the global search shortcut is enabled */
+  globalSearch: boolean;
+}
+
+interface TabbarPreferences {
+  /** Whether dragging of multiple tabs is enabled */
+  draggable: boolean;
+  /** Whether multiple tabs are enabled */
+  enable: boolean;
+  /** Tab height */
+  height: number;
+  /** Whether tab caching is enabled */
+  keepAlive: boolean;
+  /** Whether tabs are persistent */
+  persist: boolean;
+  /** Whether icons in multiple tabs are enabled */
+  showIcon: boolean;
+  /** Whether to show the maximize button */
+  showMaximize: boolean;
+  /** Whether to show the more button */
+  showMore: boolean;
+  /** Tab style */
+  styleType: TabsStyleType;
+}
+interface ThemePreferences {
+  /** Built-in theme name */
+  builtinType: BuiltinThemeType;
+  /** Destructive color */
+  colorDestructive: string;
+  /** Primary color */
+  colorPrimary: string;
+  /** Success color */
+  colorSuccess: string;
+  /** Warning color */
+  colorWarning: string;
+  /** Current theme */
+  mode: ThemeModeType;
+  /** Radius */
+  radius: string;
+  /** Whether to enable semi-dark header (only effective when theme='light') */
+  semiDarkHeader: boolean;
+  /** Whether to enable semi-dark sidebar (only effective when theme='light') */
+  semiDarkSidebar: boolean;
+}
+
+interface TransitionPreferences {
+  /** Whether page transition animations are enabled */
+  enable: boolean;
+  // /** Whether page loading loading is enabled */
+  loading: boolean;
+  /** Page transition animation */
+  name: PageTransitionType | string;
+  /** Whether page loading progress animation is enabled */
+  progress: boolean;
+}
+
+interface WidgetPreferences {
+  /** Whether fullscreen widgets are enabled */
+  fullscreen: boolean;
+  /** Whether global search widget is enabled */
+  globalSearch: boolean;
+  /** Whether language switch widget is enabled */
+  languageToggle: boolean;
+  /** Whether lock screen functionality is enabled */
+  lockScreen: boolean;
+  /** Whether notification widget is displayed */
+  notification: boolean;
+  /** Whether to show the refresh button */
+  refresh: boolean;
+  /** Whether sidebar show/hide widget is displayed */
+  sidebarToggle: boolean;
+  /** Whether theme switch widget is displayed */
+  themeToggle: boolean;
+}
+interface Preferences {
+  /** Global configuration */
+  app: AppPreferences;
+  /** Header configuration */
+  breadcrumb: BreadcrumbPreferences;
+  /** Copyright configuration */
+  copyright: CopyrightPreferences;
+  /** Footer configuration */
+  footer: FooterPreferences;
+  /** Breadcrumb configuration */
+  header: HeaderPreferences;
+  /** Logo configuration */
+  logo: LogoPreferences;
+  /** Navigation configuration */
+  navigation: NavigationPreferences;
+  /** Shortcut key configuration */
+  shortcutKeys: ShortcutKeyPreferences;
+  /** Sidebar configuration */
+  sidebar: SidebarPreferences;
+  /** Tab bar configuration */
+  tabbar: TabbarPreferences;
+  /** Theme configuration */
+  theme: ThemePreferences;
+  /** Animation configuration */
+  transition: TransitionPreferences;
+  /** Widget configuration */
+  widget: WidgetPreferences;
+}
+```
+
+:::
+
+::: warning Warning
+
+- The `overridesPreferences` method only needs to override a part of the configurations in the project. There's no need to override configurations that are not needed; they will automatically use the default settings.
+- Any configuration item can be overridden. You just need to override it within the `overridesPreferences` method. Do not modify the default configuration file.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/essentials/styles.md b/eims-ui/docs/src/en/guide/essentials/styles.md
new file mode 100644
index 0000000..16f6681
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/essentials/styles.md
@@ -0,0 +1,106 @@
+# Styles
+
+::: tip Preface
+
+For Vue projects, the [official documentation](https://vuejs.org/api/sfc-css-features.html#deep-selectors) already provides a detailed introduction to the syntax. Here, we mainly introduce the structure and usage of style files in the project.
+
+:::
+
+## Project Structure
+
+The style files in the project are stored in `@vben/styles`, which includes some global styles, such as reset styles, global variables, etc. It inherits the styles and capabilities of `@vben-core/design` and can be overridden according to project needs.
+
+## Scss
+
+The project uses `scss` as the style preprocessor, allowing the use of `scss` features such as variables, functions, mixins, etc., within the project.
+
+```vue
+<style lang="scss" scoped>
+$font-size: 30px;
+
+.box {
+  .title {
+    color: green;
+    font-size: $font-size;
+  }
+}
+</style>
+```
+
+## Postcss
+
+If you're not accustomed to using `scss`, you can also use `postcss`, which is a more powerful style processor that supports a wider range of plugins. The project includes the [postcss-nested](https://github.com/postcss/postcss-nested) plugin and is configured with `Css Variables`, making it a complete substitute for `scss`.
+
+```vue
+<style scoped>
+.box {
+  --font-size: 30px;
+  .title {
+    color: green;
+    font-size: var(--font-size);
+  }
+}
+</style>
+```
+
+## Tailwind CSS
+
+The project integrates [Tailwind CSS](https://tailwindcss.com/), allowing the use of `tailwindcss` class names to quickly build pages.
+
+```vue
+<template>
+  <div class="bg-white p-4">
+    <p class="text-green">hello world</p>
+  </div>
+</template>
+```
+
+## BEM Standard
+
+Another option to avoid style conflicts is to use the `BEM` standard. If you choose `scss`, it is recommended to use the `BEM` naming convention for better style management. The project provides a default `useNamespace` function to easily generate namespaces.
+
+```vue
+<script lang="ts" setup>
+import { useNamespace } from '@vben/hooks';
+
+const { b, e, is } = useNamespace('menu');
+</script>
+<template>
+  <div :class="[b()]">
+    <div :class="[e('item'), is('active', true)]">item1</div>
+  </div>
+</template>
+<style lang="scss" scoped>
+// If you use it within the application, this line of code can be omitted as it has already been globally introduced in all applications
+@use '@vben/styles/global' as *;
+@include b('menu') {
+  color: black;
+
+  @include e('item') {
+    background-color: black;
+
+    @include is('active') {
+      background-color: red;
+    }
+  }
+}
+</style>
+```
+
+## CSS Modules
+
+Another solution to address style conflicts is to use the `CSS Modules` modular approach. The usage method is as follows.
+
+```vue
+<template>
+  <p :class="$style.red">This should be red</p>
+</template>
+
+<style module>
+.red {
+  color: red;
+}
+</style>
+```
+
+For more usage, see the [CSS Modules official documentation](https://vuejs.org/api/sfc-css-features.html#css-modules).
diff --git a/eims-ui/docs/src/en/guide/in-depth/access.md b/eims-ui/docs/src/en/guide/in-depth/access.md
new file mode 100644
index 0000000..05997d7
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/access.md
@@ -0,0 +1,318 @@
+---
+outline: deep
+---
+
+# Access Control
+
+The framework has built-in two types of access control methods:
+
+- Determining whether a menu or button can be accessed based on user roles
+- Determining whether a menu or button can be accessed through an API
+
+## Frontend Access Control
+
+**Implementation Principle**: The permissions for routes are hardcoded on the frontend, specifying which permissions are required to view certain routes. Only general routes are initialized, and routes that require permissions are not added to the route table. After logging in or obtaining user roles through other means, the roles are used to traverse the route table to generate a route table that the role can access. This table is then added to the router instance using `router.addRoute`, achieving permission filtering.
+
+**Disadvantage**: The permissions are relatively inflexible; if the backend changes roles, the frontend needs to be adjusted accordingly. This is suitable for systems with relatively fixed roles.
+
+### Steps
+
+- Ensure the current mode is set to frontend access control
+
+Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='frontend'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    // Default value, optional
+    accessMode: 'frontend',
+  },
+});
+```
+
+- Configure route permissions
+
+#### If not configured, it is visible by default
+
+```ts {3}
+ {
+    meta: {
+      authority: ['super'],
+    },
+},
+```
+
+- Ensure the roles returned by the interface match the permissions in the route table
+
+You can look under `src/store/auth` in the application to find the following code:
+
+```ts
+// Set the login user information, ensuring that userInfo.roles is an array and contains permissions from the route table
+// For example: userInfo.roles=['super', 'admin']
+authStore.setUserInfo(userInfo);
+```
+
+At this point, the configuration is complete. You need to ensure that the roles returned by the interface after login match the permissions in the route table; otherwise, access will not be possible.
+
+### Menu Visible but Access Forbidden
+
+Sometimes, we need the menu to be visible but access to it forbidden. This can be achieved by setting `menuVisibleWithForbidden` to `true`. In this case, the menu will be visible, but access will be forbidden, redirecting to a 403 page.
+
+```ts
+{
+    meta: {
+      menuVisibleWithForbidden: true,
+    },
+},
+```
+
+## Backend Access Control
+
+**Implementation Principle**: It is achieved by dynamically generating a routing table through an API, which returns data following a certain structure. The frontend processes this data into a recognizable structure, then adds it to the routing instance using `router.addRoute`, realizing the dynamic generation of permissions.
+
+**Disadvantage**: The backend needs to provide a data structure that meets the standards, and the frontend needs to process this structure. This is suitable for systems with more complex permissions.
+
+### Steps
+
+- Ensure the current mode is set to backend access control
+
+Adjust `preferences.ts` in the corresponding application directory to ensure `accessMode='backend'`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    accessMode: 'backend',
+  },
+});
+```
+
+- Ensure the structure of the menu data returned by the interface is correct
+
+You can look under `src/router/access.ts` in the application to find the following code:
+
+```ts
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  return await generateAccessible(preferences.app.accessMode, {
+    fetchMenuListAsync: async () => {
+      // This interface is for the menu data returned by the backend
+      return await getAllMenus();
+    },
+  });
+}
+```
+
+- Interface returns menu data, see comments for explanation
+
+::: details Example of Interface Returning Menu Data
+
+```ts
+const dashboardMenus = [
+  {
+    // Here, 'BasicLayout' is hardcoded and cannot be changed
+    component: 'BasicLayout',
+    meta: {
+      order: -1,
+      title: 'page.dashboard.title',
+    },
+    name: 'Dashboard',
+    path: '/',
+    redirect: '/analytics',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        // Here is the path of the page, need to remove 'views/' and '.vue'
+        component: '/dashboard/analytics/index',
+        meta: {
+          affixTab: true,
+          title: 'page.dashboard.analytics',
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: '/dashboard/workspace/index',
+        meta: {
+          title: 'page.dashboard.workspace',
+        },
+      },
+    ],
+  },
+];
+```
+
+:::
+
+At this point, the configuration is complete. You need to ensure that after logging in, the format of the menu returned by the interface is correct; otherwise, access will not be possible.
+
+## Fine-grained Control of Buttons
+
+In some cases, we need to control the display of buttons with fine granularity. We can control the display of buttons through interfaces or roles.
+
+### Permission Code
+
+The permission code is the code returned by the interface. The logic to determine whether a button is displayed is located under `src/store/auth`:
+
+```ts
+const [fetchUserInfoResult, accessCodes] = await Promise.all([
+  fetchUserInfo(),
+  getAccessCodes(),
+]);
+
+userInfo = fetchUserInfoResult;
+authStore.setUserInfo(userInfo);
+accessStore.setAccessCodes(accessCodes);
+```
+
+Locate the `getAccessCodes` corresponding interface, which can be adjusted according to business logic.
+
+The data structure returned by the permission code is an array of strings, for example: `['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
+
+With the permission codes, you can use the `AccessControl` component and API provided by `@vben/access` to show and hide buttons.
+
+#### Component Method
+
+```vue
+<script lang="ts" setup>
+import { AccessControl, useAccess } from '@vben/access';
+
+const { accessMode, hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <!-- You need to specify type="code" -->
+  <AccessControl :codes="['AC_100100']" type="code">
+    <Button> Visible to Super account ["AC_1000001"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_100030']" type="code">
+    <Button> Visible to Admin account ["AC_100010"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_1000001']" type="code">
+    <Button> Visible to User account ["AC_1000001"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
+    <Button>
+      Visible to Super & Admin account ["AC_100100","AC_1000001"]
+    </Button>
+  </AccessControl>
+</template>
+```
+
+#### API Method
+
+```vue
+<script lang="ts" setup>
+import { AccessControl, useAccess } from '@vben/access';
+
+const { hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <Button v-if="hasAccessByCodes(['AC_100100'])">
+    Visible to Super account ["AC_1000001"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_100030'])">
+    Visible to Admin account ["AC_100010"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_1000001'])">
+    Visible to User account ["AC_1000001"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
+    Visible to Super & Admin account ["AC_100100","AC_1000001"]
+  </Button>
+</template>
+```
+
+#### Directive Method
+
+> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.
+
+```vue
+<template>
+  <Button class="mr-4" v-access:code="'AC_100100'">
+    Visible to Super account 'AC_100100'
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_100030']">
+    Visible to Admin account ["AC_100010"]
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_1000001']">
+    Visible to User account ["AC_1000001"]
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
+    Visible to Super & Admin account ["AC_100100","AC_1000001"]
+  </Button>
+</template>
+```
+
+### Roles
+
+The method of determining roles does not require permission codes returned by the interface; it directly determines whether buttons are displayed based on roles.
+
+#### Component Method
+
+```vue
+<script lang="ts" setup>
+import { AccessControl } from '@vben/access';
+</script>
+
+<template>
+  <AccessControl :codes="['super']">
+    <Button> Visible to Super account </Button>
+  </AccessControl>
+  <AccessControl :codes="['admin']">
+    <Button> Visible to Admin account </Button>
+  </AccessControl>
+  <AccessControl :codes="['user']">
+    <Button> Visible to User account </Button>
+  </AccessControl>
+  <AccessControl :codes="['super', 'admin']">
+    <Button> Super & Visible to Admin account </Button>
+  </AccessControl>
+</template>
+```
+
+#### API Method
+
+```vue
+<script lang="ts" setup>
+import { useAccess } from '@vben/access';
+
+const { hasAccessByRoles } = useAccess();
+</script>
+
+<template>
+  <Button v-if="hasAccessByRoles(['super'])"> Visible to Super account </Button>
+  <Button v-if="hasAccessByRoles(['admin'])"> Visible to Admin account </Button>
+  <Button v-if="hasAccessByRoles(['user'])"> Visible to User account </Button>
+  <Button v-if="hasAccessByRoles(['super', 'admin'])">
+    Super & Visible to Admin account
+  </Button>
+</template>
+```
+
+#### Directive Method
+
+> The directive supports binding single or multiple permission codes. For a single one, you can pass a string or an array containing one permission code, and for multiple permission codes, you can pass an array.
+
+```vue
+<template>
+  <Button class="mr-4" v-access:role="'super'">
+    Visible to Super account
+  </Button>
+  <Button class="mr-4" v-access:role="['admin']">
+    Visible to Admin account
+  </Button>
+  <Button class="mr-4" v-access:role="['user']">
+    Visible to User account
+  </Button>
+  <Button class="mr-4" v-access:role="['super', 'admin']">
+    Super & Visible to Admin account
+  </Button>
+</template>
+```
diff --git a/eims-ui/docs/src/en/guide/in-depth/check-updates.md b/eims-ui/docs/src/en/guide/in-depth/check-updates.md
new file mode 100644
index 0000000..1e5b679
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/check-updates.md
@@ -0,0 +1,48 @@
+# Check Updates
+
+## Introduction
+
+When there are updates to the website, you might need to check for updates. The framework provides this functionality. By periodically checking for updates, you can configure the `checkUpdatesInterval` and `enableCheckUpdates` fields in your application's preferences.ts file to enable and set the interval for checking updates (in minutes).
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    // Whether to enable check for updates
+    enableCheckUpdates: true,
+    // The interval for checking updates, in minutes
+    checkUpdatesInterval: 1,
+  },
+});
+```
+
+## Effect
+
+When an update is detected, a prompt will pop up asking the user whether to refresh the page:
+
+![check-updates](/guide/update-notice.png)
+
+## Replacing with Other Update Checking Methods
+
+If you need to check for updates in other ways, such as through an API to more flexibly control the update logic (such as force refresh, display update content, etc.), you can do so by modifying the `src/widgets/check-updates/check-updates.vue` file under `@vben/layouts`.
+
+```ts
+// Replace this with your update checking logic
+async function getVersionTag() {
+  try {
+    const response = await fetch('/', {
+      cache: 'no-cache',
+      method: 'HEAD',
+    });
+
+    return (
+      response.headers.get('etag') || response.headers.get('last-modified')
+    );
+  } catch {
+    console.error('Failed to fetch version tag');
+    return null;
+  }
+}
+```
diff --git a/eims-ui/docs/src/en/guide/in-depth/features.md b/eims-ui/docs/src/en/guide/in-depth/features.md
new file mode 100644
index 0000000..24fecea
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/features.md
@@ -0,0 +1,84 @@
+# Common Features
+
+A collection of some commonly used features.
+
+## Login Authentication Expiry
+
+When the interface returns a `401` status code, the framework will consider the login authentication to have expired. Upon login timeout, it will redirect to the login page or open a login popup. This can be configured in `preferences.ts` in the application directory:
+
+### Redirect to Login Page
+
+Upon login timeout, it will redirect to the login page.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    loginExpiredMode: 'page',
+  },
+});
+```
+
+### Open Login Popup
+
+When login times out, a login popup will open.
+
+![login-expired](/guide/login-expired.png)
+
+Configuration:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    loginExpiredMode: 'modal',
+  },
+});
+```
+
+## Dynamic Title
+
+- Default value: `true`
+
+When enabled, the webpage title changes according to the route's `title`. You can enable or disable this in the `preferences.ts` file in your application directory.
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    dynamicTitle: true,
+  },
+});
+```
+
+## Page Watermark
+
+- Default value: `false`
+
+When enabled, the webpage will display a watermark. You can enable or disable this in the `preferences.ts` file in your application directory.
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    watermark: true,
+  },
+});
+```
+
+If you want to update the content of the watermark, you can do so. The parameters can be referred to [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/):
+
+```ts
+import { useWatermark } from '@vben/hooks';
+
+const { destroyWatermark, updateWatermark } = useWatermark();
+
+await updateWatermark({
+  // watermark content
+  content: 'hello my watermark',
+});
+```
diff --git a/eims-ui/docs/src/en/guide/in-depth/layout.md b/eims-ui/docs/src/en/guide/in-depth/layout.md
new file mode 100644
index 0000000..412c1cf
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/layout.md
@@ -0,0 +1 @@
+# Layout
diff --git a/eims-ui/docs/src/en/guide/in-depth/loading.md b/eims-ui/docs/src/en/guide/in-depth/loading.md
new file mode 100644
index 0000000..0f1cff6
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/loading.md
@@ -0,0 +1,44 @@
+# Global Loading
+
+Global loading refers to the loading effect that appears when the page is refreshed, usually a spinning icon:
+
+![Global loading spinner](/guide/loading.png)
+
+## Principle
+
+Implemented by the `vite-plugin-inject-app-loading` plugin, the plugin injects a global `loading html` into each application.
+
+## Disable
+
+If you do not need global loading, you can disable it in the `.env` file:
+
+```bash
+VITE_INJECT_APP_LOADING=false
+```
+
+## Customization
+
+If you want to customize the global loading, you can create a `loading.html` file in the application directory, at the same level as `index.html`. The plugin will automatically read and inject this HTML. You can define the style and animation of this HTML as you wish.
+
+::: tip
+
+- You can use the same syntax as in `index.html`, such as the `VITE_APP_TITLE` variable, to get the application's title.
+- You must ensure there is an element with `id="__app-loading__"`.
+- Add a `hidden` class to the element with `id="__app-loading__"`.
+- You must ensure there is a `style[data-app-loading="inject-css"]` element.
+
+```html{1,4}
+<style data-app-loading="inject-css">
+  #__app-loading__.hidden {
+    pointer-events: none;
+    visibility: hidden;
+    opacity: 0;
+    transition: all 1s ease-out;
+  }
+  /* ... */
+</style>
+<div id="__app-loading__">
+  <!-- ... -->
+  <div class="title"><%= VITE_APP_TITLE %></div>
+</div>
+```
diff --git a/eims-ui/docs/src/en/guide/in-depth/locale.md b/eims-ui/docs/src/en/guide/in-depth/locale.md
new file mode 100644
index 0000000..549bc83
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/locale.md
@@ -0,0 +1,227 @@
+# Internationalization
+
+The project has integrated [Vue i18n](https://kazupon.github.io/vue-i18n/), and Chinese and English language packs have been configured.
+
+## IDE Plugin
+
+If you are using vscode as your development tool, it is recommended to install the [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) plugin. It can help you manage internationalization copy more conveniently. After installing this plugin, you can see the corresponding language content in your code in real-time:
+
+![](/public/guide/locale.png)
+
+## Configure Default Language
+
+You just need to override the default preferences. In the corresponding application, find the `src/preferences.ts` file and modify the value of `locale`:
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+  app: {
+    locale: 'en-US',
+  },
+});
+```
+
+## Dynamic Language Switching
+
+Switching languages consists of two parts:
+
+- Updating preferences
+- Loading the corresponding language pack
+
+```ts
+import type { SupportedLanguagesType } from '@vben/locales';
+import { loadLocaleMessages } from '@vben/locales';
+import { updatePreferences } from '@vben/preferences';
+
+async function updateLocale(value: string) {
+  // 1. Update preferences
+  const locale = value as SupportedLanguagesType;
+  updatePreferences({
+    app: {
+      locale,
+    },
+  });
+  // 2. Load the corresponding language pack
+  await loadLocaleMessages(locale);
+}
+
+updateLocale('en-US');
+```
+
+## Adding Translation Texts
+
+::: warning Attention
+
+- Do not place business translation texts inside `@vben/locales` to better manage business and general translation texts.
+- When adding new translation texts and multiple language packs are available, ensure to add the corresponding texts in all language packs.
+
+:::
+
+To add new translation texts, simply find `src/locales/langs/` in the corresponding application and add the texts accordingly, for example:
+
+**src/locales/langs/zh-CN/\*.json**
+
+````ts
+```json
+{
+  "about": {
+    "desc": "Vben Admin 鏄竴涓幇浠g殑绠$悊妯$増銆�"
+  }
+}
+````
+
+**src/locales/langs/en-US.ts**
+
+````ts
+```json
+{
+  "about": {
+    "desc": "Vben Admin is a modern management template."
+  }
+}
+````
+
+## Using Translation Texts
+
+With `@vben/locales`, you can easily use translation texts:
+
+### In Code
+
+```vue
+<script setup lang="ts">
+import { computed } from 'vue';
+import { $t } from '@vben/locales';
+
+const items = computed(() => [{ title: $t('about.desc') }]);
+</script>
+<template>
+  <div>{{ $t('about.desc') }}</div>
+  <template v-for="item in items.value">
+    <div>{{ item.title }}</div>
+  </template>
+</template>
+```
+
+## Adding a New Language Pack
+
+If you need to add a new language pack, follow these steps:
+
+- Add the corresponding language pack file in the `packages/locales/langs` directory, for example, `zh-TW.json`, and translate the respective texts.
+- In the corresponding application, locate the `src/locales/langs` file and add the new language pack `zh-TW.json`.
+- Add the corresponding language in `packages/constants/src/core.ts`:
+
+  ```ts
+  export interface LanguageOption {
+    label: string;
+    value: 'en-US' | 'zh-CN'; // [!code --]
+    value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+  }
+  export const SUPPORT_LANGUAGES: LanguageOption[] = [
+    {
+      label: '绠�浣撲腑鏂�',
+      value: 'zh-CN',
+    },
+    {
+      label: 'English',
+      value: 'en-US',
+    },
+    {
+      label: '绻佷綋涓枃', // [!code ++]
+      value: 'zh-TW', // [!code ++]
+    },
+  ];
+  ```
+
+- In `packages/locales/typing.ts`, add a new TypeScript type:
+
+  ```ts
+  export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
+  export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+  ```
+
+At this point, you can use the newly added language pack in the project.
+
+## Interface Language Switching Function
+
+If you want to disable the language switching display button on the interface, in the corresponding application, find the `src/preferences.ts` file and modify the value of `locale` accordingly:
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+  widget: {
+    languageToggle: false,
+  },
+});
+```
+
+## Remote Loading of Language Packs
+
+::: tip Tip
+
+When making interface requests through the project's built-in `request` tool, the default request header will include [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), allowing the server to dynamically internationalize data based on the request header.
+
+:::
+
+Each application has an independent language pack that can override the general language configuration. You can remotely load the corresponding language pack by finding the `src/locales/index.ts` file in the corresponding application and modifying the `loadMessages` method accordingly:
+
+```ts {3-4}
+async function loadMessages(lang: SupportedLanguagesType) {
+  const [appLocaleMessages] = await Promise.all([
+    // Modify here to load data via a remote interface
+    localesMap[lang](),
+    loadThirdPartyMessage(lang),
+  ]);
+  return appLocaleMessages.default;
+}
+```
+
+## Third-Party Language Packs
+
+Different applications may use third-party component libraries or plugins with varying internationalization methods, so they need to be handled differently. If you need to introduce a third-party language pack, you can find the `src/locales/index.ts` file in the corresponding application and modify the `loadThirdPartyMessage` method accordingly:
+
+```ts
+/**
+ * Load the dayjs language pack
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    // Default to using English
+    default: {
+      locale = await import('dayjs/locale/en');
+    }
+  }
+  if (locale) {
+    dayjs.locale(locale);
+  } else {
+    console.error(`Failed to load dayjs locale for ${lang}`);
+  }
+}
+```
+
+## Removing Internationalization
+
+Firstly, it is not recommended to remove internationalization, as it is a good development practice. However, if you really need to remove it, you can directly use Chinese copy and then retain the project's built-in language pack, which will not affect the overall development experience. The steps to remove internationalization are as follows:
+
+- Hide the language switching button on the interface, see: [Interface Language Switching Function](#interface-language-switching-function)
+- Modify the default language, see: [Configure Default Language](#configure-default-language)
+- Disable `vue-i18n` warning prompts, in the `src/locales/index.ts` file, modify `missingWarn` to `false`:
+
+  ```ts
+  async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+    await coreSetup(app, {
+      defaultLocale: preferences.app.locale,
+      loadMessages,
+      missingWarn: !import.meta.env.PROD, // [!code --]
+      missingWarn: false, // [!code ++]
+      ...options,
+    });
+  }
+  ```
diff --git a/eims-ui/docs/src/en/guide/in-depth/login.md b/eims-ui/docs/src/en/guide/in-depth/login.md
new file mode 100644
index 0000000..7fdac2c
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/login.md
@@ -0,0 +1,119 @@
+# Login
+
+This document explains how to customize the login page of your application.
+
+## Login Page Adjustment
+
+If you want to adjust the title, description, icon, and toolbar of the login page, you can do so by configuring the `props` parameter of the `AuthPageLayout` component.
+
+![login](/guide/login.png)
+
+You just need to configure the `props` parameter of `AuthPageLayout` in `src/router/routes/core.ts` within your application:
+
+```ts {4-8}
+ {
+    component: AuthPageLayout,
+    props: {
+      sloganImage: "xxx/xxx.png",
+      pageTitle: "寮�绠卞嵆鐢ㄧ殑澶у瀷涓悗鍙扮鐞嗙郴缁�",
+      pageDescription: "宸ョ▼鍖栥�侀珮鎬ц兘銆佽法缁勪欢搴撶殑鍓嶇妯$増",
+      toolbar: true,
+      toolbarList: ['color', 'language', 'layout', 'theme'],
+    }
+    // ...
+  },
+```
+
+::: tip
+
+If these configurations do not meet your needs, you can implement your own login page. Simply implement your own `AuthPageLayout`.
+
+:::
+
+## Login Form Adjustment
+
+If you want to adjust the content of the login form, you can configure the `AuthenticationLogin` component parameters in `src/views/_core/authentication/login.vue` within your application:
+
+```vue
+<AuthenticationLogin
+  :loading="authStore.loginLoading"
+  @submit="authStore.authLogin"
+/>
+```
+
+::: details AuthenticationLogin Component Props
+
+```ts
+{
+  /**
+   * @en Verification code login path
+   */
+  codeLoginPath?: string;
+  /**
+   * @en Forget password path
+   */
+  forgetPasswordPath?: string;
+
+  /**
+   * @en Whether it is in loading state
+   */
+  loading?: boolean;
+
+  /**
+   * @en QR code login path
+   */
+  qrCodeLoginPath?: string;
+
+  /**
+   * @en Registration path
+   */
+  registerPath?: string;
+
+  /**
+   * @en Whether to show verification code login
+   */
+  showCodeLogin?: boolean;
+  /**
+   * @en Whether to show forget password
+   */
+  showForgetPassword?: boolean;
+
+  /**
+   * @en Whether to show QR code login
+   */
+  showQrcodeLogin?: boolean;
+
+  /**
+   * @en Whether to show registration button
+   */
+  showRegister?: boolean;
+
+  /**
+   * @en Whether to show remember account
+   */
+  showRememberMe?: boolean;
+
+  /**
+   * @en Whether to show third-party login
+   */
+  showThirdPartyLogin?: boolean;
+
+  /**
+   * @en Login box subtitle
+   */
+  subTitle?: string;
+
+  /**
+   * @en Login box title
+   */
+  title?: string;
+}
+```
+
+:::
+
+::: tip
+
+If these configurations do not meet your needs, you can implement your own login form and related login logic.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/in-depth/theme.md b/eims-ui/docs/src/en/guide/in-depth/theme.md
new file mode 100644
index 0000000..11c9c99
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/theme.md
@@ -0,0 +1,1293 @@
+# Theme
+
+The framework is built on [shadcn-vue](https://www.shadcn-vue.com/themes.html) and [tailwindcss](https://tailwindcss.com/), offering a rich theme configuration. You can easily switch between various themes through simple configuration to meet personalized needs. You can choose to use CSS variables or Tailwind CSS utility classes for theme settings.
+
+## CSS Variables
+
+The project follows the theme configuration of [shadcn-vue](https://www.shadcn-vue.com/themes.html), for example:
+
+```html
+<div class="bg-background text-foreground" />
+```
+
+We use a simple convention for colors. The `background` variable is used for the background color of components, and the `foreground` variable is used for text color.
+
+For the following components, `background` will be `hsl(var(--primary))`, and `foreground` will be `hsl(var(--primary-foreground))`.
+
+## Detailed List of CSS Variables
+
+::: warning Note
+
+The colors inside CSS variables must use the `hsl` format, such as `0 0% 100%`, without adding `hsl()` and `,`.
+
+:::
+
+You can check the list below to understand all the available variables.
+
+::: details Default theme CSS variables
+
+```css
+:root {
+  --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+    'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+  /* Default background color of <body />...etc */
+  --background: 0 0% 100%;
+
+  /* Main area background color */
+  --background-deep: 216 20.11% 95.47%;
+  --foreground: 210 6% 21%;
+
+  /* Background color for <Card /> */
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+
+  /* Theme Colors */
+
+  --primary: 212 100% 45%;
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* Secondary colors for <Button /> */
+
+  --secondary: 240 5% 96%;
+  --secondary-foreground: 240 6% 10%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 240 5% 96%;
+  --accent-hover: 200deg 10% 90%;
+  --accent-foreground: 240 6% 10%;
+
+  /* Darker color */
+  --heavy: 192deg 9.43% 89.61%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 5.9% 90%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 240deg 5.88% 90%;
+  --input-placeholder: 217 10.6% 65%;
+  --input-background: 0 0% 100%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* Border radius for card, input and buttons */
+  --radius: 0.5rem;
+
+  /* ============= custom ============= */
+
+  /* overlay color */
+  --overlay: 0deg 0% 0% / 30%;
+
+  /* base font size */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  /* menu */
+  --sidebar: 0 0% 100%;
+  --sidebar-deep: 216 20.11% 95.47%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 0 0% 100%;
+
+  accent-color: var(--primary);
+  color-scheme: light;
+}
+```
+
+:::
+
+::: details Default theme dark mode CSS variables
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Default background color of <body />...etc */
+  --background: 222.34deg 10.43% 12.27%;
+
+  /* Main area background color */
+  --background-deep: 220deg 13.06% 9%;
+  --foreground: 0 0% 95%;
+
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+
+  /* --card: 222.2 84% 4.9%; */
+  --card-foreground: 210 40% 98%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 222.82deg 8.43% 12.27%;
+  --popover-foreground: 210 40% 98%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+  --muted: 220deg 6.82% 17.25%;
+  --muted-foreground: 215 20.2% 65.1%;
+
+  /* Theme Colors */
+
+  /* --primary: 245 82% 67%; */
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* secondary color */
+  --secondary: 240 5% 17%;
+  --secondary-foreground: 0 0% 98%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 0deg 0% 100% / 8%;
+  --accent-hover: 0deg 0% 100% / 12%;
+  --accent-foreground: 0 0% 98%;
+
+  /* Darker color */
+  --heavy: 0deg 0% 100% / 12%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 3.7% 15.9%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 0deg 0% 100% / 10%;
+  --input-placeholder: 218deg 11% 65%;
+  --input-background: 0deg 0% 100% / 5%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* base radius */
+  --radius: 0.5rem;
+
+  /* ============= Custom ============= */
+
+  /* overlay color */
+  --overlay: 0deg 0% 0% / 40%;
+
+  /* base font size */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  --sidebar: 222.34deg 10.43% 12.27%;
+  --sidebar-deep: 220deg 13.06% 9%;
+  --menu: var(--sidebar);
+  --header: 222.34deg 10.43% 12.27%;
+
+  color-scheme: dark;
+}
+```
+
+:::
+
+## Overriding Default CSS Variables
+
+You only need to override the CSS variables you want to change in your project. For example, to change the default card background color, you can add the following content to your CSS file to override it:
+
+### Under the Default Theme
+
+```css
+:root {
+  /* Background color for <Card /> */
+  --card: 0 0% 30%;
+}
+```
+
+### In Dark Mode
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+}
+```
+
+## Changing the Brand Primary Color
+
+::: tip
+
+- You need to use the `hsl` color format.
+- You must clear the cache for the changes to take effect.
+- You can use [third-party tools](https://www.w3schools.com/colors/colors_hsl.asp) to convert colors.
+
+:::
+
+You only need to customize the primary color in the `preferences.ts` file under the application directory:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    // Error color
+    colorDestructive: 'hsl(348 100% 61%)',
+    // Primary color
+    colorPrimary: 'hsl(212 100% 45%)',
+    // Success color
+    colorSuccess: 'hsl(144 57% 58%)',
+    // Warning color
+    colorWarning: 'hsl(42 84% 61%)',
+  },
+});
+```
+
+## Built-in Themes
+
+The framework includes a variety of built-in themes, which you can configure in the `preferences.ts` file:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    builtinType: 'default',
+  },
+});
+```
+
+### Built-in Theme List
+
+The framework includes 16 built-in themes and also supports custom themes. Theoretically, you can expand the themes without limit.
+
+::: details List of Built-in Theme Types
+
+```ts
+type BuiltinThemeType =
+  | 'custom'
+  | 'deep-blue'
+  | 'deep-green'
+  | 'default'
+  | 'gray'
+  | 'green'
+  | 'neutral'
+  | 'orange'
+  | 'pink'
+  | 'red'
+  | 'rose'
+  | 'sky-blue'
+  | 'slate'
+  | 'stone'
+  | 'violet'
+  | 'yellow'
+  | 'zinc'
+  | (Record<never, never> & string);
+```
+
+:::
+
+::: details Built-in Theme CSS Variables - Light
+
+```css
+:root {
+  --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+    'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+  /* Default background color of <body />...etc */
+  --background: 0 0% 100%;
+
+  /* Main area background color */
+  --background-deep: 216 20.11% 95.47%;
+  --foreground: 222 84% 5%;
+
+  /* Background color for <Card /> */
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%; */
+
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+
+  /* Theme Colors */
+
+  --primary: 212 100% 45%;
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* Secondary colors for <Button /> */
+
+  --secondary: 240 5% 96%;
+  --secondary-foreground: 240 6% 10%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 240 5% 96%;
+  --accent-hover: 200deg 10% 90%;
+  --accent-foreground: 240 6% 10%;
+
+  /* Darker color */
+  --heavy: 192deg 9.43% 89.61%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 5.9% 90%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 240deg 5.88% 90%;
+  --input-placeholder: 217 10.6% 65%;
+  --input-background: 0 0% 100%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* Border radius for card, input and buttons */
+  --radius: 0.5rem;
+
+  /* ============= custom ============= */
+
+  /* overlay color */
+  --overlay: 0deg 0% 0% / 30%;
+
+  /* base font size */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  /* menu */
+  --sidebar: 0 0% 100%;
+  --sidebar-deep: 0 0% 100%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 0 0% 100%;
+
+  accent-color: var(--primary);
+  color-scheme: light;
+}
+
+[data-theme='violet'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 262.1 83.3% 57.8%;
+}
+
+[data-theme='pink'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='rose'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='sky-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='deep-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='deep-green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='orange'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 24.6 95% 53.1%;
+}
+
+[data-theme='yellow'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 20 14.3% 4.1%;
+}
+
+[data-theme='zinc'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 240 5.9% 10%;
+}
+
+[data-theme='neutral'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 0 0% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 0 0% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 0 0% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 0 0% 96.1%;
+  --secondary-foreground: 0 0% 9%;
+  --muted: 0 0% 96.1%;
+  --muted-foreground: 0 0% 45.1%;
+  --accent: 0 0% 96.1%;
+  --accent-foreground: 0 0% 9%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 89.8%;
+  --input: 0 0% 89.8%;
+  --ring: 0 0% 3.9%;
+}
+
+[data-theme='slate'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 222.2 84% 4.9%;
+}
+
+[data-theme='gray'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 224 71.4% 4.1%;
+}
+```
+
+:::
+
+::: details 鍐呯疆涓婚css鍙橀噺 - dark
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Default background color of <body />...etc */
+  --background: 222.34deg 10.43% 12.27%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 220deg 13.06% 9%;
+  --foreground: 0 0% 95%;
+
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+
+  /* --card: 222.2 84% 4.9%; */
+  --card-foreground: 210 40% 98%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 222.82deg 8.43% 12.27%;
+  --popover-foreground: 210 40% 98%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 220deg 6.82% 17.25%; */
+
+  /* --muted-foreground: 215 20.2% 65.1%; */
+
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+
+  /* 涓婚棰滆壊 */
+
+  /* --primary: 245 82% 67%; */
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* 棰滆壊娆¤ */
+  --secondary: 240 5% 17%;
+  --secondary-foreground: 0 0% 98%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 216 5% 19%;
+  --accent-hover: 216 5% 24%;
+  --accent-foreground: 0 0% 98%;
+
+  /* Darker color */
+  --heavy: 216 5% 24%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 3.7% 22%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 0deg 0% 100% / 10%;
+  --input-placeholder: 218deg 11% 65%;
+  --input-background: 0deg 0% 100% / 5%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* 鍩烘湰鍦嗚澶у皬 */
+  --radius: 0.5rem;
+
+  /* ============= Custom ============= */
+
+  /* overlay color */
+  --overlay: 0deg 0% 0% / 40%;
+
+  /* base font size */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  --sidebar: 222.34deg 10.43% 12.27%;
+  --sidebar-deep: 220deg 13.06% 9%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 222.34deg 10.43% 12.27%;
+
+  color-scheme: dark;
+}
+
+.dark[data-theme='violet'],
+[data-theme='violet'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 263.4 70% 50.4%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
+
+.dark[data-theme='pink'],
+[data-theme='pink'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 0 0% 9%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 346.8 77.2% 49.8%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='rose'],
+[data-theme='rose'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 85.7% 97.3%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 72.2% 50.6%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='sky-blue'],
+[data-theme='sky-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='deep-blue'],
+[data-theme='deep-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='green'],
+[data-theme='green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='deep-green'],
+[data-theme='deep-green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='orange'],
+[data-theme='orange'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 0 72.2% 50.6%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 20.5 90.2% 48.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='yellow'],
+[data-theme='yellow'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 35.5 91.7% 32.9%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='zinc'],
+[data-theme='zinc'] .dark {
+  --background: 240 10% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 240 10% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 240 10% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 240 5.9% 10%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 240 3.7% 15.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 240 4.9% 83.9%;
+  --sidebar: 240 10% 3.9%;
+  --sidebar-deep: 240 10% 3.9%;
+  --header: 240 4.9% 83.9%;
+}
+
+.dark[data-theme='neutral'],
+[data-theme='neutral'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 0% 9%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 0% 83.1%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='slate'],
+[data-theme='slate'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 222.2 47.4% 11.2%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 212.7 26.8% 83.9;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='gray'],
+[data-theme='gray'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 220.9 39.3% 11%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 216 12.2% 83.9%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
+```
+
+:::
+
+## Adding a New Theme
+
+To add a new theme, simply follow these steps:
+
+- Add a new theme configuration in the application's `src/preferences.ts`.
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    builtinType: 'my-theme',
+  },
+});
+```
+
+- Add the theme's CSS variables to your CSS file.
+
+```css
+/* light */
+[data-theme='my-theme'] {
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 262.1 83.3% 57.8%;
+}
+
+/* dark */
+.dark[data-theme='my-theme'],
+[data-theme='my-theme'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 263.4 70% 50.4%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+}
+```
+
+## Dark Mode
+
+The framework includes a variety of built-in themes, which you can configure in `preferences.ts`. The dark theme also uses CSS variables for configuration:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    mode: 'dark',
+  },
+});
+```
+
+## Customizing Sidebar Color
+
+The sidebar color is configured through the `--sidebar` variable.
+
+### Under the Default Theme
+
+```css
+:root {
+  --sidebar: 0 0% 100%;
+}
+```
+
+### In Dark Mode
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --sidebar: 222.34deg 10.43% 12.27%;
+}
+```
+
+## Customizing Header Color
+
+The header color is configured through the `--header` variable.
+
+### Under the Default Theme
+
+```css
+:root {
+  --header: 0 0% 100%;
+}
+```
+
+### In Dark Mode
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --header: 222.34deg 10.43% 12.27%;
+}
+```
+
+## Color Weakness Mode
+
+Typically used in special scenarios, you can set the application to color weakness mode. This can be configured in `preferences.ts`:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    colorWeakMode: true,
+  },
+});
+```
+
+## Gray Mode
+
+Typically used in special scenarios, this mode grays out the webpage. You can configure it in `preferences.ts`:
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    colorGrayMode: true,
+  },
+});
+```
diff --git a/eims-ui/docs/src/en/guide/in-depth/ui-framework.md b/eims-ui/docs/src/en/guide/in-depth/ui-framework.md
new file mode 100644
index 0000000..667619a
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/in-depth/ui-framework.md
@@ -0,0 +1,17 @@
+# UI Framework Switching
+
+`Vue Admin` supports your freedom to choose the UI framework. The default UI framework for the demo site is `Ant Design Vue`, consistent with the older version. The framework also has built-in versions for `Element Plus` and `Naive UI`, allowing you to choose according to your preference.
+
+## Adding a New UI Framework
+
+If you want to use a different UI framework, you only need to follow these steps:
+
+1. Create a new folder inside `apps`, for example, `apps/web-xxx`.
+2. Change the `name` field in `apps/web-xxx/package.json` to `web-xxx`.
+3. Remove dependencies and code from other UI frameworks and replace them with your chosen UI framework's logic, which requires minimal changes.
+4. Adjust the language files within `locales`.
+5. Adjust the components in `app.vue`.
+6. Adapt the theme of the UI framework to match `Vben Admin`.
+7. Adjust the application name in `.env`.
+8. Add a `dev:xxx` script in the root directory of the repository.
+9. Run `pnpm install` to install dependencies.
diff --git a/eims-ui/docs/src/en/guide/introduction/changelog.md b/eims-ui/docs/src/en/guide/introduction/changelog.md
new file mode 100644
index 0000000..83c822b
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/changelog.md
@@ -0,0 +1,3 @@
+# CHANGE LOG
+
+TODO
diff --git a/eims-ui/docs/src/en/guide/introduction/quick-start.md b/eims-ui/docs/src/en/guide/introduction/quick-start.md
new file mode 100644
index 0000000..d4829dc
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/quick-start.md
@@ -0,0 +1,95 @@
+---
+outline: deep
+---
+
+# Quick Start {#quick-start}
+
+## Prerequisites
+
+::: info Environment Requirements
+
+Before starting the project, ensure that your environment meets the following requirements:
+
+- [Node.js](https://nodejs.org/en) version 20.15.0 or above. It is recommended to use [fnm](https://github.com/Schniz/fnm), [nvm](https://github.com/nvm-sh/nvm), or directly use [pnpm](https://pnpm.io/cli/env) for version management.
+- [Git](https://git-scm.com/) any version.
+
+To verify if your environment meets the above requirements, you can check the versions using the following commands:
+
+```bash
+# Ensure the correct node LTS version is displayed
+node -v
+# Ensure the correct git version is displayed
+git -v
+```
+
+:::
+
+## Starting the Project
+
+### Obtain the Source Code
+
+::: code-group
+
+```bash [GitHub]
+# Clone the code
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+```bash [Gitee]
+# Clone the code
+# The Gitee repository may not have the latest code
+git clone https://gitee.com/annsion/vue-vben-admin.git
+```
+
+:::
+
+::: danger Caution
+
+Ensure that the directory where you store the code and all its parent directories do not contain Chinese, Korean, Japanese characters, or spaces, as this may cause errors when installing dependencies and starting the project.
+
+:::
+
+### Install Dependencies
+
+Open a terminal in your code directory and execute the following commands:
+
+```bash
+# Enter the project directory
+cd vue-vben-admin
+
+# Enable the project-specified version of pnpm
+corepack enable
+
+# Install dependencies
+pnpm install
+```
+
+::: tip Note
+
+The project only supports using `pnpm` for installing dependencies. By default, `corepack` will be used to install the specified version of `pnpm`.
+
+:::
+
+### Run the Project
+
+Execute the following command to run the project:
+
+```bash
+# Start the project
+pnpm dev
+```
+
+You will see an output similar to the following, allowing you to select the project you want to run:
+
+```bash
+鈹�
+鈼�  Select the app you need to run [dev]:
+鈹�  鈼� @vben/web-antd
+鈹�  鈼� @vben/web-ele
+鈹�  鈼� @vben/web-naive
+鈹�  鈼� @vben/docs
+鈹�  鈼� @vben/playground
+鈹�
+```
+
+Now, you can visit `http://localhost:5555` in your browser to view the project.
diff --git a/eims-ui/docs/src/en/guide/introduction/roadmap.md b/eims-ui/docs/src/en/guide/introduction/roadmap.md
new file mode 100644
index 0000000..8add7b1
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/roadmap.md
@@ -0,0 +1,3 @@
+# Roadmap
+
+TODO:
diff --git a/eims-ui/docs/src/en/guide/introduction/thin.md b/eims-ui/docs/src/en/guide/introduction/thin.md
new file mode 100644
index 0000000..a310ef3
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/thin.md
@@ -0,0 +1,67 @@
+# Slimmed-Down Version
+
+Starting from version `5.0`, we no longer provide slimmed-down repositories or branches. Our goal is to offer a more consistent development experience while reducing maintenance costs. Here鈥檚 how we introduce our project, slim down, and remove unnecessary features.
+
+## Application Slimming
+
+First, identify the version of the `UI` component library you need, and then delete the corresponding applications. For example, if you choose to use `Ant Design Vue`, you can delete the other applications. Simply remove the following two folders:
+
+```bash
+apps/web-ele
+apps/web-native
+
+```
+
+::: tip
+
+If your project doesn鈥檛 include the `UI` component library you need, you can delete all other applications and create your own new application as needed.
+
+:::
+
+## Demo Code Slimming
+
+If you don鈥檛 need demo code, you can simply delete the `playground` folder
+
+## Documentation Slimming
+
+If you don鈥檛 need documentation, you can delete the `docs` folder.
+
+## Remove Mock Service
+
+If you don鈥檛 need the `Mock` service, you can delete the `apps/backend-mock` folder. Also, remove the `VITE_NITRO_MOCK` variable from the `.env.development` file in your application.
+
+```bash
+# Whether to enable Nitro Mock service, true to enable, false to disable
+VITE_NITRO_MOCK=false
+```
+
+## Installing Dependencies
+
+Now that you鈥檝e completed the slimming operations, you can install the dependencies and start your project:
+
+```bash
+# Run in the root directory
+pnpm install
+
+```
+
+## Adjusting Commands
+
+After slimming down, you may need to adjust commands according to your project. In the `package.json` file in the root directory, you can adjust the `scripts` field and remove any commands you don鈥檛 need.
+
+```json
+{
+  "scripts": {
+    "build:antd": "pnpm run build --filter=@vben/web-antd",
+    "build:docs": "pnpm run build --filter=@vben/docs",
+    "build:ele": "pnpm run build --filter=@vben/web-ele",
+    "build:naive": "pnpm run build --filter=@vben/web-naive",
+    "build:play": "pnpm run build --filter=@vben/playground",
+    "dev:antd": "pnpm -F @vben/web-antd run dev",
+    "dev:docs": "pnpm -F @vben/docs run dev",
+    "dev:ele": "pnpm -F @vben/web-ele run dev",
+    "dev:play": "pnpm -F @vben/playground run dev",
+    "dev:naive": "pnpm -F @vben/web-naive run dev"
+  }
+}
+```
diff --git a/eims-ui/docs/src/en/guide/introduction/vben.md b/eims-ui/docs/src/en/guide/introduction/vben.md
new file mode 100644
index 0000000..8a2ba1c
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/vben.md
@@ -0,0 +1,49 @@
+# About Vben Admin
+
+::: info You are reading the documentation for [Vben Admin](https://github.com/vbenjs/vue-vben-admin) version `5.0`!
+
+- Vben Admin 2.x is currently archived and only receives critical fixes.
+- The new version is not compatible with the old version. If you are using the old version (v2, v3), please refer to the [Vue Vben Admin 2.x Documentation](https://doc.vvbin.cn).
+- If you find any errors in the documentation, feel free to submit an issue to help us improve.
+- If you just want to experience it, you can check out the [Quick Start](./quick-start.md).
+
+:::
+
+[Vben Admin](https://github.com/vbenjs/vue-vben-admin) is a backend solution based on [Vue 3.0](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), and [TypeScript](https://www.typescriptlang.org/), aimed at providing an out-of-the-box solution for developing medium to large-scale projects. It includes features like component re-encapsulation, utilities, hooks, dynamic menus, permission validation, multi-theme configurations, and button-level permission control. The project uses the latest frontend technology stack, making it a good starting template for quickly building enterprise-level mid- to backend product prototypes. It can also serve as an example for learning `vue3`, `vite`, `ts`, and other mainstream technologies. The project will continue to follow the latest technologies and apply them within the project.
+
+## Features
+
+- **Latest Technology Stack**: Developed using cutting-edge frontend technologies like `Vue 3`, `Vite`, and `TypeScript`.
+- **Internationalization**: Built-in comprehensive internationalization solutions with multi-language support.
+- **Permission Validation**: Comprehensive permission validation solutions, including button-level permission control.
+- **Multi-Theme**: Built-in multiple theme configurations & dark mode to meet personalized needs.
+- **Dynamic Menu**: Supports dynamic menus that can display based on permissions.
+- **Mock Data**: High-performance local Mock data solution based on `Nitro`.
+- **Rich Components**: Provides a wide range of components to meet most business needs.
+- **Standardization**: Code quality is ensured with tools like `ESLint`, `Prettier`, `Stylelint`, `Publint`, and `CSpell`.
+- **Engineering**: Development efficiency is improved with tools like `Pnpm Monorepo`, `TurboRepo`, and `Changeset`.
+- **Multi-UI Library Support**: Supports mainstream UI libraries like `Ant Design Vue`, `Element Plus`, and `Vuetify`, without being restricted to a specific framework.
+
+## Browser Support
+
+- **Local development** is recommended using the **latest version of Chrome**. **Versions below Chrome 80 are not supported**.
+
+- **Production environment** supports modern browsers, IE is not supported.
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px"  />](http://godban.github.io/browsers-support-badges/)IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## Contribution
+
+- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) is still being actively updated. Contributions are welcome to help maintain and improve the project, aiming to create a better mid- to backend solution.
+- If you wish to join us, you can start by contributing in the following ways, and we will invite you to join based on your activity.
+
+::: info Join Us
+
+- Regularly submit `PRs`.
+- Provide valuable suggestions.
+- Participate in discussions and help resolve some `issues`.
+- Help maintain the documentation.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/introduction/why.md b/eims-ui/docs/src/en/guide/introduction/why.md
new file mode 100644
index 0000000..f0cabe8
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/introduction/why.md
@@ -0,0 +1,9 @@
+# Why Choose Us?
+
+First of all, we do not compare ourselves with other frameworks. We believe that every framework has its own characteristics and is suited for different scenarios. Our goal is to provide a simple and easy-to-use framework that allows developers to get started quickly and focus on developing business logic. Therefore, we will continue to improve and optimize our framework to offer a better experience.
+
+## Framework History
+
+Starting from Vue Vben Admin version 1.x, the framework has undergone numerous iterations and optimizations. From initially using `Vite 0.x` when there were no ready-made plugins available, we developed many custom plugins to bridge the gap between Webpack and Vite. Although many of these have since been replaced, our original intention has remained the same: to provide a simple and easy-to-use framework.
+
+Although the community maintained the project for a period, we have always closely monitored the development of Vue Vben Admin. We have witnessed many developers use Vben Admin and provide valuable suggestions and feedback. We are very grateful for everyone's support and contributions, which continue to drive us to improve Vben Admin. In the new version, we have continuously collected user feedback, started anew, and optimized the framework to provide a better user experience. Our goal is to enable developers to get started quickly and focus on developing business logic.
diff --git a/eims-ui/docs/src/en/guide/other/faq.md b/eims-ui/docs/src/en/guide/other/faq.md
new file mode 100644
index 0000000..da908f8
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/other/faq.md
@@ -0,0 +1,159 @@
+# Frequently Asked Questions #{faq}
+
+::: tip Listed are some common questions
+
+If you have a question, you can first look here. If not found, you can search or submit your question on [GitHub Issue](https://github.com/vbenjs/vue-vben-admin/issues), or if it's a discussion-type question, you can go to [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)
+
+:::
+
+## Instructions
+
+If you encounter a problem, you can start looking from the following aspects:
+
+1. Search the corresponding module's GitHub repository [issue](https://github.com/vbenjs/vue-vben-admin/issues)
+2. Search for the problem on [Google](https://www.google.com)
+3. Search for the problem on [Baidu](https://www.baidu.com)
+4. If you can't find the issue in the list below, you can ask in [issues](https://github.com/vbenjs/vue-vben-admin/issues)
+5. If it's not a problem type and needs discussion, please go to [discussions](https://github.com/vbenjs/vue-vben-admin/discussions) to discuss
+
+## Dependency Issues
+
+In a `Monorepo` project, it is necessary to develop the habit of executing `pnpm install` every time you `git pull` the code, as new dependency packages are often added. The project has already configured automatic execution of `pnpm install` in `.husky/git-merge`, but sometimes there might be issues. If it does not execute automatically, it is recommended to execute it manually once.
+
+## About Cache Update Issues
+
+The project configuration is by default cached in `localStorage`, so some configurations may not change after a version update.
+
+The solution is to modify the `version` number in `package.json` each time the code is updated. This is because the key for `localStorage` is based on the version number. Therefore, after an update, the configurations from a previous version will become invalid. Simply re-login to apply the new settings.
+
+## About Modifying Configuration Files
+
+When modifying environment files such as `.env` or the `vite.config.ts` file, Vite will automatically restart the service.
+
+There's a chance that automatic restarts may encounter issues. Simply rerunning the project can resolve these problems.
+
+## Errors When Running Locally
+
+Since Vite does not transform code locally and the code uses relatively new syntax such as optional chaining, local development requires using a higher version of the browser (`Chrome 90+`).
+
+## Blank Page After Switching Pages
+
+This issue occurs because route switching animations are enabled, and the corresponding page component has multiple root nodes. Adding a `<div></div>` at the outermost layer of the page can solve this problem.
+
+**Incorrect Example**
+
+```vue
+<template>
+  <!-- Annotations are also considered a node -->
+  <h1>text h1</h1>
+  <h2>text h2</h2>
+</template>
+```
+
+**姝g‘绀轰緥**
+
+```vue
+<template>
+  <div>
+    <h1>text h1</h1>
+    <h2>text h2</h2>
+  </div>
+</template>
+```
+
+::: tip Tip
+
+- If you want to use multiple root tags, you can disable route switching animations.
+- Root comment nodes under `template` are also counted as a node.
+
+:::
+
+## My code works locally but not when packaged
+
+The reason for this issue could be one of the following. You can check these reasons, and if there are other possibilities, feel free to add them:
+
+- The variable `ctx` was used, which is not exposed in the instance type. The Vue official documentation also advises against using this property as it is intended for internal use only.
+
+```ts
+import { getCurrentInstance } from 'vue';
+getCurrentInstance().ctx.xxxx;
+```
+
+## Dependency Installation Issues
+
+- If you cannot install dependencies or the startup reports an error, you can try executing `pnpm run reinstall`.
+- If you cannot install dependencies or encounter errors, you can try switching to a mobile hotspot for installing dependencies.
+- If that still doesn't work, you can configure a domestic mirror for installation.
+- You can also create a `.npmrc` file in the project root directory with the following content:
+
+```bash
+# .npmrc
+registry = https://registry.npmmirror.com/
+```
+
+## Package File Too Large
+
+- First, the full version will be larger because it includes many library files. You can use the simplified version for development.
+
+- Secondly, it is recommended to enable gzip, which can reduce the size to about 1/3 of the original. Gzip can be enabled directly by the server. If so, the frontend does not need to build `.gz` format files. If the frontend has built `.gz` files, for example, with nginx, you need to enable the `gzip_static: on` option.
+
+- While enabling gzip, you can also enable `brotli` for better compression than gzip. Both can coexist.
+
+**Note**
+
+- gzip_static: This module requires additional installation in nginx, as the default nginx does not include this module.
+
+- Enabling `brotli` also requires additional nginx module installation.
+
+## Runtime Errors
+
+If you encounter errors similar to the following, please check that the full project path (including all parent paths) does not contain Chinese, Japanese, or Korean characters. Otherwise, you will encounter a 404 error for the path, leading to the following issue:
+
+```ts
+[vite] Failed to resolve module import "ant-design-vue/dist/antd.css-vben-adminode_modulesant-design-vuedistantd.css". (imported by /@/setup/ant-design-vue/index.ts)
+```
+
+## Console Route Warning Issue
+
+If you see the following warning in the console, and the page `can open normally`, you can ignore this warning.
+
+Future versions of `vue-router` may provide an option to disable this warning.
+
+```ts
+[Vue Router warn]: No match found for location with path "xxxx"
+```
+
+## Startup Error
+
+If you encounter the following error message, please check if your nodejs version meets the requirements.
+
+```bash
+TypeError: str.matchAll is not a function
+at Object.extractor (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:146:27)
+at Extract (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:173:54)
+```
+
+## nginx Deployment
+
+After deploying to `nginx`锛寉ou might encounter the following error:
+
+```bash
+Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
+```
+
+Solution 1:
+
+```bash
+http {
+    #If there is such a configuration, it needs to be commented out
+    #include       mime.types;
+
+    types {
+      application/javascript js mjs;
+    }
+}
+```
+
+Solution 2锛�
+
+Open the `mime.types` file under `nginx` and change `application/javascript js;` to `application/javascript js mjs;`
diff --git a/eims-ui/docs/src/en/guide/other/project-update.md b/eims-ui/docs/src/en/guide/other/project-update.md
new file mode 100644
index 0000000..85ceef4
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/other/project-update.md
@@ -0,0 +1,54 @@
+# PROJECT UPDATE
+
+## Why Can't It Be Updated Like a npm Plugin
+
+Because the project is a complete project template, not a plugin or a package, it cannot be updated like a plugin. After you use the code, you will develop it further based on business needs, and you need to manually merge and upgrade.
+
+## What Should I Do
+
+The project is managed using a `Monorepo` approach and has abstracted some of the more core code, such as `packages/@core`, `packages/effects`. As long as the business code has not modified this part of the code, you can directly pull the latest code and then merge it into your branch. You only need to handle some conflicts simply. Other folders will only make some minor adjustments, which will not affect the business code.
+
+::: tip Recommendation
+
+It is recommended to follow the repository updates actively and merge them; do not accumulate over a long time, Otherwise, it will lead to too many merge conflicts and increase the difficulty of merging.
+
+:::
+
+## Updating Code Using Git
+
+1. Clone the code
+
+```bash
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+2. Add your company's git source address
+
+```bash
+# up is the source name, can be set arbitrarily
+# gitUrl is the latest open-source code
+git remote add up gitUrl;
+```
+
+3. Push the code to your company's git
+
+```bash
+# Push the code to your company
+# main is the branch name, adjust according to your situation
+git push up main
+# Sync the company's code
+# main is the branch name, adjust according to your situation
+git pull up main
+```
+
+4. How to sync the latest open-source code
+
+```bash
+git pull origin main
+```
+
+::: tip Tip
+
+When syncing the code, conflicts may occur. Just resolve the conflicts.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/other/remove-code.md b/eims-ui/docs/src/en/guide/other/remove-code.md
new file mode 100644
index 0000000..543a937
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/other/remove-code.md
@@ -0,0 +1,18 @@
+# Remove Code
+
+## Remove Code
+
+In the corresponding application's `index.html` file, find the following code and delete it:
+
+```html
+<!-- apps/web-antd -->
+<script>
+  var _hmt = _hmt || [];
+  (function () {
+    var hm = document.createElement('script');
+    hm.src = 'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';
+    var s = document.getElementsByTagName('script')[0];
+    s.parentNode.insertBefore(hm, s);
+  })();
+</script>
+```
diff --git a/eims-ui/docs/src/en/guide/project/changeset.md b/eims-ui/docs/src/en/guide/project/changeset.md
new file mode 100644
index 0000000..0f2abe7
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/changeset.md
@@ -0,0 +1,21 @@
+# Changeset
+
+The project has integrated [changeset](https://github.com/changesets/changesets) as a version management tool. Changeset is a version management tool that helps us better manage versions, generate changelogs, and automate releases.
+
+For detailed usage, please refer to the official documentation. If you do not need it, you can ignore it directly.
+
+## Command Line
+
+The changeset command is already built into the project:
+
+### Interactively Add Changesets
+
+```bash
+pnpm run changeset
+```
+
+### Uniformly Increment Version Numbers
+
+```bash
+pnpm run version
+```
diff --git a/eims-ui/docs/src/en/guide/project/cli.md b/eims-ui/docs/src/en/guide/project/cli.md
new file mode 100644
index 0000000..a9e43ff
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/cli.md
@@ -0,0 +1,106 @@
+---
+outline: deep
+---
+
+# CLI
+
+In the project, some command-line tools are provided for common operations, located in `scripts`.
+
+## vsh
+
+Used for some project operations, such as cleaning the project, checking the project, etc.
+
+### Usage
+
+```bash
+pnpm vsh [command] [options]
+```
+
+### vsh check-circular
+
+Check for circular references throughout the project. If there are circular references, the modules involved will be output to the console.
+
+#### Usage
+
+```bash
+pnpm vsh check-circular
+```
+
+#### Options
+
+| Option     | Description                                               |
+| ---------- | --------------------------------------------------------- |
+| `--staged` | Only check files in the git staging area, default `false` |
+
+### vsh check-dep
+
+Check the dependency situation of the entire project and output `unused dependencies`, `uninstalled dependencies` information to the console.
+
+#### Usage
+
+```bash
+pnpm vsh check-dep
+```
+
+### vsh lint
+
+Lint checks the project to see if the code in the project conforms to standards.
+
+#### Usage
+
+```bash
+pnpm vsh lint
+```
+
+#### Options
+
+| Option     | Description                                  |
+| ---------- | -------------------------------------------- |
+| `--format` | Check and try to fix errors, default `false` |
+
+### vsh publint
+
+Perform package standard checks on `Monorepo` projects to see if the packages in the project conform to standards.
+
+#### Usage
+
+```bash
+pnpm vsh publint
+```
+
+#### Options
+
+| Option    | Description                          |
+| --------- | ------------------------------------ |
+| `--check` | Only perform checks, default `false` |
+
+### vsh code-workspace
+
+Generate `vben-admin.code-workspace` file. Currently, it does not need to be executed manually and will be executed automatically when code is committed.
+
+#### Usage
+
+```bash
+pnpm vsh code-workspace
+```
+
+#### Options
+
+| Option          | Description                                               |
+| --------------- | --------------------------------------------------------- |
+| `--auto-commit` | Automatically commit during `git commit`, default `false` |
+| `--spaces`      | Indentation format, default `2` spaces                    |
+
+## turbo-run
+
+Used to quickly execute scripts in the large repository and provide option-based interactive selection.
+
+### Usage
+
+```bash
+pnpm turbo-run [command]
+```
+
+### turbo-run dev
+
+Quickly execute the `dev` command and provide option-based interactive selection.
diff --git a/eims-ui/docs/src/en/guide/project/dir.md b/eims-ui/docs/src/en/guide/project/dir.md
new file mode 100644
index 0000000..e2747f5
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/dir.md
@@ -0,0 +1,68 @@
+# Directory Explanation
+
+The directory uses Monorepo management, and the project structure is as follows:
+
+```bash
+.
+鈹溾攢鈹� Dockerfile # Docker image build file
+鈹溾攢鈹� README.md # Project documentation
+鈹溾攢鈹� apps # Project applications directory
+鈹偮犅� 鈹溾攢鈹� backend-mock # Backend mock service application
+鈹偮犅� 鈹溾攢鈹� web-antd # Frontend application based on Ant Design Vue
+鈹偮犅� 鈹溾攢鈹� web-ele # Frontend application based on Element Plus
+鈹偮犅� 鈹斺攢鈹� web-naive # Frontend application based on Naive UI
+鈹溾攢鈹� build-local-docker-image.sh # Script for building Docker images locally
+鈹溾攢鈹� cspell.json # CSpell configuration file
+鈹溾攢鈹� docs # Project documentation directory
+鈹溾攢鈹� eslint.config.mjs # ESLint configuration file
+鈹溾攢鈹� internal # Internal tools directory
+鈹偮犅� 鈹溾攢鈹� lint-configs # Code linting configurations
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� commitlint-config # Commitlint configuration
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� eslint-config # ESLint configuration
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� prettier-config # Prettier configuration
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� stylelint-config # Stylelint configuration
+鈹偮犅� 鈹溾攢鈹� node-utils # Node.js tools
+鈹偮犅� 鈹溾攢鈹� tailwind-config # Tailwind configuration
+鈹偮犅� 鈹溾攢鈹� tsconfig # Common tsconfig settings
+鈹偮犅� 鈹斺攢鈹� vite-config # Common Vite configuration
+鈹溾攢鈹� package.json # Project dependency configuration
+鈹溾攢鈹� packages # Project packages directory
+鈹偮犅� 鈹溾攢鈹� @core # Core package
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� base # Base package
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� design # Design related
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� icons # Icons
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� shared # Shared
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹斺攢鈹� typings # Type definitions
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� composables # Composable APIs
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� preferences # Preferences
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� ui-kit # UI component collection
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� layout-ui # Layout UI
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� menu-ui  # Menu UI
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� shadcn-ui # shadcn UI
+鈹偮犅� 鈹偮犅�     鈹斺攢鈹� tabs-ui # Tabs UI
+鈹偮犅� 鈹溾攢鈹� constants # Constants
+鈹偮犅� 鈹溾攢鈹� effects # Effects related packages
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� access # Access control
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� plugins # Plugins
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� common-ui # Common UI
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� hooks # Composable APIs
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� layouts # Layouts
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� request # Request
+鈹偮犅� 鈹溾攢鈹� icons # Icons
+鈹偮犅� 鈹溾攢鈹� locales # Internationalization
+鈹偮犅� 鈹溾攢鈹� preferences  # Preferences
+鈹偮犅� 鈹溾攢鈹� stores # State management
+鈹偮犅� 鈹溾攢鈹� styles # Styles
+鈹偮犅� 鈹溾攢鈹� types # Type definitions
+鈹偮犅� 鈹斺攢鈹� utils # Utilities
+鈹溾攢鈹� playground # Demo directory
+鈹溾攢鈹� pnpm-lock.yaml # pnpm lock file
+鈹溾攢鈹� pnpm-workspace.yaml # pnpm workspace configuration file
+鈹溾攢鈹� scripts # Scripts directory
+鈹偮犅� 鈹溾攢鈹� turbo-run # Turbo run script
+鈹偮犅� 鈹斺攢鈹� vsh # VSH script
+鈹溾攢鈹� stylelint.config.mjs # Stylelint configuration file
+鈹溾攢鈹� turbo.json # Turbo configuration file
+鈹溾攢鈹� vben-admin.code-workspace # VS Code workspace configuration file
+鈹斺攢鈹� vitest.config.ts # Vite configuration file
+```
diff --git a/eims-ui/docs/src/en/guide/project/standard.md b/eims-ui/docs/src/en/guide/project/standard.md
new file mode 100644
index 0000000..23770c5
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/standard.md
@@ -0,0 +1,165 @@
+# Standards
+
+::: tip Contributing Code
+
+- If you want to contribute code to the project, please ensure your code complies with the project's coding standards.
+- If you are using `vscode`, you need to install the following plugins:
+
+  - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Script code checking
+  - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Code formatting
+  - [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - Word syntax checking
+  - [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - CSS formatting
+
+:::
+
+## Purpose
+
+Students with basic engineering literacy always pay attention to coding standards, and code style checking (Code Linting, simply called Lint) is an important means to ensure the consistency of coding standards.
+
+Following the corresponding coding standards has the following benefits:
+
+- Lower bug error rate
+- Efficient development efficiency
+- Higher readability
+
+## Tools
+
+The project's configuration files are located in `internal/lint-configs`, where you can modify various lint configurations.
+
+The project integrates the following code verification tools:
+
+- [ESLint](https://eslint.org/) for JavaScript code checking
+- [Stylelint](https://stylelint.io/) for CSS style checking
+- [Prettier](https://prettier.io/) for code formatting
+- [Commitlint](https://commitlint.js.org/) for checking the standard of git commit messages
+- [Publint](https://publint.dev/) for checking the standard of npm packages
+- [Lint Staged](https://github.com/lint-staged/lint-staged) for running code verification before git commits
+- [Cspell](https://cspell.org/) for checking spelling errors
+
+## ESLint
+
+ESLint is a code standard and error checking tool used to identify and report syntax errors in TypeScript code.
+
+### Command
+
+```bash
+pnpm eslint .
+```
+
+### Configuration
+
+The ESLint configuration file is `eslint.config.mjs`, with its core configuration located in the `internal/lint-configs/eslint-config` directory, which can be modified according to project needs.
+
+## Stylelint
+
+Stylelint is used to check the style of CSS within the project. Coupled with the editor's auto-fix feature, it can effectively unify the CSS style within the project.
+
+### Command
+
+```bash
+pnpm stylelint "**/*.{vue,css,less.scss}"
+```
+
+### Configuration
+
+The Stylelint configuration file is `stylelint.config.mjs`, with its core configuration located in the `internal/lint-configs/stylelint-config` directory, which can be modified according to project needs.
+
+## Prettier
+
+Prettier Can be used to unify project code style, consistent indentation, single and double quotes, trailing commas, and other styles.
+
+### Command
+
+```bash
+pnpm prettier .
+```
+
+### Configuration
+
+The Prettier configuration file is `.prettier.mjs`, with its core configuration located in the `internal/lint-configs/prettier-config` directory, which can be modified according to project needs.
+
+## CommitLint
+
+In a team, everyone's git commit messages can vary widely, making it difficult to ensure standardization without a mechanism. How can standardization be achieved? You might think of using git's hook mechanism to write shell scripts to implement this. Of course, this is possible, but actually, JavaScript has a great tool for implementing this template, which is commitlint (used for verifying the standard of git commit messages).
+
+### Configuration
+
+The CommitLint configuration file is `.commitlintrc.mjs`, with its core configuration located in the `internal/lint-configs/commitlint-config` directory, which can be modified according to project needs.
+
+### Git Commit Standards
+
+Refer to [Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)
+
+- `feat` Add new features
+- `fix` Fix problems/BUGs
+- `style` Code style changes that do not affect the outcome
+- `perf` Optimization/performance improvement
+- `refactor` Refactoring
+- `revert` Revert changes
+- `test` Related to tests
+- `docs` Documentation/comments
+- `chore` Dependency updates/scaffold configuration modifications, etc.
+- `workflow` Workflow improvements
+- `ci` Continuous integration
+- `types` Type modifications
+
+### Disabling Git Commit Standard Checks
+
+If you want to disable Git commit standard checks, there are two ways:
+
+::: code-group
+
+```bash [Temporary disable]
+git commit -m 'feat: add home page' --no-verify
+```
+
+```bash [Permanent closed]
+# Comment out the following code in .husky/commit-msg to disable
+pnpm exec commitlint --edit "$1" # [!code --]
+```
+
+:::
+
+## Publint
+
+Publint is a tool for checking the standard of npm packages, which can check whether the package version conforms to the standard, whether it conforms to the standard ESM package specification, etc.
+
+### Command
+
+```bash
+pnpm vsh publint
+```
+
+## Cspell
+
+Cspell is a tool for checking spelling errors, which can check for spelling errors in the code, avoiding bugs caused by spelling errors.
+
+### Command
+
+```bash
+pnpm cspell lint \"**/*.ts\"  \"**/README.md\" \".changeset/*.md\" --no-progress
+```
+
+### Configuration
+
+The cspell configuration file is `cspell.json`, which can be modified according to project needs.
+
+## Git Hook
+
+Git hooks are generally combined with various lints to check code style during git commits. If the check fails, the commit will not proceed. Developers need to modify and resubmit.
+
+### husky
+
+One issue is that the check will verify all code, but we only want to check the code we are committing. This is where husky comes in.
+
+The most effective solution is to perform Lint checks locally before committing. A common practice is to use husky or pre-commit to perform a Lint check before local submission.
+
+The project defines corresponding hooks inside `.husky`.
+
+#### How to Disable Husky
+
+If you want to disable Husky, simply delete the .husky directory.
+
+### lint-staged
+
+Used for automatically fixing style issues of committed files. Its configuration file is `.lintstagedrc.mjs`, which can be modified according to project needs.
diff --git a/eims-ui/docs/src/en/guide/project/tailwindcss.md b/eims-ui/docs/src/en/guide/project/tailwindcss.md
new file mode 100644
index 0000000..74df1c8
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/tailwindcss.md
@@ -0,0 +1,13 @@
+# Tailwind CSS
+
+[Tailwind CSS](https://tailwindcss.com/) is a utility-first CSS framework for quickly building custom designs.
+
+## Configuration
+
+The project's configuration file is located in `internal/tailwind-config`, where you can modify the Tailwind CSS configuration.
+
+::: tip Restrictions on using tailwindcss in packages
+
+Tailwind CSS compilation will only be enabled if there is a `tailwind.config.mjs` file present in the corresponding package. Otherwise, Tailwind CSS will not be enabled. If you have a pure SDK package that does not require Tailwind CSS, you do not need to create a `tailwind.config.mjs` file.
+
+:::
diff --git a/eims-ui/docs/src/en/guide/project/test.md b/eims-ui/docs/src/en/guide/project/test.md
new file mode 100644
index 0000000..5989c32
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/test.md
@@ -0,0 +1,33 @@
+# Unit Testing
+
+The project incorporates [Vitest](https://vitest.dev/) as the unit testing tool. Vitest is a test runner based on Vite, offering a simple API for writing test cases.
+
+## Writing Test Cases
+
+Within the project, we follow the convention of naming test files with a `.test.ts` suffix or placing them inside a `__tests__` directory. For example, if you create a `utils.ts` file, then you would create a corresponding `utils.spec.ts` file in the same directory,
+
+```ts
+// utils.test.ts
+import { expect, test } from 'vitest';
+import { sum } from './sum';
+
+test('adds 1 + 2 to equal 3', () => {
+  expect(sum(1, 2)).toBe(3);
+});
+```
+
+## Running Tests
+
+To run the tests, execute the following command at the root of the monorepo:
+
+```bash
+pnpm test:unit
+```
+
+## Existing Unit Tests
+
+There are already some unit test cases in the project. You can search for files ending with .test.ts to view them. When you make changes to related code, you can run the unit tests to ensure the correctness of your code. It is recommended to maintain the coverage of unit tests during the development process and to run unit tests as part of the CI/CD process to ensure tests pass before deploying the project.
+
+Existing unit test status:
+
+![](/guide/test.png)
diff --git a/eims-ui/docs/src/en/guide/project/vite.md b/eims-ui/docs/src/en/guide/project/vite.md
new file mode 100644
index 0000000..f458335
--- /dev/null
+++ b/eims-ui/docs/src/en/guide/project/vite.md
@@ -0,0 +1,33 @@
+# Vite Config
+
+The project encapsulates a layer of Vite configuration and integrates some plugins for easy reuse across multiple packages and applications. The usage is as follows:
+
+## Application
+
+```ts
+// vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    // Vite configuration, override according to the official Vite documentation
+    vite: {},
+  };
+});
+```
+
+## Package
+
+```ts
+// vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    library: {},
+    // Vite configuration, override according to the official Vite documentation
+    vite: {},
+  };
+});
+```
diff --git a/eims-ui/docs/src/en/index.md b/eims-ui/docs/src/en/index.md
new file mode 100644
index 0000000..42aeef3
--- /dev/null
+++ b/eims-ui/docs/src/en/index.md
@@ -0,0 +1,76 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+sidebar: false
+
+hero:
+  name: Vben Admin
+  text: Enterprise-Level Management System Framework
+  tagline: Fully Upgraded, Ready to Use, Simple and Efficient
+  image:
+    src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp
+    alt: Vben Admin
+  actions:
+    - theme: brand
+      text: Get Started ->
+      link: /en/guide/introduction/vben
+    - theme: alt
+      text: Live Preview
+      link: https://www.vben.pro
+    - theme: alt
+      text: View on GitHub
+      link: https://github.com/vbenjs/vue-vben-admin
+
+features:
+  - icon: 馃殌
+    title: Latest Technology Stack
+    details: Based on the latest technology stack, including Vue3, Pinia, Vue Router, TypeScript, etc.
+    link: /en/guide/introduction/quick-start
+    linkText: Get Started
+  - icon: 馃
+    title: Rich Configurations
+    details: An enterprise-level frontend solution for middle and back-end systems, offering a wealth of components, templates, and various preference settings.
+    link: /en/guide/essentials/settings
+    linkText: Configuration Documentation
+  - icon: 馃帹
+    title: Theme Customization
+    details: Easily switch between various themes through simple configurations, catering to personalized needs.
+    link: /en/guide/in-depth/theme
+    linkText: Theme Documentation
+  - icon: 馃寪
+    title: Internationalization
+    details: Built-in internationalization support with multiple languages to meet global needs.
+    link: /en/guide/in-depth/locale
+    linkText: Internationalization Documentation
+  - icon: 馃攼
+    title: Access Control
+    details: Built-in access control solutions supporting various permission management methods to meet different access requirements.
+    link: /en/guide/in-depth/access
+    linkText: Access Documentation
+  - title: Vite
+    icon:
+      src: /logos/vite.svg
+    details: Modern frontend build tool with fast cold start and instant hot updates.
+    link: https://vitejs.dev/
+    linkText: Official Site
+  - title: Shadcn UI
+    icon:
+      src: /logos/shadcn-ui.svg
+    details: Core built on Shadcn UI + Tailwindcss, with business support for any UI framework.
+    link: https://www.shadcn-vue.com/
+    linkText: Official Site
+  - title: Turbo Repo
+    icon:
+      src: /logos/turborepo.svg
+    details: Standardized monorepo architecture using pnpm + monorepo + turbo for enterprise-level development standards.
+    link: https://turbo.build/
+    linkText: Official Site
+  - title: Nitro Mock Server
+    icon:
+      src: /logos/nitro.svg
+    details: Built-in Nitro Mock service makes your mock service more powerful.
+    link: https://nitro.unjs.io/
+    linkText: Official Site
+---
+
+<VbenContributors />
diff --git a/eims-ui/docs/src/friend-links/index.md b/eims-ui/docs/src/friend-links/index.md
new file mode 100644
index 0000000..84b6190
--- /dev/null
+++ b/eims-ui/docs/src/friend-links/index.md
@@ -0,0 +1,27 @@
+# 鍙嬫儏閾炬帴
+
+濡傛灉鎮ㄧ殑缃戠珯鏄笌 Vben Admin 鐩稿叧鐨勶紝涔熷睘浜庡紑婧愰」鐩紝娆㈣繋鑱旂郴鎴戜滑锛屾垜浠細灏嗕笌鎮ㄧ殑缃戠珯鍔犲叆浜ゆ崲鍙嬫儏閾炬帴銆�
+
+## 浜ゆ崲鏂瑰紡
+
+### 娣诲姞浣滆�咃紝骞舵敞鏄庢潵鎰�
+
+- 閫氳繃閭鑱旂郴浣滆�咃細 [ann.vben@gmail.com](mailto:ann.vben@gmail.com)
+- 閫氳繃寰俊鑱旂郴浣滆�咃細
+
+ <img src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/wechat.jpg" style="width: 300px;"/>
+
+### 鎻愪緵璧勬枡
+
+鎻愪緵鎮ㄧ殑缃戠珯鍚嶇О銆侀摼鎺ャ�佹弿杩般�丩OGO锛堝彲閫夛級绛変俊鎭紝鎴戜滑浼氬湪绗竴鏃堕棿娣诲姞鎮ㄧ殑缃戠珯銆�
+
+### 鍙嬫儏閾炬帴
+
+- 鍦ㄦ偍鐨勭綉绔欎笂娣诲姞鎴戜滑鐨勫弸鎯呴摼鎺ワ紝閾炬帴濡備笅锛�
+
+  - 鍚嶇О锛歏ben Admin
+  - 閾炬帴锛歨ttps://www.vben.pro
+  - 鎻忚堪锛歏ben Admin 浼佷笟绾у紑绠卞嵆鐢ㄧ殑涓悗鍙板墠绔В鍐虫柟妗�
+  - Logo锛歨ttps://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp
+
+鎴戜滑灏嗗畾鏈熺殑妫�鏌ュ弸鎯呴摼鎺ワ紝濡傛灉鍙戠幇鎮ㄧ殑缃戠珯宸茬粡鍒犻櫎浜嗘垜浠殑鍙嬫儏閾炬帴浠ュ強閾炬帴鍦板潃鏄惁姝g‘銆�
diff --git a/eims-ui/docs/src/guide/essentials/build.md b/eims-ui/docs/src/guide/essentials/build.md
new file mode 100644
index 0000000..ab9828f
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/build.md
@@ -0,0 +1,243 @@
+# 鏋勫缓涓庨儴缃�
+
+::: tip 鍓嶈█
+
+鐢变簬鏄睍绀洪」鐩紝鎵�浠ユ墦鍖呭悗鐩稿杈冨ぇ锛屽鏋滈」鐩腑娌℃湁鐢ㄥ埌鐨勬彃浠讹紝鍙互鍒犻櫎瀵瑰簲鐨勬枃浠舵垨鑰呰矾鐢憋紝涓嶅紩鐢ㄥ嵆鍙紝娌℃湁寮曠敤灏变笉浼氭墦鍖呫��
+
+:::
+
+## 鏋勫缓
+
+椤圭洰寮�鍙戝畬鎴愪箣鍚庯紝鎵ц浠ヤ笅鍛戒护杩涜鏋勫缓锛�
+
+**娉ㄦ剰锛�** 璇峰湪椤圭洰鏍圭洰褰曚笅鎵ц浠ヤ笅鍛戒护
+
+```bash
+pnpm build
+```
+
+鏋勫缓鎵撳寘鎴愬姛涔嬪悗锛屼細鍦ㄦ牴鐩綍鐢熸垚瀵瑰簲鐨勫簲鐢ㄤ笅鐨� `dist` 鏂囦欢澶癸紝閲岄潰灏辨槸鏋勫缓鎵撳寘濂界殑鏂囦欢锛屼緥濡�: `apps/web-antd/dist/`
+
+## 棰勮
+
+鍙戝竷涔嬪墠鍙互鍦ㄦ湰鍦拌繘琛岄瑙堬紝鏈夊绉嶆柟寮忥紝杩欓噷浠嬬粛涓ょ锛�
+
+- 浣跨敤椤圭洰鑷畾鐨勫懡浠よ繘琛岄瑙�(鎺ㄨ崘)
+
+**娉ㄦ剰锛�** 璇峰湪椤圭洰鏍圭洰褰曚笅鎵ц浠ヤ笅鍛戒护
+
+```bash
+pnpm preview
+```
+
+绛夊緟鏋勫缓鎴愬姛鍚庯紝璁块棶 `http://localhost:4173` 鍗冲彲鏌ョ湅鏁堟灉銆�
+
+- 鏈湴鏈嶅姟鍣ㄩ瑙�
+
+鍙互鍦ㄧ數鑴戝叏灞�瀹夎 `serve` 鏈嶅姟锛屽 `live-server`,
+
+```bash
+npm i -g live-server
+```
+
+鐒跺悗鍦� `dist` 鐩綍涓嬫墽琛� `live-server` 鍛戒护锛屽嵆鍙湪鏈湴鏌ョ湅鏁堟灉銆�
+
+```bash
+cd apps/web-antd/dist
+# 鏈湴棰勮锛岄粯璁ょ鍙�8080
+live-server
+# 鎸囧畾绔彛
+live-server --port 9000
+```
+
+## 鍘嬬缉
+
+### 寮�鍚� `gzip` 鍘嬬缉
+
+闇�瑕佸湪鎵撳寘鐨勬椂鍊欐洿鏀筦.env.production`閰嶇疆:
+
+```bash
+VITE_COMPRESS=gzip
+```
+
+### 寮�鍚� `brotli` 鍘嬬缉
+
+闇�瑕佸湪鎵撳寘鐨勬椂鍊欐洿鏀筦.env.production`閰嶇疆:
+
+```bash
+VITE_COMPRESS=brotli
+```
+
+### 鍚屾椂寮�鍚� `gzip` 鍜� `brotli` 鍘嬬缉
+
+闇�瑕佸湪鎵撳寘鐨勬椂鍊欐洿鏀筦.env.production`閰嶇疆:
+
+```bash
+VITE_COMPRESS=gzip,brotli
+```
+
+::: tip 鎻愮ず
+
+`gzip` 鍜� `brotli` 閮介渶瑕佸畨瑁呯壒瀹氭ā鍧楁墠鑳戒娇鐢ㄣ��
+
+:::
+
+::: details gzip 涓� brotli 鍦� nginx 鍐呯殑閰嶇疆
+
+```bash
+http {
+  # 寮�鍚痝zip
+  gzip on;
+  # 寮�鍚痝zip_static
+  # gzip_static 寮�鍚悗鍙兘浼氭姤閿欙紝闇�瑕佸畨瑁呯浉搴旂殑妯″潡, 鍏蜂綋瀹夎鏂瑰紡鍙互鑷鏌ヨ
+  # 鍙湁杩欎釜寮�鍚紝vue鏂囦欢鎵撳寘鐨�.gz鏂囦欢鎵嶄細鏈夋晥鏋滐紝鍚﹀垯涓嶉渶瑕佸紑鍚痝zip杩涜鎵撳寘
+  gzip_static on;
+  gzip_proxied any;
+  gzip_min_length 1k;
+  gzip_buffers 4 16k;
+  #濡傛灉nginx涓娇鐢ㄤ簡澶氬眰浠g悊 蹇呴』璁剧疆杩欎釜鎵嶅彲浠ュ紑鍚痝zip銆�
+  gzip_http_version 1.0;
+  gzip_comp_level 2;
+  gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
+  gzip_vary off;
+  gzip_disable "MSIE [1-6]\.";
+
+  # 寮�鍚� brotli鍘嬬缉
+  # 闇�瑕佸畨瑁呭搴旂殑nginx妯″潡,鍏蜂綋瀹夎鏂瑰紡鍙互鑷鏌ヨ
+  # 鍙互涓巊zip鍏卞瓨涓嶄細鍐茬獊
+  brotli on;
+  brotli_comp_level 6;
+  brotli_buffers 16 8k;
+  brotli_min_length 20;
+  brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
+}
+```
+
+:::
+
+## 鏋勫缓鍒嗘瀽
+
+濡傛灉浣犵殑鏋勫缓鏂囦欢寰堝ぇ锛屽彲浠ラ�氳繃椤圭洰鍐呯疆 [rollup-plugin-analyzer](https://github.com/doesdev/rollup-plugin-analyzer) 鎻掍欢杩涜浠g爜浣撶Н鍒嗘瀽锛屼粠鑰屼紭鍖栦綘鐨勪唬鐮併�傚彧闇�瑕佸湪`鏍圭洰褰昤涓嬫墽琛屼互涓嬪懡浠わ細
+
+```bash
+pnpm run build:analyze
+```
+
+杩愯涔嬪悗锛屽湪鑷姩鎵撳紑鐨勯〉闈㈠彲浠ョ湅鍒板叿浣撶殑浣撶Н鍒嗗竷锛屼互鍒嗘瀽鍝簺渚濊禆鏈夐棶棰樸��
+
+![Build analysis report](/guide/report.png)
+
+## 閮ㄧ讲
+
+绠�鍗曠殑閮ㄧ讲鍙渶瑕佸皢鏈�缁堢敓鎴愮殑闈欐�佹枃浠讹紝dist 鏂囦欢澶圭殑闈欐�佹枃浠跺彂甯冨埌浣犵殑 cdn 鎴栬�呴潤鎬佹湇鍔″櫒鍗冲彲锛岄渶瑕佹敞鎰忕殑鏄叾涓殑 index.html 閫氬父浼氭槸浣犲悗鍙版湇鍔$殑鍏ュ彛椤甸潰锛屽湪纭畾浜� js 鍜� css 鐨勯潤鎬佷箣鍚庡彲鑳介渶瑕佹敼鍙橀〉闈㈢殑寮曞叆璺緞銆�
+
+渚嬪涓婁紶鍒� nginx 鏈嶅姟鍣紝鍙互灏� dist 鏂囦欢澶逛笅鐨勬枃浠朵笂浼犲埌鏈嶅姟鍣ㄧ殑 `/srv/www/project/index.html` 鐩綍涓嬶紝鐒跺悗璁块棶閰嶇疆濂界殑鍩熷悕鍗冲彲銆�
+
+```bash
+# nginx閰嶇疆
+location / {
+  # 涓嶇紦瀛榟tml锛岄槻姝㈢▼搴忔洿鏂板悗缂撳瓨缁х画鐢熸晥
+  if ($request_filename ~* .*\.(?:htm|html)$) {
+    add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
+    access_log on;
+  }
+  # 杩欓噷鏄痸ue鎵撳寘鏂囦欢dist鍐呯殑鏂囦欢鐨勫瓨鏀捐矾寰�
+  root   /srv/www/project/;
+  index  index.html index.htm;
+}
+```
+
+閮ㄧ讲鏃跺彲鑳戒細鍙戠幇璧勬簮璺緞涓嶅锛屽彧闇�瑕佷慨鏀筦.env.production`鏂囦欢鍗冲彲銆�
+
+```bash
+# 鏍规嵁鑷繁璺緞鏉ラ厤缃洿鏀�
+# 娉ㄦ剰闇�瑕佷互 / 寮�澶村拰缁撳熬
+VITE_BASE=/
+VITE_BASE=/xxx/
+```
+
+### 鍓嶇璺敱涓庢湇鍔$鐨勭粨鍚�
+
+椤圭洰鍓嶇璺敱浣跨敤鐨勬槸 vue-router锛屾墍浠ヤ綘鍙互閫夋嫨涓ょ鏂瑰紡锛歨istory 鍜� hash銆�
+
+- `hash` 榛樿浼氬湪 url 鍚庨潰鎷兼帴`#`
+- `history` 鍒欎笉浼氾紝涓嶈繃 `history` 闇�瑕佹湇鍔″櫒閰嶅悎
+
+鍙湪 `.env.production` 鍐呰繘琛� mode 淇敼
+
+```bash
+VITE_ROUTER_HISTORY=hash
+```
+
+### history 璺敱妯″紡涓嬫湇鍔$閰嶇疆
+
+寮�鍚� `history` 妯″紡闇�瑕佹湇鍔″櫒閰嶇疆锛屾洿澶氱殑鏈嶅姟鍣ㄩ厤缃鎯呭彲浠ョ湅 [history-mode](https://router.vuejs.org/guide/essentials/history-mode.html#html5-mode)
+
+杩欓噷浠� `nginx` 閰嶇疆涓轰緥锛�
+
+#### 閮ㄧ讲鍒版牴鐩綍
+
+```bash {5}
+server {
+  listen 80;
+  location / {
+    # 鐢ㄤ簬閰嶅悎 History 浣跨敤
+    try_files $uri $uri/ /index.html;
+  }
+}
+```
+
+#### 閮ㄧ讲鍒伴潪鏍圭洰褰�
+
+- 棣栧厛闇�瑕佸湪鎵撳寘鐨勬椂鍊欐洿鏀筦.env.production`閰嶇疆:
+
+```bash
+VITE_BASE = /sub/
+```
+
+- 鐒跺悗鍦� nginx 閰嶇疆鏂囦欢涓厤缃�
+
+```bash {8}
+server {
+    listen       80;
+    server_name  localhost;
+    location /sub/ {
+      # 杩欓噷鏄痸ue鎵撳寘鏂囦欢dist鍐呯殑鏂囦欢鐨勫瓨鏀捐矾寰�
+      alias   /srv/www/project/;
+      index index.html index.htm;
+      try_files $uri $uri/ /sub/index.html;
+    }
+}
+```
+
+## 璺ㄥ煙澶勭悊
+
+浣跨敤 nginx 澶勭悊椤圭洰閮ㄧ讲鍚庣殑璺ㄥ煙闂
+
+1. 閰嶇疆鍓嶇椤圭洰鎺ュ彛鍦板潃锛屽湪椤圭洰鐩綍涓嬬殑``.env.production`鏂囦欢涓厤缃細
+
+```bash
+VITE_GLOB_API_URL=/api
+```
+
+2. 鍦� nginx 閰嶇疆璇锋眰杞彂鍒板悗鍙�
+
+```bash {10-11}
+server {
+  listen       8080;
+  server_name  localhost;
+  # 鎺ュ彛浠g悊锛岀敤浜庤В鍐宠法鍩熼棶棰�
+  location /api {
+    proxy_set_header Host $host;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    # 鍚庡彴鎺ュ彛鍦板潃
+    proxy_pass http://110.110.1.1:8080/api;
+    rewrite "^/api/(.*)$" /$1 break;
+    proxy_redirect default;
+    add_header Access-Control-Allow-Origin *;
+    add_header Access-Control-Allow-Headers X-Requested-With;
+    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
+  }
+}
+```
diff --git a/eims-ui/docs/src/guide/essentials/concept.md b/eims-ui/docs/src/guide/essentials/concept.md
new file mode 100644
index 0000000..8f9d8b5
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/concept.md
@@ -0,0 +1,70 @@
+# 鍩虹姒傚康
+
+鏂扮増鏈腑锛屾暣浣撳伐绋嬭繘琛屼簡閲嶆瀯锛岀幇鍦ㄦ垜浠皢浼氫粙缁嶄竴浜涘熀纭�姒傚康锛屼互渚夸簬浣犳洿濂界殑鐞嗚В鏁翠釜鏂囨。銆傝鍔″繀浠旂粏闃呰杩欎竴閮ㄥ垎銆�
+
+## 澶т粨
+
+澶т粨鎸囩殑鏄暣涓」鐩殑浠撳簱锛屽寘鍚簡鎵�鏈夌殑浠g爜銆佸寘銆佸簲鐢ㄣ�佽鑼冦�佹枃妗c�侀厤缃瓑锛屼篃灏辨槸涓�鏁翠釜 `Monorepo` 鐩綍鐨勬墍鏈夊唴瀹广��
+
+## 搴旂敤
+
+搴旂敤鎸囩殑鏄竴涓畬鏁寸殑椤圭洰锛屼竴涓」鐩彲浠ュ寘鍚涓簲鐢紝杩欎簺椤圭洰鍙互澶嶇敤澶т粨鍐呯殑浠g爜銆佸寘銆佽鑼冪瓑銆傚簲鐢ㄩ兘琚斁缃湪 `apps` 鐩綍涓嬨�傛瘡涓簲鐢ㄩ兘鏄嫭绔嬬殑锛屽彲浠ュ崟鐙繍琛屻�佹瀯寤恒�佹祴璇曘�侀儴缃诧紝鍙互寮曞叆涓嶅悓鐨勭粍浠跺簱绛夌瓑銆�
+
+::: tip
+
+搴旂敤涓嶉檺浜庡墠绔簲鐢紝涔熷彲浠ユ槸鍚庣搴旂敤銆佺Щ鍔ㄧ搴旂敤绛夛紝渚嬪 `apps/backend-mock`灏辨槸涓�涓悗绔湇鍔°��
+
+:::
+
+## 鍖�
+
+鍖呮寚鐨勬槸涓�涓嫭绔嬬殑妯″潡锛屽彲浠ユ槸涓�涓粍浠躲�佷竴涓伐鍏枫�佷竴涓簱绛夈�傚寘鍙互琚涓簲鐢ㄥ紩鐢紝涔熷彲浠ヨ鍏朵粬鍖呭紩鐢ㄣ�傚寘閮借鏀剧疆鍦� `packages` 鐩綍涓嬨��
+
+瀵逛簬杩欎簺鍖咃紝浣犲彲浠ユ妸瀹冪湅浣滄槸涓�涓嫭绔嬬殑 `npm` 鍖咃紝浣跨敤鏂瑰紡涓� `npm` 鍖呬竴鏍枫��
+
+### 鍖呭紩鍏�
+
+鍦� `package.json` 涓紩鍏ュ寘锛�
+
+```json {3}
+{
+  "dependencies": {
+    "@vben/utils": "workspace:*"
+  }
+}
+```
+
+### 鍖呬娇鐢�
+
+鍦ㄤ唬鐮佷腑寮曞叆鍖咃細
+
+```ts
+import { isString } from '@vben/utils';
+```
+
+## 鍒悕
+
+鍦ㄩ」鐩腑锛屼綘鍙互鐪嬪埌涓�浜� `#` 寮�澶寸殑璺緞锛屼緥濡傦細 `#/api`銆乣#/views`, 杩欎簺璺緞閮芥槸鍒悕锛岀敤浜庡揩閫熷畾浣嶅埌鏌愪釜鐩綍銆傚畠涓嶆槸閫氳繃 `vite` 鐨� `alias` 瀹炵幇鐨勶紝鑰屾槸閫氳繃 `Node.js` 鏈韩鐨� [subpath imports](https://nodejs.org/api/packages.html#subpath-imports) 鍘熺悊銆傚彧闇�瑕佸湪 `package.json` 涓厤缃� `imports` 瀛楁鍗冲彲銆�
+
+```json {3}
+{
+  "imports": {
+    "#/*": "./src/*"
+  }
+}
+```
+
+涓轰簡 IDE 鑳藉璇嗗埆杩欎簺鍒悕锛屾垜浠繕闇�瑕佸湪`tsconfig.json`鍐呴厤缃細
+
+```json {5}
+{
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["src/*"]
+    }
+  }
+}
+```
+
+杩欐牱锛屼綘灏卞彲浠ュ湪浠g爜涓娇鐢ㄥ埆鍚嶄簡銆�
diff --git a/eims-ui/docs/src/guide/essentials/development.md b/eims-ui/docs/src/guide/essentials/development.md
new file mode 100644
index 0000000..556e4c9
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/development.md
@@ -0,0 +1,188 @@
+# 鏈湴寮�鍙� {#development}
+
+::: tip 浠g爜鑾峰彇
+
+濡傛灉浣犺繕娌℃湁鑾峰彇浠g爜锛屽彲浠ュ厛浠� [蹇�熷紑濮媇(../introduction/quick-start.md) 澶勫紑濮嬮槄璇绘枃妗c��
+
+:::
+
+## 鍓嶇疆鍑嗗
+
+涓轰簡鏇村ソ鐨勫紑鍙戜綋楠岋紝鎴戜滑鎻愪緵浜嗕竴浜涘伐鍏烽厤缃�侀」鐩鏄庯紝浠ヤ究浜庢偍鏇村ソ鐨勫紑鍙戙��
+
+### 闇�瑕佹帉鎻$殑鍩虹鐭ヨ瘑
+
+鏈」鐩渶瑕佷竴瀹氬墠绔熀纭�鐭ヨ瘑锛岃纭繚鎺屾彙 Vue 鐨勫熀纭�鐭ヨ瘑锛屼互渚胯兘澶勭悊涓�浜涘父瑙佺殑闂銆傚缓璁湪寮�鍙戝墠鍏堝涓�涓嬩互涓嬪唴瀹癸紝鎻愬墠浜嗚В鍜屽涔犺繖浜涚煡璇嗭紝浼氬椤圭洰鐞嗚В闈炲父鏈夊府鍔�:
+
+- [Vue3](https://vuejs.org/)
+- [Tailwind CSS](https://tailwindcss.com/)
+- [TypeScript](https://www.typescriptlang.org/)
+- [Vue Router](https://router.vuejs.org/)
+- [Vitejs](https://vitejs.dev/)
+- [Pnpm](https://pnpm.io/)
+- [Turbo](https://turbo.build/)
+
+### 宸ュ叿閰嶇疆
+
+濡傛灉鎮ㄤ娇鐢ㄧ殑 IDE 鏄痆vscode](https://code.visualstudio.com/)(鎺ㄨ崘)鐨勮瘽锛屽彲浠ュ畨瑁呬互涓嬪伐鍏锋潵鎻愰珮寮�鍙戞晥鐜囧強浠g爜鏍煎紡鍖�:
+
+- [Vue - Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) - Vue 瀹樻柟鎻掍欢锛堝繀澶囷級銆�
+- [Tailwind CSS](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - Tailwindcss 鎻愮ず鎻掍欢銆�
+- [CSS Variable Autocomplete](https://marketplace.visualstudio.com/items?itemName=bradlc.vunguyentuan.vscode-css-variables) - Css 鍙橀噺鎻愮ず鎻掍欢銆�
+- [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) - Iconify 鍥炬爣鎻掍欢
+- [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) - i18n 鎻掍欢
+- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - 鑴氭湰浠g爜妫�鏌�
+- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 浠g爜鏍煎紡鍖�
+- [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - css 鏍煎紡鍖�
+- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 鍗曡瘝璇硶妫�鏌�
+- [DotENV](https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv) - .env 鏂囦欢 楂樹寒
+
+## Npm Scripts
+
+npm 鑴氭湰鏄」鐩父瑙佺殑閰嶇疆锛岀敤浜庢墽琛屼竴浜涘父瑙佺殑浠诲姟锛屾瘮濡傚惎鍔ㄩ」鐩�佹墦鍖呴」鐩瓑銆備互涓嬬殑鑴氭湰閮藉彲浠ュ湪椤圭洰鏍圭洰褰曠殑 `package.json` 鏂囦欢涓壘鍒般��
+
+鎵ц鏂瑰紡涓猴細`pnpm run [script]` 鎴� `npm run [script]`銆�
+
+```json
+{
+  "scripts": {
+    // 鏋勫缓椤圭洰
+    "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
+    // 鏋勫缓椤圭洰骞跺垎鏋�
+    "build:analyze": "turbo build:analyze",
+    // 鏋勫缓鏈湴 docker 闀滃儚
+    "build:docker": "./build-local-docker-image.sh",
+    // 鍗曠嫭鏋勫缓 web-antd 搴旂敤
+    "build:antd": "pnpm run build --filter=@vben/web-antd",
+    // 鍗曠嫭鏋勫缓鏂囨。
+    "build:docs": "pnpm run build --filter=@vben/docs",
+    // 鍗曠嫭鏋勫缓 web-ele 搴旂敤
+    "build:ele": "pnpm run build --filter=@vben/web-ele",
+    // 鍗曠嫭鏋勫缓 web-naive 搴旂敤
+    "build:naive": "pnpm run build --filter=@vben/naive",
+    // 鍗曠嫭鏋勫缓 playground 搴旂敤
+    "build:play": "pnpm run build --filter=@vben/playground",
+    // changeset 鐗堟湰绠$悊
+    "changeset": "pnpm exec changeset",
+    // 妫�鏌ラ」鐩悇绉嶉棶棰�
+    "check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell",
+    // 妫�鏌ュ惊鐜紩鐢�
+    "check:circular": "vsh check-circular",
+    // 妫�鏌ユ嫾鍐�
+    "check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress"
+    // 妫�鏌ヤ緷璧�
+    "check:dep": "vsh check-dep",
+    // 妫�鏌ョ被鍨�
+    "check:type": "turbo run typecheck",
+    // 娓呯悊椤圭洰锛堝垹闄ode_modules銆乨ist銆�.turbo锛夌瓑鐩綍
+    "clean": "node ./scripts/clean.mjs",
+    // 鎻愪氦浠g爜
+    "commit": "czg",
+    // 鍚姩椤圭洰锛堥粯璁や細杩愯鏁翠釜浠撳簱鎵�鏈夊寘鐨刣ev鑴氭湰锛�
+    "dev": "turbo-run dev",
+    // 鍚姩web-antd搴旂敤
+    "dev:antd": "pnpm -F @vben/web-antd run dev",
+    // 鍚姩鏂囨。
+    "dev:docs": "pnpm -F @vben/docs run dev",
+    // 鍚姩web-ele搴旂敤
+    "dev:ele": "pnpm -F @vben/web-ele run dev",
+    // 鍚姩web-naive搴旂敤
+    "dev:naive": "pnpm -F @vben/web-naive run dev",
+    // 鍚姩婕旂ず搴旂敤
+    "dev:play": "pnpm -F @vben/playground run dev",
+    // 鏍煎紡鍖栦唬鐮�
+    "format": "vsh lint --format",
+    // lint 浠g爜
+    "lint": "vsh lint",
+    // 渚濊禆瀹夎瀹屾垚涔嬪悗锛屾墽琛屾墍鏈夊寘鐨剆tub鑴氭湰
+    "postinstall": "pnpm -r run stub --if-present",
+    // 鍙厑璁镐娇鐢╬npm
+    "preinstall": "npx only-allow pnpm",
+    // husky鐨勫畨瑁�
+    "prepare": "is-ci || husky",
+    // 棰勮搴旂敤
+    "preview": "turbo-run preview",
+    // 鍖呰鑼冩鏌�
+    "publint": "vsh publint",
+    // 鍒犻櫎鎵�鏈夌殑node_modules銆亂arn.lock銆乸ackage.lock.json锛岄噸鏂板畨瑁呬緷璧�
+    "reinstall": "pnpm clean --del-lock && pnpm install",
+    // 杩愯 vitest 鍗曞厓娴嬭瘯
+    "test:unit": "vitest run --dom",
+    // 鏇存柊椤圭洰渚濊禆
+    "update:deps": " pnpm update --latest --recursive",
+    // changeset鐢熸垚鎻愪氦闆�
+    "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
+  }
+}
+```
+
+## 鏈湴杩愯椤圭洰
+
+濡傞渶鏈湴杩愯鏂囨。锛屽苟杩涜璋冩暣锛屽彲浠ユ墽琛屼互涓嬪懡浠わ紝鎵ц璇ュ懡浠わ紝浣犲彲浠ラ�夋嫨闇�瑕佺殑搴旂敤杩涜寮�鍙戯細
+
+```bash
+pnpm dev
+```
+
+濡傛灉浣犳兂鐩存帴杩愯鏌愪釜搴旂敤锛屽彲浠ユ墽琛屼互涓嬪懡浠わ細
+
+杩愯 `web-antd` 搴旂敤锛�
+
+```bash
+pnpm dev:antd
+```
+
+杩愯 `web-naive` 搴旂敤锛�
+
+```bash
+pnpm dev:naive
+```
+
+杩愯 `web-ele` 搴旂敤锛�
+
+```bash
+pnpm dev:ele
+```
+
+杩愯 `docs` 搴旂敤锛�
+
+```bash
+pnpm dev:docs
+```
+
+## 鍏叡闈欐�佽祫婧�
+
+椤圭洰涓渶瑕佷娇鐢ㄥ埌鐨勫叕鍏遍潤鎬佽祫婧愶紝濡傦細鍥剧墖銆侀潤鎬丠TML绛夛紝闇�瑕佸湪寮�鍙戜腑閫氳繃 `src="/xxx.png"` 鐩存帴寮曞叆鐨勩��
+
+闇�瑕佸皢璧勬簮鏀惧湪瀵瑰簲椤圭洰鐨� `public/static` 鐩綍涓嬨�傚紩鍏ョ殑璺緞涓猴細`src="/static/xxx.png"`銆�
+
+## DevTools
+
+椤圭洰鍐呯疆浜� [Vue DevTools](https://github.com/vuejs/devtools-next) 鎻掍欢锛屽彲浠ュ湪寮�鍙戣繃绋嬩腑浣跨敤銆傞粯璁ゅ叧闂紝鍙湪`.env.development` 鍐呭紑鍚紝骞堕噸鏂拌繍琛岄」鐩嵆鍙細
+
+```bash
+VITE_DEVTOOLS=true
+```
+
+寮�鍚悗锛岄」鐩繍琛屼細鍦ㄩ〉闈㈠簳閮ㄦ樉绀轰竴涓� Vue DevTools 鐨勫浘鏍囷紝鐐瑰嚮鍗冲彲鎵撳紑 DevTools銆�
+
+![Vue DevTools](/guide/devtools.png)
+
+## 鏈湴杩愯鏂囨。
+
+濡傞渶鏈湴杩愯鏂囨。锛屽苟杩涜璋冩暣锛屽彲浠ユ墽琛屼互涓嬪懡浠わ細
+
+```bash
+pnpm dev:docs
+```
+
+## 闂瑙e喅
+
+濡傛灉浣犲湪浣跨敤杩囩▼涓亣鍒颁緷璧栫浉鍏崇殑闂锛屽彲浠ュ皾璇曚互涓嬮噸鏂板畨瑁呬緷璧栵細
+
+```bash
+# 璇峰湪椤圭洰鏍圭洰褰曚笅鎵ц
+# 璇ュ懡浠や細鍒犻櫎鏁翠釜浠撳簱鎵�鏈夌殑 node_modules銆亂arn.lock銆乸ackage.lock.json鍚�
+# 鍐嶈繘琛屼緷璧栭噸鏂板畨瑁咃紙瀹夎閫熷害浼氭槑鏄惧彉鎱級銆�
+pnpm reinstall
+```
diff --git a/eims-ui/docs/src/guide/essentials/external-module.md b/eims-ui/docs/src/guide/essentials/external-module.md
new file mode 100644
index 0000000..fd8e592
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/external-module.md
@@ -0,0 +1,58 @@
+# 澶栭儴妯″潡
+
+闄や簡椤圭洰榛樿寮曞叆鐨勫閮ㄦā鍧楋紝鏈夋椂鎴戜滑杩橀渶瑕佸紩鍏ュ叾浠栧閮ㄦā鍧椼�傛垜浠互 [ant-design-vue](https://antdv.com/components/overview) 涓轰緥锛�
+
+## 瀹夎渚濊禆
+
+::: tip 瀹夎渚濊禆鍒版寚瀹氬寘
+
+- 鐢变簬椤圭洰閲囩敤浜� [pnpm](https://pnpm.io/) 浣滀负鍖呯鐞嗗伐鍏凤紝鎵�浠ユ垜浠渶瑕佷娇鐢� `pnpm` 鍛戒护鏉ュ畨瑁呬緷璧栥��
+- 閫氳繃閲囩敤浜� Monorepo 妯″潡鏉ョ鐞嗛」鐩紝鎵�浠ユ垜浠渶瑕佸湪鎸囧畾鍖呬笅瀹夎渚濊禆銆傚畨瑁呬緷璧栧墠璇风‘淇濆凡缁忚繘鍏ュ埌鎸囧畾鍖呯洰褰曚笅銆�
+
+:::
+
+```bash
+# cd /path/to/your/package
+pnpm add ant-design-vue
+```
+
+## 浣跨敤
+
+### 鍏ㄥ眬寮曞叆
+
+```ts
+import { createApp } from 'vue';
+import Antd from 'ant-design-vue';
+import App from './App';
+import 'ant-design-vue/dist/reset.css';
+
+const app = createApp(App);
+
+app.use(Antd).mount('#app');
+```
+
+#### 浣跨敤
+
+```vue
+<template>
+  <a-button>text</a-button>
+</template>
+```
+
+### 灞�閮ㄥ紩鍏�
+
+```vue
+<script setup lang="ts">
+import { Button } from 'ant-design-vue';
+</script>
+
+<template>
+  <Button>text</Button>
+</template>
+```
+
+::: warning 娉ㄦ剰
+
+- 濡傛灉缁勪欢鏈変緷璧栨牱寮忥紝鍒欓渶瑕佸啀寮曞叆鏍峰紡鏂囦欢
+
+:::
diff --git a/eims-ui/docs/src/guide/essentials/icons.md b/eims-ui/docs/src/guide/essentials/icons.md
new file mode 100644
index 0000000..db4f01d
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/icons.md
@@ -0,0 +1,78 @@
+# 鍥炬爣
+
+::: tip 鍏充簬鍥炬爣鐨勭鐞�
+
+- 椤圭洰鐨勫浘鏍囦富瑕佺敱`@vben/icons`鍖呮彁渚涳紝寤鸿缁熶竴鍦ㄨ鍖呭唴閮ㄧ鐞嗭紝浠ヤ究浜庣粺涓�绠$悊鍜岀淮鎶ゃ��
+- 濡傛灉浣犱娇鐢ㄧ殑鏄� `Vscode`锛屾帹鑽愬畨瑁� [Iconify IntelliSense](https://marketplace.visualstudio.com/items?itemName=antfu.iconify) 鎻掍欢锛屽彲浠ユ柟渚跨殑鏌ユ壘鍜屼娇鐢ㄥ浘鏍囥��
+
+:::
+
+椤圭洰涓湁浠ヤ笅澶氱鍥炬爣浣跨敤鏂瑰紡锛屽彲浠ユ牴鎹疄闄呮儏鍐甸�夋嫨浣跨敤锛�
+
+## Iconify 鍥炬爣 <Badge text="鎺ㄨ崘" type="tip"/>
+
+闆嗘垚浜� [iconify](https://github.com/iconify/iconify) 鍥炬爣搴�
+
+### 鏂板
+
+鍙湪 `packages/icons/src/iconify` 鐩綍涓嬫柊澧炲浘鏍囷細
+
+```ts
+// packages/icons/src/iconify/index.ts
+import { createIconifyIcon } from '@vben-core/icons';
+
+export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
+```
+
+### 浣跨敤
+
+```vue
+<script setup lang="ts">
+import { MdiKeyboardEsc } from '@vben/icons';
+</script>
+
+<template>
+  <!-- 涓�涓楂樹负20px鐨勫浘鏍� -->
+  <MdiKeyboardEsc class="size-5" />
+</template>
+```
+
+## Svg 鍥炬爣 <Badge text="鎺ㄨ崘" type="tip"/>
+
+娌℃湁閲囩敤 Svg Sprite 鐨勬柟寮忥紝鑰屾槸鐩存帴寮曞叆 Svg 鍥炬爣锛�
+
+### 鏂板
+
+鍙互鍦� `packages/icons/src/svg/icons` 鐩綍涓嬫柊澧炲浘鏍囨枃浠禶test.svg`, 鐒跺悗鍦� `packages/icons/src/svg/index.ts` 涓紩鍏ワ細
+
+```ts
+// packages/icons/src/svg/index.ts
+import { createIconifyIcon } from '@vben-core/icons';
+
+const SvgTestIcon = createIconifyIcon('svg:test');
+
+export { SvgTestIcon };
+```
+
+### 浣跨敤
+
+```vue
+<script setup lang="ts">
+import { SvgTestIcon } from '@vben/icons';
+</script>
+
+<template>
+  <!-- 涓�涓楂樹负20px鐨勫浘鏍� -->
+  <SvgTestIcon class="size-5" />
+</template>
+```
+
+## Tailwind CSS 鍥炬爣
+
+### 浣跨敤
+
+鐩存帴娣诲姞 Tailwind CSS 鐨勫浘鏍囩被鍚嶅嵆鍙娇鐢紝鍥炬爣绫诲悕鍙煡鐪� [iconify](https://github.com/iconify/iconify) 锛�
+
+```vue
+<span class="icon-[mdi--ab-testing]"></span>
+```
diff --git a/eims-ui/docs/src/guide/essentials/route.md b/eims-ui/docs/src/guide/essentials/route.md
new file mode 100644
index 0000000..0eb74ae
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/route.md
@@ -0,0 +1,600 @@
+---
+outline: deep
+---
+
+# 璺敱鍜岃彍鍗�
+
+鍦ㄩ」鐩腑锛屾鏋舵彁渚涗簡涓�濂楀熀纭�鐨勮矾鐢辩郴缁燂紝骞�**鏍规嵁璺敱鏂囦欢鑷姩鐢熸垚瀵瑰簲鐨勮彍鍗曠粨鏋�**銆�
+
+## 璺敱绫诲瀷
+
+璺敱鍒嗕负鏍稿績璺敱銆侀潤鎬佽矾鐢卞拰鍔ㄦ�佽矾鐢憋紝鏍稿績璺敱鏄鏋跺唴缃殑璺敱锛屽寘鍚簡鏍硅矾鐢便�佺櫥褰曡矾鐢便��404璺敱绛夛紱闈欐�佽矾鐢辨槸鍦ㄩ」鐩惎鍔ㄦ椂灏卞凡缁忕‘瀹氱殑璺敱锛涘姩鎬佽矾鐢变竴鑸槸鍦ㄧ敤鎴风櫥褰曞悗锛屾牴鎹敤鎴风殑鏉冮檺鍔ㄦ�佺敓鎴愮殑璺敱銆�
+
+闈欐�佽矾鐢卞拰鍔ㄦ�佽矾鐢遍兘浼氳蛋鏉冮檺鎺у埗锛屽彲浠ラ�氳繃閰嶇疆璺敱鐨� `meta` 灞炴�т腑鐨� `authority` 瀛楁鏉ユ帶鍒舵潈闄愶紝鍙互鍙傝�僛璺敱鏉冮檺鎺у埗](https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/router/routes/modules/demos.ts)銆�
+
+### 鏍稿績璺敱
+
+鏍稿績璺敱鏄鏋跺唴缃殑璺敱锛屽寘鍚簡鏍硅矾鐢便�佺櫥褰曡矾鐢便��404璺敱绛夛紝鏍稿績璺敱鐨勯厤缃湪搴旂敤涓� `src/router/routes/core` 鐩綍涓�
+
+::: tip
+
+鏍稿績璺敱涓昏鐢ㄤ簬妗嗘灦鐨勫熀纭�鍔熻兘锛屽洜姝や笉寤鸿灏嗕笟鍔$浉鍏崇殑璺敱鏀惧湪鏍稿績璺敱涓紝鎺ㄨ崘灏嗕笟鍔$浉鍏崇殑璺敱鏀惧湪闈欐�佽矾鐢辨垨鍔ㄦ�佽矾鐢变腑銆�
+
+:::
+
+### 闈欐�佽矾鐢�
+
+闈欐�佽矾鐢辩殑閰嶇疆鍦ㄥ簲鐢ㄤ笅 `src/router/routes/index` 鐩綍涓嬶紝鎵撳紑娉ㄩ噴鐨勬枃浠跺唴瀹�:
+
+::: tip
+
+鏉冮檺鎺у埗鏄�氳繃璺敱鐨� `meta` 灞炴�т腑鐨� `authority` 瀛楁鏉ユ帶鍒剁殑锛屽鏋滀綘鐨勯〉闈㈤」鐩笉闇�瑕佹潈闄愭帶鍒讹紝鍙互涓嶈缃� `authority` 瀛楁銆�
+
+:::
+
+```ts
+// 鏈夐渶瑕佸彲浠ヨ嚜琛屾墦寮�娉ㄩ噴锛屽苟鍒涘缓鏂囦欢澶�
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true }); // [!code --]
+const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true }); // [!code ++]
+/** 鍔ㄦ�佽矾鐢� */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 澶栭儴璺敱鍒楄〃锛岃闂繖浜涢〉闈㈠彲浠ヤ笉闇�瑕丩ayout锛屽彲鑳界敤浜庡唴宓屽湪鍒殑绯荤粺 */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles) // [!code --]
+const externalRoutes: RouteRecordRaw[] = []; // [!code --]
+const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles); // [!code ++]
+```
+
+### 鍔ㄦ�佽矾鐢�
+
+鍔ㄦ�佽矾鐢辩殑閰嶇疆鍦ㄥ搴斿簲鐢� `src/router/routes/modules` 鐩綍涓嬶紝杩欎釜鐩綍涓嬪瓨鏀句簡鎵�鏈夌殑璺敱鏂囦欢銆傛瘡涓枃浠剁殑鍐呭鏍煎紡濡備笅锛屼笌 Vue Router 鐨勮矾鐢遍厤缃牸寮忎竴鑷达紝浠ヤ笅涓轰簩绾ц矾鐢卞拰澶氱骇璺敱鐨勯厤缃��
+
+## 璺敱瀹氫箟
+
+闈欐�佽矾鐢变笌鍔ㄦ�佽矾鐢辩殑閰嶇疆鏂瑰紡涓�鑷达紝浠ヤ笅涓轰簩绾ц矾鐢卞拰澶氱骇璺敱鐨勯厤缃細
+
+### 浜岀骇璺敱
+
+::: details 浜岀骇璺敱绀轰緥浠g爜
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { VBEN_LOGO_URL } from '@vben/constants';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      badgeVariants: 'destructive',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('page.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    redirect: '/vben-admin/about',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          badgeType: 'dot',
+          badgeVariants: 'destructive',
+          icon: 'lucide:copyright',
+          title: $t('page.vben.about'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+:::
+
+### 澶氱骇璺敱
+
+::: tip
+
+- 澶氱骇璺敱鐨勭埗绾ц矾鐢辨棤闇�璁剧疆 `component` 灞炴�э紝鍙渶璁剧疆 `children` 灞炴�у嵆鍙�傞櫎闈炰綘鐪熺殑闇�瑕佸湪鐖剁骇璺敱宓屽涓嬫樉绀哄唴瀹广��
+- 濡傛灉娌℃湁鐗规畩鎯呭喌锛岀埗绾ц矾鐢辩殑 `redirect` 灞炴�э紝涓嶉渶瑕佹寚瀹氾紝榛樿浼氭寚鍚戠涓�涓瓙璺敱銆�
+
+:::
+
+::: details 澶氱骇璺敱绀轰緥浠g爜
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    redirect: '/demos/access',
+    children: [
+      // 宓屽鑿滃崟
+      {
+        meta: {
+          icon: 'ic:round-menu',
+          title: $t('demos.nested.title'),
+        },
+        name: 'NestedDemos',
+        path: '/demos/nested',
+        redirect: '/demos/nested/menu1',
+        children: [
+          {
+            name: 'Menu1Demo',
+            path: '/demos/nested/menu1',
+            component: () => import('#/views/demos/nested/menu-1.vue'),
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu1'),
+            },
+          },
+          {
+            name: 'Menu2Demo',
+            path: '/demos/nested/menu2',
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu2'),
+            },
+            redirect: '/demos/nested/menu2/menu2-1',
+            children: [
+              {
+                name: 'Menu21Demo',
+                path: '/demos/nested/menu2/menu2-1',
+                component: () => import('#/views/demos/nested/menu-2-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu2_1'),
+                },
+              },
+            ],
+          },
+          {
+            name: 'Menu3Demo',
+            path: '/demos/nested/menu3',
+            meta: {
+              icon: 'ic:round-menu',
+              title: $t('demos.nested.menu3'),
+            },
+            redirect: '/demos/nested/menu3/menu3-1',
+            children: [
+              {
+                name: 'Menu31Demo',
+                path: 'menu3-1',
+                component: () => import('#/views/demos/nested/menu-3-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu3_1'),
+                },
+              },
+              {
+                name: 'Menu32Demo',
+                path: 'menu3-2',
+                meta: {
+                  icon: 'ic:round-menu',
+                  title: $t('demos.nested.menu3_2'),
+                },
+                redirect: '/demos/nested/menu3/menu3-2/menu3-2-1',
+                children: [
+                  {
+                    name: 'Menu321Demo',
+                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',
+                    component: () =>
+                      import('#/views/demos/nested/menu-3-2-1.vue'),
+                    meta: {
+                      icon: 'ic:round-menu',
+                      keepAlive: true,
+                      title: $t('demos.nested.menu3_2_1'),
+                    },
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+:::
+
+## 鏂板椤甸潰
+
+鏂板涓�涓〉闈紝浣犲彧闇�瑕佹坊鍔犱竴涓矾鐢卞強瀵瑰簲鐨勯〉闈㈢粍浠跺嵆鍙��
+
+### 娣诲姞璺敱
+
+鍦ㄥ搴旂殑璺敱鏂囦欢涓坊鍔犱竴涓矾鐢卞璞★紝濡備笅锛�
+
+```ts
+import type { RouteRecordRaw } from 'vue-router';
+
+import { VBEN_LOGO_URL } from '@vben/constants';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'mdi:home',
+      title: $t('page.home.title'),
+    },
+    name: 'Home',
+    path: '/home',
+    redirect: '/home/index',
+    children: [
+      {
+        name: 'HomeIndex',
+        path: '/home/index',
+        component: () => import('#/views/home/index.vue'),
+        meta: {
+          icon: 'mdi:home',
+          title: $t('page.home.index'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
+```
+
+### 娣诲姞椤甸潰缁勪欢
+
+鍦╜#/views/home/`涓嬶紝鏂板涓�涓猔index.vue`鏂囦欢锛屽涓嬶細
+
+```vue
+<template>
+  <div>
+    <h1>home page</h1>
+  </div>
+</template>
+```
+
+### 楠岃瘉
+
+鍒拌繖閲岄〉闈㈠凡娣诲姞瀹屾垚锛岃闂� `http://localhost:5555/home/index` 鍑虹幇瀵瑰簲鐨勯〉闈㈠嵆鍙��
+
+## 璺敱閰嶇疆
+
+璺敱閰嶇疆椤逛富瑕佸湪瀵硅薄璺敱鐨� `meta` 灞炴�т腑锛屼互涓嬩负甯哥敤鐨勯厤缃」锛�
+
+```ts {5-8}
+const routes = [
+  {
+    name: 'HomeIndex',
+    path: '/home/index',
+    meta: {
+      icon: 'mdi:home',
+      title: $t('page.home.index'),
+    },
+  },
+];
+```
+
+::: details 璺敱Meta閰嶇疆绫诲瀷瀹氫箟
+
+```ts
+interface RouteMeta {
+  /**
+   * 婵�娲诲浘鏍囷紙鑿滃崟锛�
+   */
+  activeIcon?: string;
+  /**
+   * 褰撳墠婵�娲荤殑鑿滃崟锛屾湁鏃跺�欎笉鎯虫縺娲荤幇鏈夎彍鍗曪紝闇�瑕佹縺娲荤埗绾ц彍鍗曟椂浣跨敤
+   */
+  activePath?: string;
+  /**
+   * 鏄惁鍥哄畾鏍囩椤�
+   * @default false
+   */
+  affixTab?: boolean;
+  /**
+   * 鍥哄畾鏍囩椤电殑椤哄簭
+   * @default 0
+   */
+  affixTabOrder?: number;
+  /**
+   * 闇�瑕佺壒瀹氱殑瑙掕壊鏍囪瘑鎵嶅彲浠ヨ闂�
+   * @default []
+   */
+  authority?: string[];
+  /**
+   * 寰芥爣
+   */
+  badge?: string;
+  /**
+   * 寰芥爣绫诲瀷
+   */
+  badgeType?: 'dot' | 'normal';
+  /**
+   * 寰芥爣棰滆壊
+   */
+  badgeVariants?:
+    | 'default'
+    | 'destructive'
+    | 'primary'
+    | 'success'
+    | 'warning'
+    | string;
+  /**
+   * 褰撳墠璺敱鐨勫瓙绾у湪鑿滃崟涓笉灞曠幇
+   * @default false
+   */
+  hideChildrenInMenu?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄩ潰鍖呭睉涓笉灞曠幇
+   * @default false
+   */
+  hideInBreadcrumb?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄨ彍鍗曚腑涓嶅睍鐜�
+   * @default false
+   */
+  hideInMenu?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄦ爣绛鹃〉涓嶅睍鐜�
+   * @default false
+   */
+  hideInTab?: boolean;
+  /**
+   * 鍥炬爣锛堣彍鍗�/tab锛�
+   */
+  icon?: string;
+  /**
+   * iframe 鍦板潃
+   */
+  iframeSrc?: string;
+  /**
+   * 蹇界暐鏉冮檺锛岀洿鎺ュ彲浠ヨ闂�
+   * @default false
+   */
+  ignoreAccess?: boolean;
+  /**
+   * 寮�鍚疜eepAlive缂撳瓨
+   */
+  keepAlive?: boolean;
+  /**
+   * 澶栭摼-璺宠浆璺緞
+   */
+  link?: string;
+  /**
+   * 璺敱鏄惁宸茬粡鍔犺浇杩�
+   */
+  loaded?: boolean;
+  /**
+   * 鏍囩椤垫渶澶ф墦寮�鏁伴噺
+   * @default false
+   */
+  maxNumOfOpenTab?: number;
+  /**
+   * 鑿滃崟鍙互鐪嬪埌锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+   */
+  menuVisibleWithForbidden?: boolean;
+  /**
+   * 鍦ㄦ柊绐楀彛鎵撳紑
+   */
+  openInNewWindow?: boolean;
+  /**
+   * 鐢ㄤ簬璺敱->鑿滃崟鎺掑簭
+   */
+  order?: number;
+  /**
+   * 鑿滃崟鎵�鎼哄甫鐨勫弬鏁�
+   */
+  query?: Recordable;
+  /**
+   * 鏍囬鍚嶇О
+   */
+  title: string;
+}
+```
+
+:::
+
+### title
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勬爣棰橈紝浼氬湪鑿滃崟鍜屾爣绛鹃〉涓樉绀恒�備竴鑸細閰嶅悎鍥介檯鍖栦娇鐢ㄣ��
+
+### icon
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勫浘鏍囷紝浼氬湪鑿滃崟鍜屾爣绛鹃〉涓樉绀恒�備竴鑸細閰嶅悎鍥炬爣搴撲娇鐢紝濡傛灉鏄痐http`閾炬帴锛屼細鑷姩鍔犺浇鍥剧墖銆�
+
+### activeIcon
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勬縺娲诲浘鏍囷紝浼氬湪鑿滃崟涓樉绀恒�備竴鑸細閰嶅悎鍥炬爣搴撲娇鐢紝濡傛灉鏄痐http`閾炬帴锛屼細鑷姩鍔犺浇鍥剧墖銆�
+
+### keepAlive
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁寮�鍚紦瀛橈紝寮�鍚悗椤甸潰浼氱紦瀛橈紝涓嶄細閲嶆柊鍔犺浇锛屼粎鍦ㄦ爣绛鹃〉鍚敤鏃舵湁鏁堛��
+
+### hideInMenu
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁鍦ㄨ彍鍗曚腑闅愯棌锛岄殣钘忓悗椤甸潰涓嶄細鍦ㄨ彍鍗曚腑鏄剧ず銆�
+
+### hideInTab
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁鍦ㄦ爣绛鹃〉涓殣钘忥紝闅愯棌鍚庨〉闈笉浼氬湪鏍囩椤典腑鏄剧ず銆�
+
+### hideInBreadcrumb
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁鍦ㄩ潰鍖呭睉涓殣钘忥紝闅愯棌鍚庨〉闈笉浼氬湪闈㈠寘灞戜腑鏄剧ず銆�
+
+### hideChildrenInMenu
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勫瓙椤甸潰鏄惁鍦ㄨ彍鍗曚腑闅愯棌锛岄殣钘忓悗瀛愰〉闈笉浼氬湪鑿滃崟涓樉绀恒��
+
+### authority
+
+- 绫诲瀷锛歚string[]`
+- 榛樿鍊硷細`[]`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勬潈闄愶紝鍙湁鎷ユ湁瀵瑰簲鏉冮檺鐨勭敤鎴锋墠鑳借闂〉闈紝涓嶉厤缃垯涓嶉渶瑕佹潈闄愩��
+
+### badge
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勫窘鏍囷紝浼氬湪鑿滃崟鏄剧ず銆�
+
+### badgeType
+
+- 绫诲瀷锛歚'dot' | 'normal'`
+- 榛樿鍊硷細`'normal'`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勫窘鏍囩被鍨嬶紝`dot` 涓哄皬绾㈢偣锛宍normal` 涓烘枃鏈��
+
+### badgeVariants
+
+- 绫诲瀷锛歚'default' | 'destructive' | 'primary' | 'success' | 'warning' | string`
+- 榛樿鍊硷細`'success'`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勫窘鏍囬鑹层��
+
+### activePath
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆褰撳墠婵�娲荤殑鑿滃崟锛屾湁鏃跺�欓〉闈㈡病鏈夋樉绀哄湪鑿滃崟鍐咃紝闇�瑕佹縺娲荤埗绾ц彍鍗曟椂浣跨敤銆�
+
+### affixTab
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁鍥哄畾鏍囩椤碉紝鍥哄畾鍚庨〉闈笉鍙叧闂��
+
+### affixTabOrder
+
+- 绫诲瀷锛歚number`
+- 榛樿鍊硷細`0`
+
+鐢ㄤ簬閰嶇疆椤甸潰鍥哄畾鏍囩椤电殑鎺掑簭, 閲囩敤鍗囧簭鎺掑簭銆�
+
+### iframeSrc
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆鍐呭祵椤甸潰鐨� `iframe` 鍦板潃锛岃缃悗浼氬湪褰撳墠椤甸潰鍐呭祵瀵瑰簲鐨勯〉闈€��
+
+### ignoreAccess
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鏄惁蹇界暐鏉冮檺锛岀洿鎺ュ彲浠ヨ闂��
+
+### link
+
+- 绫诲瀷锛歚string`
+- 榛樿鍊硷細`''`
+
+鐢ㄤ簬閰嶇疆澶栭摼璺宠浆璺緞锛屼細鍦ㄦ柊绐楀彛鎵撳紑銆�
+
+### maxNumOfOpenTab
+
+- 绫诲瀷锛歚number`
+- 榛樿鍊硷細`-1`
+
+鐢ㄤ簬閰嶇疆鏍囩椤垫渶澶ф墦寮�鏁伴噺锛岃缃悗浼氬湪鎵撳紑鏂版爣绛鹃〉鏃惰嚜鍔ㄥ叧闂渶鏃╂墦寮�鐨勬爣绛鹃〉(浠呭湪鎵撳紑鍚屽悕鏍囩椤垫椂鐢熸晥)銆�
+
+### menuVisibleWithForbidden
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+鐢ㄤ簬閰嶇疆椤甸潰鍦ㄨ彍鍗曞彲浠ョ湅鍒帮紝浣嗘槸璁块棶浼氳閲嶅畾鍚戝埌403銆�
+
+### openInNewWindow
+
+- 绫诲瀷锛歚boolean`
+- 榛樿鍊硷細`false`
+
+璁剧疆涓� `true` 鏃讹紝浼氬湪鏂扮獥鍙f墦寮�椤甸潰銆�
+
+### order
+
+- 绫诲瀷锛歚number`
+- 榛樿鍊硷細`0`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勬帓搴忥紝鐢ㄤ簬璺敱鍒拌彍鍗曟帓搴忋��
+
+_娉ㄦ剰:_ 鎺掑簭浠呴拡瀵逛竴绾ц彍鍗曟湁鏁堬紝浜岀骇鑿滃崟鐨勬帓搴忛渶瑕佸湪瀵瑰簲鐨勪竴绾ц彍鍗曚腑鎸変唬鐮侀『搴忚缃��
+
+### query
+
+- 绫诲瀷锛歚Recordable`
+- 榛樿鍊硷細`{}`
+
+鐢ㄤ簬閰嶇疆椤甸潰鐨勮彍鍗曞弬鏁帮紝浼氬湪鑿滃崟涓紶閫掔粰椤甸潰銆�
+
+## 璺敱鍒锋柊
+
+璺敱鍒锋柊鏂瑰紡濡備笅锛�
+
+```vue
+<script setup lang="ts">
+import { useRefresh } from '@vben/hooks';
+
+const { refresh } = useRefresh();
+
+// 鍒锋柊褰撳墠璺敱
+refresh();
+</script>
+```
diff --git a/eims-ui/docs/src/guide/essentials/server.md b/eims-ui/docs/src/guide/essentials/server.md
new file mode 100644
index 0000000..74a45d2
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/server.md
@@ -0,0 +1,359 @@
+# 鏈嶅姟绔氦浜掍笌鏁版嵁Mock
+
+::: tip 璇存槑
+
+鏈枃妗d粙缁嶅浣曞湪寮�鍙戠幆澧冧笅浣跨敤 Mock 鏁版嵁鍜屼笌鏈嶅姟绔繘琛屼氦浜掞紝娑夊強鍒扮殑鎶�鏈湁锛�
+
+- [Nitro](https://nitro.unjs.io/) 杞婚噺绾у悗绔湇鍔″櫒锛屽彲閮ㄧ讲鍦ㄤ换浣曞湴鏂癸紝椤圭洰鐢ㄤ綔浜� Mock 鏈嶅姟鍣ㄣ��
+- [axios](https://axios-http.com/docs/intro) 鐢ㄤ簬鍙戦�� HTTP 璇锋眰涓庢湇鍔$杩涜浜や簰銆�
+
+:::
+
+## 寮�鍙戠幆澧冧氦浜�
+
+濡傛灉鍓嶇搴旂敤鍜屽悗绔帴鍙f湇鍔″櫒娌℃湁杩愯鍦ㄥ悓涓�涓富鏈轰笂锛屼綘闇�瑕佸湪寮�鍙戠幆澧冧笅灏嗘帴鍙h姹備唬鐞嗗埌鎺ュ彛鏈嶅姟鍣ㄣ�傚鏋滄槸鍚屼竴涓富鏈猴紝鍙互鐩存帴璇锋眰鍏蜂綋鐨勬帴鍙e湴鍧�銆�
+
+### 鏈湴寮�鍙戣法鍩熼厤缃�
+
+::: tip 鎻愮ず
+
+鏈湴寮�鍙戣法鍩熼厤缃」鐩凡缁忛厤缃ソ浜嗭紝濡傛湁鍏朵粬闇�姹傦紝鍙互鑷澧炲姞鎴栬�呰皟鏁撮厤缃��
+
+:::
+
+#### 閰嶇疆鏈湴寮�鍙戞帴鍙e湴鍧�
+
+鍦ㄩ」鐩牴鐩綍涓嬬殑 `.env.development` 鏂囦欢涓厤缃帴鍙e湴鍧�锛岃繖閲岄厤缃负 `/api`锛�
+
+```bash
+VITE_GLOB_API_URL=/api
+```
+
+#### 閰嶇疆寮�鍙戞湇鍔″櫒浠g悊
+
+寮�鍙戠幆澧冩椂鍊欙紝濡傛灉闇�瑕佸鐞嗚法鍩燂紝鎺ュ彛鍦板潃鍦ㄥ搴旂殑搴旂敤鐩綍涓嬬殑 `vite.config.mts` 鏂囦欢涓厤缃細
+
+```ts{8-16}
+// apps/web-antd/vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    vite: {
+      server: {
+        proxy: {// [!code focus:11]
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock浠g悊鐩爣鍦板潃
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
+```
+
+#### 鎺ュ彛璇锋眰
+
+鏍规嵁涓婇潰鐨勯厤缃紝鎴戜滑鍙互鍦ㄥ墠绔」鐩腑浣跨敤 `/api` 浣滀负鎺ュ彛璇锋眰鐨勫墠缂�锛屼緥濡傦細
+
+```ts
+import axios from 'axios';
+
+axios.get('/api/user').then((res) => {
+  console.log(res);
+});
+```
+
+姝ゆ椂锛岃姹備細琚唬鐞嗗埌 `http://localhost:5320/api/user`銆�
+
+::: warning 娉ㄦ剰
+
+浠庢祻瑙堝櫒鎺у埗鍙扮殑 Network 鐪嬶紝璇锋眰鏄� `http://localhost:5555/api/user`, 杩欐槸鍥犱负 proxy 閰嶇疆涓嶄細鏀瑰彉鏈湴璇锋眰鐨� url銆�
+
+:::
+
+### 娌℃湁璺ㄥ煙鏃剁殑閰嶇疆
+
+濡傛灉娌℃湁璺ㄥ煙闂锛屽彲浠ョ洿鎺ュ拷鐣� [閰嶇疆寮�鍙戞湇鍔″櫒浠g悊](./server.md#閰嶇疆寮�鍙戞湇鍔″櫒浠g悊) 閰嶇疆锛岀洿鎺ュ皢鎺ュ彛鍦板潃璁剧疆鍦� `VITE_GLOB_API_URL`
+
+鍦ㄩ」鐩牴鐩綍涓嬬殑 `.env.development` 鏂囦欢涓厤缃帴鍙e湴鍧�锛�
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+## 鐢熶骇鐜浜や簰
+
+### 鎺ュ彛鍦板潃閰嶇疆
+
+鍦ㄩ」鐩牴鐩綍涓嬬殑 `.env.production` 鏂囦欢涓厤缃帴鍙e湴鍧�锛�
+
+```bash
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+```
+
+::: tip 鎵撳寘濡備綍鍔ㄦ�佷慨鏀规帴鍙e湴鍧�
+
+`.env` 鏂囦欢鍐呯殑 `VITE_GLOB_*` 寮�澶寸殑鍙橀噺浼氬湪鎵撳寘鐨勬椂鍊欐敞鍏� `_app.config.js` 鏂囦欢鍐呫�傚湪 `dist/_app.config.js` 淇敼鐩稿簲鐨勬帴鍙e湴鍧�鍚庡埛鏂伴〉闈㈠嵆鍙紝涓嶉渶瑕佸湪鏍规嵁涓嶅悓鐜鎵撳寘澶氭锛屼竴娆℃墦鍖呭彲浠ョ敤浜庡涓笉鍚屾帴鍙g幆澧冪殑閮ㄧ讲銆�
+
+:::
+
+### 璺ㄥ煙澶勭悊
+
+鐢熶骇鐜濡傛灉鍑虹幇璺ㄥ煙闂锛屽彲浠ヤ娇鐢� `nginx` 浠g悊鎺ュ彛鍦板潃 鎴栬�呭悗鍙板紑鍚� `cors` 杩涜澶勭悊鍗冲彲锛堝彲鍙傝�僲ock鏈嶅姟锛夈��
+
+## 鎺ュ彛璇锋眰閰嶇疆
+
+椤圭洰涓粯璁よ嚜甯︿簡鍩轰簬 `axios` 灏佽鐨勫熀纭�鐨勮姹傞厤缃紝鏍稿績鐢� `@vben/request` 鍖呮彁渚涖�傞」鐩病鏈夎繃澶氱殑灏佽锛屽彧鏄畝鍗曠殑灏佽浜嗕竴浜涘父鐢ㄧ殑閰嶇疆锛屽鏈夊叾浠栭渶姹傦紝鍙互鑷澧炲姞鎴栬�呰皟鏁撮厤缃�傞拡瀵逛笉鍚岀殑app锛屽彲鑳芥槸鐢ㄥ埌浜嗕笉鍚岀殑缁勪欢搴撲互鍙奰store`,鎵�浠ュ湪搴旂敤鐩綍涓嬬殑`src/api/request.ts`鏂囦欢澶逛笅锛屾湁瀵瑰簲鐨勮姹傞厤缃枃浠�,濡俙web-antd`椤圭洰涓嬬殑`src/api/request.ts`鏂囦欢,鍙互鏍规嵁鑷繁鐨勯渶姹傝繘琛岄厤缃��
+
+### 璇锋眰绀轰緥
+
+#### GET 璇锋眰
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
+```
+
+#### POST/PUT 璇锋眰
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function saveUserApi(user: UserInfo) {
+  return requestClient.post<UserInfo>('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+  return requestClient.put<UserInfo>('/user', user);
+}
+
+export async function saveUserApi(user: UserInfo) {
+  const url = user.id ? `/user/${user.id}` : '/user/';
+  return requestClient.request<UserInfo>(url, {
+    data: user,
+    // 鎴栬�� PUT
+    method: user.id ? 'PUT' : 'POST',
+  });
+}
+```
+
+#### DELETE 璇锋眰
+
+```ts
+import { requestClient } from '#/api/request';
+
+export async function deleteUserApi(user: UserInfo) {
+  return requestClient.delete<boolean>(`/user/${user.id}`, user);
+}
+```
+
+### 璇锋眰閰嶇疆
+
+搴旂敤鍐呯殑`src/api/request.ts`鍙互鏍规嵁鑷繁搴旂敤鐨勬儏鍐电殑闇�姹傝繘琛岄厤缃細
+
+```ts
+/**
+ * 璇ユ枃浠跺彲鑷鏍规嵁涓氬姟閫昏緫杩涜璋冩暣
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    baseURL,
+  });
+
+  /**
+   * 閲嶆柊璁よ瘉閫昏緫
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (
+      preferences.app.loginExpiredMode === 'modal' &&
+      accessStore.isAccessChecked
+    ) {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * 鍒锋柊token閫昏緫
+   */
+  async function doRefreshToken() {
+    const accessStore = useAccessStore();
+    const resp = await refreshTokenApi();
+    const newToken = resp.data;
+    accessStore.setAccessToken(newToken);
+    return newToken;
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  // 璇锋眰澶村鐞�
+  client.addRequestInterceptor({
+    fulfilled: async (config) => {
+      const accessStore = useAccessStore();
+
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      config.headers['Accept-Language'] = preferences.app.locale;
+      return config;
+    },
+  });
+
+  // response鏁版嵁瑙f瀯
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const { data: responseData, status } = response;
+
+      const { code, data } = responseData;
+
+      if (status >= 200 && status < 400 && code === 0) {
+        return data;
+      }
+      throw Object.assign({}, response, { response });
+    },
+  });
+
+  // token杩囨湡鐨勫鐞�
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  // 閫氱敤鐨勯敊璇鐞�,濡傛灉娌℃湁杩涘叆涓婇潰鐨勯敊璇鐞嗛�昏緫锛屽氨浼氳繘鍏ヨ繖閲�
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string, error) => {
+      // 杩欓噷鍙互鏍规嵁涓氬姟杩涜瀹氬埗,浣犲彲浠ユ嬁鍒� error 鍐呯殑淇℃伅杩涜瀹氬埗鍖栧鐞嗭紝鏍规嵁涓嶅悓鐨� code 鍋氫笉鍚岀殑鎻愮ず锛岃�屼笉鏄洿鎺ヤ娇鐢� message.error 鎻愮ず msg
+      // 褰撳墠mock鎺ュ彛杩斿洖鐨勯敊璇瓧娈垫槸 error 鎴栬�� message
+      const responseData = error?.response?.data ?? {};
+      const errorMessage = responseData?.error ?? responseData?.message ?? '';
+      // 濡傛灉娌℃湁閿欒淇℃伅锛屽垯浼氭牴鎹姸鎬佺爜杩涜鎻愮ず
+      message.error(errorMessage || msg);
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
+```
+
+### 澶氫釜鎺ュ彛鍦板潃
+
+鍙渶瑕佸垱寤哄涓� `requestClient` 鍗冲彲锛屽锛�
+
+```ts
+const { apiURL, otherApiURL } = useAppConfig(
+  import.meta.env,
+  import.meta.env.PROD,
+);
+
+export const requestClient = createRequestClient(apiURL);
+
+export const otherRequestClient = createRequestClient(otherApiURL);
+```
+
+## 鍒锋柊Token
+
+椤圭洰涓粯璁ゆ彁渚涗簡鍒锋柊 Token 鐨勯�昏緫锛屽彧闇�瑕佹寜鐓т笅闈㈢殑閰嶇疆鍗冲彲寮�鍚細
+
+- 纭繚褰撳墠鍚敤浜嗗埛鏂� Token 鐨勯厤缃�
+
+璋冩暣瀵瑰簲搴旂敤鐩綍涓嬬殑`preferences.ts`锛岀‘淇漙enableRefreshToken='true'`銆�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    enableRefreshToken: true,
+  },
+});
+```
+
+鍦� `src/api/request.ts` 涓厤缃� `doRefreshToken` 鏂规硶鍗冲彲:
+
+```ts
+// 杩欓噷璋冩暣涓轰綘鐨則oken鏍煎紡
+function formatToken(token: null | string) {
+  return token ? `Bearer ${token}` : null;
+}
+
+/**
+ * 鍒锋柊token閫昏緫
+ */
+async function doRefreshToken() {
+  const accessStore = useAccessStore();
+  // 杩欓噷璋冩暣涓轰綘鐨勫埛鏂皌oken鎺ュ彛
+  const resp = await refreshTokenApi();
+  const newToken = resp.data;
+  accessStore.setAccessToken(newToken);
+  return newToken;
+}
+```
+
+## 鏁版嵁 Mock
+
+::: tip 鐢熶骇鐜 Mock
+
+鏂扮増鏈笉鍐嶆敮鎸佺敓浜х幆澧� mock锛岃浣跨敤鐪熷疄鎺ュ彛銆�
+
+:::
+
+Mock 鏁版嵁鏄墠绔紑鍙戣繃绋嬩腑蹇呬笉鍙皯鐨勪竴鐜紝鏄垎绂诲墠鍚庣寮�鍙戠殑鍏抽敭閾捐矾銆傞�氳繃棰勫厛璺熸湇鍔″櫒绔害瀹氬ソ鐨勬帴鍙o紝妯℃嫙璇锋眰鏁版嵁鐢氳嚦閫昏緫锛岃兘澶熻鍓嶇寮�鍙戠嫭绔嬭嚜涓伙紝涓嶄細琚湇鍔$鐨勫紑鍙戣繘绋嬫墍闃诲銆�
+
+椤圭洰浣跨敤 [Nitro](https://nitro.unjs.io/) 鏉ヨ繘琛屾湰鍦� mock 鏁版嵁澶勭悊銆傚叾鍘熺悊鏄湰鍦伴澶栧惎鍔ㄤ竴涓悗绔湇鍔★紝鏄竴涓湡瀹炵殑鍚庣鏈嶅姟锛屽彲浠ュ鐞嗚姹傦紝杩斿洖鏁版嵁銆�
+
+### Nitro 浣跨敤
+
+Mock 鏈嶅姟浠g爜浣嶄簬`apps/backend-mock`鐩綍涓嬶紝鏃犻渶鎵嬪姩鍚姩锛屽凡缁忛泦鎴愬湪椤圭洰涓紝鍙渶瑕佸湪椤圭洰鏍圭洰褰曚笅杩愯`pnpm dev`鍗冲彲锛岃繍琛屾垚鍔熶箣鍚庯紝鎺у埗鍙颁細鎵撳嵃 `http://localhost:5320/api`, 璁块棶璇ュ湴鍧�鍗冲彲鏌ョ湅 mock 鏈嶅姟銆�
+
+[Nitro](https://nitro.unjs.io/) 璇硶绠�鍗曪紝鍙互鏍规嵁鑷繁鐨勯渶姹傝繘琛岄厤缃強寮�鍙戯紝鍏蜂綋閰嶇疆鍙互鏌ョ湅 [Nitro 鏂囨。](https://nitro.unjs.io/)銆�
+
+## 鍏抽棴 Mock 鏈嶅姟
+
+mock鐨勬湰璐ㄦ槸涓�涓湡瀹炵殑鍚庣鏈嶅姟锛屽鏋滀笉闇�瑕� mock 鏈嶅姟锛屽彲浠ュ湪椤圭洰鏍圭洰褰曚笅鐨� `.env.development` 鏂囦欢涓厤缃� `VITE_NITRO_MOCK=false` 鍗冲彲鍏抽棴 mock 鏈嶅姟銆�
+
+```bash
+# .env.development
+VITE_NITRO_MOCK=false
+```
diff --git a/eims-ui/docs/src/guide/essentials/settings.md b/eims-ui/docs/src/guide/essentials/settings.md
new file mode 100644
index 0000000..e335720
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/settings.md
@@ -0,0 +1,540 @@
+# 閰嶇疆
+
+## 鐜鍙橀噺閰嶇疆
+
+椤圭洰鐨勭幆澧冨彉閲忛厤缃綅浜庡簲鐢ㄧ洰褰曚笅鐨� `.env`銆乣.env.development`銆乣.env.production`銆�
+
+瑙勫垯涓� [Vite Env Variables and Modes](https://vitejs.dev/guide/env-and-mode.html) 涓�鑷淬�傛牸寮忓涓嬶細
+
+```bash
+.env                # 鍦ㄦ墍鏈夌殑鐜涓杞藉叆
+.env.local          # 鍦ㄦ墍鏈夌殑鐜涓杞藉叆锛屼絾浼氳 git 蹇界暐
+.env.[mode]         # 鍙湪鎸囧畾鐨勬ā寮忎腑琚浇鍏�
+.env.[mode].local   # 鍙湪鎸囧畾鐨勬ā寮忎腑琚浇鍏ワ紝浣嗕細琚� git 蹇界暐
+```
+
+::: tip
+
+- 鍙湁浠� `VITE_` 寮�澶寸殑鍙橀噺浼氳宓屽叆鍒板鎴风渚х殑鍖呬腑锛屼綘鍙互鍦ㄩ」鐩唬鐮佷腑杩欐牱璁块棶瀹冧滑锛�
+
+  ```ts
+  console.log(import.meta.env.VITE_PROT);
+  ```
+
+- 浠� `VITE_GLOB_*` 寮�澶寸殑鐨勫彉閲忥紝鍦ㄦ墦鍖呯殑鏃跺�欙紝浼氳鍔犲叆 `_app.config.js`閰嶇疆鏂囦欢褰撲腑. :::
+
+:::
+
+## 鐜閰嶇疆璇存槑
+
+::: code-group
+
+```bash [.env]
+# 搴旂敤鏍囬
+VITE_APP_TITLE=Vben Admin
+
+# 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
+VITE_APP_NAMESPACE=vben-web-antd
+```
+
+```bash [.env.development]
+# 绔彛鍙�
+VITE_PORT=5555
+
+# 璧勬簮鍏叡璺緞,闇�瑕佷互 / 寮�澶村拰缁撳熬
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=/api
+
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=true
+
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=true
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+```
+
+```bash [.env.production]
+# 璧勬簮鍏叡璺緞,闇�瑕佷互 / 寮�澶村拰缁撳熬
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+
+# 鏄惁寮�鍚帇缂╋紝鍙互璁剧疆涓� none, brotli, gzip
+VITE_COMPRESS=gzip
+
+# 鏄惁寮�鍚� PWA
+VITE_PWA=false
+
+# vue-router 鐨勬ā寮�
+VITE_ROUTER_HISTORY=hash
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鎵撳寘鍚庢槸鍚︾敓鎴恉ist.zip
+VITE_ARCHIVER=true
+
+```
+
+:::
+
+## 鐢熶骇鐜鍔ㄦ�侀厤缃�
+
+褰撳湪澶т粨鏍圭洰褰曚笅锛屾墽琛� `pnpm build`鏋勫缓椤圭洰涔嬪悗锛屼細鑷姩鍦ㄥ搴旂殑搴旂敤涓嬬敓鎴� `dist/_app.config.js`鏂囦欢骞舵彃鍏� `index.html`銆�
+
+`_app.config.js` 鏄竴涓姩鎬侀厤缃枃浠讹紝鍙互鍦ㄩ」鐩瀯寤轰箣鍚庯紝鏍规嵁涓嶅悓鐨勭幆澧冨姩鎬佷慨鏀归厤缃�傚唴瀹瑰涓嬶細
+
+```ts
+window._VBEN_ADMIN_PRO_APP_CONF_ = {
+  VITE_GLOB_API_URL: 'https://mock-napi.vben.pro/api',
+};
+Object.freeze(window._VBEN_ADMIN_PRO_APP_CONF_);
+Object.defineProperty(window, '_VBEN_ADMIN_PRO_APP_CONF_', {
+  configurable: false,
+  writable: false,
+});
+```
+
+### 浣滅敤
+
+`_app.config.js` 鐢ㄤ簬椤圭洰鍦ㄦ墦鍖呭悗锛岄渶瑕佸姩鎬佷慨鏀归厤缃殑闇�姹傦紝濡傛帴鍙e湴鍧�銆備笉鐢ㄩ噸鏂拌繘琛屾墦鍖咃紝鍙湪鎵撳寘鍚庝慨鏀� /`dist/_app.config.js` 鍐呯殑鍙橀噺锛屽埛鏂板嵆鍙洿鏂颁唬鐮佸唴鐨勫眬閮ㄥ彉閲忋�傝繖閲屼娇鐢╜js`鏂囦欢锛屾槸涓轰簡纭繚閰嶇疆鏂囦欢鍔犺浇椤哄簭淇濇寔鍦ㄥ墠闈€��
+
+### 浣跨敤
+
+鎯宠鑾峰彇 `_app.config.js` 鍐呯殑鍙橀噺锛岄渶瑕佷娇鐢╜@vben/hooks`鎻愪緵鐨� `useAppConfig`鏂规硶銆�
+
+```ts
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+### 鏂板
+
+鏂板涓�涓彲鍔ㄦ�佷慨鏀圭殑閰嶇疆椤癸紝鍙渶瑕佹寜鐓у涓嬫楠ゅ嵆鍙細
+
+- 棣栧厛鍦� `.env` 鎴栬�呭搴旂殑寮�鍙戠幆澧冮厤缃枃浠跺唴锛屾柊澧為渶瑕佸彲鍔ㄦ�侀厤缃殑鍙橀噺锛岄渶瑕佷互 `VITE_GLOB_*` 寮�澶寸殑鍙橀噺锛屽锛�
+
+  ```bash
+  VITE_GLOB_OTHER_API_URL=https://mock-napi.vben.pro/other-api
+  ```
+
+- 鍦� `packages/types/global.d.ts`,鏂板瀵瑰簲鐨勭被鍨嬪畾涔夛紝濡傦細
+
+  ```ts
+  export interface VbenAdminProAppConfigRaw {
+    VITE_GLOB_API_URL: string;
+    VITE_GLOB_OTHER_API_URL: string; // [!code ++]
+  }
+
+  export interface ApplicationConfig {
+    apiURL: string;
+    otherApiURL: string; // [!code ++]
+  }
+  ```
+
+鍒拌繖閲岋紝灏卞彲浠ュ湪椤圭洰鍐呬娇鐢� `useAppConfig`鏂规硶鑾峰彇鍒版柊澧炵殑閰嶇疆椤逛簡銆�
+
+```ts
+const { otherApiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+```
+
+::: warning 娉ㄦ剰
+
+`useAppConfig`鏂规硶鍙兘鍦ㄥ簲鐢ㄥ唴浣跨敤锛屼笉瑕佽�﹀悎鍒板寘鍐呴儴鍘讳娇鐢ㄣ�傝繖閲屼紶鍏� `import.meta.env`鍜宍import.meta.env.PROD`鏄负浜嗛伩鍏嶈繖绉嶆儏鍐碉紝涓�涓函绮圭殑鍖咃紝搴旈伩鍏嶄娇鐢ㄧ壒瀹氭瀯寤哄伐鍏风殑鍙橀噺銆�
+
+:::
+
+## 鍋忓ソ璁剧疆
+
+椤圭洰鎻愪緵浜嗛潪甯镐赴瀵岀殑鍋忓ソ璁剧疆锛岀敤浜庡姩鎬侀厤缃」鐩殑鍚勭鍔熻兘锛�
+
+![](/guide/preferences.png)
+
+濡傛灉浣犳壘涓嶅埌鏂囨。璇存槑锛屽彲浠ュ皾璇曡嚜宸遍厤缃ソ浠ュ悗锛岀偣鍑籤澶嶅埗鍋忓ソ璁剧疆`锛岃鐩栭」鐩粯璁ゅ嵆鍙�傞厤缃枃浠朵綅浜庡簲鐢ㄧ洰褰曚笅鐨刞preferences.ts`锛屽湪杩欓噷锛屼綘鍙互瑕嗙洊妗嗘灦榛樿鐨勯厤缃紝瀹炵幇鑷畾涔夐厤缃��
+
+```ts
+import { useAppConfig } from '@vben/hooks';
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 椤圭洰閰嶇疆鏂囦欢
+ * 鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆
+ * !!! 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+});
+```
+
+### 妗嗘灦榛樿閰嶇疆
+
+::: details 鏌ョ湅妗嗘灦榛樿閰嶇疆
+
+```ts
+const defaultPreferences: Preferences = {
+  app: {
+    accessMode: 'frontend',
+    authPageLayout: 'panel-right',
+    checkUpdatesInterval: 1,
+    colorGrayMode: false,
+    colorWeakMode: false,
+    compact: false,
+    contentCompact: 'wide',
+    defaultAvatar:
+      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',
+    dynamicTitle: true,
+    enableCheckUpdates: true,
+    enablePreferences: true,
+    enableRefreshToken: false,
+    isMobile: false,
+    layout: 'sidebar-nav',
+    locale: 'zh-CN',
+    loginExpiredMode: 'modal',
+    name: 'Vben Admin',
+    preferencesButtonPosition: 'auto',
+    watermark: false,
+  },
+  breadcrumb: {
+    enable: true,
+    hideOnlyOne: false,
+    showHome: false,
+    showIcon: true,
+    styleType: 'normal',
+  },
+  copyright: {
+    companyName: 'Vben',
+    companySiteLink: 'https://www.vben.pro',
+    date: '2024',
+    enable: true,
+    icp: '',
+    icpLink: '',
+  },
+  footer: {
+    enable: true,
+    fixed: false,
+  },
+  header: {
+    enable: true,
+    hidden: false,
+    mode: 'fixed',
+  },
+  logo: {
+    enable: true,
+    source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+  },
+  navigation: {
+    accordion: true,
+    split: true,
+    styleType: 'rounded',
+  },
+  shortcutKeys: {
+    enable: true,
+    globalLockScreen: true,
+    globalLogout: true,
+    globalPreferences: true,
+    globalSearch: true,
+  },
+  sidebar: {
+    collapsed: false,
+    collapsedShowTitle: false,
+    enable: true,
+    expandOnHover: true,
+    extraCollapse: true,
+    hidden: false,
+    width: 230,
+  },
+  tabbar: {
+    draggable: true,
+    enable: true,
+    height: 36,
+    keepAlive: true,
+    persist: true,
+    showIcon: true,
+    showMaximize: true,
+    showMore: true,
+    styleType: 'chrome',
+  },
+  theme: {
+    builtinType: 'default',
+    colorDestructive: 'hsl(348 100% 61%)',
+    colorPrimary: 'hsl(212 100% 45%)',
+    colorSuccess: 'hsl(144 57% 58%)',
+    colorWarning: 'hsl(42 84% 61%)',
+    mode: 'dark',
+    radius: '0.5',
+    semiDarkHeader: false,
+    semiDarkSidebar: true,
+  },
+  transition: {
+    enable: true,
+    loading: true,
+    name: 'fade-slide',
+    progress: true,
+  },
+  widget: {
+    fullscreen: true,
+    globalSearch: true,
+    languageToggle: true,
+    lockScreen: true,
+    notification: true,
+    refresh: true,
+    sidebarToggle: true,
+    themeToggle: true,
+  },
+};
+```
+
+:::
+
+::: details 鏌ョ湅妗嗘灦榛樿閰嶇疆绫诲瀷
+
+```ts
+interface AppPreferences {
+  /** 鏉冮檺妯″紡 */
+  accessMode: AccessModeType;
+  /** 鐧诲綍娉ㄥ唽椤甸潰甯冨眬 */
+  authPageLayout: AuthPageLayoutType;
+  /** 妫�鏌ユ洿鏂拌疆璇㈡椂闂� */
+  checkUpdatesInterval: number;
+  /** 鏄惁寮�鍚伆鑹叉ā寮� */
+  colorGrayMode: boolean;
+  /** 鏄惁寮�鍚壊寮辨ā寮� */
+  colorWeakMode: boolean;
+  /** 鏄惁寮�鍚揣鍑戞ā寮� */
+  compact: boolean;
+  /** 鏄惁寮�鍚唴瀹圭揣鍑戞ā寮� */
+  contentCompact: ContentCompactType;
+  // /** 搴旂敤榛樿澶村儚 */
+  defaultAvatar: string;
+  // /** 寮�鍚姩鎬佹爣棰� */
+  dynamicTitle: boolean;
+  /** 鏄惁寮�鍚鏌ユ洿鏂� */
+  enableCheckUpdates: boolean;
+  /** 鏄惁鏄剧ず鍋忓ソ璁剧疆 */
+  enablePreferences: boolean;
+  /**
+   * @zh_CN 鏄惁寮�鍚痳efreshToken
+   */
+  enableRefreshToken: boolean;
+  /** 鏄惁绉诲姩绔� */
+  isMobile: boolean;
+  /** 甯冨眬鏂瑰紡 */
+  layout: LayoutType;
+  /** 鏀寔鐨勮瑷� */
+  locale: SupportedLanguagesType;
+  /** 鐧诲綍杩囨湡妯″紡 */
+  loginExpiredMode: LoginExpiredModeType;
+  /** 搴旂敤鍚� */
+  name: string;
+  /** 鍋忓ソ璁剧疆鎸夐挳浣嶇疆 */
+  preferencesButtonPosition: PreferencesButtonPositionType;
+  /**
+   * @zh_CN 鏄惁寮�鍚按鍗�
+   */
+  watermark: boolean;
+}
+
+interface BreadcrumbPreferences {
+  /** 闈㈠寘灞戞槸鍚﹀惎鐢� */
+  enable: boolean;
+  /** 闈㈠寘灞戞槸鍚﹀彧鏈変竴涓椂闅愯棌 */
+  hideOnlyOne: boolean;
+  /** 闈㈠寘灞戦椤靛浘鏍囨槸鍚﹀彲瑙� */
+  showHome: boolean;
+  /** 闈㈠寘灞戝浘鏍囨槸鍚﹀彲瑙� */
+  showIcon: boolean;
+  /** 闈㈠寘灞戦鏍� */
+  styleType: BreadcrumbStyleType;
+}
+
+interface CopyrightPreferences {
+  /** 鐗堟潈鍏徃鍚� */
+  companyName: string;
+  /** 鐗堟潈鍏徃鍚嶉摼鎺� */
+  companySiteLink: string;
+  /** 鐗堟潈鏃ユ湡 */
+  date: string;
+  /** 鐗堟潈鏄惁鍙 */
+  enable: boolean;
+  /** 澶囨鍙� */
+  icp: string;
+  /** 澶囨鍙烽摼鎺� */
+  icpLink: string;
+}
+
+interface FooterPreferences {
+  /** 搴曟爮鏄惁鍙 */
+  enable: boolean;
+  /** 搴曟爮鏄惁鍥哄畾 */
+  fixed: boolean;
+}
+
+interface HeaderPreferences {
+  /** 椤舵爮鏄惁鍚敤 */
+  enable: boolean;
+  /** 椤舵爮鏄惁闅愯棌,css-闅愯棌 */
+  hidden: boolean;
+  /** header鏄剧ず妯″紡 */
+  mode: LayoutHeaderModeType;
+}
+
+interface LogoPreferences {
+  /** logo鏄惁鍙 */
+  enable: boolean;
+  /** logo鍦板潃 */
+  source: string;
+}
+
+interface NavigationPreferences {
+  /** 瀵艰埅鑿滃崟鎵嬮鐞存ā寮� */
+  accordion: boolean;
+  /** 瀵艰埅鑿滃崟鏄惁鍒囧壊锛屽彧鍦� layout=mixed-nav 鐢熸晥 */
+  split: boolean;
+  /** 瀵艰埅鑿滃崟椋庢牸 */
+  styleType: NavigationStyleType;
+}
+
+interface SidebarPreferences {
+  /** 渚ц竟鏍忔槸鍚︽姌鍙� */
+  collapsed: boolean;
+  /** 渚ц竟鏍忔姌鍙犳椂锛屾槸鍚︽樉绀簍itle */
+  collapsedShowTitle: boolean;
+  /** 渚ц竟鏍忔槸鍚﹀彲瑙� */
+  enable: boolean;
+  /** 鑿滃崟鑷姩灞曞紑鐘舵�� */
+  expandOnHover: boolean;
+  /** 渚ц竟鏍忔墿灞曞尯鍩熸槸鍚︽姌鍙� */
+  extraCollapse: boolean;
+  /** 渚ц竟鏍忔槸鍚﹂殣钘� - css */
+  hidden: boolean;
+  /** 渚ц竟鏍忓搴� */
+  width: number;
+}
+
+interface ShortcutKeyPreferences {
+  /** 鏄惁鍚敤蹇嵎閿�-鍏ㄥ眬 */
+  enable: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬閿佸睆蹇嵎閿� */
+  globalLockScreen: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬娉ㄩ攢蹇嵎閿� */
+  globalLogout: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鍋忓ソ璁剧疆蹇嵎閿� */
+  globalPreferences: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鎼滅储蹇嵎閿� */
+  globalSearch: boolean;
+}
+
+interface TabbarPreferences {
+  /** 鏄惁寮�鍚鏍囩椤垫嫋鎷� */
+  draggable: boolean;
+  /** 鏄惁寮�鍚鏍囩椤� */
+  enable: boolean;
+  /** 鏍囩椤甸珮搴� */
+  height: number;
+  /** 寮�鍚爣绛鹃〉缂撳瓨鍔熻兘 */
+  keepAlive: boolean;
+  /** 鏄惁鎸佷箙鍖栨爣绛� */
+  persist: boolean;
+  /** 鏄惁寮�鍚鏍囩椤靛浘鏍� */
+  showIcon: boolean;
+  /** 鏄剧ず鏈�澶у寲鎸夐挳 */
+  showMaximize: boolean;
+  /** 鏄剧ず鏇村鎸夐挳 */
+  showMore: boolean;
+  /** 鏍囩椤甸鏍� */
+  styleType: TabsStyleType;
+}
+
+interface ThemePreferences {
+  /** 鍐呯疆涓婚鍚� */
+  builtinType: BuiltinThemeType;
+  /** 閿欒鑹� */
+  colorDestructive: string;
+  /** 涓婚鑹� */
+  colorPrimary: string;
+  /** 鎴愬姛鑹� */
+  colorSuccess: string;
+  /** 璀﹀憡鑹� */
+  colorWarning: string;
+  /** 褰撳墠涓婚 */
+  mode: ThemeModeType;
+  /** 鍦嗚 */
+  radius: string;
+  /** 鏄惁寮�鍚崐娣辫壊header锛堝彧鍦╰heme='light'鏃剁敓鏁堬級 */
+  semiDarkHeader: boolean;
+  /** 鏄惁寮�鍚崐娣辫壊鑿滃崟锛堝彧鍦╰heme='light'鏃剁敓鏁堬級 */
+  semiDarkSidebar: boolean;
+}
+
+interface TransitionPreferences {
+  /** 椤甸潰鍒囨崲鍔ㄧ敾鏄惁鍚敤 */
+  enable: boolean;
+  // /** 鏄惁寮�鍚〉闈㈠姞杞絣oading */
+  loading: boolean;
+  /** 椤甸潰鍒囨崲鍔ㄧ敾 */
+  name: PageTransitionType | string;
+  /** 鏄惁寮�鍚〉闈㈠姞杞借繘搴﹀姩鐢� */
+  progress: boolean;
+}
+
+interface WidgetPreferences {
+  /** 鏄惁鍚敤鍏ㄥ睆閮ㄤ欢 */
+  fullscreen: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鎼滅储閮ㄤ欢 */
+  globalSearch: boolean;
+  /** 鏄惁鍚敤璇█鍒囨崲閮ㄤ欢 */
+  languageToggle: boolean;
+  /** 鏄惁寮�鍚攣灞忓姛鑳� */
+  lockScreen: boolean;
+  /** 鏄惁鏄剧ず閫氱煡閮ㄤ欢 */
+  notification: boolean;
+  /** 鏄剧ず鍒锋柊鎸夐挳 */
+  refresh: boolean;
+  /** 鏄惁鏄剧ず渚ц竟鏍忔樉绀�/闅愯棌閮ㄤ欢 */
+  sidebarToggle: boolean;
+  /** 鏄惁鏄剧ず涓婚鍒囨崲閮ㄤ欢 */
+  themeToggle: boolean;
+}
+
+interface Preferences {
+  /** 鍏ㄥ眬閰嶇疆 */
+  app: AppPreferences;
+  /** 椤舵爮閰嶇疆 */
+  breadcrumb: BreadcrumbPreferences;
+  /** 鐗堟潈閰嶇疆 */
+  copyright: CopyrightPreferences;
+  /** 搴曟爮閰嶇疆 */
+  footer: FooterPreferences;
+  /** 闈㈠寘灞戦厤缃� */
+  header: HeaderPreferences;
+  /** logo閰嶇疆 */
+  logo: LogoPreferences;
+  /** 瀵艰埅閰嶇疆 */
+  navigation: NavigationPreferences;
+  /** 蹇嵎閿厤缃� */
+  shortcutKeys: ShortcutKeyPreferences;
+  /** 渚ц竟鏍忛厤缃� */
+  sidebar: SidebarPreferences;
+  /** 鏍囩椤甸厤缃� */
+  tabbar: TabbarPreferences;
+  /** 涓婚閰嶇疆 */
+  theme: ThemePreferences;
+  /** 鍔ㄧ敾閰嶇疆 */
+  transition: TransitionPreferences;
+  /** 鍔熻兘閰嶇疆 */
+  widget: WidgetPreferences;
+}
+```
+
+:::
+
+::: warning 娉ㄦ剰
+
+- `overridesPreferences`鏂规硶鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆銆�
+- 浠讳綍閰嶇疆椤归兘鍙互瑕嗙洊锛屽彧闇�瑕佸湪`overridesPreferences`鏂规硶鍐呰鐩栧嵆鍙紝涓嶈淇敼榛樿閰嶇疆鏂囦欢銆�
+- 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥銆�:::
diff --git a/eims-ui/docs/src/guide/essentials/styles.md b/eims-ui/docs/src/guide/essentials/styles.md
new file mode 100644
index 0000000..3ca3a3e
--- /dev/null
+++ b/eims-ui/docs/src/guide/essentials/styles.md
@@ -0,0 +1,106 @@
+# 鏍峰紡
+
+::: tip 鍓嶈█
+
+瀵逛簬 vue 椤圭洰锛孾瀹樻柟鏂囨。](https://vuejs.org/api/sfc-css-features.html#deep-selectors) 瀵硅娉曞凡缁忔湁姣旇緝璇︾粏鐨勪粙缁嶏紝杩欓噷涓昏鏄粙缁嶉」鐩腑鐨勬牱寮忔枃浠剁粨鏋勫拰浣跨敤銆�
+
+:::
+
+## 椤圭洰缁撴瀯
+
+椤圭洰涓殑鏍峰紡鏂囦欢瀛樻斁鍦� `@vben/styles`锛屽寘鍚竴浜涘叏灞�鏍峰紡锛屽閲嶇疆鏍峰紡銆佸叏灞�鍙橀噺绛夛紝瀹冪户鎵夸簡 `@vben-core/design` 鐨勬牱寮忓拰鑳藉姏锛屽彲浠ユ牴鎹」鐩渶姹傝繘琛岃鐩栥��
+
+## Scss
+
+椤圭洰涓娇鐢� `scss` 浣滀负鏍峰紡棰勫鐞嗗櫒锛屽彲浠ュ湪椤圭洰涓娇鐢� `scss` 鐨勭壒鎬э紝濡傚彉閲忋�佸嚱鏁般�佹贩鍚堢瓑銆�
+
+```vue
+<style lang="scss" scoped>
+$font-size: 30px;
+
+.box {
+  .title {
+    color: green;
+    font-size: $font-size;
+  }
+}
+</style>
+```
+
+## Postcss
+
+濡傛灉浣犱笉涔犳儻浣跨敤 `scss`锛屼篃鍙互浣跨敤 `postcss`锛屽畠鏄竴涓洿鍔犲己澶х殑鏍峰紡澶勭悊鍣紝鍙互浣跨敤鏇村鐨勬彃浠讹紝椤圭洰鍐呯疆浜� [postcss-nested](https://github.com/postcss/postcss-nested) 鎻掍欢锛岄厤缃� `Css Variables`锛屽畬鍏ㄥ彲浠ュ彇浠� `scss`銆�
+
+```vue
+<style scoped>
+.box {
+  --font-size: 30px;
+  .title {
+    color: green;
+    font-size: var(--font-size);
+  }
+}
+</style>
+```
+
+## Tailwind CSS
+
+椤圭洰涓泦鎴愪簡 [Tailwind CSS](https://tailwindcss.com/)锛屽彲浠ュ湪椤圭洰涓娇鐢� `tailwindcss` 鐨勭被鍚嶏紝蹇�熸瀯寤洪〉闈€��
+
+```vue
+<template>
+  <div class="bg-white p-4">
+    <p class="text-green">hello world</p>
+  </div>
+</template>
+```
+
+## BEM 瑙勮寖
+
+鏍峰紡鍐茬獊鐨勫彟涓�绉嶉�夋嫨锛屾槸浣跨敤 `BEM` 瑙勮寖銆傚鏋滈�夋嫨 `scss` 锛屽缓璁娇鐢� `BEM` 鍛藉悕瑙勮寖锛屽彲浠ユ洿濂界殑绠$悊鏍峰紡銆傞」鐩粯璁ゆ彁渚涗簡`useNamespace`鍑芥暟锛屽彲浠ユ柟渚跨殑鐢熸垚鍛藉悕绌洪棿銆�
+
+```vue
+<script lang="ts" setup>
+import { useNamespace } from '@vben/hooks';
+
+const { b, e, is } = useNamespace('menu');
+</script>
+<template>
+  <div :class="[b()]">
+    <div :class="[e('item'), is('active', true)]">item1</div>
+  </div>
+</template>
+<style lang="scss" scoped>
+// 濡傛灉浣犲湪搴旂敤鍐呬娇鐢紝杩欒浠g爜鍙互鐪佺暐锛屽凡缁忓湪鎵�鏈夌殑搴旂敤鍐呭叏灞�寮曞叆浜�
+@use '@vben/styles/global' as *;
+@include b('menu') {
+  color: black;
+
+  @include e('item') {
+    background-color: black;
+
+    @include is('active') {
+      background-color: red;
+    }
+  }
+}
+</style>
+```
+
+## CSS Modules
+
+閽堝鏍峰紡鍐茬獊闂锛岃繕鏈変竴绉嶆柟妗堟槸浣跨敤 `CSS Modules` 妯″潡鍖栨柟妗堛�備娇鐢ㄦ柟寮忓涓嬨��
+
+```vue
+<template>
+  <p :class="$style.red">This should be red</p>
+</template>
+
+<style module>
+.red {
+  color: red;
+}
+</style>
+```
+
+鏇村鐢ㄦ硶鍙互瑙� [CSS Modules 瀹樻柟鏂囨。](https://vuejs.org/api/sfc-css-features.html#css-modules)銆�
diff --git a/eims-ui/docs/src/guide/in-depth/access.md b/eims-ui/docs/src/guide/in-depth/access.md
new file mode 100644
index 0000000..c0c4bc9
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/access.md
@@ -0,0 +1,311 @@
+---
+outline: deep
+---
+
+# 鏉冮檺
+
+妗嗘灦鍐呯疆浜嗕袱绉嶆潈闄愭帶鍒舵柟寮忥細
+
+- 閫氳繃鐢ㄦ埛瑙掕壊鏉ュ垽鏂彍鍗曟垨鑰呮寜閽槸鍚﹀彲浠ヨ闂�
+- 閫氳繃鎺ュ彛鏉ュ垽鏂彍鍗曟垨鑰呮寜閽槸鍚﹀彲浠ヨ闂�
+
+## 鍓嶇璁块棶鎺у埗
+
+**瀹炵幇鍘熺悊**: 鍦ㄥ墠绔浐瀹氬啓姝昏矾鐢辩殑鏉冮檺锛屾寚瀹氳矾鐢辨湁鍝簺鏉冮檺鍙互鏌ョ湅銆傚彧鍒濆鍖栭�氱敤鐨勮矾鐢憋紝闇�瑕佹潈闄愭墠鑳借闂殑璺敱娌℃湁琚姞鍏ヨ矾鐢辫〃鍐呫�傚湪鐧诲綍鍚庢垨鑰呭叾浠栨柟寮忚幏鍙栫敤鎴疯鑹插悗锛岄�氳繃瑙掕壊鍘婚亶鍘嗚矾鐢辫〃锛岃幏鍙栬瑙掕壊鍙互璁块棶鐨勮矾鐢辫〃锛岀敓鎴愯矾鐢辫〃锛屽啀閫氳繃 `router.addRoute` 娣诲姞鍒拌矾鐢卞疄渚嬶紝瀹炵幇鏉冮檺鐨勮繃婊ゃ��
+
+**缂虹偣**: 鏉冮檺鐩稿涓嶈嚜鐢憋紝濡傛灉鍚庡彴鏀瑰姩瑙掕壊锛屽墠鍙颁篃闇�瑕佽窡鐫�鏀瑰姩銆傞�傚悎瑙掕壊杈冨浐瀹氱殑绯荤粺
+
+### 姝ラ
+
+- 纭繚褰撳墠妯″紡涓哄墠绔闂帶鍒舵ā寮�
+
+璋冩暣瀵瑰簲搴旂敤鐩綍涓嬬殑`preferences.ts`锛岀‘淇漙accessMode='frontend'`銆�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    // 榛樿鍊硷紝鍙笉濉�
+    accessMode: 'frontend',
+  },
+});
+```
+
+- 閰嶇疆璺敱鏉冮檺
+
+**濡傛灉涓嶉厤缃紝榛樿鍙**
+
+```ts {3}
+ {
+    meta: {
+      authority: ['super'],
+    },
+},
+```
+
+- 纭繚鎺ュ彛杩斿洖鐨勮鑹插拰璺敱琛ㄧ殑鏉冮檺鍖归厤
+
+鍙煡鐪嬪簲鐢ㄤ笅鐨� `src/store/auth`,鎵惧埌涓嬮潰浠g爜锛�
+
+```ts
+// 璁剧疆鐧诲綍鐢ㄦ埛淇℃伅锛岄渶瑕佺‘淇� userInfo.roles 鏄竴涓暟缁勶紝涓斿寘鍚矾鐢辫〃涓殑鏉冮檺
+// 渚嬪锛歶serInfo.roles=['super', 'admin']
+authStore.setUserInfo(userInfo);
+```
+
+鍒拌繖閲岋紝灏卞凡缁忛厤缃畬鎴愶紝浣犻渶瑕佺‘淇濈櫥褰曞悗锛屾帴鍙h繑鍥炵殑瑙掕壊鍜岃矾鐢辫〃鐨勬潈闄愬尮閰嶏紝鍚﹀垯鏃犳硶璁块棶銆�
+
+### 鑿滃崟鍙锛屼絾绂佹璁块棶
+
+鏈夋椂鍊欙紝鎴戜滑闇�瑕佽彍鍗曞彲瑙侊紝浣嗘槸绂佹璁块棶锛屽彲浠ラ�氳繃涓嬮潰鐨勬柟寮忓疄鐜帮紝璁剧疆 `menuVisibleWithForbidden` 涓� `true`锛屾鏃惰彍鍗曞彲瑙侊紝浣嗘槸绂佹璁块棶锛屼細璺宠浆403椤甸潰銆�
+
+```ts
+{
+    meta: {
+      menuVisibleWithForbidden: true,
+    },
+},
+```
+
+## 鍚庣璁块棶鎺у埗
+
+**瀹炵幇鍘熺悊**: 鏄�氳繃鎺ュ彛鍔ㄦ�佺敓鎴愯矾鐢辫〃锛屼笖閬靛惊涓�瀹氱殑鏁版嵁缁撴瀯杩斿洖銆傚墠绔牴鎹渶瑕佸鐞嗚鏁版嵁涓哄彲璇嗗埆鐨勭粨鏋勶紝鍐嶉�氳繃 `router.addRoute` 娣诲姞鍒拌矾鐢卞疄渚嬶紝瀹炵幇鏉冮檺鐨勫姩鎬佺敓鎴愩��
+
+**缂虹偣**: 鍚庣闇�瑕佹彁渚涚鍚堣鑼冪殑鏁版嵁缁撴瀯锛屽墠绔渶瑕佸鐞嗘暟鎹粨鏋勶紝閫傚悎鏉冮檺杈冧负澶嶆潅鐨勭郴缁熴��
+
+### 姝ラ
+
+- 纭繚褰撳墠妯″紡涓哄悗绔闂帶鍒舵ā寮�
+
+璋冩暣瀵瑰簲搴旂敤鐩綍涓嬬殑`preferences.ts`锛岀‘淇漙accessMode='backend'`銆�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    accessMode: 'backend',
+  },
+});
+```
+
+- 纭繚鎺ュ彛杩斿洖鐨勮彍鍗曟暟鎹粨鏋勬纭�
+
+鍙煡鐪嬪簲鐢ㄤ笅鐨� `src/router/access.ts`,鎵惧埌涓嬮潰浠g爜锛�
+
+```ts {5}
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  return await generateAccessible(preferences.app.accessMode, {
+    fetchMenuListAsync: async () => {
+      // 杩欎釜鎺ュ彛涓哄悗绔繑鍥炵殑鑿滃崟鏁版嵁
+      return await getAllMenus();
+    },
+  });
+}
+```
+
+- 鎺ュ彛杩斿洖鑿滃崟鏁版嵁锛屽彲鐪嬫敞閲婅鏄�
+
+::: details 鎺ュ彛杩斿洖鑿滃崟鏁版嵁绀轰緥
+
+```ts
+const dashboardMenus = [
+  {
+    // 杩欓噷鍥哄畾鍐欐 BasicLayout锛屼笉鍙洿鏀�
+    component: 'BasicLayout',
+    meta: {
+      order: -1,
+      title: 'page.dashboard.title',
+    },
+    name: 'Dashboard',
+    path: '/',
+    redirect: '/analytics',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        // 杩欓噷涓洪〉闈㈢殑璺緞锛岄渶瑕佸幓鎺� views/ 鍜� .vue
+        component: '/dashboard/analytics/index',
+        meta: {
+          affixTab: true,
+          title: 'page.dashboard.analytics',
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: '/dashboard/workspace/index',
+        meta: {
+          title: 'page.dashboard.workspace',
+        },
+      },
+    ],
+  },
+];
+```
+
+:::
+
+鍒拌繖閲岋紝灏卞凡缁忛厤缃畬鎴愶紝浣犻渶瑕佺‘淇濈櫥褰曞悗锛屾帴鍙h繑鍥炵殑鑿滃崟鏍煎紡姝g‘锛屽惁鍒欐棤娉曡闂��
+
+## 鎸夐挳缁嗙矑搴︽帶鍒�
+
+鍦ㄦ煇浜涙儏鍐典笅锛屾垜浠渶瑕佸鎸夐挳杩涜缁嗙矑搴︾殑鎺у埗锛屾垜浠彲浠ュ�熷姪鎺ュ彛鎴栬�呰鑹叉潵鎺у埗鎸夐挳鐨勬樉绀恒��
+
+### 鏉冮檺鐮�
+
+鏉冮檺鐮佷负鎺ュ彛杩斿洖鐨勬潈闄愮爜锛岄�氳繃鏉冮檺鐮佹潵鍒ゆ柇鎸夐挳鏄惁鏄剧ず锛岄�昏緫鍦╜src/store/auth`涓嬶細
+
+```ts
+const [fetchUserInfoResult, accessCodes] = await Promise.all([
+  fetchUserInfo(),
+  getAccessCodes(),
+]);
+
+userInfo = fetchUserInfoResult;
+authStore.setUserInfo(userInfo);
+accessStore.setAccessCodes(accessCodes);
+```
+
+鎵惧埌 `getAccessCodes` 瀵瑰簲鐨勬帴鍙o紝鍙牴鎹笟鍔¢�昏緫杩涜璋冩暣銆�
+
+鏉冮檺鐮佽繑鍥炵殑鏁版嵁缁撴瀯涓哄瓧绗︿覆鏁扮粍锛屼緥濡傦細`['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010']`
+
+鏈変簡鏉冮檺鐮侊紝灏卞彲浠ヤ娇鐢� `@vben/access` 鎻愪緵鐨刞AccessControl`缁勪欢鍙夾PI鏉ヨ繘琛屾寜閽殑鏄剧ず涓庨殣钘忋��
+
+#### 缁勪欢鏂瑰紡
+
+```vue
+<script lang="ts" setup>
+import { AccessControl, useAccess } from '@vben/access';
+
+const { accessMode, hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <!-- 闇�瑕佹寚鏄� type="code" -->
+  <AccessControl :codes="['AC_100100']" type="code">
+    <Button> Super 璐﹀彿鍙 ["AC_1000001"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_100030']" type="code">
+    <Button> Admin 璐﹀彿鍙 ["AC_100010"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_1000001']" type="code">
+    <Button> User 璐﹀彿鍙 ["AC_1000001"] </Button>
+  </AccessControl>
+  <AccessControl :codes="['AC_100100', 'AC_100010']" type="code">
+    <Button> Super & Admin 璐﹀彿鍙 ["AC_100100","AC_1000001"] </Button>
+  </AccessControl>
+</template>
+```
+
+#### API鏂瑰紡
+
+```vue
+<script lang="ts" setup>
+import { AccessControl, useAccess } from '@vben/access';
+
+const { hasAccessByCodes } = useAccess();
+</script>
+
+<template>
+  <Button v-if="hasAccessByCodes(['AC_100100'])">
+    Super 璐﹀彿鍙 ["AC_1000001"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_100030'])">
+    Admin 璐﹀彿鍙 ["AC_100010"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_1000001'])">
+    User 璐﹀彿鍙 ["AC_1000001"]
+  </Button>
+  <Button v-if="hasAccessByCodes(['AC_100100', 'AC_1000001'])">
+    Super & Admin 璐﹀彿鍙 ["AC_100100","AC_1000001"]
+  </Button>
+</template>
+```
+
+#### 鎸囦护鏂瑰紡
+
+> 鎸囦护鏀寔缁戝畾鍗曚釜鎴栧涓潈闄愮爜銆傚崟涓椂鍙互鐩存帴浼犲叆瀛楃涓叉垨鏁扮粍涓寘鍚竴涓潈闄愮爜锛屽涓潈闄愮爜鍒欎紶鍏ユ暟缁勩��
+
+```vue
+<template>
+  <Button class="mr-4" v-access:code="'AC_100100'">
+    Super 璐﹀彿鍙 'AC_100100'
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_100030']">
+    Admin 璐﹀彿鍙 ["AC_100010"]
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_1000001']">
+    User 璐﹀彿鍙 ["AC_1000001"]
+  </Button>
+  <Button class="mr-4" v-access:code="['AC_100100', 'AC_1000001']">
+    Super & Admin 璐﹀彿鍙 ["AC_100100","AC_1000001"]
+  </Button>
+</template>
+```
+
+### 瑙掕壊
+
+瑙掕壊鍒ゆ柇鏂瑰紡涓嶉渶瑕佹帴鍙h繑鍥炵殑鏉冮檺鐮侊紝鐩存帴閫氳繃瑙掕壊鏉ュ垽鏂寜閽槸鍚︽樉绀恒��
+
+#### 缁勪欢鏂瑰紡
+
+```vue
+<script lang="ts" setup>
+import { AccessControl } from '@vben/access';
+</script>
+
+<template>
+  <AccessControl :codes="['super']">
+    <Button> Super 瑙掕壊鍙 </Button>
+  </AccessControl>
+  <AccessControl :codes="['admin']">
+    <Button> Admin 瑙掕壊鍙 </Button>
+  </AccessControl>
+  <AccessControl :codes="['user']">
+    <Button> User 瑙掕壊鍙 </Button>
+  </AccessControl>
+  <AccessControl :codes="['super', 'admin']">
+    <Button> Super & Admin 瑙掕壊鍙 </Button>
+  </AccessControl>
+</template>
+```
+
+#### API鏂瑰紡
+
+```vue
+<script lang="ts" setup>
+import { useAccess } from '@vben/access';
+
+const { hasAccessByRoles } = useAccess();
+</script>
+
+<template>
+  <Button v-if="hasAccessByRoles(['super'])"> Super 璐﹀彿鍙 </Button>
+  <Button v-if="hasAccessByRoles(['admin'])"> Admin 璐﹀彿鍙 </Button>
+  <Button v-if="hasAccessByRoles(['user'])"> User 璐﹀彿鍙 </Button>
+  <Button v-if="hasAccessByRoles(['super', 'admin'])">
+    Super & Admin 璐﹀彿鍙
+  </Button>
+</template>
+```
+
+#### 鎸囦护鏂瑰紡
+
+> 鎸囦护鏀寔缁戝畾鍗曚釜鎴栧涓潈闄愮爜銆傚崟涓椂鍙互鐩存帴浼犲叆瀛楃涓叉垨鏁扮粍涓寘鍚竴涓潈闄愮爜锛屽涓潈闄愮爜鍒欎紶鍏ユ暟缁勩��
+
+```vue
+<template>
+  <Button class="mr-4" v-access:role="'super'"> Super 瑙掕壊鍙 </Button>
+  <Button class="mr-4" v-access:role="['super']"> Super 瑙掕壊鍙 </Button>
+  <Button class="mr-4" v-access:role="['admin']"> Admin 瑙掕壊鍙 </Button>
+  <Button class="mr-4" v-access:role="['user']"> User 瑙掕壊鍙 </Button>
+  <Button class="mr-4" v-access:role="['super', 'admin']">
+    Super & Admin 瑙掕壊鍙
+  </Button>
+</template>
+```
diff --git a/eims-ui/docs/src/guide/in-depth/check-updates.md b/eims-ui/docs/src/guide/in-depth/check-updates.md
new file mode 100644
index 0000000..4af9e33
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/check-updates.md
@@ -0,0 +1,48 @@
+# 妫�鏌ユ洿鏂�
+
+## 浠嬬粛
+
+褰撶綉绔欐湁鏇存柊鏃讹紝鎮ㄥ彲鑳介渶瑕佹鏌ユ洿鏂般�傛鏋舵彁渚涗簡杩欎竴鍔熻兘锛岄�氳繃瀹氭椂妫�鏌ユ洿鏂帮紝鎮ㄥ彲浠ュ湪搴旂敤鐨� preferences.ts 鏂囦欢涓厤缃� `checkUpdatesInterval`鍜� `enableCheckUpdates` 瀛楁锛屼互寮�鍚拰璁剧疆妫�鏌ユ洿鏂扮殑鏃堕棿闂撮殧锛堝崟浣嶏細鍒嗛挓锛夈��
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    // 鏄惁寮�鍚鏌ユ洿鏂�
+    enableCheckUpdates: true,
+    // 妫�鏌ユ洿鏂扮殑鏃堕棿闂撮殧锛屽崟浣嶄负鍒嗛挓
+    checkUpdatesInterval: 1,
+  },
+});
+```
+
+## 鏁堟灉
+
+妫�娴嬪埌鏇存柊鏃讹紝浼氬脊鍑烘彁绀烘锛岃闂敤鎴锋槸鍚﹀埛鏂伴〉闈細
+
+![check-updates](/guide/update-notice.png)
+
+## 鏇挎崲涓哄叾浠栨鏌ユ洿鏂版柟寮�
+
+濡傛灉闇�瑕侀�氳繃鍏朵粬鏂瑰紡妫�鏌ユ洿鏂帮紝渚嬪閫氳繃鎺ュ彛鏉ユ洿鐏垫椿鍦版帶鍒舵洿鏂伴�昏緫锛堝寮哄埗鍒锋柊銆佹樉绀烘洿鏂板唴瀹圭瓑锛夛紝浣犲彲浠ラ�氳繃淇敼 `@vben/layouts` 涓嬮潰鐨� `src/widgets/check-updates/check-updates.vue`鏂囦欢鏉ュ疄鐜般��
+
+```ts
+// 杩欓噷鍙互鏇挎崲涓轰綘鐨勬鏌ユ洿鏂伴�昏緫
+async function getVersionTag() {
+  try {
+    const response = await fetch('/', {
+      cache: 'no-cache',
+      method: 'HEAD',
+    });
+
+    return (
+      response.headers.get('etag') || response.headers.get('last-modified')
+    );
+  } catch {
+    console.error('Failed to fetch version tag');
+    return null;
+  }
+}
+```
diff --git a/eims-ui/docs/src/guide/in-depth/features.md b/eims-ui/docs/src/guide/in-depth/features.md
new file mode 100644
index 0000000..53b9670
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/features.md
@@ -0,0 +1,84 @@
+# 甯哥敤鍔熻兘
+
+涓�浜涘父鐢ㄧ殑鍔熻兘鍚堥泦銆�
+
+## 鐧诲綍璁よ瘉杩囨湡
+
+褰撴帴鍙h繑鍥瀈401`鐘舵�佺爜鏃讹紝妗嗘灦浼氳涓虹櫥褰曡璇佽繃鏈燂紝鐧诲綍瓒呮椂浼氳烦杞埌鐧诲綍椤垫垨鑰呮墦寮�鐧诲綍寮圭獥銆傚湪搴旂敤鐩綍涓嬬殑`preferences.ts`鍙互閰嶇疆锛�
+
+### 璺宠浆鐧诲綍椤甸潰
+
+鐧诲綍瓒呮椂浼氳烦杞埌鐧诲綍椤�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    loginExpiredMode: 'page',
+  },
+});
+```
+
+### 鎵撳紑鐧诲綍寮圭獥
+
+鐧诲綍瓒呮椂浼氭墦寮�鐧诲綍寮圭獥
+
+![](/guide/login-expired.png)
+
+閰嶇疆锛�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    loginExpiredMode: 'modal',
+  },
+});
+```
+
+## 鍔ㄦ�佹爣棰�
+
+- 榛樿鍊硷細`true`
+
+寮�鍚悗缃戦〉鏍囬闅忕潃璺敱鐨刞title`鑰屽彉鍖栥�傚湪搴旂敤鐩綍涓嬬殑`preferences.ts`锛屽紑鍚垨鑰呭叧闂嵆鍙��
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    dynamicTitle: true,
+  },
+});
+```
+
+## 椤甸潰姘村嵃
+
+- 榛樿鍊硷細`false`
+
+寮�鍚悗缃戦〉浼氭樉绀烘按鍗帮紝鍦ㄥ簲鐢ㄧ洰褰曚笅鐨刞preferences.ts`锛屽紑鍚垨鑰呭叧闂嵆鍙��
+
+```ts
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    watermark: true,
+  },
+});
+```
+
+濡傛灉浣犳兂鏇存柊姘村嵃鐨勫唴瀹癸紝鍙互杩欎箞鍋氾紝鍙傛暟鍙互鍙傝�� [watermark-js-plus](https://zhensherlock.github.io/watermark-js-plus/)锛�
+
+```ts
+import { useWatermark } from '@vben/hooks';
+
+const { destroyWatermark, updateWatermark } = useWatermark();
+
+await updateWatermark({
+  // 姘村嵃鍐呭
+  content: 'hello my watermark',
+});
+```
diff --git a/eims-ui/docs/src/guide/in-depth/layout.md b/eims-ui/docs/src/guide/in-depth/layout.md
new file mode 100644
index 0000000..f8317bb
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/layout.md
@@ -0,0 +1 @@
+# 甯冨眬
diff --git a/eims-ui/docs/src/guide/in-depth/loading.md b/eims-ui/docs/src/guide/in-depth/loading.md
new file mode 100644
index 0000000..60e6937
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/loading.md
@@ -0,0 +1,46 @@
+# 鍏ㄥ眬loading
+
+鍏ㄥ眬 loading 鎸囩殑鏄〉闈㈠埛鏂版椂鍑虹幇鐨勫姞杞芥晥鏋滐紝閫氬父鏄竴涓棆杞殑鍥炬爣锛�
+
+![Global loading spinner](/guide/loading.png)
+
+## 鍘熺悊
+
+鐢� `vite-plugin-inject-app-loading` 鎻掍欢瀹炵幇锛屾彃浠朵細鍦ㄦ瘡涓簲鐢ㄩ兘娉ㄥ叆涓�涓叏灞�鐨� `loading html`銆�
+
+## 鍏抽棴
+
+濡傛灉浣犱笉闇�瑕佸叏灞� loading锛屽彲浠ュ湪 `.env` 鏂囦欢涓叧闂細
+
+```bash
+VITE_INJECT_APP_LOADING=false
+```
+
+## 鑷畾涔�
+
+濡傛灉浣犳兂瑕佽嚜瀹氫箟鍏ㄥ眬 loading锛屽彲浠ュ湪搴旂敤鐩綍涓嬶紝涓巂index.html`鍚岀骇锛屽垱寤轰竴涓猔loading.html`鏂囦欢锛屾彃浠朵細鑷姩璇诲彇骞舵敞鍏ャ�傝繖涓猦tml鍙互鑷瀹氫箟鏍峰紡鍜屽姩鐢汇��
+
+::: tip
+
+- 浣犲彲浠ヤ娇鐢ㄨ窡`index.html`涓�鏍风殑璇硶锛屾瘮濡俙VITE_APP_TITLE`鍙橀噺锛屾潵鑾峰彇搴旂敤鐨勬爣棰樸��
+- 蹇呴』淇濊瘉鏈変竴涓猔id="__app-loading__"`鐨勫厓绱犮��
+- 缁檂id="__app-loading__"`鐨勫厓绱狅紝鍔犱竴涓� `hidden` class銆�
+- 蹇呴』淇濊瘉鏈変竴涓猔style[data-app-loading="inject-css"]`鐨勫厓绱犮��
+
+```html{1,4}
+<style data-app-loading="inject-css">
+  #__app-loading__.hidden {
+    pointer-events: none;
+    visibility: hidden;
+    opacity: 0;
+    transition: all 1s ease-out;
+  }
+  /* ... */
+</style>
+<div id="__app-loading__">
+  <!-- ... -->
+  <div class="title"><%= VITE_APP_TITLE %></div>
+</div>
+```
+
+:::
diff --git a/eims-ui/docs/src/guide/in-depth/locale.md b/eims-ui/docs/src/guide/in-depth/locale.md
new file mode 100644
index 0000000..e4a4a65
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/locale.md
@@ -0,0 +1,227 @@
+# 鍥介檯鍖�
+
+椤圭洰宸茬粡闆嗘垚浜� [Vue i18n](https://kazupon.github.io/vue-i18n/)锛屽苟涓斿凡缁忛厤缃ソ浜嗕腑鏂囧拰鑻辨枃鐨勮瑷�鍖呫��
+
+## IDE 鎻掍欢
+
+濡傛灉浣犱娇鐢ㄧ殑 vscode 寮�鍙戝伐鍏凤紝鍒欐帹鑽愬畨瑁� [i18n Ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 杩欎釜鎻掍欢銆傚畠鍙互甯姪浣犳洿鏂逛究鐨勭鐞嗗浗闄呭寲鐨勬枃妗堬紝瀹夎浜嗚鎻掍欢鍚庯紝浣犵殑浠g爜鍐呭彲浠ュ疄鏃剁湅鍒板搴旂殑璇█鍐呭锛�
+
+![](/public/guide/locale.png)
+
+## 閰嶇疆榛樿璇█
+
+鍙渶瑕佽鐩栭粯璁ょ殑鍋忓ソ璁剧疆鍗冲彲锛屽湪瀵瑰簲鐨勫簲鐢ㄥ唴锛屾壘鍒� `src/preferences.ts` 鏂囦欢锛屼慨鏀� `locale` 鐨勫�煎嵆鍙細
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+  app: {
+    locale: 'en-US',
+  },
+});
+```
+
+## 鍔ㄦ�佸垏鎹㈣瑷�
+
+鍒囨崲璇█鏈変袱閮ㄥ垎缁勬垚:
+
+- 鏇存柊鍋忓ソ璁剧疆
+- 鍔犺浇瀵瑰簲鐨勮瑷�鍖�
+
+```ts
+import type { SupportedLanguagesType } from '@vben/locales';
+import { loadLocaleMessages } from '@vben/locales';
+import { updatePreferences } from '@vben/preferences';
+
+async function updateLocale(value: string) {
+  // 1. 鏇存柊鍋忓ソ璁剧疆
+  const locale = value as SupportedLanguagesType;
+  updatePreferences({
+    app: {
+      locale,
+    },
+  });
+  // 2. 鍔犺浇瀵瑰簲鐨勮瑷�鍖�
+  await loadLocaleMessages(locale);
+}
+
+updateLocale('en-US');
+```
+
+## 鏂板缈昏瘧鏂囨湰
+
+::: warning 娉ㄦ剰
+
+- 璇蜂笉瑕佸皢涓氬姟缈昏瘧鏂囨湰鏀惧埌 `@vben/locales` 鍐咃紝杩欐牱鍙互鏇村ソ鐨勭鐞嗕笟鍔″拰閫氱敤鐨勭炕璇戞枃鏈��
+- 鏈夊涓瑷�鍖呯殑鎯呭喌涓嬶紝鏂板缈昏瘧鏂囨湰鏃讹紝闇�瑕佸湪鎵�鏈夎瑷�鍖呭唴鏂板瀵瑰簲鐨勬枃鏈��
+
+:::
+
+鏂板缈昏瘧鏂囨湰锛屽彧闇�瑕佸湪瀵瑰簲鐨勫簲鐢ㄥ唴锛屾壘鍒� `src/locales/langs/`锛屾柊澧炲搴旂殑鏂囨湰鍗冲彲锛屼緥:
+
+**src/locales/langs/zh-CN/\*.json**
+
+````ts
+```json
+{
+  "about": {
+    "desc": "Vben Admin 鏄竴涓幇浠g殑绠$悊妯$増銆�"
+  }
+}
+````
+
+**src/locales/langs/en-US.ts**
+
+````ts
+```json
+{
+  "about": {
+    "desc": "Vben Admin is a modern management template."
+  }
+}
+````
+
+## 浣跨敤缈昏瘧鏂囨湰
+
+閫氳繃 `@vben/locales`锛屼綘鍙互寰堟柟渚跨殑浣跨敤缈昏瘧鏂囨湰锛�
+
+### 鍦ㄤ唬鐮佷腑浣跨敤
+
+```vue
+<script setup lang="ts">
+import { computed } from 'vue';
+import { $t } from '@vben/locales';
+
+const items = computed(() => [{ title: $t('about.desc') }]);
+</script>
+<template>
+  <div>{{ $t('about.desc') }}</div>
+  <template v-for="item in items.value">
+    <div>{{ item.title }}</div>
+  </template>
+</template>
+```
+
+## 鏂板璇█鍖�
+
+濡傛灉浣犻渶瑕佹柊澧炶瑷�鍖咃紝闇�瑕佹寜鐓т互涓嬫楠よ繘琛岋細
+
+- 鍦� `packages/locales/langs` 鐩綍涓嬫柊澧炲搴旂殑璇█鍖呮枃浠讹紝渚嬶細`zh-TW.json`锛屽苟缈昏瘧瀵瑰簲鐨勬枃鏈��
+- 鍦ㄥ搴旂殑搴旂敤鍐咃紝鎵惧埌 `src/locales/langs` 鏂囦欢锛屾柊澧炲搴旂殑璇█鍖� `zh-TW.json`
+- 鍦� `packages/constants/src/core.ts`鍐咃紝鏂板瀵瑰簲鐨勮瑷�锛�
+
+  ```ts
+  export interface LanguageOption {
+    label: string;
+    value: 'en-US' | 'zh-CN'; // [!code --]
+    value: 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+  }
+  export const SUPPORT_LANGUAGES: LanguageOption[] = [
+    {
+      label: '绠�浣撲腑鏂�',
+      value: 'zh-CN',
+    },
+    {
+      label: 'English',
+      value: 'en-US',
+    },
+    {
+      label: '绻佷綋涓枃', // [!code ++]
+      value: 'zh-TW', // [!code ++]
+    },
+  ];
+  ```
+
+- 鍦� `packages/locales/typing.ts`鍐咃紝鏂板 Typescript 绫诲瀷锛�
+
+  ```ts
+  export type SupportedLanguagesType = 'en-US' | 'zh-CN'; // [!code --]
+  export type SupportedLanguagesType = 'en-US' | 'zh-CN' | 'zh-TW'; // [!code ++]
+  ```
+
+鍒拌繖閲岋紝浣犲氨鍙互鍦ㄩ」鐩唴浣跨敤鏂板鐨勮瑷�鍖呬簡銆�
+
+## 鐣岄潰鍒囨崲璇█鍔熻兘
+
+濡傛灉浣犳兂鍏抽棴鐣岄潰涓婄殑璇█鍒囨崲鏄剧ず鎸夐挳锛屽湪瀵瑰簲鐨勫簲鐢ㄥ唴锛屾壘鍒� `src/preferences.ts` 鏂囦欢锛屼慨鏀� `locale` 鐨勫�煎嵆鍙細
+
+```ts {3}
+export const overridesPreferences = defineOverridesPreferences({
+  widget: {
+    languageToggle: false,
+  },
+});
+```
+
+## 杩滅▼鍔犺浇璇█鍖�
+
+::: tip 鎻愮ず
+
+閫氳繃椤圭洰鑷甫鐨刞request`宸ュ叿杩涜鎺ュ彛璇锋眰鏃讹紝榛樿璇锋眰澶撮噷浼氬甫涓� [Accept-Language](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language) 锛屾湇鍔$鍙牴鎹姹傚ご杩涜鍔ㄦ�佹暟鎹浗闄呭寲澶勭悊銆�
+
+:::
+
+姣忎釜搴旂敤閮芥湁涓�涓嫭绔嬬殑璇█鍖咃紝瀹冨彲浠ヨ鐩栭�氱敤鐨勮瑷�閰嶇疆锛屼綘鍙互閫氳繃杩滅▼鍔犺浇鐨勬柟寮忔潵鑾峰彇瀵瑰簲鐨勮瑷�鍖咃紝鍙渶瑕佸湪瀵瑰簲鐨勫簲鐢ㄥ唴锛屾壘鍒� `src/locales/index.ts` 鏂囦欢锛屼慨鏀� `loadMessages` 鏂规硶鍗冲彲锛�
+
+```ts {3-4}
+async function loadMessages(lang: SupportedLanguagesType) {
+  const [appLocaleMessages] = await Promise.all([
+    // 杩欓噷淇敼涓鸿繙绋嬫帴鍙e姞杞芥暟鎹嵆鍙�
+    localesMap[lang](),
+    loadThirdPartyMessage(lang),
+  ]);
+  return appLocaleMessages.default;
+}
+```
+
+## 绗笁鏂硅瑷�鍖�
+
+涓嶅悓搴旂敤鍐呬娇鐢ㄧ殑绗笁鏂圭粍浠跺簱鎴栬�呮彃浠跺浗闄呭寲鏂瑰紡鍙兘涓嶄竴鑷达紝鎵�浠ラ渶瑕佸樊鍒鐞嗐�� 濡傛灉浣犻渶瑕佸紩鍏ョ涓夋柟鐨勮瑷�鍖咃紝浣犲彲浠ュ湪瀵瑰簲鐨勫簲鐢ㄥ唴锛屾壘鍒� `src/locales/index.ts` 鏂囦欢锛屼慨鏀� `loadThirdPartyMessage` 鏂规硶鍗冲彲锛�
+
+```ts
+/**
+ * 鍔犺浇dayjs鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    // 榛樿浣跨敤鑻辫
+    default: {
+      locale = await import('dayjs/locale/en');
+    }
+  }
+  if (locale) {
+    dayjs.locale(locale);
+  } else {
+    console.error(`Failed to load dayjs locale for ${lang}`);
+  }
+}
+```
+
+## 绉婚櫎鍥介檯鍖�
+
+棣栧厛锛屼笉鏄緢寤鸿绉婚櫎鍥介檯鍖栵紝鍥犱负鍥介檯鍖栨槸涓�涓緢濂界殑寮�鍙戜範鎯紝浣嗘槸濡傛灉浣犵湡鐨勯渶瑕佺Щ闄ゅ浗闄呭寲锛屼綘鍙互鐩存帴浣跨敤涓枃鏂囨锛岀劧鍚庝繚鐣欓」鐩嚜甯︾殑璇█鍖呭嵆鍙紝鏁翠綋寮�鍙戜綋楠屼笉浼氬奖鍝嶃�傜Щ闄ゅ浗闄呭寲鐨勬楠ゅ涓嬶細
+
+- 闅愯棌鐣岄潰涓婄殑璇█鍒囨崲鎸夐挳锛岃锛歔鐣岄潰鍒囨崲璇█鍔熻兘](#鐣岄潰鍒囨崲璇█鍔熻兘)
+- 淇敼榛樿璇█锛岃锛歔閰嶇疆榛樿璇█](#閰嶇疆榛樿璇█)
+- 鍏抽棴 `vue-i18n`鐨勮鍛婃彁绀猴紝鍦╜src/locales/index.ts`鏂囦欢鍐咃紝淇敼`missingWarn`涓篳false`鍗冲彲锛�
+
+  ```ts
+  async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+    await coreSetup(app, {
+      defaultLocale: preferences.app.locale,
+      loadMessages,
+      missingWarn: !import.meta.env.PROD, // [!code --]
+      missingWarn: false, // [!code ++]
+      ...options,
+    });
+  }
+  ```
diff --git a/eims-ui/docs/src/guide/in-depth/login.md b/eims-ui/docs/src/guide/in-depth/login.md
new file mode 100644
index 0000000..adb89b7
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/login.md
@@ -0,0 +1,220 @@
+---
+outline: deep
+---
+
+# 鐧诲綍
+
+鏈枃浠嬬粛濡備綍鍘绘敼閫犺嚜宸辩殑搴旂敤绋嬪簭鐧诲綍椤典互鍙婂浣曞揩閫熺殑瀵规帴鐧诲綍椤甸潰鎺ュ彛銆�
+
+## 鐧诲綍椤甸潰璋冩暣
+
+濡傛灉浣犳兂璋冩暣鐧诲綍椤甸潰鐨勬爣棰樸�佹弿杩板拰鍥炬爣浠ュ強宸ュ叿鏍忥紝浣犲彲浠ラ�氳繃閰嶇疆 `AuthPageLayout` 缁勪欢鐨勫弬鏁版潵瀹炵幇銆�
+
+![login](/guide/login.png)
+
+鍙渶瑕佸湪搴旂敤涓嬬殑 `src/layouts/auth.vue` 鍐咃紝閰嶇疆`AuthPageLayout`鐨� `props`鍙傛暟鍗冲彲锛�
+
+```vue {2-7}
+<AuthPageLayout
+  :copyright="true"
+  :toolbar="true"
+  :toolbarList="['color', 'language', 'layout', 'theme']"
+  :app-name="appName"
+  :logo="logo"
+  :page-description="$t('authentication.pageDesc')"
+  :page-title="$t('authentication.pageTitle')"
+>
+</AuthPageLayout>
+```
+
+## 鐧诲綍琛ㄥ崟璋冩暣
+
+濡傛灉浣犳兂璋冩暣鐧诲綍琛ㄥ崟鐨勭浉鍏冲唴瀹癸紝浣犲彲浠ュ湪搴旂敤涓嬬殑 `src/views/_core/authentication/login.vue` 鍐咃紝閰嶇疆`AuthenticationLogin` 缁勪欢鍙傛暟鍗冲彲锛�
+
+```vue
+<AuthenticationLogin
+  :loading="authStore.loginLoading"
+  @submit="authStore.authLogin"
+/>
+```
+
+::: details AuthenticationLogin 缁勪欢鍙傛暟
+
+```ts
+{
+  /**
+   * @zh_CN 楠岃瘉鐮佺櫥褰曡矾寰�
+   */
+  codeLoginPath?: string;
+  /**
+   * @zh_CN 蹇樿瀵嗙爜璺緞
+   */
+  forgetPasswordPath?: string;
+
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+
+  /**
+   * @zh_CN 浜岀淮鐮佺櫥褰曡矾寰�
+   */
+  qrCodeLoginPath?: string;
+
+  /**
+   * @zh_CN 娉ㄥ唽璺緞
+   */
+  registerPath?: string;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず楠岃瘉鐮佺櫥褰�
+   */
+  showCodeLogin?: boolean;
+  /**
+   * @zh_CN 鏄惁鏄剧ず蹇樿瀵嗙爜
+   */
+  showForgetPassword?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず浜岀淮鐮佺櫥褰�
+   */
+  showQrcodeLogin?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず娉ㄥ唽鎸夐挳
+   */
+  showRegister?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず璁颁綇璐﹀彿
+   */
+  showRememberMe?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず绗笁鏂圭櫥褰�
+   */
+  showThirdPartyLogin?: boolean;
+
+  /**
+   * @zh_CN 鐧诲綍妗嗗瓙鏍囬
+   */
+  subTitle?: string;
+
+  /**
+   * @zh_CN 鐧诲綍妗嗘爣棰�
+   */
+  title?: string;
+
+}
+```
+
+:::
+
+::: tip Note
+
+濡傛灉杩欎簺閰嶇疆涓嶈兘婊¤冻浣犵殑闇�姹傦紝浣犲彲浠ヨ嚜琛屽疄鐜扮櫥褰曡〃鍗曞強鐩稿叧鐧诲綍閫昏緫鎴栬�呯粰鎴戜滑鎻愪氦 `PR`銆�
+
+:::
+
+## 鎺ュ彛瀵规帴娴佺▼
+
+杩欓噷灏嗕細蹇�熺殑浠嬬粛濡備綍蹇�熷鎺ヨ嚜宸辩殑鍚庣銆�
+
+### 鍓嶇疆鏉′欢
+
+- 棣栧厛鏂囨。鐢ㄧ殑鍚庣鏈嶅姟锛屾帴鍙h繑鍥炵殑鏍煎紡缁熶竴濡備笅锛�
+
+```ts
+interface HttpResponse<T = any> {
+  /**
+   * 0 琛ㄧず鎴愬姛 鍏朵粬琛ㄧず澶辫触
+   * 0 means success, others means fail
+   */
+  code: number;
+  data: T;
+  message: string;
+}
+```
+
+濡傛灉浣犱笉绗﹀悎杩欎釜鏍煎紡锛屼綘闇�瑕佸厛闃呰 [鏈嶅姟绔氦浜抅(../essentials/server.md) 鏂囨。锛屾敼閫犱綘鐨刞request.ts`閰嶇疆銆�
+
+- 鍏舵浣犻渶瑕佸湪鍏堝皢鏈湴浠g悊鍦板潃鏀逛负浣犵殑鐪熷疄鍚庣鍦板潃锛屼綘鍙互鍦ㄥ簲鐢ㄤ笅鐨� `vite.config.mts` 鍐呴厤缃細
+
+```ts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    vite: {
+      server: {
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // 杩欓噷鏀逛负浣犵殑鐪熷疄鎺ュ彛鍦板潃
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
+```
+
+### 鐧诲綍鎺ュ彛
+
+涓轰簡鑳芥甯哥櫥褰曪紝浣犵殑鍚庣鏈�灏戦渶瑕佹彁渚� `2-3` 涓帴鍙o細
+
+- 鐧诲綍鎺ュ彛
+
+鎺ュ彛鍦板潃鍙湪搴旂敤涓嬬殑 `src/api/core/auth` 鍐呬慨鏀癸紝浠ヤ笅涓洪粯璁ゆ帴鍙e湴鍧�锛�
+
+```ts
+/**
+ * 鐧诲綍
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
+}
+
+/** 鍙渶瑕佷繚璇佺櫥褰曟帴鍙h繑鍥炲�兼湁 `accessToken` 瀛楁鍗冲彲 */
+export interface LoginResult {
+  accessToken: string;
+}
+```
+
+- 鑾峰彇鐢ㄦ埛淇℃伅鎺ュ彛
+
+鎺ュ彛鍦板潃鍙湪搴旂敤涓嬬殑 `src/api/core/user` 鍐呬慨鏀癸紝浠ヤ笅涓洪粯璁ゆ帴鍙e湴鍧�锛�
+
+```ts
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
+
+/** 鍙渶瑕佷繚璇佺櫥褰曟帴鍙h繑鍥炲�兼湁浠ヤ笅瀛楁鍗冲彲锛屽鐨勫瓧娈靛彲浠ヨ嚜琛屼娇鐢� */
+export interface UserInfo {
+  roles: string[];
+  realName: string;
+}
+```
+
+- 鑾峰彇鏉冮檺鐮� (鍙��)
+
+杩欎釜鎺ュ彛鐢ㄤ簬鑾峰彇鐢ㄦ埛鐨勬潈闄愮爜锛屾潈闄愮爜鏄敤浜庢帶鍒剁敤鎴风殑鏉冮檺鐨勶紝鎺ュ彛鍦板潃鍙湪搴旂敤涓嬬殑 `src/api/core/auth` 鍐呬慨鏀癸紝浠ヤ笅涓洪粯璁ゆ帴鍙e湴鍧�锛�
+
+```ts
+export async function getAccessCodesApi() {
+  return requestClient.get<string[]>('/auth/codes');
+}
+```
+
+濡傛灉浣犱笉闇�瑕佽繖涓潈闄愶紝浣犲彧闇�瑕佹妸浠g爜鏀逛负杩斿洖涓�涓┖鏁扮粍鍗冲彲銆�
+
+```ts {2}
+export async function getAccessCodesApi() {
+  // 杩欓噷杩斿洖涓�涓┖鏁扮粍鍗冲彲
+  return [];
+}
+```
diff --git a/eims-ui/docs/src/guide/in-depth/theme.md b/eims-ui/docs/src/guide/in-depth/theme.md
new file mode 100644
index 0000000..82fb6fc
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/theme.md
@@ -0,0 +1,1293 @@
+# 涓婚
+
+妗嗘灦鍩轰簬 [shadcn-vue](https://www.shadcn-vue.com/themes.html) 鍜� [tailwindcss](https://tailwindcss.com/) 鏋勫缓锛屾彁渚涗簡涓板瘜鐨勪富棰橀厤缃紝鍙互閫氳繃绠�鍗曠殑閰嶇疆瀹炵幇鍚勭涓婚鍒囨崲锛屾弧瓒充釜鎬у寲闇�姹傘�傛偍鍙互閫夋嫨浣跨敤 CSS 鍙橀噺鎴� Tailwind CSS 瀹炵敤绋嬪簭绫昏繘琛屼富棰樿缃��
+
+## Css 鍙橀噺
+
+椤圭洰閬靛惊 [shadcn-vue](https://www.shadcn-vue.com/themes.html) 鐨勪富棰橀厤缃紝绀轰緥锛�
+
+```html
+<div class="bg-background text-foreground" />
+```
+
+鎴戜滑瀵归鑹蹭娇鐢ㄤ竴涓畝鍗曠殑绾﹀畾銆俙background`鍙橀噺鐢ㄤ簬缁勪欢鐨勮儗鏅鑹诧紝`foreground`鍙橀噺鐢ㄤ簬鏂囨湰棰滆壊銆�
+
+浠ヤ笅缁勪欢鐨刞background`灏嗕负`hsl(var(--primary))`锛宍foreground`灏嗕负`hsl(var(--primary-foreground))`銆�
+
+## 璇︾粏鐨凜SS鍙橀噺鍒楄〃
+
+::: warning 娉ㄦ剰
+
+css 鍙橀噺鍐呯殑棰滆壊锛屽繀椤讳娇鐢� `hsl` 鏍煎紡锛屽 `0 0% 100%`锛屼笉闇�瑕佸姞 `hsl()`鍜� `锛宍銆�
+
+:::
+
+浣犲彲浠ユ煡鐪嬩笅闈㈢殑CSS鍙橀噺鍒楄〃锛屼互浜嗚В鎵�鏈夊彲鐢ㄧ殑鍙橀噺銆�
+
+::: details 榛樿涓婚 css 鍙橀噺
+
+```css
+:root {
+  --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+    'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+  /* Default background color of <body />...etc */
+  --background: 0 0% 100%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 216 20.11% 95.47%;
+  --foreground: 210 6% 21%;
+
+  /* Background color for <Card /> */
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+
+  /* 涓婚棰滆壊 */
+
+  --primary: 212 100% 45%;
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* Secondary colors for <Button /> */
+
+  --secondary: 240 5% 96%;
+  --secondary-foreground: 240 6% 10%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 240 5% 96%;
+  --accent-hover: 200deg 10% 90%;
+  --accent-foreground: 240 6% 10%;
+
+  /* Darker color */
+  --heavy: 192deg 9.43% 89.61%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 5.9% 90%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 240deg 5.88% 90%;
+  --input-placeholder: 217 10.6% 65%;
+  --input-background: 0 0% 100%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* Border radius for card, input and buttons */
+  --radius: 0.5rem;
+
+  /* ============= custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0deg 0% 0% / 30%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  /* menu */
+  --sidebar: 0 0% 100%;
+  --sidebar-deep: 216 20.11% 95.47%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 0 0% 100%;
+
+  accent-color: var(--primary);
+  color-scheme: light;
+}
+```
+
+:::
+
+::: details 榛樿涓婚榛戞殫妯″紡 css 鍙橀噺
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Default background color of <body />...etc */
+  --background: 222.34deg 10.43% 12.27%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 220deg 13.06% 9%;
+  --foreground: 0 0% 95%;
+
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+
+  /* --card: 222.2 84% 4.9%; */
+  --card-foreground: 210 40% 98%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 222.82deg 8.43% 12.27%;
+  --popover-foreground: 210 40% 98%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+  --muted: 220deg 6.82% 17.25%;
+  --muted-foreground: 215 20.2% 65.1%;
+
+  /* 涓婚棰滆壊 */
+
+  /* --primary: 245 82% 67%; */
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* 棰滆壊娆¤ */
+  --secondary: 240 5% 17%;
+  --secondary-foreground: 0 0% 98%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 0deg 0% 100% / 8%;
+  --accent-hover: 0deg 0% 100% / 12%;
+  --accent-foreground: 0 0% 98%;
+
+  /* Darker color */
+  --heavy: 0deg 0% 100% / 12%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 3.7% 15.9%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 0deg 0% 100% / 10%;
+  --input-placeholder: 218deg 11% 65%;
+  --input-background: 0deg 0% 100% / 5%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* 鍩烘湰鍦嗚澶у皬 */
+  --radius: 0.5rem;
+
+  /* ============= Custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0deg 0% 0% / 40%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  --sidebar: 222.34deg 10.43% 12.27%;
+  --sidebar-deep: 220deg 13.06% 9%;
+  --menu: var(--sidebar);
+  --header: 222.34deg 10.43% 12.27%;
+
+  color-scheme: dark;
+}
+```
+
+:::
+
+## 瑕嗙洊榛樿鐨� CSS 鍙橀噺
+
+浣犲彧闇�瑕佸湪浣犵殑椤圭洰涓鐩栦綘鎯宠淇敼鐨� CSS 鍙橀噺鍗冲彲銆備緥濡傦紝瑕佹洿鏀归粯璁ゅ崱鐗囪儗鏅壊锛屼綘鍙互鍦ㄤ綘鐨� CSS 鏂囦欢涓坊鍔犱互涓嬪唴瀹硅繘琛岃鐩栵細
+
+### 榛樿涓婚涓�
+
+```css
+:root {
+  /* Background color for <Card /> */
+  --card: 0 0% 30%;
+}
+```
+
+### 榛戞殫妯″紡涓�
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+}
+```
+
+## 鏇存敼鍝佺墝涓昏壊
+
+::: tip
+
+- 闇�瑕佷娇鐢� `hsl` 鏍煎紡棰滆壊鏍煎紡銆�
+- 淇敼鍚庨渶瑕佹竻绌虹紦瀛樻墠鍙敓鏁堛��
+- 浣犲彲浠ュ�熷姪 [绗笁鏂瑰伐鍏穄(https://www.w3schools.com/colors/colors_hsl.asp)鏉ヨ浆鎹㈤鑹层��
+
+:::
+
+鍙渶瑕佸湪搴旂敤鐩綍涓嬬殑`preferences.ts`锛岃嚜瀹氫箟閰嶇疆涓昏壊鍗冲彲锛�
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    // 閿欒鑹�
+    colorDestructive: 'hsl(348 100% 61%)',
+    // 涓婚鑹�
+    colorPrimary: 'hsl(212 100% 45%)',
+    // 鎴愬姛鑹�
+    colorSuccess: 'hsl(144 57% 58%)',
+    // 璀﹀憡鑹�
+    colorWarning: 'hsl(42 84% 61%)',
+  },
+});
+```
+
+## 鍐呯疆涓婚
+
+妗嗘灦涓唴缃簡澶氱涓婚锛屼綘鍙互鍦╜preferences.ts`涓繘琛岄厤缃細
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    builtinType: 'default',
+  },
+});
+```
+
+### 鍐呯疆涓婚鍒楄〃
+
+妗嗘灦鍐呯疆浜� 16绉嶄富棰橈紝涓旇繕鏀寔鑷畾涔変富棰樸�傜悊璁轰笂锛屼綘鍙互鏃犻檺鍒剁殑鎵╁睍涓婚銆�
+
+::: details 鍐呯疆涓婚绫诲瀷鍒楄〃
+
+```ts
+type BuiltinThemeType =
+  | 'custom'
+  | 'deep-blue'
+  | 'deep-green'
+  | 'default'
+  | 'gray'
+  | 'green'
+  | 'neutral'
+  | 'orange'
+  | 'pink'
+  | 'red'
+  | 'rose'
+  | 'sky-blue'
+  | 'slate'
+  | 'stone'
+  | 'violet'
+  | 'yellow'
+  | 'zinc'
+  | (Record<never, never> & string);
+```
+
+:::
+
+::: details 鍐呯疆涓婚css鍙橀噺 - light
+
+```css
+:root {
+  --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+    'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+  /* Default background color of <body />...etc */
+  --background: 0 0% 100%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 216 20.11% 95.47%;
+  --foreground: 222 84% 5%;
+
+  /* Background color for <Card /> */
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%; */
+
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+
+  /* 涓婚棰滆壊 */
+
+  --primary: 212 100% 45%;
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* Secondary colors for <Button /> */
+
+  --secondary: 240 5% 96%;
+  --secondary-foreground: 240 6% 10%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 240 5% 96%;
+  --accent-hover: 200deg 10% 90%;
+  --accent-foreground: 240 6% 10%;
+
+  /* Darker color */
+  --heavy: 192deg 9.43% 89.61%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 5.9% 90%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 240deg 5.88% 90%;
+  --input-placeholder: 217 10.6% 65%;
+  --input-background: 0 0% 100%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* Border radius for card, input and buttons */
+  --radius: 0.5rem;
+
+  /* ============= custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0deg 0% 0% / 30%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  /* menu */
+  --sidebar: 0 0% 100%;
+  --sidebar-deep: 0 0% 100%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 0 0% 100%;
+
+  accent-color: var(--primary);
+  color-scheme: light;
+}
+
+[data-theme='violet'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 262.1 83.3% 57.8%;
+}
+
+[data-theme='pink'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='rose'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='sky-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='deep-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='deep-green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='orange'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 24.6 95% 53.1%;
+}
+
+[data-theme='yellow'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 20 14.3% 4.1%;
+}
+
+[data-theme='zinc'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 240 5.9% 10%;
+}
+
+[data-theme='neutral'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 0 0% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 0 0% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 0 0% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 0 0% 96.1%;
+  --secondary-foreground: 0 0% 9%;
+  --muted: 0 0% 96.1%;
+  --muted-foreground: 0 0% 45.1%;
+  --accent: 0 0% 96.1%;
+  --accent-foreground: 0 0% 9%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 89.8%;
+  --input: 0 0% 89.8%;
+  --ring: 0 0% 3.9%;
+}
+
+[data-theme='slate'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 222.2 84% 4.9%;
+}
+
+[data-theme='gray'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 224 71.4% 4.1%;
+}
+```
+
+:::
+
+::: details 鍐呯疆涓婚css鍙橀噺 - dark
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Default background color of <body />...etc */
+  --background: 222.34deg 10.43% 12.27%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 220deg 13.06% 9%;
+  --foreground: 0 0% 95%;
+
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+
+  /* --card: 222.2 84% 4.9%; */
+  --card-foreground: 210 40% 98%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 222.82deg 8.43% 12.27%;
+  --popover-foreground: 210 40% 98%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 220deg 6.82% 17.25%; */
+
+  /* --muted-foreground: 215 20.2% 65.1%; */
+
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+
+  /* 涓婚棰滆壊 */
+
+  /* --primary: 245 82% 67%; */
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 0 78% 68%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* 棰滆壊娆¤ */
+  --secondary: 240 5% 17%;
+  --secondary-foreground: 0 0% 98%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 216 5% 19%;
+  --accent-hover: 216 5% 24%;
+  --accent-foreground: 0 0% 98%;
+
+  /* Darker color */
+  --heavy: 216 5% 24%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 3.7% 22%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 0deg 0% 100% / 10%;
+  --input-placeholder: 218deg 11% 65%;
+  --input-background: 0deg 0% 100% / 5%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* 鍩烘湰鍦嗚澶у皬 */
+  --radius: 0.5rem;
+
+  /* ============= Custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0deg 0% 0% / 40%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  --sidebar: 222.34deg 10.43% 12.27%;
+  --sidebar-deep: 220deg 13.06% 9%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 222.34deg 10.43% 12.27%;
+
+  color-scheme: dark;
+}
+
+.dark[data-theme='violet'],
+[data-theme='violet'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 263.4 70% 50.4%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
+
+.dark[data-theme='pink'],
+[data-theme='pink'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 0 0% 9%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 346.8 77.2% 49.8%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='rose'],
+[data-theme='rose'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 85.7% 97.3%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 72.2% 50.6%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='sky-blue'],
+[data-theme='sky-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='deep-blue'],
+[data-theme='deep-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='green'],
+[data-theme='green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='deep-green'],
+[data-theme='deep-green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='orange'],
+[data-theme='orange'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 0 72.2% 50.6%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 20.5 90.2% 48.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='yellow'],
+[data-theme='yellow'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 35.5 91.7% 32.9%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='zinc'],
+[data-theme='zinc'] .dark {
+  --background: 240 10% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 240 10% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 240 10% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 240 5.9% 10%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 240 3.7% 15.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 240 4.9% 83.9%;
+  --sidebar: 240 10% 3.9%;
+  --sidebar-deep: 240 10% 3.9%;
+  --header: 240 4.9% 83.9%;
+}
+
+.dark[data-theme='neutral'],
+[data-theme='neutral'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 0% 9%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 0% 83.1%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='slate'],
+[data-theme='slate'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 222.2 47.4% 11.2%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 212.7 26.8% 83.9;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='gray'],
+[data-theme='gray'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 220.9 39.3% 11%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 216 12.2% 83.9%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
+```
+
+:::
+
+## 鏂板涓婚
+
+鎯宠鏂板涓婚锛屽彧闇�鎸夌収浠ヤ笅姝ラ杩涜锛�
+
+- 鍦ㄥ簲鐢ㄧ殑 `src/preferences.ts`鍐呮柊澧炰竴涓富棰橀厤缃��
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    builtinType: 'my-theme',
+  },
+});
+```
+
+- 鍦ㄤ綘鐨刢ss鏂囦欢涓紝鏂板涓婚鐨刢ss鍙橀噺銆�
+
+```css
+/* light */
+[data-theme='my-theme'] {
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 262.1 83.3% 57.8%;
+}
+
+/* dark */
+.dark[data-theme='my-theme'],
+[data-theme='my-theme'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 0 62.8% 30.6%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 263.4 70% 50.4%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+}
+```
+
+## 榛戞殫妯″紡
+
+妗嗘灦涓唴缃簡澶氱涓婚锛屼綘鍙互鍦╜preferences.ts`涓繘琛岄厤缃紝榛戞殫涓婚鍚屾牱浼氳鍙朿ss鍙橀噺鏉ヨ繘琛岄厤缃細
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  theme: {
+    mode: 'dark',
+  },
+});
+```
+
+## 鑷畾涔変晶杈规爮棰滆壊
+
+渚ц竟鏍忛鑹查�氳繃`--sidebar`鍙橀噺鏉ラ厤缃�
+
+### 榛樿涓婚涓�
+
+```css
+:root {
+  --sidebar: 0 0% 100%;
+}
+```
+
+### 榛戞殫妯″紡涓�
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --sidebar: 222.34deg 10.43% 12.27%;
+}
+```
+
+## 鑷畾涔夐《鏍忛鑹�
+
+渚ц竟鏍忛鑹查�氳繃`--header`鍙橀噺鏉ラ厤缃�
+
+### 榛樿涓婚涓�
+
+```css
+:root {
+  --header: 0 0% 100%;
+}
+```
+
+### 榛戞殫妯″紡涓�
+
+```css
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  --header: 222.34deg 10.43% 12.27%;
+}
+```
+
+## 鑹插急妯″紡
+
+涓�鑸敤浜庣壒娈婂満鏅紝灏嗚缃负鑹插急妯″紡锛屼綘鍙互鍦╜preferences.ts`涓繘琛岄厤缃細
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    colorWeakMode: true,
+  },
+});
+```
+
+## 鐏拌壊妯″紡
+
+涓�鑸敤浜庣壒娈婂満鏅紝灏嗙綉椤电疆鐏帮紝浣犲彲浠ュ湪`preferences.ts`涓繘琛岄厤缃細
+
+```ts
+import { defineOverridesPreferences } from '@vben/preferences';
+
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    colorGrayMode: true,
+  },
+});
+```
diff --git a/eims-ui/docs/src/guide/in-depth/ui-framework.md b/eims-ui/docs/src/guide/in-depth/ui-framework.md
new file mode 100644
index 0000000..ce05608
--- /dev/null
+++ b/eims-ui/docs/src/guide/in-depth/ui-framework.md
@@ -0,0 +1,17 @@
+# 缁勪欢搴撳垏鎹�
+
+`Vue Admin` 鏀寔浣犺嚜鐢遍�夋嫨缁勪欢搴擄紝鐩墠婕旂ず绔欑偣鐨勯粯璁ょ粍浠跺簱鏄� `Ant Design Vue`锛屼笌鏃х増鏈繚鎸佷竴鑷淬�傚悓鏃舵鏋惰繕鍐呯疆浜� `Element Plus` 鐗堟湰鍜� `Naive UI` 鐗堟湰锛屼綘鍙互鏍规嵁鑷繁鐨勫枩濂介�夋嫨銆�
+
+## 鏂板缁勪欢搴撳簲鐢�
+
+濡傛灉浣犳兂鐢ㄥ叾浠栧埆鐨勭粍浠跺簱锛屼綘鍙渶瑕佹寜涓�涓嬫楠よ繘琛屾搷浣滐細
+
+1. 鍦╜apps`鍐呭垱寤轰竴涓柊鐨勬枃浠跺す锛屼緥濡俙apps/web-xxx`銆�
+2. 鏇存敼`apps/web-xxx/package.json`鐨刞name`瀛楁涓篳web-xxx`銆�
+3. 绉婚櫎鍏朵粬缁勪欢搴撲緷璧栧強浠g爜锛屽苟鐢ㄤ綘鐨勭粍浠跺簱杩涜鏇挎崲鐩稿簲閫昏緫锛岄渶瑕佹敼鍔ㄧ殑鍦版柟涓嶅銆�
+4. 璋冩暣`locales`鍐呯殑璇█鏂囦欢銆�
+5. 璋冩暣 `app.vue` 鍐呯殑缁勪欢銆�
+6. 鑷閫傞厤缁勪欢搴撶殑涓婚锛屼笌 `Vben Admin` 濂戝悎銆�
+7. 璋冩暣 `.env` 鍐呯殑搴旂敤鍚�
+8. 鍦ㄥぇ浠撴牴鐩綍澧炲姞 `dev:xxx` 鑴氭湰
+9. 鎵ц `pnpm install` 瀹夎渚濊禆
diff --git a/eims-ui/docs/src/guide/introduction/changelog.md b/eims-ui/docs/src/guide/introduction/changelog.md
new file mode 100644
index 0000000..782056b
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/changelog.md
@@ -0,0 +1,3 @@
+# 鏇存柊鏃ュ織
+
+TODO
diff --git a/eims-ui/docs/src/guide/introduction/quick-start.md b/eims-ui/docs/src/guide/introduction/quick-start.md
new file mode 100644
index 0000000..747c524
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/quick-start.md
@@ -0,0 +1,111 @@
+---
+outline: deep
+---
+
+# 蹇�熷紑濮� {#quick-start}
+
+## 鍓嶇疆鍑嗗
+
+::: info 鐜瑕佹眰
+
+鍦ㄥ惎鍔ㄩ」鐩墠锛屼綘闇�瑕佺‘淇濅綘鐨勭幆澧冩弧瓒充互涓嬭姹傦細
+
+- [Node.js](https://nodejs.org/en) 20.15.0 鍙婁互涓婄増鏈紝鎺ㄨ崘浣跨敤 [fnm](https://github.com/Schniz/fnm) 銆� [nvm](https://github.com/nvm-sh/nvm) 鎴栬�呯洿鎺ヤ娇鐢╗pnpm](https://pnpm.io/cli/env) 杩涜鐗堟湰绠$悊銆�
+- [Git](https://git-scm.com/) 浠绘剰鐗堟湰銆�
+
+楠岃瘉浣犵殑鐜鏄惁婊¤冻浠ヤ笂瑕佹眰锛屼綘鍙互閫氳繃浠ヤ笅鍛戒护鏌ョ湅鐗堟湰锛�
+
+```bash
+# 鍑虹幇鐩稿簲 node LTS鐗堟湰鍗冲彲
+node -v
+# 鍑虹幇鐩稿簲 git 鐗堟湰鍗冲彲
+git -v
+```
+
+:::
+
+## 鍚姩椤圭洰
+
+### 鑾峰彇婧愮爜
+
+::: code-group
+
+```sh [GitHub]
+# clone 浠g爜
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+```sh [Gitee]
+# clone 浠g爜
+# Gitee 鐨勪唬鐮佸彲鑳戒笉鏄渶鏂扮殑
+git clone https://gitee.com/annsion/vue-vben-admin.git
+```
+
+:::
+
+::: danger 娉ㄦ剰
+
+娉ㄦ剰瀛樻斁浠g爜鐨勭洰褰曞強鎵�鏈夌埗绾х洰褰曚笉鑳藉瓨鍦ㄤ腑鏂囥�侀煩鏂囥�佹棩鏂囦互鍙婄┖鏍硷紝鍚﹀垯瀹夎渚濊禆鍚庡惎鍔ㄤ細鍑洪敊銆�
+
+:::
+
+### 瀹夎渚濊禆
+
+鍦ㄤ綘鐨勪唬鐮佺洰褰曞唴鎵撳紑缁堢锛屽苟鎵ц浠ヤ笅鍛戒护:
+
+```bash
+# 杩涘叆椤圭洰鐩綍
+cd vue-vben-admin
+
+# 浣跨敤椤圭洰鎸囧畾鐨刾npm鐗堟湰杩涜渚濊禆瀹夎
+corepack enable
+
+# 瀹夎渚濊禆
+pnpm install
+```
+
+::: tip 娉ㄦ剰
+
+- 椤圭洰鍙敮鎸佷娇鐢� `pnpm` 杩涜渚濊禆瀹夎锛岄粯璁や細浣跨敤 `corepack` 鏉ュ畨瑁呮寚瀹氱増鏈殑 `pnpm`銆�:
+- 濡傛灉浣犵殑缃戠粶鐜鏃犳硶璁块棶npm婧愶紝浣犲彲浠ヨ缃郴缁熺殑鐜鍙橀噺`COREPACK_REGISTRY=https://registry.npmmirror.com`锛岀劧鍚庡啀鎵ц`pnpm install`銆�
+- 濡傛灉浣犱笉鎯充娇鐢╜corepack`锛屼綘闇�瑕佺鐢╜corepack`锛岀劧鍚庝娇鐢ㄤ綘鑷繁鐨刞pnpm`杩涜瀹夎銆�
+
+:::
+
+### 杩愯椤圭洰
+
+#### 閫夋嫨椤圭洰
+
+鎵ц浠ヤ笅鍛戒护杩愯椤圭洰:
+
+```bash
+# 鍚姩椤圭洰
+pnpm dev
+```
+
+姝ゆ椂锛屼綘浼氱湅鍒扮被浼煎涓嬬殑杈撳嚭锛岄�夋嫨浣犻渶瑕佽繍琛岀殑椤圭洰锛�
+
+```bash
+鈹�
+鈼�  Select the app you need to run [dev]:
+鈹�  鈼� @vben/web-antd
+鈹�  鈼� @vben/web-ele
+鈹�  鈼� @vben/web-naive
+鈹�  鈼� @vben/docs
+鈹�  鈼� @vben/playground
+鈹�
+```
+
+鐜板湪锛屼綘鍙互鍦ㄦ祻瑙堝櫒璁块棶 `http://localhost:5555` 鏌ョ湅椤圭洰銆�
+
+#### 杩愯鎸囧畾椤圭洰
+
+濡傛灉浣犱笉鎯抽�夋嫨椤圭洰锛屽彲浠ョ洿鎺ヨ繍琛屼互涓嬪懡浠よ繍琛屼綘闇�瑕佺殑搴旂敤锛�
+
+```bash
+pnpm run dev:antd
+pnpm run dev:ele
+pnpm run dev:naive
+pnpm run dev:docs
+pnpm run dev:play
+```
diff --git a/eims-ui/docs/src/guide/introduction/roadmap.md b/eims-ui/docs/src/guide/introduction/roadmap.md
new file mode 100644
index 0000000..6aa9896
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/roadmap.md
@@ -0,0 +1,3 @@
+# 璺嚎鍥�
+
+TODO:
diff --git a/eims-ui/docs/src/guide/introduction/thin.md b/eims-ui/docs/src/guide/introduction/thin.md
new file mode 100644
index 0000000..4db0e3b
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/thin.md
@@ -0,0 +1,94 @@
+---
+outline: deep
+---
+
+# 绮剧畝鐗堟湰
+
+浠� `5.0` 鐗堟湰寮�濮嬶紝鎴戜滑涓嶅啀鎻愪緵绮剧畝鐨勪粨搴撴垨鑰呭垎鏀�傛垜浠殑鐩爣鏄彁渚涗竴涓洿鍔犱竴鑷寸殑寮�鍙戜綋楠岋紝鍚屾椂鍑忓皯缁存姢鎴愭湰銆傚湪杩欓噷锛屾垜浠皢濡備綍浠嬬粛鑷繁鐨勯」鐩紝濡備綍鍘荤簿绠�浠ュ強绉婚櫎涓嶉渶瑕佺殑鍔熻兘銆�
+
+## 搴旂敤绮剧畝
+
+棣栧厛锛岀‘璁や綘闇�瑕佺殑 `UI` 缁勪欢搴撶増鏈紝鐒跺悗鍒犻櫎瀵瑰簲鐨勫簲鐢紝姣斿浣犻�夋嫨浣跨敤 `Ant Design Vue`锛岄偅涔堜綘鍙互鍒犻櫎鍏朵粬搴旂敤锛� 鍙渶瑕佸垹闄や笅闈袱涓枃浠跺す鍗冲彲锛�
+
+```bash
+apps/web-ele
+apps/web-naive
+
+```
+
+::: tip
+
+濡傛灉椤圭洰娌℃湁鍐呯疆浣犻渶瑕佺殑 `UI` 缁勪欢搴撳簲鐢紝浣犲彲浠ョ洿鎺ュ叏閮ㄥ垹闄ゅ叾浠栧簲鐢ㄣ�傜劧鍚庤嚜琛屾柊寤哄簲鐢ㄥ嵆鍙��
+
+:::
+
+## 婕旂ず浠g爜绮剧畝
+
+濡傛灉浣犱笉闇�瑕佹紨绀轰唬鐮侊紝浣犲彲浠ョ洿鎺ュ垹闄ょ殑`playground`鏂囦欢澶广��
+
+## 鏂囨。绮剧畝
+
+濡傛灉浣犱笉闇�瑕佹枃妗o紝浣犲彲浠ョ洿鎺ュ垹闄docs`鏂囦欢澶广��
+
+## Mock 鏈嶅姟绮剧畝
+
+濡傛灉浣犱笉闇�瑕乣Mock`鏈嶅姟锛屼綘鍙互鐩存帴鍒犻櫎`apps/backend-mock`鏂囦欢澶广�傚悓鏃跺湪浣犵殑搴旂敤涓媊.env.development`鏂囦欢涓垹闄VITE_NITRO_MOCK`鍙橀噺銆�
+
+```bash
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=false
+```
+
+## 瀹夎渚濊禆
+
+鍒拌繖閲岋紝浣犲凡缁忓畬鎴愪簡绮剧畝鎿嶄綔锛屾帴涓嬫潵浣犲彲浠ュ畨瑁呬緷璧栵紝骞跺惎鍔ㄤ綘鐨勯」鐩細
+
+```bash
+# 鏍圭洰褰曚笅鎵ц
+pnpm install
+
+```
+
+## 鍛戒护璋冩暣
+
+鍦ㄧ簿绠�鍚庯紝浣犲彲鑳介渶瑕佹牴鎹綘鐨勯」鐩皟鏁村懡浠わ紝鍦ㄦ牴鐩綍涓嬬殑`package.json`鏂囦欢涓紝浣犲彲浠ヨ皟鏁碻scripts`瀛楁锛岀Щ闄や綘涓嶉渶瑕佺殑鍛戒护銆�
+
+```json
+{
+  "scripts": {
+    "build:antd": "pnpm run build --filter=@vben/web-antd",
+    "build:docs": "pnpm run build --filter=@vben/docs",
+    "build:ele": "pnpm run build --filter=@vben/web-ele",
+    "build:naive": "pnpm run build --filter=@vben/web-naive",
+    "build:play": "pnpm run build --filter=@vben/playground",
+    "dev:antd": "pnpm -F @vben/web-antd run dev",
+    "dev:docs": "pnpm -F @vben/docs run dev",
+    "dev:ele": "pnpm -F @vben/web-ele run dev",
+    "dev:play": "pnpm -F @vben/playground run dev",
+    "dev:naive": "pnpm -F @vben/web-naive run dev"
+  }
+}
+```
+
+## 鍏朵粬
+
+濡傛灉浣犳兂鏇磋繘涓�姝ョ簿绠�锛屼綘鍙互鍒犻櫎鍙傝�冧竴涓嬫枃浠舵垨鑰呮枃浠跺す鐨勪綔鐢紝鍒ゆ柇鑷繁鏄惁闇�瑕侊紝涓嶉渶瑕佸垹闄ゅ嵆鍙細
+
+- `.changeset` 鏂囦欢澶圭敤浜庣鐞嗙増鏈彉鏇�
+- `.github` 鏂囦欢澶圭敤浜庡瓨鏀� GitHub 鐨勯厤缃枃浠�
+- `.vscode` 鏂囦欢澶圭敤浜庡瓨鏀� VSCode 鐨勯厤缃枃浠讹紝濡傛灉浣犱娇鐢ㄥ叾浠栫紪杈戝櫒锛屽彲浠ュ垹闄�
+- `./scripts/deploy` 鏂囦欢澶圭敤浜庡瓨鏀鹃儴缃茶剼鏈紝濡傛灉浣犱笉闇�瑕乨ocker閮ㄧ讲锛屽彲浠ュ垹闄�
+
+## 搴旂敤绮剧畝
+
+褰撲綘纭畾浜嗘煇涓簲鐢紝浣犺繕鍙互杩涗竴姝ョ簿绠�锛�
+
+### 鍒犻櫎涓嶉渶瑕佺殑璺敱鍙婇〉闈�
+
+- 鍦ㄥ簲鐢ㄧ殑 `src/router/routes` 鏂囦欢涓紝浣犲彲浠ュ垹闄や笉闇�瑕佺殑璺敱銆傚叾涓� `core` 鏂囦欢澶瑰唴锛屽鏋滃彧闇�瑕佺櫥褰曞拰蹇樿瀵嗙爜锛屼綘鍙互鍒犻櫎鍏朵粬璺敱锛屽蹇樿瀵嗙爜銆佹敞鍐岀瓑銆傝矾鐢卞垹闄ゅ悗锛屼綘鍙互鍒犻櫎瀵瑰簲鐨勯〉闈㈡枃浠讹紝鍦� `src/views/_core` 鏂囦欢澶逛腑銆�
+
+- 鍦ㄥ簲鐢ㄧ殑 `src/router/routes` 鏂囦欢涓紝浣犲彲浠ユ寜闇�姹傚垹闄や笉闇�瑕佺殑璺敱锛屽`demos`銆乣vben` 鐩綍绛夈�傝矾鐢卞垹闄ゅ悗锛屼綘鍙互鍒犻櫎瀵瑰簲鐨勯〉闈㈡枃浠讹紝鍦� `src/views` 鏂囦欢澶逛腑銆�
+
+### 鍒犻櫎涓嶉渶瑕佺殑缁勪欢
+
+- 鍦ㄥ簲鐢ㄧ殑 `packages/effects/common-ui/src/ui` 鏂囦欢澶逛腑锛屼綘鍙互鍒犻櫎涓嶉渶瑕佺殑缁勪欢锛屽`about`銆乣dashboard` 鐩綍绛夈�傚垹闄や箣鍓嶈鍏堢‘淇濅綘鐨勮矾鐢变腑娌℃湁寮曠敤鍒拌繖浜涚粍浠躲��
diff --git a/eims-ui/docs/src/guide/introduction/vben.md b/eims-ui/docs/src/guide/introduction/vben.md
new file mode 100644
index 0000000..a4a5f97
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/vben.md
@@ -0,0 +1,49 @@
+# 鍏充簬 Vben Admin
+
+::: info 浣犳鍦ㄩ槄璇荤殑鏄� [Vben Admin](https://github.com/vbenjs/vue-vben-admin) `5.0`鐗堟湰鐨勬枃妗o紒
+
+- Vben Admin 2.x 鐩墠宸插瓨妗o紝浠呰繘琛岄噸澶ч棶棰樹慨澶嶃��
+- 鏂扮増鏈笌鏃х増鏈笉鍏煎锛屽鏋滀綘浣跨敤鐨勬槸鏃х増鏈紙v2銆乿3锛夛紝璇锋煡鐪� [Vue Vben Admin 2.x 鏂囨。](https://doc.vvbin.cn)
+- 濡傚彂鐜版枃妗f湁璇紝娆㈣繋鎻愪氦 [issue](https://github.com/vbenjs/vue-vben-admin/issues) 甯姪鎴戜滑鏀硅繘銆�
+- 濡傛灉浣犲彧鏄兂浣撻獙涓�涓嬶紝浣犲彲浠ユ煡鐪媅蹇�熷紑濮媇(./quick-start.md)銆�
+
+:::
+
+[Vben Admin](https://github.com/vbenjs/vue-vben-admin) 鏄竴涓熀浜� [Vue3.0](https://github.com/vuejs/core)銆乕Vite](https://github.com/vitejs/vite)銆� [TypeScript](https://www.typescriptlang.org/) 鐨勪腑鍚庡彴瑙e喅鏂规锛岀洰鏍囨槸涓哄紑鍙戜腑澶у瀷椤圭洰鎻愪緵寮�绠卞嵆鐢ㄧ殑瑙e喅鏂规銆傚寘鎷簩娆″皝瑁呯粍浠躲�乽tils銆乭ooks銆佸姩鎬佽彍鍗曘�佹潈闄愭牎楠屻�佸涓婚閰嶇疆銆佹寜閽骇鍒潈闄愭帶鍒剁瓑鍔熻兘銆傞」鐩細浣跨敤鍓嶇杈冩柊鐨勬妧鏈爤锛屽彲浠ヤ綔涓洪」鐩殑鍚姩妯℃澘锛屼互甯姪浣犲揩閫熸惌寤轰紒涓氱骇涓悗鍙颁骇鍝佸師鍨嬨�備篃鍙互浣滀负涓�涓ず渚嬶紝鐢ㄤ簬瀛︿範 `vue3`銆乣vite`銆乣ts` 绛変富娴佹妧鏈�傝椤圭洰浼氭寔缁窡杩涙渶鏂版妧鏈紝骞跺皢鍏跺簲鐢ㄥ湪椤圭洰涓��
+
+## 鐗圭偣
+
+- **鏈�鏂版妧鏈爤**锛氫娇鐢� `Vue3`銆乣Vite`銆乣TypeScript` 绛夊墠绔墠娌挎妧鏈紑鍙戙��
+- **鍥介檯鍖�**锛氬唴缃畬鍠勭殑鍥介檯鍖栨柟妗堬紝鏀寔澶氳瑷�鍒囨崲銆�
+- **鏉冮檺楠岃瘉**锛氬畬鍠勭殑鏉冮檺楠岃瘉鏂规锛屾寜閽骇鍒潈闄愭帶鍒躲��
+- **澶氫富棰�**锛氬唴缃绉嶄富棰橀厤缃拰榛戞殫妯″紡锛屾弧瓒充釜鎬у寲闇�姹傘��
+- **鍔ㄦ�佽彍鍗�**锛氭敮鎸佸姩鎬佽彍鍗曪紝鍙互鏍规嵁鏉冮檺閰嶇疆鏄剧ず鑿滃崟銆�
+- **Mock 鏁版嵁**锛氬熀浜� `Nitro` 鐨勬湰鍦伴珮鎬ц兘 Mock 鏁版嵁鏂规銆�
+- **缁勪欢涓板瘜**锛氭彁渚涗簡涓板瘜鐨勭粍浠讹紝鍙互婊¤冻澶ч儴鍒嗙殑涓氬姟闇�姹傘��
+- **瑙勮寖**锛氫唬鐮佽鑼冿紝浣跨敤 `ESLint`銆乣Prettier`銆乣Stylelint`銆乣Publint`銆乣CSpell` 绛夊伐鍏蜂繚璇佷唬鐮佽川閲忋��
+- **宸ョ▼鍖�**锛氫娇鐢� `Pnpm Monorepo`銆乣TurboRepo`銆乣Changeset` 绛夊伐鍏凤紝鎻愰珮寮�鍙戞晥鐜囥��
+- **澶歎I搴撴敮鎸�**锛氭敮鎸� `Ant Design Vue`銆乣Element Plus`銆乣Naive` 绛変富娴� UI 搴擄紝涓嶅啀闄愬埗浜庣壒瀹氭鏋躲��
+
+## 娴忚鍣ㄦ敮鎸�
+
+- **鏈湴寮�鍙�**鎺ㄨ崘浣跨敤`Chrome 鏈�鏂扮増`娴忚鍣紝**涓嶆敮鎸�**`Chrome 80`浠ヤ笅鐗堟湰銆�
+
+- **鐢熶骇鐜**鏀寔鐜颁唬娴忚鍣紝涓嶆敮鎸� IE銆�
+
+| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px"  />](http://godban.github.io/browsers-support-badges/)IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Safari |
+| :-: | :-: | :-: | :-: | :-: |
+| 涓嶆敮鎸� | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
+
+## 璐$尞
+
+- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) 杩樺湪鎸佺画鏇存柊涓紝鏈」鐩杩庢偍鐨勫弬涓庯紝鍏卞悓缁存姢锛岄�愭瀹屽杽锛屾墦閫犳洿濂界殑涓悗鍙拌В鍐虫柟妗堛��
+- 濡傛灉浣犳湁鍏磋叮鍔犲叆鎴戜滑锛屽彲浠ラ�氳繃浠ヤ笅鏂瑰紡寮�濮嬶紝鎴戜滑浼氭牴鎹綘鐨勬椿璺冨害閭�璇蜂綘鍔犲叆銆�
+
+::: info 鍔犲叆鎴戜滑
+
+- 闀挎湡鎻愪氦 `PR`銆�
+- 鎻愪緵鏈変环鍊肩殑寤鸿銆�
+- 鍙備笌璁ㄨ锛屽府鍔╄В鍐� `issue`銆�
+- 鍏卞悓缁存姢鏂囨。銆�
+
+:::
diff --git a/eims-ui/docs/src/guide/introduction/why.md b/eims-ui/docs/src/guide/introduction/why.md
new file mode 100644
index 0000000..4191b3e
--- /dev/null
+++ b/eims-ui/docs/src/guide/introduction/why.md
@@ -0,0 +1,23 @@
+# 涓轰粈涔堥�夋嫨鎴戜滑?
+
+::: info 鍐欏湪鍓嶉潰
+
+鎴戜滑涓嶄細鍘诲拰鍏朵粬妗嗘灦鍋氭瘮杈冦�傛垜浠涓烘瘡涓鏋堕兘鏈夎嚜宸辩殑鐗圭偣锛岄�傚悎涓嶅悓鐨勫満鏅�傛垜浠殑鐩爣鏄彁渚涗竴涓畝鍗曘�佹槗鐢ㄧ殑妗嗘灦锛岃寮�鍙戣�呭彲浠ュ揩閫熶笂鎵嬶紝涓撴敞浜庝笟鍔¢�昏緫鐨勫紑鍙戙�傛墍浠ユ垜浠彧浼氫笉鏂畬鍠勫拰浼樺寲鎴戜滑鐨勬鏋讹紝鎻愪緵鏇村ソ鐨勪綋楠屻��
+
+:::
+
+鎴戜滑鑷村姏浜庝负寮�鍙戣�呮彁渚涗竴涓珮鏁堛�佺幇浠c�佹槗鐢ㄧ殑鍓嶇妗嗘灦銆傛垜浠殑瑙e喅鏂规鍩轰簬鏈�鏂扮殑鎶�鏈爤锛屽 Vue3銆乂ite 鍜� TypeScript锛岀‘淇濇偍鍦ㄦ瀯寤洪」鐩椂濮嬬粓璧板湪鎶�鏈殑鍓嶆部銆傚悓鏃讹紝鎴戜滑娉ㄩ噸浠g爜鐨勮川閲忎笌瑙勮寖锛岄�氳繃涓ユ牸鐨勫伐鍏烽摼淇濊瘉浠g爜鐨勪竴鑷存�у拰鍙淮鎶ゆ�с�傛棤璁烘槸鍒濆垱椤圭洰杩樻槸浼佷笟绾у簲鐢紝鎴戜滑鐨勬鏋堕兘鑳藉府鍔╂偍蹇�熸瀯寤恒�佽凯浠e拰閮ㄧ讲銆�
+
+## 妗嗘灦鍘嗙▼
+
+浠� Vue Vben Admin 1.x 鐗堟湰寮�濮嬶紝妗嗘灦缁忓巻浜嗚澶氳凯浠e拰浼樺寲銆備粠涓�寮�濮嬩娇鐢� `Vite 0.x` 鐗堟湰锛屾病鏈夌幇鎴愮殑鎻掍欢锛屽紑鍙戜簡寰堝鑷畾涔夋彃浠舵潵寮ュ悎 Webpack 鍜� Vite 涔嬮棿鐨勫樊寮傘�傝櫧鐒跺緢澶氱幇鍦ㄥ凡缁忚浠f浛锛屼絾鏄垜浠殑鍒濊》涓�鐩存病鏈夊彉锛屽氨鏄彁渚涗竴涓畝鍗曘�佹槗鐢ㄧ殑妗嗘灦銆�
+
+铏界劧涓棿鏈夋鏃堕棿鐢辩ぞ鍖虹淮鎶わ紝浣嗘垜浠竴鐩村瘑鍒囧叧娉� Vue Vben Admin 鐨勫彂灞曘�傝璇佷簡璁稿寮�鍙戣�呬娇鐢� Vben Admin锛屽苟鎻愪緵浜嗚澶氬疂璐电殑寤鸿鍜屽弽棣堛�傞潪甯告劅璋㈠ぇ瀹剁殑鏀寔鍜岃础鐚紝杩欎簺閮芥槸鎴戜滑鎸佺画鏀硅繘 Vben Admin 鐨勫姩鍔涖�傛柊鐗堟湰涓紝鎴戜滑鎸佺画鏀堕泦鐢ㄦ埛鍙嶉锛岄噸鏂板紑濮嬶紝涓嶆柇浼樺寲妗嗘灦锛屼互鎻愪緵鏇村ソ鐨勭敤鎴蜂綋楠屻�傛垜浠殑鐩爣鏄寮�鍙戣�呰兘澶熷揩閫熶笂鎵嬶紝涓撴敞浜庝笟鍔¢�昏緫鐨勫紑鍙戙��
+
+## 鍗曞厓娴嬭瘯
+
+鍗曞厓娴嬭瘯鏄‘淇濅唬鐮佽川閲忕殑鍩虹煶銆傚湪寮�鍙戣繃绋嬩腑缂栧啓鍜屾墽琛屽崟鍏冩祴璇曪紝浠ユ崟鎹夋綔鍦ㄧ殑閿欒骞舵彁鍗囦唬鐮佺殑鍙潬鎬с�傛鏋舵牳蹇冮�昏緫浣跨敤 `vitest` 鍋氫簡鍗曞厓娴嬭瘯锛屽苟鍦ㄩ�愭澧炲姞瑕嗙洊鐜囥�傞�氳繃鍗曞厓娴嬭瘯锛屽彲浠ユ斁蹇冨湴杩涜浠g爜閲嶆瀯锛屽噺灏戝洖褰掗棶棰橈紝浠庤�屾彁楂樻暣浣撳紑鍙戞晥鐜囥��
+
+## 璐ㄩ噺涓庤鑼�
+
+鎴戜滑濮嬬粓楂樺害閲嶈浠g爜鐨勮川閲忎笌瑙勮寖銆傞�氳繃浣跨敤 ESLint銆丳rettier銆丼tylelint銆丳ublint銆丆Spell 绛夊伐鍏锋潵纭繚浠g爜璐ㄩ噺銆傛垜浠殑浠g爜瑙勮寖鍩轰簬 Vue3銆乂ite銆乀ypeScript 绛夌幇浠e墠绔妧鏈埗瀹氾紝鏃ㄥ湪鎻愪緵涓�涓畝娲併�佹槗鐢ㄧ殑妗嗘灦锛屼娇寮�鍙戣�呰兘澶熷揩閫熶笂鎵嬪苟涓撴敞浜庝笟鍔¢�昏緫鐨勫紑鍙戙��
diff --git a/eims-ui/docs/src/guide/other/faq.md b/eims-ui/docs/src/guide/other/faq.md
new file mode 100644
index 0000000..02bbe8b
--- /dev/null
+++ b/eims-ui/docs/src/guide/other/faq.md
@@ -0,0 +1,159 @@
+# 甯歌闂 #{faq}
+
+::: tip 鍒椾妇浜嗕竴浜涘父瑙佺殑闂
+
+鏈夐棶棰樺彲浠ュ厛鏉ヨ繖閲屽鎵撅紝濡傛灉娌℃湁鍙互鍦� [GitHub Issue](https://github.com/vbenjs/vue-vben-admin/issues) 鎼滅储鎴栬�呮彁浜や綘鐨勯棶棰�, 濡傛灉鏄璁烘�х殑闂鍙互鍦� [GitHub Discussions](https://github.com/vbenjs/vue-vben-admin/discussions)
+
+:::
+
+## 璇存槑
+
+閬囧埌闂,鍙互鍏堜粠浠ヤ笅鍑犱釜鏂归潰鏌ユ壘
+
+1. 瀵瑰簲妯″潡鐨� GitHub 浠撳簱 [issue](https://github.com/vbenjs/vue-vben-admin/issues) 鎼滅储
+2. 浠嶽google](https://www.google.com)鎼滅储闂
+3. 浠嶽鐧惧害](https://www.baidu.com)鎼滅储闂
+4. 鍦ㄤ笅闈㈠垪琛ㄦ壘涓嶅埌闂鍙互鍒� issue 鎻愰棶 [issues](https://github.com/vbenjs/vue-vben-admin/issues)
+5. 濡傛灉涓嶆槸闂绫诲瀷鐨勶紝闇�瑕佽璁虹殑锛岃鍒� [discussions](https://github.com/vbenjs/vue-vben-admin/discussions) 璁ㄨ
+
+## 渚濊禆闂
+
+鍦� `Monorepo` 椤圭洰涓嬶紝闇�瑕佸吇鎴愭瘡娆� `git pull`浠g爜閮借鎵ц`pnpm install`鐨勪範鎯紝鍥犱负缁忓父浼氭湁鏂扮殑渚濊禆鍖呭姞鍏ワ紝椤圭洰鍦╜.husky/git-merge`宸茬粡閰嶇疆浜嗚嚜鍔ㄦ墽琛宍pnpm install`锛屼絾鏄湁鏃跺�欎細鍑虹幇闂锛屽鏋滄病鏈夎嚜鍔ㄦ墽琛岋紝寤鸿鎵嬪姩鎵ц涓�娆°��
+
+## 鍏充簬缂撳瓨鏇存柊闂
+
+椤圭洰閰嶇疆榛樿鏄紦瀛樺湪 `localStorage` 鍐咃紝鎵�浠ョ増鏈洿鏂板悗鍙兘鏈変簺閰嶇疆娌℃敼鍙樸��
+
+瑙e喅鏂瑰紡鏄瘡娆℃洿鏂颁唬鐮佺殑鏃跺�欎慨鏀� `package.json` 鍐呯殑 `version` 鐗堟湰鍙�. 鍥犱负 localStorage 鐨� key 鏄牴鎹増鏈彿鏉ョ殑銆傛墍浠ユ洿鏂板悗鐗堟湰涓嶅悓鍓嶉潰鐨勯厤缃細澶辨晥銆傞噸鏂扮櫥褰曞嵆鍙�
+
+## 鍏充簬淇敼閰嶇疆鏂囦欢鐨勯棶棰�
+
+褰撲慨鏀� `.env` 绛夌幆澧冩枃浠朵互鍙� `vite.config.ts` 鏂囦欢鏃讹紝vite 浼氳嚜鍔ㄩ噸鍚湇鍔°��
+
+鑷姩閲嶅惎鏈夊嚑鐜囧嚭鐜伴棶棰橈紝璇烽噸鏂拌繍琛岄」鐩嵆鍙В鍐�.
+
+## 鏈湴杩愯鎶ラ敊
+
+鐢变簬 vite 鍦ㄦ湰鍦版病鏈夎浆鎹唬鐮侊紝涓斾唬鐮佷腑鐢ㄥ埌浜嗗彲閫夐摼绛夋瘮杈冩柊鐨勮娉曘�傛墍浠ユ湰鍦板紑鍙戦渶瑕佷娇鐢ㄧ増鏈緝楂樼殑娴忚鍣�(`Chrome 90+`)杩涜寮�鍙�
+
+## 椤甸潰鍒囨崲鍚庨〉闈㈢┖鐧�
+
+杩欐槸鐢变簬寮�鍚簡璺敱鍒囨崲鍔ㄧ敾,涓斿搴旂殑椤甸潰缁勪欢瀛樺湪澶氫釜鏍硅妭鐐瑰鑷寸殑锛屽湪椤甸潰鏈�澶栧眰娣诲姞`<div></div>`鍗冲彲
+
+**閿欒绀轰緥**
+
+```vue
+<template>
+  <!-- 娉ㄩ噴涔熺畻涓�涓妭鐐� -->
+  <h1>text h1</h1>
+  <h2>text h2</h2>
+</template>
+```
+
+**姝g‘绀轰緥**
+
+```vue
+<template>
+  <div>
+    <h1>text h1</h1>
+    <h2>text h2</h2>
+  </div>
+</template>
+```
+
+::: tip 鎻愮ず
+
+- 濡傛灉鎯充娇鐢ㄥ涓牴鏍囩锛屽彲浠ョ鐢ㄨ矾鐢卞垏鎹㈠姩鐢�
+- template 涓嬮潰鐨勬牴娉ㄩ噴鑺傜偣涔熺畻涓�涓妭鐐�
+
+:::
+
+## 鎴戠殑浠g爜鏈湴寮�鍙戝彲浠ワ紝鎵撳寘灏变笉琛屼簡
+
+鐩墠鍙戠幇杩欎釜鍘熷洜鍙兘鏈変互涓嬶紝鍙互浠庝互涓嬪師鍥犳潵鎺掓煡锛屽鏋滆繕鏈夊埆鐨勫彲鑳斤紝娆㈣繋琛ュ厖
+
+- 浣跨敤浜� ctx 杩欎釜鍙橀噺锛宑tx 鏈韩鏈毚闇插嚭鍦ㄥ疄渚嬬被鍨嬪唴锛孷ue瀹樻柟涔熸槸璇翠簡涓嶈鐢ㄨ繖涓睘鎬с�傝繖涓睘鎬у彧鏄敤浜庡唴閮ㄤ娇鐢ㄣ��
+
+```ts
+import { getCurrentInstance } from 'vue';
+getCurrentInstance().ctx.xxxx;
+```
+
+## 渚濊禆瀹夎闂
+
+- 濡傛灉渚濊禆瀹夎涓嶄簡鎴栬�呭惎鍔ㄦ姤閿欏彲浠ュ皾璇曟墽琛宍pnpm run reinstall`銆�
+- 濡傛灉渚濊禆瀹夎涓嶄簡鎴栬�呮姤閿欙紝鍙互灏濊瘯鍒囨崲鎵嬫満鐑偣鏉ヨ繘琛屼緷璧栧畨瑁呫��
+- 濡傛灉杩樻槸涓嶈锛屽彲浠ヨ嚜琛岄厤缃浗鍐呴暅鍍忓畨瑁呫��
+- 涔熷彲浠ュ湪椤圭洰鏍圭洰褰曞垱寤� `.npmrc` 鏂囦欢锛屽唴瀹瑰涓�
+
+```bash
+# .npmrc
+registry = https://registry.npmmirror.com/
+```
+
+## 鎵撳寘鏂囦欢杩囧ぇ
+
+- 棣栧厛锛屽畬鏁寸増鐢变簬寮曠敤浜嗘瘮杈冨鐨勫簱鏂囦欢锛屾墍浠ユ墦鍖呬細姣旇緝澶с�傚彲浠ヤ娇鐢ㄧ簿绠�鐗堟潵杩涜寮�鍙�
+
+- 鍏舵寤鸿寮�鍚� gzip锛屼娇鐢ㄤ箣鍚庝綋绉細鍙湁鍘熷厛 1/3 宸﹀彸銆俫zip 鍙互鐢辨湇鍔″櫒鐩存帴寮�鍚�傚鏋滄槸杩欐牱锛屽墠绔笉闇�瑕佹瀯寤� `.gz` 鏍煎紡鐨勬枃浠讹紝濡傛灉鍓嶇鏋勫缓浜� `.gz` 鏂囦欢锛屼互 nginx 涓轰緥锛宯ginx 闇�瑕佸紑鍚� `gzip_static: on` 杩欎釜閫夐」銆�
+
+- 寮�鍚� gzip 鐨勫悓鏃惰繕鍙互鍚屾椂寮�鍚� `brotli`锛屾瘮 gzip 鏇村ソ鐨勫帇缂┿�備袱鑰呭彲浠ュ叡瀛�
+
+**娉ㄦ剰**
+
+- gzip_static: 杩欎釜妯″潡闇�瑕� nginx 鍙﹀瀹夎锛岄粯璁ょ殑 nginx 娌℃湁瀹夎杩欎釜妯″潡銆�
+
+- 寮�鍚� `brotli` 涔熼渶瑕� nginx 鍙﹀瀹夎妯″潡
+
+## 杩愯閿欒
+
+濡傛灉鍑虹幇绫讳技浠ヤ笅閿欒锛岃妫�鏌ラ」鐩叏璺緞锛堝寘鍚墍鏈夌埗绾ц矾寰勶級涓嶈兘鍑虹幇涓枃銆佹棩鏂囥�侀煩鏂囥�傚惁鍒欏皢浼氬嚭鐜拌矾寰勮闂� 404 瀵艰嚧浠ヤ笅闂
+
+```ts
+[vite] Failed to resolve module import "ant-design-vue/dist/antd.css-vben-adminode_modulesant-design-vuedistantd.css". (imported by /@/setup/ant-design-vue/index.ts)
+```
+
+## 鎺у埗鍙拌矾鐢辫鍛婇棶棰�
+
+濡傛灉鐪嬪埌鎺у埗鍙版湁濡備笅璀﹀憡锛屼笖椤甸潰**鑳芥甯告墦寮�** 鍙互蹇界暐璇ヨ鍛娿��
+
+鍚庣画 `vue-router` 鍙兘浼氭彁渚涢厤缃」鏉ュ叧闂鍛�
+
+```ts
+[Vue Router warn]: No match found for location with path "xxxx"
+```
+
+## 鍚姩鎶ラ敊
+
+褰撳嚭鐜颁互涓嬮敊璇俊鎭椂锛岃妫�鏌ヤ綘鐨� nodejs 鐗堟湰鍙锋槸鍚︾鍚堣姹�
+
+```bash
+TypeError: str.matchAll is not a function
+at Object.extractor (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:146:27)
+at Extract (vue-vben-admin-main\node_modules@purge-icons\core\dist\index.js:173:54)
+```
+
+## nginx 閮ㄧ讲
+
+閮ㄧ讲鍒� `nginx`鍚庯紝鍙兘浼氬嚭鐜颁互涓嬮敊璇細
+
+```bash
+Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
+```
+
+瑙e喅鏂瑰紡涓�锛�
+
+```bash
+http {
+    #濡傛灉鏈夋椤归厤缃渶瑕佹敞閲婃帀
+    #include       mime.types;
+
+    types {
+      application/javascript js mjs;
+    }
+}
+```
+
+瑙e喅鏂瑰紡浜岋細
+
+杩涘叆 `nginx` 涓嬬殑`mime.types`鏂囦欢, 灏哷application/javascript js;` 淇敼涓� `application/javascript js mjs;`
diff --git a/eims-ui/docs/src/guide/other/project-update.md b/eims-ui/docs/src/guide/other/project-update.md
new file mode 100644
index 0000000..a403042
--- /dev/null
+++ b/eims-ui/docs/src/guide/other/project-update.md
@@ -0,0 +1,55 @@
+# 椤圭洰鏇存柊
+
+## 涓轰粈涔堟棤娉曞儚 npm 鎻掍欢涓�鏍锋洿鏂�
+
+鍥犱负椤圭洰鏄竴涓畬鏁寸殑椤圭洰妯$増锛屼笉鏄竴涓彃浠舵垨鑰呭畨瑁呭寘锛屾棤娉曞儚鎻掍欢涓�鏍锋洿鏂帮紝浣犱娇鐢ㄤ唬鐮佸悗锛屼細鏍规嵁涓氬姟闇�姹傦紝杩涜浜屾寮�鍙戯紝闇�瑕佽嚜琛屾墜鍔ㄥ悎骞跺崌绾с��
+
+## 鎴戦渶瑕佹�庝箞鍋�
+
+椤圭洰閲囩敤浜� `Monorepo` 鐨勬柟寮忚繘琛岀鐞嗭紝骞跺皢涓�浜涙瘮杈冩牳蹇冪殑浠g爜杩涜浜嗘娊绂伙紝姣斿 `packages/@core`銆乣packages/effects`锛屽彧瑕佷笟鍔′唬鐮佹病鏈変慨鏀硅繖閮ㄥ垎浠g爜锛岄偅涔堜綘鍙互鐩存帴鎷夊彇鏈�鏂颁唬鐮侊紝鐒跺悗鍚堝苟鍒颁綘鐨勫垎鏀笂锛屽彧闇�瑕佺畝鍗曠殑澶勭悊閮ㄥ垎鍐茬獊鍗冲彲銆傚叾浣欐枃浠跺す鍙細杩涜涓�浜涘皬鐨勮皟鏁达紝涓嶄細瀵逛笟鍔′唬鐮佷骇鐢熷奖鍝嶃��
+
+::: tip 鎺ㄨ崘
+
+寤鸿鍏虫敞浠撳簱鍔ㄦ�侊紝绉瀬鍘诲悎骞讹紝涓嶈闀挎椂闂寸Н绱紝鍚﹀垯灏嗕細瀵艰嚧鍚堝苟鍐茬獊杩囧锛屽鍔犲悎骞堕毦搴︺��
+
+:::
+
+## 浣跨敤 Git 鏇存柊浠g爜
+
+1. 鍏嬮殕浠g爜
+
+```bash
+git clone https://github.com/vbenjs/vue-vben-admin.git
+```
+
+2. 娣诲姞鑷繁鐨勫叕鍙� git 婧愬湴鍧�
+
+```bash
+# up 涓烘簮鍚嶇О,鍙互闅忔剰璁剧疆
+# gitUrl涓哄紑婧愭渶鏂颁唬鐮�
+git remote add up gitUrl;
+```
+
+3. 鎻愪氦浠g爜鍒拌嚜宸卞叕鍙� git
+
+```bash
+# 鎻愪氦浠g爜鍒拌嚜宸卞叕鍙�
+# main涓哄垎鏀悕 闇�瑕佽嚜琛屾牴鎹儏鍐典慨鏀�
+git push up main
+
+# 鍚屾鍏徃鐨勪唬鐮�
+# main涓哄垎鏀悕 闇�瑕佽嚜琛屾牴鎹儏鍐典慨鏀�
+git pull up main
+```
+
+4. 濡備綍鍚屾寮�婧愭渶鏂颁唬鐮�
+
+```bash
+git pull origin main
+```
+
+::: tip 鎻愮ず
+
+鍚屾浠g爜鐨勬椂鍊欎細鍑虹幇鍐茬獊銆傚彧闇�瑕佹妸鍐茬獊瑙e喅鍗冲彲
+
+:::
diff --git a/eims-ui/docs/src/guide/other/remove-code.md b/eims-ui/docs/src/guide/other/remove-code.md
new file mode 100644
index 0000000..8326224
--- /dev/null
+++ b/eims-ui/docs/src/guide/other/remove-code.md
@@ -0,0 +1,18 @@
+# 绉婚櫎浠g爜
+
+## 绉婚櫎鐧惧害缁熻浠g爜
+
+鍦ㄥ搴斿簲鐢ㄧ殑 `index.html` 鏂囦欢涓紝鎵惧埌濡備笅浠g爜锛屽垹闄ゅ嵆鍙細
+
+```html
+<!-- apps/web-antd -->
+<script>
+  var _hmt = _hmt || [];
+  (function () {
+    var hm = document.createElement('script');
+    hm.src = 'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';
+    var s = document.getElementsByTagName('script')[0];
+    s.parentNode.insertBefore(hm, s);
+  })();
+</script>
+```
diff --git a/eims-ui/docs/src/guide/project/changeset.md b/eims-ui/docs/src/guide/project/changeset.md
new file mode 100644
index 0000000..cc206ae
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/changeset.md
@@ -0,0 +1,21 @@
+# Changeset
+
+椤圭洰鍐呯疆浜� [changeset](https://github.com/changesets/changesets) 浣滀负鐗堟湰绠$悊宸ュ叿銆侰hangeset 鏄竴涓増鏈鐞嗗伐鍏凤紝瀹冨彲浠ュ府鍔╂垜浠洿濂界殑绠$悊鐗堟湰锛岀敓鎴� changelog锛屼互鍙婅嚜鍔ㄥ彂甯冦��
+
+璇︾粏浣跨敤鏂瑰紡鍙煡鐪嬪畼鏂规枃妗o紝杩欓噷涓嶅啀闃愯堪銆傚鏋滀綘涓嶉渶瑕佸畠锛屽彲浠ョ洿鎺ュ拷鐣ャ��
+
+## 鍛戒护琛�
+
+changeset 鍛戒护鍦ㄩ」鐩腑宸茬粡鍐呯疆锛�
+
+### 浜や簰寮忓~鍐欏彉鏇撮泦
+
+```bash
+pnpm run changeset
+```
+
+### 缁熶竴鎻愬崌鐗堟湰鍙�
+
+```bash
+pnpm run version
+```
diff --git a/eims-ui/docs/src/guide/project/cli.md b/eims-ui/docs/src/guide/project/cli.md
new file mode 100644
index 0000000..3e35242
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/cli.md
@@ -0,0 +1,113 @@
+---
+outline: deep
+---
+
+# CLI
+
+椤圭洰涓紝鎻愪緵浜嗕竴浜涘懡浠よ宸ュ叿锛岀敤浜庝竴浜涘父鐢ㄧ殑鎿嶄綔锛屼唬鐮佷綅浜� `scrips` 鍐呫��
+
+## vsh
+
+鐢ㄤ簬涓�浜涢」鐩搷浣滐紝濡傛竻鐞嗛」鐩�佹鏌ラ」鐩瓑銆�
+
+### 鐢ㄦ硶
+
+```bash
+pnpm vsh [command] [options]
+```
+
+### vsh check-circular
+
+妫�鏌ユ暣涓」鐩惊鐜紩鐢紝濡傛灉鏈夊惊鐜紩鐢紝浼氬湪鎺у埗鍙拌緭鍑哄惊鐜紩鐢ㄧ殑妯″潡銆�
+
+#### 鐢ㄦ硶
+
+```bash
+pnpm vsh check-circular
+```
+
+#### 閫夐」
+
+| 閫夐」       | 璇存槑                                |
+| ---------- | ----------------------------------- |
+| `--staged` | 鍙鏌it鏆傚瓨鍖哄唴鐨勬枃浠�,榛樿`false` |
+
+### vsh check-dep
+
+妫�鏌ユ暣涓」鐩緷璧栨儏鍐碉紝骞跺湪鎺у埗鍙拌緭鍑篳鏈娇鐢ㄧ殑渚濊禆`銆乣鏈畨瑁呯殑渚濊禆`淇℃伅
+
+#### 鐢ㄦ硶
+
+```bash
+pnpm vsh check-dep
+```
+
+#### 閫夐」
+
+| 閫夐」             | 璇存槑                                    |
+| ---------------- | --------------------------------------- |
+| `-r,--recursive` | 閫掑綊鍒犻櫎鏁翠釜椤圭洰,榛樿`true`             |
+| `--del-lock`     | 鏄惁鍒犻櫎`pnpm-lock.yaml`鏂囦欢,榛樿`true` |
+
+### vsh lint
+
+瀵归」鐩繘琛宭int妫�鏌ワ紝妫�鏌ラ」鐩腑鐨勪唬鐮佹槸鍚︾鍚堣鑼冦��
+
+#### 鐢ㄦ硶
+
+```bash
+pnpm vsh lint
+```
+
+#### 閫夐」
+
+| 閫夐」       | 璇存槑                           |
+| ---------- | ------------------------------ |
+| `--format` | 妫�鏌ュ苟灏濊瘯淇閿欒,榛樿`false` |
+
+### vsh publint
+
+瀵� `Monorepo` 椤圭洰杩涜鍖呰鑼冩鏌ワ紝妫�鏌ラ」鐩腑鐨勫寘鏄惁绗﹀悎瑙勮寖銆�
+
+#### 鐢ㄦ硶
+
+```bash
+pnpm vsh publint
+```
+
+#### 閫夐」
+
+| 閫夐」      | 璇存槑                   |
+| --------- | ---------------------- |
+| `--check` | 浠呮墽琛屾鏌�,榛樿`false` |
+
+### vsh code-workspace
+
+鐢熸垚 `vben-admin.code-workspace` 鏂囦欢锛岀洰鍓嶄笉闇�瑕佹墜鍔ㄦ墽琛岋紝浼氬湪浠g爜鎻愪氦鏃惰嚜鍔ㄦ墽琛屻��
+
+#### 鐢ㄦ硶
+
+```bash
+pnpm vsh code-workspace
+```
+
+#### 閫夐」
+
+| 閫夐」            | 璇存槑                                   |
+| --------------- | -------------------------------------- |
+| `--auto-commit` | `git commit`鏃跺�欙紝鑷姩鎻愪氦,榛樿`false` |
+| `--spaces`      | 缂╄繘鏍煎紡,榛樿 `2`涓缉杩�                |
+
+## turbo-run
+
+鐢ㄤ簬蹇�熸墽琛屽ぇ浠撲腑鑴氭湰锛屽苟鎻愪緵閫夐」寮忎氦浜掗�夋嫨銆�
+
+### 鐢ㄦ硶
+
+```bash
+pnpm turbo-run [command]
+```
+
+### turbo-run dev
+
+蹇�熸墽琛宍dev`鍛戒护锛屽苟鎻愪緵閫夐」寮忎氦浜掗�夋嫨銆�
diff --git a/eims-ui/docs/src/guide/project/dir.md b/eims-ui/docs/src/guide/project/dir.md
new file mode 100644
index 0000000..e653dc2
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/dir.md
@@ -0,0 +1,68 @@
+# 鐩綍璇存槑
+
+鐩綍浣跨敤 Monorepo 绠$悊锛岄」鐩粨鏋勫涓嬶細
+
+```bash
+.
+鈹溾攢鈹� Dockerfile # Docker 闀滃儚鏋勫缓鏂囦欢
+鈹溾攢鈹� README.md # 椤圭洰璇存槑鏂囨。
+鈹溾攢鈹� apps # 椤圭洰搴旂敤鐩綍
+鈹偮犅� 鈹溾攢鈹� backend-mock # 鍚庣妯℃嫙鏈嶅姟搴旂敤
+鈹偮犅� 鈹溾攢鈹� web-antd # 鍩轰簬 Ant Design Vue 鐨勫墠绔簲鐢�
+鈹偮犅� 鈹溾攢鈹� web-ele # 鍩轰簬 Element Plus 鐨勫墠绔簲鐢�
+鈹偮犅� 鈹斺攢鈹� web-naive # 鍩轰簬 Naive UI 鐨勫墠绔簲鐢�
+鈹溾攢鈹� build-local-docker-image.sh # 鏈湴鏋勫缓 Docker 闀滃儚鑴氭湰
+鈹溾攢鈹� cspell.json # CSpell 閰嶇疆鏂囦欢
+鈹溾攢鈹� docs # 椤圭洰鏂囨。鐩綍
+鈹溾攢鈹� eslint.config.mjs # ESLint 閰嶇疆鏂囦欢
+鈹溾攢鈹� internal # 鍐呴儴宸ュ叿鐩綍
+鈹偮犅� 鈹溾攢鈹� lint-configs # 浠g爜妫�鏌ラ厤缃�
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� commitlint-config # Commitlint 閰嶇疆
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� eslint-config # ESLint 閰嶇疆
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� prettier-config # Prettier 閰嶇疆
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� stylelint-config # Stylelint 閰嶇疆
+鈹偮犅� 鈹溾攢鈹� node-utils # Node.js 宸ュ叿
+鈹偮犅� 鈹溾攢鈹� tailwind-config # Tailwind 閰嶇疆
+鈹偮犅� 鈹溾攢鈹� tsconfig # 閫氱敤 tsconfig 閰嶇疆
+鈹偮犅� 鈹斺攢鈹� vite-config # 閫氱敤Vite 閰嶇疆
+鈹溾攢鈹� package.json # 椤圭洰渚濊禆閰嶇疆
+鈹溾攢鈹� packages # 椤圭洰鍖呯洰褰�
+鈹偮犅� 鈹溾攢鈹� @core # 鏍稿績鍖�
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� base # 鍩虹鍖�
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� design # 璁捐鐩稿叧
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� icons # 鍥炬爣
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹溾攢鈹� shared # 鍏变韩
+鈹偮犅� 鈹偮犅� 鈹偮犅� 鈹斺攢鈹� typings # 绫诲瀷瀹氫箟
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� composables # 缁勫悎寮� API
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� preferences # 鍋忓ソ璁剧疆
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� ui-kit # UI 缁勪欢闆嗗悎
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� layout-ui # 甯冨眬 UI
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� menu-ui  # 鑿滃崟 UI
+鈹偮犅� 鈹偮犅�     鈹溾攢鈹� shadcn-ui # shadcn UI
+鈹偮犅� 鈹偮犅�     鈹斺攢鈹� tabs-ui # 鏍囩椤� UI
+鈹偮犅� 鈹溾攢鈹� constants # 甯搁噺
+鈹偮犅� 鈹溾攢鈹� effects # 鍓綔鐢ㄧ浉鍏冲寘
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� access # 璁块棶鎺у埗
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� plugins # 绗笁鏂瑰ぇ鍨嬩緷璧栨彃浠�
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� common-ui # 閫氱敤 UI
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� hooks # 缁勫悎寮� API
+鈹偮犅� 鈹偮犅� 鈹溾攢鈹� layouts # 甯冨眬
+鈹偮犅� 鈹偮犅� 鈹斺攢鈹� request # 璇锋眰
+鈹偮犅� 鈹溾攢鈹� icons # 鍥炬爣
+鈹偮犅� 鈹溾攢鈹� locales # 鍥介檯鍖�
+鈹偮犅� 鈹溾攢鈹� preferences  # 鍋忓ソ璁剧疆
+鈹偮犅� 鈹溾攢鈹� stores # 鐘舵�佺鐞�
+鈹偮犅� 鈹溾攢鈹� styles # 鏍峰紡
+鈹偮犅� 鈹溾攢鈹� types # 绫诲瀷瀹氫箟
+鈹偮犅� 鈹斺攢鈹� utils # 宸ュ叿
+鈹溾攢鈹� playground # 婕旂ず鐩綍
+鈹溾攢鈹� pnpm-lock.yaml # pnpm 閿佸畾鏂囦欢
+鈹溾攢鈹� pnpm-workspace.yaml # pnpm 宸ヤ綔鍖洪厤缃枃浠�
+鈹溾攢鈹� scripts # 鑴氭湰鐩綍
+鈹偮犅� 鈹溾攢鈹� turbo-run # Turbo 杩愯鑴氭湰
+鈹偮犅� 鈹斺攢鈹� vsh # VSH 鑴氭湰
+鈹溾攢鈹� stylelint.config.mjs # Stylelint 閰嶇疆鏂囦欢
+鈹溾攢鈹� turbo.json # Turbo 閰嶇疆鏂囦欢
+鈹溾攢鈹� vben-admin.code-workspace # VS Code 宸ヤ綔鍖洪厤缃枃浠�
+鈹斺攢鈹� vitest.config.ts # Vite 閰嶇疆鏂囦欢
+```
diff --git a/eims-ui/docs/src/guide/project/standard.md b/eims-ui/docs/src/guide/project/standard.md
new file mode 100644
index 0000000..3effad2
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/standard.md
@@ -0,0 +1,165 @@
+# 瑙勮寖
+
+::: tip 璐$尞浠g爜
+
+- 濡傛灉浣犳兂鍚戦」鐩础鐚唬鐮侊紝璇风‘淇濅綘鐨勪唬鐮佺鍚堥」鐩殑浠g爜瑙勮寖銆�
+- 濡傛灉浣犱娇鐢ㄧ殑鏄� `vscode`锛岄渶瑕佸畨瑁呬互涓嬫彃浠讹細
+
+  - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - 鑴氭湰浠g爜妫�鏌�
+  - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - 浠g爜鏍煎紡鍖�
+  - [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) - 鍗曡瘝璇硶妫�鏌�
+  - [Stylelint](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) - css 鏍煎紡鍖�
+
+:::
+
+## 浣滅敤
+
+鍏峰鍩烘湰宸ョ▼绱犲吇鐨勫悓瀛﹂兘浼氭敞閲嶇紪鐮佽鑼冿紝鑰屼唬鐮侀鏍兼鏌ワ紙Code Linting锛岀畝绉� Lint锛夋槸淇濋殰浠g爜瑙勮寖涓�鑷存�х殑閲嶈鎵嬫銆�
+
+閬靛惊鐩稿簲鐨勪唬鐮佽鑼冩湁浠ヤ笅濂藉锛�
+
+- 杈冨皯 bug 閿欒鐜�
+- 楂樻晥鐨勫紑鍙戞晥鐜�
+- 鏇撮珮鐨勫彲璇绘��
+
+## 宸ュ叿
+
+椤圭洰鐨勯厤缃枃浠朵綅浜� `internal/lint-configs` 涓嬶紝浣犲彲浠ュ湪杩欓噷淇敼鍚勭lint鐨勯厤缃��
+
+椤圭洰鍐呴泦鎴愪簡浠ヤ笅鍑犵浠g爜鏍¢獙宸ュ叿锛�
+
+- [ESLint](https://eslint.org/) 鐢ㄤ簬 JavaScript 浠g爜妫�鏌�
+- [Stylelint](https://stylelint.io/) 鐢ㄤ簬 CSS 鏍峰紡妫�鏌�
+- [Prettier](https://prettier.io/) 鐢ㄤ簬浠g爜鏍煎紡鍖�
+- [Commitlint](https://commitlint.js.org/) 鐢ㄤ簬妫�鏌� git 鎻愪氦淇℃伅鐨勮鑼�
+- [Publint](https://publint.dev/) 鐢ㄤ簬妫�鏌� npm 鍖呯殑瑙勮寖
+- [Lint Staged](https://github.com/lint-staged/lint-staged) 鐢ㄤ簬鍦� git 鎻愪氦鍓嶈繍琛屼唬鐮佹牎楠�
+- [Cspell](https://cspell.org/) 鐢ㄤ簬妫�鏌ユ嫾鍐欓敊璇�
+
+## ESLint
+
+ESLint 鏄竴涓唬鐮佽鑼冨拰閿欒妫�鏌ュ伐鍏凤紝鐢ㄤ簬璇嗗埆鍜屾姤鍛� TypeScript 浠g爜涓殑璇硶閿欒銆�
+
+### 鍛戒护
+
+```bash
+pnpm eslint .
+```
+
+### 閰嶇疆
+
+eslint 閰嶇疆鏂囦欢涓� `eslint.config.mjs`锛屽叾鏍稿績閰嶇疆鏀惧湪`internal/lint-configs/eslint-config`鐩綍涓嬶紝鍙互鏍规嵁椤圭洰闇�姹傝繘琛屼慨鏀广��
+
+## Stylelint
+
+Stylelint 鐢ㄤ簬鏍¢獙椤圭洰鍐呴儴 css 鐨勯鏍�,鍔犱笂缂栬緫鍣ㄧ殑鑷姩淇锛屽彲浠ュ緢濂界殑缁熶竴椤圭洰鍐呴儴 css 椋庢牸
+
+### 鍛戒护
+
+```bash
+pnpm stylelint "**/*.{vue,css,less.scss}"
+```
+
+### 閰嶇疆
+
+Stylelint 閰嶇疆鏂囦欢涓� `stylelint.config.mjs`锛屽叾鏍稿績閰嶇疆鏀惧湪`internal/lint-configs/stylelint-config`鐩綍涓嬶紝鍙互鏍规嵁椤圭洰闇�姹傝繘琛屼慨鏀广��
+
+## Prettier
+
+Prettier 鍙互鐢ㄤ簬缁熶竴椤圭洰浠g爜椋庢牸锛岀粺涓�鐨勭缉杩涳紝鍗曞弻寮曞彿锛屽熬閫楀彿绛夌瓑椋庢牸
+
+### 鍛戒护
+
+```bash
+pnpm prettier .
+```
+
+### 閰嶇疆
+
+Prettier 閰嶇疆鏂囦欢涓� `.prettier.mjs`锛屽叾鏍稿績閰嶇疆鏀惧湪`internal/lint-configs/prettier-config`鐩綍涓嬶紝鍙互鏍规嵁椤圭洰闇�姹傝繘琛屼慨鏀广��
+
+## CommitLint
+
+鍦ㄤ竴涓洟闃熶腑锛屾瘡涓汉鐨� git 鐨� commit 淇℃伅閮戒笉涓�鏍凤紝浜旇姳鍏棬锛屾病鏈変竴涓満鍒跺緢闅句繚璇佽鑼冨寲锛屽浣曟墠鑳借鑼冨寲鍛紵鍙兘浣犳兂鍒扮殑鏄� git 鐨� hook 鏈哄埗锛屽幓鍐� shell 鑴氭湰鍘诲疄鐜般�傝繖褰撶劧鍙互锛屽叾瀹� JavaScript 鏈変竴涓緢濂界殑宸ュ叿鍙互瀹炵幇杩欎釜妯℃澘锛屽畠灏辨槸 commitlint锛堢敤浜庢牎楠� git 鎻愪氦淇℃伅瑙勮寖锛夈��
+
+### 閰嶇疆
+
+CommitLint 閰嶇疆鏂囦欢涓� `.commitlintrc.mjs`锛屽叾鏍稿績閰嶇疆鏀惧湪`internal/lint-configs/commitlint-config`鐩綍涓嬶紝鍙互鏍规嵁椤圭洰闇�姹傝繘琛屼慨鏀广��
+
+### Git 鎻愪氦瑙勮寖
+
+鍙傝�� [Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)
+
+- `feat` 澧炲姞鏂板姛鑳�
+- `fix` 淇闂/BUG
+- `style` 浠g爜椋庢牸鐩稿叧鏃犲奖鍝嶈繍琛岀粨鏋滅殑
+- `perf` 浼樺寲/鎬ц兘鎻愬崌
+- `refactor` 閲嶆瀯
+- `revert` 鎾ら攢淇敼
+- `test` 娴嬭瘯鐩稿叧
+- `docs` 鏂囨。/娉ㄩ噴
+- `chore` 渚濊禆鏇存柊/鑴氭墜鏋堕厤缃慨鏀圭瓑
+- `workflow` 宸ヤ綔娴佹敼杩�
+- `ci` 鎸佺画闆嗘垚
+- `types` 绫诲瀷淇敼
+
+### 鍏抽棴Git鎻愪氦瑙勮寖妫�鏌�
+
+濡傛灉浣犳兂鍏抽棴 Git 鎻愪氦瑙勮寖妫�鏌ワ紝鏈変袱绉嶆柟寮忥細
+
+::: code-group
+
+```bash [涓存椂鍏抽棴]
+git commit -m 'feat: add home page' --no-verify
+```
+
+```bash [姘镐箙鍏抽棴]
+# 鍦� .husky/commit-msg 鍐呮敞閲婁互涓嬩唬鐮佸嵆鍙�
+pnpm exec commitlint --edit "$1" # [!code --]
+```
+
+:::
+
+## Publint
+
+Publint 鏄竴涓敤浜庢鏌� npm 鍖呯殑瑙勮寖鐨勫伐鍏凤紝鍙互妫�鏌ュ寘鐨勭増鏈彿鏄惁绗﹀悎瑙勮寖锛屾槸鍚︾鍚堟爣鍑嗙殑 ESM 瑙勮寖鍖呯瓑绛夈��
+
+### 鍛戒护
+
+```bash
+pnpm vsh publint
+```
+
+## Cspell
+
+Cspell 鏄竴涓敤浜庢鏌ユ嫾鍐欓敊璇殑宸ュ叿锛屽彲浠ユ鏌ヤ唬鐮佷腑鐨勬嫾鍐欓敊璇紝閬垮厤鍥犱负鎷煎啓閿欒瀵艰嚧鐨� bug銆�
+
+### 鍛戒护
+
+```bash
+pnpm cspell lint \"**/*.ts\"  \"**/README.md\" \".changeset/*.md\" --no-progress
+```
+
+### 閰嶇疆
+
+cspell 閰嶇疆鏂囦欢涓� `cspell.json`锛屽彲浠ユ牴鎹」鐩渶姹傝繘琛屼慨鏀广��
+
+## Git Hook
+
+git hook 涓�鑸粨鍚堝悇绉� lint锛屽湪 git 鎻愪氦浠g爜鐨勬椂鍊欒繘琛屼唬鐮侀鏍兼牎楠岋紝濡傛灉鏍¢獙娌¢�氳繃锛屽垯涓嶄細杩涜鎻愪氦銆傞渶瑕佸紑鍙戣�呰嚜琛屼慨鏀瑰悗鍐嶆杩涜鎻愪氦
+
+### husky
+
+鏈変竴涓棶棰樺氨鏄牎楠屼細鏍¢獙鍏ㄩ儴浠g爜锛屼絾鏄垜浠彧鎯虫牎楠屾垜浠嚜宸辨彁浜ょ殑浠g爜锛岃繖涓椂鍊欏氨鍙互浣跨敤 husky銆�
+
+鏈�鏈夋晥鐨勮В鍐虫柟妗堝氨鏄皢 Lint 鏍¢獙鏀惧埌鏈湴锛屽父瑙佸仛娉曟槸浣跨敤 husky 鎴栬�� pre-commit 鍦ㄦ湰鍦版彁浜や箣鍓嶅厛鍋氫竴娆� Lint 鏍¢獙銆�
+
+椤圭洰鍦� `.husky` 鍐呴儴瀹氫箟浜嗙浉搴旂殑 hooks
+
+#### 濡備綍鍏抽棴 Husky
+
+濡傛灉浣犳兂鍏抽棴 Husky锛岀洿鎺ュ垹闄� `.husky` 鐩綍鍗冲彲銆�
+
+### lint-staged
+
+鐢ㄤ簬鑷姩淇鎻愪氦鏂囦欢椋庢牸闂,鍏堕厤缃枃浠朵负 `.lintstagedrc.mjs`锛屽彲浠ユ牴鎹」鐩渶姹傝繘琛屼慨鏀广��
diff --git a/eims-ui/docs/src/guide/project/tailwindcss.md b/eims-ui/docs/src/guide/project/tailwindcss.md
new file mode 100644
index 0000000..cfab596
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/tailwindcss.md
@@ -0,0 +1,13 @@
+# Tailwind CSS
+
+[Tailwind CSS](https://tailwindcss.com/) 鏄竴涓疄鐢ㄦ�т紭鍏堢殑CSS妗嗘灦锛岀敤浜庡揩閫熸瀯寤鸿嚜瀹氫箟璁捐銆�
+
+## 閰嶇疆
+
+椤圭洰鐨勯厤缃枃浠朵綅浜� `internal/tailwind-config` 涓嬶紝浣犲彲浠ュ湪杩欓噷淇敼 Tailwind CSS 鐨勯厤缃��
+
+::: tip 鍖呬娇鐢� tailwindcss 鐨勯檺鍒�
+
+褰撳墠鍙湁瀵瑰簲鐨勫寘涓嬮潰瀛樺湪 `tailwind.config.mjs` 鏂囦欢鎵嶄細鍚敤 tailwindcss 鐨勭紪璇戯紝鍚﹀垯涓嶄細鍚敤 tailwindcss銆傚鏋滀綘鏄函绮圭殑 SDK 鍖咃紝涓嶉渶瑕佷娇鐢� tailwindcss锛屽彲浠ヤ笉鐢ㄥ垱寤� `tailwind.config.mjs` 鏂囦欢銆�
+
+:::
diff --git a/eims-ui/docs/src/guide/project/test.md b/eims-ui/docs/src/guide/project/test.md
new file mode 100644
index 0000000..abf3c50
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/test.md
@@ -0,0 +1,33 @@
+# 鍗曞厓娴嬭瘯
+
+椤圭洰鍐呯疆浜� [Vitest](https://vitest.dev/) 浣滀负鍗曞厓娴嬭瘯宸ュ叿銆俈itest 鏄竴涓熀浜� Vite 鐨勬祴璇曡繍琛屽櫒锛屽畠鎻愪緵浜嗕竴濂楃畝鍗曠殑 API 鏉ョ紪鍐欐祴璇曠敤渚嬨��
+
+## 缂栧啓娴嬭瘯鐢ㄤ緥
+
+鍦ㄩ」鐩腑锛屾垜浠害瀹氬皢娴嬭瘯鏂囦欢鍚嶄互 `.test.ts` 缁撳熬锛屾垨鑰呭瓨鏀惧埌`__tests__`鐩綍鍐呫�備緥濡傦紝鍒涘缓涓�涓� `utils.ts` 鏂囦欢锛岀劧鍚庡悓绾х洰褰昤utils.test.ts` 鏂囦欢锛�
+
+```ts
+// utils.test.ts
+import { expect, test } from 'vitest';
+import { sum } from './sum';
+
+test('adds 1 + 2 to equal 3', () => {
+  expect(sum(1, 2)).toBe(3);
+});
+```
+
+## 杩愯娴嬭瘯
+
+鍦ㄥぇ浠撴牴鐩綍涓嬭繍琛屼互涓嬪懡浠ゅ嵆鍙細
+
+```bash
+pnpm test:unit
+```
+
+## 鐜版湁鍗曞厓娴嬭瘯
+
+椤圭洰涓凡缁忔湁涓�浜涘崟鍏冩祴璇曠敤渚嬶紝鍙互鎼滅储浠.test.ts`缁撳熬鐨勬枃浠舵煡鐪嬶紝鍦ㄤ綘鏇存敼鍒扮浉鍏充唬鐮佹椂锛屽彲浠ヨ繍琛屽崟鍏冩祴璇曟潵淇濊瘉浠g爜鐨勬纭�э紝寤鸿鍦ㄥ紑鍙戣繃绋嬩腑锛屼繚鎸佸崟鍏冩祴璇曠殑瑕嗙洊鐜囷紝涓斿悓鏃跺湪 CI/CD 娴佺▼涓繍琛屽崟鍏冩祴璇曪紝淇濊瘉娴嬭瘯閫氳繃鍦ㄨ繘琛岄」鐩儴缃层��
+
+鐜版湁鍗曞厓娴嬭瘯鎯呭喌锛�
+
+![](/guide/test.png)
diff --git a/eims-ui/docs/src/guide/project/vite.md b/eims-ui/docs/src/guide/project/vite.md
new file mode 100644
index 0000000..51b5a38
--- /dev/null
+++ b/eims-ui/docs/src/guide/project/vite.md
@@ -0,0 +1,33 @@
+# Vite Config
+
+椤圭洰灏佽浜嗕竴灞倂ite閰嶇疆锛屽苟闆嗘垚浜嗕竴浜涙彃浠讹紝鏂逛究鍦ㄥ涓寘浠ュ強搴旂敤鍐呭鐢紝浣跨敤鏂瑰紡濡備笅锛�
+
+## 搴旂敤
+
+```ts
+// vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    // vite閰嶇疆锛屽弬鑰僾ite瀹樻柟鏂囨。杩涜瑕嗙洊
+    vite: {},
+  };
+});
+```
+
+## 鍖�
+
+```ts
+// vite.config.mts
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    library: {},
+    // vite閰嶇疆锛屽弬鑰僾ite瀹樻柟鏂囨。杩涜瑕嗙洊
+    vite: {},
+  };
+});
+```
diff --git a/eims-ui/docs/src/index.md b/eims-ui/docs/src/index.md
new file mode 100644
index 0000000..30aaa0a
--- /dev/null
+++ b/eims-ui/docs/src/index.md
@@ -0,0 +1,108 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+sidebar: false
+
+hero:
+  name: Vben Admin
+  text: 浼佷笟绾х鐞嗙郴缁熸鏋�
+  tagline: 鍏ㄦ柊鍗囩骇锛屽紑绠卞嵆鐢紝绠�鍗曢珮鏁�
+  image:
+    src: https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp
+    alt: Vben Admin
+  actions:
+    - theme: brand
+      text: 蹇�熷紑濮� ->
+      link: /guide/introduction/vben
+    - theme: alt
+      text: 鍦ㄧ嚎棰勮
+      link: https://www.vben.pro
+    - theme: alt
+      text: 鍦� GitHub 鏌ョ湅
+      link: https://github.com/vbenjs/vue-vben-admin
+
+features:
+  - icon: 馃殌
+    title: 鏈�鏂版妧鏈爤
+    details: 鍩轰簬 Vue3銆丳inia銆乂ue Router銆乀ypeScript銆佺瓑鏈�鏂版妧鏈爤銆�
+    link: /guide/introduction/quick-start
+    linkText: 蹇�熷紑濮�
+  - icon: 馃
+    title: 涓板瘜鐨勯厤缃�
+    details: 浼佷笟绾т腑鍚庡彴鍓嶇瑙e喅鏂规锛屾彁渚涗赴瀵岀殑缁勪欢鍜屾ā鏉夸互鍙� N 绉嶅亸濂借缃粍鍚堟柟妗堛��
+    link: /guide/essentials/settings
+    linkText: 閰嶇疆鏂囨。
+  - icon: 馃帹
+    title: 涓婚瀹氬埗
+    details: 閫氳繃绠�鍗曠殑閰嶇疆锛屽嵆鍙疄鐜板悇绉嶄富棰樺垏鎹紝婊¤冻涓�у寲闇�姹傘��
+    link: /guide/in-depth/theme
+    linkText: 涓婚鏂囨。
+  - icon: 馃寪
+    title: 鍥介檯鍖�
+    details: 鍐呯疆鍥介檯鍖栨柟妗堬紝鏀寔澶氳瑷�鍒囨崲锛屾弧瓒冲浗闄呭寲闇�姹傘��
+    link: /guide/in-depth/locale
+    linkText: 鍥介檯鍖栨枃妗�
+  - icon: 馃攼
+    title: 鏉冮檺绠$悊
+    details: 鍐呯疆鏉冮檺绠$悊鏂规锛屾敮鎸佸绉嶆潈闄愭帶鍒舵柟寮忥紝婊¤冻鍚勭鏉冮檺闇�姹傘��
+    link: /guide/in-depth/access
+    linkText: 鏉冮檺鏂囨。
+  - title: Vite
+    icon:
+      src: /logos/vite.svg
+    details: 鐜颁唬鍖栫殑鍓嶇鏋勫缓宸ュ叿锛屽揩閫熷喎鍚姩锛岀灛闂寸儹鏇存柊銆�
+    link: https://vitejs.dev/
+    linkText: 瀹樻柟绔欑偣
+  - title: Shadcn UI
+    icon:
+      src: /logos/shadcn-ui.svg
+    details: 鏍稿績鍩轰簬 Shadcn UI + Tailwindcss锛屼笟鍔″彲鏀寔浠绘剰鐨� UI 妗嗘灦銆�
+    link: https://www.shadcn-vue.com/
+    linkText: 瀹樻柟绔欑偣
+  - title: Turbo Repo
+    icon:
+      src: /logos/turborepo.svg
+    details: 瑙勮寖涓旀爣鍑嗙殑澶т粨鏋舵瀯锛屼娇鐢� pnpm + monorepo + turbo 宸ョ▼绠$悊妯″紡锛屾彁渚涗紒涓氱骇寮�鍙戣鑼冦��
+    link: https://turbo.build/
+    linkText: 瀹樻柟绔欑偣
+  - title: Nitro Mock Server
+    icon:
+      src: /logos/nitro.svg
+    details: 鍐呯疆 Nitro Mock 鏈嶅姟锛岃浣犵殑 mock 鏈嶅姟鏇村姞寮哄ぇ銆�
+    link: https://nitro.unjs.io/
+    linkText: 瀹樻柟绔欑偣
+---
+
+<!-- <script setup>
+import {
+  VPTeamPage,
+  VPTeamPageTitle,
+  VPTeamMembers,
+  VPTeamPageSection
+} from 'vitepress/theme';
+
+const members = [
+  {
+    avatar: 'https://avatars.githubusercontent.com/u/28132598?v=4',
+    name: 'Vben',
+    title: '鍒涘缓鑰�',
+    desc: 'Vben Admin浠ュ強鐩稿叧鐢熸�佺殑浣滆�咃紝璐熻矗椤圭洰鐨勬暣浣撳紑鍙戙��',
+    links: [
+      { icon: 'github', link: 'https://github.com/anncwb' },
+    ]
+  },
+]
+</script>
+
+<VPTeamPage>
+  <VPTeamPageTitle>
+    <template #title>
+      鏍稿績鎴愬憳浠嬬粛
+    </template>
+  </VPTeamPageTitle>
+  <VPTeamMembers
+    :members="members"
+  />
+</VPTeamPage> -->
+
+<VbenContributors />
diff --git a/eims-ui/docs/src/public/favicon.ico b/eims-ui/docs/src/public/favicon.ico
new file mode 100644
index 0000000..fcf9818
--- /dev/null
+++ b/eims-ui/docs/src/public/favicon.ico
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/devtools.png b/eims-ui/docs/src/public/guide/devtools.png
new file mode 100644
index 0000000..b34a685
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/devtools.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/loading.png b/eims-ui/docs/src/public/guide/loading.png
new file mode 100644
index 0000000..e1d0046
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/loading.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/locale.png b/eims-ui/docs/src/public/guide/locale.png
new file mode 100644
index 0000000..e9c79d0
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/locale.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/login-expired.png b/eims-ui/docs/src/public/guide/login-expired.png
new file mode 100644
index 0000000..bc82ba5
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/login-expired.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/login.png b/eims-ui/docs/src/public/guide/login.png
new file mode 100644
index 0000000..3774b0b
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/login.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/preferences.png b/eims-ui/docs/src/public/guide/preferences.png
new file mode 100644
index 0000000..9b1582f
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/preferences.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/qq.png b/eims-ui/docs/src/public/guide/qq.png
new file mode 100644
index 0000000..cc76cf7
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/qq.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/qq_channel.png b/eims-ui/docs/src/public/guide/qq_channel.png
new file mode 100644
index 0000000..5fa807b
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/qq_channel.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/report.png b/eims-ui/docs/src/public/guide/report.png
new file mode 100644
index 0000000..fbff280
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/report.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/test.png b/eims-ui/docs/src/public/guide/test.png
new file mode 100644
index 0000000..cbd4dc6
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/test.png
Binary files differ
diff --git a/eims-ui/docs/src/public/guide/update-notice.png b/eims-ui/docs/src/public/guide/update-notice.png
new file mode 100644
index 0000000..a4436cf
--- /dev/null
+++ b/eims-ui/docs/src/public/guide/update-notice.png
Binary files differ
diff --git a/eims-ui/docs/src/public/logos/nitro.svg b/eims-ui/docs/src/public/logos/nitro.svg
new file mode 100644
index 0000000..e5564f2
--- /dev/null
+++ b/eims-ui/docs/src/public/logos/nitro.svg
@@ -0,0 +1,42 @@
+<!-- nitro logo -->
+<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <g clip-path="url(#clip0_115_108)">
+    <path fill-rule="evenodd" clip-rule="evenodd"
+      d="M35.2166 7.02016C28.0478 -1.38317 15.4241 -2.38397 7.02077 4.78481C-1.38256 11.9536 -2.38336 24.5773 4.78542 32.9806C11.9542 41.3839 24.5779 42.3847 32.9812 35.216C41.3846 28.0472 42.3854 15.4235 35.2166 7.02016ZM25.2525 17.5175C26.0233 17.5175 26.5155 18.3527 26.1287 19.0194L26.0175 19.2111L18.4696 31.6294C18.3293 31.8602 18.0788 32.001 17.8088 32.001H17.0883C16.5946 32.001 16.2336 31.5349 16.3573 31.0569L18.4054 23.1384C18.5691 22.5053 18.0912 21.888 17.4373 21.888H14.2914C13.6375 21.888 13.1596 21.2708 13.3232 20.6377L16.4137 8.68289C16.5261 8.28056 16.8904 7.99734 17.3081 8.00208C17.3587 8.00266 17.4046 8.0035 17.4427 8.0047L20.6109 8.00465C21.217 8.00436 21.684 8.53896 21.6023 9.13949L21.5828 9.28246L20.3746 16.349C20.2702 16.9598 20.7406 17.5175 21.3603 17.5175H25.2525Z"
+      fill="url(#paint0_diamond_115_108)" />
+    <mask id="mask0_115_108" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0"
+      width="40" height="41">
+      <circle cx="20" cy="20.001" r="20" fill="url(#paint1_diamond_115_108)" />
+    </mask>
+    <g mask="url(#mask0_115_108)">
+      <g filter="url(#filter0_f_115_108)">
+        <path
+          d="M1.11145 13.4267C0.0703174 16.4179 -0.245523 19.6136 0.189923 22.7507C0.62537 25.8879 1.79965 28.8768 3.61611 31.4713C5.43256 34.0659 7.83925 36.192 10.6381 37.6746C13.4369 39.1572 16.5478 39.9538 19.7147 39.999C22.8816 40.0442 26.0139 39.3366 28.8539 37.9345C31.6939 36.5324 34.1602 34.4758 36.05 31.9341C37.9397 29.3924 39.1988 26.4383 39.7236 23.3148C40.2483 20.1914 40.0238 16.9879 39.0684 13.9682L33.2532 15.808C33.9172 17.9068 34.0732 20.1333 33.7085 22.3042C33.3438 24.4751 32.4687 26.5283 31.1552 28.2949C29.8418 30.0615 28.1276 31.4908 26.1537 32.4653C24.1799 33.4399 22.0028 33.9316 19.8017 33.9002C17.6006 33.8688 15.4384 33.3151 13.4932 32.2847C11.5479 31.2543 9.87518 29.7766 8.61269 27.9733C7.35019 26.1699 6.53403 24.0926 6.23138 21.9122C5.92873 19.7317 6.14825 17.5106 6.87187 15.4316L1.11145 13.4267Z"
+          fill="white" />
+      </g>
+    </g>
+  </g>
+  <defs>
+    <filter id="filter0_f_115_108" x="-10" y="3.42667" width="60" height="46.5744"
+      filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+      <feFlood flood-opacity="0" result="BackgroundImageFix" />
+      <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
+      <feGaussianBlur stdDeviation="5" result="effect1_foregroundBlur_115_108" />
+    </filter>
+    <radialGradient id="paint0_diamond_115_108" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
+      gradientTransform="translate(4.00069 20.0004) scale(39.0007 397.71)">
+      <stop stop-color="#31B2F3" />
+      <stop offset="0.473958" stop-color="#F27CEC" />
+      <stop offset="1" stop-color="#FD6641" />
+    </radialGradient>
+    <radialGradient id="paint1_diamond_115_108" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse"
+      gradientTransform="translate(4 20.0011) scale(39 397.703)">
+      <stop stop-color="#F27CEC" />
+      <stop offset="0.484375" stop-color="#31B2F3" />
+      <stop offset="1" stop-color="#7D7573" />
+    </radialGradient>
+    <clipPath id="clip0_115_108">
+      <rect width="146" height="40.001" fill="white" />
+    </clipPath>
+  </defs>
+</svg>
diff --git a/eims-ui/docs/src/public/logos/shadcn-ui.svg b/eims-ui/docs/src/public/logos/shadcn-ui.svg
new file mode 100644
index 0000000..2d584b9
--- /dev/null
+++ b/eims-ui/docs/src/public/logos/shadcn-ui.svg
@@ -0,0 +1 @@
+<svg class="h-6 w-6" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_102_1338)"><path d="M208 128L128 208" stroke="#41B883" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"></path><path d="M192 40L40 192" stroke="#41B883" stroke-width="16" stroke-linecap="round" stroke-linejoin="round"></path></g><defs><clipPath id="clip0_102_1338"><rect width="256" height="256" fill="white"></rect></clipPath></defs></svg>
diff --git a/eims-ui/docs/src/public/logos/turborepo.svg b/eims-ui/docs/src/public/logos/turborepo.svg
new file mode 100644
index 0000000..9c7035a
--- /dev/null
+++ b/eims-ui/docs/src/public/logos/turborepo.svg
@@ -0,0 +1,32 @@
+<svg width="104" height="104" viewBox="0 0 104 104" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <g clip-path="url(#clip0_1_17)">
+        <path d="M26.0192 7C42.0962 -2.28203 61.9038 -2.28203 77.9808 7C94.0577 16.282 103.962 33.4359 103.962 52C103.962 70.5641 94.0577 87.718 77.9808 97C61.9038 106.282 42.0962 106.282 26.0192 97C9.94229 87.718 0.038475 70.5641 0.038475 52C0.038475 33.4359 9.94229 16.282 26.0192 7Z" fill="black" fill-opacity="0.64"/>
+        <path d="M26.0192 7C42.0962 -2.28203 61.9038 -2.28203 77.9808 7C94.0577 16.282 103.962 33.4359 103.962 52C103.962 70.5641 94.0577 87.718 77.9808 97C61.9038 106.282 42.0962 106.282 26.0192 97C9.94229 87.718 0.038475 70.5641 0.038475 52C0.038475 33.4359 9.94229 16.282 26.0192 7Z" fill="url(#paint0_linear_1_17)" fill-opacity="0.15"/>
+        <path d="M26.0192 7C42.0962 -2.28203 61.9038 -2.28203 77.9808 7C94.0577 16.282 103.962 33.4359 103.962 52C103.962 70.5641 94.0577 87.718 77.9808 97C61.9038 106.282 42.0962 106.282 26.0192 97C9.94229 87.718 0.038475 70.5641 0.038475 52C0.038475 33.4359 9.94229 16.282 26.0192 7Z" fill="black" fill-opacity="0.5"/>
+        <path d="M0.538475 52C0.538475 33.6146 10.347 16.6257 26.2692 7.43301C42.1915 -1.7597 61.8085 -1.7597 77.7308 7.43301C93.653 16.6257 103.462 33.6146 103.462 52C103.462 70.3854 93.653 87.3743 77.7308 96.567C61.8085 105.76 42.1915 105.76 26.2692 96.567C10.347 87.3743 0.538475 70.3854 0.538475 52Z" stroke="url(#paint1_radial_1_17)" stroke-opacity="0.15"/>
+        <path d="M0.538475 52C0.538475 33.6146 10.347 16.6257 26.2692 7.43301C42.1915 -1.7597 61.8085 -1.7597 77.7308 7.43301C93.653 16.6257 103.462 33.6146 103.462 52C103.462 70.3854 93.653 87.3743 77.7308 96.567C61.8085 105.76 42.1915 105.76 26.2692 96.567C10.347 87.3743 0.538475 70.3854 0.538475 52Z" stroke="url(#paint2_linear_1_17)" stroke-opacity="0.5"/>
+        <path d="M51.8878 37.9262C44.1892 37.9262 37.9258 44.1896 37.9258 51.8882C37.9258 59.5868 44.1892 65.8502 51.8878 65.8502C59.5864 65.8502 65.8498 59.5868 65.8498 51.8882C65.8498 44.1896 59.5864 37.9262 51.8878 37.9262ZM51.8878 59.1136C47.8968 59.1136 44.6624 55.8792 44.6624 51.8882C44.6624 47.8972 47.8968 44.6628 51.8878 44.6628C55.8788 44.6628 59.1132 47.8972 59.1132 51.8882C59.1132 55.8792 55.8788 59.1136 51.8878 59.1136Z" fill="white"/>
+        <path fill-rule="evenodd" clip-rule="evenodd" d="M53.0581 35.633V30.42C64.3889 31.0258 73.3901 40.4066 73.3901 51.8882C73.3901 63.3698 64.3889 72.748 53.0581 73.3564V68.1434C61.5029 67.5402 68.1901 60.4838 68.1901 51.8882C68.1901 43.2926 61.5029 36.2362 53.0581 35.633ZM39.5745 62.5482C37.3359 59.9638 35.8929 56.6722 35.6355 53.0582H30.4199C30.6903 58.1152 32.7131 62.7042 35.8825 66.2376L39.5719 62.5482H39.5745ZM50.7182 73.3564V68.1434C47.1016 67.886 43.81 66.4456 41.2256 64.2044L37.5362 67.8938C41.0722 71.0658 45.6612 73.086 50.7156 73.3564H50.7182Z" fill="url(#paint3_linear_1_17)"/>
+    </g>
+    <defs>
+        <linearGradient id="paint0_linear_1_17" x1="52" y1="-8" x2="52" y2="112" gradientUnits="userSpaceOnUse">
+            <stop stop-color="#3286F1"/>
+            <stop offset="1" stop-color="#C43AC4"/>
+        </linearGradient>
+        <radialGradient id="paint1_radial_1_17" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(52 -7.99999) rotate(90) scale(154.286 154.286)">
+            <stop stop-color="white"/>
+            <stop offset="1" stop-color="white"/>
+        </radialGradient>
+        <linearGradient id="paint2_linear_1_17" x1="-8" y1="-8" x2="18.25" y2="40.75" gradientUnits="userSpaceOnUse">
+            <stop stop-color="white"/>
+            <stop offset="1" stop-color="white" stop-opacity="0"/>
+        </linearGradient>
+        <linearGradient id="paint3_linear_1_17" x1="53.9007" y1="33.4389" x2="32.7679" y2="54.5717" gradientUnits="userSpaceOnUse">
+            <stop stop-color="#0096FF"/>
+            <stop offset="1" stop-color="#FF1E56"/>
+        </linearGradient>
+        <clipPath id="clip0_1_17">
+            <rect width="104" height="104" fill="white"/>
+        </clipPath>
+    </defs>
+</svg>
diff --git a/eims-ui/docs/src/public/logos/vite.svg b/eims-ui/docs/src/public/logos/vite.svg
new file mode 100644
index 0000000..de4aedd
--- /dev/null
+++ b/eims-ui/docs/src/public/logos/vite.svg
@@ -0,0 +1,15 @@
+<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
+<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
+<defs>
+<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
+<stop stop-color="#41D1FF"/>
+<stop offset="1" stop-color="#BD34FE"/>
+</linearGradient>
+<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFEA83"/>
+<stop offset="0.0833333" stop-color="#FFDD35"/>
+<stop offset="1" stop-color="#FFA800"/>
+</linearGradient>
+</defs>
+</svg>
diff --git a/eims-ui/docs/src/sponsor/personal.md b/eims-ui/docs/src/sponsor/personal.md
new file mode 100644
index 0000000..fa2fa23
--- /dev/null
+++ b/eims-ui/docs/src/sponsor/personal.md
@@ -0,0 +1,12 @@
+# 璧炲姪
+
+濡傛灉浣犺寰楄繖涓」鐩浣犳湁甯姪锛屼綘鍙互甯綔鑰呬拱涓�鏉挅鍟¤〃绀烘敮鎸�!
+
+![](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png)
+
+鎮ㄧ殑璧炲姪灏嗗府鍔╂垜浠細
+
+- 缁存寔椤圭洰鐨勫熀纭�璁炬柦锛屽鏈嶅姟鍣ㄣ�佸煙鍚嶃�佺ぞ缇よ垂鐢ㄣ��
+- 鏀寔寮�鍙戣�呯殑璐$尞鍜屽姞蹇柊鍔熻兘鐨勫紑鍙戙��
+
+鎰熻阿鎵�鏈夌幇鏈夌殑鍜屾湭鏉ョ殑璧炲姪鑰咃紝鎮ㄧ殑鏀寔瀵规垜浠潵璇磋嚦鍏抽噸瑕侊紝璁╂垜浠竴璧锋帹鍔ㄩ」鐩户缁墠琛屻��
diff --git a/eims-ui/docs/tailwind.config.mjs b/eims-ui/docs/tailwind.config.mjs
new file mode 100644
index 0000000..9dbc8c3
--- /dev/null
+++ b/eims-ui/docs/tailwind.config.mjs
@@ -0,0 +1,11 @@
+import tailwindcssConfig from '@vben/tailwind-config';
+
+export default {
+  ...tailwindcssConfig,
+  content: [
+    ...tailwindcssConfig.content,
+    '.vitepress/**/*.{js,mts,ts,vue}',
+    'src/demos/**/*.{js,mts,ts,vue}',
+    'src/**/*.md',
+  ],
+};
diff --git a/eims-ui/docs/tsconfig.json b/eims-ui/docs/tsconfig.json
new file mode 100644
index 0000000..05147a9
--- /dev/null
+++ b/eims-ui/docs/tsconfig.json
@@ -0,0 +1,19 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["./src/_env/*"]
+    }
+  },
+  "include": [
+    ".vitepress/*.mts",
+    ".vitepress/**/*.ts",
+    ".vitepress/**/*.vue",
+    "src/*.mts",
+    "src/**/*.ts",
+    "src/**/*.vue"
+  ],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/eslint.config.mjs b/eims-ui/eslint.config.mjs
new file mode 100644
index 0000000..b29b567
--- /dev/null
+++ b/eims-ui/eslint.config.mjs
@@ -0,0 +1,5 @@
+// @ts-check
+
+import { defineConfig } from '@vben/eslint-config';
+
+export default defineConfig();
diff --git a/eims-ui/internal/lint-configs/commitlint-config/index.mjs b/eims-ui/internal/lint-configs/commitlint-config/index.mjs
new file mode 100644
index 0000000..3d85439
--- /dev/null
+++ b/eims-ui/internal/lint-configs/commitlint-config/index.mjs
@@ -0,0 +1,153 @@
+import { execSync } from 'node:child_process';
+
+import { getPackagesSync } from '@vben/node-utils';
+
+const { packages } = getPackagesSync();
+
+const allowedScopes = [
+  ...packages.map((pkg) => pkg.packageJson.name),
+  'project',
+  'style',
+  'lint',
+  'ci',
+  'dev',
+  'deploy',
+  'other',
+];
+
+// precomputed scope
+const scopeComplete = execSync('git status --porcelain || true')
+  .toString()
+  .trim()
+  .split('\n')
+  .find((r) => ~r.indexOf('M  src'))
+  ?.replace(/(\/)/g, '%%')
+  ?.match(/src%%((\w|-)*)/)?.[1]
+  ?.replace(/s$/, '');
+
+/**
+ * @type {import('cz-git').UserConfig}
+ */
+const userConfig = {
+  extends: ['@commitlint/config-conventional'],
+  plugins: ['commitlint-plugin-function-rules'],
+  prompt: {
+    /** @use `pnpm commit :f` */
+    alias: {
+      b: 'build: bump dependencies',
+      c: 'chore: update config',
+      f: 'docs: fix typos',
+      r: 'docs: update README',
+      s: 'style: update code format',
+    },
+    allowCustomIssuePrefixs: false,
+    // scopes: [...scopes, 'mock'],
+    allowEmptyIssuePrefixs: false,
+    customScopesAlign: scopeComplete ? 'bottom' : 'top',
+    defaultScope: scopeComplete,
+    // English
+    typesAppend: [
+      { name: 'workflow: workflow improvements', value: 'workflow' },
+      { name: 'types:    type definition file changes', value: 'types' },
+    ],
+
+    // 涓嫳鏂囧鐓х増
+    // messages: {
+    //   type: '閫夋嫨浣犺鎻愪氦鐨勭被鍨� :',
+    //   scope: '閫夋嫨涓�涓彁浜よ寖鍥� (鍙��):',
+    //   customScope: '璇疯緭鍏ヨ嚜瀹氫箟鐨勬彁浜よ寖鍥� :',
+    //   subject: '濉啓绠�鐭簿鐐肩殑鍙樻洿鎻忚堪 :\n',
+    //   body: '濉啓鏇村姞璇︾粏鐨勫彉鏇存弿杩� (鍙��)銆備娇鐢� "|" 鎹㈣ :\n',
+    //   breaking: '鍒椾妇闈炲吋瀹规�ч噸澶х殑鍙樻洿 (鍙��)銆備娇鐢� "|" 鎹㈣ :\n',
+    //   footerPrefixsSelect: '閫夋嫨鍏宠仈issue鍓嶇紑 (鍙��):',
+    //   customFooterPrefixs: '杈撳叆鑷畾涔塱ssue鍓嶇紑 :',
+    //   footer: '鍒椾妇鍏宠仈issue (鍙��) 渚嬪: #31, #I3244 :\n',
+    //   confirmCommit: '鏄惁鎻愪氦鎴栦慨鏀筩ommit ?',
+    // },
+    // types: [
+    //   { value: 'feat', name: 'feat:     鏂板鍔熻兘' },
+    //   { value: 'fix', name: 'fix:      淇缂洪櫡' },
+    //   { value: 'docs', name: 'docs:     鏂囨。鍙樻洿' },
+    //   { value: 'style', name: 'style:    浠g爜鏍煎紡' },
+    //   { value: 'refactor', name: 'refactor: 浠g爜閲嶆瀯' },
+    //   { value: 'perf', name: 'perf:     鎬ц兘浼樺寲' },
+    //   { value: 'test', name: 'test:     娣诲姞鐤忔紡娴嬭瘯鎴栧凡鏈夋祴璇曟敼鍔�' },
+    //   { value: 'build', name: 'build:    鏋勫缓娴佺▼銆佸閮ㄤ緷璧栧彉鏇� (濡傚崌绾� npm 鍖呫�佷慨鏀规墦鍖呴厤缃瓑)' },
+    //   { value: 'ci', name: 'ci:       淇敼 CI 閰嶇疆銆佽剼鏈�' },
+    //   { value: 'revert', name: 'revert:   鍥炴粴 commit' },
+    //   { value: 'chore', name: 'chore:    瀵规瀯寤鸿繃绋嬫垨杈呭姪宸ュ叿鍜屽簱鐨勬洿鏀� (涓嶅奖鍝嶆簮鏂囦欢銆佹祴璇曠敤渚�)' },
+    //   { value: 'wip', name: 'wip:      姝e湪寮�鍙戜腑' },
+    //   { value: 'workflow', name: 'workflow: 宸ヤ綔娴佺▼鏀硅繘' },
+    //   { value: 'types', name: 'types:    绫诲瀷瀹氫箟鏂囦欢淇敼' },
+    // ],
+    // emptyScopesAlias: 'empty:      涓嶅~鍐�',
+    // customScopesAlias: 'custom:     鑷畾涔�',
+  },
+  rules: {
+    /**
+     * type[scope]: [function] description
+     *
+     * ^^^^^^^^^^^^^^ empty line.
+     * - Something here
+     */
+    'body-leading-blank': [2, 'always'],
+    /**
+     * type[scope]: [function] description
+     *
+     * - something here
+     *
+     * ^^^^^^^^^^^^^^
+     */
+    'footer-leading-blank': [1, 'always'],
+    /**
+     * type[scope]: [function] description
+     *      ^^^^^
+     */
+    'function-rules/scope-enum': [
+      2, // level: error
+      'always',
+      (parsed) => {
+        if (!parsed.scope || allowedScopes.includes(parsed.scope)) {
+          return [true];
+        }
+
+        return [false, `scope must be one of ${allowedScopes.join(', ')}`];
+      },
+    ],
+    /**
+     * type[scope]: [function] description [No more than 108 characters]
+     *      ^^^^^
+     */
+    'header-max-length': [2, 'always', 108],
+
+    'scope-enum': [0],
+    'subject-case': [0],
+    'subject-empty': [2, 'never'],
+    'type-empty': [2, 'never'],
+    /**
+     * type[scope]: [function] description
+     * ^^^^
+     */
+    'type-enum': [
+      2,
+      'always',
+      [
+        'feat',
+        'fix',
+        'perf',
+        'style',
+        'docs',
+        'test',
+        'refactor',
+        'build',
+        'ci',
+        'chore',
+        'revert',
+        'types',
+        'release',
+      ],
+    ],
+  },
+};
+
+export default userConfig;
diff --git a/eims-ui/internal/lint-configs/commitlint-config/package.json b/eims-ui/internal/lint-configs/commitlint-config/package.json
new file mode 100644
index 0000000..fecabea
--- /dev/null
+++ b/eims-ui/internal/lint-configs/commitlint-config/package.json
@@ -0,0 +1,33 @@
+{
+  "name": "@vben/commitlint-config",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/lint-configs/commitlint-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "files": [
+    "dist"
+  ],
+  "main": "./index.mjs",
+  "module": "./index.mjs",
+  "exports": {
+    ".": {
+      "import": "./index.mjs",
+      "default": "./index.mjs"
+    }
+  },
+  "dependencies": {
+    "@commitlint/cli": "catalog:",
+    "@commitlint/config-conventional": "catalog:",
+    "@vben/node-utils": "workspace:*",
+    "commitlint-plugin-function-rules": "catalog:",
+    "cz-git": "catalog:",
+    "czg": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/build.config.ts b/eims-ui/internal/lint-configs/eslint-config/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/internal/lint-configs/eslint-config/package.json b/eims-ui/internal/lint-configs/eslint-config/package.json
new file mode 100644
index 0000000..12556ec
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/package.json
@@ -0,0 +1,56 @@
+{
+  "name": "@vben/eslint-config",
+  "version": "5.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/lint-configs/eslint-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.mjs"
+    }
+  },
+  "dependencies": {
+    "eslint-config-turbo": "catalog:",
+    "eslint-plugin-command": "catalog:",
+    "eslint-plugin-import-x": "catalog:"
+  },
+  "devDependencies": {
+    "@eslint/js": "catalog:",
+    "@types/eslint": "catalog:",
+    "@typescript-eslint/eslint-plugin": "catalog:",
+    "@typescript-eslint/parser": "catalog:",
+    "eslint": "catalog:",
+    "eslint-plugin-eslint-comments": "catalog:",
+    "eslint-plugin-jsdoc": "catalog:",
+    "eslint-plugin-jsonc": "catalog:",
+    "eslint-plugin-n": "catalog:",
+    "eslint-plugin-no-only-tests": "catalog:",
+    "eslint-plugin-perfectionist": "catalog:",
+    "eslint-plugin-prettier": "catalog:",
+    "eslint-plugin-regexp": "catalog:",
+    "eslint-plugin-unicorn": "catalog:",
+    "eslint-plugin-unused-imports": "catalog:",
+    "eslint-plugin-vitest": "catalog:",
+    "eslint-plugin-vue": "catalog:",
+    "globals": "catalog:",
+    "jsonc-eslint-parser": "catalog:",
+    "vue-eslint-parser": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/command.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/command.ts
new file mode 100644
index 0000000..67651b2
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/command.ts
@@ -0,0 +1,10 @@
+import createCommand from 'eslint-plugin-command/config';
+
+export async function command() {
+  return [
+    {
+      // @ts-expect-error - no types
+      ...createCommand(),
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/comments.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/comments.ts
new file mode 100644
index 0000000..77ccd5d
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/comments.ts
@@ -0,0 +1,24 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function comments(): Promise<Linter.Config[]> {
+  const [pluginComments] = await Promise.all([
+    // @ts-expect-error - no types
+    interopDefault(import('eslint-plugin-eslint-comments')),
+  ] as const);
+
+  return [
+    {
+      plugins: {
+        'eslint-comments': pluginComments,
+      },
+      rules: {
+        'eslint-comments/no-aggregating-enable': 'error',
+        'eslint-comments/no-duplicate-disable': 'error',
+        'eslint-comments/no-unlimited-disable': 'error',
+        'eslint-comments/no-unused-enable': 'error',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/disableds.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/disableds.ts
new file mode 100644
index 0000000..152b84c
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/disableds.ts
@@ -0,0 +1,28 @@
+import type { Linter } from 'eslint';
+
+export async function disableds(): Promise<Linter.Config[]> {
+  return [
+    {
+      files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'],
+      name: 'disables/test',
+      rules: {
+        '@typescript-eslint/ban-ts-comment': 'off',
+        'no-console': 'off',
+      },
+    },
+    {
+      files: ['**/*.d.ts'],
+      name: 'disables/dts',
+      rules: {
+        '@typescript-eslint/triple-slash-reference': 'off',
+      },
+    },
+    {
+      files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
+      name: 'disables/js',
+      rules: {
+        '@typescript-eslint/explicit-module-boundary-types': 'off',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/ignores.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/ignores.ts
new file mode 100644
index 0000000..136c956
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/ignores.ts
@@ -0,0 +1,52 @@
+import type { Linter } from 'eslint';
+
+export async function ignores(): Promise<Linter.Config[]> {
+  return [
+    {
+      ignores: [
+        '**/node_modules',
+        '**/dist',
+        '**/dist-*',
+        '**/*-dist',
+        '**/.husky',
+        '**/.nitro',
+        '**/.output',
+        '**/Dockerfile',
+        '**/package-lock.json',
+        '**/yarn.lock',
+        '**/pnpm-lock.yaml',
+        '**/bun.lockb',
+        '**/output',
+        '**/coverage',
+        '**/temp',
+        '**/.temp',
+        '**/tmp',
+        '**/.tmp',
+        '**/.history',
+        '**/.turbo',
+        '**/.nuxt',
+        '**/.next',
+        '**/.vercel',
+        '**/.changeset',
+        '**/.idea',
+        '**/.cache',
+        '**/.output',
+        '**/.vite-inspect',
+
+        '**/CHANGELOG*.md',
+        '**/*.min.*',
+        '**/LICENSE*',
+        '**/__snapshots__',
+        '**/*.snap',
+        '**/fixtures/**',
+        '**/.vitepress/cache/**',
+        '**/auto-import?(s).d.ts',
+        '**/components.d.ts',
+        '**/vite.config.mts.*',
+        '**/*.sh',
+        '**/*.ttf',
+        '**/*.woff',
+      ],
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/import.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/import.ts
new file mode 100644
index 0000000..67a08fe
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/import.ts
@@ -0,0 +1,24 @@
+import type { Linter } from 'eslint';
+
+import * as pluginImport from 'eslint-plugin-import-x';
+
+export async function importPluginConfig(): Promise<Linter.Config[]> {
+  return [
+    {
+      plugins: {
+        // @ts-expect-error - This is a dynamic import
+        import: pluginImport,
+      },
+      rules: {
+        'import/first': 'error',
+        'import/newline-after-import': 'error',
+        'import/no-duplicates': 'error',
+        'import/no-mutable-exports': 'error',
+        'import/no-named-default': 'error',
+        'import/no-self-import': 'error',
+        'import/no-unresolved': 'off',
+        'import/no-webpack-loader-syntax': 'error',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/index.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/index.ts
new file mode 100644
index 0000000..c0284ef
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/index.ts
@@ -0,0 +1,17 @@
+export * from './command';
+export * from './comments';
+export * from './disableds';
+export * from './ignores';
+export * from './import';
+export * from './javascript';
+export * from './jsdoc';
+export * from './jsonc';
+export * from './node';
+export * from './perfectionist';
+export * from './prettier';
+export * from './regexp';
+export * from './test';
+export * from './turbo';
+export * from './typescript';
+export * from './unicorn';
+export * from './vue';
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/javascript.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/javascript.ts
new file mode 100644
index 0000000..0d87c1b
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/javascript.ts
@@ -0,0 +1,242 @@
+import type { Linter } from 'eslint';
+
+// @ts-expect-error - no types
+import js from '@eslint/js';
+import pluginUnusedImports from 'eslint-plugin-unused-imports';
+import globals from 'globals';
+
+export async function javascript(): Promise<Linter.Config[]> {
+  return [
+    {
+      languageOptions: {
+        ecmaVersion: 'latest',
+        globals: {
+          ...globals.browser,
+          ...globals.es2021,
+          ...globals.node,
+          document: 'readonly',
+          navigator: 'readonly',
+          window: 'readonly',
+        },
+        parserOptions: {
+          ecmaFeatures: {
+            jsx: true,
+          },
+          ecmaVersion: 'latest',
+          sourceType: 'module',
+        },
+        sourceType: 'module',
+      },
+      linterOptions: {
+        reportUnusedDisableDirectives: true,
+      },
+      plugins: {
+        'unused-imports': pluginUnusedImports,
+      },
+      rules: {
+        ...js.configs.recommended.rules,
+        'accessor-pairs': [
+          'error',
+          { enforceForClassMembers: true, setWithoutGet: true },
+        ],
+        'array-callback-return': 'error',
+        'block-scoped-var': 'error',
+        'constructor-super': 'error',
+        'default-case-last': 'error',
+        'dot-notation': ['error', { allowKeywords: true }],
+        eqeqeq: ['error', 'always'],
+        'keyword-spacing': 'off',
+
+        'new-cap': [
+          'error',
+          { capIsNew: false, newIsCap: true, properties: true },
+        ],
+        'no-alert': 'error',
+        'no-array-constructor': 'error',
+        'no-async-promise-executor': 'error',
+        'no-caller': 'error',
+        'no-case-declarations': 'error',
+        'no-class-assign': 'error',
+        'no-compare-neg-zero': 'error',
+        'no-cond-assign': ['error', 'always'],
+        'no-console': ['error', { allow: ['warn', 'error'] }],
+        'no-const-assign': 'error',
+        'no-control-regex': 'error',
+        'no-debugger': 'error',
+        'no-delete-var': 'error',
+        'no-dupe-args': 'error',
+        'no-dupe-class-members': 'error',
+        'no-dupe-keys': 'error',
+        'no-duplicate-case': 'error',
+        'no-empty': ['error', { allowEmptyCatch: true }],
+        'no-empty-character-class': 'error',
+        'no-empty-function': 'off',
+        'no-empty-pattern': 'error',
+        'no-eval': 'error',
+        'no-ex-assign': 'error',
+        'no-extend-native': 'error',
+        'no-extra-bind': 'error',
+        'no-extra-boolean-cast': 'error',
+        'no-fallthrough': 'error',
+        'no-func-assign': 'error',
+        'no-global-assign': 'error',
+        'no-implied-eval': 'error',
+        'no-import-assign': 'error',
+        'no-invalid-regexp': 'error',
+        'no-irregular-whitespace': 'error',
+        'no-iterator': 'error',
+        'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
+        'no-lone-blocks': 'error',
+        'no-loss-of-precision': 'error',
+        'no-misleading-character-class': 'error',
+        'no-multi-str': 'error',
+        'no-new': 'error',
+        'no-new-func': 'error',
+        'no-new-object': 'error',
+        'no-new-symbol': 'error',
+        'no-new-wrappers': 'error',
+        'no-obj-calls': 'error',
+        'no-octal': 'error',
+        'no-octal-escape': 'error',
+        'no-proto': 'error',
+        'no-prototype-builtins': 'error',
+        'no-redeclare': ['error', { builtinGlobals: false }],
+        'no-regex-spaces': 'error',
+        'no-restricted-globals': [
+          'error',
+          { message: 'Use `globalThis` instead.', name: 'global' },
+          { message: 'Use `globalThis` instead.', name: 'self' },
+        ],
+        'no-restricted-properties': [
+          'error',
+          {
+            message:
+              'Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.',
+            property: '__proto__',
+          },
+          {
+            message: 'Use `Object.defineProperty` instead.',
+            property: '__defineGetter__',
+          },
+          {
+            message: 'Use `Object.defineProperty` instead.',
+            property: '__defineSetter__',
+          },
+          {
+            message: 'Use `Object.getOwnPropertyDescriptor` instead.',
+            property: '__lookupGetter__',
+          },
+          {
+            message: 'Use `Object.getOwnPropertyDescriptor` instead.',
+            property: '__lookupSetter__',
+          },
+        ],
+        'no-restricted-syntax': [
+          'error',
+          'DebuggerStatement',
+          'LabeledStatement',
+          'WithStatement',
+          'TSEnumDeclaration[const=true]',
+          'TSExportAssignment',
+        ],
+        'no-self-assign': ['error', { props: true }],
+        'no-self-compare': 'error',
+        'no-sequences': 'error',
+        'no-shadow-restricted-names': 'error',
+        'no-sparse-arrays': 'error',
+        'no-template-curly-in-string': 'error',
+        'no-this-before-super': 'error',
+        'no-throw-literal': 'error',
+        'no-undef': 'off',
+        'no-undef-init': 'error',
+        'no-unexpected-multiline': 'error',
+        'no-unmodified-loop-condition': 'error',
+        'no-unneeded-ternary': ['error', { defaultAssignment: false }],
+        'no-unreachable': 'error',
+        'no-unreachable-loop': 'error',
+        'no-unsafe-finally': 'error',
+        'no-unsafe-negation': 'error',
+        'no-unused-expressions': [
+          'error',
+          {
+            allowShortCircuit: true,
+            allowTaggedTemplates: true,
+            allowTernary: true,
+          },
+        ],
+        'no-unused-vars': [
+          'error',
+          {
+            args: 'none',
+            caughtErrors: 'none',
+            ignoreRestSiblings: true,
+            vars: 'all',
+          },
+        ],
+        'no-use-before-define': [
+          'error',
+          { classes: false, functions: false, variables: true },
+        ],
+        'no-useless-backreference': 'error',
+        'no-useless-call': 'error',
+        'no-useless-catch': 'error',
+        'no-useless-computed-key': 'error',
+        'no-useless-constructor': 'error',
+        'no-useless-rename': 'error',
+        'no-useless-return': 'error',
+        'no-var': 'error',
+        'no-with': 'error',
+        'object-shorthand': [
+          'error',
+          'always',
+          { avoidQuotes: true, ignoreConstructors: false },
+        ],
+        'one-var': ['error', { initialized: 'never' }],
+        'prefer-arrow-callback': [
+          'error',
+          {
+            allowNamedFunctions: false,
+            allowUnboundThis: true,
+          },
+        ],
+        'prefer-const': [
+          'error',
+          {
+            destructuring: 'all',
+            ignoreReadBeforeAssign: true,
+          },
+        ],
+        'prefer-exponentiation-operator': 'error',
+
+        'prefer-promise-reject-errors': 'error',
+        'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
+        'prefer-rest-params': 'error',
+        'prefer-spread': 'error',
+        'prefer-template': 'error',
+        'space-before-function-paren': 'off',
+        'spaced-comment': 'error',
+        'symbol-description': 'error',
+        'unicode-bom': ['error', 'never'],
+
+        'unused-imports/no-unused-imports': 'error',
+        'unused-imports/no-unused-vars': [
+          'error',
+          {
+            args: 'after-used',
+            argsIgnorePattern: '^_',
+            vars: 'all',
+            varsIgnorePattern: '^_',
+          },
+        ],
+        'use-isnan': [
+          'error',
+          { enforceForIndexOf: true, enforceForSwitchCase: true },
+        ],
+        'valid-typeof': ['error', { requireStringLiterals: true }],
+
+        'vars-on-top': 'error',
+        yoda: ['error', 'never'],
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/jsdoc.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/jsdoc.ts
new file mode 100644
index 0000000..1368197
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/jsdoc.ts
@@ -0,0 +1,34 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function jsdoc(): Promise<Linter.Config[]> {
+  const [pluginJsdoc] = await Promise.all([
+    interopDefault(import('eslint-plugin-jsdoc')),
+  ] as const);
+
+  return [
+    {
+      plugins: {
+        jsdoc: pluginJsdoc,
+      },
+      rules: {
+        'jsdoc/check-access': 'warn',
+        'jsdoc/check-param-names': 'warn',
+        'jsdoc/check-property-names': 'warn',
+        'jsdoc/check-types': 'warn',
+        'jsdoc/empty-tags': 'warn',
+        'jsdoc/implements-on-classes': 'warn',
+        'jsdoc/no-defaults': 'warn',
+        'jsdoc/no-multi-asterisks': 'warn',
+        'jsdoc/require-param-name': 'warn',
+        'jsdoc/require-property': 'warn',
+        'jsdoc/require-property-description': 'warn',
+        'jsdoc/require-property-name': 'warn',
+        'jsdoc/require-returns-check': 'warn',
+        'jsdoc/require-returns-description': 'warn',
+        'jsdoc/require-yields-check': 'warn',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/jsonc.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/jsonc.ts
new file mode 100644
index 0000000..4072e4c
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/jsonc.ts
@@ -0,0 +1,258 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function jsonc(): Promise<Linter.Config[]> {
+  const [pluginJsonc, parserJsonc] = await Promise.all([
+    interopDefault(import('eslint-plugin-jsonc')),
+    interopDefault(import('jsonc-eslint-parser')),
+  ] as const);
+
+  return [
+    {
+      files: ['**/*.json', '**/*.json5', '**/*.jsonc', '*.code-workspace'],
+      languageOptions: {
+        parser: parserJsonc as any,
+      },
+      plugins: {
+        jsonc: pluginJsonc as any,
+      },
+      rules: {
+        'jsonc/no-bigint-literals': 'error',
+        'jsonc/no-binary-expression': 'error',
+        'jsonc/no-binary-numeric-literals': 'error',
+        'jsonc/no-dupe-keys': 'error',
+        'jsonc/no-escape-sequence-in-identifier': 'error',
+        'jsonc/no-floating-decimal': 'error',
+        'jsonc/no-hexadecimal-numeric-literals': 'error',
+        'jsonc/no-infinity': 'error',
+        'jsonc/no-multi-str': 'error',
+        'jsonc/no-nan': 'error',
+        'jsonc/no-number-props': 'error',
+        'jsonc/no-numeric-separators': 'error',
+        'jsonc/no-octal': 'error',
+        'jsonc/no-octal-escape': 'error',
+        'jsonc/no-octal-numeric-literals': 'error',
+        'jsonc/no-parenthesized': 'error',
+        'jsonc/no-plus-sign': 'error',
+        'jsonc/no-regexp-literals': 'error',
+        'jsonc/no-sparse-arrays': 'error',
+        'jsonc/no-template-literals': 'error',
+        'jsonc/no-undefined-value': 'error',
+        'jsonc/no-unicode-codepoint-escapes': 'error',
+        'jsonc/no-useless-escape': 'error',
+        'jsonc/space-unary-ops': 'error',
+        'jsonc/valid-json-number': 'error',
+        'jsonc/vue-custom-block/no-parsing-error': 'error',
+      },
+    },
+    sortTsconfig(),
+    sortPackageJson(),
+  ];
+}
+
+function sortPackageJson(): Linter.Config {
+  return {
+    files: ['**/package.json'],
+    rules: {
+      'jsonc/sort-array-values': [
+        'error',
+        {
+          order: { type: 'asc' },
+          pathPattern: '^files$|^pnpm.neverBuiltDependencies$',
+        },
+      ],
+      'jsonc/sort-keys': [
+        'error',
+        {
+          order: [
+            'name',
+            'version',
+            'description',
+            'private',
+            'keywords',
+            'homepage',
+            'bugs',
+            'repository',
+            'license',
+            'author',
+            'contributors',
+            'categories',
+            'funding',
+            'type',
+            'scripts',
+            'files',
+            'sideEffects',
+            'bin',
+            'main',
+            'module',
+            'unpkg',
+            'jsdelivr',
+            'types',
+            'typesVersions',
+            'imports',
+            'exports',
+            'publishConfig',
+            'icon',
+            'activationEvents',
+            'contributes',
+            'peerDependencies',
+            'peerDependenciesMeta',
+            'dependencies',
+            'optionalDependencies',
+            'devDependencies',
+            'engines',
+            'packageManager',
+            'pnpm',
+            'overrides',
+            'resolutions',
+            'husky',
+            'simple-git-hooks',
+            'lint-staged',
+            'eslintConfig',
+          ],
+          pathPattern: '^$',
+        },
+        {
+          order: { type: 'asc' },
+          pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$',
+        },
+        {
+          order: { type: 'asc' },
+          pathPattern: '^(?:resolutions|overrides|pnpm.overrides)$',
+        },
+        {
+          order: ['types', 'import', 'require', 'default'],
+          pathPattern: '^exports.*$',
+        },
+      ],
+    },
+  };
+}
+
+function sortTsconfig(): Linter.Config {
+  return {
+    files: [
+      '**/tsconfig.json',
+      '**/tsconfig.*.json',
+      'internal/tsconfig/*.json',
+    ],
+    rules: {
+      'jsonc/sort-keys': [
+        'error',
+        {
+          order: [
+            'extends',
+            'compilerOptions',
+            'references',
+            'files',
+            'include',
+            'exclude',
+          ],
+          pathPattern: '^$',
+        },
+        {
+          order: [
+            /* Projects */
+            'incremental',
+            'composite',
+            'tsBuildInfoFile',
+            'disableSourceOfProjectReferenceRedirect',
+            'disableSolutionSearching',
+            'disableReferencedProjectLoad',
+            /* Language and Environment */
+            'target',
+            'jsx',
+            'jsxFactory',
+            'jsxFragmentFactory',
+            'jsxImportSource',
+            'lib',
+            'moduleDetection',
+            'noLib',
+            'reactNamespace',
+            'useDefineForClassFields',
+            'emitDecoratorMetadata',
+            'experimentalDecorators',
+            /* Modules */
+            'baseUrl',
+            'rootDir',
+            'rootDirs',
+            'customConditions',
+            'module',
+            'moduleResolution',
+            'moduleSuffixes',
+            'noResolve',
+            'paths',
+            'resolveJsonModule',
+            'resolvePackageJsonExports',
+            'resolvePackageJsonImports',
+            'typeRoots',
+            'types',
+            'allowArbitraryExtensions',
+            'allowImportingTsExtensions',
+            'allowUmdGlobalAccess',
+            /* JavaScript Support */
+            'allowJs',
+            'checkJs',
+            'maxNodeModuleJsDepth',
+            /* Type Checking */
+            'strict',
+            'strictBindCallApply',
+            'strictFunctionTypes',
+            'strictNullChecks',
+            'strictPropertyInitialization',
+            'allowUnreachableCode',
+            'allowUnusedLabels',
+            'alwaysStrict',
+            'exactOptionalPropertyTypes',
+            'noFallthroughCasesInSwitch',
+            'noImplicitAny',
+            'noImplicitOverride',
+            'noImplicitReturns',
+            'noImplicitThis',
+            'noPropertyAccessFromIndexSignature',
+            'noUncheckedIndexedAccess',
+            'noUnusedLocals',
+            'noUnusedParameters',
+            'useUnknownInCatchVariables',
+            /* Emit */
+            'declaration',
+            'declarationDir',
+            'declarationMap',
+            'downlevelIteration',
+            'emitBOM',
+            'emitDeclarationOnly',
+            'importHelpers',
+            'importsNotUsedAsValues',
+            'inlineSourceMap',
+            'inlineSources',
+            'mapRoot',
+            'newLine',
+            'noEmit',
+            'noEmitHelpers',
+            'noEmitOnError',
+            'outDir',
+            'outFile',
+            'preserveConstEnums',
+            'preserveValueImports',
+            'removeComments',
+            'sourceMap',
+            'sourceRoot',
+            'stripInternal',
+            /* Interop Constraints */
+            'allowSyntheticDefaultImports',
+            'esModuleInterop',
+            'forceConsistentCasingInFileNames',
+            'isolatedModules',
+            'preserveSymlinks',
+            'verbatimModuleSyntax',
+            /* Completeness */
+            'skipDefaultLibCheck',
+            'skipLibCheck',
+          ],
+          pathPattern: '^compilerOptions$',
+        },
+      ],
+    },
+  };
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/node.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/node.ts
new file mode 100644
index 0000000..fa960d8
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/node.ts
@@ -0,0 +1,57 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function node(): Promise<Linter.Config[]> {
+  const pluginNode = await interopDefault(import('eslint-plugin-n'));
+
+  return [
+    {
+      plugins: {
+        n: pluginNode,
+      },
+      rules: {
+        'n/handle-callback-err': ['error', '^(err|error)$'],
+        'n/no-deprecated-api': 'error',
+        'n/no-exports-assign': 'error',
+        'n/no-extraneous-import': [
+          'error',
+          {
+            allowModules: [
+              'unbuild',
+              '@vben/vite-config',
+              'vitest',
+              'vite',
+              '@vue/test-utils',
+              '@vben/tailwind-config',
+              '@playwright/test',
+            ],
+          },
+        ],
+        'n/no-new-require': 'error',
+        'n/no-path-concat': 'error',
+        // 'n/no-unpublished-import': 'off',
+        'n/no-unsupported-features/es-syntax': [
+          'error',
+          {
+            ignores: [],
+            version: '>=18.0.0',
+          },
+        ],
+        'n/prefer-global/buffer': ['error', 'never'],
+        // 'n/no-missing-import': 'off',
+        'n/prefer-global/process': ['error', 'never'],
+        'n/process-exit-as-throw': 'error',
+      },
+    },
+    {
+      files: [
+        'scripts/**/*.?([cm])[jt]s?(x)',
+        'internal/**/*.?([cm])[jt]s?(x)',
+      ],
+      rules: {
+        'n/prefer-global/process': 'off',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/perfectionist.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/perfectionist.ts
new file mode 100644
index 0000000..1b17b30
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/perfectionist.ts
@@ -0,0 +1,112 @@
+import type { Linter } from 'eslint';
+
+import perfectionistPlugin from 'eslint-plugin-perfectionist';
+
+export async function perfectionist(): Promise<Linter.Config[]> {
+  return [
+    perfectionistPlugin.configs['recommended-natural'],
+    {
+      rules: {
+        'perfectionist/sort-exports': [
+          'error',
+          {
+            order: 'asc',
+            type: 'natural',
+          },
+        ],
+        'perfectionist/sort-imports': [
+          'error',
+          {
+            customGroups: {
+              type: {
+                vben: 'vben',
+                vue: 'vue',
+              },
+              value: {
+                vben: ['@vben*', '@vben/**/**', '@vben-core/**/**'],
+                vue: ['vue', 'vue-*', '@vue*'],
+              },
+            },
+            groups: [
+              ['external-type', 'builtin-type', 'type'],
+              ['parent-type', 'sibling-type', 'index-type'],
+              ['internal-type'],
+              'builtin',
+              'vue',
+              'vben',
+              'external',
+              'internal',
+              ['parent', 'sibling', 'index'],
+              'side-effect',
+              'side-effect-style',
+              'style',
+              'object',
+              'unknown',
+            ],
+            internalPattern: ['#*', '#*/**'],
+            newlinesBetween: 'always',
+            order: 'asc',
+            type: 'natural',
+          },
+        ],
+        'perfectionist/sort-named-exports': [
+          'error',
+          {
+            order: 'asc',
+            type: 'natural',
+          },
+        ],
+        'perfectionist/sort-objects': [
+          'error',
+          {
+            customGroups: {
+              items: 'items',
+              list: 'list',
+              children: 'children',
+            },
+            groups: ['unknown', 'items', 'list', 'children'],
+            ignorePattern: ['children'],
+            order: 'asc',
+            partitionByComment: 'Part:**',
+            type: 'natural',
+          },
+        ],
+        'perfectionist/sort-vue-attributes': [
+          'error',
+          {
+            // Based on: https://vuejs.org/style-guide/rules-recommended.html#element-attribute-order
+            customGroups: {
+              /* eslint-disable perfectionist/sort-objects */
+              DEFINITION: '*(is|:is|v-is)',
+              LIST_RENDERING: 'v-for',
+              CONDITIONALS: 'v-*(else-if|if|else|show|cloak)',
+              RENDER_MODIFIERS: 'v-*(pre|once)',
+              GLOBAL: '*(:id|id)',
+              UNIQUE: '*(ref|key|:ref|:key)',
+              SLOT: '*(v-slot|slot)',
+              TWO_WAY_BINDING: '*(v-model|v-model:*)',
+              // OTHER_DIRECTIVES e.g. 'v-custom-directive'
+              EVENTS: '*(v-on|@*)',
+              CONTENT: 'v-*(html|text)',
+              /* eslint-enable perfectionist/sort-objects */
+            },
+            groups: [
+              'DEFINITION',
+              'LIST_RENDERING',
+              'CONDITIONALS',
+              'RENDER_MODIFIERS',
+              'GLOBAL',
+              'UNIQUE',
+              'SLOT',
+              'TWO_WAY_BINDING',
+              'unknown',
+              'EVENTS',
+              'CONTENT',
+            ],
+            type: 'natural',
+          },
+        ],
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/prettier.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/prettier.ts
new file mode 100644
index 0000000..3cd7af4
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/prettier.ts
@@ -0,0 +1,19 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function prettier(): Promise<Linter.Config[]> {
+  const [pluginPrettier] = await Promise.all([
+    interopDefault(import('eslint-plugin-prettier')),
+  ] as const);
+  return [
+    {
+      plugins: {
+        prettier: pluginPrettier,
+      },
+      rules: {
+        'prettier/prettier': 'error',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/regexp.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/regexp.ts
new file mode 100644
index 0000000..c0f4c9f
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/regexp.ts
@@ -0,0 +1,20 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function regexp(): Promise<Linter.Config[]> {
+  const [pluginRegexp] = await Promise.all([
+    interopDefault(import('eslint-plugin-regexp')),
+  ] as const);
+
+  return [
+    {
+      plugins: {
+        regexp: pluginRegexp,
+      },
+      rules: {
+        ...pluginRegexp.configs.recommended.rules,
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/test.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/test.ts
new file mode 100644
index 0000000..ddfde2b
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/test.ts
@@ -0,0 +1,45 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function test(): Promise<Linter.Config[]> {
+  const [pluginTest, pluginNoOnlyTests] = await Promise.all([
+    interopDefault(import('eslint-plugin-vitest')),
+    // @ts-expect-error - no types
+    interopDefault(import('eslint-plugin-no-only-tests')),
+  ] as const);
+
+  return [
+    {
+      files: [
+        `**/__tests__/**/*.?([cm])[jt]s?(x)`,
+        `**/*.spec.?([cm])[jt]s?(x)`,
+        `**/*.test.?([cm])[jt]s?(x)`,
+        `**/*.bench.?([cm])[jt]s?(x)`,
+        `**/*.benchmark.?([cm])[jt]s?(x)`,
+      ],
+      plugins: {
+        test: {
+          ...pluginTest,
+          rules: {
+            ...pluginTest.rules,
+            ...pluginNoOnlyTests.rules,
+          },
+        },
+      },
+      rules: {
+        'no-console': 'off',
+        'node/prefer-global/process': 'off',
+        'test/consistent-test-it': [
+          'error',
+          { fn: 'it', withinDescribe: 'it' },
+        ],
+        'test/no-identical-title': 'error',
+        'test/no-import-node-test': 'error',
+        'test/no-only-tests': 'error',
+        'test/prefer-hooks-in-order': 'error',
+        'test/prefer-lowercase-title': 'error',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/turbo.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/turbo.ts
new file mode 100644
index 0000000..9f6bf75
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/turbo.ts
@@ -0,0 +1,18 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function turbo(): Promise<Linter.Config[]> {
+  const [pluginTurbo] = await Promise.all([
+    // @ts-expect-error - no types
+    interopDefault(import('eslint-config-turbo')),
+  ] as const);
+
+  return [
+    {
+      plugins: {
+        turbo: pluginTurbo,
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/typescript.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/typescript.ts
new file mode 100644
index 0000000..cff9aa4
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/typescript.ts
@@ -0,0 +1,72 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function typescript(): Promise<Linter.Config[]> {
+  const [pluginTs, parserTs] = await Promise.all([
+    interopDefault(import('@typescript-eslint/eslint-plugin')),
+    // @ts-expect-error missing types
+    interopDefault(import('@typescript-eslint/parser')),
+  ] as const);
+
+  return [
+    {
+      files: ['**/*.?([cm])[jt]s?(x)'],
+      languageOptions: {
+        parser: parserTs,
+        parserOptions: {
+          createDefaultProgram: false,
+          ecmaFeatures: {
+            jsx: true,
+          },
+          ecmaVersion: 'latest',
+          extraFileExtensions: ['.vue'],
+          jsxPragma: 'React',
+          project: './tsconfig.*.json',
+          sourceType: 'module',
+        },
+      },
+      plugins: {
+        '@typescript-eslint': pluginTs,
+      },
+      rules: {
+        ...pluginTs.configs['eslint-recommended'].overrides?.[0].rules,
+        ...pluginTs.configs.strict.rules,
+        '@typescript-eslint/ban-ts-comment': [
+          'error',
+          {
+            'ts-check': false,
+            'ts-expect-error': 'allow-with-description',
+            'ts-ignore': 'allow-with-description',
+            'ts-nocheck': 'allow-with-description',
+          },
+        ],
+
+        // '@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
+        '@typescript-eslint/consistent-type-definitions': 'off',
+        '@typescript-eslint/explicit-function-return-type': 'off',
+        '@typescript-eslint/explicit-module-boundary-types': 'off',
+        '@typescript-eslint/no-empty-function': [
+          'error',
+          {
+            allow: ['arrowFunctions', 'functions', 'methods'],
+          },
+        ],
+        '@typescript-eslint/no-explicit-any': 'off',
+        '@typescript-eslint/no-namespace': 'off',
+        '@typescript-eslint/no-non-null-assertion': 'error',
+        '@typescript-eslint/no-unused-expressions': 'off',
+        '@typescript-eslint/no-unused-vars': [
+          'error',
+          {
+            argsIgnorePattern: '^_',
+            varsIgnorePattern: '^_',
+          },
+        ],
+        '@typescript-eslint/no-use-before-define': 'off',
+        '@typescript-eslint/no-var-requires': 'error',
+        'unused-imports/no-unused-vars': 'off',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/unicorn.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/unicorn.ts
new file mode 100644
index 0000000..21b1902
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/unicorn.ts
@@ -0,0 +1,45 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function unicorn(): Promise<Linter.Config[]> {
+  const [pluginUnicorn] = await Promise.all([
+    interopDefault(import('eslint-plugin-unicorn')),
+  ] as const);
+
+  return [
+    {
+      plugins: {
+        unicorn: pluginUnicorn,
+      },
+      rules: {
+        ...pluginUnicorn.configs.recommended.rules,
+
+        'unicorn/better-regex': 'off',
+        'unicorn/consistent-destructuring': 'off',
+        'unicorn/consistent-function-scoping': 'off',
+        'unicorn/expiring-todo-comments': 'off',
+        'unicorn/filename-case': 'off',
+        'unicorn/import-style': 'off',
+        'unicorn/no-array-for-each': 'off',
+        'unicorn/no-null': 'off',
+        'unicorn/no-useless-undefined': 'off',
+        'unicorn/prefer-at': 'off',
+        'unicorn/prefer-dom-node-text-content': 'off',
+        'unicorn/prefer-export-from': ['error', { ignoreUsedVariables: true }],
+        'unicorn/prefer-global-this': 'off',
+        'unicorn/prefer-top-level-await': 'off',
+        'unicorn/prevent-abbreviations': 'off',
+      },
+    },
+    {
+      files: [
+        'scripts/**/*.?([cm])[jt]s?(x)',
+        'internal/**/*.?([cm])[jt]s?(x)',
+      ],
+      rules: {
+        'unicorn/no-process-exit': 'off',
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/configs/vue.ts b/eims-ui/internal/lint-configs/eslint-config/src/configs/vue.ts
new file mode 100644
index 0000000..27cc3cf
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/configs/vue.ts
@@ -0,0 +1,150 @@
+import type { Linter } from 'eslint';
+
+import { interopDefault } from '../util';
+
+export async function vue(): Promise<Linter.Config[]> {
+  const [pluginVue, parserVue, parserTs] = await Promise.all([
+    // @ts-expect-error missing types
+    interopDefault(import('eslint-plugin-vue')),
+    interopDefault(import('vue-eslint-parser')),
+    // @ts-expect-error missing types
+    interopDefault(import('@typescript-eslint/parser')),
+  ] as const);
+
+  return [
+    {
+      files: ['**/*.vue'],
+      languageOptions: {
+        // globals: {
+        //   computed: 'readonly',
+        //   defineEmits: 'readonly',
+        //   defineExpose: 'readonly',
+        //   defineProps: 'readonly',
+        //   onMounted: 'readonly',
+        //   onUnmounted: 'readonly',
+        //   reactive: 'readonly',
+        //   ref: 'readonly',
+        //   shallowReactive: 'readonly',
+        //   shallowRef: 'readonly',
+        //   toRef: 'readonly',
+        //   toRefs: 'readonly',
+        //   watch: 'readonly',
+        //   watchEffect: 'readonly',
+        // },
+        parser: parserVue,
+        parserOptions: {
+          ecmaFeatures: {
+            jsx: true,
+          },
+          extraFileExtensions: ['.vue'],
+          parser: parserTs,
+          sourceType: 'module',
+        },
+      },
+      plugins: {
+        vue: pluginVue,
+      },
+      processor: pluginVue.processors['.vue'],
+      rules: {
+        ...pluginVue.configs.base.rules,
+        ...pluginVue.configs['vue3-essential'].rules,
+        ...pluginVue.configs['vue3-strongly-recommended'].rules,
+        ...pluginVue.configs['vue3-recommended'].rules,
+
+        'vue/attribute-hyphenation': [
+          'error',
+          'always',
+          {
+            ignore: [],
+          },
+        ],
+        'vue/attributes-order': 'off',
+        'vue/block-order': [
+          'error',
+          {
+            order: ['script', 'template', 'style'],
+          },
+        ],
+        'vue/component-name-in-template-casing': ['error', 'PascalCase'],
+        'vue/component-options-name-casing': ['error', 'PascalCase'],
+        'vue/custom-event-name-casing': ['error', 'camelCase'],
+        'vue/define-macros-order': [
+          'error',
+          {
+            order: [
+              'defineOptions',
+              'defineProps',
+              'defineEmits',
+              'defineSlots',
+            ],
+          },
+        ],
+        'vue/dot-location': ['error', 'property'],
+        'vue/dot-notation': ['error', { allowKeywords: true }],
+        'vue/eqeqeq': ['error', 'smart'],
+        'vue/html-closing-bracket-newline': 'error',
+        'vue/html-indent': 'off',
+        // 'vue/html-indent': ['error', 2],
+        'vue/html-quotes': ['error', 'double'],
+        'vue/html-self-closing': [
+          'error',
+          {
+            html: {
+              component: 'always',
+              normal: 'never',
+              void: 'always',
+            },
+            math: 'always',
+            svg: 'always',
+          },
+        ],
+        'vue/max-attributes-per-line': 'off',
+        'vue/multi-word-component-names': 'off',
+        'vue/multiline-html-element-content-newline': 'error',
+        'vue/no-empty-pattern': 'error',
+        'vue/no-extra-parens': ['error', 'functions'],
+        'vue/no-irregular-whitespace': 'error',
+        'vue/no-loss-of-precision': 'error',
+        'vue/no-reserved-component-names': 'off',
+        'vue/no-restricted-syntax': [
+          'error',
+          'DebuggerStatement',
+          'LabeledStatement',
+          'WithStatement',
+        ],
+        'vue/no-restricted-v-bind': ['error', '/^v-/'],
+        'vue/no-sparse-arrays': 'error',
+        'vue/no-unused-refs': 'error',
+        'vue/no-useless-v-bind': 'error',
+        'vue/object-shorthand': [
+          'error',
+          'always',
+          {
+            avoidQuotes: true,
+            ignoreConstructors: false,
+          },
+        ],
+        'vue/one-component-per-file': 'error',
+        'vue/prefer-import-from-vue': 'error',
+        'vue/prefer-separate-static-class': 'error',
+        'vue/prefer-template': 'error',
+        'vue/prop-name-casing': ['error', 'camelCase'],
+        'vue/require-default-prop': 'error',
+        'vue/require-explicit-emits': 'error',
+        'vue/require-prop-types': 'off',
+        'vue/script-setup-uses-vars': 'error',
+        'vue/singleline-html-element-content-newline': 'off',
+        'vue/space-infix-ops': 'error',
+        'vue/space-unary-ops': ['error', { nonwords: false, words: true }],
+        'vue/v-on-event-hyphenation': [
+          'error',
+          'always',
+          {
+            autofix: true,
+            ignore: [],
+          },
+        ],
+      },
+    },
+  ];
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/custom-config.ts b/eims-ui/internal/lint-configs/eslint-config/src/custom-config.ts
new file mode 100644
index 0000000..981c411
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/custom-config.ts
@@ -0,0 +1,165 @@
+import type { Linter } from 'eslint';
+
+const restrictedImportIgnores = [
+  '**/vite.config.mts',
+  '**/tailwind.config.mjs',
+  '**/postcss.config.mjs',
+];
+
+const customConfig: Linter.Config[] = [
+  // shadcn-ui 鍐呴儴缁勪欢鏄嚜鍔ㄧ敓鎴愮殑锛屼笉鍋氬お澶氶檺鍒�
+  {
+    files: ['packages/@core/ui-kit/shadcn-ui/**/**'],
+    rules: {
+      'vue/require-default-prop': 'off',
+    },
+  },
+  {
+    files: [
+      'apps/**/**',
+      'packages/effects/**/**',
+      'packages/utils/**/**',
+      'packages/types/**/**',
+      'packages/locales/**/**',
+    ],
+    ignores: restrictedImportIgnores,
+    rules: {
+      'perfectionist/sort-interfaces': 'off',
+      'perfectionist/sort-objects': 'off',
+    },
+  },
+  {
+    // apps鍐呴儴鐨勪竴浜涘熀纭�瑙勫垯
+    files: ['apps/**/**'],
+    ignores: restrictedImportIgnores,
+    rules: {
+      // 鍏佽浣跨敤void绫诲瀷
+      '@typescript-eslint/no-invalid-void-type': 'off',
+      // 鍏抽棴 涓嶅厑璁镐娇鐢╟onsole
+      'no-console': 'off',
+      'no-restricted-imports': [
+        'error',
+        {
+          patterns: [
+            {
+              group: ['#/api/*'],
+              message:
+                'The #/api package cannot be imported, please use the @core package itself',
+            },
+            {
+              group: ['#/layouts/*'],
+              message:
+                'The #/layouts package cannot be imported, please use the @core package itself',
+            },
+            {
+              group: ['#/locales/*'],
+              message:
+                'The #/locales package cannot be imported, please use the @core package itself',
+            },
+            {
+              group: ['#/stores/*'],
+              message:
+                'The #/stores package cannot be imported, please use the @core package itself',
+            },
+          ],
+        },
+      ],
+      'perfectionist/sort-interfaces': 'off',
+    },
+  },
+  {
+    // @core鍐呴儴缁勪欢锛屼笉鑳藉紩鍏vben/* 閲岄潰鐨勫寘
+    files: ['packages/@core/**/**'],
+    ignores: restrictedImportIgnores,
+    rules: {
+      'no-restricted-imports': [
+        'error',
+        {
+          patterns: [
+            {
+              group: ['@vben/*'],
+              message:
+                'The @core package cannot import the @vben package, please use the @core package itself',
+            },
+          ],
+        },
+      ],
+    },
+  },
+  {
+    // @core/shared鍐呴儴缁勪欢锛屼笉鑳藉紩鍏vben/* 鎴栬�� @vben-core/* 閲岄潰鐨勫寘
+    files: ['packages/@core/base/**/**'],
+    ignores: restrictedImportIgnores,
+    rules: {
+      'no-restricted-imports': [
+        'error',
+        {
+          patterns: [
+            {
+              group: ['@vben/*', '@vben-core/*'],
+              message:
+                'The @vben-core/shared package cannot import the @vben package, please use the @core/shared package itself',
+            },
+          ],
+        },
+      ],
+    },
+  },
+
+  {
+    // 涓嶈兘寮曞叆@vben/*閲岄潰鐨勫寘
+    files: [
+      'packages/types/**/**',
+      'packages/utils/**/**',
+      'packages/icons/**/**',
+      'packages/constants/**/**',
+      'packages/styles/**/**',
+      'packages/stores/**/**',
+      'packages/preferences/**/**',
+      'packages/locales/**/**',
+    ],
+    ignores: restrictedImportIgnores,
+    rules: {
+      'no-restricted-imports': [
+        'error',
+        {
+          patterns: [
+            {
+              group: ['@vben/*'],
+              message:
+                'The @vben package cannot be imported, please use the @core package itself',
+            },
+          ],
+        },
+      ],
+    },
+  },
+  // 鍚庣妯℃嫙浠g爜锛屼笉闇�瑕佸お澶氳鍒�
+  {
+    files: ['apps/backend-mock/**/**', 'docs/**/**'],
+    rules: {
+      '@typescript-eslint/no-extraneous-class': 'off',
+      'n/no-extraneous-import': 'off',
+      'n/prefer-global/buffer': 'off',
+      'n/prefer-global/process': 'off',
+      'no-console': 'off',
+      'unicorn/prefer-module': 'off',
+    },
+  },
+  {
+    files: ['**/**/playwright.config.ts'],
+    rules: {
+      'n/prefer-global/buffer': 'off',
+      'n/prefer-global/process': 'off',
+      'no-console': 'off',
+    },
+  },
+  {
+    files: ['internal/**/**', 'scripts/**/**'],
+    rules: {
+      'no-console': 'off',
+    },
+  },
+];
+
+export { customConfig };
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/index.ts b/eims-ui/internal/lint-configs/eslint-config/src/index.ts
new file mode 100644
index 0000000..c9f08bd
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/index.ts
@@ -0,0 +1,60 @@
+import type { Linter } from 'eslint';
+
+import {
+  command,
+  comments,
+  disableds,
+  ignores,
+  importPluginConfig,
+  javascript,
+  jsdoc,
+  jsonc,
+  node,
+  perfectionist,
+  prettier,
+  regexp,
+  test,
+  turbo,
+  typescript,
+  unicorn,
+  vue,
+} from './configs';
+import { customConfig } from './custom-config';
+
+type FlatConfig = Linter.Config;
+
+type FlatConfigPromise =
+  | FlatConfig
+  | FlatConfig[]
+  | Promise<FlatConfig>
+  | Promise<FlatConfig[]>;
+
+async function defineConfig(config: FlatConfig[] = []) {
+  const configs: FlatConfigPromise[] = [
+    vue(),
+    javascript(),
+    ignores(),
+    prettier(),
+    typescript(),
+    jsonc(),
+    disableds(),
+    importPluginConfig(),
+    node(),
+    perfectionist(),
+    comments(),
+    jsdoc(),
+    unicorn(),
+    test(),
+    regexp(),
+    command(),
+    turbo(),
+    ...customConfig,
+    ...config,
+  ];
+
+  const resolved = await Promise.all(configs);
+
+  return resolved.flat();
+}
+
+export { defineConfig };
diff --git a/eims-ui/internal/lint-configs/eslint-config/src/util.ts b/eims-ui/internal/lint-configs/eslint-config/src/util.ts
new file mode 100644
index 0000000..d1a10ad
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/src/util.ts
@@ -0,0 +1,8 @@
+export type Awaitable<T> = Promise<T> | T;
+
+export async function interopDefault<T>(
+  m: Awaitable<T>,
+): Promise<T extends { default: infer U } ? U : T> {
+  const resolved = await m;
+  return (resolved as any).default || resolved;
+}
diff --git a/eims-ui/internal/lint-configs/eslint-config/tsconfig.json b/eims-ui/internal/lint-configs/eslint-config/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/internal/lint-configs/eslint-config/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/internal/lint-configs/prettier-config/index.mjs b/eims-ui/internal/lint-configs/prettier-config/index.mjs
new file mode 100644
index 0000000..f6a20c8
--- /dev/null
+++ b/eims-ui/internal/lint-configs/prettier-config/index.mjs
@@ -0,0 +1,18 @@
+export default {
+  endOfLine: 'auto',
+  overrides: [
+    {
+      files: ['*.json5'],
+      options: {
+        quoteProps: 'preserve',
+        singleQuote: false,
+      },
+    },
+  ],
+  plugins: ['prettier-plugin-tailwindcss'],
+  printWidth: 80,
+  proseWrap: 'never',
+  semi: true,
+  singleQuote: true,
+  trailingComma: 'all',
+};
diff --git a/eims-ui/internal/lint-configs/prettier-config/package.json b/eims-ui/internal/lint-configs/prettier-config/package.json
new file mode 100644
index 0000000..65e8b8f
--- /dev/null
+++ b/eims-ui/internal/lint-configs/prettier-config/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "@vben/prettier-config",
+  "version": "5.0.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/lint-configs/prettier-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "files": [
+    "dist"
+  ],
+  "main": "./index.mjs",
+  "module": "./index.mjs",
+  "exports": {
+    ".": {
+      "default": "./index.mjs"
+    }
+  },
+  "dependencies": {
+    "prettier": "catalog:",
+    "prettier-plugin-tailwindcss": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/lint-configs/stylelint-config/index.mjs b/eims-ui/internal/lint-configs/stylelint-config/index.mjs
new file mode 100644
index 0000000..7ef175c
--- /dev/null
+++ b/eims-ui/internal/lint-configs/stylelint-config/index.mjs
@@ -0,0 +1,140 @@
+export default {
+  extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
+  ignoreFiles: [
+    '**/*.js',
+    '**/*.jsx',
+    '**/*.tsx',
+    '**/*.ts',
+    '**/*.json',
+    '**/*.md',
+  ],
+  overrides: [
+    {
+      customSyntax: 'postcss-html',
+      files: ['*.(html|vue)', '**/*.(html|vue)'],
+      rules: {
+        'selector-pseudo-class-no-unknown': [
+          true,
+          {
+            ignorePseudoClasses: ['global', 'deep'],
+          },
+        ],
+        'selector-pseudo-element-no-unknown': [
+          true,
+          {
+            ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'],
+          },
+        ],
+      },
+    },
+    {
+      customSyntax: 'postcss-scss',
+      extends: [
+        'stylelint-config-recommended-scss',
+        'stylelint-config-recommended-vue/scss',
+      ],
+      files: ['*.scss', '**/*.scss'],
+    },
+  ],
+  plugins: [
+    'stylelint-order',
+    '@stylistic/stylelint-plugin',
+    'stylelint-prettier',
+    'stylelint-scss',
+  ],
+  rules: {
+    'at-rule-no-unknown': [
+      true,
+      {
+        ignoreAtRules: [
+          'extends',
+          'ignores',
+          'include',
+          'mixin',
+          'if',
+          'else',
+          'media',
+          'for',
+          'at-root',
+          'tailwind',
+          'apply',
+          'variants',
+          'responsive',
+          'screen',
+          'function',
+          'each',
+          'use',
+          'forward',
+          'return',
+        ],
+      },
+    ],
+    'font-family-no-missing-generic-family-keyword': null,
+    'function-no-unknown': null,
+    'import-notation': null,
+    'media-feature-range-notation': null,
+    'named-grid-areas-no-invalid': null,
+    'no-descending-specificity': null,
+    'no-empty-source': null,
+    'order/order': [
+      [
+        'dollar-variables',
+        'custom-properties',
+        'at-rules',
+        'declarations',
+        {
+          name: 'supports',
+          type: 'at-rule',
+        },
+        {
+          name: 'media',
+          type: 'at-rule',
+        },
+        {
+          name: 'include',
+          type: 'at-rule',
+        },
+        'rules',
+      ],
+      { severity: 'error' },
+    ],
+    'prettier/prettier': true,
+    'rule-empty-line-before': [
+      'always',
+      {
+        ignore: ['after-comment', 'first-nested'],
+      },
+    ],
+    'scss/at-rule-no-unknown': [
+      true,
+      {
+        ignoreAtRules: [
+          'extends',
+          'ignores',
+          'include',
+          'mixin',
+          'if',
+          'else',
+          'media',
+          'for',
+          'at-root',
+          'tailwind',
+          'apply',
+          'variants',
+          'responsive',
+          'screen',
+          'function',
+          'each',
+          'use',
+          'forward',
+          'return',
+        ],
+      },
+    ],
+    'scss/operator-no-newline-after': null,
+    'selector-class-pattern':
+      '^(?:(?:o|c|u|t|s|is|has|_|js|qa)-)?[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*(?:__[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:--[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)?(?:[.+])?$',
+
+    'selector-not-notation': null,
+  },
+};
diff --git a/eims-ui/internal/lint-configs/stylelint-config/package.json b/eims-ui/internal/lint-configs/stylelint-config/package.json
new file mode 100644
index 0000000..514cbf7
--- /dev/null
+++ b/eims-ui/internal/lint-configs/stylelint-config/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "@vben/stylelint-config",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/lint-configs/stylelint-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "files": [
+    "dist"
+  ],
+  "main": "./index.mjs",
+  "module": "./index.mjs",
+  "exports": {
+    ".": {
+      "import": "./index.mjs",
+      "default": "./index.mjs"
+    }
+  },
+  "dependencies": {
+    "@stylistic/stylelint-plugin": "catalog:",
+    "stylelint-config-recess-order": "catalog:",
+    "stylelint-scss": "catalog:"
+  },
+  "devDependencies": {
+    "postcss": "catalog:",
+    "postcss-html": "catalog:",
+    "postcss-scss": "catalog:",
+    "prettier": "catalog:",
+    "stylelint": "catalog:",
+    "stylelint-config-recommended": "catalog:",
+    "stylelint-config-recommended-scss": "catalog:",
+    "stylelint-config-recommended-vue": "catalog:",
+    "stylelint-config-standard": "catalog:",
+    "stylelint-order": "catalog:",
+    "stylelint-prettier": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/node-utils/build.config.ts b/eims-ui/internal/node-utils/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/internal/node-utils/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/internal/node-utils/package.json b/eims-ui/internal/node-utils/package.json
new file mode 100644
index 0000000..7bbf40d
--- /dev/null
+++ b/eims-ui/internal/node-utils/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "@vben/node-utils",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/node-utils"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "import": "./dist/index.mjs",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "dependencies": {
+    "@changesets/git": "catalog:",
+    "@manypkg/get-packages": "catalog:",
+    "chalk": "catalog:",
+    "consola": "catalog:",
+    "dayjs": "catalog:",
+    "execa": "catalog:",
+    "find-up": "catalog:",
+    "ora": "catalog:",
+    "pkg-types": "catalog:",
+    "prettier": "catalog:",
+    "rimraf": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/node-utils/src/__tests__/hash.test.ts b/eims-ui/internal/node-utils/src/__tests__/hash.test.ts
new file mode 100644
index 0000000..3851306
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/__tests__/hash.test.ts
@@ -0,0 +1,52 @@
+import { createHash } from 'node:crypto';
+
+import { describe, expect, it } from 'vitest';
+
+import { generatorContentHash } from '../hash';
+
+describe('generatorContentHash', () => {
+  it('should generate an MD5 hash for the content', () => {
+    const content = 'example content';
+    const expectedHash = createHash('md5')
+      .update(content, 'utf8')
+      .digest('hex');
+    const actualHash = generatorContentHash(content);
+    expect(actualHash).toBe(expectedHash);
+  });
+
+  it('should generate an MD5 hash with specified length', () => {
+    const content = 'example content';
+    const hashLength = 10;
+    const generatedHash = generatorContentHash(content, hashLength);
+    expect(generatedHash).toHaveLength(hashLength);
+  });
+
+  it('should correctly generate the hash with specified length', () => {
+    const content = 'example content';
+    const hashLength = 8;
+    const expectedHash = createHash('md5')
+      .update(content, 'utf8')
+      .digest('hex')
+      .slice(0, hashLength);
+    const generatedHash = generatorContentHash(content, hashLength);
+    expect(generatedHash).toBe(expectedHash);
+  });
+
+  it('should return full hash if hash length parameter is not provided', () => {
+    const content = 'example content';
+    const expectedHash = createHash('md5')
+      .update(content, 'utf8')
+      .digest('hex');
+    const actualHash = generatorContentHash(content);
+    expect(actualHash).toBe(expectedHash);
+  });
+
+  it('should handle empty content', () => {
+    const content = '';
+    const expectedHash = createHash('md5')
+      .update(content, 'utf8')
+      .digest('hex');
+    const actualHash = generatorContentHash(content);
+    expect(actualHash).toBe(expectedHash);
+  });
+});
diff --git a/eims-ui/internal/node-utils/src/__tests__/path.test.ts b/eims-ui/internal/node-utils/src/__tests__/path.test.ts
new file mode 100644
index 0000000..3bab5a1
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/__tests__/path.test.ts
@@ -0,0 +1,67 @@
+// pathUtils.test.ts
+
+import { describe, expect, it } from 'vitest';
+
+import { toPosixPath } from '../path';
+
+describe('toPosixPath', () => {
+  // 娴嬭瘯 Windows 椋庢牸璺緞鍒� POSIX 椋庢牸璺緞鐨勮浆鎹�
+  it('converts Windows-style paths to POSIX paths', () => {
+    const windowsPath = String.raw`C:\Users\Example\file.txt`;
+    const expectedPosixPath = 'C:/Users/Example/file.txt';
+    expect(toPosixPath(windowsPath)).toBe(expectedPosixPath);
+  });
+
+  // 纭 POSIX 椋庢牸璺緞涓嶄細琚敼鍙�
+  it('leaves POSIX-style paths unchanged', () => {
+    const posixPath = '/home/user/file.txt';
+    expect(toPosixPath(posixPath)).toBe(posixPath);
+  });
+
+  // 娴嬭瘯甯︽湁澶氫釜鍒嗛殧绗︾殑璺緞
+  it('converts paths with mixed separators', () => {
+    const mixedPath = String.raw`C:/Users\Example\file.txt`;
+    const expectedPosixPath = 'C:/Users/Example/file.txt';
+    expect(toPosixPath(mixedPath)).toBe(expectedPosixPath);
+  });
+
+  // 娴嬭瘯绌哄瓧绗︿覆
+  it('handles empty strings', () => {
+    const emptyPath = '';
+    expect(toPosixPath(emptyPath)).toBe('');
+  });
+
+  // 娴嬭瘯浠呭寘鍚垎闅旂鐨勮矾寰�
+  it('handles path with only separators', () => {
+    const separatorsPath = '\\\\\\';
+    const expectedPosixPath = '///';
+    expect(toPosixPath(separatorsPath)).toBe(expectedPosixPath);
+  });
+
+  // 娴嬭瘯涓嶅寘鍚换浣曞垎闅旂鐨勮矾寰�
+  it('handles path without separators', () => {
+    const noSeparatorPath = 'file.txt';
+    expect(toPosixPath(noSeparatorPath)).toBe('file.txt');
+  });
+
+  // 娴嬭瘯浠ュ垎闅旂缁撳熬鐨勮矾寰�
+  it('handles path ending with a separator', () => {
+    const endingSeparatorPath = 'C:\\Users\\Example\\';
+    const expectedPosixPath = 'C:/Users/Example/';
+    expect(toPosixPath(endingSeparatorPath)).toBe(expectedPosixPath);
+  });
+
+  // 娴嬭瘯浠ュ垎闅旂寮�澶寸殑璺緞
+  it('handles path starting with a separator', () => {
+    const startingSeparatorPath = String.raw`\Users\Example`;
+    const expectedPosixPath = '/Users/Example';
+    expect(toPosixPath(startingSeparatorPath)).toBe(expectedPosixPath);
+  });
+
+  // 娴嬭瘯鍖呭惈闈炴硶瀛楃鐨勮矾寰�
+  it('handles path with invalid characters', () => {
+    const invalidCharsPath = String.raw`C:\Us*?ers\Ex<ample>|file.txt`;
+    const expectedPosixPath = 'C:/Us*?ers/Ex<ample>|file.txt';
+    expect(toPosixPath(invalidCharsPath)).toBe(expectedPosixPath);
+  });
+});
diff --git a/eims-ui/internal/node-utils/src/constants.ts b/eims-ui/internal/node-utils/src/constants.ts
new file mode 100644
index 0000000..71d8a6c
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/constants.ts
@@ -0,0 +1,6 @@
+enum UNICODE {
+  FAILURE = '\u2716', // 鉁�
+  SUCCESS = '\u2714', // 鉁�
+}
+
+export { UNICODE };
diff --git a/eims-ui/internal/node-utils/src/date.ts b/eims-ui/internal/node-utils/src/date.ts
new file mode 100644
index 0000000..d36572d
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/date.ts
@@ -0,0 +1,12 @@
+import dayjs from 'dayjs';
+import timezone from 'dayjs/plugin/timezone';
+import utc from 'dayjs/plugin/utc';
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+dayjs.tz.setDefault('Asia/Shanghai');
+
+const dateUtil = dayjs;
+
+export { dateUtil };
diff --git a/eims-ui/internal/node-utils/src/fs.ts b/eims-ui/internal/node-utils/src/fs.ts
new file mode 100644
index 0000000..8eec357
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/fs.ts
@@ -0,0 +1,39 @@
+import { promises as fs } from 'node:fs';
+import { dirname } from 'node:path';
+
+export async function outputJSON(
+  filePath: string,
+  data: any,
+  spaces: number = 2,
+) {
+  try {
+    const dir = dirname(filePath);
+    await fs.mkdir(dir, { recursive: true });
+    const jsonData = JSON.stringify(data, null, spaces);
+    await fs.writeFile(filePath, jsonData, 'utf8');
+  } catch (error) {
+    console.error('Error writing JSON file:', error);
+    throw error;
+  }
+}
+
+export async function ensureFile(filePath: string) {
+  try {
+    const dir = dirname(filePath);
+    await fs.mkdir(dir, { recursive: true });
+    await fs.writeFile(filePath, '', { flag: 'a' });
+  } catch (error) {
+    console.error('Error ensuring file:', error);
+    throw error;
+  }
+}
+
+export async function readJSON(filePath: string) {
+  try {
+    const data = await fs.readFile(filePath, 'utf8');
+    return JSON.parse(data);
+  } catch (error) {
+    console.error('Error reading JSON file:', error);
+    throw error;
+  }
+}
diff --git a/eims-ui/internal/node-utils/src/git.ts b/eims-ui/internal/node-utils/src/git.ts
new file mode 100644
index 0000000..88f159c
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/git.ts
@@ -0,0 +1,34 @@
+import path from 'node:path';
+
+import { execa } from 'execa';
+
+export * from '@changesets/git';
+
+/**
+ * 鑾峰彇鏆傚瓨鍖烘枃浠�
+ */
+async function getStagedFiles(): Promise<string[]> {
+  try {
+    const { stdout } = await execa('git', [
+      '-c',
+      'submodule.recurse=false',
+      'diff',
+      '--staged',
+      '--diff-filter=ACMR',
+      '--name-only',
+      '--ignore-submodules',
+      '-z',
+    ]);
+
+    let changedList = stdout ? stdout.replace(/\0$/, '').split('\0') : [];
+    changedList = changedList.map((item) => path.resolve(process.cwd(), item));
+    const changedSet = new Set(changedList);
+    changedSet.delete('');
+    return [...changedSet];
+  } catch (error) {
+    console.error('Failed to get staged files:', error);
+    return [];
+  }
+}
+
+export { getStagedFiles };
diff --git a/eims-ui/internal/node-utils/src/hash.ts b/eims-ui/internal/node-utils/src/hash.ts
new file mode 100644
index 0000000..81f6b05
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/hash.ts
@@ -0,0 +1,18 @@
+import { createHash } from 'node:crypto';
+
+/**
+ * 鐢熶骇鍩轰簬鍐呭鐨� hash锛屽彲鑷畾涔夐暱搴�
+ * @param content
+ * @param hashLSize
+ */
+function generatorContentHash(content: string, hashLSize?: number) {
+  const hash = createHash('md5').update(content, 'utf8').digest('hex');
+
+  if (hashLSize) {
+    return hash.slice(0, hashLSize);
+  }
+
+  return hash;
+}
+
+export { generatorContentHash };
diff --git a/eims-ui/internal/node-utils/src/index.ts b/eims-ui/internal/node-utils/src/index.ts
new file mode 100644
index 0000000..2e39ccf
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/index.ts
@@ -0,0 +1,19 @@
+export * from './constants';
+export * from './date';
+export * from './fs';
+export * from './git';
+export { add as gitAdd, getStagedFiles } from './git';
+export { generatorContentHash } from './hash';
+export * from './monorepo';
+export { toPosixPath } from './path';
+export { prettierFormat } from './prettier';
+export * from './spinner';
+export type { Package } from '@manypkg/get-packages';
+export { default as colors } from 'chalk';
+export { consola } from 'consola';
+export * from 'execa';
+
+export { default as fs } from 'node:fs/promises';
+
+export { type PackageJson, readPackageJSON } from 'pkg-types';
+export { rimraf } from 'rimraf';
diff --git a/eims-ui/internal/node-utils/src/monorepo.ts b/eims-ui/internal/node-utils/src/monorepo.ts
new file mode 100644
index 0000000..b6373e7
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/monorepo.ts
@@ -0,0 +1,46 @@
+import { dirname } from 'node:path';
+
+import {
+  getPackages as getPackagesFunc,
+  getPackagesSync as getPackagesSyncFunc,
+} from '@manypkg/get-packages';
+import { findUpSync } from 'find-up';
+
+/**
+ * 鏌ユ壘澶т粨鐨勬牴鐩綍
+ * @param cwd
+ */
+function findMonorepoRoot(cwd: string = process.cwd()) {
+  const lockFile = findUpSync('pnpm-lock.yaml', {
+    cwd,
+    type: 'file',
+  });
+  return dirname(lockFile || '');
+}
+
+/**
+ * 鑾峰彇澶т粨鐨勬墍鏈夊寘
+ */
+function getPackagesSync() {
+  const root = findMonorepoRoot();
+  return getPackagesSyncFunc(root);
+}
+
+/**
+ * 鑾峰彇澶т粨鐨勬墍鏈夊寘
+ */
+async function getPackages() {
+  const root = findMonorepoRoot();
+
+  return await getPackagesFunc(root);
+}
+
+/**
+ * 鑾峰彇澶т粨鎸囧畾鐨勫寘
+ */
+async function getPackage(pkgName: string) {
+  const { packages } = await getPackages();
+  return packages.find((pkg) => pkg.packageJson.name === pkgName);
+}
+
+export { findMonorepoRoot, getPackage, getPackages, getPackagesSync };
diff --git a/eims-ui/internal/node-utils/src/path.ts b/eims-ui/internal/node-utils/src/path.ts
new file mode 100644
index 0000000..e625fd2
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/path.ts
@@ -0,0 +1,11 @@
+import { posix } from 'node:path';
+
+/**
+ * 灏嗙粰瀹氱殑鏂囦欢璺緞杞崲涓� POSIX 椋庢牸銆�
+ * @param {string} pathname - 鍘熷鏂囦欢璺緞銆�
+ */
+function toPosixPath(pathname: string) {
+  return pathname.split(`\\`).join(posix.sep);
+}
+
+export { toPosixPath };
diff --git a/eims-ui/internal/node-utils/src/prettier.ts b/eims-ui/internal/node-utils/src/prettier.ts
new file mode 100644
index 0000000..1e1525d
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/prettier.ts
@@ -0,0 +1,21 @@
+import fs from 'node:fs/promises';
+
+import { format, getFileInfo, resolveConfig } from 'prettier';
+
+async function prettierFormat(filepath: string) {
+  const prettierOptions = await resolveConfig(filepath, {});
+
+  const fileInfo = await getFileInfo(filepath);
+
+  const input = await fs.readFile(filepath, 'utf8');
+  const output = await format(input, {
+    ...prettierOptions,
+    parser: fileInfo.inferredParser as any,
+  });
+  if (output !== input) {
+    await fs.writeFile(filepath, output, 'utf8');
+  }
+  return output;
+}
+
+export { prettierFormat };
diff --git a/eims-ui/internal/node-utils/src/spinner.ts b/eims-ui/internal/node-utils/src/spinner.ts
new file mode 100644
index 0000000..f07cc25
--- /dev/null
+++ b/eims-ui/internal/node-utils/src/spinner.ts
@@ -0,0 +1,24 @@
+import ora, { type Ora } from 'ora';
+
+interface SpinnerOptions {
+  failedText?: string;
+  successText?: string;
+  title: string;
+}
+export async function spinner<T>(
+  { failedText, successText, title }: SpinnerOptions,
+  callback: () => Promise<T>,
+): Promise<T> {
+  const loading: Ora = ora(title).start();
+
+  try {
+    const result = await callback();
+    loading.succeed(successText || 'Success!');
+    return result;
+  } catch (error) {
+    loading.fail(failedText || 'Failed!');
+    throw error;
+  } finally {
+    loading.stop();
+  }
+}
diff --git a/eims-ui/internal/node-utils/tsconfig.json b/eims-ui/internal/node-utils/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/internal/node-utils/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/internal/tailwind-config/build.config.ts b/eims-ui/internal/tailwind-config/build.config.ts
new file mode 100644
index 0000000..1f3c3c2
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/build.config.ts
@@ -0,0 +1,10 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index', './src/postcss.config'],
+  rollup: {
+    emitCJS: true,
+  },
+});
diff --git a/eims-ui/internal/tailwind-config/package.json b/eims-ui/internal/tailwind-config/package.json
new file mode 100644
index 0000000..946141d
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/package.json
@@ -0,0 +1,66 @@
+{
+  "name": "@vben/tailwind-config",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/tailwind-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "typesVersions": {
+    "*": {
+      "*": [
+        "./dist/*",
+        "./*"
+      ]
+    }
+  },
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "import": "./dist/index.mjs",
+      "require": "./dist/index.cjs"
+    },
+    "./postcss": {
+      "types": "./src/postcss.config.ts",
+      "import": "./dist/postcss.config.mjs",
+      "require": "./dist/postcss.config.cjs",
+      "default": "./dist/postcss.config.mjs"
+    },
+    "./*": "./*"
+  },
+  "peerDependencies": {
+    "tailwindcss": "^3.4.3"
+  },
+  "dependencies": {
+    "@iconify/json": "catalog:",
+    "@iconify/tailwind": "catalog:",
+    "@manypkg/get-packages": "catalog:",
+    "@tailwindcss/nesting": "catalog:",
+    "@tailwindcss/typography": "catalog:",
+    "autoprefixer": "catalog:",
+    "cssnano": "catalog:",
+    "postcss": "catalog:",
+    "postcss-antd-fixes": "catalog:",
+    "postcss-import": "catalog:",
+    "postcss-preset-env": "catalog:",
+    "tailwindcss": "catalog:",
+    "tailwindcss-animate": "catalog:"
+  },
+  "devDependencies": {
+    "@types/postcss-import": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/tailwind-config/src/index.ts b/eims-ui/internal/tailwind-config/src/index.ts
new file mode 100644
index 0000000..dafaaf9
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/src/index.ts
@@ -0,0 +1,266 @@
+import type { Config } from 'tailwindcss';
+
+import path from 'node:path';
+
+import { addDynamicIconSelectors } from '@iconify/tailwind';
+import { getPackagesSync } from '@manypkg/get-packages';
+import typographyPlugin from '@tailwindcss/typography';
+import animate from 'tailwindcss-animate';
+
+import { enterAnimationPlugin } from './plugins/entry';
+
+// import defaultTheme from 'tailwindcss/defaultTheme';
+
+const { packages } = getPackagesSync(process.cwd());
+
+const tailwindPackages: string[] = [];
+
+packages.forEach((pkg) => {
+  // apps鐩綍涓嬪拰 @vben-core/tailwind-ui 鍖呴渶瑕佷娇鐢ㄥ埌 tailwindcss ui
+  // if (fs.existsSync(path.join(pkg.dir, 'tailwind.config.mjs'))) {
+  tailwindPackages.push(pkg.dir);
+  // }
+});
+
+const shadcnUiColors = {
+  accent: {
+    DEFAULT: 'hsl(var(--accent))',
+    foreground: 'hsl(var(--accent-foreground))',
+    hover: 'hsl(var(--accent-hover))',
+    lighter: 'has(val(--accent-lighter))',
+  },
+  background: {
+    deep: 'hsl(var(--background-deep))',
+    DEFAULT: 'hsl(var(--background))',
+  },
+  border: {
+    DEFAULT: 'hsl(var(--border))',
+  },
+  card: {
+    DEFAULT: 'hsl(var(--card))',
+    foreground: 'hsl(var(--card-foreground))',
+  },
+  destructive: {
+    ...createColorsPalette('destructive'),
+    DEFAULT: 'hsl(var(--destructive))',
+  },
+
+  foreground: {
+    DEFAULT: 'hsl(var(--foreground))',
+  },
+
+  input: {
+    background: 'hsl(var(--input-background))',
+    DEFAULT: 'hsl(var(--input))',
+  },
+  muted: {
+    DEFAULT: 'hsl(var(--muted))',
+    foreground: 'hsl(var(--muted-foreground))',
+  },
+  popover: {
+    DEFAULT: 'hsl(var(--popover))',
+    foreground: 'hsl(var(--popover-foreground))',
+  },
+  primary: {
+    ...createColorsPalette('primary'),
+    DEFAULT: 'hsl(var(--primary))',
+  },
+
+  ring: 'hsl(var(--ring))',
+  secondary: {
+    DEFAULT: 'hsl(var(--secondary))',
+    desc: 'hsl(var(--secondary-desc))',
+    foreground: 'hsl(var(--secondary-foreground))',
+  },
+};
+
+const customColors = {
+  green: {
+    ...createColorsPalette('green'),
+    foreground: 'hsl(var(--success-foreground))',
+  },
+  header: {
+    DEFAULT: 'hsl(var(--header))',
+  },
+  heavy: {
+    DEFAULT: 'hsl(var(--heavy))',
+    foreground: 'hsl(var(--heavy-foreground))',
+  },
+  main: {
+    DEFAULT: 'hsl(var(--main))',
+  },
+  overlay: {
+    content: 'hsl(var(--overlay-content))',
+    DEFAULT: 'hsl(var(--overlay))',
+  },
+  red: {
+    ...createColorsPalette('red'),
+    foreground: 'hsl(var(--destructive-foreground))',
+  },
+  sidebar: {
+    deep: 'hsl(var(--sidebar-deep))',
+    DEFAULT: 'hsl(var(--sidebar))',
+  },
+  success: {
+    ...createColorsPalette('success'),
+    DEFAULT: 'hsl(var(--success))',
+  },
+  warning: {
+    ...createColorsPalette('warning'),
+    DEFAULT: 'hsl(var(--warning))',
+  },
+  yellow: {
+    ...createColorsPalette('yellow'),
+    foreground: 'hsl(var(--warning-foreground))',
+  },
+};
+
+export default {
+  content: [
+    './index.html',
+    ...tailwindPackages.map((item) =>
+      path.join(item, 'src/**/*.{vue,js,ts,jsx,tsx,svelte,astro,html}'),
+    ),
+  ],
+  darkMode: 'selector',
+  plugins: [
+    animate,
+    typographyPlugin,
+    addDynamicIconSelectors(),
+    enterAnimationPlugin,
+  ],
+  prefix: '',
+  safelist: ['dark'],
+  theme: {
+    container: {
+      center: true,
+      padding: '2rem',
+      screens: {
+        '2xl': '1400px',
+      },
+    },
+    extend: {
+      animation: {
+        'accordion-down': 'accordion-down 0.2s ease-out',
+        'accordion-up': 'accordion-up 0.2s ease-out',
+        'collapsible-down': 'collapsible-down 0.2s ease-in-out',
+        'collapsible-up': 'collapsible-up 0.2s ease-in-out',
+        float: 'float 5s linear 0ms infinite',
+      },
+
+      animationDuration: {
+        '2000': '2000ms',
+        '3000': '3000ms',
+      },
+      borderRadius: {
+        lg: 'var(--radius)',
+        md: 'calc(var(--radius) - 2px)',
+        sm: 'calc(var(--radius) - 4px)',
+        xl: 'calc(var(--radius) + 4px)',
+      },
+      boxShadow: {
+        float: `0 6px 16px 0 rgb(0 0 0 / 8%),
+          0 3px 6px -4px rgb(0 0 0 / 12%),
+          0 9px 28px 8px rgb(0 0 0 / 5%)`,
+      },
+      colors: {
+        ...customColors,
+        ...shadcnUiColors,
+      },
+      fontFamily: {
+        sans: [
+          'var(--font-family)',
+          //  ...defaultTheme.fontFamily.sans
+        ],
+      },
+      keyframes: {
+        'accordion-down': {
+          from: { height: '0' },
+          to: { height: 'var(--radix-accordion-content-height)' },
+        },
+        'accordion-up': {
+          from: { height: 'var(--radix-accordion-content-height)' },
+          to: { height: '0' },
+        },
+        'collapsible-down': {
+          from: { height: '0' },
+          to: { height: 'var(--radix-collapsible-content-height)' },
+        },
+        'collapsible-up': {
+          from: { height: 'var(--radix-collapsible-content-height)' },
+          to: { height: '0' },
+        },
+        float: {
+          '0%': { transform: 'translateY(0)' },
+          '50%': { transform: 'translateY(-20px)' },
+          '100%': { transform: 'translateY(0)' },
+        },
+      },
+      zIndex: {
+        '100': '100',
+        '1000': '1000',
+      },
+    },
+  },
+} as Config;
+
+function createColorsPalette(name: string) {
+  // backgroundLightest: '#EFF6FF', // Tailwind CSS 榛樿鐨� `blue-50`
+  //         backgroundLighter: '#DBEAFE',  // Tailwind CSS 榛樿鐨� `blue-100`
+  //         backgroundLight: '#BFDBFE',    // Tailwind CSS 榛樿鐨� `blue-200`
+  //         borderLight: '#93C5FD',        // Tailwind CSS 榛樿鐨� `blue-300`
+  //         border: '#60A5FA',             // Tailwind CSS 榛樿鐨� `blue-400`
+  //         main: '#3B82F6',               // Tailwind CSS 榛樿鐨� `blue-500`
+  //         hover: '#2563EB',              // Tailwind CSS 榛樿鐨� `blue-600`
+  //         active: '#1D4ED8',             // Tailwind CSS 榛樿鐨� `blue-700`
+  //         backgroundDark: '#1E40AF',     // Tailwind CSS 榛樿鐨� `blue-800`
+  //         backgroundDarker: '#1E3A8A',   // Tailwind CSS 榛樿鐨� `blue-900`
+  //         backgroundDarkest: '#172554',  // Tailwind CSS 榛樿鐨� `blue-950`
+
+  // 鈥�	backgroundLightest (#EFF6FF): 閫傜敤浜庢渶娴呯殑鑳屾櫙鑹诧紝鍙兘鐢ㄤ簬闈炲父杞诲井鐨勯槾褰辨垨鍗$墖鐨勮儗鏅��
+  // 鈥�	backgroundLighter (#DBEAFE): 閫傜敤浜庣暐娴呯殑鑳屾櫙鑹诧紝閫氬父鐢ㄤ簬娆¤鑳屾櫙鎴栫暐娴呯殑鍖哄煙銆�
+  // 鈥�	backgroundLight (#BFDBFE): 閫傜敤浜庢祬鑹茶儗鏅紝鍙兘鐢ㄤ簬杈撳叆妗嗘垨琛ㄥ崟鍖哄煙鐨勮儗鏅��
+  // 鈥�	borderLight (#93C5FD): 閫傜敤浜庢祬鑹茶竟妗嗭紝鍙兘鐢ㄤ簬杈撳叆妗嗘垨鍗$墖鐨勮竟妗嗐��
+  // 鈥�	border (#60A5FA): 閫傜敤浜庢櫘閫氳竟妗嗭紝鍙兘鐢ㄤ簬鎸夐挳鎴栧崱鐗囩殑杈规銆�
+  // 鈥�	main (#3B82F6): 閫傜敤浜庝富瑕佺殑涓婚鑹诧紝閫氬父鐢ㄤ簬鎸夐挳銆侀摼鎺ユ垨涓昏鐨勫己璋冭壊銆�
+  // 鈥�	hover (#2563EB): 閫傜敤浜庨紶鏍囨偓鍋滅姸鎬佷笅鐨勯鑹诧紝渚嬪鎸夐挳鎮仠鏃剁殑鑳屾櫙鑹叉垨杈规鑹层��
+  // 鈥�	active (#1D4ED8): 閫傜敤浜庢縺娲荤姸鎬佷笅鐨勯鑹诧紝渚嬪鎸夐挳鎸変笅鏃剁殑鑳屾櫙鑹叉垨杈规鑹层��
+  // 鈥�	backgroundDark (#1E40AF): 閫傜敤浜庢繁鑹茶儗鏅紝鍙兘鐢ㄤ簬涓昏鎸夐挳鎴栨繁鑹插崱鐗囪儗鏅��
+  // 鈥�	backgroundDarker (#1E3A8A): 閫傜敤浜庢洿娣辩殑鑳屾櫙锛岄�氬父鐢ㄤ簬澶撮儴瀵艰埅鏍忔垨椤佃剼銆�
+  // 鈥�	backgroundDarkest (#172554): 閫傜敤浜庢渶娣辩殑鑳屾櫙锛屽彲鑳界敤浜庨潪甯告繁鑹茬殑鍖哄煙鎴栨瀬绔姣旇壊銆�
+
+  return {
+    50: `hsl(var(--${name}-50))`,
+    100: `hsl(var(--${name}-100))`,
+    200: `hsl(var(--${name}-200))`,
+    300: `hsl(var(--${name}-300))`,
+    400: `hsl(var(--${name}-400))`,
+    500: `hsl(var(--${name}-500))`,
+    600: `hsl(var(--${name}-600))`,
+    700: `hsl(var(--${name}-700))`,
+    // 800: `hsl(var(--${name}-800))`,
+    // 900: `hsl(var(--${name}-900))`,
+    // 950: `hsl(var(--${name}-950))`,
+    // 婵�娲荤姸鎬佷笅鐨勯鑹诧紝閫傜敤浜庢寜閽寜涓嬫椂鐨勮儗鏅壊鎴栬竟妗嗚壊銆�
+    active: `hsl(var(--${name}-700))`,
+    // 娴呰壊鑳屾櫙锛岄�傜敤浜庤緭鍏ユ鎴栬〃鍗曞尯鍩熺殑鑳屾櫙銆�
+    'background-light': `hsl(var(--${name}-200))`,
+    // 閫傜敤浜庣暐娴呯殑鑳屾櫙鑹诧紝閫氬父鐢ㄤ簬娆¤鑳屾櫙鎴栫暐娴呯殑鍖哄煙銆�
+    'background-lighter': `hsl(var(--${name}-100))`,
+    // 鏈�娴呯殑鑳屾櫙鑹诧紝閫傜敤浜庨潪甯歌交寰殑闃村奖鎴栧崱鐗囩殑鑳屾櫙銆�
+    'background-lightest': `hsl(var(--${name}-50))`,
+    // 閫傜敤浜庢櫘閫氳竟妗嗭紝鍙兘鐢ㄤ簬鎸夐挳鎴栧崱鐗囩殑杈规銆�
+    border: `hsl(var(--${name}-400))`,
+    // 娴呰壊杈规锛岄�傜敤浜庤緭鍏ユ鎴栧崱鐗囩殑杈规銆�
+    'border-light': `hsl(var(--${name}-300))`,
+    foreground: `hsl(var(--${name}-foreground))`,
+    // 榧犳爣鎮仠鐘舵�佷笅鐨勯鑹诧紝閫傜敤浜庢寜閽偓鍋滄椂鐨勮儗鏅壊鎴栬竟妗嗚壊銆�
+    hover: `hsl(var(--${name}-600))`,
+    // 涓昏壊鏂囨湰
+    text: `hsl(var(--${name}-500))`,
+    // 涓昏壊鏂囨湰婵�娲绘��
+    'text-active': `hsl(var(--${name}-700))`,
+    // 涓昏壊鏂囨湰鎮诞鎬�
+    'text-hover': `hsl(var(--${name}-600))`,
+  };
+}
diff --git a/eims-ui/internal/tailwind-config/src/module.d.ts b/eims-ui/internal/tailwind-config/src/module.d.ts
new file mode 100644
index 0000000..a399653
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/src/module.d.ts
@@ -0,0 +1,3 @@
+declare module '@tailwindcss/nesting' {
+  export default any;
+}
diff --git a/eims-ui/internal/tailwind-config/src/plugins/entry.ts b/eims-ui/internal/tailwind-config/src/plugins/entry.ts
new file mode 100644
index 0000000..0d8e8ec
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/src/plugins/entry.ts
@@ -0,0 +1,53 @@
+import plugin from 'tailwindcss/plugin.js';
+
+const enterAnimationPlugin = plugin(({ addUtilities }) => {
+  const maxChild = 5;
+  const utilities: Record<string, any> = {};
+  for (let i = 1; i <= maxChild; i++) {
+    const baseDelay = 0.1;
+    const delay = `${baseDelay * i}s`;
+
+    utilities[`.enter-x:nth-child(${i})`] = {
+      animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,
+      opacity: '0',
+      transform: `translateX(50px)`,
+    };
+
+    utilities[`.enter-y:nth-child(${i})`] = {
+      animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,
+      opacity: '0',
+      transform: `translateY(50px)`,
+    };
+
+    utilities[`.-enter-x:nth-child(${i})`] = {
+      animation: `enter-x-animation 0.3s ease-in-out ${delay} forwards`,
+      opacity: '0',
+      transform: `translateX(-50px)`,
+    };
+
+    utilities[`.-enter-y:nth-child(${i})`] = {
+      animation: `enter-y-animation 0.3s ease-in-out ${delay} forwards`,
+      opacity: '0',
+      transform: `translateY(-50px)`,
+    };
+  }
+
+  // 娣诲姞鍔ㄧ敾鍏抽敭甯�
+  addUtilities(utilities);
+  addUtilities({
+    '@keyframes enter-x-animation': {
+      to: {
+        opacity: '1',
+        transform: 'translateX(0)',
+      },
+    },
+    '@keyframes enter-y-animation': {
+      to: {
+        opacity: '1',
+        transform: 'translateY(0)',
+      },
+    },
+  });
+});
+
+export { enterAnimationPlugin };
diff --git a/eims-ui/internal/tailwind-config/src/postcss.config.ts b/eims-ui/internal/tailwind-config/src/postcss.config.ts
new file mode 100644
index 0000000..43b30b3
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/src/postcss.config.ts
@@ -0,0 +1,15 @@
+import config from '.';
+
+export default {
+  plugins: {
+    ...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {}),
+    // Specifying the config is not necessary in most cases, but it is included
+    autoprefixer: {},
+    // 淇 element-plus 鍜� ant-design-vue 鐨勬牱寮忓拰tailwindcss鍐茬獊闂
+    'postcss-antd-fixes': { prefixes: ['ant', 'el'] },
+    'postcss-import': {},
+    'postcss-preset-env': {},
+    tailwindcss: { config },
+    'tailwindcss/nesting': {},
+  },
+};
diff --git a/eims-ui/internal/tailwind-config/tsconfig.json b/eims-ui/internal/tailwind-config/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/internal/tailwind-config/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/internal/tsconfig/base.json b/eims-ui/internal/tsconfig/base.json
new file mode 100644
index 0000000..1e45a78
--- /dev/null
+++ b/eims-ui/internal/tsconfig/base.json
@@ -0,0 +1,40 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Base",
+  "compilerOptions": {
+    "composite": false,
+    "target": "ESNext",
+
+    "moduleDetection": "force",
+    "experimentalDecorators": true,
+
+    "baseUrl": ".",
+    "module": "ESNext",
+
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+
+    "strict": true,
+    "strictNullChecks": true,
+    "noFallthroughCasesInSwitch": true,
+    "noImplicitAny": true,
+    "noImplicitOverride": true,
+    "noImplicitThis": true,
+    "noUncheckedIndexedAccess": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+
+    "inlineSources": false,
+    "noEmit": true,
+    "removeComments": true,
+    "sourceMap": false,
+    "allowSyntheticDefaultImports": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "isolatedModules": true,
+    "verbatimModuleSyntax": true,
+    "skipLibCheck": true,
+    "preserveWatchOutput": true
+  },
+  "exclude": ["**/node_modules/**", "**/dist/**", "**/.turbo/**"]
+}
diff --git a/eims-ui/internal/tsconfig/library.json b/eims-ui/internal/tsconfig/library.json
new file mode 100644
index 0000000..7a976f0
--- /dev/null
+++ b/eims-ui/internal/tsconfig/library.json
@@ -0,0 +1,13 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Web Application",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "jsx": "preserve",
+    "lib": ["ESNext", "DOM", "DOM.Iterable"],
+    "useDefineForClassFields": true,
+    "moduleResolution": "bundler",
+    "declaration": true,
+    "noEmit": false
+  }
+}
diff --git a/eims-ui/internal/tsconfig/node.json b/eims-ui/internal/tsconfig/node.json
new file mode 100644
index 0000000..31ce8f1
--- /dev/null
+++ b/eims-ui/internal/tsconfig/node.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Node Config",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "composite": false,
+    "lib": ["ESNext"],
+    "baseUrl": "./",
+    "types": ["node"],
+    "noImplicitAny": true
+  }
+}
diff --git a/eims-ui/internal/tsconfig/package.json b/eims-ui/internal/tsconfig/package.json
new file mode 100644
index 0000000..e39ec49
--- /dev/null
+++ b/eims-ui/internal/tsconfig/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "@vben/tsconfig",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/tsconfig"
+  },
+  "license": "MIT",
+  "type": "module",
+  "files": [
+    "base.json",
+    "library.json",
+    "node.json",
+    "web-app.json",
+    "web.json"
+  ],
+  "dependencies": {
+    "@vben/types": "workspace:*",
+    "vite": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/tsconfig/web-app.json b/eims-ui/internal/tsconfig/web-app.json
new file mode 100644
index 0000000..00479cb
--- /dev/null
+++ b/eims-ui/internal/tsconfig/web-app.json
@@ -0,0 +1,8 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Web Application",
+  "extends": "./web.json",
+  "compilerOptions": {
+    "types": ["vite/client", "@vben/types/global"]
+  }
+}
diff --git a/eims-ui/internal/tsconfig/web.json b/eims-ui/internal/tsconfig/web.json
new file mode 100644
index 0000000..a4b60ce
--- /dev/null
+++ b/eims-ui/internal/tsconfig/web.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "display": "Web Package",
+  "extends": "./base.json",
+  "compilerOptions": {
+    "jsx": "preserve",
+    "jsxImportSource": "vue",
+    "lib": ["ESNext", "DOM", "DOM.Iterable"],
+    "useDefineForClassFields": true,
+    "moduleResolution": "bundler",
+    "types": ["vite/client"],
+    "declaration": false
+  }
+}
diff --git a/eims-ui/internal/vite-config/build.config.ts b/eims-ui/internal/vite-config/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/internal/vite-config/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/internal/vite-config/package.json b/eims-ui/internal/vite-config/package.json
new file mode 100644
index 0000000..5abdcf4
--- /dev/null
+++ b/eims-ui/internal/vite-config/package.json
@@ -0,0 +1,59 @@
+{
+  "name": "@vben/vite-config",
+  "version": "5.5.0",
+  "private": true,
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "internal/vite-config"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "dependencies": {
+    "@intlify/unplugin-vue-i18n": "catalog:",
+    "@jspm/generator": "catalog:",
+    "archiver": "catalog:",
+    "cheerio": "catalog:",
+    "get-port": "catalog:",
+    "html-minifier-terser": "catalog:",
+    "nitropack": "catalog:",
+    "resolve.exports": "catalog:",
+    "vite-plugin-pwa": "catalog:",
+    "vite-plugin-vue-devtools": "catalog:"
+  },
+  "devDependencies": {
+    "@pnpm/workspace.read-manifest": "catalog:",
+    "@types/archiver": "catalog:",
+    "@types/html-minifier-terser": "catalog:",
+    "@vben/node-utils": "workspace:*",
+    "@vitejs/plugin-vue": "catalog:",
+    "@vitejs/plugin-vue-jsx": "catalog:",
+    "dayjs": "catalog:",
+    "dotenv": "catalog:",
+    "rollup": "catalog:",
+    "rollup-plugin-visualizer": "catalog:",
+    "sass": "catalog:",
+    "vite": "catalog:",
+    "vite-plugin-compression": "catalog:",
+    "vite-plugin-dts": "catalog:",
+    "vite-plugin-html": "catalog:",
+    "vite-plugin-lazy-import": "catalog:"
+  }
+}
diff --git a/eims-ui/internal/vite-config/src/config/application.ts b/eims-ui/internal/vite-config/src/config/application.ts
new file mode 100644
index 0000000..f227609
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/config/application.ts
@@ -0,0 +1,125 @@
+import type { UserConfig } from 'vite';
+
+import type { DefineApplicationOptions } from '../typing';
+
+import path, { relative } from 'node:path';
+
+import { findMonorepoRoot } from '@vben/node-utils';
+
+import { NodePackageImporter } from 'sass';
+import { defineConfig, loadEnv, mergeConfig } from 'vite';
+
+import { defaultImportmapOptions, getDefaultPwaOptions } from '../options';
+import { loadApplicationPlugins } from '../plugins';
+import { loadAndConvertEnv } from '../utils/env';
+import { getCommonConfig } from './common';
+
+function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
+  return defineConfig(async (config) => {
+    const options = await userConfigPromise?.(config);
+    const { appTitle, base, port, ...envConfig } = await loadAndConvertEnv();
+    const { command, mode } = config;
+    const { application = {}, vite = {} } = options || {};
+    const root = process.cwd();
+    const isBuild = command === 'build';
+    const env = loadEnv(mode, root);
+
+    const plugins = await loadApplicationPlugins({
+      archiver: true,
+      archiverPluginOptions: {},
+      compress: false,
+      compressTypes: ['brotli', 'gzip'],
+      devtools: true,
+      env,
+      extraAppConfig: true,
+      html: true,
+      i18n: true,
+      importmapOptions: defaultImportmapOptions,
+      injectAppLoading: true,
+      injectMetadata: true,
+      isBuild,
+      license: true,
+      mode,
+      nitroMock: !isBuild,
+      nitroMockOptions: {},
+      print: !isBuild,
+      printInfoMap: {
+        'Vben Admin Docs': 'https://doc.vben.pro',
+      },
+      pwa: true,
+      pwaOptions: getDefaultPwaOptions(appTitle),
+      vxeTableLazyImport: true,
+      ...envConfig,
+      ...application,
+    });
+
+    const { injectGlobalScss = true } = application;
+
+    const applicationConfig: UserConfig = {
+      base,
+      build: {
+        rollupOptions: {
+          output: {
+            assetFileNames: '[ext]/[name]-[hash].[ext]',
+            chunkFileNames: 'js/[name]-[hash].js',
+            entryFileNames: 'jse/index-[name]-[hash].js',
+          },
+        },
+        target: 'es2015',
+      },
+      css: createCssOptions(injectGlobalScss),
+      esbuild: {
+        drop: isBuild
+          ? [
+              // 'console',
+              'debugger',
+            ]
+          : [],
+        legalComments: 'none',
+      },
+      plugins,
+      server: {
+        host: true,
+        port,
+        warmup: {
+          // 棰勭儹鏂囦欢
+          clientFiles: [
+            './index.html',
+            './src/bootstrap.ts',
+            './src/{views,layouts,router,store,api,adapter}/*',
+          ],
+        },
+      },
+    };
+
+    const mergedCommonConfig = mergeConfig(
+      await getCommonConfig(),
+      applicationConfig,
+    );
+    return mergeConfig(mergedCommonConfig, vite);
+  });
+}
+
+function createCssOptions(injectGlobalScss = true) {
+  const root = findMonorepoRoot();
+  return {
+    preprocessorOptions: injectGlobalScss
+      ? {
+          scss: {
+            additionalData: (content: string, filepath: string) => {
+              const relativePath = relative(root, filepath);
+              // apps涓嬬殑鍖呮敞鍏ュ叏灞�鏍峰紡
+              if (relativePath.startsWith(`apps${path.sep}`)) {
+                return `@use "@vben/styles/global" as *;\n${content}`;
+              }
+              return content;
+            },
+            api: 'modern',
+            importers: [new NodePackageImporter()],
+          },
+        }
+      : {},
+  };
+}
+
+export { defineApplicationConfig };
diff --git a/eims-ui/internal/vite-config/src/config/common.ts b/eims-ui/internal/vite-config/src/config/common.ts
new file mode 100644
index 0000000..653f210
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/config/common.ts
@@ -0,0 +1,13 @@
+import type { UserConfig } from 'vite';
+
+async function getCommonConfig(): Promise<UserConfig> {
+  return {
+    build: {
+      chunkSizeWarningLimit: 2000,
+      reportCompressedSize: false,
+      sourcemap: false,
+    },
+  };
+}
+
+export { getCommonConfig };
diff --git a/eims-ui/internal/vite-config/src/config/index.ts b/eims-ui/internal/vite-config/src/config/index.ts
new file mode 100644
index 0000000..d04a84a
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/config/index.ts
@@ -0,0 +1,37 @@
+import type { DefineConfig } from '../typing';
+
+import { existsSync } from 'node:fs';
+import { join } from 'node:path';
+
+import { defineApplicationConfig } from './application';
+import { defineLibraryConfig } from './library';
+
+export * from './application';
+export * from './library';
+
+function defineConfig(
+  userConfigPromise?: DefineConfig,
+  type: 'application' | 'auto' | 'library' = 'auto',
+) {
+  let projectType = type;
+
+  // 鏍规嵁鍖呮槸鍚﹀瓨鍦� index.html,鑷姩鍒ゆ柇绫诲瀷
+  if (projectType === 'auto') {
+    const htmlPath = join(process.cwd(), 'index.html');
+    projectType = existsSync(htmlPath) ? 'application' : 'library';
+  }
+
+  switch (projectType) {
+    case 'application': {
+      return defineApplicationConfig(userConfigPromise);
+    }
+    case 'library': {
+      return defineLibraryConfig(userConfigPromise);
+    }
+    default: {
+      throw new Error(`Unsupported project type: ${projectType}`);
+    }
+  }
+}
+
+export { defineConfig };
diff --git a/eims-ui/internal/vite-config/src/config/library.ts b/eims-ui/internal/vite-config/src/config/library.ts
new file mode 100644
index 0000000..08b8135
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/config/library.ts
@@ -0,0 +1,59 @@
+import type { ConfigEnv, UserConfig } from 'vite';
+
+import type { DefineLibraryOptions } from '../typing';
+
+import { readPackageJSON } from '@vben/node-utils';
+
+import { defineConfig, mergeConfig } from 'vite';
+
+import { loadLibraryPlugins } from '../plugins';
+import { getCommonConfig } from './common';
+
+function defineLibraryConfig(userConfigPromise?: DefineLibraryOptions) {
+  return defineConfig(async (config: ConfigEnv) => {
+    const options = await userConfigPromise?.(config);
+    const { command, mode } = config;
+    const { library = {}, vite = {} } = options || {};
+    const root = process.cwd();
+    const isBuild = command === 'build';
+
+    const plugins = await loadLibraryPlugins({
+      dts: false,
+      injectMetadata: true,
+      isBuild,
+      mode,
+      ...library,
+    });
+
+    const { dependencies = {}, peerDependencies = {} } =
+      await readPackageJSON(root);
+
+    const externalPackages = [
+      ...Object.keys(dependencies),
+      ...Object.keys(peerDependencies),
+    ];
+
+    const packageConfig: UserConfig = {
+      build: {
+        lib: {
+          entry: 'src/index.ts',
+          fileName: () => 'index.mjs',
+          formats: ['es'],
+        },
+        rollupOptions: {
+          external: (id) => {
+            return externalPackages.some(
+              (pkg) => id === pkg || id.startsWith(`${pkg}/`),
+            );
+          },
+        },
+      },
+      plugins,
+    };
+    const commonConfig = await getCommonConfig();
+    const mergedConmonConfig = mergeConfig(commonConfig, packageConfig);
+    return mergeConfig(mergedConmonConfig, vite);
+  });
+}
+
+export { defineLibraryConfig };
diff --git a/eims-ui/internal/vite-config/src/index.ts b/eims-ui/internal/vite-config/src/index.ts
new file mode 100644
index 0000000..352a323
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/index.ts
@@ -0,0 +1,4 @@
+export * from './config';
+export * from './options';
+export * from './plugins';
+export { loadAndConvertEnv } from './utils/env';
diff --git a/eims-ui/internal/vite-config/src/options.ts b/eims-ui/internal/vite-config/src/options.ts
new file mode 100644
index 0000000..f1e2401
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/options.ts
@@ -0,0 +1,45 @@
+import type { Options as PwaPluginOptions } from 'vite-plugin-pwa';
+
+import type { ImportmapPluginOptions } from './typing';
+
+const isDevelopment = process.env.NODE_ENV === 'development';
+
+const getDefaultPwaOptions = (name: string): Partial<PwaPluginOptions> => ({
+  manifest: {
+    description:
+      'Vben Admin is a modern admin dashboard template based on Vue 3. ',
+    icons: [
+      {
+        sizes: '192x192',
+        src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-192.png',
+        type: 'image/png',
+      },
+      {
+        sizes: '512x512',
+        src: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/pwa-icon-512.png',
+        type: 'image/png',
+      },
+    ],
+    name: `${name}${isDevelopment ? ' dev' : ''}`,
+    short_name: `${name}${isDevelopment ? ' dev' : ''}`,
+  },
+});
+
+/**
+ * importmap CDN 鏆傛椂涓嶅紑鍚紝鍥犱负鏈変簺鍖呬笉鏀寔锛屼笖缃戠粶涓嶇ǔ瀹�
+ */
+const defaultImportmapOptions: ImportmapPluginOptions = {
+  // 閫氳繃 Importmap CDN 鏂瑰紡寮曞叆,
+  // 鐩墠鍙湁esm.sh婧愬吋瀹规�уソ涓�鐐癸紝jspm.io瀵逛簬 esm 鍏ュ彛瑕佹眰楂�
+  defaultProvider: 'esm.sh',
+  importmap: [
+    { name: 'vue' },
+    { name: 'pinia' },
+    { name: 'vue-router' },
+    // { name: 'vue-i18n' },
+    { name: 'dayjs' },
+    { name: 'vue-demi' },
+  ],
+};
+
+export { defaultImportmapOptions, getDefaultPwaOptions };
diff --git a/eims-ui/internal/vite-config/src/plugins/archiver.ts b/eims-ui/internal/vite-config/src/plugins/archiver.ts
new file mode 100644
index 0000000..8eec8a0
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/archiver.ts
@@ -0,0 +1,75 @@
+import type { PluginOption } from 'vite';
+
+import type { ArchiverPluginOptions } from '../typing';
+
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import { join } from 'node:path';
+
+import archiver from 'archiver';
+
+export const viteArchiverPlugin = (
+  options: ArchiverPluginOptions = {},
+): PluginOption => {
+  return {
+    apply: 'build',
+    closeBundle: {
+      handler() {
+        const { name = 'dist', outputDir = '.' } = options;
+
+        setTimeout(async () => {
+          const folderToZip = 'dist';
+
+          const zipOutputDir = join(process.cwd(), outputDir);
+          const zipOutputPath = join(zipOutputDir, `${name}.zip`);
+          try {
+            await fsp.mkdir(zipOutputDir, { recursive: true });
+          } catch {
+            // ignore
+          }
+
+          try {
+            await zipFolder(folderToZip, zipOutputPath);
+            console.log(`Folder has been zipped to: ${zipOutputPath}`);
+          } catch (error) {
+            console.error('Error zipping folder:', error);
+          }
+        }, 0);
+      },
+      order: 'post',
+    },
+    enforce: 'post',
+    name: 'vite:archiver',
+  };
+};
+
+async function zipFolder(
+  folderPath: string,
+  outputPath: string,
+): Promise<void> {
+  return new Promise((resolve, reject) => {
+    const output = fs.createWriteStream(outputPath);
+    const archive = archiver('zip', {
+      zlib: { level: 9 }, // 璁剧疆鍘嬬缉绾у埆涓� 9 浠ュ疄鐜版渶楂樺帇缂╃巼
+    });
+
+    output.on('close', () => {
+      console.log(
+        `ZIP file created: ${outputPath} (${archive.pointer()} total bytes)`,
+      );
+      resolve();
+    });
+
+    archive.on('error', (err) => {
+      reject(err);
+    });
+
+    archive.pipe(output);
+
+    // 浣跨敤 directory 鏂规硶浠ユ祦鐨勬柟寮忓帇缂╂枃浠跺す锛屽噺灏戝唴瀛樻秷鑰�
+    archive.directory(folderPath, false);
+
+    // 娴佸紡澶勭悊瀹屾垚
+    archive.finalize();
+  });
+}
diff --git a/eims-ui/internal/vite-config/src/plugins/extra-app-config.ts b/eims-ui/internal/vite-config/src/plugins/extra-app-config.ts
new file mode 100644
index 0000000..813819b
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/extra-app-config.ts
@@ -0,0 +1,92 @@
+import type { PluginOption } from 'vite';
+
+import {
+  colors,
+  generatorContentHash,
+  readPackageJSON,
+} from '@vben/node-utils';
+
+import { loadEnv } from '../utils/env';
+
+interface PluginOptions {
+  isBuild: boolean;
+  root: string;
+}
+
+const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
+const VBEN_ADMIN_PRO_APP_CONF = '_VBEN_ADMIN_PRO_APP_CONF_';
+
+/**
+ * 鐢ㄤ簬灏嗛厤缃枃浠舵娊绂诲嚭鏉ュ苟娉ㄥ叆鍒伴」鐩腑
+ * @returns
+ */
+
+async function viteExtraAppConfigPlugin({
+  isBuild,
+  root,
+}: PluginOptions): Promise<PluginOption | undefined> {
+  let publicPath: string;
+  let source: string;
+
+  if (!isBuild) {
+    return;
+  }
+
+  const { version = '' } = await readPackageJSON(root);
+
+  return {
+    async configResolved(config) {
+      publicPath = ensureTrailingSlash(config.base);
+      source = await getConfigSource();
+    },
+    async generateBundle() {
+      try {
+        this.emitFile({
+          fileName: GLOBAL_CONFIG_FILE_NAME,
+          source,
+          type: 'asset',
+        });
+
+        console.log(colors.cyan(`鉁╟onfiguration file is build successfully!`));
+      } catch (error) {
+        console.log(
+          colors.red(
+            `configuration file configuration file failed to package:\n${error}`,
+          ),
+        );
+      }
+    },
+    name: 'vite:extra-app-config',
+    async transformIndexHtml(html) {
+      const hash = `v=${version}-${generatorContentHash(source, 8)}`;
+
+      const appConfigSrc = `${publicPath}${GLOBAL_CONFIG_FILE_NAME}?${hash}`;
+
+      return {
+        html,
+        tags: [{ attrs: { src: appConfigSrc }, tag: 'script' }],
+      };
+    },
+  };
+}
+
+async function getConfigSource() {
+  const config = await loadEnv();
+  const windowVariable = `window.${VBEN_ADMIN_PRO_APP_CONF}`;
+  // 纭繚鍙橀噺涓嶄細琚慨鏀�
+  let source = `${windowVariable}=${JSON.stringify(config)};`;
+  source += `
+    Object.freeze(${windowVariable});
+    Object.defineProperty(window, "${VBEN_ADMIN_PRO_APP_CONF}", {
+      configurable: false,
+      writable: false,
+    });
+  `.replaceAll(/\s/g, '');
+  return source;
+}
+
+function ensureTrailingSlash(path: string) {
+  return path.endsWith('/') ? path : `${path}/`;
+}
+
+export { viteExtraAppConfigPlugin };
diff --git a/eims-ui/internal/vite-config/src/plugins/importmap.ts b/eims-ui/internal/vite-config/src/plugins/importmap.ts
new file mode 100644
index 0000000..c6154c9
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/importmap.ts
@@ -0,0 +1,245 @@
+/**
+ * 鍙傝�� https://github.com/jspm/vite-plugin-jspm锛岃皟鏁翠负闇�瑕佺殑鍔熻兘
+ */
+import type { GeneratorOptions } from '@jspm/generator';
+import type { Plugin } from 'vite';
+
+import { Generator } from '@jspm/generator';
+import { load } from 'cheerio';
+import { minify } from 'html-minifier-terser';
+
+const DEFAULT_PROVIDER = 'jspm.io';
+
+type pluginOptions = {
+  debug?: boolean;
+  defaultProvider?: 'esm.sh' | 'jsdelivr' | 'jspm.io';
+  importmap?: Array<{ name: string; range?: string }>;
+} & GeneratorOptions;
+
+// async function getLatestVersionOfShims() {
+//   const result = await fetch('https://ga.jspm.io/npm:es-module-shims');
+//   const version = result.text();
+//   return version;
+// }
+
+async function getShimsUrl(provide: string) {
+  // const version = await getLatestVersionOfShims();
+  const version = '1.10.0';
+
+  const shimsSubpath = `dist/es-module-shims.js`;
+  const providerShimsMap: Record<string, string> = {
+    'esm.sh': `https://esm.sh/es-module-shims@${version}/${shimsSubpath}`,
+    // unpkg: `https://unpkg.com/es-module-shims@${version}/${shimsSubpath}`,
+    jsdelivr: `https://cdn.jsdelivr.net/npm/es-module-shims@${version}/${shimsSubpath}`,
+
+    // 涓嬮潰涓や釜CDN涓嶇ǔ瀹氾紝鏆傛椂涓嶇敤
+    'jspm.io': `https://ga.jspm.io/npm:es-module-shims@${version}/${shimsSubpath}`,
+  };
+
+  return providerShimsMap[provide] || providerShimsMap[DEFAULT_PROVIDER];
+}
+
+let generator: Generator;
+
+async function viteImportMapPlugin(
+  pluginOptions?: pluginOptions,
+): Promise<Plugin[]> {
+  const { importmap } = pluginOptions || {};
+
+  let isSSR = false;
+  let isBuild = false;
+  let installed = false;
+  let installError: Error | null = null;
+
+  const options: pluginOptions = Object.assign(
+    {},
+    {
+      debug: false,
+      defaultProvider: 'jspm.io',
+      env: ['production', 'browser', 'module'],
+      importmap: [],
+    },
+    pluginOptions,
+  );
+
+  generator = new Generator({
+    ...options,
+    baseUrl: process.cwd(),
+  });
+
+  if (options?.debug) {
+    (async () => {
+      for await (const { message, type } of generator.logStream()) {
+        console.log(`${type}: ${message}`);
+      }
+    })();
+  }
+
+  const imports = options.inputMap?.imports ?? {};
+  const scopes = options.inputMap?.scopes ?? {};
+  const firstLayerKeys = Object.keys(scopes);
+  const inputMapScopes: string[] = [];
+  firstLayerKeys.forEach((key) => {
+    inputMapScopes.push(...Object.keys(scopes[key] || {}));
+  });
+  const inputMapImports = Object.keys(imports);
+
+  const allDepNames: string[] = [
+    ...(importmap?.map((item) => item.name) || []),
+    ...inputMapImports,
+    ...inputMapScopes,
+  ];
+  const depNames = new Set<string>(allDepNames);
+
+  const installDeps = importmap?.map((item) => ({
+    range: item.range,
+    target: item.name,
+  }));
+
+  return [
+    {
+      async config(_, { command, isSsrBuild }) {
+        isBuild = command === 'build';
+        isSSR = !!isSsrBuild;
+      },
+      enforce: 'pre',
+      name: 'importmap:external',
+      resolveId(id) {
+        if (isSSR || !isBuild) {
+          return null;
+        }
+
+        if (!depNames.has(id)) {
+          return null;
+        }
+        return { external: true, id };
+      },
+    },
+    {
+      enforce: 'post',
+      name: 'importmap:install',
+      async resolveId() {
+        if (isSSR || !isBuild || installed) {
+          return null;
+        }
+        try {
+          installed = true;
+          await Promise.allSettled(
+            (installDeps || []).map((dep) => generator.install(dep)),
+          );
+        } catch (error: any) {
+          installError = error;
+          installed = false;
+        }
+        return null;
+      },
+    },
+    {
+      buildEnd() {
+        // 鏈敓鎴恑mportmap鏃讹紝鎶涘嚭閿欒锛岄槻姝㈣turbo缂撳瓨
+        if (!installed && !isSSR) {
+          installError && console.error(installError);
+          throw new Error('Importmap installation failed.');
+        }
+      },
+      enforce: 'post',
+      name: 'importmap:html',
+      transformIndexHtml: {
+        async handler(html) {
+          if (isSSR || !isBuild) {
+            return html;
+          }
+
+          const importmapJson = generator.getMap();
+
+          if (!importmapJson) {
+            return html;
+          }
+
+          const esModuleShimsSrc = await getShimsUrl(
+            options.defaultProvider || DEFAULT_PROVIDER,
+          );
+
+          const resultHtml = await injectShimsToHtml(
+            html,
+            esModuleShimsSrc || '',
+          );
+          html = await minify(resultHtml || html, {
+            collapseWhitespace: true,
+            minifyCSS: true,
+            minifyJS: true,
+            removeComments: false,
+          });
+
+          return {
+            html,
+            tags: [
+              {
+                attrs: {
+                  type: 'importmap',
+                },
+                injectTo: 'head-prepend',
+                tag: 'script',
+                children: `${JSON.stringify(importmapJson)}`,
+              },
+            ],
+          };
+        },
+        order: 'post',
+      },
+    },
+  ];
+}
+
+async function injectShimsToHtml(html: string, esModuleShimUrl: string) {
+  const $ = load(html);
+
+  const $script = $(`script[type='module']`);
+
+  if (!$script) {
+    return;
+  }
+
+  const entry = $script.attr('src');
+
+  $script.removeAttr('type');
+  $script.removeAttr('crossorigin');
+  $script.removeAttr('src');
+  $script.html(`
+if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('importmap')) {
+  self.importShim = function () {
+      const promise = new Promise((resolve, reject) => {
+          document.head.appendChild(
+              Object.assign(document.createElement('script'), {
+                  src: '${esModuleShimUrl}',
+                  crossorigin: 'anonymous',
+                  async: true,
+                  onload() {
+                      if (!importShim.$proxy) {
+                          resolve(importShim);
+                      } else {
+                          reject(new Error('No globalThis.importShim found:' + esModuleShimUrl));
+                      }
+                  },
+                  onerror(error) {
+                      reject(error);
+                  },
+              }),
+          );
+      });
+      importShim.$proxy = true;
+      return promise.then((importShim) => importShim(...arguments));
+  };
+}
+
+var modules = ['${entry}'];
+typeof importShim === 'function'
+  ? modules.forEach((moduleName) => importShim(moduleName))
+  : modules.forEach((moduleName) => import(moduleName));
+ `);
+  $('body').after($script);
+  $('head').remove(`script[type='module']`);
+  return $.html();
+}
+
+export { viteImportMapPlugin };
diff --git a/eims-ui/internal/vite-config/src/plugins/index.ts b/eims-ui/internal/vite-config/src/plugins/index.ts
new file mode 100644
index 0000000..da08db4
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/index.ts
@@ -0,0 +1,247 @@
+import type { PluginOption } from 'vite';
+
+import type {
+  ApplicationPluginOptions,
+  CommonPluginOptions,
+  ConditionPlugin,
+  LibraryPluginOptions,
+} from '../typing';
+
+import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
+import viteVue from '@vitejs/plugin-vue';
+import viteVueJsx from '@vitejs/plugin-vue-jsx';
+import { visualizer as viteVisualizerPlugin } from 'rollup-plugin-visualizer';
+import viteCompressPlugin from 'vite-plugin-compression';
+import viteDtsPlugin from 'vite-plugin-dts';
+import { createHtmlPlugin as viteHtmlPlugin } from 'vite-plugin-html';
+import { VitePWA } from 'vite-plugin-pwa';
+import viteVueDevTools from 'vite-plugin-vue-devtools';
+
+import { viteArchiverPlugin } from './archiver';
+import { viteExtraAppConfigPlugin } from './extra-app-config';
+import { viteImportMapPlugin } from './importmap';
+import { viteInjectAppLoadingPlugin } from './inject-app-loading';
+import { viteMetadataPlugin } from './inject-metadata';
+import { viteLicensePlugin } from './license';
+import { viteNitroMockPlugin } from './nitro-mock';
+import { vitePrintPlugin } from './print';
+import { viteVxeTableImportsPlugin } from './vxe-table';
+
+/**
+ * 鑾峰彇鏉′欢鎴愮珛鐨� vite 鎻掍欢
+ * @param conditionPlugins
+ */
+async function loadConditionPlugins(conditionPlugins: ConditionPlugin[]) {
+  const plugins: PluginOption[] = [];
+  for (const conditionPlugin of conditionPlugins) {
+    if (conditionPlugin.condition) {
+      const realPlugins = await conditionPlugin.plugins();
+      plugins.push(...realPlugins);
+    }
+  }
+  return plugins.flat();
+}
+
+/**
+ * 鏍规嵁鏉′欢鑾峰彇閫氱敤鐨剉ite鎻掍欢
+ */
+async function loadCommonPlugins(
+  options: CommonPluginOptions,
+): Promise<ConditionPlugin[]> {
+  const { devtools, injectMetadata, isBuild, visualizer } = options;
+  return [
+    {
+      condition: true,
+      plugins: () => [
+        viteVue({
+          script: {
+            defineModel: true,
+            // propsDestructure: true,
+          },
+        }),
+        viteVueJsx(),
+      ],
+    },
+
+    {
+      condition: !isBuild && devtools,
+      plugins: () => [viteVueDevTools()],
+    },
+    {
+      condition: injectMetadata,
+      plugins: async () => [await viteMetadataPlugin()],
+    },
+    {
+      condition: isBuild && !!visualizer,
+      plugins: () => [<PluginOption>viteVisualizerPlugin({
+          filename: './node_modules/.cache/visualizer/stats.html',
+          gzipSize: true,
+          open: true,
+        })],
+    },
+  ];
+}
+
+/**
+ * 鏍规嵁鏉′欢鑾峰彇搴旂敤绫诲瀷鐨剉ite鎻掍欢
+ */
+async function loadApplicationPlugins(
+  options: ApplicationPluginOptions,
+): Promise<PluginOption[]> {
+  // 鍗曠嫭鍙栵紝鍚﹀垯commonOptions鎷夸笉鍒�
+  const isBuild = options.isBuild;
+  const env = options.env;
+
+  const {
+    archiver,
+    archiverPluginOptions,
+    compress,
+    compressTypes,
+    extraAppConfig,
+    html,
+    i18n,
+    importmap,
+    importmapOptions,
+    injectAppLoading,
+    license,
+    nitroMock,
+    nitroMockOptions,
+    print,
+    printInfoMap,
+    pwa,
+    pwaOptions,
+    vxeTableLazyImport,
+    ...commonOptions
+  } = options;
+
+  const commonPlugins = await loadCommonPlugins(commonOptions);
+
+  return await loadConditionPlugins([
+    ...commonPlugins,
+    {
+      condition: i18n,
+      plugins: async () => {
+        return [
+          viteVueI18nPlugin({
+            compositionOnly: true,
+            fullInstall: true,
+            runtimeOnly: true,
+          }),
+        ];
+      },
+    },
+    {
+      condition: print,
+      plugins: async () => {
+        return [await vitePrintPlugin({ infoMap: printInfoMap })];
+      },
+    },
+    {
+      condition: vxeTableLazyImport,
+      plugins: async () => {
+        return [await viteVxeTableImportsPlugin()];
+      },
+    },
+    {
+      condition: nitroMock,
+      plugins: async () => {
+        return [await viteNitroMockPlugin(nitroMockOptions)];
+      },
+    },
+
+    {
+      condition: injectAppLoading,
+      plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)],
+    },
+    {
+      condition: license,
+      plugins: async () => [await viteLicensePlugin()],
+    },
+    {
+      condition: pwa,
+      plugins: () =>
+        VitePWA({
+          injectRegister: false,
+          workbox: {
+            globPatterns: [],
+          },
+          ...pwaOptions,
+          manifest: {
+            display: 'standalone',
+            start_url: '/',
+            theme_color: '#ffffff',
+            ...pwaOptions?.manifest,
+          },
+        }),
+    },
+    {
+      condition: isBuild && !!compress,
+      plugins: () => {
+        const compressPlugins: PluginOption[] = [];
+        if (compressTypes?.includes('brotli')) {
+          compressPlugins.push(
+            viteCompressPlugin({ deleteOriginFile: false, ext: '.br' }),
+          );
+        }
+        if (compressTypes?.includes('gzip')) {
+          compressPlugins.push(
+            viteCompressPlugin({ deleteOriginFile: false, ext: '.gz' }),
+          );
+        }
+        return compressPlugins;
+      },
+    },
+    {
+      condition: !!html,
+      plugins: () => [viteHtmlPlugin({ minify: true })],
+    },
+    {
+      condition: isBuild && importmap,
+      plugins: () => {
+        return [viteImportMapPlugin(importmapOptions)];
+      },
+    },
+    {
+      condition: isBuild && extraAppConfig,
+      plugins: async () => [
+        await viteExtraAppConfigPlugin({ isBuild: true, root: process.cwd() }),
+      ],
+    },
+    {
+      condition: archiver,
+      plugins: async () => {
+        return [await viteArchiverPlugin(archiverPluginOptions)];
+      },
+    },
+  ]);
+}
+
+/**
+ * 鏍规嵁鏉′欢鑾峰彇搴撶被鍨嬬殑vite鎻掍欢
+ */
+async function loadLibraryPlugins(
+  options: LibraryPluginOptions,
+): Promise<PluginOption[]> {
+  // 鍗曠嫭鍙栵紝鍚﹀垯commonOptions鎷夸笉鍒�
+  const isBuild = options.isBuild;
+  const { dts, ...commonOptions } = options;
+  const commonPlugins = await loadCommonPlugins(commonOptions);
+  return await loadConditionPlugins([
+    ...commonPlugins,
+    {
+      condition: isBuild && !!dts,
+      plugins: () => [viteDtsPlugin({ logLevel: 'error' })],
+    },
+  ]);
+}
+
+export {
+  loadApplicationPlugins,
+  loadLibraryPlugins,
+  viteArchiverPlugin,
+  viteCompressPlugin,
+  viteDtsPlugin,
+  viteHtmlPlugin,
+  viteVisualizerPlugin,
+  viteVxeTableImportsPlugin,
+};
diff --git a/eims-ui/internal/vite-config/src/plugins/inject-app-loading/README.md b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/README.md
new file mode 100644
index 0000000..8d2358f
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/README.md
@@ -0,0 +1,3 @@
+# inject-app-loading
+
+鐢ㄤ簬鍦ㄥ簲鐢ㄥ姞杞芥椂鏄剧ず鍔犺浇鍔ㄧ敾鐨勬彃浠讹紝鍙嚜琛岄�夋嫨鍔犺浇鍔ㄧ敾鐨勬牱寮忋��
diff --git a/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html
new file mode 100644
index 0000000..20a21fb
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html
@@ -0,0 +1,107 @@
+<style data-app-loading="inject-css">
+  html {
+    /* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
+    line-height: 1.15;
+  }
+
+  .dark .loading {
+    background-color: #0d0d10;
+  }
+
+  .dark .loading .title {
+    color: rgb(255 255 255 / 85%);
+  }
+
+  .loading {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 9999;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+    pointer-events: none;
+    background-color: #f4f7f9;
+  }
+
+  .loading.hidden {
+    visibility: hidden;
+    opacity: 0;
+    transition: all 0.6s ease-out;
+  }
+
+  .loading .title {
+    margin-top: 36px;
+    font-size: 30px;
+    font-weight: 600;
+    color: rgb(0 0 0 / 85%);
+  }
+
+  .dot {
+    position: relative;
+    box-sizing: border-box;
+    display: inline-block;
+    width: 48px;
+    height: 48px;
+    margin-top: 30px;
+    font-size: 32px;
+    transform: rotate(45deg);
+    animation: rotate-ani 1.2s infinite linear;
+  }
+
+  .dot i {
+    position: absolute;
+    display: block;
+    width: 20px;
+    height: 20px;
+    background-color: hsl(var(--primary, 210 100% 50%));
+    border-radius: 100%;
+    opacity: 0.3;
+    transform: scale(0.75);
+    transform-origin: 50% 50%;
+    animation: spin-move-ani 1s infinite linear alternate;
+  }
+
+  .dot i:nth-child(1) {
+    top: 0;
+    left: 0;
+  }
+
+  .dot i:nth-child(2) {
+    top: 0;
+    right: 0;
+    animation-delay: 0.4s;
+  }
+
+  .dot i:nth-child(3) {
+    right: 0;
+    bottom: 0;
+    animation-delay: 0.8s;
+  }
+
+  .dot i:nth-child(4) {
+    bottom: 0;
+    left: 0;
+    animation-delay: 1.2s;
+  }
+
+  @keyframes rotate-ani {
+    to {
+      transform: rotate(405deg);
+    }
+  }
+
+  @keyframes spin-move-ani {
+    to {
+      opacity: 1;
+    }
+  }
+</style>
+<div class="loading" id="__app-loading__">
+  <span class="dot"><i></i><i></i><i></i><i></i></span>
+  <div class="title"><%= VITE_APP_TITLE %></div>
+</div>
diff --git a/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading.html b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading.html
new file mode 100644
index 0000000..2895705
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/default-loading.html
@@ -0,0 +1,113 @@
+<style data-app-loading="inject-css">
+  html {
+    /* same as ant-design-vue/dist/reset.css setting, avoid the title line-height changed */
+    line-height: 1.15;
+  }
+
+  .loading {
+    position: fixed;
+    top: 0;
+    left: 0;
+    z-index: 9999;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+    background-color: #f4f7f9;
+
+    /* transition: all 0.8s ease-out; */
+  }
+
+  .loading.hidden {
+    pointer-events: none;
+    visibility: hidden;
+    opacity: 0;
+    transition: all 0.8s ease-out;
+  }
+
+  .dark .loading {
+    background: #0d0d10;
+  }
+
+  .title {
+    margin-top: 66px;
+    font-size: 28px;
+    font-weight: 600;
+    color: rgb(0 0 0 / 85%);
+  }
+
+  .dark .title {
+    color: #fff;
+  }
+
+  .loader {
+    position: relative;
+    width: 48px;
+    height: 48px;
+  }
+
+  .loader::before {
+    position: absolute;
+    top: 60px;
+    left: 0;
+    width: 48px;
+    height: 5px;
+    content: '';
+    background: hsl(var(--primary, 210 100% 50%) / 50%);
+    border-radius: 50%;
+    animation: shadow-ani 0.5s linear infinite;
+  }
+
+  .loader::after {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    content: '';
+    background: hsl(var(--primary, 210 100% 50%));
+    border-radius: 4px;
+    animation: jump-ani 0.5s linear infinite;
+  }
+
+  @keyframes jump-ani {
+    15% {
+      border-bottom-right-radius: 3px;
+    }
+
+    25% {
+      transform: translateY(9px) rotate(22.5deg);
+    }
+
+    50% {
+      border-bottom-right-radius: 40px;
+      transform: translateY(18px) scale(1, 0.9) rotate(45deg);
+    }
+
+    75% {
+      transform: translateY(9px) rotate(67.5deg);
+    }
+
+    100% {
+      transform: translateY(0) rotate(90deg);
+    }
+  }
+
+  @keyframes shadow-ani {
+    0%,
+    100% {
+      transform: scale(1, 1);
+    }
+
+    50% {
+      transform: scale(1.2, 1);
+    }
+  }
+</style>
+<div class="loading" id="__app-loading__">
+  <div class="loader"></div>
+  <div class="title"><%= VITE_APP_TITLE %></div>
+</div>
diff --git a/eims-ui/internal/vite-config/src/plugins/inject-app-loading/index.ts b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/index.ts
new file mode 100644
index 0000000..9f6e2a5
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/inject-app-loading/index.ts
@@ -0,0 +1,66 @@
+import fs from 'node:fs';
+import fsp from 'node:fs/promises';
+import { join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { readPackageJSON } from '@vben/node-utils';
+
+import { type PluginOption } from 'vite';
+
+/**
+ * 鐢ㄤ簬鐢熸垚灏唋oading鏍峰紡娉ㄥ叆鍒伴」鐩腑
+ * 涓哄app鎻愪緵loading鏍峰紡锛屾棤闇�鍦ㄦ瘡涓� app -> index.html鍗曠嫭寮曞叆
+ */
+async function viteInjectAppLoadingPlugin(
+  isBuild: boolean,
+  env: Record<string, any> = {},
+  loadingTemplate = 'loading.html',
+): Promise<PluginOption | undefined> {
+  const loadingHtml = await getLoadingRawByHtmlTemplate(loadingTemplate);
+  const { version } = await readPackageJSON(process.cwd());
+  const envRaw = isBuild ? 'prod' : 'dev';
+  const cacheName = `'${env.VITE_APP_NAMESPACE}-${version}-${envRaw}-preferences-theme'`;
+
+  // 鑾峰彇缂撳瓨鐨勪富棰�
+  // 淇濊瘉榛戞殫涓婚涓嬶紝鍒锋柊椤甸潰鏃讹紝loading涔熸槸榛戞殫涓婚
+  const injectScript = `
+  <script data-app-loading="inject-js">
+  var theme = localStorage.getItem(${cacheName});
+  document.documentElement.classList.toggle('dark', /dark/.test(theme));
+</script>
+`;
+
+  if (!loadingHtml) {
+    return;
+  }
+
+  return {
+    enforce: 'pre',
+    name: 'vite:inject-app-loading',
+    transformIndexHtml: {
+      handler(html) {
+        const re = /<body\s*>/;
+        html = html.replace(re, `<body>${injectScript}${loadingHtml}`);
+        return html;
+      },
+      order: 'pre',
+    },
+  };
+}
+
+/**
+ * 鐢ㄤ簬鑾峰彇loading鐨刪tml妯℃澘
+ */
+async function getLoadingRawByHtmlTemplate(loadingTemplate: string) {
+  // 鏀寔鍦╝pp鍐呰嚜瀹氫箟loading妯℃澘锛屾ā鐗堝弬鑰僤efault-loading.html鍗冲彲
+  let appLoadingPath = join(process.cwd(), loadingTemplate);
+
+  if (!fs.existsSync(appLoadingPath)) {
+    const __dirname = fileURLToPath(new URL('.', import.meta.url));
+    appLoadingPath = join(__dirname, './default-loading.html');
+  }
+
+  return await fsp.readFile(appLoadingPath, 'utf8');
+}
+
+export { viteInjectAppLoadingPlugin };
diff --git a/eims-ui/internal/vite-config/src/plugins/inject-metadata.ts b/eims-ui/internal/vite-config/src/plugins/inject-metadata.ts
new file mode 100644
index 0000000..41c4db4
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/inject-metadata.ts
@@ -0,0 +1,111 @@
+import type { PluginOption } from 'vite';
+
+import {
+  dateUtil,
+  findMonorepoRoot,
+  getPackages,
+  readPackageJSON,
+} from '@vben/node-utils';
+
+import { readWorkspaceManifest } from '@pnpm/workspace.read-manifest';
+
+function resolvePackageVersion(
+  pkgsMeta: Record<string, string>,
+  name: string,
+  value: string,
+  catalog: Record<string, string>,
+) {
+  if (value.includes('catalog:')) {
+    return catalog[name];
+  }
+
+  if (value.includes('workspace')) {
+    return pkgsMeta[name];
+  }
+
+  return value;
+}
+
+async function resolveMonorepoDependencies() {
+  const { packages } = await getPackages();
+  const manifest = await readWorkspaceManifest(findMonorepoRoot());
+  const catalog = manifest?.catalog || {};
+
+  const resultDevDependencies: Record<string, string | undefined> = {};
+  const resultDependencies: Record<string, string | undefined> = {};
+  const pkgsMeta: Record<string, string> = {};
+
+  for (const { packageJson } of packages) {
+    pkgsMeta[packageJson.name] = packageJson.version;
+  }
+
+  for (const { packageJson } of packages) {
+    const { dependencies = {}, devDependencies = {} } = packageJson;
+    for (const [key, value] of Object.entries(dependencies)) {
+      resultDependencies[key] = resolvePackageVersion(
+        pkgsMeta,
+        key,
+        value,
+        catalog,
+      );
+    }
+    for (const [key, value] of Object.entries(devDependencies)) {
+      resultDevDependencies[key] = resolvePackageVersion(
+        pkgsMeta,
+        key,
+        value,
+        catalog,
+      );
+    }
+  }
+  return {
+    dependencies: resultDependencies,
+    devDependencies: resultDevDependencies,
+  };
+}
+
+/**
+ * 鐢ㄤ簬娉ㄥ叆椤圭洰淇℃伅
+ */
+async function viteMetadataPlugin(
+  root = process.cwd(),
+): Promise<PluginOption | undefined> {
+  const { author, description, homepage, license, version } =
+    await readPackageJSON(root);
+
+  const buildTime = dateUtil().format('YYYY-MM-DD HH:mm:ss');
+
+  return {
+    async config() {
+      const { dependencies, devDependencies } =
+        await resolveMonorepoDependencies();
+
+      const isAuthorObject = typeof author === 'object';
+      const authorName = isAuthorObject ? author.name : author;
+      const authorEmail = isAuthorObject ? author.email : null;
+      const authorUrl = isAuthorObject ? author.url : null;
+
+      return {
+        define: {
+          __VBEN_ADMIN_METADATA__: JSON.stringify({
+            authorEmail,
+            authorName,
+            authorUrl,
+            buildTime,
+            dependencies,
+            description,
+            devDependencies,
+            homepage,
+            license,
+            version,
+          }),
+          'import.meta.env.VITE_APP_VERSION': JSON.stringify(version),
+        },
+      };
+    },
+    enforce: 'post',
+    name: 'vite:inject-metadata',
+  };
+}
+
+export { viteMetadataPlugin };
diff --git a/eims-ui/internal/vite-config/src/plugins/license.ts b/eims-ui/internal/vite-config/src/plugins/license.ts
new file mode 100644
index 0000000..81fc4ff
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/license.ts
@@ -0,0 +1,63 @@
+import type {
+  NormalizedOutputOptions,
+  OutputBundle,
+  OutputChunk,
+} from 'rollup';
+import type { PluginOption } from 'vite';
+
+import { EOL } from 'node:os';
+
+import { dateUtil, readPackageJSON } from '@vben/node-utils';
+
+/**
+ * 鐢ㄤ簬娉ㄥ叆鐗堟潈淇℃伅
+ * @returns
+ */
+
+async function viteLicensePlugin(
+  root = process.cwd(),
+): Promise<PluginOption | undefined> {
+  const {
+    description = '',
+    homepage = '',
+    version = '',
+  } = await readPackageJSON(root);
+
+  return {
+    apply: 'build',
+    enforce: 'post',
+    generateBundle: {
+      handler: (_options: NormalizedOutputOptions, bundle: OutputBundle) => {
+        const date = dateUtil().format('YYYY-MM-DD ');
+        const copyrightText = `/*!
+  * Vben Admin
+  * Version: ${version}
+  * Author: vben
+  * Copyright (C) 2024 Vben
+  * License: MIT License
+  * Description: ${description}
+  * Date Created: ${date}
+  * Homepage: ${homepage}
+  * Contact: ann.vben@gmail.com
+*/
+              `.trim();
+
+        for (const [, fileContent] of Object.entries(bundle)) {
+          if (fileContent.type === 'chunk' && fileContent.isEntry) {
+            const chunkContent = fileContent as OutputChunk;
+            // 鎻掑叆鐗堟潈淇℃伅
+            const content = chunkContent.code;
+            const updatedContent = `${copyrightText}${EOL}${content}`;
+
+            // 鏇存柊bundle
+            (fileContent as OutputChunk).code = updatedContent;
+          }
+        }
+      },
+      order: 'post',
+    },
+    name: 'vite:license',
+  };
+}
+
+export { viteLicensePlugin };
diff --git a/eims-ui/internal/vite-config/src/plugins/nitro-mock.ts b/eims-ui/internal/vite-config/src/plugins/nitro-mock.ts
new file mode 100644
index 0000000..60d7327
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/nitro-mock.ts
@@ -0,0 +1,98 @@
+import type { PluginOption } from 'vite';
+
+import type { NitroMockPluginOptions } from '../typing';
+
+import { colors, consola, getPackage } from '@vben/node-utils';
+
+import getPort from 'get-port';
+import { build, createDevServer, createNitro, prepare } from 'nitropack';
+
+const hmrKeyRe = /^runtimeConfig\.|routeRules\./;
+
+export const viteNitroMockPlugin = ({
+  mockServerPackage = '@vben/backend-mock',
+  port = 5320,
+  verbose = true,
+}: NitroMockPluginOptions = {}): PluginOption => {
+  return {
+    async configureServer(server) {
+      const availablePort = await getPort({ port });
+      if (availablePort !== port) {
+        return;
+      }
+
+      const pkg = await getPackage(mockServerPackage);
+      if (!pkg) {
+        consola.log(
+          `Package ${mockServerPackage} not found. Skip mock server.`,
+        );
+        return;
+      }
+
+      runNitroServer(pkg.dir, port, verbose);
+
+      const _printUrls = server.printUrls;
+      server.printUrls = () => {
+        _printUrls();
+
+        consola.log(
+          `  ${colors.green('鉃�')}  ${colors.bold('Nitro Mock Server')}: ${colors.cyan(`http://localhost:${port}/api`)}`,
+        );
+      };
+    },
+    enforce: 'pre',
+    name: 'vite:mock-server',
+  };
+};
+
+async function runNitroServer(rootDir: string, port: number, verbose: boolean) {
+  let nitro: any;
+  const reload = async () => {
+    if (nitro) {
+      consola.info('Restarting dev server...');
+      if ('unwatch' in nitro.options._c12) {
+        await nitro.options._c12.unwatch();
+      }
+      await nitro.close();
+    }
+    nitro = await createNitro(
+      {
+        dev: true,
+        preset: 'nitro-dev',
+        rootDir,
+      },
+      {
+        c12: {
+          async onUpdate({ getDiff, newConfig }) {
+            const diff = getDiff();
+            if (diff.length === 0) {
+              return;
+            }
+            verbose &&
+              consola.info(
+                `Nitro config updated:\n${diff
+                  .map((entry) => `  ${entry.toString()}`)
+                  .join('\n')}`,
+              );
+            await (diff.every((e) => hmrKeyRe.test(e.key))
+              ? nitro.updateConfig(newConfig.config)
+              : reload());
+          },
+        },
+        watch: true,
+      },
+    );
+    nitro.hooks.hookOnce('restart', reload);
+
+    const server = createDevServer(nitro);
+    await server.listen(port, { showURL: false });
+    await prepare(nitro);
+    await build(nitro);
+
+    if (verbose) {
+      console.log('');
+      consola.success(colors.bold(colors.green('Nitro Mock Server started.')));
+    }
+  };
+  return await reload();
+}
diff --git a/eims-ui/internal/vite-config/src/plugins/print.ts b/eims-ui/internal/vite-config/src/plugins/print.ts
new file mode 100644
index 0000000..0146b8a
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/print.ts
@@ -0,0 +1,28 @@
+import type { PluginOption } from 'vite';
+
+import type { PrintPluginOptions } from '../typing';
+
+import { colors } from '@vben/node-utils';
+
+export const vitePrintPlugin = (
+  options: PrintPluginOptions = {},
+): PluginOption => {
+  const { infoMap = {} } = options;
+
+  return {
+    configureServer(server) {
+      const _printUrls = server.printUrls;
+      server.printUrls = () => {
+        _printUrls();
+
+        for (const [key, value] of Object.entries(infoMap)) {
+          console.log(
+            `  ${colors.green('鉃�')}  ${colors.bold(key)}: ${colors.cyan(value)}`,
+          );
+        }
+      };
+    },
+    enforce: 'pre',
+    name: 'vite:print-info',
+  };
+};
diff --git a/eims-ui/internal/vite-config/src/plugins/vxe-table.ts b/eims-ui/internal/vite-config/src/plugins/vxe-table.ts
new file mode 100644
index 0000000..3c107a7
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/plugins/vxe-table.ts
@@ -0,0 +1,20 @@
+import type { PluginOption } from 'vite';
+
+import { lazyImport, VxeResolver } from 'vite-plugin-lazy-import';
+
+async function viteVxeTableImportsPlugin(): Promise<PluginOption> {
+  return [
+    lazyImport({
+      resolvers: [
+        VxeResolver({
+          libraryName: 'vxe-table',
+        }),
+        VxeResolver({
+          libraryName: 'vxe-pc-ui',
+        }),
+      ],
+    }),
+  ];
+}
+
+export { viteVxeTableImportsPlugin };
diff --git a/eims-ui/internal/vite-config/src/typing.ts b/eims-ui/internal/vite-config/src/typing.ts
new file mode 100644
index 0000000..31683cc
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/typing.ts
@@ -0,0 +1,164 @@
+import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer';
+import type { ConfigEnv, PluginOption, UserConfig } from 'vite';
+import type { PluginOptions } from 'vite-plugin-dts';
+import type { Options as PwaPluginOptions } from 'vite-plugin-pwa';
+
+interface IImportMap {
+  imports?: Record<string, string>;
+  scopes?: {
+    [scope: string]: Record<string, string>;
+  };
+}
+interface PrintPluginOptions {
+  /**
+   * 鎵撳嵃鐨勬暟鎹�
+   */
+  infoMap?: Record<string, string | undefined>;
+}
+
+interface NitroMockPluginOptions {
+  /**
+   * mock server 鍖呭悕
+   */
+  mockServerPackage?: string;
+
+  /**
+   * mock 鏈嶅姟绔彛
+   */
+  port?: number;
+
+  /**
+   * mock 鏃ュ織鏄惁鎵撳嵃
+   */
+  verbose?: boolean;
+}
+
+interface ArchiverPluginOptions {
+  /**
+   * 杈撳嚭鏂囦欢鍚�
+   * @default dist
+   */
+  name?: string;
+  /**
+   * 杈撳嚭鐩綍
+   * @default .
+   */
+  outputDir?: string;
+}
+
+/**
+ * importmap 鎻掍欢閰嶇疆
+ */
+interface ImportmapPluginOptions {
+  /**
+   * CDN 渚涘簲鍟�
+   * @default jspm.io
+   */
+  defaultProvider?: 'esm.sh' | 'jspm.io';
+  /** importmap 閰嶇疆 */
+  importmap?: Array<{ name: string; range?: string }>;
+  /** 鎵嬪姩閰嶇疆importmap */
+  inputMap?: IImportMap;
+}
+
+/**
+ * 鐢ㄤ簬鍒ゆ柇鏄惁闇�瑕佸姞杞芥彃浠�
+ */
+interface ConditionPlugin {
+  // 鍒ゆ柇鏉′欢
+  condition?: boolean;
+  // 鎻掍欢瀵硅薄
+  plugins: () => PluginOption[] | PromiseLike<PluginOption[]>;
+}
+
+interface CommonPluginOptions {
+  /** 鏄惁寮�鍚痙evtools */
+  devtools?: boolean;
+  /** 鐜鍙橀噺 */
+  env?: Record<string, any>;
+  /** 鏄惁娉ㄥ叆metadata */
+  injectMetadata?: boolean;
+  /** 鏄惁鏋勫缓妯″紡 */
+  isBuild?: boolean;
+  /** 鏋勫缓妯″紡 */
+  mode?: string;
+  /** 寮�鍚緷璧栧垎鏋� */
+  visualizer?: boolean | PluginVisualizerOptions;
+}
+
+interface ApplicationPluginOptions extends CommonPluginOptions {
+  /** 寮�鍚悗锛屼細鍦ㄦ墦鍖卍ist鍚岀骇鐢熸垚dist.zip */
+  archiver?: boolean;
+  /** 鍘嬬缉褰掓。鎻掍欢閰嶇疆 */
+  archiverPluginOptions?: ArchiverPluginOptions;
+  /** 寮�鍚� gzip|brotli 鍘嬬缉 */
+  compress?: boolean;
+  /** 鍘嬬缉绫诲瀷 */
+  compressTypes?: ('brotli' | 'gzip')[];
+  /** 鍦ㄦ瀯寤虹殑鏃跺�欐娊绂婚厤缃枃浠� */
+  extraAppConfig?: boolean;
+  /** 鏄惁寮�鍚痟tml鎻掍欢  */
+  html?: boolean;
+  /** 鏄惁寮�鍚痠18n */
+  i18n?: boolean;
+  /** 鏄惁寮�鍚� importmap CDN  */
+  importmap?: boolean;
+  /** importmap 鎻掍欢閰嶇疆 */
+  importmapOptions?: ImportmapPluginOptions;
+  /** 鏄惁娉ㄥ叆app loading */
+  injectAppLoading?: boolean;
+  /** 鏄惁娉ㄥ叆鍏ㄥ眬scss */
+  injectGlobalScss?: boolean;
+  /** 鏄惁娉ㄥ叆鐗堟潈淇℃伅 */
+  license?: boolean;
+  /** 鏄惁寮�鍚痭itro mock */
+  nitroMock?: boolean;
+  /** nitro mock 鎻掍欢閰嶇疆 */
+  nitroMockOptions?: NitroMockPluginOptions;
+  /** 寮�鍚帶鍒跺彴鑷畾涔夋墦鍗� */
+  print?: boolean;
+  /** 鎵撳嵃鎻掍欢閰嶇疆 */
+  printInfoMap?: PrintPluginOptions['infoMap'];
+  /** 鏄惁寮�鍚痯wa */
+  pwa?: boolean;
+  /** pwa 鎻掍欢閰嶇疆 */
+  pwaOptions?: Partial<PwaPluginOptions>;
+  /** 鏄惁寮�鍚痸xe-table鎳掑姞杞� */
+  vxeTableLazyImport?: boolean;
+}
+
+interface LibraryPluginOptions extends CommonPluginOptions {
+  /** 寮�鍚� dts 杈撳嚭 */
+  dts?: boolean | PluginOptions;
+}
+
+type ApplicationOptions = ApplicationPluginOptions;
+
+type LibraryOptions = LibraryPluginOptions;
+
+type DefineApplicationOptions = (config?: ConfigEnv) => Promise<{
+  application?: ApplicationOptions;
+  vite?: UserConfig;
+}>;
+
+type DefineLibraryOptions = (config?: ConfigEnv) => Promise<{
+  library?: LibraryOptions;
+  vite?: UserConfig;
+}>;
+
+type DefineConfig = DefineApplicationOptions | DefineLibraryOptions;
+
+export type {
+  ApplicationPluginOptions,
+  ArchiverPluginOptions,
+  CommonPluginOptions,
+  ConditionPlugin,
+  DefineApplicationOptions,
+  DefineConfig,
+  DefineLibraryOptions,
+  IImportMap,
+  ImportmapPluginOptions,
+  LibraryPluginOptions,
+  NitroMockPluginOptions,
+  PrintPluginOptions,
+};
diff --git a/eims-ui/internal/vite-config/src/utils/env.ts b/eims-ui/internal/vite-config/src/utils/env.ts
new file mode 100644
index 0000000..3a042fe
--- /dev/null
+++ b/eims-ui/internal/vite-config/src/utils/env.ts
@@ -0,0 +1,110 @@
+import type { ApplicationPluginOptions } from '../typing';
+
+import { existsSync } from 'node:fs';
+import { join } from 'node:path';
+
+import { fs } from '@vben/node-utils';
+
+import dotenv from 'dotenv';
+
+const getBoolean = (value: string | undefined) => value === 'true';
+
+const getString = (value: string | undefined, fallback: string) =>
+  value ?? fallback;
+
+const getNumber = (value: string | undefined, fallback: number) =>
+  Number(value) || fallback;
+
+/**
+ * 鑾峰彇褰撳墠鐜涓嬬敓鏁堢殑閰嶇疆鏂囦欢鍚�
+ */
+function getConfFiles() {
+  const script = process.env.npm_lifecycle_script as string;
+  const reg = /--mode ([\d_a-z]+)/;
+  const result = reg.exec(script);
+  let mode = 'production';
+  if (result) {
+    mode = result[1] as string;
+  }
+  return ['.env', '.env.local', `.env.${mode}`, `.env.${mode}.local`];
+}
+
+/**
+ * Get the environment variables starting with the specified prefix
+ * @param match prefix
+ * @param confFiles ext
+ */
+async function loadEnv<T = Record<string, string>>(
+  match = 'VITE_GLOB_',
+  confFiles = getConfFiles(),
+) {
+  let envConfig = {};
+
+  for (const confFile of confFiles) {
+    try {
+      const confFilePath = join(process.cwd(), confFile);
+      if (existsSync(confFilePath)) {
+        const envPath = await fs.readFile(confFilePath, {
+          encoding: 'utf8',
+        });
+        const env = dotenv.parse(envPath);
+        envConfig = { ...envConfig, ...env };
+      }
+    } catch (error) {
+      console.error(`Error while parsing ${confFile}`, error);
+    }
+  }
+  const reg = new RegExp(`^(${match})`);
+  Object.keys(envConfig).forEach((key) => {
+    if (!reg.test(key)) {
+      Reflect.deleteProperty(envConfig, key);
+    }
+  });
+  return envConfig as T;
+}
+
+async function loadAndConvertEnv(
+  match = 'VITE_',
+  confFiles = getConfFiles(),
+): Promise<
+  {
+    appTitle: string;
+    base: string;
+    port: number;
+  } & Partial<ApplicationPluginOptions>
+> {
+  const envConfig = await loadEnv(match, confFiles);
+
+  const {
+    VITE_APP_TITLE,
+    VITE_ARCHIVER,
+    VITE_BASE,
+    VITE_COMPRESS,
+    VITE_DEVTOOLS,
+    VITE_INJECT_APP_LOADING,
+    VITE_NITRO_MOCK,
+    VITE_PORT,
+    VITE_PWA,
+    VITE_VISUALIZER,
+  } = envConfig;
+
+  const compressTypes = (VITE_COMPRESS ?? '')
+    .split(',')
+    .filter((item) => item === 'brotli' || item === 'gzip');
+
+  return {
+    appTitle: getString(VITE_APP_TITLE, 'Vben Admin'),
+    archiver: getBoolean(VITE_ARCHIVER),
+    base: getString(VITE_BASE, '/'),
+    compress: compressTypes.length > 0,
+    compressTypes,
+    devtools: getBoolean(VITE_DEVTOOLS),
+    injectAppLoading: getBoolean(VITE_INJECT_APP_LOADING),
+    nitroMock: getBoolean(VITE_NITRO_MOCK),
+    port: getNumber(VITE_PORT, 5173),
+    pwa: getBoolean(VITE_PWA),
+    visualizer: getBoolean(VITE_VISUALIZER),
+  };
+}
+
+export { loadAndConvertEnv, loadEnv };
diff --git a/eims-ui/internal/vite-config/tsconfig.json b/eims-ui/internal/vite-config/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/internal/vite-config/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/package.json b/eims-ui/package.json
new file mode 100644
index 0000000..6e53d71
--- /dev/null
+++ b/eims-ui/package.json
@@ -0,0 +1,124 @@
+{
+  "name": "vben-admin-monorepo",
+  "version": "5.5.0",
+  "private": true,
+  "keywords": [
+    "monorepo",
+    "turbo",
+    "vben",
+    "vben admin",
+    "vben pro",
+    "vue",
+    "vue admin",
+    "vue vben admin",
+    "vue vben admin pro",
+    "vue3"
+  ],
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": "vbenjs/vue-vben-admin.git",
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "cross-env NODE_OPTIONS=--max-old-space-size=8192 turbo build",
+    "build:analyze": "turbo build:analyze",
+    "build:antd": "pnpm run build --filter=@vben/web-antd",
+    "build:docker": "./scripts/deploy/build-local-docker-image.sh",
+    "build:docs": "pnpm run build --filter=@vben/docs",
+    "build:ele": "pnpm run build --filter=@vben/web-ele",
+    "build:naive": "pnpm run build --filter=@vben/web-naive",
+    "build:play": "pnpm run build --filter=@vben/playground",
+    "changeset": "pnpm exec changeset",
+    "check": "pnpm run check:circular && pnpm run check:dep && pnpm run check:type && pnpm check:cspell",
+    "check:circular": "vsh check-circular",
+    "check:cspell": "cspell lint **/*.ts **/README.md .changeset/*.md --no-progress",
+    "check:dep": "vsh check-dep",
+    "check:type": "turbo run typecheck",
+    "clean": "node ./scripts/clean.mjs",
+    "commit": "czg",
+    "dev": "turbo-run dev",
+    "dev:antd": "pnpm -F @vben/web-antd run dev",
+    "dev:docs": "pnpm -F @vben/docs run dev",
+    "dev:ele": "pnpm -F @vben/web-ele run dev",
+    "dev:naive": "pnpm -F @vben/web-naive run dev",
+    "dev:play": "pnpm -F @vben/playground run dev",
+    "format": "vsh lint --format",
+    "lint": "vsh lint",
+    "postinstall": "pnpm -r run stub --if-present",
+    "preinstall": "npx only-allow pnpm",
+    "prepare": "is-ci || husky",
+    "preview": "turbo-run preview",
+    "publint": "vsh publint",
+    "reinstall": "pnpm clean --del-lock && pnpm install",
+    "test:unit": "vitest run --dom",
+    "test:e2e": "turbo run test:e2e",
+    "update:deps": "npx taze -r -w",
+    "version": "pnpm exec changeset version && pnpm install --no-frozen-lockfile"
+  },
+  "devDependencies": {
+    "@changesets/changelog-github": "catalog:",
+    "@changesets/cli": "catalog:",
+    "@playwright/test": "catalog:",
+    "@types/node": "catalog:",
+    "@vben/commitlint-config": "workspace:*",
+    "@vben/eslint-config": "workspace:*",
+    "@vben/prettier-config": "workspace:*",
+    "@vben/stylelint-config": "workspace:*",
+    "@vben/tailwind-config": "workspace:*",
+    "@vben/tsconfig": "workspace:*",
+    "@vben/turbo-run": "workspace:*",
+    "@vben/vite-config": "workspace:*",
+    "@vben/vsh": "workspace:*",
+    "@vitejs/plugin-vue": "catalog:",
+    "@vitejs/plugin-vue-jsx": "catalog:",
+    "@vue/test-utils": "catalog:",
+    "autoprefixer": "catalog:",
+    "cross-env": "catalog:",
+    "cspell": "catalog:",
+    "happy-dom": "catalog:",
+    "husky": "catalog:",
+    "is-ci": "catalog:",
+    "lint-staged": "catalog:",
+    "playwright": "catalog:",
+    "rimraf": "catalog:",
+    "tailwindcss": "catalog:",
+    "turbo": "catalog:",
+    "typescript": "catalog:",
+    "unbuild": "catalog:",
+    "vite": "catalog:",
+    "vitest": "catalog:",
+    "vue": "catalog:",
+    "vue-tsc": "catalog:"
+  },
+  "engines": {
+    "node": ">=20.10.0",
+    "pnpm": ">=9.12.0"
+  },
+  "packageManager": "pnpm@9.15.0",
+  "pnpm": {
+    "peerDependencyRules": {
+      "allowedVersions": {
+        "eslint": "*"
+      }
+    },
+    "overrides": {
+      "@ast-grep/napi": "catalog:",
+      "@ctrl/tinycolor": "catalog:",
+      "clsx": "catalog:",
+      "pinia": "catalog:",
+      "vue": "catalog:"
+    },
+    "neverBuiltDependencies": [
+      "canvas",
+      "node-gyp"
+    ]
+  },
+  "resolutions": {
+    "esbuild": "0.24.0"
+  }
+}
diff --git a/eims-ui/packages/@core/README.md b/eims-ui/packages/@core/README.md
new file mode 100644
index 0000000..8eb201d
--- /dev/null
+++ b/eims-ui/packages/@core/README.md
@@ -0,0 +1,3 @@
+# @vben-core
+
+绯荤粺涓�浜涙瘮杈冨熀纭�鐨凷DK鍜孶I缁勪欢搴擄紝璇ョ洰褰曞悗缁畬鍠勫悗锛屽彲鑳戒細杩佺Щ鍑哄幓鎴栬�呭彂甯冨埌npm锛岃鍕垮皢浠讳綍涓氬姟閫昏緫鍜屼笟鍔″寘鏀惧湪璇ョ洰褰曘��
diff --git a/eims-ui/packages/@core/base/README.md b/eims-ui/packages/@core/base/README.md
new file mode 100644
index 0000000..cc745b4
--- /dev/null
+++ b/eims-ui/packages/@core/base/README.md
@@ -0,0 +1,5 @@
+# base
+
+鍩虹鍏变韩鍖咃紝璇峰嬁寮曞叆 workspace 渚濊禆
+
+-
diff --git a/eims-ui/packages/@core/base/design/package.json b/eims-ui/packages/@core/base/design/package.json
new file mode 100644
index 0000000..9e564de
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "@vben-core/design",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/base/design"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist",
+    "src"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    "./bem": {
+      "development": "./src/scss-bem/bem.scss",
+      "default": "./dist/bem.scss"
+    },
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/design.css"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/base/design/src/css/global.css b/eims-ui/packages/@core/base/design/src/css/global.css
new file mode 100644
index 0000000..d199909
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/css/global.css
@@ -0,0 +1,160 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+  *,
+  ::after,
+  ::before {
+    @apply border-border;
+
+    box-sizing: border-box;
+    border-style: solid;
+    border-width: 0;
+  }
+
+  html {
+    @apply text-foreground bg-background font-sans text-[100%];
+
+    font-variation-settings: normal;
+    line-height: 1.15;
+    text-size-adjust: 100%;
+    font-synthesis-weight: none;
+    scroll-behavior: smooth;
+    text-rendering: optimizelegibility;
+    -webkit-tap-highlight-color: transparent;
+
+    /* -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale; */
+  }
+
+  #app,
+  body,
+  html {
+    @apply size-full;
+
+    /* scrollbar-gutter: stable; */
+  }
+
+  body {
+    min-height: 100vh;
+
+    /* pointer-events: auto !important; */
+
+    /* overflow: overlay; */
+
+    /* -webkit-font-smoothing: antialiased; */
+
+    /* -moz-osx-font-smoothing: grayscale; */
+  }
+
+  a,
+  a:active,
+  a:hover,
+  a:link,
+  a:visited {
+    @apply no-underline;
+  }
+
+  ::view-transition-new(root),
+  ::view-transition-old(root) {
+    @apply animate-none mix-blend-normal;
+  }
+
+  ::view-transition-old(root) {
+    @apply z-[1];
+  }
+
+  ::view-transition-new(root) {
+    @apply z-[2147483646];
+  }
+
+  html.dark::view-transition-old(root) {
+    @apply z-[2147483646];
+  }
+
+  html.dark::view-transition-new(root) {
+    @apply z-[1];
+  }
+
+  input::placeholder,
+  textarea::placeholder {
+    @apply opacity-100;
+  }
+
+  /* input:-webkit-autofill {
+    @apply border-none;
+
+    box-shadow: 0 0 0 1000px transparent inset;
+  } */
+
+  input[type='number']::-webkit-inner-spin-button,
+  input[type='number']::-webkit-outer-spin-button {
+    @apply m-0 appearance-none;
+  }
+
+  /* 鍙湁闈瀖ac涓嬫墠杩涜璋冩暣锛宮ac涓嬩娇鐢ㄩ粯璁ゆ粴鍔ㄦ潯 */
+  html:not([data-platform='macOs']) {
+    ::-webkit-scrollbar {
+      @apply h-[10px] w-[10px];
+    }
+
+    ::-webkit-scrollbar-thumb {
+      @apply bg-border rounded-sm border-none;
+    }
+
+    ::-webkit-scrollbar-track {
+      @apply rounded-sm border-none bg-transparent shadow-none;
+    }
+
+    ::-webkit-scrollbar-button {
+      @apply hidden;
+    }
+  }
+}
+
+@layer components {
+  .flex-center {
+    @apply flex items-center justify-center;
+  }
+
+  .flex-col-center {
+    @apply flex flex-col items-center justify-center;
+  }
+
+  .outline-box {
+    @apply outline-border relative cursor-pointer rounded-md p-1 outline outline-1;
+  }
+
+  .outline-box::after {
+    @apply absolute left-1/2 top-1/2 z-20 h-0 w-[1px] rounded-sm opacity-0 outline outline-2 outline-transparent transition-all duration-300 content-[""];
+  }
+
+  .outline-box.outline-box-active {
+    @apply outline-primary outline outline-2;
+  }
+
+  .outline-box.outline-box-active::after {
+    display: none;
+  }
+
+  .outline-box:not(.outline-box-active):hover::after {
+    @apply outline-primary left-0 top-0 h-full w-full p-1 opacity-100;
+  }
+
+  .vben-link {
+    @apply text-primary hover:text-primary-hover active:text-primary-active cursor-pointer;
+  }
+
+  .card-box {
+    @apply bg-card text-card-foreground border-border rounded-xl border;
+  }
+}
+
+html.invert-mode {
+  @apply invert;
+}
+
+html.grayscale-mode {
+  @apply grayscale;
+}
diff --git a/eims-ui/packages/@core/base/design/src/css/nprogress.css b/eims-ui/packages/@core/base/design/src/css/nprogress.css
new file mode 100644
index 0000000..3503dab
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/css/nprogress.css
@@ -0,0 +1,59 @@
+/* Make clicks pass-through */
+#nprogress {
+  @apply pointer-events-none;
+}
+
+#nprogress .bar {
+  @apply bg-primary fixed left-0 top-0 z-[1031] h-[2px] w-full;
+}
+
+/* Fancy blur effect */
+#nprogress .peg {
+  @apply absolute right-0 block h-full w-[100px];
+
+  box-shadow:
+    0 0 10px hsl(var(--primary)),
+    0 0 5px hsl(var(--primary));
+  opacity: 1;
+  transform: rotate(3deg) translate(0, -4px);
+}
+
+/* Remove these to get rid of the spinner */
+#nprogress .spinner {
+  @apply fixed right-4 top-4 z-[1031] block;
+}
+
+#nprogress .spinner-icon {
+  @apply border-t-primary border-l-primary size-4 rounded-full border-[2px] border-solid border-transparent;
+
+  animation: nprogress-spinner 400ms linear infinite;
+}
+
+.nprogress-custom-parent {
+  @apply relative overflow-hidden;
+}
+
+.nprogress-custom-parent #nprogress .spinner,
+.nprogress-custom-parent #nprogress .bar {
+  @apply absolute;
+}
+
+@keyframes nprogress-spinner {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+@keyframes nprogress-spinner {
+  0% {
+    transform: rotate(0deg);
+  }
+
+  100% {
+    transform: rotate(360deg);
+  }
+}
diff --git a/eims-ui/packages/@core/base/design/src/css/transition.css b/eims-ui/packages/@core/base/design/src/css/transition.css
new file mode 100644
index 0000000..c1cb0e4
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/css/transition.css
@@ -0,0 +1,236 @@
+.slide-up-enter-active,
+.slide-up-leave-active {
+  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);
+}
+
+.slide-up-move {
+  transition: transform 0.3s;
+}
+
+.slide-up-enter-from,
+.slide-up-leave-to {
+  opacity: 0;
+  transform: translateY(-15px);
+}
+
+.slide-down-enter-active,
+.slide-down-leave-active {
+  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);
+}
+
+.slide-down-move {
+  transition: transform 0.3s;
+}
+
+.slide-down-enter-from,
+.slide-down-leave-to {
+  opacity: 0;
+  transform: translateY(15px);
+}
+
+.slide-left-enter-active,
+.slide-left-leave-active {
+  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);
+}
+
+.slide-left-move {
+  transition: transform 0.3s;
+}
+
+.slide-left-enter-from,
+.slide-left-leave-to {
+  opacity: 0;
+  transform: translate(-15px);
+}
+
+.slide-right-enter-active,
+.slide-right-leave-active {
+  transition: 0.25s cubic-bezier(0.25, 0.8, 0.5, 1);
+}
+
+.slide-right-move {
+  transition: transform 0.3s;
+}
+
+.slide-right-enter-from,
+.slide-right-leave-to {
+  opacity: 0;
+  transform: translate(15px);
+}
+
+.fade-transition-enter-active,
+.fade-transition-leave-active {
+  transition: opacity 0.2s ease-in-out;
+}
+
+.fade-transition-enter-from,
+.fade-transition-leave-to {
+  opacity: 0;
+}
+
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.2s ease-in-out;
+}
+
+.fade-enter-from,
+.fade-leave-to {
+  opacity: 0;
+}
+
+.fade-slide-leave-active,
+.fade-slide-enter-active {
+  transition: all 0.3s;
+}
+
+.fade-slide-enter-from {
+  opacity: 0;
+  transform: translate(-30px);
+}
+
+.fade-slide-leave-to {
+  opacity: 0;
+  transform: translate(30px);
+}
+
+.fade-down-enter-active,
+.fade-down-leave-active {
+  transition:
+    opacity 0.25s,
+    transform 0.3s;
+}
+
+.fade-down-enter-from {
+  opacity: 0;
+  transform: translateY(-10%);
+}
+
+.fade-down-leave-to {
+  opacity: 0;
+  transform: translateY(10%);
+}
+
+.fade-scale-leave-active,
+.fade-scale-enter-active {
+  transition: all 0.28s;
+}
+
+.fade-scale-enter-from {
+  opacity: 0;
+  transform: scale(1.2);
+}
+
+.fade-scale-leave-to {
+  opacity: 0;
+  transform: scale(0.8);
+}
+
+.fade-up-enter-active,
+.fade-up-leave-active {
+  transition:
+    opacity 0.2s,
+    transform 0.25s;
+}
+
+.fade-up-enter-from {
+  opacity: 0;
+  transform: translateY(10%);
+}
+
+.fade-up-leave-to {
+  opacity: 0;
+  transform: translateY(-10%);
+}
+
+@keyframes fade-slide {
+  0% {
+    opacity: 0;
+    transform: translate(-30px);
+  }
+
+  50% {
+    opacity: 1;
+  }
+
+  100% {
+    opacity: 0;
+    transform: translate(30px);
+  }
+}
+
+@keyframes fade {
+  0% {
+    opacity: 0;
+  }
+
+  50% {
+    opacity: 1;
+  }
+
+  100% {
+    opacity: 0;
+  }
+}
+
+@keyframes fade-up {
+  0% {
+    opacity: 0;
+    transform: translateY(10%);
+  }
+
+  50% {
+    opacity: 1;
+  }
+
+  100% {
+    opacity: 0;
+    transform: translateY(-10%);
+  }
+}
+
+@keyframes fade-down {
+  0% {
+    opacity: 0;
+    transform: translateY(-10%);
+  }
+
+  50% {
+    opacity: 1;
+  }
+
+  100% {
+    opacity: 0;
+    transform: translateY(10%);
+  }
+}
+
+.fade-slow {
+  animation: fade 3s infinite;
+}
+
+.fade-slide-slow {
+  animation: fade-slide 3s infinite;
+}
+
+.fade-up-slow {
+  animation: fade-up 3s infinite;
+}
+
+.fade-down-slow {
+  animation: fade-down 3s infinite;
+}
+
+.collapse-transition {
+  transition:
+    0.2s height ease-in-out,
+    0.2s padding-top ease-in-out,
+    0.2s padding-bottom ease-in-out;
+}
+
+.collapse-transition-leave-active,
+.collapse-transition-enter-active {
+  transition:
+    0.2s max-height ease-in-out,
+    0.2s padding-top ease-in-out,
+    0.2s margin-top ease-in-out;
+}
diff --git a/eims-ui/packages/@core/base/design/src/css/ui.css b/eims-ui/packages/@core/base/design/src/css/ui.css
new file mode 100644
index 0000000..3a002f2
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/css/ui.css
@@ -0,0 +1,83 @@
+.side-content {
+  animation-duration: 0.2s;
+  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.side-content[data-side='top'] {
+  animation-name: slide-up;
+}
+
+.side-content[data-side='bottom'] {
+  animation-name: slide-down;
+}
+
+.side-content[data-side='left'] {
+  animation-name: slide-left;
+}
+
+.side-content[data-side='right'] {
+  animation-name: slide-right;
+}
+
+.breadcrumb-transition-enter-active {
+  transition:
+    transform 0.4s cubic-bezier(0.76, 0, 0.24, 1),
+    opacity 0.4s cubic-bezier(0.76, 0, 0.24, 1);
+}
+
+.breadcrumb-transition-leave-active {
+  display: none;
+}
+
+.breadcrumb-transition-enter-from {
+  opacity: 0;
+  transform: translateX(30px) skewX(-30deg);
+}
+
+@keyframes slide-down {
+  from {
+    opacity: 0;
+    transform: translateY(-10px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes slide-left {
+  from {
+    opacity: 0;
+    transform: translateX(-10px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+@keyframes slide-right {
+  from {
+    opacity: 0;
+    transform: translateX(-10px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateX(0);
+  }
+}
+
+@keyframes slide-up {
+  from {
+    opacity: 0;
+    transform: translateY(10px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
diff --git a/eims-ui/packages/@core/base/design/src/design-tokens/dark.css b/eims-ui/packages/@core/base/design/src/design-tokens/dark.css
new file mode 100644
index 0000000..2a1d052
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/design-tokens/dark.css
@@ -0,0 +1,442 @@
+.dark,
+.dark[data-theme='custom'],
+.dark[data-theme='default'] {
+  /* Default background color of <body />...etc */
+  --background: 222.34deg 10.43% 12.27%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 220deg 13.06% 9%;
+  --foreground: 0 0% 95%;
+
+  /* Background color for <Card /> */
+  --card: 222.34deg 10.43% 12.27%;
+
+  /* --card: 222.2 84% 4.9%; */
+  --card-foreground: 210 40% 98%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 222.82deg 8.43% 12.27%;
+  --popover-foreground: 210 40% 98%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 220deg 6.82% 17.25%; */
+
+  /* --muted-foreground: 215 20.2% 65.1%; */
+
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+
+  /* 涓婚棰滆壊 */
+
+  /* --primary: 245 82% 67%; */
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --info: 180, 1.54%, 12.75%;
+  --info-foreground: 220, 4%, 58%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* 棰滆壊娆¤ */
+  --secondary: 240 5% 17%;
+  --secondary-foreground: 0 0% 98%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 216 5% 19%;
+  --accent-dark: 240 0% 22%;
+  --accent-darker: 240 0% 26%;
+  --accent-lighter: 216 5% 12%;
+  --accent-hover: 216 5% 24%;
+  --accent-foreground: 0 0% 98%;
+
+  /* Darker color */
+  --heavy: 216 5% 24%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 3.7% 22%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 0deg 0% 100% / 10%;
+  --input-placeholder: 218deg 11% 65%;
+  --input-background: 0deg 0% 100% / 5%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* 鍩烘湰鍦嗚澶у皬 */
+  --radius: 0.5rem;
+
+  /* ============= Custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0deg 0% 0% / 40%;
+  --overlay-content: 0deg 0% 0% / 40%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  --sidebar: 222.34deg 10.43% 12.27%;
+  --sidebar-deep: 220deg 13.06% 9%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 222.34deg 10.43% 12.27%;
+
+  color-scheme: dark;
+}
+
+.dark[data-theme='violet'],
+[data-theme='violet'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 263.4 70% 50.4%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
+
+.dark[data-theme='pink'],
+[data-theme='pink'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 0 0% 9%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 346.8 77.2% 49.8%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='rose'],
+[data-theme='rose'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 85.7% 97.3%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 72.2% 50.6%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='sky-blue'],
+[data-theme='sky-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='deep-blue'],
+[data-theme='deep-blue'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 224.3 76.3% 48%;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='green'],
+[data-theme='green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='deep-green'],
+[data-theme='deep-green'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 95%;
+  --card: 24 9.8% 6%;
+  --card-foreground: 0 0% 95%;
+  --popover: 0 0% 9%;
+  --popover-foreground: 0 0% 95%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 15%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 85.7% 97.3%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 142.4 71.8% 29.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='orange'],
+[data-theme='orange'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 0 72.2% 50.6%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 20.5 90.2% 48.2%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='yellow'],
+[data-theme='yellow'] .dark {
+  --background: 20 14.3% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 60 9.1% 97.8%;
+  --card: 20 14.3% 4.1%;
+  --card-foreground: 60 9.1% 97.8%;
+  --popover: 20 14.3% 4.1%;
+  --popover-foreground: 60 9.1% 97.8%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 12 6.5% 15.1%;
+  --secondary-foreground: 60 9.1% 97.8%;
+  --muted: 12 6.5% 15.1%;
+  --muted-foreground: 24 5.4% 63.9%;
+  --accent: 12 6.5% 15.1%;
+  --accent-foreground: 60 9.1% 97.8%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 12 6.5% 15.1%;
+  --input: 12 6.5% 15.1%;
+  --ring: 35.5 91.7% 32.9%;
+  --sidebar: 20 14.3% 4.1%;
+  --sidebar-deep: 20 14.3% 4.1%;
+  --header: 20 14.3% 4.1%;
+}
+
+.dark[data-theme='zinc'],
+[data-theme='zinc'] .dark {
+  --background: 240 10% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 240 10% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 240 10% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 240 5.9% 10%;
+  --secondary: 240 3.7% 15.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 240 3.7% 15.9%;
+  --muted-foreground: 240 5% 64.9%;
+  --accent: 240 3.7% 15.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 3.7% 15.9%;
+  --input: 240 3.7% 15.9%;
+  --ring: 240 4.9% 83.9%;
+  --sidebar: 240 10% 3.9%;
+  --sidebar-deep: 240 10% 3.9%;
+  --header: 240 10% 3.9%;
+}
+
+.dark[data-theme='neutral'],
+[data-theme='neutral'] .dark {
+  --background: 0 0% 3.9%;
+  --background-deep: var(--background);
+  --foreground: 0 0% 98%;
+  --card: 0 0% 3.9%;
+  --card-foreground: 0 0% 98%;
+  --popover: 0 0% 3.9%;
+  --popover-foreground: 0 0% 98%;
+  --primary-foreground: 0 0% 9%;
+  --secondary: 0 0% 14.9%;
+  --secondary-foreground: 0 0% 98%;
+  --muted: 0 0% 14.9%;
+  --muted-foreground: 0 0% 63.9%;
+  --accent: 0 0% 14.9%;
+  --accent-foreground: 0 0% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 14.9%;
+  --input: 0 0% 14.9%;
+  --ring: 0 0% 83.1%;
+  --sidebar: 0 0% 3.9%;
+  --sidebar-deep: 0 0% 3.9%;
+  --header: 0 0% 3.9%;
+}
+
+.dark[data-theme='slate'],
+[data-theme='slate'] .dark {
+  --background: 222.2 84% 4.9%;
+  --background-deep: var(--background);
+  --foreground: 210 40% 98%;
+  --card: 222.2 84% 4.9%;
+  --card-foreground: 210 40% 98%;
+  --popover: 222.2 84% 4.9%;
+  --popover-foreground: 210 40% 98%;
+  --primary-foreground: 222.2 47.4% 11.2%;
+  --secondary: 217.2 32.6% 17.5%;
+  --secondary-foreground: 210 40% 98%;
+  --muted: 217.2 32.6% 17.5%;
+  --muted-foreground: 215 20.2% 65.1%;
+  --accent: 217.2 32.6% 17.5%;
+  --accent-foreground: 210 40% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 217.2 32.6% 17.5%;
+  --input: 217.2 32.6% 17.5%;
+  --ring: 212.7 26.8% 83.9;
+  --sidebar: 222.2 84% 4.9%;
+  --sidebar-deep: 222.2 84% 4.9%;
+  --header: 222.2 84% 4.9%;
+}
+
+.dark[data-theme='gray'],
+[data-theme='gray'] .dark {
+  --background: 224 71.4% 4.1%;
+  --background-deep: var(--background);
+  --foreground: 210 20% 98%;
+  --card: 224 71.4% 4.1%;
+  --card-foreground: 210 20% 98%;
+  --popover: 224 71.4% 4.1%;
+  --popover-foreground: 210 20% 98%;
+  --primary-foreground: 220.9 39.3% 11%;
+  --secondary: 215 27.9% 16.9%;
+  --secondary-foreground: 210 20% 98%;
+  --muted: 215 27.9% 16.9%;
+  --muted-foreground: 217.9 10.6% 64.9%;
+  --accent: 215 27.9% 16.9%;
+  --accent-foreground: 210 20% 98%;
+  --destructive: 359.21 68.47% 56.47%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 215 27.9% 16.9%;
+  --input: 215 27.9% 16.9%;
+  --ring: 216 12.2% 83.9%;
+  --sidebar: 224 71.4% 4.1%;
+  --sidebar-deep: 224 71.4% 4.1%;
+  --header: 224 71.4% 4.1%;
+}
diff --git a/eims-ui/packages/@core/base/design/src/design-tokens/default.css b/eims-ui/packages/@core/base/design/src/design-tokens/default.css
new file mode 100644
index 0000000..c81ace7
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/design-tokens/default.css
@@ -0,0 +1,379 @@
+:root {
+  --font-family: -apple-system, blinkmacsystemfont, 'Segoe UI', roboto,
+    'Helvetica Neue', arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
+    'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
+
+  /* Default background color of <body />...etc */
+  --background: 0 0% 100%;
+
+  /* 涓讳綋鍖哄煙鑳屾櫙鑹� */
+  --background-deep: 216 20.11% 95.47%;
+  --foreground: 210 6% 21%;
+
+  /* Background color for <Card /> */
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+
+  /* Background color for popovers such as <DropdownMenu />, <HoverCard />, <Popover /> */
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+
+  /* Muted backgrounds such as <TabsList />, <Skeleton /> and <Switch /> */
+
+  /* --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%; */
+
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+
+  /* 涓婚棰滆壊 */
+
+  --primary: 212 100% 45%;
+  --primary-foreground: 0 0% 98%;
+
+  /* Used for destructive actions such as <Button variant="destructive"> */
+
+  --destructive: 359.33 100% 65.1%;
+  --destructive-foreground: 0 0% 98%;
+
+  /* Used for success actions such as <message> */
+
+  --info: 240, 5%, 96%;
+  --info-foreground: 220, 4%, 58%;
+
+  /* Used for success actions such as <message> */
+
+  --success: 144 57% 58%;
+  --success-foreground: 0 0% 98%;
+
+  /* Used for warning actions such as <message> */
+
+  --warning: 42 84% 61%;
+  --warning-foreground: 0 0% 98%;
+
+  /* Secondary colors for <Button /> */
+
+  --secondary: 240 5% 96%;
+  --secondary-foreground: 240 6% 10%;
+
+  /* Used for accents such as hover effects on <DropdownMenuItem>, <SelectItem>...etc */
+  --accent: 240 5% 96%;
+  --accent-dark: 216 14% 93%;
+  --accent-darker: 216 11% 91%;
+  --accent-lighter: 240 0% 98%;
+  --accent-hover: 200deg 10% 90%;
+  --accent-foreground: 240 6% 10%;
+
+  /* Darker color */
+  --heavy: 192deg 9.43% 89.61%;
+  --heavy-foreground: var(--accent-foreground);
+
+  /* Default border color */
+  --border: 240 5.9% 90%;
+
+  /* Border color for inputs such as <Input />, <Select />, <Textarea /> */
+  --input: 240deg 5.88% 90%;
+  --input-placeholder: 217 10.6% 65%;
+  --input-background: 0 0% 100%;
+
+  /* Used for focus ring */
+  --ring: 222.2 84% 4.9%;
+
+  /* Border radius for card, input and buttons */
+  --radius: 0.5rem;
+
+  /* ============= custom ============= */
+
+  /* 閬僵棰滆壊 */
+  --overlay: 0 0% 0% / 45%;
+  --overlay-content: 0 0% 95% / 45%;
+
+  /* 鍩烘湰鏂囧瓧澶у皬 */
+  --font-size-base: 16px;
+
+  /* =============component & UI============= */
+
+  /* menu */
+  --sidebar: 0 0% 100%;
+  --sidebar-deep: 0 0% 100%;
+  --menu: var(--sidebar);
+
+  /* header */
+  --header: 0 0% 100%;
+
+  accent-color: var(--primary);
+  color-scheme: light;
+}
+
+[data-theme='violet'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 262.1 83.3% 57.8%;
+}
+
+[data-theme='pink'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='rose'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 346.8 77.2% 49.8%;
+}
+
+[data-theme='sky-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='deep-blue'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 221.2 83.2% 53.3%;
+}
+
+[data-theme='green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='deep-green'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 355.7 100% 97.3%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 142.1 76.2% 36.3%;
+}
+
+[data-theme='orange'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 60 9.1% 97.8%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 24.6 95% 53.1%;
+}
+
+[data-theme='yellow'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 20 14.3% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 20 14.3% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 20 14.3% 4.1%;
+  --primary-foreground: 26 83.3% 14.1%;
+  --secondary: 60 4.8% 95.9%;
+  --secondary-foreground: 24 9.8% 10%;
+  --muted: 60 4.8% 95.9%;
+  --muted-foreground: 25 5.3% 44.7%;
+  --accent: 60 4.8% 95.9%;
+  --accent-foreground: 24 9.8% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 60 9.1% 97.8%;
+  --border: 20 5.9% 90%;
+  --input: 20 5.9% 90%;
+  --ring: 20 14.3% 4.1%;
+}
+
+[data-theme='zinc'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 240 10% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 240 10% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 240 10% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 240 4.8% 95.9%;
+  --secondary-foreground: 240 5.9% 10%;
+  --muted: 240 4.8% 95.9%;
+  --muted-foreground: 240 3.8% 46.1%;
+  --accent: 240 4.8% 95.9%;
+  --accent-foreground: 240 5.9% 10%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 240 5.9% 90%;
+  --input: 240 5.9% 90%;
+  --ring: 240 5.9% 10%;
+}
+
+[data-theme='neutral'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 0 0% 3.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 0 0% 3.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 0 0% 3.9%;
+  --primary-foreground: 0 0% 98%;
+  --secondary: 0 0% 96.1%;
+  --secondary-foreground: 0 0% 9%;
+  --muted: 0 0% 96.1%;
+  --muted-foreground: 0 0% 45.1%;
+  --accent: 0 0% 96.1%;
+  --accent-foreground: 0 0% 9%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 0 0% 98%;
+  --border: 0 0% 89.8%;
+  --input: 0 0% 89.8%;
+  --ring: 0 0% 3.9%;
+}
+
+[data-theme='slate'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 222.2 84% 4.9%;
+  --card: 0 0% 100%;
+  --card-foreground: 222.2 84% 4.9%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 222.2 84% 4.9%;
+  --primary-foreground: 210 40% 98%;
+  --secondary: 210 40% 96.1%;
+  --secondary-foreground: 222.2 47.4% 11.2%;
+  --muted: 210 40% 96.1%;
+  --muted-foreground: 215.4 16.3% 46.9%;
+  --accent: 210 40% 96.1%;
+  --accent-foreground: 222.2 47.4% 11.2%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 40% 98%;
+  --border: 214.3 31.8% 91.4%;
+  --input: 214.3 31.8% 91.4%;
+  --ring: 222.2 84% 4.9%;
+}
+
+[data-theme='gray'] {
+  /* --background: 0 0% 100%; */
+  --foreground: 224 71.4% 4.1%;
+  --card: 0 0% 100%;
+  --card-foreground: 224 71.4% 4.1%;
+  --popover: 0 0% 100%;
+  --popover-foreground: 224 71.4% 4.1%;
+  --primary-foreground: 210 20% 98%;
+  --secondary: 220 14.3% 95.9%;
+  --secondary-foreground: 220.9 39.3% 11%;
+  --muted: 220 14.3% 95.9%;
+  --muted-foreground: 220 8.9% 46.1%;
+  --accent: 220 14.3% 95.9%;
+  --accent-foreground: 220.9 39.3% 11%;
+  --destructive: 0 84.2% 60.2%;
+  --destructive-foreground: 210 20% 98%;
+  --border: 220 13% 91%;
+  --input: 220 13% 91%;
+  --ring: 224 71.4% 4.1%;
+}
diff --git a/eims-ui/packages/@core/base/design/src/design-tokens/index.ts b/eims-ui/packages/@core/base/design/src/design-tokens/index.ts
new file mode 100644
index 0000000..2d031d8
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/design-tokens/index.ts
@@ -0,0 +1,4 @@
+import './default.css';
+import './dark.css';
+
+export {};
diff --git a/eims-ui/packages/@core/base/design/src/index.ts b/eims-ui/packages/@core/base/design/src/index.ts
new file mode 100644
index 0000000..d7c0534
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/index.ts
@@ -0,0 +1,8 @@
+import './design-tokens';
+
+import './css/global.css';
+import './css/transition.css';
+import './css/nprogress.css';
+import './css/ui.css';
+
+export {};
diff --git a/eims-ui/packages/@core/base/design/src/scss-bem/bem.scss b/eims-ui/packages/@core/base/design/src/scss-bem/bem.scss
new file mode 100644
index 0000000..3910a30
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/scss-bem/bem.scss
@@ -0,0 +1,34 @@
+@forward './constants';
+
+@mixin b($block) {
+  $B: $namespace + '-' + $block !global;
+
+  .#{$B} {
+    @content;
+  }
+}
+
+@mixin e($name) {
+  @at-root {
+    &#{$element-separator}#{$name} {
+      @content;
+    }
+  }
+}
+
+@mixin m($name) {
+  @at-root {
+    &#{$modifier-separator}#{$name} {
+      @content;
+    }
+  }
+}
+
+// block__element.is-active {}
+@mixin is($state, $prefix: $state-prefix) {
+  @at-root {
+    &.#{$prefix}-#{$state} {
+      @content;
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/base/design/src/scss-bem/constants.scss b/eims-ui/packages/@core/base/design/src/scss-bem/constants.scss
new file mode 100644
index 0000000..87c24ef
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/src/scss-bem/constants.scss
@@ -0,0 +1,5 @@
+$namespace: 'vben' !default;
+$common-separator: '-' !default;
+$element-separator: '__' !default;
+$modifier-separator: '--' !default;
+$state-prefix: 'is' !default;
diff --git a/eims-ui/packages/@core/base/design/tsconfig.json b/eims-ui/packages/@core/base/design/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/base/design/vite.config.mts b/eims-ui/packages/@core/base/design/vite.config.mts
new file mode 100644
index 0000000..935929d
--- /dev/null
+++ b/eims-ui/packages/@core/base/design/vite.config.mts
@@ -0,0 +1,9 @@
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    vite: {
+      publicDir: 'src/scss-bem',
+    },
+  };
+});
diff --git a/eims-ui/packages/@core/base/icons/build.config.ts b/eims-ui/packages/@core/base/icons/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/packages/@core/base/icons/package.json b/eims-ui/packages/@core/base/icons/package.json
new file mode 100644
index 0000000..bb971c0
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "@vben-core/icons",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/base/icons"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "types": "./dist/index.d.ts",
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@iconify/vue": "catalog:",
+    "lucide-vue-next": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/base/icons/src/create-icon.ts b/eims-ui/packages/@core/base/icons/src/create-icon.ts
new file mode 100644
index 0000000..9d9ba32
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/src/create-icon.ts
@@ -0,0 +1,30 @@
+import { defineComponent, h } from 'vue';
+
+import { addIcon, Icon, type IconifyIcon } from '@iconify/vue';
+
+function createIconifyIcon(icon: string) {
+  return defineComponent({
+    name: `Icon-${icon}`,
+    setup(props, { attrs }) {
+      return () => h(Icon, { icon, ...props, ...attrs });
+    },
+  });
+}
+
+/**
+ * 鍒涘缓绂荤嚎鍥炬爣
+ * @param icon 鍥炬爣鍚嶇О 寤鸿涓巌conify鐨勫悕绉颁繚鎸佷竴鑷�
+ * @param iconComponent 浠嶡iconify/icon-xxx/xxx瀵煎叆鐨勫浘鏍�
+ * @returns IconComponent
+ */
+function createIconifyOfflineIcon(icon: string, iconComponent: IconifyIcon) {
+  return defineComponent({
+    name: `Icon-${icon}`,
+    setup(props, { attrs }) {
+      addIcon(icon, iconComponent);
+      return () => h(Icon, { icon, ...props, ...attrs });
+    },
+  });
+}
+
+export { createIconifyIcon, createIconifyOfflineIcon };
diff --git a/eims-ui/packages/@core/base/icons/src/index.ts b/eims-ui/packages/@core/base/icons/src/index.ts
new file mode 100644
index 0000000..2e3f54f
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/src/index.ts
@@ -0,0 +1,16 @@
+export * from './create-icon';
+
+export * from './lucide';
+
+export type { IconifyIcon as IconifyIconStructure } from '@iconify/vue';
+export {
+  addCollection,
+  addIcon,
+  Icon as IconifyIcon,
+  listIcons,
+} from '@iconify/vue';
+
+/**
+ * 浠嶡iconify/vue/dist/offline'瀵煎嚭鐨勭粍浠朵负绂荤嚎ICON 涓嶆敮鎸佸湪绾�
+ * 浠嶡iconify/vue'瀵煎嚭鐨勭粍浠朵负鍦ㄨ兘鎵惧埌鏈湴鍥炬爣涓虹绾� 鍚﹀垯浼氬湪绾胯幏鍙�(閫傜敤鎬ф洿寮�)
+ */
diff --git a/eims-ui/packages/@core/base/icons/src/lucide.ts b/eims-ui/packages/@core/base/icons/src/lucide.ts
new file mode 100644
index 0000000..97603eb
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/src/lucide.ts
@@ -0,0 +1,59 @@
+export {
+  ArrowDown,
+  ArrowLeft,
+  ArrowLeftFromLine as MdiMenuOpen,
+  ArrowLeftToLine,
+  ArrowRightFromLine as MdiMenuClose,
+  ArrowRightLeft,
+  ArrowRightToLine,
+  ArrowUp,
+  ArrowUpToLine,
+  Bell,
+  BookOpenText,
+  Check,
+  ChevronDown,
+  ChevronLeft,
+  ChevronRight,
+  ChevronsLeft,
+  ChevronsRight,
+  CircleHelp,
+  Copy,
+  CornerDownLeft,
+  Ellipsis,
+  Expand,
+  ExternalLink,
+  Eye,
+  EyeOff,
+  FoldHorizontal,
+  Fullscreen,
+  Github,
+  Grip,
+  Info,
+  InspectionPanel,
+  Languages,
+  LoaderCircle,
+  LockKeyhole,
+  LogOut,
+  MailCheck,
+  Maximize,
+  Menu as IconDefault,
+  Menu,
+  Minimize,
+  Minimize2,
+  MoonStar,
+  Palette,
+  PanelLeft,
+  PanelRight,
+  Pin,
+  PinOff,
+  RotateCw,
+  Search,
+  SearchX,
+  Settings,
+  Shrink,
+  Sun,
+  SunMoon,
+  SwatchBook,
+  UserRoundPen,
+  X,
+} from 'lucide-vue-next';
diff --git a/eims-ui/packages/@core/base/icons/tsconfig.json b/eims-ui/packages/@core/base/icons/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/base/icons/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/base/shared/build.config.ts b/eims-ui/packages/@core/base/shared/build.config.ts
new file mode 100644
index 0000000..98e2209
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/build.config.ts
@@ -0,0 +1,14 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    'src/store',
+    'src/constants/index',
+    'src/utils/index',
+    'src/color/index',
+    'src/cache/index',
+    'src/global-state',
+  ],
+});
diff --git a/eims-ui/packages/@core/base/shared/package.json b/eims-ui/packages/@core/base/shared/package.json
new file mode 100644
index 0000000..17fa08c
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/package.json
@@ -0,0 +1,101 @@
+{
+  "name": "@vben-core/shared",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/base/shared"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": false,
+  "exports": {
+    "./constants": {
+      "types": "./src/constants/index.ts",
+      "development": "./src/constants/index.ts",
+      "default": "./dist/constants/index.mjs"
+    },
+    "./utils": {
+      "types": "./src/utils/index.ts",
+      "development": "./src/utils/index.ts",
+      "default": "./dist/utils/index.mjs"
+    },
+    "./color": {
+      "types": "./src/color/index.ts",
+      "development": "./src/color/index.ts",
+      "default": "./dist/color/index.mjs"
+    },
+    "./cache": {
+      "types": "./src/cache/index.ts",
+      "development": "./src/cache/index.ts",
+      "default": "./dist/cache/index.mjs"
+    },
+    "./store": {
+      "types": "./src/store.ts",
+      "development": "./src/store.ts",
+      "default": "./dist/store.mjs"
+    },
+    "./global-state": {
+      "types": "./dist/global-state.d.ts",
+      "development": "./src/global-state.ts",
+      "default": "./dist/global-state.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      "./constants": {
+        "types": "./dist/constants/index.d.ts",
+        "default": "./dist/constants/index.mjs"
+      },
+      "./utils": {
+        "types": "./dist/utils/index.d.ts",
+        "default": "./dist/utils/index.mjs"
+      },
+      "./color": {
+        "types": "./dist/color/index.d.ts",
+        "default": "./dist/color/index.mjs"
+      },
+      "./cache": {
+        "types": "./dist/cache/index.d.ts",
+        "default": "./dist/cache/index.mjs"
+      },
+      "./store": {
+        "types": "./dist/store.d.ts",
+        "default": "./dist/store.mjs"
+      },
+      "./global-state": {
+        "types": "./dist/global-state.d.ts",
+        "default": "./dist/global-state.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@ctrl/tinycolor": "catalog:",
+    "@tanstack/vue-store": "catalog:",
+    "@vue/shared": "catalog:",
+    "clsx": "catalog:",
+    "dayjs": "catalog:",
+    "defu": "catalog:",
+    "lodash.clonedeep": "catalog:",
+    "lodash.get": "catalog:",
+    "lodash.isequal": "catalog:",
+    "nprogress": "catalog:",
+    "tailwind-merge": "catalog:",
+    "theme-colors": "catalog:"
+  },
+  "devDependencies": {
+    "@types/lodash.clonedeep": "catalog:",
+    "@types/lodash.get": "catalog:",
+    "@types/lodash.isequal": "catalog:",
+    "@types/nprogress": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts b/eims-ui/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts
new file mode 100644
index 0000000..a5abe5a
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts
@@ -0,0 +1,130 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { StorageManager } from '../storage-manager';
+
+describe('storageManager', () => {
+  let storageManager: StorageManager;
+
+  beforeEach(() => {
+    vi.useFakeTimers();
+    localStorage.clear();
+    storageManager = new StorageManager({
+      prefix: 'test_',
+    });
+  });
+
+  it('should set and get an item', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 30, name: 'John Doe' });
+  });
+
+  it('should return default value if item does not exist', () => {
+    const user = storageManager.getItem('nonexistent', {
+      age: 0,
+      name: 'Default User',
+    });
+    expect(user).toEqual({ age: 0, name: 'Default User' });
+  });
+
+  it('should remove an item', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    storageManager.removeItem('user');
+    const user = storageManager.getItem('user');
+    expect(user).toBeNull();
+  });
+
+  it('should clear all items with the prefix', () => {
+    storageManager.setItem('user1', { age: 30, name: 'John Doe' });
+    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });
+    storageManager.clear();
+    expect(storageManager.getItem('user1')).toBeNull();
+    expect(storageManager.getItem('user2')).toBeNull();
+  });
+
+  it('should clear expired items', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1绉掕繃鏈�
+    vi.advanceTimersByTime(1001); // 蹇繘鏃堕棿
+    storageManager.clearExpiredItems();
+    const user = storageManager.getItem('user');
+    expect(user).toBeNull();
+  });
+
+  it('should not clear non-expired items', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10绉掕繃鏈�
+    vi.advanceTimersByTime(5000); // 蹇繘鏃堕棿
+    storageManager.clearExpiredItems();
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 30, name: 'John Doe' });
+  });
+
+  it('should handle JSON parse errors gracefully', () => {
+    localStorage.setItem('test_user', '{ invalid JSON }');
+    const user = storageManager.getItem('user', {
+      age: 0,
+      name: 'Default User',
+    });
+    expect(user).toEqual({ age: 0, name: 'Default User' });
+  });
+  it('should return null for non-existent items without default value', () => {
+    const user = storageManager.getItem('nonexistent');
+    expect(user).toBeNull();
+  });
+
+  it('should overwrite existing items', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    storageManager.setItem('user', { age: 25, name: 'Jane Doe' });
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 25, name: 'Jane Doe' });
+  });
+
+  it('should handle items without expiry correctly', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    vi.advanceTimersByTime(5000);
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 30, name: 'John Doe' });
+  });
+
+  it('should remove expired items when accessed', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 1000); // 1绉掕繃鏈�
+    vi.advanceTimersByTime(1001); // 蹇繘鏃堕棿
+    const user = storageManager.getItem('user');
+    expect(user).toBeNull();
+  });
+
+  it('should not remove non-expired items when accessed', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' }, 10_000); // 10绉掕繃鏈�
+    vi.advanceTimersByTime(5000); // 蹇繘鏃堕棿
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 30, name: 'John Doe' });
+  });
+
+  it('should handle multiple items with different expiry times', () => {
+    storageManager.setItem('user1', { age: 30, name: 'John Doe' }, 1000); // 1绉掕繃鏈�
+    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' }, 2000); // 2绉掕繃鏈�
+    vi.advanceTimersByTime(1500); // 蹇繘鏃堕棿
+    storageManager.clearExpiredItems();
+    const user1 = storageManager.getItem('user1');
+    const user2 = storageManager.getItem('user2');
+    expect(user1).toBeNull();
+    expect(user2).toEqual({ age: 25, name: 'Jane Doe' });
+  });
+
+  it('should handle items with no expiry', () => {
+    storageManager.setItem('user', { age: 30, name: 'John Doe' });
+    vi.advanceTimersByTime(10_000); // 蹇繘鏃堕棿
+    storageManager.clearExpiredItems();
+    const user = storageManager.getItem('user');
+    expect(user).toEqual({ age: 30, name: 'John Doe' });
+  });
+
+  it('should clear all items correctly', () => {
+    storageManager.setItem('user1', { age: 30, name: 'John Doe' });
+    storageManager.setItem('user2', { age: 25, name: 'Jane Doe' });
+    storageManager.clear();
+    const user1 = storageManager.getItem('user1');
+    const user2 = storageManager.getItem('user2');
+    expect(user1).toBeNull();
+    expect(user2).toBeNull();
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/cache/index.ts b/eims-ui/packages/@core/base/shared/src/cache/index.ts
new file mode 100644
index 0000000..8c44d7f
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/cache/index.ts
@@ -0,0 +1 @@
+export * from './storage-manager';
diff --git a/eims-ui/packages/@core/base/shared/src/cache/storage-manager.ts b/eims-ui/packages/@core/base/shared/src/cache/storage-manager.ts
new file mode 100644
index 0000000..611cdb8
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/cache/storage-manager.ts
@@ -0,0 +1,118 @@
+type StorageType = 'localStorage' | 'sessionStorage';
+
+interface StorageManagerOptions {
+  prefix?: string;
+  storageType?: StorageType;
+}
+
+interface StorageItem<T> {
+  expiry?: number;
+  value: T;
+}
+
+class StorageManager {
+  private prefix: string;
+  private storage: Storage;
+
+  constructor({
+    prefix = '',
+    storageType = 'localStorage',
+  }: StorageManagerOptions = {}) {
+    this.prefix = prefix;
+    this.storage =
+      storageType === 'localStorage'
+        ? window.localStorage
+        : window.sessionStorage;
+  }
+
+  /**
+   * 鑾峰彇瀹屾暣鐨勫瓨鍌ㄩ敭
+   * @param key 鍘熷閿�
+   * @returns 甯﹀墠缂�鐨勫畬鏁撮敭
+   */
+  private getFullKey(key: string): string {
+    return `${this.prefix}-${key}`;
+  }
+
+  /**
+   * 娓呴櫎鎵�鏈夊甫鍓嶇紑鐨勫瓨鍌ㄩ」
+   */
+  clear(): void {
+    const keysToRemove: string[] = [];
+    for (let i = 0; i < this.storage.length; i++) {
+      const key = this.storage.key(i);
+      if (key && key.startsWith(this.prefix)) {
+        keysToRemove.push(key);
+      }
+    }
+    keysToRemove.forEach((key) => this.storage.removeItem(key));
+  }
+
+  /**
+   * 娓呴櫎鎵�鏈夎繃鏈熺殑瀛樺偍椤�
+   */
+  clearExpiredItems(): void {
+    for (let i = 0; i < this.storage.length; i++) {
+      const key = this.storage.key(i);
+      if (key && key.startsWith(this.prefix)) {
+        const shortKey = key.replace(this.prefix, '');
+        this.getItem(shortKey); // 璋冪敤 getItem 鏂规硶妫�鏌ュ苟绉婚櫎杩囨湡椤�
+      }
+    }
+  }
+
+  /**
+   * 鑾峰彇瀛樺偍椤�
+   * @param key 閿�
+   * @param defaultValue 褰撻」涓嶅瓨鍦ㄦ垨宸茶繃鏈熸椂杩斿洖鐨勯粯璁ゅ��
+   * @returns 鍊硷紝濡傛灉椤瑰凡杩囨湡鎴栬В鏋愰敊璇垯杩斿洖榛樿鍊�
+   */
+  getItem<T>(key: string, defaultValue: null | T = null): null | T {
+    const fullKey = this.getFullKey(key);
+    const itemStr = this.storage.getItem(fullKey);
+    if (!itemStr) {
+      return defaultValue;
+    }
+
+    try {
+      const item: StorageItem<T> = JSON.parse(itemStr);
+      if (item.expiry && Date.now() > item.expiry) {
+        this.storage.removeItem(fullKey);
+        return defaultValue;
+      }
+      return item.value;
+    } catch (error) {
+      console.error(`Error parsing item with key "${fullKey}":`, error);
+      this.storage.removeItem(fullKey); // 濡傛灉瑙f瀽澶辫触锛屽垹闄よ椤�
+      return defaultValue;
+    }
+  }
+
+  /**
+   * 绉婚櫎瀛樺偍椤�
+   * @param key 閿�
+   */
+  removeItem(key: string): void {
+    const fullKey = this.getFullKey(key);
+    this.storage.removeItem(fullKey);
+  }
+
+  /**
+   * 璁剧疆瀛樺偍椤�
+   * @param key 閿�
+   * @param value 鍊�
+   * @param ttl 瀛樻椿鏃堕棿锛堟绉掞級
+   */
+  setItem<T>(key: string, value: T, ttl?: number): void {
+    const fullKey = this.getFullKey(key);
+    const expiry = ttl ? Date.now() + ttl : undefined;
+    const item: StorageItem<T> = { expiry, value };
+    try {
+      this.storage.setItem(fullKey, JSON.stringify(item));
+    } catch (error) {
+      console.error(`Error setting item with key "${fullKey}":`, error);
+    }
+  }
+}
+
+export { StorageManager };
diff --git a/eims-ui/packages/@core/base/shared/src/cache/types.ts b/eims-ui/packages/@core/base/shared/src/cache/types.ts
new file mode 100644
index 0000000..d893920
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/cache/types.ts
@@ -0,0 +1,17 @@
+type StorageType = 'localStorage' | 'sessionStorage';
+
+interface StorageValue<T> {
+  data: T;
+  expiry: null | number;
+}
+
+interface IStorageCache {
+  clear(): void;
+  getItem<T>(key: string): null | T;
+  key(index: number): null | string;
+  length(): number;
+  removeItem(key: string): void;
+  setItem<T>(key: string, value: T, expiryInMinutes?: number): void;
+}
+
+export type { IStorageCache, StorageType, StorageValue };
diff --git a/eims-ui/packages/@core/base/shared/src/color/__tests__/convert.test.ts b/eims-ui/packages/@core/base/shared/src/color/__tests__/convert.test.ts
new file mode 100644
index 0000000..fc4256c
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/color/__tests__/convert.test.ts
@@ -0,0 +1,58 @@
+import { describe, expect, it } from 'vitest';
+
+import {
+  convertToHsl,
+  convertToHslCssVar,
+  convertToRgb,
+  isValidColor,
+} from '../convert';
+
+describe('color conversion functions', () => {
+  it('should correctly convert color to HSL format', () => {
+    const color = '#ff0000';
+    const expectedHsl = 'hsl(0 100% 50%)';
+    expect(convertToHsl(color)).toEqual(expectedHsl);
+  });
+
+  it('should correctly convert color with alpha to HSL format', () => {
+    const color = 'rgba(255, 0, 0, 0.5)';
+    const expectedHsl = 'hsl(0 100% 50%) 0.5';
+    expect(convertToHsl(color)).toEqual(expectedHsl);
+  });
+
+  it('should correctly convert color to HSL CSS variable format', () => {
+    const color = '#ff0000';
+    const expectedHsl = '0 100% 50%';
+    expect(convertToHslCssVar(color)).toEqual(expectedHsl);
+  });
+
+  it('should correctly convert color with alpha to HSL CSS variable format', () => {
+    const color = 'rgba(255, 0, 0, 0.5)';
+    const expectedHsl = '0 100% 50% / 0.5';
+    expect(convertToHslCssVar(color)).toEqual(expectedHsl);
+  });
+
+  it('should correctly convert color to RGB CSS variable format', () => {
+    const color = 'hsl(284, 100%, 50%)';
+    const expectedRgb = 'rgb(187, 0, 255)';
+    expect(convertToRgb(color)).toEqual(expectedRgb);
+  });
+
+  it('should correctly convert color with alpha to RGBA CSS variable format', () => {
+    const color = 'hsla(284, 100%, 50%, 0.92)';
+    const expectedRgba = 'rgba(187, 0, 255, 0.92)';
+    expect(convertToRgb(color)).toEqual(expectedRgba);
+  });
+});
+
+describe('isValidColor', () => {
+  it('isValidColor function', () => {
+    // 娴嬭瘯鏈夋晥棰滆壊
+    expect(isValidColor('blue')).toBe(true);
+    expect(isValidColor('#000000')).toBe(true);
+
+    // 娴嬭瘯鏃犳晥棰滆壊
+    expect(isValidColor('invalid color')).toBe(false);
+    expect(isValidColor()).toBe(false);
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/color/color.ts b/eims-ui/packages/@core/base/shared/src/color/color.ts
new file mode 100644
index 0000000..e3cefdb
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/color/color.ts
@@ -0,0 +1,9 @@
+import { TinyColor } from '@ctrl/tinycolor';
+
+export function isDarkColor(color: string) {
+  return new TinyColor(color).isDark();
+}
+
+export function isLightColor(color: string) {
+  return new TinyColor(color).isLight();
+}
diff --git a/eims-ui/packages/@core/base/shared/src/color/convert.ts b/eims-ui/packages/@core/base/shared/src/color/convert.ts
new file mode 100644
index 0000000..dd7dff2
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/color/convert.ts
@@ -0,0 +1,62 @@
+import { TinyColor } from '@ctrl/tinycolor';
+
+/**
+ * 灏嗛鑹茶浆鎹负HSL鏍煎紡銆�
+ *
+ * HSL鏄竴绉嶉鑹叉ā鍨嬶紝鍖呮嫭鑹茬浉(Hue)銆侀ケ鍜屽害(Saturation)鍜屼寒搴�(Lightness)涓変釜閮ㄥ垎銆�
+ *
+ * @param {string} color 杈撳叆鐨勯鑹层��
+ * @returns {string} HSL鏍煎紡鐨勯鑹插瓧绗︿覆銆�
+ */
+function convertToHsl(color: string): string {
+  const { a, h, l, s } = new TinyColor(color).toHsl();
+  const hsl = `hsl(${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%)`;
+  return a < 1 ? `${hsl} ${a}` : hsl;
+}
+
+/**
+ * 灏嗛鑹茶浆鎹负HSL CSS鍙橀噺銆�
+ *
+ * 杩欎釜鍑芥暟涓巆onvertToHsl鍑芥暟绫讳技锛屼絾鏄繑鍥炵殑瀛楃涓叉牸寮忕◢鏈変笉鍚岋紝
+ * 浠ヤ究鍙互浣滀负CSS鍙橀噺浣跨敤銆�
+ *
+ * @param {string} color 杈撳叆鐨勯鑹层��
+ * @returns {string} 鍙互浣滀负CSS鍙橀噺浣跨敤鐨凥SL鏍煎紡鐨勯鑹插瓧绗︿覆銆�
+ */
+function convertToHslCssVar(color: string): string {
+  const { a, h, l, s } = new TinyColor(color).toHsl();
+  const hsl = `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
+  return a < 1 ? `${hsl} / ${a}` : hsl;
+}
+
+/**
+ * 灏嗛鑹茶浆鎹负RGB棰滆壊瀛楃涓�
+ * TinyColor鏃犳硶澶勭悊hsl鍐呭寘鍚�'deg'銆�'grad'銆�'rad'鎴�'turn'鐨勫瓧绗︿覆
+ * 姣斿 hsl(231deg 98% 65%)灏嗚瑙f瀽涓簉gb(0, 0, 0)
+ * 杩欓噷鍦ㄨ浆鎹箣鍓嶅厛灏嗚繖浜涘崟浣嶅幓鎺�
+ * @param str 琛ㄧずHLS棰滆壊鍊肩殑瀛楃涓�
+ * @returns 濡傛灉棰滆壊鍊兼湁鏁堬紝鍒欒繑鍥炲搴旂殑RGB棰滆壊瀛楃涓诧紱濡傛灉鏃犳晥锛屽垯杩斿洖rgb(0, 0, 0)
+ */
+function convertToRgb(str: string): string {
+  return new TinyColor(str.replaceAll(/deg|grad|rad|turn/g, '')).toRgbString();
+}
+
+/**
+ * 妫�鏌ラ鑹叉槸鍚︽湁鏁�
+ * @param {string} color - 寰呮鏌ョ殑棰滆壊
+ * 濡傛灉棰滆壊鏈夋晥杩斿洖true锛屽惁鍒欒繑鍥瀎alse
+ */
+function isValidColor(color?: string) {
+  if (!color) {
+    return false;
+  }
+  return new TinyColor(color).isValid;
+}
+
+export {
+  convertToHsl,
+  convertToHslCssVar,
+  convertToRgb,
+  isValidColor,
+  TinyColor,
+};
diff --git a/eims-ui/packages/@core/base/shared/src/color/generator.ts b/eims-ui/packages/@core/base/shared/src/color/generator.ts
new file mode 100644
index 0000000..ac7bd8a
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/color/generator.ts
@@ -0,0 +1,45 @@
+import { getColors } from 'theme-colors';
+
+import { convertToHslCssVar, TinyColor } from './convert';
+
+interface ColorItem {
+  alias?: string;
+  color: string;
+  name: string;
+}
+
+function generatorColorVariables(colorItems: ColorItem[]) {
+  const colorVariables: Record<string, string> = {};
+
+  colorItems.forEach(({ alias, color, name }) => {
+    if (color) {
+      const colorsMap = getColors(new TinyColor(color).toHexString());
+
+      let mainColor = colorsMap['500'];
+
+      const colorKeys = Object.keys(colorsMap);
+
+      colorKeys.forEach((key) => {
+        const colorValue = colorsMap[key];
+
+        if (colorValue) {
+          const hslColor = convertToHslCssVar(colorValue);
+          colorVariables[`--${name}-${key}`] = hslColor;
+          if (alias) {
+            colorVariables[`--${alias}-${key}`] = hslColor;
+          }
+
+          if (key === '500') {
+            mainColor = hslColor;
+          }
+        }
+      });
+      if (alias && mainColor) {
+        colorVariables[`--${alias}`] = mainColor;
+      }
+    }
+  });
+  return colorVariables;
+}
+
+export { generatorColorVariables };
diff --git a/eims-ui/packages/@core/base/shared/src/color/index.ts b/eims-ui/packages/@core/base/shared/src/color/index.ts
new file mode 100644
index 0000000..9fade3d
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/color/index.ts
@@ -0,0 +1,3 @@
+export * from './color';
+export * from './convert';
+export * from './generator';
diff --git a/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts b/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts
new file mode 100644
index 0000000..e3d5740
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts
@@ -0,0 +1,17 @@
+export enum DictEnum {
+  SYS_COMMON_STATUS = 'sys_common_status',
+  SYS_DEVICE_TYPE = 'sys_device_type', // 璁惧绫诲瀷
+  SYS_EQU_STATUS = 'sys_equ_status', // 璁惧鐘舵��
+  SYS_GRANT_TYPE = 'sys_grant_type', // 鎺堟潈绫诲瀷
+  SYS_NORMAL_DISABLE = 'sys_normal_disable',
+  SYS_NOTICE_STATUS = 'sys_notice_status', // 閫氱煡鐘舵��
+  SYS_NOTICE_TYPE = 'sys_notice_type', // 閫氱煡绫诲瀷
+  SYS_OPER_TYPE = 'sys_oper_type', // 鎿嶄綔绫诲瀷
+  SYS_OSS_ACCESS_POLICY = 'oss_access_policy', // oss鏉冮檺妗剁被鍨�
+  SYS_SHOW_HIDE = 'sys_show_hide', // 鏄剧ず鐘舵��
+  SYS_USER_SEX = 'sys_user_sex', // 鎬у埆
+  SYS_YES_NO = 'sys_yes_no', // 鏄惁
+  WF_BUSINESS_STATUS = 'wf_business_status', // 涓氬姟鐘舵��
+
+  WF_FORM_TYPE = 'wf_form_type', // 琛ㄥ崟绫诲瀷
+}
diff --git a/eims-ui/packages/@core/base/shared/src/constants/globals.ts b/eims-ui/packages/@core/base/shared/src/constants/globals.ts
new file mode 100644
index 0000000..3c69957
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/constants/globals.ts
@@ -0,0 +1,16 @@
+/** layout content 缁勪欢鐨勯珮搴� */
+export const CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT = `--vben-content-height`;
+/** layout content 缁勪欢鐨勫搴� */
+export const CSS_VARIABLE_LAYOUT_CONTENT_WIDTH = `--vben-content-width`;
+/** layout header 缁勪欢鐨勯珮搴� */
+export const CSS_VARIABLE_LAYOUT_HEADER_HEIGHT = `--vben-header-height`;
+/** layout footer 缁勪欢鐨勯珮搴� */
+export const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--vben-footer-height`;
+
+/** 鍐呭鍖哄煙鐨勭粍浠禝D */
+export const ELEMENT_ID_MAIN_CONTENT = `__vben_main_content`;
+
+/**
+ * @zh_CN 榛樿鍛藉悕绌洪棿
+ */
+export const DEFAULT_NAMESPACE = 'vben';
diff --git a/eims-ui/packages/@core/base/shared/src/constants/index.ts b/eims-ui/packages/@core/base/shared/src/constants/index.ts
new file mode 100644
index 0000000..6e81808
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/constants/index.ts
@@ -0,0 +1,3 @@
+export * from './dict-enum';
+export * from './globals';
+export * from './vben';
diff --git a/eims-ui/packages/@core/base/shared/src/constants/vben.ts b/eims-ui/packages/@core/base/shared/src/constants/vben.ts
new file mode 100644
index 0000000..0f6cbbe
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/constants/vben.ts
@@ -0,0 +1,26 @@
+/**
+ * @zh_CN GITHUB 浠撳簱鍦板潃
+ */
+export const VBEN_GITHUB_URL = 'https://github.com/vbenjs/vue-vben-admin';
+
+/**
+ * @zh_CN 鏂囨。鍦板潃
+ */
+export const VBEN_DOC_URL = 'https://doc.vben.pro';
+
+/**
+ * @zh_CN Vben Logo
+ */
+export const VBEN_LOGO_URL =
+  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp';
+
+/**
+ * @zh_CN Vben Admin 棣栭〉鍦板潃
+ */
+export const VBEN_PREVIEW_URL = 'https://www.vben.pro';
+
+export const VBEN_ELE_PREVIEW_URL = 'https://ele.vben.pro';
+
+export const VBEN_NAIVE_PREVIEW_URL = 'https://naive.vben.pro';
+
+export const VBEN_ANT_PREVIEW_URL = 'https://ant.vben.pro';
diff --git a/eims-ui/packages/@core/base/shared/src/global-state.ts b/eims-ui/packages/@core/base/shared/src/global-state.ts
new file mode 100644
index 0000000..2d71356
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/global-state.ts
@@ -0,0 +1,45 @@
+/**
+ * 鍏ㄥ眬澶嶇敤鐨勫彉閲忋�佺粍浠躲�侀厤缃紝鍚勪釜妯″潡涔嬮棿鍏变韩
+ * 閫氳繃鍗曚緥妯″紡瀹炵幇,鍗曚緥蹇呴』娉ㄦ剰涓嶅彈璇锋眰褰卞搷锛屼緥濡傜敤鎴蜂俊鎭繖浜涢渶瑕佹牴鎹姹傝幏鍙栫殑銆傚悗缁鏋滄湁ssr闇�姹傦紝涔熶笉浼氬奖鍝�
+ */
+
+interface ComponentsState {
+  [key: string]: any;
+}
+
+interface MessageState {
+  copyPreferencesSuccess?: (title: string, content?: string) => void;
+}
+
+export interface IGlobalSharedState {
+  components: ComponentsState;
+  message: MessageState;
+}
+
+class GlobalShareState {
+  #components: ComponentsState = {};
+  #message: MessageState = {};
+
+  /**
+   * 瀹氫箟妗嗘灦鍐呴儴鍚勪釜鍦烘櫙鐨勬秷鎭彁绀�
+   */
+  public defineMessage({ copyPreferencesSuccess }: MessageState) {
+    this.#message = {
+      copyPreferencesSuccess,
+    };
+  }
+
+  public getComponents(): ComponentsState {
+    return this.#components;
+  }
+
+  public getMessage(): MessageState {
+    return this.#message;
+  }
+
+  public setComponents(value: ComponentsState) {
+    this.#components = value;
+  }
+}
+
+export const globalShareState = new GlobalShareState();
diff --git a/eims-ui/packages/@core/base/shared/src/store.ts b/eims-ui/packages/@core/base/shared/src/store.ts
new file mode 100644
index 0000000..4b03afb
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/store.ts
@@ -0,0 +1 @@
+export * from '@tanstack/vue-store';
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/diff.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/diff.test.ts
new file mode 100644
index 0000000..cb3227b
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/diff.test.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it } from 'vitest';
+
+import { diff } from '../diff';
+
+describe('diff function', () => {
+  it('should return an empty object when comparing identical objects', () => {
+    const obj1 = { a: 1, b: { c: 2 } };
+    const obj2 = { a: 1, b: { c: 2 } };
+    expect(diff(obj1, obj2)).toEqual(undefined);
+  });
+
+  it('should detect simple changes in primitive values', () => {
+    const obj1 = { a: 1, b: 2 };
+    const obj2 = { a: 1, b: 3 };
+    expect(diff(obj1, obj2)).toEqual({ b: 3 });
+  });
+
+  it('should detect nested object changes', () => {
+    const obj1 = { a: 1, b: { c: 2, d: 4 } };
+    const obj2 = { a: 1, b: { c: 3, d: 4 } };
+    expect(diff(obj1, obj2)).toEqual({ b: { c: 3 } });
+  });
+
+  it('should handle array changes', () => {
+    const obj1 = { a: [1, 2, 3], b: 2 };
+    const obj2 = { a: [1, 2, 4], b: 2 };
+    expect(diff(obj1, obj2)).toEqual({ a: [1, 2, 4] });
+  });
+
+  it('should handle added keys', () => {
+    const obj1 = { a: 1 };
+    const obj2 = { a: 1, b: 2 };
+    expect(diff(obj1, obj2)).toEqual({ b: 2 });
+  });
+
+  it('should handle removed keys', () => {
+    const obj1 = { a: 1, b: 2 };
+    const obj2 = { a: 1 };
+    expect(diff(obj1, obj2)).toEqual(undefined);
+  });
+
+  it('should handle boolean value changes', () => {
+    const obj1 = { a: true, b: false };
+    const obj2 = { a: true, b: true };
+    expect(diff(obj1, obj2)).toEqual({ b: true });
+  });
+
+  it('should handle null and undefined values', () => {
+    const obj1 = { a: null, b: undefined };
+    const obj2: any = { a: 1, b: undefined };
+    expect(diff(obj1, obj2)).toEqual({ a: 1 });
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/dom.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/dom.test.ts
new file mode 100644
index 0000000..df51268
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/dom.test.ts
@@ -0,0 +1,127 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { getElementVisibleRect } from '../dom';
+
+describe('getElementVisibleRect', () => {
+  // 璁剧疆娴忚鍣ㄨ鍙e昂瀵哥殑 mock
+  beforeEach(() => {
+    vi.spyOn(document.documentElement, 'clientHeight', 'get').mockReturnValue(
+      800,
+    );
+    vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(800);
+    vi.spyOn(document.documentElement, 'clientWidth', 'get').mockReturnValue(
+      1000,
+    );
+    vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000);
+  });
+
+  it('should return default rect if element is undefined', () => {
+    expect(getElementVisibleRect()).toEqual({
+      bottom: 0,
+      height: 0,
+      left: 0,
+      right: 0,
+      top: 0,
+      width: 0,
+    });
+  });
+
+  it('should return default rect if element is null', () => {
+    expect(getElementVisibleRect(null)).toEqual({
+      bottom: 0,
+      height: 0,
+      left: 0,
+      right: 0,
+      top: 0,
+      width: 0,
+    });
+  });
+
+  it('should return correct visible rect when element is fully visible', () => {
+    const element = {
+      getBoundingClientRect: () => ({
+        bottom: 400,
+        height: 300,
+        left: 200,
+        right: 600,
+        top: 100,
+        width: 400,
+      }),
+    } as HTMLElement;
+
+    expect(getElementVisibleRect(element)).toEqual({
+      bottom: 400,
+      height: 300,
+      left: 200,
+      right: 600,
+      top: 100,
+      width: 400,
+    });
+  });
+
+  it('should return correct visible rect when element is partially off-screen at the top', () => {
+    const element = {
+      getBoundingClientRect: () => ({
+        bottom: 200,
+        height: 250,
+        left: 100,
+        right: 500,
+        top: -50,
+        width: 400,
+      }),
+    } as HTMLElement;
+
+    expect(getElementVisibleRect(element)).toEqual({
+      bottom: 200,
+      height: 200,
+      left: 100,
+      right: 500,
+      top: 0,
+      width: 400,
+    });
+  });
+
+  it('should return correct visible rect when element is partially off-screen at the right', () => {
+    const element = {
+      getBoundingClientRect: () => ({
+        bottom: 400,
+        height: 300,
+        left: 800,
+        right: 1200,
+        top: 100,
+        width: 400,
+      }),
+    } as HTMLElement;
+
+    expect(getElementVisibleRect(element)).toEqual({
+      bottom: 400,
+      height: 300,
+      left: 800,
+      right: 1000,
+      top: 100,
+      width: 200,
+    });
+  });
+
+  it('should return all zeros when element is completely off-screen', () => {
+    const element = {
+      getBoundingClientRect: () => ({
+        bottom: 1200,
+        height: 300,
+        left: 1100,
+        right: 1400,
+        top: 900,
+        width: 300,
+      }),
+    } as HTMLElement;
+
+    expect(getElementVisibleRect(element)).toEqual({
+      bottom: 800,
+      height: 0,
+      left: 1100,
+      right: 1000,
+      top: 900,
+      width: 0,
+    });
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/inference.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/inference.test.ts
new file mode 100644
index 0000000..7fda465
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/inference.test.ts
@@ -0,0 +1,183 @@
+import { describe, expect, it } from 'vitest';
+
+import {
+  getFirstNonNullOrUndefined,
+  isBoolean,
+  isEmpty,
+  isHttpUrl,
+  isObject,
+  isUndefined,
+  isWindow,
+} from '../inference';
+
+describe('isHttpUrl', () => {
+  it("should return true when given 'http://example.com'", () => {
+    expect(isHttpUrl('http://example.com')).toBe(true);
+  });
+
+  it("should return true when given 'https://example.com'", () => {
+    expect(isHttpUrl('https://example.com')).toBe(true);
+  });
+
+  it("should return false when given 'ftp://example.com'", () => {
+    expect(isHttpUrl('ftp://example.com')).toBe(false);
+  });
+
+  it("should return false when given 'example.com'", () => {
+    expect(isHttpUrl('example.com')).toBe(false);
+  });
+});
+
+describe('isUndefined', () => {
+  it('isUndefined should return true for undefined values', () => {
+    expect(isUndefined()).toBe(true);
+  });
+
+  it('isUndefined should return false for null values', () => {
+    expect(isUndefined(null)).toBe(false);
+  });
+
+  it('isUndefined should return false for defined values', () => {
+    expect(isUndefined(0)).toBe(false);
+    expect(isUndefined('')).toBe(false);
+    expect(isUndefined(false)).toBe(false);
+  });
+
+  it('isUndefined should return false for objects and arrays', () => {
+    expect(isUndefined({})).toBe(false);
+    expect(isUndefined([])).toBe(false);
+  });
+});
+
+describe('isEmpty', () => {
+  it('should return true for empty string', () => {
+    expect(isEmpty('')).toBe(true);
+  });
+
+  it('should return true for empty array', () => {
+    expect(isEmpty([])).toBe(true);
+  });
+
+  it('should return true for empty object', () => {
+    expect(isEmpty({})).toBe(true);
+  });
+
+  it('should return false for non-empty string', () => {
+    expect(isEmpty('hello')).toBe(false);
+  });
+
+  it('should return false for non-empty array', () => {
+    expect(isEmpty([1, 2, 3])).toBe(false);
+  });
+
+  it('should return false for non-empty object', () => {
+    expect(isEmpty({ a: 1 })).toBe(false);
+  });
+
+  it('should return true for null or undefined', () => {
+    expect(isEmpty(null)).toBe(true);
+    expect(isEmpty()).toBe(true);
+  });
+
+  it('should return false for number or boolean', () => {
+    expect(isEmpty(0)).toBe(false);
+    expect(isEmpty(true)).toBe(false);
+  });
+});
+
+describe('isWindow', () => {
+  it('should return true for the window object', () => {
+    expect(isWindow(window)).toBe(true);
+  });
+
+  it('should return false for other objects', () => {
+    expect(isWindow({})).toBe(false);
+    expect(isWindow([])).toBe(false);
+    expect(isWindow(null)).toBe(false);
+  });
+});
+
+describe('isBoolean', () => {
+  it('should return true for boolean values', () => {
+    expect(isBoolean(true)).toBe(true);
+    expect(isBoolean(false)).toBe(true);
+  });
+
+  it('should return false for non-boolean values', () => {
+    expect(isBoolean(null)).toBe(false);
+    expect(isBoolean(42)).toBe(false);
+    expect(isBoolean('string')).toBe(false);
+    expect(isBoolean({})).toBe(false);
+    expect(isBoolean([])).toBe(false);
+  });
+});
+
+describe('isObject', () => {
+  it('should return true for objects', () => {
+    expect(isObject({})).toBe(true);
+    expect(isObject({ a: 1 })).toBe(true);
+  });
+
+  it('should return false for non-objects', () => {
+    expect(isObject(null)).toBe(false);
+    expect(isObject(42)).toBe(false);
+    expect(isObject('string')).toBe(false);
+    expect(isObject(true)).toBe(false);
+    expect(isObject([1, 2, 3])).toBe(true);
+    expect(isObject(new Date())).toBe(true);
+    expect(isObject(/regex/)).toBe(true);
+  });
+});
+
+describe('getFirstNonNullOrUndefined', () => {
+  describe('getFirstNonNullOrUndefined', () => {
+    it('should return the first non-null and non-undefined value for a number array', () => {
+      expect(getFirstNonNullOrUndefined<number>(undefined, null, 0, 42)).toBe(
+        0,
+      );
+      expect(getFirstNonNullOrUndefined<number>(null, undefined, 42, 123)).toBe(
+        42,
+      );
+    });
+
+    it('should return the first non-null and non-undefined value for a string array', () => {
+      expect(
+        getFirstNonNullOrUndefined<string>(undefined, null, '', 'hello'),
+      ).toBe('');
+      expect(
+        getFirstNonNullOrUndefined<string>(null, undefined, 'test', 'world'),
+      ).toBe('test');
+    });
+
+    it('should return undefined if all values are null or undefined', () => {
+      expect(getFirstNonNullOrUndefined(undefined, null)).toBeUndefined();
+      expect(getFirstNonNullOrUndefined(null)).toBeUndefined();
+    });
+
+    it('should work with a single value', () => {
+      expect(getFirstNonNullOrUndefined(42)).toBe(42);
+      expect(getFirstNonNullOrUndefined()).toBeUndefined();
+      expect(getFirstNonNullOrUndefined(null)).toBeUndefined();
+    });
+
+    it('should handle mixed types correctly', () => {
+      expect(
+        getFirstNonNullOrUndefined<number | object | string>(
+          undefined,
+          null,
+          'test',
+          123,
+          { key: 'value' },
+        ),
+      ).toBe('test');
+      expect(
+        getFirstNonNullOrUndefined<number | object | string>(
+          null,
+          undefined,
+          [1, 2, 3],
+          'string',
+        ),
+      ).toEqual([1, 2, 3]);
+    });
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/letter.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/letter.test.ts
new file mode 100644
index 0000000..a4aebaf
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/letter.test.ts
@@ -0,0 +1,116 @@
+import { describe, expect, it } from 'vitest';
+
+import {
+  capitalizeFirstLetter,
+  kebabToCamelCase,
+  toCamelCase,
+  toLowerCaseFirstLetter,
+} from '../letter';
+
+describe('capitalizeFirstLetter', () => {
+  it('should capitalize the first letter of a string', () => {
+    expect(capitalizeFirstLetter('hello')).toBe('Hello');
+    expect(capitalizeFirstLetter('world')).toBe('World');
+  });
+
+  it('should handle empty strings', () => {
+    expect(capitalizeFirstLetter('')).toBe('');
+  });
+
+  it('should handle single character strings', () => {
+    expect(capitalizeFirstLetter('a')).toBe('A');
+    expect(capitalizeFirstLetter('b')).toBe('B');
+  });
+
+  it('should not change the case of other characters', () => {
+    expect(capitalizeFirstLetter('hElLo')).toBe('HElLo');
+  });
+});
+
+describe('toLowerCaseFirstLetter', () => {
+  it('should convert the first letter to lowercase', () => {
+    expect(toLowerCaseFirstLetter('CommonAppName')).toBe('commonAppName');
+    expect(toLowerCaseFirstLetter('AnotherKeyExample')).toBe(
+      'anotherKeyExample',
+    );
+  });
+
+  it('should return the same string if the first letter is already lowercase', () => {
+    expect(toLowerCaseFirstLetter('alreadyLowerCase')).toBe('alreadyLowerCase');
+  });
+
+  it('should handle empty strings', () => {
+    expect(toLowerCaseFirstLetter('')).toBe('');
+  });
+
+  it('should handle single character strings', () => {
+    expect(toLowerCaseFirstLetter('A')).toBe('a');
+    expect(toLowerCaseFirstLetter('a')).toBe('a');
+  });
+
+  it('should handle strings with only one uppercase letter', () => {
+    expect(toLowerCaseFirstLetter('A')).toBe('a');
+  });
+
+  it('should handle strings with special characters', () => {
+    expect(toLowerCaseFirstLetter('!Special')).toBe('!Special');
+    expect(toLowerCaseFirstLetter('123Number')).toBe('123Number');
+  });
+});
+
+describe('toCamelCase', () => {
+  it('should return the key if parentKey is empty', () => {
+    expect(toCamelCase('child', '')).toBe('child');
+  });
+
+  it('should combine parentKey and key in camel case', () => {
+    expect(toCamelCase('child', 'parent')).toBe('parentChild');
+  });
+
+  it('should handle empty key and parentKey', () => {
+    expect(toCamelCase('', '')).toBe('');
+  });
+
+  it('should handle key with capital letters', () => {
+    expect(toCamelCase('Child', 'parent')).toBe('parentChild');
+    expect(toCamelCase('Child', 'Parent')).toBe('ParentChild');
+  });
+});
+
+describe('kebabToCamelCase', () => {
+  it('should convert kebab-case to camelCase correctly', () => {
+    expect(kebabToCamelCase('my-component-name')).toBe('myComponentName');
+  });
+
+  it('should handle multiple consecutive hyphens', () => {
+    expect(kebabToCamelCase('my--component--name')).toBe('myComponentName');
+  });
+
+  it('should trim leading and trailing hyphens', () => {
+    expect(kebabToCamelCase('-my-component-name-')).toBe('myComponentName');
+  });
+
+  it('should preserve the case of the first word', () => {
+    expect(kebabToCamelCase('My-component-name')).toBe('MyComponentName');
+  });
+
+  it('should convert a single word correctly', () => {
+    expect(kebabToCamelCase('component')).toBe('component');
+  });
+
+  it('should return an empty string if input is empty', () => {
+    expect(kebabToCamelCase('')).toBe('');
+  });
+
+  it('should handle strings with no hyphens', () => {
+    expect(kebabToCamelCase('mycomponentname')).toBe('mycomponentname');
+  });
+
+  it('should handle strings with only hyphens', () => {
+    expect(kebabToCamelCase('---')).toBe('');
+  });
+
+  it('should handle mixed case inputs', () => {
+    expect(kebabToCamelCase('my-Component-Name')).toBe('myComponentName');
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts
new file mode 100644
index 0000000..d11be06
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts
@@ -0,0 +1,60 @@
+import { describe, expect, it } from 'vitest';
+
+import { StateHandler } from '../state-handler';
+
+describe('stateHandler', () => {
+  it('should resolve when condition is set to true', async () => {
+    const handler = new StateHandler();
+
+    // 妯℃嫙寮傛璁剧疆 condition 涓� true
+    setTimeout(() => {
+      handler.setConditionTrue(); // 鏄庣‘瑙﹀彂 condition 涓� true
+    }, 10);
+
+    // 绛夊緟鏉′欢琚缃负 true
+    await handler.waitForCondition();
+    expect(handler.isConditionTrue()).toBe(true);
+  });
+
+  it('should resolve immediately if condition is already true', async () => {
+    const handler = new StateHandler();
+    handler.setConditionTrue(); // 鎻愬墠璁剧疆涓� true
+
+    // 绔嬪嵆 resolve锛屽洜涓� condition 宸茬粡鏄� true
+    await handler.waitForCondition();
+    expect(handler.isConditionTrue()).toBe(true);
+  });
+
+  it('should reject when condition is set to false after waiting', async () => {
+    const handler = new StateHandler();
+
+    // 妯℃嫙寮傛璁剧疆 condition 涓� false
+    setTimeout(() => {
+      handler.setConditionFalse(); // 鏄庣‘瑙﹀彂 condition 涓� false
+    }, 10);
+
+    // 绛夊緟杩囩▼涓紝鏈熸湜 Promise 琚� reject
+    await expect(handler.waitForCondition()).rejects.toThrow();
+    expect(handler.isConditionTrue()).toBe(false);
+  });
+
+  it('should reset condition to false', () => {
+    const handler = new StateHandler();
+    handler.setConditionTrue(); // 璁剧疆涓� true
+    handler.reset(); // 閲嶇疆涓� false
+
+    expect(handler.isConditionTrue()).toBe(false);
+  });
+
+  it('should resolve when condition is set to true after reset', async () => {
+    const handler = new StateHandler();
+    handler.reset(); // 纭繚鍒濆涓� false
+
+    setTimeout(() => {
+      handler.setConditionTrue(); // 閲嶇疆鍚庤缃负 true
+    }, 10);
+
+    await handler.waitForCondition();
+    expect(handler.isConditionTrue()).toBe(true);
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/tree.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/tree.test.ts
new file mode 100644
index 0000000..afe43cc
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/tree.test.ts
@@ -0,0 +1,196 @@
+import { describe, expect, it } from 'vitest';
+
+import { filterTree, mapTree, traverseTreeValues } from '../tree';
+
+describe('traverseTreeValues', () => {
+  interface Node {
+    children?: Node[];
+    name: string;
+  }
+
+  type NodeValue = string;
+
+  const sampleTree: Node[] = [
+    {
+      name: 'A',
+      children: [
+        { name: 'B' },
+        {
+          name: 'C',
+          children: [{ name: 'D' }, { name: 'E' }],
+        },
+      ],
+    },
+    {
+      name: 'F',
+      children: [
+        { name: 'G' },
+        {
+          name: 'H',
+          children: [{ name: 'I' }],
+        },
+      ],
+    },
+  ];
+
+  it('traverses tree and returns all node values', () => {
+    const values = traverseTreeValues<Node, NodeValue>(
+      sampleTree,
+      (node) => node.name,
+      {
+        childProps: 'children',
+      },
+    );
+    expect(values).toEqual(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']);
+  });
+
+  it('handles empty tree', () => {
+    const values = traverseTreeValues<Node, NodeValue>([], (node) => node.name);
+    expect(values).toEqual([]);
+  });
+
+  it('handles tree with only root node', () => {
+    const rootNode = { name: 'A' };
+    const values = traverseTreeValues<Node, NodeValue>(
+      [rootNode],
+      (node) => node.name,
+    );
+    expect(values).toEqual(['A']);
+  });
+
+  it('handles tree with only leaf nodes', () => {
+    const leafNodes = [{ name: 'A' }, { name: 'B' }, { name: 'C' }];
+    const values = traverseTreeValues<Node, NodeValue>(
+      leafNodes,
+      (node) => node.name,
+    );
+    expect(values).toEqual(['A', 'B', 'C']);
+  });
+});
+
+describe('filterTree', () => {
+  const tree = [
+    {
+      id: 1,
+      children: [
+        { id: 2 },
+        { id: 3, children: [{ id: 4 }, { id: 5 }, { id: 6 }] },
+        { id: 7 },
+      ],
+    },
+    { id: 8, children: [{ id: 9 }, { id: 10 }] },
+    { id: 11 },
+  ];
+
+  it('should return all nodes when condition is always true', () => {
+    const result = filterTree(tree, () => true, { childProps: 'children' });
+    expect(result).toEqual(tree);
+  });
+
+  it('should return only root nodes when condition is always false', () => {
+    const result = filterTree(tree, () => false);
+    expect(result).toEqual([]);
+  });
+
+  it('should return nodes with even id values', () => {
+    const result = filterTree(tree, (node) => node.id % 2 === 0);
+    expect(result).toEqual([{ id: 8, children: [{ id: 10 }] }]);
+  });
+
+  it('should return nodes with odd id values and their ancestors', () => {
+    const result = filterTree(tree, (node) => node.id % 2 === 1);
+    expect(result).toEqual([
+      {
+        id: 1,
+        children: [{ id: 3, children: [{ id: 5 }] }, { id: 7 }],
+      },
+      { id: 11 },
+    ]);
+  });
+
+  it('should return nodes with "leaf" in their name', () => {
+    const tree = [
+      {
+        name: 'root',
+        children: [
+          { name: 'leaf 1' },
+          {
+            name: 'branch',
+            children: [{ name: 'leaf 2' }, { name: 'leaf 3' }],
+          },
+          { name: 'leaf 4' },
+        ],
+      },
+    ];
+    const result = filterTree(
+      tree,
+      (node) => node.name.includes('leaf') || node.name === 'root',
+    );
+    expect(result).toEqual([
+      {
+        name: 'root',
+        children: [{ name: 'leaf 1' }, { name: 'leaf 4' }],
+      },
+    ]);
+  });
+});
+
+describe('mapTree', () => {
+  it('map infinite depth tree using mapTree', () => {
+    const tree = [
+      {
+        id: 1,
+        name: 'node1',
+        children: [
+          { id: 2, name: 'node2' },
+          { id: 3, name: 'node3' },
+          {
+            id: 4,
+            name: 'node4',
+            children: [
+              {
+                id: 5,
+                name: 'node5',
+                children: [
+                  { id: 6, name: 'node6' },
+                  { id: 7, name: 'node7' },
+                ],
+              },
+              { id: 8, name: 'node8' },
+            ],
+          },
+        ],
+      },
+    ];
+    const newTree = mapTree(tree, (node) => ({
+      ...node,
+      name: `${node.name}-new`,
+    }));
+
+    expect(newTree).toEqual([
+      {
+        id: 1,
+        name: 'node1-new',
+        children: [
+          { id: 2, name: 'node2-new' },
+          { id: 3, name: 'node3-new' },
+          {
+            id: 4,
+            name: 'node4-new',
+            children: [
+              {
+                id: 5,
+                name: 'node5-new',
+                children: [
+                  { id: 6, name: 'node6-new' },
+                  { id: 7, name: 'node7-new' },
+                ],
+              },
+              { id: 8, name: 'node8-new' },
+            ],
+          },
+        ],
+      },
+    ]);
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/unique.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/unique.test.ts
new file mode 100644
index 0000000..0aa9d61
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/unique.test.ts
@@ -0,0 +1,60 @@
+import { describe, expect, it } from 'vitest';
+
+import { uniqueByField } from '../unique';
+
+describe('uniqueByField', () => {
+  it('should return an array with unique items based on id field', () => {
+    const items = [
+      { id: 1, name: 'Item 1' },
+      { id: 2, name: 'Item 2' },
+      { id: 3, name: 'Item 3' },
+      { id: 1, name: 'Duplicate Item' },
+    ];
+
+    const uniqueItems = uniqueByField(items, 'id');
+
+    expect(uniqueItems).toHaveLength(3);
+    expect(uniqueItems).toEqual([
+      { id: 1, name: 'Item 1' },
+      { id: 2, name: 'Item 2' },
+      { id: 3, name: 'Item 3' },
+    ]);
+  });
+
+  it('should return an empty array when input array is empty', () => {
+    const items: any[] = []; // Empty array
+
+    const uniqueItems = uniqueByField(items, 'id');
+
+    // Assert expected results
+    expect(uniqueItems).toEqual([]);
+  });
+
+  it('should handle arrays with only one item correctly', () => {
+    const items = [{ id: 1, name: 'Item 1' }];
+
+    const uniqueItems = uniqueByField(items, 'id');
+
+    // Assert expected results
+    expect(uniqueItems).toHaveLength(1);
+    expect(uniqueItems).toEqual([{ id: 1, name: 'Item 1' }]);
+  });
+
+  it('should preserve the order of the first occurrence of each item', () => {
+    const items = [
+      { id: 2, name: 'Item 2' },
+      { id: 1, name: 'Item 1' },
+      { id: 3, name: 'Item 3' },
+      { id: 1, name: 'Duplicate Item' },
+    ];
+
+    const uniqueItems = uniqueByField(items, 'id');
+
+    // Assert expected results (order of first occurrences preserved)
+    expect(uniqueItems).toEqual([
+      { id: 2, name: 'Item 2' },
+      { id: 1, name: 'Item 1' },
+      { id: 3, name: 'Item 3' },
+    ]);
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts
new file mode 100644
index 0000000..4a9cdad
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts
@@ -0,0 +1,30 @@
+import { expect, it } from 'vitest';
+
+import { updateCSSVariables } from '../update-css-variables';
+
+it('updateCSSVariables should update CSS variables in :root selector', () => {
+  // 妯℃嫙鍒濆鐨勫唴鑱旀牱寮忚〃鍐呭
+  const initialStyleContent = ':root { --primaryColor: red; }';
+  document.head.innerHTML = `<style id="custom-styles">${initialStyleContent}</style>`;
+
+  // 瑕佹洿鏂扮殑CSS鍙橀噺鍜屽畠浠殑鏂板��
+  const updatedVariables = {
+    fontSize: '16px',
+    primaryColor: 'blue',
+    secondaryColor: 'green',
+  };
+
+  // 璋冪敤鍑芥暟鏉ユ洿鏂癈SS鍙橀噺
+  updateCSSVariables(updatedVariables, 'custom-styles');
+
+  // 鑾峰彇鏇存柊鍚庣殑鏍峰紡鍐呭
+  const styleElement = document.querySelector('#custom-styles');
+  const updatedStyleContent = styleElement ? styleElement.textContent : '';
+
+  // 妫�鏌ユ洿鏂板悗鐨勬牱寮忓唴瀹规槸鍚﹀寘鍚纭殑鏇存柊鍊�
+  expect(
+    updatedStyleContent?.includes('primaryColor: blue;') &&
+      updatedStyleContent?.includes('secondaryColor: green;') &&
+      updatedStyleContent?.includes('fontSize: 16px;'),
+  ).toBe(true);
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/util.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/util.test.ts
new file mode 100644
index 0000000..0d87b31
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/util.test.ts
@@ -0,0 +1,156 @@
+import { describe, expect, it } from 'vitest';
+
+import { bindMethods, getNestedValue } from '../util';
+
+class TestClass {
+  public value: string;
+
+  constructor(value: string) {
+    this.value = value;
+    bindMethods(this); // 璋冪敤閫氱敤鏂规硶
+  }
+
+  getValue() {
+    return this.value;
+  }
+
+  setValue(newValue: string) {
+    this.value = newValue;
+  }
+}
+
+describe('bindMethods', () => {
+  it('should bind methods to the instance correctly', () => {
+    const instance = new TestClass('initial');
+
+    // 瑙f瀯鏂规硶
+    const { getValue } = instance;
+
+    // 妫�鏌� getValue 鏄惁鑳芥纭皟鐢紝骞朵笖 this 缁戝畾浜� instance
+    expect(getValue()).toBe('initial');
+  });
+
+  it('should bind multiple methods', () => {
+    const instance = new TestClass('initial');
+
+    const { getValue, setValue } = instance;
+
+    // 妫�鏌� getValue 鍜� setValue 鏂规硶鏄惁姝g‘缁戝畾浜� this
+    setValue('newValue');
+    expect(getValue()).toBe('newValue');
+  });
+
+  it('should not bind non-function properties', () => {
+    const instance = new TestClass('initial');
+
+    // 妫�鏌ユ櫘閫氬睘鎬ф槸鍚︿繚鎸佸師鏍�
+    expect(instance.value).toBe('initial');
+  });
+
+  it('should not bind constructor method', () => {
+    const instance = new TestClass('test');
+
+    // 妫�鏌� constructor 鏄惁娌℃湁琚粦瀹�
+    expect(instance.constructor.name).toBe('TestClass');
+  });
+
+  it('should not bind getter/setter properties', () => {
+    class TestWithGetterSetter {
+      private _value: string = 'test';
+
+      constructor() {
+        bindMethods(this);
+      }
+
+      get value() {
+        return this._value;
+      }
+
+      set value(newValue: string) {
+        this._value = newValue;
+      }
+    }
+
+    const instance = new TestWithGetterSetter();
+    const { value } = instance;
+
+    // Getter 鍜� setter 涓嶅簲琚粦瀹�
+    expect(value).toBe('test');
+  });
+});
+
+describe('getNestedValue', () => {
+  interface UserProfile {
+    age: number;
+    name: string;
+  }
+
+  interface UserSettings {
+    theme: string;
+  }
+
+  interface Data {
+    user: {
+      profile: UserProfile;
+      settings: UserSettings;
+    };
+  }
+
+  const data: Data = {
+    user: {
+      profile: {
+        age: 25,
+        name: 'Alice',
+      },
+      settings: {
+        theme: 'dark',
+      },
+    },
+  };
+
+  it('should get a nested value when the path is valid', () => {
+    const result = getNestedValue(data, 'user.profile.name');
+    expect(result).toBe('Alice');
+  });
+
+  it('should return undefined for non-existent property', () => {
+    const result = getNestedValue(data, 'user.profile.gender');
+    expect(result).toBeUndefined();
+  });
+
+  it('should return undefined when accessing a non-existent deep path', () => {
+    const result = getNestedValue(data, 'user.nonexistent.field');
+    expect(result).toBeUndefined();
+  });
+
+  it('should return undefined if a middle level is undefined', () => {
+    const result = getNestedValue({ user: undefined }, 'user.profile.name');
+    expect(result).toBeUndefined();
+  });
+
+  it('should return the correct value for a nested setting', () => {
+    const result = getNestedValue(data, 'user.settings.theme');
+    expect(result).toBe('dark');
+  });
+
+  it('should work for a single-level path', () => {
+    const result = getNestedValue({ a: 1, b: 2 }, 'b');
+    expect(result).toBe(2);
+  });
+
+  it('should return the entire object if path is empty', () => {
+    expect(() => getNestedValue(data, '')()).toThrow();
+  });
+
+  it('should handle paths with array indexes', () => {
+    const complexData = { list: [{ name: 'Item1' }, { name: 'Item2' }] };
+    const result = getNestedValue(complexData, 'list.1.name');
+    expect(result).toBe('Item2');
+  });
+
+  it('should return undefined when accessing an out-of-bounds array index', () => {
+    const complexData = { list: [{ name: 'Item1' }] };
+    const result = getNestedValue(complexData, 'list.2.name');
+    expect(result).toBeUndefined();
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/__tests__/window.test.ts b/eims-ui/packages/@core/base/shared/src/utils/__tests__/window.test.ts
new file mode 100644
index 0000000..ebb04bb
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/__tests__/window.test.ts
@@ -0,0 +1,33 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { openWindow } from '../window';
+
+describe('openWindow', () => {
+  // 淇濆瓨鍘熷鐨� window.open 鍑芥暟
+  let originalOpen: typeof window.open;
+
+  beforeEach(() => {
+    originalOpen = window.open;
+  });
+
+  afterEach(() => {
+    window.open = originalOpen;
+  });
+
+  it('should call window.open with correct arguments', () => {
+    const url = 'https://example.com';
+    const options = { noopener: true, noreferrer: true, target: '_blank' };
+
+    window.open = vi.fn();
+
+    // 璋冪敤鍑芥暟
+    openWindow(url, options);
+
+    // 楠岃瘉 window.open 鏄惁琚纭湴璋冪敤
+    expect(window.open).toHaveBeenCalledWith(
+      url,
+      options.target,
+      'noopener=yes,noreferrer=yes',
+    );
+  });
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/cn.ts b/eims-ui/packages/@core/base/shared/src/utils/cn.ts
new file mode 100644
index 0000000..5503cc5
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/cn.ts
@@ -0,0 +1,8 @@
+import { type ClassValue, clsx } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(inputs));
+}
+
+export { cn };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/date.ts b/eims-ui/packages/@core/base/shared/src/utils/date.ts
new file mode 100644
index 0000000..3736b9a
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/date.ts
@@ -0,0 +1,26 @@
+import dayjs from 'dayjs';
+
+export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
+  try {
+    const date = dayjs(time);
+    if (!date.isValid()) {
+      throw new Error('Invalid date');
+    }
+    return date.format(format);
+  } catch (error) {
+    console.error(`Error formatting date: ${error}`);
+    return time;
+  }
+}
+
+export function formatDateTime(time: number | string) {
+  return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
+}
+
+export function isDate(value: any): value is Date {
+  return value instanceof Date;
+}
+
+export function isDayjsObject(value: any): value is dayjs.Dayjs {
+  return dayjs.isDayjs(value);
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/diff.ts b/eims-ui/packages/@core/base/shared/src/utils/diff.ts
new file mode 100644
index 0000000..449214d
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/diff.ts
@@ -0,0 +1,96 @@
+// type Diff<T = any> = T;
+
+// 姣旇緝涓や釜鏁扮粍鏄惁鐩哥瓑
+
+function arraysEqual<T>(a: T[], b: T[]): boolean {
+  if (a.length !== b.length) return false;
+  const counter = new Map<T, number>();
+  for (const value of a) {
+    counter.set(value, (counter.get(value) || 0) + 1);
+  }
+  for (const value of b) {
+    const count = counter.get(value);
+    if (count === undefined || count === 0) {
+      return false;
+    }
+    counter.set(value, count - 1);
+  }
+  return true;
+}
+
+// 娣卞害瀵规瘮涓や釜鍊�
+// function deepEqual<T>(oldVal: T, newVal: T): boolean {
+//   if (
+//     typeof oldVal === 'object' &&
+//     oldVal !== null &&
+//     typeof newVal === 'object' &&
+//     newVal !== null
+//   ) {
+//     return Array.isArray(oldVal) && Array.isArray(newVal)
+//       ? arraysEqual(oldVal, newVal)
+//       : diff(oldVal as any, newVal as any) === null;
+//   } else {
+//     return oldVal === newVal;
+//   }
+// }
+
+// // diff 鍑芥暟
+// function diff<T extends object>(
+//   oldObj: T,
+//   newObj: T,
+//   ignoreFields: (keyof T)[] = [],
+// ): { [K in keyof T]?: Diff<T[K]> } | null {
+//   const difference: { [K in keyof T]?: Diff<T[K]> } = {};
+
+//   for (const key in oldObj) {
+//     if (ignoreFields.includes(key)) continue;
+//     const oldValue = oldObj[key];
+//     const newValue = newObj[key];
+
+//     if (!deepEqual(oldValue, newValue)) {
+//       difference[key] = newValue;
+//     }
+//   }
+
+//   return Object.keys(difference).length === 0 ? null : difference;
+// }
+
+type DiffResult<T> = Partial<{
+  [K in keyof T]: T[K] extends object ? DiffResult<T[K]> : T[K];
+}>;
+
+function diff<T extends Record<string, any>>(obj1: T, obj2: T): DiffResult<T> {
+  function findDifferences(o1: any, o2: any): any {
+    if (Array.isArray(o1) && Array.isArray(o2)) {
+      if (!arraysEqual(o1, o2)) {
+        return o2;
+      }
+      return undefined;
+    }
+
+    if (
+      typeof o1 === 'object' &&
+      typeof o2 === 'object' &&
+      o1 !== null &&
+      o2 !== null
+    ) {
+      const diffResult: any = {};
+
+      const keys = new Set([...Object.keys(o1), ...Object.keys(o2)]);
+      keys.forEach((key) => {
+        const valueDiff = findDifferences(o1[key], o2[key]);
+        if (valueDiff !== undefined) {
+          diffResult[key] = valueDiff;
+        }
+      });
+
+      return Object.keys(diffResult).length > 0 ? diffResult : undefined;
+    }
+
+    return o1 === o2 ? undefined : o2;
+  }
+
+  return findDifferences(obj1, obj2);
+}
+
+export { arraysEqual, diff };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/dom.ts b/eims-ui/packages/@core/base/shared/src/utils/dom.ts
new file mode 100644
index 0000000..6961717
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/dom.ts
@@ -0,0 +1,95 @@
+export interface VisibleDomRect {
+  bottom: number;
+  height: number;
+  left: number;
+  right: number;
+  top: number;
+  width: number;
+}
+
+/**
+ * 鑾峰彇鍏冪礌鍙淇℃伅
+ * @param element
+ */
+export function getElementVisibleRect(
+  element?: HTMLElement | null | undefined,
+): VisibleDomRect {
+  if (!element) {
+    return {
+      bottom: 0,
+      height: 0,
+      left: 0,
+      right: 0,
+      top: 0,
+      width: 0,
+    };
+  }
+  const rect = element.getBoundingClientRect();
+  const viewHeight = Math.max(
+    document.documentElement.clientHeight,
+    window.innerHeight,
+  );
+
+  const top = Math.max(rect.top, 0);
+  const bottom = Math.min(rect.bottom, viewHeight);
+
+  const viewWidth = Math.max(
+    document.documentElement.clientWidth,
+    window.innerWidth,
+  );
+
+  const left = Math.max(rect.left, 0);
+  const right = Math.min(rect.right, viewWidth);
+
+  return {
+    bottom,
+    height: Math.max(0, bottom - top),
+    left,
+    right,
+    top,
+    width: Math.max(0, right - left),
+  };
+}
+
+export function getScrollbarWidth() {
+  const scrollDiv = document.createElement('div');
+
+  scrollDiv.style.visibility = 'hidden';
+  scrollDiv.style.overflow = 'scroll';
+  scrollDiv.style.position = 'absolute';
+  scrollDiv.style.top = '-9999px';
+
+  document.body.append(scrollDiv);
+
+  const innerDiv = document.createElement('div');
+  scrollDiv.append(innerDiv);
+
+  const scrollbarWidth = scrollDiv.offsetWidth - innerDiv.offsetWidth;
+
+  scrollDiv.remove();
+  return scrollbarWidth;
+}
+
+export function needsScrollbar() {
+  const doc = document.documentElement;
+  const body = document.body;
+
+  // 妫�鏌� body 鐨� overflow-y 鏍峰紡
+  const overflowY = window.getComputedStyle(body).overflowY;
+
+  // 濡傛灉鏄庣‘璁剧疆浜嗛渶瑕佹粴鍔ㄦ潯鐨勬牱寮�
+  if (overflowY === 'scroll' || overflowY === 'auto') {
+    return doc.scrollHeight > window.innerHeight;
+  }
+
+  // 鍦ㄥ叾浠栨儏鍐典笅锛屾牴鎹� scrollHeight 鍜� innerHeight 姣旇緝鍒ゆ柇
+  return doc.scrollHeight > window.innerHeight;
+}
+
+export function triggerWindowResize(): void {
+  // 鍒涘缓涓�涓柊鐨� resize 浜嬩欢
+  const resizeEvent = new Event('resize');
+
+  // 瑙﹀彂 window 鐨� resize 浜嬩欢
+  window.dispatchEvent(resizeEvent);
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/download.ts b/eims-ui/packages/@core/base/shared/src/utils/download.ts
new file mode 100644
index 0000000..3e708d3
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/download.ts
@@ -0,0 +1,156 @@
+import { openWindow } from './window';
+
+interface DownloadOptions<T = string> {
+  fileName?: string;
+  source: T;
+  target?: string;
+}
+
+const DEFAULT_FILENAME = 'downloaded_file';
+
+/**
+ * 閫氳繃 URL 涓嬭浇鏂囦欢锛屾敮鎸佽法鍩�
+ * @throws {Error} - 褰撲笅杞藉け璐ユ椂鎶涘嚭閿欒
+ */
+export async function downloadFileFromUrl({
+  fileName,
+  source,
+  target = '_blank',
+}: DownloadOptions): Promise<void> {
+  if (!source || typeof source !== 'string') {
+    throw new Error('Invalid URL.');
+  }
+
+  const isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');
+  const isSafari = window.navigator.userAgent.toLowerCase().includes('safari');
+
+  if (/iP/.test(window.navigator.userAgent)) {
+    console.error('Your browser does not support download!');
+    return;
+  }
+
+  if (isChrome || isSafari) {
+    triggerDownload(source, resolveFileName(source, fileName));
+  }
+  if (!source.includes('?')) {
+    source += '?download';
+  }
+
+  openWindow(source, { target });
+}
+
+/**
+ * 閫氳繃 Base64 涓嬭浇鏂囦欢
+ */
+export function downloadFileFromBase64({ fileName, source }: DownloadOptions) {
+  if (!source || typeof source !== 'string') {
+    throw new Error('Invalid Base64 data.');
+  }
+
+  const resolvedFileName = fileName || DEFAULT_FILENAME;
+  triggerDownload(source, resolvedFileName);
+}
+
+/**
+ * 閫氳繃鍥剧墖 URL 涓嬭浇鍥剧墖鏂囦欢
+ */
+export async function downloadFileFromImageUrl({
+  fileName,
+  source,
+}: DownloadOptions) {
+  const base64 = await urlToBase64(source);
+  downloadFileFromBase64({ fileName, source: base64 });
+}
+
+/**
+ * 閫氳繃 Blob 涓嬭浇鏂囦欢
+ */
+export function downloadFileFromBlob({
+  fileName = DEFAULT_FILENAME,
+  source,
+}: DownloadOptions<Blob>): void {
+  if (!(source instanceof Blob)) {
+    throw new TypeError('Invalid Blob data.');
+  }
+
+  const url = URL.createObjectURL(source);
+  triggerDownload(url, fileName);
+}
+
+/**
+ * 涓嬭浇鏂囦欢锛屾敮鎸� Blob銆佸瓧绗︿覆鍜屽叾浠� BlobPart 绫诲瀷
+ */
+export function downloadFileFromBlobPart({
+  fileName = DEFAULT_FILENAME,
+  source,
+}: DownloadOptions<BlobPart>): void {
+  // 濡傛灉 data 涓嶆槸 Blob锛屽垯杞崲涓� Blob
+  const blob =
+    source instanceof Blob
+      ? source
+      : new Blob([source], { type: 'application/octet-stream' });
+
+  // 鍒涘缓瀵硅薄 URL 骞惰Е鍙戜笅杞�
+  const url = URL.createObjectURL(blob);
+  triggerDownload(url, fileName);
+}
+
+/**
+ * img url to base64
+ * @param url
+ */
+export function urlToBase64(url: string, mineType?: string): Promise<string> {
+  return new Promise((resolve, reject) => {
+    let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null;
+    const ctx = canvas?.getContext('2d');
+    const img = new Image();
+    img.crossOrigin = '';
+    img.addEventListener('load', () => {
+      if (!canvas || !ctx) {
+        return reject(new Error('Failed to create canvas.'));
+      }
+      canvas.height = img.height;
+      canvas.width = img.width;
+      ctx.drawImage(img, 0, 0);
+      const dataURL = canvas.toDataURL(mineType || 'image/png');
+      canvas = null;
+      resolve(dataURL);
+    });
+    img.src = url;
+  });
+}
+
+/**
+ * 閫氱敤涓嬭浇瑙﹀彂鍑芥暟
+ * @param href - 鏂囦欢涓嬭浇鐨� URL
+ * @param fileName - 涓嬭浇鏂囦欢鐨勫悕绉帮紝濡傛灉鏈彁渚涘垯鑷姩璇嗗埆
+ * @param revokeDelay - 娓呯悊 URL 鐨勫欢杩熸椂闂� (姣)
+ */
+export function triggerDownload(
+  href: string,
+  fileName: string | undefined,
+  revokeDelay: number = 100,
+): void {
+  const defaultFileName = 'downloaded_file';
+  const finalFileName = fileName || defaultFileName;
+
+  const link = document.createElement('a');
+  link.href = href;
+  link.download = finalFileName;
+  link.style.display = 'none';
+
+  if (link.download === undefined) {
+    link.setAttribute('target', '_blank');
+  }
+
+  document.body.append(link);
+  link.click();
+  link.remove();
+
+  // 娓呯悊涓存椂 URL 浠ラ噴鏀惧唴瀛�
+  setTimeout(() => URL.revokeObjectURL(href), revokeDelay);
+}
+
+function resolveFileName(url: string, fileName?: string): string {
+  return fileName || url.slice(url.lastIndexOf('/') + 1) || DEFAULT_FILENAME;
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/index.ts b/eims-ui/packages/@core/base/shared/src/utils/index.ts
new file mode 100644
index 0000000..1bf09c7
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/index.ts
@@ -0,0 +1,19 @@
+export * from './cn';
+export * from './date';
+export * from './diff';
+export * from './dom';
+export * from './download';
+export * from './inference';
+export * from './letter';
+export * from './merge';
+export * from './nprogress';
+export * from './state-handler';
+export * from './to';
+export * from './tree';
+export * from './unique';
+export * from './update-css-variables';
+export * from './util';
+export * from './window';
+export { default as cloneDeep } from 'lodash.clonedeep';
+export { default as get } from 'lodash.get';
+export { default as isEqual } from 'lodash.isequal';
diff --git a/eims-ui/packages/@core/base/shared/src/utils/inference.ts b/eims-ui/packages/@core/base/shared/src/utils/inference.ts
new file mode 100644
index 0000000..a9ace62
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/inference.ts
@@ -0,0 +1,164 @@
+import { isFunction, isObject, isString } from '@vue/shared';
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑鍊兼槸鍚︿负undefined銆�
+ *
+ * @param {unknown} value 瑕佹鏌ョ殑鍊笺��
+ * @returns {boolean} 濡傛灉鍊兼槸undefined锛岃繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isUndefined(value?: unknown): value is undefined {
+  return value === undefined;
+}
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑鍊兼槸鍚︿负boolean
+ * @param value
+ * @returns 濡傛灉鍊兼槸甯冨皵鍊硷紝杩斿洖true锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isBoolean(value: unknown): value is boolean {
+  return typeof value === 'boolean';
+}
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑鍊兼槸鍚︿负绌恒��
+ *
+ * 浠ヤ笅鎯呭喌灏嗚璁や负鏄┖锛�
+ * - 鍊间负null銆�
+ * - 鍊间负undefined銆�
+ * - 鍊间负涓�涓┖瀛楃涓层��
+ * - 鍊间负涓�涓暱搴︿负0鐨勬暟缁勩��
+ * - 鍊间负涓�涓病鏈夊厓绱犵殑Map鎴朣et銆�
+ * - 鍊间负涓�涓病鏈夊睘鎬х殑瀵硅薄銆�
+ *
+ * @param {T} value 瑕佹鏌ョ殑鍊笺��
+ * @returns {boolean} 濡傛灉鍊间负绌猴紝杩斿洖true锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isEmpty<T = unknown>(value?: T): value is T {
+  if (value === null || value === undefined) {
+    return true;
+  }
+
+  if (Array.isArray(value) || isString(value)) {
+    return value.length === 0;
+  }
+
+  if (value instanceof Map || value instanceof Set) {
+    return value.size === 0;
+  }
+
+  if (isObject(value)) {
+    return Object.keys(value).length === 0;
+  }
+
+  return false;
+}
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑瀛楃涓叉槸鍚︿负鏈夋晥鐨凥TTP鎴朒TTPS URL銆�
+ *
+ * @param {string} url 瑕佹鏌ョ殑瀛楃涓层��
+ * @return {boolean} 濡傛灉瀛楃涓叉槸鏈夋晥鐨凥TTP鎴朒TTPS URL锛岃繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isHttpUrl(url?: string): boolean {
+  if (!url) {
+    return false;
+  }
+  // 浣跨敤姝e垯琛ㄨ揪寮忔祴璇昒RL鏄惁浠ttp:// 鎴� https:// 寮�澶�
+  const httpRegex = /^https?:\/\/.*$/;
+  return httpRegex.test(url);
+}
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑鍊兼槸鍚︿负window瀵硅薄銆�
+ *
+ * @param {any} value 瑕佹鏌ョ殑鍊笺��
+ * @returns {boolean} 濡傛灉鍊兼槸window瀵硅薄锛岃繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isWindow(value: any): value is Window {
+  return (
+    typeof window !== 'undefined' && value !== null && value === value.window
+  );
+}
+
+/**
+ * 妫�鏌ュ綋鍓嶈繍琛岀幆澧冩槸鍚︿负Mac OS銆�
+ *
+ * 杩欎釜鍑芥暟閫氳繃妫�鏌avigator.userAgent瀛楃涓叉潵鍒ゆ柇褰撳墠杩愯鐜銆�
+ * 濡傛灉userAgent瀛楃涓蹭腑鍖呭惈"macintosh"鎴�"mac os x"锛堜笉鍖哄垎澶у皬鍐欙級锛屽垯璁や负褰撳墠鐜鏄疢ac OS銆�
+ *
+ * @returns {boolean} 濡傛灉褰撳墠鐜鏄疢ac OS锛岃繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isMacOs(): boolean {
+  const macRegex = /macintosh|mac os x/i;
+  return macRegex.test(navigator.userAgent);
+}
+
+/**
+ * 妫�鏌ュ綋鍓嶈繍琛岀幆澧冩槸鍚︿负Windows OS銆�
+ *
+ * 杩欎釜鍑芥暟閫氳繃妫�鏌avigator.userAgent瀛楃涓叉潵鍒ゆ柇褰撳墠杩愯鐜銆�
+ * 濡傛灉userAgent瀛楃涓蹭腑鍖呭惈"windows"鎴�"win32"锛堜笉鍖哄垎澶у皬鍐欙級锛屽垯璁や负褰撳墠鐜鏄疻indows OS銆�
+ *
+ * @returns {boolean} 濡傛灉褰撳墠鐜鏄疻indows OS锛岃繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse銆�
+ */
+function isWindowsOs(): boolean {
+  const windowsRegex = /windows|win32/i;
+  return windowsRegex.test(navigator.userAgent);
+}
+
+/**
+ * 妫�鏌ヤ紶鍏ョ殑鍊兼槸鍚︿负鏁板瓧
+ * @param value
+ */
+function isNumber(value: any): value is number {
+  return typeof value === 'number' && Number.isFinite(value);
+}
+
+/**
+ * Returns the first value in the provided list that is neither `null` nor `undefined`.
+ *
+ * This function iterates over the input values and returns the first one that is
+ * not strictly equal to `null` or `undefined`. If all values are either `null` or
+ * `undefined`, it returns `undefined`.
+ *
+ * @template T - The type of the input values.
+ * @param {...(T | null | undefined)[]} values - A list of values to evaluate.
+ * @returns {T | undefined} - The first value that is not `null` or `undefined`, or `undefined` if none are found.
+ *
+ * @example
+ * // Returns 42 because it is the first non-null, non-undefined value.
+ * getFirstNonNullOrUndefined(undefined, null, 42, 'hello'); // 42
+ *
+ * @example
+ * // Returns 'hello' because it is the first non-null, non-undefined value.
+ * getFirstNonNullOrUndefined(null, undefined, 'hello', 123); // 'hello'
+ *
+ * @example
+ * // Returns undefined because all values are either null or undefined.
+ * getFirstNonNullOrUndefined(undefined, null); // undefined
+ */
+function getFirstNonNullOrUndefined<T>(
+  ...values: (null | T | undefined)[]
+): T | undefined {
+  for (const value of values) {
+    if (value !== undefined && value !== null) {
+      return value;
+    }
+  }
+  return undefined;
+}
+
+export {
+  getFirstNonNullOrUndefined,
+  isBoolean,
+  isEmpty,
+  isFunction,
+  isHttpUrl,
+  isMacOs,
+  isNumber,
+  isObject,
+  isString,
+  isUndefined,
+  isWindow,
+  isWindowsOs,
+};
diff --git a/eims-ui/packages/@core/base/shared/src/utils/letter.ts b/eims-ui/packages/@core/base/shared/src/utils/letter.ts
new file mode 100644
index 0000000..65a1c22
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/letter.ts
@@ -0,0 +1,47 @@
+/**
+ * 灏嗗瓧绗︿覆鐨勯瀛楁瘝澶у啓
+ * @param string
+ */
+function capitalizeFirstLetter(string: string): string {
+  return string.charAt(0).toUpperCase() + string.slice(1);
+}
+
+/**
+ * 灏嗗瓧绗︿覆鐨勯瀛楁瘝杞崲涓哄皬鍐欍��
+ *
+ * @param str 瑕佽浆鎹㈢殑瀛楃涓�
+ * @returns 棣栧瓧姣嶅皬鍐欑殑瀛楃涓�
+ */
+function toLowerCaseFirstLetter(str: string): string {
+  if (!str) return str; // 濡傛灉瀛楃涓蹭负绌猴紝鐩存帴杩斿洖
+  return str.charAt(0).toLowerCase() + str.slice(1);
+}
+
+/**
+ *  鐢熸垚椹煎嘲鍛藉悕娉曠殑閿悕
+ * @param key
+ * @param parentKey
+ */
+function toCamelCase(key: string, parentKey: string): string {
+  if (!parentKey) {
+    return key;
+  }
+  return parentKey + key.charAt(0).toUpperCase() + key.slice(1);
+}
+
+function kebabToCamelCase(str: string): string {
+  return str
+    .split('-')
+    .filter(Boolean)
+    .map((word, index) =>
+      index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1),
+    )
+    .join('');
+}
+
+export {
+  capitalizeFirstLetter,
+  kebabToCamelCase,
+  toCamelCase,
+  toLowerCaseFirstLetter,
+};
diff --git a/eims-ui/packages/@core/base/shared/src/utils/merge.ts b/eims-ui/packages/@core/base/shared/src/utils/merge.ts
new file mode 100644
index 0000000..4bf79eb
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/merge.ts
@@ -0,0 +1,10 @@
+import { createDefu } from 'defu';
+
+export { createDefu as createMerge, defu as merge } from 'defu';
+
+export const mergeWithArrayOverride = createDefu((originObj, key, updates) => {
+  if (Array.isArray(originObj[key]) && Array.isArray(updates)) {
+    originObj[key] = updates;
+    return true;
+  }
+});
diff --git a/eims-ui/packages/@core/base/shared/src/utils/nprogress.ts b/eims-ui/packages/@core/base/shared/src/utils/nprogress.ts
new file mode 100644
index 0000000..8e8fe2e
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/nprogress.ts
@@ -0,0 +1,43 @@
+import type NProgress from 'nprogress';
+
+// 鍒涘缓涓�涓狽Progress瀹炰緥鐨勫彉閲忥紝鍒濆鍊间负null
+let nProgressInstance: null | typeof NProgress = null;
+
+/**
+ * 鍔ㄦ�佸姞杞絅Progress搴擄紝骞惰繘琛岄厤缃��
+ * 姝ゅ嚱鏁伴鍏堟鏌ユ槸鍚﹀凡缁忓姞杞借繃NProgress搴擄紝濡傛灉宸茬粡鍔犺浇杩囷紝鍒欑洿鎺ヨ繑鍥濶Progress瀹炰緥銆�
+ * 鍚﹀垯锛屽姩鎬佸鍏Progress搴擄紝杩涜閰嶇疆锛岀劧鍚庤繑鍥濶Progress瀹炰緥銆�
+ *
+ * @returns  NProgress瀹炰緥鐨凱romise瀵硅薄銆�
+ */
+async function loadNprogress() {
+  if (nProgressInstance) {
+    return nProgressInstance;
+  }
+  nProgressInstance = await import('nprogress');
+  nProgressInstance.configure({
+    showSpinner: true,
+    speed: 300,
+  });
+  return nProgressInstance;
+}
+
+/**
+ * 寮�濮嬫樉绀鸿繘搴︽潯銆�
+ * 姝ゅ嚱鏁伴鍏堝姞杞絅Progress搴擄紝鐒跺悗璋冪敤NProgress鐨剆tart鏂规硶寮�濮嬫樉绀鸿繘搴︽潯銆�
+ */
+async function startProgress() {
+  const nprogress = await loadNprogress();
+  nprogress?.start();
+}
+
+/**
+ * 鍋滄鏄剧ず杩涘害鏉★紝骞堕殣钘忚繘搴︽潯銆�
+ * 姝ゅ嚱鏁伴鍏堝姞杞絅Progress搴擄紝鐒跺悗璋冪敤NProgress鐨刣one鏂规硶鍋滄骞堕殣钘忚繘搴︽潯銆�
+ */
+async function stopProgress() {
+  const nprogress = await loadNprogress();
+  nprogress?.done();
+}
+
+export { startProgress, stopProgress };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/state-handler.ts b/eims-ui/packages/@core/base/shared/src/utils/state-handler.ts
new file mode 100644
index 0000000..cef1bd8
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/state-handler.ts
@@ -0,0 +1,50 @@
+export class StateHandler {
+  private condition: boolean = false;
+  private rejectCondition: (() => void) | null = null;
+  private resolveCondition: (() => void) | null = null;
+
+  // 娓呯悊 resolve/reject 鍑芥暟
+  private clearPromises() {
+    this.resolveCondition = null;
+    this.rejectCondition = null;
+  }
+
+  isConditionTrue(): boolean {
+    return this.condition;
+  }
+
+  reset() {
+    this.condition = false;
+    this.clearPromises();
+  }
+
+  // 瑙﹀彂鐘舵�佷负 false 鏃讹紝reject
+  setConditionFalse() {
+    this.condition = false;
+    if (this.rejectCondition) {
+      this.rejectCondition();
+      this.clearPromises();
+    }
+  }
+
+  // 瑙﹀彂鐘舵�佷负 true 鏃讹紝resolve
+  setConditionTrue() {
+    this.condition = true;
+    if (this.resolveCondition) {
+      this.resolveCondition();
+      this.clearPromises();
+    }
+  }
+
+  // 杩斿洖涓�涓� Promise锛岀瓑寰� condition 鍙樹负 true
+  waitForCondition(): Promise<void> {
+    return new Promise((resolve, reject) => {
+      if (this.condition) {
+        resolve(); // 濡傛灉 condition 宸茬粡涓� true锛岀珛鍗� resolve
+      } else {
+        this.resolveCondition = resolve;
+        this.rejectCondition = reject;
+      }
+    });
+  }
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/to.ts b/eims-ui/packages/@core/base/shared/src/utils/to.ts
new file mode 100644
index 0000000..6f25405
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/to.ts
@@ -0,0 +1,21 @@
+/**
+ * @param { Readonly<Promise> } promise
+ * @param {object=} errorExt - Additional Information you can pass to the err object
+ * @return { Promise }
+ */
+export async function to<T, U = Error>(
+  promise: Readonly<Promise<T>>,
+  errorExt?: object,
+): Promise<[null, T] | [U, undefined]> {
+  try {
+    const data = await promise;
+    const result: [null, T] = [null, data];
+    return result;
+  } catch (error) {
+    if (errorExt) {
+      const parsedError = Object.assign({}, error, errorExt);
+      return [parsedError as U, undefined];
+    }
+    return [error as U, undefined];
+  }
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/tree.ts b/eims-ui/packages/@core/base/shared/src/utils/tree.ts
new file mode 100644
index 0000000..09a9481
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/tree.ts
@@ -0,0 +1,97 @@
+interface TreeConfigOptions {
+  // 瀛愬睘鎬х殑鍚嶇О锛岄粯璁や负'children'
+  childProps: string;
+}
+
+/**
+ * @zh_CN 閬嶅巻鏍戝舰缁撴瀯锛屽苟杩斿洖鎵�鏈夎妭鐐逛腑鎸囧畾鐨勫�笺��
+ * @param tree 鏍戝舰缁撴瀯鏁扮粍
+ * @param getValue 鑾峰彇鑺傜偣鍊肩殑鍑芥暟
+ * @param options 浣滀负瀛愯妭鐐规暟缁勭殑鍙�夊睘鎬у悕绉般��
+ * @returns 鎵�鏈夎妭鐐逛腑鎸囧畾鐨勫�肩殑鏁扮粍
+ */
+function traverseTreeValues<T, V>(
+  tree: T[],
+  getValue: (node: T) => V,
+  options?: TreeConfigOptions,
+): V[] {
+  const result: V[] = [];
+  const { childProps } = options || {
+    childProps: 'children',
+  };
+
+  const dfs = (treeNode: T) => {
+    const value = getValue(treeNode);
+    result.push(value);
+    const children = (treeNode as Record<string, any>)?.[childProps];
+    if (!children) {
+      return;
+    }
+    if (children.length > 0) {
+      for (const child of children) {
+        dfs(child);
+      }
+    }
+  };
+
+  for (const treeNode of tree) {
+    dfs(treeNode);
+  }
+  return result.filter(Boolean);
+}
+
+/**
+ * 鏍规嵁鏉′欢杩囨护缁欏畾鏍戠粨鏋勭殑鑺傜偣锛屽苟浠ュ師鏈夐『搴忚繑鍥炴墍鏈夊尮閰嶈妭鐐圭殑鏁扮粍銆�
+ * @param tree 瑕佽繃婊ょ殑鏍戠粨鏋勭殑鏍硅妭鐐规暟缁勩��
+ * @param filter 鐢ㄤ簬鍖归厤姣忎釜鑺傜偣鐨勬潯浠躲��
+ * @param options 浣滀负瀛愯妭鐐规暟缁勭殑鍙�夊睘鎬у悕绉般��
+ * @returns 鍖呭惈鎵�鏈夊尮閰嶈妭鐐圭殑鏁扮粍銆�
+ */
+function filterTree<T extends Record<string, any>>(
+  tree: T[],
+  filter: (node: T) => boolean,
+  options?: TreeConfigOptions,
+): T[] {
+  const { childProps } = options || {
+    childProps: 'children',
+  };
+
+  const _filterTree = (nodes: T[]): T[] => {
+    return nodes.filter((node: Record<string, any>) => {
+      if (filter(node as T)) {
+        if (node[childProps]) {
+          node[childProps] = _filterTree(node[childProps]);
+        }
+        return true;
+      }
+      return false;
+    });
+  };
+
+  return _filterTree(tree);
+}
+
+/**
+ * 鏍规嵁鏉′欢閲嶆柊鏄犲皠缁欏畾鏍戠粨鏋勭殑鑺�
+ * @param tree 瑕佽繃婊ょ殑鏍戠粨鏋勭殑鏍硅妭鐐规暟缁勩��
+ * @param mapper 鐢ㄤ簬map姣忎釜鑺傜偣鐨勬潯浠躲��
+ * @param options 浣滀负瀛愯妭鐐规暟缁勭殑鍙�夊睘鎬у悕绉般��
+ */
+function mapTree<T, V extends Record<string, any>>(
+  tree: T[],
+  mapper: (node: T) => V,
+  options?: TreeConfigOptions,
+): V[] {
+  const { childProps } = options || {
+    childProps: 'children',
+  };
+  return tree.map((node) => {
+    const mapperNode: Record<string, any> = mapper(node);
+    if (mapperNode[childProps]) {
+      mapperNode[childProps] = mapTree(mapperNode[childProps], mapper, options);
+    }
+    return mapperNode as V;
+  });
+}
+
+export { filterTree, mapTree, traverseTreeValues };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/unique.ts b/eims-ui/packages/@core/base/shared/src/utils/unique.ts
new file mode 100644
index 0000000..e81f972
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/unique.ts
@@ -0,0 +1,15 @@
+/**
+ * 鏍规嵁鎸囧畾瀛楁瀵瑰璞℃暟缁勮繘琛屽幓閲�
+ * @param arr 瑕佸幓閲嶇殑瀵硅薄鏁扮粍
+ * @param key 鍘婚噸渚濇嵁鐨勫瓧娈靛悕
+ * @returns 鍘婚噸鍚庣殑瀵硅薄鏁扮粍
+ */
+function uniqueByField<T>(arr: T[], key: keyof T): T[] {
+  const seen = new Map<any, T>();
+  return arr.filter((item) => {
+    const value = item[key];
+    return seen.has(value) ? false : (seen.set(value, item), true);
+  });
+}
+
+export { uniqueByField };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/update-css-variables.ts b/eims-ui/packages/@core/base/shared/src/utils/update-css-variables.ts
new file mode 100644
index 0000000..657deaa
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/update-css-variables.ts
@@ -0,0 +1,35 @@
+/**
+ * 鏇存柊 CSS 鍙橀噺鐨勫嚱鏁�
+ * @param variables 瑕佹洿鏂扮殑 CSS 鍙橀噺涓庡叾鏂板�肩殑鏄犲皠
+ */
+function updateCSSVariables(
+  variables: { [key: string]: string },
+  id = '__vben-styles__',
+): void {
+  // 鑾峰彇鎴栧垱寤哄唴鑱旀牱寮忚〃鍏冪礌
+  const styleElement =
+    document.querySelector(`#${id}`) || document.createElement('style');
+
+  styleElement.id = id;
+
+  // 鏋勫缓瑕佹洿鏂扮殑 CSS 鍙橀噺鐨勬牱寮忔枃鏈�
+  let cssText = ':root {';
+  for (const key in variables) {
+    if (Object.prototype.hasOwnProperty.call(variables, key)) {
+      cssText += `${key}: ${variables[key]};`;
+    }
+  }
+  cssText += '}';
+
+  // 灏嗘牱寮忔枃鏈祴鍊肩粰鍐呰仈鏍峰紡琛�
+  styleElement.textContent = cssText;
+
+  // 灏嗗唴鑱旀牱寮忚〃娣诲姞鍒版枃妗eご閮�
+  if (!document.querySelector(`#${id}`)) {
+    setTimeout(() => {
+      document.head.append(styleElement);
+    });
+  }
+}
+
+export { updateCSSVariables };
diff --git a/eims-ui/packages/@core/base/shared/src/utils/util.ts b/eims-ui/packages/@core/base/shared/src/utils/util.ts
new file mode 100644
index 0000000..885eeaa
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/util.ts
@@ -0,0 +1,44 @@
+export function bindMethods<T extends object>(instance: T): void {
+  const prototype = Object.getPrototypeOf(instance);
+  const propertyNames = Object.getOwnPropertyNames(prototype);
+
+  propertyNames.forEach((propertyName) => {
+    const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
+    const propertyValue = instance[propertyName as keyof T];
+
+    if (
+      typeof propertyValue === 'function' &&
+      propertyName !== 'constructor' &&
+      descriptor &&
+      !descriptor.get &&
+      !descriptor.set
+    ) {
+      instance[propertyName as keyof T] = propertyValue.bind(instance);
+    }
+  });
+}
+
+/**
+ * 鑾峰彇宓屽瀵硅薄鐨勫瓧娈靛��
+ * @param obj - 瑕佹煡鎵剧殑瀵硅薄
+ * @param path - 鐢ㄤ簬鏌ユ壘瀛楁鐨勮矾寰勶紝浣跨敤灏忔暟鐐瑰垎闅�
+ * @returns 瀛楁鍊硷紝鎴栬�呮湭鎵惧埌鏃惰繑鍥� undefined
+ */
+export function getNestedValue<T>(obj: T, path: string): any {
+  if (typeof path !== 'string' || path.length === 0) {
+    throw new Error('Path must be a non-empty string');
+  }
+  // 鎶婅矾寰勫瓧绗︿覆鎸� "." 鍒嗗壊鎴愭暟缁�
+  const keys = path.split('.') as (number | string)[];
+
+  let current: any = obj;
+
+  for (const key of keys) {
+    if (current === null || current === undefined) {
+      return undefined;
+    }
+    current = current[key as keyof typeof current];
+  }
+
+  return current;
+}
diff --git a/eims-ui/packages/@core/base/shared/src/utils/window.ts b/eims-ui/packages/@core/base/shared/src/utils/window.ts
new file mode 100644
index 0000000..4608f4b
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/src/utils/window.ts
@@ -0,0 +1,37 @@
+interface OpenWindowOptions {
+  noopener?: boolean;
+  noreferrer?: boolean;
+  target?: '_blank' | '_parent' | '_self' | '_top' | string;
+}
+
+/**
+ * 鏂扮獥鍙f墦寮�URL銆�
+ *
+ * @param url - 闇�瑕佹墦寮�鐨勭綉鍧�銆�
+ * @param options - 鎵撳紑绐楀彛鐨勯�夐」銆�
+ */
+function openWindow(url: string, options: OpenWindowOptions = {}): void {
+  // 瑙f瀯骞惰缃粯璁ゅ��
+  const { noopener = true, noreferrer = true, target = '_blank' } = options;
+
+  // 鍩轰簬閫夐」鍒涘缓鐗规�у瓧绗︿覆
+  const features = [noopener && 'noopener=yes', noreferrer && 'noreferrer=yes']
+    .filter(Boolean)
+    .join(',');
+
+  // 鎵撳紑绐楀彛
+  window.open(url, target, features);
+}
+
+/**
+ * 鍦ㄦ柊绐楀彛涓墦寮�璺敱銆�
+ * @param path
+ */
+function openRouteInNewWindow(path: string) {
+  const { hash, origin } = location;
+  const fullPath = path.startsWith('/') ? path : `/${path}`;
+  const url = `${origin}${hash ? '/#' : ''}${fullPath}`;
+  openWindow(url, { target: '_blank' });
+}
+
+export { openRouteInNewWindow, openWindow };
diff --git a/eims-ui/packages/@core/base/shared/tsconfig.json b/eims-ui/packages/@core/base/shared/tsconfig.json
new file mode 100644
index 0000000..f6860a3
--- /dev/null
+++ b/eims-ui/packages/@core/base/shared/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/library.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/base/typings/build.config.ts b/eims-ui/packages/@core/base/typings/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/packages/@core/base/typings/package.json b/eims-ui/packages/@core/base/typings/package.json
new file mode 100644
index 0000000..42c5db8
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/package.json
@@ -0,0 +1,44 @@
+{
+  "name": "@vben-core/typings",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/base/typings"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild"
+  },
+  "files": [
+    "dist"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "types": "./dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    },
+    "./vue-router": {
+      "types": "./vue-router.d.ts"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "types": "./dist/index.d.ts",
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/base/typings/src/app.d.ts b/eims-ui/packages/@core/base/typings/src/app.d.ts
new file mode 100644
index 0000000..e49a865
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/app.d.ts
@@ -0,0 +1,106 @@
+type LayoutType =
+  | 'full-content'
+  | 'header-nav'
+  | 'mixed-nav'
+  | 'sidebar-mixed-nav'
+  | 'sidebar-nav';
+
+type ThemeModeType = 'auto' | 'dark' | 'light';
+
+/**
+ * 鍋忓ソ璁剧疆鎸夐挳浣嶇疆
+ * fixed 鍥哄畾鍦ㄥ彸渚�
+ * header 椤舵爮
+ * auto 鑷姩
+ */
+type PreferencesButtonPositionType = 'auto' | 'fixed' | 'header';
+
+type BuiltinThemeType =
+  | 'custom'
+  | 'deep-blue'
+  | 'deep-green'
+  | 'default'
+  | 'gray'
+  | 'green'
+  | 'neutral'
+  | 'orange'
+  | 'pink'
+  | 'red'
+  | 'rose'
+  | 'sky-blue'
+  | 'slate'
+  | 'stone'
+  | 'violet'
+  | 'yellow'
+  | 'zinc'
+  | (Record<never, never> & string);
+
+type ContentCompactType = 'compact' | 'wide';
+
+type LayoutHeaderModeType = 'auto' | 'auto-scroll' | 'fixed' | 'static';
+
+/**
+ * 鐧诲綍杩囨湡妯″紡
+ * modal 寮圭獥妯″紡
+ * page 椤甸潰妯″紡
+ */
+type LoginExpiredModeType = 'modal' | 'page';
+
+/**
+ * 闈㈠寘灞戞牱寮�
+ * background 鑳屾櫙
+ * normal 榛樿
+ */
+type BreadcrumbStyleType = 'background' | 'normal';
+
+/**
+ * 鏉冮檺妯″紡
+ * backend 鍚庣鏉冮檺妯″紡
+ * frontend 鍓嶇鏉冮檺妯″紡
+ */
+type AccessModeType = 'backend' | 'frontend';
+
+/**
+ * 瀵艰埅椋庢牸
+ * plain 鏈寸礌
+ * rounded 鍦嗘鼎
+ */
+type NavigationStyleType = 'plain' | 'rounded';
+
+/**
+ * 鏍囩鏍忛鏍�
+ * brisk 杞诲揩
+ * card 鍗$墖
+ * chrome 璋锋瓕
+ * plain 鏈寸礌
+ */
+type TabsStyleType = 'brisk' | 'card' | 'chrome' | 'plain';
+
+/**
+ * 椤甸潰鍒囨崲鍔ㄧ敾
+ */
+type PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up';
+
+/**
+ * 椤甸潰鍒囨崲鍔ㄧ敾
+ * panel-center 灞呬腑甯冨眬
+ * panel-left 灞呭乏甯冨眬
+ * panel-right 灞呭彸甯冨眬
+ */
+type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right';
+
+export type {
+  AccessModeType,
+  AuthPageLayoutType,
+  BreadcrumbStyleType,
+  BuiltinThemeType,
+  ContentCompactType,
+  LayoutHeaderModeType,
+  LayoutType,
+  LoginExpiredModeType,
+  NavigationStyleType,
+  PageTransitionType,
+  PreferencesButtonPositionType,
+  TabsStyleType,
+  ThemeModeType,
+};
diff --git a/eims-ui/packages/@core/base/typings/src/basic.d.ts b/eims-ui/packages/@core/base/typings/src/basic.d.ts
new file mode 100644
index 0000000..bbe1eb0
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/basic.d.ts
@@ -0,0 +1,39 @@
+interface BasicOption {
+  label: string;
+  value: string;
+}
+
+type SelectOption = BasicOption;
+
+type TabOption = BasicOption;
+
+interface BasicUserInfo {
+  /**
+   * 澶村儚
+   */
+  avatar: string;
+  /**
+   * 鐢ㄦ埛鏉冮檺
+   */
+  permissions: string[];
+  /**
+   * 鐢ㄦ埛鏄电О
+   */
+  realName: string;
+  /**
+   * 鐢ㄦ埛瑙掕壊
+   */
+  roles: string[];
+  /**
+   * 鐢ㄦ埛id
+   */
+  userId: number | string;
+  /**
+   * 鐢ㄦ埛鍚�
+   */
+  username: string;
+}
+
+type ClassType = Array<object | string> | object | string;
+
+export type { BasicOption, BasicUserInfo, ClassType, SelectOption, TabOption };
diff --git a/eims-ui/packages/@core/base/typings/src/helper.d.ts b/eims-ui/packages/@core/base/typings/src/helper.d.ts
new file mode 100644
index 0000000..8a6385b
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/helper.d.ts
@@ -0,0 +1,129 @@
+import { type ComputedRef, type MaybeRef } from 'vue';
+
+/**
+ * 娣卞眰閫掑綊鎵�鏈夊睘鎬т负鍙��
+ */
+type DeepPartial<T> = T extends object
+  ? {
+      [P in keyof T]?: DeepPartial<T[P]>;
+    }
+  : T;
+
+/**
+ * 娣卞眰閫掑綊鎵�鏈夊睘鎬т负鍙
+ */
+type DeepReadonly<T> = {
+  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
+};
+
+/**
+ * 浠绘剰绫诲瀷鐨勫紓姝ュ嚱鏁�
+ */
+
+type AnyPromiseFunction<T extends any[] = any[], R = void> = (
+  ...arg: T
+) => PromiseLike<R>;
+
+/**
+ * 浠绘剰绫诲瀷鐨勬櫘閫氬嚱鏁�
+ */
+type AnyNormalFunction<T extends any[] = any[], R = void> = (...arg: T) => R;
+
+/**
+ * 浠绘剰绫诲瀷鐨勫嚱鏁�
+ */
+type AnyFunction<T extends any[] = any[], R = void> =
+  | AnyNormalFunction<T, R>
+  | AnyPromiseFunction<T, R>;
+
+/**
+ *  T | null 鍖呰
+ */
+type Nullable<T> = null | T;
+
+/**
+ * T | Not null 鍖呰
+ */
+type NonNullable<T> = T extends null | undefined ? never : T;
+
+/**
+ * 瀛楃涓茬被鍨嬪璞�
+ */
+type Recordable<T> = Record<string, T>;
+
+/**
+ * 瀛楃涓茬被鍨嬪璞★紙鍙锛�
+ */
+interface ReadonlyRecordable<T = any> {
+  readonly [key: string]: T;
+}
+
+/**
+ * setTimeout 杩斿洖鍊肩被鍨�
+ */
+type TimeoutHandle = ReturnType<typeof setTimeout>;
+
+/**
+ * setInterval 杩斿洖鍊肩被鍨�
+ */
+type IntervalHandle = ReturnType<typeof setInterval>;
+
+/**
+ * 涔熻瀹冩槸涓�涓绠楃殑 ref锛屾垨鑰呬竴涓� getter 鍑芥暟
+ *
+ */
+type MaybeReadonlyRef<T> = (() => T) | ComputedRef<T>;
+
+/**
+ * 涔熻瀹冩槸涓�涓� ref锛屾垨鑰呬竴涓櫘閫氬�硷紝鎴栬�呬竴涓� getter 鍑芥暟
+ *
+ */
+type MaybeComputedRef<T> = MaybeReadonlyRef<T> | MaybeRef<T>;
+
+type Merge<O extends object, T extends object> = {
+  [K in keyof O | keyof T]: K extends keyof T
+    ? T[K]
+    : K extends keyof O
+      ? O[K]
+      : never;
+};
+
+/**
+ * T = [
+ *  { name: string; age: number; },
+ *  { sex: 'male' | 'female'; age: string }
+ * ]
+ * =>
+ * MergeAll<T> = {
+ *  name: string;
+ *  sex: 'male' | 'female';
+ *  age: string
+ * }
+ */
+type MergeAll<
+  T extends object[],
+  R extends object = Record<string, any>,
+> = T extends [infer F extends object, ...infer Rest extends object[]]
+  ? MergeAll<Rest, Merge<R, F>>
+  : R;
+
+type EmitType = (name: Name, ...args: any[]) => void;
+
+export type {
+  AnyFunction,
+  AnyNormalFunction,
+  AnyPromiseFunction,
+  DeepPartial,
+  DeepReadonly,
+  EmitType,
+  IntervalHandle,
+  MaybeComputedRef,
+  MaybeReadonlyRef,
+  Merge,
+  MergeAll,
+  NonNullable,
+  Nullable,
+  ReadonlyRecordable,
+  Recordable,
+  TimeoutHandle,
+};
diff --git a/eims-ui/packages/@core/base/typings/src/index.ts b/eims-ui/packages/@core/base/typings/src/index.ts
new file mode 100644
index 0000000..33c3566
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/index.ts
@@ -0,0 +1,6 @@
+export type * from './app';
+export type * from './basic';
+export type * from './helper';
+export type * from './menu-record';
+export type * from './tabs';
+export type * from './vue-router';
diff --git a/eims-ui/packages/@core/base/typings/src/menu-record.ts b/eims-ui/packages/@core/base/typings/src/menu-record.ts
new file mode 100644
index 0000000..9cb18dc
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/menu-record.ts
@@ -0,0 +1,77 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import type { Component } from 'vue';
+
+/**
+ * 鎵╁睍璺敱鍘熷瀵硅薄
+ */
+type ExRouteRecordRaw = {
+  parent?: string;
+  parents?: string[];
+  path?: any;
+} & RouteRecordRaw;
+
+interface MenuRecordBadgeRaw {
+  /**
+   * 寰芥爣
+   */
+  badge?: string;
+  /**
+   * 寰芥爣绫诲瀷
+   */
+  badgeType?: 'dot' | 'normal';
+  /**
+   * 寰芥爣棰滆壊
+   */
+  badgeVariants?: 'destructive' | 'primary' | string;
+}
+
+/**
+ * 鑿滃崟鍘熷瀵硅薄
+ */
+interface MenuRecordRaw extends MenuRecordBadgeRaw {
+  /**
+   * 婵�娲绘椂鐨勫浘鏍囧悕
+   */
+  activeIcon?: string;
+  /**
+   * 瀛愯彍鍗�
+   */
+  children?: MenuRecordRaw[];
+  /**
+   * 鏄惁绂佺敤鑿滃崟
+   * @default false
+   */
+  disabled?: boolean;
+  /**
+   * 鍥炬爣鍚�
+   */
+  icon?: Component | string;
+  /**
+   * 鑿滃崟鍚�
+   */
+  name: string;
+  /**
+   * 鎺掑簭鍙�
+   */
+  order?: number;
+  /**
+   * 鐖剁骇璺緞
+   */
+  parent?: string;
+  /**
+   * 鎵�鏈夌埗绾ц矾寰�
+   */
+  parents?: string[];
+  /**
+   * 鑿滃崟璺緞锛屽敮涓�锛屽彲褰撲綔key
+   */
+  path: string;
+  /**
+   * 鏄惁鏄剧ず鑿滃崟
+   * @default true
+   */
+  show?: boolean;
+}
+
+export type { ExRouteRecordRaw, MenuRecordBadgeRaw, MenuRecordRaw };
diff --git a/eims-ui/packages/@core/base/typings/src/tabs.ts b/eims-ui/packages/@core/base/typings/src/tabs.ts
new file mode 100644
index 0000000..c78a90c
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/tabs.ts
@@ -0,0 +1,3 @@
+import type { RouteLocationNormalized } from 'vue-router';
+
+export type TabDefinition = RouteLocationNormalized;
diff --git a/eims-ui/packages/@core/base/typings/src/vue-router.d.ts b/eims-ui/packages/@core/base/typings/src/vue-router.d.ts
new file mode 100644
index 0000000..b95bb33
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/src/vue-router.d.ts
@@ -0,0 +1,143 @@
+import type { Router, RouteRecordRaw } from 'vue-router';
+
+import type { Component } from 'vue';
+
+interface RouteMeta {
+  /**
+   * 婵�娲诲浘鏍囷紙鑿滃崟/tab锛�
+   */
+  activeIcon?: string;
+  /**
+   * 褰撳墠婵�娲荤殑鑿滃崟锛屾湁鏃跺�欎笉鎯虫縺娲荤幇鏈夎彍鍗曪紝闇�瑕佹縺娲荤埗绾ц彍鍗曟椂浣跨敤
+   */
+  activePath?: string;
+  /**
+   * 鏄惁鍥哄畾鏍囩椤�
+   * @default false
+   */
+  affixTab?: boolean;
+  /**
+   * 鍥哄畾鏍囩椤电殑椤哄簭
+   * @default 0
+   */
+  affixTabOrder?: number;
+  /**
+   * 闇�瑕佺壒瀹氱殑瑙掕壊鏍囪瘑鎵嶅彲浠ヨ闂�
+   * @default []
+   */
+  authority?: string[];
+  /**
+   * 寰芥爣
+   */
+  badge?: string;
+  /**
+   * 寰芥爣绫诲瀷
+   */
+  badgeType?: 'dot' | 'normal';
+  /**
+   * 寰芥爣棰滆壊
+   */
+  badgeVariants?:
+    | 'default'
+    | 'destructive'
+    | 'primary'
+    | 'success'
+    | 'warning'
+    | string;
+  /**
+   * 褰撳墠璺敱鐨勫瓙绾у湪鑿滃崟涓笉灞曠幇
+   * @default false
+   */
+  hideChildrenInMenu?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄩ潰鍖呭睉涓笉灞曠幇
+   * @default false
+   */
+  hideInBreadcrumb?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄨ彍鍗曚腑涓嶅睍鐜�
+   * @default false
+   */
+  hideInMenu?: boolean;
+  /**
+   * 褰撳墠璺敱鍦ㄦ爣绛鹃〉涓嶅睍鐜�
+   * @default false
+   */
+  hideInTab?: boolean;
+  /**
+   * 鍥炬爣锛堣彍鍗�/tab锛�
+   */
+  icon?: Component | string;
+  /**
+   * iframe 鍦板潃
+   */
+  iframeSrc?: string;
+  /**
+   * 蹇界暐鏉冮檺锛岀洿鎺ュ彲浠ヨ闂�
+   * @default false
+   */
+  ignoreAccess?: boolean;
+  /**
+   * 寮�鍚疜eepAlive缂撳瓨
+   */
+  keepAlive?: boolean;
+  /**
+   * 澶栭摼-璺宠浆璺緞
+   */
+  link?: string;
+  /**
+   * 璺敱鏄惁宸茬粡鍔犺浇杩�
+   */
+  loaded?: boolean;
+  /**
+   * 鏍囩椤垫渶澶ф墦寮�鏁伴噺
+   * @default -1
+   */
+  maxNumOfOpenTab?: number;
+  /**
+   * 鑿滃崟鍙互鐪嬪埌锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+   */
+  menuVisibleWithForbidden?: boolean;
+  /**
+   * 鍦ㄦ柊绐楀彛鎵撳紑
+   */
+  openInNewWindow?: boolean;
+  /**
+   * 鐢ㄤ簬璺敱->鑿滃崟鎺掑簭
+   */
+  order?: number;
+  /**
+   * 鑿滃崟鎵�鎼哄甫鐨勫弬鏁�
+   */
+  query?: Recordable;
+  /**
+   * 鏍囬鍚嶇О
+   */
+  title: string;
+}
+
+// 瀹氫箟閫掑綊绫诲瀷浠ュ皢 RouteRecordRaw 鐨� component 灞炴�ф洿鏀逛负 string
+type RouteRecordStringComponent<T = string> = {
+  children?: RouteRecordStringComponent<T>[];
+  component: T;
+} & Omit<RouteRecordRaw, 'children' | 'component'>;
+
+type ComponentRecordType = Record<string, () => Promise<Component>>;
+
+interface GenerateMenuAndRoutesOptions {
+  fetchMenuListAsync?: () => Promise<RouteRecordStringComponent[]>;
+  forbiddenComponent?: RouteRecordRaw['component'];
+  layoutMap?: ComponentRecordType;
+  pageMap?: ComponentRecordType;
+  roles?: string[];
+  router: Router;
+  routes: RouteRecordRaw[];
+}
+
+export type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+  RouteMeta,
+  RouteRecordRaw,
+  RouteRecordStringComponent,
+};
diff --git a/eims-ui/packages/@core/base/typings/tsconfig.json b/eims-ui/packages/@core/base/typings/tsconfig.json
new file mode 100644
index 0000000..f6860a3
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/library.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/base/typings/vue-router.d.ts b/eims-ui/packages/@core/base/typings/vue-router.d.ts
new file mode 100644
index 0000000..4874bcd
--- /dev/null
+++ b/eims-ui/packages/@core/base/typings/vue-router.d.ts
@@ -0,0 +1,9 @@
+/* eslint-disable no-restricted-imports */
+import type { RouteMeta as IRouteMeta } from '@vben-core/typings';
+
+import 'vue-router';
+
+declare module 'vue-router' {
+  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
+  interface RouteMeta extends IRouteMeta {}
+}
diff --git a/eims-ui/packages/@core/composables/build.config.ts b/eims-ui/packages/@core/composables/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/packages/@core/composables/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/packages/@core/composables/package.json b/eims-ui/packages/@core/composables/package.json
new file mode 100644
index 0000000..9af4f1f
--- /dev/null
+++ b/eims-ui/packages/@core/composables/package.json
@@ -0,0 +1,47 @@
+{
+  "name": "@vben-core/composables",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@core/composables"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": false,
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "types": "./dist/index.d.ts",
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/shared": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "radix-vue": "catalog:",
+    "sortablejs": "catalog:",
+    "vue": "catalog:"
+  },
+  "devDependencies": {
+    "@types/sortablejs": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/composables/src/__tests__/use-sortable.test.ts b/eims-ui/packages/@core/composables/src/__tests__/use-sortable.test.ts
new file mode 100644
index 0000000..e7ba1f1
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/__tests__/use-sortable.test.ts
@@ -0,0 +1,48 @@
+import type { SortableOptions } from 'sortablejs';
+
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { useSortable } from '../use-sortable';
+
+describe('useSortable', () => {
+  beforeEach(() => {
+    vi.mock('sortablejs/modular/sortable.complete.esm.js', () => ({
+      default: {
+        create: vi.fn(),
+      },
+    }));
+  });
+  it('should call Sortable.create with the correct options', async () => {
+    // Create a mock element
+    const mockElement = document.createElement('div') as HTMLDivElement;
+
+    // Define custom options
+    const customOptions: SortableOptions = {
+      group: 'test-group',
+      sort: false,
+    };
+
+    // Use the useSortable function
+    const { initializeSortable } = useSortable(mockElement, customOptions);
+
+    // Initialize sortable
+    await initializeSortable();
+
+    // Import sortablejs to access the mocked create function
+    const Sortable = await import(
+      'sortablejs/modular/sortable.complete.esm.js'
+    );
+
+    // Verify that Sortable.create was called with the correct parameters
+    expect(Sortable.default.create).toHaveBeenCalledTimes(1);
+    expect(Sortable.default.create).toHaveBeenCalledWith(
+      mockElement,
+      expect.objectContaining({
+        animation: 300,
+        delay: 400,
+        delayOnTouchOnly: true,
+        ...customOptions,
+      }),
+    );
+  });
+});
diff --git a/eims-ui/packages/@core/composables/src/index.ts b/eims-ui/packages/@core/composables/src/index.ts
new file mode 100644
index 0000000..146ff00
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/index.ts
@@ -0,0 +1,13 @@
+export * from './use-is-mobile';
+export * from './use-layout-style';
+export * from './use-namespace';
+export * from './use-priority-value';
+export * from './use-scroll-lock';
+export * from './use-simple-locale';
+export * from './use-sortable';
+export {
+  useEmitAsProps,
+  useForwardExpose,
+  useForwardProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
diff --git a/eims-ui/packages/@core/composables/src/use-is-mobile.ts b/eims-ui/packages/@core/composables/src/use-is-mobile.ts
new file mode 100644
index 0000000..e35909f
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-is-mobile.ts
@@ -0,0 +1,7 @@
+import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
+
+export function useIsMobile() {
+  const breakpoints = useBreakpoints(breakpointsTailwind);
+  const isMobile = breakpoints.smaller('md');
+  return { isMobile };
+}
diff --git a/eims-ui/packages/@core/composables/src/use-layout-style.ts b/eims-ui/packages/@core/composables/src/use-layout-style.ts
new file mode 100644
index 0000000..ac599c4
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-layout-style.ts
@@ -0,0 +1,87 @@
+import type { CSSProperties } from 'vue';
+import { computed, onMounted, onUnmounted, ref } from 'vue';
+
+import {
+  CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT,
+  CSS_VARIABLE_LAYOUT_CONTENT_WIDTH,
+  CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT,
+  CSS_VARIABLE_LAYOUT_HEADER_HEIGHT,
+} from '@vben-core/shared/constants';
+import {
+  getElementVisibleRect,
+  type VisibleDomRect,
+} from '@vben-core/shared/utils';
+
+import { useCssVar, useDebounceFn } from '@vueuse/core';
+
+/**
+ * @zh_CN content style
+ */
+export function useLayoutContentStyle() {
+  let resizeObserver: null | ResizeObserver = null;
+  const contentElement = ref<HTMLDivElement | null>(null);
+  const visibleDomRect = ref<null | VisibleDomRect>(null);
+  const contentHeight = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT);
+  const contentWidth = useCssVar(CSS_VARIABLE_LAYOUT_CONTENT_WIDTH);
+
+  const overlayStyle = computed((): CSSProperties => {
+    const { height, left, top, width } = visibleDomRect.value ?? {};
+    return {
+      height: `${height}px`,
+      left: `${left}px`,
+      position: 'fixed',
+      top: `${top}px`,
+      width: `${width}px`,
+      zIndex: 150,
+    };
+  });
+
+  const debouncedCalcHeight = useDebounceFn(
+    (_entries: ResizeObserverEntry[]) => {
+      visibleDomRect.value = getElementVisibleRect(contentElement.value);
+      contentHeight.value = `${visibleDomRect.value.height}px`;
+      contentWidth.value = `${visibleDomRect.value.width}px`;
+    },
+    16,
+  );
+
+  onMounted(() => {
+    if (contentElement.value && !resizeObserver) {
+      resizeObserver = new ResizeObserver(debouncedCalcHeight);
+      resizeObserver.observe(contentElement.value);
+    }
+  });
+
+  onUnmounted(() => {
+    resizeObserver?.disconnect();
+    resizeObserver = null;
+  });
+
+  return { contentElement, overlayStyle, visibleDomRect };
+}
+
+export function useLayoutHeaderStyle() {
+  const headerHeight = useCssVar(CSS_VARIABLE_LAYOUT_HEADER_HEIGHT);
+
+  return {
+    getLayoutHeaderHeight: () => {
+      return Number.parseInt(`${headerHeight.value}`, 10);
+    },
+    setLayoutHeaderHeight: (height: number) => {
+      headerHeight.value = `${height}px`;
+    },
+  };
+}
+
+export function useLayoutFooterStyle() {
+  const footerHeight = useCssVar(CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT);
+
+  return {
+    getLayoutFooterHeight: () => {
+      return Number.parseInt(`${footerHeight.value}`, 10);
+    },
+    setLayoutFooterHeight: (height: number) => {
+      footerHeight.value = `${height}px`;
+    },
+  };
+}
diff --git a/eims-ui/packages/@core/composables/src/use-namespace.ts b/eims-ui/packages/@core/composables/src/use-namespace.ts
new file mode 100644
index 0000000..b22cf03
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-namespace.ts
@@ -0,0 +1,106 @@
+import { DEFAULT_NAMESPACE } from '@vben-core/shared/constants';
+
+/**
+ * @see copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-namespace/index.ts
+ */
+
+const statePrefix = 'is-';
+
+const _bem = (
+  namespace: string,
+  block: string,
+  blockSuffix: string,
+  element: string,
+  modifier: string,
+) => {
+  let cls = `${namespace}-${block}`;
+  if (blockSuffix) {
+    cls += `-${blockSuffix}`;
+  }
+  if (element) {
+    cls += `__${element}`;
+  }
+  if (modifier) {
+    cls += `--${modifier}`;
+  }
+  return cls;
+};
+
+const is: {
+  (name: string): string;
+  // eslint-disable-next-line @typescript-eslint/unified-signatures
+  (name: string, state: boolean | undefined): string;
+} = (name: string, ...args: [] | [boolean | undefined]) => {
+  const state = args.length > 0 ? args[0] : true;
+  return name && state ? `${statePrefix}${name}` : '';
+};
+
+const useNamespace = (block: string) => {
+  const namespace = DEFAULT_NAMESPACE;
+  const b = (blockSuffix = '') => _bem(namespace, block, blockSuffix, '', '');
+  const e = (element?: string) =>
+    element ? _bem(namespace, block, '', element, '') : '';
+  const m = (modifier?: string) =>
+    modifier ? _bem(namespace, block, '', '', modifier) : '';
+  const be = (blockSuffix?: string, element?: string) =>
+    blockSuffix && element
+      ? _bem(namespace, block, blockSuffix, element, '')
+      : '';
+  const em = (element?: string, modifier?: string) =>
+    element && modifier ? _bem(namespace, block, '', element, modifier) : '';
+  const bm = (blockSuffix?: string, modifier?: string) =>
+    blockSuffix && modifier
+      ? _bem(namespace, block, blockSuffix, '', modifier)
+      : '';
+  const bem = (blockSuffix?: string, element?: string, modifier?: string) =>
+    blockSuffix && element && modifier
+      ? _bem(namespace, block, blockSuffix, element, modifier)
+      : '';
+
+  // for css var
+  // --el-xxx: value;
+  const cssVar = (object: Record<string, string>) => {
+    const styles: Record<string, string> = {};
+    for (const key in object) {
+      if (object[key]) {
+        styles[`--${namespace}-${key}`] = object[key];
+      }
+    }
+    return styles;
+  };
+  // with block
+  const cssVarBlock = (object: Record<string, string>) => {
+    const styles: Record<string, string> = {};
+    for (const key in object) {
+      if (object[key]) {
+        styles[`--${namespace}-${block}-${key}`] = object[key];
+      }
+    }
+    return styles;
+  };
+
+  const cssVarName = (name: string) => `--${namespace}-${name}`;
+  const cssVarBlockName = (name: string) => `--${namespace}-${block}-${name}`;
+
+  return {
+    b,
+    be,
+    bem,
+    bm,
+    // css
+    cssVar,
+    cssVarBlock,
+    cssVarBlockName,
+    cssVarName,
+    e,
+    em,
+    is,
+    m,
+    namespace,
+  };
+};
+
+type UseNamespaceReturn = ReturnType<typeof useNamespace>;
+
+export type { UseNamespaceReturn };
+export { useNamespace };
diff --git a/eims-ui/packages/@core/composables/src/use-priority-value.ts b/eims-ui/packages/@core/composables/src/use-priority-value.ts
new file mode 100644
index 0000000..d29e894
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-priority-value.ts
@@ -0,0 +1,93 @@
+import type { ComputedRef, Ref } from 'vue';
+import { computed, getCurrentInstance, unref, useAttrs, useSlots } from 'vue';
+
+import {
+  getFirstNonNullOrUndefined,
+  kebabToCamelCase,
+} from '@vben-core/shared/utils';
+
+/**
+ * 渚濇浠庢彃妲姐�乤ttrs銆乸rops銆乻tate 涓幏鍙栧��
+ * @param key
+ * @param props
+ * @param state
+ */
+export function usePriorityValue<
+  T extends Record<string, any>,
+  S extends Record<string, any>,
+  K extends keyof T = keyof T,
+>(key: K, props: T, state: Readonly<Ref<NoInfer<S>>> | undefined) {
+  const instance = getCurrentInstance();
+  const slots = useSlots();
+  const attrs = useAttrs() as T;
+
+  const value = computed((): T[K] => {
+    // props涓嶇鏈夋病鏈変紶锛岄兘浼氭湁榛樿鍊硷紝浼氬奖鍝嶈繖閲岀殑椤哄簭锛�
+    // 閫氳繃鍒ゆ柇鍘熷props鏄惁鏈夊�兼潵鍒ゆ柇鏄惁浼犲叆
+    const rawProps = (instance?.vnode?.props || {}) as T;
+
+    const standardRawProps = {} as T;
+
+    for (const [key, value] of Object.entries(rawProps)) {
+      standardRawProps[kebabToCamelCase(key) as K] = value;
+    }
+    const propsKey =
+      standardRawProps?.[key] === undefined ? undefined : props[key];
+
+    // slot鍙互鍏抽棴
+    return getFirstNonNullOrUndefined(
+      slots[key as string],
+      attrs[key],
+      propsKey,
+      state?.value?.[key as keyof S],
+    ) as T[K];
+  });
+
+  return value;
+}
+
+/**
+ * 鎵归噺鑾峰彇state涓殑鍊硷紙姣忎釜鍊奸兘鏄痳ef锛�
+ * @param props
+ * @param state
+ */
+export function usePriorityValues<
+  T extends Record<string, any>,
+  S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,
+>(props: T, state: S | undefined) {
+  const result: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;
+
+  (Object.keys(props) as (keyof T)[]).forEach((key) => {
+    result[key] = usePriorityValue(key as keyof typeof props, props, state);
+  });
+
+  return result;
+}
+
+/**
+ * 鎵归噺鑾峰彇state涓殑鍊硷紙闆嗕腑鍦ㄤ竴涓猚omputed锛岀敤浜庨�忎紶锛�
+ * @param props
+ * @param state
+ */
+export function useForwardPriorityValues<
+  T extends Record<string, any>,
+  S extends Ref<Record<string, any>> = Readonly<Ref<NoInfer<T>, NoInfer<T>>>,
+>(props: T, state: S | undefined) {
+  const computedResult: { [K in keyof T]: ComputedRef<T[K]> } = {} as never;
+
+  (Object.keys(props) as (keyof T)[]).forEach((key) => {
+    computedResult[key] = usePriorityValue(
+      key as keyof typeof props,
+      props,
+      state,
+    );
+  });
+
+  return computed(() => {
+    const unwrapResult: Record<string, any> = {};
+    Object.keys(props).forEach((key) => {
+      unwrapResult[key] = unref(computedResult[key]);
+    });
+    return unwrapResult as { [K in keyof T]: T[K] };
+  });
+}
diff --git a/eims-ui/packages/@core/composables/src/use-scroll-lock.ts b/eims-ui/packages/@core/composables/src/use-scroll-lock.ts
new file mode 100644
index 0000000..d1c1497
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-scroll-lock.ts
@@ -0,0 +1,54 @@
+import { getScrollbarWidth, needsScrollbar } from '@vben-core/shared/utils';
+
+import {
+  useScrollLock as _useScrollLock,
+  tryOnBeforeUnmount,
+  tryOnMounted,
+} from '@vueuse/core';
+
+export const SCROLL_FIXED_CLASS = `_scroll__fixed_`;
+
+export function useScrollLock() {
+  const isLocked = _useScrollLock(document.body);
+  const scrollbarWidth = getScrollbarWidth();
+
+  tryOnMounted(() => {
+    if (!needsScrollbar()) {
+      return;
+    }
+    document.body.style.paddingRight = `${scrollbarWidth}px`;
+
+    const layoutFixedNodes = document.querySelectorAll<HTMLElement>(
+      `.${SCROLL_FIXED_CLASS}`,
+    );
+    const nodes = [...layoutFixedNodes];
+    if (nodes.length > 0) {
+      nodes.forEach((node) => {
+        node.dataset.transition = node.style.transition;
+        node.style.transition = 'none';
+        node.style.paddingRight = `${scrollbarWidth}px`;
+      });
+    }
+    isLocked.value = true;
+  });
+
+  tryOnBeforeUnmount(() => {
+    if (!needsScrollbar()) {
+      return;
+    }
+    isLocked.value = false;
+    const layoutFixedNodes = document.querySelectorAll<HTMLElement>(
+      `.${SCROLL_FIXED_CLASS}`,
+    );
+    const nodes = [...layoutFixedNodes];
+    if (nodes.length > 0) {
+      nodes.forEach((node) => {
+        node.style.paddingRight = '';
+        requestAnimationFrame(() => {
+          node.style.transition = node.dataset.transition || '';
+        });
+      });
+    }
+    document.body.style.paddingRight = '';
+  });
+}
diff --git a/eims-ui/packages/@core/composables/src/use-simple-locale/README.md b/eims-ui/packages/@core/composables/src/use-simple-locale/README.md
new file mode 100644
index 0000000..c0a676d
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-simple-locale/README.md
@@ -0,0 +1,3 @@
+# Simple i18n
+
+Simple i18 implementation
diff --git a/eims-ui/packages/@core/composables/src/use-simple-locale/index.ts b/eims-ui/packages/@core/composables/src/use-simple-locale/index.ts
new file mode 100644
index 0000000..1c3015b
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-simple-locale/index.ts
@@ -0,0 +1,25 @@
+import { computed, ref } from 'vue';
+
+import { createSharedComposable } from '@vueuse/core';
+
+import { getMessages, type Locale } from './messages';
+
+export const useSimpleLocale = createSharedComposable(() => {
+  const currentLocale = ref<Locale>('zh-CN');
+
+  const setSimpleLocale = (locale: Locale) => {
+    currentLocale.value = locale;
+  };
+
+  const $t = computed(() => {
+    const localeMessages = getMessages(currentLocale.value);
+    return (key: string) => {
+      return localeMessages[key] || key;
+    };
+  });
+  return {
+    $t,
+    currentLocale,
+    setSimpleLocale,
+  };
+});
diff --git a/eims-ui/packages/@core/composables/src/use-simple-locale/messages.ts b/eims-ui/packages/@core/composables/src/use-simple-locale/messages.ts
new file mode 100644
index 0000000..4b1eca2
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-simple-locale/messages.ts
@@ -0,0 +1,22 @@
+export type Locale = 'en-US' | 'zh-CN';
+
+export const messages: Record<Locale, Record<string, string>> = {
+  'en-US': {
+    cancel: 'Cancel',
+    collapse: 'Collapse',
+    confirm: 'Confirm',
+    expand: 'Expand',
+    reset: 'Reset',
+    submit: 'Submit',
+  },
+  'zh-CN': {
+    cancel: '鍙栨秷',
+    collapse: '鏀惰捣',
+    confirm: '纭',
+    expand: '灞曞紑',
+    reset: '閲嶇疆',
+    submit: '鎻愪氦',
+  },
+};
+
+export const getMessages = (locale: Locale) => messages[locale];
diff --git a/eims-ui/packages/@core/composables/src/use-sortable.ts b/eims-ui/packages/@core/composables/src/use-sortable.ts
new file mode 100644
index 0000000..57f87a6
--- /dev/null
+++ b/eims-ui/packages/@core/composables/src/use-sortable.ts
@@ -0,0 +1,29 @@
+import type { SortableOptions } from 'sortablejs';
+import type Sortable from 'sortablejs';
+
+function useSortable<T extends HTMLElement>(
+  sortableContainer: T,
+  options: SortableOptions = {},
+) {
+  const initializeSortable = async () => {
+    const Sortable = await import(
+      // @ts-expect-error - This is a dynamic import
+      'sortablejs/modular/sortable.complete.esm.js'
+    );
+    const sortable = Sortable?.default?.create?.(sortableContainer, {
+      animation: 300,
+      delay: 400,
+      delayOnTouchOnly: true,
+      ...options,
+    });
+    return sortable as Sortable;
+  };
+
+  return {
+    initializeSortable,
+  };
+}
+
+export { useSortable };
+
+export type { Sortable };
diff --git a/eims-ui/packages/@core/composables/tsconfig.json b/eims-ui/packages/@core/composables/tsconfig.json
new file mode 100644
index 0000000..f6860a3
--- /dev/null
+++ b/eims-ui/packages/@core/composables/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/library.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap b/eims-ui/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap
new file mode 100644
index 0000000..def5ff6
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap
@@ -0,0 +1,115 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defaultPreferences immutability test > should not modify the config object 1`] = `
+{
+  "app": {
+    "accessMode": "frontend",
+    "authPageLayout": "panel-right",
+    "checkUpdatesInterval": 1,
+    "colorGrayMode": false,
+    "colorWeakMode": false,
+    "compact": false,
+    "contentCompact": "wide",
+    "defaultAvatar": "https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp",
+    "dynamicTitle": true,
+    "enableCheckUpdates": true,
+    "enablePreferences": true,
+    "enableRefreshToken": false,
+    "isMobile": false,
+    "layout": "sidebar-nav",
+    "locale": "zh-CN",
+    "loginExpiredMode": "page",
+    "name": "Vben Admin",
+    "preferencesButtonPosition": "auto",
+    "watermark": false,
+  },
+  "breadcrumb": {
+    "enable": true,
+    "hideOnlyOne": false,
+    "showHome": false,
+    "showIcon": true,
+    "styleType": "normal",
+  },
+  "copyright": {
+    "companyName": "Vben",
+    "companySiteLink": "https://www.vben.pro",
+    "date": "2024",
+    "enable": true,
+    "icp": "",
+    "icpLink": "",
+    "settingShow": true,
+  },
+  "footer": {
+    "enable": false,
+    "fixed": false,
+  },
+  "header": {
+    "enable": true,
+    "hidden": false,
+    "mode": "fixed",
+  },
+  "logo": {
+    "enable": true,
+    "source": "https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp",
+  },
+  "navigation": {
+    "accordion": true,
+    "split": true,
+    "styleType": "rounded",
+  },
+  "shortcutKeys": {
+    "enable": true,
+    "globalLockScreen": true,
+    "globalLogout": true,
+    "globalPreferences": true,
+    "globalSearch": true,
+  },
+  "sidebar": {
+    "collapsed": false,
+    "collapsedShowTitle": false,
+    "enable": true,
+    "expandOnHover": true,
+    "extraCollapse": true,
+    "hidden": false,
+    "width": 224,
+  },
+  "tabbar": {
+    "draggable": true,
+    "enable": true,
+    "height": 38,
+    "keepAlive": true,
+    "persist": true,
+    "showIcon": true,
+    "showMaximize": true,
+    "showMore": true,
+    "styleType": "chrome",
+  },
+  "theme": {
+    "builtinType": "default",
+    "colorDestructive": "hsl(348 100% 61%)",
+    "colorPrimary": "hsl(212 100% 45%)",
+    "colorSuccess": "hsl(144 57% 58%)",
+    "colorWarning": "hsl(42 84% 61%)",
+    "mode": "dark",
+    "radius": "0.5",
+    "semiDarkHeader": false,
+    "semiDarkSidebar": false,
+  },
+  "transition": {
+    "enable": true,
+    "loading": true,
+    "name": "fade-slide",
+    "progress": true,
+  },
+  "widget": {
+    "fullscreen": true,
+    "globalSearch": true,
+    "languageToggle": true,
+    "lockScreen": true,
+    "notification": true,
+    "refresh": true,
+    "sidebarToggle": true,
+    "themeToggle": true,
+  },
+}
+`;
diff --git a/eims-ui/packages/@core/preferences/__tests__/config.test.ts b/eims-ui/packages/@core/preferences/__tests__/config.test.ts
new file mode 100644
index 0000000..f7c9bb3
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/__tests__/config.test.ts
@@ -0,0 +1,10 @@
+import { describe, expect, it } from 'vitest';
+
+import { defaultPreferences } from '../src/config';
+
+describe('defaultPreferences immutability test', () => {
+  // 鍒涘缓蹇収锛岀‘淇濋粯璁ら厤缃璞′笉琚慨鏀�
+  it('should not modify the config object', () => {
+    expect(defaultPreferences).toMatchSnapshot();
+  });
+});
diff --git a/eims-ui/packages/@core/preferences/__tests__/preferences.test.ts b/eims-ui/packages/@core/preferences/__tests__/preferences.test.ts
new file mode 100644
index 0000000..37657d8
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/__tests__/preferences.test.ts
@@ -0,0 +1,253 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { defaultPreferences } from '../src/config';
+import { PreferenceManager } from '../src/preferences';
+import { isDarkTheme } from '../src/update-css-variables';
+
+describe('preferences', () => {
+  let preferenceManager: PreferenceManager;
+
+  // 妯℃嫙 window.matchMedia 鏂规硶
+  vi.stubGlobal(
+    'matchMedia',
+    vi.fn().mockImplementation((query) => ({
+      addEventListener: vi.fn(),
+      addListener: vi.fn(), // Deprecated
+      dispatchEvent: vi.fn(),
+      matches: query === '(prefers-color-scheme: dark)',
+      media: query,
+      onchange: null,
+      removeEventListener: vi.fn(),
+      removeListener: vi.fn(), // Deprecated
+    })),
+  );
+  beforeEach(() => {
+    preferenceManager = new PreferenceManager();
+  });
+
+  it('loads default preferences if no saved preferences found', () => {
+    const preferences = preferenceManager.getPreferences();
+    expect(preferences).toEqual(defaultPreferences);
+  });
+
+  it('initializes preferences with overrides', async () => {
+    const overrides: any = {
+      app: {
+        locale: 'en-US',
+      },
+    };
+    await preferenceManager.initPreferences({
+      namespace: 'testNamespace',
+      overrides,
+    });
+
+    // 绛夊緟闃叉姈鍔ㄦ搷浣滃畬鎴�
+    // await new Promise((resolve) => setTimeout(resolve, 300)); // 绛夊緟100姣
+
+    const expected = {
+      ...defaultPreferences,
+      app: {
+        ...defaultPreferences.app,
+        ...overrides.app,
+      },
+    };
+
+    expect(preferenceManager.getPreferences()).toEqual(expected);
+  });
+
+  it('updates theme mode correctly', () => {
+    preferenceManager.updatePreferences({
+      theme: {
+        mode: 'light',
+      },
+    });
+
+    expect(preferenceManager.getPreferences().theme.mode).toBe('light');
+  });
+
+  it('updates color modes correctly', () => {
+    preferenceManager.updatePreferences({
+      app: { colorGrayMode: true, colorWeakMode: true },
+    });
+
+    expect(preferenceManager.getPreferences().app.colorGrayMode).toBe(true);
+    expect(preferenceManager.getPreferences().app.colorWeakMode).toBe(true);
+  });
+
+  it('resets preferences to default', () => {
+    // 鍏堟洿鏂颁竴浜涘亸濂借缃�
+    preferenceManager.updatePreferences({
+      theme: {
+        mode: 'light',
+      },
+    });
+
+    // 鐒跺悗閲嶇疆鍋忓ソ璁剧疆
+    preferenceManager.resetPreferences();
+
+    expect(preferenceManager.getPreferences()).toEqual(defaultPreferences);
+  });
+
+  it('updates isMobile correctly', () => {
+    // 妯℃嫙绉诲姩绔姸鎬�
+    vi.stubGlobal(
+      'matchMedia',
+      vi.fn().mockImplementation((query) => ({
+        addEventListener: vi.fn(),
+        addListener: vi.fn(),
+        dispatchEvent: vi.fn(),
+        matches: query === '(max-width: 768px)',
+        media: query,
+        onchange: null,
+        removeEventListener: vi.fn(),
+        removeListener: vi.fn(),
+      })),
+    );
+
+    preferenceManager.updatePreferences({
+      app: { isMobile: true },
+    });
+
+    expect(preferenceManager.getPreferences().app.isMobile).toBe(true);
+  });
+
+  it('updates the locale preference correctly', () => {
+    preferenceManager.updatePreferences({
+      app: { locale: 'en-US' },
+    });
+
+    expect(preferenceManager.getPreferences().app.locale).toBe('en-US');
+  });
+
+  it('updates the sidebar width correctly', () => {
+    preferenceManager.updatePreferences({
+      sidebar: { width: 200 },
+    });
+
+    expect(preferenceManager.getPreferences().sidebar.width).toBe(200);
+  });
+  it('updates the sidebar collapse state correctly', () => {
+    preferenceManager.updatePreferences({
+      sidebar: { collapsed: true },
+    });
+
+    expect(preferenceManager.getPreferences().sidebar.collapsed).toBe(true);
+  });
+  it('updates the navigation style type correctly', () => {
+    preferenceManager.updatePreferences({
+      navigation: { styleType: 'flat' },
+    } as any);
+
+    expect(preferenceManager.getPreferences().navigation.styleType).toBe(
+      'flat',
+    );
+  });
+
+  it('resets preferences to default correctly', () => {
+    // 鍏堟洿鏂颁竴浜涘亸濂借缃�
+    preferenceManager.updatePreferences({
+      app: { locale: 'en-US' },
+      sidebar: { collapsed: true, width: 200 },
+      theme: {
+        mode: 'light',
+      },
+    });
+
+    // 鐒跺悗閲嶇疆鍋忓ソ璁剧疆
+    preferenceManager.resetPreferences();
+
+    expect(preferenceManager.getPreferences()).toEqual(defaultPreferences);
+  });
+
+  it('does not update undefined preferences', () => {
+    const originalPreferences = preferenceManager.getPreferences();
+
+    preferenceManager.updatePreferences({
+      app: { nonexistentField: 'value' },
+    } as any);
+
+    expect(preferenceManager.getPreferences()).toEqual(originalPreferences);
+  });
+
+  it('reverts to default when a preference field is deleted', () => {
+    preferenceManager.updatePreferences({
+      app: { locale: 'en-US' },
+    });
+
+    preferenceManager.updatePreferences({
+      app: { locale: undefined },
+    });
+
+    expect(preferenceManager.getPreferences().app.locale).toBe('en-US');
+  });
+
+  it('ignores updates with invalid preference value types', () => {
+    const originalPreferences = preferenceManager.getPreferences();
+
+    preferenceManager.updatePreferences({
+      app: { isMobile: 'true' as unknown as boolean }, // 閿欒绫诲瀷
+    });
+
+    expect(preferenceManager.getPreferences()).toEqual(originalPreferences);
+  });
+
+  it('merges nested preference objects correctly', () => {
+    preferenceManager.updatePreferences({
+      app: { name: 'New App Name' },
+    });
+
+    const expected = {
+      ...defaultPreferences,
+      app: {
+        ...defaultPreferences.app,
+        name: 'New App Name',
+      },
+    };
+
+    expect(preferenceManager.getPreferences()).toEqual(expected);
+  });
+
+  it('applies updates immediately after initialization', async () => {
+    const overrides: any = {
+      app: {
+        locale: 'en-US',
+      },
+    };
+
+    await preferenceManager.initPreferences(overrides);
+
+    preferenceManager.updatePreferences({
+      theme: { mode: 'light' },
+    });
+
+    expect(preferenceManager.getPreferences().theme.mode).toBe('light');
+  });
+});
+
+describe('isDarkTheme', () => {
+  it('should return true for dark theme', () => {
+    expect(isDarkTheme('dark')).toBe(true);
+  });
+
+  it('should return false for light theme', () => {
+    expect(isDarkTheme('light')).toBe(false);
+  });
+
+  it('should return system preference for auto theme', () => {
+    vi.spyOn(window, 'matchMedia').mockImplementation((query) => ({
+      addEventListener: vi.fn(),
+      addListener: vi.fn(), // Deprecated
+      dispatchEvent: vi.fn(),
+      matches: query === '(prefers-color-scheme: dark)',
+      media: query,
+      onchange: null,
+      removeEventListener: vi.fn(),
+      removeListener: vi.fn(), // Deprecated
+    }));
+
+    expect(isDarkTheme('auto')).toBe(true);
+    expect(window.matchMedia).toHaveBeenCalledWith(
+      '(prefers-color-scheme: dark)',
+    );
+  });
+});
diff --git a/eims-ui/packages/@core/preferences/build.config.ts b/eims-ui/packages/@core/preferences/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/packages/@core/preferences/package.json b/eims-ui/packages/@core/preferences/package.json
new file mode 100644
index 0000000..1cff099
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/package.json
@@ -0,0 +1,37 @@
+{
+  "name": "@vben-core/preferences",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@core/preferences"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "#build": "pnpm unbuild"
+  },
+  "files": [
+    "dist",
+    "src"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./src/index.ts",
+      "#default": "./dist/index.mjs"
+    }
+  },
+  "dependencies": {
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/preferences/src/config.ts b/eims-ui/packages/@core/preferences/src/config.ts
new file mode 100644
index 0000000..8a3d191
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/config.ts
@@ -0,0 +1,116 @@
+import type { Preferences } from './types';
+
+const defaultPreferences: Preferences = {
+  app: {
+    accessMode: 'frontend',
+    authPageLayout: 'panel-right',
+    checkUpdatesInterval: 1,
+    colorGrayMode: false,
+    colorWeakMode: false,
+    compact: false,
+    contentCompact: 'wide',
+    defaultAvatar:
+      'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',
+    dynamicTitle: true,
+    enableCheckUpdates: true,
+    enablePreferences: true,
+    enableRefreshToken: false,
+    isMobile: false,
+    layout: 'sidebar-nav',
+    locale: 'zh-CN',
+    loginExpiredMode: 'page',
+    name: 'Vben Admin',
+    preferencesButtonPosition: 'auto',
+    watermark: false,
+  },
+  breadcrumb: {
+    enable: true,
+    hideOnlyOne: false,
+    showHome: false,
+    showIcon: true,
+    styleType: 'normal',
+  },
+  copyright: {
+    companyName: 'Vben',
+    companySiteLink: 'https://www.vben.pro',
+    date: '2024',
+    enable: true,
+    icp: '',
+    icpLink: '',
+    settingShow: true,
+  },
+  footer: {
+    enable: false,
+    fixed: false,
+  },
+  header: {
+    enable: true,
+    hidden: false,
+    mode: 'fixed',
+  },
+  logo: {
+    enable: true,
+    source: '/static/logo.png',
+  },
+  navigation: {
+    accordion: true,
+    split: true,
+    styleType: 'rounded',
+  },
+  shortcutKeys: {
+    enable: true,
+    globalLockScreen: true,
+    globalLogout: true,
+    globalPreferences: true,
+    globalSearch: true,
+  },
+  sidebar: {
+    collapsed: false,
+    collapsedShowTitle: false,
+    enable: true,
+    expandOnHover: true,
+    extraCollapse: true,
+    hidden: false,
+    width: 224,
+  },
+  tabbar: {
+    draggable: true,
+    enable: true,
+    height: 38,
+    keepAlive: true,
+    persist: true,
+    showIcon: true,
+    showMaximize: true,
+    showMore: true,
+    styleType: 'chrome',
+  },
+  theme: {
+    builtinType: 'default',
+    colorDestructive: 'hsl(348 100% 61%)',
+    colorPrimary: 'hsl(212 100% 45%)',
+    colorSuccess: 'hsl(144 57% 58%)',
+    colorWarning: 'hsl(42 84% 61%)',
+    mode: 'auto',
+    radius: '0.5',
+    semiDarkHeader: false,
+    semiDarkSidebar: false,
+  },
+  transition: {
+    enable: true,
+    loading: true,
+    name: 'fade-slide',
+    progress: true,
+  },
+  widget: {
+    fullscreen: true,
+    globalSearch: true,
+    languageToggle: true,
+    lockScreen: true,
+    notification: true,
+    refresh: true,
+    sidebarToggle: true,
+    themeToggle: true,
+  },
+};
+
+export { defaultPreferences };
diff --git a/eims-ui/packages/@core/preferences/src/constants.ts b/eims-ui/packages/@core/preferences/src/constants.ts
new file mode 100644
index 0000000..430ee3b
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/constants.ts
@@ -0,0 +1,88 @@
+import type { BuiltinThemeType } from '@vben-core/typings';
+
+interface BuiltinThemePreset {
+  color: string;
+  darkPrimaryColor?: string;
+  primaryColor?: string;
+  type: BuiltinThemeType;
+}
+
+const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
+  {
+    color: 'hsl(212 100% 45%)',
+    type: 'default',
+  },
+  {
+    color: 'hsl(245 82% 67%)',
+    type: 'violet',
+  },
+  {
+    color: 'hsl(347 77% 60%)',
+    type: 'pink',
+  },
+  {
+    color: 'hsl(42 84% 61%)',
+    type: 'yellow',
+  },
+  {
+    color: 'hsl(231 98% 65%)',
+    type: 'sky-blue',
+  },
+  {
+    color: 'hsl(161 90% 43%)',
+    type: 'green',
+  },
+  {
+    color: 'hsl(240 5% 26%)',
+    darkPrimaryColor: 'hsl(0 0% 98%)',
+    primaryColor: 'hsl(240 5.9% 10%)',
+    type: 'zinc',
+  },
+
+  {
+    color: 'hsl(181 84% 32%)',
+    type: 'deep-green',
+  },
+
+  {
+    color: 'hsl(211 91% 39%)',
+    type: 'deep-blue',
+  },
+  {
+    color: 'hsl(18 89% 40%)',
+    type: 'orange',
+  },
+  {
+    color: 'hsl(0 75% 42%)',
+    type: 'rose',
+  },
+
+  {
+    color: 'hsl(0 0% 25%)',
+    darkPrimaryColor: 'hsl(0 0% 98%)',
+    primaryColor: 'hsl(240 5.9% 10%)',
+    type: 'neutral',
+  },
+  {
+    color: 'hsl(215 25% 27%)',
+    darkPrimaryColor: 'hsl(0 0% 98%)',
+    primaryColor: 'hsl(240 5.9% 10%)',
+    type: 'slate',
+  },
+  {
+    color: 'hsl(217 19% 27%)',
+    darkPrimaryColor: 'hsl(0 0% 98%)',
+    primaryColor: 'hsl(240 5.9% 10%)',
+    type: 'gray',
+  },
+  {
+    color: '',
+    type: 'custom',
+  },
+];
+
+export const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 7);
+
+export { BUILT_IN_THEME_PRESETS };
+
+export type { BuiltinThemePreset };
diff --git a/eims-ui/packages/@core/preferences/src/index.ts b/eims-ui/packages/@core/preferences/src/index.ts
new file mode 100644
index 0000000..33444e1
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/index.ts
@@ -0,0 +1,35 @@
+import type { Preferences } from './types';
+
+import { preferencesManager } from './preferences';
+
+// 鍋忓ソ璁剧疆锛堝甫鏈夊眰绾у叧绯伙級
+const preferences: Preferences =
+  preferencesManager.getPreferences.apply(preferencesManager);
+
+// 鏇存柊鍋忓ソ璁剧疆
+const updatePreferences =
+  preferencesManager.updatePreferences.bind(preferencesManager);
+
+// 閲嶇疆鍋忓ソ璁剧疆
+const resetPreferences =
+  preferencesManager.resetPreferences.bind(preferencesManager);
+
+const clearPreferencesCache =
+  preferencesManager.clearCache.bind(preferencesManager);
+
+// 鍒濆鍖栧亸濂借缃�
+const initPreferences =
+  preferencesManager.initPreferences.bind(preferencesManager);
+
+export {
+  clearPreferencesCache,
+  initPreferences,
+  preferences,
+  preferencesManager,
+  resetPreferences,
+  updatePreferences,
+};
+
+export * from './constants';
+export type * from './types';
+export * from './use-preferences';
diff --git a/eims-ui/packages/@core/preferences/src/preferences.ts b/eims-ui/packages/@core/preferences/src/preferences.ts
new file mode 100644
index 0000000..7851fdb
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/preferences.ts
@@ -0,0 +1,228 @@
+import type { DeepPartial } from '@vben-core/typings';
+
+import type { InitialOptions, Preferences } from './types';
+
+import { markRaw, reactive, readonly, watch } from 'vue';
+
+import { StorageManager } from '@vben-core/shared/cache';
+import { isMacOs, merge } from '@vben-core/shared/utils';
+
+import {
+  breakpointsTailwind,
+  useBreakpoints,
+  useDebounceFn,
+} from '@vueuse/core';
+
+import { defaultPreferences } from './config';
+import { updateCSSVariables } from './update-css-variables';
+
+const STORAGE_KEY = 'preferences';
+const STORAGE_KEY_LOCALE = `${STORAGE_KEY}-locale`;
+const STORAGE_KEY_THEME = `${STORAGE_KEY}-theme`;
+
+class PreferenceManager {
+  private cache: null | StorageManager = null;
+  // private flattenedState: Flatten<Preferences>;
+  private initialPreferences: Preferences = defaultPreferences;
+  private isInitialized: boolean = false;
+  private savePreferences: (preference: Preferences) => void;
+  private state: Preferences = reactive<Preferences>({
+    ...this.loadPreferences(),
+  });
+  constructor() {
+    this.cache = new StorageManager();
+
+    // 閬垮厤棰戠箒鐨勬搷浣滅紦瀛�
+    this.savePreferences = useDebounceFn(
+      (preference: Preferences) => this._savePreferences(preference),
+      150,
+    );
+  }
+
+  /**
+   * 淇濆瓨鍋忓ソ璁剧疆
+   * @param {Preferences} preference - 闇�瑕佷繚瀛樼殑鍋忓ソ璁剧疆
+   */
+  private _savePreferences(preference: Preferences) {
+    this.cache?.setItem(STORAGE_KEY, preference);
+    this.cache?.setItem(STORAGE_KEY_LOCALE, preference.app.locale);
+    this.cache?.setItem(STORAGE_KEY_THEME, preference.theme.mode);
+  }
+
+  /**
+   * 澶勭悊鏇存柊鐨勯敭鍊�
+   * 鏍规嵁鏇存柊鐨勯敭鍊兼墽琛岀浉搴旂殑鎿嶄綔銆�
+   * @param {DeepPartial<Preferences>} updates - 閮ㄥ垎鏇存柊鐨勫亸濂借缃�
+   */
+  private handleUpdates(updates: DeepPartial<Preferences>) {
+    const themeUpdates = updates.theme || {};
+    const appUpdates = updates.app || {};
+    if (themeUpdates && Object.keys(themeUpdates).length > 0) {
+      updateCSSVariables(this.state);
+    }
+
+    if (
+      Reflect.has(appUpdates, 'colorGrayMode') ||
+      Reflect.has(appUpdates, 'colorWeakMode')
+    ) {
+      this.updateColorMode(this.state);
+    }
+  }
+
+  private initPlatform() {
+    const dom = document.documentElement;
+    dom.dataset.platform = isMacOs() ? 'macOs' : 'window';
+  }
+
+  /**
+   *  浠庣紦瀛樹腑鍔犺浇鍋忓ソ璁剧疆銆傚鏋滅紦瀛樹腑娌℃湁鎵惧埌瀵瑰簲鐨勫亸濂借缃紝鍒欒繑鍥為粯璁ゅ亸濂借缃��
+   */
+  private loadCachedPreferences() {
+    return this.cache?.getItem<Preferences>(STORAGE_KEY);
+  }
+
+  /**
+   * 鍔犺浇鍋忓ソ璁剧疆
+   * @returns {Preferences} 鍔犺浇鐨勫亸濂借缃�
+   */
+  private loadPreferences(): Preferences {
+    return this.loadCachedPreferences() || { ...defaultPreferences };
+  }
+
+  /**
+   * 鐩戝惉鐘舵�佸拰绯荤粺鍋忓ソ璁剧疆鐨勫彉鍖栥��
+   */
+  private setupWatcher() {
+    if (this.isInitialized) {
+      return;
+    }
+
+    // 鐩戝惉鏂偣锛屽垽鏂槸鍚︾Щ鍔ㄧ
+    const breakpoints = useBreakpoints(breakpointsTailwind);
+    const isMobile = breakpoints.smaller('md');
+    watch(
+      () => isMobile.value,
+      (val) => {
+        this.updatePreferences({
+          app: { isMobile: val },
+        });
+      },
+      { immediate: true },
+    );
+
+    // 鐩戝惉绯荤粺涓婚鍋忓ソ璁剧疆鍙樺寲
+    window
+      .matchMedia('(prefers-color-scheme: dark)')
+      .addEventListener('change', ({ matches: isDark }) => {
+        this.updatePreferences({
+          theme: { mode: isDark ? 'dark' : 'light' },
+        });
+      });
+  }
+
+  /**
+   * 鏇存柊椤甸潰棰滆壊妯″紡锛堢伆鑹层�佽壊寮憋級
+   * @param preference
+   */
+  private updateColorMode(preference: Preferences) {
+    if (preference.app) {
+      const { colorGrayMode, colorWeakMode } = preference.app;
+      const dom = document.documentElement;
+      const COLOR_WEAK = 'invert-mode';
+      const COLOR_GRAY = 'grayscale-mode';
+      colorWeakMode
+        ? dom.classList.add(COLOR_WEAK)
+        : dom.classList.remove(COLOR_WEAK);
+      colorGrayMode
+        ? dom.classList.add(COLOR_GRAY)
+        : dom.classList.remove(COLOR_GRAY);
+    }
+  }
+
+  clearCache() {
+    [STORAGE_KEY, STORAGE_KEY_LOCALE, STORAGE_KEY_THEME].forEach((key) => {
+      this.cache?.removeItem(key);
+    });
+  }
+
+  public getInitialPreferences() {
+    return this.initialPreferences;
+  }
+
+  public getPreferences() {
+    return readonly(this.state);
+  }
+
+  /**
+   * 瑕嗙洊鍋忓ソ璁剧疆
+   * overrides  瑕佽鐩栫殑鍋忓ソ璁剧疆
+   * namespace  鍛藉悕绌洪棿
+   */
+  public async initPreferences({ namespace, overrides }: InitialOptions) {
+    // 鏄惁鍒濆鍖栬繃
+    if (this.isInitialized) {
+      return;
+    }
+    // 鍒濆鍖栧瓨鍌ㄧ鐞嗗櫒
+    this.cache = new StorageManager({ prefix: namespace });
+    // 鍚堝苟鍒濆鍋忓ソ璁剧疆
+    this.initialPreferences = merge({}, overrides, defaultPreferences);
+
+    // 鍔犺浇骞跺悎骞跺綋鍓嶅瓨鍌ㄧ殑鍋忓ソ璁剧疆
+    const mergedPreference = merge(
+      {},
+      // overrides,
+      this.loadCachedPreferences() || {},
+      this.initialPreferences,
+    );
+
+    // 鏇存柊鍋忓ソ璁剧疆
+    this.updatePreferences(mergedPreference);
+
+    this.setupWatcher();
+
+    this.initPlatform();
+    // 鏍囪涓哄凡鍒濆鍖�
+    this.isInitialized = true;
+  }
+
+  /**
+   * 閲嶇疆鍋忓ソ璁剧疆
+   * 鍋忓ソ璁剧疆灏嗚閲嶇疆涓哄垵濮嬪�硷紝骞朵粠 localStorage 涓Щ闄ゃ��
+   *
+   * @example
+   * 鍋囪 initialPreferences 涓� { theme: 'light', language: 'en' }
+   * 褰撳墠 state 涓� { theme: 'dark', language: 'fr' }
+   * this.resetPreferences();
+   * 璋冪敤鍚庯紝state 灏嗚閲嶇疆涓� { theme: 'light', language: 'en' }
+   * 骞朵笖 localStorage 涓殑瀵瑰簲椤瑰皢琚Щ闄�
+   */
+  resetPreferences() {
+    // 灏嗙姸鎬侀噸缃负鍒濆鍋忓ソ璁剧疆
+    Object.assign(this.state, this.initialPreferences);
+    // 淇濆瓨閲嶇疆鍚庣殑鍋忓ソ璁剧疆
+    this.savePreferences(this.state);
+    // 浠庡瓨鍌ㄤ腑绉婚櫎鍋忓ソ璁剧疆椤�
+    [STORAGE_KEY, STORAGE_KEY_THEME, STORAGE_KEY_LOCALE].forEach((key) => {
+      this.cache?.removeItem(key);
+    });
+    this.updatePreferences(this.state);
+  }
+
+  /**
+   * 鏇存柊鍋忓ソ璁剧疆
+   * @param updates - 瑕佹洿鏂扮殑鍋忓ソ璁剧疆
+   */
+  public updatePreferences(updates: DeepPartial<Preferences>) {
+    const mergedState = merge({}, updates, markRaw(this.state));
+
+    Object.assign(this.state, mergedState);
+
+    // 鏍规嵁鏇存柊鐨勯敭鍊兼墽琛岀浉搴旂殑鎿嶄綔
+    this.handleUpdates(updates);
+    this.savePreferences(this.state);
+  }
+}
+
+const preferencesManager = new PreferenceManager();
+export { PreferenceManager, preferencesManager };
diff --git a/eims-ui/packages/@core/preferences/src/types.ts b/eims-ui/packages/@core/preferences/src/types.ts
new file mode 100644
index 0000000..2b536b8
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/types.ts
@@ -0,0 +1,281 @@
+import type {
+  AccessModeType,
+  AuthPageLayoutType,
+  BreadcrumbStyleType,
+  BuiltinThemeType,
+  ContentCompactType,
+  DeepPartial,
+  LayoutHeaderModeType,
+  LayoutType,
+  LoginExpiredModeType,
+  NavigationStyleType,
+  PageTransitionType,
+  PreferencesButtonPositionType,
+  TabsStyleType,
+  ThemeModeType,
+} from '@vben-core/typings';
+
+type SupportedLanguagesType = 'en-US' | 'zh-CN';
+
+interface AppPreferences {
+  /** 鏉冮檺妯″紡 */
+  accessMode: AccessModeType;
+  /** 鐧诲綍娉ㄥ唽椤甸潰甯冨眬 */
+  authPageLayout: AuthPageLayoutType;
+  /** 妫�鏌ユ洿鏂拌疆璇㈡椂闂� */
+  checkUpdatesInterval: number;
+  /** 鏄惁寮�鍚伆鑹叉ā寮� */
+  colorGrayMode: boolean;
+  /** 鏄惁寮�鍚壊寮辨ā寮� */
+  colorWeakMode: boolean;
+  /** 鏄惁寮�鍚揣鍑戞ā寮� */
+  compact: boolean;
+  /** 鏄惁寮�鍚唴瀹圭揣鍑戞ā寮� */
+  contentCompact: ContentCompactType;
+  // /** 搴旂敤榛樿澶村儚 */
+  defaultAvatar: string;
+  // /** 寮�鍚姩鎬佹爣棰� */
+  dynamicTitle: boolean;
+  /** 鏄惁寮�鍚鏌ユ洿鏂� */
+  enableCheckUpdates: boolean;
+  /** 鏄惁鏄剧ず鍋忓ソ璁剧疆 */
+  enablePreferences: boolean;
+  /**
+   * @zh_CN 鏄惁寮�鍚痳efreshToken
+   */
+  enableRefreshToken: boolean;
+  /** 鏄惁绉诲姩绔� */
+  isMobile: boolean;
+  /** 甯冨眬鏂瑰紡 */
+  layout: LayoutType;
+  /** 鏀寔鐨勮瑷� */
+  locale: SupportedLanguagesType;
+  /** 鐧诲綍杩囨湡妯″紡 */
+  loginExpiredMode: LoginExpiredModeType;
+  /** 搴旂敤鍚� */
+  name: string;
+  /** 鍋忓ソ璁剧疆鎸夐挳浣嶇疆 */
+  preferencesButtonPosition: PreferencesButtonPositionType;
+  /**
+   * @zh_CN 鏄惁寮�鍚按鍗�
+   */
+  watermark: boolean;
+}
+
+interface BreadcrumbPreferences {
+  /** 闈㈠寘灞戞槸鍚﹀惎鐢� */
+  enable: boolean;
+  /** 闈㈠寘灞戞槸鍚﹀彧鏈変竴涓椂闅愯棌 */
+  hideOnlyOne: boolean;
+  /** 闈㈠寘灞戦椤靛浘鏍囨槸鍚﹀彲瑙� */
+  showHome: boolean;
+  /** 闈㈠寘灞戝浘鏍囨槸鍚﹀彲瑙� */
+  showIcon: boolean;
+  /** 闈㈠寘灞戦鏍� */
+  styleType: BreadcrumbStyleType;
+}
+
+interface CopyrightPreferences {
+  /** 鐗堟潈鍏徃鍚� */
+  companyName: string;
+  /** 鐗堟潈鍏徃鍚嶉摼鎺� */
+  companySiteLink: string;
+  /** 鐗堟潈鏃ユ湡 */
+  date: string;
+  /** 鐗堟潈鏄惁鍙 */
+  enable: boolean;
+  /** 澶囨鍙� */
+  icp: string;
+  /** 澶囨鍙烽摼鎺� */
+  icpLink: string;
+  /** 璁剧疆闈㈡澘鏄惁鏄剧ず*/
+  settingShow?: boolean;
+}
+
+interface FooterPreferences {
+  /** 搴曟爮鏄惁鍙 */
+  enable: boolean;
+  /** 搴曟爮鏄惁鍥哄畾 */
+  fixed: boolean;
+}
+
+interface HeaderPreferences {
+  /** 椤舵爮鏄惁鍚敤 */
+  enable: boolean;
+  /** 椤舵爮鏄惁闅愯棌,css-闅愯棌 */
+  hidden: boolean;
+  /** header鏄剧ず妯″紡 */
+  mode: LayoutHeaderModeType;
+}
+
+interface LogoPreferences {
+  /** logo鏄惁鍙 */
+  enable: boolean;
+  /** logo鍦板潃 */
+  source: string;
+}
+
+interface NavigationPreferences {
+  /** 瀵艰埅鑿滃崟鎵嬮鐞存ā寮� */
+  accordion: boolean;
+  /** 瀵艰埅鑿滃崟鏄惁鍒囧壊锛屽彧鍦� layout=mixed-nav 鐢熸晥 */
+  split: boolean;
+  /** 瀵艰埅鑿滃崟椋庢牸 */
+  styleType: NavigationStyleType;
+}
+
+interface SidebarPreferences {
+  /** 渚ц竟鏍忔槸鍚︽姌鍙� */
+  collapsed: boolean;
+  /** 渚ц竟鏍忔姌鍙犳椂锛屾槸鍚︽樉绀簍itle */
+  collapsedShowTitle: boolean;
+  /** 渚ц竟鏍忔槸鍚﹀彲瑙� */
+  enable: boolean;
+  /** 鑿滃崟鑷姩灞曞紑鐘舵�� */
+  expandOnHover: boolean;
+  /** 渚ц竟鏍忔墿灞曞尯鍩熸槸鍚︽姌鍙� */
+  extraCollapse: boolean;
+  /** 渚ц竟鏍忔槸鍚﹂殣钘� - css */
+  hidden: boolean;
+  /** 渚ц竟鏍忓搴� */
+  width: number;
+}
+
+interface ShortcutKeyPreferences {
+  /** 鏄惁鍚敤蹇嵎閿�-鍏ㄥ眬 */
+  enable: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬閿佸睆蹇嵎閿� */
+  globalLockScreen: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬娉ㄩ攢蹇嵎閿� */
+  globalLogout: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鍋忓ソ璁剧疆蹇嵎閿� */
+  globalPreferences: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鎼滅储蹇嵎閿� */
+  globalSearch: boolean;
+}
+
+interface TabbarPreferences {
+  /** 鏄惁寮�鍚鏍囩椤垫嫋鎷� */
+  draggable: boolean;
+  /** 鏄惁寮�鍚鏍囩椤� */
+  enable: boolean;
+  /** 鏍囩椤甸珮搴� */
+  height: number;
+  /** 寮�鍚爣绛鹃〉缂撳瓨鍔熻兘 */
+  keepAlive: boolean;
+  /** 鏄惁鎸佷箙鍖栨爣绛� */
+  persist: boolean;
+  /** 鏄惁寮�鍚鏍囩椤靛浘鏍� */
+  showIcon: boolean;
+  /** 鏄剧ず鏈�澶у寲鎸夐挳 */
+  showMaximize: boolean;
+  /** 鏄剧ず鏇村鎸夐挳 */
+  showMore: boolean;
+  /** 鏍囩椤甸鏍� */
+  styleType: TabsStyleType;
+}
+
+interface ThemePreferences {
+  /** 鍐呯疆涓婚鍚� */
+  builtinType: BuiltinThemeType;
+  /** 閿欒鑹� */
+  colorDestructive: string;
+  /** 涓婚鑹� */
+  colorPrimary: string;
+  /** 鎴愬姛鑹� */
+  colorSuccess: string;
+  /** 璀﹀憡鑹� */
+  colorWarning: string;
+  /** 褰撳墠涓婚 */
+  mode: ThemeModeType;
+  /** 鍦嗚 */
+  radius: string;
+  /** 鏄惁寮�鍚崐娣辫壊header锛堝彧鍦╰heme='light'鏃剁敓鏁堬級 */
+  semiDarkHeader: boolean;
+  /** 鏄惁寮�鍚崐娣辫壊鑿滃崟锛堝彧鍦╰heme='light'鏃剁敓鏁堬級 */
+  semiDarkSidebar: boolean;
+}
+
+interface TransitionPreferences {
+  /** 椤甸潰鍒囨崲鍔ㄧ敾鏄惁鍚敤 */
+  enable: boolean;
+  // /** 鏄惁寮�鍚〉闈㈠姞杞絣oading */
+  loading: boolean;
+  /** 椤甸潰鍒囨崲鍔ㄧ敾 */
+  name: PageTransitionType | string;
+  /** 鏄惁寮�鍚〉闈㈠姞杞借繘搴﹀姩鐢� */
+  progress: boolean;
+}
+
+interface WidgetPreferences {
+  /** 鏄惁鍚敤鍏ㄥ睆閮ㄤ欢 */
+  fullscreen: boolean;
+  /** 鏄惁鍚敤鍏ㄥ眬鎼滅储閮ㄤ欢 */
+  globalSearch: boolean;
+  /** 鏄惁鍚敤璇█鍒囨崲閮ㄤ欢 */
+  languageToggle: boolean;
+  /** 鏄惁寮�鍚攣灞忓姛鑳� */
+  lockScreen: boolean;
+  /** 鏄惁鏄剧ず閫氱煡閮ㄤ欢 */
+  notification: boolean;
+  /** 鏄剧ず鍒锋柊鎸夐挳 */
+  refresh: boolean;
+  /** 鏄惁鏄剧ず渚ц竟鏍忔樉绀�/闅愯棌閮ㄤ欢 */
+  sidebarToggle: boolean;
+  /** 鏄惁鏄剧ず涓婚鍒囨崲閮ㄤ欢 */
+  themeToggle: boolean;
+}
+
+interface Preferences {
+  /** 鍏ㄥ眬閰嶇疆 */
+  app: AppPreferences;
+  /** 椤舵爮閰嶇疆 */
+  breadcrumb: BreadcrumbPreferences;
+  /** 鐗堟潈閰嶇疆 */
+  copyright: CopyrightPreferences;
+  /** 搴曟爮閰嶇疆 */
+  footer: FooterPreferences;
+  /** 闈㈠寘灞戦厤缃� */
+  header: HeaderPreferences;
+  /** logo閰嶇疆 */
+  logo: LogoPreferences;
+  /** 瀵艰埅閰嶇疆 */
+  navigation: NavigationPreferences;
+  /** 蹇嵎閿厤缃� */
+  shortcutKeys: ShortcutKeyPreferences;
+  /** 渚ц竟鏍忛厤缃� */
+  sidebar: SidebarPreferences;
+  /** 鏍囩椤甸厤缃� */
+  tabbar: TabbarPreferences;
+  /** 涓婚閰嶇疆 */
+  theme: ThemePreferences;
+  /** 鍔ㄧ敾閰嶇疆 */
+  transition: TransitionPreferences;
+  /** 鍔熻兘閰嶇疆 */
+  widget: WidgetPreferences;
+}
+
+type PreferencesKeys = keyof Preferences;
+
+interface InitialOptions {
+  namespace: string;
+  overrides?: DeepPartial<Preferences>;
+}
+export type {
+  AppPreferences,
+  BreadcrumbPreferences,
+  FooterPreferences,
+  HeaderPreferences,
+  InitialOptions,
+  LogoPreferences,
+  NavigationPreferences,
+  Preferences,
+  PreferencesKeys,
+  ShortcutKeyPreferences,
+  SidebarPreferences,
+  SupportedLanguagesType,
+  TabbarPreferences,
+  ThemePreferences,
+  TransitionPreferences,
+  WidgetPreferences,
+};
diff --git a/eims-ui/packages/@core/preferences/src/update-css-variables.ts b/eims-ui/packages/@core/preferences/src/update-css-variables.ts
new file mode 100644
index 0000000..0d3466a
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/update-css-variables.ts
@@ -0,0 +1,116 @@
+import type { Preferences } from './types';
+
+import { generatorColorVariables } from '@vben-core/shared/color';
+import { updateCSSVariables as executeUpdateCSSVariables } from '@vben-core/shared/utils';
+
+import { BUILT_IN_THEME_PRESETS } from './constants';
+
+/**
+ * 鏇存柊涓婚鐨� CSS 鍙橀噺浠ュ強鍏朵粬 CSS 鍙橀噺
+ * @param preferences - 褰撳墠鍋忓ソ璁剧疆瀵硅薄锛屽畠鐨勪富棰樺�煎皢琚敤鏉ヨ缃枃妗g殑涓婚銆�
+ */
+function updateCSSVariables(preferences: Preferences) {
+  // 褰撲慨鏀瑰埌棰滆壊鍙橀噺鏃讹紝鏇存柊 css 鍙橀噺
+  const root = document.documentElement;
+  if (!root) {
+    return;
+  }
+
+  const theme = preferences?.theme ?? {};
+
+  const { builtinType, mode, radius } = theme;
+
+  // html 璁剧疆 dark 绫�
+  if (Reflect.has(theme, 'mode')) {
+    const dark = isDarkTheme(mode);
+    root.classList.toggle('dark', dark);
+  }
+
+  // html 璁剧疆 data-theme=[builtinType]
+  if (Reflect.has(theme, 'builtinType')) {
+    const rootTheme = root.dataset.theme;
+    if (rootTheme !== builtinType) {
+      root.dataset.theme = builtinType;
+    }
+  }
+
+  // 鑾峰彇褰撳墠鐨勫唴缃富棰�
+  const currentBuiltType = [...BUILT_IN_THEME_PRESETS].find(
+    (item) => item.type === builtinType,
+  );
+
+  let builtinTypeColorPrimary: string | undefined = '';
+
+  if (currentBuiltType) {
+    const isDark = isDarkTheme(preferences.theme.mode);
+    // 璁剧疆涓嶅悓涓婚鐨勪富瑕侀鑹�
+    const color = isDark
+      ? currentBuiltType.darkPrimaryColor || currentBuiltType.primaryColor
+      : currentBuiltType.primaryColor;
+    builtinTypeColorPrimary = color || currentBuiltType.color;
+  }
+
+  // 濡傛灉鍐呯疆涓婚棰滆壊鍜岃嚜瀹氫箟棰滆壊閮戒笉瀛樺湪锛屽垯涓嶆洿鏂颁富棰橀鑹�
+  if (
+    builtinTypeColorPrimary ||
+    Reflect.has(theme, 'colorPrimary') ||
+    Reflect.has(theme, 'colorDestructive') ||
+    Reflect.has(theme, 'colorSuccess') ||
+    Reflect.has(theme, 'colorWarning')
+  ) {
+    // preferences.theme.colorPrimary = builtinTypeColorPrimary || colorPrimary;
+    updateMainColorVariables(preferences);
+  }
+
+  // 鏇存柊鍦嗚
+  if (Reflect.has(theme, 'radius')) {
+    document.documentElement.style.setProperty('--radius', `${radius}rem`);
+  }
+}
+
+/**
+ * 鏇存柊涓昏鐨� CSS 鍙橀噺
+ * @param  preference - 褰撳墠鍋忓ソ璁剧疆瀵硅薄锛屽畠鐨勯鑹插�煎皢琚浆鎹㈡垚 HSL 鏍煎紡骞惰缃负 CSS 鍙橀噺銆�
+ */
+function updateMainColorVariables(preference: Preferences) {
+  if (!preference.theme) {
+    return;
+  }
+  const { colorDestructive, colorPrimary, colorSuccess, colorWarning } =
+    preference.theme;
+
+  const colorVariables = generatorColorVariables([
+    { color: colorPrimary, name: 'primary' },
+    { alias: 'warning', color: colorWarning, name: 'yellow' },
+    { alias: 'success', color: colorSuccess, name: 'green' },
+    { alias: 'destructive', color: colorDestructive, name: 'red' },
+  ]);
+
+  // 瑕佽缃殑 CSS 鍙橀噺鏄犲皠
+  const colorMappings = {
+    '--green-500': '--success',
+    '--primary-500': '--primary',
+    '--red-500': '--destructive',
+    '--yellow-500': '--warning',
+  };
+
+  // 缁熶竴澶勭悊棰滆壊鍙橀噺鐨勬洿鏂�
+  Object.entries(colorMappings).forEach(([sourceVar, targetVar]) => {
+    const colorValue = colorVariables[sourceVar];
+    if (colorValue) {
+      document.documentElement.style.setProperty(targetVar, colorValue);
+    }
+  });
+
+  executeUpdateCSSVariables(colorVariables);
+}
+
+function isDarkTheme(theme: string) {
+  let dark = theme === 'dark';
+  if (theme === 'auto') {
+    dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
+  }
+  return dark;
+}
+
+export { isDarkTheme, updateCSSVariables };
diff --git a/eims-ui/packages/@core/preferences/src/use-preferences.ts b/eims-ui/packages/@core/preferences/src/use-preferences.ts
new file mode 100644
index 0000000..fc1e2de
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/src/use-preferences.ts
@@ -0,0 +1,232 @@
+import { computed } from 'vue';
+
+import { diff } from '@vben-core/shared/utils';
+
+import { preferencesManager } from './preferences';
+import { isDarkTheme } from './update-css-variables';
+
+function usePreferences() {
+  const preferences = preferencesManager.getPreferences();
+  const initialPreferences = preferencesManager.getInitialPreferences();
+  /**
+   * @zh_CN 璁$畻鍋忓ソ璁剧疆鐨勫彉鍖�
+   */
+  const diffPreference = computed(() => {
+    return diff(initialPreferences, preferences);
+  });
+
+  const appPreferences = computed(() => preferences.app);
+
+  const shortcutKeysPreferences = computed(() => preferences.shortcutKeys);
+
+  /**
+   * @zh_CN 鍒ゆ柇鏄惁涓烘殫榛戞ā寮�
+   * @param  preferences - 褰撳墠鍋忓ソ璁剧疆瀵硅薄锛屽畠鐨勪富棰樺�煎皢琚敤鏉ュ垽鏂槸鍚︿负鏆楅粦妯″紡銆�
+   * @returns 濡傛灉涓婚涓烘殫榛戞ā寮忥紝杩斿洖 true锛屽惁鍒欒繑鍥� false銆�
+   */
+  const isDark = computed(() => {
+    return isDarkTheme(preferences.theme.mode);
+  });
+
+  const locale = computed(() => {
+    return preferences.app.locale;
+  });
+
+  const isMobile = computed(() => {
+    return appPreferences.value.isMobile;
+  });
+
+  const theme = computed(() => {
+    return isDark.value ? 'dark' : 'light';
+  });
+
+  /**
+   * @zh_CN 甯冨眬鏂瑰紡
+   */
+  const layout = computed(() =>
+    isMobile.value ? 'sidebar-nav' : appPreferences.value.layout,
+  );
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず椤舵爮
+   */
+  const isShowHeaderNav = computed(() => {
+    return preferences.header.enable;
+  });
+
+  /**
+   * @zh_CN 鏄惁鍏ㄥ睆鏄剧ずcontent锛屼笉闇�瑕佷晶杈广�佸簳閮ㄣ�侀《閮ㄣ�乼ab鍖哄煙
+   */
+  const isFullContent = computed(
+    () => appPreferences.value.layout === 'full-content',
+  );
+
+  /**
+   * @zh_CN 鏄惁渚ц竟瀵艰埅妯″紡
+   */
+  const isSideNav = computed(
+    () => appPreferences.value.layout === 'sidebar-nav',
+  );
+
+  /**
+   * @zh_CN 鏄惁渚ц竟娣峰悎妯″紡
+   */
+  const isSideMixedNav = computed(
+    () => appPreferences.value.layout === 'sidebar-mixed-nav',
+  );
+
+  /**
+   * @zh_CN 鏄惁涓哄ご閮ㄥ鑸ā寮�
+   */
+  const isHeaderNav = computed(
+    () => appPreferences.value.layout === 'header-nav',
+  );
+
+  /**
+   * @zh_CN 鏄惁涓烘贩鍚堝鑸ā寮�
+   */
+  const isMixedNav = computed(
+    () => appPreferences.value.layout === 'mixed-nav',
+  );
+
+  /**
+   * @zh_CN 鏄惁鍖呭惈渚ц竟瀵艰埅妯″紡
+   */
+  const isSideMode = computed(() => {
+    return isMixedNav.value || isSideMixedNav.value || isSideNav.value;
+  });
+
+  const sidebarCollapsed = computed(() => {
+    return preferences.sidebar.collapsed;
+  });
+
+  /**
+   * @zh_CN 鏄惁寮�鍚痥eep-alive
+   * 鍦╰abs鍙浠ュ強寮�鍚痥eep-alive鐨勬儏鍐典笅鎵嶅紑鍚�
+   */
+  const keepAlive = computed(
+    () => preferences.tabbar.enable && preferences.tabbar.keepAlive,
+  );
+
+  /**
+   * @zh_CN 鐧诲綍娉ㄥ唽椤甸潰甯冨眬鏄惁涓哄乏渚�
+   */
+  const authPanelLeft = computed(() => {
+    return appPreferences.value.authPageLayout === 'panel-left';
+  });
+
+  /**
+   * @zh_CN 鐧诲綍娉ㄥ唽椤甸潰甯冨眬鏄惁涓哄乏渚�
+   */
+  const authPanelRight = computed(() => {
+    return appPreferences.value.authPageLayout === 'panel-right';
+  });
+
+  /**
+   * @zh_CN 鐧诲綍娉ㄥ唽椤甸潰甯冨眬鏄惁涓轰腑闂�
+   */
+  const authPanelCenter = computed(() => {
+    return appPreferences.value.authPageLayout === 'panel-center';
+  });
+
+  /**
+   * @zh_CN 鍐呭鏄惁宸茬粡鏈�澶у寲
+   * 鎺掗櫎 full-content妯″紡
+   */
+  const contentIsMaximize = computed(() => {
+    const headerIsHidden = preferences.header.hidden;
+    const sidebarIsHidden = preferences.sidebar.hidden;
+    return headerIsHidden && sidebarIsHidden && !isFullContent.value;
+  });
+
+  /**
+   * @zh_CN 鏄惁鍚敤鍏ㄥ眬鎼滅储蹇嵎閿�
+   */
+  const globalSearchShortcutKey = computed(() => {
+    const { enable, globalSearch } = shortcutKeysPreferences.value;
+    return enable && globalSearch;
+  });
+
+  /**
+   * @zh_CN 鏄惁鍚敤鍏ㄥ眬娉ㄩ攢蹇嵎閿�
+   */
+  const globalLogoutShortcutKey = computed(() => {
+    const { enable, globalLogout } = shortcutKeysPreferences.value;
+    return enable && globalLogout;
+  });
+
+  const globalLockScreenShortcutKey = computed(() => {
+    const { enable, globalLockScreen } = shortcutKeysPreferences.value;
+    return enable && globalLockScreen;
+  });
+
+  /**
+   * @zh_CN 鍋忓ソ璁剧疆鎸夐挳浣嶇疆
+   */
+  const preferencesButtonPosition = computed(() => {
+    const { enablePreferences, preferencesButtonPosition } = preferences.app;
+
+    // 濡傛灉娌℃湁鍚敤鍋忓ソ璁剧疆鎸夐挳
+    if (!enablePreferences) {
+      return {
+        fixed: false,
+        header: false,
+      };
+    }
+
+    const { header, sidebar } = preferences;
+    const headerHidden = header.hidden;
+    const sidebarHidden = sidebar.hidden;
+
+    const contentIsMaximize = headerHidden && sidebarHidden;
+
+    const isHeaderPosition = preferencesButtonPosition === 'header';
+
+    // 濡傛灉璁剧疆浜嗗浐瀹氫綅缃�
+    if (preferencesButtonPosition !== 'auto') {
+      return {
+        fixed: preferencesButtonPosition === 'fixed',
+        header: isHeaderPosition,
+      };
+    }
+
+    // 濡傛灉鏄叏灞忔ā寮忔垨鑰呮病鏈夊浐瀹氬湪椤堕儴锛�
+    const fixed =
+      contentIsMaximize ||
+      isFullContent.value ||
+      isMobile.value ||
+      !isShowHeaderNav.value;
+
+    return {
+      fixed,
+      header: !fixed,
+    };
+  });
+
+  return {
+    authPanelCenter,
+    authPanelLeft,
+    authPanelRight,
+    contentIsMaximize,
+    diffPreference,
+    globalLockScreenShortcutKey,
+    globalLogoutShortcutKey,
+    globalSearchShortcutKey,
+    isDark,
+    isFullContent,
+    isHeaderNav,
+    isMixedNav,
+    isMobile,
+    isSideMixedNav,
+    isSideMode,
+    isSideNav,
+    keepAlive,
+    layout,
+    locale,
+    preferencesButtonPosition,
+    sidebarCollapsed,
+    theme,
+  };
+}
+
+export { usePreferences };
diff --git a/eims-ui/packages/@core/preferences/tsconfig.json b/eims-ui/packages/@core/preferences/tsconfig.json
new file mode 100644
index 0000000..bbb8050
--- /dev/null
+++ b/eims-ui/packages/@core/preferences/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src", "__tests__"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/README.md b/eims-ui/packages/@core/ui-kit/README.md
new file mode 100644
index 0000000..a1746f6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/README.md
@@ -0,0 +1,3 @@
+# ui-kit
+
+鐢ㄤ簬绠$悊鍏叡缁勪欢銆佷笉鍚孶I缁勪欢搴撳皝瑁呯殑缁勪欢
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts b/eims-ui/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts
new file mode 100644
index 0000000..31aa355
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts
@@ -0,0 +1,189 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { FormApi } from '../src/form-api';
+
+describe('formApi', () => {
+  let formApi: FormApi;
+
+  beforeEach(() => {
+    formApi = new FormApi();
+  });
+
+  it('should initialize with default state', () => {
+    expect(formApi.state).toEqual(
+      expect.objectContaining({
+        actionWrapperClass: '',
+        collapsed: false,
+        collapsedRows: 1,
+        commonConfig: {},
+        handleReset: undefined,
+        handleSubmit: undefined,
+        layout: 'horizontal',
+        resetButtonOptions: {},
+        schema: [],
+        showCollapseButton: false,
+        showDefaultActions: true,
+        submitButtonOptions: {},
+        wrapperClass: 'grid-cols-1',
+      }),
+    );
+    expect(formApi.isMounted).toBe(false);
+  });
+
+  it('should mount form actions', async () => {
+    const formActions: any = {
+      meta: {},
+      resetForm: vi.fn(),
+      setFieldValue: vi.fn(),
+      setValues: vi.fn(),
+      submitForm: vi.fn(),
+      validate: vi.fn(),
+      values: { name: 'test' },
+    };
+
+    await formApi.mount(formActions);
+    expect(formApi.isMounted).toBe(true);
+    expect(formApi.form).toEqual(formActions);
+  });
+
+  it('should get values from form', async () => {
+    const formActions: any = {
+      meta: {},
+      values: { name: 'test' },
+    };
+
+    await formApi.mount(formActions);
+    const values = await formApi.getValues();
+    expect(values).toEqual({ name: 'test' });
+  });
+
+  it('should set field value', async () => {
+    const setFieldValueMock = vi.fn();
+    const formActions: any = {
+      meta: {},
+      setFieldValue: setFieldValueMock,
+      values: { name: 'test' },
+    };
+
+    await formApi.mount(formActions);
+    await formApi.setFieldValue('name', 'new value');
+    expect(setFieldValueMock).toHaveBeenCalledWith(
+      'name',
+      'new value',
+      undefined,
+    );
+  });
+
+  it('should reset form', async () => {
+    const resetFormMock = vi.fn();
+    const formActions: any = {
+      meta: {},
+      resetForm: resetFormMock,
+      values: { name: 'test' },
+    };
+
+    await formApi.mount(formActions);
+    await formApi.resetForm();
+    expect(resetFormMock).toHaveBeenCalled();
+  });
+
+  it('should call handleSubmit on submit', async () => {
+    const handleSubmitMock = vi.fn();
+    const formActions: any = {
+      meta: {},
+      submitForm: vi.fn().mockResolvedValue(true),
+      values: { name: 'test' },
+    };
+
+    const state = {
+      handleSubmit: handleSubmitMock,
+    };
+
+    formApi.setState(state);
+    await formApi.mount(formActions);
+
+    const result = await formApi.submitForm();
+    expect(formActions.submitForm).toHaveBeenCalled();
+    expect(handleSubmitMock).toHaveBeenCalledWith({ name: 'test' });
+    expect(result).toEqual({ name: 'test' });
+  });
+
+  it('should unmount form and reset state', () => {
+    formApi.unmount();
+    expect(formApi.isMounted).toBe(false);
+  });
+
+  it('should validate form', async () => {
+    const validateMock = vi.fn().mockResolvedValue(true);
+    const formActions: any = {
+      meta: {},
+      validate: validateMock,
+    };
+
+    await formApi.mount(formActions);
+    const isValid = await formApi.validate();
+    expect(validateMock).toHaveBeenCalled();
+    expect(isValid).toBe(true);
+  });
+});
+
+describe('updateSchema', () => {
+  let instance: FormApi;
+
+  beforeEach(() => {
+    instance = new FormApi();
+    instance.state = {
+      schema: [
+        { component: 'text', fieldName: 'name' },
+        { component: 'number', fieldName: 'age', label: 'Age' },
+      ],
+    };
+  });
+
+  it('should update the schema correctly when fieldName matches', () => {
+    const newSchema = [
+      { component: 'text', fieldName: 'name' },
+      { component: 'number', fieldName: 'age', label: 'Age' },
+    ];
+
+    instance.updateSchema(newSchema);
+
+    expect(instance.state?.schema?.[0]?.component).toBe('text');
+    expect(instance.state?.schema?.[1]?.label).toBe('Age');
+  });
+
+  it('should log an error if fieldName is missing in some items', () => {
+    const newSchema: any[] = [
+      { component: 'textarea', fieldName: 'name' },
+      { component: 'number' },
+    ];
+
+    const consoleErrorSpy = vi
+      .spyOn(console, 'error')
+      .mockImplementation(() => {});
+
+    instance.updateSchema(newSchema);
+
+    expect(consoleErrorSpy).toHaveBeenCalledWith(
+      'All items in the schema array must have a valid `fieldName` property to be updated',
+    );
+  });
+
+  it('should not update schema if fieldName does not match', () => {
+    const newSchema = [{ component: 'textarea', fieldName: 'unknown' }];
+
+    instance.updateSchema(newSchema);
+
+    expect(instance.state?.schema?.[0]?.component).toBe('text');
+    expect(instance.state?.schema?.[1]?.component).toBe('number');
+  });
+
+  it('should not update schema if updatedMap is empty', () => {
+    const newSchema: any[] = [{ component: 'textarea' }];
+
+    instance.updateSchema(newSchema);
+
+    expect(instance.state?.schema?.[0]?.component).toBe('text');
+    expect(instance.state?.schema?.[1]?.component).toBe('number');
+  });
+});
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/form-ui/build.config.ts
new file mode 100644
index 0000000..18eaa60
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/build.config.ts
@@ -0,0 +1,21 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/package.json b/eims-ui/packages/@core/ui-kit/form-ui/package.json
new file mode 100644
index 0000000..3b5f86e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/package.json
@@ -0,0 +1,51 @@
+{
+  "name": "@vben-core/form-ui",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/form-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vee-validate/zod": "catalog:",
+    "@vueuse/core": "catalog:",
+    "vee-validate": "catalog:",
+    "vue": "catalog:",
+    "zod": "catalog:",
+    "zod-defaults": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/form-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/components/form-actions.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/components/form-actions.vue
new file mode 100644
index 0000000..ac5505d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/components/form-actions.vue
@@ -0,0 +1,205 @@
+<script setup lang="ts">
+import { computed, toRaw, unref, watch } from 'vue';
+
+import { useSimpleLocale } from '@vben-core/composables';
+import { VbenExpandableArrow } from '@vben-core/shadcn-ui';
+import {
+  cn,
+  formatDate,
+  isFunction,
+  triggerWindowResize,
+} from '@vben-core/shared/utils';
+
+import { COMPONENT_MAP } from '../config';
+import { injectFormProps } from '../use-form-context';
+
+const { $t } = useSimpleLocale();
+
+const [rootProps, form] = injectFormProps();
+
+const collapsed = defineModel({ default: false });
+
+const resetButtonOptions = computed(() => {
+  return {
+    content: `${$t.value('reset')}`,
+    show: true,
+    ...unref(rootProps).resetButtonOptions,
+  };
+});
+
+const submitButtonOptions = computed(() => {
+  return {
+    content: `${$t.value('submit')}`,
+    show: true,
+    ...unref(rootProps).submitButtonOptions,
+  };
+});
+
+// const isQueryForm = computed(() => {
+//   return !!unref(rootProps).showCollapseButton;
+// });
+
+const queryFormStyle = computed(() => {
+  if (!unref(rootProps).actionWrapperClass) {
+    return {
+      'grid-column': `-2 / -1`,
+      marginLeft: 'auto',
+    };
+  }
+
+  return {};
+});
+
+async function handleSubmit(e: Event) {
+  e?.preventDefault();
+  e?.stopPropagation();
+  const { valid } = await form.validate();
+  if (!valid) {
+    return;
+  }
+
+  const values = handleRangeTimeValue(toRaw(form.values));
+  await unref(rootProps).handleSubmit?.(values);
+}
+
+async function handleReset(e: Event) {
+  e?.preventDefault();
+  e?.stopPropagation();
+  const props = unref(rootProps);
+
+  const values = toRaw(form.values);
+  // 娓呯悊鏃堕棿瀛楁
+  props.fieldMappingTime &&
+    props.fieldMappingTime.forEach(([_, [startTimeKey, endTimeKey]]) => {
+      delete values[startTimeKey];
+      delete values[endTimeKey];
+    });
+
+  if (isFunction(props.handleReset)) {
+    await props.handleReset?.(values);
+  } else {
+    form.resetForm();
+  }
+}
+
+function handleRangeTimeValue(values: Record<string, any>) {
+  const fieldMappingTime = unref(rootProps).fieldMappingTime;
+
+  if (!fieldMappingTime || !Array.isArray(fieldMappingTime)) {
+    return values;
+  }
+
+  fieldMappingTime.forEach(
+    ([field, [startTimeKey, endTimeKey], format = 'YYYY-MM-DD']) => {
+      if (startTimeKey && endTimeKey && values[field] === null) {
+        delete values[startTimeKey];
+        delete values[endTimeKey];
+      }
+
+      if (!values[field]) {
+        delete values[field];
+        return;
+      }
+
+      const [startTime, endTime] = values[field];
+      const [startTimeFormat, endTimeFormat] = Array.isArray(format)
+        ? format
+        : [format, format];
+
+      values[startTimeKey] = startTime
+        ? formatDate(startTime, startTimeFormat)
+        : undefined;
+      values[endTimeKey] = endTime
+        ? formatDate(endTime, endTimeFormat)
+        : undefined;
+
+      delete values[field];
+    },
+  );
+
+  return values;
+}
+
+watch(
+  () => collapsed.value,
+  () => {
+    const props = unref(rootProps);
+    if (props.collapseTriggerResize) {
+      triggerWindowResize();
+    }
+  },
+);
+
+defineExpose({
+  handleReset,
+  handleSubmit,
+});
+</script>
+<template>
+  <div
+    :class="
+      cn('col-span-full w-full pb-6 text-right', rootProps.actionWrapperClass)
+    "
+    :style="queryFormStyle"
+  >
+    <template v-if="rootProps.actionButtonsReverse">
+      <!-- 鎻愪氦鎸夐挳鍓� -->
+      <slot name="submit-before"></slot>
+
+      <component
+        :is="COMPONENT_MAP.PrimaryButton"
+        v-if="submitButtonOptions.show"
+        class="ml-3"
+        type="button"
+        @click="handleSubmit"
+        v-bind="submitButtonOptions"
+      >
+        {{ submitButtonOptions.content }}
+      </component>
+    </template>
+
+    <!-- 閲嶇疆鎸夐挳鍓� -->
+    <slot name="reset-before"></slot>
+
+    <component
+      :is="COMPONENT_MAP.DefaultButton"
+      v-if="resetButtonOptions.show"
+      class="ml-3"
+      type="button"
+      @click="handleReset"
+      v-bind="resetButtonOptions"
+    >
+      {{ resetButtonOptions.content }}
+    </component>
+
+    <template v-if="!rootProps.actionButtonsReverse">
+      <!-- 鎻愪氦鎸夐挳鍓� -->
+      <slot name="submit-before"></slot>
+
+      <component
+        :is="COMPONENT_MAP.PrimaryButton"
+        v-if="submitButtonOptions.show"
+        class="ml-3"
+        type="button"
+        @click="handleSubmit"
+        v-bind="submitButtonOptions"
+      >
+        {{ submitButtonOptions.content }}
+      </component>
+    </template>
+
+    <!-- 灞曞紑鎸夐挳鍓� -->
+    <slot name="expand-before"></slot>
+
+    <VbenExpandableArrow
+      v-if="rootProps.showCollapseButton"
+      v-model:model-value="collapsed"
+      class="ml-2"
+    >
+      <span>{{ collapsed ? $t('expand') : $t('collapse') }}</span>
+    </VbenExpandableArrow>
+
+    <!-- 灞曞紑鎸夐挳鍚� -->
+    <slot name="expand-after"></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/config.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/config.ts
new file mode 100644
index 0000000..95f5f3a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/config.ts
@@ -0,0 +1,84 @@
+import type {
+  BaseFormComponentType,
+  FormCommonConfig,
+  VbenFormAdapterOptions,
+} from './types';
+
+import type { Component } from 'vue';
+import { h } from 'vue';
+
+import {
+  VbenButton,
+  VbenCheckbox,
+  Input as VbenInput,
+  VbenInputCaptcha,
+  VbenInputPassword,
+  VbenPinInput,
+  VbenSelect,
+} from '@vben-core/shadcn-ui';
+import { globalShareState } from '@vben-core/shared/global-state';
+
+import { defineRule } from 'vee-validate';
+
+const DEFAULT_MODEL_PROP_NAME = 'modelValue';
+
+export const DEFAULT_FORM_COMMON_CONFIG: FormCommonConfig = {};
+
+export const COMPONENT_MAP: Record<BaseFormComponentType, Component> = {
+  DefaultButton: h(VbenButton, { size: 'sm', variant: 'outline' }),
+  PrimaryButton: h(VbenButton, { size: 'sm', variant: 'default' }),
+  VbenCheckbox,
+  VbenInput,
+  VbenInputCaptcha,
+  VbenInputPassword,
+  VbenPinInput,
+  VbenSelect,
+};
+
+export const COMPONENT_BIND_EVENT_MAP: Partial<
+  Record<BaseFormComponentType, string>
+> = {
+  VbenCheckbox: 'checked',
+};
+
+export function setupVbenForm<
+  T extends BaseFormComponentType = BaseFormComponentType,
+>(options: VbenFormAdapterOptions<T>) {
+  const { config, defineRules } = options;
+
+  const { disabledOnChangeListener = false, emptyStateValue = undefined } =
+    (config || {}) as FormCommonConfig;
+
+  Object.assign(DEFAULT_FORM_COMMON_CONFIG, {
+    disabledOnChangeListener,
+    emptyStateValue,
+  });
+
+  if (defineRules) {
+    for (const key of Object.keys(defineRules)) {
+      defineRule(key, defineRules[key as never]);
+    }
+  }
+
+  const baseModelPropName =
+    config?.baseModelPropName ?? DEFAULT_MODEL_PROP_NAME;
+  const modelPropNameMap = config?.modelPropNameMap as
+    | Record<BaseFormComponentType, string>
+    | undefined;
+
+  const components = globalShareState.getComponents();
+
+  for (const component of Object.keys(components)) {
+    const key = component as BaseFormComponentType;
+    COMPONENT_MAP[key] = components[component as never];
+
+    if (baseModelPropName !== DEFAULT_MODEL_PROP_NAME) {
+      COMPONENT_BIND_EVENT_MAP[key] = baseModelPropName;
+    }
+
+    // 瑕嗙洊鐗规畩缁勪欢鐨刴odelPropName
+    if (modelPropNameMap && modelPropNameMap[key]) {
+      COMPONENT_BIND_EVENT_MAP[key] = modelPropNameMap[key];
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-api.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-api.ts
new file mode 100644
index 0000000..585afaf
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-api.ts
@@ -0,0 +1,351 @@
+import type { Recordable } from '@vben-core/typings';
+import type {
+  FormState,
+  GenericObject,
+  ResetFormOpts,
+  ValidationOptions,
+} from 'vee-validate';
+
+import type { FormActions, FormSchema, VbenFormProps } from './types';
+
+import { toRaw } from 'vue';
+
+import { Store } from '@vben-core/shared/store';
+import {
+  bindMethods,
+  createMerge,
+  isDate,
+  isDayjsObject,
+  isFunction,
+  isObject,
+  mergeWithArrayOverride,
+  StateHandler,
+} from '@vben-core/shared/utils';
+
+function getDefaultState(): VbenFormProps {
+  return {
+    actionWrapperClass: '',
+    collapsed: false,
+    collapsedRows: 1,
+    collapseTriggerResize: false,
+    commonConfig: {},
+    handleReset: undefined,
+    handleSubmit: undefined,
+    handleValuesChange: undefined,
+    layout: 'horizontal',
+    resetButtonOptions: {},
+    schema: [],
+    showCollapseButton: false,
+    showDefaultActions: true,
+    submitButtonOptions: {},
+    submitOnChange: false,
+    submitOnEnter: false,
+    wrapperClass: 'grid-cols-1',
+  };
+}
+
+export class FormApi {
+  // 鏈�鍚庝竴娆$偣鍑绘彁浜ゆ椂鐨勮〃鍗曞��
+  private latestSubmissionValues: null | Recordable<any> = null;
+  private prevState: null | VbenFormProps = null;
+
+  // private api: Pick<VbenFormProps, 'handleReset' | 'handleSubmit'>;
+  public form = {} as FormActions;
+  isMounted = false;
+
+  public state: null | VbenFormProps = null;
+
+  stateHandler: StateHandler;
+
+  public store: Store<VbenFormProps>;
+
+  constructor(options: VbenFormProps = {}) {
+    const { ...storeState } = options;
+
+    const defaultState = getDefaultState();
+
+    this.store = new Store<VbenFormProps>(
+      {
+        ...defaultState,
+        ...storeState,
+      },
+      {
+        onUpdate: () => {
+          this.prevState = this.state;
+          this.state = this.store.state;
+          this.updateState();
+        },
+      },
+    );
+
+    this.state = this.store.state;
+    this.stateHandler = new StateHandler();
+    bindMethods(this);
+  }
+
+  private async getForm() {
+    if (!this.isMounted) {
+      // 绛夊緟form鎸傝浇
+      await this.stateHandler.waitForCondition();
+    }
+    if (!this.form?.meta) {
+      throw new Error('<VbenForm /> is not mounted');
+    }
+    return this.form;
+  }
+
+  private updateState() {
+    const currentSchema = this.state?.schema ?? [];
+    const prevSchema = this.prevState?.schema ?? [];
+    // 杩涜浜嗗垹闄chema鎿嶄綔
+    if (currentSchema.length < prevSchema.length) {
+      const currentFields = new Set(
+        currentSchema.map((item) => item.fieldName),
+      );
+      const deletedSchema = prevSchema.filter(
+        (item) => !currentFields.has(item.fieldName),
+      );
+
+      for (const schema of deletedSchema) {
+        this.form?.setFieldValue(schema.fieldName, undefined);
+      }
+    }
+  }
+
+  // 濡傛灉闇�瑕佸娆℃洿鏂扮姸鎬侊紝鍙互浣跨敤 batch 鏂规硶
+  batchStore(cb: () => void) {
+    this.store.batch(cb);
+  }
+
+  getLatestSubmissionValues() {
+    return this.latestSubmissionValues || {};
+  }
+
+  getState() {
+    return this.state;
+  }
+
+  async getValues() {
+    const form = await this.getForm();
+    return form.values;
+  }
+
+  merge(formApi: FormApi) {
+    const chain = [this, formApi];
+    const proxy = new Proxy(formApi, {
+      get(target: any, prop: any) {
+        if (prop === 'merge') {
+          return (nextFormApi: FormApi) => {
+            chain.push(nextFormApi);
+            return proxy;
+          };
+        }
+        if (prop === 'submitAllForm') {
+          return async (needMerge: boolean = true) => {
+            try {
+              const results = await Promise.all(
+                chain.map(async (api) => {
+                  const form = await api.getForm();
+                  const validateResult = await api.validate();
+                  if (!validateResult.valid) {
+                    return;
+                  }
+                  const rawValues = toRaw(form.values || {});
+                  return rawValues;
+                }),
+              );
+              if (needMerge) {
+                const mergedResults = Object.assign({}, ...results);
+                return mergedResults;
+              }
+              return results;
+            } catch (error) {
+              console.error('Validation error:', error);
+            }
+          };
+        }
+        return target[prop];
+      },
+    });
+
+    return proxy;
+  }
+
+  mount(formActions: FormActions) {
+    if (!this.isMounted) {
+      Object.assign(this.form, formActions);
+      this.stateHandler.setConditionTrue();
+      this.setLatestSubmissionValues({ ...toRaw(this.form.values) });
+      this.isMounted = true;
+    }
+  }
+
+  /**
+   * 鏍规嵁瀛楁鍚嶇Щ闄よ〃鍗曢」
+   * @param fields
+   */
+  async removeSchemaByFields(fields: string[]) {
+    const fieldSet = new Set(fields);
+    const schema = this.state?.schema ?? [];
+
+    const filterSchema = schema.filter((item) => !fieldSet.has(item.fieldName));
+
+    this.setState({
+      schema: filterSchema,
+    });
+  }
+
+  /**
+   * 閲嶇疆琛ㄥ崟
+   */
+  async resetForm(
+    state?: Partial<FormState<GenericObject>> | undefined,
+    opts?: Partial<ResetFormOpts>,
+  ) {
+    const form = await this.getForm();
+    return form.resetForm(state, opts);
+  }
+
+  async resetValidate() {
+    const form = await this.getForm();
+    const fields = Object.keys(form.errors.value);
+    fields.forEach((field) => {
+      form.setFieldError(field, undefined);
+    });
+  }
+
+  async setFieldValue(field: string, value: any, shouldValidate?: boolean) {
+    const form = await this.getForm();
+    form.setFieldValue(field, value, shouldValidate);
+  }
+
+  setLatestSubmissionValues(values: null | Recordable<any>) {
+    this.latestSubmissionValues = { ...toRaw(values) };
+  }
+
+  setState(
+    stateOrFn:
+      | ((prev: VbenFormProps) => Partial<VbenFormProps>)
+      | Partial<VbenFormProps>,
+  ) {
+    if (isFunction(stateOrFn)) {
+      this.store.setState((prev) => {
+        return mergeWithArrayOverride(stateOrFn(prev), prev);
+      });
+    } else {
+      this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev));
+    }
+  }
+
+  /**
+   * 璁剧疆琛ㄥ崟鍊�
+   * @param fields record
+   * @param filterFields 杩囨护涓嶅湪schema涓畾涔夌殑瀛楁 榛樿涓簍rue
+   * @param shouldValidate
+   */
+  async setValues(
+    fields: Record<string, any>,
+    filterFields: boolean = true,
+    shouldValidate: boolean = false,
+  ) {
+    const form = await this.getForm();
+    if (!filterFields) {
+      form.setValues(fields, shouldValidate);
+      return;
+    }
+
+    /**
+     * 鍚堝苟绠楁硶鏈夊緟鏀硅繘锛岀洰鍓嶇殑绠楁硶涓嶆敮鎸乷bject绫诲瀷鐨勫�笺��
+     * antd鐨勬棩鏈熸椂闂寸浉鍏崇粍浠剁殑鍊肩被鍨嬩负dayjs瀵硅薄
+     * element-plus鐨勬棩鏈熸椂闂寸浉鍏崇粍浠剁殑鍊肩被鍨嬪彲鑳戒负Date瀵硅薄
+     * 浠ヤ笂涓ょ绫诲瀷闇�瑕佹帓闄ゆ繁搴﹀悎骞�
+     */
+    const fieldMergeFn = createMerge((obj, key, value) => {
+      if (key in obj) {
+        obj[key] =
+          !Array.isArray(obj[key]) &&
+          isObject(obj[key]) &&
+          !isDayjsObject(obj[key]) &&
+          !isDate(obj[key])
+            ? fieldMergeFn(obj[key], value)
+            : value;
+      }
+      return true;
+    });
+    const filteredFields = fieldMergeFn(fields, form.values);
+    form.setValues(filteredFields, shouldValidate);
+  }
+
+  async submitForm(e?: Event) {
+    e?.preventDefault();
+    e?.stopPropagation();
+    const form = await this.getForm();
+    await form.submitForm();
+    const rawValues = toRaw(form.values || {});
+    await this.state?.handleSubmit?.(rawValues);
+
+    return rawValues;
+  }
+
+  unmount() {
+    this.form?.resetForm?.();
+    // this.state = null;
+    this.latestSubmissionValues = null;
+    this.isMounted = false;
+    this.stateHandler.reset();
+  }
+
+  updateSchema(schema: Partial<FormSchema>[]) {
+    const updated: Partial<FormSchema>[] = [...schema];
+    const hasField = updated.every(
+      (item) => Reflect.has(item, 'fieldName') && item.fieldName,
+    );
+
+    if (!hasField) {
+      console.error(
+        'All items in the schema array must have a valid `fieldName` property to be updated',
+      );
+      return;
+    }
+    const currentSchema = [...(this.state?.schema ?? [])];
+
+    const updatedMap: Record<string, any> = {};
+
+    updated.forEach((item) => {
+      if (item.fieldName) {
+        updatedMap[item.fieldName] = item;
+      }
+    });
+
+    currentSchema.forEach((schema, index) => {
+      const updatedData = updatedMap[schema.fieldName];
+      if (updatedData) {
+        currentSchema[index] = mergeWithArrayOverride(
+          updatedData,
+          schema,
+        ) as FormSchema;
+      }
+    });
+    this.setState({ schema: currentSchema });
+  }
+
+  async validate(opts?: Partial<ValidationOptions>) {
+    const form = await this.getForm();
+
+    const validateResult = await form.validate(opts);
+
+    if (Object.keys(validateResult?.errors ?? {}).length > 0) {
+      console.error('validate error', validateResult?.errors);
+    }
+    return validateResult;
+  }
+
+  async validateAndSubmitForm() {
+    const form = await this.getForm();
+    const { valid } = await form.validate();
+    if (!valid) {
+      return;
+    }
+    return await this.submitForm();
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/context.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/context.ts
new file mode 100644
index 0000000..af4b15c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/context.ts
@@ -0,0 +1,24 @@
+import type { FormRenderProps } from '../types';
+
+import { computed } from 'vue';
+
+import { createContext } from '@vben-core/shadcn-ui';
+
+export const [injectRenderFormProps, provideFormRenderProps] =
+  createContext<FormRenderProps>('FormRenderProps');
+
+export const useFormContext = () => {
+  const formRenderProps = injectRenderFormProps();
+
+  const isVertical = computed(() => formRenderProps.layout === 'vertical');
+
+  const componentMap = computed(() => formRenderProps.componentMap);
+  const componentBindEventMap = computed(
+    () => formRenderProps.componentBindEventMap,
+  );
+  return {
+    componentBindEventMap,
+    componentMap,
+    isVertical,
+  };
+};
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts
new file mode 100644
index 0000000..9881db1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts
@@ -0,0 +1,124 @@
+import type {
+  FormItemDependencies,
+  FormSchemaRuleType,
+  MaybeComponentProps,
+} from '../types';
+
+import { computed, ref, watch } from 'vue';
+
+import { isBoolean, isFunction } from '@vben-core/shared/utils';
+
+import { useFormValues } from 'vee-validate';
+
+import { injectRenderFormProps } from './context';
+
+export default function useDependencies(
+  getDependencies: () => FormItemDependencies | undefined,
+) {
+  const values = useFormValues();
+
+  const formRenderProps = injectRenderFormProps();
+
+  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+  const formApi = formRenderProps.form!;
+
+  if (!values) {
+    throw new Error('useDependencies should be used within <VbenForm>');
+  }
+
+  const isIf = ref(true);
+  const isDisabled = ref(false);
+  const isShow = ref(true);
+  const isRequired = ref(false);
+  const dynamicComponentProps = ref<MaybeComponentProps>({});
+  const dynamicRules = ref<FormSchemaRuleType>();
+
+  const triggerFieldValues = computed(() => {
+    // 璇ュ瓧娈靛彲鑳戒細琚涓瓧娈佃Е鍙�
+    const triggerFields = getDependencies()?.triggerFields ?? [];
+    return triggerFields.map((dep) => {
+      return values.value[dep];
+    });
+  });
+
+  const resetConditionState = () => {
+    isDisabled.value = false;
+    isIf.value = true;
+    isShow.value = true;
+    isRequired.value = false;
+    dynamicRules.value = undefined;
+    dynamicComponentProps.value = {};
+  };
+
+  watch(
+    [triggerFieldValues, getDependencies],
+    async ([_values, dependencies]) => {
+      if (!dependencies || !dependencies?.triggerFields?.length) {
+        return;
+      }
+      resetConditionState();
+      const {
+        componentProps,
+        disabled,
+        if: whenIf,
+        required,
+        rules,
+        show,
+        trigger,
+      } = dependencies;
+
+      // 1. 浼樺厛鍒ゆ柇if锛屽鏋渋f涓篺alse锛屽垯涓嶆覆鏌揹om锛屽悗缁垽鏂篃涓嶅啀鎵ц
+      const formValues = values.value;
+
+      if (isFunction(whenIf)) {
+        isIf.value = !!(await whenIf(formValues, formApi));
+        // 涓嶆覆鏌�
+        if (!isIf.value) return;
+      } else if (isBoolean(whenIf)) {
+        isIf.value = whenIf;
+        if (!isIf.value) return;
+      }
+
+      // 2. 鍒ゆ柇show锛屽鏋渟how涓篺alse锛屽垯闅愯棌
+      if (isFunction(show)) {
+        isShow.value = !!(await show(formValues, formApi));
+        if (!isShow.value) return;
+      } else if (isBoolean(show)) {
+        isShow.value = show;
+        if (!isShow.value) return;
+      }
+
+      if (isFunction(componentProps)) {
+        dynamicComponentProps.value = await componentProps(formValues, formApi);
+      }
+
+      if (isFunction(rules)) {
+        dynamicRules.value = await rules(formValues, formApi);
+      }
+
+      if (isFunction(disabled)) {
+        isDisabled.value = !!(await disabled(formValues, formApi));
+      } else if (isBoolean(disabled)) {
+        isDisabled.value = disabled;
+      }
+
+      if (isFunction(required)) {
+        isRequired.value = !!(await required(formValues, formApi));
+      }
+
+      if (isFunction(trigger)) {
+        await trigger(formValues, formApi);
+      }
+    },
+    { deep: true, immediate: true },
+  );
+
+  return {
+    dynamicComponentProps,
+    dynamicRules,
+    isDisabled,
+    isIf,
+    isRequired,
+    isShow,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts
new file mode 100644
index 0000000..a7b8ef4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts
@@ -0,0 +1,99 @@
+import type { FormRenderProps } from '../types';
+
+import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue';
+
+import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
+
+/**
+ * 鍔ㄦ�佽绠楄鏁�
+ */
+export function useExpandable(props: FormRenderProps) {
+  const wrapperRef = useTemplateRef<HTMLElement>('wrapperRef');
+  const rowMapping = ref<Record<number, number>>({});
+  // 鏄惁宸茬粡璁$畻杩囦竴娆�
+  const isCalculated = ref(false);
+
+  const breakpoints = useBreakpoints(breakpointsTailwind);
+
+  const keepFormItemIndex = computed(() => {
+    const rows = props.collapsedRows ?? 1;
+    const mapping = rowMapping.value;
+    let maxItem = 0;
+    for (let index = 1; index <= rows; index++) {
+      maxItem += mapping?.[index] ?? 0;
+    }
+    // 淇濇寔涓�琛�
+    return maxItem - 1 || 1;
+  });
+
+  watch(
+    [
+      () => props.showCollapseButton,
+      () => breakpoints.active().value,
+      () => props.schema?.length,
+    ],
+    async ([val]) => {
+      if (val) {
+        await nextTick();
+        rowMapping.value = {};
+        isCalculated.value = false;
+        await calculateRowMapping();
+      }
+    },
+  );
+
+  async function calculateRowMapping() {
+    if (!props.showCollapseButton) {
+      return;
+    }
+
+    await nextTick();
+    if (!wrapperRef.value) {
+      return;
+    }
+    // 灏忓睆骞曚笉璁$畻
+    // if (breakpoints.smaller('sm').value) {
+    //   // 淇濇寔涓�琛�
+    //   rowMapping.value = { 1: 2 };
+    //   return;
+    // }
+
+    const formItems = [...wrapperRef.value.children];
+
+    const container = wrapperRef.value;
+    const containerStyles = window.getComputedStyle(container);
+    const rowHeights = containerStyles
+      .getPropertyValue('grid-template-rows')
+      .split(' ');
+
+    const containerRect = container?.getBoundingClientRect();
+
+    formItems.forEach((el) => {
+      const itemRect = el.getBoundingClientRect();
+
+      // 璁$畻鍏冪礌鍦ㄧ鍑犺
+      const itemTop = itemRect.top - containerRect.top;
+      let rowStart = 0;
+      let cumulativeHeight = 0;
+
+      for (const [i, rowHeight] of rowHeights.entries()) {
+        cumulativeHeight += Number.parseFloat(rowHeight);
+        if (itemTop < cumulativeHeight) {
+          rowStart = i + 1;
+          break;
+        }
+      }
+      if (rowStart > (props?.collapsedRows ?? 1)) {
+        return;
+      }
+      rowMapping.value[rowStart] = (rowMapping.value[rowStart] ?? 0) + 1;
+      isCalculated.value = true;
+    });
+  }
+
+  onMounted(() => {
+    calculateRowMapping();
+  });
+
+  return { isCalculated, keepFormItemIndex, wrapperRef };
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
new file mode 100644
index 0000000..e9ee8f8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
@@ -0,0 +1,346 @@
+<script setup lang="ts">
+import type { ZodType } from 'zod';
+
+import type { FormSchema, MaybeComponentProps } from '../types';
+
+import { computed, nextTick, useTemplateRef, watch } from 'vue';
+
+import {
+  FormControl,
+  FormDescription,
+  FormField,
+  FormItem,
+  FormMessage,
+  VbenRenderContent,
+} from '@vben-core/shadcn-ui';
+import { cn, isFunction, isObject, isString } from '@vben-core/shared/utils';
+
+import { toTypedSchema } from '@vee-validate/zod';
+import { useFieldError, useFormValues } from 'vee-validate';
+
+import { injectRenderFormProps, useFormContext } from './context';
+import useDependencies from './dependencies';
+import FormLabel from './form-label.vue';
+import { isEventObjectLike } from './helper';
+
+interface Props extends FormSchema {}
+
+const {
+  commonComponentProps,
+  component,
+  componentProps,
+  dependencies,
+  description,
+  disabled,
+  disabledOnChangeListener,
+  emptyStateValue,
+  fieldName,
+  formFieldProps,
+  label,
+  labelClass,
+  labelWidth,
+  renderComponentContent,
+  rules,
+} = defineProps<
+  {
+    commonComponentProps: MaybeComponentProps;
+  } & Props
+>();
+
+const { componentBindEventMap, componentMap, isVertical } = useFormContext();
+const formRenderProps = injectRenderFormProps();
+const values = useFormValues();
+const errors = useFieldError(fieldName);
+const fieldComponentRef = useTemplateRef<HTMLInputElement>('fieldComponentRef');
+const formApi = formRenderProps.form;
+
+const isInValid = computed(() => errors.value?.length > 0);
+
+const FieldComponent = computed(() => {
+  const finalComponent = isString(component)
+    ? componentMap.value[component]
+    : component;
+  if (!finalComponent) {
+    // 缁勪欢鏈敞鍐�
+    console.warn(`Component ${component} is not registered`);
+  }
+  return finalComponent;
+});
+
+const {
+  dynamicComponentProps,
+  dynamicRules,
+  isDisabled,
+  isIf,
+  isRequired,
+  isShow,
+} = useDependencies(() => dependencies);
+
+const labelStyle = computed(() => {
+  return labelClass?.includes('w-') || isVertical.value
+    ? {}
+    : {
+        width: `${labelWidth}px`,
+      };
+});
+
+const currentRules = computed(() => {
+  return dynamicRules.value || rules;
+});
+
+const visible = computed(() => {
+  return isIf.value && isShow.value;
+});
+
+const shouldRequired = computed(() => {
+  if (!visible.value) {
+    return false;
+  }
+
+  if (!currentRules.value) {
+    return isRequired.value;
+  }
+
+  if (isRequired.value) {
+    return true;
+  }
+
+  if (isString(currentRules.value)) {
+    return ['required', 'selectRequired'].includes(currentRules.value);
+  }
+
+  let isOptional = currentRules?.value?.isOptional?.();
+
+  // 濡傛灉鏈夎缃粯璁ゅ�硷紝鍒欎笉鏄繀濉紝闇�瑕佺壒娈婂鐞�
+  const typeName = currentRules?.value?._def?.typeName;
+  if (typeName === 'ZodDefault') {
+    const innerType = currentRules?.value?._def.innerType;
+    if (innerType) {
+      isOptional = innerType.isOptional?.();
+    }
+  }
+
+  return !isOptional;
+});
+
+const fieldRules = computed(() => {
+  if (!visible.value) {
+    return null;
+  }
+
+  let rules = currentRules.value;
+  if (!rules) {
+    return isRequired.value ? 'required' : null;
+  }
+
+  if (isString(rules)) {
+    return rules;
+  }
+
+  const isOptional = !shouldRequired.value;
+  if (!isOptional) {
+    const unwrappedRules = (rules as any)?.unwrap?.();
+    if (unwrappedRules) {
+      rules = unwrappedRules;
+    }
+  }
+  return toTypedSchema(rules as ZodType);
+});
+
+const computedProps = computed(() => {
+  const finalComponentProps = isFunction(componentProps)
+    ? componentProps(values.value, formApi!)
+    : componentProps;
+
+  return {
+    ...commonComponentProps,
+    ...finalComponentProps,
+    ...dynamicComponentProps.value,
+  };
+});
+
+watch(
+  () => computedProps.value?.autofocus,
+  (value) => {
+    if (value === true) {
+      nextTick(() => {
+        autofocus();
+      });
+    }
+  },
+  { immediate: true },
+);
+
+const shouldDisabled = computed(() => {
+  return isDisabled.value || disabled || computedProps.value?.disabled;
+});
+
+const customContentRender = computed(() => {
+  if (!isFunction(renderComponentContent)) {
+    return {};
+  }
+  return renderComponentContent(values.value, formApi!);
+});
+
+const renderContentKey = computed(() => {
+  return Object.keys(customContentRender.value);
+});
+
+const fieldProps = computed(() => {
+  const rules = fieldRules.value;
+  return {
+    keepValue: true,
+    label,
+    ...(rules ? { rules } : {}),
+    ...(formFieldProps as Record<string, any>),
+  };
+});
+
+function fieldBindEvent(slotProps: Record<string, any>) {
+  const modelValue = slotProps.componentField.modelValue;
+  const handler = slotProps.componentField['onUpdate:modelValue'];
+
+  const bindEventField = isString(component)
+    ? componentBindEventMap.value?.[component]
+    : null;
+
+  let value = modelValue;
+  // antd design 鐨勪竴浜涚粍浠朵細浼犻�掍竴涓� event 瀵硅薄
+  if (modelValue && isObject(modelValue) && bindEventField) {
+    value = isEventObjectLike(modelValue)
+      ? modelValue?.target?.[bindEventField]
+      : (modelValue?.[bindEventField] ?? modelValue);
+  }
+
+  if (bindEventField) {
+    return {
+      [`onUpdate:${bindEventField}`]: handler,
+      [bindEventField]: value === undefined ? emptyStateValue : value,
+      onChange: disabledOnChangeListener
+        ? undefined
+        : (e: Record<string, any>) => {
+            const shouldUnwrap = isEventObjectLike(e);
+            const onChange = slotProps?.componentField?.onChange;
+            if (!shouldUnwrap) {
+              return onChange?.(e);
+            }
+
+            return onChange?.(e?.target?.[bindEventField] ?? e);
+          },
+      onInput: () => {},
+    };
+  }
+  return {};
+}
+
+function createComponentProps(slotProps: Record<string, any>) {
+  const bindEvents = fieldBindEvent(slotProps);
+
+  const binds = {
+    ...slotProps.componentField,
+    ...computedProps.value,
+    ...bindEvents,
+    ...(Reflect.has(computedProps.value, 'onChange')
+      ? { onChange: computedProps.value.onChange }
+      : {}),
+    ...(Reflect.has(computedProps.value, 'onInput')
+      ? { onInput: computedProps.value.onInput }
+      : {}),
+  };
+
+  return binds;
+}
+
+function autofocus() {
+  if (
+    fieldComponentRef.value &&
+    isFunction(fieldComponentRef.value.focus) &&
+    // 妫�鏌ュ綋鍓嶆槸鍚︽湁鍏冪礌琚仛鐒�
+    document.activeElement !== fieldComponentRef.value
+  ) {
+    fieldComponentRef.value?.focus?.();
+  }
+}
+</script>
+
+<template>
+  <FormField
+    v-if="isIf"
+    v-bind="fieldProps"
+    v-slot="slotProps"
+    :name="fieldName"
+  >
+    <FormItem
+      v-show="isShow"
+      :class="{
+        'form-valid-error': isInValid,
+        'flex-col': isVertical,
+        'flex-row items-center': !isVertical,
+      }"
+      class="flex pb-6"
+      v-bind="$attrs"
+    >
+      <FormLabel
+        v-if="!hideLabel"
+        :class="
+          cn(
+            'flex leading-6',
+            {
+              'mr-2 flex-shrink-0 justify-end': !isVertical,
+              'mb-1 flex-row': isVertical,
+            },
+            labelClass,
+          )
+        "
+        :help="help"
+        :required="shouldRequired && !hideRequiredMark"
+        :style="labelStyle"
+      >
+        {{ label }}
+      </FormLabel>
+      <div :class="cn('relative flex w-full items-center', wrapperClass)">
+        <FormControl :class="cn(controlClass)">
+          <slot
+            v-bind="{
+              ...slotProps,
+              ...createComponentProps(slotProps),
+              disabled: shouldDisabled,
+              isInValid,
+            }"
+          >
+            <component
+              :is="FieldComponent"
+              ref="fieldComponentRef"
+              :class="{
+                'border-destructive focus:border-destructive hover:border-destructive/80 focus:shadow-[0_0_0_2px_rgba(255,38,5,0.06)]':
+                  isInValid,
+              }"
+              v-bind="createComponentProps(slotProps)"
+              :disabled="shouldDisabled"
+            >
+              <template v-for="name in renderContentKey" :key="name" #[name]>
+                <VbenRenderContent
+                  :content="customContentRender[name]"
+                  v-bind="slotProps"
+                />
+              </template>
+              <!-- <slot></slot> -->
+            </component>
+          </slot>
+        </FormControl>
+        <!-- 鑷畾涔夊悗缂� -->
+        <div v-if="suffix" class="ml-1">
+          <VbenRenderContent :content="suffix" />
+        </div>
+
+        <FormDescription v-if="description">
+          <VbenRenderContent :content="description" />
+        </FormDescription>
+
+        <Transition name="slide-up">
+          <FormMessage class="absolute -bottom-[22px]" />
+        </Transition>
+      </div>
+    </FormItem>
+  </FormField>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue
new file mode 100644
index 0000000..f4876b5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { FormLabel, VbenHelpTooltip } from '@vben-core/shadcn-ui';
+import { cn } from '@vben-core/shared/utils';
+
+interface Props {
+  class?: string;
+  help?: string;
+  required?: boolean;
+}
+
+const props = defineProps<Props>();
+</script>
+
+<template>
+  <FormLabel :class="cn('flex items-center', props.class)">
+    <span v-if="required" class="text-destructive mr-[2px]">*</span>
+    <slot></slot>
+    <VbenHelpTooltip v-if="help" trigger-class="size-3.5 ml-1">
+      <!-- 鍙�氳繃\n鎹㈣ -->
+      <span class="whitespace-pre-line">
+        {{ help }}
+      </span>
+    </VbenHelpTooltip>
+  </FormLabel>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form.vue
new file mode 100644
index 0000000..348f03d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/form.vue
@@ -0,0 +1,160 @@
+<script setup lang="ts">
+import type { ZodTypeAny } from 'zod';
+
+import type {
+  FormCommonConfig,
+  FormRenderProps,
+  FormSchema,
+  FormShape,
+} from '../types';
+
+import { computed } from 'vue';
+
+import { Form } from '@vben-core/shadcn-ui';
+import { cn, isString, mergeWithArrayOverride } from '@vben-core/shared/utils';
+
+import { type GenericObject } from 'vee-validate';
+
+import { provideFormRenderProps } from './context';
+import { useExpandable } from './expandable';
+import FormField from './form-field.vue';
+import { getBaseRules, getDefaultValueInZodStack } from './helper';
+
+interface Props extends FormRenderProps {}
+
+const props = withDefaults(
+  defineProps<{ globalCommonConfig?: FormCommonConfig } & Props>(),
+  {
+    collapsedRows: 1,
+    commonConfig: () => ({}),
+    globalCommonConfig: () => ({}),
+    showCollapseButton: false,
+    wrapperClass: 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
+  },
+);
+
+const emits = defineEmits<{
+  submit: [event: any];
+}>();
+
+provideFormRenderProps(props);
+
+const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
+
+const shapes = computed(() => {
+  const resultShapes: FormShape[] = [];
+  props.schema?.forEach((schema) => {
+    const { fieldName } = schema;
+    const rules = schema.rules as ZodTypeAny;
+
+    let typeName = '';
+    if (rules && !isString(rules)) {
+      typeName = rules._def.typeName;
+    }
+
+    const baseRules = getBaseRules(rules) as ZodTypeAny;
+
+    resultShapes.push({
+      default: getDefaultValueInZodStack(rules),
+      fieldName,
+      required: !['ZodNullable', 'ZodOptional'].includes(typeName),
+      rules: baseRules,
+    });
+  });
+  return resultShapes;
+});
+
+const formComponent = computed(() => (props.form ? 'form' : Form));
+
+const formComponentProps = computed(() => {
+  return props.form
+    ? {
+        onSubmit: props.form.handleSubmit((val) => emits('submit', val)),
+      }
+    : {
+        onSubmit: (val: GenericObject) => emits('submit', val),
+      };
+});
+
+const formCollapsed = computed(() => {
+  return props.collapsed && isCalculated.value;
+});
+
+const computedSchema = computed(
+  (): ({
+    commonComponentProps: Record<string, any>;
+    formFieldProps: Record<string, any>;
+  } & Omit<FormSchema, 'formFieldProps'>)[] => {
+    const {
+      componentProps = {},
+      controlClass = '',
+      disabled,
+      disabledOnChangeListener = false,
+      emptyStateValue = undefined,
+      formFieldProps = {},
+      formItemClass = '',
+      hideLabel = false,
+      hideRequiredMark = false,
+      labelClass = '',
+      labelWidth = 100,
+      wrapperClass = '',
+    } = mergeWithArrayOverride(props.commonConfig, props.globalCommonConfig);
+    return (props.schema || []).map((schema, index) => {
+      const keepIndex = keepFormItemIndex.value;
+
+      const hidden =
+        // 鎶樺彔鐘舵�� & 鏄剧ず鎶樺彔鎸夐挳 & 褰撳墠绱㈠紩澶т簬淇濈暀绱㈠紩
+        props.showCollapseButton && !!formCollapsed.value && keepIndex
+          ? keepIndex <= index
+          : false;
+
+      return {
+        disabled,
+        disabledOnChangeListener,
+        emptyStateValue,
+        hideLabel,
+        hideRequiredMark,
+        labelWidth,
+        wrapperClass,
+        ...schema,
+        commonComponentProps: componentProps,
+        componentProps: schema.componentProps,
+        controlClass: cn(controlClass, schema.controlClass),
+        formFieldProps: {
+          ...formFieldProps,
+          ...schema.formFieldProps,
+        },
+        formItemClass: cn(
+          'flex-shrink-0',
+          { hidden },
+          formItemClass,
+          schema.formItemClass,
+        ),
+        labelClass: cn(labelClass, schema.labelClass),
+      };
+    });
+  },
+);
+</script>
+
+<template>
+  <component :is="formComponent" v-bind="formComponentProps">
+    <div ref="wrapperRef" :class="wrapperClass" class="grid">
+      <template v-for="cSchema in computedSchema" :key="cSchema.fieldName">
+        <!-- <div v-if="$slots[cSchema.fieldName]" :class="cSchema.formItemClass">
+          <slot :definition="cSchema" :name="cSchema.fieldName"> </slot>
+        </div> -->
+        <FormField
+          v-bind="cSchema"
+          :class="cSchema.formItemClass"
+          :rules="cSchema.rules"
+        >
+          <template #default="slotProps">
+            <slot v-bind="slotProps" :name="cSchema.fieldName"> </slot>
+          </template>
+        </FormField>
+      </template>
+      <slot :shapes="shapes"></slot>
+    </div>
+  </component>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/helper.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/helper.ts
new file mode 100644
index 0000000..cdb3999
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/helper.ts
@@ -0,0 +1,60 @@
+import type {
+  AnyZodObject,
+  ZodDefault,
+  ZodEffects,
+  ZodNumber,
+  ZodString,
+  ZodTypeAny,
+} from 'zod';
+
+import { isObject, isString } from '@vben-core/shared/utils';
+
+/**
+ * Get the lowest level Zod type.
+ * This will unpack optionals, refinements, etc.
+ */
+export function getBaseRules<
+  ChildType extends AnyZodObject | ZodTypeAny = ZodTypeAny,
+>(schema: ChildType | ZodEffects<ChildType>): ChildType | null {
+  if (!schema || isString(schema)) return null;
+  if ('innerType' in schema._def)
+    return getBaseRules(schema._def.innerType as ChildType);
+
+  if ('schema' in schema._def)
+    return getBaseRules(schema._def.schema as ChildType);
+
+  return schema as ChildType;
+}
+
+/**
+ * Search for a "ZodDefault" in the Zod stack and return its value.
+ */
+export function getDefaultValueInZodStack(schema: ZodTypeAny): any {
+  if (!schema || isString(schema)) {
+    return;
+  }
+  const typedSchema = schema as unknown as ZodDefault<ZodNumber | ZodString>;
+
+  if (typedSchema._def.typeName === 'ZodDefault')
+    return typedSchema._def.defaultValue();
+
+  if ('innerType' in typedSchema._def) {
+    return getDefaultValueInZodStack(
+      typedSchema._def.innerType as unknown as ZodTypeAny,
+    );
+  }
+  if ('schema' in typedSchema._def) {
+    return getDefaultValueInZodStack(
+      (typedSchema._def as any).schema as ZodTypeAny,
+    );
+  }
+
+  return undefined;
+}
+
+export function isEventObjectLike(obj: any) {
+  if (!obj || !isObject(obj)) {
+    return false;
+  }
+  return Reflect.has(obj, 'target') && Reflect.has(obj, 'stopPropagation');
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/index.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/index.ts
new file mode 100644
index 0000000..7fc1706
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/form-render/index.ts
@@ -0,0 +1,3 @@
+export { default as Form } from './form.vue';
+export { default as FormField } from './form-field.vue';
+export { default as FormLabel } from './form-label.vue';
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/index.ts
new file mode 100644
index 0000000..67ed4a5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/index.ts
@@ -0,0 +1,12 @@
+export { setupVbenForm } from './config';
+
+export type {
+  BaseFormComponentType,
+  ExtendedFormApi,
+  FormSchema as VbenFormSchema,
+  VbenFormProps,
+} from './types';
+
+export * from './use-vben-form';
+// export { default as VbenForm } from './vben-form.vue';
+export * as z from 'zod';
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/types.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/types.ts
new file mode 100644
index 0000000..2f8a7be
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/types.ts
@@ -0,0 +1,389 @@
+import type { VbenButtonProps } from '@vben-core/shadcn-ui';
+import type { ClassType } from '@vben-core/typings';
+import type { FieldOptions, FormContext, GenericObject } from 'vee-validate';
+import type { ZodTypeAny } from 'zod';
+
+import type { FormApi } from './form-api';
+
+import type { Component, HtmlHTMLAttributes, Ref } from 'vue';
+
+export type FormLayout = 'horizontal' | 'vertical';
+
+export type BaseFormComponentType =
+  | 'DefaultButton'
+  | 'PrimaryButton'
+  | 'VbenCheckbox'
+  | 'VbenInput'
+  | 'VbenInputPassword'
+  | 'VbenPinInput'
+  | 'VbenSelect'
+  | (Record<never, never> & string);
+
+type Breakpoints = '' | '2xl:' | '3xl:' | 'lg:' | 'md:' | 'sm:' | 'xl:';
+
+type GridCols = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
+
+export type WrapperClassType =
+  | `${Breakpoints}grid-cols-${GridCols}`
+  | (Record<never, never> & string);
+
+export type FormItemClassType =
+  | `${Breakpoints}cols-end-${'auto' | GridCols}`
+  | `${Breakpoints}cols-span-${'auto' | 'full' | GridCols}`
+  | `${Breakpoints}cols-start-${'auto' | GridCols}`
+  | (Record<never, never> & string)
+  | WrapperClassType;
+
+export type FormFieldOptions = Partial<
+  {
+    validateOnBlur?: boolean;
+    validateOnChange?: boolean;
+    validateOnInput?: boolean;
+    validateOnModelUpdate?: boolean;
+  } & FieldOptions
+>;
+
+export interface FormShape {
+  /** 榛樿鍊� */
+  default?: any;
+  /** 瀛楁鍚� */
+  fieldName: string;
+  /** 鏄惁蹇呭~ */
+  required?: boolean;
+  rules?: ZodTypeAny;
+}
+
+export type MaybeComponentPropKey =
+  | 'options'
+  | 'placeholder'
+  | 'title'
+  | keyof HtmlHTMLAttributes
+  | (Record<never, never> & string);
+
+export type MaybeComponentProps = { [K in MaybeComponentPropKey]?: any };
+
+export type FormActions = FormContext<GenericObject>;
+
+export type CustomRenderType = (() => Component | string) | string;
+
+export type FormSchemaRuleType =
+  | 'required'
+  | 'selectRequired'
+  | null
+  | (Record<never, never> & string)
+  | ZodTypeAny;
+
+type FormItemDependenciesCondition<T = boolean | PromiseLike<boolean>> = (
+  value: Partial<Record<string, any>>,
+  actions: FormActions,
+) => T;
+
+type FormItemDependenciesConditionWithRules = (
+  value: Partial<Record<string, any>>,
+  actions: FormActions,
+) => FormSchemaRuleType | PromiseLike<FormSchemaRuleType>;
+
+type FormItemDependenciesConditionWithProps = (
+  value: Partial<Record<string, any>>,
+  actions: FormActions,
+) => MaybeComponentProps | PromiseLike<MaybeComponentProps>;
+
+export interface FormItemDependencies {
+  /**
+   * 缁勪欢鍙傛暟
+   * @returns 缁勪欢鍙傛暟
+   */
+  componentProps?: FormItemDependenciesConditionWithProps;
+  /**
+   * 鏄惁绂佺敤
+   * @returns 鏄惁绂佺敤
+   */
+  disabled?: boolean | FormItemDependenciesCondition;
+  /**
+   * 鏄惁娓叉煋锛堝垹闄om锛�
+   * @returns 鏄惁娓叉煋
+   */
+  if?: boolean | FormItemDependenciesCondition;
+  /**
+   * 鏄惁蹇呭~
+   * @returns 鏄惁蹇呭~
+   */
+  required?: FormItemDependenciesCondition;
+  /**
+   * 瀛楁瑙勫垯
+   */
+  rules?: FormItemDependenciesConditionWithRules;
+  /**
+   * 鏄惁闅愯棌(Css)
+   * @returns 鏄惁闅愯棌
+   */
+  show?: boolean | FormItemDependenciesCondition;
+  /**
+   * 浠绘剰瑙﹀彂閮戒細鎵ц
+   */
+  trigger?: FormItemDependenciesCondition<void>;
+  /**
+   * 瑙﹀彂瀛楁
+   */
+  triggerFields: string[];
+}
+
+type ComponentProps =
+  | ((
+      value: Partial<Record<string, any>>,
+      actions: FormActions,
+    ) => MaybeComponentProps)
+  | MaybeComponentProps;
+
+export interface FormCommonConfig {
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刾rops
+   */
+  componentProps?: ComponentProps;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬帶浠舵牱寮�
+   */
+  controlClass?: string;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勭鐢ㄧ姸鎬�
+   * @default false
+   */
+  disabled?: boolean;
+  /**
+   * 鏄惁绂佺敤鎵�鏈夎〃鍗曢」鐨刢hange浜嬩欢鐩戝惉
+   * @default false
+   */
+  disabledOnChangeListener?: boolean;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勭┖鐘舵�佸��,榛樿閮芥槸undefined锛宯aive-ui鐨勭┖鐘舵�佸�兼槸null
+   */
+  emptyStateValue?: null | undefined;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬帶浠舵牱寮�
+   * @default {}
+   */
+  formFieldProps?: FormFieldOptions;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨勬爡鏍煎竷灞�
+   * @default ""
+   */
+  formItemClass?: string;
+  /**
+   * 闅愯棌鎵�鏈夎〃鍗曢」label
+   * @default false
+   */
+  hideLabel?: boolean;
+  /**
+   * 鏄惁闅愯棌蹇呭~鏍囪
+   * @default false
+   */
+  hideRequiredMark?: boolean;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刲abel鏍峰紡
+   * @default ""
+   */
+  labelClass?: string;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨刲abel瀹藉害
+   */
+  labelWidth?: number;
+  /**
+   * 鎵�鏈夎〃鍗曢」鐨剋rapper鏍峰紡
+   */
+  wrapperClass?: string;
+}
+
+type RenderComponentContentType = (
+  value: Partial<Record<string, any>>,
+  api: FormActions,
+) => Record<string, any>;
+
+export type HandleSubmitFn = (
+  values: Record<string, any>,
+) => Promise<void> | void;
+
+export type HandleResetFn = (
+  values: Record<string, any>,
+) => Promise<void> | void;
+
+export type FieldMappingTime = [
+  string,
+  [string, string],
+  ([string, string] | string)?,
+][];
+
+export interface FormSchema<
+  T extends BaseFormComponentType = BaseFormComponentType,
+> extends FormCommonConfig {
+  /** 缁勪欢 */
+  component: Component | T;
+  /** 缁勪欢鍙傛暟 */
+  componentProps?: ComponentProps;
+  /** 榛樿鍊� */
+  defaultValue?: any;
+  /** 渚濊禆 */
+  dependencies?: FormItemDependencies;
+  /** 鎻忚堪 */
+  description?: string;
+  /** 瀛楁鍚� */
+  fieldName: string;
+  /** 甯姪淇℃伅 */
+  help?: string;
+  /** 琛ㄥ崟椤� */
+  label?: string;
+  // 鑷畾涔夌粍浠跺唴閮ㄦ覆鏌�
+  renderComponentContent?: RenderComponentContentType;
+  /** 瀛楁瑙勫垯 */
+  rules?: FormSchemaRuleType;
+  /** 鍚庣紑 */
+  suffix?: CustomRenderType;
+}
+
+export interface FormFieldProps extends FormSchema {
+  required?: boolean;
+}
+
+export interface FormRenderProps<
+  T extends BaseFormComponentType = BaseFormComponentType,
+> {
+  /**
+   * 鏄惁灞曞紑锛屽湪showCollapseButton=true涓嬬敓鏁�
+   */
+  collapsed?: boolean;
+  /**
+   * 鎶樺彔鏃朵繚鎸佽鏁�
+   * @default 1
+   */
+  collapsedRows?: number;
+  /**
+   * 鏄惁瑙﹀彂resize浜嬩欢
+   * @default false
+   */
+  collapseTriggerResize?: boolean;
+  /**
+   * 琛ㄥ崟椤归�氱敤鍚庡閰嶇疆锛屽綋瀛愰」鐩病閰嶇疆鏃朵娇鐢ㄨ繖閲岀殑閰嶇疆锛屽瓙椤圭洰閰嶇疆浼樺厛绾ч珮浜庢閰嶇疆
+   */
+  commonConfig?: FormCommonConfig;
+  /**
+   * 缁勪欢v-model浜嬩欢缁戝畾
+   */
+  componentBindEventMap?: Partial<Record<BaseFormComponentType, string>>;
+  /**
+   * 缁勪欢闆嗗悎
+   */
+  componentMap: Record<BaseFormComponentType, Component>;
+  /**
+   * 琛ㄥ崟瀹炰緥
+   */
+  form?: FormContext<GenericObject>;
+  /**
+   * 琛ㄥ崟椤瑰竷灞�
+   */
+  layout?: FormLayout;
+  /**
+   * 琛ㄥ崟瀹氫箟
+   */
+  schema?: FormSchema<T>[];
+  /**
+   * 鏄惁鏄剧ず灞曞紑/鎶樺彔
+   */
+  showCollapseButton?: boolean;
+  /**
+   * 琛ㄥ崟鏍呮牸甯冨眬
+   * @default "grid-cols-1"
+   */
+  wrapperClass?: WrapperClassType;
+}
+
+export interface ActionButtonOptions extends VbenButtonProps {
+  [key: string]: any;
+  content?: string;
+  show?: boolean;
+}
+
+export interface VbenFormProps<
+  T extends BaseFormComponentType = BaseFormComponentType,
+> extends Omit<
+    FormRenderProps<T>,
+    'componentBindEventMap' | 'componentMap' | 'form'
+  > {
+  /**
+   * 鎿嶄綔鎸夐挳鏄惁鍙嶈浆锛堟彁浜ゆ寜閽墠缃級
+   */
+  actionButtonsReverse?: boolean;
+  /**
+   * 琛ㄥ崟鎿嶄綔鍖哄煙class
+   */
+  actionWrapperClass?: ClassType;
+  /**
+   * 琛ㄥ崟瀛楁鏄犲皠鎴愭椂闂存牸寮�
+   */
+  fieldMappingTime?: FieldMappingTime;
+  /**
+   * 琛ㄥ崟閲嶇疆鍥炶皟
+   */
+  handleReset?: HandleResetFn;
+  /**
+   * 琛ㄥ崟鎻愪氦鍥炶皟
+   */
+  handleSubmit?: HandleSubmitFn;
+  /**
+   * 琛ㄥ崟鍊煎彉鍖栧洖璋�
+   */
+  handleValuesChange?: (values: Record<string, any>) => void;
+  /**
+   * 閲嶇疆鎸夐挳鍙傛暟
+   */
+  resetButtonOptions?: ActionButtonOptions;
+  /**
+   * 鏄惁鏄剧ず榛樿鎿嶄綔鎸夐挳
+   * @default true
+   */
+  showDefaultActions?: boolean;
+
+  /**
+   * 鎻愪氦鎸夐挳鍙傛暟
+   */
+  submitButtonOptions?: ActionButtonOptions;
+
+  /**
+   * 鏄惁鍦ㄥ瓧娈靛�兼敼鍙樻椂鎻愪氦琛ㄥ崟
+   * @default false
+   */
+  submitOnChange?: boolean;
+
+  /**
+   * 鏄惁鍦ㄥ洖杞︽椂鎻愪氦琛ㄥ崟
+   * @default false
+   */
+  submitOnEnter?: boolean;
+}
+
+export type ExtendedFormApi = {
+  useStore: <T = NoInfer<VbenFormProps>>(
+    selector?: (state: NoInfer<VbenFormProps>) => T,
+  ) => Readonly<Ref<T>>;
+} & FormApi;
+
+export interface VbenFormAdapterOptions<
+  T extends BaseFormComponentType = BaseFormComponentType,
+> {
+  config?: {
+    baseModelPropName?: string;
+    disabledOnChangeListener?: boolean;
+    emptyStateValue?: null | undefined;
+    modelPropNameMap?: Partial<Record<T, string>>;
+  };
+  defineRules?: {
+    required?: (
+      value: any,
+      params: any,
+      ctx: Record<string, any>,
+    ) => boolean | string;
+    selectRequired?: (
+      value: any,
+      params: any,
+      ctx: Record<string, any>,
+    ) => boolean | string;
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/use-form-context.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/use-form-context.ts
new file mode 100644
index 0000000..05838fc
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/use-form-context.ts
@@ -0,0 +1,59 @@
+import type { FormActions, VbenFormProps } from './types';
+
+import { computed, type ComputedRef, unref, useSlots } from 'vue';
+
+import { createContext } from '@vben-core/shadcn-ui';
+import { isString } from '@vben-core/shared/utils';
+
+import { useForm } from 'vee-validate';
+import { object, type ZodRawShape } from 'zod';
+import { getDefaultsForSchema } from 'zod-defaults';
+
+export const [injectFormProps, provideFormProps] =
+  createContext<[ComputedRef<VbenFormProps> | VbenFormProps, FormActions]>(
+    'VbenFormProps',
+  );
+
+export function useFormInitial(
+  props: ComputedRef<VbenFormProps> | VbenFormProps,
+) {
+  const slots = useSlots();
+  const initialValues = generateInitialValues();
+
+  const form = useForm({
+    ...(Object.keys(initialValues)?.length ? { initialValues } : {}),
+  });
+
+  const delegatedSlots = computed(() => {
+    const resultSlots: string[] = [];
+
+    for (const key of Object.keys(slots)) {
+      if (key !== 'default') {
+        resultSlots.push(key);
+      }
+    }
+    return resultSlots;
+  });
+
+  function generateInitialValues() {
+    const initialValues: Record<string, any> = {};
+
+    const zodObject: ZodRawShape = {};
+    (unref(props).schema || []).forEach((item) => {
+      if (Reflect.has(item, 'defaultValue')) {
+        initialValues[item.fieldName] = item.defaultValue;
+      } else if (item.rules && !isString(item.rules)) {
+        zodObject[item.fieldName] = item.rules;
+      }
+    });
+
+    const schemaInitialValues = getDefaultsForSchema(object(zodObject));
+
+    return { ...initialValues, ...schemaInitialValues };
+  }
+
+  return {
+    delegatedSlots,
+    form,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/use-vben-form.ts b/eims-ui/packages/@core/ui-kit/form-ui/src/use-vben-form.ts
new file mode 100644
index 0000000..f5d07b9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/use-vben-form.ts
@@ -0,0 +1,50 @@
+import type {
+  BaseFormComponentType,
+  ExtendedFormApi,
+  VbenFormProps,
+} from './types';
+
+import { defineComponent, h, isReactive, onBeforeUnmount, watch } from 'vue';
+
+import { useStore } from '@vben-core/shared/store';
+
+import { FormApi } from './form-api';
+import VbenUseForm from './vben-use-form.vue';
+
+export function useVbenForm<
+  T extends BaseFormComponentType = BaseFormComponentType,
+>(options: VbenFormProps<T>) {
+  const IS_REACTIVE = isReactive(options);
+  const api = new FormApi(options);
+  const extendedApi: ExtendedFormApi = api as never;
+  extendedApi.useStore = (selector) => {
+    return useStore(api.store, selector);
+  };
+
+  const Form = defineComponent(
+    (props: VbenFormProps, { attrs, slots }) => {
+      onBeforeUnmount(() => {
+        api.unmount();
+      });
+      api.setState({ ...props, ...attrs });
+      return () =>
+        h(VbenUseForm, { ...props, ...attrs, formApi: extendedApi }, slots);
+    },
+    {
+      inheritAttrs: false,
+      name: 'VbenUseForm',
+    },
+  );
+  // Add reactivity support
+  if (IS_REACTIVE) {
+    watch(
+      () => options.schema,
+      () => {
+        api.setState({ schema: options.schema });
+      },
+      { immediate: true },
+    );
+  }
+
+  return [Form, extendedApi] as const;
+}
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/vben-form.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/vben-form.vue
new file mode 100644
index 0000000..260e75c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/vben-form.vue
@@ -0,0 +1,77 @@
+<script setup lang="ts">
+import type { VbenFormProps } from './types';
+
+import { ref, watchEffect } from 'vue';
+
+import { useForwardPropsEmits } from '@vben-core/composables';
+
+import FormActions from './components/form-actions.vue';
+import {
+  COMPONENT_BIND_EVENT_MAP,
+  COMPONENT_MAP,
+  DEFAULT_FORM_COMMON_CONFIG,
+} from './config';
+import { Form } from './form-render';
+import { provideFormProps, useFormInitial } from './use-form-context';
+
+// 閫氳繃 extends 浼氬鑷寸儹鏇存柊鍗℃
+interface Props extends VbenFormProps {}
+const props = withDefaults(defineProps<Props>(), {
+  actionWrapperClass: '',
+  collapsed: false,
+  collapsedRows: 1,
+  commonConfig: () => ({}),
+  handleReset: undefined,
+  handleSubmit: undefined,
+  layout: 'horizontal',
+  resetButtonOptions: () => ({}),
+  showCollapseButton: false,
+  showDefaultActions: true,
+  submitButtonOptions: () => ({}),
+  wrapperClass: 'grid-cols-1',
+});
+
+const forward = useForwardPropsEmits(props);
+
+const currentCollapsed = ref(false);
+
+const { delegatedSlots, form } = useFormInitial(props);
+
+provideFormProps([props, form]);
+
+const handleUpdateCollapsed = (value: boolean) => {
+  currentCollapsed.value = !!value;
+};
+
+watchEffect(() => {
+  currentCollapsed.value = props.collapsed;
+});
+</script>
+
+<template>
+  <Form
+    v-bind="forward"
+    :collapsed="currentCollapsed"
+    :component-bind-event-map="COMPONENT_BIND_EVENT_MAP"
+    :component-map="COMPONENT_MAP"
+    :form="form"
+    :global-common-config="DEFAULT_FORM_COMMON_CONFIG"
+  >
+    <template
+      v-for="slotName in delegatedSlots"
+      :key="slotName"
+      #[slotName]="slotProps"
+    >
+      <slot :name="slotName" v-bind="slotProps"></slot>
+    </template>
+    <template #default="slotProps">
+      <slot v-bind="slotProps">
+        <FormActions
+          v-if="showDefaultActions"
+          :model-value="currentCollapsed"
+          @update:model-value="handleUpdateCollapsed"
+        />
+      </slot>
+    </template>
+  </Form>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/src/vben-use-form.vue b/eims-ui/packages/@core/ui-kit/form-ui/src/vben-use-form.vue
new file mode 100644
index 0000000..855472d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/src/vben-use-form.vue
@@ -0,0 +1,113 @@
+<script setup lang="ts">
+import type { ExtendedFormApi, VbenFormProps } from './types';
+
+// import { toRaw, watch } from 'vue';
+
+import { useForwardPriorityValues } from '@vben-core/composables';
+// import { isFunction } from '@vben-core/shared/utils';
+
+import { toRaw, useTemplateRef, watch } from 'vue';
+
+import { useDebounceFn } from '@vueuse/core';
+
+import FormActions from './components/form-actions.vue';
+import {
+  COMPONENT_BIND_EVENT_MAP,
+  COMPONENT_MAP,
+  DEFAULT_FORM_COMMON_CONFIG,
+} from './config';
+import { Form } from './form-render';
+import { provideFormProps, useFormInitial } from './use-form-context';
+// 閫氳繃 extends 浼氬鑷寸儹鏇存柊鍗℃锛屾墍浠ラ噸澶嶅啓浜嗕竴閬�
+interface Props extends VbenFormProps {
+  formApi: ExtendedFormApi;
+}
+
+const props = defineProps<Props>();
+
+const formActionsRef = useTemplateRef<typeof FormActions>('formActionsRef');
+
+const state = props.formApi?.useStore?.();
+
+const forward = useForwardPriorityValues(props, state);
+
+const { delegatedSlots, form } = useFormInitial(forward);
+
+provideFormProps([forward, form]);
+
+props.formApi?.mount?.(form);
+
+const handleUpdateCollapsed = (value: boolean) => {
+  props.formApi?.setState({ collapsed: !!value });
+};
+
+function handleKeyDownEnter(event: KeyboardEvent) {
+  if (
+    !state.value.submitOnEnter ||
+    !formActionsRef.value ||
+    !formActionsRef.value.handleSubmit
+  ) {
+    return;
+  }
+  // 濡傛灉鏄� textarea 涓嶉樆姝㈤粯璁よ涓猴紝鍚﹀垯浼氬鑷存棤娉曟崲琛屻��
+  // 璺宠繃 textarea 鐨勫洖杞︽彁浜ゅ鐞�
+  if (event.target instanceof HTMLTextAreaElement) {
+    return;
+  }
+  event.preventDefault();
+
+  formActionsRef.value?.handleSubmit?.();
+}
+
+watch(
+  () => form.values,
+  useDebounceFn(() => {
+    forward.value.handleValuesChange?.(toRaw(form.values));
+    state.value.submitOnChange && props.formApi?.submitForm();
+  }, 300),
+  { deep: true },
+);
+</script>
+
+<template>
+  <Form
+    @keydown.enter="handleKeyDownEnter"
+    v-bind="forward"
+    :collapsed="state.collapsed"
+    :component-bind-event-map="COMPONENT_BIND_EVENT_MAP"
+    :component-map="COMPONENT_MAP"
+    :form="form"
+    :global-common-config="DEFAULT_FORM_COMMON_CONFIG"
+  >
+    <template
+      v-for="slotName in delegatedSlots"
+      :key="slotName"
+      #[slotName]="slotProps"
+    >
+      <slot :name="slotName" v-bind="slotProps"></slot>
+    </template>
+    <template #default="slotProps">
+      <slot v-bind="slotProps">
+        <FormActions
+          v-if="forward.showDefaultActions"
+          ref="formActionsRef"
+          :model-value="state.collapsed"
+          @update:model-value="handleUpdateCollapsed"
+        >
+          <template #reset-before="resetSlotProps">
+            <slot name="reset-before" v-bind="resetSlotProps"></slot>
+          </template>
+          <template #submit-before="submitSlotProps">
+            <slot name="submit-before" v-bind="submitSlotProps"></slot>
+          </template>
+          <template #expand-before="expandBeforeSlotProps">
+            <slot name="expand-before" v-bind="expandBeforeSlotProps"></slot>
+          </template>
+          <template #expand-after="expandAfterSlotProps">
+            <slot name="expand-after" v-bind="expandAfterSlotProps"></slot>
+          </template>
+        </FormActions>
+      </slot>
+    </template>
+  </Form>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/form-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/form-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/form-ui/tsconfig.json
new file mode 100644
index 0000000..bbb8050
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/form-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src", "__tests__"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/layout-ui/build.config.ts
new file mode 100644
index 0000000..18eaa60
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/build.config.ts
@@ -0,0 +1,21 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/package.json b/eims-ui/packages/@core/ui-kit/layout-ui/package.json
new file mode 100644
index 0000000..d249146
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@vben-core/layout-ui",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/layout-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/layout-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/index.ts b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/index.ts
new file mode 100644
index 0000000..f17826d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/index.ts
@@ -0,0 +1,5 @@
+export { default as LayoutContent } from './layout-content.vue';
+export { default as LayoutFooter } from './layout-footer.vue';
+export { default as LayoutHeader } from './layout-header.vue';
+export { default as LayoutSidebar } from './layout-sidebar.vue';
+export { default as LayoutTabbar } from './layout-tabbar.vue';
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue
new file mode 100644
index 0000000..926e621
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue
@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { ContentCompactType } from '@vben-core/typings';
+
+import type { CSSProperties } from 'vue';
+import { computed } from 'vue';
+
+import { useLayoutContentStyle } from '@vben-core/composables';
+import { Slot } from '@vben-core/shadcn-ui';
+
+interface Props {
+  /**
+   * 鍐呭鍖哄煙瀹氬
+   */
+  contentCompact: ContentCompactType;
+  /**
+   * 瀹氬甯冨眬瀹藉害
+   */
+  contentCompactWidth: number;
+  padding: number;
+  paddingBottom: number;
+  paddingLeft: number;
+  paddingRight: number;
+  paddingTop: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const { contentElement, overlayStyle } = useLayoutContentStyle();
+
+const style = computed((): CSSProperties => {
+  const {
+    contentCompact,
+    padding,
+    paddingBottom,
+    paddingLeft,
+    paddingRight,
+    paddingTop,
+  } = props;
+
+  const compactStyle: CSSProperties =
+    contentCompact === 'compact'
+      ? { margin: '0 auto', width: `${props.contentCompactWidth}px` }
+      : {};
+  return {
+    ...compactStyle,
+    flex: 1,
+    padding: `${padding}px`,
+    paddingBottom: `${paddingBottom}px`,
+    paddingLeft: `${paddingLeft}px`,
+    paddingRight: `${paddingRight}px`,
+    paddingTop: `${paddingTop}px`,
+  };
+});
+</script>
+
+<template>
+  <main ref="contentElement" :style="style" class="bg-background-deep relative">
+    <Slot :style="overlayStyle">
+      <slot name="overlay"></slot>
+    </Slot>
+    <slot></slot>
+  </main>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue
new file mode 100644
index 0000000..d4fb16f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue
@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed } from 'vue';
+
+interface Props {
+  /**
+   * 鏄惁鍥哄畾鍦ㄥ簳閮�
+   */
+  fixed?: boolean;
+  height: number;
+  /**
+   * 鏄惁鏄剧ず
+   * @default true
+   */
+  show?: boolean;
+  width: string;
+  zIndex: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  show: true,
+});
+
+const style = computed((): CSSProperties => {
+  const { fixed, height, show, width, zIndex } = props;
+  return {
+    height: `${height}px`,
+    marginBottom: show ? '0' : `-${height}px`,
+    position: fixed ? 'fixed' : 'static',
+    width,
+    zIndex,
+  };
+});
+</script>
+
+<template>
+  <footer
+    :style="style"
+    class="bg-background-deep bottom-0 w-full transition-all duration-200"
+  >
+    <slot></slot>
+  </footer>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue
new file mode 100644
index 0000000..792c8d8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue
@@ -0,0 +1,76 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed, useSlots } from 'vue';
+
+interface Props {
+  /**
+   * 妯睆
+   */
+  fullWidth: boolean;
+  /**
+   * 楂樺害
+   */
+  height: number;
+  /**
+   * 鏄惁绉诲姩绔�
+   */
+  isMobile: boolean;
+  /**
+   * 鏄惁鏄剧ず
+   */
+  show: boolean;
+  /**
+   * 渚ц竟鑿滃崟瀹藉害
+   */
+  sidebarWidth: number;
+  /**
+   * 涓婚
+   */
+  theme: string | undefined;
+  /**
+   * 瀹藉害
+   */
+  width: string;
+  /**
+   * zIndex
+   */
+  zIndex: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const slots = useSlots();
+
+const style = computed((): CSSProperties => {
+  const { fullWidth, height, show } = props;
+  const right = !show || !fullWidth ? undefined : 0;
+
+  return {
+    height: `${height}px`,
+    marginTop: show ? 0 : `-${height}px`,
+    right,
+  };
+});
+
+const logoStyle = computed((): CSSProperties => {
+  return {
+    minWidth: `${props.isMobile ? 40 : props.sidebarWidth}px`,
+  };
+});
+</script>
+
+<template>
+  <header
+    :class="theme"
+    :style="style"
+    class="border-border bg-header top-0 flex w-full flex-[0_0_auto] items-center border-b pl-2 transition-[margin-top] duration-200"
+  >
+    <div v-if="slots.logo" :style="logoStyle">
+      <slot name="logo"></slot>
+    </div>
+
+    <slot name="toggle-button"> </slot>
+
+    <slot></slot>
+  </header>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue
new file mode 100644
index 0000000..5f7fe3b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue
@@ -0,0 +1,315 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed, shallowRef, useSlots, watchEffect } from 'vue';
+
+import { VbenScrollbar } from '@vben-core/shadcn-ui';
+
+import { useScrollLock } from '@vueuse/core';
+
+import { SidebarCollapseButton, SidebarFixedButton } from './widgets';
+
+interface Props {
+  /**
+   * 鎶樺彔鍖哄煙楂樺害
+   * @default 42
+   */
+  collapseHeight?: number;
+  /**
+   * 鎶樺彔瀹藉害
+   * @default 48
+   */
+  collapseWidth?: number;
+  /**
+   * 闅愯棌鐨刣om鏄惁鍙
+   * @default true
+   */
+  domVisible?: boolean;
+  /**
+   * 鎵╁睍鍖哄煙瀹藉害
+   */
+  extraWidth: number;
+  /**
+   * 鍥哄畾鎵╁睍鍖哄煙
+   * @default false
+   */
+  fixedExtra?: boolean;
+  /**
+   * 澶撮儴楂樺害
+   */
+  headerHeight: number;
+  /**
+   * 鏄惁渚ц竟娣峰悎妯″紡
+   * @default false
+   */
+  isSidebarMixed?: boolean;
+  /**
+   * 椤堕儴margin
+   * @default 60
+   */
+  marginTop?: number;
+  /**
+   * 娣峰悎鑿滃崟瀹藉害
+   * @default 80
+   */
+  mixedWidth?: number;
+  /**
+   * 椤堕儴padding
+   * @default 60
+   */
+  paddingTop?: number;
+  /**
+   * 鏄惁鏄剧ず
+   * @default true
+   */
+  show?: boolean;
+  /**
+   * 鏄剧ず鎶樺彔鎸夐挳
+   * @default false
+   */
+  showCollapseButton?: boolean;
+  /**
+   * 涓婚
+   */
+  theme: string;
+
+  /**
+   * 瀹藉害
+   */
+  width: number;
+  /**
+   * zIndex
+   * @default 0
+   */
+  zIndex?: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  collapseHeight: 42,
+  collapseWidth: 48,
+  domVisible: true,
+  fixedExtra: false,
+  isSidebarMixed: false,
+  marginTop: 0,
+  mixedWidth: 70,
+  paddingTop: 0,
+  show: true,
+  showCollapseButton: true,
+  zIndex: 0,
+});
+
+const emit = defineEmits<{ leave: [] }>();
+const collapse = defineModel<boolean>('collapse');
+const extraCollapse = defineModel<boolean>('extraCollapse');
+const expandOnHovering = defineModel<boolean>('expandOnHovering');
+const expandOnHover = defineModel<boolean>('expandOnHover');
+const extraVisible = defineModel<boolean>('extraVisible');
+
+const isLocked = useScrollLock(document.body);
+const slots = useSlots();
+
+const asideRef = shallowRef<HTMLDivElement | null>();
+
+const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
+
+const style = computed((): CSSProperties => {
+  const { isSidebarMixed, marginTop, paddingTop, zIndex } = props;
+
+  return {
+    '--scroll-shadow': 'var(--sidebar)',
+    ...calcMenuWidthStyle(false),
+    height: `calc(100% - ${marginTop}px)`,
+    marginTop: `${marginTop}px`,
+    paddingTop: `${paddingTop}px`,
+    zIndex,
+    ...(isSidebarMixed && extraVisible.value ? { transition: 'none' } : {}),
+  };
+});
+
+const extraStyle = computed((): CSSProperties => {
+  const { extraWidth, show, width, zIndex } = props;
+
+  return {
+    left: `${width}px`,
+    width: extraVisible.value && show ? `${extraWidth}px` : 0,
+    zIndex,
+  };
+});
+
+const extraTitleStyle = computed((): CSSProperties => {
+  const { headerHeight } = props;
+
+  return {
+    height: `${headerHeight - 1}px`,
+  };
+});
+
+const contentWidthStyle = computed((): CSSProperties => {
+  const { collapseWidth, fixedExtra, isSidebarMixed, mixedWidth } = props;
+  if (isSidebarMixed && fixedExtra) {
+    return { width: `${collapse.value ? collapseWidth : mixedWidth}px` };
+  }
+  return {};
+});
+
+const contentStyle = computed((): CSSProperties => {
+  const { collapseHeight, headerHeight } = props;
+
+  return {
+    height: `calc(100% - ${headerHeight + collapseHeight}px)`,
+    paddingTop: '8px',
+    ...contentWidthStyle.value,
+  };
+});
+
+const headerStyle = computed((): CSSProperties => {
+  const { headerHeight, isSidebarMixed } = props;
+
+  return {
+    ...(isSidebarMixed ? { display: 'flex', justifyContent: 'center' } : {}),
+    height: `${headerHeight}px`,
+    ...contentWidthStyle.value,
+  };
+});
+
+const extraContentStyle = computed((): CSSProperties => {
+  const { collapseHeight, headerHeight } = props;
+  return {
+    height: `calc(100% - ${headerHeight + collapseHeight}px)`,
+  };
+});
+
+const collapseStyle = computed((): CSSProperties => {
+  return {
+    height: `${props.collapseHeight}px`,
+  };
+});
+
+watchEffect(() => {
+  extraVisible.value = props.fixedExtra ? true : extraVisible.value;
+});
+
+function calcMenuWidthStyle(isHiddenDom: boolean): CSSProperties {
+  const { extraWidth, fixedExtra, isSidebarMixed, show, width } = props;
+
+  let widthValue =
+    width === 0
+      ? '0px'
+      : `${width + (isSidebarMixed && fixedExtra && extraVisible.value ? extraWidth : 0)}px`;
+
+  const { collapseWidth } = props;
+
+  if (isHiddenDom && expandOnHovering.value && !expandOnHover.value) {
+    widthValue = `${collapseWidth}px`;
+  }
+
+  return {
+    ...(widthValue === '0px' ? { overflow: 'hidden' } : {}),
+    flex: `0 0 ${widthValue}`,
+    marginLeft: show ? 0 : `-${widthValue}`,
+    maxWidth: widthValue,
+    minWidth: widthValue,
+    width: widthValue,
+  };
+}
+
+function handleMouseenter(e: MouseEvent) {
+  if (e?.offsetX < 10) {
+    return;
+  }
+
+  // 鏈紑鍚拰鏈姌鍙犵姸鎬佷笉鐢熸晥
+  if (expandOnHover.value) {
+    return;
+  }
+  if (!expandOnHovering.value) {
+    collapse.value = false;
+  }
+  if (props.isSidebarMixed) {
+    isLocked.value = true;
+  }
+  expandOnHovering.value = true;
+}
+
+function handleMouseleave() {
+  emit('leave');
+  if (props.isSidebarMixed) {
+    isLocked.value = false;
+  }
+  if (expandOnHover.value) {
+    return;
+  }
+
+  expandOnHovering.value = false;
+  collapse.value = true;
+  extraVisible.value = false;
+}
+</script>
+
+<template>
+  <div
+    v-if="domVisible"
+    :class="theme"
+    :style="hiddenSideStyle"
+    class="h-full transition-all duration-150"
+  ></div>
+  <aside
+    :class="[
+      theme,
+      {
+        'bg-sidebar-deep': isSidebarMixed,
+        'bg-sidebar border-border border-r': !isSidebarMixed,
+      },
+    ]"
+    :style="style"
+    class="fixed left-0 top-0 h-full transition-all duration-150"
+    @mouseenter="handleMouseenter"
+    @mouseleave="handleMouseleave"
+  >
+    <SidebarFixedButton
+      v-if="!collapse && !isSidebarMixed"
+      v-model:expand-on-hover="expandOnHover"
+    />
+    <div v-if="slots.logo" :style="headerStyle">
+      <slot name="logo"></slot>
+    </div>
+    <VbenScrollbar :style="contentStyle" shadow shadow-border>
+      <slot></slot>
+    </VbenScrollbar>
+
+    <div :style="collapseStyle"></div>
+    <SidebarCollapseButton
+      v-if="showCollapseButton && !isSidebarMixed"
+      v-model:collapsed="collapse"
+    />
+    <div
+      v-if="isSidebarMixed"
+      ref="asideRef"
+      :class="{
+        'border-l': extraVisible,
+      }"
+      :style="extraStyle"
+      class="border-border bg-sidebar fixed top-0 h-full overflow-hidden border-r transition-all duration-200"
+    >
+      <SidebarCollapseButton
+        v-if="isSidebarMixed && expandOnHover"
+        v-model:collapsed="extraCollapse"
+      />
+
+      <SidebarFixedButton
+        v-if="!extraCollapse"
+        v-model:expand-on-hover="expandOnHover"
+      />
+      <div v-if="!extraCollapse" :style="extraTitleStyle" class="pl-2">
+        <slot name="extra-title"></slot>
+      </div>
+      <VbenScrollbar
+        :style="extraContentStyle"
+        class="border-border py-2"
+        shadow
+        shadow-border
+      >
+        <slot name="extra"></slot>
+      </VbenScrollbar>
+    </div>
+  </aside>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue
new file mode 100644
index 0000000..2a2cfd9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed } from 'vue';
+
+interface Props {
+  /**
+   * 楂樺害
+   */
+  height: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const style = computed((): CSSProperties => {
+  const { height } = props;
+  return {
+    height: `${height}px`,
+  };
+});
+</script>
+
+<template>
+  <section
+    :style="style"
+    class="border-border bg-background flex w-full border-b transition-all"
+  >
+    <slot></slot>
+  </section>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts
new file mode 100644
index 0000000..8dfbe6c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts
@@ -0,0 +1,2 @@
+export { default as SidebarCollapseButton } from './sidebar-collapse-button.vue';
+export { default as SidebarFixedButton } from './sidebar-fixed-button.vue';
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue
new file mode 100644
index 0000000..8092c0d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import { ChevronsLeft, ChevronsRight } from '@vben-core/icons';
+
+const collapsed = defineModel<boolean>('collapsed');
+
+function handleCollapsed() {
+  collapsed.value = !collapsed.value;
+}
+</script>
+
+<template>
+  <div
+    class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 left-3 z-10 cursor-pointer rounded-sm p-1"
+    @click.stop="handleCollapsed"
+  >
+    <ChevronsRight v-if="collapsed" class="size-4" />
+    <ChevronsLeft v-else class="size-4" />
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue
new file mode 100644
index 0000000..ce839f5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import { Pin, PinOff } from '@vben-core/icons';
+
+const expandOnHover = defineModel<boolean>('expandOnHover');
+
+function toggleFixed() {
+  expandOnHover.value = !expandOnHover.value;
+}
+</script>
+
+<template>
+  <div
+    class="flex-center hover:text-foreground text-foreground/60 hover:bg-accent-hover bg-accent absolute bottom-2 right-3 z-10 cursor-pointer rounded-sm p-[5px] transition-all duration-300"
+    @click="toggleFixed"
+  >
+    <PinOff v-if="!expandOnHover" class="size-3.5" />
+    <Pin v-else class="size-3.5" />
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts b/eims-ui/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts
new file mode 100644
index 0000000..354fcb4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts
@@ -0,0 +1,41 @@
+import type { LayoutType } from '@vben-core/typings';
+
+import type { VbenLayoutProps } from '../vben-layout';
+
+import { computed } from 'vue';
+
+export function useLayout(props: VbenLayoutProps) {
+  const currentLayout = computed(() =>
+    props.isMobile ? 'sidebar-nav' : (props.layout as LayoutType),
+  );
+
+  /**
+   * 鏄惁鍏ㄥ睆鏄剧ずcontent锛屼笉闇�瑕佷晶杈广�佸簳閮ㄣ�侀《閮ㄣ�乼ab鍖哄煙
+   */
+  const isFullContent = computed(() => currentLayout.value === 'full-content');
+
+  /**
+   * 鏄惁渚ц竟娣峰悎妯″紡
+   */
+  const isSidebarMixedNav = computed(
+    () => currentLayout.value === 'sidebar-mixed-nav',
+  );
+
+  /**
+   * 鏄惁涓哄ご閮ㄥ鑸ā寮�
+   */
+  const isHeaderNav = computed(() => currentLayout.value === 'header-nav');
+
+  /**
+   * 鏄惁涓烘贩鍚堝鑸ā寮�
+   */
+  const isMixedNav = computed(() => currentLayout.value === 'mixed-nav');
+
+  return {
+    currentLayout,
+    isFullContent,
+    isHeaderNav,
+    isMixedNav,
+    isSidebarMixedNav,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/layout-ui/src/index.ts
new file mode 100644
index 0000000..ca8c8a7
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/index.ts
@@ -0,0 +1,2 @@
+export type * from './vben-layout';
+export { default as VbenAdminLayout } from './vben-layout.vue';
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.ts b/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.ts
new file mode 100644
index 0000000..f7dd39c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.ts
@@ -0,0 +1,165 @@
+import type {
+  ContentCompactType,
+  LayoutHeaderModeType,
+  LayoutType,
+  ThemeModeType,
+} from '@vben-core/typings';
+
+interface VbenLayoutProps {
+  /**
+   * 鍐呭鍖哄煙瀹氬
+   * @default 'wide'
+   */
+  contentCompact?: ContentCompactType;
+  /**
+   * 瀹氬甯冨眬瀹藉害
+   * @default 1200
+   */
+  contentCompactWidth?: number;
+  /**
+   * padding
+   * @default 16
+   */
+  contentPadding?: number;
+  /**
+   * paddingBottom
+   * @default 16
+   */
+  contentPaddingBottom?: number;
+  /**
+   * paddingLeft
+   * @default 16
+   */
+  contentPaddingLeft?: number;
+  /**
+   * paddingRight
+   * @default 16
+   */
+  contentPaddingRight?: number;
+  /**
+   * paddingTop
+   * @default 16
+   */
+  contentPaddingTop?: number;
+  /**
+   * footer 鏄惁鍙
+   * @default false
+   */
+  footerEnable?: boolean;
+  /**
+   * footer 鏄惁鍥哄畾
+   * @default true
+   */
+  footerFixed?: boolean;
+  /**
+   * footer 楂樺害
+   * @default 32
+   */
+  footerHeight?: number;
+
+  /**
+   * header楂樺害
+   * @default 48
+   */
+  headerHeight?: number;
+  /**
+   * 椤舵爮鏄惁闅愯棌
+   * @default false
+   */
+  headerHidden?: boolean;
+  /**
+   * header 鏄剧ず妯″紡
+   * @default 'fixed'
+   */
+  headerMode?: LayoutHeaderModeType;
+  /**
+   * header 椤舵爮涓婚
+   */
+  headerTheme?: ThemeModeType;
+  /**
+   * 鏄惁鏄剧ずheader鍒囨崲渚ц竟鏍忔寜閽�
+   * @default
+   */
+  headerToggleSidebarButton?: boolean;
+  /**
+   * header鏄惁鏄剧ず
+   * @default true
+   */
+  headerVisible?: boolean;
+  /**
+   * 鏄惁绉诲姩绔樉绀�
+   * @default false
+   */
+  isMobile?: boolean;
+  /**
+   * 甯冨眬鏂瑰紡
+   * sidebar-nav 渚ц竟鑿滃崟甯冨眬
+   * header-nav 椤堕儴鑿滃崟甯冨眬
+   * mixed-nav 渚ц竟&椤堕儴鑿滃崟甯冨眬
+   * sidebar-mixed-nav 渚ц竟娣峰悎鑿滃崟甯冨眬
+   * full-content 鍏ㄥ睆鍐呭甯冨眬
+   * @default sidebar-nav
+   */
+  layout?: LayoutType;
+  /**
+   * 渚ц竟鑿滃崟鎶樺彔鐘舵��
+   * @default false
+   */
+  sidebarCollapse?: boolean;
+  /**
+   * 渚ц竟鑿滃崟鏄惁鎶樺彔鏃讹紝鏄惁鏄剧ずtitle
+   * @default true
+   */
+  sidebarCollapseShowTitle?: boolean;
+  /**
+   * 渚ц竟鏍忔槸鍚﹀彲瑙�
+   * @default true
+   */
+  sidebarEnable?: boolean;
+  /**
+   * 渚ц竟鑿滃崟鎶樺彔棰濆瀹藉害
+   * @default 48
+   */
+  sidebarExtraCollapsedWidth?: number;
+  /**
+   * 渚ц竟鏍忔槸鍚﹂殣钘�
+   * @default false
+   */
+  sidebarHidden?: boolean;
+  /**
+   * 娣峰悎渚ц竟鏍忓搴�
+   * @default 80
+   */
+  sidebarMixedWidth?: number;
+  /**
+   * 渚ц竟鏍�
+   * @default dark
+   */
+  sidebarTheme?: ThemeModeType;
+  /**
+   * 渚ц竟鏍忓搴�
+   * @default 210
+   */
+  sidebarWidth?: number;
+  /**
+   *  渚ц竟鑿滃崟鎶樺彔瀹藉害
+   * @default 48
+   */
+  sideCollapseWidth?: number;
+  /**
+   * tab鏄惁鍙
+   * @default true
+   */
+  tabbarEnable?: boolean;
+  /**
+   * tab楂樺害
+   * @default 30
+   */
+  tabbarHeight?: number;
+  /**
+   * zIndex
+   * @default 100
+   */
+  zIndex?: number;
+}
+export type { VbenLayoutProps };
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.vue b/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.vue
new file mode 100644
index 0000000..fe9b1d8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/src/vben-layout.vue
@@ -0,0 +1,596 @@
+<script setup lang="ts">
+import type { VbenLayoutProps } from './vben-layout';
+
+import type { CSSProperties } from 'vue';
+import { computed, ref, watch } from 'vue';
+
+import {
+  SCROLL_FIXED_CLASS,
+  useLayoutFooterStyle,
+  useLayoutHeaderStyle,
+} from '@vben-core/composables';
+import { Menu } from '@vben-core/icons';
+import { VbenIconButton } from '@vben-core/shadcn-ui';
+import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
+
+import { useMouse, useScroll, useThrottleFn } from '@vueuse/core';
+
+import {
+  LayoutContent,
+  LayoutFooter,
+  LayoutHeader,
+  LayoutSidebar,
+  LayoutTabbar,
+} from './components';
+import { useLayout } from './hooks/use-layout';
+
+interface Props extends VbenLayoutProps {}
+
+defineOptions({
+  name: 'VbenLayout',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  contentCompact: 'wide',
+  contentCompactWidth: 1200,
+  contentPadding: 0,
+  contentPaddingBottom: 0,
+  contentPaddingLeft: 0,
+  contentPaddingRight: 0,
+  contentPaddingTop: 0,
+  footerEnable: false,
+  footerFixed: true,
+  footerHeight: 32,
+  headerHeight: 50,
+  headerHidden: false,
+  headerMode: 'fixed',
+  headerToggleSidebarButton: true,
+  headerVisible: true,
+  isMobile: false,
+  layout: 'sidebar-nav',
+  sidebarCollapseShowTitle: false,
+  sidebarExtraCollapsedWidth: 60,
+  sidebarHidden: false,
+  sidebarMixedWidth: 80,
+  sidebarTheme: 'dark',
+  sidebarWidth: 180,
+  sideCollapseWidth: 60,
+  tabbarEnable: true,
+  tabbarHeight: 40,
+  zIndex: 200,
+});
+
+const emit = defineEmits<{ sideMouseLeave: []; toggleSidebar: [] }>();
+const sidebarCollapse = defineModel<boolean>('sidebarCollapse');
+const sidebarExtraVisible = defineModel<boolean>('sidebarExtraVisible');
+const sidebarExtraCollapse = defineModel<boolean>('sidebarExtraCollapse');
+const sidebarExpandOnHover = defineModel<boolean>('sidebarExpandOnHover');
+const sidebarEnable = defineModel<boolean>('sidebarEnable', { default: true });
+
+// side鏄惁澶勪簬hover鐘舵�佸睍寮�鑿滃崟涓�
+const sidebarExpandOnHovering = ref(false);
+const headerIsHidden = ref(false);
+const contentRef = ref();
+
+const {
+  arrivedState,
+  directions,
+  isScrolling,
+  y: scrollY,
+} = useScroll(document);
+
+const { setLayoutHeaderHeight } = useLayoutHeaderStyle();
+const { setLayoutFooterHeight } = useLayoutFooterStyle();
+
+const { y: mouseY } = useMouse({ target: contentRef, type: 'client' });
+
+const {
+  currentLayout,
+  isFullContent,
+  isHeaderNav,
+  isMixedNav,
+  isSidebarMixedNav,
+} = useLayout(props);
+
+/**
+ * 椤舵爮鏄惁鑷姩闅愯棌
+ */
+const isHeaderAutoMode = computed(() => props.headerMode === 'auto');
+
+const headerWrapperHeight = computed(() => {
+  let height = 0;
+  if (props.headerVisible && !props.headerHidden) {
+    height += props.headerHeight;
+  }
+  if (props.tabbarEnable) {
+    height += props.tabbarHeight;
+  }
+  return height;
+});
+
+const getSideCollapseWidth = computed(() => {
+  const { sidebarCollapseShowTitle, sidebarMixedWidth, sideCollapseWidth } =
+    props;
+
+  return sidebarCollapseShowTitle || isSidebarMixedNav.value
+    ? sidebarMixedWidth
+    : sideCollapseWidth;
+});
+
+/**
+ * 鍔ㄦ�佽幏鍙栦晶杈瑰尯鍩熸槸鍚﹀彲瑙�
+ */
+const sidebarEnableState = computed(() => {
+  return !isHeaderNav.value && sidebarEnable.value;
+});
+
+/**
+ * 渚ц竟鍖哄煙绂婚《閮ㄩ珮搴�
+ */
+const sidebarMarginTop = computed(() => {
+  const { headerHeight, isMobile } = props;
+  return isMixedNav.value && !isMobile ? headerHeight : 0;
+});
+
+/**
+ * 鍔ㄦ�佽幏鍙栦晶杈瑰搴�
+ */
+const getSidebarWidth = computed(() => {
+  const { isMobile, sidebarHidden, sidebarMixedWidth, sidebarWidth } = props;
+  let width = 0;
+
+  if (sidebarHidden) {
+    return width;
+  }
+
+  if (
+    !sidebarEnableState.value ||
+    (sidebarHidden && !isSidebarMixedNav.value && !isMixedNav.value)
+  ) {
+    return width;
+  }
+
+  if (isSidebarMixedNav.value && !isMobile) {
+    width = sidebarMixedWidth;
+  } else if (sidebarCollapse.value) {
+    width = isMobile ? 0 : getSideCollapseWidth.value;
+  } else {
+    width = sidebarWidth;
+  }
+  return width;
+});
+
+/**
+ * 鑾峰彇鎵╁睍鍖哄煙瀹藉害
+ */
+const sidebarExtraWidth = computed(() => {
+  const { sidebarExtraCollapsedWidth, sidebarWidth } = props;
+
+  return sidebarExtraCollapse.value ? sidebarExtraCollapsedWidth : sidebarWidth;
+});
+
+/**
+ * 鏄惁渚ц竟鏍忔ā寮忥紝鍖呭惈娣峰悎渚ц竟
+ */
+const isSideMode = computed(
+  () =>
+    currentLayout.value === 'mixed-nav' ||
+    currentLayout.value === 'sidebar-mixed-nav' ||
+    currentLayout.value === 'sidebar-nav',
+);
+
+/**
+ * header fixed鍊�
+ */
+const headerFixed = computed(() => {
+  const { headerMode } = props;
+  return (
+    isMixedNav.value ||
+    headerMode === 'fixed' ||
+    headerMode === 'auto-scroll' ||
+    headerMode === 'auto'
+  );
+});
+
+const showSidebar = computed(() => {
+  return isSideMode.value && sidebarEnable.value && !props.sidebarHidden;
+});
+
+/**
+ * 閬僵鍙鎬�
+ */
+const maskVisible = computed(() => !sidebarCollapse.value && props.isMobile);
+
+const mainStyle = computed(() => {
+  let width = '100%';
+  let sidebarAndExtraWidth = 'unset';
+  if (
+    headerFixed.value &&
+    currentLayout.value !== 'header-nav' &&
+    currentLayout.value !== 'mixed-nav' &&
+    showSidebar.value &&
+    !props.isMobile
+  ) {
+    // fixed妯″紡涓嬬敓鏁�
+    const isSideNavEffective =
+      isSidebarMixedNav.value &&
+      sidebarExpandOnHover.value &&
+      sidebarExtraVisible.value;
+
+    if (isSideNavEffective) {
+      const sideCollapseWidth = sidebarCollapse.value
+        ? getSideCollapseWidth.value
+        : props.sidebarMixedWidth;
+      const sideWidth = sidebarExtraCollapse.value
+        ? props.sidebarExtraCollapsedWidth
+        : props.sidebarWidth;
+
+      // 100% - 渚ц竟鑿滃崟娣峰悎瀹藉害 - 鑿滃崟瀹藉害
+      sidebarAndExtraWidth = `${sideCollapseWidth + sideWidth}px`;
+      width = `calc(100% - ${sidebarAndExtraWidth})`;
+    } else {
+      sidebarAndExtraWidth =
+        sidebarExpandOnHovering.value && !sidebarExpandOnHover.value
+          ? `${getSideCollapseWidth.value}px`
+          : `${getSidebarWidth.value}px`;
+      width = `calc(100% - ${sidebarAndExtraWidth})`;
+    }
+  }
+  return {
+    sidebarAndExtraWidth,
+    width,
+  };
+});
+
+// 璁$畻 tabbar 鐨勬牱寮�
+const tabbarStyle = computed((): CSSProperties => {
+  let width = '';
+  let marginLeft = 0;
+
+  // 濡傛灉涓嶆槸娣峰悎瀵艰埅锛宼abbar 鐨勫搴︿负 100%
+  if (!isMixedNav.value || props.sidebarHidden) {
+    width = '100%';
+  } else if (sidebarEnable.value) {
+    // 榧犳爣鍦ㄤ晶杈规爮涓婃椂锛屼笖渚ц竟鏍忓睍寮�鏃剁殑瀹藉害
+    const onHoveringWidth = sidebarExpandOnHover.value
+      ? props.sidebarWidth
+      : getSideCollapseWidth.value;
+
+    // 璁剧疆 marginLeft锛屾牴鎹晶杈规爮鏄惁鎶樺彔鏉ュ喅瀹�
+    marginLeft = sidebarCollapse.value
+      ? getSideCollapseWidth.value
+      : onHoveringWidth;
+
+    // 璁剧疆 tabbar 鐨勫搴︼紝璁$畻鏂瑰紡涓� 100% 鍑忓幓渚ц竟鏍忕殑瀹藉害
+    width = `calc(100% - ${sidebarCollapse.value ? getSidebarWidth.value : onHoveringWidth}px)`;
+  } else {
+    // 榛樿鎯呭喌涓嬶紝tabbar 鐨勫搴︿负 100%
+    width = '100%';
+  }
+
+  return {
+    marginLeft: `${marginLeft}px`,
+    width,
+  };
+});
+
+const contentStyle = computed((): CSSProperties => {
+  const fixed = headerFixed.value;
+
+  const { footerEnable, footerFixed, footerHeight } = props;
+  return {
+    marginTop:
+      fixed &&
+      !isFullContent.value &&
+      !headerIsHidden.value &&
+      (!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value)
+        ? `${headerWrapperHeight.value}px`
+        : 0,
+    paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`,
+  };
+});
+
+const headerZIndex = computed(() => {
+  const { zIndex } = props;
+  const offset = isMixedNav.value ? 1 : 0;
+  return zIndex + offset;
+});
+
+const headerWrapperStyle = computed((): CSSProperties => {
+  const fixed = headerFixed.value;
+  return {
+    height: isFullContent.value ? '0' : `${headerWrapperHeight.value}px`,
+    left: isMixedNav.value ? 0 : mainStyle.value.sidebarAndExtraWidth,
+    position: fixed ? 'fixed' : 'static',
+    top:
+      headerIsHidden.value || isFullContent.value
+        ? `-${headerWrapperHeight.value}px`
+        : 0,
+    width: mainStyle.value.width,
+    'z-index': headerZIndex.value,
+  };
+});
+
+/**
+ * 渚ц竟鏍弞-index
+ */
+const sidebarZIndex = computed(() => {
+  const { isMobile, zIndex } = props;
+  let offset = isMobile || isSideMode.value ? 1 : -1;
+
+  if (isMixedNav.value) {
+    offset += 1;
+  }
+
+  return zIndex + offset;
+});
+
+const footerWidth = computed(() => {
+  if (!props.footerFixed) {
+    return '100%';
+  }
+
+  return mainStyle.value.width;
+});
+
+const maskStyle = computed((): CSSProperties => {
+  return { zIndex: props.zIndex };
+});
+
+const showHeaderToggleButton = computed(() => {
+  return (
+    props.isMobile ||
+    (props.headerToggleSidebarButton &&
+      isSideMode.value &&
+      !isSidebarMixedNav.value &&
+      !isMixedNav.value &&
+      !props.isMobile)
+  );
+});
+
+const showHeaderLogo = computed(() => {
+  return !isSideMode.value || isMixedNav.value || props.isMobile;
+});
+
+watch(
+  () => props.isMobile,
+  (val) => {
+    if (val) {
+      sidebarCollapse.value = true;
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+
+watch(
+  [() => headerWrapperHeight.value, () => isFullContent.value],
+  ([height]) => {
+    setLayoutHeaderHeight(isFullContent.value ? 0 : height);
+  },
+  {
+    immediate: true,
+  },
+);
+
+watch(
+  () => props.footerHeight,
+  (height: number) => {
+    setLayoutFooterHeight(height);
+  },
+  {
+    immediate: true,
+  },
+);
+
+{
+  const mouseMove = () => {
+    mouseY.value > headerWrapperHeight.value
+      ? (headerIsHidden.value = true)
+      : (headerIsHidden.value = false);
+  };
+  watch(
+    [() => props.headerMode, () => mouseY.value],
+    () => {
+      if (!isHeaderAutoMode.value || isMixedNav.value || isFullContent.value) {
+        if (props.headerMode !== 'auto-scroll') {
+          headerIsHidden.value = false;
+        }
+        return;
+      }
+      headerIsHidden.value = true;
+      mouseMove();
+    },
+    {
+      immediate: true,
+    },
+  );
+}
+
+{
+  const checkHeaderIsHidden = useThrottleFn((top, bottom, topArrived) => {
+    if (scrollY.value < headerWrapperHeight.value) {
+      headerIsHidden.value = false;
+      return;
+    }
+    if (topArrived) {
+      headerIsHidden.value = false;
+      return;
+    }
+
+    if (top) {
+      headerIsHidden.value = false;
+    } else if (bottom) {
+      headerIsHidden.value = true;
+    }
+  }, 300);
+
+  watch(
+    () => scrollY.value,
+    () => {
+      if (
+        props.headerMode !== 'auto-scroll' ||
+        isMixedNav.value ||
+        isFullContent.value
+      ) {
+        return;
+      }
+      if (isScrolling.value) {
+        checkHeaderIsHidden(
+          directions.top,
+          directions.bottom,
+          arrivedState.top,
+        );
+      }
+    },
+  );
+}
+
+function handleClickMask() {
+  sidebarCollapse.value = true;
+}
+
+function handleHeaderToggle() {
+  if (props.isMobile) {
+    sidebarCollapse.value = false;
+  } else {
+    emit('toggleSidebar');
+  }
+}
+
+const idMainContent = ELEMENT_ID_MAIN_CONTENT;
+</script>
+
+<template>
+  <div class="relative flex min-h-full w-full">
+    <LayoutSidebar
+      v-if="sidebarEnableState"
+      v-model:collapse="sidebarCollapse"
+      v-model:expand-on-hover="sidebarExpandOnHover"
+      v-model:expand-on-hovering="sidebarExpandOnHovering"
+      v-model:extra-collapse="sidebarExtraCollapse"
+      v-model:extra-visible="sidebarExtraVisible"
+      :collapse-width="getSideCollapseWidth"
+      :dom-visible="!isMobile"
+      :extra-width="sidebarExtraWidth"
+      :fixed-extra="sidebarExpandOnHover"
+      :header-height="isMixedNav ? 0 : headerHeight"
+      :is-sidebar-mixed="isSidebarMixedNav"
+      :margin-top="sidebarMarginTop"
+      :mixed-width="sidebarMixedWidth"
+      :show="showSidebar"
+      :theme="sidebarTheme"
+      :width="getSidebarWidth"
+      :z-index="sidebarZIndex"
+      @leave="() => emit('sideMouseLeave')"
+    >
+      <template v-if="isSideMode && !isMixedNav" #logo>
+        <slot name="logo"></slot>
+      </template>
+
+      <template v-if="isSidebarMixedNav">
+        <slot name="mixed-menu"></slot>
+      </template>
+      <template v-else>
+        <slot name="menu"></slot>
+      </template>
+
+      <template #extra>
+        <slot name="side-extra"></slot>
+      </template>
+      <template #extra-title>
+        <slot name="side-extra-title"></slot>
+      </template>
+    </LayoutSidebar>
+
+    <div
+      ref="contentRef"
+      class="flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in"
+    >
+      <div
+        :class="[
+          {
+            'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20,
+          },
+          SCROLL_FIXED_CLASS,
+        ]"
+        :style="headerWrapperStyle"
+        class="overflow-hidden transition-all duration-200"
+      >
+        <LayoutHeader
+          v-if="headerVisible"
+          :full-width="!isSideMode"
+          :height="headerHeight"
+          :is-mobile="isMobile"
+          :show="!isFullContent && !headerHidden"
+          :sidebar-width="sidebarWidth"
+          :theme="headerTheme"
+          :width="mainStyle.width"
+          :z-index="headerZIndex"
+        >
+          <template v-if="showHeaderLogo" #logo>
+            <slot name="logo"></slot>
+          </template>
+
+          <template #toggle-button>
+            <VbenIconButton
+              v-if="showHeaderToggleButton"
+              class="my-0 mr-1 rounded-md"
+              @click="handleHeaderToggle"
+            >
+              <Menu class="size-4" />
+            </VbenIconButton>
+          </template>
+          <slot name="header"></slot>
+        </LayoutHeader>
+
+        <LayoutTabbar
+          v-if="tabbarEnable"
+          :height="tabbarHeight"
+          :style="tabbarStyle"
+        >
+          <slot name="tabbar"></slot>
+        </LayoutTabbar>
+      </div>
+
+      <!-- </div> -->
+      <LayoutContent
+        :id="idMainContent"
+        :content-compact="contentCompact"
+        :content-compact-width="contentCompactWidth"
+        :padding="contentPadding"
+        :padding-bottom="contentPaddingBottom"
+        :padding-left="contentPaddingLeft"
+        :padding-right="contentPaddingRight"
+        :padding-top="contentPaddingTop"
+        :style="contentStyle"
+        class="transition-[margin-top] duration-200"
+      >
+        <slot name="content"></slot>
+
+        <template #overlay>
+          <slot name="content-overlay"></slot>
+        </template>
+      </LayoutContent>
+
+      <LayoutFooter
+        v-if="footerEnable"
+        :fixed="footerFixed"
+        :height="footerHeight"
+        :show="!isFullContent"
+        :width="footerWidth"
+        :z-index="zIndex"
+      >
+        <slot name="footer"></slot>
+      </LayoutFooter>
+    </div>
+    <slot name="extra"></slot>
+    <div
+      v-if="maskVisible"
+      :style="maskStyle"
+      class="bg-overlay fixed left-0 top-0 h-full w-full transition-[background-color] duration-200"
+      @click="handleClickMask"
+    ></div>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/layout-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/layout-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/layout-ui/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/layout-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/README.md b/eims-ui/packages/@core/ui-kit/menu-ui/README.md
new file mode 100644
index 0000000..dd77a95
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/README.md
@@ -0,0 +1 @@
+# 鑿滃崟缁勪欢
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/menu-ui/build.config.ts
new file mode 100644
index 0000000..1ff78fa
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/build.config.ts
@@ -0,0 +1,26 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+      pattern: ['**/*'],
+    },
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/package.json b/eims-ui/packages/@core/ui-kit/menu-ui/package.json
new file mode 100644
index 0000000..208f929
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@vben-core/menu-ui",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/menu-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/menu-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue
new file mode 100644
index 0000000..b89c406
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue
@@ -0,0 +1,96 @@
+<script lang="ts" setup>
+import type { RendererElement } from 'vue';
+
+defineOptions({
+  name: 'CollapseTransition',
+});
+
+const reset = (el: RendererElement) => {
+  el.style.maxHeight = '';
+  el.style.overflow = el.dataset.oldOverflow;
+  el.style.paddingTop = el.dataset.oldPaddingTop;
+  el.style.paddingBottom = el.dataset.oldPaddingBottom;
+};
+
+const on = {
+  afterEnter(el: RendererElement) {
+    el.style.maxHeight = '';
+    el.style.overflow = el.dataset.oldOverflow;
+  },
+
+  afterLeave(el: RendererElement) {
+    reset(el);
+  },
+
+  beforeEnter(el: RendererElement) {
+    if (!el.dataset) el.dataset = {};
+
+    el.dataset.oldPaddingTop = el.style.paddingTop;
+    el.dataset.oldMarginTop = el.style.marginTop;
+
+    el.dataset.oldPaddingBottom = el.style.paddingBottom;
+    el.dataset.oldMarginBottom = el.style.marginBottom;
+    if (el.style.height) el.dataset.elExistsHeight = el.style.height;
+
+    el.style.maxHeight = 0;
+    el.style.paddingTop = 0;
+    el.style.marginTop = 0;
+    el.style.paddingBottom = 0;
+    el.style.marginBottom = 0;
+  },
+
+  beforeLeave(el: RendererElement) {
+    if (!el.dataset) el.dataset = {};
+    el.dataset.oldPaddingTop = el.style.paddingTop;
+    el.dataset.oldMarginTop = el.style.marginTop;
+    el.dataset.oldPaddingBottom = el.style.paddingBottom;
+    el.dataset.oldMarginBottom = el.style.marginBottom;
+    el.dataset.oldOverflow = el.style.overflow;
+    el.style.maxHeight = `${el.scrollHeight}px`;
+    el.style.overflow = 'hidden';
+  },
+
+  enter(el: RendererElement) {
+    requestAnimationFrame(() => {
+      el.dataset.oldOverflow = el.style.overflow;
+      if (el.dataset.elExistsHeight) {
+        el.style.maxHeight = el.dataset.elExistsHeight;
+      } else if (el.scrollHeight === 0) {
+        el.style.maxHeight = 0;
+      } else {
+        el.style.maxHeight = `${el.scrollHeight}px`;
+      }
+
+      el.style.paddingTop = el.dataset.oldPaddingTop;
+      el.style.paddingBottom = el.dataset.oldPaddingBottom;
+      el.style.marginTop = el.dataset.oldMarginTop;
+      el.style.marginBottom = el.dataset.oldMarginBottom;
+      el.style.overflow = 'hidden';
+    });
+  },
+
+  enterCancelled(el: RendererElement) {
+    reset(el);
+  },
+
+  leave(el: RendererElement) {
+    if (el.scrollHeight !== 0) {
+      el.style.maxHeight = 0;
+      el.style.paddingTop = 0;
+      el.style.paddingBottom = 0;
+      el.style.marginTop = 0;
+      el.style.marginBottom = 0;
+    }
+  },
+
+  leaveCancelled(el: RendererElement) {
+    reset(el);
+  },
+};
+</script>
+
+<template>
+  <transition name="collapse-transition" v-on="on">
+    <slot></slot>
+  </transition>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/index.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/index.ts
new file mode 100644
index 0000000..7c697dc
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/index.ts
@@ -0,0 +1,4 @@
+export { default as Menu } from './menu.vue';
+export { default as MenuBadge } from './menu-badge.vue';
+export { default as MenuItem } from './menu-item.vue';
+export { default as SubMenu } from './sub-menu.vue';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue
new file mode 100644
index 0000000..823cbd7
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue
@@ -0,0 +1,28 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+
+interface Props {
+  dotClass?: string;
+  dotStyle?: CSSProperties;
+}
+
+withDefaults(defineProps<Props>(), {
+  dotClass: '',
+  dotStyle: () => ({}),
+});
+</script>
+<template>
+  <span class="relative mr-1 flex size-1.5">
+    <span
+      :class="dotClass"
+      :style="dotStyle"
+      class="absolute inline-flex h-full w-full animate-ping rounded-full opacity-75"
+    >
+    </span>
+    <span
+      :class="dotClass"
+      :style="dotStyle"
+      class="relative inline-flex size-1.5 rounded-full"
+    ></span>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue
new file mode 100644
index 0000000..b1dd94c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue
@@ -0,0 +1,57 @@
+<script setup lang="ts">
+import type { MenuRecordBadgeRaw } from '@vben-core/typings';
+
+import { computed } from 'vue';
+
+import { isValidColor } from '@vben-core/shared/color';
+
+import BadgeDot from './menu-badge-dot.vue';
+
+interface Props extends MenuRecordBadgeRaw {
+  hasChildren?: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const variantsMap: Record<string, string> = {
+  default: 'bg-green-500',
+  destructive: 'bg-destructive',
+  primary: 'bg-primary',
+  success: 'bg-green-500',
+  warning: 'bg-yellow-500',
+};
+
+const isDot = computed(() => props.badgeType === 'dot');
+
+const badgeClass = computed(() => {
+  const { badgeVariants } = props;
+
+  if (!badgeVariants) {
+    return variantsMap.default;
+  }
+
+  return variantsMap[badgeVariants] || badgeVariants;
+});
+
+const badgeStyle = computed(() => {
+  if (badgeClass.value && isValidColor(badgeClass.value)) {
+    return {
+      backgroundColor: badgeClass.value,
+    };
+  }
+  return {};
+});
+</script>
+<template>
+  <span v-if="isDot || badge" :class="$attrs.class" class="absolute">
+    <BadgeDot v-if="isDot" :dot-class="badgeClass" :dot-style="badgeStyle" />
+    <div
+      v-else
+      :class="badgeClass"
+      :style="badgeStyle"
+      class="text-primary-foreground flex-center rounded-xl px-1.5 py-0.5 text-[10px]"
+    >
+      {{ badge }}
+    </div>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue
new file mode 100644
index 0000000..a72d348
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue
@@ -0,0 +1,122 @@
+<script lang="ts" setup>
+import type { MenuItemProps, MenuItemRegistered } from '../types';
+
+import { computed, onBeforeUnmount, onMounted, reactive, useSlots } from 'vue';
+
+import { useNamespace } from '@vben-core/composables';
+import { VbenIcon, VbenTooltip } from '@vben-core/shadcn-ui';
+
+import { MenuBadge } from '../components';
+import { useMenu, useMenuContext, useSubMenuContext } from '../hooks';
+
+interface Props extends MenuItemProps {}
+
+defineOptions({ name: 'MenuItem' });
+
+const props = withDefaults(defineProps<Props>(), {
+  disabled: false,
+});
+
+const emit = defineEmits<{ click: [MenuItemRegistered] }>();
+
+const slots = useSlots();
+const { b, e, is } = useNamespace('menu-item');
+const nsMenu = useNamespace('menu');
+const rootMenu = useMenuContext();
+const subMenu = useSubMenuContext();
+const { parentMenu, parentPaths } = useMenu();
+
+const active = computed(() => props.path === rootMenu?.activePath);
+const menuIcon = computed(() =>
+  active.value ? props.activeIcon || props.icon : props.icon,
+);
+
+const isTopLevelMenuItem = computed(
+  () => parentMenu.value?.type.name === 'Menu',
+);
+
+const collapseShowTitle = computed(
+  () =>
+    rootMenu.props?.collapseShowTitle &&
+    isTopLevelMenuItem.value &&
+    rootMenu.props.collapse,
+);
+
+const showTooltip = computed(
+  () =>
+    rootMenu.props.mode === 'vertical' &&
+    isTopLevelMenuItem.value &&
+    rootMenu.props?.collapse &&
+    slots.title,
+);
+
+const item: MenuItemRegistered = reactive({
+  active,
+  parentPaths: parentPaths.value,
+  path: props.path || '',
+});
+
+/**
+ * 鑿滃崟椤圭偣鍑讳簨浠�
+ */
+function handleClick() {
+  if (props.disabled) {
+    return;
+  }
+  rootMenu?.handleMenuItemClick?.({
+    parentPaths: parentPaths.value,
+    path: props.path,
+  });
+  emit('click', item);
+}
+
+onMounted(() => {
+  subMenu?.addSubMenu?.(item);
+  rootMenu?.addMenuItem?.(item);
+});
+
+onBeforeUnmount(() => {
+  subMenu?.removeSubMenu?.(item);
+  rootMenu?.removeMenuItem?.(item);
+});
+</script>
+<template>
+  <li
+    :class="[
+      rootMenu.theme,
+      b(),
+      is('active', active),
+      is('disabled', disabled),
+      is('collapse-show-title', collapseShowTitle),
+    ]"
+    role="menuitem"
+    @click.stop="handleClick"
+  >
+    <VbenTooltip
+      v-if="showTooltip"
+      :content-class="[rootMenu.theme]"
+      side="right"
+    >
+      <template #trigger>
+        <div :class="[nsMenu.be('tooltip', 'trigger')]">
+          <VbenIcon :class="nsMenu.e('icon')" :icon="menuIcon" />
+          <slot></slot>
+          <span v-if="collapseShowTitle" :class="nsMenu.e('name')">
+            <slot name="title"></slot>
+          </span>
+        </div>
+      </template>
+      <slot name="title"></slot>
+    </VbenTooltip>
+    <div v-show="!showTooltip" :class="[e('content')]">
+      <MenuBadge
+        v-if="rootMenu.props.mode !== 'horizontal'"
+        class="right-2"
+        v-bind="props"
+      />
+      <VbenIcon :class="nsMenu.e('icon')" :icon="menuIcon" />
+      <slot></slot>
+      <slot name="title"></slot>
+    </div>
+  </li>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu.vue
new file mode 100644
index 0000000..ea7a14c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/menu.vue
@@ -0,0 +1,854 @@
+<script lang="ts" setup>
+import type { UseResizeObserverReturn } from '@vueuse/core';
+
+import type {
+  MenuItemClicked,
+  MenuItemRegistered,
+  MenuProps,
+  MenuProvider,
+} from '../types';
+
+import {
+  computed,
+  nextTick,
+  reactive,
+  ref,
+  toRef,
+  useSlots,
+  type VNodeArrayChildren,
+  watch,
+  watchEffect,
+} from 'vue';
+
+import { useNamespace } from '@vben-core/composables';
+import { Ellipsis } from '@vben-core/icons';
+import { isHttpUrl } from '@vben-core/shared/utils';
+
+import { useResizeObserver } from '@vueuse/core';
+
+import {
+  createMenuContext,
+  createSubMenuContext,
+  useMenuStyle,
+} from '../hooks';
+import { flattedChildren } from '../utils';
+import SubMenu from './sub-menu.vue';
+
+interface Props extends MenuProps {}
+
+defineOptions({ name: 'Menu' });
+
+const props = withDefaults(defineProps<Props>(), {
+  accordion: true,
+  collapse: false,
+  mode: 'vertical',
+  rounded: true,
+  theme: 'dark',
+});
+
+const emit = defineEmits<{
+  close: [string, string[]];
+  open: [string, string[]];
+  select: [string, string[]];
+}>();
+
+const { b, is } = useNamespace('menu');
+const menuStyle = useMenuStyle();
+const slots = useSlots();
+const menu = ref<HTMLUListElement>();
+const sliceIndex = ref(-1);
+const openedMenus = ref<MenuProvider['openedMenus']>(
+  props.defaultOpeneds && !props.collapse ? [...props.defaultOpeneds] : [],
+);
+const activePath = ref<MenuProvider['activePath']>(props.defaultActive);
+const items = ref<MenuProvider['items']>({});
+const subMenus = ref<MenuProvider['subMenus']>({});
+const mouseInChild = ref(false);
+
+const isMenuPopup = computed<MenuProvider['isMenuPopup']>(() => {
+  return (
+    props.mode === 'horizontal' || (props.mode === 'vertical' && props.collapse)
+  );
+});
+
+const getSlot = computed(() => {
+  // 鏇存柊鎻掓Ы鍐呭
+  const defaultSlots: VNodeArrayChildren = slots.default?.() ?? [];
+
+  const originalSlot = flattedChildren(defaultSlots) as VNodeArrayChildren;
+  const slotDefault =
+    sliceIndex.value === -1
+      ? originalSlot
+      : originalSlot.slice(0, sliceIndex.value);
+
+  const slotMore =
+    sliceIndex.value === -1 ? [] : originalSlot.slice(sliceIndex.value);
+
+  return { showSlotMore: slotMore.length > 0, slotDefault, slotMore };
+});
+
+watch(
+  () => props.collapse,
+  (value) => {
+    if (value) openedMenus.value = [];
+  },
+);
+
+watch(items.value, initMenu);
+
+watch(
+  () => props.defaultActive,
+  (currentActive = '') => {
+    if (!items.value[currentActive]) {
+      activePath.value = '';
+    }
+    updateActiveName(currentActive);
+  },
+);
+
+let resizeStopper: UseResizeObserverReturn['stop'];
+watchEffect(() => {
+  if (props.mode === 'horizontal') {
+    resizeStopper = useResizeObserver(menu, handleResize).stop;
+  } else {
+    resizeStopper?.();
+  }
+});
+
+// 娉ㄥ叆涓婁笅鏂�
+createMenuContext(
+  reactive({
+    activePath,
+    addMenuItem,
+    addSubMenu,
+    closeMenu,
+    handleMenuItemClick,
+    handleSubMenuClick,
+    isMenuPopup,
+    openedMenus,
+    openMenu,
+    props,
+    removeMenuItem,
+    removeSubMenu,
+    subMenus,
+    theme: toRef(props, 'theme'),
+    items,
+  }),
+);
+
+createSubMenuContext({
+  addSubMenu,
+  level: 1,
+  mouseInChild,
+  removeSubMenu,
+});
+
+function calcMenuItemWidth(menuItem: HTMLElement) {
+  const computedStyle = getComputedStyle(menuItem);
+  const marginLeft = Number.parseInt(computedStyle.marginLeft, 10);
+  const marginRight = Number.parseInt(computedStyle.marginRight, 10);
+  return menuItem.offsetWidth + marginLeft + marginRight || 0;
+}
+
+function calcSliceIndex() {
+  if (!menu.value) {
+    return -1;
+  }
+  const items = [...(menu.value?.childNodes ?? [])].filter(
+    (item) =>
+      // remove comment type node #12634
+      item.nodeName !== '#comment' &&
+      (item.nodeName !== '#text' || item.nodeValue),
+  ) as HTMLElement[];
+
+  const moreItemWidth = 46;
+  const computedMenuStyle = getComputedStyle(menu?.value);
+
+  const paddingLeft = Number.parseInt(computedMenuStyle.paddingLeft, 10);
+  const paddingRight = Number.parseInt(computedMenuStyle.paddingRight, 10);
+  const menuWidth = menu.value?.clientWidth - paddingLeft - paddingRight;
+
+  let calcWidth = 0;
+  let sliceIndex = 0;
+  items.forEach((item, index) => {
+    calcWidth += calcMenuItemWidth(item);
+    if (calcWidth <= menuWidth - moreItemWidth) {
+      sliceIndex = index + 1;
+    }
+  });
+  return sliceIndex === items.length ? -1 : sliceIndex;
+}
+
+function debounce(fn: () => void, wait = 33.34) {
+  let timer: null | ReturnType<typeof setTimeout>;
+  return () => {
+    timer && clearTimeout(timer);
+    timer = setTimeout(() => {
+      fn();
+    }, wait);
+  };
+}
+
+let isFirstTimeRender = true;
+function handleResize() {
+  if (sliceIndex.value === calcSliceIndex()) {
+    return;
+  }
+  const callback = () => {
+    sliceIndex.value = -1;
+    nextTick(() => {
+      sliceIndex.value = calcSliceIndex();
+    });
+  };
+  callback();
+  // // execute callback directly when first time resize to avoid shaking
+  isFirstTimeRender ? callback() : debounce(callback)();
+  isFirstTimeRender = false;
+}
+
+function getActivePaths() {
+  const activeItem = activePath.value && items.value[activePath.value];
+
+  if (!activeItem || props.mode === 'horizontal' || props.collapse) {
+    return [];
+  }
+
+  return activeItem.parentPaths;
+}
+
+// 榛樿灞曞紑鑿滃崟
+function initMenu() {
+  const parentPaths = getActivePaths();
+
+  // 灞曞紑璇ヨ彍鍗曢」鐨勮矾寰勪笂鎵�鏈夊瓙鑿滃崟
+  // expand all subMenus of the menu item
+  parentPaths.forEach((path) => {
+    const subMenu = subMenus.value[path];
+    subMenu && openMenu(path, subMenu.parentPaths);
+  });
+}
+
+function updateActiveName(val: string) {
+  const itemsInData = items.value;
+  const item =
+    itemsInData[val] ||
+    (activePath.value && itemsInData[activePath.value]) ||
+    itemsInData[props.defaultActive || ''];
+
+  activePath.value = item ? item.path : val;
+}
+
+function handleMenuItemClick(data: MenuItemClicked) {
+  const { collapse, mode } = props;
+  if (mode === 'horizontal' || collapse) {
+    openedMenus.value = [];
+  }
+  const { parentPaths, path } = data;
+  if (!path || !parentPaths) {
+    return;
+  }
+  if (!isHttpUrl(path)) {
+    activePath.value = path;
+  }
+
+  emit('select', path, parentPaths);
+}
+
+function handleSubMenuClick({ parentPaths, path }: MenuItemRegistered) {
+  const isOpened = openedMenus.value.includes(path);
+
+  if (isOpened) {
+    closeMenu(path, parentPaths);
+  } else {
+    openMenu(path, parentPaths);
+  }
+}
+
+function close(path: string) {
+  const i = openedMenus.value.indexOf(path);
+
+  if (i !== -1) {
+    openedMenus.value.splice(i, 1);
+  }
+}
+
+/**
+ * 鍏抽棴銆佹姌鍙犺彍鍗�
+ */
+function closeMenu(path: string, parentPaths: string[]) {
+  if (props.accordion) {
+    openedMenus.value = subMenus.value[path]?.parentPaths ?? [];
+  }
+
+  close(path);
+
+  emit('close', path, parentPaths);
+}
+
+/**
+ * 鐐瑰嚮灞曞紑鑿滃崟
+ */
+function openMenu(path: string, parentPaths: string[]) {
+  if (openedMenus.value.includes(path)) {
+    return;
+  }
+  // 鎵嬮鐞存ā寮忚彍鍗�
+  if (props.accordion) {
+    const activeParentPaths = getActivePaths();
+    if (activeParentPaths.includes(path)) {
+      parentPaths = activeParentPaths;
+    }
+    openedMenus.value = openedMenus.value.filter((path: string) =>
+      parentPaths.includes(path),
+    );
+  }
+  openedMenus.value.push(path);
+  emit('open', path, parentPaths);
+}
+
+function addMenuItem(item: MenuItemRegistered) {
+  items.value[item.path] = item;
+}
+
+function addSubMenu(subMenu: MenuItemRegistered) {
+  subMenus.value[subMenu.path] = subMenu;
+}
+
+function removeSubMenu(subMenu: MenuItemRegistered) {
+  Reflect.deleteProperty(subMenus.value, subMenu.path);
+}
+
+function removeMenuItem(item: MenuItemRegistered) {
+  Reflect.deleteProperty(items.value, item.path);
+}
+</script>
+<template>
+  <ul
+    ref="menu"
+    :class="[
+      theme,
+      b(),
+      is(mode, true),
+      is(theme, true),
+      is('rounded', rounded),
+      is('collapse', collapse),
+    ]"
+    :style="menuStyle"
+    role="menu"
+  >
+    <template v-if="mode === 'horizontal' && getSlot.showSlotMore">
+      <template v-for="item in getSlot.slotDefault" :key="item.key">
+        <component :is="item" />
+      </template>
+      <SubMenu is-sub-menu-more path="sub-menu-more">
+        <template #title>
+          <Ellipsis class="size-4" />
+        </template>
+        <template v-for="item in getSlot.slotMore" :key="item.key">
+          <component :is="item" />
+        </template>
+      </SubMenu>
+    </template>
+    <template v-else>
+      <slot></slot>
+    </template>
+  </ul>
+</template>
+
+<style lang="scss">
+$namespace: vben;
+
+@mixin menu-item-active {
+  color: var(--menu-item-active-color);
+  text-decoration: none;
+  cursor: pointer;
+  background: var(--menu-item-active-background-color);
+}
+
+@mixin menu-item {
+  position: relative;
+  display: flex;
+  // gap: 12px;
+  align-items: center;
+  height: var(--menu-item-height);
+  padding: var(--menu-item-padding-y) var(--menu-item-padding-x);
+  margin: 0 var(--menu-item-margin-x) var(--menu-item-margin-y)
+    var(--menu-item-margin-x);
+  font-size: var(--menu-font-size);
+  color: var(--menu-item-color);
+  text-decoration: none;
+  white-space: nowrap;
+  list-style: none;
+  cursor: pointer;
+  background: var(--menu-item-background-color);
+  border: none;
+  border-radius: var(--menu-item-radius);
+  transition:
+    background 0.15s ease,
+    color 0.15s ease,
+    padding 0.15s ease,
+    border-color 0.15s ease;
+
+  &.is-disabled {
+    cursor: not-allowed;
+    background: none !important;
+    opacity: 0.25;
+  }
+
+  .#{$namespace}-menu__icon {
+    transition: transform 0.25s;
+  }
+
+  &:hover {
+    .#{$namespace}-menu__icon {
+      transform: scale(1.2);
+    }
+  }
+
+  &:hover,
+  &:focus {
+    outline: none;
+  }
+
+  * {
+    vertical-align: bottom;
+  }
+}
+
+@mixin menu-title {
+  max-width: var(--menu-title-width);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  opacity: 1;
+}
+
+.#{$namespace}-menu__popup-container,
+.#{$namespace}-menu {
+  --menu-title-width: 140px;
+  --menu-item-icon-size: 16px;
+  --menu-item-height: 38px;
+  --menu-item-padding-y: 21px;
+  --menu-item-padding-x: 12px;
+  --menu-item-popup-padding-y: 20px;
+  --menu-item-popup-padding-x: 12px;
+  --menu-item-margin-y: 2px;
+  --menu-item-margin-x: 0px;
+  --menu-item-collapse-padding-y: 23.5px;
+  --menu-item-collapse-padding-x: 0px;
+  --menu-item-collapse-margin-y: 4px;
+  --menu-item-collapse-margin-x: 0px;
+  --menu-item-radius: 0px;
+  --menu-item-indent: 16px;
+  --menu-font-size: 14px;
+
+  &.is-dark {
+    --menu-background-color: hsl(var(--menu));
+    // --menu-submenu-opened-background-color: hsl(var(--menu-opened-dark));
+    --menu-item-background-color: var(--menu-background-color);
+    --menu-item-color: hsl(var(--foreground) / 80%);
+    --menu-item-hover-color: hsl(var(--accent-foreground));
+    --menu-item-hover-background-color: hsl(var(--accent));
+    --menu-item-active-color: hsl(var(--accent-foreground));
+    --menu-item-active-background-color: hsl(var(--accent));
+    --menu-submenu-hover-color: hsl(var(--foreground));
+    --menu-submenu-hover-background-color: hsl(var(--accent));
+    --menu-submenu-active-color: hsl(var(--foreground));
+    --menu-submenu-active-background-color: transparent;
+    --menu-submenu-background-color: var(--menu-background-color);
+  }
+
+  &.is-light {
+    --menu-background-color: hsl(var(--menu));
+    // --menu-submenu-opened-background-color: hsl(var(--menu-opened));
+    --menu-item-background-color: var(--menu-background-color);
+    --menu-item-color: hsl(var(--foreground));
+    --menu-item-hover-color: var(--menu-item-color);
+    --menu-item-hover-background-color: hsl(var(--accent));
+    --menu-item-active-color: hsl(var(--primary));
+    --menu-item-active-background-color: hsl(var(--primary) / 15%);
+    --menu-submenu-hover-color: hsl(var(--primary));
+    --menu-submenu-hover-background-color: hsl(var(--accent));
+    --menu-submenu-active-color: hsl(var(--primary));
+    --menu-submenu-active-background-color: transparent;
+    --menu-submenu-background-color: var(--menu-background-color);
+  }
+
+  &.is-rounded {
+    --menu-item-margin-x: 8px;
+    --menu-item-collapse-margin-x: 6px;
+    --menu-item-radius: 8px;
+  }
+
+  &.is-horizontal:not(.is-rounded) {
+    --menu-item-height: 40px;
+    --menu-item-radius: 6px;
+  }
+
+  &.is-horizontal.is-rounded {
+    --menu-item-height: 40px;
+    --menu-item-radius: 6px;
+    --menu-item-padding-x: 12px;
+  }
+
+  // .vben-menu__popup,
+  &.is-horizontal {
+    --menu-item-padding-y: 0px;
+    --menu-item-padding-x: 10px;
+    --menu-item-margin-y: 0px;
+    --menu-item-margin-x: 1px;
+    --menu-background-color: transparent;
+
+    &.is-dark {
+      --menu-item-hover-color: hsl(var(--accent-foreground));
+      --menu-item-hover-background-color: hsl(var(--accent));
+      --menu-item-active-color: hsl(var(--accent-foreground));
+      --menu-item-active-background-color: hsl(var(--accent));
+      --menu-submenu-active-color: hsl(var(--foreground));
+      --menu-submenu-active-background-color: hsl(var(--accent));
+      --menu-submenu-hover-color: hsl(var(--accent-foreground));
+      --menu-submenu-hover-background-color: hsl(var(--accent));
+    }
+
+    &.is-light {
+      --menu-item-active-color: hsl(var(--primary));
+      --menu-item-active-background-color: hsl(var(--primary) / 15%);
+      --menu-item-hover-background-color: hsl(var(--accent));
+      --menu-item-hover-color: hsl(var(--primary));
+      --menu-submenu-active-color: hsl(var(--primary));
+      --menu-submenu-active-background-color: hsl(var(--primary) / 15%);
+      --menu-submenu-hover-color: hsl(var(--primary));
+      --menu-submenu-hover-background-color: hsl(var(--accent));
+    }
+  }
+}
+
+.#{$namespace}-menu {
+  position: relative;
+  box-sizing: border-box;
+  padding-left: 0;
+  margin: 0;
+  list-style: none;
+  background: hsl(var(--menu-background-color));
+
+  // 鍨傜洿鑿滃崟
+  &.is-vertical {
+    &:not(.#{$namespace}-menu.is-collapse) {
+      & .#{$namespace}-menu-item,
+      & .#{$namespace}-sub-menu-content,
+      & .#{$namespace}-menu-item-group__title {
+        padding-left: calc(
+          var(--menu-item-indent) + var(--menu-level) * var(--menu-item-indent)
+        );
+        white-space: nowrap;
+      }
+
+      & > .#{$namespace}-sub-menu {
+        & > .#{$namespace}-menu {
+          & > .#{$namespace}-menu-item {
+            padding-left: calc(
+              0px + var(--menu-item-indent) + var(--menu-level) *
+                var(--menu-item-indent)
+            );
+          }
+        }
+
+        & > .#{$namespace}-sub-menu-content {
+          padding-left: calc(var(--menu-item-indent) - 8px);
+        }
+      }
+      & > .#{$namespace}-menu-item {
+        padding-left: calc(var(--menu-item-indent) - 8px);
+      }
+    }
+  }
+
+  &.is-horizontal {
+    display: flex;
+    flex-wrap: nowrap;
+    max-width: 100%;
+    height: var(--height-horizontal-height);
+    border-right: none;
+
+    .#{$namespace}-menu-item {
+      display: inline-flex;
+      align-items: center;
+      justify-content: center;
+      height: var(--menu-item-height);
+      padding-right: calc(var(--menu-item-padding-x) + 6px);
+      margin: 0;
+      margin-right: 2px;
+      // border-bottom: 2px solid transparent;
+      border-radius: var(--menu-item-radius);
+    }
+
+    & > .#{$namespace}-sub-menu {
+      height: var(--menu-item-height);
+      margin-right: 2px;
+
+      &:focus,
+      &:hover {
+        outline: none;
+      }
+
+      & .#{$namespace}-sub-menu-content {
+        height: 100%;
+        padding-right: 40px;
+        // border-bottom: 2px solid transparent;
+        border-radius: var(--menu-item-radius);
+      }
+    }
+
+    & .#{$namespace}-menu-item:not(.is-disabled):hover,
+    & .#{$namespace}-menu-item:not(.is-disabled):focus {
+      outline: none;
+    }
+
+    & > .#{$namespace}-menu-item.is-active {
+      color: var(--menu-item-active-color);
+    }
+
+    // &.is-light {
+    //   & > .#{$namespace}-sub-menu {
+    //     &.is-active {
+    //       border-bottom: 2px solid var(--menu-item-active-color);
+    //     }
+    //     &:not(.is-active) .#{$namespace}-sub-menu-content {
+    //       &:hover {
+    //         border-bottom: 2px solid var(--menu-item-active-color);
+    //       }
+    //     }
+    //   }
+    //   & > .#{$namespace}-menu-item.is-active {
+    //     border-bottom: 2px solid var(--menu-item-active-color);
+    //   }
+
+    //   & .#{$namespace}-menu-item:not(.is-disabled):hover,
+    //   & .#{$namespace}-menu-item:not(.is-disabled):focus {
+    //     border-bottom: 2px solid var(--menu-item-active-color);
+    //   }
+    // }
+  }
+  // 鎶樺彔鑿滃崟
+
+  &.is-collapse {
+    .#{$namespace}-menu__icon {
+      margin-right: 0;
+    }
+    .#{$namespace}-sub-menu__icon-arrow {
+      display: none;
+    }
+
+    .#{$namespace}-sub-menu-content,
+    .#{$namespace}-menu-item {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding: var(--menu-item-collapse-padding-y)
+        var(--menu-item-collapse-padding-x);
+      margin: var(--menu-item-collapse-margin-y)
+        var(--menu-item-collapse-margin-x);
+      transition: all 0.3s;
+
+      &.is-active {
+        background: var(--menu-item-active-background-color) !important;
+        border-radius: var(--menu-item-radius);
+      }
+    }
+
+    &.is-light {
+      .#{$namespace}-sub-menu-content,
+      .#{$namespace}-menu-item {
+        &.is-active {
+          // color: hsl(var(--primary-foreground)) !important;
+          background: var(--menu-item-active-background-color) !important;
+        }
+      }
+    }
+
+    &.is-rounded {
+      .#{$namespace}-sub-menu-content,
+      .#{$namespace}-menu-item {
+        &.is-collapse-show-title {
+          // padding: 32px 0 !important;
+          margin: 4px 8px !important;
+        }
+      }
+    }
+  }
+
+  &__popup-container {
+    max-width: 240px;
+    height: unset;
+    padding: 0;
+    background: var(--menu-background-color);
+  }
+
+  &__popup {
+    padding: 10px 0;
+    border-radius: var(--menu-item-radius);
+
+    .#{$namespace}-sub-menu-content,
+    .#{$namespace}-menu-item {
+      padding: var(--menu-item-popup-padding-y) var(--menu-item-popup-padding-x);
+    }
+  }
+
+  &__icon {
+    flex-shrink: 0;
+    width: var(--menu-item-icon-size);
+    height: var(--menu-item-icon-size);
+    margin-right: 8px;
+    text-align: center;
+    vertical-align: middle;
+  }
+}
+
+.#{$namespace}-menu-item {
+  fill: var(--menu-item-color);
+
+  @include menu-item;
+
+  &.is-active {
+    fill: var(--menu-item-active-color);
+
+    @include menu-item-active;
+  }
+
+  &__content {
+    display: inline-flex;
+    align-items: center;
+    width: 100%;
+    height: var(--menu-item-height);
+
+    span {
+      @include menu-title;
+    }
+  }
+
+  &.is-collapse-show-title {
+    padding: 32px 0 !important;
+    // margin: 4px 8px !important;
+    .#{$namespace}-menu-tooltip__trigger {
+      flex-direction: column;
+    }
+    .#{$namespace}-menu__icon {
+      display: block;
+      font-size: 20px !important;
+      transition: all 0.25s ease;
+    }
+
+    .#{$namespace}-menu__name {
+      display: inline-flex;
+      margin-top: 8px;
+      margin-bottom: 0;
+      font-size: 12px;
+      font-weight: 400;
+      line-height: normal;
+      transition: all 0.25s ease;
+    }
+  }
+
+  &:not(.is-active):hover {
+    color: var(--menu-item-hover-color);
+    text-decoration: none;
+    cursor: pointer;
+    background: var(--menu-item-hover-background-color) !important;
+  }
+
+  .#{$namespace}-menu-tooltip__trigger {
+    position: absolute;
+    top: 0;
+    left: 0;
+    box-sizing: border-box;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    height: 100%;
+    padding: 0 var(--menu-item-padding-x);
+    font-size: var(--menu-font-size);
+    line-height: var(--menu-item-height);
+  }
+}
+
+.#{$namespace}-sub-menu {
+  padding-left: 0;
+  margin: 0;
+  list-style: none;
+  background: var(--menu-submenu-background-color);
+  fill: var(--menu-item-color);
+
+  &.is-active {
+    div[data-state='open'] > .#{$namespace}-sub-menu-content,
+    > .#{$namespace}-sub-menu-content {
+      // font-weight: 500;
+      color: var(--menu-submenu-active-color);
+      text-decoration: none;
+      cursor: pointer;
+      background: var(--menu-submenu-active-background-color);
+      fill: var(--menu-submenu-active-color);
+    }
+  }
+}
+
+.#{$namespace}-sub-menu-content {
+  height: var(--menu-item-height);
+
+  @include menu-item;
+
+  &__icon-arrow {
+    position: absolute;
+    top: 50%;
+    right: 10px;
+    width: inherit;
+    margin-top: -8px;
+    margin-right: 0;
+    // font-size: 16px;
+    font-weight: normal;
+    opacity: 1;
+    transition: transform 0.25s ease;
+  }
+
+  &__title {
+    @include menu-title;
+  }
+
+  &.is-collapse-show-title {
+    flex-direction: column;
+    padding: 32px 0 !important;
+    // margin: 4px 8px !important;
+    .#{$namespace}-menu__icon {
+      display: block;
+      font-size: 20px !important;
+      transition: all 0.25s ease;
+    }
+    .#{$namespace}-sub-menu-content__title {
+      display: inline-flex;
+      flex-shrink: 0;
+      margin-top: 8px;
+      margin-bottom: 0;
+      font-size: 12px;
+      font-weight: 400;
+      line-height: normal;
+      transition: all 0.25s ease;
+    }
+  }
+
+  &.is-more {
+    padding-right: 12px !important;
+  }
+
+  // &:not(.is-active):hover {
+  &:hover {
+    color: var(--menu-submenu-hover-color);
+    text-decoration: none;
+    cursor: pointer;
+    background: var(--menu-submenu-hover-background-color) !important;
+
+    // svg {
+    //   fill: var(--menu-submenu-hover-color);
+    // }
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts
new file mode 100644
index 0000000..898ea16
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts
@@ -0,0 +1,2 @@
+export type * from './normal-menu';
+export { default as NormalMenu } from './normal-menu.vue';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts
new file mode 100644
index 0000000..82edb4f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts
@@ -0,0 +1,27 @@
+import type { MenuRecordRaw } from '@vben-core/typings';
+
+interface NormalMenuProps {
+  /**
+   * 鑿滃崟鏁版嵁
+   */
+  activePath?: string;
+  /**
+   * 鏄惁鎶樺彔
+   */
+  collapse?: boolean;
+  /**
+   * 鑿滃崟椤�
+   */
+  menus?: MenuRecordRaw[];
+  /**
+   * @zh_CN 鏄惁鍦嗘鼎椋庢牸
+   * @default true
+   */
+  rounded?: boolean;
+  /**
+   * 涓婚
+   */
+  theme?: 'dark' | 'light';
+}
+
+export type { NormalMenuProps };
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue
new file mode 100644
index 0000000..7cb29e5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue
@@ -0,0 +1,161 @@
+<script setup lang="ts">
+import type { MenuRecordRaw } from '@vben-core/typings';
+
+import type { NormalMenuProps } from './normal-menu';
+
+import { useNamespace } from '@vben-core/composables';
+import { VbenIcon } from '@vben-core/shadcn-ui';
+
+interface Props extends NormalMenuProps {}
+
+defineOptions({
+  name: 'NormalMenu',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  activePath: '',
+  collapse: false,
+  menus: () => [],
+  theme: 'dark',
+});
+
+const emit = defineEmits<{
+  enter: [MenuRecordRaw];
+  select: [MenuRecordRaw];
+}>();
+
+const { b, e, is } = useNamespace('normal-menu');
+
+function menuIcon(menu: MenuRecordRaw) {
+  return props.activePath === menu.path
+    ? menu.activeIcon || menu.icon
+    : menu.icon;
+}
+</script>
+
+<template>
+  <ul
+    :class="[
+      theme,
+      b(),
+      is('collapse', collapse),
+      is(theme, true),
+      is('rounded', rounded),
+    ]"
+    class="relative"
+  >
+    <template v-for="menu in menus" :key="menu.path">
+      <li
+        :class="[e('item'), is('active', activePath === menu.path)]"
+        @click="() => emit('select', menu)"
+        @mouseenter="() => emit('enter', menu)"
+      >
+        <VbenIcon :class="e('icon')" :icon="menuIcon(menu)" fallback />
+
+        <span :class="e('name')" class="truncate"> {{ menu.name }}</span>
+      </li>
+    </template>
+  </ul>
+</template>
+<style lang="scss" scoped>
+$namespace: vben;
+
+.#{$namespace}-normal-menu {
+  --menu-item-margin-y: 4px;
+  --menu-item-margin-x: 0px;
+  --menu-item-padding-y: 9px;
+  --menu-item-padding-x: 0px;
+  --menu-item-radius: 0px;
+
+  height: calc(100% - 4px);
+
+  &.is-rounded {
+    --menu-item-radius: 6px;
+    --menu-item-margin-x: 8px;
+  }
+
+  &.is-dark {
+    .#{$namespace}-normal-menu__item {
+      @apply text-foreground/80;
+      // color: hsl(var(--foreground) / 80%);
+
+      &:not(.is-active):hover {
+        @apply text-foreground;
+      }
+
+      &.is-active {
+        .#{$namespace}-normal-menu__name,
+        .#{$namespace}-normal-menu__icon {
+          @apply text-foreground;
+        }
+      }
+    }
+  }
+
+  &.is-collapse {
+    .#{$namespace}-normal-menu__name {
+      width: 0;
+      height: 0;
+      margin-top: 0;
+      overflow: hidden;
+      opacity: 0;
+    }
+
+    .#{$namespace}-normal-menu__icon {
+      font-size: 20px;
+    }
+  }
+
+  &__item {
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    // max-width: 64px;
+    // max-height: 64px;
+    padding: var(--menu-item-padding-y) var(--menu-item-padding-x);
+    margin: var(--menu-item-margin-y) var(--menu-item-margin-x);
+    color: hsl(var(--foreground) / 90%);
+    cursor: pointer;
+    border-radius: var(--menu-item-radius);
+    transition:
+      background 0.15s ease,
+      padding 0.15s ease,
+      border-color 0.15s ease;
+
+    &.is-active {
+      @apply text-primary bg-primary dark:bg-accent;
+
+      .#{$namespace}-normal-menu__name,
+      .#{$namespace}-normal-menu__icon {
+        @apply text-primary-foreground font-semibold;
+      }
+    }
+
+    &:not(.is-active):hover {
+      @apply dark:bg-accent text-primary bg-heavy dark:text-foreground;
+    }
+
+    &:hover {
+      .#{$namespace}-normal-menu__icon {
+        transform: scale(1.2);
+      }
+    }
+  }
+
+  &__icon {
+    max-height: 20px;
+    font-size: 20px;
+    transition: all 0.25s ease;
+  }
+
+  &__name {
+    margin-top: 8px;
+    margin-bottom: 0;
+    font-size: 12px;
+    font-weight: 400;
+    transition: all 0.25s ease;
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue
new file mode 100644
index 0000000..31eead1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue
@@ -0,0 +1,105 @@
+<script lang="ts" setup>
+import type { MenuItemProps } from '../types';
+
+import { computed } from 'vue';
+
+import { useNamespace } from '@vben-core/composables';
+import { ChevronDown, ChevronRight } from '@vben-core/icons';
+import { VbenIcon } from '@vben-core/shadcn-ui';
+
+import { useMenuContext } from '../hooks';
+
+interface Props extends MenuItemProps {
+  isMenuMore: boolean;
+  isTopLevelMenuSubmenu: boolean;
+  level?: number;
+}
+
+defineOptions({ name: 'SubMenuContent' });
+
+const props = withDefaults(defineProps<Props>(), {
+  isMenuMore: false,
+  level: 0,
+});
+
+const rootMenu = useMenuContext();
+const { b, e, is } = useNamespace('sub-menu-content');
+const nsMenu = useNamespace('menu');
+
+const opened = computed(() => {
+  return rootMenu?.openedMenus.includes(props.path);
+});
+
+const collapse = computed(() => {
+  return rootMenu.props.collapse;
+});
+
+const isFirstLevel = computed(() => {
+  return props.level === 1;
+});
+
+const getCollapseShowTitle = computed(() => {
+  return (
+    rootMenu.props.collapseShowTitle && isFirstLevel.value && collapse.value
+  );
+});
+
+const mode = computed(() => {
+  return rootMenu?.props.mode;
+});
+
+const showArrowIcon = computed(() => {
+  return mode.value === 'horizontal' || !(isFirstLevel.value && collapse.value);
+});
+
+const hiddenTitle = computed(() => {
+  return (
+    mode.value === 'vertical' &&
+    isFirstLevel.value &&
+    collapse.value &&
+    !getCollapseShowTitle.value
+  );
+});
+
+const iconComp = computed(() => {
+  return (mode.value === 'horizontal' && !isFirstLevel.value) ||
+    (mode.value === 'vertical' && collapse.value)
+    ? ChevronRight
+    : ChevronDown;
+});
+
+const iconArrowStyle = computed(() => {
+  return opened.value ? { transform: `rotate(180deg)` } : {};
+});
+</script>
+<template>
+  <div
+    :class="[
+      b(),
+      is('collapse-show-title', getCollapseShowTitle),
+      is('more', isMenuMore),
+    ]"
+  >
+    <slot></slot>
+
+    <VbenIcon
+      v-if="!isMenuMore"
+      :class="nsMenu.e('icon')"
+      :icon="icon"
+      fallback
+    />
+
+    <div v-if="!hiddenTitle" :class="[e('title')]">
+      <slot name="title"></slot>
+    </div>
+
+    <component
+      :is="iconComp"
+      v-if="!isMenuMore"
+      v-show="showArrowIcon"
+      :class="[e('icon-arrow')]"
+      :style="iconArrowStyle"
+      class="size-4"
+    />
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue
new file mode 100644
index 0000000..17bc121
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue
@@ -0,0 +1,273 @@
+<script lang="ts" setup>
+import type { HoverCardContentProps } from '@vben-core/shadcn-ui';
+
+import type { MenuItemRegistered, MenuProvider, SubMenuProps } from '../types';
+
+import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
+
+import { useNamespace } from '@vben-core/composables';
+import { VbenHoverCard } from '@vben-core/shadcn-ui';
+
+import {
+  createSubMenuContext,
+  useMenu,
+  useMenuContext,
+  useMenuStyle,
+  useSubMenuContext,
+} from '../hooks';
+import CollapseTransition from './collapse-transition.vue';
+import SubMenuContent from './sub-menu-content.vue';
+
+interface Props extends SubMenuProps {
+  isSubMenuMore?: boolean;
+}
+
+defineOptions({ name: 'SubMenu' });
+
+const props = withDefaults(defineProps<Props>(), {
+  disabled: false,
+  isSubMenuMore: false,
+});
+
+const { parentMenu, parentPaths } = useMenu();
+const { b, is } = useNamespace('sub-menu');
+const nsMenu = useNamespace('menu');
+const rootMenu = useMenuContext();
+const subMenu = useSubMenuContext();
+const subMenuStyle = useMenuStyle(subMenu);
+
+const mouseInChild = ref(false);
+
+const items = ref<MenuProvider['items']>({});
+const subMenus = ref<MenuProvider['subMenus']>({});
+const timer = ref<null | ReturnType<typeof setTimeout>>(null);
+
+createSubMenuContext({
+  addSubMenu,
+  handleMouseleave,
+  level: (subMenu?.level ?? 0) + 1,
+  mouseInChild,
+  removeSubMenu,
+});
+
+const opened = computed(() => {
+  return rootMenu?.openedMenus.includes(props.path);
+});
+const isTopLevelMenuSubmenu = computed(
+  () => parentMenu.value?.type.name === 'Menu',
+);
+const mode = computed(() => rootMenu?.props.mode ?? 'vertical');
+const rounded = computed(() => rootMenu?.props.rounded);
+const currentLevel = computed(() => subMenu?.level ?? 0);
+const isFirstLevel = computed(() => {
+  return currentLevel.value === 1;
+});
+
+const contentProps = computed((): HoverCardContentProps => {
+  const isHorizontal = mode.value === 'horizontal';
+  const side = isHorizontal && isFirstLevel.value ? 'bottom' : 'right';
+  return {
+    collisionPadding: { top: 20 },
+    side,
+    sideOffset: isHorizontal ? 5 : 10,
+  };
+});
+
+const active = computed(() => {
+  let isActive = false;
+
+  Object.values(items.value).forEach((item) => {
+    if (item.active) {
+      isActive = true;
+    }
+  });
+
+  Object.values(subMenus.value).forEach((subItem) => {
+    if (subItem.active) {
+      isActive = true;
+    }
+  });
+  return isActive;
+});
+
+function addSubMenu(subMenu: MenuItemRegistered) {
+  subMenus.value[subMenu.path] = subMenu;
+}
+
+function removeSubMenu(subMenu: MenuItemRegistered) {
+  Reflect.deleteProperty(subMenus.value, subMenu.path);
+}
+
+/**
+ * 鐐瑰嚮submenu灞曞紑/鍏抽棴
+ */
+function handleClick() {
+  const mode = rootMenu?.props.mode;
+  if (
+    // 褰撳墠鑿滃崟绂佺敤鏃讹紝涓嶅睍寮�
+    props.disabled ||
+    (rootMenu?.props.collapse && mode === 'vertical') ||
+    // 姘村钩妯″紡涓嬩笉灞曞紑
+    mode === 'horizontal'
+  ) {
+    return;
+  }
+
+  rootMenu?.handleSubMenuClick({
+    active: active.value,
+    parentPaths: parentPaths.value,
+    path: props.path,
+  });
+}
+
+function handleMouseenter(event: FocusEvent | MouseEvent, showTimeout = 300) {
+  if (event.type === 'focus') {
+    return;
+  }
+
+  if (
+    (!rootMenu?.props.collapse && rootMenu?.props.mode === 'vertical') ||
+    props.disabled
+  ) {
+    if (subMenu) {
+      subMenu.mouseInChild.value = true;
+    }
+    return;
+  }
+  if (subMenu) {
+    subMenu.mouseInChild.value = true;
+  }
+
+  timer.value && window.clearTimeout(timer.value);
+  timer.value = setTimeout(() => {
+    rootMenu?.openMenu(props.path, parentPaths.value);
+  }, showTimeout);
+  parentMenu.value?.vnode.el?.dispatchEvent(new MouseEvent('mouseenter'));
+}
+
+function handleMouseleave(deepDispatch = false) {
+  if (
+    !rootMenu?.props.collapse &&
+    rootMenu?.props.mode === 'vertical' &&
+    subMenu
+  ) {
+    subMenu.mouseInChild.value = false;
+    return;
+  }
+
+  timer.value && window.clearTimeout(timer.value);
+
+  if (subMenu) {
+    subMenu.mouseInChild.value = false;
+  }
+  timer.value = setTimeout(() => {
+    !mouseInChild.value && rootMenu?.closeMenu(props.path, parentPaths.value);
+  }, 300);
+
+  if (deepDispatch) {
+    subMenu?.handleMouseleave?.(true);
+  }
+}
+
+const menuIcon = computed(() =>
+  active.value ? props.activeIcon || props.icon : props.icon,
+);
+
+const item = reactive({
+  active,
+  parentPaths,
+  path: props.path,
+});
+
+onMounted(() => {
+  subMenu?.addSubMenu?.(item);
+  rootMenu?.addSubMenu?.(item);
+});
+
+onBeforeUnmount(() => {
+  subMenu?.removeSubMenu?.(item);
+  rootMenu?.removeSubMenu?.(item);
+});
+</script>
+<template>
+  <li
+    :class="[
+      b(),
+      is('opened', opened),
+      is('active', active),
+      is('disabled', disabled),
+    ]"
+    @focus="handleMouseenter"
+    @mouseenter="handleMouseenter"
+    @mouseleave="() => handleMouseleave()"
+  >
+    <template v-if="rootMenu.isMenuPopup">
+      <VbenHoverCard
+        :content-class="[
+          rootMenu.theme,
+          nsMenu.e('popup-container'),
+          is(rootMenu.theme, true),
+          opened ? '' : 'hidden',
+        ]"
+        :content-props="contentProps"
+        :open="true"
+        :open-delay="0"
+      >
+        <template #trigger>
+          <SubMenuContent
+            :class="is('active', active)"
+            :icon="menuIcon"
+            :is-menu-more="isSubMenuMore"
+            :is-top-level-menu-submenu="isTopLevelMenuSubmenu"
+            :level="currentLevel"
+            :path="path"
+            @click.stop="handleClick"
+          >
+            <template #title>
+              <slot name="title"></slot>
+            </template>
+          </SubMenuContent>
+        </template>
+        <div
+          :class="[nsMenu.is(mode, true), nsMenu.e('popup')]"
+          @focus="(e) => handleMouseenter(e, 100)"
+          @mouseenter="(e) => handleMouseenter(e, 100)"
+          @mouseleave="() => handleMouseleave(true)"
+        >
+          <ul
+            :class="[nsMenu.b(), is('rounded', rounded)]"
+            :style="subMenuStyle"
+          >
+            <slot></slot>
+          </ul>
+        </div>
+      </VbenHoverCard>
+    </template>
+
+    <template v-else>
+      <SubMenuContent
+        :class="is('active', active)"
+        :icon="menuIcon"
+        :is-menu-more="isSubMenuMore"
+        :is-top-level-menu-submenu="isTopLevelMenuSubmenu"
+        :level="currentLevel"
+        :path="path"
+        @click.stop="handleClick"
+      >
+        <slot name="content"></slot>
+        <template #title>
+          <slot name="title"></slot>
+        </template>
+      </SubMenuContent>
+      <CollapseTransition>
+        <ul
+          v-show="opened"
+          :class="[nsMenu.b(), is('rounded', rounded)]"
+          :style="subMenuStyle"
+        >
+          <slot></slot>
+        </ul>
+      </CollapseTransition>
+    </template>
+  </li>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/index.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/index.ts
new file mode 100644
index 0000000..f9acf32
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/index.ts
@@ -0,0 +1,2 @@
+export * from './use-menu';
+export * from './use-menu-context';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts
new file mode 100644
index 0000000..357b296
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts
@@ -0,0 +1,55 @@
+import type { MenuProvider, SubMenuProvider } from '../types';
+
+import { getCurrentInstance, inject, provide } from 'vue';
+
+import { findComponentUpward } from '../utils';
+
+const menuContextKey = Symbol('menuContext');
+
+/**
+ * @zh_CN Provide menu context
+ */
+function createMenuContext(injectMenuData: MenuProvider) {
+  provide(menuContextKey, injectMenuData);
+}
+
+/**
+ * @zh_CN Provide menu context
+ */
+function createSubMenuContext(injectSubMenuData: SubMenuProvider) {
+  const instance = getCurrentInstance();
+
+  provide(`subMenu:${instance?.uid}`, injectSubMenuData);
+}
+
+/**
+ * @zh_CN Inject menu context
+ */
+function useMenuContext() {
+  const instance = getCurrentInstance();
+  if (!instance) {
+    throw new Error('instance is required');
+  }
+  const rootMenu = inject(menuContextKey) as MenuProvider;
+  return rootMenu;
+}
+
+/**
+ * @zh_CN Inject menu context
+ */
+function useSubMenuContext() {
+  const instance = getCurrentInstance();
+  if (!instance) {
+    throw new Error('instance is required');
+  }
+  const parentMenu = findComponentUpward(instance, ['Menu', 'SubMenu']);
+  const subMenu = inject(`subMenu:${parentMenu?.uid}`) as SubMenuProvider;
+  return subMenu;
+}
+
+export {
+  createMenuContext,
+  createSubMenuContext,
+  useMenuContext,
+  useSubMenuContext,
+};
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts
new file mode 100644
index 0000000..9207445
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts
@@ -0,0 +1,48 @@
+import type { SubMenuProvider } from '../types';
+
+import { computed, getCurrentInstance } from 'vue';
+
+import { findComponentUpward } from '../utils';
+
+function useMenu() {
+  const instance = getCurrentInstance();
+  if (!instance) {
+    throw new Error('instance is required');
+  }
+
+  /**
+   * @zh_CN 鑾峰彇鎵�鏈夌埗绾ц彍鍗曢摼璺�
+   */
+  const parentPaths = computed(() => {
+    let parent = instance.parent;
+    const paths: string[] = [instance.props.path as string];
+    while (parent?.type.name !== 'Menu') {
+      if (parent?.props.path) {
+        paths.unshift(parent.props.path as string);
+      }
+      parent = parent?.parent ?? null;
+    }
+
+    return paths;
+  });
+
+  const parentMenu = computed(() => {
+    return findComponentUpward(instance, ['Menu', 'SubMenu']);
+  });
+
+  return {
+    parentMenu,
+    parentPaths,
+  };
+}
+
+function useMenuStyle(menu?: SubMenuProvider) {
+  const subMenuStyle = computed(() => {
+    return {
+      '--menu-level': menu ? (menu?.level ?? 0 + 1) : 0,
+    };
+  });
+  return subMenuStyle;
+}
+
+export { useMenu, useMenuStyle };
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/index.ts
new file mode 100644
index 0000000..575a233
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/index.ts
@@ -0,0 +1,3 @@
+export * from './components/normal-menu';
+export { default as Menu } from './menu.vue';
+export type * from './types';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/menu.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/menu.vue
new file mode 100644
index 0000000..4ecf6a9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/menu.vue
@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import type { MenuRecordRaw } from '@vben-core/typings';
+
+import type { MenuProps } from './types';
+
+import { useForwardProps } from '@vben-core/composables';
+
+import { Menu } from './components';
+import SubMenu from './sub-menu.vue';
+
+interface Props extends MenuProps {
+  menus: MenuRecordRaw[];
+}
+
+defineOptions({
+  name: 'MenuView',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  collapse: false,
+  // theme: 'dark',
+});
+
+const forward = useForwardProps(props);
+
+// const emit = defineEmits<{
+//   'update:openKeys': [key: Key[]];
+//   'update:selectedKeys': [key: Key[]];
+// }>();
+</script>
+
+<template>
+  <Menu v-bind="forward">
+    <template v-for="menu in menus" :key="menu.path">
+      <SubMenu :menu="menu" />
+    </template>
+  </Menu>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/sub-menu.vue b/eims-ui/packages/@core/ui-kit/menu-ui/src/sub-menu.vue
new file mode 100644
index 0000000..e4d471f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/sub-menu.vue
@@ -0,0 +1,71 @@
+<script setup lang="ts">
+import type { MenuRecordRaw } from '@vben-core/typings';
+
+import { computed } from 'vue';
+
+import { MenuBadge, MenuItem, SubMenu as SubMenuComp } from './components';
+// eslint-disable-next-line import/no-self-import
+import SubMenu from './sub-menu.vue';
+
+interface Props {
+  /**
+   * 鑿滃崟椤�
+   */
+  menu: MenuRecordRaw;
+}
+
+defineOptions({
+  name: 'SubMenuUi',
+});
+
+const props = withDefaults(defineProps<Props>(), {});
+
+/**
+ * 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣锛屽姩鎬佹覆鏌� menu-item/sub-menu-item
+ */
+const hasChildren = computed(() => {
+  const { menu } = props;
+  return (
+    Reflect.has(menu, 'children') && !!menu.children && menu.children.length > 0
+  );
+});
+</script>
+
+<template>
+  <MenuItem
+    v-if="!hasChildren"
+    :key="menu.path"
+    :active-icon="menu.activeIcon"
+    :badge="menu.badge"
+    :badge-type="menu.badgeType"
+    :badge-variants="menu.badgeVariants"
+    :icon="menu.icon"
+    :path="menu.path"
+  >
+    <template #title>
+      <span>{{ menu.name }}</span>
+    </template>
+  </MenuItem>
+  <SubMenuComp
+    v-else
+    :key="`${menu.path}_sub`"
+    :active-icon="menu.activeIcon"
+    :icon="menu.icon"
+    :path="menu.path"
+  >
+    <template #content>
+      <MenuBadge
+        :badge="menu.badge"
+        :badge-type="menu.badgeType"
+        :badge-variants="menu.badgeVariants"
+        class="right-6"
+      />
+    </template>
+    <template #title>
+      <span>{{ menu.name }}</span>
+    </template>
+    <template v-for="childItem in menu.children || []" :key="childItem.path">
+      <SubMenu :menu="childItem" />
+    </template>
+  </SubMenuComp>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/types.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/types.ts
new file mode 100644
index 0000000..99422e8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/types.ts
@@ -0,0 +1,139 @@
+import type { MenuRecordBadgeRaw, ThemeModeType } from '@vben-core/typings';
+
+import type { Component, Ref } from 'vue';
+
+interface MenuProps {
+  /**
+   * @zh_CN 鏄惁寮�鍚墜椋庣惔妯″紡
+   * @default true
+   */
+  accordion?: boolean;
+  /**
+   * @zh_CN 鑿滃崟鏄惁鎶樺彔
+   * @default false
+   */
+  collapse?: boolean;
+
+  /**
+   * @zh_CN 鑿滃崟鎶樺彔鏃舵槸鍚︽樉绀鸿彍鍗曞悕绉�
+   * @default false
+   */
+  collapseShowTitle?: boolean;
+
+  /**
+   * @zh_CN 榛樿婵�娲荤殑鑿滃崟
+   */
+  defaultActive?: string;
+
+  /**
+   * @zh_CN 榛樿灞曞紑鐨勮彍鍗�
+   */
+  defaultOpeneds?: string[];
+
+  /**
+   * @zh_CN 鑿滃崟妯″紡
+   * @default vertical
+   */
+  mode?: 'horizontal' | 'vertical';
+
+  /**
+   * @zh_CN 鏄惁鍦嗘鼎椋庢牸
+   * @default true
+   */
+  rounded?: boolean;
+
+  /**
+   * @zh_CN 鑿滃崟涓婚
+   * @default dark
+   */
+  theme?: ThemeModeType;
+}
+
+interface SubMenuProps extends MenuRecordBadgeRaw {
+  /**
+   * @zh_CN 婵�娲诲浘鏍�
+   */
+  activeIcon?: string;
+  /**
+   * @zh_CN 鏄惁绂佺敤
+   */
+  disabled?: boolean;
+  /**
+   * @zh_CN 鍥炬爣
+   */
+  icon?: Component | string;
+  /**
+   * @zh_CN submenu 鍚嶇О
+   */
+  path: string;
+}
+
+interface MenuItemProps extends MenuRecordBadgeRaw {
+  /**
+   * @zh_CN 鍥炬爣
+   */
+  activeIcon?: string;
+  /**
+   * @zh_CN 鏄惁绂佺敤
+   */
+  disabled?: boolean;
+  /**
+   * @zh_CN 鍥炬爣
+   */
+  icon?: Component | string;
+  /**
+   * @zh_CN menuitem 鍚嶇О
+   */
+  path: string;
+}
+
+interface MenuItemRegistered {
+  active: boolean;
+  parentPaths: string[];
+  path: string;
+}
+
+interface MenuItemClicked {
+  parentPaths: string[];
+  path: string;
+}
+
+interface MenuProvider {
+  activePath?: string;
+  addMenuItem: (item: MenuItemRegistered) => void;
+
+  addSubMenu: (item: MenuItemRegistered) => void;
+  closeMenu: (path: string, parentLinks: string[]) => void;
+  handleMenuItemClick: (item: MenuItemClicked) => void;
+  handleSubMenuClick: (subMenu: MenuItemRegistered) => void;
+  isMenuPopup: boolean;
+  items: Record<string, MenuItemRegistered>;
+
+  openedMenus: string[];
+  openMenu: (path: string, parentLinks: string[]) => void;
+  props: MenuProps;
+  removeMenuItem: (item: MenuItemRegistered) => void;
+
+  removeSubMenu: (item: MenuItemRegistered) => void;
+
+  subMenus: Record<string, MenuItemRegistered>;
+  theme: string;
+}
+
+interface SubMenuProvider {
+  addSubMenu: (item: MenuItemRegistered) => void;
+  handleMouseleave?: (deepDispatch: boolean) => void;
+  level: number;
+  mouseInChild: Ref<boolean>;
+  removeSubMenu: (item: MenuItemRegistered) => void;
+}
+
+export type {
+  MenuItemClicked,
+  MenuItemProps,
+  MenuItemRegistered,
+  MenuProps,
+  MenuProvider,
+  SubMenuProps,
+  SubMenuProvider,
+};
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/src/utils/index.ts b/eims-ui/packages/@core/ui-kit/menu-ui/src/utils/index.ts
new file mode 100644
index 0000000..dd6a85c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/src/utils/index.ts
@@ -0,0 +1,51 @@
+import type {
+  ComponentInternalInstance,
+  VNode,
+  VNodeChild,
+  VNodeNormalizedChildren,
+} from 'vue';
+import { isVNode } from 'vue';
+
+type VNodeChildAtom = Exclude<VNodeChild, Array<any>>;
+type RawSlots = Exclude<VNodeNormalizedChildren, Array<any> | null | string>;
+
+type FlattenVNodes = Array<RawSlots | VNodeChildAtom>;
+
+/**
+ * @zh_CN Find the parent component upward
+ * @param instance
+ * @param parentNames
+ */
+function findComponentUpward(
+  instance: ComponentInternalInstance,
+  parentNames: string[],
+) {
+  let parent = instance.parent;
+  while (parent && !parentNames.includes(parent?.type?.name ?? '')) {
+    parent = parent.parent;
+  }
+  return parent;
+}
+
+const flattedChildren = (
+  children: FlattenVNodes | VNode | VNodeNormalizedChildren,
+): FlattenVNodes => {
+  const vNodes = Array.isArray(children) ? children : [children];
+  const result: FlattenVNodes = [];
+
+  vNodes.forEach((child) => {
+    if (Array.isArray(child)) {
+      result.push(...flattedChildren(child));
+    } else if (isVNode(child) && Array.isArray(child.children)) {
+      result.push(...flattedChildren(child.children));
+    } else {
+      result.push(child);
+      if (isVNode(child) && child.component?.subTree) {
+        result.push(...flattedChildren(child.component.subTree));
+      }
+    }
+  });
+  return result;
+};
+
+export { findComponentUpward, flattedChildren };
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/menu-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/menu-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/menu-ui/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/menu-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/popup-ui/build.config.ts
new file mode 100644
index 0000000..18eaa60
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/build.config.ts
@@ -0,0 +1,21 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/package.json b/eims-ui/packages/@core/ui-kit/popup-ui/package.json
new file mode 100644
index 0000000..3ef78c7
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@vben-core/popup-ui",
+  "version": "5.2.1",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/popup-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/popup-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts
new file mode 100644
index 0000000..8d715ff
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts
@@ -0,0 +1,113 @@
+import type { DrawerState } from '../drawer';
+
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { DrawerApi } from '../drawer-api';
+
+// 妯℃嫙 Store 绫�
+vi.mock('@vben-core/shared/store', () => {
+  return {
+    isFunction: (fn: any) => typeof fn === 'function',
+    Store: class {
+      private _state: DrawerState;
+      private options: any;
+
+      constructor(initialState: DrawerState, options: any) {
+        this._state = initialState;
+        this.options = options;
+      }
+
+      batch(cb: () => void) {
+        cb();
+      }
+
+      setState(fn: (prev: DrawerState) => DrawerState) {
+        this._state = fn(this._state);
+        this.options.onUpdate();
+      }
+
+      get state() {
+        return this._state;
+      }
+    },
+  };
+});
+
+describe('drawerApi', () => {
+  let drawerApi: DrawerApi;
+  let drawerState: DrawerState;
+
+  beforeEach(() => {
+    drawerApi = new DrawerApi();
+    drawerState = drawerApi.store.state;
+  });
+
+  it('should initialize with default state', () => {
+    expect(drawerState.isOpen).toBe(false);
+    expect(drawerState.cancelText).toBe(undefined);
+    expect(drawerState.confirmText).toBe(undefined);
+  });
+
+  it('should open the drawer', () => {
+    drawerApi.open();
+    expect(drawerApi.store.state.isOpen).toBe(true);
+  });
+
+  it('should close the drawer if onBeforeClose allows it', () => {
+    drawerApi.open();
+    drawerApi.close();
+    expect(drawerApi.store.state.isOpen).toBe(false);
+  });
+
+  it('should not close the drawer if onBeforeClose returns false', () => {
+    const onBeforeClose = vi.fn(() => false);
+    const drawerApiWithHook = new DrawerApi({ onBeforeClose });
+    drawerApiWithHook.open();
+    drawerApiWithHook.close();
+    expect(drawerApiWithHook.store.state.isOpen).toBe(true);
+    expect(onBeforeClose).toHaveBeenCalled();
+  });
+
+  it('should trigger onCancel and keep drawer open if onCancel is provided', () => {
+    const onCancel = vi.fn();
+    const drawerApiWithHook = new DrawerApi({ onCancel });
+    drawerApiWithHook.open();
+    drawerApiWithHook.onCancel();
+    expect(onCancel).toHaveBeenCalled();
+    expect(drawerApiWithHook.store.state.isOpen).toBe(true); // 鍏抽棴閫昏緫涓嶅湪 onCancel 鍐�
+  });
+
+  it('should update shared data correctly', () => {
+    const testData = { key: 'value' };
+    drawerApi.setData(testData);
+    expect(drawerApi.getData()).toEqual(testData);
+  });
+
+  it('should set state correctly using an object', () => {
+    drawerApi.setState({ title: 'New Title' });
+    expect(drawerApi.store.state.title).toBe('New Title');
+  });
+
+  it('should set state correctly using a function', () => {
+    drawerApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));
+    expect(drawerApi.store.state.confirmText).toBe('Yes');
+  });
+
+  it('should call onOpenChange when state changes', () => {
+    const onOpenChange = vi.fn();
+    const drawerApiWithHook = new DrawerApi({ onOpenChange });
+    drawerApiWithHook.open();
+    expect(onOpenChange).toHaveBeenCalledWith(true);
+  });
+
+  it('should batch state updates', () => {
+    const batchSpy = vi.spyOn(drawerApi.store, 'batch');
+    drawerApi.batchStore(() => {
+      drawerApi.setState({ title: 'Batch Title' });
+      drawerApi.setState({ confirmText: 'Batch Confirm' });
+    });
+    expect(batchSpy).toHaveBeenCalled();
+    expect(drawerApi.store.state.title).toBe('Batch Title');
+    expect(drawerApi.store.state.confirmText).toBe('Batch Confirm');
+  });
+});
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
new file mode 100644
index 0000000..ca23d10
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
@@ -0,0 +1,143 @@
+import type { DrawerApiOptions, DrawerState } from './drawer';
+
+import { Store } from '@vben-core/shared/store';
+import { bindMethods, isFunction } from '@vben-core/shared/utils';
+
+export class DrawerApi {
+  private api: Pick<
+    DrawerApiOptions,
+    'onBeforeClose' | 'onCancel' | 'onConfirm' | 'onOpenChange'
+  >;
+  // private prevState!: DrawerState;
+  private state!: DrawerState;
+
+  // 鍏变韩鏁版嵁
+  public sharedData: Record<'payload', any> = {
+    payload: {},
+  };
+
+  public store: Store<DrawerState>;
+
+  constructor(options: DrawerApiOptions = {}) {
+    const {
+      connectedComponent: _,
+      onBeforeClose,
+      onCancel,
+      onConfirm,
+      onOpenChange,
+      ...storeState
+    } = options;
+
+    const defaultState: DrawerState = {
+      class: '',
+      closable: true,
+      closeOnClickModal: true,
+      closeOnPressEscape: true,
+      confirmLoading: false,
+      contentClass: '',
+      footer: true,
+      header: true,
+      isOpen: false,
+      loading: false,
+      modal: true,
+      openAutoFocus: false,
+      placement: 'right',
+      showCancelButton: true,
+      showConfirmButton: true,
+      title: '',
+    };
+
+    this.store = new Store<DrawerState>(
+      {
+        ...defaultState,
+        ...storeState,
+      },
+      {
+        onUpdate: () => {
+          const state = this.store.state;
+          if (state?.isOpen === this.state?.isOpen) {
+            this.state = state;
+          } else {
+            this.state = state;
+            this.api.onOpenChange?.(!!state?.isOpen);
+          }
+        },
+      },
+    );
+    this.state = this.store.state;
+    this.api = {
+      onBeforeClose,
+      onCancel,
+      onConfirm,
+      onOpenChange,
+    };
+    bindMethods(this);
+  }
+
+  // 濡傛灉闇�瑕佸娆℃洿鏂扮姸鎬侊紝鍙互浣跨敤 batch 鏂规硶
+  batchStore(cb: () => void) {
+    this.store.batch(cb);
+  }
+
+  /**
+   * 鍏抽棴寮圭獥
+   */
+  close() {
+    // 閫氳繃 onBeforeClose 閽╁瓙鍑芥暟鏉ュ垽鏂槸鍚﹀厑璁稿叧闂脊绐�
+    // 濡傛灉 onBeforeClose 杩斿洖 false锛屽垯涓嶅叧闂脊绐�
+    const allowClose = this.api.onBeforeClose?.() ?? true;
+    if (allowClose) {
+      this.store.setState((prev) => ({ ...prev, isOpen: false }));
+    }
+  }
+
+  drawerLoading(loading: boolean) {
+    this.store.setState((prev) => ({
+      ...prev,
+      confirmLoading: loading,
+      loading,
+    }));
+  }
+
+  getData<T extends object = Record<string, any>>() {
+    return (this.sharedData?.payload ?? {}) as T;
+  }
+
+  /**
+   * 鍙栨秷鎿嶄綔
+   */
+  onCancel() {
+    if (this.api.onCancel) {
+      this.api.onCancel?.();
+    } else {
+      this.close();
+    }
+  }
+
+  /**
+   * 纭鎿嶄綔
+   */
+  onConfirm() {
+    this.api.onConfirm?.();
+  }
+
+  open() {
+    this.store.setState((prev) => ({ ...prev, isOpen: true }));
+  }
+
+  setData<T>(payload: T) {
+    this.sharedData.payload = payload;
+  }
+
+  setState(
+    stateOrFn:
+      | ((prev: DrawerState) => Partial<DrawerState>)
+      | Partial<DrawerState>,
+  ) {
+    if (isFunction(stateOrFn)) {
+      this.store.setState(stateOrFn);
+    } else {
+      this.store.setState((prev) => ({ ...prev, ...stateOrFn }));
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
new file mode 100644
index 0000000..f75ee50
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
@@ -0,0 +1,151 @@
+import type { ClassType } from '@vben-core/typings';
+
+import type { DrawerApi } from './drawer-api';
+
+import type { Component, Ref } from 'vue';
+
+export type DrawerPlacement = 'bottom' | 'left' | 'right' | 'top';
+
+export interface DrawerProps {
+  /**
+   * 鏄惁鎸傝浇鍒板唴瀹瑰尯鍩�
+   * @default false
+   */
+  appendToMain?: boolean;
+  /**
+   * 鍙栨秷鎸夐挳鏂囧瓧
+   */
+  cancelText?: string;
+  class?: ClassType;
+  /**
+   * 鏄惁鏄剧ず鍙充笂瑙掔殑鍏抽棴鎸夐挳
+   * @default true
+   */
+  closable?: boolean;
+  /**
+   * 鐐瑰嚮寮圭獥閬僵鏄惁鍏抽棴寮圭獥
+   * @default true
+   */
+  closeOnClickModal?: boolean;
+  /**
+   * 鎸変笅 ESC 閿槸鍚﹀叧闂脊绐�
+   * @default true
+   */
+  closeOnPressEscape?: boolean;
+  /**
+   * 纭畾鎸夐挳 loading
+   * @default false
+   */
+  confirmLoading?: boolean;
+  /**
+   * 纭畾鎸夐挳鏂囧瓧
+   */
+  confirmText?: string;
+  contentClass?: string;
+  /**
+   * 寮圭獥鎻忚堪
+   */
+  description?: string;
+  /**
+   * 鏄惁鏄剧ず搴曢儴
+   * @default true
+   */
+  footer?: boolean;
+  /**
+   * 寮圭獥搴曢儴鏍峰紡
+   */
+  footerClass?: ClassType;
+  /**
+   * 鏄惁鏄剧ず椤舵爮
+   * @default true
+   */
+  header?: boolean;
+  /**
+   * 寮圭獥澶撮儴鏍峰紡
+   */
+  headerClass?: ClassType;
+  /**
+   * 寮圭獥鏄惁鏄剧ず
+   * @default false
+   */
+  loading?: boolean;
+
+  /**
+   * 鏄惁鏄剧ず閬僵
+   * @default true
+   */
+  modal?: boolean;
+  /**
+   * 鏄惁鑷姩鑱氱劍
+   */
+  openAutoFocus?: boolean;
+  /**
+   * 鎶藉眽浣嶇疆
+   * @default right
+   */
+  placement?: DrawerPlacement;
+
+  /**
+   * 鏄惁鏄剧ず鍙栨秷鎸夐挳
+   * @default true
+   */
+  showCancelButton?: boolean;
+  /**
+   * 鏄惁鏄剧ず纭鎸夐挳
+   * @default true
+   */
+  showConfirmButton?: boolean;
+  /**
+   * 寮圭獥鏍囬
+   */
+  title?: string;
+  /**
+   * 寮圭獥鏍囬鎻愮ず
+   */
+  titleTooltip?: string;
+  /**
+   * 鎶藉眽灞傜骇
+   */
+  zIndex?: number;
+}
+
+export interface DrawerState extends DrawerProps {
+  /** 寮圭獥鎵撳紑鐘舵�� */
+  isOpen?: boolean;
+  /**
+   * 鍏变韩鏁版嵁
+   */
+  sharedData?: Record<string, any>;
+}
+
+export type ExtendedDrawerApi = {
+  useStore: <T = NoInfer<DrawerState>>(
+    selector?: (state: NoInfer<DrawerState>) => T,
+  ) => Readonly<Ref<T>>;
+} & DrawerApi;
+
+export interface DrawerApiOptions extends DrawerState {
+  /**
+   * 鐙珛鐨勫脊绐楃粍浠�
+   */
+  connectedComponent?: Component;
+  /**
+   * 鍏抽棴鍓嶇殑鍥炶皟锛岃繑鍥� false 鍙互闃绘鍏抽棴
+   * @returns
+   */
+  onBeforeClose?: () => void;
+  /**
+   * 鐐瑰嚮鍙栨秷鎸夐挳鐨勫洖璋�
+   */
+  onCancel?: () => void;
+  /**
+   * 鐐瑰嚮纭畾鎸夐挳鐨勫洖璋�
+   */
+  onConfirm?: () => void;
+  /**
+   * 寮圭獥鐘舵�佸彉鍖栧洖璋�
+   * @param isOpen
+   * @returns
+   */
+  onOpenChange?: (isOpen: boolean) => void;
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
new file mode 100644
index 0000000..31a4098
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
@@ -0,0 +1,251 @@
+<script lang="ts" setup>
+import type { DrawerProps, ExtendedDrawerApi } from './drawer';
+
+import { computed, provide, ref, useId, watch } from 'vue';
+
+import {
+  useIsMobile,
+  usePriorityValues,
+  useSimpleLocale,
+} from '@vben-core/composables';
+import { X } from '@vben-core/icons';
+import {
+  Sheet,
+  SheetClose,
+  SheetContent,
+  SheetDescription,
+  SheetFooter,
+  SheetHeader,
+  SheetTitle,
+  VbenButton,
+  VbenHelpTooltip,
+  VbenIconButton,
+  VbenLoading,
+  VisuallyHidden,
+} from '@vben-core/shadcn-ui';
+import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
+import { globalShareState } from '@vben-core/shared/global-state';
+import { cn } from '@vben-core/shared/utils';
+
+interface Props extends DrawerProps {
+  drawerApi?: ExtendedDrawerApi;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  appendToMain: false,
+  drawerApi: undefined,
+  zIndex: 1000,
+});
+
+const components = globalShareState.getComponents();
+
+const id = useId();
+provide('DISMISSABLE_DRAWER_ID', id);
+
+const wrapperRef = ref<HTMLElement>();
+const { $t } = useSimpleLocale();
+const { isMobile } = useIsMobile();
+
+const state = props.drawerApi?.useStore?.();
+
+const {
+  appendToMain,
+  cancelText,
+  class: drawerClass,
+  closable,
+  closeOnClickModal,
+  closeOnPressEscape,
+  confirmLoading,
+  confirmText,
+  contentClass,
+  description,
+  footer: showFooter,
+  footerClass,
+  header: showHeader,
+  headerClass,
+  loading: showLoading,
+  modal,
+  openAutoFocus,
+  placement,
+  showCancelButton,
+  showConfirmButton,
+  title,
+  titleTooltip,
+  zIndex,
+} = usePriorityValues(props, state);
+
+watch(
+  () => showLoading.value,
+  (v) => {
+    if (v && wrapperRef.value) {
+      wrapperRef.value.scrollTo({
+        // behavior: 'smooth',
+        top: 0,
+      });
+    }
+  },
+);
+
+function interactOutside(e: Event) {
+  if (!closeOnClickModal.value) {
+    e.preventDefault();
+  }
+}
+function escapeKeyDown(e: KeyboardEvent) {
+  if (!closeOnPressEscape.value) {
+    e.preventDefault();
+  }
+}
+// pointer-down-outside
+function pointerDownOutside(e: Event) {
+  const target = e.target as HTMLElement;
+  const dismissableDrawer = target?.dataset.dismissableDrawer;
+  if (!closeOnClickModal.value || dismissableDrawer !== id) {
+    e.preventDefault();
+  }
+}
+
+function handerOpenAutoFocus(e: Event) {
+  if (!openAutoFocus.value) {
+    e?.preventDefault();
+  }
+}
+
+function handleFocusOutside(e: Event) {
+  e.preventDefault();
+  e.stopPropagation();
+}
+
+const getAppendTo = computed(() => {
+  return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
+});
+</script>
+<template>
+  <Sheet
+    :modal="false"
+    :open="state?.isOpen"
+    @update:open="() => drawerApi?.close()"
+  >
+    <SheetContent
+      :append-to="getAppendTo"
+      :class="
+        cn('flex w-[520px] flex-col', drawerClass, {
+          '!w-full': isMobile || placement === 'bottom' || placement === 'top',
+          'max-h-[100vh]': placement === 'bottom' || placement === 'top',
+        })
+      "
+      :modal="modal"
+      :open="state?.isOpen"
+      :side="placement"
+      :z-index="zIndex"
+      @close-auto-focus="handleFocusOutside"
+      @escape-key-down="escapeKeyDown"
+      @focus-outside="handleFocusOutside"
+      @interact-outside="interactOutside"
+      @open-auto-focus="handerOpenAutoFocus"
+      @pointer-down-outside="pointerDownOutside"
+    >
+      <SheetHeader
+        v-if="showHeader"
+        :class="
+          cn(
+            '!flex flex-row items-center justify-between border-b px-6 py-5',
+            headerClass,
+            {
+              'px-4 py-3': closable,
+            },
+          )
+        "
+      >
+        <div>
+          <SheetTitle v-if="title" class="text-left">
+            <slot name="title">
+              {{ title }}
+
+              <VbenHelpTooltip v-if="titleTooltip" trigger-class="pb-1">
+                {{ titleTooltip }}
+              </VbenHelpTooltip>
+            </slot>
+          </SheetTitle>
+          <SheetDescription v-if="description" class="mt-1 text-xs">
+            <slot name="description">
+              {{ description }}
+            </slot>
+          </SheetDescription>
+        </div>
+
+        <VisuallyHidden v-if="!title || !description">
+          <SheetTitle v-if="!title" />
+          <SheetDescription v-if="!description" />
+        </VisuallyHidden>
+
+        <div class="flex-center">
+          <slot name="extra"></slot>
+          <SheetClose
+            v-if="closable"
+            as-child
+            class="data-[state=open]:bg-secondary ml-[2px] cursor-pointer rounded-full opacity-80 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
+          >
+            <VbenIconButton>
+              <X class="size-4" />
+            </VbenIconButton>
+          </SheetClose>
+        </div>
+      </SheetHeader>
+      <template v-else>
+        <VisuallyHidden>
+          <SheetTitle />
+          <SheetDescription />
+        </VisuallyHidden>
+      </template>
+      <div
+        ref="wrapperRef"
+        :class="
+          cn('relative flex-1 overflow-y-auto p-3', contentClass, {
+            'overflow-hidden': showLoading,
+          })
+        "
+      >
+        <VbenLoading v-if="showLoading" class="size-full" spinning />
+
+        <slot></slot>
+      </div>
+
+      <SheetFooter
+        v-if="showFooter"
+        :class="
+          cn(
+            'w-full flex-row items-center justify-end border-t p-2 px-3',
+            footerClass,
+          )
+        "
+      >
+        <slot name="prepend-footer"></slot>
+        <slot name="footer">
+          <component
+            :is="components.DefaultButton || VbenButton"
+            v-if="showCancelButton"
+            variant="ghost"
+            @click="() => drawerApi?.onCancel()"
+          >
+            <slot name="cancelText">
+              {{ cancelText || $t('cancel') }}
+            </slot>
+          </component>
+
+          <component
+            :is="components.PrimaryButton || VbenButton"
+            v-if="showConfirmButton"
+            :loading="confirmLoading"
+            @click="() => drawerApi?.onConfirm()"
+          >
+            <slot name="confirmText">
+              {{ confirmText || $t('confirm') }}
+            </slot>
+          </component>
+        </slot>
+        <slot name="append-footer"></slot>
+      </SheetFooter>
+    </SheetContent>
+  </Sheet>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/index.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/index.ts
new file mode 100644
index 0000000..f2dd839
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/index.ts
@@ -0,0 +1,3 @@
+export type * from './drawer';
+export { default as VbenDrawer } from './drawer.vue';
+export { useVbenDrawer } from './use-drawer';
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts
new file mode 100644
index 0000000..c3ff263
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts
@@ -0,0 +1,105 @@
+import type {
+  DrawerApiOptions,
+  DrawerProps,
+  ExtendedDrawerApi,
+} from './drawer';
+
+import { defineComponent, h, inject, nextTick, provide, reactive } from 'vue';
+
+import { useStore } from '@vben-core/shared/store';
+
+import VbenDrawer from './drawer.vue';
+import { DrawerApi } from './drawer-api';
+
+const USER_DRAWER_INJECT_KEY = Symbol('VBEN_DRAWER_INJECT');
+
+export function useVbenDrawer<
+  TParentDrawerProps extends DrawerProps = DrawerProps,
+>(options: DrawerApiOptions = {}) {
+  // Drawer涓�鑸細鎶界鍑烘潵锛屾墍浠ュ鏋滄湁浼犲叆 connectedComponent锛屽垯琛ㄧず涓哄閮ㄨ皟鐢紝涓庡唴閮ㄧ粍浠惰繘琛岃繛鎺�
+  // 澶栭儴鐨凞rawer閫氳繃provide/inject浼犻�抋pi
+
+  const { connectedComponent } = options;
+  if (connectedComponent) {
+    const extendedApi = reactive({});
+    const Drawer = defineComponent(
+      (props: TParentDrawerProps, { attrs, slots }) => {
+        provide(USER_DRAWER_INJECT_KEY, {
+          extendApi(api: ExtendedDrawerApi) {
+            // 涓嶈兘鐩存帴缁� reactive 璧嬪�硷紝浼氫涪澶卞搷搴�
+            // 涓嶈兘鐢� Object.assign,浼氫涪澶� api 鐨勫師鍨嬪嚱鏁�
+            Object.setPrototypeOf(extendedApi, api);
+          },
+          options,
+        });
+        checkProps(extendedApi as ExtendedDrawerApi, {
+          ...props,
+          ...attrs,
+          ...slots,
+        });
+        return () => h(connectedComponent, { ...props, ...attrs }, slots);
+      },
+      {
+        inheritAttrs: false,
+        name: 'VbenParentDrawer',
+      },
+    );
+    return [Drawer, extendedApi as ExtendedDrawerApi] as const;
+  }
+
+  const injectData = inject<any>(USER_DRAWER_INJECT_KEY, {});
+
+  const mergedOptions = {
+    ...injectData.options,
+    ...options,
+  } as DrawerApiOptions;
+
+  mergedOptions.onOpenChange = (isOpen: boolean) => {
+    options.onOpenChange?.(isOpen);
+    injectData.options?.onOpenChange?.(isOpen);
+  };
+  const api = new DrawerApi(mergedOptions);
+
+  const extendedApi: ExtendedDrawerApi = api as never;
+
+  extendedApi.useStore = (selector) => {
+    return useStore(api.store, selector);
+  };
+
+  const Drawer = defineComponent(
+    (props: DrawerProps, { attrs, slots }) => {
+      return () =>
+        h(VbenDrawer, { ...props, ...attrs, drawerApi: extendedApi }, slots);
+    },
+    {
+      inheritAttrs: false,
+      name: 'VbenDrawer',
+    },
+  );
+  injectData.extendApi?.(extendedApi);
+  return [Drawer, extendedApi] as const;
+}
+
+async function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {
+  if (!attrs || Object.keys(attrs).length === 0) {
+    return;
+  }
+  await nextTick();
+
+  const state = api?.store?.state;
+
+  if (!state) {
+    return;
+  }
+
+  const stateKeys = new Set(Object.keys(state));
+
+  for (const attr of Object.keys(attrs)) {
+    if (stateKeys.has(attr) && !['class'].includes(attr)) {
+      // connectedComponent瀛樺湪鏃讹紝涓嶈浼犲叆Drawer鐨刾rops锛屼細閫犳垚澶嶆潅搴︽彁鍗囷紝濡傛灉浣犻渶瑕佷慨鏀笵rawer鐨刾rops锛岃浣跨敤 useVbenDrawer 鎴栬�卆pi
+      console.warn(
+        `[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,
+      );
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/index.ts
new file mode 100644
index 0000000..56e7ade
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/index.ts
@@ -0,0 +1,2 @@
+export * from './drawer';
+export * from './modal';
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts
new file mode 100644
index 0000000..9c2ef20
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts
@@ -0,0 +1,128 @@
+import type { ModalState } from '../modal';
+
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { ModalApi } from '../modal-api';
+
+vi.mock('@vben-core/shared/store', () => {
+  return {
+    isFunction: (fn: any) => typeof fn === 'function',
+    Store: class {
+      private _state: ModalState;
+      private options: any;
+
+      constructor(initialState: ModalState, options: any) {
+        this._state = initialState;
+        this.options = options;
+      }
+
+      batch(cb: () => void) {
+        cb();
+      }
+
+      setState(fn: (prev: ModalState) => ModalState) {
+        this._state = fn(this._state);
+        this.options.onUpdate();
+      }
+
+      get state() {
+        return this._state;
+      }
+    },
+  };
+});
+
+describe('modalApi', () => {
+  let modalApi: ModalApi;
+  // 浣跨敤 modalState 鑰屼笉鏄� state
+  let modalState: ModalState;
+
+  beforeEach(() => {
+    modalApi = new ModalApi();
+    // 鑾峰彇 modalApi 鍐呯殑 state
+    modalState = modalApi.store.state;
+  });
+
+  it('should initialize with default state', () => {
+    expect(modalState.isOpen).toBe(false);
+    expect(modalState.cancelText).toBe(undefined);
+    expect(modalState.confirmText).toBe(undefined);
+  });
+
+  it('should open the modal', () => {
+    modalApi.open();
+    expect(modalApi.store.state.isOpen).toBe(true);
+  });
+
+  it('should close the modal if onBeforeClose allows it', () => {
+    modalApi.close();
+    expect(modalApi.store.state.isOpen).toBe(false);
+  });
+
+  it('should not close the modal if onBeforeClose returns false', () => {
+    const onBeforeClose = vi.fn(() => false);
+    const modalApiWithHook = new ModalApi({ onBeforeClose });
+    modalApiWithHook.open();
+    modalApiWithHook.close();
+    expect(modalApiWithHook.store.state.isOpen).toBe(true);
+    expect(onBeforeClose).toHaveBeenCalled();
+  });
+
+  it('should trigger onCancel and close the modal if no onCancel hook is provided', () => {
+    const onCancel = vi.fn();
+    const modalApiWithHook = new ModalApi({ onCancel });
+    modalApiWithHook.open();
+    modalApiWithHook.onCancel();
+    expect(onCancel).toHaveBeenCalled();
+    expect(modalApiWithHook.store.state.isOpen).toBe(true);
+  });
+
+  it('should update shared data correctly', () => {
+    const testData = { key: 'value' };
+    modalApi.setData(testData);
+    expect(modalApi.getData()).toEqual(testData);
+  });
+
+  it('should set state correctly using an object', () => {
+    modalApi.setState({ title: 'New Title' });
+    expect(modalApi.store.state.title).toBe('New Title');
+  });
+
+  it('should set state correctly using a function', () => {
+    modalApi.setState((prev) => ({ ...prev, confirmText: 'Yes' }));
+    expect(modalApi.store.state.confirmText).toBe('Yes');
+  });
+
+  it('should call onOpenChange when state changes', () => {
+    const onOpenChange = vi.fn();
+    const modalApiWithHook = new ModalApi({ onOpenChange });
+    modalApiWithHook.open();
+    expect(onOpenChange).toHaveBeenCalledWith(true);
+  });
+
+  it('should batch state updates', () => {
+    const batchSpy = vi.spyOn(modalApi.store, 'batch');
+    modalApi.batchStore(() => {
+      modalApi.setState({ title: 'Batch Title' });
+      modalApi.setState({ confirmText: 'Batch Confirm' });
+    });
+    expect(batchSpy).toHaveBeenCalled();
+    expect(modalApi.store.state.title).toBe('Batch Title');
+    expect(modalApi.store.state.confirmText).toBe('Batch Confirm');
+  });
+
+  it('should call onClosed callback when provided', () => {
+    const onClosed = vi.fn();
+    const modalApiWithHook = new ModalApi({ onClosed });
+    modalApiWithHook.onClosed();
+    expect(onClosed).toHaveBeenCalled();
+  });
+
+  it('should call onOpened callback when provided', () => {
+    const onOpened = vi.fn();
+    const modalApiWithHook = new ModalApi({ onOpened });
+    modalApiWithHook.open();
+    modalApiWithHook.onOpened();
+    expect(onOpened).toHaveBeenCalled();
+  });
+});
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/index.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/index.ts
new file mode 100644
index 0000000..c8d3498
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/index.ts
@@ -0,0 +1,3 @@
+export type * from './modal';
+export { default as VbenModal } from './modal.vue';
+export { useVbenModal } from './use-modal';
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
new file mode 100644
index 0000000..ddf4824
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts
@@ -0,0 +1,180 @@
+import type { ModalApiOptions, ModalState } from './modal';
+
+import { Store } from '@vben-core/shared/store';
+import { bindMethods, isFunction } from '@vben-core/shared/utils';
+
+export class ModalApi {
+  private api: Pick<
+    ModalApiOptions,
+    | 'onBeforeClose'
+    | 'onCancel'
+    | 'onClosed'
+    | 'onConfirm'
+    | 'onOpenChange'
+    | 'onOpened'
+  >;
+  // private prevState!: ModalState;
+  private state!: ModalState;
+
+  // 鍏变韩鏁版嵁
+  public sharedData: Record<'payload', any> = {
+    payload: {},
+  };
+
+  public store: Store<ModalState>;
+
+  constructor(options: ModalApiOptions = {}) {
+    const {
+      connectedComponent: _,
+      onBeforeClose,
+      onCancel,
+      onClosed,
+      onConfirm,
+      onOpenChange,
+      onOpened,
+      ...storeState
+    } = options;
+
+    const defaultState: ModalState = {
+      bordered: true,
+      centered: false,
+      class: '',
+      closeOnClickModal: true,
+      closeOnPressEscape: true,
+      confirmDisabled: false,
+      confirmLoading: false,
+      contentClass: '',
+      draggable: false,
+      footer: true,
+      footerClass: '',
+      fullscreen: false,
+      fullscreenButton: true,
+      header: true,
+      headerClass: '',
+      isOpen: false,
+      loading: false,
+      modal: true,
+      openAutoFocus: false,
+      showCancelButton: true,
+      showConfirmButton: true,
+      title: '',
+    };
+
+    this.store = new Store<ModalState>(
+      {
+        ...defaultState,
+        ...storeState,
+      },
+      {
+        onUpdate: () => {
+          const state = this.store.state;
+
+          // 姣忔鏇存柊鐘舵�佹椂锛岄兘浼氳皟鐢� onOpenChange 鍥炶皟鍑芥暟
+          if (state?.isOpen === this.state?.isOpen) {
+            this.state = state;
+          } else {
+            this.state = state;
+            this.api.onOpenChange?.(!!state?.isOpen);
+          }
+        },
+      },
+    );
+
+    this.state = this.store.state;
+
+    this.api = {
+      onBeforeClose,
+      onCancel,
+      onClosed,
+      onConfirm,
+      onOpenChange,
+      onOpened,
+    };
+    bindMethods(this);
+  }
+
+  // 濡傛灉闇�瑕佸娆℃洿鏂扮姸鎬侊紝鍙互浣跨敤 batch 鏂规硶
+  batchStore(cb: () => void) {
+    this.store.batch(cb);
+  }
+
+  /**
+   * 鍏抽棴寮圭獥
+   */
+  close() {
+    // 閫氳繃 onBeforeClose 閽╁瓙鍑芥暟鏉ュ垽鏂槸鍚﹀厑璁稿叧闂脊绐�
+    // 濡傛灉 onBeforeClose 杩斿洖 false锛屽垯涓嶅叧闂脊绐�
+    const allowClose = this.api.onBeforeClose?.() ?? true;
+    if (allowClose) {
+      this.store.setState((prev) => ({ ...prev, isOpen: false }));
+    }
+  }
+
+  getData<T extends object = Record<string, any>>() {
+    return (this.sharedData?.payload ?? {}) as T;
+  }
+
+  modalLoading(loading: boolean) {
+    this.store.setState((prev) => ({
+      ...prev,
+      confirmLoading: loading,
+      loading,
+    }));
+  }
+
+  /**
+   * 鍙栨秷鎿嶄綔
+   */
+  onCancel() {
+    if (this.api.onCancel) {
+      this.api.onCancel?.();
+    } else {
+      this.close();
+    }
+  }
+
+  /**
+   * 寮圭獥鍏抽棴鍔ㄧ敾鎾斁瀹屾瘯鍚庣殑鍥炶皟
+   */
+  onClosed() {
+    if (!this.state.isOpen) {
+      this.api.onClosed?.();
+    }
+  }
+
+  /**
+   * 纭鎿嶄綔
+   */
+  onConfirm() {
+    this.api.onConfirm?.();
+  }
+
+  /**
+   * 寮圭獥鎵撳紑鍔ㄧ敾鎾斁瀹屾瘯鍚庣殑鍥炶皟
+   */
+  onOpened() {
+    if (this.state.isOpen) {
+      this.api.onOpened?.();
+    }
+  }
+
+  open() {
+    this.store.setState((prev) => ({ ...prev, isOpen: true }));
+  }
+
+  setData<T>(payload: T) {
+    this.sharedData.payload = payload;
+  }
+
+  setState(
+    stateOrFn:
+      | ((prev: ModalState) => Partial<ModalState>)
+      | Partial<ModalState>,
+  ) {
+    if (isFunction(stateOrFn)) {
+      this.store.setState(stateOrFn);
+    } else {
+      this.store.setState((prev) => ({ ...prev, ...stateOrFn }));
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
new file mode 100644
index 0000000..5508d00
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.ts
@@ -0,0 +1,175 @@
+import type { ModalApi } from './modal-api';
+
+import type { Component, Ref } from 'vue';
+
+export interface ModalProps {
+  /**
+   * 鏄惁瑕佹寕杞藉埌鍐呭鍖哄煙
+   * @default false
+   */
+  appendToMain?: boolean;
+  /**
+   * 鏄惁鏄剧ず杈规
+   * @default false
+   */
+  bordered?: boolean;
+  /**
+   * 鍙栨秷鎸夐挳鏂囧瓧
+   */
+  cancelText?: string;
+  /**
+   * 鏄惁灞呬腑
+   * @default false
+   */
+  centered?: boolean;
+
+  class?: string;
+
+  /**
+   * 鏄惁鏄剧ず鍙充笂瑙掔殑鍏抽棴鎸夐挳
+   * @default true
+   */
+  closable?: boolean;
+  /**
+   * 鐐瑰嚮寮圭獥閬僵鏄惁鍏抽棴寮圭獥
+   * @default true
+   */
+  closeOnClickModal?: boolean;
+  /**
+   * 鎸変笅 ESC 閿槸鍚﹀叧闂脊绐�
+   * @default true
+   */
+  closeOnPressEscape?: boolean;
+  /**
+   * 绂佺敤纭鎸夐挳
+   */
+  confirmDisabled?: boolean;
+  /**
+   * 纭畾鎸夐挳 loading
+   * @default false
+   */
+  confirmLoading?: boolean;
+  /**
+   * 纭畾鎸夐挳鏂囧瓧
+   */
+  confirmText?: string;
+  contentClass?: string;
+  /**
+   * 寮圭獥鎻忚堪
+   */
+  description?: string;
+  /**
+   * 鏄惁鍙嫋鎷�
+   * @default false
+   */
+  draggable?: boolean;
+  /**
+   * 鏄惁鏄剧ず搴曢儴
+   * @default true
+   */
+  footer?: boolean;
+  footerClass?: string;
+  /**
+   * 鏄惁鍏ㄥ睆
+   * @default false
+   */
+  fullscreen?: boolean;
+  /**
+   * 鏄惁鏄剧ず鍏ㄥ睆鎸夐挳
+   * @default true
+   */
+  fullscreenButton?: boolean;
+  /**
+   * 鏄惁鏄剧ず椤舵爮
+   * @default true
+   */
+  header?: boolean;
+  headerClass?: string;
+  /**
+   * 寮圭獥鏄惁鏄剧ず
+   * @default false
+   */
+  loading?: boolean;
+  /**
+   * 鏄惁鏄剧ず閬僵
+   * @default true
+   */
+  modal?: boolean;
+  /**
+   * 鏄惁鑷姩鑱氱劍
+   */
+  openAutoFocus?: boolean;
+  /**
+   * 鏄惁鏄剧ず鍙栨秷鎸夐挳
+   * @default true
+   */
+  showCancelButton?: boolean;
+  /**
+   * 鏄惁鏄剧ず纭鎸夐挳
+   * @default true
+   */
+  showConfirmButton?: boolean;
+  /**
+   * 寮圭獥鏍囬
+   */
+  title?: string;
+  /**
+   * 寮圭獥鏍囬鎻愮ず
+   */
+  titleTooltip?: string;
+  /**
+   * 寮圭獥灞傜骇
+   */
+  zIndex?: number;
+}
+
+export interface ModalState extends ModalProps {
+  /** 寮圭獥鎵撳紑鐘舵�� */
+  isOpen?: boolean;
+  /**
+   * 鍏变韩鏁版嵁
+   */
+  sharedData?: Record<string, any>;
+}
+
+export type ExtendedModalApi = {
+  useStore: <T = NoInfer<ModalState>>(
+    selector?: (state: NoInfer<ModalState>) => T,
+  ) => Readonly<Ref<T>>;
+} & ModalApi;
+
+export interface ModalApiOptions extends ModalState {
+  /**
+   * 鐙珛鐨勫脊绐楃粍浠�
+   */
+  connectedComponent?: Component;
+  /**
+   * 鍏抽棴鍓嶇殑鍥炶皟锛岃繑鍥� false 鍙互闃绘鍏抽棴
+   * @returns
+   */
+  onBeforeClose?: () => void;
+  /**
+   * 鐐瑰嚮鍙栨秷鎸夐挳鐨勫洖璋�
+   */
+  onCancel?: () => void;
+  /**
+   * 寮圭獥鍏抽棴鍔ㄧ敾缁撴潫鐨勫洖璋�
+   * @returns
+   */
+  onClosed?: () => void;
+  /**
+   * 鐐瑰嚮纭畾鎸夐挳鐨勫洖璋�
+   */
+  onConfirm?: () => void;
+  /**
+   * 寮圭獥鐘舵�佸彉鍖栧洖璋�
+   * @param isOpen
+   * @returns
+   */
+  onOpenChange?: (isOpen: boolean) => void;
+  /**
+   * 寮圭獥鎵撳紑鍔ㄧ敾缁撴潫鐨勫洖璋�
+   * @returns
+   */
+  onOpened?: () => void;
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.vue b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
new file mode 100644
index 0000000..4e7d7ca
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/modal.vue
@@ -0,0 +1,311 @@
+<script lang="ts" setup>
+import type { ExtendedModalApi, ModalProps } from './modal';
+
+import { computed, nextTick, provide, ref, useId, watch } from 'vue';
+
+import {
+  useIsMobile,
+  usePriorityValues,
+  useSimpleLocale,
+} from '@vben-core/composables';
+import { Expand, Shrink } from '@vben-core/icons';
+import {
+  Dialog,
+  DialogContent,
+  DialogDescription,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+  VbenButton,
+  VbenHelpTooltip,
+  VbenIconButton,
+  VbenLoading,
+  VisuallyHidden,
+} from '@vben-core/shadcn-ui';
+import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
+import { globalShareState } from '@vben-core/shared/global-state';
+import { cn } from '@vben-core/shared/utils';
+
+import { useModalDraggable } from './use-modal-draggable';
+
+interface Props extends ModalProps {
+  modalApi?: ExtendedModalApi;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  appendToMain: false,
+  modalApi: undefined,
+});
+
+const components = globalShareState.getComponents();
+
+const contentRef = ref();
+const wrapperRef = ref<HTMLElement>();
+const dialogRef = ref();
+const headerRef = ref();
+const footerRef = ref();
+
+const id = useId();
+
+provide('DISMISSABLE_MODAL_ID', id);
+
+const { $t } = useSimpleLocale();
+const { isMobile } = useIsMobile();
+const state = props.modalApi?.useStore?.();
+
+const {
+  appendToMain,
+  bordered,
+  cancelText,
+  centered,
+  class: modalClass,
+  closable,
+  closeOnClickModal,
+  closeOnPressEscape,
+  confirmDisabled,
+  confirmLoading,
+  confirmText,
+  contentClass,
+  description,
+  draggable,
+  footer: showFooter,
+  footerClass,
+  fullscreen,
+  fullscreenButton,
+  header,
+  headerClass,
+  loading: showLoading,
+  modal,
+  openAutoFocus,
+  showCancelButton,
+  showConfirmButton,
+  title,
+  titleTooltip,
+  zIndex,
+} = usePriorityValues(props, state);
+
+const shouldFullscreen = computed(
+  () => (fullscreen.value && header.value) || isMobile.value,
+);
+
+const shouldDraggable = computed(
+  () => draggable.value && !shouldFullscreen.value && header.value,
+);
+
+const { dragging, transform } = useModalDraggable(
+  dialogRef,
+  headerRef,
+  shouldDraggable,
+);
+
+watch(
+  () => state?.value?.isOpen,
+  async (v) => {
+    if (v) {
+      await nextTick();
+      if (!contentRef.value) return;
+      const innerContentRef = contentRef.value.getContentRef();
+      dialogRef.value = innerContentRef.$el;
+      // reopen modal reassign value
+      const { offsetX, offsetY } = transform;
+      dialogRef.value.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
+    }
+  },
+);
+
+watch(
+  () => showLoading.value,
+  (v) => {
+    if (v && wrapperRef.value) {
+      wrapperRef.value.scrollTo({
+        // behavior: 'smooth',
+        top: 0,
+      });
+    }
+  },
+);
+
+function handleFullscreen() {
+  props.modalApi?.setState((prev) => {
+    // if (prev.fullscreen) {
+    //   resetPosition();
+    // }
+    return { ...prev, fullscreen: !fullscreen.value };
+  });
+}
+function interactOutside(e: Event) {
+  if (!closeOnClickModal.value) {
+    e.preventDefault();
+    e.stopPropagation();
+  }
+}
+function escapeKeyDown(e: KeyboardEvent) {
+  if (!closeOnPressEscape.value) {
+    e.preventDefault();
+  }
+}
+
+function handerOpenAutoFocus(e: Event) {
+  if (!openAutoFocus.value) {
+    e?.preventDefault();
+  }
+}
+
+// pointer-down-outside
+function pointerDownOutside(e: Event) {
+  const target = e.target as HTMLElement;
+  const isDismissableModal = target?.dataset.dismissableModal;
+  if (!closeOnClickModal.value || isDismissableModal !== id) {
+    e.preventDefault();
+    e.stopPropagation();
+  }
+}
+
+function handleFocusOutside(e: Event) {
+  e.preventDefault();
+  e.stopPropagation();
+}
+const getAppendTo = computed(() => {
+  return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
+});
+</script>
+<template>
+  <Dialog
+    :modal="false"
+    :open="state?.isOpen"
+    @update:open="() => modalApi?.close()"
+  >
+    <DialogContent
+      ref="contentRef"
+      :append-to="getAppendTo"
+      :class="
+        cn(
+          'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0 sm:rounded-[var(--radius)]',
+          modalClass,
+          {
+            'border-border border': bordered,
+            'shadow-3xl': !bordered,
+            'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
+              shouldFullscreen,
+            'top-1/2 !-translate-y-1/2': centered && !shouldFullscreen,
+            'duration-300': !dragging,
+          },
+        )
+      "
+      :modal="modal"
+      :open="state?.isOpen"
+      :show-close="closable"
+      :z-index="zIndex"
+      close-class="top-3"
+      @close-auto-focus="handleFocusOutside"
+      @closed="() => modalApi?.onClosed()"
+      @escape-key-down="escapeKeyDown"
+      @focus-outside="handleFocusOutside"
+      @interact-outside="interactOutside"
+      @open-auto-focus="handerOpenAutoFocus"
+      @opened="() => modalApi?.onOpened()"
+      @pointer-down-outside="pointerDownOutside"
+    >
+      <DialogHeader
+        ref="headerRef"
+        :class="
+          cn(
+            'px-5 py-4',
+            {
+              'border-b': bordered,
+              hidden: !header,
+              'cursor-move select-none': shouldDraggable,
+            },
+            headerClass,
+          )
+        "
+      >
+        <DialogTitle v-if="title" class="text-left">
+          <slot name="title">
+            {{ title }}
+
+            <slot v-if="titleTooltip" name="titleTooltip">
+              <VbenHelpTooltip trigger-class="pb-1">
+                {{ titleTooltip }}
+              </VbenHelpTooltip>
+            </slot>
+          </slot>
+        </DialogTitle>
+        <DialogDescription v-if="description">
+          <slot name="description">
+            {{ description }}
+          </slot>
+        </DialogDescription>
+        <VisuallyHidden v-if="!title || !description">
+          <DialogTitle v-if="!title" />
+          <DialogDescription v-if="!description" />
+        </VisuallyHidden>
+      </DialogHeader>
+      <div
+        ref="wrapperRef"
+        :class="
+          cn('relative min-h-40 flex-1 overflow-y-auto p-3', contentClass, {
+            'pointer-events-none overflow-hidden': showLoading,
+          })
+        "
+      >
+        <VbenLoading
+          v-if="showLoading"
+          class="size-full h-auto min-h-full"
+          spinning
+        />
+        <slot></slot>
+      </div>
+
+      <VbenIconButton
+        v-if="fullscreenButton"
+        class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-3 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
+        @click="handleFullscreen"
+      >
+        <Shrink v-if="fullscreen" class="size-3.5" />
+        <Expand v-else class="size-3.5" />
+      </VbenIconButton>
+
+      <DialogFooter
+        v-if="showFooter"
+        ref="footerRef"
+        :class="
+          cn(
+            'flex-row items-center justify-end p-2',
+            {
+              'border-t': bordered,
+            },
+            footerClass,
+          )
+        "
+      >
+        <slot name="prepend-footer"></slot>
+        <slot name="footer">
+          <component
+            :is="components.DefaultButton || VbenButton"
+            v-if="showCancelButton"
+            variant="ghost"
+            @click="() => modalApi?.onCancel()"
+          >
+            <slot name="cancelText">
+              {{ cancelText || $t('cancel') }}
+            </slot>
+          </component>
+
+          <component
+            :is="components.PrimaryButton || VbenButton"
+            v-if="showConfirmButton"
+            :disabled="confirmDisabled"
+            :loading="confirmLoading"
+            @click="() => modalApi?.onConfirm()"
+          >
+            <slot name="confirmText">
+              {{ confirmText || $t('confirm') }}
+            </slot>
+          </component>
+        </slot>
+        <slot name="append-footer"></slot>
+      </DialogFooter>
+    </DialogContent>
+  </Dialog>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts
new file mode 100644
index 0000000..218f6bb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts
@@ -0,0 +1,116 @@
+/**
+ * @copy https://github.com/element-plus/element-plus/blob/dev/packages/hooks/use-draggable/index.ts
+ * 璋冩暣閮ㄥ垎缁嗚妭
+ */
+
+import { onBeforeUnmount, onMounted, reactive, ref, watchEffect } from 'vue';
+import type { ComputedRef, Ref } from 'vue';
+
+import { unrefElement } from '@vueuse/core';
+
+export function useModalDraggable(
+  targetRef: Ref<HTMLElement | undefined>,
+  dragRef: Ref<HTMLElement | undefined>,
+  draggable: ComputedRef<boolean>,
+) {
+  const transform = reactive({
+    offsetX: 0,
+    offsetY: 0,
+  });
+
+  const dragging = ref(false);
+
+  const onMousedown = (e: MouseEvent) => {
+    const downX = e.clientX;
+    const downY = e.clientY;
+
+    if (!targetRef.value) {
+      return;
+    }
+
+    const targetRect = targetRef.value.getBoundingClientRect();
+
+    const { offsetX, offsetY } = transform;
+    const targetLeft = targetRect.left;
+    const targetTop = targetRect.top;
+    const targetWidth = targetRect.width;
+    const targetHeight = targetRect.height;
+    const docElement = document.documentElement;
+    const clientWidth = docElement.clientWidth;
+    const clientHeight = docElement.clientHeight;
+
+    const minLeft = -targetLeft + offsetX;
+    const minTop = -targetTop + offsetY;
+    const maxLeft = clientWidth - targetLeft - targetWidth + offsetX;
+    const maxTop = clientHeight - targetTop - targetHeight + offsetY;
+
+    const onMousemove = (e: MouseEvent) => {
+      let moveX = offsetX + e.clientX - downX;
+      let moveY = offsetY + e.clientY - downY;
+
+      moveX = Math.min(Math.max(moveX, minLeft), maxLeft);
+      moveY = Math.min(Math.max(moveY, minTop), maxTop);
+
+      transform.offsetX = moveX;
+      transform.offsetY = moveY;
+
+      if (targetRef.value) {
+        targetRef.value.style.transform = `translate(${moveX}px, ${moveY}px)`;
+        dragging.value = true;
+      }
+    };
+
+    const onMouseup = () => {
+      dragging.value = false;
+      document.removeEventListener('mousemove', onMousemove);
+      document.removeEventListener('mouseup', onMouseup);
+    };
+
+    document.addEventListener('mousemove', onMousemove);
+    document.addEventListener('mouseup', onMouseup);
+  };
+
+  const onDraggable = () => {
+    const dragDom = unrefElement(dragRef);
+    if (dragDom && targetRef.value) {
+      dragDom.addEventListener('mousedown', onMousedown);
+    }
+  };
+
+  const offDraggable = () => {
+    const dragDom = unrefElement(dragRef);
+    if (dragDom && targetRef.value) {
+      dragDom.removeEventListener('mousedown', onMousedown);
+    }
+  };
+
+  const resetPosition = () => {
+    transform.offsetX = 0;
+    transform.offsetY = 0;
+
+    const target = unrefElement(targetRef);
+    if (target) {
+      target.style.transform = 'none';
+    }
+  };
+
+  onMounted(() => {
+    watchEffect(() => {
+      if (draggable.value) {
+        onDraggable();
+      } else {
+        offDraggable();
+      }
+    });
+  });
+
+  onBeforeUnmount(() => {
+    offDraggable();
+  });
+
+  return {
+    dragging,
+    resetPosition,
+    transform,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts
new file mode 100644
index 0000000..f972530
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts
@@ -0,0 +1,117 @@
+import type { ExtendedModalApi, ModalApiOptions, ModalProps } from './modal';
+
+import { defineComponent, h, inject, nextTick, provide, reactive } from 'vue';
+
+import { useStore } from '@vben-core/shared/store';
+
+import VbenModal from './modal.vue';
+import { ModalApi } from './modal-api';
+
+const USER_MODAL_INJECT_KEY = Symbol('VBEN_MODAL_INJECT');
+
+export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
+  options: ModalApiOptions = {},
+) {
+  // Modal涓�鑸細鎶界鍑烘潵锛屾墍浠ュ鏋滄湁浼犲叆 connectedComponent锛屽垯琛ㄧず涓哄閮ㄨ皟鐢紝涓庡唴閮ㄧ粍浠惰繘琛岃繛鎺�
+  // 澶栭儴鐨凪odal閫氳繃provide/inject浼犻�抋pi
+
+  const { connectedComponent } = options;
+  if (connectedComponent) {
+    const extendedApi = reactive({});
+    const Modal = defineComponent(
+      (props: TParentModalProps, { attrs, slots }) => {
+        provide(USER_MODAL_INJECT_KEY, {
+          extendApi(api: ExtendedModalApi) {
+            // 涓嶈兘鐩存帴缁� reactive 璧嬪�硷紝浼氫涪澶卞搷搴�
+            // 涓嶈兘鐢� Object.assign,浼氫涪澶� api 鐨勫師鍨嬪嚱鏁�
+            Object.setPrototypeOf(extendedApi, api);
+          },
+          options,
+        });
+        checkProps(extendedApi as ExtendedModalApi, {
+          ...props,
+          ...attrs,
+          ...slots,
+        });
+        return () =>
+          h(
+            connectedComponent,
+            {
+              ...props,
+              ...attrs,
+            },
+            slots,
+          );
+      },
+      {
+        inheritAttrs: false,
+        name: 'VbenParentModal',
+      },
+    );
+    return [Modal, extendedApi as ExtendedModalApi] as const;
+  }
+
+  const injectData = inject<any>(USER_MODAL_INJECT_KEY, {});
+
+  const mergedOptions = {
+    ...injectData.options,
+    ...options,
+  } as ModalApiOptions;
+
+  mergedOptions.onOpenChange = (isOpen: boolean) => {
+    options.onOpenChange?.(isOpen);
+    injectData.options?.onOpenChange?.(isOpen);
+  };
+  const api = new ModalApi(mergedOptions);
+
+  const extendedApi: ExtendedModalApi = api as never;
+
+  extendedApi.useStore = (selector) => {
+    return useStore(api.store, selector);
+  };
+
+  const Modal = defineComponent(
+    (props: ModalProps, { attrs, slots }) => {
+      return () =>
+        h(
+          VbenModal,
+          {
+            ...props,
+            ...attrs,
+            modalApi: extendedApi,
+          },
+          slots,
+        );
+    },
+    {
+      inheritAttrs: false,
+      name: 'VbenModal',
+    },
+  );
+  injectData.extendApi?.(extendedApi);
+  return [Modal, extendedApi] as const;
+}
+
+async function checkProps(api: ExtendedModalApi, attrs: Record<string, any>) {
+  if (!attrs || Object.keys(attrs).length === 0) {
+    return;
+  }
+  await nextTick();
+
+  const state = api?.store?.state;
+
+  if (!state) {
+    return;
+  }
+
+  const stateKeys = new Set(Object.keys(state));
+
+  for (const attr of Object.keys(attrs)) {
+    if (stateKeys.has(attr) && !['class'].includes(attr)) {
+      // connectedComponent瀛樺湪鏃讹紝涓嶈浼犲叆Modal鐨刾rops锛屼細閫犳垚澶嶆潅搴︽彁鍗囷紝濡傛灉浣犻渶瑕佷慨鏀筂odal鐨刾rops锛岃浣跨敤 useModal 鎴栬�卆pi
+      console.warn(
+        `[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api.`,
+      );
+    }
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/popup-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/popup-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/popup-ui/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/popup-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/build.config.ts
new file mode 100644
index 0000000..aec9340
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/build.config.ts
@@ -0,0 +1,27 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+
+      pattern: ['**/*'],
+    },
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/components.json b/eims-ui/packages/@core/ui-kit/shadcn-ui/components.json
new file mode 100644
index 0000000..b497f43
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/components.json
@@ -0,0 +1,16 @@
+{
+  "$schema": "https://shadcn-vue.com/schema.json",
+  "style": "new-york",
+  "typescript": true,
+  "tailwind": {
+    "config": "tailwind.config.mjs",
+    "css": "src/assets/index.css",
+    "baseColor": "slate",
+    "cssVariables": true
+  },
+  "framework": "vite",
+  "aliases": {
+    "components": "@vben-core/shadcn-ui/components",
+    "utils": "@vben-core/shared/utils"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/package.json b/eims-ui/packages/@core/ui-kit/shadcn-ui/package.json
new file mode 100644
index 0000000..688afa7
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/package.json
@@ -0,0 +1,54 @@
+{
+  "name": "@vben-core/shadcn-ui",
+  "version": "5.5.0",
+  "#main": "./dist/index.mjs",
+  "#module": "./dist/index.mjs",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/shadcn-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "#build": "pnpm unbuild",
+    "#prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./src/index.ts",
+  "module": "./src/index.ts",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./src/index.ts",
+      "//default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./src/index.ts"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "class-variance-authority": "catalog:",
+    "lucide-vue-next": "catalog:",
+    "radix-vue": "catalog:",
+    "vee-validate": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
new file mode 100644
index 0000000..1006db4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue
@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+import type {
+  AvatarFallbackProps,
+  AvatarImageProps,
+  AvatarRootProps,
+} from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { Avatar, AvatarFallback, AvatarImage } from '../../ui';
+
+interface Props extends AvatarRootProps, AvatarFallbackProps, AvatarImageProps {
+  alt?: string;
+  class?: ClassType;
+  dot?: boolean;
+  dotClass?: ClassType;
+}
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  alt: 'avatar',
+  as: 'button',
+  dot: false,
+  dotClass: 'bg-green-500',
+});
+
+const text = computed(() => {
+  return props.alt.slice(-2).toUpperCase();
+});
+</script>
+
+<template>
+  <div :class="props.class" class="relative flex flex-shrink-0 items-center">
+    <Avatar :class="props.class" class="size-full">
+      <AvatarImage :alt="alt" :src="src" />
+      <AvatarFallback>{{ text }}</AvatarFallback>
+    </Avatar>
+    <span
+      v-if="dot"
+      :class="dotClass"
+      class="border-background absolute bottom-0 right-0 size-3 rounded-full border-2"
+    >
+    </span>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts
new file mode 100644
index 0000000..8a2169c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts
@@ -0,0 +1 @@
+export { default as VbenAvatar } from './avatar.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
new file mode 100644
index 0000000..115b5b3
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue
@@ -0,0 +1,43 @@
+<script lang="ts" setup>
+import type { BacktopProps } from './backtop';
+
+import { computed } from 'vue';
+
+import { ArrowUpToLine } from '@vben-core/icons';
+
+import { VbenButton } from '../button';
+import { useBackTop } from './use-backtop';
+
+interface Props extends BacktopProps {}
+
+defineOptions({ name: 'BackTop' });
+
+const props = withDefaults(defineProps<Props>(), {
+  bottom: 20,
+  isGroup: false,
+  right: 24,
+  target: '',
+  visibilityHeight: 200,
+});
+
+const backTopStyle = computed(() => ({
+  bottom: `${props.bottom}px`,
+  right: `${props.right}px`,
+}));
+
+const { handleClick, visible } = useBackTop(props);
+</script>
+<template>
+  <transition name="fade-down">
+    <VbenButton
+      v-if="visible"
+      :style="backTopStyle"
+      class="dark:bg-accent dark:hover:bg-heavy bg-background hover:bg-heavy data shadow-float fixed bottom-10 z-[1000] size-10 rounded-full duration-500"
+      size="icon"
+      variant="icon"
+      @click="handleClick"
+    >
+      <ArrowUpToLine class="size-4" />
+    </VbenButton>
+  </transition>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts
new file mode 100644
index 0000000..de422c0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts
@@ -0,0 +1,38 @@
+export const backtopProps = {
+  /**
+   * @zh_CN bottom distance.
+   */
+  bottom: {
+    default: 40,
+    type: Number,
+  },
+  /**
+   * @zh_CN right distance.
+   */
+  right: {
+    default: 40,
+    type: Number,
+  },
+  /**
+   * @zh_CN the target to trigger scroll.
+   */
+  target: {
+    default: '',
+    type: String,
+  },
+  /**
+   * @zh_CN the button will not show until the scroll height reaches this value.
+   */
+  visibilityHeight: {
+    default: 200,
+    type: Number,
+  },
+} as const;
+
+export interface BacktopProps {
+  bottom?: number;
+  isGroup?: boolean;
+  right?: number;
+  target?: string;
+  visibilityHeight?: number;
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts
new file mode 100644
index 0000000..7a6e543
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts
@@ -0,0 +1 @@
+export { default as VbenBackTop } from './back-top.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts
new file mode 100644
index 0000000..6a51a95
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts
@@ -0,0 +1,45 @@
+import type { BacktopProps } from './backtop';
+
+import { onMounted, ref, shallowRef } from 'vue';
+
+import { useEventListener, useThrottleFn } from '@vueuse/core';
+
+export const useBackTop = (props: BacktopProps) => {
+  const el = shallowRef<HTMLElement>();
+  const container = shallowRef<Document | HTMLElement>();
+  const visible = ref(false);
+
+  const handleScroll = () => {
+    if (el.value) {
+      visible.value = el.value.scrollTop >= (props?.visibilityHeight ?? 0);
+    }
+  };
+
+  const handleClick = () => {
+    el.value?.scrollTo({ behavior: 'smooth', top: 0 });
+  };
+
+  const handleScrollThrottled = useThrottleFn(handleScroll, 300, true);
+
+  useEventListener(container, 'scroll', handleScrollThrottled);
+  onMounted(() => {
+    container.value = document;
+    el.value = document.documentElement;
+
+    if (props.target) {
+      el.value = document.querySelector<HTMLElement>(props.target) ?? undefined;
+
+      if (!el.value) {
+        throw new Error(`target does not exist: ${props.target}`);
+      }
+      container.value = el.value;
+    }
+    // Give visible an initial value, fix #13066
+    handleScroll();
+  });
+
+  return {
+    handleClick,
+    visible,
+  };
+};
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue
new file mode 100644
index 0000000..cfed25b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue
@@ -0,0 +1,109 @@
+<script lang="ts" setup>
+import type { BreadcrumbProps } from './types';
+
+import { VbenIcon } from '../icon';
+
+interface Props extends BreadcrumbProps {}
+
+defineOptions({ name: 'Breadcrumb' });
+const { breadcrumbs, showIcon } = defineProps<Props>();
+
+const emit = defineEmits<{ select: [string] }>();
+
+function handleClick(index: number, path?: string) {
+  if (!path || index === breadcrumbs.length - 1) {
+    return;
+  }
+  emit('select', path);
+}
+</script>
+<template>
+  <ul class="flex">
+    <TransitionGroup name="breadcrumb-transition">
+      <template
+        v-for="(item, index) in breadcrumbs"
+        :key="`${item.path}-${item.title}-${index}`"
+      >
+        <li>
+          <a
+            href="javascript:void 0"
+            @click.stop="handleClick(index, item.path)"
+          >
+            <span class="flex-center z-10 h-full">
+              <VbenIcon
+                v-if="showIcon"
+                :icon="item.icon"
+                class="mr-1 size-4 flex-shrink-0"
+              />
+              <span
+                :class="{
+                  'text-foreground font-normal':
+                    index === breadcrumbs.length - 1,
+                }"
+                >{{ item.title }}
+              </span>
+            </span>
+          </a>
+        </li>
+      </template>
+    </TransitionGroup>
+  </ul>
+</template>
+<style scoped>
+li {
+  @apply h-7;
+}
+
+li a {
+  @apply text-muted-foreground bg-accent relative mr-9 flex h-7 items-center py-0 pl-[5px] pr-2 text-[13px];
+}
+
+li a > span {
+  @apply -ml-3;
+}
+
+li:first-child a > span {
+  @apply -ml-1;
+}
+
+li:first-child a {
+  @apply rounded-[4px_0_0_4px] pl-[15px];
+}
+
+li:first-child a::before {
+  @apply border-none;
+}
+
+li:last-child a {
+  @apply rounded-[0_4px_4px_0] pr-[15px];
+}
+
+li:last-child a::after {
+  @apply border-none;
+}
+
+li a::before,
+li a::after {
+  @apply border-accent absolute top-0 h-0 w-0 border-[.875rem] border-solid content-[''];
+}
+
+li a::before {
+  @apply -left-7 z-10 border-l-transparent;
+}
+
+li a::after {
+  @apply border-l-accent left-full border-transparent;
+}
+
+li:not(:last-child) a:hover {
+  @apply bg-accent-hover;
+}
+
+li:not(:last-child) a:hover::before {
+  @apply border-accent-hover border-l-transparent;
+}
+
+li:not(:last-child) a:hover::after {
+  @apply border-l-accent-hover;
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue
new file mode 100644
index 0000000..88ee9fd
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue
@@ -0,0 +1,22 @@
+<script lang="ts" setup>
+import type { BreadcrumbProps } from './types';
+
+import { useForwardPropsEmits } from 'radix-vue';
+
+import Breadcrumb from './breadcrumb.vue';
+import BreadcrumbBackground from './breadcrumb-background.vue';
+
+interface Props extends BreadcrumbProps {
+  class?: any;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const emit = defineEmits<{ select: [string] }>();
+
+const forward = useForwardPropsEmits(props, emit);
+</script>
+<template>
+  <Breadcrumb v-if="styleType === 'normal'" v-bind="forward" />
+  <BreadcrumbBackground v-if="styleType === 'background'" v-bind="forward" />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue
new file mode 100644
index 0000000..db2ce65
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue
@@ -0,0 +1,98 @@
+<script lang="ts" setup>
+import type { BreadcrumbProps } from './types';
+
+import { ChevronDown } from '@vben-core/icons';
+
+import {
+  Breadcrumb,
+  BreadcrumbItem,
+  BreadcrumbLink,
+  BreadcrumbList,
+  BreadcrumbPage,
+  BreadcrumbSeparator,
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuItem,
+  DropdownMenuTrigger,
+} from '../../ui';
+import { VbenIcon } from '../icon';
+
+interface Props extends BreadcrumbProps {}
+
+defineOptions({ name: 'Breadcrumb' });
+withDefaults(defineProps<Props>(), {
+  showIcon: false,
+});
+
+const emit = defineEmits<{ select: [string] }>();
+
+function handleClick(path?: string) {
+  if (!path) {
+    return;
+  }
+  emit('select', path);
+}
+</script>
+<template>
+  <Breadcrumb>
+    <BreadcrumbList>
+      <TransitionGroup name="breadcrumb-transition">
+        <template
+          v-for="(item, index) in breadcrumbs"
+          :key="`${item.path}-${item.title}-${index}`"
+        >
+          <BreadcrumbItem>
+            <div v-if="item.items?.length ?? 0 > 0">
+              <DropdownMenu>
+                <DropdownMenuTrigger class="flex items-center gap-1">
+                  <VbenIcon v-if="showIcon" :icon="item.icon" class="size-5" />
+                  {{ item.title }}
+                  <ChevronDown class="size-4" />
+                </DropdownMenuTrigger>
+                <DropdownMenuContent align="start">
+                  <template
+                    v-for="menuItem in item.items"
+                    :key="`sub-${menuItem.path}`"
+                  >
+                    <DropdownMenuItem @click.stop="handleClick(menuItem.path)">
+                      {{ menuItem.title }}
+                    </DropdownMenuItem>
+                  </template>
+                </DropdownMenuContent>
+              </DropdownMenu>
+            </div>
+            <BreadcrumbLink
+              v-else-if="index !== breadcrumbs.length - 1"
+              href="javascript:void 0"
+              @click.stop="handleClick(item.path)"
+            >
+              <div class="flex-center">
+                <VbenIcon
+                  v-if="showIcon"
+                  :class="{ 'size-5': item.isHome }"
+                  :icon="item.icon"
+                  class="mr-1 size-4"
+                />
+                {{ item.title }}
+              </div>
+            </BreadcrumbLink>
+            <BreadcrumbPage v-else>
+              <div class="flex-center">
+                <VbenIcon
+                  v-if="showIcon"
+                  :class="{ 'size-5': item.isHome }"
+                  :icon="item.icon"
+                  class="mr-1 size-4"
+                />
+                {{ item.title }}
+              </div>
+            </BreadcrumbPage>
+            <BreadcrumbSeparator
+              v-if="index < breadcrumbs.length - 1 && !item.isHome"
+            />
+          </BreadcrumbItem>
+        </template>
+      </TransitionGroup>
+    </BreadcrumbList>
+  </Breadcrumb>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts
new file mode 100644
index 0000000..9e31cb1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts
@@ -0,0 +1,3 @@
+export { default as VbenBreadcrumbView } from './breadcrumb-view.vue';
+
+export type * from './types';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts
new file mode 100644
index 0000000..fbf251c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts
@@ -0,0 +1,17 @@
+import type { BreadcrumbStyleType } from '@vben-core/typings';
+
+import type { Component } from 'vue';
+
+export interface IBreadcrumb {
+  icon?: Component | string;
+  isHome?: boolean;
+  items?: IBreadcrumb[];
+  path?: string;
+  title?: string;
+}
+
+export interface BreadcrumbProps {
+  breadcrumbs: IBreadcrumb[];
+  showIcon?: boolean;
+  styleType?: BreadcrumbStyleType;
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts
new file mode 100644
index 0000000..8839742
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts
@@ -0,0 +1,24 @@
+import type { AsTag } from 'radix-vue';
+
+import type { ButtonVariants, ButtonVariantSize } from '../../ui';
+
+import type { Component } from 'vue';
+
+export interface VbenButtonProps {
+  /**
+   * The element or component this component should render as. Can be overwrite by `asChild`
+   * @defaultValue "div"
+   */
+  as?: AsTag | Component;
+  /**
+   * Change the default rendered element for the one passed as a child, merging their props and behavior.
+   *
+   * Read our [Composition](https://www.radix-vue.com/guides/composition.html) guide for more details.
+   */
+  asChild?: boolean;
+  class?: any;
+  disabled?: boolean;
+  loading?: boolean;
+  size?: ButtonVariantSize;
+  variant?: ButtonVariants;
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue
new file mode 100644
index 0000000..cb9b3e5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue
@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import type { VbenButtonProps } from './button';
+
+import { computed } from 'vue';
+
+import { LoaderCircle } from '@vben-core/icons';
+import { cn } from '@vben-core/shared/utils';
+
+import { Primitive } from 'radix-vue';
+
+import { buttonVariants } from '../../ui';
+
+interface Props extends VbenButtonProps {}
+
+const props = withDefaults(defineProps<Props>(), {
+  as: 'button',
+  class: '',
+  disabled: false,
+  loading: false,
+  size: 'default',
+  variant: 'default',
+});
+
+const isDisabled = computed(() => {
+  return props.disabled || props.loading;
+});
+</script>
+
+<template>
+  <Primitive
+    :as="as"
+    :as-child="asChild"
+    :class="cn(buttonVariants({ variant, size }), props.class)"
+    :disabled="isDisabled"
+  >
+    <LoaderCircle
+      v-if="loading"
+      class="text-md mr-2 size-4 flex-shrink-0 animate-spin"
+    />
+    <slot></slot>
+  </Primitive>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue
new file mode 100644
index 0000000..ac626c1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue
@@ -0,0 +1,68 @@
+<script setup lang="ts">
+import type { ButtonVariants } from '../../ui';
+import type { VbenButtonProps } from './button';
+
+import { computed, useSlots } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { VbenTooltip } from '../tooltip';
+import VbenButton from './button.vue';
+
+interface Props extends VbenButtonProps {
+  class?: any;
+  disabled?: boolean;
+  onClick?: () => void;
+  tooltip?: string;
+  tooltipDelayDuration?: number;
+  tooltipSide?: 'bottom' | 'left' | 'right' | 'top';
+  variant?: ButtonVariants;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  disabled: false,
+  onClick: () => {},
+  tooltipDelayDuration: 200,
+  tooltipSide: 'bottom',
+  variant: 'icon',
+});
+
+const slots = useSlots();
+
+const showTooltip = computed(() => !!slots.tooltip || !!props.tooltip);
+</script>
+
+<template>
+  <VbenButton
+    v-if="!showTooltip"
+    :class="cn('rounded-full', props.class)"
+    :disabled="disabled"
+    :variant="variant"
+    size="icon"
+    @click="onClick"
+  >
+    <slot></slot>
+  </VbenButton>
+
+  <VbenTooltip
+    v-else
+    :delay-duration="tooltipDelayDuration"
+    :side="tooltipSide"
+  >
+    <template #trigger>
+      <VbenButton
+        :class="cn('rounded-full', props.class)"
+        :disabled="disabled"
+        :variant="variant"
+        size="icon"
+        @click="onClick"
+      >
+        <slot></slot>
+      </VbenButton>
+    </template>
+    <slot v-if="slots.tooltip" name="tooltip"> </slot>
+    <template v-else>
+      {{ tooltip }}
+    </template>
+  </VbenTooltip>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts
new file mode 100644
index 0000000..4afd1c2
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts
@@ -0,0 +1,3 @@
+export type * from './button';
+export { default as VbenButton } from './button.vue';
+export { default as VbenIconButton } from './icon-button.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue
new file mode 100644
index 0000000..3c2e9da
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue';
+
+import { useId } from 'vue';
+
+import { useForwardPropsEmits } from 'radix-vue';
+
+import { Checkbox } from '../../ui/checkbox';
+
+const props = defineProps<CheckboxRootProps>();
+
+const emits = defineEmits<CheckboxRootEmits>();
+
+const checked = defineModel<boolean>('checked');
+
+const forwarded = useForwardPropsEmits(props, emits);
+
+const id = useId();
+</script>
+
+<template>
+  <div class="flex items-center">
+    <Checkbox v-bind="forwarded" :id="id" v-model:checked="checked" />
+    <label :for="id" class="ml-2 cursor-pointer text-sm"> <slot></slot> </label>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts
new file mode 100644
index 0000000..3df9ded
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts
@@ -0,0 +1 @@
+export { default as VbenCheckbox } from './checkbox.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue
new file mode 100644
index 0000000..4cc4119
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue
@@ -0,0 +1,96 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+import type {
+  ContextMenuContentProps,
+  ContextMenuRootEmits,
+  ContextMenuRootProps,
+} from 'radix-vue';
+
+import type { IContextMenuItem } from './interface';
+
+import { computed } from 'vue';
+
+import { useForwardPropsEmits } from 'radix-vue';
+
+import {
+  ContextMenu,
+  ContextMenuContent,
+  ContextMenuItem,
+  ContextMenuSeparator,
+  ContextMenuShortcut,
+  ContextMenuTrigger,
+} from '../../ui/context-menu';
+
+const props = defineProps<
+  {
+    class?: ClassType;
+    contentClass?: ClassType;
+    contentProps?: ContextMenuContentProps;
+    handlerData?: Record<string, any>;
+    itemClass?: ClassType;
+    menus: (data: any) => IContextMenuItem[];
+  } & ContextMenuRootProps
+>();
+
+const emits = defineEmits<ContextMenuRootEmits>();
+
+const delegatedProps = computed(() => {
+  const {
+    class: _cls,
+    contentClass: _,
+    contentProps: _cProps,
+    itemClass: _iCls,
+    ...delegated
+  } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+
+const menusView = computed(() => {
+  return props.menus?.(props.handlerData);
+});
+
+function handleClick(menu: IContextMenuItem) {
+  if (menu.disabled) {
+    return;
+  }
+  menu?.handler?.(props.handlerData);
+}
+</script>
+
+<template>
+  <ContextMenu v-bind="forwarded">
+    <ContextMenuTrigger as-child>
+      <slot></slot>
+    </ContextMenuTrigger>
+    <ContextMenuContent
+      :class="contentClass"
+      v-bind="contentProps"
+      class="side-content z-[1000]"
+    >
+      <template v-for="menu in menusView" :key="menu.key">
+        <ContextMenuItem
+          :class="itemClass"
+          :disabled="menu.disabled"
+          :inset="menu.inset || !menu.icon"
+          class="cursor-pointer"
+          @click="handleClick(menu)"
+        >
+          <component
+            :is="menu.icon"
+            v-if="menu.icon"
+            class="mr-2 size-4 text-lg"
+          />
+
+          {{ menu.text }}
+          <ContextMenuShortcut v-if="menu.shortcut">
+            {{ menu.shortcut }}
+          </ContextMenuShortcut>
+        </ContextMenuItem>
+        <ContextMenuSeparator v-if="menu.separator" />
+      </template>
+    </ContextMenuContent>
+  </ContextMenu>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts
new file mode 100644
index 0000000..53a3abe
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts
@@ -0,0 +1,3 @@
+export { default as VbenContextMenu } from './context-menu.vue';
+
+export type * from './interface';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts
new file mode 100644
index 0000000..0af653f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts
@@ -0,0 +1,38 @@
+import type { Component } from 'vue';
+
+interface IContextMenuItem {
+  /**
+   * @zh_CN 鏄惁绂佺敤
+   */
+  disabled?: boolean;
+  /**
+   * @zh_CN 鐐瑰嚮浜嬩欢澶勭悊
+   * @param data
+   */
+  handler?: (data: any) => void;
+  /**
+   * @zh_CN 鍥炬爣
+   */
+  icon?: Component;
+  /**
+   * @zh_CN 鏄惁鏄剧ず鍥炬爣
+   */
+  inset?: boolean;
+  /**
+   * @zh_CN 鍞竴鏍囪瘑
+   */
+  key: string;
+  /**
+   * @zh_CN 鏄惁鏄垎鍓茬嚎
+   */
+  separator?: boolean;
+  /**
+   * @zh_CN 蹇嵎閿�
+   */
+  shortcut?: string;
+  /**
+   * @zh_CN 鏍囬
+   */
+  text: string;
+}
+export type { IContextMenuItem };
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue
new file mode 100644
index 0000000..f252049
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue
@@ -0,0 +1,111 @@
+<script lang="ts" setup>
+import { computed, onMounted, ref, unref, watch, watchEffect } from 'vue';
+
+import { isNumber } from '@vben-core/shared/utils';
+
+import { TransitionPresets, useTransition } from '@vueuse/core';
+
+interface Props {
+  autoplay?: boolean;
+  color?: string;
+  decimal?: string;
+  decimals?: number;
+  duration?: number;
+  endVal?: number;
+  prefix?: string;
+  separator?: string;
+  startVal?: number;
+  suffix?: string;
+  transition?: keyof typeof TransitionPresets;
+  useEasing?: boolean;
+}
+
+defineOptions({ name: 'CountToAnimator' });
+
+const props = withDefaults(defineProps<Props>(), {
+  autoplay: true,
+  color: '',
+  decimal: '.',
+  decimals: 0,
+  duration: 1500,
+  endVal: 2021,
+  prefix: '',
+  separator: ',',
+  startVal: 0,
+  suffix: '',
+  transition: 'linear',
+  useEasing: true,
+});
+
+const emit = defineEmits(['onStarted', 'onFinished']);
+
+const source = ref(props.startVal);
+const disabled = ref(false);
+let outputValue = useTransition(source);
+
+const value = computed(() => formatNumber(unref(outputValue)));
+
+watchEffect(() => {
+  source.value = props.startVal;
+});
+
+watch([() => props.startVal, () => props.endVal], () => {
+  if (props.autoplay) {
+    start();
+  }
+});
+
+onMounted(() => {
+  props.autoplay && start();
+});
+
+function start() {
+  run();
+  source.value = props.endVal;
+}
+
+function reset() {
+  source.value = props.startVal;
+  run();
+}
+
+function run() {
+  outputValue = useTransition(source, {
+    disabled,
+    duration: props.duration,
+    onFinished: () => emit('onFinished'),
+    onStarted: () => emit('onStarted'),
+    ...(props.useEasing
+      ? { transition: TransitionPresets[props.transition] }
+      : {}),
+  });
+}
+
+function formatNumber(num: number | string) {
+  if (!num && num !== 0) {
+    return '';
+  }
+  const { decimal, decimals, prefix, separator, suffix } = props;
+  num = Number(num).toFixed(decimals);
+  num += '';
+
+  const x = num.split('.');
+  let x1 = x[0];
+  const x2 = x.length > 1 ? decimal + x[1] : '';
+
+  const rgx = /(\d+)(\d{3})/;
+  if (separator && !isNumber(separator) && x1) {
+    while (rgx.test(x1)) {
+      x1 = x1.replace(rgx, `$1${separator}$2`);
+    }
+  }
+  return prefix + x1 + x2 + suffix;
+}
+
+defineExpose({ reset });
+</script>
+<template>
+  <span :style="{ color }">
+    {{ value }}
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts
new file mode 100644
index 0000000..a97bafb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts
@@ -0,0 +1 @@
+export { default as VbenCountToAnimator } from './count-to-animator.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue
new file mode 100644
index 0000000..f1bbdee
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue
@@ -0,0 +1,49 @@
+<script lang="ts" setup>
+import type {
+  DropdownMenuProps,
+  VbenDropdownMenuItem as IDropdownMenuItem,
+} from './interface';
+
+import {
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuGroup,
+  DropdownMenuItem,
+  DropdownMenuSeparator,
+  DropdownMenuTrigger,
+} from '../../ui';
+
+interface Props extends DropdownMenuProps {}
+
+defineOptions({ name: 'DropdownMenu' });
+const props = withDefaults(defineProps<Props>(), {});
+
+function handleItemClick(menu: IDropdownMenuItem) {
+  if (menu.disabled) {
+    return;
+  }
+  menu?.handler?.(props);
+}
+</script>
+<template>
+  <DropdownMenu>
+    <DropdownMenuTrigger class="flex h-full items-center gap-1">
+      <slot></slot>
+    </DropdownMenuTrigger>
+    <DropdownMenuContent align="start">
+      <DropdownMenuGroup>
+        <template v-for="menu in menus" :key="menu.value">
+          <DropdownMenuItem
+            :disabled="menu.disabled"
+            class="data-[state=checked]:bg-accent data-[state=checked]:text-accent-foreground text-foreground/80 mb-1 cursor-pointer"
+            @click="handleItemClick(menu)"
+          >
+            <component :is="menu.icon" v-if="menu.icon" class="mr-2 size-4" />
+            {{ menu.label }}
+          </DropdownMenuItem>
+          <DropdownMenuSeparator v-if="menu.separator" class="bg-border" />
+        </template>
+      </DropdownMenuGroup>
+    </DropdownMenuContent>
+  </DropdownMenu>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue
new file mode 100644
index 0000000..c0e23c8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue
@@ -0,0 +1,52 @@
+<script lang="ts" setup>
+import type { DropdownMenuProps } from './interface';
+
+import {
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuGroup,
+  DropdownMenuItem,
+  DropdownMenuTrigger,
+} from '../../ui';
+
+interface Props extends DropdownMenuProps {}
+
+defineOptions({ name: 'DropdownRadioMenu' });
+withDefaults(defineProps<Props>(), {});
+
+const modelValue = defineModel<string>();
+
+function handleItemClick(value: string) {
+  modelValue.value = value;
+}
+</script>
+<template>
+  <DropdownMenu>
+    <DropdownMenuTrigger as-child class="flex items-center gap-1">
+      <slot></slot>
+    </DropdownMenuTrigger>
+    <DropdownMenuContent align="start">
+      <DropdownMenuGroup>
+        <template v-for="menu in menus" :key="menu.key">
+          <DropdownMenuItem
+            :class="
+              menu.value === modelValue
+                ? 'bg-accent text-accent-foreground'
+                : ''
+            "
+            class="data-[state=checked]:bg-accent data-[state=checked]:text-accent-foreground text-foreground/80 mb-1 cursor-pointer"
+            @click="handleItemClick(menu.value)"
+          >
+            <component :is="menu.icon" v-if="menu.icon" class="mr-2 size-4" />
+            <span
+              v-if="!menu.icon"
+              :class="menu.value === modelValue ? 'bg-foreground' : ''"
+              class="mr-2 size-1.5 rounded-full"
+            ></span>
+            {{ menu.label }}
+          </DropdownMenuItem>
+        </template>
+      </DropdownMenuGroup>
+    </DropdownMenuContent>
+  </DropdownMenu>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts
new file mode 100644
index 0000000..bff1700
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts
@@ -0,0 +1,4 @@
+export { default as VbenDropdownMenu } from './dropdown-menu.vue';
+export { default as VbenDropdownRadioMenu } from './dropdown-radio-menu.vue';
+
+export type * from './interface';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts
new file mode 100644
index 0000000..01a31a1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts
@@ -0,0 +1,32 @@
+import type { Component } from 'vue';
+
+interface VbenDropdownMenuItem {
+  disabled?: boolean;
+  /**
+   * @zh_CN 鐐瑰嚮浜嬩欢澶勭悊
+   * @param data
+   */
+  handler?: (data: any) => void;
+  /**
+   * @zh_CN 鍥炬爣
+   */
+  icon?: Component;
+  /**
+   * @zh_CN 鏍囬
+   */
+  label: string;
+  /**
+   * @zh_CN 鏄惁鏄垎鍓茬嚎
+   */
+  separator?: boolean;
+  /**
+   * @zh_CN 鍞竴鏍囪瘑
+   */
+  value: string;
+}
+
+interface DropdownMenuProps {
+  menus: VbenDropdownMenuItem[];
+}
+
+export type { DropdownMenuProps, VbenDropdownMenuItem };
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue
new file mode 100644
index 0000000..5cdf619
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue
@@ -0,0 +1,31 @@
+<script lang="ts" setup>
+import { ChevronDown } from '@vben-core/icons';
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: string;
+}>();
+
+// 鎺у埗绠ご灞曞紑/鏀惰捣鐘舵��
+const collapsed = defineModel({ default: false });
+</script>
+
+<template>
+  <div
+    :class="cn('vben-link inline-flex items-center', props.class)"
+    @click="collapsed = !collapsed"
+  >
+    <slot :is-expanded="collapsed">
+      {{ collapsed }}
+      <!-- <span>{{ isExpanded ? '鏀惰捣' : '灞曞紑' }}</span> -->
+    </slot>
+    <div
+      :class="{ 'rotate-180': !collapsed }"
+      class="transition-transform duration-300"
+    >
+      <slot name="icon">
+        <ChevronDown class="size-4" />
+      </slot>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts
new file mode 100644
index 0000000..a35bd9a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts
@@ -0,0 +1 @@
+export { default as VbenExpandableArrow } from './expandable-arrow.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue
new file mode 100644
index 0000000..59f2897
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue
@@ -0,0 +1,28 @@
+<script lang="ts" setup>
+import { Maximize, Minimize } from '@vben-core/icons';
+
+import { useFullscreen } from '@vueuse/core';
+
+import { VbenIconButton } from '../button';
+
+defineOptions({ name: 'FullScreen' });
+
+const { isFullscreen, toggle } = useFullscreen();
+
+// 閲嶆柊妫�鏌ュ叏灞忕姸鎬�
+isFullscreen.value = !!(
+  document.fullscreenElement ||
+  // @ts-ignore
+  document.webkitFullscreenElement ||
+  // @ts-ignore
+  document.mozFullScreenElement ||
+  // @ts-ignore
+  document.msFullscreenElement
+);
+</script>
+<template>
+  <VbenIconButton @click="toggle">
+    <Minimize v-if="isFullscreen" class="text-foreground size-4" />
+    <Maximize v-else class="text-foreground size-4" />
+  </VbenIconButton>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts
new file mode 100644
index 0000000..3997ee0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts
@@ -0,0 +1 @@
+export { default as VbenFullScreen } from './full-screen.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue
new file mode 100644
index 0000000..f528d61
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue
@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+import type {
+  HoverCardContentProps,
+  HoverCardRootEmits,
+  HoverCardRootProps,
+} from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { useForwardPropsEmits } from 'radix-vue';
+
+import { HoverCard, HoverCardContent, HoverCardTrigger } from '../../ui';
+
+interface Props extends HoverCardRootProps {
+  class?: ClassType;
+  contentClass?: ClassType;
+  contentProps?: HoverCardContentProps;
+}
+
+const props = defineProps<Props>();
+
+const emits = defineEmits<HoverCardRootEmits>();
+
+const delegatedProps = computed(() => {
+  const {
+    class: _cls,
+    contentClass: _,
+    contentProps: _cProps,
+    ...delegated
+  } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <HoverCard v-bind="forwarded">
+    <HoverCardTrigger as-child class="h-full">
+      <div class="h-full cursor-pointer">
+        <slot name="trigger"></slot>
+      </div>
+    </HoverCardTrigger>
+    <HoverCardContent
+      :class="contentClass"
+      v-bind="contentProps"
+      class="side-content z-[1000]"
+    >
+      <slot></slot>
+    </HoverCardContent>
+  </HoverCard>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts
new file mode 100644
index 0000000..44a7580
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts
@@ -0,0 +1,2 @@
+export { default as VbenHoverCard } from './hover-card.vue';
+export type { HoverCardContentProps } from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue
new file mode 100644
index 0000000..bb3d3a5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { type Component, computed } from 'vue';
+
+import { IconDefault, IconifyIcon } from '@vben-core/icons';
+import {
+  isFunction,
+  isHttpUrl,
+  isObject,
+  isString,
+} from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  // 娌℃湁鏄惁鏄剧ず榛樿鍥炬爣
+  fallback?: boolean;
+  icon?: Component | Function | string;
+}>();
+
+const isRemoteIcon = computed(() => {
+  return isString(props.icon) && isHttpUrl(props.icon);
+});
+
+const isComponent = computed(() => {
+  const { icon } = props;
+  return !isString(icon) && (isObject(icon) || isFunction(icon));
+});
+</script>
+
+<template>
+  <component :is="icon as Component" v-if="isComponent" v-bind="$attrs" />
+  <img v-else-if="isRemoteIcon" :src="icon as string" v-bind="$attrs" />
+  <IconifyIcon v-else-if="icon" v-bind="$attrs" :icon="icon as string" />
+  <IconDefault v-else-if="fallback" v-bind="$attrs" />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts
new file mode 100644
index 0000000..8f3f204
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts
@@ -0,0 +1 @@
+export { default as VbenIcon } from './icon.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/index.ts
new file mode 100644
index 0000000..034bbbc
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/index.ts
@@ -0,0 +1,24 @@
+export * from './avatar';
+export * from './back-top';
+export * from './breadcrumb';
+export * from './button';
+export * from './checkbox';
+export * from './context-menu';
+export * from './count-to-animator';
+export * from './dropdown-menu';
+export * from './expandable-arrow';
+export * from './full-screen';
+export * from './hover-card';
+export * from './icon';
+export * from './input-captcha';
+export * from './input-password';
+export * from './logo';
+export * from './pin-input';
+export * from './popover';
+export * from './render-content';
+export * from './scrollbar';
+export * from './segmented';
+export * from './select';
+export * from './spine-text';
+export * from './spinner';
+export * from './tooltip';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/index.ts
new file mode 100644
index 0000000..49ec05f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/index.ts
@@ -0,0 +1 @@
+export { default as VbenInputCaptcha } from './input-captcha.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/input-captcha.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/input-captcha.vue
new file mode 100644
index 0000000..607c38b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-captcha/input-captcha.vue
@@ -0,0 +1,58 @@
+<script setup lang="ts">
+import { Input as VbenInput } from '../../ui/input';
+/**
+ * 闈為�氱敤缁勪欢 鐩存帴鎸変笟鍔℃潵鍐�
+ */
+defineProps({
+  captcha: {
+    default: '',
+    type: String,
+  },
+  label: {
+    default: '楠岃瘉鐮�',
+    type: String,
+  },
+  placeholder: {
+    default: '楠岃瘉鐮�',
+    type: String,
+  },
+});
+
+defineEmits<{ captchaClick: [] }>();
+
+const modelValue = defineModel({ default: '', type: String });
+</script>
+
+<!-- 鍥剧墖楠岃瘉鐮� -->
+<template>
+  <div class="flex w-full">
+    <div class="flex-1">
+      <VbenInput
+        id="code"
+        v-model="modelValue"
+        :class="$attrs.class ?? {}"
+        :label="label"
+        :placeholder="placeholder"
+        name="code"
+        required
+        type="text"
+      />
+    </div>
+    <img
+      :src="captcha"
+      class="h-[40px] w-[115px] rounded-r-md"
+      @click="$emit('captchaClick')"
+    />
+  </div>
+</template>
+
+<style lang="scss">
+/**
+  楠岃瘉鐮佽緭鍏ユ鏍峰紡
+  鍘婚櫎鍙宠竟鐨勫渾瑙�
+*/
+input[id='code'] {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts
new file mode 100644
index 0000000..eeca558
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts
@@ -0,0 +1 @@
+export { default as VbenInputPassword } from './input-password.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue
new file mode 100644
index 0000000..be79862
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue
@@ -0,0 +1,57 @@
+<script setup lang="ts">
+import { ref, useSlots } from 'vue';
+
+import { Eye, EyeOff } from '@vben-core/icons';
+import { cn } from '@vben-core/shared/utils';
+
+import { Input } from '../../ui';
+import PasswordStrength from './password-strength.vue';
+
+interface Props {
+  class?: any;
+  /**
+   * 鏄惁鏄剧ず瀵嗙爜寮哄害
+   */
+  passwordStrength?: boolean;
+}
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = defineProps<Props>();
+
+const modelValue = defineModel<string>();
+
+const slots = useSlots();
+
+const show = ref(false);
+</script>
+
+<template>
+  <div class="relative w-full">
+    <Input
+      v-bind="$attrs"
+      v-model="modelValue"
+      :class="cn(props.class)"
+      :type="show ? 'text' : 'password'"
+    />
+    <template v-if="passwordStrength">
+      <PasswordStrength :password="modelValue" />
+      <p v-if="slots.strengthText" class="text-muted-foreground mt-1.5 text-xs">
+        <slot name="strengthText"> </slot>
+      </p>
+    </template>
+    <div
+      :class="{
+        'top-3': !!passwordStrength,
+        'top-1/2 -translate-y-1/2 items-center': !passwordStrength,
+      }"
+      class="hover:text-foreground text-foreground/60 absolute inset-y-0 right-0 flex cursor-pointer pr-3 text-lg leading-5"
+      @click="show = !show"
+    >
+      <Eye v-if="show" class="size-4" />
+      <EyeOff v-else class="size-4" />
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue
new file mode 100644
index 0000000..dae90ef
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue
@@ -0,0 +1,66 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+const props = withDefaults(defineProps<{ password?: string }>(), {
+  password: '',
+});
+
+const strengthList: string[] = [
+  '',
+  '#e74242',
+  '#ED6F6F',
+  '#EFBD47',
+  '#55D18780',
+  '#55D187',
+];
+
+const currentStrength = computed(() => {
+  return checkPasswordStrength(props.password);
+});
+
+const currentColor = computed(() => {
+  return strengthList[currentStrength.value];
+});
+
+/**
+ * Check the strength of a password
+ */
+function checkPasswordStrength(password: string) {
+  let strength = 0;
+
+  // Check length
+  if (password.length >= 8) strength++;
+
+  // Check for lowercase letters
+  if (/[a-z]/.test(password)) strength++;
+
+  // Check for uppercase letters
+  if (/[A-Z]/.test(password)) strength++;
+
+  // Check for numbers
+  if (/\d/.test(password)) strength++;
+
+  // Check for special characters
+  if (/[^\da-z]/i.test(password)) strength++;
+
+  return strength;
+}
+</script>
+
+<template>
+  <div class="relative mt-2 flex items-center justify-between">
+    <template v-for="index in 5" :key="index">
+      <div
+        class="dark:bg-input-background bg-heavy relative mr-1 h-1.5 w-1/5 rounded-sm last:mr-0"
+      >
+        <span
+          :style="{
+            backgroundColor: currentColor,
+            width: currentStrength >= index ? '100%' : '',
+          }"
+          class="absolute left-0 h-full w-0 rounded-sm transition-all duration-500"
+        ></span>
+      </div>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts
new file mode 100644
index 0000000..d2a2f99
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts
@@ -0,0 +1 @@
+export { default as VbenLogo } from './logo.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue
new file mode 100644
index 0000000..1c3b447
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue
@@ -0,0 +1,65 @@
+<script setup lang="ts">
+import { VbenAvatar } from '../avatar';
+
+interface Props {
+  /**
+   * @zh_CN 鏄惁鏀惰捣鏂囨湰
+   */
+  collapsed?: boolean;
+  /**
+   * @zh_CN Logo 璺宠浆鍦板潃
+   */
+  href?: string;
+  /**
+   * @zh_CN Logo 鍥剧墖澶у皬
+   */
+  logoSize?: number;
+  /**
+   * @zh_CN Logo 鍥炬爣
+   */
+  src?: string;
+  /**
+   * @zh_CN Logo 鏂囨湰
+   */
+  text: string;
+  /**
+   * @zh_CN Logo 涓婚
+   */
+  theme?: string;
+}
+
+defineOptions({
+  name: 'VbenLogo',
+});
+
+withDefaults(defineProps<Props>(), {
+  collapsed: false,
+  href: 'javascript:void 0',
+  logoSize: 32,
+  src: '',
+  theme: 'light',
+});
+</script>
+
+<template>
+  <div :class="theme" class="flex h-full items-center text-lg">
+    <a
+      :class="$attrs.class"
+      :href="href"
+      class="flex h-full items-center gap-2 overflow-hidden px-3 text-lg leading-normal transition-all duration-500"
+    >
+      <VbenAvatar
+        v-if="src"
+        :alt="text"
+        :src="src"
+        class="relative w-8 rounded-none bg-transparent"
+      />
+      <span
+        v-if="!collapsed"
+        class="text-foreground truncate text-nowrap font-semibold"
+      >
+        {{ text }}
+      </span>
+    </a>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts
new file mode 100644
index 0000000..9d6a61a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts
@@ -0,0 +1,3 @@
+export { default as VbenPinInput } from './input.vue';
+
+export type * from './types';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue
new file mode 100644
index 0000000..7ba5cfb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue
@@ -0,0 +1,116 @@
+<script setup lang="ts">
+import type { PinInputProps } from './types';
+
+import { computed, onBeforeUnmount, ref, useId, watch } from 'vue';
+
+import { PinInput, PinInputGroup, PinInputInput } from '../../ui';
+import { VbenButton } from '../button';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const {
+  codeLength = 6,
+  createText = async () => {},
+  disabled = false,
+  handleSendCode = async () => {},
+  loading = false,
+  maxTime = 60,
+} = defineProps<PinInputProps>();
+
+const emit = defineEmits<{
+  complete: [];
+  sendError: [error: any];
+}>();
+
+const timer = ref<ReturnType<typeof setTimeout>>();
+
+const modelValue = defineModel<string>();
+
+const inputValue = ref<string[]>([]);
+const countdown = ref(0);
+
+const btnText = computed(() => {
+  const countdownValue = countdown.value;
+  return createText?.(countdownValue);
+});
+
+const btnLoading = computed(() => {
+  return loading || countdown.value > 0;
+});
+
+watch(
+  () => modelValue.value,
+  () => {
+    inputValue.value = modelValue.value?.split('') ?? [];
+  },
+);
+
+function handleComplete(e: string[]) {
+  modelValue.value = e.join('');
+  emit('complete');
+}
+
+async function handleSend(e: Event) {
+  try {
+    e?.preventDefault();
+    await handleSendCode();
+    countdown.value = maxTime;
+    startCountdown();
+  } catch (error) {
+    console.error('Failed to send code:', error);
+    // Consider emitting an error event or showing a notification
+    emit('sendError', error);
+  }
+}
+
+function startCountdown() {
+  if (countdown.value > 0) {
+    timer.value = setTimeout(() => {
+      countdown.value--;
+      startCountdown();
+    }, 1000);
+  }
+}
+
+onBeforeUnmount(() => {
+  countdown.value = 0;
+  clearTimeout(timer.value);
+});
+
+const id = useId();
+</script>
+
+<template>
+  <PinInput
+    :id="id"
+    v-model="inputValue"
+    :disabled="disabled"
+    class="flex w-full justify-between"
+    otp
+    placeholder="鈼�"
+    type="number"
+    @complete="handleComplete"
+  >
+    <div class="relative flex w-full">
+      <PinInputGroup class="mr-2">
+        <PinInputInput
+          v-for="(item, index) in codeLength"
+          :key="item"
+          :index="index"
+        />
+      </PinInputGroup>
+      <VbenButton
+        :disabled="disabled"
+        :loading="btnLoading"
+        class="flex-grow"
+        size="lg"
+        variant="outline"
+        @click="handleSend"
+      >
+        {{ btnText }}
+      </VbenButton>
+    </div>
+  </PinInput>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts
new file mode 100644
index 0000000..182d884
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts
@@ -0,0 +1,30 @@
+interface PinInputProps {
+  class?: any;
+  /**
+   * 楠岃瘉鐮侀暱搴�
+   */
+  codeLength?: number;
+  /**
+   * 鍙戦�侀獙璇佺爜鎸夐挳鏂囨湰
+   */
+  createText?: (countdown: number) => string;
+  /**
+   * 鏄惁绂佺敤
+   */
+  disabled?: boolean;
+  /**
+   * 鑷畾涔夐獙璇佺爜鍙戦�侀�昏緫
+   * @returns
+   */
+  handleSendCode?: () => Promise<void>;
+  /**
+   * 鍙戦�侀獙璇佺爜鎸夐挳loading
+   */
+  loading?: boolean;
+  /**
+   * 鏈�澶ч噸璇曟椂闂�
+   */
+  maxTime?: number;
+}
+
+export type { PinInputProps };
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts
new file mode 100644
index 0000000..bc0b64a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts
@@ -0,0 +1 @@
+export { default as VbenPopover } from './popover.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue
new file mode 100644
index 0000000..b38e0b4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue
@@ -0,0 +1,57 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+import type {
+  PopoverContentProps,
+  PopoverRootEmits,
+  PopoverRootProps,
+} from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { useForwardPropsEmits } from 'radix-vue';
+
+import {
+  PopoverContent,
+  Popover as PopoverRoot,
+  PopoverTrigger,
+} from '../../ui';
+
+interface Props extends PopoverRootProps {
+  class?: ClassType;
+  contentClass?: ClassType;
+  contentProps?: PopoverContentProps;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const emits = defineEmits<PopoverRootEmits>();
+
+const delegatedProps = computed(() => {
+  const {
+    class: _cls,
+    contentClass: _,
+    contentProps: _cProps,
+    ...delegated
+  } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <PopoverRoot v-bind="forwarded">
+    <PopoverTrigger>
+      <slot name="trigger"></slot>
+
+      <PopoverContent
+        :class="contentClass"
+        class="side-content z-[1000]"
+        v-bind="contentProps"
+      >
+        <slot></slot>
+      </PopoverContent>
+    </PopoverTrigger>
+  </PopoverRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts
new file mode 100644
index 0000000..788c8af
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts
@@ -0,0 +1 @@
+export { default as VbenRenderContent } from './render-content.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue
new file mode 100644
index 0000000..8476d7a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue
@@ -0,0 +1,39 @@
+<script lang="ts">
+import type { Component, PropType } from 'vue';
+import { defineComponent, h } from 'vue';
+
+import { isFunction, isObject } from '@vben-core/shared/utils';
+
+export default defineComponent({
+  name: 'RenderContent',
+  props: {
+    content: {
+      default: undefined as
+        | PropType<(() => any) | Component | string>
+        | undefined,
+      type: [Object, String, Function],
+    },
+  },
+  setup(props, { attrs, slots }) {
+    return () => {
+      if (!props.content) {
+        return null;
+      }
+      const isComponent =
+        (isObject(props.content) || isFunction(props.content)) &&
+        props.content !== null;
+      if (!isComponent) {
+        return props.content;
+      }
+      return h(props.content as never, {
+        ...attrs,
+        props: {
+          ...props,
+          ...attrs,
+        },
+        slots,
+      });
+    };
+  },
+});
+</script>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts
new file mode 100644
index 0000000..57f6f1b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts
@@ -0,0 +1 @@
+export { default as VbenScrollbar } from './scrollbar.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue
new file mode 100644
index 0000000..f066b91
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue
@@ -0,0 +1,153 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+
+import { computed, ref } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ScrollArea, ScrollBar } from '../../ui';
+
+interface Props {
+  class?: ClassType;
+  horizontal?: boolean;
+  scrollBarClass?: ClassType;
+  shadow?: boolean;
+  shadowBorder?: boolean;
+  shadowBottom?: boolean;
+  shadowLeft?: boolean;
+  shadowRight?: boolean;
+  shadowTop?: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  class: '',
+  horizontal: false,
+  shadow: false,
+  shadowBorder: false,
+  shadowBottom: true,
+  shadowLeft: false,
+  shadowRight: false,
+  shadowTop: true,
+});
+
+const emit = defineEmits<{
+  scrollAt: [{ bottom: boolean; left: boolean; right: boolean; top: boolean }];
+}>();
+
+const isAtTop = ref(true);
+const isAtRight = ref(false);
+const isAtBottom = ref(false);
+const isAtLeft = ref(true);
+
+const showShadowTop = computed(() => props.shadow && props.shadowTop);
+const showShadowBottom = computed(() => props.shadow && props.shadowBottom);
+const showShadowLeft = computed(() => props.shadow && props.shadowLeft);
+const showShadowRight = computed(() => props.shadow && props.shadowRight);
+
+const computedShadowClasses = computed(() => {
+  return {
+    'both-shadow':
+      !isAtLeft.value &&
+      !isAtRight.value &&
+      showShadowLeft.value &&
+      showShadowRight.value,
+    'left-shadow': !isAtLeft.value && showShadowLeft.value,
+    'right-shadow': !isAtRight.value && showShadowRight.value,
+  };
+});
+
+function handleScroll(event: Event) {
+  const target = event.target as HTMLElement;
+  const scrollTop = target?.scrollTop ?? 0;
+  const scrollLeft = target?.scrollLeft ?? 0;
+  const offsetHeight = target?.offsetHeight ?? 0;
+  const offsetWidth = target?.offsetWidth ?? 0;
+  const scrollHeight = target?.scrollHeight ?? 0;
+  const scrollWidth = target?.scrollWidth ?? 0;
+  isAtTop.value = scrollTop <= 0;
+  isAtLeft.value = scrollLeft <= 0;
+  isAtBottom.value = scrollTop + offsetHeight >= scrollHeight;
+  isAtRight.value = scrollLeft + offsetWidth >= scrollWidth;
+
+  emit('scrollAt', {
+    bottom: isAtBottom.value,
+    left: isAtLeft.value,
+    right: isAtRight.value,
+    top: isAtTop.value,
+  });
+}
+</script>
+
+<template>
+  <ScrollArea
+    :class="[cn(props.class), computedShadowClasses]"
+    :on-scroll="handleScroll"
+    class="vben-scrollbar relative"
+  >
+    <div
+      v-if="showShadowTop"
+      :class="{
+        'opacity-100': !isAtTop,
+        'border-border border-t': shadowBorder && !isAtTop,
+      }"
+      class="scrollbar-top-shadow pointer-events-none absolute top-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
+    ></div>
+    <slot></slot>
+    <div
+      v-if="showShadowBottom"
+      :class="{
+        'opacity-100': !isAtTop && !isAtBottom,
+        'border-border border-b': shadowBorder && !isAtTop && !isAtBottom,
+      }"
+      class="scrollbar-bottom-shadow pointer-events-none absolute bottom-0 z-10 h-12 w-full opacity-0 transition-opacity duration-300 ease-in-out will-change-[opacity]"
+    ></div>
+    <ScrollBar
+      v-if="horizontal"
+      :class="scrollBarClass"
+      orientation="horizontal"
+    />
+  </ScrollArea>
+</template>
+
+<style scoped>
+.vben-scrollbar {
+  &:not(.both-shadow).left-shadow {
+    mask-image: linear-gradient(90deg, transparent, #000 16px);
+  }
+
+  &:not(.both-shadow).right-shadow {
+    mask-image: linear-gradient(
+      90deg,
+      #000 0%,
+      #000 calc(100% - 16px),
+      transparent
+    );
+  }
+
+  &.both-shadow {
+    mask-image: linear-gradient(
+      90deg,
+      transparent,
+      #000 16px,
+      #000 calc(100% - 16px),
+      transparent 100%
+    );
+  }
+}
+
+.scrollbar-top-shadow {
+  background: linear-gradient(
+    to bottom,
+    hsl(var(--scroll-shadow, var(--background))),
+    transparent
+  );
+}
+
+.scrollbar-bottom-shadow {
+  background: linear-gradient(
+    to top,
+    hsl(var(--scroll-shadow, var(--background))),
+    transparent
+  );
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts
new file mode 100644
index 0000000..1ec820d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts
@@ -0,0 +1,3 @@
+export { default as VbenSegmented } from './segmented.vue';
+
+export type * from './types';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue
new file mode 100644
index 0000000..f1a8e57
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue
@@ -0,0 +1,59 @@
+<script setup lang="ts">
+import type { SegmentedItem } from './types';
+
+import { computed } from 'vue';
+
+import { TabsTrigger } from 'radix-vue';
+
+import { Tabs, TabsContent, TabsList } from '../../ui';
+import TabsIndicator from './tabs-indicator.vue';
+
+interface Props {
+  defaultValue?: string;
+  tabs: SegmentedItem[];
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  defaultValue: '',
+  tabs: () => [],
+});
+
+const activeTab = defineModel<string>();
+
+const getDefaultValue = computed(() => {
+  return props.defaultValue || props.tabs[0]?.value;
+});
+
+const tabsStyle = computed(() => {
+  return {
+    'grid-template-columns': `repeat(${props.tabs.length}, minmax(0, 1fr))`,
+  };
+});
+
+const tabsIndicatorStyle = computed(() => {
+  return {
+    width: `${(100 / props.tabs.length).toFixed(0)}%`,
+  };
+});
+</script>
+
+<template>
+  <Tabs v-model="activeTab" :default-value="getDefaultValue">
+    <TabsList :style="tabsStyle" class="bg-accent relative grid w-full">
+      <TabsIndicator :style="tabsIndicatorStyle" />
+      <template v-for="tab in tabs" :key="tab.value">
+        <TabsTrigger
+          :value="tab.value"
+          class="z-20 inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium disabled:pointer-events-none disabled:opacity-50"
+        >
+          {{ tab.label }}
+        </TabsTrigger>
+      </template>
+    </TabsList>
+    <template v-for="tab in tabs" :key="tab.value">
+      <TabsContent :value="tab.value">
+        <slot :name="tab.value"></slot>
+      </TabsContent>
+    </template>
+  </Tabs>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue
new file mode 100644
index 0000000..886eb6d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import type { TabsIndicatorProps } from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { TabsIndicator, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & TabsIndicatorProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <TabsIndicator
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'absolute bottom-0 left-0 z-10 h-full w-1/2 translate-x-[--radix-tabs-indicator-position] rounded-full px-0 py-1 pr-1 transition-[width,transform] duration-300',
+        props.class,
+      )
+    "
+  >
+    <div
+      class="bg-background text-foreground inline-flex h-full w-full items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
+    >
+      <slot></slot>
+    </div>
+  </TabsIndicator>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts
new file mode 100644
index 0000000..b24f983
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts
@@ -0,0 +1,6 @@
+interface SegmentedItem {
+  label: string;
+  value: string;
+}
+
+export type { SegmentedItem };
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts
new file mode 100644
index 0000000..1aa5d98
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts
@@ -0,0 +1 @@
+export { default as VbenSelect } from './select.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue
new file mode 100644
index 0000000..1f79768
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue
@@ -0,0 +1,31 @@
+<script lang="ts" setup>
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from '../../ui';
+
+interface Props {
+  class?: any;
+  // 寮瑰嚭灞傜殑绫诲悕
+  contentClass?: any;
+  options?: Array<{ label: string; value: string }>;
+  placeholder?: string;
+}
+
+const props = defineProps<Props>();
+</script>
+<template>
+  <Select>
+    <SelectTrigger :class="props.class">
+      <SelectValue :placeholder="placeholder" />
+    </SelectTrigger>
+    <SelectContent :class="props.contentClass">
+      <template v-for="item in options" :key="item.value">
+        <SelectItem :value="item.value"> {{ item.label }} </SelectItem>
+      </template>
+    </SelectContent>
+  </Select>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts
new file mode 100644
index 0000000..a529826
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts
@@ -0,0 +1 @@
+export { default as VbenSpineText } from './spine-text.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue
new file mode 100644
index 0000000..f5357ae
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue
@@ -0,0 +1,49 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+const { animationDuration = 2, animationIterationCount = 'infinite' } =
+  defineProps<{
+    // 鍔ㄧ敾鎸佺画鏃堕棿锛屽崟浣嶇
+    animationDuration?: number;
+    // 鍔ㄧ敾鏄惁鍙墽琛屼竴娆�
+    animationIterationCount?: 'infinite' | number;
+  }>();
+
+const style = computed(() => {
+  return {
+    animation: `shine ${animationDuration}s linear ${animationIterationCount}`,
+  };
+});
+</script>
+<template>
+  <div :style="style" class="vben-spine-text !bg-clip-text text-transparent">
+    <slot></slot>
+  </div>
+</template>
+<style>
+.vben-spine-text {
+  background:
+    radial-gradient(circle at center, rgb(255 255 255 / 80%), #f000) -200% 50% /
+      200% 100% no-repeat,
+    #000;
+
+  /* animation: shine 3s linear infinite; */
+}
+
+.dark .vben-spine-text {
+  background:
+    radial-gradient(circle at center, rgb(24 24 26 / 80%), transparent) -200% 50% /
+      200% 100% no-repeat,
+    #f4f4f4;
+}
+
+@keyframes shine {
+  0% {
+    background-position: 200% 0%;
+  }
+
+  100% {
+    background-position: -200% 0%;
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts
new file mode 100644
index 0000000..4bba740
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts
@@ -0,0 +1,2 @@
+export { default as VbenLoading } from './loading.vue';
+export { default as VbenSpinner } from './spinner.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue
new file mode 100644
index 0000000..756fa0f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue
@@ -0,0 +1,137 @@
+<script lang="ts" setup>
+import { ref, watch } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+interface Props {
+  class?: string;
+  /**
+   * @zh_CN 鏈�灏忓姞杞芥椂闂�
+   * @en_US Minimum loading time
+   */
+  minLoadingTime?: number;
+
+  /**
+   * @zh_CN loading鐘舵�佸紑鍚�
+   */
+  spinning?: boolean;
+  /**
+   * @zh_CN 鏂囧瓧
+   */
+  text?: string;
+}
+
+defineOptions({
+  name: 'VbenLoading',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  minLoadingTime: 50,
+  text: '',
+});
+// const startTime = ref(0);
+const showSpinner = ref(false);
+const renderSpinner = ref(true);
+const timer = ref<ReturnType<typeof setTimeout>>();
+
+watch(
+  () => props.spinning,
+  (show) => {
+    if (!show) {
+      showSpinner.value = false;
+      clearTimeout(timer.value);
+      return;
+    }
+
+    // startTime.value = performance.now();
+    timer.value = setTimeout(() => {
+      // const loadingTime = performance.now() - startTime.value;
+
+      showSpinner.value = true;
+      if (showSpinner.value) {
+        renderSpinner.value = true;
+      }
+    }, props.minLoadingTime);
+  },
+  {
+    immediate: true,
+  },
+);
+
+function onTransitionEnd() {
+  if (!showSpinner.value) {
+    renderSpinner.value = false;
+  }
+}
+</script>
+
+<template>
+  <div
+    :class="
+      cn(
+        'z-100 dark:bg-overlay bg-overlay-content pointer-events-none absolute left-0 top-0 flex size-full flex-col items-center justify-center transition-all duration-500',
+        {
+          'invisible opacity-0': !showSpinner,
+        },
+        props.class,
+      )
+    "
+    @transitionend="onTransitionEnd"
+  >
+    <span class="dot relative inline-block size-9 text-3xl">
+      <i
+        v-for="index in 4"
+        :key="index"
+        class="bg-primary absolute block size-4 origin-[50%_50%] scale-75 rounded-full opacity-30"
+      ></i>
+    </span>
+
+    <div v-if="text" class="mt-4 text-xs">{{ text }}</div>
+  </div>
+</template>
+
+<style scoped>
+.dot {
+  transform: rotate(45deg);
+  animation: rotate-ani 1.2s infinite linear;
+}
+
+.dot i {
+  animation: spin-move-ani 1s infinite linear alternate;
+}
+
+.dot i:nth-child(1) {
+  top: 0;
+  left: 0;
+}
+
+.dot i:nth-child(2) {
+  top: 0;
+  right: 0;
+  animation-delay: 0.4s;
+}
+
+.dot i:nth-child(3) {
+  right: 0;
+  bottom: 0;
+  animation-delay: 0.8s;
+}
+
+.dot i:nth-child(4) {
+  bottom: 0;
+  left: 0;
+  animation-delay: 1.2s;
+}
+
+@keyframes rotate-ani {
+  to {
+    transform: rotate(405deg);
+  }
+}
+
+@keyframes spin-move-ani {
+  to {
+    opacity: 1;
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue
new file mode 100644
index 0000000..a72ed49
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue
@@ -0,0 +1,125 @@
+<script lang="ts" setup>
+import { ref, watch } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+interface Props {
+  class?: string;
+  /**
+   * @zh_CN 鏈�灏忓姞杞芥椂闂�
+   * @en_US Minimum loading time
+   */
+  minLoadingTime?: number;
+  /**
+   * @zh_CN loading鐘舵�佸紑鍚�
+   */
+  spinning?: boolean;
+}
+
+defineOptions({
+  name: 'VbenSpinner',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  minLoadingTime: 50,
+});
+// const startTime = ref(0);
+const showSpinner = ref(false);
+const renderSpinner = ref(true);
+const timer = ref<ReturnType<typeof setTimeout>>();
+
+watch(
+  () => props.spinning,
+  (show) => {
+    if (!show) {
+      showSpinner.value = false;
+      clearTimeout(timer.value);
+      return;
+    }
+
+    // startTime.value = performance.now();
+    timer.value = setTimeout(() => {
+      // const loadingTime = performance.now() - startTime.value;
+
+      showSpinner.value = true;
+      if (showSpinner.value) {
+        renderSpinner.value = true;
+      }
+    }, props.minLoadingTime);
+  },
+  {
+    immediate: true,
+  },
+);
+
+function onTransitionEnd() {
+  if (!showSpinner.value) {
+    renderSpinner.value = false;
+  }
+}
+</script>
+
+<template>
+  <div
+    :class="
+      cn(
+        'flex-center z-100 bg-overlay-content absolute left-0 top-0 size-full backdrop-blur-sm transition-all duration-500',
+        {
+          'invisible opacity-0': !showSpinner,
+        },
+        props.class,
+      )
+    "
+    @transitionend="onTransitionEnd"
+  >
+    <div
+      class="loader before:bg-primary/50 after:bg-primary relative size-12 before:absolute before:left-0 before:top-[60px] before:h-[5px] before:w-12 before:rounded-[50%] before:content-[''] after:absolute after:left-0 after:top-0 after:h-full after:w-full after:rounded after:content-['']"
+    ></div>
+  </div>
+</template>
+
+<style scoped>
+.loader {
+  &::before {
+    animation: loader-shadow-ani 0.5s linear infinite;
+  }
+
+  &::after {
+    animation: loader-jump-ani 0.5s linear infinite;
+  }
+}
+
+@keyframes loader-jump-ani {
+  15% {
+    border-bottom-right-radius: 3px;
+  }
+
+  25% {
+    transform: translateY(9px) rotate(22.5deg);
+  }
+
+  50% {
+    border-bottom-right-radius: 40px;
+    transform: translateY(18px) scale(1, 0.9) rotate(45deg);
+  }
+
+  75% {
+    transform: translateY(9px) rotate(67.5deg);
+  }
+
+  100% {
+    transform: translateY(0) rotate(90deg);
+  }
+}
+
+@keyframes loader-shadow-ani {
+  0%,
+  100% {
+    transform: scale(1, 1);
+  }
+
+  50% {
+    transform: scale(1.2, 1);
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue
new file mode 100644
index 0000000..2e84b62
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue
@@ -0,0 +1,31 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { CircleHelp } from 'lucide-vue-next';
+
+import Tooltip from './tooltip.vue';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+defineProps<{ triggerClass?: string }>();
+</script>
+
+<template>
+  <Tooltip :delay-duration="300" side="top">
+    <template #trigger>
+      <slot name="trigger">
+        <CircleHelp
+          :class="
+            cn(
+              'text-foreground/80 hover:text-foreground inline-flex size-5 cursor-pointer',
+              triggerClass,
+            )
+          "
+        />
+      </slot>
+    </template>
+    <slot></slot>
+  </Tooltip>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts
new file mode 100644
index 0000000..65bf053
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts
@@ -0,0 +1,2 @@
+export { default as VbenHelpTooltip } from './help-tooltip.vue';
+export { default as VbenTooltip } from './tooltip.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue
new file mode 100644
index 0000000..ae5f5e4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue
@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+import type { TooltipContentProps } from 'radix-vue';
+
+import type { StyleValue } from 'vue';
+
+import {
+  Tooltip,
+  TooltipContent,
+  TooltipProvider,
+  TooltipTrigger,
+} from '../../ui';
+
+interface Props {
+  contentClass?: ClassType;
+  contentStyle?: StyleValue;
+  delayDuration?: number;
+  side?: TooltipContentProps['side'];
+}
+
+withDefaults(defineProps<Props>(), {
+  delayDuration: 0,
+  side: 'right',
+});
+</script>
+
+<template>
+  <TooltipProvider :delay-duration="delayDuration">
+    <Tooltip>
+      <TooltipTrigger as-child tabindex="-1">
+        <slot name="trigger"></slot>
+      </TooltipTrigger>
+      <TooltipContent
+        :class="contentClass"
+        :side="side"
+        :style="contentStyle"
+        class="side-content text-popover-foreground bg-accent rounded-md"
+      >
+        <slot></slot>
+      </TooltipContent>
+    </Tooltip>
+  </TooltipProvider>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/index.ts
new file mode 100644
index 0000000..00e1b99
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/index.ts
@@ -0,0 +1,3 @@
+export * from './components';
+export * from './ui';
+export { createContext, Slot, VisuallyHidden } from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue
new file mode 100644
index 0000000..fb8f05c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  AccordionRoot,
+  type AccordionRootEmits,
+  type AccordionRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<AccordionRootProps>();
+const emits = defineEmits<AccordionRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <AccordionRoot v-bind="forwarded">
+    <slot></slot>
+  </AccordionRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue
new file mode 100644
index 0000000..5183a5b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { AccordionContent, type AccordionContentProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & AccordionContentProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <AccordionContent
+    v-bind="delegatedProps"
+    class="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
+  >
+    <div :class="cn('pb-4 pt-0', props.class)">
+      <slot></slot>
+    </div>
+  </AccordionContent>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue
new file mode 100644
index 0000000..189d0c2
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue
@@ -0,0 +1,27 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  AccordionItem,
+  type AccordionItemProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & AccordionItemProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <AccordionItem v-bind="forwardedProps" :class="cn('border-b', props.class)">
+    <slot></slot>
+  </AccordionItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue
new file mode 100644
index 0000000..48d65e6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue
@@ -0,0 +1,41 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronDown } from 'lucide-vue-next';
+import {
+  AccordionHeader,
+  AccordionTrigger,
+  type AccordionTriggerProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & AccordionTriggerProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <AccordionHeader class="flex">
+    <AccordionTrigger
+      v-bind="delegatedProps"
+      :class="
+        cn(
+          'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+      <slot name="icon">
+        <ChevronDown
+          class="text-muted-foreground h-4 w-4 shrink-0 transition-transform duration-200"
+        />
+      </slot>
+    </AccordionTrigger>
+  </AccordionHeader>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts
new file mode 100644
index 0000000..821d3a1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts
@@ -0,0 +1,4 @@
+export { default as Accordion } from './Accordion.vue';
+export { default as AccordionContent } from './AccordionContent.vue';
+export { default as AccordionItem } from './AccordionItem.vue';
+export { default as AccordionTrigger } from './AccordionTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue
new file mode 100644
index 0000000..d3eeb4f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { AvatarRoot } from 'radix-vue';
+
+import { avatarVariant, type AvatarVariants } from './avatar';
+
+const props = withDefaults(
+  defineProps<{
+    class?: any;
+    shape?: AvatarVariants['shape'];
+    size?: AvatarVariants['size'];
+  }>(),
+  {
+    shape: 'circle',
+    size: 'sm',
+  },
+);
+</script>
+
+<template>
+  <AvatarRoot :class="cn(avatarVariant({ size, shape }), props.class)">
+    <slot></slot>
+  </AvatarRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue
new file mode 100644
index 0000000..fb115ed
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { AvatarFallback, type AvatarFallbackProps } from 'radix-vue';
+
+const props = defineProps<AvatarFallbackProps>();
+</script>
+
+<template>
+  <AvatarFallback v-bind="props">
+    <slot></slot>
+  </AvatarFallback>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue
new file mode 100644
index 0000000..bac84a5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue
@@ -0,0 +1,9 @@
+<script setup lang="ts">
+import { AvatarImage, type AvatarImageProps } from 'radix-vue';
+
+const props = defineProps<AvatarImageProps>();
+</script>
+
+<template>
+  <AvatarImage v-bind="props" class="h-full w-full object-cover" />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts
new file mode 100644
index 0000000..b996415
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts
@@ -0,0 +1,20 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+
+export const avatarVariant = cva(
+  'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden',
+  {
+    variants: {
+      shape: {
+        circle: 'rounded-full',
+        square: 'rounded-md',
+      },
+      size: {
+        base: 'h-16 w-16 text-2xl',
+        lg: 'h-32 w-32 text-5xl',
+        sm: 'h-10 w-10 text-xs',
+      },
+    },
+  },
+);
+
+export type AvatarVariants = VariantProps<typeof avatarVariant>;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts
new file mode 100644
index 0000000..fef6b01
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts
@@ -0,0 +1,4 @@
+export * from './avatar';
+export { default as Avatar } from './Avatar.vue';
+export { default as AvatarFallback } from './AvatarFallback.vue';
+export { default as AvatarImage } from './AvatarImage.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue
new file mode 100644
index 0000000..729dc9d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { type BadgeVariants, badgeVariants } from './badge';
+
+const props = defineProps<{
+  class?: any;
+  variant?: BadgeVariants['variant'];
+}>();
+</script>
+
+<template>
+  <div :class="cn(badgeVariants({ variant }), props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts
new file mode 100644
index 0000000..dd6b227
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts
@@ -0,0 +1,23 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+
+export const badgeVariants = cva(
+  'inline-flex items-center rounded-md border border-border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
+  {
+    defaultVariants: {
+      variant: 'default',
+    },
+    variants: {
+      variant: {
+        default:
+          'border-transparent bg-accent hover:bg-accent text-primary-foreground shadow',
+        destructive:
+          'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive-hover',
+        outline: 'text-foreground',
+        secondary:
+          'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
+      },
+    },
+  },
+);
+
+export type BadgeVariants = VariantProps<typeof badgeVariants>;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts
new file mode 100644
index 0000000..b37175b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts
@@ -0,0 +1,3 @@
+export * from './badge';
+
+export { default as Badge } from './Badge.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue
new file mode 100644
index 0000000..eb065de
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <nav :class="props.class" aria-label="breadcrumb" role="navigation">
+    <slot></slot>
+  </nav>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue
new file mode 100644
index 0000000..b98f99e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue
@@ -0,0 +1,22 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+import { MoreHorizontal } from 'lucide-vue-next';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <span
+    :class="cn('flex h-9 w-9 items-center justify-center', props.class)"
+    aria-hidden="true"
+    role="presentation"
+  >
+    <slot>
+      <MoreHorizontal class="h-4 w-4" />
+    </slot>
+    <span class="sr-only">More</span>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue
new file mode 100644
index 0000000..0ceb3eb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue
@@ -0,0 +1,17 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <li
+    :class="
+      cn('hover:text-foreground inline-flex items-center gap-1.5', props.class)
+    "
+  >
+    <slot></slot>
+  </li>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue
new file mode 100644
index 0000000..c0b95c7
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+import { Primitive, type PrimitiveProps } from 'radix-vue';
+
+const props = withDefaults(defineProps<{ class?: any } & PrimitiveProps>(), {
+  as: 'a',
+});
+</script>
+
+<template>
+  <Primitive
+    :as="as"
+    :as-child="asChild"
+    :class="cn('hover:text-foreground transition-colors', props.class)"
+  >
+    <slot></slot>
+  </Primitive>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue
new file mode 100644
index 0000000..94600a9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue
@@ -0,0 +1,20 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <ol
+    :class="
+      cn(
+        'text-muted-foreground flex flex-wrap items-center gap-1.5 break-words text-sm sm:gap-2.5',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </ol>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue
new file mode 100644
index 0000000..948aa47
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue
@@ -0,0 +1,18 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <span
+    :class="cn('text-foreground font-normal', props.class)"
+    aria-current="page"
+    aria-disabled="true"
+    role="link"
+  >
+    <slot></slot>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue
new file mode 100644
index 0000000..bf05851
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronRight } from 'lucide-vue-next';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <li
+    :class="cn('[&>svg]:size-3.5', props.class)"
+    aria-hidden="true"
+    role="presentation"
+  >
+    <slot>
+      <ChevronRight />
+    </slot>
+  </li>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts
new file mode 100644
index 0000000..d650f7e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts
@@ -0,0 +1,7 @@
+export { default as Breadcrumb } from './Breadcrumb.vue';
+export { default as BreadcrumbEllipsis } from './BreadcrumbEllipsis.vue';
+export { default as BreadcrumbItem } from './BreadcrumbItem.vue';
+export { default as BreadcrumbLink } from './BreadcrumbLink.vue';
+export { default as BreadcrumbList } from './BreadcrumbList.vue';
+export { default as BreadcrumbPage } from './BreadcrumbPage.vue';
+export { default as BreadcrumbSeparator } from './BreadcrumbSeparator.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue
new file mode 100644
index 0000000..7895d01
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue
@@ -0,0 +1,30 @@
+<script setup lang="ts">
+import type { ButtonVariants, ButtonVariantSize } from './types';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Primitive, type PrimitiveProps } from 'radix-vue';
+
+import { buttonVariants } from './button';
+
+interface Props extends PrimitiveProps {
+  class?: any;
+  size?: ButtonVariantSize;
+  variant?: ButtonVariants;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  as: 'button',
+  class: '',
+});
+</script>
+
+<template>
+  <Primitive
+    :as="as"
+    :as-child="asChild"
+    :class="cn(buttonVariants({ variant, size }), props.class)"
+  >
+    <slot></slot>
+  </Primitive>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts
new file mode 100644
index 0000000..3ca9b4b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts
@@ -0,0 +1,34 @@
+import { cva } from 'class-variance-authority';
+
+export const buttonVariants = cva(
+  'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed  disabled:opacity-50',
+  {
+    defaultVariants: {
+      size: 'default',
+      variant: 'default',
+    },
+    variants: {
+      size: {
+        default: 'h-9 px-4 py-2',
+        icon: 'h-8 w-8 rounded-sm px-1 text-lg',
+        lg: 'h-10 rounded-md px-8',
+        sm: 'h-8 rounded-md px-3 text-xs',
+        xs: 'h-8 w-8 rounded-sm px-1 text-xs',
+      },
+      variant: {
+        default:
+          'bg-primary text-primary-foreground shadow hover:bg-primary/90',
+        destructive:
+          'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive-hover',
+        ghost: 'hover:bg-accent hover:text-accent-foreground',
+        heavy: 'hover:bg-heavy hover:text-heavy-foreground',
+        icon: 'hover:bg-accent hover:text-accent-foreground text-foreground/80',
+        link: 'text-primary underline-offset-4 hover:underline',
+        outline:
+          'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
+        secondary:
+          'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
+      },
+    },
+  },
+);
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts
new file mode 100644
index 0000000..4a575f9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts
@@ -0,0 +1,5 @@
+export * from './button';
+
+export { default as Button } from './Button.vue';
+
+export type * from './types';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts
new file mode 100644
index 0000000..cc5e174
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts
@@ -0,0 +1,20 @@
+export type ButtonVariantSize =
+  | 'default'
+  | 'icon'
+  | 'lg'
+  | 'sm'
+  | 'xs'
+  | null
+  | undefined;
+
+export type ButtonVariants =
+  | 'default'
+  | 'destructive'
+  | 'ghost'
+  | 'heavy'
+  | 'icon'
+  | 'link'
+  | 'outline'
+  | 'secondary'
+  | null
+  | undefined;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue
new file mode 100644
index 0000000..8f396a6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue
@@ -0,0 +1,20 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div
+    :class="
+      cn(
+        'bg-card text-card-foreground border-border rounded-xl border',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue
new file mode 100644
index 0000000..8e8fe50
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div :class="cn('p-6 pt-0', props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue
new file mode 100644
index 0000000..7797c36
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <p :class="cn('text-muted-foreground text-sm', props.class)">
+    <slot></slot>
+  </p>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue
new file mode 100644
index 0000000..01af357
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div :class="cn('flex items-center p-6 pt-0', props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue
new file mode 100644
index 0000000..ced1e8b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div :class="cn('flex flex-col gap-y-1.5 p-5', props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue
new file mode 100644
index 0000000..e357cdc
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <h3 :class="cn('font-semibold leading-none tracking-tight', props.class)">
+    <slot></slot>
+  </h3>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts
new file mode 100644
index 0000000..d652969
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts
@@ -0,0 +1,6 @@
+export { default as Card } from './Card.vue';
+export { default as CardContent } from './CardContent.vue';
+export { default as CardDescription } from './CardDescription.vue';
+export { default as CardFooter } from './CardFooter.vue';
+export { default as CardHeader } from './CardHeader.vue';
+export { default as CardTitle } from './CardTitle.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue
new file mode 100644
index 0000000..a0462e6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Check } from 'lucide-vue-next';
+import {
+  CheckboxIndicator,
+  CheckboxRoot,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & CheckboxRootProps>();
+const emits = defineEmits<CheckboxRootEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <CheckboxRoot
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground border-border peer h-4 w-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <CheckboxIndicator
+      class="flex h-full w-full items-center justify-center text-current"
+    >
+      <slot>
+        <Check class="h-4 w-4" />
+      </slot>
+    </CheckboxIndicator>
+  </CheckboxRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts
new file mode 100644
index 0000000..7f906aa
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts
@@ -0,0 +1 @@
+export { default as Checkbox } from './Checkbox.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue
new file mode 100644
index 0000000..082636a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue
@@ -0,0 +1,18 @@
+<script setup lang="ts">
+import type { ContextMenuRootEmits, ContextMenuRootProps } from 'radix-vue';
+
+import { ContextMenuRoot, useForwardPropsEmits } from 'radix-vue';
+
+const props = withDefaults(defineProps<ContextMenuRootProps>(), {
+  modal: false,
+});
+const emits = defineEmits<ContextMenuRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <ContextMenuRoot v-bind="forwarded">
+    <slot></slot>
+  </ContextMenuRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue
new file mode 100644
index 0000000..5a78756
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue
@@ -0,0 +1,44 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Check } from 'lucide-vue-next';
+import {
+  ContextMenuCheckboxItem,
+  type ContextMenuCheckboxItemEmits,
+  type ContextMenuCheckboxItemProps,
+  ContextMenuItemIndicator,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & ContextMenuCheckboxItemProps>();
+const emits = defineEmits<ContextMenuCheckboxItemEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ContextMenuCheckboxItem
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <ContextMenuItemIndicator>
+        <Check class="h-4 w-4" />
+      </ContextMenuItemIndicator>
+    </span>
+    <slot></slot>
+  </ContextMenuCheckboxItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue
new file mode 100644
index 0000000..87796a1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue
@@ -0,0 +1,40 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ContextMenuContent,
+  type ContextMenuContentEmits,
+  type ContextMenuContentProps,
+  ContextMenuPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & ContextMenuContentProps>();
+const emits = defineEmits<ContextMenuContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ContextMenuPortal>
+    <ContextMenuContent
+      v-bind="forwarded"
+      :class="
+        cn(
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-[1000] min-w-32 overflow-hidden rounded-md border p-1 shadow-md',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+    </ContextMenuContent>
+  </ContextMenuPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue
new file mode 100644
index 0000000..d1d5804
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { ContextMenuGroup, type ContextMenuGroupProps } from 'radix-vue';
+
+const props = defineProps<ContextMenuGroupProps>();
+</script>
+
+<template>
+  <ContextMenuGroup v-bind="props">
+    <slot></slot>
+  </ContextMenuGroup>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue
new file mode 100644
index 0000000..ed11878
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue
@@ -0,0 +1,40 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ContextMenuItem,
+  type ContextMenuItemEmits,
+  type ContextMenuItemProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<
+  { class?: any; inset?: boolean } & ContextMenuItemProps
+>();
+const emits = defineEmits<ContextMenuItemEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ContextMenuItem
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        inset && 'pl-8',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </ContextMenuItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue
new file mode 100644
index 0000000..eff8fe4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ContextMenuLabel, type ContextMenuLabelProps } from 'radix-vue';
+
+const props = defineProps<
+  { class?: any; inset?: boolean } & ContextMenuLabelProps
+>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <ContextMenuLabel
+    v-bind="delegatedProps"
+    :class="
+      cn(
+        'text-foreground px-2 py-1.5 text-sm font-semibold',
+        inset && 'pl-8',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </ContextMenuLabel>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue
new file mode 100644
index 0000000..bcd95ed
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { ContextMenuPortal, type ContextMenuPortalProps } from 'radix-vue';
+
+const props = defineProps<ContextMenuPortalProps>();
+</script>
+
+<template>
+  <ContextMenuPortal v-bind="props">
+    <slot></slot>
+  </ContextMenuPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue
new file mode 100644
index 0000000..bfed356
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  ContextMenuRadioGroup,
+  type ContextMenuRadioGroupEmits,
+  type ContextMenuRadioGroupProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<ContextMenuRadioGroupProps>();
+const emits = defineEmits<ContextMenuRadioGroupEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <ContextMenuRadioGroup v-bind="forwarded">
+    <slot></slot>
+  </ContextMenuRadioGroup>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue
new file mode 100644
index 0000000..05d7a49
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue
@@ -0,0 +1,44 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Circle } from 'lucide-vue-next';
+import {
+  ContextMenuItemIndicator,
+  ContextMenuRadioItem,
+  type ContextMenuRadioItemEmits,
+  type ContextMenuRadioItemProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & ContextMenuRadioItemProps>();
+const emits = defineEmits<ContextMenuRadioItemEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ContextMenuRadioItem
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <ContextMenuItemIndicator>
+        <Circle class="h-2 w-2 fill-current" />
+      </ContextMenuItemIndicator>
+    </span>
+    <slot></slot>
+  </ContextMenuRadioItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue
new file mode 100644
index 0000000..56231e0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ContextMenuSeparator,
+  type ContextMenuSeparatorProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & ContextMenuSeparatorProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <ContextMenuSeparator
+    v-bind="delegatedProps"
+    :class="cn('bg-border -mx-1 my-1 h-px', props.class)"
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue
new file mode 100644
index 0000000..21d0f9b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <span
+    :class="
+      cn('text-muted-foreground ml-auto text-xs tracking-widest', props.class)
+    "
+  >
+    <slot></slot>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue
new file mode 100644
index 0000000..a3747fe
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  ContextMenuSub,
+  type ContextMenuSubEmits,
+  type ContextMenuSubProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<ContextMenuSubProps>();
+const emits = defineEmits<ContextMenuSubEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <ContextMenuSub v-bind="forwarded">
+    <slot></slot>
+  </ContextMenuSub>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue
new file mode 100644
index 0000000..7e78128
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ContextMenuSubContent,
+  type DropdownMenuSubContentEmits,
+  type DropdownMenuSubContentProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DropdownMenuSubContentProps>();
+const emits = defineEmits<DropdownMenuSubContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ContextMenuSubContent
+    v-bind="forwarded"
+    :class="
+      cn(
+        'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </ContextMenuSubContent>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue
new file mode 100644
index 0000000..fbf6fe1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue
@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronRight } from 'lucide-vue-next';
+import {
+  ContextMenuSubTrigger,
+  type ContextMenuSubTriggerProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<
+  {
+    class?: any;
+    inset?: boolean;
+  } & ContextMenuSubTriggerProps
+>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <ContextMenuSubTrigger
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
+        inset && 'pl-8',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+    <ChevronRight class="ml-auto h-4 w-4" />
+  </ContextMenuSubTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue
new file mode 100644
index 0000000..41446d0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import {
+  ContextMenuTrigger,
+  type ContextMenuTriggerProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<ContextMenuTriggerProps>();
+
+const forwardedProps = useForwardProps(props);
+</script>
+
+<template>
+  <ContextMenuTrigger v-bind="forwardedProps">
+    <slot></slot>
+  </ContextMenuTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts
new file mode 100644
index 0000000..c9f7d0d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts
@@ -0,0 +1,14 @@
+export { default as ContextMenu } from './ContextMenu.vue';
+export { default as ContextMenuCheckboxItem } from './ContextMenuCheckboxItem.vue';
+export { default as ContextMenuContent } from './ContextMenuContent.vue';
+export { default as ContextMenuGroup } from './ContextMenuGroup.vue';
+export { default as ContextMenuItem } from './ContextMenuItem.vue';
+export { default as ContextMenuLabel } from './ContextMenuLabel.vue';
+export { default as ContextMenuRadioGroup } from './ContextMenuRadioGroup.vue';
+export { default as ContextMenuRadioItem } from './ContextMenuRadioItem.vue';
+export { default as ContextMenuSeparator } from './ContextMenuSeparator.vue';
+export { default as ContextMenuShortcut } from './ContextMenuShortcut.vue';
+export { default as ContextMenuSub } from './ContextMenuSub.vue';
+export { default as ContextMenuSubContent } from './ContextMenuSubContent.vue';
+export { default as ContextMenuSubTrigger } from './ContextMenuSubTrigger.vue';
+export { default as ContextMenuTrigger } from './ContextMenuTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue
new file mode 100644
index 0000000..36e4227
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  DialogRoot,
+  type DialogRootEmits,
+  type DialogRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<DialogRootProps>();
+const emits = defineEmits<DialogRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <DialogRoot v-bind="forwarded">
+    <slot></slot>
+  </DialogRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue
new file mode 100644
index 0000000..b168349
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { DialogClose, type DialogCloseProps } from 'radix-vue';
+
+const props = defineProps<DialogCloseProps>();
+</script>
+
+<template>
+  <DialogClose v-bind="props">
+    <slot></slot>
+  </DialogClose>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue
new file mode 100644
index 0000000..9a8d739
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue
@@ -0,0 +1,117 @@
+<script setup lang="ts">
+import type { ClassType } from '@vben-core/typings';
+
+import { computed, ref } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { X } from 'lucide-vue-next';
+import {
+  DialogClose,
+  DialogContent,
+  type DialogContentEmits,
+  type DialogContentProps,
+  DialogPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+import DialogOverlay from './DialogOverlay.vue';
+
+const props = withDefaults(
+  defineProps<
+    {
+      appendTo?: HTMLElement | string;
+      class?: ClassType;
+      closeClass?: ClassType;
+      modal?: boolean;
+      open?: boolean;
+      showClose?: boolean;
+      zIndex?: number;
+    } & DialogContentProps
+  >(),
+  { appendTo: 'body', showClose: true, zIndex: 1000 },
+);
+const emits = defineEmits<
+  { close: []; closed: []; opened: [] } & DialogContentEmits
+>();
+
+const delegatedProps = computed(() => {
+  const {
+    class: _,
+    modal: _modal,
+    open: _open,
+    showClose: __,
+    ...delegated
+  } = props;
+
+  return delegated;
+});
+
+function isAppendToBody() {
+  return (
+    props.appendTo === 'body' ||
+    props.appendTo === document.body ||
+    !props.appendTo
+  );
+}
+
+const position = computed(() => {
+  return isAppendToBody() ? 'fixed' : 'absolute';
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+
+const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
+function onAnimationEnd(event: AnimationEvent) {
+  // 鍙湁鍦� contentRef 鐨勫姩鐢荤粨鏉熸椂鎵嶈Е鍙� opened/closed 浜嬩欢
+  if (event.target === contentRef.value?.$el) {
+    if (props.open) {
+      emits('opened');
+    } else {
+      emits('closed');
+    }
+  }
+}
+defineExpose({
+  getContentRef: () => contentRef.value,
+});
+</script>
+
+<template>
+  <DialogPortal :to="appendTo">
+    <Transition name="fade">
+      <DialogOverlay
+        v-if="open && modal"
+        :style="{ zIndex, position }"
+        @click="() => emits('close')"
+      />
+    </Transition>
+    <DialogContent
+      ref="contentRef"
+      :style="{ zIndex, position }"
+      @animationend="onAnimationEnd"
+      v-bind="forwarded"
+      :class="
+        cn(
+          'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] w-full p-6 shadow-lg outline-none sm:rounded-xl',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+
+      <DialogClose
+        v-if="showClose"
+        :class="
+          cn(
+            'data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-3 top-3 h-6 w-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none',
+            props.closeClass,
+          )
+        "
+        @click="() => emits('close')"
+      >
+        <X class="h-4 w-4" />
+      </DialogClose>
+    </DialogContent>
+  </DialogPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue
new file mode 100644
index 0000000..5ca8694
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue
@@ -0,0 +1,30 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DialogDescription,
+  type DialogDescriptionProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DialogDescriptionProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <DialogDescription
+    v-bind="forwardedProps"
+    :class="cn('text-muted-foreground text-sm', props.class)"
+  >
+    <slot></slot>
+  </DialogDescription>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue
new file mode 100644
index 0000000..09460b9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{ class?: any }>();
+</script>
+
+<template>
+  <div
+    :class="
+      cn('flex flex-row flex-col-reverse justify-end gap-x-2', props.class)
+    "
+  >
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue
new file mode 100644
index 0000000..3632b2a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div
+    :class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)"
+  >
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue
new file mode 100644
index 0000000..f2142ac
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { inject } from 'vue';
+
+import { useScrollLock } from '@vben-core/composables';
+
+useScrollLock();
+const id = inject('DISMISSABLE_MODAL_ID');
+</script>
+<template>
+  <div :data-dismissable-modal="id" class="bg-overlay inset-0"></div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue
new file mode 100644
index 0000000..99ab7b1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue
@@ -0,0 +1,71 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { X } from 'lucide-vue-next';
+import {
+  DialogClose,
+  DialogContent,
+  type DialogContentEmits,
+  type DialogContentProps,
+  DialogOverlay,
+  DialogPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = withDefaults(
+  defineProps<{ class?: any; zIndex?: number } & DialogContentProps>(),
+  { zIndex: 1000 },
+);
+const emits = defineEmits<DialogContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DialogPortal>
+    <DialogOverlay
+      :style="{ zIndex }"
+      class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border absolute inset-0 grid place-items-center overflow-y-auto border bg-black/80"
+    >
+      <DialogContent
+        :class="
+          cn(
+            'border-border bg-background relative z-50 my-8 grid w-full max-w-lg gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
+            props.class,
+          )
+        "
+        :style="{ zIndex }"
+        v-bind="forwarded"
+        @pointer-down-outside="
+          (event) => {
+            const originalEvent = event.detail.originalEvent;
+            const target = originalEvent.target as HTMLElement;
+            if (
+              originalEvent.offsetX > target.clientWidth ||
+              originalEvent.offsetY > target.clientHeight
+            ) {
+              event.preventDefault();
+            }
+          }
+        "
+      >
+        <slot></slot>
+
+        <DialogClose
+          class="hover:bg-secondary absolute right-4 top-4 rounded-md p-0.5 transition-colors"
+        >
+          <X class="h-4 w-4" />
+          <span class="sr-only">Close</span>
+        </DialogClose>
+      </DialogContent>
+    </DialogOverlay>
+  </DialogPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue
new file mode 100644
index 0000000..1776c01
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue
@@ -0,0 +1,28 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DialogTitleProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <DialogTitle
+    v-bind="forwardedProps"
+    :class="
+      cn('text-lg font-semibold leading-none tracking-tight', props.class)
+    "
+  >
+    <slot></slot>
+  </DialogTitle>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue
new file mode 100644
index 0000000..8ae4c33
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { DialogTrigger, type DialogTriggerProps } from 'radix-vue';
+
+const props = defineProps<DialogTriggerProps>();
+</script>
+
+<template>
+  <DialogTrigger v-bind="props">
+    <slot></slot>
+  </DialogTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts
new file mode 100644
index 0000000..e924dd4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts
@@ -0,0 +1,9 @@
+export { default as Dialog } from './Dialog.vue';
+export { default as DialogClose } from './DialogClose.vue';
+export { default as DialogContent } from './DialogContent.vue';
+export { default as DialogDescription } from './DialogDescription.vue';
+export { default as DialogFooter } from './DialogFooter.vue';
+export { default as DialogHeader } from './DialogHeader.vue';
+export { default as DialogScrollContent } from './DialogScrollContent.vue';
+export { default as DialogTitle } from './DialogTitle.vue';
+export { default as DialogTrigger } from './DialogTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue
new file mode 100644
index 0000000..6a4328e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import {
+  DropdownMenuRoot,
+  type DropdownMenuRootEmits,
+  type DropdownMenuRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = withDefaults(defineProps<DropdownMenuRootProps>(), {
+  modal: false,
+});
+const emits = defineEmits<DropdownMenuRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <DropdownMenuRoot v-bind="forwarded">
+    <slot></slot>
+  </DropdownMenuRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
new file mode 100644
index 0000000..508218c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
@@ -0,0 +1,44 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Check } from 'lucide-vue-next';
+import {
+  DropdownMenuCheckboxItem,
+  type DropdownMenuCheckboxItemEmits,
+  type DropdownMenuCheckboxItemProps,
+  DropdownMenuItemIndicator,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DropdownMenuCheckboxItemProps>();
+const emits = defineEmits<DropdownMenuCheckboxItemEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DropdownMenuCheckboxItem
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <DropdownMenuItemIndicator>
+        <Check class="h-4 w-4" />
+      </DropdownMenuItemIndicator>
+    </span>
+    <slot></slot>
+  </DropdownMenuCheckboxItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue
new file mode 100644
index 0000000..9800a90
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DropdownMenuContent,
+  type DropdownMenuContentEmits,
+  type DropdownMenuContentProps,
+  DropdownMenuPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & DropdownMenuContentProps>(),
+  {
+    sideOffset: 4,
+  },
+);
+const emits = defineEmits<DropdownMenuContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DropdownMenuPortal>
+    <DropdownMenuContent
+      v-bind="forwarded"
+      :class="
+        cn(
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-[1000] min-w-32 overflow-hidden rounded-md border p-1 shadow-md',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+    </DropdownMenuContent>
+  </DropdownMenuPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue
new file mode 100644
index 0000000..f1e2305
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { DropdownMenuGroup, type DropdownMenuGroupProps } from 'radix-vue';
+
+const props = defineProps<DropdownMenuGroupProps>();
+</script>
+
+<template>
+  <DropdownMenuGroup v-bind="props">
+    <slot></slot>
+  </DropdownMenuGroup>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue
new file mode 100644
index 0000000..3aac667
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue
@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DropdownMenuItem,
+  type DropdownMenuItemProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<
+  { class?: any; inset?: boolean } & DropdownMenuItemProps
+>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <DropdownMenuItem
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        inset && 'pl-8',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </DropdownMenuItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue
new file mode 100644
index 0000000..decd5d2
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue
@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DropdownMenuLabel,
+  type DropdownMenuLabelProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<
+  { class?: any; inset?: boolean } & DropdownMenuLabelProps
+>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <DropdownMenuLabel
+    v-bind="forwardedProps"
+    :class="
+      cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)
+    "
+  >
+    <slot></slot>
+  </DropdownMenuLabel>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue
new file mode 100644
index 0000000..9c28706
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  DropdownMenuRadioGroup,
+  type DropdownMenuRadioGroupEmits,
+  type DropdownMenuRadioGroupProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<DropdownMenuRadioGroupProps>();
+const emits = defineEmits<DropdownMenuRadioGroupEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <DropdownMenuRadioGroup v-bind="forwarded">
+    <slot></slot>
+  </DropdownMenuRadioGroup>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue
new file mode 100644
index 0000000..54bcee3
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Circle } from 'lucide-vue-next';
+import {
+  DropdownMenuItemIndicator,
+  DropdownMenuRadioItem,
+  type DropdownMenuRadioItemEmits,
+  type DropdownMenuRadioItemProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DropdownMenuRadioItemProps>();
+
+const emits = defineEmits<DropdownMenuRadioItemEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DropdownMenuRadioItem
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
+      <DropdownMenuItemIndicator>
+        <Circle class="h-2 w-2 fill-current" />
+      </DropdownMenuItemIndicator>
+    </span>
+    <slot></slot>
+  </DropdownMenuRadioItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue
new file mode 100644
index 0000000..f18fc79
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DropdownMenuSeparator,
+  type DropdownMenuSeparatorProps,
+} from 'radix-vue';
+
+const props = defineProps<
+  {
+    class?: any;
+  } & DropdownMenuSeparatorProps
+>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <DropdownMenuSeparator
+    v-bind="delegatedProps"
+    :class="cn('bg-border -mx-1 my-1 h-px', props.class)"
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue
new file mode 100644
index 0000000..39f5963
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <span :class="cn('ml-auto text-xs tracking-widest opacity-60', props.class)">
+    <slot></slot>
+  </span>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue
new file mode 100644
index 0000000..088f87d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  DropdownMenuSub,
+  type DropdownMenuSubEmits,
+  type DropdownMenuSubProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<DropdownMenuSubProps>();
+const emits = defineEmits<DropdownMenuSubEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <DropdownMenuSub v-bind="forwarded">
+    <slot></slot>
+  </DropdownMenuSub>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue
new file mode 100644
index 0000000..a368921
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DropdownMenuSubContent,
+  type DropdownMenuSubContentEmits,
+  type DropdownMenuSubContentProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DropdownMenuSubContentProps>();
+const emits = defineEmits<DropdownMenuSubContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DropdownMenuSubContent
+    v-bind="forwarded"
+    :class="
+      cn(
+        'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-lg',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </DropdownMenuSubContent>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue
new file mode 100644
index 0000000..5efdbf6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronRight } from 'lucide-vue-next';
+import {
+  DropdownMenuSubTrigger,
+  type DropdownMenuSubTriggerProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DropdownMenuSubTriggerProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <DropdownMenuSubTrigger
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+    <ChevronRight class="ml-auto h-4 w-4" />
+  </DropdownMenuSubTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue
new file mode 100644
index 0000000..3cf6fa1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import {
+  DropdownMenuTrigger,
+  type DropdownMenuTriggerProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<DropdownMenuTriggerProps>();
+
+const forwardedProps = useForwardProps(props);
+</script>
+
+<template>
+  <DropdownMenuTrigger class="outline-none" v-bind="forwardedProps">
+    <slot></slot>
+  </DropdownMenuTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts
new file mode 100644
index 0000000..c99f319
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts
@@ -0,0 +1,16 @@
+export { default as DropdownMenu } from './DropdownMenu.vue';
+
+export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue';
+export { default as DropdownMenuContent } from './DropdownMenuContent.vue';
+export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue';
+export { default as DropdownMenuItem } from './DropdownMenuItem.vue';
+export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue';
+export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue';
+export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue';
+export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue';
+export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue';
+export { default as DropdownMenuSub } from './DropdownMenuSub.vue';
+export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue';
+export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue';
+export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue';
+export { DropdownMenuPortal } from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue
new file mode 100644
index 0000000..bd9ed85
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { Slot } from 'radix-vue';
+
+import { useFormField } from './useFormField';
+
+const { error, formDescriptionId, formItemId, formMessageId } = useFormField();
+</script>
+
+<template>
+  <Slot
+    :id="formItemId"
+    :aria-describedby="
+      !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`
+    "
+    :aria-invalid="!!error"
+  >
+    <slot></slot>
+  </Slot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue
new file mode 100644
index 0000000..871ba30
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue
@@ -0,0 +1,20 @@
+<script lang="ts" setup>
+import { cn } from '@vben-core/shared/utils';
+
+import { useFormField } from './useFormField';
+
+const props = defineProps<{
+  class?: any;
+}>();
+
+const { formDescriptionId } = useFormField();
+</script>
+
+<template>
+  <p
+    :id="formDescriptionId"
+    :class="cn('text-muted-foreground text-sm', props.class)"
+  >
+    <slot></slot>
+  </p>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue
new file mode 100644
index 0000000..165c992
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue
@@ -0,0 +1,20 @@
+<script lang="ts" setup>
+import { provide, useId } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { FORM_ITEM_INJECTION_KEY } from './injectionKeys';
+
+const props = defineProps<{
+  class?: any;
+}>();
+
+const id = useId() as string;
+provide(FORM_ITEM_INJECTION_KEY, id);
+</script>
+
+<template>
+  <div :class="cn(props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue
new file mode 100644
index 0000000..797d6e2
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue
@@ -0,0 +1,18 @@
+<script lang="ts" setup>
+import type { LabelProps } from 'radix-vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Label } from '../label';
+import { useFormField } from './useFormField';
+
+const props = defineProps<{ class?: any } & LabelProps>();
+
+const { formItemId } = useFormField();
+</script>
+
+<template>
+  <Label :class="cn(props.class)" :for="formItemId">
+    <slot></slot>
+  </Label>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue
new file mode 100644
index 0000000..fb8a8b9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue
@@ -0,0 +1,18 @@
+<script lang="ts" setup>
+import { toValue } from 'vue';
+
+import { ErrorMessage } from 'vee-validate';
+
+import { useFormField } from './useFormField';
+
+const { formMessageId, name } = useFormField();
+</script>
+
+<template>
+  <ErrorMessage
+    :id="formMessageId"
+    :name="toValue(name)"
+    as="p"
+    class="text-destructive text-[0.8rem]"
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts
new file mode 100644
index 0000000..3e8467b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts
@@ -0,0 +1,11 @@
+export { default as FormControl } from './FormControl.vue';
+export { default as FormDescription } from './FormDescription.vue';
+export { default as FormItem } from './FormItem.vue';
+export { default as FormLabel } from './FormLabel.vue';
+export { default as FormMessage } from './FormMessage.vue';
+export { FORM_ITEM_INJECTION_KEY } from './injectionKeys';
+export {
+  Field as FormField,
+  FieldArray as FormFieldArray,
+  Form,
+} from 'vee-validate';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts
new file mode 100644
index 0000000..3c86caa
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts
@@ -0,0 +1,4 @@
+import type { InjectionKey } from 'vue';
+
+// eslint-disable-next-line symbol-description
+export const FORM_ITEM_INJECTION_KEY = Symbol() as InjectionKey<string>;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts
new file mode 100644
index 0000000..dfb8d4c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts
@@ -0,0 +1,38 @@
+import { inject } from 'vue';
+
+import {
+  FieldContextKey,
+  useFieldError,
+  useIsFieldDirty,
+  useIsFieldTouched,
+  useIsFieldValid,
+} from 'vee-validate';
+
+import { FORM_ITEM_INJECTION_KEY } from './injectionKeys';
+
+export function useFormField() {
+  const fieldContext = inject(FieldContextKey);
+  const fieldItemContext = inject(FORM_ITEM_INJECTION_KEY);
+
+  if (!fieldContext)
+    throw new Error('useFormField should be used within <FormField>');
+
+  const { name } = fieldContext;
+  const id = fieldItemContext;
+
+  const fieldState = {
+    error: useFieldError(name),
+    isDirty: useIsFieldDirty(name),
+    isTouched: useIsFieldTouched(name),
+    valid: useIsFieldValid(name),
+  };
+
+  return {
+    formDescriptionId: `${id}-form-item-description`,
+    formItemId: `${id}-form-item`,
+    formMessageId: `${id}-form-item-message`,
+    id,
+    name,
+    ...fieldState,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue
new file mode 100644
index 0000000..6c4ac04
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  HoverCardRoot,
+  type HoverCardRootEmits,
+  type HoverCardRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<HoverCardRootProps>();
+const emits = defineEmits<HoverCardRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <HoverCardRoot v-bind="forwarded">
+    <slot></slot>
+  </HoverCardRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue
new file mode 100644
index 0000000..444a182
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue
@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  HoverCardContent,
+  type HoverCardContentProps,
+  HoverCardPortal,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & HoverCardContentProps>(),
+  {
+    sideOffset: 4,
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <HoverCardPortal>
+    <HoverCardContent
+      v-bind="forwardedProps"
+      :class="
+        cn(
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border z-[1000] w-64 rounded-md border p-4 shadow-md outline-none',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+    </HoverCardContent>
+  </HoverCardPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue
new file mode 100644
index 0000000..fe6893a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { HoverCardTrigger, type HoverCardTriggerProps } from 'radix-vue';
+
+const props = defineProps<HoverCardTriggerProps>();
+</script>
+
+<template>
+  <HoverCardTrigger v-bind="props">
+    <slot></slot>
+  </HoverCardTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts
new file mode 100644
index 0000000..dd4a1ef
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts
@@ -0,0 +1,3 @@
+export { default as HoverCard } from './HoverCard.vue';
+export { default as HoverCardContent } from './HoverCardContent.vue';
+export { default as HoverCardTrigger } from './HoverCardTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts
new file mode 100644
index 0000000..2711f94
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts
@@ -0,0 +1,28 @@
+export * from './accordion';
+export * from './avatar';
+export * from './badge';
+export * from './breadcrumb';
+export * from './button';
+export * from './card';
+export * from './checkbox';
+export * from './dialog';
+export * from './dropdown-menu';
+export * from './form';
+export * from './hover-card';
+export * from './input';
+export * from './label';
+export * from './number-field';
+export * from './pagination';
+export * from './pin-input';
+export * from './popover';
+export * from './radio-group';
+export * from './scroll-area';
+export * from './select';
+export * from './separator';
+export * from './sheet';
+export * from './switch';
+export * from './tabs';
+export * from './textarea';
+export * from './toggle';
+export * from './toggle-group';
+export * from './tooltip';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue
new file mode 100644
index 0000000..68b90db
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { useVModel } from '@vueuse/core';
+
+const props = defineProps<{
+  class?: any;
+  defaultValue?: number | string;
+  modelValue?: number | string;
+}>();
+
+const emits = defineEmits<{
+  (e: 'update:modelValue', payload: number | string): void;
+}>();
+
+const modelValue = useVModel(props, 'modelValue', emits, {
+  defaultValue: props.defaultValue,
+  passive: true,
+});
+</script>
+
+<template>
+  <input
+    v-model="modelValue"
+    :class="
+      cn(
+        'border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+        props.class,
+      )
+    "
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts
new file mode 100644
index 0000000..c5248c5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts
@@ -0,0 +1 @@
+export { default as Input } from './Input.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue
new file mode 100644
index 0000000..a416935
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Label, type LabelProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & LabelProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <Label
+    v-bind="delegatedProps"
+    :class="
+      cn(
+        'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </Label>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts
new file mode 100644
index 0000000..c98e59f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts
@@ -0,0 +1 @@
+export { default as Label } from './Label.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue
new file mode 100644
index 0000000..4d01c6a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import type { NumberFieldRootEmits, NumberFieldRootProps } from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { NumberFieldRoot, useForwardPropsEmits } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & NumberFieldRootProps>();
+const emits = defineEmits<NumberFieldRootEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <NumberFieldRoot v-bind="forwarded" :class="cn('grid gap-1.5', props.class)">
+    <slot></slot>
+  </NumberFieldRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue
new file mode 100644
index 0000000..f6d1b92
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue
@@ -0,0 +1,20 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{
+  class?: any;
+}>();
+</script>
+
+<template>
+  <div
+    :class="
+      cn(
+        'relative [&>[data-slot=input]]:has-[[data-slot=decrement]]:pl-5 [&>[data-slot=input]]:has-[[data-slot=increment]]:pr-5',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue
new file mode 100644
index 0000000..9f40db9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import type { NumberFieldDecrementProps } from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Minus } from 'lucide-vue-next';
+import { NumberFieldDecrement, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & NumberFieldDecrementProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <NumberFieldDecrement
+    data-slot="decrement"
+    v-bind="forwarded"
+    :class="
+      cn(
+        'absolute left-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',
+        props.class,
+      )
+    "
+  >
+    <slot>
+      <Minus class="h-4 w-4" />
+    </slot>
+  </NumberFieldDecrement>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue
new file mode 100644
index 0000000..bfdb0bf
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import type { NumberFieldIncrementProps } from 'radix-vue';
+
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Plus } from 'lucide-vue-next';
+import { NumberFieldIncrement, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & NumberFieldIncrementProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <NumberFieldIncrement
+    data-slot="increment"
+    v-bind="forwarded"
+    :class="
+      cn(
+        'absolute right-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',
+        props.class,
+      )
+    "
+  >
+    <slot>
+      <Plus class="h-4 w-4" />
+    </slot>
+  </NumberFieldIncrement>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue
new file mode 100644
index 0000000..48e621e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { NumberFieldInput } from 'radix-vue';
+</script>
+
+<template>
+  <NumberFieldInput
+    :class="
+      cn(
+        'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex h-9 w-full rounded-md border bg-transparent py-1 text-center text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+      )
+    "
+    data-slot="input"
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts
new file mode 100644
index 0000000..bcdde78
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts
@@ -0,0 +1,5 @@
+export { default as NumberField } from './NumberField.vue';
+export { default as NumberFieldContent } from './NumberFieldContent.vue';
+export { default as NumberFieldDecrement } from './NumberFieldDecrement.vue';
+export { default as NumberFieldIncrement } from './NumberFieldIncrement.vue';
+export { default as NumberFieldInput } from './NumberFieldInput.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue
new file mode 100644
index 0000000..a05beb8
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue
@@ -0,0 +1,27 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { MoreHorizontal } from 'lucide-vue-next';
+import { PaginationEllipsis, type PaginationEllipsisProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & PaginationEllipsisProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <PaginationEllipsis
+    v-bind="delegatedProps"
+    :class="cn('flex size-8 items-center justify-center', props.class)"
+  >
+    <slot>
+      <MoreHorizontal class="size-4" />
+    </slot>
+  </PaginationEllipsis>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue
new file mode 100644
index 0000000..ea5ca42
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronsLeft } from 'lucide-vue-next';
+import { PaginationFirst, type PaginationFirstProps } from 'radix-vue';
+
+import { Button } from '../button';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & PaginationFirstProps>(),
+  {
+    asChild: true,
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <PaginationFirst v-bind="delegatedProps">
+    <Button :class="cn('size-8 p-0', props.class)" variant="outline">
+      <slot>
+        <ChevronsLeft class="size-4" />
+      </slot>
+    </Button>
+  </PaginationFirst>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue
new file mode 100644
index 0000000..d6b24fd
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronsRight } from 'lucide-vue-next';
+import { PaginationLast, type PaginationLastProps } from 'radix-vue';
+
+import { Button } from '../button';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & PaginationLastProps>(),
+  {
+    asChild: true,
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <PaginationLast v-bind="delegatedProps">
+    <Button :class="cn('size-8 p-0', props.class)" variant="outline">
+      <slot>
+        <ChevronsRight class="size-4" />
+      </slot>
+    </Button>
+  </PaginationLast>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue
new file mode 100644
index 0000000..cc67596
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronRight } from 'lucide-vue-next';
+import { PaginationNext, type PaginationNextProps } from 'radix-vue';
+
+import { Button } from '../button';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & PaginationNextProps>(),
+  {
+    asChild: true,
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <PaginationNext v-bind="delegatedProps">
+    <Button :class="cn('size-8 p-0', props.class)" variant="outline">
+      <slot>
+        <ChevronRight class="size-4" />
+      </slot>
+    </Button>
+  </PaginationNext>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue
new file mode 100644
index 0000000..4996e68
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronLeft } from 'lucide-vue-next';
+import { PaginationPrev, type PaginationPrevProps } from 'radix-vue';
+
+import { Button } from '../button';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & PaginationPrevProps>(),
+  {
+    asChild: true,
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <PaginationPrev v-bind="delegatedProps">
+    <Button :class="cn('size-8 p-0', props.class)" variant="outline">
+      <slot>
+        <ChevronLeft class="size-4" />
+      </slot>
+    </Button>
+  </PaginationPrev>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts
new file mode 100644
index 0000000..ce93dc4
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts
@@ -0,0 +1,10 @@
+export { default as PaginationEllipsis } from './PaginationEllipsis.vue';
+export { default as PaginationFirst } from './PaginationFirst.vue';
+export { default as PaginationLast } from './PaginationLast.vue';
+export { default as PaginationNext } from './PaginationNext.vue';
+export { default as PaginationPrev } from './PaginationPrev.vue';
+export {
+  PaginationList,
+  PaginationListItem,
+  PaginationRoot as Pagination,
+} from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue
new file mode 100644
index 0000000..298753b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue
@@ -0,0 +1,31 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  PinInputRoot,
+  type PinInputRootEmits,
+  type PinInputRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & PinInputRootProps>();
+const emits = defineEmits<PinInputRootEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <PinInputRoot
+    v-bind="forwarded"
+    :class="cn('flex items-center gap-2', props.class)"
+  >
+    <slot></slot>
+  </PinInputRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue
new file mode 100644
index 0000000..393273d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue
@@ -0,0 +1,23 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & PrimitiveProps>();
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+  return delegated;
+});
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <Primitive
+    v-bind="forwardedProps"
+    :class="cn('flex items-center', props.class)"
+  >
+    <slot></slot>
+  </Primitive>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue
new file mode 100644
index 0000000..6971f25
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  PinInputInput,
+  type PinInputInputProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & PinInputInputProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <PinInputInput
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'border-input bg-background relative flex h-10 w-10 items-center justify-center border-y border-r text-center text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md focus:relative focus:z-10 focus:outline-none focus:ring-2',
+        props.class,
+      )
+    "
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue
new file mode 100644
index 0000000..d6b867a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { Dot } from 'lucide-vue-next';
+import { Primitive, type PrimitiveProps, useForwardProps } from 'radix-vue';
+
+const props = defineProps<PrimitiveProps>();
+const forwardedProps = useForwardProps(props);
+</script>
+
+<template>
+  <Primitive v-bind="forwardedProps">
+    <slot>
+      <Dot />
+    </slot>
+  </Primitive>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts
new file mode 100644
index 0000000..585c0d6
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts
@@ -0,0 +1,4 @@
+export { default as PinInput } from './PinInput.vue';
+export { default as PinInputGroup } from './PinInputGroup.vue';
+export { default as PinInputInput } from './PinInputInput.vue';
+export { default as PinInputSeparator } from './PinInputSeparator.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue
new file mode 100644
index 0000000..c4ae695
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import type { PopoverRootEmits, PopoverRootProps } from 'radix-vue';
+
+import { PopoverRoot, useForwardPropsEmits } from 'radix-vue';
+
+const props = defineProps<PopoverRootProps>();
+const emits = defineEmits<PopoverRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <PopoverRoot v-bind="forwarded">
+    <slot></slot>
+  </PopoverRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue
new file mode 100644
index 0000000..9d1799b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue
@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  PopoverContent,
+  type PopoverContentEmits,
+  type PopoverContentProps,
+  PopoverPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(
+  defineProps<{ class?: any } & PopoverContentProps>(),
+  {
+    align: 'center',
+    sideOffset: 4,
+  },
+);
+const emits = defineEmits<PopoverContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <PopoverPortal>
+    <PopoverContent
+      v-bind="{ ...forwarded, ...$attrs }"
+      :class="
+        cn(
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border w-72 rounded-md border p-4 shadow-md outline-none',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+    </PopoverContent>
+  </PopoverPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue
new file mode 100644
index 0000000..ca39507
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { PopoverTrigger, type PopoverTriggerProps } from 'radix-vue';
+
+const props = defineProps<PopoverTriggerProps>();
+</script>
+
+<template>
+  <PopoverTrigger v-bind="props">
+    <slot></slot>
+  </PopoverTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts
new file mode 100644
index 0000000..dbe007b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts
@@ -0,0 +1,4 @@
+export { default as Popover } from './Popover.vue';
+export { default as PopoverContent } from './PopoverContent.vue';
+export { default as PopoverTrigger } from './PopoverTrigger.vue';
+export { PopoverAnchor } from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue
new file mode 100644
index 0000000..35c4870
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  RadioGroupRoot,
+  type RadioGroupRootEmits,
+  type RadioGroupRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & RadioGroupRootProps>();
+const emits = defineEmits<RadioGroupRootEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <RadioGroupRoot :class="cn('grid gap-2', props.class)" v-bind="forwarded">
+    <slot></slot>
+  </RadioGroupRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue
new file mode 100644
index 0000000..2346813
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue
@@ -0,0 +1,39 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Circle } from 'lucide-vue-next';
+import {
+  RadioGroupIndicator,
+  RadioGroupItem,
+  type RadioGroupItemProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & RadioGroupItemProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <RadioGroupItem
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'border-primary text-primary focus-visible:ring-ring aspect-square h-4 w-4 rounded-full border shadow focus:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <RadioGroupIndicator class="flex items-center justify-center">
+      <Circle class="h-2.5 w-2.5 fill-current text-current" />
+    </RadioGroupIndicator>
+  </RadioGroupItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts
new file mode 100644
index 0000000..7e2c65f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts
@@ -0,0 +1,2 @@
+export { default as RadioGroup } from './RadioGroup.vue';
+export { default as RadioGroupItem } from './RadioGroupItem.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue
new file mode 100644
index 0000000..94dfcad
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue
@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ScrollAreaCorner,
+  ScrollAreaRoot,
+  type ScrollAreaRootProps,
+  ScrollAreaViewport,
+} from 'radix-vue';
+
+import ScrollBar from './ScrollBar.vue';
+
+const props = withDefaults(
+  defineProps<
+    {
+      class?: any;
+      onScroll?: (event: Event) => void;
+      viewportProps?: { onScroll: (event: Event) => void };
+    } & ScrollAreaRootProps
+  >(),
+  {
+    onScroll: () => {},
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+  return delegated;
+});
+</script>
+
+<template>
+  <ScrollAreaRoot
+    v-bind="delegatedProps"
+    :class="cn('relative overflow-hidden', props.class)"
+  >
+    <ScrollAreaViewport
+      as-child
+      class="h-full w-full rounded-[inherit]"
+      @scroll="onScroll"
+    >
+      <slot></slot>
+    </ScrollAreaViewport>
+    <ScrollBar />
+    <ScrollAreaCorner />
+  </ScrollAreaRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue
new file mode 100644
index 0000000..f79ff24
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue
@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ScrollAreaScrollbar,
+  type ScrollAreaScrollbarProps,
+  ScrollAreaThumb,
+} from 'radix-vue';
+
+const props = withDefaults(
+  defineProps<{ class?: any } & ScrollAreaScrollbarProps>(),
+  {
+    orientation: 'vertical',
+  },
+);
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <ScrollAreaScrollbar
+    v-bind="delegatedProps"
+    :class="
+      cn(
+        'flex touch-none select-none transition-colors',
+        orientation === 'vertical' &&
+          'h-full w-2.5 border-l border-l-transparent p-px',
+        orientation === 'horizontal' &&
+          'h-2.5 flex-col border-t border-t-transparent p-px',
+        props.class,
+      )
+    "
+  >
+    <ScrollAreaThumb class="bg-border relative flex-1 rounded-full" />
+  </ScrollAreaScrollbar>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts
new file mode 100644
index 0000000..d6541f3
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts
@@ -0,0 +1,2 @@
+export { default as ScrollArea } from './ScrollArea.vue';
+export { default as ScrollBar } from './ScrollBar.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue
new file mode 100644
index 0000000..f4aebbf
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import type { SelectRootEmits, SelectRootProps } from 'radix-vue';
+
+import { SelectRoot, useForwardPropsEmits } from 'radix-vue';
+
+const props = defineProps<SelectRootProps>();
+const emits = defineEmits<SelectRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <SelectRoot v-bind="forwarded">
+    <slot></slot>
+  </SelectRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue
new file mode 100644
index 0000000..568a280
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue
@@ -0,0 +1,67 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  SelectContent,
+  type SelectContentEmits,
+  type SelectContentProps,
+  SelectPortal,
+  SelectViewport,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+import SelectScrollDownButton from './SelectScrollDownButton.vue';
+import SelectScrollUpButton from './SelectScrollUpButton.vue';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(
+  defineProps<{ class?: any } & SelectContentProps>(),
+  {
+    position: 'popper',
+  },
+);
+const emits = defineEmits<SelectContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <SelectPortal>
+    <SelectContent
+      v-bind="{ ...forwarded, ...$attrs }"
+      :class="
+        cn(
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border relative z-[1000] max-h-96 min-w-32 overflow-hidden rounded-md border shadow-md',
+          position === 'popper' &&
+            'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
+          props.class,
+        )
+      "
+    >
+      <SelectScrollUpButton />
+      <SelectViewport
+        :class="
+          cn(
+            'p-1',
+            position === 'popper' &&
+              'h-[--radix-select-trigger-height] w-full min-w-[--radix-select-trigger-width]',
+          )
+        "
+      >
+        <slot></slot>
+      </SelectViewport>
+      <SelectScrollDownButton />
+    </SelectContent>
+  </SelectPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue
new file mode 100644
index 0000000..df2296c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue
@@ -0,0 +1,21 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { SelectGroup, type SelectGroupProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectGroupProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <SelectGroup :class="cn('w-full p-1', props.class)" v-bind="delegatedProps">
+    <slot></slot>
+  </SelectGroup>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue
new file mode 100644
index 0000000..ea96e10
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue
@@ -0,0 +1,46 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Check } from 'lucide-vue-next';
+import {
+  SelectItem,
+  SelectItemIndicator,
+  type SelectItemProps,
+  SelectItemText,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectItemProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <SelectItem
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
+      <SelectItemIndicator>
+        <Check class="h-4 w-4" />
+      </SelectItemIndicator>
+    </span>
+
+    <SelectItemText>
+      <slot></slot>
+    </SelectItemText>
+  </SelectItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue
new file mode 100644
index 0000000..ec6ca07
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { SelectItemText, type SelectItemTextProps } from 'radix-vue';
+
+const props = defineProps<SelectItemTextProps>();
+</script>
+
+<template>
+  <SelectItemText v-bind="props">
+    <slot></slot>
+  </SelectItemText>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue
new file mode 100644
index 0000000..5984268
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue
@@ -0,0 +1,13 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { SelectLabel, type SelectLabelProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectLabelProps>();
+</script>
+
+<template>
+  <SelectLabel :class="cn('px-2 py-1.5 text-sm font-semibold', props.class)">
+    <slot></slot>
+  </SelectLabel>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue
new file mode 100644
index 0000000..9aa28b0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue
@@ -0,0 +1,35 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronDown } from 'lucide-vue-next';
+import {
+  SelectScrollDownButton,
+  type SelectScrollDownButtonProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectScrollDownButtonProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <SelectScrollDownButton
+    v-bind="forwardedProps"
+    :class="
+      cn('flex cursor-default items-center justify-center py-1', props.class)
+    "
+  >
+    <slot>
+      <ChevronDown class="h-4 w-4" />
+    </slot>
+  </SelectScrollDownButton>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue
new file mode 100644
index 0000000..c1b23bb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue
@@ -0,0 +1,35 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronUp } from 'lucide-vue-next';
+import {
+  SelectScrollUpButton,
+  type SelectScrollUpButtonProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectScrollUpButtonProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <SelectScrollUpButton
+    v-bind="forwardedProps"
+    :class="
+      cn('flex cursor-default items-center justify-center py-1', props.class)
+    "
+  >
+    <slot>
+      <ChevronUp class="h-4 w-4" />
+    </slot>
+  </SelectScrollUpButton>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue
new file mode 100644
index 0000000..f93a7d1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue
@@ -0,0 +1,22 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { SelectSeparator, type SelectSeparatorProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectSeparatorProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <SelectSeparator
+    v-bind="delegatedProps"
+    :class="cn('bg-muted -mx-1 my-1 h-px', props.class)"
+  />
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue
new file mode 100644
index 0000000..9cb34f0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue
@@ -0,0 +1,40 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { ChevronDown } from 'lucide-vue-next';
+import {
+  SelectIcon,
+  SelectTrigger,
+  type SelectTriggerProps,
+  useForwardProps,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SelectTriggerProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <SelectTrigger
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'border-input ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+    <SelectIcon as-child>
+      <ChevronDown class="h-4 w-4 opacity-50" />
+    </SelectIcon>
+  </SelectTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue
new file mode 100644
index 0000000..197579a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { SelectValue, type SelectValueProps } from 'radix-vue';
+
+const props = defineProps<SelectValueProps>();
+</script>
+
+<template>
+  <SelectValue v-bind="props">
+    <slot></slot>
+  </SelectValue>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts
new file mode 100644
index 0000000..d7fdf0d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts
@@ -0,0 +1,11 @@
+export { default as Select } from './Select.vue';
+export { default as SelectContent } from './SelectContent.vue';
+export { default as SelectGroup } from './SelectGroup.vue';
+export { default as SelectItem } from './SelectItem.vue';
+export { default as SelectItemText } from './SelectItemText.vue';
+export { default as SelectLabel } from './SelectLabel.vue';
+export { default as SelectScrollDownButton } from './SelectScrollDownButton.vue';
+export { default as SelectScrollUpButton } from './SelectScrollUpButton.vue';
+export { default as SelectSeparator } from './SelectSeparator.vue';
+export { default as SelectTrigger } from './SelectTrigger.vue';
+export { default as SelectValue } from './SelectValue.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue
new file mode 100644
index 0000000..cf6ca4a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue
@@ -0,0 +1,42 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { Separator, type SeparatorProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any; label?: string } & SeparatorProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <Separator
+    v-bind="delegatedProps"
+    :class="
+      cn(
+        'bg-border relative shrink-0',
+        props.orientation === 'vertical' ? 'h-full w-px' : 'h-px w-full',
+        props.class,
+      )
+    "
+  >
+    <span
+      v-if="props.label"
+      :class="
+        cn(
+          'text-muted-foreground bg-background absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center text-xs',
+          props.orientation === 'vertical'
+            ? 'w-[1px] px-1 py-2'
+            : 'h-[1px] px-2 py-1',
+        )
+      "
+    >
+      {{ props.label }}
+    </span>
+  </Separator>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts
new file mode 100644
index 0000000..3cb07b0
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts
@@ -0,0 +1 @@
+export { default as Separator } from './Separator.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue
new file mode 100644
index 0000000..36e4227
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  DialogRoot,
+  type DialogRootEmits,
+  type DialogRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<DialogRootProps>();
+const emits = defineEmits<DialogRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <DialogRoot v-bind="forwarded">
+    <slot></slot>
+  </DialogRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue
new file mode 100644
index 0000000..b168349
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { DialogClose, type DialogCloseProps } from 'radix-vue';
+
+const props = defineProps<DialogCloseProps>();
+</script>
+
+<template>
+  <DialogClose v-bind="props">
+    <slot></slot>
+  </DialogClose>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue
new file mode 100644
index 0000000..5b09675
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue
@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  DialogContent,
+  type DialogContentEmits,
+  type DialogContentProps,
+  DialogPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+import { type SheetVariants, sheetVariants } from './sheet';
+import SheetOverlay from './SheetOverlay.vue';
+
+interface SheetContentProps extends DialogContentProps {
+  appendTo?: HTMLElement | string;
+  class?: any;
+  modal?: boolean;
+  open?: boolean;
+  side?: SheetVariants['side'];
+  zIndex?: number;
+}
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(defineProps<SheetContentProps>(), {
+  appendTo: 'body',
+  zIndex: 1000,
+});
+
+const emits = defineEmits<DialogContentEmits>();
+
+const delegatedProps = computed(() => {
+  const {
+    class: _,
+    modal: _modal,
+    open: _open,
+    side: _side,
+    ...delegated
+  } = props;
+
+  return delegated;
+});
+
+function isAppendToBody() {
+  return (
+    props.appendTo === 'body' ||
+    props.appendTo === document.body ||
+    !props.appendTo
+  );
+}
+
+const position = computed(() => {
+  return isAppendToBody() ? 'fixed' : 'absolute';
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <DialogPortal :to="appendTo">
+    <Transition name="fade">
+      <SheetOverlay v-if="open && modal" :style="{ zIndex, position }" />
+    </Transition>
+    <DialogContent
+      :class="cn(sheetVariants({ side }), props.class)"
+      :style="{ zIndex, position }"
+      v-bind="{ ...forwarded, ...$attrs }"
+    >
+      <slot></slot>
+
+      <!-- <DialogClose
+        class="data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
+      >
+        <Cross2Icon class="h-5 w-" />
+      </DialogClose> -->
+    </DialogContent>
+  </DialogPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue
new file mode 100644
index 0000000..2e90656
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { DialogDescription, type DialogDescriptionProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DialogDescriptionProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <DialogDescription
+    :class="cn('text-muted-foreground text-sm', props.class)"
+    v-bind="delegatedProps"
+  >
+    <slot></slot>
+  </DialogDescription>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue
new file mode 100644
index 0000000..09460b9
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{ class?: any }>();
+</script>
+
+<template>
+  <div
+    :class="
+      cn('flex flex-row flex-col-reverse justify-end gap-x-2', props.class)
+    "
+  >
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue
new file mode 100644
index 0000000..c6cc25c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+const props = defineProps<{ class?: any }>();
+</script>
+
+<template>
+  <div :class="cn('flex flex-col text-center sm:text-left', props.class)">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue
new file mode 100644
index 0000000..c9e9686
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { inject } from 'vue';
+
+import { useScrollLock } from '@vben-core/composables';
+
+useScrollLock();
+const id = inject('DISMISSABLE_DRAWER_ID');
+</script>
+<template>
+  <div :data-dismissable-drawer="id" class="bg-overlay inset-0"></div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue
new file mode 100644
index 0000000..95c8eac
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { DialogTitle, type DialogTitleProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & DialogTitleProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <DialogTitle
+    :class="cn('text-foreground font-medium', props.class)"
+    v-bind="delegatedProps"
+  >
+    <slot></slot>
+  </DialogTitle>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue
new file mode 100644
index 0000000..8ae4c33
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { DialogTrigger, type DialogTriggerProps } from 'radix-vue';
+
+const props = defineProps<DialogTriggerProps>();
+</script>
+
+<template>
+  <DialogTrigger v-bind="props">
+    <slot></slot>
+  </DialogTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts
new file mode 100644
index 0000000..fd3095a
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts
@@ -0,0 +1,10 @@
+export * from './sheet';
+export { default as Sheet } from './Sheet.vue';
+export { default as SheetClose } from './SheetClose.vue';
+export { default as SheetContent } from './SheetContent.vue';
+export { default as SheetDescription } from './SheetDescription.vue';
+export { default as SheetFooter } from './SheetFooter.vue';
+export { default as SheetHeader } from './SheetHeader.vue';
+export { default as SheetTitle } from './SheetTitle.vue';
+
+export { default as SheetTrigger } from './SheetTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts
new file mode 100644
index 0000000..5fd114f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts
@@ -0,0 +1,22 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+
+export const sheetVariants = cva(
+  'bg-background shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 border-border',
+  {
+    defaultVariants: {
+      side: 'right',
+    },
+    variants: {
+      side: {
+        bottom:
+          'inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
+        left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left ',
+        right:
+          'inset-y-0 right-0 w-3/4 border-l  data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right',
+        top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
+      },
+    },
+  },
+);
+
+export type SheetVariants = VariantProps<typeof sheetVariants>;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue
new file mode 100644
index 0000000..6a28899
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  SwitchRoot,
+  type SwitchRootEmits,
+  type SwitchRootProps,
+  SwitchThumb,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<{ class?: any } & SwitchRootProps>();
+
+const emits = defineEmits<SwitchRootEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <SwitchRoot
+    v-bind="forwarded"
+    :class="
+      cn(
+        'focus-visible:ring-ring focus-visible:ring-offset-background data-[state=checked]:bg-primary data-[state=unchecked]:bg-input peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
+        props.class,
+      )
+    "
+  >
+    <SwitchThumb
+      :class="
+        cn(
+          'bg-background pointer-events-none block h-4 w-4 rounded-full shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',
+        )
+      "
+    />
+  </SwitchRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts
new file mode 100644
index 0000000..924a2d1
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts
@@ -0,0 +1 @@
+export { default as Switch } from './Switch.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue
new file mode 100644
index 0000000..b21d780
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+import type { TabsRootEmits, TabsRootProps } from 'radix-vue';
+
+import { TabsRoot, useForwardPropsEmits } from 'radix-vue';
+
+const props = defineProps<TabsRootProps>();
+const emits = defineEmits<TabsRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <TabsRoot v-bind="forwarded">
+    <slot></slot>
+  </TabsRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue
new file mode 100644
index 0000000..0e3d9c5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { TabsContent, type TabsContentProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & TabsContentProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <TabsContent
+    :class="
+      cn(
+        'ring-offset-background focus-visible:ring-ring mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
+        props.class,
+      )
+    "
+    v-bind="delegatedProps"
+  >
+    <slot></slot>
+  </TabsContent>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue
new file mode 100644
index 0000000..756df6d
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue
@@ -0,0 +1,29 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { TabsList, type TabsListProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & TabsListProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+</script>
+
+<template>
+  <TabsList
+    v-bind="delegatedProps"
+    :class="
+      cn(
+        'bg-muted text-muted-foreground inline-flex h-9 items-center justify-center rounded-lg p-1',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </TabsList>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue
new file mode 100644
index 0000000..1bec624
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue
@@ -0,0 +1,31 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import { TabsTrigger, type TabsTriggerProps, useForwardProps } from 'radix-vue';
+
+const props = defineProps<{ class?: any } & TabsTriggerProps>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <TabsTrigger
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        'ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow',
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </TabsTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts
new file mode 100644
index 0000000..571950c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts
@@ -0,0 +1,5 @@
+export { default as Tabs } from './Tabs.vue';
+export { default as TabsContent } from './TabsContent.vue';
+export { default as TabsList } from './TabsList.vue';
+export { default as TabsTrigger } from './TabsTrigger.vue';
+export { TabsIndicator } from 'radix-vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue
new file mode 100644
index 0000000..2425167
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue
@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import { cn } from '@vben-core/shared/utils';
+
+import { useVModel } from '@vueuse/core';
+
+const props = defineProps<{
+  class?: any;
+  defaultValue?: number | string;
+  modelValue?: number | string;
+}>();
+
+const emits = defineEmits<{
+  (e: 'update:modelValue', payload: number | string): void;
+}>();
+
+const modelValue = useVModel(props, 'modelValue', emits, {
+  defaultValue: props.defaultValue,
+  passive: true,
+});
+</script>
+
+<template>
+  <textarea
+    v-model="modelValue"
+    :class="
+      cn(
+        'border-input placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[60px] w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
+        props.class,
+      )
+    "
+  ></textarea>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts
new file mode 100644
index 0000000..e2d4773
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts
@@ -0,0 +1 @@
+export { default as Textarea } from './Textarea.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue
new file mode 100644
index 0000000..66b3562
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue
@@ -0,0 +1,48 @@
+<script setup lang="ts">
+import type { VariantProps } from 'class-variance-authority';
+
+import type { toggleVariants } from '../toggle';
+
+import { computed, provide } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ToggleGroupRoot,
+  type ToggleGroupRootEmits,
+  type ToggleGroupRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+type ToggleGroupVariants = VariantProps<typeof toggleVariants>;
+
+const props = defineProps<
+  {
+    class?: any;
+    size?: ToggleGroupVariants['size'];
+    variant?: ToggleGroupVariants['variant'];
+  } & ToggleGroupRootProps
+>();
+const emits = defineEmits<ToggleGroupRootEmits>();
+
+provide('toggleGroup', {
+  size: props.size,
+  variant: props.variant,
+});
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <ToggleGroupRoot
+    v-bind="forwarded"
+    :class="cn('flex items-center justify-center gap-1', props.class)"
+  >
+    <slot></slot>
+  </ToggleGroupRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue
new file mode 100644
index 0000000..abf918f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import type { VariantProps } from 'class-variance-authority';
+
+import { computed, inject } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  ToggleGroupItem,
+  type ToggleGroupItemProps,
+  useForwardProps,
+} from 'radix-vue';
+
+import { toggleVariants } from '../toggle';
+
+type ToggleGroupVariants = VariantProps<typeof toggleVariants>;
+
+const props = defineProps<
+  {
+    class?: any;
+    size?: ToggleGroupVariants['size'];
+    variant?: ToggleGroupVariants['variant'];
+  } & ToggleGroupItemProps
+>();
+
+const context = inject<ToggleGroupVariants>('toggleGroup');
+
+const delegatedProps = computed(() => {
+  const { class: _, size: _size, variant: _variant, ...delegated } = props;
+  return delegated;
+});
+
+const forwardedProps = useForwardProps(delegatedProps);
+</script>
+
+<template>
+  <ToggleGroupItem
+    v-bind="forwardedProps"
+    :class="
+      cn(
+        toggleVariants({
+          variant: context?.variant || variant,
+          size: context?.size || size,
+        }),
+        props.class,
+      )
+    "
+  >
+    <slot></slot>
+  </ToggleGroupItem>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts
new file mode 100644
index 0000000..ac3e34b
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts
@@ -0,0 +1,2 @@
+export { default as ToggleGroup } from './ToggleGroup.vue';
+export { default as ToggleGroupItem } from './ToggleGroupItem.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue
new file mode 100644
index 0000000..4517b9c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue
@@ -0,0 +1,48 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  Toggle,
+  type ToggleEmits,
+  type ToggleProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+import { type ToggleVariants, toggleVariants } from './toggle';
+
+const props = withDefaults(
+  defineProps<
+    {
+      class?: any;
+      size?: ToggleVariants['size'];
+      variant?: ToggleVariants['variant'];
+    } & ToggleProps
+  >(),
+  {
+    disabled: false,
+    size: 'default',
+    variant: 'default',
+  },
+);
+
+const emits = defineEmits<ToggleEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, size: _size, variant: _variant, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <Toggle
+    v-bind="forwarded"
+    :class="cn(toggleVariants({ variant, size }), props.class)"
+  >
+    <slot></slot>
+  </Toggle>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts
new file mode 100644
index 0000000..ecc1e3f
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts
@@ -0,0 +1,2 @@
+export * from './toggle';
+export { default as Toggle } from './Toggle.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts
new file mode 100644
index 0000000..150eaa5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts
@@ -0,0 +1,25 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+
+export const toggleVariants = cva(
+  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground',
+  {
+    defaultVariants: {
+      size: 'default',
+      variant: 'default',
+    },
+    variants: {
+      size: {
+        default: 'h-9 px-3',
+        lg: 'h-10 px-3',
+        sm: 'h-8 px-2',
+      },
+      variant: {
+        default: 'bg-transparent',
+        outline:
+          'border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground',
+      },
+    },
+  },
+);
+
+export type ToggleVariants = VariantProps<typeof toggleVariants>;
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue
new file mode 100644
index 0000000..13cca04
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue
@@ -0,0 +1,19 @@
+<script setup lang="ts">
+import {
+  TooltipRoot,
+  type TooltipRootEmits,
+  type TooltipRootProps,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+const props = defineProps<TooltipRootProps>();
+const emits = defineEmits<TooltipRootEmits>();
+
+const forwarded = useForwardPropsEmits(props, emits);
+</script>
+
+<template>
+  <TooltipRoot v-bind="forwarded">
+    <slot></slot>
+  </TooltipRoot>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue
new file mode 100644
index 0000000..81b951e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue
@@ -0,0 +1,52 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { cn } from '@vben-core/shared/utils';
+
+import {
+  TooltipContent,
+  type TooltipContentEmits,
+  type TooltipContentProps,
+  TooltipPortal,
+  useForwardPropsEmits,
+} from 'radix-vue';
+
+defineOptions({
+  inheritAttrs: false,
+});
+
+const props = withDefaults(
+  defineProps<{ class?: any } & TooltipContentProps>(),
+  {
+    class: '',
+    side: 'right',
+    sideOffset: 5,
+  },
+);
+
+const emits = defineEmits<TooltipContentEmits>();
+
+const delegatedProps = computed(() => {
+  const { class: _, ...delegated } = props;
+
+  return delegated;
+});
+
+const forwarded = useForwardPropsEmits(delegatedProps, emits);
+</script>
+
+<template>
+  <TooltipPortal>
+    <TooltipContent
+      v-bind="{ ...forwarded, ...$attrs }"
+      :class="
+        cn(
+          'bg-accent text-accent-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 border-border shadow-float z-[1000] overflow-hidden rounded-sm border px-4 py-2 text-xs',
+          props.class,
+        )
+      "
+    >
+      <slot></slot>
+    </TooltipContent>
+  </TooltipPortal>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue
new file mode 100644
index 0000000..b13a457
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { TooltipProvider, type TooltipProviderProps } from 'radix-vue';
+
+const props = defineProps<TooltipProviderProps>();
+</script>
+
+<template>
+  <TooltipProvider v-bind="props">
+    <slot></slot>
+  </TooltipProvider>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue
new file mode 100644
index 0000000..2aa3794
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+import { TooltipTrigger, type TooltipTriggerProps } from 'radix-vue';
+
+const props = defineProps<TooltipTriggerProps>();
+</script>
+
+<template>
+  <TooltipTrigger v-bind="props">
+    <slot></slot>
+  </TooltipTrigger>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts
new file mode 100644
index 0000000..94e681c
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts
@@ -0,0 +1,4 @@
+export { default as Tooltip } from './Tooltip.vue';
+export { default as TooltipContent } from './TooltipContent.vue';
+export { default as TooltipProvider } from './TooltipProvider.vue';
+export { default as TooltipTrigger } from './TooltipTrigger.vue';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/shadcn-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/shadcn-ui/tsconfig.json
new file mode 100644
index 0000000..0a46bc5
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/shadcn-ui/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "@vben-core/shadcn-ui/*": ["./src/*"]
+    }
+  },
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/build.config.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/build.config.ts
new file mode 100644
index 0000000..18eaa60
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/build.config.ts
@@ -0,0 +1,21 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: [
+    {
+      builder: 'mkdist',
+      input: './src',
+      loaders: ['vue'],
+      pattern: ['**/*.vue'],
+    },
+    {
+      builder: 'mkdist',
+      format: 'esm',
+      input: './src',
+      loaders: ['js'],
+      pattern: ['**/*.ts'],
+    },
+  ],
+});
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/package.json b/eims-ui/packages/@core/ui-kit/tabs-ui/package.json
new file mode 100644
index 0000000..93906eb
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/package.json
@@ -0,0 +1,47 @@
+{
+  "name": "@vben-core/tabs-ui",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/@vben-core/uikit/tabs-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "build": "pnpm unbuild",
+    "prepublishOnly": "npm run build"
+  },
+  "files": [
+    "dist"
+  ],
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "development": "./src/index.ts",
+      "default": "./dist/index.mjs"
+    }
+  },
+  "publishConfig": {
+    "exports": {
+      ".": {
+        "default": "./dist/index.mjs"
+      }
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/postcss.config.mjs b/eims-ui/packages/@core/ui-kit/tabs-ui/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/index.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/index.ts
new file mode 100644
index 0000000..3c28c94
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/index.ts
@@ -0,0 +1,2 @@
+export { default as Tabs } from './tabs/tabs.vue';
+export { default as TabsChrome } from './tabs-chrome/tabs.vue';
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue
new file mode 100644
index 0000000..490e31e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue
@@ -0,0 +1,194 @@
+<script setup lang="ts">
+import type { TabDefinition } from '@vben-core/typings';
+
+import type { TabConfig, TabsProps } from '../../types';
+
+import { computed, ref } from 'vue';
+
+import { Pin, X } from '@vben-core/icons';
+import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';
+
+interface Props extends TabsProps {}
+
+defineOptions({
+  name: 'VbenTabsChrome',
+  // eslint-disable-next-line perfectionist/sort-objects
+  inheritAttrs: false,
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  contentClass: 'vben-tabs-content',
+  contextMenus: () => [],
+  gap: 7,
+  tabs: () => [],
+});
+
+const emit = defineEmits<{
+  close: [string];
+  unpin: [TabDefinition];
+}>();
+const active = defineModel<string>('active');
+
+const contentRef = ref();
+const tabRef = ref();
+
+const style = computed(() => {
+  const { gap } = props;
+  return {
+    '--gap': `${gap}px`,
+  };
+});
+
+const tabsView = computed(() => {
+  return props.tabs.map((tab) => {
+    const { fullPath, meta, name, path } = tab || {};
+    const { affixTab, icon, newTabTitle, tabClosable, title } = meta || {};
+    return {
+      affixTab: !!affixTab,
+      closable: Reflect.has(meta, 'tabClosable') ? !!tabClosable : true,
+      fullPath,
+      icon: icon as string,
+      key: fullPath || path,
+      meta,
+      name,
+      path,
+      title: (newTabTitle || title || name) as string,
+    } as TabConfig;
+  });
+});
+</script>
+
+<template>
+  <div
+    ref="contentRef"
+    :class="contentClass"
+    :style="style"
+    class="tabs-chrome !flex h-full w-max overflow-y-hidden pr-6"
+  >
+    <TransitionGroup name="slide-left">
+      <div
+        v-for="(tab, i) in tabsView"
+        :key="tab.key"
+        ref="tabRef"
+        :class="[
+          {
+            'is-active': tab.key === active,
+            draggable: !tab.affixTab,
+            'affix-tab': tab.affixTab,
+          },
+        ]"
+        :data-active-tab="active"
+        :data-index="i"
+        class="tabs-chrome__item draggable translate-all group relative -mr-3 flex h-full select-none items-center"
+        data-tab-item="true"
+        @click="active = tab.key"
+      >
+        <VbenContextMenu
+          :handler-data="tab"
+          :menus="contextMenus"
+          :modal="false"
+          item-class="pr-6"
+        >
+          <div class="relative size-full px-1">
+            <!-- divider -->
+            <div
+              v-if="i !== 0 && tab.key !== active"
+              class="tabs-chrome__divider bg-border absolute left-[var(--gap)] top-1/2 z-0 h-4 w-[1px] translate-y-[-50%] transition-all"
+            ></div>
+            <!-- background -->
+            <div
+              class="tabs-chrome__background absolute z-[-1] size-full px-[calc(var(--gap)-1px)] py-0 transition-opacity duration-150"
+            >
+              <div
+                class="tabs-chrome__background-content group-[.is-active]:bg-primary/15 dark:group-[.is-active]:bg-accent h-full rounded-tl-[var(--gap)] rounded-tr-[var(--gap)] duration-150"
+              ></div>
+              <svg
+                class="tabs-chrome__background-before group-[.is-active]:fill-primary/15 dark:group-[.is-active]:fill-accent absolute bottom-0 left-[-1px] fill-transparent transition-all duration-150"
+                height="7"
+                width="7"
+              >
+                <path d="M 0 7 A 7 7 0 0 0 7 0 L 7 7 Z" />
+              </svg>
+              <svg
+                class="tabs-chrome__background-after group-[.is-active]:fill-primary/15 dark:group-[.is-active]:fill-accent absolute bottom-0 right-[-1px] fill-transparent transition-all duration-150"
+                height="7"
+                width="7"
+              >
+                <path d="M 0 0 A 7 7 0 0 0 7 7 L 0 7 Z" />
+              </svg>
+            </div>
+
+            <!-- extra -->
+            <div
+              class="tabs-chrome__extra absolute right-[var(--gap)] top-1/2 z-[3] size-4 translate-y-[-50%]"
+            >
+              <!-- close-icon -->
+              <X
+                v-show="!tab.affixTab && tabsView.length > 1 && tab.closable"
+                class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground text-accent-foreground/80 group-[.is-active]:text-accent-foreground mt-[2px] size-3 cursor-pointer rounded-full transition-all"
+                @click.stop="() => emit('close', tab.key)"
+              />
+              <Pin
+                v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
+                class="hover:text-accent-foreground text-accent-foreground/80 group-[.is-active]:text-accent-foreground mt-[1px] size-3.5 cursor-pointer rounded-full transition-all"
+                @click.stop="() => emit('unpin', tab)"
+              />
+            </div>
+
+            <!-- tab-item-main -->
+            <div
+              class="tabs-chrome__item-main group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground text-accent-foreground z-[2] mx-[calc(var(--gap)*2)] my-0 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pl-2 pr-4 duration-150"
+            >
+              <VbenIcon
+                v-if="showIcon"
+                :icon="tab.icon"
+                class="mr-1 flex size-4 items-center overflow-hidden"
+              />
+              <span class="flex-1 overflow-hidden whitespace-nowrap text-sm">
+                {{ tab.title }}
+              </span>
+            </div>
+          </div>
+        </VbenContextMenu>
+      </div>
+    </TransitionGroup>
+  </div>
+</template>
+
+<style scoped>
+.tabs-chrome {
+  &__item:not(.dragging) {
+    @apply cursor-pointer;
+
+    &:hover:not(.is-active) {
+      & + .tabs-chrome__item {
+        .tabs-chrome__divider {
+          @apply opacity-0;
+        }
+      }
+
+      .tabs-chrome__divider {
+        @apply opacity-0;
+      }
+
+      .tabs-chrome__background {
+        @apply pb-[2px];
+
+        &-content {
+          @apply bg-accent mx-[2px] rounded-md;
+        }
+      }
+    }
+
+    &.is-active {
+      @apply z-[2];
+
+      & + .tabs-chrome__item {
+        .tabs-chrome__divider {
+          @apply opacity-0 !important;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
new file mode 100644
index 0000000..ba77aab
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue
@@ -0,0 +1,133 @@
+<script lang="ts" setup>
+import type { TabDefinition } from '@vben-core/typings';
+
+import type { TabConfig, TabsProps } from '../../types';
+
+import { computed } from 'vue';
+
+import { Pin, X } from '@vben-core/icons';
+import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';
+
+interface Props extends TabsProps {}
+
+defineOptions({
+  name: 'VbenTabs',
+  // eslint-disable-next-line perfectionist/sort-objects
+  inheritAttrs: false,
+});
+const props = withDefaults(defineProps<Props>(), {
+  contentClass: 'vben-tabs-content',
+  contextMenus: () => [],
+  tabs: () => [],
+});
+
+const emit = defineEmits<{
+  close: [string];
+  unpin: [TabDefinition];
+}>();
+const active = defineModel<string>('active');
+
+const typeWithClass = computed(() => {
+  const typeClasses: Record<string, { content: string }> = {
+    brisk: {
+      content: `h-full after:content-['']  after:absolute after:bottom-0 after:left-0 after:w-full after:h-[1.5px] after:bg-primary after:scale-x-0 after:transition-[transform] after:ease-out after:duration-300 hover:after:scale-x-100 after:origin-left [&.is-active]:after:scale-x-100 [&:not(:first-child)]:border-l last:border-r last:border-r border-border`,
+    },
+    card: {
+      content:
+        'h-[calc(100%-6px)] rounded-md ml-2 border border-border  transition-all',
+    },
+    plain: {
+      content:
+        'h-full [&:not(:first-child)]:border-l last:border-r border-border',
+    },
+  };
+
+  return typeClasses[props.styleType || 'plain'] || { content: '' };
+});
+
+const tabsView = computed(() => {
+  return props.tabs.map((tab) => {
+    const { fullPath, meta, name, path } = tab || {};
+    const { affixTab, icon, newTabTitle, tabClosable, title } = meta || {};
+    return {
+      affixTab: !!affixTab,
+      closable: Reflect.has(meta, 'tabClosable') ? !!tabClosable : true,
+      fullPath,
+      icon: icon as string,
+      key: fullPath || path,
+      meta,
+      name,
+      path,
+      title: (newTabTitle || title || name) as string,
+    } as TabConfig;
+  });
+});
+</script>
+
+<template>
+  <div
+    :class="contentClass"
+    class="relative !flex h-full w-max items-center overflow-hidden pr-6"
+  >
+    <TransitionGroup name="slide-left">
+      <div
+        v-for="(tab, i) in tabsView"
+        :key="tab.key"
+        :class="[
+          {
+            'is-active dark:bg-accent bg-primary/15': tab.key === active,
+            draggable: !tab.affixTab,
+            'affix-tab': tab.affixTab,
+          },
+          typeWithClass.content,
+        ]"
+        :data-index="i"
+        class="tab-item [&:not(.is-active)]:hover:bg-accent translate-all group relative flex cursor-pointer select-none"
+        data-tab-item="true"
+        @click="active = tab.key"
+      >
+        <VbenContextMenu
+          :handler-data="tab"
+          :menus="contextMenus"
+          :modal="false"
+          item-class="pr-6"
+        >
+          <div class="relative flex size-full items-center">
+            <!-- extra -->
+            <div
+              class="absolute right-1.5 top-1/2 z-[3] translate-y-[-50%] overflow-hidden"
+            >
+              <!-- close-icon -->
+              <X
+                v-show="!tab.affixTab && tabsView.length > 1 && tab.closable"
+                class="hover:bg-accent stroke-accent-foreground/80 hover:stroke-accent-foreground dark:group-[.is-active]:text-accent-foreground group-[.is-active]:text-primary size-3 cursor-pointer rounded-full transition-all"
+                @click.stop="() => emit('close', tab.key)"
+              />
+              <Pin
+                v-show="tab.affixTab && tabsView.length > 1 && tab.closable"
+                class="hover:bg-accent hover:stroke-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mt-[1px] size-3.5 cursor-pointer rounded-full transition-all"
+                @click.stop="() => emit('unpin', tab)"
+              />
+            </div>
+
+            <!-- tab-item-main -->
+            <div
+              class="text-accent-foreground group-[.is-active]:text-primary dark:group-[.is-active]:text-accent-foreground mx-3 mr-4 flex h-full items-center overflow-hidden rounded-tl-[5px] rounded-tr-[5px] pr-3 transition-all duration-300"
+            >
+              <VbenIcon
+                v-if="showIcon"
+                :icon="tab.icon"
+                class="mr-2 flex size-4 items-center overflow-hidden"
+                fallback
+              />
+
+              <span class="flex-1 overflow-hidden whitespace-nowrap text-sm">
+                {{ tab.title }}
+              </span>
+            </div>
+          </div>
+        </VbenContextMenu>
+      </div>
+    </TransitionGroup>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts
new file mode 100644
index 0000000..a26899e
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts
@@ -0,0 +1,2 @@
+export { default as TabsToolMore } from './tool-more.vue';
+export { default as TabsToolScreen } from './tool-screen.vue';
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue
new file mode 100644
index 0000000..0cbfc73
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue
@@ -0,0 +1,18 @@
+<script lang="ts" setup>
+import type { DropdownMenuProps } from '@vben-core/shadcn-ui';
+
+import { ChevronDown } from '@vben-core/icons';
+import { VbenDropdownMenu } from '@vben-core/shadcn-ui';
+
+defineProps<DropdownMenuProps>();
+</script>
+
+<template>
+  <VbenDropdownMenu :menus="menus" :modal="false">
+    <div
+      class="flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold"
+    >
+      <ChevronDown class="size-4" />
+    </div>
+  </VbenDropdownMenu>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue
new file mode 100644
index 0000000..0183719
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { Fullscreen, Minimize2 } from '@vben-core/icons';
+
+const screen = defineModel<boolean>('screen');
+
+function toggleScreen() {
+  screen.value = !screen.value;
+}
+</script>
+
+<template>
+  <div
+    class="flex-center hover:bg-muted hover:text-foreground text-muted-foreground border-border h-full cursor-pointer border-l px-2 text-lg font-semibold"
+    @click="toggleScreen"
+  >
+    <Minimize2 v-if="screen" class="size-4" />
+    <Fullscreen v-else class="size-4" />
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/index.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/index.ts
new file mode 100644
index 0000000..6d562db
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/index.ts
@@ -0,0 +1,3 @@
+export * from './components/widgets';
+export { default as TabsView } from './tabs-view.vue';
+export type { IContextMenuItem } from '@vben-core/shadcn-ui';
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue b/eims-ui/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue
new file mode 100644
index 0000000..7656e48
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue
@@ -0,0 +1,95 @@
+<script setup lang="ts">
+import type { TabsEmits, TabsProps } from './types';
+
+import { useForwardPropsEmits } from '@vben-core/composables';
+import { ChevronLeft, ChevronRight } from '@vben-core/icons';
+import { VbenScrollbar } from '@vben-core/shadcn-ui';
+
+import { Tabs, TabsChrome } from './components';
+import { useTabsDrag } from './use-tabs-drag';
+import { useTabsViewScroll } from './use-tabs-view-scroll';
+
+interface Props extends TabsProps {}
+
+defineOptions({
+  name: 'TabsView',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  contentClass: 'vben-tabs-content',
+  draggable: true,
+  styleType: 'chrome',
+});
+
+const emit = defineEmits<TabsEmits>();
+
+const forward = useForwardPropsEmits(props, emit);
+
+const {
+  handleScrollAt,
+  scrollbarRef,
+  scrollDirection,
+  scrollIsAtLeft,
+  scrollIsAtRight,
+  showScrollButton,
+} = useTabsViewScroll(props);
+
+useTabsDrag(props, emit);
+</script>
+
+<template>
+  <div class="flex h-full flex-1 overflow-hidden">
+    <!-- 宸︿晶婊氬姩鎸夐挳 -->
+    <span
+      v-show="showScrollButton"
+      :class="{
+        'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtLeft,
+        'pointer-events-none opacity-30': scrollIsAtLeft,
+      }"
+      class="border-r px-2"
+      @click="scrollDirection('left')"
+    >
+      <ChevronLeft class="size-4 h-full" />
+    </span>
+
+    <div
+      :class="{
+        'pt-[3px]': styleType === 'chrome',
+      }"
+      class="size-full flex-1 overflow-hidden"
+    >
+      <VbenScrollbar
+        ref="scrollbarRef"
+        :shadow-bottom="false"
+        :shadow-top="false"
+        class="h-full"
+        horizontal
+        scroll-bar-class="z-10 hidden "
+        shadow
+        shadow-left
+        shadow-right
+        @scroll-at="handleScrollAt"
+      >
+        <TabsChrome
+          v-if="styleType === 'chrome'"
+          v-bind="{ ...forward, ...$attrs, ...$props }"
+        />
+
+        <Tabs v-else v-bind="{ ...forward, ...$attrs, ...$props }" />
+      </VbenScrollbar>
+    </div>
+
+    <!-- 鍙充晶婊氬姩鎸夐挳 -->
+    <span
+      v-show="showScrollButton"
+      :class="{
+        'hover:bg-muted text-muted-foreground cursor-pointer': !scrollIsAtRight,
+        'pointer-events-none opacity-30': scrollIsAtRight,
+      }"
+      class="hover:bg-muted text-muted-foreground cursor-pointer border-l px-2"
+      @click="scrollDirection('right')"
+    >
+      <ChevronRight class="size-4 h-full" />
+    </span>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/types.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/types.ts
new file mode 100644
index 0000000..ce0ac47
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/types.ts
@@ -0,0 +1,64 @@
+import type { IContextMenuItem } from '@vben-core/shadcn-ui';
+import type { TabDefinition, TabsStyleType } from '@vben-core/typings';
+
+export type TabsEmits = {
+  close: [string];
+  sortTabs: [number, number];
+  unpin: [TabDefinition];
+};
+
+export interface TabsProps {
+  active?: string;
+  /**
+   * @zh_CN content class
+   * @default tabs-chrome
+   */
+  contentClass?: string;
+  /**
+   * @zh_CN 鍙抽敭鑿滃崟
+   */
+  contextMenus?: (data: any) => IContextMenuItem[];
+  /**
+   * @zh_CN 鏄惁鍙互鎷栨嫿
+   */
+  draggable?: boolean;
+  /**
+   * @zh_CN 闂撮殭
+   * @default 7
+   * 浠呴檺 tabs-chrome
+   */
+  gap?: number;
+  /**
+   * @zh_CN tab 鏈�澶у搴�
+   * 浠呴檺 tabs-chrome
+   */
+  maxWidth?: number;
+
+  /**
+   * @zh_CN tab鏈�灏忓搴�
+   * 浠呴檺 tabs-chrome
+   */
+  minWidth?: number;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず鍥炬爣
+   */
+  showIcon?: boolean;
+  /**
+   * @zh_CN 鏍囩椤甸鏍�
+   */
+  styleType?: TabsStyleType;
+
+  /**
+   * @zh_CN 閫夐」鍗℃暟鎹�
+   */
+  tabs?: TabDefinition[];
+}
+
+export interface TabConfig extends TabDefinition {
+  affixTab: boolean;
+  closable: boolean;
+  icon: string;
+  key: string;
+  title: string;
+}
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts
new file mode 100644
index 0000000..db4b7ce
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts
@@ -0,0 +1,127 @@
+import type { EmitType } from '@vben-core/typings';
+
+import type { TabsProps } from './types';
+
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
+
+import {
+  type Sortable,
+  useIsMobile,
+  useSortable,
+} from '@vben-core/composables';
+
+// 鍙兘浼氭壘鍒版嫋鎷界殑瀛愬厓绱狅紝杩欓噷闇�瑕佺‘淇濇嫋鎷界殑dom鏃秚ab鍏冪礌
+function findParentElement(element: HTMLElement) {
+  const parentCls = 'group';
+  return element.classList.contains(parentCls)
+    ? element
+    : element.closest(`.${parentCls}`);
+}
+
+export function useTabsDrag(props: TabsProps, emit: EmitType) {
+  const sortableInstance = ref<null | Sortable>(null);
+
+  async function initTabsSortable() {
+    await nextTick();
+
+    const el = document.querySelectorAll(
+      `.${props.contentClass}`,
+    )?.[0] as HTMLElement;
+
+    if (!el) {
+      console.warn('Element not found for sortable initialization');
+      return;
+    }
+
+    const resetElState = async () => {
+      el.style.cursor = 'default';
+      // el.classList.remove('dragging');
+      el.querySelector('.draggable')?.classList.remove('dragging');
+    };
+
+    const { initializeSortable } = useSortable(el, {
+      filter: (_evt, target: HTMLElement) => {
+        const parent = findParentElement(target);
+        const draggable = parent?.classList.contains('draggable');
+        return !draggable || !props.draggable;
+      },
+      onEnd(evt) {
+        const { newIndex, oldIndex } = evt;
+        // const fromElement = evt.item;
+        const { srcElement } = (evt as any).originalEvent;
+
+        if (!srcElement) {
+          resetElState();
+          return;
+        }
+
+        const srcParent = findParentElement(srcElement);
+
+        if (!srcParent) {
+          resetElState();
+          return;
+        }
+
+        if (!srcParent.classList.contains('draggable')) {
+          resetElState();
+
+          return;
+        }
+
+        if (
+          oldIndex !== undefined &&
+          newIndex !== undefined &&
+          !Number.isNaN(oldIndex) &&
+          !Number.isNaN(newIndex) &&
+          oldIndex !== newIndex
+        ) {
+          emit('sortTabs', oldIndex, newIndex);
+        }
+        resetElState();
+      },
+      onMove(evt) {
+        const parent = findParentElement(evt.related);
+        if (parent?.classList.contains('draggable') && props.draggable) {
+          const isCurrentAffix = evt.dragged.classList.contains('affix-tab');
+          const isRelatedAffix = evt.related.classList.contains('affix-tab');
+          // 涓嶅厑璁稿湪鍥哄畾鐨則ab鍜岄潪鍥哄畾鐨則ab涔嬮棿浜掔浉鎷栨嫿
+          return isCurrentAffix === isRelatedAffix;
+        } else {
+          return false;
+        }
+      },
+      onStart: () => {
+        el.style.cursor = 'grabbing';
+        el.querySelector('.draggable')?.classList.add('dragging');
+        // el.classList.add('dragging');
+      },
+    });
+
+    sortableInstance.value = await initializeSortable();
+  }
+
+  async function init() {
+    const { isMobile } = useIsMobile();
+
+    // 绉诲姩绔笅tab涓嶉渶瑕佹嫋鎷�
+    if (isMobile.value) {
+      return;
+    }
+    await nextTick();
+    initTabsSortable();
+  }
+
+  onMounted(init);
+
+  watch(
+    () => props.styleType,
+    () => {
+      sortableInstance.value?.destroy();
+      init();
+    },
+  );
+
+  onUnmounted(() => {
+    sortableInstance.value?.destroy();
+  });
+}
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts b/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts
new file mode 100644
index 0000000..a56b382
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts
@@ -0,0 +1,194 @@
+import type { TabsProps } from './types';
+
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
+
+import { VbenScrollbar } from '@vben-core/shadcn-ui';
+
+import { useDebounceFn } from '@vueuse/core';
+
+type DomElement = Element | null | undefined;
+
+export function useTabsViewScroll(props: TabsProps) {
+  let resizeObserver: null | ResizeObserver = null;
+  let mutationObserver: MutationObserver | null = null;
+  let tabItemCount = 0;
+  const scrollbarRef = ref<InstanceType<typeof VbenScrollbar> | null>(null);
+  const scrollViewportEl = ref<DomElement>(null);
+  const showScrollButton = ref(false);
+  const scrollIsAtLeft = ref(true);
+  const scrollIsAtRight = ref(false);
+
+  function getScrollClientWidth() {
+    const scrollbarEl = scrollbarRef.value?.$el;
+    if (!scrollbarEl || !scrollViewportEl.value) return {};
+
+    const scrollbarWidth = scrollbarEl.clientWidth;
+    const scrollViewWidth = scrollViewportEl.value.clientWidth;
+
+    return {
+      scrollbarWidth,
+      scrollViewWidth,
+    };
+  }
+
+  function scrollDirection(
+    direction: 'left' | 'right',
+    distance: number = 150,
+  ) {
+    const { scrollbarWidth, scrollViewWidth } = getScrollClientWidth();
+
+    if (!scrollbarWidth || !scrollViewWidth) return;
+
+    if (scrollbarWidth > scrollViewWidth) return;
+
+    scrollViewportEl.value?.scrollBy({
+      behavior: 'smooth',
+      left:
+        direction === 'left'
+          ? -(scrollbarWidth - distance)
+          : +(scrollbarWidth - distance),
+    });
+  }
+
+  async function initScrollbar() {
+    await nextTick();
+
+    const scrollbarEl = scrollbarRef.value?.$el;
+    if (!scrollbarEl) {
+      return;
+    }
+
+    const viewportEl = scrollbarEl?.querySelector(
+      'div[data-radix-scroll-area-viewport]',
+    );
+
+    scrollViewportEl.value = viewportEl;
+    calcShowScrollbarButton();
+
+    await nextTick();
+    scrollToActiveIntoView();
+
+    // 鐩戝惉澶у皬鍙樺寲
+    resizeObserver?.disconnect();
+    resizeObserver = new ResizeObserver(
+      useDebounceFn((_entries: ResizeObserverEntry[]) => {
+        calcShowScrollbarButton();
+        scrollToActiveIntoView();
+      }, 100),
+    );
+    resizeObserver.observe(viewportEl);
+
+    tabItemCount = props.tabs?.length || 0;
+    mutationObserver?.disconnect();
+    // 浣跨敤 MutationObserver 浠呯洃鍚瓙鑺傜偣鏁伴噺鍙樺寲
+    mutationObserver = new MutationObserver(() => {
+      const count = viewportEl.querySelectorAll(
+        `div[data-tab-item="true"]`,
+      ).length;
+
+      if (count > tabItemCount) {
+        scrollToActiveIntoView();
+      }
+
+      if (count !== tabItemCount) {
+        calcShowScrollbarButton();
+        tabItemCount = count;
+      }
+    });
+
+    // 閰嶇疆涓轰粎鐩戝惉瀛愯妭鐐圭殑娣诲姞鍜岀Щ闄�
+    mutationObserver.observe(viewportEl, {
+      attributes: false,
+      childList: true,
+      subtree: true,
+    });
+  }
+
+  async function scrollToActiveIntoView() {
+    if (!scrollViewportEl.value) {
+      return;
+    }
+    await nextTick();
+    const viewportEl = scrollViewportEl.value;
+    const { scrollbarWidth } = getScrollClientWidth();
+    const { scrollWidth } = viewportEl;
+
+    if (scrollbarWidth >= scrollWidth) {
+      return;
+    }
+
+    requestAnimationFrame(() => {
+      const activeItem = viewportEl?.querySelector('.is-active');
+      activeItem?.scrollIntoView({ behavior: 'smooth', inline: 'start' });
+    });
+  }
+
+  /**
+   * 璁$畻tabs 瀹藉害锛岀敤浜庡垽鏂槸鍚︽樉绀哄乏鍙虫粴鍔ㄦ寜閽�
+   */
+  async function calcShowScrollbarButton() {
+    if (!scrollViewportEl.value) {
+      return;
+    }
+
+    const { scrollbarWidth } = getScrollClientWidth();
+
+    showScrollButton.value =
+      scrollViewportEl.value.scrollWidth > scrollbarWidth;
+  }
+
+  const handleScrollAt = useDebounceFn(({ left, right }) => {
+    scrollIsAtLeft.value = left;
+    scrollIsAtRight.value = right;
+  }, 100);
+
+  watch(
+    () => props.active,
+    async () => {
+      // 200涓轰簡绛夊緟 tab 鍒囨崲鍔ㄧ敾瀹屾垚
+      // setTimeout(() => {
+      scrollToActiveIntoView();
+      // }, 300);
+    },
+    {
+      flush: 'post',
+    },
+  );
+
+  // watch(
+  //   () => props.tabs?.length,
+  //   async () => {
+  //     await nextTick();
+  //     calcShowScrollbarButton();
+  //   },
+  //   {
+  //     flush: 'post',
+  //   },
+  // );
+
+  watch(
+    () => props.styleType,
+    () => {
+      initScrollbar();
+    },
+  );
+
+  onMounted(initScrollbar);
+
+  onUnmounted(() => {
+    resizeObserver?.disconnect();
+    mutationObserver?.disconnect();
+    resizeObserver = null;
+    mutationObserver = null;
+  });
+
+  return {
+    handleScrollAt,
+    initScrollbar,
+    scrollbarRef,
+    scrollDirection,
+    scrollIsAtLeft,
+    scrollIsAtRight,
+    showScrollButton,
+  };
+}
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs b/eims-ui/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/packages/@core/ui-kit/tabs-ui/tsconfig.json b/eims-ui/packages/@core/ui-kit/tabs-ui/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/@core/ui-kit/tabs-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/constants/README.md b/eims-ui/packages/constants/README.md
new file mode 100644
index 0000000..1fae490
--- /dev/null
+++ b/eims-ui/packages/constants/README.md
@@ -0,0 +1,19 @@
+# @vben/constants
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨勫父閲忥紝缁ф壙浜� `@vben-core/shared/constants` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤甯搁噺鍙互鏀惧湪杩欓噷銆�
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/constants
+```
+
+### 浣跨敤
+
+```ts
+import { DEFAULT_HOME_PATH } from '@vben/constants';
+```
diff --git a/eims-ui/packages/constants/package.json b/eims-ui/packages/constants/package.json
new file mode 100644
index 0000000..a838a79
--- /dev/null
+++ b/eims-ui/packages/constants/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "@vben/constants",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/constants"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/shared": "workspace:*"
+  }
+}
diff --git a/eims-ui/packages/constants/src/core.ts b/eims-ui/packages/constants/src/core.ts
new file mode 100644
index 0000000..9cc2521
--- /dev/null
+++ b/eims-ui/packages/constants/src/core.ts
@@ -0,0 +1,29 @@
+/**
+ * @zh_CN 鐧诲綍椤甸潰 url 鍦板潃
+ */
+export const LOGIN_PATH = '/auth/login';
+
+/**
+ * @zh_CN 榛樿棣栭〉鍦板潃
+ */
+// export const DEFAULT_HOME_PATH = '/analytics';
+export const DEFAULT_HOME_PATH = '/index';
+
+export interface LanguageOption {
+  label: string;
+  value: 'en-US' | 'zh-CN';
+}
+
+/**
+ * Supported languages
+ */
+export const SUPPORT_LANGUAGES: LanguageOption[] = [
+  {
+    label: '绠�浣撲腑鏂�',
+    value: 'zh-CN',
+  },
+  {
+    label: 'English',
+    value: 'en-US',
+  },
+];
diff --git a/eims-ui/packages/constants/src/index.ts b/eims-ui/packages/constants/src/index.ts
new file mode 100644
index 0000000..6502c6d
--- /dev/null
+++ b/eims-ui/packages/constants/src/index.ts
@@ -0,0 +1,2 @@
+export * from './core';
+export * from '@vben-core/shared/constants';
diff --git a/eims-ui/packages/constants/tsconfig.json b/eims-ui/packages/constants/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/constants/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/README.md b/eims-ui/packages/effects/README.md
new file mode 100644
index 0000000..4965b51
--- /dev/null
+++ b/eims-ui/packages/effects/README.md
@@ -0,0 +1,10 @@
+## Effects 鐩綍
+
+`effects` 鐩綍涓撻棬鐢ㄤ簬瀛樻斁涓庤交寰�﹀悎鐩稿叧鐨勪唬鐮佸拰閫昏緫銆傚鏋滀綘鐨勫寘鍏锋湁浠ヤ笅鐗圭偣锛屽缓璁皢鍏舵斁缃湪 `effects` 鐩綍涓嬶細
+
+- **鐘舵�佺鐞�**锛氫娇鐢ㄧ姸鎬佺鐞嗘鏋� `pinia`锛屽苟鍖呭惈澶勭悊鍓綔鐢紙濡傚紓姝ユ搷浣溿�丄PI 璋冪敤锛夌殑閮ㄥ垎銆�
+- **鐢ㄦ埛鍋忓ソ璁剧疆**锛氫娇鐢� `@vben-core/preferences` 澶勭悊鐢ㄦ埛鍋忓ソ璁剧疆锛屾秹鍙婃湰鍦板瓨鍌ㄦ垨娴忚鍣ㄧ紦瀛橀�昏緫锛堝浣跨敤 `localStorage`锛夈��
+- **瀵艰埅鍜岃矾鐢�**锛氬鐞嗗鑸�侀〉闈㈣烦杞瓑鍦烘櫙锛岄渶瑕佺鐞嗚矾鐢卞彉鍖栫殑閫昏緫銆�
+- **缁勪欢搴撲緷璧�**锛氬寘鍚笌鐗瑰畾缁勪欢搴撶揣瀵嗚�﹀悎鎴栦緷璧栧ぇ鍨嬩粨搴撶殑閮ㄥ垎銆�
+
+閫氳繃灏嗙浉鍏充唬鐮佸綊绫诲埌 `effects` 鐩綍锛屽彲浠ヤ娇椤圭洰缁撴瀯鏇村姞娓呮櫚锛屼究浜庣淮鎶ゅ拰鎵╁睍銆�
diff --git a/eims-ui/packages/effects/access/package.json b/eims-ui/packages/effects/access/package.json
new file mode 100644
index 0000000..71cf35a
--- /dev/null
+++ b/eims-ui/packages/effects/access/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "@vben/access",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/permissions"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben/preferences": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "vue": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/access/src/access-control.vue b/eims-ui/packages/effects/access/src/access-control.vue
new file mode 100644
index 0000000..219608e
--- /dev/null
+++ b/eims-ui/packages/effects/access/src/access-control.vue
@@ -0,0 +1,47 @@
+<!--
+ Access control component for fine-grained access control.
+ TODO: 鍙互鎵╁睍鏇村畬鍠勭殑鍔熻兘锛�
+ 1. 鏀寔澶氫釜鏉冮檺鐮侊紝鍙鏈変竴涓潈闄愮爜婊¤冻鍗冲彲 鎴栬�� 澶氫釜鏉冮檺鐮佸叏閮ㄦ弧瓒�
+ 2. 鏀寔澶氫釜瑙掕壊锛屽彧瑕佹湁涓�涓鑹叉弧瓒冲嵆鍙� 鎴栬�� 澶氫釜瑙掕壊鍏ㄩ儴婊¤冻
+ 3. 鏀寔鑷畾涔夋潈闄愮爜鍜岃鑹茬殑鍒ゆ柇閫昏緫
+-->
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { useAccess } from './use-access';
+
+interface Props {
+  /**
+   * Specified codes is visible
+   * @default []
+   */
+  codes?: string[];
+
+  /**
+   * 閫氳繃浠�涔堟柟寮忔潵鎺у埗缁勪欢锛屽鏋滄槸 role锛屽垯浼犲叆瑙掕壊锛屽鏋滄槸 code锛屽垯浼犲叆鏉冮檺鐮�
+   * @default 'role'
+   */
+  type?: 'code' | 'role';
+}
+
+defineOptions({
+  name: 'AccessControl',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  codes: () => [],
+  type: 'role',
+});
+
+const { hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+const hasAuth = computed(() => {
+  const { codes, type } = props;
+  return type === 'role' ? hasAccessByRoles(codes) : hasAccessByCodes(codes);
+});
+</script>
+
+<template>
+  <slot v-if="!codes"></slot>
+  <slot v-else-if="hasAuth"></slot>
+</template>
diff --git a/eims-ui/packages/effects/access/src/accessible.ts b/eims-ui/packages/effects/access/src/accessible.ts
new file mode 100644
index 0000000..d206adf
--- /dev/null
+++ b/eims-ui/packages/effects/access/src/accessible.ts
@@ -0,0 +1,100 @@
+import type {
+  AccessModeType,
+  GenerateMenuAndRoutesOptions,
+  RouteRecordRaw,
+} from '@vben/types';
+
+import {
+  cloneDeep,
+  generateMenus,
+  generateRoutesByBackend,
+  generateRoutesByFrontend,
+  mapTree,
+  setObjToUrlParams,
+} from '@vben/utils';
+
+async function generateAccessible(
+  mode: AccessModeType,
+  options: GenerateMenuAndRoutesOptions,
+) {
+  const { router } = options;
+
+  options.routes = cloneDeep(options.routes);
+  // 鐢熸垚璺敱
+  const accessibleRoutes = await generateRoutes(mode, options);
+
+  // 鍔ㄦ�佹坊鍔犲埌router瀹炰緥鍐�
+  accessibleRoutes.forEach((route) => {
+    /**
+     * 澶栭摼涓嶅簲璇ヨ娣诲姞鍒拌矾鐢� 鐢眒enu澶勭悊
+     */
+    if (/^https?:\/\//.test(route.path)) {
+      return;
+    }
+    router.addRoute(route);
+  });
+
+  // 鐢熸垚鑿滃崟
+  const accessibleMenus = await generateMenus(accessibleRoutes, options.router);
+
+  return { accessibleMenus, accessibleRoutes };
+}
+
+/**
+ * Generate routes
+ * @param mode
+ * @param options
+ */
+async function generateRoutes(
+  mode: AccessModeType,
+  options: GenerateMenuAndRoutesOptions,
+) {
+  const { forbiddenComponent, roles, routes } = options;
+
+  let resultRoutes: RouteRecordRaw[] = routes;
+  switch (mode) {
+    case 'backend': {
+      resultRoutes = await generateRoutesByBackend(options);
+      break;
+    }
+    case 'frontend': {
+      resultRoutes = await generateRoutesByFrontend(
+        routes,
+        roles || [],
+        forbiddenComponent,
+      );
+      break;
+    }
+  }
+
+  /**
+   * 璋冩暣璺敱鏍戯紝鍋氫互涓嬪鐞嗭細
+   * 1. 瀵规湭娣诲姞redirect鐨勮矾鐢辨坊鍔爎edirect
+   */
+  resultRoutes = mapTree(resultRoutes, (route) => {
+    // 濡傛灉鏈塺edirect鎴栬�呮病鏈夊瓙璺敱锛屽垯鐩存帴杩斿洖
+    if (route.redirect || !route.children || route.children.length === 0) {
+      return route;
+    }
+    const firstChild = route.children[0];
+
+    // 濡傛灉瀛愯矾鐢变笉鏄互/寮�澶达紝鍒欑洿鎺ヨ繑鍥�,杩欑鎯呭喌闇�瑕佽绠楀叏閮ㄧ埗绾х殑path鎵嶈兘寰楀嚭姝g‘鐨刾ath锛岃繖閲屼笉鍋氬鐞�
+    if (!firstChild?.path || !firstChild.path.startsWith('/')) {
+      return route;
+    }
+
+    // 绗竴涓矾鐢卞鏋滄湁query鍙傛暟 闇�瑕佸姞涓婂弬鏁�
+    const fistChildQuery = route.children[0]?.meta?.query;
+    // 鏍圭洰褰曡彍鍗曞浐瀹氬彧鏈変竴涓猚hildren 涓攑ath涓�/ 涓嶉渶瑕佹坊鍔爎edirect
+    route.redirect =
+      fistChildQuery && route.children.length !== 1 && route.path !== '/'
+        ? setObjToUrlParams(firstChild.path, fistChildQuery)
+        : firstChild.path;
+
+    return route;
+  });
+
+  return resultRoutes;
+}
+
+export { generateAccessible };
diff --git a/eims-ui/packages/effects/access/src/directive.ts b/eims-ui/packages/effects/access/src/directive.ts
new file mode 100644
index 0000000..35d9d51
--- /dev/null
+++ b/eims-ui/packages/effects/access/src/directive.ts
@@ -0,0 +1,42 @@
+/**
+ * Global authority directive
+ * Used for fine-grained control of component permissions
+ * @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME"
+ * @Example v-access:code="[ROLE_CODE]" or v-access:code="ROLE_CODE"
+ */
+import type { App, Directive, DirectiveBinding } from 'vue';
+
+import { useAccess } from './use-access';
+
+function isAccessible(
+  el: Element,
+  binding: DirectiveBinding<string | string[]>,
+) {
+  const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess();
+
+  const value = binding.value;
+
+  if (!value) return;
+  const authMethod =
+    accessMode.value === 'frontend' && binding.arg === 'role'
+      ? hasAccessByRoles
+      : hasAccessByCodes;
+
+  const values = Array.isArray(value) ? value : [value];
+
+  if (!authMethod(values)) {
+    el?.remove();
+  }
+}
+
+const mounted = (el: Element, binding: DirectiveBinding<string | string[]>) => {
+  isAccessible(el, binding);
+};
+
+const authDirective: Directive = {
+  mounted,
+};
+
+export function registerAccessDirective(app: App) {
+  app.directive('access', authDirective);
+}
diff --git a/eims-ui/packages/effects/access/src/index.ts b/eims-ui/packages/effects/access/src/index.ts
new file mode 100644
index 0000000..392aa53
--- /dev/null
+++ b/eims-ui/packages/effects/access/src/index.ts
@@ -0,0 +1,4 @@
+export { default as AccessControl } from './access-control.vue';
+export * from './accessible';
+export * from './directive';
+export * from './use-access';
diff --git a/eims-ui/packages/effects/access/src/use-access.ts b/eims-ui/packages/effects/access/src/use-access.ts
new file mode 100644
index 0000000..05ac348
--- /dev/null
+++ b/eims-ui/packages/effects/access/src/use-access.ts
@@ -0,0 +1,59 @@
+import { computed } from 'vue';
+
+import { preferences, updatePreferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+
+function useAccess() {
+  const accessStore = useAccessStore();
+  const userStore = useUserStore();
+  const accessMode = computed(() => {
+    return preferences.app.accessMode;
+  });
+
+  /**
+   * 鍩轰簬瑙掕壊鍒ゆ柇鏄惁鏈夋潈闄�
+   * @description: Determine whether there is permission锛孴he role is judged by the user's role
+   * @param roles
+   */
+  function hasAccessByRoles(roles: string[]) {
+    const userRoleSet = new Set(userStore.userRoles);
+    const intersection = roles.filter((item) => userRoleSet.has(item));
+    return intersection.length > 0;
+  }
+
+  /**
+   * 鍩轰簬鏉冮檺鐮佸垽鏂槸鍚︽湁鏉冮檺
+   * @description: Determine whether there is permission锛孴he permission code is judged by the user's permission code
+   * @param codes
+   */
+  function hasAccessByCodes(codes: string[]) {
+    const userCodesSet = new Set(accessStore.accessCodes);
+    /**
+     * 绠$悊鍛樻潈闄�
+     */
+    if (userCodesSet.has('*:*:*')) {
+      return true;
+    }
+    // 鍏朵粬 鍒ゆ柇鏄惁瀛樺湪
+    const intersection = codes.filter((item) => userCodesSet.has(item));
+    return intersection.length > 0;
+  }
+
+  async function toggleAccessMode() {
+    updatePreferences({
+      app: {
+        accessMode:
+          preferences.app.accessMode === 'frontend' ? 'backend' : 'frontend',
+      },
+    });
+  }
+
+  return {
+    accessMode,
+    hasAccessByCodes,
+    hasAccessByRoles,
+    toggleAccessMode,
+  };
+}
+
+export { useAccess };
diff --git a/eims-ui/packages/effects/access/tsconfig.json b/eims-ui/packages/effects/access/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/effects/access/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/common-ui/package.json b/eims-ui/packages/effects/common-ui/package.json
new file mode 100644
index 0000000..7a0733c
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/package.json
@@ -0,0 +1,54 @@
+{
+  "name": "@vben/common-ui",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/common-ui"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@codemirror/lang-html": "^6.4.9",
+    "@codemirror/lang-java": "^6.0.1",
+    "@codemirror/lang-javascript": "^6.2.2",
+    "@codemirror/lang-sql": "^6.7.1",
+    "@codemirror/lang-vue": "^0.1.3",
+    "@codemirror/lang-xml": "^6.1.0",
+    "@codemirror/theme-one-dark": "^6.1.2",
+    "@vben-core/form-ui": "workspace:*",
+    "@vben-core/popup-ui": "workspace:*",
+    "@vben-core/preferences": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "@vueuse/integrations": "catalog:",
+    "codemirror": "6.0.1",
+    "qrcode": "catalog:",
+    "vditor": "3.10.7",
+    "vue": "catalog:",
+    "vue-codemirror6": "1.3.4",
+    "vue-json-pretty": "^2.4.0",
+    "vue-router": "catalog:"
+  },
+  "devDependencies": {
+    "@types/qrcode": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/common-ui/src/components/api-component/api-component.vue b/eims-ui/packages/effects/common-ui/src/components/api-component/api-component.vue
new file mode 100644
index 0000000..d1d42ad
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/api-component/api-component.vue
@@ -0,0 +1,205 @@
+<script lang="ts" setup>
+import type { AnyPromiseFunction } from '@vben/types';
+
+import { type Component, computed, ref, unref, useAttrs, watch } from 'vue';
+
+import { LoaderCircle } from '@vben/icons';
+import { get, isEqual, isFunction } from '@vben-core/shared/utils';
+
+import { objectOmit } from '@vueuse/core';
+
+type OptionsItem = {
+  [name: string]: any;
+  children?: OptionsItem[];
+  disabled?: boolean;
+  label?: string;
+  value?: string;
+};
+
+interface Props {
+  /** 缁勪欢 */
+  component: Component;
+  /** 鏄惁灏唙alue浠庢暟瀛楄浆涓簊tring */
+  numberToString?: boolean;
+  /** 鑾峰彇options鏁版嵁鐨勫嚱鏁� */
+  api?: (arg?: any) => Promise<OptionsItem[] | Record<string, any>>;
+  /** 浼犻�掔粰api鐨勫弬鏁� */
+  params?: Record<string, any>;
+  /** 浠巃pi杩斿洖鐨勭粨鏋滀腑鎻愬彇options鏁扮粍鐨勫瓧娈靛悕 */
+  resultField?: string;
+  /** label瀛楁鍚� */
+  labelField?: string;
+  /** children瀛楁鍚嶏紝闇�瑕佸眰绾ф暟鎹殑缁勪欢鍙敤 */
+  childrenField?: string;
+  /** value瀛楁鍚� */
+  valueField?: string;
+  /** 缁勪欢鎺ユ敹options鏁版嵁鐨勫睘鎬у悕 */
+  optionsPropName?: string;
+  /** 鏄惁绔嬪嵆璋冪敤api */
+  immediate?: boolean;
+  /** 姣忔`visibleEvent`浜嬩欢鍙戠敓鏃堕兘閲嶆柊璇锋眰鏁版嵁 */
+  alwaysLoad?: boolean;
+  /** 鍦╝pi璇锋眰涔嬪墠鐨勫洖璋冨嚱鏁� */
+  beforeFetch?: AnyPromiseFunction<any, any>;
+  /** 鍦╝pi璇锋眰涔嬪悗鐨勫洖璋冨嚱鏁� */
+  afterFetch?: AnyPromiseFunction<any, any>;
+  /** 鐩存帴浼犲叆閫夐」鏁版嵁锛屼篃浣滀负api杩斿洖绌烘暟鎹椂鐨勫悗澶囨暟鎹� */
+  options?: OptionsItem[];
+  /** 缁勪欢鐨勬彃妲藉悕绉帮紝鐢ㄦ潵鏄剧ず涓�涓�"鍔犺浇涓�"鐨勫浘鏍� */
+  loadingSlot?: string;
+  /** 瑙﹀彂api璇锋眰鐨勪簨浠跺悕 */
+  visibleEvent?: string;
+  /** 缁勪欢鐨剉-model灞炴�у悕锛岄粯璁や负modelValue銆傞儴鍒嗙粍浠跺彲鑳戒负value */
+  modelPropName?: string;
+}
+
+defineOptions({ name: 'ApiComponent', inheritAttrs: false });
+
+const props = withDefaults(defineProps<Props>(), {
+  labelField: 'label',
+  valueField: 'value',
+  childrenField: '',
+  optionsPropName: 'options',
+  resultField: '',
+  visibleEvent: '',
+  numberToString: false,
+  params: () => ({}),
+  immediate: true,
+  alwaysLoad: false,
+  loadingSlot: '',
+  beforeFetch: undefined,
+  afterFetch: undefined,
+  modelPropName: 'modelValue',
+  api: undefined,
+  options: () => [],
+});
+
+const emit = defineEmits<{
+  optionsChange: [OptionsItem[]];
+}>();
+
+const modelValue = defineModel({ default: '' });
+
+const attrs = useAttrs();
+
+const refOptions = ref<OptionsItem[]>([]);
+const loading = ref(false);
+// 棣栨鏄惁鍔犺浇杩囦簡
+const isFirstLoaded = ref(false);
+
+const getOptions = computed(() => {
+  const { labelField, valueField, childrenField, numberToString } = props;
+
+  const refOptionsData = unref(refOptions);
+
+  function transformData(data: OptionsItem[]): OptionsItem[] {
+    return data.map((item) => {
+      const value = get(item, valueField);
+      return {
+        ...objectOmit(item, [labelField, valueField, childrenField]),
+        label: get(item, labelField),
+        value: numberToString ? `${value}` : value,
+        ...(childrenField && item[childrenField]
+          ? { children: transformData(item[childrenField]) }
+          : {}),
+      };
+    });
+  }
+
+  const data: OptionsItem[] = transformData(refOptionsData);
+
+  return data.length > 0 ? data : props.options;
+});
+
+const bindProps = computed(() => {
+  return {
+    [props.modelPropName]: unref(modelValue),
+    [props.optionsPropName]: unref(getOptions),
+    [`onUpdate:${props.modelPropName}`]: (val: string) => {
+      modelValue.value = val;
+    },
+    ...objectOmit(attrs, ['onUpdate:value']),
+    ...(props.visibleEvent
+      ? {
+          [props.visibleEvent]: handleFetchForVisible,
+        }
+      : {}),
+  };
+});
+
+async function fetchApi() {
+  let { api, beforeFetch, afterFetch, params, resultField } = props;
+
+  if (!api || !isFunction(api) || loading.value) {
+    return;
+  }
+  refOptions.value = [];
+  try {
+    loading.value = true;
+    if (beforeFetch && isFunction(beforeFetch)) {
+      params = (await beforeFetch(params)) || params;
+    }
+    let res = await api(params);
+    if (afterFetch && isFunction(afterFetch)) {
+      res = (await afterFetch(res)) || res;
+    }
+    isFirstLoaded.value = true;
+    if (Array.isArray(res)) {
+      refOptions.value = res;
+      emitChange();
+      return;
+    }
+    if (resultField) {
+      refOptions.value = get(res, resultField) || [];
+    }
+    emitChange();
+  } catch (error) {
+    console.warn(error);
+    // reset status
+    isFirstLoaded.value = false;
+  } finally {
+    loading.value = false;
+  }
+}
+
+async function handleFetchForVisible(visible: boolean) {
+  if (visible) {
+    if (props.alwaysLoad) {
+      await fetchApi();
+    } else if (!props.immediate && !unref(isFirstLoaded)) {
+      await fetchApi();
+    }
+  }
+}
+
+watch(
+  () => props.params,
+  (value, oldValue) => {
+    if (isEqual(value, oldValue)) {
+      return;
+    }
+    fetchApi();
+  },
+  { deep: true, immediate: props.immediate },
+);
+
+function emitChange() {
+  emit('optionsChange', unref(getOptions));
+}
+</script>
+<template>
+  <div v-bind="{ ...$attrs }">
+    <component
+      :is="component"
+      v-bind="bindProps"
+      :placeholder="$attrs.placeholder"
+    >
+      <template v-for="item in Object.keys($slots)" #[item]="data">
+        <slot :name="item" v-bind="data || {}"></slot>
+      </template>
+      <template v-if="loadingSlot && loading" #[loadingSlot]>
+        <LoaderCircle class="animate-spin" />
+      </template>
+    </component>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/api-component/index.ts b/eims-ui/packages/effects/common-ui/src/components/api-component/index.ts
new file mode 100644
index 0000000..9815763
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/api-component/index.ts
@@ -0,0 +1 @@
+export { default as ApiComponent } from './api-component.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts b/eims-ui/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts
new file mode 100644
index 0000000..511fb3b
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts
@@ -0,0 +1,19 @@
+import type { CaptchaPoint } from '../types';
+
+import { reactive } from 'vue';
+
+export function useCaptchaPoints() {
+  const points = reactive<CaptchaPoint[]>([]);
+  function addPoint(point: CaptchaPoint) {
+    points.push(point);
+  }
+
+  function clearPoints() {
+    points.splice(0, points.length);
+  }
+  return {
+    addPoint,
+    clearPoints,
+    points,
+  };
+}
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/index.ts b/eims-ui/packages/effects/common-ui/src/components/captcha/index.ts
new file mode 100644
index 0000000..6ad68c4
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/index.ts
@@ -0,0 +1,6 @@
+export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue';
+export { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue';
+
+export { default as SliderCaptcha } from './slider-captcha/index.vue';
+export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue';
+export type * from './types';
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue
new file mode 100644
index 0000000..d4b1361
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue
@@ -0,0 +1,175 @@
+<script setup lang="ts">
+import type { CaptchaPoint, PointSelectionCaptchaProps } from '../types';
+
+import { RotateCw } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { VbenButton, VbenIconButton } from '@vben-core/shadcn-ui';
+
+import { useCaptchaPoints } from '../hooks/useCaptchaPoints';
+import CaptchaCard from './point-selection-captcha-card.vue';
+
+const props = withDefaults(defineProps<PointSelectionCaptchaProps>(), {
+  height: '220px',
+  hintImage: '',
+  hintText: '',
+  paddingX: '12px',
+  paddingY: '16px',
+  showConfirm: false,
+  title: '',
+  width: '300px',
+});
+const emit = defineEmits<{
+  click: [CaptchaPoint];
+  confirm: [Array<CaptchaPoint>, clear: () => void];
+  refresh: [];
+}>();
+const { addPoint, clearPoints, points } = useCaptchaPoints();
+
+if (!props.hintImage && !props.hintText) {
+  console.warn('At least one of hint image or hint text must be provided');
+}
+
+const POINT_OFFSET = 11;
+
+function getElementPosition(element: HTMLElement) {
+  const rect = element.getBoundingClientRect();
+  return {
+    x: rect.left + window.scrollX,
+    y: rect.top + window.scrollY,
+  };
+}
+
+function handleClick(e: MouseEvent) {
+  try {
+    const dom = e.currentTarget as HTMLElement;
+    if (!dom) throw new Error('Element not found');
+
+    const { x: domX, y: domY } = getElementPosition(dom);
+
+    const mouseX = e.clientX + window.scrollX;
+    const mouseY = e.clientY + window.scrollY;
+
+    if (typeof mouseX !== 'number' || typeof mouseY !== 'number') {
+      throw new TypeError('Mouse coordinates not found');
+    }
+
+    const xPos = mouseX - domX;
+    const yPos = mouseY - domY;
+
+    const rect = dom.getBoundingClientRect();
+
+    // 鐐瑰嚮浣嶇疆杈圭晫鏍¢獙
+    if (xPos < 0 || yPos < 0 || xPos > rect.width || yPos > rect.height) {
+      console.warn('Click position is out of the valid range');
+      return;
+    }
+
+    const x = Math.ceil(xPos);
+    const y = Math.ceil(yPos);
+
+    const point = {
+      i: points.length,
+      t: Date.now(),
+      x,
+      y,
+    };
+
+    addPoint(point);
+
+    emit('click', point);
+    e.stopPropagation();
+    e.preventDefault();
+  } catch (error) {
+    console.error('Error in handleClick:', error);
+  }
+}
+
+function clear() {
+  try {
+    clearPoints();
+  } catch (error) {
+    console.error('Error in clear:', error);
+  }
+}
+
+function handleRefresh() {
+  try {
+    clear();
+    emit('refresh');
+  } catch (error) {
+    console.error('Error in handleRefresh:', error);
+  }
+}
+
+function handleConfirm() {
+  if (!props.showConfirm) return;
+  try {
+    emit('confirm', points, clear);
+  } catch (error) {
+    console.error('Error in handleConfirm:', error);
+  }
+}
+</script>
+<template>
+  <CaptchaCard
+    :captcha-image="captchaImage"
+    :height="height"
+    :padding-x="paddingX"
+    :padding-y="paddingY"
+    :title="title"
+    :width="width"
+    @click="handleClick"
+  >
+    <template #title>
+      <slot name="title">{{ $t('ui.captcha.title') }}</slot>
+    </template>
+
+    <template #extra>
+      <VbenIconButton
+        :aria-label="$t('ui.captcha.refreshAriaLabel')"
+        class="ml-1"
+        @click="handleRefresh"
+      >
+        <RotateCw class="size-5" />
+      </VbenIconButton>
+      <VbenButton
+        v-if="showConfirm"
+        :aria-label="$t('ui.captcha.confirmAriaLabel')"
+        class="ml-2"
+        size="sm"
+        @click="handleConfirm"
+      >
+        {{ $t('ui.captcha.confirm') }}
+      </VbenButton>
+    </template>
+
+    <div
+      v-for="(point, index) in points"
+      :key="index"
+      :aria-label="$t('ui.captcha.pointAriaLabel') + (index + 1)"
+      :style="{
+        top: `${point.y - POINT_OFFSET}px`,
+        left: `${point.x - POINT_OFFSET}px`,
+      }"
+      class="bg-primary text-primary-50 border-primary-50 absolute z-20 flex h-5 w-5 cursor-default items-center justify-center rounded-full border-2"
+      role="button"
+      tabindex="0"
+    >
+      {{ index + 1 }}
+    </div>
+    <template #footer>
+      <img
+        v-if="hintImage"
+        :alt="$t('ui.captcha.alt')"
+        :src="hintImage"
+        class="border-border h-10 w-full rounded border"
+      />
+      <div
+        v-else-if="hintText"
+        class="border-border flex-center h-10 w-full rounded border"
+      >
+        {{ `${$t('ui.captcha.clickInOrder')}` + `銆�${hintText}銆慲 }}
+      </div>
+    </template>
+  </CaptchaCard>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue
new file mode 100644
index 0000000..0ece2bf
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue
@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import type { PointSelectionCaptchaCardProps } from '../types';
+
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+import {
+  Card,
+  CardContent,
+  CardFooter,
+  CardHeader,
+  CardTitle,
+} from '@vben-core/shadcn-ui';
+
+const props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), {
+  height: '220px',
+  paddingX: '12px',
+  paddingY: '16px',
+  title: '',
+  width: '300px',
+});
+
+const emit = defineEmits<{
+  click: [MouseEvent];
+}>();
+
+const parseValue = (value: number | string) => {
+  if (typeof value === 'number') {
+    return value;
+  }
+  const parsed = Number.parseFloat(value);
+  return Number.isNaN(parsed) ? 0 : parsed;
+};
+
+const rootStyles = computed(() => ({
+  padding: `${parseValue(props.paddingY)}px ${parseValue(props.paddingX)}px`,
+  width: `${parseValue(props.width) + parseValue(props.paddingX) * 2}px`,
+}));
+
+const captchaStyles = computed(() => {
+  return {
+    height: `${parseValue(props.height)}px`,
+    width: `${parseValue(props.width)}px`,
+  };
+});
+
+function handleClick(e: MouseEvent) {
+  emit('click', e);
+}
+</script>
+<template>
+  <Card :style="rootStyles" aria-labelledby="captcha-title" role="region">
+    <CardHeader class="p-0">
+      <CardTitle id="captcha-title" class="flex items-center justify-between">
+        <template v-if="$slots.title">
+          <slot name="title">{{ $t('ui.captcha.title') }}</slot>
+        </template>
+        <template v-else>
+          <span>{{ title }}</span>
+        </template>
+        <div class="flex items-center justify-end">
+          <slot name="extra"></slot>
+        </div>
+      </CardTitle>
+    </CardHeader>
+    <CardContent class="relative mt-2 flex w-full overflow-hidden rounded p-0">
+      <img
+        v-show="captchaImage"
+        :alt="$t('ui.captcha.alt')"
+        :src="captchaImage"
+        :style="captchaStyles"
+        class="relative z-10"
+        @click="handleClick"
+      />
+      <div class="absolute inset-0">
+        <slot></slot>
+      </div>
+    </CardContent>
+    <CardFooter class="mt-2 flex justify-between p-0">
+      <slot name="footer"></slot>
+    </CardFooter>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue
new file mode 100644
index 0000000..fa43493
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue
@@ -0,0 +1,243 @@
+<script setup lang="ts">
+import type {
+  CaptchaVerifyPassingData,
+  SliderCaptchaProps,
+  SliderRotateVerifyPassingData,
+} from '../types';
+
+import { reactive, unref, useTemplateRef, watch, watchEffect } from 'vue';
+
+import { $t } from '@vben/locales';
+import { cn } from '@vben-core/shared/utils';
+
+import { useTimeoutFn } from '@vueuse/core';
+
+import SliderCaptchaAction from './slider-captcha-action.vue';
+import SliderCaptchaBar from './slider-captcha-bar.vue';
+import SliderCaptchaContent from './slider-captcha-content.vue';
+
+const props = withDefaults(defineProps<SliderCaptchaProps>(), {
+  actionStyle: () => ({}),
+  barStyle: () => ({}),
+  contentStyle: () => ({}),
+  isSlot: false,
+  successText: '',
+  text: '',
+  wrapperStyle: () => ({}),
+});
+
+const emit = defineEmits<{
+  end: [MouseEvent | TouchEvent];
+  move: [SliderRotateVerifyPassingData];
+  start: [MouseEvent | TouchEvent];
+  success: [CaptchaVerifyPassingData];
+}>();
+
+const modelValue = defineModel<boolean>({ default: false });
+
+const state = reactive({
+  endTime: 0,
+  isMoving: false,
+  isPassing: false,
+  moveDistance: 0,
+  startTime: 0,
+  toLeft: false,
+});
+
+defineExpose({
+  resume,
+});
+
+const wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef');
+const barRef = useTemplateRef<typeof SliderCaptchaBar>('barRef');
+const contentRef = useTemplateRef<typeof SliderCaptchaContent>('contentRef');
+const actionRef = useTemplateRef<typeof SliderCaptchaAction>('actionRef');
+
+watch(
+  () => state.isPassing,
+  (isPassing) => {
+    if (isPassing) {
+      const { endTime, startTime } = state;
+      const time = (endTime - startTime) / 1000;
+      emit('success', { isPassing, time: time.toFixed(1) });
+      modelValue.value = isPassing;
+    }
+  },
+);
+
+watchEffect(() => {
+  state.isPassing = !!modelValue.value;
+});
+
+function getEventPageX(e: MouseEvent | TouchEvent): number {
+  if ('pageX' in e) {
+    return e.pageX;
+  } else if ('touches' in e && e.touches[0]) {
+    return e.touches[0].pageX;
+  }
+  return 0;
+}
+
+function handleDragStart(e: MouseEvent | TouchEvent) {
+  if (state.isPassing) {
+    return;
+  }
+  if (!actionRef.value) return;
+  emit('start', e);
+
+  state.moveDistance =
+    getEventPageX(e) -
+    Number.parseInt(
+      actionRef.value.getStyle().left.replace('px', '') || '0',
+      10,
+    );
+  state.startTime = Date.now();
+  state.isMoving = true;
+}
+
+function getOffset(actionEl: HTMLDivElement) {
+  const wrapperWidth = wrapperRef.value?.offsetWidth ?? 220;
+  const actionWidth = actionEl?.offsetWidth ?? 40;
+  const offset = wrapperWidth - actionWidth - 6;
+  return { actionWidth, offset, wrapperWidth };
+}
+
+function handleDragMoving(e: MouseEvent | TouchEvent) {
+  const { isMoving, moveDistance } = state;
+  if (isMoving) {
+    const actionEl = unref(actionRef);
+    const barEl = unref(barRef);
+    if (!actionEl || !barEl) return;
+    const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());
+    const moveX = getEventPageX(e) - moveDistance;
+
+    emit('move', {
+      event: e,
+      moveDistance,
+      moveX,
+    });
+    if (moveX > 0 && moveX <= offset) {
+      actionEl.setLeft(`${moveX}px`);
+      barEl.setWidth(`${moveX + actionWidth / 2}px`);
+    } else if (moveX > offset) {
+      actionEl.setLeft(`${wrapperWidth - actionWidth}px`);
+      barEl.setWidth(`${wrapperWidth - actionWidth / 2}px`);
+      if (!props.isSlot) {
+        checkPass();
+      }
+    }
+  }
+}
+
+function handleDragOver(e: MouseEvent | TouchEvent) {
+  const { isMoving, isPassing, moveDistance } = state;
+  if (isMoving && !isPassing) {
+    emit('end', e);
+    const actionEl = actionRef.value;
+    const barEl = unref(barRef);
+    if (!actionEl || !barEl) return;
+    const moveX = getEventPageX(e) - moveDistance;
+    const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());
+    if (moveX < offset) {
+      if (props.isSlot) {
+        setTimeout(() => {
+          if (modelValue.value) {
+            const contentEl = unref(contentRef);
+            if (contentEl) {
+              contentEl.getEl().style.width = `${Number.parseInt(barEl.getEl().style.width)}px`;
+            }
+          } else {
+            resume();
+          }
+        }, 0);
+      } else {
+        resume();
+      }
+    } else {
+      actionEl.setLeft(`${wrapperWidth - actionWidth}px`);
+      barEl.setWidth(`${wrapperWidth - actionWidth / 2}px`);
+      checkPass();
+    }
+    state.isMoving = false;
+  }
+}
+
+function checkPass() {
+  if (props.isSlot) {
+    resume();
+    return;
+  }
+  state.endTime = Date.now();
+  state.isPassing = true;
+  state.isMoving = false;
+}
+
+function resume() {
+  state.isMoving = false;
+  state.isPassing = false;
+  state.moveDistance = 0;
+  state.toLeft = false;
+  state.startTime = 0;
+  state.endTime = 0;
+  const actionEl = unref(actionRef);
+  const barEl = unref(barRef);
+  const contentEl = unref(contentRef);
+  if (!actionEl || !barEl || !contentEl) return;
+
+  contentEl.getEl().style.width = '100%';
+  state.toLeft = true;
+  useTimeoutFn(() => {
+    state.toLeft = false;
+    actionEl.setLeft('0');
+    barEl.setWidth('0');
+  }, 300);
+}
+</script>
+
+<template>
+  <div
+    ref="wrapperRef"
+    :class="
+      cn(
+        'border-border bg-background-deep relative flex h-10 w-full items-center overflow-hidden rounded-md border text-center',
+        props.class,
+      )
+    "
+    :style="wrapperStyle"
+    @mouseleave="handleDragOver"
+    @mousemove="handleDragMoving"
+    @mouseup="handleDragOver"
+    @touchend="handleDragOver"
+    @touchmove="handleDragMoving"
+  >
+    <SliderCaptchaBar
+      ref="barRef"
+      :bar-style="barStyle"
+      :to-left="state.toLeft"
+    />
+    <SliderCaptchaContent
+      ref="contentRef"
+      :content-style="contentStyle"
+      :is-passing="state.isPassing"
+      :success-text="successText || $t('ui.captcha.sliderSuccessText')"
+      :text="text || $t('ui.captcha.sliderDefaultText')"
+    >
+      <template v-if="$slots.text" #text>
+        <slot :is-passing="state.isPassing" name="text"></slot>
+      </template>
+    </SliderCaptchaContent>
+
+    <SliderCaptchaAction
+      ref="actionRef"
+      :action-style="actionStyle"
+      :is-passing="state.isPassing"
+      :to-left="state.toLeft"
+      @mousedown="handleDragStart"
+      @touchstart="handleDragStart"
+    >
+      <template v-if="$slots.actionIcon" #icon>
+        <slot :is-passing="state.isPassing" name="actionIcon"></slot>
+      </template>
+    </SliderCaptchaAction>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue
new file mode 100644
index 0000000..fe0b5aa
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue
@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed, ref, useTemplateRef } from 'vue';
+
+import { Check, ChevronsRight } from '@vben/icons';
+import { Slot } from '@vben-core/shadcn-ui';
+
+const props = defineProps<{
+  actionStyle: CSSProperties;
+  isPassing: boolean;
+  toLeft: boolean;
+}>();
+
+const actionRef = useTemplateRef<HTMLDivElement>('actionRef');
+
+const left = ref('0');
+
+const style = computed(() => {
+  const { actionStyle } = props;
+  return {
+    ...actionStyle,
+    left: left.value,
+  };
+});
+
+const isDragging = computed(() => {
+  const currentLeft = Number.parseInt(left.value as string);
+
+  return currentLeft > 10 && !props.isPassing;
+});
+
+defineExpose({
+  getEl: () => {
+    return actionRef.value;
+  },
+  getStyle: () => {
+    return actionRef?.value?.style;
+  },
+  setLeft: (val: string) => {
+    left.value = val;
+  },
+});
+</script>
+
+<template>
+  <div
+    ref="actionRef"
+    :class="{
+      'transition-width !left-0 duration-300': toLeft,
+      'rounded-md': isDragging,
+    }"
+    :style="style"
+    class="bg-background dark:bg-accent absolute left-0 top-0 flex h-full cursor-move items-center justify-center px-3.5 shadow-md"
+    name="captcha-action"
+  >
+    <Slot :is-passing="isPassing" class="text-foreground/60 size-4">
+      <slot name="icon">
+        <ChevronsRight v-if="!isPassing" />
+        <Check v-else />
+      </slot>
+    </Slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue
new file mode 100644
index 0000000..eacf684
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue
@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { computed, type CSSProperties, ref, useTemplateRef } from 'vue';
+
+const props = defineProps<{
+  barStyle: CSSProperties;
+  toLeft: boolean;
+}>();
+
+const barRef = useTemplateRef<HTMLDivElement>('barRef');
+
+const width = ref('0');
+
+const style = computed(() => {
+  const { barStyle } = props;
+  return {
+    ...barStyle,
+    width: width.value,
+  };
+});
+
+defineExpose({
+  getEl: () => {
+    return barRef.value;
+  },
+  setWidth: (val: string) => {
+    width.value = val;
+  },
+});
+</script>
+
+<template>
+  <div
+    ref="barRef"
+    :class="toLeft && 'transition-width !w-0 duration-300'"
+    :style="style"
+    class="bg-success absolute h-full"
+  ></div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue
new file mode 100644
index 0000000..5c481f2
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue
@@ -0,0 +1,52 @@
+<script setup lang="ts">
+import type { CSSProperties } from 'vue';
+import { computed, useTemplateRef } from 'vue';
+
+import { VbenSpineText } from '@vben-core/shadcn-ui';
+
+const props = defineProps<{
+  contentStyle: CSSProperties;
+  isPassing: boolean;
+  successText: string;
+  text: string;
+}>();
+
+const contentRef = useTemplateRef<HTMLDivElement>('contentRef');
+
+const style = computed(() => {
+  const { contentStyle } = props;
+
+  return {
+    ...contentStyle,
+  };
+});
+
+defineExpose({
+  getEl: () => {
+    return contentRef.value;
+  },
+});
+</script>
+
+<template>
+  <div
+    ref="contentRef"
+    :class="{
+      [$style.success]: isPassing,
+    }"
+    :style="style"
+    class="absolute top-0 flex size-full select-none items-center justify-center text-xs"
+  >
+    <slot name="text">
+      <VbenSpineText class="flex h-full items-center">
+        {{ isPassing ? successText : text }}
+      </VbenSpineText>
+    </slot>
+  </div>
+</template>
+
+<style module>
+.success {
+  -webkit-text-fill-color: hsl(0deg 0% 98%);
+}
+</style>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue
new file mode 100644
index 0000000..8894589
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue
@@ -0,0 +1,213 @@
+<script setup lang="ts">
+import type {
+  CaptchaVerifyPassingData,
+  SliderCaptchaActionType,
+  SliderRotateCaptchaProps,
+  SliderRotateVerifyPassingData,
+} from '../types';
+
+import { computed, reactive, unref, useTemplateRef, watch } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import { useTimeoutFn } from '@vueuse/core';
+
+import SliderCaptcha from '../slider-captcha/index.vue';
+
+const props = withDefaults(defineProps<SliderRotateCaptchaProps>(), {
+  defaultTip: '',
+  diffDegree: 20,
+  imageSize: 260,
+  maxDegree: 300,
+  minDegree: 120,
+  src: '',
+});
+
+const emit = defineEmits<{
+  success: [CaptchaVerifyPassingData];
+}>();
+
+const slideBarRef = useTemplateRef<SliderCaptchaActionType>('slideBarRef');
+
+const state = reactive({
+  currentRotate: 0,
+  dragging: false,
+  endTime: 0,
+  imgStyle: {},
+  isPassing: false,
+  randomRotate: 0,
+  showTip: false,
+  startTime: 0,
+  toOrigin: false,
+});
+
+const modalValue = defineModel<boolean>({ default: false });
+
+watch(
+  () => state.isPassing,
+  (isPassing) => {
+    if (isPassing) {
+      const { endTime, startTime } = state;
+      const time = (endTime - startTime) / 1000;
+      emit('success', { isPassing, time: time.toFixed(1) });
+    }
+    modalValue.value = isPassing;
+  },
+);
+
+const getImgWrapStyleRef = computed(() => {
+  const { imageSize, imageWrapperStyle } = props;
+  return {
+    height: `${imageSize}px`,
+    width: `${imageSize}px`,
+    ...imageWrapperStyle,
+  };
+});
+
+const getFactorRef = computed(() => {
+  const { maxDegree, minDegree } = props;
+  if (minDegree > maxDegree) {
+    console.warn('minDegree should not be greater than maxDegree');
+  }
+
+  if (minDegree === maxDegree) {
+    return Math.floor(1 + Math.random() * 1) / 10 + 1;
+  }
+  return 1;
+});
+
+function handleStart() {
+  state.startTime = Date.now();
+}
+
+function handleDragBarMove(data: SliderRotateVerifyPassingData) {
+  state.dragging = true;
+  const { imageSize, maxDegree } = props;
+  const { moveX } = data;
+  const denominator = imageSize!;
+  if (denominator === 0) {
+    return;
+  }
+  const currentRotate = Math.ceil(
+    (moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef),
+  );
+  state.currentRotate = currentRotate;
+  setImgRotate(state.randomRotate - currentRotate);
+}
+
+function handleImgOnLoad() {
+  const { maxDegree, minDegree } = props;
+  const ranRotate = Math.floor(
+    minDegree! + Math.random() * (maxDegree! - minDegree!),
+  ); // 鐢熸垚闅忔満瑙掑害
+  state.randomRotate = ranRotate;
+  setImgRotate(ranRotate);
+}
+
+function handleDragEnd() {
+  const { currentRotate, randomRotate } = state;
+  const { diffDegree } = props;
+
+  if (Math.abs(randomRotate - currentRotate) >= (diffDegree || 20)) {
+    setImgRotate(randomRotate);
+    state.toOrigin = true;
+    useTimeoutFn(() => {
+      state.toOrigin = false;
+      state.showTip = true;
+      //  鏃堕棿涓庡姩鐢绘椂闂翠繚鎸佷竴鑷�
+    }, 300);
+  } else {
+    checkPass();
+  }
+  state.showTip = true;
+  state.dragging = false;
+}
+
+function setImgRotate(deg: number) {
+  state.imgStyle = {
+    transform: `rotateZ(${deg}deg)`,
+  };
+}
+
+function checkPass() {
+  state.isPassing = true;
+  state.endTime = Date.now();
+}
+
+function resume() {
+  state.showTip = false;
+  const basicEl = unref(slideBarRef);
+  if (!basicEl) {
+    return;
+  }
+  state.isPassing = false;
+
+  basicEl.resume();
+  handleImgOnLoad();
+}
+
+const imgCls = computed(() => {
+  return state.toOrigin ? ['transition-transform duration-300'] : [];
+});
+
+const verifyTip = computed(() => {
+  return state.isPassing
+    ? $t('ui.captcha.sliderRotateSuccessTip', [
+        ((state.endTime - state.startTime) / 1000).toFixed(1),
+      ])
+    : $t('ui.captcha.sliderRotateFailTip');
+});
+
+defineExpose({
+  resume,
+});
+</script>
+
+<template>
+  <div class="relative flex flex-col items-center">
+    <div
+      :style="getImgWrapStyleRef"
+      class="border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md"
+    >
+      <img
+        :class="imgCls"
+        :src="src"
+        :style="state.imgStyle"
+        alt="verify"
+        class="w-full rounded-full"
+        @click="resume"
+        @load="handleImgOnLoad"
+      />
+      <div
+        class="absolute bottom-3 left-0 z-10 block h-7 w-full text-center text-xs leading-[30px] text-white"
+      >
+        <div
+          v-if="state.showTip"
+          :class="{
+            'bg-success/80': state.isPassing,
+            'bg-destructive/80': !state.isPassing,
+          }"
+        >
+          {{ verifyTip }}
+        </div>
+        <div v-if="!state.dragging" class="bg-black/30">
+          {{ defaultTip || $t('ui.captcha.sliderRotateDefaultTip') }}
+        </div>
+      </div>
+    </div>
+
+    <SliderCaptcha
+      ref="slideBarRef"
+      v-model="modalValue"
+      class="mt-5"
+      is-slot
+      @end="handleDragEnd"
+      @move="handleDragBarMove"
+      @start="handleStart"
+    >
+      <template v-for="(_, key) in $slots" :key="key" #[key]="slotProps">
+        <slot :name="key" v-bind="slotProps"></slot>
+      </template>
+    </SliderCaptcha>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/captcha/types.ts b/eims-ui/packages/effects/common-ui/src/components/captcha/types.ts
new file mode 100644
index 0000000..ba3adc7
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/captcha/types.ts
@@ -0,0 +1,175 @@
+import type { ClassType } from '@vben/types';
+
+import type { CSSProperties } from 'vue';
+
+export interface CaptchaData {
+  /**
+   * x
+   */
+  x: number;
+  /**
+   * y
+   */
+  y: number;
+  /**
+   * 鏃堕棿鎴�
+   */
+  t: number;
+}
+export interface CaptchaPoint extends CaptchaData {
+  /**
+   * 鏁版嵁绱㈠紩
+   */
+  i: number;
+}
+export interface PointSelectionCaptchaCardProps {
+  /**
+   * 楠岃瘉鐮佸浘鐗�
+   */
+  captchaImage: string;
+  /**
+   * 楠岃瘉鐮佸浘鐗囬珮搴�
+   * @default '220px'
+   */
+  height?: number | string;
+  /**
+   * 姘村钩鍐呰竟璺�
+   * @default '12px'
+   */
+  paddingX?: number | string;
+  /**
+   * 鍨傜洿鍐呰竟璺�
+   * @default '16px'
+   */
+  paddingY?: number | string;
+  /**
+   * 鏍囬
+   * @default '璇锋寜鍥句緷娆$偣鍑�'
+   */
+  title?: string;
+  /**
+   * 楠岃瘉鐮佸浘鐗囧搴�
+   * @default '300px'
+   */
+  width?: number | string;
+}
+
+export interface PointSelectionCaptchaProps
+  extends PointSelectionCaptchaCardProps {
+  /**
+   * 鏄惁灞曠ず纭畾鎸夐挳
+   * @default false
+   */
+  showConfirm?: boolean;
+  /**
+   * 鎻愮ず鍥剧墖
+   * @default ''
+   */
+  hintImage?: string;
+  /**
+   * 鎻愮ず鏂囨湰
+   * @default ''
+   */
+  hintText?: string;
+}
+
+export interface SliderCaptchaProps {
+  class?: ClassType;
+  /**
+   * @description 婊戝潡鐨勬牱寮�
+   * @default {}
+   */
+  actionStyle?: CSSProperties;
+
+  /**
+   * @description 婊戝潡鏉$殑鏍峰紡
+   * @default {}
+   */
+  barStyle?: CSSProperties;
+
+  /**
+   * @description 鍐呭鐨勬牱寮�
+   * @default {}
+   */
+  contentStyle?: CSSProperties;
+
+  /**
+   * @description 缁勪欢鐨勬牱寮�
+   * @default {}
+   */
+  wrapperStyle?: CSSProperties;
+
+  /**
+   * @description 鏄惁浣滀负鎻掓Ы浣跨敤锛岀敤浜庤仈鍔ㄧ粍浠讹紝鍙弬鑰冩棆杞牎楠岀粍浠�
+   * @default false
+   */
+  isSlot?: boolean;
+
+  /**
+   * @description 楠岃瘉鎴愬姛鐨勬彁绀�
+   * @default '楠岃瘉閫氳繃'
+   */
+  successText?: string;
+
+  /**
+   * @description 鎻愮ず鏂囧瓧
+   * @default '璇锋寜浣忔粦鍧楁嫋鍔�'
+   */
+  text?: string;
+}
+
+export interface SliderRotateCaptchaProps {
+  /**
+   * @description 鏃嬭浆鐨勮搴�
+   * @default 20
+   */
+  diffDegree?: number;
+
+  /**
+   * @description 鍥剧墖鐨勫搴�
+   * @default 260
+   */
+  imageSize?: number;
+
+  /**
+   * @description 鍥剧墖鐨勬牱寮�
+   * @default {}
+   */
+  imageWrapperStyle?: CSSProperties;
+
+  /**
+   * @description 鏈�澶ф棆杞搴�
+   * @default 270
+   */
+  maxDegree?: number;
+
+  /**
+   * @description 鏈�灏忔棆杞搴�
+   * @default 90
+   */
+  minDegree?: number;
+
+  /**
+   * @description 鍥剧墖鐨勫湴鍧�
+   */
+  src?: string;
+  /**
+   * @description 榛樿鎻愮ず鏂囨湰
+   */
+  defaultTip?: string;
+}
+
+export interface CaptchaVerifyPassingData {
+  isPassing: boolean;
+  time: number | string;
+}
+
+export interface SliderCaptchaActionType {
+  resume: () => void;
+}
+
+export interface SliderRotateVerifyPassingData {
+  event: MouseEvent | TouchEvent;
+  moveDistance: number;
+  moveX: number;
+}
diff --git a/eims-ui/packages/effects/common-ui/src/components/code-mirror/code-mirror.vue b/eims-ui/packages/effects/common-ui/src/components/code-mirror/code-mirror.vue
new file mode 100644
index 0000000..a449f08
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/code-mirror/code-mirror.vue
@@ -0,0 +1,68 @@
+<script setup lang="ts">
+import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
+import CodeMirror from 'vue-codemirror6';
+
+import { usePreferences } from '@vben/preferences';
+
+import { javascript } from '@codemirror/lang-javascript';
+import { oneDark } from '@codemirror/theme-one-dark';
+
+import { type LanguageSupport, languageSupportMap } from './data';
+
+const props = withDefaults(
+  defineProps<{
+    /**
+     * 璇█
+     */
+    language: LanguageSupport;
+    /**
+     * 鍙
+     */
+    readonly?: boolean;
+  }>(),
+  {
+    language: 'js',
+    readonly: false,
+  },
+);
+
+const codeMirrorRef =
+  useTemplateRef<InstanceType<typeof CodeMirror>>('codeMirrorRef');
+
+const { isDark } = usePreferences();
+
+const modelValue = defineModel({ default: '', type: String });
+
+const lang = computed(() => languageSupportMap[props.language] ?? javascript());
+
+// 閫氳繃v-if 鍗歌浇鎸傝浇杈惧埌鏇存柊璇█鐨勭洰鐨�
+const langChanged = ref(true);
+watch(
+  () => props.language,
+  () => {
+    langChanged.value = false;
+    nextTick(() => (langChanged.value = true));
+  },
+);
+/** 鎻掍欢 */
+const extensions = [oneDark];
+</script>
+
+<template>
+  <CodeMirror
+    v-if="langChanged"
+    v-bind="$attrs"
+    ref="codeMirrorRef"
+    v-model="modelValue"
+    :dark="isDark"
+    :extensions="extensions"
+    :lang="lang"
+    :readonly="props.readonly"
+    basic
+    wrap
+  >
+    <template v-for="slotName in Object.keys($slots)" #[slotName]="scope">
+      <slot :name="slotName" v-bind="scope ?? {}"></slot>
+    </template>
+  </CodeMirror>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/code-mirror/data.ts b/eims-ui/packages/effects/common-ui/src/components/code-mirror/data.ts
new file mode 100644
index 0000000..3824bee
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/code-mirror/data.ts
@@ -0,0 +1,24 @@
+import { html } from '@codemirror/lang-html';
+import { java } from '@codemirror/lang-java';
+import { javascript } from '@codemirror/lang-javascript';
+import { sql } from '@codemirror/lang-sql';
+import { vue } from '@codemirror/lang-vue';
+import { xml } from '@codemirror/lang-xml';
+
+/**
+ * 鍙嚜琛屽畨瑁呬緷璧栧苟鎸夋牸寮忛厤缃� 鍑芥暟褰㈠弬涓洪厤缃」
+ * @see https://github.com/logue/vue-codemirror6?tab=readme-ov-file#supported-languages Language Support椤�
+ */
+export const languageSupportMap = {
+  html: html(),
+  java: java(),
+  js: javascript(),
+  jsx: javascript({ jsx: true }),
+  sql: sql(),
+  ts: javascript({ typescript: true }),
+  tsx: javascript({ jsx: true, typescript: true }),
+  vue: vue(),
+  xml: xml(),
+};
+
+export type LanguageSupport = keyof typeof languageSupportMap;
diff --git a/eims-ui/packages/effects/common-ui/src/components/code-mirror/index.ts b/eims-ui/packages/effects/common-ui/src/components/code-mirror/index.ts
new file mode 100644
index 0000000..c9c7c65
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/code-mirror/index.ts
@@ -0,0 +1,2 @@
+export { default as CodeMirror } from './code-mirror.vue';
+export type { LanguageSupport } from './data';
diff --git a/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue b/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue
new file mode 100644
index 0000000..bd4f1fd
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue
@@ -0,0 +1,142 @@
+<script setup lang="ts">
+import { computed, type CSSProperties, ref, watchEffect } from 'vue';
+
+import { VbenTooltip } from '@vben-core/shadcn-ui';
+
+interface Props {
+  /**
+   * 鏄惁鍚敤鐐瑰嚮鏂囨湰灞曞紑鍏ㄩ儴
+   * @default false
+   */
+  expand?: boolean;
+  /**
+   * 鏂囨湰鏈�澶ц鏁�
+   * @default 1
+   */
+  line?: number;
+  /**
+   * 鏂囨湰鏈�澶у搴�
+   * @default '100%'
+   */
+  maxWidth?: number | string;
+  /**
+   * 鎻愮ず妗嗕綅缃�
+   * @default 'top'
+   */
+  placement?: 'bottom' | 'left' | 'right' | 'top';
+  /**
+   * 鏄惁鍚敤鏂囨湰鎻愮ず妗�
+   * @default true
+   */
+  tooltip?: boolean;
+  /**
+   * 鎻愮ず妗嗚儗鏅鑹诧紝浼樺厛绾ч珮浜� overlayStyle
+   */
+  tooltipBackgroundColor?: string;
+  /**
+   * 鎻愮ず鏂囨湰瀛椾綋棰滆壊锛屼紭鍏堢骇楂樹簬 overlayStyle
+   */
+  tooltipColor?: string;
+  /**
+   * 鎻愮ず鏂囨湰瀛椾綋澶у皬锛屽崟浣峱x锛屼紭鍏堢骇楂樹簬 overlayStyle
+   */
+  tooltipFontSize?: number;
+  /**
+   * 鎻愮ず妗嗗唴瀹规渶澶у搴︼紝鍗曚綅px锛岄粯璁や笉璁剧疆鏃讹紝鎻愮ず鏂囨湰鍐呭鑷姩涓庡睍绀烘枃鏈搴︿繚鎸佷竴鑷�
+   */
+  tooltipMaxWidth?: number;
+  /**
+   * 鎻愮ず妗嗗唴瀹瑰尯鍩熸牱寮�
+   * @default { textAlign: 'justify' }
+   */
+  tooltipOverlayStyle?: CSSProperties;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  expand: false,
+  line: 1,
+  maxWidth: '100%',
+  placement: 'top',
+  tooltip: true,
+  tooltipBackgroundColor: '',
+  tooltipColor: '',
+  tooltipFontSize: 14,
+  tooltipMaxWidth: undefined,
+  tooltipOverlayStyle: () => ({ textAlign: 'justify' }),
+});
+const emit = defineEmits<{ expandChange: [boolean] }>();
+
+const textMaxWidth = computed(() => {
+  if (typeof props.maxWidth === 'number') {
+    return `${props.maxWidth}px`;
+  }
+  return props.maxWidth;
+});
+const ellipsis = ref();
+const isExpand = ref(false);
+const defaultTooltipMaxWidth = ref();
+
+watchEffect(
+  () => {
+    if (props.tooltip && ellipsis.value) {
+      defaultTooltipMaxWidth.value =
+        props.tooltipMaxWidth ?? ellipsis.value.offsetWidth + 24;
+    }
+  },
+  { flush: 'post' },
+);
+function onExpand() {
+  isExpand.value = !isExpand.value;
+  emit('expandChange', isExpand.value);
+}
+
+function handleExpand() {
+  props.expand && onExpand();
+}
+</script>
+<template>
+  <div>
+    <VbenTooltip
+      :content-style="{
+        ...tooltipOverlayStyle,
+        maxWidth: `${defaultTooltipMaxWidth}px`,
+        fontSize: `${tooltipFontSize}px`,
+        color: tooltipColor,
+        backgroundColor: tooltipBackgroundColor,
+      }"
+      :disabled="!props.tooltip || isExpand"
+      :side="placement"
+    >
+      <slot name="tooltip">
+        <slot></slot>
+      </slot>
+
+      <template #trigger>
+        <div
+          ref="ellipsis"
+          :class="{
+            '!cursor-pointer': expand,
+            ['block truncate']: line === 1,
+            [$style.ellipsisMultiLine]: line > 1,
+          }"
+          :style="{
+            '-webkit-line-clamp': isExpand ? '' : line,
+            'max-width': textMaxWidth,
+          }"
+          class="cursor-text overflow-hidden"
+          @click="handleExpand"
+          v-bind="$attrs"
+        >
+          <slot></slot>
+        </div>
+      </template>
+    </VbenTooltip>
+  </div>
+</template>
+
+<style module>
+.ellipsisMultiLine {
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+}
+</style>
diff --git a/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/index.ts b/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/index.ts
new file mode 100644
index 0000000..67a236c
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/ellipsis-text/index.ts
@@ -0,0 +1 @@
+export { default as EllipsisText } from './ellipsis-text.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue b/eims-ui/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue
new file mode 100644
index 0000000..323ce44
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue
@@ -0,0 +1,230 @@
+<script setup lang="ts">
+import { computed, h, ref, type VNode, watch, watchEffect } from 'vue';
+
+import { usePagination } from '@vben/hooks';
+import { EmptyIcon, Grip, listIcons } from '@vben/icons';
+import { $t } from '@vben/locales';
+import {
+  Button,
+  Pagination,
+  PaginationEllipsis,
+  PaginationFirst,
+  PaginationLast,
+  PaginationList,
+  PaginationListItem,
+  PaginationNext,
+  PaginationPrev,
+  VbenIcon,
+  VbenIconButton,
+  VbenPopover,
+} from '@vben-core/shadcn-ui';
+
+import { refDebounced } from '@vueuse/core';
+
+interface Props {
+  pageSize?: number;
+  prefix?: string;
+  /**
+   * 鍥炬爣鍒楄〃
+   */
+  icons?: string[];
+  /** Input缁勪欢 */
+  inputComponent?: VNode;
+  /** 鍥炬爣鎻掓Ы鍚嶏紝棰勮鍥炬爣灏嗚娓叉煋鍒版鎻掓Ы涓� */
+  iconSlot?: string;
+  /** input缁勪欢鐨勫�煎睘鎬у悕绉� */
+  modelValueProp?: string;
+  /** 鍥炬爣鏍峰紡 */
+  iconClass?: string;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  prefix: 'ant-design',
+  pageSize: 36,
+  icons: () => [],
+  inputComponent: () => h('div'),
+  iconSlot: 'default',
+  iconClass: 'size-4',
+  modelValueProp: 'value',
+});
+
+const emit = defineEmits<{
+  change: [string];
+}>();
+
+const modelValue = defineModel({ default: '', type: String });
+
+const visible = ref(false);
+const currentSelect = ref('');
+const currentPage = ref(1);
+const keyword = ref('');
+const keywordDebounce = refDebounced(keyword, 300);
+const currentList = computed(() => {
+  try {
+    if (props.prefix) {
+      const icons = listIcons('', props.prefix);
+      if (icons.length === 0) {
+        console.warn(`No icons found for prefix: ${props.prefix}`);
+      }
+      return icons;
+    } else {
+      return props.icons;
+    }
+  } catch (error) {
+    console.error('Failed to load icons:', error);
+    return [];
+  }
+});
+
+const showList = computed(() => {
+  return currentList.value.filter((item) =>
+    item.includes(keywordDebounce.value),
+  );
+});
+
+const { paginationList, total, setCurrentPage } = usePagination(
+  showList,
+  props.pageSize,
+);
+
+watchEffect(() => {
+  currentSelect.value = modelValue.value;
+});
+
+watch(
+  () => currentSelect.value,
+  (v) => {
+    emit('change', v);
+  },
+);
+
+const handleClick = (icon: string) => {
+  currentSelect.value = icon;
+  modelValue.value = icon;
+  close();
+};
+
+const handlePageChange = (page: number) => {
+  currentPage.value = page;
+  setCurrentPage(page);
+};
+
+function toggleOpenState() {
+  visible.value = !visible.value;
+}
+
+function open() {
+  visible.value = true;
+}
+
+function close() {
+  visible.value = false;
+}
+
+function onKeywordChange(v: string) {
+  keyword.value = v;
+}
+
+const searchInputProps = computed(() => {
+  return {
+    placeholder: $t('ui.iconPicker.search'),
+    [props.modelValueProp]: keyword.value,
+    [`onUpdate:${props.modelValueProp}`]: onKeywordChange,
+    class: 'mx-2',
+  };
+});
+
+defineExpose({ toggleOpenState, open, close });
+</script>
+<template>
+  <VbenPopover
+    v-model:open="visible"
+    :content-props="{ align: 'end', alignOffset: -11, sideOffset: 8 }"
+    content-class="p-0 pt-3"
+  >
+    <template #trigger>
+      <component
+        :is="inputComponent"
+        :[modelValueProp]="currentSelect"
+        :placeholder="$t('ui.iconPicker.placeholder')"
+      >
+        <template #[iconSlot]>
+          <VbenIcon :icon="currentSelect || Grip" class="size-4" />
+        </template>
+      </component>
+    </template>
+    <div class="mb-2 flex w-full">
+      <component :is="inputComponent" v-bind="searchInputProps" />
+    </div>
+
+    <template v-if="paginationList.length > 0">
+      <div class="grid max-h-[360px] w-full grid-cols-6 justify-items-center">
+        <VbenIconButton
+          v-for="(item, index) in paginationList"
+          :key="index"
+          :tooltip="item"
+          tooltip-side="top"
+          @click="handleClick(item)"
+        >
+          <VbenIcon
+            :class="{
+              'text-primary transition-all': currentSelect === item,
+            }"
+            :icon="item"
+          />
+        </VbenIconButton>
+      </div>
+      <div
+        v-if="total >= pageSize"
+        class="flex-center flex justify-end overflow-hidden border-t py-2 pr-3"
+      >
+        <Pagination
+          :items-per-page="36"
+          :sibling-count="1"
+          :total="total"
+          show-edges
+          size="small"
+          @update:page="handlePageChange"
+        >
+          <PaginationList
+            v-slot="{ items }"
+            class="flex w-full items-center gap-1"
+          >
+            <PaginationFirst class="size-5" />
+            <PaginationPrev class="size-5" />
+            <template v-for="(item, index) in items">
+              <PaginationListItem
+                v-if="item.type === 'page'"
+                :key="index"
+                :value="item.value"
+                as-child
+              >
+                <Button
+                  :variant="item.value === currentPage ? 'default' : 'outline'"
+                  class="size-5 p-0 text-sm"
+                >
+                  {{ item.value }}
+                </Button>
+              </PaginationListItem>
+              <PaginationEllipsis
+                v-else
+                :key="item.type"
+                :index="index"
+                class="size-5"
+              />
+            </template>
+            <PaginationNext class="size-5" />
+            <PaginationLast class="size-5" />
+          </PaginationList>
+        </Pagination>
+      </div>
+    </template>
+
+    <template v-else>
+      <div class="flex-col-center text-muted-foreground min-h-[150px] w-full">
+        <EmptyIcon class="size-10" />
+        <div class="mt-1 text-sm">{{ $t('common.noData') }}</div>
+      </div>
+    </template>
+  </VbenPopover>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/icon-picker/index.ts b/eims-ui/packages/effects/common-ui/src/components/icon-picker/index.ts
new file mode 100644
index 0000000..3dabc86
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/icon-picker/index.ts
@@ -0,0 +1 @@
+export { default as IconPicker } from './icon-picker.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/index.ts b/eims-ui/packages/effects/common-ui/src/components/index.ts
new file mode 100644
index 0000000..70f9e57
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/index.ts
@@ -0,0 +1,23 @@
+export * from './api-component';
+export * from './captcha';
+export * from './code-mirror';
+export * from './ellipsis-text';
+export * from './icon-picker';
+export * from './json-preview';
+export * from './markdown';
+export * from './page';
+export * from './resize';
+export * from '@vben-core/form-ui';
+export * from '@vben-core/popup-ui';
+
+// 缁欐枃妗g敤
+export {
+  VbenButton,
+  VbenCountToAnimator,
+  VbenInputPassword,
+  VbenLoading,
+  VbenPinInput,
+  VbenSpinner,
+} from '@vben-core/shadcn-ui';
+
+export { globalShareState } from '@vben-core/shared/global-state';
diff --git a/eims-ui/packages/effects/common-ui/src/components/json-preview/index.ts b/eims-ui/packages/effects/common-ui/src/components/json-preview/index.ts
new file mode 100644
index 0000000..332d22c
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/json-preview/index.ts
@@ -0,0 +1 @@
+export { default as JsonPreview } from './json-preview.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/json-preview/json-preview.vue b/eims-ui/packages/effects/common-ui/src/components/json-preview/json-preview.vue
new file mode 100644
index 0000000..58c7aaa
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/json-preview/json-preview.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import VueJsonPretty from 'vue-json-pretty';
+
+import 'vue-json-pretty/lib/styles.css';
+
+defineProps<{ data: any }>();
+</script>
+
+<template>
+  <VueJsonPretty :data="data" :deep="3" :show-length="true" path="res" />
+</template>
+
+<style lang="less">
+html[class='dark'] {
+  .vjs-tree-node:hover {
+    background-color: #333;
+  }
+}
+</style>
diff --git a/eims-ui/packages/effects/common-ui/src/components/markdown/editor.vue b/eims-ui/packages/effects/common-ui/src/components/markdown/editor.vue
new file mode 100644
index 0000000..47ffbe0
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/markdown/editor.vue
@@ -0,0 +1,136 @@
+<script setup lang="ts">
+import {
+  onBeforeUnmount,
+  onMounted,
+  type PropType,
+  shallowRef,
+  useTemplateRef,
+  watch,
+} from 'vue';
+
+import { usePreferences } from '@vben/preferences';
+
+import Vditor from 'vditor';
+
+import 'vditor/dist/index.css';
+
+const props = defineProps({
+  // 缂栬緫鍣ㄩ珮搴�
+  height: {
+    // string鎴栬�卬umber绫诲瀷
+    type: [String, Number],
+    default: 500,
+  },
+  /**
+   * 缂栬緫妯″紡銆傞粯璁ゅ��: 'wysiwyg'
+   * wysiwyg: 鎵�瑙佸嵆鎵�寰�
+   * ir: 鍗虫椂娓叉煋
+   * sv: 鍒嗗睆棰勮
+   */
+  mode: {
+    type: String as PropType<'ir' | 'sv' | 'wysiwyg'>,
+    default: 'wysiwyg',
+  },
+  // 缂栬緫鍣ㄥ敮涓�ID 缂撳瓨浣跨敤 鍙褰曚笂娆¤緭鍏�
+  id: {
+    type: String,
+    required: false,
+    default: '',
+    validator(value, props) {
+      if (!value && props.enableCache) {
+        console.warn('The id is required when enableCache is true');
+        return false;
+      }
+      return true;
+    },
+  },
+  enableCache: {
+    type: Boolean,
+    default: false,
+  },
+  // 绂佺敤缂栬緫鍣�
+  disabled: {
+    type: Boolean,
+    default: false,
+  },
+  // 鍏朵粬閰嶇疆椤�
+  options: {
+    type: Object as PropType<IOptions>,
+    default: () => ({}),
+  },
+});
+
+const emit = defineEmits<{
+  // 鍒濆鍖� cdn鍔犺浇瀹屾垚
+  mounted: [];
+}>();
+
+// 鎸傝浇鑺傜偣
+const vditorRef = useTemplateRef('vditorRef');
+// 缂栬緫鍣ㄥ疄渚�
+const vditorInstance = shallowRef<null | Vditor>(null);
+
+// 鐩戝惉涓婚鍒囨崲x
+const { isDark, locale } = usePreferences();
+watch(isDark, (dark) => {
+  const theme = dark ? 'dark' : 'light';
+  vditorInstance.value?.setTheme(dark ? 'dark' : 'classic', theme, theme);
+});
+
+// 鍙屽悜缁戝畾
+const content = defineModel('value', {
+  type: String,
+  default: '',
+});
+/**
+ * 涓轰簡淇濇寔澶栭儴鐩存帴(v-model)涓庣紪杈戝櫒鍐呴儴鐨勫悓姝�
+ * 娉ㄦ剰: 涓嬮潰鐨刬nput浜嬩欢涔熶細瑙﹀彂watch
+ */
+watch(content, (value) => {
+  vditorInstance.value?.setValue(value);
+});
+
+// 鐩戝惉绂佺敤
+function changeDisabled(disabled: boolean) {
+  if (disabled) {
+    vditorInstance.value?.disabled();
+  } else {
+    vditorInstance.value?.enable();
+  }
+}
+watch(() => props.disabled, changeDisabled);
+
+onMounted(() => {
+  vditorInstance.value = new Vditor(vditorRef.value!, {
+    mode: props.mode,
+    value: content.value,
+    height: props.height,
+    lang: locale.value.replace('-', '_') as any,
+    cache: {
+      enable: props.enableCache,
+      id: props.id,
+    },
+    theme: isDark.value ? 'dark' : 'classic',
+    // 鎵嬪姩鍝嶅簲寮�
+    input(value) {
+      content.value = value;
+    },
+    // 鍔犺浇瀹屾垚鐨勪簨浠�
+    after() {
+      // 闇�瑕佸垵濮嬪寲灏辩鐢ㄧ殑鎯呭喌
+      changeDisabled(props.disabled);
+      emit('mounted');
+    },
+    ...props.options,
+  });
+});
+
+onBeforeUnmount(() => {
+  vditorInstance.value?.destroy();
+  vditorInstance.value = null;
+});
+</script>
+
+<template>
+  <div ref="vditorRef"></div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/markdown/index.ts b/eims-ui/packages/effects/common-ui/src/components/markdown/index.ts
new file mode 100644
index 0000000..dfea14d
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/markdown/index.ts
@@ -0,0 +1,2 @@
+export { default as MarkdownEditor } from './editor.vue';
+export { default as MarkdownPreviewer } from './preview.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/markdown/preview.vue b/eims-ui/packages/effects/common-ui/src/components/markdown/preview.vue
new file mode 100644
index 0000000..3ead292
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/markdown/preview.vue
@@ -0,0 +1,107 @@
+<script setup lang="ts">
+import {
+  onBeforeUnmount,
+  onMounted,
+  type PropType,
+  shallowRef,
+  useTemplateRef,
+  watch,
+} from 'vue';
+
+import { usePreferences } from '@vben/preferences';
+
+import Vditor from 'vditor';
+
+import 'vditor/dist/index.css';
+
+const props = defineProps({
+  // 缂栬緫鍣ㄩ珮搴�
+  height: {
+    // string鎴栬�卬umber绫诲瀷
+    type: [String, Number],
+    default: 500,
+  },
+  // 鍏朵粬閰嶇疆椤�
+  options: {
+    type: Object as PropType<IOptions>,
+    default: () => ({}),
+  },
+});
+
+const emit = defineEmits<{
+  // 鍒濆鍖� cdn鍔犺浇瀹屾垚
+  mounted: [];
+}>();
+
+// 鎸傝浇鑺傜偣
+const vditorRef = useTemplateRef('vditorRef');
+// 缂栬緫鍣ㄥ疄渚�
+const vditorInstance = shallowRef<null | Vditor>(null);
+
+// 鐩戝惉涓婚鍒囨崲x
+const { isDark, locale } = usePreferences();
+watch(isDark, (dark) => {
+  const theme = dark ? 'dark' : 'light';
+  vditorInstance.value?.setTheme(dark ? 'dark' : 'classic', theme, theme);
+});
+
+// 鍙屽悜缁戝畾
+const content = defineModel('value', {
+  type: String,
+  default: '',
+});
+
+/**
+ * 鐢变簬涓嶈兘杈撳叆 闇�瑕佷娇鐢╳atch鐩戝惉
+ */
+watch(content, (value) => {
+  vditorInstance.value?.setValue(value);
+});
+
+onMounted(() => {
+  vditorInstance.value = new Vditor(vditorRef.value!, {
+    mode: 'wysiwyg',
+    value: content.value,
+    height: props.height,
+    // 寮�鍚墦瀛楁満妯″紡
+    // typewriterMode: true,
+    lang: locale.value.replace('-', '_') as any,
+    cache: {
+      enable: false,
+    },
+    theme: isDark.value ? 'dark' : 'classic',
+    // 棰勮(鍙妯″紡) 涓嶆樉绀哄伐鍏锋爮
+    toolbar: [],
+    // 鍔犺浇瀹屾垚鐨勪簨浠�
+    after() {
+      emit('mounted');
+      // 绂佺敤缂栬緫鍣�
+      vditorInstance.value?.disabled();
+    },
+    ...props.options,
+  });
+});
+
+onBeforeUnmount(() => {
+  vditorInstance.value?.destroy();
+  vditorInstance.value = null;
+});
+</script>
+
+<template>
+  <div ref="vditorRef"></div>
+</template>
+
+<style>
+.vditor-wysiwyg pre.vditor-reset[contenteditable='false'] {
+  cursor: unset;
+  opacity: 1;
+}
+
+/**
+dark妯″紡鏍峰紡闇�瑕侀噸缃�
+*/
+.vditor--dark .vditor-reset {
+  color: #d1d5da;
+}
+</style>
diff --git a/eims-ui/packages/effects/common-ui/src/components/page/__tests__/page.test.ts b/eims-ui/packages/effects/common-ui/src/components/page/__tests__/page.test.ts
new file mode 100644
index 0000000..776fe6a
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/page/__tests__/page.test.ts
@@ -0,0 +1,88 @@
+import { mount } from '@vue/test-utils';
+import { describe, expect, it } from 'vitest';
+
+import { Page } from '..';
+
+describe('page.vue', () => {
+  it('renders title when passed', () => {
+    const wrapper = mount(Page, {
+      props: {
+        title: 'Test Title',
+      },
+    });
+
+    expect(wrapper.text()).toContain('Test Title');
+  });
+
+  it('renders description when passed', () => {
+    const wrapper = mount(Page, {
+      props: {
+        description: 'Test Description',
+      },
+    });
+
+    expect(wrapper.text()).toContain('Test Description');
+  });
+
+  it('renders default slot content', () => {
+    const wrapper = mount(Page, {
+      slots: {
+        default: '<p>Default Slot Content</p>',
+      },
+    });
+
+    expect(wrapper.html()).toContain('<p>Default Slot Content</p>');
+  });
+
+  it('renders footer slot when showFooter is true', () => {
+    const wrapper = mount(Page, {
+      props: {
+        showFooter: true,
+      },
+      slots: {
+        footer: '<p>Footer Slot Content</p>',
+      },
+    });
+
+    expect(wrapper.html()).toContain('<p>Footer Slot Content</p>');
+  });
+
+  it('applies the custom contentClass', () => {
+    const wrapper = mount(Page, {
+      props: {
+        contentClass: 'custom-class',
+      },
+    });
+
+    const contentDiv = wrapper.find('.p-4');
+    expect(contentDiv.classes()).toContain('custom-class');
+  });
+
+  it('does not render title slot if title prop is provided', () => {
+    const wrapper = mount(Page, {
+      props: {
+        title: 'Test Title',
+      },
+      slots: {
+        title: '<p>Title Slot Content</p>',
+      },
+    });
+
+    expect(wrapper.text()).toContain('Title Slot Content');
+    expect(wrapper.html()).not.toContain('Test Title');
+  });
+
+  it('does not render description slot if description prop is provided', () => {
+    const wrapper = mount(Page, {
+      props: {
+        description: 'Test Description',
+      },
+      slots: {
+        description: '<p>Description Slot Content</p>',
+      },
+    });
+
+    expect(wrapper.text()).toContain('Description Slot Content');
+    expect(wrapper.html()).not.toContain('Test Description');
+  });
+});
diff --git a/eims-ui/packages/effects/common-ui/src/components/page/index.ts b/eims-ui/packages/effects/common-ui/src/components/page/index.ts
new file mode 100644
index 0000000..65bf3c6
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/page/index.ts
@@ -0,0 +1 @@
+export { default as Page } from './page.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/page/page.vue b/eims-ui/packages/effects/common-ui/src/components/page/page.vue
new file mode 100644
index 0000000..e955478
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/page/page.vue
@@ -0,0 +1,123 @@
+<script setup lang="ts">
+import {
+  computed,
+  nextTick,
+  onMounted,
+  ref,
+  type StyleValue,
+  useTemplateRef,
+} from 'vue';
+
+import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/shared/constants';
+import { cn } from '@vben-core/shared/utils';
+
+interface Props {
+  title?: string;
+  description?: string;
+  contentClass?: string;
+  padding?: boolean;
+  /**
+   * 鏍规嵁content鍙楂樺害鑷�傚簲
+   */
+  autoContentHeight?: boolean;
+  headerClass?: string;
+  footerClass?: string;
+}
+
+defineOptions({
+  name: 'Page',
+});
+
+const { autoContentHeight = false, padding = true } = defineProps<Props>();
+
+const headerHeight = ref(0);
+const footerHeight = ref(0);
+const shouldAutoHeight = ref(false);
+
+
+
+const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
+const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
+
+const contentStyle = computed<StyleValue>(() => {
+  if (autoContentHeight) {
+    return {
+      height: `calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT}) - ${headerHeight.value}px)`,
+      overflowY: shouldAutoHeight.value ? 'auto' : 'unset',
+    };
+  }
+  return {};
+});
+
+async function calcContentHeight() {
+  if (!autoContentHeight) {
+    return;
+  }
+  await nextTick();
+  headerHeight.value = headerRef.value?.offsetHeight || 0;
+  footerHeight.value = footerRef.value?.offsetHeight || 0;
+  setTimeout(() => {
+    shouldAutoHeight.value = true;
+  }, 30);
+}
+
+onMounted(() => {
+  calcContentHeight();
+});
+</script>
+
+<template>
+  <div class="relative">
+    <div
+      v-if="
+        description ||
+        $slots.description ||
+        title ||
+        $slots.title ||
+        $slots.extra
+      "
+      ref="headerRef"
+      :class="
+        cn(
+          'bg-card border-border relative flex items-end border-b px-6 py-4',
+          headerClass,
+        )
+      "
+    >
+      <div class="flex-auto">
+        <slot name="title">
+          <div v-if="title" class="mb-2 flex text-lg font-semibold">
+            {{ title }}
+          </div>
+        </slot>
+
+        <slot name="description">
+          <p v-if="description" class="text-muted-foreground">
+            {{ description }}
+          </p>
+        </slot>
+      </div>
+
+      <div v-if="$slots.extra">
+        <slot name="extra"></slot>
+      </div>
+    </div>
+
+    <div :class="[contentClass, { 'p-4': padding }]" :style="contentStyle" class="h-full">
+      <slot></slot>
+    </div>
+
+    <div
+      v-if="$slots.footer"
+      ref="footerRef"
+      :class="
+        cn(
+          'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
+          footerClass,
+        )
+      "
+    >
+      <slot name="footer"></slot>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/components/resize/index.ts b/eims-ui/packages/effects/common-ui/src/components/resize/index.ts
new file mode 100644
index 0000000..f937522
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/resize/index.ts
@@ -0,0 +1 @@
+export { default as VResize } from './resize.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/components/resize/resize.vue b/eims-ui/packages/effects/common-ui/src/components/resize/resize.vue
new file mode 100644
index 0000000..aaf89ea
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/components/resize/resize.vue
@@ -0,0 +1,1122 @@
+<script lang="ts" setup>
+/**
+ * This components is refactored from vue-drag-resize: https://github.com/kirillmurashov/vue-drag-resize
+ */
+
+import {
+  computed,
+  getCurrentInstance,
+  nextTick,
+  onBeforeUnmount,
+  onMounted,
+  ref,
+  toRefs,
+  watch,
+} from 'vue';
+
+const props = defineProps({
+  stickSize: {
+    type: Number,
+    default: 8,
+  },
+  parentScaleX: {
+    type: Number,
+    default: 1,
+  },
+  parentScaleY: {
+    type: Number,
+    default: 1,
+  },
+  isActive: {
+    type: Boolean,
+    default: false,
+  },
+  preventActiveBehavior: {
+    type: Boolean,
+    default: false,
+  },
+  isDraggable: {
+    type: Boolean,
+    default: true,
+  },
+  isResizable: {
+    type: Boolean,
+    default: true,
+  },
+  aspectRatio: {
+    type: Boolean,
+    default: false,
+  },
+  parentLimitation: {
+    type: Boolean,
+    default: false,
+  },
+  snapToGrid: {
+    type: Boolean,
+    default: false,
+  },
+  gridX: {
+    type: Number,
+    default: 50,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  gridY: {
+    type: Number,
+    default: 50,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  parentW: {
+    type: Number,
+    default: 0,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  parentH: {
+    type: Number,
+    default: 0,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  w: {
+    type: [String, Number],
+    default: 200,
+    validator(val: number) {
+      return typeof val === 'string' ? val === 'auto' : val >= 0;
+    },
+  },
+  h: {
+    type: [String, Number],
+    default: 200,
+    validator(val: number) {
+      return typeof val === 'string' ? val === 'auto' : val >= 0;
+    },
+  },
+  minw: {
+    type: Number,
+    default: 50,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  minh: {
+    type: Number,
+    default: 50,
+    validator(val: number) {
+      return val >= 0;
+    },
+  },
+  x: {
+    type: Number,
+    default: 0,
+    validator(val: number) {
+      return typeof val === 'number';
+    },
+  },
+  y: {
+    type: Number,
+    default: 0,
+    validator(val: number) {
+      return typeof val === 'number';
+    },
+  },
+  z: {
+    type: [String, Number],
+    default: 'auto',
+    validator(val: number) {
+      return typeof val === 'string' ? val === 'auto' : val >= 0;
+    },
+  },
+  dragHandle: {
+    type: String,
+    default: null,
+  },
+  dragCancel: {
+    type: String,
+    default: null,
+  },
+  sticks: {
+    type: Array<'bl' | 'bm' | 'br' | 'ml' | 'mr' | 'tl' | 'tm' | 'tr'>,
+    default() {
+      return ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'];
+    },
+  },
+  axis: {
+    type: String,
+    default: 'both',
+    validator(val: string) {
+      return ['both', 'none', 'x', 'y'].includes(val);
+    },
+  },
+  contentClass: {
+    type: String,
+    required: false,
+    default: '',
+  },
+});
+
+const emit = defineEmits([
+  'clicked',
+  'dragging',
+  'dragstop',
+  'resizing',
+  'resizestop',
+  'activated',
+  'deactivated',
+]);
+
+const styleMapping = {
+  y: {
+    t: 'top',
+    m: 'marginTop',
+    b: 'bottom',
+  },
+  x: {
+    l: 'left',
+    m: 'marginLeft',
+    r: 'right',
+  },
+};
+
+function addEvents(events: Map<string, (...args: any[]) => void>) {
+  events.forEach((cb, eventName) => {
+    document.documentElement.addEventListener(eventName, cb);
+  });
+}
+
+function removeEvents(events: Map<string, (...args: any[]) => void>) {
+  events.forEach((cb, eventName) => {
+    document.documentElement.removeEventListener(eventName, cb);
+  });
+}
+
+const {
+  stickSize,
+  parentScaleX,
+  parentScaleY,
+  isActive,
+  preventActiveBehavior,
+  isDraggable,
+  isResizable,
+  aspectRatio,
+  parentLimitation,
+  snapToGrid,
+  gridX,
+  gridY,
+  parentW,
+  parentH,
+  w,
+  h,
+  minw,
+  minh,
+  x,
+  y,
+  z,
+  dragHandle,
+  dragCancel,
+  sticks,
+  axis,
+  contentClass,
+} = toRefs(props);
+
+// states
+const active = ref(false);
+const zIndex = ref<null | number>(null);
+const parentWidth = ref<null | number>(null);
+const parentHeight = ref<null | number>(null);
+const left = ref<null | number>(null);
+const top = ref<null | number>(null);
+const right = ref<null | number>(null);
+const bottom = ref<null | number>(null);
+
+const aspectFactor = ref<null | number>(null);
+
+// state end
+
+const stickDrag = ref(false);
+const bodyDrag = ref(false);
+const dimensionsBeforeMove = ref({
+  pointerX: 0,
+  pointerY: 0,
+  x: 0,
+  y: 0,
+  w: 0,
+  h: 0,
+  top: 0,
+  right: 0,
+  bottom: 0,
+  left: 0,
+  width: 0,
+  height: 0,
+});
+const limits = ref({
+  left: { min: null as null | number, max: null as null | number },
+  right: { min: null as null | number, max: null as null | number },
+  top: { min: null as null | number, max: null as null | number },
+  bottom: { min: null as null | number, max: null as null | number },
+});
+const currentStick = ref<null | string>(null);
+
+const parentElement = ref<HTMLElement | null>(null);
+
+const width = computed(() => parentWidth.value! - left.value! - right.value!);
+
+const height = computed(() => parentHeight.value! - top.value! - bottom.value!);
+
+const rect = computed(() => ({
+  left: Math.round(left.value!),
+  top: Math.round(top.value!),
+  width: Math.round(width.value),
+  height: Math.round(height.value),
+}));
+
+const saveDimensionsBeforeMove = ({
+  pointerX,
+  pointerY,
+}: {
+  pointerX: number;
+  pointerY: number;
+}) => {
+  dimensionsBeforeMove.value.pointerX = pointerX;
+  dimensionsBeforeMove.value.pointerY = pointerY;
+
+  dimensionsBeforeMove.value.left = left.value as number;
+  dimensionsBeforeMove.value.right = right.value as number;
+  dimensionsBeforeMove.value.top = top.value as number;
+  dimensionsBeforeMove.value.bottom = bottom.value as number;
+
+  dimensionsBeforeMove.value.width = width.value as number;
+  dimensionsBeforeMove.value.height = height.value as number;
+
+  aspectFactor.value = width.value / height.value;
+};
+
+const sideCorrectionByLimit = (
+  limit: { max: number; min: number },
+  current: number,
+) => {
+  let value = current;
+
+  if (limit.min !== null && current < limit.min) {
+    value = limit.min;
+  } else if (limit.max !== null && limit.max < current) {
+    value = limit.max;
+  }
+
+  return value;
+};
+
+const rectCorrectionByLimit = (rect: {
+  newBottom: number;
+  newLeft: number;
+  newRight: number;
+  newTop: number;
+}) => {
+  // const { limits } = this;
+  let { newRight, newLeft, newBottom, newTop } = rect;
+
+  type RectRange = {
+    max: number;
+    min: number;
+  };
+
+  newLeft = sideCorrectionByLimit(limits.value.left as RectRange, newLeft);
+  newRight = sideCorrectionByLimit(limits.value.right as RectRange, newRight);
+  newTop = sideCorrectionByLimit(limits.value.top as RectRange, newTop);
+  newBottom = sideCorrectionByLimit(
+    limits.value.bottom as RectRange,
+    newBottom,
+  );
+
+  return {
+    newLeft,
+    newRight,
+    newTop,
+    newBottom,
+  };
+};
+
+const rectCorrectionByAspectRatio = (rect: {
+  newBottom: number;
+  newLeft: number;
+  newRight: number;
+  newTop: number;
+}) => {
+  let { newLeft, newRight, newTop, newBottom } = rect;
+  // const { parentWidth, parentHeight, currentStick, aspectFactor, dimensionsBeforeMove } = this;
+
+  let newWidth = parentWidth.value! - newLeft - newRight;
+  let newHeight = parentHeight.value! - newTop - newBottom;
+
+  if (currentStick.value![1] === 'm') {
+    const deltaHeight = newHeight - dimensionsBeforeMove.value.height;
+
+    newLeft -= (deltaHeight * aspectFactor.value!) / 2;
+    newRight -= (deltaHeight * aspectFactor.value!) / 2;
+  } else if (currentStick.value![0] === 'm') {
+    const deltaWidth = newWidth - dimensionsBeforeMove.value.width;
+
+    newTop -= deltaWidth / aspectFactor.value! / 2;
+    newBottom -= deltaWidth / aspectFactor.value! / 2;
+  } else if (newWidth / newHeight > aspectFactor.value!) {
+    newWidth = aspectFactor.value! * newHeight;
+
+    if (currentStick.value![1] === 'l') {
+      newLeft = parentWidth.value! - newRight - newWidth;
+    } else {
+      newRight = parentWidth.value! - newLeft - newWidth;
+    }
+  } else {
+    newHeight = newWidth / aspectFactor.value!;
+
+    if (currentStick.value![0] === 't') {
+      newTop = parentHeight.value! - newBottom - newHeight;
+    } else {
+      newBottom = parentHeight.value! - newTop - newHeight;
+    }
+  }
+
+  return { newLeft, newRight, newTop, newBottom };
+};
+
+const stickMove = (delta: { x: number; y: number }) => {
+  let newTop = dimensionsBeforeMove.value.top;
+  let newBottom = dimensionsBeforeMove.value.bottom;
+  let newLeft = dimensionsBeforeMove.value.left;
+  let newRight = dimensionsBeforeMove.value.right;
+  switch (currentStick.value![0]) {
+    case 'b': {
+      newBottom = dimensionsBeforeMove.value.bottom + delta.y;
+
+      if (snapToGrid.value) {
+        newBottom =
+          (parentHeight.value as number) -
+          Math.round(
+            ((parentHeight.value as number) - newBottom) / gridY.value,
+          ) *
+            gridY.value;
+      }
+
+      break;
+    }
+
+    case 't': {
+      newTop = dimensionsBeforeMove.value.top - delta.y;
+
+      if (snapToGrid.value) {
+        newTop = Math.round(newTop / gridY.value) * gridY.value;
+      }
+
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+
+  switch (currentStick.value![1]) {
+    case 'l': {
+      newLeft = dimensionsBeforeMove.value.left - delta.x;
+
+      if (snapToGrid.value) {
+        newLeft = Math.round(newLeft / gridX.value) * gridX.value;
+      }
+
+      break;
+    }
+
+    case 'r': {
+      newRight = dimensionsBeforeMove.value.right + delta.x;
+
+      if (snapToGrid.value) {
+        newRight =
+          (parentWidth.value as number) -
+          Math.round(((parentWidth.value as number) - newRight) / gridX.value) *
+            gridX.value;
+      }
+
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+
+  ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByLimit({
+    newLeft,
+    newRight,
+    newTop,
+    newBottom,
+  }));
+
+  if (aspectRatio.value) {
+    ({ newLeft, newRight, newTop, newBottom } = rectCorrectionByAspectRatio({
+      newLeft,
+      newRight,
+      newTop,
+      newBottom,
+    }));
+  }
+
+  left.value = newLeft;
+  right.value = newRight;
+  top.value = newTop;
+  bottom.value = newBottom;
+
+  emit('resizing', rect.value);
+};
+
+const stickUp = () => {
+  stickDrag.value = false;
+  // dimensionsBeforeMove.value = {
+  //   pointerX: 0,
+  //   pointerY: 0,
+  //   x: 0,
+  //   y: 0,
+  //   w: 0,
+  //   h: 0,
+  // };
+
+  Object.assign(dimensionsBeforeMove.value, {
+    pointerX: 0,
+    pointerY: 0,
+    x: 0,
+    y: 0,
+    w: 0,
+    h: 0,
+  });
+
+  limits.value = {
+    left: { min: null, max: null },
+    right: { min: null, max: null },
+    top: { min: null, max: null },
+    bottom: { min: null, max: null },
+  };
+
+  emit('resizing', rect.value);
+  emit('resizestop', rect.value);
+};
+
+const calcDragLimitation = () => {
+  return {
+    left: { min: 0, max: (parentWidth.value as number) - width.value },
+    right: { min: 0, max: (parentWidth.value as number) - width.value },
+    top: { min: 0, max: (parentHeight.value as number) - height.value },
+    bottom: { min: 0, max: (parentHeight.value as number) - height.value },
+  };
+};
+
+const calcResizeLimits = () => {
+  // const { aspectFactor, width, height, bottom, top, left, right } = this;
+
+  const parentLim = parentLimitation.value ? 0 : null;
+
+  if (aspectRatio.value) {
+    if (minw.value / minh.value > (aspectFactor.value as number)) {
+      minh.value = minw.value / (aspectFactor.value as number);
+    } else {
+      minw.value = ((aspectFactor.value as number) * minh.value) as number;
+    }
+  }
+
+  const limits = {
+    left: {
+      min: parentLim,
+      max: (left.value as number) + (width.value - minw.value),
+    },
+    right: {
+      min: parentLim,
+      max: (right.value as number) + (width.value - minw.value),
+    },
+    top: {
+      min: parentLim,
+      max: (top.value as number) + (height.value - minh.value),
+    },
+    bottom: {
+      min: parentLim,
+      max: (bottom.value as number) + (height.value - minh.value),
+    },
+  };
+
+  if (aspectRatio.value) {
+    const aspectLimits = {
+      left: {
+        min:
+          left.value! -
+          Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,
+        max:
+          left.value! +
+          ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,
+      },
+      right: {
+        min:
+          right.value! -
+          Math.min(top.value!, bottom.value!) * aspectFactor.value! * 2,
+        max:
+          right.value! +
+          ((height.value - minh.value!) / 2) * aspectFactor.value! * 2,
+      },
+      top: {
+        min:
+          top.value! -
+          (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,
+        max:
+          top.value! +
+          ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,
+      },
+      bottom: {
+        min:
+          bottom.value! -
+          (Math.min(left.value!, right.value!) / aspectFactor.value!) * 2,
+        max:
+          bottom.value! +
+          ((width.value - minw.value) / 2 / aspectFactor.value!) * 2,
+      },
+    };
+
+    if (currentStick.value![0] === 'm') {
+      limits.left = {
+        min: Math.max(limits.left.min!, aspectLimits.left.min),
+        max: Math.min(limits.left.max, aspectLimits.left.max),
+      };
+      limits.right = {
+        min: Math.max(limits.right.min!, aspectLimits.right.min),
+        max: Math.min(limits.right.max, aspectLimits.right.max),
+      };
+    } else if (currentStick.value![1] === 'm') {
+      limits.top = {
+        min: Math.max(limits.top.min!, aspectLimits.top.min),
+        max: Math.min(limits.top.max, aspectLimits.top.max),
+      };
+      limits.bottom = {
+        min: Math.max(limits.bottom.min!, aspectLimits.bottom.min),
+        max: Math.min(limits.bottom.max, aspectLimits.bottom.max),
+      };
+    }
+  }
+
+  return limits;
+};
+
+const positionStyle = computed(() => ({
+  top: `${top.value}px`,
+  left: `${left.value}px`,
+  zIndex: zIndex.value!,
+}));
+
+const sizeStyle = computed(() => ({
+  width: w.value === 'auto' ? 'auto' : `${width.value}px`,
+  height: h.value === 'auto' ? 'auto' : `${height.value}px`,
+}));
+
+const stickStyles = computed(() => (stick: string) => {
+  const stickStyle = {
+    width: `${stickSize.value / parentScaleX.value}px`,
+    height: `${stickSize.value / parentScaleY.value}px`,
+  };
+  stickStyle[
+    styleMapping.y[stick[0] as 'b' | 'm' | 't'] as 'height' | 'width'
+  ] = `${stickSize.value / parentScaleX.value / -2}px`;
+  stickStyle[
+    styleMapping.x[stick[1] as 'l' | 'm' | 'r'] as 'height' | 'width'
+  ] = `${stickSize.value / parentScaleX.value / -2}px`;
+  return stickStyle;
+});
+
+const bodyMove = (delta: { x: number; y: number }) => {
+  let newTop = dimensionsBeforeMove.value.top - delta.y;
+  let newBottom = dimensionsBeforeMove.value.bottom + delta.y;
+  let newLeft = dimensionsBeforeMove.value.left - delta.x;
+  let newRight = dimensionsBeforeMove.value.right + delta.x;
+
+  if (snapToGrid.value) {
+    let alignTop = true;
+    let alignLeft = true;
+
+    let diffT = newTop - Math.floor(newTop / gridY.value) * gridY.value;
+    let diffB =
+      (parentHeight.value as number) -
+      newBottom -
+      Math.floor(((parentHeight.value as number) - newBottom) / gridY.value) *
+        gridY.value;
+    let diffL = newLeft - Math.floor(newLeft / gridX.value) * gridX.value;
+    let diffR =
+      (parentWidth.value as number) -
+      newRight -
+      Math.floor(((parentWidth.value as number) - newRight) / gridX.value) *
+        gridX.value;
+
+    if (diffT > gridY.value / 2) {
+      diffT -= gridY.value;
+    }
+    if (diffB > gridY.value / 2) {
+      diffB -= gridY.value;
+    }
+    if (diffL > gridX.value / 2) {
+      diffL -= gridX.value;
+    }
+    if (diffR > gridX.value / 2) {
+      diffR -= gridX.value;
+    }
+
+    if (Math.abs(diffB) < Math.abs(diffT)) {
+      alignTop = false;
+    }
+    if (Math.abs(diffR) < Math.abs(diffL)) {
+      alignLeft = false;
+    }
+
+    newTop -= alignTop ? diffT : diffB;
+    newBottom = (parentHeight.value as number) - height.value - newTop;
+    newLeft -= alignLeft ? diffL : diffR;
+    newRight = (parentWidth.value as number) - width.value - newLeft;
+  }
+
+  ({
+    newLeft: left.value,
+    newRight: right.value,
+    newTop: top.value,
+    newBottom: bottom.value,
+  } = rectCorrectionByLimit({ newLeft, newRight, newTop, newBottom }));
+
+  emit('dragging', rect.value);
+};
+
+const bodyUp = () => {
+  bodyDrag.value = false;
+  emit('dragging', rect.value);
+  emit('dragstop', rect.value);
+
+  // dimensionsBeforeMove.value = { pointerX: 0, pointerY: 0, x: 0, y: 0, w: 0, h: 0 };
+  Object.assign(dimensionsBeforeMove.value, {
+    pointerX: 0,
+    pointerY: 0,
+    x: 0,
+    y: 0,
+    w: 0,
+    h: 0,
+  });
+
+  limits.value = {
+    left: { min: null, max: null },
+    right: { min: null, max: null },
+    top: { min: null, max: null },
+    bottom: { min: null, max: null },
+  };
+};
+
+const stickDown = (
+  stick: string,
+  ev: { pageX: any; pageY: any; touches?: any },
+  force = false,
+) => {
+  if ((!isResizable.value || !active.value) && !force) {
+    return;
+  }
+
+  stickDrag.value = true;
+
+  const pointerX = ev.pageX === undefined ? ev.touches[0].pageX : ev.pageX;
+  const pointerY = ev.pageY === undefined ? ev.touches[0].pageY : ev.pageY;
+
+  saveDimensionsBeforeMove({ pointerX, pointerY });
+
+  currentStick.value = stick;
+
+  limits.value = calcResizeLimits();
+};
+
+const move = (ev: MouseEvent & TouchEvent) => {
+  if (!stickDrag.value && !bodyDrag.value) {
+    return;
+  }
+
+  ev.stopPropagation();
+
+  // touches 鍏煎鎬т唬鐮�
+  const pageX = ev.pageX === undefined ? ev.touches![0]!.pageX : ev.pageX;
+  const pageY = ev.pageY === undefined ? ev.touches![0]!.pageY : ev.pageY;
+
+  const delta = {
+    x: (dimensionsBeforeMove.value.pointerX - pageX) / parentScaleX.value,
+    y: (dimensionsBeforeMove.value.pointerY - pageY) / parentScaleY.value,
+  };
+
+  if (stickDrag.value) {
+    stickMove(delta);
+  }
+
+  if (bodyDrag.value) {
+    switch (axis.value) {
+      case 'none': {
+        return;
+      }
+      case 'x': {
+        delta.y = 0;
+
+        break;
+      }
+      case 'y': {
+        delta.x = 0;
+
+        break;
+      }
+      // No default
+    }
+    bodyMove(delta);
+  }
+};
+
+const up = () => {
+  if (stickDrag.value) {
+    stickUp();
+  } else if (bodyDrag.value) {
+    bodyUp();
+  }
+};
+
+const deselect = () => {
+  if (preventActiveBehavior.value) {
+    return;
+  }
+  active.value = false;
+};
+
+const domEvents = ref(
+  new Map([
+    ['mousedown', deselect],
+    ['mouseleave', up],
+    ['mousemove', move],
+    ['mouseup', up],
+    ['touchcancel', up],
+    ['touchend', up],
+    ['touchmove', move],
+    ['touchstart', up],
+  ]),
+);
+
+const container = ref<HTMLDivElement>();
+
+onMounted(() => {
+  const currentInstance = getCurrentInstance();
+  const $el = currentInstance?.vnode.el as HTMLElement;
+
+  parentElement.value = $el?.parentNode as HTMLElement;
+  parentWidth.value = parentW.value ?? parentElement.value?.clientWidth;
+  parentHeight.value = parentH.value ?? parentElement.value?.clientHeight;
+
+  left.value = x.value;
+  top.value = y.value;
+  right.value = (parentWidth.value -
+    (w.value === 'auto' ? container.value!.scrollWidth : (w.value as number)) -
+    left.value) as number;
+  bottom.value = (parentHeight.value -
+    (h.value === 'auto' ? container.value!.scrollHeight : (h.value as number)) -
+    top.value) as number;
+
+  addEvents(domEvents.value);
+
+  if (dragHandle.value) {
+    [...($el?.querySelectorAll(dragHandle.value) || [])].forEach(
+      (dragHandle) => {
+        (dragHandle as HTMLElement).dataset.dragHandle = String(
+          currentInstance?.uid,
+        );
+      },
+    );
+  }
+
+  if (dragCancel.value) {
+    [...($el?.querySelectorAll(dragCancel.value) || [])].forEach(
+      (cancelHandle) => {
+        (cancelHandle as HTMLElement).dataset.dragCancel = String(
+          currentInstance?.uid,
+        );
+      },
+    );
+  }
+});
+
+onBeforeUnmount(() => {
+  removeEvents(domEvents.value);
+});
+
+const bodyDown = (ev: MouseEvent & TouchEvent) => {
+  const { target, button } = ev;
+
+  if (!preventActiveBehavior.value) {
+    active.value = true;
+  }
+
+  if (button && button !== 0) {
+    return;
+  }
+
+  emit('clicked', ev);
+
+  if (!active.value) {
+    return;
+  }
+
+  if (
+    dragHandle.value &&
+    (target! as HTMLElement).dataset.dragHandle !==
+      getCurrentInstance()?.uid.toString()
+  ) {
+    return;
+  }
+
+  if (
+    dragCancel.value &&
+    (target! as HTMLElement).dataset.dragCancel ===
+      getCurrentInstance()?.uid.toString()
+  ) {
+    return;
+  }
+
+  if (ev.stopPropagation !== undefined) {
+    ev.stopPropagation();
+  }
+
+  if (ev.preventDefault !== undefined) {
+    ev.preventDefault();
+  }
+
+  if (isDraggable.value) {
+    bodyDrag.value = true;
+  }
+
+  const pointerX = ev.pageX === undefined ? ev.touches[0]!.pageX : ev.pageX;
+  const pointerY = ev.pageY === undefined ? ev.touches[0]!.pageY : ev.pageY;
+
+  saveDimensionsBeforeMove({ pointerX, pointerY });
+
+  if (parentLimitation.value) {
+    limits.value = calcDragLimitation();
+  }
+};
+
+watch(
+  () => active.value,
+  (isActive) => {
+    if (isActive) {
+      emit('activated');
+    } else {
+      emit('deactivated');
+    }
+  },
+);
+
+watch(
+  () => isActive.value,
+  (val) => {
+    active.value = val;
+  },
+  { immediate: true },
+);
+
+watch(
+  () => z.value,
+  (val) => {
+    if ((val as number) >= 0 || val === 'auto') {
+      zIndex.value = val as number;
+    }
+  },
+  { immediate: true },
+);
+
+watch(
+  () => x.value,
+  (newVal, oldVal) => {
+    if (stickDrag.value || bodyDrag.value || newVal === left.value) {
+      return;
+    }
+
+    const delta = oldVal - newVal;
+
+    bodyDown({ pageX: left.value!, pageY: top.value! } as MouseEvent &
+      TouchEvent);
+    bodyMove({ x: delta, y: 0 });
+
+    nextTick(() => {
+      bodyUp();
+    });
+  },
+);
+
+watch(
+  () => y.value,
+  (newVal, oldVal) => {
+    if (stickDrag.value || bodyDrag.value || newVal === top.value) {
+      return;
+    }
+
+    const delta = oldVal - newVal;
+
+    bodyDown({ pageX: left.value, pageY: top.value } as MouseEvent &
+      TouchEvent);
+    bodyMove({ x: 0, y: delta });
+
+    nextTick(() => {
+      bodyUp();
+    });
+  },
+);
+
+watch(
+  () => w.value,
+  (newVal, oldVal) => {
+    if (stickDrag.value || bodyDrag.value || newVal === width.value) {
+      return;
+    }
+
+    const stick = 'mr';
+    const delta = (oldVal as number) - (newVal as number);
+
+    stickDown(
+      stick,
+      { pageX: right.value, pageY: top.value! + height.value / 2 },
+      true,
+    );
+    stickMove({ x: delta, y: 0 });
+
+    nextTick(() => {
+      stickUp();
+    });
+  },
+);
+
+watch(
+  () => h.value,
+  (newVal, oldVal) => {
+    if (stickDrag.value || bodyDrag.value || newVal === height.value) {
+      return;
+    }
+
+    const stick = 'bm';
+    const delta = (oldVal as number) - (newVal as number);
+
+    stickDown(
+      stick,
+      { pageX: left.value! + width.value / 2, pageY: bottom.value },
+      true,
+    );
+    stickMove({ x: 0, y: delta });
+
+    nextTick(() => {
+      stickUp();
+    });
+  },
+);
+
+watch(
+  () => parentW.value,
+  (val) => {
+    right.value = val - width.value - left.value!;
+    parentWidth.value = val;
+  },
+);
+
+watch(
+  () => parentH.value,
+  (val) => {
+    bottom.value = val - height.value - top.value!;
+    parentHeight.value = val;
+  },
+);
+</script>
+
+<template>
+  <div
+    :class="`${active || isActive ? 'active' : 'inactive'} ${contentClass ? contentClass : ''}`"
+    :style="positionStyle"
+    class="resize"
+    @mousedown="bodyDown($event as TouchEvent & MouseEvent)"
+    @touchend="up"
+    @touchstart="bodyDown($event as TouchEvent & MouseEvent)"
+  >
+    <div ref="container" :style="sizeStyle" class="content-container">
+      <slot></slot>
+    </div>
+    <div
+      v-for="(stick, index) of sticks"
+      :key="index"
+      :class="[`resize-stick-${stick}`, isResizable ? '' : 'not-resizable']"
+      :style="stickStyles(stick)"
+      class="resize-stick"
+      @mousedown.stop.prevent="
+        stickDown(stick, $event as TouchEvent & MouseEvent)
+      "
+      @touchstart.stop.prevent="
+        stickDown(stick, $event as TouchEvent & MouseEvent)
+      "
+    ></div>
+  </div>
+</template>
+
+<style lang="css" scoped>
+.resize {
+  position: absolute;
+  box-sizing: border-box;
+}
+
+.resize.active::before {
+  position: absolute;
+  top: 0;
+  left: 0;
+  box-sizing: border-box;
+  width: 100%;
+  height: 100%;
+  content: '';
+  outline: 1px dashed #d6d6d6;
+}
+
+.resize-stick {
+  position: absolute;
+  box-sizing: border-box;
+  font-size: 1px;
+  background: #fff;
+  border: 1px solid #6c6c6c;
+  box-shadow: 0 0 2px #bbb;
+}
+
+.inactive .resize-stick {
+  display: none;
+}
+
+.resize-stick-tl,
+.resize-stick-br {
+  cursor: nwse-resize;
+}
+
+.resize-stick-tm,
+.resize-stick-bm {
+  left: 50%;
+  cursor: ns-resize;
+}
+
+.resize-stick-tr,
+.resize-stick-bl {
+  cursor: nesw-resize;
+}
+
+.resize-stick-ml,
+.resize-stick-mr {
+  top: 50%;
+  cursor: ew-resize;
+}
+
+.resize-stick.not-resizable {
+  display: none;
+}
+
+.content-container {
+  position: relative;
+  display: block;
+}
+</style>
diff --git a/eims-ui/packages/effects/common-ui/src/index.ts b/eims-ui/packages/effects/common-ui/src/index.ts
new file mode 100644
index 0000000..27bd718
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/index.ts
@@ -0,0 +1,2 @@
+export * from './components';
+export * from './ui';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/about/about.ts b/eims-ui/packages/effects/common-ui/src/ui/about/about.ts
new file mode 100644
index 0000000..c4cf957
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/about/about.ts
@@ -0,0 +1,14 @@
+import type { Component } from 'vue';
+
+interface AboutProps {
+  description?: string;
+  name?: string;
+  title?: string;
+}
+
+interface DescriptionItem {
+  content: Component | string;
+  title: string;
+}
+
+export type { AboutProps, DescriptionItem };
diff --git a/eims-ui/packages/effects/common-ui/src/ui/about/about.vue b/eims-ui/packages/effects/common-ui/src/ui/about/about.vue
new file mode 100644
index 0000000..9395d70
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/about/about.vue
@@ -0,0 +1,182 @@
+<script setup lang="ts">
+import type { AboutProps, DescriptionItem } from './about';
+
+import { h } from 'vue';
+
+import {
+  VBEN_DOC_URL,
+  VBEN_GITHUB_URL,
+  VBEN_PREVIEW_URL,
+} from '@vben/constants';
+import { VbenRenderContent } from '@vben-core/shadcn-ui';
+
+import { Page } from '../../components';
+
+interface Props extends AboutProps {}
+
+defineOptions({
+  name: 'AboutUI',
+});
+
+withDefaults(defineProps<Props>(), {
+  description:
+    '鏄竴涓幇浠e寲寮�绠卞嵆鐢ㄧ殑涓悗鍙拌В鍐虫柟妗堬紝閲囩敤鏈�鏂扮殑鎶�鏈爤锛屽寘鎷� Vue 3.0銆乂ite銆乀ailwindCSS 鍜� TypeScript 绛夊墠娌挎妧鏈紝浠g爜瑙勮寖涓ヨ皑锛屾彁渚涗赴瀵岀殑閰嶇疆閫夐」锛屾棬鍦ㄤ负涓ぇ鍨嬮」鐩殑寮�鍙戞彁渚涚幇鎴愮殑寮�绠卞嵆鐢ㄨВ鍐虫柟妗堝強涓板瘜鐨勭ず渚嬶紝鍚屾椂锛屽畠涔熸槸瀛︿範鍜屾繁鍏ュ墠绔妧鏈殑涓�涓瀬浣崇ず渚嬨��',
+  name: 'Vben Admin',
+  title: '鍏充簬椤圭洰',
+});
+
+declare global {
+  const __VBEN_ADMIN_METADATA__: {
+    authorEmail: string;
+    authorName: string;
+    authorUrl: string;
+    buildTime: string;
+    dependencies: Record<string, string>;
+    description: string;
+    devDependencies: Record<string, string>;
+    homepage: string;
+    license: string;
+    repositoryUrl: string;
+    version: string;
+  };
+}
+
+const renderLink = (href: string, text: string) =>
+  h(
+    'a',
+    { href, target: '_blank', class: 'vben-link' },
+    { default: () => text },
+  );
+
+const {
+  authorEmail,
+  authorName,
+  authorUrl,
+  buildTime,
+  dependencies = {},
+  devDependencies = {},
+  homepage,
+  license,
+  version,
+  // vite inject-metadata 鎻掍欢娉ㄥ叆鐨勫叏灞�鍙橀噺
+} = __VBEN_ADMIN_METADATA__ || {};
+
+const vbenDescriptionItems: DescriptionItem[] = [
+  {
+    content: version,
+    title: '鐗堟湰鍙�',
+  },
+  {
+    content: license,
+    title: '寮�婧愯鍙崗璁�',
+  },
+  {
+    content: buildTime,
+    title: '鏈�鍚庢瀯寤烘椂闂�',
+  },
+  {
+    content: renderLink(homepage, '鐐瑰嚮鏌ョ湅'),
+    title: '涓婚〉',
+  },
+  {
+    content: renderLink(VBEN_DOC_URL, '鐐瑰嚮鏌ョ湅'),
+    title: '鏂囨。鍦板潃',
+  },
+  {
+    content: renderLink(VBEN_PREVIEW_URL, '鐐瑰嚮鏌ョ湅'),
+    title: '棰勮鍦板潃',
+  },
+  {
+    content: renderLink(VBEN_GITHUB_URL, '鐐瑰嚮鏌ョ湅'),
+    title: 'Github',
+  },
+  {
+    content: h('div', [
+      renderLink(authorUrl, `${authorName}  `),
+      renderLink(`mailto:${authorEmail}`, authorEmail),
+    ]),
+    title: '浣滆��',
+  },
+];
+
+const dependenciesItems = Object.keys(dependencies).map((key) => ({
+  content: dependencies[key],
+  title: key,
+}));
+
+const devDependenciesItems = Object.keys(devDependencies).map((key) => ({
+  content: devDependencies[key],
+  title: key,
+}));
+</script>
+
+<template>
+  <Page :title="title">
+    <template #description>
+      <p class="text-foreground mt-3 text-sm leading-6">
+        <a :href="VBEN_GITHUB_URL" class="vben-link" target="_blank">
+          {{ name }}
+        </a>
+        {{ description }}
+      </p>
+    </template>
+    <div class="card-box p-5">
+      <div>
+        <h5 class="text-foreground text-lg">鍩烘湰淇℃伅</h5>
+      </div>
+      <div class="mt-4">
+        <dl class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
+          <template v-for="item in vbenDescriptionItems" :key="item.title">
+            <div class="border-border border-t px-4 py-6 sm:col-span-1 sm:px-0">
+              <dt class="text-foreground text-sm font-medium leading-6">
+                {{ item.title }}
+              </dt>
+              <dd class="text-foreground mt-1 text-sm leading-6 sm:mt-2">
+                <VbenRenderContent :content="item.content" />
+              </dd>
+            </div>
+          </template>
+        </dl>
+      </div>
+    </div>
+
+    <div class="card-box mt-6 p-5">
+      <div>
+        <h5 class="text-foreground text-lg">鐢熶骇鐜渚濊禆</h5>
+      </div>
+      <div class="mt-4">
+        <dl class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
+          <template v-for="item in dependenciesItems" :key="item.title">
+            <div class="border-border border-t px-4 py-3 sm:col-span-1 sm:px-0">
+              <dt class="text-foreground text-sm">
+                {{ item.title }}
+              </dt>
+              <dd class="text-foreground/80 mt-1 text-sm sm:mt-2">
+                <VbenRenderContent :content="item.content" />
+              </dd>
+            </div>
+          </template>
+        </dl>
+      </div>
+    </div>
+    <div class="card-box mt-6 p-5">
+      <div>
+        <h5 class="text-foreground text-lg">寮�鍙戠幆澧冧緷璧�</h5>
+      </div>
+      <div class="mt-4">
+        <dl class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
+          <template v-for="item in devDependenciesItems" :key="item.title">
+            <div class="border-border border-t px-4 py-3 sm:col-span-1 sm:px-0">
+              <dt class="text-foreground text-sm">
+                {{ item.title }}
+              </dt>
+              <dd class="text-foreground/80 mt-1 text-sm sm:mt-2">
+                <VbenRenderContent :content="item.content" />
+              </dd>
+            </div>
+          </template>
+        </dl>
+      </div>
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/about/index.ts b/eims-ui/packages/effects/common-ui/src/ui/about/index.ts
new file mode 100644
index 0000000..5860f5b
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/about/index.ts
@@ -0,0 +1 @@
+export { default as About } from './about.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/auth-title.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/auth-title.vue
new file mode 100644
index 0000000..3ed9a6b
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/auth-title.vue
@@ -0,0 +1,13 @@
+<template>
+  <div class="mb-7 sm:mx-auto sm:w-full sm:max-w-md">
+    <h2
+      class="text-foreground mb-3 text-3xl font-bold leading-9 tracking-tight lg:text-4xl"
+    >
+      <slot></slot>
+    </h2>
+
+    <p class="text-muted-foreground lg:text-md text-sm">
+      <slot name="desc"></slot>
+    </p>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/code-login.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/code-login.vue
new file mode 100644
index 0000000..e3c3d1b
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/code-login.vue
@@ -0,0 +1,118 @@
+<script setup lang="ts">
+import type { VbenFormSchema } from '@vben-core/form-ui';
+
+import { computed, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { useVbenForm } from '@vben-core/form-ui';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+import Title from './auth-title.vue';
+
+interface Props {
+  formSchema: VbenFormSchema[];
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+  /**
+   * @zh_CN 鐧诲綍璺緞
+   */
+  loginPath?: string;
+  /**
+   * @zh_CN 鏍囬
+   */
+  title?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 鎸夐挳鏂囨湰
+   */
+  submitButtonText?: string;
+}
+
+defineOptions({
+  name: 'AuthenticationCodeLogin',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  loading: false,
+  loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
+});
+
+const emit = defineEmits<{
+  submit: [{ code: string; phoneNumber: string; tenantId: string }];
+}>();
+
+const router = useRouter();
+
+const [Form, formApi] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => props.formSchema),
+    showDefaultActions: false,
+  }),
+);
+
+async function handleSubmit() {
+  const { valid } = await formApi.validate();
+  const values = await formApi.getValues();
+  if (valid) {
+    emit('submit', {
+      tenantId: values?.tenantId,
+      code: values?.code,
+      phoneNumber: values?.phoneNumber,
+    });
+  }
+}
+
+function goToLogin() {
+  router.push(props.loginPath);
+}
+
+defineExpose({
+  getFormApi: () => formApi,
+});
+</script>
+
+<template>
+  <div>
+    <Title>
+      <slot name="title">
+        {{ title || $t('authentication.welcomeBack') }} 馃摬
+      </slot>
+      <template #desc>
+        <span class="text-muted-foreground">
+          <slot name="subTitle">
+            {{ subTitle || $t('authentication.codeSubtitle') }}
+          </slot>
+        </span>
+      </template>
+    </Title>
+    <Form />
+    <VbenButton
+      :class="{
+        'cursor-wait': loading,
+      }"
+      :loading="loading"
+      class="w-full"
+      @click="handleSubmit"
+    >
+      <slot name="submitButtonText">
+        {{ submitButtonText || $t('common.login') }}
+      </slot>
+    </VbenButton>
+    <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
+      {{ $t('common.back') }}
+    </VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/forget-password.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/forget-password.vue
new file mode 100644
index 0000000..7955ded
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/forget-password.vue
@@ -0,0 +1,115 @@
+<script setup lang="ts">
+import type { VbenFormSchema } from '@vben-core/form-ui';
+
+import { computed, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { useVbenForm } from '@vben-core/form-ui';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+import Title from './auth-title.vue';
+
+interface Props {
+  formSchema: VbenFormSchema[];
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+  /**
+   * @zh_CN 鐧诲綍璺緞
+   */
+  loginPath?: string;
+  /**
+   * @zh_CN 鏍囬
+   */
+  title?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 鎸夐挳鏂囨湰
+   */
+  submitButtonText?: string;
+}
+
+defineOptions({
+  name: 'ForgetPassword',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  loading: false,
+  loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
+});
+
+const emit = defineEmits<{
+  submit: [Record<string, any>];
+}>();
+
+const [Form, formApi] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => props.formSchema),
+    showDefaultActions: false,
+  }),
+);
+
+const router = useRouter();
+
+async function handleSubmit() {
+  const { valid } = await formApi.validate();
+  const values = await formApi.getValues();
+  if (valid) {
+    emit('submit', values);
+  }
+}
+
+function goToLogin() {
+  router.push(props.loginPath);
+}
+
+defineExpose({
+  getFormApi: () => formApi,
+});
+</script>
+
+<template>
+  <div>
+    <Title>
+      <slot name="title">
+        {{ title || $t('authentication.forgetPassword') }} 馃う馃徎鈥嶁檪锔�
+      </slot>
+      <template #desc>
+        <slot name="subTitle">
+          {{ subTitle || $t('authentication.forgetPasswordSubtitle') }}
+        </slot>
+      </template>
+    </Title>
+    <Form />
+
+    <div>
+      <VbenButton
+        :class="{
+          'cursor-wait': loading,
+        }"
+        aria-label="submit"
+        class="mt-2 w-full"
+        @click="handleSubmit"
+      >
+        <slot name="submitButtonText">
+          {{ submitButtonText || $t('authentication.sendResetLink') }}
+        </slot>
+      </VbenButton>
+      <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
+        {{ $t('common.back') }}
+      </VbenButton>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/index.ts b/eims-ui/packages/effects/common-ui/src/ui/authentication/index.ts
new file mode 100644
index 0000000..dcd05b7
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/index.ts
@@ -0,0 +1,12 @@
+export { default as AuthenticationCodeLogin } from './code-login.vue';
+export { default as AuthenticationForgetPassword } from './forget-password.vue';
+export { default as AuthenticationLogin } from './login.vue';
+export { default as AuthenticationLoginExpiredModal } from './login-expired-modal.vue';
+export { default as AuthenticationQrCodeLogin } from './qrcode-login.vue';
+export { default as AuthenticationRegister } from './register.vue';
+export type {
+  AuthenticationProps,
+  GrantType,
+  LoginAndRegisterParams,
+  LoginCodeParams,
+} from './types';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue
new file mode 100644
index 0000000..0b705ad
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue
@@ -0,0 +1,56 @@
+<script setup lang="ts">
+import type { AuthenticationProps } from './types';
+
+import { watch } from 'vue';
+
+import { useVbenModal } from '@vben-core/popup-ui';
+import { Slot, VbenAvatar } from '@vben-core/shadcn-ui';
+
+interface Props extends AuthenticationProps {
+  avatar?: string;
+}
+
+defineOptions({
+  name: 'LoginExpiredModal',
+});
+
+withDefaults(defineProps<Props>(), {
+  avatar: '',
+});
+
+const open = defineModel<boolean>('open');
+
+const [Modal, modalApi] = useVbenModal();
+
+watch(
+  () => open.value,
+  (val) => {
+    modalApi.setState({ isOpen: val });
+  },
+);
+</script>
+
+<template>
+  <div>
+    <Modal
+      :closable="false"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+      :footer="false"
+      :fullscreen-button="false"
+      :header="false"
+      class="border-none px-10 py-6 text-center shadow-xl sm:w-[600px] sm:rounded-2xl md:h-[unset]"
+    >
+      <VbenAvatar :src="avatar" class="mx-auto mb-6 size-20" />
+      <Slot
+        :show-forget-password="false"
+        :show-register="false"
+        :show-remember-me="false"
+        :sub-title="$t('authentication.loginAgainSubTitle')"
+        :title="$t('authentication.loginAgainTitle')"
+      >
+        <slot> </slot>
+      </Slot>
+    </Modal>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/login.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/login.vue
new file mode 100644
index 0000000..0905074
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/login.vue
@@ -0,0 +1,186 @@
+<script setup lang="ts">
+import type { VbenFormSchema } from '@vben-core/form-ui';
+
+import type { AuthenticationProps, LoginAndRegisterParams } from './types';
+
+import { computed, onMounted, reactive, ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { useVbenForm } from '@vben-core/form-ui';
+import { VbenButton, VbenCheckbox } from '@vben-core/shadcn-ui';
+import { cloneDeep } from '@vben-core/shared/utils';
+
+import Title from './auth-title.vue';
+import ThirdPartyLogin from './third-party-login.vue';
+
+interface Props extends AuthenticationProps {
+  formSchema: VbenFormSchema[];
+}
+
+defineOptions({
+  name: 'AuthenticationLogin',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  codeLoginPath: '/auth/code-login',
+  forgetPasswordPath: '/auth/forget-password',
+  formSchema: () => [],
+  loading: false,
+  qrCodeLoginPath: '/auth/qrcode-login',
+  registerPath: '/auth/register',
+  showCodeLogin: true,
+  showForgetPassword: true,
+  showQrcodeLogin: true,
+  showRegister: true,
+  showRememberMe: true,
+  showThirdPartyLogin: true,
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
+});
+
+const emit = defineEmits<{
+  submit: [LoginAndRegisterParams];
+}>();
+
+const [Form, formApi] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => props.formSchema),
+    showDefaultActions: false,
+  }),
+);
+const router = useRouter();
+
+const REMEMBER_ME_KEY = `REMEMBER_ME_USERNAME_${location.hostname}`;
+
+const localUsername = localStorage.getItem(REMEMBER_ME_KEY) || '';
+
+const rememberMe = ref(!!localUsername);
+
+async function handleSubmit() {
+  const { valid } = await formApi.validate();
+  if (valid) {
+    const values = cloneDeep(await formApi.getValues());
+    localStorage.setItem(
+      REMEMBER_ME_KEY,
+      rememberMe.value ? values?.username : '',
+    );
+    // 鍔犱笂璁よ瘉绫诲瀷
+    (values as any).grantType = 'password';
+    emit('submit', values as LoginAndRegisterParams);
+  }
+}
+
+function handleGo(path: string) {
+  router.push(path);
+}
+
+onMounted(() => {
+  if (localUsername) {
+    formApi.setFieldValue('username', localUsername);
+  }
+});
+
+defineExpose({
+  getFormApi: () => formApi,
+});
+</script>
+
+<template>
+  <div @keydown.enter.prevent="handleSubmit">
+    <slot name="title">
+      <Title>
+        <slot name="title">
+          {{ title || `${$t('authentication.welcomeBack')} 馃憢馃徎` }}
+        </slot>
+        <template #desc>
+          <span class="text-muted-foreground">
+            <slot name="subTitle">
+              {{ subTitle || $t('authentication.loginSubtitle') }}
+            </slot>
+          </span>
+        </template>
+      </Title>
+    </slot>
+
+    <Form />
+
+    <div
+      v-if="showRememberMe || showForgetPassword"
+      class="mb-6 flex justify-between"
+    >
+      <div class="flex-center">
+        <VbenCheckbox
+          v-if="showRememberMe"
+          v-model:checked="rememberMe"
+          name="rememberMe"
+        >
+          {{ $t('authentication.rememberMe') }}
+        </VbenCheckbox>
+      </div>
+
+      <span
+        v-if="showForgetPassword"
+        class="vben-link text-sm font-normal"
+        @click="handleGo(forgetPasswordPath)"
+      >
+        {{ $t('authentication.forgetPassword') }}
+      </span>
+    </div>
+    <VbenButton
+      :class="{
+        'cursor-wait': loading,
+      }"
+      :loading="loading"
+      aria-label="login"
+      class="w-full"
+      @click="handleSubmit"
+    >
+      {{ submitButtonText || $t('common.login') }}
+    </VbenButton>
+
+    <div
+      v-if="showCodeLogin || showQrcodeLogin"
+      class="mb-2 mt-4 flex items-center justify-between"
+    >
+      <VbenButton
+        v-if="showCodeLogin"
+        class="w-1/2"
+        variant="outline"
+        @click="handleGo(codeLoginPath)"
+      >
+        {{ $t('authentication.mobileLogin') }}
+      </VbenButton>
+      <VbenButton
+        v-if="showQrcodeLogin"
+        class="ml-4 w-1/2"
+        variant="outline"
+        @click="handleGo(qrCodeLoginPath)"
+      >
+        {{ $t('authentication.qrcodeLogin') }}
+      </VbenButton>
+    </div>
+
+    <!-- 绗笁鏂圭櫥褰� -->
+    <slot v-if="showThirdPartyLogin" name="third-party-login">
+      <ThirdPartyLogin />
+    </slot>
+
+    <slot name="to-register">
+      <div v-if="showRegister" class="mt-3 text-center text-sm">
+        {{ $t('authentication.accountTip') }}
+        <span
+          class="vben-link text-sm font-normal"
+          @click="handleGo(registerPath)"
+        >
+          {{ $t('authentication.createAccount') }}
+        </span>
+      </div>
+    </slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue
new file mode 100644
index 0000000..6e7a332
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue
@@ -0,0 +1,94 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+import { useQRCode } from '@vueuse/integrations/useQRCode';
+
+import Title from './auth-title.vue';
+
+interface Props {
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+  /**
+   * @zh_CN 鐧诲綍璺緞
+   */
+  loginPath?: string;
+  /**
+   * @zh_CN 鏍囬
+   */
+  title?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 鎸夐挳鏂囨湰
+   */
+  submitButtonText?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  description?: string;
+}
+
+defineOptions({
+  name: 'AuthenticationQrCodeLogin',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  description: '',
+  loading: false,
+  loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
+});
+
+const router = useRouter();
+
+const text = ref('https://vben.vvbin.cn');
+
+const qrcode = useQRCode(text, {
+  errorCorrectionLevel: 'H',
+  margin: 4,
+});
+
+function goToLogin() {
+  router.push(props.loginPath);
+}
+</script>
+
+<template>
+  <div>
+    <Title>
+      <slot name="title">
+        {{ title || $t('authentication.welcomeBack') }} 馃摫
+      </slot>
+      <template #desc>
+        <span class="text-muted-foreground">
+          <slot name="subTitle">
+            {{ subTitle || $t('authentication.qrcodeSubtitle') }}
+          </slot>
+        </span>
+      </template>
+    </Title>
+
+    <div class="flex-col-center mt-6">
+      <img :src="qrcode" alt="qrcode" class="w-1/2" />
+      <p class="text-muted-foreground mt-4 text-sm">
+        <slot name="description">
+          {{ description || $t('authentication.qrcodePrompt') }}
+        </slot>
+      </p>
+    </div>
+
+    <VbenButton class="mt-4 w-full" variant="outline" @click="goToLogin()">
+      {{ $t('common.back') }}
+    </VbenButton>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/register.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/register.vue
new file mode 100644
index 0000000..f603a89
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/register.vue
@@ -0,0 +1,119 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+import type { VbenFormSchema } from '@vben-core/form-ui';
+
+import { computed, reactive } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { useVbenForm } from '@vben-core/form-ui';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+import Title from './auth-title.vue';
+
+interface Props {
+  formSchema: VbenFormSchema[];
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+  /**
+   * @zh_CN 鐧诲綍璺緞
+   */
+  loginPath?: string;
+  /**
+   * @zh_CN 鏍囬
+   */
+  title?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  subTitle?: string;
+  /**
+   * @zh_CN 鎸夐挳鏂囨湰
+   */
+  submitButtonText?: string;
+}
+
+defineOptions({
+  name: 'RegisterForm',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  formSchema: () => [],
+  loading: false,
+  loginPath: '/auth/login',
+  submitButtonText: '',
+  subTitle: '',
+  title: '',
+});
+
+const emit = defineEmits<{
+  submit: [Recordable<any>];
+}>();
+
+const [Form, formApi] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => props.formSchema),
+    showDefaultActions: false,
+  }),
+);
+
+const router = useRouter();
+
+async function handleSubmit() {
+  const { valid } = await formApi.validate();
+  const values = await formApi.getValues();
+  if (valid) {
+    emit('submit', values as { password: string; username: string });
+  }
+}
+
+function goToLogin() {
+  router.push(props.loginPath);
+}
+
+defineExpose({
+  getFormApi: () => formApi,
+});
+</script>
+
+<template>
+  <div>
+    <Title>
+      <slot name="title">
+        {{ title || $t('authentication.createAnAccount') }} 馃殌
+      </slot>
+      <template #desc>
+        <slot name="subTitle">
+          {{ subTitle || $t('authentication.signUpSubtitle') }}
+        </slot>
+      </template>
+    </Title>
+    <Form />
+
+    <VbenButton
+      :class="{
+        'cursor-wait': loading,
+      }"
+      :loading="loading"
+      aria-label="register"
+      class="mt-2 w-full"
+      @click="handleSubmit"
+    >
+      <slot name="submitButtonText">
+        {{ submitButtonText || $t('authentication.signUp') }}
+      </slot>
+    </VbenButton>
+    <div class="mt-4 text-center text-sm">
+      {{ $t('authentication.alreadyHaveAccount') }}
+      <span class="vben-link text-sm font-normal" @click="goToLogin()">
+        {{ $t('authentication.goToLogin') }}
+      </span>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/third-party-login.vue b/eims-ui/packages/effects/common-ui/src/ui/authentication/third-party-login.vue
new file mode 100644
index 0000000..98afc9a
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/third-party-login.vue
@@ -0,0 +1,43 @@
+<script setup lang="ts">
+import { GiteeIcon, MdiGithub, MdiQqchat, MdiWechat } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { VbenIconButton } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'ThirdPartyLogin',
+});
+
+defineEmits<{
+  /**
+   * 绗笁鏂圭櫥褰� platfrom 瀵瑰簲骞冲彴鐨剆tring
+   */
+  oauthLogin: [plateform: string];
+}>();
+</script>
+
+<template>
+  <div class="w-full sm:mx-auto md:max-w-md">
+    <div class="mt-4 flex items-center justify-between">
+      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
+      <span class="text-muted-foreground text-center text-xs uppercase">
+        {{ $t('authentication.thirdPartyLogin') }}
+      </span>
+      <span class="border-input w-[35%] border-b dark:border-gray-600"></span>
+    </div>
+
+    <div class="mt-4 flex flex-wrap justify-around">
+      <VbenIconButton class="mb-3" @click="$emit('oauthLogin', 'wechat')">
+        <MdiWechat class="size-[24px] text-green-600" />
+      </VbenIconButton>
+      <VbenIconButton class="mb-3" @click="$emit('oauthLogin', 'qq')">
+        <MdiQqchat class="size-[24px]" />
+      </VbenIconButton>
+      <VbenIconButton class="mb-3" @click="$emit('oauthLogin', 'github')">
+        <MdiGithub class="size-[24px]" />
+      </VbenIconButton>
+      <VbenIconButton class="mb-3" @click="$emit('oauthLogin', 'gitee')">
+        <GiteeIcon class="size-[24px] text-red-700" />
+      </VbenIconButton>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/authentication/types.ts b/eims-ui/packages/effects/common-ui/src/ui/authentication/types.ts
new file mode 100644
index 0000000..0e4288f
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/authentication/types.ts
@@ -0,0 +1,117 @@
+interface AuthenticationProps {
+  /**
+   * @zh_CN 楠岃瘉鐮佺櫥褰曡矾寰�
+   */
+  codeLoginPath?: string;
+
+  /**
+   * @zh_CN 蹇樿瀵嗙爜璺緞
+   */
+  forgetPasswordPath?: string;
+
+  /**
+   * @zh_CN 鏄惁澶勪簬鍔犺浇澶勭悊鐘舵��
+   */
+  loading?: boolean;
+
+  /**
+   * @zh_CN 浜岀淮鐮佺櫥褰曡矾寰�
+   */
+  qrCodeLoginPath?: string;
+
+  /**
+   * @zh_CN 娉ㄥ唽璺緞
+   */
+  registerPath?: string;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず楠岃瘉鐮佺櫥褰�
+   */
+  showCodeLogin?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず蹇樿瀵嗙爜
+   */
+  showForgetPassword?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず浜岀淮鐮佺櫥褰�
+   */
+  showQrcodeLogin?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず娉ㄥ唽鎸夐挳
+   */
+  showRegister?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず璁颁綇璐﹀彿
+   */
+  showRememberMe?: boolean;
+
+  /**
+   * @zh_CN 鏄惁鏄剧ず绗笁鏂圭櫥褰�
+   */
+  showThirdPartyLogin?: boolean;
+
+  /**
+   * @zh_CN 鐧诲綍妗嗗瓙鏍囬
+   */
+  subTitle?: string;
+
+  /**
+   * @zh_CN 鐧诲綍妗嗘爣棰�
+   */
+  title?: string;
+  /**
+   * @zh_CN 鎻愪氦鎸夐挳鏂囨湰
+   */
+  submitButtonText?: string;
+}
+
+/**
+ * 鐧诲綍绫诲瀷
+ * password 瀵嗙爜
+ * sms 鐭俊
+ * social 绗笁鏂筼auth
+ * email 閭
+ * xcx 灏忕▼搴�
+ */
+type GrantType = 'email' | 'password' | 'sms' | 'social' | 'xcx';
+
+interface LoginAndRegisterParams {
+  code?: string;
+  grantType: GrantType;
+  password: string;
+  tenantId: string;
+  username: string;
+  uuid?: string;
+}
+
+interface LoginCodeParams {
+  tenantId: string;
+  code: string;
+  phoneNumber: string;
+}
+
+interface LoginEmits {
+  submit: [LoginAndRegisterParams];
+}
+
+interface LoginCodeEmits {
+  submit: [LoginCodeParams];
+}
+
+interface RegisterEmits {
+  submit: [LoginAndRegisterParams];
+}
+
+export type {
+  AuthenticationProps,
+  GrantType,
+  LoginAndRegisterParams,
+  LoginCodeEmits,
+  LoginCodeParams,
+  LoginEmits,
+  RegisterEmits,
+};
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue
new file mode 100644
index 0000000..294d517
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue
@@ -0,0 +1,24 @@
+<script setup lang="ts">
+import { Card, CardContent, CardHeader, CardTitle } from '@vben-core/shadcn-ui';
+
+interface Props {
+  title: string;
+}
+
+defineOptions({
+  name: 'AnalysisChartCard',
+});
+
+withDefaults(defineProps<Props>(), {});
+</script>
+
+<template>
+  <Card>
+    <CardHeader>
+      <CardTitle class="text-xl">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent>
+      <slot></slot>
+    </CardContent>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue
new file mode 100644
index 0000000..9c8cf20
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue
@@ -0,0 +1,40 @@
+<script setup lang="ts">
+import type { TabOption } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@vben-core/shadcn-ui';
+
+interface Props {
+  tabs: TabOption[];
+}
+
+defineOptions({
+  name: 'AnalysisChartsTabs',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  tabs: () => [],
+});
+
+const defaultValue = computed(() => {
+  return props.tabs?.[0]?.value;
+});
+</script>
+
+<template>
+  <div class="card-box w-full px-4 pb-5 pt-3">
+    <Tabs :default-value="defaultValue">
+      <TabsList>
+        <template v-for="tab in tabs" :key="tab.label">
+          <TabsTrigger :value="tab.value"> {{ tab.label }} </TabsTrigger>
+        </template>
+      </TabsList>
+      <template v-for="tab in tabs" :key="tab.label">
+        <TabsContent :value="tab.value" class="pt-4">
+          <slot :name="tab.value"></slot>
+        </TabsContent>
+      </template>
+    </Tabs>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue
new file mode 100644
index 0000000..ea4d7bc
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue
@@ -0,0 +1,55 @@
+<script setup lang="ts">
+import type { AnalysisOverviewItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardFooter,
+  CardHeader,
+  CardTitle,
+  VbenCountToAnimator,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: AnalysisOverviewItem[];
+}
+
+defineOptions({
+  name: 'AnalysisOverview',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+</script>
+
+<template>
+  <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
+    <template v-for="item in items" :key="item.title">
+      <Card :title="item.title" class="w-full">
+        <CardHeader>
+          <CardTitle class="text-xl">{{ item.title }}</CardTitle>
+        </CardHeader>
+
+        <CardContent class="flex items-center justify-between">
+          <VbenCountToAnimator
+            :end-val="item.value"
+            :start-val="1"
+            class="text-xl"
+            prefix=""
+          />
+          <VbenIcon :icon="item.icon" class="size-8 flex-shrink-0" />
+        </CardContent>
+        <CardFooter class="justify-between">
+          <span>{{ item.totalTitle }}</span>
+          <VbenCountToAnimator
+            :end-val="item.totalValue"
+            :start-val="1"
+            prefix=""
+          />
+        </CardFooter>
+      </Card>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts
new file mode 100644
index 0000000..7c67b87
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts
@@ -0,0 +1,3 @@
+export { default as AnalysisChartCard } from './analysis-chart-card.vue';
+export { default as AnalysisChartsTabs } from './analysis-charts-tabs.vue';
+export { default as AnalysisOverview } from './analysis-overview.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/index.ts b/eims-ui/packages/effects/common-ui/src/ui/dashboard/index.ts
new file mode 100644
index 0000000..bc74424
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/index.ts
@@ -0,0 +1,3 @@
+export * from './analysis';
+export type * from './typing';
+export * from './workbench';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/typing.ts b/eims-ui/packages/effects/common-ui/src/ui/dashboard/typing.ts
new file mode 100644
index 0000000..48fc9c7
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/typing.ts
@@ -0,0 +1,48 @@
+import type { Component } from 'vue';
+
+interface AnalysisOverviewItem {
+  icon: Component | string;
+  title: string;
+  totalTitle: string;
+  totalValue: number;
+  value: number;
+}
+
+interface WorkbenchProjectItem {
+  color?: string;
+  content: string;
+  date: string;
+  group: string;
+  icon: Component | string;
+  title: string;
+  url?: string;
+}
+
+interface WorkbenchTrendItem {
+  avatar: string;
+  content: string;
+  date: string;
+  title: string;
+}
+
+interface WorkbenchTodoItem {
+  completed: boolean;
+  content: string;
+  date: string;
+  title: string;
+}
+
+interface WorkbenchQuickNavItem {
+  color?: string;
+  icon: Component | string;
+  title: string;
+  url?: string;
+}
+
+export type {
+  AnalysisOverviewItem,
+  WorkbenchProjectItem,
+  WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
+};
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts
new file mode 100644
index 0000000..76b7af1
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts
@@ -0,0 +1,5 @@
+export { default as WorkbenchHeader } from './workbench-header.vue';
+export { default as WorkbenchProject } from './workbench-project.vue';
+export { default as WorkbenchQuickNav } from './workbench-quick-nav.vue';
+export { default as WorkbenchTodo } from './workbench-todo.vue';
+export { default as WorkbenchTrends } from './workbench-trends.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue
new file mode 100644
index 0000000..a3ea3eb
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue
@@ -0,0 +1,46 @@
+<script lang="ts" setup>
+import { VbenAvatar } from '@vben-core/shadcn-ui';
+
+interface Props {
+  avatar?: string;
+}
+
+defineOptions({
+  name: 'WorkbenchHeader',
+});
+
+withDefaults(defineProps<Props>(), {
+  avatar: '',
+});
+</script>
+<template>
+  <div class="card-box p-4 py-6 lg:flex">
+    <VbenAvatar :src="avatar" class="size-20" />
+    <div
+      v-if="$slots.title || $slots.description"
+      class="flex flex-col justify-center md:ml-6 md:mt-0"
+    >
+      <h1 v-if="$slots.title" class="text-md font-semibold md:text-xl">
+        <slot name="title"></slot>
+      </h1>
+      <span v-if="$slots.description" class="text-foreground/80 mt-1">
+        <slot name="description"></slot>
+      </span>
+    </div>
+    <div class="mt-4 flex flex-1 justify-end md:mt-0">
+      <div class="flex flex-col justify-center text-right">
+        <span class="text-foreground/80"> 寰呭姙 </span>
+        <span class="text-2xl">2/10</span>
+      </div>
+
+      <div class="mx-12 flex flex-col justify-center text-right md:mx-16">
+        <span class="text-foreground/80"> 椤圭洰 </span>
+        <span class="text-2xl">8</span>
+      </div>
+      <div class="mr-4 flex flex-col justify-center text-right md:mr-10">
+        <span class="text-foreground/80"> 鍥㈤槦 </span>
+        <span class="text-2xl">300</span>
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue
new file mode 100644
index 0000000..b706292
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue
@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { WorkbenchProjectItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchProjectItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchProject',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+
+defineEmits(['click']);
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-0">
+      <template v-for="(item, index) in items" :key="item.title">
+        <div
+          :class="{
+            'border-r-0': index % 3 === 2,
+            'border-b-0': index < 3,
+            'pb-4': index > 2,
+          }"
+          class="border-border group w-full cursor-pointer border-b border-r border-t p-4 transition-all hover:shadow-xl md:w-1/2 lg:w-1/3"
+        >
+          <div class="flex items-center">
+            <VbenIcon
+              :color="item.color"
+              :icon="item.icon"
+              class="size-8 transition-all duration-300 group-hover:scale-110"
+              @click="$emit('click', item)"
+            />
+            <span class="ml-4 text-lg font-medium">{{ item.title }}</span>
+          </div>
+          <div class="text-foreground/80 mt-4 flex h-10">
+            {{ item.content }}
+          </div>
+          <div class="text-foreground/80 flex justify-between">
+            <span>{{ item.group }}</span>
+            <span>{{ item.date }}</span>
+          </div>
+        </div>
+      </template>
+    </CardContent>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue
new file mode 100644
index 0000000..7884609
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue
@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import type { WorkbenchQuickNavItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchQuickNavItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchQuickNav',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+
+defineEmits(['click']);
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-0">
+      <template v-for="(item, index) in items" :key="item.title">
+        <div
+          :class="{
+            'border-r-0': index % 3 === 2,
+            'pb-4': index > 2,
+            'border-b-0': index < 3,
+          }"
+          class="flex-col-center border-border group w-1/3 cursor-pointer border-b border-r border-t py-8 hover:shadow-xl"
+          @click="$emit('click', item)"
+        >
+          <VbenIcon
+            :color="item.color"
+            :icon="item.icon"
+            class="size-7 transition-all duration-300 group-hover:scale-125"
+          />
+          <span class="text-md mt-2 truncate">{{ item.title }}</span>
+        </div>
+      </template>
+    </CardContent>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue
new file mode 100644
index 0000000..8aae81f
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue
@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { WorkbenchTodoItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenCheckbox,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchTodoItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchTodo',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-5 pt-0">
+      <ul class="divide-border w-full divide-y" role="list">
+        <li
+          v-for="item in items"
+          :key="item.title"
+          :class="{
+            'select-none line-through opacity-60': item.completed,
+          }"
+          class="flex cursor-pointer justify-between gap-x-6 py-5"
+        >
+          <div class="flex min-w-0 items-center gap-x-4">
+            <VbenCheckbox v-model:checked="item.completed" name="completed" />
+            <div class="min-w-0 flex-auto">
+              <p class="text-foreground text-sm font-semibold leading-6">
+                {{ item.title }}
+              </p>
+              <!-- eslint-disable vue/no-v-html -->
+              <p
+                class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
+                v-html="item.content"
+              ></p>
+            </div>
+          </div>
+          <div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
+            <span class="text-foreground/80 mt-6 text-xs leading-6">
+              {{ item.date }}
+            </span>
+          </div>
+        </li>
+      </ul>
+    </CardContent>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue
new file mode 100644
index 0000000..358b210
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue
@@ -0,0 +1,64 @@
+<script setup lang="ts">
+import type { WorkbenchTrendItem } from '../typing';
+
+import {
+  Card,
+  CardContent,
+  CardHeader,
+  CardTitle,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+interface Props {
+  items: WorkbenchTrendItem[];
+  title: string;
+}
+
+defineOptions({
+  name: 'WorkbenchTrends',
+});
+
+withDefaults(defineProps<Props>(), {
+  items: () => [],
+});
+</script>
+
+<template>
+  <Card>
+    <CardHeader class="py-4">
+      <CardTitle class="text-lg">{{ title }}</CardTitle>
+    </CardHeader>
+    <CardContent class="flex flex-wrap p-5 pt-0">
+      <ul class="divide-border w-full divide-y" role="list">
+        <li
+          v-for="item in items"
+          :key="item.title"
+          class="flex justify-between gap-x-6 py-5"
+        >
+          <div class="flex min-w-0 items-center gap-x-4">
+            <VbenIcon
+              :icon="item.avatar"
+              alt=""
+              class="size-10 flex-none rounded-full"
+            />
+            <div class="min-w-0 flex-auto">
+              <p class="text-foreground text-sm font-semibold leading-6">
+                {{ item.title }}
+              </p>
+              <!-- eslint-disable vue/no-v-html -->
+              <p
+                class="text-foreground/80 *:text-primary mt-1 truncate text-xs leading-5"
+                v-html="item.content"
+              ></p>
+            </div>
+          </div>
+          <div class="hidden h-full shrink-0 sm:flex sm:flex-col sm:items-end">
+            <span class="text-foreground/80 mt-6 text-xs leading-6">
+              {{ item.date }}
+            </span>
+          </div>
+        </li>
+      </ul>
+    </CardContent>
+  </Card>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.ts b/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.ts
new file mode 100644
index 0000000..5f8e193
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.ts
@@ -0,0 +1,25 @@
+interface FallbackProps {
+  /**
+   * 鎻忚堪
+   */
+  description?: string;
+  /**
+   *  @zh_CN 棣栭〉璺敱鍦板潃
+   *  @default /
+   */
+  homePath?: string;
+  /**
+   * @zh_CN 榛樿鏄剧ず鐨勫浘鐗�
+   * @default pageNotFoundSvg
+   */
+  image?: string;
+  /**
+   *  @zh_CN 鍐呯疆绫诲瀷
+   */
+  status?: '403' | '404' | '500' | 'coming-soon' | 'offline';
+  /**
+   *  @zh_CN 椤甸潰鎻愮ず璇�
+   */
+  title?: string;
+}
+export type { FallbackProps };
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.vue
new file mode 100644
index 0000000..dc46ef4
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/fallback.vue
@@ -0,0 +1,163 @@
+<script setup lang="ts">
+import type { FallbackProps } from './fallback';
+
+import { computed, defineAsyncComponent } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { ArrowLeft, RotateCw } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+interface Props extends FallbackProps {}
+
+defineOptions({
+  name: 'Fallback',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  description: '',
+  homePath: '/',
+  image: '',
+  showBack: true,
+  status: 'coming-soon',
+  title: '',
+});
+
+const Icon403 = defineAsyncComponent(() => import('./icons/icon-403.vue'));
+const Icon404 = defineAsyncComponent(() => import('./icons/icon-404.vue'));
+const Icon500 = defineAsyncComponent(() => import('./icons/icon-500.vue'));
+const IconHello = defineAsyncComponent(
+  () => import('./icons/icon-coming-soon.vue'),
+);
+const IconOffline = defineAsyncComponent(
+  () => import('./icons/icon-offline.vue'),
+);
+
+const titleText = computed(() => {
+  if (props.title) {
+    return props.title;
+  }
+
+  switch (props.status) {
+    case '403': {
+      return $t('ui.fallback.forbidden');
+    }
+    case '404': {
+      return $t('ui.fallback.pageNotFound');
+    }
+    case '500': {
+      return $t('ui.fallback.internalError');
+    }
+    case 'coming-soon': {
+      return $t('ui.fallback.comingSoon');
+    }
+    case 'offline': {
+      return $t('ui.fallback.offlineError');
+    }
+    default: {
+      return '';
+    }
+  }
+});
+
+const descText = computed(() => {
+  if (props.description) {
+    return props.description;
+  }
+  switch (props.status) {
+    case '403': {
+      return $t('ui.fallback.forbiddenDesc');
+    }
+    case '404': {
+      return $t('ui.fallback.pageNotFoundDesc');
+    }
+    case '500': {
+      return $t('ui.fallback.internalErrorDesc');
+    }
+    case 'offline': {
+      return $t('ui.fallback.offlineErrorDesc');
+    }
+    default: {
+      return '';
+    }
+  }
+});
+
+const fallbackIcon = computed(() => {
+  switch (props.status) {
+    case '403': {
+      return Icon403;
+    }
+    case '404': {
+      return Icon404;
+    }
+    case '500': {
+      return Icon500;
+    }
+    case 'coming-soon': {
+      return IconHello;
+    }
+    case 'offline': {
+      return IconOffline;
+    }
+    default: {
+      return null;
+    }
+  }
+});
+
+const showBack = computed(() => {
+  return props.status === '403' || props.status === '404';
+});
+
+const showRefresh = computed(() => {
+  return props.status === '500' || props.status === 'offline';
+});
+
+const { push } = useRouter();
+
+// 杩斿洖棣栭〉
+function back() {
+  push(props.homePath);
+}
+
+function refresh() {
+  location.reload();
+}
+</script>
+
+<template>
+  <div class="flex size-full flex-col items-center justify-center duration-300">
+    <img v-if="image" :src="image" class="md:1/3 w-1/2 lg:w-1/4" />
+    <component
+      :is="fallbackIcon"
+      v-else-if="fallbackIcon"
+      class="md:1/3 h-1/3 w-1/2 lg:w-1/4"
+    />
+    <div class="flex-col-center">
+      <slot v-if="$slots.title" name="title"></slot>
+      <p
+        v-else-if="titleText"
+        class="text-foreground mt-8 text-2xl md:text-3xl lg:text-4xl"
+      >
+        {{ titleText }}
+      </p>
+      <slot v-if="$slots.describe" name="describe"></slot>
+      <p
+        v-else-if="descText"
+        class="text-muted-foreground md:text-md my-4 lg:text-lg"
+      >
+        {{ descText }}
+      </p>
+      <slot v-if="$slots.action" name="action"></slot>
+      <VbenButton v-else-if="showBack" size="lg" @click="back">
+        <ArrowLeft class="mr-2 size-4" />
+        {{ $t('common.backToHome') }}
+      </VbenButton>
+      <VbenButton v-else-if="showRefresh" size="lg" @click="refresh">
+        <RotateCw class="mr-2 size-4" />
+        {{ $t('common.refresh') }}
+      </VbenButton>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue
new file mode 100644
index 0000000..e390867
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue
@@ -0,0 +1,151 @@
+<template>
+  <svg
+    height="659.29778"
+    viewBox="0 0 586 659.29778"
+    width="586"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+  >
+    <circle cx="332.47856" cy="254" fill="#f2f2f2" r="254.00001" />
+    <path
+      d="M498.46363,113.58835H33.17063c-.99774-.02133-1.78931-.84746-1.76797-1.84521,.02069-.96771,.80026-1.74727,1.76797-1.76796H498.46363c.99774,.02133,1.78931,.84746,1.76794,1.84521-.02069,.96771-.80023,1.74727-1.76794,1.76796Z"
+      fill="#cacaca"
+    />
+    <rect
+      fill="#fff"
+      height="34.98639"
+      rx="17.49318"
+      ry="17.49318"
+      width="163.61147"
+      x="193.77441"
+      y="174.47256"
+    />
+    <path
+      d="M128.17493,244.44534H422.98542c9.66122,0,17.49316,7.83197,17.49316,17.49319h0c0,9.66122-7.83194,17.49319-17.49316,17.49319H128.17493c-9.66122,0-17.49318-7.83197-17.49318-17.49319h0c0-9.66122,7.83196-17.49319,17.49318-17.49319Z"
+      fill="#fff"
+    />
+    <path
+      d="M128.17493,314.41812H422.98542c9.66122,0,17.49316,7.83197,17.49316,17.49319h0c0,9.66122-7.83194,17.49319-17.49316,17.49319H128.17493c-9.66122,0-17.49318-7.83197-17.49318-17.49319h0c0-9.66122,7.83196-17.49319,17.49318-17.49319Z"
+      fill="#fff"
+    />
+    <path
+      d="M91.64085,657.75932l-.69385-.06793c-23.54068-2.42871-44.82135-15.08929-58.18845-34.61835-3.66138-5.44159-6.62299-11.32251-8.815-17.50409l-.21069-.58966,.62375-.05048c7.44699-.59924,15.09732-1.86292,18.49585-2.46417l-21.91473-7.42511-.1355-.65033c-1.29926-6.10406,1.24612-12.38458,6.4285-15.86176,5.19641-3.64447,12.08731-3.76111,17.40405-.29449,2.38599,1.52399,4.88162,3.03339,7.29489,4.49359,8.29321,5.01636,16.8688,10.20337,23.29828,17.30121,9.74951,10.97778,14.02298,25.76984,11.63,40.25562l4.7829,17.47595Z"
+      fill="#f2f2f2"
+    />
+    <polygon
+      fill="#a0616a"
+      points="171.30016 646.86102 182.10017 646.85999 187.23916 605.198 171.29716 605.19897 171.30016 646.86102"
+    />
+    <path
+      d="M170.9192,658.12816l33.21436-.00122v-.41998c-.00049-7.13965-5.78833-12.92737-12.92798-12.92773h-.00079l-6.06702-4.60278-11.3197,4.60345-2.89941,.00012,.00055,13.34814Z"
+      fill="#2f2e41"
+    />
+    <polygon
+      fill="#a0616a"
+      points="84.74116 616.94501 93.38016 623.42603 122.49316 593.185 109.74116 583.61902 84.74116 616.94501"
+    />
+    <path
+      d="M77.67448,625.72966l26.569,19.93188,.25208-.336c4.2843-5.71136,3.12799-13.81433-2.58279-18.09937l-.00064-.00049-2.09079-7.32275-11.81735-3.11102-2.31931-1.73993-8.01019,10.67767Z"
+      fill="#2f2e41"
+    />
+    <path
+      d="M120.64463,451.35271s.59625,16.26422,1.3483,29.30737c.12335,2.13916-4.88821,4.46301-4.75842,6.7901,.08609,1.54395,1.02808,3.04486,1.1156,4.65472,.09235,1.69897-1.20822,3.20282-1.1156,4.95984,.09052,1.71667,1.57422,3.6853,1.66373,5.44244,.96317,18.9093,4.45459,41.54633,.9584,47.87439-1.72299,3.11871-23.68533,46.32446-23.68533,46.32446,0,0,12.23666,18.35498,15.73285,12.23663,4.61771-8.08099,40.20615-45.88745,40.20615-53.10712,0-7.21088,8.23346-61.25323,8.23346-61.25323l5.74103,31.98169,2.63239,6.33655-.82715,3.71997,1.70117,5.02045,.09192,4.96838,1.65619,9.22614s-4.98199,71.88159-2.17633,73.88312c2.81439,2.01038,16.44086,5.62018,18.04901,2.01038,1.59955-3.6098,12.0108-75.01947,12.0108-75.01947,0,0,1.6781-32.72424,3.49622-63.14111,.1048-1.76556,1.34607-3.89825,1.4422-5.63763,.11365-2.01898-.67297-4.64111-.56818-6.599,.11365-2.24628,1.11005-3.82831,1.20618-5.97852,.74292-16.6156-3.42761-36.84912-4.7561-38.84192-4.01202-6.01343-7.62177-10.82074-7.62177-10.82074,0,0-54.03558-17.75403-68.47485,.28625l-3.30185,25.37585Z"
+      fill="#2f2e41"
+    />
+    <path
+      d="M174.53779,284.10378l-21.4209-4.28418-9.9964,13.56656h0c-18.65262,18.34058-18.93359,34.52753-15.60379,60.47382v36.41553l-2.41,24.41187s-8.53156,17.84521,.26788,22.00006,66.59857,3.80066,72.117,2.14209,.73517-3.69482-.71399-11.4245c-2.72211-14.51929-.90131-7.51562-.71399-12.13849,2.68585-66.31363-3.57013-93.5379-4.20544-100.69376l-10.89398-19.75858-6.42639-10.71042Z"
+      fill="#3f3d56"
+    />
+    <path
+      d="M287.43909,337.57097c-2.23248,4.23007-7.47144,5.84943-11.70148,3.61694-.45099-.23804-.88013-.51541-1.28229-.82895l-46.26044,29.37308,.13336-15.9924,44.93842-26.07846c3.20093-3.58887,8.70514-3.90332,12.29401-.70239,3.00305,2.67844,3.7796,7.0657,1.87842,10.61218Z"
+      fill="#a0616a"
+    />
+    <path
+      d="M157.62488,302.62425l-5.26666-.55807c-4.86633-.50473-9.64093,1.57941-12.57947,5.491-1.12549,1.48346-1.9339,3.18253-2.37491,4.99164l-.00317,.01447c-1.32108,5.44534,.75095,11.15201,5.25803,14.48117l18.19031,13.41101c12.76544,17.24899,36.75653,28.69272,64.89832,37.98978l43.74274-27.16666-15.47186-18.73843-30.00336,16.0798-44.59833-34.52374-.0257-.02075-16.97424-10.936-4.79169-.5152Z"
+      fill="#3f3d56"
+    />
+    <circle cx="167.29993" cy="248.60526" fill="#a0616a" r="24.9798" />
+    <path
+      d="M167.8769,273.59047c-.20135,.00662-.4032,.01108-.6048,.01657-.0863,.22388-.17938,.44583-.2868,.66357l.8916-.68015Z"
+      fill="#2f2e41"
+    />
+    <path
+      d="M174.73243,249.29823c.03918,.24612,.09912,.48846,.17914,.72449-.03302-.24731-.09308-.49026-.17914-.72449Z"
+      fill="#2f2e41"
+    />
+    <path
+      d="M192.59852,224.6942c-1.0282,3.19272-1.94586-.85715-5.32825-.12869-4.06885,.87625-8.80377,.57532-12.13586-1.91879-4.96478-3.64273-11.39874-4.62335-17.22333-2.62509-5.70154,2.01706-15.25348,3.43933-16.73907,9.30179-.51642,2.03781-.7215,4.24933-1.97321,5.9382-1.09436,1.47662-2.82166,2.31854-4.26608,3.45499-4.87726,3.83743-1.14954,14.73981,1.15881,20.50046,2.30838,5.76065,7.60355,9.95721,13.42526,12.10678,5.63281,2.07977,11.7464,2.44662,17.75531,2.28317,1.04517-2.7106,.59363-5.84137-.26874-8.65134-.93359-3.04199-2.31592-5.97791-2.70593-9.13599s.46643-6.74527,3.11444-8.50986c2.4339-1.62192,6.39465-.63388,7.32062,1.98843-.54028-3.27841,2.7807-6.4509,6.20508-7.00882,3.67651-.599,7.35291,.72833,11.01886,1.38901s2.36475-14.77301,.64209-18.98425Z"
+      fill="#2f2e41"
+    />
+    <circle
+      cx="281.3585"
+      cy="285.71051"
+      fill="hsl(var(--primary))"
+      r="51.12006"
+      transform="translate(-26.58509 542.54478) rotate(-85.26884)"
+    />
+    <path
+      d="M294.78675,264.41051l-13.42828,13.42828-13.42828-13.42828c-2.17371-2.17374-5.69806-2.17374-7.87177,0s-2.17371,5.69803,0,7.87177l13.42828,13.42828-13.42828,13.42828c-2.17169,2.17575-2.1684,5.70007,.00739,7.87177,2.17285,2.16879,5.69153,2.16879,7.86438-.00003l13.42828-13.42828,13.42828,13.42828c2.17578,2.17169,5.70007,2.1684,7.87177-.00735,2.16882-2.17288,2.16882-5.6915,0-7.86438l-13.42828-13.42828,13.42828-13.42828c2.17371-2.17374,2.17371-5.69803,0-7.87177s-5.69806-2.17374-7.87177,0h0Z"
+      fill="#fff"
+    />
+    <path
+      d="M261.21387,242.74385c1.5069,4.53946-.95154,9.44101-5.49097,10.94791-.48401,.16064-.9812,.27823-1.4859,.35141l-10.83051,53.71692-11.44788-11.16785,12.29266-50.48209c-.37366-4.7944,3.21008-8.98395,8.00452-9.3576,4.01166-.31265,7.71509,2.16425,8.95807,5.9913Z"
+      fill="#a0616a"
+    />
+    <path
+      d="M146.12519,312.22478l-4.04883,3.41412c-3.73322,3.16214-5.53476,8.05035-4.74649,12.87888,.29129,1.83917,.95773,3.59879,1.95786,5.16949l.00824,.0123c3.01477,4.72311,8.5672,7.17865,14.08978,6.23117l22.27075-3.84171c21.28461,2.72995,46.15155-6.65967,72.34302-20.53055l10.67969-50.37274-24.23297-1.80811-9.16821,32.78271-55.78815,8.28149-.03278,.00415-19.64294,4.67767-3.68896,3.1011Z"
+      fill="#3f3d56"
+    />
+    <path
+      d="M272.93684,658.99046l-271.75,.30731c-.65759-.00214-1.18896-.53693-1.18683-1.19452,.00211-.6546,.53223-1.18469,1.18683-1.18683l271.75-.30731c.65759,.00214,1.18896,.53693,1.18683,1.19452-.00208,.6546-.53223,1.18469-1.18683,1.18683Z"
+      fill="#cacaca"
+    />
+    <g>
+      <ellipse
+        cx="56.77685"
+        cy="82.05834"
+        fill="#3f3d56"
+        rx="8.45661"
+        ry="8.64507"
+      />
+      <ellipse
+        cx="85.9906"
+        cy="82.05834"
+        fill="#3f3d56"
+        rx="8.45661"
+        ry="8.64507"
+      />
+      <ellipse
+        cx="115.20435"
+        cy="82.05834"
+        fill="#3f3d56"
+        rx="8.45661"
+        ry="8.64507"
+      />
+      <path
+        d="M148.51577,88.89113c-.25977,0-.51904-.10059-.71484-.30078l-5.70605-5.83301c-.38037-.38867-.38037-1.00977,0-1.39844l5.70605-5.83252c.38721-.39453,1.021-.40088,1.41406-.01562,.39502,.38623,.40186,1.01953,.01562,1.41406l-5.02197,5.1333,5.02197,5.13379c.38623,.39453,.37939,1.02783-.01562,1.41406-.19434,.19043-.44678,.28516-.69922,.28516Z"
+        fill="#3f3d56"
+      />
+      <path
+        d="M158.10415,88.89113c-.25244,0-.50488-.09473-.69922-.28516-.39502-.38623-.40186-1.01904-.01562-1.41406l5.02148-5.13379-5.02148-5.1333c-.38623-.39453-.37939-1.02783,.01562-1.41406,.39404-.38672,1.02783-.37939,1.41406,.01562l5.70557,5.83252c.38037,.38867,.38037,1.00977,0,1.39844l-5.70557,5.83301c-.1958,.2002-.45508,.30078-.71484,.30078Z"
+        fill="#3f3d56"
+      />
+      <path
+        d="M456.61398,74.41416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z"
+        fill="#3f3d56"
+      />
+      <path
+        d="M430.61398,74.41416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z"
+        fill="#3f3d56"
+      />
+      <path
+        d="M481.11398,74.91416h-10.60999c-1.21002,0-2.19,.97998-2.19,2.19v10.62c0,1.21002,.97998,2.19,2.19,2.19h10.60999c1.21002,0,2.20001-.97998,2.20001-2.19v-10.62c0-1.21002-.98999-2.19-2.20001-2.19Z"
+        fill="#3f3d56"
+      />
+      <path
+        d="M321.19229,78.95414h-84.81c-1.48004,0-2.67004,1.20001-2.67004,2.67004s1.19,2.66998,2.67004,2.66998h84.81c1.46997,0,2.66998-1.20001,2.66998-2.66998s-1.20001-2.67004-2.66998-2.67004Z"
+        fill="#3f3d56"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue
new file mode 100644
index 0000000..385cf6a
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue
@@ -0,0 +1,154 @@
+<template>
+  <svg
+    height="571"
+    viewBox="0 0 860 571"
+    width="860"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+  >
+    <path
+      d="M605.66974,324.95306c-7.66934-12.68446-16.7572-26.22768-30.98954-30.36953-16.482-4.7965-33.4132,4.73193-47.77473,14.13453a1392.15692,1392.15692,0,0,0-123.89338,91.28311l.04331.49238q46.22556-3.1878,92.451-6.37554c22.26532-1.53546,45.29557-3.2827,64.97195-13.8156,7.46652-3.99683,14.74475-9.33579,23.20555-9.70782,10.51175-.46217,19.67733,6.87923,26.8802,14.54931,42.60731,45.371,54.937,114.75409,102.73817,154.61591A1516.99453,1516.99453,0,0,0,605.66974,324.95306Z"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M867.57068,709.78146c-4.71167-5.94958-6.6369-7.343-11.28457-13.34761q-56.7644-73.41638-106.70791-151.79237-33.92354-53.23-64.48275-108.50439-14.54864-26.2781-28.29961-52.96872-10.67044-20.6952-20.8646-41.63793c-1.94358-3.98782-3.8321-7.99393-5.71122-12.00922-4.42788-9.44232-8.77341-18.93047-13.43943-28.24449-5.31686-10.61572-11.789-21.74485-21.55259-28.877a29.40493,29.40493,0,0,0-15.31855-5.89458c-7.948-.51336-15.28184,2.76855-22.17568,6.35295-50.43859,26.301-97.65922,59.27589-140.3696,96.79771A730.77816,730.77816,0,0,0,303.32241,496.24719c-1.008,1.43927-3.39164.06417-2.37419-1.38422q6.00933-8.49818,12.25681-16.81288A734.817,734.817,0,0,1,500.80465,303.06436q18.24824-11.82581,37.18269-22.54245c6.36206-3.60275,12.75188-7.15967,19.25136-10.49653,6.37146-3.27274,13.13683-6.21547,20.41563-6.32547,24.7701-.385,37.59539,27.66695,46.40506,46.54248q4.15283,8.9106,8.40636,17.76626,16.0748,33.62106,33.38729,66.628,10.68453,20.379,21.83683,40.51955,34.7071,62.71816,73.77854,122.897c34.5059,53.1429,68.73651,100.08874,108.04585,149.78472C870.59617,709.21309,868.662,711.17491,867.57068,709.78146Z"
+      fill="#e4e4e4"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M414.91613,355.804c-1.43911-1.60428-2.86927-3.20856-4.31777-4.81284-11.42244-12.63259-23.6788-25.11847-39.3644-32.36067a57.11025,57.11025,0,0,0-23.92679-5.54622c-8.56213.02753-16.93178,2.27348-24.84306,5.41792-3.74034,1.49427-7.39831,3.1902-11.00078,4.99614-4.11634,2.07182-8.15927,4.28118-12.1834,6.50883q-11.33112,6.27044-22.36816,13.09089-21.9606,13.57221-42.54566,29.21623-10.67111,8.11311-20.90174,16.75788-9.51557,8.03054-18.64618,16.492c-1.30169,1.20091-3.24527-.74255-1.94358-1.94347,1.60428-1.49428,3.22691-2.97938,4.84955-4.44613q6.87547-6.21546,13.9712-12.19257,12.93921-10.91827,26.54851-20.99312,21.16293-15.67614,43.78288-29.22541,11.30361-6.76545,22.91829-12.96259c2.33794-1.24675,4.70318-2.466,7.09572-3.6211a113.11578,113.11578,0,0,1,16.86777-6.86632,60.0063,60.0063,0,0,1,25.476-2.50265,66.32706,66.32706,0,0,1,23.50512,8.1314c15.40091,8.60812,27.34573,21.919,38.97,34.90915C418.03337,355.17141,416.09875,357.12405,414.91613,355.804Z"
+      fill="#e4e4e4"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M730.47659,486.71092l36.90462-13.498,18.32327-6.70183c5.96758-2.18267,11.92082-4.66747,18.08988-6.23036a28.53871,28.53871,0,0,1,16.37356.20862,37.73753,37.73753,0,0,1,12.771,7.91666,103.63965,103.63965,0,0,1,10.47487,11.18643c3.98932,4.79426,7.91971,9.63877,11.86772,14.46706q24.44136,29.89094,48.56307,60.04134,24.12117,30.14991,47.91981,60.556,23.85681,30.48041,47.38548,61.21573,2.88229,3.76518,5.75966,7.53415c1.0598,1.38809,3.44949.01962,2.37472-1.38808Q983.582,650.9742,959.54931,620.184q-24.09177-30.86383-48.51647-61.46586-24.42421-30.60141-49.17853-60.93743-6.16706-7.55761-12.35445-15.09858c-3.47953-4.24073-6.91983-8.52718-10.73628-12.47427-7.00539-7.24516-15.75772-13.64794-26.23437-13.82166-6.15972-.10214-12.121,1.85248-17.844,3.92287-6.16968,2.232-12.32455,4.50571-18.48633,6.75941l-37.16269,13.59243-9.29067,3.3981c-1.64875.603-.93651,3.2619.73111,2.652Z"
+      fill="#e4e4e4"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M366.37741,334.52609c-18.75411-9.63866-42.77137-7.75087-60.00508,4.29119a855.84708,855.84708,0,0,1,97.37056,22.72581C390.4603,353.75916,380.07013,341.5635,366.37741,334.52609Z"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M306.18775,338.7841l-3.61042,2.93462c1.22123-1.02713,2.4908-1.99013,3.795-2.90144C306.31073,338.80665,306.24935,338.79473,306.18775,338.7841Z"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M831.54929,486.84576c-3.6328-4.42207-7.56046-9.05222-12.99421-10.84836l-5.07308.20008A575.436,575.436,0,0,0,966.74929,651.418Q899.14929,569.13192,831.54929,486.84576Z"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M516.08388,450.36652A37.4811,37.4811,0,0,0,531.015,471.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M749.08388,653.36652A37.4811,37.4811,0,0,0,764.015,674.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M284.08388,639.36652A37.4811,37.4811,0,0,0,299.015,660.32518c2.82017,1.92011,6.15681,3.76209,7.12158,7.03463a8.37858,8.37858,0,0,1-.87362,6.1499,24.88351,24.88351,0,0,1-3.86126,5.04137l-.13667.512c-6.99843-4.14731-13.65641-9.3934-17.52227-16.55115s-4.40553-16.53895.34116-23.14544"
+      fill="#f2f2f2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <circle cx="649.24878" cy="51" fill="hsl(var(--primary))" r="51" />
+    <path
+      d="M911.21851,176.29639c-24.7168-3.34094-52.93512,10.01868-59.34131,34.12353a21.59653,21.59653,0,0,0-41.09351,2.10871l2.82972,2.02667a372.27461,372.27461,0,0,0,160.65881-.72638C957.07935,195.76,935.93537,179.63727,911.21851,176.29639Z"
+      fill="#f0f0f0"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M805.21851,244.29639c-24.7168-3.34094-52.93512,10.01868-59.34131,34.12353a21.59653,21.59653,0,0,0-41.09351,2.10871l2.82972,2.02667a372.27461,372.27461,0,0,0,160.65881-.72638C851.07935,263.76,829.93537,247.63727,805.21851,244.29639Z"
+      fill="#f0f0f0"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M1020.94552,257.15423a.98189.98189,0,0,1-.30176-.04688C756.237,173.48919,523.19942,184.42376,374.26388,208.32122c-20.26856,3.251-40.59131,7.00586-60.40381,11.16113-5.05811,1.05957-10.30567,2.19532-15.59668,3.37793-6.31885,1.40723-12.55371,2.85645-18.53223,4.30567q-3.873.917-7.59472,1.84863c-3.75831.92773-7.57178,1.89453-11.65967,2.957-4.56787,1.17774-9.209,2.41309-13.79737,3.67188a.44239.44239,0,0,1-.05127.01465l.00049.001c-5.18261,1.415-10.33789,2.8711-15.32324,4.3252-2.69824.77929-5.30371,1.54785-7.79932,2.30664-.2788.07715-.52587.15136-.77636.22754l-.53614.16308c-.31054.09473-.61718.1875-.92382.27539l-.01953.00586.00048.001-.81152.252c-.96777.293-1.91211.5791-2.84082.86426-24.54492,7.56641-38.03809,12.94922-38.17139,13.00195a1,1,0,1,1-.74414-1.85644c.13428-.05274,13.69336-5.46289,38.32764-13.05762.93213-.28613,1.87891-.57226,2.84961-.86621l.7539-.23438c.02588-.00976.05176-.01757.07813-.02539.30518-.08691.60986-.17968.91943-.27343l.53711-.16309c.26758-.08105.53125-.16113.80127-.23535,2.47852-.75391,5.09278-1.52441,7.79785-2.30664,4.98731-1.45508,10.14746-2.91113,15.334-4.32813.01611-.00586.03271-.00976.04883-.01464v-.001c4.60449-1.2627,9.26269-2.50293,13.84521-3.68457,4.09424-1.06348,7.915-2.03223,11.67969-2.96192q3.73755-.93017,7.60937-1.85253c5.98536-1.45118,12.23291-2.90235,18.563-4.3125,5.29932-1.1836,10.55567-2.32227,15.62207-3.38282,19.84326-4.16211,40.19776-7.92285,60.49707-11.17871C523.09591,182.415,756.46749,171.46282,1021.2463,255.2011a.99974.99974,0,0,1-.30078,1.95313Z"
+      fill="#ccc"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M432.92309,584.266a6.72948,6.72948,0,0,0-1.7-2.67,6.42983,6.42983,0,0,0-.92-.71c-2.61-1.74-6.51-2.13-8.99,0a5.81012,5.81012,0,0,0-.69.71q-1.11,1.365-2.28,2.67c-1.28,1.46-2.59,2.87-3.96,4.24-.39.38-.78.77-1.18,1.15-.23.23-.46.45-.69.67-.88.84-1.78,1.65-2.69,2.45-.48.43-.96.85-1.45,1.26-.73.61-1.46,1.22-2.2,1.81-.07.05-.14.1-.21.16-.02.01-.03.03-.05.04-.01,0-.02,0-.03.02a.17861.17861,0,0,0-.07.05c-.22.15-.37.25-.48.34.04-.01995.08-.05.12-.07-.18.14-.37.28-.55.42-1.75,1.29-3.54,2.53-5.37,3.69a99.21022,99.21022,0,0,1-14.22,7.55c-.33.13-.67.27-1.01.4a85.96993,85.96993,0,0,1-40.85,6.02q-2.13008-.165-4.26-.45c-1.64-.24-3.27-.53-4.89-.86a97.93186,97.93186,0,0,1-18.02-5.44,118.65185,118.65185,0,0,1-20.66-12.12c-1-.71-2.01-1.42-3.02-2.11,1.15-2.82,2.28-5.64,3.38-8.48.55-1.37,1.08-2.74,1.6-4.12,4.09-10.63,7.93-21.36,11.61-32.13q5.58-16.365,10.53-32.92.51-1.68.99-3.36,2.595-8.745,4.98-17.53c.15-.56994.31-1.12994.45-1.7q.68994-2.52,1.35-5.04c1-3.79-1.26-8.32-5.24-9.23a7.63441,7.63441,0,0,0-9.22,5.24c-.43,1.62-.86,3.23-1.3,4.85q-3.165,11.74494-6.66,23.41-.51,1.68-1.02,3.36-7.71,25.41-16.93,50.31-1.11,3.015-2.25,6.01c-.37.98-.74,1.96-1.12,2.94-.73,1.93-1.48,3.86-2.23,5.79-.43006,1.13-.87006,2.26-1.31,3.38-.29.71-.57,1.42-.85,2.12a41.80941,41.80941,0,0,0-8.81-2.12l-.48-.06a27.397,27.397,0,0,0-7.01.06,23.91419,23.91419,0,0,0-17.24,10.66c-4.77,7.51-4.71,18.25,1.98,24.63,6.89,6.57,17.32,6.52,25.43,2.41a28.35124,28.35124,0,0,0,10.52-9.86,50.56939,50.56939,0,0,0,2.74-4.65c.21.14.42.28.63.43.8.56,1.6,1.13,2.39,1.69a111.73777,111.73777,0,0,0,14.51,8.91,108.35887,108.35887,0,0,0,34.62,10.47c.27.03.53.07.8.1,1.33.17,2.67.3,4.01.41a103.78229,103.78229,0,0,0,55.58-11.36q2.175-1.125,4.31-2.36,3.315-1.92,6.48-4.08c1.15-.78,2.27-1.57,3.38-2.4a101.04244,101.04244,0,0,0,13.51-11.95q2.35491-2.475,4.51-5.11005a8.0612,8.0612,0,0,0,2.2-5.3A7.5644,7.5644,0,0,0,432.92309,584.266Zm-165.59,23.82c.21-.15.42-.31.62-.47C267.89312,607.766,267.60308,607.936,267.33312,608.086Zm3.21-3.23c-.23.26-.44.52-.67.78a23.36609,23.36609,0,0,1-2.25,2.2c-.11.1-.23.2-.35.29a.00976.00976,0,0,0-.01.01,3.80417,3.80417,0,0,0-.42005.22q-.645.39-1.31994.72a17.00459,17.00459,0,0,1-2.71.75,16.79925,16.79925,0,0,1-2.13.02h-.02a14.82252,14.82252,0,0,1-1.45-.4c-.24-.12-.47-.25994-.7-.4-.09-.08-.17005-.16-.22-.21a2.44015,2.44015,0,0,1-.26995-.29.0098.0098,0,0,0-.01-.01c-.11005-.2-.23005-.4-.34-.6a.031.031,0,0,1-.01-.02c-.08-.25-.15-.51-.21-.77a12.51066,12.51066,0,0,1,.01-1.37,13.4675,13.4675,0,0,1,.54-1.88,11.06776,11.06776,0,0,1,.69-1.26c.02-.04.12-.2.23-.38.01-.01.01-.01.01-.02.15-.17.3-.35.46-.51.27-.3.56-.56.85-.83a18.02212,18.02212,0,0,1,1.75-1.01,19.48061,19.48061,0,0,1,2.93-.79,24.98945,24.98945,0,0,1,4.41.04,30.30134,30.30134,0,0,1,4.1,1.01,36.94452,36.94452,0,0,1-2.77,4.54C270.6231,604.746,270.58312,604.806,270.54308,604.856Zm-11.12-3.29a2.18029,2.18029,0,0,1-.31.38995A1.40868,1.40868,0,0,1,259.42309,601.566Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M402.86309,482.136q-.13494,4.71-.27,9.42-.285,10.455-.59,20.92-.315,11.775-.66,23.54-.165,6.07507-.34,12.15-.465,16.365-.92,32.72c-.03,1.13-.07,2.25-.1,3.38q-.225,8.11506-.45,16.23-.255,8.805-.5,17.61-.18,6.59994-.37,13.21-1.34994,47.895-2.7,95.79a7.64844,7.64844,0,0,1-7.5,7.5,7.56114,7.56114,0,0,1-7.5-7.5q.75-26.94,1.52-53.88.675-24.36,1.37-48.72.225-8.025.45-16.06.345-12.09.68-24.18c.03-1.13.07-2.25.1-3.38.02-.99.05-1.97.08-2.96q.66-23.475,1.32-46.96.27-9.24.52-18.49.3-10.545.6-21.08c.09-3.09.17005-6.17.26-9.26a7.64844,7.64844,0,0,1,7.5-7.5A7.56116,7.56116,0,0,1,402.86309,482.136Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M814.29118,484.2172a893.23753,893.23753,0,0,1-28.16112,87.94127c-3.007,7.94641-6.08319,15.877-9.3715,23.71185l.75606-1.7916a54.58274,54.58274,0,0,1-5.58953,10.61184q-.22935.32119-.46685.63642,1.16559-1.49043.4428-.589c-.25405.30065-.5049.60219-.7676.89546a23.66436,23.66436,0,0,1-2.2489,2.20318q-.30139.25767-.61188.5043l.93783-.729c-.10884.25668-.87275.59747-1.11067.74287a18.25362,18.25362,0,0,1-2.40479,1.21853l1.7916-.75606a19.0859,19.0859,0,0,1-4.23122,1.16069l1.9938-.26791a17.02055,17.02055,0,0,1-4.29785.046l1.99379.2679a14.0022,14.0022,0,0,1-3.40493-.917l1.79159.75606a12.01175,12.01175,0,0,1-1.67882-.89614c-.27135-.17688-1.10526-.80852-.01487.02461,1.13336.86595.14562.07434-.08763-.15584-.19427-.19171-.36962-.4-.55974-.595-.88208-.90454.99637,1.55662.39689.49858a18.18179,18.18179,0,0,1-.87827-1.63672l.75606,1.7916a11.92493,11.92493,0,0,1-.728-2.65143l.26791,1.9938a13.65147,13.65147,0,0,1-.00316-3.40491l-.2679,1.9938a15.96371,15.96371,0,0,1,.99486-3.68011l-.75606,1.7916a16.72914,16.72914,0,0,1,1.17794-2.29848,6.72934,6.72934,0,0,1,.72851-1.0714c.04915.01594-1.26865,1.51278-.56937.757.1829-.19767.354-.40592.539-.602.29617-.31382.61354-.60082.92561-.89791,1.04458-.99442-1.46188.966-.25652.17907a19.0489,19.0489,0,0,1,2.74925-1.49923l-1.79159.75606a20.31136,20.31136,0,0,1,4.99523-1.33984l-1.9938.2679a25.62828,25.62828,0,0,1,6.46062.07647l-1.9938-.2679a33.21056,33.21056,0,0,1,7.89178,2.2199l-1.7916-.75606c5.38965,2.31383,10.16308,5.74926,14.928,9.118a111.94962,111.94962,0,0,0,14.50615,8.9065,108.38849,108.38849,0,0,0,34.62226,10.47371,103.93268,103.93268,0,0,0,92.58557-36.75192,8.07773,8.07773,0,0,0,2.1967-5.3033,7.63232,7.63232,0,0,0-2.1967-5.3033c-2.75154-2.52586-7.94926-3.239-10.6066,0a95.63575,95.63575,0,0,1-8.10664,8.72692q-2.01736,1.914-4.14232,3.70983-1.21364,1.02588-2.46086,2.01121c-.3934.31081-1.61863,1.13807.26309-.19744-.43135.30614-.845.64036-1.27058.95478a99.26881,99.26881,0,0,1-20.33215,11.56478l1.79159-.75606a96.8364,96.8364,0,0,1-24.17119,6.62249l1.99379-.2679a97.64308,97.64308,0,0,1-25.75362-.03807l1.99379.2679a99.79982,99.79982,0,0,1-24.857-6.77027l1.7916.75607a116.02515,116.02515,0,0,1-21.7364-12.59112,86.87725,86.87725,0,0,0-11.113-6.99417,42.8238,42.8238,0,0,0-14.43784-4.38851c-9.43884-1.11076-19.0571,2.56562-24.24624,10.72035-4.77557,7.50482-4.71394,18.24362,1.97369,24.62519,6.8877,6.5725,17.31846,6.51693,25.43556,2.40567,7.81741-3.95946,12.51288-12.18539,15.815-19.94186,7.43109-17.45514,14.01023-35.31364,20.1399-53.263q9.09651-26.63712,16.49855-53.81332.91661-3.36581,1.80683-6.73869c1.001-3.78869-1.26094-8.32-5.23829-9.22589a7.63317,7.63317,0,0,0-9.22589,5.23829Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M889.12382,482.13557l-2.69954,95.79311-2.68548,95.29418-1.5185,53.88362a7.56465,7.56465,0,0,0,7.5,7.5,7.64923,7.64923,0,0,0,7.5-7.5l2.69955-95.79311,2.68548-95.29418,1.51849-53.88362a7.56465,7.56465,0,0,0-7.5-7.5,7.64923,7.64923,0,0,0-7.5,7.5Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M629.52566,700.36106h2.32885V594.31942h54.32863v-2.32291H631.85451V547.25214H673.8102q-.92256-1.17339-1.89893-2.31694H631.85451V515.38231c-.7703-.32846-1.54659-.64493-2.32885-.9435V544.9352h-45.652V507.07c-.78227.03583-1.55258.08959-2.3289.15527v37.71h-36.4201V516.68409c-.78227.34636-1.55258.71061-2.31694,1.0928V544.9352h-30.6158v2.31694h30.6158v44.74437h-30.6158v2.32291h30.6158V700.36106h2.31694V594.31942a36.41283,36.41283,0,0,1,36.4201,36.42007v69.62157h2.3289V594.31942h45.652Zm-84.401-108.36455V547.25214h36.4201v44.74437Zm38.749,0V547.25214h.91362a44.74135,44.74135,0,0,1,44.73842,44.74437Z"
+      opacity="0.2"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M615.30309,668.566a63.05854,63.05854,0,0,1-20.05,33.7c-.74.64-1.48,1.26-2.25,1.87q-2.805.25506-5.57.52c-1.53.14-3.04.29-4.54.43l-.27.03-.19-1.64-.76-6.64a37.623,37.623,0,0,1-3.3-32.44c2.64-7.12,7.42-13.41,12.12-19.65,6.49-8.62,12.8-17.14,13.03-27.65a60.54415,60.54415,0,0,1,7.9,13.33,16.432,16.432,0,0,0-5.12,3.76995c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39,1,.11,2,.21,3,.32a63.99025,63.99025,0,0,1,2.45,12.18A61.18851,61.18851,0,0,1,615.30309,668.566Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M648.50311,642.356c-5.9,4.29-9.35,10.46-12.03,17.26a16.62776,16.62776,0,0,0-7.17,4.58c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39-2.68,8.04-5.14,16.36-9.88,23.15a36.98942,36.98942,0,0,1-12.03,10.91,38.49166,38.49166,0,0,1-4.02,1.99q-7.62.585-14.95,1.25-2.805.25506-5.57.52c-1.53.14-3.04.29-4.54.43q-.015-.825,0-1.65a63.30382,63.30382,0,0,1,15.25-39.86c.45-.52.91-1.03,1.38-1.54a61.7925,61.7925,0,0,1,16.81-12.7A62.65425,62.65425,0,0,1,648.50311,642.356Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M589.16308,699.526l-1.15,3.4-.58,1.73c-1.53.14-3.04.29-4.54.43l-.27.03c-1.66.17-3.31.34-4.96.51-.43-.5-.86-1.01-1.28-1.53a62.03045,62.03045,0,0,1,8.07-87.11c-1.32,6.91.22,13.53,2.75,20.1-.27.11-.53.22-.78.34a16.432,16.432,0,0,0-5.12,3.76995c-.41.45-.82,1.08-.54,1.62006.24.46.84.57,1.36.62994,1.25.13,2.51.26,3.76.39,1,.11,2,.21,3,.32q.705.075,1.41.15c.07.15.13.29.2.44,2.85,6.18,5.92,12.39,7.65,18.83a43.66591,43.66591,0,0,1,1.02,4.91A37.604,37.604,0,0,1,589.16308,699.526Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M689.82123,554.48655c-8.60876-16.79219-21.94605-30.92088-37.63219-41.30357a114.2374,114.2374,0,0,0-52.5626-18.37992q-3.69043-.33535-7.399-.39281c-2.92141-.04371-46.866,12.63176-61.58712,22.98214a114.29462,114.29462,0,0,0-35.333,39.527,102.49972,102.49972,0,0,0-12.12557,51.6334,113.56387,113.56387,0,0,0,14.70268,51.47577,110.47507,110.47507,0,0,0,36.44425,38.74592C549.66655,708.561,565.07375,734.51,583.1831,735.426c18.24576.923,39.05418-23.55495,55.6951-30.98707a104.42533,104.42533,0,0,0,41.72554-34.005,110.24964,110.24964,0,0,0,19.599-48.94777c2.57368-18.08313,1.37415-36.73271-4.80123-54.01627a111.85969,111.85969,0,0,0-5.58024-12.9833c-1.77961-3.50519-6.996-4.7959-10.26142-2.69063a7.67979,7.67979,0,0,0-2.69064,10.26142q1.56766,3.08773,2.91536,6.27758l-.75606-1.7916a101.15088,101.15088,0,0,1,6.87641,25.53816l-.26791-1.99379a109.2286,109.2286,0,0,1-.06613,28.68252l.26791-1.9938a109.73379,109.73379,0,0,1-7.55462,27.67419l.75606-1.79159a104.212,104.212,0,0,1-6.67151,13.09835q-1.92308,3.18563-4.08062,6.22159c-.63172.8881-1.28287,1.761-1.939,2.63114-.85625,1.13555,1.16691-1.48321.28228-.36941-.15068.18972-.30049.3801-.45182.5693q-.68121.85165-1.3818,1.68765a93.61337,93.61337,0,0,1-10.17647,10.38359q-1.36615,1.19232-2.77786,2.33115c-.46871.37832-.932.77269-1.42079,1.12472.01861-.0134,1.57956-1.19945.65556-.511-.2905.21644-.57851.43619-.86961.65184q-2.90994,2.1558-5.97433,4.092a103.48509,103.48509,0,0,1-14.75565,7.7131l1.7916-.75606a109.21493,109.21493,0,0,1-27.59663,7.55154l1.9938-.26791a108.15361,108.15361,0,0,1-28.58907.0506l1.99379.2679a99.835,99.835,0,0,1-25.09531-6.78448l1.79159.75607a93.64314,93.64314,0,0,1-13.41605-6.99094q-3.17437-2-6.18358-4.24743c-.2862-.21359-.56992-.43038-.855-.64549-.9155-.69088.65765.50965.67021.51787a19.16864,19.16864,0,0,1-1.535-1.22469q-1.45353-1.18358-2.86136-2.4218a101.98931,101.98931,0,0,1-10.49319-10.70945q-1.21308-1.43379-2.37407-2.91054c-.33524-.4263-.9465-1.29026.40424.5289-.17775-.23939-.36206-.47414-.54159-.71223q-.64657-.85751-1.27568-1.72793-2.203-3.048-4.18787-6.24586a109.29037,109.29037,0,0,1-7.8054-15.10831l.75606,1.7916a106.58753,106.58753,0,0,1-7.34039-26.837l.26791,1.9938a97.86589,97.86589,0,0,1-.04843-25.63587l-.2679,1.9938A94.673,94.673,0,0,1,505.27587,570.55l-.75606,1.7916a101.55725,101.55725,0,0,1,7.19519-13.85624q2.0655-3.32328,4.37767-6.4847.52528-.71832,1.06244-1.42786c.324-.4279,1.215-1.49333-.30537.38842.14906-.18449.29252-.37428.43942-.56041q1.26882-1.60756,2.59959-3.1649A107.40164,107.40164,0,0,1,530.772,536.21508q1.47408-1.29171,2.99464-2.52906.6909-.56218,1.39108-1.11284c.18664-.14673.37574-.29073.56152-.43858-1.99743,1.58953-.555.43261-.10157.09288q3.13393-2.34833,6.43534-4.46134a103.64393,103.64393,0,0,1,15.38655-8.10791l-1.7916.75606c7.76008-3.25839,42.14086-10.9492,48.394-10.10973l-1.99379-.26791A106.22471,106.22471,0,0,1,628.768,517.419l-1.7916-.75606a110.31334,110.31334,0,0,1,12.6002,6.32922q3.04344,1.78405,5.96742,3.76252,1.38351.93658,2.73809,1.915.677.48917,1.34626.98885c.24789.185.49386.37253.74135.558,1.03924.779-1.43148-1.1281-.34209-.26655a110.84261,110.84261,0,0,1,10.36783,9.2532q2.401,2.445,4.63686,5.04515,1.14659,1.33419,2.24643,2.70757c.36436.45495,1.60506,2.101.08448.08457.37165.49285.74744.98239,1.11436,1.47884a97.97718,97.97718,0,0,1,8.39161,13.53807c1.79317,3.49775,6.98675,4.80186,10.26142,2.69064A7.67666,7.67666,0,0,0,689.82123,554.48655Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M602.43116,676.88167a3.77983,3.77983,0,0,1-2.73939-6.55137c.09531-.37882.16368-.65085.259-1.02968q-.05115-.12366-.1029-.24717c-3.47987-8.29769-25.685,14.83336-26.645,22.63179a30.029,30.029,0,0,0,.52714,10.32752A120.39223,120.39223,0,0,1,562.77838,652.01a116.20247,116.20247,0,0,1,.72078-12.96332q.59712-5.293,1.65679-10.51055a121.78667,121.78667,0,0,1,24.1515-51.61646c6.87378.38364,12.898-.66348,13.47967-13.98532.10346-2.36972,1.86113-4.42156,2.24841-6.756-.65621.08607-1.32321.13985-1.97941.18285-.20444.0107-.41958.02149-.624.03228l-.07709.00346a3.745,3.745,0,0,1-3.07566-6.10115q.425-.52305.85054-1.04557c.43036-.53793.87143-1.06507,1.30171-1.60292a1.865,1.865,0,0,0,.13986-.16144c.49494-.61322.98971-1.21564,1.48465-1.82885a10.82911,10.82911,0,0,0-3.55014-3.43169c-4.95941-2.90463-11.80146-.89293-15.38389,3.59313-3.59313,4.486-4.27083,10.77947-3.023,16.3843a43.39764,43.39764,0,0,0,6.003,13.3828c-.269.34429-.54872.67779-.81765,1.02209a122.57366,122.57366,0,0,0-12.79359,20.2681c1.0163-7.93863-11.41159-36.60795-16.21776-42.68052-5.773-7.29409-17.61108-4.11077-18.62815,5.13562q-.01476.13428-.02884.26849,1.07082.60411,2.0964,1.28237a5.12707,5.12707,0,0,1-2.06713,9.33031l-.10452.01613c-9.55573,13.64367,21.07745,49.1547,28.74518,41.18139a125.11045,125.11045,0,0,0-6.73449,31.69282,118.66429,118.66429,0,0,0,.08607,19.15986l-.03231-.22593C558.90163,648.154,529.674,627.51374,521.139,629.233c-4.91675.99041-9.75952.76525-9.01293,5.72484q.01788.11874.03635.2375a34.4418,34.4418,0,0,1,3.862,1.86105q1.07082.60423,2.09639,1.28237a5.12712,5.12712,0,0,1-2.06712,9.33039l-.10464.01606c-.07528.01079-.13987.02157-.21507.03237-4.34967,14.96631,27.90735,39.12,47.5177,31.43461h.01081a125.07484,125.07484,0,0,0,8.402,24.52806H601.679c.10765-.3335.20443-.67779.3013-1.01129a34.102,34.102,0,0,1-8.30521-.49477c2.22693-2.73257,4.45377-5.48664,6.6807-8.21913a1.86122,1.86122,0,0,0,.13986-.16135c1.12956-1.39849,2.26992-2.78627,3.39948-4.18476l.00061-.00173a49.95232,49.95232,0,0,0-1.46367-12.72495Zm-34.37066-67.613.0158-.02133-.0158.04282Zm-6.64832,59.93237-.25822-.58084c.01079-.41957.01079-.83914,0-1.26942,0-.11845-.0215-.23672-.0215-.35508.09678.74228.18285,1.48464.29042,2.22692Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <circle cx="95.24878" cy="439" fill="hsl(var(--foreground))" r="11" />
+    <circle cx="227.24878" cy="559" fill="hsl(var(--foreground))" r="11" />
+    <circle cx="728.24878" cy="559" fill="hsl(var(--foreground))" r="11" />
+    <circle cx="755.24878" cy="419" fill="hsl(var(--foreground))" r="11" />
+    <circle cx="723.24878" cy="317" fill="hsl(var(--foreground))" r="11" />
+    <path
+      d="M434.1831,583.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,434.1831,583.426Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <circle cx="484.24878" cy="349" fill="hsl(var(--foreground))" r="11" />
+    <path
+      d="M545.1831,513.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,545.1831,513.426Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <path
+      d="M403.1831,481.426a10.949,10.949,0,1,1-.21-2.16A10.9921,10.9921,0,0,1,403.1831,481.426Z"
+      fill="hsl(var(--foreground))"
+      transform="translate(-169.93432 -164.42601)"
+    />
+    <circle cx="599.24878" cy="443" fill="hsl(var(--foreground))" r="11" />
+    <circle cx="426.24878" cy="338" fill="hsl(var(--foreground))" r="16" />
+    <path
+      d="M1028.875,735.26666l-857.75.30733a1.19068,1.19068,0,1,1,0-2.38136l857.75-.30734a1.19069,1.19069,0,0,1,0,2.38137Z"
+      fill="#cacaca"
+      transform="translate(-169.93432 -164.42601)"
+    />
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue
new file mode 100644
index 0000000..97326b7
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue
@@ -0,0 +1,215 @@
+<template>
+  <svg
+    height="699"
+    viewBox="0 0 1119 699"
+    width="1119"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+  >
+    <title>server down</title>
+    <circle cx="292.60911" cy="213" fill="#f2f2f2" r="213" />
+    <path
+      d="M31.39089,151.64237c0,77.49789,48.6181,140.20819,108.70073,140.20819"
+      fill="#2f2e41"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M140.09162,291.85056c0-78.36865,54.255-141.78356,121.30372-141.78356"
+      fill="hsl(var(--primary))"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M70.77521,158.66768c0,73.61476,31.00285,133.18288,69.31641,133.18288"
+      fill="hsl(var(--primary))"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M140.09162,291.85056c0-100.13772,62.7103-181.16788,140.20819-181.16788"
+      fill="#2f2e41"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M117.22379,292.83905s15.41555-.47479,20.06141-3.783,23.713-7.2585,24.86553-1.95278,23.16671,26.38821,5.76263,26.5286-40.43935-2.711-45.07627-5.53549S117.22379,292.83905,117.22379,292.83905Z"
+      fill="#a8a8a8"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M168.224,311.78489c-17.40408.14042-40.43933-2.71094-45.07626-5.53548-3.53126-2.151-4.93843-9.86945-5.40926-13.43043-.32607.014-.51463.02-.51463.02s.97638,12.43276,5.61331,15.2573,27.67217,5.67589,45.07626,5.53547c5.02386-.04052,6.7592-1.82793,6.66391-4.47526C173.87935,310.756,171.96329,311.75474,168.224,311.78489Z"
+      opacity="0.2"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <ellipse cx="198.60911" cy="424.5" fill="#3f3d56" rx="187" ry="25.43993" />
+    <ellipse cx="198.60911" cy="424.5" opacity="0.1" rx="157" ry="21.35866" />
+    <ellipse cx="836.60911" cy="660.5" fill="#3f3d56" rx="283" ry="38.5" />
+    <ellipse cx="310.60911" cy="645.5" fill="#3f3d56" rx="170" ry="23.12721" />
+    <path
+      d="M494,726.5c90,23,263-30,282-90"
+      fill="none"
+      stroke="#2f2e41"
+      stroke-miterlimit="10"
+      stroke-width="2"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M341,359.5s130-36,138,80-107,149-17,172"
+      fill="none"
+      stroke="#2f2e41"
+      stroke-miterlimit="10"
+      stroke-width="2"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M215.40233,637.78332s39.0723-10.82,41.47675,24.04449-32.15951,44.78287-5.10946,51.69566"
+      fill="none"
+      stroke="#2f2e41"
+      stroke-miterlimit="10"
+      stroke-width="2"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M810.09554,663.73988,802.218,714.03505s-38.78182,20.60284-11.51335,21.20881,155.73324,0,155.73324,0,24.84461,0-14.54318-21.81478l-7.87756-52.719Z"
+      fill="#2f2e41"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M785.21906,734.69812c6.193-5.51039,16.9989-11.252,16.9989-11.252l7.87756-50.2952,113.9216.10717,7.87756,49.582c9.185,5.08711,14.8749,8.987,18.20362,11.97818,5.05882-1.15422,10.58716-5.44353-18.20362-21.38921l-7.87756-52.719-113.9216,3.02983L802.218,714.03506S769.62985,731.34968,785.21906,734.69812Z"
+      opacity="0.1"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <rect
+      fill="#2f2e41"
+      height="357.51989"
+      rx="18.04568"
+      width="513.25314"
+      x="578.43291"
+      y="212.68859"
+    />
+    <rect
+      fill="#3f3d56"
+      height="267.83694"
+      width="478.71308"
+      x="595.70294"
+      y="231.77652"
+    />
+    <circle cx="835.05948" cy="223.29299" fill="#f2f2f2" r="3.02983" />
+    <path
+      d="M1123.07694,621.32226V652.6628a18.04341,18.04341,0,0,1-18.04568,18.04568H627.86949A18.04341,18.04341,0,0,1,609.8238,652.6628V621.32226Z"
+      fill="#2f2e41"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <polygon
+      fill="#2f2e41"
+      points="968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 651.452 645.651 962.312 645.651 968.978 667.466"
+    />
+    <path
+      d="M1125.828,762.03359c-.59383,2.539-2.83591,5.21743-7.90178,7.75032-18.179,9.08949-55.1429-2.42386-55.1429-2.42386s-28.4804-4.84773-28.4804-17.573a22.72457,22.72457,0,0,1,2.49658-1.48459c7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z"
+      fill="#2f2e41"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <path
+      d="M1125.828,762.03359c-22.251,8.526-42.0843,9.1622-62.43871-4.975-10.26507-7.12617-19.59089-8.88955-26.58979-8.75618,7.64294-4.04351,32.98449-14.02122,77.9177.42248a18.73921,18.73921,0,0,1,8.54106,5.59715C1125.07908,756.45353,1126.50669,759.15715,1125.828,762.03359Z"
+      opacity="0.1"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <ellipse
+      cx="1066.53846"
+      cy="654.13477"
+      fill="#f2f2f2"
+      rx="7.87756"
+      ry="2.42386"
+    />
+    <circle cx="835.05948" cy="545.66686" fill="#f2f2f2" r="11.51335" />
+    <polygon
+      opacity="0.1"
+      points="968.978 667.466 968.978 673.526 642.968 673.526 642.968 668.678 643.417 667.466 968.978 667.466"
+    />
+    <rect fill="#2f2e41" height="242" width="208" x="108.60911" y="159" />
+    <rect fill="#3f3d56" height="86" width="250" x="87.60911" y="135" />
+    <rect fill="#3f3d56" height="86" width="250" x="87.60911" y="237" />
+    <rect fill="#3f3d56" height="86" width="250" x="87.60911" y="339" />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.4"
+      width="16"
+      x="271.60911"
+      y="150"
+    />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.8"
+      width="16"
+      x="294.60911"
+      y="150"
+    />
+    <rect fill="#6c63ff" height="16" width="16" x="317.60911" y="150" />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.4"
+      width="16"
+      x="271.60911"
+      y="251"
+    />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.8"
+      width="16"
+      x="294.60911"
+      y="251"
+    />
+    <rect fill="#6c63ff" height="16" width="16" x="317.60911" y="251" />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.4"
+      width="16"
+      x="271.60911"
+      y="352"
+    />
+    <rect
+      fill="#6c63ff"
+      height="16"
+      opacity="0.8"
+      width="16"
+      x="294.60911"
+      y="352"
+    />
+    <rect fill="#6c63ff" height="16" width="16" x="317.60911" y="352" />
+    <circle cx="316.60911" cy="538" fill="#2f2e41" r="79" />
+    <rect fill="#2f2e41" height="43" width="24" x="280.60911" y="600" />
+    <rect fill="#2f2e41" height="43" width="24" x="328.60911" y="600" />
+    <ellipse cx="300.60911" cy="643.5" fill="#2f2e41" rx="20" ry="7.5" />
+    <ellipse cx="348.60911" cy="642.5" fill="#2f2e41" rx="20" ry="7.5" />
+    <circle cx="318.60911" cy="518" fill="#fff" r="27" />
+    <circle cx="318.60911" cy="518" fill="#3f3d56" r="9" />
+    <path
+      d="M271.36733,565.03228c-6.37889-28.56758,14.01185-57.43392,45.544-64.47477s62.2651,10.41,68.644,38.9776-14.51861,39.10379-46.05075,46.14464S277.74622,593.59986,271.36733,565.03228Z"
+      fill="#6c63ff"
+      transform="translate(-31.39089 -100.5)"
+    />
+    <ellipse
+      cx="417.21511"
+      cy="611.34365"
+      fill="#2f2e41"
+      rx="39.5"
+      ry="12.40027"
+      transform="translate(-238.28665 112.98044) rotate(-23.17116)"
+    />
+    <ellipse
+      cx="269.21511"
+      cy="664.34365"
+      fill="#2f2e41"
+      rx="39.5"
+      ry="12.40027"
+      transform="translate(-271.07969 59.02084) rotate(-23.17116)"
+    />
+    <path
+      d="M394,661.5c0,7.732-19.90861,23-42,23s-43-14.268-43-22,20.90861-6,43-6S394,653.768,394,661.5Z"
+      fill="#fff"
+      transform="translate(-31.39089 -100.5)"
+    />
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue
new file mode 100644
index 0000000..e511c43
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue
@@ -0,0 +1,262 @@
+<template>
+  <svg
+    data-name="Layer 1"
+    height="424.8366"
+    viewBox="0 0 979.32677 424.8366"
+    width="979.32677"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+  >
+    <path
+      d="M993.71816,412.83936H419.142a9.19888,9.19888,0,0,0,0,18.39776H435.417V651.3026a9.19888,9.19888,0,0,0,18.39776,0l.1398-220.06548h461.1557l42.52,220.06548a9.19887,9.19887,0,1,0,18.39775,0l2.67633-220.06548h15.01383a9.19888,9.19888,0,0,0,0-18.39776Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M518.73716,371.85047v38.9547H421.141a19.48915,19.48915,0,1,1-1.35523-38.95474q.67739-.02358,1.35523,0Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M521.13449,410.50552a1.49881,1.49881,0,0,1-1.49822,1.49822H419.40273a20.52615,20.52615,0,0,1,0-41.05229H519.63627a1.49827,1.49827,0,1,1,0,2.99653H419.40273a17.52964,17.52964,0,0,0,0,35.05924H519.63627A1.49883,1.49883,0,0,1,521.13449,410.50552Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M518.73716,380.84H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M518.73716,388.03169H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M518.73716,395.22332H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M518.73716,402.41487H413.85905a.29966.29966,0,0,1-.00552-.59929H518.73716a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M500.33941,330.80932v38.95474H402.74324a19.48915,19.48915,0,0,1-1.35522-38.95474q.67737-.02358,1.35522,0Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M502.73673,369.46442a1.49885,1.49885,0,0,1-1.49822,1.49826H401.005a20.52614,20.52614,0,0,1,0-41.05229H501.23851a1.49826,1.49826,0,1,1,0,2.99652H401.005a17.52964,17.52964,0,0,0,0,35.05928H501.23851A1.49884,1.49884,0,0,1,502.73673,369.46442Z"
+      fill="#3f3d56"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M500.33941,339.79886H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M500.33941,346.99054H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M500.33941,354.18217H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M500.33941,361.37376H395.4613a.29966.29966,0,0,1-.00553-.59929H500.33941a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M613.87355,550.68347V516.71838a5.661,5.661,0,0,0-5.66085-5.66085H479.4284a5.661,5.661,0,0,0-5.66084,5.66085v33.96509Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <rect
+      fill="#ccc"
+      height="43.87158"
+      width="140.10602"
+      x="363.43092"
+      y="325.83868"
+    />
+    <path
+      d="M473.76756,620.02887V653.994a5.661,5.661,0,0,0,5.66084,5.66084H608.2127a5.661,5.661,0,0,0,5.66085-5.66084V620.02887Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <circle cx="432.77633" cy="294.70402" fill="#fff" r="4.24564" />
+    <circle cx="432.77633" cy="351.3125" fill="#fff" r="4.24564" />
+    <circle cx="433.00385" cy="406.72228" fill="#fff" r="4.24564" />
+    <path
+      d="M597.989,472.33053v38.9547H500.39287a19.48916,19.48916,0,0,1-1.35647-38.9547q.678-.02358,1.35647,0Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M600.38637,510.98558a1.49881,1.49881,0,0,1-1.49822,1.49822H498.65461a20.52615,20.52615,0,0,1-.0247-41.05229H598.88815a1.49827,1.49827,0,1,1,0,2.99653H498.65461a17.52963,17.52963,0,0,0,0,35.05923H598.88815A1.49885,1.49885,0,0,1,600.38637,510.98558Z"
+      fill="#3f3d56"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M597.989,481.32H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M597.989,488.51175H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M597.989,495.70338H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M597.989,502.89493H493.111a.29966.29966,0,0,1-.00553-.59929H597.98913a.29966.29966,0,0,1,0,.59929Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M483.36747,317.81415H438.90162a2.74745,2.74745,0,0,0-1.21689.28306l-11.22288,5.61835a2.0452,2.0452,0,0,0,0,3.76443l11.22288,5.61835a2.74718,2.74718,0,0,0,1.21689.28306h44.46585a2.33381,2.33381,0,0,0,2.4628-2.16532v-11.2367A2.3338,2.3338,0,0,0,483.36747,317.81415Z"
+      fill="#3f3d56"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M485.83027,319.97947v11.2367a2.33383,2.33383,0,0,1-2.4628,2.16532h-8.8589V317.81415h8.8589A2.33383,2.33383,0,0,1,485.83027,319.97947Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M216.78083,537.99332a35.33951,35.33951,0,0,0,34.12552-6.01134c11.95262-10.03214,15.70013-26.56,18.74934-41.864q4.50949-22.63308,9.019-45.26617l-18.88217,13.00153c-13.57891,9.34993-27.46375,18.99939-36.86572,32.54233S209.42082,522.42587,216.975,537.08"
+      fill="#e6e6e6"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M218.39489,592.79741c-1.91113-13.92071-3.87625-28.0202-2.53572-42.09016,1.19057-12.4956,5.00277-24.70032,12.764-34.70734a57.73582,57.73582,0,0,1,14.81307-13.42309c1.48131-.935,2.84468,1.41257,1.36983,2.34348a54.88844,54.88844,0,0,0-21.71125,26.19626c-4.72684,12.02273-5.48591,25.12848-4.67135,37.90006.4926,7.72345,1.53656,15.39627,2.58859,23.05926a1.40615,1.40615,0,0,1-.94781,1.66928,1.3653,1.3653,0,0,1-1.6693-.94781Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M236.80246,568.16434a26.01425,26.01425,0,0,0,22.6665,11.69871c11.47417-.54466,21.04-8.55293,29.651-16.15584l25.46969-22.48783-16.85671-.80672c-12.12234-.58011-24.55745-1.12124-36.10356,2.617s-22.19457,12.73508-24.30583,24.68624"
+      fill="#e6e6e6"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M212.99392,600.79976c9.19853-16.27621,19.86805-34.36538,38.93262-40.14695A43.445,43.445,0,0,1,268.3022,558.962c1.73863.14991,1.30448,2.82994-.431,2.6803a40.36111,40.36111,0,0,0-26.133,6.91386c-7.36852,5.01554-13.10573,11.98848-17.96161,19.383-2.97439,4.52936-5.63867,9.25082-8.30346,13.966-.85161,1.50687-3.34078.41915-2.47922-1.10534Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M198.25523,617.93168a19.69836,19.69836,0,0,1,12.0709-16.49847v-9.40956h15.782v9.70608a19.68812,19.68812,0,0,1,11.41362,16.202l3.711,43.13835H194.54417Z"
+      fill="#f2f2f2"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M734.973,411.955l-4.69488-1.97685-3.22067-23.53551h-42.889l-3.491,23.43936-4.20031,2.10013a.99744.99744,0,0,0,.44611,1.88955h57.66283A.99739.99739,0,0,0,734.973,411.955Z"
+      fill="#e6e6e6"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M811.1898,389.574H600.50692a4.174,4.174,0,0,1-4.16467-4.174V355.69092H815.35446V385.4A4.17408,4.17408,0,0,1,811.1898,389.574Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M815.57469,369.73213H596.15V242.61337a5.0375,5.0375,0,0,1,5.03186-5.03167h209.361a5.03755,5.03755,0,0,1,5.03191,5.03167Z"
+      fill="#3f3d56"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M802.46932,360.50584h-193.214a3.88344,3.88344,0,0,1-3.87919-3.87908V250.68707a3.88365,3.88365,0,0,1,3.87919-3.87932h193.214a3.88366,3.88366,0,0,1,3.8792,3.87932V356.62676A3.88345,3.88345,0,0,1,802.46932,360.50584Z"
+      fill="#fff"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M751.57964,397.88662a11.6159,11.6159,0,0,1,17.666,2.27241l26.13446-4.64642,6.69716,15.19317-36.99908,6.04328a11.67883,11.67883,0,0,1-13.49855-18.86244Z"
+      fill="#ffb6b6"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M775.77611,417.286l27.24571-.33963,3.44882-.04668,55.43253-.69843s15.05312-14.3609,28.16068-29.1465l-1.83719-13.28833A54.29159,54.29159,0,0,0,870.023,340.1519C851.24988,352.696,840.363,377.52559,840.363,377.52559l-34.37018,8.22071-3.43848.82227-21.35608,5.10326Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M915.25011,498.96167H864.39249c0,2.17915-55.59414,3.94772-55.59414,3.94772a20.30858,20.30858,0,0,0-3.33166,3.15818,19.59694,19.59694,0,0,0-4.58,12.63271v3.15818a19.74588,19.74588,0,0,0,19.73861,19.73861h94.62478a19.75579,19.75579,0,0,0,19.73862-19.73861v-3.15818A19.76607,19.76607,0,0,0,915.25011,498.96167Z"
+      fill="#e4e4e4"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <rect
+      fill="#e4e4e4"
+      height="118.48951"
+      width="20.52816"
+      x="747.4019"
+      y="303.23122"
+    />
+    <path
+      d="M799.31222,658.58132c0,2.218,31.10721.858,69.47992.858s69.47991,1.36012,69.47991-.858-31.1072-19.807-69.47991-19.807S799.31222,656.36323,799.31222,658.58132Z"
+      fill="#e4e4e4"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <polygon
+      fill="#ffb6b6"
+      points="675.186 407.461 659.908 407.46 652.64 348.531 675.188 348.532 675.186 407.461"
+    />
+    <path
+      d="M789.41863,659.852l-49.2623-.00183v-.62309a19.17528,19.17528,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z"
+      fill="#2f2e41"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <polygon
+      fill="#ffb6b6"
+      points="630.031 407.461 614.753 407.46 607.485 348.531 630.033 348.532 630.031 407.461"
+    />
+    <path
+      d="M744.2636,659.852l-49.2623-.00183v-.62309a19.1753,19.1753,0,0,1,19.17426-19.17395h.00122l30.08773.00122Z"
+      fill="#2f2e41"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <circle cx="766.88656" cy="41.63615" fill="#ffb6b6" r="26.56401" />
+    <path
+      d="M920.21655,461.22417s8.91308,47.1307-24.99958,53.13247-82.86639,10.21993-82.86639,10.21993L790.36706,627.14324l-29.53443-2.63675s3.928-123.46737,13.5876-133.127,70.71212-38.58282,70.71212-38.58282Z"
+      fill="#2f2e41"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M853.98286,441.47135,839.151,456.35062s-107.0941,17.25-111.22553,41.9852c-6.23747,37.34427-13.60493,118.552-13.60493,118.552l32.1988-2.41491,12.62647-92.31123,51.5182-11.71874L869.27729,478.5Z"
+      fill="#2f2e41"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M902.78526,263.36115c-2.6223-4.94751-5.95413-14.80785-11.24679-16.63657a42.07731,42.07731,0,0,0-9.05841-1.92972l-8.99618,3.46009,4.89616-3.808q-1.42988-.08519-2.85817-.13928l-6.0699,2.33453,3.10542-2.41532c-5.65883-.05808-11.5.53031-15.88468,3.9752-3.73817,2.93677-7.44169,14.06185-8.04057,18.77753a35.9171,35.9171,0,0,0,.6603,13.53055l1.53716,1.46166a18.85936,18.85936,0,0,0,1.206-3.83883,18.18056,18.18056,0,0,1,8.70263-11.80641l.08368-.0472c2.5782-1.451,5.7065-1.3841,8.66308-1.27769l14.04158.50527c3.37829.12158,7.01608.33533,9.64978,2.45443a15.888,15.888,0,0,1,3.85826,5.58929c1.30868,2.6414,3.8661,12.60418,3.8661,12.60418s1.44689-1.88062,2.1404-.48092a48.39766,48.39766,0,0,0,2.01437-11.23347A22.00877,22.00877,0,0,0,902.78526,263.36115Z"
+      fill="#2f2e41"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M995.69426,290.88349A11.61582,11.61582,0,0,0,985.181,305.26136l-21.3614,15.75722,6.40951,15.31674,29.8539-22.67594a11.67883,11.67883,0,0,0-4.38876-22.77589Z"
+      fill="#ffb6b6"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M992.25627,323.052l-53.551,59.4744s-25.60913-8.19816-45.41466-17.08624l-8.8977-27.32787a54.34329,54.34329,0,0,1-2.60112-19.66442c27.45606-7.306,59.391,19.87863,59.391,19.87863l40.08517-31.39877Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M867.301,465.6169c-9.554-3.30029-19.43312-6.71277-30.08912-7.99385l-.45773-.05533.12632-.443c11.03073-38.7308,8.27761-63.50657,2.87195-100.72306a37.59072,37.59072,0,0,1,21.5483-39.50121l.06542-.02958,30.43436-1.93391.06935-.00423,22.13437,6.50989a15.18313,15.18313,0,0,1,10.86724,14.83111c-.23987,12.23937.26868,25.9043.80711,40.37114,1.20787,32.45569,2.45686,66.01647-4.63045,87.79166l-.03718.11412-.09462.07416a36.09883,36.09883,0,0,1-23.08086,8.10758C887.90057,472.73235,877.76186,469.23034,867.301,465.6169Z"
+      fill="hsl(var(--primary))"
+      transform="translate(-110.33661 -237.5817)"
+    />
+    <path
+      d="M1088.24817,662.4183H111.75183a1.41521,1.41521,0,1,1,0-2.83042h976.49634a1.41521,1.41521,0,1,1,0,2.83042Z"
+      fill="#ccc"
+      transform="translate(-110.33661 -237.5817)"
+    />
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue
new file mode 100644
index 0000000..9e50b19
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue
@@ -0,0 +1,112 @@
+<template>
+  <svg
+    height="458.68642"
+    viewBox="0 0 656 458.68642"
+    width="656"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+  >
+    <rect fill="#3f3d56" height="2" width="656" y="434.34322" />
+    <g>
+      <path
+        d="M471.97092,210.81397c-6.0733-36.41747-37.72842-64.16942-75.86423-64.16942H240.14931c-38.12099,0-69.76869,27.72972-75.86421,64.12497-.70358,4.16241-1.06653,8.44331-1.06653,12.80573v135.88599c0,4.36237,.36295,8.63589,1.06653,12.79831,4.85126,28.99625,25.92996,52.49686,53.58563,60.84393,7.05095,2.13306,14.53143,3.28104,22.27859,3.28104h155.9574c7.74716,0,15.22763-1.14798,22.27859-3.28104,27.66309-8.35449,48.74921-31.86993,53.58563-60.88837,.6962-4.14758,1.05911-8.40628,1.05911-12.75388V223.57525c0-4.34758-.36292-8.61369-1.05911-12.76128h-.00003Zm-62.66592,222.28954c-4.2883,.76285-8.69516,1.16281-13.19827,1.16281H240.14931c-4.50313,0-8.90997-.39999-13.19829-1.16281-35.01768-6.22885-61.60677-36.83228-61.60677-73.64224v-45.10526c0-127.45004,103.31242-165.58582,230.76244-165.58582,41.31314,0,74.80505,33.49194,74.80505,74.80505v135.88599c-100.29059,13.42047-26.58911,67.41339-61.60678,73.64224l.00003,.00003Z"
+        fill="#3f3d56"
+      />
+      <polygon
+        fill="hsl(var(--primary))"
+        points="349.16196 249.18644 355.16196 288.18642 443.16196 276.18642 434.66196 230.6195 349.16196 249.18644"
+      />
+      <rect
+        fill="#2f2e41"
+        height="37.66125"
+        width="36.38461"
+        x="381.84177"
+        y="30.34218"
+      />
+      <polygon
+        fill="#ffb6b6"
+        points="385.16196 70.18643 394.16196 43.18643 411.70447 43.18643 412.62653 70.18643 385.16196 70.18643"
+      />
+      <polygon
+        isolation="isolate"
+        opacity=".1"
+        points="385.16196 70.18643 394.16196 43.18643 411.70447 43.18643 412.62653 70.18643 385.16196 70.18643"
+      />
+      <path
+        d="M394.66196,310.68642l-1,104-1,8v11.48425l15,1.51575,1-23s16-45,12-80-2-25-2-25l-24,3Z"
+        fill="#ffb6b6"
+      />
+      <path
+        d="M404.18408,318.85363l-36.90134,97.23831-1.97873,7.81567-4.1777,10.69742-14.52368-4.04477,7.43539-21.78796s1.46619-47.7373,17.92432-78.88422,10.9574-22.5596,10.9574-22.5596l21.26434,11.52512v.00003Z"
+        fill="#ffb6b6"
+      />
+      <path
+        d="M385.16196,67.18643l-27,12,17.23959,89.01208-2.72385,127.75565-18,38s-3.01575,21.73227,27.98425,7.73227,66-18,66-18l-8.5-58.5-7.5-153.5,1-34-22-14s-26.5,3.5-26.5,3.50001Z"
+        fill="#2f2e41"
+      />
+      <path
+        d="M370.1243,335.34322l-29.96231-50.15677,34.23959-116.98792-16.23959-89.01208,28.49045-12.19685s14.74915,14.36248,14.74915,26.20894-31.27728,242.1447-31.27728,242.1447v-.00003Z"
+        fill="#e6e6e6"
+      />
+      <path
+        d="M435.1243,325.34322l-27.19693-233.62811c-.34341-2.94999,.16013-5.93678,1.45178-8.6111l7.78284-16.11441,30.5,8.69685-12.26041,95.51208,32.76041,93.98792-33.03769,60.15677Z"
+        fill="#e6e6e6"
+      />
+      <path
+        d="M410.66196,433.68642s-19-11-21-5-3,11-3,11c0,0-5,19,10,19s14-8.64172,14-8.64172v-16.35828Z"
+        fill="#2f2e41"
+      />
+      <path
+        d="M344.53574,427.60598s21.69977-3.33459,21.3801,2.9819c-.3197,6.31647-1.20709,11.33768-1.20709,11.33768,0,0-2.25433,19.51712-16.22662,14.06046s-9.89713-13.14252-9.89713-13.14252l5.95078-15.23749-.00003-.00003Z"
+        fill="#2f2e41"
+      />
+      <circle cx="404.10297" cy="33.02146" fill="#ffb6b6" r="24.85993" />
+      <path
+        d="M423.96469,10.86766c-1.15707-6.12936-7.44913-10.27514-13.66504-10.79501s-12.30453,1.82726-17.90228,4.57921c-3.79456,1.86548-7.53061,3.96811-10.60425,6.87182s-5.46063,6.69692-6.01202,10.88913c-.19507,1.48324-.1698,3.03289-.77692,4.40016-.75845,1.708-2.38654,2.86795-3.36917,4.4576-1.76227,2.85096-.95267,6.99858,1.75238,8.97753-3.40024,1.44912-6.89398,2.96069-9.48602,5.59563s-4.08878,6.70308-2.66644,10.11462c.50323,1.20699,1.33481,2.26349,1.76489,3.49843,.81668,2.34499,.03943,5.00909-1.40924,7.02585s-3.49316,3.51228-5.50174,4.97226c5.16196,1.01177,10.43097,1.80015,15.66992,1.32811s10.49707-2.30805,14.29086-5.95176c3.79379-3.64371,5.88083-9.26437,4.51974-14.34539-1.04269-3.89231-3.95898-7.30301-3.95712-11.33256,.00143-3.09747,1.7431-5.89158,3.4249-8.49271,3.67291-5.68066,7.34579-11.36132,11.01868-17.04197,.66068-1.02183,1.35739-2.07924,2.4014-2.70425,1.77606-1.06326,4.0798-.59568,5.95227,.28683,1.87244,.88252,3.58304,2.14867,5.57941,2.69585,4.07452,1.11677,8.80106-1.44789,10.08575-5.47261"
+        fill="#2f2e41"
+      />
+      <path
+        d="M409.27951,61.42523c-2.07159,2.0061-5.05701,2.65225-7.82379,3.46516s-5.70978,2.09141-6.95499,4.69243c-1.22101,2.55043-.33459,5.78793,1.68692,7.76505s4.95816,2.80999,7.78555,2.77077c2.82736-.03922,5.58282-.86796,8.24176-1.8301,7.27054-2.63087,14.15665-6.32148,20.37314-10.919-4.02679-1.11411-6.66107-5.81614-5.50836-9.83205,.93768-3.26677,3.80499-5.54528,5.75616-8.32809,3.35959-4.79151,3.91925-11.10753,2.80676-16.85277-1.11246-5.74524-3.73163-11.07097-6.32358-16.3176-.81934-1.65853-1.65805-3.34513-2.93619-4.68245-1.27814-1.33731-3.08783-2.29539-4.92776-2.10379-3.05334,.31795-5.00302,3.66989-5.02377,6.7397s1.32593,5.95491,2.34732,8.84988c1.05231,2.98259,1.78381,6.14409,1.50146,9.29425-.2366,2.63989-1.19669,5.21132-2.74811,7.36029-1.19809,1.65954-2.72479,3.05223-4.0275,4.63097-1.00714,1.22055-1.90009,2.60309-2.16486,4.16321-.48181,2.83914,1.18356,5.71186,.72714,8.55519-.48248,3.0056-3.6452,5.3067-6.65341,4.84085"
+        fill="#2f2e41"
+      />
+      <g>
+        <circle
+          cx="333.2486"
+          cy="323.64455"
+          fill="hsl(var(--primary))"
+          r="85"
+        />
+        <g>
+          <path
+            d="M384.17838,316.82296h-10.56668c-1.64377-9.68713-6.7168-18.46011-14.2923-24.71729-17.43427-14.39993-43.24109-11.94022-57.64099,5.49411-.04913,.05563-.09644,.11282-.14169,.17151-1.15063,1.49146-.87427,3.63333,.61716,4.784,1.49118,1.1507,3.63306,.87448,4.78394-.61697,6.25537-7.5788,15.72369-12.40167,26.31064-12.40167,16.20853,.00195,30.17899,11.40631,33.42572,27.28629h-9.31805c-.3988,.00012-.78458,.13992-1.09082,.39502-.72375,.60281-.82175,1.6781-.21915,2.40186l13.41125,16.09894c.06577,.07889,.13855,.1517,.21759,.21747,.72324,.60327,1.79871,.50583,2.40186-.21747l13.41125-16.09894c.25504-.30624,.3949-.69223,.39514-1.09082,.00027-.94186-.763-1.70566-1.70486-1.70605v.00003Z"
+            fill="#fff"
+          />
+          <path
+            d="M364.34329,344.7337c-1.49146-1.15063-3.63333-.87433-4.78394,.6171-4.96201,6.00781-11.83066,10.13629-19.46436,11.69922-18.46167,3.77988-36.49231-8.12213-40.27225-26.58392h9.3183c.94186-.0004,1.70514-.76419,1.70486-1.70605-.00027-.39853-.14011-.78452-.39514-1.09082l-13.41125-16.09888c-.60312-.72336-1.67862-.8208-2.40186-.21753-.07904,.06577-.15182,.13855-.21759,.21753l-13.41125,16.09888c-.6026,.72375-.50461,1.7991,.21915,2.40186,.30624,.25516,.69205,.3949,1.09082,.39502h10.56641c1.64404,9.68723,6.7168,18.46011,14.29254,24.71729,17.43427,14.39999,43.24109,11.94022,57.64099-5.49405,.04913-.05569,.09619-.11295,.14142-.17163,1.15088-1.49146,.87454-3.63327-.61691-4.784h.00006Z"
+            fill="#fff"
+          />
+        </g>
+      </g>
+      <path
+        id="uuid-da16df1e-5659-4232-96f6-61e8c639a9ec-574"
+        d="M356.98148,237.19363c-1.02939,7.36621-5.66458,12.80598-10.35239,12.15012-4.68781-.65588-7.65225-7.15837-6.62149-14.52707,.37137-2.94914,1.4436-5.76646,3.12701-8.21626l4.75577-31.15587,14.57297,2.54338-6.23553,30.44414c.94736,2.81844,1.20581,5.82278,.75369,8.76157h-.00003Z"
+        fill="#ffb6b6"
+      />
+      <path
+        d="M369.66196,77.68643s-15-5-17,13-4,39.99999-4,39.99999c0,0-9,21-5,32s11,3.3307,4,12.66534-6.02478,40.04724-6.02478,40.04724l22.52478-1.13387s12.5-82.57875,12.5-84.57875-7-52-7-52v.00004Z"
+        fill="#e6e6e6"
+      />
+      <g>
+        <path
+          id="uuid-6bf35aa9-e432-4b51-af77-8f4eb19e6e42-575"
+          d="M467.16132,233.84998c.27881,7.43257-3.33017,13.60114-8.06033,13.7778s-8.78937-5.70491-9.06732-13.14017c-.15176-2.96857,.40961-5.93028,1.63712-8.63741l-.78369-31.507,14.79315-.05261-.798,31.0659c1.42709,2.60854,2.20859,5.52095,2.27905,8.49347l.00003,.00002Z"
+          fill="#ffb6b6"
+        />
+        <path
+          d="M444.06961,77.34876s15.08694-4.73121,16.76505,13.30165,3.28473,51.06508,3.28473,51.06508c0,0,8.62338,21.15744,4.42749,32.08421s-11.05774,3.13365-4.22565,12.59187c6.83212,9.45822,4.37997,36.13126,4.37997,36.13126l-22.50095-1.53612s-10.09427-78.77167-10.05853-80.77133,7.92792-62.86664,7.92792-62.86664l-.00003,.00002Z"
+          fill="#e6e6e6"
+        />
+      </g>
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/warning.svg b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/warning.svg
new file mode 100644
index 0000000..951a905
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/icons/warning.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="524.67001" height="418.27099" viewBox="0 0 524.67001 418.27099" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M442.17403,400.47713c2.06599,.12871,3.20692-2.43846,1.64338-3.93389l-.1557-.61814c.0204-.04935,.04089-.09868,.06153-.14794,1.23211-2.94003,4.62545-4.33201,7.57137-3.11404,9.3142,3.85087-.51966,12.69986,.21957,18.68773,.25911,2.06671,8.35473,2.18034,7.89681,4.2086,4.30482-9.41207,6.56835-19.68889,6.56478-30.02306-.0009-2.59653-.14392-5.19297-.43543-7.78281-.23975-2.11845-.56985-4.22389-.9969-6.30999-2.30966-11.27639-7.30614-22.01572-14.51084-30.98461-3.46263-1.89129-1.35074-4.85018-3.09586-8.39544-.62694-1.27868-6.21792-1.30745-6.45092-2.70892,.25019,.03272,3.86434-3.721,2.6705-5.5767-.78555-1.22107-.54106-2.7763,.4681-3.82017,.09887-.1023,.19234-.2103,.27796-.32648,2.98093-4.04443,7.09003-3.33985,9.23695,2.15406,4.58304,2.31107,4.62871,6.14647,1.81834,9.83619-1.78798,2.34745-2.03264,5.52304-3.60129,8.03604,.16157,.20664,.32958,.40684,.49112,.61348,2.96237,3.79686,5.52482,7.87809,7.68524,12.16592-.61182-4.76599,.28705-10.50831,1.8215-14.21023,1.75933-4.24835,5.06953-7.8221,7.96883-11.49665,3.46275-4.38865,10.5104-2.39707,11.12286,3.15951,.00588,.05337,.0116,.10665,.01724,.16003-.42884,.24212-.84895,.49935-1.25929,.77094-2.33882,1.54808-1.52824,5.17442,1.24391,5.60071l.06278,.00965c-.1545,1.54372-5.63258,6.40679-6.01957,7.91187,3.70514,14.30838,.93282,16.19755-10.46624,16.43703l-.59825,.8522c1.08024,3.1058,1.94956,6.2861,2.60235,9.50743,.61462,2.99021,1.042,6.01282,1.28197,9.04845,.29847,3.82994,.27396,7.6795-.04769,11.50325l.01933-.13563c.81879-4.21143,3.1039-8.1457,6.42284-10.87249,4.94421-4.06436,11.93091-5.56281,17.2652-8.83022,2.56778-1.57285,5.85959,.45742,5.41241,3.4352l-.02177,.14262c-.79432,.32315-1.56922,.69808-2.31831,1.11814-.42921,.24237-.84965,.49978-1.26032,.77165-2.33916,1.54848-1.52796,5.1753,1.24498,5.60009l.06281,.00962c.0452,.00645,.08399,.01291,.12913,.0194-1.3617,3.23628-14.33553,7.80147-16.71149,10.39229-2.31031,12.49793-1.17531,12.12596-11.81075,8.49032h-.00647c-1.16085,5.06419-2.8578,10.01225-5.03931,14.72794l-18.0202,.00623c-.06471-.2002-.12288-.40688-.18109-.60712,1.66645,.10285,3.34571,.00534,4.98619-.29875-1.33757-1.64013-2.67509-3.29317-4.01266-4.93324-.0323-.03228-.05819-.06459-.08402-.09686l-.02036-.02517-1.85532-6.10724c.14644-1.35476,.38536-2.69828,.70958-4.02051l.00049-.00037v.00006Z" fill="#f2f2f2"/><path d="M251.74443,416.41995l-159.45702,.05516c-8.01074,.00277-15.18649-4.13684-19.19426-11.07295-2.00413-3.46855-3.00642-7.27337-3.00774-11.07904-.00132-3.80518,.99882-7.61119,3.00007-11.08063l79.67786-145.04905c4.00346-6.93937,11.17634-11.08346,19.18708-11.08623s15.18649,4.13635,19.19475,11.07295l79.78843,145.01196c1.99876,3.45927,2.99861,7.25971,2.99894,11.06293-.00015,3.80322-.99981,7.60874-3.00154,11.07868-4.00297,6.93889-11.17585,11.08346-19.1866,11.08623h.00002Zm-179.65463-22.09948c-.00026,3.46387,17.5953-4.00023,19.41817-.8451,3.64623,6.31026-6.50934,21.00225,.77874,20.99973,0,0,173.27016-3.828,176.91202-10.14078,1.82069-3.15639,2.73062-6.61911,2.72942-10.08102s-.91353-6.92351-2.73688-10.07864l-79.78845-145.01196c-3.63597-6.2922-10.16364-10.05801-17.45172-10.05549-7.28467,.00252-99.86105,161.74891-99.86132,165.21326h.00002Z" fill="#3f3d56"/><path d="M253.51521,414.41934c-1.99862,4.00069,91.61376,2.7712,92.72051,2.77082,0,0,26.3119-.58131,26.86492-1.53993,.27648-.47931,.41466-1.00515,.41448-1.53084s-.13873-1.05137-.4156-1.5305l-12.11626-22.02074c-.55215-.9555-1.54341-1.52736-2.65013-1.52698-.04608,.00002-.11394,.04093-.20168,.11933-16.16328,14.44385-36.0828,23.99237-57.75707,24.31469-23.047,.34272-46.73217,.6899-46.85919,.94416h.00002Z" fill="#3f3d56"/><path d="M0,417.0814c.00023,.66003,.53044,1.18982,1.19047,1.18959l522.28995-.18066c.65997-.00023,1.18982-.53038,1.18959-1.19041-.00023-.65997-.53044-1.18982-1.19041-1.18959l-522.28995,.18066c-.66003,.00023-1.18988,.53044-1.18965,1.19041Z" fill="#ccc"/><g><polygon points="403.87773 411.30541 394.83299 411.30765 390.51828 376.42194 403.86746 376.41823 403.87773 411.30541" fill="#a0616a"/><path d="M372.88925,411.11096h0c-.28145,.4744-.42951,2.00528-.42932,2.55685h0c.00059,1.6954,1.37542,3.06935,3.07089,3.06876l28.01047-.00969c1.15659-.0004,2.09391-.93832,2.09351-2.09496l-.0004-1.16617s1.38444-3.50542-1.46987-7.82444c0,0-3.54448,3.38386-8.84444-1.91244l-1.56336-2.82981-11.30656,8.27506-6.26838,.77377c-1.3714,.16927-2.58738-.02532-3.29241,1.16307h-.00012Z" fill="#2f2e41"/></g><g><polygon points="369.19708 381.46752 360.62951 384.36642 345.36911 352.70019 358.01396 348.42131 369.19708 381.46752" fill="#a0616a"/><path d="M339.77867,391.20807h0c-.11468,.53956,.23535,2.03724,.41217,2.5597h0c.54355,1.60589,2.28601,2.46714,3.89196,1.92358l26.53193-8.98019c1.09554-.3708,1.68312-1.55951,1.31228-2.65512l-.37389-1.10461s.18882-3.76416-3.8984-6.94155c0,0-2.27401,4.34084-8.99107,1.02096l-2.38732-2.18005-8.0607,11.46034-5.69037,2.74062c-1.24494,.59958-2.45919,.80471-2.74651,2.15628l-.00009,.00003Z" fill="#2f2e41"/></g><polygon points="355.22599 179.09003 337.68255 237.19081 316.97199 289.45207 349.76053 364.08569 361.91802 358.67731 347.37062 290.11706 377.87822 243.59436 392.11437 388.82623 404.27349 388.14652 420.76309 212.84336 423.11421 174.67566 355.22599 179.09003" fill="#2f2e41"/><path d="M408.20979,50.38513l-25.66813,4.73752-2.02258,11.48454-15.53439,7.43609-8.07702,84.4428s-13.50433,17.56819-2.69414,22.96862l68.9007-6.77904s3.37327-12.4903-.00473-13.67529-3.38832-31.01955-3.38832-31.01955l15.51573-61.36599-22.97048-8.09829-4.05664-10.13141Z" fill="#e6e6e6"/><circle cx="393.06995" cy="29.43589" r="20.7276" fill="#a0616a"/><path d="M406.79605,32.51227c-1.65401,.9055-.08471,5.22869-1.11848,5.60245-1.19492,.43202-5.55162-4.52715-5.60554-10.08176-.01633-1.68115,.37051-2.48839-.00155-4.48164-.48668-2.6073-1.98045-5.68253-3.36317-5.60089-.81965,.04839-1.62013,1.20723-1.67986,2.2414-.0837,1.44941,1.32419,2.01989,1.12139,2.80064-.38627,1.4871-6.29829,2.5138-8.40308,.00291-1.65013-1.9685-.38463-5.4247-1.12236-5.60167-.54378-.13045-1.12759,1.77241-3.35988,3.9226-.84103,.8101-2.09186,2.0149-2.80044,1.68159-1.02397-.48167-.28003-3.87624-.56157-3.92125-.23314-.03727-.37947,2.3487-1.67908,4.48223-1.66968,2.74103-5.11398,4.85374-6.72112,3.92377-.98466-.56978-1.06245-2.15606-1.12158-3.36084-.1245-2.53816-3.81308-8.37644-2.85882-11.09166,1.94221-5.5263,5.2701-1.63078,6.7752-3.47504,2.03756-2.49669,3.86572-1.15434,7.28133-3.92396,3.33668-2.70564,3.36577-5.42504,5.60011-5.604,2.01221-.16116,2.7278,1.98528,5.04242,1.67887,1.96079-.25957,2.38749-1.92436,3.92087-1.68198,1.40389,.2219,1.49646,1.68849,3.36201,2.23966,1.19101,.35188,1.45267-.15743,2.80103-.00097,2.80559,.32556,4.69002,2.88083,5.043,3.35949,1.36081,1.84526,.83282,2.62341,2.24236,4.48086,1.21555,1.6018,3.90913,.9216,4.92189,1.72162,3.30928,2.61409,4.73124,7.43497,4.75994,12.92962,.0201,3.8431-.48103,5.78482-1.59913,10.63564-.84901,3.6834-4.78175,8.44334-6.94987,10.5659-.58199,.56975-2.21351,2.167-3.36066,1.68178-1.08704-.45979-1.11995-2.52764-1.12139-2.80064-.0049-.93901,.24521-2.1009,2.23907-5.04263,2.09442-3.09006,2.92645-3.44271,2.79948-4.48262-.22445-1.83818-3.16424-3.52123-4.48263-2.79948h.00012Z" fill="#2f2e41"/><g><path d="M334.49457,225.75979c-.64513,5.40264,1.61895,10.11513,5.05699,10.52567s6.7481-3.63632,7.39324-9.03898c.28242-2.36492,.00723-4.59754-.6797-6.39504l2.44642-22.92684-10.7834-.91891-1.26717,22.69891c-1.09088,1.58522-1.88401,3.69026-2.16639,6.05519h.00003Z" fill="#a0616a"/><path d="M365.49095,73.49769s-5.58664,.07946-9.28568,7.30383c-1.96565,3.83897-12.48211,75.62767-12.48211,75.62767l-9.68742,58.80847,16.50214,.08313,12.859-55.69302,10.81723-32.30088-8.72315-53.82921Z" fill="#e6e6e6"/></g><path d="M411.92961,217.13028c-1.58023,5.20651-.17535,10.24237,3.13786,11.24797s7.28015-2.39987,8.86035-7.60638c.69172-2.27906,.81133-4.5254,.44941-6.41533l6.4191-22.14543-10.45641-2.79098-5.21815,22.12729c-1.35133,1.36996-2.50044,3.30383-3.19216,5.58289v-.00003Z" fill="#a0616a"/><path d="M423.41564,69.63219s8.10413-6.08248,14.86262,3.37246c6.75846,9.45495,9.48742,87.1388,9.48742,87.1388l-18.89796,47.96845-14.18755-4.72373,13.49008-58.7749-23.65861-44.57614,18.90403-30.40494h-.00003Z" fill="#e6e6e6"/><g><circle cx="218.47958" cy="311.43145" r="73" fill="#6c63ff"/><g><circle cx="218.49274" cy="349.47878" r="6.70264" fill="#fff"/><path d="M218.4641,266.68145c-.6157,4.0912,.48747,4.94727,.49357,22.58508,.0061,17.63782,3.66579,41.28574-.47148,41.28717s-5.65047-48.80276-20.01681-53.12218c-16.89088-5.07846,21.98785-23.99409,19.99471-10.75007Z" fill="#fff"/></g></g><path d="M120.50313,348.70219l-6.59532,13.93527c7.97328-5.71745,20.42715-10.64598,30.3376-13.28567-9.23403-4.46037-20.53313-11.65189-27.2835-18.77194l3.7934,14.72434c-44.47393-9.0585-76.41138-43.17661-76.4249-82.25924l-1.60648-.5527c.01412,40.82281,31.50971,76.96121,77.7792,86.20995Z" fill="#3f3d56"/></svg>
\ No newline at end of file
diff --git a/eims-ui/packages/effects/common-ui/src/ui/fallback/index.ts b/eims-ui/packages/effects/common-ui/src/ui/fallback/index.ts
new file mode 100644
index 0000000..f56f665
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/fallback/index.ts
@@ -0,0 +1,2 @@
+export type * from './fallback';
+export { default as Fallback } from './fallback.vue';
diff --git a/eims-ui/packages/effects/common-ui/src/ui/index.ts b/eims-ui/packages/effects/common-ui/src/ui/index.ts
new file mode 100644
index 0000000..fb99fde
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/src/ui/index.ts
@@ -0,0 +1,4 @@
+export * from './about';
+export * from './authentication';
+export * from './dashboard';
+export * from './fallback';
diff --git a/eims-ui/packages/effects/common-ui/tsconfig.json b/eims-ui/packages/effects/common-ui/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/effects/common-ui/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/hooks/README.md b/eims-ui/packages/effects/hooks/README.md
new file mode 100644
index 0000000..54d9ff7
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/README.md
@@ -0,0 +1,19 @@
+# @vben/hooks
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨� hook锛岀户鎵夸簡 `@vben/hooks` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤 hooks 鍙互鏀惧湪杩欓噷銆�
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/hooks
+```
+
+### 浣跨敤
+
+```ts
+import { useNamespace } from '@vben/hooks';
+```
diff --git a/eims-ui/packages/effects/hooks/package.json b/eims-ui/packages/effects/hooks/package.json
new file mode 100644
index 0000000..627e235
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/package.json
@@ -0,0 +1,32 @@
+{
+  "name": "@vben/hooks",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/hooks"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "vue": "catalog:",
+    "vue-router": "catalog:",
+    "watermark-js-plus": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/hooks/src/index.ts b/eims-ui/packages/effects/hooks/src/index.ts
new file mode 100644
index 0000000..51f6406
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/index.ts
@@ -0,0 +1,8 @@
+export * from './use-app-config';
+export * from './use-content-maximize';
+export * from './use-design-tokens';
+export * from './use-pagination';
+export * from './use-refresh';
+export * from './use-tabs';
+export * from './use-watermark';
+export * from '@vben-core/composables';
diff --git a/eims-ui/packages/effects/hooks/src/use-app-config.ts b/eims-ui/packages/effects/hooks/src/use-app-config.ts
new file mode 100644
index 0000000..6cf497e
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-app-config.ts
@@ -0,0 +1,40 @@
+import type {
+  ApplicationConfig,
+  VbenAdminProAppConfigRaw,
+} from '@vben/types/global';
+
+/**
+ * 鐢� vite-inject-app-config 娉ㄥ叆鐨勫叏灞�閰嶇疆
+ */
+export function useAppConfig(
+  env: Record<string, any>,
+  isProduction: boolean,
+): ApplicationConfig {
+  // 鐢熶骇鐜涓嬶紝鐩存帴浣跨敤 window._VBEN_ADMIN_PRO_APP_CONF_ 鍏ㄥ眬鍙橀噺
+  const config = isProduction
+    ? window._VBEN_ADMIN_PRO_APP_CONF_
+    : (env as VbenAdminProAppConfigRaw);
+
+  const {
+    VITE_GLOB_API_URL,
+    VITE_GLOB_APP_CLIENT_ID,
+    VITE_GLOB_ENABLE_ENCRYPT,
+    VITE_GLOB_RSA_PRIVATE_KEY,
+    VITE_GLOB_RSA_PUBLIC_KEY,
+    VITE_GLOB_SSE_ENABLE,
+  } = config;
+
+  return {
+    // 鍚庣鍦板潃
+    apiURL: VITE_GLOB_API_URL,
+    // 瀹㈡埛绔痥ey
+    clientId: VITE_GLOB_APP_CLIENT_ID,
+    enableEncrypt: VITE_GLOB_ENABLE_ENCRYPT === 'true',
+    // RSA绉侀挜
+    rsaPrivateKey: VITE_GLOB_RSA_PRIVATE_KEY,
+    // RSA鍏挜
+    rsaPublicKey: VITE_GLOB_RSA_PUBLIC_KEY,
+    // 鏄惁寮�鍚痵se
+    sseEnable: VITE_GLOB_SSE_ENABLE === 'true',
+  };
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-content-maximize.ts b/eims-ui/packages/effects/hooks/src/use-content-maximize.ts
new file mode 100644
index 0000000..77d1fab
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-content-maximize.ts
@@ -0,0 +1,24 @@
+import { updatePreferences, usePreferences } from '@vben/preferences';
+/**
+ * 涓讳綋鍖哄煙鏈�澶у寲
+ */
+export function useContentMaximize() {
+  const { contentIsMaximize } = usePreferences();
+
+  function toggleMaximize() {
+    const isMaximize = contentIsMaximize.value;
+
+    updatePreferences({
+      header: {
+        hidden: !isMaximize,
+      },
+      sidebar: {
+        hidden: !isMaximize,
+      },
+    });
+  }
+  return {
+    contentIsMaximize,
+    toggleMaximize,
+  };
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-design-tokens.ts b/eims-ui/packages/effects/hooks/src/use-design-tokens.ts
new file mode 100644
index 0000000..8ee7440
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-design-tokens.ts
@@ -0,0 +1,280 @@
+import { reactive, watch } from 'vue';
+
+import { preferences, usePreferences } from '@vben/preferences';
+import { convertToRgb, updateCSSVariables } from '@vben/utils';
+
+/**
+ * 鐢ㄤ簬閫傞厤鍚勪釜妗嗘灦鐨勮璁$郴缁�
+ */
+
+export function useAntdDesignTokens() {
+  const rootStyles = getComputedStyle(document.documentElement);
+
+  const tokens = reactive({
+    borderRadius: '' as any,
+    colorBgBase: '',
+    colorBgContainer: '',
+    colorBgElevated: '',
+    colorBgLayout: '',
+    colorBgMask: '',
+    colorBorder: '',
+    colorBorderSecondary: '',
+    colorError: '',
+    colorInfo: '',
+    colorPrimary: '',
+    colorSuccess: '',
+    colorTextBase: '',
+    colorWarning: '',
+  });
+
+  const getCssVariableValue = (variable: string, isColor: boolean = true) => {
+    const value = rootStyles.getPropertyValue(variable);
+    return isColor ? `hsl(${value})` : value;
+  };
+
+  watch(
+    () => preferences.theme,
+    () => {
+      tokens.colorPrimary = getCssVariableValue('--primary');
+
+      tokens.colorInfo = getCssVariableValue('--primary');
+
+      tokens.colorError = getCssVariableValue('--destructive');
+
+      tokens.colorWarning = getCssVariableValue('--warning');
+
+      tokens.colorSuccess = getCssVariableValue('--success');
+
+      tokens.colorTextBase = getCssVariableValue('--foreground');
+
+      getCssVariableValue('--primary-foreground');
+
+      tokens.colorBorderSecondary = tokens.colorBorder =
+        getCssVariableValue('--border');
+
+      tokens.colorBgElevated = getCssVariableValue('--popover');
+
+      tokens.colorBgContainer = getCssVariableValue('--card');
+
+      tokens.colorBgBase = getCssVariableValue('--background');
+
+      const radius = Number.parseFloat(getCssVariableValue('--radius', false));
+      // 1rem = 16px
+      tokens.borderRadius = radius * 16;
+
+      tokens.colorBgLayout = getCssVariableValue('--background-deep');
+      tokens.colorBgMask = getCssVariableValue('--overlay');
+    },
+    { immediate: true },
+  );
+
+  return {
+    tokens,
+  };
+}
+
+export function useNaiveDesignTokens() {
+  const rootStyles = getComputedStyle(document.documentElement);
+
+  const commonTokens = reactive({
+    baseColor: '',
+    bodyColor: '',
+    borderColor: '',
+    borderRadius: '',
+    cardColor: '',
+    dividerColor: '',
+    errorColor: '',
+    errorColorHover: '',
+    errorColorPressed: '',
+    errorColorSuppl: '',
+    invertedColor: '',
+    modalColor: '',
+    popoverColor: '',
+    primaryColor: '',
+    primaryColorHover: '',
+    primaryColorPressed: '',
+    primaryColorSuppl: '',
+    successColor: '',
+    successColorHover: '',
+    successColorPressed: '',
+    successColorSuppl: '',
+    tableColor: '',
+    textColorBase: '',
+    warningColor: '',
+    warningColorHover: '',
+    warningColorPressed: '',
+    warningColorSuppl: '',
+  });
+
+  const getCssVariableValue = (variable: string, isColor: boolean = true) => {
+    const value = rootStyles.getPropertyValue(variable);
+    return isColor ? convertToRgb(`hsl(${value})`) : value;
+  };
+
+  watch(
+    () => preferences.theme,
+    () => {
+      commonTokens.primaryColor = getCssVariableValue('--primary');
+      commonTokens.primaryColorHover = getCssVariableValue('--primary-600');
+      commonTokens.primaryColorPressed = getCssVariableValue('--primary-700');
+      commonTokens.primaryColorSuppl = getCssVariableValue('--primary-800');
+
+      commonTokens.errorColor = getCssVariableValue('--destructive');
+      commonTokens.errorColorHover = getCssVariableValue('--destructive-600');
+      commonTokens.errorColorPressed = getCssVariableValue('--destructive-700');
+      commonTokens.errorColorSuppl = getCssVariableValue('--destructive-800');
+
+      commonTokens.warningColor = getCssVariableValue('--warning');
+      commonTokens.warningColorHover = getCssVariableValue('--warning-600');
+      commonTokens.warningColorPressed = getCssVariableValue('--warning-700');
+      commonTokens.warningColorSuppl = getCssVariableValue('--warning-800');
+
+      commonTokens.successColor = getCssVariableValue('--success');
+      commonTokens.successColorHover = getCssVariableValue('--success-600');
+      commonTokens.successColorPressed = getCssVariableValue('--success-700');
+      commonTokens.successColorSuppl = getCssVariableValue('--success-800');
+
+      commonTokens.textColorBase = getCssVariableValue('--foreground');
+
+      commonTokens.baseColor = getCssVariableValue('--primary-foreground');
+
+      commonTokens.dividerColor = commonTokens.borderColor =
+        getCssVariableValue('--border');
+
+      commonTokens.modalColor = commonTokens.popoverColor =
+        getCssVariableValue('--popover');
+
+      commonTokens.tableColor = commonTokens.cardColor =
+        getCssVariableValue('--card');
+
+      commonTokens.bodyColor = getCssVariableValue('--background');
+      commonTokens.invertedColor = getCssVariableValue('--background-deep');
+
+      commonTokens.borderRadius = getCssVariableValue('--radius', false);
+    },
+    { immediate: true },
+  );
+  return {
+    commonTokens,
+  };
+}
+
+export function useElementPlusDesignTokens() {
+  const { isDark } = usePreferences();
+  const rootStyles = getComputedStyle(document.documentElement);
+
+  const getCssVariableValueRaw = (variable: string) => {
+    return rootStyles.getPropertyValue(variable);
+  };
+
+  const getCssVariableValue = (variable: string, isColor: boolean = true) => {
+    const value = getCssVariableValueRaw(variable);
+    return isColor ? convertToRgb(`hsl(${value})`) : value;
+  };
+
+  watch(
+    () => preferences.theme,
+    () => {
+      const background = getCssVariableValue('--background');
+      const border = getCssVariableValue('--border');
+      const accent = getCssVariableValue('--accent');
+
+      const variables: Record<string, string> = {
+        '--el-bg-color': background,
+        '--el-bg-color-overlay': getCssVariableValue('--popover'),
+        '--el-bg-color-page': getCssVariableValue('--background-deep'),
+        '--el-border-color': border,
+        '--el-border-color-dark': border,
+        '--el-border-color-extra-light': border,
+        '--el-border-color-hover': accent,
+        '--el-border-color-light': border,
+        '--el-border-color-lighter': border,
+
+        '--el-border-radius-base': getCssVariableValue('--radius', false),
+        '--el-color-danger': getCssVariableValue('--destructive-500'),
+        '--el-color-danger-dark-2': getCssVariableValue('--destructive'),
+        '--el-color-danger-light-3': getCssVariableValue('--destructive-400'),
+        '--el-color-danger-light-5': getCssVariableValue('--destructive-300'),
+        '--el-color-danger-light-7': getCssVariableValue('--destructive-200'),
+        '--el-color-danger-light-8': isDark.value
+          ? border
+          : getCssVariableValue('--destructive-100'),
+        '--el-color-danger-light-9': isDark.value
+          ? accent
+          : getCssVariableValue('--destructive-50'),
+
+        '--el-color-error': getCssVariableValue('--destructive-500'),
+        '--el-color-error-dark-2': getCssVariableValue('--destructive'),
+        '--el-color-error-light-3': getCssVariableValue('--destructive-400'),
+        '--el-color-error-light-5': getCssVariableValue('--destructive-300'),
+        '--el-color-error-light-7': getCssVariableValue('--destructive-200'),
+        '--el-color-error-light-8': isDark.value
+          ? border
+          : getCssVariableValue('--destructive-100'),
+        '--el-color-error-light-9': isDark.value
+          ? accent
+          : getCssVariableValue('--destructive-50'),
+
+        '--el-color-info-light-8': border,
+        '--el-color-info-light-9': getCssVariableValue('--info'), // getCssVariableValue('--secondary'),
+        '--el-color-primary': getCssVariableValue('--primary-500'),
+        '--el-color-primary-dark-2': getCssVariableValue('--primary'),
+        '--el-color-primary-light-3': getCssVariableValue('--primary-400'),
+        '--el-color-primary-light-5': getCssVariableValue('--primary-300'),
+        '--el-color-primary-light-7': isDark.value
+          ? border
+          : getCssVariableValue('--primary-200'),
+        '--el-color-primary-light-8': isDark.value
+          ? border
+          : getCssVariableValue('--primary-100'),
+        '--el-color-primary-light-9': isDark.value
+          ? accent
+          : getCssVariableValue('--primary-50'),
+
+        '--el-color-success': getCssVariableValue('--success-500'),
+        '--el-color-success-dark-2': getCssVariableValue('--success'),
+        '--el-color-success-light-3': getCssVariableValue('--success-400'),
+        '--el-color-success-light-5': getCssVariableValue('--success-300'),
+        '--el-color-success-light-7': getCssVariableValue('--success-200'),
+        '--el-color-success-light-8': isDark.value
+          ? border
+          : getCssVariableValue('--success-100'),
+        '--el-color-success-light-9': isDark.value
+          ? accent
+          : getCssVariableValue('--success-50'),
+
+        '--el-color-warning': getCssVariableValue('--warning-500'),
+        '--el-color-warning-dark-2': getCssVariableValue('--warning'),
+        '--el-color-warning-light-3': getCssVariableValue('--warning-400'),
+        '--el-color-warning-light-5': getCssVariableValue('--warning-300'),
+        '--el-color-warning-light-7': getCssVariableValue('--warning-200'),
+        '--el-color-warning-light-8': isDark.value
+          ? border
+          : getCssVariableValue('--warning-100'),
+        '--el-color-warning-light-9': isDark.value
+          ? accent
+          : getCssVariableValue('--warning-50'),
+
+        '--el-fill-color': getCssVariableValue('--accent'),
+        '--el-fill-color-blank': background,
+        '--el-fill-color-light': getCssVariableValue('--accent'),
+        '--el-fill-color-lighter': getCssVariableValue('--accent-lighter'),
+
+        '--el-fill-color-dark': getCssVariableValue('--accent-dark'),
+        '--el-fill-color-darker': getCssVariableValue('--accent-darker'),
+
+        // 瑙e喅ElLoading鑳屾櫙鑹查棶棰�
+        '--el-mask-color': isDark.value
+          ? 'rgba(0,0,0,.8)'
+          : 'rgba(255,255,255,.9)',
+
+        '--el-text-color-primary': getCssVariableValue('--foreground'),
+
+        '--el-text-color-regular': getCssVariableValue('--foreground'),
+      };
+
+      updateCSSVariables(variables, `__vben_design_styles__`);
+    },
+    { immediate: true },
+  );
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-pagination.ts b/eims-ui/packages/effects/hooks/src/use-pagination.ts
new file mode 100644
index 0000000..23b36dc
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-pagination.ts
@@ -0,0 +1,57 @@
+import type { Ref } from 'vue';
+import { computed, ref, unref } from 'vue';
+
+/**
+ * Paginates an array of items
+ * @param list The array to paginate
+ * @param pageNo The current page number (1-based)
+ * @param pageSize Number of items per page
+ * @returns Paginated array slice
+ * @throws {Error} If pageNo or pageSize are invalid
+ */
+function pagination<T = any>(list: T[], pageNo: number, pageSize: number): T[] {
+  if (pageNo < 1) throw new Error('Page number must be positive');
+  if (pageSize < 1) throw new Error('Page size must be positive');
+
+  const offset = (pageNo - 1) * Number(pageSize);
+  const ret =
+    offset + pageSize >= list.length
+      ? list.slice(offset)
+      : list.slice(offset, offset + pageSize);
+  return ret;
+}
+
+export function usePagination<T = any>(list: Ref<T[]>, pageSize: number) {
+  const currentPage = ref(1);
+  const pageSizeRef = ref(pageSize);
+
+  const totalPages = computed(() =>
+    Math.ceil(unref(list).length / unref(pageSizeRef)),
+  );
+
+  const paginationList = computed(() => {
+    return pagination(unref(list), unref(currentPage), unref(pageSizeRef));
+  });
+
+  const total = computed(() => {
+    return unref(list).length;
+  });
+
+  function setCurrentPage(page: number) {
+    if (page < 1 || page > unref(totalPages)) {
+      throw new Error('Invalid page number');
+    }
+    currentPage.value = page;
+  }
+
+  function setPageSize(pageSize: number) {
+    if (pageSize < 1) {
+      throw new Error('Page size must be positive');
+    }
+    pageSizeRef.value = pageSize;
+    // Reset to first page to prevent invalid state
+    currentPage.value = 1;
+  }
+
+  return { setCurrentPage, total, setPageSize, paginationList };
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-refresh.ts b/eims-ui/packages/effects/hooks/src/use-refresh.ts
new file mode 100644
index 0000000..b3a5cae
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-refresh.ts
@@ -0,0 +1,16 @@
+import { useRouter } from 'vue-router';
+
+import { useTabbarStore } from '@vben/stores';
+
+export function useRefresh() {
+  const router = useRouter();
+  const tabbarStore = useTabbarStore();
+
+  async function refresh() {
+    await tabbarStore.refresh(router);
+  }
+
+  return {
+    refresh,
+  };
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-tabs.ts b/eims-ui/packages/effects/hooks/src/use-tabs.ts
new file mode 100644
index 0000000..aa79d72
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-tabs.ts
@@ -0,0 +1,113 @@
+import { type RouteLocationNormalized, useRoute, useRouter } from 'vue-router';
+
+import { useTabbarStore } from '@vben/stores';
+
+export function useTabs() {
+  const router = useRouter();
+  const route = useRoute();
+  const tabbarStore = useTabbarStore();
+
+  async function closeLeftTabs(tab?: RouteLocationNormalized) {
+    await tabbarStore.closeLeftTabs(tab || route);
+  }
+
+  async function closeAllTabs() {
+    await tabbarStore.closeAllTabs(router);
+  }
+
+  async function closeRightTabs(tab?: RouteLocationNormalized) {
+    await tabbarStore.closeRightTabs(tab || route);
+  }
+
+  async function closeOtherTabs(tab?: RouteLocationNormalized) {
+    await tabbarStore.closeOtherTabs(tab || route);
+  }
+
+  async function closeCurrentTab(tab?: RouteLocationNormalized) {
+    await tabbarStore.closeTab(tab || route, router);
+  }
+
+  async function pinTab(tab?: RouteLocationNormalized) {
+    await tabbarStore.pinTab(tab || route);
+  }
+
+  async function unpinTab(tab?: RouteLocationNormalized) {
+    await tabbarStore.unpinTab(tab || route);
+  }
+
+  async function toggleTabPin(tab?: RouteLocationNormalized) {
+    await tabbarStore.toggleTabPin(tab || route);
+  }
+
+  async function refreshTab() {
+    await tabbarStore.refresh(router);
+  }
+
+  async function openTabInNewWindow(tab?: RouteLocationNormalized) {
+    await tabbarStore.openTabInNewWindow(tab || route);
+  }
+
+  async function closeTabByKey(key: string) {
+    await tabbarStore.closeTabByKey(key, router);
+  }
+
+  async function setTabTitle(title: string) {
+    tabbarStore.setUpdateTime();
+    await tabbarStore.setTabTitle(route, title);
+  }
+
+  async function resetTabTitle() {
+    tabbarStore.setUpdateTime();
+    await tabbarStore.resetTabTitle(route);
+  }
+
+  /**
+   * 鑾峰彇鎿嶄綔鏄惁绂佺敤
+   * @param tab
+   */
+  function getTabDisableState(tab: RouteLocationNormalized = route) {
+    const tabs = tabbarStore.getTabs;
+    const affixTabs = tabbarStore.affixTabs;
+    const index = tabs.findIndex((item) => item.path === tab.path);
+
+    const disabled = tabs.length <= 1;
+
+    const { meta } = tab;
+    const affixTab = meta?.affixTab ?? false;
+    const isCurrentTab = route.path === tab.path;
+
+    // 褰撳墠澶勪簬鏈�宸︿晶鎴栬�呭噺鍘诲浐瀹氭爣绛鹃〉鐨勬暟閲忕瓑浜�0
+    const disabledCloseLeft =
+      index === 0 || index - affixTabs.length <= 0 || !isCurrentTab;
+
+    const disabledCloseRight = !isCurrentTab || index === tabs.length - 1;
+
+    const disabledCloseOther =
+      disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1;
+    return {
+      disabledCloseAll: disabled,
+      disabledCloseCurrent: !!affixTab || disabled,
+      disabledCloseLeft,
+      disabledCloseOther,
+      disabledCloseRight,
+      disabledRefresh: !isCurrentTab,
+    };
+  }
+
+  return {
+    closeAllTabs,
+    closeCurrentTab,
+    closeLeftTabs,
+    closeOtherTabs,
+    closeRightTabs,
+    closeTabByKey,
+    getTabDisableState,
+    openTabInNewWindow,
+    pinTab,
+    refreshTab,
+    resetTabTitle,
+    setTabTitle,
+    toggleTabPin,
+    unpinTab,
+  };
+}
diff --git a/eims-ui/packages/effects/hooks/src/use-watermark.ts b/eims-ui/packages/effects/hooks/src/use-watermark.ts
new file mode 100644
index 0000000..c3f56ea
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/src/use-watermark.ts
@@ -0,0 +1,88 @@
+import type { Watermark, WatermarkOptions } from 'watermark-js-plus';
+
+import { nextTick, onUnmounted, readonly, ref } from 'vue';
+
+import { updatePreferences } from '@vben/preferences';
+
+const watermark = ref<Watermark>();
+const unmountedHooked = ref<boolean>(false);
+const cachedOptions = ref<Partial<WatermarkOptions>>({
+  advancedStyle: {
+    colorStops: [
+      {
+        color: 'gray',
+        offset: 0,
+      },
+      {
+        color: 'gray',
+        offset: 1,
+      },
+    ],
+    type: 'linear',
+  },
+  // fontSize: '20px',
+  content: '',
+  contentType: 'multi-line-text',
+  globalAlpha: 0.25,
+  gridLayoutOptions: {
+    cols: 2,
+    gap: [20, 20],
+    matrix: [
+      [1, 0],
+      [0, 1],
+    ],
+    rows: 2,
+  },
+  height: 200,
+  layout: 'grid',
+  rotate: 30,
+  width: 160,
+});
+
+export function useWatermark() {
+  async function initWatermark(options: Partial<WatermarkOptions>) {
+    const { Watermark } = await import('watermark-js-plus');
+
+    cachedOptions.value = {
+      ...cachedOptions.value,
+      ...options,
+    };
+    watermark.value = new Watermark(cachedOptions.value);
+    updatePreferences({ app: { watermark: true } });
+    await watermark.value?.create();
+  }
+
+  async function updateWatermark(options: Partial<WatermarkOptions>) {
+    if (watermark.value) {
+      await nextTick();
+      await watermark.value?.changeOptions({
+        ...cachedOptions.value,
+        ...options,
+      });
+    } else {
+      await initWatermark(options);
+    }
+  }
+
+  function destroyWatermark() {
+    if (watermark.value) {
+      watermark.value.destroy();
+      watermark.value = undefined;
+    }
+    updatePreferences({ app: { watermark: false } });
+  }
+
+  // 鍙湪绗竴娆¤皟鐢ㄦ椂娉ㄥ唽鍗歌浇閽╁瓙锛岄槻姝㈤噸澶嶆敞鍐屼互鑷翠簬鍦ㄨ矾鐢卞垏鎹㈡椂閿�姣佷簡姘村嵃
+  if (!unmountedHooked.value) {
+    unmountedHooked.value = true;
+    onUnmounted(() => {
+      destroyWatermark();
+    });
+  }
+
+  return {
+    destroyWatermark,
+    updateWatermark,
+    watermark: readonly(watermark),
+  };
+}
diff --git a/eims-ui/packages/effects/hooks/tsconfig.json b/eims-ui/packages/effects/hooks/tsconfig.json
new file mode 100644
index 0000000..b13aa7a
--- /dev/null
+++ b/eims-ui/packages/effects/hooks/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "compilerOptions": {
+    "types": ["vite/client", "@vben/types/global"]
+  },
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/layouts/package.json b/eims-ui/packages/effects/layouts/package.json
new file mode 100644
index 0000000..89bf4e8
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "@vben/layouts",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/layouts"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/composables": "workspace:*",
+    "@vben-core/form-ui": "workspace:*",
+    "@vben-core/layout-ui": "workspace:*",
+    "@vben-core/menu-ui": "workspace:*",
+    "@vben-core/popup-ui": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/tabs-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/layouts/src/authentication/authentication.vue b/eims-ui/packages/effects/layouts/src/authentication/authentication.vue
new file mode 100644
index 0000000..ceae802
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/authentication.vue
@@ -0,0 +1,156 @@
+<script setup lang="ts">
+import type { ToolbarType } from './types';
+
+import { preferences, usePreferences } from '@vben/preferences';
+
+import { Copyright } from '../basic/copyright';
+import AuthenticationFormView from './form.vue';
+import SloganIcon from './icons/slogan.vue';
+import Toolbar from './toolbar.vue';
+
+interface Props {
+  appName?: string;
+  logo?: string;
+  pageTitle?: string;
+  pageDescription?: string;
+  sloganImage?: string;
+  toolbar?: boolean;
+  copyright?: boolean;
+  toolbarList?: ToolbarType[];
+}
+
+withDefaults(defineProps<Props>(), {
+  appName: '',
+  copyright: true,
+  logo: '',
+  pageDescription: '',
+  pageTitle: '',
+  sloganImage: '',
+  toolbar: true,
+  toolbarList: () => ['color', 'language', 'layout', 'theme'],
+});
+
+const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
+  usePreferences();
+</script>
+
+<template>
+  <div
+    :class="[isDark]"
+    class="flex min-h-full flex-1 select-none overflow-x-hidden"
+  >
+    <template v-if="toolbar">
+      <slot name="toolbar">
+        <Toolbar :toolbar-list="toolbarList" />
+      </slot>
+    </template>
+    <!-- 宸︿晶璁よ瘉闈㈡澘 -->
+    <AuthenticationFormView
+      v-if="authPanelLeft"
+      class="min-h-full w-2/5 flex-1"
+      transition-name="slide-left"
+    >
+      <template v-if="copyright" #copyright>
+        <slot name="copyright">
+          <Copyright
+            v-if="preferences.copyright.enable"
+            v-bind="preferences.copyright"
+          />
+        </slot>
+      </template>
+    </AuthenticationFormView>
+
+    <!-- 澶撮儴 Logo 鍜屽簲鐢ㄥ悕绉� -->
+    <div v-if="logo || appName" class="absolute left-0 top-0 z-10 flex flex-1">
+      <div
+        class="text-foreground lg:text-foreground ml-4 mt-4 flex flex-1 items-center sm:left-6 sm:top-6"
+      >
+        <img v-if="logo" :alt="appName" :src="logo" class="mr-2" width="42" />
+        <p v-if="appName" class="text-xl font-medium">
+          {{ appName }}
+        </p>
+      </div>
+    </div>
+
+    <!-- 绯荤粺浠嬬粛 -->
+    <div v-if="!authPanelCenter" class="relative hidden w-0 flex-1 lg:block">
+      <div
+        class="bg-background-deep absolute inset-0 h-full w-full dark:bg-[#070709]"
+      >
+        <div class="login-background absolute left-0 top-0 size-full"></div>
+        <div class="flex-col-center -enter-x mr-20 h-full">
+          <template v-if="sloganImage">
+            <img
+              :alt="appName"
+              :src="sloganImage"
+              class="animate-float h-64 w-2/5"
+            />
+          </template>
+          <SloganIcon v-else :alt="appName" class="animate-float h-64 w-2/5" />
+          <div class="text-1xl text-foreground mt-6 font-sans lg:text-2xl">
+            {{ pageTitle }}
+          </div>
+          <div class="dark:text-muted-foreground mt-2">
+            {{ pageDescription }}
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 涓績璁よ瘉闈㈡澘 -->
+    <div v-if="authPanelCenter" class="flex-center relative w-full">
+      <div class="login-background absolute left-0 top-0 size-full"></div>
+      <AuthenticationFormView
+        class="md:bg-background shadow-primary/5 shadow-float w-full rounded-3xl pb-20 md:w-2/3 lg:w-1/2 xl:w-[36%]"
+      >
+        <template v-if="copyright" #copyright>
+          <slot name="copyright">
+            <Copyright
+              v-if="preferences.copyright.enable"
+              v-bind="preferences.copyright"
+            />
+          </slot>
+        </template>
+      </AuthenticationFormView>
+    </div>
+
+    <!-- 鍙充晶璁よ瘉闈㈡澘 -->
+    <AuthenticationFormView
+      v-if="authPanelRight"
+      class="min-h-full w-[34%] flex-1"
+    >
+      <template v-if="copyright" #copyright>
+        <slot name="copyright">
+          <Copyright
+            v-if="preferences.copyright.enable"
+            v-bind="preferences.copyright"
+          />
+        </slot>
+      </template>
+    </AuthenticationFormView>
+  </div>
+</template>
+
+<style scoped>
+.login-background {
+  background: linear-gradient(
+    154deg,
+    #07070915 30%,
+    hsl(var(--primary) / 30%) 48%,
+    #07070915 64%
+  );
+  filter: blur(100px);
+}
+
+.dark {
+  .login-background {
+    background: linear-gradient(
+      154deg,
+      #07070915 30%,
+      hsl(var(--primary) / 20%) 48%,
+      #07070915 64%
+    );
+    filter: blur(100px);
+  }
+}
+</style>
diff --git a/eims-ui/packages/effects/layouts/src/authentication/form.vue b/eims-ui/packages/effects/layouts/src/authentication/form.vue
new file mode 100644
index 0000000..80c9074
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/form.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+defineOptions({
+  name: 'AuthenticationFormView',
+});
+</script>
+
+<template>
+  <div
+    class="flex-col-center dark:bg-background-deep bg-background relative px-6 py-10 lg:flex-initial lg:px-8"
+  >
+    <slot></slot>
+    <!-- Router View with Transition and KeepAlive -->
+    <RouterView v-slot="{ Component, route }">
+      <Transition appear mode="out-in" name="slide-right">
+        <KeepAlive :include="['Login']">
+          <component
+            :is="Component"
+            :key="route.fullPath"
+            class="enter-x mt-6 w-full sm:mx-auto md:max-w-md"
+          />
+        </KeepAlive>
+      </Transition>
+    </RouterView>
+
+    <!-- Footer Copyright -->
+
+    <div
+      class="text-muted-foreground absolute bottom-3 flex text-center text-xs"
+    >
+      <slot name="copyright"> </slot>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/authentication/icons/slogan.vue b/eims-ui/packages/effects/layouts/src/authentication/icons/slogan.vue
new file mode 100644
index 0000000..82cc119
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/icons/slogan.vue
@@ -0,0 +1,4568 @@
+<template>
+  <svg
+    enable-background="new 0 0 800 800"
+    version="1.1"
+    viewBox="0 0 800 800"
+    x="0px"
+    xml:space="preserve"
+    xmlns="http://www.w3.org/2000/svg"
+    xmlns:xlink="http://www.w3.org/1999/xlink"
+    y="0px"
+  >
+    <filter
+      id="filter-95"
+      filterUnits="objectBoundingBox"
+      height="124.9%"
+      width="114.5%"
+      x="-7.3%"
+      y="-12.5%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="4.21434086" />
+    </filter>
+    <filter
+      id="filter-79"
+      filterUnits="objectBoundingBox"
+      height="101.4%"
+      width="100.8%"
+      x="-0.4%"
+      y="-0.7%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <filter
+      id="filter-71"
+      filterUnits="objectBoundingBox"
+      height="142.5%"
+      width="120.1%"
+      x="-10.1%"
+      y="-21.3%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="4.21434086" />
+    </filter>
+    <filter
+      id="filter-59"
+      filterUnits="objectBoundingBox"
+      height="181.0%"
+      width="133.4%"
+      x="-16.7%"
+      y="-40.5%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="4.85695311" />
+    </filter>
+    <filter
+      id="filter-56"
+      filterUnits="objectBoundingBox"
+      height="181.0%"
+      width="133.4%"
+      x="-16.7%"
+      y="-40.5%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="2.91417187" />
+    </filter>
+    <filter
+      id="filter-53"
+      filterUnits="objectBoundingBox"
+      height="100.9%"
+      width="100.5%"
+      x="-0.2%"
+      y="-0.4%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <filter
+      id="filter-50"
+      filterUnits="objectBoundingBox"
+      height="241.5%"
+      width="643.8%"
+      x="-271.9%"
+      y="-70.7%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="16.2954513" />
+    </filter>
+    <filter
+      id="filter-5"
+      filterUnits="objectBoundingBox"
+      height="100.8%"
+      width="100.4%"
+      x="-0.2%"
+      y="-0.4%"
+    >
+      <feOffset dx="0" dy="-3" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <filter
+      id="filter-46"
+      filterUnits="objectBoundingBox"
+      height="100.7%"
+      width="100.4%"
+      x="-0.2%"
+      y="-0.3%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <filter
+      id="filter-43"
+      filterUnits="objectBoundingBox"
+      height="241.5%"
+      width="643.8%"
+      x="-271.9%"
+      y="-70.7%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="20.3693141" />
+    </filter>
+    <filter
+      id="filter-39"
+      filterUnits="objectBoundingBox"
+      height="113.3%"
+      width="107.0%"
+      x="-3.5%"
+      y="-6.7%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="3.51195071" />
+    </filter>
+    <filter
+      id="filter-34"
+      filterUnits="objectBoundingBox"
+      height="103.6%"
+      width="102.1%"
+      x="-1.1%"
+      y="-1.8%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0"
+      />
+    </filter>
+    <filter
+      id="filter-29"
+      filterUnits="objectBoundingBox"
+      height="103.6%"
+      width="102.1%"
+      x="-1.1%"
+      y="-1.8%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0"
+      />
+    </filter>
+    <filter
+      id="filter-24"
+      filterUnits="objectBoundingBox"
+      height="103.6%"
+      width="102.1%"
+      x="-1.1%"
+      y="-1.8%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0"
+      />
+    </filter>
+    <filter
+      id="filter-20"
+      filterUnits="objectBoundingBox"
+      height="102.3%"
+      width="101.3%"
+      x="-0.7%"
+      y="-1.1%"
+    >
+      <feOffset dx="0" dy="-3" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <filter
+      id="filter-14"
+      filterUnits="objectBoundingBox"
+      height="103.6%"
+      width="102.1%"
+      x="-1.0%"
+      y="-1.8%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0"
+      />
+    </filter>
+    <filter
+      id="filter-109"
+      filterUnits="objectBoundingBox"
+      height="102.5%"
+      width="101.4%"
+      x="-0.7%"
+      y="-1.2%"
+    >
+      <feOffset dx="0" dy="-1" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.833806818 0"
+      />
+    </filter>
+    <filter
+      id="filter-106"
+      filterUnits="objectBoundingBox"
+      height="149.1%"
+      width="128.6%"
+      x="-14.3%"
+      y="-24.5%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="4.71559623" />
+    </filter>
+    <filter
+      id="filter-100"
+      filterUnits="objectBoundingBox"
+      height="133.5%"
+      width="119.4%"
+      x="-9.7%"
+      y="-16.8%"
+    >
+      <feGaussianBlur in="SourceGraphic" stdDeviation="4.21434086" />
+    </filter>
+    <filter
+      id="filter-10"
+      filterUnits="objectBoundingBox"
+      height="100.7%"
+      width="100.4%"
+      x="-0.2%"
+      y="-0.3%"
+    >
+      <feOffset dx="0" dy="-3" in="SourceAlpha" result="shadowOffsetInner1" />
+      <feComposite
+        in="shadowOffsetInner1"
+        in2="SourceAlpha"
+        k2="-1"
+        k3="1"
+        operator="arithmetic"
+        result="shadowInnerInner1"
+      />
+      <feColorMatrix
+        in="shadowInnerInner1"
+        type="matrix"
+        values="0 0 0 0 1   0 0 0 0 1   0 0 0 0 1  0 0 0 0.498880026 0"
+      />
+    </filter>
+    <title>87667-SVG8</title>
+    <g>
+      <g id="Group澶囦唤" transform="translate(40.000000, 350.000000)">
+        <linearGradient
+          id="Shape_1_"
+          gradientTransform="matrix(352.3498 0 0 -229.3688 -21376.5684 335815.1875)"
+          gradientUnits="userSpaceOnUse"
+          x1="62.7934"
+          x2="61.7099"
+          y1="1462.9332"
+          y2="1462.535"
+        >
+          <stop offset="0" style="stop-color: #0043fb" />
+          <stop offset="1" style="stop-color: #3684ff" />
+        </linearGradient>
+        <path
+          id="Shape"
+          d="M368,428.9c1.4,0.8,3.2,0.8,4.6,0l344.4-198.3c2.8-1.6,3.4-5.4,1.2-7.8l-16.3-22.7
+			L370.3,395.7v31.6l-3.2,1L368,428.9z"
+          fill="url(#Shape_1_)"
+        />
+
+        <linearGradient
+          id="SVGID_1_"
+          gradientTransform="matrix(369.5781 0 0 -241.7468 -22811.1367 353968.8438)"
+          gradientUnits="userSpaceOnUse"
+          x1="63.31"
+          x2="61.5984"
+          y1="1462.5217"
+          y2="1463.1935"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #00c6fb" />
+          <stop offset="1" style="stop-color: #005bea" />
+        </linearGradient>
+        <path
+          d="M370.3,427.3c0,1.3-1.4,2.1-2.5,1.4L3.2,217.3c-2.8-1.6-3.4-5.4-1.2-7.8l17.8-22.3l350.5,208.4
+			V427.3L370.3,427.3z"
+          fill="url(#SVGID_1_)"
+        />
+        <g>
+          <g>
+            <linearGradient
+              id="path-4_1_"
+              gradientTransform="matrix(689.8593 0 0 -397.2563 -42654.3008 582014.8125)"
+              gradientUnits="userSpaceOnUse"
+              x1="62.5423"
+              x2="62.1013"
+              y1="1464.4305"
+              y2="1464.7888"
+            >
+              <stop offset="0" style="stop-color: #4587ef" />
+              <stop offset="1" style="stop-color: #00209e" />
+            </linearGradient>
+            <path
+              id="path-4"
+              clip-rule="evenodd"
+              d="M355.7,393.8L18,198.7
+					c-4-2.3-4-8.1,0-10.4L337.8,3.6c7.4-4.3,16.5-4.3,24,0l340.1,196.5c4,2.3,4,8.1,0,10.4L384.4,393.8
+					C375.5,398.9,364.6,398.9,355.7,393.8z"
+              fill="url(#path-4_1_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g filter="url(#filter-5)">
+            <path
+              clip-rule="evenodd"
+              d="M355.7,393.8L18,198.7c-4-2.3-4-8.1,0-10.4L337.8,3.6c7.4-4.3,16.5-4.3,24,0
+					l340.1,196.5c4,2.3,4,8.1,0,10.4L384.4,393.8C375.5,398.9,364.6,398.9,355.7,393.8z"
+              fill-rule="evenodd"
+            />
+          </g>
+        </g>
+        <path
+          id="Shape澶囦唤"
+          d="M356.1,376L49.6,199c-3.6-2.1-3.6-7.4,0-9.5
+			L339.8,21.9c6.7-3.9,15-3.9,21.7,0l308.6,178.3c3.6,2.1,3.6,7.4,0,9.5L382.1,376C374.1,380.7,364.1,380.7,356.1,376z"
+          fill="none"
+          stroke="#FFFFFF"
+          stroke-width="0.9511"
+        />
+      </g>
+      <g id="Group" transform="translate(0.000000, 259.000000)">
+        <linearGradient
+          id="SVGID_2_"
+          gradientTransform="matrix(391.4998 0 0 -254.8542 -39423.0664 396432.7188)"
+          gradientUnits="userSpaceOnUse"
+          x1="102.8224"
+          x2="101.7388"
+          y1="1554.3767"
+          y2="1553.9784"
+        >
+          <stop offset="0" style="stop-color: #0043fb" />
+          <stop offset="1" style="stop-color: #3684ff" />
+        </linearGradient>
+        <path
+          d="M408.9,476.5c1.6,0.9,3.5,0.9,5.1,0l382.6-220.3c3.1-1.8,3.8-6,1.3-8.7l-18.1-25.2L411.4,439.6
+			v35.2l-3.5,1.1L408.9,476.5z"
+          fill="url(#SVGID_2_)"
+        />
+
+        <linearGradient
+          id="SVGID_3_"
+          gradientTransform="matrix(410.6423 0 0 -268.6075 -41782.7344 417855)"
+          gradientUnits="userSpaceOnUse"
+          x1="103.3376"
+          x2="101.626"
+          y1="1553.9424"
+          y2="1554.6141"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #00c6fb" />
+          <stop offset="1" style="stop-color: #005bea" />
+        </linearGradient>
+        <path
+          d="M411.4,474.8c0,1.4-1.5,2.3-2.8,1.6L3.6,241.5c-3.1-1.8-3.8-6-1.3-8.7L22,208l389.4,231.6V474.8
+			L411.4,474.8z"
+          fill="url(#SVGID_3_)"
+        />
+        <g>
+          <g>
+            <linearGradient
+              id="path-9_1_"
+              gradientTransform="matrix(766.5103 0 0 -441.3958 -78065.4141 686963.125)"
+              gradientUnits="userSpaceOnUse"
+              x1="102.5571"
+              x2="102.1161"
+              y1="1555.6865"
+              y2="1556.0448"
+            >
+              <stop offset="0" style="stop-color: #4587ef" />
+              <stop offset="1" style="stop-color: #00209e" />
+            </linearGradient>
+            <path
+              id="path-9"
+              clip-rule="evenodd"
+              d="M395.2,437.6L20,220.8
+					c-4.5-2.6-4.5-9,0-11.6L375.3,4c8.2-4.8,18.4-4.8,26.6,0l377.9,218.3c4.5,2.6,4.5,9,0,11.6L427.1,437.6
+					C417.2,443.3,405.1,443.3,395.2,437.6z"
+              fill="url(#path-9_1_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g filter="url(#filter-10)">
+            <path
+              clip-rule="evenodd"
+              d="M395.2,437.6L20,220.8c-4.5-2.6-4.5-9,0-11.6L375.3,4c8.2-4.8,18.4-4.8,26.6,0
+					l377.9,218.3c4.5,2.6,4.5,9,0,11.6L427.1,437.6C417.2,443.3,405.1,443.3,395.2,437.6z"
+              fill-rule="evenodd"
+            />
+          </g>
+        </g>
+        <path
+          d="M395.6,417.8L55.2,221.1c-4.1-2.3-4.1-8.2,0-10.5L377.6,24.4
+			c7.5-4.3,16.7-4.3,24.2,0l342.9,198.1c4.1,2.3,4.1,8.2,0,10.5L424.6,417.8C415.6,423,404.6,423,395.6,417.8z"
+          fill="none"
+          stroke="#FFFFFF"
+          stroke-width="1.0568"
+        />
+      </g>
+      <g id="缂栫粍澶囦唤-4" transform="translate(386.000000, 561.000000)">
+        <g id="缂栫粍澶囦唤-3" transform="translate(0.000000, 69.529529)">
+          <g id="Stroke-1">
+            <g>
+              <linearGradient
+                id="path-13_1_"
+                gradientTransform="matrix(47.9924 0 0 -27.7074 13731.9688 31874.9453)"
+                gradientUnits="userSpaceOnUse"
+                x1="-285.6253"
+                x2="-285.6253"
+                y1="1149.4111"
+                y2="1150.4111"
+              >
+                <stop offset="0" style="stop-color: #3a3aff" />
+                <stop offset="1" style="stop-color: #0707d6" />
+              </linearGradient>
+              <polygon
+                id="path-13"
+                clip-rule="evenodd"
+                fill="url(#path-13_1_)"
+                fill-rule="evenodd"
+                points="0.1,13.9 24.1,27.8 48.1,13.9
+						24.1,0.1 					"
+              />
+            </g>
+            <g>
+              <linearGradient
+                id="SVGID_4_"
+                gradientTransform="matrix(47.9924 0 0 -27.7074 13731.9688 31874.9453)"
+                gradientUnits="userSpaceOnUse"
+                x1="-285.6253"
+                x2="-285.6253"
+                y1="1149.4111"
+                y2="1150.4294"
+              >
+                <stop
+                  offset="0"
+                  style="stop-color: #8fa0ff; stop-opacity: 0.467"
+                />
+                <stop
+                  offset="1"
+                  style="stop-color: #0f0f0f; stop-opacity: 0.06"
+                />
+                <stop offset="1" style="stop-color: #2f59e1; stop-opacity: 0" />
+              </linearGradient>
+              <polygon
+                clip-rule="evenodd"
+                fill="url(#SVGID_4_)"
+                fill-rule="evenodd"
+                points="0.1,13.9 24.1,27.8 48.1,13.9 24.1,0.1
+						"
+              />
+            </g>
+            <g filter="url(#filter-14)">
+              <polygon
+                clip-rule="evenodd"
+                fill-rule="evenodd"
+                points="0.1,13.9 24.1,27.8 48.1,13.9 24.1,0.1 					"
+              />
+            </g>
+          </g>
+
+          <linearGradient
+            id="Stroke-3_1_"
+            gradientTransform="matrix(23.9962 0 0 -41.5628 6916.9932 48336.7578)"
+            gradientUnits="userSpaceOnUse"
+            x1="-287.7007"
+            x2="-287.815"
+            y1="1162.8857"
+            y2="1161.1971"
+          >
+            <stop offset="0" style="stop-color: #4f3eff" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <polygon
+            id="Stroke-3"
+            clip-rule="evenodd"
+            fill="url(#Stroke-3_1_)"
+            fill-rule="evenodd"
+            points="24.1,55.5 24.1,27.8 0.1,13.9
+				0.1,41.6 			"
+          />
+
+          <linearGradient
+            id="Stroke-5_1_"
+            gradientTransform="matrix(23.9962 0 0 -41.5628 6941.0435 48336.7578)"
+            gradientUnits="userSpaceOnUse"
+            x1="-287.7007"
+            x2="-287.815"
+            y1="1162.8857"
+            y2="1161.1971"
+          >
+            <stop offset="0" style="stop-color: #1200ca" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <polygon
+            id="Stroke-5"
+            clip-rule="evenodd"
+            fill="url(#Stroke-5_1_)"
+            fill-rule="evenodd"
+            points="24.1,55.5 24.1,27.8
+				48.1,13.9 48.1,41.6 			"
+          />
+        </g>
+
+        <linearGradient
+          id="鐭╁舰_1_"
+          gradientTransform="matrix(48.245 0 0 -97.3101 13803.5742 121267.3516)"
+          gradientUnits="userSpaceOnUse"
+          x1="-285.6142"
+          x2="-285.6142"
+          y1="1246.0574"
+          y2="1244.9515"
+        >
+          <stop offset="0" style="stop-color: #fff; stop-opacity: 0" />
+          <stop offset="1" style="stop-color: #fff" />
+        </linearGradient>
+
+        <polygon
+          id="鐭╁舰"
+          clip-rule="evenodd"
+          enable-background="new    "
+          fill="url(#鐭╁舰_1_)"
+          fill-rule="evenodd"
+          opacity="0.1977"
+          points="
+			0,0 48.2,0 48.2,83.7 24.1,97.3 0,83.7 		"
+        />
+      </g>
+      <g id="缂栫粍-4" transform="translate(71.000000, 199.000000)">
+        <g id="Shape澶囦唤-2">
+          <g>
+            <linearGradient
+              id="path-19_1_"
+              gradientTransform="matrix(228.3947 0 0 -131.5657 -6978.2363 212124.2031)"
+              gradientUnits="userSpaceOnUse"
+              x1="31.2434"
+              x2="30.8024"
+              y1="1610.2603"
+              y2="1610.6188"
+            >
+              <stop offset="0" style="stop-color: #4587ef" />
+              <stop offset="1" style="stop-color: #00209e" />
+            </linearGradient>
+            <path
+              id="path-19"
+              clip-rule="evenodd"
+              d="M63.4,312.7l-62-35.9
+					c-1.9-1.1-1.9-3.8,0-4.9l151.1-87.4c3.5-2,7.8-2,11.3,0l63.1,36.6c1.9,1.1,1.9,3.8,0,4.9L77,312.7
+					C72.8,315.2,67.6,315.2,63.4,312.7z"
+              fill="url(#path-19_1_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g filter="url(#filter-20)">
+            <path
+              clip-rule="evenodd"
+              d="M63.4,312.7l-62-35.9c-1.9-1.1-1.9-3.8,0-4.9l151.1-87.4c3.5-2,7.8-2,11.3,0
+					l63.1,36.6c1.9,1.1,1.9,3.8,0,4.9L77,312.7C72.8,315.2,67.6,315.2,63.4,312.7z"
+              fill-rule="evenodd"
+            />
+          </g>
+        </g>
+        <g id="缂栫粍-13" transform="translate(45.000000, 0.000000)">
+          <g id="缂栫粍澶囦唤-17" transform="translate(90.066225, 54.000000)">
+            <g>
+              <g>
+                <linearGradient
+                  id="path-23_1_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 5055.4995 41979.2891)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-105.7092"
+                  x2="-105.7092"
+                  y1="1526.6367"
+                  y2="1527.6367"
+                >
+                  <stop offset="0" style="stop-color: #3a3aff" />
+                  <stop offset="1" style="stop-color: #0707d6" />
+                </linearGradient>
+                <polygon
+                  id="path-23"
+                  clip-rule="evenodd"
+                  fill="url(#path-23_1_)"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6
+							47.7,13.8 23.9,0.1 						"
+                />
+              </g>
+              <g>
+                <linearGradient
+                  id="SVGID_5_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 5055.4995 41979.2891)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-105.7092"
+                  x2="-105.7092"
+                  y1="1526.6367"
+                  y2="1527.655"
+                >
+                  <stop
+                    offset="0"
+                    style="stop-color: #8fa0ff; stop-opacity: 0.467"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #0f0f0f; stop-opacity: 0.06"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #2f59e1; stop-opacity: 0"
+                  />
+                </linearGradient>
+                <polygon
+                  clip-rule="evenodd"
+                  fill="url(#SVGID_5_)"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1
+													"
+                />
+              </g>
+              <g filter="url(#filter-24)">
+                <polygon
+                  clip-rule="evenodd"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1 						"
+                />
+              </g>
+            </g>
+
+            <linearGradient
+              id="SVGID_6_"
+              gradientTransform="matrix(23.7991 0 0 -168.4388 2578.7588 262543.8125)"
+              gradientUnits="userSpaceOnUse"
+              x1="-107.8491"
+              x2="-107.8559"
+              y1="1558.8499"
+              y2="1557.1613"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_6_)"
+              fill-rule="evenodd"
+              points="23.9,182.3 23.9,27.6 0.1,13.8 0.1,168.5
+					"
+            />
+
+            <linearGradient
+              id="SVGID_7_"
+              gradientTransform="matrix(23.7991 0 0 -168.4388 2602.6116 262543.8125)"
+              gradientUnits="userSpaceOnUse"
+              x1="-107.8491"
+              x2="-107.8559"
+              y1="1558.8499"
+              y2="1557.1613"
+            >
+              <stop offset="0" style="stop-color: #1200ca" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_7_)"
+              fill-rule="evenodd"
+              points="23.9,182.3 23.9,27.6 47.7,13.8 47.7,168.5
+									"
+            />
+          </g>
+          <g id="缂栫粍澶囦唤-16" transform="translate(45.562914, 134.529801)">
+            <g>
+              <g>
+                <linearGradient
+                  id="path-28_1_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 2937.218 39766.3438)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-61.7058"
+                  x2="-60.7058"
+                  y1="1446.6069"
+                  y2="1446.6069"
+                >
+                  <stop offset="0" style="stop-color: #bda0e5" />
+                  <stop offset="1" style="stop-color: #5f3abd" />
+                </linearGradient>
+                <polygon
+                  id="path-28"
+                  clip-rule="evenodd"
+                  fill="url(#path-28_1_)"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6
+							47.7,13.8 23.9,0.1 						"
+                />
+              </g>
+              <g>
+                <linearGradient
+                  id="SVGID_8_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 2937.218 39766.3438)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-61.2058"
+                  x2="-61.2058"
+                  y1="1446.1069"
+                  y2="1447.1252"
+                >
+                  <stop
+                    offset="0"
+                    style="stop-color: #8fa0ff; stop-opacity: 0.467"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #0f0f0f; stop-opacity: 0.06"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #2f59e1; stop-opacity: 0"
+                  />
+                </linearGradient>
+                <polygon
+                  clip-rule="evenodd"
+                  fill="url(#SVGID_8_)"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1
+													"
+                />
+              </g>
+              <g filter="url(#filter-29)">
+                <polygon
+                  clip-rule="evenodd"
+                  fill-rule="evenodd"
+                  points="0.1,13.8 23.9,27.6 47.7,13.8 23.9,0.1 						"
+                />
+              </g>
+            </g>
+
+            <linearGradient
+              id="SVGID_9_"
+              gradientTransform="matrix(23.7991 0 0 -114.399 1519.618 168778.2344)"
+              gradientUnits="userSpaceOnUse"
+              x1="-63.3488"
+              x2="-63.3488"
+              y1="1475.4679"
+              y2="1474.0222"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="1" style="stop-color: #f77" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_9_)"
+              fill-rule="evenodd"
+              points="23.9,128.2 23.9,27.6 0.1,13.8 0.1,114.5
+					"
+            />
+
+            <linearGradient
+              id="SVGID_10_"
+              gradientTransform="matrix(23.7991 0 0 -114.399 1543.4708 168778.2344)"
+              gradientUnits="userSpaceOnUse"
+              x1="-63.3488"
+              x2="-63.3488"
+              y1="1475.4679"
+              y2="1474.0222"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="1" style="stop-color: #d73838" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_10_)"
+              fill-rule="evenodd"
+              points="23.9,128.2 23.9,27.6 47.7,13.8 47.7,114.5
+									"
+            />
+          </g>
+          <g id="缂栫粍澶囦唤-18" transform="translate(0.000000, 0.271523)">
+            <g>
+              <g>
+                <linearGradient
+                  id="path-33_1_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 768.5011 43638.7383)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-16.1429"
+                  x2="-15.1429"
+                  y1="1580.8652"
+                  y2="1580.8652"
+                >
+                  <stop offset="0" style="stop-color: #8afffc" />
+                  <stop offset="1" style="stop-color: #003dde" />
+                </linearGradient>
+                <polygon
+                  id="path-33"
+                  clip-rule="evenodd"
+                  fill="url(#path-33_1_)"
+                  fill-rule="evenodd"
+                  points="0.1,196.8 23.9,210.6
+							47.7,196.8 23.9,183.1 						"
+                />
+              </g>
+              <g>
+                <linearGradient
+                  id="SVGID_11_"
+                  gradientTransform="matrix(47.5983 0 0 -27.4798 768.5011 43638.7383)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-15.6429"
+                  x2="-15.6429"
+                  y1="1580.3652"
+                  y2="1581.3835"
+                >
+                  <stop
+                    offset="0"
+                    style="stop-color: #8fa0ff; stop-opacity: 0.467"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #0f0f0f; stop-opacity: 0.06"
+                  />
+                  <stop
+                    offset="1"
+                    style="stop-color: #2f59e1; stop-opacity: 0"
+                  />
+                </linearGradient>
+                <polygon
+                  clip-rule="evenodd"
+                  fill="url(#SVGID_11_)"
+                  fill-rule="evenodd"
+                  points="0.1,196.8 23.9,210.6 47.7,196.8
+							23.9,183.1 						"
+                />
+              </g>
+              <g filter="url(#filter-34)">
+                <polygon
+                  clip-rule="evenodd"
+                  fill-rule="evenodd"
+                  points="0.1,196.8 23.9,210.6 47.7,196.8 23.9,183.1 						"
+                />
+              </g>
+            </g>
+
+            <linearGradient
+              id="SVGID_12_"
+              gradientTransform="matrix(48 0 0 -80.5525 774 129477.0156)"
+              gradientUnits="userSpaceOnUse"
+              x1="-15.625"
+              x2="-15.625"
+              y1="1604.7488"
+              y2="1605.7488"
+            >
+              <stop offset="0" style="stop-color: #45efed" />
+              <stop offset="1" style="stop-color: #d0ffed; stop-opacity: 0" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              enable-background="new    "
+              fill="url(#SVGID_12_)"
+              fill-rule="evenodd"
+              opacity="0.3"
+              points="
+					0,130 48,130 48,196.7 24,210.6 0,196.7 				"
+            />
+
+            <linearGradient
+              id="鐭╁舰澶囦唤_1_"
+              gradientTransform="matrix(48 0 0 -80.5525 820 129428.7578)"
+              gradientUnits="userSpaceOnUse"
+              x1="-15.625"
+              x2="-15.625"
+              y1="1604.7488"
+              y2="1605.7488"
+            >
+              <stop offset="0" style="stop-color: #45efed" />
+              <stop offset="1" style="stop-color: #d0ffed; stop-opacity: 0" />
+            </linearGradient>
+
+            <polygon
+              id="鐭╁舰澶囦唤"
+              clip-rule="evenodd"
+              enable-background="new    "
+              fill="url(#鐭╁舰澶囦唤_1_)"
+              fill-rule="evenodd"
+              opacity="0.3"
+              points="
+					46,81.7 94,81.7 94,148.5 70,162.3 46,148.5 				"
+            />
+
+            <linearGradient
+              id="鐭╁舰澶囦唤-4_1_"
+              gradientTransform="matrix(48 0 0 -80.5525 863 129347.75)"
+              gradientUnits="userSpaceOnUse"
+              x1="-15.625"
+              x2="-15.625"
+              y1="1604.7488"
+              y2="1605.7488"
+            >
+              <stop offset="0" style="stop-color: #45efed" />
+              <stop offset="1" style="stop-color: #d0ffed; stop-opacity: 0" />
+            </linearGradient>
+
+            <polygon
+              id="鐭╁舰澶囦唤-4"
+              clip-rule="evenodd"
+              enable-background="new    "
+              fill="url(#鐭╁舰澶囦唤-4_1_)"
+              fill-rule="evenodd"
+              opacity="0.3"
+              points="
+					89,0.7 137,0.7 137,67.5 113,81.3 89,67.5 				"
+            />
+
+            <linearGradient
+              id="SVGID_13_"
+              gradientTransform="matrix(23.7991 0 0 -93.207 435.2595 150023.5938)"
+              gradientUnits="userSpaceOnUse"
+              x1="-17.8122"
+              x2="-17.7572"
+              y1="1607.5193"
+              y2="1606.3573"
+            >
+              <stop offset="0" style="stop-color: #68dfff" />
+              <stop offset="1" style="stop-color: #004a8b" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_13_)"
+              fill-rule="evenodd"
+              points="23.9,290 23.9,210.6 0.1,196.8 0.1,276.3
+					"
+            />
+
+            <linearGradient
+              id="SVGID_14_"
+              gradientTransform="matrix(23.7991 0 0 -93.207 459.1122 150023.5938)"
+              gradientUnits="userSpaceOnUse"
+              x1="-17.8038"
+              x2="-17.7678"
+              y1="1607.3881"
+              y2="1606.5361"
+            >
+              <stop offset="0" style="stop-color: #0567de" />
+              <stop offset="1" style="stop-color: #00048b" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_14_)"
+              fill-rule="evenodd"
+              points="23.9,290 23.9,210.6 47.7,196.8 47.7,276.3
+									"
+            />
+          </g>
+        </g>
+      </g>
+      <g id="缂栫粍-9" transform="translate(286.000000, 26.000000)">
+        <g id="缂栫粍-3" transform="translate(0.000000, 326.797996)">
+          <g id="妞渾褰�" filter="url(#filter-39)">
+            <linearGradient
+              id="SVGID_15_"
+              gradientTransform="matrix(298.9761 -31.4237 -16.5194 -157.172 79324.2969 223473.4688)"
+              gradientUnits="userSpaceOnUse"
+              x1="-183.6863"
+              x2="-184.3618"
+              y1="1458.1069"
+              y2="1457.9841"
+            >
+              <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M161.7,23.6c82.6-8.7,153.2,19.5,157.7,62.9
+					c4.6,43.4-58.7,85.6-141.2,94.3C95.7,189.5,25,161.3,20.5,117.9S79.1,32.3,161.7,23.6z"
+              fill="url(#SVGID_15_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g transform="translate(0.000000, 32.309947)">
+            <g id="褰㈢姸缁撳悎">
+              <linearGradient
+                id="SVGID_16_"
+                gradientTransform="matrix(252.8605 0 0 -153.121 46628.3242 218334.6719)"
+                gradientUnits="userSpaceOnUse"
+                x1="-184.3435"
+                x2="-183.4387"
+                y1="1425.4349"
+                y2="1425.3547"
+              >
+                <stop offset="0" style="stop-color: #3b76df" />
+                <stop offset="1" style="stop-color: #0c2ea7" />
+              </linearGradient>
+              <path
+                clip-rule="evenodd"
+                d="M36.9,21.3c49.2-28.4,129.8-28.4,179,0
+						c9.7,5.6,17.5,12.2,23.4,19.4l13.5,0v39.3l-0.1,0c-1.3,19.3-13.6,38.3-36.8,51.7c-49.2,28.4-129.8,28.4-179,0
+						C13.7,118.4,1.4,99.4,0.1,80.1l-0.1,0V40.7l13.5,0C19.4,33.5,27.2,26.9,36.9,21.3z"
+                fill="url(#SVGID_16_)"
+                fill-rule="evenodd"
+              />
+            </g>
+            <defs>
+              <filter
+                id="Adobe_OpacityMaskFilter"
+                filterUnits="userSpaceOnUse"
+                height="86.4"
+                width="22.5"
+                x="18.3"
+                y="59.7"
+              >
+                <feColorMatrix
+                  type="matrix"
+                  values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                />
+              </filter>
+            </defs>
+            <mask
+              id="mask-42_1_"
+              height="86.4"
+              maskUnits="userSpaceOnUse"
+              width="22.5"
+              x="18.3"
+              y="59.7"
+            >
+              <g filter="url(#Adobe_OpacityMaskFilter)">
+                <path
+                  id="path-41_1_"
+                  clip-rule="evenodd"
+                  d="M36.9,21.3c49.2-28.4,129.8-28.4,179,0
+							c9.7,5.6,17.5,12.2,23.4,19.4l13.5,0v39.3l-0.1,0c-1.3,19.3-13.6,38.3-36.8,51.7c-49.2,28.4-129.8,28.4-179,0
+							C13.7,118.4,1.4,99.4,0.1,80.1l-0.1,0V40.7l13.5,0C19.4,33.5,27.2,26.9,36.9,21.3z"
+                  fill="#FFFFFF"
+                  fill-rule="evenodd"
+                />
+              </g>
+            </mask>
+            <g filter="url(#filter-43)" mask="url(#mask-42_1_)">
+              <rect
+                clip-rule="evenodd"
+                fill="#FFFFFF"
+                fill-rule="evenodd"
+                height="86.4"
+                width="22.5"
+                x="18.3"
+                y="59.7"
+              />
+            </g>
+          </g>
+          <g id="Stroke-1澶囦唤">
+            <g>
+              <linearGradient
+                id="path-45_1_"
+                gradientTransform="matrix(252.8604 0 0 -146.0971 46628.3203 212993.0469)"
+                gradientUnits="userSpaceOnUse"
+                x1="-183.7127"
+                x2="-184.1537"
+                y1="1457.2306"
+                y2="1457.5913"
+              >
+                <stop offset="0" style="stop-color: #4587ef" />
+                <stop offset="1" style="stop-color: #00209e" />
+              </linearGradient>
+              <path
+                id="path-45"
+                clip-rule="evenodd"
+                d="M36.9,21.3c-49.2,28.4-49.2,75,0,103.4
+						c49.2,28.4,129.8,28.4,179,0c49.2-28.4,49.2-75,0-103.4C166.7-7.1,86.2-7.1,36.9,21.3z"
+                fill="url(#path-45_1_)"
+                fill-rule="evenodd"
+              />
+            </g>
+            <g filter="url(#filter-46)">
+              <path
+                clip-rule="evenodd"
+                d="M36.9,21.3c-49.2,28.4-49.2,75,0,103.4c49.2,28.4,129.8,28.4,179,0
+						c49.2-28.4,49.2-75,0-103.4C166.7-7.1,86.2-7.1,36.9,21.3z"
+                fill-rule="evenodd"
+              />
+            </g>
+          </g>
+        </g>
+        <g id="缂栫粍-3澶囦唤" transform="translate(24.286045, 0.000000)">
+          <g transform="translate(1.000000, 323.847957)">
+            <g>
+              <linearGradient
+                id="SVGID_17_"
+                gradientTransform="matrix(202.2884 0 0 -122.4968 42438.1328 178783.5781)"
+                gradientUnits="userSpaceOnUse"
+                x1="-209.8152"
+                x2="-208.7883"
+                y1="1459.0104"
+                y2="1458.9812"
+              >
+                <stop offset="0" style="stop-color: #8dcbff" />
+                <stop offset="0.1196" style="stop-color: #cafbff" />
+                <stop offset="0.768" style="stop-color: #7feeff" />
+                <stop offset="1" style="stop-color: #adcbff" />
+              </linearGradient>
+              <path
+                clip-rule="evenodd"
+                d="M29.5,17.1c39.4-22.8,103.8-22.8,143.2,0
+						c7.8,4.5,14,9.8,18.7,15.5l10.8,0v31.5l-0.1,0c-1.1,15.5-10.9,30.6-29.4,41.4c-39.4,22.8-103.8,22.8-143.2,0
+						C11,94.7,1.2,79.5,0.1,64.1l-0.1,0V32.6l10.8,0C15.5,26.8,21.8,21.6,29.5,17.1z"
+                fill="url(#SVGID_17_)"
+                fill-rule="evenodd"
+              />
+            </g>
+            <defs>
+              <filter
+                id="Adobe_OpacityMaskFilter_1_"
+                filterUnits="userSpaceOnUse"
+                height="69.1"
+                width="18"
+                x="14.6"
+                y="47.8"
+              >
+                <feColorMatrix
+                  type="matrix"
+                  values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                />
+              </filter>
+            </defs>
+            <mask
+              id="mask-49_1_"
+              height="69.1"
+              maskUnits="userSpaceOnUse"
+              width="18"
+              x="14.6"
+              y="47.8"
+            >
+              <g filter="url(#Adobe_OpacityMaskFilter_1_)">
+                <path
+                  id="path-48_1_"
+                  clip-rule="evenodd"
+                  d="M29.5,17.1c39.4-22.8,103.8-22.8,143.2,0
+							c7.8,4.5,14,9.8,18.7,15.5l10.8,0v31.5l-0.1,0c-1.1,15.5-10.9,30.6-29.4,41.4c-39.4,22.8-103.8,22.8-143.2,0
+							C11,94.7,1.2,79.5,0.1,64.1l-0.1,0V32.6l10.8,0C15.5,26.8,21.8,21.6,29.5,17.1z"
+                  fill="#FFFFFF"
+                  fill-rule="evenodd"
+                />
+              </g>
+            </mask>
+            <g filter="url(#filter-50)" mask="url(#mask-49_1_)">
+              <rect
+                clip-rule="evenodd"
+                fill="#FFFFFF"
+                fill-rule="evenodd"
+                height="69.1"
+                width="18"
+                x="14.6"
+                y="47.8"
+              />
+            </g>
+          </g>
+          <g>
+            <g>
+              <linearGradient
+                id="path-52_1_"
+                gradientTransform="matrix(202.2884 0 0 -116.8777 42236.8438 208684.4531)"
+                gradientUnits="userSpaceOnUse"
+                x1="-208.0996"
+                x2="-208.5406"
+                y1="1782.2883"
+                y2="1782.6489"
+              >
+                <stop offset="0" style="stop-color: #4587ef" />
+                <stop offset="1" style="stop-color: #00209e" />
+              </linearGradient>
+              <path
+                id="path-52"
+                clip-rule="evenodd"
+                d="M30.5,315.1c-39.4,22.8-39.4,60,0,82.7
+						c39.4,22.8,103.8,22.8,143.2,0c39.4-22.8,39.4-60,0-82.7C134.4,292.3,69.9,292.3,30.5,315.1z"
+                fill="url(#path-52_1_)"
+                fill-rule="evenodd"
+              />
+            </g>
+            <g filter="url(#filter-53)">
+              <path
+                clip-rule="evenodd"
+                d="M30.5,315.1c-39.4,22.8-39.4,60,0,82.7c39.4,22.8,103.8,22.8,143.2,0
+						c39.4-22.8,39.4-60,0-82.7C134.4,292.3,69.9,292.3,30.5,315.1z"
+                fill-rule="evenodd"
+              />
+            </g>
+          </g>
+
+          <linearGradient
+            id="SVGID_18_"
+            gradientTransform="matrix(202.5744 0 0 -414.8777 42296.1367 742296.8125)"
+            gradientUnits="userSpaceOnUse"
+            x1="-208.2896"
+            x2="-208.2896"
+            y1="1788.1943"
+            y2="1789.1943"
+          >
+            <stop offset="0" style="stop-color: #45efed" />
+            <stop offset="1" style="stop-color: #d0ffed; stop-opacity: 0" />
+          </linearGradient>
+          <path
+            clip-rule="evenodd"
+            d="M202.7,0
+				l0,350.2c3.1,17-6.5,34.7-29,47.6c-39.4,22.8-103.8,22.8-143.2,0C12,387.1,2.2,373.1,1.1,359l-0.4,0V0H202.7z"
+            enable-background="new    "
+            fill="url(#SVGID_18_)"
+            fill-rule="evenodd"
+            opacity="0.3"
+          />
+        </g>
+      </g>
+      <g id="缂栫粍-11澶囦唤" transform="translate(329.000000, 539.000000)">
+        <g id="缂栫粍-6澶囦唤" transform="translate(0.000000, 4.148936)">
+          <g filter="url(#filter-56)">
+            <linearGradient
+              id="SVGID_19_"
+              gradientTransform="matrix(52.2766 0 0 -21.5745 11984.5537 26508.6328)"
+              gradientUnits="userSpaceOnUse"
+              x1="-227.9383"
+              x2="-228.6138"
+              y1="1226.9152"
+              y2="1226.8395"
+            >
+              <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <ellipse
+              clip-rule="evenodd"
+              cx="41.9"
+              cy="39.8"
+              fill="url(#SVGID_19_)"
+              fill-rule="evenodd"
+              rx="26.1"
+              ry="10.8"
+            />
+          </g>
+
+          <radialGradient
+            id="SVGID_20_"
+            cx="-228.8779"
+            cy="1253.5115"
+            gradientTransform="matrix(48.9574 0 0 -48.9574 11215.3408 61379.1055)"
+            gradientUnits="userSpaceOnUse"
+            r="0.9018"
+          >
+            <stop offset="0" style="stop-color: #dedbff" />
+            <stop offset="0.3987" style="stop-color: #4165fc" />
+            <stop offset="1" style="stop-color: #0a00c2" />
+          </radialGradient>
+          <circle
+            clip-rule="evenodd"
+            cx="24.5"
+            cy="24.5"
+            fill="url(#SVGID_20_)"
+            fill-rule="evenodd"
+            r="24.5"
+          />
+        </g>
+        <g id="缂栫粍-6" transform="translate(23.510638, 0.000000)">
+          <g filter="url(#filter-59)">
+            <linearGradient
+              id="SVGID_21_"
+              gradientTransform="matrix(87.1277 0 0 -35.9574 21954.6836 45008.2383)"
+              gradientUnits="userSpaceOnUse"
+              x1="-250.6685"
+              x2="-251.344"
+              y1="1249.9197"
+              y2="1249.844"
+            >
+              <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <ellipse
+              clip-rule="evenodd"
+              cx="69.8"
+              cy="66.4"
+              fill="url(#SVGID_21_)"
+              fill-rule="evenodd"
+              rx="43.6"
+              ry="18"
+            />
+          </g>
+
+          <radialGradient
+            id="SVGID_22_"
+            cx="-251.5552"
+            cy="1265.9697"
+            gradientTransform="matrix(81.5957 0 0 -81.5957 20542.6016 103315.0391)"
+            gradientUnits="userSpaceOnUse"
+            r="0.9018"
+          >
+            <stop offset="0" style="stop-color: #dedbff" />
+            <stop offset="0.3987" style="stop-color: #4165fc" />
+            <stop offset="1" style="stop-color: #0a00c2" />
+          </radialGradient>
+          <circle
+            clip-rule="evenodd"
+            cx="40.8"
+            cy="40.8"
+            fill="url(#SVGID_22_)"
+            fill-rule="evenodd"
+            r="40.8"
+          />
+        </g>
+      </g>
+
+      <g
+        id="缂栫粍澶囦唤-9"
+        opacity="0.5"
+        transform="translate(488.000000, 172.000000) scale(-1, 1) translate(-488.000000, -172.000000) translate(449.000000, 122.000000)"
+      >
+        <linearGradient
+          id="SVGID_23_"
+          gradientTransform="matrix(-75.8604 0 0 -99.5101 32139.0957 167716.875)"
+          gradientUnits="userSpaceOnUse"
+          x1="423.6246"
+          x2="424.2521"
+          y1="1683.8809"
+          y2="1685.3489"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #00c6fb" />
+        </linearGradient>
+        <path
+          d="M72.5,0l3.8,2.1L75.1,4l-1.6,0.6l-0.7,49.2c0,1.6-0.9,3.4-2.1,4.2l-0.2,0.1L5.7,95.5l0,0l-0.7,4
+			l-3.7-2.1c-0.1,0-0.1-0.1-0.2-0.1l0,0c-0.4-0.3-0.7-0.9-0.7-1.8l0,0l0.8-51.8c0-1.7,1-3.6,2.3-4.3l0,0L71.2,0.3
+			C71.7,0,72.1-0.1,72.5,0L72.5,0z"
+          fill="url(#SVGID_23_)"
+        />
+
+        <linearGradient
+          id="SVGID_24_"
+          gradientTransform="matrix(-73.087 0 0 -97.5101 30963.9746 164327.5781)"
+          gradientUnits="userSpaceOnUse"
+          x1="423.5395"
+          x2="424.1461"
+          y1="1683.6631"
+          y2="1685.1311"
+        >
+          <stop offset="0" style="stop-color: #005bea" />
+          <stop offset="1" style="stop-color: #00c6fb" />
+        </linearGradient>
+        <path
+          d="M6.3,99.2l67.8-39.1c1.2-0.7,2.3-2.7,2.3-4.3L77.1,4c0-1.7-1-2.4-2.3-1.7L7,41.4
+			c-1.2,0.7-2.3,2.7-2.3,4.3L4,97.5C4,99.2,5,100,6.3,99.2z"
+          fill="url(#SVGID_24_)"
+        />
+        <g
+          id="XMLID_902_"
+          opacity="0.3"
+          transform="translate(51.463000, 21.500000)"
+        >
+          <path
+            id="XMLID_905_"
+            d="M17.9,4.7L1.7,14.1c-0.5,0.3-1.2,0.1-1.5-0.4C0.1,13.5,0,13.3,0,13.1
+				c0-1.2,0.6-2.2,1.6-2.8l16.3-9.4c0.5-0.3,1.2-0.1,1.5,0.4c0.1,0.2,0.1,0.4,0.1,0.5C19.5,3,18.9,4.1,17.9,4.7z"
+            fill="#FFFFFF"
+          />
+          <path
+            id="XMLID_905_澶囦唤"
+            d="M18.2,14.6L5.5,21.9c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4
+				c0-0.9,0.5-1.7,1.3-2.2l12.6-7.3c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,13.3,18.9,14.2,18.2,14.6z"
+            fill="#FFFFFF"
+          />
+          <path
+            id="XMLID_905_澶囦唤-2"
+            d="M18.2,22.3L5.5,29.6c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4
+				c0-0.9,0.5-1.7,1.3-2.2l12.6-7.3c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,21,18.9,21.8,18.2,22.3z"
+            fill="#FFFFFF"
+          />
+          <path
+            id="XMLID_905_澶囦唤-3"
+            d="M18.2,29.9L5.5,37.2c-0.4,0.2-0.9,0.1-1.1-0.3c-0.1-0.1-0.1-0.3-0.1-0.4
+				c0-0.9,0.5-1.7,1.3-2.2L18.2,27c0.4-0.2,0.9-0.1,1.1,0.3c0.1,0.1,0.1,0.3,0.1,0.4C19.4,28.7,18.9,29.5,18.2,29.9z"
+            fill="#FFFFFF"
+          />
+        </g>
+
+        <linearGradient
+          id="SVGID_25_"
+          gradientTransform="matrix(-43.8881 0 0 -83.0886 18579.1777 139875)"
+          gradientUnits="userSpaceOnUse"
+          x1="422.0028"
+          x2="421.7111"
+          y1="1683.5527"
+          y2="1682.4626"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+        <polygon
+          enable-background="new    "
+          fill="url(#SVGID_25_)"
+          opacity="0.4"
+          points="50,16.6 28.7,86.3 51,73.4 72.6,3.2 		"
+        />
+
+        <linearGradient
+          id="XMLID_22_"
+          gradientTransform="matrix(-6.6055 0 0 -25.864 2720.3372 42898.332)"
+          gradientUnits="userSpaceOnUse"
+          x1="408.911"
+          x2="408.7796"
+          y1="1654.5455"
+          y2="1655.6864"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="XMLID_23_"
+          gradientTransform="matrix(-6.6055 0 0 -25.864 2720.3372 42898.332)"
+          gradientUnits="userSpaceOnUse"
+          x1="409.0583"
+          x2="409.0583"
+          y1="1656.3246"
+          y2="1655.3246"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+        <polygon
+          id="XMLID_875_"
+          fill="url(#XMLID_22_)"
+          points="21.6,81.2 15,85 15,63
+			21.6,59.2 		"
+          stroke="url(#XMLID_23_)"
+          stroke-width="0.5"
+        />
+
+        <linearGradient
+          id="XMLID_24_"
+          gradientTransform="matrix(-6.6055 0 0 -32.7555 2732.1479 54570.1641)"
+          gradientUnits="userSpaceOnUse"
+          x1="409.0159"
+          x2="408.9963"
+          y1="1663.0452"
+          y2="1663.531"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="XMLID_25_"
+          gradientTransform="matrix(-6.6055 0 0 -32.7555 2732.1479 54570.1641)"
+          gradientUnits="userSpaceOnUse"
+          x1="409.0583"
+          x2="409.0583"
+          y1="1664.5974"
+          y2="1663.5974"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+        <polygon
+          id="XMLID_874_"
+          fill="url(#XMLID_24_)"
+          points="33.4,74.4 26.8,78.2
+			26.8,49.3 33.4,45.4 		"
+          stroke="url(#XMLID_25_)"
+          stroke-width="0.5"
+        />
+
+        <linearGradient
+          id="XMLID_26_"
+          gradientTransform="matrix(-6.6055 0 0 -39.6465 2744.3577 66240.9141)"
+          gradientUnits="userSpaceOnUse"
+          x1="408.98"
+          x2="408.9241"
+          y1="1668.4514"
+          y2="1669.1958"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="XMLID_27_"
+          gradientTransform="matrix(-6.6055 0 0 -39.6465 2744.3577 66240.9141)"
+          gradientUnits="userSpaceOnUse"
+          x1="409.0583"
+          x2="409.0583"
+          y1="1669.994"
+          y2="1668.994"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+        <polygon
+          id="XMLID_873_"
+          fill="url(#XMLID_26_)"
+          points="45.6,67.3 39,71.1 39,35.3
+			45.6,31.5 		"
+          stroke="url(#XMLID_27_)"
+          stroke-width="0.5"
+        />
+      </g>
+      <g id="浜哄浠�" transform="translate(364.000000, 134.000000)">
+        <path
+          id="Path"
+          clip-rule="evenodd"
+          d="M78,41.6c0,0,6.5-5.1,7.6-5.4c7.2-2.4,8-1,9.4,0.7
+			c1.4,1.6-4,4.2-5.4,5.7c-0.7,0.8,4.5-1,3.9,1c-0.5,1.5-4.9,2.2-5.6,2.9s-5.3,3.8-5.3,3.8L78,41.6z"
+          fill="#F7C19C"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="SVGID_26_"
+          gradientTransform="matrix(66.553 0 0 -42.1921 17559.9336 70059.375)"
+          gradientUnits="userSpaceOnUse"
+          x1="-263.0341"
+          x2="-263.2938"
+          y1="1659.3563"
+          y2="1659.0363"
+        >
+          <stop offset="0" style="stop-color: #3158d3" />
+          <stop offset="1" style="stop-color: #306ef3" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M53,81.7c5.3-2,34.6-33.6,34.6-33.6
+			c-3.3-7.5-9.4-7.6-9.4-7.6L50.5,61.6c0,0-24.3-19.7-28.7-21.7s12.7,33,12.7,33S47.8,83.7,53,81.7z"
+          fill="url(#SVGID_26_)"
+          fill-rule="evenodd"
+        />
+        <g
+          id="Oval"
+          enable-background="new    "
+          filter="url(#filter-71)"
+          opacity="0.5267"
+        >
+          <linearGradient
+            id="SVGID_27_"
+            gradientTransform="matrix(125.5104 0 0 -59.4816 33000.125 99355.7422)"
+            gradientUnits="userSpaceOnUse"
+            x1="-261.8036"
+            x2="-262.479"
+            y1="1666.1232"
+            y2="1666.0233"
+          >
+            <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <ellipse
+            clip-rule="evenodd"
+            cx="77.2"
+            cy="256.5"
+            fill="url(#SVGID_27_)"
+            fill-rule="evenodd"
+            rx="62.8"
+            ry="29.7"
+          />
+        </g>
+
+        <linearGradient
+          id="SVGID_28_"
+          gradientTransform="matrix(37.5807 0 0 -16.9728 9948.6885 27801.6328)"
+          gradientUnits="userSpaceOnUse"
+          x1="-264.5023"
+          x2="-262.5973"
+          y1="1623.2751"
+          y2="1622.7434"
+        >
+          <stop offset="0" style="stop-color: #434343" />
+          <stop offset="1" style="stop-color: #122142" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M6.3,242.5c-1.9,1.4-7.6,6.1-5.2,12.6
+			c2.4,6.5,8.7,4.1,12.8,2.9c4.1-1.2,9.3-4.2,15.3-5.1c6-0.9,12.9-5.5,5.8-8.6C30.3,242.2,6.3,242.5,6.3,242.5z"
+          fill="url(#SVGID_28_)"
+          fill-rule="evenodd"
+        />
+        <path
+          clip-rule="evenodd"
+          d="M51.7,252.1l-2.2,9.5c0,0-5.1,0.3-8.5-1.4
+			c-1.1-0.5-2-1.3-2.5-2.3l2.8-13.2l10.3-65.3l-9.3-33.8L16.9,246.6c0,0-3.1,1.6-6.5,0.4c-0.7-0.3-3.6-2-4.1-2.9l29.2-106.8l20,4.8
+			l8.5,45L51.7,252.1z"
+          fill="#EFAD81"
+          fill-rule="evenodd"
+        />
+        <path
+          clip-rule="evenodd"
+          d="M34.8,39.4l1.4-8.4c0,0-2-21.1,3.8-23.2s18.3-0.3,18.4,10
+			c0.1,10.4-0.1,19.3-4.6,19.1c-4.5-0.2-5.3-1-5.3-1l0.1,8.1L34.8,39.4z"
+          fill="#F7C19C"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="SVGID_29_"
+          gradientTransform="matrix(65.856 0 0 -139.1891 17361.0918 233445.5938)"
+          gradientUnits="userSpaceOnUse"
+          x1="-263.1151"
+          x2="-263.0032"
+          y1="1676.3293"
+          y2="1675.5613"
+        >
+          <stop offset="0" style="stop-color: #021814" />
+          <stop offset="1" style="stop-color: #424fec" />
+        </linearGradient>
+        <path
+          d="M17.5,117.5l1.9,57.1L4.8,238c0,0,3.3,5.5,18.1,4.1c0,0,16.4-56.8,18-59.2
+			c1.6-2.4,4.4-21.7,4.4-21.7s2.5,29.8,1.7,32.9c-0.8,3.2-8.4,56.9-8.4,56.9s3.1,7.4,17,5.2c0,0,15-62,15-67.8v-62.1L17.5,117.5z"
+          fill="url(#SVGID_29_)"
+        />
+
+        <linearGradient
+          id="SVGID_30_"
+          gradientTransform="matrix(38.3908 0 0 -17.2271 10193.9805 28243.3203)"
+          gradientUnits="userSpaceOnUse"
+          x1="-264.4597"
+          x2="-262.5546"
+          y1="1624.1052"
+          y2="1623.5803"
+        >
+          <stop offset="0" style="stop-color: #434343" />
+          <stop offset="1" style="stop-color: #122142" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M50.9,258.4c0,0-2.9,1.7-6.7,0.7c-3.8-1-4.4-3-5.6-3.1
+			c-1.2-0.1-5,6.2-5,11.4c0,3.4,4.2,6.7,13.4,5.6c10.7-1.3,9.7,1,19-1c9.3-1.9,6.1-7.6,0.7-8.2c-5.4-0.6-10.7-1.5-12.7-3
+			C52.1,259.4,50.9,258.4,50.9,258.4z"
+          fill="url(#SVGID_30_)"
+          fill-rule="evenodd"
+        />
+        <path
+          clip-rule="evenodd"
+          d="M129.6,67.3c-0.6,0.2-1.7,0.5-2.9,0.8c-0.6-0.4-1.4-2.4-2-2.7
+			c-1.2-0.5-3.1,3.8-3.9,4.9l-4.9,2.6l-0.9,9.2c2.5,0.1,5-1.1,7.5-1.4c1.4-0.3,13.7-6.6,15.5-10.8C139,67.4,133.6,65.7,129.6,67.3z"
+          fill="#F7C19C"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="SVGID_31_"
+          gradientTransform="matrix(107.5405 0 0 -93.2162 28291.4941 155960.2031)"
+          gradientUnits="userSpaceOnUse"
+          x1="-261.9086"
+          x2="-262.8504"
+          y1="1672.3391"
+          y2="1672.2106"
+        >
+          <stop offset="0" style="stop-color: #77f7e1" />
+          <stop offset="1" style="stop-color: #424fec" />
+        </linearGradient>
+        <path
+          d="M76.5,100.3c5.7,0.2,44.9-17.6,44.9-17.6c-0.2-8.2-5.8-10.7-5.8-10.7l-33.7,8.6
+			c0,0-14.7-27.5-18-31.1C60.7,46,49.1,40,49.1,40S39,43.3,34.6,35c0,0-3.2-0.8-8.7-0.8S12.3,46,14.1,69.2s2,53,2,53
+			s16.7,7.8,54.5,4.2l-7.9-41.5C62.8,84.9,70.9,100.2,76.5,100.3z"
+          fill="url(#SVGID_31_)"
+        />
+
+        <linearGradient
+          id="SVGID_32_"
+          gradientTransform="matrix(33.4128 0 0 -34.3382 8885.7266 56796.8203)"
+          gradientUnits="userSpaceOnUse"
+          x1="-264.4242"
+          x2="-265.0254"
+          y1="1653.8715"
+          y2="1653.0199"
+        >
+          <stop offset="0" style="stop-color: #253c6f" />
+          <stop offset="1" style="stop-color: #3068e8" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M53,18.9c0,0,10.3,1.5,10-5.4c-0.2-6.9-4.7-3.6-5.9-9.4
+			c-1.4-7-11-2.3-22.3,0c-14.1,2.8,4.7,43.2,4.6,26.7s1.7-4.4,7.1-5.3c0.8-0.6-1.1-2.6,0-3.9C48.3,19.9,53,18.9,53,18.9z"
+          fill="url(#SVGID_32_)"
+          fill-rule="evenodd"
+        />
+      </g>
+      <g id="Stroke-1澶囦唤-3" opacity="0.2645">
+        <g filter="url(#filter-79)">
+          <path
+            id="path-78_1_"
+            clip-rule="evenodd"
+            d="M322.9,141.3c-49.2,28.4-49.2,75,0,103.4
+				c49.2,28.4,129.8,28.4,179,0c49.2-28.4,49.2-75,0-103.4C452.7,112.9,372.2,112.9,322.9,141.3z"
+            fill-rule="evenodd"
+          />
+        </g>
+        <g>
+          <linearGradient
+            id="SVGID_33_"
+            gradientTransform="matrix(252.8604 0 0 -146.0971 -25403.7617 264655.8438)"
+            gradientUnits="userSpaceOnUse"
+            x1="102.0966"
+            x2="102.0966"
+            y1="1810.3647"
+            y2="1809.6846"
+          >
+            <stop offset="0" style="stop-color: #fff; stop-opacity: 0" />
+            <stop offset="1" style="stop-color: #fff" />
+          </linearGradient>
+          <path
+            d="M322.9,141.3c-49.2,28.4-49.2,75,0,103.4c49.2,28.4,129.8,28.4,179,0
+				c49.2-28.4,49.2-75,0-103.4C452.7,112.9,372.2,112.9,322.9,141.3z"
+            fill="none"
+            stroke="url(#SVGID_33_)"
+          />
+        </g>
+      </g>
+
+      <linearGradient
+        id="Stroke-1澶囦唤-4_1_"
+        gradientTransform="matrix(224 0 0 -130 -22445.5664 235373.9844)"
+        gradientUnits="userSpaceOnUse"
+        x1="102.0446"
+        x2="102.0446"
+        y1="1809.8226"
+        y2="1809.215"
+      >
+        <stop offset="0" style="stop-color: #fff" />
+        <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+      </linearGradient>
+      <path
+        id="Stroke-1澶囦唤-4"
+        d="
+		M333.1,116c-43.6,25.3-43.6,66.7,0,92c43.6,25.3,115,25.3,158.6,0c43.6-25.3,43.6-66.7,0-92C448.1,90.7,376.8,90.7,333.1,116z"
+        enable-background="new    "
+        fill="none"
+        opacity="0.2645"
+        stroke="url(#Stroke-1澶囦唤-4_1_)"
+      />
+
+      <linearGradient
+        id="Stroke-1澶囦唤-5_1_"
+        gradientTransform="matrix(224 0 0 -130 -22445.5664 235434.9375)"
+        gradientUnits="userSpaceOnUse"
+        x1="102.0446"
+        x2="102.0446"
+        y1="1809.8226"
+        y2="1809.215"
+      >
+        <stop offset="0" style="stop-color: #fff" />
+        <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+      </linearGradient>
+
+      <path
+        id="Stroke-1澶囦唤-5"
+        d="
+		M333.1,177c-43.6,25.3-43.6,66.7,0,92c43.6,25.3,115,25.3,158.6,0c43.6-25.3,43.6-66.7,0-92C448.1,151.7,376.8,151.7,333.1,177z"
+        enable-background="new    "
+        fill="none"
+        opacity="7.956659e-02"
+        stroke="url(#Stroke-1澶囦唤-5_1_)"
+      />
+      <g id="缂栫粍-15" transform="translate(286.000000, 69.000000)">
+        <linearGradient
+          id="SVGID_34_"
+          gradientTransform="matrix(84.647 0 0 -130.0737 15677.0488 226435.8125)"
+          gradientUnits="userSpaceOnUse"
+          x1="-184.6048"
+          x2="-184.7916"
+          y1="1739.7522"
+          y2="1740.8326"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M84.6,54
+			v71.1c0,3.8-2.9,5.8-6.4,4.6c-14-5-27.2-11.1-39.4-18.1C25.4,103.8,14,95.3,4.7,86.3C2.1,83.6,0,78.4,0,74.6V3.5
+			c0-3.8,2.1-4.6,4.7-1.9c9.3,9,20.6,17.6,34.1,25.3C51,33.9,64.2,39.9,78.2,45C81.8,46.2,84.6,50.2,84.6,54z"
+          enable-background="new    "
+          fill="url(#SVGID_34_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_35_"
+          gradientTransform="matrix(42.8864 0 0 -55.1569 8005.1216 95474.0859)"
+          gradientUnits="userSpaceOnUse"
+          x1="-186.8636"
+          x2="-185.8636"
+          y1="1729.7074"
+          y2="1729.7074"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          d="M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37
+			c0,13.6-9.7,19.1-21.5,12.3C21.6,86.6,12,70,12,56.4C12.1,42.8,21.7,37.3,33.5,44.1z M33.4,85.5c8,4.6,14.6,0.9,14.6-8.3
+			c0-9.2-6.5-20.5-14.5-25.1c-8-4.6-14.6-0.9-14.6,8.3C18.9,69.6,25.4,80.9,33.4,85.5L33.4,85.5z"
+          enable-background="new    "
+          fill="url(#SVGID_35_)"
+          opacity="0.4"
+        />
+
+        <linearGradient
+          id="SVGID_36_"
+          gradientTransform="matrix(21.3932 0 0 -37.017 4071.8147 63756.6836)"
+          gradientUnits="userSpaceOnUse"
+          x1="-189.5823"
+          x2="-188.5823"
+          y1="1720.6718"
+          y2="1720.6718"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37l-6.9-4
+			c0-9.2-6.5-20.5-14.5-25.1L33.5,44.1z"
+          fill="url(#SVGID_36_)"
+          fill-rule="evenodd"
+        />
+      </g>
+
+      <g
+        id="缂栫粍-15澶囦唤"
+        transform="translate(524.500000, 179.500000) scale(-1, 1) translate(-524.500000, -179.500000) translate(482.000000, 114.000000)"
+      >
+        <linearGradient
+          id="SVGID_37_"
+          gradientTransform="matrix(-84.647 0 0 -130.0737 39258.8555 220582.5)"
+          gradientUnits="userSpaceOnUse"
+          x1="463.1948"
+          x2="463.008"
+          y1="1694.7522"
+          y2="1695.8326"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M84.6,54
+			v71.1c0,3.8-2.9,5.8-6.4,4.6c-14-5-27.2-11.1-39.4-18.1C25.4,103.8,14,95.3,4.7,86.3C2.1,83.6,0,78.4,0,74.6V3.5
+			c0-3.8,2.1-4.6,4.7-1.9c9.3,9,20.6,17.6,34.1,25.3C51,33.9,64.2,39.9,78.2,45C81.8,46.2,84.6,50.2,84.6,54z"
+          enable-background="new    "
+          fill="url(#SVGID_37_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_38_"
+          gradientTransform="matrix(-42.8864 0 0 -55.1569 19852.209 92992.0234)"
+          gradientUnits="userSpaceOnUse"
+          x1="462.6216"
+          x2="463.1363"
+          y1="1684.7074"
+          y2="1684.7074"
+        >
+          <stop offset="0" style="stop-color: #ccff70" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          d="M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37
+			c0,13.6-9.7,19.1-21.5,12.3C21.6,86.6,12,70,12,56.4C12.1,42.8,21.7,37.3,33.5,44.1z M33.4,85.5c8,4.6,14.6,0.9,14.6-8.3
+			c0-9.2-6.5-20.5-14.5-25.1c-8-4.6-14.6-0.9-14.6,8.3C18.9,69.6,25.4,80.9,33.4,85.5L33.4,85.5z"
+          enable-background="new    "
+          fill="url(#SVGID_38_)"
+          opacity="0.4"
+        />
+
+        <linearGradient
+          id="SVGID_39_"
+          gradientTransform="matrix(-21.3932 0 0 -37.017 9879.3115 62090.918)"
+          gradientUnits="userSpaceOnUse"
+          x1="461.0466"
+          x2="462.0466"
+          y1="1675.6718"
+          y2="1675.6718"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afa91" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M33.5,44.1c11.8,6.8,21.4,23.4,21.4,37l-6.9-4
+			c0-9.2-6.5-20.5-14.5-25.1L33.5,44.1z"
+          fill="url(#SVGID_39_)"
+          fill-rule="evenodd"
+        />
+      </g>
+      <g id="缂栫粍" transform="translate(457.000000, 235.000000)">
+        <linearGradient
+          id="SVGID_40_"
+          gradientTransform="matrix(94.2244 0 0 -135.8154 33551.6523 213971.6875)"
+          gradientUnits="userSpaceOnUse"
+          x1="-355.4666"
+          x2="-355.6789"
+          y1="1574.0848"
+          y2="1575.1653"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M36.3,166.1
+			c-9.3,4.2-19.3,7.7-29.7,10.5c-3.6,1-6.6-1.4-6.6-5.1v-44.7c0-3.8,3-7.5,6.6-8.4C17,115.5,27,112,36.3,107.8
+			c4.8-2.2,9.5-4.6,13.9-7.2c28.4-16.5,43.1-38,44-59.6v54.4c0.8,23-13.8,46-44,63.6C45.8,161.5,41.1,163.9,36.3,166.1z"
+          enable-background="new    "
+          fill="url(#SVGID_40_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_41_"
+          gradientTransform="matrix(19.3679 0 0 -68.3208 7052.4458 107110.6953)"
+          gradientUnits="userSpaceOnUse"
+          x1="-359.7519"
+          x2="-359.7874"
+          y1="1566.6797"
+          y2="1567.7601"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M79.4,59.9
+			c-2.4-2.9-4.6-8.1-4.6-11.8V3.5c0-3.8,2.2-4.6,4.6-1.8c17.4,20.9,19.5,45,6.1,66.6C83.7,65.5,81.7,62.7,79.4,59.9z"
+          enable-background="new    "
+          fill="url(#SVGID_41_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_42_"
+          gradientTransform="matrix(5.707 0 0 -15.38 2179.3494 23459.5469)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.3728"
+          x2="-372.3728"
+          y1="1517.4354"
+          y2="1516.2238"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <polygon
+          clip-rule="evenodd"
+          fill="url(#SVGID_42_)"
+          fill-rule="evenodd"
+          points="57.1,146.8 57,135.5 51.4,138.7 51.4,150.9
+			"
+        />
+
+        <linearGradient
+          id="Path澶囦唤_1_"
+          gradientTransform="matrix(5.707 0 0 -15.38 2199.9822 23445.7344)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.3728"
+          x2="-372.3728"
+          y1="1517.4354"
+          y2="1516.2238"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <polygon
+          id="Path澶囦唤"
+          clip-rule="evenodd"
+          fill="url(#Path澶囦唤_1_)"
+          fill-rule="evenodd"
+          points="77.7,133 77.7,121.7
+			72,124.9 72,137 		"
+        />
+
+        <linearGradient
+          id="SVGID_43_"
+          gradientTransform="matrix(5.791 0 0 -44.69 2175.166 69834.2344)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.1319"
+          x2="-372.1109"
+          y1="1562.8905"
+          y2="1558.8889"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M23.2,165.4c-1.9,0.7-3.8,1.4-5.7,2.1l-0.1-42.8
+			c1.9-0.6,3.8-1.3,5.7-1.9L23.2,165.4z"
+          fill="url(#SVGID_43_)"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="SVGID_44_"
+          gradientTransform="matrix(5.754 0 0 -21.635 2173.4099 33364.9844)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.2268"
+          x2="-372.2268"
+          y1="1536.7212"
+          y2="1535.3361"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M34.5,160.5c-1,0.5-2,1-3.1,1.4
+			c-0.8,0.4-1.7,0.8-2.6,1.1L28.7,144c0,0,0.1,0,0.1,0c0.9-0.4,1.7-0.8,2.6-1.1c1-0.5,2-0.9,3-1.4L34.5,160.5z"
+          fill="url(#SVGID_44_)"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="SVGID_45_"
+          gradientTransform="matrix(5.78 0 0 -42.615 2194.2666 66542.2656)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.1471"
+          x2="-372.1471"
+          y1="1559.7903"
+          y2="1558.4763"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M46.1,154.2c-0.6,0.4-1.2,0.7-1.9,1.1
+			c-1.2,0.7-2.5,1.4-3.8,2.1l-0.1-39.3l5.7-3.3L46.1,154.2z"
+          fill="url(#SVGID_45_)"
+          fill-rule="evenodd"
+        />
+
+        <linearGradient
+          id="Path澶囦唤-2_1_"
+          gradientTransform="matrix(5.78 0 0 -28.2102 2214.8997 43745.1641)"
+          gradientUnits="userSpaceOnUse"
+          x1="-372.1471"
+          x2="-372.1471"
+          y1="1547.6044"
+          y2="1546.2904"
+        >
+          <stop offset="0" style="stop-color: #4c83ff" />
+          <stop offset="1" style="stop-color: #2afadf" />
+        </linearGradient>
+        <path
+          id="Path澶囦唤-2"
+          clip-rule="evenodd"
+          d="M66.8,140.4
+			c-0.6,0.4-1.2,0.7-1.9,1.1c-1.2,0.7-2.5,1.4-3.8,2.1L61,118.7l5.7-3.3L66.8,140.4z"
+          fill="url(#Path澶囦唤-2_1_)"
+          fill-rule="evenodd"
+        />
+      </g>
+
+      <g
+        id="缂栫粍澶囦唤"
+        transform="translate(316.500000, 268.500000) scale(-1, 1) translate(-316.500000, -268.500000) translate(269.000000, 180.000000)"
+      >
+        <linearGradient
+          id="SVGID_46_"
+          gradientTransform="matrix(-94.2244 0 0 -135.8154 24584.7852 221441.5469)"
+          gradientUnits="userSpaceOnUse"
+          x1="260.3016"
+          x2="260.0893"
+          y1="1629.0848"
+          y2="1630.1653"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M36.3,166.1
+			c-9.3,4.2-19.3,7.7-29.7,10.5c-3.6,1-6.6-1.4-6.6-5.1v-44.7c0-3.8,3-7.5,6.6-8.4C17,115.5,27,112,36.3,107.8
+			c4.8-2.2,9.5-4.6,13.9-7.2c28.4-16.5,43.1-38,44-59.6v54.4c0.8,23-13.8,46-44,63.6C45.8,161.5,41.1,163.9,36.3,166.1z"
+          enable-background="new    "
+          fill="url(#SVGID_46_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_47_"
+          gradientTransform="matrix(-19.3679 0 0 -68.3208 5047.2349 110868.3359)"
+          gradientUnits="userSpaceOnUse"
+          x1="256.219"
+          x2="256.1836"
+          y1="1621.6797"
+          y2="1622.7601"
+        >
+          <stop offset="0" style="stop-color: #4587ef" />
+          <stop offset="1" style="stop-color: #00209e" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M79.4,59.9
+			c-2.4-2.9-4.6-8.1-4.6-11.8V3.5c0-3.8,2.2-4.6,4.6-1.8c17.4,20.9,19.5,45,6.1,66.6C83.7,65.5,81.7,62.7,79.4,59.9z"
+          enable-background="new    "
+          fill="url(#SVGID_47_)"
+          fill-rule="evenodd"
+          opacity="0.5"
+        />
+
+        <linearGradient
+          id="璺緞_1_"
+          gradientTransform="matrix(-65.0245 0 0 -44.112 16953.9395 71322.6641)"
+          gradientUnits="userSpaceOnUse"
+          x1="259.3418"
+          x2="258.6121"
+          y1="1614.2808"
+          y2="1614.0671"
+        >
+          <stop offset="0" style="stop-color: #f8ff24" />
+          <stop offset="1" style="stop-color: #fff" />
+        </linearGradient>
+
+        <path
+          id="璺緞"
+          d="
+			M84.5,110.9c-11.6-15.5-17.4-14.7-17.4,2.4c0,25.7-11.4,29.9-19.6,17.1c-8.2-12.9-23.3-14.6-28,13.6"
+          enable-background="new    "
+          fill="none"
+          opacity="0.6"
+          stroke="url(#璺緞_1_)"
+          stroke-linecap="round"
+          stroke-width="3.5247"
+        />
+      </g>
+      <g id="缂栫粍-11" transform="translate(558.000000, 306.000000)">
+        <g id="product3" transform="translate(11.447727, 0.000000)">
+          <g filter="url(#filter-95)">
+            <linearGradient
+              id="SVGID_48_"
+              gradientTransform="matrix(174.1648 0 0 -101.4708 81515.7969 152491.3594)"
+              gradientUnits="userSpaceOnUse"
+              x1="-467.0351"
+              x2="-467.7105"
+              y1="1501.2344"
+              y2="1501.0835"
+            >
+              <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M171.8,157.9c4.3,2.5,4.3,6.5,0,8.9L81.2,220
+					c-4.8,2.5-10.6,2.5-15.4,0L4.1,184.4c-4.3-2.5-4.3-6.5,0-8.9l90.5-53.2c4.8-2.5,10.6-2.5,15.4,0L171.8,157.9z"
+              fill="url(#SVGID_48_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g id="缂栫粍-2" transform="translate(0.862170, 124.812382)">
+            <linearGradient
+              id="SVGID_49_"
+              gradientTransform="matrix(145.0025 0 0 -83.8574 68008.0859 115279.1875)"
+              gradientUnits="userSpaceOnUse"
+              x1="-469.0133"
+              x2="-468.0133"
+              y1="1374.2056"
+              y2="1374.2056"
+            >
+              <stop offset="0" style="stop-color: #6ecaf9" />
+              <stop offset="0.35" style="stop-color: #a1ddfb" />
+              <stop offset="1" style="stop-color: #fff" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M141.8,37.5c4.3,2.5,4.3,6.5,0,8.9L80.4,82
+					c-4.8,2.5-10.6,2.5-15.4,0L3.2,46.4c-4.3-2.5-4.3-6.5,0-8.9L64.6,1.8c4.8-2.5,10.6-2.5,15.4,0L141.8,37.5z"
+              fill="url(#SVGID_49_)"
+              fill-rule="evenodd"
+            />
+
+            <linearGradient
+              id="SVGID_50_"
+              gradientTransform="matrix(132.2205 0 0 -73.006 62028.5859 100235.5703)"
+              gradientUnits="userSpaceOnUse"
+              x1="-469.0813"
+              x2="-468.0813"
+              y1="1372.403"
+              y2="1372.403"
+            >
+              <stop offset="0.12" style="stop-color: #5c90fe" />
+              <stop offset="0.56" style="stop-color: #466cf5" />
+              <stop offset="0.69" style="stop-color: #4265f3" />
+              <stop offset="0.87" style="stop-color: #3853ef" />
+              <stop offset="1" style="stop-color: #2e42eb" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M72.8,78.5c-1.7,0.1-3.4-0.3-5-1.1L6.4,42L67.3,6.5
+					c1.5-0.8,3.2-1.1,5-1.1c1.7-0.1,3.4,0.3,5,1.1L138.6,42L77.7,77.3C76.2,78.1,74.5,78.5,72.8,78.5z"
+              fill="url(#SVGID_50_)"
+              fill-rule="evenodd"
+            />
+
+            <linearGradient
+              id="SVGID_51_"
+              gradientTransform="matrix(144.9687 0 0 -54.9245 67992.2734 75196.0781)"
+              gradientUnits="userSpaceOnUse"
+              x1="-469.0135"
+              x2="-468.0135"
+              y1="1367.8169"
+              y2="1367.8169"
+            >
+              <stop offset="0.12" style="stop-color: #5c90fe" />
+              <stop offset="0.56" style="stop-color: #466cf5" />
+              <stop offset="0.69" style="stop-color: #4265f3" />
+              <stop offset="0.87" style="stop-color: #3853ef" />
+              <stop offset="1" style="stop-color: #2e42eb" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M145,42c0,0.1,0,0.2,0,0.3s0,0.2,0,0.3s0,0.2-0.1,0.3
+					c-0.1,0.1-0.1,0.2-0.1,0.3s-0.1,0.2-0.1,0.3c0,0.1-0.1,0.2-0.2,0.3l-0.2,0.2c-0.1,0.1-0.2,0.3-0.3,0.4l-0.2,0.2
+					c-0.1,0.2-0.3,0.3-0.5,0.5l-0.2,0.2l-0.3,0.3l-0.3,0.2l-0.4,0.3l-0.4,0.3L80.5,82c-0.4,0.2-0.7,0.4-1.1,0.5l-0.3,0.1
+					c-0.3,0.1-0.6,0.2-0.9,0.3l-0.3,0.1l-0.6,0.2l-0.4,0.1l-0.6,0.1l-0.4,0.1c-0.4,0.1-0.8,0.1-1.2,0.2h-0.4h-0.7H72h-0.6h-0.5
+					l-0.6,0l-0.5-0.1l-0.6-0.1l-0.5-0.1l-0.7-0.2l-0.4-0.1c-0.4-0.1-0.8-0.2-1.2-0.4l-0.2-0.1c-0.5-0.2-1-0.4-1.5-0.7L3.2,46.5
+					C1.1,45.2,0,43.6,0,42v13.3c0,1.6,1.1,3.2,3.2,4.5L65,95.4c0.5,0.3,1,0.5,1.5,0.7h0.1h0.1c0.4,0.2,0.8,0.3,1.2,0.4h0.1l0.3,0.1
+					l0.7,0.2h0.2h0.3l0.6,0.1h0.2h0.3l0.5,0.1h0.3h0.3H72h1.6h0.7h0.3h0.1c0.4,0,0.8-0.1,1.2-0.2H76l0.4-0.1l0.5,0.1l0.4-0.1
+					l0.6-0.2H78l0.2-0.1c0.3-0.1,0.6-0.2,0.9-0.3l0.3-0.1c0.4-0.2,0.7-0.3,1.1-0.5l61.4-35.6l0.1-0.1l0.3-0.2l0.4-0.3l0.3-0.2
+					l0.3-0.3l0.1-0.1l0.1-0.1c0.2-0.2,0.3-0.3,0.5-0.5L144,58l0.1-0.1c0.1-0.1,0.2-0.2,0.3-0.4l0.1-0.2v-0.1
+					c0.1-0.1,0.1-0.2,0.2-0.3s0.1-0.1,0.1-0.2v-0.1c0-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2,0.1-0.2c0.1-0.1,0,0,0-0.1s0-0.2,0-0.3
+					s0-0.2,0-0.2c0-0.1,0-0.1,0-0.1l0,0L145,42z"
+              fill="url(#SVGID_51_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <g id="缂栫粍-2澶囦唤" transform="translate(8.400000, 103.200000)">
+            <g
+              id="Path澶囦唤-3"
+              enable-background="new    "
+              filter="url(#filter-100)"
+              opacity="0.6817"
+            >
+              <linearGradient
+                id="SVGID_52_"
+                gradientTransform="matrix(130.5022 0 0 -75.4716 62201.1797 105298.6953)"
+                gradientUnits="userSpaceOnUse"
+                x1="-475.6305"
+                x2="-476.3059"
+                y1="1394.5802"
+                y2="1394.4315"
+              >
+                <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+                <stop offset="1" style="stop-color: #060071" />
+              </linearGradient>
+              <path
+                clip-rule="evenodd"
+                d="M127.6,51.7c3.9,2.2,3.9,5.8,0,8L72.3,91.8
+						c-4.4,2.2-9.5,2.2-13.9,0L2.9,59.7c-3.8-2.2-3.9-5.8,0-8l55.2-32.1c4.4-2.2,9.5-2.2,13.9,0L127.6,51.7z"
+                fill="url(#SVGID_52_)"
+                fill-rule="evenodd"
+              />
+            </g>
+
+            <linearGradient
+              id="SVGID_53_"
+              gradientTransform="matrix(130.5022 0 0 -75.4716 62201.1797 105280.6953)"
+              gradientUnits="userSpaceOnUse"
+              x1="-476.6293"
+              x2="-475.6293"
+              y1="1394.4705"
+              y2="1394.4705"
+            >
+              <stop offset="0" style="stop-color: #6ecaf9" />
+              <stop offset="0.35" style="stop-color: #a1ddfb" />
+              <stop offset="1" style="stop-color: #fff" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M127.6,33.7c3.9,2.2,3.9,5.8,0,8L72.3,73.8
+					c-4.4,2.2-9.5,2.2-13.9,0L2.9,41.7c-3.8-2.2-3.9-5.8,0-8L58.1,1.7c4.4-2.2,9.5-2.2,13.9,0L127.6,33.7z"
+              fill="url(#SVGID_53_)"
+              fill-rule="evenodd"
+            />
+
+            <linearGradient
+              id="SVGID_54_"
+              gradientTransform="matrix(118.9985 0 0 -65.7054 56732.918 91530.375)"
+              gradientUnits="userSpaceOnUse"
+              x1="-476.7049"
+              x2="-475.7049"
+              y1="1392.4675"
+              y2="1392.4675"
+            >
+              <stop offset="0.12" style="stop-color: #5c90fe" />
+              <stop offset="0.56" style="stop-color: #466cf5" />
+              <stop offset="0.69" style="stop-color: #4265f3" />
+              <stop offset="0.87" style="stop-color: #3853ef" />
+              <stop offset="1" style="stop-color: #2e42eb" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M65.5,70.6c-1.6,0.1-3.1-0.3-4.5-1L5.8,37.8L60.6,5.9
+					c1.4-0.7,2.9-1,4.5-1c1.6,0,3.1,0.3,4.5,1l55.2,31.9L69.9,69.6C68.6,70.3,67,70.6,65.5,70.6z"
+              fill="url(#SVGID_54_)"
+              fill-rule="evenodd"
+            />
+
+            <linearGradient
+              id="SVGID_55_"
+              gradientTransform="matrix(130.4718 0 0 -49.432 62186.7266 68643.1094)"
+              gradientUnits="userSpaceOnUse"
+              x1="-476.6295"
+              x2="-475.6295"
+              y1="1387.3719"
+              y2="1387.3719"
+            >
+              <stop offset="0.12" style="stop-color: #5c90fe" />
+              <stop offset="0.56" style="stop-color: #466cf5" />
+              <stop offset="0.69" style="stop-color: #4265f3" />
+              <stop offset="0.87" style="stop-color: #3853ef" />
+              <stop offset="1" style="stop-color: #2e42eb" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M130.5,37.8c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3
+					s0,0.2-0.1,0.3c-0.1,0.1,0,0.2-0.1,0.3s-0.1,0.2-0.1,0.2c0,0.1-0.1,0.2-0.1,0.3l-0.1,0.2c-0.1,0.1-0.1,0.2-0.2,0.3l-0.2,0.2
+					c-0.1,0.2-0.3,0.3-0.4,0.4l-0.2,0.2l-0.3,0.3l-0.3,0.2l-0.3,0.2l-0.4,0.2L72.4,73.8c-0.3,0.2-0.6,0.3-1,0.5l-0.3,0.1
+					c-0.3,0.1-0.5,0.2-0.8,0.3l-0.3,0.1l-0.5,0.1L69.2,75l-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.1-1.1,0.2h-0.3h-0.7h-1.4h-0.5h-0.5
+					l-0.5,0l-0.4-0.1l-0.5-0.1L62,75.2L61.4,75L61,74.9c-0.4-0.1-0.7-0.2-1-0.4l-0.1-0.1c-0.5-0.2-0.9-0.4-1.3-0.6L2.9,41.8
+					C1,40.7,0,39.3,0,37.8v12c0,1.5,1,2.9,2.9,4l55.6,32.1c0.4,0.2,0.9,0.5,1.3,0.6h0.1H60c0.3,0.1,0.7,0.3,1,0.3h0.1l0.3,0.1
+					l0.6,0.1h0.2h0.2l0.5,0.1h0.2h0.2l0.5,0.1h0.2h0.3h0.5h1.4h0.7h0.3h0.1c0.4,0,0.7-0.1,1.1-0.2h0.1l0.3-0.1l0.4,0.1l0.4-0.1
+					l0.5-0.1h0.1l0.2-0.1c0.3-0.1,0.5-0.2,0.8-0.3l0.3-0.1c0.3-0.1,0.7-0.3,1-0.5l55.2-32.1l0.1-0.1l0.3-0.2l0.3-0.2l0.3-0.2
+					l0.3-0.3l0.1,0l0.1-0.1c0.1-0.1,0.3-0.3,0.4-0.4l0.1-0.1l0.1-0.1c0.1-0.1,0.2-0.2,0.2-0.3l0.1-0.1v-0.1c0.1-0.1,0.1-0.2,0.1-0.3
+					c0-0.1,0.1-0.1,0.1-0.2V51c0-0.1,0.1-0.2,0.1-0.3s0-0.1,0.1-0.2c0.1-0.1,0,0,0,0s0-0.2,0-0.3c0-0.1,0-0.1,0-0.2s0-0.1,0-0.1l0,0
+					L130.5,37.8z"
+              fill="url(#SVGID_55_)"
+              fill-rule="evenodd"
+            />
+          </g>
+          <path
+            clip-rule="evenodd"
+            d="M63.9,130.7l0.1,0.4
+				L63.9,130.7z"
+            fill="#666666"
+            fill-rule="evenodd"
+            stroke="#000000"
+            stroke-width="0.6"
+          />
+          <path
+            clip-rule="evenodd"
+            d="M63.8,130l0.1,0.4
+				L63.8,130z"
+            fill="#666666"
+            fill-rule="evenodd"
+            stroke="#000000"
+            stroke-width="0.6"
+          />
+
+          <linearGradient
+            id="SVGID_56_"
+            gradientTransform="matrix(132.2205 0 0 -178.9849 61915.457 269544.7812)"
+            gradientUnits="userSpaceOnUse"
+            x1="-467.7177"
+            x2="-467.7209"
+            y1="1504.9636"
+            y2="1506.2531"
+          >
+            <stop offset="0" style="stop-color: #00dcf3" />
+            <stop
+              offset="1.000000e-02"
+              style="stop-color: #00dbf3; stop-opacity: 0.97"
+            />
+            <stop
+              offset="8.000000e-02"
+              style="stop-color: #00d0ef; stop-opacity: 0.77"
+            />
+            <stop
+              offset="0.16"
+              style="stop-color: #00c7ec; stop-opacity: 0.59"
+            />
+            <stop
+              offset="0.24"
+              style="stop-color: #00beea; stop-opacity: 0.43"
+            />
+            <stop
+              offset="0.32"
+              style="stop-color: #00b7e8; stop-opacity: 0.3"
+            />
+            <stop
+              offset="0.42"
+              style="stop-color: #00b2e6; stop-opacity: 0.19"
+            />
+            <stop
+              offset="0.52"
+              style="stop-color: #00ade5; stop-opacity: 0.1"
+            />
+            <stop
+              offset="0.63"
+              style="stop-color: #00aae4; stop-opacity: 4e-2"
+            />
+            <stop
+              offset="0.77"
+              style="stop-color: #00a9e3; stop-opacity: 1e-2"
+            />
+            <stop offset="1" style="stop-color: #00a8e3; stop-opacity: 0" />
+          </linearGradient>
+          <path
+            clip-rule="evenodd"
+            d="M7.3,0.1v142.4l61.4,35.4c1.5,0.8,3.3,1.1,5,1.1
+				c1.7,0.1,3.4-0.3,5-1.1l60.9-35.4V0L7.3,0.1z"
+            fill="url(#SVGID_56_)"
+            fill-rule="evenodd"
+          />
+        </g>
+        <g id="缂栫粍澶囦唤-8" transform="translate(47.447727, 63.600000)">
+          <g
+            enable-background="new    "
+            filter="url(#filter-106)"
+            opacity="0.3003"
+          >
+            <linearGradient
+              id="SVGID_57_"
+              gradientTransform="matrix(99.0186 0 0 -57.6674 49956.1875 82510.0469)"
+              gradientUnits="userSpaceOnUse"
+              x1="-503.4795"
+              x2="-504.155"
+              y1="1430.0212"
+              y2="1429.8705"
+            >
+              <stop offset="0" style="stop-color: #1b0f9c; stop-opacity: 0" />
+              <stop offset="1" style="stop-color: #060071" />
+            </linearGradient>
+            <polygon
+              clip-rule="evenodd"
+              fill="url(#SVGID_57_)"
+              fill-rule="evenodd"
+              points="3.5,59.5 38.6,79.7 102.5,42.3 67.4,22.1
+					"
+            />
+          </g>
+          <g>
+            <g>
+              <linearGradient
+                id="path-108_1_"
+                gradientTransform="matrix(70.176 0 0 -40.5146 35432.1289 57650.0859)"
+                gradientUnits="userSpaceOnUse"
+                x1="-504.9012"
+                x2="-503.9012"
+                y1="1422.4436"
+                y2="1422.4436"
+              >
+                <stop offset="0" style="stop-color: #fff" />
+                <stop offset="1" style="stop-color: #00a2ff" />
+              </linearGradient>
+              <polygon
+                id="path-108"
+                clip-rule="evenodd"
+                fill="url(#path-108_1_)"
+                fill-rule="evenodd"
+                points="0.2,20.4 35.3,40.6
+						70.4,20.4 35.3,0.1 					"
+              />
+            </g>
+            <g filter="url(#filter-109)">
+              <polygon
+                clip-rule="evenodd"
+                fill-rule="evenodd"
+                points="0.2,20.4 35.3,40.6 70.4,20.4 35.3,0.1 					"
+              />
+            </g>
+          </g>
+
+          <linearGradient
+            id="SVGID_58_"
+            gradientTransform="matrix(35.088 0 0 -60.7744 17767.0781 87007.4453)"
+            gradientUnits="userSpaceOnUse"
+            x1="-505.8155"
+            x2="-505.9297"
+            y1="1431.3086"
+            y2="1429.8619"
+          >
+            <stop offset="0" style="stop-color: #7bedff" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <polygon
+            clip-rule="evenodd"
+            fill="url(#SVGID_58_)"
+            fill-rule="evenodd"
+            points="35.2,81.1 35.2,40.6 0.1,20.4 0.1,60.9 			"
+          />
+          <g id="缂栫粍-10" transform="translate(4.431004, 28.063025)">
+            <g id="缂栫粍-8">
+              <g id="Shape澶囦唤-3" transform="translate(0.000000, -0.000000)">
+                <g id="钂欑増">
+                  <linearGradient
+                    id="SVGID_59_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3322.1904 14513.207)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-523.204"
+                    x2="-524.0609"
+                    y1="1326.9464"
+                    y2="1325.4684"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_59_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_2_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-113_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_2_)">
+                    <polygon
+                      id="path-112_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_60_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3111.8501 14516.8223)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-491.1827"
+                  x2="-491.4043"
+                  y1="1326.7101"
+                  y2="1326.2715"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_60_)"
+                  mask="url(#mask-113_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g id="Shape澶囦唤-4" transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_61_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3383.2495 14453.3994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-532.7115"
+                    x2="-533.1328"
+                    y1="1319.3007"
+                    y2="1321.1917"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_61_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_3_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-117_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_3_)">
+                    <polygon
+                      id="path-116_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_62_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3172.9092 14457.0146)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-500.7126"
+                  x2="-501.1153"
+                  y1="1321.2085"
+                  y2="1320.8575"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_62_)"
+                  mask="url(#mask-117_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g id="Shape澶囦唤-5" transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_63_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3443.9341 14392.0537)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-542.2824"
+                    x2="-542.7037"
+                    y1="1313.6917"
+                    y2="1315.5826"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_63_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_4_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-120_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_4_)">
+                    <polygon
+                      id="path-119_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_64_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3233.5935 14395.6689)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-510.2835"
+                  x2="-510.6862"
+                  y1="1315.5994"
+                  y2="1315.2484"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_64_)"
+                  mask="url(#mask-120_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+            <g id="缂栫粍-8澶囦唤" transform="translate(0.000000, 11.077510)">
+              <g transform="translate(0.000000, -0.000000)">
+                <g>
+                  <linearGradient
+                    id="SVGID_65_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3322.1904 14392.0537)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-523.204"
+                    x2="-524.0609"
+                    y1="1315.8689"
+                    y2="1314.3909"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_65_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_5_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-122_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_5_)">
+                    <polygon
+                      id="path-121_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_66_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3111.8501 14395.6689)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-491.1827"
+                  x2="-491.4043"
+                  y1="1315.6326"
+                  y2="1315.194"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_66_)"
+                  mask="url(#mask-122_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_67_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3383.2495 14332.2451)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-532.7115"
+                    x2="-533.1328"
+                    y1="1308.2231"
+                    y2="1310.1143"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_67_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_6_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-124_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_6_)">
+                    <polygon
+                      id="path-123_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_68_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3172.9092 14335.8613)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-500.7126"
+                  x2="-501.1153"
+                  y1="1310.131"
+                  y2="1309.78"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_68_)"
+                  mask="url(#mask-124_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_69_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3443.9341 14270.8994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-542.2824"
+                    x2="-542.7037"
+                    y1="1302.6141"
+                    y2="1304.5051"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_69_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_7_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-126_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_7_)">
+                    <polygon
+                      id="path-125_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_70_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3233.5935 14274.5156)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-510.2835"
+                  x2="-510.6862"
+                  y1="1304.5219"
+                  y2="1304.1709"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_70_)"
+                  mask="url(#mask-126_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+            <g id="缂栫粍-8澶囦唤-2" transform="translate(0.000000, 22.155020)">
+              <g transform="translate(0.000000, -0.000000)">
+                <g>
+                  <linearGradient
+                    id="SVGID_71_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3322.1904 14270.8994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-523.204"
+                    x2="-524.0609"
+                    y1="1304.7914"
+                    y2="1303.3134"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_71_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_8_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-128_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_8_)">
+                    <polygon
+                      id="path-127_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_72_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3111.8501 14274.5156)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-491.1827"
+                  x2="-491.4043"
+                  y1="1304.5552"
+                  y2="1304.1165"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_72_)"
+                  mask="url(#mask-128_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_73_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3383.2495 14211.0918)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-532.7115"
+                    x2="-533.1328"
+                    y1="1297.1456"
+                    y2="1299.0367"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_73_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_9_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-130_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_9_)">
+                    <polygon
+                      id="path-129_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_74_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3172.9092 14214.708)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-500.7126"
+                  x2="-501.1153"
+                  y1="1299.0535"
+                  y2="1298.7025"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_74_)"
+                  mask="url(#mask-130_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_75_"
+                    gradientTransform="matrix(6.3405 0 0 -10.9369 3443.9341 14149.7461)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="-542.2824"
+                    x2="-542.7037"
+                    y1="1291.5366"
+                    y2="1293.4276"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_75_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_10_"
+                    filterUnits="userSpaceOnUse"
+                    height="10.9"
+                    width="6.3"
+                    x="0"
+                    y="3.6"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask
+                  id="mask-132_1_"
+                  height="10.9"
+                  maskUnits="userSpaceOnUse"
+                  width="6.3"
+                  x="0"
+                  y="3.6"
+                >
+                  <g filter="url(#Adobe_OpacityMaskFilter_10_)">
+                    <polygon
+                      id="path-131_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_76_"
+                  gradientTransform="matrix(-6.3405 0 0 -10.9369 -3233.5935 14153.3623)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="-510.2835"
+                  x2="-510.6862"
+                  y1="1293.4443"
+                  y2="1293.0934"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_76_)"
+                  mask="url(#mask-132_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+          </g>
+
+          <linearGradient
+            id="SVGID_77_"
+            gradientTransform="matrix(35.088 0 0 -60.7744 17802.2441 87007.4453)"
+            gradientUnits="userSpaceOnUse"
+            x1="-505.8547"
+            x2="-505.8547"
+            y1="1431.6647"
+            y2="1430.4622"
+          >
+            <stop offset="0" style="stop-color: #7bedff" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <polygon
+            clip-rule="evenodd"
+            fill="url(#SVGID_77_)"
+            fill-rule="evenodd"
+            points="35.3,81.1 35.3,40.6 70.4,20.4 70.4,60.9
+				"
+          />
+
+          <g
+            id="缂栫粍-10澶囦唤-4"
+            transform="translate(53.703560, 51.063025) scale(-1, 1) translate(-53.703560, -51.063025) translate(40.203560, 28.063025)"
+          >
+            <g>
+              <g transform="translate(0.000000, -0.000000)">
+                <g>
+                  <linearGradient
+                    id="SVGID_78_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3516.198 14513.207)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="553.8022"
+                    x2="552.9454"
+                    y1="1326.9464"
+                    y2="1325.4684"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_78_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_11_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-135_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_11_)">
+                    <polygon
+                      id="path-134_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_79_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3713.8577 14516.8223)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="586.1296"
+                  x2="585.908"
+                  y1="1326.7101"
+                  y2="1326.2715"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_79_)"
+                  mask="url(#mask-135_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_80_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3455.1392 14453.3994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="544.0497"
+                    x2="543.6284"
+                    y1="1319.3007"
+                    y2="1321.1917"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_80_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_12_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-137_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_12_)">
+                    <polygon
+                      id="path-136_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_81_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3652.7986 14457.0146)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="576.3993"
+                  x2="575.9966"
+                  y1="1321.2085"
+                  y2="1320.8575"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_81_)"
+                  mask="url(#mask-137_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_82_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3394.4546 14392.0537)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="534.4787"
+                    x2="534.0574"
+                    y1="1313.6917"
+                    y2="1315.5826"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_82_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_13_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-139_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_13_)">
+                    <polygon
+                      id="path-138_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_83_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3592.114 14395.6689)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="566.8283"
+                  x2="566.4257"
+                  y1="1315.5994"
+                  y2="1315.2484"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_83_)"
+                  mask="url(#mask-139_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+            <g transform="translate(0.000000, 11.077510)">
+              <g transform="translate(0.000000, -0.000000)">
+                <g>
+                  <linearGradient
+                    id="SVGID_84_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3516.198 14392.0537)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="553.8022"
+                    x2="552.9454"
+                    y1="1315.8689"
+                    y2="1314.3909"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_84_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_14_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-141_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_14_)">
+                    <polygon
+                      id="path-140_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_85_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3713.8577 14395.6689)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="586.1296"
+                  x2="585.908"
+                  y1="1315.6326"
+                  y2="1315.194"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_85_)"
+                  mask="url(#mask-141_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_86_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3455.1392 14332.2451)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="544.0497"
+                    x2="543.6284"
+                    y1="1308.2231"
+                    y2="1310.1143"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_86_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_15_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-143_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_15_)">
+                    <polygon
+                      id="path-142_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_87_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3652.7986 14335.8613)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="576.3993"
+                  x2="575.9966"
+                  y1="1310.131"
+                  y2="1309.78"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_87_)"
+                  mask="url(#mask-143_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_88_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3394.4546 14270.8994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="534.4787"
+                    x2="534.0574"
+                    y1="1302.6141"
+                    y2="1304.5051"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_88_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_16_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-145_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_16_)">
+                    <polygon
+                      id="path-144_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_89_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3592.114 14274.5156)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="566.8283"
+                  x2="566.4257"
+                  y1="1304.5219"
+                  y2="1304.1709"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_89_)"
+                  mask="url(#mask-145_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+            <g transform="translate(0.000000, 22.155020)">
+              <g transform="translate(0.000000, -0.000000)">
+                <g>
+                  <linearGradient
+                    id="SVGID_90_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3516.198 14270.8994)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="553.8022"
+                    x2="552.9454"
+                    y1="1304.7914"
+                    y2="1303.3134"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #fb6583" />
+                    <stop offset="0.1302" style="stop-color: #fc7688" />
+                    <stop offset="0.5277" style="stop-color: #fda797" />
+                    <stop offset="0.8302" style="stop-color: #ffc6a0" />
+                    <stop offset="1" style="stop-color: #ffd1a3" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_90_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_17_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-147_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_17_)">
+                    <polygon
+                      id="path-146_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_91_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3713.8577 14274.5156)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="586.1296"
+                  x2="585.908"
+                  y1="1304.5552"
+                  y2="1304.1165"
+                >
+                  <stop offset="0" style="stop-color: #fb6583" />
+                  <stop offset="1" style="stop-color: #ffd1a3" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_91_)"
+                  mask="url(#mask-147_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(9.630049, 5.468450)">
+                <g>
+                  <linearGradient
+                    id="SVGID_92_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3455.1392 14211.0918)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="544.0497"
+                    x2="543.6284"
+                    y1="1297.1456"
+                    y2="1299.0367"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_92_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_18_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-149_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_18_)">
+                    <polygon
+                      id="path-148_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_93_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3652.7986 14214.708)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="576.3993"
+                  x2="575.9966"
+                  y1="1299.0535"
+                  y2="1298.7025"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_93_)"
+                  mask="url(#mask-149_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+              <g transform="translate(19.201017, 11.077510)">
+                <g>
+                  <linearGradient
+                    id="SVGID_94_"
+                    gradientTransform="matrix(-6.3405 0 0 -10.9369 3394.4546 14149.7461)"
+                    gradientUnits="userSpaceOnUse"
+                    x1="534.4787"
+                    x2="534.0574"
+                    y1="1291.5366"
+                    y2="1293.4276"
+                  >
+                    <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+                    <stop offset="0.2823" style="stop-color: #285ecb" />
+                    <stop offset="0.538" style="stop-color: #3aa3dd" />
+                    <stop offset="0.75" style="stop-color: #47d5eb" />
+                    <stop offset="0.9102" style="stop-color: #4ff4f3" />
+                    <stop offset="1" style="stop-color: #52fff6" />
+                  </linearGradient>
+                  <polygon
+                    fill="url(#SVGID_94_)"
+                    points="0,7.3 6.3,10.9 6.3,3.7 0,0 							"
+                  />
+                </g>
+                <defs>
+                  <filter
+                    id="Adobe_OpacityMaskFilter_19_"
+                    filterUnits="userSpaceOnUse"
+                  >
+                    <feColorMatrix
+                      type="matrix"
+                      values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                    />
+                  </filter>
+                </defs>
+                <mask id="mask-151_1_" maskUnits="userSpaceOnUse">
+                  <g filter="url(#Adobe_OpacityMaskFilter_19_)">
+                    <polygon
+                      id="path-150_1_"
+                      clip-rule="evenodd"
+                      fill="#FFFFFF"
+                      fill-rule="evenodd"
+                      points="0,7.3 6.3,10.9 6.3,3.7 0,0
+																	"
+                    />
+                  </g>
+                </mask>
+
+                <linearGradient
+                  id="SVGID_95_"
+                  gradientTransform="matrix(6.3405 0 0 -10.9369 -3592.114 14153.3623)"
+                  gradientUnits="userSpaceOnUse"
+                  x1="566.8283"
+                  x2="566.4257"
+                  y1="1293.4443"
+                  y2="1293.0934"
+                >
+                  <stop offset="0" style="stop-color: #00c4ba" />
+                  <stop offset="1" style="stop-color: #52fff6" />
+                </linearGradient>
+                <polygon
+                  fill="url(#SVGID_95_)"
+                  mask="url(#mask-151_1_)"
+                  points="6.3,10.9 0,14.6 0,7.3 6.3,3.6 						"
+                />
+              </g>
+            </g>
+          </g>
+        </g>
+
+        <g
+          id="妞渾"
+          transform="translate(83.218192, 86.783330) rotate(5.000000) translate(-83.218192, -86.783330) translate(7.218192, 10.783330)"
+        >
+          <g id="缂栫粍-5" transform="translate(8.161827, 36.521835)">
+            <linearGradient
+              id="SVGID_96_"
+              gradientTransform="matrix(124.0018 47.351 0.1479 -31.3606 42600.2344 62547.3867)"
+              gradientUnits="userSpaceOnUse"
+              x1="-344.7103"
+              x2="-344.7103"
+              y1="1473.182"
+              y2="1472.182"
+            >
+              <stop
+                offset="0"
+                style="stop-color: #5cd7e8; stop-opacity: 0.1893"
+              />
+              <stop offset="1" style="stop-color: #fff" />
+            </linearGradient>
+
+            <ellipse
+              cx="68"
+              cy="38.7"
+              fill="none"
+              rx="14.6"
+              ry="66.6"
+              stroke="url(#SVGID_96_)"
+              stroke-width="0.6"
+              transform="matrix(-0.3746 0.9272 -0.9272 -0.3746 129.3914 -9.7912)"
+            />
+
+            <ellipse
+              clip-rule="evenodd"
+              cx="60.3"
+              cy="51.5"
+              fill="#FFFFFF"
+              fill-rule="evenodd"
+              rx="1.7"
+              ry="1.7"
+              transform="matrix(2.765398e-06 1 -1 2.765398e-06 111.8035 -8.8797)"
+            />
+
+            <ellipse
+              id="妞渾褰㈠浠�"
+              clip-rule="evenodd"
+              cx="86"
+              cy="30.8"
+              enable-background="new    "
+              fill="#FFFFFF"
+              fill-rule="evenodd"
+              opacity="0.2662"
+              rx="1.1"
+              ry="1"
+              transform="matrix(2.765396e-06 1 -1 2.765396e-06 116.7571 -55.2401)"
+            />
+          </g>
+
+          <g
+            transform="translate(76.180160, 76.074544) rotate(-45.000000) translate(-76.180160, -76.074544) translate(8.680160, 37.074544)"
+          >
+            <linearGradient
+              id="SVGID_97_"
+              gradientTransform="matrix(87.4224 55.5937 87.656 11.2551 42330.7227 60598.5664)"
+              gradientUnits="userSpaceOnUse"
+              x1="-1242.9404"
+              x2="-1242.9404"
+              y1="757.5463"
+              y2="756.5463"
+            >
+              <stop
+                offset="0"
+                style="stop-color: #5cd7e8; stop-opacity: 0.1893"
+              />
+              <stop offset="1" style="stop-color: #fff" />
+            </linearGradient>
+
+            <ellipse
+              cx="67.9"
+              cy="38.7"
+              fill="none"
+              rx="66.5"
+              ry="14.6"
+              stroke="url(#SVGID_97_)"
+              stroke-width="0.6"
+              transform="matrix(-0.9272 -0.3746 0.3746 -0.9272 116.2823 100.0875)"
+            />
+
+            <ellipse
+              clip-rule="evenodd"
+              cx="31.9"
+              cy="37"
+              fill="#FFFFFF"
+              fill-rule="evenodd"
+              rx="1.7"
+              ry="1.7"
+              transform="matrix(-1 -5.213811e-07 5.213811e-07 -1 63.8725 74.0324)"
+            />
+
+            <ellipse
+              clip-rule="evenodd"
+              cx="85.8"
+              cy="30.8"
+              enable-background="new    "
+              fill="#FFFFFF"
+              fill-rule="evenodd"
+              opacity="0.2662"
+              rx="1"
+              ry="1.1"
+              transform="matrix(-1 2.765399e-06 -2.765399e-06 -1 171.6696 61.5172)"
+            />
+          </g>
+        </g>
+      </g>
+
+      <g
+        id="缂栫粍澶囦唤-11"
+        transform="translate(694.000000, 158.500000) scale(-1, 1) translate(-694.000000, -158.500000) translate(622.000000, 65.000000)"
+      >
+        <linearGradient
+          id="SVGID_98_"
+          gradientTransform="matrix(-142.0107 0 0 -186.2829 94193.1797 325470.9375)"
+          gradientUnits="userSpaceOnUse"
+          x1="663.2509"
+          x2="663.8784"
+          y1="1745.6415"
+          y2="1747.1095"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #00c6fb" />
+        </linearGradient>
+        <path
+          d="M134.9,0l7.1,4l-2.2,3.6l-3,1.2l-1.4,92c0,3-1.8,6.5-4,8l-0.2,0.1L10,178.8l0,0l-1.2,7.5l-7-3.9
+			c-0.1-0.1-0.3-0.1-0.4-0.2l0,0c-0.8-0.6-1.3-1.7-1.3-3.3l0,0l1.4-97.1c0-3.1,1.9-6.7,4.2-8.1l0,0L132.6,0.5
+			C133.5,0,134.3-0.1,134.9,0L134.9,0z"
+          fill="url(#SVGID_98_)"
+        />
+
+        <linearGradient
+          id="SVGID_99_"
+          gradientTransform="matrix(-136.8189 0 0 -182.5389 90752.4922 318912.7812)"
+          gradientUnits="userSpaceOnUse"
+          x1="662.8271"
+          x2="662.9656"
+          y1="1746.7982"
+          y2="1746.3707"
+        >
+          <stop offset="0" style="stop-color: #276cfc" />
+          <stop offset="1" style="stop-color: #84ffd1" />
+        </linearGradient>
+        <path
+          clip-rule="evenodd"
+          d="M11,185.8l126.9-73.2c2.3-1.4,4.2-5,4.2-8.1l1.4-97.1
+			c0-3.1-1.9-4.6-4.2-3.2L12.4,77.4c-2.3,1.4-4.2,5-4.2,8.1l-1.4,97.1C6.8,185.7,8.7,187.1,11,185.8z"
+          fill="url(#SVGID_99_)"
+          fill-rule="evenodd"
+        />
+        <g opacity="0.3" transform="translate(95.618736, 40.248000)">
+          <path
+            d="M33.5,8.7L3.1,26.3c-1,0.6-2.2,0.2-2.8-0.7
+				c-0.2-0.3-0.3-0.7-0.3-1c0-2.2,1.2-4.2,3-5.2L33.5,1.7c1-0.6,2.2-0.2,2.8,0.7c0.2,0.3,0.3,0.7,0.3,1C36.6,5.7,35.4,7.7,33.5,8.7z
+				"
+            enable-background="new    "
+            fill="#FFFFFF"
+            opacity="0.3007"
+          />
+          <path
+            d="M34,27.4L10.3,41c-0.8,0.4-1.7,0.2-2.1-0.6
+				C8,40.2,8,40,8,39.7c0-1.7,0.9-3.2,2.4-4.1L34,22c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8C36.3,25,35.4,26.5,34,27.4z"
+            enable-background="new    "
+            fill="#FFFFFF"
+            opacity="0.3007"
+          />
+          <path
+            d="M34,41.7L10.3,55.4c-0.8,0.4-1.7,0.2-2.1-0.6
+				C8,54.6,8,54.3,8,54c0-1.7,0.9-3.2,2.4-4.1L34,36.3c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8
+				C36.3,39.3,35.4,40.9,34,41.7z"
+            enable-background="new    "
+            fill="#FFFFFF"
+            opacity="0.3007"
+          />
+          <path
+            d="M34,56L10.3,69.7c-0.8,0.4-1.7,0.2-2.1-0.6
+				C8,68.9,8,68.6,8,68.3c0-1.7,0.9-3.2,2.4-4.1L34,50.6c0.8-0.4,1.7-0.2,2.1,0.6c0.1,0.2,0.2,0.5,0.2,0.8
+				C36.3,53.6,35.4,55.2,34,56z"
+            enable-background="new    "
+            fill="#FFFFFF"
+            opacity="0.3007"
+          />
+        </g>
+
+        <linearGradient
+          id="SVGID_100_"
+          gradientTransform="matrix(-82.1586 0 0 -155.5418 54504.3555 271598.7188)"
+          gradientUnits="userSpaceOnUse"
+          x1="662.0853"
+          x2="661.7936"
+          y1="1746.2543"
+          y2="1745.1642"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+        <polygon
+          enable-background="new    "
+          fill="url(#SVGID_100_)"
+          opacity="0.4"
+          points="93,31 53,161.5 94.8,137.4 135.2,6 		"
+        />
+
+        <linearGradient
+          id="SVGID_101_"
+          gradientTransform="matrix(-12.3655 0 0 -48.4174 8136.0479 83952.2812)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.1039"
+          x2="654.9725"
+          y1="1729.8617"
+          y2="1731.0027"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="SVGID_102_"
+          gradientTransform="matrix(-12.3655 0 0 -48.4174 8136.0479 83952.2812)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.2512"
+          x2="655.2512"
+          y1="1731.6409"
+          y2="1730.6409"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+
+        <polygon
+          enable-background="new    "
+          fill="url(#SVGID_101_)"
+          opacity="0.3007"
+          points="
+			39.7,152 27.4,159.1 27.4,117.9 39.7,110.7 		"
+          stroke="url(#SVGID_102_)"
+          stroke-width="0.5"
+        />
+
+        <g
+          transform="translate(72.980000, 101.800000) scale(-1, 1) translate(-72.980000, -101.800000) translate(13.480000, 28.800000)"
+        >
+          <linearGradient
+            id="SVGID_103_"
+            gradientTransform="matrix(116.289 0 0 -102.7515 61913.2812 176111.3281)"
+            gradientUnits="userSpaceOnUse"
+            x1="-531.9647"
+            x2="-531.5446"
+            y1="1713.5308"
+            y2="1713.0157"
+          >
+            <stop offset="0" style="stop-color: #fff" />
+            <stop offset="1" style="stop-color: #fff" />
+          </linearGradient>
+
+          <linearGradient
+            id="SVGID_104_"
+            gradientTransform="matrix(116.289 0 0 -102.7515 61913.2812 176111.3281)"
+            gradientUnits="userSpaceOnUse"
+            x1="-531.3857"
+            x2="-532.1153"
+            y1="1713.6992"
+            y2="1713.3367"
+          >
+            <stop offset="0" style="stop-color: #f8ff24" />
+            <stop offset="1" style="stop-color: #fff" />
+          </linearGradient>
+          <path
+            clip-rule="evenodd"
+            d="
+				M117.6,103.3c-6-3.4-9-14.2-11.9-24.6c-2.9-10.2-5.7-20.7-11.4-24c-5.7-3.3-8.6,3.9-11.4,10.8c-2.9,7.1-5.9,14.4-11.9,10.9
+				c-6-3.5-9-14.2-11.8-24.6c-2.9-10.2-5.8-20.7-11.4-24s-8.6,3.9-11.4,10.8c-2.9,7.1-5.9,14.4-11.9,10.9c-6-3.4-9-14.2-11.8-24.6
+				C9.9,14.9,7,4.3,1.3,1.1V0.5c6,3.4,9,14.2,11.9,24.6c2.8,10.2,5.7,20.7,11.4,24c5.7,3.3,8.6-3.9,11.4-10.8
+				c2.9-7.1,5.9-14.4,11.8-10.9s9,14.2,11.9,24.6c2.9,10.2,5.7,20.7,11.4,24c5.7,3.2,8.6-3.9,11.4-10.8c2.9-7.1,5.9-14.4,11.8-10.9
+				c6,3.5,9,14.2,11.9,24.6c2.9,10.2,5.8,20.7,11.4,24V103.3z"
+            fill="url(#SVGID_103_)"
+            fill-rule="evenodd"
+            stroke="url(#SVGID_104_)"
+            stroke-width="1.4256"
+          />
+
+          <linearGradient
+            id="璺緞-2_1_"
+            gradientTransform="matrix(117.4617 0 0 -144.8008 62535.8438 248597.6562)"
+            gradientUnits="userSpaceOnUse"
+            x1="-531.8884"
+            x2="-531.8884"
+            y1="1716.8223"
+            y2="1715.8223"
+          >
+            <stop offset="0" style="stop-color: #fff" />
+            <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+          </linearGradient>
+          <path
+            id="璺緞-2"
+            clip-rule="evenodd"
+            d="M0.6,0.5v77.2l117,67.6l0.5-42
+				c-3.3-3.2-5.5-5.6-6.5-7.3c-4.4-7.6-5.6-14.4-6.1-18.2c-1.1-7.7-9.1-26.4-15.2-23.3c-6.1,3.1-10.8,27.4-17.9,23.3
+				c-7-4-15.5-32-17.3-39.4S46,22.8,41.4,29.7c-1,1.5-4.9,9.1-6,11.5c-7.7,15.9-13.7,7.5-19.1-5C14.1,31.1,9.8,15.4,6.2,6.8
+				C5,3.9,3.2,1.8,0.6,0.5z"
+            fill="url(#璺緞-2_1_)"
+            fill-rule="evenodd"
+          />
+          <g id="缂栫粍-7" transform="translate(41.723113, 19.522022)">
+            <path
+              id="Fill-11"
+              clip-rule="evenodd"
+              d="
+					M5.4,0.8c3,1.9,5.4,6.4,5.4,10.1c0,3.7-2.4,5.2-5.4,3.4C2.4,12.4,0,7.9,0,4.2C0,0.4,2.4-1.1,5.4,0.8"
+              enable-background="new    "
+              fill="#AA69FF"
+              fill-rule="evenodd"
+              opacity="0.6"
+            />
+            <path
+              clip-rule="evenodd"
+              d="M9.7,10.7
+					c0,3.2-2,4.5-4.3,2.9C3,12,1.1,8.1,1.1,4.9c0-3.2,2-4.5,4.3-2.9S9.7,7.5,9.7,10.7z"
+              enable-background="new    "
+              fill="#7005FF"
+              fill-rule="evenodd"
+              opacity="0.6"
+            />
+            <path
+              clip-rule="evenodd"
+              d="M7.4,9c0,1.6-1,2.2-2.2,1.4C4.1,9.6,3.1,7.6,3.1,6
+					c0-1.6,1-2.2,2.2-1.4S7.4,7.4,7.4,9z"
+              fill="#E7C769"
+              fill-rule="evenodd"
+            />
+          </g>
+        </g>
+
+        <linearGradient
+          id="SVGID_105_"
+          gradientTransform="matrix(-12.3655 0 0 -61.3183 8158.1587 106537.3281)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.2088"
+          x2="655.1892"
+          y1="1734.5078"
+          y2="1734.9935"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="SVGID_106_"
+          gradientTransform="matrix(-12.3655 0 0 -61.3183 8158.1587 106537.3281)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.2512"
+          x2="655.2512"
+          y1="1736.0601"
+          y2="1735.0601"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+
+        <polygon
+          enable-background="new    "
+          fill="url(#SVGID_105_)"
+          opacity="0.3007"
+          points="
+			61.8,139.2 49.5,146.4 49.5,92.2 61.8,85.1 		"
+          stroke="url(#SVGID_106_)"
+          stroke-width="0.5"
+        />
+
+        <linearGradient
+          id="SVGID_107_"
+          gradientTransform="matrix(-12.3655 0 0 -74.2182 8181.0142 129120.2578)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.1729"
+          x2="655.117"
+          y1="1737.4004"
+          y2="1738.1447"
+        >
+          <stop offset="5.400000e-03" style="stop-color: #130cb5" />
+          <stop offset="0.2823" style="stop-color: #285ecb" />
+          <stop offset="0.538" style="stop-color: #3aa3dd" />
+          <stop offset="0.75" style="stop-color: #47d5eb" />
+          <stop offset="0.9102" style="stop-color: #4ff4f3" />
+          <stop offset="1" style="stop-color: #52fff6" />
+        </linearGradient>
+
+        <linearGradient
+          id="SVGID_108_"
+          gradientTransform="matrix(-12.3655 0 0 -74.2182 8181.0142 129120.2578)"
+          gradientUnits="userSpaceOnUse"
+          x1="655.2512"
+          x2="655.2512"
+          y1="1738.9429"
+          y2="1737.9429"
+        >
+          <stop offset="0" style="stop-color: #fff" />
+          <stop offset="1" style="stop-color: #fff; stop-opacity: 0" />
+        </linearGradient>
+
+        <polygon
+          enable-background="new    "
+          fill="url(#SVGID_107_)"
+          opacity="0.3007"
+          points="
+			84.7,126 72.3,133.2 72.3,66.1 84.7,59 		"
+          stroke="url(#SVGID_108_)"
+          stroke-width="0.5"
+        />
+      </g>
+      <g id="缂栫粍-16" transform="translate(51.000000, 152.000000)">
+        <g id="浜�">
+          <g transform="translate(0.000000, 0.000000)">
+            <g>
+              <linearGradient
+                id="SVGID_109_"
+                gradientTransform="matrix(100.2748 0 0 -95.0757 -5012.0137 157345.375)"
+                gradientUnits="userSpaceOnUse"
+                x1="49.8504"
+                x2="50.8986"
+                y1="1654.3923"
+                y2="1654.5082"
+              >
+                <stop offset="0" style="stop-color: #544cde" />
+                <stop offset="0.5868" style="stop-color: #a7a0ff" />
+                <stop offset="1" style="stop-color: #7b74ff" />
+              </linearGradient>
+              <path
+                clip-rule="evenodd"
+                d="M70.3,14.7c0,0.3,0,0.5,0,0.7
+						c1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0
+						C2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33
+						C61-3.8,70.3,1.6,70.3,14.7z"
+                fill="url(#SVGID_109_)"
+                fill-rule="evenodd"
+              />
+            </g>
+            <defs>
+              <filter
+                id="Adobe_OpacityMaskFilter_20_"
+                filterUnits="userSpaceOnUse"
+                height="67.1"
+                width="76.3"
+                x="58.3"
+                y="-13.8"
+              >
+                <feColorMatrix
+                  type="matrix"
+                  values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                />
+              </filter>
+            </defs>
+            <mask
+              id="mask-168_1_"
+              height="67.1"
+              maskUnits="userSpaceOnUse"
+              width="76.3"
+              x="58.3"
+              y="-13.8"
+            >
+              <g filter="url(#Adobe_OpacityMaskFilter_20_)">
+                <path
+                  id="path-167_1_"
+                  clip-rule="evenodd"
+                  d="M70.3,14.7c0,0.3,0,0.5,0,0.7
+							c1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0
+							C2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33
+							C61-3.8,70.3,1.6,70.3,14.7z"
+                  fill="#FFFFFF"
+                  fill-rule="evenodd"
+                />
+              </g>
+            </mask>
+
+            <linearGradient
+              id="鐭╁舰澶囦唤-3_1_"
+              gradientTransform="matrix(76.2914 0 0 -67.1042 -3730.5828 110741.1094)"
+              gradientUnits="userSpaceOnUse"
+              x1="49.8816"
+              x2="50.4973"
+              y1="1649.8344"
+              y2="1650.4406"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="0.4096" style="stop-color: #9c92ff" />
+              <stop offset="0.7979" style="stop-color: #2519da" />
+              <stop offset="1" style="stop-color: #0d04ab" />
+            </linearGradient>
+
+            <path
+              id="鐭╁舰澶囦唤-3"
+              clip-rule="evenodd"
+              d="
+					M100.1-13.4l29.3,15.6l5.2,15.3C112,43,96.4,54.9,87.8,53.2S69.3,34.5,58.3,2.2c10.3-7,18.4-11.6,24.2-13.7
+					S94.1-14.3,100.1-13.4z"
+              fill="url(#鐭╁舰澶囦唤-3_1_)"
+              fill-rule="evenodd"
+              mask="url(#mask-168_1_)"
+            />
+            <defs>
+              <filter
+                id="Adobe_OpacityMaskFilter_21_"
+                filterUnits="userSpaceOnUse"
+                height="67.1"
+                width="76.3"
+                x="0"
+                y="-13.8"
+              >
+                <feColorMatrix
+                  type="matrix"
+                  values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                />
+              </filter>
+            </defs>
+            <mask
+              id="mask-168_2_"
+              height="67.1"
+              maskUnits="userSpaceOnUse"
+              width="76.3"
+              x="0"
+              y="-13.8"
+            >
+              <g filter="url(#Adobe_OpacityMaskFilter_21_)">
+                <path
+                  id="path-167_2_"
+                  clip-rule="evenodd"
+                  d="M70.3,14.7c0,0.3,0,0.5,0,0.7
+							c1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0
+							C2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33
+							C61-3.8,70.3,1.6,70.3,14.7z"
+                  fill="#FFFFFF"
+                  fill-rule="evenodd"
+                />
+              </g>
+            </mask>
+
+            <linearGradient
+              id="鐭╁舰澶囦唤-2_1_"
+              gradientTransform="matrix(76.2914 0 0 -67.1042 -3788.8608 110741.1094)"
+              gradientUnits="userSpaceOnUse"
+              x1="49.8816"
+              x2="50.4973"
+              y1="1649.8344"
+              y2="1650.4406"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="0.4096" style="stop-color: #9c92ff" />
+              <stop offset="0.7979" style="stop-color: #2519da" />
+              <stop offset="1" style="stop-color: #0d04ab" />
+            </linearGradient>
+
+            <path
+              id="鐭╁舰澶囦唤-2"
+              clip-rule="evenodd"
+              d="
+					M41.8-13.4L71.1,2.2l5.2,15.3C53.7,43,38.1,54.9,29.5,53.2S11,34.5,0,2.2c10.3-7,18.4-11.6,24.2-13.7S35.8-14.3,41.8-13.4z"
+              fill="url(#鐭╁舰澶囦唤-2_1_)"
+              fill-rule="evenodd"
+              mask="url(#mask-168_2_)"
+            />
+            <defs>
+              <filter
+                id="Adobe_OpacityMaskFilter_22_"
+                filterUnits="userSpaceOnUse"
+                height="67.1"
+                width="76.3"
+                x="-12.7"
+                y="35.5"
+              >
+                <feColorMatrix
+                  type="matrix"
+                  values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0"
+                />
+              </filter>
+            </defs>
+            <mask
+              id="mask-168_3_"
+              height="67.1"
+              maskUnits="userSpaceOnUse"
+              width="76.3"
+              x="-12.7"
+              y="35.5"
+            >
+              <g filter="url(#Adobe_OpacityMaskFilter_22_)">
+                <path
+                  id="path-167_3_"
+                  clip-rule="evenodd"
+                  d="M70.3,14.7c0,0.3,0,0.5,0,0.7
+							c1.5-1.4,3.2-2.6,4.8-3.5c5.6-3.2,10.6-3.3,14-0.8l11.1,6.6l-7.1,11c-2.1,10-8.9,20.5-17.2,25.7L23.9,84.6L18,95.1L6.2,88l0,0
+							C2.4,85.8,0,81.2,0,74.5c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33
+							C61-3.8,70.3,1.6,70.3,14.7z"
+                  fill="#FFFFFF"
+                  fill-rule="evenodd"
+                />
+              </g>
+            </mask>
+
+            <linearGradient
+              id="SVGID_110_"
+              gradientTransform="matrix(76.2914 0 0 -67.1042 -3801.5762 110790.3594)"
+              gradientUnits="userSpaceOnUse"
+              x1="49.8816"
+              x2="50.4973"
+              y1="1649.8344"
+              y2="1650.4406"
+            >
+              <stop offset="0" style="stop-color: #4f3eff" />
+              <stop offset="0.4096" style="stop-color: #9c92ff" />
+              <stop offset="0.7979" style="stop-color: #2519da" />
+              <stop offset="1" style="stop-color: #0d04ab" />
+            </linearGradient>
+            <path
+              clip-rule="evenodd"
+              d="M29.1,35.9l29.3,15.6
+					l5.2,15.3C41,92.3,25.4,104.1,16.8,102.4c-8.7-1.7-18.5-18.7-29.5-50.9c10.3-7,18.4-11.6,24.2-13.7S23.1,35,29.1,35.9z"
+              fill="url(#SVGID_110_)"
+              fill-rule="evenodd"
+              mask="url(#mask-168_3_)"
+            />
+          </g>
+
+          <linearGradient
+            id="Fill-1澶囦唤_1_"
+            gradientTransform="matrix(93.8386 0 0 -89.2609 -4672.3262 147666.9375)"
+            gradientUnits="userSpaceOnUse"
+            x1="50.6106"
+            x2="50.1002"
+            y1="1654.2188"
+            y2="1652.9083"
+          >
+            <stop offset="0" style="stop-color: #5e51e4" />
+            <stop offset="1" style="stop-color: #060071" />
+          </linearGradient>
+          <path
+            id="Fill-1澶囦唤"
+            clip-rule="evenodd"
+            d="M86.6,18.8
+				c10.3-6,18.6-1.1,18.7,10.7c0,11.6-7.9,25.6-17.9,31.8l-55.2,32l-0.4,0.2c-11.3,6.3-20.3,0.9-20.4-12.1
+				c0-13.1,9.2-29.2,20.6-35.8c3-1.7,5.9-2.7,8.4-2.8c1.1-12.6,9.9-26.9,20.5-33c11.4-6.6,20.7-1.3,20.8,11.9c0,0.3,0,0.5,0,0.7
+				C83.3,21,84.9,19.7,86.6,18.8"
+            fill="url(#Fill-1澶囦唤_1_)"
+            fill-rule="evenodd"
+          />
+        </g>
+      </g>
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/authentication/index.ts b/eims-ui/packages/effects/layouts/src/authentication/index.ts
new file mode 100644
index 0000000..6c684d1
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/index.ts
@@ -0,0 +1 @@
+export { default as AuthPageLayout } from './authentication.vue';
diff --git a/eims-ui/packages/effects/layouts/src/authentication/toolbar.vue b/eims-ui/packages/effects/layouts/src/authentication/toolbar.vue
new file mode 100644
index 0000000..94d321a
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/toolbar.vue
@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import type { ToolbarType } from './types';
+
+import { computed } from 'vue';
+
+import { preferences } from '@vben/preferences';
+
+import {
+  AuthenticationColorToggle,
+  AuthenticationLayoutToggle,
+  LanguageToggle,
+  ThemeToggle,
+} from '../widgets';
+
+interface Props {
+  toolbarList?: ToolbarType[];
+}
+
+defineOptions({
+  name: 'AuthenticationToolbar',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  toolbarList: () => ['color', 'language', 'layout', 'theme'],
+});
+
+const showColor = computed(() => props.toolbarList.includes('color'));
+const showLayout = computed(() => props.toolbarList.includes('layout'));
+const showLanguage = computed(() => props.toolbarList.includes('language'));
+const showTheme = computed(() => props.toolbarList.includes('theme'));
+</script>
+
+<template>
+  <div
+    :class="{
+      'bg-accent rounded-3xl px-3 py-1': toolbarList.length > 1,
+    }"
+    class="flex-center absolute right-2 top-4 z-10"
+  >
+    <!-- Only show on medium and larger screens -->
+    <div class="hidden md:flex">
+      <AuthenticationColorToggle v-if="showColor" />
+      <AuthenticationLayoutToggle v-if="showLayout" />
+    </div>
+    <!-- Always show Language and Theme toggles -->
+    <LanguageToggle v-if="showLanguage && preferences.widget.languageToggle" />
+    <ThemeToggle v-if="showTheme && preferences.widget.themeToggle" />
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/authentication/types.ts b/eims-ui/packages/effects/layouts/src/authentication/types.ts
new file mode 100644
index 0000000..c4c1c7f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/authentication/types.ts
@@ -0,0 +1 @@
+export type ToolbarType = 'color' | 'language' | 'layout' | 'theme';
diff --git a/eims-ui/packages/effects/layouts/src/basic/README.md b/eims-ui/packages/effects/layouts/src/basic/README.md
new file mode 100644
index 0000000..b1266ea
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/README.md
@@ -0,0 +1,7 @@
+## layout
+
+### header
+
+- 鏀寔N涓嚜瀹氫箟鎻掓Ы锛屽懡鍚嶆柟寮忥細header-right-n锛宧eader-left-n
+- header-left-n 锛屾帓搴忔柟寮忥細0-19 ,breadcrumb 21-x
+- header-right-n 锛屾帓搴忔柟寮忥細0-49锛実lobal-search锛�51-59锛宼heme-toggle锛�61-69锛宭anguage-toggle锛�71-79锛宖ullscreen锛�81-89锛宯otification锛�91-149锛寀ser-dropdown锛�151-x
diff --git a/eims-ui/packages/effects/layouts/src/basic/content/content-spinner.vue b/eims-ui/packages/effects/layouts/src/basic/content/content-spinner.vue
new file mode 100644
index 0000000..e97e4b6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/content/content-spinner.vue
@@ -0,0 +1,12 @@
+<script lang="ts" setup>
+import { VbenSpinner } from '@vben-core/shadcn-ui';
+
+import { useContentSpinner } from './use-content-spinner';
+
+defineOptions({ name: 'LayoutContentSpinner' });
+
+const { spinning } = useContentSpinner();
+</script>
+<template>
+  <VbenSpinner :spinning="spinning" />
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/content/content.vue b/eims-ui/packages/effects/layouts/src/basic/content/content.vue
new file mode 100644
index 0000000..4ce9e4d
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/content/content.vue
@@ -0,0 +1,114 @@
+<script lang="ts" setup>
+import type {
+  RouteLocationNormalizedLoaded,
+  RouteLocationNormalizedLoadedGeneric,
+} from 'vue-router';
+
+import { type VNode } from 'vue';
+import { RouterView } from 'vue-router';
+
+import { preferences, usePreferences } from '@vben/preferences';
+import { storeToRefs, useTabbarStore } from '@vben/stores';
+
+import { IFrameRouterView } from '../../iframe';
+
+defineOptions({ name: 'LayoutContent' });
+
+const tabbarStore = useTabbarStore();
+const { keepAlive } = usePreferences();
+
+const { getCachedTabs, getExcludeCachedTabs, renderRouteView } =
+  storeToRefs(tabbarStore);
+
+// 椤甸潰鍒囨崲鍔ㄧ敾
+function getTransitionName(_route: RouteLocationNormalizedLoaded) {
+  // 濡傛灉鍋忓ソ璁剧疆鏈缃紝鍒欎笉浣跨敤鍔ㄧ敾
+  const { tabbar, transition } = preferences;
+  const transitionName = transition.name;
+  if (!transitionName || !transition.enable) {
+    return;
+  }
+
+  // 鏍囩椤垫湭鍚敤鎴栬�呮湭寮�鍚紦瀛橈紝鍒欎娇鐢ㄥ叏灞�閰嶇疆鍔ㄧ敾
+  if (!tabbar.enable || !keepAlive) {
+    return transitionName;
+  }
+
+  // 濡傛灉椤甸潰宸茬粡鍔犺浇杩囷紝鍒欎笉浣跨敤鍔ㄧ敾
+  // if (route.meta.loaded) {
+  //   return;
+  // }
+  // 宸茬粡鎵撳紑涓斿凡缁忓姞杞借繃鐨勯〉闈笉浣跨敤鍔ㄧ敾
+  // const inTabs = getCachedTabs.value.includes(route.name as string);
+
+  // return inTabs && route.meta.loaded ? undefined : transitionName;
+  return transitionName;
+}
+
+/**
+ * 杞崲缁勪欢锛岃嚜鍔ㄦ坊鍔� name
+ * @param component
+ */
+function transformComponent(
+  component: VNode,
+  route: RouteLocationNormalizedLoadedGeneric,
+) {
+  // 缁勪欢瑙嗗浘鏈壘鍒帮紝濡傛灉鏈夎缃悗澶囪鍥撅紝鍒欒繑鍥炲悗澶囪鍥撅紝濡傛灉娌℃湁锛屽垯鎶涘嚭閿欒
+  if (!component) {
+    console.error(
+      'Component view not found锛宲lease check the route configuration',
+    );
+    return undefined;
+  }
+
+  const routeName = route.name as string;
+  // 濡傛灉缁勪欢娌℃湁 name锛屽垯鐩存帴杩斿洖
+  if (!routeName) {
+    return component;
+  }
+  const componentName = (component?.type as any)?.name;
+
+  // 宸茬粡璁剧疆杩� name锛屽垯鐩存帴杩斿洖
+  if (componentName) {
+    return component;
+  }
+
+  // componentName 涓� routeName 涓�鑷达紝鍒欑洿鎺ヨ繑鍥�
+  if (componentName === routeName) {
+    return component;
+  }
+
+  // 璁剧疆 name
+  component.type ||= {};
+  (component.type as any).name = routeName;
+
+  return component;
+}
+</script>
+
+<template>
+  <div class="relative h-full">
+    <IFrameRouterView />
+    <RouterView v-slot="{ Component, route }">
+      <Transition :name="getTransitionName(route)" appear mode="out-in">
+        <KeepAlive
+          v-if="keepAlive"
+          :exclude="getExcludeCachedTabs"
+          :include="getCachedTabs"
+        >
+          <component
+            :is="transformComponent(Component, route)"
+            v-if="renderRouteView"
+            v-show="!route.meta.iframeSrc"
+            :key="route.fullPath"
+          />
+        </KeepAlive>
+        <component
+          :is="Component"
+          v-else-if="renderRouteView"
+          :key="route.fullPath"
+        />
+      </Transition>
+    </RouterView>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/content/index.ts b/eims-ui/packages/effects/layouts/src/basic/content/index.ts
new file mode 100644
index 0000000..500cbcc
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/content/index.ts
@@ -0,0 +1,2 @@
+export { default as LayoutContent } from './content.vue';
+export { default as LayoutContentSpinner } from './content-spinner.vue';
diff --git a/eims-ui/packages/effects/layouts/src/basic/content/use-content-spinner.ts b/eims-ui/packages/effects/layouts/src/basic/content/use-content-spinner.ts
new file mode 100644
index 0000000..dfe3c53
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/content/use-content-spinner.ts
@@ -0,0 +1,50 @@
+import { computed, ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { preferences } from '@vben/preferences';
+
+function useContentSpinner() {
+  const spinning = ref(false);
+  const startTime = ref(0);
+  const router = useRouter();
+  const minShowTime = 500; // 鏈�灏忔樉绀烘椂闂�
+  const enableLoading = computed(() => preferences.transition.loading);
+
+  // 缁撴潫鍔犺浇鍔ㄧ敾
+  const onEnd = () => {
+    if (!enableLoading.value) {
+      return;
+    }
+    const processTime = performance.now() - startTime.value;
+    if (processTime < minShowTime) {
+      setTimeout(() => {
+        spinning.value = false;
+      }, minShowTime - processTime);
+    } else {
+      spinning.value = false;
+    }
+  };
+
+  // 璺敱鍓嶇疆瀹堝崼
+  router.beforeEach((to) => {
+    if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) {
+      return true;
+    }
+    startTime.value = performance.now();
+    spinning.value = true;
+    return true;
+  });
+
+  // 璺敱鍚庣疆瀹堝崼
+  router.afterEach((to) => {
+    if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) {
+      return true;
+    }
+    onEnd();
+    return true;
+  });
+
+  return { spinning };
+}
+
+export { useContentSpinner };
diff --git a/eims-ui/packages/effects/layouts/src/basic/copyright/copyright.vue b/eims-ui/packages/effects/layouts/src/basic/copyright/copyright.vue
new file mode 100644
index 0000000..8202076
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/copyright/copyright.vue
@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+interface Props {
+  companyName: string;
+  companySiteLink?: string;
+  date: string;
+  icp?: string;
+  icpLink?: string;
+}
+
+defineOptions({
+  name: 'Copyright',
+});
+
+withDefaults(defineProps<Props>(), {
+  companyName: 'Vben Admin',
+  companySiteLink: '',
+  date: '2024',
+  icp: '',
+  icpLink: '',
+});
+</script>
+
+<template>
+  <div class="text-md flex-center">
+    <!-- ICP Link -->
+    <a
+      v-if="icp"
+      :href="icpLink || 'javascript:void(0)'"
+      class="hover:text-primary-hover mx-1"
+      target="_blank"
+    >
+      {{ icp }}
+    </a>
+
+    <!-- Copyright Text -->
+    Copyright 漏 {{ date }}
+
+    <!-- Company Link -->
+    <a
+      v-if="companyName"
+      :href="companySiteLink || 'javascript:void(0)'"
+      class="hover:text-primary-hover mx-1"
+      target="_blank"
+    >
+      {{ companyName }}
+    </a>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/copyright/index.ts b/eims-ui/packages/effects/layouts/src/basic/copyright/index.ts
new file mode 100644
index 0000000..e0620da
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/copyright/index.ts
@@ -0,0 +1 @@
+export { default as Copyright } from './copyright.vue';
diff --git a/eims-ui/packages/effects/layouts/src/basic/footer/footer.vue b/eims-ui/packages/effects/layouts/src/basic/footer/footer.vue
new file mode 100644
index 0000000..6fc256d
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/footer/footer.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+defineOptions({
+  name: 'LayoutFooter',
+});
+</script>
+
+<template>
+  <div class="flex-center text-muted-foreground relative h-full w-full text-xs">
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/footer/index.ts b/eims-ui/packages/effects/layouts/src/basic/footer/index.ts
new file mode 100644
index 0000000..7e149a2
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/footer/index.ts
@@ -0,0 +1 @@
+export { default as LayoutFooter } from './footer.vue';
diff --git a/eims-ui/packages/effects/layouts/src/basic/header/header.vue b/eims-ui/packages/effects/layouts/src/basic/header/header.vue
new file mode 100644
index 0000000..546342b
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/header/header.vue
@@ -0,0 +1,168 @@
+<script lang="ts" setup>
+import { computed, useSlots } from 'vue';
+
+import { useRefresh } from '@vben/hooks';
+import { RotateCw } from '@vben/icons';
+import { preferences, usePreferences } from '@vben/preferences';
+import { useAccessStore } from '@vben/stores';
+import { VbenFullScreen, VbenIconButton } from '@vben-core/shadcn-ui';
+
+import {
+  GlobalSearch,
+  LanguageToggle,
+  PreferencesButton,
+  ThemeToggle,
+} from '../../widgets';
+
+interface Props {
+  /**
+   * Logo 涓婚
+   */
+  theme?: string;
+}
+
+defineOptions({
+  name: 'LayoutHeader',
+});
+
+withDefaults(defineProps<Props>(), {
+  theme: 'light',
+});
+
+const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
+
+const REFERENCE_VALUE = 50;
+
+const accessStore = useAccessStore();
+const { globalSearchShortcutKey, preferencesButtonPosition } = usePreferences();
+const slots = useSlots();
+const { refresh } = useRefresh();
+
+const rightSlots = computed(() => {
+  const list = [{ index: REFERENCE_VALUE + 100, name: 'user-dropdown' }];
+  if (preferences.widget.globalSearch) {
+    list.push({
+      index: REFERENCE_VALUE,
+      name: 'global-search',
+    });
+  }
+
+  if (preferencesButtonPosition.value.header) {
+    list.push({
+      index: REFERENCE_VALUE + 10,
+      name: 'preferences',
+    });
+  }
+  if (preferences.widget.themeToggle) {
+    list.push({
+      index: REFERENCE_VALUE + 20,
+      name: 'theme-toggle',
+    });
+  }
+  if (preferences.widget.languageToggle) {
+    list.push({
+      index: REFERENCE_VALUE + 30,
+      name: 'language-toggle',
+    });
+  }
+  if (preferences.widget.fullscreen) {
+    list.push({
+      index: REFERENCE_VALUE + 40,
+      name: 'fullscreen',
+    });
+  }
+  if (preferences.widget.notification) {
+    list.push({
+      index: REFERENCE_VALUE + 50,
+      name: 'notification',
+    });
+  }
+
+  Object.keys(slots).forEach((key) => {
+    const name = key.split('-');
+    if (key.startsWith('header-right')) {
+      list.push({ index: Number(name[2]), name: key });
+    }
+  });
+  return list.sort((a, b) => a.index - b.index);
+});
+
+const leftSlots = computed(() => {
+  const list: Array<{ index: number; name: string }> = [];
+
+  if (preferences.widget.refresh) {
+    list.push({
+      index: 0,
+      name: 'refresh',
+    });
+  }
+
+  Object.keys(slots).forEach((key) => {
+    const name = key.split('-');
+    if (key.startsWith('header-left')) {
+      list.push({ index: Number(name[2]), name: key });
+    }
+  });
+  return list.sort((a, b) => a.index - b.index);
+});
+
+function clearPreferencesAndLogout() {
+  emit('clearPreferencesAndLogout');
+}
+</script>
+
+<template>
+  <template
+    v-for="slot in leftSlots.filter((item) => item.index < REFERENCE_VALUE)"
+    :key="slot.name"
+  >
+    <slot :name="slot.name">
+      <template v-if="slot.name === 'refresh'">
+        <VbenIconButton class="my-0 mr-1 rounded-md" @click="refresh">
+          <RotateCw class="size-4" />
+        </VbenIconButton>
+      </template>
+    </slot>
+  </template>
+  <div class="flex-center hidden lg:block">
+    <slot name="breadcrumb"></slot>
+  </div>
+  <template
+    v-for="slot in leftSlots.filter((item) => item.index > REFERENCE_VALUE)"
+    :key="slot.name"
+  >
+    <slot :name="slot.name"></slot>
+  </template>
+  <div class="flex h-full min-w-0 flex-1 items-center">
+    <slot name="menu"></slot>
+  </div>
+  <div class="flex h-full min-w-0 flex-shrink-0 items-center">
+    <template v-for="slot in rightSlots" :key="slot.name">
+      <slot :name="slot.name">
+        <template v-if="slot.name === 'global-search'">
+          <GlobalSearch
+            :enable-shortcut-key="globalSearchShortcutKey"
+            :menus="accessStore.accessMenus"
+            class="mr-1 sm:mr-4"
+          />
+        </template>
+
+        <template v-else-if="slot.name === 'preferences'">
+          <PreferencesButton
+            class="mr-1"
+            @clear-preferences-and-logout="clearPreferencesAndLogout"
+          />
+        </template>
+        <template v-else-if="slot.name === 'theme-toggle'">
+          <ThemeToggle class="mr-1 mt-[2px]" />
+        </template>
+        <template v-else-if="slot.name === 'language-toggle'">
+          <LanguageToggle class="mr-1" />
+        </template>
+        <template v-else-if="slot.name === 'fullscreen'">
+          <VbenFullScreen class="mr-1" />
+        </template>
+      </slot>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/header/index.ts b/eims-ui/packages/effects/layouts/src/basic/header/index.ts
new file mode 100644
index 0000000..44f0729
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/header/index.ts
@@ -0,0 +1 @@
+export { default as LayoutHeader } from './header.vue';
diff --git a/eims-ui/packages/effects/layouts/src/basic/index.ts b/eims-ui/packages/effects/layouts/src/basic/index.ts
new file mode 100644
index 0000000..b3a01cd
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/index.ts
@@ -0,0 +1 @@
+export { default as BasicLayout } from './layout.vue';
diff --git a/eims-ui/packages/effects/layouts/src/basic/layout.vue b/eims-ui/packages/effects/layouts/src/basic/layout.vue
new file mode 100644
index 0000000..5361177
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/layout.vue
@@ -0,0 +1,342 @@
+<script lang="ts" setup>
+import type { MenuRecordRaw } from '@vben/types';
+
+import { computed, useSlots, watch } from 'vue';
+
+import { useRefresh } from '@vben/hooks';
+import { $t } from '@vben/locales';
+import {
+  preferences,
+  updatePreferences,
+  usePreferences,
+} from '@vben/preferences';
+import { useLockStore } from '@vben/stores';
+import { cloneDeep, mapTree } from '@vben/utils';
+import { VbenAdminLayout } from '@vben-core/layout-ui';
+import { VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
+
+import { Breadcrumb, CheckUpdates, Preferences } from '../widgets';
+import { LayoutContent, LayoutContentSpinner } from './content';
+import { Copyright } from './copyright';
+import { LayoutFooter } from './footer';
+import { LayoutHeader } from './header';
+import {
+  LayoutExtraMenu,
+  LayoutMenu,
+  LayoutMixedMenu,
+  useExtraMenu,
+  useMixedMenu,
+} from './menu';
+import { LayoutTabbar } from './tabbar';
+
+defineOptions({ name: 'BasicLayout' });
+
+const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
+
+const {
+  isDark,
+  isHeaderNav,
+  isMixedNav,
+  isMobile,
+  isSideMixedNav,
+  layout,
+  preferencesButtonPosition,
+  sidebarCollapsed,
+  theme,
+} = usePreferences();
+const lockStore = useLockStore();
+const { refresh } = useRefresh();
+
+const sidebarTheme = computed(() => {
+  const dark = isDark.value || preferences.theme.semiDarkSidebar;
+  return dark ? 'dark' : 'light';
+});
+
+const headerTheme = computed(() => {
+  const dark = isDark.value || preferences.theme.semiDarkHeader;
+  return dark ? 'dark' : 'light';
+});
+
+const logoClass = computed(() => {
+  const { collapsedShowTitle } = preferences.sidebar;
+  const classes: string[] = [];
+
+  if (collapsedShowTitle && sidebarCollapsed.value && !isMixedNav.value) {
+    classes.push('mx-auto');
+  }
+
+  if (isSideMixedNav.value) {
+    classes.push('flex-center');
+  }
+
+  return classes.join(' ');
+});
+
+const isMenuRounded = computed(() => {
+  return preferences.navigation.styleType === 'rounded';
+});
+
+const logoCollapsed = computed(() => {
+  if (isMobile.value && sidebarCollapsed.value) {
+    return true;
+  }
+  if (isHeaderNav.value || isMixedNav.value) {
+    return false;
+  }
+  return sidebarCollapsed.value || isSideMixedNav.value;
+});
+
+const showHeaderNav = computed(() => {
+  return !isMobile.value && (isHeaderNav.value || isMixedNav.value);
+});
+
+// 渚ц竟澶氬垪鑿滃崟
+const {
+  extraActiveMenu,
+  extraMenus,
+  handleDefaultSelect,
+  handleMenuMouseEnter,
+  handleMixedMenuSelect,
+  handleSideMouseLeave,
+  sidebarExtraVisible,
+} = useExtraMenu();
+
+const {
+  handleMenuSelect,
+  headerActive,
+  headerMenus,
+  sidebarActive,
+  sidebarMenus,
+  sidebarVisible,
+} = useMixedMenu();
+
+/**
+ * 鍖呰鑿滃崟锛岀炕璇戣彍鍗曞悕绉�
+ * @param menus 鍘熷鑿滃崟鏁版嵁
+ * @param deep 鏄惁娣卞害鍖呰銆傚浜庡弻鍒楀竷灞�锛屽彧闇�瑕佸寘瑁呯涓�灞傦紝鍥犱负鏇存繁灞傜殑鏁版嵁浼氬湪鎵╁睍鑿滃崟涓噸鏂板寘瑁�
+ */
+function wrapperMenus(menus: MenuRecordRaw[], deep: boolean = true) {
+  return deep
+    ? mapTree(menus, (item) => {
+        return { ...cloneDeep(item), name: $t(item.name) };
+      })
+    : menus.map((item) => {
+        return { ...cloneDeep(item), name: $t(item.name) };
+      });
+}
+
+function toggleSidebar() {
+  updatePreferences({
+    sidebar: {
+      hidden: !preferences.sidebar.hidden,
+    },
+  });
+}
+
+function clearPreferencesAndLogout() {
+  emit('clearPreferencesAndLogout');
+}
+
+watch(
+  () => preferences.app.layout,
+  async (val) => {
+    if (val === 'sidebar-mixed-nav' && preferences.sidebar.hidden) {
+      updatePreferences({
+        sidebar: {
+          hidden: false,
+        },
+      });
+    }
+  },
+);
+
+// 璇█鏇存柊鍚庯紝鍒锋柊椤甸潰
+watch(() => preferences.app.locale, refresh);
+
+const slots = useSlots();
+const headerSlots = computed(() => {
+  return Object.keys(slots).filter((key) => key.startsWith('header-'));
+});
+</script>
+
+<template>
+  <VbenAdminLayout
+    v-model:sidebar-extra-visible="sidebarExtraVisible"
+    :content-compact="preferences.app.contentCompact"
+    :footer-enable="preferences.footer.enable"
+    :footer-fixed="preferences.footer.fixed"
+    :header-hidden="preferences.header.hidden"
+    :header-mode="preferences.header.mode"
+    :header-theme="headerTheme"
+    :header-toggle-sidebar-button="preferences.widget.sidebarToggle"
+    :header-visible="preferences.header.enable"
+    :is-mobile="preferences.app.isMobile"
+    :layout="layout"
+    :sidebar-collapse="preferences.sidebar.collapsed"
+    :sidebar-collapse-show-title="preferences.sidebar.collapsedShowTitle"
+    :sidebar-enable="sidebarVisible"
+    :sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
+    :sidebar-extra-collapse="preferences.sidebar.extraCollapse"
+    :sidebar-hidden="preferences.sidebar.hidden"
+    :sidebar-theme="sidebarTheme"
+    :sidebar-width="preferences.sidebar.width"
+    :tabbar-enable="preferences.tabbar.enable"
+    :tabbar-height="preferences.tabbar.height"
+    @side-mouse-leave="handleSideMouseLeave"
+    @toggle-sidebar="toggleSidebar"
+    @update:sidebar-collapse="
+      (value: boolean) => updatePreferences({ sidebar: { collapsed: value } })
+    "
+    @update:sidebar-enable="
+      (value: boolean) => updatePreferences({ sidebar: { enable: value } })
+    "
+    @update:sidebar-expand-on-hover="
+      (value: boolean) =>
+        updatePreferences({ sidebar: { expandOnHover: value } })
+    "
+    @update:sidebar-extra-collapse="
+      (value: boolean) =>
+        updatePreferences({ sidebar: { extraCollapse: value } })
+    "
+  >
+    <!-- logo -->
+    <template #logo>
+      <VbenLogo
+        v-if="preferences.logo.enable"
+        :class="logoClass"
+        :collapsed="logoCollapsed"
+        :src="preferences.logo.source"
+        :text="preferences.app.name"
+        :theme="showHeaderNav ? headerTheme : theme"
+      />
+    </template>
+    <!-- 澶撮儴鍖哄煙 -->
+    <template #header>
+      <LayoutHeader
+        :theme="theme"
+        @clear-preferences-and-logout="clearPreferencesAndLogout"
+      >
+        <template
+          v-if="!showHeaderNav && preferences.breadcrumb.enable"
+          #breadcrumb
+        >
+          <Breadcrumb
+            :hide-when-only-one="preferences.breadcrumb.hideOnlyOne"
+            :show-home="preferences.breadcrumb.showHome"
+            :show-icon="preferences.breadcrumb.showIcon"
+            :type="preferences.breadcrumb.styleType"
+          />
+        </template>
+        <template v-if="showHeaderNav" #menu>
+          <LayoutMenu
+            :default-active="headerActive"
+            :menus="wrapperMenus(headerMenus)"
+            :rounded="isMenuRounded"
+            :theme="headerTheme"
+            class="w-full"
+            mode="horizontal"
+            @select="handleMenuSelect"
+          />
+        </template>
+        <template #user-dropdown>
+          <slot name="user-dropdown"></slot>
+        </template>
+        <template #notification>
+          <slot name="notification"></slot>
+        </template>
+        <template v-for="item in headerSlots" #[item]>
+          <slot :name="item"></slot>
+        </template>
+      </LayoutHeader>
+    </template>
+    <!-- 渚ц竟鑿滃崟鍖哄煙 -->
+    <template #menu>
+      <LayoutMenu
+        :accordion="preferences.navigation.accordion"
+        :collapse="preferences.sidebar.collapsed"
+        :collapse-show-title="preferences.sidebar.collapsedShowTitle"
+        :default-active="sidebarActive"
+        :menus="wrapperMenus(sidebarMenus)"
+        :rounded="isMenuRounded"
+        :theme="sidebarTheme"
+        mode="vertical"
+        @select="handleMenuSelect"
+      />
+    </template>
+    <template #mixed-menu>
+      <LayoutMixedMenu
+        :active-path="extraActiveMenu"
+        :menus="wrapperMenus(headerMenus, false)"
+        :rounded="isMenuRounded"
+        :theme="sidebarTheme"
+        @default-select="handleDefaultSelect"
+        @enter="handleMenuMouseEnter"
+        @select="handleMixedMenuSelect"
+      />
+    </template>
+    <!-- 渚ц竟棰濆鍖哄煙 -->
+    <template #side-extra>
+      <LayoutExtraMenu
+        :accordion="preferences.navigation.accordion"
+        :collapse="preferences.sidebar.extraCollapse"
+        :menus="wrapperMenus(extraMenus)"
+        :rounded="isMenuRounded"
+        :theme="sidebarTheme"
+      />
+    </template>
+    <template #side-extra-title>
+      <VbenLogo
+        v-if="preferences.logo.enable"
+        :text="preferences.app.name"
+        :theme="theme"
+      />
+    </template>
+
+    <template #tabbar>
+      <LayoutTabbar
+        v-if="preferences.tabbar.enable"
+        :show-icon="preferences.tabbar.showIcon"
+        :theme="theme"
+      />
+    </template>
+
+    <!-- 涓讳綋鍐呭 -->
+    <template #content>
+      <LayoutContent />
+    </template>
+
+    <template v-if="preferences.transition.loading" #content-overlay>
+      <LayoutContentSpinner />
+    </template>
+
+    <!-- 椤佃剼 -->
+    <template v-if="preferences.footer.enable" #footer>
+      <LayoutFooter>
+        <Copyright
+          v-if="preferences.copyright.enable"
+          v-bind="preferences.copyright"
+        />
+      </LayoutFooter>
+    </template>
+
+    <template #extra>
+      <slot name="extra"></slot>
+      <CheckUpdates
+        v-if="preferences.app.enableCheckUpdates"
+        :check-updates-interval="preferences.app.checkUpdatesInterval"
+      />
+
+      <Transition v-if="preferences.widget.lockScreen" name="slide-up">
+        <slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
+      </Transition>
+
+      <template v-if="preferencesButtonPosition.fixed">
+        <Preferences
+          class="z-100 fixed bottom-20 right-0"
+          @clear-preferences-and-logout="clearPreferencesAndLogout"
+        />
+      </template>
+      <VbenBackTop />
+    </template>
+  </VbenAdminLayout>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/extra-menu.vue b/eims-ui/packages/effects/layouts/src/basic/menu/extra-menu.vue
new file mode 100644
index 0000000..d8ccc1b
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/extra-menu.vue
@@ -0,0 +1,40 @@
+<script lang="ts" setup>
+import type { MenuRecordRaw } from '@vben/types';
+import type { MenuProps } from '@vben-core/menu-ui';
+
+import { useRoute } from 'vue-router';
+
+import { Menu } from '@vben-core/menu-ui';
+
+import { useNavigation } from './use-navigation';
+
+interface Props extends MenuProps {
+  collapse?: boolean;
+  menus: MenuRecordRaw[];
+}
+
+withDefaults(defineProps<Props>(), {
+  accordion: true,
+  menus: () => [],
+});
+
+const route = useRoute();
+const { navigation } = useNavigation();
+
+async function handleSelect(key: string) {
+  await navigation(key);
+}
+</script>
+
+<template>
+  <Menu
+    :accordion="accordion"
+    :collapse="collapse"
+    :default-active="route.meta?.activePath || route.path"
+    :menus="menus"
+    :rounded="rounded"
+    :theme="theme"
+    mode="vertical"
+    @select="handleSelect"
+  />
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/index.ts b/eims-ui/packages/effects/layouts/src/basic/menu/index.ts
new file mode 100644
index 0000000..72b87ad
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/index.ts
@@ -0,0 +1,5 @@
+export { default as LayoutExtraMenu } from './extra-menu.vue';
+export { default as LayoutMenu } from './menu.vue';
+export { default as LayoutMixedMenu } from './mixed-menu.vue';
+export * from './use-extra-menu';
+export * from './use-mixed-menu';
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/menu.vue b/eims-ui/packages/effects/layouts/src/basic/menu/menu.vue
new file mode 100644
index 0000000..11c34e1
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/menu.vue
@@ -0,0 +1,37 @@
+<script lang="ts" setup>
+import type { MenuRecordRaw } from '@vben/types';
+import type { MenuProps } from '@vben-core/menu-ui';
+
+import { Menu } from '@vben-core/menu-ui';
+
+interface Props extends MenuProps {
+  menus: MenuRecordRaw[];
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  accordion: true,
+  menus: () => [],
+});
+
+const emit = defineEmits<{
+  select: [string, string?];
+}>();
+
+function handleMenuSelect(key: string) {
+  emit('select', key, props.mode);
+}
+</script>
+
+<template>
+  <Menu
+    :accordion="accordion"
+    :collapse="collapse"
+    :collapse-show-title="collapseShowTitle"
+    :default-active="defaultActive"
+    :menus="menus"
+    :mode="mode"
+    :rounded="rounded"
+    :theme="theme"
+    @select="handleMenuSelect"
+  />
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/mixed-menu.vue b/eims-ui/packages/effects/layouts/src/basic/menu/mixed-menu.vue
new file mode 100644
index 0000000..b54bc48
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/mixed-menu.vue
@@ -0,0 +1,44 @@
+<script lang="ts" setup>
+import type { MenuRecordRaw } from '@vben/types';
+import type { NormalMenuProps } from '@vben-core/menu-ui';
+
+import { onBeforeMount } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { findMenuByPath } from '@vben/utils';
+import { NormalMenu } from '@vben-core/menu-ui';
+
+interface Props extends NormalMenuProps {}
+
+const props = defineProps<Props>();
+
+const emit = defineEmits<{
+  defaultSelect: [MenuRecordRaw, MenuRecordRaw?];
+  enter: [MenuRecordRaw];
+  select: [MenuRecordRaw];
+}>();
+
+const route = useRoute();
+
+onBeforeMount(() => {
+  const menu = findMenuByPath(props.menus || [], route.path);
+  if (menu) {
+    const rootMenu = (props.menus || []).find(
+      (item) => item.path === menu.parents?.[0],
+    );
+    emit('defaultSelect', menu, rootMenu);
+  }
+});
+</script>
+
+<template>
+  <NormalMenu
+    :active-path="activePath"
+    :collapse="collapse"
+    :menus="menus"
+    :rounded="rounded"
+    :theme="theme"
+    @enter="(menu) => emit('enter', menu)"
+    @select="(menu) => emit('select', menu)"
+  />
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/use-extra-menu.ts b/eims-ui/packages/effects/layouts/src/basic/menu/use-extra-menu.ts
new file mode 100644
index 0000000..a1c6d3f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/use-extra-menu.ts
@@ -0,0 +1,109 @@
+import type { MenuRecordRaw } from '@vben/types';
+
+import { computed, ref, watch } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { preferences } from '@vben/preferences';
+import { useAccessStore } from '@vben/stores';
+import { findRootMenuByPath } from '@vben/utils';
+
+import { useNavigation } from './use-navigation';
+
+function useExtraMenu() {
+  const accessStore = useAccessStore();
+  const { navigation } = useNavigation();
+
+  const menus = computed(() => accessStore.accessMenus);
+
+  const route = useRoute();
+  const extraMenus = ref<MenuRecordRaw[]>([]);
+  const sidebarExtraVisible = ref<boolean>(false);
+  const extraActiveMenu = ref('');
+
+  /**
+   * 閫夋嫨娣峰悎鑿滃崟浜嬩欢
+   * @param menu
+   */
+  const handleMixedMenuSelect = async (menu: MenuRecordRaw) => {
+    extraMenus.value = menu?.children ?? [];
+    extraActiveMenu.value = menu.parents?.[0] ?? menu.path;
+    const hasChildren = extraMenus.value.length > 0;
+
+    sidebarExtraVisible.value = hasChildren;
+    if (!hasChildren) {
+      await navigation(menu.path);
+    }
+  };
+
+  /**
+   * 閫夋嫨榛樿鑿滃崟浜嬩欢
+   * @param menu
+   * @param rootMenu
+   */
+  const handleDefaultSelect = (
+    menu: MenuRecordRaw,
+    rootMenu?: MenuRecordRaw,
+  ) => {
+    extraMenus.value = rootMenu?.children ?? [];
+    extraActiveMenu.value = menu.parents?.[0] ?? menu.path;
+
+    if (preferences.sidebar.expandOnHover) {
+      sidebarExtraVisible.value = extraMenus.value.length > 0;
+    }
+  };
+
+  /**
+   * 渚ц竟鑿滃崟榧犳爣绉诲嚭浜嬩欢
+   */
+  const handleSideMouseLeave = () => {
+    if (preferences.sidebar.expandOnHover) {
+      return;
+    }
+    sidebarExtraVisible.value = false;
+
+    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
+      menus.value,
+      route.path,
+    );
+    extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
+    extraMenus.value = rootMenu?.children ?? [];
+  };
+
+  const handleMenuMouseEnter = (menu: MenuRecordRaw) => {
+    if (!preferences.sidebar.expandOnHover) {
+      const { findMenu } = findRootMenuByPath(menus.value, menu.path);
+      extraMenus.value = findMenu?.children ?? [];
+      extraActiveMenu.value = menu.parents?.[0] ?? menu.path;
+      sidebarExtraVisible.value = extraMenus.value.length > 0;
+    }
+  };
+
+  watch(
+    () => route.path,
+    (path) => {
+      const currentPath = route.meta?.activePath || path;
+      // if (preferences.sidebar.expandOnHover) {
+      //   return;
+      // }
+      const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
+        menus.value,
+        currentPath,
+      );
+      extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? '';
+      extraMenus.value = rootMenu?.children ?? [];
+    },
+    { immediate: true },
+  );
+
+  return {
+    extraActiveMenu,
+    extraMenus,
+    handleDefaultSelect,
+    handleMenuMouseEnter,
+    handleMixedMenuSelect,
+    handleSideMouseLeave,
+    sidebarExtraVisible,
+  };
+}
+
+export { useExtraMenu };
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts b/eims-ui/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts
new file mode 100644
index 0000000..ca78fc0
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts
@@ -0,0 +1,129 @@
+import type { MenuRecordRaw } from '@vben/types';
+
+import { computed, onBeforeMount, ref, watch } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { preferences, usePreferences } from '@vben/preferences';
+import { useAccessStore } from '@vben/stores';
+import { findRootMenuByPath } from '@vben/utils';
+
+import { useNavigation } from './use-navigation';
+
+function useMixedMenu() {
+  const { navigation } = useNavigation();
+  const accessStore = useAccessStore();
+  const route = useRoute();
+  const splitSideMenus = ref<MenuRecordRaw[]>([]);
+  const rootMenuPath = ref<string>('');
+
+  const { isMixedNav } = usePreferences();
+
+  const needSplit = computed(
+    () => preferences.navigation.split && isMixedNav.value,
+  );
+
+  const sidebarVisible = computed(() => {
+    const enableSidebar = preferences.sidebar.enable;
+    if (needSplit.value) {
+      return enableSidebar && splitSideMenus.value.length > 0;
+    }
+    return enableSidebar;
+  });
+  const menus = computed(() => accessStore.accessMenus);
+
+  /**
+   * 澶撮儴鑿滃崟
+   */
+  const headerMenus = computed(() => {
+    if (!needSplit.value) {
+      return menus.value;
+    }
+    return menus.value.map((item) => {
+      return {
+        ...item,
+        children: [],
+      };
+    });
+  });
+
+  /**
+   * 渚ц竟鑿滃崟
+   */
+  const sidebarMenus = computed(() => {
+    return needSplit.value ? splitSideMenus.value : menus.value;
+  });
+
+  /**
+   * 渚ц竟鑿滃崟婵�娲昏矾寰�
+   */
+  const sidebarActive = computed(() => {
+    return (route?.meta?.activePath as string) ?? route.path;
+  });
+
+  /**
+   * 澶撮儴鑿滃崟婵�娲昏矾寰�
+   */
+  const headerActive = computed(() => {
+    if (!needSplit.value) {
+      return route.path;
+    }
+    return rootMenuPath.value;
+  });
+
+  /**
+   * 鑿滃崟鐐瑰嚮浜嬩欢澶勭悊
+   * @param key 鑿滃崟璺緞
+   * @param mode 鑿滃崟妯″紡
+   */
+  const handleMenuSelect = (key: string, mode?: string) => {
+    if (!needSplit.value || mode === 'vertical') {
+      navigation(key);
+      return;
+    }
+
+    const rootMenu = menus.value.find((item) => item.path === key);
+    rootMenuPath.value = rootMenu?.path ?? '';
+    splitSideMenus.value = rootMenu?.children ?? [];
+    if (splitSideMenus.value.length === 0) {
+      navigation(key);
+    }
+  };
+
+  /**
+   * 璁$畻渚ц竟鑿滃崟
+   * @param path 璺敱璺緞
+   */
+  function calcSideMenus(path: string = route.path) {
+    let { rootMenu } = findRootMenuByPath(menus.value, path);
+    if (!rootMenu) {
+      rootMenu = menus.value.find((item) => item.path === path);
+    }
+    rootMenuPath.value = rootMenu?.path ?? '';
+    splitSideMenus.value = rootMenu?.children ?? [];
+  }
+
+  watch(
+    () => route.path,
+    (path) => {
+      const currentPath = (route?.meta?.activePath as string) ?? path;
+      calcSideMenus(currentPath);
+    },
+    { immediate: true },
+  );
+
+  // 鍒濆鍖栬绠椾晶杈硅彍鍗�
+  onBeforeMount(() => {
+    calcSideMenus(route.meta?.activePath || route.path);
+  });
+
+  return {
+    handleMenuSelect,
+    headerActive,
+    headerMenus,
+    sidebarActive,
+    sidebarMenus,
+    sidebarVisible,
+  };
+}
+
+export { useMixedMenu };
diff --git a/eims-ui/packages/effects/layouts/src/basic/menu/use-navigation.ts b/eims-ui/packages/effects/layouts/src/basic/menu/use-navigation.ts
new file mode 100644
index 0000000..ace6445
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/menu/use-navigation.ts
@@ -0,0 +1,33 @@
+import { type RouteRecordNormalized, useRouter } from 'vue-router';
+
+import { isHttpUrl, openRouteInNewWindow, openWindow } from '@vben/utils';
+
+function useNavigation() {
+  const router = useRouter();
+  const routes = router.getRoutes();
+
+  const routeMetaMap = new Map<string, RouteRecordNormalized>();
+
+  routes.forEach((route) => {
+    routeMetaMap.set(route.path, route);
+  });
+
+  const navigation = async (path: string) => {
+    const route = routeMetaMap.get(path);
+    const { openInNewWindow = false, query = {} } = route?.meta ?? {};
+    if (isHttpUrl(path)) {
+      openWindow(path, { target: '_blank' });
+    } else if (openInNewWindow) {
+      openRouteInNewWindow(path);
+    } else {
+      await router.push({
+        path,
+        query,
+      });
+    }
+  };
+
+  return { navigation };
+}
+
+export { useNavigation };
diff --git a/eims-ui/packages/effects/layouts/src/basic/tabbar/index.ts b/eims-ui/packages/effects/layouts/src/basic/tabbar/index.ts
new file mode 100644
index 0000000..5cc2479
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/tabbar/index.ts
@@ -0,0 +1,2 @@
+export { default as LayoutTabbar } from './tabbar.vue';
+export * from './use-tabbar';
diff --git a/eims-ui/packages/effects/layouts/src/basic/tabbar/tabbar.vue b/eims-ui/packages/effects/layouts/src/basic/tabbar/tabbar.vue
new file mode 100644
index 0000000..f932364
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/tabbar/tabbar.vue
@@ -0,0 +1,72 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { useContentMaximize, useTabs } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import { useTabbarStore } from '@vben/stores';
+import { TabsToolMore, TabsToolScreen, TabsView } from '@vben-core/tabs-ui';
+
+import { useTabbar } from './use-tabbar';
+
+defineOptions({
+  name: 'LayoutTabbar',
+});
+
+defineProps<{ showIcon?: boolean; theme?: string }>();
+
+const route = useRoute();
+const tabbarStore = useTabbarStore();
+const { contentIsMaximize, toggleMaximize } = useContentMaximize();
+const { unpinTab } = useTabs();
+
+const {
+  createContextMenus,
+  currentActive,
+  currentTabs,
+  handleClick,
+  handleClose,
+} = useTabbar();
+
+const menus = computed(() => {
+  const tab = tabbarStore.getTabByPath(currentActive.value);
+  const menus = createContextMenus(tab);
+  return menus.map((item) => {
+    return {
+      ...item,
+      label: item.text,
+      value: item.key,
+    };
+  });
+});
+
+// 鍒锋柊鍚庡鏋滀笉淇濇寔tab鐘舵�侊紝鍏抽棴鍏朵粬tab
+if (!preferences.tabbar.persist) {
+  tabbarStore.closeOtherTabs(route);
+}
+</script>
+
+<template>
+  <TabsView
+    :active="currentActive"
+    :class="theme"
+    :context-menus="createContextMenus"
+    :draggable="preferences.tabbar.draggable"
+    :show-icon="showIcon"
+    :style-type="preferences.tabbar.styleType"
+    :tabs="currentTabs"
+    @close="handleClose"
+    @sort-tabs="tabbarStore.sortTabs"
+    @unpin="unpinTab"
+    @update:active="handleClick"
+  />
+  <div class="flex-center h-full">
+    <TabsToolMore v-if="preferences.tabbar.showMore" :menus="menus" />
+    <TabsToolScreen
+      v-if="preferences.tabbar.showMaximize"
+      :screen="contentIsMaximize"
+      @change="toggleMaximize"
+      @update:screen="toggleMaximize"
+    />
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts b/eims-ui/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts
new file mode 100644
index 0000000..52b32dc
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts
@@ -0,0 +1,220 @@
+import type { TabDefinition } from '@vben/types';
+import type { IContextMenuItem } from '@vben-core/tabs-ui';
+import type { RouteLocationNormalizedGeneric } from 'vue-router';
+
+import { computed, ref, watch } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+import { useContentMaximize, useTabs } from '@vben/hooks';
+import {
+  ArrowLeftToLine,
+  ArrowRightLeft,
+  ArrowRightToLine,
+  ExternalLink,
+  FoldHorizontal,
+  Fullscreen,
+  Minimize2,
+  Pin,
+  PinOff,
+  RotateCw,
+  X,
+} from '@vben/icons';
+import { $t, useI18n } from '@vben/locales';
+import { useAccessStore, useTabbarStore } from '@vben/stores';
+import { filterTree } from '@vben/utils';
+
+export function useTabbar() {
+  const router = useRouter();
+  const route = useRoute();
+  const accessStore = useAccessStore();
+  const tabbarStore = useTabbarStore();
+  const { contentIsMaximize, toggleMaximize } = useContentMaximize();
+  const {
+    closeAllTabs,
+    closeCurrentTab,
+    closeLeftTabs,
+    closeOtherTabs,
+    closeRightTabs,
+    closeTabByKey,
+    getTabDisableState,
+    openTabInNewWindow,
+    refreshTab,
+    toggleTabPin,
+  } = useTabs();
+
+  const currentActive = computed(() => {
+    return route.fullPath;
+  });
+
+  const { locale } = useI18n();
+  const currentTabs = ref<RouteLocationNormalizedGeneric[]>();
+  watch(
+    [
+      () => tabbarStore.getTabs,
+      () => tabbarStore.updateTime,
+      () => locale.value,
+    ],
+    ([tabs]) => {
+      currentTabs.value = tabs.map((item) => wrapperTabLocale(item));
+    },
+  );
+
+  /**
+   * 鍒濆鍖栧浐瀹氭爣绛鹃〉
+   */
+  const initAffixTabs = () => {
+    const affixTabs = filterTree(router.getRoutes(), (route) => {
+      return !!route.meta?.affixTab;
+    });
+    tabbarStore.setAffixTabs(affixTabs);
+  };
+
+  // 鐐瑰嚮tab,璺宠浆璺敱
+  const handleClick = (key: string) => {
+    router.push(key);
+  };
+
+  // 鍏抽棴tab
+  const handleClose = async (key: string) => {
+    await closeTabByKey(key);
+  };
+
+  function wrapperTabLocale(tab: RouteLocationNormalizedGeneric) {
+    return {
+      ...tab,
+      meta: {
+        ...tab?.meta,
+        title: $t(tab?.meta?.title as string),
+      },
+    };
+  }
+
+  watch(
+    () => accessStore.accessMenus,
+    () => {
+      initAffixTabs();
+    },
+    { immediate: true },
+  );
+
+  watch(
+    () => route.path,
+    () => {
+      const meta = route.matched?.[route.matched.length - 1]?.meta;
+      tabbarStore.addTab({
+        ...route,
+        meta: meta || route.meta,
+      });
+    },
+    { immediate: true },
+  );
+
+  const createContextMenus = (tab: TabDefinition) => {
+    const {
+      disabledCloseAll,
+      disabledCloseCurrent,
+      disabledCloseLeft,
+      disabledCloseOther,
+      disabledCloseRight,
+      disabledRefresh,
+    } = getTabDisableState(tab);
+
+    const affixTab = tab?.meta?.affixTab ?? false;
+
+    const menus: IContextMenuItem[] = [
+      {
+        disabled: disabledCloseCurrent,
+        handler: async () => {
+          await closeCurrentTab(tab);
+        },
+        icon: X,
+        key: 'close',
+        text: $t('preferences.tabbar.contextMenu.close'),
+      },
+      {
+        handler: async () => {
+          await toggleTabPin(tab);
+        },
+        icon: affixTab ? PinOff : Pin,
+        key: 'affix',
+        text: affixTab
+          ? $t('preferences.tabbar.contextMenu.unpin')
+          : $t('preferences.tabbar.contextMenu.pin'),
+      },
+      {
+        handler: async () => {
+          if (!contentIsMaximize.value) {
+            await router.push(tab.fullPath);
+          }
+          toggleMaximize();
+        },
+        icon: contentIsMaximize.value ? Minimize2 : Fullscreen,
+        key: contentIsMaximize.value ? 'restore-maximize' : 'maximize',
+        text: contentIsMaximize.value
+          ? $t('preferences.tabbar.contextMenu.restoreMaximize')
+          : $t('preferences.tabbar.contextMenu.maximize'),
+      },
+      {
+        disabled: disabledRefresh,
+        handler: refreshTab,
+        icon: RotateCw,
+        key: 'reload',
+        text: $t('preferences.tabbar.contextMenu.reload'),
+      },
+      {
+        handler: async () => {
+          await openTabInNewWindow(tab);
+        },
+        icon: ExternalLink,
+        key: 'open-in-new-window',
+        separator: true,
+        text: $t('preferences.tabbar.contextMenu.openInNewWindow'),
+      },
+
+      {
+        disabled: disabledCloseLeft,
+        handler: async () => {
+          await closeLeftTabs(tab);
+        },
+        icon: ArrowLeftToLine,
+        key: 'close-left',
+        text: $t('preferences.tabbar.contextMenu.closeLeft'),
+      },
+      {
+        disabled: disabledCloseRight,
+        handler: async () => {
+          await closeRightTabs(tab);
+        },
+        icon: ArrowRightToLine,
+        key: 'close-right',
+        separator: true,
+        text: $t('preferences.tabbar.contextMenu.closeRight'),
+      },
+      {
+        disabled: disabledCloseOther,
+        handler: async () => {
+          await closeOtherTabs(tab);
+        },
+        icon: FoldHorizontal,
+        key: 'close-other',
+        text: $t('preferences.tabbar.contextMenu.closeOther'),
+      },
+      {
+        disabled: disabledCloseAll,
+        handler: closeAllTabs,
+        icon: ArrowRightLeft,
+        key: 'close-all',
+        text: $t('preferences.tabbar.contextMenu.closeAll'),
+      },
+    ];
+    return menus;
+  };
+
+  return {
+    createContextMenus,
+    currentActive,
+    currentTabs,
+    handleClick,
+    handleClose,
+  };
+}
diff --git a/eims-ui/packages/effects/layouts/src/iframe/iframe-router-view.vue b/eims-ui/packages/effects/layouts/src/iframe/iframe-router-view.vue
new file mode 100644
index 0000000..0e45ed9
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/iframe/iframe-router-view.vue
@@ -0,0 +1,85 @@
+<script lang="ts" setup>
+import type { RouteLocationNormalized } from 'vue-router';
+
+import { computed, ref } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { preferences } from '@vben/preferences';
+import { useTabbarStore } from '@vben/stores';
+import { VbenSpinner } from '@vben-core/shadcn-ui';
+
+defineOptions({ name: 'IFrameRouterView' });
+
+const spinningList = ref<boolean[]>([]);
+const tabbarStore = useTabbarStore();
+const route = useRoute();
+
+const enableTabbar = computed(() => preferences.tabbar.enable);
+
+const iframeRoutes = computed(() => {
+  if (!enableTabbar.value) {
+    return route.meta.iframeSrc ? [route] : [];
+  }
+  return tabbarStore.getTabs.filter((tab) => !!tab.meta?.iframeSrc);
+});
+
+const tabNames = computed(
+  () => new Set(iframeRoutes.value.map((item) => item.name as string)),
+);
+
+const showIframe = computed(() => iframeRoutes.value.length > 0);
+
+function routeShow(tabItem: RouteLocationNormalized) {
+  return tabItem.name === route.name;
+}
+
+function canRender(tabItem: RouteLocationNormalized) {
+  const { meta, name } = tabItem;
+
+  if (!name || !tabbarStore.renderRouteView) {
+    return false;
+  }
+
+  if (!enableTabbar.value) {
+    return routeShow(tabItem);
+  }
+
+  // 璺熼殢 keepAlive 鐘舵��,涓庡叾浠杢ab椤典繚鎸佷竴鑷�
+  if (
+    !meta?.keepAlive &&
+    tabNames.value.has(name as string) &&
+    name !== route.name
+  ) {
+    return false;
+  }
+  return tabbarStore.getTabs.some((tab) => tab.name === name);
+}
+
+function hideLoading(index: number) {
+  spinningList.value[index] = false;
+}
+
+function showSpinning(index: number) {
+  const curSpinning = spinningList.value[index];
+  // 棣栨鍔犺浇鏃舵樉绀簂oading
+  return curSpinning === undefined ? true : curSpinning;
+}
+</script>
+<template>
+  <template v-if="showIframe">
+    <template v-for="(item, index) in iframeRoutes" :key="item.fullPath">
+      <div
+        v-if="canRender(item)"
+        v-show="routeShow(item)"
+        class="relative size-full"
+      >
+        <VbenSpinner :spinning="showSpinning(index)" />
+        <iframe
+          :src="item.meta.iframeSrc as string"
+          class="size-full"
+          @load="hideLoading(index)"
+        ></iframe>
+      </div>
+    </template>
+  </template>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/iframe/iframe-view.vue b/eims-ui/packages/effects/layouts/src/iframe/iframe-view.vue
new file mode 100644
index 0000000..7b8b46c
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/iframe/iframe-view.vue
@@ -0,0 +1,3 @@
+<template>
+  <div></div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/iframe/index.ts b/eims-ui/packages/effects/layouts/src/iframe/index.ts
new file mode 100644
index 0000000..1b8c131
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/iframe/index.ts
@@ -0,0 +1,2 @@
+export { default as IFrameRouterView } from './iframe-router-view.vue';
+export { default as IFrameView } from './iframe-view.vue';
diff --git a/eims-ui/packages/effects/layouts/src/index.ts b/eims-ui/packages/effects/layouts/src/index.ts
new file mode 100644
index 0000000..124a44a
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/index.ts
@@ -0,0 +1,4 @@
+export * from './authentication';
+export * from './basic';
+export * from './iframe';
+export * from './widgets';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/breadcrumb.vue b/eims-ui/packages/effects/layouts/src/widgets/breadcrumb.vue
new file mode 100644
index 0000000..744aed2
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/breadcrumb.vue
@@ -0,0 +1,72 @@
+<script lang="ts" setup>
+import type { BreadcrumbStyleType } from '@vben/types';
+import type { IBreadcrumb } from '@vben-core/shadcn-ui';
+
+import { computed } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+import { $t } from '@vben/locales';
+import { VbenBreadcrumbView } from '@vben-core/shadcn-ui';
+
+interface Props {
+  hideWhenOnlyOne?: boolean;
+  showHome?: boolean;
+  showIcon?: boolean;
+  type?: BreadcrumbStyleType;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  showHome: false,
+  showIcon: false,
+  type: 'normal',
+});
+
+const route = useRoute();
+const router = useRouter();
+
+const breadcrumbs = computed((): IBreadcrumb[] => {
+  const matched = route.matched;
+
+  const resultBreadcrumb: IBreadcrumb[] = [];
+
+  for (const match of matched) {
+    const { meta, path } = match;
+    const { hideChildrenInMenu, hideInBreadcrumb, icon, name, title } =
+      meta || {};
+    if (hideInBreadcrumb || hideChildrenInMenu || !path) {
+      continue;
+    }
+
+    resultBreadcrumb.push({
+      icon,
+      path: path || route.path,
+      title: title ? $t((title || name) as string) : '',
+    });
+  }
+  if (props.showHome) {
+    resultBreadcrumb.unshift({
+      icon: 'mdi:home-outline',
+      isHome: true,
+      path: '/',
+    });
+  }
+  if (props.hideWhenOnlyOne && resultBreadcrumb.length === 1) {
+    return [];
+  }
+
+  return resultBreadcrumb;
+});
+
+function handleSelect(path: string) {
+  router.push(path);
+}
+</script>
+<template>
+  <VbenBreadcrumbView
+    :breadcrumbs="breadcrumbs"
+    :show-icon="showIcon"
+    :style-type="type"
+    class="ml-2"
+    @select="handleSelect"
+  />
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/check-updates/check-updates.vue b/eims-ui/packages/effects/layouts/src/widgets/check-updates/check-updates.vue
new file mode 100644
index 0000000..a0c9ade
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/check-updates/check-updates.vue
@@ -0,0 +1,134 @@
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref } from 'vue';
+
+import { $t } from '@vben/locales';
+import { useVbenModal } from '@vben-core/popup-ui';
+
+interface Props {
+  // 杞鏃堕棿锛屽垎閽�
+  checkUpdatesInterval?: number;
+  // 妫�鏌ユ洿鏂扮殑鍦板潃
+  checkUpdateUrl?: string;
+}
+
+defineOptions({ name: 'CheckUpdates' });
+
+const props = withDefaults(defineProps<Props>(), {
+  checkUpdatesInterval: 1,
+  checkUpdateUrl: import.meta.env.BASE_URL || '/',
+});
+
+let isCheckingUpdates = false;
+const currentVersionTag = ref('');
+const lastVersionTag = ref('');
+const timer = ref<ReturnType<typeof setInterval>>();
+
+const [UpdateNoticeModal, modalApi] = useVbenModal({
+  closable: false,
+  closeOnPressEscape: false,
+  closeOnClickModal: false,
+  onConfirm() {
+    lastVersionTag.value = currentVersionTag.value;
+    window.location.reload();
+    // handleSubmitLogout();
+  },
+});
+
+async function getVersionTag() {
+  try {
+    if (
+      location.hostname === 'localhost' ||
+      location.hostname === '127.0.0.1'
+    ) {
+      return null;
+    }
+    const response = await fetch(props.checkUpdateUrl, {
+      cache: 'no-cache',
+      method: 'HEAD',
+    });
+
+    return (
+      response.headers.get('etag') || response.headers.get('last-modified')
+    );
+  } catch {
+    console.error('Failed to fetch version tag');
+    return null;
+  }
+}
+
+async function checkForUpdates() {
+  const versionTag = await getVersionTag();
+  if (!versionTag) {
+    return;
+  }
+
+  // 棣栨杩愯鏃朵笉鎻愮ず鏇存柊
+  if (!lastVersionTag.value) {
+    lastVersionTag.value = versionTag;
+    return;
+  }
+
+  if (lastVersionTag.value !== versionTag && versionTag) {
+    clearInterval(timer.value);
+    handleNotice(versionTag);
+  }
+}
+function handleNotice(versionTag: string) {
+  currentVersionTag.value = versionTag;
+  modalApi.open();
+}
+
+function start() {
+  if (props.checkUpdatesInterval <= 0) {
+    return;
+  }
+
+  // 姣� checkUpdatesInterval(榛樿鍊间负1) 鍒嗛挓妫�鏌ヤ竴娆�
+  timer.value = setInterval(
+    checkForUpdates,
+    props.checkUpdatesInterval * 60 * 1000,
+  );
+}
+
+function handleVisibilitychange() {
+  if (document.hidden) {
+    stop();
+  } else {
+    if (!isCheckingUpdates) {
+      isCheckingUpdates = true;
+      checkForUpdates().finally(() => {
+        isCheckingUpdates = false;
+        start();
+      });
+    }
+  }
+}
+
+function stop() {
+  clearInterval(timer.value);
+}
+
+onMounted(() => {
+  start();
+  document.addEventListener('visibilitychange', handleVisibilitychange);
+});
+
+onUnmounted(() => {
+  stop();
+  document.removeEventListener('visibilitychange', handleVisibilitychange);
+});
+</script>
+<template>
+  <UpdateNoticeModal
+    :cancel-text="$t('common.cancel')"
+    :confirm-text="$t('common.refresh')"
+    :fullscreen-button="false"
+    :title="$t('ui.widgets.checkUpdatesTitle')"
+    centered
+    content-class="px-8 min-h-10"
+    footer-class="border-none mb-3 mr-3"
+    header-class="border-none"
+  >
+    {{ $t('ui.widgets.checkUpdatesDescription') }}
+  </UpdateNoticeModal>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/check-updates/index.ts b/eims-ui/packages/effects/layouts/src/widgets/check-updates/index.ts
new file mode 100644
index 0000000..fc20c66
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/check-updates/index.ts
@@ -0,0 +1 @@
+export { default as CheckUpdates } from './check-updates.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/color-toggle.vue b/eims-ui/packages/effects/layouts/src/widgets/color-toggle.vue
new file mode 100644
index 0000000..67cad31
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/color-toggle.vue
@@ -0,0 +1,63 @@
+<script setup lang="ts">
+import type { BuiltinThemeType } from '@vben/types';
+
+import { Palette } from '@vben/icons';
+import {
+  COLOR_PRESETS,
+  preferences,
+  updatePreferences,
+} from '@vben/preferences';
+import { VbenIconButton } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'AuthenticationColorToggle',
+});
+
+function handleUpdate(colorPrimary: string, type: BuiltinThemeType) {
+  updatePreferences({
+    theme: {
+      colorPrimary,
+      builtinType: type,
+    },
+  });
+}
+</script>
+
+<template>
+  <div class="group relative flex items-center overflow-hidden">
+    <div
+      class="flex w-0 overflow-hidden transition-all duration-500 ease-out group-hover:w-60"
+    >
+      <template v-for="preset in COLOR_PRESETS" :key="preset.color">
+        <VbenIconButton
+          class="flex-center flex-shrink-0"
+          @click="handleUpdate(preset.color, preset.type)"
+        >
+          <div
+            :style="{ backgroundColor: preset.color }"
+            class="flex-center relative size-5 rounded-full hover:scale-110"
+          >
+            <svg
+              v-if="preferences.theme.builtinType === preset.type"
+              class="h-3.5 w-3.5 text-white"
+              height="1em"
+              viewBox="0 0 15 15"
+              width="1em"
+            >
+              <path
+                clip-rule="evenodd"
+                d="M11.467 3.727c.289.189.37.576.181.865l-4.25 6.5a.625.625 0 0 1-.944.12l-2.75-2.5a.625.625 0 0 1 .841-.925l2.208 2.007l3.849-5.886a.625.625 0 0 1 .865-.181"
+                fill="currentColor"
+                fill-rule="evenodd"
+              />
+            </svg>
+          </div>
+        </VbenIconButton>
+      </template>
+    </div>
+
+    <VbenIconButton>
+      <Palette class="text-primary size-4" />
+    </VbenIconButton>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/global-search/global-search.vue b/eims-ui/packages/effects/layouts/src/widgets/global-search/global-search.vue
new file mode 100644
index 0000000..197251b
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/global-search/global-search.vue
@@ -0,0 +1,156 @@
+<script setup lang="ts">
+import type { MenuRecordRaw } from '@vben/types';
+
+import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
+
+import {
+  ArrowDown,
+  ArrowUp,
+  CornerDownLeft,
+  MdiKeyboardEsc,
+  Search,
+} from '@vben/icons';
+import { $t } from '@vben/locales';
+import { isWindowsOs } from '@vben/utils';
+import { useVbenModal } from '@vben-core/popup-ui';
+
+import { useMagicKeys, whenever } from '@vueuse/core';
+
+import SearchPanel from './search-panel.vue';
+
+defineOptions({
+  name: 'GlobalSearch',
+});
+
+const props = withDefaults(
+  defineProps<{ enableShortcutKey?: boolean; menus: MenuRecordRaw[] }>(),
+  {
+    enableShortcutKey: true,
+    menus: () => [],
+  },
+);
+
+const keyword = ref('');
+const searchInputRef = ref<HTMLInputElement>();
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onOpenChange(isOpen: boolean) {
+    if (!isOpen) {
+      keyword.value = '';
+    }
+  },
+});
+const open = modalApi.useStore((state) => state.isOpen);
+
+function handleClose() {
+  modalApi.close();
+  keyword.value = '';
+}
+
+const keys = useMagicKeys();
+const cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];
+whenever(cmd!, () => {
+  if (props.enableShortcutKey) {
+    modalApi.open();
+  }
+});
+
+whenever(open, () => {
+  nextTick(() => {
+    searchInputRef.value?.focus();
+  });
+});
+
+const preventDefaultBrowserSearchHotKey = (event: KeyboardEvent) => {
+  if (event.key?.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) {
+    event.preventDefault();
+  }
+};
+
+const toggleKeydownListener = () => {
+  if (props.enableShortcutKey) {
+    window.addEventListener('keydown', preventDefaultBrowserSearchHotKey);
+  } else {
+    window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
+  }
+};
+
+const toggleOpen = () => {
+  open.value ? modalApi.close() : modalApi.open();
+};
+
+watch(() => props.enableShortcutKey, toggleKeydownListener);
+
+onMounted(() => {
+  toggleKeydownListener();
+
+  onUnmounted(() => {
+    window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
+  });
+});
+</script>
+
+<template>
+  <div>
+    <Modal
+      :fullscreen-button="false"
+      class="w-[600px]"
+      header-class="py-2 border-b"
+    >
+      <template #title>
+        <div class="flex items-center">
+          <Search class="text-muted-foreground mr-2 size-4" />
+          <input
+            ref="searchInputRef"
+            v-model="keyword"
+            :placeholder="$t('ui.widgets.search.searchNavigate')"
+            class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm font-normal outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent"
+          />
+        </div>
+      </template>
+
+      <SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
+      <template #footer>
+        <div class="flex w-full justify-start text-xs">
+          <div class="mr-2 flex items-center">
+            <CornerDownLeft class="mr-1 size-3" />
+            {{ $t('ui.widgets.search.select') }}
+          </div>
+          <div class="mr-2 flex items-center">
+            <ArrowUp class="mr-1 size-3" />
+            <ArrowDown class="mr-1 size-3" />
+            {{ $t('ui.widgets.search.navigate') }}
+          </div>
+          <div class="flex items-center">
+            <MdiKeyboardEsc class="mr-1 size-3" />
+            {{ $t('ui.widgets.search.close') }}
+          </div>
+        </div>
+      </template>
+    </Modal>
+    <div
+      class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
+      @click="toggleOpen()"
+    >
+      <Search
+        class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100"
+      />
+      <span
+        class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block"
+      >
+        {{ $t('ui.widgets.search.title') }}
+      </span>
+      <span
+        v-if="enableShortcutKey"
+        class="bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block"
+      >
+        {{ isWindowsOs() ? 'Ctrl' : '鈱�' }}
+        <kbd>K</kbd>
+      </span>
+      <span v-else></span>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/global-search/index.ts b/eims-ui/packages/effects/layouts/src/widgets/global-search/index.ts
new file mode 100644
index 0000000..cd490ae
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/global-search/index.ts
@@ -0,0 +1 @@
+export { default as GlobalSearch } from './global-search.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/global-search/search-panel.vue b/eims-ui/packages/effects/layouts/src/widgets/global-search/search-panel.vue
new file mode 100644
index 0000000..acbc2f1
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/global-search/search-panel.vue
@@ -0,0 +1,287 @@
+<script setup lang="ts">
+import type { MenuRecordRaw } from '@vben/types';
+
+import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { SearchX, X } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { mapTree, traverseTreeValues, uniqueByField } from '@vben/utils';
+import { VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
+import { isHttpUrl } from '@vben-core/shared/utils';
+
+import { onKeyStroke, useLocalStorage, useThrottleFn } from '@vueuse/core';
+
+defineOptions({
+  name: 'SearchPanel',
+});
+
+const props = withDefaults(
+  defineProps<{ keyword: string; menus: MenuRecordRaw[] }>(),
+  {
+    keyword: '',
+    menus: () => [],
+  },
+);
+const emit = defineEmits<{ close: [] }>();
+
+const router = useRouter();
+const searchHistory = useLocalStorage<MenuRecordRaw[]>(
+  `__search-history-${location.hostname}__`,
+  [],
+);
+const activeIndex = ref(-1);
+const searchItems = shallowRef<MenuRecordRaw[]>([]);
+const searchResults = ref<MenuRecordRaw[]>([]);
+
+const handleSearch = useThrottleFn(search, 200);
+
+// 鎼滅储鍑芥暟锛岀敤浜庢牴鎹悳绱㈠叧閿瘝鏌ユ壘鍖归厤鐨勮彍鍗曢」
+function search(searchKey: string) {
+  // 鍘婚櫎鎼滅储鍏抽敭璇嶇殑鍓嶅悗绌烘牸
+  searchKey = searchKey.trim();
+
+  // 濡傛灉鎼滅储鍏抽敭璇嶄负绌猴紝娓呯┖鎼滅储缁撴灉骞惰繑鍥�
+  if (!searchKey) {
+    searchResults.value = [];
+    return;
+  }
+
+  // 浣跨敤鎼滅储鍏抽敭璇嶅垱寤烘鍒欒〃杈惧紡
+  const reg = createSearchReg(searchKey);
+
+  // 鍒濆鍖栫粨鏋滄暟缁�
+  const results: MenuRecordRaw[] = [];
+
+  // 閬嶅巻鎼滅储椤�
+  traverseTreeValues(searchItems.value, (item) => {
+    // 濡傛灉鑿滃崟椤圭殑鍚嶇О鍖归厤姝e垯琛ㄨ揪寮忥紝灏嗗叾娣诲姞鍒扮粨鏋滄暟缁勪腑
+    if (reg.test(item.name?.toLowerCase())) {
+      results.push(item);
+    }
+  });
+
+  // 鏇存柊鎼滅储缁撴灉
+  searchResults.value = results;
+
+  // 濡傛灉鏈夋悳绱㈢粨鏋滐紝璁剧疆绱㈠紩涓� 0
+  if (results.length > 0) {
+    activeIndex.value = 0;
+  }
+
+  // 璧嬪�肩储寮曚负 0
+  activeIndex.value = 0;
+}
+
+// When the keyboard up and down keys move to an invisible place
+// the scroll bar needs to scroll automatically
+function scrollIntoView() {
+  const element = document.querySelector(
+    `[data-search-item="${activeIndex.value}"]`,
+  );
+
+  if (element) {
+    element.scrollIntoView({ block: 'nearest' });
+  }
+}
+
+// enter keyboard event
+async function handleEnter() {
+  if (searchResults.value.length === 0) {
+    return;
+  }
+  const result = searchResults.value;
+  const index = activeIndex.value;
+  if (result.length === 0 || index < 0) {
+    return;
+  }
+  const to = result[index];
+  if (to) {
+    searchHistory.value.push(to);
+    handleClose();
+    await nextTick();
+    if (isHttpUrl(to.path)) {
+      window.open(to.path, '_blank');
+    } else {
+      router.push({ path: to.path, replace: true });
+    }
+  }
+}
+
+// Arrow key up
+function handleUp() {
+  if (searchResults.value.length === 0) {
+    return;
+  }
+  activeIndex.value--;
+  if (activeIndex.value < 0) {
+    activeIndex.value = searchResults.value.length - 1;
+  }
+  scrollIntoView();
+}
+
+// Arrow key down
+function handleDown() {
+  if (searchResults.value.length === 0) {
+    return;
+  }
+  activeIndex.value++;
+  if (activeIndex.value > searchResults.value.length - 1) {
+    activeIndex.value = 0;
+  }
+  scrollIntoView();
+}
+
+// close search modal
+function handleClose() {
+  searchResults.value = [];
+  emit('close');
+}
+
+// Activate when the mouse moves to a certain line
+function handleMouseenter(e: MouseEvent) {
+  const index = (e.target as HTMLElement)?.dataset.index;
+  activeIndex.value = Number(index);
+}
+
+function removeItem(index: number) {
+  if (props.keyword) {
+    searchResults.value.splice(index, 1);
+  } else {
+    searchHistory.value.splice(index, 1);
+  }
+  activeIndex.value = Math.max(activeIndex.value - 1, 0);
+  scrollIntoView();
+}
+
+// 瀛樺偍鎵�鏈夐渶瑕佽浆涔夌殑鐗规畩瀛楃
+const code = new Set([
+  '$',
+  '(',
+  ')',
+  '*',
+  '+',
+  '.',
+  '?',
+  '[',
+  '\\',
+  ']',
+  '^',
+  '{',
+  '|',
+  '}',
+]);
+
+// 杞崲鍑芥暟锛岀敤浜庤浆涔夌壒娈婂瓧绗�
+function transform(c: string) {
+  // 濡傛灉瀛楃鍦ㄧ壒娈婂瓧绗﹀垪琛ㄤ腑锛岃繑鍥炶浆涔夊悗鐨勫瓧绗�
+  // 濡傛灉涓嶅湪锛岃繑鍥炲瓧绗︽湰韬�
+  return code.has(c) ? `\\${c}` : c;
+}
+
+// 鍒涘缓鎼滅储姝e垯琛ㄨ揪寮�
+function createSearchReg(key: string) {
+  // 灏嗚緭鍏ョ殑瀛楃涓叉媶鍒嗕负鍗曚釜瀛楃
+  // 瀵规瘡涓瓧绗﹁繘琛岃浆涔�
+  // 鐒跺悗鐢�'.*'杩炴帴鎵�鏈夊瓧绗︼紝鍒涘缓姝e垯琛ㄨ揪寮�
+  const keys = [...key].map((item) => transform(item)).join('.*');
+  // 杩斿洖鍒涘缓鐨勬鍒欒〃杈惧紡
+  return new RegExp(`.*${keys}.*`);
+}
+
+watch(
+  () => props.keyword,
+  (val) => {
+    if (val) {
+      handleSearch(val);
+    } else {
+      searchResults.value = [...searchHistory.value];
+    }
+  },
+);
+
+onMounted(() => {
+  searchItems.value = mapTree(props.menus, (item) => {
+    return {
+      ...item,
+      name: $t(item?.name),
+    };
+  });
+  if (searchHistory.value.length > 0) {
+    searchResults.value = searchHistory.value;
+  }
+  // enter search
+  onKeyStroke('Enter', handleEnter);
+  // Monitor keyboard arrow keys
+  onKeyStroke('ArrowUp', handleUp);
+  onKeyStroke('ArrowDown', handleDown);
+  // esc close
+  onKeyStroke('Escape', handleClose);
+});
+</script>
+
+<template>
+  <VbenScrollbar>
+    <div class="!flex h-full justify-center px-2 sm:max-h-[450px]">
+      <!-- 鏃犳悳绱㈢粨鏋� -->
+      <div
+        v-if="keyword && searchResults.length === 0"
+        class="text-muted-foreground text-center"
+      >
+        <SearchX class="mx-auto mt-4 size-12" />
+        <p class="mb-10 mt-6 text-xs">
+          {{ $t('ui.widgets.search.noResults') }}
+          <span class="text-foreground text-sm font-medium">
+            "{{ keyword }}"
+          </span>
+        </p>
+      </div>
+      <!-- 鍘嗗彶鎼滅储璁板綍 & 娌℃湁鎼滅储缁撴灉 -->
+      <div
+        v-if="!keyword && searchResults.length === 0"
+        class="text-muted-foreground text-center"
+      >
+        <p class="my-10 text-xs">
+          {{ $t('ui.widgets.search.noRecent') }}
+        </p>
+      </div>
+
+      <ul v-show="searchResults.length > 0" class="w-full">
+        <li
+          v-if="searchHistory.length > 0 && !keyword"
+          class="text-muted-foreground mb-2 text-xs"
+        >
+          {{ $t('ui.widgets.search.recent') }}
+        </li>
+        <li
+          v-for="(item, index) in uniqueByField(searchResults, 'path')"
+          :key="item.path"
+          :class="
+            activeIndex === index
+              ? 'active bg-primary text-primary-foreground'
+              : ''
+          "
+          :data-index="index"
+          :data-search-item="index"
+          class="bg-accent flex-center group mb-3 w-full cursor-pointer rounded-lg px-4 py-4"
+          @click="handleEnter"
+          @mouseenter="handleMouseenter"
+        >
+          <VbenIcon
+            :icon="item.icon"
+            class="mr-2 size-5 flex-shrink-0"
+            fallback
+          />
+
+          <span class="flex-1">{{ item.name }}</span>
+          <div
+            class="flex-center dark:hover:bg-accent hover:text-primary-foreground rounded-full p-1 hover:scale-110"
+            @click.stop="removeItem(index)"
+          >
+            <X class="size-4" />
+          </div>
+        </li>
+      </ul>
+    </div>
+  </VbenScrollbar>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/index.ts b/eims-ui/packages/effects/layouts/src/widgets/index.ts
new file mode 100644
index 0000000..f6a4a7b
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/index.ts
@@ -0,0 +1,11 @@
+export { default as Breadcrumb } from './breadcrumb.vue';
+export * from './check-updates';
+export { default as AuthenticationColorToggle } from './color-toggle.vue';
+export * from './global-search';
+export { default as LanguageToggle } from './language-toggle.vue';
+export { default as AuthenticationLayoutToggle } from './layout-toggle.vue';
+export * from './lock-screen';
+export * from './notification';
+export * from './preferences';
+export * from './theme-toggle';
+export * from './user-dropdown';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/language-toggle.vue b/eims-ui/packages/effects/layouts/src/widgets/language-toggle.vue
new file mode 100644
index 0000000..c8b612b
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/language-toggle.vue
@@ -0,0 +1,37 @@
+<script setup lang="ts">
+import type { SupportedLanguagesType } from '@vben/locales';
+
+import { SUPPORT_LANGUAGES } from '@vben/constants';
+import { Languages } from '@vben/icons';
+import { loadLocaleMessages } from '@vben/locales';
+import { preferences, updatePreferences } from '@vben/preferences';
+import { VbenDropdownRadioMenu, VbenIconButton } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'LanguageToggle',
+});
+
+async function handleUpdate(value: string) {
+  const locale = value as SupportedLanguagesType;
+  updatePreferences({
+    app: {
+      locale,
+    },
+  });
+  await loadLocaleMessages(locale);
+}
+</script>
+
+<template>
+  <div>
+    <VbenDropdownRadioMenu
+      :menus="SUPPORT_LANGUAGES"
+      :model-value="preferences.app.locale"
+      @update:model-value="handleUpdate"
+    >
+      <VbenIconButton>
+        <Languages class="text-foreground size-4" />
+      </VbenIconButton>
+    </VbenDropdownRadioMenu>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/layout-toggle.vue b/eims-ui/packages/effects/layouts/src/widgets/layout-toggle.vue
new file mode 100644
index 0000000..21823c3
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/layout-toggle.vue
@@ -0,0 +1,61 @@
+<script setup lang="ts">
+import type { AuthPageLayoutType } from '@vben/types';
+import type { VbenDropdownMenuItem } from '@vben-core/shadcn-ui';
+
+import { computed } from 'vue';
+
+import { InspectionPanel, PanelLeft, PanelRight } from '@vben/icons';
+import { $t } from '@vben/locales';
+import {
+  preferences,
+  updatePreferences,
+  usePreferences,
+} from '@vben/preferences';
+import { VbenDropdownRadioMenu, VbenIconButton } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'AuthenticationLayoutToggle',
+});
+
+const menus = computed((): VbenDropdownMenuItem[] => [
+  {
+    icon: PanelLeft,
+    label: $t('authentication.layout.alignLeft'),
+    value: 'panel-left',
+  },
+  {
+    icon: InspectionPanel,
+    label: $t('authentication.layout.center'),
+    value: 'panel-center',
+  },
+  {
+    icon: PanelRight,
+    label: $t('authentication.layout.alignRight'),
+    value: 'panel-right',
+  },
+]);
+
+const { authPanelCenter, authPanelLeft, authPanelRight } = usePreferences();
+
+function handleUpdate(value: string) {
+  updatePreferences({
+    app: {
+      authPageLayout: value as AuthPageLayoutType,
+    },
+  });
+}
+</script>
+
+<template>
+  <VbenDropdownRadioMenu
+    :menus="menus"
+    :model-value="preferences.app.authPageLayout"
+    @update:model-value="handleUpdate"
+  >
+    <VbenIconButton>
+      <PanelRight v-if="authPanelRight" class="size-4" />
+      <PanelLeft v-if="authPanelLeft" class="size-4" />
+      <InspectionPanel v-if="authPanelCenter" class="size-4" />
+    </VbenIconButton>
+  </VbenDropdownRadioMenu>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/lock-screen/index.ts b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/index.ts
new file mode 100644
index 0000000..1609bec
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/index.ts
@@ -0,0 +1,2 @@
+export { default as LockScreen } from './lock-screen.vue';
+export { default as LockScreenModal } from './lock-screen-modal.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
new file mode 100644
index 0000000..a346d82
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue
@@ -0,0 +1,101 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { computed, reactive } from 'vue';
+
+import { $t } from '@vben/locales';
+import { useVbenForm, z } from '@vben-core/form-ui';
+import { useVbenModal } from '@vben-core/popup-ui';
+import { VbenAvatar, VbenButton } from '@vben-core/shadcn-ui';
+
+interface Props {
+  avatar?: string;
+  text?: string;
+}
+
+defineOptions({
+  name: 'LockScreenModal',
+});
+
+withDefaults(defineProps<Props>(), {
+  avatar: '',
+  text: '',
+});
+
+const emit = defineEmits<{
+  submit: [Recordable<any>];
+}>();
+
+const [Form, { resetForm, validate, getValues }] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => [
+      {
+        component: 'VbenInputPassword' as const,
+        componentProps: {
+          placeholder: $t('ui.widgets.lockScreen.placeholder'),
+        },
+        fieldName: 'lockScreenPassword',
+        formFieldProps: { validateOnBlur: false },
+        label: $t('authentication.password'),
+        rules: z
+          .string()
+          .min(1, { message: $t('ui.widgets.lockScreen.placeholder') }),
+      },
+    ]),
+    showDefaultActions: false,
+  }),
+);
+
+const [Modal] = useVbenModal({
+  onConfirm() {
+    handleSubmit();
+  },
+  onOpenChange(isOpen) {
+    if (isOpen) {
+      resetForm();
+    }
+  },
+});
+
+async function handleSubmit() {
+  const { valid } = await validate();
+  const values = await getValues();
+  if (valid) {
+    emit('submit', values?.lockScreenPassword);
+  }
+}
+</script>
+
+<template>
+  <Modal
+    :footer="false"
+    :fullscreen-button="false"
+    :title="$t('ui.widgets.lockScreen.title')"
+  >
+    <div
+      class="mb-10 flex w-full flex-col items-center px-10"
+      @keydown.enter.prevent="handleSubmit"
+    >
+      <div class="w-full">
+        <div class="ml-2 flex w-full flex-col items-center">
+          <VbenAvatar
+            :src="avatar"
+            class="size-20"
+            dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
+          />
+          <div class="text-foreground my-6 flex items-center font-medium">
+            {{ text }}
+          </div>
+        </div>
+        <Form />
+        <VbenButton class="mt-1 w-full" @click="handleSubmit">
+          {{ $t('ui.widgets.lockScreen.screenButton') }}
+        </VbenButton>
+      </div>
+    </div>
+  </Modal>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
new file mode 100644
index 0000000..cce417d
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue
@@ -0,0 +1,155 @@
+<script setup lang="ts">
+import { computed, reactive, ref } from 'vue';
+
+import { LockKeyhole } from '@vben/icons';
+import { $t, useI18n } from '@vben/locales';
+import { storeToRefs, useLockStore } from '@vben/stores';
+import { useScrollLock } from '@vben-core/composables';
+import { useVbenForm, z } from '@vben-core/form-ui';
+import { VbenAvatar, VbenButton } from '@vben-core/shadcn-ui';
+
+import { useDateFormat, useNow } from '@vueuse/core';
+
+interface Props {
+  avatar?: string;
+}
+
+defineOptions({
+  name: 'LockScreen',
+});
+
+withDefaults(defineProps<Props>(), {
+  avatar: '',
+});
+
+defineEmits<{ toLogin: [] }>();
+
+const { locale } = useI18n();
+const lockStore = useLockStore();
+
+const now = useNow();
+const meridiem = useDateFormat(now, 'A');
+const hour = useDateFormat(now, 'HH');
+const minute = useDateFormat(now, 'mm');
+const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });
+
+const showUnlockForm = ref(false);
+const { lockScreenPassword } = storeToRefs(lockStore);
+
+const [Form, { form, validate }] = useVbenForm(
+  reactive({
+    commonConfig: {
+      hideLabel: true,
+      hideRequiredMark: true,
+    },
+    schema: computed(() => [
+      {
+        component: 'VbenInputPassword' as const,
+        componentProps: {
+          placeholder: $t('ui.widgets.lockScreen.placeholder'),
+        },
+        fieldName: 'password',
+        label: $t('authentication.password'),
+        rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+      },
+    ]),
+    showDefaultActions: false,
+  }),
+);
+
+const validPass = computed(
+  () => lockScreenPassword?.value === form?.values?.password,
+);
+
+async function handleSubmit() {
+  const { valid } = await validate();
+  if (valid) {
+    if (validPass.value) {
+      lockStore.unlockScreen();
+    } else {
+      form.setFieldError('password', $t('authentication.passwordErrorTip'));
+    }
+  }
+}
+
+function toggleUnlockForm() {
+  showUnlockForm.value = !showUnlockForm.value;
+}
+
+useScrollLock();
+</script>
+
+<template>
+  <div class="bg-background fixed z-[2000] size-full">
+    <transition name="slide-left">
+      <div v-show="!showUnlockForm" class="size-full">
+        <div
+          class="flex-col-center text-foreground/80 hover:text-foreground group my-4 cursor-pointer text-xl font-semibold"
+          @click="toggleUnlockForm"
+        >
+          <LockKeyhole
+            class="size-5 transition-all duration-300 group-hover:scale-125"
+          />
+          <span>{{ $t('ui.widgets.lockScreen.unlock') }}</span>
+        </div>
+        <div class="flex h-full justify-center px-[10%]">
+          <div
+            class="bg-accent flex-center relative mb-14 mr-20 h-4/5 w-2/5 flex-auto rounded-3xl text-center text-[260px]"
+          >
+            <span class="absolute left-4 top-4 text-xl font-semibold">
+              {{ meridiem }}
+            </span>
+            {{ hour }}
+          </div>
+          <div
+            class="bg-accent flex-center mb-14 h-4/5 w-2/5 flex-auto rounded-3xl text-center text-[260px]"
+          >
+            {{ minute }}
+          </div>
+        </div>
+      </div>
+    </transition>
+
+    <transition name="slide-right">
+      <div
+        v-if="showUnlockForm"
+        class="flex-center size-full"
+        @keydown.enter.prevent="handleSubmit"
+      >
+        <div class="flex-col-center mb-10 w-[300px]">
+          <VbenAvatar :src="avatar" class="enter-x mb-6 size-20" />
+
+          <div class="enter-x mb-2 w-full items-center">
+            <Form />
+          </div>
+          <VbenButton class="enter-x w-full" @click="handleSubmit">
+            {{ $t('ui.widgets.lockScreen.entry') }}
+          </VbenButton>
+          <VbenButton
+            class="enter-x my-2 w-full"
+            variant="ghost"
+            @click="$emit('toLogin')"
+          >
+            {{ $t('ui.widgets.lockScreen.backToLogin') }}
+          </VbenButton>
+          <VbenButton
+            class="enter-x mr-2 w-full"
+            variant="ghost"
+            @click="toggleUnlockForm"
+          >
+            {{ $t('common.back') }}
+          </VbenButton>
+        </div>
+      </div>
+    </transition>
+
+    <div
+      class="enter-y absolute bottom-5 w-full text-center xl:text-xl 2xl:text-3xl"
+    >
+      <div v-if="showUnlockForm" class="enter-x mb-2 text-3xl">
+        {{ hour }}:{{ minute }} <span class="text-lg">{{ meridiem }}</span>
+      </div>
+      <div class="text-3xl">{{ date }}</div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/notification/index.ts b/eims-ui/packages/effects/layouts/src/widgets/notification/index.ts
new file mode 100644
index 0000000..e219b71
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/notification/index.ts
@@ -0,0 +1,3 @@
+export { default as Notification } from './notification.vue';
+
+export type * from './types';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/notification/notification.vue b/eims-ui/packages/effects/layouts/src/widgets/notification/notification.vue
new file mode 100644
index 0000000..946fdfd
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/notification/notification.vue
@@ -0,0 +1,186 @@
+<script lang="ts" setup>
+import type { NotificationItem } from './types';
+
+import { Bell, MailCheck } from '@vben/icons';
+import { $t } from '@vben/locales';
+import {
+  VbenButton,
+  VbenIconButton,
+  VbenPopover,
+  VbenScrollbar,
+} from '@vben-core/shadcn-ui';
+
+import { useToggle } from '@vueuse/core';
+
+interface Props {
+  /**
+   * 鏄剧ず鍦嗙偣
+   */
+  dot?: boolean;
+  /**
+   * 娑堟伅鍒楄〃
+   */
+  notifications?: NotificationItem[];
+}
+
+defineOptions({ name: 'NotificationPopup' });
+
+withDefaults(defineProps<Props>(), {
+  dot: false,
+  notifications: () => [],
+});
+
+const emit = defineEmits<{
+  clear: [];
+  makeAll: [];
+  read: [NotificationItem];
+  viewAll: [];
+}>();
+
+const [open, toggle] = useToggle();
+
+function close() {
+  open.value = false;
+}
+
+function handleViewAll() {
+  emit('viewAll');
+  close();
+}
+
+function handleMakeAll() {
+  emit('makeAll');
+}
+
+function handleClear() {
+  emit('clear');
+}
+
+function handleClick(item: NotificationItem) {
+  emit('read', item);
+}
+</script>
+<template>
+  <VbenPopover
+    v-model:open="open"
+    content-class="relative right-2 w-[360px] p-0"
+  >
+    <template #trigger>
+      <div class="flex-center mr-2 h-full" @click.stop="toggle()">
+        <VbenIconButton class="bell-button text-foreground relative">
+          <span
+            v-if="dot"
+            class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
+          ></span>
+          <Bell class="size-4" />
+        </VbenIconButton>
+      </div>
+    </template>
+
+    <div class="relative">
+      <div class="flex items-center justify-between p-4 py-3">
+        <div class="text-foreground">{{ $t('ui.widgets.notifications') }}</div>
+        <VbenIconButton
+          :disabled="notifications.length <= 0"
+          :tooltip="$t('ui.widgets.markAllAsRead')"
+          @click="handleMakeAll"
+        >
+          <MailCheck class="size-4" />
+        </VbenIconButton>
+      </div>
+      <VbenScrollbar v-if="notifications.length > 0">
+        <ul class="!flex max-h-[360px] w-full flex-col">
+          <template v-for="item in notifications" :key="item.title">
+            <li
+              class="hover:bg-accent border-border relative flex w-full cursor-pointer items-start gap-5 border-t px-3 py-3"
+              @click="handleClick(item)"
+            >
+              <span
+                v-if="!item.isRead"
+                class="bg-primary absolute right-2 top-2 h-2 w-2 rounded"
+              ></span>
+
+              <span
+                class="relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full"
+              >
+                <img
+                  :src="item.avatar"
+                  class="aspect-square h-full w-full object-cover"
+                  role="img"
+                />
+              </span>
+              <div class="flex flex-col gap-1 leading-none">
+                <p class="font-semibold">{{ item.title }}</p>
+                <p class="text-muted-foreground my-1 line-clamp-2 text-xs">
+                  {{ item.message }}
+                </p>
+                <p class="text-muted-foreground line-clamp-2 text-xs">
+                  {{ item.date }}
+                </p>
+              </div>
+            </li>
+          </template>
+        </ul>
+      </VbenScrollbar>
+
+      <template v-else>
+        <div class="flex-center text-muted-foreground min-h-[150px] w-full">
+          {{ $t('common.noData') }}
+        </div>
+      </template>
+
+      <div
+        class="border-border flex items-center justify-between border-t px-4 py-3"
+      >
+        <VbenButton
+          :disabled="notifications.length <= 0"
+          size="sm"
+          variant="ghost"
+          @click="handleClear"
+        >
+          {{ $t('ui.widgets.clearNotifications') }}
+        </VbenButton>
+        <VbenButton size="sm" @click="handleViewAll">
+          {{ $t('ui.widgets.viewAll') }}
+        </VbenButton>
+      </div>
+    </div>
+  </VbenPopover>
+</template>
+
+<style scoped>
+:deep(.bell-button) {
+  &:hover {
+    svg {
+      animation: bell-ring 1s both;
+    }
+  }
+}
+
+@keyframes bell-ring {
+  0%,
+  100% {
+    transform-origin: top;
+  }
+
+  15% {
+    transform: rotateZ(10deg);
+  }
+
+  30% {
+    transform: rotateZ(-10deg);
+  }
+
+  45% {
+    transform: rotateZ(5deg);
+  }
+
+  60% {
+    transform: rotateZ(-5deg);
+  }
+
+  75% {
+    transform: rotateZ(2deg);
+  }
+}
+</style>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/notification/types.ts b/eims-ui/packages/effects/layouts/src/widgets/notification/types.ts
new file mode 100644
index 0000000..3b50e12
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/notification/types.ts
@@ -0,0 +1,10 @@
+interface NotificationItem {
+  avatar: string;
+  date: string;
+  isRead?: boolean;
+  message: string;
+  title: string;
+  userId: number | string;
+}
+
+export type { NotificationItem };
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/block.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/block.vue
new file mode 100644
index 0000000..c8cc9e6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/block.vue
@@ -0,0 +1,22 @@
+<script setup lang="ts">
+interface Props {
+  title?: string;
+}
+
+defineOptions({
+  name: 'PreferenceBlock',
+});
+
+withDefaults(defineProps<Props>(), {
+  title: '',
+});
+</script>
+
+<template>
+  <div class="flex flex-col py-4">
+    <h3 class="mb-3 font-semibold leading-none tracking-tight">
+      {{ title }}
+    </h3>
+    <slot></slot>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue
new file mode 100644
index 0000000..b27d074
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceAnimation',
+});
+
+const transitionProgress = defineModel<boolean>('transitionProgress', {
+  // 榛樿鍊�
+  default: false,
+});
+const transitionName = defineModel<string>('transitionName');
+const transitionEnable = defineModel<boolean>('transitionEnable');
+const transitionLoading = defineModel<boolean>('transitionLoading');
+
+const transitionPreset = ['fade', 'fade-slide', 'fade-up', 'fade-down'];
+
+function handleClick(value: string) {
+  transitionName.value = value;
+}
+</script>
+
+<template>
+  <SwitchItem v-model="transitionProgress">
+    {{ $t('preferences.animation.progress') }}
+  </SwitchItem>
+  <SwitchItem v-model="transitionLoading">
+    {{ $t('preferences.animation.loading') }}
+  </SwitchItem>
+  <SwitchItem v-model="transitionEnable">
+    {{ $t('preferences.animation.transition') }}
+  </SwitchItem>
+  <div
+    v-if="transitionEnable"
+    class="mb-2 mt-3 flex justify-between gap-3 px-2"
+  >
+    <div
+      v-for="item in transitionPreset"
+      :key="item"
+      :class="{
+        'outline-box-active': transitionName === item,
+      }"
+      class="outline-box p-2"
+      @click="handleClick(item)"
+    >
+      <div :class="`${item}-slow`" class="bg-accent h-10 w-12 rounded-md"></div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue
new file mode 100644
index 0000000..630882f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue
@@ -0,0 +1,31 @@
+<script setup lang="ts">
+import { SUPPORT_LANGUAGES } from '@vben/constants';
+import { $t } from '@vben/locales';
+
+import SelectItem from '../select-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceGeneralConfig',
+});
+
+const appLocale = defineModel<string>('appLocale');
+const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
+const appWatermark = defineModel<boolean>('appWatermark');
+const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
+</script>
+
+<template>
+  <SelectItem v-model="appLocale" :items="SUPPORT_LANGUAGES">
+    {{ $t('preferences.language') }}
+  </SelectItem>
+  <SwitchItem v-model="appDynamicTitle">
+    {{ $t('preferences.dynamicTitle') }}
+  </SwitchItem>
+  <SwitchItem v-model="appWatermark">
+    {{ $t('preferences.watermark') }}
+  </SwitchItem>
+  <SwitchItem v-model="appEnableCheckUpdates">
+    {{ $t('preferences.checkUpdates') }}
+  </SwitchItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/index.ts b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/index.ts
new file mode 100644
index 0000000..59595dc
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/index.ts
@@ -0,0 +1,19 @@
+export { default as Block } from './block.vue';
+export { default as Animation } from './general/animation.vue';
+export { default as General } from './general/general.vue';
+export { default as Breadcrumb } from './layout/breadcrumb.vue';
+export { default as Content } from './layout/content.vue';
+export { default as Copyright } from './layout/copyright.vue';
+export { default as Footer } from './layout/footer.vue';
+export { default as Header } from './layout/header.vue';
+export { default as Layout } from './layout/layout.vue';
+export { default as Navigation } from './layout/navigation.vue';
+export { default as Sidebar } from './layout/sidebar.vue';
+export { default as Tabbar } from './layout/tabbar.vue';
+export { default as Widget } from './layout/widget.vue';
+export { default as GlobalShortcutKeys } from './shortcut-keys/global.vue';
+export { default as SwitchItem } from './switch-item.vue';
+export { default as BuiltinTheme } from './theme/builtin.vue';
+export { default as ColorMode } from './theme/color-mode.vue';
+export { default as Radius } from './theme/radius.vue';
+export { default as Theme } from './theme/theme.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
new file mode 100644
index 0000000..c480db0
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { useSlots } from 'vue';
+
+import { CircleHelp } from '@vben/icons';
+import { Input, VbenTooltip } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceSelectItem',
+});
+
+withDefaults(
+  defineProps<{
+    disabled?: boolean;
+    items?: SelectOption[];
+    placeholder?: string;
+  }>(),
+  {
+    disabled: false,
+    placeholder: '',
+    items: () => [],
+  },
+);
+
+const inputValue = defineModel<string>();
+
+const slots = useSlots();
+</script>
+
+<template>
+  <div
+    :class="{
+      'hover:bg-accent': !slots.tip,
+      'pointer-events-none opacity-50': disabled,
+    }"
+    class="my-1 flex w-full items-center justify-between rounded-md px-2 py-1"
+  >
+    <span class="flex items-center text-sm">
+      <slot></slot>
+
+      <VbenTooltip v-if="slots.tip" side="bottom">
+        <template #trigger>
+          <CircleHelp class="ml-1 size-3 cursor-help" />
+        </template>
+        <slot name="tip"></slot>
+      </VbenTooltip>
+    </span>
+    <Input v-model="inputValue" class="h-8 w-[165px]" />
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue
new file mode 100644
index 0000000..51f1a40
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue
@@ -0,0 +1,56 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+import ToggleItem from '../toggle-item.vue';
+
+defineOptions({
+  name: 'PreferenceBreadcrumbConfig',
+});
+
+const props = defineProps<{ disabled?: boolean }>();
+
+const breadcrumbEnable = defineModel<boolean>('breadcrumbEnable');
+const breadcrumbShowIcon = defineModel<boolean>('breadcrumbShowIcon');
+const breadcrumbStyleType = defineModel<string>('breadcrumbStyleType');
+const breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');
+const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
+
+const typeItems: SelectOption[] = [
+  { label: $t('preferences.normal'), value: 'normal' },
+  { label: $t('preferences.breadcrumb.background'), value: 'background' },
+];
+
+const disableItem = computed(() => {
+  return !breadcrumbEnable.value || props.disabled;
+});
+</script>
+
+<template>
+  <SwitchItem v-model="breadcrumbEnable" :disabled="disabled">
+    {{ $t('preferences.breadcrumb.enable') }}
+  </SwitchItem>
+  <SwitchItem v-model="breadcrumbHideOnlyOne" :disabled="disableItem">
+    {{ $t('preferences.breadcrumb.hideOnlyOne') }}
+  </SwitchItem>
+  <SwitchItem v-model="breadcrumbShowIcon" :disabled="disableItem">
+    {{ $t('preferences.breadcrumb.icon') }}
+  </SwitchItem>
+  <SwitchItem
+    v-model="breadcrumbShowHome"
+    :disabled="disableItem || !breadcrumbShowIcon"
+  >
+    {{ $t('preferences.breadcrumb.home') }}
+  </SwitchItem>
+  <ToggleItem
+    v-model="breadcrumbStyleType"
+    :disabled="disableItem"
+    :items="typeItems"
+  >
+    {{ $t('preferences.breadcrumb.style') }}
+  </ToggleItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue
new file mode 100644
index 0000000..cd77377
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import { type Component, computed } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import { ContentCompact, ContentWide } from '../../icons';
+
+defineOptions({
+  name: 'PreferenceLayoutContent',
+});
+
+const modelValue = defineModel<string>({ default: 'wide' });
+
+const components: Record<string, Component> = {
+  compact: ContentCompact,
+  wide: ContentWide,
+};
+
+const PRESET = computed(() => [
+  {
+    name: $t('preferences.wide'),
+    type: 'wide',
+  },
+  {
+    name: $t('preferences.compact'),
+    type: 'compact',
+  },
+]);
+
+function activeClass(theme: string): string[] {
+  return theme === modelValue.value ? ['outline-box-active'] : [];
+}
+</script>
+
+<template>
+  <div class="flex w-full gap-5">
+    <template v-for="theme in PRESET" :key="theme.name">
+      <div
+        class="flex w-[100px] cursor-pointer flex-col"
+        @click="modelValue = theme.type"
+      >
+        <div :class="activeClass(theme.type)" class="outline-box flex-center">
+          <component :is="components[theme.type]" />
+        </div>
+        <div class="text-muted-foreground mt-2 text-center text-xs">
+          {{ theme.name }}
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue
new file mode 100644
index 0000000..9389029
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue
@@ -0,0 +1,44 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import InputItem from '../input-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+const props = defineProps<{ disabled: boolean }>();
+
+const copyrightEnable = defineModel<boolean>('copyrightEnable');
+const copyrightDate = defineModel<string>('copyrightDate');
+const copyrightIcp = defineModel<string>('copyrightIcp');
+const copyrightIcpLink = defineModel<string>('copyrightIcpLink');
+const copyrightCompanyName = defineModel<string>('copyrightCompanyName');
+const copyrightCompanySiteLink = defineModel<string>(
+  'copyrightCompanySiteLink',
+);
+
+const itemDisabled = computed(() => props.disabled || !copyrightEnable.value);
+</script>
+
+<template>
+  <SwitchItem v-model="copyrightEnable" :disabled="disabled">
+    {{ $t('preferences.copyright.enable') }}
+  </SwitchItem>
+
+  <InputItem v-model="copyrightCompanyName" :disabled="itemDisabled">
+    {{ $t('preferences.copyright.companyName') }}
+  </InputItem>
+  <InputItem v-model="copyrightCompanySiteLink" :disabled="itemDisabled">
+    {{ $t('preferences.copyright.companySiteLink') }}
+  </InputItem>
+  <InputItem v-model="copyrightDate" :disabled="itemDisabled">
+    {{ $t('preferences.copyright.date') }}
+  </InputItem>
+
+  <InputItem v-model="copyrightIcp" :disabled="itemDisabled">
+    {{ $t('preferences.copyright.icp') }}
+  </InputItem>
+  <InputItem v-model="copyrightIcpLink" :disabled="itemDisabled">
+    {{ $t('preferences.copyright.icpLink') }}
+  </InputItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue
new file mode 100644
index 0000000..8a77920
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue
@@ -0,0 +1,17 @@
+<script setup lang="ts">
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+
+const footerEnable = defineModel<boolean>('footerEnable');
+const footerFixed = defineModel<boolean>('footerFixed');
+</script>
+
+<template>
+  <SwitchItem v-model="footerEnable">
+    {{ $t('preferences.footer.visible') }}
+  </SwitchItem>
+  <SwitchItem v-model="footerFixed" :disabled="!footerEnable">
+    {{ $t('preferences.footer.fixed') }}
+  </SwitchItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue
new file mode 100644
index 0000000..cdb236c
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import type { LayoutHeaderModeType, SelectOption } from '@vben/types';
+
+import { $t } from '@vben/locales';
+
+import SelectItem from '../select-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+defineProps<{ disabled: boolean }>();
+
+const headerEnable = defineModel<boolean>('headerEnable');
+const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
+
+const localeItems: SelectOption[] = [
+  {
+    label: $t('preferences.header.modeStatic'),
+    value: 'static',
+  },
+  {
+    label: $t('preferences.header.modeFixed'),
+    value: 'fixed',
+  },
+  {
+    label: $t('preferences.header.modeAuto'),
+    value: 'auto',
+  },
+  {
+    label: $t('preferences.header.modeAutoScroll'),
+    value: 'auto-scroll',
+  },
+];
+</script>
+
+<template>
+  <SwitchItem v-model="headerEnable" :disabled="disabled">
+    {{ $t('preferences.header.visible') }}
+  </SwitchItem>
+  <SelectItem
+    v-model="headerMode"
+    :disabled="!headerEnable"
+    :items="localeItems"
+  >
+    {{ $t('preferences.mode') }}
+  </SelectItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue
new file mode 100644
index 0000000..ec5d3cf
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue
@@ -0,0 +1,95 @@
+<script setup lang="ts">
+import type { LayoutType } from '@vben/types';
+
+import { type Component, computed } from 'vue';
+
+import { CircleHelp } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { VbenTooltip } from '@vben-core/shadcn-ui';
+
+import {
+  FullContent,
+  HeaderNav,
+  MixedNav,
+  SidebarMixedNav,
+  SidebarNav,
+} from '../../icons';
+
+interface PresetItem {
+  name: string;
+  tip: string;
+  type: LayoutType;
+}
+
+defineOptions({
+  name: 'PreferenceLayout',
+});
+
+const modelValue = defineModel<LayoutType>({ default: 'sidebar-nav' });
+
+const components: Record<LayoutType, Component> = {
+  'full-content': FullContent,
+  'header-nav': HeaderNav,
+  'mixed-nav': MixedNav,
+  'sidebar-mixed-nav': SidebarMixedNav,
+  'sidebar-nav': SidebarNav,
+};
+
+const PRESET = computed((): PresetItem[] => [
+  {
+    name: $t('preferences.vertical'),
+    tip: $t('preferences.verticalTip'),
+    type: 'sidebar-nav',
+  },
+  {
+    name: $t('preferences.twoColumn'),
+    tip: $t('preferences.twoColumnTip'),
+    type: 'sidebar-mixed-nav',
+  },
+  {
+    name: $t('preferences.horizontal'),
+    tip: $t('preferences.horizontalTip'),
+    type: 'header-nav',
+  },
+  {
+    name: $t('preferences.mixedMenu'),
+    tip: $t('preferences.mixedMenuTip'),
+    type: 'mixed-nav',
+  },
+  {
+    name: $t('preferences.fullContent'),
+    tip: $t('preferences.fullContentTip'),
+    type: 'full-content',
+  },
+]);
+
+function activeClass(theme: string): string[] {
+  return theme === modelValue.value ? ['outline-box-active'] : [];
+}
+</script>
+
+<template>
+  <div class="flex w-full flex-wrap gap-5">
+    <template v-for="theme in PRESET" :key="theme.name">
+      <div
+        class="flex w-[100px] cursor-pointer flex-col"
+        @click="modelValue = theme.type"
+      >
+        <div :class="activeClass(theme.type)" class="outline-box flex-center">
+          <component :is="components[theme.type]" />
+        </div>
+        <div
+          class="text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs"
+        >
+          {{ theme.name }}
+          <VbenTooltip v-if="theme.tip" side="bottom">
+            <template #trigger>
+              <CircleHelp class="ml-1 size-3 cursor-help" />
+            </template>
+            {{ theme.tip }}
+          </VbenTooltip>
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue
new file mode 100644
index 0000000..23acb1f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue
@@ -0,0 +1,45 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+import ToggleItem from '../toggle-item.vue';
+
+defineOptions({
+  name: 'PreferenceNavigationConfig',
+});
+
+defineProps<{ disabled?: boolean; disabledNavigationSplit?: boolean }>();
+
+const navigationStyleType = defineModel<string>('navigationStyleType');
+const navigationSplit = defineModel<boolean>('navigationSplit');
+const navigationAccordion = defineModel<boolean>('navigationAccordion');
+
+const stylesItems: SelectOption[] = [
+  { label: $t('preferences.rounded'), value: 'rounded' },
+  { label: $t('preferences.plain'), value: 'plain' },
+];
+</script>
+
+<template>
+  <ToggleItem
+    v-model="navigationStyleType"
+    :disabled="disabled"
+    :items="stylesItems"
+  >
+    {{ $t('preferences.navigationMenu.style') }}
+  </ToggleItem>
+  <SwitchItem
+    v-model="navigationSplit"
+    :disabled="disabledNavigationSplit || disabled"
+  >
+    {{ $t('preferences.navigationMenu.split') }}
+    <template #tip>
+      {{ $t('preferences.navigationMenu.splitTip') }}
+    </template>
+  </SwitchItem>
+  <SwitchItem v-model="navigationAccordion" :disabled="disabled">
+    {{ $t('preferences.navigationMenu.accordion') }}
+  </SwitchItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue
new file mode 100644
index 0000000..3c9efd6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue
@@ -0,0 +1,39 @@
+<script setup lang="ts">
+import { $t } from '@vben/locales';
+
+import NumberFieldItem from '../number-field-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+defineProps<{ disabled: boolean }>();
+
+const sidebarEnable = defineModel<boolean>('sidebarEnable');
+const sidebarWidth = defineModel<number>('sidebarWidth');
+const sidebarCollapsedShowTitle = defineModel<boolean>(
+  'sidebarCollapsedShowTitle',
+);
+const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
+</script>
+
+<template>
+  <SwitchItem v-model="sidebarEnable" :disabled="disabled">
+    {{ $t('preferences.sidebar.visible') }}
+  </SwitchItem>
+  <SwitchItem v-model="sidebarCollapsed" :disabled="!sidebarEnable || disabled">
+    {{ $t('preferences.sidebar.collapsed') }}
+  </SwitchItem>
+  <SwitchItem
+    v-model="sidebarCollapsedShowTitle"
+    :disabled="!sidebarEnable || disabled || !sidebarCollapsed"
+  >
+    {{ $t('preferences.sidebar.collapsedShowTitle') }}
+  </SwitchItem>
+  <NumberFieldItem
+    v-model="sidebarWidth"
+    :disabled="!sidebarEnable || disabled"
+    :max="320"
+    :min="160"
+    :step="10"
+  >
+    {{ $t('preferences.sidebar.width') }}
+  </NumberFieldItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue
new file mode 100644
index 0000000..5a3824a
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue
@@ -0,0 +1,68 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import SelectItem from '../select-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceTabsConfig',
+});
+
+defineProps<{ disabled?: boolean }>();
+
+const tabbarEnable = defineModel<boolean>('tabbarEnable');
+const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
+const tabbarPersist = defineModel<boolean>('tabbarPersist');
+const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
+const tabbarStyleType = defineModel<string>('tabbarStyleType');
+const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
+const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
+
+const styleItems = computed((): SelectOption[] => [
+  {
+    label: $t('preferences.tabbar.styleType.chrome'),
+    value: 'chrome',
+  },
+  {
+    label: $t('preferences.tabbar.styleType.plain'),
+    value: 'plain',
+  },
+  {
+    label: $t('preferences.tabbar.styleType.card'),
+    value: 'card',
+  },
+
+  {
+    label: $t('preferences.tabbar.styleType.brisk'),
+    value: 'brisk',
+  },
+]);
+</script>
+
+<template>
+  <SwitchItem v-model="tabbarEnable" :disabled="disabled">
+    {{ $t('preferences.tabbar.enable') }}
+  </SwitchItem>
+  <SwitchItem v-model="tabbarPersist" :disabled="!tabbarEnable">
+    {{ $t('preferences.tabbar.persist') }}
+  </SwitchItem>
+  <SwitchItem v-model="tabbarDraggable" :disabled="!tabbarEnable">
+    {{ $t('preferences.tabbar.draggable') }}
+  </SwitchItem>
+  <SwitchItem v-model="tabbarShowIcon" :disabled="!tabbarEnable">
+    {{ $t('preferences.tabbar.icon') }}
+  </SwitchItem>
+  <SwitchItem v-model="tabbarShowMore" :disabled="!tabbarEnable">
+    {{ $t('preferences.tabbar.showMore') }}
+  </SwitchItem>
+  <SwitchItem v-model="tabbarShowMaximize" :disabled="!tabbarEnable">
+    {{ $t('preferences.tabbar.showMaximize') }}
+  </SwitchItem>
+  <SelectItem v-model="tabbarStyleType" :items="styleItems">
+    {{ $t('preferences.tabbar.styleType.title') }}
+  </SelectItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue
new file mode 100644
index 0000000..82addb3
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue
@@ -0,0 +1,71 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+
+import SelectItem from '../select-item.vue';
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceInterfaceControl',
+});
+
+const widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');
+const widgetFullscreen = defineModel<boolean>('widgetFullscreen');
+const widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');
+const widgetNotification = defineModel<boolean>('widgetNotification');
+const widgetThemeToggle = defineModel<boolean>('widgetThemeToggle');
+const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');
+const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
+const appPreferencesButtonPosition = defineModel<string>(
+  'appPreferencesButtonPosition',
+);
+const widgetRefresh = defineModel<boolean>('widgetRefresh');
+
+const positionItems = computed((): SelectOption[] => [
+  {
+    label: $t('preferences.position.auto'),
+    value: 'auto',
+  },
+  {
+    label: $t('preferences.position.header'),
+    value: 'header',
+  },
+  {
+    label: $t('preferences.position.fixed'),
+    value: 'fixed',
+  },
+]);
+</script>
+
+<template>
+  <SwitchItem v-model="widgetGlobalSearch">
+    {{ $t('preferences.widget.globalSearch') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetThemeToggle">
+    {{ $t('preferences.widget.themeToggle') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetLanguageToggle">
+    {{ $t('preferences.widget.languageToggle') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetFullscreen">
+    {{ $t('preferences.widget.fullscreen') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetNotification">
+    {{ $t('preferences.widget.notification') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetLockScreen">
+    {{ $t('preferences.widget.lockScreen') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetSidebarToggle">
+    {{ $t('preferences.widget.sidebarToggle') }}
+  </SwitchItem>
+  <SwitchItem v-model="widgetRefresh">
+    {{ $t('preferences.widget.refresh') }}
+  </SwitchItem>
+  <SelectItem v-model="appPreferencesButtonPosition" :items="positionItems">
+    {{ $t('preferences.position.title') }}
+  </SelectItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue
new file mode 100644
index 0000000..00a5328
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue
@@ -0,0 +1,65 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { useSlots } from 'vue';
+
+import { CircleHelp } from '@vben/icons';
+import {
+  NumberField,
+  NumberFieldContent,
+  NumberFieldDecrement,
+  NumberFieldIncrement,
+  NumberFieldInput,
+  VbenTooltip,
+} from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceSelectItem',
+});
+
+withDefaults(
+  defineProps<{
+    disabled?: boolean;
+    items?: SelectOption[];
+    placeholder?: string;
+  }>(),
+  {
+    disabled: false,
+    placeholder: '',
+    items: () => [],
+  },
+);
+
+const inputValue = defineModel<number>();
+
+const slots = useSlots();
+</script>
+
+<template>
+  <div
+    :class="{
+      'hover:bg-accent': !slots.tip,
+      'pointer-events-none opacity-50': disabled,
+    }"
+    class="my-1 flex w-full items-center justify-between rounded-md px-2 py-1"
+  >
+    <span class="flex items-center text-sm">
+      <slot></slot>
+
+      <VbenTooltip v-if="slots.tip" side="bottom">
+        <template #trigger>
+          <CircleHelp class="ml-1 size-3 cursor-help" />
+        </template>
+        <slot name="tip"></slot>
+      </VbenTooltip>
+    </span>
+
+    <NumberField v-model="inputValue" v-bind="$attrs" class="w-[165px]">
+      <NumberFieldContent>
+        <NumberFieldDecrement />
+        <NumberFieldInput />
+        <NumberFieldIncrement />
+      </NumberFieldContent>
+    </NumberField>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue
new file mode 100644
index 0000000..4e31015
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue
@@ -0,0 +1,67 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { useSlots } from 'vue';
+
+import { CircleHelp } from '@vben/icons';
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+  VbenTooltip,
+} from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceSelectItem',
+});
+
+withDefaults(
+  defineProps<{
+    disabled?: boolean;
+    items?: SelectOption[];
+    placeholder?: string;
+  }>(),
+  {
+    disabled: false,
+    placeholder: '',
+    items: () => [],
+  },
+);
+
+const selectValue = defineModel<string>();
+
+const slots = useSlots();
+</script>
+
+<template>
+  <div
+    :class="{
+      'hover:bg-accent': !slots.tip,
+      'pointer-events-none opacity-50': disabled,
+    }"
+    class="my-1 flex w-full items-center justify-between rounded-md px-2 py-1"
+  >
+    <span class="flex items-center text-sm">
+      <slot></slot>
+
+      <VbenTooltip v-if="slots.tip" side="bottom">
+        <template #trigger>
+          <CircleHelp class="ml-1 size-3 cursor-help" />
+        </template>
+        <slot name="tip"></slot>
+      </VbenTooltip>
+    </span>
+    <Select v-model="selectValue">
+      <SelectTrigger class="h-8 w-[165px]">
+        <SelectValue :placeholder="placeholder" />
+      </SelectTrigger>
+      <SelectContent>
+        <template v-for="item in items" :key="item.value">
+          <SelectItem :value="item.value"> {{ item.label }} </SelectItem>
+        </template>
+      </SelectContent>
+    </Select>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue
new file mode 100644
index 0000000..f71a1f6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue
@@ -0,0 +1,50 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { $t } from '@vben/locales';
+import { isWindowsOs } from '@vben/utils';
+
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceGeneralConfig',
+});
+
+const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
+const shortcutKeysGlobalSearch = defineModel<boolean>(
+  'shortcutKeysGlobalSearch',
+);
+const shortcutKeysLogout = defineModel<boolean>('shortcutKeysLogout');
+// const shortcutKeysPreferences = defineModel<boolean>('shortcutKeysPreferences');
+const shortcutKeysLockScreen = defineModel<boolean>('shortcutKeysLockScreen');
+
+const altView = computed(() => (isWindowsOs() ? 'Alt' : '鈱�'));
+</script>
+
+<template>
+  <SwitchItem v-model="shortcutKeysEnable">
+    {{ $t('preferences.shortcutKeys.title') }}
+  </SwitchItem>
+  <SwitchItem
+    v-model="shortcutKeysGlobalSearch"
+    :disabled="!shortcutKeysEnable"
+  >
+    {{ $t('preferences.shortcutKeys.search') }}
+    <template #shortcut>
+      {{ isWindowsOs() ? 'Ctrl' : '鈱�' }}
+      <kbd> K </kbd>
+    </template>
+  </SwitchItem>
+  <SwitchItem v-model="shortcutKeysLogout" :disabled="!shortcutKeysEnable">
+    {{ $t('preferences.shortcutKeys.logout') }}
+    <template #shortcut> {{ altView }} Q </template>
+  </SwitchItem>
+  <!-- <SwitchItem v-model="shortcutKeysPreferences" :disabled="!shortcutKeysEnable">
+    {{ $t('preferences.shortcutKeys.preferences') }}
+    <template #shortcut> {{ altView }} , </template>
+  </SwitchItem> -->
+  <SwitchItem v-model="shortcutKeysLockScreen" :disabled="!shortcutKeysEnable">
+    {{ $t('ui.widgets.lockScreen.title') }}
+    <template #shortcut> {{ altView }} L </template>
+  </SwitchItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue
new file mode 100644
index 0000000..8ca7dd6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue
@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import { useSlots } from 'vue';
+
+import { CircleHelp } from '@vben/icons';
+import { Switch, VbenTooltip } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceSwitchItem',
+});
+
+withDefaults(defineProps<{ disabled?: boolean }>(), {
+  disabled: false,
+});
+
+const checked = defineModel<boolean>();
+
+const slots = useSlots();
+
+function handleClick() {
+  checked.value = !checked.value;
+}
+</script>
+
+<template>
+  <div
+    :class="{
+      'pointer-events-none opacity-50': disabled,
+    }"
+    class="hover:bg-accent my-1 flex w-full items-center justify-between rounded-md px-2 py-2.5"
+    @click="handleClick"
+  >
+    <span class="flex items-center text-sm">
+      <slot></slot>
+
+      <VbenTooltip v-if="slots.tip" side="bottom">
+        <template #trigger>
+          <CircleHelp class="ml-1 size-3 cursor-help" />
+        </template>
+        <slot name="tip"></slot>
+      </VbenTooltip>
+    </span>
+    <span v-if="$slots.shortcut" class="ml-auto mr-2 text-xs opacity-60">
+      <slot name="shortcut"></slot>
+    </span>
+    <Switch v-model:checked="checked" @click.stop />
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
new file mode 100644
index 0000000..480bc8c
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue
@@ -0,0 +1,141 @@
+<script setup lang="ts">
+import type { BuiltinThemeType } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { UserRoundPen } from '@vben/icons';
+import { $t } from '@vben/locales';
+import {
+  BUILT_IN_THEME_PRESETS,
+  type BuiltinThemePreset,
+} from '@vben/preferences';
+import { convertToHsl, TinyColor } from '@vben/utils';
+
+defineOptions({
+  name: 'PreferenceBuiltinTheme',
+});
+
+const props = defineProps<{ isDark: boolean }>();
+
+const colorInput = ref();
+const modelValue = defineModel<BuiltinThemeType>({ default: 'default' });
+const themeColorPrimary = defineModel<string>('themeColorPrimary');
+
+const inputValue = computed(() => {
+  return new TinyColor(themeColorPrimary.value || '').toHexString();
+});
+
+const builtinThemePresets = computed(() => {
+  return [...BUILT_IN_THEME_PRESETS];
+});
+
+function typeView(name: BuiltinThemeType) {
+  switch (name) {
+    case 'custom': {
+      return $t('preferences.theme.builtin.custom');
+    }
+    case 'deep-blue': {
+      return $t('preferences.theme.builtin.deepBlue');
+    }
+    case 'deep-green': {
+      return $t('preferences.theme.builtin.deepGreen');
+    }
+    case 'default': {
+      return $t('preferences.theme.builtin.default');
+    }
+    case 'gray': {
+      return $t('preferences.theme.builtin.gray');
+    }
+    case 'green': {
+      return $t('preferences.theme.builtin.green');
+    }
+
+    case 'neutral': {
+      return $t('preferences.theme.builtin.neutral');
+    }
+    case 'orange': {
+      return $t('preferences.theme.builtin.orange');
+    }
+    case 'pink': {
+      return $t('preferences.theme.builtin.pink');
+    }
+    case 'rose': {
+      return $t('preferences.theme.builtin.rose');
+    }
+    case 'sky-blue': {
+      return $t('preferences.theme.builtin.skyBlue');
+    }
+    case 'slate': {
+      return $t('preferences.theme.builtin.slate');
+    }
+    case 'violet': {
+      return $t('preferences.theme.builtin.violet');
+    }
+    case 'yellow': {
+      return $t('preferences.theme.builtin.yellow');
+    }
+    case 'zinc': {
+      return $t('preferences.theme.builtin.zinc');
+    }
+  }
+}
+
+function handleSelect(theme: BuiltinThemePreset) {
+  modelValue.value = theme.type;
+  const primaryColor = props.isDark
+    ? theme.darkPrimaryColor || theme.primaryColor
+    : theme.primaryColor;
+
+  themeColorPrimary.value = primaryColor || theme.color;
+}
+
+function handleInputChange(e: Event) {
+  const target = e.target as HTMLInputElement;
+  themeColorPrimary.value = convertToHsl(target.value);
+}
+
+function selectColor() {
+  colorInput.value?.[0]?.click?.();
+}
+</script>
+
+<template>
+  <div class="flex w-full flex-wrap justify-between">
+    <template v-for="theme in builtinThemePresets" :key="theme.type">
+      <div class="flex cursor-pointer flex-col" @click="handleSelect(theme)">
+        <div
+          :class="{
+            'outline-box-active': theme.type === modelValue,
+          }"
+          class="outline-box flex-center group cursor-pointer"
+        >
+          <template v-if="theme.type !== 'custom'">
+            <div
+              :style="{ backgroundColor: theme.color }"
+              class="mx-10 my-2 size-5 rounded-md"
+            ></div>
+          </template>
+          <template v-else>
+            <div class="size-full px-10 py-2" @click.stop="selectColor">
+              <div class="flex-center relative size-5 rounded-sm">
+                <UserRoundPen
+                  class="absolute z-10 size-5 opacity-60 group-hover:opacity-100"
+                />
+                <input
+                  ref="colorInput"
+                  :value="inputValue"
+                  class="absolute inset-0 opacity-0"
+                  type="color"
+                  @input="handleInputChange"
+                />
+              </div>
+            </div>
+          </template>
+        </div>
+        <div class="text-muted-foreground my-2 text-center text-xs">
+          {{ typeView(theme.type) }}
+        </div>
+      </div>
+    </template>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue
new file mode 100644
index 0000000..9a41d4e
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue
@@ -0,0 +1,26 @@
+<script setup lang="ts">
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceColorMode',
+});
+
+const appColorWeakMode = defineModel<boolean>('appColorWeakMode', {
+  default: false,
+});
+
+const appColorGrayMode = defineModel<boolean>('appColorGrayMode', {
+  default: false,
+});
+</script>
+
+<template>
+  <SwitchItem v-model="appColorWeakMode">
+    {{ $t('preferences.theme.weakMode') }}
+  </SwitchItem>
+  <SwitchItem v-model="appColorGrayMode">
+    {{ $t('preferences.theme.grayMode') }}
+  </SwitchItem>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue
new file mode 100644
index 0000000..4201ed6
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue
@@ -0,0 +1,38 @@
+<script setup lang="ts">
+import { ToggleGroup, ToggleGroupItem } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceColorMode',
+});
+
+const modelValue = defineModel<string | undefined>('themeRadius', {
+  default: '0.5',
+});
+
+const items = [
+  { label: '0', value: '0' },
+  { label: '0.25', value: '0.25' },
+  { label: '0.5', value: '0.5' },
+  { label: '0.75', value: '0.75' },
+  { label: '1', value: '1' },
+];
+</script>
+
+<template>
+  <ToggleGroup
+    v-model="modelValue"
+    class="gap-2"
+    size="sm"
+    type="single"
+    variant="outline"
+  >
+    <template v-for="item in items" :key="item.value">
+      <ToggleGroupItem
+        :value="item.value"
+        class="data-[state=on]:bg-primary data-[state=on]:text-primary-foreground h-7 w-16 rounded-sm"
+      >
+        {{ item.label }}
+      </ToggleGroupItem>
+    </template>
+  </ToggleGroup>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue
new file mode 100644
index 0000000..e509d66
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue
@@ -0,0 +1,83 @@
+<script setup lang="ts">
+import type { ThemeModeType } from '@vben/types';
+
+import type { Component } from 'vue';
+
+import { MoonStar, Sun, SunMoon } from '@vben/icons';
+import { $t } from '@vben/locales';
+
+import SwitchItem from '../switch-item.vue';
+
+defineOptions({
+  name: 'PreferenceTheme',
+});
+
+const modelValue = defineModel<string>({ default: 'auto' });
+const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
+const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
+
+const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
+  {
+    icon: Sun,
+    name: 'light',
+  },
+  {
+    icon: MoonStar,
+    name: 'dark',
+  },
+  {
+    icon: SunMoon,
+    name: 'auto',
+  },
+];
+
+function activeClass(theme: string): string[] {
+  return theme === modelValue.value ? ['outline-box-active'] : [];
+}
+
+function nameView(name: string) {
+  switch (name) {
+    case 'auto': {
+      return $t('preferences.followSystem');
+    }
+    case 'dark': {
+      return $t('preferences.theme.dark');
+    }
+    case 'light': {
+      return $t('preferences.theme.light');
+    }
+  }
+}
+</script>
+
+<template>
+  <div class="flex w-full flex-wrap justify-between">
+    <template v-for="theme in THEME_PRESET" :key="theme.name">
+      <div
+        class="flex cursor-pointer flex-col"
+        @click="modelValue = theme.name"
+      >
+        <div
+          :class="activeClass(theme.name)"
+          class="outline-box flex-center py-4"
+        >
+          <component :is="theme.icon" class="mx-9 size-5" />
+        </div>
+        <div class="text-muted-foreground mt-2 text-center text-xs">
+          {{ nameView(theme.name) }}
+        </div>
+      </div>
+    </template>
+
+    <SwitchItem
+      v-model="themeSemiDarkSidebar"
+      :disabled="modelValue === 'dark'"
+      class="mt-6"
+    >
+      {{ $t('preferences.theme.darkSidebar') }}
+    </SwitchItem>
+    <SwitchItem v-model="themeSemiDarkHeader" :disabled="modelValue === 'dark'">
+      {{ $t('preferences.theme.darkHeader') }}
+    </SwitchItem>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue
new file mode 100644
index 0000000..df2c39f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue
@@ -0,0 +1,46 @@
+<script setup lang="ts">
+import type { SelectOption } from '@vben/types';
+
+import { ToggleGroup, ToggleGroupItem } from '@vben-core/shadcn-ui';
+
+defineOptions({
+  name: 'PreferenceToggleItem',
+});
+
+withDefaults(defineProps<{ disabled?: boolean; items: SelectOption[] }>(), {
+  disabled: false,
+  items: () => [],
+});
+
+const modelValue = defineModel<string>();
+</script>
+
+<template>
+  <div
+    :class="{
+      'pointer-events-none opacity-50': disabled,
+    }"
+    class="hover:bg-accent flex w-full items-center justify-between rounded-md px-2 py-2"
+    disabled
+  >
+    <span class="text-sm">
+      <slot></slot>
+    </span>
+    <ToggleGroup
+      v-model="modelValue"
+      class="gap-2"
+      size="sm"
+      type="single"
+      variant="outline"
+    >
+      <template v-for="item in items" :key="item.value">
+        <ToggleGroupItem
+          :value="item.value"
+          class="data-[state=on]:bg-primary data-[state=on]:text-primary-foreground h-7 rounded-sm"
+        >
+          {{ item.label }}
+        </ToggleGroupItem>
+      </template>
+    </ToggleGroup>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue
new file mode 100644
index 0000000..a1bcefd
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue
@@ -0,0 +1,119 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <rect
+        id="svg_1"
+        fill="currentColor"
+        fill-opacity="0.02"
+        height="66"
+        rx="4"
+        stroke="null"
+        width="104"
+        x="0.13514"
+        y="0.13514"
+      />
+      <rect
+        id="svg_8"
+        fill="hsl(var(--primary))"
+        height="9.07027"
+        stroke="null"
+        width="104.07934"
+        x="-0.07419"
+        y="-0.05773"
+      />
+      <rect
+        id="svg_3"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="15.58168"
+        y="3.20832"
+      />
+      <path
+        id="svg_12"
+        d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
+        fill="#ffffff"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.51892"
+        rx="2"
+        stroke="null"
+        width="41.98275"
+        x="45.37589"
+        y="13.53192"
+      />
+      <path
+        id="svg_14"
+        d="m16.4123,15.53192c0,-1.08676 0.74096,-2 1.62271,-2l21.74653,0c0.88175,0 1.62271,0.91324 1.62271,2l0,17.24865c0,1.08676 -0.74096,2 -1.62271,2l-21.74653,0c-0.88175,0 -1.62271,-0.91324 -1.62271,-2l0,-17.24865z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.65405"
+        rx="2"
+        stroke="null"
+        width="71.10636"
+        x="16.54743"
+        y="39.34689"
+      />
+      <rect
+        id="svg_21"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="28.14924"
+        y="3.07319"
+      />
+      <rect
+        id="svg_22"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="41.25735"
+        y="3.20832"
+      />
+      <rect
+        id="svg_23"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="54.23033"
+        y="3.07319"
+      />
+      <rect
+        id="svg_4"
+        fill="#ffffff"
+        height="7.13843"
+        rx="2"
+        stroke="null"
+        width="7.78397"
+        x="1.5327"
+        y="0.881"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue
new file mode 100644
index 0000000..5cbcaca
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue
@@ -0,0 +1,50 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <path
+        id="svg_1"
+        d="m0.13514,4.13514c0,-2.17352 1.82648,-4 4,-4l96,0c2.17352,0 4,1.82648 4,4l0,58c0,2.17352 -1.82648,4 -4,4l-96,0c-2.17352,0 -4,-1.82648 -4,-4l0,-58z"
+        fill="currentColor"
+        fill-opacity="0.02"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="26.57155"
+        rx="2"
+        stroke="null"
+        width="53.18333"
+        x="45.79979"
+        y="3.77232"
+      />
+      <path
+        id="svg_14"
+        d="m4.28142,5.96169c0,-1.37748 1.06465,-2.53502 2.33158,-2.53502l31.2463,0c1.26693,0 2.33158,1.15754 2.33158,2.53502l0,21.86282c0,1.37748 -1.06465,2.53502 -2.33158,2.53502l-31.2463,0c-1.26693,0 -2.33158,-1.15754 -2.33158,-2.53502l0,-21.86282z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="25.02247"
+        rx="2"
+        stroke="null"
+        width="94.39371"
+        x="4.56735"
+        y="34.92584"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue
new file mode 100644
index 0000000..18158b3
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue
@@ -0,0 +1,119 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <rect
+        id="svg_1"
+        fill="currentColor"
+        fill-opacity="0.02"
+        height="66"
+        rx="4"
+        stroke="null"
+        width="104"
+        x="0.13514"
+        y="0.13514"
+      />
+      <rect
+        id="svg_8"
+        fill="hsl(var(--primary))"
+        height="9.07027"
+        stroke="null"
+        width="104.07934"
+        x="-0.07419"
+        y="-0.05773"
+      />
+      <rect
+        id="svg_3"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="15.58168"
+        y="3.20832"
+      />
+      <path
+        id="svg_12"
+        d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
+        fill="#ffffff"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.51892"
+        rx="2"
+        stroke="null"
+        width="53.60438"
+        x="43.484"
+        y="13.66705"
+      />
+      <path
+        id="svg_14"
+        d="m3.43932,15.53192c0,-1.08676 1.03344,-2 2.26323,-2l30.33036,0c1.22979,0 2.26323,0.91324 2.26323,2l0,17.24865c0,1.08676 -1.03344,2 -2.26323,2l-30.33036,0c-1.22979,0 -2.26323,-0.91324 -2.26323,-2l0,-17.24865z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.65405"
+        rx="2"
+        stroke="null"
+        width="95.02528"
+        x="3.30419"
+        y="39.34689"
+      />
+      <rect
+        id="svg_21"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="28.14924"
+        y="3.07319"
+      />
+      <rect
+        id="svg_22"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="41.25735"
+        y="3.20832"
+      />
+      <rect
+        id="svg_23"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="54.23033"
+        y="3.07319"
+      />
+      <rect
+        id="svg_4"
+        fill="#ffffff"
+        height="7.13843"
+        rx="2"
+        stroke="null"
+        width="7.78397"
+        x="1.5327"
+        y="0.881"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/index.ts b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/index.ts
new file mode 100644
index 0000000..c0c5a28
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/index.ts
@@ -0,0 +1,10 @@
+import HeaderNav from './header-nav.vue';
+
+export { default as ContentCompact } from './content-compact.vue';
+export { default as FullContent } from './full-content.vue';
+export { default as MixedNav } from './mixed-nav.vue';
+export { default as SidebarMixedNav } from './sidebar-mixed-nav.vue';
+export { default as SidebarNav } from './sidebar-nav.vue';
+
+const ContentWide = HeaderNav;
+export { ContentWide, HeaderNav };
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue
new file mode 100644
index 0000000..d194383
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue
@@ -0,0 +1,161 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <rect
+        id="svg_1"
+        fill="currentColor"
+        fill-opacity="0.02"
+        height="66"
+        rx="4"
+        stroke="null"
+        width="104"
+        x="0.13514"
+        y="0.13514"
+      />
+      <rect
+        id="svg_8"
+        fill="hsl(var(--primary))"
+        height="9.07027"
+        stroke="null"
+        width="104.07934"
+        x="-0.07419"
+        y="-0.05773"
+      />
+      <rect
+        id="svg_3"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="15.58168"
+        y="3.20832"
+      />
+      <path
+        id="svg_12"
+        d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
+        fill="#ffffff"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.51892"
+        rx="2"
+        stroke="null"
+        width="44.13071"
+        x="53.37873"
+        y="13.45652"
+      />
+      <path
+        id="svg_14"
+        d="m19.4393,15.74245c0,-1.08676 0.79001,-2 1.73013,-2l23.18605,0c0.94011,0 1.73013,0.91324 1.73013,2l0,17.24865c0,1.08676 -0.79001,2 -1.73013,2l-23.18605,0c-0.94011,0 -1.73013,-0.91324 -1.73013,-2l0,-17.24865z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.65405"
+        rx="2"
+        stroke="null"
+        width="78.39372"
+        x="19.93575"
+        y="39.34689"
+      />
+      <rect
+        id="svg_21"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="28.14924"
+        y="3.07319"
+      />
+      <rect
+        id="svg_22"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="41.25735"
+        y="3.20832"
+      />
+      <rect
+        id="svg_23"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="7.52486"
+        x="54.23033"
+        y="3.07319"
+      />
+      <rect
+        id="svg_4"
+        fill="#ffffff"
+        height="7.13843"
+        rx="2"
+        stroke="null"
+        width="7.78397"
+        x="1.5327"
+        y="0.881"
+      />
+      <rect
+        id="svg_5"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="56.81191"
+        stroke="null"
+        width="15.44642"
+        x="-0.06423"
+        y="9.03113"
+      />
+      <path
+        id="svg_2"
+        d="m2.38669,15.38074c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <path
+        id="svg_6"
+        d="m2.38669,28.43336c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <path
+        id="svg_7"
+        d="m2.17616,41.27545c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+      <path
+        id="svg_9"
+        d="m2.17616,54.32806c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
+        fill="currentColor"
+        fill-opacity="0.08"
+        opacity="undefined"
+        stroke="null"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/setting.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/setting.vue
new file mode 100644
index 0000000..d824e11
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/setting.vue
@@ -0,0 +1,12 @@
+<template>
+  <svg
+    height="1em"
+    viewBox="0 0 24 24"
+    width="1em"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M19.9 12.66a1 1 0 0 1 0-1.32l1.28-1.44a1 1 0 0 0 .12-1.17l-2-3.46a1 1 0 0 0-1.07-.48l-1.88.38a1 1 0 0 1-1.15-.66l-.61-1.83a1 1 0 0 0-.95-.68h-4a1 1 0 0 0-1 .68l-.56 1.83a1 1 0 0 1-1.15.66L5 4.79a1 1 0 0 0-1 .48L2 8.73a1 1 0 0 0 .1 1.17l1.27 1.44a1 1 0 0 1 0 1.32L2.1 14.1a1 1 0 0 0-.1 1.17l2 3.46a1 1 0 0 0 1.07.48l1.88-.38a1 1 0 0 1 1.15.66l.61 1.83a1 1 0 0 0 1 .68h4a1 1 0 0 0 .95-.68l.61-1.83a1 1 0 0 1 1.15-.66l1.88.38a1 1 0 0 0 1.07-.48l2-3.46a1 1 0 0 0-.12-1.17ZM18.41 14l.8.9l-1.28 2.22l-1.18-.24a3 3 0 0 0-3.45 2L12.92 20h-2.56L10 18.86a3 3 0 0 0-3.45-2l-1.18.24l-1.3-2.21l.8-.9a3 3 0 0 0 0-4l-.8-.9l1.28-2.2l1.18.24a3 3 0 0 0 3.45-2L10.36 4h2.56l.38 1.14a3 3 0 0 0 3.45 2l1.18-.24l1.28 2.22l-.8.9a3 3 0 0 0 0 3.98m-6.77-6a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2"
+    />
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue
new file mode 100644
index 0000000..8fc0ba4
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue
@@ -0,0 +1,173 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <rect
+        id="svg_1"
+        fill="currentColor"
+        fill-opacity="0.02"
+        height="66"
+        rx="4"
+        stroke="null"
+        width="104"
+        x="0.13514"
+        y="0.13514"
+      />
+      <path
+        id="svg_2"
+        d="m-3.37838,3.7543a1.93401,4.02457 0 0 1 1.93401,-4.02457l11.3488,0l0,66.40541l-11.3488,0a1.93401,4.02457 0 0 1 -1.93401,-4.02457l0,-58.35627z"
+        fill="hsl(var(--primary))"
+        stroke="null"
+      />
+      <rect
+        id="svg_3"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="5.47439"
+        x="1.64059"
+        y="15.46086"
+      />
+      <rect
+        id="svg_4"
+        fill="#ffffff"
+        height="7.67897"
+        rx="2"
+        stroke="null"
+        width="8.18938"
+        x="0.58676"
+        y="1.42154"
+      />
+      <rect
+        id="svg_8"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="9.07027"
+        rx="2"
+        stroke="null"
+        width="75.91967"
+        x="25.38277"
+        y="1.42876"
+      />
+      <rect
+        id="svg_9"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="27.91529"
+        y="3.69284"
+      />
+      <rect
+        id="svg_10"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="80.75054"
+        y="3.62876"
+      />
+      <rect
+        id="svg_11"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="87.78868"
+        y="3.69981"
+      />
+      <rect
+        id="svg_12"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="94.6847"
+        y="3.62876"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.51892"
+        rx="2"
+        stroke="null"
+        width="42.9287"
+        x="58.75427"
+        y="14.613"
+      />
+      <rect
+        id="svg_14"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="20.97838"
+        rx="2"
+        stroke="null"
+        width="28.36894"
+        x="26.14342"
+        y="14.613"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.65405"
+        rx="2"
+        stroke="null"
+        width="75.09493"
+        x="26.34264"
+        y="39.68822"
+      />
+      <rect
+        id="svg_5"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="5.47439"
+        x="1.79832"
+        y="28.39462"
+      />
+      <rect
+        id="svg_6"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="5.47439"
+        x="1.64059"
+        y="41.80156"
+      />
+      <rect
+        id="svg_7"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        stroke="null"
+        width="5.47439"
+        x="1.64059"
+        y="55.36623"
+      />
+      <rect
+        id="svg_16"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="65.72065"
+        stroke="null"
+        width="12.49265"
+        x="9.85477"
+        y="-0.02618"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue
new file mode 100644
index 0000000..83ff399
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue
@@ -0,0 +1,153 @@
+<template>
+  <svg
+    class="custom-radio-image"
+    fill="none"
+    height="66"
+    width="104"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g>
+      <rect
+        id="svg_1"
+        fill="currentColor"
+        fill-opacity="0.02"
+        height="66"
+        rx="4"
+        stroke="null"
+        width="104"
+      />
+      <path
+        id="svg_2"
+        d="m-3.37838,3.61916a4.4919,4.02457 0 0 1 4.4919,-4.02457l26.35848,0l0,66.40541l-26.35848,0a4.4919,4.02457 0 0 1 -4.4919,-4.02457l0,-58.35627z"
+        fill="hsl(var(--primary))"
+        stroke="null"
+      />
+      <rect
+        id="svg_3"
+        fill="#e5e5e5"
+        height="2.789"
+        rx="1.395"
+        width="17.66"
+        x="4.906"
+        y="23.884"
+      />
+      <rect
+        id="svg_4"
+        fill="#ffffff"
+        height="9.706"
+        rx="2"
+        width="9.811"
+        x="8.83"
+        y="5.881"
+      />
+      <path
+        id="svg_5"
+        d="m4.906,35.833c0,-0.75801 0.63699,-1.395 1.395,-1.395l14.87,0c0.75801,0 1.395,0.63699 1.395,1.395l0,-0.001c0,0.75801 -0.63699,1.395 -1.395,1.395l-14.87,0c-0.75801,0 -1.395,-0.63699 -1.395,-1.395l0,0.001z"
+        fill="#ffffff"
+        opacity="undefined"
+      />
+      <rect
+        id="svg_6"
+        fill="#ffffff"
+        height="2.789"
+        rx="1.395"
+        width="17.66"
+        x="4.906"
+        y="44.992"
+      />
+      <rect
+        id="svg_7"
+        fill="#ffffff"
+        height="2.789"
+        rx="1.395"
+        width="17.66"
+        x="4.906"
+        y="55.546"
+      />
+      <rect
+        id="svg_8"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="9.07027"
+        rx="2"
+        stroke="null"
+        width="73.53879"
+        x="28.97986"
+        y="1.42876"
+      />
+      <rect
+        id="svg_9"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="32.039"
+        y="3.89903"
+      />
+      <rect
+        id="svg_10"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="80.75054"
+        y="3.62876"
+      />
+      <rect
+        id="svg_11"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="87.58249"
+        y="3.49362"
+      />
+      <rect
+        id="svg_12"
+        fill="#b2b2b2"
+        height="4.4"
+        rx="1"
+        stroke="null"
+        width="3.925"
+        x="94.6847"
+        y="3.62876"
+      />
+      <rect
+        id="svg_13"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.51892"
+        rx="2"
+        stroke="null"
+        width="45.63141"
+        x="56.05157"
+        y="14.613"
+      />
+      <rect
+        id="svg_14"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="20.97838"
+        rx="2"
+        stroke="null"
+        width="22.82978"
+        x="29.38527"
+        y="14.613"
+      />
+      <rect
+        id="svg_15"
+        fill="currentColor"
+        fill-opacity="0.08"
+        height="21.65405"
+        rx="2"
+        stroke="null"
+        width="72.45771"
+        x="28.97986"
+        y="39.48203"
+      />
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/index.ts b/eims-ui/packages/effects/layouts/src/widgets/preferences/index.ts
new file mode 100644
index 0000000..0a7d32c
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/index.ts
@@ -0,0 +1,3 @@
+export { default as Preferences } from './preferences.vue';
+export { default as PreferencesButton } from './preferences-button.vue';
+export * from './use-open-preferences';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-button.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-button.vue
new file mode 100644
index 0000000..29e110d
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-button.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { Settings } from '@vben/icons';
+import { VbenIconButton } from '@vben-core/shadcn-ui';
+
+import Preferences from './preferences.vue';
+
+const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
+
+function clearPreferencesAndLogout() {
+  emit('clearPreferencesAndLogout');
+}
+</script>
+<template>
+  <Preferences @clear-preferences-and-logout="clearPreferencesAndLogout">
+    <VbenIconButton>
+      <Settings class="text-foreground size-4" />
+    </VbenIconButton>
+  </Preferences>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue
new file mode 100644
index 0000000..77bf4d7
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue
@@ -0,0 +1,423 @@
+<script setup lang="ts">
+import type { SupportedLanguagesType } from '@vben/locales';
+import type {
+  BreadcrumbStyleType,
+  BuiltinThemeType,
+  ContentCompactType,
+  LayoutHeaderModeType,
+  LayoutType,
+  NavigationStyleType,
+  PreferencesButtonPositionType,
+  ThemeModeType,
+} from '@vben/types';
+import type { SegmentedItem } from '@vben-core/shadcn-ui';
+
+import { computed, ref } from 'vue';
+
+import { Copy, RotateCw } from '@vben/icons';
+import { $t, loadLocaleMessages } from '@vben/locales';
+import {
+  clearPreferencesCache,
+  preferences,
+  resetPreferences,
+  usePreferences,
+} from '@vben/preferences';
+import { useVbenDrawer } from '@vben-core/popup-ui';
+import {
+  VbenButton,
+  VbenIconButton,
+  VbenSegmented,
+} from '@vben-core/shadcn-ui';
+import { globalShareState } from '@vben-core/shared/global-state';
+
+import { useClipboard } from '@vueuse/core';
+
+import {
+  Animation,
+  Block,
+  Breadcrumb,
+  BuiltinTheme,
+  ColorMode,
+  Content,
+  Copyright,
+  Footer,
+  General,
+  GlobalShortcutKeys,
+  Header,
+  Layout,
+  Navigation,
+  Radius,
+  Sidebar,
+  Tabbar,
+  Theme,
+  Widget,
+} from './blocks';
+
+const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
+
+const message = globalShareState.getMessage();
+
+const appLocale = defineModel<SupportedLanguagesType>('appLocale');
+const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
+const appLayout = defineModel<LayoutType>('appLayout');
+const appColorGrayMode = defineModel<boolean>('appColorGrayMode');
+const appColorWeakMode = defineModel<boolean>('appColorWeakMode');
+const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
+const appWatermark = defineModel<boolean>('appWatermark');
+const appEnableCheckUpdates = defineModel<boolean>('appEnableCheckUpdates');
+const appPreferencesButtonPosition = defineModel<PreferencesButtonPositionType>(
+  'appPreferencesButtonPosition',
+);
+
+const transitionProgress = defineModel<boolean>('transitionProgress');
+const transitionName = defineModel<string>('transitionName');
+const transitionLoading = defineModel<boolean>('transitionLoading');
+const transitionEnable = defineModel<boolean>('transitionEnable');
+
+const themeColorPrimary = defineModel<string>('themeColorPrimary');
+const themeBuiltinType = defineModel<BuiltinThemeType>('themeBuiltinType');
+const themeMode = defineModel<ThemeModeType>('themeMode');
+const themeRadius = defineModel<string>('themeRadius');
+const themeSemiDarkSidebar = defineModel<boolean>('themeSemiDarkSidebar');
+const themeSemiDarkHeader = defineModel<boolean>('themeSemiDarkHeader');
+
+const sidebarEnable = defineModel<boolean>('sidebarEnable');
+const sidebarWidth = defineModel<number>('sidebarWidth');
+const sidebarCollapsed = defineModel<boolean>('sidebarCollapsed');
+const sidebarCollapsedShowTitle = defineModel<boolean>(
+  'sidebarCollapsedShowTitle',
+);
+
+const headerEnable = defineModel<boolean>('headerEnable');
+const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
+
+const breadcrumbEnable = defineModel<boolean>('breadcrumbEnable');
+const breadcrumbShowIcon = defineModel<boolean>('breadcrumbShowIcon');
+const breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');
+const breadcrumbStyleType = defineModel<BreadcrumbStyleType>(
+  'breadcrumbStyleType',
+);
+const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
+
+const tabbarEnable = defineModel<boolean>('tabbarEnable');
+const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
+const tabbarShowMore = defineModel<boolean>('tabbarShowMore');
+const tabbarShowMaximize = defineModel<boolean>('tabbarShowMaximize');
+const tabbarPersist = defineModel<boolean>('tabbarPersist');
+const tabbarDraggable = defineModel<boolean>('tabbarDraggable');
+const tabbarStyleType = defineModel<string>('tabbarStyleType');
+
+const navigationStyleType = defineModel<NavigationStyleType>(
+  'navigationStyleType',
+);
+const navigationSplit = defineModel<boolean>('navigationSplit');
+const navigationAccordion = defineModel<boolean>('navigationAccordion');
+
+// const logoVisible = defineModel<boolean>('logoVisible');
+
+const footerEnable = defineModel<boolean>('footerEnable');
+const footerFixed = defineModel<boolean>('footerFixed');
+
+const copyrightSettingShow = defineModel<boolean>('copyrightSettingShow');
+const copyrightEnable = defineModel<boolean>('copyrightEnable');
+const copyrightCompanyName = defineModel<string>('copyrightCompanyName');
+const copyrightCompanySiteLink = defineModel<string>(
+  'copyrightCompanySiteLink',
+);
+const copyrightDate = defineModel<string>('copyrightDate');
+const copyrightIcp = defineModel<string>('copyrightIcp');
+const copyrightIcpLink = defineModel<string>('copyrightIcpLink');
+
+const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
+const shortcutKeysGlobalSearch = defineModel<boolean>(
+  'shortcutKeysGlobalSearch',
+);
+const shortcutKeysGlobalLogout = defineModel<boolean>(
+  'shortcutKeysGlobalLogout',
+);
+
+const shortcutKeysGlobalLockScreen = defineModel<boolean>(
+  'shortcutKeysGlobalLockScreen',
+);
+
+const widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');
+const widgetFullscreen = defineModel<boolean>('widgetFullscreen');
+const widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');
+const widgetNotification = defineModel<boolean>('widgetNotification');
+const widgetThemeToggle = defineModel<boolean>('widgetThemeToggle');
+const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');
+const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
+const widgetRefresh = defineModel<boolean>('widgetRefresh');
+
+const {
+  diffPreference,
+  isDark,
+  isFullContent,
+  isHeaderNav,
+  isMixedNav,
+  isSideMixedNav,
+  isSideMode,
+  isSideNav,
+} = usePreferences();
+const { copy } = useClipboard({ legacy: true });
+
+const [Drawer] = useVbenDrawer();
+
+const activeTab = ref('appearance');
+
+const tabs = computed((): SegmentedItem[] => {
+  return [
+    {
+      label: $t('preferences.appearance'),
+      value: 'appearance',
+    },
+    {
+      label: $t('preferences.layout'),
+      value: 'layout',
+    },
+    {
+      label: $t('preferences.shortcutKeys.title'),
+      value: 'shortcutKey',
+    },
+    {
+      label: $t('preferences.general'),
+      value: 'general',
+    },
+  ];
+});
+
+const showBreadcrumbConfig = computed(() => {
+  return (
+    !isFullContent.value &&
+    !isMixedNav.value &&
+    !isHeaderNav.value &&
+    preferences.header.enable
+  );
+});
+
+async function handleCopy() {
+  await copy(JSON.stringify(diffPreference.value, null, 2));
+
+  message.copyPreferencesSuccess?.(
+    $t('preferences.copyPreferencesSuccessTitle'),
+    $t('preferences.copyPreferencesSuccess'),
+  );
+}
+
+async function handleClearCache() {
+  resetPreferences();
+  clearPreferencesCache();
+  emit('clearPreferencesAndLogout');
+}
+
+async function handleReset() {
+  if (!diffPreference.value) {
+    return;
+  }
+  resetPreferences();
+  await loadLocaleMessages(preferences.app.locale);
+}
+</script>
+
+<template>
+  <div>
+    <Drawer
+      :description="$t('preferences.subtitle')"
+      :title="$t('preferences.title')"
+      class="sm:max-w-sm"
+    >
+      <template #extra>
+        <div class="flex items-center">
+          <VbenIconButton
+            :disabled="!diffPreference"
+            :tooltip="$t('preferences.resetTip')"
+            class="relative"
+          >
+            <span
+              v-if="diffPreference"
+              class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
+            ></span>
+            <RotateCw class="size-4" @click="handleReset" />
+          </VbenIconButton>
+        </div>
+      </template>
+
+      <div class="p-1">
+        <VbenSegmented v-model="activeTab" :tabs="tabs">
+          <template #general>
+            <Block :title="$t('preferences.general')">
+              <General
+                v-model:app-dynamic-title="appDynamicTitle"
+                v-model:app-enable-check-updates="appEnableCheckUpdates"
+                v-model:app-locale="appLocale"
+                v-model:app-watermark="appWatermark"
+              />
+            </Block>
+
+            <Block :title="$t('preferences.animation.title')">
+              <Animation
+                v-model:transition-enable="transitionEnable"
+                v-model:transition-loading="transitionLoading"
+                v-model:transition-name="transitionName"
+                v-model:transition-progress="transitionProgress"
+              />
+            </Block>
+          </template>
+          <template #appearance>
+            <Block :title="$t('preferences.theme.title')">
+              <Theme
+                v-model="themeMode"
+                v-model:theme-semi-dark-header="themeSemiDarkHeader"
+                v-model:theme-semi-dark-sidebar="themeSemiDarkSidebar"
+              />
+            </Block>
+            <Block :title="$t('preferences.theme.builtin.title')">
+              <BuiltinTheme
+                v-model="themeBuiltinType"
+                v-model:theme-color-primary="themeColorPrimary"
+                :is-dark="isDark"
+              />
+            </Block>
+            <Block :title="$t('preferences.theme.radius')">
+              <Radius v-model="themeRadius" />
+            </Block>
+            <Block :title="$t('preferences.other')">
+              <ColorMode
+                v-model:app-color-gray-mode="appColorGrayMode"
+                v-model:app-color-weak-mode="appColorWeakMode"
+              />
+            </Block>
+          </template>
+          <template #layout>
+            <Block :title="$t('preferences.layout')">
+              <Layout v-model="appLayout" />
+            </Block>
+            <Block :title="$t('preferences.content')">
+              <Content v-model="appContentCompact" />
+            </Block>
+
+            <Block :title="$t('preferences.sidebar.title')">
+              <Sidebar
+                v-model:sidebar-collapsed="sidebarCollapsed"
+                v-model:sidebar-collapsed-show-title="sidebarCollapsedShowTitle"
+                v-model:sidebar-enable="sidebarEnable"
+                v-model:sidebar-width="sidebarWidth"
+                :disabled="!isSideMode"
+              />
+            </Block>
+
+            <Block :title="$t('preferences.header.title')">
+              <Header
+                v-model:header-enable="headerEnable"
+                v-model:header-mode="headerMode"
+                :disabled="isFullContent"
+              />
+            </Block>
+
+            <Block :title="$t('preferences.navigationMenu.title')">
+              <Navigation
+                v-model:navigation-accordion="navigationAccordion"
+                v-model:navigation-split="navigationSplit"
+                v-model:navigation-style-type="navigationStyleType"
+                :disabled="isFullContent"
+                :disabled-navigation-split="!isMixedNav"
+              />
+            </Block>
+
+            <Block :title="$t('preferences.breadcrumb.title')">
+              <Breadcrumb
+                v-model:breadcrumb-enable="breadcrumbEnable"
+                v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
+                v-model:breadcrumb-show-home="breadcrumbShowHome"
+                v-model:breadcrumb-show-icon="breadcrumbShowIcon"
+                v-model:breadcrumb-style-type="breadcrumbStyleType"
+                :disabled="
+                  !showBreadcrumbConfig || !(isSideNav || isSideMixedNav)
+                "
+              />
+            </Block>
+            <Block :title="$t('preferences.tabbar.title')">
+              <Tabbar
+                v-model:tabbar-draggable="tabbarDraggable"
+                v-model:tabbar-enable="tabbarEnable"
+                v-model:tabbar-persist="tabbarPersist"
+                v-model:tabbar-show-icon="tabbarShowIcon"
+                v-model:tabbar-show-maximize="tabbarShowMaximize"
+                v-model:tabbar-show-more="tabbarShowMore"
+                v-model:tabbar-style-type="tabbarStyleType"
+              />
+            </Block>
+            <Block :title="$t('preferences.widget.title')">
+              <Widget
+                v-model:app-preferences-button-position="
+                  appPreferencesButtonPosition
+                "
+                v-model:widget-fullscreen="widgetFullscreen"
+                v-model:widget-global-search="widgetGlobalSearch"
+                v-model:widget-language-toggle="widgetLanguageToggle"
+                v-model:widget-lock-screen="widgetLockScreen"
+                v-model:widget-notification="widgetNotification"
+                v-model:widget-refresh="widgetRefresh"
+                v-model:widget-sidebar-toggle="widgetSidebarToggle"
+                v-model:widget-theme-toggle="widgetThemeToggle"
+              />
+            </Block>
+            <Block :title="$t('preferences.footer.title')">
+              <Footer
+                v-model:footer-enable="footerEnable"
+                v-model:footer-fixed="footerFixed"
+              />
+            </Block>
+            <Block
+              v-if="copyrightSettingShow"
+              :title="$t('preferences.copyright.title')"
+            >
+              <Copyright
+                v-model:copyright-company-name="copyrightCompanyName"
+                v-model:copyright-company-site-link="copyrightCompanySiteLink"
+                v-model:copyright-date="copyrightDate"
+                v-model:copyright-enable="copyrightEnable"
+                v-model:copyright-icp="copyrightIcp"
+                v-model:copyright-icp-link="copyrightIcpLink"
+                :disabled="!footerEnable"
+              />
+            </Block>
+          </template>
+
+          <template #shortcutKey>
+            <Block :title="$t('preferences.shortcutKeys.global')">
+              <GlobalShortcutKeys
+                v-model:shortcut-keys-enable="shortcutKeysEnable"
+                v-model:shortcut-keys-global-search="shortcutKeysGlobalSearch"
+                v-model:shortcut-keys-lock-screen="shortcutKeysGlobalLockScreen"
+                v-model:shortcut-keys-logout="shortcutKeysGlobalLogout"
+              />
+            </Block>
+          </template>
+        </VbenSegmented>
+      </div>
+
+      <template #footer>
+        <VbenButton
+          :disabled="!diffPreference"
+          class="mx-4 w-full"
+          size="sm"
+          variant="default"
+          @click="handleCopy"
+        >
+          <Copy class="mr-2 size-3" />
+          {{ $t('preferences.copyPreferences') }}
+        </VbenButton>
+        <VbenButton
+          :disabled="!diffPreference"
+          class="mr-4 w-full"
+          size="sm"
+          variant="ghost"
+          @click="handleClearCache"
+        >
+          {{ $t('preferences.clearAndLogout') }}
+        </VbenButton>
+      </template>
+    </Drawer>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences.vue b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences.vue
new file mode 100644
index 0000000..9479adb
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/preferences.vue
@@ -0,0 +1,71 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { Settings } from '@vben/icons';
+import { $t, loadLocaleMessages } from '@vben/locales';
+import { preferences, updatePreferences } from '@vben/preferences';
+import { capitalizeFirstLetter } from '@vben/utils';
+import { useVbenDrawer } from '@vben-core/popup-ui';
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+import PreferencesDrawer from './preferences-drawer.vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  connectedComponent: PreferencesDrawer,
+});
+
+/**
+ * preferences 杞垚 vue props
+ * preferences.widget.fullscreen=>widgetFullscreen
+ */
+const attrs = computed(() => {
+  const result: Record<string, any> = {};
+  for (const [key, value] of Object.entries(preferences)) {
+    for (const [subKey, subValue] of Object.entries(value)) {
+      result[`${key}${capitalizeFirstLetter(subKey)}`] = subValue;
+    }
+  }
+  return result;
+});
+
+/**
+ * preferences 杞垚 vue listener
+ * preferences.widget.fullscreen=>@update:widgetFullscreen
+ */
+const listen = computed(() => {
+  const result: Record<string, any> = {};
+  for (const [key, value] of Object.entries(preferences)) {
+    if (typeof value === 'object') {
+      for (const subKey of Object.keys(value)) {
+        result[`update:${key}${capitalizeFirstLetter(subKey)}`] = (
+          val: any,
+        ) => {
+          updatePreferences({ [key]: { [subKey]: val } });
+          if (key === 'app' && subKey === 'locale') {
+            loadLocaleMessages(val);
+          }
+        };
+      }
+    } else {
+      result[key] = value;
+    }
+  }
+  return result;
+});
+</script>
+<template>
+  <div>
+    <Drawer v-bind="{ ...$attrs, ...attrs }" v-on="listen" />
+
+    <div @click="() => drawerApi.open()">
+      <slot>
+        <VbenButton
+          :title="$t('preferences.title')"
+          class="bg-primary flex-col-center size-10 cursor-pointer rounded-l-lg rounded-r-none border-none"
+        >
+          <Settings class="size-5" />
+        </VbenButton>
+      </slot>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts b/eims-ui/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts
new file mode 100644
index 0000000..eb9d847
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts
@@ -0,0 +1,16 @@
+import { ref } from 'vue';
+
+const openPreferences = ref(false);
+
+function useOpenPreferences() {
+  function handleOpenPreference() {
+    openPreferences.value = true;
+  }
+
+  return {
+    handleOpenPreference,
+    openPreferences,
+  };
+}
+
+export { useOpenPreferences };
diff --git a/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/index.ts b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/index.ts
new file mode 100644
index 0000000..0673d21
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/index.ts
@@ -0,0 +1 @@
+export { default as ThemeToggle } from './theme-toggle.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue
new file mode 100644
index 0000000..77f330c
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue
@@ -0,0 +1,185 @@
+<script lang="ts" setup>
+import { computed, nextTick } from 'vue';
+
+import { VbenButton } from '@vben-core/shadcn-ui';
+
+interface Props {
+  /**
+   * 绫诲瀷
+   */
+  type?: 'icon' | 'normal';
+}
+
+defineOptions({
+  name: 'ThemeToggleButton',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  type: 'normal',
+});
+
+const isDark = defineModel<boolean>();
+
+const theme = computed(() => {
+  return isDark.value ? 'light' : 'dark';
+});
+
+const bindProps = computed(() => {
+  const type = props.type;
+
+  return type === 'normal'
+    ? {
+        variant: 'heavy' as const,
+      }
+    : {
+        class: 'rounded-full',
+        size: 'icon' as const,
+        style: { padding: '7px' },
+        variant: 'icon' as const,
+      };
+});
+
+function toggleTheme(event: MouseEvent) {
+  const isAppearanceTransition =
+    // @ts-expect-error
+    document.startViewTransition &&
+    !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
+  if (!isAppearanceTransition || !event) {
+    isDark.value = !isDark.value;
+    return;
+  }
+  const x = event.clientX;
+  const y = event.clientY;
+  const endRadius = Math.hypot(
+    Math.max(x, innerWidth - x),
+    Math.max(y, innerHeight - y),
+  );
+  // @ts-ignore startViewTransition
+  const transition = document.startViewTransition(async () => {
+    isDark.value = !isDark.value;
+    await nextTick();
+  });
+  transition.ready.then(() => {
+    const clipPath = [
+      `circle(0px at ${x}px ${y}px)`,
+      `circle(${endRadius}px at ${x}px ${y}px)`,
+    ];
+    document.documentElement.animate(
+      {
+        clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
+      },
+      {
+        duration: 450,
+        easing: 'ease-in',
+        pseudoElement: isDark.value
+          ? '::view-transition-old(root)'
+          : '::view-transition-new(root)',
+      },
+    );
+  });
+}
+</script>
+
+<template>
+  <VbenButton
+    :aria-label="theme"
+    :class="[`is-${theme}`]"
+    aria-live="polite"
+    class="theme-toggle cursor-pointer border-none bg-none"
+    v-bind="bindProps"
+    @click.stop="toggleTheme"
+  >
+    <svg aria-hidden="true" height="24" viewBox="0 0 24 24" width="24">
+      <mask
+        id="theme-toggle-moon"
+        class="theme-toggle__moon"
+        fill="hsl(var(--foreground)/80%)"
+        stroke="none"
+      >
+        <rect fill="white" height="100%" width="100%" x="0" y="0" />
+        <circle cx="40" cy="8" fill="black" r="11" />
+      </mask>
+      <circle
+        id="sun"
+        class="theme-toggle__sun"
+        cx="12"
+        cy="12"
+        mask="url(#theme-toggle-moon)"
+        r="11"
+      />
+      <g class="theme-toggle__sun-beams">
+        <line x1="12" x2="12" y1="1" y2="3" />
+        <line x1="12" x2="12" y1="21" y2="23" />
+        <line x1="4.22" x2="5.64" y1="4.22" y2="5.64" />
+        <line x1="18.36" x2="19.78" y1="18.36" y2="19.78" />
+        <line x1="1" x2="3" y1="12" y2="12" />
+        <line x1="21" x2="23" y1="12" y2="12" />
+        <line x1="4.22" x2="5.64" y1="19.78" y2="18.36" />
+        <line x1="18.36" x2="19.78" y1="5.64" y2="4.22" />
+      </g>
+    </svg>
+  </VbenButton>
+</template>
+
+<style scoped>
+.theme-toggle {
+  &__moon {
+    & > circle {
+      transition: transform 0.5s cubic-bezier(0, 0, 0.3, 1);
+    }
+  }
+
+  &__sun {
+    @apply fill-foreground/90 stroke-none;
+
+    transition: transform 1.6s cubic-bezier(0.25, 0, 0.2, 1);
+    transform-origin: center center;
+
+    &:hover > svg > & {
+      @apply fill-foreground/90;
+    }
+  }
+
+  &__sun-beams {
+    @apply stroke-foreground/90 stroke-[2px];
+
+    transition:
+      transform 1.6s cubic-bezier(0.5, 1.5, 0.75, 1.25),
+      opacity 0.6s cubic-bezier(0.25, 0, 0.3, 1);
+    transform-origin: center center;
+
+    &:hover > svg > & {
+      @apply stroke-foreground;
+    }
+  }
+
+  &.is-light {
+    .theme-toggle__sun {
+      @apply scale-50;
+    }
+
+    .theme-toggle__sun-beams {
+      transform: rotateZ(0.25turn);
+    }
+  }
+
+  &.is-dark {
+    .theme-toggle__moon {
+      & > circle {
+        transform: translateX(-20px);
+      }
+    }
+
+    .theme-toggle__sun-beams {
+      @apply opacity-0;
+    }
+  }
+
+  &:hover > svg {
+    .theme-toggle__sun,
+    .theme-toggle__moon {
+      @apply fill-foreground;
+    }
+  }
+}
+</style>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue
new file mode 100644
index 0000000..4ddc6b8
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue
@@ -0,0 +1,82 @@
+<script lang="ts" setup>
+import type { ThemeModeType } from '@vben/types';
+
+import { MoonStar, Sun, SunMoon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import {
+  preferences,
+  updatePreferences,
+  usePreferences,
+} from '@vben/preferences';
+import {
+  ToggleGroup,
+  ToggleGroupItem,
+  VbenTooltip,
+} from '@vben-core/shadcn-ui';
+
+import ThemeButton from './theme-button.vue';
+
+defineOptions({
+  name: 'ThemeToggle',
+});
+
+withDefaults(defineProps<{ shouldOnHover?: boolean }>(), {
+  shouldOnHover: false,
+});
+
+function handleChange(isDark: boolean) {
+  updatePreferences({
+    theme: { mode: isDark ? 'dark' : 'light' },
+  });
+}
+
+const { isDark } = usePreferences();
+
+const PRESETS = [
+  {
+    icon: Sun,
+    name: 'light',
+    title: $t('preferences.theme.light'),
+  },
+  {
+    icon: MoonStar,
+    name: 'dark',
+    title: $t('preferences.theme.dark'),
+  },
+  {
+    icon: SunMoon,
+    name: 'auto',
+    title: $t('preferences.followSystem'),
+  },
+];
+</script>
+<template>
+  <div>
+    <VbenTooltip :disabled="!shouldOnHover" side="bottom">
+      <template #trigger>
+        <ThemeButton
+          :model-value="isDark"
+          type="icon"
+          @update:model-value="handleChange"
+        />
+      </template>
+      <ToggleGroup
+        :model-value="preferences.theme.mode"
+        class="gap-2"
+        type="single"
+        variant="outline"
+        @update:model-value="
+          (val) => updatePreferences({ theme: { mode: val as ThemeModeType } })
+        "
+      >
+        <ToggleGroupItem
+          v-for="item in PRESETS"
+          :key="item.name"
+          :value="item.name"
+        >
+          <component :is="item.icon" class="size-5" />
+        </ToggleGroupItem>
+      </ToggleGroup>
+    </VbenTooltip>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/index.ts b/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/index.ts
new file mode 100644
index 0000000..86429e9
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/index.ts
@@ -0,0 +1 @@
+export { default as UserDropdown } from './user-dropdown.vue';
diff --git a/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue
new file mode 100644
index 0000000..475ba6f
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue
@@ -0,0 +1,227 @@
+<script setup lang="ts">
+import type { AnyFunction } from '@vben/types';
+
+import type { Component } from 'vue';
+import { computed, ref } from 'vue';
+
+import { LockKeyhole, LogOut } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { preferences, usePreferences } from '@vben/preferences';
+import { useLockStore } from '@vben/stores';
+import { isWindowsOs } from '@vben/utils';
+import { useVbenModal } from '@vben-core/popup-ui';
+import {
+  Badge,
+  DropdownMenu,
+  DropdownMenuContent,
+  DropdownMenuItem,
+  DropdownMenuLabel,
+  DropdownMenuSeparator,
+  DropdownMenuShortcut,
+  DropdownMenuTrigger,
+  VbenAvatar,
+  VbenIcon,
+} from '@vben-core/shadcn-ui';
+
+import { useMagicKeys, whenever } from '@vueuse/core';
+
+import { LockScreenModal } from '../lock-screen';
+
+interface Props {
+  /**
+   * 澶村儚
+   */
+  avatar?: string;
+  /**
+   * @zh_CN 鎻忚堪
+   */
+  description?: string;
+  /**
+   * 鏄惁鍚敤蹇嵎閿�
+   */
+  enableShortcutKey?: boolean;
+  /**
+   * 鑿滃崟鏁扮粍
+   */
+  menus?: Array<{ handler: AnyFunction; icon?: Component; text: string }>;
+
+  /**
+   * 鏍囩鏂囨湰
+   */
+  tagText?: string;
+  /**
+   * 鏂囨湰
+   */
+  text?: string;
+}
+
+defineOptions({
+  name: 'UserDropdown',
+});
+
+const props = withDefaults(defineProps<Props>(), {
+  avatar: '',
+  description: '',
+  enableShortcutKey: true,
+  menus: () => [],
+  showShortcutKey: true,
+  tagText: '',
+  text: '',
+});
+
+const emit = defineEmits<{ logout: [] }>();
+const openPopover = ref(false);
+
+const { globalLockScreenShortcutKey, globalLogoutShortcutKey } =
+  usePreferences();
+const lockStore = useLockStore();
+const [LockModal, lockModalApi] = useVbenModal({
+  connectedComponent: LockScreenModal,
+});
+const [LogoutModal, logoutModalApi] = useVbenModal({
+  onConfirm() {
+    handleSubmitLogout();
+  },
+});
+
+const altView = computed(() => (isWindowsOs() ? 'Alt' : '鈱�'));
+
+const enableLogoutShortcutKey = computed(() => {
+  return props.enableShortcutKey && globalLogoutShortcutKey.value;
+});
+
+const enableLockScreenShortcutKey = computed(() => {
+  return props.enableShortcutKey && globalLockScreenShortcutKey.value;
+});
+
+const enableShortcutKey = computed(() => {
+  return props.enableShortcutKey && preferences.shortcutKeys.enable;
+});
+
+function handleOpenLock() {
+  lockModalApi.open();
+}
+
+function handleSubmitLock(lockScreenPassword: string) {
+  lockModalApi.close();
+  lockStore.lockScreen(lockScreenPassword);
+}
+
+function handleLogout() {
+  // emit
+  logoutModalApi.open();
+  openPopover.value = false;
+}
+
+function handleSubmitLogout() {
+  emit('logout');
+  logoutModalApi.close();
+}
+
+if (enableShortcutKey.value) {
+  const keys = useMagicKeys();
+  whenever(keys['Alt+KeyQ']!, () => {
+    if (enableLogoutShortcutKey.value) {
+      handleLogout();
+    }
+  });
+
+  whenever(keys['Alt+KeyL']!, () => {
+    if (enableLockScreenShortcutKey.value) {
+      handleOpenLock();
+    }
+  });
+}
+</script>
+
+<template>
+  <LockModal
+    v-if="preferences.widget.lockScreen"
+    :avatar="avatar"
+    :text="text"
+    @submit="handleSubmitLock"
+  />
+
+  <LogoutModal
+    :cancel-text="$t('common.cancel')"
+    :confirm-text="$t('common.confirm')"
+    :fullscreen-button="false"
+    :title="$t('common.prompt')"
+    centered
+    content-class="px-8 min-h-10"
+    footer-class="border-none mb-3 mr-3"
+    header-class="border-none"
+  >
+    {{ $t('ui.widgets.logoutTip') }}
+  </LogoutModal>
+
+  <DropdownMenu>
+    <DropdownMenuTrigger>
+      <div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full p-1.5">
+        <div class="hover:text-accent-foreground flex-center">
+          <VbenAvatar :alt="text" :src="avatar" class="size-8" dot />
+        </div>
+      </div>
+    </DropdownMenuTrigger>
+    <DropdownMenuContent class="mr-2 min-w-[240px] p-0 pb-1">
+      <DropdownMenuLabel class="flex items-center p-3">
+        <VbenAvatar
+          :alt="text"
+          :src="avatar"
+          class="size-12"
+          dot
+          dot-class="bottom-0 right-1 border-2 size-4 bg-green-500"
+        />
+        <div class="ml-2 w-full">
+          <div
+            v-if="tagText || text || $slots.tagText"
+            class="text-foreground mb-1 flex items-center text-sm font-medium"
+          >
+            {{ text }}
+            <slot name="tagText">
+              <Badge v-if="tagText" class="ml-2 text-green-400">
+                {{ tagText }}
+              </Badge>
+            </slot>
+          </div>
+          <div class="text-muted-foreground text-xs font-normal">
+            {{ description }}
+          </div>
+        </div>
+      </DropdownMenuLabel>
+      <DropdownMenuSeparator v-if="menus?.length" />
+      <DropdownMenuItem
+        v-for="menu in menus"
+        :key="menu.text"
+        class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
+        @click="menu.handler"
+      >
+        <VbenIcon :icon="menu.icon" class="mr-2 size-4" />
+        {{ menu.text }}
+      </DropdownMenuItem>
+      <DropdownMenuSeparator />
+      <DropdownMenuItem
+        v-if="preferences.widget.lockScreen"
+        class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
+        @click="handleOpenLock"
+      >
+        <LockKeyhole class="mr-2 size-4" />
+        {{ $t('ui.widgets.lockScreen.title') }}
+        <DropdownMenuShortcut v-if="enableLockScreenShortcutKey">
+          {{ altView }} L
+        </DropdownMenuShortcut>
+      </DropdownMenuItem>
+      <DropdownMenuSeparator v-if="preferences.widget.lockScreen" />
+      <DropdownMenuItem
+        class="mx-1 flex cursor-pointer items-center rounded-sm py-1 leading-8"
+        @click="handleLogout"
+      >
+        <LogOut class="mr-2 size-4" />
+        {{ $t('common.logout') }}
+        <DropdownMenuShortcut v-if="enableLogoutShortcutKey">
+          {{ altView }} Q
+        </DropdownMenuShortcut>
+      </DropdownMenuItem>
+    </DropdownMenuContent>
+  </DropdownMenu>
+</template>
diff --git a/eims-ui/packages/effects/layouts/tsconfig.json b/eims-ui/packages/effects/layouts/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/effects/layouts/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/plugins/README.md b/eims-ui/packages/effects/plugins/README.md
new file mode 100644
index 0000000..c394c9c
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/README.md
@@ -0,0 +1,28 @@
+# @vben/plugins
+
+璇ョ洰褰曠敤浜庡瓨鏀鹃」鐩腑闆嗘垚鐨勭涓夋柟搴撳強鍏剁浉鍏虫彃浠躲�傛瘡涓彃浠堕兘鍖呭惈浜嗗彲閲嶇敤鐨勯�昏緫銆侀厤缃拰缁勪欢锛屾柟渚垮湪椤圭洰涓繘琛岀粺涓�绠$悊鍜岃皟鐢ㄣ��
+
+## 娉ㄦ剰
+
+鎵�鏈夌殑绗笁鏂规彃浠堕兘蹇呴』浠� `subpath` 褰㈠紡寮曞叆锛屼緥锛�
+
+浠� `echarts` 涓轰緥锛屽紩鍏ユ柟寮忓涓嬶細
+
+**packages.json**
+
+```json
+"exports": {
+    "./echarts": {
+      "types": "./src/echarts/index.ts",
+      "default": "./src/echarts/index.ts"
+    }
+  }
+```
+
+**浣跨敤鏂瑰紡**
+
+```ts
+import { useEcharts } from '@vben/plugins/echarts';
+```
+
+杩欐牱鍋氱殑濂藉鏄紝搴旂敤鍙互鑷閫夋嫨鏄惁浣跨敤鎻掍欢锛岃�屼笉浼氬洜涓烘彃浠剁殑寮曞叆鍙婂壇浣滅敤鑰屽鑷存墦鍖呬綋绉澶э紝鍙紩鍏ラ渶瑕佺殑鎻掍欢鍗冲彲銆�
diff --git a/eims-ui/packages/effects/plugins/package.json b/eims-ui/packages/effects/plugins/package.json
new file mode 100644
index 0000000..6226651
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/package.json
@@ -0,0 +1,42 @@
+{
+  "name": "@vben/plugins",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/plugins"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    "./echarts": {
+      "types": "./src/echarts/index.ts",
+      "default": "./src/echarts/index.ts"
+    },
+    "./vxe-table": {
+      "types": "./src/vxe-table/index.ts",
+      "default": "./src/vxe-table/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/form-ui": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:*",
+    "@vben-core/shared": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "echarts": "catalog:",
+    "vue": "catalog:",
+    "vxe-pc-ui": "catalog:",
+    "vxe-table": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/plugins/src/echarts/echarts-ui.vue b/eims-ui/packages/effects/plugins/src/echarts/echarts-ui.vue
new file mode 100644
index 0000000..70d1f20
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/echarts/echarts-ui.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+interface Props {
+  height?: string;
+  width?: string;
+}
+
+withDefaults(defineProps<Props>(), {
+  height: '300px',
+  width: '100%',
+});
+</script>
+
+<template>
+  <div v-bind="$attrs" :style="{ height, width }"></div>
+</template>
diff --git a/eims-ui/packages/effects/plugins/src/echarts/echarts.ts b/eims-ui/packages/effects/plugins/src/echarts/echarts.ts
new file mode 100644
index 0000000..a576b86
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/echarts/echarts.ts
@@ -0,0 +1,70 @@
+import type {
+  // 绯诲垪绫诲瀷鐨勫畾涔夊悗缂�閮戒负 SeriesOption
+  BarSeriesOption,
+  LineSeriesOption,
+} from 'echarts/charts';
+import type {
+  DatasetComponentOption,
+  GridComponentOption,
+  // 缁勪欢绫诲瀷鐨勫畾涔夊悗缂�閮戒负 ComponentOption
+  TitleComponentOption,
+  TooltipComponentOption,
+} from 'echarts/components';
+import type { ComposeOption } from 'echarts/core';
+
+import {
+  BarChart,
+  GaugeChart,
+  LineChart,
+  MapChart,
+  PieChart,
+  RadarChart,
+} from 'echarts/charts';
+import {
+  // 鏁版嵁闆嗙粍浠�
+  DatasetComponent,
+  GridComponent,
+  LegendComponent,
+  TitleComponent,
+  ToolboxComponent,
+  TooltipComponent,
+  // 鍐呯疆鏁版嵁杞崲鍣ㄧ粍浠� (filter, sort)
+  TransformComponent,
+  VisualMapComponent,
+} from 'echarts/components';
+import * as echarts from 'echarts/core';
+import { LabelLayout, UniversalTransition } from 'echarts/features';
+import { CanvasRenderer } from 'echarts/renderers';
+
+// 閫氳繃 ComposeOption 鏉ョ粍鍚堝嚭涓�涓彧鏈夊繀椤荤粍浠跺拰鍥捐〃鐨� Option 绫诲瀷
+export type ECOption = ComposeOption<
+  | BarSeriesOption
+  | DatasetComponentOption
+  | GridComponentOption
+  | LineSeriesOption
+  | TitleComponentOption
+  | TooltipComponentOption
+>;
+
+// 娉ㄥ唽蹇呴』鐨勭粍浠�
+echarts.use([
+  TitleComponent,
+  PieChart,
+  RadarChart,
+  TooltipComponent,
+  GridComponent,
+  DatasetComponent,
+  TransformComponent,
+  BarChart,
+  LineChart,
+  LabelLayout,
+  UniversalTransition,
+  CanvasRenderer,
+  LegendComponent,
+  ToolboxComponent,
+  GaugeChart,
+  VisualMapComponent,
+  MapChart,
+]);
+
+export default echarts;
diff --git a/eims-ui/packages/effects/plugins/src/echarts/index.ts b/eims-ui/packages/effects/plugins/src/echarts/index.ts
new file mode 100644
index 0000000..80f36a1
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/echarts/index.ts
@@ -0,0 +1,3 @@
+export * from './echarts';
+export { default as EchartsUI } from './echarts-ui.vue';
+export * from './use-echarts';
diff --git a/eims-ui/packages/effects/plugins/src/echarts/use-echarts.ts b/eims-ui/packages/effects/plugins/src/echarts/use-echarts.ts
new file mode 100644
index 0000000..5752f5e
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/echarts/use-echarts.ts
@@ -0,0 +1,118 @@
+import type { EChartsOption } from 'echarts';
+
+import type EchartsUI from './echarts-ui.vue';
+
+import type { Ref } from 'vue';
+import { computed, nextTick, watch } from 'vue';
+
+import { usePreferences } from '@vben/preferences';
+
+import {
+  tryOnUnmounted,
+  useDebounceFn,
+  useResizeObserver,
+  useTimeoutFn,
+  useWindowSize,
+} from '@vueuse/core';
+
+import echarts from './echarts';
+
+type EchartsUIType = typeof EchartsUI | undefined;
+
+type EchartsThemeType = 'dark' | 'light' | null;
+
+function useEcharts(chartRef: Ref<EchartsUIType>) {
+  let chartInstance: echarts.ECharts | null = null;
+  let cacheOptions: EChartsOption = {};
+
+  const { isDark } = usePreferences();
+  const { height, width } = useWindowSize();
+  const resizeHandler: () => void = useDebounceFn(resize, 200);
+
+  const getOptions = computed((): EChartsOption => {
+    if (!isDark.value) {
+      return {};
+    }
+
+    return {
+      backgroundColor: 'transparent',
+    };
+  });
+
+  const initCharts = (t?: EchartsThemeType) => {
+    const el = chartRef?.value?.$el;
+    if (!el) {
+      return;
+    }
+    chartInstance = echarts.init(el, t || isDark.value ? 'dark' : null);
+
+    return chartInstance;
+  };
+
+  const renderEcharts = (options: EChartsOption, clear = true) => {
+    cacheOptions = options;
+    const currentOptions = {
+      ...options,
+      ...getOptions.value,
+    };
+    return new Promise((resolve) => {
+      if (chartRef.value?.offsetHeight === 0) {
+        useTimeoutFn(() => {
+          renderEcharts(currentOptions);
+          resolve(null);
+        }, 30);
+        return;
+      }
+      nextTick(() => {
+        useTimeoutFn(() => {
+          if (!chartInstance) {
+            const instance = initCharts();
+            if (!instance) return;
+          }
+          clear && chartInstance?.clear();
+          chartInstance?.setOption(currentOptions);
+          resolve(null);
+        }, 30);
+      });
+    });
+  };
+
+  function resize(withAnimation = true) {
+    chartInstance?.resize({
+      animation: withAnimation
+        ? {
+            duration: 300,
+            easing: 'quadraticIn',
+          }
+        : undefined,
+    });
+  }
+
+  watch([width, height], () => {
+    resizeHandler?.();
+  });
+
+  useResizeObserver(chartRef as never, resizeHandler);
+
+  watch(isDark, () => {
+    if (chartInstance) {
+      chartInstance.dispose();
+      initCharts();
+      renderEcharts(cacheOptions);
+      resize();
+    }
+  });
+
+  tryOnUnmounted(() => {
+    // 閿�姣佸疄渚嬶紝閲婃斁璧勬簮
+    chartInstance?.dispose();
+  });
+  return {
+    renderEcharts,
+    resize,
+  };
+}
+
+export { useEcharts };
+
+export type { EchartsUIType };
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/api.ts b/eims-ui/packages/effects/plugins/src/vxe-table/api.ts
new file mode 100644
index 0000000..365c90b
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/api.ts
@@ -0,0 +1,115 @@
+import type { ExtendedFormApi } from '@vben-core/form-ui';
+import type { VxeGridInstance } from 'vxe-table';
+
+import type { VxeGridProps } from './types';
+
+import { toRaw } from 'vue';
+
+import { Store } from '@vben-core/shared/store';
+import {
+  bindMethods,
+  isFunction,
+  mergeWithArrayOverride,
+  StateHandler,
+} from '@vben-core/shared/utils';
+
+function getDefaultState(): VxeGridProps {
+  return {
+    class: '',
+    gridClass: '',
+    gridOptions: {},
+    gridEvents: {},
+    formOptions: undefined,
+  };
+}
+
+export class VxeGridApi {
+  private isMounted = false;
+
+  private stateHandler: StateHandler;
+  public formApi = {} as ExtendedFormApi;
+
+  // private prevState: null | VxeGridProps = null;
+  public grid = {} as VxeGridInstance;
+
+  public state: null | VxeGridProps = null;
+
+  public store: Store<VxeGridProps>;
+
+  constructor(options: VxeGridProps = {}) {
+    const storeState = { ...options };
+
+    const defaultState = getDefaultState();
+    this.store = new Store<VxeGridProps>(
+      mergeWithArrayOverride(storeState, defaultState),
+      {
+        onUpdate: () => {
+          // this.prevState = this.state;
+          this.state = this.store.state;
+        },
+      },
+    );
+
+    this.state = this.store.state;
+    this.stateHandler = new StateHandler();
+    bindMethods(this);
+  }
+
+  mount(instance: null | VxeGridInstance, formApi: ExtendedFormApi) {
+    if (!this.isMounted && instance) {
+      this.grid = instance;
+      this.formApi = formApi;
+      this.stateHandler.setConditionTrue();
+      this.isMounted = true;
+    }
+  }
+
+  async query(params: Record<string, any> = {}) {
+    try {
+      await this.grid.commitProxy('query', toRaw(params));
+    } catch (error) {
+      console.error('Error occurred while querying:', error);
+    }
+  }
+
+  async reload(params: Record<string, any> = {}) {
+    try {
+      await this.grid.commitProxy('reload', toRaw(params));
+    } catch (error) {
+      console.error('Error occurred while reloading:', error);
+    }
+  }
+
+  setGridOptions(options: Partial<VxeGridProps['gridOptions']>) {
+    this.setState({
+      gridOptions: options,
+    });
+  }
+
+  setLoading(isLoading: boolean) {
+    this.setState({
+      gridOptions: {
+        loading: isLoading,
+      },
+    });
+  }
+
+  setState(
+    stateOrFn:
+      | ((prev: VxeGridProps) => Partial<VxeGridProps>)
+      | Partial<VxeGridProps>,
+  ) {
+    if (isFunction(stateOrFn)) {
+      this.store.setState((prev) => {
+        return mergeWithArrayOverride(stateOrFn(prev), prev);
+      });
+    } else {
+      this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev));
+    }
+  }
+
+  unmount() {
+    this.isMounted = false;
+    this.stateHandler.reset();
+  }
+}
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/extends.ts b/eims-ui/packages/effects/plugins/src/vxe-table/extends.ts
new file mode 100644
index 0000000..d20ecfa
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/extends.ts
@@ -0,0 +1,80 @@
+import type { Recordable } from '@vben/types';
+import type { VxeGridProps, VxeUIExport } from 'vxe-table';
+
+import type { VxeGridApi } from './api';
+
+import { formatDate, formatDateTime, isFunction } from '@vben/utils';
+
+export function extendProxyOptions(
+  api: VxeGridApi,
+  options: VxeGridProps,
+  getFormValues: () => Recordable<any>,
+) {
+  [
+    'query',
+    'querySuccess',
+    'queryError',
+    'queryAll',
+    'queryAllSuccess',
+    'queryAllError',
+  ].forEach((key) => {
+    extendProxyOption(key, api, options, getFormValues);
+  });
+}
+
+function extendProxyOption(
+  key: string,
+  api: VxeGridApi,
+  options: VxeGridProps,
+  getFormValues: () => Recordable<any>,
+) {
+  const { proxyConfig } = options;
+  const configFn = (proxyConfig?.ajax as Recordable<any>)?.[key];
+  if (!isFunction(configFn)) {
+    return options;
+  }
+
+  const wrapperFn = async (
+    params: Recordable<any>,
+    customValues: Recordable<any>,
+    ...args: Recordable<any>[]
+  ) => {
+    const formValues = getFormValues();
+    const data = await configFn(
+      params,
+      {
+        /**
+         * 寮�鍚痶oolbarConfig.refresh鍔熻兘
+         * 鐐瑰嚮鍒锋柊鎸夐挳 杩欓噷鐨勫�间负PointerEvent 浼氭惡甯﹂敊璇弬鏁�
+         */
+        ...(customValues instanceof PointerEvent ? {} : customValues),
+        ...formValues,
+      },
+      ...args,
+    );
+    return data;
+  };
+  api.setState({
+    gridOptions: {
+      proxyConfig: {
+        ajax: {
+          [key]: wrapperFn,
+        },
+      },
+    },
+  });
+}
+
+export function extendsDefaultFormatter(vxeUI: VxeUIExport) {
+  vxeUI.formats.add('formatDate', {
+    tableCellFormatMethod({ cellValue }) {
+      return formatDate(cellValue);
+    },
+  });
+
+  vxeUI.formats.add('formatDateTime', {
+    tableCellFormatMethod({ cellValue }) {
+      return formatDateTime(cellValue);
+    },
+  });
+}
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/index.ts b/eims-ui/packages/effects/plugins/src/vxe-table/index.ts
new file mode 100644
index 0000000..190a00b
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/index.ts
@@ -0,0 +1,4 @@
+export { setupVbenVxeTable } from './init';
+export * from './use-vxe-grid';
+export { default as VbenVxeGrid } from './use-vxe-grid.vue';
+export type { VxeGridDefines, VxeGridListeners, VxeGridProps } from 'vxe-table';
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/init.ts b/eims-ui/packages/effects/plugins/src/vxe-table/init.ts
new file mode 100644
index 0000000..9051cd1
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/init.ts
@@ -0,0 +1,131 @@
+import type { SetupVxeTable } from './types';
+
+import { defineComponent, watch } from 'vue';
+
+import { usePreferences } from '@vben/preferences';
+import { useVbenForm } from '@vben-core/form-ui';
+
+import {
+  VxeButton,
+  VxeCheckbox,
+
+  // VxeFormGather,
+  // VxeForm,
+  // VxeFormItem,
+  VxeIcon,
+  VxeInput,
+  VxeLoading,
+  VxeModal,
+  VxeNumberInput,
+  VxePager,
+  // VxeList,
+  // VxeModal,
+  // VxeOptgroup,
+  // VxeOption,
+  // VxePulldown,
+  // VxeRadio,
+  // VxeRadioButton,
+  VxeRadioGroup,
+  VxeSelect,
+  VxeTooltip,
+  VxeUI,
+  VxeUpload,
+  // VxeSwitch,
+  // VxeTextarea,
+} from 'vxe-pc-ui';
+import enUS from 'vxe-pc-ui/lib/language/en-US';
+
+// 瀵煎叆榛樿鐨勮瑷�
+import zhCN from 'vxe-pc-ui/lib/language/zh-CN';
+import {
+  VxeColgroup,
+  VxeColumn,
+  VxeGrid,
+  VxeTable,
+  VxeToolbar,
+} from 'vxe-table';
+
+import { extendsDefaultFormatter } from './extends';
+
+// 鏄惁鍔犺浇杩�
+let isInit = false;
+
+// eslint-disable-next-line import/no-mutable-exports
+export let useTableForm: typeof useVbenForm;
+
+// 閮ㄥ垎缁勪欢锛屽鏋滄病娉ㄥ唽锛寁xe-table 浼氭姤閿欙紝杩欓噷瀹為檯娌$敤缁勪欢锛屽彧鏄负浜嗕笉鎶ラ敊锛屽悓鏃跺彲浠ュ噺灏戞墦鍖呬綋绉�
+const createVirtualComponent = (name = '') => {
+  return defineComponent({
+    name,
+  });
+};
+
+export function initVxeTable() {
+  if (isInit) {
+    return;
+  }
+
+  VxeUI.component(VxeTable);
+  VxeUI.component(VxeColumn);
+  VxeUI.component(VxeColgroup);
+  VxeUI.component(VxeGrid);
+  VxeUI.component(VxeToolbar);
+
+  VxeUI.component(VxeButton);
+  // VxeUI.component(VxeButtonGroup);
+  VxeUI.component(VxeCheckbox);
+  // VxeUI.component(VxeCheckboxGroup);
+  VxeUI.component(createVirtualComponent('VxeForm'));
+  // VxeUI.component(VxeFormGather);
+  // VxeUI.component(VxeFormItem);
+  VxeUI.component(VxeIcon);
+  VxeUI.component(VxeInput);
+  // VxeUI.component(VxeList);
+  VxeUI.component(VxeLoading);
+  VxeUI.component(VxeModal);
+  VxeUI.component(VxeNumberInput);
+  // VxeUI.component(VxeOptgroup);
+  // VxeUI.component(VxeOption);
+  VxeUI.component(VxePager);
+  // VxeUI.component(VxePulldown);
+  // VxeUI.component(VxeRadio);
+  // VxeUI.component(VxeRadioButton);
+  VxeUI.component(VxeRadioGroup);
+  VxeUI.component(VxeSelect);
+  // VxeUI.component(VxeSwitch);
+  // VxeUI.component(VxeTextarea);
+  VxeUI.component(VxeTooltip);
+  VxeUI.component(VxeUpload);
+
+  isInit = true;
+}
+
+export function setupVbenVxeTable(setupOptions: SetupVxeTable) {
+  const { configVxeTable, useVbenForm } = setupOptions;
+
+  initVxeTable();
+  useTableForm = useVbenForm;
+
+  const preference = usePreferences();
+
+  const localMap = {
+    'zh-CN': zhCN,
+    'en-US': enUS,
+  };
+
+  watch(
+    [() => preference.theme.value, () => preference.locale.value],
+    ([theme, locale]) => {
+      VxeUI.setTheme(theme === 'dark' ? 'dark' : 'light');
+      VxeUI.setI18n(locale, localMap[locale]);
+      VxeUI.setLanguage(locale);
+    },
+    {
+      immediate: true,
+    },
+  );
+
+  extendsDefaultFormatter(VxeUI);
+
+  configVxeTable(VxeUI);
+}
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/style.css b/eims-ui/packages/effects/plugins/src/vxe-table/style.css
new file mode 100644
index 0000000..31e5766
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/style.css
@@ -0,0 +1,112 @@
+:root .vxe-grid {
+  --vxe-ui-font-color: hsl(var(--foreground));
+  --vxe-ui-font-primary-color: hsl(var(--primary));
+
+  /* --vxe-ui-font-lighten-color: #babdc0;
+  --vxe-ui-font-darken-color: #86898e; */
+  --vxe-ui-font-disabled-color: hsl(var(--foreground) / 50%);
+
+  /* base */
+  --vxe-ui-base-popup-border-color: hsl(var(--border));
+  --vxe-ui-input-disabled-color: hsl(var(--border) / 60%);
+
+  /* --vxe-ui-base-popup-box-shadow: 0px 12px 30px 8px rgb(0 0 0 / 50%); */
+
+  /* layout */
+  --vxe-ui-layout-background-color: hsl(var(--background));
+  --vxe-ui-table-resizable-line-color: hsl(var(--heavy));
+
+  /* --vxe-ui-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px hsl(var(--accent));
+  --vxe-ui-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px hsl(var(--accent)); */
+
+  /* input */
+  --vxe-ui-input-border-color: hsl(var(--border));
+
+  /* --vxe-ui-input-placeholder-color: #8d9095; */
+
+  /* --vxe-ui-input-disabled-background-color: #262727; */
+
+  /* loading */
+  --vxe-ui-loading-background-color: hsl(var(--overlay-content));
+
+  /* table */
+  --vxe-ui-table-header-background-color: hsl(0deg 0% 98%);
+  --vxe-ui-table-border-color: hsl(var(--border));
+  --vxe-ui-table-row-hover-background-color: hsl(var(--accent-hover));
+  --vxe-ui-table-row-striped-background-color: hsl(var(--accent) / 60%);
+  --vxe-ui-table-row-hover-striped-background-color: hsl(var(--accent));
+  --vxe-ui-table-row-radio-checked-background-color: hsl(var(--accent));
+  --vxe-ui-table-row-hover-radio-checked-background-color: hsl(
+    var(--accent-hover)
+  );
+  --vxe-ui-table-row-checkbox-checked-background-color: hsl(var(--accent));
+  --vxe-ui-table-row-hover-checkbox-checked-background-color: hsl(
+    var(--accent-hover)
+  );
+  --vxe-ui-table-row-current-background-color: hsl(var(--accent));
+  --vxe-ui-table-row-hover-current-background-color: hsl(var(--accent-hover));
+
+  /* --vxe-ui-table-fixed-scrolling-box-shadow-color: rgb(0 0 0 / 80%); */
+}
+
+html[data-vxe-ui-theme='dark'] .vxe-grid {
+  --vxe-ui-table-header-background-color: hsl(var(--accent) / 50%);
+}
+
+.vxe-pager {
+  .vxe-pager--prev-btn:not(.is--disabled):active,
+  .vxe-pager--next-btn:not(.is--disabled):active,
+  .vxe-pager--num-btn:not(.is--disabled):active,
+  .vxe-pager--jump-prev:not(.is--disabled):active,
+  .vxe-pager--jump-next:not(.is--disabled):active,
+  .vxe-pager--prev-btn:not(.is--disabled):focus,
+  .vxe-pager--next-btn:not(.is--disabled):focus,
+  .vxe-pager--num-btn:not(.is--disabled):focus,
+  .vxe-pager--jump-prev:not(.is--disabled):focus,
+  .vxe-pager--jump-next:not(.is--disabled):focus {
+    color: hsl(var(--accent-foreground));
+    background-color: hsl(var(--accent));
+    border: 1px solid hsl(var(--border));
+    box-shadow: 0 0 0 1px hsl(var(--border));
+  }
+
+  .vxe-pager--wrapper {
+    display: flex;
+    align-items: center;
+  }
+
+  .vxe-pager--sizes {
+    margin-right: auto;
+  }
+}
+
+.vxe-pager--wrapper {
+  @apply justify-center md:justify-end;
+}
+
+.vxe-tools--operate {
+  margin-right: 0.25rem;
+  margin-left: 0.75rem;
+}
+
+.vxe-table-custom--checkbox-option:hover {
+  background: none !important;
+}
+
+.vxe-toolbar {
+  padding: 0;
+}
+
+/** 鍏抽棴鎼滅储琛ㄥ崟 */
+.vxe-grid:not(.vxe-grid--form-wrapper form) .vxe-toolbar {
+  padding: 0.6em 0 !important;
+}
+
+/** 寮�鍚悳绱㈣〃鍗� */
+.vxe-grid:has(.vxe-grid--form-wrapper form) .vxe-toolbar {
+  padding: 0 0 0.6em !important;
+}
+
+.vxe-tools--operate:not(:has(button)) {
+  margin-left: 0;
+}
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/types.ts b/eims-ui/packages/effects/plugins/src/vxe-table/types.ts
new file mode 100644
index 0000000..f56575b
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/types.ts
@@ -0,0 +1,61 @@
+import type { ClassType, DeepPartial } from '@vben/types';
+import type { VbenFormProps } from '@vben-core/form-ui';
+import type {
+  VxeGridListeners,
+  VxeGridProps as VxeTableGridProps,
+  VxeUIExport,
+} from 'vxe-table';
+
+import type { VxeGridApi } from './api';
+
+import type { Ref } from 'vue';
+
+import { useVbenForm } from '@vben-core/form-ui';
+
+export interface VxePaginationInfo {
+  currentPage: number;
+  pageSize: number;
+  total: number;
+}
+
+export interface VxeGridProps {
+  /**
+   * 鏍囬
+   */
+  tableTitle?: string;
+  /**
+   * 鏍囬甯姪
+   */
+  tableTitleHelp?: string;
+  /**
+   * 缁勪欢class
+   */
+  class?: ClassType;
+  /**
+   * vxe-grid class
+   */
+  gridClass?: ClassType;
+  /**
+   * vxe-grid 閰嶇疆
+   */
+  gridOptions?: DeepPartial<VxeTableGridProps>;
+  /**
+   * vxe-grid 浜嬩欢
+   */
+  gridEvents?: Partial<VxeGridListeners>;
+  /**
+   * 琛ㄥ崟閰嶇疆
+   */
+  formOptions?: VbenFormProps;
+}
+
+export type ExtendedVxeGridApi = {
+  useStore: <T = NoInfer<VxeGridProps>>(
+    selector?: (state: NoInfer<VxeGridProps>) => T,
+  ) => Readonly<Ref<T>>;
+} & VxeGridApi;
+
+export interface SetupVxeTable {
+  configVxeTable: (ui: VxeUIExport) => void;
+  useVbenForm: typeof useVbenForm;
+}
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts b/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts
new file mode 100644
index 0000000..a309f5a
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts
@@ -0,0 +1,45 @@
+import type { ExtendedVxeGridApi, VxeGridProps } from './types';
+
+import { defineComponent, h, onBeforeUnmount } from 'vue';
+
+import { useStore } from '@vben-core/shared/store';
+
+import { VxeGridApi } from './api';
+import VxeGrid from './use-vxe-grid.vue';
+
+export function useVbenVxeGrid(options: VxeGridProps) {
+  // const IS_REACTIVE = isReactive(options);
+  const api = new VxeGridApi(options);
+  const extendedApi: ExtendedVxeGridApi = api as ExtendedVxeGridApi;
+  extendedApi.useStore = (selector) => {
+    return useStore(api.store, selector);
+  };
+
+  const Grid = defineComponent(
+    (props: VxeGridProps, { attrs, slots }) => {
+      onBeforeUnmount(() => {
+        api.unmount();
+      });
+      api.setState({ ...props, ...attrs });
+      return () => h(VxeGrid, { ...props, ...attrs, api: extendedApi }, slots);
+    },
+    {
+      inheritAttrs: false,
+      name: 'VbenVxeGrid',
+    },
+  );
+  // Add reactivity support
+  // if (IS_REACTIVE) {
+  //   watch(
+  //     () => options,
+  //     () => {
+  //       api.setState(options);
+  //     },
+  //     { immediate: true },
+  //   );
+  // }
+
+  return [Grid, extendedApi] as const;
+}
+
+export type UseVbenVxeGrid = typeof useVbenVxeGrid;
diff --git a/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue
new file mode 100644
index 0000000..642ef11
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue
@@ -0,0 +1,356 @@
+<script lang="ts" setup>
+import type { VbenFormProps } from '@vben-core/form-ui';
+import type {
+  VxeGridInstance,
+  VxeGridProps as VxeTableGridProps,
+} from 'vxe-table';
+
+import type { ExtendedVxeGridApi, VxeGridProps } from './types';
+
+import {
+  computed,
+  nextTick,
+  onMounted,
+  onUnmounted,
+  toRaw,
+  useSlots,
+  useTemplateRef,
+  watch,
+} from 'vue';
+
+import { usePriorityValues } from '@vben/hooks';
+import { EmptyIcon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { usePreferences } from '@vben/preferences';
+import { cloneDeep, cn, mergeWithArrayOverride } from '@vben/utils';
+import { VbenHelpTooltip, VbenLoading } from '@vben-core/shadcn-ui';
+
+import { VxeGrid, VxeUI } from 'vxe-table';
+
+import { extendProxyOptions } from './extends';
+import { useTableForm } from './init';
+
+import 'vxe-table/styles/cssvar.scss';
+import 'vxe-pc-ui/styles/cssvar.scss';
+import './style.css';
+
+interface Props extends VxeGridProps {
+  api: ExtendedVxeGridApi;
+}
+
+const props = withDefaults(defineProps<Props>(), {});
+
+const FORM_SLOT_PREFIX = 'form-';
+
+const TOOLBAR_ACTIONS = 'toolbar-actions';
+const TOOLBAR_TOOLS = 'toolbar-tools';
+
+const gridRef = useTemplateRef<VxeGridInstance>('gridRef');
+
+const state = props.api?.useStore?.();
+
+const {
+  gridOptions,
+  class: className,
+  gridClass,
+  gridEvents,
+  formOptions,
+  tableTitle,
+  tableTitleHelp,
+} = usePriorityValues(props, state);
+
+const { isMobile } = usePreferences();
+
+const slots = useSlots();
+
+const [Form, formApi] = useTableForm({
+  handleSubmit: async () => {
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(toRaw(formValues));
+    props.api.reload(formValues);
+  },
+  handleReset: async () => {
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    props.api.reload(formValues);
+  },
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  showCollapseButton: true,
+  submitButtonOptions: {
+    content: $t('common.query'),
+  },
+  // enter鎻愪氦
+  submitOnEnter: true,
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+const showTableTitle = computed(() => {
+  return !!slots.tableTitle?.() || tableTitle.value;
+});
+
+const showToolbar = computed(() => {
+  return (
+    !!slots[TOOLBAR_ACTIONS]?.() ||
+    !!slots[TOOLBAR_TOOLS]?.() ||
+    showTableTitle.value
+  );
+});
+
+const toolbarOptions = computed(() => {
+  const slotActions = slots[TOOLBAR_ACTIONS]?.();
+  const slotTools = slots[TOOLBAR_TOOLS]?.();
+
+  if (!showToolbar.value) {
+    return {};
+  }
+  // 寮哄埗浣跨敤鍥哄畾鐨則oolbar閰嶇疆锛屼笉鍏佽鐢ㄦ埛鑷畾涔�
+  // 鍑忓皯閰嶇疆鐨勫鏉傚害锛屼互鍙婂悗缁淮鎶ょ殑鎴愭湰
+  return {
+    toolbarConfig: {
+      slots: {
+        ...(slotActions || showTableTitle.value
+          ? { buttons: TOOLBAR_ACTIONS }
+          : {}),
+        ...(slotTools ? { tools: TOOLBAR_TOOLS } : {}),
+      },
+    },
+  };
+});
+
+const options = computed(() => {
+  const globalGridConfig = VxeUI?.getConfig()?.grid ?? {};
+
+  const mergedOptions: VxeTableGridProps = cloneDeep(
+    mergeWithArrayOverride(
+      {},
+      toolbarOptions.value,
+      toRaw(gridOptions.value),
+      globalGridConfig,
+    ),
+  );
+
+  if (mergedOptions.proxyConfig) {
+    const { ajax } = mergedOptions.proxyConfig;
+    mergedOptions.proxyConfig.enabled = !!ajax;
+    // 涓嶈嚜鍔ㄥ姞杞芥暟鎹�, 鐢辩粍浠舵帶鍒�
+    mergedOptions.proxyConfig.autoLoad = false;
+  }
+
+  if (mergedOptions.pagerConfig) {
+    const mobileLayouts = [
+      'PrevJump',
+      'PrevPage',
+      'Number',
+      'NextPage',
+      'NextJump',
+    ] as any;
+    const layouts = [
+      'Total',
+      'Sizes',
+      'Home',
+      ...mobileLayouts,
+      'End',
+    ] as readonly string[];
+    mergedOptions.pagerConfig = mergeWithArrayOverride(
+      {},
+      mergedOptions.pagerConfig,
+      {
+        pageSize: 20,
+        background: true,
+        pageSizes: [10, 20, 30, 50, 100, 200],
+        className: 'mt-2 w-full',
+        layouts: isMobile.value ? mobileLayouts : layouts,
+        size: 'mini' as const,
+      },
+    );
+  }
+  if (mergedOptions.formConfig) {
+    mergedOptions.formConfig.enabled = false;
+  }
+  return mergedOptions;
+});
+
+const events = computed(() => {
+  return {
+    ...gridEvents.value,
+  };
+});
+
+const delegatedSlots = computed(() => {
+  const resultSlots: string[] = [];
+
+  for (const key of Object.keys(slots)) {
+    if (!['empty', 'form', 'loading', TOOLBAR_ACTIONS].includes(key)) {
+      resultSlots.push(key);
+    }
+  }
+  return resultSlots;
+});
+
+const delegatedFormSlots = computed(() => {
+  const resultSlots: string[] = [];
+
+  for (const key of Object.keys(slots)) {
+    if (key.startsWith(FORM_SLOT_PREFIX)) {
+      resultSlots.push(key);
+    }
+  }
+  return resultSlots.map((key) => key.replace(FORM_SLOT_PREFIX, ''));
+});
+
+async function init() {
+  await nextTick();
+  const globalGridConfig = VxeUI?.getConfig()?.grid ?? {};
+  const defaultGridOptions: VxeTableGridProps = mergeWithArrayOverride(
+    {},
+    toRaw(gridOptions.value),
+    toRaw(globalGridConfig),
+  );
+  // 鍐呴儴涓诲姩鍔犺浇鏁版嵁锛岄槻姝orm鐨勯粯璁ゅ�煎奖鍝�
+  const autoLoad = defaultGridOptions.proxyConfig?.autoLoad;
+  const enableProxyConfig = options.value.proxyConfig?.enabled;
+  if (enableProxyConfig && autoLoad) {
+    props.api.reload(formApi.form?.values ?? {});
+  }
+
+  // form 鐢� vben-form浠f浛锛屾墍浠ヤ笉閫傞厤formConfig锛岃繖閲岀粰鍑鸿鍛�
+  const formConfig = gridOptions.value?.formConfig;
+  // 澶勭悊鏌愪釜椤甸潰鍔犺浇澶氫釜Table鏃讹紝绗�2涓箣鍚庣殑Table鍒濆鍖栨姤鍑鸿鍛�
+  // 鍥犱负绗竴娆″垵濮嬪寲涔嬪悗浼氭妸defaultGridOptions鍜実ridOptions鍚堝苟鍚庣紦瀛樿繘State
+  if (formConfig && formConfig.enabled) {
+    console.warn(
+      '[Vben Vxe Table]: The formConfig in the grid is not supported, please use the `formOptions` props',
+    );
+  }
+  props.api?.setState?.({ gridOptions: defaultGridOptions });
+  // form 鐢� vben-form 浠f浛锛屾墍浠ラ渶瑕佷繚璇乹uery鐩稿叧浜嬩欢鍙互鎷垮埌鍙傛暟
+  extendProxyOptions(props.api, defaultGridOptions, () =>
+    formApi.getLatestSubmissionValues(),
+  );
+}
+
+// formOptions鏀寔鍝嶅簲寮�
+watch(
+  formOptions,
+  () => {
+    formApi.setState((prev) => {
+      const finalFormOptions: VbenFormProps = mergeWithArrayOverride(
+        {},
+        formOptions.value,
+        prev,
+      );
+      return {
+        ...finalFormOptions,
+        collapseTriggerResize: !!finalFormOptions.showCollapseButton,
+      };
+    });
+  },
+  {
+    immediate: true,
+  },
+);
+
+onMounted(() => {
+  props.api?.mount?.(gridRef.value, formApi);
+  init();
+});
+
+onUnmounted(() => {
+  formApi?.unmount?.();
+  props.api?.unmount?.();
+});
+</script>
+
+<template>
+  <div :class="cn('bg-card h-full rounded-md', className)">
+    <VxeGrid
+      ref="gridRef"
+      :class="
+        cn(
+          'p-2 pt-0',
+          {
+            'pt-0': showToolbar && !formOptions,
+          },
+          gridClass,
+        )
+      "
+      v-bind="options"
+      v-on="events"
+    >
+      <!-- 宸︿晶鎿嶄綔鍖哄煙鎴栬�卼itle -->
+      <template v-if="showToolbar" #toolbar-actions="slotProps">
+        <slot v-if="showTableTitle" name="table-title">
+          <div class="mr-1 pl-1 text-[1rem]">
+            {{ tableTitle }}
+            <VbenHelpTooltip v-if="tableTitleHelp" trigger-class="pb-1">
+              {{ tableTitleHelp }}
+            </VbenHelpTooltip>
+          </div>
+        </slot>
+        <slot name="toolbar-actions" v-bind="slotProps"> </slot>
+      </template>
+
+      <!-- 缁ф壙榛樿鐨剆lot -->
+      <template
+        v-for="slotName in delegatedSlots"
+        :key="slotName"
+        #[slotName]="slotProps"
+      >
+        <slot :name="slotName" v-bind="slotProps"></slot>
+      </template>
+
+      <!-- form琛ㄥ崟 -->
+      <template #form>
+        <div v-if="formOptions" class="relative rounded py-3 pb-4">
+          <slot name="form">
+            <Form>
+              <template
+                v-for="slotName in delegatedFormSlots"
+                :key="slotName"
+                #[slotName]="slotProps"
+              >
+                <slot
+                  :name="`${FORM_SLOT_PREFIX}${slotName}`"
+                  v-bind="slotProps"
+                ></slot>
+              </template>
+              <template #reset-before="slotProps">
+                <slot name="reset-before" v-bind="slotProps"></slot>
+              </template>
+              <template #submit-before="slotProps">
+                <slot name="submit-before" v-bind="slotProps"></slot>
+              </template>
+              <template #expand-before="slotProps">
+                <slot name="expand-before" v-bind="slotProps"></slot>
+              </template>
+              <template #expand-after="slotProps">
+                <slot name="expand-after" v-bind="slotProps"></slot>
+              </template>
+            </Form>
+          </slot>
+          <div
+            class="bg-background-deep z-100 absolute -left-2 bottom-1 h-2 w-[calc(100%+1rem)] overflow-hidden md:bottom-2 md:h-3"
+          ></div>
+        </div>
+      </template>
+      <!-- loading -->
+      <template #loading>
+        <slot name="loading">
+          <VbenLoading :spinning="true" />
+        </slot>
+      </template>
+      <!-- 缁熶竴鎺х姸鎬� -->
+      <template #empty>
+        <slot name="empty">
+          <EmptyIcon class="mx-auto" />
+          <div class="mt-2">{{ $t('common.noData') }}</div>
+        </slot>
+      </template>
+    </VxeGrid>
+  </div>
+</template>
diff --git a/eims-ui/packages/effects/plugins/tsconfig.json b/eims-ui/packages/effects/plugins/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/effects/plugins/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/effects/request/package.json b/eims-ui/packages/effects/request/package.json
new file mode 100644
index 0000000..3cff702
--- /dev/null
+++ b/eims-ui/packages/effects/request/package.json
@@ -0,0 +1,32 @@
+{
+  "name": "@vben/request",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/effects/request"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben/locales": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "axios": "catalog:",
+    "qs": "^6.13.1"
+  },
+  "devDependencies": {
+    "@types/qs": "^6.9.17",
+    "axios-mock-adapter": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/effects/request/src/index.ts b/eims-ui/packages/effects/request/src/index.ts
new file mode 100644
index 0000000..e1805bf
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/index.ts
@@ -0,0 +1,3 @@
+export * from './request-client';
+export * from 'axios';
+export { stringify } from 'qs';
diff --git a/eims-ui/packages/effects/request/src/request-client/index.ts b/eims-ui/packages/effects/request/src/request-client/index.ts
new file mode 100644
index 0000000..a44cd15
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/index.ts
@@ -0,0 +1,3 @@
+export * from './preset-interceptors';
+export * from './request-client';
+export type * from './types';
diff --git a/eims-ui/packages/effects/request/src/request-client/modules/downloader.test.ts b/eims-ui/packages/effects/request/src/request-client/modules/downloader.test.ts
new file mode 100644
index 0000000..0e78b54
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/modules/downloader.test.ts
@@ -0,0 +1,84 @@
+import type { AxiosRequestConfig } from 'axios';
+
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { FileDownloader } from './downloader';
+
+describe('fileDownloader', () => {
+  let fileDownloader: FileDownloader;
+  const mockAxiosInstance = {
+    get: vi.fn(),
+  } as any;
+
+  beforeEach(() => {
+    fileDownloader = new FileDownloader(mockAxiosInstance);
+  });
+
+  it('should create an instance of FileDownloader', () => {
+    expect(fileDownloader).toBeInstanceOf(FileDownloader);
+  });
+
+  it('should download a file and return a Blob', async () => {
+    const url = 'https://example.com/file';
+    const mockBlob = new Blob(['file content'], { type: 'text/plain' });
+    const mockResponse: Blob = mockBlob;
+
+    mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);
+
+    const result = await fileDownloader.download(url);
+
+    expect(result).toBeInstanceOf(Blob);
+    expect(result).toEqual(mockBlob);
+    expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
+      responseType: 'blob',
+    });
+  });
+
+  it('should merge provided config with default config', async () => {
+    const url = 'https://example.com/file';
+    const mockBlob = new Blob(['file content'], { type: 'text/plain' });
+    const mockResponse: Blob = mockBlob;
+
+    mockAxiosInstance.get.mockResolvedValueOnce(mockResponse);
+
+    const customConfig: AxiosRequestConfig = {
+      headers: { 'Custom-Header': 'value' },
+    };
+
+    const result = await fileDownloader.download(url, customConfig);
+    expect(result).toBeInstanceOf(Blob);
+    expect(result).toEqual(mockBlob);
+    expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, {
+      ...customConfig,
+      responseType: 'blob',
+    });
+  });
+
+  it('should handle errors gracefully', async () => {
+    const url = 'https://example.com/file';
+    mockAxiosInstance.get.mockRejectedValueOnce(new Error('Network Error'));
+    await expect(fileDownloader.download(url)).rejects.toThrow('Network Error');
+  });
+
+  it('should handle empty URL gracefully', async () => {
+    const url = '';
+    mockAxiosInstance.get.mockRejectedValueOnce(
+      new Error('Request failed with status code 404'),
+    );
+
+    await expect(fileDownloader.download(url)).rejects.toThrow(
+      'Request failed with status code 404',
+    );
+  });
+
+  it('should handle null URL gracefully', async () => {
+    const url = null as unknown as string;
+    mockAxiosInstance.get.mockRejectedValueOnce(
+      new Error('Request failed with status code 404'),
+    );
+
+    await expect(fileDownloader.download(url)).rejects.toThrow(
+      'Request failed with status code 404',
+    );
+  });
+});
diff --git a/eims-ui/packages/effects/request/src/request-client/modules/downloader.ts b/eims-ui/packages/effects/request/src/request-client/modules/downloader.ts
new file mode 100644
index 0000000..bf065d3
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/modules/downloader.ts
@@ -0,0 +1,31 @@
+import type { AxiosRequestConfig } from 'axios';
+
+import type { RequestClient } from '../request-client';
+import type { RequestResponse } from '../types';
+
+class FileDownloader {
+  private client: RequestClient;
+
+  constructor(client: RequestClient) {
+    this.client = client;
+  }
+
+  public async download(
+    url: string,
+    config?: AxiosRequestConfig,
+  ): Promise<RequestResponse<Blob>> {
+    const finalConfig: AxiosRequestConfig = {
+      ...config,
+      responseType: 'blob',
+    };
+
+    const response = await this.client.get<RequestResponse<Blob>>(
+      url,
+      finalConfig,
+    );
+
+    return response;
+  }
+}
+
+export { FileDownloader };
diff --git a/eims-ui/packages/effects/request/src/request-client/modules/interceptor.ts b/eims-ui/packages/effects/request/src/request-client/modules/interceptor.ts
new file mode 100644
index 0000000..f6d2ad8
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/modules/interceptor.ts
@@ -0,0 +1,40 @@
+import type { AxiosInstance, AxiosResponse } from 'axios';
+
+import type {
+  RequestInterceptorConfig,
+  ResponseInterceptorConfig,
+} from '../types';
+
+const defaultRequestInterceptorConfig: RequestInterceptorConfig = {
+  fulfilled: (response) => response,
+  rejected: (error) => Promise.reject(error),
+};
+
+const defaultResponseInterceptorConfig: ResponseInterceptorConfig = {
+  fulfilled: (response: AxiosResponse) => response,
+  rejected: (error) => Promise.reject(error),
+};
+
+class InterceptorManager {
+  private axiosInstance: AxiosInstance;
+
+  constructor(instance: AxiosInstance) {
+    this.axiosInstance = instance;
+  }
+
+  addRequestInterceptor({
+    fulfilled,
+    rejected,
+  }: RequestInterceptorConfig = defaultRequestInterceptorConfig) {
+    this.axiosInstance.interceptors.request.use(fulfilled, rejected);
+  }
+
+  addResponseInterceptor<T = any>({
+    fulfilled,
+    rejected,
+  }: ResponseInterceptorConfig<T> = defaultResponseInterceptorConfig) {
+    this.axiosInstance.interceptors.response.use(fulfilled, rejected);
+  }
+}
+
+export { InterceptorManager };
diff --git a/eims-ui/packages/effects/request/src/request-client/modules/uploader.test.ts b/eims-ui/packages/effects/request/src/request-client/modules/uploader.test.ts
new file mode 100644
index 0000000..8306656
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/modules/uploader.test.ts
@@ -0,0 +1,118 @@
+import type { AxiosRequestConfig, AxiosResponse } from 'axios';
+
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { FileUploader } from './uploader';
+
+describe('fileUploader', () => {
+  let fileUploader: FileUploader;
+  // Mock the AxiosInstance
+  const mockAxiosInstance = {
+    post: vi.fn(),
+  } as any;
+
+  beforeEach(() => {
+    fileUploader = new FileUploader(mockAxiosInstance);
+  });
+
+  it('should create an instance of FileUploader', () => {
+    expect(fileUploader).toBeInstanceOf(FileUploader);
+  });
+
+  it('should upload a file and return the response', async () => {
+    const url = 'https://example.com/upload';
+    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
+    const mockResponse: AxiosResponse = {
+      config: {} as any,
+      data: { success: true },
+      headers: {},
+      status: 200,
+      statusText: 'OK',
+    };
+
+    (
+      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
+    ).mockResolvedValueOnce(mockResponse);
+
+    const result = await fileUploader.upload(url, { file });
+    expect(result).toEqual(mockResponse);
+    expect(mockAxiosInstance.post).toHaveBeenCalledWith(
+      url,
+      expect.any(FormData),
+      {
+        headers: {
+          'Content-Type': 'multipart/form-data',
+        },
+      },
+    );
+  });
+
+  it('should merge provided config with default config', async () => {
+    const url = 'https://example.com/upload';
+    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
+    const mockResponse: AxiosResponse = {
+      config: {} as any,
+      data: { success: true },
+      headers: {},
+      status: 200,
+      statusText: 'OK',
+    };
+
+    (
+      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
+    ).mockResolvedValueOnce(mockResponse);
+
+    const customConfig: AxiosRequestConfig = {
+      headers: { 'Custom-Header': 'value' },
+    };
+
+    const result = await fileUploader.upload(url, { file }, customConfig);
+    expect(result).toEqual(mockResponse);
+    expect(mockAxiosInstance.post).toHaveBeenCalledWith(
+      url,
+      expect.any(FormData),
+      {
+        headers: {
+          'Content-Type': 'multipart/form-data',
+          'Custom-Header': 'value',
+        },
+      },
+    );
+  });
+
+  it('should handle errors gracefully', async () => {
+    const url = 'https://example.com/upload';
+    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
+    (
+      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
+    ).mockRejectedValueOnce(new Error('Network Error'));
+
+    await expect(fileUploader.upload(url, { file })).rejects.toThrow(
+      'Network Error',
+    );
+  });
+
+  it('should handle empty URL gracefully', async () => {
+    const url = '';
+    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
+    (
+      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
+    ).mockRejectedValueOnce(new Error('Request failed with status code 404'));
+
+    await expect(fileUploader.upload(url, { file })).rejects.toThrow(
+      'Request failed with status code 404',
+    );
+  });
+
+  it('should handle null URL gracefully', async () => {
+    const url = null as unknown as string;
+    const file = new File(['file content'], 'test.txt', { type: 'text/plain' });
+    (
+      mockAxiosInstance.post as unknown as ReturnType<typeof vi.fn>
+    ).mockRejectedValueOnce(new Error('Request failed with status code 404'));
+
+    await expect(fileUploader.upload(url, { file })).rejects.toThrow(
+      'Request failed with status code 404',
+    );
+  });
+});
diff --git a/eims-ui/packages/effects/request/src/request-client/modules/uploader.ts b/eims-ui/packages/effects/request/src/request-client/modules/uploader.ts
new file mode 100644
index 0000000..e9a9f60
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/modules/uploader.ts
@@ -0,0 +1,35 @@
+import type { AxiosRequestConfig, AxiosResponse } from 'axios';
+
+import type { RequestClient } from '../request-client';
+
+class FileUploader {
+  private client: RequestClient;
+
+  constructor(client: RequestClient) {
+    this.client = client;
+  }
+
+  public async upload(
+    url: string,
+    data: { file: Blob | File } & Record<string, any>,
+    config?: AxiosRequestConfig,
+  ): Promise<AxiosResponse> {
+    const formData = new FormData();
+
+    Object.entries(data).forEach(([key, value]) => {
+      formData.append(key, value);
+    });
+
+    const finalConfig: AxiosRequestConfig = {
+      ...config,
+      headers: {
+        'Content-Type': 'multipart/form-data',
+        ...config?.headers,
+      },
+    };
+
+    return this.client.post(url, formData, finalConfig);
+  }
+}
+
+export { FileUploader };
diff --git a/eims-ui/packages/effects/request/src/request-client/preset-interceptors.ts b/eims-ui/packages/effects/request/src/request-client/preset-interceptors.ts
new file mode 100644
index 0000000..2049eea
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/preset-interceptors.ts
@@ -0,0 +1,126 @@
+import type { RequestClient } from './request-client';
+import type { MakeErrorMessageFn, ResponseInterceptorConfig } from './types';
+
+import { $t } from '@vben/locales';
+
+import axios from 'axios';
+
+export const authenticateResponseInterceptor = ({
+  client,
+  doReAuthenticate,
+  doRefreshToken,
+  enableRefreshToken,
+  formatToken,
+}: {
+  client: RequestClient;
+  doReAuthenticate: () => Promise<void>;
+  doRefreshToken: () => Promise<string>;
+  enableRefreshToken: boolean;
+  formatToken: (token: string) => null | string;
+}): ResponseInterceptorConfig => {
+  return {
+    rejected: async (error) => {
+      const { config, response } = error;
+      // 濡傛灉涓嶆槸 401 閿欒锛岀洿鎺ユ姏鍑哄紓甯�
+      if (response?.status !== 401) {
+        throw error;
+      }
+      // 鍒ゆ柇鏄惁鍚敤浜� refreshToken 鍔熻兘
+      // 濡傛灉娌℃湁鍚敤鎴栬�呭凡缁忔槸閲嶈瘯璇锋眰浜嗭紝鐩存帴璺宠浆鍒伴噸鏂扮櫥褰�
+      if (!enableRefreshToken || config.__isRetryRequest) {
+        await doReAuthenticate();
+        throw error;
+      }
+      // 濡傛灉姝e湪鍒锋柊 token锛屽垯灏嗚姹傚姞鍏ラ槦鍒楋紝绛夊緟鍒锋柊瀹屾垚
+      if (client.isRefreshing) {
+        return new Promise((resolve) => {
+          client.refreshTokenQueue.push((newToken: string) => {
+            config.headers.Authorization = formatToken(newToken);
+            resolve(client.request(config.url, { ...config }));
+          });
+        });
+      }
+
+      // 鏍囪寮�濮嬪埛鏂� token
+      client.isRefreshing = true;
+      // 鏍囪褰撳墠璇锋眰涓洪噸璇曡姹傦紝閬垮厤鏃犻檺寰幆
+      config.__isRetryRequest = true;
+
+      try {
+        const newToken = await doRefreshToken();
+
+        // 澶勭悊闃熷垪涓殑璇锋眰
+        client.refreshTokenQueue.forEach((callback) => callback(newToken));
+        // 娓呯┖闃熷垪
+        client.refreshTokenQueue = [];
+
+        return client.request(error.config.url, { ...error.config });
+      } catch (refreshError) {
+        // 濡傛灉鍒锋柊 token 澶辫触锛屽鐞嗛敊璇紙濡傚己鍒剁櫥鍑烘垨璺宠浆鐧诲綍椤甸潰锛�
+        client.refreshTokenQueue.forEach((callback) => callback(''));
+        client.refreshTokenQueue = [];
+        console.error('Refresh token failed, please login again.');
+        await doReAuthenticate();
+
+        throw refreshError;
+      } finally {
+        client.isRefreshing = false;
+      }
+    },
+  };
+};
+
+export const errorMessageResponseInterceptor = (
+  makeErrorMessage?: MakeErrorMessageFn,
+): ResponseInterceptorConfig => {
+  return {
+    rejected: (error: any) => {
+      if (axios.isCancel(error)) {
+        return Promise.reject(error);
+      }
+
+      const err: string = error?.toString?.() ?? '';
+      let errMsg = '';
+      if (err?.includes('Network Error')) {
+        errMsg = $t('ui.fallback.http.networkError');
+      } else if (error?.message?.includes?.('timeout')) {
+        errMsg = $t('ui.fallback.http.requestTimeout');
+      }
+      if (errMsg) {
+        makeErrorMessage?.(errMsg, error);
+        return Promise.reject(error);
+      }
+
+      let errorMessage = '';
+      const status = error?.response?.status;
+
+      switch (status) {
+        case 400: {
+          errorMessage = $t('ui.fallback.http.badRequest');
+          break;
+        }
+        case 401: {
+          errorMessage = $t('ui.fallback.http.unauthorized');
+          break;
+        }
+        case 403: {
+          errorMessage = $t('ui.fallback.http.forbidden');
+          break;
+        }
+        case 404: {
+          errorMessage = $t('ui.fallback.http.notFound');
+          break;
+        }
+        case 408: {
+          errorMessage = $t('ui.fallback.http.requestTimeout');
+          break;
+        }
+        default: {
+          errorMessage = $t('ui.fallback.http.internalServerError');
+        }
+      }
+      makeErrorMessage?.(errorMessage, error);
+      return Promise.reject(error);
+    },
+  };
+};
diff --git a/eims-ui/packages/effects/request/src/request-client/request-client.test.ts b/eims-ui/packages/effects/request/src/request-client/request-client.test.ts
new file mode 100644
index 0000000..2d94525
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/request-client.test.ts
@@ -0,0 +1,99 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import { afterEach, beforeEach, describe, expect, it } from 'vitest';
+
+import { RequestClient } from './request-client';
+
+describe('requestClient', () => {
+  let mock: MockAdapter;
+  let requestClient: RequestClient;
+
+  beforeEach(() => {
+    mock = new MockAdapter(axios);
+    requestClient = new RequestClient();
+  });
+
+  afterEach(() => {
+    mock.reset();
+  });
+
+  it('should successfully make a GET request', async () => {
+    mock.onGet('test/url').reply(200, { data: 'response' });
+
+    const response = await requestClient.get('test/url');
+
+    expect(response.data).toEqual({ data: 'response' });
+  });
+
+  it('should successfully make a POST request', async () => {
+    const postData = { key: 'value' };
+    const mockData = { data: 'response' };
+    mock.onPost('/test/post', postData).reply(200, mockData);
+    const response = await requestClient.post('/test/post', postData);
+    expect(response.data).toEqual(mockData);
+  });
+
+  it('should successfully make a PUT request', async () => {
+    const putData = { key: 'updatedValue' };
+    const mockData = { data: 'updated response' };
+    mock.onPut('/test/put', putData).reply(200, mockData);
+    const response = await requestClient.put('/test/put', putData);
+    expect(response.data).toEqual(mockData);
+  });
+
+  it('should successfully make a DELETE request', async () => {
+    const mockData = { data: 'delete response' };
+    mock.onDelete('/test/delete').reply(200, mockData);
+    const response = await requestClient.delete('/test/delete');
+    expect(response.data).toEqual(mockData);
+  });
+
+  it('should handle network errors', async () => {
+    mock.onGet('/test/error').networkError();
+    try {
+      await requestClient.get('/test/error');
+      expect(true).toBe(false);
+    } catch (error: any) {
+      expect(error.isAxiosError).toBe(true);
+      expect(error.message).toBe('Network Error');
+    }
+  });
+
+  it('should handle timeout', async () => {
+    mock.onGet('/test/timeout').timeout();
+    try {
+      await requestClient.get('/test/timeout');
+      expect(true).toBe(false);
+    } catch (error: any) {
+      expect(error.isAxiosError).toBe(true);
+      expect(error.code).toBe('ECONNABORTED');
+    }
+  });
+
+  it('should successfully upload a file', async () => {
+    const fileData = new Blob(['file contents'], { type: 'text/plain' });
+
+    mock.onPost('/test/upload').reply((config) => {
+      return config.data instanceof FormData && config.data.has('file')
+        ? [200, { data: 'file uploaded' }]
+        : [400, { error: 'Bad Request' }];
+    });
+
+    const response = await requestClient.upload('/test/upload', {
+      file: fileData,
+    });
+    expect(response.data).toEqual({ data: 'file uploaded' });
+  });
+
+  it('should successfully download a file as a blob', async () => {
+    const mockFileContent = new Blob(['mock file content'], {
+      type: 'text/plain',
+    });
+
+    mock.onGet('/test/download').reply(200, mockFileContent);
+
+    const res = await requestClient.download('/test/download');
+
+    expect(res.data).toBeInstanceOf(Blob);
+  });
+});
diff --git a/eims-ui/packages/effects/request/src/request-client/request-client.ts b/eims-ui/packages/effects/request/src/request-client/request-client.ts
new file mode 100644
index 0000000..6c84018
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/request-client.ts
@@ -0,0 +1,162 @@
+import type {
+  AxiosInstance,
+  AxiosRequestConfig,
+  AxiosResponse,
+  CreateAxiosDefaults,
+} from 'axios';
+
+import { bindMethods, merge } from '@vben/utils';
+
+import axios from 'axios';
+
+import { FileDownloader } from './modules/downloader';
+import { InterceptorManager } from './modules/interceptor';
+import { FileUploader } from './modules/uploader';
+import { type RequestClientOptions } from './types';
+
+class RequestClient {
+  private readonly instance: AxiosInstance;
+
+  public addRequestInterceptor: InterceptorManager['addRequestInterceptor'];
+  public addResponseInterceptor: InterceptorManager['addResponseInterceptor'];
+
+  public download: FileDownloader['download'];
+  // 鏄惁姝e湪鍒锋柊token
+  public isRefreshing = false;
+  // 鍒锋柊token闃熷垪
+  public refreshTokenQueue: ((token: string) => void)[] = [];
+  public upload: FileUploader['upload'];
+
+  /**
+   * 鏋勯�犲嚱鏁帮紝鐢ㄤ簬鍒涘缓Axios瀹炰緥
+   * @param options - Axios璇锋眰閰嶇疆锛屽彲閫�
+   */
+  constructor(options: RequestClientOptions = {}) {
+    // 鍚堝苟榛樿閰嶇疆鍜屼紶鍏ョ殑閰嶇疆
+    const defaultConfig: CreateAxiosDefaults = {
+      headers: {
+        'Content-Type': 'application/json;charset=utf-8',
+      },
+      // 榛樿瓒呮椂鏃堕棿
+      timeout: 10_000,
+    };
+    const { ...axiosConfig } = options;
+    const requestConfig = merge(axiosConfig, defaultConfig);
+    this.instance = axios.create(requestConfig);
+
+    bindMethods(this);
+
+    // 瀹炰緥鍖栨嫤鎴櫒绠$悊鍣�
+    const interceptorManager = new InterceptorManager(this.instance);
+    this.addRequestInterceptor =
+      interceptorManager.addRequestInterceptor.bind(interceptorManager);
+    this.addResponseInterceptor =
+      interceptorManager.addResponseInterceptor.bind(interceptorManager);
+
+    // 瀹炰緥鍖栨枃浠朵笂浼犲櫒
+    const fileUploader = new FileUploader(this);
+    this.upload = fileUploader.upload.bind(fileUploader);
+    // 瀹炰緥鍖栨枃浠朵笅杞藉櫒
+    const fileDownloader = new FileDownloader(this);
+    this.download = fileDownloader.download.bind(fileDownloader);
+  }
+
+  /**
+   * DELETE璇锋眰鏂规硶
+   */
+  public delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
+    return this.request<T>(url, { ...config, method: 'DELETE' });
+  }
+
+  /**
+   * DELETE璇锋眰鏂规硶 鎴愬姛浼氬脊鍑簃sg
+   */
+  public deleteWithMsg<T = any>(
+    url: string,
+    config?: AxiosRequestConfig,
+  ): Promise<T> {
+    return this.request<T>(url, {
+      ...config,
+      method: 'DELETE',
+      successMessageMode: 'message',
+    });
+  }
+
+  /**
+   * GET璇锋眰鏂规硶
+   */
+  public get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
+    return this.request<T>(url, { ...config, method: 'GET' });
+  }
+
+  /**
+   * POST璇锋眰鏂规硶
+   */
+  public post<T = any>(
+    url: string,
+    data?: any,
+    config?: AxiosRequestConfig,
+  ): Promise<T> {
+    return this.request<T>(url, { ...config, data, method: 'POST' });
+  }
+
+  /**
+   * POST璇锋眰鏂规硶 鎴愬姛浼氬脊鍑簃sg
+   */
+  public postWithMsg<T = any>(
+    url: string,
+    data?: any,
+    config?: AxiosRequestConfig,
+  ): Promise<T> {
+    return this.request<T>(url, {
+      ...config,
+      data,
+      method: 'POST',
+      successMessageMode: 'message',
+    });
+  }
+
+  /**
+   * PUT璇锋眰鏂规硶
+   */
+  public put<T = any>(
+    url: string,
+    data?: any,
+    config?: AxiosRequestConfig,
+  ): Promise<T> {
+    return this.request<T>(url, { ...config, data, method: 'PUT' });
+  }
+
+  /**
+   * PUT璇锋眰鏂规硶 鎴愬姛浼氬脊鍑簃sg
+   */
+  public putWithMsg<T = any>(
+    url: string,
+    data?: any,
+    config?: AxiosRequestConfig,
+  ): Promise<T> {
+    return this.request<T>(url, {
+      ...config,
+      data,
+      method: 'PUT',
+      successMessageMode: 'message',
+    });
+  }
+
+  /**
+   * 閫氱敤鐨勮姹傛柟娉�
+   */
+  public async request<T>(url: string, config: AxiosRequestConfig): Promise<T> {
+    try {
+      const response: AxiosResponse<T> = await this.instance({
+        url,
+        ...config,
+      });
+      return response as T;
+    } catch (error: any) {
+      throw error.response ? error.response.data : error;
+    }
+  }
+}
+
+export { RequestClient };
diff --git a/eims-ui/packages/effects/request/src/request-client/types.ts b/eims-ui/packages/effects/request/src/request-client/types.ts
new file mode 100644
index 0000000..aca3f62
--- /dev/null
+++ b/eims-ui/packages/effects/request/src/request-client/types.ts
@@ -0,0 +1,78 @@
+import type {
+  AxiosResponse,
+  CreateAxiosDefaults,
+  InternalAxiosRequestConfig,
+} from 'axios';
+
+type RequestResponse<T = any> = AxiosResponse<T>;
+
+type RequestContentType =
+  | 'application/json;charset=utf-8'
+  | 'application/octet-stream;charset=utf-8'
+  | 'application/x-www-form-urlencoded;charset=utf-8'
+  | 'multipart/form-data;charset=utf-8';
+
+type RequestClientOptions = CreateAxiosDefaults;
+
+interface RequestInterceptorConfig {
+  fulfilled?: (
+    config: InternalAxiosRequestConfig,
+  ) =>
+    | InternalAxiosRequestConfig<any>
+    | Promise<InternalAxiosRequestConfig<any>>;
+  rejected?: (error: any) => any;
+}
+
+interface ResponseInterceptorConfig<T = any> {
+  fulfilled?: (
+    response: AxiosResponse<T>,
+  ) => AxiosResponse | Promise<AxiosResponse>;
+  rejected?: (error: any) => any;
+}
+
+type MakeErrorMessageFn = (message: string, error: any) => void;
+
+interface HttpResponse<T = any> {
+  code: number;
+  data: T;
+  msg: string;
+}
+
+export type {
+  HttpResponse,
+  MakeErrorMessageFn,
+  RequestClientOptions,
+  RequestContentType,
+  RequestInterceptorConfig,
+  RequestResponse,
+  ResponseInterceptorConfig,
+};
+
+export type ErrorMessageMode = 'message' | 'modal' | 'none' | undefined;
+export type SuccessMessageMode = ErrorMessageMode;
+
+/**
+ * 鎷撳睍axios鐨勮姹傞厤缃�
+ */
+declare module 'axios' {
+  interface AxiosRequestConfig {
+    /** 鏄惁鍔犲瘑璇锋眰鍙傛暟  */
+    encrypt?: boolean;
+    /**
+     * 閿欒寮圭獥绫诲瀷
+     */
+    errorMessageMode?: ErrorMessageMode;
+    /**
+     * 鏄惁杩斿洖鍘熺敓axios鍝嶅簲
+     */
+    isReturnNativeResponse?: boolean;
+    /**
+     * 鏄惁闇�瑕佽浆鎹㈠搷搴� 鍗冲彧鑾峰彇{code, msg, data}涓殑data
+     */
+    isTransformResponse?: boolean;
+    /**
+     * 鎴愬姛寮圭獥绫诲瀷
+     */
+    successMessageMode?: SuccessMessageMode;
+  }
+}
diff --git a/eims-ui/packages/effects/request/tsconfig.json b/eims-ui/packages/effects/request/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/effects/request/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/icons/README.md b/eims-ui/packages/icons/README.md
new file mode 100644
index 0000000..bc50d25
--- /dev/null
+++ b/eims-ui/packages/icons/README.md
@@ -0,0 +1,19 @@
+# @vben/icons
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨勫浘鏍囨枃浠讹紝缁ф壙浜� `@vben-core/icons` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤鍥炬爣鍙互鏀惧湪杩欓噷銆�
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/icons
+```
+
+### 浣跨敤
+
+```ts
+import { X } from '@vben/icons';
+```
diff --git a/eims-ui/packages/icons/package.json b/eims-ui/packages/icons/package.json
new file mode 100644
index 0000000..4c9e43c
--- /dev/null
+++ b/eims-ui/packages/icons/package.json
@@ -0,0 +1,60 @@
+{
+  "name": "@vben/icons",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/icons"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/icons": "workspace:*",
+    "@vben-core/shadcn-ui": "workspace:^"
+  },
+  "devDependencies": {
+    "@iconify/icons-akar-icons": "^1.2.19",
+    "@iconify/icons-ant-design": "^1.2.7",
+    "@iconify/icons-arcticons": "^1.2.77",
+    "@iconify/icons-bi": "^1.2.19",
+    "@iconify/icons-bx": "^1.2.6",
+    "@iconify/icons-carbon": "^1.2.20",
+    "@iconify/icons-devicon": "^1.2.17",
+    "@iconify/icons-emojione": "^1.2.6",
+    "@iconify/icons-eos-icons": "^1.2.6",
+    "@iconify/icons-fa-brands": "^1.2.4",
+    "@iconify/icons-fe": "^1.2.5",
+    "@iconify/icons-flat-color-icons": "^1.2.5",
+    "@iconify/icons-fluent": "^1.2.38",
+    "@iconify/icons-fluent-mdl2": "^1.2.1",
+    "@iconify/icons-ic": "^1.2.13",
+    "@iconify/icons-icon-park-outline": "^1.2.11",
+    "@iconify/icons-icon-park-twotone": "^1.2.8",
+    "@iconify/icons-la": "^1.2.3",
+    "@iconify/icons-logos": "^1.2.36",
+    "@iconify/icons-lucide": "^1.2.135",
+    "@iconify/icons-majesticons": "^1.2.6",
+    "@iconify/icons-material-symbols": "^1.2.58",
+    "@iconify/icons-mdi": "^1.2.48",
+    "@iconify/icons-mingcute": "^1.2.9",
+    "@iconify/icons-noto": "^1.2.10",
+    "@iconify/icons-ph": "^1.2.5",
+    "@iconify/icons-ri": "^1.2.10",
+    "@iconify/icons-simple-icons": "^1.2.74",
+    "@iconify/icons-skill-icons": "^1.2.1",
+    "@iconify/icons-solar": "^1.2.3",
+    "@iconify/icons-streamline": "^1.2.3",
+    "@iconify/icons-tabler": "^1.2.95",
+    "@iconify/icons-uiw": "^1.2.6",
+    "@iconify/icons-vscode-icons": "^1.2.29",
+    "@iconify/icons-wpf": "^1.2.3"
+  }
+}
diff --git a/eims-ui/packages/icons/src/iconify-offline/index.ts b/eims-ui/packages/icons/src/iconify-offline/index.ts
new file mode 100644
index 0000000..6e2e19e
--- /dev/null
+++ b/eims-ui/packages/icons/src/iconify-offline/index.ts
@@ -0,0 +1,186 @@
+import { createIconifyOfflineIcon } from '@vben-core/icons';
+
+import githubOutlined from '@iconify/icons-ant-design/github-outlined';
+import inboxIcon from '@iconify/icons-ant-design/inbox-outlined';
+import userOutlined from '@iconify/icons-ant-design/user-outlined';
+import ucIcon from '@iconify/icons-arcticons/uc-browser';
+import defaultFileIcon from '@iconify/icons-bx/file';
+import sqlIcon from '@iconify/icons-carbon/sql';
+import linuxIcon from '@iconify/icons-devicon/linux';
+import windowsIcon from '@iconify/icons-devicon/windows8';
+import alipayIcon from '@iconify/icons-fa-brands/alipay';
+import androidIcon from '@iconify/icons-flat-color-icons/android-os';
+import comandLine from '@iconify/icons-flat-color-icons/command-line';
+import folderIcon from '@iconify/icons-flat-color-icons/folder';
+import defaultOsIcon from '@iconify/icons-ic/outline-computer';
+import memoryIcon from '@iconify/icons-la/memory';
+import chromeIcon from '@iconify/icons-logos/chrome';
+import firefoxIcon from '@iconify/icons-logos/firefox';
+import edgeIcon from '@iconify/icons-logos/microsoft-edge';
+import operaIcon from '@iconify/icons-logos/opera';
+import quarkIcon from '@iconify/icons-logos/quarkus-icon';
+import redisIcon from '@iconify/icons-logos/redis';
+import safariIcon from '@iconify/icons-logos/safari';
+import vueIcon from '@iconify/icons-logos/vue';
+import iphoneIcon from '@iconify/icons-majesticons/iphone-x-apps-line';
+import menuIcon from '@iconify/icons-material-symbols/menu';
+import okButtonIcon from '@iconify/icons-mdi/button-pointer';
+import micromessengerIcon from '@iconify/icons-mdi/wechat';
+import defaultBrowserIcon from '@iconify/icons-ph/browser-duotone';
+import baiduIcon from '@iconify/icons-ri/baidu-fill';
+import dingdingFill from '@iconify/icons-ri/dingding-fill';
+import dingtalkIcon from '@iconify/icons-ri/dingding-line';
+import taobaoIconFill from '@iconify/icons-ri/taobao-fill';
+import giteeIcon from '@iconify/icons-simple-icons/gitee';
+import qqIcon from '@iconify/icons-simple-icons/tencentqq';
+import javaIcon from '@iconify/icons-skill-icons/java-light';
+import tsIcon from '@iconify/icons-skill-icons/typescript';
+import xmlIcon from '@iconify/icons-tabler/file-type-xml';
+import githubOAuthIcon from '@iconify/icons-uiw/github';
+import excelIcon from '@iconify/icons-vscode-icons/file-type-excel';
+import osxIcon from '@iconify/icons-wpf/macos';
+
+import './menu-icons';
+
+// 鐢ㄦ埛 涓嬫媺鑿滃崟
+export const GitHubOutlined = createIconifyOfflineIcon(
+  'ant-design:github-outlined',
+  githubOutlined,
+);
+
+export const UserOutlined = createIconifyOfflineIcon(
+  'ant-design:user-outlined',
+  userOutlined,
+);
+
+// 缂撳瓨鐩戞帶浣跨敤
+export const RedisIcon = createIconifyOfflineIcon('logos:redis', redisIcon);
+export const CommandLineIcon = createIconifyOfflineIcon(
+  'flat-color-icons:command-line',
+  comandLine,
+);
+export const MemoryIcon = createIconifyOfflineIcon('la:memory', memoryIcon);
+
+// 鐢ㄦ埛绠$悊 瀵煎叆
+// Excel鍥炬爣
+export const ExcelIcon = createIconifyOfflineIcon(
+  'vscode-icons:file-type-excel',
+  excelIcon,
+);
+// 鎷栨嫿涓婁紶鍥炬爣
+export const InBoxIcon = createIconifyOfflineIcon(
+  'ant-design:inbox-outlined',
+  inboxIcon,
+);
+
+// 绗笁鏂圭櫥褰曠浉鍏冲浘鏍�
+export const TaobaoIcon = createIconifyOfflineIcon(
+  'ri:taobao-fill',
+  taobaoIconFill,
+);
+export const AlipayIcon = createIconifyOfflineIcon(
+  'fa-brands:alipay',
+  alipayIcon,
+);
+export const DingdingIcon = createIconifyOfflineIcon(
+  'ri:dingding-fill',
+  dingdingFill,
+);
+export const GiteeIcon = createIconifyOfflineIcon(
+  'simple-icons:gitee',
+  giteeIcon,
+);
+export const GithubOAuthIcon = createIconifyOfflineIcon(
+  'uiw:github',
+  githubOAuthIcon,
+);
+
+// 绯荤粺鐩稿叧鍥炬爣
+export const WindowsIcon = createIconifyOfflineIcon(
+  'devicon:windows8',
+  windowsIcon,
+);
+export const LinuxIcon = createIconifyOfflineIcon('devicon:linux', linuxIcon);
+export const OSXIcon = createIconifyOfflineIcon('wpf:macos', osxIcon);
+export const AndroidIcon = createIconifyOfflineIcon(
+  'flat-color-icons:android-os',
+  androidIcon,
+);
+export const IPhoneIcon = createIconifyOfflineIcon(
+  'majesticons:iphone-x-apps-line',
+  iphoneIcon,
+);
+// 涓婇潰鍥炬爣娌℃壘鍒� 榛樿鍥炬爣
+export const DefaultOsIcon = createIconifyOfflineIcon(
+  'ic:outline-computer',
+  defaultOsIcon,
+);
+
+// 娴忚鍣ㄧ浉鍏冲浘鏍�
+export const ChromeIcon = createIconifyOfflineIcon('logos:chrome', chromeIcon);
+export const EdgeIcon = createIconifyOfflineIcon(
+  'logos:microsoft-edge',
+  edgeIcon,
+);
+export const FirefoxIcon = createIconifyOfflineIcon(
+  'logos:firefox',
+  firefoxIcon,
+);
+export const OperaIcon = createIconifyOfflineIcon('logos:opera', operaIcon);
+export const SafariIcon = createIconifyOfflineIcon('logos:safari', safariIcon);
+export const MicromessengerIcon = createIconifyOfflineIcon(
+  'mdi:wechat',
+  micromessengerIcon,
+);
+export const QuarkIcon = createIconifyOfflineIcon(
+  'logos:quarkus-icon',
+  quarkIcon,
+);
+export const QQIcon = createIconifyOfflineIcon(
+  'simple-icons:tencentqq',
+  qqIcon,
+);
+export const DingtalkIcon = createIconifyOfflineIcon(
+  'ri:dingding-line',
+  dingtalkIcon,
+);
+export const UcIcon = createIconifyOfflineIcon('arcticons:uc-browser', ucIcon);
+export const BaiduIcon = createIconifyOfflineIcon('ri:baidu-fill', baiduIcon);
+// 鏈煡娴忚鍣ㄥ浘鏍�
+export const DefaultBrowserIcon = createIconifyOfflineIcon(
+  'ph:browser-duotone',
+  defaultBrowserIcon,
+);
+
+// 鑿滃崟绫诲瀷 鐩綍/鎸夐挳/鑿滃崟
+export const FolderIcon = createIconifyOfflineIcon(
+  'flat-color-icons:folder',
+  folderIcon,
+);
+export const OkButtonIcon = createIconifyOfflineIcon(
+  'mdi:button-pointer',
+  okButtonIcon,
+);
+export const MenuIcon = createIconifyOfflineIcon(
+  'material-symbols:menu',
+  menuIcon,
+);
+
+export const JavaIcon = createIconifyOfflineIcon(
+  'skill-icons:java-light',
+  javaIcon,
+);
+export const XmlIcon = createIconifyOfflineIcon(
+  'tabler:file-type-xml',
+  xmlIcon,
+);
+export const SqlIcon = createIconifyOfflineIcon('carbon:sql', sqlIcon);
+export const TsIcon = createIconifyOfflineIcon(
+  'skill-icons:typescript',
+  tsIcon,
+);
+export const VueIcon = createIconifyOfflineIcon('logos:vue', vueIcon);
+export const DefaultFileIcon = createIconifyOfflineIcon(
+  'flat-color-icons:folder',
+  defaultFileIcon,
+);
diff --git a/eims-ui/packages/icons/src/iconify-offline/menu-icons.ts b/eims-ui/packages/icons/src/iconify-offline/menu-icons.ts
new file mode 100644
index 0000000..e462a78
--- /dev/null
+++ b/eims-ui/packages/icons/src/iconify-offline/menu-icons.ts
@@ -0,0 +1,104 @@
+import { addIcon } from '@vben-core/icons';
+
+import airpods from '@iconify/icons-akar-icons/airpods';
+import schedule from '@iconify/icons-akar-icons/schedule';
+import settingOutline from '@iconify/icons-ant-design/setting-outlined';
+import Operation from '@iconify/icons-arcticons/one-hand-operation';
+import BaseLineHousesFill from '@iconify/icons-bi/houses-fill';
+import BxPackage from '@iconify/icons-bx/package';
+import modelAlt from '@iconify/icons-carbon/model-alt';
+import taskApproved from '@iconify/icons-carbon/task-approved';
+import redisWordmark from '@iconify/icons-devicon/redis-wordmark';
+import springWordmark from '@iconify/icons-devicon/spring-wordmark';
+import vscode from '@iconify/icons-devicon/vscode';
+import evergreenTree from '@iconify/icons-emojione/evergreen-tree';
+import RoleBindingOutlined from '@iconify/icons-eos-icons/role-binding-outlined';
+import SystemGroup from '@iconify/icons-eos-icons/system-group';
+import NoticePush from '@iconify/icons-fe/notice-push';
+import plus from '@iconify/icons-flat-color-icons/plus';
+import from24 from '@iconify/icons-fluent/form-24-regular';
+import builDefinition from '@iconify/icons-fluent-mdl2/build-definition';
+import Dictionary from '@iconify/icons-fluent-mdl2/dictionary';
+import leaveUser from '@iconify/icons-fluent-mdl2/leave-user';
+import BaseLineHouse from '@iconify/icons-ic/baseline-house';
+import monitor from '@iconify/icons-ic/baseline-monitor';
+import roundLaunch from '@iconify/icons-ic/round-launch';
+import MenuSharp from '@iconify/icons-ic/sharp-menu';
+import Appointment from '@iconify/icons-icon-park-outline/appointment';
+import SettingTwo from '@iconify/icons-icon-park-twotone/setting-two';
+import boolOpenText from '@iconify/icons-lucide/book-open-text';
+import copyright from '@iconify/icons-lucide/copyright';
+import table from '@iconify/icons-lucide/table';
+import cloudDoneOutlineRounded from '@iconify/icons-material-symbols/cloud-done-outline-rounded';
+import generatingTokensOutline from '@iconify/icons-material-symbols/generating-tokens-outline';
+import LogoDevOutline from '@iconify/icons-material-symbols/logo-dev-outline';
+import ccOutline from '@iconify/icons-mdi/cc-outline';
+import tools from '@iconify/icons-mdi/tools';
+import workflowOutline from '@iconify/icons-mdi/workflow-outline';
+import DepartmentLine from '@iconify/icons-mingcute/department-line';
+import profileLine from '@iconify/icons-mingcute/profile-line';
+import UserDuotone from '@iconify/icons-ph/user-duotone';
+import insatnceLine from '@iconify/icons-ri/instance-line';
+import todoLine from '@iconify/icons-ri/todo-line';
+import Authy from '@iconify/icons-simple-icons/authy';
+import FolderWithFilesOutline from '@iconify/icons-solar/folder-with-files-outline';
+import monitorBoldDuotone from '@iconify/icons-solar/monitor-bold-duotone';
+import InterfaceLoginDialPadFingerPasswordDialPadDotFinger from '@iconify/icons-streamline/interface-login-dial-pad-finger-password-dial-pad-dot-finger';
+import categoryPlus from '@iconify/icons-tabler/category-plus';
+import code from '@iconify/icons-tabler/code';
+
+/**
+ * 杩欓噷娣诲姞鑿滃崟鍥炬爣
+ */
+addIcon('eos-icons:system-group', SystemGroup);
+addIcon('ph:user-duotone', UserDuotone);
+addIcon('eos-icons:role-binding-outlined', RoleBindingOutlined);
+addIcon('ic:sharp-menu', MenuSharp);
+addIcon('mingcute:department-line', DepartmentLine);
+addIcon('icon-park-outline:appointment', Appointment);
+addIcon('fluent-mdl2:dictionary', Dictionary);
+addIcon('icon-park-twotone:setting-two', SettingTwo);
+addIcon('fe:notice-push', NoticePush);
+addIcon('material-symbols:logo-dev-outline', LogoDevOutline);
+addIcon('arcticons:one-hand-operation', Operation);
+addIcon(
+  'streamline:interface-login-dial-pad-finger-password-dial-pad-dot-finger',
+  InterfaceLoginDialPadFingerPasswordDialPadDotFinger,
+);
+addIcon('solar:folder-with-files-outline', FolderWithFilesOutline);
+addIcon('simple-icons:authy', Authy);
+addIcon('ic:baseline-house', BaseLineHouse);
+addIcon('bi:houses-fill', BaseLineHousesFill);
+addIcon('bx:package', BxPackage);
+addIcon('solar:monitor-bold-duotone', monitorBoldDuotone);
+addIcon('material-symbols:generating-tokens-outline', generatingTokensOutline);
+addIcon('devicon:redis-wordmark', redisWordmark);
+addIcon('devicon:spring-wordmark', springWordmark);
+addIcon('akar-icons:schedule', schedule);
+addIcon('akar-icons:airpods', airpods);
+addIcon('mdi:tools', tools);
+addIcon('tabler:code', code);
+addIcon('flat-color-icons:plus', plus);
+addIcon('devicon:vscode', vscode);
+addIcon('lucide:table', table);
+addIcon('emojione:evergreen-tree', evergreenTree);
+addIcon('fluent-mdl2:leave-user', leaveUser);
+addIcon('mdi:workflow-outline', workflowOutline);
+addIcon('tabler:category-plus', categoryPlus);
+addIcon('carbon:model-alt', modelAlt);
+addIcon('fluent-mdl2:build-definition', builDefinition);
+addIcon('fluent-mdl2:build-definition', builDefinition);
+addIcon('icon-park-outline:monitor', monitor);
+addIcon('ri:instance-line', insatnceLine);
+addIcon('ri:todo-line', todoLine);
+addIcon('fluent:form-24-regular', from24);
+addIcon('carbon:task-approved', taskApproved);
+addIcon('ic:round-launch', roundLaunch);
+addIcon('material-symbols:cloud-done-outline-rounded', cloudDoneOutlineRounded);
+addIcon('mdi:cc-outline', ccOutline);
+addIcon('lucide:book-open-text', boolOpenText);
+addIcon('lucide:copyright', copyright);
+// 涓汉涓績
+addIcon('mingcute:profile-line', profileLine);
+// oss閰嶇疆
+addIcon('ant-design:setting-outlined', settingOutline);
diff --git a/eims-ui/packages/icons/src/iconify/index.ts b/eims-ui/packages/icons/src/iconify/index.ts
new file mode 100644
index 0000000..1e59ef0
--- /dev/null
+++ b/eims-ui/packages/icons/src/iconify/index.ts
@@ -0,0 +1,18 @@
+import { createIconifyIcon } from '@vben-core/icons';
+
+export * from '@vben-core/icons';
+
+export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc');
+
+export const MdiWechat = createIconifyIcon('mdi:wechat');
+
+export const MdiGithub = createIconifyIcon('mdi:github');
+
+export const MdiGoogle = createIconifyIcon('mdi:google');
+
+export const MdiQqchat = createIconifyIcon('mdi:qqchat');
+
+export const EosSystem = createIconifyIcon('eos-icons:system-group');
+
+// 涓汉涓績
+export const ProfileIcon = createIconifyIcon('mingcute:profile-line');
diff --git a/eims-ui/packages/icons/src/icons/empty-icon.vue b/eims-ui/packages/icons/src/icons/empty-icon.vue
new file mode 100644
index 0000000..444a765
--- /dev/null
+++ b/eims-ui/packages/icons/src/icons/empty-icon.vue
@@ -0,0 +1,27 @@
+<template>
+  <svg
+    height="41"
+    viewBox="0 0 64 41"
+    width="64"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <g fill="none" fill-rule="evenodd" transform="translate(0 1)">
+      <ellipse
+        cx="32"
+        cy="33"
+        fill="hsl(var(--background-deep))"
+        rx="32"
+        ry="7"
+      />
+      <g fill-rule="nonzero" stroke="hsl(var(--heavy))">
+        <path
+          d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
+        />
+        <path
+          d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
+          fill="hsl(var(--accent))"
+        />
+      </g>
+    </g>
+  </svg>
+</template>
diff --git a/eims-ui/packages/icons/src/index.ts b/eims-ui/packages/icons/src/index.ts
new file mode 100644
index 0000000..53d7b00
--- /dev/null
+++ b/eims-ui/packages/icons/src/index.ts
@@ -0,0 +1,5 @@
+export * from './iconify/index.js';
+export * from './iconify-offline/index.js';
+export { default as EmptyIcon } from './icons/empty-icon.vue';
+export * from './svg/index.js';
+export { VbenIcon } from '@vben-core/shadcn-ui';
diff --git a/eims-ui/packages/icons/src/svg/icons/antdv-logo.svg b/eims-ui/packages/icons/src/svg/icons/antdv-logo.svg
new file mode 100644
index 0000000..dbfcee7
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/antdv-logo.svg
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch -->
+    <title>Vue</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+        <linearGradient x1="69.644116%" y1="0%" x2="69.644116%" y2="100%" id="linearGradient-1">
+            <stop stop-color="#29CDFF" offset="0%"></stop>
+            <stop stop-color="#148EFF" offset="37.8600687%"></stop>
+            <stop stop-color="#0A60FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="-19.8191553%" y1="-36.7931464%" x2="138.57919%" y2="157.637507%" id="linearGradient-2">
+            <stop stop-color="#29CDFF" offset="0%"></stop>
+            <stop stop-color="#0F78FF" offset="100%"></stop>
+        </linearGradient>
+        <linearGradient x1="68.1279872%" y1="-35.6905737%" x2="30.4400914%" y2="114.942679%" id="linearGradient-3">
+            <stop stop-color="#FA8E7D" offset="0%"></stop>
+            <stop stop-color="#F74A5C" offset="51.2635191%"></stop>
+            <stop stop-color="#F51D2C" offset="100%"></stop>
+        </linearGradient>
+    </defs>
+    <g id="Vue" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Group" transform="translate(19.000000, 9.000000)">
+            <path d="M89.96,90.48 C78.58,93.48 68.33,83.36 67.62,82.48 L46.6604487,62.2292258 C45.5023849,61.1103236 44.8426845,59.5728835 44.8296987,57.9626396 L44.5035564,17.5209948 C44.4948861,16.4458744 44.0537714,15.4195095 43.2796864,14.6733517 L29.6459999,1.53153737 C28.055475,-0.00160504005 25.5232423,0.0449126588 23.9900999,1.63543756 C23.2715121,2.38092066 22.87,3.37600834 22.87,4.41143746 L22.87,64.3864751 C22.87,67.0807891 23.9572233,69.6611067 25.885409,71.5429748 L63.6004615,108.352061 C65.9466323,110.641873 69.6963584,110.624605 72.0213403,108.313281" id="Path-Copy" fill="url(#linearGradient-1)" fill-rule="nonzero" transform="translate(56.415000, 54.831157) scale(-1, 1) translate(-56.415000, -54.831157) "></path>
+            <path d="M68,90.1163122 C56.62,93.1163122 45.46,83.36 44.75,82.48 L23.7904487,62.2292258 C22.6323849,61.1103236 21.9726845,59.5728835 21.9596987,57.9626396 L21.6335564,17.5209948 C21.6248861,16.4458744 21.1837714,15.4195095 20.4096864,14.6733517 L6.7759999,1.53153737 C5.185475,-0.00160504005 2.65324232,0.0449126588 1.12009991,1.63543756 C0.401512125,2.38092066 3.90211878e-13,3.37600834 3.90798505e-13,4.41143746 L3.94351218e-13,64.3864751 C3.94681177e-13,67.0807891 1.08722326,69.6611067 3.01540903,71.5429748 L40.7807092,108.401101 C43.1069304,110.671444 46.8180151,110.676525 49.1504445,108.412561" id="Path" fill="url(#linearGradient-2)" fill-rule="nonzero"></path>
+            <path d="M43.2983488,19.0991931 L27.5566079,3.88246244 C26.7624281,3.11476967 26.7409561,1.84862177 27.5086488,1.05444194 C27.8854826,0.664606611 28.4044438,0.444472651 28.9466386,0.444472651 L60.3925021,0.444472651 C61.4970716,0.444472651 62.3925021,1.33990315 62.3925021,2.44447265 C62.3925021,2.9858375 62.1730396,3.50407742 61.7842512,3.88079942 L46.0801285,19.0975301 C45.3051579,19.8484488 44.0742167,19.8491847 43.2983488,19.0991931 Z" id="Path" fill="url(#linearGradient-3)"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/eims-ui/packages/icons/src/svg/icons/avatar-1.svg b/eims-ui/packages/icons/src/svg/icons/avatar-1.svg
new file mode 100644
index 0000000..b05970d
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/avatar-1.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 391.31 560.11"><defs><style>.avatar-1-cls-1{fill:#f9cdb7;}.avatar-1-cls-2{fill:#e2a78d;}.avatar-1-cls-3{fill:#213346;}.avatar-1-cls-4{fill:#bfe1ee;}.avatar-1-cls-5{fill:#dfe7ea;}.avatar-1-cls-6{fill:#b46078;}.avatar-1-cls-7{fill:#96426e;}.avatar-1-cls-8{fill:#fff;}.avatar-1-cls-9{fill:#fefdf5;}.avatar-1-avatar-1-cls-10{fill:#f4eae1;}.avatar-1-avatar-1-cls-11{fill:#f9637c;}.avatar-1-avatar-1-cls-12{fill:#ba4264;}.avatar-1-avatar-1-cls-13{fill:#b13a59;}</style></defs><title>Asset 15</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><circle class="avatar-1-cls-1" cx="45.9" cy="303.35" r="41.4"/><path class="avatar-1-cls-2" d="M78.13,278.08a41.39,41.39,0,0,0-57.27,57.27,41.4,41.4,0,1,1,57.27-57.27Z"/><path class="avatar-1-cls-3" d="M45.9,347.82a45.9,45.9,0,1,1,45.89-45.9A46,46,0,0,1,45.9,347.82Zm0-82.79a36.9,36.9,0,1,0,36.89,36.89A36.94,36.94,0,0,0,45.9,265Z"/><circle class="avatar-1-cls-1" cx="345.41" cy="303.35" r="41.4"/><path class="avatar-1-cls-3" d="M345.42,347.82a45.9,45.9,0,1,1,45.89-45.9A46,46,0,0,1,345.42,347.82Zm0-82.79a36.9,36.9,0,1,0,36.89,36.89A36.94,36.94,0,0,0,345.42,265Z"/><path class="avatar-1-cls-1" d="M191.57,88.78h2.79a146.1,146.1,0,0,1,146.1,146.1v95A147.5,147.5,0,0,1,193,477.43h0a147.5,147.5,0,0,1-147.5-147.5v-95a146.1,146.1,0,0,1,146.1-146.1Z"/><path class="avatar-1-cls-2" d="M211.7,474.46a147.74,147.74,0,0,1-20.29,1.41c-81.14,0-147.5-66.37-147.5-147.5v-97c0-79.3,64.87-144.18,144.17-144.18h6.65a142.14,142.14,0,0,1,17,1C147.26,95.87,91.42,154.6,81.17,220.06a509,509,0,0,1-13.33,61.86L54.49,328.37C54.49,402.62,140.07,464.5,211.7,474.46Z"/><path class="avatar-1-cls-3" d="M191.41,481.93a152.43,152.43,0,0,1-152-152V234.88A151,151,0,0,1,190,84.28h2.79a151,151,0,0,1,150.61,150.6v95.05a152.45,152.45,0,0,1-152,152ZM190,93.28a142,142,0,0,0-141.6,141.6v95.05a142.82,142.82,0,0,0,244,101,142,142,0,0,0,42-101V234.88A142,142,0,0,0,192.8,93.28Z"/><path class="avatar-1-cls-4" d="M325.44,305.26v.19C324.89,305.48,325.11,305.35,325.44,305.26Z"/><path class="avatar-1-cls-3" d="M368.43,305.61a3,3,0,0,1-2.94-2.41c-4.06-20.3-24.53-16.89-25.4-16.73a3,3,0,1,1-1-5.91c9.36-1.67,28.17.66,32.33,21.46a3,3,0,0,1-2.35,3.53A3,3,0,0,1,368.43,305.61Z"/><path class="avatar-1-cls-3" d="M21.27,308.26a2.36,2.36,0,0,1-.37,0,3,3,0,0,1-2.61-3.34c1.75-14.23,7.79-21.26,12.55-24.65a20.94,20.94,0,0,1,10.61-4.05,3,3,0,0,1,.24,6c-.65,0-14.7,1.08-17.45,23.43A3,3,0,0,1,21.27,308.26Z"/><ellipse class="avatar-1-cls-5" cx="184.64" cy="499.11" rx="179.73" ry="52.86"/><path class="avatar-1-cls-6" d="M335.74,353.31c21.15,38.6,14.42,76.22,15.16,112.12l-11.45-12.67a123.72,123.72,0,0,1-30.05,60,44.13,44.13,0,0,0-13.92-15.33,92.89,92.89,0,0,1-28.69,48.92,37.34,37.34,0,0,0-1.06-30.87A58.87,58.87,0,0,1,233.6,551.2a24.22,24.22,0,0,0,2.63-23.34c-11.66,19.79-45.18,20.39-57.53,1-.86,3.91-.23,9.05,3.76,9.38-16.8,2.59-32.18-4.49-43.74-16.95a28.25,28.25,0,0,0,9.37,18.32A51.33,51.33,0,0,1,105.4,511.3c-21.68,1.35-43.33-13.51-49.87-34.21a10.36,10.36,0,0,1-2.7,9.92C15.38,468,17.38,382.75,41.91,354.63c0,0,51.63,8.28,83,32.06,8.53,6.48,8.78-2.64,21-7.72,16.48-6.83,45.87-11.63,62.57-11.7,24.41-.11,37.46,30.85,53.1,16.16C303,344.58,335.38,352.66,335.74,353.31Z"/><path class="avatar-1-cls-7" d="M352.35,461,340.9,448.3a123.83,123.83,0,0,1-30,60,44.26,44.26,0,0,0-13.92-15.34,92.89,92.89,0,0,1-28.69,48.92A37.38,37.38,0,0,0,267.18,511a58.84,58.84,0,0,1-32.13,35.77,24.22,24.22,0,0,0,2.63-23.33c-11.66,19.79-45.18,20.39-57.53,1-.87,3.91.11,18.31,4.11,18.65-16.8,2.58-32.53-13.76-44.09-26.22.67,7,2.41,19.59,7.68,24.23-17.9-.91-33.22-18.12-41-34.26-21.68,1.35-43.33-13.5-49.87-34.21a10.38,10.38,0,0,1-2.7,9.93C41.34,476,32.8,461.71,28.19,444.67,44.75,456.74,64.24,465,83.51,472.46c13.08,5,26.33,9.83,40.12,12.34,13.38,2.43,27.05,2.67,40.65,2.91,37.73.65,77,1,111.14-15.22,9.78-4.65,20.09-12.6,19.75-23.43-.39-12.38-13.93-19.44-25.48-23.87,24.6-3.65,44.78-22.73,56-44.92a136.88,136.88,0,0,0,9.89-26.39l3.31,2.58C349,391.91,351.61,425.08,352.35,461Z"/><path class="avatar-1-cls-3" d="M256.37,560.11l7.72-18.34a32.54,32.54,0,0,0,2.3-16.08,63.44,63.44,0,0,1-29.54,26.86l-15.22,6.65,9.78-13.42A19.55,19.55,0,0,0,235,535.31c-6.64,5.87-15.71,9.29-25.74,9.47a40.71,40.71,0,0,1-22-5.69c1.08,5.49,1.15,10.37-3.11,12.33l-1.88.87-1.88-.87c-13.79-6.36-24.61-12.92-33.69-20.51,1.54,6.3,3.28,8.56,4.17,9.34l9.71,8.53-12.91-.66c-19.13-1-35-18.9-43.5-35h-.05c-18.58,0-36.49-10.43-46.18-26.13l-.46.48-2.31,2.25-2.88-1.46C38,481,27.7,464.56,23.31,441.92c-6.43-33.13.88-73.25,16.66-91.33a4.5,4.5,0,0,1,6.78,5.91c-14.15,16.23-20.57,53-14.61,83.71,3.45,17.74,10.68,31,20.55,37.85a5.39,5.39,0,0,0-.06-2.56L61.27,473c5.89,18.64,25.78,32.29,45.3,31.07l3-.19,1.31,2.73c7.82,16.21,18.57,26.05,28.08,30.23A85.81,85.81,0,0,1,135.69,519l-1.27-13.24,9.05,9.75c9,9.69,19.89,17.53,34.83,25-.35-1.64-.78-3.38-1.09-4.62-1.3-5.17-2-8.22-1.46-10.69l2.33-10.64,5.86,9.18c4.85,7.6,14,12.09,24.49,12.09h.66c10.8-.2,20-5,24.71-13l4.51-7.66,3.5,8.16a28.32,28.32,0,0,1,2,14.83,54.25,54.25,0,0,0,19.1-26.84l3.33-10.56,5,9.89a41.62,41.62,0,0,1,4.38,18.57,88.24,88.24,0,0,0,16.95-35.57l1.43-6.48,5.49,3.73a48.58,48.58,0,0,1,11.95,11.55,120.21,120.21,0,0,0,25.08-53.29l1.69-8.89,10.47,11.59c2.16-37.59-3.37-68.28-17.17-95.91a4.5,4.5,0,1,1,8-4c15.83,31.7,21.33,67,17.31,111.15l-.93,10.24-12.53-13.87A127.42,127.42,0,0,1,314.17,513l-4.26,4.66-3-5.54a39.46,39.46,0,0,0-7.37-9.62,97.41,97.41,0,0,1-28.29,44.41Z"/><path class="avatar-1-cls-1" d="M158.08,455.14A10.16,10.16,0,0,1,147.94,445V406.25a10.17,10.17,0,0,1,10.14-10.14H229a10.17,10.17,0,0,1,10.13,10.14V445A10.16,10.16,0,0,1,229,455.14"/><path class="avatar-1-cls-2" d="M240.85,410.47v12a10.15,10.15,0,0,0-9.29-6.1H160.61a10.16,10.16,0,0,0-10.14,10.13v26.74a10.1,10.1,0,0,1-.84-4V410.47a10.16,10.16,0,0,1,10.13-10.13h71A10.16,10.16,0,0,1,240.85,410.47Z"/><path class="avatar-1-cls-3" d="M193.13,394.93c7.32,0,14.47,0,21.37.11l10.16.12,2.48,0,1.23,0h.34l.45,0,.89.06a14.83,14.83,0,0,1,6.56,2.4,14.65,14.65,0,0,1,6.5,11.19l0,.81v.68l0,1.11-.06,2.21c0,1.45-.08,2.89-.13,4.3-.18,5.64-.38,10.9-.61,15.69s-.48,9.14-.75,12.95c0,.48-.06,1-.1,1.41,0,.23,0,.45,0,.68s-.05.55-.08.81a12.38,12.38,0,0,1-.77,3.09,12,12,0,0,1-3.1,4.43,10.12,10.12,0,0,1-6.49,2.68,5.06,5.06,0,0,1-1.78-.27c-.39-.15-.58-.31-.58-.49s.19-.35.52-.54l1.41-.68a10.84,10.84,0,0,0,4.06-3.37,8.74,8.74,0,0,0,1.39-3.21,8.13,8.13,0,0,0,.13-1.92l0-.53c0-.23,0-.45-.05-.68,0-.46-.07-.93-.1-1.41-.27-3.81-.52-8.15-.74-12.95s-.44-10.05-.62-15.69c0-1.41-.09-2.85-.13-4.3l-.06-2.21,0-1.11v-.28l0-.16,0-.32a5.68,5.68,0,0,0-2.72-4.14,5.59,5.59,0,0,0-2.44-.77h-.76l-1.23,0-2.48,0-10.16.12c-6.9.07-14.05.1-21.37.1s-14.47,0-21.37-.1l-10.17-.12-2.47,0-1.23,0h-.76a5.59,5.59,0,0,0-2.44.77,5.68,5.68,0,0,0-2.72,4.14l0,.32,0,.16v.28l0,1.11-.06,2.21c0,1.45-.09,2.89-.13,4.3-.18,5.64-.39,10.9-.62,15.69s-.47,9.14-.74,12.95c0,.48-.07,1-.1,1.41,0,.23,0,.45,0,.68l0,.53a8.13,8.13,0,0,0,.13,1.92,8.58,8.58,0,0,0,1.39,3.21,10.69,10.69,0,0,0,4.06,3.37l1.4.68c.34.19.52.37.52.54s-.18.34-.57.49a5.06,5.06,0,0,1-1.78.27,10.14,10.14,0,0,1-6.5-2.68,12,12,0,0,1-3.09-4.43,12.38,12.38,0,0,1-.77-3.09c0-.26-.07-.59-.08-.81l-.06-.68c0-.46-.06-.93-.1-1.41-.26-3.81-.51-8.15-.74-12.95s-.43-10.05-.61-15.69c0-1.41-.09-2.85-.13-4.3,0-.73-.05-1.47-.07-2.21l0-1.11v-.68l0-.81a14.74,14.74,0,0,1,13.06-13.59l.89-.06.45,0h.34l1.23,0,2.47,0,10.17-.12C178.66,395,185.81,394.93,193.13,394.93Z"/><path class="avatar-1-cls-3" d="M54.48,374.11a37.83,37.83,0,0,0,.49,9.41,39.45,39.45,0,0,0,3,9.29,40.75,40.75,0,0,1-5.73-8.37,42.54,42.54,0,0,1-3.46-9.9,46.05,46.05,0,0,1-1-10.71,50.72,50.72,0,0,1,.42-5.48,35.47,35.47,0,0,1,1.17-5.68l10.41,4.56a24.21,24.21,0,0,0-2,3.68,43.89,43.89,0,0,0-1.6,4.2A39.74,39.74,0,0,0,54.48,374.11Z"/><path class="avatar-1-cls-3" d="M70,382.66c.81,7.4,4.1,14.79,8.86,21.21A47.32,47.32,0,0,1,64.51,384a38.71,38.71,0,0,1-2.31-12.94,35.09,35.09,0,0,1,2.63-13.62l10,5.38C71,367.93,69.21,375.33,70,382.66Z"/><path class="avatar-1-cls-3" d="M98.32,388.23a51,51,0,0,0,6.84,20.32,54,54,0,0,1-12.35-18.93A56.65,56.65,0,0,1,89,366.14l11.2,1.92A47.79,47.79,0,0,0,98.32,388.23Z"/><path class="avatar-1-cls-3" d="M282.66,384.17a26.93,26.93,0,0,1-.31,8.78c-.5,2.23-1.26,3.53-2,3.48-1.43-.15-2-5.39-2.82-11.65s-1.36-11.51,0-12c.66-.21,1.71.88,2.72,2.92A27,27,0,0,1,282.66,384.17Z"/><path class="avatar-1-cls-3" d="M305.19,378.25a35.36,35.36,0,0,1-2.39,12.16c-1.21,3-2.49,4.54-3.14,4.31-1.37-.52.25-7.73.42-16.61s-.95-16.16.45-16.6c.65-.19,1.85,1.45,2.91,4.47A35.62,35.62,0,0,1,305.19,378.25Z"/><path class="avatar-1-cls-3" d="M328.91,374.58a53,53,0,0,1,.5,9.22,44.45,44.45,0,0,1-.88,7.48c-.89,4.19-2.12,6.59-2.77,6.45-1.47-.31-.09-10.37-1.91-22.42s-5.7-21.42-4.36-22.11c.6-.31,2.41,1.68,4.41,5.46a46.7,46.7,0,0,1,2.91,6.93A56.29,56.29,0,0,1,328.91,374.58Z"/><path class="avatar-1-cls-3" d="M63.25,476.89a41,41,0,0,1-.26-8.64,36.07,36.07,0,0,1,.52-3.73,28.41,28.41,0,0,1,.79-3.18c1.19-3.83,2.68-5.88,3.3-5.66s.47,2.63.25,6.31c0,.93-.12,1.93-.13,3s0,2.22,0,3.41a68.87,68.87,0,0,0,.61,7.76,75.5,75.5,0,0,0,1.58,7.62c.34,1.15.63,2.26,1,3.27s.66,2,1,2.85c1.24,3.47,2.14,5.7,1.53,6.13s-2.54-1.16-4.76-4.51A27.16,27.16,0,0,1,67,488.7a35.74,35.74,0,0,1-1.55-3.44A41.24,41.24,0,0,1,63.25,476.89Z"/><path class="avatar-1-cls-3" d="M95.32,490.74a52.94,52.94,0,0,1-.06-13.92c.47-3.51,1.17-5.64,1.87-5.63s1.28,2.19,1.74,5.63.8,8.16,1.51,13.2c.37,2.51.82,4.86,1.3,7,.29,1,.5,2.06.8,3q.19.7.39,1.35l.41,1.23c1,3.14,1.89,5.16,1.29,5.61s-2.46-.92-4.52-4l-.78-1.23c-.25-.43-.48-.9-.73-1.39a31.63,31.63,0,0,1-1.37-3.18A41.46,41.46,0,0,1,95.32,490.74Z"/><path class="avatar-1-cls-3" d="M133.57,497.43c-4.22-15-4.79-27.65-3.43-27.82s4.23,11.85,8.35,26.45,7.93,26.36,6.6,26.93S137.74,512.42,133.57,497.43Z"/><path class="avatar-1-cls-3" d="M246.46,509.58c1.89-6.31,3.22-12.24,4.4-16.52s2.17-6.94,2.88-6.83.94,2.91.68,7.41a78.07,78.07,0,0,1-3.07,17.43,59.78,59.78,0,0,1-3.67,9.2,42.39,42.39,0,0,1-2.2,3.76c-.37.57-.73,1.13-1.1,1.64l-1.13,1.43c-3,3.61-5.46,5.14-5.93,4.69s.94-2.87,2.92-6.68c.25-.47.5-1,.77-1.49l.78-1.65c.56-1.12,1-2.39,1.62-3.67C244.45,515.67,245.5,512.73,246.46,509.58Z"/><path class="avatar-1-cls-3" d="M276.25,498.2c1.34-7.68,2-14.9,3-20.1s1.81-8.37,2.51-8.31,1.07,3.35,1.08,8.62a122.32,122.32,0,0,1-1.55,20.69,60.77,60.77,0,0,1-3.08,11.26,42.45,42.45,0,0,1-4.42,8.53c-3.14,4.54-6,6.46-6.51,6s1.27-3.2,3.37-7.8a68.85,68.85,0,0,0,3.11-8.29A89.28,89.28,0,0,0,276.25,498.2Z"/><path class="avatar-1-cls-3" d="M306.39,479c1.49-6.22,2.52-12,3.48-16.23s1.83-6.81,2.54-6.73,1.08,2.78,1,7.15a78.88,78.88,0,0,1-2.11,17,58.26,58.26,0,0,1-3,9.11c-.63,1.35-1.19,2.63-1.87,3.77-.33.58-.63,1.14-1,1.66l-1,1.47c-2.59,3.69-4.87,5.39-5.38,5s.61-2.87,2.22-6.72L302,493c.2-.53.41-1.08.62-1.66.47-1.12.85-2.38,1.32-3.67C304.79,485,305.63,482.1,306.39,479Z"/><path class="avatar-1-cls-3" d="M316.6,469.6c1.61-4,2.93-7.79,4-11.33.5-1.78,1-3.46,1.41-5.07s.78-3.1,1.1-4.47c1.26-5.5,1.93-9,2.68-9s1.27,3.64.89,9.52c-.1,1.46-.24,3.07-.52,4.78s-.61,3.53-1,5.44a76.28,76.28,0,0,1-9.69,23.34c-1.07,1.63-2.07,3.19-3.13,4.56s-2.05,2.64-3,3.74c-3.89,4.42-6.89,6.55-7.37,6.09s1.47-3.46,4.47-8.24c.75-1.2,1.57-2.5,2.39-3.94s1.69-3,2.6-4.58C313.16,477.18,315,473.53,316.6,469.6Z"/><path class="avatar-1-cls-8" d="M36.38,392.54c.75-3.65,2.73-6.2,4.07-5.78s1.62,3.43.93,6.81-2.14,6-3.55,5.89S35.63,396.18,36.38,392.54Z"/><path class="avatar-1-cls-8" d="M37.64,432a53,53,0,0,1-1.88-14.87c.13-3.85.79-6.2,1.47-6.2,1.47,0,2.42,9.08,5.35,19.74s6.63,19,5.37,19.72c-.59.34-2.36-1.34-4.42-4.6A51.58,51.58,0,0,1,37.64,432Z"/><path class="avatar-1-cls-3" d="M125.55,391.49h-.49c-5.14-.18-9.18-3.25-12.42-5.71l-.2-.15a157,157,0,0,0-68.06-29.49,4.5,4.5,0,0,1,1.51-8.87,166.07,166.07,0,0,1,72,31.19l.19.15c2.47,1.87,5,3.8,7.31,3.89s4.86-1.61,7.58-3.4l.77-.5C149.09,368.55,169,363,189.86,363h0c20.83,0,40.77,5.52,56.13,15.56l.77.5c2.71,1.79,5.3,3.48,7.58,3.4s4.84-2,7.3-3.89l.2-.15a166.07,166.07,0,0,1,72-31.19,4.5,4.5,0,1,1,1.51,8.87,157,157,0,0,0-68.06,29.49l-.2.15c-3.24,2.46-7.28,5.53-12.42,5.71s-9.43-2.62-12.85-4.87l-.74-.49c-28.72-18.76-73.71-18.76-102.43,0l-.74.49C134.6,388.79,130.5,391.49,125.55,391.49Z"/><path class="avatar-1-cls-3" d="M190.39,345.16a4.49,4.49,0,0,1-4.5-4.5V294.07a4.5,4.5,0,0,1,9,0v46.59A4.5,4.5,0,0,1,190.39,345.16Z"/><path class="avatar-1-cls-2" d="M178.07,222.19c1.68,7.42,1.09,17.32-4.12,23.31-6.08,7-15.65,5.56-23.92,5.21a103.64,103.64,0,0,0-30,3.07c-8,2.05-15.14,7-23.27,8.36-8.9,1.55-11-3.2-5.06-9.72,7-7.66,17-15.82,26.45-20.25,17.56-8.26,39.91-12.29,59.6-10.32"/><path class="avatar-1-cls-2" d="M204.25,225.47c-1.68,7.42-1.08,17.32,4.13,23.31,6.07,7,15.65,5.56,23.92,5.21a103.61,103.61,0,0,1,30,3.07c8,2.05,15.14,6.95,23.27,8.36,8.91,1.55,11-3.19,5.06-9.72-6.94-7.66-17-15.81-26.44-20.25-17.57-8.26-39.91-12.29-59.61-10.31"/><path class="avatar-1-cls-6" d="M205.19,214.55c-1.68,7.41-1.09,17.31,4.12,23.3,6.07,7,15.65,5.57,23.92,5.22a103.23,103.23,0,0,1,30,3.07c8,2.05,15.15,6.94,23.27,8.36,8.91,1.55,11-3.2,5.07-9.73-6.95-7.66-17-15.81-26.45-20.25-17.57-8.26-39.91-12.28-59.6-10.31"/><path class="avatar-1-cls-3" d="M289.6,259.29a22.42,22.42,0,0,1-3.85-.36c-5-.87-9.51-2.84-13.86-4.75a64.83,64.83,0,0,0-9.76-3.68,98.35,98.35,0,0,0-28.71-2.93c-.88,0-1.78.08-2.68.13-8,.44-18,1-24.83-6.89-6.61-7.6-6.88-19.43-5.11-27.26a5.34,5.34,0,0,1,4.29-3.82,123.23,123.23,0,0,1,62,10.72c9.2,4.33,19.88,12.49,27.87,21.3,5.87,6.47,4.76,11.05,3.58,13.2C297.53,256.7,295.17,259.29,289.6,259.29Zm-51.81-20.82a106.54,106.54,0,0,1,26.58,3.31,73,73,0,0,1,11.13,4.16c4,1.77,7.86,3.44,11.79,4.12a12.72,12.72,0,0,0,2.79.22,12.53,12.53,0,0,0-1.83-2.48c-7.24-8-16.83-15.35-25-19.2a114.19,114.19,0,0,0-54.15-10.17c-.7,5.74.13,12.44,3.63,16.47,4,4.56,10.57,4.2,17.55,3.82l2.79-.15C234.63,238.51,236.21,238.47,237.79,238.47Z"/><path class="avatar-1-cls-6" d="M173.31,210.57c1.68,7.42,1.09,17.32-4.12,23.3-6.08,7-15.66,5.57-23.93,5.22a103.27,103.27,0,0,0-30,3.07c-8,2.05-15.14,7-23.27,8.36-8.91,1.55-11-3.2-5.06-9.72,6.94-7.66,17-15.82,26.45-20.25,17.56-8.26,39.9-12.29,59.6-10.32"/><path class="avatar-1-cls-3" d="M88.89,255.31c-5.56,0-7.93-2.59-8.89-4.34-1.19-2.15-2.3-6.72,3.58-13.2,8-8.81,18.66-17,27.86-21.29a123,123,0,0,1,62-10.72,5.3,5.3,0,0,1,4.29,3.82c1.77,7.82,1.49,19.65-5.12,27.25-6.86,7.88-16.82,7.33-24.83,6.89l-2.68-.13a98.35,98.35,0,0,0-28.71,2.93,66.24,66.24,0,0,0-9.75,3.68c-4.36,1.91-8.86,3.88-13.87,4.75A22.42,22.42,0,0,1,88.89,255.31Zm-.47-9a12.45,12.45,0,0,0,2.78-.21c3.93-.69,7.75-2.36,11.8-4.13a73.52,73.52,0,0,1,11.12-4.16,107.61,107.61,0,0,1,31.33-3.2c.92,0,1.85.09,2.8.14,7,.38,13.57.75,17.54-3.82,3.51-4,4.33-10.72,3.63-16.47a114.34,114.34,0,0,0-54.15,10.17c-8.19,3.85-17.78,11.21-25,19.2A12.55,12.55,0,0,0,88.42,246.3Z"/><path class="avatar-1-cls-3" d="M183.32,443.66a115.94,115.94,0,0,1-19.23-1.61,3.5,3.5,0,1,1,1.27-6.88c.3.05,30.64,5.45,44.81-4.67a15.44,15.44,0,0,0,6.65-10.76,3.5,3.5,0,1,1,6.92,1.05,22.47,22.47,0,0,1-9.51,15.42C205.9,442.15,193.63,443.66,183.32,443.66Z"/><path class="avatar-1-cls-3" d="M353.48,315.47a3,3,0,0,1-2.91-2.3,38.7,38.7,0,0,1-1.16-13.9A21,21,0,0,1,355.94,286a3,3,0,0,1,4,4.48,15.11,15.11,0,0,0-4.57,9.53,33.19,33.19,0,0,0,1,11.77,3,3,0,0,1-2.22,3.61A2.79,2.79,0,0,1,353.48,315.47Z"/><path class="avatar-1-cls-3" d="M33.65,315.47a2.79,2.79,0,0,1-.7-.08,3,3,0,0,1-2.23-3.61,33.19,33.19,0,0,0,1-11.77,15.1,15.1,0,0,0-4.56-9.53,3,3,0,1,1,4-4.48,21,21,0,0,1,6.53,13.27,38.93,38.93,0,0,1-1.16,13.9A3,3,0,0,1,33.65,315.47Z"/><path class="avatar-1-cls-8" d="M257.31,169.69a45.27,45.27,0,0,1,7.68,4,35.23,35.23,0,0,1,5.5,4.42c2.85,2.87,4,5.23,3.3,6s-3.05,0-6.42-1.57l-5.81-2.68c-2.18-1-4.56-2-7.09-3s-5-1.88-7.24-2.68l-6.07-2c-3.49-1.2-5.77-2.2-5.73-3.28s2.48-2,6.52-2.08a34.71,34.71,0,0,1,7,.58A45.21,45.21,0,0,1,257.31,169.69Z"/><path class="avatar-1-cls-8" d="M37.56,196.45a14.27,14.27,0,0,1,4.18-5.72c1.52-1.16,2.92-1.47,3.78-.87s1.07,2,.85,3.68a23.93,23.93,0,0,1-1.76,5.89,23.77,23.77,0,0,1-3,5.37c-1.06,1.34-2.18,2.15-3.23,1.95s-1.79-1.42-2-3.31A14.32,14.32,0,0,1,37.56,196.45Z"/><path class="avatar-1-cls-8" d="M59.41,173.58c3.26-1.52,6.63-1.21,7.53.71s-1,4.71-4.29,6.23-6.63,1.2-7.53-.71S56.15,175.1,59.41,173.58Z"/><path class="avatar-1-cls-8" d="M74.62,157.15c2.37-5.05,5.43-8.82,7.45-8.15s2.07,5.88-.51,11.39-6.65,8.81-8.43,7.7S72.26,162.2,74.62,157.15Z"/><path class="avatar-1-cls-9" d="M57.89,159.15V82c0-15.57,6.93-29.64,17.59-35.75l38.7-22.17c46.33-26.53,98.7-26.53,145,0l38.71,22.17C308.57,52.33,315.49,66.4,315.49,82v77.18"/><path class="avatar-1-avatar-1-cls-10" d="M312.46,80.79v19.39c-49.22-48.34-115.1-74.62-177.69-59.93-17.18,4-34.87,11.84-45.35,28.33-13.07,20.57-10.54,52.57,5.53,70C106.58,151.12,122,155,137.89,158h-83V80.79c0-15.58,6.92-29.65,17.59-35.76l38.7-22.17c46.32-26.52,98.7-26.52,145,0L294.88,45C305.55,51.14,312.46,65.21,312.46,80.79Z"/><path class="avatar-1-cls-3" d="M315.3,163.91a4.5,4.5,0,0,1-4.5-4.5V82.23c0-14-6-26.52-15.32-31.85L256.77,28.22c-22.36-12.81-46-19.31-70.27-19.31s-47.91,6.5-70.27,19.31L77.52,50.38C68.22,55.71,62.2,68.22,62.2,82.23v77.18a4.5,4.5,0,0,1-9,0V82.23c0-17.18,7.79-32.75,19.85-39.66l38.7-22.16c47.51-27.21,102-27.21,149.5,0L300,42.57C312,49.48,319.8,65.05,319.8,82.23v77.18A4.49,4.49,0,0,1,315.3,163.91Z"/><path class="avatar-1-avatar-1-cls-11" d="M358.91,168a188.7,188.7,0,0,1-7.86,25.11c-1.65,4.39-15.77,41.8-14.06,43.41-34-31.93-86.3-52.37-145-52.37S81.13,204.56,47.14,236.44c-12.27-38.2-42.51-96.29-6.57-129,10.27-9.35,23.35-13.28,36.1-16.5,72.69-18.36,148.62-20.81,221.57-3.88,12,2.79,24,6.15,34.87,12.74s20.46,16.78,25,30C362.43,142.3,361.73,155.35,358.91,168Z"/><path class="avatar-1-avatar-1-cls-12" d="M61.88,102.48C69,96,77.49,92.12,86.27,89.28q-4.09,1-8.18,2c-12.75,3.22-25.83,7.15-36.1,16.5-35.94,32.71-5.7,90.8,6.57,129a163.52,163.52,0,0,1,17-13.88C52.14,185,28.54,132.83,61.88,102.48Z"/><path class="avatar-1-avatar-1-cls-13" d="M104.58,105a1,1,0,0,1-.19-2c6.25-1.26,12.88-2.39,19.71-3.36a1,1,0,0,1,.28,2c-6.79,1-13.39,2.09-19.6,3.34A.68.68,0,0,1,104.58,105Z"/><path class="avatar-1-avatar-1-cls-13" d="M57.19,120.46a1,1,0,0,1-.84-.46,1,1,0,0,1,.3-1.38c.42-.27,10.63-6.73,35.7-12.92a1,1,0,1,1,.48,1.94c-24.75,6.11-35,12.6-35.1,12.66A1,1,0,0,1,57.19,120.46Z"/><path class="avatar-1-avatar-1-cls-13" d="M220.93,96.32h-.09c-6.83-.61-13.48-1-19.79-1.22a1,1,0,0,1,0-2h0c6.34.2,13,.62,19.9,1.23a1,1,0,0,1-.09,2Z"/><path class="avatar-1-avatar-1-cls-13" d="M152,99.31a1,1,0,0,1-.16-2l5.35-.91c10.3-1.78,21-3.62,31.71-3.45a1,1,0,1,1,0,2c-10.58-.16-21.13,1.66-31.34,3.42l-5.37.91Z"/><path class="avatar-1-avatar-1-cls-13" d="M326.33,116.8a1,1,0,0,1-.33-.06c-6.55-2.35-13-4.47-19.07-6.29a1,1,0,0,1-.67-1.25,1,1,0,0,1,1.25-.67c6.13,1.83,12.58,4,19.16,6.33a1,1,0,0,1-.34,1.94Z"/><path class="avatar-1-avatar-1-cls-13" d="M295.34,107.21a1,1,0,0,1-.24,0C270.44,101,258.75,102,258.64,102a1,1,0,1,1-.19-2c.48,0,12.09-1.07,37.13,5.24a1,1,0,0,1-.24,2Z"/><path class="avatar-1-avatar-1-cls-13" d="M105.15,117.87a1,1,0,0,1-.19-2c6.24-1.26,12.88-2.39,19.71-3.36a1,1,0,1,1,.28,2c-6.79,1-13.39,2.09-19.6,3.34A.68.68,0,0,1,105.15,117.87Z"/><path class="avatar-1-avatar-1-cls-13" d="M57.76,133.34a1,1,0,0,1-.54-1.84c.42-.27,10.63-6.73,35.7-12.92a1,1,0,0,1,.48,1.94c-24.69,6.1-35,12.6-35.1,12.66A1,1,0,0,1,57.76,133.34Z"/><path class="avatar-1-avatar-1-cls-13" d="M221.5,109.2h-.09c-6.83-.61-13.49-1-19.79-1.22a1,1,0,0,1-1-1,1,1,0,0,1,1-1c6.33.2,13,.62,19.89,1.23a1,1,0,0,1-.08,2Z"/><path class="avatar-1-avatar-1-cls-13" d="M152.57,112.24a1,1,0,0,1-.35-1.94c.46-.17,11.58-4.16,37.21-4.46a1,1,0,0,1,1,1,1,1,0,0,1-1,1c-25.23.3-36.44,4.3-36.55,4.34A1,1,0,0,1,152.57,112.24Z"/><path class="avatar-1-avatar-1-cls-13" d="M326.9,129.68a1,1,0,0,1-.34-.06c-6.54-2.35-12.95-4.47-19.06-6.29a1,1,0,0,1,.58-1.92c6.13,1.83,12.58,4,19.16,6.33a1,1,0,0,1-.34,1.94Z"/><path class="avatar-1-avatar-1-cls-13" d="M295.91,120.09a1,1,0,0,1-.24,0c-24.72-6.23-36.35-5.2-36.46-5.19a1,1,0,0,1-.2-2c.49,0,12.09-1.07,37.14,5.24a1,1,0,0,1-.24,2Z"/><path class="avatar-1-avatar-1-cls-13" d="M104,132.4a1,1,0,0,1-1-.8,1,1,0,0,1,.78-1.18c6.25-1.25,12.88-2.39,19.71-3.36a1,1,0,0,1,1.14.85,1,1,0,0,1-.85,1.13c-6.8,1-13.4,2.09-19.61,3.34A.65.65,0,0,1,104,132.4Z"/><path class="avatar-1-avatar-1-cls-13" d="M56.62,147.87a1,1,0,0,1-.84-.46,1,1,0,0,1,.3-1.38c.42-.27,10.64-6.73,35.71-12.92a1,1,0,0,1,1.21.73,1,1,0,0,1-.74,1.21c-24.74,6.11-35,12.6-35.1,12.66A1,1,0,0,1,56.62,147.87Z"/><path class="avatar-1-avatar-1-cls-13" d="M220.36,123.73h-.09c-6.83-.62-13.48-1-19.78-1.23a1,1,0,0,1-1-1,1,1,0,0,1,1-1c6.34.2,13,.62,19.9,1.23a1,1,0,0,1-.09,2Z"/><path class="avatar-1-avatar-1-cls-13" d="M151.43,126.77a1,1,0,0,1-.35-1.94c.47-.17,11.58-4.16,37.22-4.46h0a1,1,0,0,1,0,2c-25.29.3-36.43,4.3-36.54,4.34A1.07,1.07,0,0,1,151.43,126.77Z"/><path class="avatar-1-avatar-1-cls-13" d="M325.77,144.22a1,1,0,0,1-.34-.06c-6.54-2.36-12.95-4.48-19.06-6.3a1,1,0,0,1-.67-1.25,1,1,0,0,1,1.24-.67c6.14,1.84,12.59,4,19.16,6.33a1,1,0,0,1-.33,1.95Z"/><path class="avatar-1-avatar-1-cls-13" d="M294.77,134.62l-.24,0c-24.65-6.21-36.35-5.2-36.46-5.19a1,1,0,0,1-.19-2c.48,0,12.08-1.07,37.14,5.24a1,1,0,0,1-.25,2Z"/><path class="avatar-1-cls-8" d="M134.28,55.94a21.68,21.68,0,0,1,9.13,1c2.27.86,3.52,2,3.38,3s-1.6,1.81-3.74,2.36a52.83,52.83,0,0,1-8.1,1.2,52.47,52.47,0,0,1-8.19.23c-2.2-.16-3.76-.65-4.09-1.66s.7-2.36,2.79-3.59A21.52,21.52,0,0,1,134.28,55.94Z"/><path class="avatar-1-cls-8" d="M189.16,54c14.08.87,25.23,3.94,25,6s-11.61,2.48-25.44,1.63S163.63,59,163.64,56.91,175.09,53.15,189.16,54Z"/><path class="avatar-1-cls-3" d="M45,244.59l-2.18-6.77c-1.91-6-4.28-12.43-6.78-19.29-13.82-37.8-31-84.85,1.47-114.42C48.67,94,62.43,89.89,75.57,86.57c75.35-19,152.7-20.37,223.69-3.89C311.33,85.48,324.07,89,335.45,96c12.88,7.83,22.44,19.32,26.92,32.35,4.08,11.86,4.39,25.17.93,40.67h0a191.33,191.33,0,0,1-8,25.71l-.14.4c-10,26.58-13.67,38.62-13.77,40.85a3.89,3.89,0,0,0-1.28-2.7l-6.16,6.56C299.3,207.29,247.58,188.65,192,188.65S84.83,207.26,50.21,239.73ZM197.37,80.24A489.6,489.6,0,0,0,77.77,95.3c-12,3-24.58,6.73-34.17,15.47-28,25.5-12,69.4.92,104.68,1.65,4.52,3.25,8.88,4.7,13.07,36.12-31.14,87.71-48.87,142.8-48.87,54.72,0,106,17.49,142,48.22,1-3.25,2.37-7.53,4.18-12.73,2.27-6.56,5.11-14.37,8.44-23.22l.15-.39A184.81,184.81,0,0,0,354.52,167c3.08-13.83,2.87-25.54-.66-35.78-3.8-11.05-12-20.85-23.09-27.6-9.72-5.91-20.44-9.15-33.54-12.19A441.79,441.79,0,0,0,197.37,80.24ZM358.91,168h0Z"/><path class="avatar-1-cls-8" d="M316.3,283a85,85,0,0,1-.17-10.5c.2-2.77.72-4.63,1.76-4.88s2.37,1.22,3.57,3.91a35.67,35.67,0,0,1,1.44,22.17c-.84,2.82-2,4.45-3,4.34s-1.82-1.89-2.38-4.61A83.3,83.3,0,0,1,316.3,283Z"/><path class="avatar-1-cls-8" d="M310.41,253a8.45,8.45,0,0,1-.74-3.45,4,4,0,0,1,1-2.95,2.9,2.9,0,0,1,3.26-.34,7.5,7.5,0,0,1,3.8,8.75,2.92,2.92,0,0,1-2.48,2.15,4.08,4.08,0,0,1-2.87-1.26A8.5,8.5,0,0,1,310.41,253Z"/><path class="avatar-1-cls-8" d="M300.23,237.15c-1-1.27-.45-3.35,1.22-4.65s3.82-1.33,4.82-.06.44,3.36-1.23,4.66S301.22,238.42,300.23,237.15Z"/><path class="avatar-1-cls-8" d="M258.7,168A36.44,36.44,0,0,1,271.61,173c3,2,4.41,3.89,3.92,4.8s-2.75.81-6,.2-7.55-1.61-12.31-2.55-9.11-1.61-12.36-2.27-5.37-1.37-5.47-2.44,1.91-2.24,5.43-3A36.43,36.43,0,0,1,258.7,168Z"/><path class="avatar-1-cls-8" d="M296.63,182.34a5.05,5.05,0,0,1,2.82,2.8,3,3,0,0,1-.45,3,4.48,4.48,0,0,1-2.58,1.46,4.48,4.48,0,0,1-4.87-2,4.37,4.37,0,0,1-.75-2.87,3,3,0,0,1,1.85-2.44A5.05,5.05,0,0,1,296.63,182.34Z"/><path class="avatar-1-cls-8" d="M320.06,194.45a16.53,16.53,0,0,1,5.18,5.14c1,1.69,1.19,3.15.49,3.94s-2.13.8-3.88.28a28.09,28.09,0,0,1-11.07-7.19c-1.19-1.39-1.77-2.7-1.32-3.67s1.85-1.37,3.8-1.15A16.57,16.57,0,0,1,320.06,194.45Z"/><circle class="avatar-1-cls-3" cx="133.38" cy="300.14" r="22.91"/><circle class="avatar-1-cls-1" cx="143.6" cy="283.11" r="12.7"/><circle class="avatar-1-cls-8" cx="124.18" cy="308.69" r="5.28"/><circle class="avatar-1-cls-3" cx="239.38" cy="305.14" r="22.91"/><circle class="avatar-1-cls-1" cx="249.6" cy="288.11" r="12.7"/><circle class="avatar-1-cls-8" cx="230.18" cy="313.69" r="5.28"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/avatar-2.svg b/eims-ui/packages/icons/src/svg/icons/avatar-2.svg
new file mode 100644
index 0000000..8e17b0b
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/avatar-2.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 379.47 510.81"><defs><style>.avatar-2-cls-1{fill:#dfe7ea;}.avatar-2-cls-2{fill:#ceea57;}.avatar-2-cls-3{fill:#213346;}.avatar-2-cls-4{fill:#95bc4a;}.avatar-2-cls-5{fill:#bfe1ee;}.avatar-2-avatar-2-cls-11,.avatar-2-cls-6{fill:#fff;}.avatar-2-cls-7{fill:#f5a2c6;}.avatar-2-cls-8{fill:#d676a3;}.avatar-2-cls-9{fill:#f9637c;}.avatar-2-avatar-2-cls-10{fill:#cc3656;}.avatar-2-avatar-2-cls-11{opacity:0.5;}.avatar-2-avatar-2-cls-12{fill:#f6aecd;}.avatar-2-avatar-2-cls-13{fill:#86b9f8;}.avatar-2-avatar-2-cls-14{fill:#7662fa;}</style></defs><title>Asset 16</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><ellipse class="avatar-2-cls-1" cx="191.74" cy="457.95" rx="179.73" ry="52.86"/><circle class="avatar-2-cls-2" cx="334.64" cy="271.05" r="40.33"/><path class="avatar-2-cls-3" d="M334.64,314.49a44.83,44.83,0,1,1,44.83-44.83A44.88,44.88,0,0,1,334.64,314.49Zm0-80.66a35.83,35.83,0,1,0,35.83,35.83A35.87,35.87,0,0,0,334.64,233.83Z"/><path class="avatar-2-cls-3" d="M356.42,273.33a3,3,0,0,1-2.93-2.41c-3.92-19.6-23.82-16.39-24.67-16.24a3,3,0,0,1-1.05-5.91c9.15-1.63,27.53.65,31.6,21a3,3,0,0,1-2.35,3.53A3.05,3.05,0,0,1,356.42,273.33Z"/><circle class="avatar-2-cls-2" cx="44.83" cy="269.05" r="40.33"/><path class="avatar-2-cls-4" d="M76.23,244.43a40.32,40.32,0,0,0-55.79,55.79,40.33,40.33,0,1,1,55.79-55.79Z"/><path class="avatar-2-cls-3" d="M44.83,312.49a44.83,44.83,0,1,1,44.83-44.83A44.88,44.88,0,0,1,44.83,312.49Zm0-80.66a35.83,35.83,0,1,0,35.83,35.83A35.87,35.87,0,0,0,44.83,231.83Z"/><path class="avatar-2-cls-2" d="M188.76,62h2.72A142.34,142.34,0,0,1,333.82,204.34v92.6a143.7,143.7,0,0,1-143.7,143.7h0a143.7,143.7,0,0,1-143.7-143.7v-92.6A142.34,142.34,0,0,1,188.76,62Z"/><path class="avatar-2-cls-4" d="M208.37,437.76a143.43,143.43,0,0,1-19.77,1.37c-79,0-143.71-64.66-143.71-143.71V200.94c0-77.25,63.22-140.46,140.47-140.46h6.48a136.88,136.88,0,0,1,16.53,1C138.82,69.71,84.43,129.29,84.43,200.94v94.48C84.43,367.76,138.58,428.06,208.37,437.76Z"/><path class="avatar-2-cls-3" d="M188.6,445.15A148.62,148.62,0,0,1,40.39,296.94v-92.6A147.26,147.26,0,0,1,187.24,57.5H190A147.26,147.26,0,0,1,336.8,204.34v92.6A148.62,148.62,0,0,1,188.6,445.15ZM187.24,66.5A138.26,138.26,0,0,0,49.39,204.34v92.6a139,139,0,0,0,237.52,98.31,138.2,138.2,0,0,0,40.89-98.31v-92.6A138.24,138.24,0,0,0,190,66.5Z"/><path class="avatar-2-cls-5" d="M319.19,272.92v.18C318.65,273.12,318.86,273,319.19,272.92Z"/><path class="avatar-2-cls-3" d="M20.84,273.92a2.31,2.31,0,0,1-.37,0,3,3,0,0,1-2.61-3.34c1.7-13.89,7.61-20.76,12.26-24.07a20.44,20.44,0,0,1,10.38-4,3,3,0,0,1,.23,6c-.63,0-14.25,1.06-16.92,22.76A3,3,0,0,1,20.84,273.92Z"/><path class="avatar-2-cls-3" d="M190.57,306.5a3,3,0,0,1-3-3V256.91a3,3,0,1,1,6,0V303.5A3,3,0,0,1,190.57,306.5Z"/><path class="avatar-2-cls-6" d="M40.94,365.6c.72-3.5,2.66-5.94,4-5.52s1.67,3.31,1,6.55-2.1,5.77-3.51,5.62S40.22,369.1,40.94,365.6Z"/><path class="avatar-2-cls-6" d="M42.16,403.44a49.43,49.43,0,0,1-1.78-14.27c.14-3.7.8-5.95,1.48-6,1.47,0,2.43,8.7,5.23,18.9s6.3,18.17,5,18.93c-.59.34-2.31-1.26-4.31-4.37A48.78,48.78,0,0,1,42.16,403.44Z"/><path class="avatar-2-cls-7" d="M137.75,2.51a33.77,33.77,0,0,0-24.37,10.94,34,34,0,0,0-41.26,46,34,34,0,1,0,38.79,54.36,34,34,0,0,0,54.73-27.46c0-.39,0-.78-.06-1.17a34,34,0,1,0,7.68-66.91,34.46,34.46,0,0,0-5.87.62A33.92,33.92,0,0,0,137.75,2.51Z"/><path class="avatar-2-cls-8" d="M89.32,49.48a33.74,33.74,0,0,0,2.8,12.94,34,34,0,0,0,6.82,64,34.92,34.92,0,0,1-6.91.82A34,34,0,0,1,77.12,62.42a34,34,0,0,1,30.57-47.49,34.27,34.27,0,0,1,8.1.82A34,34,0,0,0,89.32,49.48Z"/><path class="avatar-2-cls-3" d="M86.42,130.69A38.47,38.47,0,0,1,66.54,59.3,38.47,38.47,0,0,1,102.61,9.43a38.62,38.62,0,0,1,9.42,1A38,38,0,0,1,137.67,0h0a38.68,38.68,0,0,1,31.88,16c1.2-.14,2.42-.22,3.63-.24a38.47,38.47,0,0,1,28.34,65.18,38.17,38.17,0,0,1-27,11.75,40.18,40.18,0,0,1-4.53-.19,38.46,38.46,0,0,1-58.66,29.07,38.09,38.09,0,0,1-24.22,9.13ZM103.29,18.42h-.53a29.45,29.45,0,0,0-28.94,30,29,29,0,0,0,2.43,11.22l1.75,4L74,65.5a29.47,29.47,0,1,0,33.65,47.16l2.8-2.92,3.2,2.48A29.45,29.45,0,0,0,161.14,88.4c0-.29,0-.58,0-.87l-.53-6.29,6.12,1.55a29.47,29.47,0,1,0,6.65-58.05,28.71,28.71,0,0,0-5.08.54l-3.08.6-1.63-2.68A29.59,29.59,0,0,0,137.83,9h0a29.21,29.21,0,0,0-21.14,9.5l-1.93,2.09L112,19.75A29.32,29.32,0,0,0,103.29,18.42ZM137.75,4.51h0Z"/><polygon class="avatar-2-cls-3" points="225.1 107.59 226.73 112.26 221.44 110.12 233.38 107.94 235.94 107.48 236.58 109.21 243.09 126.94 231.9 111.73 235.06 112.98 224.2 118.39 221.46 119.76 218.98 116.27 215.87 111.89 194.8 82.23 205.66 66.03 225.1 107.59"/><polygon class="avatar-2-cls-3" points="81.49 154.74 81.53 157.94 84.27 155.47 76.54 156.78 74.89 157.06 74.88 158.25 74.82 170.43 78.27 158.75 76.63 160.2 84.41 161.1 86.37 161.33 87.11 158.67 88.04 155.33 95.65 128.68 84.16 125.25 81.49 154.74"/><polygon class="avatar-2-cls-3" points="197.95 122.51 197.9 126.47 194.51 123.42 204.09 125.03 206.15 125.38 206.16 126.86 206.23 141.99 201.95 127.48 203.99 129.29 194.33 130.4 191.89 130.68 190.97 127.38 189.82 123.23 180.37 90.14 194.63 85.89 197.95 122.51"/><polygon class="avatar-2-cls-3" points="149.78 144.16 144.65 143.61 144.93 142.63 148.61 118.63 135.56 121.73 137.8 143.28 138.05 145.98 138.25 148.13 140.4 147.9 147.64 147.1 148.59 155.26 151.23 145.32 151.49 144.35 149.78 144.16"/><circle class="avatar-2-cls-3" cx="241.03" cy="227.35" r="41.06"/><rect class="avatar-2-cls-9" x="238.09" y="225.78" width="15.99" height="86.04" rx="6.5"/><path class="avatar-2-avatar-2-cls-10" d="M249.78,310.38a5.81,5.81,0,0,1-3.69,1.43c-4.42,0-8-5.69-8-12.71V238.48c0-7,3.58-12.7,8-12.7a5.8,5.8,0,0,1,3.69,1.42c-2.56,2.13-4.31,6.38-4.31,11.28V299.1C245.47,304,247.22,308.25,249.78,310.38Z"/><path class="avatar-2-cls-3" d="M246.09,314.81a11,11,0,0,1-11-11v-70a11,11,0,0,1,22,0v70A11,11,0,0,1,246.09,314.81Zm0-86a5,5,0,0,0-5,5v70a5,5,0,1,0,10,0v-70A5,5,0,0,0,246.09,228.78Z"/><path class="avatar-2-cls-6" d="M296.05,131.36a75.23,75.23,0,0,1,6,11c.74,1.78,1.43,3.47,1.95,5.11s1,3.16,1.31,4.57c1.35,5.68,1.2,9.35.22,9.6-2.16.52-6.69-12.4-15.84-26.1-9-13.81-19.06-23.07-17.73-24.84.61-.81,4.05.51,8.73,4,1.17.87,2.42,1.86,3.69,3s2.58,2.43,3.93,3.81A76.62,76.62,0,0,1,296.05,131.36Z"/><path class="avatar-2-cls-6" d="M313.3,178.31c.48,2.42-.82,4.71-2.89,5.12s-4.15-1.22-4.62-3.64.82-4.72,2.9-5.13S312.83,175.89,313.3,178.31Z"/><path class="avatar-2-cls-6" d="M317,202.62c.54,4.11-.73,7.66-2.82,7.94s-4.24-2.84-4.77-6.94.73-7.66,2.83-7.94S316.48,198.52,317,202.62Z"/><circle class="avatar-2-avatar-2-cls-11" cx="229.78" cy="343.53" r="5.28"/><path class="avatar-2-avatar-2-cls-12" d="M138,52.68a29,29,0,0,0-19.37-.87c-4.89,1.53-7.35,3.77-7.61,3.46-.11-.12.35-.84,1.49-1.84A19.53,19.53,0,0,1,118,50.11a27.32,27.32,0,0,1,9.38-1.92,29,29,0,0,1,11.56,2.13,27.34,27.34,0,0,1,9.7,6.66,27.9,27.9,0,0,1,5.25,8,23.39,23.39,0,0,1,1.74,6.16c.19,1.49.1,2.34-.06,2.36-.42.07-.9-3.21-3.31-7.74a30.26,30.26,0,0,0-5.31-7.14A27.38,27.38,0,0,0,138,52.68Z"/><path class="avatar-2-avatar-2-cls-12" d="M108.26,80.3a20.07,20.07,0,0,1,5.12-6.47,17.38,17.38,0,0,1,5.9-3.25,12.35,12.35,0,0,1,4.47-.59c1.06.08,1.62.29,1.61.45,0,.42-2.29.4-5.44,1.83a19,19,0,0,0-5,3.33,20.41,20.41,0,0,0-4.38,5.83,30,30,0,0,0-2.72,13.22c0,3.56.27,5.81-.11,5.89s-1.22-2.07-1.69-5.78a27.59,27.59,0,0,1,0-6.59A24.21,24.21,0,0,1,108.26,80.3Z"/><path class="avatar-2-avatar-2-cls-12" d="M140.43,20.33a25.58,25.58,0,0,1,7.06,2.46,15.34,15.34,0,0,1,4.81,3.92,8.61,8.61,0,0,1,1.76,3.83c.16,1,0,1.54-.14,1.56-.41.07-.75-2-3-4.19a16.3,16.3,0,0,0-4.52-3,28.82,28.82,0,0,0-6.48-2.05,20.5,20.5,0,0,0-6.69-.31,13.86,13.86,0,0,0-5.09,1.69c-2.71,1.55-3.75,3.39-4.09,3.2-.15-.07-.09-.63.35-1.52a9.55,9.55,0,0,1,2.73-3.17,13.55,13.55,0,0,1,5.72-2.52A19.9,19.9,0,0,1,140.43,20.33Z"/><path class="avatar-2-avatar-2-cls-12" d="M186.89,58.43a31.33,31.33,0,0,0,1.87-9.7,11.92,11.92,0,0,0-2.48-7.23,38.35,38.35,0,0,0-3.72-4.12c-.95-1-1.44-1.54-1.33-1.68s.8.18,2,.91a22.1,22.1,0,0,1,4.49,3.76,12.88,12.88,0,0,1,3.43,8.27,30.14,30.14,0,0,1-1.79,10.58,20.67,20.67,0,0,1-2.38,5.16,14,14,0,0,1-3.87,3.81,16.85,16.85,0,0,1-8.49,2.65,18,18,0,0,1-5.85-.68c-1.33-.39-2-.81-1.95-1,.1-.41,3,.43,7.63-.16a16.46,16.46,0,0,0,7.33-2.79A12.18,12.18,0,0,0,184.85,63,19.79,19.79,0,0,0,186.89,58.43Z"/><path class="avatar-2-avatar-2-cls-12" d="M85.1,87.16A13.11,13.11,0,0,1,81,78.56c-.12-2.47.54-3.89.85-3.83s.39,1.48.94,3.56A14,14,0,0,0,94.08,88.92c2.11.43,3.54.36,3.61.74s-1.3,1-3.78,1.06A13.1,13.1,0,0,1,85.1,87.16Z"/><path class="avatar-2-avatar-2-cls-12" d="M133,92.83a24.28,24.28,0,0,0,4.74-.43,20,20,0,0,0,2-.52,16.5,16.5,0,0,0,1.73-.6c2.1-.83,3.36-1.6,3.61-1.3s-.66,1.54-2.78,2.91a13.24,13.24,0,0,1-1.81,1,16.71,16.71,0,0,1-2.21.82,18.08,18.08,0,0,1-10.7-.22,16.23,16.23,0,0,1-2.18-.92,11.2,11.2,0,0,1-1.76-1c-2.06-1.46-2.88-2.81-2.66-3s1.49.54,3.55,1.46c.52.22,1.08.47,1.71.67s1.3.4,2,.6A24.26,24.26,0,0,0,133,92.83Z"/><path class="avatar-2-avatar-2-cls-12" d="M104.17,42.92a20.9,20.9,0,0,1,4-4,17.67,17.67,0,0,1,2.09-1.33,12.45,12.45,0,0,1,2-.9c2.48-.93,4.14-.86,4.19-.55s-1.36.94-3.41,2.17a17.51,17.51,0,0,0-1.62,1.08c-.58.38-1.13.88-1.74,1.37a23.08,23.08,0,0,0-6,8.07c-.29.72-.6,1.4-.8,2.06s-.4,1.29-.55,1.87c-.59,2.31-.7,3.86-1.09,3.89s-.86-1.53-.7-4.17a13.28,13.28,0,0,1,.3-2.13,16.39,16.39,0,0,1,.66-2.4A20.41,20.41,0,0,1,104.17,42.92Z"/><path class="avatar-2-avatar-2-cls-12" d="M163.78,45.73a23.94,23.94,0,0,0,1.71-3.89,22.19,22.19,0,0,0,.81-3.4c.32-2,.34-3.32.72-3.38s.95,1.21,1.09,3.46a14.52,14.52,0,0,1-.35,3.94A16.69,16.69,0,0,1,163,50.82a14.36,14.36,0,0,1-3.2,2.32c-2,1-3.43,1.14-3.54.85s1-1.06,2.54-2.35a22.65,22.65,0,0,0,2.5-2.45A23.79,23.79,0,0,0,163.78,45.73Z"/><path class="avatar-2-cls-6" d="M173.73,70.51a21.63,21.63,0,0,0,8.47-4.27c1.93-1.57,3-3,3.68-2.73.32.11.49.65.41,1.55a8.73,8.73,0,0,1-1.32,3.5,16.46,16.46,0,0,1-10,6.9,22.68,22.68,0,0,1-11.76-.33c-2.83-.87-4.37-1.93-4.22-2.6s2-.89,4.71-1A47.09,47.09,0,0,0,173.73,70.51Z"/><path class="avatar-2-cls-6" d="M186.07,51.39c.2-1.77,1.49-3.08,2.89-2.93s2.38,1.72,2.19,3.49-1.49,3.08-2.89,2.92S185.88,53.16,186.07,51.39Z"/><path class="avatar-2-cls-6" d="M183.86,41.8a2.6,2.6,0,0,1,4.14-3,2.61,2.61,0,0,1-4.14,3Z"/><path class="avatar-2-avatar-2-cls-13" d="M330,302c20.28,37,13.83,73.05,14.54,107.47l-11-12.15a118.62,118.62,0,0,1-28.8,57.47,42.38,42.38,0,0,0-13.34-14.7A89.09,89.09,0,0,1,263.9,487a35.8,35.8,0,0,0-1-29.59,56.4,56.4,0,0,1-30.8,34.29,23.17,23.17,0,0,0,2.52-22.37c-11.17,19-43.3,19.54-55.14,1-.82,3.75-.22,8.67,3.61,9-16.11,2.48-30.85-4.3-41.93-16.25a27.05,27.05,0,0,0,9,17.56,49.18,49.18,0,0,1-40.92-27.17c-20.77,1.29-41.53-12.94-47.8-32.79a9.91,9.91,0,0,1-2.59,9.51c-35.89-18.22-34-99.94-10.46-126.89,0,0,49.48,7.94,79.51,30.74,6.43,4.88,14.43-4.6,23.27-7.4,17.51-5.53,38.32-11.15,56.88-11.22,23.39-.1,35.9,29.56,50.89,15.49C298.57,293.65,329.64,301.39,330,302Z"/><path class="avatar-2-avatar-2-cls-14" d="M345.91,405.22l-11-12.16a118.76,118.76,0,0,1-28.81,57.48,42.3,42.3,0,0,0-13.34-14.7,89,89,0,0,1-27.51,46.89,35.83,35.83,0,0,0-1-29.59,56.4,56.4,0,0,1-30.8,34.29A23.2,23.2,0,0,0,236,465.06c-11.17,19-43.3,19.54-55.14,1-.83,3.75.11,17.55,3.94,17.87-16.1,2.48-31.18-13.18-42.26-25.13.64,6.7,2.31,18.78,7.36,23.23-17.16-.88-31.84-17.37-39.3-32.84-20.78,1.29-41.53-12.95-47.8-32.79a9.91,9.91,0,0,1-2.58,9.51c-12.41-6.3-20.59-20-25-36.31,15.87,11.57,34.55,19.51,53,26.63,12.54,4.82,25.24,9.42,38.46,11.83,12.82,2.33,25.92,2.56,39,2.79,36.17.62,73.84.94,106.53-14.59,9.37-4.45,19.26-12.08,18.93-22.46-.37-11.86-13.35-18.63-24.42-22.88,23.58-3.5,42.91-21.78,53.67-43.05a131.59,131.59,0,0,0,9.48-25.3L333,305C342.73,339,345.19,370.81,345.91,405.22Z"/><path class="avatar-2-cls-3" d="M253.41,500.93l7.73-18.34a31,31,0,0,0,2.25-14.75,61,61,0,0,1-28.12,25.32l-15.22,6.65,9.79-13.42a18.51,18.51,0,0,0,3.37-9.49,38.29,38.29,0,0,1-24.46,8.83,39.29,39.29,0,0,1-20.87-5.26c1,5.16.93,9.73-3.16,11.61l-1.89.86-1.88-.86c-13-6-23.27-12.19-31.89-19.33,1.42,5.57,3,7.6,3.8,8.31l9.71,8.53-12.91-.66c-18.37-.93-33.64-18.1-41.8-33.56-17.77,0-34.88-10-44.23-24.92l-.28.28L61,433l-2.87-1.46c-13.73-7-23.61-22.79-27.84-44.54-6.17-31.81.86-70.33,16-87.71a4.5,4.5,0,1,1,6.78,5.92c-13.31,15.26-19.57,51.18-14,80.07,3.26,16.82,10.08,29.4,19.38,36a5.07,5.07,0,0,0-.1-2.09l8.63-2.54c5.62,17.79,24.6,30.81,43.23,29.66l3-.19,1.31,2.72c7.38,15.29,17.47,24.65,26.45,28.73a83.68,83.68,0,0,1-3-16.73l-1.27-13.24,9.05,9.75c8.53,9.2,18.86,16.65,33,23.73-.31-1.46-.69-2.95-1-4-1.25-5-1.93-7.92-1.4-10.33l2.33-10.64,5.86,9.18c4.71,7.38,13.68,11.69,24,11.5s19.08-4.81,23.52-12.35l4.51-7.66,3.51,8.17a27.18,27.18,0,0,1,2,13.86A51.87,51.87,0,0,0,260,453.4l3.32-10.56,5,9.88a40,40,0,0,1,4.21,17.36,84.32,84.32,0,0,0,15.89-33.6l1.43-6.48,5.49,3.72a47,47,0,0,1,11.36,10.93,115.09,115.09,0,0,0,23.84-50.82l1.7-8.88,10,11.05c2-35.79-3.31-65-16.46-91.39a4.5,4.5,0,1,1,8-4C349,331,354.25,364.9,350.39,407.23l-.93,10.24-12.07-13.36a122.34,122.34,0,0,1-27.94,51.07l-4.26,4.65-3-5.53a37.69,37.69,0,0,0-6.81-9,93.54,93.54,0,0,1-27.08,42.37Z"/><path class="avatar-2-cls-2" d="M159.69,399.62a9.74,9.74,0,0,1-9.71-9.71V352.76a9.74,9.74,0,0,1,9.71-9.71h68a9.75,9.75,0,0,1,9.72,9.71v37.15a9.75,9.75,0,0,1-9.72,9.71"/><path class="avatar-2-cls-4" d="M239,356.81v11.52a9.75,9.75,0,0,0-8.91-5.85h-68a9.74,9.74,0,0,0-9.71,9.71v25.63a9.65,9.65,0,0,1-.81-3.87V356.81a9.75,9.75,0,0,1,9.71-9.72h68A9.76,9.76,0,0,1,239,356.81Z"/><path class="avatar-2-cls-3" d="M193.29,341.91c7,0,13.87,0,20.49.1l9.74.12,2.37,0,1.18,0h.33l.43,0,.85.06a14.26,14.26,0,0,1,6.29,2.29,14.06,14.06,0,0,1,6.23,10.73l0,.78v.65l0,1.07c0,.7,0,1.41-.05,2.11,0,1.39-.09,2.77-.13,4.12-.17,5.41-.37,10.45-.59,15s-.45,8.76-.71,12.42c0,.45-.07.9-.1,1.34,0,.22,0,.44-.05.66s-.05.52-.08.78a11.57,11.57,0,0,1-.74,3,11.41,11.41,0,0,1-3,4.24,9.64,9.64,0,0,1-6.23,2.57,4.68,4.68,0,0,1-1.7-.26c-.38-.14-.55-.3-.55-.46s.17-.34.49-.52l1.35-.66a10.23,10.23,0,0,0,3.89-3.22,8.51,8.51,0,0,0,1.34-3.09,8,8,0,0,0,.12-1.84l0-.5c0-.22,0-.44-.05-.66l-.09-1.34c-.26-3.66-.5-7.82-.72-12.42s-.41-9.63-.59-15c0-1.35-.08-2.73-.12-4.12l-.06-2.11,0-1.07v-.43l0-.3a5.41,5.41,0,0,0-4.95-4.71h-.73l-1.18,0-2.37,0-9.74.12c-6.62.06-13.47.1-20.49.1s-13.87,0-20.48-.1l-9.74-.12-2.38,0-1.18,0h-.73a5.42,5.42,0,0,0-4.94,4.71l0,.3,0,.16v.27l0,1.07c0,.7,0,1.41-.05,2.11,0,1.39-.09,2.77-.13,4.12-.17,5.41-.37,10.45-.59,15s-.46,8.76-.71,12.42c0,.45-.07.9-.1,1.34,0,.22,0,.44,0,.66l0,.5a7.43,7.43,0,0,0,.13,1.84,8.18,8.18,0,0,0,1.34,3.09,10.21,10.21,0,0,0,3.88,3.22l1.35.66c.32.18.5.35.5.52s-.18.32-.55.46A4.74,4.74,0,0,1,157,404a9.6,9.6,0,0,1-6.22-2.57,11.32,11.32,0,0,1-3-4.24,12,12,0,0,1-.74-3c0-.26-.06-.57-.08-.78s0-.44-.05-.66l-.09-1.34c-.26-3.66-.5-7.82-.72-12.42s-.41-9.63-.59-15c0-1.35-.08-2.73-.12-4.12l-.06-2.11,0-1.07v-.65l0-.78a14.08,14.08,0,0,1,6.22-10.73,14.31,14.31,0,0,1,6.29-2.29l.86-.06.43,0h.32l1.18,0,2.38,0,9.74-.12C179.42,342,186.28,341.91,193.29,341.91Z"/><path class="avatar-2-cls-3" d="M60.39,322a37.09,37.09,0,0,0,.47,9,37.78,37.78,0,0,0,2.92,8.91,39.35,39.35,0,0,1-5.49-8A40.74,40.74,0,0,1,55,322.37a44.5,44.5,0,0,1-1-10.27,49.21,49.21,0,0,1,.4-5.25,33.42,33.42,0,0,1,1.13-5.44l10,4.36a23.19,23.19,0,0,0-1.89,3.53,41.21,41.21,0,0,0-1.54,4A38.35,38.35,0,0,0,60.39,322Z"/><path class="avatar-2-cls-3" d="M75.3,330.15c.78,7.09,3.93,14.18,8.49,20.33A45.39,45.39,0,0,1,70,331.43,37.16,37.16,0,0,1,67.79,319,33.53,33.53,0,0,1,70.32,306l9.59,5.16C76.2,316,74.51,323.12,75.3,330.15Z"/><path class="avatar-2-cls-3" d="M102.41,335.48A49,49,0,0,0,109,355a51.46,51.46,0,0,1-11.83-18.14,54.08,54.08,0,0,1-3.61-22.51l10.73,1.85A45.78,45.78,0,0,0,102.41,335.48Z"/><path class="avatar-2-cls-3" d="M279.1,331.6a25.9,25.9,0,0,1-.28,8.41c-.49,2.14-1.22,3.39-1.88,3.33-1.37-.13-2-5.16-2.7-11.16s-1.3-11,0-11.49c.63-.2,1.64.84,2.61,2.8A25.74,25.74,0,0,1,279.1,331.6Z"/><path class="avatar-2-cls-3" d="M300.7,325.92a34.06,34.06,0,0,1-2.28,11.66c-1.17,2.83-2.4,4.35-3,4.13-1.32-.5.23-7.41.4-15.92s-.91-15.49.43-15.91c.62-.19,1.77,1.39,2.79,4.28A34.18,34.18,0,0,1,300.7,325.92Z"/><path class="avatar-2-cls-3" d="M323.44,322.4a51.55,51.55,0,0,1,.48,8.84,42.08,42.08,0,0,1-.84,7.17c-.86,4-2,6.32-2.66,6.19-1.41-.31-.09-10-1.83-21.5s-5.47-20.53-4.18-21.19c.58-.3,2.31,1.61,4.22,5.24a44.14,44.14,0,0,1,2.79,6.64A53.12,53.12,0,0,1,323.44,322.4Z"/><path class="avatar-2-cls-3" d="M68.8,420.47a39.61,39.61,0,0,1-.25-8.28,35.94,35.94,0,0,1,.5-3.58,25.93,25.93,0,0,1,.76-3c1.14-3.68,2.57-5.64,3.16-5.43s.45,2.52.24,6.05c0,.89-.12,1.85-.12,2.88s0,2.13,0,3.28a59.18,59.18,0,0,0,2.11,14.73c.33,1.1.6,2.17.94,3.14s.63,1.89.92,2.73c1.2,3.32,2,5.46,1.47,5.87s-2.43-1.11-4.56-4.32a23.37,23.37,0,0,1-1.57-2.71,33.94,33.94,0,0,1-1.49-3.3A40.12,40.12,0,0,1,68.8,420.47Z"/><path class="avatar-2-cls-3" d="M99.55,433.75a50.42,50.42,0,0,1-.07-13.35c.45-3.36,1.12-5.4,1.79-5.39s1.24,2.09,1.67,5.4.77,7.81,1.45,12.64c.35,2.41.78,4.67,1.25,6.7.27,1,.47,2,.76,2.85l.38,1.3c.14.41.27.8.39,1.18,1,3,1.81,4.94,1.24,5.37s-2.36-.88-4.34-3.84c-.24-.37-.49-.77-.74-1.18s-.46-.87-.7-1.33a28,28,0,0,1-1.31-3.05A39.4,39.4,0,0,1,99.55,433.75Z"/><path class="avatar-2-cls-3" d="M136.2,440.16c-4-14.35-4.59-26.51-3.28-26.67s4.05,11.36,8,25.35,7.6,25.27,6.32,25.82S140.2,454.53,136.2,440.16Z"/><path class="avatar-2-cls-3" d="M244.41,451.81c1.82-6.05,3.09-11.74,4.22-15.84s2.08-6.65,2.75-6.55.91,2.79.66,7.11a75.23,75.23,0,0,1-2.94,16.7,56.28,56.28,0,0,1-3.52,8.82c-.71,1.29-1.35,2.52-2.1,3.61-.37.54-.71,1.07-1.06,1.56l-1.08,1.38c-2.84,3.46-5.24,4.92-5.69,4.49s.9-2.74,2.8-6.4c.24-.45.48-.93.74-1.43l.74-1.58c.54-1.08,1-2.29,1.55-3.52C242.49,457.64,243.49,454.83,244.41,451.81Z"/><path class="avatar-2-cls-3" d="M273,440.9c1.29-7.37,2-14.28,2.87-19.27s1.74-8,2.41-8,1,3.21,1,8.27a116.76,116.76,0,0,1-1.5,19.83,57.15,57.15,0,0,1-2.95,10.79,40,40,0,0,1-4.24,8.17c-3,4.36-5.79,6.2-6.23,5.76s1.21-3.06,3.23-7.47a65,65,0,0,0,3-7.94A85.72,85.72,0,0,0,273,440.9Z"/><path class="avatar-2-cls-3" d="M301.86,422.49c1.43-6,2.41-11.53,3.33-15.56s1.76-6.53,2.43-6.46,1,2.67,1,6.86a74.69,74.69,0,0,1-2,16.31,56.91,56.91,0,0,1-2.88,8.73c-.61,1.29-1.15,2.53-1.8,3.62-.31.55-.6,1.09-.91,1.59l-.95,1.41c-2.48,3.54-4.67,5.16-5.16,4.77s.59-2.76,2.14-6.45l.6-1.45q.3-.76.6-1.59c.45-1.08.82-2.28,1.26-3.51C300.32,428.25,301.13,425.46,301.86,422.49Z"/><path class="avatar-2-cls-3" d="M311.64,413.48c1.55-3.78,2.81-7.46,3.86-10.85.48-1.71,1-3.33,1.35-4.87s.75-3,1.06-4.28c1.21-5.28,1.85-8.64,2.57-8.62s1.22,3.49.85,9.12c-.1,1.41-.23,2.95-.5,4.59s-.58,3.38-1,5.21a72.61,72.61,0,0,1-9.28,22.38c-1,1.56-2,3-3,4.36s-2,2.53-2.89,3.59c-3.73,4.24-6.6,6.27-7.06,5.84s1.41-3.32,4.28-7.9c.72-1.15,1.51-2.4,2.29-3.78s1.62-2.84,2.49-4.39C308.34,420.75,310.06,417.25,311.64,413.48Z"/><path class="avatar-2-cls-6" d="M42.94,339.6c.72-3.5,2.66-5.94,4-5.52s1.67,3.31,1,6.55-2.1,5.77-3.51,5.62S42.22,343.1,42.94,339.6Z"/><path class="avatar-2-cls-6" d="M44.16,377.44a49.43,49.43,0,0,1-1.78-14.27c.14-3.7.8-5.95,1.48-6,1.47,0,2.43,8.7,5.23,18.9s6.3,18.17,5,18.93c-.59.34-2.31-1.26-4.31-4.37A48.78,48.78,0,0,1,44.16,377.44Z"/><path class="avatar-2-cls-3" d="M128.52,338.8H128c-5-.18-8.88-3.13-12-5.51l-.19-.14a150.17,150.17,0,0,0-65.16-28.23A4.5,4.5,0,0,1,52.19,296,159.48,159.48,0,0,1,121.27,326l.19.15c2.35,1.77,4.77,3.61,6.9,3.69s4.58-1.53,7.15-3.22l.75-.49c14.75-9.64,33.89-14.95,53.9-14.95h0c20,0,39.15,5.31,53.9,14.95l.74.48c2.58,1.7,5,3.3,7.15,3.23s4.56-1.92,6.9-3.69l.19-.15A159.59,159.59,0,0,1,328.13,296a4.5,4.5,0,0,1,1.52,8.88,150.17,150.17,0,0,0-65.16,28.23l-.19.14c-3.13,2.38-7,5.33-12,5.51s-9.12-2.53-12.42-4.7l-.71-.47c-27.47-17.94-70.5-17.94-98,0l-.72.47C137.27,336.2,133.32,338.8,128.52,338.8Z"/><path class="avatar-2-cls-3" d="M210.09,385.31h-36a3.5,3.5,0,1,1,0-7h36a3.5,3.5,0,0,1,0,7Z"/><circle class="avatar-2-avatar-2-cls-14" cx="256.32" cy="340.31" r="34.5"/><circle class="avatar-2-cls-6" cx="246.03" cy="330.35" r="40.04"/><circle class="avatar-2-avatar-2-cls-11" cx="250.78" cy="312.53" r="5.28"/><polygon class="avatar-2-cls-3" points="141.26 29.28 141.29 32.05 143.66 29.92 136.97 31.05 135.54 31.29 135.53 32.32 135.48 42.88 138.47 32.75 137.05 34.01 143.79 34.79 145.49 34.99 146.13 32.68 146.93 29.79 152.37 10.18 143.58 3.72 141.26 29.28"/><polygon class="avatar-2-cls-3" points="131.05 92.41 129.84 89.02 133.69 90.55 125.03 92.19 123.17 92.54 122.7 91.28 117.89 78.43 126.08 89.43 123.78 88.53 131.65 84.56 133.64 83.55 135.46 86.07 137.73 89.24 153.18 110.69 145.37 122.52 131.05 92.41"/><circle class="avatar-2-cls-3" cx="123.96" cy="232.98" r="22.91"/><circle class="avatar-2-cls-2" cx="134.18" cy="215.95" r="12.7"/><circle class="avatar-2-cls-6" cx="114.77" cy="241.53" r="5.28"/><circle class="avatar-2-cls-3" cx="242.84" cy="330.2" r="15.77"/><circle class="avatar-2-cls-6" cx="255.89" cy="340.77" r="10.18"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/avatar-3.svg b/eims-ui/packages/icons/src/svg/icons/avatar-3.svg
new file mode 100644
index 0000000..ca79178
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/avatar-3.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 391.79 532.35"><defs><style>.avatar-3-cls-1{fill:#f9cdb7;}.avatar-3-cls-2{fill:#e2a78d;}.avatar-3-cls-3{fill:#213346;}.avatar-3-cls-4{fill:#bfe1ee;}.avatar-3-cls-5{fill:#dfe7ea;}.avatar-3-cls-6{fill:#e99a4f;}.avatar-3-cls-7{fill:#ce7149;}.avatar-3-cls-8,.avatar-3-cls-9{fill:#fff;}.avatar-3-cls-9{opacity:0.5;}</style></defs><title>Asset 17</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><circle class="avatar-3-cls-1" cx="345.9" cy="275.59" r="41.4"/><path class="avatar-3-cls-2" d="M333.5,312.37a41.4,41.4,0,1,0,0-79.56,41.41,41.41,0,0,1,0,79.56Z"/><circle class="avatar-3-cls-1" cx="45.9" cy="275.59" r="41.4"/><path class="avatar-3-cls-2" d="M55.4,314.37a41.4,41.4,0,1,1,0-79.56,41.41,41.41,0,0,0,0,79.56Z"/><path class="avatar-3-cls-3" d="M45.9,320.06a45.9,45.9,0,1,1,45.89-45.9A46,46,0,0,1,45.9,320.06Zm0-82.79a36.9,36.9,0,1,0,36.89,36.89A36.94,36.94,0,0,0,45.9,237.27Z"/><path class="avatar-3-cls-3" d="M21.27,281a3.1,3.1,0,0,1-.43,0,3.51,3.51,0,0,1-3.05-3.9c1.77-14.41,7.92-21.55,12.76-25a21.46,21.46,0,0,1,10.88-4.14,3.5,3.5,0,0,1,.28,7c-.65,0-14.28,1.11-17,23A3.5,3.5,0,0,1,21.27,281Z"/><path class="avatar-3-cls-3" d="M33.65,288.21a3.88,3.88,0,0,1-.82-.09,3.5,3.5,0,0,1-2.59-4.22,32.88,32.88,0,0,0,1-11.59,14.61,14.61,0,0,0-4.4-9.21,3.5,3.5,0,1,1,4.65-5.23,21.52,21.52,0,0,1,6.69,13.58,39.36,39.36,0,0,1-1.16,14.07A3.5,3.5,0,0,1,33.65,288.21Z"/><path class="avatar-3-cls-3" d="M345.9,320.06a45.9,45.9,0,1,1,45.89-45.9A46,46,0,0,1,345.9,320.06Zm0-82.79a36.9,36.9,0,1,0,36.89,36.89A36.94,36.94,0,0,0,345.9,237.27Z"/><path class="avatar-3-cls-3" d="M370.52,281a3.5,3.5,0,0,1-3.47-3.07c-2.69-21.94-16.39-23-17-23a3.52,3.52,0,0,1-3.32-3.66,3.47,3.47,0,0,1,3.6-3.34,21.46,21.46,0,0,1,10.88,4.14c4.85,3.45,11,10.59,12.76,25A3.5,3.5,0,0,1,371,281,3,3,0,0,1,370.52,281Z"/><path class="avatar-3-cls-3" d="M358.15,288.21a3.49,3.49,0,0,1-3.4-2.69,39.2,39.2,0,0,1-1.17-14.08,21.56,21.56,0,0,1,6.69-13.57,3.5,3.5,0,1,1,4.66,5.23,14.56,14.56,0,0,0-4.4,9.21,32.42,32.42,0,0,0,1,11.59,3.52,3.52,0,0,1-2.6,4.22A3.72,3.72,0,0,1,358.15,288.21Z"/><path class="avatar-3-cls-1" d="M196.57,61h2.79a146.1,146.1,0,0,1,146.1,146.1v95A147.5,147.5,0,0,1,198,449.67h0a147.5,147.5,0,0,1-147.5-147.5v-95A146.1,146.1,0,0,1,196.57,61Z"/><path class="avatar-3-cls-2" d="M216.7,446.7a147.74,147.74,0,0,1-20.29,1.41c-81.14,0-147.5-66.37-147.5-147.5v-97c0-79.3,64.87-144.18,144.17-144.18h6.65a142.14,142.14,0,0,1,17,1C152.26,68.11,96.42,126.84,86.17,192.3a509.6,509.6,0,0,1-13.33,61.87L59.49,300.61C59.49,374.86,145.07,436.74,216.7,446.7Z"/><path class="avatar-3-cls-3" d="M196.41,454.17a152.43,152.43,0,0,1-152-152V207.12A151,151,0,0,1,195,56.52h2.79a151,151,0,0,1,150.61,150.6v95.05a152.45,152.45,0,0,1-152,152ZM195,65.52a142,142,0,0,0-141.6,141.6v95.05a143.43,143.43,0,0,0,143,143h0a143.43,143.43,0,0,0,143-143V207.12A142,142,0,0,0,197.8,65.52Z"/><path class="avatar-3-cls-4" d="M330.44,277.5v.2C329.89,277.72,330.11,277.59,330.44,277.5Z"/><ellipse class="avatar-3-cls-5" cx="189.64" cy="471.35" rx="179.73" ry="52.86"/><path class="avatar-3-cls-6" d="M340.74,325.56c21.15,38.59,14.42,76.21,15.16,112.11L344.45,425A123.67,123.67,0,0,1,314.4,485a44.13,44.13,0,0,0-13.92-15.33,92.89,92.89,0,0,1-28.69,48.92,37.34,37.34,0,0,0-1.06-30.87,58.87,58.87,0,0,1-32.13,35.77,24.22,24.22,0,0,0,2.63-23.34c-11.66,19.79-45.18,20.39-57.53,1-.86,3.91-.23,9.05,3.76,9.38-16.8,2.59-32.18-4.49-43.74-16.95a28.25,28.25,0,0,0,9.37,18.32,51.33,51.33,0,0,1-42.69-28.35c-21.68,1.35-43.33-13.5-49.87-34.21a10.36,10.36,0,0,1-2.7,9.92C20.38,440.24,22.38,355,46.91,326.87c0,0,51.63,8.28,83,32.07,20,15.18,54.48-19.31,83.62-19.43,24.41-.11,37.46,30.85,53.1,16.16C308,316.82,340.38,324.9,340.74,325.56Z"/><path class="avatar-3-cls-7" d="M357.35,433.22,345.9,420.54a123.83,123.83,0,0,1-30,60,44.26,44.26,0,0,0-13.92-15.34,92.85,92.85,0,0,1-28.69,48.92,37.38,37.38,0,0,0-1.06-30.87A58.84,58.84,0,0,1,240.05,519a24.22,24.22,0,0,0,2.63-23.33c-11.66,19.79-45.18,20.39-57.53,1-.87,3.92.11,18.31,4.11,18.65-16.8,2.58-32.53-13.75-44.09-26.22.67,7,2.41,19.59,7.68,24.23-17.9-.91-33.22-18.12-41-34.26-21.68,1.35-43.33-13.5-49.87-34.21a10.38,10.38,0,0,1-2.7,9.93C46.34,448.23,37.8,434,33.19,416.91,49.75,429,69.24,437.27,88.51,444.7c13.08,5,26.33,9.83,40.12,12.34,13.38,2.43,27.05,2.67,40.65,2.91,37.73.65,77,1,111.14-15.22,9.78-4.65,20.09-12.6,19.75-23.43-.39-12.38-13.93-19.44-25.48-23.87,24.6-3.65,44.78-22.73,56-44.92a136.88,136.88,0,0,0,9.89-26.39l3.31,2.58C354,364.15,356.61,397.32,357.35,433.22Z"/><path class="avatar-3-cls-6" d="M180.3,341l-49.84,18.58-82-37.21a62.33,62.33,0,0,0-12.09,21.43A237,237,0,0,1,86,361.31a244.47,244.47,0,0,1,22.74,12.33c4,2.46,12.45,10.51,17.42,9.89a10.29,10.29,0,0,0,4.12-1.85c45.61-29.33,79.08-30.62,132.55-21.06L237.74,346Z"/><path class="avatar-3-cls-3" d="M261.36,532.35,269.09,514a32.54,32.54,0,0,0,2.3-16.08,63.44,63.44,0,0,1-29.54,26.86l-15.22,6.65L236.41,518A19.55,19.55,0,0,0,240,507.55c-6.64,5.87-15.71,9.29-25.74,9.47a40.79,40.79,0,0,1-22.06-5.69c1.1,5.49,1.16,10.38-3.1,12.33l-1.88.87-1.88-.87c-13.79-6.36-24.61-12.91-33.69-20.51,1.53,6.3,3.28,8.56,4.17,9.34l9.71,8.53-12.91-.66c-19.13-1-35-18.9-43.5-35h-.06c-18.58,0-36.48-10.43-46.17-26.13l-.47.48L60.12,462l-2.88-1.46C43,453.25,32.7,436.8,28.31,414.16,21.88,381,29.19,340.91,45,322.83a4.5,4.5,0,1,1,6.78,5.92c-14.15,16.22-20.57,53-14.61,83.7,3.45,17.74,10.68,31,20.55,37.85a5.39,5.39,0,0,0-.06-2.56l8.64-2.54c5.89,18.64,25.8,32.28,45.3,31.07l3-.19,1.32,2.73C123.72,495,134.47,504.86,144,509a85.81,85.81,0,0,1-3.29-17.82L139.42,478l9.05,9.75c9,9.69,19.89,17.53,34.83,25-.35-1.64-.78-3.38-1.09-4.62-1.3-5.17-2-8.22-1.46-10.69l2.33-10.64,5.86,9.18c4.95,7.76,14.36,12.28,25.15,12.09s20-5,24.71-13l4.51-7.66,3.5,8.17a28.27,28.27,0,0,1,2,14.82,54.35,54.35,0,0,0,19.11-26.83L271.21,473l5,9.89a41.62,41.62,0,0,1,4.38,18.57,88.11,88.11,0,0,0,16.95-35.57l1.43-6.48,5.49,3.73a48.76,48.76,0,0,1,11.95,11.55,120.21,120.21,0,0,0,25.08-53.29l1.69-8.89,10.47,11.59c2.16-37.59-3.37-68.28-17.17-95.91a4.5,4.5,0,1,1,8-4c15.83,31.7,21.33,67,17.31,111.15l-.93,10.24-12.53-13.87a127.51,127.51,0,0,1-29.2,53.55l-4.26,4.65-3-5.54a39.94,39.94,0,0,0-7.38-9.62,97.41,97.41,0,0,1-28.29,44.41Z"/><path class="avatar-3-cls-1" d="M163.08,427.38a10.16,10.16,0,0,1-10.14-10.13V378.49a10.17,10.17,0,0,1,10.14-10.14H234a10.17,10.17,0,0,1,10.13,10.14v38.76A10.16,10.16,0,0,1,234,427.38"/><path class="avatar-3-cls-2" d="M245.85,382.71v12a10.15,10.15,0,0,0-9.29-6.1H165.61a10.16,10.16,0,0,0-10.14,10.13V425.5a10.1,10.1,0,0,1-.84-4V382.71a10.16,10.16,0,0,1,10.13-10.13h71A10.16,10.16,0,0,1,245.85,382.71Z"/><path class="avatar-3-cls-3" d="M198.13,367.18c7.32,0,14.47,0,21.37.1l10.16.12,2.48,0,1.23,0h.34l.45,0,.89.06a14.83,14.83,0,0,1,6.56,2.4,14.65,14.65,0,0,1,6.5,11.19l0,.81v.68l0,1.11L248,386c0,1.45-.08,2.89-.13,4.3-.18,5.64-.38,10.9-.61,15.69s-.48,9.14-.75,12.95c0,.48-.06.95-.1,1.41,0,.23,0,.46,0,.68s-.05.55-.08.81a12.57,12.57,0,0,1-.77,3.1,12,12,0,0,1-3.1,4.42A10.12,10.12,0,0,1,236,432a4.84,4.84,0,0,1-1.78-.27c-.39-.15-.58-.31-.58-.49s.19-.35.52-.54l1.41-.68a10.84,10.84,0,0,0,4.06-3.37,8.74,8.74,0,0,0,1.39-3.21,8.13,8.13,0,0,0,.13-1.92l0-.53c0-.22,0-.45-.05-.68,0-.46-.07-.93-.1-1.41-.27-3.81-.52-8.15-.74-12.95s-.44-10.05-.62-15.69c0-1.41-.09-2.85-.13-4.3l-.06-2.21,0-1.11v-.28l0-.16,0-.32a5.7,5.7,0,0,0-2.72-4.14,5.59,5.59,0,0,0-2.44-.77h-.76l-1.23,0-2.48,0-10.16.12c-6.9.07-14.05.11-21.37.11s-14.47,0-21.37-.11L166.59,377l-2.47,0-1.23,0h-.76a5.59,5.59,0,0,0-2.44.77,5.7,5.7,0,0,0-2.72,4.14l0,.32,0,.16v.28l0,1.11-.06,2.21c0,1.45-.09,2.89-.13,4.3-.18,5.64-.39,10.9-.62,15.69s-.47,9.14-.74,12.95c0,.48-.07.95-.1,1.41,0,.23,0,.46,0,.68l0,.53a8.13,8.13,0,0,0,.13,1.92,8.58,8.58,0,0,0,1.39,3.21,10.69,10.69,0,0,0,4.06,3.37l1.4.68c.34.19.52.37.52.54s-.18.34-.57.49a4.84,4.84,0,0,1-1.78.27,10.14,10.14,0,0,1-6.5-2.68,12,12,0,0,1-3.09-4.42,12.57,12.57,0,0,1-.77-3.1c0-.26-.07-.59-.08-.81l-.06-.68c0-.46-.06-.93-.1-1.41-.26-3.81-.51-8.15-.74-12.95s-.43-10.05-.61-15.69c0-1.41-.09-2.85-.13-4.3,0-.73-.05-1.47-.07-2.21l0-1.11V382l0-.81a14.74,14.74,0,0,1,13.06-13.59l.89-.06.45,0h.34l1.23,0,2.47,0,10.17-.12C183.66,367.21,190.81,367.18,198.13,367.18Z"/><path class="avatar-3-cls-3" d="M59.48,346.35a37.83,37.83,0,0,0,.49,9.41,39.45,39.45,0,0,0,3,9.29,40.75,40.75,0,0,1-5.73-8.37,42.54,42.54,0,0,1-3.46-9.9,46.05,46.05,0,0,1-1-10.71,50.92,50.92,0,0,1,.42-5.48,35.69,35.69,0,0,1,1.17-5.68l10.41,4.56a24.7,24.7,0,0,0-2,3.68,43.89,43.89,0,0,0-1.6,4.2A39.74,39.74,0,0,0,59.48,346.35Z"/><path class="avatar-3-cls-3" d="M75,354.9c.81,7.4,4.1,14.8,8.86,21.21a47.35,47.35,0,0,1-14.38-19.87,38.82,38.82,0,0,1-2.31-12.95,35.09,35.09,0,0,1,2.63-13.62l10,5.38C76,340.17,74.21,347.57,75,354.9Z"/><path class="avatar-3-cls-3" d="M103.32,360.47a51,51,0,0,0,6.84,20.32,54,54,0,0,1-12.35-18.93A56.65,56.65,0,0,1,94,338.38l11.2,1.92A47.79,47.79,0,0,0,103.32,360.47Z"/><path class="avatar-3-cls-3" d="M287.66,356.41a26.93,26.93,0,0,1-.31,8.78c-.5,2.23-1.26,3.53-2,3.48-1.43-.15-2-5.39-2.82-11.65s-1.36-11.51,0-12c.66-.22,1.71.87,2.72,2.91A27,27,0,0,1,287.66,356.41Z"/><path class="avatar-3-cls-3" d="M310.19,350.49a35.36,35.36,0,0,1-2.39,12.16c-1.21,3-2.49,4.54-3.14,4.31-1.37-.52.25-7.73.42-16.61s-.95-16.16.45-16.6c.65-.19,1.85,1.45,2.91,4.47A35.62,35.62,0,0,1,310.19,350.49Z"/><path class="avatar-3-cls-3" d="M333.91,346.82a53,53,0,0,1,.5,9.22,44.45,44.45,0,0,1-.88,7.48c-.89,4.19-2.12,6.59-2.77,6.45-1.47-.31-.09-10.37-1.91-22.42s-5.7-21.42-4.36-22.11c.6-.31,2.41,1.68,4.41,5.46a46.7,46.7,0,0,1,2.91,6.93A56.29,56.29,0,0,1,333.91,346.82Z"/><path class="avatar-3-cls-3" d="M68.25,449.13a41,41,0,0,1-.26-8.64,36.07,36.07,0,0,1,.52-3.73,28.41,28.41,0,0,1,.79-3.18c1.19-3.83,2.68-5.88,3.3-5.66s.47,2.63.25,6.32c0,.92-.12,1.92-.13,3s0,2.22,0,3.41a68.87,68.87,0,0,0,.61,7.76A75.5,75.5,0,0,0,74.89,456c.34,1.15.63,2.26,1,3.27s.66,2,1,2.85c1.24,3.47,2.14,5.7,1.53,6.13s-2.54-1.16-4.76-4.51A26.15,26.15,0,0,1,72,460.94a35.74,35.74,0,0,1-1.55-3.44A41.24,41.24,0,0,1,68.25,449.13Z"/><path class="avatar-3-cls-3" d="M100.32,463a52.94,52.94,0,0,1-.06-13.92c.47-3.51,1.17-5.64,1.87-5.63s1.28,2.19,1.74,5.63.8,8.16,1.51,13.2c.37,2.51.82,4.86,1.3,7,.29,1,.5,2.06.8,3q.19.7.39,1.35l.41,1.23c1,3.14,1.89,5.16,1.29,5.61s-2.46-.92-4.52-4l-.78-1.23c-.25-.43-.48-.9-.73-1.39a31.63,31.63,0,0,1-1.37-3.18A41.46,41.46,0,0,1,100.32,463Z"/><path class="avatar-3-cls-3" d="M138.57,469.67c-4.22-15-4.79-27.65-3.43-27.82s4.23,11.85,8.35,26.45,7.93,26.36,6.6,26.93S142.74,484.66,138.57,469.67Z"/><path class="avatar-3-cls-3" d="M251.46,481.82c1.89-6.31,3.22-12.24,4.4-16.52s2.17-6.94,2.88-6.83.94,2.91.68,7.41a78.07,78.07,0,0,1-3.07,17.43,59.38,59.38,0,0,1-3.67,9.2,42.39,42.39,0,0,1-2.2,3.76c-.37.57-.73,1.13-1.1,1.64l-1.13,1.43c-3,3.61-5.46,5.14-5.93,4.69s.94-2.87,2.92-6.68c.25-.47.5-1,.77-1.49l.78-1.65c.56-1.12,1-2.39,1.62-3.67C249.45,487.91,250.5,485,251.46,481.82Z"/><path class="avatar-3-cls-3" d="M281.25,470.44c1.34-7.68,2-14.9,3-20.1s1.81-8.37,2.51-8.31,1.07,3.35,1.08,8.62a122.32,122.32,0,0,1-1.55,20.69,60.77,60.77,0,0,1-3.08,11.26,42.45,42.45,0,0,1-4.42,8.53c-3.14,4.54-6,6.46-6.51,6s1.27-3.2,3.37-7.8a68.21,68.21,0,0,0,3.11-8.29A89.28,89.28,0,0,0,281.25,470.44Z"/><path class="avatar-3-cls-3" d="M311.39,451.23c1.49-6.22,2.52-12,3.48-16.23s1.83-6.81,2.54-6.73,1.08,2.78,1,7.15a78.88,78.88,0,0,1-2.11,17,58.26,58.26,0,0,1-3,9.11c-.63,1.35-1.19,2.63-1.87,3.78-.33.57-.63,1.13-1,1.65l-1,1.47c-2.59,3.69-4.87,5.39-5.38,5s.61-2.87,2.22-6.72c.2-.48.42-1,.64-1.51s.41-1.08.62-1.66c.47-1.12.85-2.38,1.32-3.67C309.79,457.25,310.63,454.34,311.39,451.23Z"/><path class="avatar-3-cls-3" d="M321.6,441.84c1.61-3.95,2.93-7.79,4-11.33.5-1.78,1-3.46,1.41-5.07s.78-3.1,1.1-4.47c1.26-5.5,1.93-9,2.68-9s1.27,3.64.89,9.52c-.1,1.46-.24,3.07-.52,4.78s-.61,3.53-1,5.44a76,76,0,0,1-9.69,23.34c-1.07,1.63-2.07,3.19-3.13,4.56s-2.05,2.64-3,3.74c-3.89,4.43-6.89,6.55-7.37,6.09s1.47-3.46,4.47-8.24c.75-1.2,1.57-2.5,2.39-3.94s1.69-3,2.6-4.58C318.16,449.42,320,445.77,321.6,441.84Z"/><path class="avatar-3-cls-8" d="M41.38,364.78c.75-3.65,2.73-6.2,4.07-5.78s1.62,3.43.93,6.81-2.14,6-3.55,5.89S40.63,368.42,41.38,364.78Z"/><path class="avatar-3-cls-8" d="M42.64,404.21a53,53,0,0,1-1.88-14.87c.13-3.85.79-6.2,1.47-6.2,1.47,0,2.42,9.08,5.35,19.74s6.63,19,5.37,19.72c-.59.34-2.36-1.34-4.42-4.6A51.58,51.58,0,0,1,42.64,404.21Z"/><path class="avatar-3-cls-3" d="M130.55,363.73h-.49c-5.14-.18-9.18-3.24-12.42-5.71l-.2-.15a157,157,0,0,0-68.07-29.49,4.5,4.5,0,0,1,1.52-8.87,166.07,166.07,0,0,1,72,31.19l.2.15c2.46,1.87,5,3.8,7.3,3.89s4.87-1.61,7.58-3.4l.77-.5c15.36-10,35.29-15.56,56.13-15.56h0c20.83,0,40.77,5.52,56.13,15.56l.77.5c2.71,1.79,5.25,3.48,7.58,3.4s4.84-2,7.3-3.89l.2-.15a166.07,166.07,0,0,1,72-31.19,4.5,4.5,0,0,1,1.52,8.87,157,157,0,0,0-68.07,29.49l-.2.15c-3.24,2.46-7.28,5.53-12.42,5.71s-9.43-2.62-12.85-4.87l-.74-.49c-28.72-18.76-73.71-18.76-102.43,0l-.74.49C139.6,361,135.5,363.73,130.55,363.73Z"/><path class="avatar-3-cls-3" d="M195.39,318.4a3.5,3.5,0,0,1-3.5-3.5V268.31a3.5,3.5,0,0,1,7,0V314.9A3.5,3.5,0,0,1,195.39,318.4Z"/><path class="avatar-3-cls-2" d="M209.25,194.71c-1.68,7.42-1.08,17.32,4.13,23.31,6.07,7,15.65,5.56,23.92,5.22a103.26,103.26,0,0,1,30,3.06c8,2,15.14,6.95,23.27,8.36,8.91,1.55,11-3.19,5.06-9.72-6.94-7.66-17-15.81-26.44-20.25a118.77,118.77,0,0,0-59.61-10.31"/><path class="avatar-3-cls-6" d="M210.19,183.79c-1.68,7.41-1.09,17.31,4.12,23.3,6.07,7,15.65,5.57,23.92,5.22a103.23,103.23,0,0,1,30,3.07c8,2.05,15.15,6.94,23.27,8.36,8.91,1.55,11-3.2,5.07-9.73-6.95-7.65-17-15.81-26.45-20.24a118.64,118.64,0,0,0-59.6-10.32"/><path class="avatar-3-cls-3" d="M294.6,227.53a21.4,21.4,0,0,1-3.68-.35c-4.88-.84-9.33-2.79-13.63-4.67a65.63,65.63,0,0,0-9.91-3.74,99.68,99.68,0,0,0-29-3c-.89,0-1.79.08-2.69.13-7.79.43-17.48,1-24-6.55-6.37-7.32-6.62-18.78-4.9-26.37a3.52,3.52,0,0,1,1.16-1.91,3.48,3.48,0,0,1,2.26-1.14,122,122,0,0,1,61.44,10.63c9.08,4.27,19.64,12.34,27.55,21.06,5.45,6,4.5,10.13,3.44,12.05C301.77,225.25,299.66,227.53,294.6,227.53Zm-51.81-18.82A105.61,105.61,0,0,1,269.13,212a72.87,72.87,0,0,1,11,4.1c4.1,1.8,8,3.49,12,4.2a8.67,8.67,0,0,0,4.3,0c-.08-.54-.6-1.9-2.43-3.91-7.32-8.08-17-15.53-25.34-19.44a115.35,115.35,0,0,0-55.46-10.2c-.91,6.15-.12,13.61,3.76,18.07,4.29,4.93,11.12,4.55,18.35,4.15l2.78-.14C239.66,208.75,241.23,208.71,242.79,208.71Z"/><path class="avatar-3-cls-2" d="M183.07,186.43c1.68,7.42,1.09,17.32-4.12,23.31-6.08,7-15.65,5.56-23.92,5.21A103.64,103.64,0,0,0,125,218c-8,2-15.14,6.95-23.27,8.36-8.9,1.55-11-3.2-5.06-9.72,7-7.66,17-15.82,26.45-20.25,17.56-8.26,39.91-12.29,59.6-10.31"/><path class="avatar-3-cls-6" d="M178.31,175.81c1.68,7.42,1.09,17.32-4.12,23.31-6.08,7-15.66,5.56-23.93,5.21a103.27,103.27,0,0,0-30,3.07c-8,2-15.14,6.95-23.27,8.36-8.91,1.55-11-3.2-5.06-9.72,6.94-7.66,17-15.82,26.45-20.25,17.56-8.26,39.9-12.29,59.6-10.32"/><path class="avatar-3-cls-3" d="M93.9,219.55c-5.06,0-7.17-2.27-8-3.82-1.05-1.92-2-6,3.44-12,7.91-8.72,18.47-16.8,27.56-21.07A122.07,122.07,0,0,1,178.31,172a3.5,3.5,0,0,1,2.25,1.14,3.44,3.44,0,0,1,1.16,1.91c1.72,7.59,1.47,19.05-4.89,26.37-6.54,7.52-16.23,7-24,6.56l-2.69-.14a99.71,99.71,0,0,0-29,3,66,66,0,0,0-9.91,3.74c-4.3,1.88-8.75,3.83-13.63,4.68A21.29,21.29,0,0,1,93.9,219.55Zm-1.83-7.24a8.88,8.88,0,0,0,4.3,0c4-.7,7.93-2.4,12-4.19a72.1,72.1,0,0,1,11-4.11,106.66,106.66,0,0,1,31-3.17c.91,0,1.84.09,2.78.14,7.23.4,14.06.77,18.36-4.16,3.87-4.46,4.66-11.92,3.75-18.07A115.18,115.18,0,0,0,119.85,189c-8.31,3.9-18,11.35-25.35,19.43C92.67,210.41,92.15,211.77,92.07,212.31Z"/><path class="avatar-3-cls-7" d="M340.46,243.84c-6-46.08-35.17-92.93-58.18-123.34l-7-5.27,60-2.06C346.81,155.27,349.82,201.11,340.46,243.84Z"/><path class="avatar-3-cls-8" d="M249.46,120.86a38.06,38.06,0,0,1,6.86,3.6,29.12,29.12,0,0,1,4.87,4c2.51,2.63,3.45,4.8,2.77,5.58s-2.86.14-5.88-1.15c-1.51-.65-3.27-1.42-5.19-2.28s-4-1.75-6.26-2.65-4.4-1.67-6.37-2.4-3.8-1.34-5.34-1.9c-3.08-1.15-5.09-2.14-5-3.22s2.22-2,5.84-2.14a29.39,29.39,0,0,1,6.3.43A38.48,38.48,0,0,1,249.46,120.86Z"/><path class="avatar-3-cls-6" d="M92.19,132.81c29.19-4.84,58.37,3.32,87,9,29,5.73,57,5.91,86-.74,38.4-8.81,88.08-27.83,106.7-71.12A76.9,76.9,0,0,0,375,61.34c-20.42,14.6-47.12,12.59-69.71,3s-42.46-25.77-63.5-39.17S197.13.91,173.16,3.63c-23.29,2.64-47.76,17.86-65.39,35A78.55,78.55,0,0,0,91.53,60.7C88,68.12,87.33,78.9,81.26,84.4c-2.86,2.59-6.59,3.46-10,5.08-15.49,7.47-21.13,29-23.64,48-5.17,39-3.54,79,1.88,118"/><path class="avatar-3-cls-3" d="M344,247a4.31,4.31,0,0,1-1.12-.15,4.5,4.5,0,0,1-3.24-5.48c11.44-44.36,5.43-83.13-7.1-127.69a4.5,4.5,0,1,1,8.66-2.44c12.93,46,19.09,86.07,7.16,132.38A4.51,4.51,0,0,1,344,247Z"/><path class="avatar-3-cls-7" d="M84.69,146.36c0,1.6,0,3.18-.09,4.75L75.34,178.6l-3.12,9.24c-3.13,5.88-6.5,11.7-9.62,17.59S59.57,217,57.35,223a130.31,130.31,0,0,0-6.44,22.57c-2-10.35-6-20.67-7.22-31.15,4.9-4.13,7.94-10.22,9.47-16.49,1.66-6.79,1.69-13.86,1.72-20.85a34.9,34.9,0,0,1,7.45,16.14c.05-.22.1-.46.15-.69q4.08-19.68,6.46-39.66c.72,1.35,1.38,2.72,2,4.13a71.28,71.28,0,0,1,2.81,9.87c0-.33.09-.64.12-1Q76,150.39,76.69,134.7A48.12,48.12,0,0,1,84.69,146.36Z"/><path class="avatar-3-cls-7" d="M338,110.71a155.88,155.88,0,0,1-30.76,16c-2.21.87-4.44,1.72-6.67,2.52-4.79,1.72-9.61,3.25-14.4,4.64-8.59,2.5-17.07,4.5-25.07,6.1-29,5.82-57,5.66-86,.65-15.34-2.66-30.82-5.94-46.39-7.76h0l-37.41.79c0,.4.09.81.12,1.21l-1.06.14-1.67,4.22h0l-1.12,2.81c.18-1.56.3-3.14.34-4.74a56.14,56.14,0,0,0-.35-8.13l35.56-.75a95,95,0,0,1-13.84,2l1.47,0a70.84,70.84,0,0,0,14.31-2h0c10-2.44,23.3-8.24,32.64-12.89-1.21,3.52-4,10.23-7.47,11.6,13.7.77,23.75-2.55,37.16-5.45a30.37,30.37,0,0,1-12.68,10.25l-.52.22c.56,0,1.12,0,1.69,0,.17-.09.33-.19.49-.29a49.15,49.15,0,0,0,6.42-4.7s-3.72,6-3.72,6h0a103,103,0,0,0,44.29-4.43l5.39-1.77,5.76-.8c-1.71,1.75-6.58,3.31-8.61,4.67a34.78,34.78,0,0,1-9.85,4.61c1.37,0,3.49,2.12,4.85,2,10.13-.7,19.39-4.89,29.33-7.14,3.41-.77,7.56-2.33,11-3.14,3-.73,12.1-3.72,15-4.82L275,125.25l3.61-.08-2.11-.59-3,3c.11,0-.86,1.54-.75,1.5,16.8-4.79,47.23-14.23,63.65-20.18h1.07C337.63,109.47,337.82,110.08,338,110.71Z"/><path class="avatar-3-cls-3" d="M49.07,260.3a4.4,4.4,0,0,1-1.42-.23,4.51,4.51,0,0,1-2.85-5.69c3-8.87,40.51-120.88,40.89-122a4.5,4.5,0,0,1,8.54,2.86c-.38,1.13-37.94,113.13-40.89,122A4.5,4.5,0,0,1,49.07,260.3Z"/><path class="avatar-3-cls-8" d="M53.66,144.87a12,12,0,0,1,3.85-5.08c1.42-1,2.76-1.21,3.62-.61s1.14,1.88,1,3.42A20.34,20.34,0,0,1,58,152.52c-1,1.17-2.11,1.87-3.16,1.67s-1.81-1.31-2.09-3A12,12,0,0,1,53.66,144.87Z"/><path class="avatar-3-cls-8" d="M73.29,124.32c2.9-1.35,6-.89,6.87,1s-.73,4.57-3.63,5.93-6,.89-6.87-1S70.39,125.68,73.29,124.32Z"/><path class="avatar-3-cls-8" d="M86.6,109.93c2.1-4.46,5-7.73,7-7.06s2.24,5.38-.07,10.31-6.09,7.77-7.88,6.65S84.52,114.4,86.6,109.93Z"/><path class="avatar-3-cls-3" d="M70.57,69.83a55.25,55.25,0,0,0-9.49-9.16c-2.74-2-4.72-2.87-5.16-2.37-.89,1.07,4.59,7,10.86,14.67l2.69,3.26a17.67,17.67,0,0,0-6.57-.85c-2,.18-3.16.77-3.19,1.43s1,1.34,2.69,2,3.87,1.45,6.3,2.34,4.61,1.76,6.3,2.31l.77.23c1.72,1.88,2.94,2.92,3.46,2.62s.07-2.44-1.41-5.5A56.54,56.54,0,0,0,70.57,69.83Z"/><path class="avatar-3-cls-3" d="M189.84,121.17c-.54.28-1.18.64-1.9,1.06s-1.52.9-2.37,1.43l-1.32.83-1.38.88-2.93,1.88-1.53,1c-.26.16-.51.32-.78.47l-.78.48q-1.57.94-3.18,1.83c-1.07.57-2.15,1.12-3.22,1.63l-.82.36c-.26.13-.53.24-.81.36l-1.6.65c-1.07.4-2.11.8-3.13,1.09-.51.18-1,.29-1.49.44s-1,.24-1.43.37l-1.35.3-1.25.23c-.79.12-1.5.23-2.1.29s-1.08.11-1.41.15l-.52.07.41.31a10.67,10.67,0,0,0,1.24.79,16.92,16.92,0,0,0,2.09,1l1.36.43c.48.12,1,.24,1.54.35s1.12.18,1.71.23,1.22.09,1.85.09a22.9,22.9,0,0,0,4-.34,18.43,18.43,0,0,0,2.06-.44l1-.28,1-.34a27.94,27.94,0,0,0,4-1.77,34.42,34.42,0,0,0,3.63-2.31l.84-.64c.27-.21.53-.44.79-.66.53-.44,1-.89,1.51-1.36a33.1,33.1,0,0,0,2.6-2.77c.39-.46.75-.92,1.1-1.37l.95-1.32c.59-.87,1.1-1.68,1.52-2.42s.77-1.4,1-2,.46-1,.59-1.32l.19-.49-.47.22C190.82,120.66,190.38,120.88,189.84,121.17Z"/><path class="avatar-3-cls-3" d="M232.08,127.34l-2.08.93c-.79.37-1.67.79-2.64,1.22-.47.23-1,.48-1.47.71l-1.57.75L221,132.56c-.58.26-1.16.55-1.75.84-.3.15-.59.29-.9.42l-.9.43c-1.2.59-2.44,1.13-3.65,1.73s-2.46,1.15-3.68,1.68l-.91.41c-.3.15-.6.28-.9.41-.61.26-1.2.52-1.78.81-1.18.49-2.31,1.05-3.4,1.51-.55.24-1.08.47-1.59.72s-1,.44-1.5.66c-1,.46-1.86.86-2.65,1.22l-2.08,1c-.58.28-1,.52-1.35.69l-.48.27.53.12c.35.07.86.16,1.5.25a21.78,21.78,0,0,0,2.34.23,30.35,30.35,0,0,0,3,0c.55,0,1.13-.05,1.73-.1s1.2-.13,1.84-.21c1.26-.15,2.57-.42,3.93-.72.67-.16,1.35-.35,2-.55.34-.09.69-.19,1-.3l1-.36c1.39-.45,2.74-1,4.1-1.63s2.66-1.31,3.9-2.07l.94-.55c.31-.19.6-.39.9-.59.59-.4,1.18-.79,1.74-1.2,1.1-.85,2.16-1.66,3.09-2.53l1.35-1.27c.42-.42.81-.86,1.19-1.26a26,26,0,0,0,1.94-2.33,21.05,21.05,0,0,0,1.34-1.93c.35-.55.6-1,.77-1.31l.26-.49-.52.19C233.14,126.89,232.67,127.08,232.08,127.34Z"/><path class="avatar-3-cls-3" d="M285.59,114.78c-.58.47-1.29,1-2.1,1.64-.4.31-.82.65-1.26,1l-1.41,1.09c-.48.38-1,.79-1.49,1.19L277.72,121c-1.08.88-2.28,1.73-3.45,2.67-.62.44-1.22.91-1.84,1.38-.3.23-.61.47-.93.69l-.95.69c-1.25,1-2.58,1.85-3.86,2.79s-2.62,1.84-3.94,2.7l-1,.65c-.31.23-.64.44-1,.65-.65.42-1.29.83-1.92,1.26-1.28.78-2.49,1.63-3.69,2.34l-1.73,1.1c-.55.36-1.12.66-1.64,1l-1.51,1-1.38.84c-.87.54-1.63,1-2.27,1.42s-1.13.72-1.47,1l-.52.36h.63c.41,0,1,0,1.76-.05a26.4,26.4,0,0,0,2.72-.26l1.67-.25c.58-.11,1.18-.24,1.81-.39s1.3-.29,2-.48,1.36-.41,2.07-.63c1.42-.44,2.87-1,4.37-1.67.74-.33,1.48-.69,2.23-1.06.38-.18.76-.36,1.13-.57l1.11-.62c1.5-.81,2.94-1.78,4.39-2.74s2.79-2.05,4.07-3.18l1-.84c.32-.27.62-.57.92-.86.6-.59,1.2-1.16,1.76-1.74,1.1-1.2,2.15-2.35,3.05-3.54l1.3-1.73c.41-.57.76-1.15,1.12-1.68s.68-1.07,1-1.58l.8-1.48a24.8,24.8,0,0,0,1.17-2.47c.29-.7.5-1.26.64-1.64l.2-.59-.52.36C286.65,114,286.17,114.32,285.59,114.78Z"/><path class="avatar-3-cls-3" d="M75.07,168.26c0-.33,0-.66-.07-1-.07-.66-.14-1.3-.21-1.94s-.22-1.25-.33-1.86a16,16,0,0,0-.4-1.75c-.16-.57-.32-1.11-.47-1.64s-.38-1-.56-1.5-.38-.92-.55-1.35-.42-.8-.61-1.17a13.83,13.83,0,0,0-1.09-1.82c-.34-.49-.61-.86-.79-1.11l-.29-.39.11.47.35,1.3c.17.55.33,1.23.49,2,.09.38.18.79.28,1.22s.14.89.22,1.37.2,1,.24,1.47.12,1,.18,1.59.1,1.1.14,1.67.11,1.15.1,1.75,0,1.2,0,1.81c0,.31,0,.62,0,.93l0,.93q0,.94-.06,1.89c0,.64-.06,1.27-.11,1.91-.11,1.27-.2,2.55-.36,3.8l-.1.94-.12.94c-.08.61-.15,1.22-.23,1.83-.19,1.19-.32,2.37-.51,3.47-.08.56-.16,1.1-.23,1.62s-.16,1-.24,1.52c-.14,1-.27,1.87-.39,2.67s-.2,1.5-.27,2.07-.13,1-.16,1.35,0,.48,0,.48l.23-.42.61-1.21c.26-.53.55-1.17.88-1.92s.67-1.59,1-2.53l.54-1.47q.24-.76.51-1.59c.36-1.09.65-2.27,1-3.49.15-.61.28-1.24.41-1.87l.2-1,.15-1c.23-1.3.37-2.65.48-4,.06-.67.06-1.36.09-2a19.44,19.44,0,0,0,0-2Z"/><path class="avatar-3-cls-3" d="M62.89,191.23l-.23-.94c-.08-.31-.17-.62-.27-.92-.19-.61-.36-1.21-.59-1.78a24.73,24.73,0,0,0-1.44-3.24c-.26-.5-.52-1-.8-1.43s-.56-.88-.84-1.28a22.14,22.14,0,0,0-1.65-2.09c-.53-.59-1-1.07-1.44-1.45s-.77-.66-1-.84l-.37-.27.22.4c.14.26.36.64.62,1.13s.57,1.07.89,1.75.68,1.46,1,2.31c.18.42.35.86.52,1.33s.34.94.5,1.43c.34,1,.64,2,.92,3.14.15.54.26,1.11.39,1.67.07.29.13.57.18.86l.16.87c.21,1.16.37,2.35.5,3.55s.19,2.39.21,3.58v.89a8.42,8.42,0,0,1,0,.87c0,.59,0,1.16,0,1.73s-.05,1.13-.1,1.67-.09,1.09-.16,1.61-.11,1-.18,1.52-.13,1-.22,1.43c-.14.91-.31,1.75-.46,2.5s-.31,1.4-.43,1.94l-.3,1.26c-.07.3-.1.45-.1.45l.27-.37c.18-.24.44-.6.75-1.07s.66-1.07,1-1.77a24.08,24.08,0,0,0,1.12-2.41c.2-.45.35-.93.53-1.43s.33-1,.48-1.56.29-1.1.41-1.68.24-1.17.33-1.78.17-1.23.23-1.86c0-.32.06-.64.08-.95l0-1a32.15,32.15,0,0,0-.12-3.92A35.27,35.27,0,0,0,62.89,191.23Z"/><path class="avatar-3-cls-3" d="M340.52,135.12c-.56-.33-2.35,1.41-4.39,4.82a31.05,31.05,0,0,0-1.53,2.85c-.53,1-1,2.19-1.5,3.41a54.73,54.73,0,0,0-2.4,8.19,53.3,53.3,0,0,0-1,8.48c0,1.31,0,2.55,0,3.72s.16,2.24.29,3.22c.54,3.94,1.5,6.24,2.14,6.16,1.42-.19,1-9.55,3.37-20.59S341.75,135.85,340.52,135.12Z"/><path class="avatar-3-cls-3" d="M332.65,76.3q.6-.6,1.08-1.11c1.28-1.36,1.88-2.21,1.67-2.46s-1.68.43-4.06,1.79q.2-.28.12-.42c-.32-.6-3.28.45-8,1.89-1.18.36-2.47.76-3.87,1.11s-2.89.74-4.46,1.13c-3.16.7-6.64,1.35-10.34,1.81s-7.24.61-10.48.67c-1.61,0-3.15,0-4.59,0s-2.79-.11-4-.17c-4.93-.3-8-.62-8.21,0s2.72,2,7.75,3.17a39.25,39.25,0,0,0,4.15.75c1.5.25,3.12.36,4.83.49a68.2,68.2,0,0,0,11.11-.34,68,68,0,0,0,10.48-2.16A105.26,105.26,0,0,1,303,86.69a105.34,105.34,0,0,1-13.4,2.42c-2.09.18-4.08.41-5.94.45-.94,0-1.84.12-2.71.12l-2.51,0c-6.38,0-10.4-.39-10.54.3-.06.31.87.77,2.65,1.35l1.48.45c.55.14,1.15.26,1.79.4a42.19,42.19,0,0,0,4.43.73l2.6.29c.9.08,1.85.09,2.83.14,2,.12,4.05,0,6.26,0a78.72,78.72,0,0,0,14.2-2.19,78.61,78.61,0,0,0,13.5-4.9c2-1,3.85-1.92,5.51-3,.84-.51,1.66-1,2.42-1.48l2.14-1.5a44.2,44.2,0,0,0,3.53-2.77C331.77,77.08,332.24,76.69,332.65,76.3Z"/><path class="avatar-3-cls-3" d="M258.59,56.35c.84-.51,1.67-1,2.42-1.49l2.14-1.49a42.47,42.47,0,0,0,3.53-2.77c.5-.43,1-.82,1.38-1.21s.77-.77,1.09-1.11c1.27-1.36,1.87-2.22,1.67-2.46s-1.69.43-4.07,1.79c.13-.19.17-.33.12-.43-.32-.59-3.27.46-8,1.9-1.18.35-2.47.75-3.87,1.11s-2.89.74-4.46,1.13c-3.15.7-6.64,1.35-10.34,1.8s-7.24.61-10.47.68c-1.62,0-3.16,0-4.6,0s-2.79-.11-4-.18c-4.92-.29-8-.61-8.21,0s2.72,2,7.75,3.17c1.26.28,2.65.56,4.15.75s3.12.36,4.83.49a67.15,67.15,0,0,0,11.11-.35,66.79,66.79,0,0,0,10.48-2.16,104.66,104.66,0,0,1-12.79,4.27A105.34,105.34,0,0,1,225,62.2c-2.09.18-4.07.41-5.94.45-.94,0-1.84.12-2.71.12l-2.5,0c-6.39,0-10.41-.39-10.55.29-.06.31.87.78,2.65,1.36l1.48.45c.55.14,1.15.26,1.79.4a42.64,42.64,0,0,0,4.43.73l2.6.28c.9.09,1.85.1,2.83.15,2,.12,4,0,6.26,0a79.62,79.62,0,0,0,14.2-2.19,78.61,78.61,0,0,0,13.5-4.9C255.05,58.32,256.93,57.4,258.59,56.35Z"/><path class="avatar-3-cls-3" d="M195.19,30.86c.37-.2.73-.43,1.11-.66.73-.47,1.54-.92,2.32-1.45.41-.24.8-.5,1.2-.76.21-.13.41-.27.62-.39l.61-.4c.81-.54,1.66-1.05,2.48-1.62s1.64-1.1,2.47-1.63l.6-.41c.2-.15.4-.28.6-.41.41-.27.81-.53,1.19-.81.79-.52,1.53-1.08,2.26-1.57l1-.76c.34-.26.67-.49,1-.72l1.76-1.33c.52-.43,1-.8,1.37-1.1s.68-.59.88-.77l.15-.14.21-.06,1.73-.51.62-.2-.62-.19c-.41-.12-1-.29-1.77-.45s-1.69-.35-2.77-.5-2.3-.26-3.64-.33c-.67,0-1.37,0-2.1,0s-1.47,0-2.23.07a47,47,0,0,0-4.82.5c-.83.13-1.67.29-2.52.47l-1.28.28-1.28.32A43.6,43.6,0,0,0,191.24,17a39.83,39.83,0,0,0-4.92,2.38c-.39.22-.78.45-1.16.69l-1.13.73c-.73.51-1.46,1-2.13,1.56a28.65,28.65,0,0,0-3.65,3.44l-.78.89-.7.92a17.84,17.84,0,0,0-1.22,1.8,15.91,15.91,0,0,0-1,1.75c-.14.28-.27.55-.41.82s-.21.55-.31.81a18.1,18.1,0,0,0-.83,2.76,13.93,13.93,0,0,0-.26,1.82c0,.41,0,.63,0,.63l.41-.49c.28-.32.61-.81,1.11-1.37s1.07-1.25,1.8-2l.54-.55.61-.56c.41-.38.83-.78,1.31-1.15s.93-.8,1.47-1.18l.78-.59.83-.58c1.11-.79,2.36-1.53,3.64-2.28l2-1.09,1-.52q.51-.27,1.05-.51c1.42-.69,2.91-1.31,4.4-1.92,1.16-.46,2.32-.9,3.5-1.32l0,0-.63.53c-.21.18-.4.37-.6.56-.39.37-.77.74-1.13,1.12a27.05,27.05,0,0,0-2,2.33c-.28.39-.56.76-.81,1.14s-.48.76-.69,1.13a18.31,18.31,0,0,0-1,2.06,12.12,12.12,0,0,0-.65,1.69c-.16.48-.26.87-.33,1.13l-.09.42.39-.17c.25-.11.61-.28,1.05-.5l1.53-.82,1.9-1.07Z"/><path class="avatar-3-cls-3" d="M107.52,78.93q-.13-.72-.33-1.71l-.46-2.13c-.1-.38-.19-.78-.29-1.19s-.2-.82-.31-1.25c-.23-.84-.42-1.75-.7-2.65-.1-.46-.23-.91-.37-1.38-.07-.23-.13-.46-.19-.7l-.2-.7c-.28-.94-.51-1.9-.81-2.84s-.57-1.9-.83-2.85l-.21-.7c-.09-.23-.15-.46-.22-.69-.14-.46-.27-.92-.43-1.37-.25-.91-.57-1.78-.83-2.62l-.41-1.23c-.15-.4-.27-.79-.4-1.17l-.75-2.06-.65-1.64c-.18-.46-.35-.82-.47-1.07l-.09-.18v-.22c0-.77,0-1.39,0-1.8s0-.65,0-.65l-.36.53c-.24.35-.57.87-1,1.55s-.83,1.52-1.29,2.51-.93,2.12-1.4,3.38c-.21.63-.44,1.29-.66,2s-.4,1.42-.6,2.16c-.37,1.49-.7,3.09-.94,4.75q-.18,1.24-.3,2.55L92,66.84q0,.66-.06,1.32A42.83,42.83,0,0,0,92,73.58a39.33,39.33,0,0,0,.82,5.4c.09.44.19.88.31,1.31l.37,1.3c.27.85.54,1.69.86,2.49a29.54,29.54,0,0,0,2.21,4.51l.62,1,.67.93a19.84,19.84,0,0,0,1.36,1.7,15.78,15.78,0,0,0,1.39,1.43l.67.63.68.54a17.42,17.42,0,0,0,2.39,1.6,12.55,12.55,0,0,0,1.66.79l.59.24-.35-.54c-.22-.36-.59-.82-1-1.47s-.88-1.39-1.34-2.3l-.37-.67-.35-.75c-.24-.5-.5-1-.72-1.59s-.49-1.13-.69-1.75c-.11-.3-.22-.61-.34-.92l-.3-1c-.43-1.3-.76-2.71-1.11-4.15-.14-.74-.29-1.48-.44-2.23L99.44,79a11.19,11.19,0,0,1-.18-1.16c-.24-1.55-.39-3.16-.54-4.76-.1-1.25-.17-2.49-.22-3.74v0l.32.75c.11.25.23.5.35.74.25.48.48,1,.74,1.41a28.05,28.05,0,0,0,1.65,2.55c.29.38.57.76.86,1.11s.58.69.87,1A18.9,18.9,0,0,0,105,78.52a12.68,12.68,0,0,0,1.42,1.12c.41.3.75.51,1,.65l.37.21s0-.15,0-.42S107.6,79.41,107.52,78.93Z"/><path class="avatar-3-cls-3" d="M157.63,30.1c.21-.26.41-.52.63-.76l.62-.77c.82-1,1.69-2.06,2.5-3.13s1.66-2.11,2.5-3.13l.6-.79c.19-.27.4-.52.6-.78.41-.51.81-1,1.18-1.54.8-1,1.52-2,2.25-3,.36-.48.7-1,1-1.41s.66-.92,1-1.35l1.7-2.45c.5-.77.93-1.44,1.3-2s.63-1,.81-1.36l.13-.24.25-.17,2-1.38.71-.52h-.87c-.58,0-1.41.06-2.46.17s-2.34.26-3.79.52-3.07.63-4.82,1.1c-.87.26-1.78.52-2.71.83s-1.88.66-2.85,1c-1.94.76-4,1.64-6,2.67-1,.52-2,1.07-3,1.66l-1.53.9-1.51.95a65.41,65.41,0,0,0-5.9,4.36,52.74,52.74,0,0,0-5.32,5.14c-.42.44-.82.9-1.21,1.37l-1.14,1.41c-.73,1-1.45,1.92-2.09,2.91a39.74,39.74,0,0,0-3.25,6q-.31.75-.63,1.47t-.51,1.47a25.35,25.35,0,0,0-.81,2.83,22.86,22.86,0,0,0-.5,2.66c0,.42-.11.83-.17,1.23s0,.79-.06,1.17a22.82,22.82,0,0,0,.1,3.9,18.82,18.82,0,0,0,.42,2.44l.2.85.32-.81c.23-.53.45-1.3.86-2.23s.85-2.06,1.49-3.28l.46-.94.55-1a23.46,23.46,0,0,1,1.2-2c.44-.69.86-1.42,1.39-2.12l.76-1.1.83-1.09c1.09-1.49,2.39-3,3.72-4.47l2.11-2.23L141.81,32c.36-.38.74-.75,1.13-1.11,1.54-1.47,3.19-2.89,4.85-4.31,1.3-1.08,2.61-2.13,4-3.17l0,0-.59.95c-.19.31-.36.64-.53,1-.34.65-.68,1.28-1,1.93a38.56,38.56,0,0,0-1.52,3.8c-.2.63-.4,1.23-.57,1.82s-.29,1.18-.41,1.74a27.31,27.31,0,0,0-.49,3.1,18.32,18.32,0,0,0-.12,2.44c0,.68,0,1.23,0,1.6l.06.57L147,42c.28-.25.67-.62,1.14-1.09l1.63-1.69,2-2.18c.35-.4.71-.82,1.09-1.24s.75-.87,1.14-1.32c.75-.92,1.6-1.84,2.38-2.84C156.83,31.11,157.23,30.61,157.63,30.1Z"/><path class="avatar-3-cls-3" d="M188.32,415.9a115.94,115.94,0,0,1-19.23-1.61,3.5,3.5,0,1,1,1.26-6.88c.31,0,30.65,5.45,44.82-4.67A15.44,15.44,0,0,0,221.82,392a3.5,3.5,0,1,1,6.92,1,22.47,22.47,0,0,1-9.51,15.42C210.9,414.39,198.63,415.9,188.32,415.9Z"/><circle class="avatar-3-cls-9" cx="260.6" cy="260.93" r="5.28"/><circle class="avatar-3-cls-3" cx="245.8" cy="264.38" r="22.91"/><circle class="avatar-3-cls-1" cx="256.02" cy="247.35" r="12.7"/><path class="avatar-3-cls-8" d="M300.59,168.74c1.29,2.37,1.34,4.85.1,5.52s-3.29-.7-4.58-3.08-1.34-4.85-.1-5.52S299.3,166.36,300.59,168.74Z"/><path class="avatar-3-cls-8" d="M310.25,189.88c1.94,3.62,2.51,7.1,1.27,7.77s-3.83-1.73-5.77-5.36-2.52-7.1-1.27-7.77S308.3,186.25,310.25,189.88Z"/><path class="avatar-3-cls-2" d="M299.47,144.54a262.36,262.36,0,0,1-35.32,10.62c-29,6.65-57,6.47-86,.74-25.17-5-50.77-11.88-76.43-10.17q2.81-6.3,6.16-12.27l18.41-.39c10.64,1.22,21.21,3.34,31.78,5.55.36.16.75.32,1.18.49l1.36.43c.48.12,1,.24,1.54.35s1.12.18,1.71.23,1.22.09,1.85.09h.06c7.43,1.54,14.86,3,22.32,4.12,2.23.33,4.49.63,6.8.88l-.46.26.53.12c.35.07.86.16,1.5.25a21.78,21.78,0,0,0,2.34.23,30.35,30.35,0,0,0,3,0c.53,0,1.1-.05,1.68-.1,27.91,1.92,60.1-1.45,89.18-11.39C295,137.79,297.22,141.11,299.47,144.54Z"/><path class="avatar-3-cls-3" d="M48.53,260.48a4.48,4.48,0,0,1-4.45-3.88c-6.29-45.25-7.1-84.24-2.47-119.22C45.3,109.48,53.85,92.67,67.76,86c1.14-.55,2.28-1,3.38-1.45a18.15,18.15,0,0,0,5.5-2.92c3.46-3.14,5-8.42,6.69-14a62.23,62.23,0,0,1,4-10.82C101,30.15,129.81,8.13,159,2c40.31-8.54,71.8,12.57,102.27,33,14.23,9.53,28.94,19.39,44.16,25.83,24.66,10.44,48.47,9.52,65.33-2.54l10.62-7.6-3.69,12.53a80.3,80.3,0,0,1-3.28,9.09C365.33,93.3,343.91,122,293.34,139c-32.79,11-72.38,14.65-105.89,9.64-9.25-1.38-18.56-3.32-27.56-5.2-23.42-4.88-45.55-9.49-68.56-5.67a4.5,4.5,0,0,1-1.47-8.88c24.66-4.09,48.66.91,71.87,5.74,8.87,1.85,18.05,3.77,27.05,5.11,32.17,4.81,70.18,1.35,101.69-9.27,25.37-8.54,58.45-25.6,74.21-58.63-18,7.64-40.17,6.76-62.78-2.81-16-6.78-31.08-16.88-45.66-26.65C226,22.14,197.43,3,160.84,10.75c-26.25,5.56-53.21,26.18-65.55,50.13A54.71,54.71,0,0,0,92,70.14c-1.85,6.24-3.95,13.3-9.28,18.13a25.88,25.88,0,0,1-8.19,4.6c-1,.4-1.95.79-2.83,1.21-10.95,5.28-17.87,19.83-21.13,44.48C46,172.72,46.82,210.93,53,255.37a4.5,4.5,0,0,1-3.84,5.07A4.4,4.4,0,0,1,48.53,260.48Z"/><path class="avatar-3-cls-3" d="M343.6,255.94a4.49,4.49,0,0,1-4.5-4.47c-.3-40.92-49.59-113.6-50.09-114.33a4.5,4.5,0,1,1,7.44-5.08c2.09,3.07,51.33,75.71,51.65,119.35a4.51,4.51,0,0,1-4.47,4.53Z"/><path class="avatar-3-cls-8" d="M327.53,239.22a114.3,114.3,0,0,1,1,14c0,2.15,0,4.2-.15,6.11s-.26,3.69-.45,5.31c-.76,6.47-2,10.34-2.64,10.25-1.5-.19-.14-15.93-2.82-35-2.51-19.06-8.05-33.86-6.65-34.44.61-.26,2.82,3.14,5.29,9.17.62,1.51,1.26,3.17,1.86,5s1.19,3.78,1.78,5.85A114.05,114.05,0,0,1,327.53,239.22Z"/><circle class="avatar-3-cls-3" cx="145.8" cy="264.38" r="22.91"/><circle class="avatar-3-cls-1" cx="156.02" cy="247.35" r="12.7"/><circle class="avatar-3-cls-8" cx="136.6" cy="272.93" r="5.28"/><circle class="avatar-3-cls-8" cx="239.6" cy="272.93" r="5.28"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/avatar-4.svg b/eims-ui/packages/icons/src/svg/icons/avatar-4.svg
new file mode 100644
index 0000000..d9138df
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/avatar-4.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 464.12 605.75"><defs><style>.avatar-4-cls-1{fill:#dfe7ea;}.avatar-4-cls-2{fill:#f0d7c2;}.avatar-4-cls-3{fill:#d7ad8c;}.avatar-4-cls-4{fill:#c4987a;}.avatar-4-cls-5{fill:#8376a5;}.avatar-4-cls-6{fill:#655a8e;}.avatar-4-cls-7{fill:#ebcbac;}.avatar-4-avatar-4-cls-16,.avatar-4-cls-8,.avatar-4-cls-9{fill:none;stroke:#42565e;stroke-miterlimit:10;}.avatar-4-cls-8{stroke-linecap:round;}.avatar-4-cls-8,.avatar-4-cls-9{stroke-width:10px;}.avatar-4-cls-9{stroke-linecap:square;}.avatar-4-avatar-4-cls-10{fill:#dcb79b;}.avatar-4-avatar-4-cls-11{fill:#fff;}.avatar-4-avatar-4-cls-12{fill:#40565a;}.avatar-4-avatar-4-cls-13{fill:#a699d6;}.avatar-4-avatar-4-cls-14{fill:#485d63;}.avatar-4-avatar-4-cls-15{fill:#796f9c;}.avatar-4-avatar-4-cls-16{stroke-width:11px;}.avatar-4-avatar-4-cls-17{fill:#325560;}</style></defs><title>Asset 120</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><ellipse class="avatar-4-cls-1" cx="236.82" cy="551.53" rx="184.33" ry="54.22"/><path class="avatar-4-cls-2" d="M30.24,275.91A69.67,69.67,0,0,0,21.69,369c4.48,6,10.06,11.3,16.89,14.32s15,3.46,21.65,0"/><path class="avatar-4-cls-3" d="M18,366.5c3.62,6.7,8.36,12.95,14.66,17.24,2.69,1.84,7,1.57,11.13,1.27-5.9-4.26-10.4-10.26-13.86-16.68-15.65-29-9.35-68.14,14.59-90.75H68.76v-1.84H32.58C8.64,298.37,2.34,337.52,18,366.5Z"/><path class="avatar-4-cls-3" d="M419,275a69.67,69.67,0,0,1,29.75,88.61c-3,6.84-7.19,13.32-13.14,17.82s-13.82,6.82-21.06,5"/><path class="avatar-4-cls-4" d="M411.42,386.76a29.59,29.59,0,0,0,19.15-4.19c6.72-4,11.79-10.17,15.61-16.77A67.58,67.58,0,0,0,453.47,316c-4.12-16.58-18.64-31.49-33.49-41l-1,13.49c7.89,8.45,16.35,18.74,19.1,29.76a67.58,67.58,0,0,1-7.29,49.78c-3.82,6.6-8.9,12.74-15.61,16.77A30.36,30.36,0,0,1,411.42,386.76Z"/><path class="avatar-4-cls-5" d="M452.36,118.46c-8.78-30.07-32.4-57-62.92-63.67a46.85,46.85,0,0,0-9.71-17.86c-5.41-6.13-12.35-10.72-19.61-14.48-36.17-18.7-79.26-17-119.65-11.85-16.15,2.07-32.27,4.63-48,8.91C128.34,37,73,84.38,45.91,145.09s-22.25,133.54,7.56,193L262.36,185.91V334.35H414.7c-8.85-26.74-4.64-73.12,7.76-98.72,9.21-19,22.61-32.09,28.47-53.07C457,160.94,458.72,140.29,452.36,118.46Z"/><path class="avatar-4-cls-6" d="M454.65,186.37C452,196,447.72,203.88,443,211.49c-.82-48.6-11-97.83-36.11-139.38A92.48,92.48,0,0,0,398.41,60c28,8.43,49.4,34,57.66,62.31C462.44,144.1,460.69,164.75,454.65,186.37Z"/><path class="avatar-4-cls-7" d="M53.69,331.22c15.1-11.09,21.39-30.36,26.05-48.51A691.24,691.24,0,0,0,99.16,167.36l91,27.16c10,3,20.12,6,30.54,6.38,26.17,1,49.73-14.31,74.25-23.5A165.16,165.16,0,0,1,370,167.87s7.5,121.7,48.83,164.47c.81,73-43.54,137.46-92.3,191.78-11.27,12.55-23,25.08-37.55,33.62l-.21.12a72.52,72.52,0,0,1-36.5,10.2l-29.86.15a71.65,71.65,0,0,1-36.73-9.91l-1-.56c-14.55-8.54-26.28-21.06-37.55-33.62C98.47,469.8,52,405.33,52.78,332.34"/><path class="avatar-4-cls-2" d="M146.18,528.31c-48.31-54-94-118-93.24-190.45l.91-1.13c15.09-11.09,21.39-30.36,26-48.51A690.78,690.78,0,0,0,99.31,172.88l28.18,8.41C118.46,222.82,83,409.19,146.18,528.31Z"/><path class="avatar-4-cls-3" d="M323.51,525.35a270.7,270.7,0,0,1-19.2,19.85c22.46-40.14,35.38-85.8,40-131.73,6.33-63.1-2.24-126.93-17.2-188.56-.55-2.26-1.17-4.63-2.75-6.34-2.47-2.67-6.5-3-10.13-3.13-20.76-.84-41.76-1.81-61.63-7.87a105.08,105.08,0,0,1-17.44-7c19.43-4.07,37.77-14.78,56.7-21.88A165.11,165.11,0,0,1,367,169.1s7.49,121.69,48.83,164.46C416.61,406.56,372.26,471,323.51,525.35Z"/><path class="avatar-4-cls-8" d="M390.57,54.45c31.3,6,55.6,33.41,64.53,64,6.37,21.82,4.61,42.47-1.43,64.1-5.86,21-19.26,34.06-28.47,53.07-12.4,25.6-14.78,71.07-5.93,97.81"/><path class="avatar-4-cls-8" d="M27.49,275.91A69.67,69.67,0,0,0,18.93,369c4.48,6,10.06,11.3,16.89,14.32s15,3.46,21.65,0"/><path class="avatar-4-cls-8" d="M422.38,274.38A69.67,69.67,0,0,1,452.13,363c-3,6.84-7.19,13.32-13.14,17.82s-13.82,6.82-21.06,5"/><polygon class="avatar-4-cls-3" points="237.17 353.31 237.17 432.24 264.71 432.24 237.17 353.31"/><polyline class="avatar-4-cls-9" points="237.32 357.44 236.19 423.51 236.11 428.1"/><path class="avatar-4-avatar-4-cls-10" d="M344.27,308.58c.57,5-.41,9-1.09,8.93s-.9-4-1.45-8.65-1.2-8.52-.51-8.75S343.71,303.58,344.27,308.58Z"/><path class="avatar-4-avatar-4-cls-11" d="M160.6,204.75a109.34,109.34,0,0,1,22.25,7.54c5.49,2.71,8.48,5.28,8,6.57s-4.34,1.18-10.15.31-13.7-2.41-22.45-4.49A144,144,0,0,1,136,207.81c-5.57-2.38-8.76-4.67-8.36-6s4.24-1.55,10.15-1A175.83,175.83,0,0,1,160.6,204.75Z"/><path class="avatar-4-avatar-4-cls-12" d="M397.3,128.18a75.72,75.72,0,0,1,1.9,14c0,2.17.07,4.23-.09,6.16-.07,1-.1,1.89-.21,2.78l-.35,2.55c-1,6.48-2.82,10.19-3.8,10s-1.24-4.15-1.61-10.27L393,151c0-.83-.16-1.7-.23-2.59-.11-1.78-.38-3.68-.6-5.67-.54-4-1.27-8.29-2.32-12.78s-2.39-8.66-3.69-12.45c-.71-1.87-1.32-3.68-2-5.33-.34-.83-.63-1.65-1-2.41l-.95-2.21c-2.43-5.63-4.08-9.23-3.19-9.9s4.05,1.91,7.9,7.22l1.46,2.11c.5.74.95,1.55,1.44,2.38,1,1.65,1.9,3.5,2.85,5.46A75.74,75.74,0,0,1,397.3,128.18Z"/><path class="avatar-4-avatar-4-cls-12" d="M435.13,118.25a108.47,108.47,0,0,1-2.34,18.33c-.67,2.76-1.29,5.39-2.1,7.78-.39,1.2-.73,2.37-1.14,3.46L428.33,151a55.23,55.23,0,0,1-2.41,5.25c-.39.76-.74,1.46-1.11,2.09s-.74,1.19-1.08,1.69c-1.34,2-2.3,3-2.79,2.77-1-.47.38-5.47,2.21-13.44l.71-3.13c.25-1.08.43-2.23.67-3.4.51-2.34.86-4.87,1.31-7.51A173.57,173.57,0,0,0,427.48,118a173.79,173.79,0,0,0-.37-17.39c-.26-2.66-.43-5.21-.77-7.58-.16-1.18-.25-2.34-.42-3.44l-.48-3.17c-1.25-8.08-2.3-13.17-1.24-13.56.5-.18,1.38.87,2.58,3q.45.79,1,1.76c.32.66.62,1.38,1,2.17a55.19,55.19,0,0,1,2,5.41l1,3.21c.33,1.12.59,2.31.89,3.54.64,2.45,1.06,5.11,1.53,7.91A108.47,108.47,0,0,1,435.13,118.25Z"/><path class="avatar-4-avatar-4-cls-12" d="M407,237.87a61.19,61.19,0,0,1,3-13.43,51.88,51.88,0,0,1,2.35-5.53c.43-.84.8-1.66,1.25-2.41l1.31-2.14a30.51,30.51,0,0,1,2.52-3.48c.4-.49.77-.95,1.14-1.34s.75-.73,1.09-1c1.35-1.2,2.28-1.69,2.71-1.38.91.66-.62,4.15-2.6,9.64l-.77,2.16c-.27.75-.48,1.55-.74,2.36-.56,1.61-1,3.38-1.49,5.21A83.83,83.83,0,0,0,414.29,251c.13,1.9.18,3.72.4,5.4.1.85.14,1.68.25,2.46l.32,2.27c.83,5.79,1.62,9.51.59,10-.48.21-1.3-.46-2.37-1.9q-.4-.54-.85-1.23c-.29-.46-.55-1-.84-1.54A30.49,30.49,0,0,1,410,262.5l-.85-2.36c-.28-.83-.48-1.71-.73-2.61a51.91,51.91,0,0,1-1.18-5.89A61.23,61.23,0,0,1,407,237.87Z"/><path class="avatar-4-avatar-4-cls-13" d="M338.06,11a505.1,505.1,0,0,0-65.52,7.53c-9.44,1.72-18.9,3.72-27.78,7.32C237.13,29,230,33.22,222.27,36.08l-1,.35c-15.13,5.37-33.2,6.48-43.21,19L179.81,52q1.31-2.53,2.6-5.07a64.64,64.64,0,0,0-39.5,17c-.84.79-1.73,1.54-2.63,2.27-9,7.24-20.27,11.3-28.87,19.81q-.45-4.32-.89-8.65-2,1.23-3.94,2.52c-9.37,6.19-18,13.53-24.81,22.49-7.31,9.7-12.31,21.4-12.89,33.52a2.76,2.76,0,0,0-1.28-1.65c-.22.33-.44.67-.65,1a164.8,164.8,0,0,0-25.72,75.23q-1.39-4.56-2.77-9.1c-.08,1.17-.16,2.37-.21,3.63a304,304,0,0,0,3.3,57.5,58,58,0,0,1-13.19-23.61,221.08,221.08,0,0,1,5.31-59.68A200.24,200.24,0,0,1,46,142.48a217.66,217.66,0,0,1,18.72-33.54A52.26,52.26,0,0,1,66.84,100a231.53,231.53,0,0,1,78.78-67.78,147.77,147.77,0,0,0-11.25,10A223.1,223.1,0,0,1,179,21.07q6.69-2.31,13.52-4.18a312,312,0,0,1,36.29-7.31c3.89-.58,7.79-1.1,11.68-1.61,10.4-1.34,21-2.43,31.56-3C294.53,3.75,317,4.85,338.06,11Z"/><path class="avatar-4-cls-8" d="M50.86,335.92C21,276.49,16.19,203.66,43.3,142.95S125.73,34.84,189.89,17.37c15.71-4.28,31.83-6.84,48-8.91,40.39-5.18,83.48-6.85,119.65,11.85,7.26,3.75,14.2,8.35,19.61,14.48C388.79,48,392,67.82,386,84.4s-20.53,29.56-37.4,34.67"/><path class="avatar-4-avatar-4-cls-12" d="M119.45,55.71a122.27,122.27,0,0,1,11.37-12.29c1.91-1.73,3.71-3.37,5.52-4.79s3.48-2.72,5.07-3.83c6.39-4.44,10.89-6.3,11.46-5.47,1.28,1.85-13.39,13.4-27.43,31.16C111.22,78.11,103.19,95,101.1,94.13c-.93-.38-.12-5.17,2.8-12.39.74-1.8,1.58-3.75,2.62-5.79s2.18-4.19,3.45-6.44A122.24,122.24,0,0,1,119.45,55.71Z"/><path class="avatar-4-avatar-4-cls-12" d="M152.92,44.74a155.46,155.46,0,0,1,12.6-13.37c2.09-1.91,4.07-3.71,6-5.29s3.78-3,5.5-4.29c6.91-5,11.74-7.28,12.34-6.46,1.32,1.81-14.6,14.92-30.58,34.31C142.68,68.9,132.71,87,130.69,86c-.91-.44.42-5.6,4.09-13.32.92-1.92,2-4,3.21-6.2s2.61-4.49,4.1-6.89A155.46,155.46,0,0,1,152.92,44.74Z"/><path class="avatar-4-avatar-4-cls-12" d="M193,32.11a87.62,87.62,0,0,1,14.89-12.4,79.37,79.37,0,0,1,14-7.35c8.37-3.31,14-3.82,14.24-2.87s-4.55,3.39-11.85,7.73a121.7,121.7,0,0,0-25.76,20.23c-8.94,9.23-15.89,18.86-21.16,25.73s-8.78,11.07-9.7,10.51,1-5.67,5.14-13.44A127.77,127.77,0,0,1,193,32.11Z"/><path class="avatar-4-avatar-4-cls-12" d="M246.25,15.32A101.07,101.07,0,0,1,263,7.14a76.92,76.92,0,0,1,14.74-4c8.63-1.37,14-.51,14.08.47s-5,2.2-12.8,4.79a141.76,141.76,0,0,0-28.82,13.45c-10.67,6.49-19.73,13.51-26.43,18.52s-11.06,8-11.8,7.22,2.32-5.1,8.21-11.27A131.37,131.37,0,0,1,246.25,15.32Z"/><path class="avatar-4-avatar-4-cls-12" d="M38.39,192.46a120.8,120.8,0,0,0,3.08,13.79c.66,2.07,1.22,4.08,1.91,5.9.33.91.6,1.82.94,2.67l.95,2.43c2.44,6.21,4.26,10.1,3.34,10.76-.43.31-1.43-.29-2.9-1.67q-.55-.52-1.19-1.18c-.41-.45-.81-1-1.26-1.52a38.32,38.32,0,0,1-2.81-3.91L39,217.34c-.5-.84-.94-1.75-1.43-2.68a65,65,0,0,1-2.76-6.13,71.66,71.66,0,0,1-4.66-30.3,64.9,64.9,0,0,1,.79-6.68c.19-1,.33-2,.56-3l.69-2.72a38.34,38.34,0,0,1,1.5-4.57c.26-.66.49-1.27.74-1.83s.53-1,.78-1.48c1-1.76,1.76-2.63,2.26-2.47,1.07.35.52,4.61.05,11.26l-.17,2.61c-.06.9,0,1.85-.09,2.82-.11,1.94,0,4,0,6.2A120.86,120.86,0,0,0,38.39,192.46Z"/><path class="avatar-4-avatar-4-cls-12" d="M36.06,250.75a94.42,94.42,0,0,0,5.12,8.54c.9,1.25,1.71,2.48,2.56,3.55.42.55.8,1.1,1.2,1.6l1.16,1.45c3,3.71,5,6.11,4.35,7s-3.77,0-8.06-3.08l-1.65-1.24c-.57-.44-1.1-1-1.68-1.47a42.43,42.43,0,0,1-3.46-3.52,47.69,47.69,0,0,1-10.33-19.94,42.32,42.32,0,0,1-.88-4.85c-.09-.77-.19-1.5-.23-2.22s0-1.4-.06-2.06c0-5.26,1.13-8.39,2.13-8.36s1.91,3.05,3.23,7.61l.52,1.78c.18.62.41,1.25.62,1.91.38,1.32.92,2.69,1.42,4.14A94.39,94.39,0,0,0,36.06,250.75Z"/><path class="avatar-4-avatar-4-cls-12" d="M67.93,123.65A94.35,94.35,0,0,0,69.15,133c.31,1.43.54,2.81.87,4.07.16.64.27,1.27.43,1.86l.44,1.71c1.13,4.37,1.93,7.26,1,7.85s-3.35-1.43-6-5.72l-1-1.71c-.33-.6-.61-1.25-.92-1.92a40.14,40.14,0,0,1-1.7-4.39,45.45,45.45,0,0,1-1.49-21.39,40.27,40.27,0,0,1,1.08-4.58c.22-.71.4-1.39.64-2l.73-1.83c2-4.61,4.21-6.91,5.12-6.49s.62,3.42.11,7.91l-.2,1.76c-.07.61-.1,1.25-.17,1.9-.15,1.3-.19,2.7-.3,4.16A94.26,94.26,0,0,0,67.93,123.65Z"/><path class="avatar-4-cls-6" d="M355.66,174.31a165.11,165.11,0,0,0-59.78,10.43c-10.63,4-21.07,9.1-31.63,13.56v-4.12L252.17,203a106,106,0,0,1-14.22,3.9c-1.55.3-3.11.56-4.69.78a69.08,69.08,0,0,1-11.64.58c-10.43-.39-20.55-3.4-30.53-6.38l-56.29-16.8-14.54-4.34-20.14-6q-2.75,33.38-8.73,66.39Q87.06,265.14,81,288.82c-.1.41-.21.82-.31,1.23-4.66,18.14-10.95,37.42-26,48.5l-.92,1.13c0,1.12,0,2.25,0,3.36Q50.69,336.71,48,330.2c11.22-9.15,18.92-22.41,22.74-36.44,4.32-15.88,4-32.73,1.4-49a1.49,1.49,0,0,0,1.43.57c1.44-.21,3-2.36,3.4-4.18a188.87,188.87,0,0,0,4.36-49.24c0-.66-.06-1.31-.09-2l3.23,3.4c6-11.47,4.25-31.47,6.3-44.25,13.89,12.88,48.77,13.2,66.08,5.51-4.33,3.77-5,12.86-10.1,15.6,1.53,0-8.28,5-6.75,4.94a129.75,129.75,0,0,0,65.78-21.6c-5.24,11-14.41,26.68-26,30.42,1.69.36,2.65-6.32,4.34-6q12.47,2.51,25.09,4.17c12.06,1.61,24.59,2.62,36.17-1.11,14.49-4.66,25.64-16.08,36.16-27.09q0,2.9-.35,5.8a65.84,65.84,0,0,1-5,19.31l32.61-13.88c.05.5.09,1,.12,1.51a27,27,0,0,1-3.55,14.74q25.15-11.8,49.59-25A27.75,27.75,0,0,1,355.66,174.31Z"/><path class="avatar-4-cls-6" d="M411.74,319.21c-8.3-10.85-15.05-25-20.53-40.32-.08-.22-.16-.44-.23-.65-11.25-33.09-16.84-70.92-19.39-93.54,10.71,26.93,25,59.59,39.5,85.45h0C408.88,287.05,408.92,304.81,411.74,319.21Z"/><path class="avatar-4-avatar-4-cls-14" d="M269.63,176.7c24.26-13.66,43.82-25.11,45.05-23.33s-16.68,16.14-41.28,30-46.18,21.74-47,19.86S245.4,190.42,269.63,176.7Z"/><path class="avatar-4-avatar-4-cls-14" d="M257.18,173.65c4.41-4.6,8.39-9.18,11.9-13.46,1.71-2.18,3.38-4.21,4.84-6.2.74-1,1.49-1.92,2.16-2.85l1.94-2.68c4.93-6.84,8-11.24,9-10.75s-.41,5.73-4.33,13.56l-1.59,3c-.56,1.05-1.22,2.11-1.87,3.22-1.28,2.24-2.84,4.51-4.47,6.91a121.8,121.8,0,0,1-26.14,27c-2.34,1.71-4.56,3.34-6.75,4.7-1.09.69-2.12,1.38-3.15,2l-3,1.69c-7.7,4.18-13,5.67-13.41,4.78s3.78-4.16,10.45-9.32l2.61-2c.91-.7,1.81-1.48,2.78-2.25,1.94-1.52,3.92-3.26,6-5C248.28,182.34,252.73,178.22,257.18,173.65Z"/><path class="avatar-4-avatar-4-cls-12" d="M167.43,170.51a127.73,127.73,0,0,0,20.86-7.38c3-1.53,6-2.88,8.6-4.48,1.31-.77,2.63-1.44,3.82-2.21l3.41-2.23c2.24-1.34,4.06-2.84,5.78-4,.84-.61,1.67-1.15,2.38-1.68s1.35-1.06,1.94-1.5c2.38-1.77,3.91-2.61,4.3-2.26s-.39,1.87-2.19,4.37q-.68.93-1.54,2c-.6.72-1.3,1.44-2,2.23a55.67,55.67,0,0,1-5.34,5.13l-3.32,2.77c-1.17.95-2.49,1.79-3.81,2.73a89.12,89.12,0,0,1-8.83,5.42,103.88,103.88,0,0,1-22.17,8.5,103.87,103.87,0,0,1-23.57,2.85,89.14,89.14,0,0,1-10.34-.66c-1.61-.22-3.17-.34-4.64-.63l-4.23-.9a55.7,55.7,0,0,1-7.12-2c-1-.36-2-.66-2.85-1s-1.63-.75-2.32-1.09c-2.76-1.36-4.16-2.34-4-2.84s1.92-.47,4.86,0c.73.11,1.54.26,2.42.42s1.86.23,2.89.37c2.07.25,4.38.72,7,.86l4.06.38c1.41.13,2.89.1,4.41.17,3,.2,6.29,0,9.69-.06A127.74,127.74,0,0,0,167.43,170.51Z"/><path class="avatar-4-avatar-4-cls-12" d="M132.77,165a101.23,101.23,0,0,0,11.59-5.33c1.7-1,3.36-1.87,4.83-2.84.74-.47,1.49-.89,2.17-1.36l2-1.33c5-3.41,8.07-5.83,8.93-5.11.4.34.13,1.39-.74,3q-.33.61-.76,1.34c-.3.47-.67.95-1.06,1.47a32.16,32.16,0,0,1-2.84,3.38L155,160c-.64.63-1.36,1.21-2.09,1.85a54.7,54.7,0,0,1-4.91,3.75,60.59,60.59,0,0,1-26.34,9.87,54.62,54.62,0,0,1-6.16.4c-1,0-1.9,0-2.79,0l-2.57-.2a32.13,32.13,0,0,1-4.36-.68c-.64-.14-1.23-.26-1.76-.41s-1-.34-1.45-.5c-1.73-.66-2.62-1.27-2.54-1.8.17-1.11,4.09-1.32,10.09-2l2.35-.29c.81-.1,1.65-.27,2.52-.4,1.74-.23,3.58-.66,5.51-1A101.21,101.21,0,0,0,132.77,165Z"/><path class="avatar-4-avatar-4-cls-12" d="M72.26,253c-3.94-18.19-10.05-32.28-8.1-33.34.9-.48,3.66,2.5,6.83,8.12.79,1.41,1.62,3,2.4,4.69S75,236,75.75,238a99.8,99.8,0,0,1,4,13.3,99.82,99.82,0,0,1,2,13.73c.12,2.13.24,4.15.2,6.05s-.07,3.66-.19,5.27c-.5,6.44-1.74,10.3-2.76,10.25C76.78,286.49,76.37,271.13,72.26,253Z"/><path class="avatar-4-avatar-4-cls-12" d="M82.64,210.52c-.93-5.11-1.91-9.93-2.87-14.31-.52-2.17-1-4.26-1.47-6.19l-.69-2.81-.68-2.58c-1.72-6.58-2.86-10.76-1.87-11.26s3.8,3,6.94,9.37l1.19,2.53c.4.89.76,1.83,1.15,2.8.8,1.94,1.5,4.06,2.24,6.29a126.38,126.38,0,0,1,3.6,14.79,156.62,156.62,0,0,1,2.4,27.28c0,7-.65,11.34-1.7,11.43s-2.36-4.11-3.69-10.92S84.46,220.74,82.64,210.52Z"/><path class="avatar-4-avatar-4-cls-12" d="M344.09,154.54c1.54-2,2.91-4,4.14-5.82.58-.94,1.18-1.81,1.68-2.67s1-1.65,1.46-2.38c1.79-2.95,3.1-4.91,4.17-4.69s1.56,2.67.92,6.54a22.28,22.28,0,0,1-.74,3.1,30,30,0,0,1-1.27,3.44A34.57,34.57,0,0,1,344.2,165.2a30,30,0,0,1-3,2.07,22.28,22.28,0,0,1-2.83,1.48c-3.59,1.57-6.13,1.62-6.56.71s1.11-2.74,3.53-5.19c.6-.62,1.27-1.27,2-2s1.41-1.49,2.18-2.28C340.94,158.34,342.52,156.53,344.09,154.54Z"/><path class="avatar-4-cls-8" d="M53.84,333.37C68.95,322.28,75.23,303,79.9,284.86A691.24,691.24,0,0,0,99.31,169.51l91,27.16c10,3,20.12,6,30.54,6.38,26.17,1,49.73-14.31,74.25-23.5A165.16,165.16,0,0,1,370.19,170s7.5,121.7,48.83,164.47c.81,73-43.54,137.46-92.3,191.78-11.27,12.55-23,25.08-37.55,33.62L289,560a72.52,72.52,0,0,1-36.5,10.2l-29.86.15a71.65,71.65,0,0,1-36.73-9.91l-1-.56c-14.55-8.54-26.28-21.06-37.55-33.62C98.62,472,52.12,407.48,52.93,334.49"/><path class="avatar-4-avatar-4-cls-15" d="M366.79,83c3.56-9.19,4.7-18.51,5.61-25.39s1.67-11.38,3.11-11.5,3.15,4.16,4.11,11.49a63.11,63.11,0,0,1,.29,13.08,57.22,57.22,0,0,1-3.61,16A46.21,46.21,0,0,1,367.44,101a36.74,36.74,0,0,1-11,8.3,22.84,22.84,0,0,1-8.9,2.45c-2.21.06-3.45-.39-3.59-1.06-.32-1.48,3.72-3.27,8.61-7.49A48.83,48.83,0,0,0,360.21,95,53.81,53.81,0,0,0,366.79,83Z"/><path class="avatar-4-avatar-4-cls-15" d="M393.72,82.48c.87-4.87,1.17-9.75,1.81-13.49s1.62-6.21,3-6.35,2.93,2,4.17,5.79a32.63,32.63,0,0,1,1.39,6.9,33.45,33.45,0,0,1-.35,9,27.19,27.19,0,0,1-3.21,8.81,20.26,20.26,0,0,1-5.08,5.9,11.07,11.07,0,0,1-4.8,2.28c-1.31.2-2.17-.08-2.53-.67-.73-1.26.54-3.35,1.86-6.32A49.1,49.1,0,0,0,393.72,82.48Z"/><path class="avatar-4-avatar-4-cls-15" d="M363.5,116.33c3.72-2.45,7.13-4.62,9.92-6.06s5-2.06,6-1.12.74,3.29-1,6.3a32.08,32.08,0,0,1-21.71,14.25c-3.46.41-5.77-.25-6.18-1.58s1-3.12,3.44-5.1S359.77,118.77,363.5,116.33Z"/><path class="avatar-4-avatar-4-cls-15" d="M405.25,202a22.88,22.88,0,0,1,7.56-8.1c2.52-1.51,4.63-1.74,5.6-.75s.76,3-.12,5.45a57,57,0,0,1-4.2,8.5,57,57,0,0,1-5.26,7.89c-1.67,2-3.28,3.19-4.65,2.83s-2.2-2.28-2.16-5.22A22.88,22.88,0,0,1,405.25,202Z"/><path class="avatar-4-avatar-4-cls-11" d="M46.05,163.48a38.77,38.77,0,0,1,3.68-7.13,28.5,28.5,0,0,1,4.21-5c2.78-2.58,5.19-3.49,6.27-2.63s.8,3.3-.21,6.55-2.66,7.39-4.44,12-3.35,8.72-4.8,11.81-2.84,5.08-4.27,5-2.54-2.4-2.85-6.18a28.52,28.52,0,0,1,.3-6.56A38.81,38.81,0,0,1,46.05,163.48Z"/><path class="avatar-4-avatar-4-cls-11" d="M77.47,109.21a11.49,11.49,0,0,1,6.45-3c2-.16,3.51.49,4.17,1.73a4.9,4.9,0,0,1-.29,4.37,16,16,0,0,1-8.4,7.53,4.9,4.9,0,0,1-4.37-.18c-1.16-.79-1.64-2.38-1.27-4.33A11.49,11.49,0,0,1,77.47,109.21Z"/><ellipse class="avatar-4-avatar-4-cls-11" cx="210.56" cy="221.64" rx="5.11" ry="8.76" transform="translate(-22.94 418.97) rotate(-86.67)"/><path class="avatar-4-cls-9" d="M224.78,442.79h22.94"/><path class="avatar-4-cls-9" d="M20.87,340A35.55,35.55,0,0,1,42,316.79"/><path class="avatar-4-cls-9" d="M442.19,340A35.55,35.55,0,0,0,421,316.79"/><path class="avatar-4-avatar-4-cls-11" d="M36.71,359.23a58.7,58.7,0,0,1,4.48,7.36c1.06,2.29,1.34,4.25.37,5.29s-2.92,1-5.37-.08a19.33,19.33,0,0,1-8-6.91c-2.49-3.68-3.38-8-2.81-11.09a7,7,0,0,1,1.47-3.46,2.37,2.37,0,0,1,2.07-.95c1.42.21,2.44,1.71,3.61,3.43S35.05,356.75,36.71,359.23Z"/><path class="avatar-4-cls-3" d="M306.74,281.15a53.41,53.41,0,0,0-19.38,5.9c-4.86,2.45-8,4.52-9.27,3.52-.59-.47-.59-1.67.1-3.41a20.9,20.9,0,0,1,4.39-6.38,33.08,33.08,0,0,1,4-3.56,37.32,37.32,0,0,1,5.31-3.26,38.1,38.1,0,0,1,28.15-2.45,37.32,37.32,0,0,1,5.79,2.29,33.07,33.07,0,0,1,4.6,2.8,20.9,20.9,0,0,1,5.43,5.52c1,1.6,1.18,2.78.69,3.34-1.07,1.2-4.53-.29-9.74-1.86A53.41,53.41,0,0,0,306.74,281.15Z"/><path class="avatar-4-cls-9" d="M342.4,280.36a49.37,49.37,0,0,0-70.8,6.17"/><path class="avatar-4-avatar-4-cls-16" d="M264.12,323.48c12.85-5.69,25.89-11.31,39.71-13.84s28.68-1.72,41.06,4.94"/><path class="avatar-3-avatar-4-cls-17" d="M326.2,321.18a17.9,17.9,0,0,1-35.79,0c0-9.88,8-13.77,17.9-13.77S326.2,311.3,326.2,321.18Z"/><path class="avatar-4-cls-3" d="M167.36,281.15a53.41,53.41,0,0,1,19.38,5.9c4.86,2.45,8,4.52,9.27,3.52.59-.47.59-1.67-.1-3.41a20.9,20.9,0,0,0-4.39-6.38,33.08,33.08,0,0,0-4-3.56,37.32,37.32,0,0,0-5.31-3.26A38.1,38.1,0,0,0,154,271.51a37.32,37.32,0,0,0-5.79,2.29,33.07,33.07,0,0,0-4.6,2.8,20.9,20.9,0,0,0-5.43,5.52c-1,1.6-1.18,2.78-.69,3.34,1.07,1.2,4.53-.29,9.74-1.86A53.41,53.41,0,0,1,167.36,281.15Z"/><path class="avatar-4-cls-9" d="M131.69,280.36a49.37,49.37,0,0,1,70.8,6.17"/><path class="avatar-4-avatar-4-cls-16" d="M210,323.48c-12.85-5.69-25.89-11.31-39.71-13.84s-28.68-1.72-41.06,4.94"/><path class="avatar-3-avatar-4-cls-17" d="M147.9,321.18a17.9,17.9,0,0,0,35.79,0c0-9.88-8-13.77-17.9-13.77S147.9,311.3,147.9,321.18Z"/><path class="avatar-4-cls-9" d="M206,498.28A59.24,59.24,0,0,0,236,503c14.26-1.51,29.15-10,32.35-24"/><circle class="avatar-4-cls-2" cx="237.17" cy="528.6" r="10.55" transform="translate(-329.15 406.34) rotate(-53.65)"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/bell.svg b/eims-ui/packages/icons/src/svg/icons/bell.svg
new file mode 100644
index 0000000..90c34e1
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/bell.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 419.23 419.23"><defs><style>.svg-bell-cls-1{fill:#fbc907;}.svg-bell-cls-2{fill:#f3a70f;}.svg-bell-cls-3{fill:#426572;}.svg-bell-cls-4,.svg-bell-cls-9{fill:#fff;}.svg-bell-cls-5{fill:#e8e8e8;}.svg-bell-cls-6{fill:#dadada;}.svg-bell-cls-7{opacity:0.1;}.svg-bell-cls-8{fill:#55e0ff;}.svg-bell-cls-9{opacity:0.4;}</style></defs><title>Asset 510</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><circle class="svg-bell-cls-1" cx="210.66" cy="209.62" r="203.61"/><path class="svg-bell-cls-2" d="M27.21,209.62A203.61,203.61,0,0,1,220.72,6.26q-5-.25-10.08-.25C98.19,4.86,6.11,95.09,5,207.54S94.05,412.07,206.5,413.21q2.07,0,4.13,0,5.06,0,10.08-.25A203.61,203.61,0,0,1,27.21,209.62Z"/><path class="svg-bell-cls-3" d="M209.61,419.23C94,419.23,0,325.19,0,209.61S94,0,209.61,0,419.23,94,419.23,209.61,325.19,419.23,209.61,419.23Zm0-407.23C100.65,12,12,100.65,12,209.61s88.65,197.61,197.61,197.61,197.61-88.65,197.61-197.61S318.58,12,209.61,12Z"/><path class="svg-bell-cls-4" d="M111.69,60.1a195,195,0,0,1,41.08-21.2c3.59-1.34,2-7.14-1.6-5.79a201.47,201.47,0,0,0-42.51,21.8c-3.18,2.15-.18,7.35,3,5.18Z"/><path class="svg-bell-cls-4" d="M35.09,160.61c3.09-10.2,8-20,13.05-29.32A212.37,212.37,0,0,1,95.87,72.18c2.93-2.52-1.33-6.75-4.24-4.24A217.08,217.08,0,0,0,43,128.26C37.63,138,32.54,148.34,29.31,159c-1.12,3.7,4.67,5.29,5.79,1.6Z"/><circle class="svg-bell-cls-5" cx="211.45" cy="212.12" r="156.89"/><path class="svg-bell-cls-6" d="M67.05,232.07a156.89,156.89,0,0,1,283.33-92.82A156.91,156.91,0,1,0,85,304.92,156.19,156.19,0,0,1,67.05,232.07Z"/><path class="svg-bell-cls-5" d="M211.32,152.25h0a9.16,9.16,0,0,1,9.16,9.16V210.5a9.16,9.16,0,0,1-9.16,9.16h0a9.16,9.16,0,0,1-9.16-9.16V161.41A9.16,9.16,0,0,1,211.32,152.25Z"/><circle class="svg-bell-cls-5" cx="211.14" cy="221.32" r="15.94"/><path class="svg-bell-cls-3" d="M210.48,92.62c6.29,0,6.29-9.77,0-9.77S204.19,92.62,210.48,92.62Z"/><path class="svg-bell-cls-3" d="M210.48,343.89c6.29,0,6.29-9.77,0-9.77S204.19,343.89,210.48,343.89Z"/><path class="svg-bell-cls-3" d="M339.84,218.25c6.29,0,6.29-9.77,0-9.77S333.55,218.25,339.84,218.25Z"/><path class="svg-bell-cls-3" d="M81.13,218.25c6.29,0,6.29-9.77,0-9.77S74.84,218.25,81.13,218.25Z"/><path class="svg-bell-cls-3" d="M205.56,153.32h0a9.16,9.16,0,0,1,9.16,9.16v49.09a9.16,9.16,0,0,1-9.16,9.16h0a9.16,9.16,0,0,1-9.16-9.16V162.49A9.16,9.16,0,0,1,205.56,153.32Z"/><circle class="cls-3" cx="205.38" cy="221.15" r="15.94"/><path class="cls-3" d="M135.78,272.58l135.16-89.89L290.11,170c5.22-3.46.33-11.94-4.92-8.44L150,251.4l-19.17,12.74C125.64,267.6,130.52,276.08,135.78,272.58Z"/><g class="svg-bell-cls-7"><ellipse class="svg-bell-cls-8" cx="210.2" cy="211.21" rx="156.89" ry="154.23"/></g><path class="svg-bell-cls-9" d="M243.13,60.17,84.37,301.88a162.18,162.18,0,0,1-18.58-47.29L193.5,60.21a153.88,153.88,0,0,1,49.67,0Z"/><path class="svg-bell-cls-9" d="M289.69,72.6,115.93,325.78a155.09,155.09,0,0,1-14.77-15L270,64.76A155.38,155.38,0,0,1,289.69,72.6Z"/><path class="svg-bell-cls-9" d="M362.16,171.75h0L232.51,360.68h0a160.93,160.93,0,0,1-42.54.43L346.63,132.84A151.63,151.63,0,0,1,362.16,171.75Z"/><path class="cls-3" d="M210.12,369.75c-89.82,0-162.89-71.88-162.89-160.23S120.31,49.29,210.12,49.29,373,121.17,373,209.52,299.94,369.75,210.12,369.75Zm0-308.46c-83.2,0-150.89,66.5-150.89,148.23s67.69,148.23,150.89,148.23S361,291.25,361,209.52,293.32,61.29,210.12,61.29Z"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/cake.svg b/eims-ui/packages/icons/src/svg/icons/cake.svg
new file mode 100644
index 0000000..43901fb
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/cake.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 392.49 390.69"><defs><style>.svg-cake-cls-1{fill:#fff;}.svg-cake-cls-2{fill:#f3aa9f;}.svg-cake-cls-3{fill:#e1978f;}.svg-cake-cls-4,.svg-cake-cls-6{fill:#426572;}.svg-cake-cls-5{fill:#e1d2d5;}.svg-cake-cls-6{font-size:100.43px;font-family:Dosis-ExtraBold, Dosis;font-weight:700;}</style></defs><title>Asset 480</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path class="svg-cake-cls-1" d="M383.9,162H199.69V2.19q4-.19,8.16-.19A176.87,176.87,0,0,1,383.9,162Z"/><path class="svg-cake-cls-2" d="M355.38,210a176.83,176.83,0,0,1-95.72,157.18l-.15.07A176.88,176.88,0,1,1,101.72,50.67l.15-.07a175.93,175.93,0,0,1,72.82-17.4V191H354.37A177.9,177.9,0,0,1,355.38,210Z"/><path class="svg-cake-cls-3" d="M357.53,212.16a176,176,0,0,1-17.44,76.66,1,1,0,0,1-.07.15A176.89,176.89,0,0,1,73.47,352.79l1.23.38q6,1.86,12.26,3.29A177,177,0,0,0,303.49,191h52.78A178.15,178.15,0,0,1,357.53,212.16Z"/><path class="svg-cake-cls-4" d="M182.85,390.69a182.87,182.87,0,0,1-84-345.31l.41-.2a180.59,180.59,0,0,1,75.13-20l6.27-.28V185H364.36l.51,5.44c.54,5.77.82,11.62.82,17.4a180.72,180.72,0,0,1-20.18,83.56c-.06.12-.12.26-.2.41a184.39,184.39,0,0,1-83,80.77l-.18.08,0,0A181.06,181.06,0,0,1,182.85,390.69ZM104.33,56.08A170.88,170.88,0,0,0,256.9,361.85l.17-.08,0,0a172.34,172.34,0,0,0,77.5-75.38l.15-.29a168.84,168.84,0,0,0,18.93-78.23c0-3.6-.11-7.23-.34-10.84H168.69V37.58a168.41,168.41,0,0,0-64.07,18.35Z"/><path class="svg-cake-cls-5" d="M382.9,158H309.11c-2.89-46.4-18.43-98.49-36.89-144.29l1.33.51a177.49,177.49,0,0,1,92.51,83.56A175.63,175.63,0,0,1,382.9,158Z"/><path class="svg-cake-cls-4" d="M392.49,172H195.69V.47L201.4.2C204.11.07,207,0,209.85,0a182.87,182.87,0,0,1,182,165.44Zm-184.8-12H379.18A170.89,170.89,0,0,0,209.85,12h-2.16Z"/><text class="svg-cake-cls-6" transform="translate(232.67 133.93)">%</text><path class="svg-cake-cls-1" d="M101.22,81.14a166.34,166.34,0,0,1,34.83-18c3.58-1.34,2-7.14-1.6-5.79A172.89,172.89,0,0,0,98.19,76c-3.18,2.15-.18,7.35,3,5.18Z"/><path class="svg-cake-cls-1" d="M36.28,166.34c2.62-8.63,6.74-16.94,11.05-24.83A180.58,180.58,0,0,1,87.86,91.34c2.93-2.52-1.33-6.75-4.24-4.24-23.3,20.06-44.07,47.84-53.12,77.65-1.12,3.7,4.67,5.29,5.79,1.6Z"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/card.svg b/eims-ui/packages/icons/src/svg/icons/card.svg
new file mode 100644
index 0000000..40ff3e3
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/card.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 445 271.8"><defs><style>.svg-card-cls-1{fill:#32caf8;}.svg-card-cls-2{fill:#00aaf8;opacity:0.5;}.svg-card-cls-3{fill:#fff;}.svg-card-cls-4{fill:#426572;}</style></defs><g><g><rect class="svg-card-cls-1" x="6" y="8.17" width="433" height="259.8" rx="12" ry="12"/><path class="svg-card-cls-2" d="M439,21.16V255a13,13,0,0,1-13,13H28.72l381-259.8H426A13,13,0,0,1,439,21.16Z"/><path class="svg-card-cls-3" d="M328,33.24h88.92c3.86,0,3.87-6,0-6H328c-3.86,0-3.87,6,0,6Z"/><path class="svg-card-cls-3" d="M283.49,33.24H312.6c3.86,0,3.87-6,0-6H283.49c-3.86,0-3.87,6,0,6Z"/><path class="svg-card-cls-4" d="M427,271.8H18a18,18,0,0,1-18-18V18A18,18,0,0,1,18,0H427a18,18,0,0,1,18,18V253.8A18,18,0,0,1,427,271.8ZM18,12a6,6,0,0,0-6,6V253.8a6,6,0,0,0,6,6H427a6,6,0,0,0,6-6V18a6,6,0,0,0-6-6Z"/><rect class="svg-card-cls-4" x="37.89" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="55.93" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="73.97" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="92.01" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="118.71" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="136.76" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="154.8" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="172.84" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="199.54" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="217.58" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="235.63" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="253.67" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="280.37" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="298.41" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="316.45" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="334.49" y="125.08" width="12" height="20.57"/><rect class="svg-card-cls-4" x="43.89" y="177.53" width="161.29" height="12"/><rect class="svg-card-cls-4" x="43.89" y="204.59" width="68.2" height="12"/><circle class="svg-card-cls-3" cx="379.46" cy="207.35" r="23.82"/><rect class="svg-card-cls-3" x="43.89" y="36.31" width="72.53" height="47.63" rx="12" ry="12"/><path class="svg-card-cls-4" d="M104.42,88.86H55.89a18,18,0,0,1-18-18V47.23a18,18,0,0,1,18-18h48.53a18,18,0,0,1,18,18V70.86A18,18,0,0,1,104.42,88.86ZM55.89,41.23a6,6,0,0,0-6,6V70.86a6,6,0,0,0,6,6h48.53a6,6,0,0,0,6-6V47.23a6,6,0,0,0-6-6Z"/><path class="svg-card-cls-4" d="M379.46,241.49a29.81,29.81,0,1,1,29.82-29.82A29.85,29.85,0,0,1,379.46,241.49Zm0-47.63a17.81,17.81,0,1,0,17.82,17.81A17.84,17.84,0,0,0,379.46,193.86Z"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/download.svg b/eims-ui/packages/icons/src/svg/icons/download.svg
new file mode 100644
index 0000000..af9ff15
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/download.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 356.99 419.8"><defs><style>.svg-download-cls-1{fill:#ffa546;}.svg-download-cls-2{fill:#ff6059;opacity:0.4;}.svg-download-cls-3{fill:#426572;}.cls-4{fill:#ffd947;}</style></defs><g><g><path class="svg-download-cls-1" d="M351,380.73v17.59a15.52,15.52,0,0,1-15.47,15.48H21.46A15.52,15.52,0,0,1,6,398.32V380.73a15.51,15.51,0,0,1,15.47-15.47H335.52A15.51,15.51,0,0,1,351,380.73Z"/><path class="svg-download-cls-2" d="M351,406.85c0,3.95-7,7.19-15.47,7.19H21.46C13,414,6,410.8,6,406.85V380.73a15.51,15.51,0,0,1,15.47-15.47H37.66l3.44,25.27c0,4,7,7.2,15.47,7.2l283.72,12.44,7.38-2.28Z"/><path class="svg-download-cls-3" d="M335.52,419.8H21.46A21.5,21.5,0,0,1,0,398.32V380.73a21.49,21.49,0,0,1,21.46-21.47H335.52A21.49,21.49,0,0,1,357,380.73v17.59a21.52,21.52,0,0,1-21.46,21.48ZM21.46,371.26A9.48,9.48,0,0,0,12,380.73v17.59a9.48,9.48,0,0,0,9.46,9.48H335.52a9.52,9.52,0,0,0,9.46-9.48V380.73a9.48,9.48,0,0,0-9.46-9.47Z"/><path class="svg-download-cls-1" d="M247.93,138H233.23V41.7A35.7,35.7,0,0,0,197.53,6H159.45a35.7,35.7,0,0,0-35.7,35.7V138H109.06C80,138,61.84,169.48,76.37,194.64l34.72,60.13,30,52c16.6,28.76,58.12,28.76,74.72,0l30-52,34.72-60.13C295.14,169.48,277,138,247.93,138Z"/><path class="svg-download-cls-2" d="M280.62,188l-34.73,60.13-30,52c-11.24,19.46-66.68,32.78-52.52,18.88,60.22-59.12,104.3-182.16,104.3-182.16A37.74,37.74,0,0,1,280.62,188Z"/><path class="cls-4" d="M192.3,6c-.22.23-.42.47-.63.72-38.92,45-18.36,116.49-42.85,170.71-10.14,22.45-29.18,41.51-52.15,49.48L78,194.64C63.52,169.48,81.67,138,110.72,138h14.7V41.7A35.7,35.7,0,0,1,161.12,6Z"/><path class="svg-download-cls-3" d="M178.49,334.39h0a48.64,48.64,0,0,1-42.56-24.57L71.17,197.64A43.75,43.75,0,0,1,109.06,132h8.69V41.7A41.74,41.74,0,0,1,159.45,0h38.09a41.75,41.75,0,0,1,41.7,41.7V132h8.69a43.75,43.75,0,0,1,37.89,65.62L221,309.82A48.64,48.64,0,0,1,178.49,334.39ZM109.06,144a31.75,31.75,0,0,0-27.49,47.62l64.76,112.17a37.14,37.14,0,0,0,64.33,0l64.76-112.17A31.75,31.75,0,0,0,247.92,144H227.23V41.7A29.73,29.73,0,0,0,197.53,12H159.45a29.73,29.73,0,0,0-29.7,29.7V144Z"/></g></g></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/message.svg b/eims-ui/packages/icons/src/svg/icons/message.svg
new file mode 100644
index 0000000..9bdbc90
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/message.svg
@@ -0,0 +1 @@
+<svg t="1727417479543" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4291" width="64" height="64"><path d="M240 658.08h220.784l55.744 65.04 55.744-65.04h220.768V272H240v386.08z m-48 32V240a16 16 0 0 1 16-16h617.04a16 16 0 0 1 16 16v450.08a16 16 0 0 1-16 16H594.336l-65.664 76.64a16 16 0 0 1-24.304 0l-65.664-76.64H208a16 16 0 0 1-16-16zM366.256 498.56a33.488 33.488 0 1 1 0-66.992 33.488 33.488 0 0 1 0 66.992z m150.272 0a33.488 33.488 0 1 1 0-66.992 33.488 33.488 0 0 1 0 66.992z m150.24 0a33.488 33.488 0 1 1 0-66.992 33.488 33.488 0 0 1 0 66.992z" fill="#1677ff" p-id="4292"></path></svg>
diff --git a/eims-ui/packages/icons/src/svg/icons/system.svg b/eims-ui/packages/icons/src/svg/icons/system.svg
new file mode 100644
index 0000000..a7e92fd
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/icons/system.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="M6.988 8.608a.5.5 0 0 1-.977-.211v-.005l.02-.072q.015-.062.052-.156c.047-.123.126-.29.25-.46A1.7 1.7 0 0 1 7.753 7c.553 0 1.002.215 1.309.561c.298.337.438.772.438 1.189c0 .349-.069.648-.205.906a1.8 1.8 0 0 1-.507.585a5 5 0 0 1-.48.313l-.056.034c-.168.1-.306.187-.425.29c-.394.341-.652.702-.764 1.122H9a.5.5 0 0 1 0 1H6.5a.5.5 0 0 1-.5-.5c0-1.01.475-1.774 1.173-2.378c.19-.166.396-.29.567-.393l.058-.035a4 4 0 0 0 .379-.244a.8.8 0 0 0 .233-.26a.9.9 0 0 0 .09-.44a.8.8 0 0 0-.187-.526C8.203 8.1 8.03 8 7.753 8c-.33 0-.505.146-.614.295a1 1 0 0 0-.147.3zM11 7a.5.5 0 0 1 .5.5V10H13V7.5a.5.5 0 0 1 1 0v5a.5.5 0 0 1-1 0V11h-2a.5.5 0 0 1-.5-.5v-3A.5.5 0 0 1 11 7m-1-5a8 8 0 1 0 0 16a8 8 0 0 0 0-16m-7 8a7 7 0 1 1 14 0a7 7 0 0 1-14 0"/></svg>
\ No newline at end of file
diff --git a/eims-ui/packages/icons/src/svg/index.ts b/eims-ui/packages/icons/src/svg/index.ts
new file mode 100644
index 0000000..b9554bd
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/index.ts
@@ -0,0 +1,27 @@
+import { createIconifyIcon } from '@vben-core/icons';
+
+import './load.js';
+
+const SvgAvatar1Icon = createIconifyIcon('svg:avatar-1');
+const SvgAvatar2Icon = createIconifyIcon('svg:avatar-2');
+const SvgAvatar3Icon = createIconifyIcon('svg:avatar-3');
+const SvgAvatar4Icon = createIconifyIcon('svg:avatar-4');
+const SvgDownloadIcon = createIconifyIcon('svg:download');
+const SvgCardIcon = createIconifyIcon('svg:card');
+const SvgBellIcon = createIconifyIcon('svg:bell');
+const SvgCakeIcon = createIconifyIcon('svg:cake');
+const SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo');
+
+export {
+  SvgAntdvLogoIcon,
+  SvgAvatar1Icon,
+  SvgAvatar2Icon,
+  SvgAvatar3Icon,
+  SvgAvatar4Icon,
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+};
+
+export { default as SvgMessageUrl } from './icons/message.svg';
diff --git a/eims-ui/packages/icons/src/svg/load.ts b/eims-ui/packages/icons/src/svg/load.ts
new file mode 100644
index 0000000..25f4261
--- /dev/null
+++ b/eims-ui/packages/icons/src/svg/load.ts
@@ -0,0 +1,61 @@
+import type { IconifyIconStructure } from '@vben-core/icons';
+
+import { addIcon } from '@vben-core/icons';
+
+let loaded = false;
+if (!loaded) {
+  loadSvgIcons();
+  loaded = true;
+}
+
+function parseSvg(svgData: string): IconifyIconStructure {
+  const parser = new DOMParser();
+  const xmlDoc = parser.parseFromString(svgData, 'image/svg+xml');
+  const svgElement = xmlDoc.documentElement;
+
+  const svgContent = [...svgElement.childNodes]
+    .filter((node) => node.nodeType === Node.ELEMENT_NODE)
+    .map((node) => new XMLSerializer().serializeToString(node))
+    .join('');
+
+  const viewBoxValue = svgElement.getAttribute('viewBox') || '';
+  const [left, top, width, height] = viewBoxValue.split(' ').map((val) => {
+    const num = Number(val);
+    return Number.isNaN(num) ? undefined : num;
+  });
+
+  return {
+    body: svgContent,
+    height,
+    left,
+    top,
+    width,
+  };
+}
+
+/**
+ * 鑷畾涔夌殑svg鍥剧墖杞寲涓虹粍浠�
+ * @example ./svg/avatar.svg
+ * <Icon icon="svg:avatar"></Icon>
+ */
+async function loadSvgIcons() {
+  const svgEagers = import.meta.glob('./icons/**', {
+    eager: true,
+    query: '?raw',
+  });
+
+  await Promise.all(
+    Object.entries(svgEagers).map((svg) => {
+      const [key, body] = svg as [string, { default: string } | string];
+
+      // ./icons/xxxx.svg => xxxxxx
+      const start = key.lastIndexOf('/') + 1;
+      const end = key.lastIndexOf('.');
+      const iconName = key.slice(start, end);
+
+      return addIcon(`svg:${iconName}`, {
+        ...parseSvg(typeof body === 'object' ? body.default : body),
+      });
+    }),
+  );
+}
diff --git a/eims-ui/packages/icons/tsconfig.json b/eims-ui/packages/icons/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/icons/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/locales/package.json b/eims-ui/packages/locales/package.json
new file mode 100644
index 0000000..de1dc42
--- /dev/null
+++ b/eims-ui/packages/locales/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "@vben/locales",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/locales"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@intlify/core-base": "catalog:",
+    "@vben-core/composables": "workspace:*",
+    "vue": "catalog:",
+    "vue-i18n": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/locales/src/i18n.ts b/eims-ui/packages/locales/src/i18n.ts
new file mode 100644
index 0000000..99259c3
--- /dev/null
+++ b/eims-ui/packages/locales/src/i18n.ts
@@ -0,0 +1,146 @@
+import type { Locale } from 'vue-i18n';
+
+import type {
+  ImportLocaleFn,
+  LoadMessageFn,
+  LocaleSetupOptions,
+  SupportedLanguagesType,
+} from './typing';
+
+import { type App, unref } from 'vue';
+import { createI18n } from 'vue-i18n';
+
+import { useSimpleLocale } from '@vben-core/composables';
+
+const i18n = createI18n({
+  globalInjection: true,
+  legacy: false,
+  locale: '',
+  messages: {},
+});
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const { setSimpleLocale } = useSimpleLocale();
+
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
+let loadMessages: LoadMessageFn;
+
+/**
+ * Load locale modules
+ * @param modules
+ */
+function loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {
+  const localesMap: Record<Locale, ImportLocaleFn> = {};
+
+  for (const [path, loadLocale] of Object.entries(modules)) {
+    const key = path.match(/([\w-]*)\.(json)/)?.[1];
+    if (key) {
+      localesMap[key] = loadLocale as ImportLocaleFn;
+    }
+  }
+  return localesMap;
+}
+
+/**
+ * Load locale modules with directory structure
+ * @param regexp - Regular expression to match language and file names
+ * @param modules - The modules object containing paths and import functions
+ * @returns A map of locales to their corresponding import functions
+ */
+function loadLocalesMapFromDir(
+  regexp: RegExp,
+  modules: Record<string, () => Promise<unknown>>,
+): Record<Locale, ImportLocaleFn> {
+  const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};
+  const localesMap: Record<Locale, ImportLocaleFn> = {};
+
+  // Iterate over the modules to extract language and file names
+  for (const path in modules) {
+    const match = path.match(regexp);
+    if (match) {
+      const [_, locale, fileName] = match;
+      if (locale && fileName) {
+        if (!localesRaw[locale]) {
+          localesRaw[locale] = {};
+        }
+        if (modules[path]) {
+          localesRaw[locale][fileName] = modules[path];
+        }
+      }
+    }
+  }
+
+  // Convert raw locale data into async import functions
+  for (const [locale, files] of Object.entries(localesRaw)) {
+    localesMap[locale] = async () => {
+      const messages: Record<string, any> = {};
+      for (const [fileName, importFn] of Object.entries(files)) {
+        messages[fileName] = ((await importFn()) as any)?.default;
+      }
+      return { default: messages };
+    };
+  }
+
+  return localesMap;
+}
+
+/**
+ * Set i18n language
+ * @param locale
+ */
+function setI18nLanguage(locale: Locale) {
+  i18n.global.locale.value = locale;
+
+  document?.querySelector('html')?.setAttribute('lang', locale);
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+  const { defaultLocale = 'zh-CN' } = options;
+  // app鍙互鑷鎵╁睍涓�浜涚涓夋柟搴撳拰缁勪欢搴撶殑鍥介檯鍖�
+  loadMessages = options.loadMessages || (async () => ({}));
+  app.use(i18n);
+  await loadLocaleMessages(defaultLocale);
+
+  // 鍦ㄦ帶鍒跺彴鎵撳嵃璀﹀憡
+  i18n.global.setMissingHandler((locale, key) => {
+    if (options.missingWarn && key.includes('.')) {
+      console.warn(
+        `[intlify] Not found '${key}' key in '${locale}' locale messages.`,
+      );
+    }
+  });
+}
+
+/**
+ * Load locale messages
+ * @param lang
+ */
+async function loadLocaleMessages(lang: SupportedLanguagesType) {
+  if (unref(i18n.global.locale) === lang) {
+    return setI18nLanguage(lang);
+  }
+  setSimpleLocale(lang);
+
+  const message = await localesMap[lang]?.();
+
+  if (message?.default) {
+    i18n.global.setLocaleMessage(lang, message.default);
+  }
+
+  const mergeMessage = await loadMessages(lang);
+  i18n.global.mergeLocaleMessage(lang, mergeMessage);
+
+  return setI18nLanguage(lang);
+}
+
+export {
+  i18n,
+  loadLocaleMessages,
+  loadLocalesMap,
+  loadLocalesMapFromDir,
+  setupI18n,
+};
diff --git a/eims-ui/packages/locales/src/index.ts b/eims-ui/packages/locales/src/index.ts
new file mode 100644
index 0000000..eb2251a
--- /dev/null
+++ b/eims-ui/packages/locales/src/index.ts
@@ -0,0 +1,28 @@
+import {
+  i18n,
+  loadLocaleMessages,
+  loadLocalesMap,
+  loadLocalesMapFromDir,
+  setupI18n,
+} from './i18n';
+
+const $t = i18n.global.t;
+
+export {
+  $t,
+  i18n,
+  loadLocaleMessages,
+  loadLocalesMap,
+  loadLocalesMapFromDir,
+  setupI18n,
+};
+export {
+  type ImportLocaleFn,
+  type LocaleSetupOptions,
+  type SupportedLanguagesType,
+} from './typing';
+export type { CompileError } from '@intlify/core-base';
+
+export { useI18n } from 'vue-i18n';
+
+export type { Locale } from 'vue-i18n';
diff --git a/eims-ui/packages/locales/src/langs/en-US/authentication.json b/eims-ui/packages/locales/src/langs/en-US/authentication.json
new file mode 100644
index 0000000..4155f87
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/en-US/authentication.json
@@ -0,0 +1,56 @@
+{
+  "welcomeBack": "Welcome Back",
+  "pageTitle": "Plug-and-play Admin system",
+  "pageDesc": "Efficient, versatile frontend template",
+  "loginSuccess": "Login Successful",
+  "loginSuccessDesc": "Welcome Back",
+  "loginSubtitle": "Enter your account details to manage your projects",
+  "selectAccount": "Quick Select Account",
+  "username": "Username",
+  "password": "Password",
+  "usernameTip": "Please enter username",
+  "passwordErrorTip": "Password is incorrect",
+  "passwordTip": "Please enter password",
+  "verifyRequiredTip": "Please complete the verification first",
+  "rememberMe": "Remember Me",
+  "createAnAccount": "Create an Account",
+  "createAccount": "Create Account",
+  "alreadyHaveAccount": "Already have an account?",
+  "accountTip": "Don't have an account?",
+  "signUp": "Sign Up",
+  "signUpSubtitle": "Make managing your applications simple and fun",
+  "confirmPassword": "Confirm Password",
+  "confirmPasswordTip": "The passwords do not match",
+  "agree": "I agree to",
+  "privacyPolicy": "Privacy-policy",
+  "terms": "Terms",
+  "agreeTip": "Please agree to the Privacy Policy and Terms",
+  "goToLogin": "Login instead",
+  "passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols",
+  "forgetPassword": "Forget Password?",
+  "forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password",
+  "emailTip": "Please enter email",
+  "emailValidErrorTip": "The email format you entered is incorrect",
+  "sendResetLink": "Send Reset Link",
+  "email": "Email",
+  "qrcodeSubtitle": "Scan the QR code with your phone to login",
+  "qrcodePrompt": "Click 'Confirm' after scanning to complete login",
+  "qrcodeLogin": "QR Code Login",
+  "codeSubtitle": "Enter your phone number to start managing your project",
+  "code": "Security code",
+  "codeTip": "Security code is required",
+  "mobile": "Mobile",
+  "mobileLogin": "Mobile Login",
+  "mobileTip": "Please enter mobile number",
+  "mobileErrortip": "The phone number format is incorrect",
+  "sendCode": "Get Security code",
+  "sendText": "Resend in {0}s",
+  "thirdPartyLogin": "Or continue with",
+  "loginAgainTitle": "Please Log In Again",
+  "loginAgainSubTitle": "Your login session has expired. Please log in again to continue.",
+  "layout": {
+    "center": "Align Center",
+    "alignLeft": "Align Left",
+    "alignRight": "Align Right"
+  }
+}
diff --git a/eims-ui/packages/locales/src/langs/en-US/common.json b/eims-ui/packages/locales/src/langs/en-US/common.json
new file mode 100644
index 0000000..23308b7
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/en-US/common.json
@@ -0,0 +1,13 @@
+{
+  "back": "Back",
+  "backToHome": "Back To Home",
+  "login": "Login",
+  "logout": "Logout",
+  "prompt": "Prompt",
+  "cancel": "Cancel",
+  "confirm": "Confirm",
+  "noData": "No Data",
+  "refresh": "Refresh",
+  "loadingMenu": "Loading Menu",
+  "query": "Search"
+}
diff --git a/eims-ui/packages/locales/src/langs/en-US/preferences.json b/eims-ui/packages/locales/src/langs/en-US/preferences.json
new file mode 100644
index 0000000..8ba3cce
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/en-US/preferences.json
@@ -0,0 +1,169 @@
+{
+  "title": "Preferences",
+  "subtitle": "Customize Preferences & Preview in Real Time",
+  "resetTip": "Data has changed, click to reset",
+  "resetTitle": "Reset Preferences",
+  "resetSuccess": "Preferences reset successfully",
+  "appearance": "Appearance",
+  "layout": "Layout",
+  "content": "Content",
+  "other": "Other",
+  "wide": "Wide",
+  "compact": "Fixed",
+  "followSystem": "Follow System",
+  "vertical": "Vertical",
+  "verticalTip": "Side vertical menu mode",
+  "horizontal": "Horizontal",
+  "horizontalTip": "Horizontal menu mode, all menus displayed at the top",
+  "twoColumn": "Two Column",
+  "twoColumnTip": "Vertical Two Column Menu Mode",
+  "mixedMenu": "Mixed Menu",
+  "mixedMenuTip": "Vertical & Horizontal Menu Co-exists",
+  "fullContent": "Full Content",
+  "fullContentTip": "Only display content body, hide all menus",
+  "normal": "Normal",
+  "plain": "Plain",
+  "rounded": "Rounded",
+  "copyPreferences": "Copy Preferences",
+  "copyPreferencesSuccessTitle": "Copy successful",
+  "copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app",
+  "clearAndLogout": "Clear Cache & Logout",
+  "mode": "Mode",
+  "general": "General",
+  "language": "Language",
+  "dynamicTitle": "Dynamic Title",
+  "watermark": "Watermark",
+  "checkUpdates": "Periodic update check",
+  "position": {
+    "title": "Preferences Postion",
+    "header": "Header",
+    "auto": "Auto",
+    "fixed": "Fixed"
+  },
+  "sidebar": {
+    "title": "Sidebar",
+    "width": "Width",
+    "visible": "Show Sidebar",
+    "collapsed": "Collpase Menu",
+    "collapsedShowTitle": "Show Menu Title"
+  },
+  "tabbar": {
+    "title": "Tabbar",
+    "enable": "Enable Tab Bar",
+    "icon": "Show Tabbar Icon",
+    "showMore": "Show More Button",
+    "showMaximize": "Show Maximize Button",
+    "persist": "Persist Tabs",
+    "draggable": "Enable Draggable Sort",
+    "styleType": {
+      "title": "Tabs Style",
+      "chrome": "Chrome",
+      "card": "Card",
+      "plain": "Plain",
+      "brisk": "Brisk"
+    },
+    "contextMenu": {
+      "reload": "Reload",
+      "close": "Close",
+      "pin": "Pin",
+      "unpin": "Unpin",
+      "closeLeft": "Close Left Tabs",
+      "closeRight": "Close Right Tabs",
+      "closeOther": "Close Other Tabs",
+      "closeAll": "Close All Tabs",
+      "openInNewWindow": "Open in New Window",
+      "maximize": "Maximize",
+      "restoreMaximize": "Restore"
+    }
+  },
+  "navigationMenu": {
+    "title": "Navigation Menu",
+    "style": "Navigation Menu Style",
+    "accordion": "Sidebar Accordion Menu",
+    "split": "Navigation Menu Separation",
+    "splitTip": "When enabled, the sidebar displays the top bar's submenu"
+  },
+  "breadcrumb": {
+    "title": "Breadcrumb",
+    "home": "Show Home Button",
+    "enable": "Enable Breadcrumb",
+    "icon": "Show Breadcrumb Icon",
+    "background": "background",
+    "style": "Breadcrumb Style",
+    "hideOnlyOne": "Hidden when only one"
+  },
+  "animation": {
+    "title": "Animation",
+    "loading": "Page Loading",
+    "transition": "Page Transition",
+    "progress": "Page Progress"
+  },
+  "theme": {
+    "title": "Theme",
+    "radius": "Radius",
+    "light": "Light",
+    "dark": "Dark",
+    "darkSidebar": "Semi Dark Sidebar",
+    "darkHeader": "Semi Dark Header",
+    "weakMode": "Weak Mode",
+    "grayMode": "Gray Mode",
+    "builtin": {
+      "title": "Built-in",
+      "default": "Default",
+      "violet": "Violet",
+      "pink": "Pink",
+      "rose": "Rose",
+      "skyBlue": "Sky Blue",
+      "deepBlue": "Deep Blue",
+      "green": "Green",
+      "deepGreen": "Deep Green",
+      "orange": "Orange",
+      "yellow": "Yellow",
+      "zinc": "Zinc",
+      "neutral": "Neutral",
+      "slate": "Slate",
+      "gray": "Gray",
+      "custom": "Custom"
+    }
+  },
+  "header": {
+    "title": "Header",
+    "visible": "Show Header",
+    "modeStatic": "Static",
+    "modeFixed": "Fixed",
+    "modeAuto": "Auto hide & Show",
+    "modeAutoScroll": "Scroll to Hide & Show"
+  },
+  "footer": {
+    "title": "Footer",
+    "visible": "Show Footer",
+    "fixed": "Fixed at Bottom"
+  },
+  "copyright": {
+    "title": "Copyright",
+    "enable": "Enable Copyright",
+    "companyName": "Company Name",
+    "companySiteLink": "Company Site Link",
+    "date": "Date",
+    "icp": "ICP License Number",
+    "icpLink": "ICP Site Link"
+  },
+  "shortcutKeys": {
+    "title": "Shortcut Keys",
+    "global": "Global",
+    "search": "Global Search",
+    "logout": "Logout",
+    "preferences": "Preferences"
+  },
+  "widget": {
+    "title": "Widget",
+    "globalSearch": "Enable Global Search",
+    "fullscreen": "Enable Fullscreen",
+    "themeToggle": "Enable Theme Toggle",
+    "languageToggle": "Enable Language Toggle",
+    "notification": "Enable Notification",
+    "sidebarToggle": "Enable Sidebar Toggle",
+    "lockScreen": "Enable Lock Screen",
+    "refresh": "Enable Refresh"
+  }
+}
diff --git a/eims-ui/packages/locales/src/langs/en-US/ui.json b/eims-ui/packages/locales/src/langs/en-US/ui.json
new file mode 100644
index 0000000..d2a3d1c
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/en-US/ui.json
@@ -0,0 +1,82 @@
+{
+  "formRules": {
+    "required": "Please enter {0}",
+    "selectRequired": "Please select {0}"
+  },
+  "placeholder": {
+    "input": "Please enter",
+    "select": "Please select"
+  },
+  "captcha": {
+    "title": "Please complete the security verification",
+    "sliderSuccessText": "Passed",
+    "sliderDefaultText": "Slider and drag",
+    "alt": "Supports img tag src attribute value",
+    "sliderRotateDefaultTip": "Click picture to refresh",
+    "sliderRotateFailTip": "Validation failed",
+    "sliderRotateSuccessTip": "Validation successful, time {0} seconds",
+    "refreshAriaLabel": "Refresh captcha",
+    "confirmAriaLabel": "Confirm selection",
+    "confirm": "Confirm",
+    "pointAriaLabel": "Click point",
+    "clickInOrder": "Please click in order"
+  },
+  "iconPicker": {
+    "placeholder": "Select an icon",
+    "search": "Search icon..."
+  },
+  "fallback": {
+    "pageNotFound": "Oops! Page Not Found",
+    "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",
+    "forbidden": "Oops! Access Denied",
+    "forbiddenDesc": "Sorry, but you don't have permission to access this page.",
+    "internalError": "Oops! Something Went Wrong",
+    "internalErrorDesc": "Sorry, but the server encountered an error.",
+    "offline": "Offline Page",
+    "offlineError": "Oops! Network Error",
+    "offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.",
+    "comingSoon": "Coming Soon",
+    "http": {
+      "requestTimeout": "The request timed out. Please try again later.",
+      "networkError": "A network error occurred. Please check your internet connection and try again.",
+      "badRequest": "Bad Request. Please check your input and try again.",
+      "unauthorized": "Unauthorized. Please log in to continue.",
+      "forbidden": "Forbidden. You do not have permission to access this resource.",
+      "notFound": "Not Found. The requested resource could not be found.",
+      "internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later."
+    }
+  },
+  "widgets": {
+    "document": "Document",
+    "profile": "Profile",
+    "qa": "Q&A",
+    "setting": "Settings",
+    "logoutTip": "Do you want to logout?",
+    "viewAll": "View All Messages",
+    "notifications": "Notifications",
+    "markAllAsRead": "Make All as Read",
+    "clearNotifications": "Clear",
+    "checkUpdatesTitle": "New Version Available",
+    "checkUpdatesDescription": "Click to refresh and get the latest version",
+    "search": {
+      "title": "Search",
+      "searchNavigate": "Search Navigation",
+      "select": "Select",
+      "navigate": "Navigate",
+      "close": "Close",
+      "noResults": "No Search Results Found",
+      "noRecent": "No Search History",
+      "recent": "Search History"
+    },
+    "lockScreen": {
+      "title": "Lock Screen",
+      "screenButton": "Locking",
+      "password": "Password",
+      "placeholder": "Please enter password",
+      "unlock": "Click to unlock",
+      "errorPasswordTip": "Password error, please re-enter",
+      "backToLogin": "Back to login",
+      "entry": "Enter the system"
+    }
+  }
+}
diff --git a/eims-ui/packages/locales/src/langs/zh-CN/authentication.json b/eims-ui/packages/locales/src/langs/zh-CN/authentication.json
new file mode 100644
index 0000000..4533db8
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/zh-CN/authentication.json
@@ -0,0 +1,56 @@
+{
+  "welcomeBack": "娆㈣繋鍥炴潵",
+  "pageTitle": "寮�绠卞嵆鐢ㄧ殑澶у瀷涓悗鍙扮鐞嗙郴缁�",
+  "pageDesc": "宸ョ▼鍖栥�侀珮鎬ц兘銆佽法缁勪欢搴撶殑鍓嶇妯$増",
+  "loginSuccess": "鐧诲綍鎴愬姛",
+  "loginSuccessDesc": "娆㈣繋鍥炴潵",
+  "loginSubtitle": "璇疯緭鍏ユ偍鐨勫笎鎴蜂俊鎭互寮�濮嬬鐞嗘偍鐨勯」鐩�",
+  "selectAccount": "蹇�熼�夋嫨璐﹀彿",
+  "username": "璐﹀彿",
+  "password": "瀵嗙爜",
+  "usernameTip": "璇疯緭鍏ョ敤鎴峰悕",
+  "passwordTip": "璇疯緭鍏ュ瘑鐮�",
+  "verifyRequiredTip": "璇峰厛瀹屾垚楠岃瘉",
+  "passwordErrorTip": "瀵嗙爜閿欒",
+  "rememberMe": "璁颁綇璐﹀彿",
+  "createAnAccount": "鍒涘缓涓�涓处鍙�",
+  "createAccount": "鍒涘缓璐﹀彿",
+  "alreadyHaveAccount": "宸茬粡鏈夎处鍙蜂簡?",
+  "accountTip": "杩樻病鏈夎处鍙�?",
+  "signUp": "娉ㄥ唽",
+  "signUpSubtitle": "璁╂偍鐨勫簲鐢ㄧ▼搴忕鐞嗗彉寰楃畝鍗曡�屾湁瓒�",
+  "confirmPassword": "纭瀵嗙爜",
+  "confirmPasswordTip": "涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�",
+  "agree": "鎴戝悓鎰�",
+  "privacyPolicy": "闅愮鏀跨瓥",
+  "terms": "鏉℃",
+  "agreeTip": "璇峰悓鎰忛殣绉佹斂绛栧拰鏉℃",
+  "goToLogin": "鍘荤櫥褰�",
+  "passwordStrength": "浣跨敤 8 涓垨鏇村瀛楃锛屾贩鍚堝瓧姣嶃�佹暟瀛楀拰绗﹀彿",
+  "forgetPassword": "蹇樿瀵嗙爜?",
+  "forgetPasswordSubtitle": "杈撳叆鎮ㄧ殑鐢靛瓙閭欢锛屾垜浠皢鍚戞偍鍙戦�侀噸缃瘑鐮佺殑杩炴帴",
+  "emailTip": "璇疯緭鍏ラ偖绠�",
+  "emailValidErrorTip": "浣犺緭鍏ョ殑閭鏍煎紡涓嶆纭�",
+  "sendResetLink": "鍙戦�侀噸缃摼鎺�",
+  "email": "閭",
+  "qrcodeSubtitle": "璇风敤鎵嬫満鎵弿浜岀淮鐮佺櫥褰�",
+  "qrcodePrompt": "鎵爜鍚庣偣鍑� '纭'锛屽嵆鍙畬鎴愮櫥褰�",
+  "qrcodeLogin": "鎵爜鐧诲綍",
+  "codeSubtitle": "璇疯緭鍏ユ偍鐨勬墜鏈哄彿鐮佷互寮�濮嬬鐞嗘偍鐨勯」鐩�",
+  "code": "楠岃瘉鐮�",
+  "codeTip": "璇疯緭鍏ラ獙璇佺爜",
+  "mobile": "鎵嬫満鍙风爜",
+  "mobileTip": "璇疯緭鍏ユ墜鏈哄彿",
+  "mobileErrortip": "鎵嬫満鍙风爜鏍煎紡閿欒",
+  "mobileLogin": "鎵嬫満鍙风櫥褰�",
+  "sendCode": "鑾峰彇楠岃瘉鐮�",
+  "sendText": "{0}绉掑悗閲嶆柊鑾峰彇",
+  "thirdPartyLogin": "鍏朵粬鐧诲綍鏂瑰紡",
+  "loginAgainTitle": "閲嶆柊鐧诲綍",
+  "loginAgainSubTitle": "鎮ㄧ殑鐧诲綍鐘舵�佸凡杩囨湡锛岃閲嶆柊鐧诲綍浠ョ户缁��",
+  "layout": {
+    "center": "灞呬腑",
+    "alignLeft": "灞呭乏",
+    "alignRight": "灞呭彸"
+  }
+}
diff --git a/eims-ui/packages/locales/src/langs/zh-CN/common.json b/eims-ui/packages/locales/src/langs/zh-CN/common.json
new file mode 100644
index 0000000..fdfc6e4
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/zh-CN/common.json
@@ -0,0 +1,13 @@
+{
+  "back": "杩斿洖",
+  "backToHome": "杩斿洖棣栭〉",
+  "login": "鐧诲綍",
+  "logout": "閫�鍑虹櫥褰�",
+  "prompt": "鎻愮ず",
+  "cancel": "鍙栨秷",
+  "confirm": "纭",
+  "noData": "鏆傛棤鏁版嵁",
+  "refresh": "鍒锋柊",
+  "loadingMenu": "鍔犺浇鑿滃崟涓�",
+  "query": "鏌ヨ"
+}
diff --git a/eims-ui/packages/locales/src/langs/zh-CN/preferences.json b/eims-ui/packages/locales/src/langs/zh-CN/preferences.json
new file mode 100644
index 0000000..8f5038e
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/zh-CN/preferences.json
@@ -0,0 +1,169 @@
+{
+  "title": "鍋忓ソ璁剧疆",
+  "subtitle": "鑷畾涔夊亸濂借缃� & 瀹炴椂棰勮",
+  "resetTitle": "閲嶇疆鍋忓ソ璁剧疆",
+  "resetTip": "鏁版嵁鏈夊彉鍖栵紝鐐瑰嚮鍙繘琛岄噸缃�",
+  "resetSuccess": "閲嶇疆鍋忓ソ璁剧疆鎴愬姛",
+  "appearance": "澶栬",
+  "layout": "甯冨眬",
+  "content": "鍐呭",
+  "other": "鍏跺畠",
+  "wide": "娴佸紡",
+  "compact": "瀹氬",
+  "followSystem": "璺熼殢绯荤粺",
+  "vertical": "鍨傜洿",
+  "verticalTip": "渚ц竟鍨傜洿鑿滃崟妯″紡",
+  "horizontal": "姘村钩",
+  "horizontalTip": "姘村钩鑿滃崟妯″紡锛岃彍鍗曞叏閮ㄦ樉绀哄湪椤堕儴",
+  "twoColumn": "鍙屽垪鑿滃崟",
+  "twoColumnTip": "鍨傜洿鍙屽垪鑿滃崟妯″紡",
+  "mixedMenu": "娣峰悎鑿滃崟",
+  "mixedMenuTip": "鍨傜洿姘村钩鑿滃崟鍏卞瓨",
+  "fullContent": "鍐呭鍏ㄥ睆",
+  "fullContentTip": "涓嶆樉绀轰换浣曡彍鍗曪紝鍙樉绀哄唴瀹逛富浣�",
+  "normal": "甯歌",
+  "plain": "鏈寸礌",
+  "rounded": "鍦嗘鼎",
+  "copyPreferences": "澶嶅埗鍋忓ソ璁剧疆",
+  "copyPreferencesSuccessTitle": "澶嶅埗鎴愬姛",
+  "copyPreferencesSuccess": "澶嶅埗鎴愬姛锛岃鍦� app 涓嬬殑 `src/preferences.ts`鍐呰繘琛岃鐩�",
+  "clearAndLogout": "娓呯┖缂撳瓨 & 閫�鍑虹櫥褰�",
+  "mode": "妯″紡",
+  "general": "閫氱敤",
+  "language": "璇█",
+  "dynamicTitle": "鍔ㄦ�佹爣棰�",
+  "watermark": "姘村嵃",
+  "checkUpdates": "瀹氭椂妫�鏌ユ洿鏂�",
+  "position": {
+    "title": "鍋忓ソ璁剧疆浣嶇疆",
+    "header": "椤舵爮",
+    "auto": "鑷姩",
+    "fixed": "鍥哄畾"
+  },
+  "sidebar": {
+    "title": "渚ц竟鏍�",
+    "width": "瀹藉害",
+    "visible": "鏄剧ず渚ц竟鏍�",
+    "collapsed": "鎶樺彔鑿滃崟",
+    "collapsedShowTitle": "鎶樺彔鏄剧ず鑿滃崟鍚�"
+  },
+  "tabbar": {
+    "title": "鏍囩鏍�",
+    "enable": "鍚敤鏍囩鏍�",
+    "icon": "鏄剧ず鏍囩鏍忓浘鏍�",
+    "showMore": "鏄剧ず鏇村鎸夐挳",
+    "showMaximize": "鏄剧ず鏈�澶у寲鎸夐挳",
+    "persist": "鎸佷箙鍖栨爣绛鹃〉",
+    "draggable": "鍚姩鎷栨嫿鎺掑簭",
+    "styleType": {
+      "title": "鏍囩椤甸鏍�",
+      "chrome": "璋锋瓕",
+      "card": "鍗$墖",
+      "plain": "鏈寸礌",
+      "brisk": "杞诲揩"
+    },
+    "contextMenu": {
+      "reload": "閲嶆柊鍔犺浇",
+      "close": "鍏抽棴",
+      "pin": "鍥哄畾",
+      "unpin": "鍙栨秷鍥哄畾",
+      "closeLeft": "鍏抽棴宸︿晶鏍囩椤�",
+      "closeRight": "鍏抽棴鍙充晶鏍囩椤�",
+      "closeOther": "鍏抽棴鍏跺畠鏍囩椤�",
+      "closeAll": "鍏抽棴鍏ㄩ儴鏍囩椤�",
+      "openInNewWindow": "鍦ㄦ柊绐楀彛鎵撳紑",
+      "maximize": "鏈�澶у寲",
+      "restoreMaximize": "杩樺師"
+    }
+  },
+  "navigationMenu": {
+    "title": "瀵艰埅鑿滃崟",
+    "style": "瀵艰埅鑿滃崟椋庢牸",
+    "accordion": "渚ц竟瀵艰埅鑿滃崟鎵嬮鐞存ā寮�",
+    "split": "瀵艰埅鑿滃崟鍒嗙",
+    "splitTip": "寮�鍚椂锛屼晶杈规爮鏄剧ず椤舵爮瀵瑰簲鑿滃崟鐨勫瓙鑿滃崟"
+  },
+  "breadcrumb": {
+    "title": "闈㈠寘灞戝鑸�",
+    "enable": "寮�鍚潰鍖呭睉瀵艰埅",
+    "icon": "鏄剧ず闈㈠寘灞戝浘鏍�",
+    "home": "鏄剧ず棣栭〉鎸夐挳",
+    "style": "闈㈠寘灞戦鏍�",
+    "hideOnlyOne": "浠呮湁涓�涓椂闅愯棌",
+    "background": "鑳屾櫙"
+  },
+  "animation": {
+    "title": "鍔ㄧ敾",
+    "loading": "椤甸潰鍒囨崲 Loading",
+    "transition": "椤甸潰鍒囨崲鍔ㄧ敾",
+    "progress": "椤甸潰鍒囨崲杩涘害鏉�"
+  },
+  "theme": {
+    "title": "涓婚",
+    "radius": "鍦嗚",
+    "light": "娴呰壊",
+    "dark": "娣辫壊",
+    "darkSidebar": "娣辫壊渚ц竟鏍�",
+    "darkHeader": "娣辫壊椤舵爮",
+    "weakMode": "鑹插急妯″紡",
+    "grayMode": "鐏拌壊妯″紡",
+    "builtin": {
+      "title": "鍐呯疆涓婚",
+      "default": "榛樿",
+      "violet": "绱綏鍏�",
+      "pink": "妯辫姳绮�",
+      "rose": "鐜懓绾�",
+      "skyBlue": "澶╄摑鑹�",
+      "deepBlue": "娣辫摑鑹�",
+      "green": "娴呯豢鑹�",
+      "deepGreen": "娣辩豢鑹�",
+      "orange": "姗欓粍鑹�",
+      "yellow": "鏌犳榛�",
+      "zinc": "閿岃壊鐏�",
+      "neutral": "涓�ц壊",
+      "slate": "鐭虫澘鐏�",
+      "gray": "涓伆鑹�",
+      "custom": "鑷畾涔�"
+    }
+  },
+  "header": {
+    "title": "椤舵爮",
+    "modeStatic": "闈欐",
+    "modeFixed": "鍥哄畾",
+    "modeAuto": "鑷姩闅愯棌鍜屾樉绀�",
+    "modeAutoScroll": "婊氬姩闅愯棌鍜屾樉绀�",
+    "visible": "鏄剧ず椤舵爮"
+  },
+  "footer": {
+    "title": "搴曟爮",
+    "visible": "鏄剧ず搴曟爮",
+    "fixed": "鍥哄畾鍦ㄥ簳閮�"
+  },
+  "copyright": {
+    "title": "鐗堟潈",
+    "enable": "鍚敤鐗堟潈",
+    "companyName": "鍏徃鍚�",
+    "companySiteLink": "鍏徃涓婚〉",
+    "date": "鏃ユ湡",
+    "icp": "ICP 澶囨鍙�",
+    "icpLink": "ICP 缃戠珯閾炬帴"
+  },
+  "shortcutKeys": {
+    "title": "蹇嵎閿�",
+    "global": "鍏ㄥ眬",
+    "search": "鍏ㄥ眬鎼滅储",
+    "logout": "閫�鍑虹櫥褰�",
+    "preferences": "鍋忓ソ璁剧疆"
+  },
+  "widget": {
+    "title": "灏忛儴浠�",
+    "globalSearch": "鍚敤鍏ㄥ眬鎼滅储",
+    "fullscreen": "鍚敤鍏ㄥ睆",
+    "themeToggle": "鍚敤涓婚鍒囨崲",
+    "languageToggle": "鍚敤璇█鍒囨崲",
+    "notification": "鍚敤閫氱煡",
+    "sidebarToggle": "鍚敤渚ц竟鏍忓垏鎹�",
+    "lockScreen": "鍚敤閿佸睆",
+    "refresh": "鍚敤鍒锋柊"
+  }
+}
diff --git a/eims-ui/packages/locales/src/langs/zh-CN/ui.json b/eims-ui/packages/locales/src/langs/zh-CN/ui.json
new file mode 100644
index 0000000..1d30d1d
--- /dev/null
+++ b/eims-ui/packages/locales/src/langs/zh-CN/ui.json
@@ -0,0 +1,82 @@
+{
+  "formRules": {
+    "required": "璇疯緭鍏0}",
+    "selectRequired": "璇烽�夋嫨{0}"
+  },
+  "placeholder": {
+    "input": "璇疯緭鍏�",
+    "select": "璇烽�夋嫨"
+  },
+  "captcha": {
+    "title": "璇峰畬鎴愬畨鍏ㄩ獙璇�",
+    "sliderSuccessText": "楠岃瘉閫氳繃",
+    "sliderDefaultText": "璇锋寜浣忔粦鍧楁嫋鍔�",
+    "sliderRotateDefaultTip": "鐐瑰嚮鍥剧墖鍙埛鏂�",
+    "sliderRotateFailTip": "楠岃瘉澶辫触",
+    "sliderRotateSuccessTip": "楠岃瘉鎴愬姛锛岃�楁椂{0}绉�",
+    "alt": "鏀寔img鏍囩src灞炴�у��",
+    "refreshAriaLabel": "鍒锋柊楠岃瘉鐮�",
+    "confirmAriaLabel": "纭閫夋嫨",
+    "confirm": "纭",
+    "pointAriaLabel": "鐐瑰嚮鐐�",
+    "clickInOrder": "璇蜂緷娆$偣鍑�"
+  },
+  "iconPicker": {
+    "placeholder": "閫夋嫨涓�涓浘鏍�",
+    "search": "鎼滅储鍥炬爣..."
+  },
+  "fallback": {
+    "pageNotFound": "鍝庡憖锛佹湭鎵惧埌椤甸潰",
+    "pageNotFoundDesc": "鎶辨瓑锛屾垜浠棤娉曟壘鍒版偍瑕佹壘鐨勯〉闈€��",
+    "forbidden": "鍝庡憖锛佽闂鎷掔粷",
+    "forbiddenDesc": "鎶辨瓑锛屾偍娌℃湁鏉冮檺璁块棶姝ら〉闈€��",
+    "internalError": "鍝庡憖锛佸嚭閿欎簡",
+    "internalErrorDesc": "鎶辨瓑锛屾湇鍔″櫒閬囧埌閿欒銆�",
+    "offline": "绂荤嚎椤甸潰",
+    "offlineError": "鍝庡憖锛佺綉缁滈敊璇�",
+    "offlineErrorDesc": "鎶辨瓑锛屾棤娉曡繛鎺ュ埌浜掕仈缃戯紝璇锋鏌ユ偍鐨勭綉缁滆繛鎺ュ苟閲嶈瘯銆�",
+    "comingSoon": "鍗冲皢鎺ㄥ嚭",
+    "http": {
+      "requestTimeout": "璇锋眰瓒呮椂锛岃绋嶅悗鍐嶈瘯銆�",
+      "networkError": "缃戠粶寮傚父锛岃妫�鏌ユ偍鐨勭綉缁滆繛鎺ュ悗閲嶈瘯銆�",
+      "badRequest": "璇锋眰閿欒銆傝妫�鏌ユ偍鐨勮緭鍏ュ苟閲嶈瘯銆�",
+      "unauthorized": "鐧诲綍璁よ瘉杩囨湡锛岃閲嶆柊鐧诲綍鍚庣户缁��",
+      "forbidden": "绂佹璁块棶, 鎮ㄦ病鏈夋潈闄愯闂璧勬簮銆�",
+      "notFound": "鏈壘鍒�, 璇锋眰鐨勮祫婧愪笉瀛樺湪銆�",
+      "internalServerError": "鍐呴儴鏈嶅姟鍣ㄩ敊璇紝璇风◢鍚庡啀璇曘��"
+    }
+  },
+  "widgets": {
+    "document": "鏂囨。",
+    "profile": "涓汉涓績",
+    "qa": "闂 & 甯姪",
+    "setting": "璁剧疆",
+    "logoutTip": "鏄惁閫�鍑虹櫥褰曪紵",
+    "viewAll": "鏌ョ湅鎵�鏈夋秷鎭�",
+    "notifications": "閫氱煡",
+    "markAllAsRead": "鍏ㄩ儴鏍囪涓哄凡璇�",
+    "clearNotifications": "娓呯┖",
+    "checkUpdatesTitle": "鏂扮増鏈彲鐢�",
+    "checkUpdatesDescription": "鐐瑰嚮鍒锋柊浠ヨ幏鍙栨渶鏂扮増鏈�",
+    "search": {
+      "title": "鎼滅储",
+      "searchNavigate": "鎼滅储瀵艰埅鑿滃崟",
+      "select": "閫夋嫨",
+      "navigate": "瀵艰埅",
+      "close": "鍏抽棴",
+      "noResults": "鏈壘鍒版悳绱㈢粨鏋�",
+      "noRecent": "娌℃湁鎼滅储鍘嗗彶",
+      "recent": "鎼滅储鍘嗗彶"
+    },
+    "lockScreen": {
+      "title": "閿佸畾灞忓箷",
+      "screenButton": "閿佸畾",
+      "password": "瀵嗙爜",
+      "placeholder": "璇疯緭鍏ラ攣灞忓瘑鐮�",
+      "unlock": "鐐瑰嚮瑙i攣",
+      "errorPasswordTip": "瀵嗙爜閿欒锛岃閲嶆柊杈撳叆",
+      "backToLogin": "杩斿洖鐧诲綍",
+      "entry": "杩涘叆绯荤粺"
+    }
+  }
+}
diff --git a/eims-ui/packages/locales/src/typing.ts b/eims-ui/packages/locales/src/typing.ts
new file mode 100644
index 0000000..fdebac2
--- /dev/null
+++ b/eims-ui/packages/locales/src/typing.ts
@@ -0,0 +1,25 @@
+export type SupportedLanguagesType = 'en-US' | 'zh-CN';
+
+export type ImportLocaleFn = () => Promise<{ default: Record<string, string> }>;
+
+export type LoadMessageFn = (
+  lang: SupportedLanguagesType,
+) => Promise<Record<string, string> | undefined>;
+
+export interface LocaleSetupOptions {
+  /**
+   * Default language
+   * @default zh-CN
+   */
+  defaultLocale?: SupportedLanguagesType;
+  /**
+   * Load message function
+   * @param lang
+   * @returns
+   */
+  loadMessages?: LoadMessageFn;
+  /**
+   * Whether to warn when the key is not found
+   */
+  missingWarn?: boolean;
+}
diff --git a/eims-ui/packages/locales/tsconfig.json b/eims-ui/packages/locales/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/locales/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/preferences/package.json b/eims-ui/packages/preferences/package.json
new file mode 100644
index 0000000..6797c37
--- /dev/null
+++ b/eims-ui/packages/preferences/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "@vben/preferences",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/preferences"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/preferences": "workspace:*",
+    "@vben-core/typings": "workspace:*"
+  }
+}
diff --git a/eims-ui/packages/preferences/src/index.ts b/eims-ui/packages/preferences/src/index.ts
new file mode 100644
index 0000000..75fab43
--- /dev/null
+++ b/eims-ui/packages/preferences/src/index.ts
@@ -0,0 +1,17 @@
+import type { Preferences } from '@vben-core/preferences';
+import type { DeepPartial } from '@vben-core/typings';
+
+/**
+ * 濡傛灉浣犳兂鎵�鏈夌殑app閮戒娇鐢ㄧ浉鍚岀殑榛樿鍋忓ソ璁剧疆锛屼綘鍙互鍦ㄨ繖閲屽畾涔�
+ * 鑰屼笉鏄幓淇敼 @vben-core/preferences 涓殑榛樿鍋忓ソ璁剧疆
+ * @param preferences
+ * @returns
+ */
+
+function defineOverridesPreferences(preferences: DeepPartial<Preferences>) {
+  return preferences;
+}
+
+export { defineOverridesPreferences };
+
+export * from '@vben-core/preferences';
diff --git a/eims-ui/packages/preferences/tsconfig.json b/eims-ui/packages/preferences/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/preferences/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/stores/package.json b/eims-ui/packages/stores/package.json
new file mode 100644
index 0000000..a579c18
--- /dev/null
+++ b/eims-ui/packages/stores/package.json
@@ -0,0 +1,30 @@
+{
+  "name": "@vben/stores",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/stores"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "pinia": "catalog:",
+    "pinia-plugin-persistedstate": "catalog:",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/stores/shim-pinia.d.ts b/eims-ui/packages/stores/shim-pinia.d.ts
new file mode 100644
index 0000000..69be75d
--- /dev/null
+++ b/eims-ui/packages/stores/shim-pinia.d.ts
@@ -0,0 +1,9 @@
+// https://github.com/vuejs/pinia/issues/2098
+declare module 'pinia' {
+  export function acceptHMRUpdate(
+    initialUseStore: any | StoreDefinition,
+    hot: any,
+  ): (newModule: any) => any;
+}
+
+export {};
diff --git a/eims-ui/packages/stores/src/index.ts b/eims-ui/packages/stores/src/index.ts
new file mode 100644
index 0000000..41b3662
--- /dev/null
+++ b/eims-ui/packages/stores/src/index.ts
@@ -0,0 +1,3 @@
+export * from './modules';
+export * from './setup';
+export { defineStore, storeToRefs } from 'pinia';
diff --git a/eims-ui/packages/stores/src/modules/access.test.ts b/eims-ui/packages/stores/src/modules/access.test.ts
new file mode 100644
index 0000000..211e256
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/access.test.ts
@@ -0,0 +1,46 @@
+import { createPinia, setActivePinia } from 'pinia';
+import { beforeEach, describe, expect, it } from 'vitest';
+
+import { useAccessStore } from './access';
+
+describe('useAccessStore', () => {
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('updates accessMenus state', () => {
+    const store = useAccessStore();
+    expect(store.accessMenus).toEqual([]);
+    store.setAccessMenus([{ name: 'Dashboard', path: '/dashboard' }]);
+    expect(store.accessMenus).toEqual([
+      { name: 'Dashboard', path: '/dashboard' },
+    ]);
+  });
+
+  it('updates accessToken state correctly', () => {
+    const store = useAccessStore();
+    expect(store.accessToken).toBeNull(); // 鍒濆鐘舵��
+    store.setAccessToken('abc123');
+    expect(store.accessToken).toBe('abc123');
+  });
+
+  it('returns the correct accessToken', () => {
+    const store = useAccessStore();
+    store.setAccessToken('xyz789');
+    expect(store.accessToken).toBe('xyz789');
+  });
+
+  // 娴嬭瘯璁剧疆绌虹殑璁块棶鑿滃崟鍒楄〃
+  it('handles empty accessMenus correctly', () => {
+    const store = useAccessStore();
+    store.setAccessMenus([]);
+    expect(store.accessMenus).toEqual([]);
+  });
+
+  // 娴嬭瘯璁剧疆绌虹殑璁块棶璺敱鍒楄〃
+  it('handles empty accessRoutes correctly', () => {
+    const store = useAccessStore();
+    store.setAccessRoutes([]);
+    expect(store.accessRoutes).toEqual([]);
+  });
+});
diff --git a/eims-ui/packages/stores/src/modules/access.ts b/eims-ui/packages/stores/src/modules/access.ts
new file mode 100644
index 0000000..ee8641a
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/access.ts
@@ -0,0 +1,85 @@
+import type { MenuRecordRaw } from '@vben-core/typings';
+import type { RouteRecordRaw } from 'vue-router';
+
+import { acceptHMRUpdate, defineStore } from 'pinia';
+
+type AccessToken = null | string;
+
+interface AccessState {
+  /**
+   * 鏉冮檺鐮�
+   */
+  accessCodes: string[];
+  /**
+   * 鍙闂殑鑿滃崟鍒楄〃
+   */
+  accessMenus: MenuRecordRaw[];
+  /**
+   * 鍙闂殑璺敱鍒楄〃
+   */
+  accessRoutes: RouteRecordRaw[];
+  /**
+   * 鐧诲綍 accessToken
+   */
+  accessToken: AccessToken;
+  /**
+   * 鏄惁宸茬粡妫�鏌ヨ繃鏉冮檺
+   */
+  isAccessChecked: boolean;
+  /**
+   * 鐧诲綍鏄惁杩囨湡
+   */
+  loginExpired: boolean;
+  /**
+   * 鐧诲綍 accessToken
+   */
+  refreshToken: AccessToken;
+}
+
+/**
+ * @zh_CN 璁块棶鏉冮檺鐩稿叧
+ */
+export const useAccessStore = defineStore('core-access', {
+  actions: {
+    setAccessCodes(codes: string[]) {
+      this.accessCodes = codes;
+    },
+    setAccessMenus(menus: MenuRecordRaw[]) {
+      this.accessMenus = menus;
+    },
+    setAccessRoutes(routes: RouteRecordRaw[]) {
+      this.accessRoutes = routes;
+    },
+    setAccessToken(token: AccessToken) {
+      this.accessToken = token;
+    },
+    setIsAccessChecked(isAccessChecked: boolean) {
+      this.isAccessChecked = isAccessChecked;
+    },
+    setLoginExpired(loginExpired: boolean) {
+      this.loginExpired = loginExpired;
+    },
+    setRefreshToken(token: AccessToken) {
+      this.refreshToken = token;
+    },
+  },
+  persist: {
+    // 鎸佷箙鍖�
+    pick: ['accessToken', 'refreshToken', 'accessCodes'],
+  },
+  state: (): AccessState => ({
+    accessCodes: [],
+    accessMenus: [],
+    accessRoutes: [],
+    accessToken: null,
+    isAccessChecked: false,
+    loginExpired: false,
+    refreshToken: null,
+  }),
+});
+
+// 瑙e喅鐑洿鏂伴棶棰�
+const hot = import.meta.hot;
+if (hot) {
+  hot.accept(acceptHMRUpdate(useAccessStore, hot));
+}
diff --git a/eims-ui/packages/stores/src/modules/index.ts b/eims-ui/packages/stores/src/modules/index.ts
new file mode 100644
index 0000000..7941cbe
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/index.ts
@@ -0,0 +1,4 @@
+export * from './access';
+export * from './lock';
+export * from './tabbar';
+export * from './user';
diff --git a/eims-ui/packages/stores/src/modules/lock.test.ts b/eims-ui/packages/stores/src/modules/lock.test.ts
new file mode 100644
index 0000000..d8dbe55
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/lock.test.ts
@@ -0,0 +1,31 @@
+import { createPinia, setActivePinia } from 'pinia';
+import { beforeEach, describe, expect, it } from 'vitest';
+
+import { useLockStore } from './lock';
+
+describe('useLockStore', () => {
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('should initialize with correct default state', () => {
+    const store = useLockStore();
+    expect(store.isLockScreen).toBe(false);
+    expect(store.lockScreenPassword).toBeUndefined();
+  });
+
+  it('should lock screen with a password', () => {
+    const store = useLockStore();
+    store.lockScreen('1234');
+    expect(store.isLockScreen).toBe(true);
+    expect(store.lockScreenPassword).toBe('1234');
+  });
+
+  it('should unlock screen and clear password', () => {
+    const store = useLockStore();
+    store.lockScreen('1234');
+    store.unlockScreen();
+    expect(store.isLockScreen).toBe(false);
+    expect(store.lockScreenPassword).toBeUndefined();
+  });
+});
diff --git a/eims-ui/packages/stores/src/modules/lock.ts b/eims-ui/packages/stores/src/modules/lock.ts
new file mode 100644
index 0000000..76a9600
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/lock.ts
@@ -0,0 +1,33 @@
+import { defineStore } from 'pinia';
+
+interface AppState {
+  /**
+   * 鏄惁閿佸睆鐘舵��
+   */
+  isLockScreen: boolean;
+  /**
+   * 閿佸睆瀵嗙爜
+   */
+  lockScreenPassword?: string;
+}
+
+export const useLockStore = defineStore('core-lock', {
+  actions: {
+    lockScreen(password: string) {
+      this.isLockScreen = true;
+      this.lockScreenPassword = password;
+    },
+
+    unlockScreen() {
+      this.isLockScreen = false;
+      this.lockScreenPassword = undefined;
+    },
+  },
+  persist: {
+    pick: ['isLockScreen', 'lockScreenPassword'],
+  },
+  state: (): AppState => ({
+    isLockScreen: false,
+    lockScreenPassword: undefined,
+  }),
+});
diff --git a/eims-ui/packages/stores/src/modules/tabbar.test.ts b/eims-ui/packages/stores/src/modules/tabbar.test.ts
new file mode 100644
index 0000000..d74615c
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/tabbar.test.ts
@@ -0,0 +1,295 @@
+import { createRouter, createWebHistory } from 'vue-router';
+
+import { createPinia, setActivePinia } from 'pinia';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { useTabbarStore } from './tabbar';
+
+describe('useAccessStore', () => {
+  const router = createRouter({
+    history: createWebHistory(),
+    routes: [],
+  });
+  router.push = vi.fn();
+  router.replace = vi.fn();
+  beforeEach(() => {
+    setActivePinia(createPinia());
+    vi.clearAllMocks();
+  });
+
+  it('adds a new tab', () => {
+    const store = useTabbarStore();
+    const tab: any = {
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    };
+    store.addTab(tab);
+    expect(store.tabs.length).toBe(1);
+    expect(store.tabs[0]).toEqual(tab);
+  });
+
+  it('adds a new tab if it does not exist', () => {
+    const store = useTabbarStore();
+    const newTab: any = {
+      fullPath: '/new',
+      meta: {},
+      name: 'New',
+      path: '/new',
+    };
+    store.addTab(newTab);
+    expect(store.tabs).toContainEqual(newTab);
+  });
+
+  it('updates an existing tab instead of adding a new one', () => {
+    const store = useTabbarStore();
+    const initialTab: any = {
+      fullPath: '/existing',
+      meta: {},
+      name: 'Existing',
+      path: '/existing',
+      query: {},
+    };
+    store.tabs.push(initialTab);
+    const updatedTab = { ...initialTab, query: { id: '1' } };
+    store.addTab(updatedTab);
+    expect(store.tabs.length).toBe(1);
+    expect(store.tabs[0]?.query).toEqual({ id: '1' });
+  });
+
+  it('closes all tabs', async () => {
+    const store = useTabbarStore();
+    store.tabs = [
+      { fullPath: '/home', meta: {}, name: 'Home', path: '/home' },
+    ] as any;
+    router.replace = vi.fn();
+
+    await store.closeAllTabs(router);
+
+    expect(store.tabs.length).toBe(1);
+  });
+
+  it('closes a non-affix tab', () => {
+    const store = useTabbarStore();
+    const tab: any = {
+      fullPath: '/closable',
+      meta: {},
+      name: 'Closable',
+      path: '/closable',
+    };
+    store.tabs.push(tab);
+    store._close(tab);
+    expect(store.tabs.length).toBe(0);
+  });
+
+  it('does not close an affix tab', () => {
+    const store = useTabbarStore();
+    const affixTab: any = {
+      fullPath: '/affix',
+      meta: { affixTab: true },
+      name: 'Affix',
+      path: '/affix',
+    };
+    store.tabs.push(affixTab);
+    store._close(affixTab);
+    expect(store.tabs.length).toBe(1); // Affix tab should not be closed
+  });
+
+  it('returns all cache tabs', () => {
+    const store = useTabbarStore();
+    store.cachedTabs.add('Home');
+    store.cachedTabs.add('About');
+    expect(store.getCachedTabs).toEqual(['Home', 'About']);
+  });
+
+  it('returns all tabs, including affix tabs', () => {
+    const store = useTabbarStore();
+    const normalTab: any = {
+      fullPath: '/normal',
+      meta: {},
+      name: 'Normal',
+      path: '/normal',
+    };
+    const affixTab: any = {
+      fullPath: '/affix',
+      meta: { affixTab: true },
+      name: 'Affix',
+      path: '/affix',
+    };
+    store.tabs.push(normalTab);
+    store.affixTabs.push(affixTab);
+    expect(store.getTabs).toContainEqual(normalTab);
+    expect(store.affixTabs).toContainEqual(affixTab);
+  });
+
+  it('navigates to a specific tab', async () => {
+    const store = useTabbarStore();
+    const tab: any = { meta: {}, name: 'Dashboard', path: '/dashboard' };
+
+    await store._goToTab(tab, router);
+
+    expect(router.replace).toHaveBeenCalledWith({
+      params: {},
+      path: '/dashboard',
+      query: {},
+    });
+  });
+
+  it('closes multiple tabs by paths', async () => {
+    const store = useTabbarStore();
+    store.addTab({
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    } as any);
+    store.addTab({
+      fullPath: '/about',
+      meta: {},
+      name: 'About',
+      path: '/about',
+    } as any);
+    store.addTab({
+      fullPath: '/contact',
+      meta: {},
+      name: 'Contact',
+      path: '/contact',
+    } as any);
+
+    await store._bulkCloseByPaths(['/home', '/contact']);
+
+    expect(store.tabs).toHaveLength(1);
+    expect(store.tabs[0]?.name).toBe('About');
+  });
+
+  it('closes all tabs to the left of the specified tab', async () => {
+    const store = useTabbarStore();
+    store.addTab({
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    } as any);
+    store.addTab({
+      fullPath: '/about',
+      meta: {},
+      name: 'About',
+      path: '/about',
+    } as any);
+    const targetTab: any = {
+      fullPath: '/contact',
+      meta: {},
+      name: 'Contact',
+      path: '/contact',
+    };
+    store.addTab(targetTab);
+
+    await store.closeLeftTabs(targetTab);
+
+    expect(store.tabs).toHaveLength(1);
+    expect(store.tabs[0]?.name).toBe('Contact');
+  });
+
+  it('closes all tabs except the specified tab', async () => {
+    const store = useTabbarStore();
+    store.addTab({
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    } as any);
+    const targetTab: any = {
+      fullPath: '/about',
+      meta: {},
+      name: 'About',
+      path: '/about',
+    };
+    store.addTab(targetTab);
+    store.addTab({
+      fullPath: '/contact',
+      meta: {},
+      name: 'Contact',
+      path: '/contact',
+    } as any);
+
+    await store.closeOtherTabs(targetTab);
+
+    expect(store.tabs).toHaveLength(1);
+    expect(store.tabs[0]?.name).toBe('About');
+  });
+
+  it('closes all tabs to the right of the specified tab', async () => {
+    const store = useTabbarStore();
+    const targetTab: any = {
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    };
+    store.addTab(targetTab);
+    store.addTab({
+      fullPath: '/about',
+      meta: {},
+      name: 'About',
+      path: '/about',
+    } as any);
+    store.addTab({
+      fullPath: '/contact',
+      meta: {},
+      name: 'Contact',
+      path: '/contact',
+    } as any);
+
+    await store.closeRightTabs(targetTab);
+
+    expect(store.tabs).toHaveLength(1);
+    expect(store.tabs[0]?.name).toBe('Home');
+  });
+
+  it('closes the tab with the specified key', async () => {
+    const store = useTabbarStore();
+    const keyToClose = '/about';
+    store.addTab({
+      fullPath: '/home',
+      meta: {},
+      name: 'Home',
+      path: '/home',
+    } as any);
+    store.addTab({
+      fullPath: keyToClose,
+      meta: {},
+      name: 'About',
+      path: '/about',
+    } as any);
+    store.addTab({
+      fullPath: '/contact',
+      meta: {},
+      name: 'Contact',
+      path: '/contact',
+    } as any);
+
+    await store.closeTabByKey(keyToClose, router);
+
+    expect(store.tabs).toHaveLength(2);
+    expect(
+      store.tabs.find((tab) => tab.fullPath === keyToClose),
+    ).toBeUndefined();
+  });
+
+  it('refreshes the current tab', async () => {
+    const store = useTabbarStore();
+    const currentTab: any = {
+      fullPath: '/dashboard',
+      meta: { name: 'Dashboard' },
+      name: 'Dashboard',
+      path: '/dashboard',
+    };
+    router.currentRoute.value = currentTab;
+
+    await store.refresh(router);
+
+    expect(store.excludeCachedTabs.has('Dashboard')).toBe(false);
+    expect(store.renderRouteView).toBe(true);
+  });
+});
diff --git a/eims-ui/packages/stores/src/modules/tabbar.ts b/eims-ui/packages/stores/src/modules/tabbar.ts
new file mode 100644
index 0000000..53a74fe
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/tabbar.ts
@@ -0,0 +1,558 @@
+import type { TabDefinition } from '@vben-core/typings';
+import type { Router, RouteRecordNormalized } from 'vue-router';
+
+import { toRaw } from 'vue';
+
+import {
+  openRouteInNewWindow,
+  startProgress,
+  stopProgress,
+} from '@vben-core/shared/utils';
+
+import { acceptHMRUpdate, defineStore } from 'pinia';
+
+interface TabbarState {
+  /**
+   * @zh_CN 褰撳墠鎵撳紑鐨勬爣绛鹃〉鍒楄〃缂撳瓨
+   */
+  cachedTabs: Set<string>;
+  /**
+   * @zh_CN 鎷栨嫿缁撴潫鐨勭储寮�
+   */
+  dragEndIndex: number;
+  /**
+   * @zh_CN 闇�瑕佹帓闄ょ紦瀛樼殑鏍囩椤�
+   */
+  excludeCachedTabs: Set<string>;
+  /**
+   * @zh_CN 鏄惁鍒锋柊
+   */
+  renderRouteView?: boolean;
+  /**
+   * @zh_CN 褰撳墠鎵撳紑鐨勬爣绛鹃〉鍒楄〃
+   */
+  tabs: TabDefinition[];
+  /**
+   * @zh_CN 鏇存柊鏃堕棿锛岀敤浜庝竴浜涙洿鏂板満鏅紝浣跨敤watch娣卞害鐩戝惉鐨勮瘽锛屼細鎹熻�楁�ц兘
+   */
+  updateTime?: number;
+}
+
+/**
+ * @zh_CN 璁块棶鏉冮檺鐩稿叧
+ */
+export const useTabbarStore = defineStore('core-tabbar', {
+  actions: {
+    /**
+     * Close tabs in bulk
+     */
+    async _bulkCloseByPaths(paths: string[]) {
+      this.tabs = this.tabs.filter((item) => {
+        return !paths.includes(getTabPath(item));
+      });
+
+      this.updateCacheTabs();
+    },
+    /**
+     * @zh_CN 鍏抽棴鏍囩椤�
+     * @param tab
+     */
+    _close(tab: TabDefinition) {
+      const { fullPath } = tab;
+      if (isAffixTab(tab)) {
+        return;
+      }
+      const index = this.tabs.findIndex((item) => item.fullPath === fullPath);
+      index !== -1 && this.tabs.splice(index, 1);
+    },
+    /**
+     * @zh_CN 璺宠浆鍒伴粯璁ゆ爣绛鹃〉
+     */
+    async _goToDefaultTab(router: Router) {
+      if (this.getTabs.length <= 0) {
+        return;
+      }
+      const firstTab = this.getTabs[0];
+      if (firstTab) {
+        await this._goToTab(firstTab, router);
+      }
+    },
+    /**
+     * @zh_CN 璺宠浆鍒版爣绛鹃〉
+     * @param tab
+     * @param router
+     */
+    async _goToTab(tab: TabDefinition, router: Router) {
+      const { params, path, query } = tab;
+      const toParams = {
+        params: params || {},
+        path,
+        query: query || {},
+      };
+      await router.replace(toParams);
+    },
+    /**
+     * @zh_CN 娣诲姞鏍囩椤�
+     * @param routeTab
+     */
+    addTab(routeTab: TabDefinition) {
+      const tab = cloneTab(routeTab);
+      if (!isTabShown(tab)) {
+        return;
+      }
+
+      const tabIndex = this.tabs.findIndex((tab) => {
+        return getTabPath(tab) === getTabPath(routeTab);
+      });
+
+      if (tabIndex === -1) {
+        // 鑾峰彇鍔ㄦ�佽矾鐢辨墦寮�鏁帮紝瓒呰繃 0 鍗充唬琛ㄩ渶瑕佹帶鍒舵墦寮�鏁�
+        const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??
+          -1) as number;
+        // 濡傛灉鍔ㄦ�佽矾鐢卞眰绾уぇ浜� 0 浜嗭紝閭d箞灏辫闄愬埗璇ヨ矾鐢辩殑鎵撳紑鏁伴檺鍒朵簡
+        // 鑾峰彇鍒板凡缁忔墦寮�鐨勫姩鎬佽矾鐢辨暟, 鍒ゆ柇鏄惁澶т簬鏌愪竴涓��
+        if (
+          maxNumOfOpenTab > 0 &&
+          this.tabs.filter((tab) => tab.name === routeTab.name).length >=
+            maxNumOfOpenTab
+        ) {
+          // 鍏抽棴绗竴涓�
+          const index = this.tabs.findIndex(
+            (item) => item.name === routeTab.name,
+          );
+          index !== -1 && this.tabs.splice(index, 1);
+        }
+
+        this.tabs.push(tab);
+      } else {
+        // 椤甸潰宸茬粡瀛樺湪锛屼笉閲嶅娣诲姞閫夐」鍗★紝鍙洿鏂伴�夐」鍗″弬鏁�
+        const currentTab = toRaw(this.tabs)[tabIndex];
+        const mergedTab = {
+          ...currentTab,
+          ...tab,
+          meta: { ...currentTab?.meta, ...tab.meta },
+        };
+        if (currentTab) {
+          const curMeta = currentTab.meta;
+          if (Reflect.has(curMeta, 'affixTab')) {
+            mergedTab.meta.affixTab = curMeta.affixTab;
+          }
+          if (Reflect.has(curMeta, 'newTabTitle')) {
+            mergedTab.meta.newTabTitle = curMeta.newTabTitle;
+          }
+        }
+
+        this.tabs.splice(tabIndex, 1, mergedTab);
+      }
+      this.updateCacheTabs();
+    },
+    /**
+     * @zh_CN 鍏抽棴鎵�鏈夋爣绛鹃〉
+     */
+    async closeAllTabs(router: Router) {
+      const newTabs = this.tabs.filter((tab) => isAffixTab(tab));
+      this.tabs = newTabs.length > 0 ? newTabs : [...this.tabs].splice(0, 1);
+      await this._goToDefaultTab(router);
+      this.updateCacheTabs();
+    },
+    /**
+     * @zh_CN 鍏抽棴宸︿晶鏍囩椤�
+     * @param tab
+     */
+    async closeLeftTabs(tab: TabDefinition) {
+      const index = this.tabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+
+      if (index < 1) {
+        return;
+      }
+
+      const leftTabs = this.tabs.slice(0, index);
+      const paths: string[] = [];
+
+      for (const item of leftTabs) {
+        if (!isAffixTab(item)) {
+          paths.push(getTabPath(item));
+        }
+      }
+      await this._bulkCloseByPaths(paths);
+    },
+    /**
+     * @zh_CN 鍏抽棴鍏朵粬鏍囩椤�
+     * @param tab
+     */
+    async closeOtherTabs(tab: TabDefinition) {
+      const closePaths = this.tabs.map((item) => getTabPath(item));
+
+      const paths: string[] = [];
+
+      for (const path of closePaths) {
+        if (path !== tab.fullPath) {
+          const closeTab = this.tabs.find((item) => getTabPath(item) === path);
+          if (!closeTab) {
+            continue;
+          }
+          if (!isAffixTab(closeTab)) {
+            paths.push(getTabPath(closeTab));
+          }
+        }
+      }
+      await this._bulkCloseByPaths(paths);
+    },
+    /**
+     * @zh_CN 鍏抽棴鍙充晶鏍囩椤�
+     * @param tab
+     */
+    async closeRightTabs(tab: TabDefinition) {
+      const index = this.tabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+
+      if (index !== -1 && index < this.tabs.length - 1) {
+        const rightTabs = this.tabs.slice(index + 1);
+
+        const paths: string[] = [];
+        for (const item of rightTabs) {
+          if (!isAffixTab(item)) {
+            paths.push(getTabPath(item));
+          }
+        }
+        await this._bulkCloseByPaths(paths);
+      }
+    },
+
+    /**
+     * @zh_CN 鍏抽棴鏍囩椤�
+     * @param tab
+     * @param router
+     */
+    async closeTab(tab: TabDefinition, router: Router) {
+      const { currentRoute } = router;
+
+      // 鍏抽棴涓嶆槸婵�娲婚�夐」鍗�
+      if (getTabPath(currentRoute.value) !== getTabPath(tab)) {
+        this._close(tab);
+        this.updateCacheTabs();
+        return;
+      }
+      const index = this.getTabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(currentRoute.value),
+      );
+
+      const before = this.getTabs[index - 1];
+      const after = this.getTabs[index + 1];
+
+      // 涓嬩竴涓猼ab瀛樺湪锛岃烦杞埌涓嬩竴涓�
+      if (after) {
+        this._close(tab);
+        await this._goToTab(after, router);
+        // 涓婁竴涓猼ab瀛樺湪锛岃烦杞埌涓婁竴涓�
+      } else if (before) {
+        this._close(tab);
+        await this._goToTab(before, router);
+      } else {
+        console.error('Failed to close the tab; only one tab remains open.');
+      }
+    },
+
+    /**
+     * @zh_CN 閫氳繃key鍏抽棴鏍囩椤�
+     * @param key
+     * @param router
+     */
+    async closeTabByKey(key: string, router: Router) {
+      const originKey = decodeURIComponent(key);
+      const index = this.tabs.findIndex(
+        (item) => getTabPath(item) === originKey,
+      );
+      if (index === -1) {
+        return;
+      }
+
+      const tab = this.tabs[index];
+      if (tab) {
+        await this.closeTab(tab, router);
+      }
+    },
+
+    /**
+     * 鏍规嵁璺緞鑾峰彇鏍囩椤�
+     * @param path
+     */
+    getTabByPath(path: string) {
+      return this.getTabs.find(
+        (item) => getTabPath(item) === path,
+      ) as TabDefinition;
+    },
+    /**
+     * @zh_CN 鏂扮獥鍙f墦寮�鏍囩椤�
+     * @param tab
+     */
+    async openTabInNewWindow(tab: TabDefinition) {
+      openRouteInNewWindow(tab.fullPath || tab.path);
+    },
+
+    /**
+     * @zh_CN 鍥哄畾鏍囩椤�
+     * @param tab
+     */
+    async pinTab(tab: TabDefinition) {
+      const index = this.tabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+      if (index !== -1) {
+        const oldTab = this.tabs[index];
+        tab.meta.affixTab = true;
+        tab.meta.title = oldTab?.meta?.title as string;
+        // this.addTab(tab);
+        this.tabs.splice(index, 1, tab);
+      }
+      // 杩囨护鍥哄畾tabs锛屽悗闈㈡洿鏀筧ffixTabOrder鐨勫�肩殑璇濆彲鑳戒細鏈夐棶棰橈紝鐩墠琛�464鎺掑簭affixTabs娌℃湁璁剧疆鍊�
+      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));
+      // 鑾峰緱鍥哄畾tabs鐨刬ndex
+      const newIndex = affixTabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+      // 浜ゆ崲浣嶇疆閲嶆柊鎺掑簭
+      await this.sortTabs(index, newIndex);
+    },
+
+    /**
+     * 鍒锋柊鏍囩椤�
+     */
+    async refresh(router: Router) {
+      const { currentRoute } = router;
+      const { name } = currentRoute.value;
+
+      this.excludeCachedTabs.add(name as string);
+      this.renderRouteView = false;
+      startProgress();
+
+      await new Promise((resolve) => setTimeout(resolve, 200));
+
+      this.excludeCachedTabs.delete(name as string);
+      this.renderRouteView = true;
+      stopProgress();
+    },
+
+    /**
+     * @zh_CN 閲嶇疆鏍囩椤垫爣棰�
+     */
+    async resetTabTitle(tab: TabDefinition) {
+      if (tab?.meta?.newTabTitle) {
+        return;
+      }
+      const findTab = this.tabs.find(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+      if (findTab) {
+        findTab.meta.newTabTitle = undefined;
+        await this.updateCacheTabs();
+      }
+    },
+
+    /**
+     * 璁剧疆鍥哄畾鏍囩椤�
+     * @param tabs
+     */
+    setAffixTabs(tabs: RouteRecordNormalized[]) {
+      for (const tab of tabs) {
+        tab.meta.affixTab = true;
+        this.addTab(routeToTab(tab));
+      }
+    },
+
+    /**
+     * @zh_CN 璁剧疆鏍囩椤垫爣棰�
+     * @param tab
+     * @param title
+     */
+    async setTabTitle(tab: TabDefinition, title: string) {
+      const findTab = this.tabs.find(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+
+      if (findTab) {
+        findTab.meta.newTabTitle = title;
+
+        await this.updateCacheTabs();
+      }
+    },
+
+    setUpdateTime() {
+      this.updateTime = Date.now();
+    },
+    /**
+     * @zh_CN 璁剧疆鏍囩椤甸『搴�
+     * @param oldIndex
+     * @param newIndex
+     */
+    async sortTabs(oldIndex: number, newIndex: number) {
+      const currentTab = this.tabs[oldIndex];
+      if (!currentTab) {
+        return;
+      }
+      this.tabs.splice(oldIndex, 1);
+      this.tabs.splice(newIndex, 0, currentTab);
+      this.dragEndIndex = this.dragEndIndex + 1;
+    },
+    /**
+     * @zh_CN 鍒囨崲鍥哄畾鏍囩椤�
+     * @param tab
+     */
+    async toggleTabPin(tab: TabDefinition) {
+      const affixTab = tab?.meta?.affixTab ?? false;
+
+      await (affixTab ? this.unpinTab(tab) : this.pinTab(tab));
+    },
+
+    /**
+     * @zh_CN 鍙栨秷鍥哄畾鏍囩椤�
+     * @param tab
+     */
+    async unpinTab(tab: TabDefinition) {
+      const index = this.tabs.findIndex(
+        (item) => getTabPath(item) === getTabPath(tab),
+      );
+
+      if (index !== -1) {
+        const oldTab = this.tabs[index];
+        tab.meta.affixTab = false;
+        tab.meta.title = oldTab?.meta?.title as string;
+        // this.addTab(tab);
+        this.tabs.splice(index, 1, tab);
+      }
+      // 杩囨护鍥哄畾tabs锛屽悗闈㈡洿鏀筧ffixTabOrder鐨勫�肩殑璇濆彲鑳戒細鏈夐棶棰橈紝鐩墠琛�464鎺掑簭affixTabs娌℃湁璁剧疆鍊�
+      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));
+      // 鑾峰緱鍥哄畾tabs鐨刬ndex,浣跨敤鍥哄畾tabs鐨勪笅涓�涓綅缃篃灏辨槸娲诲姩tabs鐨勭涓�涓綅缃�
+      const newIndex = affixTabs.length;
+      // 浜ゆ崲浣嶇疆閲嶆柊鎺掑簭
+      await this.sortTabs(index, newIndex);
+    },
+
+    /**
+     * 鏍规嵁褰撳墠鎵撳紑鐨勯�夐」鍗℃洿鏂扮紦瀛�
+     */
+    async updateCacheTabs() {
+      const cacheMap = new Set<string>();
+
+      for (const tab of this.tabs) {
+        // 璺宠繃涓嶉渶瑕佹寔涔呭寲鐨勬爣绛鹃〉
+        const keepAlive = tab.meta?.keepAlive;
+        if (!keepAlive) {
+          continue;
+        }
+        (tab.matched || []).forEach((t, i) => {
+          if (i > 0) {
+            cacheMap.add(t.name as string);
+          }
+        });
+
+        const name = tab.name as string;
+        cacheMap.add(name);
+      }
+      this.cachedTabs = cacheMap;
+    },
+  },
+  getters: {
+    affixTabs(): TabDefinition[] {
+      const affixTabs = this.tabs.filter((tab) => isAffixTab(tab));
+
+      return affixTabs.sort((a, b) => {
+        const orderA = (a.meta?.affixTabOrder ?? 0) as number;
+        const orderB = (b.meta?.affixTabOrder ?? 0) as number;
+        return orderA - orderB;
+      });
+    },
+    getCachedTabs(): string[] {
+      return [...this.cachedTabs];
+    },
+    getExcludeCachedTabs(): string[] {
+      return [...this.excludeCachedTabs];
+    },
+    getTabs(): TabDefinition[] {
+      const normalTabs = this.tabs.filter((tab) => !isAffixTab(tab));
+      return [...this.affixTabs, ...normalTabs].filter(Boolean);
+    },
+  },
+  persist: [
+    // tabs涓嶉渶瑕佷繚瀛樺湪localStorage
+    {
+      pick: ['tabs'],
+      storage: sessionStorage,
+    },
+  ],
+  state: (): TabbarState => ({
+    cachedTabs: new Set(),
+    dragEndIndex: 0,
+    excludeCachedTabs: new Set(),
+    renderRouteView: true,
+    tabs: [],
+    updateTime: Date.now(),
+  }),
+});
+
+// 瑙e喅鐑洿鏂伴棶棰�
+const hot = import.meta.hot;
+if (hot) {
+  hot.accept(acceptHMRUpdate(useTabbarStore, hot));
+}
+
+/**
+ * @zh_CN 鍏嬮殕璺敱,闃叉璺敱琚慨鏀�
+ * @param route
+ */
+function cloneTab(route: TabDefinition): TabDefinition {
+  if (!route) {
+    return route;
+  }
+  const { matched, meta, ...opt } = route;
+  return {
+    ...opt,
+    matched: (matched
+      ? matched.map((item) => ({
+          meta: item.meta,
+          name: item.name,
+          path: item.path,
+        }))
+      : undefined) as RouteRecordNormalized[],
+    meta: {
+      ...meta,
+      newTabTitle: meta.newTabTitle,
+    },
+  };
+}
+
+/**
+ * @zh_CN 鏄惁鏄浐瀹氭爣绛鹃〉
+ * @param tab
+ */
+function isAffixTab(tab: TabDefinition) {
+  return tab?.meta?.affixTab ?? false;
+}
+
+/**
+ * @zh_CN 鏄惁鏄剧ず鏍囩
+ * @param tab
+ */
+function isTabShown(tab: TabDefinition) {
+  const matched = tab?.matched ?? [];
+  return !tab.meta.hideInTab && matched.every((item) => !item.meta.hideInTab);
+}
+
+/**
+ * @zh_CN 鑾峰彇鏍囩椤佃矾寰�
+ * @param tab
+ */
+function getTabPath(tab: RouteRecordNormalized | TabDefinition) {
+  return decodeURIComponent((tab as TabDefinition).fullPath || tab.path);
+}
+
+function routeToTab(route: RouteRecordNormalized) {
+  return {
+    meta: route.meta,
+    name: route.name,
+    path: route.path,
+  } as TabDefinition;
+}
diff --git a/eims-ui/packages/stores/src/modules/user.test.ts b/eims-ui/packages/stores/src/modules/user.test.ts
new file mode 100644
index 0000000..3d8a22c
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/user.test.ts
@@ -0,0 +1,37 @@
+import { createPinia, setActivePinia } from 'pinia';
+import { beforeEach, describe, expect, it } from 'vitest';
+
+import { useUserStore } from './user';
+
+describe('useUserStore', () => {
+  beforeEach(() => {
+    setActivePinia(createPinia());
+  });
+
+  it('returns correct userInfo', () => {
+    const store = useUserStore();
+    const userInfo: any = { name: 'Jane Doe', roles: [{ value: 'user' }] };
+    store.setUserInfo(userInfo);
+    expect(store.userInfo).toEqual(userInfo);
+  });
+
+  // 娴嬭瘯閲嶇疆鐢ㄦ埛淇℃伅鏃剁殑琛屼负
+  it('clears userInfo and userRoles when setting null userInfo', () => {
+    const store = useUserStore();
+    store.setUserInfo({
+      roles: [{ roleName: 'User', value: 'user' }],
+    } as any);
+    expect(store.userInfo).not.toBeNull();
+    expect(store.userRoles.length).toBeGreaterThan(0);
+
+    store.setUserInfo(null as any);
+    expect(store.userInfo).toBeNull();
+    expect(store.userRoles).toEqual([]);
+  });
+
+  // 娴嬭瘯鍦ㄦ病鏈夌敤鎴疯鑹叉椂杩斿洖绌烘暟缁�
+  it('returns an empty array for userRoles if not set', () => {
+    const store = useUserStore();
+    expect(store.userRoles).toEqual([]);
+  });
+});
diff --git a/eims-ui/packages/stores/src/modules/user.ts b/eims-ui/packages/stores/src/modules/user.ts
new file mode 100644
index 0000000..afc974a
--- /dev/null
+++ b/eims-ui/packages/stores/src/modules/user.ts
@@ -0,0 +1,68 @@
+import { acceptHMRUpdate, defineStore } from 'pinia';
+
+interface BasicUserInfo {
+  [key: string]: any;
+  /**
+   * 澶村儚
+   */
+  avatar: string;
+  /**
+   * 鐢ㄦ埛鏉冮檺
+   */
+  permissions: string[];
+  /**
+   * 鐢ㄦ埛鏄电О
+   */
+  realName: string;
+  /**
+   * 鐢ㄦ埛瑙掕壊
+   */
+  roles: string[];
+  /**
+   * 鐢ㄦ埛id
+   */
+  userId: number | string;
+  /**
+   * 鐢ㄦ埛鍚�
+   */
+  username: string;
+}
+
+interface AccessState {
+  /**
+   * 鐢ㄦ埛淇℃伅
+   */
+  userInfo: BasicUserInfo | null;
+  /**
+   * 鐢ㄦ埛瑙掕壊
+   */
+  userRoles: string[];
+}
+
+/**
+ * @zh_CN 鐢ㄦ埛淇℃伅鐩稿叧
+ */
+export const useUserStore = defineStore('core-user', {
+  actions: {
+    setUserInfo(userInfo: BasicUserInfo | null) {
+      // 璁剧疆鐢ㄦ埛淇℃伅
+      this.userInfo = userInfo;
+      // 璁剧疆瑙掕壊淇℃伅
+      const roles = userInfo?.roles ?? [];
+      this.setUserRoles(roles);
+    },
+    setUserRoles(roles: string[]) {
+      this.userRoles = roles;
+    },
+  },
+  state: (): AccessState => ({
+    userInfo: null,
+    userRoles: [],
+  }),
+});
+
+// 瑙e喅鐑洿鏂伴棶棰�
+const hot = import.meta.hot;
+if (hot) {
+  hot.accept(acceptHMRUpdate(useUserStore, hot));
+}
diff --git a/eims-ui/packages/stores/src/setup.ts b/eims-ui/packages/stores/src/setup.ts
new file mode 100644
index 0000000..890c4dc
--- /dev/null
+++ b/eims-ui/packages/stores/src/setup.ts
@@ -0,0 +1,43 @@
+import type { Pinia } from 'pinia';
+
+import type { App } from 'vue';
+
+import { createPinia } from 'pinia';
+
+let pinia: Pinia;
+
+export interface InitStoreOptions {
+  /**
+   * @zh_CN 搴旂敤鍚�,鐢变簬 @vben/stores 鏄叕鐢ㄧ殑锛屽悗缁彲鑳芥湁澶氫釜app锛屼负浜嗛槻姝㈠涓猘pp缂撳瓨鍐茬獊锛屽彲鍦ㄨ繖閲岄厤缃簲鐢ㄥ悕,搴旂敤鍚嶅皢琚敤浜庢寔涔呭寲鐨勫墠缂�
+   */
+  namespace: string;
+}
+
+/**
+ * @zh_CN 鍒濆鍖杙inia
+ */
+export async function initStores(app: App, options: InitStoreOptions) {
+  const { createPersistedState } = await import('pinia-plugin-persistedstate');
+  pinia = createPinia();
+  const { namespace } = options;
+  pinia.use(
+    createPersistedState({
+      // key $appName-$store.id
+      key: (storeKey) => `${namespace}-${storeKey}`,
+      storage: localStorage,
+    }),
+  );
+  app.use(pinia);
+  return pinia;
+}
+
+export function resetAllStores() {
+  if (!pinia) {
+    console.error('Pinia is not installed');
+    return;
+  }
+  const allStores = (pinia as any)._s;
+  for (const [_key, store] of allStores) {
+    store.$reset();
+  }
+}
diff --git a/eims-ui/packages/stores/tsconfig.json b/eims-ui/packages/stores/tsconfig.json
new file mode 100644
index 0000000..3057820
--- /dev/null
+++ b/eims-ui/packages/stores/tsconfig.json
@@ -0,0 +1,5 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src", "shim-pinia.d.ts"]
+}
diff --git a/eims-ui/packages/styles/README.md b/eims-ui/packages/styles/README.md
new file mode 100644
index 0000000..4826446
--- /dev/null
+++ b/eims-ui/packages/styles/README.md
@@ -0,0 +1,19 @@
+# @vben/styles
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨勬牱寮忔枃浠讹紝缁ф壙浜� `@vben-core/design` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤鐨勬牱寮忔枃浠跺彲浠ユ斁鍦ㄨ繖閲屻��
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/styles
+```
+
+### 浣跨敤
+
+```ts
+import '@vben/styles';
+```
diff --git a/eims-ui/packages/styles/package.json b/eims-ui/packages/styles/package.json
new file mode 100644
index 0000000..9a9aad4
--- /dev/null
+++ b/eims-ui/packages/styles/package.json
@@ -0,0 +1,31 @@
+{
+  "name": "@vben/styles",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/styles"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    },
+    "./antd": {
+      "default": "./src/antd/index.css"
+    },
+    "./ele": {
+      "default": "./src/ele/index.css"
+    },
+    "./global": {
+      "default": "./src/global/index.scss"
+    }
+  },
+  "dependencies": {
+    "@vben-core/design": "workspace:*"
+  }
+}
diff --git a/eims-ui/packages/styles/src/antd/index.css b/eims-ui/packages/styles/src/antd/index.css
new file mode 100644
index 0000000..cac0c5d
--- /dev/null
+++ b/eims-ui/packages/styles/src/antd/index.css
@@ -0,0 +1,110 @@
+/* ant-design-vue 缁勪欢搴撶殑涓�浜涙牱寮忛噸缃� */
+
+.ant-app {
+  width: 100%;
+  height: 100%;
+  overscroll-behavior: none;
+  color: inherit;
+}
+
+.ant-btn {
+  .anticon {
+    display: inline-flex;
+  }
+}
+
+.ant-message-notice-content,
+.ant-notification-notice {
+  @apply dark:border-border/60 dark:border;
+}
+
+.form-valid-error {
+  /** select 閫夋嫨鍣ㄧ殑鏍峰紡 */
+
+  .ant-select .ant-select-selector {
+    border-color: hsl(var(--destructive)) !important;
+  }
+
+  .ant-select-focused .ant-select-selector {
+    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important;
+  }
+
+  /** 鏁板瓧杈撳叆妗嗘牱寮� */
+  .ant-input-number-focused {
+    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+  }
+
+  /** 瀵嗙爜杈撳叆妗嗘牱寮� */
+  .ant-input-affix-wrapper:hover {
+    border-color: hsl(var(--destructive));
+    box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+  }
+}
+
+/** 鍖洪棿閫夋嫨鍣ㄤ笅闈㈡潵鍥炲垏鎹㈡椂鐨勬牱寮� */
+.ant-app .form-valid-error .ant-picker-active-bar {
+  background-color: hsl(var(--destructive));
+}
+
+/** 鏃堕棿閫夋嫨鍣ㄧ殑鏍峰紡 */
+.ant-app .form-valid-error .ant-picker-focused {
+  box-shadow: 0 0 0 2px rgb(255 38 5 / 6%);
+}
+
+/** 鍓嶅悗缃皬鍦嗙偣鏍峰紡 */
+.dot-before-common {
+  @apply before:relative before:top-[-2px] before:mr-[5px] before:inline-block before:size-[6px] before:rounded-full before:content-[''];
+}
+
+.dot-before-red {
+  @apply dot-before-common before:bg-red-500;
+}
+
+.dot-before-green {
+  @apply dot-before-common before:bg-green-500;
+}
+
+/**
+vxe琛ㄦ牸鍙充笂瑙抰oolbar鍏冪礌涔嬮棿鐨勯棿璺�
+*/
+.vxe-button + .vxe-button.type--button {
+  margin-left: 8px !important;
+}
+
+/**
+vxe榛樿鍦嗚
+*/
+html {
+  --vxe-ui-border-radius: 8px !important;
+}
+
+/**
+vxe琛ㄦ牸loading 鍙姞杞借〃鏍� 涓嶅姞杞戒笂闈㈢殑琛ㄥ崟
+*/
+.vxe-grid.is--loading::before {
+  content: none !important;
+}
+
+/**
+鑷畾涔塻uccess鎸夐挳鏍峰紡
+ghost鎸夐挳涓撶敤!
+*/
+.btn-success {
+  color: hsl(var(--success)) !important;
+  border-color: hsl(var(--success)) !important;
+}
+
+.btn-success:hover {
+  color: hsl(var(--success) / 50%) !important;
+  border-color: hsl(var(--success) / 50%) !important;
+}
+
+html.dark button[disabled].btn-success {
+  color: rgb(242 242 242 / 25%) !important;
+  border-color: hsl(240deg 3.7% 22%) !important;
+}
+
+button[disabled].btn-success {
+  color: rgb(50 54 57 / 25%) !important;
+  border-color: hsl(240deg 5.9% 90%) !important;
+}
diff --git a/eims-ui/packages/styles/src/ele/index.css b/eims-ui/packages/styles/src/ele/index.css
new file mode 100644
index 0000000..111af0f
--- /dev/null
+++ b/eims-ui/packages/styles/src/ele/index.css
@@ -0,0 +1,3 @@
+.el-card {
+  --el-card-border-radius: var(--radius) !important;
+}
diff --git a/eims-ui/packages/styles/src/global/index.scss b/eims-ui/packages/styles/src/global/index.scss
new file mode 100644
index 0000000..c7af9bb
--- /dev/null
+++ b/eims-ui/packages/styles/src/global/index.scss
@@ -0,0 +1 @@
+@use '@vben-core/design/bem' as *;
diff --git a/eims-ui/packages/styles/src/index.ts b/eims-ui/packages/styles/src/index.ts
new file mode 100644
index 0000000..b375456
--- /dev/null
+++ b/eims-ui/packages/styles/src/index.ts
@@ -0,0 +1 @@
+import '@vben-core/design';
diff --git a/eims-ui/packages/styles/tsconfig.json b/eims-ui/packages/styles/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/styles/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/types/README.md b/eims-ui/packages/types/README.md
new file mode 100644
index 0000000..f796f31
--- /dev/null
+++ b/eims-ui/packages/types/README.md
@@ -0,0 +1,20 @@
+# @vben/types
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨勫伐鍏风被鍨嬶紝缁ф壙浜� `@vben-core/typings` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤鐨勭被鍨嬪畾涔夊彲浠ユ斁鍦ㄨ繖閲屻��
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/types
+```
+
+### 浣跨敤
+
+```ts
+// 鎺ㄨ崘鍔犱笂 type
+import type { SelectOption } from '@vben/types';
+```
diff --git a/eims-ui/packages/types/global.d.ts b/eims-ui/packages/types/global.d.ts
new file mode 100644
index 0000000..5cf2d38
--- /dev/null
+++ b/eims-ui/packages/types/global.d.ts
@@ -0,0 +1,44 @@
+import type { RouteMeta as IRouteMeta } from '@vben-core/typings';
+
+import 'vue-router';
+
+declare module 'vue-router' {
+  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
+  interface RouteMeta extends IRouteMeta {}
+}
+
+export interface VbenAdminProAppConfigRaw {
+  // 鍚庣鎺ュ彛鍦板潃
+  VITE_GLOB_API_URL: string;
+  // 瀹㈡埛绔疘D
+  VITE_GLOB_APP_CLIENT_ID: string;
+  // # 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
+  VITE_GLOB_ENABLE_ENCRYPT: string;
+  // RSA璇锋眰瑙e瘑绉侀挜
+  VITE_GLOB_RSA_PRIVATE_KEY: string;
+  // RSA璇锋眰鍔犲瘑鍏挜
+  VITE_GLOB_RSA_PUBLIC_KEY: string;
+  // 鏄惁寮�鍚痵se  娉ㄦ剰浠庨厤缃枃浠惰幏鍙栫殑绫诲瀷涓簊tring
+  VITE_GLOB_SSE_ENABLE: string;
+}
+
+export interface ApplicationConfig {
+  // 鍚庣鎺ュ彛鍦板潃
+  apiURL: string;
+  // 瀹㈡埛绔痥ey
+  clientId: string;
+  // 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
+  enableEncrypt: boolean;
+  // RSA鍝嶅簲瑙e瘑绉侀挜
+  rsaPrivateKey: string;
+  // RSA璇锋眰鍔犲瘑鍏挜
+  rsaPublicKey: string;
+  // 鏄惁寮�鍚痵se
+  sseEnable: boolean;
+}
+
+declare global {
+  interface Window {
+    _VBEN_ADMIN_PRO_APP_CONF_: VbenAdminProAppConfigRaw;
+  }
+}
diff --git a/eims-ui/packages/types/package.json b/eims-ui/packages/types/package.json
new file mode 100644
index 0000000..ec0a41a
--- /dev/null
+++ b/eims-ui/packages/types/package.json
@@ -0,0 +1,27 @@
+{
+  "name": "@vben/types",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/types"
+  },
+  "license": "MIT",
+  "type": "module",
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    },
+    "./global": {
+      "types": "./global.d.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/typings": "workspace:*",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/types/src/index.ts b/eims-ui/packages/types/src/index.ts
new file mode 100644
index 0000000..1e266c4
--- /dev/null
+++ b/eims-ui/packages/types/src/index.ts
@@ -0,0 +1,2 @@
+export type * from './user';
+export type * from '@vben-core/typings';
diff --git a/eims-ui/packages/types/src/user.ts b/eims-ui/packages/types/src/user.ts
new file mode 100644
index 0000000..82d1b12
--- /dev/null
+++ b/eims-ui/packages/types/src/user.ts
@@ -0,0 +1,11 @@
+import type { BasicUserInfo } from '@vben-core/typings';
+
+/** 鐢ㄦ埛淇℃伅 */
+interface UserInfo extends BasicUserInfo {
+  /**
+   * 鎷撳睍浣跨敤
+   */
+  [key: string]: any;
+}
+
+export type { UserInfo };
diff --git a/eims-ui/packages/types/tsconfig.json b/eims-ui/packages/types/tsconfig.json
new file mode 100644
index 0000000..ce1a891
--- /dev/null
+++ b/eims-ui/packages/types/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/packages/utils/README.md b/eims-ui/packages/utils/README.md
new file mode 100644
index 0000000..f06068a
--- /dev/null
+++ b/eims-ui/packages/utils/README.md
@@ -0,0 +1,19 @@
+# @vben/utils
+
+鐢ㄤ簬澶氫釜 `app` 鍏敤鐨勫伐鍏峰寘锛岀户鎵夸簡 `@vben-core/shared/utils` 鐨勬墍鏈夎兘鍔涖�備笟鍔′笂鏈夐�氱敤鐨勫伐鍏峰嚱鏁板彲浠ユ斁鍦ㄨ繖閲屻��
+
+## 鐢ㄦ硶
+
+### 娣诲姞渚濊禆
+
+```bash
+# 杩涘叆鐩爣搴旂敤鐩綍锛屼緥濡� apps/xxxx-app
+# cd apps/xxxx-app
+pnpm add @vben/utils
+```
+
+### 浣跨敤
+
+```ts
+import { isString } from '@vben/utils';
+```
diff --git a/eims-ui/packages/utils/package.json b/eims-ui/packages/utils/package.json
new file mode 100644
index 0000000..94fb97a
--- /dev/null
+++ b/eims-ui/packages/utils/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "@vben/utils",
+  "version": "5.5.0",
+  "homepage": "https://github.com/vbenjs/vue-vben-admin",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "packages/utils"
+  },
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "**/*.css"
+  ],
+  "exports": {
+    ".": {
+      "types": "./src/index.ts",
+      "default": "./src/index.ts"
+    }
+  },
+  "dependencies": {
+    "@vben-core/shared": "workspace:*",
+    "@vben-core/typings": "workspace:*",
+    "file-type": "^19.5.0",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/packages/utils/src/helpers/__tests__/enum-options.test.ts b/eims-ui/packages/utils/src/helpers/__tests__/enum-options.test.ts
new file mode 100644
index 0000000..14bfce8
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/__tests__/enum-options.test.ts
@@ -0,0 +1,19 @@
+import { describe, expect, it } from 'vitest';
+
+import { optionsToEnum } from '../enum-options';
+
+describe('optionsToEnum Test', () => {
+  it('should return an enum object', () => {
+    const genderOptions = [
+      { label: '鐢�', value: 1, enumName: 'GENDER_MALE' },
+      { label: '濂�', value: 2, enumName: 'GENDER_FEMALE' },
+    ] as const;
+
+    const enumTest = optionsToEnum(genderOptions);
+    const male = enumTest.GENDER_MALE;
+    const female = enumTest.GENDER_FEMALE;
+
+    expect(male).toBe(1);
+    expect(female).toBe(2);
+  });
+});
diff --git a/eims-ui/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts b/eims-ui/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts
new file mode 100644
index 0000000..fc0d76b
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts
@@ -0,0 +1,88 @@
+import { describe, expect, it } from 'vitest';
+
+import { findMenuByPath, findRootMenuByPath } from '../find-menu-by-path';
+
+// 绀轰緥鑿滃崟鏁版嵁
+const menus: any[] = [
+  { path: '/', children: [] },
+  { path: '/about', children: [] },
+  {
+    path: '/contact',
+    children: [
+      { path: '/contact/email', children: [] },
+      { path: '/contact/phone', children: [] },
+    ],
+  },
+  {
+    path: '/services',
+    children: [
+      { path: '/services/design', children: [] },
+      {
+        path: '/services/development',
+        children: [{ path: '/services/development/web', children: [] }],
+      },
+    ],
+  },
+];
+
+describe('menu Finder Tests', () => {
+  it('finds a top-level menu', () => {
+    const menu = findMenuByPath(menus, '/about');
+    expect(menu).toBeDefined();
+    expect(menu?.path).toBe('/about');
+  });
+
+  it('finds a nested menu', () => {
+    const menu = findMenuByPath(menus, '/services/development/web');
+    expect(menu).toBeDefined();
+    expect(menu?.path).toBe('/services/development/web');
+  });
+
+  it('returns null for a non-existent path', () => {
+    const menu = findMenuByPath(menus, '/non-existent');
+    expect(menu).toBeNull();
+  });
+
+  it('handles empty menus list', () => {
+    const menu = findMenuByPath([], '/about');
+    expect(menu).toBeNull();
+  });
+
+  it('handles menu items without children', () => {
+    const menu = findMenuByPath(
+      [{ path: '/only', children: undefined }] as any[],
+      '/only',
+    );
+    expect(menu).toBeDefined();
+    expect(menu?.path).toBe('/only');
+  });
+
+  it('finds root menu by path', () => {
+    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
+      menus,
+      '/services/development/web',
+    );
+
+    expect(findMenu).toBeDefined();
+    expect(rootMenu).toBeUndefined();
+    expect(rootMenuPath).toBeUndefined();
+    expect(findMenu?.path).toBe('/services/development/web');
+  });
+
+  it('returns null for undefined or empty path', () => {
+    const menuUndefinedPath = findMenuByPath(menus);
+    const menuEmptyPath = findMenuByPath(menus, '');
+    expect(menuUndefinedPath).toBeNull();
+    expect(menuEmptyPath).toBeNull();
+  });
+
+  it('checks for root menu when path does not exist', () => {
+    const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
+      menus,
+      '/non-existent',
+    );
+    expect(findMenu).toBeNull();
+    expect(rootMenu).toBeUndefined();
+    expect(rootMenuPath).toBeUndefined();
+  });
+});
diff --git a/eims-ui/packages/utils/src/helpers/__tests__/generate-menus.test.ts b/eims-ui/packages/utils/src/helpers/__tests__/generate-menus.test.ts
new file mode 100644
index 0000000..9d98b5a
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/__tests__/generate-menus.test.ts
@@ -0,0 +1,236 @@
+import type { Router, RouteRecordRaw } from 'vue-router';
+
+import { createRouter, createWebHistory } from 'vue-router';
+
+import { describe, expect, it, vi } from 'vitest';
+
+import { generateMenus } from '../generate-menus';
+
+// Nested route setup to test child inclusion and hideChildrenInMenu functionality
+
+describe('generateMenus', () => {
+  // 妯℃嫙璺敱鏁版嵁
+  const mockRoutes = [
+    {
+      meta: { icon: 'home-icon', title: '棣栭〉' },
+      name: 'home',
+      path: '/home',
+    },
+    {
+      meta: { hideChildrenInMenu: true, icon: 'about-icon', title: '鍏充簬' },
+      name: 'about',
+      path: '/about',
+      children: [
+        {
+          path: 'team',
+          name: 'team',
+          meta: { icon: 'team-icon', title: '鍥㈤槦' },
+        },
+      ],
+    },
+  ] as RouteRecordRaw[];
+
+  // 妯℃嫙 Vue 璺敱鍣ㄥ疄渚�
+  const mockRouter = {
+    getRoutes: vi.fn(() => [
+      { name: 'home', path: '/home' },
+      { name: 'about', path: '/about' },
+      { name: 'team', path: '/about/team' },
+    ]),
+  };
+
+  it('the correct menu list should be generated according to the route', async () => {
+    const expectedMenus = [
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: 'home-icon',
+        name: '棣栭〉',
+        order: undefined,
+        parent: undefined,
+        parents: undefined,
+        path: '/home',
+        show: true,
+        children: [],
+      },
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: 'about-icon',
+        name: '鍏充簬',
+        order: undefined,
+        parent: undefined,
+        parents: undefined,
+        path: '/about',
+        show: true,
+        children: [],
+      },
+    ];
+
+    const menus = await generateMenus(mockRoutes, mockRouter as any);
+    expect(menus).toEqual(expectedMenus);
+  });
+
+  it('includes additional meta properties in menu items', async () => {
+    const mockRoutesWithMeta = [
+      {
+        meta: { icon: 'user-icon', order: 1, title: 'Profile' },
+        name: 'profile',
+        path: '/profile',
+      },
+    ] as RouteRecordRaw[];
+
+    const menus = await generateMenus(mockRoutesWithMeta, mockRouter as any);
+    expect(menus).toEqual([
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: 'user-icon',
+        name: 'Profile',
+        order: 1,
+        parent: undefined,
+        parents: undefined,
+        path: '/profile',
+        show: true,
+        children: [],
+      },
+    ]);
+  });
+
+  it('handles dynamic route parameters correctly', async () => {
+    const mockRoutesWithParams = [
+      {
+        meta: { icon: 'details-icon', title: 'User Details' },
+        name: 'userDetails',
+        path: '/users/:userId',
+      },
+    ] as RouteRecordRaw[];
+
+    const menus = await generateMenus(mockRoutesWithParams, mockRouter as any);
+    expect(menus).toEqual([
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: 'details-icon',
+        name: 'User Details',
+        order: undefined,
+        parent: undefined,
+        parents: undefined,
+        path: '/users/:userId',
+        show: true,
+        children: [],
+      },
+    ]);
+  });
+
+  it('processes routes with redirects correctly', async () => {
+    const mockRoutesWithRedirect = [
+      {
+        name: 'redirectedRoute',
+        path: '/old-path',
+        redirect: '/new-path',
+      },
+      {
+        meta: { icon: 'path-icon', title: 'New Path' },
+        name: 'newPath',
+        path: '/new-path',
+      },
+    ] as RouteRecordRaw[];
+
+    const menus = await generateMenus(
+      mockRoutesWithRedirect,
+      mockRouter as any,
+    );
+    expect(menus).toEqual([
+      // Assuming your generateMenus function excludes redirect routes from the menu
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: undefined,
+        name: 'redirectedRoute',
+        order: undefined,
+        parent: undefined,
+        parents: undefined,
+        path: '/old-path',
+        show: true,
+        children: [],
+      },
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: 'path-icon',
+        name: 'New Path',
+        order: undefined,
+        parent: undefined,
+        parents: undefined,
+        path: '/new-path',
+        show: true,
+        children: [],
+      },
+    ]);
+  });
+
+  const routes: any = [
+    {
+      meta: { order: 2, title: 'Home' },
+      name: 'home',
+      path: '/',
+    },
+    {
+      meta: { order: 1, title: 'About' },
+      name: 'about',
+      path: '/about',
+    },
+  ];
+
+  const router: Router = createRouter({
+    history: createWebHistory(),
+    routes,
+  });
+
+  it('should generate menu list with correct order', async () => {
+    const menus = await generateMenus(routes, router);
+    const expectedMenus = [
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: undefined,
+        name: 'About',
+        order: 1,
+        parent: undefined,
+        parents: undefined,
+        path: '/about',
+        show: true,
+        children: [],
+      },
+      {
+        badge: undefined,
+        badgeType: undefined,
+        badgeVariants: undefined,
+        icon: undefined,
+        name: 'Home',
+        order: 2,
+        parent: undefined,
+        parents: undefined,
+        path: '/',
+        show: true,
+        children: [],
+      },
+    ];
+
+    expect(menus).toEqual(expectedMenus);
+  });
+
+  it('should handle empty routes', async () => {
+    const emptyRoutes: any[] = [];
+    const menus = await generateMenus(emptyRoutes, router);
+    expect(menus).toEqual([]);
+  });
+});
diff --git a/eims-ui/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts b/eims-ui/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts
new file mode 100644
index 0000000..8e01853
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts
@@ -0,0 +1,105 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { describe, expect, it } from 'vitest';
+
+import {
+  generateRoutesByFrontend,
+  hasAuthority,
+} from '../generate-routes-frontend';
+
+// Mock 璺敱鏁版嵁
+const mockRoutes = [
+  {
+    meta: {
+      authority: ['admin', 'user'],
+      hideInMenu: false,
+    },
+    path: '/dashboard',
+    children: [
+      {
+        path: '/dashboard/overview',
+        meta: { authority: ['admin'], hideInMenu: false },
+      },
+      {
+        path: '/dashboard/stats',
+        meta: { authority: ['user'], hideInMenu: true },
+      },
+    ],
+  },
+  {
+    meta: { authority: ['admin'], hideInMenu: false },
+    path: '/settings',
+  },
+  {
+    meta: { hideInMenu: false },
+    path: '/profile',
+  },
+] as RouteRecordRaw[];
+
+describe('hasAuthority', () => {
+  it('should return true if there is no authority defined', () => {
+    expect(hasAuthority(mockRoutes[2], ['admin'])).toBe(true);
+  });
+
+  it('should return true if the user has the required authority', () => {
+    expect(hasAuthority(mockRoutes[0], ['admin'])).toBe(true);
+  });
+
+  it('should return false if the user does not have the required authority', () => {
+    expect(hasAuthority(mockRoutes[1], ['user'])).toBe(false);
+  });
+});
+
+describe('generateRoutesByFrontend', () => {
+  it('should handle routes without children', async () => {
+    const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [
+      'user',
+    ]);
+    expect(generatedRoutes).toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          path: '/profile', // This route has no children and should be included
+        }),
+      ]),
+    );
+  });
+
+  it('should handle empty roles array', async () => {
+    const generatedRoutes = await generateRoutesByFrontend(mockRoutes, []);
+    expect(generatedRoutes).toEqual(
+      expect.arrayContaining([
+        // Only routes without authority should be included
+        expect.objectContaining({
+          path: '/profile',
+        }),
+      ]),
+    );
+    expect(generatedRoutes).not.toEqual(
+      expect.arrayContaining([
+        expect.objectContaining({
+          path: '/dashboard',
+        }),
+        expect.objectContaining({
+          path: '/settings',
+        }),
+      ]),
+    );
+  });
+
+  it('should handle missing meta fields', async () => {
+    const routesWithMissingMeta = [
+      { path: '/path1' }, // No meta
+      { meta: {}, path: '/path2' }, // Empty meta
+      { meta: { authority: ['admin'] }, path: '/path3' }, // Only authority
+    ];
+    const generatedRoutes = await generateRoutesByFrontend(
+      routesWithMissingMeta as RouteRecordRaw[],
+      ['admin'],
+    );
+    expect(generatedRoutes).toEqual([
+      { path: '/path1' },
+      { meta: {}, path: '/path2' },
+      { meta: { authority: ['admin'] }, path: '/path3' },
+    ]);
+  });
+});
diff --git a/eims-ui/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts b/eims-ui/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts
new file mode 100644
index 0000000..3615556
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts
@@ -0,0 +1,68 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import type { RouteModuleType } from '../merge-route-modules';
+
+import { describe, expect, it } from 'vitest';
+
+import { mergeRouteModules } from '../merge-route-modules';
+
+describe('mergeRouteModules', () => {
+  it('should merge route modules correctly', () => {
+    const routeModules: Record<string, RouteModuleType> = {
+      './dynamic-routes/about.ts': {
+        default: [
+          {
+            component: () => Promise.resolve({ template: '<div>About</div>' }),
+            name: 'About',
+            path: '/about',
+          },
+        ],
+      },
+      './dynamic-routes/home.ts': {
+        default: [
+          {
+            component: () => Promise.resolve({ template: '<div>Home</div>' }),
+            name: 'Home',
+            path: '/',
+          },
+        ],
+      },
+    };
+
+    const expectedRoutes: RouteRecordRaw[] = [
+      {
+        component: expect.any(Function),
+        name: 'About',
+        path: '/about',
+      },
+      {
+        component: expect.any(Function),
+        name: 'Home',
+        path: '/',
+      },
+    ];
+
+    const mergedRoutes = mergeRouteModules(routeModules);
+    expect(mergedRoutes).toEqual(expectedRoutes);
+  });
+
+  it('should handle empty modules', () => {
+    const routeModules: Record<string, RouteModuleType> = {};
+    const expectedRoutes: RouteRecordRaw[] = [];
+
+    const mergedRoutes = mergeRouteModules(routeModules);
+    expect(mergedRoutes).toEqual(expectedRoutes);
+  });
+
+  it('should handle modules with no default export', () => {
+    const routeModules: Record<string, RouteModuleType> = {
+      './dynamic-routes/empty.ts': {
+        default: [],
+      },
+    };
+    const expectedRoutes: RouteRecordRaw[] = [];
+
+    const mergedRoutes = mergeRouteModules(routeModules);
+    expect(mergedRoutes).toEqual(expectedRoutes);
+  });
+});
diff --git a/eims-ui/packages/utils/src/helpers/enum-options.ts b/eims-ui/packages/utils/src/helpers/enum-options.ts
new file mode 100644
index 0000000..5ac4c5a
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/enum-options.ts
@@ -0,0 +1,47 @@
+/**
+ * @author dap
+ * @description 鏋氫妇閫夐」
+ */
+
+/**
+ * 瀹氫箟options绫诲瀷
+ */
+export interface EnumsOption {
+  /**
+   * 鏋氫妇鍚嶇О 寤鸿浣跨敤鍏ㄥぇ鍐欏瓧姣峗
+   */
+  enumName: string;
+  /**
+   * option鐨勬爣绛�
+   */
+  label: string;
+  /**
+   * option鐨勫��
+   */
+  value: boolean | number | string;
+}
+
+export type EnumResult<T extends readonly EnumsOption[]> = {
+  [key in T[number]['enumName']]: Extract<
+    T[number],
+    { enumName: key }
+  >['value'];
+};
+
+/**
+ * 灏唎ptions杞负鏋氫妇
+ * 娉ㄦ剰鑷畾涔夌殑options闇�瑕佸姞涓奱s const浣滀负甯搁噺澶勭悊
+ * 璇﹁: packages\utils\src\helpers\__tests__\enum-options.test.ts
+ * @param options 鏋氫妇閫夐」
+ * @returns 杞灇涓�
+ */
+export function optionsToEnum<T extends readonly EnumsOption[]>(
+  options: T,
+): EnumResult<T> {
+  type K = T[number]['enumName'];
+  const result = {} as EnumResult<T>;
+  options.forEach((item) => {
+    result[item.enumName as K] = item.value;
+  });
+  return result;
+}
diff --git a/eims-ui/packages/utils/src/helpers/find-menu-by-path.ts b/eims-ui/packages/utils/src/helpers/find-menu-by-path.ts
new file mode 100644
index 0000000..1c69e62
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/find-menu-by-path.ts
@@ -0,0 +1,37 @@
+import type { MenuRecordRaw } from '@vben-core/typings';
+
+function findMenuByPath(
+  list: MenuRecordRaw[],
+  path?: string,
+): MenuRecordRaw | null {
+  for (const menu of list) {
+    if (menu.path === path) {
+      return menu;
+    }
+    const findMenu = menu.children && findMenuByPath(menu.children, path);
+    if (findMenu) {
+      return findMenu;
+    }
+  }
+  return null;
+}
+
+/**
+ * 鏌ユ壘鏍硅彍鍗�
+ * @param menus
+ * @param path
+ */
+function findRootMenuByPath(menus: MenuRecordRaw[], path?: string) {
+  const findMenu = findMenuByPath(menus, path);
+  const rootMenuPath = findMenu?.parents?.[0];
+  const rootMenu = rootMenuPath
+    ? menus.find((item) => item.path === rootMenuPath)
+    : undefined;
+  return {
+    findMenu,
+    rootMenu,
+    rootMenuPath,
+  };
+}
+
+export { findMenuByPath, findRootMenuByPath };
diff --git a/eims-ui/packages/utils/src/helpers/generate-menus.ts b/eims-ui/packages/utils/src/helpers/generate-menus.ts
new file mode 100644
index 0000000..48c30fd
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/generate-menus.ts
@@ -0,0 +1,80 @@
+import type { ExRouteRecordRaw, MenuRecordRaw } from '@vben-core/typings';
+import type { Router, RouteRecordRaw } from 'vue-router';
+
+import { filterTree, mapTree } from '@vben-core/shared/utils';
+
+/**
+ * 鏍规嵁 routes 鐢熸垚鑿滃崟鍒楄〃
+ * @param routes
+ */
+async function generateMenus(
+  routes: RouteRecordRaw[],
+  router: Router,
+): Promise<MenuRecordRaw[]> {
+  // 灏嗚矾鐢卞垪琛ㄨ浆鎹负涓�涓互 name 涓洪敭鐨勫璞℃槧灏�
+  // 鑾峰彇鎵�鏈塺outer鏈�缁堢殑path鍙妌ame
+  const finalRoutesMap: { [key: string]: string } = Object.fromEntries(
+    router.getRoutes().map(({ name, path }) => [name, path]),
+  );
+
+  let menus = mapTree<ExRouteRecordRaw, MenuRecordRaw>(routes, (route) => {
+    // 璺敱琛ㄧ殑璺緞鍐欐硶鏈夊绉嶏紝杩欓噷浠巖outer鑾峰彇鍒版渶缁堢殑path骞惰祴鍊�
+    const path = finalRoutesMap[route.name as string] ?? route.path;
+
+    // 杞崲涓鸿彍鍗曠粨鏋�
+    // const path = matchRoute?.path ?? route.path;
+    const { meta, name: routeName, redirect, children } = route;
+    const {
+      activeIcon,
+      badge,
+      badgeType,
+      badgeVariants,
+      hideChildrenInMenu = false,
+      icon,
+      link,
+      order,
+      title = '',
+    } = meta || {};
+
+    const name = (title || routeName || '') as string;
+
+    // 闅愯棌瀛愯彍鍗�
+    const resultChildren = hideChildrenInMenu
+      ? []
+      : (children as MenuRecordRaw[]);
+
+    // 灏嗚彍鍗曠殑鎵�鏈夌埗绾у拰鐖剁骇鑿滃崟璁板綍鍒拌彍鍗曢」鍐�
+    if (resultChildren && resultChildren.length > 0) {
+      resultChildren.forEach((child) => {
+        child.parents = [...(route.parents || []), path];
+        child.parent = path;
+      });
+    }
+    // 闅愯棌瀛愯彍鍗�
+    const resultPath = hideChildrenInMenu ? redirect || path : link || path;
+    return {
+      activeIcon,
+      badge,
+      badgeType,
+      badgeVariants,
+      icon,
+      name,
+      order,
+      parent: route.parent,
+      parents: route.parents,
+      path: resultPath as string,
+      show: !route?.meta?.hideInMenu,
+      children: resultChildren || [],
+    };
+  });
+
+  // 瀵硅彍鍗曡繘琛屾帓搴�
+  menus = menus.sort((a, b) => (a.order || 999) - (b.order || 999));
+
+  const finalMenus = filterTree(menus, (menu) => {
+    return !!menu.show;
+  });
+  return finalMenus;
+}
+
+export { generateMenus };
diff --git a/eims-ui/packages/utils/src/helpers/generate-routes-backend.ts b/eims-ui/packages/utils/src/helpers/generate-routes-backend.ts
new file mode 100644
index 0000000..f64a69a
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/generate-routes-backend.ts
@@ -0,0 +1,87 @@
+import type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+  RouteRecordStringComponent,
+} from '@vben-core/typings';
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mapTree } from '@vben-core/shared/utils';
+
+/**
+ * 鍔ㄦ�佺敓鎴愯矾鐢� - 鍚庣鏂瑰紡
+ */
+async function generateRoutesByBackend(
+  options: GenerateMenuAndRoutesOptions,
+): Promise<RouteRecordRaw[]> {
+  const { fetchMenuListAsync, layoutMap = {}, pageMap = {} } = options;
+
+  try {
+    const menuRoutes = await fetchMenuListAsync?.();
+    if (!menuRoutes) {
+      return [];
+    }
+
+    const normalizePageMap: ComponentRecordType = {};
+
+    for (const [key, value] of Object.entries(pageMap)) {
+      normalizePageMap[normalizeViewPath(key)] = value;
+    }
+
+    const routes = convertRoutes(menuRoutes, layoutMap, normalizePageMap);
+
+    return routes;
+  } catch (error) {
+    console.error(error);
+    return [];
+  }
+}
+
+function convertRoutes(
+  routes: RouteRecordStringComponent[],
+  layoutMap: ComponentRecordType,
+  pageMap: ComponentRecordType,
+): RouteRecordRaw[] {
+  return mapTree(routes, (node) => {
+    const route = node as unknown as RouteRecordRaw;
+    const { component, name } = node;
+
+    if (!name) {
+      console.error('route name is required', route);
+    }
+
+    // layout杞崲
+    if (component && layoutMap[component]) {
+      route.component = layoutMap[component];
+      // 椤甸潰缁勪欢杞崲
+    } else if (component) {
+      const normalizePath = normalizeViewPath(component);
+      route.component =
+        pageMap[
+          normalizePath.endsWith('.vue')
+            ? normalizePath
+            : `${normalizePath}.vue`
+        ];
+      if (!route.component) {
+        console.error(`鏈壘鍒板搴旂粍浠�: /views${component}.vue`);
+        // 榛樿涓�404椤甸潰
+        route.component = layoutMap.NotFoundComponent;
+      }
+    }
+
+    return route;
+  });
+}
+
+function normalizeViewPath(path: string): string {
+  // 鍘婚櫎鐩稿璺緞鍓嶇紑
+  const normalizedPath = path.replace(/^(\.\/|\.\.\/)+/, '');
+
+  // 纭繚璺緞浠� '/' 寮�澶�
+  const viewPath = normalizedPath.startsWith('/')
+    ? normalizedPath
+    : `/${normalizedPath}`;
+
+  // 杩欓噷鑰﹀悎浜唙ben-admin鐨勭洰褰曠粨鏋�
+  return viewPath.replace(/^\/views/, '');
+}
+export { generateRoutesByBackend };
diff --git a/eims-ui/packages/utils/src/helpers/generate-routes-frontend.ts b/eims-ui/packages/utils/src/helpers/generate-routes-frontend.ts
new file mode 100644
index 0000000..dafc8a7
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/generate-routes-frontend.ts
@@ -0,0 +1,58 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { filterTree, mapTree } from '@vben-core/shared/utils';
+
+/**
+ * 鍔ㄦ�佺敓鎴愯矾鐢� - 鍓嶇鏂瑰紡
+ */
+async function generateRoutesByFrontend(
+  routes: RouteRecordRaw[],
+  roles: string[],
+  forbiddenComponent?: RouteRecordRaw['component'],
+): Promise<RouteRecordRaw[]> {
+  // 鏍规嵁瑙掕壊鏍囪瘑杩囨护璺敱琛�,鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鎷ユ湁鎸囧畾鏉冮檺
+  const finalRoutes = filterTree(routes, (route) => {
+    return hasAuthority(route, roles);
+  });
+
+  if (!forbiddenComponent) {
+    return finalRoutes;
+  }
+
+  // 濡傛灉鏈夌姝㈣闂殑椤甸潰锛屽皢绂佹璁块棶鐨勯〉闈㈡浛鎹负403椤甸潰
+  return mapTree(finalRoutes, (route) => {
+    if (menuHasVisibleWithForbidden(route)) {
+      route.component = forbiddenComponent;
+    }
+    return route;
+  });
+}
+
+/**
+ * 鍒ゆ柇璺敱鏄惁鏈夋潈闄愯闂�
+ * @param route
+ * @param access
+ */
+function hasAuthority(route: RouteRecordRaw, access: string[]) {
+  const authority = route.meta?.authority;
+  if (!authority) {
+    return true;
+  }
+  const canAccess = access.some((value) => authority.includes(value));
+
+  return canAccess || (!canAccess && menuHasVisibleWithForbidden(route));
+}
+
+/**
+ * 鍒ゆ柇璺敱鏄惁鍦ㄨ彍鍗曚腑鏄剧ず锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+ * @param route
+ */
+function menuHasVisibleWithForbidden(route: RouteRecordRaw) {
+  return (
+    !!route.meta?.authority &&
+    Reflect.has(route.meta || {}, 'menuVisibleWithForbidden') &&
+    !!route.meta?.menuVisibleWithForbidden
+  );
+}
+
+export { generateRoutesByFrontend, hasAuthority };
diff --git a/eims-ui/packages/utils/src/helpers/get-popup-container.ts b/eims-ui/packages/utils/src/helpers/get-popup-container.ts
new file mode 100644
index 0000000..ccd48ec
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/get-popup-container.ts
@@ -0,0 +1,34 @@
+/**
+ * Returns the parent node of the given element or the document body if the element is not provided.it
+ */
+export function getPopupContainer(node?: HTMLElement): HTMLElement {
+  return (node?.parentNode as HTMLElement) ?? document.body;
+}
+
+/**
+ * VxeTable涓撶敤寮圭獥灞�
+ * 瑙e喅闂: https://gitee.com/dapppp/ruoyi-plus-vben5/issues/IB1DM3
+ * 鍗曡〃鏍肩敤娉曡窡涓婇潰getPopupContainer涓�鏍�
+ * 涓�涓〉闈�(body涓�)鏈夊涓〃鏍煎厓绱� 蹇呴』鍏堟寚瀹欼D & ID鍙傛暟浼犲叆璇ュ嚱鏁�
+ * <BasicTable id="xxx" />
+ * getVxePopupContainer="(node) => getVxePopupContainer(node, 'xxx')"
+ * @param _node 瑙﹀彂鐨勫厓绱�
+ * @param id 琛ㄦ牸鍞竴id 褰撻〉闈�(璇ョ獥鍙�)鏈�>=涓や釜琛ㄦ牸 蹇呴』鎻愪緵ID
+ * @returns 鎸傝浇鑺傜偣
+ */
+export function getVxePopupContainer(
+  _node?: HTMLElement,
+  id?: string,
+): HTMLElement {
+  let selector = 'div.vxe-table--body-wrapper.body--wrapper';
+  if (id) {
+    selector = `div#${id} ${selector}`;
+  }
+  // 鎸傝浇鍒皏xe-table鐨勬粴鍔ㄥ尯鍩�
+  const vxeTableContainerNode = document.querySelector(selector);
+  if (!vxeTableContainerNode) {
+    console.warn('鏃犳硶鎵惧埌vxe-table鍏冪礌, 灏嗕細鎸傝浇鍒癰ody.');
+    return document.body;
+  }
+  return vxeTableContainerNode as HTMLElement;
+}
diff --git a/eims-ui/packages/utils/src/helpers/index.ts b/eims-ui/packages/utils/src/helpers/index.ts
new file mode 100644
index 0000000..1733d1a
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/index.ts
@@ -0,0 +1,14 @@
+export * from './enum-options';
+export * from './find-menu-by-path';
+export * from './generate-menus';
+export * from './generate-routes-backend';
+export * from './generate-routes-frontend';
+export * from './get-popup-container';
+export * from './merge-route-modules';
+export * from './mitt';
+export * from './request';
+export * from './reset-routes';
+export * from './safe';
+export * from './tree';
+export * from './unmount-global-loading';
+export * from './uuid';
diff --git a/eims-ui/packages/utils/src/helpers/merge-route-modules.ts b/eims-ui/packages/utils/src/helpers/merge-route-modules.ts
new file mode 100644
index 0000000..53e21f3
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/merge-route-modules.ts
@@ -0,0 +1,28 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+// 瀹氫箟妯″潡绫诲瀷
+interface RouteModuleType {
+  default: RouteRecordRaw[];
+}
+
+/**
+ * 鍚堝苟鍔ㄦ�佽矾鐢辨ā鍧楃殑榛樿瀵煎嚭
+ * @param routeModules 鍔ㄦ�佸鍏ョ殑璺敱妯″潡瀵硅薄
+ * @returns 鍚堝苟鍚庣殑璺敱閰嶇疆鏁扮粍
+ */
+function mergeRouteModules(
+  routeModules: Record<string, unknown>,
+): RouteRecordRaw[] {
+  const mergedRoutes: RouteRecordRaw[] = [];
+
+  for (const routeModule of Object.values(routeModules)) {
+    const moduleRoutes = (routeModule as RouteModuleType)?.default ?? [];
+    mergedRoutes.push(...moduleRoutes);
+  }
+
+  return mergedRoutes;
+}
+
+export { mergeRouteModules };
+
+export type { RouteModuleType };
diff --git a/eims-ui/packages/utils/src/helpers/mitt.ts b/eims-ui/packages/utils/src/helpers/mitt.ts
new file mode 100644
index 0000000..52be313
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/mitt.ts
@@ -0,0 +1,135 @@
+/**
+ * copy to https://github.com/developit/mitt
+ * Expand clear method
+ */
+export type EventType = string | symbol;
+
+// An event handler can take an optional event argument
+// and should not return a value
+export type Handler<T = unknown> = (event: T) => void;
+export type WildcardHandler<T = Record<string, unknown>> = (
+  type: keyof T,
+  event: T[keyof T],
+) => void;
+
+// An array of all currently registered event handlers for a type
+export type EventHandlerList<T = unknown> = Array<Handler<T>>;
+export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<
+  WildcardHandler<T>
+>;
+
+// A map of event types and their corresponding event handlers.
+export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
+  '*' | keyof Events,
+  EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
+>;
+
+export interface Emitter<Events extends Record<EventType, unknown>> {
+  all: EventHandlerMap<Events>;
+
+  clear(): void;
+  emit<Key extends keyof Events>(
+    type: undefined extends Events[Key] ? Key : never,
+  ): void;
+
+  emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
+  off(type: '*', handler: WildcardHandler<Events>): void;
+
+  off<Key extends keyof Events>(
+    type: Key,
+    handler?: Handler<Events[Key]>,
+  ): void;
+  on(type: '*', handler: WildcardHandler<Events>): void;
+  on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
+}
+
+/**
+ * Mitt: Tiny (~200b) functional event emitter / pubsub.
+ * @name mitt
+ * @returns {Mitt} any
+ */
+export function mitt<Events extends Record<EventType, unknown>>(
+  all?: EventHandlerMap<Events>,
+): Emitter<Events> {
+  type GenericEventHandler =
+    | Handler<Events[keyof Events]>
+    | WildcardHandler<Events>;
+  all = all || new Map();
+
+  return {
+    /**
+     * A Map of event names to registered handler functions.
+     */
+    all,
+
+    /**
+     * Clear all
+     */
+    clear() {
+      this.all.clear();
+    },
+
+    /**
+     * Invoke all handlers for the given type.
+     * If present, `'*'` handlers are invoked after type-matched handlers.
+     *
+     * Note: Manually firing '*' handlers is not supported.
+     *
+     * @param {string|symbol} type The event type to invoke
+     * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
+     * @memberOf mitt
+     */
+    emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
+      let handlers = all?.get(type);
+      if (handlers) {
+        [...(handlers as EventHandlerList<Events[keyof Events]>)].forEach(
+          (handler) => {
+            handler(evt as Events[Key]);
+          },
+        );
+      }
+
+      handlers = all?.get('*');
+      if (handlers) {
+        [...(handlers as WildCardEventHandlerList<Events>)].forEach(
+          (handler) => {
+            handler(type, evt as Events[Key]);
+          },
+        );
+      }
+    },
+
+    /**
+     * Remove an event handler for the given type.
+     * If `handler` is omitted, all handlers of the given type are removed.
+     * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)
+     * @param {Function} [handler] Handler function to remove
+     * @memberOf mitt
+     */
+    off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
+      const handlers: Array<GenericEventHandler> | undefined = all?.get(type);
+      if (handlers) {
+        if (handler) {
+          handlers.splice(handlers.indexOf(handler) >>> 0, 1);
+        } else {
+          all?.set(type, []);
+        }
+      }
+    },
+
+    /**
+     * Register an event handler for the given type.
+     * @param {string|symbol} type Type of event to listen for, or `'*'` for all events
+     * @param {Function} handler Function to call in response to given event
+     * @memberOf mitt
+     */
+    on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
+      const handlers: Array<GenericEventHandler> | undefined = all?.get(type);
+      if (handlers) {
+        handlers.push(handler);
+      } else {
+        all?.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
+      }
+    },
+  };
+}
diff --git a/eims-ui/packages/utils/src/helpers/request.ts b/eims-ui/packages/utils/src/helpers/request.ts
new file mode 100644
index 0000000..b29e294
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/request.ts
@@ -0,0 +1,24 @@
+/**
+ * 涓�浜涘彂閫佽姹� 闇�瑕佺敤鍒扮殑宸ュ叿
+ */
+
+/**
+ * Add the object as a parameter to the URL
+ * @param baseUrl url
+ * @param obj
+ * @returns {string}
+ * eg:
+ *  let obj = {a: '3', b: '4'}
+ *  setObjToUrlParams('www.baidu.com', obj)
+ *  ==>www.baidu.com?a=3&b=4
+ */
+export function setObjToUrlParams(baseUrl: string, obj: any): string {
+  let parameters = '';
+  for (const key in obj) {
+    parameters += `${key}=${encodeURIComponent(obj[key])}&`;
+  }
+  parameters = parameters.replace(/&$/, '');
+  return /\?$/.test(baseUrl)
+    ? baseUrl + parameters
+    : baseUrl.replace(/\/?$/, '?') + parameters;
+}
diff --git a/eims-ui/packages/utils/src/helpers/reset-routes.ts b/eims-ui/packages/utils/src/helpers/reset-routes.ts
new file mode 100644
index 0000000..0d53a00
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/reset-routes.ts
@@ -0,0 +1,31 @@
+import type { Router, RouteRecordName, RouteRecordRaw } from 'vue-router';
+
+import { traverseTreeValues } from '@vben-core/shared/utils';
+
+/**
+ * @zh_CN 閲嶇疆鎵�鏈夎矾鐢憋紝濡傛湁鎸囧畾鐧藉悕鍗曢櫎澶�
+ */
+export function resetStaticRoutes(router: Router, routes: RouteRecordRaw[]) {
+  // 鑾峰彇闈欐�佽矾鐢辨墍鏈夎妭鐐瑰寘鍚瓙鑺傜偣鐨� name锛屽苟鎺掗櫎涓嶅瓨鍦� name 瀛楁鐨勮矾鐢�
+  const staticRouteNames = traverseTreeValues<
+    RouteRecordRaw,
+    RouteRecordName | undefined
+  >(routes, (route) => {
+    // 杩欎簺璺敱闇�瑕佹寚瀹� name锛岄槻姝㈠湪璺敱閲嶇疆鏃讹紝涓嶈兘鍒犻櫎娌℃湁鎸囧畾 name 鐨勮矾鐢�
+    if (!route.name) {
+      console.warn(
+        `The route with the path ${route.path} needs to have the field name specified.`,
+      );
+    }
+    return route.name;
+  });
+
+  const { getRoutes, hasRoute, removeRoute } = router;
+  const allRoutes = getRoutes();
+  allRoutes.forEach(({ name }) => {
+    // 瀛樺湪浜庤矾鐢辫〃涓旈潪鐧藉悕鍗曟墠闇�瑕佸垹闄�
+    if (name && !staticRouteNames.includes(name) && hasRoute(name)) {
+      removeRoute(name);
+    }
+  });
+}
diff --git a/eims-ui/packages/utils/src/helpers/safe.ts b/eims-ui/packages/utils/src/helpers/safe.ts
new file mode 100644
index 0000000..ad31337
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/safe.ts
@@ -0,0 +1,10 @@
+/**
+ * 璺熷悗鍙伴�昏緫涓�鑷�
+ * Number.isSafeInteger褰㈠弬鍙兘涓篘umber绫诲瀷 鍏朵粬鐨勭洿鎺ヨ繑鍥瀎alse
+ * @param str 鏁板瓧
+ * @returns 瀹夊叏鏁板唴杩斿洖number绫诲瀷 鍚﹀垯杩斿洖鍘熷瓧绗︿覆
+ */
+export function safeParseNumber(str: string): number | string {
+  const num = Number(str);
+  return Number.isSafeInteger(num) ? num : str;
+}
diff --git a/eims-ui/packages/utils/src/helpers/tree.ts b/eims-ui/packages/utils/src/helpers/tree.ts
new file mode 100644
index 0000000..9b0f4b7
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/tree.ts
@@ -0,0 +1,400 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+interface TreeHelperConfig {
+  children: string;
+  id: string;
+  pid: string;
+}
+
+type Fn = (node: any, parentNode?: any) => any;
+
+// 榛樿閰嶇疆
+const DEFAULT_CONFIG: TreeHelperConfig = {
+  id: 'id',
+  pid: 'parentId',
+  children: 'children',
+};
+
+// 鑾峰彇閰嶇疆銆�  Object.assign 浠庝竴涓垨澶氫釜婧愬璞″鍒跺埌鐩爣瀵硅薄
+const getConfig = (config: Partial<TreeHelperConfig>) =>
+  Object.assign({}, DEFAULT_CONFIG, config);
+
+// tree from list
+// 鍒楄〃涓殑鏍�
+export function listToTree<T = any>(
+  list: any[],
+  config: Partial<TreeHelperConfig> = {},
+): T[] {
+  const conf = getConfig(config) as TreeHelperConfig;
+  const nodeMap = new Map();
+  const result: T[] = [];
+  const { id, pid, children } = conf;
+
+  for (const node of list) {
+    node[children] = node[children] || [];
+    nodeMap.set(node[id], node);
+  }
+  for (const node of list) {
+    const parent = nodeMap.get(node[pid]);
+    (parent ? parent[children] : result).push(node);
+  }
+  return result;
+}
+
+export function treeToList<T = any>(
+  tree: any,
+  config: Partial<TreeHelperConfig> = {},
+): T {
+  config = getConfig(config);
+  const { children } = config;
+  const result: any = [...tree];
+  for (let i = 0; i < result.length; i++) {
+    if (!result[i][children!]) continue;
+    result.splice(i + 1, 0, ...result[i][children!]);
+  }
+  return result;
+}
+
+export function findNode<T = any>(
+  tree: any,
+  func: Fn,
+  config: Partial<TreeHelperConfig> = {},
+): null | T {
+  config = getConfig(config);
+  const { children } = config;
+  const list = [...tree];
+  for (const node of list) {
+    if (func(node)) return node;
+    node[children!] && list.push(...node[children!]);
+  }
+  return null;
+}
+
+export function findNodeAll<T = any>(
+  tree: any,
+  func: Fn,
+  config: Partial<TreeHelperConfig> = {},
+): T[] {
+  config = getConfig(config);
+  const { children } = config;
+  const list = [...tree];
+  const result: T[] = [];
+  for (const node of list) {
+    func(node) && result.push(node);
+    node[children!] && list.push(...node[children!]);
+  }
+  return result;
+}
+
+export function findPath<T = any>(
+  tree: any,
+  func: Fn,
+  config: Partial<TreeHelperConfig> = {},
+): null | T | T[] {
+  config = getConfig(config);
+  const path: T[] = [];
+  const list = [...tree];
+  const visitedSet = new Set();
+  const { children } = config;
+  while (list.length > 0) {
+    const node = list[0];
+    if (visitedSet.has(node)) {
+      path.pop();
+      list.shift();
+    } else {
+      visitedSet.add(node);
+      node[children!] && list.unshift(...node[children!]);
+      path.push(node);
+      if (func(node)) {
+        return path;
+      }
+    }
+  }
+  return null;
+}
+
+export function findPathAll(
+  tree: any,
+  func: Fn,
+  config: Partial<TreeHelperConfig> = {},
+) {
+  config = getConfig(config);
+  const path: any[] = [];
+  const list = [...tree];
+  const result: any[] = [];
+  const { children } = config;
+  const visitedSet = new Set();
+  while (list.length > 0) {
+    const node = list[0];
+    if (visitedSet.has(node)) {
+      path.pop();
+      list.shift();
+    } else {
+      visitedSet.add(node);
+      node[children!] && list.unshift(...node[children!]);
+      path.push(node);
+      func(node) && result.push([...path]);
+    }
+  }
+  return result;
+}
+
+export function filter<T = any>(
+  tree: T[],
+  func: (n: T) => boolean,
+  // Partial 灏� T 涓殑鎵�鏈夊睘鎬ц涓哄彲閫�
+  config: Partial<TreeHelperConfig> = {},
+): T[] {
+  // 鑾峰彇閰嶇疆
+  config = getConfig(config);
+  const children = config.children as string;
+
+  function listFilter(list: T[]) {
+    return list
+      .map((node: any) => ({ ...node }))
+      .filter((node) => {
+        // 閫掑綊璋冪敤 瀵瑰惈鏈塩hildren椤�  杩涜鍐嶆璋冪敤鑷韩鍑芥暟 listFilter
+        node[children] = node[children] && listFilter(node[children]);
+        // 鎵ц浼犲叆鐨勫洖璋� func 杩涜杩囨护
+        return func(node) || (node[children] && node[children].length > 0);
+      });
+  }
+
+  return listFilter(tree);
+}
+
+export function forEach<T = any>(
+  tree: T[],
+  func: (n: T) => any,
+  config: Partial<TreeHelperConfig> = {},
+): void {
+  config = getConfig(config);
+  const list: any[] = [...tree];
+  const { children } = config;
+  for (let i = 0; i < list.length; i++) {
+    // func 杩斿洖true灏辩粓姝㈤亶鍘嗭紝閬垮厤澶ч噺鑺傜偣鍦烘櫙涓嬫棤鎰忎箟寰幆锛屽紩璧锋祻瑙堝櫒鍗¢】
+    if (func(list[i])) {
+      return;
+    }
+    children &&
+      list[i][children] &&
+      list.splice(i + 1, 0, ...list[i][children]);
+  }
+}
+
+/**
+ * @description: Extract tree specified structure
+ * @description: 鎻愬彇鏍戞寚瀹氱粨鏋�
+ */
+export function treeMap<T = any>(
+  treeData: T[],
+  opt: { children?: string; conversion: Fn },
+): T[] {
+  return treeData.map((item) => treeMapEach(item, opt));
+}
+
+/**
+ * @description: Extract tree specified structure
+ * @description: 鎻愬彇鏍戞寚瀹氱粨鏋�
+ */
+export function treeMapEach(
+  data: any,
+  { conversion, children = 'children' }: { children?: string; conversion: Fn },
+) {
+  const haveChildren =
+    Array.isArray(data[children]) && data[children].length > 0;
+  const conversionData = conversion(data) || {};
+  return haveChildren
+    ? {
+        ...conversionData,
+        [children]: data[children].map((i: number) =>
+          treeMapEach(i, {
+            children,
+            conversion,
+          }),
+        ),
+      }
+    : {
+        ...conversionData,
+      };
+}
+
+/**
+ * 閫掑綊閬嶅巻鏍戠粨鏋�
+ * @param treeDatas 鏍�
+ * @param callBack 鍥炶皟
+ * @param parentNode 鐖惰妭鐐�
+ */
+export function eachTree(treeDatas: any[], callBack: Fn, parentNode = {}) {
+  treeDatas.forEach((element) => {
+    const newNode = callBack(element, parentNode) || element;
+    if (element.children) {
+      eachTree(element.children, callBack, newNode);
+    }
+  });
+}
+
+// 濡傛灉鑺傜偣鐨刢hildren涓虹┖, 鍒欏垹闄hildren灞炴��
+export function removeEmptyChildren(data: any[], childrenField = 'children') {
+  data.forEach((item) => {
+    if (!item[childrenField]) {
+      return;
+    }
+    if (item[childrenField].length > 0) {
+      removeEmptyChildren(item[childrenField]);
+    } else {
+      Reflect.deleteProperty(item, childrenField);
+    }
+  });
+}
+
+// eslint-disable-next-line jsdoc/require-returns-check
+/**
+ *
+ * 娣诲姞鍏ㄥ悕 濡� 绁栧厛鑺傜偣-鐖惰妭鐐�-瀛愯妭鐐�
+ * @param treeData 宸茬粡鏄痶ree鏁版嵁
+ * @param labelName 鏍囩鐨勫瓧娈靛悕绉�
+ * @param splitStr 鍒嗛殧绗�
+ * @returns void 鏃犺繑鍥炲�� 浼氫慨鏀瑰師濮嬫暟鎹�
+ */
+export function addFullName(
+  treeData: any[],
+  labelName = 'label',
+  splitStr = '-',
+) {
+  function addFullNameProperty(node: any, parentNames: any[] = []) {
+    const fullNameParts = [...parentNames, node[labelName]];
+    node.fullName = fullNameParts.join(splitStr);
+    if (node.children && node.children.length > 0) {
+      node.children.forEach((childNode: any) => {
+        addFullNameProperty(childNode, fullNameParts);
+      });
+    }
+  }
+
+  treeData.forEach((item: any) => {
+    addFullNameProperty(item);
+  });
+}
+
+/**
+ * https://blog.csdn.net/Web_J/article/details/129281329
+ * 缁欏嚭鑺傜偣nodeId 鎵惧埌鎵�鏈夌埗鑺傜偣ID
+ * @param treeList 鏍戝舰缁撴瀯list
+ * @param nodeId 瑕佸鎵剧殑鑺傜偣ID
+ * @param config config
+ * @returns 鐖惰妭鐐笽D鏁扮粍
+ */
+export function findParentsIds(
+  treeList: any[],
+  nodeId: number,
+  config: Partial<TreeHelperConfig> = {},
+) {
+  const conf = getConfig(config) as TreeHelperConfig;
+  const { id, children } = conf;
+
+  // 鐢ㄤ簬瀛樺偍鎵�鏈夌埗鑺傜偣ID鐨勬暟缁�
+  const parentIds: number[] = [];
+
+  function traverse(node: any, nodeId: number) {
+    if (node[id] === nodeId) {
+      return true;
+    }
+    if (node[children]) {
+      // 濡傛灉褰撳墠鑺傜偣鏈夊瓙鑺傜偣锛屽垯缁х画閬嶅巻瀛愯妭鐐�
+      for (const childNode of node[children]) {
+        if (traverse(childNode, nodeId)) {
+          // 濡傛灉鍦ㄥ瓙鑺傜偣涓壘鍒颁簡瀛愯妭鐐圭殑鐖惰妭鐐癸紝鍒欏皢褰撳墠鑺傜偣鐨処D娣诲姞鍒扮埗鑺傜偣ID鏁扮粍涓紝骞惰繑鍥瀟rue琛ㄧず宸茬粡鎵惧埌浜嗗瓙鑺傜偣
+          parentIds.push(node[id]);
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  for (const node of treeList) {
+    if (traverse(node, nodeId)) {
+      // 濡傛灉鍦ㄥ綋鍓嶈妭鐐圭殑瀛愭爲涓壘鍒颁簡瀛愯妭鐐圭殑鐖惰妭鐐癸紝鍒欑洿鎺ラ��鍑哄惊鐜�
+      break;
+    }
+  }
+
+  return parentIds.sort();
+}
+
+/**
+ * 缁欏嚭鑺傜偣鏁扮粍 鎵惧埌鎵�鏈夌埗鑺傜偣ID
+ * @param treeList 鏍戝舰缁撴瀯list
+ * @param nodeIds 瑕佸鎵剧殑鑺傜偣ID list
+ * @param config config
+ * @returns 鐖惰妭鐐笽D鏁扮粍
+ */
+export function findGroupParentIds(
+  treeList: any[],
+  nodeIds: number[],
+  config: Partial<TreeHelperConfig> = {},
+) {
+  // 鐢ㄤ簬瀛樺偍鎵�鏈夌埗鑺傜偣ID鐨凷et 涓昏涓轰簡鍘婚噸
+  const parentIds = new Set<number>();
+
+  nodeIds.forEach((nodeId) => {
+    findParentsIds(treeList, nodeId, config).forEach((parentId) => {
+      parentIds.add(parentId);
+    });
+  });
+
+  return [...parentIds].sort();
+}
+
+/**
+ * 鎵惧埌鎵�鏈塈D 杩斿洖鏁扮粍
+ * @param treeList list
+ * @param config
+ * @returns ID鏁扮粍
+ */
+export function findAllIds(
+  treeList: any[],
+  config: Partial<TreeHelperConfig> = DEFAULT_CONFIG,
+) {
+  const conf = getConfig(config) as TreeHelperConfig;
+  const { id, children } = conf;
+  const ids: number[] = [];
+
+  treeList.forEach((item) => {
+    if (item[children]) {
+      const tempIds = findAllIds(item[children], config);
+      ids.push(...tempIds);
+    }
+    ids.push(item[id]);
+  });
+
+  return [...ids].sort();
+}
+
+/**
+ * @description 杩欓噷鎶勭殑filterByLevel鍑芥暟
+ * @description 涓昏鐢ㄤ簬鑾峰彇鎸囧畾灞傜骇鐨勮妭鐐规暟缁�
+ */
+export function findIdsByLevel(
+  level = 1,
+  list?: any[],
+  config: Partial<TreeHelperConfig> = DEFAULT_CONFIG,
+  currentLevel = 1,
+) {
+  if (!level) {
+    return [];
+  }
+  const res: (number | string)[] = [];
+  const data = list || [];
+  for (const item of data) {
+    const { id: keyField, children: childrenField } = config;
+    const key = keyField ? item[keyField] : '';
+    const children = childrenField ? item[childrenField] : [];
+    res.push(key);
+    if (children && children.length > 0 && currentLevel < level) {
+      currentLevel += 1;
+      res.push(...findIdsByLevel(level, children, config, currentLevel));
+    }
+  }
+  return res as number[] | string[];
+}
diff --git a/eims-ui/packages/utils/src/helpers/unmount-global-loading.ts b/eims-ui/packages/utils/src/helpers/unmount-global-loading.ts
new file mode 100644
index 0000000..10b88ea
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/unmount-global-loading.ts
@@ -0,0 +1,31 @@
+/**
+ * 绉婚櫎骞堕攢姣乴oading
+ * 鏀惧湪杩欓噷鏄�屼笉鏄斁鍦� index.html 鐨刟pp鏍囩鍐咃紝鏄洜涓鸿繖鏍锋瘮杈冧笉浼氱敓纭紝娓叉煋杩囧揩鍙兘浼氭湁闂儊
+ * 閫氳繃鍏堟坊鍔燾ss鍔ㄧ敾闅愯棌锛屽湪鍔ㄧ敾缁撴潫鍚庡湪绉婚櫎loading鑺傜偣鏉ユ敼鍠勪綋楠�
+ * 涓嶅ソ鐨勫湴鏂规槸浼氬鍔犱竴浜涗唬鐮侀噺
+ * 鑷畾涔塴oading鍙互瑙侊細https://doc.vben.pro/guide/in-depth/loading.html
+ */
+export function unmountGlobalLoading() {
+  // 鏌ユ壘鍏ㄥ眬 loading 鍏冪礌
+  const loadingElement = document.querySelector('#__app-loading__');
+
+  if (loadingElement) {
+    // 娣诲姞闅愯棌绫伙紝瑙﹀彂杩囨浮鍔ㄧ敾
+    loadingElement.classList.add('hidden');
+
+    // 鏌ユ壘鎵�鏈夐渶瑕佺Щ闄ょ殑娉ㄥ叆 loading 鍏冪礌
+    const injectLoadingElements = document.querySelectorAll(
+      '[data-app-loading^="inject"]',
+    );
+
+    // 褰撹繃娓″姩鐢荤粨鏉熸椂锛岀Щ闄� loading 鍏冪礌鍜屾墍鏈夋敞鍏ョ殑 loading 鍏冪礌
+    loadingElement.addEventListener(
+      'transitionend',
+      () => {
+        loadingElement.remove(); // 绉婚櫎 loading 鍏冪礌
+        injectLoadingElements.forEach((el) => el.remove()); // 绉婚櫎鎵�鏈夋敞鍏ョ殑 loading 鍏冪礌
+      },
+      { once: true },
+    ); // 纭繚浜嬩欢鍙Е鍙戜竴娆�
+  }
+}
diff --git a/eims-ui/packages/utils/src/helpers/uuid.ts b/eims-ui/packages/utils/src/helpers/uuid.ts
new file mode 100644
index 0000000..81c49a0
--- /dev/null
+++ b/eims-ui/packages/utils/src/helpers/uuid.ts
@@ -0,0 +1,42 @@
+const hexList: string[] = [];
+for (let i = 0; i <= 15; i++) {
+  hexList[i] = i.toString(16);
+}
+
+export function buildUUID(): string {
+  let uuid = '';
+  for (let i = 1; i <= 36; i++) {
+    switch (i) {
+      case 9:
+      case 14:
+      case 19:
+      case 24: {
+        uuid += '-';
+
+        break;
+      }
+      case 15: {
+        uuid += 4;
+
+        break;
+      }
+      case 20: {
+        uuid += hexList[(Math.random() * 4) | 8];
+
+        break;
+      }
+      default: {
+        uuid += hexList[Math.trunc(Math.random() * 16)];
+      }
+    }
+  }
+  return uuid.replaceAll('-', '');
+}
+
+let unique = 0;
+export function buildShortUUID(prefix = ''): string {
+  const time = Date.now();
+  const random = Math.floor(Math.random() * 1_000_000_000);
+  unique++;
+  return `${prefix}_${random}${unique}${String(time)}`;
+}
diff --git a/eims-ui/packages/utils/src/index.ts b/eims-ui/packages/utils/src/index.ts
new file mode 100644
index 0000000..dd84fa7
--- /dev/null
+++ b/eims-ui/packages/utils/src/index.ts
@@ -0,0 +1,5 @@
+export * from './helpers';
+export * from '@vben-core/shared/cache';
+export * from '@vben-core/shared/color';
+export * from '@vben-core/shared/utils';
+export { fileTypeFromBlob } from 'file-type';
diff --git a/eims-ui/packages/utils/tsconfig.json b/eims-ui/packages/utils/tsconfig.json
new file mode 100644
index 0000000..255148a
--- /dev/null
+++ b/eims-ui/packages/utils/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/library.json",
+  "compilerOptions": {
+    "types": ["@vben-core/typings/vue-router"]
+  },
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/playground/.env b/eims-ui/playground/.env
new file mode 100644
index 0000000..3295730
--- /dev/null
+++ b/eims-ui/playground/.env
@@ -0,0 +1,5 @@
+# 搴旂敤鏍囬
+VITE_APP_TITLE=Vben Admin
+
+# 搴旂敤鍛藉悕绌洪棿锛岀敤浜庣紦瀛樸�乻tore绛夊姛鑳界殑鍓嶇紑锛岀‘淇濋殧绂�
+VITE_APP_NAMESPACE=vben-web-play
diff --git a/eims-ui/playground/.env.analyze b/eims-ui/playground/.env.analyze
new file mode 100644
index 0000000..ffafa8d
--- /dev/null
+++ b/eims-ui/playground/.env.analyze
@@ -0,0 +1,7 @@
+# public path
+VITE_BASE=/
+
+# Basic interface address SPA
+VITE_GLOB_API_URL=/api
+
+VITE_VISUALIZER=true
diff --git a/eims-ui/playground/.env.development b/eims-ui/playground/.env.development
new file mode 100644
index 0000000..dcf361e
--- /dev/null
+++ b/eims-ui/playground/.env.development
@@ -0,0 +1,16 @@
+# 绔彛鍙�
+VITE_PORT=5555
+
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=/api
+
+# 鏄惁寮�鍚� Nitro Mock鏈嶅姟锛宼rue 涓哄紑鍚紝false 涓哄叧闂�
+VITE_NITRO_MOCK=true
+
+# 鏄惁鎵撳紑 devtools锛宼rue 涓烘墦寮�锛宖alse 涓哄叧闂�
+VITE_DEVTOOLS=false
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
diff --git a/eims-ui/playground/.env.production b/eims-ui/playground/.env.production
new file mode 100644
index 0000000..5375847
--- /dev/null
+++ b/eims-ui/playground/.env.production
@@ -0,0 +1,19 @@
+VITE_BASE=/
+
+# 鎺ュ彛鍦板潃
+VITE_GLOB_API_URL=https://mock-napi.vben.pro/api
+
+# 鏄惁寮�鍚帇缂╋紝鍙互璁剧疆涓� none, brotli, gzip
+VITE_COMPRESS=none
+
+# 鏄惁寮�鍚� PWA
+VITE_PWA=false
+
+# vue-router 鐨勬ā寮�
+VITE_ROUTER_HISTORY=hash
+
+# 鏄惁娉ㄥ叆鍏ㄥ眬loading
+VITE_INJECT_APP_LOADING=true
+
+# 鎵撳寘鍚庢槸鍚︾敓鎴恉ist.zip
+VITE_ARCHIVER=true
diff --git a/eims-ui/playground/__tests__/e2e/auth-login.spec.ts b/eims-ui/playground/__tests__/e2e/auth-login.spec.ts
new file mode 100644
index 0000000..bb6cd28
--- /dev/null
+++ b/eims-ui/playground/__tests__/e2e/auth-login.spec.ts
@@ -0,0 +1,20 @@
+import { expect, test } from '@playwright/test';
+
+import { authLogin } from './common/auth';
+
+test.beforeEach(async ({ page }) => {
+  await page.goto('/');
+});
+
+test.describe('Auth Login Page Tests', () => {
+  test('check title and page elements', async ({ page }) => {
+    // 鑾峰彇椤甸潰鏍囬骞舵柇瑷�鏍囬鍖呭惈 'Vben Admin'
+    const title = await page.title();
+    expect(title).toContain('Vben Admin');
+  });
+
+  // 娴嬭瘯鐢ㄤ緥: 鎴愬姛鐧诲綍
+  test('should successfully login with valid credentials', async ({ page }) => {
+    await authLogin(page);
+  });
+});
diff --git a/eims-ui/playground/__tests__/e2e/common/auth.ts b/eims-ui/playground/__tests__/e2e/common/auth.ts
new file mode 100644
index 0000000..26b526f
--- /dev/null
+++ b/eims-ui/playground/__tests__/e2e/common/auth.ts
@@ -0,0 +1,46 @@
+import type { Page } from '@playwright/test';
+
+import { expect } from '@playwright/test';
+
+export async function authLogin(page: Page) {
+  // 纭繚鐧诲綍琛ㄥ崟姝e父
+  const usernameInput = await page.locator(`input[name='username']`);
+  await expect(usernameInput).toBeVisible();
+
+  const passwordInput = await page.locator(`input[name='password']`);
+  await expect(passwordInput).toBeVisible();
+
+  const sliderCaptcha = await page.locator(`div[name='captcha']`);
+  const sliderCaptchaAction = await page.locator(`div[name='captcha-action']`);
+  await expect(sliderCaptcha).toBeVisible();
+  await expect(sliderCaptchaAction).toBeVisible();
+
+  // 鎷栧姩楠岃瘉鐮佹粦鍧�
+  // 鑾峰彇鎷栧姩鎸夐挳鐨勪綅缃�
+  const sliderCaptchaBox = await sliderCaptcha.boundingBox();
+  if (!sliderCaptchaBox) throw new Error('婊戝潡鏈壘鍒�');
+
+  const actionBoundingBox = await sliderCaptchaAction.boundingBox();
+  if (!actionBoundingBox) throw new Error('瑕佹嫋鍔ㄧ殑鎸夐挳鏈壘鍒�');
+
+  // 璁$畻璧峰浣嶇疆鍜岀洰鏍囦綅缃�
+  const startX = actionBoundingBox.x + actionBoundingBox.width / 2; // div 涓績鐨� x 鍧愭爣
+  const startY = actionBoundingBox.y + actionBoundingBox.height / 2; // div 涓績鐨� y 鍧愭爣
+
+  const targetX = startX + sliderCaptchaBox.width + actionBoundingBox.width; // 鍚戝彸鎷栧姩瀹瑰櫒鐨勫搴�
+  const targetY = startY; // y 鍧愭爣淇濇寔涓嶅彉
+
+  // 妯℃嫙榧犳爣鎷栧姩
+  await page.mouse.move(startX, startY); // 绉诲姩鍒� action 鐨勪腑蹇�
+  await page.mouse.down(); // 鎸変笅榧犳爣
+  await page.mouse.move(targetX, targetY, { steps: 20 }); // 鎷栧姩鍒扮洰鏍囦綅缃�
+  await page.mouse.up(); // 鏉惧紑榧犳爣
+
+  // 鍦ㄦ嫋鍔ㄥ悗杩涜鏂█锛屾鏌ction鏄惁鍦ㄩ鏈熶綅缃�,
+  const newActionBoundingBox = await sliderCaptchaAction.boundingBox();
+  expect(newActionBoundingBox?.x).toBeGreaterThan(actionBoundingBox.x);
+
+  // 鍒拌繖閲屽凡缁忔牎楠屾垚鍔燂紝鐐瑰嚮杩涜鐧诲綍
+  await page.waitForTimeout(300);
+  await page.getByRole('button', { name: 'login' }).click();
+}
diff --git a/eims-ui/playground/index.html b/eims-ui/playground/index.html
new file mode 100644
index 0000000..ca53269
--- /dev/null
+++ b/eims-ui/playground/index.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang="zh">
+  <head>
+    <meta charset="UTF-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="renderer" content="webkit" />
+    <meta name="description" content="A Modern Back-end Management System" />
+    <meta name="keywords" content="Vben Admin Vue3 Vite" />
+    <meta name="author" content="Vben" />
+    <meta
+      name="viewport"
+      content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
+    />
+    <!-- 鐢� vite 娉ㄥ叆 VITE_APP_TITLE 鍙橀噺锛屽湪 .env 鏂囦欢鍐呴厤缃� -->
+    <title><%= VITE_APP_TITLE %></title>
+    <link rel="icon" href="/favicon.ico" />
+    <script>
+      // 鐢熶骇鐜涓嬫敞鍏ョ櫨搴︾粺璁�
+      if (window._VBEN_ADMIN_PRO_APP_CONF_) {
+        var _hmt = _hmt || [];
+        (function () {
+          var hm = document.createElement('script');
+          hm.src =
+            'https://hm.baidu.com/hm.js?d20a01273820422b6aa2ee41b6c9414d';
+          var s = document.getElementsByTagName('script')[0];
+          s.parentNode.insertBefore(hm, s);
+        })();
+      }
+    </script>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.ts"></script>
+  </body>
+</html>
diff --git a/eims-ui/playground/package.json b/eims-ui/playground/package.json
new file mode 100644
index 0000000..abdca7c
--- /dev/null
+++ b/eims-ui/playground/package.json
@@ -0,0 +1,54 @@
+{
+  "name": "@vben/playground",
+  "version": "5.5.0",
+  "homepage": "https://vben.pro",
+  "bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vbenjs/vue-vben-admin.git",
+    "directory": "playground"
+  },
+  "license": "MIT",
+  "author": {
+    "name": "vben",
+    "email": "ann.vben@gmail.com",
+    "url": "https://github.com/anncwb"
+  },
+  "type": "module",
+  "scripts": {
+    "build": "pnpm vite build --mode production",
+    "build:analyze": "pnpm vite build --mode analyze",
+    "dev": "pnpm vite --mode development",
+    "preview": "vite preview",
+    "typecheck": "vue-tsc --noEmit --skipLibCheck",
+    "test:e2e": "playwright test",
+    "test:e2e-ui": "playwright test --ui",
+    "test:e2e-codegen": "playwright codegen"
+  },
+  "imports": {
+    "#/*": "./src/*"
+  },
+  "dependencies": {
+    "@tanstack/vue-query": "catalog:",
+    "@vben/access": "workspace:*",
+    "@vben/common-ui": "workspace:*",
+    "@vben/constants": "workspace:*",
+    "@vben/hooks": "workspace:*",
+    "@vben/icons": "workspace:*",
+    "@vben/layouts": "workspace:*",
+    "@vben/locales": "workspace:*",
+    "@vben/plugins": "workspace:*",
+    "@vben/preferences": "workspace:*",
+    "@vben/request": "workspace:*",
+    "@vben/stores": "workspace:*",
+    "@vben/styles": "workspace:*",
+    "@vben/types": "workspace:*",
+    "@vben/utils": "workspace:*",
+    "@vueuse/core": "catalog:",
+    "ant-design-vue": "catalog:",
+    "dayjs": "catalog:",
+    "pinia": "catalog:",
+    "vue": "catalog:",
+    "vue-router": "catalog:"
+  }
+}
diff --git a/eims-ui/playground/playwright.config.ts b/eims-ui/playground/playwright.config.ts
new file mode 100644
index 0000000..ca0c908
--- /dev/null
+++ b/eims-ui/playground/playwright.config.ts
@@ -0,0 +1,108 @@
+import type { PlaywrightTestConfig } from '@playwright/test';
+
+import { devices } from '@playwright/test';
+
+/**
+ * Read environment variables from file.
+ * https://github.com/motdotla/dotenv
+ */
+// require('dotenv').config();
+
+/**
+ * See https://playwright.dev/docs/test-configuration.
+ */
+const config: PlaywrightTestConfig = {
+  expect: {
+    /**
+     * Maximum time expect() should wait for the condition to be met.
+     * For example in `await expect(locator).toHaveText();`
+     */
+    timeout: 5000,
+  },
+  /* Fail the build on CI if you accidentally left test.only in the source code. */
+  forbidOnly: !!process.env.CI,
+  /* Folder for test artifacts such as screenshots, videos, traces, etc. */
+  outputDir: 'node_modules/.e2e/test-results/',
+  /* Configure projects for major browsers */
+  projects: [
+    {
+      name: 'chromium',
+      use: {
+        ...devices['Desktop Chrome'],
+      },
+    },
+    // {
+    //   name: 'firefox',
+    //   use: {
+    //     ...devices['Desktop Firefox'],
+    //   },
+    // },
+    // {
+    //   name: 'webkit',
+    //   use: {
+    //     ...devices['Desktop Safari'],
+    //   },
+    // },
+
+    /* Test against mobile viewports. */
+    // {
+    //   name: 'Mobile Chrome',
+    //   use: {
+    //     ...devices['Pixel 5'],
+    //   },
+    // },
+    // {
+    //   name: 'Mobile Safari',
+    //   use: {
+    //     ...devices['iPhone 12'],
+    //   },
+    // },
+
+    /* Test against branded browsers. */
+    // {
+    //   name: 'Microsoft Edge',
+    //   use: {
+    //     channel: 'msedge',
+    //   },
+    // },
+    // {
+    //   name: 'Google Chrome',
+    //   use: {
+    //     channel: 'chrome',
+    //   },
+    // },
+  ],
+  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+  reporter: [
+    ['list'],
+    ['html', { outputFolder: 'node_modules/.e2e/test-results' }],
+  ],
+  /* Retry on CI only */
+  retries: process.env.CI ? 2 : 0,
+  testDir: './__tests__/e2e',
+  /* Maximum time one test can run for. */
+  timeout: 30 * 1000,
+  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+  use: {
+    /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
+    actionTimeout: 0,
+    /* Base URL to use in actions like `await page.goto('/')`. */
+    baseURL: 'http://localhost:5555',
+    /* Only on CI systems run the tests headless */
+    headless: !!process.env.CI,
+    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+    trace: 'retain-on-failure',
+  },
+
+  /* Run your local dev server before starting the tests */
+  webServer: {
+    command: process.env.CI ? 'pnpm preview --port 5555' : 'pnpm dev',
+    port: 5555,
+    reuseExistingServer: !process.env.CI,
+  },
+
+  /* Opt out of parallel tests on CI. */
+  workers: process.env.CI ? 1 : undefined,
+};
+
+export default config;
diff --git a/eims-ui/playground/postcss.config.mjs b/eims-ui/playground/postcss.config.mjs
new file mode 100644
index 0000000..3d80704
--- /dev/null
+++ b/eims-ui/playground/postcss.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config/postcss';
diff --git a/eims-ui/playground/public/favicon.ico b/eims-ui/playground/public/favicon.ico
new file mode 100644
index 0000000..fcf9818
--- /dev/null
+++ b/eims-ui/playground/public/favicon.ico
Binary files differ
diff --git a/eims-ui/playground/src/adapter/component/index.ts b/eims-ui/playground/src/adapter/component/index.ts
new file mode 100644
index 0000000..b9b89dd
--- /dev/null
+++ b/eims-ui/playground/src/adapter/component/index.ts
@@ -0,0 +1,169 @@
+/**
+ * 閫氱敤缁勪欢鍏卞悓鐨勪娇鐢ㄧ殑鍩虹缁勪欢锛屽師鍏堟斁鍦� adapter/form 鍐呴儴锛岄檺鍒朵簡浣跨敤鑼冨洿锛岃繖閲屾彁鍙栧嚭鏉ワ紝鏂逛究鍏朵粬鍦版柟浣跨敤
+ * 鍙敤浜� vben-form銆乿ben-modal銆乿ben-drawer 绛夌粍浠朵娇鐢�,
+ */
+
+import type { BaseFormComponentType } from '@vben/common-ui';
+
+import type { Component, SetupContext } from 'vue';
+import { h } from 'vue';
+
+import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import {
+  AutoComplete,
+  Button,
+  Checkbox,
+  CheckboxGroup,
+  DatePicker,
+  Divider,
+  Input,
+  InputNumber,
+  InputPassword,
+  Mentions,
+  notification,
+  Radio,
+  RadioGroup,
+  RangePicker,
+  Rate,
+  Select,
+  Space,
+  Switch,
+  Textarea,
+  TimePicker,
+  TreeSelect,
+  Upload,
+} from 'ant-design-vue';
+
+const withDefaultPlaceholder = <T extends Component>(
+  component: T,
+  type: 'input' | 'select',
+) => {
+  return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
+    const placeholder = props?.placeholder || $t(`ui.placeholder.${type}`);
+    return h(component, { ...props, ...attrs, placeholder }, slots);
+  };
+};
+
+// 杩欓噷闇�瑕佽嚜琛屾牴鎹笟鍔$粍浠跺簱杩涜閫傞厤锛岄渶瑕佺敤鍒扮殑缁勪欢閮介渶瑕佸湪杩欓噷绫诲瀷璇存槑
+export type ComponentType =
+  | 'ApiSelect'
+  | 'ApiTreeSelect'
+  | 'AutoComplete'
+  | 'Checkbox'
+  | 'CheckboxGroup'
+  | 'DatePicker'
+  | 'DefaultButton'
+  | 'Divider'
+  | 'IconPicker'
+  | 'Input'
+  | 'InputNumber'
+  | 'InputPassword'
+  | 'Mentions'
+  | 'PrimaryButton'
+  | 'Radio'
+  | 'RadioGroup'
+  | 'RangePicker'
+  | 'Rate'
+  | 'Select'
+  | 'Space'
+  | 'Switch'
+  | 'Textarea'
+  | 'TimePicker'
+  | 'TreeSelect'
+  | 'Upload'
+  | BaseFormComponentType;
+
+async function initComponentAdapter() {
+  const components: Partial<Record<ComponentType, Component>> = {
+    // 濡傛灉浣犵殑缁勪欢浣撶Н姣旇緝澶э紝鍙互浣跨敤寮傛鍔犺浇
+    // Button: () =>
+    // import('xxx').then((res) => res.Button),
+
+    ApiSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: Select,
+          loadingSlot: 'suffixIcon',
+          modelPropName: 'value',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    ApiTreeSelect: (props, { attrs, slots }) => {
+      return h(
+        ApiComponent,
+        {
+          placeholder: $t('ui.placeholder.select'),
+          ...props,
+          ...attrs,
+          component: TreeSelect,
+          fieldNames: { label: 'label', value: 'value', children: 'children' },
+          loadingSlot: 'suffixIcon',
+          modelPropName: 'value',
+          optionsPropName: 'treeData',
+          visibleEvent: 'onVisibleChange',
+        },
+        slots,
+      );
+    },
+    AutoComplete,
+    Checkbox,
+    CheckboxGroup,
+    DatePicker,
+    // 鑷畾涔夐粯璁ゆ寜閽�
+    DefaultButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'default' }, slots);
+    },
+    Divider,
+    IconPicker: (props, { attrs, slots }) => {
+      return h(
+        IconPicker,
+        { iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs },
+        slots,
+      );
+    },
+    Input: withDefaultPlaceholder(Input, 'input'),
+    InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
+    InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
+    Mentions: withDefaultPlaceholder(Mentions, 'input'),
+    // 鑷畾涔変富瑕佹寜閽�
+    PrimaryButton: (props, { attrs, slots }) => {
+      return h(Button, { ...props, attrs, type: 'primary' }, slots);
+    },
+    Radio,
+    RadioGroup,
+    RangePicker,
+    Rate,
+    Select: withDefaultPlaceholder(Select, 'select'),
+    Space,
+    Switch,
+    Textarea: withDefaultPlaceholder(Textarea, 'input'),
+    TimePicker,
+    TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
+    Upload,
+  };
+
+  // 灏嗙粍浠舵敞鍐屽埌鍏ㄥ眬鍏变韩鐘舵�佷腑
+  globalShareState.setComponents(components);
+
+  // 瀹氫箟鍏ㄥ眬鍏变韩鐘舵�佷腑鐨勬秷鎭彁绀�
+  globalShareState.defineMessage({
+    // 澶嶅埗鎴愬姛娑堟伅鎻愮ず
+    copyPreferencesSuccess: (title, content) => {
+      notification.success({
+        description: content,
+        message: title,
+        placement: 'bottomRight',
+      });
+    },
+  });
+}
+
+export { initComponentAdapter };
diff --git a/eims-ui/playground/src/adapter/form.ts b/eims-ui/playground/src/adapter/form.ts
new file mode 100644
index 0000000..dfe8fed
--- /dev/null
+++ b/eims-ui/playground/src/adapter/form.ts
@@ -0,0 +1,45 @@
+import type {
+  VbenFormSchema as FormSchema,
+  VbenFormProps,
+} from '@vben/common-ui';
+
+import type { ComponentType } from './component';
+
+import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+setupVbenForm<ComponentType>({
+  config: {
+    // ant design vue缁勪欢搴撻粯璁ら兘鏄� v-model:value
+    baseModelPropName: 'value',
+    // 涓�浜涚粍浠舵槸 v-model:checked 鎴栬�� v-model:fileList
+    modelPropNameMap: {
+      Checkbox: 'checked',
+      Radio: 'checked',
+      Switch: 'checked',
+      Upload: 'fileList',
+    },
+  },
+  defineRules: {
+    // 杈撳叆椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    required: (value, _params, ctx) => {
+      if (value === undefined || value === null || value.length === 0) {
+        return $t('ui.formRules.required', [ctx.label]);
+      }
+      return true;
+    },
+    // 閫夋嫨椤圭洰蹇呭~鍥介檯鍖栭�傞厤
+    selectRequired: (value, _params, ctx) => {
+      if (value === undefined || value === null) {
+        return $t('ui.formRules.selectRequired', [ctx.label]);
+      }
+      return true;
+    },
+  },
+});
+
+const useVbenForm = useForm<ComponentType>;
+
+export { useVbenForm, z };
+export type VbenFormSchema = FormSchema<ComponentType>;
+export type { VbenFormProps };
diff --git a/eims-ui/playground/src/adapter/vxe-table.ts b/eims-ui/playground/src/adapter/vxe-table.ts
new file mode 100644
index 0000000..8f68b15
--- /dev/null
+++ b/eims-ui/playground/src/adapter/vxe-table.ts
@@ -0,0 +1,68 @@
+import { h } from 'vue';
+
+import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table';
+
+import { Button, Image } from 'ant-design-vue';
+
+import { useVbenForm } from './form';
+
+setupVbenVxeTable({
+  configVxeTable: (vxeUI) => {
+    vxeUI.setConfig({
+      grid: {
+        align: 'center',
+        border: false,
+        columnConfig: {
+          resizable: true,
+        },
+
+        formConfig: {
+          // 鍏ㄥ眬绂佺敤vxe-table鐨勮〃鍗曢厤缃紝浣跨敤formOptions
+          enabled: false,
+        },
+        minHeight: 180,
+        proxyConfig: {
+          autoLoad: true,
+          response: {
+            result: 'items',
+            total: 'total',
+            list: 'items',
+          },
+          showActiveMsg: true,
+          showResponseMsg: false,
+        },
+        round: true,
+        showOverflow: true,
+        size: 'small',
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellImage' },
+    vxeUI.renderer.add('CellImage', {
+      renderTableDefault(_renderOpts, params) {
+        const { column, row } = params;
+        return h(Image, { src: row[column.field] });
+      },
+    });
+
+    // 琛ㄦ牸閰嶇疆椤瑰彲浠ョ敤 cellRender: { name: 'CellLink' },
+    vxeUI.renderer.add('CellLink', {
+      renderTableDefault(renderOpts) {
+        const { props } = renderOpts;
+        return h(
+          Button,
+          { size: 'small', type: 'link' },
+          { default: () => props?.text },
+        );
+      },
+    });
+
+    // 杩欓噷鍙互鑷鎵╁睍 vxe-table 鐨勫叏灞�閰嶇疆锛屾瘮濡傝嚜瀹氫箟鏍煎紡鍖�
+    // vxeUI.formats.add
+  },
+  useVbenForm,
+});
+
+export { useVbenVxeGrid };
+
+export type * from '@vben/plugins/vxe-table';
diff --git a/eims-ui/playground/src/api/core/auth.ts b/eims-ui/playground/src/api/core/auth.ts
new file mode 100644
index 0000000..71d9f99
--- /dev/null
+++ b/eims-ui/playground/src/api/core/auth.ts
@@ -0,0 +1,51 @@
+import { baseRequestClient, requestClient } from '#/api/request';
+
+export namespace AuthApi {
+  /** 鐧诲綍鎺ュ彛鍙傛暟 */
+  export interface LoginParams {
+    password?: string;
+    username?: string;
+  }
+
+  /** 鐧诲綍鎺ュ彛杩斿洖鍊� */
+  export interface LoginResult {
+    accessToken: string;
+  }
+
+  export interface RefreshTokenResult {
+    data: string;
+    status: number;
+  }
+}
+
+/**
+ * 鐧诲綍
+ */
+export async function loginApi(data: AuthApi.LoginParams) {
+  return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
+}
+
+/**
+ * 鍒锋柊accessToken
+ */
+export async function refreshTokenApi() {
+  return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 閫�鍑虹櫥褰�
+ */
+export async function logoutApi() {
+  return baseRequestClient.post('/auth/logout', {
+    withCredentials: true,
+  });
+}
+
+/**
+ * 鑾峰彇鐢ㄦ埛鏉冮檺鐮�
+ */
+export async function getAccessCodesApi() {
+  return requestClient.get<string[]>('/auth/codes');
+}
diff --git a/eims-ui/playground/src/api/core/index.ts b/eims-ui/playground/src/api/core/index.ts
new file mode 100644
index 0000000..28a5aef
--- /dev/null
+++ b/eims-ui/playground/src/api/core/index.ts
@@ -0,0 +1,3 @@
+export * from './auth';
+export * from './menu';
+export * from './user';
diff --git a/eims-ui/playground/src/api/core/menu.ts b/eims-ui/playground/src/api/core/menu.ts
new file mode 100644
index 0000000..9ef60b1
--- /dev/null
+++ b/eims-ui/playground/src/api/core/menu.ts
@@ -0,0 +1,10 @@
+import type { RouteRecordStringComponent } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛鎵�鏈夎彍鍗�
+ */
+export async function getAllMenusApi() {
+  return requestClient.get<RouteRecordStringComponent[]>('/menu/all');
+}
diff --git a/eims-ui/playground/src/api/core/user.ts b/eims-ui/playground/src/api/core/user.ts
new file mode 100644
index 0000000..7e28ea8
--- /dev/null
+++ b/eims-ui/playground/src/api/core/user.ts
@@ -0,0 +1,10 @@
+import type { UserInfo } from '@vben/types';
+
+import { requestClient } from '#/api/request';
+
+/**
+ * 鑾峰彇鐢ㄦ埛淇℃伅
+ */
+export async function getUserInfoApi() {
+  return requestClient.get<UserInfo>('/user/info');
+}
diff --git a/eims-ui/playground/src/api/examples/index.ts b/eims-ui/playground/src/api/examples/index.ts
new file mode 100644
index 0000000..c830b81
--- /dev/null
+++ b/eims-ui/playground/src/api/examples/index.ts
@@ -0,0 +1,2 @@
+export * from './status';
+export * from './table';
diff --git a/eims-ui/playground/src/api/examples/status.ts b/eims-ui/playground/src/api/examples/status.ts
new file mode 100644
index 0000000..4a75fe7
--- /dev/null
+++ b/eims-ui/playground/src/api/examples/status.ts
@@ -0,0 +1,10 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * 妯℃嫙浠绘剰鐘舵�佺爜
+ */
+async function getMockStatusApi(status: string) {
+  return requestClient.get('/status', { params: { status } });
+}
+
+export { getMockStatusApi };
diff --git a/eims-ui/playground/src/api/examples/table.ts b/eims-ui/playground/src/api/examples/table.ts
new file mode 100644
index 0000000..4739ca9
--- /dev/null
+++ b/eims-ui/playground/src/api/examples/table.ts
@@ -0,0 +1,18 @@
+import { requestClient } from '#/api/request';
+
+export namespace DemoTableApi {
+  export interface PageFetchParams {
+    [key: string]: any;
+    page: number;
+    pageSize: number;
+  }
+}
+
+/**
+ * 鑾峰彇绀轰緥琛ㄦ牸鏁版嵁
+ */
+async function getExampleTableApi(params: DemoTableApi.PageFetchParams) {
+  return requestClient.get('/table/list', { params });
+}
+
+export { getExampleTableApi };
diff --git a/eims-ui/playground/src/api/index.ts b/eims-ui/playground/src/api/index.ts
new file mode 100644
index 0000000..ab806c6
--- /dev/null
+++ b/eims-ui/playground/src/api/index.ts
@@ -0,0 +1,2 @@
+export * from './core';
+export * from './examples';
diff --git a/eims-ui/playground/src/api/request.ts b/eims-ui/playground/src/api/request.ts
new file mode 100644
index 0000000..b1f6c06
--- /dev/null
+++ b/eims-ui/playground/src/api/request.ts
@@ -0,0 +1,114 @@
+/**
+ * 璇ユ枃浠跺彲鑷鏍规嵁涓氬姟閫昏緫杩涜璋冩暣
+ */
+import type { HttpResponse } from '@vben/request';
+
+import { useAppConfig } from '@vben/hooks';
+import { preferences } from '@vben/preferences';
+import {
+  authenticateResponseInterceptor,
+  errorMessageResponseInterceptor,
+  RequestClient,
+} from '@vben/request';
+import { useAccessStore } from '@vben/stores';
+
+import { message } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+import { refreshTokenApi } from './core';
+
+const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
+
+function createRequestClient(baseURL: string) {
+  const client = new RequestClient({
+    baseURL,
+  });
+
+  /**
+   * 閲嶆柊璁よ瘉閫昏緫
+   */
+  async function doReAuthenticate() {
+    console.warn('Access token or refresh token is invalid or expired. ');
+    const accessStore = useAccessStore();
+    const authStore = useAuthStore();
+    accessStore.setAccessToken(null);
+    if (
+      preferences.app.loginExpiredMode === 'modal' &&
+      accessStore.isAccessChecked
+    ) {
+      accessStore.setLoginExpired(true);
+    } else {
+      await authStore.logout();
+    }
+  }
+
+  /**
+   * 鍒锋柊token閫昏緫
+   */
+  async function doRefreshToken() {
+    const accessStore = useAccessStore();
+    const resp = await refreshTokenApi();
+    const newToken = resp.data;
+    accessStore.setAccessToken(newToken);
+    return newToken;
+  }
+
+  function formatToken(token: null | string) {
+    return token ? `Bearer ${token}` : null;
+  }
+
+  // 璇锋眰澶村鐞�
+  client.addRequestInterceptor({
+    fulfilled: async (config) => {
+      const accessStore = useAccessStore();
+
+      config.headers.Authorization = formatToken(accessStore.accessToken);
+      config.headers['Accept-Language'] = preferences.app.locale;
+      return config;
+    },
+  });
+
+  // response鏁版嵁瑙f瀯
+  client.addResponseInterceptor<HttpResponse>({
+    fulfilled: (response) => {
+      const { data: responseData, status } = response;
+
+      const { code, data } = responseData;
+
+      if (status >= 200 && status < 400 && code === 0) {
+        return data;
+      }
+      throw Object.assign({}, response, { response });
+    },
+  });
+
+  // token杩囨湡鐨勫鐞�
+  client.addResponseInterceptor(
+    authenticateResponseInterceptor({
+      client,
+      doReAuthenticate,
+      doRefreshToken,
+      enableRefreshToken: preferences.app.enableRefreshToken,
+      formatToken,
+    }),
+  );
+
+  // 閫氱敤鐨勯敊璇鐞�,濡傛灉娌℃湁杩涘叆涓婇潰鐨勯敊璇鐞嗛�昏緫锛屽氨浼氳繘鍏ヨ繖閲�
+  client.addResponseInterceptor(
+    errorMessageResponseInterceptor((msg: string, error) => {
+      // 杩欓噷鍙互鏍规嵁涓氬姟杩涜瀹氬埗,浣犲彲浠ユ嬁鍒� error 鍐呯殑淇℃伅杩涜瀹氬埗鍖栧鐞嗭紝鏍规嵁涓嶅悓鐨� code 鍋氫笉鍚岀殑鎻愮ず锛岃�屼笉鏄洿鎺ヤ娇鐢� message.error 鎻愮ず msg
+      // 褰撳墠mock鎺ュ彛杩斿洖鐨勯敊璇瓧娈垫槸 error 鎴栬�� message
+      const responseData = error?.response?.data ?? {};
+      const errorMessage = responseData?.error ?? responseData?.message ?? '';
+      // 濡傛灉娌℃湁閿欒淇℃伅锛屽垯浼氭牴鎹姸鎬佺爜杩涜鎻愮ず
+      message.error(errorMessage || msg);
+    }),
+  );
+
+  return client;
+}
+
+export const requestClient = createRequestClient(apiURL);
+
+export const baseRequestClient = new RequestClient({ baseURL: apiURL });
diff --git a/eims-ui/playground/src/app.vue b/eims-ui/playground/src/app.vue
new file mode 100644
index 0000000..bbaccce
--- /dev/null
+++ b/eims-ui/playground/src/app.vue
@@ -0,0 +1,39 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { useAntdDesignTokens } from '@vben/hooks';
+import { preferences, usePreferences } from '@vben/preferences';
+
+import { App, ConfigProvider, theme } from 'ant-design-vue';
+
+import { antdLocale } from '#/locales';
+
+defineOptions({ name: 'App' });
+
+const { isDark } = usePreferences();
+const { tokens } = useAntdDesignTokens();
+
+const tokenTheme = computed(() => {
+  const algorithm = isDark.value
+    ? [theme.darkAlgorithm]
+    : [theme.defaultAlgorithm];
+
+  // antd 绱у噾妯″紡绠楁硶
+  if (preferences.app.compact) {
+    algorithm.push(theme.compactAlgorithm);
+  }
+
+  return {
+    algorithm,
+    token: tokens,
+  };
+});
+</script>
+
+<template>
+  <ConfigProvider :locale="antdLocale" :theme="tokenTheme">
+    <App>
+      <RouterView />
+    </App>
+  </ConfigProvider>
+</template>
diff --git a/eims-ui/playground/src/bootstrap.ts b/eims-ui/playground/src/bootstrap.ts
new file mode 100644
index 0000000..09b8cfa
--- /dev/null
+++ b/eims-ui/playground/src/bootstrap.ts
@@ -0,0 +1,52 @@
+import { createApp, watchEffect } from 'vue';
+
+import { registerAccessDirective } from '@vben/access';
+import { preferences } from '@vben/preferences';
+import { initStores } from '@vben/stores';
+import '@vben/styles';
+import '@vben/styles/antd';
+
+import { VueQueryPlugin } from '@tanstack/vue-query';
+import { useTitle } from '@vueuse/core';
+
+import { $t, setupI18n } from '#/locales';
+import { router } from '#/router';
+
+import { initComponentAdapter } from './adapter/component';
+import App from './app.vue';
+
+async function bootstrap(namespace: string) {
+  // 鍒濆鍖栫粍浠堕�傞厤鍣�
+  await initComponentAdapter();
+
+  const app = createApp(App);
+
+  // 鍥介檯鍖� i18n 閰嶇疆
+  await setupI18n(app);
+
+  // 閰嶇疆 pinia-tore
+  await initStores(app, { namespace });
+
+  // 瀹夎鏉冮檺鎸囦护
+  registerAccessDirective(app);
+
+  // 閰嶇疆璺敱鍙婅矾鐢卞畧鍗�
+  app.use(router);
+
+  // 閰嶇疆@tanstack/vue-query
+  app.use(VueQueryPlugin);
+
+  // 鍔ㄦ�佹洿鏂版爣棰�
+  watchEffect(() => {
+    if (preferences.app.dynamicTitle) {
+      const routeTitle = router.currentRoute.value.meta?.title;
+      const pageTitle =
+        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
+      useTitle(pageTitle);
+    }
+  });
+
+  app.mount('#app');
+}
+
+export { bootstrap };
diff --git a/eims-ui/playground/src/layouts/auth.vue b/eims-ui/playground/src/layouts/auth.vue
new file mode 100644
index 0000000..18d415b
--- /dev/null
+++ b/eims-ui/playground/src/layouts/auth.vue
@@ -0,0 +1,23 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+
+import { AuthPageLayout } from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+
+import { $t } from '#/locales';
+
+const appName = computed(() => preferences.app.name);
+const logo = computed(() => preferences.logo.source);
+</script>
+
+<template>
+  <AuthPageLayout
+    :app-name="appName"
+    :logo="logo"
+    :page-description="$t('authentication.pageDesc')"
+    :page-title="$t('authentication.pageTitle')"
+  >
+    <!-- 鑷畾涔夊伐鍏锋爮 -->
+    <!-- <template #toolbar></template> -->
+  </AuthPageLayout>
+</template>
diff --git a/eims-ui/playground/src/layouts/basic.vue b/eims-ui/playground/src/layouts/basic.vue
new file mode 100644
index 0000000..f75b3dd
--- /dev/null
+++ b/eims-ui/playground/src/layouts/basic.vue
@@ -0,0 +1,158 @@
+<script lang="ts" setup>
+import type { NotificationItem } from '@vben/layouts';
+
+import { computed, ref, watch } from 'vue';
+
+import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
+import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
+import { useWatermark } from '@vben/hooks';
+import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons';
+import {
+  BasicLayout,
+  LockScreen,
+  Notification,
+  UserDropdown,
+} from '@vben/layouts';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import { $t } from '#/locales';
+import { useAuthStore } from '#/store';
+import LoginForm from '#/views/_core/authentication/login.vue';
+
+const notifications = ref<NotificationItem[]>([
+  {
+    avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
+    date: '3灏忔椂鍓�',
+    isRead: true,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏀跺埌浜� 14 浠芥柊鍛ㄦ姤',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '鍒氬垰',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏈卞亸鍙� 鍥炲浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/1',
+    date: '2024-01-01',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '鏇蹭附涓� 璇勮浜嗕綘',
+  },
+  {
+    avatar: 'https://avatar.vercel.sh/satori',
+    date: '1澶╁墠',
+    isRead: false,
+    message: '鎻忚堪淇℃伅鎻忚堪淇℃伅鎻忚堪淇℃伅',
+    title: '浠e姙鎻愰啋',
+  },
+]);
+
+const userStore = useUserStore();
+const authStore = useAuthStore();
+const accessStore = useAccessStore();
+const { destroyWatermark, updateWatermark } = useWatermark();
+const showDot = computed(() =>
+  notifications.value.some((item) => !item.isRead),
+);
+
+const menus = computed(() => [
+  {
+    handler: () => {
+      openWindow(VBEN_DOC_URL, {
+        target: '_blank',
+      });
+    },
+    icon: BookOpenText,
+    text: $t('ui.widgets.document'),
+  },
+  {
+    handler: () => {
+      openWindow(VBEN_GITHUB_URL, {
+        target: '_blank',
+      });
+    },
+    icon: MdiGithub,
+    text: 'GitHub',
+  },
+  {
+    handler: () => {
+      openWindow(`${VBEN_GITHUB_URL}/issues`, {
+        target: '_blank',
+      });
+    },
+    icon: CircleHelp,
+    text: $t('ui.widgets.qa'),
+  },
+]);
+
+const avatar = computed(() => {
+  return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
+});
+
+async function handleLogout() {
+  await authStore.logout(false);
+}
+
+function handleNoticeClear() {
+  notifications.value = [];
+}
+
+function handleMakeAll() {
+  notifications.value.forEach((item) => (item.isRead = true));
+}
+
+watch(
+  () => preferences.app.watermark,
+  async (enable) => {
+    if (enable) {
+      await updateWatermark({
+        content: `${userStore.userInfo?.username}`,
+      });
+    } else {
+      destroyWatermark();
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+</script>
+
+<template>
+  <BasicLayout @clear-preferences-and-logout="handleLogout">
+    <template #user-dropdown>
+      <UserDropdown
+        :avatar
+        :menus
+        :text="userStore.userInfo?.realName"
+        description="ann.vben@gmail.com"
+        tag-text="Pro"
+        @logout="handleLogout"
+      />
+    </template>
+    <template #notification>
+      <Notification
+        :dot="showDot"
+        :notifications="notifications"
+        @clear="handleNoticeClear"
+        @make-all="handleMakeAll"
+      />
+    </template>
+    <template #extra>
+      <AuthenticationLoginExpiredModal
+        v-model:open="accessStore.loginExpired"
+        :avatar
+      >
+        <LoginForm />
+      </AuthenticationLoginExpiredModal>
+    </template>
+    <template #lock-screen>
+      <LockScreen :avatar @to-login="handleLogout" />
+    </template>
+  </BasicLayout>
+</template>
diff --git a/eims-ui/playground/src/layouts/index.ts b/eims-ui/playground/src/layouts/index.ts
new file mode 100644
index 0000000..a432078
--- /dev/null
+++ b/eims-ui/playground/src/layouts/index.ts
@@ -0,0 +1,6 @@
+const BasicLayout = () => import('./basic.vue');
+const AuthPageLayout = () => import('./auth.vue');
+
+const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView);
+
+export { AuthPageLayout, BasicLayout, IFrameView };
diff --git a/eims-ui/playground/src/locales/README.md b/eims-ui/playground/src/locales/README.md
new file mode 100644
index 0000000..7b45103
--- /dev/null
+++ b/eims-ui/playground/src/locales/README.md
@@ -0,0 +1,3 @@
+# locale
+
+姣忎釜app浣跨敤鐨勫浗闄呭寲鍙兘涓嶅悓锛岃繖閲岀敤浜庢墿灞曞浗闄呭寲鐨勫姛鑳斤紝渚嬪鎵╁睍 dayjs銆乤ntd缁勪欢搴撶殑澶氳瑷�鍒囨崲锛屼互鍙奱pp鏈韩鐨勫浗闄呭寲鏂囦欢銆�
diff --git a/eims-ui/playground/src/locales/index.ts b/eims-ui/playground/src/locales/index.ts
new file mode 100644
index 0000000..1972e06
--- /dev/null
+++ b/eims-ui/playground/src/locales/index.ts
@@ -0,0 +1,100 @@
+import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
+import type { Locale } from 'ant-design-vue/es/locale';
+
+import type { App } from 'vue';
+import { ref } from 'vue';
+
+import {
+  $t,
+  setupI18n as coreSetup,
+  loadLocalesMapFromDir,
+} from '@vben/locales';
+import { preferences } from '@vben/preferences';
+
+import antdEnLocale from 'ant-design-vue/es/locale/en_US';
+import antdDefaultLocale from 'ant-design-vue/es/locale/zh_CN';
+import dayjs from 'dayjs';
+
+const antdLocale = ref<Locale>(antdDefaultLocale);
+
+const modules = import.meta.glob('./langs/**/*.json');
+
+const localesMap = loadLocalesMapFromDir(
+  /\.\/langs\/([^/]+)\/(.*)\.json$/,
+  modules,
+);
+/**
+ * 鍔犺浇搴旂敤鐗规湁鐨勮瑷�鍖�
+ * 杩欓噷涔熷彲浠ユ敼閫犱负浠庢湇鍔$鑾峰彇缈昏瘧鏁版嵁
+ * @param lang
+ */
+async function loadMessages(lang: SupportedLanguagesType) {
+  const [appLocaleMessages] = await Promise.all([
+    localesMap[lang]?.(),
+    loadThirdPartyMessage(lang),
+  ]);
+  return appLocaleMessages?.default;
+}
+
+/**
+ * 鍔犺浇绗笁鏂圭粍浠跺簱鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
+  await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
+}
+
+/**
+ * 鍔犺浇dayjs鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadDayjsLocale(lang: SupportedLanguagesType) {
+  let locale;
+  switch (lang) {
+    case 'en-US': {
+      locale = await import('dayjs/locale/en');
+      break;
+    }
+    case 'zh-CN': {
+      locale = await import('dayjs/locale/zh-cn');
+      break;
+    }
+    // 榛樿浣跨敤鑻辫
+    default: {
+      locale = await import('dayjs/locale/en');
+    }
+  }
+  if (locale) {
+    dayjs.locale(locale);
+  } else {
+    console.error(`Failed to load dayjs locale for ${lang}`);
+  }
+}
+
+/**
+ * 鍔犺浇antd鐨勮瑷�鍖�
+ * @param lang
+ */
+async function loadAntdLocale(lang: SupportedLanguagesType) {
+  switch (lang) {
+    case 'en-US': {
+      antdLocale.value = antdEnLocale;
+      break;
+    }
+    case 'zh-CN': {
+      antdLocale.value = antdDefaultLocale;
+      break;
+    }
+  }
+}
+
+async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
+  await coreSetup(app, {
+    defaultLocale: preferences.app.locale,
+    loadMessages,
+    missingWarn: !import.meta.env.PROD,
+    ...options,
+  });
+}
+
+export { $t, antdLocale, setupI18n };
diff --git a/eims-ui/playground/src/locales/langs/en-US/demos.json b/eims-ui/playground/src/locales/langs/en-US/demos.json
new file mode 100644
index 0000000..44b1278
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/en-US/demos.json
@@ -0,0 +1,70 @@
+{
+  "title": "Demos",
+  "access": {
+    "frontendPermissions": "Frontend Permissions",
+    "backendPermissions": "Backend Permissions",
+    "pageAccess": "Page Access",
+    "buttonControl": "Button Control",
+    "menuVisible403": "Menu Visible(403)",
+    "superVisible": "Visible to Super",
+    "adminVisible": "Visible to Admin",
+    "userVisible": "Visible to User"
+  },
+  "nested": {
+    "title": "Nested Menu",
+    "menu1": "Menu 1",
+    "menu2": "Menu 2",
+    "menu2_1": "Menu 2-1",
+    "menu3": "Menu 3",
+    "menu3_1": "Menu 3-1",
+    "menu3_2": "Menu 3-2",
+    "menu3_2_1": "Menu 3-2-1"
+  },
+  "outside": {
+    "title": "External Pages",
+    "embedded": "Embedded",
+    "externalLink": "External Link"
+  },
+  "badge": {
+    "title": "Menu Badge",
+    "dot": "Dot Badge",
+    "text": "Text Badge",
+    "color": "Badge Color"
+  },
+  "activeIcon": {
+    "title": "Active Menu Icon",
+    "children": "Children Active Icon"
+  },
+  "fallback": {
+    "title": "Fallback Page"
+  },
+  "features": {
+    "title": "Features",
+    "hideChildrenInMenu": "Hide Menu Children",
+    "loginExpired": "Login Expired",
+    "icons": "Icons",
+    "watermark": "Watermark",
+    "tabs": "Tabs",
+    "tabDetail": "Tab Detail Page",
+    "fullScreen": "FullScreen",
+    "clipboard": "Clipboard",
+    "menuWithQuery": "Menu With Query",
+    "openInNewWindow": "Open in New Window",
+    "fileDownload": "File Download"
+  },
+  "breadcrumb": {
+    "navigation": "Breadcrumb Navigation",
+    "lateral": "Lateral Mode",
+    "lateralDetail": "Lateral Mode Detail",
+    "level": "Level Mode",
+    "levelDetail": "Level Mode Detail"
+  },
+  "vben": {
+    "title": "Project",
+    "about": "About",
+    "document": "Document",
+    "antdv": "Ant Design Vue Version",
+    "naive-ui": "Naive UI Version",
+    "element-plus": "Element Plus Version"
+  }
+}
diff --git a/eims-ui/playground/src/locales/langs/en-US/examples.json b/eims-ui/playground/src/locales/langs/en-US/examples.json
new file mode 100644
index 0000000..490a17a
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/en-US/examples.json
@@ -0,0 +1,60 @@
+{
+  "title": "Examples",
+  "modal": {
+    "title": "Modal"
+  },
+  "drawer": {
+    "title": "Drawer"
+  },
+  "ellipsis": {
+    "title": "EllipsisText"
+  },
+  "form": {
+    "title": "Form",
+    "basic": "Basic Form",
+    "query": "Query Form",
+    "rules": "Form Rules",
+    "dynamic": "Dynamic Form",
+    "custom": "Custom Component",
+    "api": "Api",
+    "merge": "Merge Form"
+  },
+  "vxeTable": {
+    "title": "Vxe Table",
+    "basic": "Basic Table",
+    "remote": "Remote Load",
+    "tree": "Tree Table",
+    "fixed": "Fixed Header/Column",
+    "virtual": "Virtual Scroll",
+    "editCell": "Edit Cell",
+    "editRow": "Edit Row",
+    "custom-cell": "Custom Cell",
+    "form": "Form Table"
+  },
+  "captcha": {
+    "title": "Captcha",
+    "pointSelection": "Point Selection Captcha",
+    "sliderCaptcha": "Slider Captcha",
+    "sliderRotateCaptcha": "Rotate Captcha",
+    "captchaCardTitle": "Please complete the security verification",
+    "pageDescription": "Verify user identity by clicking on specific locations in the image.",
+    "pageTitle": "Captcha Component Example",
+    "basic": "Basic Usage",
+    "titlePlaceholder": "Captcha Title Text",
+    "captchaImageUrlPlaceholder": "Captcha Image (supports img tag src attribute value)",
+    "hintImage": "Hint Image",
+    "hintText": "Hint Text",
+    "hintImagePlaceholder": "Hint Image (supports img tag src attribute value)",
+    "hintTextPlaceholder": "Hint Text",
+    "showConfirm": "Show Confirm",
+    "hideConfirm": "Hide Confirm",
+    "widthPlaceholder": "Captcha Image Width Default 300px",
+    "heightPlaceholder": "Captcha Image Height Default 220px",
+    "paddingXPlaceholder": "Horizontal Padding Default 12px",
+    "paddingYPlaceholder": "Vertical Padding Default 16px",
+    "index": "Index:",
+    "timestamp": "Timestamp:",
+    "x": "x:",
+    "y": "y:"
+  }
+}
diff --git a/eims-ui/playground/src/locales/langs/en-US/page.json b/eims-ui/playground/src/locales/langs/en-US/page.json
new file mode 100644
index 0000000..618a258
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/en-US/page.json
@@ -0,0 +1,14 @@
+{
+  "auth": {
+    "login": "Login",
+    "register": "Register",
+    "codeLogin": "Code Login",
+    "qrcodeLogin": "Qr Code Login",
+    "forgetPassword": "Forget Password"
+  },
+  "dashboard": {
+    "title": "Dashboard",
+    "analytics": "Analytics",
+    "workspace": "Workspace"
+  }
+}
diff --git a/eims-ui/playground/src/locales/langs/zh-CN/demos.json b/eims-ui/playground/src/locales/langs/zh-CN/demos.json
new file mode 100644
index 0000000..254e072
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/zh-CN/demos.json
@@ -0,0 +1,70 @@
+{
+  "title": "婕旂ず",
+  "access": {
+    "frontendPermissions": "鍓嶇鏉冮檺",
+    "backendPermissions": "鍚庣鏉冮檺",
+    "pageAccess": "椤甸潰璁块棶",
+    "buttonControl": "鎸夐挳鎺у埗",
+    "menuVisible403": "鑿滃崟鍙(403)",
+    "superVisible": "Super 鍙",
+    "adminVisible": "Admin 鍙",
+    "userVisible": "User 鍙"
+  },
+  "nested": {
+    "title": "宓屽鑿滃崟",
+    "menu1": "鑿滃崟 1",
+    "menu2": "鑿滃崟 2",
+    "menu2_1": "鑿滃崟 2-1",
+    "menu3": "鑿滃崟 3",
+    "menu3_1": "鑿滃崟 3-1",
+    "menu3_2": "鑿滃崟 3-2",
+    "menu3_2_1": "鑿滃崟 3-2-1"
+  },
+  "outside": {
+    "title": "澶栭儴椤甸潰",
+    "embedded": "鍐呭祵",
+    "externalLink": "澶栭摼"
+  },
+  "badge": {
+    "title": "鑿滃崟寰芥爣",
+    "dot": "鐐瑰窘鏍�",
+    "text": "鏂囨湰寰芥爣",
+    "color": "寰芥爣棰滆壊"
+  },
+  "activeIcon": {
+    "title": "鑿滃崟婵�娲诲浘鏍�",
+    "children": "瀛愮骇婵�娲诲浘鏍�"
+  },
+  "fallback": {
+    "title": "缂虹渷椤�"
+  },
+  "features": {
+    "title": "鍔熻兘",
+    "hideChildrenInMenu": "闅愯棌瀛愯彍鍗�",
+    "loginExpired": "鐧诲綍杩囨湡",
+    "icons": "鍥炬爣",
+    "watermark": "姘村嵃",
+    "tabs": "鏍囩椤�",
+    "tabDetail": "鏍囩璇︽儏椤�",
+    "fullScreen": "鍏ㄥ睆",
+    "clipboard": "鍓创鏉�",
+    "menuWithQuery": "甯﹀弬鑿滃崟",
+    "openInNewWindow": "鏂扮獥鍙f墦寮�",
+    "fileDownload": "鏂囦欢涓嬭浇"
+  },
+  "breadcrumb": {
+    "navigation": "闈㈠寘灞戝鑸�",
+    "lateral": "骞崇骇妯″紡",
+    "level": "灞傜骇妯″紡",
+    "levelDetail": "灞傜骇妯″紡璇︽儏",
+    "lateralDetail": "骞崇骇妯″紡璇︽儏"
+  },
+  "vben": {
+    "title": "椤圭洰",
+    "about": "鍏充簬",
+    "document": "鏂囨。",
+    "antdv": "Ant Design Vue 鐗堟湰",
+    "naive-ui": "Naive UI 鐗堟湰",
+    "element-plus": "Element Plus 鐗堟湰"
+  }
+}
diff --git a/eims-ui/playground/src/locales/langs/zh-CN/examples.json b/eims-ui/playground/src/locales/langs/zh-CN/examples.json
new file mode 100644
index 0000000..227ec49
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/zh-CN/examples.json
@@ -0,0 +1,63 @@
+{
+  "title": "绀轰緥",
+  "modal": {
+    "title": "寮圭獥"
+  },
+  "drawer": {
+    "title": "鎶藉眽"
+  },
+  "ellipsis": {
+    "title": "鏂囨湰鐪佺暐"
+  },
+  "resize": {
+    "title": "鎷栧姩璋冩暣"
+  },
+  "form": {
+    "title": "琛ㄥ崟",
+    "basic": "鍩虹琛ㄥ崟",
+    "query": "鏌ヨ琛ㄥ崟",
+    "rules": "琛ㄥ崟鏍¢獙",
+    "dynamic": "鍔ㄦ�佽〃鍗�",
+    "custom": "鑷畾涔夌粍浠�",
+    "api": "Api",
+    "merge": "鍚堝苟琛ㄥ崟"
+  },
+  "vxeTable": {
+    "title": "Vxe 琛ㄦ牸",
+    "basic": "鍩虹琛ㄦ牸",
+    "remote": "杩滅▼鍔犺浇",
+    "tree": "鏍戝舰琛ㄦ牸",
+    "fixed": "鍥哄畾琛ㄥご/鍒�",
+    "virtual": "铏氭嫙婊氬姩",
+    "editCell": "鍗曞厓鏍肩紪杈�",
+    "editRow": "琛岀紪杈�",
+    "custom-cell": "鑷畾涔夊崟鍏冩牸",
+    "form": "鎼滅储琛ㄥ崟"
+  },
+  "captcha": {
+    "title": "楠岃瘉鐮�",
+    "pointSelection": "鐐归�夐獙璇�",
+    "sliderCaptcha": "婊戝潡楠岃瘉",
+    "sliderRotateCaptcha": "鏃嬭浆楠岃瘉",
+    "captchaCardTitle": "璇峰畬鎴愬畨鍏ㄩ獙璇�",
+    "pageDescription": "閫氳繃鐐瑰嚮鍥剧墖涓殑鐗瑰畾浣嶇疆鏉ラ獙璇佺敤鎴疯韩浠姐��",
+    "pageTitle": "楠岃瘉鐮佺粍浠剁ず渚�",
+    "basic": "鍩烘湰浣跨敤",
+    "titlePlaceholder": "楠岃瘉鐮佹爣棰樻枃妗�",
+    "captchaImageUrlPlaceholder": "楠岃瘉鐮佸浘鐗囷紙鏀寔img鏍囩src灞炴�у�硷級",
+    "hintImage": "鎻愮ず鍥剧墖",
+    "hintText": "鎻愮ず鏂囨湰",
+    "hintImagePlaceholder": "鎻愮ず鍥剧墖锛堟敮鎸乮mg鏍囩src灞炴�у�硷級",
+    "hintTextPlaceholder": "鎻愮ず鏂囨湰",
+    "showConfirm": "灞曠ず纭",
+    "hideConfirm": "闅愯棌纭",
+    "widthPlaceholder": "楠岃瘉鐮佸浘鐗囧搴� 榛樿300px",
+    "heightPlaceholder": "楠岃瘉鐮佸浘鐗囬珮搴� 榛樿220px",
+    "paddingXPlaceholder": "姘村钩鍐呰竟璺� 榛樿12px",
+    "paddingYPlaceholder": "鍨傜洿鍐呰竟璺� 榛樿16px",
+    "index": "绱㈠紩锛�",
+    "timestamp": "鏃堕棿鎴筹細",
+    "x": "x锛�",
+    "y": "y锛�"
+  }
+}
diff --git a/eims-ui/playground/src/locales/langs/zh-CN/page.json b/eims-ui/playground/src/locales/langs/zh-CN/page.json
new file mode 100644
index 0000000..4cb6708
--- /dev/null
+++ b/eims-ui/playground/src/locales/langs/zh-CN/page.json
@@ -0,0 +1,14 @@
+{
+  "auth": {
+    "login": "鐧诲綍",
+    "register": "娉ㄥ唽",
+    "codeLogin": "楠岃瘉鐮佺櫥褰�",
+    "qrcodeLogin": "浜岀淮鐮佺櫥褰�",
+    "forgetPassword": "蹇樿瀵嗙爜"
+  },
+  "dashboard": {
+    "title": "姒傝",
+    "analytics": "鍒嗘瀽椤�",
+    "workspace": "宸ヤ綔鍙�"
+  }
+}
diff --git a/eims-ui/playground/src/main.ts b/eims-ui/playground/src/main.ts
new file mode 100644
index 0000000..5d728a0
--- /dev/null
+++ b/eims-ui/playground/src/main.ts
@@ -0,0 +1,31 @@
+import { initPreferences } from '@vben/preferences';
+import { unmountGlobalLoading } from '@vben/utils';
+
+import { overridesPreferences } from './preferences';
+
+/**
+ * 搴旂敤鍒濆鍖栧畬鎴愪箣鍚庡啀杩涜椤甸潰鍔犺浇娓叉煋
+ */
+async function initApplication() {
+  // name鐢ㄤ簬鎸囧畾椤圭洰鍞竴鏍囪瘑
+  // 鐢ㄤ簬鍖哄垎涓嶅悓椤圭洰鐨勫亸濂借缃互鍙婂瓨鍌ㄦ暟鎹殑key鍓嶇紑浠ュ強鍏朵粬涓�浜涢渶瑕侀殧绂荤殑鏁版嵁
+  const env = import.meta.env.PROD ? 'prod' : 'dev';
+  const appVersion = import.meta.env.VITE_APP_VERSION;
+  const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${appVersion}-${env}`;
+
+  // app鍋忓ソ璁剧疆鍒濆鍖�
+  await initPreferences({
+    namespace,
+    overrides: overridesPreferences,
+  });
+
+  // 鍚姩搴旂敤骞舵寕杞�
+  // vue搴旂敤涓昏閫昏緫鍙婅鍥�
+  const { bootstrap } = await import('./bootstrap');
+  await bootstrap(namespace);
+
+  // 绉婚櫎骞堕攢姣乴oading
+  unmountGlobalLoading();
+}
+
+initApplication();
diff --git a/eims-ui/playground/src/preferences.ts b/eims-ui/playground/src/preferences.ts
new file mode 100644
index 0000000..b2e9ace
--- /dev/null
+++ b/eims-ui/playground/src/preferences.ts
@@ -0,0 +1,13 @@
+import { defineOverridesPreferences } from '@vben/preferences';
+
+/**
+ * @description 椤圭洰閰嶇疆鏂囦欢
+ * 鍙渶瑕佽鐩栭」鐩腑鐨勪竴閮ㄥ垎閰嶇疆锛屼笉闇�瑕佺殑閰嶇疆涓嶇敤瑕嗙洊锛屼細鑷姩浣跨敤榛樿閰嶇疆
+ * !!! 鏇存敼閰嶇疆鍚庤娓呯┖缂撳瓨锛屽惁鍒欏彲鑳戒笉鐢熸晥
+ */
+export const overridesPreferences = defineOverridesPreferences({
+  // overrides
+  app: {
+    name: import.meta.env.VITE_APP_TITLE,
+  },
+});
diff --git a/eims-ui/playground/src/router/access.ts b/eims-ui/playground/src/router/access.ts
new file mode 100644
index 0000000..3a48be2
--- /dev/null
+++ b/eims-ui/playground/src/router/access.ts
@@ -0,0 +1,42 @@
+import type {
+  ComponentRecordType,
+  GenerateMenuAndRoutesOptions,
+} from '@vben/types';
+
+import { generateAccessible } from '@vben/access';
+import { preferences } from '@vben/preferences';
+
+import { message } from 'ant-design-vue';
+
+import { getAllMenusApi } from '#/api';
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
+
+async function generateAccess(options: GenerateMenuAndRoutesOptions) {
+  const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
+
+  const layoutMap: ComponentRecordType = {
+    BasicLayout,
+    IFrameView,
+  };
+
+  return await generateAccessible(preferences.app.accessMode, {
+    ...options,
+    fetchMenuListAsync: async () => {
+      message.loading({
+        content: `${$t('common.loadingMenu')}...`,
+        duration: 1.5,
+      });
+      return await getAllMenusApi();
+    },
+    // 鍙互鎸囧畾娌℃湁鏉冮檺璺宠浆403椤甸潰
+    forbiddenComponent,
+    // 濡傛灉 route.meta.menuVisibleWithForbidden = true
+    layoutMap,
+    pageMap,
+  });
+}
+
+export { generateAccess };
diff --git a/eims-ui/playground/src/router/guard.ts b/eims-ui/playground/src/router/guard.ts
new file mode 100644
index 0000000..bddb28d
--- /dev/null
+++ b/eims-ui/playground/src/router/guard.ts
@@ -0,0 +1,123 @@
+import type { Router } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { preferences } from '@vben/preferences';
+import { useAccessStore, useUserStore } from '@vben/stores';
+import { startProgress, stopProgress } from '@vben/utils';
+
+import { accessRoutes, coreRouteNames } from '#/router/routes';
+import { useAuthStore } from '#/store';
+
+import { generateAccess } from './access';
+
+/**
+ * 閫氱敤瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupCommonGuard(router: Router) {
+  // 璁板綍宸茬粡鍔犺浇鐨勯〉闈�
+  const loadedPaths = new Set<string>();
+
+  router.beforeEach(async (to) => {
+    to.meta.loaded = loadedPaths.has(to.path);
+
+    // 椤甸潰鍔犺浇杩涘害鏉�
+    if (!to.meta.loaded && preferences.transition.progress) {
+      startProgress();
+    }
+    return true;
+  });
+
+  router.afterEach((to) => {
+    // 璁板綍椤甸潰鏄惁鍔犺浇,濡傛灉宸茬粡鍔犺浇锛屽悗缁殑椤甸潰鍒囨崲鍔ㄧ敾绛夋晥鏋滀笉鍦ㄩ噸澶嶆墽琛�
+    loadedPaths.add(to.path);
+
+    // 鍏抽棴椤甸潰鍔犺浇杩涘害鏉�
+    if (preferences.transition.progress) {
+      stopProgress();
+    }
+  });
+}
+
+/**
+ * 鏉冮檺璁块棶瀹堝崼閰嶇疆
+ * @param router
+ */
+function setupAccessGuard(router: Router) {
+  router.beforeEach(async (to, from) => {
+    const accessStore = useAccessStore();
+    const userStore = useUserStore();
+    const authStore = useAuthStore();
+    // 鍩烘湰璺敱锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴�
+    if (coreRouteNames.includes(to.name as string)) {
+      if (to.path === LOGIN_PATH && accessStore.accessToken) {
+        return decodeURIComponent(
+          (to.query?.redirect as string) || DEFAULT_HOME_PATH,
+        );
+      }
+      return true;
+    }
+
+    // accessToken 妫�鏌�
+    if (!accessStore.accessToken) {
+      // 鏄庣‘澹版槑蹇界暐鏉冮檺璁块棶鏉冮檺锛屽垯鍙互璁块棶
+      if (to.meta.ignoreAccess) {
+        return true;
+      }
+
+      // 娌℃湁璁块棶鏉冮檺锛岃烦杞櫥褰曢〉闈�
+      if (to.fullPath !== LOGIN_PATH) {
+        return {
+          path: LOGIN_PATH,
+          // 濡備笉闇�瑕侊紝鐩存帴鍒犻櫎 query
+          query: { redirect: encodeURIComponent(to.fullPath) },
+          // 鎼哄甫褰撳墠璺宠浆鐨勯〉闈紝鐧诲綍鍚庨噸鏂拌烦杞椤甸潰
+          replace: true,
+        };
+      }
+      return to;
+    }
+
+    // 鏄惁宸茬粡鐢熸垚杩囧姩鎬佽矾鐢�
+    if (accessStore.isAccessChecked) {
+      return true;
+    }
+
+    // 鐢熸垚璺敱琛�
+    // 褰撳墠鐧诲綍鐢ㄦ埛鎷ユ湁鐨勮鑹叉爣璇嗗垪琛�
+    const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
+    const userRoles = userInfo.roles ?? [];
+
+    // 鐢熸垚鑿滃崟鍜岃矾鐢�
+    const { accessibleMenus, accessibleRoutes } = await generateAccess({
+      roles: userRoles,
+      router,
+      // 鍒欎細鍦ㄨ彍鍗曚腑鏄剧ず锛屼絾鏄闂細琚噸瀹氬悜鍒�403
+      routes: accessRoutes,
+    });
+
+    // 淇濆瓨鑿滃崟淇℃伅鍜岃矾鐢变俊鎭�
+    accessStore.setAccessMenus(accessibleMenus);
+    accessStore.setAccessRoutes(accessibleRoutes);
+    accessStore.setIsAccessChecked(true);
+    const redirectPath = (from.query.redirect ?? to.fullPath) as string;
+
+    return {
+      ...router.resolve(decodeURIComponent(redirectPath)),
+      replace: true,
+    };
+  });
+}
+
+/**
+ * 椤圭洰瀹堝崼閰嶇疆
+ * @param router
+ */
+function createRouterGuard(router: Router) {
+  /** 閫氱敤 */
+  setupCommonGuard(router);
+  /** 鏉冮檺璁块棶 */
+  setupAccessGuard(router);
+}
+
+export { createRouterGuard };
diff --git a/eims-ui/playground/src/router/index.ts b/eims-ui/playground/src/router/index.ts
new file mode 100644
index 0000000..4840230
--- /dev/null
+++ b/eims-ui/playground/src/router/index.ts
@@ -0,0 +1,37 @@
+import {
+  createRouter,
+  createWebHashHistory,
+  createWebHistory,
+} from 'vue-router';
+
+import { resetStaticRoutes } from '@vben/utils';
+
+import { createRouterGuard } from './guard';
+import { routes } from './routes';
+
+/**
+ *  @zh_CN 鍒涘缓vue-router瀹炰緥
+ */
+const router = createRouter({
+  history:
+    import.meta.env.VITE_ROUTER_HISTORY === 'hash'
+      ? createWebHashHistory(import.meta.env.VITE_BASE)
+      : createWebHistory(import.meta.env.VITE_BASE),
+  // 搴旇娣诲姞鍒拌矾鐢辩殑鍒濆璺敱鍒楄〃銆�
+  routes,
+  scrollBehavior: (to, _from, savedPosition) => {
+    if (savedPosition) {
+      return savedPosition;
+    }
+    return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 };
+  },
+  // 鏄惁搴旇绂佹灏鹃儴鏂滄潬銆�
+  // strict: true,
+});
+
+const resetRoutes = () => resetStaticRoutes(router, routes);
+
+// 鍒涘缓璺敱瀹堝崼
+createRouterGuard(router);
+
+export { resetRoutes, router };
diff --git a/eims-ui/playground/src/router/routes/core.ts b/eims-ui/playground/src/router/routes/core.ts
new file mode 100644
index 0000000..fe030a9
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/core.ts
@@ -0,0 +1,88 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+
+import { AuthPageLayout } from '#/layouts';
+import { $t } from '#/locales';
+import Login from '#/views/_core/authentication/login.vue';
+
+/** 鍏ㄥ眬404椤甸潰 */
+const fallbackNotFoundRoute: RouteRecordRaw = {
+  component: () => import('#/views/_core/fallback/not-found.vue'),
+  meta: {
+    hideInBreadcrumb: true,
+    hideInMenu: true,
+    hideInTab: true,
+    title: '404',
+  },
+  name: 'FallbackNotFound',
+  path: '/:path(.*)*',
+};
+
+/** 鍩烘湰璺敱锛岃繖浜涜矾鐢辨槸蹇呴』瀛樺湪鐨� */
+const coreRoutes: RouteRecordRaw[] = [
+  {
+    meta: {
+      title: 'Root',
+    },
+    name: 'Root',
+    path: '/',
+    redirect: DEFAULT_HOME_PATH,
+  },
+  {
+    component: AuthPageLayout,
+    meta: {
+      hideInTab: true,
+      title: 'Authentication',
+    },
+    name: 'Authentication',
+    path: '/auth',
+    redirect: LOGIN_PATH,
+    children: [
+      {
+        name: 'Login',
+        path: 'login',
+        component: Login,
+        meta: {
+          title: $t('page.auth.login'),
+        },
+      },
+      {
+        name: 'CodeLogin',
+        path: 'code-login',
+        component: () => import('#/views/_core/authentication/code-login.vue'),
+        meta: {
+          title: $t('page.auth.codeLogin'),
+        },
+      },
+      {
+        name: 'QrCodeLogin',
+        path: 'qrcode-login',
+        component: () =>
+          import('#/views/_core/authentication/qrcode-login.vue'),
+        meta: {
+          title: $t('page.auth.qrcodeLogin'),
+        },
+      },
+      {
+        name: 'ForgetPassword',
+        path: 'forget-password',
+        component: () =>
+          import('#/views/_core/authentication/forget-password.vue'),
+        meta: {
+          title: $t('page.auth.forgetPassword'),
+        },
+      },
+      {
+        name: 'Register',
+        path: 'register',
+        component: () => import('#/views/_core/authentication/register.vue'),
+        meta: {
+          title: $t('page.auth.register'),
+        },
+      },
+    ],
+  },
+];
+
+export { coreRoutes, fallbackNotFoundRoute };
diff --git a/eims-ui/playground/src/router/routes/index.ts b/eims-ui/playground/src/router/routes/index.ts
new file mode 100644
index 0000000..e6fb144
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/index.ts
@@ -0,0 +1,37 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { mergeRouteModules, traverseTreeValues } from '@vben/utils';
+
+import { coreRoutes, fallbackNotFoundRoute } from './core';
+
+const dynamicRouteFiles = import.meta.glob('./modules/**/*.ts', {
+  eager: true,
+});
+
+// 鏈夐渶瑕佸彲浠ヨ嚜琛屾墦寮�娉ㄩ噴锛屽苟鍒涘缓鏂囦欢澶�
+// const externalRouteFiles = import.meta.glob('./external/**/*.ts', { eager: true });
+// const staticRouteFiles = import.meta.glob('./static/**/*.ts', { eager: true });
+
+/** 鍔ㄦ�佽矾鐢� */
+const dynamicRoutes: RouteRecordRaw[] = mergeRouteModules(dynamicRouteFiles);
+
+/** 澶栭儴璺敱鍒楄〃锛岃闂繖浜涢〉闈㈠彲浠ヤ笉闇�瑕丩ayout锛屽彲鑳界敤浜庡唴宓屽湪鍒殑绯荤粺(涓嶄細鏄剧ず鍦ㄨ彍鍗曚腑) */
+// const externalRoutes: RouteRecordRaw[] = mergeRouteModules(externalRouteFiles);
+// const staticRoutes: RouteRecordRaw[] = mergeRouteModules(staticRouteFiles);
+const staticRoutes: RouteRecordRaw[] = [];
+const externalRoutes: RouteRecordRaw[] = [];
+
+/** 璺敱鍒楄〃锛岀敱鍩烘湰璺敱銆佸閮ㄨ矾鐢卞拰404鍏滃簳璺敱缁勬垚
+ *  鏃犻渶璧版潈闄愰獙璇侊紙浼氫竴鐩存樉绀哄湪鑿滃崟涓級 */
+const routes: RouteRecordRaw[] = [
+  ...coreRoutes,
+  ...externalRoutes,
+  fallbackNotFoundRoute,
+];
+
+/** 鍩烘湰璺敱鍒楄〃锛岃繖浜涜矾鐢变笉闇�瑕佽繘鍏ユ潈闄愭嫤鎴� */
+const coreRouteNames = traverseTreeValues(coreRoutes, (route) => route.name);
+
+/** 鏈夋潈闄愭牎楠岀殑璺敱鍒楄〃锛屽寘鍚姩鎬佽矾鐢卞拰闈欐�佽矾鐢� */
+const accessRoutes = [...dynamicRoutes, ...staticRoutes];
+export { accessRoutes, coreRouteNames, routes };
diff --git a/eims-ui/playground/src/router/routes/modules/dashboard.ts b/eims-ui/playground/src/router/routes/modules/dashboard.ts
new file mode 100644
index 0000000..1bddab9
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/modules/dashboard.ts
@@ -0,0 +1,40 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'lucide:layout-dashboard',
+      order: -1,
+      title: $t('page.dashboard.title'),
+    },
+    name: 'Dashboard',
+    path: '/',
+    children: [
+      {
+        name: 'Analytics',
+        path: '/analytics',
+        component: () => import('#/views/dashboard/analytics/index.vue'),
+        meta: {
+          affixTab: true,
+          icon: 'lucide:area-chart',
+          title: $t('page.dashboard.analytics'),
+        },
+      },
+      {
+        name: 'Workspace',
+        path: '/workspace',
+        component: () => import('#/views/dashboard/workspace/index.vue'),
+        meta: {
+          icon: 'carbon:workspace',
+          title: $t('page.dashboard.workspace'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/playground/src/router/routes/modules/demos.ts b/eims-ui/playground/src/router/routes/modules/demos.ts
new file mode 100644
index 0000000..46ebeeb
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/modules/demos.ts
@@ -0,0 +1,572 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ic:baseline-view-in-ar',
+      keepAlive: true,
+      order: 1000,
+      title: $t('demos.title'),
+    },
+    name: 'Demos',
+    path: '/demos',
+    children: [
+      // 鏉冮檺鎺у埗
+      {
+        meta: {
+          icon: 'mdi:shield-key-outline',
+          title: $t('demos.access.frontendPermissions'),
+        },
+        name: 'AccessDemos',
+        path: '/demos/access',
+        children: [
+          {
+            name: 'AccessPageControlDemo',
+            path: '/demos/access/page-control',
+            component: () => import('#/views/demos/access/index.vue'),
+            meta: {
+              icon: 'mdi:page-previous-outline',
+              title: $t('demos.access.pageAccess'),
+            },
+          },
+          {
+            name: 'AccessButtonControlDemo',
+            path: '/demos/access/button-control',
+            component: () => import('#/views/demos/access/button-control.vue'),
+            meta: {
+              icon: 'mdi:button-cursor',
+              title: $t('demos.access.buttonControl'),
+            },
+          },
+          {
+            name: 'AccessMenuVisible403Demo',
+            path: '/demos/access/menu-visible-403',
+            component: () =>
+              import('#/views/demos/access/menu-visible-403.vue'),
+            meta: {
+              authority: ['no-body'],
+              icon: 'mdi:button-cursor',
+              menuVisibleWithForbidden: true,
+              title: $t('demos.access.menuVisible403'),
+            },
+          },
+          {
+            name: 'AccessSuperVisibleDemo',
+            path: '/demos/access/super-visible',
+            component: () => import('#/views/demos/access/super-visible.vue'),
+            meta: {
+              authority: ['super'],
+              icon: 'mdi:button-cursor',
+              title: $t('demos.access.superVisible'),
+            },
+          },
+          {
+            name: 'AccessAdminVisibleDemo',
+            path: '/demos/access/admin-visible',
+            component: () => import('#/views/demos/access/admin-visible.vue'),
+            meta: {
+              authority: ['admin'],
+              icon: 'mdi:button-cursor',
+              title: $t('demos.access.adminVisible'),
+            },
+          },
+          {
+            name: 'AccessUserVisibleDemo',
+            path: '/demos/access/user-visible',
+            component: () => import('#/views/demos/access/user-visible.vue'),
+            meta: {
+              authority: ['user'],
+              icon: 'mdi:button-cursor',
+              title: $t('demos.access.userVisible'),
+            },
+          },
+        ],
+      },
+      // 鍔熻兘
+      {
+        meta: {
+          icon: 'mdi:feature-highlight',
+          title: $t('demos.features.title'),
+        },
+        name: 'FeaturesDemos',
+        path: '/demos/features',
+        children: [
+          {
+            name: 'LoginExpiredDemo',
+            path: '/demos/features/login-expired',
+            component: () =>
+              import('#/views/demos/features/login-expired/index.vue'),
+            meta: {
+              icon: 'mdi:encryption-expiration',
+              title: $t('demos.features.loginExpired'),
+            },
+          },
+          {
+            name: 'IconsDemo',
+            path: '/demos/features/icons',
+            component: () => import('#/views/demos/features/icons/index.vue'),
+            meta: {
+              icon: 'lucide:annoyed',
+              title: $t('demos.features.icons'),
+            },
+          },
+          {
+            name: 'WatermarkDemo',
+            path: '/demos/features/watermark',
+            component: () =>
+              import('#/views/demos/features/watermark/index.vue'),
+            meta: {
+              icon: 'lucide:tags',
+              title: $t('demos.features.watermark'),
+            },
+          },
+          {
+            name: 'FeatureTabsDemo',
+            path: '/demos/features/tabs',
+            component: () => import('#/views/demos/features/tabs/index.vue'),
+            meta: {
+              icon: 'lucide:app-window',
+              title: $t('demos.features.tabs'),
+            },
+          },
+          {
+            name: 'FeatureTabDetailDemo',
+            path: '/demos/features/tabs/detail/:id',
+            component: () =>
+              import('#/views/demos/features/tabs/tab-detail.vue'),
+            meta: {
+              activePath: '/demos/features/tabs',
+              hideInMenu: true,
+              maxNumOfOpenTab: 3,
+              title: $t('demos.features.tabDetail'),
+            },
+          },
+          {
+            name: 'HideChildrenInMenuParentDemo',
+            path: '/demos/features/hide-menu-children',
+            component: () =>
+              import('#/views/demos/features/hide-menu-children/parent.vue'),
+            meta: {
+              hideChildrenInMenu: true,
+              icon: 'ic:round-menu',
+              title: $t('demos.features.hideChildrenInMenu'),
+            },
+            children: [
+              {
+                name: 'HideChildrenInMenuDemo',
+                path: '',
+                component: () =>
+                  import(
+                    '#/views/demos/features/hide-menu-children/children.vue'
+                  ),
+                meta: {
+                  hideInMenu: true,
+                  title: $t('demos.features.hideChildrenInMenu'),
+                },
+              },
+              {
+                name: 'HideChildrenInMenuChildrenDemo',
+                path: '/demos/features/hide-menu-children/children',
+                component: () =>
+                  import(
+                    '#/views/demos/features/hide-menu-children/children.vue'
+                  ),
+                meta: { title: $t('demos.features.hideChildrenInMenu') },
+              },
+            ],
+          },
+          {
+            name: 'FullScreenDemo',
+            path: '/demos/features/full-screen',
+            component: () =>
+              import('#/views/demos/features/full-screen/index.vue'),
+            meta: {
+              icon: 'lucide:fullscreen',
+              title: $t('demos.features.fullScreen'),
+            },
+          },
+          {
+            name: 'FileDownloadDemo',
+            path: '/demos/features/file-download',
+            component: () =>
+              import('#/views/demos/features/file-download/index.vue'),
+            meta: {
+              icon: 'lucide:hard-drive-download',
+              title: $t('demos.features.fileDownload'),
+            },
+          },
+          {
+            name: 'ClipboardDemo',
+            path: '/demos/features/clipboard',
+            component: () =>
+              import('#/views/demos/features/clipboard/index.vue'),
+            meta: {
+              icon: 'lucide:copy',
+              title: $t('demos.features.clipboard'),
+            },
+          },
+          {
+            name: 'MenuQueryDemo',
+            path: '/demos/menu-query',
+            component: () =>
+              import('#/views/demos/features/menu-query/index.vue'),
+            meta: {
+              icon: 'lucide:curly-braces',
+              query: {
+                id: 1,
+              },
+              title: $t('demos.features.menuWithQuery'),
+            },
+          },
+          {
+            name: 'NewWindowDemo',
+            path: '/demos/new-window',
+            component: () =>
+              import('#/views/demos/features/new-window/index.vue'),
+            meta: {
+              icon: 'lucide:app-window',
+              openInNewWindow: true,
+              title: $t('demos.features.openInNewWindow'),
+            },
+          },
+          {
+            name: 'VueQueryDemo',
+            path: '/demos/features/vue-query',
+            component: () =>
+              import('#/views/demos/features/vue-query/index.vue'),
+            meta: {
+              icon: 'lucide:git-pull-request-arrow',
+              title: 'Tanstack Query',
+            },
+          },
+        ],
+      },
+      // 闈㈠寘灞戝鑸�
+      {
+        name: 'BreadcrumbDemos',
+        path: '/demos/breadcrumb',
+        meta: {
+          icon: 'lucide:navigation',
+          title: $t('demos.breadcrumb.navigation'),
+        },
+        children: [
+          {
+            name: 'BreadcrumbLateralDemo',
+            path: '/demos/breadcrumb/lateral',
+            component: () => import('#/views/demos/breadcrumb/lateral.vue'),
+            meta: {
+              icon: 'lucide:navigation',
+              title: $t('demos.breadcrumb.lateral'),
+            },
+          },
+          {
+            name: 'BreadcrumbLateralDetailDemo',
+            path: '/demos/breadcrumb/lateral-detail',
+            component: () =>
+              import('#/views/demos/breadcrumb/lateral-detail.vue'),
+            meta: {
+              activePath: '/demos/breadcrumb/lateral',
+              hideInMenu: true,
+              title: $t('demos.breadcrumb.lateralDetail'),
+            },
+          },
+          {
+            name: 'BreadcrumbLevelDemo',
+            path: '/demos/breadcrumb/level',
+            meta: {
+              icon: 'lucide:navigation',
+              title: $t('demos.breadcrumb.level'),
+            },
+            children: [
+              {
+                name: 'BreadcrumbLevelDetailDemo',
+                path: '/demos/breadcrumb/level/detail',
+                component: () =>
+                  import('#/views/demos/breadcrumb/level-detail.vue'),
+                meta: {
+                  title: $t('demos.breadcrumb.levelDetail'),
+                },
+              },
+            ],
+          },
+        ],
+      },
+      // 缂虹渷椤�
+      {
+        meta: {
+          icon: 'mdi:lightbulb-error-outline',
+          title: $t('demos.fallback.title'),
+        },
+        name: 'FallbackDemos',
+        path: '/demos/fallback',
+        children: [
+          {
+            name: 'Fallback403Demo',
+            path: '/demos/fallback/403',
+            component: () => import('#/views/_core/fallback/forbidden.vue'),
+            meta: {
+              icon: 'mdi:do-not-disturb-alt',
+              title: '403',
+            },
+          },
+          {
+            name: 'Fallback404Demo',
+            path: '/demos/fallback/404',
+            component: () => import('#/views/_core/fallback/not-found.vue'),
+            meta: {
+              icon: 'mdi:table-off',
+              title: '404',
+            },
+          },
+          {
+            name: 'Fallback500Demo',
+            path: '/demos/fallback/500',
+            component: () =>
+              import('#/views/_core/fallback/internal-error.vue'),
+            meta: {
+              icon: 'mdi:server-network-off',
+              title: '500',
+            },
+          },
+          {
+            name: 'FallbackOfflineDemo',
+            path: '/demos/fallback/offline',
+            component: () => import('#/views/_core/fallback/offline.vue'),
+            meta: {
+              icon: 'mdi:offline',
+              title: $t('ui.fallback.offline'),
+            },
+          },
+        ],
+      },
+      // 鑿滃崟寰芥爣
+      {
+        meta: {
+          badgeType: 'dot',
+          badgeVariants: 'destructive',
+          icon: 'lucide:circle-dot',
+          title: $t('demos.badge.title'),
+        },
+        name: 'BadgeDemos',
+        path: '/demos/badge',
+        children: [
+          {
+            name: 'BadgeDotDemo',
+            component: () => import('#/views/demos/badge/index.vue'),
+            path: '/demos/badge/dot',
+            meta: {
+              badgeType: 'dot',
+              icon: 'lucide:square-dot',
+              title: $t('demos.badge.dot'),
+            },
+          },
+          {
+            name: 'BadgeTextDemo',
+            component: () => import('#/views/demos/badge/index.vue'),
+            path: '/demos/badge/text',
+            meta: {
+              badge: '10',
+              icon: 'lucide:square-dot',
+              title: $t('demos.badge.text'),
+            },
+          },
+          {
+            name: 'BadgeColorDemo',
+            component: () => import('#/views/demos/badge/index.vue'),
+            path: '/demos/badge/color',
+            meta: {
+              badge: 'Hot',
+              badgeVariants: 'destructive',
+              icon: 'lucide:square-dot',
+              title: $t('demos.badge.color'),
+            },
+          },
+        ],
+      },
+      // 鑿滃崟婵�娲诲浘鏍�
+      {
+        meta: {
+          activeIcon: 'fluent-emoji:radioactive',
+          icon: 'bi:radioactive',
+          title: $t('demos.activeIcon.title'),
+        },
+        name: 'ActiveIconDemos',
+        path: '/demos/active-icon',
+        children: [
+          {
+            name: 'ActiveIconDemo',
+            component: () => import('#/views/demos/active-icon/index.vue'),
+            path: '/demos/active-icon/children',
+            meta: {
+              activeIcon: 'fluent-emoji:radioactive',
+              icon: 'bi:radioactive',
+              title: $t('demos.activeIcon.children'),
+            },
+          },
+        ],
+      },
+      // 澶栭儴閾炬帴
+      {
+        meta: {
+          icon: 'ic:round-settings-input-composite',
+          title: $t('demos.outside.title'),
+        },
+        name: 'OutsideDemos',
+        path: '/demos/outside',
+        children: [
+          {
+            name: 'IframeDemos',
+            path: '/demos/outside/iframe',
+            meta: {
+              icon: 'mdi:newspaper-variant-outline',
+              title: $t('demos.outside.embedded'),
+            },
+            children: [
+              {
+                name: 'VueDocumentDemo',
+                path: '/demos/outside/iframe/vue-document',
+                component: IFrameView,
+                meta: {
+                  icon: 'logos:vue',
+                  iframeSrc: 'https://cn.vuejs.org/',
+                  keepAlive: true,
+                  title: 'Vue',
+                },
+              },
+              {
+                name: 'TailwindcssDemo',
+                path: '/demos/outside/iframe/tailwindcss',
+                component: IFrameView,
+                meta: {
+                  icon: 'devicon:tailwindcss',
+                  iframeSrc: 'https://tailwindcss.com/',
+                  // keepAlive: true,
+                  title: 'Tailwindcss',
+                },
+              },
+            ],
+          },
+          {
+            name: 'ExternalLinkDemos',
+            path: '/demos/outside/external-link',
+            meta: {
+              icon: 'mdi:newspaper-variant-multiple-outline',
+              title: $t('demos.outside.externalLink'),
+            },
+            children: [
+              {
+                name: 'ViteDemo',
+                path: '/demos/outside/external-link/vite',
+                component: IFrameView,
+                meta: {
+                  icon: 'logos:vitejs',
+                  link: 'https://vitejs.dev/',
+                  title: 'Vite',
+                },
+              },
+              {
+                name: 'VueUseDemo',
+                path: '/demos/outside/external-link/vue-use',
+                component: IFrameView,
+                meta: {
+                  icon: 'logos:vueuse',
+                  link: 'https://vueuse.org',
+                  title: 'VueUse',
+                },
+              },
+            ],
+          },
+        ],
+      },
+      // 宓屽鑿滃崟
+      {
+        meta: {
+          icon: 'ic:round-menu',
+          title: $t('demos.nested.title'),
+        },
+        name: 'NestedDemos',
+        path: '/demos/nested',
+        children: [
+          {
+            name: 'Menu1Demo',
+            path: '/demos/nested/menu1',
+            component: () => import('#/views/demos/nested/menu-1.vue'),
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu1'),
+            },
+          },
+          {
+            name: 'Menu2Demo',
+            path: '/demos/nested/menu2',
+            meta: {
+              icon: 'ic:round-menu',
+              keepAlive: true,
+              title: $t('demos.nested.menu2'),
+            },
+            children: [
+              {
+                name: 'Menu21Demo',
+                path: '/demos/nested/menu2/menu2-1',
+                component: () => import('#/views/demos/nested/menu-2-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu2_1'),
+                },
+              },
+            ],
+          },
+          {
+            name: 'Menu3Demo',
+            path: '/demos/nested/menu3',
+            meta: {
+              icon: 'ic:round-menu',
+              title: $t('demos.nested.menu3'),
+            },
+            children: [
+              {
+                name: 'Menu31Demo',
+                path: 'menu3-1',
+                component: () => import('#/views/demos/nested/menu-3-1.vue'),
+                meta: {
+                  icon: 'ic:round-menu',
+                  keepAlive: true,
+                  title: $t('demos.nested.menu3_1'),
+                },
+              },
+              {
+                name: 'Menu32Demo',
+                path: 'menu3-2',
+                meta: {
+                  icon: 'ic:round-menu',
+                  title: $t('demos.nested.menu3_2'),
+                },
+                children: [
+                  {
+                    name: 'Menu321Demo',
+                    path: '/demos/nested/menu3/menu3-2/menu3-2-1',
+                    component: () =>
+                      import('#/views/demos/nested/menu-3-2-1.vue'),
+                    meta: {
+                      icon: 'ic:round-menu',
+                      keepAlive: true,
+                      title: $t('demos.nested.menu3_2_1'),
+                    },
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/playground/src/router/routes/modules/examples.ts b/eims-ui/playground/src/router/routes/modules/examples.ts
new file mode 100644
index 0000000..82202b3
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/modules/examples.ts
@@ -0,0 +1,244 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import { BasicLayout } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      icon: 'ion:layers-outline',
+      keepAlive: true,
+      order: 1000,
+      title: $t('examples.title'),
+    },
+    name: 'Examples',
+    path: '/examples',
+    children: [
+      {
+        name: 'FormExample',
+        path: '/examples/form',
+        meta: {
+          icon: 'mdi:form-select',
+          title: $t('examples.form.title'),
+        },
+        children: [
+          {
+            name: 'FormBasicExample',
+            path: '/examples/form/basic',
+            component: () => import('#/views/examples/form/basic.vue'),
+            meta: {
+              title: $t('examples.form.basic'),
+            },
+          },
+          {
+            name: 'FormQueryExample',
+            path: '/examples/form/query',
+            component: () => import('#/views/examples/form/query.vue'),
+            meta: {
+              title: $t('examples.form.query'),
+            },
+          },
+          {
+            name: 'FormRulesExample',
+            path: '/examples/form/rules',
+            component: () => import('#/views/examples/form/rules.vue'),
+            meta: {
+              title: $t('examples.form.rules'),
+            },
+          },
+          {
+            name: 'FormDynamicExample',
+            path: '/examples/form/dynamic',
+            component: () => import('#/views/examples/form/dynamic.vue'),
+            meta: {
+              title: $t('examples.form.dynamic'),
+            },
+          },
+          {
+            name: 'FormCustomExample',
+            path: '/examples/form/custom',
+            component: () => import('#/views/examples/form/custom.vue'),
+            meta: {
+              title: $t('examples.form.custom'),
+            },
+          },
+          {
+            name: 'FormApiExample',
+            path: '/examples/form/api',
+            component: () => import('#/views/examples/form/api.vue'),
+            meta: {
+              title: $t('examples.form.api'),
+            },
+          },
+          {
+            name: 'FormMergeExample',
+            path: '/examples/form/merge',
+            component: () => import('#/views/examples/form/merge.vue'),
+            meta: {
+              title: $t('examples.form.merge'),
+            },
+          },
+        ],
+      },
+      {
+        name: 'VxeTableExample',
+        path: '/examples/vxe-table',
+        meta: {
+          icon: 'lucide:table',
+          title: $t('examples.vxeTable.title'),
+        },
+        children: [
+          {
+            name: 'VxeTableBasicExample',
+            path: '/examples/vxe-table/basic',
+            component: () => import('#/views/examples/vxe-table/basic.vue'),
+            meta: {
+              title: $t('examples.vxeTable.basic'),
+            },
+          },
+          {
+            name: 'VxeTableRemoteExample',
+            path: '/examples/vxe-table/remote',
+            component: () => import('#/views/examples/vxe-table/remote.vue'),
+            meta: {
+              title: $t('examples.vxeTable.remote'),
+            },
+          },
+          {
+            name: 'VxeTableTreeExample',
+            path: '/examples/vxe-table/tree',
+            component: () => import('#/views/examples/vxe-table/tree.vue'),
+            meta: {
+              title: $t('examples.vxeTable.tree'),
+            },
+          },
+          {
+            name: 'VxeTableFixedExample',
+            path: '/examples/vxe-table/fixed',
+            component: () => import('#/views/examples/vxe-table/fixed.vue'),
+            meta: {
+              title: $t('examples.vxeTable.fixed'),
+            },
+          },
+          {
+            name: 'VxeTableCustomCellExample',
+            path: '/examples/vxe-table/custom-cell',
+            component: () =>
+              import('#/views/examples/vxe-table/custom-cell.vue'),
+            meta: {
+              title: $t('examples.vxeTable.custom-cell'),
+            },
+          },
+          {
+            name: 'VxeTableFormExample',
+            path: '/examples/vxe-table/form',
+            component: () => import('#/views/examples/vxe-table/form.vue'),
+            meta: {
+              title: $t('examples.vxeTable.form'),
+            },
+          },
+          {
+            name: 'VxeTableEditCellExample',
+            path: '/examples/vxe-table/edit-cell',
+            component: () => import('#/views/examples/vxe-table/edit-cell.vue'),
+            meta: {
+              title: $t('examples.vxeTable.editCell'),
+            },
+          },
+          {
+            name: 'VxeTableEditRowExample',
+            path: '/examples/vxe-table/edit-row',
+            component: () => import('#/views/examples/vxe-table/edit-row.vue'),
+            meta: {
+              title: $t('examples.vxeTable.editRow'),
+            },
+          },
+          {
+            name: 'VxeTableVirtualExample',
+            path: '/examples/vxe-table/virtual',
+            component: () => import('#/views/examples/vxe-table/virtual.vue'),
+            meta: {
+              title: $t('examples.vxeTable.virtual'),
+            },
+          },
+        ],
+      },
+      {
+        name: 'CaptchaExample',
+        path: '/examples/captcha',
+        meta: {
+          icon: 'logos:recaptcha',
+          title: $t('examples.captcha.title'),
+        },
+        children: [
+          {
+            name: 'DragVerifyExample',
+            path: '/examples/captcha/slider',
+            component: () =>
+              import('#/views/examples/captcha/slider-captcha.vue'),
+            meta: {
+              title: $t('examples.captcha.sliderCaptcha'),
+            },
+          },
+          {
+            name: 'RotateVerifyExample',
+            path: '/examples/captcha/slider-rotate',
+            component: () =>
+              import('#/views/examples/captcha/slider-rotate-captcha.vue'),
+            meta: {
+              title: $t('examples.captcha.sliderRotateCaptcha'),
+            },
+          },
+          {
+            name: 'CaptchaPointSelectionExample',
+            path: '/examples/captcha/point-selection',
+            component: () =>
+              import('#/views/examples/captcha/point-selection-captcha.vue'),
+            meta: {
+              title: $t('examples.captcha.pointSelection'),
+            },
+          },
+        ],
+      },
+      {
+        name: 'ModalExample',
+        path: '/examples/modal',
+        component: () => import('#/views/examples/modal/index.vue'),
+        meta: {
+          icon: 'system-uicons:window-content',
+          title: $t('examples.modal.title'),
+        },
+      },
+      {
+        name: 'DrawerExample',
+        path: '/examples/drawer',
+        component: () => import('#/views/examples/drawer/index.vue'),
+        meta: {
+          icon: 'iconoir:drawer',
+          title: $t('examples.drawer.title'),
+        },
+      },
+      {
+        name: 'EllipsisExample',
+        path: '/examples/ellipsis',
+        component: () => import('#/views/examples/ellipsis/index.vue'),
+        meta: {
+          icon: 'ion:ellipsis-horizontal',
+          title: $t('examples.ellipsis.title'),
+        },
+      },
+      {
+        name: 'VueResizeDemo',
+        path: '/demos/resize/basic',
+        component: () => import('#/views/examples/resize/basic.vue'),
+        meta: {
+          icon: 'material-symbols:resize',
+          title: $t('examples.resize.title'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/playground/src/router/routes/modules/vben.ts b/eims-ui/playground/src/router/routes/modules/vben.ts
new file mode 100644
index 0000000..2f2eb66
--- /dev/null
+++ b/eims-ui/playground/src/router/routes/modules/vben.ts
@@ -0,0 +1,94 @@
+import type { RouteRecordRaw } from 'vue-router';
+
+import {
+  VBEN_ANT_PREVIEW_URL,
+  VBEN_DOC_URL,
+  VBEN_ELE_PREVIEW_URL,
+  VBEN_GITHUB_URL,
+  VBEN_LOGO_URL,
+  VBEN_NAIVE_PREVIEW_URL,
+} from '@vben/constants';
+import { SvgAntdvLogoIcon } from '@vben/icons';
+
+import { BasicLayout, IFrameView } from '#/layouts';
+import { $t } from '#/locales';
+
+const routes: RouteRecordRaw[] = [
+  {
+    component: BasicLayout,
+    meta: {
+      badgeType: 'dot',
+      icon: VBEN_LOGO_URL,
+      order: 9999,
+      title: $t('demos.vben.title'),
+    },
+    name: 'VbenProject',
+    path: '/vben-admin',
+    children: [
+      {
+        name: 'VbenAbout',
+        path: '/vben-admin/about',
+        component: () => import('#/views/_core/about/index.vue'),
+        meta: {
+          icon: 'lucide:copyright',
+          title: $t('demos.vben.about'),
+        },
+      },
+      {
+        name: 'VbenDocument',
+        path: '/vben-admin/document',
+        component: IFrameView,
+        meta: {
+          icon: 'lucide:book-open-text',
+          link: VBEN_DOC_URL,
+          title: $t('demos.vben.document'),
+        },
+      },
+      {
+        name: 'VbenGithub',
+        path: '/vben-admin/github',
+        component: IFrameView,
+        meta: {
+          icon: 'mdi:github',
+          link: VBEN_GITHUB_URL,
+          title: 'Github',
+        },
+      },
+      {
+        name: 'VbenAntdv',
+        path: '/vben-admin/antdv',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: SvgAntdvLogoIcon,
+          link: VBEN_ANT_PREVIEW_URL,
+          title: $t('demos.vben.antdv'),
+        },
+      },
+      {
+        name: 'VbenNaive',
+        path: '/vben-admin/naive',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:naiveui',
+          link: VBEN_NAIVE_PREVIEW_URL,
+          title: $t('demos.vben.naive-ui'),
+        },
+      },
+      {
+        name: 'VbenElementPlus',
+        path: '/vben-admin/ele',
+        component: IFrameView,
+        meta: {
+          badgeType: 'dot',
+          icon: 'logos:element',
+          link: VBEN_ELE_PREVIEW_URL,
+          title: $t('demos.vben.element-plus'),
+        },
+      },
+    ],
+  },
+];
+
+export default routes;
diff --git a/eims-ui/playground/src/store/auth.ts b/eims-ui/playground/src/store/auth.ts
new file mode 100644
index 0000000..9976ac5
--- /dev/null
+++ b/eims-ui/playground/src/store/auth.ts
@@ -0,0 +1,117 @@
+import type { Recordable, UserInfo } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { DEFAULT_HOME_PATH, LOGIN_PATH } from '@vben/constants';
+import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores';
+
+import { notification } from 'ant-design-vue';
+import { defineStore } from 'pinia';
+
+import { getAccessCodesApi, getUserInfoApi, loginApi, logoutApi } from '#/api';
+import { $t } from '#/locales';
+
+export const useAuthStore = defineStore('auth', () => {
+  const accessStore = useAccessStore();
+  const userStore = useUserStore();
+  const router = useRouter();
+
+  const loginLoading = ref(false);
+
+  /**
+   * 寮傛澶勭悊鐧诲綍鎿嶄綔
+   * Asynchronously handle the login process
+   * @param params 鐧诲綍琛ㄥ崟鏁版嵁
+   * @param onSuccess 鎴愬姛涔嬪悗鐨勫洖璋冨嚱鏁�
+   */
+  async function authLogin(
+    params: Recordable<any>,
+    onSuccess?: () => Promise<void> | void,
+  ) {
+    // 寮傛澶勭悊鐢ㄦ埛鐧诲綍鎿嶄綔骞惰幏鍙� accessToken
+    let userInfo: null | UserInfo = null;
+    try {
+      loginLoading.value = true;
+      const { accessToken } = await loginApi(params);
+
+      // 濡傛灉鎴愬姛鑾峰彇鍒� accessToken
+      if (accessToken) {
+        accessStore.setAccessToken(accessToken);
+
+        // 鑾峰彇鐢ㄦ埛淇℃伅骞跺瓨鍌ㄥ埌 accessStore 涓�
+        const [fetchUserInfoResult, accessCodes] = await Promise.all([
+          fetchUserInfo(),
+          getAccessCodesApi(),
+        ]);
+
+        userInfo = fetchUserInfoResult;
+
+        userStore.setUserInfo(userInfo);
+        accessStore.setAccessCodes(accessCodes);
+
+        if (accessStore.loginExpired) {
+          accessStore.setLoginExpired(false);
+        } else {
+          onSuccess
+            ? await onSuccess?.()
+            : await router.push(userInfo.homePath || DEFAULT_HOME_PATH);
+        }
+
+        if (userInfo?.realName) {
+          notification.success({
+            description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`,
+            duration: 3,
+            message: $t('authentication.loginSuccess'),
+          });
+        }
+      }
+    } finally {
+      loginLoading.value = false;
+    }
+
+    return {
+      userInfo,
+    };
+  }
+
+  async function logout(redirect: boolean = true) {
+    try {
+      await logoutApi();
+    } catch {
+      // 涓嶅仛浠讳綍澶勭悊
+    }
+
+    resetAllStores();
+    accessStore.setLoginExpired(false);
+
+    // 鍥炵櫥褰曢〉甯︿笂褰撳墠璺敱鍦板潃
+    await router.replace({
+      path: LOGIN_PATH,
+      query: redirect
+        ? {
+            redirect: encodeURIComponent(router.currentRoute.value.fullPath),
+          }
+        : {},
+    });
+  }
+
+  async function fetchUserInfo() {
+    let userInfo: null | UserInfo = null;
+    userInfo = await getUserInfoApi();
+    userStore.setUserInfo(userInfo);
+    return userInfo;
+  }
+
+  function $reset() {
+    loginLoading.value = false;
+  }
+
+  return {
+    $reset,
+    authLogin,
+    fetchUserInfo,
+    loginLoading,
+    logout,
+  };
+});
diff --git a/eims-ui/playground/src/store/index.ts b/eims-ui/playground/src/store/index.ts
new file mode 100644
index 0000000..269586e
--- /dev/null
+++ b/eims-ui/playground/src/store/index.ts
@@ -0,0 +1 @@
+export * from './auth';
diff --git a/eims-ui/playground/src/views/_core/README.md b/eims-ui/playground/src/views/_core/README.md
new file mode 100644
index 0000000..8248afe
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/README.md
@@ -0,0 +1,3 @@
+# \_core
+
+姝ょ洰褰曞寘鍚簲鐢ㄧ▼搴忔甯歌繍琛屾墍闇�鐨勫熀鏈鍥俱�傝繖浜涜鍥炬槸搴旂敤绋嬪簭甯冨眬涓娇鐢ㄧ殑瑙嗗浘銆�
diff --git a/eims-ui/playground/src/views/_core/about/index.vue b/eims-ui/playground/src/views/_core/about/index.vue
new file mode 100644
index 0000000..0ee5243
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/about/index.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { About } from '@vben/common-ui';
+
+defineOptions({ name: 'About' });
+</script>
+
+<template>
+  <About />
+</template>
diff --git a/eims-ui/playground/src/views/_core/authentication/code-login.vue b/eims-ui/playground/src/views/_core/authentication/code-login.vue
new file mode 100644
index 0000000..556b273
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/authentication/code-login.vue
@@ -0,0 +1,65 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationCodeLogin, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'CodeLogin' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.mobile'),
+      },
+      fieldName: 'phoneNumber',
+      label: $t('authentication.mobile'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.mobileTip') })
+        .refine((v) => /^\d{11}$/.test(v), {
+          message: $t('authentication.mobileErrortip'),
+        }),
+    },
+    {
+      component: 'VbenPinInput',
+      componentProps: {
+        createText: (countdown: number) => {
+          const text =
+            countdown > 0
+              ? $t('authentication.sendText', [countdown])
+              : $t('authentication.sendCode');
+          return text;
+        },
+        placeholder: $t('authentication.code'),
+      },
+      fieldName: 'code',
+      label: $t('authentication.code'),
+      rules: z.string().min(1, { message: $t('authentication.codeTip') }),
+    },
+  ];
+});
+/**
+ * 寮傛澶勭悊鐧诲綍鎿嶄綔
+ * Asynchronously handle the login process
+ * @param values 鐧诲綍琛ㄥ崟鏁版嵁
+ */
+async function handleLogin(values: Recordable<any>) {
+  // eslint-disable-next-line no-console
+  console.log(values);
+}
+</script>
+
+<template>
+  <AuthenticationCodeLogin
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleLogin"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/_core/authentication/forget-password.vue b/eims-ui/playground/src/views/_core/authentication/forget-password.vue
new file mode 100644
index 0000000..3449111
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/authentication/forget-password.vue
@@ -0,0 +1,42 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+
+import { computed, ref } from 'vue';
+
+import { AuthenticationForgetPassword, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'ForgetPassword' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: 'example@example.com',
+      },
+      fieldName: 'email',
+      label: $t('authentication.email'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.emailTip') })
+        .email($t('authentication.emailValidErrorTip')),
+    },
+  ];
+});
+
+function handleSubmit(value: Record<string, any>) {
+  // eslint-disable-next-line no-console
+  console.log('reset email:', value);
+}
+</script>
+
+<template>
+  <AuthenticationForgetPassword
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/_core/authentication/login.vue b/eims-ui/playground/src/views/_core/authentication/login.vue
new file mode 100644
index 0000000..4f6f564
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/authentication/login.vue
@@ -0,0 +1,115 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { BasicOption } from '@vben/types';
+
+import { computed, markRaw } from 'vue';
+
+import { AuthenticationLogin, SliderCaptcha, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+import { useAuthStore } from '#/store';
+
+defineOptions({ name: 'Login' });
+
+const authStore = useAuthStore();
+
+const MOCK_USER_OPTIONS: BasicOption[] = [
+  {
+    label: 'Super',
+    value: 'vben',
+  },
+  {
+    label: 'Admin',
+    value: 'admin',
+  },
+  {
+    label: 'User',
+    value: 'jack',
+  },
+];
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenSelect',
+      // componentProps(_values, form) {
+      //   return {
+      //     'onUpdate:modelValue': (value: string) => {
+      //       const findItem = MOCK_USER_OPTIONS.find(
+      //         (item) => item.value === value,
+      //       );
+      //       if (findItem) {
+      //         form.setValues({
+      //           password: '123456',
+      //           username: findItem.label,
+      //         });
+      //       }
+      //     },
+      //     options: MOCK_USER_OPTIONS,
+      //     placeholder: $t('authentication.selectAccount'),
+      //   };
+      // },
+      componentProps: {
+        options: MOCK_USER_OPTIONS,
+        placeholder: $t('authentication.selectAccount'),
+      },
+      fieldName: 'selectAccount',
+      label: $t('authentication.selectAccount'),
+      rules: z
+        .string()
+        .min(1, { message: $t('authentication.selectAccount') })
+        .optional()
+        .default('vben'),
+    },
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      dependencies: {
+        trigger(values, form) {
+          if (values.selectAccount) {
+            const findUser = MOCK_USER_OPTIONS.find(
+              (item) => item.value === values.selectAccount,
+            );
+            if (findUser) {
+              form.setValues({
+                password: '123456',
+                username: findUser.value,
+              });
+            }
+          }
+        },
+        triggerFields: ['selectAccount'],
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: markRaw(SliderCaptcha),
+      fieldName: 'captcha',
+      rules: z.boolean().refine((value) => value, {
+        message: $t('authentication.verifyRequiredTip'),
+      }),
+    },
+  ];
+});
+</script>
+
+<template>
+  <AuthenticationLogin
+    :form-schema="formSchema"
+    :loading="authStore.loginLoading"
+    @submit="authStore.authLogin"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/_core/authentication/qrcode-login.vue b/eims-ui/playground/src/views/_core/authentication/qrcode-login.vue
new file mode 100644
index 0000000..23f5f2d
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/authentication/qrcode-login.vue
@@ -0,0 +1,10 @@
+<script lang="ts" setup>
+import { AuthenticationQrCodeLogin } from '@vben/common-ui';
+import { LOGIN_PATH } from '@vben/constants';
+
+defineOptions({ name: 'QrCodeLogin' });
+</script>
+
+<template>
+  <AuthenticationQrCodeLogin :login-path="LOGIN_PATH" />
+</template>
diff --git a/eims-ui/playground/src/views/_core/authentication/register.vue b/eims-ui/playground/src/views/_core/authentication/register.vue
new file mode 100644
index 0000000..b1a5de7
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/authentication/register.vue
@@ -0,0 +1,96 @@
+<script lang="ts" setup>
+import type { VbenFormSchema } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
+
+import { computed, h, ref } from 'vue';
+
+import { AuthenticationRegister, z } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+
+defineOptions({ name: 'Register' });
+
+const loading = ref(false);
+
+const formSchema = computed((): VbenFormSchema[] => {
+  return [
+    {
+      component: 'VbenInput',
+      componentProps: {
+        placeholder: $t('authentication.usernameTip'),
+      },
+      fieldName: 'username',
+      label: $t('authentication.username'),
+      rules: z.string().min(1, { message: $t('authentication.usernameTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        passwordStrength: true,
+        placeholder: $t('authentication.password'),
+      },
+      fieldName: 'password',
+      label: $t('authentication.password'),
+      renderComponentContent() {
+        return {
+          strengthText: () => $t('authentication.passwordStrength'),
+        };
+      },
+      rules: z.string().min(1, { message: $t('authentication.passwordTip') }),
+    },
+    {
+      component: 'VbenInputPassword',
+      componentProps: {
+        placeholder: $t('authentication.confirmPassword'),
+      },
+      dependencies: {
+        rules(values) {
+          const { password } = values;
+          return z
+            .string({ required_error: $t('authentication.passwordTip') })
+            .min(1, { message: $t('authentication.passwordTip') })
+            .refine((value) => value === password, {
+              message: $t('authentication.confirmPasswordTip'),
+            });
+        },
+        triggerFields: ['password'],
+      },
+      fieldName: 'confirmPassword',
+      label: $t('authentication.confirmPassword'),
+    },
+    {
+      component: 'VbenCheckbox',
+      fieldName: 'agreePolicy',
+      renderComponentContent: () => ({
+        default: () =>
+          h('span', [
+            $t('authentication.agree'),
+            h(
+              'a',
+              {
+                class: 'vben-link ml-1 ',
+                href: '',
+              },
+              `${$t('authentication.privacyPolicy')} & ${$t('authentication.terms')}`,
+            ),
+          ]),
+      }),
+      rules: z.boolean().refine((value) => !!value, {
+        message: $t('authentication.agreeTip'),
+      }),
+    },
+  ];
+});
+
+function handleSubmit(value: Recordable<any>) {
+  // eslint-disable-next-line no-console
+  console.log('register submit:', value);
+}
+</script>
+
+<template>
+  <AuthenticationRegister
+    :form-schema="formSchema"
+    :loading="loading"
+    @submit="handleSubmit"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/_core/fallback/coming-soon.vue b/eims-ui/playground/src/views/_core/fallback/coming-soon.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/fallback/coming-soon.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/playground/src/views/_core/fallback/forbidden.vue b/eims-ui/playground/src/views/_core/fallback/forbidden.vue
new file mode 100644
index 0000000..8ea65fe
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/fallback/forbidden.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback403Demo' });
+</script>
+
+<template>
+  <Fallback status="403" />
+</template>
diff --git a/eims-ui/playground/src/views/_core/fallback/internal-error.vue b/eims-ui/playground/src/views/_core/fallback/internal-error.vue
new file mode 100644
index 0000000..819a47d
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/fallback/internal-error.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback500Demo' });
+</script>
+
+<template>
+  <Fallback status="500" />
+</template>
diff --git a/eims-ui/playground/src/views/_core/fallback/not-found.vue b/eims-ui/playground/src/views/_core/fallback/not-found.vue
new file mode 100644
index 0000000..4d178e9
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/fallback/not-found.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'Fallback404Demo' });
+</script>
+
+<template>
+  <Fallback status="404" />
+</template>
diff --git a/eims-ui/playground/src/views/_core/fallback/offline.vue b/eims-ui/playground/src/views/_core/fallback/offline.vue
new file mode 100644
index 0000000..5de4a88
--- /dev/null
+++ b/eims-ui/playground/src/views/_core/fallback/offline.vue
@@ -0,0 +1,9 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+
+defineOptions({ name: 'FallbackOfflineDemo' });
+</script>
+
+<template>
+  <Fallback status="offline" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/analytics-trends.vue b/eims-ui/playground/src/views/dashboard/analytics/analytics-trends.vue
new file mode 100644
index 0000000..fadfc91
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/analytics-trends.vue
@@ -0,0 +1,100 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        areaStyle: {},
+        data: [
+          111, 2000, 6000, 16_000, 33_333, 55_555, 64_000, 33_333, 18_000,
+          36_000, 70_000, 42_444, 23_222, 13_000, 8000, 4000, 1200, 333, 222,
+          111,
+        ],
+        itemStyle: {
+          color: '#5ab1ef',
+        },
+        smooth: true,
+        type: 'line',
+      },
+      {
+        areaStyle: {},
+        data: [
+          33, 66, 88, 333, 3333, 6200, 20_000, 3000, 1200, 13_000, 22_000,
+          11_000, 2221, 1201, 390, 198, 60, 30, 22, 11,
+        ],
+        itemStyle: {
+          color: '#019680',
+        },
+        smooth: true,
+        type: 'line',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          color: '#019680',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    // xAxis: {
+    //   axisTick: {
+    //     show: false,
+    //   },
+    //   boundaryGap: false,
+    //   data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+    //   type: 'category',
+    // },
+    xAxis: {
+      axisTick: {
+        show: false,
+      },
+      boundaryGap: false,
+      data: Array.from({ length: 18 }).map((_item, index) => `${index + 6}:00`),
+      splitLine: {
+        lineStyle: {
+          type: 'solid',
+          width: 1,
+        },
+        show: true,
+      },
+      type: 'category',
+    },
+    yAxis: [
+      {
+        axisTick: {
+          show: false,
+        },
+        max: 80_000,
+        splitArea: {
+          show: true,
+        },
+        splitNumber: 4,
+        type: 'value',
+      },
+    ],
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-data.vue b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-data.vue
new file mode 100644
index 0000000..30c4265
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-data.vue
@@ -0,0 +1,84 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: 0,
+      data: ['璁块棶', '瓒嬪娍'],
+    },
+    radar: {
+      indicator: [
+        {
+          name: '缃戦〉',
+        },
+        {
+          name: '绉诲姩绔�',
+        },
+        {
+          name: 'Ipad',
+        },
+        {
+          name: '瀹㈡埛绔�',
+        },
+        {
+          name: '绗笁鏂�',
+        },
+        {
+          name: '鍏跺畠',
+        },
+      ],
+      radius: '60%',
+      splitNumber: 8,
+    },
+    series: [
+      {
+        areaStyle: {
+          opacity: 1,
+          shadowBlur: 0,
+          shadowColor: 'rgba(0,0,0,.2)',
+          shadowOffsetX: 0,
+          shadowOffsetY: 10,
+        },
+        data: [
+          {
+            itemStyle: {
+              color: '#b6a2de',
+            },
+            name: '璁块棶',
+            value: [90, 50, 86, 40, 50, 20],
+          },
+          {
+            itemStyle: {
+              color: '#5ab1ef',
+            },
+            name: '瓒嬪娍',
+            value: [70, 75, 70, 76, 20, 85],
+          },
+        ],
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        symbolSize: 0,
+        type: 'radar',
+      },
+    ],
+    tooltip: {},
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-sales.vue b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-sales.vue
new file mode 100644
index 0000000..260520b
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-sales.vue
@@ -0,0 +1,48 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 400;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        center: ['50%', '50%'],
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '澶栧寘', value: 500 },
+          { name: '瀹氬埗', value: 310 },
+          { name: '鎶�鏈敮鎸�', value: 274 },
+          { name: '杩滅▼', value: 400 },
+        ].sort((a, b) => {
+          return a.value - b.value;
+        }),
+        name: '鍟嗕笟鍗犳瘮',
+        radius: '80%',
+        roseType: 'radius',
+        type: 'pie',
+      },
+    ],
+
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-source.vue b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-source.vue
new file mode 100644
index 0000000..e0d0aab
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits-source.vue
@@ -0,0 +1,67 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    legend: {
+      bottom: '2%',
+      left: 'center',
+    },
+    series: [
+      {
+        animationDelay() {
+          return Math.random() * 100;
+        },
+        animationEasing: 'exponentialInOut',
+        animationType: 'scale',
+        avoidLabelOverlap: false,
+        color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
+        data: [
+          { name: '鎼滅储寮曟搸', value: 1048 },
+          { name: '鐩存帴璁块棶', value: 735 },
+          { name: '閭欢钀ラ攢', value: 580 },
+          { name: '鑱旂洘骞垮憡', value: 484 },
+        ],
+        emphasis: {
+          label: {
+            fontSize: '12',
+            fontWeight: 'bold',
+            show: true,
+          },
+        },
+        itemStyle: {
+          // borderColor: '#fff',
+          borderRadius: 10,
+          borderWidth: 2,
+        },
+        label: {
+          position: 'center',
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        name: '璁块棶鏉ユ簮',
+        radius: ['40%', '65%'],
+        type: 'pie',
+      },
+    ],
+    tooltip: {
+      trigger: 'item',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/analytics-visits.vue b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits.vue
new file mode 100644
index 0000000..7e1f14e
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/analytics-visits.vue
@@ -0,0 +1,57 @@
+<script lang="ts" setup>
+import { onMounted, ref } from 'vue';
+
+import {
+  EchartsUI,
+  type EchartsUIType,
+  useEcharts,
+} from '@vben/plugins/echarts';
+
+const chartRef = ref<EchartsUIType>();
+const { renderEcharts } = useEcharts(chartRef);
+
+onMounted(() => {
+  renderEcharts({
+    grid: {
+      bottom: 0,
+      containLabel: true,
+      left: '1%',
+      right: '1%',
+      top: '2 %',
+    },
+    series: [
+      {
+        barMaxWidth: 80,
+        // color: '#4f69fd',
+        data: [
+          3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000,
+          3200, 4800,
+        ],
+        type: 'bar',
+      },
+    ],
+    tooltip: {
+      axisPointer: {
+        lineStyle: {
+          // color: '#4f69fd',
+          width: 1,
+        },
+      },
+      trigger: 'axis',
+    },
+    xAxis: {
+      data: Array.from({ length: 12 }).map((_item, index) => `${index + 1}鏈坄),
+      type: 'category',
+    },
+    yAxis: {
+      max: 8000,
+      splitNumber: 4,
+      type: 'value',
+    },
+  });
+});
+</script>
+
+<template>
+  <EchartsUI ref="chartRef" />
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/analytics/index.vue b/eims-ui/playground/src/views/dashboard/analytics/index.vue
new file mode 100644
index 0000000..00b34df
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/analytics/index.vue
@@ -0,0 +1,90 @@
+<script lang="ts" setup>
+import type { AnalysisOverviewItem } from '@vben/common-ui';
+import type { TabOption } from '@vben/types';
+
+import {
+  AnalysisChartCard,
+  AnalysisChartsTabs,
+  AnalysisOverview,
+} from '@vben/common-ui';
+import {
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+} from '@vben/icons';
+
+import AnalyticsTrends from './analytics-trends.vue';
+import AnalyticsVisits from './analytics-visits.vue';
+import AnalyticsVisitsData from './analytics-visits-data.vue';
+import AnalyticsVisitsSales from './analytics-visits-sales.vue';
+import AnalyticsVisitsSource from './analytics-visits-source.vue';
+
+const overviewItems: AnalysisOverviewItem[] = [
+  {
+    icon: SvgCardIcon,
+    title: '鐢ㄦ埛閲�',
+    totalTitle: '鎬荤敤鎴烽噺',
+    totalValue: 120_000,
+    value: 2000,
+  },
+  {
+    icon: SvgCakeIcon,
+    title: '璁块棶閲�',
+    totalTitle: '鎬昏闂噺',
+    totalValue: 500_000,
+    value: 20_000,
+  },
+  {
+    icon: SvgDownloadIcon,
+    title: '涓嬭浇閲�',
+    totalTitle: '鎬讳笅杞介噺',
+    totalValue: 120_000,
+    value: 8000,
+  },
+  {
+    icon: SvgBellIcon,
+    title: '浣跨敤閲�',
+    totalTitle: '鎬讳娇鐢ㄩ噺',
+    totalValue: 50_000,
+    value: 5000,
+  },
+];
+
+const chartTabs: TabOption[] = [
+  {
+    label: '娴侀噺瓒嬪娍',
+    value: 'trends',
+  },
+  {
+    label: '鏈堣闂噺',
+    value: 'visits',
+  },
+];
+</script>
+
+<template>
+  <div class="p-5">
+    <AnalysisOverview :items="overviewItems" />
+    <AnalysisChartsTabs :tabs="chartTabs" class="mt-5">
+      <template #trends>
+        <AnalyticsTrends />
+      </template>
+      <template #visits>
+        <AnalyticsVisits />
+      </template>
+    </AnalysisChartsTabs>
+
+    <div class="mt-5 w-full md:flex">
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏁伴噺">
+        <AnalyticsVisitsData />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mr-4 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSource />
+      </AnalysisChartCard>
+      <AnalysisChartCard class="mt-5 md:mt-0 md:w-1/3" title="璁块棶鏉ユ簮">
+        <AnalyticsVisitsSales />
+      </AnalysisChartCard>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/playground/src/views/dashboard/workspace/index.vue b/eims-ui/playground/src/views/dashboard/workspace/index.vue
new file mode 100644
index 0000000..b95d613
--- /dev/null
+++ b/eims-ui/playground/src/views/dashboard/workspace/index.vue
@@ -0,0 +1,266 @@
+<script lang="ts" setup>
+import type {
+  WorkbenchProjectItem,
+  WorkbenchQuickNavItem,
+  WorkbenchTodoItem,
+  WorkbenchTrendItem,
+} from '@vben/common-ui';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import {
+  AnalysisChartCard,
+  WorkbenchHeader,
+  WorkbenchProject,
+  WorkbenchQuickNav,
+  WorkbenchTodo,
+  WorkbenchTrends,
+} from '@vben/common-ui';
+import { preferences } from '@vben/preferences';
+import { useUserStore } from '@vben/stores';
+import { openWindow } from '@vben/utils';
+
+import AnalyticsVisitsSource from '../analytics/analytics-visits-source.vue';
+
+const userStore = useUserStore();
+
+// 杩欐槸涓�涓ず渚嬫暟鎹紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// url 涔熷彲浠ユ槸鍐呴儴璺敱锛屽湪 navTo 鏂规硶涓瘑鍒鐞嗭紝杩涜鍐呴儴璺宠浆
+// 渚嬪锛歶rl: /dashboard/workspace
+const projectItems: WorkbenchProjectItem[] = [
+  {
+    color: '',
+    content: '涓嶈绛夊緟鏈轰細锛岃�岃鍒涢�犳満浼氥��',
+    date: '2021-04-01',
+    group: '寮�婧愮粍',
+    icon: 'carbon:logo-github',
+    title: 'Github',
+    url: 'https://github.com',
+  },
+  {
+    color: '#3fb27f',
+    content: '鐜板湪鐨勪綘鍐冲畾灏嗘潵鐨勪綘銆�',
+    date: '2021-04-01',
+    group: '绠楁硶缁�',
+    icon: 'ion:logo-vue',
+    title: 'Vue',
+    url: 'https://vuejs.org',
+  },
+  {
+    color: '#e18525',
+    content: '娌℃湁浠�涔堟墠鑳芥瘮鍔姏鏇撮噸瑕併��',
+    date: '2021-04-01',
+    group: '涓婄彮鎽搁奔',
+    icon: 'ion:logo-html5',
+    title: 'Html5',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML',
+  },
+  {
+    color: '#bf0c2c',
+    content: '鐑儏鍜屾鏈涘彲浠ョ獊鐮翠竴鍒囬毦鍏炽��',
+    date: '2021-04-01',
+    group: 'UI',
+    icon: 'ion:logo-angular',
+    title: 'Angular',
+    url: 'https://angular.io',
+  },
+  {
+    color: '#00d8ff',
+    content: '鍋ュ悍鐨勮韩浣撴槸瀹炵幇鐩爣鐨勫熀鐭炽��',
+    date: '2021-04-01',
+    group: '鎶�鏈墰',
+    icon: 'bx:bxl-react',
+    title: 'React',
+    url: 'https://reactjs.org',
+  },
+  {
+    color: '#EBD94E',
+    content: '璺槸璧板嚭鏉ョ殑锛岃�屼笉鏄┖鎯冲嚭鏉ョ殑銆�',
+    date: '2021-04-01',
+    group: '鏋舵瀯缁�',
+    icon: 'ion:logo-javascript',
+    title: 'Js',
+    url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript',
+  },
+];
+
+// 鍚屾牱锛岃繖閲岀殑 url 涔熷彲浠ヤ娇鐢ㄤ互 http 寮�澶寸殑澶栭儴閾炬帴
+const quickNavItems: WorkbenchQuickNavItem[] = [
+  {
+    color: '#1fdaca',
+    icon: 'ion:home-outline',
+    title: '棣栭〉',
+    url: '/',
+  },
+  {
+    color: '#bf0c2c',
+    icon: 'ion:grid-outline',
+    title: '浠〃鐩�',
+    url: '/dashboard',
+  },
+  {
+    color: '#e18525',
+    icon: 'ion:layers-outline',
+    title: '缁勪欢',
+    url: '/demos/features/icons',
+  },
+  {
+    color: '#3fb27f',
+    icon: 'ion:settings-outline',
+    title: '绯荤粺绠$悊',
+    url: '/demos/features/login-expired', // 杩欓噷鐨� URL 鏄ず渚嬶紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+  },
+  {
+    color: '#4daf1bc9',
+    icon: 'ion:key-outline',
+    title: '鏉冮檺绠$悊',
+    url: '/demos/access/page-control',
+  },
+  {
+    color: '#00d8ff',
+    icon: 'ion:bar-chart-outline',
+    title: '鍥捐〃',
+    url: '/analytics',
+  },
+];
+
+const todoItems = ref<WorkbenchTodoItem[]>([
+  {
+    completed: false,
+    content: `瀹℃煡鏈�杩戞彁浜ゅ埌Git浠撳簱鐨勫墠绔唬鐮侊紝纭繚浠g爜璐ㄩ噺鍜岃鑼冦�俙,
+    date: '2024-07-30 11:00:00',
+    title: '瀹℃煡鍓嶇浠g爜鎻愪氦',
+  },
+  {
+    completed: true,
+    content: `妫�鏌ュ苟浼樺寲绯荤粺鎬ц兘锛岄檷浣嶤PU浣跨敤鐜囥�俙,
+    date: '2024-07-30 11:00:00',
+    title: '绯荤粺鎬ц兘浼樺寲',
+  },
+  {
+    completed: false,
+    content: `杩涜绯荤粺瀹夊叏妫�鏌ワ紝纭繚娌℃湁瀹夊叏婕忔礊鎴栨湭鎺堟潈鐨勮闂�� `,
+    date: '2024-07-30 11:00:00',
+    title: '瀹夊叏妫�鏌�',
+  },
+  {
+    completed: false,
+    content: `鏇存柊椤圭洰涓殑鎵�鏈塶pm渚濊禆鍖咃紝纭繚浣跨敤鏈�鏂扮増鏈�俙,
+    date: '2024-07-30 11:00:00',
+    title: '鏇存柊椤圭洰渚濊禆',
+  },
+  {
+    completed: false,
+    content: `淇鐢ㄦ埛鎶ュ憡鐨勯〉闈I鏄剧ず闂锛岀‘淇濆湪涓嶅悓娴忚鍣ㄤ腑鏄剧ず涓�鑷淬�� `,
+    date: '2024-07-30 11:00:00',
+    title: '淇UI鏄剧ず闂',
+  },
+]);
+const trendItems: WorkbenchTrendItem[] = [
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍦� <a>寮�婧愮粍</a> 鍒涘缓浜嗛」鐩� <a>Vue</a>`,
+    date: '鍒氬垰',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏虫敞浜� <a>濞佸粔</a> `,
+    date: '1涓皬鏃跺墠',
+    title: '鑹炬枃',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1澶╁墠',
+    title: '鍏嬮噷鏂�',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓涓�涓猇ite鎻掍欢</a> `,
+    date: '2澶╁墠',
+    title: 'Vben',
+  },
+  {
+    avatar: 'svg:avatar-1',
+    content: `鍥炲浜� <a>鏉板厠</a> 鐨勯棶棰� <a>濡備綍杩涜椤圭洰浼樺寲锛�</a>`,
+    date: '3澶╁墠',
+    title: '鐨壒',
+  },
+  {
+    avatar: 'svg:avatar-2',
+    content: `鍏抽棴浜嗛棶棰� <a>濡備綍杩愯椤圭洰</a> `,
+    date: '1鍛ㄥ墠',
+    title: '鏉板厠',
+  },
+  {
+    avatar: 'svg:avatar-3',
+    content: `鍙戝竷浜� <a>涓汉鍔ㄦ��</a> `,
+    date: '1鍛ㄥ墠',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鎺ㄩ�佷簡浠g爜鍒� <a>Github</a>`,
+    date: '2021-04-01 20:00',
+    title: '濞佸粔',
+  },
+  {
+    avatar: 'svg:avatar-4',
+    content: `鍙戣〃鏂囩珷 <a>濡備綍缂栧啓浣跨敤 Admin Vben</a> `,
+    date: '2021-03-01 20:00',
+    title: 'Vben',
+  },
+];
+
+const router = useRouter();
+
+// 杩欐槸涓�涓ず渚嬫柟娉曪紝瀹為檯椤圭洰涓渶瑕佹牴鎹疄闄呮儏鍐佃繘琛岃皟鏁�
+// This is a sample method, adjust according to the actual project requirements
+function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) {
+  if (nav.url?.startsWith('http')) {
+    openWindow(nav.url);
+    return;
+  }
+  if (nav.url?.startsWith('/')) {
+    router.push(nav.url).catch((error) => {
+      console.error('Navigation failed:', error);
+    });
+  } else {
+    console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`);
+  }
+}
+</script>
+
+<template>
+  <div class="p-5">
+    <WorkbenchHeader
+      :avatar="userStore.userInfo?.avatar || preferences.app.defaultAvatar"
+    >
+      <template #title>
+        鏃╁畨, {{ userStore.userInfo?.realName }}, 寮�濮嬫偍涓�澶╃殑宸ヤ綔鍚э紒
+      </template>
+      <template #description> 浠婃棩鏅达紝20鈩� - 32鈩冿紒 </template>
+    </WorkbenchHeader>
+
+    <div class="mt-5 flex flex-col lg:flex-row">
+      <div class="mr-4 w-full lg:w-3/5">
+        <WorkbenchProject :items="projectItems" title="椤圭洰" @click="navTo" />
+        <WorkbenchTrends :items="trendItems" class="mt-5" title="鏈�鏂板姩鎬�" />
+      </div>
+      <div class="w-full lg:w-2/5">
+        <WorkbenchQuickNav
+          :items="quickNavItems"
+          class="mt-5 lg:mt-0"
+          title="蹇嵎瀵艰埅"
+          @click="navTo"
+        />
+        <WorkbenchTodo :items="todoItems" class="mt-5" title="寰呭姙浜嬮」" />
+        <AnalysisChartCard class="mt-5" title="璁块棶鏉ユ簮">
+          <AnalyticsVisitsSource />
+        </AnalysisChartCard>
+      </div>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/admin-visible.vue b/eims-ui/playground/src/views/demos/access/admin-visible.vue
new file mode 100644
index 0000000..079b930
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/admin-visible.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠椤甸潰浠� Admin 璐﹀彿鍙"
+    status="coming-soon"
+    title="椤甸潰璁块棶娴嬭瘯"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/button-control.vue b/eims-ui/playground/src/views/demos/access/button-control.vue
new file mode 100644
index 0000000..b923e3c
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/button-control.vue
@@ -0,0 +1,155 @@
+<script lang="ts" setup>
+import type { Recordable } from '@vben/types';
+
+import { useRouter } from 'vue-router';
+
+import { AccessControl, useAccess } from '@vben/access';
+import { Page } from '@vben/common-ui';
+import { resetAllStores, useUserStore } from '@vben/stores';
+
+import { Button, Card } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+const accounts: Record<string, Recordable<any>> = {
+  admin: {
+    password: '123456',
+    username: 'admin',
+  },
+  super: {
+    password: '123456',
+    username: 'vben',
+  },
+  user: {
+    password: '123456',
+    username: 'jack',
+  },
+};
+
+const { accessMode, hasAccessByCodes } = useAccess();
+const authStore = useAuthStore();
+const userStore = useUserStore();
+const router = useRouter();
+
+function roleButtonType(role: string) {
+  return userStore.userRoles.includes(role) ? 'primary' : 'default';
+}
+
+async function changeAccount(role: string) {
+  if (userStore.userRoles.includes(role)) {
+    return;
+  }
+
+  const account = accounts[role];
+  resetAllStores();
+  await authStore.authLogin(account, async () => {
+    router.go(0);
+  });
+}
+</script>
+
+<template>
+  <Page
+    :title="`${accessMode === 'frontend' ? '鍓嶇' : '鍚庣'}鎸夐挳璁块棶鏉冮檺婕旂ず`"
+    description="鍒囨崲涓嶅悓鐨勮处鍙凤紝瑙傚療鎸夐挳鍙樺寲銆�"
+  >
+    <Card class="mb-5">
+      <template #title>
+        <span class="font-semibold">褰撳墠瑙掕壊:</span>
+        <span class="text-primary mx-4 text-lg">
+          {{ userStore.userRoles?.[0] }}
+        </span>
+      </template>
+
+      <Button :type="roleButtonType('super')" @click="changeAccount('super')">
+        鍒囨崲涓� Super 璐﹀彿
+      </Button>
+
+      <Button
+        :type="roleButtonType('admin')"
+        class="mx-4"
+        @click="changeAccount('admin')"
+      >
+        鍒囨崲涓� Admin 璐﹀彿
+      </Button>
+      <Button :type="roleButtonType('user')" @click="changeAccount('user')">
+        鍒囨崲涓� User 璐﹀彿
+      </Button>
+    </Card>
+
+    <Card class="mb-5" title="缁勪欢褰㈠紡鎺у埗 - 鏉冮檺鐮�">
+      <AccessControl :codes="['AC_100100']" type="code">
+        <Button class="mr-4"> Super 璐﹀彿鍙 ["AC_100100"] </Button>
+      </AccessControl>
+      <AccessControl :codes="['AC_100030']" type="code">
+        <Button class="mr-4"> Admin 璐﹀彿鍙 ["AC_100030"] </Button>
+      </AccessControl>
+      <AccessControl :codes="['AC_1000001']" type="code">
+        <Button class="mr-4"> User 璐﹀彿鍙 ["AC_1000001"] </Button>
+      </AccessControl>
+      <AccessControl :codes="['AC_100100', 'AC_100030']" type="code">
+        <Button class="mr-4">
+          Super & Admin 璐﹀彿鍙 ["AC_100100","AC_100030"]
+        </Button>
+      </AccessControl>
+    </Card>
+
+    <Card
+      v-if="accessMode === 'frontend'"
+      class="mb-5"
+      title="缁勪欢褰㈠紡鎺у埗 - 瑙掕壊"
+    >
+      <AccessControl :codes="['super']" type="role">
+        <Button class="mr-4"> Super 瑙掕壊鍙 </Button>
+      </AccessControl>
+      <AccessControl :codes="['admin']" type="role">
+        <Button class="mr-4"> Admin 瑙掕壊鍙 </Button>
+      </AccessControl>
+      <AccessControl :codes="['user']" type="role">
+        <Button class="mr-4"> User 瑙掕壊鍙 </Button>
+      </AccessControl>
+      <AccessControl :codes="['super', 'admin']" type="role">
+        <Button class="mr-4"> Super & Admin 瑙掕壊鍙 </Button>
+      </AccessControl>
+    </Card>
+
+    <Card class="mb-5" title="鍑芥暟褰㈠紡鎺у埗">
+      <Button v-if="hasAccessByCodes(['AC_100100'])" class="mr-4">
+        Super 璐﹀彿鍙 ["AC_100100"]
+      </Button>
+      <Button v-if="hasAccessByCodes(['AC_100030'])" class="mr-4">
+        Admin 璐﹀彿鍙 ["AC_100030"]
+      </Button>
+      <Button v-if="hasAccessByCodes(['AC_1000001'])" class="mr-4">
+        User 璐﹀彿鍙 ["AC_1000001"]
+      </Button>
+      <Button v-if="hasAccessByCodes(['AC_100100', 'AC_100030'])" class="mr-4">
+        Super & Admin 璐﹀彿鍙 ["AC_100100","AC_100030"]
+      </Button>
+    </Card>
+
+    <Card class="mb-5" title="鎸囦护鏂瑰紡 - 鏉冮檺鐮�">
+      <Button class="mr-4" v-access:code="['AC_100100']">
+        Super 璐﹀彿鍙 ["AC_100100"]
+      </Button>
+      <Button class="mr-4" v-access:code="['AC_100030']">
+        Admin 璐﹀彿鍙 ["AC_100030"]
+      </Button>
+      <Button class="mr-4" v-access:code="['AC_1000001']">
+        User 璐﹀彿鍙 ["AC_1000001"]
+      </Button>
+      <Button class="mr-4" v-access:code="['AC_100100', 'AC_100030']">
+        Super & Admin 璐﹀彿鍙 ["AC_100100","AC_100030"]
+      </Button>
+    </Card>
+
+    <Card v-if="accessMode === 'frontend'" class="mb-5" title="鎸囦护鏂瑰紡 - 瑙掕壊">
+      <Button class="mr-4" v-access:role="['super']"> Super 瑙掕壊鍙 </Button>
+      <Button class="mr-4" v-access:role="['admin']"> Admin 瑙掕壊鍙 </Button>
+      <Button class="mr-4" v-access:role="['user']"> User 瑙掕壊鍙 </Button>
+      <Button class="mr-4" v-access:role="['super', 'admin']">
+        Super & Admin 瑙掕壊鍙
+      </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/index.vue b/eims-ui/playground/src/views/demos/access/index.vue
new file mode 100644
index 0000000..5f1c9dc
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/index.vue
@@ -0,0 +1,93 @@
+<script lang="ts" setup>
+import type { Recordable } from '@vben/types';
+
+import { useRouter } from 'vue-router';
+
+import { useAccess } from '@vben/access';
+import { Page } from '@vben/common-ui';
+import { resetAllStores, useUserStore } from '@vben/stores';
+
+import { Button, Card } from 'ant-design-vue';
+
+import { useAuthStore } from '#/store';
+
+const accounts: Record<string, Recordable<any>> = {
+  admin: {
+    password: '123456',
+    username: 'admin',
+  },
+  super: {
+    password: '123456',
+    username: 'vben',
+  },
+  user: {
+    password: '123456',
+    username: 'jack',
+  },
+};
+
+const { accessMode, toggleAccessMode } = useAccess();
+const userStore = useUserStore();
+const accessStore = useAuthStore();
+const router = useRouter();
+
+function roleButtonType(role: string) {
+  return userStore.userRoles.includes(role) ? 'primary' : 'default';
+}
+
+async function changeAccount(role: string) {
+  if (userStore.userRoles.includes(role)) {
+    return;
+  }
+
+  const account = accounts[role];
+  resetAllStores();
+  await accessStore.authLogin(account, async () => {
+    router.go(0);
+  });
+}
+
+async function handleToggleAccessMode() {
+  await toggleAccessMode();
+  resetAllStores();
+
+  await accessStore.authLogin(accounts.super, async () => {
+    setTimeout(() => {
+      router.go(0);
+    }, 150);
+  });
+}
+</script>
+
+<template>
+  <Page
+    :title="`${accessMode === 'frontend' ? '鍓嶇' : '鍚庣'}椤甸潰璁块棶鏉冮檺婕旂ず`"
+    description="鍒囨崲涓嶅悓鐨勮处鍙凤紝瑙傚療宸︿晶鑿滃崟鍙樺寲銆�"
+  >
+    <Card class="mb-5" title="鏉冮檺妯″紡">
+      <span class="font-semibold">褰撳墠鏉冮檺妯″紡:</span>
+      <span class="text-primary mx-4">{{
+        accessMode === 'frontend' ? '鍓嶇鏉冮檺鎺у埗' : '鍚庣鏉冮檺鎺у埗'
+      }}</span>
+      <Button type="primary" @click="handleToggleAccessMode">
+        鍒囨崲涓簕{ accessMode === 'frontend' ? '鍚庣' : '鍓嶇' }}鏉冮檺妯″紡
+      </Button>
+    </Card>
+    <Card title="璐﹀彿鍒囨崲">
+      <Button :type="roleButtonType('super')" @click="changeAccount('super')">
+        鍒囨崲涓� Super 璐﹀彿
+      </Button>
+
+      <Button
+        :type="roleButtonType('admin')"
+        class="mx-4"
+        @click="changeAccount('admin')"
+      >
+        鍒囨崲涓� Admin 璐﹀彿
+      </Button>
+      <Button :type="roleButtonType('user')" @click="changeAccount('user')">
+        鍒囨崲涓� User 璐﹀彿
+      </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/menu-visible-403.vue b/eims-ui/playground/src/views/demos/access/menu-visible-403.vue
new file mode 100644
index 0000000..7e3cde8
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/menu-visible-403.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠椤甸潰鐢ㄦ埛涓嶅彲瑙侊紝浼氳閲嶅畾鍚戝埌403椤甸潰"
+    status="coming-soon"
+    title="椤甸潰璁块棶娴嬭瘯"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/super-visible.vue b/eims-ui/playground/src/views/demos/access/super-visible.vue
new file mode 100644
index 0000000..877fcd1
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/super-visible.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠椤甸潰浠� Super 璐﹀彿鍙"
+    status="coming-soon"
+    title="椤甸潰璁块棶娴嬭瘯"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/access/user-visible.vue b/eims-ui/playground/src/views/demos/access/user-visible.vue
new file mode 100644
index 0000000..a3c5f00
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/access/user-visible.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠椤甸潰浠� User 璐﹀彿鍙"
+    status="coming-soon"
+    title="椤甸潰璁块棶娴嬭瘯"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/active-icon/index.vue b/eims-ui/playground/src/views/demos/active-icon/index.vue
new file mode 100644
index 0000000..af9f69a
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/active-icon/index.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="鐢ㄤ簬鑿滃崟婵�娲绘樉绀轰笉鍚岀殑鍥炬爣"
+    status="coming-soon"
+    title="婵�娲诲浘鏍囩ず渚�"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/badge/index.vue b/eims-ui/playground/src/views/demos/badge/index.vue
new file mode 100644
index 0000000..92d70c7
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/badge/index.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback description="鐢ㄤ簬寰芥爣绀轰緥" status="coming-soon" title="寰芥爣绀轰緥" />
+</template>
diff --git a/eims-ui/playground/src/views/demos/breadcrumb/lateral-detail.vue b/eims-ui/playground/src/views/demos/breadcrumb/lateral-detail.vue
new file mode 100644
index 0000000..8a4de64
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/breadcrumb/lateral-detail.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useRouter } from 'vue-router';
+
+import { Fallback } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+const router = useRouter();
+</script>
+
+<template>
+  <Fallback
+    description="闈㈠寘灞戝鑸�-骞崇骇妯″紡-璇︽儏椤�"
+    status="coming-soon"
+    title="娉ㄦ剰瑙傚療闈㈠寘灞戝鑸彉鍖�"
+  >
+    <template #action>
+      <Button @click="router.go(-1)">杩斿洖</Button>
+    </template>
+  </Fallback>
+</template>
diff --git a/eims-ui/playground/src/views/demos/breadcrumb/lateral.vue b/eims-ui/playground/src/views/demos/breadcrumb/lateral.vue
new file mode 100644
index 0000000..2c24abf
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/breadcrumb/lateral.vue
@@ -0,0 +1,25 @@
+<script lang="ts" setup>
+import { useRouter } from 'vue-router';
+
+import { Fallback } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+const router = useRouter();
+
+function details() {
+  router.push({ name: 'BreadcrumbLateralDetailDemo' });
+}
+</script>
+
+<template>
+  <Fallback
+    description="鐐瑰嚮鏌ョ湅璇︽儏锛屽苟瑙傚療闈㈠寘灞戝鑸彉鍖�"
+    status="coming-soon"
+    title="闈㈠寘灞戝鑸�-骞崇骇妯″紡"
+  >
+    <template #action>
+      <Button type="primary" @click="details">鐐瑰嚮鏌ョ湅璇︽儏</Button>
+    </template>
+  </Fallback>
+</template>
diff --git a/eims-ui/playground/src/views/demos/breadcrumb/level-detail.vue b/eims-ui/playground/src/views/demos/breadcrumb/level-detail.vue
new file mode 100644
index 0000000..7aa18d4
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/breadcrumb/level-detail.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="闈㈠寘灞戝鑸�-灞傜骇妯″紡-璇︽儏椤�"
+    status="coming-soon"
+    title="娉ㄦ剰瑙傚療闈㈠寘灞戝鑸彉鍖�"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/clipboard/index.vue b/eims-ui/playground/src/views/demos/features/clipboard/index.vue
new file mode 100644
index 0000000..792315f
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/clipboard/index.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { useClipboard } from '@vueuse/core';
+import { Button, Card, Input } from 'ant-design-vue';
+
+const source = ref('Hello');
+const { copy, text } = useClipboard({ legacy: true, source });
+</script>
+
+<template>
+  <Page title="鍓垏鏉跨ず渚�">
+    <Card title="鍩烘湰浣跨敤">
+      <p class="mb-3">
+        Current copied: <code>{{ text || 'none' }}</code>
+      </p>
+      <div class="flex">
+        <Input v-model:value="source" class="mr-3 flex w-[200px]" />
+        <Button type="primary" @click="copy(source)"> Copy </Button>
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/file-download/base64.ts b/eims-ui/playground/src/views/demos/features/file-download/base64.ts
new file mode 100644
index 0000000..ee6ac2b
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/file-download/base64.ts
@@ -0,0 +1 @@
+export default `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAAsSAAALEgHS3X78AAAAAXNSR0IArs4c6QAAIABJREFUeF7tvQmYZFd1H37eVnv1Nj2rZjQaSSONNJJBCyDABiTAQAxxTGLH4W8HCJgQ5/+3wRAwccDg8NlOjM1nxzGOiQGDHf4QiDFgvLCK3SAZtC8zo5596Z7ea3/Lzfc7956q20/V3dUzPa2e7nqfRtX16r377rv3nHPP8jvnOtQ/+iOwiUfA2cTv3n/1/ghQnwH6RLCpR6DPAJt6+vsv32eAPg1s6hHoM8Cmnv7+y/cZoE8Dm3oE+gywqae///J9BujTwKYegT4DbOrp7798nwH6NLCpR6DPAJt6+vsv32eAPg1s6hHoM8Cmnv7+y/cZoE8Dm3oE+gywqae///J9BujTwKYegT4DbOrp7798nwH6NLCpR6DPAJt6+vsv32eAPg1s6hHoM8Cmnv7+y/cZoE8Dm3oE+gywqae///J9BujTwKYegT4DPEXT/9WxsRzVav7+wT3ZphsVG6EqF0Ma9FrxkBMGo+5h5wp0LYmpGDXVDr/hbcf3KBefyxScI40bWt/yivUH9u7dO/0UvcKGeGyfAVZxGo99dvpN3hPZX1ORMxrFCbmJoiRR5LoOJQlRHCl+mh84FOKPUJGjiOJYkeMQuZ6eDvyNA9dHnkMe7nP4P1JKX6fQrudQcThDuZJPczvqn6/9yMxrbti9e3IVX2nDN9VngIuc4m+fOJHf9/nRx2uz8e6ompDnOVRvxZTxXGrGCSml+DPne0zACROxItdxKGFqdqkZRhS4DhV8n+bDiLKeS1GS8DUtIsoQUStRfD9+a8UJt4+jkPEIbDWyK0/5YZecrUnt9J7pW665ZuvjF/lqm+L2PgNcxDQf/+LkW/2HS78zf77JhNoKI3LIoRDi3hyuQ5SAzoXgIeGJyMOqoAU7xWAE0tcoUuRaBfvwm+c4bYKvRzGvEDnP4/uiRP8+XPKpNJqj8k6P3JJDEwPVD13xjNLrLuL1NsWtfQa4wGk+/Sdzn29Nuj/RrCU02wopA0kea8IfyPg014rahNqMYyZ2+8DAO4Yp8Hfe96gWxe1LioFHjShpMwerRlg9zBWlwKdqGPH3wHWZcXBudE+BijtdcosOnWnWv733ZYXnXuArborb+gxwAdN8/EOzn61M+q9oVBLyw5hYKpt2sr7H6kylpYlTDhCprAz2arDY4wuBR7VwIUNUw5ilfdbHGuEwA4DoE1Lch8FMQNmcS+WtOWYCxyc6l2t87co7C3dewGtuilv6DLDCaT7+halfqzyUfW+9klBUh+LTOSC165HW+1MCn3zoQrABlOLVAN+hvuQ8lxowaH2XEkPwWA1wfzOKn9QO2gATiNqE77AvcC0+YSOUtmRpZG9Abp7IyTo0v7P+O1sOFN62wlfdFJf3GWAF03zo5OTu5NP5Y83J2K03FhK/EDSag4EKQ9U+8LvvONRInV/u8SBoqFbyKddjFcEBVsNqwAa1MZJLWZ+GjVHsb9Huo7G9M0+//urh+5Z73mb7vc8AK5jxQx+oRY0zkVdrhKzmhJZin5bKaLbpuJRVCbmBx9Ld1uGFSXpRh6SLLceljNKMlX6+tANVi1eBkkdbry6QkyHyhvQ0f4u+Ftx5553RCl55w1/aZ4Aep/jo1+Y+OvlV5+fhiIewVa3QeHe0l6fbgdOLDTAEuBHaS/YAbKMVoicfCWFV0edlBYDtgP7kfW0LDO3xySsjyEDUClqnSj+a3d3jK2+Ky/oM0MM0/2BsbCj/2W1T1anEgd4/mA1othkukOjpZlinjxaqQT08alUuwSoARvA9h1WhwhaXvBE91bM7qr+39YbSW1blQRugkT4D9DCJUH3mz8VeWGstSvRpiS7qj918zfWokHQ8OytdNeT6pVYWXAMjGl6hoWxAuaJHQztzlB1x2DWaNBQd2j9x7c37tx/p4dU3/CV9Blhmio99ff6D579Mr/fDiP3yKz0ixyEfnh9ySDlEUGkChW/ap49P2AhhmCxQdcBAOKDz29finM0A3RhN+gjDG27SoR15Km/3yCsRORnAMlSSe5HrrfRdNuL1fQZYYlYfe+z0aPLXg+O12cSJmxEpK8Kbvk0IfTGprn01mhESR/+twQ2KGSRGUMxcExiGQXjLPkLDFGCg5Q6GTChFjuvSSM5jJgBUQrxCzdHw7vLNmRcs185G/73PAEvM8OMfqIXzZ2M/7e/vdgsYAECInCHO0IGk1wSM/wsDcATYc0kBJ2R+g6wHA+B+eI0g1XEv2vBxp+EDPAOknwGWyDAHvkeO/oZ77cMxOIxsLkNDeYe27C2QXyJWhWAUn9sx+y/23DD06Y1O5Eu9X58BFhmdk9+ffe+5z7u/BtRl3GTsZtdDiBskCB0f0hxqi6gpIFrPSHh8alp2GDRXSxzKK20TtFUZxArIpZzSQTCcB8G3EAHmdp028YNpwBxYTZixLKgE2oSrNFbEkeOs61JxJEsjuwJyi0RuQccH7i/fm7n99tsXf8ENzh19Bugywd89dGhg4DO7ZrtFe21fvH2rnF/s94YDou5I6IbjMZHj0GoREe4FQQtTwF4AAxRUzCuELCewJcBo9oE20ioTYg2INAOXhANGsWCFQPxYCZoUTpbvzIxucDpf9PX6DNBlaA79Sa1eG09yjbnmAoPTvhT6uOjiaclfdz3KJzrwpSW4JnwhepHiQvg2MWupriW6MAeelTHMgvO4L5PxqBomC5gKLIFnCANJf3l1cIjKmYCKgxka3BZQZlh7hfCg2R3V3916Q+mtm5EJ+gyQmvUz9838u3Of9f+Ik1EM1gdqjAtIMymyjV0Qm0cJxUZlSTMIVBPXEDMGWuwCECqIWNqCqs4qE4xffhb0f5elPNqQQ5gObYFRbI8S5xmYVWCpSUUMozQU0MjuLLkFIifQeKGxXWe2Xn/9rvObjQn6DJCa8UffX02qMzrghQNECkKDMQodXg4QoK3b4xqcA5PIeRC5/C3EjGtE4oudwBIekdqE2tdjdVFsGOtzOFoOkmr039pJqhml6Kj2vTaTsloEncp0m43vRNFIzqeRKwoLvEKxE9fyL/CLfQbYbCNgve/jf1abrB1PRqJmTLHRm0W3lk9IcfbdmxVB1Bh8F9cmiBAS2bYLArMaSDwATAC6BAELI8g5gT500+txLbw+YAowJ75DxZKVA9/BHLLKdINRuIFP20qe9gqViZycw9Dp+kDjy4O35V+0mUigvwKY2T724NQrqn+T/Wx1JmTgGohX/PMsjVO4HvmOz6rrMxHiH7sujcSWwYWNAIIVF6e4K+vGEJa22EYIXKpFWre3Vxx0UyLJIPzQqF14hhjYtoqFtks+tSHWer0w2CQHSTsBlW2vEOwBIjpzxfQr9l438vnNwgR9BjAz/dgf1OLKZOwu5vMHQ8CgLScRVVyfDWAhaNHN8V3+1r78xKgqHf0fRApCRzuLHTYATlQtXMueIGg0lhdImCJtUOM7XKdgJDAImBPvIJ4oPxdQSRFt2V2g4mgHK4TnfOuqo/k79+1rbAYm6DMAER3+q8q9cz9Qt0Jw1xpR2/gUvzoIvpQgTNWRoiJNZaWwI7uQs/Ld912KTarjkwbbAhChHUh2eI9gzCLnHfq6xAKg4kiwy3a1iiq2QMITEVYAKFcIqOFOfM9QssB96gUeDfguje4uUGGHy7nEOBpu8/TA83NclmWjH5ueAY4cOX3l7MfKx5I4oWpL43EkggvJyfq+CTQJpiftDQKRQLJDcqcjwQJvwCerKMZI1l4ejfORFQUEjvsh1XMGdgGmAAGLWoX7uD9mJRA7AZ4jGM1Qm2wGEU+TjS2SezzfozJyB0QVKlCbCSo7G388ciD/7/oMsMFH4PE/rMbzE4nbrEOr1m5I0b1BNOL9EbXE9vaIjYBz2vB1FkSBObBlSqGIdIcBiwPXZlXMahWugfqE69EWVJycWQmartvGCGF1qLk+B9AiE/YCw4q6ZUeDGV5hBcckFiHGsfQ3mw8orxRt2Z6ngd0euTkNmMNx4sqJ6665ZtuhjUwCm3oFOPH1yv+a+jr9qyjs+PyhKkDXBmwZ0Vk7SCUuUTFiRbriHhCipMbjfhCcECCkNohdAmOs4rDPX7cPYgURgyghybECaebR/kswJVYErAxQxdASVpM2wI5/R391vEIwRGBppMwL0+pn6Wc0XI+fg+9FwKaVou1XFylbdshDGiUzUNLM3+nl+gywAUfgofHxkvPR4nx9PqGw3mL92wav4ZWhmoixKlgdrfNraQ1pXjRGMUgGf4sur92UOiUSBAmiw3cYxmAQSHMQrBirxSSmqusx44CIhaGwGqAtGM4Ch8AKAOLW6hFWD+21EqNcsEMMmjPBNfQf7ITnwDgW4xr3BPkMFRJFxQGfRq/Mkb/VlKGDy3UovKdwS+YZG5AE+JU27Qrw+IcbM5Vj4WAjUuS2OtldQkgy4SAcDUVImHjxO75DEuPAd/wDceEcmEaMT0hc8cTgHhAyfgOha9tAEzcIGvcB89Mil41VfDKjqJhqZoXh3ABFBLUomyBQpp8v/RJPDz6bjtdmCPRDq1teO3aAfuC8vIufR/05oquuyFNhq9vOI8a5c7tnXrBn//DdG5EJNiUDHHtg4uUzf5X/3EwtIT+OmKggcUHEQuDi1xeDkqEGBqcjKgvsAzEuNbFrRhH8D4gLBAwpjFgBDhAiVhoY2LgfvqU20A11Q41KBJicXkG0dO8QdcyrgVZljGvUTq4xapPAJNCGqGPoCxhNQHiMG0piAnYJzIuVoFj2aM+eHPnbOqShlEqyd23MBJpNyQAPv6+qRPURghe3JohE1BJ84jsbuyY5XevqxIQLFQSH+PsFj4Pz8OagTYnUaomsiRm6e+zgPs104l4Fw4A4OVpsoURt75OsJLAfcGiIhf6sc4U4BOK0d0lDsWFDaIMYh2SY4W+NcdLJOFCX8B65gSzt3paj/KDLtoBj8sYmt8++beeNQ7+z0VaBTccAY39Zu3f2weTWsBlTPezAk0Uai1ojBCwTro1WnZAiDADmAENILIAJzniDQIqQrkL4uA7SGMSp/UCaOXA99HkcsgrpxBeTSpkyxDFhsClw2DEAAdelCVSYS5Cr3HcTrba9REIIhZxP2wYC2rI7w2A5iQ0w89wpmOyNwwabigHGxqavmv94MBY2FbXq0Ps1UcOLAwKBFAVxgKAFQyN+dfwOHz6IBlJ03hjIop4ITA4qBgYV14MoRb3Bd7ElwBxoR6K3tvEqgS8mcMNM8jc+bWxSmgzBtLA5RLeXPomLVRhOVhhWjcz1wnRQhYYGMrRnf5GA4kYesRxHbji//+C12w5vHPLfZEbwY79bU5W5mKJGSKjvIB4dSSmEx0fOCaAMRJs2cnEdGEAIXeAPwgwCcBOPi/wu3hlGjSotieUQSd1ecSxdXq4CAWPVge4uf+M3GMk4oD6dDzJUsorswp0L9ykOqFwgevkuDCLPBKNkSFFuIEO7t2rvJ1QhOZrX1T88fEvx3/QZ4DIcgeNfqX7myBejnyy5iiqxJgZIdyEG8aBAUotLFOoKAk+ip8PNCWNWCEc8KWgLnh2bIdAeJLG0j7aE0cT7IwxgS3r0ib1AJmDWKburVSRZBdLEm2YgIXxp22YiELqsduLexXe8A94xk8+wNwjxEWzm4eccCrIOTZSb39r7T/I/ehlO/6Jd3hQq0NjY2NDkX2+fmj0ZOgOeokqk1QsYjJCakKgsIUl7cEA8ogZBP8d5DnYZDw2CS7hO9HS4I+FJsiW6MJQ98mIfgHjxfKwIsCmwQkjFCFyDSRH9HJ/4LmoT2hPitdsWJhX9XuII3Jbpn6hC3fombWGFyeUC2j6UYeIPkKhgjvkrwm9d9RN9BrjsBMBDf9poVk5EmUojpjhRVHA04dm6sa0Lw3iFLi/wAZG6IA4BmUkgCQQmrlBchzbRNmwLIVROqDHeFq2fL5Q7jOe3vEpaXdE2g32I/x/nbImPZ8GkRmwA9+B7NokX5Bq0odDG2JaVRewPtAmmAZMXcz7lSy7lM64KEtfxco6KG8qh0eandv/8wE9fdgSwRIc3/Apw8rtzv3n6m+474tmEqqE2es8dn6Dde7a0JbiA2xhQZgxXcRfCXy+HTZQiYUWSw/jkDDATYBJJbJctESITxmAj2HPIibULUgieYwpuB9bAdYKQxA6Yg+tQYIqRiisU5+XA77xSmRUJq5Ncj2twKZgX9onEPdr9ifW+Y8NZlxkA1awDMJdPqt5KnPJt9X++567R/9NngMtkBD75yU96Nx37iehcgyiuRmxAQoLjGPKJZowqpL3m+hDJmtap0xLZ/h0RXLTLfn8DXViYzavbFn3c7oeca0MfuoTnax4iv5opMuYzH2tbBf3gf1YivbyL9AfqmYD8qr5HhShuu2vlWi7M1Ywol3FpIOsxA0QtRb4BxmEnnFt+HVV2N9ax4V7Inp4ffKTZSMZa2enmwoJRkJxJK6ZhT0MBPAvi0G16BeJgM4nAD0SqdhtISFkQ1sJVBIEnLc3FZrA9NdJezfOYmdBuNtZGa8X3Fnh4lnq2zQS9TnLYiinIeDToKi7XCOIPAofqVR6/5Lb3lDdcOcVex+ayY/tjh6ZeMfGJzGenYyKnburvGGNQXnri1CRtu2LLgmisrRPbLy36t0h+fIetIBAIXCuANjAYIrC2p6buuQSpnT7ASGgLDAHpXLRcmKL2SDtgCL2UOOTGnQoVom7hOrQBFQjPkhXAVpE4zuABz+SQnyBYl/DK4mM/sjChIOuxCmQf7HJ9/cyWg3v2TF12hLBMhzcsA3z/96tqquKQN6+LnnGAy9Ww4rb3BqpQxqVqU0Of00EmqCoSsGq4OkcYh62HQ4WRUoaiS9tlEW0Vwy6RItJbGAvPlxKILG6NoczV5FyHHKP3g5Gg04NE2ZNl1Bv0jPvnaJgGG928O2VHrWu5LmXw/ia7jO8PE0IJxQT6f8ZjaAS2Kx7IuFSPFOV9h6ZzNPmid5Q3ZPGsDckAhz5Ve2T6wfjAXNMkqSeKImM8gniFAcAUzckKjQ7l2lh9Idi0OzEtSNr4f7Mk2PkAuFYHuzS2n5PYLeOViR97hLVLGepGoN83PE2kuAffQawhKBmqkKtxPXAzcbkU3i+s86wQqw5KISKdUu/DzZtl5Mx39lgZJGk9Id5cA03HlSZlcj6rP1E5IK8WUVzw+VN5Do28cb54+65dtY0m/fE+G44Bjj4y+ZyzX8p9a/5szDm17JkxLkioEJy1xVBi7NelCDbe/OQ8jY6W2oAxnuiUFZwmYFuyo/201Bc3qUhdkfjyHc2n1SJpA8Tp+FIYC/aCZgD7XhA380XgUi6GVDdeIhiz7AbVTMQrhQHdNZGFBuyRWQlwP54VRwkhd7kQ6JVGBS7FOY+cSkSjdyXvu+3FQ/9hIxL/hmSAez7UTKZPx45T0apP2n0ICRtE2IV9ocen6DtUjdLx1Q7RiVSXdEkBxUn7kKwamaldkHKI/10YiFUdFLxiCLb23sghZdNxPyRvnWA3xHorJZcYtlyI4zbj2Ek8EgtA2yDiOWzXil3qXZeGwkg/z7xzE7tUgqEUUSPRK0Yrq+HarktUQpwkcKnSVOpf/EZxoUGwwThhQ60AR79a/csj9zn/LBmPqIZsrXjhbixCrB2CI8LOpI2sT8npaRreWm5P72LGsD3/QtzdPiGtYWwOhE8ufzIbEw0af4owBuAZYCov2zGEu3l97JUH71P1PLYJ8K74G5/SJmwe2C65MKZG4NNAFOnIs+tSDWXozOHkfSrlHKo0FgqAm99Q3339ntFTG4zmF7zOhmGAQ4cmByb/Njc7M+eQW9ETjWwvSDcPRqSF6U/7+udAHGFEE2emaNvOkQUDlCZuW7JD6opxDQAa2gXBYbeXIgtUbQeI+gMVrO1NQgkW45Nntd5smhdzIKtTDhF34zl4l7zfcZ/KO2BFgiqVM1IfXiTYIxVPl2qHKgYGkQAZGJOwl7GBgoP4eaUEY/gO5WO9j/GWW5K/uPOV5Z/byMS/oVSgH3yk2To/EQfOVEgAOmPdBtFD0MEIhAqAJb9gDELG9puitCAQEHIlVLQ969AMOVTocT9fSFkQI4i2AXeiCUihTQSwclHClZlFf0d/wJTCOLhX3KPSFkdoQaji2QHSM07YQIanCNcJY0LNYU+VQ2w0Q/fHMRP47b+5kC4YIU7IixKqWd5YMMAcBshs5O14DrmNMHr1u0rBRif+DcMAx783//5j33XfVD8PyaYTwSFpxRMyoBJWD6A/wxsE/zekHOYc31l2G+nsnJujgZECzz0IDteKezP9KZ4ikbRSFlGSZ/j3WNsbTejmcDX65vlm9RBQnniBQNya8DWhA2KBQyLApThm5tC5wWxQkGe8XHg/BNAQOMNqEylAGbSBDgZQTehZihK0m9Nw7lYeFe90sG7QbOB3x7+a33XjVVvP9BngMhiBRx+dKFe+OTB7/lzswOcPosUBPRfqAPv+TVAIXg82LsEMrYiqGZ+KrYgCp+Pbn04ccqbmaWBrmSO2bUlr/PCiX9uf7UJUXKwKKkfSZjAQGTw2eIYEpmw3rHimjJ1LsFpwDgSPA+qNqDGIYeA7DrwTmFeAdZy4g+1RYx19xt9cjzRJGP3qZD1SdW2PNKD2gCmyLlWyHmGx472PieiGfdVPvPRnhn72Mpj6VeniZW8DPPyx5uyJk/GAOxsy4XC2kwS1gMc30VWpwYOVAeoJIqbQ20FAYBJgbUAss4FPST2iARUTSgd2M3BB5C0A2LxOES3bfJxNiJBHwsSPqG3OIxc+dbPKQOXBefSF8f9JZ8VCHyDFIek1qlTbDSDqQXhzXM3A+A1qGtQuEDO+g3kEq8DlUJhE4OxPSEHvB0PlAlYPw6xDsH1wLuMTwVZH2ODNbw82HNxhKU65rBng5P3Trzl5d+bDMHydKKH5yGGXHyYVhIxDvCMgMkhHHGxUIhCFoFCccFwABwgCf0O6Tk/M08jWcttoZW9KAoLT3h0QI8B00OfzxlGIZ+Leth7uezRkQRugl4sqg/vtKnR4/ryvSyJCXZMDqxgmCR4hvBvagMqF5+Cc/Y5PmmgsefB9ctaYQ0ErpjDjEXY+cLYENBcBKsq6Ei9Tr3j15PZrd+wYXxXRepk0ctkygFLK+94H6tH0NFGrBtef1vl1BQX9CakJKY9VgItTYVJMDc0E+/IG+h6OJ5kVAKoDVJ+oEVOu0aJ8KcOEWbYImenKJZqJdWAp42lvkBA+CFPwOFBZQPTtAlWua1YcMJ4GuLFkN2oLJD5WCOj3sAPwCQMb74N+QsWT1QbnwLAMnDOeHLCEGMyIlMHb08h55KMIABim4LJwALzfySIa7FCzoei5B2ofe8E/G/jXlwndrlo3L1sGeOwT9ePHj6s9yZTWa0GkIDK76gGIGgQE9UbryJpQocKAYEBoYBKoI6wKYEdIAy1gXqlHtMVFDR/t6RFbIYR71XM4uQbPA6SArwcRGqGLZ0FVAVPARoBk72yu0dkbWJ6NvgjsGUzDwTADrRbUaLdMMDxXmJ1dvVykV98LQxkesQhwjEiRk3GpWfCpmnepEnSUNoeS6D2/mN0UXp8051yWDHDk4fMvmvhy/otQfWDhgXCYAE3hKpaWxssCFYd3YDThfyEsEIquhIBCtEBELgx44rxTj8ip1GloKM+QAVF18Cy7bj+iqWAOqOOMrQHa0rhExeMoeH5xeWpDtbNPmADxoO+DEUMTMWbYhokvyGSxbQDCt2aTmQ9eJgOcg7HPJRCB/2klTPwKhF8KaNpLqOUTZSLiz3/74pPD+/btm1k1sXoZNXRZMsC9H2kl589EjpoT1UHjX0QaSkoivrMENsQPNUkIEoSF81g/QEiCF8I9cAuWjKGKVcCdrVJ+pMi4IakNBGM0aiXMFGCOgqfrBYn+DgaA+tWGHiPVMIppPvAZ3iAqj+B02OljPFa4J218g5DRvpQ90dWftaFt1xkSVQjvgcBuBDXINFYZytJ0WRN9M4D7lOhZN4Z//NPP3vhl0BfjycuOAY59sfq3hx9yXhLNJtQIO0Wi8II2EcuLwSUpXhYQJQgIyej2kcK9tX8CYXG1t3pEhYypx2nUrQFjEyxsSXtsGHINkJ0PYu+4LnVmVgeBaN8r6o0Q/lJCVK6Rd9FlFLWahnfjFQP/4H8Fk+Rdms8FdG5YR5Jjl6iBZBcKG+97dT5/GQnsVe/qZcUAjz4xcf3MFwqPzsxq1QcGJFQO6OCyaVx6hEAkw2HEbk85oNMPR6iJiWpt2nXILsRGxNatEyBhBInpRrevRxTOVWnbSLFtgGLgxOsjXiRcDf1dDHId5dXBqaUOrBR4FwHYyXexK5jQmxEjRLFKYIWyGQalzdnFySUZtc0SZR2K52NSLlF1UEv+WbM7vCwvb3re/PC+fcObUvWR+bisGOAfP9KKpyYjt14lVj9kZ0R5GanCJswgLyeenjSsUbVicjId4hQCRHuiGknbWAXyzZAyxYCqMRGSA4VosRrgb6g4ksoIAxzMgD6IqgKXrDCDGMUgboZtwDdvvFEgcsA2oHLZqpD8jWulr2CGLMMhdBsgflwX+Q5F9ZhqQ1maKxKd2uIy1geHmxC9sDDxe696xfa3rLpIvcwavGwY4MQ3K//z8Xvc11VmFQdtbGIF4RSM5LNlrbhF2eCFhEf2U2BlhzDeB0uAGQZ8NwY15hHBLhAhE6PnsCo07BNjaXA+9LXBCg+UztLSWxexSuVoYJx9LKbeYLWBaiIeJHGZulFCia+ZyJ4ovIsk3MCzJCodG71IlYwVNT2icCDLfT+zw6HZosuqT+SBOZLWJ1/uZy8zWr0k3b0sGEAplf2HD9Qb5yeJGphRcwihiKrQ7WUgGaF3Q51hAhSLUGgejAFPEVyPogoJ4YFh4OM3nhXk4YbT8xSUi7wCQKC24cy+rr0vwTJBYIJBqh423+jgecTmkFWGVwG4ao3El4iujfeHpNcb3mnm57gDkKCpGkNhxiHVSKhbDAF1AAAgAElEQVRSDLhvp7c5NFV2mfBh/OL47886X962bVvlklDUZdboZcEA932sWZkYj4vNmmYA23hMS1V7ZWDd2WBqNOVoBByrC5DYBniGOROia6tLlsHKg8T5tsDeEGXPzlEwVKA4oze6kNImUqcHl9s++6Z4mvCD6YP0m41sa3NrXGIb5ZDwUOlkZbO9PDhnMwCInHMEmgklA1maGiB6/AqPIpgOANd5RC8v1f7iF55X2vAw5175cN0zwLEHpn/+8JezHw2r1E7YaBOIEFMzZrCXED/0YDYMgX6E9EbEF/j3QKsToDhgY1gdMkTEtUJZsurVIm0DyIACUpCrhTRi6goJnl6Y0jae25NgcantucHzxK2JSyRQZu8bIOqPbeRK6iTek3kKaFDDRQh41YeyVCWHTl/h0KHtnSnOUlT//IszGuraP3gE1j0DwOc/cSpy7GwlEHrZZEC15xG5rAabL4YhfmslijJd3J8gPI2l72xizSqM5SKFdMUOijiEsGFvoLJ05twMbR0pMjQBun6bKY0dYUtx25BND7q9gslqIDBrMWrRB+kL3g3XQf3B39w3UH/BpWZTUbPoMyPNDhJ97xqPZrOdFeXD+05tyNImF8PL65oBDn26+vCxY84NM9OKbVPJUYHE4/LlRoUR6dsOCIUJxYHW6XGIP5+lpRXFlZeX64xJbHBDqOjQWQmwIghR4xOAsp1hRNPA1FieJLPAtCWLrEoevDKRxinJ80Sflwm025eVSfou7k1u3wf4T791C3sNwBipJ1QtB1yNem6U6KHdLk1Ysv7HSvUP/e6txdddDLFsxHvXLQOMHZq849gX8t9pVDTYbQFUwaAcRR/ubBdEnHTS8DXxw+BlH7/BxQAewUaxqZUPSQlJinZ4ReDisB0CBdELtoidi0Zc6y31iFWhfNbVcGVjbMv9jBMyK5Kt3gheCefEdSmEJckvAnGAHVELXPKihXYPfkeMC94ep+hRraUoynpUAdCurGhsp0ePjUJAAJaBKHkS/vAOT++C1z8WjMC6ZQCGO5yOnGaoKMa/lLdDVAdblWGJaurxgPCF8EBoIHT8DrVBSoXYpUyE6ERCC96GrzUqEKcjmn7A7Qp7YFcrpPFM0HZFgvCRg4xniqtS7xRpUKoGmgy1Bjq8eHYkm0zeE6ucrHC2miepi1HGoSRU5KB0YUQ0kwuoNaBoruDQt692qZnTxXUTl+hTO6f27N+95WSf9p88AuuSAY5+pfrpI/c7r5ybVjpbKeUpEWKxX4fVEiPRRZURvdn2lIDQ7ToNQshsD1h7gImOLa5G3Cc6uu2F2u4mNJFgcztN4OLREVelQBP0pni6j/bzbVshra6xuoMGDTfHgXZx+lCnfP03AHBTeZ/CnE+T24ge2eXS+KBOCsK/W4Yb3/3Itfln94m/+wisOwZ44Ilz26f/ZuBsbUa1vT52ppP9NyQoozmt3RZFrbHVChAhpLWtY4OuxLhcjjgWu26m0qJdRY0itn366KPe7d3hAJ2sVugDGAmqjXhwFnt2C1h/uF2h6+ddUk1kdSlyix7/7WRdSqoxzQZEjWKOpf/YDo/u37NwSu97xsbb2G65+VrJ7+uOAf7xI63o/LnIi1rEui0O8eoIBkagAyAiNoaNdIa0FhcorhXhKWoGVoL0CrDcYAnxpyU1PzNJaMB1KJ9xqNbUhA7iZx3dbE0KBpVVRj7xTMEfdXs+l0I0BWqDCJUtNJZfoaQEHpIFzCGhCoi/kKOGj82sHbpvl0PNvJb+UNfe2zh55yt+bM/X5BlfHRvLBc1msMMfagPgksBpb4MXNp2B5cbD/t0P3IbjxvAH8OGGqh1cOxvN1HHuRw8cmF9Jm2t97bpigGPfnn//2Pe9N8HrYyVgtY1FkaTotLgvRW0QwkPQSNyHIDJRS9IDC109zzutr3wIgK+frFbUTVsHnAiR3qQTDMNzOjvDaPtB+suFbE1FCuDj2HuDRBXY1wanzRWgERKWshVoEIk6fA0SfDTzNGDgBh7VBnyaHXLo0V0uncgTzfkOlQPNhC/aFd59v/KeX0E9VDQJHy6Yw9PPw94f+JQtsDkx3jqPoTHxP3IDIpB6r6b0oEKFOaJtgcNmS8lTCMPQsO80trTibzzz7NQvrocdJ1c++5eIRe+5555g/r6bW7MnIpozbh0QqejBMCxR04bLhjBuxuDcjZ4cJbr+DibMB8ozScj3XIqM77QVR4T91VE6EPcyoQJ3D91fosXWu7nmulgl5GGnSKVLLXoOEKgxDeYyNF2tK2m/EbUo52tHSxh3tPyIN75WFEehozj32LYg4MNPVL5QoDCK0Bf9ozUrsZflbw2VUNbF7mSKHLh5HXLmPZ+icpaq122hY1dGnPBeyzo0uls3A7i4Ug7qYLVdyL1Mn0CiUtCoXm5dcA3S6zFdw1lFo1mi7YFDIxnEZYiKBn+1pRl943Ul/wWO40iqxoqfczE3rBsG+O7fhWfPTdB2dzamOYgk9AzLf0jkBg4x7RhC5V3aYxAwkQtUKIgOyEuDtceEAzmMT67JY+gRuB6sEEHGoTjSoDqFVC6xmgOHMq2EWgggyx69XH65Q7RV5dADh8fojqddrcfdVNzCZLN7lNUXrlHeuQ9ZM9iko82h5pm4F0sEngG/pqZ1aiGTBRvUISfYPBr5/HGGqNnUwwBAnjdIVB3B7o1EJ3MJNQNF3tU+NUOH3xns1GgrKPrxGEcL79dmDKxIvBpwJT2iZkhko7jxfF61rGqTEpvhecCKhD4aMpZXLejdVnk6txUV7Ss4tDOrGEeFelw+qmY7RD9SD3/lZYOZ918MMV/IveuCAU79cPq133+g9KHJSaJKSxMtqwugDxdITIuIgcXB+o7JxRZHBkAGnkl0aQ/KB0R1LbD5WplMu9gbikMB3Lao2Ekr/cj2Ug5Xi9h95YAmfOOJ4UE017MdYvz/6D8uy+QMQxjIQqgcyjmKmkrbMEYz4f6yxwvElNH7gmXqeoo4tRFepIRoGqUPiw414QoloiPNkOJnZ6i4i2im5lCtoYmdUzTBd5L4b8qfoGAGiBYCwFY1hYDwG84LEcv59Heb4HIZ/Sxpj13S1mKXR0TaIRoqKLq64NC+nOL+DcGzpWFWNNqKv/H6kv+8CyHkC73nKWcApZT7d5+KwzNnlItCtU4joUZMpLIuB7UEFmBvQWq/bNFJqAqKgSDNORQ3FJVQDCoFRZZ78gpbnpocYkO3NeXwzpGYLwhu+HVA7DgQHINkxwbSU7NN2r4rT9Uq9vJVDIlY2BdcC2GuK7K1TBtCgHgG2y5KE64cYVFRUH3yVIjCxDaNEQhIv5x2FM17KHDl0Im5mB4frNFVLx1iAgTx4wDB4TtWUPleby4k6kzQ+b0XAgLjpGv94jlot9uB9nE9Vgrci+uwImC1vG5Q0Y1FfRdWgJLJVdjejP/+NWX/Jb30ZzWuecoZ4Htfaow9MeZdNVchiqEmVGNyhgNewgERlsDQQs154asvQIAq4OMTDiJBwkLSckDMJJjwnZZ0F8MaRA5ixz0g3rqRzvI7nvHVf7iX7nrWbZTLO1Svd9R1/AWm4WoMVvPtlEqkKhqGsb0/UUGRDwlvboLExHPEU4XVQ2IgUOfwDmdI0SRyEiKiqSSmQ82zdOB1V1K95VCz1bGd0RYkq6yQdhaobdyK9E1liS4YYFkR8Il/tlplXygqEogdK4G0acNY8Hc2Q1TMKrqh7NC2DFHZV1TyHGqidpPn0HX18Pd+ajCzJsk6TykDPPHw+PMe+uHw3WfPaEKHqgLijVCTE1XPjKSGGgO9XAYUG9xhO59uh43iFHW125WQzhmzJ5FN9HlH44xkBRBiPD/Xoh0jGYqeXO2cu2HjjbKQ9DA+LWLu1tckA+iG/gfCl+rkyFyEuoNz6DvkAn6bIEWoVT6rEpoOI5qr1Gjvz47S/EBHnRHVposG1+4CFkdTC4z1euj+oq6k9XzcJOfanwaXJYyRfje7/fRvYAD8832tnt46TLQ7p9geAGhRcpP++fHpm6+9duTB1ZDyS7XxlDGAUsr5ymei8PgJ8uabelBgmMoGztzpRPFmFqhm1j4EAh3G7AbkCK0RY0KEjN/hDSA0kTMRsUTXxhfDFLA6wKhsdbYbwu/a5u1ghtDWdD2iMtx5KHhlJL30xyZ8e6AV7Hg2pk0CC/Ru2CgomQiCw2oBBkCSekv3yc4fk9UEbcKunlSKJhTREQUVMabzMxVKhk/S1n95CzWaJgJtyjGK/i5MgFUABC9uz/RqaktoeQdRd2y1J33dUoSebse2H8A4aBfnRgqKbhvQ3qEyKlNbFFkPyHv3JfYOPWUM8Pg36n/7j4/6Lzkz1a7MvcBo4gEEvADS3uxeAj84VBshFKgpOaPTQ+qyf1w55Ds6FiDECkaAZIeuD5UI9+NvEELR2plOpD5LPTOD0HQeO3Kannbtrq4Gc+Ij8V2rTosdSUAEL6rK4X2goumdWUwYoI0QFcKUlsCM2OCyqhShVPMTIvnna1SZmaR9b72e85NxwOsFG8pWZSBlQVBiB1xyaWqcF8tJXJsBS3miqwcU3Vwm2pLp7HuMNsqt5PFfLHnXX8p+PyUMcOTI1JUPfbd8DCmOsw3ijR/Ea9N2CUByNsI28WMTZ2YEE+Fl4jfEzFLSEC2IGOdhaIoKJC8JJsHggyFA4ND18Rv+4T4wCe6zoc/jcyHtGAraKsOCdK3UzEBNgcPHtgPknHwyihM2QV6R19ABKvaQGvtBmBY5xyBu2AGzjqJDiuh4q0XVepPmxifpwBuvpuqwy4YuVrH0AekKY7MVaWkLY1R0cyNb2rcspsosdn45gkyrUWGTKOiSgYwVBWM1kCc6MKTo+gLRoK/nDYZxNVb0wlb06ucPZj663DMv9PenhAG+/rmodWRMBTpY3tuRGA5x4eO0DiF4nBJJbxvFQti2cQlpDdXJVjPsNuGtASPMgvgmp2jnaGfXmDiryGt2hs22ObBagIDN5urcJNAcTPCm/AqugY6PcyBuxjIZphGfv/QFCW0zjqJxRfRwGFIzimnizASFzuO07z+8pO3xsfvO6g4YMauJXvz2aRWkm/tzqZmA90Y8TN28QYvdK5Hl5drGCnb7FqI9ObXAK4T7Xn7o4ezBgwe7sHlvtLPcinTxrayghRPfq/6P7z+SecOJc5r7G4lDkMyYfBMHareG36GqiB4PohS8jejWttFq6+OCERJpzFLPcmvaRqL45PF72wNDRIePnaYb9u5KxW5196DWuMbFKG3r6hFax8dRM5vRiWtVtkVNSx2OxVmMgnbwHWrSCVL0mEpoHsk3M/NUGz9Ne999C7cPb4wYs+kpsAm+G8HCE4N7xa0Je2gx784KpnfZS7sxhHiGdpcVPa3sUMHTW1vlsZdDrBA1jt6WcS5J7dI1XQGwmcWJh4anT55S3mxdEyQmm111EHfI6zU+cjAF9HmoRD72vcp4/B0S1jXrubgIQW9gEuyIIkkm+E1cj4L1TztwbCYAw8B2QBtob7Ke0JWjHvv820hP40rFd4HqSL6ASHsYv1n4481qIH1sF98yBjpWBK4jatkq7Lo0JFSBR9hR9JBSNBVGVGuFNHVukq7+me3UuqqwQPqbLQJ6hjvIKrEstV7EBbBFWo2Ysvmli4LJI7hwdY7owKCiG4raPgpMlBjMvLcef/xVg/6rLqJLXW9dUwb45ufD+ZNnqDQ+o4M0MGo5ad10TQxJ0cFxHnp6hPIkKDtirsN5u+qCSG7djg5c2Ydg+dvJLqgi3d4tXROhfUxHRMcOH6KnH9jfPi3qkjATVixOtJFItK+xN/gdxA0GEMmO67jIlUXwnfjDQpsBPYfPf5YUjSmi0yqh89U6zc3MU338Qbr6N1/K7mJIb8Y9+dqNifHsprNfqB5/sYQGNK+BRvXcFBggFyi6fVjDJWAP4BDP0I+fm7julj3bDvXcYA8XrhkDnH5w+k333Fd6/7HTeoKZVE1lNhA+A9IMPkQYAfuXAPfD1wISbDxAkqoo78crAABnvEuvZhodVNIrAmQQpDtsBPwu0jhohpRkA/5NnonrJ+dC2jagV1xbhRIpLzp+G6djeY3gamRiNBOHa2xpb88JwyBMOfU2QyREFVJ0XhE9YlSfmbkKVU4fpat+45lM9FwYzPLdo81uMIWloAuL3bMUzXSLEXS7HgxZr7aoUF5ZFiaYFdHjnSWtCg34iqES9vF2JEms4rGqjS3Wr3tOny6cvXtrdXxcqw7zDZ2tBE8OJl7bAFq9EYgAzgmkAKqPRHTxDLkWxIrzck4IFud4AwhDwKLj2wQtqoaoSfjETurY9WUIerwZGdnfi8sWWkYtE5BpH0atELAJEOucANlTQKrFGUaxIQ7SDwgFuD2nkUhD1Pb6VGoNmp+Yov0/tY0aBwa6Gr6rSA+r0lSEldBo7M06UXYF5XcBrSjlFO3IEt06qL1C7MAw8zEYJg+/segdXJWOrlVZlO/8bTh+9DhtPTvd6bYYtyJ5YcziReU7Clc9KSfWfmtLNKeDUenvEhPgHRMlQtsKKcoErFaByJEbALXlvvsfomc/7SCBkLXR3EmhZEwbbzrR/UAbuE8+FwuSpe8WOALMILR9lBQ9FIU0W63T/OQshbPH6NrfeAG7RSFd04Esaa8btmetjNvlCFLecbnr8DtUoZKBSlyVVzScWgXumq6++BnbS1/qpa3lrrnkK8Cxx2Ze+N1vFL90etJsS2qkIUvxMKJW4C+AEbAxanAzqOrAm14YzD8bbyZiKiqNbcjiZb1WRE4GuHljPxij1g4yiRokn1zrBy7P+ZB2bQkoDDUzyGF7lHiCTD/g25fnc61Q6x69snXgzN0ywNgmMK5Q3kAv0VifR5KYqlFMk1OzVDt3lK55z7OZUcVLwz5+wEMsThTsX9orhH1fYDOsxQG9P2wpyiMTJnVgB1YgdjlQh3Gzw95dOgcmGCgousNEiQdkCTDXrpYqdMkZ4PMfD9Wps0hv1D0X/V0kMbw38PzYHhoQixNGFPseM4AckMb2XPrYaA67Olo2QnosbcIDQ8H4FQiyXAviB8qyjNazARuzIHLbjYl2QNAgcvYwmd95HgFpaOlzaAs95vSFlIdHjDnYCAJSw+2AOOP9K46iB5Wi8VZI03NVqk/P0s7nFch/7q6eVJ/ldP5LzQTLGb5gTmHU5VYEMDj+XTOgWBWyEaN4j1yszv1y3t1xse90SRngB19uPvDQ4+5N0xVt+NpQAzxYCIUlN7Ysxa6NnMiieAdHcaCB8BU2kjM7PwL7E5gaP7aaYXt7ug0M9HwYxml36Dz87cfO0I37dvJvdjaigf2381zslYH7bQJqYhhLcCvNrO3+GNWN8x1MrACJLwh4nVJEh8OQZqp1qkzOUGvmcbr+PS+lOYPs7HWywQgwKMFoi8UJem1rqetEqvM1iFvUI8oV7I2bFt4tDGDbCEu1D/UNqNGbBh2CKlTGJuMWxd7UjN79E+XgPRfzLpeMAY4eOvfse7818u0T4x18ijCAEI2oD04rIoXNaq0DRjC8NvCi4KVZNTJ6u4N9s8x2R91WUpuA5Xfsowj3KLIOkRYpBwh+ei6krQMBS3yR/HZfxNePfkDtMWVGdX0hI+nRosQgwAzot7wfr/om3gGVJxom8qdM5lWs8f0ziuhx4/WZOD9DjfGjdOA/PYfmrIp46NNiPvynSvq36kReQASiXsrYbTWQGITYAFFgnENQg1pNoky2k4tsrxJ4X6hCg3lFzxp0aDB4sj3w0yfHd1x99fZzF8oEl4YBlHK+9tmoNXaMfIE7gPih7kD10eqEDjDBFpDNIGyVhCu2md0bUb4cORcg+lKzRa1chr0/OlBG5DdbFCG0ucjbpA1qIUwY3uOxQ+dOzdBVe4ba0lzUHPRnUUlueRDS9oXtOpWtevEpxAvJzFluALqB0YnoBwkCXiFNTc9Tc26edj8nR87zdzOUYSkdfi2CWksR13KqjNy7HCRC0qUlQV/ukyjx3rKiZw7ps7ZR7ClqvDXrrMDPtPBtLgkDPPL12pfveyy4a3JKZ02BIODyNCtlW/WRh7vYyRw5AM2QWtmgTcdCWLINEvz2obWbZ4hNrq19c1kamxlxjI8fz2TpHMUMZ8bfAkyDxJ+eatAVW3LsvRHG4JReE7RCH7h6BKADgG1bXiHkKGRh2FnuThleIfj2KmDS/oDYBO4F6g8YAdL/iCI6yV6fBlWmZqk1c5RueOcLqJrRhu5iySpPldRvr54m2FWZrVNpcCEN2ok2ac89agYIoeM3e3WQVQKfckAVwrRfb6LENgPMhopuTJK//Lmy/8oLWQVWnQEOHx6/9tHvDx86dNyUFDQgNfbKpIxYtgEQCEp0EgyMVFs9YYbhims6UcIGubmtiBJLbbKlrjAKzokhirZA5DCmTEoxTc+1aPuWDM0aA12MXAHOSa66nb4ogyxtpKPI+B0qEiSzVDfhdzRJ+vqdOq7V46Taqg8SXGZPHKaD77iDJk1dAMmLBpdJIArn8OpAel4IE6zmqgE7IJPpnlsMqQ7D2CZmvL/YDml1h8euC3IUhjOYYCCn6GBZ2wM516H5GDWT9Jz+wpnpg/v3b3l4pUyw6gzwd/87jI+dJLfa6iSkpLOrdIKK1u1jIypwToJOXP3Z7MqC5PW2rWD0bNG7RRqz18i8uQ2qk+AVJL2tr3M0FT7/++6nZ9/6I6yCMcbI0uflmcxABrfTjRHE3hAcD+4TAmsn96fSJGF0g4HOO4qOGZgzB7zGz9PWZ3jk3XkNCwa7AsNKJ3ap67slwFxo+2EroiBlvy3XFlYAz5h83QxiqSoj17AqarxCSKB5wQiAcpgvhyHTEDg7cw5diGt0VRngni/NvufwWOFdEzMaySjoTfH2SMQXsAYmDux+0oqo5vtSCK0dUZX0QBClDS8G4YKwBXMjkVdbsuN5IGpIZwlKifqF9iA1GtWQtmzzKap38gZwTTp4JQZ7WteV8wy54FpE5tOsVKL7S6ohViOpSoF+AeN/Gsk2YYsarYiBbuH043Tte19CNfjMkeBiql4wSiSVbLIcEXOqIxfiWo4cL/z3VjOhjKlg10srIHYQta0Spcd1KVcqosTwbu0uansATFAxYzQSOLS1GX3l35SDF/bSF7lmVRkAPn+oPjgg9QVazGXH2YPiUNBoUZjLsFuRUYxG8oOobQkswSepKILvYArB2Jjy+PwstCHBQhA+7hEGklXCVpEqlZBGhwKCpBGQucYL6XiAnZYnKo3ZTKaNeWAmM/WH0oPIW69CzTFtgfC5bhDq5hj4BFQfBLwqgDlPz1F94jQdeMdtVDEJ5V1qdfG72qtL+hpISa6DtAaBr5VCHITgFlSeMy66pQxkWyXCuyHPAWN5+4jOJU5HiX98fOaWW3YP/7BXJlg1Bhj74eRrv/ntgQ+dn1/o7093RKK7XObDRFWhooBohcg7eKBOJDXdjrgrobeDeMU/b8OOxQawGQKM98jDj9JNBw90HaPlaocuVy2NIc6m+BSYHp4eeHxwTrLB5hxFT9iqz8QUXXGrR+5L9nF2l12/qNeJXMvrIMkbtQaVBi1LdZkOCJFjn7fsRWzSBGMYqxvqC901QpTzUHaxQ8aeUo23Zt2evUKrxgCf/NNQnZ/RBawk33bBMmNgDeLZ0bifTnYUiF985+JTBzFDynLqnFED0KZAkMV9Kvq6fMfqYHtroCNipYb0rcxrpGc6oCUrxAKXplRmgFfIoC8lP18IPV2cgs/DSLV2YwUTGAQAqz4gfnh9pit1qtcaVD/1D3T1f/mpZV2eNo1BGgIKvVi+74UYx70yUdjq+PJ7uWc5V+liKZNLtT1UIrqmrOhgSavIUlcI99zWTH75RWXvD3rp26oxwIf/IFTw+YtvXx5uQxFsA1VUAUhFSF3YDAwblmXeUol4AJOEAtT6NNFXieaK2iRoSjyXty81Kha+M2wBQLNGRNVKhUa3aYey6NbijRK9XfouKpoQrwwWGArBnxg6rTGQ8UwQHe9GY5YwXMflCI09Mm8CXo8arM98pU4zJw7RwV+9g2pFnXJoE24v3hq7xg8/6xLq/FAZ8S/t1emF0CAB2mqoGUjBBQmDIDC2ILoM9RiuVhQVsIr4SmxgwATItmbUAgZAf3o1iFeFAcbGx3d85sPDZ0C80PNtLw3r+MYFCVUE38EIAn0WG0DwNZDiICZxRbK/3DICoeszkzBsuFNHhifBSGwQvGRx4X6GJ6C0yMQ07dg9zK45WTVwG+/PK356vZkkX8+rgVkSmNDMtcI8bQPZuDbFEAbhckFa8y4VbkvRrEN0PKX6bHm6osEX7aca7klVdbAJK53YIlCHpQpa9USYPV6EMYPvvl4NqWhyJXq8dcFli8Eg2GBH/dFFkBS25wgNYowHikQ/MkS0L89pk7zqyvHMWuun7xzKfmq5Pq4KAxw+PHXT5z5dfgBRXZHM6aCV+MtFz2dpYEVHUfXByQIHqg9bJWGjNNLBMiFYjtaaZBKoN+zaND54DISoIiBuEG/VUn0Eh8MZVcY/L2qW7dFh/72R8OhD2r2JPqaltDAWzk9jh0rAOUz1CXh9DiUxnZurUrPRotqp++na9/64hldcoE9/uQlezd+XA7t1e9ZS6o8t7dOSX+5LA+jwDPEiASZxLUosllBtWqdQQvhh7DOKpt+cdTrVDBYZiFVjgE98svwAngyIAqK+Aj8Qrw90bnmYTdwMC0ClMBSVxabTVnIJG7cm2or+S5KJ3Wk7Wiw7rUu0laOMKC3SjGhs7Am66eB1C4YBKgoYwPAXM50EsNhLZVYfXCOHVJ6W33FzOwYBCWYYBm0B3ZlVDsMdgPUR1ef85Cw1zp+iG992O503iD+po2lHUFeTeFejrbAZUWBqNPXS3nK6/1JtdAuSpa+HR2gbssdKDrtEt2ZQNVuXV0SZxf+cT/vznvzEVWGA06fnRv/XB9wJbNUjR7bWZPQmqtxQbgAAABvWSURBVLdJ0oltmOJK1HG1t/+Ue1l3NsWecM6OIAsQzX4VGWgYzLIMMnEbSEOzGlIJu0YYghbdHszRzYgV7w1gDrYqw8Y1jE/DECaPnz09dUdRHjgnh2iS9N9SCucYKQJaC3V9GoA6n5mg3NVNtfVfHnSk1EgvBIVreqnGlm5rtfKCV1IOpVElyhXhLSLKGa8PIA/Q5W0vUC+Ebr9PWhXaNaLoQNGhskecQsnVuM38/HZxjRgAHfytt4wrZ3CAgOtp5QE81oYoG4dENG8wMLADYAMwOVr4epMSrI1A49sHYYk+LmlxeEGJvfCOQakCsCBOvDZLaOzeUototOzz6mLHAvC3+OnRPzxX1BecF78/+sBxBo/oPKQL9v2SvpuanSB09I/tG7NSsZfLVIOeVEQPRRE1UdIQ0v/cEbr+XT9Gs8Z2sCd4Me+NZHst9ntaFbO/X6xHqFf4srxHmkhxvttqkFZ70ozLSFEgR5cQ0+UC0W0mMmwHTPH+fzS4fP7wqqwA6Phv/NKp8VZpcGtuoLMKgAig30pQC8SLB0JKiiqB39huML8JpFh0cUhpLG/IlhJ1B8TJsGLjZRE3sCSayISHrZiOPHGIbrqx4/PnrYYso1quFdUF39EupD8TvzGQIVXAcHLI9QK3kOT7tksWwUCj+oxxaZOQAHeYPX2Kbvrlm2k892SQ23LR3V5XidW+rjrbpOJgl9JuSz3IljZdGKA9B6ZmKZqyGcL2EEkmmZCzzUywA24cVrwqQ+MRgnaUiv58FBs7LX2sGgMcOnTumg/+Sf5wrpRhbL+ozRyUNIPBXpNWTCoAOt94e8x3diFaFRKgwogx23ahWfq2SO92fR6zciDcGnmejjxXQxodCbjsIphD2u/mauSBMNTLG7dYxao40YazvRT55FBIioq8hZJ2e2KlQxag5AuDT1qOInh/ThDR2SiiqUqNk9uLV8zQyL++fckMr15Vll7cpMsRwFK/C0FeiNol7dqrR7eVQX5nl7LJK2C3p+UNgXsU7lDpBys2CID6Ol/gqrJigSWqKX7OuZR8YjQNrn7y264aA6DpX/33p5o0MJgJSlneLDpdyw4MAMJkSWqpHKLXsy8fLys2gLV7EfviDYOIILbVJryIMAMIHXo/sCNuEDBhimQW20J0e9Hp5V55jmiPVdgSxo8vaFR8YmVmJjZeJOwKiRNsOBMRor2o5vxYGFIjAtxhnhrjY7Tvvc9dkvh7JTbZygiPBSr0Uh3Q2wvF7mjPbs8E04henyY/wfyDoNvKibVSyH22B4jHFLv/AEZiQHTyHWNQyBMhV8DwRHs+bg5b//v9V+V+ZrlxWVUGOHToUPZ/fnB7wwG2fyDH+3GBESQABsJm/d8QuXCsGKxsExj9myfW+E4xWKLmiK4uiFGOEUDE5/x2aXVce+TwCbpu/542XkcGQiSLPEegyvhdnscSHIn5DlHZlFdpkKIcwaUJw13r/AhsDSPFUmIFfF9H9ZEML1Z9Th6lg2+5lSawKFuFa5ebIPyeZoqL1el7eWadNzztnuC+2P1tCZ9Sf7pdb6sx7MKGvm/UQskRkIK6wizIPsOBgltYOcAcQ8MaFsGEPONQbkTXFv1Q61h+3759Zr+cxd94VRkAj/mz3z/7sfvHsj9Ho2XKhBE5OZ+BYVBnBLkp0lYkPmNnjAojObhp0JfsU2fBPtp714nUxjNwP6R/Gu4gHht7KHjTDUArjL6P32DEQttlDxUCeCACcggMkKWOjintcFlyGMOOopxyOLcXbR62Al71ap1azmN0w+vuars9u01JN5VG7IJeV4ZeiLuXa8SL08u1cs1KIA1pTBDAdUiVhHTHqgM1SCS9QC/wCWYAo4BB4U0qoaJ0RlE9dqiQVRTPOrR3S9T8q11BT0ClVWcADMabXndceQNlymI/5ozPRiWkPvb+wgPheoQaxBh9Y3TivrZBauXB4py4LSU6K6oPe4iszdgUEiSaEc3MTNMVu7cxdYswYvXFbBpnqztslJvnsd1ganIWTURbGAL9mCNFQ6g2ByYzjAKJD3UI7eNZUH2mEfBSCc21Qu31GT9K+977HKYT7JO1VtHblRAvrhUJjv5V556c5bXS9kTKyw6T9v1c38ioN7JHMkeCjdmKvogNYucHsJMCO4dCjXKJSkWifIMoQsYeoNYJ0Uf9qcE79m+Z66W/l4QBnnji3Pb/9j7vbHYwR1ExxwSGnUIFpAbPkGB3RIIyA4geD0xA4D0JFyOS3lYBONkdxGoivnPTDRoZyemNpcVukHKFRl+3IQtwzyJnANcKZkfiFVLrx0aY4tl6+yJstKHzm6Gp8f69qCznKDoK47fVonlUdzg/TQf+v2tpNn9hG1WsxPfey4T3cg0ILpvtXe/nNk3uQVrvT3vc5Pk4z/8MI0i2GyQ/GAY7foq6IwyAa8MW9oN2yMWWtzB8MxoiDTvNTYgGm43HvndbvjvUt8vLXxIGwHM++Hun/uLR44VXBfmA4oxPQU6DPPB/LixroTwXELZkYFkux3Q4QxhAXKV4CVF9tg4F7SQJRITBfEifhGdK7pP2OIBFigY91Cbt1AGyCR5eHjF4RUXBc8X9CVWJ7RVHUZWIzmAbIwS8miFNn52g/I5JGn3ts3gbI0itXuvyr4WevxgzAO+TLy7rQXzS7WLEsiFscD2svxsq43qmSGAxSTE2A0hj8OxAwkMdAuELjJq3eEJsCQMO5ECgN93AnHA9BMxTi+hjN1PmdsfpOSPikjEAXujNrzueuOWy4xcz5JW0H1k8PEK8eAExgttZVAYJyohOK0gVAQ/kum13l8QBEHxDew8+9BA9/ek3a2iDeIwMPBl6vsQA2jYI8hAMFEHsAfHng/9qjqKSchjSUDAqEVQeEDswPmAMqEL4hEGMgJf4/M+dHqfW3Bhd95/upNlVQGheqA3QdhqIW3GZJQC6db7UyzrRucZOaEkbt+lQFH6HyxOSO11XiOcFq7VxiQqyVRlbDTZG26Xua1sA1yNIiVX91X7t9e/cX/zTlfT+kjLAYydOXPGB92ZPZuARGsob96d+pF9vkVfKsOeFpZ3JA5YsJ47ESklxEHOjRXEuo4kfVSRct+3XR3tzMw3aOZIjuC3bkWBzfzszy/LWsMpjorUwXiEyYMiOiFcHS7px1UKvRwQ4MME4e9DQDtQeGPgnDdyBvT6njtENb72lDXPutbLySiZvta+9ELCb3Qch3HS/IMnFkBW053IgOYkPcBol9jOGBwgqU1NRbhgq0EIUwK5mdO7eZwUrrhR3SRkAA/GHv3n2m2Pj2ecGhQypUpZhzFydzRC84HUETw+1BOVRklzAniEGxxkkqESPpeoC2sfOkgC7lYseJY7bxt8LklO8SgJ94G06LbhyjO9GQouQtGMGMpniFcKnxETlOiS5wPCF23Oy1qDJ0+M0emNE+Z880FNJw5US8mpHjIU4a/MRFcqLV3brtZ/iDRKjGt+hsrD91CDKwj8Dh4SVHM/7HSBYaQieGcUUBgATYLVQdUVO3mGpL3gimYMzT18e9tCt/5ecAfDQt7zhdEKFPKtCUS7DFR9UnJDva4JlCENTV2sWrw1L+qYufSJRYokuS36ANrwUnTx2gq699kq+105Z5MExxrCdpI6/pVK0eHPsIBd7loxqY3t7JM8BGB+gPKH6QE06h5KGKqHZMGKvT+3k9+n6//xPaR7tGOZquzNNhBnjcqFqzWKEuJzdwHqy3z1neDlczmLPhMsSxCqS3f4OY5ZNAKi5JpILaS5eH/wuVeLQPvrAAVKzcoNx0C6rPuaA5EclOQmkgk9+J5h85s/eNPr9XhnUvm5NGOCb9526/lP/PXg0t6VAYSGra35Gsa7rw3q+YinvGM8PXESJ55Ib6g2x2cVoxHMS64pxEjeAz39gq6nuIFgjy+sjTMGrhfldVCScEzemGLjw98Obw0nyxsMjWWicuWZ+BzPATJxw9E4up0Jdznzm+GE6+LZnUrVEVAf6Ee0AVWoVEBKp1SvkYbmJtTEyy1272O+AOmfz/ooyyiTqK3sB2G1zzoVJ8IH6B4KFAcxwh5b+tGW2GMTiRQKTAAzHwg/GsIrIcXxmGOQFo4Axfrshrnz963eUn3+h770mDIDO/dFvnf6bQycyL2XXaC7DyS0c1EKBKxA7DFnePdlsGC05xMY/6UJcoOy5AbLhVmB9zpw7Sddcs699niVJGJMHy8gY3fjEiiKrAfbdRXBLiF/gDLL6QOAIA/B2TdirGIW7PG0r6BVCUcMhxvk/GEc0U2vQzNnztO8VIxQfHKGqJbVkcpaT0Bc6iRd7H1SMXK53D5X46LttfSqS3HaHghFkk24ui24G2k5zxH3teIABOSI4ZkN4UXsUzMMhLqhHEdHEMy9M9WnPycUO3kruf/MbzikXHqFyjrPBVC4gB6wMFB8kPbuDdEk0jJHt/pS4gUSEo0bEQa/hkRxhVYhRY4jVKW1jCJwZ99mReQ68GXeQ52OfXUUZTqAw3rpUdTpRhzhoZ70sVgJsXn0cO7iHIU3PVGh+9nt07dtfThVMktmbV25Zid4uK8RKxvZSXCv6OD4jxAZ6rrWgo7lcAwhuaGvghMh5fq3zEv3luUcSE++DZjwR0PnzRCVIfZ+oagzgT3vntj/3aTvGL+bd12wFQCe/8J1Tz/37DwffhCoE6o4Dn3yj4oiLUoheYgO4T4hZiJ/98LWQRgcCzjOwoRCSFMO5xDCq4oSlN1Co2GmSP9FgN8FhOAVGLbxBU4gRmJqmYE43gLKmvT44YPg+aJCe8Prs/fVbKAiJZrvVSzSzBFw/u36Nr9z2Ti63m0vaZui2+cVKEaLVuQYVLQh7N2JazDvEnhrohSm3GBu3qTACoA9ghgUJ9Wa8mfhNsIXdoLFmIDkyYDyz8ot36FnN2T/97HOGXn8xxI9715QB8MB3/vsTJ2tB6QoOkOUCdmcKMWLyJC6Aa/G3eIfEPcp5AM2IDh16nG646cYF749r25h9M2BCEKB3SBQB0eGZgvGHClQzeB4xbqWuJxOoAtYkoQJWJxC+o3gTbYiew9Uazc5WaOfLBsi5tsSEzZNo7cGbnqTlCL3bpC5lMHfbGmkxdatXNczO5DJD0JYZ4sIUYky7NHspm5KOEAvBi+3AqlTSItfNsPQX2AT6PxwTPXzbxak+T4kKZB7q/Mr/O5k4oLpiltg9GkZ6F0hseuF7vFkGZX1KooSg+yeZgJym3jEGEh3lTQaHsjqjC4C7jK/LoAgmxypVyAwV6VqjoiLxrjMSDZNOGXEghjJWEKQ5IgAGT0+mEVMm63OSCyK+JxD0arU4yWXmxBN07TtvpxCgOmxe3WPQ6WKl18Xe36i2KFfsfSdHCXjZ/n6p7CwuSymbIlJd1Bz26BjDVwJhbdiz2fvMQbAyJAqriu0tGGIcEQY5wF0NmIRLdPpp2B/FWRUQ+JqvAKwKffnEy7746fwXYBDH2YASED10vxAbneodJJXnccwAA8EYIUTMAo8NX+VGVCjkF8ApeMWIYt7pkQvrWgJCcEJScU28QCzluWSLIhRlBwQaCS8RoM8w3LBTOSnKQP3xXGp4APQpmnEdekIldGK2QrX5Kt34yh00vzugeQPSsmvzQPdHVxZ4gVJ1PnshZFtyy98SXLN/E89SL5J+pW5YxuQD4oDCtCaC3nZvArNv1e7p9k6M6UFQ0yS+iHcIKwnPMVRWc402AomKyMQLNNYHJSdfn59/w2/dNPDBXsasl2ueEgZAx977llOPTMeFA1gBoAolgDiohN2h8PYoUyYFpdPhMYqbETVDRVNTM7Rrz1ZNVK1Eg+AwcshCM1lZWDlg4NrYncV0Y4E+iEcI3+Hn9yJF2Loo8l3yWjGFGZezv+phQmdaEY1RQlOtFs2dG6crf+0AJ6XAUBSi4oCbIQoxwm0mWA7jvxQBL0fcyxE2G6Io1bI6WkTb3Ynm7GQVSHjG9VjZlNql2dlGlaERBvMjblUhXEj/IpCpxpDe1awf+8FzClf1Qti9XvOUMcC73/1ud27ql2Jsfu2MFLUtgHkx26NCPw/DhHwTDm4h4tuIaGQgoIoxMhExxgrC+qHU7TEeIY4gG1WIK7lZniXZqFsGCc1xTSErwCWBMawKGdJqUKOR0Ezg0NFKjU4A7jw+SVF1nKHO3WDOyEjDefsAkbC0W0RNWqkHaCmjdzHPU3UupNGtwZP61ivRpJPkxUiWz26pj6zTG9iLuEQ5AQqqkYkTcNWIpiIHtS9BC1pL5pxx+C1O3LJKHGu96FPGAOjD333hxP/z939f+nMYxGExR5kk5t3j4R1CbAD4fs93eFUAMxw+8hjdfPNBBs/hkMyytkFjqRZ2kgt+l2oRILz2TvWINcSKXN9lAoe+3zQE344Qm5jCdBTTjO/ShMH7yD5embEn6Iq/+LklIQ9gBKhfi9XxXMwoXuw80I+wNVbiWu2VuBe7bimQXLeqEWkjeqnnc5Vu8frAHmhpyAOMXzGovzI6ddPBvVseutj3SN//lDIAOvP2XziahLmykyllqREElE1iSjDzBiAH0R41Y2o1QhodznGhLCiLWDHEZSq4H5b6kOSRIqws8Bb5qDYHW4JFikOxIWjJ9MIndEuoOxkFpKeODg+Qw8ktxcShCphSKXoicGl+rkLHHMUJ7sFDD5OqHFX7/vyXnGlfw3Kxly+6D3UH/0SiS1wgrb4s58FZjSivTDqIqVnvJLosp0qliWW58ig9g+kkV8PEaHSqo6IkDsn1OkY5r9ou0a2q+vkvPaf0itUmfiaJS9HoStpUSjlvfuP5xMv75G0tc4xbgWhrIa8EDJpqxW3VRwKJnB1mPEdt/AgnV+g8ZCwSwPuA6AWCbWsdYZRQ4LuET8Yk8RKt7Q2uWxom1FQJhb5LUaRoqtaiEyrU25lOzVI4d4b8sftppHYiLv32u7zqXq3oLjBWO6VF29Jafk/r6fiOVQq2hB1EA1NDRUjXDUU7xivLZRV7OdoYfdmaKrUDZS9tXMg1C4pfGYMIqg/eAUyJjKKkAaGlQ/BOxmHvD95vOEmih5+RjipcSC+63/OUMwC6dffdp5/3/388c3cwUqSc73CNUIScEJ2FSB87fJiuO7CfQhMJE+ONq0AbQm7BXvAdioEVksrQgC/EMSlYZuZNpZ6Pljk6chzBRRonjApNAldjgMKYWo5D9URRrRnR2SikSqVBx1VEk1PH2sT/vKc97d7/+Ot3/fxdM6OPYcm2jeBudf5FZ+8Gj+7m6QEz2MR/MfihKIzJNxCR1SOhVEt22D31kxjA7IU20V6oO8qUD1FwVxcccnyHUNEHoLezt66+3m93a10wADr0zrd/9+NHZ/f87Gh5gOsGuagdBDWmEdHQQIaqoVZrYD3ik7E9wNTBW+M71EKqnAH8wAuEyhS4jv92HO1XxmH8/6xJYZXJeZRzXF5NolZEju+RD1UHnp9Y0VyIim4JnZmp0ANRlY1ekfw3X3X1mS/+zev3oNmbPjr58MmrR25AMomoNXY1N1wDYoYdgJ6IVLdXAiF2WZolVNHOkTDwiuXSJLt5gdg/D5/6KiTnCAF1iwvYxIXfGeZs75mMjfNMRYekqiiqxGyH4Vq/6FIQOBTD9e0T/XBfb5UdLoaZ1w0D4CXe9Pp7Hz4X77phy/YB9vvCEK5Upqg8uIXBbey/h5enFWuCZgwEkZsBrFozi5yHKgSYRdxKyM/7fA+YoX0Y5Rzt4h78FiPvgEFZimphTOdJ0fjZGc75nahV6PyJQ0QzT6hyMJFcMbp18t5vvHm7PfhbP3iu3rpmay436LQxMJDYUvmZVx2UdjRGrNzLMs7oxd1sAvu6C0moXyr55EKJB9AGQBRs+Ww/B0A2oERB7IA/4DpdakXj+sPZmMK5mIpRRTXmYqc8RKqZLzheHKtWueTcveeHxdtvv712of3r9b51xQDo9Cvf/Jmfaow97f+M7hrgWvQ7rxikWq1FhUKGkBKJgWw2QyoUslStNimbRb6A3gHe9z2KEAxrRlQsZqlSaVLJpGLKgMzN6eIymQyuTSiT8fl63I+j6rvUQC2jiQpNJTFNVufpuDdDQ4+covr0V5mDbtm/879+6+vveke3Qb7rl/76td993o9/yC955KJqsZVeuBLPSK8T2Mt13fbx7eW+9DXdIA5p5hK/Pie3IzCI4KEh46SiJX44n5A6O0NqGhkTwAElVBiIlSqNUL7W/N6Zt155x4X070LuWXcMIC/xjBf+4YeHys97DbCdWWfQwJthHHkclZWjVQ9Z0ss5eIuwbSerS6mjXmlygAwlvhlmAWLHfq5cKDchFxtn1yqkopgqM+dpzK3S8MQszYdnklAd5eve+c5Xjb7jF39sernBfubbv/Er/zhy4Hf9vYOUGfFZt8XBcQD8Q0kXg0BFdhOw70BBMijM+MwZAW6SP/h1ZFNpc45hyZGWtAlq5piaqYAUiJEJ6QtUJl+LeAjgBiZhHec4omt2E4HqBCnN+bowxgPEYnTkFs8AA4inB0YqVgF+B2uDEXuFgooTVxNeUVvnGkTzdVITc0SVOUrmz8DTwDVyHNejggru/9xr/NvuvPPOHk365Wagt9/XLQNI9//gz7+6+zN/dt9vnZ8a/Mmp8145k81TGDYpWAyMbm6Mwhb5droRqx/do5+tVoM8z6dq8zwrImECcESdMt786S1D2e9s3bP9Wx/+/X/yx/v37++C8l96oO9RKvi3r/3cG+8f2f0+tfPKjK4R0x1/w0wLakIMxNQ75E1DsPEa6B+1+dmeMTa9YfIEQCgEAuEVWOSQyDpn0QGxB5wBrGveasZ84qwPj4zeOIFLGNqVyJahKcRwEinZXWmQmq1ywEKdmiRVO0/+uQnKTUypfHY2cZOIMnv2fepVL9v9q7/95pdp6fIUHOueAZ6CMbnkj/zcPfcUvvPNmXKlGm89/8TYSORkS6f80eFWS62sFkmSFJTrNl2VAA2SVZR4zdhzkFunKM4r5YSO6zZJxT3Veagn/pZ2kTDXpUYU5xPHfdKejq1mNNBtkDJZfy5Tn2sVSvmjeyvHxka25I4P771qcnDAP//in7xm9s4eShVe8sFPPaDPAGs94v3nrasR6DPAupqOfmfWegT6DLDWI95/3roagT4DrKvp6HdmrUegzwBrPeL9562rEegzwLqajn5n1noE+gyw1iPef966GoE+A6yr6eh3Zq1HoM8Aaz3i/eetqxHoM8C6mo5+Z9Z6BPoMsNYj3n/euhqBPgOsq+nod2atR6DPAGs94v3nrasR6DPAupqOfmfWegT6DLDWI95/3roagT4DrKvp6HdmrUegzwBrPeL9562rEegzwLqajn5n1noE+gyw1iPef966GoE+A6yr6eh3Zq1HoM8Aaz3i/eetqxHoM8C6mo5+Z9Z6BPoMsNYj3n/euhqBPgOsq+nod2atR6DPAGs94v3nrasR6DPAupqOfmfWegT6DLDWI95/3roagT4DrKvp6HdmrUegzwBrPeL9562rEegzwLqajn5n1noE+gyw1iPef966GoH/C1zAroKuwIcHAAAAAElFTkSuQmCC`;
diff --git a/eims-ui/playground/src/views/demos/features/file-download/index.vue b/eims-ui/playground/src/views/demos/features/file-download/index.vue
new file mode 100644
index 0000000..b4125b8
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/file-download/index.vue
@@ -0,0 +1,74 @@
+<script setup lang="ts">
+import { Page } from '@vben/common-ui';
+import {
+  downloadFileFromBase64,
+  downloadFileFromBlobPart,
+  downloadFileFromImageUrl,
+  downloadFileFromUrl,
+} from '@vben/utils';
+
+import { Button, Card } from 'ant-design-vue';
+
+import imageBase64 from './base64';
+</script>
+
+<template>
+  <Page title="鏂囦欢涓嬭浇绀轰緥">
+    <Card title="鏍规嵁鏂囦欢鍦板潃涓嬭浇鏂囦欢">
+      <Button
+        type="primary"
+        @click="
+          downloadFileFromUrl({
+            source:
+              'https://codeload.github.com/vbenjs/vue-vben-admin-doc/zip/main',
+            target: '_self',
+          })
+        "
+      >
+        Download File
+      </Button>
+    </Card>
+
+    <Card class="my-5" title="鏍规嵁鍦板潃涓嬭浇鍥剧墖">
+      <Button
+        type="primary"
+        @click="
+          downloadFileFromImageUrl({
+            source:
+              'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+            fileName: 'vben-logo.png',
+          })
+        "
+      >
+        Download File
+      </Button>
+    </Card>
+
+    <Card class="my-5" title="base64娴佷笅杞�">
+      <Button
+        type="primary"
+        @click="
+          downloadFileFromBase64({
+            source: imageBase64,
+            fileName: 'image.png',
+          })
+        "
+      >
+        Download Image
+      </Button>
+    </Card>
+    <Card class="my-5" title="鏂囨湰涓嬭浇">
+      <Button
+        type="primary"
+        @click="
+          downloadFileFromBlobPart({
+            source: 'text content',
+            fileName: 'test.txt',
+          })
+        "
+      >
+        Download TxT
+      </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/full-screen/index.vue b/eims-ui/playground/src/views/demos/features/full-screen/index.vue
new file mode 100644
index 0000000..485b2e4
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/full-screen/index.vue
@@ -0,0 +1,47 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { useFullscreen } from '@vueuse/core';
+import { Button, Card } from 'ant-design-vue';
+
+const domRef = ref<HTMLElement>();
+
+const { enter, exit, isFullscreen, toggle } = useFullscreen();
+
+const { isFullscreen: isDomFullscreen, toggle: toggleDom } =
+  useFullscreen(domRef);
+</script>
+
+<template>
+  <Page title="鍏ㄥ睆绀轰緥">
+    <Card title="Window Full Screen">
+      <div class="flex flex-wrap items-center gap-4">
+        <Button :disabled="isFullscreen" type="primary" @click="enter">
+          Enter Window Full Screen
+        </Button>
+        <Button @click="toggle"> Toggle Window Full Screen </Button>
+
+        <Button :disabled="!isFullscreen" danger @click="exit">
+          Exit Window Full Screen
+        </Button>
+
+        <span class="text-nowrap"> Current State: {{ isFullscreen }} </span>
+      </div>
+    </Card>
+
+    <Card class="mt-5" title="Dom Full Screen">
+      <Button type="primary" @click="toggleDom"> Enter Dom Full Screen </Button>
+    </Card>
+
+    <div
+      ref="domRef"
+      class="mx-auto mt-10 flex h-64 w-1/2 items-center justify-center rounded-md bg-yellow-400"
+    >
+      <Button class="mr-2" type="primary" @click="toggleDom">
+        {{ isDomFullscreen ? 'Exit Dom Full Screen' : 'Enter Dom Full Screen' }}
+      </Button>
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/hide-menu-children/children.vue b/eims-ui/playground/src/views/demos/features/hide-menu-children/children.vue
new file mode 100644
index 0000000..9b009e3
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/hide-menu-children/children.vue
@@ -0,0 +1,3 @@
+<template>
+  <div>children</div>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/hide-menu-children/parent.vue b/eims-ui/playground/src/views/demos/features/hide-menu-children/parent.vue
new file mode 100644
index 0000000..9208775
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/hide-menu-children/parent.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠鑿滃崟鐨勫瓙鑿滃崟涓嶅彲瑙�"
+    status="coming-soon"
+    title="闅愯棌瀛愯彍鍗�"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/icons/index.vue b/eims-ui/playground/src/views/demos/features/icons/index.vue
new file mode 100644
index 0000000..cc5ed06
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/icons/index.vue
@@ -0,0 +1,106 @@
+<script lang="ts" setup>
+import { h, ref } from 'vue';
+
+import { IconPicker, Page } from '@vben/common-ui';
+import {
+  MdiGithub,
+  MdiGoogle,
+  MdiKeyboardEsc,
+  MdiQqchat,
+  MdiWechat,
+  SvgAvatar1Icon,
+  SvgAvatar2Icon,
+  SvgAvatar3Icon,
+  SvgAvatar4Icon,
+  SvgBellIcon,
+  SvgCakeIcon,
+  SvgCardIcon,
+  SvgDownloadIcon,
+} from '@vben/icons';
+
+import { Card, Input } from 'ant-design-vue';
+
+const iconValue = ref('ant-design:trademark-outlined');
+
+const inputComponent = h(Input);
+</script>
+
+<template>
+  <Page title="鍥炬爣">
+    <template #description>
+      <div class="text-foreground/80 mt-2">
+        鍥炬爣鍙湪
+        <a
+          class="text-primary"
+          href="https://icon-sets.iconify.design/"
+          target="_blank"
+        >
+          Iconify
+        </a>
+        涓煡鎵撅紝鏀寔澶氱鍥炬爣搴擄紝濡� Material Design, Font Awesome, Jam Icons 绛夈��
+      </div>
+    </template>
+
+    <Card class="mb-5" title="Iconify">
+      <div class="flex items-center gap-5">
+        <MdiGithub class="size-8" />
+        <MdiGoogle class="size-8 text-red-500" />
+        <MdiQqchat class="size-8 text-green-500" />
+        <MdiWechat class="size-8" />
+        <MdiKeyboardEsc class="size-8" />
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="Svg Icons">
+      <div class="flex items-center gap-5">
+        <SvgAvatar1Icon class="size-8" />
+        <SvgAvatar2Icon class="size-8 text-red-500" />
+        <SvgAvatar3Icon class="size-8 text-green-500" />
+        <SvgAvatar4Icon class="size-8" />
+        <SvgCakeIcon class="size-8" />
+        <SvgBellIcon class="size-8" />
+        <SvgCardIcon class="size-8" />
+        <SvgDownloadIcon class="size-8" />
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="Tailwind CSS">
+      <div class="flex items-center gap-5 text-3xl">
+        <span class="icon-[ant-design--alipay-circle-outlined]"></span>
+        <span class="icon-[ant-design--account-book-filled]"></span>
+        <span class="icon-[ant-design--container-outlined]"></span>
+        <span class="icon-[svg-spinners--wind-toy]"></span>
+        <span class="icon-[svg-spinners--blocks-wave]"></span>
+        <span class="icon-[line-md--compass-filled-loop]"></span>
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="鍥炬爣閫夋嫨鍣�">
+      <div class="mb-5 flex items-center gap-5">
+        <span>鍘熷鏍峰紡(Iconify):</span>
+        <IconPicker class="w-[200px]" />
+      </div>
+      <div class="mb-5 flex items-center gap-5">
+        <span>鍘熷鏍峰紡(svg):</span>
+        <IconPicker class="w-[200px]" prefix="svg" />
+      </div>
+      <div class="mb-5 flex items-center gap-5">
+        <span>浣跨敤Input:</span>
+        <IconPicker :input-component="inputComponent" icon-slot="addonAfter" />
+      </div>
+      <div class="flex items-center gap-5">
+        <span>鍙墜鍔ㄨ緭鍏ワ紝鍙兘鐐瑰嚮鍥炬爣鎵撳紑寮圭獥:</span>
+        <Input
+          v-model:value="iconValue"
+          allow-clear
+          placeholder="鐐瑰嚮杩欓噷閫夋嫨鍥炬爣"
+          style="width: 300px"
+        >
+          <template #addonAfter>
+            <IconPicker v-model="iconValue" class="w-[200px]" />
+          </template>
+        </Input>
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/login-expired/index.vue b/eims-ui/playground/src/views/demos/features/login-expired/index.vue
new file mode 100644
index 0000000..532839a
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/login-expired/index.vue
@@ -0,0 +1,39 @@
+<script lang="ts" setup>
+import type { LoginExpiredModeType } from '@vben/types';
+
+import { Page } from '@vben/common-ui';
+import { preferences, updatePreferences } from '@vben/preferences';
+
+import { Button, Card } from 'ant-design-vue';
+
+import { getMockStatusApi } from '#/api';
+
+async function handleClick(type: LoginExpiredModeType) {
+  const loginExpiredMode = preferences.app.loginExpiredMode;
+
+  updatePreferences({ app: { loginExpiredMode: type } });
+  await getMockStatusApi('401');
+  updatePreferences({ app: { loginExpiredMode } });
+}
+</script>
+
+<template>
+  <Page title="鐧诲綍杩囨湡婕旂ず">
+    <template #description>
+      <div class="text-foreground/80 mt-2">
+        鎺ュ彛璇锋眰閬囧埌401鐘舵�佺爜鏃讹紝闇�瑕侀噸鏂扮櫥褰曘�傛湁涓ょ鏂瑰紡锛�
+        <p>1.杞埌鐧诲綍椤碉紝鐧诲綍鎴愬姛鍚庤烦杞洖鍘熼〉闈�</p>
+        <p>
+          2.寮瑰嚭閲嶆柊鐧诲綍寮圭獥锛岀櫥褰曞悗鍏抽棴寮圭獥锛屼笉杩涜浠讳綍椤甸潰璺宠浆锛堝埛鏂板悗杩樻槸浼氳烦杞櫥褰曢〉闈級
+        </p>
+      </div>
+    </template>
+
+    <Card class="mb-5" title="璺宠浆鐧诲綍椤甸潰鏂瑰紡">
+      <Button type="primary" @click="handleClick('page')"> 鐐瑰嚮瑙﹀彂 </Button>
+    </Card>
+    <Card class="mb-5" title="鐧诲綍寮圭獥鏂瑰紡">
+      <Button type="primary" @click="handleClick('modal')"> 鐐瑰嚮瑙﹀彂 </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/menu-query/index.vue b/eims-ui/playground/src/views/demos/features/menu-query/index.vue
new file mode 100644
index 0000000..6943a24
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/menu-query/index.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="鐐瑰嚮鑿滃崟锛屽皢浼氬甫涓婂弬鏁�"
+    status="coming-soon"
+    title="鑿滃崟甯﹀弬绀轰緥"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/new-window/index.vue b/eims-ui/playground/src/views/demos/features/new-window/index.vue
new file mode 100644
index 0000000..68f89d0
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/new-window/index.vue
@@ -0,0 +1,11 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback
+    description="褰撳墠椤甸潰宸插湪鏂扮獥鍙e唴鎵撳紑"
+    status="coming-soon"
+    title="鏂扮獥鍙f墦寮�椤甸潰"
+  />
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/tabs/index.vue b/eims-ui/playground/src/views/demos/features/tabs/index.vue
new file mode 100644
index 0000000..5e7bfa2
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/tabs/index.vue
@@ -0,0 +1,105 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page } from '@vben/common-ui';
+import { useTabs } from '@vben/hooks';
+
+import { Button, Card, Input } from 'ant-design-vue';
+
+const router = useRouter();
+const newTabTitle = ref('');
+
+const {
+  closeAllTabs,
+  closeCurrentTab,
+  closeLeftTabs,
+  closeOtherTabs,
+  closeRightTabs,
+  closeTabByKey,
+  refreshTab,
+  resetTabTitle,
+  setTabTitle,
+} = useTabs();
+
+function openTab() {
+  // 杩欓噷灏辨槸璺敱璺宠浆锛屼篃鍙互鐢╬ath
+  router.push({ name: 'VbenAbout' });
+}
+
+function openTabWithParams(id: number) {
+  // 杩欓噷灏辨槸璺敱璺宠浆锛屼篃鍙互鐢╬ath
+  router.push({ name: 'FeatureTabDetailDemo', params: { id } });
+}
+
+function reset() {
+  newTabTitle.value = '';
+  resetTabTitle();
+}
+</script>
+
+<template>
+  <Page description="鐢ㄤ簬闇�瑕佹搷浣滄爣绛鹃〉鐨勫満鏅�" title="鏍囩椤�">
+    <Card class="mb-5" title="鎵撳紑/鍏抽棴鏍囩椤�">
+      <div class="text-foreground/80 mb-3">
+        濡傛灉鏍囩椤靛瓨鍦紝鐩存帴璺宠浆鍒囨崲銆傚鏋滄爣绛鹃〉涓嶅瓨鍦紝鍒欐墦寮�鏂扮殑鏍囩椤点��
+      </div>
+      <div class="flex flex-wrap gap-3">
+        <Button type="primary" @click="openTab"> 鎵撳紑 "鍏充簬" 鏍囩椤� </Button>
+        <Button type="primary" @click="closeTabByKey('/vben-admin/about')">
+          鍏抽棴 "鍏充簬" 鏍囩椤�
+        </Button>
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="鏍囩椤垫搷浣�">
+      <div class="text-foreground/80 mb-3">鐢ㄤ簬鍔ㄦ�佹帶鍒舵爣绛鹃〉鐨勫悇绉嶆搷浣�</div>
+      <div class="flex flex-wrap gap-3">
+        <Button type="primary" @click="closeCurrentTab()">
+          鍏抽棴褰撳墠鏍囩椤�
+        </Button>
+        <Button type="primary" @click="closeLeftTabs()">
+          鍏抽棴宸︿晶鏍囩椤�
+        </Button>
+        <Button type="primary" @click="closeRightTabs()">
+          鍏抽棴鍙充晶鏍囩椤�
+        </Button>
+        <Button type="primary" @click="closeAllTabs()"> 鍏抽棴鎵�鏈夋爣绛鹃〉 </Button>
+        <Button type="primary" @click="closeOtherTabs()">
+          鍏抽棴鍏朵粬鏍囩椤�
+        </Button>
+        <Button type="primary" @click="refreshTab()"> 鍒锋柊褰撳墠鏍囩椤� </Button>
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="鍔ㄦ�佹爣棰�">
+      <div class="text-foreground/80 mb-3">
+        璇ユ搷浣滀笉浼氬奖鍝嶉〉闈㈡爣棰橈紝浠呬慨鏀筎ab鏍囬
+      </div>
+      <div class="flex flex-wrap items-center gap-3">
+        <Input
+          v-model:value="newTabTitle"
+          class="w-40"
+          placeholder="璇疯緭鍏ユ柊鏍囬"
+        />
+        <Button type="primary" @click="() => setTabTitle(newTabTitle)">
+          淇敼
+        </Button>
+        <Button @click="reset"> 閲嶇疆 </Button>
+      </div>
+    </Card>
+
+    <Card class="mb-5" title="鏈�澶ф墦寮�鏁伴噺">
+      <div class="text-foreground/80 mb-3">
+        闄愬埗甯﹀弬鏁扮殑tab鎵撳紑鐨勬渶澶ф暟閲忥紝鐢� `route.meta.maxNumOfOpenTab` 鎺у埗
+      </div>
+      <div class="flex flex-wrap items-center gap-3">
+        <template v-for="item in 5" :key="item">
+          <Button type="primary" @click="openTabWithParams(item)">
+            鎵撳紑{{ item }}璇︽儏椤�
+          </Button>
+        </template>
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/tabs/tab-detail.vue b/eims-ui/playground/src/views/demos/features/tabs/tab-detail.vue
new file mode 100644
index 0000000..c03b61c
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/tabs/tab-detail.vue
@@ -0,0 +1,23 @@
+<script lang="ts" setup>
+import { computed } from 'vue';
+import { useRoute } from 'vue-router';
+
+import { Page } from '@vben/common-ui';
+import { useTabs } from '@vben/hooks';
+
+const route = useRoute();
+
+const { setTabTitle } = useTabs();
+
+const index = computed(() => {
+  return route.params?.id ?? -1;
+});
+
+setTabTitle(`No.${index.value} - 璇︽儏淇℃伅`);
+</script>
+
+<template>
+  <Page :title="`鏍囩椤�${index}璇︽儏椤礰">
+    <template #description> {{ index }} - 璇︽儏椤靛唴瀹瑰湪姝� </template>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/vue-query/index.vue b/eims-ui/playground/src/views/demos/features/vue-query/index.vue
new file mode 100644
index 0000000..d57cf81
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/vue-query/index.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+import { Page } from '@vben/common-ui';
+
+import { Card } from 'ant-design-vue';
+
+import InfiniteQueries from './infinite-queries.vue';
+import PaginatedQueries from './paginated-queries.vue';
+import QueryRetries from './query-retries.vue';
+</script>
+
+<template>
+  <Page title="Vue Query绀轰緥">
+    <div class="grid grid-cols-1 gap-4 md:grid-cols-2">
+      <Card title="鍒嗛〉鏌ヨ">
+        <PaginatedQueries />
+      </Card>
+      <Card title="鏃犻檺婊氬姩">
+        <InfiniteQueries class="h-[300px] overflow-auto" />
+      </Card>
+      <Card title="閿欒閲嶈瘯">
+        <QueryRetries />
+      </Card>
+    </div>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/vue-query/infinite-queries.vue b/eims-ui/playground/src/views/demos/features/vue-query/infinite-queries.vue
new file mode 100644
index 0000000..2add4c1
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/vue-query/infinite-queries.vue
@@ -0,0 +1,58 @@
+<script setup lang="ts">
+import type { IProducts } from './typing';
+
+import { useInfiniteQuery } from '@tanstack/vue-query';
+import { Button } from 'ant-design-vue';
+
+const LIMIT = 10;
+const fetchProducts = async ({ pageParam = 0 }): Promise<IProducts> => {
+  const res = await fetch(
+    `https://dummyjson.com/products?limit=${LIMIT}&skip=${pageParam * LIMIT}`,
+  );
+  return res.json();
+};
+
+const {
+  data,
+  error,
+  fetchNextPage,
+  hasNextPage,
+  isError,
+  isFetching,
+  isFetchingNextPage,
+  isPending,
+} = useInfiniteQuery({
+  getNextPageParam: (current, allPages) => {
+    const nextPage = allPages.length + 1;
+    const lastPage = current.skip + current.limit;
+    if (lastPage === current.total) return;
+    return nextPage;
+  },
+  initialPageParam: 0,
+  queryFn: fetchProducts,
+  queryKey: ['products'],
+});
+</script>
+
+<template>
+  <div>
+    <span v-if="isPending">鍔犺浇...</span>
+    <span v-else-if="isError">鍑洪敊浜�: {{ error }}</span>
+    <div v-else-if="data">
+      <span v-if="isFetching && !isFetchingNextPage">Fetching...</span>
+      <ul v-for="(group, index) in data.pages" :key="index">
+        <li v-for="product in group.products" :key="product.id">
+          {{ product.title }}
+        </li>
+      </ul>
+      <Button
+        :disabled="!hasNextPage || isFetchingNextPage"
+        @click="() => fetchNextPage()"
+      >
+        <span v-if="isFetchingNextPage">鍔犺浇涓�...</span>
+        <span v-else-if="hasNextPage">鍔犺浇鏇村</span>
+        <span v-else>娌℃湁鏇村浜�</span>
+      </Button>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/vue-query/paginated-queries.vue b/eims-ui/playground/src/views/demos/features/vue-query/paginated-queries.vue
new file mode 100644
index 0000000..b2e3c26
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/vue-query/paginated-queries.vue
@@ -0,0 +1,51 @@
+<script setup lang="ts">
+import type { IProducts } from './typing';
+
+import { type Ref, ref } from 'vue';
+
+import { keepPreviousData, useQuery } from '@tanstack/vue-query';
+import { Button } from 'ant-design-vue';
+
+const LIMIT = 10;
+const fetcher = async (page: Ref<number>): Promise<IProducts> => {
+  const res = await fetch(
+    `https://dummyjson.com/products?limit=${LIMIT}&skip=${(page.value - 1) * LIMIT}`,
+  );
+  return res.json();
+};
+
+const page = ref(1);
+const { data, error, isError, isPending, isPlaceholderData } = useQuery({
+  // The data from the last successful fetch is available while new data is being requested.
+  placeholderData: keepPreviousData,
+  queryFn: () => fetcher(page),
+  queryKey: ['products', page],
+});
+const prevPage = () => {
+  page.value = Math.max(page.value - 1, 1);
+};
+const nextPage = () => {
+  if (!isPlaceholderData.value) {
+    page.value = page.value + 1;
+  }
+};
+</script>
+
+<template>
+  <div class="flex gap-4">
+    <Button size="small" @click="prevPage">涓婁竴椤�</Button>
+    <p>褰撳墠椤�: {{ page }}</p>
+    <Button size="small" @click="nextPage">涓嬩竴椤�</Button>
+  </div>
+  <div class="p-4">
+    <div v-if="isPending">鍔犺浇涓�...</div>
+    <div v-else-if="isError">鍑洪敊浜�: {{ error }}</div>
+    <div v-else-if="data">
+      <ul>
+        <li v-for="item in data.products" :key="item.id">
+          {{ item.title }}
+        </li>
+      </ul>
+    </div>
+  </div>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/vue-query/query-retries.vue b/eims-ui/playground/src/views/demos/features/vue-query/query-retries.vue
new file mode 100644
index 0000000..0080386
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/vue-query/query-retries.vue
@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+
+import { useQuery } from '@tanstack/vue-query';
+import { Button } from 'ant-design-vue';
+
+const count = ref(-1);
+async function fetchApi() {
+  count.value += 1;
+  return new Promise((_resolve, reject) => {
+    setTimeout(() => {
+      reject(new Error('something went wrong!'));
+    }, 1000);
+  });
+}
+
+const { error, isFetching, refetch } = useQuery({
+  enabled: false, // Disable automatic refetching when the query mounts
+  queryFn: fetchApi,
+  queryKey: ['queryKey'],
+  retry: 3, // Will retry failed requests 3 times before displaying an error
+});
+
+const onClick = async () => {
+  count.value = -1;
+  await refetch();
+};
+</script>
+
+<template>
+  <Button :loading="isFetching" @click="onClick"> 鍙戣捣閿欒閲嶈瘯 </Button>
+  <p v-if="count > 0" class="my-3">閲嶈瘯娆℃暟{{ count }}</p>
+  <p>{{ error }}</p>
+</template>
diff --git a/eims-ui/playground/src/views/demos/features/vue-query/typing.ts b/eims-ui/playground/src/views/demos/features/vue-query/typing.ts
new file mode 100644
index 0000000..95558dd
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/vue-query/typing.ts
@@ -0,0 +1,18 @@
+export interface IProducts {
+  limit: number;
+  products: {
+    brand: string;
+    category: string;
+    description: string;
+    discountPercentage: string;
+    id: string;
+    images: string[];
+    price: string;
+    rating: string;
+    stock: string;
+    thumbnail: string;
+    title: string;
+  }[];
+  skip: number;
+  total: number;
+}
diff --git a/eims-ui/playground/src/views/demos/features/watermark/index.vue b/eims-ui/playground/src/views/demos/features/watermark/index.vue
new file mode 100644
index 0000000..77b3f17
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/features/watermark/index.vue
@@ -0,0 +1,86 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+import { useWatermark } from '@vben/hooks';
+
+import { Button, Card } from 'ant-design-vue';
+
+const { destroyWatermark, updateWatermark, watermark } = useWatermark();
+
+async function recreateWaterMark() {
+  destroyWatermark();
+  await updateWatermark({});
+}
+
+async function createWaterMark() {
+  await updateWatermark({
+    advancedStyle: {
+      colorStops: [
+        {
+          color: 'red',
+          offset: 0,
+        },
+        {
+          color: 'blue',
+          offset: 1,
+        },
+      ],
+      type: 'linear',
+    },
+    content: `hello my watermark\n${new Date().toLocaleString()}`,
+    globalAlpha: 0.5,
+    gridLayoutOptions: {
+      cols: 2,
+      gap: [20, 20],
+      matrix: [
+        [1, 0],
+        [0, 1],
+      ],
+      rows: 2,
+    },
+    height: 200,
+    layout: 'grid',
+    rotate: 22,
+    width: 200,
+  });
+}
+</script>
+
+<template>
+  <Page title="姘村嵃">
+    <template #description>
+      <div class="text-foreground/80 mt-2">
+        姘村嵃浣跨敤浜�
+        <a
+          class="text-primary"
+          href="https://zhensherlock.github.io/watermark-js-plus/"
+          target="_blank"
+        >
+          watermark-js-plus
+        </a>
+        寮�婧愭彃浠讹紝璇︾粏閰嶇疆鍙鎻掍欢閰嶇疆銆�
+      </div>
+    </template>
+
+    <Card title="浣跨敤">
+      <Button
+        :disabled="!!watermark"
+        class="mr-2"
+        type="primary"
+        @click="recreateWaterMark"
+      >
+        鍒涘缓姘村嵃
+      </Button>
+      <Button
+        :disabled="!watermark"
+        class="mr-2"
+        type="primary"
+        @click="createWaterMark"
+      >
+        鏇存柊姘村嵃
+      </Button>
+      <Button :disabled="!watermark" danger @click="destroyWatermark">
+        绉婚櫎姘村嵃
+      </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/demos/nested/menu-1.vue b/eims-ui/playground/src/views/demos/nested/menu-1.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/nested/menu-1.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/playground/src/views/demos/nested/menu-2-1.vue b/eims-ui/playground/src/views/demos/nested/menu-2-1.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/nested/menu-2-1.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/playground/src/views/demos/nested/menu-3-1.vue b/eims-ui/playground/src/views/demos/nested/menu-3-1.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/nested/menu-3-1.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/playground/src/views/demos/nested/menu-3-2-1.vue b/eims-ui/playground/src/views/demos/nested/menu-3-2-1.vue
new file mode 100644
index 0000000..f394930
--- /dev/null
+++ b/eims-ui/playground/src/views/demos/nested/menu-3-2-1.vue
@@ -0,0 +1,7 @@
+<script lang="ts" setup>
+import { Fallback } from '@vben/common-ui';
+</script>
+
+<template>
+  <Fallback status="coming-soon" />
+</template>
diff --git a/eims-ui/playground/src/views/examples/captcha/point-selection-captcha.vue b/eims-ui/playground/src/views/examples/captcha/point-selection-captcha.vue
new file mode 100644
index 0000000..ae8ab0a
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/captcha/point-selection-captcha.vue
@@ -0,0 +1,181 @@
+<script lang="ts" setup>
+import type { CaptchaPoint } from '@vben/common-ui';
+
+import { reactive, ref } from 'vue';
+
+import { Page, PointSelectionCaptcha } from '@vben/common-ui';
+
+import { Card, Input, InputNumber, message, Switch } from 'ant-design-vue';
+
+import { $t } from '#/locales';
+
+const DEFAULT_CAPTCHA_IMAGE =
+  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-captcha-image.jpeg';
+
+const DEFAULT_HINT_IMAGE =
+  'https://unpkg.com/@vbenjs/static-source@0.1.7/source/default-hint-image.png';
+
+const selectedPoints = ref<CaptchaPoint[]>([]);
+const params = reactive({
+  captchaImage: '',
+  captchaImageUrl: DEFAULT_CAPTCHA_IMAGE,
+  height: undefined,
+  hintImage: '',
+  hintImageUrl: DEFAULT_HINT_IMAGE,
+  hintText: '鍞囷紝鐕曪紝纰达紝鎵�',
+  paddingX: undefined,
+  paddingY: undefined,
+  showConfirm: true,
+  showHintImage: false,
+  title: '',
+  width: undefined,
+});
+const handleConfirm = (points: CaptchaPoint[], clear: () => void) => {
+  message.success({
+    content: `captcha points: ${JSON.stringify(points)}`,
+  });
+  clear();
+  selectedPoints.value = [];
+};
+const handleRefresh = () => {
+  selectedPoints.value = [];
+};
+const handleClick = (point: CaptchaPoint) => {
+  selectedPoints.value.push(point);
+};
+</script>
+
+<template>
+  <Page
+    :description="$t('examples.captcha.pageDescription')"
+    :title="$t('examples.captcha.pageTitle')"
+  >
+    <Card :title="$t('examples.captcha.basic')" class="mb-4 overflow-x-auto">
+      <div class="mb-3 flex items-center justify-start">
+        <Input
+          v-model:value="params.title"
+          :placeholder="$t('examples.captcha.titlePlaceholder')"
+          class="w-64"
+        />
+        <Input
+          v-model:value="params.captchaImageUrl"
+          :placeholder="$t('examples.captcha.captchaImageUrlPlaceholder')"
+          class="ml-8 w-64"
+        />
+        <div class="ml-8 flex w-96 items-center">
+          <Switch
+            v-model:checked="params.showHintImage"
+            :checked-children="$t('examples.captcha.hintImage')"
+            :un-checked-children="$t('examples.captcha.hintText')"
+            class="mr-4 w-40"
+          />
+          <Input
+            v-show="params.showHintImage"
+            v-model:value="params.hintImageUrl"
+            :placeholder="$t('examples.captcha.hintImagePlaceholder')"
+          />
+          <Input
+            v-show="!params.showHintImage"
+            v-model:value="params.hintText"
+            :placeholder="$t('examples.captcha.hintTextPlaceholder')"
+          />
+        </div>
+
+        <Switch
+          v-model:checked="params.showConfirm"
+          :checked-children="$t('examples.captcha.showConfirm')"
+          :un-checked-children="$t('examples.captcha.hideConfirm')"
+          class="ml-8 w-28"
+        />
+      </div>
+      <div class="mb-3 flex items-center justify-start">
+        <div>
+          <InputNumber
+            v-model:value="params.width"
+            :min="1"
+            :placeholder="$t('examples.captcha.widthPlaceholder')"
+            :precision="0"
+            :step="1"
+            class="w-64"
+          >
+            <template #addonAfter>px</template>
+          </InputNumber>
+        </div>
+        <div class="ml-8">
+          <InputNumber
+            v-model:value="params.height"
+            :min="1"
+            :placeholder="$t('examples.captcha.heightPlaceholder')"
+            :precision="0"
+            :step="1"
+            class="w-64"
+          >
+            <template #addonAfter>px</template>
+          </InputNumber>
+        </div>
+        <div class="ml-8">
+          <InputNumber
+            v-model:value="params.paddingX"
+            :min="1"
+            :placeholder="$t('examples.captcha.paddingXPlaceholder')"
+            :precision="0"
+            :step="1"
+            class="w-64"
+          >
+            <template #addonAfter>px</template>
+          </InputNumber>
+        </div>
+        <div class="ml-8">
+          <InputNumber
+            v-model:value="params.paddingY"
+            :min="1"
+            :placeholder="$t('examples.captcha.paddingYPlaceholder')"
+            :precision="0"
+            :step="1"
+            class="w-64"
+          >
+            <template #addonAfter>px</template>
+          </InputNumber>
+        </div>
+      </div>
+
+      <PointSelectionCaptcha
+        :captcha-image="params.captchaImageUrl || params.captchaImage"
+        :height="params.height || 220"
+        :hint-image="
+          params.showHintImage ? params.hintImageUrl || params.hintImage : ''
+        "
+        :hint-text="params.hintText"
+        :padding-x="params.paddingX"
+        :padding-y="params.paddingY"
+        :show-confirm="params.showConfirm"
+        :width="params.width || 300"
+        class="float-left"
+        @click="handleClick"
+        @confirm="handleConfirm"
+        @refresh="handleRefresh"
+      >
+        <template #title>
+          {{ params.title || $t('examples.captcha.captchaCardTitle') }}
+        </template>
+      </PointSelectionCaptcha>
+
+      <ol class="float-left p-5">
+        <li v-for="point in selectedPoints" :key="point.i" class="flex">
+          <span class="mr-3 w-16">{{
+            $t('examples.captcha.index') + point.i
+          }}</span>
+          <span class="mr-3 w-52">{{
+            $t('examples.captcha.timestamp') + point.t
+          }}</span>
+          <span class="mr-3 w-16">{{
+            $t('examples.captcha.x') + point.x
+          }}</span>
+          <span class="mr-3 w-16">{{
+            $t('examples.captcha.y') + point.y
+          }}</span>
+        </li>
+      </ol>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/captcha/slider-captcha.vue b/eims-ui/playground/src/views/examples/captcha/slider-captcha.vue
new file mode 100644
index 0000000..0a39765
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/captcha/slider-captcha.vue
@@ -0,0 +1,117 @@
+<script lang="ts" setup>
+import type {
+  CaptchaVerifyPassingData,
+  SliderCaptchaActionType,
+} from '@vben/common-ui';
+
+import { ref } from 'vue';
+
+import { Page, SliderCaptcha } from '@vben/common-ui';
+import { Bell, Sun } from '@vben/icons';
+
+import { Button, Card, message } from 'ant-design-vue';
+
+function handleSuccess(data: CaptchaVerifyPassingData) {
+  const { time } = data;
+  message.success(`鏍¢獙鎴愬姛,鑰楁椂${time}绉抈);
+}
+function handleBtnClick(elRef?: SliderCaptchaActionType) {
+  if (!elRef) {
+    return;
+  }
+  elRef.resume();
+}
+
+const el1 = ref<SliderCaptchaActionType>();
+const el2 = ref<SliderCaptchaActionType>();
+const el3 = ref<SliderCaptchaActionType>();
+const el4 = ref<SliderCaptchaActionType>();
+const el5 = ref<SliderCaptchaActionType>();
+const el6 = ref<SliderCaptchaActionType>();
+</script>
+
+<template>
+  <Page description="鐢ㄤ簬鍓嶇绠�鍗曠殑鎷栧姩鏍¢獙鍦烘櫙" title="婊戝潡鏍¢獙">
+    <Card class="mb-5" title="鍩虹绀轰緥">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha ref="el1" @success="handleSuccess" />
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el1)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+    <Card class="mb-5" title="鑷畾涔夊渾瑙�">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha
+          ref="el2"
+          class="rounded-full"
+          @success="handleSuccess"
+        />
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el2)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+    <Card class="mb-5" title="鑷畾涔夎儗鏅壊">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha
+          ref="el3"
+          :bar-style="{
+            backgroundColor: '#018ffb',
+          }"
+          success-text="鏍¢獙鎴愬姛"
+          text="鎷栧姩浠ヨ繘琛屾牎楠�"
+          @success="handleSuccess"
+        />
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el3)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+    <Card class="mb-5" title="鑷畾涔夋嫋鎷藉浘鏍�">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha ref="el4" @success="handleSuccess">
+          <template #actionIcon="{ isPassing }">
+            <Bell v-if="isPassing" />
+            <Sun v-else />
+          </template>
+        </SliderCaptcha>
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el4)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+    <Card class="mb-5" title="鑷畾涔夋枃鏈�">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha
+          ref="el5"
+          success-text="鎴愬姛"
+          text="鎷栧姩"
+          @success="handleSuccess"
+        />
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el5)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+    <Card class="mb-5" title="鑷畾涔夊唴瀹�(slot)">
+      <div class="flex items-center justify-center p-4 px-[30%]">
+        <SliderCaptcha ref="el6" @success="handleSuccess">
+          <template #text="{ isPassing }">
+            <template v-if="isPassing">
+              <Bell class="mr-2 size-4" />
+              鎴愬姛
+            </template>
+            <template v-else>
+              鎷栧姩
+              <Sun class="ml-2 size-4" />
+            </template>
+          </template>
+        </SliderCaptcha>
+        <Button class="ml-2" type="primary" @click="handleBtnClick(el6)">
+          杩樺師
+        </Button>
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/captcha/slider-rotate-captcha.vue b/eims-ui/playground/src/views/examples/captcha/slider-rotate-captcha.vue
new file mode 100644
index 0000000..2377577
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/captcha/slider-rotate-captcha.vue
@@ -0,0 +1,28 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+
+import { Page, SliderRotateCaptcha } from '@vben/common-ui';
+import { preferences } from '@vben/preferences';
+import { useUserStore } from '@vben/stores';
+
+import { Card, message } from 'ant-design-vue';
+
+const userStore = useUserStore();
+function handleSuccess() {
+  message.success('success!');
+}
+
+const avatar = computed(() => {
+  return userStore.userInfo?.avatar || preferences.app.defaultAvatar;
+});
+</script>
+
+<template>
+  <Page description="鐢ㄤ簬鍓嶇绠�鍗曠殑鎷栧姩鏍¢獙鍦烘櫙" title="婊戝潡鏃嬭浆鏍¢獙">
+    <Card class="mb-5" title="鍩烘湰绀轰緥">
+      <div class="flex items-center justify-center p-4">
+        <SliderRotateCaptcha :src="avatar" @success="handleSuccess" />
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/doc-button.vue b/eims-ui/playground/src/views/examples/doc-button.vue
new file mode 100644
index 0000000..529c743
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/doc-button.vue
@@ -0,0 +1,16 @@
+<script lang="ts" setup>
+import { VBEN_DOC_URL } from '@vben/constants';
+import { openWindow } from '@vben/utils';
+
+import { Button } from 'ant-design-vue';
+
+const props = defineProps<{ path: string }>();
+
+function handleClick() {
+  openWindow(VBEN_DOC_URL + props.path);
+}
+</script>
+
+<template>
+  <Button @click="handleClick">鏌ョ湅缁勪欢鏂囨。</Button>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/auto-height-demo.vue b/eims-ui/playground/src/views/examples/drawer/auto-height-demo.vue
new file mode 100644
index 0000000..0c32734
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/auto-height-demo.vue
@@ -0,0 +1,47 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+const list = ref<number[]>([]);
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // drawerApi.close();
+  },
+  onOpenChange(isOpen) {
+    if (isOpen) {
+      handleUpdate(10);
+    }
+  },
+});
+
+function handleUpdate(len: number) {
+  drawerApi.setState({ loading: true });
+  setTimeout(() => {
+    list.value = Array.from({ length: len }, (_v, k) => k + 1);
+    drawerApi.setState({ loading: false });
+  }, 2000);
+}
+</script>
+<template>
+  <Drawer title="鑷姩璁$畻楂樺害">
+    <div
+      v-for="item in list"
+      :key="item"
+      class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
+    >
+      {{ item }}
+    </div>
+
+    <template #prepend-footer>
+      <Button type="link" @click="handleUpdate(6)">鐐瑰嚮鏇存柊鏁版嵁</Button>
+    </template>
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/base-demo.vue b/eims-ui/playground/src/views/examples/drawer/base-demo.vue
new file mode 100644
index 0000000..ffa5e39
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/base-demo.vue
@@ -0,0 +1,24 @@
+<script lang="ts" setup>
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // drawerApi.close();
+  },
+});
+</script>
+<template>
+  <Drawer title="鍩虹鎶藉眽绀轰緥" title-tooltip="鏍囬鎻愮ず鍐呭">
+    <template #extra> extra </template>
+    base demo
+
+    <!-- <template #prepend-footer> slot </template> -->
+    <!-- <template #append-footer> prepend slot </template> -->
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/dynamic-demo.vue b/eims-ui/playground/src/views/examples/drawer/dynamic-demo.vue
new file mode 100644
index 0000000..ce5560f
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/dynamic-demo.vue
@@ -0,0 +1,31 @@
+<script lang="ts" setup>
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // drawerApi.close();
+  },
+  title: '鍔ㄦ�佷慨鏀归厤缃ず渚�',
+});
+
+// const state = drawerApi.useStore();
+
+function handleUpdateTitle() {
+  drawerApi.setState({ title: '鍐呴儴鍔ㄦ�佹爣棰�' });
+}
+</script>
+<template>
+  <Drawer>
+    <div class="flex-col-center">
+      <Button class="mb-3" type="primary" @click="handleUpdateTitle()">
+        鍐呴儴鍔ㄦ�佷慨鏀规爣棰�
+      </Button>
+    </div>
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/form-drawer-demo.vue b/eims-ui/playground/src/views/examples/drawer/form-drawer-demo.vue
new file mode 100644
index 0000000..5af392f
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/form-drawer-demo.vue
@@ -0,0 +1,56 @@
+<script lang="ts" setup>
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { useVbenForm } from '#/adapter/form';
+
+defineOptions({
+  name: 'FormDrawerDemo',
+});
+
+const [Form, formApi] = useVbenForm({
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field1',
+      label: '瀛楁1',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field2',
+      label: '瀛楁2',
+      rules: 'required',
+    },
+  ],
+  showDefaultActions: false,
+});
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm: async () => {
+    await formApi.submitForm();
+    drawerApi.close();
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      const { values } = drawerApi.getData<Record<string, any>>();
+      if (values) {
+        formApi.setValues(values);
+      }
+    }
+  },
+  title: '鍐呭祵琛ㄥ崟绀轰緥',
+});
+</script>
+<template>
+  <Drawer>
+    <Form />
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/in-content-demo.vue b/eims-ui/playground/src/views/examples/drawer/in-content-demo.vue
new file mode 100644
index 0000000..8bc29b2
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/in-content-demo.vue
@@ -0,0 +1,21 @@
+<script lang="ts" setup>
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // drawerApi.close();
+  },
+});
+</script>
+<template>
+  <Drawer append-to-main title="鍩虹鎶藉眽绀轰緥" title-tooltip="鏍囬鎻愮ず鍐呭">
+    <template #extra> extra </template>
+    鏈娊灞夋寚瀹氬湪鍐呭鍖哄煙鎵撳紑
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/index.vue b/eims-ui/playground/src/views/examples/drawer/index.vue
new file mode 100644
index 0000000..32d3c95
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/index.vue
@@ -0,0 +1,188 @@
+<script lang="ts" setup>
+import { type DrawerPlacement, Page, useVbenDrawer } from '@vben/common-ui';
+
+import { Button, Card } from 'ant-design-vue';
+
+import DocButton from '../doc-button.vue';
+import AutoHeightDemo from './auto-height-demo.vue';
+import BaseDemo from './base-demo.vue';
+import DynamicDemo from './dynamic-demo.vue';
+import FormDrawerDemo from './form-drawer-demo.vue';
+import inContentDemo from './in-content-demo.vue';
+import SharedDataDemo from './shared-data-demo.vue';
+
+const [BaseDrawer, baseDrawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: BaseDemo,
+  // placement: 'left',
+});
+
+const [InContentDrawer, inContentDrawerApi] = useVbenDrawer({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: inContentDemo,
+  // placement: 'left',
+});
+
+const [AutoHeightDrawer, autoHeightDrawerApi] = useVbenDrawer({
+  connectedComponent: AutoHeightDemo,
+});
+
+const [DynamicDrawer, dynamicDrawerApi] = useVbenDrawer({
+  connectedComponent: DynamicDemo,
+});
+
+const [SharedDataDrawer, sharedDrawerApi] = useVbenDrawer({
+  connectedComponent: SharedDataDemo,
+});
+
+const [FormDrawer, formDrawerApi] = useVbenDrawer({
+  connectedComponent: FormDrawerDemo,
+});
+
+function openBaseDrawer(placement: DrawerPlacement = 'right') {
+  baseDrawerApi.setState({ placement });
+  baseDrawerApi.open();
+}
+
+function openInContentDrawer(placement: DrawerPlacement = 'right') {
+  inContentDrawerApi.setState({ class: '', placement });
+  if (placement === 'top') {
+    // 椤甸潰椤堕儴鍖哄煙鐨勫眰绾у彧鏈�200锛屾墍浠ヨ缃竴涓綆浜�200鐨勫�硷紝鎶藉眽浠庨《閮ㄦ粦鍑烘潵鐨勬椂鍊欐墠姣旇緝鍚堥��
+    inContentDrawerApi.setState({ zIndex: 199 });
+  } else {
+    inContentDrawerApi.setState({ zIndex: undefined });
+  }
+  inContentDrawerApi.open();
+}
+
+function openMaxContentDrawer() {
+  // 杩欓噷鍙槸鐢ㄦ潵婕旂ず鏂逛究銆傚疄闄呬笂鑷繁浣跨敤鐨勬椂鍊欏彲浠ョ洿鎺ュ皢杩欎簺閰嶇疆鍗歌浇Drawer鐨勫睘鎬ч噷
+  inContentDrawerApi.setState({ class: 'w-full', placement: 'right' });
+  inContentDrawerApi.open();
+}
+
+function openAutoHeightDrawer() {
+  autoHeightDrawerApi.open();
+}
+
+function openDynamicDrawer() {
+  dynamicDrawerApi.open();
+}
+
+function handleUpdateTitle() {
+  dynamicDrawerApi.setState({ title: '澶栭儴鍔ㄦ�佹爣棰�' });
+  dynamicDrawerApi.open();
+}
+
+function openSharedDrawer() {
+  sharedDrawerApi.setData({
+    content: '澶栭儴浼犻�掔殑鏁版嵁 content',
+    payload: '澶栭儴浼犻�掔殑鏁版嵁 payload',
+  });
+  sharedDrawerApi.open();
+}
+
+function openFormDrawer() {
+  formDrawerApi.setData({
+    // 琛ㄥ崟鍊�
+    values: { field1: 'abc', field2: '123' },
+  });
+  formDrawerApi.open();
+}
+</script>
+
+<template>
+  <Page
+    auto-content-height
+    description="鎶藉眽缁勪欢閫氬父鐢ㄤ簬鍦ㄥ綋鍓嶉〉闈笂鏄剧ず涓�涓鐩栧眰锛岀敤浠ュ睍绀洪噸瑕佷俊鎭垨鎻愪緵鐢ㄦ埛浜や簰鐣岄潰銆�"
+    title="鎶藉眽缁勪欢绀轰緥"
+  >
+    <template #extra>
+      <DocButton path="/components/common-ui/vben-drawer" />
+    </template>
+    <BaseDrawer />
+    <InContentDrawer />
+    <AutoHeightDrawer />
+    <DynamicDrawer />
+    <SharedDataDrawer />
+    <FormDrawer />
+
+    <Card class="mb-4" title="鍩烘湰浣跨敤">
+      <p class="mb-3">涓�涓熀纭�鐨勬娊灞夌ず渚�</p>
+      <Button class="mb-2" type="primary" @click="openBaseDrawer('right')">
+        鍙充晶鎵撳紑
+      </Button>
+      <Button
+        class="mb-2 ml-2"
+        type="primary"
+        @click="openBaseDrawer('bottom')"
+      >
+        搴曢儴鎵撳紑
+      </Button>
+      <Button class="mb-2 ml-2" type="primary" @click="openBaseDrawer('left')">
+        宸︿晶鎵撳紑
+      </Button>
+      <Button class="mb-2 ml-2" type="primary" @click="openBaseDrawer('top')">
+        椤堕儴鎵撳紑
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="鍦ㄥ唴瀹瑰尯鍩熸墦寮�">
+      <p class="mb-3">鎸囧畾鎶藉眽鍦ㄥ唴瀹瑰尯鍩熸墦寮�锛屼笉浼氳鐩栭《閮ㄥ拰宸︿晶鑿滃崟绛夊尯鍩�</p>
+      <Button class="mb-2" type="primary" @click="openInContentDrawer('right')">
+        鍙充晶鎵撳紑
+      </Button>
+      <Button
+        class="mb-2 ml-2"
+        type="primary"
+        @click="openInContentDrawer('bottom')"
+      >
+        搴曢儴鎵撳紑
+      </Button>
+      <Button
+        class="mb-2 ml-2"
+        type="primary"
+        @click="openInContentDrawer('left')"
+      >
+        宸︿晶鎵撳紑
+      </Button>
+      <Button
+        class="mb-2 ml-2"
+        type="primary"
+        @click="openInContentDrawer('top')"
+      >
+        椤堕儴鎵撳紑
+      </Button>
+      <Button class="mb-2 ml-2" type="primary" @click="openMaxContentDrawer">
+        鍐呭鍖哄煙鍏ㄥ睆鎵撳紑
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="鍐呭楂樺害鑷�傚簲婊氬姩">
+      <p class="mb-3">鍙牴鎹唴瀹硅嚜鍔ㄨ绠楁粴鍔ㄩ珮搴�</p>
+      <Button type="primary" @click="openAutoHeightDrawer">鎵撳紑鎶藉眽</Button>
+    </Card>
+
+    <Card class="mb-4" title="鍔ㄦ�侀厤缃ず渚�">
+      <p class="mb-3">閫氳繃 setState 鍔ㄦ�佽皟鏁存娊灞夋暟鎹�</p>
+      <Button type="primary" @click="openDynamicDrawer">鎵撳紑鎶藉眽</Button>
+      <Button class="ml-2" type="primary" @click="handleUpdateTitle">
+        浠庡閮ㄤ慨鏀规爣棰樺苟鎵撳紑
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="鍐呭鏁版嵁鍏变韩绀轰緥">
+      <p class="mb-3">閫氳繃鍏变韩 sharedData 鏉ヨ繘琛屾暟鎹氦浜�</p>
+      <Button type="primary" @click="openSharedDrawer">
+        鎵撳紑鎶藉眽骞朵紶閫掓暟鎹�
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="琛ㄥ崟鎶藉眽绀轰緥">
+      <p class="mb-3">鎵撳紑鎶藉眽骞惰缃〃鍗晄chema浠ュ強鏁版嵁</p>
+      <Button type="primary" @click="openFormDrawer">
+        鎵撳紑鎶藉眽骞惰缃〃鍗晄chema浠ュ強鏁版嵁
+      </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/drawer/shared-data-demo.vue b/eims-ui/playground/src/views/examples/drawer/shared-data-demo.vue
new file mode 100644
index 0000000..d542273
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/drawer/shared-data-demo.vue
@@ -0,0 +1,29 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const data = ref();
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  onCancel() {
+    drawerApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // drawerApi.close();
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      data.value = drawerApi.getData<Record<string, any>>();
+    }
+  },
+});
+</script>
+<template>
+  <Drawer title="鏁版嵁鍏变韩绀轰緥">
+    <div class="flex-col-center">澶栭儴浼犻�掓暟鎹細 {{ data }}</div>
+  </Drawer>
+</template>
diff --git a/eims-ui/playground/src/views/examples/ellipsis/index.vue b/eims-ui/playground/src/views/examples/ellipsis/index.vue
new file mode 100644
index 0000000..ff5066f
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/ellipsis/index.vue
@@ -0,0 +1,41 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { EllipsisText, Page } from '@vben/common-ui';
+
+import { Card } from 'ant-design-vue';
+
+const longText = `Vben Admin 鏄竴涓熀浜� Vue3.0銆乂ite銆� TypeScript 鐨勫悗鍙拌В鍐虫柟妗堬紝鐩爣鏄负寮�鍙戜腑澶у瀷椤圭洰鎻愪緵寮�绠卞嵆鐢ㄧ殑瑙e喅鏂规銆傚寘鎷簩娆″皝瑁呯粍浠躲�乽tils銆乭ooks銆佸姩鎬佽彍鍗曘�佹潈闄愭牎楠屻�佸涓婚閰嶇疆銆佹寜閽骇鍒潈闄愭帶鍒剁瓑鍔熻兘銆傞」鐩細浣跨敤鍓嶇杈冩柊鐨勬妧鏈爤锛屽彲浠ヤ綔涓洪」鐩殑鍚姩妯$増锛屼互甯姪浣犲揩閫熸惌寤轰紒涓氱骇涓悗鍙颁骇鍝佸師鍨嬨�備篃鍙互浣滀负涓�涓ず渚嬶紝鐢ㄤ簬瀛︿範 vue3銆乿ite銆乼s 绛変富娴佹妧鏈�傝椤圭洰浼氭寔缁窡杩涙渶鏂版妧鏈紝骞跺皢鍏跺簲鐢ㄥ湪椤圭洰涓�俈ben Admin 鏄竴涓熀浜� Vue3.0銆乂ite銆� TypeScript 鐨勫悗鍙拌В鍐虫柟妗堬紝鐩爣鏄负寮�鍙戜腑澶у瀷椤圭洰鎻愪緵寮�绠卞嵆鐢ㄧ殑瑙e喅鏂规銆傚寘鎷簩娆″皝瑁呯粍浠躲�乽tils銆乭ooks銆佸姩鎬佽彍鍗曘�佹潈闄愭牎楠屻�佸涓婚閰嶇疆銆佹寜閽骇鍒潈闄愭帶鍒剁瓑鍔熻兘銆傞」鐩細浣跨敤鍓嶇杈冩柊鐨勬妧鏈爤锛屽彲浠ヤ綔涓洪」鐩殑鍚姩妯$増锛屼互甯姪浣犲揩閫熸惌寤轰紒涓氱骇涓悗鍙颁骇鍝佸師鍨嬨�備篃鍙互浣滀负涓�涓ず渚嬶紝鐢ㄤ簬瀛︿範 vue3銆乿ite銆乼s 绛変富娴佹妧鏈�傝椤圭洰浼氭寔缁窡杩涙渶鏂版妧鏈紝骞跺皢鍏跺簲鐢ㄥ湪椤圭洰涓�俈ben Admin 鏄竴涓熀浜� Vue3.0銆乂ite銆� TypeScript 鐨勫悗鍙拌В鍐虫柟妗堬紝鐩爣鏄负寮�鍙戜腑澶у瀷椤圭洰鎻愪緵寮�绠卞嵆鐢ㄧ殑瑙e喅鏂规銆傚寘鎷簩娆″皝瑁呯粍浠躲�乽tils銆乭ooks銆佸姩鎬佽彍鍗曘�佹潈闄愭牎楠屻�佸涓婚閰嶇疆銆佹寜閽骇鍒潈闄愭帶鍒剁瓑鍔熻兘銆傞」鐩細浣跨敤鍓嶇杈冩柊鐨勬妧鏈爤锛屽彲浠ヤ綔涓洪」鐩殑鍚姩妯$増锛屼互甯姪浣犲揩閫熸惌寤轰紒涓氱骇涓悗鍙颁骇鍝佸師鍨嬨�備篃鍙互浣滀负涓�涓ず渚嬶紝鐢ㄤ簬瀛︿範 vue3銆乿ite銆乼s 绛変富娴佹妧鏈�傝椤圭洰浼氭寔缁窡杩涙渶鏂版妧鏈紝骞跺皢鍏跺簲鐢ㄥ湪椤圭洰涓�俈ben Admin 鏄竴涓熀浜� Vue3.0銆乂ite銆� TypeScript 鐨勫悗鍙拌В鍐虫柟妗堬紝鐩爣鏄负寮�鍙戜腑澶у瀷椤圭洰鎻愪緵寮�绠卞嵆鐢ㄧ殑瑙e喅鏂规銆傚寘鎷簩娆″皝瑁呯粍浠躲�乽tils銆乭ooks銆佸姩鎬佽彍鍗曘�佹潈闄愭牎楠屻�佸涓婚閰嶇疆銆佹寜閽骇鍒潈闄愭帶鍒剁瓑鍔熻兘銆傞」鐩細浣跨敤鍓嶇杈冩柊鐨勬妧鏈爤锛屽彲浠ヤ綔涓洪」鐩殑鍚姩妯$増锛屼互甯姪浣犲揩閫熸惌寤轰紒涓氱骇涓悗鍙颁骇鍝佸師鍨嬨�備篃鍙互浣滀负涓�涓ず渚嬶紝鐢ㄤ簬瀛︿範 vue3銆乿ite銆乼s 绛変富娴佹妧鏈�傝椤圭洰浼氭寔缁窡杩涙渶鏂版妧鏈紝骞跺皢鍏跺簲鐢ㄥ湪椤圭洰涓�俙;
+
+const text = ref(longText);
+</script>
+
+<template>
+  <Page
+    description="鐢ㄤ簬澶氳鏂囨湰鐪佺暐锛屾敮鎸佺偣鍑诲睍寮�鍜岃嚜瀹氫箟鍐呭銆�"
+    title="鏂囨湰鐪佺暐缁勪欢绀轰緥"
+  >
+    <Card class="mb-4" title="鍩烘湰浣跨敤">
+      <EllipsisText :max-width="500">{{ text }}</EllipsisText>
+    </Card>
+
+    <Card class="mb-4" title="澶氳鐪佺暐">
+      <EllipsisText :line="2">{{ text }}</EllipsisText>
+    </Card>
+
+    <Card class="mb-4" title="鐐瑰嚮灞曞紑">
+      <EllipsisText :line="3" expand>{{ text }}</EllipsisText>
+    </Card>
+    <Card class="mb-4" title="鑷畾涔夊唴瀹�">
+      <EllipsisText :max-width="240">
+        浣忓湪鎴戝績閲屽鐙殑 瀛ょ嫭鐨勬捣鎬� 鐥涜嫤涔嬬帇 寮�濮嬪帉鍊� 娣辨捣鐨勫厜 鍋滄粸鐨勬捣娴�
+        <template #tooltip>
+          <div style="text-align: center">
+            銆婄Е鐨囧矝銆�<br />浣忓湪鎴戝績閲屽鐙殑<br />瀛ょ嫭鐨勬捣鎬� 鐥涜嫤涔嬬帇<br />寮�濮嬪帉鍊�
+            娣辨捣鐨勫厜 鍋滄粸鐨勬捣娴�
+          </div>
+        </template>
+      </EllipsisText>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/api.vue b/eims-ui/playground/src/views/examples/form/api.vue
new file mode 100644
index 0000000..02abfce
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/api.vue
@@ -0,0 +1,265 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message, Space } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const isReverseActionButtons = ref(false);
+
+const [BaseForm, formApi] = useVbenForm({
+  // 缈昏浆鎿嶄綔鎸夐挳鐨勪綅缃�
+  actionButtonsReverse: isReverseActionButtons.value,
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 浣跨敤 tailwindcss grid甯冨眬
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  layout: 'horizontal',
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'field1',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field2',
+      label: 'field2',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'fieldOptions',
+      label: '涓嬫媺閫�',
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+
+function handleClick(
+  action:
+    | 'batchAddSchema'
+    | 'batchDeleteSchema'
+    | 'disabled'
+    | 'hiddenAction'
+    | 'hiddenResetButton'
+    | 'hiddenSubmitButton'
+    | 'labelWidth'
+    | 'resetDisabled'
+    | 'resetLabelWidth'
+    | 'reverseActionButtons'
+    | 'showAction'
+    | 'showResetButton'
+    | 'showSubmitButton'
+    | 'updateActionAlign'
+    | 'updateResetButton'
+    | 'updateSchema'
+    | 'updateSubmitButton',
+) {
+  switch (action) {
+    case 'batchAddSchema': {
+      formApi.setState((prev) => {
+        const currentSchema = prev?.schema ?? [];
+        const newSchema = [];
+        for (let i = 0; i < 3; i++) {
+          newSchema.push({
+            component: 'Input',
+            componentProps: {
+              placeholder: '璇疯緭鍏�',
+            },
+            fieldName: `field${i}${Date.now()}`,
+            label: `field+`,
+          });
+        }
+        return {
+          schema: [...currentSchema, ...newSchema],
+        };
+      });
+      break;
+    }
+
+    case 'batchDeleteSchema': {
+      formApi.setState((prev) => {
+        const currentSchema = prev?.schema ?? [];
+        return {
+          schema: currentSchema.slice(0, -3),
+        };
+      });
+      break;
+    }
+    case 'disabled': {
+      formApi.setState({ commonConfig: { disabled: true } });
+      break;
+    }
+    case 'hiddenAction': {
+      formApi.setState({ showDefaultActions: false });
+      break;
+    }
+    case 'hiddenResetButton': {
+      formApi.setState({ resetButtonOptions: { show: false } });
+      break;
+    }
+    case 'hiddenSubmitButton': {
+      formApi.setState({ submitButtonOptions: { show: false } });
+      break;
+    }
+    case 'labelWidth': {
+      formApi.setState({
+        commonConfig: {
+          labelWidth: 150,
+        },
+      });
+      break;
+    }
+    case 'resetDisabled': {
+      formApi.setState({ commonConfig: { disabled: false } });
+      break;
+    }
+    case 'resetLabelWidth': {
+      formApi.setState({
+        commonConfig: {
+          labelWidth: 100,
+        },
+      });
+      break;
+    }
+    case 'reverseActionButtons': {
+      isReverseActionButtons.value = !isReverseActionButtons.value;
+      formApi.setState({ actionButtonsReverse: isReverseActionButtons.value });
+      break;
+    }
+    case 'showAction': {
+      formApi.setState({ showDefaultActions: true });
+      break;
+    }
+    case 'showResetButton': {
+      formApi.setState({ resetButtonOptions: { show: true } });
+      break;
+    }
+    case 'showSubmitButton': {
+      formApi.setState({ submitButtonOptions: { show: true } });
+      break;
+    }
+    case 'updateActionAlign': {
+      formApi.setState({
+        // 鍙互鑷璋冩暣class
+        actionWrapperClass: 'text-center',
+      });
+      break;
+    }
+
+    case 'updateResetButton': {
+      formApi.setState({
+        resetButtonOptions: { disabled: true },
+      });
+      break;
+    }
+    case 'updateSchema': {
+      formApi.updateSchema([
+        {
+          componentProps: {
+            options: [
+              {
+                label: '閫夐」1',
+                value: '1',
+              },
+              {
+                label: '閫夐」2',
+                value: '2',
+              },
+              {
+                label: '閫夐」3',
+                value: '3',
+              },
+            ],
+          },
+          fieldName: 'fieldOptions',
+        },
+      ]);
+      message.success('瀛楁 `fieldOptions` 涓嬫媺閫夐」鏇存柊鎴愬姛銆�');
+      break;
+    }
+    case 'updateSubmitButton': {
+      formApi.setState({
+        submitButtonOptions: { loading: true },
+      });
+      break;
+    }
+  }
+}
+</script>
+
+<template>
+  <Page description="琛ㄥ崟缁勪欢api鎿嶄綔绀轰緥銆�" title="琛ㄥ崟缁勪欢">
+    <Space class="mb-5 flex-wrap">
+      <Button @click="handleClick('updateSchema')">updateSchema</Button>
+      <Button @click="handleClick('labelWidth')">鏇存敼labelWidth</Button>
+      <Button @click="handleClick('resetLabelWidth')">杩樺師labelWidth</Button>
+      <Button @click="handleClick('disabled')">绂佺敤琛ㄥ崟</Button>
+      <Button @click="handleClick('resetDisabled')">瑙i櫎绂佺敤</Button>
+      <Button @click="handleClick('reverseActionButtons')">
+        缈昏浆鎿嶄綔鎸夐挳浣嶇疆
+      </Button>
+      <Button @click="handleClick('hiddenAction')">闅愯棌鎿嶄綔鎸夐挳</Button>
+      <Button @click="handleClick('showAction')">鏄剧ず鎿嶄綔鎸夐挳</Button>
+      <Button @click="handleClick('hiddenResetButton')">闅愯棌閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('showResetButton')">鏄剧ず閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('hiddenSubmitButton')">闅愯棌鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('showSubmitButton')">鏄剧ず鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('updateResetButton')">淇敼閲嶇疆鎸夐挳</Button>
+      <Button @click="handleClick('updateSubmitButton')">淇敼鎻愪氦鎸夐挳</Button>
+      <Button @click="handleClick('updateActionAlign')">
+        璋冩暣鎿嶄綔鎸夐挳浣嶇疆
+      </Button>
+      <Button @click="handleClick('batchAddSchema')"> 鎵归噺娣诲姞琛ㄥ崟椤� </Button>
+      <Button @click="handleClick('batchDeleteSchema')">
+        鎵归噺鍒犻櫎琛ㄥ崟椤�
+      </Button>
+    </Space>
+    <Card title="鎿嶄綔绀轰緥">
+      <BaseForm />
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/basic.vue b/eims-ui/playground/src/views/examples/form/basic.vue
new file mode 100644
index 0000000..959aa26
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/basic.vue
@@ -0,0 +1,407 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message, TabPane, Tabs } from 'ant-design-vue';
+import dayjs from 'dayjs';
+
+import { useVbenForm } from '#/adapter/form';
+import { getAllMenusApi } from '#/api';
+
+import DocButton from '../doc-button.vue';
+
+const activeTab = ref('basic');
+
+const [BaseForm, baseFormApi] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  fieldMappingTime: [['rangePicker', ['startTime', 'endTime'], 'YYYY-MM-DD']],
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'username',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楃涓�',
+    },
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'ApiSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        afterFetch: (data: { name: string; path: string }[]) => {
+          return data.map((item: any) => ({
+            label: item.name,
+            value: item.path,
+          }));
+        },
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+      },
+      // 瀛楁鍚�
+      fieldName: 'api',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiSelect',
+    },
+    {
+      component: 'ApiTreeSelect',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        // 鑿滃崟鎺ュ彛
+        api: getAllMenusApi,
+        childrenField: 'children',
+        // 鑿滃崟鎺ュ彛杞琽ptions鏍煎紡
+        labelField: 'name',
+        valueField: 'path',
+      },
+      // 瀛楁鍚�
+      fieldName: 'apiTree',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: 'ApiTreeSelect',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏ュ瘑鐮�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧(甯﹀悗缂�)',
+      suffix: () => '楼',
+    },
+    {
+      component: 'IconPicker',
+      fieldName: 'icon',
+      label: '鍥炬爣',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+    },
+    {
+      component: 'RadioGroup',
+      componentProps: {
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'radioGroup',
+      label: '鍗曢�夌粍',
+    },
+    {
+      component: 'Radio',
+      fieldName: 'radio',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['Radio'],
+        };
+      },
+    },
+    {
+      component: 'CheckboxGroup',
+      componentProps: {
+        name: 'cname',
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'checkboxGroup',
+      label: '澶氶�夌粍',
+    },
+    {
+      component: 'Checkbox',
+      fieldName: 'checkbox',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['鎴戝凡闃呰骞跺悓鎰�'],
+        };
+      },
+    },
+    {
+      component: 'Mentions',
+      componentProps: {
+        options: [
+          {
+            label: 'afc163',
+            value: 'afc163',
+          },
+          {
+            label: 'zombieJ',
+            value: 'zombieJ',
+          },
+        ],
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'mentions',
+      label: '鎻愬強',
+    },
+    {
+      component: 'Rate',
+      fieldName: 'rate',
+      label: '璇勫垎',
+    },
+    {
+      component: 'Switch',
+      componentProps: {
+        class: 'w-auto',
+      },
+      fieldName: 'switch',
+      label: '寮�鍏�',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+    },
+    {
+      component: 'RangePicker',
+      fieldName: 'rangePicker',
+      label: '鑼冨洿閫夋嫨鍣�',
+    },
+    {
+      component: 'TimePicker',
+      fieldName: 'timePicker',
+      label: '鏃堕棿閫夋嫨妗�',
+    },
+    {
+      component: 'TreeSelect',
+      componentProps: {
+        allowClear: true,
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: [
+          {
+            label: 'root 1',
+            value: 'root 1',
+            children: [
+              {
+                label: 'parent 1',
+                value: 'parent 1',
+                children: [
+                  {
+                    label: 'parent 1-0',
+                    value: 'parent 1-0',
+                    children: [
+                      {
+                        label: 'my leaf',
+                        value: 'leaf1',
+                      },
+                      {
+                        label: 'your leaf',
+                        value: 'leaf2',
+                      },
+                    ],
+                  },
+                  {
+                    label: 'parent 1-1',
+                    value: 'parent 1-1',
+                  },
+                ],
+              },
+              {
+                label: 'parent 2',
+                value: 'parent 2',
+              },
+            ],
+          },
+        ],
+        treeNodeFilterProp: 'label',
+      },
+      fieldName: 'treeSelect',
+      label: '鏍戦�夋嫨',
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+const [CustomLayoutForm] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  layout: 'horizontal',
+  schema: [
+    {
+      component: 'Select',
+      fieldName: 'field1',
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'TreeSelect',
+      fieldName: 'field2',
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'Mentions',
+      fieldName: 'field3',
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field4',
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'InputNumber',
+      fieldName: 'field5',
+      // 浠庣涓夊垪寮�濮� 鐩稿綋浜庝腑闂寸┖浜嗕竴鍒�
+      formItemClass: 'col-start-3',
+      label: '鍓嶉潰绌轰簡涓�鍒�',
+    },
+    {
+      component: 'Textarea',
+      fieldName: 'field6',
+      // 鍗犳弧涓夊垪绌洪棿 鍩虹嚎瀵归綈
+      formItemClass: 'col-span-3 items-baseline',
+      label: '鍗犳弧涓夊垪',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field7',
+      // 鍗犳弧2鍒楃┖闂� 浠庣浜屽垪寮�濮� 鐩稿綋浜庡墠闈㈢┖浜嗕竴鍒�
+      formItemClass: 'col-span-2 col-start-2',
+      label: '鍗犳弧2鍒�',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field8',
+      // 宸﹀彸鐣欑┖
+      formItemClass: 'col-start-2',
+      label: '宸﹀彸鐣欑┖',
+    },
+    {
+      component: 'InputPassword',
+      fieldName: 'field9',
+      formItemClass: 'col-start-1',
+      label: '瀛楃涓�',
+    },
+  ],
+  // 涓�鍏变笁鍒�
+  wrapperClass: 'grid-cols-3',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+
+function handleSetFormValue() {
+  /**
+   * 璁剧疆琛ㄥ崟鍊�(澶氫釜)
+   */
+  baseFormApi.setValues({
+    checkboxGroup: ['1'],
+    datePicker: dayjs('2022-01-01'),
+    mentions: '@afc163',
+    number: 3,
+    options: '1',
+    password: '2',
+    radioGroup: '1',
+    rangePicker: [dayjs('2022-01-01'), dayjs('2022-01-02')],
+    rate: 3,
+    switch: true,
+    timePicker: dayjs('2022-01-01 12:00:00'),
+    treeSelect: 'leaf1',
+    username: '1',
+  });
+
+  // 璁剧疆鍗曚釜琛ㄥ崟鍊�
+  baseFormApi.setFieldValue('checkbox', true);
+}
+</script>
+
+<template>
+  <Page
+    content-class="flex flex-col gap-4"
+    description="琛ㄥ崟缁勪欢鍩虹绀轰緥锛岃娉ㄦ剰锛岃椤甸潰鐢ㄥ埌鐨勫弬鏁颁唬鐮佷細娣诲姞涓�浜涚畝鍗曟敞閲婏紝鏂逛究鐞嗚В锛岃浠旂粏鏌ョ湅銆�"
+    header-class="pb-0"
+    title="琛ㄥ崟缁勪欢"
+  >
+    <template #description>
+      <div class="text-muted-foreground">
+        <p>
+          琛ㄥ崟缁勪欢鍩虹绀轰緥锛岃娉ㄦ剰锛岃椤甸潰鐢ㄥ埌鐨勫弬鏁颁唬鐮佷細娣诲姞涓�浜涚畝鍗曟敞閲婏紝鏂逛究鐞嗚В锛岃浠旂粏鏌ョ湅銆�
+        </p>
+      </div>
+      <Tabs v-model:active-key="activeTab" :tab-bar-style="{ marginBottom: 0 }">
+        <TabPane key="basic" tab="鍩虹绀轰緥" />
+        <TabPane key="layout" tab="鑷畾涔夊竷灞�" />
+      </Tabs>
+    </template>
+    <template #extra>
+      <DocButton path="/components/common-ui/vben-form" />
+    </template>
+    <Card v-show="activeTab === 'basic'" title="鍩虹绀轰緥">
+      <template #extra>
+        <Button type="primary" @click="handleSetFormValue">璁剧疆琛ㄥ崟鍊�</Button>
+      </template>
+      <BaseForm />
+    </Card>
+    <Card v-show="activeTab === 'layout'" title="浣跨敤tailwind鑷畾涔夊竷灞�">
+      <CustomLayoutForm />
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/custom.vue b/eims-ui/playground/src/views/examples/form/custom.vue
new file mode 100644
index 0000000..a035e59
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/custom.vue
@@ -0,0 +1,75 @@
+<script lang="ts" setup>
+import { h } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Card, Input, message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [Form] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+    labelClass: 'w-2/6',
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      fieldName: 'field',
+      label: '鑷畾涔夊悗缂�',
+      suffix: () => h('span', { class: 'text-red-600' }, '鍏�'),
+    },
+    {
+      component: 'Input',
+      fieldName: 'field1',
+      label: '鑷畾涔夌粍浠秙lot',
+      renderComponentContent: () => ({
+        prefix: () => 'prefix',
+        suffix: () => 'suffix',
+      }),
+    },
+    {
+      component: h(Input, { placeholder: '璇疯緭鍏�' }),
+      fieldName: 'field2',
+      label: '鑷畾涔夌粍浠�',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field3',
+      label: '鑷畾涔夌粍浠�(slot)',
+      rules: 'required',
+    },
+  ],
+  // 涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Page description="琛ㄥ崟缁勪欢鑷畾涔夌ず渚�" title="琛ㄥ崟缁勪欢">
+    <Card title="鍩虹绀轰緥">
+      <Form>
+        <template #field3="slotProps">
+          <Input placeholder="璇疯緭鍏�" v-bind="slotProps" />
+        </template>
+      </Form>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/dynamic.vue b/eims-ui/playground/src/views/examples/form/dynamic.vue
new file mode 100644
index 0000000..c11a3c1
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/dynamic.vue
@@ -0,0 +1,262 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [Form, formApi] = useVbenForm({
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  schema: [
+    {
+      component: 'Input',
+      defaultValue: 'hidden value',
+      dependencies: {
+        show: false,
+        // 闅忔剰涓�涓瓧娈垫敼鍙樻椂锛岄兘浼氳Е鍙�
+        triggerFields: ['field1Switch'],
+      },
+      fieldName: 'hiddenField',
+      label: '闅愯棌瀛楁',
+    },
+    {
+      component: 'Switch',
+      defaultValue: true,
+      fieldName: 'field1Switch',
+      help: '閫氳繃Dom鎺у埗閿�姣�',
+      label: '鏄剧ず瀛楁1',
+    },
+    {
+      component: 'Switch',
+      defaultValue: true,
+      fieldName: 'field2Switch',
+      help: '閫氳繃css鎺у埗闅愯棌',
+      label: '鏄剧ず瀛楁2',
+    },
+    {
+      component: 'Switch',
+      fieldName: 'field3Switch',
+      label: '绂佺敤瀛楁3',
+    },
+    {
+      component: 'Switch',
+      fieldName: 'field4Switch',
+      label: '瀛楁4蹇呭~',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        if(values) {
+          return !!values.field1Switch;
+        },
+        // 鍙湁鎸囧畾鐨勫瓧娈垫敼鍙樻椂锛屾墠浼氳Е鍙�
+        triggerFields: ['field1Switch'],
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁1',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        show(values) {
+          return !!values.field2Switch;
+        },
+        triggerFields: ['field2Switch'],
+      },
+      fieldName: 'field2',
+      label: '瀛楁2',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        disabled(values) {
+          return !!values.field3Switch;
+        },
+        triggerFields: ['field3Switch'],
+      },
+      fieldName: 'field3',
+      label: '瀛楁3',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        required(values) {
+          return !!values.field4Switch;
+        },
+        triggerFields: ['field4Switch'],
+      },
+      fieldName: 'field4',
+      label: '瀛楁4',
+    },
+    {
+      component: 'Input',
+      dependencies: {
+        rules(values) {
+          if (values.field1 === '123') {
+            return 'required';
+          }
+          return null;
+        },
+        triggerFields: ['field1'],
+      },
+      fieldName: 'field5',
+      help: '褰撳瓧娈�1鐨勫�间负`123`鏃讹紝蹇呭~',
+      label: '鍔ㄦ�乺ules',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        class: 'w-full',
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      dependencies: {
+        componentProps(values) {
+          if (values.field2 === '123') {
+            return {
+              options: [
+                {
+                  label: '閫夐」1',
+                  value: '1',
+                },
+                {
+                  label: '閫夐」2',
+                  value: '2',
+                },
+                {
+                  label: '閫夐」3',
+                  value: '3',
+                },
+              ],
+            };
+          }
+          return {};
+        },
+        triggerFields: ['field2'],
+      },
+      fieldName: 'field6',
+      help: '褰撳瓧娈�2鐨勫�间负`123`鏃讹紝鏇存敼涓嬫媺閫夐」',
+      label: '鍔ㄦ�侀厤缃�',
+    },
+    {
+      component: 'Input',
+      fieldName: 'field7',
+      label: '瀛楁7',
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-3 lg:grid-cols-4',
+});
+
+const [SyncForm] = useVbenForm({
+  handleSubmit: onSubmit,
+  schema: [
+    {
+      component: 'Input',
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁1',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        disabled: true,
+      },
+      dependencies: {
+        trigger(values, form) {
+          form.setFieldValue('field2', values.field1);
+        },
+        // 鍙湁鎸囧畾鐨勫瓧娈垫敼鍙樻椂锛屾墠浼氳Е鍙�
+        triggerFields: ['field1'],
+      },
+      // 瀛楁鍚�
+      fieldName: 'field2',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁2',
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-3 lg:grid-cols-4',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+
+function handleDelete() {
+  formApi.setState((prev) => {
+    return {
+      schema: prev.schema?.filter((item) => item.fieldName !== 'field7'),
+    };
+  });
+}
+
+function handleAdd() {
+  formApi.setState((prev) => {
+    return {
+      schema: [
+        ...(prev?.schema ?? []),
+        {
+          component: 'Input',
+          fieldName: `field${Date.now()}`,
+          label: '瀛楁+',
+        },
+      ],
+    };
+  });
+}
+
+function handleUpdate() {
+  formApi.setState((prev) => {
+    return {
+      schema: prev.schema?.map((item) => {
+        if (item.fieldName === 'field3') {
+          return {
+            ...item,
+            label: '瀛楁3-淇敼',
+          };
+        }
+        return item;
+      }),
+    };
+  });
+}
+</script>
+
+<template>
+  <Page
+    description="琛ㄥ崟缁勪欢鍔ㄦ�佽仈鍔ㄧず渚嬶紝鍖呭惈浜嗗父鐢ㄧ殑鍦烘櫙銆傚鍒犳敼锛屾湰璐ㄤ笂鏄慨鏀箂chema锛屼綘涔熷彲浠ラ�氳繃 `setState` 鍔ㄦ�佷慨鏀箂chema銆�"
+    title="琛ㄥ崟缁勪欢"
+  >
+    <Card title="琛ㄥ崟鍔ㄦ�佽仈鍔ㄧず渚�">
+      <template #extra>
+        <Button class="mr-2" @click="handleUpdate">淇敼瀛楁3</Button>
+        <Button class="mr-2" @click="handleDelete">鍒犻櫎瀛楁7</Button>
+        <Button @click="handleAdd">娣诲姞瀛楁</Button>
+      </template>
+      <Form />
+    </Card>
+
+    <Card class="mt-5" title="瀛楁鍚屾锛屽瓧娈�1鏁版嵁涓庡瓧娈�2鏁版嵁鍚屾">
+      <SyncForm />
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/merge.vue b/eims-ui/playground/src/views/examples/form/merge.vue
new file mode 100644
index 0000000..22f20fa
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/merge.vue
@@ -0,0 +1,116 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message, Step, Steps, Switch } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const currentTab = ref(0);
+function onFirstSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form1 values: ${JSON.stringify(values)}`,
+  });
+  currentTab.value = 1;
+}
+function onSecondReset() {
+  currentTab.value = 0;
+}
+function onSecondSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form2 values: ${JSON.stringify(values)}`,
+  });
+}
+
+const [FirstForm, firstFormApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  handleSubmit: onFirstSubmit,
+  layout: 'horizontal',
+  resetButtonOptions: {
+    show: false,
+  },
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'formFirst',
+      label: '琛ㄥ崟1瀛楁',
+      rules: 'required',
+    },
+  ],
+  submitButtonOptions: {
+    content: '涓嬩竴姝�',
+  },
+  wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',
+});
+const [SecondForm, secondFormApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  handleReset: onSecondReset,
+  handleSubmit: onSecondSubmit,
+  layout: 'horizontal',
+  resetButtonOptions: {
+    content: '涓婁竴姝�',
+  },
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'formSecond',
+      label: '琛ㄥ崟2瀛楁',
+      rules: 'required',
+    },
+  ],
+  wrapperClass: 'grid-cols-1 md:grid-cols-1 lg:grid-cols-1',
+});
+const needMerge = ref(true);
+async function handleMergeSubmit() {
+  const values = await firstFormApi
+    .merge(secondFormApi)
+    .submitAllForm(needMerge.value);
+  message.success({
+    content: `merged form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Page
+    description="琛ㄥ崟缁勪欢鍚堝苟绀轰緥锛氬湪鏌愪簺鍦烘櫙涓嬶紝渚嬪鍒嗘琛ㄥ崟锛岄渶瑕佸悎骞跺涓〃鍗曞苟缁熶竴鎻愪氦銆傞粯璁ゆ儏鍐典笅锛屼娇鐢� Object.assign 瑙勫垯鍚堝苟琛ㄥ崟銆傚鏋滈渶瑕佺壒娈婂鐞嗘暟鎹紝鍙互浼犲叆 false銆�"
+    title="琛ㄥ崟缁勪欢"
+  >
+    <Card title="鍩虹绀轰緥">
+      <template #extra>
+        <Switch
+          v-model:checked="needMerge"
+          checked-children="寮�鍚瓧娈靛悎骞�"
+          class="mr-4"
+          un-checked-children="鍏抽棴瀛楁鍚堝苟"
+        />
+        <Button type="primary" @click="handleMergeSubmit">鍚堝苟鎻愪氦</Button>
+      </template>
+      <div class="mx-auto max-w-lg">
+        <Steps :current="currentTab" class="steps">
+          <Step title="琛ㄥ崟1" />
+          <Step title="琛ㄥ崟2" />
+        </Steps>
+        <div class="p-20">
+          <FirstForm v-show="currentTab === 0" />
+          <SecondForm v-show="currentTab === 1" />
+        </div>
+      </div>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/query.vue b/eims-ui/playground/src/views/examples/form/query.vue
new file mode 100644
index 0000000..2329236
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/query.vue
@@ -0,0 +1,147 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { Card, message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+const [QueryForm] = useVbenForm({
+  // 榛樿灞曞紑
+  collapsed: false,
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏ョ敤鎴峰悕',
+      },
+      // 瀛楁鍚�
+      fieldName: 'username',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楃涓�',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏ュ瘑鐮�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧(甯﹀悗缂�)',
+      suffix: () => '楼',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+    },
+  ],
+  // 鏄惁鍙睍寮�
+  showCollapseButton: true,
+  submitButtonOptions: {
+    content: '鏌ヨ',
+  },
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+const [QueryForm1] = useVbenForm({
+  // 榛樿灞曞紑
+  collapsed: true,
+  collapsedRows: 2,
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: (() => {
+    const schema = [];
+    for (let index = 0; index < 14; index++) {
+      schema.push({
+        // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+        component: 'Input',
+        // 瀛楁鍚�
+        fieldName: `field${index}`,
+        // 鐣岄潰鏄剧ず鐨刲abel
+        label: `瀛楁${index}`,
+      });
+    }
+    return schema;
+  })(),
+  // 鏄惁鍙睍寮�
+  showCollapseButton: true,
+  submitButtonOptions: {
+    content: '鏌ヨ',
+  },
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Page
+    description="鏌ヨ琛ㄥ崟锛屽父鐢ㄨ鍜岃〃鏍肩粍鍚堜娇鐢紝鍙繘琛屾敹缂╁睍寮�銆�"
+    title="琛ㄥ崟缁勪欢"
+  >
+    <Card class="mb-5" title="鏌ヨ琛ㄥ崟锛岄粯璁ゅ睍寮�">
+      <QueryForm />
+    </Card>
+    <Card title="鏌ヨ琛ㄥ崟锛岄粯璁ゆ姌鍙狅紝鎶樺彔鏃朵繚鐣�2琛�">
+      <QueryForm1 />
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/form/rules.vue b/eims-ui/playground/src/views/examples/form/rules.vue
new file mode 100644
index 0000000..dd95894
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/form/rules.vue
@@ -0,0 +1,243 @@
+<script lang="ts" setup>
+import { Page } from '@vben/common-ui';
+
+import { Button, Card, message } from 'ant-design-vue';
+
+import { useVbenForm, z } from '#/adapter/form';
+
+const [Form, formApi] = useVbenForm({
+  // 鎵�鏈夎〃鍗曢」鍏辩敤锛屽彲鍗曠嫭鍦ㄨ〃鍗曞唴瑕嗙洊
+  commonConfig: {
+    // 鎵�鏈夎〃鍗曢」
+    componentProps: {
+      class: 'w-full',
+    },
+  },
+  // 鎻愪氦鍑芥暟
+  handleSubmit: onSubmit,
+  // 鍨傜洿甯冨眬锛宭abel鍜宨nput鍦ㄤ笉鍚岃锛屽�间负vertical
+  // 姘村钩甯冨眬锛宭abel鍜宨nput鍦ㄥ悓涓�琛�
+  layout: 'horizontal',
+  schema: [
+    {
+      // 缁勪欢闇�瑕佸湪 #/adapter.ts鍐呮敞鍐岋紝骞跺姞涓婄被鍨�
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field1',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '瀛楁1',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      defaultValue: '榛樿鍊�',
+      fieldName: 'field2',
+      label: '榛樿鍊�(蹇呭~)',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field3',
+      label: '榛樿鍊�(闈炲繀濉�)',
+      rules: z.string().default('榛樿鍊�').optional(),
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field31',
+      label: '鑷畾涔変俊鎭�',
+      rules: z.string().min(1, { message: '鏈�灏戣緭鍏�1涓瓧绗�' }),
+    },
+    {
+      component: 'Input',
+      // 瀵瑰簲缁勪欢鐨勫弬鏁�
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      // 瀛楁鍚�
+      fieldName: 'field4',
+      // 鐣岄潰鏄剧ず鐨刲abel
+      label: '閭',
+      rules: z.string().email('璇疯緭鍏ユ纭殑閭'),
+    },
+    {
+      component: 'InputNumber',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'number',
+      label: '鏁板瓧',
+      rules: 'required',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        filterOption: true,
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+      },
+      defaultValue: undefined,
+      fieldName: 'options',
+      label: '涓嬫媺閫�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'RadioGroup',
+      componentProps: {
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'radioGroup',
+      label: '鍗曢�夌粍',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'CheckboxGroup',
+      componentProps: {
+        name: 'cname',
+        options: [
+          {
+            label: '閫夐」1',
+            value: '1',
+          },
+          {
+            label: '閫夐」2',
+            value: '2',
+          },
+        ],
+      },
+      fieldName: 'checkboxGroup',
+      label: '澶氶�夌粍',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'Checkbox',
+      fieldName: 'checkbox',
+      label: '',
+      renderComponentContent: () => {
+        return {
+          default: () => ['鎴戝凡闃呰骞跺悓鎰�'],
+        };
+      },
+      rules: 'selectRequired',
+    },
+    {
+      component: 'DatePicker',
+      defaultValue: undefined,
+      fieldName: 'datePicker',
+      label: '鏃ユ湡閫夋嫨妗�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'RangePicker',
+      defaultValue: undefined,
+      fieldName: 'rangePicker',
+      label: '鍖洪棿閫夋嫨妗�',
+      rules: 'selectRequired',
+    },
+    {
+      component: 'InputPassword',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'password',
+      label: '瀵嗙爜',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'input-blur',
+      formFieldProps: {
+        validateOnChange: false,
+        validateOnModelUpdate: false,
+      },
+      help: 'blur鏃舵墠浼氳Е鍙戞牎楠�',
+      label: 'blur瑙﹀彂',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'input-async',
+      label: '寮傛鏍¢獙',
+      rules: z
+        .string()
+        .min(3, '鐢ㄦ埛鍚嶈嚦灏戦渶瑕�3涓瓧绗�')
+        .refine(
+          async (username) => {
+            // 鍋囪杩欐槸涓�涓紓姝ュ嚱鏁帮紝妯℃嫙妫�鏌ョ敤鎴峰悕鏄惁宸插瓨鍦�
+            const checkUsernameExists = async (
+              username: string,
+            ): Promise<boolean> => {
+              await new Promise((resolve) => setTimeout(resolve, 1000));
+              return username === 'existingUser';
+            };
+            const exists = await checkUsernameExists(username);
+            return !exists;
+          },
+          {
+            message: '鐢ㄦ埛鍚嶅凡瀛樺湪',
+          },
+        ),
+    },
+  ],
+  // 澶у睆涓�琛屾樉绀�3涓紝涓睆涓�琛屾樉绀�2涓紝灏忓睆涓�琛屾樉绀�1涓�
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.success({
+    content: `form values: ${JSON.stringify(values)}`,
+  });
+}
+</script>
+
+<template>
+  <Page description="琛ㄥ崟鏍¢獙绀轰緥" title="琛ㄥ崟缁勪欢">
+    <Card title="鍩虹缁勪欢鏍¢獙绀轰緥">
+      <template #extra>
+        <Button @click="() => formApi.validate()">鏍¢獙琛ㄥ崟</Button>
+        <Button class="mx-2" @click="() => formApi.resetValidate()">
+          娓呯┖鏍¢獙淇℃伅
+        </Button>
+      </template>
+      <Form />
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/auto-height-demo.vue b/eims-ui/playground/src/views/examples/modal/auto-height-demo.vue
new file mode 100644
index 0000000..28939a6
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/auto-height-demo.vue
@@ -0,0 +1,46 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+const list = ref<number[]>([]);
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+  },
+  onOpenChange(isOpen) {
+    if (isOpen) {
+      handleUpdate(10);
+    }
+  },
+});
+
+function handleUpdate(len: number) {
+  modalApi.setState({ confirmDisabled: true, loading: true });
+  setTimeout(() => {
+    list.value = Array.from({ length: len }, (_v, k) => k + 1);
+    modalApi.setState({ confirmDisabled: false, loading: false });
+  }, 2000);
+}
+</script>
+
+<template>
+  <Modal title="鑷姩璁$畻楂樺害">
+    <div
+      v-for="item in list"
+      :key="item"
+      class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
+    >
+      {{ item }}
+    </div>
+    <template #prepend-footer>
+      <Button type="link" @click="handleUpdate(6)">鐐瑰嚮鏇存柊鏁版嵁</Button>
+    </template>
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/base-demo.vue b/eims-ui/playground/src/views/examples/modal/base-demo.vue
new file mode 100644
index 0000000..40afb86
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/base-demo.vue
@@ -0,0 +1,26 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onClosed() {
+    message.info('onClosed锛氬叧闂姩鐢荤粨鏉�');
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // modalApi.close();
+  },
+  onOpened() {
+    message.info('onOpened锛氭墦寮�鍔ㄧ敾缁撴潫');
+  },
+});
+</script>
+<template>
+  <Modal class="w-[600px]" title="鍩虹寮圭獥绀轰緥" title-tooltip="鏍囬鎻愮ず鍐呭">
+    base demo
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/drag-demo.vue b/eims-ui/playground/src/views/examples/modal/drag-demo.vue
new file mode 100644
index 0000000..4520303
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/drag-demo.vue
@@ -0,0 +1,19 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const [Modal, modalApi] = useVbenModal({
+  draggable: true,
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // modalApi.close();
+  },
+});
+</script>
+<template>
+  <Modal title="鍙嫋鎷界ず渚�"> 榧犳爣绉诲姩鍒� header 涓婏紝鍙嫋鎷藉脊绐� </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/dynamic-demo.vue b/eims-ui/playground/src/views/examples/modal/dynamic-demo.vue
new file mode 100644
index 0000000..33d1c4e
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/dynamic-demo.vue
@@ -0,0 +1,41 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+const [Modal, modalApi] = useVbenModal({
+  draggable: true,
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // modalApi.close();
+  },
+  title: '鍔ㄦ�佷慨鏀归厤缃ず渚�',
+});
+
+const state = modalApi.useStore();
+
+function handleUpdateTitle() {
+  modalApi.setState({ title: '鍐呴儴鍔ㄦ�佹爣棰�' });
+}
+
+function handleToggleFullscreen() {
+  modalApi.setState((prev) => {
+    return { ...prev, fullscreen: !prev.fullscreen };
+  });
+}
+</script>
+<template>
+  <Modal>
+    <div class="flex-col-center">
+      <Button class="mb-3" type="primary" @click="handleUpdateTitle()">
+        鍐呴儴鍔ㄦ�佷慨鏀规爣棰�
+      </Button>
+      <Button class="mb-3" type="primary" @click="handleToggleFullscreen()">
+        {{ state.fullscreen ? '閫�鍑哄叏灞�' : '鎵撳紑鍏ㄥ睆' }}
+      </Button>
+    </div>
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/form-modal-demo.vue b/eims-ui/playground/src/views/examples/modal/form-modal-demo.vue
new file mode 100644
index 0000000..5179ffe
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/form-modal-demo.vue
@@ -0,0 +1,78 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+
+defineOptions({
+  name: 'FormModelDemo',
+});
+
+function onSubmit(values: Record<string, any>) {
+  message.info(JSON.stringify(values)); // 鍙細鎵ц涓�娆�
+}
+
+const [Form, formApi] = useVbenForm({
+  handleSubmit: onSubmit,
+  schema: [
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field1',
+      label: '瀛楁1',
+      rules: 'required',
+    },
+    {
+      component: 'Input',
+      componentProps: {
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field2',
+      label: '瀛楁2',
+      rules: 'required',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        options: [
+          { label: '閫夐」1', value: '1' },
+          { label: '閫夐」2', value: '2' },
+        ],
+        placeholder: '璇疯緭鍏�',
+      },
+      fieldName: 'field3',
+      label: '瀛楁3',
+      rules: 'required',
+    },
+  ],
+  showDefaultActions: false,
+});
+
+const [Modal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm: async () => {
+    await formApi.validateAndSubmitForm();
+    // modalApi.close();
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      const { values } = modalApi.getData<Record<string, any>>();
+      if (values) {
+        formApi.setValues(values);
+      }
+    }
+  },
+  title: '鍐呭祵琛ㄥ崟绀轰緥',
+});
+</script>
+<template>
+  <Modal>
+    <Form />
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/in-content-demo.vue b/eims-ui/playground/src/views/examples/modal/in-content-demo.vue
new file mode 100644
index 0000000..4ffbcea
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/in-content-demo.vue
@@ -0,0 +1,25 @@
+<script lang="ts" setup>
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // modalApi.close();
+  },
+});
+</script>
+<template>
+  <Modal
+    append-to-main
+    class="w-[600px]"
+    title="鍩虹寮圭獥绀轰緥"
+    title-tooltip="鏍囬鎻愮ず鍐呭"
+  >
+    姝ゅ脊绐楁寚瀹氬湪鍐呭鍖哄煙鎵撳紑
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/index.vue b/eims-ui/playground/src/views/examples/modal/index.vue
new file mode 100644
index 0000000..4176f14
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/index.vue
@@ -0,0 +1,143 @@
+<script lang="ts" setup>
+import { Page, useVbenModal } from '@vben/common-ui';
+
+import { Button, Card } from 'ant-design-vue';
+
+import DocButton from '../doc-button.vue';
+import AutoHeightDemo from './auto-height-demo.vue';
+import BaseDemo from './base-demo.vue';
+import DragDemo from './drag-demo.vue';
+import DynamicDemo from './dynamic-demo.vue';
+import FormModalDemo from './form-modal-demo.vue';
+import InContentModalDemo from './in-content-demo.vue';
+import SharedDataDemo from './shared-data-demo.vue';
+
+const [BaseModal, baseModalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: BaseDemo,
+});
+
+const [InContentModal, inContentModalApi] = useVbenModal({
+  // 杩炴帴鎶界鐨勭粍浠�
+  connectedComponent: InContentModalDemo,
+});
+
+const [AutoHeightModal, autoHeightModalApi] = useVbenModal({
+  connectedComponent: AutoHeightDemo,
+});
+
+const [DragModal, dragModalApi] = useVbenModal({
+  connectedComponent: DragDemo,
+});
+
+const [DynamicModal, dynamicModalApi] = useVbenModal({
+  connectedComponent: DynamicDemo,
+});
+
+const [SharedDataModal, sharedModalApi] = useVbenModal({
+  connectedComponent: SharedDataDemo,
+});
+
+const [FormModal, formModalApi] = useVbenModal({
+  connectedComponent: FormModalDemo,
+});
+
+function openBaseModal() {
+  baseModalApi.open();
+}
+
+function openInContentModal() {
+  inContentModalApi.open();
+}
+
+function openAutoHeightModal() {
+  autoHeightModalApi.open();
+}
+
+function openDragModal() {
+  dragModalApi.open();
+}
+
+function openDynamicModal() {
+  dynamicModalApi.open();
+}
+
+function openSharedModal() {
+  sharedModalApi.setData({
+    content: '澶栭儴浼犻�掔殑鏁版嵁 content',
+    payload: '澶栭儴浼犻�掔殑鏁版嵁 payload',
+  });
+  sharedModalApi.open();
+}
+
+function handleUpdateTitle() {
+  dynamicModalApi.setState({ title: '澶栭儴鍔ㄦ�佹爣棰�' });
+  dynamicModalApi.open();
+}
+
+function openFormModal() {
+  formModalApi.setData({
+    // 琛ㄥ崟鍊�
+    values: { field1: 'abc' },
+  });
+  formModalApi.open();
+}
+</script>
+
+<template>
+  <Page
+    auto-content-height
+    description="寮圭獥缁勪欢甯哥敤浜庡湪涓嶇寮�褰撳墠椤甸潰鐨勬儏鍐典笅锛屾樉绀洪澶栫殑淇℃伅銆佽〃鍗曟垨鎿嶄綔鎻愮ず锛屾洿澶歛pi璇锋煡鐪嬬粍浠舵枃妗c��"
+    title="寮圭獥缁勪欢绀轰緥"
+  >
+    <template #extra>
+      <DocButton path="/components/common-ui/vben-modal" />
+    </template>
+    <BaseModal />
+    <InContentModal />
+    <AutoHeightModal />
+    <DragModal />
+    <DynamicModal />
+    <SharedDataModal />
+    <FormModal />
+    <Card class="mb-4" title="鍩烘湰浣跨敤">
+      <p class="mb-3">涓�涓熀纭�鐨勫脊绐楃ず渚�</p>
+      <Button type="primary" @click="openBaseModal">鎵撳紑寮圭獥</Button>
+    </Card>
+
+    <Card class="mb-4" title="鎸囧畾瀹瑰櫒">
+      <p class="mb-3">鍦ㄥ唴瀹瑰尯鍩熸墦寮�寮圭獥鐨勭ず渚�</p>
+      <Button type="primary" @click="openInContentModal">鎵撳紑寮圭獥</Button>
+    </Card>
+
+    <Card class="mb-4" title="鍐呭楂樺害鑷�傚簲">
+      <p class="mb-3">鍙牴鎹唴瀹瑰苟鑷姩璋冩暣楂樺害</p>
+      <Button type="primary" @click="openAutoHeightModal">鎵撳紑寮圭獥</Button>
+    </Card>
+
+    <Card class="mb-4" title="鍙嫋鎷界ず渚�">
+      <p class="mb-3">閰嶇疆 draggable 鍙紑鍚嫋鎷藉姛鑳�</p>
+      <Button type="primary" @click="openDragModal">鎵撳紑寮圭獥</Button>
+    </Card>
+
+    <Card class="mb-4" title="鍔ㄦ�侀厤缃ず渚�">
+      <p class="mb-3">閫氳繃 setState 鍔ㄦ�佽皟鏁村脊绐楁暟鎹�</p>
+      <Button type="primary" @click="openDynamicModal">鎵撳紑寮圭獥</Button>
+      <Button class="ml-2" type="primary" @click="handleUpdateTitle">
+        浠庡閮ㄤ慨鏀规爣棰樺苟鎵撳紑
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="鍐呭鏁版嵁鍏变韩绀轰緥">
+      <p class="mb-3">閫氳繃鍏变韩 sharedData 鏉ヨ繘琛屾暟鎹氦浜�</p>
+      <Button type="primary" @click="openSharedModal">
+        鎵撳紑寮圭獥骞朵紶閫掓暟鎹�
+      </Button>
+    </Card>
+
+    <Card class="mb-4" title="琛ㄥ崟寮圭獥绀轰緥">
+      <p class="mb-3">寮圭獥涓庤〃鍗曠粨鍚�</p>
+      <Button type="primary" @click="openFormModal"> 鎵撳紑寮圭獥 </Button>
+    </Card>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/modal/shared-data-demo.vue b/eims-ui/playground/src/views/examples/modal/shared-data-demo.vue
new file mode 100644
index 0000000..8ba6e7e
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/modal/shared-data-demo.vue
@@ -0,0 +1,29 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+const data = ref();
+
+const [Modal, modalApi] = useVbenModal({
+  onCancel() {
+    modalApi.close();
+  },
+  onConfirm() {
+    message.info('onConfirm');
+    // modalApi.close();
+  },
+  onOpenChange(isOpen: boolean) {
+    if (isOpen) {
+      data.value = modalApi.getData<Record<string, any>>();
+    }
+  },
+});
+</script>
+<template>
+  <Modal title="鏁版嵁鍏变韩绀轰緥">
+    <div class="flex-col-center">澶栭儴浼犻�掓暟鎹細 {{ data }}</div>
+  </Modal>
+</template>
diff --git a/eims-ui/playground/src/views/examples/resize/basic.vue b/eims-ui/playground/src/views/examples/resize/basic.vue
new file mode 100644
index 0000000..6295839
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/resize/basic.vue
@@ -0,0 +1,58 @@
+<script lang="ts" setup>
+import { ref } from 'vue';
+
+import { Page, VResize } from '@vben/common-ui';
+
+const colorMap = ['red', 'green', 'yellow', 'gray'];
+
+type TSize = {
+  height: number;
+  left: number;
+  top: number;
+  width: number;
+};
+
+const sizeList = ref<TSize[]>([
+  { height: 200, left: 200, top: 200, width: 200 },
+  { height: 300, left: 300, top: 300, width: 300 },
+  { height: 400, left: 400, top: 400, width: 400 },
+  { height: 500, left: 500, top: 500, width: 500 },
+]);
+
+const resize = (size?: TSize, rect?: TSize) => {
+  if (!size || !rect) return;
+
+  size.height = rect.height;
+  size.left = rect.left;
+  size.top = rect.top;
+  size.width = rect.width;
+};
+</script>
+
+<template>
+  <Page description="Resize缁勪欢鍩虹绀轰緥" title="Resize缁勪欢">
+    <div class="m-4 bg-blue-500 p-48 text-xl">
+      <div v-for="size in sizeList" :key="size.width">
+        {{
+          `width: ${size.width}px, height: ${size.height}px, top: ${size.top}px, left: ${size.left}px`
+        }}
+      </div>
+    </div>
+
+    <template v-for="(_, idx) of 4" :key="idx">
+      <VResize
+        :h="100 * (idx + 1)"
+        :w="100 * (idx + 1)"
+        :x="100 * (idx + 1)"
+        :y="100 * (idx + 1)"
+        @dragging="(rect) => resize(sizeList[idx], rect)"
+        @resizing="(rect) => resize(sizeList[idx], rect)"
+      >
+        <div
+          :style="{ backgroundColor: colorMap[idx] }"
+          class="h-full w-full"
+        ></div>
+      </VResize>
+    </template>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/basic.vue b/eims-ui/playground/src/views/examples/vxe-table/basic.vue
new file mode 100644
index 0000000..1216468
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/basic.vue
@@ -0,0 +1,96 @@
+<script lang="ts" setup>
+import type { VxeGridListeners, VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import DocButton from '../doc-button.vue';
+import { MOCK_TABLE_DATA } from './table-data';
+
+interface RowType {
+  address: string;
+  age: number;
+  id: number;
+  name: string;
+  nickname: string;
+  role: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'name', title: 'Name' },
+    { field: 'age', sortable: true, title: 'Age' },
+    { field: 'nickname', title: 'Nickname' },
+    { field: 'role', title: 'Role' },
+    { field: 'address', showOverflow: true, title: 'Address' },
+  ],
+  data: MOCK_TABLE_DATA,
+  pagerConfig: {
+    enabled: false,
+  },
+  sortConfig: {
+    multiple: true,
+  },
+};
+
+const gridEvents: VxeGridListeners<RowType> = {
+  cellClick: ({ row }) => {
+    message.info(`cell-click: ${row.name}`);
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridEvents, gridOptions });
+
+const showBorder = gridApi.useStore((state) => state.gridOptions?.border);
+const showStripe = gridApi.useStore((state) => state.gridOptions?.stripe);
+
+function changeBorder() {
+  gridApi.setGridOptions({
+    border: !showBorder.value,
+  });
+}
+
+function changeStripe() {
+  gridApi.setGridOptions({
+    stripe: !showStripe.value,
+  });
+}
+
+function changeLoading() {
+  gridApi.setLoading(true);
+  setTimeout(() => {
+    gridApi.setLoading(false);
+  }, 2000);
+}
+</script>
+
+<template>
+  <Page
+    description="琛ㄦ牸缁勪欢甯哥敤浜庡揩閫熷紑鍙戞暟鎹睍绀轰笌浜や簰鐣岄潰锛岀ず渚嬫暟鎹负闈欐�佹暟鎹�傝缁勪欢鏄vxe-table杩涜绠�鍗曠殑浜屾灏佽锛屽ぇ閮ㄥ垎灞炴�т笌鏂规硶涓巚xe-table淇濇寔涓�鑷淬��"
+    title="琛ㄦ牸鍩虹绀轰緥"
+  >
+    <template #extra>
+      <DocButton path="/components/common-ui/vben-vxe-table" />
+    </template>
+    <Grid table-title="鍩虹鍒楄〃" table-title-help="鎻愮ず">
+      <!-- <template #toolbar-actions>
+        <Button class="mr-2" type="primary">宸︿晶鎻掓Ы</Button>
+      </template> -->
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="changeBorder">
+          {{ showBorder ? '闅愯棌' : '鏄剧ず' }}杈规
+        </Button>
+        <Button class="mr-2" type="primary" @click="changeLoading">
+          鏄剧ずloading
+        </Button>
+        <Button type="primary" @click="changeStripe">
+          {{ showStripe ? '闅愯棌' : '鏄剧ず' }}鏂戦┈绾�
+        </Button>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/custom-cell.vue b/eims-ui/playground/src/views/examples/vxe-table/custom-cell.vue
new file mode 100644
index 0000000..46fd29c
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/custom-cell.vue
@@ -0,0 +1,107 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, Image, Switch, Tag } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  imageUrl: string;
+  open: boolean;
+  price: string;
+  productName: string;
+  releaseDate: string;
+  status: 'error' | 'success' | 'warning';
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'category', title: 'Category', width: 100 },
+    {
+      field: 'imageUrl',
+      slots: { default: 'image-url' },
+      title: 'Image',
+      width: 100,
+    },
+    {
+      cellRender: { name: 'CellImage' },
+      field: 'imageUrl2',
+      title: 'Render Image',
+      width: 130,
+    },
+    {
+      field: 'open',
+      slots: { default: 'open' },
+      title: 'Open',
+      width: 100,
+    },
+    {
+      field: 'status',
+      slots: { default: 'status' },
+      title: 'Status',
+      width: 100,
+    },
+    { field: 'color', title: 'Color', width: 100 },
+    { field: 'productName', title: 'Product Name', width: 200 },
+    { field: 'price', title: 'Price', width: 100 },
+    {
+      field: 'releaseDate',
+      formatter: 'formatDateTime',
+      title: 'Date',
+      width: 200,
+    },
+    {
+      cellRender: { name: 'CellLink', props: { text: '缂栬緫' } },
+      field: 'action',
+      fixed: 'right',
+      title: '鎿嶄綔',
+      width: 120,
+    },
+  ],
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid>
+      <template #image-url="{ row }">
+        <Image :src="row.imageUrl" height="30" width="30" />
+      </template>
+      <template #open="{ row }">
+        <Switch v-model:checked="row.open" />
+      </template>
+      <template #status="{ row }">
+        <Tag :color="row.color">{{ row.status }}</Tag>
+      </template>
+      <template #action>
+        <Button type="link">缂栬緫</Button>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/edit-cell.vue b/eims-ui/playground/src/views/examples/vxe-table/edit-cell.vue
new file mode 100644
index 0000000..9aebde8
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/edit-cell.vue
@@ -0,0 +1,57 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { editRender: { name: 'input' }, field: 'category', title: 'Category' },
+    { editRender: { name: 'input' }, field: 'color', title: 'Color' },
+    {
+      editRender: { name: 'input' },
+      field: 'productName',
+      title: 'Product Name',
+    },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+  ],
+  editConfig: {
+    mode: 'cell',
+    trigger: 'click',
+  },
+  height: 'auto',
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  showOverflow: true,
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid />
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/edit-row.vue b/eims-ui/playground/src/views/examples/vxe-table/edit-row.vue
new file mode 100644
index 0000000..f9d25ca
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/edit-row.vue
@@ -0,0 +1,94 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button, message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { editRender: { name: 'input' }, field: 'category', title: 'Category' },
+    { editRender: { name: 'input' }, field: 'color', title: 'Color' },
+    {
+      editRender: { name: 'input' },
+      field: 'productName',
+      title: 'Product Name',
+    },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+    { slots: { default: 'action' }, title: '鎿嶄綔' },
+  ],
+  editConfig: {
+    mode: 'row',
+    trigger: 'click',
+  },
+  height: 'auto',
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  showOverflow: true,
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+function hasEditStatus(row: RowType) {
+  return gridApi.grid?.isEditByRow(row);
+}
+
+function editRowEvent(row: RowType) {
+  gridApi.grid?.setEditRow(row);
+}
+
+async function saveRowEvent(row: RowType) {
+  await gridApi.grid?.clearEdit();
+
+  gridApi.setLoading(true);
+  setTimeout(() => {
+    gridApi.setLoading(false);
+    message.success({
+      content: `淇濆瓨鎴愬姛锛乧ategory=${row.category}`,
+    });
+  }, 600);
+}
+
+const cancelRowEvent = (_row: RowType) => {
+  gridApi.grid?.clearEdit();
+};
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid>
+      <template #action="{ row }">
+        <template v-if="hasEditStatus(row)">
+          <Button type="link" @click="saveRowEvent(row)">淇濆瓨</Button>
+          <Button type="link" @click="cancelRowEvent(row)">鍙栨秷</Button>
+        </template>
+        <template v-else>
+          <Button type="link" @click="editRowEvent(row)">缂栬緫</Button>
+        </template>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/fixed.vue b/eims-ui/playground/src/views/examples/vxe-table/fixed.vue
new file mode 100644
index 0000000..399d352
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/fixed.vue
@@ -0,0 +1,69 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { fixed: 'left', title: '搴忓彿', type: 'seq', width: 50 },
+    { field: 'category', title: 'Category', width: 300 },
+    { field: 'color', title: 'Color', width: 300 },
+    { field: 'productName', title: 'Product Name', width: 300 },
+    { field: 'price', title: 'Price', width: 300 },
+    {
+      field: 'releaseDate',
+      formatter: 'formatDateTime',
+      title: 'DateTime',
+      width: 500,
+    },
+    {
+      field: 'action',
+      fixed: 'right',
+      slots: { default: 'action' },
+      title: '鎿嶄綔',
+      width: 120,
+    },
+  ],
+  height: 'auto',
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  rowConfig: {
+    isHover: true,
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ gridOptions });
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid>
+      <template #action>
+        <Button type="link">缂栬緫</Button>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/form.vue b/eims-ui/playground/src/views/examples/vxe-table/form.vue
new file mode 100644
index 0000000..9003503
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/form.vue
@@ -0,0 +1,112 @@
+<script lang="ts" setup>
+import type { VbenFormProps } from '#/adapter/form';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { message } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const formOptions: VbenFormProps = {
+  // 榛樿灞曞紑
+  collapsed: false,
+  schema: [
+    {
+      component: 'Input',
+      defaultValue: '1',
+      fieldName: 'category',
+      label: 'Category',
+    },
+    {
+      component: 'Input',
+      fieldName: 'productName',
+      label: 'ProductName',
+    },
+    {
+      component: 'Input',
+      fieldName: 'price',
+      label: 'Price',
+    },
+    {
+      component: 'Select',
+      componentProps: {
+        allowClear: true,
+        options: [
+          {
+            label: 'Color1',
+            value: '1',
+          },
+          {
+            label: 'Color2',
+            value: '2',
+          },
+        ],
+        placeholder: '璇烽�夋嫨',
+      },
+      fieldName: 'color',
+      label: 'Color',
+    },
+    {
+      component: 'DatePicker',
+      fieldName: 'datePicker',
+      label: 'Date',
+    },
+  ],
+  // 鎺у埗琛ㄥ崟鏄惁鏄剧ず鎶樺彔鎸夐挳
+  showCollapseButton: true,
+  // 鏄惁鍦ㄥ瓧娈靛�兼敼鍙樻椂鎻愪氦琛ㄥ崟
+  submitOnChange: true,
+  // 鎸変笅鍥炶溅鏃舵槸鍚︽彁浜よ〃鍗�
+  submitOnEnter: false,
+};
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },
+    { field: 'category', title: 'Category' },
+    { field: 'color', title: 'Color' },
+    { field: 'productName', title: 'Product Name' },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'Date' },
+  ],
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues) => {
+        message.success(`Query params: ${JSON.stringify(formValues)}`);
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues,
+        });
+      },
+    },
+  },
+};
+
+const [Grid] = useVbenVxeGrid({ formOptions, gridOptions });
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid />
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/remote.vue b/eims-ui/playground/src/views/examples/vxe-table/remote.vue
new file mode 100644
index 0000000..7fc98a0
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/remote.vue
@@ -0,0 +1,74 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { getExampleTableApi } from '#/api';
+
+interface RowType {
+  category: string;
+  color: string;
+  id: string;
+  price: string;
+  productName: string;
+  releaseDate: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  checkboxConfig: {
+    highlight: true,
+    labelField: 'name',
+  },
+  columns: [
+    { title: '搴忓彿', type: 'seq', width: 50 },
+    { align: 'left', title: 'Name', type: 'checkbox', width: 100 },
+    { field: 'category', title: 'Category' },
+    { field: 'color', title: 'Color' },
+    { field: 'productName', title: 'Product Name' },
+    { field: 'price', title: 'Price' },
+    { field: 'releaseDate', formatter: 'formatDateTime', title: 'DateTime' },
+  ],
+  exportConfig: {},
+  height: 'auto',
+  keepSource: true,
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }) => {
+        return await getExampleTableApi({
+          page: page.currentPage,
+          pageSize: page.pageSize,
+        });
+      },
+    },
+  },
+  toolbarConfig: {
+    custom: true,
+    export: true,
+    // import: true,
+    refresh: true,
+    zoom: true,
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({
+  gridOptions,
+});
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid table-title="鏁版嵁鍒楄〃" table-title-help="鎻愮ず">
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="() => gridApi.query()">
+          鍒锋柊褰撳墠椤甸潰
+        </Button>
+        <Button type="primary" @click="() => gridApi.reload()">
+          鍒锋柊骞惰繑鍥炵涓�椤�
+        </Button>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/table-data.ts b/eims-ui/playground/src/views/examples/vxe-table/table-data.ts
new file mode 100644
index 0000000..b4eb5ed
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/table-data.ts
@@ -0,0 +1,172 @@
+interface TableRowData {
+  address: string;
+  age: number;
+  id: number;
+  name: string;
+  nickname: string;
+  role: string;
+}
+
+const roles = ['User', 'Admin', 'Manager', 'Guest'];
+
+export const MOCK_TABLE_DATA: TableRowData[] = (() => {
+  const data: TableRowData[] = [];
+  for (let i = 0; i < 40; i++) {
+    data.push({
+      address: `New York${i}`,
+      age: i + 1,
+      id: i,
+      name: `Test${i}`,
+      nickname: `Test${i}`,
+      role: roles[Math.floor(Math.random() * roles.length)] as string,
+    });
+  }
+  return data;
+})();
+
+export const MOCK_TREE_TABLE_DATA = [
+  {
+    date: '2020-08-01',
+    id: 10_000,
+    name: 'Test1',
+    parentId: null,
+    size: 1024,
+    type: 'mp3',
+  },
+  {
+    date: '2021-04-01',
+    id: 10_050,
+    name: 'Test2',
+    parentId: null,
+    size: 0,
+    type: 'mp4',
+  },
+  {
+    date: '2020-03-01',
+    id: 24_300,
+    name: 'Test3',
+    parentId: 10_050,
+    size: 1024,
+    type: 'avi',
+  },
+  {
+    date: '2021-04-01',
+    id: 20_045,
+    name: 'Test4',
+    parentId: 24_300,
+    size: 600,
+    type: 'html',
+  },
+  {
+    date: '2021-04-01',
+    id: 10_053,
+    name: 'Test5',
+    parentId: 24_300,
+    size: 0,
+    type: 'avi',
+  },
+  {
+    date: '2021-10-01',
+    id: 24_330,
+    name: 'Test6',
+    parentId: 10_053,
+    size: 25,
+    type: 'txt',
+  },
+  {
+    date: '2020-01-01',
+    id: 21_011,
+    name: 'Test7',
+    parentId: 10_053,
+    size: 512,
+    type: 'pdf',
+  },
+  {
+    date: '2021-06-01',
+    id: 22_200,
+    name: 'Test8',
+    parentId: 10_053,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2020-11-01',
+    id: 23_666,
+    name: 'Test9',
+    parentId: null,
+    size: 2048,
+    type: 'xlsx',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_677,
+    name: 'Test10',
+    parentId: 23_666,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_671,
+    name: 'Test11',
+    parentId: 23_677,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_672,
+    name: 'Test12',
+    parentId: 23_677,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_688,
+    name: 'Test13',
+    parentId: 23_666,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_681,
+    name: 'Test14',
+    parentId: 23_688,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 23_682,
+    name: 'Test15',
+    parentId: 23_688,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2020-10-01',
+    id: 24_555,
+    name: 'Test16',
+    parentId: null,
+    size: 224,
+    type: 'avi',
+  },
+  {
+    date: '2021-06-01',
+    id: 24_566,
+    name: 'Test17',
+    parentId: 24_555,
+    size: 1024,
+    type: 'js',
+  },
+  {
+    date: '2021-06-01',
+    id: 24_577,
+    name: 'Test18',
+    parentId: 24_555,
+    size: 1024,
+    type: 'js',
+  },
+];
diff --git a/eims-ui/playground/src/views/examples/vxe-table/tree.vue b/eims-ui/playground/src/views/examples/vxe-table/tree.vue
new file mode 100644
index 0000000..c8a1df4
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/tree.vue
@@ -0,0 +1,62 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { Page } from '@vben/common-ui';
+
+import { Button } from 'ant-design-vue';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+import { MOCK_TREE_TABLE_DATA } from './table-data';
+
+interface RowType {
+  date: string;
+  id: number;
+  name: string;
+  parentId: null | number;
+  size: number;
+  type: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { type: 'seq', width: 70 },
+    { field: 'name', minWidth: 300, title: 'Name', treeNode: true },
+    { field: 'size', title: 'Size' },
+    { field: 'type', title: 'Type' },
+    { field: 'date', title: 'Date' },
+  ],
+  data: MOCK_TREE_TABLE_DATA,
+  pagerConfig: {
+    enabled: false,
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    transform: true,
+  },
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+const expandAll = () => {
+  gridApi.grid?.setAllTreeExpand(true);
+};
+
+const collapseAll = () => {
+  gridApi.grid?.setAllTreeExpand(false);
+};
+</script>
+
+<template>
+  <Page>
+    <Grid table-title="鏁版嵁鍒楄〃" table-title-help="鎻愮ず">
+      <template #toolbar-tools>
+        <Button class="mr-2" type="primary" @click="expandAll">
+          灞曞紑鍏ㄩ儴
+        </Button>
+        <Button type="primary" @click="collapseAll"> 鎶樺彔鍏ㄩ儴 </Button>
+      </template>
+    </Grid>
+  </Page>
+</template>
diff --git a/eims-ui/playground/src/views/examples/vxe-table/virtual.vue b/eims-ui/playground/src/views/examples/vxe-table/virtual.vue
new file mode 100644
index 0000000..f35a691
--- /dev/null
+++ b/eims-ui/playground/src/views/examples/vxe-table/virtual.vue
@@ -0,0 +1,66 @@
+<script lang="ts" setup>
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { onMounted } from 'vue';
+
+import { Page } from '@vben/common-ui';
+
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+
+interface RowType {
+  id: number;
+  name: string;
+  role: string;
+  sex: string;
+}
+
+const gridOptions: VxeGridProps<RowType> = {
+  columns: [
+    { type: 'seq', width: 70 },
+    { field: 'name', title: 'Name' },
+    { field: 'role', title: 'Role' },
+    { field: 'sex', title: 'Sex' },
+  ],
+  data: [],
+  height: 'auto',
+  pagerConfig: {
+    enabled: false,
+  },
+  scrollY: {
+    enabled: true,
+    gt: 0,
+  },
+  showOverflow: true,
+};
+
+const [Grid, gridApi] = useVbenVxeGrid({ gridOptions });
+
+// 妯℃嫙琛屾暟鎹�
+const loadList = (size = 200) => {
+  try {
+    const dataList: RowType[] = [];
+    for (let i = 0; i < size; i++) {
+      dataList.push({
+        id: 10_000 + i,
+        name: `Test${i}`,
+        role: 'Developer',
+        sex: '鐢�',
+      });
+    }
+    gridApi.setGridOptions({ data: dataList });
+  } catch (error) {
+    console.error('Failed to load data:', error);
+    // Implement user-friendly error handling
+  }
+};
+
+onMounted(() => {
+  loadList(1000);
+});
+</script>
+
+<template>
+  <Page auto-content-height>
+    <Grid />
+  </Page>
+</template>
diff --git a/eims-ui/playground/tailwind.config.mjs b/eims-ui/playground/tailwind.config.mjs
new file mode 100644
index 0000000..f17f556
--- /dev/null
+++ b/eims-ui/playground/tailwind.config.mjs
@@ -0,0 +1 @@
+export { default } from '@vben/tailwind-config';
diff --git a/eims-ui/playground/tsconfig.json b/eims-ui/playground/tsconfig.json
new file mode 100644
index 0000000..02c287f
--- /dev/null
+++ b/eims-ui/playground/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/web-app.json",
+  "compilerOptions": {
+    "baseUrl": ".",
+    "paths": {
+      "#/*": ["./src/*"]
+    }
+  },
+  "references": [{ "path": "./tsconfig.node.json" }],
+  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
+}
diff --git a/eims-ui/playground/tsconfig.node.json b/eims-ui/playground/tsconfig.node.json
new file mode 100644
index 0000000..c2f0d86
--- /dev/null
+++ b/eims-ui/playground/tsconfig.node.json
@@ -0,0 +1,10 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "compilerOptions": {
+    "composite": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "noEmit": false
+  },
+  "include": ["vite.config.mts"]
+}
diff --git a/eims-ui/playground/vite.config.mts b/eims-ui/playground/vite.config.mts
new file mode 100644
index 0000000..b6360f1
--- /dev/null
+++ b/eims-ui/playground/vite.config.mts
@@ -0,0 +1,20 @@
+import { defineConfig } from '@vben/vite-config';
+
+export default defineConfig(async () => {
+  return {
+    application: {},
+    vite: {
+      server: {
+        proxy: {
+          '/api': {
+            changeOrigin: true,
+            rewrite: (path) => path.replace(/^\/api/, ''),
+            // mock浠g悊鐩爣鍦板潃
+            target: 'http://localhost:5320/api',
+            ws: true,
+          },
+        },
+      },
+    },
+  };
+});
diff --git a/eims-ui/pnpm-workspace.yaml b/eims-ui/pnpm-workspace.yaml
new file mode 100644
index 0000000..f63903b
--- /dev/null
+++ b/eims-ui/pnpm-workspace.yaml
@@ -0,0 +1,183 @@
+packages:
+  - internal/*
+  - internal/lint-configs/*
+  - packages/*
+  - packages/@core/base/*
+  - packages/@core/ui-kit/*
+  - packages/@core/forward/*
+  - packages/@core/*
+  - packages/effects/*
+  - packages/business/*
+  - apps/*
+  - scripts/*
+  - docs
+  - playground
+catalog:
+  '@ast-grep/napi': ^0.31.1
+  '@changesets/changelog-github': ^0.5.0
+  '@changesets/cli': ^2.27.10
+  '@changesets/git': ^3.0.2
+  '@clack/prompts': ^0.8.2
+  '@commitlint/cli': ^19.6.0
+  '@commitlint/config-conventional': ^19.6.0
+  '@ctrl/tinycolor': ^4.1.0
+  '@eslint/js': ^9.16.0
+  '@faker-js/faker': ^9.3.0
+  '@iconify/json': ^2.2.281
+  '@iconify/tailwind': ^1.2.0
+  '@iconify/vue': ^4.2.0
+  '@intlify/core-base': ^10.0.5
+  '@intlify/unplugin-vue-i18n': ^6.0.1
+  '@jspm/generator': ^2.4.1
+  '@manypkg/get-packages': ^2.2.2
+  '@nolebase/vitepress-plugin-git-changelog': ^2.11.1
+  '@playwright/test': ^1.49.1
+  '@pnpm/workspace.read-manifest': ^1000.0.0
+  '@stylistic/stylelint-plugin': ^3.1.1
+  '@tailwindcss/nesting': 0.0.0-insiders.565cd3e
+  '@tailwindcss/typography': ^0.5.15
+  '@tanstack/vue-query': ^5.62.7
+  '@tanstack/vue-store': ^0.6.0
+  '@types/archiver': ^6.0.3
+  '@types/eslint': ^9.6.1
+  '@types/html-minifier-terser': ^7.0.2
+  '@types/jsonwebtoken': ^9.0.7
+  '@types/lodash.clonedeep': ^4.5.9
+  '@types/lodash.get': ^4.4.9
+  '@types/lodash.isequal': ^4.5.8
+  '@types/node': ^22.10.1
+  '@types/nprogress': ^0.2.3
+  '@types/postcss-import': ^14.0.3
+  '@types/qrcode': ^1.5.5
+  '@types/sortablejs': ^1.15.8
+  '@typescript-eslint/eslint-plugin': ^8.18.0
+  '@typescript-eslint/parser': ^8.18.0
+  '@vee-validate/zod': ^4.14.7
+  '@vite-pwa/vitepress': ^0.5.3
+  '@vitejs/plugin-vue': ^5.2.1
+  '@vitejs/plugin-vue-jsx': ^4.1.1
+  '@vue/reactivity': ^3.5.13
+  '@vue/shared': ^3.5.13
+  '@vue/test-utils': ^2.4.6
+  '@vueuse/core': ^12.0.0
+  '@vueuse/integrations': ^12.0.0
+  ant-design-vue: ^4.2.6
+  archiver: ^7.0.1
+  autoprefixer: ^10.4.20
+  axios: ^1.7.9
+  axios-mock-adapter: ^2.1.0
+  cac: ^6.7.14
+  chalk: ^5.3.0
+  cheerio: 1.0.0
+  circular-dependency-scanner: ^2.3.0
+  class-variance-authority: ^0.7.1
+  clsx: ^2.1.1
+  commitlint-plugin-function-rules: ^4.0.1
+  consola: ^3.2.3
+  cross-env: ^7.0.3
+  cspell: ^8.16.1
+  cssnano: ^7.0.6
+  cz-git: ^1.11.0
+  czg: ^1.11.0
+  dayjs: ^1.11.13
+  defu: ^6.1.4
+  depcheck: ^1.4.7
+  dotenv: ^16.4.7
+  echarts: ^5.5.1
+  element-plus: ^2.9.0
+  eslint: ^9.16.0
+  eslint-config-turbo: ^2.3.3
+  eslint-plugin-command: ^0.2.6
+  eslint-plugin-eslint-comments: ^3.2.0
+  eslint-plugin-import-x: ^4.5.0
+  eslint-plugin-jsdoc: ^50.6.1
+  eslint-plugin-jsonc: ^2.18.2
+  eslint-plugin-n: ^17.15.0
+  eslint-plugin-no-only-tests: ^3.3.0
+  eslint-plugin-perfectionist: ^3.9.1
+  eslint-plugin-prettier: ^5.2.1
+  eslint-plugin-regexp: ^2.7.0
+  eslint-plugin-unicorn: ^56.0.1
+  eslint-plugin-unused-imports: ^4.1.4
+  eslint-plugin-vitest: ^0.5.4
+  eslint-plugin-vue: ^9.32.0
+  execa: ^9.5.2
+  find-up: ^7.0.0
+  get-port: ^7.1.0
+  globals: ^15.13.0
+  h3: ^1.13.0
+  happy-dom: ^15.11.7
+  html-minifier-terser: ^7.2.0
+  husky: ^9.1.7
+  is-ci: ^3.0.1
+  jsonc-eslint-parser: ^2.4.0
+  jsonwebtoken: ^9.0.2
+  lint-staged: ^15.2.11
+  lodash.clonedeep: ^4.5.0
+  lodash.get: ^4.4.2
+  lodash.isequal: ^4.5.0
+  lucide-vue-next: ^0.465.0
+  medium-zoom: ^1.1.0
+  naive-ui: ^2.40.3
+  nitropack: ^2.10.4
+  nprogress: ^0.2.0
+  ora: ^8.1.1
+  pinia: 2.2.2
+  pinia-plugin-persistedstate: ^4.1.3
+  pkg-types: ^1.2.1
+  playwright: ^1.49.1
+  postcss: ^8.4.49
+  postcss-antd-fixes: ^0.2.0
+  postcss-html: ^1.7.0
+  postcss-import: ^16.1.0
+  postcss-preset-env: ^10.1.1
+  postcss-scss: ^4.0.9
+  prettier: ^3.4.2
+  prettier-plugin-tailwindcss: ^0.6.9
+  publint: ^0.2.12
+  qrcode: ^1.5.4
+  radix-vue: ^1.9.11
+  resolve.exports: ^2.0.3
+  rimraf: ^6.0.1
+  rollup: ^4.28.1
+  rollup-plugin-visualizer: ^5.12.0
+  sass: 1.80.6
+  sortablejs: ^1.15.6
+  stylelint: ^16.11.0
+  stylelint-config-recess-order: ^5.1.1
+  stylelint-config-recommended: ^14.0.1
+  stylelint-config-recommended-scss: ^14.1.0
+  stylelint-config-recommended-vue: ^1.5.0
+  stylelint-config-standard: ^36.0.1
+  stylelint-order: ^6.0.4
+  stylelint-prettier: ^5.0.2
+  stylelint-scss: ^6.10.0
+  tailwind-merge: ^2.5.5
+  tailwindcss: ^3.4.16
+  tailwindcss-animate: ^1.0.7
+  theme-colors: ^0.1.0
+  turbo: ^2.3.3
+  typescript: 5.6.3
+  unbuild: ^3.0.0-rc.11
+  unplugin-element-plus: ^0.8.0
+  vee-validate: ^4.14.7
+  vite: ^6.0.3
+  vite-plugin-compression: ^0.5.1
+  vite-plugin-dts: 4.2.1
+  vite-plugin-html: ^3.2.2
+  vite-plugin-lazy-import: ^1.0.7
+  vite-plugin-pwa: ^0.21.1
+  vite-plugin-vue-devtools: ^7.6.7
+  vitepress: ^1.5.0
+  vitepress-plugin-group-icons: ^1.3.1
+  vitest: ^2.1.8
+  vue: ^3.5.13
+  vue-eslint-parser: ^9.4.3
+  vue-i18n: ^10.0.5
+  vue-router: ^4.5.0
+  vue-tsc: ^2.1.10
+  vxe-pc-ui: ^4.3.4
+  vxe-table: 4.9.5
+  watermark-js-plus: ^1.5.7
+  zod: ^3.24.1
+  zod-defaults: ^0.1.3
diff --git a/eims-ui/scripts/clean.mjs b/eims-ui/scripts/clean.mjs
new file mode 100644
index 0000000..e2840d3
--- /dev/null
+++ b/eims-ui/scripts/clean.mjs
@@ -0,0 +1,53 @@
+import { promises as fs } from 'node:fs';
+import { join } from 'node:path';
+
+const rootDir = process.cwd();
+
+/**
+ * 閫掑綊鏌ユ壘骞跺垹闄ょ洰鏍囩洰褰�
+ * @param {string} currentDir - 褰撳墠閬嶅巻鐨勭洰褰曡矾寰�
+ */
+async function cleanTargetsRecursively(currentDir, targets) {
+  const items = await fs.readdir(currentDir);
+
+  for (const item of items) {
+    try {
+      const itemPath = join(currentDir, item);
+      if (targets.includes(item)) {
+        // 鍖归厤鍒扮洰鏍囩洰褰曟垨鏂囦欢鏃剁洿鎺ュ垹闄�
+        await fs.rm(itemPath, { force: true, recursive: true });
+        console.log(`Deleted: ${itemPath}`);
+      }
+      const stat = await fs.lstat(itemPath);
+      if (stat.isDirectory()) {
+        await cleanTargetsRecursively(itemPath, targets);
+      }
+    } catch {
+      // console.error(
+      //   `Error handling item ${item} in ${currentDir}: ${error.message}`,
+      // );
+    }
+  }
+}
+
+(async function startCleanup() {
+  // 瑕佸垹闄ょ殑鐩綍鍙婃枃浠跺悕绉�
+  const targets = ['node_modules', 'dist', '.turbo', 'dist.zip'];
+
+  const deleteLockFile = process.argv.includes('--del-lock');
+  const cleanupTargets = [...targets];
+  if (deleteLockFile) {
+    cleanupTargets.push('pnpm-lock.yaml');
+  }
+
+  console.log(
+    `Starting cleanup of targets: ${cleanupTargets.join(', ')} from root: ${rootDir}`,
+  );
+
+  try {
+    await cleanTargetsRecursively(rootDir, cleanupTargets);
+    console.log('Cleanup process completed.');
+  } catch (error) {
+    console.error(`Unexpected error during cleanup: ${error.message}`);
+  }
+})();
diff --git a/eims-ui/scripts/deploy/Dockerfile b/eims-ui/scripts/deploy/Dockerfile
new file mode 100644
index 0000000..9fd1519
--- /dev/null
+++ b/eims-ui/scripts/deploy/Dockerfile
@@ -0,0 +1,31 @@
+FROM node:20-slim AS builder
+
+# --max-old-space-size
+ENV PNPM_HOME="/pnpm"
+ENV PATH="$PNPM_HOME:$PATH"
+ENV NODE_OPTIONS=--max-old-space-size=8192
+ENV TZ=Asia/Shanghai
+
+RUN corepack enable
+
+WORKDIR /app
+
+# copy package.json and pnpm-lock.yaml to workspace
+COPY . /app
+
+RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
+RUN pnpm run build --filter=\!./docs
+
+RUN echo "Builder Success 馃帀"
+
+FROM nginx:stable-alpine AS production
+
+RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf
+COPY --from=builder /app/playground/dist /usr/share/nginx/html
+
+COPY --from=builder /app/scripts/deploy/nginx.conf /etc/nginx/nginx.conf
+
+EXPOSE 8080
+
+# start nginx
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/eims-ui/scripts/deploy/build-local-docker-image.sh b/eims-ui/scripts/deploy/build-local-docker-image.sh
new file mode 100755
index 0000000..4881487
--- /dev/null
+++ b/eims-ui/scripts/deploy/build-local-docker-image.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log
+ERROR=""
+IMAGE_NAME="vben-admin-local"
+
+function stop_and_remove_container() {
+    # Stop and remove the existing container
+    docker stop ${IMAGE_NAME} >/dev/null 2>&1
+    docker rm ${IMAGE_NAME} >/dev/null 2>&1
+}
+
+function remove_image() {
+    # Remove the existing image
+    docker rmi vben-admin-pro >/dev/null 2>&1
+}
+
+function install_dependencies() {
+    # Install all dependencies
+    cd ${SCRIPT_DIR}
+    pnpm install || ERROR="install_dependencies failed"
+}
+
+function build_image() {
+    # build docker
+    docker build ../../ -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed"
+}
+
+function log_message() {
+    if [[ ${ERROR} != "" ]];
+    then
+        >&2 echo "build failed, Please check build-local-docker-image.log for more details"
+        >&2 echo "ERROR: ${ERROR}"
+        exit 1
+    else
+        echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container"
+        echo ""
+        echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}"
+    fi
+}
+
+echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE}
+stop_and_remove_container
+remove_image
+
+echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
+install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
+
+if [[ ${ERROR} == "" ]]; then
+    echo "Info: Building docker image" | tee -a ${LOG_FILE}
+    build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
+fi
+
+log_message | tee -a ${LOG_FILE}
diff --git a/eims-ui/scripts/deploy/nginx.conf b/eims-ui/scripts/deploy/nginx.conf
new file mode 100644
index 0000000..8e6ab10
--- /dev/null
+++ b/eims-ui/scripts/deploy/nginx.conf
@@ -0,0 +1,75 @@
+
+#user  nobody;
+worker_processes 1;
+
+#error_log  logs/error.log;
+#error_log  logs/error.log  notice;
+#error_log  logs/error.log  info;
+
+#pid        logs/nginx.pid;
+
+
+events {
+  worker_connections 1024;
+}
+
+
+http {
+  include mime.types;
+  default_type application/octet-stream;
+
+  types {
+    application/javascript  js mjs;
+    text/css                css;
+    text/html               html;
+  }
+
+  sendfile on;
+  # tcp_nopush     on;
+
+  #keepalive_timeout  0;
+  # keepalive_timeout 65;
+
+  # gzip on;
+  # gzip_buffers 32 16k;
+  # gzip_comp_level 6;
+  # gzip_min_length 1k;
+  # gzip_static on;
+  # gzip_types text/plain
+  #   text/css
+  #   application/javascript
+  #   application/json
+  #   application/x-javascript
+  #   text/xml
+  #   application/xml
+  #   application/xml+rss
+  #   text/javascript; #璁剧疆鍘嬬缉鐨勬枃浠剁被鍨�
+  # gzip_vary on;
+
+  server {
+    listen 8080;
+    server_name localhost;
+
+    location / {
+      root /usr/share/nginx/html;
+      try_files $uri $uri/ /index.html;
+      index index.html;
+      # Enable CORS
+      add_header 'Access-Control-Allow-Origin' '*';
+      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+      add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
+      if ($request_method = 'OPTIONS') {
+        add_header 'Access-Control-Max-Age' 1728000;
+        add_header 'Content-Type' 'text/plain charset=UTF-8';
+        add_header 'Content-Length' 0;
+        return 204;
+      }
+    }
+
+    error_page 500 502 503 504 /50x.html;
+
+    location = /50x.html {
+        root /usr/share/nginx/html;
+    }
+  }
+}
diff --git a/eims-ui/scripts/preview/1.png b/eims-ui/scripts/preview/1.png
new file mode 100644
index 0000000..d538d12
--- /dev/null
+++ b/eims-ui/scripts/preview/1.png
Binary files differ
diff --git a/eims-ui/scripts/preview/10.png b/eims-ui/scripts/preview/10.png
new file mode 100644
index 0000000..30103d4
--- /dev/null
+++ b/eims-ui/scripts/preview/10.png
Binary files differ
diff --git a/eims-ui/scripts/preview/2.png b/eims-ui/scripts/preview/2.png
new file mode 100644
index 0000000..3a4889b
--- /dev/null
+++ b/eims-ui/scripts/preview/2.png
Binary files differ
diff --git a/eims-ui/scripts/preview/3.png b/eims-ui/scripts/preview/3.png
new file mode 100644
index 0000000..fd0ce94
--- /dev/null
+++ b/eims-ui/scripts/preview/3.png
Binary files differ
diff --git a/eims-ui/scripts/preview/4.png b/eims-ui/scripts/preview/4.png
new file mode 100644
index 0000000..822e7bd
--- /dev/null
+++ b/eims-ui/scripts/preview/4.png
Binary files differ
diff --git a/eims-ui/scripts/preview/5.png b/eims-ui/scripts/preview/5.png
new file mode 100644
index 0000000..5a58fd1
--- /dev/null
+++ b/eims-ui/scripts/preview/5.png
Binary files differ
diff --git a/eims-ui/scripts/preview/6.png b/eims-ui/scripts/preview/6.png
new file mode 100644
index 0000000..03f1038
--- /dev/null
+++ b/eims-ui/scripts/preview/6.png
Binary files differ
diff --git a/eims-ui/scripts/preview/7.png b/eims-ui/scripts/preview/7.png
new file mode 100644
index 0000000..80ebb22
--- /dev/null
+++ b/eims-ui/scripts/preview/7.png
Binary files differ
diff --git a/eims-ui/scripts/preview/8.png b/eims-ui/scripts/preview/8.png
new file mode 100644
index 0000000..1e9f9b2
--- /dev/null
+++ b/eims-ui/scripts/preview/8.png
Binary files differ
diff --git a/eims-ui/scripts/preview/9.png b/eims-ui/scripts/preview/9.png
new file mode 100644
index 0000000..20d497d
--- /dev/null
+++ b/eims-ui/scripts/preview/9.png
Binary files differ
diff --git a/eims-ui/scripts/turbo-run/README.md b/eims-ui/scripts/turbo-run/README.md
new file mode 100644
index 0000000..65ffcf4
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/README.md
@@ -0,0 +1,3 @@
+# @vben/turbo-run
+
+turbo-run is a command line tool that allows you to run multiple commands in parallel.
diff --git a/eims-ui/scripts/turbo-run/bin/turbo-run.mjs b/eims-ui/scripts/turbo-run/bin/turbo-run.mjs
new file mode 100755
index 0000000..407754d
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/bin/turbo-run.mjs
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+import('../dist/index.mjs');
diff --git a/eims-ui/scripts/turbo-run/build.config.ts b/eims-ui/scripts/turbo-run/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/scripts/turbo-run/package.json b/eims-ui/scripts/turbo-run/package.json
new file mode 100644
index 0000000..4c7fd91
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "@vben/turbo-run",
+  "version": "5.5.0",
+  "private": true,
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "bin": {
+    "turbo-run": "./bin/turbo-run.mjs"
+  },
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "default": "./dist/index.mjs"
+    },
+    "./package.json": "./package.json"
+  },
+  "dependencies": {
+    "@clack/prompts": "catalog:",
+    "@vben/node-utils": "workspace:*",
+    "cac": "catalog:"
+  }
+}
diff --git a/eims-ui/scripts/turbo-run/src/index.ts b/eims-ui/scripts/turbo-run/src/index.ts
new file mode 100644
index 0000000..2f8dad0
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/src/index.ts
@@ -0,0 +1,29 @@
+import { colors, consola } from '@vben/node-utils';
+
+import { cac } from 'cac';
+
+import { run } from './run';
+
+try {
+  const turboRun = cac('turbo-run');
+
+  turboRun
+    .command('[script]')
+    .usage(`Run turbo interactively.`)
+    .action(async (command: string) => {
+      run({ command });
+    });
+
+  // Invalid command
+  turboRun.on('command:*', () => {
+    consola.error(colors.red('Invalid command!'));
+    process.exit(1);
+  });
+
+  turboRun.usage('turbo-run');
+  turboRun.help();
+  turboRun.parse();
+} catch (error) {
+  consola.error(error);
+  process.exit(1);
+}
diff --git a/eims-ui/scripts/turbo-run/src/run.ts b/eims-ui/scripts/turbo-run/src/run.ts
new file mode 100644
index 0000000..6a8762f
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/src/run.ts
@@ -0,0 +1,67 @@
+import { execaCommand, getPackages } from '@vben/node-utils';
+
+import { cancel, isCancel, select } from '@clack/prompts';
+
+interface RunOptions {
+  command?: string;
+}
+
+export async function run(options: RunOptions) {
+  const { command } = options;
+  if (!command) {
+    console.error('Please enter the command to run');
+    process.exit(1);
+  }
+  const { packages } = await getPackages();
+  // const appPkgs = await findApps(process.cwd(), packages);
+  // const websitePkg = packages.find(
+  //   (item) => item.packageJson.name === '@vben/website',
+  // );
+
+  // 鍙樉绀烘湁瀵瑰簲鍛戒护鐨勫寘
+  const selectPkgs = packages.filter((pkg) => {
+    return (pkg?.packageJson as Record<string, any>)?.scripts?.[command];
+  });
+
+  let selectPkg: string | symbol;
+  if (selectPkgs.length > 1) {
+    selectPkg = await select<any, string>({
+      message: `Select the app you need to run [${command}]:`,
+      options: selectPkgs.map((item) => ({
+        label: item?.packageJson.name,
+        value: item?.packageJson.name,
+      })),
+    });
+
+    if (isCancel(selectPkg) || !selectPkg) {
+      cancel('馃憢 Has cancelled');
+      process.exit(0);
+    }
+  } else {
+    selectPkg = selectPkgs[0]?.packageJson?.name ?? '';
+  }
+
+  if (!selectPkg) {
+    console.error('No app found');
+    process.exit(1);
+  }
+
+  execaCommand(`pnpm --filter=${selectPkg} run ${command}`, {
+    stdio: 'inherit',
+  });
+}
+
+/**
+ * 杩囨护app鍖�
+ * @param root
+ * @param packages
+ */
+// async function findApps(root: string, packages: Package[]) {
+//   // apps鍐呯殑
+//   const appPackages = packages.filter((pkg) => {
+//     const viteConfigExists = fs.existsSync(join(pkg.dir, 'vite.config.mts'));
+//     return pkg.dir.startsWith(join(root, 'apps')) && viteConfigExists;
+//   });
+
+//   return appPackages;
+// }
diff --git a/eims-ui/scripts/turbo-run/tsconfig.json b/eims-ui/scripts/turbo-run/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/scripts/turbo-run/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git a/eims-ui/scripts/vsh/README.md b/eims-ui/scripts/vsh/README.md
new file mode 100644
index 0000000..7cc8fbf
--- /dev/null
+++ b/eims-ui/scripts/vsh/README.md
@@ -0,0 +1,3 @@
+# @vben/vsh
+
+shell 鑴氭湰宸ュ叿闆嗗悎
diff --git a/eims-ui/scripts/vsh/bin/vsh.mjs b/eims-ui/scripts/vsh/bin/vsh.mjs
new file mode 100755
index 0000000..407754d
--- /dev/null
+++ b/eims-ui/scripts/vsh/bin/vsh.mjs
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+import('../dist/index.mjs');
diff --git a/eims-ui/scripts/vsh/build.config.ts b/eims-ui/scripts/vsh/build.config.ts
new file mode 100644
index 0000000..97e572c
--- /dev/null
+++ b/eims-ui/scripts/vsh/build.config.ts
@@ -0,0 +1,7 @@
+import { defineBuildConfig } from 'unbuild';
+
+export default defineBuildConfig({
+  clean: true,
+  declaration: true,
+  entries: ['src/index'],
+});
diff --git a/eims-ui/scripts/vsh/package.json b/eims-ui/scripts/vsh/package.json
new file mode 100644
index 0000000..30b9f17
--- /dev/null
+++ b/eims-ui/scripts/vsh/package.json
@@ -0,0 +1,31 @@
+{
+  "name": "@vben/vsh",
+  "version": "5.5.0",
+  "private": true,
+  "license": "MIT",
+  "type": "module",
+  "scripts": {
+    "stub": "pnpm unbuild --stub"
+  },
+  "files": [
+    "dist"
+  ],
+  "bin": {
+    "vsh": "./bin/vsh.mjs"
+  },
+  "main": "./dist/index.mjs",
+  "module": "./dist/index.mjs",
+  "exports": {
+    ".": {
+      "default": "./dist/index.mjs"
+    },
+    "./package.json": "./package.json"
+  },
+  "dependencies": {
+    "@vben/node-utils": "workspace:*",
+    "cac": "catalog:",
+    "circular-dependency-scanner": "catalog:",
+    "depcheck": "catalog:",
+    "publint": "catalog:"
+  }
+}
diff --git a/eims-ui/scripts/vsh/src/check-circular/index.ts b/eims-ui/scripts/vsh/src/check-circular/index.ts
new file mode 100644
index 0000000..8af9789
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/check-circular/index.ts
@@ -0,0 +1,80 @@
+import type { CAC } from 'cac';
+
+import { extname } from 'node:path';
+
+import { getStagedFiles } from '@vben/node-utils';
+
+import { circularDepsDetect, printCircles } from 'circular-dependency-scanner';
+
+const IGNORE_DIR = [
+  'dist',
+  '.turbo',
+  'output',
+  '.cache',
+  'scripts',
+  'internal',
+  'packages/effects/request/src/',
+  'packages/@core/ui-kit/menu-ui/src/',
+  'packages/@core/ui-kit/popup-ui/src/',
+].join(',');
+
+const IGNORE = [`**/{${IGNORE_DIR}}/**`];
+
+interface CommandOptions {
+  staged: boolean;
+  verbose: boolean;
+}
+
+async function checkCircular({ staged, verbose }: CommandOptions) {
+  const results = await circularDepsDetect({
+    absolute: staged,
+    cwd: process.cwd(),
+    ignore: IGNORE,
+  });
+
+  if (staged) {
+    let files = await getStagedFiles();
+
+    const allowedExtensions = new Set([
+      '.cjs',
+      '.js',
+      '.jsx',
+      '.mjs',
+      '.ts',
+      '.tsx',
+      '.vue',
+    ]);
+
+    // 杩囨护鏂囦欢鍒楄〃
+    files = files.filter((file) => allowedExtensions.has(extname(file)));
+
+    const circularFiles: string[][] = [];
+
+    for (const file of files) {
+      for (const result of results) {
+        const resultFiles = result.flat();
+        if (resultFiles.includes(file)) {
+          circularFiles.push(result);
+        }
+      }
+    }
+    verbose && printCircles(circularFiles);
+  } else {
+    verbose && printCircles(results);
+  }
+}
+
+function defineCheckCircularCommand(cac: CAC) {
+  cac
+    .command('check-circular')
+    .option(
+      '--staged',
+      'Whether it is the staged commit mode, in which mode, if there is a circular dependency, an alarm will be given.',
+    )
+    .usage(`Analysis of project circular dependencies.`)
+    .action(async ({ staged }) => {
+      await checkCircular({ staged, verbose: true });
+    });
+}
+
+export { defineCheckCircularCommand };
diff --git a/eims-ui/scripts/vsh/src/check-dep/index.ts b/eims-ui/scripts/vsh/src/check-dep/index.ts
new file mode 100644
index 0000000..7626229
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/check-dep/index.ts
@@ -0,0 +1,85 @@
+import type { CAC } from 'cac';
+
+import { getPackages } from '@vben/node-utils';
+
+import depcheck from 'depcheck';
+
+async function runDepcheck() {
+  const { packages } = await getPackages();
+  await Promise.all(
+    packages.map(async (pkg) => {
+      if (
+        [
+          '@vben/backend-mock',
+          '@vben/commitlint-config',
+          '@vben/eslint-config',
+          '@vben/lint-staged-config',
+          '@vben/node-utils',
+          '@vben/prettier-config',
+          '@vben/stylelint-config',
+          '@vben/tailwind-config',
+          '@vben/tsconfig',
+          '@vben/vite-config',
+          '@vben/vite-config',
+          '@vben/vsh',
+        ].includes(pkg.packageJson.name)
+      ) {
+        return;
+      }
+
+      const unused = await depcheck(pkg.dir, {
+        ignoreMatches: [
+          'vite',
+          'vitest',
+          'unbuild',
+          '@vben/tsconfig',
+          '@vben/vite-config',
+          '@vben/tailwind-config',
+          '@types/*',
+          '@vben-core/design',
+        ],
+        ignorePatterns: ['dist', 'node_modules', 'public'],
+      });
+
+      // 鍒犻櫎file:鍓嶇紑鐨勪緷璧栨彁绀猴紝璇ヤ緷璧栨槸鏈湴渚濊禆
+      Reflect.deleteProperty(unused.missing, 'file:');
+      Object.keys(unused.missing).forEach((key) => {
+        unused.missing[key] = (unused.missing[key] || []).filter(
+          (item: string) => !item.startsWith('/'),
+        );
+        if (unused.missing[key].length === 0) {
+          Reflect.deleteProperty(unused.missing, key);
+        }
+      });
+
+      if (
+        Object.keys(unused.missing).length === 0 &&
+        unused.dependencies.length === 0 &&
+        unused.devDependencies.length === 0
+      ) {
+        return;
+      }
+      console.error(
+        '\n',
+        pkg.packageJson.name,
+        '\n missing:',
+        unused.missing,
+        '\n dependencies:',
+        unused.dependencies,
+        '\n devDependencies:',
+        unused.devDependencies,
+      );
+    }),
+  );
+}
+
+function defineDepcheckCommand(cac: CAC) {
+  cac
+    .command('check-dep')
+    .usage(`Analysis of project circular dependencies.`)
+    .action(async () => {
+      await runDepcheck();
+    });
+}
+
+export { defineDepcheckCommand };
diff --git a/eims-ui/scripts/vsh/src/code-workspace/index.ts b/eims-ui/scripts/vsh/src/code-workspace/index.ts
new file mode 100644
index 0000000..d5ec4ee
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/code-workspace/index.ts
@@ -0,0 +1,78 @@
+import type { CAC } from 'cac';
+
+import { join, relative } from 'node:path';
+
+import {
+  colors,
+  consola,
+  findMonorepoRoot,
+  getPackages,
+  gitAdd,
+  outputJSON,
+  prettierFormat,
+  toPosixPath,
+} from '@vben/node-utils';
+
+const CODE_WORKSPACE_FILE = join('vben-admin.code-workspace');
+
+interface CodeWorkspaceCommandOptions {
+  autoCommit?: boolean;
+  spaces?: number;
+}
+
+async function createCodeWorkspace({
+  autoCommit = false,
+  spaces = 2,
+}: CodeWorkspaceCommandOptions) {
+  const { packages, rootDir } = await getPackages();
+
+  let folders = packages.map((pkg) => {
+    const { dir, packageJson } = pkg;
+    return {
+      name: packageJson.name,
+      path: toPosixPath(relative(rootDir, dir)),
+    };
+  });
+
+  folders = folders.filter(Boolean);
+
+  const monorepoRoot = findMonorepoRoot();
+  const outputPath = join(monorepoRoot, CODE_WORKSPACE_FILE);
+  await outputJSON(outputPath, { folders }, spaces);
+
+  await prettierFormat(outputPath);
+  if (autoCommit) {
+    await gitAdd(CODE_WORKSPACE_FILE, monorepoRoot);
+  }
+}
+
+async function runCodeWorkspace({
+  autoCommit,
+  spaces,
+}: CodeWorkspaceCommandOptions) {
+  await createCodeWorkspace({
+    autoCommit,
+    spaces,
+  });
+  if (autoCommit) {
+    return;
+  }
+  consola.log('');
+  consola.success(colors.green(`${CODE_WORKSPACE_FILE} is updated!`));
+  consola.log('');
+}
+
+function defineCodeWorkspaceCommand(cac: CAC) {
+  cac
+    .command('code-workspace')
+    .usage('Update the `.code-workspace` file')
+    .option('--spaces [number]', '.code-workspace JSON file spaces.', {
+      default: 2,
+    })
+    .option('--auto-commit', 'auto commit .code-workspace JSON file.', {
+      default: false,
+    })
+    .action(runCodeWorkspace);
+}
+
+export { defineCodeWorkspaceCommand };
diff --git a/eims-ui/scripts/vsh/src/index.ts b/eims-ui/scripts/vsh/src/index.ts
new file mode 100644
index 0000000..2b00448
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/index.ts
@@ -0,0 +1,41 @@
+import { colors, consola } from '@vben/node-utils';
+
+import { cac } from 'cac';
+
+import { defineCheckCircularCommand } from './check-circular';
+import { defineDepcheckCommand } from './check-dep';
+import { defineCodeWorkspaceCommand } from './code-workspace';
+import { defineLintCommand } from './lint';
+import { definePubLintCommand } from './publint';
+
+try {
+  const vsh = cac('vsh');
+
+  // vsh lint
+  defineLintCommand(vsh);
+
+  // vsh publint
+  definePubLintCommand(vsh);
+
+  // vsh code-workspace
+  defineCodeWorkspaceCommand(vsh);
+
+  // vsh check-circular
+  defineCheckCircularCommand(vsh);
+
+  // vsh check-dep
+  defineDepcheckCommand(vsh);
+
+  // Invalid command
+  vsh.on('command:*', () => {
+    consola.error(colors.red('Invalid command!'));
+    process.exit(1);
+  });
+
+  vsh.usage('vsh');
+  vsh.help();
+  vsh.parse();
+} catch (error) {
+  consola.error(error);
+  process.exit(1);
+}
diff --git a/eims-ui/scripts/vsh/src/lint/index.ts b/eims-ui/scripts/vsh/src/lint/index.ts
new file mode 100644
index 0000000..5d381e8
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/lint/index.ts
@@ -0,0 +1,48 @@
+import type { CAC } from 'cac';
+
+import { execaCommand } from '@vben/node-utils';
+
+interface LintCommandOptions {
+  /**
+   * Format lint problem.
+   */
+  format?: boolean;
+}
+
+async function runLint({ format }: LintCommandOptions) {
+  // process.env.FORCE_COLOR = '3';
+
+  if (format) {
+    await execaCommand(`stylelint "**/*.{vue,css,less.scss}" --cache --fix`, {
+      stdio: 'inherit',
+    });
+    await execaCommand(`eslint . --cache --fix`, {
+      stdio: 'inherit',
+    });
+    await execaCommand(`prettier . --write --cache --log-level warn`, {
+      stdio: 'inherit',
+    });
+    return;
+  }
+  await Promise.all([
+    execaCommand(`eslint . --cache`, {
+      stdio: 'inherit',
+    }),
+    execaCommand(`prettier . --ignore-unknown --check --cache`, {
+      stdio: 'inherit',
+    }),
+    execaCommand(`stylelint "**/*.{vue,css,less.scss}" --cache`, {
+      stdio: 'inherit',
+    }),
+  ]);
+}
+
+function defineLintCommand(cac: CAC) {
+  cac
+    .command('lint')
+    .usage('Batch execute project lint check.')
+    .option('--format', 'Format lint problem.')
+    .action(runLint);
+}
+
+export { defineLintCommand };
diff --git a/eims-ui/scripts/vsh/src/publint/index.ts b/eims-ui/scripts/vsh/src/publint/index.ts
new file mode 100644
index 0000000..658c0c5
--- /dev/null
+++ b/eims-ui/scripts/vsh/src/publint/index.ts
@@ -0,0 +1,185 @@
+import type { CAC } from 'cac';
+import type { Result } from 'publint';
+
+import { basename, dirname, join } from 'node:path';
+
+import {
+  colors,
+  consola,
+  ensureFile,
+  findMonorepoRoot,
+  generatorContentHash,
+  getPackages,
+  outputJSON,
+  readJSON,
+  UNICODE,
+} from '@vben/node-utils';
+
+import { publint } from 'publint';
+import { formatMessage } from 'publint/utils';
+
+const CACHE_FILE = join(
+  'node_modules',
+  '.cache',
+  'publint',
+  '.pkglintcache.json',
+);
+
+interface PubLintCommandOptions {
+  /**
+   * Only errors are checked, no program exit is performed
+   */
+  check?: boolean;
+}
+
+/**
+ * Get files that require lint
+ * @param files
+ */
+async function getLintFiles(files: string[] = []) {
+  const lintFiles: string[] = [];
+
+  if (files?.length > 0) {
+    return files.filter((file) => basename(file) === 'package.json');
+  }
+
+  const { packages } = await getPackages();
+
+  for (const { dir } of packages) {
+    lintFiles.push(join(dir, 'package.json'));
+  }
+  return lintFiles;
+}
+
+function getCacheFile() {
+  const root = findMonorepoRoot();
+  return join(root, CACHE_FILE);
+}
+
+async function readCache(cacheFile: string) {
+  try {
+    await ensureFile(cacheFile);
+    return await readJSON(cacheFile);
+  } catch {
+    return {};
+  }
+}
+
+async function runPublint(files: string[], { check }: PubLintCommandOptions) {
+  const lintFiles = await getLintFiles(files);
+  const cacheFile = getCacheFile();
+
+  const cacheData = await readCache(cacheFile);
+  const cache: Record<string, { hash: string; result: Result }> = cacheData;
+
+  const results = await Promise.all(
+    lintFiles.map(async (file) => {
+      try {
+        const pkgJson = await readJSON(file);
+
+        if (pkgJson.private) {
+          return null;
+        }
+
+        Reflect.deleteProperty(pkgJson, 'dependencies');
+        Reflect.deleteProperty(pkgJson, 'devDependencies');
+        Reflect.deleteProperty(pkgJson, 'peerDependencies');
+        const content = JSON.stringify(pkgJson);
+        const hash = generatorContentHash(content);
+
+        const publintResult: Result =
+          cache?.[file]?.hash === hash
+            ? (cache?.[file]?.result ?? [])
+            : await publint({
+                level: 'suggestion',
+                pkgDir: dirname(file),
+                strict: true,
+              });
+
+        cache[file] = {
+          hash,
+          result: publintResult,
+        };
+
+        return { pkgJson, pkgPath: file, publintResult };
+      } catch {
+        return null;
+      }
+    }),
+  );
+
+  await outputJSON(cacheFile, cache);
+  printResult(results, check);
+}
+
+function printResult(
+  results: Array<{
+    pkgJson: Record<string, number | string>;
+    pkgPath: string;
+    publintResult: Result;
+  } | null>,
+  check?: boolean,
+) {
+  let errorCount = 0;
+  let warningCount = 0;
+  let suggestionsCount = 0;
+
+  for (const result of results) {
+    if (!result) {
+      continue;
+    }
+    const { pkgJson, pkgPath, publintResult } = result;
+    const messages = publintResult?.messages ?? [];
+    if (messages?.length < 1) {
+      continue;
+    }
+
+    consola.log('');
+    consola.log(pkgPath);
+    for (const message of messages) {
+      switch (message.type) {
+        case 'error': {
+          errorCount++;
+
+          break;
+        }
+        case 'suggestion': {
+          suggestionsCount++;
+          break;
+        }
+        case 'warning': {
+          warningCount++;
+
+          break;
+        }
+        // No default
+      }
+      const ruleUrl = `https://publint.dev/rules#${message.code.toLocaleLowerCase()}`;
+      consola.log(
+        `  ${formatMessage(message, pkgJson)}${colors.dim(` ${ruleUrl}`)}`,
+      );
+    }
+  }
+
+  const totalCount = warningCount + errorCount + suggestionsCount;
+  if (totalCount > 0) {
+    consola.error(
+      colors.red(
+        `${UNICODE.FAILURE} ${totalCount} problem (${errorCount} errors, ${warningCount} warnings, ${suggestionsCount} suggestions)`,
+      ),
+    );
+    !check && process.exit(1);
+  } else {
+    consola.log(colors.green(`${UNICODE.SUCCESS} No problem`));
+  }
+}
+
+function definePubLintCommand(cac: CAC) {
+  cac
+    .command('publint [...files]')
+    .usage('Check if the monorepo package conforms to the publint standard.')
+    .option('--check', 'Only errors are checked, no program exit is performed.')
+    .action(runPublint);
+}
+
+export { definePubLintCommand };
diff --git a/eims-ui/scripts/vsh/tsconfig.json b/eims-ui/scripts/vsh/tsconfig.json
new file mode 100644
index 0000000..b2ec3b6
--- /dev/null
+++ b/eims-ui/scripts/vsh/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/tsconfig",
+  "extends": "@vben/tsconfig/node.json",
+  "include": ["src"],
+  "exclude": ["node_modules"]
+}
diff --git "a/eims-ui/scripts/\350\217\234\345\215\225\345\233\276\346\240\207\346\233\277\346\215\242sql/update_icon.sql" "b/eims-ui/scripts/\350\217\234\345\215\225\345\233\276\346\240\207\346\233\277\346\215\242sql/update_icon.sql"
new file mode 100644
index 0000000..ea289d8
--- /dev/null
+++ "b/eims-ui/scripts/\350\217\234\345\215\225\345\233\276\346\240\207\346\233\277\346\215\242sql/update_icon.sql"
@@ -0,0 +1,46 @@
+UPDATE sys_menu SET icon = 'eos-icons:system-group' WHERE menu_id = 1;
+UPDATE sys_menu SET icon = 'solar:monitor-bold-duotone' WHERE menu_id = 2;
+UPDATE sys_menu SET icon = 'mdi:tools' WHERE menu_id = 3;
+UPDATE sys_menu SET icon = 'flat-color-icons:plus' WHERE menu_id = 4;
+UPDATE sys_menu SET icon = 'devicon:vscode' WHERE menu_id = 5;
+UPDATE sys_menu SET icon = 'ic:baseline-house' WHERE menu_id = 6;
+UPDATE sys_menu SET icon = 'ph:user-duotone' WHERE menu_id = 100;
+UPDATE sys_menu SET icon = 'eos-icons:role-binding-outlined' WHERE menu_id = 101;
+UPDATE sys_menu SET icon = 'ic:sharp-menu' WHERE menu_id = 102;
+UPDATE sys_menu SET icon = 'mingcute:department-line' WHERE menu_id = 103;
+UPDATE sys_menu SET icon = 'icon-park-outline:appointment' WHERE menu_id = 104;
+UPDATE sys_menu SET icon = 'fluent-mdl2:dictionary' WHERE menu_id = 105;
+UPDATE sys_menu SET icon = 'icon-park-twotone:setting-two' WHERE menu_id = 106;
+UPDATE sys_menu SET icon = 'fe:notice-push' WHERE menu_id = 107;
+UPDATE sys_menu SET icon = 'material-symbols:logo-dev-outline' WHERE menu_id = 108;
+UPDATE sys_menu SET icon = 'material-symbols:generating-tokens-outline' WHERE menu_id = 109;
+UPDATE sys_menu SET icon = 'devicon:redis-wordmark' WHERE menu_id = 113;
+UPDATE sys_menu SET icon = 'fluent:form-new-24-regular' WHERE menu_id = 114;
+UPDATE sys_menu SET icon = 'tabler:code' WHERE menu_id = 115;
+UPDATE sys_menu SET icon = 'devicon:spring-wordmark' WHERE menu_id = 117;
+UPDATE sys_menu SET icon = 'solar:folder-with-files-outline' WHERE menu_id = 118;
+UPDATE sys_menu SET icon = 'akar-icons:schedule' WHERE menu_id = 120;
+UPDATE sys_menu SET icon = 'bi:houses-fill' WHERE menu_id = 121;
+UPDATE sys_menu SET icon = 'bx:package' WHERE menu_id = 122;
+UPDATE sys_menu SET icon = 'simple-icons:authy' WHERE menu_id = 123;
+UPDATE sys_menu SET icon = 'arcticons:one-hand-operation' WHERE menu_id = 500;
+UPDATE sys_menu SET icon = 'streamline:interface-login-dial-pad-finger-password-dial-pad-dot-finger' WHERE menu_id = 501;
+
+UPDATE sys_menu SET icon = 'lucide:table' WHERE menu_id = 1500;
+UPDATE sys_menu SET icon = 'emojione:evergreen-tree' WHERE menu_id = 1506;
+
+/*UPDATE sys_menu SET icon = 'icon-park-twotone:web-page' WHERE menu_id = 4; PLUS瀹樼綉 */
+UPDATE sys_menu SET icon = 'mdi:workflow-outline' WHERE menu_id = 11616;
+UPDATE sys_menu SET icon = 'carbon:model-alt' WHERE menu_id = 11617;
+UPDATE sys_menu SET icon = 'carbon:task-approved' WHERE menu_id = 11618;
+UPDATE sys_menu SET icon = 'ri:todo-line' WHERE menu_id = 11619;
+UPDATE sys_menu SET icon = 'fluent-mdl2:build-definition' WHERE menu_id = 11620;
+UPDATE sys_menu SET icon = 'ri:instance-line' WHERE menu_id = 11621;
+UPDATE sys_menu SET icon = 'tabler:category-plus' WHERE menu_id = 11622;
+UPDATE sys_menu SET icon = 'ic:round-launch' WHERE menu_id = 11629;
+UPDATE sys_menu SET icon = 'icon-park-outline:monitor' WHERE menu_id = 11630;
+UPDATE sys_menu SET icon = 'ri:todo-line' WHERE menu_id = 11631;
+UPDATE sys_menu SET icon = 'material-symbols:cloud-done-outline-rounded' WHERE menu_id = 11632;
+UPDATE sys_menu SET icon = 'mdi:cc-outline' WHERE menu_id = 11633;
+UPDATE sys_menu SET icon = 'fluent-mdl2:leave-user' WHERE menu_id = 11638;
+UPDATE sys_menu SET icon = 'fluent:form-24-regular' WHERE menu_id = 11628;
diff --git a/eims-ui/stylelint.config.mjs b/eims-ui/stylelint.config.mjs
new file mode 100644
index 0000000..e380674
--- /dev/null
+++ b/eims-ui/stylelint.config.mjs
@@ -0,0 +1,4 @@
+export default {
+  extends: ['@vben/stylelint-config'],
+  root: true,
+};
diff --git a/eims-ui/tea.yaml b/eims-ui/tea.yaml
new file mode 100644
index 0000000..6e56d6f
--- /dev/null
+++ b/eims-ui/tea.yaml
@@ -0,0 +1,6 @@
+# https://tea.xyz/what-is-this-file
+---
+version: 1.0.0
+codeOwners:
+  - '0xB33cc732DFc15Cd39eF50Fb165c876E24417E48f'
+quorum: 1
diff --git a/eims-ui/turbo.json b/eims-ui/turbo.json
new file mode 100644
index 0000000..3443e27
--- /dev/null
+++ b/eims-ui/turbo.json
@@ -0,0 +1,49 @@
+{
+  "$schema": "https://turbo.build/schema.json",
+  "globalDependencies": [
+    "pnpm-lock.yaml",
+    "**/.env.*local",
+    "**/tsconfig*.json",
+    "internal/node-utils/*.json",
+    "internal/node-utils/src/**/*.ts",
+    "internal/tailwind-config/src/**/*.ts",
+    "internal/vite-config/*.json",
+    "internal/vite-config/src/**/*.ts",
+    "scripts/*/src/**/*.ts",
+    "scripts/*/src/**/*.json"
+  ],
+  "globalEnv": ["NODE_ENV"],
+  "tasks": {
+    "build": {
+      "dependsOn": ["^build"],
+      "outputs": [
+        "dist/**",
+        "dist.zip",
+        ".vitepress/dist.zip",
+        ".vitepress/dist/**"
+      ]
+    },
+    "preview": {
+      "dependsOn": ["^build"],
+      "outputs": ["dist/**"]
+    },
+    "build:analyze": {
+      "dependsOn": ["^build"],
+      "outputs": ["dist/**"]
+    },
+    "@vben/backend-mock#build": {
+      "dependsOn": ["^build"],
+      "outputs": [".nitro/**", ".output/**"]
+    },
+    "test:e2e": {},
+    "dev": {
+      "dependsOn": [],
+      "outputs": [],
+      "cache": false,
+      "persistent": true
+    },
+    "typecheck": {
+      "outputs": []
+    }
+  }
+}
diff --git a/eims-ui/vitest.config.ts b/eims-ui/vitest.config.ts
new file mode 100644
index 0000000..a10b5fa
--- /dev/null
+++ b/eims-ui/vitest.config.ts
@@ -0,0 +1,11 @@
+import Vue from '@vitejs/plugin-vue';
+import VueJsx from '@vitejs/plugin-vue-jsx';
+import { configDefaults, defineConfig } from 'vitest/config';
+
+export default defineConfig({
+  plugins: [Vue(), VueJsx()],
+  test: {
+    environment: 'happy-dom',
+    exclude: [...configDefaults.exclude, '**/e2e/**'],
+  },
+});
diff --git a/eims-ui/vitest.workspace.ts b/eims-ui/vitest.workspace.ts
new file mode 100644
index 0000000..f00d6f6
--- /dev/null
+++ b/eims-ui/vitest.workspace.ts
@@ -0,0 +1,3 @@
+import { defineWorkspace } from 'vitest/config';
+
+export default defineWorkspace(['vitest.config.ts']);
diff --git a/eims/.DS_Store b/eims/.DS_Store
new file mode 100644
index 0000000..a6ee1b3
--- /dev/null
+++ b/eims/.DS_Store
Binary files differ
diff --git a/eims/.editorconfig b/eims/.editorconfig
new file mode 100644
index 0000000..25b312e
--- /dev/null
+++ b/eims/.editorconfig
@@ -0,0 +1,18 @@
+# http://editorconfig.org
+root = true
+
+# 绌烘牸鏇夸唬Tab缂╄繘鍦ㄥ悇绉嶇紪杈戝伐鍏蜂笅鏁堟灉涓�鑷�
+[*]
+indent_style = space
+indent_size = 4
+charset = utf-8
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{json,yml,yaml}]
+indent_size = 2
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/eims/.gitignore b/eims/.gitignore
new file mode 100644
index 0000000..fa3ee97
--- /dev/null
+++ b/eims/.gitignore
@@ -0,0 +1,48 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### JRebel ###
+rebel.xml
+
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
+
+.flattened-pom.xml
diff --git a/eims/.run/ruoyi-monitor-admin.run.xml b/eims/.run/ruoyi-monitor-admin.run.xml
new file mode 100644
index 0000000..478b4f3
--- /dev/null
+++ b/eims/.run/ruoyi-monitor-admin.run.xml
@@ -0,0 +1,12 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
+    <deployment type="dockerfile">
+      <settings>
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" />
+        <option name="buildOnly" value="true" />
+        <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
+      </settings>
+    </deployment>
+    <method v="2" />
+  </configuration>
+</component>
diff --git a/eims/.run/ruoyi-server.run.xml b/eims/.run/ruoyi-server.run.xml
new file mode 100644
index 0000000..541800d
--- /dev/null
+++ b/eims/.run/ruoyi-server.run.xml
@@ -0,0 +1,12 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="婕旂ず鏈�">
+    <deployment type="dockerfile">
+      <settings>
+        <option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" />
+        <option name="buildOnly" value="true" />
+        <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
+      </settings>
+    </deployment>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/eims/.run/ruoyi-snailjob-server.run.xml b/eims/.run/ruoyi-snailjob-server.run.xml
new file mode 100644
index 0000000..5221eef
--- /dev/null
+++ b/eims/.run/ruoyi-snailjob-server.run.xml
@@ -0,0 +1,12 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
+    <deployment type="dockerfile">
+      <settings>
+        <option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" />
+        <option name="buildOnly" value="true" />
+        <option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
+      </settings>
+    </deployment>
+    <method v="2" />
+  </configuration>
+</component>
diff --git a/eims/LICENSE b/eims/LICENSE
new file mode 100644
index 0000000..32b3071
--- /dev/null
+++ b/eims/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2019 RuoYi-Vue-Plus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/eims/README.md b/eims/README.md
new file mode 100644
index 0000000..eeb3f7b
--- /dev/null
+++ b/eims/README.md
@@ -0,0 +1,182 @@
+<img src="https://foruda.gitee.com/images/1679673773341074847/178e8451_1766278.png" width="50%" height="50%">
+<div style="height: 10px; clear: both;"></div>
+
+- - -
+## 骞冲彴绠�浠�
+
+[![鐮佷簯Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus)
+[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
+[![浣跨敤IntelliJ IDEA寮�鍙戠淮鎶(https://img.shields.io/badge/IntelliJ%20IDEA-鎻愪緵鏀寔-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
+<br>
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]()
+[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
+[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
+
+> RuoYi-Vue-Plus 鏄噸鍐� RuoYi-Vue 閽堝 `鍒嗗竷寮忛泦缇や笌澶氱鎴穈 鍦烘櫙鍏ㄦ柟浣嶅崌绾�(涓嶅吋瀹瑰師妗嗘灦)
+
+> 椤圭洰浠g爜銆佹枃妗� 鍧囧紑婧愬厤璐瑰彲鍟嗙敤 閬靛惊寮�婧愬崗璁湪椤圭洰涓繚鐣欏紑婧愬崗璁枃浠跺嵆鍙�<br>
+娲诲埌鑰佸啓鍒拌�� 涓哄叴瓒h�屽紑婧� 涓哄涔犺�屽紑婧� 涓鸿澶у鐪熸鍙互瀛﹀埌鎶�鏈�屽紑婧�
+
+> 绯荤粺婕旂ず: [浼犻�侀棬](https://plus-doc.dromara.org/#/common/demo_system)
+
+> 鍓嶇椤圭洰鍦板潃: [plus-ui](https://gitee.com/JavaLionLi/plus-ui)
+
+> 鏂囨。鍦板潃: [plus-doc](https://plus-doc.dromara.org)
+
+## 璧炲姪鍟�
+
+MaxKey 涓氱晫棰嗗厛鍗曠偣鐧诲綍浜у搧 - https://gitee.com/dromara/MaxKey <br>
+CCFlow 椹拌仒浣庝唬鐮�-娴佺▼-琛ㄥ崟 - https://gitee.com/opencc/RuoYi-JFlow <br>
+鏁拌埖绉戞妧 杞欢瀹氬埗寮�鍙慉PP灏忕▼搴忕瓑 - http://www.shuduokeji.com/ <br>
+寮曡繄淇℃伅 杞欢寮�鍙戝钩鍙� - https://www.jnpfsoft.com/index.html?from=plus-doc <br>
+[濡備綍鎴愪负璧炲姪鍟� 鍔犵兢鑱旂郴浣滆�呰璋圿(https://plus-doc.dromara.org/#/common/add_group)
+
+# 鏈鏋朵笌RuoYi鐨勫姛鑳藉樊寮�
+
+| 鍔熻兘          | 鏈鏋�                                                                                                               | RuoYi                                                                              |
+|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
+| 鍓嶇椤圭洰        | 閲囩敤 Vue3 + TS + ElementPlus 閲嶅啓                                                                                     | 鍩轰簬Vue2/Vue3 + JS                                                                   | 
+| 鍚庣椤圭洰缁撴瀯      | 閲囩敤鎻掍欢鍖� + 鎵╁睍鍖呭舰寮� 缁撴瀯瑙h�� 鏄撲簬鎵╁睍                                                                                           | 妯″潡鐩镐簰娉ㄥ叆鑰﹀悎涓ラ噸闅句互鎵╁睍                                                                     | 
+| 鍚庣浠g爜椋庢牸      | 涓ユ牸閬靛畧Alibaba瑙勮寖涓庨」鐩粺涓�閰嶇疆鐨勪唬鐮佹牸寮忓寲                                                                                        | 浠g爜涔﹀啓涓庡父瑙勭粨鏋勪笉鍚岄槄璇婚殰纰嶅ぇ                                                                   |
+| Web瀹瑰櫒       | 閲囩敤 Undertow 鍩轰簬 XNIO 鐨勯珮鎬ц兘瀹瑰櫒                                                                                        | 閲囩敤 Tomcat                                                                          |
+| 鏉冮檺璁よ瘉        | 閲囩敤 Sa-Token銆丣wt 闈欐�佷娇鐢ㄥ姛鑳介綈鍏� 浣庤�﹀悎 楂樻墿灞�                                                                                  | Spring Security 閰嶇疆绻佺悙鎵╁睍鎬ф瀬宸�                                                          |
+| 鏉冮檺娉ㄨВ        | 閲囩敤 Sa-Token 鏀寔娉ㄨВ 鐧诲綍鏍¢獙銆佽鑹叉牎楠屻�佹潈闄愭牎楠屻�佷簩绾ц璇佹牎楠屻�丠ttpBasic鏍¢獙銆佸拷鐣ユ牎楠�<br/>瑙掕壊涓庢潈闄愭牎楠屾敮鎸佸绉嶆潯浠� 濡� `AND` `OR` 鎴� `鏉冮檺 OR 瑙掕壊` 绛夊鏉傝〃杈惧紡        | 鍙敮鎸佹槸鍚﹀瓨鍦ㄥ尮閰�                                                                          |
+| 涓夋柟閴存潈        | 閲囩敤 JustAuth 绗笁鏂圭櫥褰曠粍浠� 鏀寔寰俊銆侀拤閽夌瓑鏁板崄绉嶄笁鏂硅璇�                                                                               | 鏃�                                                                                  |
+| 鍏崇郴鏁版嵁搴撴敮鎸�     | 鍘熺敓鏀寔 MySQL銆丱racle銆丳ostgreSQL銆丼QLServer<br/>鍙悓鏃朵娇鐢ㄥ紓鏋勫垏鎹�(鏀寔鍏朵粬 mybatis-plus 鏀寔鐨勬墍鏈夋暟鎹簱 鍙渶瑕佸鍔爅dbc渚濊禆鍗冲彲浣跨敤 杈炬ⅵ閲戜粨绛夊潎鏈夋垚鍔熸渚�)      | 鏀寔 Mysql銆丱racle 涓嶆敮鎸佸悓鏃朵娇鐢ㄣ�佷笉鏀寔寮傛瀯鍒囨崲                                                    |
+| 缂撳瓨鏁版嵁搴�       | 鏀寔 Redis 5-7 鏀寔澶ч儴鍒嗘柊鍔熻兘鐗规�� 濡� 鍒嗗竷寮忛檺娴併�佸垎甯冨紡闃熷垪                                                                             | Redis 绠�鍗� get set 鏀寔                                                                |
+| Redis瀹㈡埛绔�    | 閲囩敤 Redisson Redis瀹樻柟鎺ㄨ崘 鍩轰簬Netty鐨勫鎴风宸ュ叿<br/>鏀寔Redis 90%浠ヤ笂鐨勫懡浠� 搴曞眰浼樺寲瑙勯伩寰堝涓嶆纭殑鐢ㄦ硶 渚嬪: keys琚浆鎹负scan<br/>鏀寔鍗曟満銆佸摠鍏点�佸崟涓婚泦缇ゃ�佸涓婚泦缇ょ瓑妯″紡 | Lettuce + RedisTemplate 鏀寔妯″紡灏� 宸ュ叿浣跨敤绻佺悙<br/>杩炴帴姹犻噰鐢� common-pool Bug澶氱粡甯告�у嚭闂              |
+| 缂撳瓨娉ㄨВ        | 閲囩敤 Spring-Cache 娉ㄨВ 瀵瑰叾鎵╁睍浜嗗疄鐜版敮鎸佷簡鏇村鍔熻兘<br/>渚嬪 杩囨湡鏃堕棿 鏈�澶х┖闂叉椂闂� 缁勬渶澶ч暱搴︾瓑 鍙渶涓�涓敞瑙e嵆鍙畬鎴愭暟鎹嚜鍔ㄧ紦瀛�                                      | 闇�鎵嬪姩缂栧啓Redis浠g爜閫昏緫                                                                     |
+| ORM妗嗘灦       | 閲囩敤 Mybatis-Plus 鍩轰簬瀵硅薄鍑犱箮涓嶇敤鍐橲QL鍏╦ava鎿嶄綔 鍔熻兘寮哄ぇ鎻掍欢浼楀<br/>渚嬪澶氱鎴锋彃浠� 鍒嗛〉鎻掍欢 涔愯閿佹彃浠剁瓑绛�                                             | 閲囩敤 Mybatis 鍩轰簬XML闇�瑕佹墜鍐橲QL                                                            |
+| SQL鐩戞帶       | 閲囩敤 p6spy 鍙緭鍑哄畬鏁碨QL涓庢墽琛屾椂闂寸洃鎺�                                                                                          | log杈撳嚭 闇�鎵嬪姩鎷兼帴sql涓庡弬鏁版棤娉曞揩閫熸煡鐪嬭皟璇曢棶棰�                                                        |
+| 鏁版嵁鍒嗛〉        | 閲囩敤 Mybatis-Plus 鍒嗛〉鎻掍欢<br/>妗嗘灦瀵瑰叾杩涜浜嗘墿灞� 瀵硅薄鍖栧垎椤靛璞� 鏀寔澶氱鏂瑰紡浼犲弬 鏀寔鍓嶇澶氭帓搴� 澶嶆潅鎺掑簭                                                  | 閲囩敤 PageHelper 浠呮敮鎸佸崟鏌ヨ鍒嗛〉 鍙傛暟鍙兘浠巔aram浼� 鍙兘鍗曟帓搴� 鍔熻兘鎵╁睍鎬у樊 浣撻獙涓嶅ソ                               |
+| 鏁版嵁鏉冮檺        | 閲囩敤 Mybatis-Plus 鎻掍欢 鑷鍒嗘瀽鎷兼帴SQL 鏃犳劅寮忚繃婊�<br/>鍙渶涓篗apper璁剧疆濂芥敞瑙f潯浠� 鏀寔澶氱鑷畾涔� 涓嶉檺浜庨儴闂ㄨ鑹�                                           | 閲囩敤 娉ㄨВ+aop 瀹炵幇 鍩轰簬閮ㄩ棬瑙掕壊 鐢熸垚鐨剆ql鍏煎鎬у樊 涓嶆敮鎸佸叾浠栦笟鍔℃墿灞�<br/>鐢熸垚sql鍚庨渶鎵嬪姩鎷兼帴鍒板叿浣撲笟鍔ql涓� 瀵逛簬澶氫釜Mapper鏌ヨ涓嶈捣浣滅敤 |
+| 鏁版嵁鑴辨晱        | 閲囩敤 娉ㄨВ + jackson 搴忓垪鍖栨湡闂磋劚鏁� 鏀寔涓嶅悓妯″潡涓嶅悓鐨勮劚鏁忔潯浠�<br/>鏀寔澶氱绛栫暐 濡傝韩浠借瘉銆佹墜鏈哄彿銆佸湴鍧�銆侀偖绠便�侀摱琛屽崱绛� 鍙嚜琛屾墿灞�                                        | 鏃�                                                                                  |
+| 鏁版嵁鍔犺В瀵�       | 閲囩敤 娉ㄨВ + mybatis 鎷︽埅鍣� 瀵瑰瓨鍙栨暟鎹湡闂磋嚜鍔ㄥ姞瑙e瘑<br/>鏀寔澶氱绛栫暐 濡侭ASE64銆丄ES銆丷SA銆丼M2銆丼M4绛�                                              | 鏃�                                                                                  |
+| 鎺ュ彛浼犺緭鍔犲瘑      | 閲囩敤 鍔ㄦ�� AES + RSA 鍔犲瘑璇锋眰 body 姣忎竴娆¤姹傜閽ラ兘涓嶅悓澶у箙搴﹂檷浣庡彲鐮磋В鎬�                                                                     | 鏃�                                                                                  |
+| 鏁版嵁缈昏瘧        | 閲囩敤 娉ㄨВ + jackson 搴忓垪鍖栨湡闂村姩鎬佷慨鏀规暟鎹� 鏁版嵁杩涜缈昏瘧<br/>鏀寔澶氱妯″紡: `鏄犲皠缈昏瘧` `鐩存帴缈昏瘧` `鍏朵粬鎵╁睍鏉′欢缈昏瘧` 鎺ュ彛鍖栦袱姝ュ嵆鍙畬鎴愯嚜瀹氫箟鎵╁睍 鍐呯疆澶氱缈昏瘧瀹炵幇                   | 鏃�                                                                                  |
+| 澶氭暟鎹簮妗嗘灦      | 閲囩敤 dynamic-datasource 鏀寔甯傞潰澶ч儴鍒嗘暟鎹簱<br/>閫氳繃yml閰嶇疆鍗冲彲鍔ㄦ�佺鐞嗗紓鏋勪笉鍚岀绫荤殑鏁版嵁搴� 涔熷彲閫氳繃鍓嶇椤甸潰娣诲姞鏁版嵁婧�<br/>鏀寔spel琛ㄨ揪寮忎粠璇锋眰澶村弬鏁扮瓑鏉′欢鍒囨崲鏁版嵁婧�            | 鍩轰簬 druid 鎵嬪姩缂栧啓浠g爜閰嶇疆鏁版嵁婧� 閰嶇疆绻佺悙 鏀寔鎬у樊                                                     |
+| 澶氭暟鎹簮浜嬪姟      | 閲囩敤 dynamic-datasource 鏀寔澶氭暟鎹簮涓嶅悓绉嶇被鐨勬暟鎹簱浜嬪姟鍥炴粴                                                                          | 涓嶆敮鎸�                                                                                |
+| 鏁版嵁搴撹繛鎺ユ睜      | 閲囩敤 HikariCP Spring瀹樻柟鍐呯疆杩炴帴姹� 閰嶇疆绠�鍗� 浠ユ�ц兘涓庣ǔ瀹氭�ч椈鍚嶅ぉ涓�                                                                        | 閲囩敤 druid bug浼楀 绀惧尯缁存姢宸� 娲昏穬搴︿綆 閰嶇疆浼楀绻佺悙鎬ц兘涓�鑸�                                               |
+| 鏁版嵁搴撲富閿�       | 閲囩敤 闆姳ID 鍩轰簬鏃堕棿鎴崇殑 鏈夊簭澧為暱 鍞竴ID 鍐嶄篃涓嶇敤涓哄垎搴撳垎琛� 鏁版嵁鍚堝苟涓婚敭鍐茬獊閲嶅鑰屽彂鎰�                                                                  | 閲囩敤 鏁版嵁搴撹嚜澧濱D 鏀寔鏁版嵁閲忔湁闄� 涓嶆敮鎸佸鏁版嵁婧愪富閿敮涓�                                                     |
+| WebSocket鍗忚 | 鍩轰簬 Spring 灏佽鐨� WebSocket 鍗忚 鎵╁睍浜員oken閴存潈涓庡垎甯冨紡浼氳瘽鍚屾 涓嶅啀鍙槸鍩轰簬鍗曟満鐨勫簾鐗�                                                         | 鏃�                                                                                  |
+| SSE鎺ㄩ��       | 閲囩敤 Spring SSE 瀹炵幇 鎵╁睍浜員oken閴存潈涓庡垎甯冨紡浼氳瘽鍚屾                                                                               | 鏃�                                                                                  |
+| 搴忓垪鍖�         | 閲囩敤 Jackson Spring瀹樻柟鍐呯疆搴忓垪鍖� 闈犺氨!!!                                                                                    | 閲囩敤 fastjson bugjson 杩滆繎闂诲悕                                                           | 
+| 鍒嗗竷寮忓箓绛�       | 鍙傝�冪編鍥TIS闃查噸绯荤粺绠�鍖栧疄鐜�(缁嗚妭鍙湅鏂囨。)                                                                                          | 鎵嬪姩缂栧啓娉ㄨВ鍩轰簬aop瀹炵幇                                                                      |
+| 鍒嗗竷寮忛攣        | 閲囩敤 Lock4j 搴曞眰鍩轰簬 Redisson                                                                                           | 鏃�                                                                                  |
+| 鍒嗗竷寮忎换鍔¤皟搴�     | 閲囩敤 SnailJob 澶╃敓鏀寔鍒嗗竷寮� 缁熶竴鐨勭鐞嗕腑蹇� 鏀寔澶氱鏁版嵁搴� 鏀寔鍒嗙墖閲嶈瘯DAG浠诲姟娴佺瓑                                                                 | 閲囩敤 Quartz 鍩轰簬鏁版嵁搴撻攣鎬ц兘宸� 闆嗙兢闇�瑕佸仛寰堝閰嶇疆涓庢敼閫�                                                   | 
+| 鏂囦欢瀛樺偍        | 閲囩敤 Minio 鍒嗗竷寮忔枃浠跺瓨鍌� 澶╃敓鏀寔澶氭満銆佸纭洏銆佸鍒嗙墖銆佸鍓湰瀛樺偍<br/>鏀寔鏉冮檺绠$悊 瀹夊叏鍙潬 鏂囦欢鍙姞瀵嗗瓨鍌�                                                     | 閲囩敤 鏈満鏂囦欢瀛樺偍 鏂囦欢瑁告紡 鏄撲涪澶辨硠婕� 涓嶆敮鎸侀泦缇ゆ湁鍗曠偣鏁堝簲                                                    |
+| 浜戝瓨鍌�         | 閲囩敤 AWS S3 鍗忚瀹㈡埛绔� 鏀寔 涓冪墰銆侀樋閲屻�佽吘璁� 绛変竴鍒囨敮鎸丼3鍗忚鐨勫巶瀹�                                                                          | 涓嶆敮鎸�                                                                                |
+| 鐭俊          | 閲囩敤 sms4j 鐭俊铻嶅悎鍖� 鏀寔鏁板崄绉嶇煭淇″巶瀹� 鍙渶鍦▂ml閰嶇疆濂藉巶瀹跺瘑閽ュ嵆鍙娇鐢� 鍙鍘傚鍏辩敤                                                                 | 涓嶆敮鎸�                                                                                |
+| 閭欢          | 閲囩敤 mail-api 閫氱敤鍗忚鏀寔澶ч儴鍒嗛偖浠跺巶鍟�                                                                                         | 涓嶆敮鎸�                                                                                |
+| 鎺ュ彛鏂囨。        | 閲囩敤 SpringDoc銆乯avadoc 鏃犳敞瑙i浂鍏ヤ镜鍩轰簬java娉ㄩ噴<br/>鍙渶鎶婃敞閲婂啓濂� 鏃犻渶鍐嶅啓涓�澶у爢鐨勬枃妗f敞瑙d簡                                                     | 閲囩敤 Springfox 宸插仠姝㈢淮鎶� 闇�瑕佺紪鍐欏ぇ閲忕殑娉ㄨВ鏉ユ敮鎸佹枃妗g敓鎴�                                                | 
+| 鏍¢獙妗嗘灦        | 閲囩敤 Validation 鏀寔娉ㄨВ涓庡伐鍏风被鏍¢獙 娉ㄨВ鏀寔鍥介檯鍖�                                                                                  | 浠呮敮鎸佹敞瑙� 涓旀敞瑙d笉鏀寔鍥介檯鍖�                                                                    |
+| Excel妗嗘灦     | 閲囩敤 Alibaba EasyExcel 鍩轰簬鎻掍欢鍖�<br/>妗嗘灦瀵瑰叾澧炲姞浜嗗緢澶氬姛鑳� 渚嬪 鑷姩鍚堝苟鐩稿悓鍐呭 鑷姩鎺掑垪甯冨眬 瀛楀吀缈昏瘧绛�                                               | 鍩轰簬 POI 鎵嬪啓瀹炵幇 鍔熻兘鏈夐檺 澶嶆潅 鎵╁睍鎬у樊                                                           |
+| 宸ヤ綔娴佹敮鎸�       | 鏀寔鍚勭澶嶆潅瀹℃壒 杞姙 濮旀淳 鍔犲噺绛� 浼氱 鎴栫 绁ㄧ 绛夊姛鑳�                                                                                   | 鏃�                                                                                  |
+| 宸ュ叿绫绘鏋�       | 閲囩敤 Hutool銆丩ombok 涓婄櫨绉嶅伐鍏疯鐩�90%鐨勪娇鐢ㄩ渶姹� 鍩轰簬娉ㄨВ鑷姩鐢熸垚 get set 绛夌畝鍖栨鏋跺ぇ閲忎唬鐮�                                                       | 鎵嬪啓宸ュ叿绋冲畾鎬у樊鏄撳嚭闂 宸ュ叿鏁伴噺鏈夐檺 浠g爜鑷冭偪闇�鑷繁鎵嬪啓 get set 绛�                                            | 
+| 鐩戞帶妗嗘灦        | 閲囩敤 SpringBoot-Admin 鍩轰簬SpringBoot瀹樻柟 actuator 鎺㈤拡鏈哄埗<br/>瀹炴椂鐩戞帶鏈嶅姟鐘舵�� 妗嗘灦杩樹负鍏舵墿灞曚簡鍦ㄧ嚎鏃ュ織鏌ョ湅鐩戞帶                                    | 鏃�                                                                                  | 
+| 閾捐矾杩借釜        | 閲囩敤 Apache SkyWalking 杩樺湪涓鸿姹備笉鐭ラ亾鍘诲摢浜� 鍒板摢鍑轰簡闂鑰岀儲鎭煎悧<br/>鐢ㄤ簡瀹冨嵆鍙疄鏃舵煡鐪嬭姹傜粡杩囩殑姣忎竴澶勬瘡涓�涓妭鐐�                                            | 鏃�                                                                                  |
+| 浠g爜鐢熸垚鍣�       | 鍙渶璁捐濂借〃缁撴瀯 涓�閿敓鎴愭墍鏈塩rud浠g爜涓庨〉闈�<br/>闄嶄綆80%鐨勫紑鍙戦噺 鎶婄簿鍔涢兘鎶曞叆鍒颁笟鍔¤璁′笂<br/>妗嗘灦涓哄叾閫傞厤MP銆丼pringDoc瑙勮寖鍖栦唬鐮� 鍚屾椂鏀寔鍔ㄦ�佸鏁版嵁婧愪唬鐮佺敓鎴�                    | 浠g爜鐢熸垚鍘熺敓缁撴瀯 鍙敮鎸佸崟鏁版嵁婧愮敓鎴�                                                                 |
+| 閮ㄧ讲鏂瑰紡        | 鏀寔 Docker 缂栨帓 涓�閿惌寤烘墍鏈夌幆澧� 璁╁紑鍙戜汉鍛樹粠姝や笉鍐嶄负鎼缓鐜鑰岀儲鎭�                                                                           | 鍘熺敓jar閮ㄧ讲 鍏朵粬鐜闇�鎵嬪姩涓嬭浇瀹夎 鑷鎼缓                                                           | 
+| 椤圭洰璺緞淇敼      | 鎻愪緵璇︾粏鐨勪慨鏀规柟妗堟枃妗� 骞朵负鍏跺仛浜嗕竴浜涙敼鍔� 闈炲父绠�鍗曞嵆鍙慨鏀规垚鑷繁鎯宠鐨�                                                                              | 闇�瑕佸仛寰堝鏀归�� 鏂囨。璇存槑鏈夐檺                                                                     |
+| 鍥介檯鍖�         | 鍩轰簬璇锋眰澶村姩鎬佽繑鍥炰笉鍚岃绉嶇殑鏂囨湰鍐呭 寮�鍙戦毦搴︿綆 鏈夊搴旂殑宸ュ叿绫� 鏀寔澶ч儴鍒嗘敞瑙e唴瀹瑰浗闄呭寲                                                                     | 鍙彁渚涘熀纭�鍔熻兘 鍏朵粬闇�鑷缂栧啓鎵╁睍                                                                  |
+| 浠g爜鍗曚緥娴嬭瘯      | 鎻愪緵鍗曚緥娴嬭瘯 浣跨敤鏂瑰紡缂栧啓鏂规硶涓巑aven澶氱幆澧冨崟娴嬫彃浠�                                                                                      | 鍙彁渚涘熀纭�鍔熻兘 鍏朵粬闇�鑷缂栧啓鎵╁睍                                                                  |
+| Demo妗堜緥      | 鎻愪緵妗嗘灦鍔熻兘鐨勫疄闄呬娇鐢ㄦ渚� 鍗曠嫭涓�涓ā鍧楁彁渚涗簡寰堝寰堝叏                                                                                       | 鏃�                                                                                  |
+
+
+## 鏈鏋朵笌RuoYi鐨勪笟鍔″樊寮�
+
+| 涓氬姟     | 鍔熻兘璇存槑                                                                 | 鏈鏋� | RuoYi            |
+|--------|----------------------------------------------------------------------|-----|------------------|
+| 绉熸埛绠$悊   | 绯荤粺鍐呯鎴风殑绠$悊 濡�:绉熸埛濂楅銆佽繃鏈熸椂闂淬�佺敤鎴锋暟閲忋�佷紒涓氫俊鎭瓑                                      | 鏀寔  | 鏃�                |
+| 绉熸埛濂楅绠$悊 | 绯荤粺鍐呯鎴锋墍鑳戒娇鐢ㄧ殑濂楅绠$悊 濡�:濂楅鍐呮墍鍖呭惈鐨勮彍鍗曠瓑                                          | 鏀寔  | 鏃�                |
+| 瀹㈡埛绔鐞�  | 绯荤粺鍐呭鎺ョ殑鎵�鏈夊鎴风绠$悊 濡�: pc绔�佸皬绋嬪簭绔瓑<br>鏀寔鍔ㄦ�佹巿鏉冪櫥褰曟柟寮� 濡�: 鐭俊鐧诲綍銆佸瘑鐮佺櫥褰曠瓑 鏀寔鍔ㄦ�佹帶鍒秚oken鏃舵晥 | 鏀寔  | 鏃�                |
+| 鐢ㄦ埛绠$悊   | 鐢ㄦ埛鐨勭鐞嗛厤缃� 濡�:鏂板鐢ㄦ埛銆佸垎閰嶇敤鎴锋墍灞為儴闂ㄣ�佽鑹层�佸矖浣嶇瓑                                       | 鏀寔  | 鏀寔               |
+| 閮ㄩ棬绠$悊   | 閰嶇疆绯荤粺缁勭粐鏈烘瀯锛堝叕鍙搞�侀儴闂ㄣ�佸皬缁勶級 鏍戠粨鏋勫睍鐜版敮鎸佹暟鎹潈闄�                                       | 鏀寔  | 鏀寔               |
+| 宀椾綅绠$悊   | 閰嶇疆绯荤粺鐢ㄦ埛鎵�灞炴媴浠昏亴鍔�                                                         | 鏀寔  | 鏀寔               |
+| 鑿滃崟绠$悊   | 閰嶇疆绯荤粺鑿滃崟銆佹搷浣滄潈闄愩�佹寜閽潈闄愭爣璇嗙瓑                                                  | 鏀寔  | 鏀寔               |
+| 瑙掕壊绠$悊   | 瑙掕壊鑿滃崟鏉冮檺鍒嗛厤銆佽缃鑹叉寜鏈烘瀯杩涜鏁版嵁鑼冨洿鏉冮檺鍒掑垎                                           | 鏀寔  | 鏀寔               |
+| 瀛楀吀绠$悊   | 瀵圭郴缁熶腑缁忓父浣跨敤鐨勪竴浜涜緝涓哄浐瀹氱殑鏁版嵁杩涜缁存姢                                               | 鏀寔  | 鏀寔               |
+| 鍙傛暟绠$悊   | 瀵圭郴缁熷姩鎬侀厤缃父鐢ㄥ弬鏁�                                                          | 鏀寔  | 鏀寔               |
+| 閫氱煡鍏憡   | 绯荤粺閫氱煡鍏憡淇℃伅鍙戝竷缁存姢                                                         | 鏀寔  | 鏀寔               |
+| 鎿嶄綔鏃ュ織   | 绯荤粺姝e父鎿嶄綔鏃ュ織璁板綍鍜屾煡璇� 绯荤粺寮傚父淇℃伅鏃ュ織璁板綍鍜屾煡璇�                                          | 鏀寔  | 鏀寔               |
+| 鐧诲綍鏃ュ織   | 绯荤粺鐧诲綍鏃ュ織璁板綍鏌ヨ鍖呭惈鐧诲綍寮傚父                                                     | 鏀寔  | 鏀寔               |
+| 鏂囦欢绠$悊   | 绯荤粺鏂囦欢灞曠ず銆佷笂浼犮�佷笅杞姐�佸垹闄ょ瓑绠$悊                                                   | 鏀寔  | 鏃�                |
+| 鏂囦欢閰嶇疆绠$悊 | 绯荤粺鏂囦欢涓婁紶銆佷笅杞芥墍闇�瑕佺殑閰嶇疆淇℃伅鍔ㄦ�佹坊鍔犮�佷慨鏀广�佸垹闄ょ瓑绠$悊                                       | 鏀寔  | 鏃�                |
+| 鍦ㄧ嚎鐢ㄦ埛绠$悊 | 宸茬櫥褰曠郴缁熺殑鍦ㄧ嚎鐢ㄦ埛淇℃伅鐩戞帶涓庡己鍒惰涪鍑烘搷浣�                                                | 鏀寔  | 鏀寔               |
+| 瀹氭椂浠诲姟   | 杩愯鎶ヨ〃銆佷换鍔$鐞�(娣诲姞銆佷慨鏀广�佸垹闄�)銆佹棩蹇楃鐞嗐�佹墽琛屽櫒绠$悊绛�                                      | 鏀寔  | 浠呮敮鎸佷换鍔′笌鏃ュ織绠$悊       |
+| 浠g爜鐢熸垚   | 澶氭暟鎹簮鍓嶅悗绔唬鐮佺殑鐢熸垚锛坖ava銆乭tml銆亁ml銆乻ql锛夋敮鎸丆RUD涓嬭浇                              | 鏀寔  | 浠呮敮鎸佸崟鏁版嵁婧�          |
+| 绯荤粺鎺ュ彛   | 鏍规嵁涓氬姟浠g爜鑷姩鐢熸垚鐩稿叧鐨刟pi鎺ュ彛鏂囨。                                                 | 鏀寔  | 鏀寔               |
+| 鏈嶅姟鐩戞帶   | 鐩戣闆嗙兢绯荤粺CPU銆佸唴瀛樸�佺鐩樸�佸爢鏍堛�佸湪绾挎棩蹇椼�丼pring鐩稿叧閰嶇疆绛�                                  | 鏀寔  | 浠呮敮鎸佸崟鏈篊PU銆佸唴瀛樸�佺鐩樼洃鎺� |
+| 缂撳瓨鐩戞帶   | 瀵圭郴缁熺殑缂撳瓨淇℃伅鏌ヨ锛屽懡浠ょ粺璁$瓑銆�                                                    | 鏀寔  | 鏀寔               |
+| 鍦ㄧ嚎鏋勫缓鍣�  | 鎷栧姩琛ㄥ崟鍏冪礌鐢熸垚鐩稿簲鐨凥TML浠g爜銆�                                                   | 鏀寔  | 鏀寔               |
+| 浣跨敤妗堜緥   | 绯荤粺鐨勪竴浜涘姛鑳芥渚�                                                            | 鏀寔  | 涓嶆敮鎸�              |
+
+## 鍙傝�冩枃妗�
+
+浣跨敤妗嗘灦鍓嶈浠旂粏闃呰鏂囨。閲嶇偣娉ㄦ剰浜嬮」
+<br>
+>[鍒濆鍖栭」鐩� 蹇呯湅](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init)
+>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init)
+>
+>[涓撴爮涓庤棰� 鍏ラ棬蹇呯湅](https://plus-doc.dromara.org/#/common/column)
+>>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column)
+>
+>[閮ㄧ讲椤圭洰 蹇呯湅](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy)
+>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy)
+>
+>[濡備綍鍔犵兢](https://plus-doc.dromara.org/#/common/add_group)
+>>[https://plus-doc.dromara.org/#/common/add_group](https://plus-doc.dromara.org/#/common/add_group)
+>
+>[鍙傝�冩枃妗� Wiki](https://plus-doc.dromara.org)
+>>[https://plus-doc.dromara.org](https://plus-doc.dromara.org)
+
+## 杞欢鏋舵瀯鍥�
+
+![Plus閮ㄧ讲鏋舵瀯鍥綸(https://foruda.gitee.com/images/1678981882624240692/ae2a3f3e_1766278.png "Plus閮ㄧ讲鏋舵瀯鍥�.png")
+
+## 濡備綍鍙備笌璐$尞
+
+[鍙備笌璐$尞鐨勬柟寮� https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution)
+
+## 鎹愮尞浣滆��
+浣滆�呬负鍏艰亴鍋氬紑婧�,骞虫椂杩橀渶瑕佸伐浣�,濡傛灉甯埌浜嗘偍鍙互璇蜂綔鑰呭悆涓洅楗�  
+<img src="https://foruda.gitee.com/images/1678975784848381069/d8661ed9_1766278.png" width="300px" height="450px" />
+<img src="https://foruda.gitee.com/images/1678975801230205215/6f96229d_1766278.png" width="300px" height="450px" />
+
+## 婕旂ず鍥句緥
+
+|                                                                                            |                                                                                            |
+|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "灞忓箷鎴浘") |
+| ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "灞忓箷鎴浘") | ![杈撳叆鍥剧墖璇存槑](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "灞忓箷鎴浘") |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eims/pom.xml b/eims/pom.xml
new file mode 100644
index 0000000..5227853
--- /dev/null
+++ b/eims/pom.xml
@@ -0,0 +1,521 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.dromara</groupId>
+    <artifactId>ruoyi-vue-plus</artifactId>
+    <version>${revision}</version>
+
+    <name>RuoYi-Vue-Plus</name>
+    <url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
+    <description>璁惧鏅鸿兘绠$悊绯荤粺</description>
+
+    <properties>
+        <revision>5.2.2</revision>
+        <spring-boot.version>3.2.9</spring-boot.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>17</java.version>
+        <mybatis.version>3.5.16</mybatis.version>
+        <springdoc.version>2.6.0</springdoc.version>
+        <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
+        <easyexcel.version>4.0.2</easyexcel.version>
+        <velocity.version>2.3</velocity.version>
+        <satoken.version>1.38.0</satoken.version>
+        <mybatis-plus.version>3.5.7</mybatis-plus.version>
+        <p6spy.version>3.9.1</p6spy.version>
+        <hutool.version>5.8.31</hutool.version>
+        <okhttp.version>4.10.0</okhttp.version>
+        <spring-boot-admin.version>3.2.3</spring-boot-admin.version>
+        <redisson.version>3.34.1</redisson.version>
+        <lock4j.version>2.2.7</lock4j.version>
+        <dynamic-ds.version>4.3.1</dynamic-ds.version>
+        <snailjob.version>1.1.2</snailjob.version>
+        <mapstruct-plus.version>1.4.4</mapstruct-plus.version>
+        <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
+        <lombok.version>1.18.34</lombok.version>
+        <bouncycastle.version>1.76</bouncycastle.version>
+        <justauth.version>1.16.6</justauth.version>
+        <!-- 绂荤嚎IP鍦板潃瀹氫綅搴� -->
+        <ip2region.version>2.7.0</ip2region.version>
+        <undertow.version>2.3.15.Final</undertow.version>
+
+        <!-- OSS 閰嶇疆 -->
+        <aws.sdk.version>2.25.15</aws.sdk.version>
+        <aws.crt.version>0.29.13</aws.crt.version>
+        <!-- SMS 閰嶇疆 -->
+        <sms4j.version>3.3.2</sms4j.version>
+        <!-- 闄愬埗妗嗘灦涓殑fastjson鐗堟湰 -->
+        <fastjson.version>1.2.83</fastjson.version>
+        <!-- 闈㈠悜杩愯鏃剁殑D-ORM渚濊禆 -->
+        <anyline.version>8.7.2-20240808</anyline.version>
+        <!--宸ヤ綔娴侀厤缃�-->
+        <flowable.version>7.0.1</flowable.version>
+
+        <!-- 鎻掍欢鐗堟湰 -->
+        <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
+        <maven-war-plugin.version>3.2.2</maven-war-plugin.version>
+        <maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison>
+        <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
+        <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
+    </properties>
+
+    <profiles>
+        <profile>
+            <id>local</id>
+            <properties>
+                <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
+                <profiles.active>local</profiles.active>
+                <logging.level>info</logging.level>
+            </properties>
+        </profile>
+        <profile>
+            <id>dev</id>
+            <properties>
+                <!-- 鐜鏍囪瘑锛岄渶瑕佷笌閰嶇疆鏂囦欢鐨勫悕绉扮浉瀵瑰簲 -->
+                <profiles.active>dev</profiles.active>
+                <logging.level>info</logging.level>
+            </properties>
+            <activation>
+                <!-- 榛樿鐜 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+        <profile>
+            <id>prod</id>
+            <properties>
+                <profiles.active>prod</profiles.active>
+                <logging.level>warn</logging.level>
+            </properties>
+        </profile>
+    </profiles>
+
+    <!-- 渚濊禆澹版槑 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringBoot鐨勪緷璧栭厤缃�-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- hutool 鐨勪緷璧栭厤缃�-->
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-bom</artifactId>
+                <version>${hutool.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.flowable</groupId>
+                <artifactId>flowable-bom</artifactId>
+                <version>${flowable.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- JustAuth 鐨勪緷璧栭厤缃�-->
+            <dependency>
+                <groupId>me.zhyd.oauth</groupId>
+                <artifactId>JustAuth</artifactId>
+                <version>${justauth.version}</version>
+            </dependency>
+
+            <!-- common 鐨勪緷璧栭厤缃�-->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-bom</artifactId>
+                <version>${revision}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
+                <version>${springdoc.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.github.therapi</groupId>
+                <artifactId>therapi-runtime-javadoc</artifactId>
+                <version>${therapi-javadoc.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel</artifactId>
+                <version>${easyexcel.version}</version>
+            </dependency>
+
+            <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- Sa-Token 鏉冮檺璁よ瘉, 鍦ㄧ嚎鏂囨。锛歨ttp://sa-token.dev33.cn/ -->
+            <dependency>
+                <groupId>cn.dev33</groupId>
+                <artifactId>sa-token-spring-boot3-starter</artifactId>
+                <version>${satoken.version}</version>
+            </dependency>
+            <!-- Sa-Token 鏁村悎 jwt -->
+            <dependency>
+                <groupId>cn.dev33</groupId>
+                <artifactId>sa-token-jwt</artifactId>
+                <version>${satoken.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>cn.hutool</groupId>
+                        <artifactId>hutool-all</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>cn.dev33</groupId>
+                <artifactId>sa-token-core</artifactId>
+                <version>${satoken.version}</version>
+            </dependency>
+
+            <!-- dynamic-datasource 澶氭暟鎹簮-->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
+                <version>${dynamic-ds.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mybatis</groupId>
+                <artifactId>mybatis</artifactId>
+                <version>${mybatis.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-annotation</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <!-- sql鎬ц兘鍒嗘瀽鎻掍欢 -->
+            <dependency>
+                <groupId>p6spy</groupId>
+                <artifactId>p6spy</artifactId>
+                <version>${p6spy.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>${okhttp.version}</version>
+            </dependency>
+
+            <!--  AWS SDK for Java 2.x  -->
+            <dependency>
+                <groupId>software.amazon.awssdk</groupId>
+                <artifactId>s3</artifactId>
+                <version>${aws.sdk.version}</version>
+            </dependency>
+            <!-- 浣跨敤AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔� -->
+            <dependency>
+                <groupId>software.amazon.awssdk.crt</groupId>
+                <artifactId>aws-crt</artifactId>
+                <version>${aws.crt.version}</version>
+            </dependency>
+            <!-- 鍩轰簬 AWS CRT 鐨� S3 瀹㈡埛绔殑鎬ц兘澧炲己鐨� S3 浼犺緭绠$悊鍣� -->
+            <dependency>
+                <groupId>software.amazon.awssdk</groupId>
+                <artifactId>s3-transfer-manager</artifactId>
+                <version>${aws.sdk.version}</version>
+            </dependency>
+            <!--鐭俊sms4j-->
+            <dependency>
+                <groupId>org.dromara.sms4j</groupId>
+                <artifactId>sms4j-spring-boot-starter</artifactId>
+                <version>${sms4j.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>de.codecentric</groupId>
+                <artifactId>spring-boot-admin-starter-server</artifactId>
+                <version>${spring-boot-admin.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>de.codecentric</groupId>
+                <artifactId>spring-boot-admin-starter-client</artifactId>
+                <version>${spring-boot-admin.version}</version>
+            </dependency>
+
+            <!--redisson-->
+            <dependency>
+                <groupId>org.redisson</groupId>
+                <artifactId>redisson-spring-boot-starter</artifactId>
+                <version>${redisson.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
+                <version>${lock4j.version}</version>
+            </dependency>
+
+            <!-- SnailJob Client -->
+            <dependency>
+                <groupId>com.aizuda</groupId>
+                <artifactId>snail-job-client-starter</artifactId>
+                <version>${snailjob.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aizuda</groupId>
+                <artifactId>snail-job-client-job-core</artifactId>
+                <version>${snailjob.version}</version>
+            </dependency>
+
+            <!-- 鍔犲瘑鍖呭紩鍏� -->
+            <dependency>
+                <groupId>org.bouncycastle</groupId>
+                <artifactId>bcprov-jdk15to18</artifactId>
+                <version>${bouncycastle.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.github.linpeilie</groupId>
+                <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
+                <version>${mapstruct-plus.version}</version>
+            </dependency>
+
+            <!-- 绂荤嚎IP鍦板潃瀹氫綅搴� ip2region -->
+            <dependency>
+                <groupId>org.lionsoul</groupId>
+                <artifactId>ip2region</artifactId>
+                <version>${ip2region.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-core</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-servlet</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.undertow</groupId>
+                <artifactId>undertow-websockets-jsr</artifactId>
+                <version>${undertow.version}</version>
+            </dependency>
+
+            <dependency>
+                <artifactId>commons-compress</artifactId>
+                <groupId>org.apache.commons</groupId>
+                <version>1.26.2</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-system</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-job</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-generator</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-demo</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>lb-eims</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+
+            <!--  宸ヤ綔娴佹ā鍧�  -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-workflow</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>ruoyi-admin</module>
+        <module>ruoyi-common</module>
+        <module>ruoyi-extend</module>
+        <module>ruoyi-modules</module>
+    </modules>
+    <packaging>pom</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.verison}</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <annotationProcessorPaths>
+                        <path>
+                            <groupId>com.github.therapi</groupId>
+                            <artifactId>therapi-runtime-javadoc-scribe</artifactId>
+                            <version>${therapi-javadoc.version}</version>
+                        </path>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                            <version>${lombok.version}</version>
+                        </path>
+                        <path>
+                            <groupId>org.springframework.boot</groupId>
+                            <artifactId>spring-boot-configuration-processor</artifactId>
+                            <version>${spring-boot.version}</version>
+                        </path>
+                        <path>
+                            <groupId>io.github.linpeilie</groupId>
+                            <artifactId>mapstruct-plus-processor</artifactId>
+                            <version>${mapstruct-plus.version}</version>
+                        </path>
+                        <path>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok-mapstruct-binding</artifactId>
+                            <version>${mapstruct-plus.lombok.version}</version>
+                        </path>
+                    </annotationProcessorPaths>
+                    <compilerArgs>
+                        <arg>-parameters</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+            <!-- 鍗曞厓娴嬭瘯浣跨敤 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${maven-surefire-plugin.version}</version>
+                <configuration>
+                    <argLine>-Dfile.encoding=UTF-8</argLine>
+                    <!-- 鏍规嵁鎵撳寘鐜鎵ц瀵瑰簲鐨凘Tag娴嬭瘯鏂规硶 -->
+                    <groups>${profiles.active}</groups>
+                    <!-- 鎺掗櫎鏍囩 -->
+                    <excludedGroups>exclude</excludedGroups>
+                </configuration>
+            </plugin>
+            <!-- 缁熶竴鐗堟湰鍙风鐞� -->
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>flatten-maven-plugin</artifactId>
+                <version>${flatten-maven-plugin.version}</version>
+                <configuration>
+                    <updatePomFile>true</updatePomFile>
+                    <flattenMode>resolveCiFriendliesOnly</flattenMode>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>flatten</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>flatten</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>flatten.clean</id>
+                        <phase>clean</phase>
+                        <goals>
+                            <goal>clean</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <!-- 鍏抽棴杩囨护 -->
+                <filtering>false</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <!-- 寮曞叆鎵�鏈� 鍖归厤鏂囦欢杩涜杩囨护 -->
+                <includes>
+                    <include>application*</include>
+                    <include>bootstrap*</include>
+                    <include>banner*</include>
+                </includes>
+                <!-- 鍚敤杩囨护 鍗宠璧勬簮涓殑鍙橀噺灏嗕細琚繃婊ゅ櫒涓殑鍊兼浛鎹� -->
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>huawei nexus</name>
+            <url>https://mirrors.huaweicloud.com/repository/maven/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>huawei nexus</name>
+            <url>https://mirrors.huaweicloud.com/repository/maven/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>
+
+
diff --git a/eims/ruoyi-admin/.DS_Store b/eims/ruoyi-admin/.DS_Store
new file mode 100644
index 0000000..ee77193
--- /dev/null
+++ b/eims/ruoyi-admin/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-admin/Dockerfile b/eims/ruoyi-admin/Dockerfile
new file mode 100644
index 0000000..737cbfc
--- /dev/null
+++ b/eims/ruoyi-admin/Dockerfile
@@ -0,0 +1,26 @@
+# 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM findepi/graalvm:java17-native
+
+LABEL maintainer="Lion Li"
+
+RUN mkdir -p /ruoyi/server/logs \
+    /ruoyi/server/temp \
+    /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/server
+
+ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-admin.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+           # 搴旂敤鍚嶇О 濡傛灉鎯冲尯鍒嗛泦缇よ妭鐐圭洃鎺� 鏀规垚涓嶅悓鐨勫悕绉板嵆鍙�
+           #-Dskywalking.agent.service_name=ruoyi-server \
+           #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+           -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
+           -jar app.jar
+
diff --git a/eims/ruoyi-admin/pom.xml b/eims/ruoyi-admin/pom.xml
new file mode 100644
index 0000000..fb0cab4
--- /dev/null
+++ b/eims/ruoyi-admin/pom.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-vue-plus</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>ruoyi-admin</artifactId>
+
+    <description>
+        web鏈嶅姟鍏ュ彛
+    </description>
+
+    <dependencies>
+
+        <!-- Mysql椹卞姩鍖� -->
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+        </dependency>
+
+<!--        &lt;!&ndash; mp鏀寔鐨勬暟鎹簱鍧囨敮鎸� 鍙渶瑕佸鍔犲搴旂殑jdbc渚濊禆鍗冲彲 &ndash;&gt;-->
+<!--        &lt;!&ndash; Oracle &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.oracle.database.jdbc</groupId>-->
+<!--            <artifactId>ojdbc8</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; 鍏煎oracle浣庣増鏈� &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.oracle.database.nls</groupId>-->
+<!--            <artifactId>orai18n</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; PostgreSql &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>org.postgresql</groupId>-->
+<!--            <artifactId>postgresql</artifactId>-->
+<!--        </dependency>-->
+<!--        &lt;!&ndash; SqlServer &ndash;&gt;-->
+<!--        <dependency>-->
+<!--            <groupId>com.microsoft.sqlserver</groupId>-->
+<!--            <artifactId>mssql-jdbc</artifactId>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-social</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-ratelimiter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mail</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-system</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-job</artifactId>
+        </dependency>
+
+        <!-- 浠g爜鐢熸垚-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-generator</artifactId>
+        </dependency>
+
+        <!--  demo妯″潡  -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-demo</artifactId>
+        </dependency>
+
+        <!--  杞﹂棿璐ㄩ噺妯″潡  -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>lb-eims</artifactId>
+        </dependency>
+
+        <!--  宸ヤ綔娴佹ā鍧�  -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-workflow</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- skywalking 鏁村悎 logback -->
+<!--        <dependency>-->
+<!--            <groupId>org.apache.skywalking</groupId>-->
+<!--            <artifactId>apm-toolkit-logback-1.x</artifactId>-->
+<!--            <version>${涓庝綘鐨刟gent鎺㈤拡鐗堟湰淇濇寔涓�鑷磢</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.apache.skywalking</groupId>-->
+<!--            <artifactId>apm-toolkit-trace</artifactId>-->
+<!--            <version>${涓庝綘鐨刟gent鎺㈤拡鐗堟湰淇濇寔涓�鑷磢</version>-->
+<!--        </dependency>-->
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>${maven-jar-plugin.version}</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>${maven-war-plugin.version}</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java b/eims/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java
new file mode 100644
index 0000000..5734b09
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java
@@ -0,0 +1,23 @@
+package org.dromara;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 鍚姩绋嬪簭
+ *
+ * @author Lion Li
+ */
+
+@SpringBootApplication(scanBasePackages={"org.dromara", "cn.shlanbao"})
+public class DromaraApplication {
+
+    public static void main(String[] args) {
+        SpringApplication application = new SpringApplication(DromaraApplication.class);
+        application.setApplicationStartup(new BufferingApplicationStartup(2048));
+        application.run(args);
+        System.out.println("(鈾モ棤鈥库棤)锞夛緸  璁惧鏅鸿兘绠$悊绯荤粺 鍚姩鎴愬姛   醿�(麓凇`醿�)锞�");
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java b/eims/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java
new file mode 100644
index 0000000..066a683
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java
@@ -0,0 +1,18 @@
+package org.dromara;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web瀹瑰櫒涓繘琛岄儴缃�
+ *
+ * @author Lion Li
+ */
+public class DromaraServletInitializer extends SpringBootServletInitializer {
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(DromaraApplication.class);
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
new file mode 100644
index 0000000..92d39f0
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
@@ -0,0 +1,234 @@
+package org.dromara.web.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.utils.AuthStateUtils;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.RegisterBody;
+import org.dromara.common.core.domain.model.SocialLoginBody;
+import org.dromara.common.core.utils.*;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.SocialUtils;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.dromara.common.sse.utils.SseMessageUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.service.ISysClientService;
+import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysSocialService;
+import org.dromara.system.service.ISysTenantService;
+import org.dromara.web.domain.vo.LoginTenantVo;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.domain.vo.TenantListVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.dromara.web.service.SysRegisterService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 璁よ瘉
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@SaIgnore
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/auth")
+public class AuthController {
+
+    private final SocialProperties socialProperties;
+    private final SysLoginService loginService;
+    private final SysRegisterService registerService;
+    private final ISysConfigService configService;
+    private final ISysTenantService tenantService;
+    private final ISysSocialService socialUserService;
+    private final ISysClientService clientService;
+    private final ScheduledExecutorService scheduledExecutorService;
+
+
+    /**
+     * 鐧诲綍鏂规硶
+     *
+     * @param body 鐧诲綍淇℃伅
+     * @return 缁撴灉
+     */
+    @ApiEncrypt
+    @PostMapping("/login")
+    public R<LoginVo> login(@RequestBody String body) {
+        LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        // 鎺堟潈绫诲瀷鍜屽鎴风id
+        String clientId = loginBody.getClientId();
+        String grantType = loginBody.getGrantType();
+        SysClientVo client = clientService.queryByClientId(clientId);
+        // 鏌ヨ涓嶅埌 client 鎴� client 鍐呬笉鍖呭惈 grantType
+        if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
+            log.info("瀹㈡埛绔痠d: {} 璁よ瘉绫诲瀷锛歿} 寮傚父!.", clientId, grantType);
+            return R.fail(MessageUtils.message("auth.grant.type.error"));
+        } else if (!UserConstants.NORMAL.equals(client.getStatus())) {
+            return R.fail(MessageUtils.message("auth.grant.type.blocked"));
+        }
+        // 鏍¢獙绉熸埛
+        loginService.checkTenant(loginBody.getTenantId());
+        // 鐧诲綍
+        LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
+
+        Long userId = LoginHelper.getUserId();
+        scheduledExecutorService.schedule(() -> {
+            SseMessageDto dto = new SseMessageDto();
+            dto.setMessage("娆㈣繋鐧诲綍璁惧鏅鸿兘绠$悊绯荤粺");
+            dto.setUserIds(List.of(userId));
+            SseMessageUtils.publishMessage(dto);
+        }, 5, TimeUnit.SECONDS);
+        return R.ok(loginVo);
+    }
+
+    /**
+     * 绗笁鏂圭櫥褰曡姹�
+     *
+     * @param source 鐧诲綍鏉ユ簮
+     * @return 缁撴灉
+     */
+    @GetMapping("/binding/{source}")
+    public R<String> authBinding(@PathVariable("source") String source,
+                                 @RequestParam String tenantId, @RequestParam String domain) {
+        SocialLoginConfigProperties obj = socialProperties.getType().get(source);
+        if (ObjectUtil.isNull(obj)) {
+            return R.fail(source + "骞冲彴璐﹀彿鏆備笉鏀寔");
+        }
+        AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
+        Map<String, String> map = new HashMap<>();
+        map.put("tenantId", tenantId);
+        map.put("domain", domain);
+        map.put("state", AuthStateUtils.createState());
+        String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8));
+        return R.ok("鎿嶄綔鎴愬姛", authorizeUrl);
+    }
+
+    /**
+     * 绗笁鏂圭櫥褰曞洖璋冧笟鍔″鐞� 缁戝畾鎺堟潈
+     *
+     * @param loginBody 璇锋眰浣�
+     * @return 缁撴灉
+     */
+    @PostMapping("/social/callback")
+    public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
+        // 鑾峰彇绗笁鏂圭櫥褰曚俊鎭�
+        AuthResponse<AuthUser> response = SocialUtils.loginAuth(
+                loginBody.getSource(), loginBody.getSocialCode(),
+                loginBody.getSocialState(), socialProperties);
+        AuthUser authUserData = response.getData();
+        // 鍒ゆ柇鎺堟潈鍝嶅簲鏄惁鎴愬姛
+        if (!response.ok()) {
+            return R.fail(response.getMsg());
+        }
+        loginService.socialRegister(authUserData);
+        return R.ok();
+    }
+
+
+    /**
+     * 鍙栨秷鎺堟潈
+     *
+     * @param socialId socialId
+     */
+    @DeleteMapping(value = "/unlock/{socialId}")
+    public R<Void> unlockSocial(@PathVariable Long socialId) {
+        Boolean rows = socialUserService.deleteWithValidById(socialId);
+        return rows ? R.ok() : R.fail("鍙栨秷鎺堟潈澶辫触");
+    }
+
+
+    /**
+     * 閫�鍑虹櫥褰�
+     */
+    @PostMapping("/logout")
+    public R<Void> logout() {
+        loginService.logout();
+        return R.ok("閫�鍑烘垚鍔�");
+    }
+
+    /**
+     * 鐢ㄦ埛娉ㄥ唽
+     */
+    @ApiEncrypt
+    @PostMapping("/register")
+    public R<Void> register(@Validated @RequestBody RegisterBody user) {
+        if (!configService.selectRegisterEnabled(user.getTenantId())) {
+            return R.fail("褰撳墠绯荤粺娌℃湁寮�鍚敞鍐屽姛鑳斤紒");
+        }
+        registerService.register(user);
+        return R.ok();
+    }
+
+    /**
+     * 鐧诲綍椤甸潰绉熸埛涓嬫媺妗�
+     *
+     * @return 绉熸埛鍒楄〃
+     */
+    @GetMapping("/tenant/list")
+    public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
+        // 杩斿洖瀵硅薄
+        LoginTenantVo result = new LoginTenantVo();
+        boolean enable = TenantHelper.isEnable();
+        result.setTenantEnabled(enable);
+        // 濡傛灉鏈紑鍚鎴疯繖鐩存帴杩斿洖
+        if (!enable) {
+            return R.ok(result);
+        }
+
+        List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
+        List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
+        try {
+            // 濡傛灉鍙秴绠¤繑鍥炴墍鏈夌鎴�
+            if (LoginHelper.isSuperAdmin()) {
+                result.setVoList(voList);
+                return R.ok(result);
+            }
+        } catch (NotLoginException ignored) {
+        }
+
+        // 鑾峰彇鍩熷悕
+        String host;
+        String referer = request.getHeader("referer");
+        if (StringUtils.isNotBlank(referer)) {
+            // 杩欓噷浠巖eferer涓彇鍊兼槸涓轰簡鏈湴浣跨敤hosts娣诲姞铏氭嫙鍩熷悕锛屾柟渚挎湰鍦扮幆澧冭皟璇�
+            host = referer.split("//")[1].split("/")[0];
+        } else {
+            host = new URL(request.getRequestURL().toString()).getHost();
+        }
+        // 鏍规嵁鍩熷悕杩涜绛涢��
+        List<TenantListVo> list = StreamUtils.filter(voList, vo ->
+                StringUtils.equals(vo.getDomain(), host));
+        result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
+        return R.ok(result);
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
new file mode 100644
index 0000000..1a476a9
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
@@ -0,0 +1,136 @@
+package org.dromara.web.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.hutool.captcha.AbstractCaptcha;
+import cn.hutool.captcha.generator.CodeGenerator;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
+import jakarta.validation.constraints.NotBlank;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.mail.config.properties.MailProperties;
+import org.dromara.common.mail.utils.MailUtils;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.ratelimiter.enums.LimitType;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.web.config.properties.CaptchaProperties;
+import org.dromara.common.web.enums.CaptchaType;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.web.domain.vo.CaptchaVo;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.Duration;
+import java.util.LinkedHashMap;
+
+/**
+ * 楠岃瘉鐮佹搷浣滃鐞�
+ *
+ * @author Lion Li
+ */
+@SaIgnore
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+public class CaptchaController {
+
+    private final CaptchaProperties captchaProperties;
+    private final MailProperties mailProperties;
+
+    /**
+     * 鐭俊楠岃瘉鐮�
+     *
+     * @param phonenumber 鐢ㄦ埛鎵嬫満鍙�
+     */
+    @RateLimiter(key = "#phonenumber", time = 60, count = 1)
+    @GetMapping("/resource/sms/code")
+    public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
+        String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
+        String code = RandomUtil.randomNumbers(4);
+        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        // 楠岃瘉鐮佹ā鏉縤d 鑷澶勭悊 (鏌ユ暟鎹簱鎴栧啓姝诲潎鍙�)
+        String templateId = "";
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
+        map.put("code", code);
+        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
+        SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
+        if (!smsResponse.isSuccess()) {
+            log.error("楠岃瘉鐮佺煭淇″彂閫佸紓甯� => {}", smsResponse);
+            return R.fail(smsResponse.getData().toString());
+        }
+        return R.ok();
+    }
+
+    /**
+     * 閭楠岃瘉鐮�
+     *
+     * @param email 閭
+     */
+    @RateLimiter(key = "#email", time = 60, count = 1)
+    @GetMapping("/resource/email/code")
+    public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
+        if (!mailProperties.getEnabled()) {
+            return R.fail("褰撳墠绯荤粺娌℃湁寮�鍚偖绠卞姛鑳斤紒");
+        }
+        String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
+        String code = RandomUtil.randomNumbers(4);
+        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        try {
+            MailUtils.sendText(email, "鐧诲綍楠岃瘉鐮�", "鎮ㄦ湰娆¢獙璇佺爜涓猴細" + code + "锛屾湁鏁堟�т负" + Constants.CAPTCHA_EXPIRATION + "鍒嗛挓锛岃灏藉揩濉啓銆�");
+        } catch (Exception e) {
+            log.error("楠岃瘉鐮佺煭淇″彂閫佸紓甯� => {}", e.getMessage());
+            return R.fail(e.getMessage());
+        }
+        return R.ok();
+    }
+
+    /**
+     * 鐢熸垚楠岃瘉鐮�
+     */
+    @RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
+    @GetMapping("/auth/code")
+    public R<CaptchaVo> getCode() {
+        CaptchaVo captchaVo = new CaptchaVo();
+        boolean captchaEnabled = captchaProperties.getEnable();
+        if (!captchaEnabled) {
+            captchaVo.setCaptchaEnabled(false);
+            return R.ok(captchaVo);
+        }
+        // 淇濆瓨楠岃瘉鐮佷俊鎭�
+        String uuid = IdUtil.simpleUUID();
+        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
+        // 鐢熸垚楠岃瘉鐮�
+        CaptchaType captchaType = captchaProperties.getType();
+        boolean isMath = CaptchaType.MATH == captchaType;
+        Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
+        CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
+        AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
+        captcha.setGenerator(codeGenerator);
+        captcha.createCode();
+        // 濡傛灉鏄暟瀛﹂獙璇佺爜锛屼娇鐢⊿pEL琛ㄨ揪寮忓鐞嗛獙璇佺爜缁撴灉
+        String code = captcha.getCode();
+        if (isMath) {
+            ExpressionParser parser = new SpelExpressionParser();
+            Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
+            code = exp.getValue(String.class);
+        }
+        RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        captchaVo.setUuid(uuid);
+        captchaVo.setImg(captcha.getImageBase64());
+        return R.ok(captchaVo);
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java
new file mode 100644
index 0000000..c444f28
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java
@@ -0,0 +1,32 @@
+package org.dromara.web.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import org.dromara.common.core.config.RuoYiConfig;
+import org.dromara.common.core.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 棣栭〉
+ *
+ * @author Lion Li
+ */
+@SaIgnore
+@RequiredArgsConstructor
+@RestController
+public class IndexController {
+
+    /**
+     * 绯荤粺鍩虹閰嶇疆
+     */
+    private final RuoYiConfig ruoyiConfig;
+
+    /**
+     * 璁块棶棣栭〉锛屾彁绀鸿
+     */
+    @GetMapping("/")
+    public String index() {
+        return StringUtils.format("娆㈣繋浣跨敤{}鍚庡彴绠$悊妗嗘灦锛屽綋鍓嶇増鏈細v{}锛岃閫氳繃鍓嶇鍦板潃璁块棶銆�", ruoyiConfig.getName(), ruoyiConfig.getVersion());
+    }
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java
new file mode 100644
index 0000000..664df1e
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java
@@ -0,0 +1,25 @@
+package org.dromara.web.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 楠岃瘉鐮佷俊鎭�
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class CaptchaVo {
+
+    /**
+     * 鏄惁寮�鍚獙璇佺爜
+     */
+    private Boolean captchaEnabled = true;
+
+    private String uuid;
+
+    /**
+     * 楠岃瘉鐮佸浘鐗�
+     */
+    private String img;
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java
new file mode 100644
index 0000000..0a83ace
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java
@@ -0,0 +1,25 @@
+package org.dromara.web.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鐧诲綍绉熸埛瀵硅薄
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class LoginTenantVo {
+
+    /**
+     * 绉熸埛寮�鍏�
+     */
+    private Boolean tenantEnabled;
+
+    /**
+     * 绉熸埛瀵硅薄鍒楄〃
+     */
+    private List<TenantListVo> voList;
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java
new file mode 100644
index 0000000..834afe5
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java
@@ -0,0 +1,54 @@
+package org.dromara.web.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * 鐧诲綍楠岃瘉淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class LoginVo {
+
+    /**
+     * 鎺堟潈浠ょ墝
+     */
+    @JsonProperty("access_token")
+    private String accessToken;
+
+    /**
+     * 鍒锋柊浠ょ墝
+     */
+    @JsonProperty("refresh_token")
+    private String refreshToken;
+
+    /**
+     * 鎺堟潈浠ょ墝 access_token 鐨勬湁鏁堟湡
+     */
+    @JsonProperty("expire_in")
+    private Long expireIn;
+
+    /**
+     * 鍒锋柊浠ょ墝 refresh_token 鐨勬湁鏁堟湡
+     */
+    @JsonProperty("refresh_expire_in")
+    private Long refreshExpireIn;
+
+    /**
+     * 搴旂敤id
+     */
+    @JsonProperty("client_id")
+    private String clientId;
+
+    /**
+     * 浠ょ墝鏉冮檺
+     */
+    private String scope;
+
+    /**
+     * 鐢ㄦ埛 openid
+     */
+    private String openid;
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java
new file mode 100644
index 0000000..db9c271
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java
@@ -0,0 +1,31 @@
+package org.dromara.web.domain.vo;
+
+import org.dromara.system.domain.vo.SysTenantVo;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+/**
+ * 绉熸埛鍒楄〃
+ *
+ * @author Lion Li
+ */
+@Data
+@AutoMapper(target = SysTenantVo.class)
+public class TenantListVo {
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 浼佷笟鍚嶇О
+     */
+    private String companyName;
+
+    /**
+     * 鍩熷悕
+     */
+    private String domain;
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java
new file mode 100644
index 0000000..07595e0
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java
@@ -0,0 +1,165 @@
+package org.dromara.web.listener;
+
+import cn.dev33.satoken.config.SaTokenConfig;
+import cn.dev33.satoken.listener.SaTokenListener;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.domain.dto.UserOnlineDTO;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.ip.AddressUtils;
+import org.dromara.common.log.event.LogininforEvent;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+
+/**
+ * 鐢ㄦ埛琛屼负 渚﹀惉鍣ㄧ殑瀹炵幇
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Component
+@Slf4j
+public class UserActionListener implements SaTokenListener {
+
+    private final SaTokenConfig tokenConfig;
+    private final SysLoginService loginService;
+
+    /**
+     * 姣忔鐧诲綍鏃惰Е鍙�
+     */
+    @Override
+    public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
+        UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
+        String ip = ServletUtils.getClientIP();
+        UserOnlineDTO dto = new UserOnlineDTO();
+        dto.setIpaddr(ip);
+        dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
+        dto.setBrowser(userAgent.getBrowser().getName());
+        dto.setOs(userAgent.getOs().getName());
+        dto.setLoginTime(System.currentTimeMillis());
+        dto.setTokenId(tokenValue);
+        String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY);
+        String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY);
+        dto.setUserName(username);
+        dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY));
+        dto.setDeviceType(loginModel.getDevice());
+        dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            if(tokenConfig.getTimeout() == -1) {
+                RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
+            } else {
+                RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
+            }
+        });
+        // 璁板綍鐧诲綍鏃ュ織
+        LogininforEvent logininforEvent = new LogininforEvent();
+        logininforEvent.setTenantId(tenantId);
+        logininforEvent.setUsername(username);
+        logininforEvent.setStatus(Constants.LOGIN_SUCCESS);
+        logininforEvent.setMessage(MessageUtils.message("user.login.success"));
+        logininforEvent.setRequest(ServletUtils.getRequest());
+        SpringUtils.context().publishEvent(logininforEvent);
+        // 鏇存柊鐧诲綍淇℃伅
+        loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip);
+        log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
+    }
+
+    /**
+     * 姣忔娉ㄩ攢鏃惰Е鍙�
+     */
+    @Override
+    public void doLogout(String loginType, Object loginId, String tokenValue) {
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
+        log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
+    }
+
+    /**
+     * 姣忔琚涪涓嬬嚎鏃惰Е鍙�
+     */
+    @Override
+    public void doKickout(String loginType, Object loginId, String tokenValue) {
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
+        log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
+    }
+
+    /**
+     * 姣忔琚《涓嬬嚎鏃惰Е鍙�
+     */
+    @Override
+    public void doReplaced(String loginType, Object loginId, String tokenValue) {
+        String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+        TenantHelper.dynamic(tenantId, () -> {
+            RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+        });
+        log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
+    }
+
+    /**
+     * 姣忔琚皝绂佹椂瑙﹀彂
+     */
+    @Override
+    public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
+    }
+
+    /**
+     * 姣忔琚В灏佹椂瑙﹀彂
+     */
+    @Override
+    public void doUntieDisable(String loginType, Object loginId, String service) {
+    }
+
+    /**
+     * 姣忔鎵撳紑浜岀骇璁よ瘉鏃惰Е鍙�
+     */
+    @Override
+    public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
+    }
+
+    /**
+     * 姣忔鍒涘缓Session鏃惰Е鍙�
+     */
+    @Override
+    public void doCloseSafe(String loginType, String tokenValue, String service) {
+    }
+
+    /**
+     * 姣忔鍒涘缓Session鏃惰Е鍙�
+     */
+    @Override
+    public void doCreateSession(String id) {
+    }
+
+    /**
+     * 姣忔娉ㄩ攢Session鏃惰Е鍙�
+     */
+    @Override
+    public void doLogoutSession(String id) {
+    }
+
+    /**
+     * 姣忔Token缁湡鏃惰Е鍙�
+     */
+    @Override
+    public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
+    }
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java
new file mode 100644
index 0000000..a75b913
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java
@@ -0,0 +1,46 @@
+package org.dromara.web.service;
+
+
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.web.domain.vo.LoginVo;
+
+/**
+ * 鎺堟潈绛栫暐
+ *
+ * @author Michelle.Chung
+ */
+public interface IAuthStrategy {
+
+    String BASE_NAME = "AuthStrategy";
+
+    /**
+     * 鐧诲綍
+     *
+     * @param body      鐧诲綍瀵硅薄
+     * @param client    鎺堟潈绠$悊瑙嗗浘瀵硅薄
+     * @param grantType 鎺堟潈绫诲瀷
+     * @return 鐧诲綍楠岃瘉淇℃伅
+     */
+    static LoginVo login(String body, SysClientVo client, String grantType) {
+        // 鎺堟潈绫诲瀷鍜屽鎴风id
+        String beanName = grantType + BASE_NAME;
+        if (!SpringUtils.containsBean(beanName)) {
+            throw new ServiceException("鎺堟潈绫诲瀷涓嶆纭�!");
+        }
+        IAuthStrategy instance = SpringUtils.getBean(beanName);
+        return instance.login(body, client);
+    }
+
+    /**
+     * 鐧诲綍
+     *
+     * @param body   鐧诲綍瀵硅薄
+     * @param client 鎺堟潈绠$悊瑙嗗浘瀵硅薄
+     * @return 鐧诲綍楠岃瘉淇℃伅
+     */
+    LoginVo login(String body, SysClientVo client);
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
new file mode 100644
index 0000000..c7ad917
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -0,0 +1,246 @@
+package org.dromara.web.service;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Opt;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.lock.annotation.Lock4j;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthUser;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.dto.RoleDTO;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.TenantStatus;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.*;
+import org.dromara.common.log.event.LogininforEvent;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.exception.TenantException;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.*;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.time.Duration;
+import java.util.Date;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * 鐧诲綍鏍¢獙鏂规硶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class SysLoginService {
+
+    @Value("${user.password.maxRetryCount}")
+    private Integer maxRetryCount;
+
+    @Value("${user.password.lockTime}")
+    private Integer lockTime;
+
+    private final ISysTenantService tenantService;
+    private final ISysPermissionService permissionService;
+    private final ISysSocialService sysSocialService;
+    private final ISysRoleService roleService;
+    private final ISysDeptService deptService;
+    private final SysUserMapper userMapper;
+
+
+    /**
+     * 缁戝畾绗笁鏂圭敤鎴�
+     *
+     * @param authUserData 鎺堟潈鍝嶅簲瀹炰綋
+     */
+    @Lock4j
+    public void socialRegister(AuthUser authUserData) {
+        String authId = authUserData.getSource() + authUserData.getUuid();
+        // 绗笁鏂圭敤鎴蜂俊鎭�
+        SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class);
+        BeanUtil.copyProperties(authUserData.getToken(), bo);
+        Long userId = LoginHelper.getUserId();
+        bo.setUserId(userId);
+        bo.setAuthId(authId);
+        bo.setOpenId(authUserData.getUuid());
+        bo.setUserName(authUserData.getUsername());
+        bo.setNickName(authUserData.getNickname());
+        List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId);
+        if (CollUtil.isNotEmpty(checkList)) {
+            throw new ServiceException("姝や笁鏂硅处鍙峰凡缁忚缁戝畾!");
+        }
+        // 鏌ヨ鏄惁宸茬粡缁戝畾鐢ㄦ埛
+        SysSocialBo params = new SysSocialBo();
+        params.setUserId(userId);
+        params.setSource(bo.getSource());
+        List<SysSocialVo> list = sysSocialService.queryList(params);
+        if (CollUtil.isEmpty(list)) {
+            // 娌℃湁缁戝畾鐢ㄦ埛, 鏂板鐢ㄦ埛淇℃伅
+            sysSocialService.insertByBo(bo);
+        } else {
+            // 鏇存柊鐢ㄦ埛淇℃伅
+            bo.setId(list.get(0).getId());
+            sysSocialService.updateByBo(bo);
+            // 濡傛灉瑕佺粦瀹氱殑骞冲彴璐﹀彿宸茬粡琚粦瀹氳繃浜� 鏄惁鎶涘紓甯歌嚜琛屽喅鏂�
+            // throw new ServiceException("姝ゅ钩鍙拌处鍙峰凡缁忚缁戝畾!");
+        }
+    }
+
+
+    /**
+     * 閫�鍑虹櫥褰�
+     */
+    public void logout() {
+        try {
+            LoginUser loginUser = LoginHelper.getLoginUser();
+            if (ObjectUtil.isNull(loginUser)) {
+                return;
+            }
+            if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
+                // 瓒呯骇绠$悊鍛� 鐧诲嚭娓呴櫎鍔ㄦ�佺鎴�
+                TenantHelper.clearDynamic();
+            }
+            recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
+        } catch (NotLoginException ignored) {
+        } finally {
+            try {
+                StpUtil.logout();
+            } catch (NotLoginException ignored) {
+            }
+        }
+    }
+
+    /**
+     * 璁板綍鐧诲綍淇℃伅
+     *
+     * @param tenantId 绉熸埛ID
+     * @param username 鐢ㄦ埛鍚�
+     * @param status   鐘舵��
+     * @param message  娑堟伅鍐呭
+     */
+    public void recordLogininfor(String tenantId, String username, String status, String message) {
+        LogininforEvent logininforEvent = new LogininforEvent();
+        logininforEvent.setTenantId(tenantId);
+        logininforEvent.setUsername(username);
+        logininforEvent.setStatus(status);
+        logininforEvent.setMessage(message);
+        logininforEvent.setRequest(ServletUtils.getRequest());
+        SpringUtils.context().publishEvent(logininforEvent);
+    }
+
+    /**
+     * 鏋勫缓鐧诲綍鐢ㄦ埛
+     */
+    public LoginUser buildLoginUser(SysUserVo user) {
+        LoginUser loginUser = new LoginUser();
+        loginUser.setTenantId(user.getTenantId());
+        loginUser.setUserId(user.getUserId());
+        loginUser.setDeptId(user.getDeptId());
+        loginUser.setUsername(user.getUserName());
+        loginUser.setNickname(user.getNickName());
+        loginUser.setUserType(user.getUserType());
+        loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
+        loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
+        if (ObjectUtil.isNotNull(user.getDeptId())) {
+            Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
+            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
+            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
+        }
+        List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
+        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
+        return loginUser;
+    }
+
+    /**
+     * 璁板綍鐧诲綍淇℃伅
+     *
+     * @param userId 鐢ㄦ埛ID
+     */
+    public void recordLoginInfo(Long userId, String ip) {
+        SysUser sysUser = new SysUser();
+        sysUser.setUserId(userId);
+        sysUser.setLoginIp(ip);
+        sysUser.setLoginDate(DateUtils.getNowDate());
+        sysUser.setUpdateBy(userId);
+        DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
+    }
+
+    /**
+     * 鐧诲綍鏍¢獙
+     */
+    public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
+        String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
+        String loginFail = Constants.LOGIN_FAIL;
+
+        // 鑾峰彇鐢ㄦ埛鐧诲綍閿欒娆℃暟锛岄粯璁や负0 (鍙嚜瀹氫箟闄愬埗绛栫暐 渚嬪: key + username + ip)
+        int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
+        // 閿佸畾鏃堕棿鍐呯櫥褰� 鍒欒涪鍑�
+        if (errorNumber >= maxRetryCount) {
+            recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
+            throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
+        }
+
+        if (supplier.get()) {
+            // 閿欒娆℃暟閫掑
+            errorNumber++;
+            RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
+            // 杈惧埌瑙勫畾閿欒娆℃暟 鍒欓攣瀹氱櫥褰�
+            if (errorNumber >= maxRetryCount) {
+                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
+                throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
+            } else {
+                // 鏈揪鍒拌瀹氶敊璇鏁�
+                recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
+                throw new UserException(loginType.getRetryLimitCount(), errorNumber);
+            }
+        }
+
+        // 鐧诲綍鎴愬姛 娓呯┖閿欒娆℃暟
+        RedisUtils.deleteObject(errorKey);
+    }
+
+    /**
+     * 鏍¢獙绉熸埛
+     *
+     * @param tenantId 绉熸埛ID
+     */
+    public void checkTenant(String tenantId) {
+        if (!TenantHelper.isEnable()) {
+            return;
+        }
+        if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+            return;
+        }
+        if (StringUtils.isBlank(tenantId)) {
+            throw new TenantException("tenant.number.not.blank");
+        }
+        SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
+        if (ObjectUtil.isNull(tenant)) {
+            log.info("鐧诲綍绉熸埛锛歿} 涓嶅瓨鍦�.", tenantId);
+            throw new TenantException("tenant.not.exists");
+        } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) {
+            log.info("鐧诲綍绉熸埛锛歿} 宸茶鍋滅敤.", tenantId);
+            throw new TenantException("tenant.blocked");
+        } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
+            && new Date().after(tenant.getExpireTime())) {
+            log.info("鐧诲綍绉熸埛锛歿} 宸茶秴杩囨湁鏁堟湡.", tenantId);
+            throw new TenantException("tenant.expired");
+        }
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
new file mode 100644
index 0000000..ddab279
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
@@ -0,0 +1,115 @@
+package org.dromara.web.service;
+
+import cn.dev33.satoken.secure.BCrypt;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.RegisterBody;
+import org.dromara.common.core.enums.UserType;
+import org.dromara.common.core.exception.user.CaptchaException;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.event.LogininforEvent;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.config.properties.CaptchaProperties;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 娉ㄥ唽鏍¢獙鏂规硶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysRegisterService {
+
+    private final ISysUserService userService;
+    private final SysUserMapper userMapper;
+    private final CaptchaProperties captchaProperties;
+
+    /**
+     * 娉ㄥ唽
+     */
+    public void register(RegisterBody registerBody) {
+        String tenantId = registerBody.getTenantId();
+        String username = registerBody.getUsername();
+        String password = registerBody.getPassword();
+        // 鏍¢獙鐢ㄦ埛绫诲瀷鏄惁瀛樺湪
+        String userType = UserType.getUserType(registerBody.getUserType()).getUserType();
+
+        boolean captchaEnabled = captchaProperties.getEnable();
+        // 楠岃瘉鐮佸紑鍏�
+        if (captchaEnabled) {
+            validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid());
+        }
+        SysUserBo sysUser = new SysUserBo();
+        sysUser.setUserName(username);
+        sysUser.setNickName(username);
+        sysUser.setPassword(BCrypt.hashpw(password));
+        sysUser.setUserType(userType);
+
+        boolean exist = TenantHelper.dynamic(tenantId, () -> {
+            return userMapper.exists(new LambdaQueryWrapper<SysUser>()
+                .eq(SysUser::getUserName, sysUser.getUserName()));
+        });
+        if (exist) {
+            throw new UserException("user.register.save.error", username);
+        }
+        boolean regFlag = userService.registerUser(sysUser, tenantId);
+        if (!regFlag) {
+            throw new UserException("user.register.error");
+        }
+        recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
+    }
+
+    /**
+     * 鏍¢獙楠岃瘉鐮�
+     *
+     * @param username 鐢ㄦ埛鍚�
+     * @param code     楠岃瘉鐮�
+     * @param uuid     鍞竴鏍囪瘑
+     */
+    public void validateCaptcha(String tenantId, String username, String code, String uuid) {
+        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
+        String captcha = RedisUtils.getCacheObject(verifyKey);
+        RedisUtils.deleteObject(verifyKey);
+        if (captcha == null) {
+            recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha)) {
+            recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error"));
+            throw new CaptchaException();
+        }
+    }
+
+    /**
+     * 璁板綍鐧诲綍淇℃伅
+     *
+     * @param tenantId 绉熸埛ID
+     * @param username 鐢ㄦ埛鍚�
+     * @param status   鐘舵��
+     * @param message  娑堟伅鍐呭
+     * @return
+     */
+    private void recordLogininfor(String tenantId, String username, String status, String message) {
+        LogininforEvent logininforEvent = new LogininforEvent();
+        logininforEvent.setTenantId(tenantId);
+        logininforEvent.setUsername(username);
+        logininforEvent.setStatus(status);
+        logininforEvent.setMessage(message);
+        logininforEvent.setRequest(ServletUtils.getRequest());
+        SpringUtils.context().publishEvent(logininforEvent);
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
new file mode 100644
index 0000000..b5a2497
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
@@ -0,0 +1,102 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.EmailLoginBody;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 閭欢璁よ瘉绛栫暐
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("email" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class EmailAuthStrategy implements IAuthStrategy {
+
+    private final SysLoginService loginService;
+    private final SysUserMapper userMapper;
+
+    @Override
+    public LoginVo login(String body, SysClientVo client) {
+        EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        String tenantId = loginBody.getTenantId();
+        String email = loginBody.getEmail();
+        String emailCode = loginBody.getEmailCode();
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByEmail(email);
+            loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
+        loginUser.setClientKey(client.getClientKey());
+        loginUser.setDeviceType(client.getDeviceType());
+        SaLoginModel model = new SaLoginModel();
+        model.setDevice(client.getDeviceType());
+        // 鑷畾涔夊垎閰� 涓嶅悓鐢ㄦ埛浣撶郴 涓嶅悓 token 鎺堟潈鏃堕棿 涓嶈缃粯璁よ蛋鍏ㄥ眬 yml 閰嶇疆
+        // 渚嬪: 鍚庡彴鐢ㄦ埛30鍒嗛挓杩囨湡 app鐢ㄦ埛1澶╄繃鏈�
+        model.setTimeout(client.getTimeout());
+        model.setActiveTimeout(client.getActiveTimeout());
+        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
+        // 鐢熸垚token
+        LoginHelper.login(loginUser, model);
+
+        LoginVo loginVo = new LoginVo();
+        loginVo.setAccessToken(StpUtil.getTokenValue());
+        loginVo.setExpireIn(StpUtil.getTokenTimeout());
+        loginVo.setClientId(client.getClientId());
+        return loginVo;
+    }
+
+    /**
+     * 鏍¢獙閭楠岃瘉鐮�
+     */
+    private boolean validateEmailCode(String tenantId, String email, String emailCode) {
+        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
+        if (StringUtils.isBlank(code)) {
+            loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        return code.equals(emailCode);
+    }
+
+    private SysUserVo loadUserByEmail(String email) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", email);
+            throw new UserException("user.not.exists", email);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", email);
+            throw new UserException("user.blocked", email);
+        }
+        return user;
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
new file mode 100644
index 0000000..f28024f
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
@@ -0,0 +1,123 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.domain.model.PasswordLoginBody;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaException;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.config.properties.CaptchaProperties;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 瀵嗙爜璁よ瘉绛栫暐
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("password" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class PasswordAuthStrategy implements IAuthStrategy {
+
+    private final CaptchaProperties captchaProperties;
+    private final SysLoginService loginService;
+    private final SysUserMapper userMapper;
+
+    @Override
+    public LoginVo login(String body, SysClientVo client) {
+        PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        String tenantId = loginBody.getTenantId();
+        String username = loginBody.getUsername();
+        String password = loginBody.getPassword();
+        String code = loginBody.getCode();
+        String uuid = loginBody.getUuid();
+
+        boolean captchaEnabled = captchaProperties.getEnable();
+        // 楠岃瘉鐮佸紑鍏�
+        if (captchaEnabled) {
+            validateCaptcha(tenantId, username, code, uuid);
+        }
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByUsername(username);
+            loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser
+            return loginService.buildLoginUser(user);
+        });
+        loginUser.setClientKey(client.getClientKey());
+        loginUser.setDeviceType(client.getDeviceType());
+        SaLoginModel model = new SaLoginModel();
+        model.setDevice(client.getDeviceType());
+        // 鑷畾涔夊垎閰� 涓嶅悓鐢ㄦ埛浣撶郴 涓嶅悓 token 鎺堟潈鏃堕棿 涓嶈缃粯璁よ蛋鍏ㄥ眬 yml 閰嶇疆
+        // 渚嬪: 鍚庡彴鐢ㄦ埛30鍒嗛挓杩囨湡 app鐢ㄦ埛1澶╄繃鏈�
+        model.setTimeout(client.getTimeout());
+        model.setActiveTimeout(client.getActiveTimeout());
+        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
+        // 鐢熸垚token
+        LoginHelper.login(loginUser, model);
+
+        LoginVo loginVo = new LoginVo();
+        loginVo.setAccessToken(StpUtil.getTokenValue());
+        loginVo.setExpireIn(StpUtil.getTokenTimeout());
+        loginVo.setClientId(client.getClientId());
+        return loginVo;
+    }
+
+    /**
+     * 鏍¢獙楠岃瘉鐮�
+     *
+     * @param username 鐢ㄦ埛鍚�
+     * @param code     楠岃瘉鐮�
+     * @param uuid     鍞竴鏍囪瘑
+     */
+    private void validateCaptcha(String tenantId, String username, String code, String uuid) {
+        String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
+        String captcha = RedisUtils.getCacheObject(verifyKey);
+        RedisUtils.deleteObject(verifyKey);
+        if (captcha == null) {
+            loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha)) {
+            loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
+            throw new CaptchaException();
+        }
+    }
+
+    private SysUserVo loadUserByUsername(String username) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
+            throw new UserException("user.not.exists", username);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
+            throw new UserException("user.blocked", username);
+        }
+        return user;
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
new file mode 100644
index 0000000..89f8462
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
@@ -0,0 +1,102 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.domain.model.SmsLoginBody;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鐭俊璁よ瘉绛栫暐
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("sms" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class SmsAuthStrategy implements IAuthStrategy {
+
+    private final SysLoginService loginService;
+    private final SysUserMapper userMapper;
+
+    @Override
+    public LoginVo login(String body, SysClientVo client) {
+        SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        String tenantId = loginBody.getTenantId();
+        String phonenumber = loginBody.getPhonenumber();
+        String smsCode = loginBody.getSmsCode();
+        LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+            SysUserVo user = loadUserByPhonenumber(phonenumber);
+            loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
+        loginUser.setClientKey(client.getClientKey());
+        loginUser.setDeviceType(client.getDeviceType());
+        SaLoginModel model = new SaLoginModel();
+        model.setDevice(client.getDeviceType());
+        // 鑷畾涔夊垎閰� 涓嶅悓鐢ㄦ埛浣撶郴 涓嶅悓 token 鎺堟潈鏃堕棿 涓嶈缃粯璁よ蛋鍏ㄥ眬 yml 閰嶇疆
+        // 渚嬪: 鍚庡彴鐢ㄦ埛30鍒嗛挓杩囨湡 app鐢ㄦ埛1澶╄繃鏈�
+        model.setTimeout(client.getTimeout());
+        model.setActiveTimeout(client.getActiveTimeout());
+        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
+        // 鐢熸垚token
+        LoginHelper.login(loginUser, model);
+
+        LoginVo loginVo = new LoginVo();
+        loginVo.setAccessToken(StpUtil.getTokenValue());
+        loginVo.setExpireIn(StpUtil.getTokenTimeout());
+        loginVo.setClientId(client.getClientId());
+        return loginVo;
+    }
+
+    /**
+     * 鏍¢獙鐭俊楠岃瘉鐮�
+     */
+    private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
+        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
+        if (StringUtils.isBlank(code)) {
+            loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        return code.equals(smsCode);
+    }
+
+    private SysUserVo loadUserByPhonenumber(String phonenumber) {
+        SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber);
+            throw new UserException("user.not.exists", phonenumber);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", phonenumber);
+            throw new UserException("user.blocked", phonenumber);
+        }
+        return user;
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
new file mode 100644
index 0000000..8463026
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
@@ -0,0 +1,131 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.domain.model.SocialLoginBody;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.SocialUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysSocialService;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 绗笁鏂规巿鏉冪瓥鐣�
+ *
+ * @author thiszhc is 涓変笁
+ */
+@Slf4j
+@Service("social" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class SocialAuthStrategy implements IAuthStrategy {
+
+    private final SocialProperties socialProperties;
+    private final ISysSocialService sysSocialService;
+    private final SysUserMapper userMapper;
+    private final SysLoginService loginService;
+
+    /**
+     * 鐧诲綍-绗笁鏂规巿鏉冪櫥褰�
+     *
+     * @param body     鐧诲綍淇℃伅
+     * @param client   瀹㈡埛绔俊鎭�
+     */
+    @Override
+    public LoginVo login(String body, SysClientVo client) {
+        SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        AuthResponse<AuthUser> response = SocialUtils.loginAuth(
+                loginBody.getSource(), loginBody.getSocialCode(),
+                loginBody.getSocialState(), socialProperties);
+        if (!response.ok()) {
+            throw new ServiceException(response.getMsg());
+        }
+        AuthUser authUserData = response.getData();
+        if ("GITEE".equals(authUserData.getSource())) {
+            // 濡傜敤鎴蜂娇鐢� gitee 鐧诲綍椤烘墜 star 缁欎綔鑰呬竴鐐规敮鎸� 鎷掔粷鐧藉珫
+            HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus")
+                    .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
+                    .executeAsync();
+            HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus")
+                    .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
+                    .executeAsync();
+        }
+
+        List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid());
+        if (CollUtil.isEmpty(list)) {
+            throw new ServiceException("浣犺繕娌℃湁缁戝畾绗笁鏂硅处鍙凤紝缁戝畾鍚庢墠鍙互鐧诲綍锛�");
+        }
+        SysSocialVo social;
+        if (TenantHelper.isEnable()) {
+            Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId()));
+            if (opt.isEmpty()) {
+                throw new ServiceException("瀵逛笉璧凤紝浣犳病鏈夋潈闄愮櫥褰曞綋鍓嶇鎴凤紒");
+            }
+            social = opt.get();
+        } else {
+            social = list.get(0);
+        }
+        LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> {
+            SysUserVo user = loadUser(social.getUserId());
+            // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+            return loginService.buildLoginUser(user);
+        });
+        loginUser.setClientKey(client.getClientKey());
+        loginUser.setDeviceType(client.getDeviceType());
+        SaLoginModel model = new SaLoginModel();
+        model.setDevice(client.getDeviceType());
+        // 鑷畾涔夊垎閰� 涓嶅悓鐢ㄦ埛浣撶郴 涓嶅悓 token 鎺堟潈鏃堕棿 涓嶈缃粯璁よ蛋鍏ㄥ眬 yml 閰嶇疆
+        // 渚嬪: 鍚庡彴鐢ㄦ埛30鍒嗛挓杩囨湡 app鐢ㄦ埛1澶╄繃鏈�
+        model.setTimeout(client.getTimeout());
+        model.setActiveTimeout(client.getActiveTimeout());
+        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
+        // 鐢熸垚token
+        LoginHelper.login(loginUser, model);
+
+        LoginVo loginVo = new LoginVo();
+        loginVo.setAccessToken(StpUtil.getTokenValue());
+        loginVo.setExpireIn(StpUtil.getTokenTimeout());
+        loginVo.setClientId(client.getClientId());
+        return loginVo;
+    }
+
+    private SysUserVo loadUser(Long userId) {
+        SysUserVo user = userMapper.selectVoById(userId);
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", "");
+            throw new UserException("user.not.exists", "");
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", "");
+            throw new UserException("user.blocked", "");
+        }
+        return user;
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
new file mode 100644
index 0000000..aa8be73
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
@@ -0,0 +1,92 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.model.XcxLoginBody;
+import org.dromara.common.core.domain.model.XcxLoginUser;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 灏忕▼搴忚璇佺瓥鐣�
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("xcx" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class XcxAuthStrategy implements IAuthStrategy {
+
+    private final SysLoginService loginService;
+
+    @Override
+    public LoginVo login(String body, SysClientVo client) {
+        XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
+        ValidatorUtils.validate(loginBody);
+        // xcxCode 涓� 灏忕▼搴忚皟鐢� wx.login 鎺堟潈鍚庤幏鍙�
+        String xcxCode = loginBody.getXcxCode();
+        // 澶氫釜灏忕▼搴忚瘑鍒娇鐢�
+        String appid = loginBody.getAppid();
+
+        // todo 浠ヤ笅鑷瀹炵幇
+        // 鏍¢獙 appid + appsrcret + xcxCode 璋冪敤鐧诲綍鍑瘉鏍¢獙鎺ュ彛 鑾峰彇 session_key 涓� openid
+        String openid = "";
+        // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+        SysUserVo user = loadUserByOpenid(openid);
+
+        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+        XcxLoginUser loginUser = new XcxLoginUser();
+        loginUser.setTenantId(user.getTenantId());
+        loginUser.setUserId(user.getUserId());
+        loginUser.setUsername(user.getUserName());
+        loginUser.setNickname(user.getNickName());
+        loginUser.setUserType(user.getUserType());
+        loginUser.setClientKey(client.getClientKey());
+        loginUser.setDeviceType(client.getDeviceType());
+        loginUser.setOpenid(openid);
+
+        SaLoginModel model = new SaLoginModel();
+        model.setDevice(client.getDeviceType());
+        // 鑷畾涔夊垎閰� 涓嶅悓鐢ㄦ埛浣撶郴 涓嶅悓 token 鎺堟潈鏃堕棿 涓嶈缃粯璁よ蛋鍏ㄥ眬 yml 閰嶇疆
+        // 渚嬪: 鍚庡彴鐢ㄦ埛30鍒嗛挓杩囨湡 app鐢ㄦ埛1澶╄繃鏈�
+        model.setTimeout(client.getTimeout());
+        model.setActiveTimeout(client.getActiveTimeout());
+        model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
+        // 鐢熸垚token
+        LoginHelper.login(loginUser, model);
+
+        LoginVo loginVo = new LoginVo();
+        loginVo.setAccessToken(StpUtil.getTokenValue());
+        loginVo.setExpireIn(StpUtil.getTokenTimeout());
+        loginVo.setClientId(client.getClientId());
+        loginVo.setOpenid(openid);
+        return loginVo;
+    }
+
+    private SysUserVo loadUserByOpenid(String openid) {
+        // 浣跨敤 openid 鏌ヨ缁戝畾鐢ㄦ埛 濡傛湭缁戝畾鐢ㄦ埛 鍒欐牴鎹笟鍔¤嚜琛屽鐞� 渚嬪 鍒涘缓榛樿鐢ㄦ埛
+        // todo 鑷瀹炵幇 userService.selectUserByOpenid(openid);
+        SysUserVo user = new SysUserVo();
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", openid);
+            // todo 鐢ㄦ埛涓嶅瓨鍦� 涓氬姟閫昏緫鑷瀹炵幇
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", openid);
+            // todo 鐢ㄦ埛宸茶鍋滅敤 涓氬姟閫昏緫鑷瀹炵幇
+        }
+        return user;
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/main/resources/application-dev.yml b/eims/ruoyi-admin/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..4ca327a
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/application-dev.yml
@@ -0,0 +1,261 @@
+--- # 鐩戞帶涓績閰嶇疆
+spring.boot.admin.client:
+  # 澧炲姞瀹㈡埛绔紑鍏�
+  enabled: false
+  url: http://localhost:9090/admin
+  instance:
+    service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
+  username: ruoyi
+  password: 123456
+
+--- # snail-job 閰嶇疆
+snail-job:
+  enabled: false
+  # 闇�瑕佸湪 SnailJob 鍚庡彴缁勭鐞嗗垱寤哄搴斿悕绉扮殑缁�,鐒跺悗鍒涘缓浠诲姟鐨勬椂鍊欓�夋嫨瀵瑰簲鐨勭粍,鎵嶈兘姝g‘鍒嗘淳浠诲姟
+  group: "ruoyi_group"
+  # SnailJob 鎺ュ叆楠岃瘉浠ょ墝 璇﹁ script/sql/snail_job.sql `sj_group_config` 琛�
+  token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
+  server:
+    host: 127.0.0.1
+    port: 17888
+  # 璇﹁ script/sql/snail_job.sql `sj_namespace` 琛�
+  namespace: ${spring.profiles.active}
+  # 闅忎富搴旂敤绔彛椋橀��
+  port: 2${server.port}
+
+--- # 鏁版嵁婧愰厤缃�
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    # 鍔ㄦ�佹暟鎹簮鏂囨。 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+    dynamic:
+      # 鎬ц兘鍒嗘瀽鎻掍欢(鏈夋�ц兘鎹熻�� 涓嶅缓璁敓浜х幆澧冧娇鐢�)
+      p6spy: true
+      # 璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
+      primary: master
+      # 涓ユ牸妯″紡 鍖归厤涓嶅埌鏁版嵁婧愬垯鎶ラ敊
+      strict: true
+      datasource:
+        # 涓诲簱鏁版嵁婧�
+        master:
+          type: ${spring.datasource.type}
+          driverClassName: com.mysql.cj.jdbc.Driver
+          # jdbc 鎵�鏈夊弬鏁伴厤缃弬鑰� https://lionli.blog.csdn.net/article/details/122018562
+          # rewriteBatchedStatements=true 鎵瑰鐞嗕紭鍖� 澶у箙鎻愬崌鎵归噺鎻掑叆鏇存柊鍒犻櫎鎬ц兘(瀵规暟鎹簱鏈夋�ц兘鎹熻�� 浣跨敤鎵归噺鎿嶄綔搴旇�冭檻鎬ц兘闂)
+          url: jdbc:mysql://localhost:3306/eims?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+          username: root
+          password: 123456
+        # 浠庡簱鏁版嵁婧�
+#        slave:
+#          lazy: true
+#          type: ${spring.datasource.type}
+#          driverClassName: com.mysql.cj.jdbc.Driver
+#          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+#          username:
+#          password:
+#        oracle:
+#          type: ${spring.datasource.type}
+#          driverClassName: oracle.jdbc.OracleDriver
+#          url: jdbc:oracle:thin:@//localhost:1521/XE
+#          username: ROOT
+#          password: root
+#        postgres:
+#          type: ${spring.datasource.type}
+#          driverClassName: org.postgresql.Driver
+#          url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
+#          username: root
+#          password: root
+#        sqlserver:
+#          type: ${spring.datasource.type}
+#          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
+#          url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
+#          username: SA
+#          password: root
+      hikari:
+        # 鏈�澶ц繛鎺ユ睜鏁伴噺
+        maxPoolSize: 20
+        # 鏈�灏忕┖闂茬嚎绋嬫暟閲�
+        minIdle: 10
+        # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+        connectionTimeout: 30000
+        # 鏍¢獙瓒呮椂鏃堕棿
+        validationTimeout: 5000
+        # 绌洪棽杩炴帴瀛樻椿鏈�澶ф椂闂达紝榛樿10鍒嗛挓
+        idleTimeout: 600000
+        # 姝ゅ睘鎬ф帶鍒舵睜涓繛鎺ョ殑鏈�闀跨敓鍛藉懆鏈燂紝鍊�0琛ㄧず鏃犻檺鐢熷懡鍛ㄦ湡锛岄粯璁�30鍒嗛挓
+        maxLifetime: 1800000
+        # 澶氫箙妫�鏌ヤ竴娆¤繛鎺ョ殑娲绘��
+        keepaliveTime: 30000
+
+--- # redis 鍗曟満閰嶇疆(鍗曟満涓庨泦缇ゅ彧鑳藉紑鍚竴涓彟涓�涓渶瑕佹敞閲婃帀)
+spring.data:
+  redis:
+    # 鍦板潃
+    host: localhost
+    # 绔彛锛岄粯璁や负6379
+    port: 6379
+    # 鏁版嵁搴撶储寮�
+    database: 0
+    # redis 瀵嗙爜蹇呴』閰嶇疆
+    #password: ruoyi123
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    # 鏄惁寮�鍚痵sl
+    ssl.enabled: false
+
+# redisson 閰嶇疆
+redisson:
+  # redis key鍓嶇紑
+  keyPrefix:
+  # 绾跨▼姹犳暟閲�
+  threads: 4
+  # Netty绾跨▼姹犳暟閲�
+  nettyThreads: 8
+  # 鍗曡妭鐐归厤缃�
+  singleServerConfig:
+    # 瀹㈡埛绔悕绉�
+    clientName: ${ruoyi.name}
+    # 鏈�灏忕┖闂茶繛鎺ユ暟
+    connectionMinimumIdleSize: 8
+    # 杩炴帴姹犲ぇ灏�
+    connectionPoolSize: 32
+    # 杩炴帴绌洪棽瓒呮椂锛屽崟浣嶏細姣
+    idleConnectionTimeout: 10000
+    # 鍛戒护绛夊緟瓒呮椂锛屽崟浣嶏細姣
+    timeout: 3000
+    # 鍙戝竷鍜岃闃呰繛鎺ユ睜澶у皬
+    subscriptionConnectionPoolSize: 50
+
+--- # mail 閭欢鍙戦��
+mail:
+  enabled: false
+  host: smtp.163.com
+  port: 465
+  # 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
+  auth: true
+  # 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
+  from: xxx@163.com
+  # 鐢ㄦ埛鍚嶏紙娉ㄦ剰锛氬鏋滀娇鐢╢oxmail閭锛屾澶剈ser涓簈q鍙凤級
+  user: xxx@163.com
+  # 瀵嗙爜锛堟敞鎰忥紝鏌愪簺閭闇�瑕佷负SMTP鏈嶅姟鍗曠嫭璁剧疆瀵嗙爜锛岃鎯呮煡鐪嬬浉鍏冲府鍔╋級
+  pass: xxxxxxxxxx
+  # 浣跨敤 STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘��
+  starttlsEnable: true
+  # 浣跨敤SSL瀹夊叏杩炴帴
+  sslEnable: true
+  # SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
+  timeout: 0
+  # Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
+  connectionTimeout: 0
+
+--- # sms 鐭俊 鏀寔 闃块噷浜� 鑵捐浜� 浜戠墖 绛夌瓑鍚勫紡鍚勬牱鐨勭煭淇℃湇鍔″晢
+# https://sms4j.com/doc3/ 宸紓閰嶇疆鏂囨。鍦板潃 鏀寔鍗曞巶鍟嗗閰嶇疆锛屽彲浠ラ厤缃涓悓鏃朵娇鐢�
+sms:
+  # 閰嶇疆婧愮被鍨嬬敤浜庢爣瀹氶厤缃潵婧�(interface,yaml)
+  config-type: yaml
+  # 鐢ㄤ簬鏍囧畾yml涓殑閰嶇疆鏄惁寮�鍚煭淇℃嫤鎴紝鎺ュ彛閰嶇疆涓嶅彈姝ら檺鍒�
+  restricted: true
+  # 鐭俊鎷︽埅闄愬埗鍗曟墜鏈哄彿姣忓垎閽熸渶澶у彂閫侊紝鍙寮�鍚簡鎷︽埅鐨勯厤缃湁鏁�
+  minute-max: 1
+  # 鐭俊鎷︽埅闄愬埗鍗曟墜鏈哄彿姣忔棩鏈�澶у彂閫侀噺锛屽彧瀵瑰紑鍚簡鎷︽埅鐨勯厤缃湁鏁�
+  account-max: 30
+  # 浠ヤ笅閰嶇疆鏉ヨ嚜浜� org.dromara.sms4j.provider.config.BaseConfig绫讳腑
+  blends:
+    # 鍞竴ID 鐢ㄤ簬鍙戦�佺煭淇″鎵惧叿浣撻厤缃� 闅忎究瀹氫箟鍒敤涓枃鍗冲彲
+    # 鍙互鍚屾椂瀛樺湪涓や釜鐩稿悓鍘傚晢 渚嬪: ali1 ali2 涓や釜涓嶅悓鐨勯樋閲岀煭淇¤处鍙� 涔熷彲鐢ㄤ簬鍖哄垎绉熸埛
+    config1:
+      # 妗嗘灦瀹氫箟鐨勫巶鍟嗗悕绉版爣璇嗭紝鏍囧畾姝ら厤缃槸鍝釜鍘傚晢锛岃缁嗚鐪嬪巶鍟嗘爣璇嗕粙缁嶉儴鍒�
+      supplier: alibaba
+      # 鏈変簺绉颁负accessKey鏈変簺绉颁箣涓篴piKey锛屼篃鏈夌О涓簊dkKey鎴栬�卆ppId銆�
+      access-key-id: 鎮ㄧ殑accessKey
+      # 绉颁负accessSecret鏈変簺绉颁箣涓篴piSecret
+      access-key-secret: 鎮ㄧ殑accessKeySecret
+      signature: 鎮ㄧ殑鐭俊绛惧悕
+      sdk-app-id: 鎮ㄧ殑sdkAppId
+    config2:
+      # 鍘傚晢鏍囪瘑锛屾爣瀹氭閰嶇疆鏄摢涓巶鍟嗭紝璇︾粏璇风湅鍘傚晢鏍囪瘑浠嬬粛閮ㄥ垎
+      supplier: tencent
+      access-key-id: 鎮ㄧ殑accessKey
+      access-key-secret: 鎮ㄧ殑accessKeySecret
+      signature: 鎮ㄧ殑鐭俊绛惧悕
+      sdk-app-id: 鎮ㄧ殑sdkAppId
+
+
+--- # 涓夋柟鎺堟潈
+justauth:
+  # 鍓嶇澶栫綉璁块棶鍦板潃
+  address: http://localhost:80
+  type:
+    maxkey:
+      # maxkey 鏈嶅姟鍣ㄥ湴鍧�
+      # 娉ㄦ剰 濡備笅鍧囬厤缃潎涓嶉渶瑕佷慨鏀� maxkey 宸茬粡鍐呯疆濂戒簡鏁版嵁
+      server-url: http://sso.maxkey.top
+      client-id: 876892492581044224
+      client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
+      redirect-uri: ${justauth.address}/social-callback?source=maxkey
+    topiam:
+      # topiam 鏈嶅姟鍣ㄥ湴鍧�
+      server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
+      client-id: 449c4*********937************759
+      client-secret: ac7***********1e0************28d
+      redirect-uri: ${justauth.address}/social-callback?source=topiam
+      scopes: [openid, email, phone, profile]
+    qq:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=qq
+      union-id: false
+    weibo:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=weibo
+    gitee:
+      client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
+      client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
+      redirect-uri: ${justauth.address}/social-callback?source=gitee
+    dingtalk:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=dingtalk
+    baidu:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=baidu
+    csdn:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=csdn
+    coding:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=coding
+      coding-group-name: xx
+    oschina:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=oschina
+    alipay_wallet:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
+      alipay-public-key: MIIB**************DAQAB
+    wechat_open:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_open
+    wechat_mp:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
+    wechat_enterprise:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
+      agent-id: 1000002
+    gitlab:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=gitlab
diff --git a/eims/ruoyi-admin/src/main/resources/application-prod.yml b/eims/ruoyi-admin/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..2823bba
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/application-prod.yml
@@ -0,0 +1,263 @@
+--- # 涓存椂鏂囦欢瀛樺偍浣嶇疆 閬垮厤涓存椂鏂囦欢琚郴缁熸竻鐞嗘姤閿�
+spring.servlet.multipart.location: /ruoyi/server/temp
+
+--- # 鐩戞帶涓績閰嶇疆
+spring.boot.admin.client:
+  # 澧炲姞瀹㈡埛绔紑鍏�
+  enabled: true
+  url: http://localhost:9090/admin
+  instance:
+    service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
+  username: ruoyi
+  password: 123456
+
+--- # snail-job 閰嶇疆
+snail-job:
+  enabled: true
+  # 闇�瑕佸湪 SnailJob 鍚庡彴缁勭鐞嗗垱寤哄搴斿悕绉扮殑缁�,鐒跺悗鍒涘缓浠诲姟鐨勬椂鍊欓�夋嫨瀵瑰簲鐨勭粍,鎵嶈兘姝g‘鍒嗘淳浠诲姟
+  group: "ruoyi_group"
+  # SnailJob 鎺ュ叆楠岃瘉浠ょ墝 璇﹁ script/sql/snail_job.sql `sj_group_config` 琛�
+  token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
+  server:
+    host: 127.0.0.1
+    port: 17888
+  # 璇﹁ script/sql/snail_job.sql `sj_namespace` 琛�
+  namespace: ${spring.profiles.active}
+  # 闅忎富搴旂敤绔彛椋橀��
+  port: 2${server.port}
+
+--- # 鏁版嵁婧愰厤缃�
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    # 鍔ㄦ�佹暟鎹簮鏂囨。 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+    dynamic:
+      # 鎬ц兘鍒嗘瀽鎻掍欢(鏈夋�ц兘鎹熻�� 涓嶅缓璁敓浜х幆澧冧娇鐢�)
+      p6spy: false
+      # 璁剧疆榛樿鐨勬暟鎹簮鎴栬�呮暟鎹簮缁�,榛樿鍊煎嵆涓� master
+      primary: master
+      # 涓ユ牸妯″紡 鍖归厤涓嶅埌鏁版嵁婧愬垯鎶ラ敊
+      strict: true
+      datasource:
+        # 涓诲簱鏁版嵁婧�
+        master:
+          type: ${spring.datasource.type}
+          driverClassName: com.mysql.cj.jdbc.Driver
+          # jdbc 鎵�鏈夊弬鏁伴厤缃弬鑰� https://lionli.blog.csdn.net/article/details/122018562
+          # rewriteBatchedStatements=true 鎵瑰鐞嗕紭鍖� 澶у箙鎻愬崌鎵归噺鎻掑叆鏇存柊鍒犻櫎鎬ц兘(瀵规暟鎹簱鏈夋�ц兘鎹熻�� 浣跨敤鎵归噺鎿嶄綔搴旇�冭檻鎬ц兘闂)
+          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+          username: root
+          password: root
+        # 浠庡簱鏁版嵁婧�
+        slave:
+          lazy: true
+          type: ${spring.datasource.type}
+          driverClassName: com.mysql.cj.jdbc.Driver
+          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+          username:
+          password:
+#        oracle:
+#          type: ${spring.datasource.type}
+#          driverClassName: oracle.jdbc.OracleDriver
+#          url: jdbc:oracle:thin:@//localhost:1521/XE
+#          username: ROOT
+#          password: root
+#        postgres:
+#          type: ${spring.datasource.type}
+#          driverClassName: org.postgresql.Driver
+#          url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
+#          username: root
+#          password: root
+#        sqlserver:
+#          type: ${spring.datasource.type}
+#          driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
+#          url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
+#          username: SA
+#          password: root
+      hikari:
+        # 鏈�澶ц繛鎺ユ睜鏁伴噺
+        maxPoolSize: 20
+        # 鏈�灏忕┖闂茬嚎绋嬫暟閲�
+        minIdle: 10
+        # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+        connectionTimeout: 30000
+        # 鏍¢獙瓒呮椂鏃堕棿
+        validationTimeout: 5000
+        # 绌洪棽杩炴帴瀛樻椿鏈�澶ф椂闂达紝榛樿10鍒嗛挓
+        idleTimeout: 600000
+        # 姝ゅ睘鎬ф帶鍒舵睜涓繛鎺ョ殑鏈�闀跨敓鍛藉懆鏈燂紝鍊�0琛ㄧず鏃犻檺鐢熷懡鍛ㄦ湡锛岄粯璁�30鍒嗛挓
+        maxLifetime: 1800000
+        # 澶氫箙妫�鏌ヤ竴娆¤繛鎺ョ殑娲绘��
+        keepaliveTime: 30000
+
+--- # redis 鍗曟満閰嶇疆(鍗曟満涓庨泦缇ゅ彧鑳藉紑鍚竴涓彟涓�涓渶瑕佹敞閲婃帀)
+spring.data:
+  redis:
+    # 鍦板潃
+    host: localhost
+    # 绔彛锛岄粯璁や负6379
+    port: 6379
+    # 鏁版嵁搴撶储寮�
+    database: 0
+    # redis 瀵嗙爜蹇呴』閰嶇疆
+    password: ruoyi123
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    # 鏄惁寮�鍚痵sl
+    ssl.enabled: false
+
+# redisson 閰嶇疆
+redisson:
+  # redis key鍓嶇紑
+  keyPrefix:
+  # 绾跨▼姹犳暟閲�
+  threads: 16
+  # Netty绾跨▼姹犳暟閲�
+  nettyThreads: 32
+  # 鍗曡妭鐐归厤缃�
+  singleServerConfig:
+    # 瀹㈡埛绔悕绉�
+    clientName: ${ruoyi.name}
+    # 鏈�灏忕┖闂茶繛鎺ユ暟
+    connectionMinimumIdleSize: 32
+    # 杩炴帴姹犲ぇ灏�
+    connectionPoolSize: 64
+    # 杩炴帴绌洪棽瓒呮椂锛屽崟浣嶏細姣
+    idleConnectionTimeout: 10000
+    # 鍛戒护绛夊緟瓒呮椂锛屽崟浣嶏細姣
+    timeout: 3000
+    # 鍙戝竷鍜岃闃呰繛鎺ユ睜澶у皬
+    subscriptionConnectionPoolSize: 50
+
+--- # mail 閭欢鍙戦��
+mail:
+  enabled: false
+  host: smtp.163.com
+  port: 465
+  # 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
+  auth: true
+  # 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
+  from: xxx@163.com
+  # 鐢ㄦ埛鍚嶏紙娉ㄦ剰锛氬鏋滀娇鐢╢oxmail閭锛屾澶剈ser涓簈q鍙凤級
+  user: xxx@163.com
+  # 瀵嗙爜锛堟敞鎰忥紝鏌愪簺閭闇�瑕佷负SMTP鏈嶅姟鍗曠嫭璁剧疆瀵嗙爜锛岃鎯呮煡鐪嬬浉鍏冲府鍔╋級
+  pass: xxxxxxxxxx
+  # 浣跨敤 STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘��
+  starttlsEnable: true
+  # 浣跨敤SSL瀹夊叏杩炴帴
+  sslEnable: true
+  # SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
+  timeout: 0
+  # Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
+  connectionTimeout: 0
+
+--- # sms 鐭俊 鏀寔 闃块噷浜� 鑵捐浜� 浜戠墖 绛夌瓑鍚勫紡鍚勬牱鐨勭煭淇℃湇鍔″晢
+# https://sms4j.com/doc3/ 宸紓閰嶇疆鏂囨。鍦板潃 鏀寔鍗曞巶鍟嗗閰嶇疆锛屽彲浠ラ厤缃涓悓鏃朵娇鐢�
+sms:
+  # 閰嶇疆婧愮被鍨嬬敤浜庢爣瀹氶厤缃潵婧�(interface,yaml)
+  config-type: yaml
+  # 鐢ㄤ簬鏍囧畾yml涓殑閰嶇疆鏄惁寮�鍚煭淇℃嫤鎴紝鎺ュ彛閰嶇疆涓嶅彈姝ら檺鍒�
+  restricted: true
+  # 鐭俊鎷︽埅闄愬埗鍗曟墜鏈哄彿姣忓垎閽熸渶澶у彂閫侊紝鍙寮�鍚簡鎷︽埅鐨勯厤缃湁鏁�
+  minute-max: 1
+  # 鐭俊鎷︽埅闄愬埗鍗曟墜鏈哄彿姣忔棩鏈�澶у彂閫侀噺锛屽彧瀵瑰紑鍚簡鎷︽埅鐨勯厤缃湁鏁�
+  account-max: 30
+  # 浠ヤ笅閰嶇疆鏉ヨ嚜浜� org.dromara.sms4j.provider.config.BaseConfig绫讳腑
+  blends:
+    # 鍞竴ID 鐢ㄤ簬鍙戦�佺煭淇″鎵惧叿浣撻厤缃� 闅忎究瀹氫箟鍒敤涓枃鍗冲彲
+    # 鍙互鍚屾椂瀛樺湪涓や釜鐩稿悓鍘傚晢 渚嬪: ali1 ali2 涓や釜涓嶅悓鐨勯樋閲岀煭淇¤处鍙� 涔熷彲鐢ㄤ簬鍖哄垎绉熸埛
+    config1:
+      # 妗嗘灦瀹氫箟鐨勫巶鍟嗗悕绉版爣璇嗭紝鏍囧畾姝ら厤缃槸鍝釜鍘傚晢锛岃缁嗚鐪嬪巶鍟嗘爣璇嗕粙缁嶉儴鍒�
+      supplier: alibaba
+      # 鏈変簺绉颁负accessKey鏈変簺绉颁箣涓篴piKey锛屼篃鏈夌О涓簊dkKey鎴栬�卆ppId銆�
+      access-key-id: 鎮ㄧ殑accessKey
+      # 绉颁负accessSecret鏈変簺绉颁箣涓篴piSecret
+      access-key-secret: 鎮ㄧ殑accessKeySecret
+      signature: 鎮ㄧ殑鐭俊绛惧悕
+      sdk-app-id: 鎮ㄧ殑sdkAppId
+    config2:
+      # 鍘傚晢鏍囪瘑锛屾爣瀹氭閰嶇疆鏄摢涓巶鍟嗭紝璇︾粏璇风湅鍘傚晢鏍囪瘑浠嬬粛閮ㄥ垎
+      supplier: tencent
+      access-key-id: 鎮ㄧ殑accessKey
+      access-key-secret: 鎮ㄧ殑accessKeySecret
+      signature: 鎮ㄧ殑鐭俊绛惧悕
+      sdk-app-id: 鎮ㄧ殑sdkAppId
+
+--- # 涓夋柟鎺堟潈
+justauth:
+  # 鍓嶇澶栫綉璁块棶鍦板潃
+  address: http://localhost:80
+  type:
+    maxkey:
+      # maxkey 鏈嶅姟鍣ㄥ湴鍧�
+      # 娉ㄦ剰 濡備笅鍧囬厤缃潎涓嶉渶瑕佷慨鏀� maxkey 宸茬粡鍐呯疆濂戒簡鏁版嵁
+      server-url: http://sso.maxkey.top
+      client-id: 876892492581044224
+      client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
+      redirect-uri: ${justauth.address}/social-callback?source=maxkey
+    topiam:
+      # topiam 鏈嶅姟鍣ㄥ湴鍧�
+      server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
+      client-id: 449c4*********937************759
+      client-secret: ac7***********1e0************28d
+      redirect-uri: ${justauth.address}/social-callback?source=topiam
+      scopes: [ openid, email, phone, profile ]
+    qq:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=qq
+      union-id: false
+    weibo:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=weibo
+    gitee:
+      client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
+      client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
+      redirect-uri: ${justauth.address}/social-callback?source=gitee
+    dingtalk:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=dingtalk
+    baidu:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=baidu
+    csdn:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=csdn
+    coding:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=coding
+      coding-group-name: xx
+    oschina:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=oschina
+    alipay_wallet:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
+      alipay-public-key: MIIB**************DAQAB
+    wechat_open:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_open
+    wechat_mp:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
+    wechat_enterprise:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
+      agent-id: 1000002
+    gitlab:
+      client-id: 10**********6
+      client-secret: 1f7d08**********5b7**********29e
+      redirect-uri: ${justauth.address}/social-callback?source=gitlab
diff --git a/eims/ruoyi-admin/src/main/resources/application.yml b/eims/ruoyi-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..7b1cc81
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/application.yml
@@ -0,0 +1,295 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi-Vue-Plus
+  # 鐗堟湰
+  version: ${revision}
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2024
+
+captcha:
+  enable: false
+  # 椤甸潰 <鍙傛暟璁剧疆> 鍙紑鍚叧闂� 楠岃瘉鐮佹牎楠�
+  # 楠岃瘉鐮佺被鍨� math 鏁扮粍璁$畻 char 瀛楃楠岃瘉
+  type: MATH
+  # line 绾挎骞叉壈 circle 鍦嗗湀骞叉壈 shear 鎵洸骞叉壈
+  category: CIRCLE
+  # 鏁板瓧楠岃瘉鐮佷綅鏁�
+  numberLength: 1
+  # 瀛楃楠岃瘉鐮侀暱搴�
+  charLength: 4
+
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 8080
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  # undertow 閰嶇疆
+  undertow:
+    # HTTP post鍐呭鐨勬渶澶уぇ灏忋�傚綋鍊间负-1鏃讹紝榛樿鍊间负澶у皬鏄棤闄愮殑
+    max-http-post-size: -1
+    # 浠ヤ笅鐨勯厤缃細褰卞搷buffer,杩欎簺buffer浼氱敤浜庢湇鍔″櫒杩炴帴鐨処O鎿嶄綔,鏈夌偣绫讳技netty鐨勬睜鍖栧唴瀛樼鐞�
+    # 姣忓潡buffer鐨勭┖闂村ぇ灏�,瓒婂皬鐨勭┖闂磋鍒╃敤瓒婂厖鍒�
+    buffer-size: 512
+    # 鏄惁鍒嗛厤鐨勭洿鎺ュ唴瀛�
+    direct-buffers: true
+    threads:
+      # 璁剧疆IO绾跨▼鏁�, 瀹冧富瑕佹墽琛岄潪闃诲鐨勪换鍔�,瀹冧滑浼氳礋璐e涓繛鎺�, 榛樿璁剧疆姣忎釜CPU鏍稿績涓�涓嚎绋�
+      io: 8
+      # 闃诲浠诲姟绾跨▼姹�, 褰撴墽琛岀被浼約ervlet璇锋眰闃诲鎿嶄綔, undertow浼氫粠杩欎釜绾跨▼姹犱腑鍙栧緱绾跨▼,瀹冪殑鍊艰缃彇鍐充簬绯荤粺鐨勮礋杞�
+      worker: 256
+
+# 鏃ュ織閰嶇疆
+logging:
+  level:
+    org.dromara: @logging.level@
+    org.springframework: warn
+    org.mybatis.spring.mapper: error
+  config: classpath:logback-plus.xml
+
+# 鐢ㄦ埛閰嶇疆
+user:
+  password:
+    # 瀵嗙爜鏈�澶ч敊璇鏁�
+    maxRetryCount: 5
+    # 瀵嗙爜閿佸畾鏃堕棿锛堥粯璁�10鍒嗛挓锛�
+    lockTime: 10
+
+# Spring閰嶇疆
+spring:
+  application:
+    name: ${ruoyi.name}
+  threads:
+    # 寮�鍚櫄鎷熺嚎绋� 浠卝dk21鍙敤
+    virtual:
+      enabled: false
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  profiles:
+    active: @profiles.active@
+  # 鏂囦欢涓婁紶
+  servlet:
+    multipart:
+      # 鍗曚釜鏂囦欢澶у皬
+      max-file-size: 10MB
+      # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+      max-request-size: 20MB
+  mvc:
+    # 璁剧疆闈欐�佽祫婧愯矾寰� 闃叉鎵�鏈夎姹傞兘鍘绘煡闈欐�佽祫婧�
+    static-path-pattern: /static/**
+    format:
+      date-time: yyyy-MM-dd HH:mm:ss
+  jackson:
+    # 鏃ユ湡鏍煎紡鍖�
+    date-format: yyyy-MM-dd HH:mm:ss
+    serialization:
+      # 鏍煎紡鍖栬緭鍑�
+      indent_output: false
+      # 蹇界暐鏃犳硶杞崲鐨勫璞�
+      fail_on_empty_beans: false
+    deserialization:
+      # 鍏佽瀵硅薄蹇界暐json涓笉瀛樺湪鐨勫睘鎬�
+      fail_on_unknown_properties: false
+
+# Sa-Token閰嶇疆
+sa-token:
+  # token鍚嶇О (鍚屾椂涔熸槸cookie鍚嶇О)
+  token-name: Authorization
+  # 鏄惁鍏佽鍚屼竴璐﹀彿骞跺彂鐧诲綍 (涓簍rue鏃跺厑璁镐竴璧风櫥褰�, 涓篺alse鏃舵柊鐧诲綍鎸ゆ帀鏃х櫥褰�)
+  is-concurrent: true
+  # 鍦ㄥ浜虹櫥褰曞悓涓�璐﹀彿鏃讹紝鏄惁鍏辩敤涓�涓猼oken (涓簍rue鏃舵墍鏈夌櫥褰曞叡鐢ㄤ竴涓猼oken, 涓篺alse鏃舵瘡娆$櫥褰曟柊寤轰竴涓猼oken)
+  is-share: false
+  # jwt绉橀挜
+  jwt-secret-key: abcdefghijklmnopqrstuvwxyz
+
+# security閰嶇疆
+security:
+  # 鎺掗櫎璺緞
+  excludes:
+    # 闈欐�佽祫婧�
+    - /*.html
+    - /**/*.html
+    - /**/*.css
+    - /**/*.js
+    # 鍏叡璺緞
+    - /favicon.ico
+    - /error
+    # swagger 鏂囨。閰嶇疆
+    - /*/api-docs
+    - /*/api-docs/**
+
+# 澶氱鎴烽厤缃�
+tenant:
+  # 鏄惁寮�鍚�
+  enable: false
+  # 鎺掗櫎琛�
+  excludes:
+    - sys_menu
+    - sys_tenant
+    - sys_tenant_package
+    - sys_role_dept
+    - sys_role_menu
+    - sys_user_post
+    - sys_user_role
+    - sys_client
+    - sys_oss_config
+
+# MyBatisPlus閰嶇疆
+# https://baomidou.com/config/
+mybatis-plus:
+  # 澶氬寘鍚嶄娇鐢� 渚嬪 org.dromara.**.mapper,org.xxx.**.mapper
+  mapperPackage: org.dromara.**.mapper,cn.shlanbao.**.mapper
+  # 瀵瑰簲鐨� XML 鏂囦欢浣嶇疆
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 瀹炰綋鎵弿锛屽涓猵ackage鐢ㄩ�楀彿鎴栬�呭垎鍙峰垎闅�
+  typeAliasesPackage: org.dromara.**.domain, cn.shlanbao.**.domain
+  global-config:
+    dbConfig:
+      # 涓婚敭绫诲瀷
+      # AUTO 鑷 NONE 绌� INPUT 鐢ㄦ埛杈撳叆 ASSIGN_ID 闆姳 ASSIGN_UUID 鍞竴 UUID
+      # 濡傞渶鏀逛负鑷 闇�瑕佸皢鏁版嵁搴撹〃鍏ㄩ儴璁剧疆涓鸿嚜澧�
+      idType: ASSIGN_ID
+
+# 鏁版嵁鍔犲瘑
+mybatis-encryptor:
+  # 鏄惁寮�鍚姞瀵�
+  enable: false
+  # 榛樿鍔犲瘑绠楁硶
+  algorithm: BASE64
+  # 缂栫爜鏂瑰紡 BASE64/HEX銆傞粯璁ASE64
+  encode: BASE64
+  # 瀹夊叏绉橀挜 瀵圭О绠楁硶鐨勭閽� 濡傦細AES锛孲M4
+  password:
+  # 鍏閽� 闈炲绉扮畻娉曠殑鍏閽� 濡傦細SM2锛孯SA
+  publicKey:
+  privateKey:
+
+# api鎺ュ彛鍔犲瘑
+api-decrypt:
+  # 鏄惁寮�鍚叏灞�鎺ュ彛鍔犲瘑
+  enabled: false
+  # AES 鍔犲瘑澶存爣璇�
+  headerFlag: encrypt-key
+  # 鍝嶅簲鍔犲瘑鍏挜 闈炲绉扮畻娉曠殑鍏閽� 濡傦細SM2锛孯SA 浣跨敤鑰呰鑷鏇存崲
+  # 瀵瑰簲鍓嶇瑙e瘑绉侀挜 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
+  publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
+  # 璇锋眰瑙e瘑绉侀挜 闈炲绉扮畻娉曠殑鍏閽� 濡傦細SM2锛孯SA 浣跨敤鑰呰鑷鏇存崲
+  # 瀵瑰簲鍓嶇鍔犲瘑鍏挜 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+  privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
+
+springdoc:
+  api-docs:
+    # 鏄惁寮�鍚帴鍙f枃妗�
+    enabled: true
+#  swagger-ui:
+#    # 鎸佷箙鍖栬璇佹暟鎹�
+#    persistAuthorization: true
+  info:
+    # 鏍囬
+    title: '鏍囬锛�${ruoyi.name}澶氱鎴风鐞嗙郴缁焈鎺ュ彛鏂囨。'
+    # 鎻忚堪
+    description: '鎻忚堪锛氱敤浜庣鐞嗛泦鍥㈡棗涓嬪叕鍙哥殑浜哄憳淇℃伅,鍏蜂綋鍖呮嫭XXX,XXX妯″潡...'
+    # 鐗堟湰
+    version: '鐗堟湰鍙�: ${ruoyi.version}'
+    # 浣滆�呬俊鎭�
+    contact:
+      name: Lion Li
+      email: crazylionli@163.com
+      url: https://gitee.com/dromara/RuoYi-Vue-Plus
+  components:
+    # 閴存潈鏂瑰紡閰嶇疆
+    security-schemes:
+      apiKey:
+        type: APIKEY
+        in: HEADER
+        name: ${sa-token.token-name}
+  #杩欓噷瀹氫箟浜嗕袱涓垎缁勶紝鍙畾涔夊涓紝涔熷彲浠ヤ笉瀹氫箟
+  group-configs:
+    - group: 1.婕旂ず妯″潡
+      packages-to-scan: org.dromara.demo
+    - group: 2.閫氱敤妯″潡
+      packages-to-scan: org.dromara.web
+    - group: 3.绯荤粺妯″潡
+      packages-to-scan: org.dromara.system
+    - group: 4.浠g爜鐢熸垚妯″潡
+      packages-to-scan: org.dromara.generator
+    - group: 5.璁惧妯″潡
+      packages-to-scan: cn.shlanbao.eims
+
+# 闃叉XSS鏀诲嚮
+xss:
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
+# 鍏ㄥ眬绾跨▼姹犵浉鍏抽厤缃�
+# 濡備娇鐢↗DK21璇风洿鎺ヤ娇鐢ㄨ櫄鎷熺嚎绋� 涓嶈寮�鍚閰嶇疆
+thread-pool:
+  # 鏄惁寮�鍚嚎绋嬫睜
+  enabled: false
+  # 闃熷垪鏈�澶ч暱搴�
+  queueCapacity: 128
+  # 绾跨▼姹犵淮鎶ょ嚎绋嬫墍鍏佽鐨勭┖闂叉椂闂�
+  keepAliveSeconds: 300
+
+--- # 鍒嗗竷寮忛攣 lock4j 鍏ㄥ眬閰嶇疆
+lock4j:
+  # 鑾峰彇鍒嗗竷寮忛攣瓒呮椂鏃堕棿锛岄粯璁や负 3000 姣
+  acquire-timeout: 3000
+  # 鍒嗗竷寮忛攣鐨勮秴鏃舵椂闂达紝榛樿涓� 30 绉�
+  expire: 30000
+
+--- # Actuator 鐩戞帶绔偣鐨勯厤缃」
+management:
+  endpoints:
+    web:
+      exposure:
+        include: '*'
+  endpoint:
+    health:
+      show-details: ALWAYS
+    logfile:
+      external-file: ./logs/sys-console.log
+
+--- # 榛樿/鎺ㄨ崘浣跨敤sse鎺ㄩ��
+sse:
+  enabled: true
+  path: /resource/sse
+
+--- # websocket
+websocket:
+  # 濡傛灉鍏抽棴 闇�瑕佸拰鍓嶇寮�鍏充竴璧峰叧闂�
+  enabled: false
+  # 璺緞
+  path: /resource/websocket
+  # 璁剧疆璁块棶婧愬湴鍧�
+  allowedOrigins: '*'
+
+--- #flowable閰嶇疆
+flowable:
+  # 寮�鍏� 鐢ㄤ簬鍚姩/鍋滅敤宸ヤ綔娴�
+  enabled: true
+  process.enabled: ${flowable.enabled}
+  eventregistry.enabled: ${flowable.enabled}
+  async-executor-activate: false #鍏抽棴瀹氭椂浠诲姟JOB
+  #  灏哾atabaseSchemaUpdate璁剧疆涓簍rue銆傚綋Flowable鍙戠幇搴撲笌鏁版嵁搴撹〃缁撴瀯涓嶄竴鑷存椂锛屼細鑷姩灏嗘暟鎹簱琛ㄧ粨鏋勫崌绾ц嚦鏂扮増鏈��
+  database-schema-update: true
+  activity-font-name: 瀹嬩綋
+  label-font-name: 瀹嬩綋
+  annotation-font-name: 瀹嬩綋
+  # 鍏抽棴鍚勪釜妯″潡鐢熸垚琛紝鐩墠鍙娇鐢ㄥ伐浣滄祦鍩虹琛�
+  idm:
+    enabled: false
+  cmmn:
+    enabled: false
+  dmn:
+    enabled: false
+  app:
+    enabled: false
diff --git a/eims/ruoyi-admin/src/main/resources/banner.txt b/eims/ruoyi-admin/src/main/resources/banner.txt
new file mode 100644
index 0000000..21b1126
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+Application Version: ${revision}
+Spring Boot Version: ${spring-boot.version}
+__________            _____.___.__         ____   ____                     __________.__
+\______   \__ __  ____\__  |   |__|        \   \ /   /_ __   ____          \______   \  |  __ __  ______
+ |       _/  |  \/  _ \/   |   |  |  ______ \   Y   /  |  \_/ __ \   ______ |     ___/  | |  |  \/  ___/
+ |    |   \  |  (  <_> )____   |  | /_____/  \     /|  |  /\  ___/  /_____/ |    |   |  |_|  |  /\___ \
+ |____|_  /____/ \____// ______|__|           \___/ |____/  \___  >         |____|   |____/____//____  >
+        \/             \/                                       \/                                   \/
diff --git a/eims/ruoyi-admin/src/main/resources/i18n/messages.properties b/eims/ruoyi-admin/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..cce11c8
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -0,0 +1,61 @@
+#閿欒娑堟伅
+not.null=* 蹇呴』濉啓
+user.jcaptcha.error=楠岃瘉鐮侀敊璇�
+user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥
+user.not.exists=瀵逛笉璧�, 鎮ㄧ殑璐﹀彿锛歿0} 涓嶅瓨鍦�.
+user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆�
+user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茶鍒犻櫎
+user.blocked=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茬鐢紝璇疯仈绯荤鐞嗗憳
+role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+user.logout.success=閫�鍑烘垚鍔�
+length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.username.not.blank=鐢ㄦ埛鍚嶄笉鑳戒负绌�
+user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶�
+user.username.length.valid=璐︽埛闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.password.not.blank=鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖
+user.password.length.valid=鐢ㄦ埛瀵嗙爜闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.password.not.valid=* 5-50涓瓧绗�
+user.email.not.valid=閭鏍煎紡閿欒
+user.email.not.blank=閭涓嶈兘涓虹┖
+user.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌�
+user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
+user.login.success=鐧诲綍鎴愬姛
+user.register.success=娉ㄥ唽鎴愬姛
+user.register.save.error=淇濆瓨鐢ㄦ埛 {0} 澶辫触锛屾敞鍐岃处鍙峰凡瀛樺湪
+user.register.error=娉ㄥ唽澶辫触锛岃鑱旂郴绯荤粺绠$悊浜哄憳
+user.notfound=璇烽噸鏂扮櫥褰�
+user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰�
+user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍
+auth.grant.type.error=璁よ瘉鏉冮檺绫诲瀷閿欒
+auth.grant.type.blocked=璁よ瘉鏉冮檺绫诲瀷宸茬鐢�
+auth.grant.type.not.blank=璁よ瘉鏉冮檺绫诲瀷涓嶈兘涓虹┖
+auth.clientid.not.blank=璁よ瘉瀹㈡埛绔痠d涓嶈兘涓虹┖
+##鏂囦欢涓婁紶娑堟伅
+upload.exceed.maxSize=涓婁紶鐨勬枃浠跺ぇ灏忚秴鍑洪檺鍒剁殑鏂囦欢澶у皬锛�<br/>鍏佽鐨勬枃浠舵渶澶уぇ灏忔槸锛歿0}MB锛�
+upload.filename.exceed.length=涓婁紶鐨勬枃浠跺悕鏈�闀縶0}涓瓧绗�
+##鏉冮檺
+no.permission=鎮ㄦ病鏈夋暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.create.permission=鎮ㄦ病鏈夊垱寤烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.update.permission=鎮ㄦ病鏈変慨鏀规暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.delete.permission=鎮ㄦ病鏈夊垹闄ゆ暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.export.permission=鎮ㄦ病鏈夊鍑烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+repeat.submit.message=涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍊欏啀璇�
+rate.limiter.message=璁块棶杩囦簬棰戠箒锛岃绋嶅�欏啀璇�
+sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌�
+sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+email.code.not.blank=閭楠岃瘉鐮佷笉鑳戒负绌�
+email.code.retry.limit.count=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+email.code.retry.limit.exceed=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+xcx.code.not.blank=灏忕▼搴廩code]涓嶈兘涓虹┖
+social.source.not.blank=绗笁鏂圭櫥褰曞钩鍙癧source]涓嶈兘涓虹┖
+social.code.not.blank=绗笁鏂圭櫥褰曞钩鍙癧code]涓嶈兘涓虹┖
+social.state.not.blank=绗笁鏂圭櫥褰曞钩鍙癧state]涓嶈兘涓虹┖
+##绉熸埛
+tenant.number.not.blank=绉熸埛缂栧彿涓嶈兘涓虹┖
+tenant.not.exists=瀵逛笉璧�, 鎮ㄧ殑绉熸埛涓嶅瓨鍦紝璇疯仈绯荤鐞嗗憳
+tenant.blocked=瀵逛笉璧凤紝鎮ㄧ殑绉熸埛宸茬鐢紝璇疯仈绯荤鐞嗗憳
+tenant.expired=瀵逛笉璧凤紝鎮ㄧ殑绉熸埛宸茶繃鏈燂紝璇疯仈绯荤鐞嗗憳
diff --git a/eims/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/eims/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
new file mode 100644
index 0000000..f948c4a
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -0,0 +1,61 @@
+#閿欒娑堟伅
+not.null=* Required fill in
+user.jcaptcha.error=Captcha error
+user.jcaptcha.expire=Captcha invalid
+user.not.exists=Sorry, your account: {0} does not exist
+user.password.not.match=User does not exist/Password error
+user.password.retry.limit.count=Password input error {0} times
+user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
+user.password.delete=Sorry, your account锛歿0} has been deleted
+user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
+role.blocked=Role disabled锛宲lease contact administrators
+user.logout.success=Exit successful
+length.not.valid=The length must be between {min} and {max} characters
+user.username.not.blank=Username cannot be blank
+user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
+user.username.length.valid=Account length must be between {min} and {max} characters
+user.password.not.blank=Password cannot be empty
+user.password.length.valid=Password length must be between {min} and {max} characters
+user.password.not.valid=* 5-50 characters
+user.email.not.valid=Mailbox format error
+user.email.not.blank=Mailbox cannot be blank
+user.phonenumber.not.blank=Phone number cannot be blank
+user.mobile.phone.number.not.valid=Phone number format error
+user.login.success=Login successful
+user.register.success=Register successful
+user.register.save.error=Failed to save user {0}, The registered account already exists
+user.register.error=Register failed, please contact system administrator
+user.notfound=Please login again
+user.forcelogout=The administrator is forced to exit锛宲lease login again
+user.unknown.error=Unknown error, please login again
+auth.grant.type.error=Auth grant type error
+auth.grant.type.blocked=Auth grant type disabled
+auth.grant.type.not.blank=Auth grant type cannot be blank
+auth.clientid.not.blank=Auth clientid cannot be blank
+##鏂囦欢涓婁紶娑堟伅
+upload.exceed.maxSize=The uploaded file size exceeds the limit file size锛�<br/>the maximum allowed file size is锛歿0}MB锛�
+upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
+##鏉冮檺
+no.permission=You do not have permission to the data锛宲lease contact your administrator to add permissions [{0}]
+no.create.permission=You do not have permission to create data锛宲lease contact your administrator to add permissions [{0}]
+no.update.permission=You do not have permission to modify data锛宲lease contact your administrator to add permissions [{0}]
+no.delete.permission=You do not have permission to delete data锛宲lease contact your administrator to add permissions [{0}]
+no.export.permission=You do not have permission to export data锛宲lease contact your administrator to add permissions [{0}]
+no.view.permission=You do not have permission to view data锛宲lease contact your administrator to add permissions [{0}]
+repeat.submit.message=Repeat submit is not allowed, please try again later
+rate.limiter.message=Visit too frequently, please try again later
+sms.code.not.blank=Sms code cannot be blank
+sms.code.retry.limit.count=Sms code input error {0} times
+sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
+email.code.not.blank=Email code cannot be blank
+email.code.retry.limit.count=Email code input error {0} times
+email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
+xcx.code.not.blank=Mini program [code] cannot be blank
+social.source.not.blank=Social login platform [source] cannot be blank
+social.code.not.blank=Social login platform [code] cannot be blank
+social.state.not.blank=Social login platform [state] cannot be blank
+##绉熸埛
+tenant.number.not.blank=Tenant number cannot be blank
+tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator
+tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator
+tenant.expired=Sorry, your tenant has expired. Please contact the administrator.
diff --git a/eims/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/eims/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
new file mode 100644
index 0000000..cce11c8
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -0,0 +1,61 @@
+#閿欒娑堟伅
+not.null=* 蹇呴』濉啓
+user.jcaptcha.error=楠岃瘉鐮侀敊璇�
+user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥
+user.not.exists=瀵逛笉璧�, 鎮ㄧ殑璐﹀彿锛歿0} 涓嶅瓨鍦�.
+user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆�
+user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茶鍒犻櫎
+user.blocked=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛歿0} 宸茬鐢紝璇疯仈绯荤鐞嗗憳
+role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+user.logout.success=閫�鍑烘垚鍔�
+length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.username.not.blank=鐢ㄦ埛鍚嶄笉鑳戒负绌�
+user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶�
+user.username.length.valid=璐︽埛闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.password.not.blank=鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖
+user.password.length.valid=鐢ㄦ埛瀵嗙爜闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+user.password.not.valid=* 5-50涓瓧绗�
+user.email.not.valid=閭鏍煎紡閿欒
+user.email.not.blank=閭涓嶈兘涓虹┖
+user.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌�
+user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
+user.login.success=鐧诲綍鎴愬姛
+user.register.success=娉ㄥ唽鎴愬姛
+user.register.save.error=淇濆瓨鐢ㄦ埛 {0} 澶辫触锛屾敞鍐岃处鍙峰凡瀛樺湪
+user.register.error=娉ㄥ唽澶辫触锛岃鑱旂郴绯荤粺绠$悊浜哄憳
+user.notfound=璇烽噸鏂扮櫥褰�
+user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰�
+user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍
+auth.grant.type.error=璁よ瘉鏉冮檺绫诲瀷閿欒
+auth.grant.type.blocked=璁よ瘉鏉冮檺绫诲瀷宸茬鐢�
+auth.grant.type.not.blank=璁よ瘉鏉冮檺绫诲瀷涓嶈兘涓虹┖
+auth.clientid.not.blank=璁よ瘉瀹㈡埛绔痠d涓嶈兘涓虹┖
+##鏂囦欢涓婁紶娑堟伅
+upload.exceed.maxSize=涓婁紶鐨勬枃浠跺ぇ灏忚秴鍑洪檺鍒剁殑鏂囦欢澶у皬锛�<br/>鍏佽鐨勬枃浠舵渶澶уぇ灏忔槸锛歿0}MB锛�
+upload.filename.exceed.length=涓婁紶鐨勬枃浠跺悕鏈�闀縶0}涓瓧绗�
+##鏉冮檺
+no.permission=鎮ㄦ病鏈夋暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.create.permission=鎮ㄦ病鏈夊垱寤烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.update.permission=鎮ㄦ病鏈変慨鏀规暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.delete.permission=鎮ㄦ病鏈夊垹闄ゆ暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.export.permission=鎮ㄦ病鏈夊鍑烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+repeat.submit.message=涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍊欏啀璇�
+rate.limiter.message=璁块棶杩囦簬棰戠箒锛岃绋嶅�欏啀璇�
+sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌�
+sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+email.code.not.blank=閭楠岃瘉鐮佷笉鑳戒负绌�
+email.code.retry.limit.count=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+email.code.retry.limit.exceed=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+xcx.code.not.blank=灏忕▼搴廩code]涓嶈兘涓虹┖
+social.source.not.blank=绗笁鏂圭櫥褰曞钩鍙癧source]涓嶈兘涓虹┖
+social.code.not.blank=绗笁鏂圭櫥褰曞钩鍙癧code]涓嶈兘涓虹┖
+social.state.not.blank=绗笁鏂圭櫥褰曞钩鍙癧state]涓嶈兘涓虹┖
+##绉熸埛
+tenant.number.not.blank=绉熸埛缂栧彿涓嶈兘涓虹┖
+tenant.not.exists=瀵逛笉璧�, 鎮ㄧ殑绉熸埛涓嶅瓨鍦紝璇疯仈绯荤鐞嗗憳
+tenant.blocked=瀵逛笉璧凤紝鎮ㄧ殑绉熸埛宸茬鐢紝璇疯仈绯荤鐞嗗憳
+tenant.expired=瀵逛笉璧凤紝鎮ㄧ殑绉熸埛宸茶繃鏈燂紝璇疯仈绯荤鐞嗗憳
diff --git a/eims/ruoyi-admin/src/main/resources/ip2region.xdb b/eims/ruoyi-admin/src/main/resources/ip2region.xdb
new file mode 100644
index 0000000..7052c05
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/ip2region.xdb
Binary files differ
diff --git a/eims/ruoyi-admin/src/main/resources/logback-plus.xml b/eims/ruoyi-admin/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..40fa33b
--- /dev/null
+++ b/eims/ruoyi-admin/src/main/resources/logback-plus.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="log.path" value="./logs"/>
+    <property name="console.log.pattern"
+              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
+
+    <!-- 鎺у埗鍙拌緭鍑� -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${console.log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 鎺у埗鍙拌緭鍑� -->
+    <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sys-console.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶� 1澶� -->
+            <maxHistory>1</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>INFO</level>
+        </filter>
+    </appender>
+
+    <!-- 绯荤粺鏃ュ織杈撳嚭 -->
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sys-info.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>INFO</level>
+            <!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sys-error.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>ERROR</level>
+            <!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- info寮傛杈撳嚭 -->
+    <appender name="async_info" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 涓嶄涪澶辨棩蹇�.榛樿鐨�,濡傛灉闃熷垪鐨�80%宸叉弧,鍒欎細涓㈠純TRACT銆丏EBUG銆両NFO绾у埆鐨勬棩蹇� -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 鏇存敼榛樿鐨勯槦鍒楃殑娣卞害,璇ュ�间細褰卞搷鎬ц兘.榛樿鍊间负256 -->
+        <queueSize>512</queueSize>
+        <!-- 娣诲姞闄勫姞鐨刟ppender,鏈�澶氬彧鑳芥坊鍔犱竴涓� -->
+        <appender-ref ref="file_info"/>
+    </appender>
+
+    <!-- error寮傛杈撳嚭 -->
+    <appender name="async_error" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 涓嶄涪澶辨棩蹇�.榛樿鐨�,濡傛灉闃熷垪鐨�80%宸叉弧,鍒欎細涓㈠純TRACT銆丏EBUG銆両NFO绾у埆鐨勬棩蹇� -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 鏇存敼榛樿鐨勯槦鍒楃殑娣卞害,璇ュ�间細褰卞搷鎬ц兘.榛樿鍊间负256 -->
+        <queueSize>512</queueSize>
+        <!-- 娣诲姞闄勫姞鐨刟ppender,鏈�澶氬彧鑳芥坊鍔犱竴涓� -->
+        <appender-ref ref="file_error"/>
+    </appender>
+
+    <!-- 鏁村悎 skywalking 鎺у埗鍙拌緭鍑� tid -->
+<!--    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
+<!--        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
+<!--            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
+<!--                <pattern>[%tid] ${console.log.pattern}</pattern>-->
+<!--            </layout>-->
+<!--            <charset>utf-8</charset>-->
+<!--        </encoder>-->
+<!--    </appender>-->
+
+    <!-- 鏁村悎 skywalking 鎺ㄩ�侀噰闆嗘棩蹇� -->
+<!--    <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">-->
+<!--        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
+<!--            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
+<!--                <pattern>[%tid] ${console.log.pattern}</pattern>-->
+<!--            </layout>-->
+<!--            <charset>utf-8</charset>-->
+<!--        </encoder>-->
+<!--    </appender>-->
+
+    <!--绯荤粺鎿嶄綔鏃ュ織-->
+    <root level="info">
+        <appender-ref ref="console" />
+        <appender-ref ref="async_info" />
+        <appender-ref ref="async_error" />
+        <appender-ref ref="file_console" />
+<!--        <appender-ref ref="sky_log"/>-->
+    </root>
+
+</configuration>
diff --git a/eims/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java b/eims/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java
new file mode 100644
index 0000000..dba2323
--- /dev/null
+++ b/eims/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java
@@ -0,0 +1,45 @@
+package org.dromara.test;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+/**
+ * 鏂█鍗曞厓娴嬭瘯妗堜緥
+ *
+ * @author Lion Li
+ */
+@DisplayName("鏂█鍗曞厓娴嬭瘯妗堜緥")
+public class AssertUnitTest {
+
+    @DisplayName("娴嬭瘯 assertEquals 鏂规硶")
+    @Test
+    public void testAssertEquals() {
+        Assertions.assertEquals("666", new String("666"));
+        Assertions.assertNotEquals("666", new String("666"));
+    }
+
+    @DisplayName("娴嬭瘯 assertSame 鏂规硶")
+    @Test
+    public void testAssertSame() {
+        Object obj = new Object();
+        Object obj1 = obj;
+        Assertions.assertSame(obj, obj1);
+        Assertions.assertNotSame(obj, obj1);
+    }
+
+    @DisplayName("娴嬭瘯 assertTrue 鏂规硶")
+    @Test
+    public void testAssertTrue() {
+        Assertions.assertTrue(true);
+        Assertions.assertFalse(true);
+    }
+
+    @DisplayName("娴嬭瘯 assertNull 鏂规硶")
+    @Test
+    public void testAssertNull() {
+        Assertions.assertNull(null);
+        Assertions.assertNotNull(null);
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java b/eims/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java
new file mode 100644
index 0000000..5b3dfdc
--- /dev/null
+++ b/eims/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java
@@ -0,0 +1,70 @@
+package org.dromara.test;
+
+import org.dromara.common.core.config.RuoYiConfig;
+import org.junit.jupiter.api.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 鍗曞厓娴嬭瘯妗堜緥
+ *
+ * @author Lion Li
+ */
+@SpringBootTest // 姝ゆ敞瑙e彧鑳藉湪 springboot 涓诲寘涓嬩娇鐢� 闇�鍖呭惈 main 鏂规硶涓� yml 閰嶇疆鏂囦欢
+@DisplayName("鍗曞厓娴嬭瘯妗堜緥")
+public class DemoUnitTest {
+
+    @Autowired
+    private RuoYiConfig ruoYiConfig;
+
+    @DisplayName("娴嬭瘯 @SpringBootTest @Test @DisplayName 娉ㄨВ")
+    @Test
+    public void testTest() {
+        System.out.println(ruoYiConfig);
+    }
+
+    @Disabled
+    @DisplayName("娴嬭瘯 @Disabled 娉ㄨВ")
+    @Test
+    public void testDisabled() {
+        System.out.println(ruoYiConfig);
+    }
+
+    @Timeout(value = 2L, unit = TimeUnit.SECONDS)
+    @DisplayName("娴嬭瘯 @Timeout 娉ㄨВ")
+    @Test
+    public void testTimeout() throws InterruptedException {
+        Thread.sleep(3000);
+        System.out.println(ruoYiConfig);
+    }
+
+
+    @DisplayName("娴嬭瘯 @RepeatedTest 娉ㄨВ")
+    @RepeatedTest(3)
+    public void testRepeatedTest() {
+        System.out.println(666);
+    }
+
+    @BeforeAll
+    public static void testBeforeAll() {
+        System.out.println("@BeforeAll ==================");
+    }
+
+    @BeforeEach
+    public void testBeforeEach() {
+        System.out.println("@BeforeEach ==================");
+    }
+
+    @AfterEach
+    public void testAfterEach() {
+        System.out.println("@AfterEach ==================");
+    }
+
+    @AfterAll
+    public static void testAfterAll() {
+        System.out.println("@AfterAll ==================");
+    }
+
+}
diff --git a/eims/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java b/eims/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java
new file mode 100644
index 0000000..1db51df
--- /dev/null
+++ b/eims/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java
@@ -0,0 +1,72 @@
+package org.dromara.test;
+
+import org.dromara.common.core.enums.UserType;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * 甯﹀弬鏁板崟鍏冩祴璇曟渚�
+ *
+ * @author Lion Li
+ */
+@DisplayName("甯﹀弬鏁板崟鍏冩祴璇曟渚�")
+public class ParamUnitTest {
+
+    @DisplayName("娴嬭瘯 @ValueSource 娉ㄨВ")
+    @ParameterizedTest
+    @ValueSource(strings = {"t1", "t2", "t3"})
+    public void testValueSource(String str) {
+        System.out.println(str);
+    }
+
+    @DisplayName("娴嬭瘯 @NullSource 娉ㄨВ")
+    @ParameterizedTest
+    @NullSource
+    public void testNullSource(String str) {
+        System.out.println(str);
+    }
+
+    @DisplayName("娴嬭瘯 @EnumSource 娉ㄨВ")
+    @ParameterizedTest
+    @EnumSource(UserType.class)
+    public void testEnumSource(UserType type) {
+        System.out.println(type.getUserType());
+    }
+
+    @DisplayName("娴嬭瘯 @MethodSource 娉ㄨВ")
+    @ParameterizedTest
+    @MethodSource("getParam")
+    public void testMethodSource(String str) {
+        System.out.println(str);
+    }
+
+    public static Stream<String> getParam() {
+        List<String> list = new ArrayList<>();
+        list.add("t1");
+        list.add("t2");
+        list.add("t3");
+        return list.stream();
+    }
+
+    @BeforeEach
+    public void testBeforeEach() {
+        System.out.println("@BeforeEach ==================");
+    }
+
+    @AfterEach
+    public void testAfterEach() {
+        System.out.println("@AfterEach ==================");
+    }
+
+
+}
diff --git a/eims/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java b/eims/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java
new file mode 100644
index 0000000..b50afa6
--- /dev/null
+++ b/eims/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java
@@ -0,0 +1,54 @@
+package org.dromara.test;
+
+import org.junit.jupiter.api.*;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * 鏍囩鍗曞厓娴嬭瘯妗堜緥
+ *
+ * @author Lion Li
+ */
+@SpringBootTest
+@DisplayName("鏍囩鍗曞厓娴嬭瘯妗堜緥")
+public class TagUnitTest {
+
+    @Tag("dev")
+    @DisplayName("娴嬭瘯 @Tag dev")
+    @Test
+    public void testTagDev() {
+        System.out.println("dev");
+    }
+
+    @Tag("prod")
+    @DisplayName("娴嬭瘯 @Tag prod")
+    @Test
+    public void testTagProd() {
+        System.out.println("prod");
+    }
+
+    @Tag("local")
+    @DisplayName("娴嬭瘯 @Tag local")
+    @Test
+    public void testTagLocal() {
+        System.out.println("local");
+    }
+
+    @Tag("exclude")
+    @DisplayName("娴嬭瘯 @Tag exclude")
+    @Test
+    public void testTagExclude() {
+        System.out.println("exclude");
+    }
+
+    @BeforeEach
+    public void testBeforeEach() {
+        System.out.println("@BeforeEach ==================");
+    }
+
+    @AfterEach
+    public void testAfterEach() {
+        System.out.println("@AfterEach ==================");
+    }
+
+
+}
diff --git a/eims/ruoyi-common/pom.xml b/eims/ruoyi-common/pom.xml
new file mode 100644
index 0000000..2930fd0
--- /dev/null
+++ b/eims/ruoyi-common/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-vue-plus</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <modules>
+        <module>ruoyi-common-bom</module>
+        <module>ruoyi-common-social</module>
+        <module>ruoyi-common-core</module>
+        <module>ruoyi-common-doc</module>
+        <module>ruoyi-common-excel</module>
+        <module>ruoyi-common-idempotent</module>
+        <module>ruoyi-common-job</module>
+        <module>ruoyi-common-log</module>
+        <module>ruoyi-common-mail</module>
+        <module>ruoyi-common-mybatis</module>
+        <module>ruoyi-common-oss</module>
+        <module>ruoyi-common-ratelimiter</module>
+        <module>ruoyi-common-redis</module>
+        <module>ruoyi-common-satoken</module>
+        <module>ruoyi-common-security</module>
+        <module>ruoyi-common-sms</module>
+        <module>ruoyi-common-web</module>
+        <module>ruoyi-common-translation</module>
+        <module>ruoyi-common-sensitive</module>
+        <module>ruoyi-common-json</module>
+        <module>ruoyi-common-encrypt</module>
+        <module>ruoyi-common-tenant</module>
+        <module>ruoyi-common-websocket</module>
+        <module>ruoyi-common-sse</module>
+    </modules>
+
+    <artifactId>ruoyi-common</artifactId>
+    <packaging>pom</packaging>
+
+    <description>
+        common 閫氱敤妯″潡
+    </description>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-bom/pom.xml b/eims/ruoyi-common/ruoyi-common-bom/pom.xml
new file mode 100644
index 0000000..455408d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.dromara</groupId>
+    <artifactId>ruoyi-common-bom</artifactId>
+    <version>${revision}</version>
+    <packaging>pom</packaging>
+
+    <description>
+        ruoyi-common-bom common渚濊禆椤�
+    </description>
+
+    <properties>
+        <revision>5.2.2</revision>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- 鏍稿績妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-core</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鎺ュ彛妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-doc</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- excel -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-excel</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 骞傜瓑 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-idempotent</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 璋冨害妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-job</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鏃ュ織璁板綍 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-log</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 閭欢鏈嶅姟 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-mail</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鏁版嵁搴撴湇鍔� -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-mybatis</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- OSS -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-oss</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 闄愭祦 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-ratelimiter</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 缂撳瓨鏈嶅姟 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-redis</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- satoken -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-satoken</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 瀹夊叏妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-security</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鐭俊妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-sms</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-social</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- web鏈嶅姟 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-web</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 缈昏瘧妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-translation</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鑴辨晱妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-sensitive</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 搴忓垪鍖栨ā鍧� -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-json</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 鏁版嵁搴撳姞瑙e瘑妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-encrypt</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- 绉熸埛妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-tenant</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- WebSocket妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-websocket</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <!-- SSE妯″潡 -->
+            <dependency>
+                <groupId>org.dromara</groupId>
+                <artifactId>ruoyi-common-sse</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-core/pom.xml b/eims/ruoyi-common/ruoyi-common-core/pom.xml
new file mode 100644
index 0000000..ad37e90
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/pom.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-core</artifactId>
+
+    <description>
+        ruoyi-common-core 鏍稿績妯″潡
+    </description>
+
+    <dependencies>
+        <!-- Spring妗嗘灦鍩烘湰鐨勬牳蹇冨伐鍏� -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+
+        <!-- SpringWeb妯″潡 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
+        <!-- 鑷畾涔夐獙璇佹敞瑙� -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!--甯哥敤宸ュ叿绫� -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <!-- servlet鍖� -->
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-extra</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <!--  鑷姩鐢熸垚YML閰嶇疆鍏宠仈JSON鏂囦欢  -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-properties-migrator</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.github.linpeilie</groupId>
+            <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 绂荤嚎IP鍦板潃瀹氫綅搴� -->
+        <dependency>
+            <groupId>org.lionsoul</groupId>
+            <artifactId>ip2region</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java
new file mode 100644
index 0000000..d9f70e4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java
@@ -0,0 +1,17 @@
+package org.dromara.common.core.config;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ * 绋嬪簭娉ㄨВ閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@EnableAspectJAutoProxy
+@EnableAsync(proxyTargetClass = true)
+public class ApplicationConfig {
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
new file mode 100644
index 0000000..cd01e33
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
@@ -0,0 +1,52 @@
+package org.dromara.common.core.config;
+
+import cn.hutool.core.util.ArrayUtil;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+/**
+ * 寮傛閰嶇疆
+ * <p>
+ * 濡傛灉鏈娇鐢ㄨ櫄鎷熺嚎绋嬪垯鐢熸晥
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+public class AsyncConfig implements AsyncConfigurer {
+
+    /**
+     * 鑷畾涔� @Async 娉ㄨВ浣跨敤绯荤粺绾跨▼姹�
+     */
+    @Override
+    public Executor getAsyncExecutor() {
+        if(SpringUtils.isVirtual()) {
+            return new VirtualThreadTaskExecutor("async-");
+        }
+        return SpringUtils.getBean("scheduledExecutorService");
+    }
+
+    /**
+     * 寮傛鎵ц寮傚父澶勭悊
+     */
+    @Override
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+        return (throwable, method, objects) -> {
+            throwable.printStackTrace();
+            StringBuilder sb = new StringBuilder();
+            sb.append("Exception message - ").append(throwable.getMessage())
+                .append(", Method name - ").append(method.getName());
+            if (ArrayUtil.isNotEmpty(objects)) {
+                sb.append(", Parameter value - ").append(Arrays.toString(objects));
+            }
+            throw new ServiceException(sb.toString());
+        };
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java
new file mode 100644
index 0000000..cc0d2df
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java
@@ -0,0 +1,33 @@
+package org.dromara.common.core.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 璇诲彇椤圭洰鐩稿叧閰嶇疆
+ *
+ * @author Lion Li
+ */
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "ruoyi")
+public class RuoYiConfig {
+
+    /**
+     * 椤圭洰鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 鐗堟湰
+     */
+    private String version;
+
+    /**
+     * 鐗堟潈骞翠唤
+     */
+    private String copyrightYear;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..b4d4528
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java
@@ -0,0 +1,78 @@
+package org.dromara.common.core.config;
+
+import jakarta.annotation.PreDestroy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.dromara.common.core.config.properties.ThreadPoolProperties;
+import org.dromara.common.core.utils.Threads;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 绾跨▼姹犻厤缃�
+ *
+ * @author Lion Li
+ **/
+@Slf4j
+@AutoConfiguration
+@EnableConfigurationProperties(ThreadPoolProperties.class)
+public class ThreadPoolConfig {
+
+    /**
+     * 鏍稿績绾跨▼鏁� = cpu 鏍稿績鏁� + 1
+     */
+    private final int core = Runtime.getRuntime().availableProcessors() + 1;
+
+    private ScheduledExecutorService scheduledExecutorService;
+
+    @Bean(name = "threadPoolTaskExecutor")
+    @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
+    public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(core);
+        executor.setMaxPoolSize(core * 2);
+        executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
+        executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        return executor;
+    }
+
+    /**
+     * 鎵ц鍛ㄦ湡鎬ф垨瀹氭椂浠诲姟
+     */
+    @Bean(name = "scheduledExecutorService")
+    protected ScheduledExecutorService scheduledExecutorService() {
+        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core,
+            new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
+            new ThreadPoolExecutor.CallerRunsPolicy()) {
+            @Override
+            protected void afterExecute(Runnable r, Throwable t) {
+                super.afterExecute(r, t);
+                Threads.printException(r, t);
+            }
+        };
+        this.scheduledExecutorService = scheduledThreadPoolExecutor;
+        return scheduledThreadPoolExecutor;
+    }
+
+    /**
+     * 閿�姣佷簨浠�
+     */
+    @PreDestroy
+    public void destroy() {
+        try {
+            log.info("====鍏抽棴鍚庡彴浠诲姟浠诲姟绾跨▼姹�====");
+            Threads.shutdownAndAwaitTermination(scheduledExecutorService);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
new file mode 100644
index 0000000..45c5bd1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
@@ -0,0 +1,40 @@
+package org.dromara.common.core.config;
+
+import jakarta.validation.Validator;
+import org.hibernate.validator.HibernateValidator;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+import java.util.Properties;
+
+/**
+ * 鏍¢獙妗嗘灦閰嶇疆绫�
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+public class ValidatorConfig {
+
+    /**
+     * 閰嶇疆鏍¢獙妗嗘灦 蹇�熻繑鍥炴ā寮�
+     */
+    @Bean
+    public Validator validator(MessageSource messageSource) {
+        try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
+            // 鍥介檯鍖�
+            factoryBean.setValidationMessageSource(messageSource);
+            // 璁剧疆浣跨敤 HibernateValidator 鏍¢獙鍣�
+            factoryBean.setProviderClass(HibernateValidator.class);
+            Properties properties = new Properties();
+            // 璁剧疆 蹇�熷紓甯歌繑鍥�
+            properties.setProperty("hibernate.validator.fail_fast", "true");
+            factoryBean.setValidationProperties(properties);
+            // 鍔犺浇閰嶇疆
+            factoryBean.afterPropertiesSet();
+            return factoryBean.getValidator();
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java
new file mode 100644
index 0000000..820564f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 绾跨▼姹� 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "thread-pool")
+public class ThreadPoolProperties {
+
+    /**
+     * 鏄惁寮�鍚嚎绋嬫睜
+     */
+    private boolean enabled;
+
+    /**
+     * 闃熷垪鏈�澶ч暱搴�
+     */
+    private int queueCapacity;
+
+    /**
+     * 绾跨▼姹犵淮鎶ょ嚎绋嬫墍鍏佽鐨勭┖闂叉椂闂�
+     */
+    private int keepAliveSeconds;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
new file mode 100644
index 0000000..ceb8370
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 缂撳瓨鐨刱ey 甯搁噺
+ *
+ * @author Lion Li
+ */
+public interface CacheConstants {
+
+    /**
+     * 鍦ㄧ嚎鐢ㄦ埛 redis key
+     */
+    String ONLINE_TOKEN_KEY = "online_tokens:";
+
+    /**
+     * 鍙傛暟绠$悊 cache key
+     */
+    String SYS_CONFIG_KEY = "sys_config:";
+
+    /**
+     * 瀛楀吀绠$悊 cache key
+     */
+    String SYS_DICT_KEY = "sys_dict:";
+
+    /**
+     * 鐧诲綍璐︽埛瀵嗙爜閿欒娆℃暟 redis key
+     */
+    String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
new file mode 100644
index 0000000..28ba177
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java
@@ -0,0 +1,73 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 缂撳瓨缁勫悕绉板父閲�
+ * <p>
+ * key 鏍煎紡涓� cacheNames#ttl#maxIdleTime#maxSize
+ * <p>
+ * ttl 杩囨湡鏃堕棿 濡傛灉璁剧疆涓�0鍒欎笉杩囨湡 榛樿涓�0
+ * maxIdleTime 鏈�澶х┖闂叉椂闂� 鏍规嵁LRU绠楁硶娓呯悊绌洪棽鏁版嵁 濡傛灉璁剧疆涓�0鍒欎笉妫�娴� 榛樿涓�0
+ * maxSize 缁勬渶澶ч暱搴� 鏍规嵁LRU绠楁硶娓呯悊婧㈠嚭鏁版嵁 濡傛灉璁剧疆涓�0鍒欐棤闄愰暱 榛樿涓�0
+ * <p>
+ * 渚嬪瓙: test#60s銆乼est#0#60s銆乼est#0#1m#1000銆乼est#1h#0#500
+ *
+ * @author Lion Li
+ */
+public interface CacheNames {
+
+    /**
+     * 婕旂ず妗堜緥
+     */
+    String DEMO_CACHE = "demo:cache#60s#10m#20";
+
+    /**
+     * 绯荤粺閰嶇疆
+     */
+    String SYS_CONFIG = "sys_config";
+
+    /**
+     * 鏁版嵁瀛楀吀
+     */
+    String SYS_DICT = "sys_dict";
+
+    /**
+     * 绉熸埛
+     */
+    String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d";
+
+    /**
+     * 鐢ㄦ埛璐︽埛
+     */
+    String SYS_USER_NAME = "sys_user_name#30d";
+
+    /**
+     * 鐢ㄦ埛鍚嶇О
+     */
+    String SYS_NICKNAME = "sys_nickname#30d";
+
+    /**
+     * 閮ㄩ棬
+     */
+    String SYS_DEPT = "sys_dept#30d";
+
+    /**
+     * OSS鍐呭
+     */
+    String SYS_OSS = "sys_oss#30d";
+
+    /**
+     * OSS閰嶇疆
+     */
+    String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
+
+    /**
+     * 鍦ㄧ嚎鐢ㄦ埛
+     */
+    String ONLINE_TOKEN = "online_tokens";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
new file mode 100644
index 0000000..cdbda89
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java
@@ -0,0 +1,81 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 閫氱敤甯搁噺淇℃伅
+ *
+ * @author ruoyi
+ */
+public interface Constants {
+
+    /**
+     * UTF-8 瀛楃闆�
+     */
+    String UTF8 = "UTF-8";
+
+    /**
+     * GBK 瀛楃闆�
+     */
+    String GBK = "GBK";
+
+    /**
+     * www涓诲煙
+     */
+    String WWW = "www.";
+
+    /**
+     * http璇锋眰
+     */
+    String HTTP = "http://";
+
+    /**
+     * https璇锋眰
+     */
+    String HTTPS = "https://";
+
+    /**
+     * 閫氱敤鎴愬姛鏍囪瘑
+     */
+    String SUCCESS = "0";
+
+    /**
+     * 閫氱敤澶辫触鏍囪瘑
+     */
+    String FAIL = "1";
+
+    /**
+     * 鐧诲綍鎴愬姛
+     */
+    String LOGIN_SUCCESS = "Success";
+
+    /**
+     * 娉ㄩ攢
+     */
+    String LOGOUT = "Logout";
+
+    /**
+     * 娉ㄥ唽
+     */
+    String REGISTER = "Register";
+
+    /**
+     * 鐧诲綍澶辫触
+     */
+    String LOGIN_FAIL = "Error";
+
+    /**
+     * 楠岃瘉鐮佹湁鏁堟湡锛堝垎閽燂級
+     */
+    Integer CAPTCHA_EXPIRATION = 2;
+
+    /**
+     * 浠ょ墝
+     */
+    String TOKEN = "token";
+
+    /**
+     * 椤剁骇閮ㄩ棬id
+     */
+    Long TOP_PARENT_ID = 0L;
+
+}
+
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
new file mode 100644
index 0000000..5352b11
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
@@ -0,0 +1,34 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 鍏ㄥ眬鐨刱ey甯搁噺 (涓氬姟鏃犲叧鐨刱ey)
+ *
+ * @author Lion Li
+ */
+public interface GlobalConstants {
+
+    /**
+     * 鍏ㄥ眬 redis key (涓氬姟鏃犲叧鐨刱ey)
+     */
+    String GLOBAL_REDIS_KEY = "global:";
+
+    /**
+     * 楠岃瘉鐮� redis key
+     */
+    String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
+
+    /**
+     * 闃查噸鎻愪氦 redis key
+     */
+    String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:";
+
+    /**
+     * 闄愭祦 redis key
+     */
+    String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
+
+    /**
+     * 涓夋柟璁よ瘉 redis key
+     */
+    String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java
new file mode 100644
index 0000000..85566e8
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java
@@ -0,0 +1,93 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 杩斿洖鐘舵�佺爜
+ *
+ * @author Lion Li
+ */
+public interface HttpStatus {
+    /**
+     * 鎿嶄綔鎴愬姛
+     */
+    int SUCCESS = 200;
+
+    /**
+     * 瀵硅薄鍒涘缓鎴愬姛
+     */
+    int CREATED = 201;
+
+    /**
+     * 璇锋眰宸茬粡琚帴鍙�
+     */
+    int ACCEPTED = 202;
+
+    /**
+     * 鎿嶄綔宸茬粡鎵ц鎴愬姛锛屼絾鏄病鏈夎繑鍥炴暟鎹�
+     */
+    int NO_CONTENT = 204;
+
+    /**
+     * 璧勬簮宸茶绉婚櫎
+     */
+    int MOVED_PERM = 301;
+
+    /**
+     * 閲嶅畾鍚�
+     */
+    int SEE_OTHER = 303;
+
+    /**
+     * 璧勬簮娌℃湁琚慨鏀�
+     */
+    int NOT_MODIFIED = 304;
+
+    /**
+     * 鍙傛暟鍒楄〃閿欒锛堢己灏戯紝鏍煎紡涓嶅尮閰嶏級
+     */
+    int BAD_REQUEST = 400;
+
+    /**
+     * 鏈巿鏉�
+     */
+    int UNAUTHORIZED = 401;
+
+    /**
+     * 璁块棶鍙楅檺锛屾巿鏉冭繃鏈�
+     */
+    int FORBIDDEN = 403;
+
+    /**
+     * 璧勬簮锛屾湇鍔℃湭鎵惧埌
+     */
+    int NOT_FOUND = 404;
+
+    /**
+     * 涓嶅厑璁哥殑http鏂规硶
+     */
+    int BAD_METHOD = 405;
+
+    /**
+     * 璧勬簮鍐茬獊锛屾垨鑰呰祫婧愯閿�
+     */
+    int CONFLICT = 409;
+
+    /**
+     * 涓嶆敮鎸佺殑鏁版嵁锛屽獟浣撶被鍨�
+     */
+    int UNSUPPORTED_TYPE = 415;
+
+    /**
+     * 绯荤粺鍐呴儴閿欒
+     */
+    int ERROR = 500;
+
+    /**
+     * 鎺ュ彛鏈疄鐜�
+     */
+    int NOT_IMPLEMENTED = 501;
+
+    /**
+     * 绯荤粺璀﹀憡娑堟伅
+     */
+    int WARN = 601;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java
new file mode 100644
index 0000000..77eed8c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java
@@ -0,0 +1,54 @@
+package org.dromara.common.core.constant;
+
+import cn.hutool.core.lang.RegexPool;
+
+/**
+ * 甯哥敤姝e垯琛ㄨ揪寮忓瓧绗︿覆
+ * <p>
+ * 甯哥敤姝e垯琛ㄨ揪寮忛泦鍚堬紝鏇村姝e垯瑙�: https://any86.github.io/any-rule/
+ *
+ * @author Feng
+ */
+public interface RegexConstants extends RegexPool {
+
+    /**
+     * 瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�
+     */
+    String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$";
+
+    /**
+     * 鏉冮檺鏍囪瘑蹇呴』绗﹀悎 tool:build:list 鏍煎紡锛屾垨鑰呯┖瀛楃涓�
+     */
+    String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$";
+
+    /**
+     * 韬唤璇佸彿鐮侊紙鍚�6浣嶏級
+     */
+    String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
+
+    /**
+     * QQ鍙风爜
+     */
+    String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$";
+
+    /**
+     * 閭斂缂栫爜
+     */
+    String POSTAL_CODE = "^[1-9]\\d{5}$";
+
+    /**
+     * 娉ㄥ唽璐﹀彿
+     */
+    String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$";
+
+    /**
+     * 瀵嗙爜锛氬寘鍚嚦灏�8涓瓧绗︼紝鍖呮嫭澶у啓瀛楁瘝銆佸皬鍐欏瓧姣嶃�佹暟瀛楀拰鐗规畩瀛楃
+     */
+    String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$";
+
+    /**
+     * 閫氱敤鐘舵�侊紙0琛ㄧず姝e父锛�1琛ㄧず鍋滅敤锛�
+     */
+    String STATUS = "^[01]$";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java
new file mode 100644
index 0000000..86b63c9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java
@@ -0,0 +1,45 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 绉熸埛甯搁噺淇℃伅
+ *
+ * @author Lion Li
+ */
+public interface TenantConstants {
+
+    /**
+     * 绉熸埛姝e父鐘舵��
+     */
+    String NORMAL = "0";
+
+    /**
+     * 绉熸埛灏佺鐘舵��
+     */
+    String DISABLE = "1";
+
+    /**
+     * 瓒呯骇绠$悊鍛業D
+     */
+    Long SUPER_ADMIN_ID = 1L;
+
+    /**
+     * 瓒呯骇绠$悊鍛樿鑹� roleKey
+     */
+    String SUPER_ADMIN_ROLE_KEY = "superadmin";
+
+    /**
+     * 绉熸埛绠$悊鍛樿鑹� roleKey
+     */
+    String TENANT_ADMIN_ROLE_KEY = "admin";
+
+    /**
+     * 绉熸埛绠$悊鍛樿鑹插悕绉�
+     */
+    String TENANT_ADMIN_ROLE_NAME = "绠$悊鍛�";
+
+    /**
+     * 榛樿绉熸埛ID
+     */
+    String DEFAULT_TENANT_ID = "000000";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
new file mode 100644
index 0000000..76f6dd4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
@@ -0,0 +1,152 @@
+package org.dromara.common.core.constant;
+
+/**
+ * 鐢ㄦ埛甯搁噺淇℃伅
+ *
+ * @author ruoyi
+ */
+public interface UserConstants {
+
+    /**
+     * 骞冲彴鍐呯郴缁熺敤鎴风殑鍞竴鏍囧織
+     */
+    String SYS_USER = "SYS_USER";
+
+    /**
+     * 姝e父鐘舵��
+     */
+    String NORMAL = "0";
+
+    /**
+     * 寮傚父鐘舵��
+     */
+    String EXCEPTION = "1";
+
+    /**
+     * 鐢ㄦ埛姝e父鐘舵��
+     */
+    String USER_NORMAL = "0";
+
+    /**
+     * 鐢ㄦ埛灏佺鐘舵��
+     */
+    String USER_DISABLE = "1";
+
+    /**
+     * 瑙掕壊姝e父鐘舵��
+     */
+    String ROLE_NORMAL = "0";
+
+    /**
+     * 瑙掕壊灏佺鐘舵��
+     */
+    String ROLE_DISABLE = "1";
+
+    /**
+     * 閮ㄩ棬姝e父鐘舵��
+     */
+    String DEPT_NORMAL = "0";
+
+    /**
+     * 閮ㄩ棬鍋滅敤鐘舵��
+     */
+    String DEPT_DISABLE = "1";
+
+    /**
+     * 宀椾綅姝e父鐘舵��
+     */
+    String POST_NORMAL = "0";
+
+    /**
+     * 宀椾綅鍋滅敤鐘舵��
+     */
+    String POST_DISABLE = "1";
+
+    /**
+     * 瀛楀吀姝e父鐘舵��
+     */
+    String DICT_NORMAL = "0";
+
+    /**
+     * 閫氱敤瀛樺湪鏍囧織
+     */
+    String DEL_FLAG_NORMAL = "0";
+
+    /**
+     * 閫氱敤鍒犻櫎鏍囧織
+     */
+    String DEL_FLAG_REMOVED  = "2";
+
+    /**
+     * 鏄惁涓虹郴缁熼粯璁わ紙鏄級
+     */
+    String YES = "Y";
+
+    /**
+     * 鏄惁鑿滃崟澶栭摼锛堟槸锛�
+     */
+    String YES_FRAME = "0";
+
+    /**
+     * 鏄惁鑿滃崟澶栭摼锛堝惁锛�
+     */
+    String NO_FRAME = "1";
+
+    /**
+     * 鑿滃崟姝e父鐘舵��
+     */
+    String MENU_NORMAL = "0";
+
+    /**
+     * 鑿滃崟鍋滅敤鐘舵��
+     */
+    String MENU_DISABLE = "1";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堢洰褰曪級
+     */
+    String TYPE_DIR = "M";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堣彍鍗曪級
+     */
+    String TYPE_MENU = "C";
+
+    /**
+     * 鑿滃崟绫诲瀷锛堟寜閽級
+     */
+    String TYPE_BUTTON = "F";
+
+    /**
+     * Layout缁勪欢鏍囪瘑
+     */
+    String LAYOUT = "Layout";
+
+    /**
+     * ParentView缁勪欢鏍囪瘑
+     */
+    String PARENT_VIEW = "ParentView";
+
+    /**
+     * InnerLink缁勪欢鏍囪瘑
+     */
+    String INNER_LINK = "InnerLink";
+
+    /**
+     * 鐢ㄦ埛鍚嶉暱搴﹂檺鍒�
+     */
+    int USERNAME_MIN_LENGTH = 2;
+    int USERNAME_MAX_LENGTH = 20;
+
+    /**
+     * 瀵嗙爜闀垮害闄愬埗
+     */
+    int PASSWORD_MIN_LENGTH = 5;
+    int PASSWORD_MAX_LENGTH = 20;
+
+    /**
+     * 瓒呯骇绠$悊鍛業D
+     */
+    Long SUPER_ADMIN_ID = 1L;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java
new file mode 100644
index 0000000..be85805
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java
@@ -0,0 +1,110 @@
+package org.dromara.common.core.domain;
+
+import org.dromara.common.core.constant.HttpStatus;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鍝嶅簲淇℃伅涓讳綋
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+public class R<T> implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎴愬姛
+     */
+    public static final int SUCCESS = 200;
+
+    /**
+     * 澶辫触
+     */
+    public static final int FAIL = 500;
+
+    private int code;
+
+    private String msg;
+
+    private T data;
+
+    public static <T> R<T> ok() {
+        return restResult(null, SUCCESS, "鎿嶄綔鎴愬姛");
+    }
+
+    public static <T> R<T> ok(T data) {
+        return restResult(data, SUCCESS, "鎿嶄綔鎴愬姛");
+    }
+
+    public static <T> R<T> ok(String msg) {
+        return restResult(null, SUCCESS, msg);
+    }
+
+    public static <T> R<T> ok(String msg, T data) {
+        return restResult(data, SUCCESS, msg);
+    }
+
+    public static <T> R<T> fail() {
+        return restResult(null, FAIL, "鎿嶄綔澶辫触");
+    }
+
+    public static <T> R<T> fail(String msg) {
+        return restResult(null, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(T data) {
+        return restResult(data, FAIL, "鎿嶄綔澶辫触");
+    }
+
+    public static <T> R<T> fail(String msg, T data) {
+        return restResult(data, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(int code, String msg) {
+        return restResult(null, code, msg);
+    }
+
+    /**
+     * 杩斿洖璀﹀憡娑堟伅
+     *
+     * @param msg 杩斿洖鍐呭
+     * @return 璀﹀憡娑堟伅
+     */
+    public static <T> R<T> warn(String msg) {
+        return restResult(null, HttpStatus.WARN, msg);
+    }
+
+    /**
+     * 杩斿洖璀﹀憡娑堟伅
+     *
+     * @param msg 杩斿洖鍐呭
+     * @param data 鏁版嵁瀵硅薄
+     * @return 璀﹀憡娑堟伅
+     */
+    public static <T> R<T> warn(String msg, T data) {
+        return restResult(data, HttpStatus.WARN, msg);
+    }
+
+    private static <T> R<T> restResult(T data, int code, String msg) {
+        R<T> r = new R<>();
+        r.setCode(code);
+        r.setData(data);
+        r.setMsg(msg);
+        return r;
+    }
+
+    public static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getCode();
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java
new file mode 100644
index 0000000..463821c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java
@@ -0,0 +1,46 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * OSS瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+public class OssDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瀵硅薄瀛樺偍涓婚敭
+     */
+    private Long ossId;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String fileName;
+
+    /**
+     * 鍘熷悕
+     */
+    private String originalName;
+
+    /**
+     * 鏂囦欢鍚庣紑鍚�
+     */
+    private String fileSuffix;
+
+    /**
+     * URL鍦板潃
+     */
+    private String url;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java
new file mode 100644
index 0000000..aea8e7a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java
@@ -0,0 +1,42 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 瑙掕壊
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+public class RoleDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瑙掕壊ID
+     */
+    private Long roleId;
+
+    /**
+     * 瑙掕壊鍚嶇О
+     */
+    private String roleName;
+
+    /**
+     * 瑙掕壊鏉冮檺
+     */
+    private String roleKey;
+
+    /**
+     * 鏁版嵁鑼冨洿锛�1锛氭墍鏈夋暟鎹潈闄愶紱2锛氳嚜瀹氫箟鏁版嵁鏉冮檺锛�3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺锛�4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶紱5锛氫粎鏈汉鏁版嵁鏉冮檺锛�
+     */
+    private String dataScope;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java
new file mode 100644
index 0000000..cb5def9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java
@@ -0,0 +1,73 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 鐢ㄦ埛
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@NoArgsConstructor
+public class UserDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+     */
+    private String userType;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+     */
+    private String sex;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java
new file mode 100644
index 0000000..43d8c3c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java
@@ -0,0 +1,72 @@
+package org.dromara.common.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 褰撳墠鍦ㄧ嚎浼氳瘽
+ *
+ * @author ruoyi
+ */
+
+@Data
+@NoArgsConstructor
+public class UserOnlineDTO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浼氳瘽缂栧彿
+     */
+    private String tokenId;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 鐢ㄦ埛鍚嶇О
+     */
+    private String userName;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦板潃
+     */
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String os;
+
+    /**
+     * 鐧诲綍鏃堕棿
+     */
+    private Long loginTime;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
new file mode 100644
index 0000000..61c7efc
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java
@@ -0,0 +1,41 @@
+package org.dromara.common.core.domain.event;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鎬讳綋娴佺▼鐩戝惉
+ *
+ * @author may
+ */
+
+@Data
+public class ProcessEvent implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹氫箟key
+     */
+    private String key;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessKey;
+
+    /**
+     * 鐘舵��
+     */
+    private String status;
+
+    /**
+     * 褰撲负true鏃朵负鐢宠浜鸿妭鐐瑰姙鐞�
+     */
+    private boolean submit;
+
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
new file mode 100644
index 0000000..019ca82
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java
@@ -0,0 +1,40 @@
+package org.dromara.common.core.domain.event;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 娴佺▼鍔炵悊鐩戝惉
+ *
+ * @author may
+ */
+
+@Data
+public class ProcessTaskEvent implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹氫箟key
+     */
+    private String key;
+
+    /**
+     * 瀹℃壒鑺傜偣key
+     */
+    private String taskDefinitionKey;
+
+    /**
+     * 浠诲姟id
+     */
+    private String taskId;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessKey;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java
new file mode 100644
index 0000000..ffde8c6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java
@@ -0,0 +1,31 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 閭欢鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class EmailLoginBody extends LoginBody {
+
+    /**
+     * 閭
+     */
+    @NotBlank(message = "{user.email.not.blank}")
+    @Email(message = "{user.email.not.valid}")
+    private String email;
+
+    /**
+     * 閭code
+     */
+    @NotBlank(message = "{email.code.not.blank}")
+    private String emailCode;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java
new file mode 100644
index 0000000..63bee0d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java
@@ -0,0 +1,48 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class LoginBody implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瀹㈡埛绔痠d
+     */
+    @NotBlank(message = "{auth.clientid.not.blank}")
+    private String clientId;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    @NotBlank(message = "{auth.grant.type.not.blank}")
+    private String grantType;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 楠岃瘉鐮�
+     */
+    private String code;
+
+    /**
+     * 鍞竴鏍囪瘑
+     */
+    private String uuid;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
new file mode 100644
index 0000000..c723e76
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
@@ -0,0 +1,142 @@
+package org.dromara.common.core.domain.model;
+
+import org.dromara.common.core.domain.dto.RoleDTO;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 鐧诲綍鐢ㄦ埛韬唤鏉冮檺
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+public class LoginUser implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 閮ㄩ棬绫诲埆缂栫爜
+     */
+    private String deptCategory;
+
+    /**
+     * 閮ㄩ棬鍚�
+     */
+    private String deptName;
+
+    /**
+     * 鐢ㄦ埛鍞竴鏍囪瘑
+     */
+    private String token;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷
+     */
+    private String userType;
+
+    /**
+     * 鐧诲綍鏃堕棿
+     */
+    private Long loginTime;
+
+    /**
+     * 杩囨湡鏃堕棿
+     */
+    private Long expireTime;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦扮偣
+     */
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String os;
+
+    /**
+     * 鑿滃崟鏉冮檺
+     */
+    private Set<String> menuPermission;
+
+    /**
+     * 瑙掕壊鏉冮檺
+     */
+    private Set<String> rolePermission;
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    private String username;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    private String nickname;
+
+    /**
+     * 瑙掕壊瀵硅薄
+     */
+    private List<RoleDTO> roles;
+
+    /**
+     * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
+     */
+    private Long roleId;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * 鑾峰彇鐧诲綍id
+     */
+    public String getLoginId() {
+        if (userType == null) {
+            throw new IllegalArgumentException("鐢ㄦ埛绫诲瀷涓嶈兘涓虹┖");
+        }
+        if (userId == null) {
+            throw new IllegalArgumentException("鐢ㄦ埛ID涓嶈兘涓虹┖");
+        }
+        return userType + ":" + userId;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
new file mode 100644
index 0000000..22de8f2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java
@@ -0,0 +1,33 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.hibernate.validator.constraints.Length;
+
+import static org.dromara.common.core.constant.UserConstants.*;
+
+/**
+ * 瀵嗙爜鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class PasswordLoginBody extends LoginBody {
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    @NotBlank(message = "{user.username.not.blank}")
+    @Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+    private String username;
+
+    /**
+     * 鐢ㄦ埛瀵嗙爜
+     */
+    @NotBlank(message = "{user.password.not.blank}")
+    @Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+    private String password;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
new file mode 100644
index 0000000..440422b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java
@@ -0,0 +1,35 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.hibernate.validator.constraints.Length;
+
+import static org.dromara.common.core.constant.UserConstants.*;
+
+/**
+ * 鐢ㄦ埛娉ㄥ唽瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class RegisterBody extends LoginBody {
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    @NotBlank(message = "{user.username.not.blank}")
+    @Length(min = USERNAME_MIN_LENGTH, max = USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+    private String username;
+
+    /**
+     * 鐢ㄦ埛瀵嗙爜
+     */
+    @NotBlank(message = "{user.password.not.blank}")
+    @Length(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+    private String password;
+
+    private String userType;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java
new file mode 100644
index 0000000..a878348
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java
@@ -0,0 +1,29 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鐭俊鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SmsLoginBody extends LoginBody {
+
+    /**
+     * 鎵嬫満鍙�
+     */
+    @NotBlank(message = "{user.phonenumber.not.blank}")
+    private String phonenumber;
+
+    /**
+     * 鐭俊code
+     */
+    @NotBlank(message = "{sms.code.not.blank}")
+    private String smsCode;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java
new file mode 100644
index 0000000..0d1b121
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java
@@ -0,0 +1,35 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 涓夋柟鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class SocialLoginBody extends LoginBody {
+
+    /**
+     * 绗笁鏂圭櫥褰曞钩鍙�
+     */
+    @NotBlank(message = "{social.source.not.blank}")
+    private String source;
+
+    /**
+     * 绗笁鏂圭櫥褰昪ode
+     */
+    @NotBlank(message = "{social.code.not.blank}")
+    private String socialCode;
+
+    /**
+     * 绗笁鏂圭櫥褰晄ocialState
+     */
+    @NotBlank(message = "{social.state.not.blank}")
+    private String socialState;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java
new file mode 100644
index 0000000..518fe2e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java
@@ -0,0 +1,28 @@
+package org.dromara.common.core.domain.model;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 涓夋柟鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class XcxLoginBody extends LoginBody {
+
+    /**
+     * 灏忕▼搴廼d(澶氫釜灏忕▼搴忔椂浣跨敤)
+     */
+    private String appid;
+
+    /**
+     * 灏忕▼搴廲ode
+     */
+    @NotBlank(message = "{xcx.code.not.blank}")
+    private String xcxCode;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java
new file mode 100644
index 0000000..e5f3d6c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java
@@ -0,0 +1,27 @@
+package org.dromara.common.core.domain.model;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+
+/**
+ * 灏忕▼搴忕櫥褰曠敤鎴疯韩浠芥潈闄�
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+public class XcxLoginUser extends LoginUser {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * openid
+     */
+    private String openid;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
new file mode 100644
index 0000000..0af943a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java
@@ -0,0 +1,152 @@
+package org.dromara.common.core.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 涓氬姟鐘舵�佹灇涓�
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum BusinessStatusEnum {
+    /**
+     * 宸叉挙閿�
+     */
+    CANCEL("cancel", "宸叉挙閿�"),
+    /**
+     * 鑽夌
+     */
+    DRAFT("draft", "鑽夌"),
+    /**
+     * 寰呭鏍�
+     */
+    WAITING("waiting", "寰呭鏍�"),
+    /**
+     * 宸插畬鎴�
+     */
+    FINISH("finish", "宸插畬鎴�"),
+    /**
+     * 宸蹭綔搴�
+     */
+    INVALID("invalid", "宸蹭綔搴�"),
+    /**
+     * 宸查��鍥�
+     */
+    BACK("back", "宸查��鍥�"),
+    /**
+     * 宸茬粓姝�
+     */
+    TERMINATION("termination", "宸茬粓姝�");
+
+    /**
+     * 鐘舵��
+     */
+    private final String status;
+
+    /**
+     * 鎻忚堪
+     */
+    private final String desc;
+
+    /**
+     * 鑾峰彇涓氬姟鐘舵��
+     *
+     * @param status 鐘舵��
+     */
+    public static String findByStatus(String status) {
+        if (StringUtils.isBlank(status)) {
+            return StrUtil.EMPTY;
+        }
+        return Arrays.stream(BusinessStatusEnum.values())
+            .filter(statusEnum -> statusEnum.getStatus().equals(status))
+            .findFirst()
+            .map(BusinessStatusEnum::getDesc)
+            .orElse(StrUtil.EMPTY);
+    }
+
+    /**
+     * 鍚姩娴佺▼鏍¢獙
+     *
+     * @param status 鐘舵��
+     */
+    public static void checkStartStatus(String status) {
+        if (WAITING.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡鎻愪氦杩囩敵璇�,姝e湪瀹℃壒涓紒");
+        } else if (FINISH.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡瀹屾垚鐢宠锛�");
+        } else if (INVALID.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡浣滃簾锛�");
+        } else if (TERMINATION.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡缁堟锛�");
+        } else if (StringUtils.isBlank(status)) {
+            throw new ServiceException("娴佺▼鐘舵�佷负绌猴紒");
+        }
+    }
+
+    /**
+     * 鎾ら攢娴佺▼鏍¢獙
+     *
+     * @param status 鐘舵��
+     */
+    public static void checkCancelStatus(String status) {
+        if (CANCEL.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡鎾ら攢锛�");
+        } else if (FINISH.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡瀹屾垚鐢宠锛�");
+        } else if (INVALID.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡浣滃簾锛�");
+        } else if (TERMINATION.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡缁堟锛�");
+        } else if (BACK.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡閫�鍥烇紒");
+        } else if (StringUtils.isBlank(status)) {
+            throw new ServiceException("娴佺▼鐘舵�佷负绌猴紒");
+        }
+    }
+
+    /**
+     * 椹冲洖娴佺▼鏍¢獙
+     *
+     * @param status 鐘舵��
+     */
+    public static void checkBackStatus(String status) {
+        if (BACK.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡閫�鍥烇紒");
+        } else if (FINISH.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡瀹屾垚鐢宠锛�");
+        } else if (INVALID.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡浣滃簾锛�");
+        } else if (TERMINATION.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡缁堟锛�");
+        } else if (CANCEL.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡鎾ら攢锛�");
+        } else if (StringUtils.isBlank(status)) {
+            throw new ServiceException("娴佺▼鐘舵�佷负绌猴紒");
+        }
+    }
+
+    /**
+     * 浣滃簾,缁堟娴佺▼鏍¢獙
+     *
+     * @param status 鐘舵��
+     */
+    public static void checkInvalidStatus(String status) {
+        if (FINISH.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡瀹屾垚鐢宠锛�");
+        } else if (INVALID.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡浣滃簾锛�");
+        } else if (TERMINATION.getStatus().equals(status)) {
+            throw new ServiceException("璇ュ崟鎹凡缁堟锛�");
+        } else if (StringUtils.isBlank(status)) {
+            throw new ServiceException("娴佺▼鐘舵�佷负绌猴紒");
+        }
+    }
+}
+
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java
new file mode 100644
index 0000000..dbadfc2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java
@@ -0,0 +1,37 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 璁惧绫诲瀷
+ * 閽堝涓�濂� 鐢ㄦ埛浣撶郴
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum DeviceType {
+
+    /**
+     * pc绔�
+     */
+    PC("pc"),
+
+    /**
+     * app绔�
+     */
+    APP("app"),
+
+    /**
+     * 灏忕▼搴忕
+     */
+    XCX("xcx"),
+
+    /**
+     * social绗笁鏂圭
+     */
+    SOCIAL("social");
+
+    private final String device;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java
new file mode 100644
index 0000000..f9cac66
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java
@@ -0,0 +1,44 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 鐧诲綍绫诲瀷
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum LoginType {
+
+    /**
+     * 瀵嗙爜鐧诲綍
+     */
+    PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
+
+    /**
+     * 鐭俊鐧诲綍
+     */
+    SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
+
+    /**
+     * 閭鐧诲綍
+     */
+    EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
+
+    /**
+     * 灏忕▼搴忕櫥褰�
+     */
+    XCX("", "");
+
+    /**
+     * 鐧诲綍閲嶈瘯瓒呭嚭闄愬埗鎻愮ず
+     */
+    final String retryLimitExceed;
+
+    /**
+     * 鐧诲綍閲嶈瘯闄愬埗璁℃暟鎻愮ず
+     */
+    final String retryLimitCount;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java
new file mode 100644
index 0000000..400a399
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/TenantStatus.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 鐢ㄦ埛鐘舵��
+ *
+ * @author LionLi
+ */
+@Getter
+@AllArgsConstructor
+public enum TenantStatus {
+    /**
+     * 姝e父
+     */
+    OK("0", "姝e父"),
+    /**
+     * 鍋滅敤
+     */
+    DISABLE("1", "鍋滅敤"),
+    /**
+     * 鍒犻櫎
+     */
+    DELETED("2", "鍒犻櫎");
+
+    private final String code;
+    private final String info;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java
new file mode 100644
index 0000000..be7e44d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 鐢ㄦ埛鐘舵��
+ *
+ * @author ruoyi
+ */
+@Getter
+@AllArgsConstructor
+public enum UserStatus {
+    /**
+     * 姝e父
+     */
+    OK("0", "姝e父"),
+    /**
+     * 鍋滅敤
+     */
+    DISABLE("1", "鍋滅敤"),
+    /**
+     * 鍒犻櫎
+     */
+    DELETED("2", "鍒犻櫎");
+
+    private final String code;
+    private final String info;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java
new file mode 100644
index 0000000..69e4753
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java
@@ -0,0 +1,37 @@
+package org.dromara.common.core.enums;
+
+import org.dromara.common.core.utils.StringUtils;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 璁惧绫诲瀷
+ * 閽堝澶氬 鐢ㄦ埛浣撶郴
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum UserType {
+
+    /**
+     * pc绔�
+     */
+    SYS_USER("sys_user"),
+
+    /**
+     * app绔�
+     */
+    APP_USER("app_user");
+
+    private final String userType;
+
+    public static UserType getUserType(String str) {
+        for (UserType value : values()) {
+            if (StringUtils.contains(str, value.getUserType())) {
+                return value;
+            }
+        }
+        throw new RuntimeException("'UserType' not found By " + str);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
new file mode 100644
index 0000000..e9dc6ec
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
@@ -0,0 +1,59 @@
+package org.dromara.common.core.exception;
+
+import lombok.*;
+
+import java.io.Serial;
+
+/**
+ * 涓氬姟寮傚父
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public final class ServiceException extends RuntimeException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閿欒鐮�
+     */
+    private Integer code;
+
+    /**
+     * 閿欒鎻愮ず
+     */
+    private String message;
+
+    /**
+     * 閿欒鏄庣粏锛屽唴閮ㄨ皟璇曢敊璇�
+     */
+    private String detailMessage;
+
+    public ServiceException(String message) {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code) {
+        this.message = message;
+        this.code = code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public ServiceException setMessage(String message) {
+        this.message = message;
+        return this;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage) {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java
new file mode 100644
index 0000000..40ce01b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java
@@ -0,0 +1,74 @@
+package org.dromara.common.core.exception.base;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+
+/**
+ * 鍩虹寮傚父
+ *
+ * @author ruoyi
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class BaseException extends RuntimeException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎵�灞炴ā鍧�
+     */
+    private String module;
+
+    /**
+     * 閿欒鐮�
+     */
+    private String code;
+
+    /**
+     * 閿欒鐮佸搴旂殑鍙傛暟
+     */
+    private Object[] args;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    private String defaultMessage;
+
+    public BaseException(String module, String code, Object[] args) {
+        this(module, code, args, null);
+    }
+
+    public BaseException(String module, String defaultMessage) {
+        this(module, null, null, defaultMessage);
+    }
+
+    public BaseException(String code, Object[] args) {
+        this(null, code, args, null);
+    }
+
+    public BaseException(String defaultMessage) {
+        this(null, null, null, defaultMessage);
+    }
+
+    @Override
+    public String getMessage() {
+        String message = null;
+        if (!StringUtils.isEmpty(code)) {
+            message = MessageUtils.message(code, args);
+        }
+        if (message == null) {
+            message = defaultMessage;
+        }
+        return message;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java
new file mode 100644
index 0000000..d374fc0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java
@@ -0,0 +1,21 @@
+package org.dromara.common.core.exception.file;
+
+import org.dromara.common.core.exception.base.BaseException;
+
+import java.io.Serial;
+
+/**
+ * 鏂囦欢淇℃伅寮傚父绫�
+ *
+ * @author ruoyi
+ */
+public class FileException extends BaseException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public FileException(String code, Object[] args) {
+        super("file", code, args, null);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java
new file mode 100644
index 0000000..af98124
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.exception.file;
+
+import java.io.Serial;
+
+/**
+ * 鏂囦欢鍚嶇О瓒呴暱闄愬埗寮傚父绫�
+ *
+ * @author ruoyi
+ */
+public class FileNameLengthLimitExceededException extends FileException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public FileNameLengthLimitExceededException(int defaultFileNameLength) {
+        super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java
new file mode 100644
index 0000000..1eb8d40
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.exception.file;
+
+import java.io.Serial;
+
+/**
+ * 鏂囦欢鍚嶅ぇ灏忛檺鍒跺紓甯哥被
+ *
+ * @author ruoyi
+ */
+public class FileSizeLimitExceededException extends FileException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public FileSizeLimitExceededException(long defaultMaxSize) {
+        super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java
new file mode 100644
index 0000000..43824e0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.exception.user;
+
+import java.io.Serial;
+
+/**
+ * 楠岃瘉鐮侀敊璇紓甯哥被
+ *
+ * @author ruoyi
+ */
+public class CaptchaException extends UserException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaException() {
+        super("user.jcaptcha.error");
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java
new file mode 100644
index 0000000..f4b8cac
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.exception.user;
+
+import java.io.Serial;
+
+/**
+ * 楠岃瘉鐮佸け鏁堝紓甯哥被
+ *
+ * @author ruoyi
+ */
+public class CaptchaExpireException extends UserException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaExpireException() {
+        super("user.jcaptcha.expire");
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java
new file mode 100644
index 0000000..024fed6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java
@@ -0,0 +1,20 @@
+package org.dromara.common.core.exception.user;
+
+import org.dromara.common.core.exception.base.BaseException;
+
+import java.io.Serial;
+
+/**
+ * 鐢ㄦ埛淇℃伅寮傚父绫�
+ *
+ * @author ruoyi
+ */
+public class UserException extends BaseException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public UserException(String code, Object... args) {
+        super("user", code, args, null);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java
new file mode 100644
index 0000000..fd907d2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java
@@ -0,0 +1,52 @@
+package org.dromara.common.core.factory;
+
+import cn.hutool.core.lang.PatternPool;
+import org.dromara.common.core.constant.RegexConstants;
+
+import java.util.regex.Pattern;
+
+/**
+ * 姝e垯琛ㄨ揪寮忔ā寮忔睜宸ュ巶
+ * <p>鍒濆鍖栫殑鏃跺�欏皢姝e垯琛ㄨ揪寮忓姞鍏ョ紦瀛樻睜褰撲腑</p>
+ * <p>鎻愰珮姝e垯琛ㄨ揪寮忕殑鎬ц兘锛岄伩鍏嶉噸澶嶇紪璇戠浉鍚岀殑姝e垯琛ㄨ揪寮�</p>
+ *
+ * @author 21001
+ */
+public class RegexPatternPoolFactory extends PatternPool {
+
+    /**
+     * 瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�
+     */
+    public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE);
+
+    /**
+     * 韬唤璇佸彿鐮侊紙鍚�6浣嶏級
+     */
+    public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6);
+
+    /**
+     * QQ鍙风爜
+     */
+    public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER);
+
+    /**
+     * 閭斂缂栫爜
+     */
+    public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE);
+
+    /**
+     * 娉ㄥ唽璐﹀彿
+     */
+    public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT);
+
+    /**
+     * 瀵嗙爜锛氬寘鍚嚦灏�8涓瓧绗︼紝鍖呮嫭澶у啓瀛楁瘝銆佸皬鍐欏瓧姣嶃�佹暟瀛楀拰鐗规畩瀛楃
+     */
+    public static final Pattern PASSWORD = get(RegexConstants.PASSWORD);
+
+    /**
+     * 閫氱敤鐘舵�侊紙0琛ㄧず姝e父锛�1琛ㄧず鍋滅敤锛�
+     */
+    public static final Pattern STATUS = get(RegexConstants.STATUS);
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
new file mode 100644
index 0000000..af61b90
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
@@ -0,0 +1,31 @@
+package org.dromara.common.core.factory;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.DefaultPropertySourceFactory;
+import org.springframework.core.io.support.EncodedResource;
+
+import java.io.IOException;
+
+/**
+ * yml 閰嶇疆婧愬伐鍘�
+ *
+ * @author Lion Li
+ */
+public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
+
+    @Override
+    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
+        String sourceName = resource.getResource().getFilename();
+        if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
+            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+            factory.setResources(resource.getResource());
+            factory.afterPropertiesSet();
+            return new PropertiesPropertySource(sourceName, factory.getObject());
+        }
+        return super.createPropertySource(name, resource);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java
new file mode 100644
index 0000000..7328c69
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.service;
+
+/**
+ * 閫氱敤 鍙傛暟閰嶇疆鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface ConfigService {
+
+    /**
+     * 鏍规嵁鍙傛暟 key 鑾峰彇鍙傛暟鍊�
+     *
+     * @param configKey 鍙傛暟 key
+     * @return 鍙傛暟鍊�
+     */
+    String getConfigValue(String configKey);
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
new file mode 100644
index 0000000..db9463e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
@@ -0,0 +1,18 @@
+package org.dromara.common.core.service;
+
+/**
+ * 閫氱敤 閮ㄩ棬鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface DeptService {
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ閮ㄩ棬鍚嶇О
+     *
+     * @param deptIds 閮ㄩ棬ID涓查�楀彿鍒嗛殧
+     * @return 閮ㄩ棬鍚嶇О涓查�楀彿鍒嗛殧
+     */
+    String selectDeptNameByIds(String deptIds);
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java
new file mode 100644
index 0000000..b78a7f2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java
@@ -0,0 +1,67 @@
+package org.dromara.common.core.service;
+
+import java.util.Map;
+
+/**
+ * 閫氱敤 瀛楀吀鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface DictService {
+
+    /**
+     * 鍒嗛殧绗�
+     */
+    String SEPARATOR = ",";
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀鍊�
+     * @return 瀛楀吀鏍囩
+     */
+    default String getDictLabel(String dictType, String dictValue) {
+        return getDictLabel(dictType, dictValue, SEPARATOR);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictLabel 瀛楀吀鏍囩
+     * @return 瀛楀吀鍊�
+     */
+    default String getDictValue(String dictType, String dictLabel) {
+        return getDictValue(dictType, dictLabel, SEPARATOR);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀鍊�
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鏍囩
+     */
+    String getDictLabel(String dictType, String dictValue, String separator);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictLabel 瀛楀吀鏍囩
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鍊�
+     */
+    String getDictValue(String dictType, String dictLabel, String separator);
+
+    /**
+     * 鑾峰彇瀛楀吀涓嬫墍鏈夌殑瀛楀吀鍊间笌鏍囩
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return dictValue涓簁ey锛宒ictLabel涓哄�肩粍鎴愮殑Map
+     */
+    Map<String, String> getAllDictByDictType(String dictType);
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/EquTypeService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/EquTypeService.java
new file mode 100644
index 0000000..8de0cc3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/EquTypeService.java
@@ -0,0 +1,11 @@
+package org.dromara.common.core.service;
+
+public interface EquTypeService {
+    /**
+     * 閫氳繃璁惧绫诲瀷ID鏌ヨ璁惧绫诲瀷鍚嶇О
+     *
+     * @param equTypeIds 閮ㄩ棬ID涓查�楀彿鍒嗛殧
+     * @return 閮ㄩ棬鍚嶇О涓查�楀彿鍒嗛殧
+     */
+    String selectEquTypeNameByIds(String equTypeIds);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java
new file mode 100644
index 0000000..1a52de0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java
@@ -0,0 +1,29 @@
+package org.dromara.common.core.service;
+
+import org.dromara.common.core.domain.dto.OssDTO;
+
+import java.util.List;
+
+/**
+ * 閫氱敤 OSS鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface OssService {
+
+    /**
+     * 閫氳繃ossId鏌ヨ瀵瑰簲鐨剈rl
+     *
+     * @param ossIds ossId涓查�楀彿鍒嗛殧
+     * @return url涓查�楀彿鍒嗛殧
+     */
+    String selectUrlByIds(String ossIds);
+
+    /**
+     * 閫氳繃ossId鏌ヨ鍒楄〃
+     *
+     * @param ossIds ossId涓查�楀彿鍒嗛殧
+     * @return 鍒楄〃
+     */
+    List<OssDTO> selectByIds(String ossIds);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
new file mode 100644
index 0000000..43aef28
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
@@ -0,0 +1,85 @@
+package org.dromara.common.core.service;
+
+import org.dromara.common.core.domain.dto.UserDTO;
+
+import java.util.List;
+
+/**
+ * 閫氱敤 鐢ㄦ埛鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface UserService {
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛璐︽埛
+     */
+    String selectUserNameById(Long userId);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛鍚嶇О
+     */
+    String selectNicknameById(Long userId);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userIds 鐢ㄦ埛ID 澶氫釜鐢ㄩ�楀彿闅斿紑
+     * @return 鐢ㄦ埛鍚嶇О
+     */
+    String selectNicknameByIds(String userIds);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵嬫満鍙�
+     *
+     * @param userId 鐢ㄦ埛id
+     * @return 鐢ㄦ埛鎵嬫満鍙�
+     */
+    String selectPhonenumberById(Long userId);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛閭
+     *
+     * @param userId 鐢ㄦ埛id
+     * @return 鐢ㄦ埛閭
+     */
+    String selectEmailById(Long userId);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鍒楄〃
+     *
+     * @param userIds 鐢ㄦ埛ids
+     * @return 鐢ㄦ埛鍒楄〃
+     */
+    List<UserDTO> selectListByIds(List<Long> userIds);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ鐢ㄦ埛ID
+     *
+     * @param roleIds 瑙掕壊ids
+     * @return 鐢ㄦ埛ids
+     */
+    List<Long> selectUserIdsByRoleIds(List<Long> roleIds);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ鐢ㄦ埛
+     *
+     * @param roleIds 瑙掕壊ids
+     * @return 鐢ㄦ埛
+     */
+    List<UserDTO> selectUsersByRoleIds(List<Long> roleIds);
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ鐢ㄦ埛
+     *
+     * @param deptIds 閮ㄩ棬ids
+     * @return 鐢ㄦ埛
+     */
+    List<UserDTO> selectUsersByDeptIds(List<Long> deptIds);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
new file mode 100644
index 0000000..4e556c9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java
@@ -0,0 +1,76 @@
+package org.dromara.common.core.service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 閫氱敤 宸ヤ綔娴佹湇鍔�
+ *
+ * @author may
+ */
+public interface WorkflowService {
+
+    /**
+     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     * @return 缁撴灉
+     */
+    boolean deleteRunAndHisInstance(List<String> businessKeys);
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param taskId 浠诲姟id
+     */
+    String getBusinessStatusByTaskId(String taskId);
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param businessKey 涓氬姟id
+     */
+    String getBusinessStatus(String businessKey);
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     *
+     * @param taskId       浠诲姟id
+     * @param variableName 鍙橀噺鍚嶇О
+     * @param value        鍙橀噺鍊�
+     */
+    void setVariable(String taskId, String variableName, Object value);
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     *
+     * @param taskId    浠诲姟id
+     * @param variables 娴佺▼鍙橀噺
+     */
+    void setVariables(String taskId, Map<String, Object> variables);
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
+     *
+     * @param taskId       浠诲姟id
+     * @param variableName 鍙橀噺鍚嶇О
+     * @param value        鍙橀噺鍊�
+     */
+    void setVariableLocal(String taskId, String variableName, Object value);
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
+     *
+     * @param taskId    浠诲姟id
+     * @param variables 娴佺▼鍙橀噺
+     */
+    void setVariablesLocal(String taskId, Map<String, Object> variables);
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ娴佺▼瀹炰緥id
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    String getInstanceIdByBusinessKey(String businessKey);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
new file mode 100644
index 0000000..72178a7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
@@ -0,0 +1,168 @@
+package org.dromara.common.core.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+/**
+ * 鏃堕棿宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
+
+    public static final String YYYY = "yyyy";
+
+    public static final String YYYY_MM = "yyyy-MM";
+
+    public static final String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    private static final String[] PARSE_PATTERNS = {
+        "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+        "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+        "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    /**
+     * 鑾峰彇褰撳墠Date鍨嬫棩鏈�
+     *
+     * @return Date() 褰撳墠鏃ユ湡
+     */
+    public static Date getNowDate() {
+        return new Date();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     *
+     * @return String
+     */
+    public static String getDate() {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static String getTime() {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static String dateTimeNow() {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static String dateTimeNow(final String format) {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static String dateTime(final Date date) {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static String parseDateToStr(final String format, final Date date) {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static Date dateTime(final String format, final String ts) {
+        try {
+            return new SimpleDateFormat(format).parse(ts);
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
+     */
+    public static String datePath() {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
+     */
+    public static String dateTime() {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     */
+    public static Date parseDate(Object str) {
+        if (str == null) {
+            return null;
+        }
+        try {
+            return parseDate(str.toString(), PARSE_PATTERNS);
+        } catch (ParseException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     */
+    public static Date getServerStartDate() {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 璁$畻鐩稿樊澶╂暟
+     */
+    public static int differentDaysByMillisecond(Date date1, Date date2) {
+        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
+    }
+
+    /**
+     * 璁$畻涓や釜鏃堕棿宸�
+     */
+    public static String getDatePoor(Date endDate, Date nowDate) {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 鑾峰緱涓や釜鏃堕棿鐨勬绉掓椂闂村樊寮�
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 璁$畻宸灏戝ぉ
+        long day = diff / nd;
+        // 璁$畻宸灏戝皬鏃�
+        long hour = diff % nd / nh;
+        // 璁$畻宸灏戝垎閽�
+        long min = diff % nd % nh / nm;
+        // 璁$畻宸灏戠//杈撳嚭缁撴灉
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "澶�" + hour + "灏忔椂" + min + "鍒嗛挓";
+    }
+
+    /**
+     * 澧炲姞 LocalDateTime ==> Date
+     */
+    public static Date toDate(LocalDateTime temporalAccessor) {
+        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+
+    /**
+     * 澧炲姞 LocalDate ==> Date
+     */
+    public static Date toDate(LocalDate temporalAccessor) {
+        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
+        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java
new file mode 100644
index 0000000..b6acff7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java
@@ -0,0 +1,93 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import io.github.linpeilie.Converter;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Mapstruct 宸ュ叿绫�
+ * <p>鍙傝�冩枃妗o細<a href="https://mapstruct.plus/introduction/quick-start.html">mapstruct-plus</a></p>
+ *
+ *
+ * @author Michelle.Chung
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class MapstructUtils {
+
+    private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);
+
+    /**
+     * 灏� T 绫诲瀷瀵硅薄锛岃浆鎹负 desc 绫诲瀷鐨勫璞″苟杩斿洖
+     *
+     * @param source 鏁版嵁鏉ユ簮瀹炰綋
+     * @param desc   鎻忚堪瀵硅薄 杞崲鍚庣殑瀵硅薄
+     * @return desc
+     */
+    public static <T, V> V convert(T source, Class<V> desc) {
+        if (ObjectUtil.isNull(source)) {
+            return null;
+        }
+        if (ObjectUtil.isNull(desc)) {
+            return null;
+        }
+        return CONVERTER.convert(source, desc);
+    }
+
+    /**
+     * 灏� T 绫诲瀷瀵硅薄锛屾寜鐓ч厤缃殑鏄犲皠瀛楁瑙勫垯锛岀粰 desc 绫诲瀷鐨勫璞¤祴鍊煎苟杩斿洖 desc 瀵硅薄
+     *
+     * @param source 鏁版嵁鏉ユ簮瀹炰綋
+     * @param desc   杞崲鍚庣殑瀵硅薄
+     * @return desc
+     */
+    public static <T, V> V convert(T source, V desc) {
+        if (ObjectUtil.isNull(source)) {
+            return null;
+        }
+        if (ObjectUtil.isNull(desc)) {
+            return null;
+        }
+        return CONVERTER.convert(source, desc);
+    }
+
+    /**
+     * 灏� T 绫诲瀷鐨勯泦鍚堬紝杞崲涓� desc 绫诲瀷鐨勯泦鍚堝苟杩斿洖
+     *
+     * @param sourceList 鏁版嵁鏉ユ簮瀹炰綋鍒楄〃
+     * @param desc       鎻忚堪瀵硅薄 杞崲鍚庣殑瀵硅薄
+     * @return desc
+     */
+    public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) {
+        if (ObjectUtil.isNull(sourceList)) {
+            return null;
+        }
+        if (CollUtil.isEmpty(sourceList)) {
+            return CollUtil.newArrayList();
+        }
+        return CONVERTER.convert(sourceList, desc);
+    }
+
+    /**
+     * 灏� Map 杞崲涓� beanClass 绫诲瀷鐨勯泦鍚堝苟杩斿洖
+     *
+     * @param map       鏁版嵁鏉ユ簮
+     * @param beanClass bean绫�
+     * @return bean瀵硅薄
+     */
+    public static <T> T convert(Map<String, Object> map, Class<T> beanClass) {
+        if (MapUtil.isEmpty(map)) {
+            return null;
+        }
+        if (ObjectUtil.isNull(beanClass)) {
+            return null;
+        }
+        return CONVERTER.convert(map, beanClass);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
new file mode 100644
index 0000000..48dfc08
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
@@ -0,0 +1,33 @@
+package org.dromara.common.core.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.springframework.context.MessageSource;
+import org.springframework.context.NoSuchMessageException;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+/**
+ * 鑾峰彇i18n璧勬簮鏂囦欢
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class MessageUtils {
+
+    private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class);
+
+    /**
+     * 鏍规嵁娑堟伅閿拰鍙傛暟 鑾峰彇娑堟伅 濮旀墭缁檚pring messageSource
+     *
+     * @param code 娑堟伅閿�
+     * @param args 鍙傛暟
+     * @return 鑾峰彇鍥介檯鍖栫炕璇戝��
+     */
+    public static String message(String code, Object... args) {
+        try {
+            return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
+        } catch (NoSuchMessageException e) {
+            return code;
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
new file mode 100644
index 0000000..a1316eb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
@@ -0,0 +1,228 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.extra.servlet.JakartaServletUtil;
+import cn.hutool.http.HttpStatus;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.util.LinkedCaseInsensitiveMap;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 瀹㈡埛绔伐鍏风被
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ServletUtils extends JakartaServletUtil {
+
+    /**
+     * 鑾峰彇String鍙傛暟
+     */
+    public static String getParameter(String name) {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 鑾峰彇String鍙傛暟
+     */
+    public static String getParameter(String name, String defaultValue) {
+        return Convert.toStr(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 鑾峰彇Integer鍙傛暟
+     */
+    public static Integer getParameterToInt(String name) {
+        return Convert.toInt(getRequest().getParameter(name));
+    }
+
+    /**
+     * 鑾峰彇Integer鍙傛暟
+     */
+    public static Integer getParameterToInt(String name, Integer defaultValue) {
+        return Convert.toInt(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 鑾峰彇Boolean鍙傛暟
+     */
+    public static Boolean getParameterToBool(String name) {
+        return Convert.toBool(getRequest().getParameter(name));
+    }
+
+    /**
+     * 鑾峰彇Boolean鍙傛暟
+     */
+    public static Boolean getParameterToBool(String name, Boolean defaultValue) {
+        return Convert.toBool(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 鑾峰緱鎵�鏈夎姹傚弬鏁�
+     *
+     * @param request 璇锋眰瀵硅薄{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String[]> getParams(ServletRequest request) {
+        final Map<String, String[]> map = request.getParameterMap();
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * 鑾峰緱鎵�鏈夎姹傚弬鏁�
+     *
+     * @param request 璇锋眰瀵硅薄{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String> getParamMap(ServletRequest request) {
+        Map<String, String> params = new HashMap<>();
+        for (Map.Entry<String, String[]> entry : getParams(request).entrySet()) {
+            params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR));
+        }
+        return params;
+    }
+
+    /**
+     * 鑾峰彇request
+     */
+    public static HttpServletRequest getRequest() {
+        try {
+            return getRequestAttributes().getRequest();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇response
+     */
+    public static HttpServletResponse getResponse() {
+        try {
+            return getRequestAttributes().getResponse();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇session
+     */
+    public static HttpSession getSession() {
+        return getRequest().getSession();
+    }
+
+    public static ServletRequestAttributes getRequestAttributes() {
+        try {
+            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+            return (ServletRequestAttributes) attributes;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static String getHeader(HttpServletRequest request, String name) {
+        String value = request.getHeader(name);
+        if (StringUtils.isEmpty(value)) {
+            return StringUtils.EMPTY;
+        }
+        return urlDecode(value);
+    }
+
+    public static Map<String, String> getHeaders(HttpServletRequest request) {
+        Map<String, String> map = new LinkedCaseInsensitiveMap<>();
+        Enumeration<String> enumeration = request.getHeaderNames();
+        if (enumeration != null) {
+            while (enumeration.hasMoreElements()) {
+                String key = enumeration.nextElement();
+                String value = request.getHeader(key);
+                map.put(key, value);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 灏嗗瓧绗︿覆娓叉煋鍒板鎴风
+     *
+     * @param response 娓叉煋瀵硅薄
+     * @param string   寰呮覆鏌撶殑瀛楃涓�
+     */
+    public static void renderString(HttpServletResponse response, String string) {
+        try {
+            response.setStatus(HttpStatus.HTTP_OK);
+            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+            response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
+            response.getWriter().print(string);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 鏄惁鏄疉jax寮傛璇锋眰
+     *
+     * @param request
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request) {
+
+        String accept = request.getHeader("accept");
+        if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) {
+            return true;
+        }
+
+        String xRequestedWith = request.getHeader("X-Requested-With");
+        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) {
+            return true;
+        }
+
+        String uri = request.getRequestURI();
+        if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
+            return true;
+        }
+
+        String ajax = request.getParameter("__ajax");
+        return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml");
+    }
+
+    public static String getClientIP() {
+        return getClientIP(getRequest());
+    }
+
+    /**
+     * 鍐呭缂栫爜
+     *
+     * @param str 鍐呭
+     * @return 缂栫爜鍚庣殑鍐呭
+     */
+    public static String urlEncode(String str) {
+        return URLEncoder.encode(str, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * 鍐呭瑙g爜
+     *
+     * @param str 鍐呭
+     * @return 瑙g爜鍚庣殑鍐呭
+     */
+    public static String urlDecode(String str) {
+        return URLDecoder.decode(str, StandardCharsets.UTF_8);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java
new file mode 100644
index 0000000..169c6e2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java
@@ -0,0 +1,67 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.extra.spring.SpringUtil;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.boot.autoconfigure.thread.Threading;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring宸ュ叿绫�
+ *
+ * @author Lion Li
+ */
+@Component
+public final class SpringUtils extends SpringUtil {
+
+    /**
+     * 濡傛灉BeanFactory鍖呭惈涓�涓笌鎵�缁欏悕绉板尮閰嶇殑bean瀹氫箟锛屽垯杩斿洖true
+     */
+    public static boolean containsBean(String name) {
+        return getBeanFactory().containsBean(name);
+    }
+
+    /**
+     * 鍒ゆ柇浠ョ粰瀹氬悕瀛楁敞鍐岀殑bean瀹氫箟鏄竴涓猻ingleton杩樻槸涓�涓猵rototype銆�
+     * 濡傛灉涓庣粰瀹氬悕瀛楃浉搴旂殑bean瀹氫箟娌℃湁琚壘鍒帮紝灏嗕細鎶涘嚭涓�涓紓甯革紙NoSuchBeanDefinitionException锛�
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+        return getBeanFactory().isSingleton(name);
+    }
+
+    /**
+     * @return Class 娉ㄥ唽瀵硅薄鐨勭被鍨�
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
+        return getBeanFactory().getType(name);
+    }
+
+    /**
+     * 濡傛灉缁欏畾鐨刡ean鍚嶅瓧鍦╞ean瀹氫箟涓湁鍒悕锛屽垯杩斿洖杩欎簺鍒悕
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+        return getBeanFactory().getAliases(name);
+    }
+
+    /**
+     * 鑾峰彇aop浠g悊瀵硅薄
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker) {
+        return (T) getBean(invoker.getClass());
+    }
+
+
+    /**
+     * 鑾峰彇spring涓婁笅鏂�
+     */
+    public static ApplicationContext context() {
+        return getApplicationContext();
+    }
+
+    public static boolean isVirtual() {
+        return Threading.VIRTUAL.isActive(getBean(Environment.class));
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
new file mode 100644
index 0000000..1342deb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
@@ -0,0 +1,283 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * stream 娴佸伐鍏风被
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class StreamUtils {
+
+    /**
+     * 灏哻ollection杩囨护
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param function   杩囨护鏂规硶
+     * @return 杩囨护鍚庣殑list
+     */
+    public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return CollUtil.newArrayList();
+        }
+        // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂
+        return collection.stream().filter(function).collect(Collectors.toList());
+    }
+
+    /**
+     * 鎵惧埌娴佷腑婊¤冻鏉′欢鐨勭涓�涓厓绱�
+     *
+     * @param collection 闇�瑕佹煡璇㈢殑闆嗗悎
+     * @param function   杩囨护鏂规硶
+     * @return 鎵惧埌绗﹀悎鏉′欢鐨勭涓�涓厓绱狅紝娌℃湁鍒欒繑鍥瀗ull
+     */
+    public static <E> E findFirst(Collection<E> collection, Predicate<E> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return null;
+        }
+        return collection.stream().filter(function).findFirst().orElse(null);
+    }
+
+    /**
+     * 鎵惧埌娴佷腑浠绘剰涓�涓弧瓒虫潯浠剁殑鍏冪礌
+     *
+     * @param collection 闇�瑕佹煡璇㈢殑闆嗗悎
+     * @param function   杩囨护鏂规硶
+     * @return 鎵惧埌绗﹀悎鏉′欢鐨勪换鎰忎竴涓厓绱狅紝娌℃湁鍒欒繑鍥瀗ull
+     */
+    public static <E> Optional<E> findAny(Collection<E> collection, Predicate<E> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return Optional.empty();
+        }
+        return collection.stream().filter(function).findAny();
+    }
+
+    /**
+     * 灏哻ollection鎷兼帴
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param function   鎷兼帴鏂规硶
+     * @return 鎷兼帴鍚庣殑list
+     */
+    public static <E> String join(Collection<E> collection, Function<E, String> function) {
+        return join(collection, function, StringUtils.SEPARATOR);
+    }
+
+    /**
+     * 灏哻ollection鎷兼帴
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param function   鎷兼帴鏂规硶
+     * @param delimiter  鎷兼帴绗�
+     * @return 鎷兼帴鍚庣殑list
+     */
+    public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
+        if (CollUtil.isEmpty(collection)) {
+            return StringUtils.EMPTY;
+        }
+        return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
+    }
+
+    /**
+     * 灏哻ollection鎺掑簭
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param comparing  鎺掑簭鏂规硶
+     * @return 鎺掑簭鍚庣殑list
+     */
+    public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
+        if (CollUtil.isEmpty(collection)) {
+            return CollUtil.newArrayList();
+        }
+        // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂
+        return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
+    }
+
+    /**
+     * 灏哻ollection杞寲涓虹被鍨嬩笉鍙樼殑map<br>
+     * <B>{@code Collection<V>  ---->  Map<K,V>}</B>
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param key        V绫诲瀷杞寲涓篕绫诲瀷鐨刲ambda鏂规硶
+     * @param <V>        collection涓殑娉涘瀷
+     * @param <K>        map涓殑key绫诲瀷
+     * @return 杞寲鍚庣殑map
+     */
+    public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
+        if (CollUtil.isEmpty(collection)) {
+            return MapUtil.newHashMap();
+        }
+        return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
+    }
+
+    /**
+     * 灏咰ollection杞寲涓簃ap(value绫诲瀷涓巆ollection鐨勬硾鍨嬩笉鍚�)<br>
+     * <B>{@code Collection<E> -----> Map<K,V>  }</B>
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param key        E绫诲瀷杞寲涓篕绫诲瀷鐨刲ambda鏂规硶
+     * @param value      E绫诲瀷杞寲涓篤绫诲瀷鐨刲ambda鏂规硶
+     * @param <E>        collection涓殑娉涘瀷
+     * @param <K>        map涓殑key绫诲瀷
+     * @param <V>        map涓殑value绫诲瀷
+     * @return 杞寲鍚庣殑map
+     */
+    public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
+        if (CollUtil.isEmpty(collection)) {
+            return MapUtil.newHashMap();
+        }
+        return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
+    }
+
+    /**
+     * 灏哻ollection鎸夌収瑙勫垯(姣斿鏈夌浉鍚岀殑鐝骇id)鍒嗙被鎴恗ap<br>
+     * <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
+     *
+     * @param collection 闇�瑕佸垎绫荤殑闆嗗悎
+     * @param key        鍒嗙被鐨勮鍒�
+     * @param <E>        collection涓殑娉涘瀷
+     * @param <K>        map涓殑key绫诲瀷
+     * @return 鍒嗙被鍚庣殑map
+     */
+    public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
+        if (CollUtil.isEmpty(collection)) {
+            return MapUtil.newHashMap();
+        }
+        return collection
+            .stream().filter(Objects::nonNull)
+            .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
+    }
+
+    /**
+     * 灏哻ollection鎸夌収涓や釜瑙勫垯(姣斿鏈夌浉鍚岀殑骞寸骇id,鐝骇id)鍒嗙被鎴愬弻灞俶ap<br>
+     * <B>{@code Collection<E>  --->  Map<T,Map<U,List<E>>> } </B>
+     *
+     * @param collection 闇�瑕佸垎绫荤殑闆嗗悎
+     * @param key1       绗竴涓垎绫荤殑瑙勫垯
+     * @param key2       绗簩涓垎绫荤殑瑙勫垯
+     * @param <E>        闆嗗悎鍏冪礌绫诲瀷
+     * @param <K>        绗竴涓猰ap涓殑key绫诲瀷
+     * @param <U>        绗簩涓猰ap涓殑key绫诲瀷
+     * @return 鍒嗙被鍚庣殑map
+     */
+    public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
+        if (CollUtil.isEmpty(collection)) {
+            return MapUtil.newHashMap();
+        }
+        return collection
+            .stream().filter(Objects::nonNull)
+            .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
+    }
+
+    /**
+     * 灏哻ollection鎸夌収涓や釜瑙勫垯(姣斿鏈夌浉鍚岀殑骞寸骇id,鐝骇id)鍒嗙被鎴愬弻灞俶ap<br>
+     * <B>{@code Collection<E>  --->  Map<T,Map<U,E>> } </B>
+     *
+     * @param collection 闇�瑕佸垎绫荤殑闆嗗悎
+     * @param key1       绗竴涓垎绫荤殑瑙勫垯
+     * @param key2       绗簩涓垎绫荤殑瑙勫垯
+     * @param <T>        绗竴涓猰ap涓殑key绫诲瀷
+     * @param <U>        绗簩涓猰ap涓殑key绫诲瀷
+     * @param <E>        collection涓殑娉涘瀷
+     * @return 鍒嗙被鍚庣殑map
+     */
+    public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
+        if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
+            return MapUtil.newHashMap();
+        }
+        return collection
+            .stream().filter(Objects::nonNull)
+            .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
+    }
+
+    /**
+     * 灏哻ollection杞寲涓篖ist闆嗗悎锛屼絾鏄袱鑰呯殑娉涘瀷涓嶅悓<br>
+     * <B>{@code Collection<E>  ------>  List<T> } </B>
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param function   collection涓殑娉涘瀷杞寲涓簂ist娉涘瀷鐨刲ambda琛ㄨ揪寮�
+     * @param <E>        collection涓殑娉涘瀷
+     * @param <T>        List涓殑娉涘瀷
+     * @return 杞寲鍚庣殑list
+     */
+    public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
+        if (CollUtil.isEmpty(collection)) {
+            return CollUtil.newArrayList();
+        }
+        return collection
+            .stream()
+            .map(function)
+            .filter(Objects::nonNull)
+            // 娉ㄦ剰姝ゅ涓嶈浣跨敤 .toList() 鏂拌娉� 鍥犱负杩斿洖鐨勬槸涓嶅彲鍙楲ist 浼氬鑷村簭鍒楀寲闂
+            .collect(Collectors.toList());
+    }
+
+    /**
+     * 灏哻ollection杞寲涓篠et闆嗗悎锛屼絾鏄袱鑰呯殑娉涘瀷涓嶅悓<br>
+     * <B>{@code Collection<E>  ------>  Set<T> } </B>
+     *
+     * @param collection 闇�瑕佽浆鍖栫殑闆嗗悎
+     * @param function   collection涓殑娉涘瀷杞寲涓簊et娉涘瀷鐨刲ambda琛ㄨ揪寮�
+     * @param <E>        collection涓殑娉涘瀷
+     * @param <T>        Set涓殑娉涘瀷
+     * @return 杞寲鍚庣殑Set
+     */
+    public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
+        if (CollUtil.isEmpty(collection) || function == null) {
+            return CollUtil.newHashSet();
+        }
+        return collection
+            .stream()
+            .map(function)
+            .filter(Objects::nonNull)
+            .collect(Collectors.toSet());
+    }
+
+
+    /**
+     * 鍚堝苟涓や釜鐩稿悓key绫诲瀷鐨刴ap
+     *
+     * @param map1  绗竴涓渶瑕佸悎骞剁殑 map
+     * @param map2  绗簩涓渶瑕佸悎骞剁殑 map
+     * @param merge 鍚堝苟鐨刲ambda锛屽皢key  value1 value2鍚堝苟鎴愭渶缁堢殑绫诲瀷,娉ㄦ剰value鍙兘涓虹┖鐨勬儏鍐�
+     * @param <K>   map涓殑key绫诲瀷
+     * @param <X>   绗竴涓� map鐨剉alue绫诲瀷
+     * @param <Y>   绗簩涓� map鐨剉alue绫诲瀷
+     * @param <V>   鏈�缁坢ap鐨剉alue绫诲瀷
+     * @return 鍚堝苟鍚庣殑map
+     */
+    public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
+        if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
+            return MapUtil.newHashMap();
+        } else if (MapUtil.isEmpty(map1)) {
+            map1 = MapUtil.newHashMap();
+        } else if (MapUtil.isEmpty(map2)) {
+            map2 = MapUtil.newHashMap();
+        }
+        Set<K> key = new HashSet<>();
+        key.addAll(map1.keySet());
+        key.addAll(map2.keySet());
+        Map<K, V> map = new HashMap<>();
+        for (K t : key) {
+            X x = map1.get(t);
+            Y y = map2.get(t);
+            V z = merge.apply(x, y);
+            if (z != null) {
+                map.put(t, z);
+            }
+        }
+        return map;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
new file mode 100644
index 0000000..dd6ebb1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java
@@ -0,0 +1,323 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.StrUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 瀛楃涓插伐鍏风被
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+    public static final String SEPARATOR = ",";
+
+    public static final String SLASH = "/";
+
+    /**
+     * 鑾峰彇鍙傛暟涓嶄负绌哄��
+     *
+     * @param str defaultValue 瑕佸垽鏂殑value
+     * @return value 杩斿洖鍊�
+     */
+    public static String blankToDefault(String str, String defaultValue) {
+        return StrUtil.blankToDefault(str, defaultValue);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓虹┖涓�
+     *
+     * @param str String
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(String str) {
+        return StrUtil.isEmpty(str);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓洪潪绌轰覆
+     *
+     * @param str String
+     * @return true锛氶潪绌轰覆 false锛氱┖涓�
+     */
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+
+    /**
+     * 鍘荤┖鏍�
+     */
+    public static String trim(String str) {
+        return StrUtil.trim(str);
+    }
+
+    /**
+     * 鎴彇瀛楃涓�
+     *
+     * @param str   瀛楃涓�
+     * @param start 寮�濮�
+     * @return 缁撴灉
+     */
+    public static String substring(final String str, int start) {
+        return substring(str, start, str.length());
+    }
+
+    /**
+     * 鎴彇瀛楃涓�
+     *
+     * @param str   瀛楃涓�
+     * @param start 寮�濮�
+     * @param end   缁撴潫
+     * @return 缁撴灉
+     */
+    public static String substring(final String str, int start, int end) {
+        return StrUtil.sub(str, start, end);
+    }
+
+    /**
+     * 鏍煎紡鍖栨枃鏈�, {} 琛ㄧず鍗犱綅绗�<br>
+     * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br>
+     * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br>
+     * 渚嬶細<br>
+     * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is {} for a<br>
+     * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     *
+     * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {} 琛ㄧず
+     * @param params   鍙傛暟鍊�
+     * @return 鏍煎紡鍖栧悗鐨勬枃鏈�
+     */
+    public static String format(String template, Object... params) {
+        return StrUtil.format(template, params);
+    }
+
+    /**
+     * 鏄惁涓篽ttp(s)://寮�澶�
+     *
+     * @param link 閾炬帴
+     * @return 缁撴灉
+     */
+    public static boolean ishttp(String link) {
+        return Validator.isUrl(link);
+    }
+
+    /**
+     * 瀛楃涓茶浆set
+     *
+     * @param str 瀛楃涓�
+     * @param sep 鍒嗛殧绗�
+     * @return set闆嗗悎
+     */
+    public static Set<String> str2Set(String str, String sep) {
+        return new HashSet<>(str2List(str, sep, true, false));
+    }
+
+    /**
+     * 瀛楃涓茶浆list
+     *
+     * @param str         瀛楃涓�
+     * @param sep         鍒嗛殧绗�
+     * @param filterBlank 杩囨护绾┖鐧�
+     * @param trim        鍘绘帀棣栧熬绌虹櫧
+     * @return list闆嗗悎
+     */
+    public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
+        List<String> list = new ArrayList<>();
+        if (isEmpty(str)) {
+            return list;
+        }
+
+        // 杩囨护绌虹櫧瀛楃涓�
+        if (filterBlank && isBlank(str)) {
+            return list;
+        }
+        String[] split = str.split(sep);
+        for (String string : split) {
+            if (filterBlank && isBlank(string)) {
+                continue;
+            }
+            if (trim) {
+                string = trim(string);
+            }
+            list.add(string);
+        }
+
+        return list;
+    }
+
+    /**
+     * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀寘鍚寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆鍚屾椂涓插拷鐣ュぇ灏忓啓
+     *
+     * @param cs                  鎸囧畾瀛楃涓�
+     * @param searchCharSequences 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁�
+     * @return 鏄惁鍖呭惈浠绘剰涓�涓瓧绗︿覆
+     */
+    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
+        return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences);
+    }
+
+    /**
+     * 椹煎嘲杞笅鍒掔嚎鍛藉悕
+     */
+    public static String toUnderScoreCase(String str) {
+        return StrUtil.toUnderlineCase(str);
+    }
+
+    /**
+     * 鏄惁鍖呭惈瀛楃涓�
+     *
+     * @param str  楠岃瘉瀛楃涓�
+     * @param strs 瀛楃涓茬粍
+     * @return 鍖呭惈杩斿洖true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs) {
+        return StrUtil.equalsAnyIgnoreCase(str, strs);
+    }
+
+    /**
+     * 灏嗕笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆杞崲涓洪┘宄板紡銆傚鏋滆浆鎹㈠墠鐨勪笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆涓虹┖锛屽垯杩斿洖绌哄瓧绗︿覆銆� 渚嬪锛欻ELLO_WORLD->HelloWorld
+     *
+     * @param name 杞崲鍓嶇殑涓嬪垝绾垮ぇ鍐欐柟寮忓懡鍚嶇殑瀛楃涓�
+     * @return 杞崲鍚庣殑椹煎嘲寮忓懡鍚嶇殑瀛楃涓�
+     */
+    public static String convertToCamelCase(String name) {
+        return StrUtil.upperFirst(StrUtil.toCamelCase(name));
+    }
+
+    /**
+     * 椹煎嘲寮忓懡鍚嶆硶 渚嬪锛歶ser_name->userName
+     */
+    public static String toCamelCase(String s) {
+        return StrUtil.toCamelCase(s);
+    }
+
+    /**
+     * 鏌ユ壘鎸囧畾瀛楃涓叉槸鍚﹀尮閰嶆寚瀹氬瓧绗︿覆鍒楄〃涓殑浠绘剰涓�涓瓧绗︿覆
+     *
+     * @param str  鎸囧畾瀛楃涓�
+     * @param strs 闇�瑕佹鏌ョ殑瀛楃涓叉暟缁�
+     * @return 鏄惁鍖归厤
+     */
+    public static boolean matches(String str, List<String> strs) {
+        if (isEmpty(str) || CollUtil.isEmpty(strs)) {
+            return false;
+        }
+        for (String pattern : strs) {
+            if (isMatch(pattern, str)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 鍒ゆ柇url鏄惁涓庤鍒欓厤缃�:
+     * ? 琛ㄧず鍗曚釜瀛楃;
+     * * 琛ㄧず涓�灞傝矾寰勫唴鐨勪换鎰忓瓧绗︿覆锛屼笉鍙法灞傜骇;
+     * ** 琛ㄧず浠绘剰灞傝矾寰�;
+     *
+     * @param pattern 鍖归厤瑙勫垯
+     * @param url     闇�瑕佸尮閰嶇殑url
+     */
+    public static boolean isMatch(String pattern, String url) {
+        AntPathMatcher matcher = new AntPathMatcher();
+        return matcher.match(pattern, url);
+    }
+
+    /**
+     * 鏁板瓧宸﹁竟琛ラ綈0锛屼娇涔嬭揪鍒版寚瀹氶暱搴︺�傛敞鎰忥紝濡傛灉鏁板瓧杞崲涓哄瓧绗︿覆鍚庯紝闀垮害澶т簬size锛屽垯鍙繚鐣� 鏈�鍚巗ize涓瓧绗︺��
+     *
+     * @param num  鏁板瓧瀵硅薄
+     * @param size 瀛楃涓叉寚瀹氶暱搴�
+     * @return 杩斿洖鏁板瓧鐨勫瓧绗︿覆鏍煎紡锛岃瀛楃涓蹭负鎸囧畾闀垮害銆�
+     */
+    public static String padl(final Number num, final int size) {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 瀛楃涓插乏琛ラ綈銆傚鏋滃師濮嬪瓧绗︿覆s闀垮害澶т簬size锛屽垯鍙繚鐣欐渶鍚巗ize涓瓧绗︺��
+     *
+     * @param s    鍘熷瀛楃涓�
+     * @param size 瀛楃涓叉寚瀹氶暱搴�
+     * @param c    鐢ㄤ簬琛ラ綈鐨勫瓧绗�
+     * @return 杩斿洖鎸囧畾闀垮害鐨勫瓧绗︿覆锛岀敱鍘熷瓧绗︿覆宸﹁ˉ榻愭垨鎴彇寰楀埌銆�
+     */
+    public static String padl(final String s, final int size, final char c) {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null) {
+            final int len = s.length();
+            if (s.length() <= size) {
+                sb.append(String.valueOf(c).repeat(size - len));
+                sb.append(s);
+            } else {
+                return s.substring(len - size, len);
+            }
+        } else {
+            sb.append(String.valueOf(c).repeat(Math.max(0, size)));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 鍒囧垎瀛楃涓�(鍒嗛殧绗﹂粯璁ら�楀彿)
+     *
+     * @param str 琚垏鍒嗙殑瀛楃涓�
+     * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃
+     */
+    public static List<String> splitList(String str) {
+        return splitTo(str, Convert::toStr);
+    }
+
+    /**
+     * 鍒囧垎瀛楃涓�
+     *
+     * @param str       琚垏鍒嗙殑瀛楃涓�
+     * @param separator 鍒嗛殧绗�
+     * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃
+     */
+    public static List<String> splitList(String str, String separator) {
+        return splitTo(str, separator, Convert::toStr);
+    }
+
+    /**
+     * 鍒囧垎瀛楃涓茶嚜瀹氫箟杞崲(鍒嗛殧绗﹂粯璁ら�楀彿)
+     *
+     * @param str    琚垏鍒嗙殑瀛楃涓�
+     * @param mapper 鑷畾涔夎浆鎹�
+     * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃
+     */
+    public static <T> List<T> splitTo(String str, Function<? super Object, T> mapper) {
+        return splitTo(str, SEPARATOR, mapper);
+    }
+
+    /**
+     * 鍒囧垎瀛楃涓茶嚜瀹氫箟杞崲
+     *
+     * @param str       琚垏鍒嗙殑瀛楃涓�
+     * @param separator 鍒嗛殧绗�
+     * @param mapper    鑷畾涔夎浆鎹�
+     * @return 鍒嗗壊鍚庣殑鏁版嵁鍒楄〃
+     */
+    public static <T> List<T> splitTo(String str, String separator, Function<? super Object, T> mapper) {
+        if (isBlank(str)) {
+            return new ArrayList<>(0);
+        }
+        return StrUtil.split(str, separator)
+            .stream()
+            .filter(Objects::nonNull)
+            .map(mapper)
+            .collect(Collectors.toList());
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
new file mode 100644
index 0000000..ae6cfa3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
@@ -0,0 +1,75 @@
+package org.dromara.common.core.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.*;
+
+/**
+ * 绾跨▼鐩稿叧宸ュ叿绫�.
+ *
+ * @author ruoyi
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class Threads {
+
+    /**
+     * sleep绛夊緟,鍗曚綅涓烘绉�
+     */
+    public static void sleep(long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            return;
+        }
+    }
+
+    /**
+     * 鍋滄绾跨▼姹�
+     * 鍏堜娇鐢╯hutdown, 鍋滄鎺ユ敹鏂颁换鍔″苟灏濊瘯瀹屾垚鎵�鏈夊凡瀛樺湪浠诲姟.
+     * 濡傛灉瓒呮椂, 鍒欒皟鐢╯hutdownNow, 鍙栨秷鍦╳orkQueue涓璓ending鐨勪换鍔�,骞朵腑鏂墍鏈夐樆濉炲嚱鏁�.
+     * 濡傛灉浠嶇劧瓒呮檪锛屽墖寮峰埗閫�鍑�.
+     * 鍙﹀鍦╯hutdown鏃剁嚎绋嬫湰韬璋冪敤涓柇鍋氫簡澶勭悊.
+     */
+    public static void shutdownAndAwaitTermination(ExecutorService pool) {
+        if (pool != null && !pool.isShutdown()) {
+            pool.shutdown();
+            try {
+                if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                    pool.shutdownNow();
+                    if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                        log.info("Pool did not terminate");
+                    }
+                }
+            } catch (InterruptedException ie) {
+                pool.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * 鎵撳嵃绾跨▼寮傚父淇℃伅
+     */
+    public static void printException(Runnable r, Throwable t) {
+        if (t == null && r instanceof Future<?>) {
+            try {
+                Future<?> future = (Future<?>) r;
+                if (future.isDone()) {
+                    future.get();
+                }
+            } catch (CancellationException ce) {
+                t = ce;
+            } catch (ExecutionException ee) {
+                t = ee.getCause();
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (t != null) {
+            log.error(t.getMessage(), t);
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java
new file mode 100644
index 0000000..d0163e6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java
@@ -0,0 +1,35 @@
+package org.dromara.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import cn.hutool.core.lang.tree.parser.NodeParser;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 鎵╁睍 hutool TreeUtil 灏佽绯荤粺鏍戞瀯寤�
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class TreeBuildUtils extends TreeUtil {
+
+    /**
+     * 鏍规嵁鍓嶇瀹氬埗宸紓鍖栧瓧娈�
+     */
+    public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
+
+    public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) {
+        if (CollUtil.isEmpty(list)) {
+            return null;
+        }
+        K k = ReflectUtils.invokeGetter(list.get(0), "parentId");
+        return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java
new file mode 100644
index 0000000..06b8fd6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java
@@ -0,0 +1,35 @@
+package org.dromara.common.core.utils;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.Validator;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.Set;
+
+/**
+ * Validator 鏍¢獙妗嗘灦宸ュ叿
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ValidatorUtils {
+
+    private static final Validator VALID = SpringUtils.getBean(Validator.class);
+
+    /**
+     * 瀵圭粰瀹氬璞¤繘琛屽弬鏁版牎楠岋紝骞舵牴鎹寚瀹氱殑鏍¢獙缁勮繘琛屾牎楠�
+     *
+     * @param object 瑕佽繘琛屾牎楠岀殑瀵硅薄
+     * @param groups 鏍¢獙缁�
+     * @throws ConstraintViolationException 濡傛灉鏍¢獙涓嶉�氳繃锛屽垯鎶涘嚭鍙傛暟鏍¢獙寮傚父
+     */
+    public static <T> void validate(T object, Class<?>... groups) {
+        Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
+        if (!validate.isEmpty()) {
+            throw new ConstraintViolationException("鍙傛暟鏍¢獙寮傚父", validate);
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java
new file mode 100644
index 0000000..573b207
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java
@@ -0,0 +1,43 @@
+package org.dromara.common.core.utils.file;
+
+import cn.hutool.core.io.FileUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 鏂囦欢澶勭悊宸ュ叿绫�
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class FileUtils extends FileUtil {
+
+    /**
+     * 涓嬭浇鏂囦欢鍚嶉噸鏂扮紪鐮�
+     *
+     * @param response     鍝嶅簲瀵硅薄
+     * @param realFileName 鐪熷疄鏂囦欢鍚�
+     */
+    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) {
+        String percentEncodedFileName = percentEncode(realFileName);
+        String contentDispositionValue = "attachment; filename=%s;filename*=utf-8''%s".formatted(percentEncodedFileName, percentEncodedFileName);
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
+        response.setHeader("Content-disposition", contentDispositionValue);
+        response.setHeader("download-filename", percentEncodedFileName);
+    }
+
+    /**
+     * 鐧惧垎鍙风紪鐮佸伐鍏锋柟娉�
+     *
+     * @param s 闇�瑕佺櫨鍒嗗彿缂栫爜鐨勫瓧绗︿覆
+     * @return 鐧惧垎鍙风紪鐮佸悗鐨勫瓧绗︿覆
+     */
+    public static String percentEncode(String s) {
+        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8);
+        return encode.replaceAll("\\+", "%20");
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java
new file mode 100644
index 0000000..23fa2cf
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java
@@ -0,0 +1,40 @@
+package org.dromara.common.core.utils.file;
+
+/**
+ * 濯掍綋绫诲瀷宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class MimeTypeUtils {
+    public static final String IMAGE_PNG = "image/png";
+
+    public static final String IMAGE_JPG = "image/jpg";
+
+    public static final String IMAGE_JPEG = "image/jpeg";
+
+    public static final String IMAGE_BMP = "image/bmp";
+
+    public static final String IMAGE_GIF = "image/gif";
+
+    public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
+
+    public static final String[] FLASH_EXTENSION = {"swf", "flv"};
+
+    public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
+        "asf", "rm", "rmvb"};
+
+    public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
+
+    public static final String[] DEFAULT_ALLOWED_EXTENSION = {
+        // 鍥剧墖
+        "bmp", "gif", "jpg", "jpeg", "png",
+        // word excel powerpoint
+        "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
+        // 鍘嬬缉鏂囦欢
+        "rar", "zip", "gz", "bz2",
+        // 瑙嗛鏍煎紡
+        "mp4", "avi", "rmvb",
+        // pdf
+        "pdf"};
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
new file mode 100644
index 0000000..3f7cd57
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java
@@ -0,0 +1,33 @@
+package org.dromara.common.core.utils.ip;
+
+import cn.hutool.core.net.NetUtil;
+import cn.hutool.http.HtmlUtil;
+import org.dromara.common.core.utils.StringUtils;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 鑾峰彇鍦板潃绫�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class AddressUtils {
+
+    // 鏈煡鍦板潃
+    public static final String UNKNOWN = "XX XX";
+
+    public static String getRealAddressByIP(String ip) {
+        if (StringUtils.isBlank(ip)) {
+            return UNKNOWN;
+        }
+        // 鍐呯綉涓嶆煡璇�
+        ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
+        if (NetUtil.isInnerIP(ip)) {
+            return "鍐呯綉IP";
+        }
+        return RegionUtils.getCityInfo(ip);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
new file mode 100644
index 0000000..6e2a44e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java
@@ -0,0 +1,67 @@
+package org.dromara.common.core.utils.ip;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.ObjectUtil;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.file.FileUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.lionsoul.ip2region.xdb.Searcher;
+
+import java.io.File;
+
+/**
+ * 鏍规嵁ip鍦板潃瀹氫綅宸ュ叿绫伙紝绂荤嚎鏂瑰紡
+ * 鍙傝�冨湴鍧�锛�<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">闆嗘垚 ip2region 瀹炵幇绂荤嚎IP鍦板潃瀹氫綅搴�</a>
+ *
+ * @author lishuyan
+ */
+@Slf4j
+public class RegionUtils {
+
+    private static final Searcher SEARCHER;
+
+    static {
+        String fileName = "/ip2region.xdb";
+        File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
+        if (!FileUtils.exist(existFile)) {
+            ClassPathResource fileStream = new ClassPathResource(fileName);
+            if (ObjectUtil.isEmpty(fileStream.getStream())) {
+                throw new ServiceException("RegionUtils鍒濆鍖栧け璐ワ紝鍘熷洜锛欼P鍦板潃搴撴暟鎹笉瀛樺湪锛�");
+            }
+            FileUtils.writeFromStream(fileStream.getStream(), existFile);
+        }
+
+        String dbPath = existFile.getPath();
+
+        // 1銆佷粠 dbPath 鍔犺浇鏁翠釜 xdb 鍒板唴瀛樸��
+        byte[] cBuff;
+        try {
+            cBuff = Searcher.loadContentFromFile(dbPath);
+        } catch (Exception e) {
+            throw new ServiceException("RegionUtils鍒濆鍖栧け璐ワ紝鍘熷洜锛氫粠ip2region.xdb鏂囦欢鍔犺浇鍐呭澶辫触锛�" + e.getMessage());
+        }
+        // 2銆佷娇鐢ㄤ笂杩扮殑 cBuff 鍒涘缓涓�涓畬鍏ㄥ熀浜庡唴瀛樼殑鏌ヨ瀵硅薄銆�
+        try {
+            SEARCHER = Searcher.newWithBuffer(cBuff);
+        } catch (Exception e) {
+            throw new ServiceException("RegionUtils鍒濆鍖栧け璐ワ紝鍘熷洜锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鏍规嵁IP鍦板潃绂荤嚎鑾峰彇鍩庡競
+     */
+    public static String getCityInfo(String ip) {
+        try {
+            ip = ip.trim();
+            // 3銆佹墽琛屾煡璇�
+            String region = SEARCHER.search(ip);
+            return region.replace("0|", "").replace("|0", "");
+        } catch (Exception e) {
+            log.error("IP鍦板潃绂荤嚎鑾峰彇鍩庡競寮傚父 {}", ip);
+            return "鏈煡";
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java
new file mode 100644
index 0000000..367e8c9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java
@@ -0,0 +1,56 @@
+package org.dromara.common.core.utils.reflect;
+
+import cn.hutool.core.util.ReflectUtil;
+import org.dromara.common.core.utils.StringUtils;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.lang.reflect.Method;
+
+/**
+ * 鍙嶅皠宸ュ叿绫�. 鎻愪緵璋冪敤getter/setter鏂规硶, 璁块棶绉佹湁鍙橀噺, 璋冪敤绉佹湁鏂规硶, 鑾峰彇娉涘瀷绫诲瀷Class, 琚獳OP杩囩殑鐪熷疄绫荤瓑宸ュ叿鍑芥暟.
+ *
+ * @author Lion Li
+ */
+@SuppressWarnings("rawtypes")
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ReflectUtils extends ReflectUtil {
+
+    private static final String SETTER_PREFIX = "set";
+
+    private static final String GETTER_PREFIX = "get";
+
+    /**
+     * 璋冪敤Getter鏂规硶.
+     * 鏀寔澶氱骇锛屽锛氬璞″悕.瀵硅薄鍚�.鏂规硶
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeGetter(Object obj, String propertyName) {
+        Object object = obj;
+        for (String name : StringUtils.split(propertyName, ".")) {
+            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+            object = invoke(object, getterMethodName);
+        }
+        return (E) object;
+    }
+
+    /**
+     * 璋冪敤Setter鏂规硶, 浠呭尮閰嶆柟娉曞悕銆�
+     * 鏀寔澶氱骇锛屽锛氬璞″悕.瀵硅薄鍚�.鏂规硶
+     */
+    public static <E> void invokeSetter(Object obj, String propertyName, E value) {
+        Object object = obj;
+        String[] names = StringUtils.split(propertyName, ".");
+        for (int i = 0; i < names.length; i++) {
+            if (i < names.length - 1) {
+                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+                object = invoke(object, getterMethodName);
+            } else {
+                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+                Method method = getMethodByName(object.getClass(), setterMethodName);
+                invoke(object, method, value);
+            }
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java
new file mode 100644
index 0000000..b8b12d4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java
@@ -0,0 +1,30 @@
+package org.dromara.common.core.utils.regex;
+
+
+import cn.hutool.core.util.ReUtil;
+import org.dromara.common.core.constant.RegexConstants;
+
+/**
+ * 姝e垯鐩稿叧宸ュ叿绫�
+ *
+ * @author Feng
+ */
+public final class RegexUtils extends ReUtil {
+
+    /**
+     * 浠庤緭鍏ュ瓧绗︿覆涓彁鍙栧尮閰嶇殑閮ㄥ垎锛屽鏋滄病鏈夊尮閰嶅垯杩斿洖榛樿鍊�
+     *
+     * @param input        瑕佹彁鍙栫殑杈撳叆瀛楃涓�
+     * @param regex        鐢ㄤ簬鍖归厤鐨勬鍒欒〃杈惧紡锛屽彲浠ヤ娇鐢� {@link RegexConstants} 涓畾涔夌殑甯搁噺
+     * @param defaultInput 濡傛灉娌℃湁鍖归厤鏃惰繑鍥炵殑榛樿鍊�
+     * @return 濡傛灉鎵惧埌鍖归厤鐨勯儴鍒嗭紝鍒欒繑鍥炲尮閰嶇殑閮ㄥ垎锛屽惁鍒欒繑鍥為粯璁ゅ��
+     */
+    public static String extractFromString(String input, String regex, String defaultInput) {
+        try {
+            return ReUtil.get(regex, input, 1);
+        } catch (Exception e) {
+            return defaultInput;
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java
new file mode 100644
index 0000000..c0dda20
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java
@@ -0,0 +1,105 @@
+package org.dromara.common.core.utils.regex;
+
+import cn.hutool.core.exceptions.ValidateException;
+import cn.hutool.core.lang.Validator;
+import org.dromara.common.core.factory.RegexPatternPoolFactory;
+
+import java.util.regex.Pattern;
+
+/**
+ * 姝e垯瀛楁鏍¢獙鍣�
+ * 涓昏楠岃瘉瀛楁闈炵┖銆佹槸鍚︿负婊¤冻鎸囧畾鏍煎紡绛�
+ *
+ * @author Feng
+ */
+public class RegexValidator extends Validator {
+
+    /**
+     * 瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�
+     */
+    public static final Pattern DICTIONARY_TYPE = RegexPatternPoolFactory.DICTIONARY_TYPE;
+
+    /**
+     * 韬唤璇佸彿鐮侊紙鍚�6浣嶏級
+     */
+    public static final Pattern ID_CARD_LAST_6 = RegexPatternPoolFactory.ID_CARD_LAST_6;
+
+    /**
+     * QQ鍙风爜
+     */
+    public static final Pattern QQ_NUMBER = RegexPatternPoolFactory.QQ_NUMBER;
+
+    /**
+     * 閭斂缂栫爜
+     */
+    public static final Pattern POSTAL_CODE = RegexPatternPoolFactory.POSTAL_CODE;
+
+    /**
+     * 娉ㄥ唽璐﹀彿
+     */
+    public static final Pattern ACCOUNT = RegexPatternPoolFactory.ACCOUNT;
+
+    /**
+     * 瀵嗙爜锛氬寘鍚嚦灏�8涓瓧绗︼紝鍖呮嫭澶у啓瀛楁瘝銆佸皬鍐欏瓧姣嶃�佹暟瀛楀拰鐗规畩瀛楃
+     */
+    public static final Pattern PASSWORD = RegexPatternPoolFactory.PASSWORD;
+
+    /**
+     * 閫氱敤鐘舵�侊紙0琛ㄧず姝e父锛�1琛ㄧず鍋滅敤锛�
+     */
+    public static final Pattern STATUS = RegexPatternPoolFactory.STATUS;
+
+
+    /**
+     * 妫�鏌ヨ緭鍏ョ殑璐﹀彿鏄惁鍖归厤棰勫畾涔夌殑瑙勫垯
+     *
+     * @param value 瑕侀獙璇佺殑璐﹀彿
+     * @return 濡傛灉璐﹀彿绗﹀悎瑙勫垯锛岃繑鍥� true锛涘惁鍒欙紝杩斿洖 false銆�
+     */
+    public static boolean isAccount(CharSequence value) {
+        return isMatchRegex(ACCOUNT, value);
+    }
+
+    /**
+     * 楠岃瘉杈撳叆鐨勮处鍙锋槸鍚︾鍚堣鍒欙紝濡傛灉涓嶇鍚堬紝鍒欐姏鍑� ValidateException 寮傚父
+     *
+     * @param value    瑕侀獙璇佺殑璐﹀彿
+     * @param errorMsg 楠岃瘉澶辫触鏃舵姏鍑虹殑寮傚父娑堟伅
+     * @param <T>      CharSequence 鐨勫瓙绫诲瀷
+     * @return 濡傛灉楠岃瘉閫氳繃锛岃繑鍥炶緭鍏ョ殑璐﹀彿
+     * @throws ValidateException 濡傛灉楠岃瘉澶辫触
+     */
+    public static <T extends CharSequence> T validateAccount(T value, String errorMsg) throws ValidateException {
+        if (!isAccount(value)) {
+            throw new ValidateException(errorMsg);
+        }
+        return value;
+    }
+
+    /**
+     * 妫�鏌ヨ緭鍏ョ殑鐘舵�佹槸鍚﹀尮閰嶉瀹氫箟鐨勮鍒�
+     *
+     * @param value 瑕侀獙璇佺殑鐘舵��
+     * @return 濡傛灉鐘舵�佺鍚堣鍒欙紝杩斿洖 true锛涘惁鍒欙紝杩斿洖 false銆�
+     */
+    public static boolean isStatus(CharSequence value) {
+        return isMatchRegex(STATUS, value);
+    }
+
+    /**
+     * 楠岃瘉杈撳叆鐨勭姸鎬佹槸鍚︾鍚堣鍒欙紝濡傛灉涓嶇鍚堬紝鍒欐姏鍑� ValidateException 寮傚父
+     *
+     * @param value    瑕侀獙璇佺殑鐘舵��
+     * @param errorMsg 楠岃瘉澶辫触鏃舵姏鍑虹殑寮傚父娑堟伅
+     * @param <T>      CharSequence 鐨勫瓙绫诲瀷
+     * @return 濡傛灉楠岃瘉閫氳繃锛岃繑鍥炶緭鍏ョ殑鐘舵��
+     * @throws ValidateException 濡傛灉楠岃瘉澶辫触
+     */
+    public static <T extends CharSequence> T validateStatus(T value, String errorMsg) throws ValidateException {
+        if (!isStatus(value)) {
+            throw new ValidateException(errorMsg);
+        }
+        return value;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
new file mode 100644
index 0000000..3e109b2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java
@@ -0,0 +1,56 @@
+package org.dromara.common.core.utils.sql;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+
+/**
+ * sql鎿嶄綔宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class SqlUtil {
+
+    /**
+     * 瀹氫箟甯哥敤鐨� sql鍏抽敭瀛�
+     */
+    public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
+
+    /**
+     * 浠呮敮鎸佸瓧姣嶃�佹暟瀛椼�佷笅鍒掔嚎銆佺┖鏍笺�侀�楀彿銆佸皬鏁扮偣锛堟敮鎸佸涓瓧娈垫帓搴忥級
+     */
+    public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+    /**
+     * 妫�鏌ュ瓧绗︼紝闃叉娉ㄥ叆缁曡繃
+     */
+    public static String escapeOrderBySql(String value) {
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
+            throw new IllegalArgumentException("鍙傛暟涓嶇鍚堣鑼冿紝涓嶈兘杩涜鏌ヨ");
+        }
+        return value;
+    }
+
+    /**
+     * 楠岃瘉 order by 璇硶鏄惁绗﹀悎瑙勮寖
+     */
+    public static boolean isValidOrderBySql(String value) {
+        return value.matches(SQL_PATTERN);
+    }
+
+    /**
+     * SQL鍏抽敭瀛楁鏌�
+     */
+    public static void filterKeyword(String value) {
+        if (StringUtils.isEmpty(value)) {
+            return;
+        }
+        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
+        for (String sqlKeyword : sqlKeywords) {
+            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) {
+                throw new IllegalArgumentException("鍙傛暟瀛樺湪SQL娉ㄥ叆椋庨櫓");
+            }
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java
new file mode 100644
index 0000000..0275899
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java
@@ -0,0 +1,9 @@
+package org.dromara.common.core.validate;
+
+/**
+ * 鏍¢獙鍒嗙粍 add
+ *
+ * @author Lion Li
+ */
+public interface AddGroup {
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java
new file mode 100644
index 0000000..77c5040
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java
@@ -0,0 +1,9 @@
+package org.dromara.common.core.validate;
+
+/**
+ * 鏍¢獙鍒嗙粍 edit
+ *
+ * @author Lion Li
+ */
+public interface EditGroup {
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java
new file mode 100644
index 0000000..02a0ac2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java
@@ -0,0 +1,9 @@
+package org.dromara.common.core.validate;
+
+/**
+ * 鏍¢獙鍒嗙粍 query
+ *
+ * @author Lion Li
+ */
+public interface QueryGroup {
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java
new file mode 100644
index 0000000..eed495f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java
@@ -0,0 +1,26 @@
+package org.dromara.common.core.xss;
+
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鑷畾涔墄ss鏍¢獙娉ㄨВ
+ *
+ * @author Lion Li
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
+@Constraint(validatedBy = {XssValidator.class})
+public @interface Xss {
+
+    String message() default "涓嶅厑璁镐换浣曡剼鏈繍琛�";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java
new file mode 100644
index 0000000..9c32563
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java
@@ -0,0 +1,21 @@
+package org.dromara.common.core.xss;
+
+import cn.hutool.core.util.ReUtil;
+import cn.hutool.http.HtmlUtil;
+
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+/**
+ * 鑷畾涔墄ss鏍¢獙娉ㄨВ瀹炵幇
+ *
+ * @author Lion Li
+ */
+public class XssValidator implements ConstraintValidator<Xss, String> {
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
+        return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..3395e73
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,6 @@
+org.dromara.common.core.config.ApplicationConfig
+org.dromara.common.core.config.AsyncConfig
+org.dromara.common.core.config.RuoYiConfig
+org.dromara.common.core.config.ThreadPoolConfig
+org.dromara.common.core.config.ValidatorConfig
+org.dromara.common.core.utils.SpringUtils
diff --git a/eims/ruoyi-common/ruoyi-common-doc/pom.xml b/eims/ruoyi-common/ruoyi-common-doc/pom.xml
new file mode 100644
index 0000000..c6199a1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-doc/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-doc</artifactId>
+
+    <description>
+        ruoyi-common-doc 绯荤粺鎺ュ彛
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.therapi</groupId>
+            <artifactId>therapi-runtime-javadoc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-kotlin</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
new file mode 100644
index 0000000..069ef9a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
@@ -0,0 +1,126 @@
+package org.dromara.common.doc.config;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.Paths;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.doc.config.properties.SpringDocProperties;
+import org.dromara.common.doc.handler.OpenApiHandler;
+import org.springdoc.core.configuration.SpringDocConfiguration;
+import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
+import org.springdoc.core.customizers.OpenApiCustomizer;
+import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
+import org.springdoc.core.properties.SpringDocConfigProperties;
+import org.springdoc.core.providers.JavadocProvider;
+import org.springdoc.core.service.OpenAPIService;
+import org.springdoc.core.service.SecurityService;
+import org.springdoc.core.utils.PropertyResolverUtils;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Swagger 鏂囨。閰嶇疆
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@AutoConfiguration(before = SpringDocConfiguration.class)
+@EnableConfigurationProperties(SpringDocProperties.class)
+@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
+public class SpringDocConfig {
+
+    private final ServerProperties serverProperties;
+
+    @Bean
+    @ConditionalOnMissingBean(OpenAPI.class)
+    public OpenAPI openApi(SpringDocProperties properties) {
+        OpenAPI openApi = new OpenAPI();
+        // 鏂囨。鍩烘湰淇℃伅
+        SpringDocProperties.InfoProperties infoProperties = properties.getInfo();
+        Info info = convertInfo(infoProperties);
+        openApi.info(info);
+        // 鎵╁睍鏂囨。淇℃伅
+        openApi.externalDocs(properties.getExternalDocs());
+        openApi.tags(properties.getTags());
+        openApi.paths(properties.getPaths());
+        openApi.components(properties.getComponents());
+        Set<String> keySet = properties.getComponents().getSecuritySchemes().keySet();
+        List<SecurityRequirement> list = new ArrayList<>();
+        SecurityRequirement securityRequirement = new SecurityRequirement();
+        keySet.forEach(securityRequirement::addList);
+        list.add(securityRequirement);
+        openApi.security(list);
+
+        return openApi;
+    }
+
+    private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
+        Info info = new Info();
+        info.setTitle(infoProperties.getTitle());
+        info.setDescription(infoProperties.getDescription());
+        info.setContact(infoProperties.getContact());
+        info.setLicense(infoProperties.getLicense());
+        info.setVersion(infoProperties.getVersion());
+        return info;
+    }
+
+    /**
+     * 鑷畾涔� openapi 澶勭悊鍣�
+     */
+    @Bean
+    public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI,
+                                         SecurityService securityParser,
+                                         SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
+                                         Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
+                                         Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
+        return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
+    }
+
+    /**
+     * 瀵瑰凡缁忕敓鎴愬ソ鐨� OpenApi 杩涜鑷畾涔夋搷浣�
+     */
+    @Bean
+    public OpenApiCustomizer openApiCustomizer() {
+        String contextPath = serverProperties.getServlet().getContextPath();
+        String finalContextPath;
+        if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) {
+            finalContextPath = "";
+        } else {
+            finalContextPath = contextPath;
+        }
+        // 瀵规墍鏈夎矾寰勫鍔犲墠缃笂涓嬫枃璺緞
+        return openApi -> {
+            Paths oldPaths = openApi.getPaths();
+            if (oldPaths instanceof PlusPaths) {
+                return;
+            }
+            PlusPaths newPaths = new PlusPaths();
+            oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v));
+            openApi.setPaths(newPaths);
+        };
+    }
+
+    /**
+     * 鍗曠嫭浣跨敤涓�涓被渚夸簬鍒ゆ柇 瑙e喅springdoc璺緞鎷兼帴閲嶅闂
+     *
+     * @author Lion Li
+     */
+    static class PlusPaths extends Paths {
+
+        public PlusPaths() {
+            super();
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
new file mode 100644
index 0000000..eae3b4c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
@@ -0,0 +1,94 @@
+package org.dromara.common.doc.config.properties;
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.Paths;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.License;
+import io.swagger.v3.oas.models.tags.Tag;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+
+import java.util.List;
+
+/**
+ * swagger 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "springdoc")
+public class SpringDocProperties {
+
+    /**
+     * 鏂囨。鍩烘湰淇℃伅
+     */
+    @NestedConfigurationProperty
+    private InfoProperties info = new InfoProperties();
+
+    /**
+     * 鎵╁睍鏂囨。鍦板潃
+     */
+    @NestedConfigurationProperty
+    private ExternalDocumentation externalDocs;
+
+    /**
+     * 鏍囩
+     */
+    private List<Tag> tags = null;
+
+    /**
+     * 璺緞
+     */
+    @NestedConfigurationProperty
+    private Paths paths = null;
+
+    /**
+     * 缁勪欢
+     */
+    @NestedConfigurationProperty
+    private Components components = null;
+
+    /**
+     * <p>
+     * 鏂囨。鐨勫熀纭�灞炴�т俊鎭�
+     * </p>
+     *
+     * @see io.swagger.v3.oas.models.info.Info
+     *
+     * 涓轰簡 springboot 鑷姩鐢熶骇閰嶇疆鎻愮ず淇℃伅锛屾墍浠ヨ繖閲屽鍒朵竴涓被鍑烘潵
+     */
+    @Data
+    public static class InfoProperties {
+
+        /**
+         * 鏍囬
+         */
+        private String title = null;
+
+        /**
+         * 鎻忚堪
+         */
+        private String description = null;
+
+        /**
+         * 鑱旂郴浜轰俊鎭�
+         */
+        @NestedConfigurationProperty
+        private Contact contact = null;
+
+        /**
+         * 璁稿彲璇�
+         */
+        @NestedConfigurationProperty
+        private License license = null;
+
+        /**
+         * 鐗堟湰
+         */
+        private String version = null;
+
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java
new file mode 100644
index 0000000..56b7369
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java
@@ -0,0 +1,253 @@
+package org.dromara.common.doc.handler;
+
+import cn.hutool.core.io.IoUtil;
+import io.swagger.v3.core.jackson.TypeNameResolver;
+import io.swagger.v3.core.util.AnnotationsUtils;
+import io.swagger.v3.oas.annotations.tags.Tags;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.Paths;
+import io.swagger.v3.oas.models.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
+import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
+import org.springdoc.core.properties.SpringDocConfigProperties;
+import org.springdoc.core.providers.JavadocProvider;
+import org.springdoc.core.service.OpenAPIService;
+import org.springdoc.core.service.SecurityService;
+import org.springdoc.core.utils.PropertyResolverUtils;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.method.HandlerMethod;
+
+import java.io.StringReader;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 鑷畾涔� openapi 澶勭悊鍣�
+ * 瀵规簮鐮佸姛鑳借繘琛屼慨鏀� 澧炲己浣跨敤
+ */
+@Slf4j
+@SuppressWarnings("all")
+public class OpenApiHandler extends OpenAPIService {
+
+    /**
+     * The Basic error controller.
+     */
+    private static Class<?> basicErrorController;
+
+    /**
+     * The Security parser.
+     */
+    private final SecurityService securityParser;
+
+    /**
+     * The Mappings map.
+     */
+    private final Map<String, Object> mappingsMap = new HashMap<>();
+
+    /**
+     * The Springdoc tags.
+     */
+    private final Map<HandlerMethod, Tag> springdocTags = new HashMap<>();
+
+    /**
+     * The Open api builder customisers.
+     */
+    private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers;
+
+    /**
+     * The server base URL customisers.
+     */
+    private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers;
+
+    /**
+     * The Spring doc config properties.
+     */
+    private final SpringDocConfigProperties springDocConfigProperties;
+
+    /**
+     * The Cached open api map.
+     */
+    private final Map<String, OpenAPI> cachedOpenAPI = new HashMap<>();
+
+    /**
+     * The Property resolver utils.
+     */
+    private final PropertyResolverUtils propertyResolverUtils;
+
+    /**
+     * The javadoc provider.
+     */
+    private final Optional<JavadocProvider> javadocProvider;
+
+    /**
+     * The Context.
+     */
+    private ApplicationContext context;
+
+    /**
+     * The Open api.
+     */
+    private OpenAPI openAPI;
+
+    /**
+     * The Is servers present.
+     */
+    private boolean isServersPresent;
+
+    /**
+     * The Server base url.
+     */
+    private String serverBaseUrl;
+
+    /**
+     * Instantiates a new Open api builder.
+     *
+     * @param openAPI                   the open api
+     * @param securityParser            the security parser
+     * @param springDocConfigProperties the spring doc config properties
+     * @param propertyResolverUtils     the property resolver utils
+     * @param openApiBuilderCustomizers the open api builder customisers
+     * @param serverBaseUrlCustomizers  the server base url customizers
+     * @param javadocProvider           the javadoc provider
+     */
+    public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser,
+                          SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
+                          Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers,
+                          Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers,
+                          Optional<JavadocProvider> javadocProvider) {
+        super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider);
+        if (openAPI.isPresent()) {
+            this.openAPI = openAPI.get();
+            if (this.openAPI.getComponents() == null)
+                this.openAPI.setComponents(new Components());
+            if (this.openAPI.getPaths() == null)
+                this.openAPI.setPaths(new Paths());
+            if (!CollectionUtils.isEmpty(this.openAPI.getServers()))
+                this.isServersPresent = true;
+        }
+        this.propertyResolverUtils = propertyResolverUtils;
+        this.securityParser = securityParser;
+        this.springDocConfigProperties = springDocConfigProperties;
+        this.openApiBuilderCustomisers = openApiBuilderCustomizers;
+        this.serverBaseUrlCustomizers = serverBaseUrlCustomizers;
+        this.javadocProvider = javadocProvider;
+        if (springDocConfigProperties.isUseFqn())
+            TypeNameResolver.std.setUseFqn(true);
+    }
+
+    @Override
+    public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) {
+
+        Set<Tag> tags = new HashSet<>();
+        Set<String> tagsStr = new HashSet<>();
+
+        buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale);
+        buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale);
+
+        if (!CollectionUtils.isEmpty(tagsStr))
+            tagsStr = tagsStr.stream()
+                .map(str -> propertyResolverUtils.resolve(str, locale))
+                .collect(Collectors.toSet());
+
+        if (springdocTags.containsKey(handlerMethod)) {
+            io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod);
+            tagsStr.add(tag.getName());
+            if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) {
+                openAPI.addTagsItem(tag);
+            }
+        }
+
+        if (!CollectionUtils.isEmpty(tagsStr)) {
+            if (CollectionUtils.isEmpty(operation.getTags()))
+                operation.setTags(new ArrayList<>(tagsStr));
+            else {
+                Set<String> operationTagsSet = new HashSet<>(operation.getTags());
+                operationTagsSet.addAll(tagsStr);
+                operation.getTags().clear();
+                operation.getTags().addAll(operationTagsSet);
+            }
+        }
+
+        if (isAutoTagClasses(operation)) {
+
+
+            if (javadocProvider.isPresent()) {
+                String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType());
+                if (StringUtils.isNotBlank(description)) {
+                    io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag();
+
+                    // 鑷畾涔夐儴鍒� 淇敼浣跨敤java娉ㄩ噴褰搕ag鍚�
+                    List<String> list = IoUtil.readLines(new StringReader(description), new ArrayList<>());
+                    // tag.setName(tagAutoName);
+                    tag.setName(list.get(0));
+                    operation.addTagsItem(list.get(0));
+
+                    tag.setDescription(description);
+                    if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) {
+                        openAPI.addTagsItem(tag);
+                    }
+                }
+            } else {
+                String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName());
+                operation.addTagsItem(tagAutoName);
+            }
+        }
+
+        if (!CollectionUtils.isEmpty(tags)) {
+            // Existing tags
+            List<io.swagger.v3.oas.models.tags.Tag> openApiTags = openAPI.getTags();
+            if (!CollectionUtils.isEmpty(openApiTags))
+                tags.addAll(openApiTags);
+            openAPI.setTags(new ArrayList<>(tags));
+        }
+
+        // Handle SecurityRequirement at operation level
+        io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser
+            .getSecurityRequirements(handlerMethod);
+        if (securityRequirements != null) {
+            if (securityRequirements.length == 0)
+                operation.setSecurity(Collections.emptyList());
+            else
+                securityParser.buildSecurityRequirement(securityRequirements, operation);
+        }
+
+        return operation;
+    }
+
+    private void buildTagsFromMethod(Method method, Set<io.swagger.v3.oas.models.tags.Tag> tags, Set<String> tagsStr, Locale locale) {
+        // method tags
+        Set<Tags> tagsSet = AnnotatedElementUtils
+            .findAllMergedAnnotations(method, Tags.class);
+        Set<io.swagger.v3.oas.annotations.tags.Tag> methodTags = tagsSet.stream()
+            .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet());
+        methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class));
+        if (!CollectionUtils.isEmpty(methodTags)) {
+            tagsStr.addAll(StreamUtils.toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale)));
+            List<io.swagger.v3.oas.annotations.tags.Tag> allTags = new ArrayList<>(methodTags);
+            addTags(allTags, tags, locale);
+        }
+    }
+
+    private void addTags(List<io.swagger.v3.oas.annotations.tags.Tag> sourceTags, Set<io.swagger.v3.oas.models.tags.Tag> tags, Locale locale) {
+        Optional<Set<io.swagger.v3.oas.models.tags.Tag>> optionalTagSet = AnnotationsUtils
+            .getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true);
+        optionalTagSet.ifPresent(tagsSet -> {
+            tagsSet.forEach(tag -> {
+                tag.name(propertyResolverUtils.resolve(tag.getName(), locale));
+                tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale));
+                if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName())))
+                    tags.add(tag);
+            });
+        });
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..fe11e76
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.doc.config.SpringDocConfig
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/pom.xml b/eims/ruoyi-common/ruoyi-common-encrypt/pom.xml
new file mode 100644
index 0000000..ed4910e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-encrypt</artifactId>
+
+    <description>
+        ruoyi-common-encrypt 鏁版嵁鍔犺В瀵嗘ā鍧�
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15to18</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-crypto</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+            <optional>true</optional>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis-spring</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java
new file mode 100644
index 0000000..7f52de8
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java
@@ -0,0 +1,20 @@
+package org.dromara.common.encrypt.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 寮哄埗鍔犲瘑娉ㄨВ
+ *
+ * @author Michelle.Chung
+ */
+@Documented
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ApiEncrypt {
+
+    /**
+     * 鍝嶅簲鍔犲瘑蹇界暐锛岄粯璁や笉鍔犲瘑锛屼负 true 鏃跺姞瀵�
+     */
+    boolean response() default false;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java
new file mode 100644
index 0000000..d357d72
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java
@@ -0,0 +1,44 @@
+package org.dromara.common.encrypt.annotation;
+
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+
+import java.lang.annotation.*;
+
+/**
+ * 瀛楁鍔犲瘑娉ㄨВ
+ *
+ * @author 鑰侀┈
+ */
+@Documented
+@Inherited
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EncryptField {
+
+    /**
+     * 鍔犲瘑绠楁硶
+     */
+    AlgorithmType algorithm() default AlgorithmType.DEFAULT;
+
+    /**
+     * 绉橀挜銆侫ES銆丼M4闇�瑕�
+     */
+    String password() default "";
+
+    /**
+     * 鍏挜銆俁SA銆丼M2闇�瑕�
+     */
+    String publicKey() default "";
+
+    /**
+     * 绉侀挜銆俁SA銆丼M2闇�瑕�
+     */
+    String privateKey() default "";
+
+    /**
+     * 缂栫爜鏂瑰紡銆傚鍔犲瘑绠楁硶涓築ASE64鐨勪笉璧蜂綔鐢�
+     */
+    EncodeType encode() default EncodeType.DEFAULT;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
new file mode 100644
index 0000000..098f6bc
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
@@ -0,0 +1,32 @@
+package org.dromara.common.encrypt.config;
+
+import jakarta.servlet.DispatcherType;
+import org.dromara.common.encrypt.filter.CryptoFilter;
+import org.dromara.common.encrypt.properties.ApiDecryptProperties;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * api 瑙e瘑鑷姩閰嶇疆
+ *
+ * @author wdhcr
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(ApiDecryptProperties.class)
+@ConditionalOnProperty(value = "api-decrypt.enabled", havingValue = "true")
+public class ApiDecryptAutoConfiguration {
+
+    @Bean
+    public FilterRegistrationBean<CryptoFilter> cryptoFilterRegistration(ApiDecryptProperties properties) {
+        FilterRegistrationBean<CryptoFilter> registration = new FilterRegistrationBean<>();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new CryptoFilter(properties));
+        registration.addUrlPatterns("/*");
+        registration.setName("cryptoFilter");
+        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+        return registration;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java
new file mode 100644
index 0000000..fbc4e52
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java
@@ -0,0 +1,49 @@
+package org.dromara.common.encrypt.config;
+
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.encrypt.core.EncryptorManager;
+import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor;
+import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor;
+import org.dromara.common.encrypt.properties.EncryptorProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * 鍔犺В瀵嗛厤缃�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@AutoConfiguration(after = MybatisPlusAutoConfiguration.class)
+@EnableConfigurationProperties(EncryptorProperties.class)
+@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true")
+@Slf4j
+public class EncryptorAutoConfiguration {
+
+    @Autowired
+    private EncryptorProperties properties;
+
+    @Bean
+    public EncryptorManager encryptorManager(MybatisPlusProperties mybatisPlusProperties) {
+        return new EncryptorManager(mybatisPlusProperties.getTypeAliasesPackage());
+    }
+
+    @Bean
+    public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) {
+        return new MybatisEncryptInterceptor(encryptorManager, properties);
+    }
+
+    @Bean
+    public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) {
+        return new MybatisDecryptInterceptor(encryptorManager, properties);
+    }
+
+}
+
+
+
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java
new file mode 100644
index 0000000..2f02eaf
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java
@@ -0,0 +1,41 @@
+package org.dromara.common.encrypt.core;
+
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import lombok.Data;
+
+/**
+ * 鍔犲瘑涓婁笅鏂� 鐢ㄤ簬encryptor浼犻�掑繀瑕佺殑鍙傛暟銆�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Data
+public class EncryptContext {
+
+    /**
+     * 榛樿绠楁硶
+     */
+    private AlgorithmType algorithm;
+
+    /**
+     * 瀹夊叏绉橀挜
+     */
+    private String password;
+
+    /**
+     * 鍏挜
+     */
+    private String publicKey;
+
+    /**
+     * 绉侀挜
+     */
+    private String privateKey;
+
+    /**
+     * 缂栫爜鏂瑰紡锛宐ase64/hex
+     */
+    private EncodeType encode;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
new file mode 100644
index 0000000..a6d3cf9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java
@@ -0,0 +1,158 @@
+package org.dromara.common.encrypt.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.ReflectUtil;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.io.Resources;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.EncryptField;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.ClassMetadata;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * 鍔犲瘑绠$悊绫�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Slf4j
+@NoArgsConstructor
+public class EncryptorManager {
+
+    /**
+     * 缂撳瓨鍔犲瘑鍣�
+     */
+    Map<EncryptContext, IEncryptor> encryptorMap = new ConcurrentHashMap<>();
+
+    /**
+     * 绫诲姞瀵嗗瓧娈电紦瀛�
+     */
+    Map<Class<?>, Set<Field>> fieldCache = new ConcurrentHashMap<>();
+
+    /**
+     * 鏋勯�犳柟娉曚紶鍏ョ被鍔犲瘑瀛楁缂撳瓨
+     *
+     * @param typeAliasesPackage 瀹炰綋绫诲寘
+     */
+    public EncryptorManager(String typeAliasesPackage) {
+        scanEncryptClasses(typeAliasesPackage);
+    }
+
+
+    /**
+     * 鑾峰彇绫诲姞瀵嗗瓧娈电紦瀛�
+     */
+    public Set<Field> getFieldCache(Class<?> sourceClazz) {
+        if (ObjectUtil.isNotNull(fieldCache)) {
+            return fieldCache.get(sourceClazz);
+        }
+        return null;
+    }
+
+    /**
+     * 娉ㄥ唽鍔犲瘑鎵ц鑰呭埌缂撳瓨
+     *
+     * @param encryptContext 鍔犲瘑鎵ц鑰呴渶瑕佺殑鐩稿叧閰嶇疆鍙傛暟
+     */
+    public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) {
+        if (encryptorMap.containsKey(encryptContext)) {
+            return encryptorMap.get(encryptContext);
+        }
+        IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext);
+        encryptorMap.put(encryptContext, encryptor);
+        return encryptor;
+    }
+
+    /**
+     * 绉婚櫎缂撳瓨涓殑鍔犲瘑鎵ц鑰�
+     *
+     * @param encryptContext 鍔犲瘑鎵ц鑰呴渶瑕佺殑鐩稿叧閰嶇疆鍙傛暟
+     */
+    public void removeEncryptor(EncryptContext encryptContext) {
+        this.encryptorMap.remove(encryptContext);
+    }
+
+    /**
+     * 鏍规嵁閰嶇疆杩涜鍔犲瘑銆備細杩涜鏈湴缂撳瓨瀵瑰簲鐨勭畻娉曞拰瀵瑰簲鐨勭閽ヤ俊鎭��
+     *
+     * @param value          寰呭姞瀵嗙殑鍊�
+     * @param encryptContext 鍔犲瘑鐩稿叧鐨勯厤缃俊鎭�
+     */
+    public String encrypt(String value, EncryptContext encryptContext) {
+        IEncryptor encryptor = this.registAndGetEncryptor(encryptContext);
+        return encryptor.encrypt(value, encryptContext.getEncode());
+    }
+
+    /**
+     * 鏍规嵁閰嶇疆杩涜瑙e瘑
+     *
+     * @param value          寰呰В瀵嗙殑鍊�
+     * @param encryptContext 鍔犲瘑鐩稿叧鐨勯厤缃俊鎭�
+     */
+    public String decrypt(String value, EncryptContext encryptContext) {
+        IEncryptor encryptor = this.registAndGetEncryptor(encryptContext);
+        return encryptor.decrypt(value);
+    }
+
+    /**
+     * 閫氳繃 typeAliasesPackage 璁剧疆鐨勬壂鎻忓寘 鎵弿缂撳瓨瀹炰綋
+     */
+    private void scanEncryptClasses(String typeAliasesPackage) {
+        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
+        String[] packagePatternArray = StringUtils.splitPreserveAllTokens(typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+        String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
+        try {
+            for (String packagePattern : packagePatternArray) {
+                String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
+                Resource[] resources = resolver.getResources(classpath + path + "/*.class");
+                for (Resource resource : resources) {
+                    ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
+                    Class<?> clazz = Resources.classForName(classMetadata.getClassName());
+                    Set<Field> encryptFieldSet = getEncryptFieldSetFromClazz(clazz);
+                    if (CollUtil.isNotEmpty(encryptFieldSet)) {
+                        fieldCache.put(clazz, encryptFieldSet);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("鍒濆鍖栨暟鎹畨鍏ㄧ紦瀛樻椂鍑洪敊:{}", e.getMessage());
+        }
+    }
+
+    /**
+     * 鑾峰緱涓�涓被鐨勫姞瀵嗗瓧娈甸泦鍚�
+     */
+    private Set<Field> getEncryptFieldSetFromClazz(Class<?> clazz) {
+        Set<Field> fieldSet = new HashSet<>();
+        // 鍒ゆ柇clazz濡傛灉鏄帴鍙�,鍐呴儴绫�,鍖垮悕绫诲氨鐩存帴杩斿洖
+        if (clazz.isInterface() || clazz.isMemberClass() || clazz.isAnonymousClass()) {
+            return fieldSet;
+        }
+        while (clazz != null) {
+            Field[] fields = clazz.getDeclaredFields();
+            fieldSet.addAll(Arrays.asList(fields));
+            clazz = clazz.getSuperclass();
+        }
+        fieldSet = fieldSet.stream().filter(field ->
+                field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class)
+            .collect(Collectors.toSet());
+        for (Field field : fieldSet) {
+            field.setAccessible(true);
+        }
+        return fieldSet;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java
new file mode 100644
index 0000000..dbc4420
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java
@@ -0,0 +1,35 @@
+package org.dromara.common.encrypt.core;
+
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+
+/**
+ * 鍔犺В鑰�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public interface IEncryptor {
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    AlgorithmType algorithm();
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     * @return 鍔犲瘑鍚庣殑瀛楃涓�
+     */
+    String encrypt(String value, EncodeType encodeType);
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @return 瑙e瘑鍚庣殑瀛楃涓�
+     */
+    String decrypt(String value);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java
new file mode 100644
index 0000000..858d229
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java
@@ -0,0 +1,18 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.core.IEncryptor;
+
+/**
+ * 鎵�鏈夊姞瀵嗘墽琛岃�呯殑鍩虹被
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public abstract class AbstractEncryptor implements IEncryptor {
+
+    public AbstractEncryptor(EncryptContext context) {
+        // 鐢ㄦ埛閰嶇疆鏍¢獙涓庨厤缃敞鍏�
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java
new file mode 100644
index 0000000..e4dc597
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java
@@ -0,0 +1,55 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+/**
+ * AES绠楁硶瀹炵幇
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public class AesEncryptor extends AbstractEncryptor {
+
+    private final EncryptContext context;
+
+    public AesEncryptor(EncryptContext context) {
+        super(context);
+        this.context = context;
+    }
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    @Override
+    public AlgorithmType algorithm() {
+        return AlgorithmType.AES;
+    }
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     */
+    @Override
+    public String encrypt(String value, EncodeType encodeType) {
+        if (encodeType == EncodeType.HEX) {
+            return EncryptUtils.encryptByAesHex(value, context.getPassword());
+        } else {
+            return EncryptUtils.encryptByAes(value, context.getPassword());
+        }
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     */
+    @Override
+    public String decrypt(String value) {
+        return EncryptUtils.decryptByAes(value, context.getPassword());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java
new file mode 100644
index 0000000..0028548
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java
@@ -0,0 +1,48 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+/**
+ * Base64绠楁硶瀹炵幇
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public class Base64Encryptor extends AbstractEncryptor {
+
+    public Base64Encryptor(EncryptContext context) {
+        super(context);
+    }
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    @Override
+    public AlgorithmType algorithm() {
+        return AlgorithmType.BASE64;
+    }
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     */
+    @Override
+    public String encrypt(String value, EncodeType encodeType) {
+        return EncryptUtils.encryptByBase64(value);
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     */
+    @Override
+    public String decrypt(String value) {
+        return EncryptUtils.decryptByBase64(value);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java
new file mode 100644
index 0000000..5f03a4b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java
@@ -0,0 +1,62 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+
+/**
+ * RSA绠楁硶瀹炵幇
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public class RsaEncryptor extends AbstractEncryptor {
+
+    private final EncryptContext context;
+
+    public RsaEncryptor(EncryptContext context) {
+        super(context);
+        String privateKey = context.getPrivateKey();
+        String publicKey = context.getPublicKey();
+        if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
+            throw new IllegalArgumentException("RSA鍏閽ュ潎闇�瑕佹彁渚涳紝鍏挜鍔犲瘑锛岀閽ヨВ瀵嗐��");
+        }
+        this.context = context;
+    }
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    @Override
+    public AlgorithmType algorithm() {
+        return AlgorithmType.RSA;
+    }
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     */
+    @Override
+    public String encrypt(String value, EncodeType encodeType) {
+        if (encodeType == EncodeType.HEX) {
+            return EncryptUtils.encryptByRsaHex(value, context.getPublicKey());
+        } else {
+            return EncryptUtils.encryptByRsa(value, context.getPublicKey());
+        }
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     */
+    @Override
+    public String decrypt(String value) {
+        return EncryptUtils.decryptByRsa(value, context.getPrivateKey());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java
new file mode 100644
index 0000000..aec5d82
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java
@@ -0,0 +1,61 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+/**
+ * sm2绠楁硶瀹炵幇
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public class Sm2Encryptor extends AbstractEncryptor {
+
+    private final EncryptContext context;
+
+    public Sm2Encryptor(EncryptContext context) {
+        super(context);
+        String privateKey = context.getPrivateKey();
+        String publicKey = context.getPublicKey();
+        if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
+            throw new IllegalArgumentException("SM2鍏閽ュ潎闇�瑕佹彁渚涳紝鍏挜鍔犲瘑锛岀閽ヨВ瀵嗐��");
+        }
+        this.context = context;
+    }
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    @Override
+    public AlgorithmType algorithm() {
+        return AlgorithmType.SM2;
+    }
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     */
+    @Override
+    public String encrypt(String value, EncodeType encodeType) {
+        if (encodeType == EncodeType.HEX) {
+            return EncryptUtils.encryptBySm2Hex(value, context.getPublicKey());
+        } else {
+            return EncryptUtils.encryptBySm2(value, context.getPublicKey());
+        }
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     */
+    @Override
+    public String decrypt(String value) {
+        return EncryptUtils.decryptBySm2(value, context.getPrivateKey());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java
new file mode 100644
index 0000000..adaf674
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java
@@ -0,0 +1,55 @@
+package org.dromara.common.encrypt.core.encryptor;
+
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+/**
+ * sm4绠楁硶瀹炵幇
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public class Sm4Encryptor extends AbstractEncryptor {
+
+    private final EncryptContext context;
+
+    public Sm4Encryptor(EncryptContext context) {
+        super(context);
+        this.context = context;
+    }
+
+    /**
+     * 鑾峰緱褰撳墠绠楁硶
+     */
+    @Override
+    public AlgorithmType algorithm() {
+        return AlgorithmType.SM4;
+    }
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     * @param encodeType 鍔犲瘑鍚庣殑缂栫爜鏍煎紡
+     */
+    @Override
+    public String encrypt(String value, EncodeType encodeType) {
+        if (encodeType == EncodeType.HEX) {
+            return EncryptUtils.encryptBySm4Hex(value, context.getPassword());
+        } else {
+            return EncryptUtils.encryptBySm4(value, context.getPassword());
+        }
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param value      寰呭姞瀵嗗瓧绗︿覆
+     */
+    @Override
+    public String decrypt(String value) {
+        return EncryptUtils.decryptBySm4(value, context.getPassword());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java
new file mode 100644
index 0000000..26ee1ee
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java
@@ -0,0 +1,48 @@
+package org.dromara.common.encrypt.enumd;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.encrypt.core.encryptor.*;
+
+/**
+ * 绠楁硶鍚嶇О
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Getter
+@AllArgsConstructor
+public enum AlgorithmType {
+
+    /**
+     * 榛樿璧皔ml閰嶇疆
+     */
+    DEFAULT(null),
+
+    /**
+     * base64
+     */
+    BASE64(Base64Encryptor.class),
+
+    /**
+     * aes
+     */
+    AES(AesEncryptor.class),
+
+    /**
+     * rsa
+     */
+    RSA(RsaEncryptor.class),
+
+    /**
+     * sm2
+     */
+    SM2(Sm2Encryptor.class),
+
+    /**
+     * sm4
+     */
+    SM4(Sm4Encryptor.class);
+
+    private final Class<? extends AbstractEncryptor> clazz;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java
new file mode 100644
index 0000000..f471221
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java
@@ -0,0 +1,26 @@
+package org.dromara.common.encrypt.enumd;
+
+/**
+ * 缂栫爜绫诲瀷
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+public enum EncodeType {
+
+    /**
+     * 榛樿浣跨敤yml閰嶇疆
+     */
+    DEFAULT,
+
+    /**
+     * base64缂栫爜
+     */
+    BASE64,
+
+    /**
+     * 16杩涘埗缂栫爜
+     */
+    HEX;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
new file mode 100644
index 0000000..9835132
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
@@ -0,0 +1,110 @@
+package org.dromara.common.encrypt.filter;
+
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.dromara.common.core.constant.HttpStatus;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.encrypt.properties.ApiDecryptProperties;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.HandlerExecutionChain;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.io.IOException;
+
+
+/**
+ * Crypto 杩囨护鍣�
+ *
+ * @author wdhcr
+ */
+public class CryptoFilter implements Filter {
+    private final ApiDecryptProperties properties;
+
+    public CryptoFilter(ApiDecryptProperties properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletRequest servletRequest = (HttpServletRequest) request;
+        HttpServletResponse servletResponse = (HttpServletResponse) response;
+        // 鑾峰彇鍔犲瘑娉ㄨВ
+        ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest);
+        boolean responseFlag = apiEncrypt != null && apiEncrypt.response();
+        ServletRequest requestWrapper = null;
+        ServletResponse responseWrapper = null;
+        EncryptResponseBodyWrapper responseBodyWrapper = null;
+
+        // 鏄惁涓� put 鎴栬�� post 璇锋眰
+        if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) {
+            // 鏄惁瀛樺湪鍔犲瘑鏍囧ご
+            String headerValue = servletRequest.getHeader(properties.getHeaderFlag());
+            if (StringUtils.isNotBlank(headerValue)) {
+                // 璇锋眰瑙e瘑
+                requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag());
+            } else {
+                // 鏄惁鏈夋敞瑙o紝鏈夊氨鎶ラ敊锛屾病鏈夋斁琛�
+                if (ObjectUtil.isNotNull(apiEncrypt)) {
+                    HandlerExceptionResolver exceptionResolver = SpringUtils.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
+                    exceptionResolver.resolveException(
+                        servletRequest, servletResponse, null,
+                        new ServiceException("娌℃湁璁块棶鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�", HttpStatus.FORBIDDEN));
+                    return;
+                }
+            }
+        }
+
+        // 鍒ゆ柇鏄惁鍝嶅簲鍔犲瘑
+        if (responseFlag) {
+            responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse);
+            responseWrapper = responseBodyWrapper;
+        }
+
+        chain.doFilter(
+            ObjectUtil.defaultIfNull(requestWrapper, request),
+            ObjectUtil.defaultIfNull(responseWrapper, response));
+
+        if (responseFlag) {
+            servletResponse.reset();
+            // 瀵瑰師濮嬪唴瀹瑰姞瀵�
+            String encryptContent = responseBodyWrapper.getEncryptContent(
+                servletResponse, properties.getPublicKey(), properties.getHeaderFlag());
+            // 瀵瑰姞瀵嗗悗鐨勫唴瀹瑰啓鍑�
+            servletResponse.getWriter().write(encryptContent);
+        }
+    }
+
+    /**
+     * 鑾峰彇 ApiEncrypt 娉ㄨВ
+     */
+    private ApiEncrypt getApiEncryptAnnotation(HttpServletRequest servletRequest) {
+        RequestMappingHandlerMapping handlerMapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
+        // 鑾峰彇娉ㄨВ
+        try {
+            HandlerExecutionChain mappingHandler = handlerMapping.getHandler(servletRequest);
+            if (ObjectUtil.isNotNull(mappingHandler)) {
+                Object handler = mappingHandler.getHandler();
+                if (ObjectUtil.isNotNull(handler)) {
+                    // 浠巋andler鑾峰彇娉ㄨВ
+                    if (handler instanceof HandlerMethod handlerMethod) {
+                        return handlerMethod.getMethodAnnotation(ApiEncrypt.class);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return null;
+    }
+
+    @Override
+    public void destroy() {
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java
new file mode 100644
index 0000000..98f4bc7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java
@@ -0,0 +1,94 @@
+package org.dromara.common.encrypt.filter;
+
+import cn.hutool.core.io.IoUtil;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+import org.springframework.http.MediaType;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 瑙e瘑璇锋眰鍙傛暟宸ュ叿绫�
+ *
+ * @author wdhcr
+ */
+public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper {
+
+    private final byte[] body;
+
+    public DecryptRequestBodyWrapper(HttpServletRequest request, String privateKey, String headerFlag) throws IOException {
+        super(request);
+        // 鑾峰彇 AES 瀵嗙爜 閲囩敤 RSA 鍔犲瘑
+        String headerRsa = request.getHeader(headerFlag);
+        String decryptAes = EncryptUtils.decryptByRsa(headerRsa, privateKey);
+        // 瑙e瘑 AES 瀵嗙爜
+        String aesPassword = EncryptUtils.decryptByBase64(decryptAes);
+        request.setCharacterEncoding(Constants.UTF8);
+        byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false);
+        String requestBody = new String(readBytes, StandardCharsets.UTF_8);
+        // 瑙e瘑 body 閲囩敤 AES 鍔犲瘑
+        String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword);
+        body = decryptBody.getBytes(StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public BufferedReader getReader() {
+        return new BufferedReader(new InputStreamReader(getInputStream()));
+    }
+
+
+    @Override
+    public int getContentLength() {
+        return body.length;
+    }
+
+    @Override
+    public long getContentLengthLong() {
+        return body.length;
+    }
+
+    @Override
+    public String getContentType() {
+        return MediaType.APPLICATION_JSON_VALUE;
+    }
+
+
+    @Override
+    public ServletInputStream getInputStream() {
+        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+        return new ServletInputStream() {
+            @Override
+            public int read() {
+                return bais.read();
+            }
+
+            @Override
+            public int available() {
+                return body.length;
+            }
+
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+
+            }
+        };
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java
new file mode 100644
index 0000000..c0af232
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java
@@ -0,0 +1,121 @@
+package org.dromara.common.encrypt.filter;
+
+import cn.hutool.core.util.RandomUtil;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponseWrapper;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 鍔犲瘑鍝嶅簲鍙傛暟鍖呰绫�
+ *
+ * @author Michelle.Chung
+ */
+public class EncryptResponseBodyWrapper extends HttpServletResponseWrapper {
+
+    private final ByteArrayOutputStream byteArrayOutputStream;
+    private final ServletOutputStream servletOutputStream;
+    private final PrintWriter printWriter;
+
+    public EncryptResponseBodyWrapper(HttpServletResponse response) throws IOException {
+        super(response);
+        this.byteArrayOutputStream = new ByteArrayOutputStream();
+        this.servletOutputStream = this.getOutputStream();
+        this.printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));
+    }
+
+    @Override
+    public PrintWriter getWriter() {
+        return printWriter;
+    }
+
+    @Override
+    public void flushBuffer() throws IOException {
+        if (servletOutputStream != null) {
+            servletOutputStream.flush();
+        }
+        if (printWriter != null) {
+            printWriter.flush();
+        }
+    }
+
+    @Override
+    public void reset() {
+        byteArrayOutputStream.reset();
+    }
+
+    public byte[] getResponseData() throws IOException {
+        flushBuffer();
+        return byteArrayOutputStream.toByteArray();
+    }
+
+    public String getContent() throws IOException {
+        flushBuffer();
+        return byteArrayOutputStream.toString();
+    }
+
+    /**
+     * 鑾峰彇鍔犲瘑鍐呭
+     *
+     * @param servletResponse response
+     * @param publicKey       RSA鍏挜 (鐢ㄤ簬鍔犲瘑 AES 绉橀挜)
+     * @param headerFlag      璇锋眰澶存爣蹇�
+     * @return 鍔犲瘑鍐呭
+     * @throws IOException
+     */
+    public String getEncryptContent(HttpServletResponse servletResponse, String publicKey, String headerFlag) throws IOException {
+        // 鐢熸垚绉橀挜
+        String aesPassword = RandomUtil.randomString(32);
+        // 绉橀挜浣跨敤 Base64 缂栫爜
+        String encryptAes = EncryptUtils.encryptByBase64(aesPassword);
+        // Rsa 鍏挜鍔犲瘑 Base64 缂栫爜
+        String encryptPassword = EncryptUtils.encryptByRsa(encryptAes, publicKey);
+
+        // 璁剧疆鍝嶅簲澶�
+        servletResponse.addHeader("Access-Control-Expose-Headers", headerFlag);
+        servletResponse.setHeader(headerFlag, encryptPassword);
+        servletResponse.setHeader("Access-Control-Allow-Origin", "*");
+        servletResponse.setHeader("Access-Control-Allow-Methods", "*");
+        servletResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString());
+
+        // 鑾峰彇鍘熷鍐呭
+        String originalBody = this.getContent();
+        // 瀵瑰唴瀹硅繘琛屽姞瀵�
+        return EncryptUtils.encryptByAes(originalBody, aesPassword);
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() throws IOException {
+        return new ServletOutputStream() {
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setWriteListener(WriteListener writeListener) {
+
+            }
+
+            @Override
+            public void write(int b) throws IOException {
+                byteArrayOutputStream.write(b);
+            }
+
+            @Override
+            public void write(byte[] b) throws IOException {
+                byteArrayOutputStream.write(b);
+            }
+
+            @Override
+            public void write(byte[] b, int off, int len) throws IOException {
+                byteArrayOutputStream.write(b, off, len);
+            }
+        };
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java
new file mode 100644
index 0000000..460aa36
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java
@@ -0,0 +1,120 @@
+package org.dromara.common.encrypt.interceptor;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.resultset.ResultSetHandler;
+import org.apache.ibatis.plugin.*;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.EncryptField;
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.core.EncryptorManager;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.properties.EncryptorProperties;
+
+import java.lang.reflect.Field;
+import java.sql.Statement;
+import java.util.*;
+
+/**
+ * 鍑哄弬瑙e瘑鎷︽埅鍣�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Slf4j
+@Intercepts({@Signature(
+    type = ResultSetHandler.class,
+    method = "handleResultSets",
+    args = {Statement.class})
+})
+@AllArgsConstructor
+public class MybatisDecryptInterceptor implements Interceptor {
+
+    private final EncryptorManager encryptorManager;
+    private final EncryptorProperties defaultProperties;
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        // 鑾峰彇鎵цmysql鎵ц缁撴灉
+        Object result = invocation.proceed();
+        if (result == null) {
+            return null;
+        }
+        decryptHandler(result);
+        return result;
+    }
+
+    /**
+     * 瑙e瘑瀵硅薄
+     *
+     * @param sourceObject 寰呭姞瀵嗗璞�
+     */
+    private void decryptHandler(Object sourceObject) {
+        if (ObjectUtil.isNull(sourceObject)) {
+            return;
+        }
+        if (sourceObject instanceof Map<?, ?> map) {
+            new HashSet<>(map.values()).forEach(this::decryptHandler);
+            return;
+        }
+        if (sourceObject instanceof List<?> list) {
+            if(CollUtil.isEmpty(list)) {
+                return;
+            }
+            // 鍒ゆ柇绗竴涓厓绱犳槸鍚﹀惈鏈夋敞瑙c�傚鏋滄病鏈夌洿鎺ヨ繑鍥烇紝鎻愰珮鏁堢巼
+            Object firstItem = list.get(0);
+            if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
+                return;
+            }
+            list.forEach(this::decryptHandler);
+            return;
+        }
+        // 涓嶅湪缂撳瓨涓殑绫�,灏辨槸娌℃湁鍔犲瘑娉ㄨВ鐨勭被(褰撶劧涔熸湁鍙兘鏄痶ypeAliasesPackage鍐欓敊)
+        Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
+        if(ObjectUtil.isNull(fields)){
+            return;
+        }
+        try {
+            for (Field field : fields) {
+                field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field));
+            }
+        } catch (Exception e) {
+            log.error("澶勭悊瑙e瘑瀛楁鏃跺嚭閿�", e);
+        }
+    }
+
+    /**
+     * 瀛楁鍊艰繘琛屽姞瀵嗐�傞�氳繃瀛楁鐨勬壒娉ㄦ敞鍐屾柊鐨勫姞瀵嗙畻娉�
+     *
+     * @param value 寰呭姞瀵嗙殑鍊�
+     * @param field 寰呭姞瀵嗗瓧娈�
+     * @return 鍔犲瘑鍚庣粨鏋�
+     */
+    private String decryptField(String value, Field field) {
+        if (ObjectUtil.isNull(value)) {
+            return null;
+        }
+        EncryptField encryptField = field.getAnnotation(EncryptField.class);
+        EncryptContext encryptContext = new EncryptContext();
+        encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
+        encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
+        encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
+        encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
+        encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
+        return this.encryptorManager.decrypt(value, encryptContext);
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        return Plugin.wrap(target, this);
+    }
+
+    @Override
+    public void setProperties(Properties properties) {
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java
new file mode 100644
index 0000000..bcc2f4c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java
@@ -0,0 +1,124 @@
+package org.dromara.common.encrypt.interceptor;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.parameter.ParameterHandler;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.EncryptField;
+import org.dromara.common.encrypt.core.EncryptContext;
+import org.dromara.common.encrypt.core.EncryptorManager;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import org.dromara.common.encrypt.properties.EncryptorProperties;
+
+import java.lang.reflect.Field;
+import java.sql.PreparedStatement;
+import java.util.*;
+
+/**
+ * 鍏ュ弬鍔犲瘑鎷︽埅鍣�
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Slf4j
+@Intercepts({@Signature(
+    type = ParameterHandler.class,
+    method = "setParameters",
+    args = {PreparedStatement.class})
+})
+@AllArgsConstructor
+public class MybatisEncryptInterceptor implements Interceptor {
+
+    private final EncryptorManager encryptorManager;
+    private final EncryptorProperties defaultProperties;
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        return invocation;
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        if (target instanceof ParameterHandler parameterHandler) {
+            // 杩涜鍔犲瘑鎿嶄綔
+            Object parameterObject = parameterHandler.getParameterObject();
+            if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) {
+                this.encryptHandler(parameterObject);
+            }
+        }
+        return target;
+    }
+
+    /**
+     * 鍔犲瘑瀵硅薄
+     *
+     * @param sourceObject 寰呭姞瀵嗗璞�
+     */
+    private void encryptHandler(Object sourceObject) {
+        if (ObjectUtil.isNull(sourceObject)) {
+            return;
+        }
+        if (sourceObject instanceof Map<?, ?> map) {
+            new HashSet<>(map.values()).forEach(this::encryptHandler);
+            return;
+        }
+        if (sourceObject instanceof List<?> list) {
+            if(CollUtil.isEmpty(list)) {
+                return;
+            }
+            // 鍒ゆ柇绗竴涓厓绱犳槸鍚﹀惈鏈夋敞瑙c�傚鏋滄病鏈夌洿鎺ヨ繑鍥烇紝鎻愰珮鏁堢巼
+            Object firstItem = list.get(0);
+            if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) {
+                return;
+            }
+            list.forEach(this::encryptHandler);
+            return;
+        }
+        // 涓嶅湪缂撳瓨涓殑绫�,灏辨槸娌℃湁鍔犲瘑娉ㄨВ鐨勭被(褰撶劧涔熸湁鍙兘鏄痶ypeAliasesPackage鍐欓敊)
+        Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
+        if(ObjectUtil.isNull(fields)){
+            return;
+        }
+        try {
+            for (Field field : fields) {
+                field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field));
+            }
+        } catch (Exception e) {
+            log.error("澶勭悊鍔犲瘑瀛楁鏃跺嚭閿�", e);
+        }
+    }
+
+    /**
+     * 瀛楁鍊艰繘琛屽姞瀵嗐�傞�氳繃瀛楁鐨勬壒娉ㄦ敞鍐屾柊鐨勫姞瀵嗙畻娉�
+     *
+     * @param value 寰呭姞瀵嗙殑鍊�
+     * @param field 寰呭姞瀵嗗瓧娈�
+     * @return 鍔犲瘑鍚庣粨鏋�
+     */
+    private String encryptField(String value, Field field) {
+        if (ObjectUtil.isNull(value)) {
+            return null;
+        }
+        EncryptField encryptField = field.getAnnotation(EncryptField.class);
+        EncryptContext encryptContext = new EncryptContext();
+        encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm());
+        encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode());
+        encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password());
+        encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey());
+        encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey());
+        return this.encryptorManager.encrypt(value, encryptContext);
+    }
+
+
+    @Override
+    public void setProperties(Properties properties) {
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java
new file mode 100644
index 0000000..6aadb3e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java
@@ -0,0 +1,34 @@
+package org.dromara.common.encrypt.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * api瑙e瘑灞炴�ч厤缃被
+ * @author wdhcr
+ */
+@Data
+@ConfigurationProperties(prefix = "api-decrypt")
+public class ApiDecryptProperties {
+
+    /**
+     * 鍔犲瘑寮�鍏�
+     */
+    private Boolean enabled;
+
+    /**
+     * 澶撮儴鏍囪瘑
+     */
+    private String headerFlag;
+
+    /**
+     * 鍝嶅簲鍔犲瘑鍏挜
+     */
+    private String publicKey;
+
+    /**
+     * 璇锋眰瑙e瘑绉侀挜
+     */
+    private String privateKey;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java
new file mode 100644
index 0000000..ba445c1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java
@@ -0,0 +1,48 @@
+package org.dromara.common.encrypt.properties;
+
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import org.dromara.common.encrypt.enumd.EncodeType;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 鍔犺В瀵嗗睘鎬ч厤缃被
+ *
+ * @author 鑰侀┈
+ * @version 4.6.0
+ */
+@Data
+@ConfigurationProperties(prefix = "mybatis-encryptor")
+public class EncryptorProperties {
+
+    /**
+     * 杩囨护寮�鍏�
+     */
+    private Boolean enable;
+
+    /**
+     * 榛樿绠楁硶
+     */
+    private AlgorithmType algorithm;
+
+    /**
+     * 瀹夊叏绉橀挜
+     */
+    private String password;
+
+    /**
+     * 鍏挜
+     */
+    private String publicKey;
+
+    /**
+     * 绉侀挜
+     */
+    private String privateKey;
+
+    /**
+     * 缂栫爜鏂瑰紡锛宐ase64/hex
+     */
+    private EncodeType encode;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java
new file mode 100644
index 0000000..8e34843
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java
@@ -0,0 +1,311 @@
+package org.dromara.common.encrypt.utils;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.SmUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import cn.hutool.crypto.asymmetric.SM2;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 瀹夊叏鐩稿叧宸ュ叿绫�
+ *
+ * @author 鑰侀┈
+ */
+public class EncryptUtils {
+    /**
+     * 鍏挜
+     */
+    public static final String PUBLIC_KEY = "publicKey";
+    /**
+     * 绉侀挜
+     */
+    public static final String PRIVATE_KEY = "privateKey";
+
+    /**
+     * Base64鍔犲瘑
+     *
+     * @param data 寰呭姞瀵嗘暟鎹�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆
+     */
+    public static String encryptByBase64(String data) {
+        return Base64.encode(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Base64瑙e瘑
+     *
+     * @param data 寰呰В瀵嗘暟鎹�
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     */
+    public static String decryptByBase64(String data) {
+        return Base64.decodeStr(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * AES鍔犲瘑
+     *
+     * @param data     寰呰В瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
+     */
+    public static String encryptByAes(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("AES闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // aes绠楁硶鐨勭閽ヨ姹傛槸16浣嶃��24浣嶃��32浣�
+        int[] array = {16, 24, 32};
+        if (!ArrayUtil.contains(array, password.length())) {
+            throw new IllegalArgumentException("AES绉橀挜闀垮害瑕佹眰涓�16浣嶃��24浣嶃��32浣�");
+        }
+        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * AES鍔犲瘑
+     *
+     * @param data     寰呰В瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptByAesHex(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("AES闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // aes绠楁硶鐨勭閽ヨ姹傛槸16浣嶃��24浣嶃��32浣�
+        int[] array = {16, 24, 32};
+        if (!ArrayUtil.contains(array, password.length())) {
+            throw new IllegalArgumentException("AES绉橀挜闀垮害瑕佹眰涓�16浣嶃��24浣嶃��32浣�");
+        }
+        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * AES瑙e瘑
+     *
+     * @param data     寰呰В瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     */
+    public static String decryptByAes(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("AES闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // aes绠楁硶鐨勭閽ヨ姹傛槸16浣嶃��24浣嶃��32浣�
+        int[] array = {16, 24, 32};
+        if (!ArrayUtil.contains(array, password.length())) {
+            throw new IllegalArgumentException("AES绉橀挜闀垮害瑕佹眰涓�16浣嶃��24浣嶃��32浣�");
+        }
+        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * sm4鍔犲瘑
+     *
+     * @param data     寰呭姞瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
+     */
+    public static String encryptBySm4(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("SM4闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // sm4绠楁硶鐨勭閽ヨ姹傛槸16浣嶉暱搴�
+        int sm4PasswordLength = 16;
+        if (sm4PasswordLength != password.length()) {
+            throw new IllegalArgumentException("SM4绉橀挜闀垮害瑕佹眰涓�16浣�");
+        }
+        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * sm4鍔犲瘑
+     *
+     * @param data     寰呭姞瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
+     */
+    public static String encryptBySm4Hex(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("SM4闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // sm4绠楁硶鐨勭閽ヨ姹傛槸16浣嶉暱搴�
+        int sm4PasswordLength = 16;
+        if (sm4PasswordLength != password.length()) {
+            throw new IllegalArgumentException("SM4绉橀挜闀垮害瑕佹眰涓�16浣�");
+        }
+        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * sm4瑙e瘑
+     *
+     * @param data     寰呰В瀵嗘暟鎹�
+     * @param password 绉橀挜瀛楃涓�
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     */
+    public static String decryptBySm4(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("SM4闇�瑕佷紶鍏ョ閽ヤ俊鎭�");
+        }
+        // sm4绠楁硶鐨勭閽ヨ姹傛槸16浣嶉暱搴�
+        int sm4PasswordLength = 16;
+        if (sm4PasswordLength != password.length()) {
+            throw new IllegalArgumentException("SM4绉橀挜闀垮害瑕佹眰涓�16浣�");
+        }
+        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * 浜х敓sm2鍔犺В瀵嗛渶瑕佺殑鍏挜鍜岀閽�
+     *
+     * @return 鍏閽ap
+     */
+    public static Map<String, String> generateSm2Key() {
+        Map<String, String> keyMap = new HashMap<>(2);
+        SM2 sm2 = SmUtil.sm2();
+        keyMap.put(PRIVATE_KEY, sm2.getPrivateKeyBase64());
+        keyMap.put(PUBLIC_KEY, sm2.getPublicKeyBase64());
+        return keyMap;
+    }
+
+    /**
+     * sm2鍏挜鍔犲瘑
+     *
+     * @param data      寰呭姞瀵嗘暟鎹�
+     * @param publicKey 鍏挜
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
+     */
+    public static String encryptBySm2(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("SM2闇�瑕佷紶鍏ュ叕閽ヨ繘琛屽姞瀵�");
+        }
+        SM2 sm2 = SmUtil.sm2(null, publicKey);
+        return sm2.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
+     * sm2鍏挜鍔犲瘑
+     *
+     * @param data      寰呭姞瀵嗘暟鎹�
+     * @param publicKey 鍏挜
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptBySm2Hex(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("SM2闇�瑕佷紶鍏ュ叕閽ヨ繘琛屽姞瀵�");
+        }
+        SM2 sm2 = SmUtil.sm2(null, publicKey);
+        return sm2.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
+     * sm2绉侀挜瑙e瘑
+     *
+     * @param data       寰呭姞瀵嗘暟鎹�
+     * @param privateKey 绉侀挜
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     */
+    public static String decryptBySm2(String data, String privateKey) {
+        if (StrUtil.isBlank(privateKey)) {
+            throw new IllegalArgumentException("SM2闇�瑕佷紶鍏ョ閽ヨ繘琛岃В瀵�");
+        }
+        SM2 sm2 = SmUtil.sm2(privateKey, null);
+        return sm2.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * 浜х敓RSA鍔犺В瀵嗛渶瑕佺殑鍏挜鍜岀閽�
+     *
+     * @return 鍏閽ap
+     */
+    public static Map<String, String> generateRsaKey() {
+        Map<String, String> keyMap = new HashMap<>(2);
+        RSA rsa = SecureUtil.rsa();
+        keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64());
+        keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64());
+        return keyMap;
+    }
+
+    /**
+     * rsa鍏挜鍔犲瘑
+     *
+     * @param data      寰呭姞瀵嗘暟鎹�
+     * @param publicKey 鍏挜
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Base64缂栫爜
+     */
+    public static String encryptByRsa(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("RSA闇�瑕佷紶鍏ュ叕閽ヨ繘琛屽姞瀵�");
+        }
+        RSA rsa = SecureUtil.rsa(null, publicKey);
+        return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
+     * rsa鍏挜鍔犲瘑
+     *
+     * @param data      寰呭姞瀵嗘暟鎹�
+     * @param publicKey 鍏挜
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptByRsaHex(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("RSA闇�瑕佷紶鍏ュ叕閽ヨ繘琛屽姞瀵�");
+        }
+        RSA rsa = SecureUtil.rsa(null, publicKey);
+        return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
+     * rsa绉侀挜瑙e瘑
+     *
+     * @param data       寰呭姞瀵嗘暟鎹�
+     * @param privateKey 绉侀挜
+     * @return 瑙e瘑鍚庡瓧绗︿覆
+     */
+    public static String decryptByRsa(String data, String privateKey) {
+        if (StrUtil.isBlank(privateKey)) {
+            throw new IllegalArgumentException("RSA闇�瑕佷紶鍏ョ閽ヨ繘琛岃В瀵�");
+        }
+        RSA rsa = SecureUtil.rsa(privateKey, null);
+        return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * md5鍔犲瘑
+     *
+     * @param data 寰呭姞瀵嗘暟鎹�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptByMd5(String data) {
+        return SecureUtil.md5(data);
+    }
+
+    /**
+     * sha256鍔犲瘑
+     *
+     * @param data 寰呭姞瀵嗘暟鎹�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptBySha256(String data) {
+        return SecureUtil.sha256(data);
+    }
+
+    /**
+     * sm3鍔犲瘑
+     *
+     * @param data 寰呭姞瀵嗘暟鎹�
+     * @return 鍔犲瘑鍚庡瓧绗︿覆, 閲囩敤Hex缂栫爜
+     */
+    public static String encryptBySm3(String data) {
+        return SmUtil.sm3(data);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..132cf29
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,3 @@
+org.dromara.common.encrypt.config.EncryptorAutoConfiguration
+org.dromara.common.encrypt.config.ApiDecryptAutoConfiguration
+
diff --git a/eims/ruoyi-common/ruoyi-common-excel/pom.xml b/eims/ruoyi-common/ruoyi-common-excel/pom.xml
new file mode 100644
index 0000000..14b9410
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/pom.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-excel</artifactId>
+
+    <description>
+        ruoyi-common-excel
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+        </dependency>
+        <dependency>
+            <artifactId>commons-compress</artifactId>
+            <groupId>org.apache.commons</groupId>
+            <version>1.26.2</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java
new file mode 100644
index 0000000..6b9211b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java
@@ -0,0 +1,29 @@
+package org.dromara.common.excel.annotation;
+
+import org.dromara.common.excel.core.CellMergeStrategy;
+
+import java.lang.annotation.*;
+
+/**
+ * excel 鍒楀崟鍏冩牸鍚堝苟(鍚堝苟鍒楃浉鍚岄」)
+ *
+ * 闇�鎼厤 {@link CellMergeStrategy} 绛栫暐浣跨敤
+ *
+ * @author Lion Li
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface CellMerge {
+
+	/**
+	 * col index
+	 */
+	int index() default -1;
+
+    /**
+     * 鍚堝苟闇�瑕佷緷璧栫殑鍏朵粬瀛楁鍚嶇О
+     */
+    String[] mergeBy() default {};
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java
new file mode 100644
index 0000000..5c51842
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java
@@ -0,0 +1,32 @@
+package org.dromara.common.excel.annotation;
+
+import org.dromara.common.core.utils.StringUtils;
+
+import java.lang.annotation.*;
+
+/**
+ * 瀛楀吀鏍煎紡鍖�
+ *
+ * @author Lion Li
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelDictFormat {
+
+    /**
+     * 濡傛灉鏄瓧鍏哥被鍨嬶紝璇疯缃瓧鍏哥殑type鍊� (濡�: sys_user_sex)
+     */
+    String dictType() default "";
+
+    /**
+     * 璇诲彇鍐呭杞〃杈惧紡 (濡�: 0=鐢�,1=濂�,2=鏈煡)
+     */
+    String readConverterExp() default "";
+
+    /**
+     * 鍒嗛殧绗︼紝璇诲彇瀛楃涓茬粍鍐呭
+     */
+    String separator() default StringUtils.SEPARATOR;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java
new file mode 100644
index 0000000..290379d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java
@@ -0,0 +1,30 @@
+package org.dromara.common.excel.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 鏋氫妇鏍煎紡鍖�
+ *
+ * @author Liang
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelEnumFormat {
+
+    /**
+     * 瀛楀吀鏋氫妇绫诲瀷
+     */
+    Class<? extends Enum<?>> enumClass();
+
+    /**
+     * 瀛楀吀鏋氫妇绫讳腑瀵瑰簲鐨刢ode灞炴�у悕绉帮紝榛樿涓篶ode
+     */
+    String codeField() default "code";
+
+    /**
+     * 瀛楀吀鏋氫妇绫讳腑瀵瑰簲鐨則ext灞炴�у悕绉帮紝榛樿涓簍ext
+     */
+    String textField() default "text";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java
new file mode 100644
index 0000000..07cc4c4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java
@@ -0,0 +1,52 @@
+package org.dromara.common.excel.convert;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+
+/**
+ * 澶ф暟鍊艰浆鎹�
+ * Excel 鏁板�奸暱搴︿綅15浣� 澶т簬15浣嶇殑鏁板�艰浆鎹綅瀛楃涓�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class ExcelBigNumberConvert implements Converter<Long> {
+
+    @Override
+    public Class<Long> supportJavaTypeKey() {
+        return Long.class;
+    }
+
+    @Override
+    public CellDataTypeEnum supportExcelTypeKey() {
+        return CellDataTypeEnum.STRING;
+    }
+
+    @Override
+    public Long convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        return Convert.toLong(cellData.getData());
+    }
+
+    @Override
+    public WriteCellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        if (ObjectUtil.isNotNull(object)) {
+            String str = Convert.toStr(object);
+            if (str.length() > 15) {
+                return new WriteCellData<>(str);
+            }
+        }
+        WriteCellData<Object> cellData = new WriteCellData<>(new BigDecimal(object));
+        cellData.setType(CellDataTypeEnum.NUMBER);
+        return cellData;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java
new file mode 100644
index 0000000..61eeabf
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java
@@ -0,0 +1,73 @@
+package org.dromara.common.excel.convert;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.excel.utils.ExcelUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+
+/**
+ * 瀛楀吀鏍煎紡鍖栬浆鎹㈠鐞�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class ExcelDictConvert implements Converter<Object> {
+
+    @Override
+    public Class<Object> supportJavaTypeKey() {
+        return Object.class;
+    }
+
+    @Override
+    public CellDataTypeEnum supportExcelTypeKey() {
+        return null;
+    }
+
+    @Override
+    public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+        String type = anno.dictType();
+        String label = cellData.getStringValue();
+        String value;
+        if (StringUtils.isBlank(type)) {
+            value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator());
+        } else {
+            value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator());
+        }
+        return Convert.convert(contentProperty.getField().getType(), value);
+    }
+
+    @Override
+    public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        if (ObjectUtil.isNull(object)) {
+            return new WriteCellData<>("");
+        }
+        ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+        String type = anno.dictType();
+        String value = Convert.toStr(object);
+        String label;
+        if (StringUtils.isBlank(type)) {
+            label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator());
+        } else {
+            label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator());
+        }
+        return new WriteCellData<>(label);
+    }
+
+    private ExcelDictFormat getAnnotation(Field field) {
+        return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java
new file mode 100644
index 0000000..b948ea7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java
@@ -0,0 +1,87 @@
+package org.dromara.common.excel.convert;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.excel.annotation.ExcelEnumFormat;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 鏋氫妇鏍煎紡鍖栬浆鎹㈠鐞�
+ *
+ * @author Liang
+ */
+@Slf4j
+public class ExcelEnumConvert implements Converter<Object> {
+
+    @Override
+    public Class<Object> supportJavaTypeKey() {
+        return Object.class;
+    }
+
+    @Override
+    public CellDataTypeEnum supportExcelTypeKey() {
+        return null;
+    }
+
+    @Override
+    public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        cellData.checkEmpty();
+        // Excel涓~鍏ョ殑鏄灇涓句腑鎸囧畾鐨勬弿杩�
+        Object textValue = switch (cellData.getType()) {
+            case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue();
+            case NUMBER -> cellData.getNumberValue();
+            case BOOLEAN -> cellData.getBooleanValue();
+            default -> throw new IllegalArgumentException("鍗曞厓鏍肩被鍨嬪紓甯�!");
+        };
+        // 濡傛灉鏄┖鍊�
+        if (ObjectUtil.isNull(textValue)) {
+            return null;
+        }
+        Map<Object, String> enumCodeToTextMap = beforeConvert(contentProperty);
+        // 浠嶫ava杈撳嚭鑷矱xcel鏄痗ode杞瑃ext
+        // 鍥犳浠嶦xcel杞琂ava搴旇灏唗ext涓巆ode瀵硅皟
+        Map<Object, Object> enumTextToCodeMap = new HashMap<>();
+        enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key));
+        // 搴旇浠巘ext -> code涓煡鎵�
+        Object codeValue = enumTextToCodeMap.get(textValue);
+        return Convert.convert(contentProperty.getField().getType(), codeValue);
+    }
+
+    @Override
+    public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+        if (ObjectUtil.isNull(object)) {
+            return new WriteCellData<>("");
+        }
+        Map<Object, String> enumValueMap = beforeConvert(contentProperty);
+        String value = Convert.toStr(enumValueMap.get(object), "");
+        return new WriteCellData<>(value);
+    }
+
+    private Map<Object, String> beforeConvert(ExcelContentProperty contentProperty) {
+        ExcelEnumFormat anno = getAnnotation(contentProperty.getField());
+        Map<Object, String> enumValueMap = new HashMap<>();
+        Enum<?>[] enumConstants = anno.enumClass().getEnumConstants();
+        for (Enum<?> enumConstant : enumConstants) {
+            Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField());
+            String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField());
+            enumValueMap.put(codeValue, textValue);
+        }
+        return enumValueMap;
+    }
+
+    private ExcelEnumFormat getAnnotation(Field field) {
+        return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
new file mode 100644
index 0000000..7c7721c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
@@ -0,0 +1,157 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.write.handler.WorkbookWriteHandler;
+import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext;
+import com.alibaba.excel.write.merge.AbstractMergeStrategy;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.excel.annotation.CellMerge;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * 鍒楀�奸噸澶嶅悎骞剁瓥鐣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler {
+
+    private final List<CellRangeAddress> cellList;
+    private final boolean hasTitle;
+    private int rowIndex;
+
+    public CellMergeStrategy(List<?> list, boolean hasTitle) {
+        this.hasTitle = hasTitle;
+        // 琛屽悎骞跺紑濮嬩笅鏍�
+        this.rowIndex = hasTitle ? 1 : 0;
+        this.cellList = handle(list, hasTitle);
+    }
+
+    @Override
+    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
+        //鍗曞厓鏍煎啓鍏ヤ簡,閬嶅巻鍚堝苟鍖哄煙,濡傛灉璇ell鍦ㄥ尯鍩熷唴,浣嗛潪棣栬,鍒欐竻绌�
+        final int rowIndex = cell.getRowIndex();
+        if (CollUtil.isNotEmpty(cellList)){
+            for (CellRangeAddress cellAddresses : cellList) {
+                final int firstRow = cellAddresses.getFirstRow();
+                if (cellAddresses.isInRange(cell) && rowIndex != firstRow){
+                    cell.setBlank();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) {
+        //褰撳墠琛ㄦ牸鍐欏畬鍚庯紝缁熶竴鍐欏叆
+        if (CollUtil.isNotEmpty(cellList)){
+            for (CellRangeAddress item : cellList) {
+                context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item);
+            }
+        }
+    }
+
+    @SneakyThrows
+    private List<CellRangeAddress> handle(List<?> list, boolean hasTitle) {
+        List<CellRangeAddress> cellList = new ArrayList<>();
+        if (CollUtil.isEmpty(list)) {
+            return cellList;
+        }
+        Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName()));
+
+        // 鏈夋敞瑙g殑瀛楁
+        List<Field> mergeFields = new ArrayList<>();
+        List<Integer> mergeFieldsIndex = new ArrayList<>();
+        for (int i = 0; i < fields.length; i++) {
+            Field field = fields[i];
+            if (field.isAnnotationPresent(CellMerge.class)) {
+                CellMerge cm = field.getAnnotation(CellMerge.class);
+                mergeFields.add(field);
+                mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index());
+                if (hasTitle) {
+                    ExcelProperty property = field.getAnnotation(ExcelProperty.class);
+                    rowIndex = Math.max(rowIndex, property.value().length);
+                }
+            }
+        }
+
+        Map<Field, RepeatCell> map = new HashMap<>();
+        // 鐢熸垚涓や袱鍚堝苟鍗曞厓鏍�
+        for (int i = 0; i < list.size(); i++) {
+            for (int j = 0; j < mergeFields.size(); j++) {
+                Field field = mergeFields.get(j);
+                Object val = ReflectUtils.invokeGetter(list.get(i), field.getName());
+
+                int colNum = mergeFieldsIndex.get(j);
+                if (!map.containsKey(field)) {
+                    map.put(field, new RepeatCell(val, i));
+                } else {
+                    RepeatCell repeatCell = map.get(field);
+                    Object cellValue = repeatCell.getValue();
+                    if (cellValue == null || "".equals(cellValue)) {
+                        // 绌哄�艰烦杩囦笉鍚堝苟
+                        continue;
+                    }
+
+                    if (!cellValue.equals(val)) {
+                        if ((i - repeatCell.getCurrent() > 1)) {
+                            cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
+                        }
+                        map.put(field, new RepeatCell(val, i));
+                    } else if (i == list.size() - 1) {
+                        if (i > repeatCell.getCurrent() && isMerge(list, i, field)) {
+                            cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
+                        }
+                    } else if (!isMerge(list, i, field)) {
+                        if ((i - repeatCell.getCurrent() > 1)) {
+                            cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
+                        }
+                        map.put(field, new RepeatCell(val, i));
+                    }
+                }
+            }
+        }
+        return cellList;
+    }
+
+    private boolean isMerge(List<?> list, int i, Field field) {
+        boolean isMerge = true;
+        CellMerge cm = field.getAnnotation(CellMerge.class);
+        final String[] mergeBy = cm.mergeBy();
+        if (StrUtil.isAllNotBlank(mergeBy)) {
+            //姣斿褰撳墠list(i)鍜宭ist(i - 1)鐨勫悇涓睘鎬у�间竴涓�姣斿 濡傛灉鍏ㄤ负鐪� 鍒欎负鐪�
+            for (String fieldName : mergeBy) {
+                final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName);
+                final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName);
+                if (!Objects.equals(valPre, valCurrent)) {
+                    //渚濊禆瀛楁濡傛湁浠讳竴涓嶇瓑鍊�,鍒欐爣璁颁负涓嶅彲鍚堝苟
+                    isMerge = false;
+                }
+            }
+        }
+        return isMerge;
+    }
+
+    @Data
+    @AllArgsConstructor
+    static class RepeatCell {
+
+        private Object value;
+
+        private int current;
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java
new file mode 100644
index 0000000..b6fa0b4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java
@@ -0,0 +1,104 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.alibaba.excel.exception.ExcelDataConvertException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Excel 瀵煎叆鐩戝惉
+ *
+ * @author Yjoioooo
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor
+public class DefaultExcelListener<T> extends AnalysisEventListener<T> implements ExcelListener<T> {
+
+    /**
+     * 鏄惁Validator妫�楠岋紝榛樿涓烘槸
+     */
+    private Boolean isValidate = Boolean.TRUE;
+
+    /**
+     * excel 琛ㄥご鏁版嵁
+     */
+    private Map<Integer, String> headMap;
+
+    /**
+     * 瀵煎叆鍥炴墽
+     */
+    private ExcelResult<T> excelResult;
+
+    public DefaultExcelListener(boolean isValidate) {
+        this.excelResult = new DefaultExcelResult<>();
+        this.isValidate = isValidate;
+    }
+
+    /**
+     * 澶勭悊寮傚父
+     *
+     * @param exception ExcelDataConvertException
+     * @param context   Excel 涓婁笅鏂�
+     */
+    @Override
+    public void onException(Exception exception, AnalysisContext context) throws Exception {
+        String errMsg = null;
+        if (exception instanceof ExcelDataConvertException excelDataConvertException) {
+            // 濡傛灉鏄煇涓�涓崟鍏冩牸鐨勮浆鎹㈠紓甯� 鑳借幏鍙栧埌鍏蜂綋琛屽彿
+            Integer rowIndex = excelDataConvertException.getRowIndex();
+            Integer columnIndex = excelDataConvertException.getColumnIndex();
+            errMsg = StrUtil.format("绗瑊}琛�-绗瑊}鍒�-琛ㄥご{}: 瑙f瀽寮傚父<br/>",
+                rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));
+            if (log.isDebugEnabled()) {
+                log.error(errMsg);
+            }
+        }
+        if (exception instanceof ConstraintViolationException constraintViolationException) {
+            Set<ConstraintViolation<?>> constraintViolations = constraintViolationException.getConstraintViolations();
+            String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", ");
+            errMsg = StrUtil.format("绗瑊}琛屾暟鎹牎楠屽紓甯�: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);
+            if (log.isDebugEnabled()) {
+                log.error(errMsg);
+            }
+        }
+        excelResult.getErrorList().add(errMsg);
+        throw new ExcelAnalysisException(errMsg);
+    }
+
+    @Override
+    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
+        this.headMap = headMap;
+        log.debug("瑙f瀽鍒颁竴鏉¤〃澶存暟鎹�: {}", JsonUtils.toJsonString(headMap));
+    }
+
+    @Override
+    public void invoke(T data, AnalysisContext context) {
+        if (isValidate) {
+            ValidatorUtils.validate(data);
+        }
+        excelResult.getList().add(data);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+        log.debug("鎵�鏈夋暟鎹В鏋愬畬鎴愶紒");
+    }
+
+    @Override
+    public ExcelResult<T> getExcelResult() {
+        return excelResult;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java
new file mode 100644
index 0000000..7373e12
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java
@@ -0,0 +1,73 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 榛樿excel杩斿洖瀵硅薄
+ *
+ * @author Yjoioooo
+ * @author Lion Li
+ */
+public class DefaultExcelResult<T> implements ExcelResult<T> {
+
+    /**
+     * 鏁版嵁瀵硅薄list
+     */
+    @Setter
+    private List<T> list;
+
+    /**
+     * 閿欒淇℃伅鍒楄〃
+     */
+    @Setter
+    private List<String> errorList;
+
+    public DefaultExcelResult() {
+        this.list = new ArrayList<>();
+        this.errorList = new ArrayList<>();
+    }
+
+    public DefaultExcelResult(List<T> list, List<String> errorList) {
+        this.list = list;
+        this.errorList = errorList;
+    }
+
+    public DefaultExcelResult(ExcelResult<T> excelResult) {
+        this.list = excelResult.getList();
+        this.errorList = excelResult.getErrorList();
+    }
+
+    @Override
+    public List<T> getList() {
+        return list;
+    }
+
+    @Override
+    public List<String> getErrorList() {
+        return errorList;
+    }
+
+    /**
+     * 鑾峰彇瀵煎叆鍥炴墽
+     *
+     * @return 瀵煎叆鍥炴墽
+     */
+    @Override
+    public String getAnalysis() {
+        int successCount = list.size();
+        int errorCount = errorList.size();
+        if (successCount == 0) {
+            return "璇诲彇澶辫触锛屾湭瑙f瀽鍒版暟鎹�";
+        } else {
+            if (errorCount == 0) {
+                return StrUtil.format("鎭枩鎮紝鍏ㄩ儴璇诲彇鎴愬姛锛佸叡{}鏉�", successCount);
+            } else {
+                return "";
+            }
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
new file mode 100644
index 0000000..8b53a0c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
@@ -0,0 +1,149 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * <h1>Excel涓嬫媺鍙�夐」</h1>
+ * 娉ㄦ剰锛氫负纭繚涓嬫媺妗嗚В鏋愭纭紝浼犲�煎姟蹇呬娇鐢╟reateOptionValue()鍋氫负鍊肩殑鎷兼帴
+ *
+ * @author Emil.Zhang
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@SuppressWarnings("unused")
+public class DropDownOptions {
+    /**
+     * 涓�绾т笅鎷夋墍鍦ㄥ垪index锛屼粠0寮�濮嬬畻
+     */
+    private int index = 0;
+    /**
+     * 浜岀骇涓嬫媺鎵�鍦ㄧ殑index锛屼粠0寮�濮嬬畻锛屼笉鑳戒笌涓�绾х浉鍚�
+     */
+    private int nextIndex = 0;
+    /**
+     * 涓�绾т笅鎷夋墍鍖呭惈鐨勬暟鎹�
+     */
+    private List<String> options = new ArrayList<>();
+    /**
+     * 浜岀骇涓嬫媺鎵�鍖呭惈鐨勬暟鎹甅ap
+     * <p>浠ユ瘡涓�涓竴绾ч�夐」鍊间负Key锛屾瘡涓竴绾ч�夐」瀵瑰簲鐨勪簩绾ф暟鎹负Value</p>
+     */
+    private Map<String, List<String>> nextOptions = new HashMap<>();
+    /**
+     * 鍒嗛殧绗�
+     */
+    private static final String DELIMITER = "_";
+
+    /**
+     * 鍒涘缓鍙湁涓�绾х殑涓嬫媺閫�
+     */
+    public DropDownOptions(int index, List<String> options) {
+        this.index = index;
+        this.options = options;
+    }
+
+    /**
+     * <h2>鍒涘缓姣忎釜閫夐」鍙�夊��</h2>
+     * <p>娉ㄦ剰锛氫笉鑳戒互鏁板瓧锛岀壒娈婄鍙峰紑澶达紝閫夐」涓笉鍙互鍖呭惈浠讳綍杩愮畻绗﹀彿</p>
+     *
+     * @param vars 鍙�夊�煎唴鍖呭惈鐨勫弬鏁�
+     * @return 鍚堣鐨勫彲閫夊��
+     */
+    public static String createOptionValue(Object... vars) {
+        StringBuilder stringBuffer = new StringBuilder();
+        String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$";
+        for (int i = 0; i < vars.length; i++) {
+            String var = StrUtil.trimToEmpty(String.valueOf(vars[i]));
+            if (!var.matches(regex)) {
+                throw new ServiceException("閫夐」鏁版嵁涓嶇鍚堣鍒欙紝浠呭厑璁镐娇鐢ㄤ腑鑻辨枃瀛楃浠ュ強鏁板瓧");
+            }
+            stringBuffer.append(var);
+            if (i < vars.length - 1) {
+                // 鐩磋嚦鏈�鍚庝竴涓墠锛岄兘浠浣滀负鍒囧壊绾�
+                stringBuffer.append(DELIMITER);
+            }
+        }
+        if (stringBuffer.toString().matches("^\\d_*$")) {
+            throw new ServiceException("绂佹浠ユ暟瀛楀紑澶�");
+        }
+        return stringBuffer.toString();
+    }
+
+    /**
+     * 灏嗗鐞嗗悗鍚堢悊鐨勫彲閫夊�艰В鏋愪负鍘熷鐨勫弬鏁�
+     *
+     * @param option 缁忚繃澶勭悊鍚庣殑鍚堢悊鐨勫彲閫夐」
+     * @return 鍘熷鐨勫弬鏁�
+     */
+    public static List<String> analyzeOptionValue(String option) {
+        return StrUtil.split(option, DELIMITER, true, true);
+    }
+
+    /**
+     * 鍒涘缓绾ц仈涓嬫媺閫夐」
+     *
+     * @param parentList                  鐖跺疄浣撳彲閫夐」鍘熷鏁版嵁
+     * @param parentIndex                 鐖朵笅鎷夐�変綅缃�
+     * @param sonList                     瀛愬疄浣撳彲閫夐」鍘熷鏁版嵁
+     * @param sonIndex                    瀛愪笅鎷夐�変綅缃�
+     * @param parentHowToGetIdFunction    鐖剁被濡備綍鑾峰彇鍞竴鏍囪瘑
+     * @param sonHowToGetParentIdFunction 瀛愮被濡備綍鑾峰彇鐖剁被鐨勫敮涓�鏍囪瘑
+     * @param howToBuildEveryOption       濡備綍鐢熸垚涓嬫媺閫夊唴瀹�
+     * @return 绾ц仈涓嬫媺閫夐」
+     */
+    public static <T> DropDownOptions buildLinkedOptions(List<T> parentList,
+                                                         int parentIndex,
+                                                         List<T> sonList,
+                                                         int sonIndex,
+                                                         Function<T, Number> parentHowToGetIdFunction,
+                                                         Function<T, Number> sonHowToGetParentIdFunction,
+                                                         Function<T, String> howToBuildEveryOption) {
+        DropDownOptions parentLinkSonOptions = new DropDownOptions();
+        // 鍏堝垱寤虹埗绫荤殑涓嬫媺
+        parentLinkSonOptions.setIndex(parentIndex);
+        parentLinkSonOptions.setOptions(
+            parentList.stream()
+                .map(howToBuildEveryOption)
+                .collect(Collectors.toList())
+        );
+        // 鎻愬彇鐖�-瀛愮骇鑱斾笅鎷�
+        Map<String, List<String>> sonOptions = new HashMap<>();
+        // 鐖剁骇渚濇嵁鑷繁鐨処D鍒嗙粍
+        Map<Number, List<T>> parentGroupByIdMap =
+            parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction));
+        // 閬嶅巻姣忎釜瀛愰泦锛屾彁鍙栧埌Map涓�
+        sonList.forEach(everySon -> {
+            if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) {
+                // 鎵惧埌瀵瑰簲鐨勪笂绾�
+                T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0);
+                // 鎻愬彇鍚嶇О鍜孖D浣滀负Key
+                String key = howToBuildEveryOption.apply(parentObj);
+                // Key瀵瑰簲鐨刅alue
+                List<String> thisParentSonOptionList;
+                if (sonOptions.containsKey(key)) {
+                    thisParentSonOptionList = sonOptions.get(key);
+                } else {
+                    thisParentSonOptionList = new ArrayList<>();
+                    sonOptions.put(key, thisParentSonOptionList);
+                }
+                // 寰�Value涓坊鍔犲綋鍓嶅瓙闆嗛�夐」
+                thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon));
+            }
+        });
+        parentLinkSonOptions.setNextIndex(sonIndex);
+        parentLinkSonOptions.setNextOptions(sonOptions);
+        return parentLinkSonOptions;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
new file mode 100644
index 0000000..b3f68ed
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
@@ -0,0 +1,373 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.metadata.FieldCache;
+import com.alibaba.excel.metadata.FieldWrapper;
+import com.alibaba.excel.util.ClassUtils;
+import com.alibaba.excel.write.handler.SheetWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.annotation.ExcelEnumFormat;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * <h1>Excel琛ㄦ牸涓嬫媺閫夋搷浣�</h1>
+ * 鑰冭檻鍒颁笅鎷夐�夎繃澶氬彲鑳藉鑷碋xcel鎵撳紑缂撴參鐨勯棶棰橈紝鍙牎楠屽墠1000琛�
+ * <p>
+ * 鍗冲彧鏈夊墠1000琛岀殑鏁版嵁鍙互鐢ㄤ笅鎷夋锛岃秴鍑虹殑鑷閫氳繃闄愬埗鏁版嵁閲忕殑褰㈠紡锛岀浜屾杈撳嚭
+ *
+ * @author Emil.Zhang
+ */
+@Slf4j
+public class ExcelDownHandler implements SheetWriteHandler {
+
+    /**
+     * Excel琛ㄦ牸涓殑鍒楀悕鑻辨枃
+     * 浠呬负浜嗚В鏋愬垪鑻辨枃锛岀姝慨鏀�
+     */
+    private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+    /**
+     * 鍗曢�夋暟鎹甋heet鍚�
+     */
+    private static final String OPTIONS_SHEET_NAME = "options";
+    /**
+     * 鑱斿姩閫夋嫨鏁版嵁Sheet鍚嶇殑澶�
+     */
+    private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions";
+    /**
+     * 涓嬫媺鍙�夐」
+     */
+    private final List<DropDownOptions> dropDownOptions;
+    /**
+     * 褰撳墠鍗曢�夎繘搴�
+     */
+    private int currentOptionsColumnIndex;
+    /**
+     * 褰撳墠鑱斿姩閫夋嫨杩涘害
+     */
+    private int currentLinkedOptionsSheetIndex;
+    private final DictService dictService;
+
+    public ExcelDownHandler(List<DropDownOptions> options) {
+        this.dropDownOptions = options;
+        this.currentOptionsColumnIndex = 0;
+        this.currentLinkedOptionsSheetIndex = 0;
+        this.dictService = SpringUtils.getBean(DictService.class);
+    }
+
+    /**
+     * <h2>寮�濮嬪垱寤轰笅鎷夋暟鎹�</h2>
+     * 1.閫氳繃瑙f瀽浼犲叆鐨凘ExcelProperty鍚岀骇鏄惁鏍囨敞鏈堾DropDown閫夐」
+     * 濡傛灉鏈変笖璁剧疆浜唙alue鍊硷紝鍒欏皢鍏剁洿鎺ョ疆涓轰笅鎷夊彲閫夐」
+     * <p>
+     * 2.鎴栬�呭湪璋冪敤ExcelUtil鏃舵寚瀹氫簡鍙�夐」锛屽皢渚濇嵁浼犲叆鐨勫彲閫夐」鍋氫笅鎷�
+     * <p>
+     * 3.浜岃�呭苟瀛橈紝娉ㄦ剰璋冪敤鏂瑰紡
+     */
+    @Override
+    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
+        Sheet sheet = writeSheetHolder.getSheet();
+        // 寮�濮嬭缃笅鎷夋 HSSFWorkbook
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        Workbook workbook = writeWorkbookHolder.getWorkbook();
+        FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder);
+        for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {
+            Integer index = entry.getKey();
+            FieldWrapper wrapper = entry.getValue();
+            Field field = wrapper.getField();
+            // 寰幆瀹炰綋涓殑姣忎釜灞炴��
+            // 鍙�夌殑涓嬫媺鍊�
+            List<String> options = new ArrayList<>();
+            if (field.isAnnotationPresent(ExcelDictFormat.class)) {
+                // 濡傛灉鎸囧畾浜咢ExcelDictFormat锛屽垯浣跨敤瀛楀吀鐨勯�昏緫
+                ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class);
+                String dictType = format.dictType();
+                String converterExp = format.readConverterExp();
+                if (StringUtils.isNotBlank(dictType)) {
+                    // 濡傛灉浼犻�掍簡瀛楀吀鍚嶏紝鍒欎緷鎹瓧鍏稿缓绔嬩笅鎷�
+                    Collection<String> values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
+                        .orElseThrow(() -> new ServiceException(String.format("瀛楀吀 %s 涓嶅瓨鍦�", dictType)))
+                        .values();
+                    options = new ArrayList<>(values);
+                } else if (StringUtils.isNotBlank(converterExp)) {
+                    // 濡傛灉鎸囧畾浜嗙‘鍒囩殑鍊硷紝鍒欑洿鎺ヨВ鏋愮‘鍒囩殑鍊�
+                    List<String> strList = StringUtils.splitList(converterExp, format.separator());
+                    options = StreamUtils.toList(strList, s -> StringUtils.split(s, "=")[1]);
+                }
+            } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) {
+                // 鍚﹀垯濡傛灉鎸囧畾浜咢ExcelEnumFormat锛屽垯浣跨敤鏋氫妇鐨勯�昏緫
+                ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
+                List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
+                options = StreamUtils.toList(values, String::valueOf);
+            }
+            if (ObjectUtil.isNotEmpty(options)) {
+                // 浠呭綋涓嬫媺鍙�夐」涓嶄负绌烘椂鎵ц
+                if (options.size() > 20) {
+                    // 杩欓噷闄愬埗濡傛灉鍙�夐」澶т簬20锛屽垯浣跨敤棰濆琛ㄥ舰寮�
+                    dropDownWithSheet(helper, workbook, sheet, index, options);
+                } else {
+                    // 鍚﹀垯浣跨敤鍥哄畾鍊煎舰寮�
+                    dropDownWithSimple(helper, sheet, index, options);
+                }
+            }
+        }
+        if (CollUtil.isEmpty(dropDownOptions)) {
+            return;
+        }
+        dropDownOptions.forEach(everyOptions -> {
+            // 濡傛灉浼犻�掍簡涓嬫媺妗嗛�夋嫨鍣ㄥ弬鏁�
+            if (!everyOptions.getNextOptions().isEmpty()) {
+                // 褰撲簩绾ч�夐」涓嶄负绌烘椂锛屼娇鐢ㄩ澶栧叧鑱旇〃鐨勫舰寮�
+                dropDownLinkedOptions(helper, workbook, sheet, everyOptions);
+            } else if (everyOptions.getOptions().size() > 10) {
+                // 褰撲竴绾ч�夐」鍙傛暟涓暟澶т簬10锛屼娇鐢ㄩ澶栬〃鐨勫舰寮�
+                dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
+            } else if (everyOptions.getOptions().size() != 0) {
+                // 褰撲竴绾ч�夐」涓暟涓嶄负绌猴紝浣跨敤榛樿褰㈠紡
+                dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
+            }
+        });
+    }
+
+    /**
+     * <h2>绠�鍗曚笅鎷夋</h2>
+     * 鐩存帴灏嗗彲閫夐」鎷兼帴涓烘寚瀹氬垪鐨勬暟鎹牎楠屽��
+     *
+     * @param celIndex 鍒梚ndex
+     * @param value    涓嬫媺閫夊彲閫夊��
+     */
+    private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List<String> value) {
+        if (ObjectUtil.isEmpty(value)) {
+            return;
+        }
+        this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class)));
+    }
+
+    /**
+     * <h2>棰濆琛ㄦ牸褰㈠紡鐨勭骇鑱斾笅鎷夋</h2>
+     *
+     * @param options 棰濆琛ㄦ牸褰㈠紡瀛樺偍鐨勪笅鎷夊彲閫夐」
+     */
+    private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) {
+        String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex);
+        // 鍒涘缓鑱斿姩涓嬫媺鏁版嵁琛�
+        Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
+        // 灏嗕笅鎷夎〃闅愯棌
+        workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
+        // 瀹屽杽妯悜鐨勪竴绾ч�夐」鏁版嵁琛�
+        List<String> firstOptions = options.getOptions();
+        Map<String, List<String>> secoundOptionsMap = options.getNextOptions();
+
+        // 鍒涘缓鍚嶇О绠$悊鍣�
+        Name name = workbook.createName();
+        // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕
+        name.setNameName(linkedOptionsSheetName);
+        // 浠ユí鍚戠涓�琛屽垱寤轰竴绾т笅鎷夋嫾鎺ュ紩鐢ㄤ綅缃�
+        String firstOptionsFunction = String.format("%s!$%s$1:$%s$1",
+            linkedOptionsSheetName,
+            getExcelColumnName(0),
+            getExcelColumnName(firstOptions.size())
+        );
+        // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆
+        name.setRefersToFormula(firstOptionsFunction);
+        // 璁剧疆鏁版嵁鏍¢獙涓哄簭鍒楁ā寮忥紝寮曠敤鐨勬槸鍚嶇О绠$悊鍣ㄤ腑鐨勫埆鍚�
+        this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
+
+        for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) {
+            // 鍏堟彁鍙栦富琛ㄤ腑涓�绾т笅鎷夌殑鍒楀悕
+            String firstOptionsColumnName = getExcelColumnName(columIndex);
+            // 涓�娆″惊鐜槸姣忎竴涓竴绾ч�夐」
+            int finalI = columIndex;
+            // 鏈寰幆鐨勪竴绾ч�夐」鍊�
+            String thisFirstOptionsValue = firstOptions.get(columIndex);
+            // 鍒涘缓绗竴琛岀殑鏁版嵁
+            Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
+                // 濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓绗竴琛�
+                .orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
+                // 绗竴琛屽綋鍓嶅垪
+                .createCell(columIndex)
+                // 璁剧疆鍊间负褰撳墠涓�绾ч�夐」鍊�
+                .setCellValue(thisFirstOptionsValue);
+
+            // 绗簩琛屽紑濮嬶紝璁剧疆绗簩绾у埆閫夐」鍙傛暟
+            List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
+            if (CollUtil.isEmpty(secondOptions)) {
+                // 蹇呴』淇濊瘉鑷冲皯鏈変竴涓叧鑱旈�夐」锛屽惁鍒欏皢瀵艰嚧Excel瑙f瀽閿欒
+                secondOptions = Collections.singletonList("鏆傛棤_0");
+            }
+
+            // 浠ヨ涓�绾ч�夐」鍊煎垱寤哄瓙鍚嶇О绠$悊鍣�
+            Name sonName = workbook.createName();
+            // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕
+            sonName.setNameName(thisFirstOptionsValue);
+            // 浠ョ浜岃璇ュ垪鏁版嵁鎷兼帴寮曠敤浣嶇疆
+            String sonFunction = String.format("%s!$%s$2:$%s$%d",
+                linkedOptionsSheetName,
+                firstOptionsColumnName,
+                firstOptionsColumnName,
+                secondOptions.size() + 1
+            );
+            // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆
+            sonName.setRefersToFormula(sonFunction);
+            // 鏁版嵁楠岃瘉涓哄簭鍒楁ā寮忥紝寮曠敤鍒版瘡涓�涓富琛ㄤ腑鐨勪簩绾ч�夐」浣嶇疆
+            // 鍒涘缓瀛愰」鐨勫悕绉扮鐞嗗櫒锛屽彧鏄负浜嗕娇寰桬xcel鍙互璇嗗埆鍒版暟鎹�
+            String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex());
+            for (int i = 0; i < 100; i++) {
+                // 浠ヤ竴绾ч�夐」瀵瑰簲鐨勪富浣撴墍鍦ㄤ綅缃垱寤轰簩绾т笅鎷�
+                String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1);
+                // 浜岀骇鍙兘涓昏〃姣忎竴琛岀殑姣忎竴鍒楁坊鍔犱簩绾ф牎楠�
+                markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
+            }
+
+            for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) {
+                // 浠庣浜岃寮�濮嬪~鍏呬簩绾ч�夐」
+                int finalRowIndex = rowIndex + 1;
+                int finalColumIndex = columIndex;
+
+                Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
+                    // 娌℃湁鍒欏垱寤�
+                    .orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex));
+                Optional
+                    // 鍦ㄦ湰绾т竴绾ч�夐」鎵�鍦ㄧ殑鍒�
+                    .ofNullable(row.getCell(finalColumIndex))
+                    // 涓嶅瓨鍦ㄥ垯鍒涘缓
+                    .orElseGet(() -> row.createCell(finalColumIndex))
+                    // 璁剧疆浜岀骇閫夐」鍊�
+                    .setCellValue(secondOptions.get(rowIndex));
+            }
+        }
+
+        currentLinkedOptionsSheetIndex++;
+    }
+
+    /**
+     * <h2>棰濆琛ㄦ牸褰㈠紡鐨勬櫘閫氫笅鎷夋</h2>
+     * 鐢变簬涓嬫媺妗嗗彲閫夊�兼暟閲忚繃澶氾紝涓烘彁鍗嘐xcel鎵撳紑鏁堢巼锛屼娇鐢ㄩ澶栬〃鏍煎舰寮忓仛涓嬫媺
+     *
+     * @param celIndex 涓嬫媺閫�
+     * @param value    涓嬫媺閫夊彲閫夊��
+     */
+    private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List<String> value) {
+        // 鍒涘缓涓嬫媺鏁版嵁琛�
+        Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME)))
+            .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME)));
+        // 灏嗕笅鎷夎〃闅愯棌
+        workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true);
+        // 瀹屽杽绾靛悜鐨勪竴绾ч�夐」鏁版嵁琛�
+        for (int i = 0; i < value.size(); i++) {
+            int finalI = i;
+            // 鑾峰彇姣忎竴閫夐」琛岋紝濡傛灉娌℃湁鍒欏垱寤�
+            Row row = Optional.ofNullable(simpleDataSheet.getRow(i))
+                .orElseGet(() -> simpleDataSheet.createRow(finalI));
+            // 鑾峰彇鏈骇閫夐」瀵瑰簲鐨勯�夐」鍒楋紝濡傛灉娌℃湁鍒欏垱寤�
+            Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex))
+                .orElseGet(() -> row.createCell(currentOptionsColumnIndex));
+            // 璁剧疆鍊�
+            cell.setCellValue(value.get(i));
+        }
+
+        // 鍒涘缓鍚嶇О绠$悊鍣�
+        Name name = workbook.createName();
+        // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑鍒悕
+        String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex);
+        name.setNameName(nameName);
+        // 浠ョ旱鍚戠涓�鍒楀垱寤轰竴绾т笅鎷夋嫾鎺ュ紩鐢ㄤ綅缃�
+        String function = String.format("%s!$%s$1:$%s$%d",
+            OPTIONS_SHEET_NAME,
+            getExcelColumnName(currentOptionsColumnIndex),
+            getExcelColumnName(currentOptionsColumnIndex),
+            value.size());
+        // 璁剧疆鍚嶇О绠$悊鍣ㄧ殑寮曠敤浣嶇疆
+        name.setRefersToFormula(function);
+        // 璁剧疆鏁版嵁鏍¢獙涓哄簭鍒楁ā寮忥紝寮曠敤鐨勬槸鍚嶇О绠$悊鍣ㄤ腑鐨勫埆鍚�
+        this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName));
+        currentOptionsColumnIndex++;
+    }
+
+    /**
+     * 鎸傝浇涓嬫媺鐨勫垪锛屼粎闄愪竴绾ч�夐」
+     */
+    private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex,
+                                    DataValidationConstraint constraint) {
+        // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪
+        CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex);
+        markDataValidationToSheet(helper, sheet, constraint, addressList);
+    }
+
+    /**
+     * 鎸傝浇涓嬫媺鐨勫垪锛屼粎闄愪簩绾ч�夐」
+     */
+    private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex,
+                                          Integer celIndex, DataValidationConstraint constraint) {
+        // 璁剧疆鏁版嵁鏈夋晥鎬у姞杞藉湪鍝釜鍗曞厓鏍间笂,鍥涗釜鍙傛暟鍒嗗埆鏄細璧峰琛屻�佺粓姝㈣銆佽捣濮嬪垪銆佺粓姝㈠垪
+        CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex);
+        markDataValidationToSheet(helper, sheet, constraint, addressList);
+    }
+
+    /**
+     * 搴旂敤鏁版嵁鏍¢獙
+     */
+    private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet,
+                                           DataValidationConstraint constraint, CellRangeAddressList addressList) {
+        // 鏁版嵁鏈夋晥鎬у璞�
+        DataValidation dataValidation = helper.createValidation(constraint, addressList);
+        // 澶勭悊Excel鍏煎鎬ч棶棰�
+        if (dataValidation instanceof XSSFDataValidation) {
+            //鏁版嵁鏍¢獙
+            dataValidation.setSuppressDropDownArrow(true);
+            //閿欒鎻愮ず
+            dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
+            dataValidation.createErrorBox("鎻愮ず", "姝ゅ�间笌鍗曞厓鏍煎畾涔夋暟鎹笉涓�鑷�");
+            dataValidation.setShowErrorBox(true);
+            //閫夊畾鎻愮ず
+            dataValidation.createPromptBox("濉啓璇存槑锛�", "濉啓鍐呭鍙兘涓轰笅鎷変腑鏁版嵁锛屽叾浠栨暟鎹皢瀵艰嚧瀵煎叆澶辫触");
+            dataValidation.setShowPromptBox(true);
+            sheet.addValidationData(dataValidation);
+        } else {
+            dataValidation.setSuppressDropDownArrow(false);
+        }
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * <h2>渚濇嵁鍒梚ndex鑾峰彇鍒楀悕鑻辨枃</h2>
+     * 渚濇嵁鍒梚ndex杞崲涓篍xcel涓殑鍒楀悕鑻辨枃
+     * <p>渚嬪绗�1鍒楋紝index涓�0锛岃В鏋愬嚭鏉ヤ负A鍒�</p>
+     * 绗�27鍒楋紝index涓�26锛岃В鏋愪负AA鍒�
+     * <p>绗�28鍒楋紝index涓�27锛岃В鏋愪负AB鍒�</p>
+     *
+     * @param columnIndex 鍒梚ndex
+     * @return 鍒梚ndex鎵�鍦ㄥ緱鑻辨枃鍚�
+     */
+    private String getExcelColumnName(int columnIndex) {
+        // 26涓�寰幆鐨勬鏁�
+        int columnCircleCount = columnIndex / 26;
+        // 26涓�寰幆鍐呯殑浣嶇疆
+        int thisCircleColumnIndex = columnIndex % 26;
+        // 26涓�寰幆鐨勬鏁板ぇ浜�0锛屽垯瑙嗕负鏍忓悕鑷冲皯涓や綅
+        String columnPrefix = columnCircleCount == 0
+            ? StrUtil.EMPTY
+            : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1);
+        // 浠�26涓�寰幆鍐呭彇瀵瑰簲鐨勬爮浣嶅悕
+        String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1);
+        // 灏嗕簩鑰呮嫾鎺ュ嵆涓烘渶缁堢殑鏍忎綅鍚�
+        return columnPrefix + columnNext;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java
new file mode 100644
index 0000000..2d0340f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java
@@ -0,0 +1,14 @@
+package org.dromara.common.excel.core;
+
+import com.alibaba.excel.read.listener.ReadListener;
+
+/**
+ * Excel 瀵煎叆鐩戝惉
+ *
+ * @author Lion Li
+ */
+public interface ExcelListener<T> extends ReadListener<T> {
+
+    ExcelResult<T> getExcelResult();
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java
new file mode 100644
index 0000000..0c2a418
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java
@@ -0,0 +1,26 @@
+package org.dromara.common.excel.core;
+
+import java.util.List;
+
+/**
+ * excel杩斿洖瀵硅薄
+ *
+ * @author Lion Li
+ */
+public interface ExcelResult<T> {
+
+    /**
+     * 瀵硅薄鍒楄〃
+     */
+    List<T> getList();
+
+    /**
+     * 閿欒鍒楄〃
+     */
+    List<String> getErrorList();
+
+    /**
+     * 瀵煎叆鍥炴墽
+     */
+    String getAnalysis();
+}
diff --git a/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
new file mode 100644
index 0000000..a6c14ad
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
@@ -0,0 +1,436 @@
+package org.dromara.common.excel.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.resource.ClassPathResource;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.fill.FillConfig;
+import com.alibaba.excel.write.metadata.fill.FillWrapper;
+import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.excel.convert.ExcelBigNumberConvert;
+import org.dromara.common.excel.core.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Excel鐩稿叧澶勭悊
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ExcelUtil {
+
+    /**
+     * 鍚屾瀵煎叆(閫傜敤浜庡皬鏁版嵁閲�)
+     *
+     * @param is 杈撳叆娴�
+     * @return 杞崲鍚庨泦鍚�
+     */
+    public static <T> List<T> importExcel(InputStream is, Class<T> clazz) {
+        return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync();
+    }
+
+
+    /**
+     * 浣跨敤鏍¢獙鐩戝惉鍣� 寮傛瀵煎叆 鍚屾杩斿洖
+     *
+     * @param is         杈撳叆娴�
+     * @param clazz      瀵硅薄绫诲瀷
+     * @param isValidate 鏄惁 Validator 妫�楠� 榛樿涓烘槸
+     * @return 杞崲鍚庨泦鍚�
+     */
+    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, boolean isValidate) {
+        DefaultExcelListener<T> listener = new DefaultExcelListener<>(isValidate);
+        EasyExcel.read(is, clazz, listener).sheet().doRead();
+        return listener.getExcelResult();
+    }
+
+    /**
+     * 浣跨敤鑷畾涔夌洃鍚櫒 寮傛瀵煎叆 鑷畾涔夎繑鍥�
+     *
+     * @param is       杈撳叆娴�
+     * @param clazz    瀵硅薄绫诲瀷
+     * @param listener 鑷畾涔夌洃鍚櫒
+     * @return 杞崲鍚庨泦鍚�
+     */
+    public static <T> ExcelResult<T> importExcel(InputStream is, Class<T> clazz, ExcelListener<T> listener) {
+        EasyExcel.read(is, clazz, listener).sheet().doRead();
+        return listener.getExcelResult();
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param response  鍝嶅簲浣�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response) {
+        try {
+            resetResponse(sheetName, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportExcel(list, sheetName, clazz, false, os, null);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param response  鍝嶅簲浣�
+     * @param options   绾ц仈涓嬫媺閫�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, HttpServletResponse response, List<DropDownOptions> options) {
+        try {
+            resetResponse(sheetName, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportExcel(list, sheetName, clazz, false, os, options);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param merge     鏄惁鍚堝苟鍗曞厓鏍�
+     * @param response  鍝嶅簲浣�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response) {
+        try {
+            resetResponse(sheetName, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportExcel(list, sheetName, clazz, merge, os, null);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param merge     鏄惁鍚堝苟鍗曞厓鏍�
+     * @param response  鍝嶅簲浣�
+     * @param options   绾ц仈涓嬫媺閫�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge, HttpServletResponse response, List<DropDownOptions> options) {
+        try {
+            resetResponse(sheetName, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportExcel(list, sheetName, clazz, merge, os, options);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param os        杈撳嚭娴�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, OutputStream os) {
+        exportExcel(list, sheetName, clazz, false, os, null);
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param os        杈撳嚭娴�
+     * @param options   绾ц仈涓嬫媺閫夊唴瀹�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, OutputStream os, List<DropDownOptions> options) {
+        exportExcel(list, sheetName, clazz, false, os, options);
+    }
+
+    /**
+     * 瀵煎嚭excel
+     *
+     * @param list      瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param clazz     瀹炰綋绫�
+     * @param merge     鏄惁鍚堝苟鍗曞厓鏍�
+     * @param os        杈撳嚭娴�
+     */
+    public static <T> void exportExcel(List<T> list, String sheetName, Class<T> clazz, boolean merge,
+                                       OutputStream os, List<DropDownOptions> options) {
+        ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
+            .autoCloseStream(false)
+            // 鑷姩閫傞厤
+            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
+            // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
+            .registerConverter(new ExcelBigNumberConvert())
+            .sheet(sheetName);
+        if (merge) {
+            // 鍚堝苟澶勭悊鍣�
+            builder.registerWriteHandler(new CellMergeStrategy(list, true));
+        }
+        // 娣诲姞涓嬫媺妗嗘搷浣�
+        builder.registerWriteHandler(new ExcelDownHandler(options));
+        builder.doWrite(list);
+    }
+
+    /**
+     * 鍗曡〃澶氭暟鎹ā鏉垮鍑� 妯℃澘鏍煎紡涓� {.灞炴�
+     *
+     * @param filename     鏂囦欢鍚�
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param response     鍝嶅簲浣�
+     */
+    public static void exportTemplate(List<Object> data, String filename, String templatePath, HttpServletResponse response) {
+        try {
+            resetResponse(filename, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportTemplate(data, templatePath, os);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 鍗曡〃澶氭暟鎹ā鏉垮鍑� 妯℃澘鏍煎紡涓� {.灞炴�
+     *
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param os           杈撳嚭娴�
+     */
+    public static void exportTemplate(List<Object> data, String templatePath, OutputStream os) {
+        ClassPathResource templateResource = new ClassPathResource(templatePath);
+        ExcelWriter excelWriter = EasyExcel.write(os)
+            .withTemplate(templateResource.getStream())
+            .autoCloseStream(false)
+            // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
+            .registerConverter(new ExcelBigNumberConvert())
+            .build();
+        WriteSheet writeSheet = EasyExcel.writerSheet().build();
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
+        // 鍗曡〃澶氭暟鎹鍑� 妯℃澘鏍煎紡涓� {.灞炴�
+        for (Object d : data) {
+            excelWriter.fill(d, writeSheet);
+        }
+        excelWriter.finish();
+    }
+
+    /**
+     * 澶氳〃澶氭暟鎹ā鏉垮鍑� 妯℃澘鏍煎紡涓� {key.灞炴�
+     *
+     * @param filename     鏂囦欢鍚�
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param response     鍝嶅簲浣�
+     */
+    public static void exportTemplateMultiList(Map<String, Object> data, String filename, String templatePath, HttpServletResponse response) {
+        try {
+            resetResponse(filename, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportTemplateMultiList(data, templatePath, os);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 澶歴heet妯℃澘瀵煎嚭 妯℃澘鏍煎紡涓� {key.灞炴�
+     *
+     * @param filename     鏂囦欢鍚�
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param response     鍝嶅簲浣�
+     */
+    public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String filename, String templatePath, HttpServletResponse response) {
+        try {
+            resetResponse(filename, response);
+            ServletOutputStream os = response.getOutputStream();
+            exportTemplateMultiSheet(data, templatePath, os);
+        } catch (IOException e) {
+            throw new RuntimeException("瀵煎嚭Excel寮傚父");
+        }
+    }
+
+    /**
+     * 澶氳〃澶氭暟鎹ā鏉垮鍑� 妯℃澘鏍煎紡涓� {key.灞炴�
+     *
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param os           杈撳嚭娴�
+     */
+    public static void exportTemplateMultiList(Map<String, Object> data, String templatePath, OutputStream os) {
+        ClassPathResource templateResource = new ClassPathResource(templatePath);
+        ExcelWriter excelWriter = EasyExcel.write(os)
+            .withTemplate(templateResource.getStream())
+            .autoCloseStream(false)
+            // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
+            .registerConverter(new ExcelBigNumberConvert())
+            .build();
+        WriteSheet writeSheet = EasyExcel.writerSheet().build();
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
+        for (Map.Entry<String, Object> map : data.entrySet()) {
+            // 璁剧疆鍒楄〃鍚庣画杩樻湁鏁版嵁
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+            if (map.getValue() instanceof Collection) {
+                // 澶氳〃瀵煎嚭蹇呴』浣跨敤 FillWrapper
+                excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
+            } else {
+                excelWriter.fill(map.getValue(), writeSheet);
+            }
+        }
+        excelWriter.finish();
+    }
+
+    /**
+     * 澶歴heet妯℃澘瀵煎嚭 妯℃澘鏍煎紡涓� {key.灞炴�
+     *
+     * @param templatePath 妯℃澘璺緞 resource 鐩綍涓嬬殑璺緞鍖呮嫭妯℃澘鏂囦欢鍚�
+     *                     渚嬪: excel/temp.xlsx
+     *                     閲嶇偣: 妯℃澘鏂囦欢蹇呴』鏀剧疆鍒板惎鍔ㄧ被瀵瑰簲鐨� resource 鐩綍涓�
+     * @param data         妯℃澘闇�瑕佺殑鏁版嵁
+     * @param os           杈撳嚭娴�
+     */
+    public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String templatePath, OutputStream os) {
+        ClassPathResource templateResource = new ClassPathResource(templatePath);
+        ExcelWriter excelWriter = EasyExcel.write(os)
+            .withTemplate(templateResource.getStream())
+            .autoCloseStream(false)
+            // 澶ф暟鍊艰嚜鍔ㄨ浆鎹� 闃叉澶辩湡
+            .registerConverter(new ExcelBigNumberConvert())
+            .build();
+        if (CollUtil.isEmpty(data)) {
+            throw new IllegalArgumentException("鏁版嵁涓虹┖");
+        }
+        for (int i = 0; i < data.size(); i++) {
+            WriteSheet writeSheet = EasyExcel.writerSheet(i).build();
+            for (Map.Entry<String, Object> map : data.get(i).entrySet()) {
+                // 璁剧疆鍒楄〃鍚庣画杩樻湁鏁版嵁
+                FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+                if (map.getValue() instanceof Collection) {
+                    // 澶氳〃瀵煎嚭蹇呴』浣跨敤 FillWrapper
+                    excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
+                } else {
+                    excelWriter.fill(map.getValue(), writeSheet);
+                }
+            }
+        }
+        excelWriter.finish();
+    }
+
+    /**
+     * 閲嶇疆鍝嶅簲浣�
+     */
+    private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException {
+        String filename = encodingFilename(sheetName);
+        FileUtils.setAttachmentResponseHeader(response, filename);
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
+    }
+
+    /**
+     * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡
+     *
+     * @param propertyValue 鍙傛暟鍊�
+     * @param converterExp  缈昏瘧娉ㄨВ
+     * @param separator     鍒嗛殧绗�
+     * @return 瑙f瀽鍚庡��
+     */
+    public static String convertByExp(String propertyValue, String converterExp, String separator) {
+        StringBuilder propertyString = new StringBuilder();
+        String[] convertSource = converterExp.split(StringUtils.SEPARATOR);
+        for (String item : convertSource) {
+            String[] itemArray = item.split("=");
+            if (StringUtils.containsAny(propertyValue, separator)) {
+                for (String value : propertyValue.split(separator)) {
+                    if (itemArray[0].equals(value)) {
+                        propertyString.append(itemArray[1] + separator);
+                        break;
+                    }
+                }
+            } else {
+                if (itemArray[0].equals(propertyValue)) {
+                    return itemArray[1];
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2
+     *
+     * @param propertyValue 鍙傛暟鍊�
+     * @param converterExp  缈昏瘧娉ㄨВ
+     * @param separator     鍒嗛殧绗�
+     * @return 瑙f瀽鍚庡��
+     */
+    public static String reverseByExp(String propertyValue, String converterExp, String separator) {
+        StringBuilder propertyString = new StringBuilder();
+        String[] convertSource = converterExp.split(StringUtils.SEPARATOR);
+        for (String item : convertSource) {
+            String[] itemArray = item.split("=");
+            if (StringUtils.containsAny(propertyValue, separator)) {
+                for (String value : propertyValue.split(separator)) {
+                    if (itemArray[1].equals(value)) {
+                        propertyString.append(itemArray[0] + separator);
+                        break;
+                    }
+                }
+            } else {
+                if (itemArray[1].equals(propertyValue)) {
+                    return itemArray[0];
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 缂栫爜鏂囦欢鍚�
+     */
+    public static String encodingFilename(String filename) {
+        return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx";
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-idempotent/pom.xml b/eims/ruoyi-common/ruoyi-common-idempotent/pom.xml
new file mode 100644
index 0000000..64418b4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-idempotent/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-idempotent</artifactId>
+
+    <description>
+        ruoyi-common-idempotent 骞傜瓑鍔熻兘
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-crypto</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-core</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java
new file mode 100644
index 0000000..42ae802
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java
@@ -0,0 +1,29 @@
+package org.dromara.common.idempotent.annotation;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 鑷畾涔夋敞瑙i槻姝㈣〃鍗曢噸澶嶆彁浜�
+ *
+ * @author Lion Li
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+
+    /**
+     * 闂撮殧鏃堕棿(ms)锛屽皬浜庢鏃堕棿瑙嗕负閲嶅鎻愪氦
+     */
+    int interval() default 5000;
+
+    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+
+    /**
+     * 鎻愮ず娑堟伅 鏀寔鍥介檯鍖� 鏍煎紡涓� {code}
+     */
+    String message() default "{repeat.submit.message}";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java
new file mode 100644
index 0000000..5a27e91
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java
@@ -0,0 +1,146 @@
+package org.dromara.common.idempotent.aspectj;
+
+import cn.dev33.satoken.SaManager;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.SecureUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * 闃叉閲嶅鎻愪氦(鍙傝�冪編鍥TIS闃查噸绯荤粺)
+ *
+ * @author Lion Li
+ */
+@Aspect
+public class RepeatSubmitAspect {
+
+    private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>();
+
+    @Before("@annotation(repeatSubmit)")
+    public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
+        // 濡傛灉娉ㄨВ涓嶄负0 鍒欎娇鐢ㄦ敞瑙f暟鍊�
+        long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
+
+        if (interval < 1000) {
+            throw new ServiceException("閲嶅鎻愪氦闂撮殧鏃堕棿涓嶈兘灏忎簬'1'绉�");
+        }
+        HttpServletRequest request = ServletUtils.getRequest();
+        String nowParams = argsArrayToString(point.getArgs());
+
+        // 璇锋眰鍦板潃锛堜綔涓哄瓨鏀綾ache鐨刱ey鍊硷級
+        String url = request.getRequestURI();
+
+        // 鍞竴鍊硷紙娌℃湁娑堟伅澶村垯浣跨敤璇锋眰鍦板潃锛�
+        String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName()));
+
+        submitKey = SecureUtil.md5(submitKey + ":" + nowParams);
+        // 鍞竴鏍囪瘑锛堟寚瀹歬ey + url + 娑堟伅澶达級
+        String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey;
+        if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) {
+            KEY_CACHE.set(cacheRepeatKey);
+        } else {
+            String message = repeatSubmit.message();
+            if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
+                message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1));
+            }
+            throw new ServiceException(message);
+        }
+    }
+
+    /**
+     * 澶勭悊瀹岃姹傚悗鎵ц
+     *
+     * @param joinPoint 鍒囩偣
+     */
+    @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) {
+        if (jsonResult instanceof R<?> r) {
+            try {
+                // 鎴愬姛鍒欎笉鍒犻櫎redis鏁版嵁 淇濊瘉鍦ㄦ湁鏁堟椂闂村唴鏃犳硶閲嶅鎻愪氦
+                if (r.getCode() == R.SUCCESS) {
+                    return;
+                }
+                RedisUtils.deleteObject(KEY_CACHE.get());
+            } finally {
+                KEY_CACHE.remove();
+            }
+        }
+    }
+
+    /**
+     * 鎷︽埅寮傚父鎿嶄綔
+     *
+     * @param joinPoint 鍒囩偣
+     * @param e         寮傚父
+     */
+    @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) {
+        RedisUtils.deleteObject(KEY_CACHE.get());
+        KEY_CACHE.remove();
+    }
+
+    /**
+     * 鍙傛暟鎷艰
+     */
+    private String argsArrayToString(Object[] paramsArray) {
+        StringJoiner params = new StringJoiner(" ");
+        if (ArrayUtil.isEmpty(paramsArray)) {
+            return params.toString();
+        }
+        for (Object o : paramsArray) {
+            if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
+                params.add(JsonUtils.toJsonString(o));
+            }
+        }
+        return params.toString();
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁闇�瑕佽繃婊ょ殑瀵硅薄銆�
+     *
+     * @param o 瀵硅薄淇℃伅銆�
+     * @return 濡傛灉鏄渶瑕佽繃婊ょ殑瀵硅薄锛屽垯杩斿洖true锛涘惁鍒欒繑鍥瀎alse銆�
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o) {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            return MultipartFile.class.isAssignableFrom(clazz.getComponentType());
+        } else if (Collection.class.isAssignableFrom(clazz)) {
+            Collection collection = (Collection) o;
+            for (Object value : collection) {
+                return value instanceof MultipartFile;
+            }
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            Map map = (Map) o;
+            for (Object value : map.values()) {
+                return value instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+               || o instanceof BindingResult;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java
new file mode 100644
index 0000000..fcb9d03
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java
@@ -0,0 +1,21 @@
+package org.dromara.common.idempotent.config;
+
+import org.dromara.common.idempotent.aspectj.RepeatSubmitAspect;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.connection.RedisConfiguration;
+
+/**
+ * 骞傜瓑鍔熻兘閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration(after = RedisConfiguration.class)
+public class IdempotentConfig {
+
+    @Bean
+    public RepeatSubmitAspect repeatSubmitAspect() {
+        return new RepeatSubmitAspect();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..f2fa958
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.idempotent.config.IdempotentConfig
diff --git a/eims/ruoyi-common/ruoyi-common-job/pom.xml b/eims/ruoyi-common/ruoyi-common-job/pom.xml
new file mode 100644
index 0000000..3a4a0cb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-job/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-job</artifactId>
+
+    <description>
+        ruoyi-common-job 瀹氭椂浠诲姟
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure</artifactId>
+        </dependency>
+
+        <!-- SnailJob client -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-client-job-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java b/eims/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java
new file mode 100644
index 0000000..cba3753
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java
@@ -0,0 +1,37 @@
+package org.dromara.common.job.config;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import com.aizuda.snailjob.client.common.appender.SnailLogbackAppender;
+import com.aizuda.snailjob.client.common.event.SnailClientStartingEvent;
+import com.aizuda.snailjob.client.starter.EnableSnailJob;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * 鍚姩瀹氭椂浠诲姟
+ *
+ * @author opensnail
+ * @date 2024-05-17
+ */
+@AutoConfiguration
+@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true")
+@EnableScheduling
+@EnableSnailJob
+public class SnailJobConfig {
+
+    @EventListener(SnailClientStartingEvent.class)
+    public void onStarting(SnailClientStartingEvent event) {
+        LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+        SnailLogbackAppender<ILoggingEvent> ca = new SnailLogbackAppender<>();
+        ca.setName("snail_log_appender");
+        ca.start();
+        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
+        rootLogger.addAppender(ca);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..3aa1881
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.job.config.SnailJobConfig
diff --git a/eims/ruoyi-common/ruoyi-common-json/pom.xml b/eims/ruoyi-common/ruoyi-common-json/pom.xml
new file mode 100644
index 0000000..870df5c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-json/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-json</artifactId>
+
+    <description>
+        ruoyi-common-json 搴忓垪鍖栨ā鍧�
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <!-- JSON宸ュ叿绫� -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java
new file mode 100644
index 0000000..8f5a45d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java
@@ -0,0 +1,47 @@
+package org.dromara.common.json.config;
+
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import org.dromara.common.json.handler.BigNumberSerializer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.TimeZone;
+
+/**
+ * jackson 閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@AutoConfiguration(before = JacksonAutoConfiguration.class)
+public class JacksonConfig {
+
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer customizer() {
+        return builder -> {
+            // 鍏ㄥ眬閰嶇疆搴忓垪鍖栬繑鍥� JSON 澶勭悊
+            JavaTimeModule javaTimeModule = new JavaTimeModule();
+            javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE);
+            javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE);
+            javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE);
+            javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
+            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
+            builder.modules(javaTimeModule);
+            builder.timeZone(TimeZone.getDefault());
+            log.info("鍒濆鍖� jackson 閰嶇疆");
+        };
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java
new file mode 100644
index 0000000..f2a7c2d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java
@@ -0,0 +1,42 @@
+package org.dromara.common.json.handler;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
+
+import java.io.IOException;
+
+/**
+ * 瓒呭嚭 JS 鏈�澶ф渶灏忓�� 澶勭悊
+ *
+ * @author Lion Li
+ */
+@JacksonStdImpl
+public class BigNumberSerializer extends NumberSerializer {
+
+    /**
+     * 鏍规嵁 JS Number.MAX_SAFE_INTEGER 涓� Number.MIN_SAFE_INTEGER 寰楁潵
+     */
+    private static final long MAX_SAFE_INTEGER = 9007199254740991L;
+    private static final long MIN_SAFE_INTEGER = -9007199254740991L;
+
+    /**
+     * 鎻愪緵瀹炰緥
+     */
+    public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class);
+
+    public BigNumberSerializer(Class<? extends Number> rawType) {
+        super(rawType);
+    }
+
+    @Override
+    public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+        // 瓒呭嚭鑼冨洿 搴忓垪鍖栦綅瀛楃涓�
+        if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {
+            super.serialize(value, gen, provider);
+        } else {
+            gen.writeString(value.toString());
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java
new file mode 100644
index 0000000..65c2faa
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java
@@ -0,0 +1,170 @@
+package org.dromara.common.json.utils;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.MismatchedInputException;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * JSON 宸ュ叿绫�
+ *
+ * @author 鑺嬮亾婧愮爜
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class JsonUtils {
+
+    private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);
+
+    public static ObjectMapper getObjectMapper() {
+        return OBJECT_MAPPER;
+    }
+
+    /**
+     * 灏嗗璞¤浆鎹负JSON鏍煎紡鐨勫瓧绗︿覆
+     *
+     * @param object 瑕佽浆鎹㈢殑瀵硅薄
+     * @return JSON鏍煎紡鐨勫瓧绗︿覆锛屽鏋滃璞′负null锛屽垯杩斿洖null
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烰SON澶勭悊寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static String toJsonString(Object object) {
+        if (ObjectUtil.isNull(object)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.writeValueAsString(object);
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄
+     *
+     * @param text  JSON鏍煎紡鐨勫瓧绗︿覆
+     * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷
+     * @param <T>   鐩爣瀵硅薄鐨勬硾鍨嬬被鍨�
+     * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鍒欒繑鍥瀗ull
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static <T> T parseObject(String text, Class<T> clazz) {
+        if (StringUtils.isEmpty(text)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.readValue(text, clazz);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏嗗瓧鑺傛暟缁勮浆鎹负鎸囧畾绫诲瀷鐨勫璞�
+     *
+     * @param bytes 瀛楄妭鏁扮粍
+     * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷
+     * @param <T>   鐩爣瀵硅薄鐨勬硾鍨嬬被鍨�
+     * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧鑺傛暟缁勪负绌哄垯杩斿洖null
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
+        if (ArrayUtil.isEmpty(bytes)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.readValue(bytes, clazz);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄锛屾敮鎸佸鏉傜被鍨�
+     *
+     * @param text          JSON鏍煎紡鐨勫瓧绗︿覆
+     * @param typeReference 鎸囧畾绫诲瀷鐨凾ypeReference瀵硅薄
+     * @param <T>           鐩爣瀵硅薄鐨勬硾鍨嬬被鍨�
+     * @return 杞崲鍚庣殑瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鍒欒繑鍥瀗ull
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static <T> T parseObject(String text, TypeReference<T> typeReference) {
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.readValue(text, typeReference);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓篋ict瀵硅薄
+     *
+     * @param text JSON鏍煎紡鐨勫瓧绗︿覆
+     * @return 杞崲鍚庣殑Dict瀵硅薄锛屽鏋滃瓧绗︿覆涓虹┖鎴栬�呬笉鏄疛SON鏍煎紡鍒欒繑鍥瀗ull
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static Dict parseMap(String text) {
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class));
+        } catch (MismatchedInputException e) {
+            // 绫诲瀷涓嶅尮閰嶈鏄庝笉鏄痡son
+            return null;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓篋ict瀵硅薄鐨勫垪琛�
+     *
+     * @param text JSON鏍煎紡鐨勫瓧绗︿覆
+     * @return 杞崲鍚庣殑Dict瀵硅薄鐨勫垪琛紝濡傛灉瀛楃涓蹭负绌哄垯杩斿洖null
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static List<Dict> parseArrayMap(String text) {
+        if (StringUtils.isBlank(text)) {
+            return null;
+        }
+        try {
+            return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 灏咼SON鏍煎紡鐨勫瓧绗︿覆杞崲涓烘寚瀹氱被鍨嬪璞$殑鍒楄〃
+     *
+     * @param text  JSON鏍煎紡鐨勫瓧绗︿覆
+     * @param clazz 瑕佽浆鎹㈢殑鐩爣瀵硅薄绫诲瀷
+     * @param <T>   鐩爣瀵硅薄鐨勬硾鍨嬬被鍨�
+     * @return 杞崲鍚庣殑瀵硅薄鐨勫垪琛紝濡傛灉瀛楃涓蹭负绌哄垯杩斿洖绌哄垪琛�
+     * @throws RuntimeException 濡傛灉杞崲杩囩▼涓彂鐢烮O寮傚父锛屽垯鎶涘嚭杩愯鏃跺紓甯�
+     */
+    public static <T> List<T> parseArray(String text, Class<T> clazz) {
+        if (StringUtils.isEmpty(text)) {
+            return new ArrayList<>();
+        }
+        try {
+            return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..1625397
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.json.config.JacksonConfig
diff --git a/eims/ruoyi-common/ruoyi-common-log/pom.xml b/eims/ruoyi-common/ruoyi-common-log/pom.xml
new file mode 100644
index 0000000..1e2b33b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-log</artifactId>
+
+    <description>
+        ruoyi-common-log 鏃ュ織璁板綍
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java
new file mode 100644
index 0000000..2dced97
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java
@@ -0,0 +1,48 @@
+package org.dromara.common.log.annotation;
+
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.log.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 鑷畾涔夋搷浣滄棩蹇楄褰曟敞瑙�
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log {
+    /**
+     * 妯″潡
+     */
+    String title() default "";
+
+    /**
+     * 鍔熻兘
+     */
+    BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 鎿嶄綔浜虹被鍒�
+     */
+    OperatorType operatorType() default OperatorType.MANAGE;
+
+    /**
+     * 鏄惁淇濆瓨璇锋眰鐨勫弬鏁�
+     */
+    boolean isSaveRequestData() default true;
+
+    /**
+     * 鏄惁淇濆瓨鍝嶅簲鐨勫弬鏁�
+     */
+    boolean isSaveResponseData() default true;
+
+
+    /**
+     * 鎺掗櫎鎸囧畾鐨勮姹傚弬鏁�
+     */
+    String[] excludeParamNames() default {};
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
new file mode 100644
index 0000000..cdbd00f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
@@ -0,0 +1,221 @@
+package org.dromara.common.log.aspect;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.StopWatch;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessStatus;
+import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.http.HttpMethod;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Aspect
+@AutoConfiguration
+public class LogAspect {
+
+    /**
+     * 鎺掗櫎鏁忔劅灞炴�у瓧娈�
+     */
+    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
+
+
+    /**
+     * 璁℃椂 key
+     */
+    private static final ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
+
+    /**
+     * 澶勭悊璇锋眰鍓嶆墽琛�
+     */
+    @Before(value = "@annotation(controllerLog)")
+    public void doBefore(JoinPoint joinPoint, Log controllerLog) {
+        StopWatch stopWatch = new StopWatch();
+        KEY_CACHE.set(stopWatch);
+        stopWatch.start();
+    }
+
+    /**
+     * 澶勭悊瀹岃姹傚悗鎵ц
+     *
+     * @param joinPoint 鍒囩偣
+     */
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+        handleLog(joinPoint, controllerLog, null, jsonResult);
+    }
+
+    /**
+     * 鎷︽埅寮傚父鎿嶄綔
+     *
+     * @param joinPoint 鍒囩偣
+     * @param e         寮傚父
+     */
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+        handleLog(joinPoint, controllerLog, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
+        try {
+
+            // *========鏁版嵁搴撴棩蹇�=========*//
+            OperLogEvent operLog = new OperLogEvent();
+            operLog.setTenantId(LoginHelper.getTenantId());
+            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+            // 璇锋眰鐨勫湴鍧�
+            String ip = ServletUtils.getClientIP();
+            operLog.setOperIp(ip);
+            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
+            LoginUser loginUser = LoginHelper.getLoginUser();
+            operLog.setOperName(loginUser.getUsername());
+            operLog.setDeptName(loginUser.getDeptName());
+
+            if (e != null) {
+                operLog.setStatus(BusinessStatus.FAIL.ordinal());
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+            }
+            // 璁剧疆鏂规硶鍚嶇О
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            operLog.setMethod(className + "." + methodName + "()");
+            // 璁剧疆璇锋眰鏂瑰紡
+            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
+            // 澶勭悊璁剧疆娉ㄨВ涓婄殑鍙傛暟
+            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
+            // 璁剧疆娑堣�楁椂闂�
+            StopWatch stopWatch = KEY_CACHE.get();
+            stopWatch.stop();
+            operLog.setCostTime(stopWatch.getTime());
+            // 鍙戝竷浜嬩欢淇濆瓨鏁版嵁搴�
+            SpringUtils.context().publishEvent(operLog);
+        } catch (Exception exp) {
+            // 璁板綍鏈湴寮傚父鏃ュ織
+            log.error("寮傚父淇℃伅:{}", exp.getMessage());
+            exp.printStackTrace();
+        } finally {
+            KEY_CACHE.remove();
+        }
+    }
+
+    /**
+     * 鑾峰彇娉ㄨВ涓鏂规硶鐨勬弿杩颁俊鎭� 鐢ㄤ簬Controller灞傛敞瑙�
+     *
+     * @param log     鏃ュ織
+     * @param operLog 鎿嶄綔鏃ュ織
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {
+        // 璁剧疆action鍔ㄤ綔
+        operLog.setBusinessType(log.businessType().ordinal());
+        // 璁剧疆鏍囬
+        operLog.setTitle(log.title());
+        // 璁剧疆鎿嶄綔浜虹被鍒�
+        operLog.setOperatorType(log.operatorType().ordinal());
+        // 鏄惁闇�瑕佷繚瀛榬equest锛屽弬鏁板拰鍊�
+        if (log.isSaveRequestData()) {
+            // 鑾峰彇鍙傛暟鐨勪俊鎭紝浼犲叆鍒版暟鎹簱涓��
+            setRequestValue(joinPoint, operLog, log.excludeParamNames());
+        }
+        // 鏄惁闇�瑕佷繚瀛榬esponse锛屽弬鏁板拰鍊�
+        if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {
+            operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 2000));
+        }
+    }
+
+    /**
+     * 鑾峰彇璇锋眰鐨勫弬鏁帮紝鏀惧埌log涓�
+     *
+     * @param operLog 鎿嶄綔鏃ュ織
+     * @throws Exception 寮傚父
+     */
+    private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
+        Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
+        String requestMethod = operLog.getRequestMethod();
+        if (MapUtil.isEmpty(paramsMap)
+                && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
+            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+        } else {
+            MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);
+            MapUtil.removeAny(paramsMap, excludeParamNames);
+            operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 2000));
+        }
+    }
+
+    /**
+     * 鍙傛暟鎷艰
+     */
+    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
+        StringJoiner params = new StringJoiner(" ");
+        if (ArrayUtil.isEmpty(paramsArray)) {
+            return params.toString();
+        }
+        for (Object o : paramsArray) {
+            if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
+                String str = JsonUtils.toJsonString(o);
+                Dict dict = JsonUtils.parseMap(str);
+                if (MapUtil.isNotEmpty(dict)) {
+                    MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
+                    MapUtil.removeAny(dict, excludeParamNames);
+                    str = JsonUtils.toJsonString(dict);
+                }
+                params.add(str);
+            }
+        }
+        return params.toString();
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁闇�瑕佽繃婊ょ殑瀵硅薄銆�
+     *
+     * @param o 瀵硅薄淇℃伅銆�
+     * @return 濡傛灉鏄渶瑕佽繃婊ょ殑瀵硅薄锛屽垯杩斿洖true锛涘惁鍒欒繑鍥瀎alse銆�
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o) {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray()) {
+            return MultipartFile.class.isAssignableFrom(clazz.getComponentType());
+        } else if (Collection.class.isAssignableFrom(clazz)) {
+            Collection collection = (Collection) o;
+            for (Object value : collection) {
+                return value instanceof MultipartFile;
+            }
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            Map map = (Map) o;
+            for (Object value : map.values()) {
+                return value instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+               || o instanceof BindingResult;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java
new file mode 100644
index 0000000..d303dc3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java
@@ -0,0 +1,18 @@
+package org.dromara.common.log.enums;
+
+/**
+ * 鎿嶄綔鐘舵��
+ *
+ * @author ruoyi
+ */
+public enum BusinessStatus {
+    /**
+     * 鎴愬姛
+     */
+    SUCCESS,
+
+    /**
+     * 澶辫触
+     */
+    FAIL,
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java
new file mode 100644
index 0000000..2d25ebb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java
@@ -0,0 +1,58 @@
+package org.dromara.common.log.enums;
+
+/**
+ * 涓氬姟鎿嶄綔绫诲瀷
+ *
+ * @author ruoyi
+ */
+public enum BusinessType {
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鏂板
+     */
+    INSERT,
+
+    /**
+     * 淇敼
+     */
+    UPDATE,
+
+    /**
+     * 鍒犻櫎
+     */
+    DELETE,
+
+    /**
+     * 鎺堟潈
+     */
+    GRANT,
+
+    /**
+     * 瀵煎嚭
+     */
+    EXPORT,
+
+    /**
+     * 瀵煎叆
+     */
+    IMPORT,
+
+    /**
+     * 寮洪��
+     */
+    FORCE,
+
+    /**
+     * 鐢熸垚浠g爜
+     */
+    GENCODE,
+
+    /**
+     * 娓呯┖鏁版嵁
+     */
+    CLEAN,
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java
new file mode 100644
index 0000000..de9328b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java
@@ -0,0 +1,23 @@
+package org.dromara.common.log.enums;
+
+/**
+ * 鎿嶄綔浜虹被鍒�
+ *
+ * @author ruoyi
+ */
+public enum OperatorType {
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鍚庡彴鐢ㄦ埛
+     */
+    MANAGE,
+
+    /**
+     * 鎵嬫満绔敤鎴�
+     */
+    MOBILE
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java
new file mode 100644
index 0000000..938eaad
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java
@@ -0,0 +1,52 @@
+package org.dromara.common.log.event;
+
+import lombok.Data;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐧诲綍浜嬩欢
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class LogininforEvent implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String username;
+
+    /**
+     * 鐧诲綍鐘舵�� 0鎴愬姛 1澶辫触
+     */
+    private String status;
+
+    /**
+     * 鎻愮ず娑堟伅
+     */
+    private String message;
+
+    /**
+     * 璇锋眰浣�
+     */
+    private HttpServletRequest request;
+
+    /**
+     * 鍏朵粬鍙傛暟
+     */
+    private Object[] args;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java
new file mode 100644
index 0000000..0386192
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java
@@ -0,0 +1,115 @@
+package org.dromara.common.log.event;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鎿嶄綔鏃ュ織浜嬩欢
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class OperLogEvent implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏃ュ織涓婚敭
+     */
+    private Long operId;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鎿嶄綔妯″潡
+     */
+    private String title;
+
+    /**
+     * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+     */
+    private Integer businessType;
+
+    /**
+     * 涓氬姟绫诲瀷鏁扮粍
+     */
+    private Integer[] businessTypes;
+
+    /**
+     * 璇锋眰鏂规硶
+     */
+    private String method;
+
+    /**
+     * 璇锋眰鏂瑰紡
+     */
+    private String requestMethod;
+
+    /**
+     * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+     */
+    private Integer operatorType;
+
+    /**
+     * 鎿嶄綔浜哄憳
+     */
+    private String operName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 璇锋眰url
+     */
+    private String operUrl;
+
+    /**
+     * 鎿嶄綔鍦板潃
+     */
+    private String operIp;
+
+    /**
+     * 鎿嶄綔鍦扮偣
+     */
+    private String operLocation;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    private String operParam;
+
+    /**
+     * 杩斿洖鍙傛暟
+     */
+    private String jsonResult;
+
+    /**
+     * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+     */
+    private Integer status;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    private String errorMsg;
+
+    /**
+     * 鎿嶄綔鏃堕棿
+     */
+    private Date operTime;
+
+    /**
+     * 娑堣�楁椂闂�
+     */
+    private Long costTime;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..6893020
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.log.aspect.LogAspect
diff --git a/eims/ruoyi-common/ruoyi-common-mail/pom.xml b/eims/ruoyi-common/ruoyi-common-mail/pom.xml
new file mode 100644
index 0000000..c0e1b2e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mail/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-mail</artifactId>
+
+    <description>
+        ruoyi-common-mail 閭欢妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.mail</groupId>
+            <artifactId>jakarta.mail-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.angus</groupId>
+            <artifactId>jakarta.mail</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
new file mode 100644
index 0000000..0ea3007
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
@@ -0,0 +1,37 @@
+package org.dromara.common.mail.config;
+
+import cn.hutool.extra.mail.MailAccount;
+import org.dromara.common.mail.config.properties.MailProperties;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * JavaMail 閰嶇疆
+ *
+ * @author Michelle.Chung
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(MailProperties.class)
+public class MailConfig {
+
+    @Bean
+    @ConditionalOnProperty(value = "mail.enabled", havingValue = "true")
+    public MailAccount mailAccount(MailProperties mailProperties) {
+        MailAccount account = new MailAccount();
+        account.setHost(mailProperties.getHost());
+        account.setPort(mailProperties.getPort());
+        account.setAuth(mailProperties.getAuth());
+        account.setFrom(mailProperties.getFrom());
+        account.setUser(mailProperties.getUser());
+        account.setPass(mailProperties.getPass());
+        account.setSocketFactoryPort(mailProperties.getPort());
+        account.setStarttlsEnable(mailProperties.getStarttlsEnable());
+        account.setSslEnable(mailProperties.getSslEnable());
+        account.setTimeout(mailProperties.getTimeout());
+        account.setConnectionTimeout(mailProperties.getConnectionTimeout());
+        return account;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
new file mode 100644
index 0000000..d0e78a2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
@@ -0,0 +1,69 @@
+package org.dromara.common.mail.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * JavaMail 閰嶇疆灞炴��
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ConfigurationProperties(prefix = "mail")
+public class MailProperties {
+
+    /**
+     * 杩囨护寮�鍏�
+     */
+    private Boolean enabled;
+
+    /**
+     * SMTP鏈嶅姟鍣ㄥ煙鍚�
+     */
+    private String host;
+
+    /**
+     * SMTP鏈嶅姟绔彛
+     */
+    private Integer port;
+
+    /**
+     * 鏄惁闇�瑕佺敤鎴峰悕瀵嗙爜楠岃瘉
+     */
+    private Boolean auth;
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    private String user;
+
+    /**
+     * 瀵嗙爜
+     */
+    private String pass;
+
+    /**
+     * 鍙戦�佹柟锛岄伒寰猂FC-822鏍囧噯
+     */
+    private String from;
+
+    /**
+     * 浣跨敤 STARTTLS瀹夊叏杩炴帴锛孲TARTTLS鏄绾枃鏈�氫俊鍗忚鐨勬墿灞曘�傚畠灏嗙函鏂囨湰杩炴帴鍗囩骇涓哄姞瀵嗚繛鎺ワ紙TLS鎴朣SL锛夛紝 鑰屼笉鏄娇鐢ㄤ竴涓崟鐙殑鍔犲瘑閫氫俊绔彛銆�
+     */
+    private Boolean starttlsEnable;
+
+    /**
+     * 浣跨敤 SSL瀹夊叏杩炴帴
+     */
+    private Boolean sslEnable;
+
+    /**
+     * SMTP瓒呮椂鏃堕暱锛屽崟浣嶆绉掞紝缂虹渷鍊间笉瓒呮椂
+     */
+    private Long timeout;
+
+    /**
+     * Socket杩炴帴瓒呮椂鍊硷紝鍗曚綅姣锛岀己鐪佸�间笉瓒呮椂
+     */
+    private Long connectionTimeout;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
new file mode 100644
index 0000000..a28701f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
@@ -0,0 +1,469 @@
+package org.dromara.common.mail.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.CharUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.mail.JakartaMail;
+import cn.hutool.extra.mail.JakartaUserPassAuthenticator;
+import cn.hutool.extra.mail.MailAccount;
+import jakarta.mail.Authenticator;
+import jakarta.mail.Session;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * 閭欢宸ュ叿绫�
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class MailUtils {
+
+    private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
+
+    /**
+     * 鑾峰彇閭欢鍙戦�佸疄渚�
+     */
+    public static MailAccount getMailAccount() {
+        return ACCOUNT;
+    }
+
+    /**
+     * 鑾峰彇閭欢鍙戦�佸疄渚� (鑷畾涔夊彂閫佷汉浠ュ強鎺堟潈鐮�)
+     *
+     * @param user 鍙戦�佷汉
+     * @param pass 鎺堟潈鐮�
+     */
+    public static MailAccount getMailAccount(String from, String user, String pass) {
+        ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom()));
+        ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser()));
+        ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass()));
+        return ACCOUNT;
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�佹枃鏈偖浠讹紝鍙戦�佺粰鍗曚釜鎴栧涓敹浠朵汉<br>
+     * 澶氫釜鏀朵欢浜哄彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to      鏀朵欢浜�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String sendText(String to, String subject, String content, File... files) {
+        return send(to, subject, content, false, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�丠TML閭欢锛屽彂閫佺粰鍗曚釜鎴栧涓敹浠朵汉<br>
+     * 澶氫釜鏀朵欢浜哄彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to      鏀朵欢浜�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String sendHtml(String to, String subject, String content, File... files) {
+        return send(to, subject, content, true, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佸崟涓垨澶氫釜鏀朵欢浜�<br>
+     * 澶氫釜鏀朵欢浜哄彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to      鏀朵欢浜�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param isHtml  鏄惁涓篐TML
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String send(String to, String subject, String content, boolean isHtml, File... files) {
+        return send(splitAddress(to), subject, content, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佸崟涓垨澶氫釜鏀朵欢浜�<br>
+     * 澶氫釜鏀朵欢浜恒�佹妱閫佷汉銆佸瘑閫佷汉鍙互浣跨敤閫楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to      鏀朵欢浜猴紝鍙互浣跨敤閫楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param cc      鎶勯�佷汉锛屽彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param bcc     瀵嗛�佷汉锛屽彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param isHtml  鏄惁涓篐TML
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.0.3
+     */
+    public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) {
+        return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�佹枃鏈偖浠讹紝鍙戦�佺粰澶氫汉
+     *
+     * @param tos     鏀朵欢浜哄垪琛�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String sendText(Collection<String> tos, String subject, String content, File... files) {
+        return send(tos, subject, content, false, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�丠TML閭欢锛屽彂閫佺粰澶氫汉
+     *
+     * @param tos     鏀朵欢浜哄垪琛�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String sendHtml(Collection<String> tos, String subject, String content, File... files) {
+        return send(tos, subject, content, true, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佺粰澶氫汉
+     *
+     * @param tos     鏀朵欢浜哄垪琛�
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param isHtml  鏄惁涓篐TML
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String send(Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
+        return send(tos, null, null, subject, content, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佺粰澶氫汉
+     *
+     * @param tos     鏀朵欢浜哄垪琛�
+     * @param ccs     鎶勯�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param bccs    瀵嗛�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param subject 鏍囬
+     * @param content 姝f枃
+     * @param isHtml  鏄惁涓篐TML
+     * @param files   闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.0.3
+     */
+    public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
+        return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files);
+    }
+
+    // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢璁よ瘉瀵硅薄
+     * @param to          鏀朵欢浜猴紝澶氫釜鏀朵欢浜洪�楀彿鎴栬�呭垎鍙烽殧寮�
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) {
+        return send(mailAccount, splitAddress(to), subject, content, isHtml, files);
+    }
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢甯愭埛淇℃伅
+     * @param tos         鏀朵欢浜哄垪琛�
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
+        return send(mailAccount, tos, null, null, subject, content, isHtml, files);
+    }
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢甯愭埛淇℃伅
+     * @param tos         鏀朵欢浜哄垪琛�
+     * @param ccs         鎶勯�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param bccs        瀵嗛�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.0.3
+     */
+    public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
+        return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�丠TML閭欢锛屽彂閫佺粰鍗曚釜鎴栧涓敹浠朵汉<br>
+     * 澶氫釜鏀朵欢浜哄彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to       鏀朵欢浜�
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String sendHtml(String to, String subject, String content, Map<String, InputStream> imageMap, File... files) {
+        return send(to, subject, content, imageMap, true, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佸崟涓垨澶氫釜鏀朵欢浜�<br>
+     * 澶氫釜鏀朵欢浜哄彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to       鏀朵欢浜�
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml   鏄惁涓篐TML
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(splitAddress(to), subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佸崟涓垨澶氫釜鏀朵欢浜�<br>
+     * 澶氫釜鏀朵欢浜恒�佹妱閫佷汉銆佸瘑閫佷汉鍙互浣跨敤閫楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     *
+     * @param to       鏀朵欢浜猴紝鍙互浣跨敤閫楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param cc       鎶勯�佷汉锛屽彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param bcc      瀵嗛�佷汉锛屽彲浠ヤ娇鐢ㄩ�楀彿鈥�,鈥濆垎闅旓紝涔熷彲浠ラ�氳繃鍒嗗彿鈥�;鈥濆垎闅�
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml   鏄惁涓篐TML
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.0.3
+     */
+    public static String send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�丠TML閭欢锛屽彂閫佺粰澶氫汉
+     *
+     * @param tos      鏀朵欢浜哄垪琛�
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String sendHtml(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, File... files) {
+        return send(tos, subject, content, imageMap, true, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佺粰澶氫汉
+     *
+     * @param tos      鏀朵欢浜哄垪琛�
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml   鏄惁涓篐TML
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     */
+    public static String send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(tos, null, null, subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 浣跨敤閰嶇疆鏂囦欢涓缃殑璐︽埛鍙戦�侀偖浠讹紝鍙戦�佺粰澶氫汉
+     *
+     * @param tos      鏀朵欢浜哄垪琛�
+     * @param ccs      鎶勯�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param bccs     瀵嗛�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param subject  鏍囬
+     * @param content  姝f枃
+     * @param imageMap 鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml   鏄惁涓篐TML
+     * @param files    闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.0.3
+     */
+    public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
+    }
+
+    // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢璁よ瘉瀵硅薄
+     * @param to          鏀朵欢浜猴紝澶氫釜鏀朵欢浜洪�楀彿鎴栬�呭垎鍙烽殧寮�
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param imageMap    鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     * @since 3.2.0
+     */
+    public static String send(MailAccount mailAccount, String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢甯愭埛淇℃伅
+     * @param tos         鏀朵欢浜哄垪琛�
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param imageMap    鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.6.3
+     */
+    public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount 閭欢甯愭埛淇℃伅
+     * @param tos         鏀朵欢浜哄垪琛�
+     * @param ccs         鎶勯�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param bccs        瀵嗛�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param subject     鏍囬
+     * @param content     姝f枃
+     * @param imageMap    鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:$IMAGE_PLACEHOLDER
+     * @param isHtml      鏄惁涓篐TML鏍煎紡
+     * @param files       闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.6.3
+     */
+    public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap,
+                              boolean isHtml, File... files) {
+        return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
+    }
+
+    /**
+     * 鏍规嵁閰嶇疆鏂囦欢锛岃幏鍙栭偖浠跺鎴风浼氳瘽
+     *
+     * @param mailAccount 閭欢璐︽埛閰嶇疆
+     * @param isSingleton 鏄惁鍗曚緥锛堝叏灞�鍏变韩浼氳瘽锛�
+     * @return {@link Session}
+     * @since 5.5.7
+     */
+    public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
+        Authenticator authenticator = null;
+        if (mailAccount.isAuth()) {
+            authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
+        }
+
+        return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
+            : Session.getInstance(mailAccount.getSmtpProps(), authenticator);
+    }
+
+    // ------------------------------------------------------------------------------------------------------------------------ Private method start
+
+    /**
+     * 鍙戦�侀偖浠剁粰澶氫汉
+     *
+     * @param mailAccount      閭欢甯愭埛淇℃伅
+     * @param useGlobalSession 鏄惁鍏ㄥ眬鍏变韩Session
+     * @param tos              鏀朵欢浜哄垪琛�
+     * @param ccs              鎶勯�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param bccs             瀵嗛�佷汉鍒楄〃锛屽彲浠ヤ负null鎴栫┖
+     * @param subject          鏍囬
+     * @param content          姝f枃
+     * @param imageMap         鍥剧墖涓庡崰浣嶇锛屽崰浣嶇鏍煎紡涓篶id:${cid}
+     * @param isHtml           鏄惁涓篐TML鏍煎紡
+     * @param files            闄勪欢鍒楄〃
+     * @return message-id
+     * @since 4.6.3
+     */
+    private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
+                               Map<String, InputStream> imageMap, boolean isHtml, File... files) {
+        final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession);
+
+        // 鍙�夋妱閫佷汉
+        if (CollUtil.isNotEmpty(ccs)) {
+            mail.setCcs(ccs.toArray(new String[0]));
+        }
+        // 鍙�夊瘑閫佷汉
+        if (CollUtil.isNotEmpty(bccs)) {
+            mail.setBccs(bccs.toArray(new String[0]));
+        }
+
+        mail.setTos(tos.toArray(new String[0]));
+        mail.setTitle(subject);
+        mail.setContent(content);
+        mail.setHtml(isHtml);
+        mail.setFiles(files);
+
+        // 鍥剧墖
+        if (MapUtil.isNotEmpty(imageMap)) {
+            for (Entry<String, InputStream> entry : imageMap.entrySet()) {
+                mail.addImage(entry.getKey(), entry.getValue());
+                // 鍏抽棴娴�
+                IoUtil.close(entry.getValue());
+            }
+        }
+
+        return mail.send();
+    }
+
+    /**
+     * 灏嗗涓仈绯讳汉杞负鍒楄〃锛屽垎闅旂涓洪�楀彿鎴栬�呭垎鍙�
+     *
+     * @param addresses 澶氫釜鑱旂郴浜猴紝濡傛灉涓虹┖杩斿洖null
+     * @return 鑱旂郴浜哄垪琛�
+     */
+    private static List<String> splitAddress(String addresses) {
+        if (StrUtil.isBlank(addresses)) {
+            return null;
+        }
+
+        List<String> result;
+        if (StrUtil.contains(addresses, CharUtil.COMMA)) {
+            result = StrUtil.splitTrim(addresses, CharUtil.COMMA);
+        } else if (StrUtil.contains(addresses, ';')) {
+            result = StrUtil.splitTrim(addresses, ';');
+        } else {
+            result = CollUtil.newArrayList(addresses);
+        }
+        return result;
+    }
+    // ------------------------------------------------------------------------------------------------------------------------ Private method end
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..ef0cf11
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.mail.config.MailConfig
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/pom.xml b/eims/ruoyi-common/ruoyi-common-mybatis/pom.xml
new file mode 100644
index 0000000..a58064a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-mybatis</artifactId>
+
+    <description>
+        ruoyi-common-mybatis 鏁版嵁搴撴湇鍔�
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+
+        <!-- dynamic-datasource 澶氭暟鎹簮-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+        </dependency>
+
+        <!-- sql鎬ц兘鍒嗘瀽鎻掍欢 -->
+        <dependency>
+            <groupId>p6spy</groupId>
+            <artifactId>p6spy</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
new file mode 100644
index 0000000..2879b9d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
@@ -0,0 +1,40 @@
+package org.dromara.common.mybatis.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 鏁版嵁鏉冮檺娉ㄨВ锛岀敤浜庢爣璁版暟鎹潈闄愮殑鍗犱綅绗﹀叧閿瓧鍜屾浛鎹㈠��
+ * <p>
+ * 涓�涓敞瑙e彧鑳藉搴斾竴涓ā鏉�
+ * </p>
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataColumn {
+
+    /**
+     * 鏁版嵁鏉冮檺妯℃澘鐨勫崰浣嶇鍏抽敭瀛楋紝榛樿涓� "deptName"
+     *
+     * @return 鍗犱綅绗﹀叧閿瓧鏁扮粍
+     */
+    String[] key() default "deptName";
+
+    /**
+     * 鏁版嵁鏉冮檺妯℃澘鐨勫崰浣嶇鏇挎崲鍊硷紝榛樿涓� "dept_id"
+     *
+     * @return 鍗犱綅绗︽浛鎹㈠�兼暟缁�
+     */
+    String[] value() default "dept_id";
+
+    /**
+     * 鏉冮檺鏍囪瘑绗� 鐢ㄤ簬閫氳繃鑿滃崟鏉冮檺鏍囪瘑绗︽潵鑾峰彇鏁版嵁鏉冮檺
+     * 鎷ユ湁姝ゆ爣璇嗙鐨勮鑹� 灏嗕笉浼氭嫾鎺ユ瑙掕壊鐨勬暟鎹繃婊ql
+     *
+     * @return 鏉冮檺鏍囪瘑绗�
+     */
+    String permission() default "";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
new file mode 100644
index 0000000..f5f22d5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
@@ -0,0 +1,30 @@
+package org.dromara.common.mybatis.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 鏁版嵁鏉冮檺缁勬敞瑙o紝鐢ㄤ簬鏍囪鏁版嵁鏉冮檺閰嶇疆鏁扮粍
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataPermission {
+
+    /**
+     * 鏁版嵁鏉冮檺閰嶇疆鏁扮粍锛岀敤浜庢寚瀹氭暟鎹潈闄愮殑鍗犱綅绗﹀叧閿瓧鍜屾浛鎹㈠��
+     *
+     * @return 鏁版嵁鏉冮檺閰嶇疆鏁扮粍
+     */
+    DataColumn[] value();
+
+    /**
+     * 鏉冮檺鎷兼帴鏍囪瘑绗�(鐢ㄤ簬鎸囧畾杩炴帴璇彞鐨剆ql绗﹀彿)
+     * 濡備笉濉� 榛樿 select 鐢� OR 鍏朵粬璇彞鐢� AND
+     * 鍐呭 OR 鎴栬�� AND
+     */
+    String joinStr() default "";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..0bc5b66
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -0,0 +1,119 @@
+package org.dromara.common.mybatis.config;
+
+import cn.hutool.core.net.NetUtil;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
+import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
+import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.BeansException;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * mybatis-plus閰嶇疆绫�(涓嬫柟娉ㄩ噴鏈夋彃浠朵粙缁�)
+ *
+ * @author Lion Li
+ */
+@EnableTransactionManagement(proxyTargetClass = true)
+@MapperScan("${mybatis-plus.mapperPackage}")
+@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
+public class MybatisPlusConfig {
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        // 澶氱鎴锋彃浠� 蹇呴』鏀惧埌绗竴浣�
+        try {
+            TenantLineInnerInterceptor tenant = SpringUtils.getBean(TenantLineInnerInterceptor.class);
+            interceptor.addInnerInterceptor(tenant);
+        } catch (BeansException ignore) {
+        }
+        // 鏁版嵁鏉冮檺澶勭悊
+        interceptor.addInnerInterceptor(dataPermissionInterceptor());
+        // 鍒嗛〉鎻掍欢
+        interceptor.addInnerInterceptor(paginationInnerInterceptor());
+        // 涔愯閿佹彃浠�
+        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
+        return interceptor;
+    }
+
+    /**
+     * 鏁版嵁鏉冮檺鎷︽埅鍣�
+     */
+    public PlusDataPermissionInterceptor dataPermissionInterceptor() {
+        return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage"));
+    }
+
+    /**
+     * 鍒嗛〉鎻掍欢锛岃嚜鍔ㄨ瘑鍒暟鎹簱绫诲瀷
+     */
+    public PaginationInnerInterceptor paginationInnerInterceptor() {
+        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
+        // 鍒嗛〉鍚堢悊鍖�
+        paginationInnerInterceptor.setOverflow(true);
+        return paginationInnerInterceptor;
+    }
+
+    /**
+     * 涔愯閿佹彃浠�
+     */
+    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
+        return new OptimisticLockerInnerInterceptor();
+    }
+
+    /**
+     * 鍏冨璞″瓧娈靛~鍏呮帶鍒跺櫒
+     */
+    @Bean
+    public MetaObjectHandler metaObjectHandler() {
+        return new InjectionMetaObjectHandler();
+    }
+
+    /**
+     * 浣跨敤缃戝崱淇℃伅缁戝畾闆姳鐢熸垚鍣�
+     * 闃叉闆嗙兢闆姳ID閲嶅
+     */
+    @Bean
+    public IdentifierGenerator idGenerator() {
+        return new DefaultIdentifierGenerator(NetUtil.getLocalhost());
+    }
+
+    /**
+     * 寮傚父澶勭悊鍣�
+     */
+    @Bean
+    public MybatisExceptionHandler mybatisExceptionHandler() {
+        return new MybatisExceptionHandler();
+    }
+
+    /**
+     * PaginationInnerInterceptor 鍒嗛〉鎻掍欢锛岃嚜鍔ㄨ瘑鍒暟鎹簱绫诲瀷
+     * https://baomidou.com/pages/97710a/
+     * OptimisticLockerInnerInterceptor 涔愯閿佹彃浠�
+     * https://baomidou.com/pages/0d93c0/
+     * MetaObjectHandler 鍏冨璞″瓧娈靛~鍏呮帶鍒跺櫒
+     * https://baomidou.com/pages/4c6bcf/
+     * ISqlInjector sql娉ㄥ叆鍣�
+     * https://baomidou.com/pages/42ea4a/
+     * BlockAttackInnerInterceptor 濡傛灉鏄鍏ㄨ〃鐨勫垹闄ゆ垨鏇存柊鎿嶄綔锛屽氨浼氱粓姝㈣鎿嶄綔
+     * https://baomidou.com/pages/f9a237/
+     * IllegalSQLInnerInterceptor sql鎬ц兘瑙勮寖鎻掍欢(鍨冨溇SQL鎷︽埅)
+     * IdentifierGenerator 鑷畾涔変富閿瓥鐣�
+     * https://baomidou.com/pages/568eb2/
+     * TenantLineInnerInterceptor 澶氱鎴锋彃浠�
+     * https://baomidou.com/pages/aef2f2/
+     * DynamicTableNameInnerInterceptor 鍔ㄦ�佽〃鍚嶆彃浠�
+     * https://baomidou.com/pages/2a45ff/
+     */
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
new file mode 100644
index 0000000..13a7941
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java
@@ -0,0 +1,70 @@
+package org.dromara.common.mybatis.core.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Entity鍩虹被
+ *
+ * @author Lion Li
+ */
+@Data
+public class BaseEntity implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎼滅储鍊�
+     */
+    @JsonIgnore
+    @TableField(exist = false)
+    private String searchValue;
+
+    /**
+     * 鍒涘缓閮ㄩ棬
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createDept;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createBy;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /**
+     * 鏇存柊鑰�
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Long updateBy;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    @TableField(exist = false)
+    private Map<String, Object> params = new HashMap<>();
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
new file mode 100644
index 0000000..956be9f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java
@@ -0,0 +1,348 @@
+package org.dromara.common.mybatis.core.mapper;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.toolkit.Db;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 鑷畾涔� Mapper 鎺ュ彛, 瀹炵幇 鑷畾涔夋墿灞�
+ *
+ * @param <T> table 娉涘瀷
+ * @param <V> vo 娉涘瀷
+ * @author Lion Li
+ * @since 2021-05-13
+ */
+@SuppressWarnings("unchecked")
+public interface BaseMapperPlus<T, V> extends BaseMapper<T> {
+
+    Log log = LogFactory.getLog(BaseMapperPlus.class);
+
+    /**
+     * 鑾峰彇褰撳墠瀹炰緥瀵硅薄鍏宠仈鐨勬硾鍨嬬被鍨� V 鐨� Class 瀵硅薄
+     *
+     * @return 杩斿洖褰撳墠瀹炰緥瀵硅薄鍏宠仈鐨勬硾鍨嬬被鍨� V 鐨� Class 瀵硅薄
+     */
+    default Class<V> currentVoClass() {
+        return (Class<V>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1];
+    }
+
+    /**
+     * 鑾峰彇褰撳墠瀹炰緥瀵硅薄鍏宠仈鐨勬硾鍨嬬被鍨� T 鐨� Class 瀵硅薄
+     *
+     * @return 杩斿洖褰撳墠瀹炰緥瀵硅薄鍏宠仈鐨勬硾鍨嬬被鍨� T 鐨� Class 瀵硅薄
+     */
+    default Class<T> currentModelClass() {
+        return (Class<T>) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0];
+    }
+
+    /**
+     * 浣跨敤榛樿鐨勬煡璇㈡潯浠舵煡璇㈠苟杩斿洖缁撴灉鍒楄〃
+     *
+     * @return 杩斿洖鏌ヨ缁撴灉鐨勫垪琛�
+     */
+    default List<T> selectList() {
+        return this.selectList(new QueryWrapper<>());
+    }
+
+    /**
+     * 鎵归噺鎻掑叆瀹炰綋瀵硅薄闆嗗悎
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @return 鎻掑叆鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
+     */
+    default boolean insertBatch(Collection<T> entityList) {
+        Db.saveBatch(entityList);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鎵归噺鏍规嵁ID鏇存柊瀹炰綋瀵硅薄闆嗗悎
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @return 鏇存柊鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
+     */
+    default boolean updateBatchById(Collection<T> entityList) {
+        Db.updateBatchById(entityList);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鎵归噺鎻掑叆鎴栨洿鏂板疄浣撳璞¢泦鍚�
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @return 鎻掑叆鎴栨洿鏂版搷浣滄槸鍚︽垚鍔熺殑甯冨皵鍊�
+     */
+    default boolean insertOrUpdateBatch(Collection<T> entityList) {
+        Db.saveOrUpdateBatch(entityList);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鎵归噺鎻掑叆瀹炰綋瀵硅薄闆嗗悎骞舵寚瀹氭壒澶勭悊澶у皬
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @param batchSize  鎵瑰鐞嗗ぇ灏�
+     * @return 鎻掑叆鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
+     */
+    default boolean insertBatch(Collection<T> entityList, int batchSize) {
+        Db.saveBatch(entityList, batchSize);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鎵归噺鏍规嵁ID鏇存柊瀹炰綋瀵硅薄闆嗗悎骞舵寚瀹氭壒澶勭悊澶у皬
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @param batchSize  鎵瑰鐞嗗ぇ灏�
+     * @return 鏇存柊鎿嶄綔鏄惁鎴愬姛鐨勫竷灏斿��
+     */
+    default boolean updateBatchById(Collection<T> entityList, int batchSize) {
+        Db.updateBatchById(entityList, batchSize);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鎵归噺鎻掑叆鎴栨洿鏂板疄浣撳璞¢泦鍚堝苟鎸囧畾鎵瑰鐞嗗ぇ灏�
+     *
+     * @param entityList 瀹炰綋瀵硅薄闆嗗悎
+     * @param batchSize  鎵瑰鐞嗗ぇ灏�
+     * @return 鎻掑叆鎴栨洿鏂版搷浣滄槸鍚︽垚鍔熺殑甯冨皵鍊�
+     */
+    default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
+        Db.saveOrUpdateBatch(entityList, batchSize);
+        // 涓存椂瑙e喅 鏂扮増鏈� mp 鎻掑叆鐘舵�佸垽鏂敊璇棶棰�
+        return true;
+    }
+
+    /**
+     * 鏍规嵁ID鏌ヨ鍗曚釜VO瀵硅薄
+     *
+     * @param id 涓婚敭ID
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄
+     */
+    default V selectVoById(Serializable id) {
+        return selectVoById(id, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁ID鏌ヨ鍗曚釜VO瀵硅薄骞跺皢鍏惰浆鎹负鎸囧畾鐨刅O绫�
+     *
+     * @param id      涓婚敭ID
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> C selectVoById(Serializable id, Class<C> voClass) {
+        T obj = this.selectById(id);
+        if (ObjectUtil.isNull(obj)) {
+            return null;
+        }
+        return MapstructUtils.convert(obj, voClass);
+    }
+
+    /**
+     * 鏍规嵁ID闆嗗悎鎵归噺鏌ヨVO瀵硅薄鍒楄〃
+     *
+     * @param idList 涓婚敭ID闆嗗悎
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃
+     */
+    default List<V> selectVoBatchIds(Collection<? extends Serializable> idList) {
+        return selectVoBatchIds(idList, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁ID闆嗗悎鎵归噺鏌ヨ瀹炰綋瀵硅薄鍒楄〃锛屽苟灏嗗叾杞崲涓烘寚瀹氱殑VO瀵硅薄鍒楄〃
+     *
+     * @param idList  涓婚敭ID闆嗗悎
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
+        List<T> list = this.selectBatchIds(idList);
+        if (CollUtil.isEmpty(list)) {
+            return CollUtil.newArrayList();
+        }
+        return MapstructUtils.convert(list, voClass);
+    }
+
+    /**
+     * 鏍规嵁鏌ヨ鏉′欢Map鏌ヨVO瀵硅薄鍒楄〃
+     *
+     * @param map 鏌ヨ鏉′欢Map
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃
+     */
+    default List<V> selectVoByMap(Map<String, Object> map) {
+        return selectVoByMap(map, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁鏌ヨ鏉′欢Map鏌ヨ瀹炰綋瀵硅薄鍒楄〃锛屽苟灏嗗叾杞崲涓烘寚瀹氱殑VO瀵硅薄鍒楄〃
+     *
+     * @param map     鏌ヨ鏉′欢Map
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
+        List<T> list = this.selectByMap(map);
+        if (CollUtil.isEmpty(list)) {
+            return CollUtil.newArrayList();
+        }
+        return MapstructUtils.convert(list, voClass);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ鍗曚釜VO瀵硅薄
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄
+     */
+    default V selectVoOne(Wrapper<T> wrapper) {
+        return selectVoOne(wrapper, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ鍗曚釜VO瀵硅薄锛屽苟鏍规嵁闇�瑕佸喅瀹氭槸鍚︽姏鍑哄紓甯�
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param throwEx 鏄惁鎶涘嚭寮傚父鐨勬爣蹇�
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄
+     */
+    default V selectVoOne(Wrapper<T> wrapper, boolean throwEx) {
+        return selectVoOne(wrapper, this.currentVoClass(), throwEx);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ鍗曚釜VO瀵硅薄锛屽苟鎸囧畾杩斿洖鐨刅O瀵硅薄鐨勭被鍨�
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param voClass 杩斿洖鐨刅O瀵硅薄鐨凜lass瀵硅薄
+     * @param <C>     杩斿洖鐨刅O瀵硅薄鐨勭被鍨�
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄锛岀粡杩囩被鍨嬭浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
+        return selectVoOne(wrapper, voClass, true);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ鍗曚釜瀹炰綋瀵硅薄锛屽苟灏嗗叾杞崲涓烘寚瀹氱殑VO瀵硅薄
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param throwEx 鏄惁鎶涘嚭寮傚父鐨勬爣蹇�
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @return 鏌ヨ鍒扮殑鍗曚釜VO瀵硅薄锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass, boolean throwEx) {
+        T obj = this.selectOne(wrapper, throwEx);
+        if (ObjectUtil.isNull(obj)) {
+            return null;
+        }
+        return MapstructUtils.convert(obj, voClass);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈塚O瀵硅薄鍒楄〃
+     *
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃
+     */
+    default List<V> selectVoList() {
+        return selectVoList(new QueryWrapper<>(), this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨVO瀵硅薄鍒楄〃
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃
+     */
+    default List<V> selectVoList(Wrapper<T> wrapper) {
+        return selectVoList(wrapper, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ瀹炰綋瀵硅薄鍒楄〃锛屽苟灏嗗叾杞崲涓烘寚瀹氱殑VO瀵硅薄鍒楄〃
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒楄〃锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
+        List<T> list = this.selectList(wrapper);
+        if (CollUtil.isEmpty(list)) {
+            return CollUtil.newArrayList();
+        }
+        return MapstructUtils.convert(list, voClass);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨVO瀵硅薄鍒楄〃
+     *
+     * @param page    鍒嗛〉淇℃伅
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒嗛〉鍒楄〃
+     */
+    default <P extends IPage<V>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper) {
+        return selectVoPage(page, wrapper, this.currentVoClass());
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀹炰綋瀵硅薄鍒楄〃锛屽苟灏嗗叾杞崲涓烘寚瀹氱殑VO瀵硅薄鍒嗛〉鍒楄〃
+     *
+     * @param page    鍒嗛〉淇℃伅
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param voClass 瑕佽浆鎹㈢殑VO绫荤殑Class瀵硅薄
+     * @param <C>     VO绫荤殑绫诲瀷
+     * @param <P>     VO瀵硅薄鍒嗛〉鍒楄〃鐨勭被鍨�
+     * @return 鏌ヨ鍒扮殑VO瀵硅薄鍒嗛〉鍒楄〃锛岀粡杩囪浆鎹负鎸囧畾鐨刅O绫诲悗杩斿洖
+     */
+    default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
+        // 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀹炰綋瀵硅薄鍒楄〃
+        List<T> list = this.selectList(page, wrapper);
+        // 鍒涘缓涓�涓柊鐨刅O瀵硅薄鍒嗛〉鍒楄〃锛屽苟璁剧疆鍒嗛〉淇℃伅
+        IPage<C> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+        if (CollUtil.isEmpty(list)) {
+            return (P) voPage;
+        }
+        voPage.setRecords(MapstructUtils.convert(list, voClass));
+        return (P) voPage;
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鏌ヨ绗﹀悎鏉′欢鐨勫璞★紝骞跺皢鍏惰浆鎹负鎸囧畾绫诲瀷鐨勫璞″垪琛�
+     *
+     * @param wrapper 鏌ヨ鏉′欢Wrapper
+     * @param mapper  杞崲鍑芥暟锛岀敤浜庡皢鏌ヨ鍒扮殑瀵硅薄杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄
+     * @param <C>     瑕佽浆鎹㈢殑瀵硅薄鐨勭被鍨�
+     * @return 鏌ヨ鍒扮殑绗﹀悎鏉′欢鐨勫璞″垪琛紝缁忚繃杞崲涓烘寚瀹氱被鍨嬬殑瀵硅薄鍚庤繑鍥�
+     */
+    default <C> List<C> selectObjs(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
+        return StreamUtils.toList(this.selectObjs(wrapper), mapper);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
new file mode 100644
index 0000000..6ca9b27
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
@@ -0,0 +1,120 @@
+package org.dromara.common.mybatis.core.page;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.sql.SqlUtil;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鍒嗛〉鏌ヨ瀹炰綋绫�
+ *
+ * @author Lion Li
+ */
+@Data
+public class PageQuery implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鍒嗛〉澶у皬
+     */
+    private Integer pageSize;
+
+    /**
+     * 褰撳墠椤垫暟
+     */
+    private Integer pageNum;
+
+    /**
+     * 鎺掑簭鍒�
+     */
+    private String orderByColumn;
+
+    /**
+     * 鎺掑簭鐨勬柟鍚慸esc鎴栬�卆sc
+     */
+    private String isAsc;
+
+    /**
+     * 褰撳墠璁板綍璧峰绱㈠紩 榛樿鍊�
+     */
+    public static final int DEFAULT_PAGE_NUM = 1;
+
+    /**
+     * 姣忛〉鏄剧ず璁板綍鏁� 榛樿鍊� 榛樿鏌ュ叏閮�
+     */
+    public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
+
+    /**
+     * 鏋勫缓鍒嗛〉瀵硅薄
+     */
+    public <T> Page<T> build() {
+        Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
+        Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
+        if (pageNum <= 0) {
+            pageNum = DEFAULT_PAGE_NUM;
+        }
+        Page<T> page = new Page<>(pageNum, pageSize);
+        List<OrderItem> orderItems = buildOrderItem();
+        if (CollUtil.isNotEmpty(orderItems)) {
+            page.addOrder(orderItems);
+        }
+        return page;
+    }
+
+    /**
+     * 鏋勫缓鎺掑簭
+     *
+     * 鏀寔鐨勭敤娉曞涓�:
+     * {isAsc:"asc",orderByColumn:"id"} order by id asc
+     * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
+     * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
+     * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
+     */
+    private List<OrderItem> buildOrderItem() {
+        if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
+            return null;
+        }
+        String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
+        orderBy = StringUtils.toUnderScoreCase(orderBy);
+
+        // 鍏煎鍓嶇鎺掑簭绫诲瀷
+        isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
+
+        String[] orderByArr = orderBy.split(StringUtils.SEPARATOR);
+        String[] isAscArr = isAsc.split(StringUtils.SEPARATOR);
+        if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
+            throw new ServiceException("鎺掑簭鍙傛暟鏈夎");
+        }
+
+        List<OrderItem> list = new ArrayList<>();
+        // 姣忎釜瀛楁鍚勮嚜鎺掑簭
+        for (int i = 0; i < orderByArr.length; i++) {
+            String orderByStr = orderByArr[i];
+            String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
+            if ("asc".equals(isAscStr)) {
+                list.add(OrderItem.asc(orderByStr));
+            } else if ("desc".equals(isAscStr)) {
+                list.add(OrderItem.desc(orderByStr));
+            } else {
+                throw new ServiceException("鎺掑簭鍙傛暟鏈夎");
+            }
+        }
+        return list;
+    }
+
+    public Integer getFirstNum() {
+        return (pageNum - 1) * pageSize;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
new file mode 100644
index 0000000..8ecfb54
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java
@@ -0,0 +1,89 @@
+package org.dromara.common.mybatis.core.page;
+
+import cn.hutool.http.HttpStatus;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 琛ㄦ牸鍒嗛〉鏁版嵁瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+public class TableDataInfo<T> implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎬昏褰曟暟
+     */
+    private long total;
+
+    /**
+     * 鍒楄〃鏁版嵁
+     */
+    private List<T> rows;
+
+    /**
+     * 娑堟伅鐘舵�佺爜
+     */
+    private int code;
+
+    /**
+     * 娑堟伅鍐呭
+     */
+    private String msg;
+
+    /**
+     * 鍒嗛〉
+     *
+     * @param list  鍒楄〃鏁版嵁
+     * @param total 鎬昏褰曟暟
+     */
+    public TableDataInfo(List<T> list, long total) {
+        this.rows = list;
+        this.total = total;
+    }
+
+    /**
+     * 鏍规嵁鍒嗛〉瀵硅薄鏋勫缓琛ㄦ牸鍒嗛〉鏁版嵁瀵硅薄
+     */
+    public static <T> TableDataInfo<T> build(IPage<T> page) {
+        TableDataInfo<T> rspData = new TableDataInfo<>();
+        rspData.setCode(HttpStatus.HTTP_OK);
+        rspData.setMsg("鏌ヨ鎴愬姛");
+        rspData.setRows(page.getRecords());
+        rspData.setTotal(page.getTotal());
+        return rspData;
+    }
+
+    /**
+     * 鏍规嵁鏁版嵁鍒楄〃鏋勫缓琛ㄦ牸鍒嗛〉鏁版嵁瀵硅薄
+     */
+    public static <T> TableDataInfo<T> build(List<T> list) {
+        TableDataInfo<T> rspData = new TableDataInfo<>();
+        rspData.setCode(HttpStatus.HTTP_OK);
+        rspData.setMsg("鏌ヨ鎴愬姛");
+        rspData.setRows(list);
+        rspData.setTotal(list.size());
+        return rspData;
+    }
+
+    /**
+     * 鏋勫缓琛ㄦ牸鍒嗛〉鏁版嵁瀵硅薄
+     */
+    public static <T> TableDataInfo<T> build() {
+        TableDataInfo<T> rspData = new TableDataInfo<>();
+        rspData.setCode(HttpStatus.HTTP_OK);
+        rspData.setMsg("鏌ヨ鎴愬姛");
+        return rspData;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java
new file mode 100644
index 0000000..5084424
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java
@@ -0,0 +1,58 @@
+package org.dromara.common.mybatis.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.utils.StringUtils;
+
+/**
+ * 鏁版嵁搴撶被鍨�
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum DataBaseType {
+
+    /**
+     * MySQL
+     */
+    MY_SQL("MySQL"),
+
+    /**
+     * Oracle
+     */
+    ORACLE("Oracle"),
+
+    /**
+     * PostgreSQL
+     */
+    POSTGRE_SQL("PostgreSQL"),
+
+    /**
+     * SQL Server
+     */
+    SQL_SERVER("Microsoft SQL Server");
+
+    /**
+     * 鏁版嵁搴撶被鍨�
+     */
+    private final String type;
+
+    /**
+     * 鏍规嵁鏁版嵁搴撲骇鍝佸悕绉版煡鎵惧搴旂殑鏁版嵁搴撶被鍨�
+     *
+     * @param databaseProductName 鏁版嵁搴撲骇鍝佸悕绉�
+     * @return 瀵瑰簲鐨勬暟鎹簱绫诲瀷鏋氫妇鍊硷紝濡傛灉鏈壘鍒板垯杩斿洖 null
+     */
+    public static DataBaseType find(String databaseProductName) {
+        if (StringUtils.isBlank(databaseProductName)) {
+            return null;
+        }
+        for (DataBaseType type : values()) {
+            if (type.getType().equals(databaseProductName)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
new file mode 100644
index 0000000..981bd42
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
@@ -0,0 +1,82 @@
+package org.dromara.common.mybatis.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+
+/**
+ * 鏁版嵁鏉冮檺绫诲瀷鏋氫妇
+ * <p>
+ * 鏀寔浣跨敤 SpEL 妯℃澘琛ㄨ揪寮忓畾涔� SQL 鏌ヨ鏉′欢
+ * 鍐呯疆鏁版嵁锛�
+ * - {@code user}: 褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛屽弬鑰� {@link LoginUser}
+ * 鍐呯疆鏈嶅姟锛�
+ * - {@code sdss}: 绯荤粺鏁版嵁鏉冮檺鏈嶅姟锛屽弬鑰� ISysDataScopeService
+ * 濡傞渶鎵╁睍鏁版嵁锛屽彲浠ラ�氳繃 {@link DataPermissionHelper} 杩涜鎿嶄綔
+ * 濡傞渶鎵╁睍鏈嶅姟锛屽彲浠ラ�氳繃 ISysDataScopeService 鑷缂栧啓
+ * </p>
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@Getter
+@AllArgsConstructor
+public enum DataScopeType {
+
+    /**
+     * 鍏ㄩ儴鏁版嵁鏉冮檺
+     */
+    ALL("1", "", ""),
+
+    /**
+     * 鑷畾鏁版嵁鏉冮檺
+     */
+    CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
+
+    /**
+     * 閮ㄩ棬鏁版嵁鏉冮檺
+     */
+    DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
+
+    /**
+     * 閮ㄩ棬鍙婁互涓嬫暟鎹潈闄�
+     */
+    DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
+
+    /**
+     * 浠呮湰浜烘暟鎹潈闄�
+     */
+    SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
+
+    private final String code;
+
+    /**
+     * SpEL 妯℃澘琛ㄨ揪寮忥紝鐢ㄤ簬鏋勫缓 SQL 鏌ヨ鏉′欢
+     */
+    private final String sqlTemplate;
+
+    /**
+     * 濡傛灉涓嶆弧瓒� {@code sqlTemplate} 鐨勬潯浠讹紝鍒欎娇鐢ㄦ榛樿 SQL 琛ㄨ揪寮�
+     */
+    private final String elseSql;
+
+    /**
+     * 鏍规嵁鏋氫妇浠g爜鏌ユ壘瀵瑰簲鐨勬灇涓惧��
+     *
+     * @param code 鏋氫妇浠g爜
+     * @return 瀵瑰簲鐨勬灇涓惧�硷紝濡傛灉鏈壘鍒板垯杩斿洖 null
+     */
+    public static DataScopeType findCode(String code) {
+        if (StringUtils.isBlank(code)) {
+            return null;
+        }
+        for (DataScopeType type : values()) {
+            if (type.getCode().equals(code)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
new file mode 100644
index 0000000..7d44d26
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
@@ -0,0 +1,103 @@
+package org.dromara.common.mybatis.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpStatus;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.reflection.MetaObject;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.satoken.utils.LoginHelper;
+
+import java.util.Date;
+
+/**
+ * MP娉ㄥ叆澶勭悊鍣�
+ *
+ * @author Lion Li
+ * @date 2021/4/25
+ */
+@Slf4j
+public class InjectionMetaObjectHandler implements MetaObjectHandler {
+
+    /**
+     * 鎻掑叆濉厖鏂规硶锛岀敤浜庡湪鎻掑叆鏁版嵁鏃惰嚜鍔ㄥ~鍏呭疄浣撳璞′腑鐨勫垱寤烘椂闂淬�佹洿鏂版椂闂淬�佸垱寤轰汉銆佹洿鏂颁汉绛変俊鎭�
+     *
+     * @param metaObject 鍏冨璞★紝鐢ㄤ簬鑾峰彇鍘熷瀵硅薄骞惰繘琛屽~鍏�
+     */
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        try {
+            if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
+                // 鑾峰彇褰撳墠鏃堕棿浣滀负鍒涘缓鏃堕棿鍜屾洿鏂版椂闂达紝濡傛灉鍒涘缓鏃堕棿涓嶄负绌猴紝鍒欎娇鐢ㄥ垱寤烘椂闂达紝鍚﹀垯浣跨敤褰撳墠鏃堕棿
+                Date current = ObjectUtil.isNotNull(baseEntity.getCreateTime())
+                    ? baseEntity.getCreateTime() : new Date();
+                baseEntity.setCreateTime(current);
+                baseEntity.setUpdateTime(current);
+
+                // 濡傛灉鍒涘缓浜轰负绌猴紝鍒欏~鍏呭綋鍓嶇櫥褰曠敤鎴风殑淇℃伅
+                if (ObjectUtil.isNull(baseEntity.getCreateBy())) {
+                    LoginUser loginUser = getLoginUser();
+                    if (ObjectUtil.isNotNull(loginUser)) {
+                        Long userId = loginUser.getUserId();
+                        // 濉厖鍒涘缓浜恒�佹洿鏂颁汉鍜屽垱寤洪儴闂ㄤ俊鎭�
+                        baseEntity.setCreateBy(userId);
+                        baseEntity.setUpdateBy(userId);
+                        baseEntity.setCreateDept(ObjectUtil.isNotNull(baseEntity.getCreateDept())
+                            ? baseEntity.getCreateDept() : loginUser.getDeptId());
+                    }
+                }
+            } else {
+                Date date = new Date();
+                this.strictInsertFill(metaObject, "createTime", Date.class, date);
+                this.strictInsertFill(metaObject, "updateTime", Date.class, date);
+            }
+        } catch (Exception e) {
+            throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鏇存柊濉厖鏂规硶锛岀敤浜庡湪鏇存柊鏁版嵁鏃惰嚜鍔ㄥ~鍏呭疄浣撳璞′腑鐨勬洿鏂版椂闂村拰鏇存柊浜轰俊鎭�
+     *
+     * @param metaObject 鍏冨璞★紝鐢ㄤ簬鑾峰彇鍘熷瀵硅薄骞惰繘琛屽~鍏�
+     */
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        try {
+            if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) {
+                // 鑾峰彇褰撳墠鏃堕棿浣滀负鏇存柊鏃堕棿锛屾棤璁哄師濮嬪璞′腑鐨勬洿鏂版椂闂存槸鍚︿负绌洪兘濉厖
+                Date current = new Date();
+                baseEntity.setUpdateTime(current);
+
+                // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛鐨処D锛屽苟濉厖鏇存柊浜轰俊鎭�
+                Long userId = LoginHelper.getUserId();
+                if (ObjectUtil.isNotNull(userId)) {
+                    baseEntity.setUpdateBy(userId);
+                }
+            } else {
+                this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
+            }
+        } catch (Exception e) {
+            throw new ServiceException("鑷姩娉ㄥ叆寮傚父 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+     *
+     * @return 褰撳墠鐧诲綍鐢ㄦ埛鐨勪俊鎭紝濡傛灉鐢ㄦ埛鏈櫥褰曞垯杩斿洖 null
+     */
+    private LoginUser getLoginUser() {
+        LoginUser loginUser;
+        try {
+            loginUser = LoginHelper.getLoginUser();
+        } catch (Exception e) {
+            log.warn("鑷姩娉ㄥ叆璀﹀憡 => 鐢ㄦ埛鏈櫥褰�");
+            return null;
+        }
+        return loginUser;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java
new file mode 100644
index 0000000..518d52d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java
@@ -0,0 +1,46 @@
+package org.dromara.common.mybatis.handler;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * Mybatis寮傚父澶勭悊鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RestControllerAdvice
+public class MybatisExceptionHandler {
+
+    /**
+     * 涓婚敭鎴朥NIQUE绱㈠紩锛屾暟鎹噸澶嶅紓甯�
+     */
+    @ExceptionHandler(DuplicateKeyException.class)
+    public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鏁版嵁搴撲腑宸插瓨鍦ㄨ褰�'{}'", requestURI, e.getMessage());
+        return R.fail("鏁版嵁搴撲腑宸插瓨鍦ㄨ璁板綍锛岃鑱旂郴绠$悊鍛樼‘璁�");
+    }
+
+    /**
+     * Mybatis绯荤粺寮傚父 閫氱敤澶勭悊
+     */
+    @ExceptionHandler(MyBatisSystemException.class)
+    public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        String message = e.getMessage();
+        if (StringUtils.contains("CannotFindDataSourceException", message)) {
+            log.error("璇锋眰鍦板潃'{}', 鏈壘鍒版暟鎹簮", requestURI);
+            return R.fail("鏈壘鍒版暟鎹簮锛岃鑱旂郴绠$悊鍛樼‘璁�");
+        }
+        log.error("璇锋眰鍦板潃'{}', Mybatis绯荤粺寮傚父", requestURI, e);
+        return R.fail(message);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
new file mode 100644
index 0000000..5ac74c3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -0,0 +1,274 @@
+package org.dromara.common.mybatis.handler;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.Parenthesis;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import org.apache.ibatis.io.Resources;
+import org.dromara.common.core.domain.dto.RoleDTO;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.enums.DataScopeType;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.ClassMetadata;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.expression.BeanResolver;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.util.ClassUtils;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+/**
+ * 鏁版嵁鏉冮檺杩囨护
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@Slf4j
+public class PlusDataPermissionHandler {
+
+    /**
+     * 鏂规硶鎴栫被(鍚嶇О) 涓� 娉ㄨВ鐨勬槧灏勫叧绯荤紦瀛�
+     */
+    private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
+
+    /**
+     * spel 瑙f瀽鍣�
+     */
+    private final ExpressionParser parser = new SpelExpressionParser();
+    private final ParserContext parserContext = new TemplateParserContext();
+    /**
+     * bean瑙f瀽鍣� 鐢ㄤ簬澶勭悊 spel 琛ㄨ揪寮忎腑瀵� bean 鐨勮皟鐢�
+     */
+    private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
+
+    /**
+     * 鏋勯�犳柟娉曪紝鎵弿鎸囧畾鍖呬笅鐨� Mapper 绫诲苟鍒濆鍖栫紦瀛�
+     *
+     * @param mapperPackage Mapper 绫绘墍鍦ㄧ殑鍖呰矾寰�
+     */
+    public PlusDataPermissionHandler(String mapperPackage) {
+        scanMapperClasses(mapperPackage);
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁杩囨护鏉′欢鐨� SQL 鐗囨
+     *
+     * @param where             鍘熷鐨勬煡璇㈡潯浠惰〃杈惧紡
+     * @param mappedStatementId Mapper 鏂规硶鐨� ID
+     * @param isSelect          鏄惁涓烘煡璇㈣鍙�
+     * @return 鏁版嵁杩囨护鏉′欢鐨� SQL 鐗囨
+     */
+    public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
+        // 鑾峰彇鏁版嵁鏉冮檺閰嶇疆
+        DataPermission dataPermission = getDataPermission(mappedStatementId);
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+        LoginUser currentUser = DataPermissionHelper.getVariable("user");
+        if (ObjectUtil.isNull(currentUser)) {
+            currentUser = LoginHelper.getLoginUser();
+            DataPermissionHelper.setVariable("user", currentUser);
+        }
+        // 濡傛灉鏄秴绾х鐞嗗憳鎴栫鎴风鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
+        if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
+            return where;
+        }
+        // 鏋勯�犳暟鎹繃婊ゆ潯浠剁殑 SQL 鐗囨
+        String dataFilterSql = buildDataFilter(dataPermission, isSelect);
+        if (StringUtils.isBlank(dataFilterSql)) {
+            return where;
+        }
+        try {
+            Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
+            // 鏁版嵁鏉冮檺浣跨敤鍗曠嫭鐨勬嫭鍙� 闃叉涓庡叾浠栨潯浠跺啿绐�
+            Parenthesis parenthesis = new Parenthesis(expression);
+            if (ObjectUtil.isNotNull(where)) {
+                return new AndExpression(where, parenthesis);
+            } else {
+                return parenthesis;
+            }
+        } catch (JSQLParserException e) {
+            throw new ServiceException("鏁版嵁鏉冮檺瑙f瀽寮傚父 => " + e.getMessage());
+        }
+    }
+
+    /**
+     * 鏋勫缓鏁版嵁杩囨护鏉′欢鐨� SQL 璇彞
+     *
+     * @param dataPermission 鏁版嵁鏉冮檺娉ㄨВ
+     * @param isSelect       鏍囧織褰撳墠鎿嶄綔鏄惁涓烘煡璇㈡搷浣滐紝鏌ヨ鎿嶄綔鍜屾洿鏂版垨鍒犻櫎鎿嶄綔鍦ㄥ鐞嗚繃婊ゆ潯浠舵椂浼氭湁涓嶅悓鐨勫鐞嗘柟寮�
+     * @return 鏋勫缓鐨勬暟鎹繃婊ゆ潯浠剁殑 SQL 璇彞
+     * @throws ServiceException 濡傛灉瑙掕壊鐨勬暟鎹寖鍥村紓甯告垨鑰� key 涓� value 鐨勯暱搴︿笉鍖归厤锛屽垯鎶涘嚭 ServiceException 寮傚父
+     */
+    private String buildDataFilter(DataPermission dataPermission, boolean isSelect) {
+        // 鏇存柊鎴栧垹闄ら渶婊¤冻鎵�鏈夋潯浠�
+        String joinStr = isSelect ? " OR " : " AND ";
+        if (StringUtils.isNotBlank(dataPermission.joinStr())) {
+            joinStr = " " + dataPermission.joinStr() + " ";
+        }
+        LoginUser user = DataPermissionHelper.getVariable("user");
+        StandardEvaluationContext context = new StandardEvaluationContext();
+        context.setBeanResolver(beanResolver);
+        DataPermissionHelper.getContext().forEach(context::setVariable);
+        Set<String> conditions = new HashSet<>();
+        for (RoleDTO role : user.getRoles()) {
+            user.setRoleId(role.getRoleId());
+            // 鑾峰彇瑙掕壊鏉冮檺娉涘瀷
+            DataScopeType type = DataScopeType.findCode(role.getDataScope());
+            if (ObjectUtil.isNull(type)) {
+                throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => " + role.getDataScope());
+            }
+            // 鍏ㄩ儴鏁版嵁鏉冮檺鐩存帴杩斿洖
+            if (type == DataScopeType.ALL) {
+                return "";
+            }
+            boolean isSuccess = false;
+            for (DataColumn dataColumn : dataPermission.value()) {
+                if (dataColumn.key().length != dataColumn.value().length) {
+                    throw new ServiceException("瑙掕壊鏁版嵁鑼冨洿寮傚父 => key涓巚alue闀垮害涓嶅尮閰�");
+                }
+                // 涓嶅寘鍚� key 鍙橀噺 鍒欎笉澶勭悊
+                if (!StringUtils.containsAny(type.getSqlTemplate(),
+                    Arrays.stream(dataColumn.key()).map(key -> "#" + key).toArray(String[]::new)
+                )) {
+                    continue;
+                }
+                // 鍖呭惈鏉冮檺鏍囪瘑绗� 杩欑洿鎺ヨ烦杩�
+                if (StringUtils.isNotBlank(dataColumn.permission()) &&
+                    CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
+                ) {
+                    isSuccess = true;
+                    continue;
+                }
+                // 璁剧疆娉ㄨВ鍙橀噺 key 涓鸿〃杈惧紡鍙橀噺 value 涓哄彉閲忓��
+                for (int i = 0; i < dataColumn.key().length; i++) {
+                    context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
+                }
+
+                // 瑙f瀽sql妯℃澘骞跺~鍏�
+                String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class);
+                conditions.add(joinStr + sql);
+                isSuccess = true;
+            }
+            // 鏈鐞嗘垚鍔熷垯濉厖鍏滃簳鏂规
+            if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) {
+                conditions.add(joinStr + type.getElseSql());
+            }
+        }
+
+        if (CollUtil.isNotEmpty(conditions)) {
+            String sql = StreamUtils.join(conditions, Function.identity(), "");
+            return sql.substring(joinStr.length());
+        }
+        return "";
+    }
+
+    /**
+     * 鎵弿鎸囧畾鍖呬笅鐨� Mapper 绫伙紝骞舵煡鎵惧叾涓甫鏈夌壒瀹氭敞瑙g殑鏂规硶鎴栫被
+     *
+     * @param mapperPackage Mapper 绫绘墍鍦ㄧ殑鍖呰矾寰�
+     */
+    private void scanMapperClasses(String mapperPackage) {
+        // 鍒涘缓璧勬簮瑙f瀽鍣ㄥ拰鍏冩暟鎹鍙栧伐鍘�
+        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
+        // 灏� Mapper 鍖呰矾寰勬寜鍒嗛殧绗︽媶鍒嗕负鏁扮粍
+        String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+        String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
+        try {
+            for (String packagePattern : packagePatternArray) {
+                // 灏嗗寘璺緞杞崲涓鸿祫婧愯矾寰�
+                String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
+                // 鑾峰彇鎸囧畾璺緞涓嬬殑鎵�鏈� .class 鏂囦欢璧勬簮
+                Resource[] resources = resolver.getResources(classpath + path + "/*.class");
+                for (Resource resource : resources) {
+                    // 鑾峰彇璧勬簮鐨勭被鍏冩暟鎹�
+                    ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
+                    // 鑾峰彇璧勬簮瀵瑰簲鐨勭被瀵硅薄
+                    Class<?> clazz = Resources.classForName(classMetadata.getClassName());
+                    // 鏌ユ壘绫讳腑鐨勭壒瀹氭敞瑙�
+                    findAnnotation(clazz);
+                }
+            }
+        } catch (Exception e) {
+            log.error("鍒濆鍖栨暟鎹畨鍏ㄧ紦瀛樻椂鍑洪敊:{}", e.getMessage());
+        }
+    }
+
+    /**
+     * 鍦ㄦ寚瀹氱殑绫讳腑鏌ユ壘鐗瑰畾鐨勬敞瑙� DataPermission锛屽苟灏嗗甫鏈夎繖涓敞瑙g殑鏂规硶鎴栫被瀛樺偍鍒� dataPermissionCacheMap 涓�
+     *
+     * @param clazz 瑕佹煡鎵剧殑绫�
+     */
+    private void findAnnotation(Class<?> clazz) {
+        DataPermission dataPermission;
+        for (Method method : clazz.getMethods()) {
+            if (method.isDefault() || method.isVarArgs()) {
+                continue;
+            }
+            String mappedStatementId = clazz.getName() + "." + method.getName();
+            if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
+                dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
+                dataPermissionCacheMap.put(mappedStatementId, dataPermission);
+            }
+        }
+        if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
+            dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
+            dataPermissionCacheMap.put(clazz.getName(), dataPermission);
+        }
+    }
+
+    /**
+     * 鏍规嵁鏄犲皠璇彞 ID 鎴栫被鍚嶈幏鍙栧搴旂殑 DataPermission 娉ㄨВ瀵硅薄
+     *
+     * @param mapperId 鏄犲皠璇彞 ID
+     * @return DataPermission 娉ㄨВ瀵硅薄锛屽鏋滀笉瀛樺湪鍒欒繑鍥� null
+     */
+    public DataPermission getDataPermission(String mapperId) {
+        // 妫�鏌ョ紦瀛樹腑鏄惁鍖呭惈鏄犲皠璇彞 ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
+        if (dataPermissionCacheMap.containsKey(mapperId)) {
+            return dataPermissionCacheMap.get(mapperId);
+        }
+        // 濡傛灉缂撳瓨涓笉鍖呭惈鏄犲皠璇彞 ID 瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄锛屽垯灏濊瘯浣跨敤绫诲悕浣滀负閿煡鎵�
+        String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
+        if (dataPermissionCacheMap.containsKey(clazzName)) {
+            return dataPermissionCacheMap.get(clazzName);
+        }
+        return null;
+    }
+
+    /**
+     * 妫�鏌ョ粰瀹氱殑鏄犲皠璇彞 ID 鏄惁鏈夋晥锛屽嵆鏄惁鑳藉鎵惧埌瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄
+     *
+     * @param mapperId 鏄犲皠璇彞 ID
+     * @return 濡傛灉鎵惧埌瀵瑰簲鐨� DataPermission 娉ㄨВ瀵硅薄锛屽垯杩斿洖 false锛涘惁鍒欒繑鍥� true
+     */
+    public boolean invalid(String mapperId) {
+        return getDataPermission(mapperId) == null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
new file mode 100644
index 0000000..a7cfee5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
@@ -0,0 +1,81 @@
+package org.dromara.common.mybatis.helper;
+
+import cn.hutool.core.convert.Convert;
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.mybatis.enums.DataBaseType;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鏁版嵁搴撳姪鎵�
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class DataBaseHelper {
+
+    private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);
+
+    /**
+     * 鑾峰彇褰撳墠鏁版嵁搴撶被鍨�
+     */
+    public static DataBaseType getDataBaseType() {
+        DataSource dataSource = DS.determineDataSource();
+        try (Connection conn = dataSource.getConnection()) {
+            DatabaseMetaData metaData = conn.getMetaData();
+            String databaseProductName = metaData.getDatabaseProductName();
+            return DataBaseType.find(databaseProductName);
+        } catch (SQLException e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    public static boolean isMySql() {
+        return DataBaseType.MY_SQL == getDataBaseType();
+    }
+
+    public static boolean isOracle() {
+        return DataBaseType.ORACLE == getDataBaseType();
+    }
+
+    public static boolean isPostgerSql() {
+        return DataBaseType.POSTGRE_SQL == getDataBaseType();
+    }
+
+    public static boolean isSqlServer() {
+        return DataBaseType.SQL_SERVER == getDataBaseType();
+    }
+
+    public static String findInSet(Object var1, String var2) {
+        DataBaseType dataBasyType = getDataBaseType();
+        String var = Convert.toStr(var1);
+        if (dataBasyType == DataBaseType.SQL_SERVER) {
+            // charindex(',100,' , ',0,100,101,') <> 0
+            return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
+        } else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
+            // (select position(',100,' in ',0,100,101,')) <> 0
+            return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2);
+        } else if (dataBasyType == DataBaseType.ORACLE) {
+            // instr(',0,100,101,' , ',100,') <> 0
+            return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);
+        }
+        // find_in_set(100 , '0,100,101')
+        return "find_in_set('%s' , %s) <> 0".formatted(var, var2);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鍔犺浇鐨勬暟鎹簱鍚�
+     */
+    public static List<String> getDataSourceNameList() {
+        return new ArrayList<>(DS.getDataSources().keySet());
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
new file mode 100644
index 0000000..932f173
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
@@ -0,0 +1,148 @@
+package org.dromara.common.mybatis.helper;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.context.model.SaStorage;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+import java.util.function.Supplier;
+
+/**
+ * 鏁版嵁鏉冮檺鍔╂墜
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@SuppressWarnings("unchecked cast")
+public class DataPermissionHelper {
+
+    private static final String DATA_PERMISSION_KEY = "data:permission";
+
+    private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
+
+    /**
+     * 浠庝笂涓嬫枃涓幏鍙栨寚瀹氶敭鐨勫彉閲忓�硷紝骞跺皢鍏惰浆鎹负鎸囧畾鐨勭被鍨�
+     *
+     * @param key 鍙橀噺鐨勯敭
+     * @param <T> 鍙橀噺鍊肩殑绫诲瀷
+     * @return 鎸囧畾閿殑鍙橀噺鍊硷紝濡傛灉涓嶅瓨鍦ㄥ垯杩斿洖 null
+     */
+    public static <T> T getVariable(String key) {
+        Map<String, Object> context = getContext();
+        return (T) context.get(key);
+    }
+
+    /**
+     * 鍚戜笂涓嬫枃涓缃寚瀹氶敭鐨勫彉閲忓��
+     *
+     * @param key   瑕佽缃殑鍙橀噺鐨勯敭
+     * @param value 瑕佽缃殑鍙橀噺鍊�
+     */
+    public static void setVariable(String key, Object value) {
+        Map<String, Object> context = getContext();
+        context.put(key, value);
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁鏉冮檺涓婁笅鏂�
+     *
+     * @return 瀛樺偍鍦⊿aStorage涓殑Map瀵硅薄锛岀敤浜庡瓨鍌ㄦ暟鎹潈闄愮浉鍏崇殑涓婁笅鏂囦俊鎭�
+     * @throws NullPointerException 濡傛灉鏁版嵁鏉冮檺涓婁笅鏂囩被鍨嬪紓甯革紝鍒欐姏鍑篘ullPointerException
+     */
+    public static Map<String, Object> getContext() {
+        SaStorage saStorage = SaHolder.getStorage();
+        Object attribute = saStorage.get(DATA_PERMISSION_KEY);
+        if (ObjectUtil.isNull(attribute)) {
+            saStorage.set(DATA_PERMISSION_KEY, new HashMap<>());
+            attribute = saStorage.get(DATA_PERMISSION_KEY);
+        }
+        if (attribute instanceof Map map) {
+            return map;
+        }
+        throw new NullPointerException("data permission context type exception");
+    }
+
+    private static IgnoreStrategy getIgnoreStrategy() {
+        Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
+        if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
+            if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
+                return ignoreStrategy;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 寮�鍚拷鐣ユ暟鎹潈闄�(寮�鍚悗闇�鎵嬪姩璋冪敤 {@link #disableIgnore()} 鍏抽棴)
+     */
+    public static void enableIgnore() {
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNull(ignoreStrategy)) {
+            InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
+        } else {
+            ignoreStrategy.setDataPermission(true);
+        }
+        Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+        reentrantStack.push(reentrantStack.size() + 1);
+    }
+
+    /**
+     * 鍏抽棴蹇界暐鏁版嵁鏉冮檺
+     */
+    public static void disableIgnore() {
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNotNull(ignoreStrategy)) {
+            boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
+                && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
+                && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
+                && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine())
+                && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
+            Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+            boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
+            if (noOtherIgnoreStrategy && empty) {
+                InterceptorIgnoreHelper.clearIgnoreStrategy();
+            } else if (empty) {
+                ignoreStrategy.setDataPermission(false);
+            }
+
+        }
+    }
+
+    /**
+     * 鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static void ignore(Runnable handle) {
+        enableIgnore();
+        try {
+            handle.run();
+        } finally {
+            disableIgnore();
+        }
+    }
+
+    /**
+     * 鍦ㄥ拷鐣ユ暟鎹潈闄愪腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static <T> T ignore(Supplier<T> handle) {
+        enableIgnore();
+        try {
+            return handle.get();
+        } finally {
+            disableIgnore();
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java
new file mode 100644
index 0000000..85a4d0a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java
@@ -0,0 +1,181 @@
+package org.dromara.common.mybatis.interceptor;
+
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
+import com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.delete.Delete;
+import net.sf.jsqlparser.statement.select.PlainSelect;
+import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.statement.select.SetOperationList;
+import net.sf.jsqlparser.statement.update.Update;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.dromara.common.mybatis.handler.PlusDataPermissionHandler;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * 鏁版嵁鏉冮檺鎷︽埅鍣�
+ *
+ * @author Lion Li
+ * @version 3.5.0
+ */
+@Slf4j
+public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor {
+
+    private final PlusDataPermissionHandler dataPermissionHandler;
+
+    /**
+     * 鏋勯�犲嚱鏁帮紝鍒濆鍖� PlusDataPermissionHandler 瀹炰緥
+     *
+     * @param mapperPackage 鎵弿鐨勬槧灏勫櫒鍖�
+     */
+    public PlusDataPermissionInterceptor(String mapperPackage) {
+        this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
+    }
+
+    /**
+     * 鍦ㄦ墽琛屾煡璇箣鍓嶏紝妫�鏌ュ苟澶勭悊鏁版嵁鏉冮檺鐩稿叧閫昏緫
+     *
+     * @param executor      MyBatis 鎵ц鍣ㄥ璞�
+     * @param ms            鏄犲皠璇彞瀵硅薄
+     * @param parameter     鏂规硶鍙傛暟
+     * @param rowBounds     鍒嗛〉瀵硅薄
+     * @param resultHandler 缁撴灉澶勭悊鍣�
+     * @param boundSql      缁戝畾鐨� SQL 瀵硅薄
+     * @throws SQLException 濡傛灉鍙戠敓 SQL 寮傚父
+     */
+    @Override
+    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+        // 妫�鏌ユ槸鍚﹂渶瑕佸拷鐣ユ暟鎹潈闄愬鐞�
+        if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
+            return;
+        }
+        // 妫�鏌ユ槸鍚︾己灏戞湁鏁堢殑鏁版嵁鏉冮檺娉ㄨВ
+        if (dataPermissionHandler.invalid(ms.getId())) {
+            return;
+        }
+        // 瑙f瀽 sql 鍒嗛厤瀵瑰簲鏂规硶
+        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
+        mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
+    }
+
+    /**
+     * 鍦ㄥ噯澶� SQL 璇彞涔嬪墠锛屾鏌ュ苟澶勭悊鏇存柊鍜屽垹闄ゆ搷浣滅殑鏁版嵁鏉冮檺鐩稿叧閫昏緫
+     *
+     * @param sh                 MyBatis StatementHandler 瀵硅薄
+     * @param connection         鏁版嵁搴撹繛鎺ュ璞�
+     * @param transactionTimeout 浜嬪姟瓒呮椂鏃堕棿
+     */
+    @Override
+    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
+        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
+        MappedStatement ms = mpSh.mappedStatement();
+        // 鑾峰彇 SQL 鍛戒护绫诲瀷锛堝銆佸垹銆佹敼銆佹煡锛�
+        SqlCommandType sct = ms.getSqlCommandType();
+
+        // 鍙鐞嗘洿鏂板拰鍒犻櫎鎿嶄綔鐨� SQL 璇彞
+        if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
+            if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
+                return;
+            }
+            // 妫�鏌ユ槸鍚︾己灏戞湁鏁堢殑鏁版嵁鏉冮檺娉ㄨВ
+            if (dataPermissionHandler.invalid(ms.getId())) {
+                return;
+            }
+            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
+            mpBs.sql(parserMulti(mpBs.sql(), ms.getId()));
+        }
+    }
+
+    /**
+     * 澶勭悊 SELECT 鏌ヨ璇彞涓殑 WHERE 鏉′欢
+     *
+     * @param select SELECT 鏌ヨ瀵硅薄
+     * @param index  鏌ヨ璇彞鐨勭储寮�
+     * @param sql    鏌ヨ璇彞
+     * @param obj    WHERE 鏉′欢鍙傛暟
+     */
+    @Override
+    protected void processSelect(Select select, int index, String sql, Object obj) {
+        if (select instanceof PlainSelect) {
+            this.setWhere((PlainSelect) select, (String) obj);
+        } else if (select instanceof SetOperationList setOperationList) {
+            List<Select> selectBodyList = setOperationList.getSelects();
+            selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
+        }
+    }
+
+    /**
+     * 澶勭悊 UPDATE 璇彞涓殑 WHERE 鏉′欢
+     *
+     * @param update UPDATE 鏌ヨ瀵硅薄
+     * @param index  鏌ヨ璇彞鐨勭储寮�
+     * @param sql    鏌ヨ璇彞
+     * @param obj    WHERE 鏉′欢鍙傛暟
+     */
+    @Override
+    protected void processUpdate(Update update, int index, String sql, Object obj) {
+        Expression sqlSegment = dataPermissionHandler.getSqlSegment(update.getWhere(), (String) obj, false);
+        if (null != sqlSegment) {
+            update.setWhere(sqlSegment);
+        }
+    }
+
+    /**
+     * 澶勭悊 DELETE 璇彞涓殑 WHERE 鏉′欢
+     *
+     * @param delete DELETE 鏌ヨ瀵硅薄
+     * @param index  鏌ヨ璇彞鐨勭储寮�
+     * @param sql    鏌ヨ璇彞
+     * @param obj    WHERE 鏉′欢鍙傛暟
+     */
+    @Override
+    protected void processDelete(Delete delete, int index, String sql, Object obj) {
+        Expression sqlSegment = dataPermissionHandler.getSqlSegment(delete.getWhere(), (String) obj, false);
+        if (null != sqlSegment) {
+            delete.setWhere(sqlSegment);
+        }
+    }
+
+    /**
+     * 璁剧疆 SELECT 璇彞鐨� WHERE 鏉′欢
+     *
+     * @param plainSelect       SELECT 鏌ヨ瀵硅薄
+     * @param mappedStatementId 鏄犲皠璇彞鐨� ID
+     */
+    protected void setWhere(PlainSelect plainSelect, String mappedStatementId) {
+        Expression sqlSegment = dataPermissionHandler.getSqlSegment(plainSelect.getWhere(), mappedStatementId, true);
+        if (null != sqlSegment) {
+            plainSelect.setWhere(sqlSegment);
+        }
+    }
+
+    /**
+     * 鏋勫缓琛ㄨ揪寮忥紝鐢ㄤ簬澶勭悊琛ㄧ殑鏁版嵁鏉冮檺
+     *
+     * @param table        琛ㄥ璞�
+     * @param where        WHERE 鏉′欢琛ㄨ揪寮�
+     * @param whereSegment WHERE 鏉′欢鐗囨
+     * @return 鏋勫缓鐨勮〃杈惧紡
+     */
+    @Override
+    public Expression buildTableExpression(Table table, Expression where, String whereSegment) {
+        // 鍙湁鏂扮増鏁版嵁鏉冮檺澶勭悊鍣ㄦ墠浼氭墽琛屽埌杩欓噷
+        final MultiDataPermissionHandler handler = (MultiDataPermissionHandler) dataPermissionHandler;
+        return handler.getSqlSegment(table, where, whereSegment);
+    }
+}
+
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..cc625da
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.mybatis.config.MybatisPlusConfig
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
new file mode 100644
index 0000000..f5dc637
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
@@ -0,0 +1,33 @@
+# 鍐呯疆閰嶇疆 涓嶅厑璁镐慨鏀� 濡傞渶淇敼璇峰湪 nacos 涓婂啓鐩稿悓閰嶇疆瑕嗙洊
+# MyBatisPlus閰嶇疆
+# https://baomidou.com/config/
+mybatis-plus:
+  # 鍚姩鏃舵槸鍚︽鏌� MyBatis XML 鏂囦欢鐨勫瓨鍦紝榛樿涓嶆鏌�
+  checkConfigLocation: false
+  configuration:
+    # 鑷姩椹煎嘲鍛藉悕瑙勫垯锛坈amel case锛夋槧灏�
+    mapUnderscoreToCamelCase: true
+    # MyBatis 鑷姩鏄犲皠绛栫暐
+    # NONE锛氫笉鍚敤 PARTIAL锛氬彧瀵归潪宓屽 resultMap 鑷姩鏄犲皠 FULL锛氬鎵�鏈� resultMap 鑷姩鏄犲皠
+    autoMappingBehavior: FULL
+    # MyBatis 鑷姩鏄犲皠鏃舵湭鐭ュ垪鎴栨湭鐭ュ睘鎬у鐞嗙瓥
+    # NONE锛氫笉鍋氬鐞� WARNING锛氭墦鍗扮浉鍏宠鍛� FAILING锛氭姏鍑哄紓甯稿拰璇︾粏淇℃伅
+    autoMappingUnknownColumnBehavior: NONE
+    # 鏇磋缁嗙殑鏃ュ織杈撳嚭 浼氭湁鎬ц兘鎹熻�� org.apache.ibatis.logging.stdout.StdOutImpl
+    # 鍏抽棴鏃ュ織璁板綍 (鍙崟绾娇鐢� p6spy 鍒嗘瀽) org.apache.ibatis.logging.nologging.NoLoggingImpl
+    # 榛樿鏃ュ織杈撳嚭 org.apache.ibatis.logging.slf4j.Slf4jImpl
+    logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+  global-config:
+    # 鏄惁鎵撳嵃 Logo banner
+    banner: true
+    dbConfig:
+      # 涓婚敭绫诲瀷
+      # AUTO 鑷 NONE 绌� INPUT 鐢ㄦ埛杈撳叆 ASSIGN_ID 闆姳 ASSIGN_UUID 鍞竴 UUID
+      idType: ASSIGN_ID
+      # 閫昏緫宸插垹闄ゅ��(妗嗘灦琛ㄥ潎浣跨敤姝ゅ�� 绂佹闅忔剰淇敼)
+      logicDeleteValue: 2
+      # 閫昏緫鏈垹闄ゅ��
+      logicNotDeleteValue: 0
+      insertStrategy: NOT_NULL
+      updateStrategy: NOT_NULL
+      whereStrategy: NOT_NULL
diff --git a/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties
new file mode 100644
index 0000000..f3ed7d8
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties
@@ -0,0 +1,20 @@
+# p6spy 鎬ц兘鍒嗘瀽鎻掍欢閰嶇疆鏂囦欢
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 鑷畾涔夋棩蹇楁墦鍗�
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#鏃ュ織杈撳嚭鍒版帶鍒跺彴
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 浣跨敤鏃ュ織绯荤粺璁板綍 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 鍙栨秷JDBC URL鍓嶇紑
+useprefix=true
+# 閰嶇疆璁板綍 Log 渚嬪,鍙幓鎺夌殑缁撴灉闆嗘湁error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 鏃ユ湡鏍煎紡
+dateformat=yyyy-MM-dd HH:mm:ss
+# SQL璇彞鎵撳嵃鏃堕棿鏍煎紡
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
+# 鏄惁杩囨护 Log
+filter=true
+# 杩囨护 Log 鏃舵墍鎺掗櫎鐨� sql 鍏抽敭瀛楋紝浠ラ�楀彿鍒嗛殧
+exclude=
diff --git a/eims/ruoyi-common/ruoyi-common-oss/pom.xml b/eims/ruoyi-common/ruoyi-common-oss/pom.xml
new file mode 100644
index 0000000..18d004f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-oss</artifactId>
+
+    <description>
+        ruoyi-common-oss oss鏈嶅姟
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <!--  AWS SDK for Java 2.x  -->
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>s3</artifactId>
+            <exclusions>
+                <!-- 灏嗗熀浜� Netty 鐨� HTTP 瀹㈡埛绔粠绫昏矾寰勪腑绉婚櫎 -->
+                <exclusion>
+                    <groupId>software.amazon.awssdk</groupId>
+                    <artifactId>netty-nio-client</artifactId>
+                </exclusion>
+                <!-- 灏嗗熀浜� CRT 鐨� HTTP 瀹㈡埛绔粠绫昏矾寰勪腑绉婚櫎 -->
+                <exclusion>
+                    <groupId>software.amazon.awssdk</groupId>
+                    <artifactId>aws-crt-client</artifactId>
+                </exclusion>
+                <!-- 灏嗗熀浜� Apache 鐨� HTTP 瀹㈡埛绔粠绫昏矾寰勪腑绉婚櫎 -->
+                <exclusion>
+                    <groupId>software.amazon.awssdk</groupId>
+                    <artifactId>apache-client</artifactId>
+                </exclusion>
+                <!-- 灏嗛厤缃熀浜� URL 杩炴帴鐨� HTTP 瀹㈡埛绔粠绫昏矾寰勪腑绉婚櫎 -->
+                <exclusion>
+                    <groupId>software.amazon.awssdk</groupId>
+                    <artifactId>url-connection-client</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 浣跨敤AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔� -->
+        <dependency>
+            <groupId>software.amazon.awssdk.crt</groupId>
+            <artifactId>aws-crt</artifactId>
+        </dependency>
+
+        <!-- 鍩轰簬 AWS CRT 鐨� S3 瀹㈡埛绔殑鎬ц兘澧炲己鐨� S3 浼犺緭绠$悊鍣� -->
+        <dependency>
+            <groupId>software.amazon.awssdk</groupId>
+            <artifactId>s3-transfer-manager</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java
new file mode 100644
index 0000000..9d8db93
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java
@@ -0,0 +1,40 @@
+package org.dromara.common.oss.constant;
+
+import org.dromara.common.core.constant.GlobalConstants;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 瀵硅薄瀛樺偍甯搁噺
+ *
+ * @author Lion Li
+ */
+public interface OssConstant {
+
+    /**
+     * 榛樿閰嶇疆KEY
+     */
+    String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config";
+
+    /**
+     * 棰勮鍒楄〃璧勬簮寮�鍏矺ey
+     */
+    String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";
+
+    /**
+     * 绯荤粺鏁版嵁ids
+     */
+    List<Long> SYSTEM_DATA_IDS = Arrays.asList(1L, 2L, 3L, 4L);
+
+    /**
+     * 浜戞湇鍔″晢
+     */
+    String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"};
+
+    /**
+     * https 鐘舵��
+     */
+    String IS_HTTPS = "Y";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
new file mode 100644
index 0000000..5e300da
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
@@ -0,0 +1,595 @@
+package org.dromara.common.oss.core;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.IdUtil;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.oss.constant.OssConstant;
+import org.dromara.common.oss.entity.UploadResult;
+import org.dromara.common.oss.enumd.AccessPolicyType;
+import org.dromara.common.oss.enumd.PolicyType;
+import org.dromara.common.oss.exception.OssException;
+import org.dromara.common.oss.properties.OssProperties;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.core.ResponseInputStream;
+import software.amazon.awssdk.core.async.AsyncRequestBody;
+import software.amazon.awssdk.core.async.AsyncResponseTransformer;
+import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3AsyncClient;
+import software.amazon.awssdk.services.s3.S3Configuration;
+import software.amazon.awssdk.services.s3.model.GetObjectResponse;
+import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
+import software.amazon.awssdk.services.s3.model.S3Exception;
+import software.amazon.awssdk.services.s3.presigner.S3Presigner;
+import software.amazon.awssdk.transfer.s3.S3TransferManager;
+import software.amazon.awssdk.transfer.s3.model.*;
+import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+
+/**
+ * S3 瀛樺偍鍗忚 鎵�鏈夊吋瀹筍3鍗忚鐨勪簯鍘傚晢鍧囨敮鎸�
+ * 闃块噷浜� 鑵捐浜� 涓冪墰浜� minio
+ *
+ * @author AprilWind
+ */
+public class OssClient {
+
+    /**
+     * 鏈嶅姟鍟�
+     */
+    private final String configKey;
+
+    /**
+     * 閰嶇疆灞炴��
+     */
+    private final OssProperties properties;
+
+    /**
+     * Amazon S3 寮傛瀹㈡埛绔�
+     */
+    private final S3AsyncClient client;
+
+    /**
+     * 鐢ㄤ簬绠$悊 S3 鏁版嵁浼犺緭鐨勯珮绾у伐鍏�
+     */
+    private final S3TransferManager transferManager;
+
+    /**
+     * AWS S3 棰勭鍚� URL 鐨勭敓鎴愬櫒
+     */
+    private final S3Presigner presigner;
+
+    /**
+     * 鏋勯�犳柟娉�
+     *
+     * @param configKey     閰嶇疆閿�
+     * @param ossProperties Oss閰嶇疆灞炴��
+     */
+    public OssClient(String configKey, OssProperties ossProperties) {
+        this.configKey = configKey;
+        this.properties = ossProperties;
+        try {
+            // 鍒涘缓 AWS 璁よ瘉淇℃伅
+            StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
+                AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
+
+            //MinIO 浣跨敤 HTTPS 闄愬埗浣跨敤鍩熷悕璁块棶锛岀珯鐐瑰~鍩熷悕銆傞渶瑕佸惎鐢ㄨ矾寰勬牱寮忚闂�
+            boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
+
+            //鍒涘缓AWS鍩轰簬 CRT 鐨� S3 瀹㈡埛绔�
+            this.client = S3AsyncClient.crtBuilder()
+                .credentialsProvider(credentialsProvider)
+                .endpointOverride(URI.create(getEndpoint()))
+                .region(of())
+                .targetThroughputInGbps(20.0)
+                .minimumPartSizeInBytes(10 * 1025 * 1024L)
+                .checksumValidationEnabled(false)
+                .forcePathStyle(isStyle)
+                .build();
+
+            //AWS鍩轰簬 CRT 鐨� S3 AsyncClient 瀹炰緥鐢ㄤ綔 S3 浼犺緭绠$悊鍣ㄧ殑搴曞眰瀹㈡埛绔�
+            this.transferManager = S3TransferManager.builder().s3Client(this.client).build();
+
+            // 鍒涘缓 S3 閰嶇疆瀵硅薄
+            S3Configuration config = S3Configuration.builder().chunkedEncodingEnabled(false)
+                .pathStyleAccessEnabled(isStyle).build();
+
+            // 鍒涘缓 棰勭鍚� URL 鐨勭敓鎴愬櫒 瀹炰緥锛岀敤浜庣敓鎴� S3 棰勭鍚� URL
+            this.presigner = S3Presigner.builder()
+                .region(of())
+                .credentialsProvider(credentialsProvider)
+                .endpointOverride(URI.create(getDomain()))
+                .serviceConfiguration(config)
+                .build();
+
+            // 鍒涘缓瀛樺偍妗�
+            createBucket();
+        } catch (Exception e) {
+            if (e instanceof OssException) {
+                throw e;
+            }
+            throw new OssException("閰嶇疆閿欒! 璇锋鏌ョ郴缁熼厤缃�:[" + e.getMessage() + "]");
+        }
+    }
+
+    /**
+     * 鍚屾鍒涘缓瀛樺偍妗�
+     * 濡傛灉瀛樺偍妗朵笉瀛樺湪锛屼細杩涜鍒涘缓锛涘鏋滃瓨鍌ㄦ《瀛樺湪锛屼笉鎵ц浠讳綍鎿嶄綔
+     *
+     * @throws OssException 褰撳垱寤哄瓨鍌ㄦ《鏃跺彂鐢熷紓甯告椂鎶涘嚭
+     */
+    public void createBucket() {
+        String bucketName = properties.getBucketName();
+        try {
+            // 灏濊瘯鑾峰彇瀛樺偍妗剁殑淇℃伅
+            client.headBucket(
+                    x -> x.bucket(bucketName)
+                        .build())
+                .join();
+        } catch (Exception ex) {
+            if (ex.getCause() instanceof NoSuchBucketException) {
+                try {
+                    // 瀛樺偍妗朵笉瀛樺湪锛屽皾璇曞垱寤哄瓨鍌ㄦ《
+                    client.createBucket(
+                            x -> x.bucket(bucketName))
+                        .join();
+
+                    // 璁剧疆瀛樺偍妗剁殑璁块棶绛栫暐锛圔ucket Policy锛�
+                    client.putBucketPolicy(
+                            x -> x.bucket(bucketName)
+                                .policy(getPolicy(bucketName, getAccessPolicy().getPolicyType())))
+                        .join();
+                } catch (S3Exception e) {
+                    // 瀛樺偍妗跺垱寤烘垨绛栫暐璁剧疆澶辫触
+                    throw new OssException("鍒涘缓Bucket澶辫触, 璇锋牳瀵归厤缃俊鎭�:[" + e.getMessage() + "]");
+                }
+            } else {
+                throw new OssException("鍒ゆ柇Bucket鏄惁瀛樺湪澶辫触锛岃鏍稿閰嶇疆淇℃伅:[" + ex.getMessage() + "]");
+            }
+        }
+    }
+
+    /**
+     * 涓婁紶鏂囦欢鍒� Amazon S3锛屽苟杩斿洖涓婁紶缁撴灉
+     *
+     * @param filePath    鏈湴鏂囦欢璺緞
+     * @param key         鍦� Amazon S3 涓殑瀵硅薄閿�
+     * @param md5Digest   鏈湴鏂囦欢鐨� MD5 鍝堝笇鍊硷紙鍙�夛級
+     * @param contentType 鏂囦欢鍐呭绫诲瀷
+     * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
+     * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public UploadResult upload(Path filePath, String key, String md5Digest, String contentType) {
+        try {
+            // 鏋勫缓涓婁紶璇锋眰瀵硅薄
+            FileUpload fileUpload = transferManager.uploadFile(
+                x -> x.putObjectRequest(
+                        y -> y.bucket(properties.getBucketName())
+                            .key(key)
+                            .contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
+                            .contentType(contentType)
+                            .acl(getAccessPolicy().getObjectCannedACL())
+                            .build())
+                    .addTransferListener(LoggingTransferListener.create())
+                    .source(filePath).build());
+
+            // 绛夊緟涓婁紶瀹屾垚骞惰幏鍙栦笂浼犵粨鏋�
+            CompletedFileUpload uploadResult = fileUpload.completionFuture().join();
+            String eTag = uploadResult.response().eTag();
+
+            // 鎻愬彇涓婁紶缁撴灉涓殑 ETag锛屽苟鏋勫缓涓�涓嚜瀹氫箟鐨� UploadResult 瀵硅薄
+            return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build();
+        } catch (Exception e) {
+            // 鎹曡幏寮傚父骞舵姏鍑鸿嚜瀹氫箟寮傚父
+            throw new OssException("涓婁紶鏂囦欢澶辫触锛岃妫�鏌ラ厤缃俊鎭�:[" + e.getMessage() + "]");
+        } finally {
+            // 鏃犺涓婁紶鏄惁鎴愬姛锛屾渶缁堥兘浼氬垹闄や复鏃舵枃浠�
+            FileUtils.del(filePath);
+        }
+    }
+
+    /**
+     * 涓婁紶 InputStream 鍒� Amazon S3
+     *
+     * @param inputStream 瑕佷笂浼犵殑杈撳叆娴�
+     * @param key         鍦� Amazon S3 涓殑瀵硅薄閿�
+     * @param length      杈撳叆娴佺殑闀垮害
+     * @param contentType 鏂囦欢鍐呭绫诲瀷
+     * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
+     * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {
+        // 濡傛灉杈撳叆娴佷笉鏄� ByteArrayInputStream锛屽垯灏嗗叾璇诲彇涓哄瓧鑺傛暟缁勫啀鍒涘缓 ByteArrayInputStream
+        if (!(inputStream instanceof ByteArrayInputStream)) {
+            inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
+        }
+        try {
+            // 鍒涘缓寮傛璇锋眰浣擄紙length濡傛灉涓虹┖浼氭姤閿欙級
+            BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(length);
+
+            // 浣跨敤 transferManager 杩涜涓婁紶
+            Upload upload = transferManager.upload(
+                x -> x.requestBody(body)
+                    .putObjectRequest(
+                        y -> y.bucket(properties.getBucketName())
+                            .key(key)
+                            .contentType(contentType)
+                            .acl(getAccessPolicy().getObjectCannedACL())
+                            .build())
+                    .build());
+
+            // 灏嗚緭鍏ユ祦鍐欏叆璇锋眰浣�
+            body.writeInputStream(inputStream);
+
+            // 绛夊緟鏂囦欢涓婁紶鎿嶄綔瀹屾垚
+            CompletedUpload uploadResult = upload.completionFuture().join();
+            String eTag = uploadResult.response().eTag();
+
+            // 鎻愬彇涓婁紶缁撴灉涓殑 ETag锛屽苟鏋勫缓涓�涓嚜瀹氫箟鐨� UploadResult 瀵硅薄
+            return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build();
+        } catch (Exception e) {
+            throw new OssException("涓婁紶鏂囦欢澶辫触锛岃妫�鏌ラ厤缃俊鎭�:[" + e.getMessage() + "]");
+        }
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢浠� Amazon S3 鍒颁复鏃剁洰褰�
+     *
+     * @param path 鏂囦欢鍦� Amazon S3 涓殑瀵硅薄閿�
+     * @return 涓嬭浇鍚庣殑鏂囦欢鍦ㄦ湰鍦扮殑涓存椂璺緞
+     * @throws OssException 濡傛灉涓嬭浇澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public Path fileDownload(String path) {
+        // 鏋勫缓涓存椂鏂囦欢
+        Path tempFilePath = FileUtils.createTempFile().toPath();
+        // 浣跨敤 S3TransferManager 涓嬭浇鏂囦欢
+        FileDownload downloadFile = transferManager.downloadFile(
+            x -> x.getObjectRequest(
+                    y -> y.bucket(properties.getBucketName())
+                        .key(removeBaseUrl(path))
+                        .build())
+                .addTransferListener(LoggingTransferListener.create())
+                .destination(tempFilePath)
+                .build());
+        // 绛夊緟鏂囦欢涓嬭浇鎿嶄綔瀹屾垚
+        downloadFile.completionFuture().join();
+        return tempFilePath;
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢浠� Amazon S3 鍒� 杈撳嚭娴�
+     *
+     * @param key 鏂囦欢鍦� Amazon S3 涓殑瀵硅薄閿�
+     * @param out 杈撳嚭娴�
+     * @return 杈撳嚭娴佷腑鍐欏叆鐨勫瓧鑺傛暟锛堥暱搴︼級
+     * @throws OssException 濡傛灉涓嬭浇澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public long download(String key, OutputStream out) {
+        try {
+            // 鏋勫缓涓嬭浇璇锋眰
+            DownloadRequest<ResponseInputStream<GetObjectResponse>> downloadRequest = DownloadRequest.builder()
+                // 鏂囦欢瀵硅薄
+                .getObjectRequest(y -> y.bucket(properties.getBucketName())
+                    .key(key)
+                    .build())
+                .addTransferListener(LoggingTransferListener.create())
+                // 浣跨敤璁㈤槄杞崲鍣�
+                .responseTransformer(AsyncResponseTransformer.toBlockingInputStream())
+                .build();
+            // 浣跨敤 S3TransferManager 涓嬭浇鏂囦欢
+            Download<ResponseInputStream<GetObjectResponse>> responseFuture = transferManager.download(downloadRequest);
+            // 杈撳嚭鍒版祦涓�
+            try (ResponseInputStream<GetObjectResponse> responseStream = responseFuture.completionFuture().join().result()) { // auto-closeable stream
+                return responseStream.transferTo(out); // 闃诲璋冪敤绾跨▼ blocks the calling thread
+            }
+        } catch (Exception e) {
+            throw new OssException("鏂囦欢涓嬭浇澶辫触锛岄敊璇俊鎭�:[" + e.getMessage() + "]");
+        }
+    }
+
+    /**
+     * 鍒犻櫎浜戝瓨鍌ㄦ湇鍔′腑鎸囧畾璺緞涓嬫枃浠�
+     *
+     * @param path 鎸囧畾璺緞
+     */
+    public void delete(String path) {
+        try {
+            client.deleteObject(
+                x -> x.bucket(properties.getBucketName())
+                    .key(removeBaseUrl(path))
+                    .build());
+        } catch (Exception e) {
+            throw new OssException("鍒犻櫎鏂囦欢澶辫触锛岃妫�鏌ラ厤缃俊鎭�:[" + e.getMessage() + "]");
+        }
+    }
+
+    /**
+     * 鑾峰彇绉佹湁URL閾炬帴
+     *
+     * @param objectKey 瀵硅薄KEY
+     * @param second    鎺堟潈鏃堕棿
+     */
+    public String getPrivateUrl(String objectKey, Integer second) {
+        // 浣跨敤 AWS S3 棰勭鍚� URL 鐨勭敓鎴愬櫒 鑾峰彇瀵硅薄鐨勯绛惧悕 URL
+        URL url = presigner.presignGetObject(
+                x -> x.signatureDuration(Duration.ofSeconds(second))
+                    .getObjectRequest(
+                        y -> y.bucket(properties.getBucketName())
+                            .key(objectKey)
+                            .build())
+                    .build())
+            .url();
+        return url.toString();
+    }
+
+    /**
+     * 涓婁紶 byte[] 鏁版嵁鍒� Amazon S3锛屼娇鐢ㄦ寚瀹氱殑鍚庣紑鏋勯�犲璞¢敭銆�
+     *
+     * @param data   瑕佷笂浼犵殑 byte[] 鏁版嵁
+     * @param suffix 瀵硅薄閿殑鍚庣紑
+     * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
+     * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public UploadResult uploadSuffix(byte[] data, String suffix) {
+        return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
+    }
+
+    /**
+     * 涓婁紶 InputStream 鍒� Amazon S3锛屼娇鐢ㄦ寚瀹氱殑鍚庣紑鏋勯�犲璞¢敭銆�
+     *
+     * @param inputStream 瑕佷笂浼犵殑杈撳叆娴�
+     * @param suffix      瀵硅薄閿殑鍚庣紑
+     * @param length      杈撳叆娴佺殑闀垮害
+     * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
+     * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length) {
+        return upload(inputStream, getPath(properties.getPrefix(), suffix), length, FileUtils.getMimeType(suffix));
+    }
+
+    /**
+     * 涓婁紶鏂囦欢鍒� Amazon S3锛屼娇鐢ㄦ寚瀹氱殑鍚庣紑鏋勯�犲璞¢敭
+     *
+     * @param file   瑕佷笂浼犵殑鏂囦欢
+     * @param suffix 瀵硅薄閿殑鍚庣紑
+     * @return UploadResult 鍖呭惈涓婁紶鍚庣殑鏂囦欢淇℃伅
+     * @throws OssException 濡傛灉涓婁紶澶辫触锛屾姏鍑鸿嚜瀹氫箟寮傚父
+     */
+    public UploadResult uploadSuffix(File file, String suffix) {
+        return upload(file.toPath(), getPath(properties.getPrefix(), suffix), null, FileUtils.getMimeType(suffix));
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢杈撳叆娴�
+     *
+     * @param path 瀹屾暣鏂囦欢璺緞
+     * @return 杈撳叆娴�
+     */
+    public InputStream getObjectContent(String path) throws IOException {
+        // 涓嬭浇鏂囦欢鍒颁复鏃剁洰褰�
+        Path tempFilePath = fileDownload(path);
+        // 鍒涘缓杈撳叆娴�
+        InputStream inputStream = Files.newInputStream(tempFilePath);
+        // 鍒犻櫎涓存椂鏂囦欢
+        FileUtils.del(tempFilePath);
+        // 杩斿洖瀵硅薄鍐呭鐨勮緭鍏ユ祦
+        return inputStream;
+    }
+
+    /**
+     * 鑾峰彇 S3 瀹㈡埛绔殑缁堢鐐� URL
+     *
+     * @return 缁堢鐐� URL
+     */
+    public String getEndpoint() {
+        // 鏍规嵁閰嶇疆鏂囦欢涓殑鏄惁浣跨敤 HTTPS锛岃缃崗璁ご閮�
+        String header = getIsHttps();
+        // 鎷兼帴鍗忚澶撮儴鍜岀粓绔偣锛屽緱鍒板畬鏁寸殑缁堢鐐� URL
+        return header + properties.getEndpoint();
+    }
+
+    /**
+     * 鑾峰彇 S3 瀹㈡埛绔殑缁堢鐐� URL锛堣嚜瀹氫箟鍩熷悕锛�
+     *
+     * @return 缁堢鐐� URL
+     */
+    public String getDomain() {
+        // 浠庨厤缃腑鑾峰彇鍩熷悕銆佺粓绔偣銆佹槸鍚︿娇鐢� HTTPS 绛変俊鎭�
+        String domain = properties.getDomain();
+        String endpoint = properties.getEndpoint();
+        String header = getIsHttps();
+
+        // 濡傛灉鏄簯鏈嶅姟鍟嗭紝鐩存帴杩斿洖鍩熷悕鎴栫粓绔偣
+        if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) {
+            return StringUtils.isNotEmpty(domain) ? header + domain : header + endpoint;
+        }
+
+        // 濡傛灉鏄� MinIO锛屽鐞嗗煙鍚嶅苟杩斿洖
+        if (StringUtils.isNotEmpty(domain)) {
+            return domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP) ? domain : header + domain;
+        }
+
+        // 杩斿洖缁堢鐐�
+        return header + endpoint;
+    }
+
+    /**
+     * 鏍规嵁浼犲叆鐨� region 鍙傛暟杩斿洖鐩稿簲鐨� AWS 鍖哄煙
+     * 濡傛灉 region 鍙傛暟闈炵┖锛屼娇鐢� Region.of 鏂规硶鍒涘缓骞惰繑鍥炲搴旂殑 AWS 鍖哄煙瀵硅薄
+     * 濡傛灉 region 鍙傛暟涓虹┖锛岃繑鍥炰竴涓粯璁ょ殑 AWS 鍖哄煙锛堜緥濡傦紝us-east-1锛夛紝浣滀负骞挎硾鏀寔鐨勫尯鍩�
+     *
+     * @return 瀵瑰簲鐨� AWS 鍖哄煙瀵硅薄锛屾垨鑰呴粯璁ょ殑骞挎硾鏀寔鐨勫尯鍩燂紙us-east-1锛�
+     */
+    public Region of() {
+        //AWS 鍖哄煙瀛楃涓�
+        String region = properties.getRegion();
+        // 濡傛灉 region 鍙傛暟闈炵┖锛屼娇鐢� Region.of 鏂规硶鍒涘缓瀵瑰簲鐨� AWS 鍖哄煙瀵硅薄锛屽惁鍒欒繑鍥為粯璁ゅ尯鍩�
+        return StringUtils.isNotEmpty(region) ? Region.of(region) : Region.US_EAST_1;
+    }
+
+    /**
+     * 鑾峰彇浜戝瓨鍌ㄦ湇鍔$殑URL
+     *
+     * @return 鏂囦欢璺緞
+     */
+    public String getUrl() {
+        String domain = properties.getDomain();
+        String endpoint = properties.getEndpoint();
+        String header = getIsHttps();
+        // 浜戞湇鍔″晢鐩存帴杩斿洖
+        if (StringUtils.containsAny(endpoint, OssConstant.CLOUD_SERVICE)) {
+            return header + (StringUtils.isNotEmpty(domain) ? domain : properties.getBucketName() + "." + endpoint);
+        }
+        // MinIO 鍗曠嫭澶勭悊
+        if (StringUtils.isNotEmpty(domain)) {
+            // 濡傛灉 domain 浠� "https://" 鎴� "http://" 寮�澶�
+            return (domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP)) ?
+                domain + StringUtils.SLASH + properties.getBucketName() : header + domain + StringUtils.SLASH + properties.getBucketName();
+        }
+        return header + endpoint + StringUtils.SLASH + properties.getBucketName();
+    }
+
+    /**
+     * 鐢熸垚涓�涓鍚堢壒瀹氳鍒欑殑銆佸敮涓�鐨勬枃浠惰矾寰勩�傞�氳繃浣跨敤鏃ユ湡銆乁UID銆佸墠缂�鍜屽悗缂�绛夊厓绱犵殑缁勫悎锛岀‘淇濅簡鏂囦欢璺緞鐨勭嫭涓�鏃犱簩鎬�
+     *
+     * @param prefix 鍓嶇紑
+     * @param suffix 鍚庣紑
+     * @return 鏂囦欢璺緞
+     */
+    public String getPath(String prefix, String suffix) {
+        // 鐢熸垚uuid
+        String uuid = IdUtil.fastSimpleUUID();
+        // 鐢熸垚鏃ユ湡璺緞
+        String datePath = DateUtils.datePath();
+        // 鎷兼帴璺緞
+        String path = StringUtils.isNotEmpty(prefix) ?
+            prefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid : datePath + StringUtils.SLASH + uuid;
+        return path + suffix;
+    }
+
+    /**
+     * 绉婚櫎璺緞涓殑鍩虹URL閮ㄥ垎锛屽緱鍒扮浉瀵硅矾寰�
+     *
+     * @param path 瀹屾暣鐨勮矾寰勶紝鍖呮嫭鍩虹URL鍜岀浉瀵硅矾寰�
+     * @return 鍘婚櫎鍩虹URL鍚庣殑鐩稿璺緞
+     */
+    public String removeBaseUrl(String path) {
+        return path.replace(getUrl() + StringUtils.SLASH, "");
+    }
+
+    /**
+     * 鏈嶅姟鍟�
+     */
+    public String getConfigKey() {
+        return configKey;
+    }
+
+    /**
+     * 鑾峰彇鏄惁浣跨敤 HTTPS 鐨勯厤缃紝骞惰繑鍥炵浉搴旂殑鍗忚澶撮儴銆�
+     *
+     * @return 鍗忚澶撮儴锛屾牴鎹槸鍚︿娇鐢� HTTPS 杩斿洖 "https://" 鎴� "http://"
+     */
+    public String getIsHttps() {
+        return OssConstant.IS_HTTPS.equals(properties.getIsHttps()) ? Constants.HTTPS : Constants.HTTP;
+    }
+
+    /**
+     * 妫�鏌ラ厤缃槸鍚︾浉鍚�
+     */
+    public boolean checkPropertiesSame(OssProperties properties) {
+        return this.properties.equals(properties);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠妗舵潈闄愮被鍨�
+     *
+     * @return 褰撳墠妗舵潈闄愮被鍨媍ode
+     */
+    public AccessPolicyType getAccessPolicy() {
+        return AccessPolicyType.getByType(properties.getAccessPolicy());
+    }
+
+    /**
+     * 鐢熸垚 AWS S3 瀛樺偍妗惰闂瓥鐣�
+     *
+     * @param bucketName 瀛樺偍妗�
+     * @param policyType 妗剁瓥鐣ョ被鍨�
+     * @return 绗﹀悎 AWS S3 瀛樺偍妗惰闂瓥鐣ユ牸寮忕殑瀛楃涓�
+     */
+    private static String getPolicy(String bucketName, PolicyType policyType) {
+        String policy = switch (policyType) {
+            case WRITE -> """
+                {
+                  "Version": "2012-10-17",
+                  "Statement": []
+                }
+                """;
+            case READ_WRITE -> """
+                {
+                  "Version": "2012-10-17",
+                  "Statement": [
+                    {
+                      "Effect": "Allow",
+                      "Principal": "*",
+                      "Action": [
+                        "s3:GetBucketLocation",
+                        "s3:ListBucket",
+                        "s3:ListBucketMultipartUploads"
+                      ],
+                      "Resource": "arn:aws:s3:::bucketName"
+                    },
+                    {
+                      "Effect": "Allow",
+                      "Principal": "*",
+                      "Action": [
+                        "s3:AbortMultipartUpload",
+                        "s3:DeleteObject",
+                        "s3:GetObject",
+                        "s3:ListMultipartUploadParts",
+                        "s3:PutObject"
+                      ],
+                      "Resource": "arn:aws:s3:::bucketName/*"
+                    }
+                  ]
+                }
+                """;
+            case READ -> """
+                {
+                  "Version": "2012-10-17",
+                  "Statement": [
+                    {
+                      "Effect": "Allow",
+                      "Principal": "*",
+                      "Action": ["s3:GetBucketLocation"],
+                      "Resource": "arn:aws:s3:::bucketName"
+                    },
+                    {
+                      "Effect": "Deny",
+                      "Principal": "*",
+                      "Action": ["s3:ListBucket"],
+                      "Resource": "arn:aws:s3:::bucketName"
+                    },
+                    {
+                      "Effect": "Allow",
+                      "Principal": "*",
+                      "Action": "s3:GetObject",
+                      "Resource": "arn:aws:s3:::bucketName/*"
+                    }
+                  ]
+                }
+                """;
+        };
+        return policy.replaceAll("bucketName", bucketName);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java
new file mode 100644
index 0000000..81a18e6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java
@@ -0,0 +1,30 @@
+package org.dromara.common.oss.entity;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * 涓婁紶杩斿洖浣�
+ *
+ * @author Lion Li
+ */
+@Data
+@Builder
+public class UploadResult {
+
+    /**
+     * 鏂囦欢璺緞
+     */
+    private String url;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String filename;
+
+    /**
+     * 宸蹭笂浼犲璞$殑瀹炰綋鏍囪锛堢敤鏉ユ牎楠屾枃浠讹級
+     */
+    private String eTag;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java
new file mode 100644
index 0000000..6d39133
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java
@@ -0,0 +1,61 @@
+package org.dromara.common.oss.enumd;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import software.amazon.awssdk.services.s3.model.BucketCannedACL;
+import software.amazon.awssdk.services.s3.model.ObjectCannedACL;
+
+/**
+ * 妗惰闂瓥鐣ラ厤缃�
+ *
+ * @author 闄堣碀
+ */
+@Getter
+@AllArgsConstructor
+public enum AccessPolicyType {
+
+    /**
+     * private
+     */
+    PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE, PolicyType.WRITE),
+
+    /**
+     * public
+     */
+    PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE, PolicyType.READ_WRITE),
+
+    /**
+     * custom
+     */
+    CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ, PolicyType.READ);
+
+    /**
+     * 妗� 鏉冮檺绫诲瀷锛堟暟鎹簱鍊硷級
+     */
+    private final String type;
+
+    /**
+     * 妗� 鏉冮檺绫诲瀷
+     */
+    private final BucketCannedACL bucketCannedACL;
+
+    /**
+     * 鏂囦欢瀵硅薄 鏉冮檺绫诲瀷
+     */
+    private final ObjectCannedACL objectCannedACL;
+
+    /**
+     * 妗剁瓥鐣ョ被鍨�
+     */
+    private final PolicyType policyType;
+
+    public static AccessPolicyType getByType(String type) {
+        for (AccessPolicyType value : values()) {
+            if (value.getType().equals(type)) {
+                return value;
+            }
+        }
+        throw new RuntimeException("'type' not found By " + type);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java
new file mode 100644
index 0000000..fe96341
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/PolicyType.java
@@ -0,0 +1,35 @@
+package org.dromara.common.oss.enumd;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * minio绛栫暐閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum PolicyType {
+
+    /**
+     * 鍙
+     */
+    READ("read-only"),
+
+    /**
+     * 鍙啓
+     */
+    WRITE("write-only"),
+
+    /**
+     * 璇诲啓
+     */
+    READ_WRITE("read-write");
+
+    /**
+     * 绫诲瀷
+     */
+    private final String type;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/exception/OssException.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/exception/OssException.java
new file mode 100644
index 0000000..52e9623
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/exception/OssException.java
@@ -0,0 +1,19 @@
+package org.dromara.common.oss.exception;
+
+import java.io.Serial;
+
+/**
+ * OSS寮傚父绫�
+ *
+ * @author Lion Li
+ */
+public class OssException extends RuntimeException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public OssException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
new file mode 100644
index 0000000..3da1ba5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
@@ -0,0 +1,73 @@
+package org.dromara.common.oss.factory;
+
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.oss.constant.OssConstant;
+import org.dromara.common.oss.core.OssClient;
+import org.dromara.common.oss.exception.OssException;
+import org.dromara.common.oss.properties.OssProperties;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 鏂囦欢涓婁紶Factory
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class OssFactory {
+
+    private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();
+    private static final ReentrantLock LOCK = new ReentrantLock();
+
+    /**
+     * 鑾峰彇榛樿瀹炰緥
+     */
+    public static OssClient instance() {
+        // 鑾峰彇redis 榛樿绫诲瀷
+        String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY);
+        if (StringUtils.isEmpty(configKey)) {
+            throw new OssException("鏂囦欢瀛樺偍鏈嶅姟绫诲瀷鏃犳硶鎵惧埌!");
+        }
+        return instance(configKey);
+    }
+
+    /**
+     * 鏍规嵁绫诲瀷鑾峰彇瀹炰緥
+     */
+    public static OssClient instance(String configKey) {
+        String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
+        if (json == null) {
+            throw new OssException("绯荤粺寮傚父, '" + configKey + "'閰嶇疆淇℃伅涓嶅瓨鍦�!");
+        }
+        OssProperties properties = JsonUtils.parseObject(json, OssProperties.class);
+        // 浣跨敤绉熸埛鏍囪瘑閬垮厤澶氫釜绉熸埛鐩稿悓key瀹炰緥瑕嗙洊
+        String key = configKey;
+        if (StringUtils.isNotBlank(properties.getTenantId())) {
+            key = properties.getTenantId() + ":" + configKey;
+        }
+        OssClient client = CLIENT_CACHE.get(key);
+        // 瀹㈡埛绔笉瀛樺湪鎴栭厤缃笉鐩稿悓鍒欓噸鏂版瀯寤�
+        if (client == null || !client.checkPropertiesSame(properties)) {
+            LOCK.lock();
+            try {
+                client = CLIENT_CACHE.get(key);
+                if (client == null || !client.checkPropertiesSame(properties)) {
+                    CLIENT_CACHE.put(key, new OssClient(configKey, properties));
+                    log.info("鍒涘缓OSS瀹炰緥 key => {}", configKey);
+                    return CLIENT_CACHE.get(key);
+                }
+            } finally {
+                LOCK.unlock();
+            }
+        }
+        return client;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java
new file mode 100644
index 0000000..cb37206
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java
@@ -0,0 +1,63 @@
+package org.dromara.common.oss.properties;
+
+import lombok.Data;
+
+/**
+ * OSS瀵硅薄瀛樺偍 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+public class OssProperties {
+
+    /**
+     * 绉熸埛id
+     */
+    private String tenantId;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    private String endpoint;
+
+    /**
+     * 鑷畾涔夊煙鍚�
+     */
+    private String domain;
+
+    /**
+     * 鍓嶇紑
+     */
+    private String prefix;
+
+    /**
+     * ACCESS_KEY
+     */
+    private String accessKey;
+
+    /**
+     * SECRET_KEY
+     */
+    private String secretKey;
+
+    /**
+     * 瀛樺偍绌洪棿鍚�
+     */
+    private String bucketName;
+
+    /**
+     * 瀛樺偍鍖哄煙
+     */
+    private String region;
+
+    /**
+     * 鏄惁https锛圷=鏄�,N=鍚︼級
+     */
+    private String isHttps;
+
+    /**
+     * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+     */
+    private String accessPolicy;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/pom.xml b/eims/ruoyi-common/ruoyi-common-ratelimiter/pom.xml
new file mode 100644
index 0000000..bbde940
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-ratelimiter</artifactId>
+
+    <description>
+        ruoyi-common-ratelimiter 闄愭祦鍔熻兘
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java
new file mode 100644
index 0000000..de09752
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java
@@ -0,0 +1,41 @@
+package org.dromara.common.ratelimiter.annotation;
+
+import org.dromara.common.ratelimiter.enums.LimitType;
+
+import java.lang.annotation.*;
+
+/**
+ * 闄愭祦娉ㄨВ
+ *
+ * @author Lion Li
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter {
+    /**
+     * 闄愭祦key,鏀寔浣跨敤Spring el琛ㄨ揪寮忔潵鍔ㄦ�佽幏鍙栨柟娉曚笂鐨勫弬鏁板��
+     * 鏍煎紡绫讳技浜�  #code.id #{#code}
+     */
+    String key() default "";
+
+    /**
+     * 闄愭祦鏃堕棿,鍗曚綅绉�
+     */
+    int time() default 60;
+
+    /**
+     * 闄愭祦娆℃暟
+     */
+    int count() default 100;
+
+    /**
+     * 闄愭祦绫诲瀷
+     */
+    LimitType limitType() default LimitType.DEFAULT;
+
+    /**
+     * 鎻愮ず娑堟伅 鏀寔鍥介檯鍖� 鏍煎紡涓� {code}
+     */
+    String message() default "{rate.limiter.message}";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
new file mode 100644
index 0000000..1f4904a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
@@ -0,0 +1,111 @@
+package org.dromara.common.ratelimiter.aspectj;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.ratelimiter.enums.LimitType;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.redisson.api.RateType;
+import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.context.expression.MethodBasedEvaluationContext;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.ParserContext;
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+
+import java.lang.reflect.Method;
+
+/**
+ * 闄愭祦澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Aspect
+public class RateLimiterAspect {
+
+    /**
+     * 瀹氫箟spel琛ㄨ揪寮忚В鏋愬櫒
+     */
+    private final ExpressionParser parser = new SpelExpressionParser();
+    /**
+     * 瀹氫箟spel瑙f瀽妯$増
+     */
+    private final ParserContext parserContext = new TemplateParserContext();
+    /**
+     * 鏂规硶鍙傛暟瑙f瀽鍣�
+     */
+    private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
+
+
+    @Before("@annotation(rateLimiter)")
+    public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
+        int time = rateLimiter.time();
+        int count = rateLimiter.count();
+        try {
+            String combineKey = getCombineKey(rateLimiter, point);
+            RateType rateType = RateType.OVERALL;
+            if (rateLimiter.limitType() == LimitType.CLUSTER) {
+                rateType = RateType.PER_CLIENT;
+            }
+            long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
+            if (number == -1) {
+                String message = rateLimiter.message();
+                if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
+                    message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1));
+                }
+                throw new ServiceException(message);
+            }
+            log.info("闄愬埗浠ょ墝 => {}, 鍓╀綑浠ょ墝 => {}, 缂撳瓨key => '{}'", count, number, combineKey);
+        } catch (Exception e) {
+            if (e instanceof ServiceException) {
+                throw e;
+            } else {
+                throw new RuntimeException("鏈嶅姟鍣ㄩ檺娴佸紓甯革紝璇风◢鍊欏啀璇�", e);
+            }
+        }
+    }
+
+    private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
+        String key = rateLimiter.key();
+        // 鍒ゆ柇 key 涓嶄负绌� 鍜� 涓嶆槸琛ㄨ揪寮�
+        if (StringUtils.isNotBlank(key) && StringUtils.containsAny(key, "#")) {
+            MethodSignature signature = (MethodSignature) point.getSignature();
+            Method targetMethod = signature.getMethod();
+            Object[] args = point.getArgs();
+            MethodBasedEvaluationContext context =
+                new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
+            context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory()));
+            Expression expression;
+            if (StringUtils.startsWith(key, parserContext.getExpressionPrefix())
+                && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) {
+                expression = parser.parseExpression(key, parserContext);
+            } else {
+                expression = parser.parseExpression(key);
+            }
+            key = expression.getValue(context, String.class);
+        }
+        StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY);
+        stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":");
+        if (rateLimiter.limitType() == LimitType.IP) {
+            // 鑾峰彇璇锋眰ip
+            stringBuffer.append(ServletUtils.getClientIP()).append(":");
+        } else if (rateLimiter.limitType() == LimitType.CLUSTER) {
+            // 鑾峰彇瀹㈡埛绔疄渚媔d
+            stringBuffer.append(RedisUtils.getClient().getId()).append(":");
+        }
+        return stringBuffer.append(key).toString();
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/config/RateLimiterConfig.java b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/config/RateLimiterConfig.java
new file mode 100644
index 0000000..4b7e5b7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/config/RateLimiterConfig.java
@@ -0,0 +1,20 @@
+package org.dromara.common.ratelimiter.config;
+
+import org.dromara.common.ratelimiter.aspectj.RateLimiterAspect;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.connection.RedisConfiguration;
+
+/**
+ * @author guangxin
+ * @date 2023/1/18
+ */
+@AutoConfiguration(after = RedisConfiguration.class)
+public class RateLimiterConfig {
+
+    @Bean
+    public RateLimiterAspect rateLimiterAspect() {
+        return new RateLimiterAspect();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/enums/LimitType.java b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/enums/LimitType.java
new file mode 100644
index 0000000..b7f059f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/enums/LimitType.java
@@ -0,0 +1,24 @@
+package org.dromara.common.ratelimiter.enums;
+
+/**
+ * 闄愭祦绫诲瀷
+ *
+ * @author ruoyi
+ */
+
+public enum LimitType {
+    /**
+     * 榛樿绛栫暐鍏ㄥ眬闄愭祦
+     */
+    DEFAULT,
+
+    /**
+     * 鏍规嵁璇锋眰鑰匢P杩涜闄愭祦
+     */
+    IP,
+
+    /**
+     * 瀹炰緥闄愭祦(闆嗙兢澶氬悗绔疄渚�)
+     */
+    CLUSTER
+}
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..3b95432
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.ratelimiter.config.RateLimiterConfig
diff --git a/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json
new file mode 100644
index 0000000..b16432b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json
@@ -0,0 +1,7 @@
+{
+  "org.dromara.common.ratelimiter.annotation.RateLimiter@key": {
+    "method": {
+      "parameters": true
+    }
+  }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/pom.xml b/eims/ruoyi-common/ruoyi-common-redis/pom.xml
new file mode 100644
index 0000000..f56f8aa
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-redis</artifactId>
+
+    <description>
+        ruoyi-common-redis 缂撳瓨鏈嶅姟
+    </description>
+
+    <dependencies>
+        <!-- RuoYi Common Core-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <!--redisson-->
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java
new file mode 100644
index 0000000..d57ba4e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java
@@ -0,0 +1,45 @@
+package org.dromara.common.redis.config;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.dromara.common.redis.manager.PlusSpringCacheManager;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 缂撳瓨閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@EnableCaching
+public class CacheConfig {
+
+    /**
+     * caffeine 鏈湴缂撳瓨澶勭悊鍣�
+     */
+    @Bean
+    public Cache<Object, Object> caffeine() {
+        return Caffeine.newBuilder()
+            // 璁剧疆鏈�鍚庝竴娆″啓鍏ユ垨璁块棶鍚庣粡杩囧浐瀹氭椂闂磋繃鏈�
+            .expireAfterWrite(30, TimeUnit.SECONDS)
+            // 鍒濆鐨勭紦瀛樼┖闂村ぇ灏�
+            .initialCapacity(100)
+            // 缂撳瓨鐨勬渶澶ф潯鏁�
+            .maximumSize(1000)
+            .build();
+    }
+
+    /**
+     * 鑷畾涔夌紦瀛樼鐞嗗櫒 鏁村悎spring-cache
+     */
+    @Bean
+    public CacheManager cacheManager() {
+        return new PlusSpringCacheManager();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
new file mode 100644
index 0000000..f8fe79a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java
@@ -0,0 +1,156 @@
+package org.dromara.common.redis.config;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.redis.config.properties.RedissonProperties;
+import org.dromara.common.redis.handler.KeyPrefixHandler;
+import org.dromara.common.redis.handler.RedisExceptionHandler;
+import org.redisson.client.codec.StringCodec;
+import org.redisson.codec.CompositeCodec;
+import org.redisson.codec.TypedJsonJacksonCodec;
+import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.TimeZone;
+
+/**
+ * redis閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@AutoConfiguration
+@EnableConfigurationProperties(RedissonProperties.class)
+public class RedisConfig {
+
+    @Autowired
+    private RedissonProperties redissonProperties;
+
+    @Bean
+    public RedissonAutoConfigurationCustomizer redissonCustomizer() {
+        return config -> {
+            JavaTimeModule javaTimeModule = new JavaTimeModule();
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
+            javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
+            ObjectMapper om = new ObjectMapper();
+            om.registerModule(javaTimeModule);
+            om.setTimeZone(TimeZone.getDefault());
+            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+            // 鎸囧畾搴忓垪鍖栬緭鍏ョ殑绫诲瀷锛岀被蹇呴』鏄潪final淇グ鐨勩�傚簭鍒楀寲鏃跺皢瀵硅薄鍏ㄧ被鍚嶄竴璧蜂繚瀛樹笅鏉�
+            om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
+            TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om);
+            // 缁勫悎搴忓垪鍖� key 浣跨敤 String 鍐呭浣跨敤閫氱敤 json 鏍煎紡
+            CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec);
+            config.setThreads(redissonProperties.getThreads())
+                .setNettyThreads(redissonProperties.getNettyThreads())
+                // 缂撳瓨 Lua 鑴氭湰 鍑忓皯缃戠粶浼犺緭(redisson 澶ч儴鍒嗙殑鍔熻兘閮芥槸鍩轰簬 Lua 鑴氭湰瀹炵幇)
+                .setUseScriptCache(true)
+                .setCodec(codec);
+            if (SpringUtils.isVirtual()) {
+                config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-"));
+            }
+            RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
+            if (ObjectUtil.isNotNull(singleServerConfig)) {
+                // 浣跨敤鍗曟満妯″紡
+                config.useSingleServer()
+                    //璁剧疆redis key鍓嶇紑
+                    .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
+                    .setTimeout(singleServerConfig.getTimeout())
+                    .setClientName(singleServerConfig.getClientName())
+                    .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
+                    .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
+                    .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
+                    .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());
+            }
+            // 闆嗙兢閰嶇疆鏂瑰紡 鍙傝�冧笅鏂规敞閲�
+            RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig();
+            if (ObjectUtil.isNotNull(clusterServersConfig)) {
+                config.useClusterServers()
+                    //璁剧疆redis key鍓嶇紑
+                    .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
+                    .setTimeout(clusterServersConfig.getTimeout())
+                    .setClientName(clusterServersConfig.getClientName())
+                    .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
+                    .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
+                    .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
+                    .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
+                    .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize())
+                    .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
+                    .setReadMode(clusterServersConfig.getReadMode())
+                    .setSubscriptionMode(clusterServersConfig.getSubscriptionMode());
+            }
+            log.info("鍒濆鍖� redis 閰嶇疆");
+        };
+    }
+
+    /**
+     * 寮傚父澶勭悊鍣�
+     */
+    @Bean
+    public RedisExceptionHandler redisExceptionHandler() {
+        return new RedisExceptionHandler();
+    }
+
+    /**
+     * redis闆嗙兢閰嶇疆 yml
+     *
+     * --- # redis 闆嗙兢閰嶇疆(鍗曟満涓庨泦缇ゅ彧鑳藉紑鍚竴涓彟涓�涓渶瑕佹敞閲婃帀)
+     * spring.data:
+     *   redis:
+     *     cluster:
+     *       nodes:
+     *         - 192.168.0.100:6379
+     *         - 192.168.0.101:6379
+     *         - 192.168.0.102:6379
+     *     # 瀵嗙爜
+     *     password:
+     *     # 杩炴帴瓒呮椂鏃堕棿
+     *     timeout: 10s
+     *     # 鏄惁寮�鍚痵sl
+     *     ssl.enabled: false
+     *
+     * redisson:
+     *   # 绾跨▼姹犳暟閲�
+     *   threads: 16
+     *   # Netty绾跨▼姹犳暟閲�
+     *   nettyThreads: 32
+     *   # 闆嗙兢閰嶇疆
+     *   clusterServersConfig:
+     *     # 瀹㈡埛绔悕绉�
+     *     clientName: ${ruoyi.name}
+     *     # master鏈�灏忕┖闂茶繛鎺ユ暟
+     *     masterConnectionMinimumIdleSize: 32
+     *     # master杩炴帴姹犲ぇ灏�
+     *     masterConnectionPoolSize: 64
+     *     # slave鏈�灏忕┖闂茶繛鎺ユ暟
+     *     slaveConnectionMinimumIdleSize: 32
+     *     # slave杩炴帴姹犲ぇ灏�
+     *     slaveConnectionPoolSize: 64
+     *     # 杩炴帴绌洪棽瓒呮椂锛屽崟浣嶏細姣
+     *     idleConnectionTimeout: 10000
+     *     # 鍛戒护绛夊緟瓒呮椂锛屽崟浣嶏細姣
+     *     timeout: 3000
+     *     # 鍙戝竷鍜岃闃呰繛鎺ユ睜澶у皬
+     *     subscriptionConnectionPoolSize: 50
+     *     # 璇诲彇妯″紡
+     *     readMode: "SLAVE"
+     *     # 璁㈤槄妯″紡
+     *     subscriptionMode: "MASTER"
+     */
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java
new file mode 100644
index 0000000..ebec786
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java
@@ -0,0 +1,135 @@
+package org.dromara.common.redis.config.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.redisson.config.ReadMode;
+import org.redisson.config.SubscriptionMode;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Redisson 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "redisson")
+public class RedissonProperties {
+
+    /**
+     * redis缂撳瓨key鍓嶇紑
+     */
+    private String keyPrefix;
+
+    /**
+     * 绾跨▼姹犳暟閲�,榛樿鍊� = 褰撳墠澶勭悊鏍告暟閲� * 2
+     */
+    private int threads;
+
+    /**
+     * Netty绾跨▼姹犳暟閲�,榛樿鍊� = 褰撳墠澶勭悊鏍告暟閲� * 2
+     */
+    private int nettyThreads;
+
+    /**
+     * 鍗曟満鏈嶅姟閰嶇疆
+     */
+    private SingleServerConfig singleServerConfig;
+
+    /**
+     * 闆嗙兢鏈嶅姟閰嶇疆
+     */
+    private ClusterServersConfig clusterServersConfig;
+
+    @Data
+    @NoArgsConstructor
+    public static class SingleServerConfig {
+
+        /**
+         * 瀹㈡埛绔悕绉�
+         */
+        private String clientName;
+
+        /**
+         * 鏈�灏忕┖闂茶繛鎺ユ暟
+         */
+        private int connectionMinimumIdleSize;
+
+        /**
+         * 杩炴帴姹犲ぇ灏�
+         */
+        private int connectionPoolSize;
+
+        /**
+         * 杩炴帴绌洪棽瓒呮椂锛屽崟浣嶏細姣
+         */
+        private int idleConnectionTimeout;
+
+        /**
+         * 鍛戒护绛夊緟瓒呮椂锛屽崟浣嶏細姣
+         */
+        private int timeout;
+
+        /**
+         * 鍙戝竷鍜岃闃呰繛鎺ユ睜澶у皬
+         */
+        private int subscriptionConnectionPoolSize;
+
+    }
+
+    @Data
+    @NoArgsConstructor
+    public static class ClusterServersConfig {
+
+        /**
+         * 瀹㈡埛绔悕绉�
+         */
+        private String clientName;
+
+        /**
+         * master鏈�灏忕┖闂茶繛鎺ユ暟
+         */
+        private int masterConnectionMinimumIdleSize;
+
+        /**
+         * master杩炴帴姹犲ぇ灏�
+         */
+        private int masterConnectionPoolSize;
+
+        /**
+         * slave鏈�灏忕┖闂茶繛鎺ユ暟
+         */
+        private int slaveConnectionMinimumIdleSize;
+
+        /**
+         * slave杩炴帴姹犲ぇ灏�
+         */
+        private int slaveConnectionPoolSize;
+
+        /**
+         * 杩炴帴绌洪棽瓒呮椂锛屽崟浣嶏細姣
+         */
+        private int idleConnectionTimeout;
+
+        /**
+         * 鍛戒护绛夊緟瓒呮椂锛屽崟浣嶏細姣
+         */
+        private int timeout;
+
+        /**
+         * 鍙戝竷鍜岃闃呰繛鎺ユ睜澶у皬
+         */
+        private int subscriptionConnectionPoolSize;
+
+        /**
+         * 璇诲彇妯″紡
+         */
+        private ReadMode readMode;
+
+        /**
+         * 璁㈤槄妯″紡
+         */
+        private SubscriptionMode subscriptionMode;
+
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java
new file mode 100644
index 0000000..3bf3e34
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java
@@ -0,0 +1,50 @@
+package org.dromara.common.redis.handler;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.redisson.api.NameMapper;
+
+/**
+ * redis缂撳瓨key鍓嶇紑澶勭悊
+ *
+ * @author ye
+ * @date 2022/7/14 17:44
+ * @since 4.3.0
+ */
+public class KeyPrefixHandler implements NameMapper {
+
+    private final String keyPrefix;
+
+    public KeyPrefixHandler(String keyPrefix) {
+        //鍓嶇紑涓虹┖ 鍒欒繑鍥炵┖鍓嶇紑
+        this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":";
+    }
+
+    /**
+     * 澧炲姞鍓嶇紑
+     */
+    @Override
+    public String map(String name) {
+        if (StringUtils.isBlank(name)) {
+            return null;
+        }
+        if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) {
+            return keyPrefix + name;
+        }
+        return name;
+    }
+
+    /**
+     * 鍘婚櫎鍓嶇紑
+     */
+    @Override
+    public String unmap(String name) {
+        if (StringUtils.isBlank(name)) {
+            return null;
+        }
+        if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) {
+            return name.substring(keyPrefix.length());
+        }
+        return name;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java
new file mode 100644
index 0000000..5e904f3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java
@@ -0,0 +1,30 @@
+package org.dromara.common.redis.handler;
+
+import cn.hutool.http.HttpStatus;
+import com.baomidou.lock.exception.LockFailureException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * Redis寮傚父澶勭悊鍣�
+ *
+ * @author AprilWind
+ */
+@Slf4j
+@RestControllerAdvice
+public class RedisExceptionHandler {
+
+    /**
+     * 鍒嗗竷寮忛攣Lock4j寮傚父
+     */
+    @ExceptionHandler(LockFailureException.class)
+    public R<Void> handleLockFailureException(LockFailureException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("鑾峰彇閿佸け璐ヤ簡'{}',鍙戠敓Lock4j寮傚父.", requestURI, e);
+        return R.fail(HttpStatus.HTTP_UNAVAILABLE, "涓氬姟澶勭悊涓紝璇风◢鍚庡啀璇�...");
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
new file mode 100644
index 0000000..793e21f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
@@ -0,0 +1,92 @@
+package org.dromara.common.redis.manager;
+
+import org.dromara.common.core.utils.SpringUtils;
+import org.springframework.cache.Cache;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Cache 瑁呴グ鍣ㄦā寮�(鐢ㄤ簬鎵╁睍 Caffeine 涓�绾х紦瀛�)
+ *
+ * @author LionLi
+ */
+public class CaffeineCacheDecorator implements Cache {
+
+    private static final com.github.benmanes.caffeine.cache.Cache<Object, Object>
+        CAFFEINE = SpringUtils.getBean("caffeine");
+
+    private final String name;
+    private final Cache cache;
+
+    public CaffeineCacheDecorator(String name, Cache cache) {
+        this.name = name;
+        this.cache = cache;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Object getNativeCache() {
+        return cache.getNativeCache();
+    }
+
+    public String getUniqueKey(Object key) {
+        return name + ":" + key;
+    }
+
+    @Override
+    public ValueWrapper get(Object key) {
+        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key));
+        return (ValueWrapper) o;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T get(Object key, Class<T> type) {
+        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
+        return (T) o;
+    }
+
+    @Override
+    public void put(Object key, Object value) {
+        CAFFEINE.invalidate(getUniqueKey(key));
+        cache.put(key, value);
+    }
+
+    public ValueWrapper putIfAbsent(Object key, Object value) {
+        CAFFEINE.invalidate(getUniqueKey(key));
+        return cache.putIfAbsent(key, value);
+    }
+
+    @Override
+    public void evict(Object key) {
+        evictIfPresent(key);
+    }
+
+    public boolean evictIfPresent(Object key) {
+        boolean b = cache.evictIfPresent(key);
+        if (b) {
+            CAFFEINE.invalidate(getUniqueKey(key));
+        }
+        return b;
+    }
+
+    @Override
+    public void clear() {
+        cache.clear();
+    }
+
+    public boolean invalidate() {
+        return cache.invalidate();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T get(Object key, Callable<T> valueLoader) {
+        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, valueLoader));
+        return (T) o;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
new file mode 100644
index 0000000..740e2a1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2013-2021 Nikita Koksharov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.dromara.common.redis.manager;
+
+import org.dromara.common.redis.utils.RedisUtils;
+import org.redisson.api.RMap;
+import org.redisson.api.RMapCache;
+import org.redisson.spring.cache.CacheConfig;
+import org.redisson.spring.cache.RedissonCache;
+import org.springframework.boot.convert.DurationStyle;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
+import org.springframework.util.StringUtils;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A {@link org.springframework.cache.CacheManager} implementation
+ * backed by Redisson instance.
+ * <p>
+ * 淇敼 RedissonSpringCacheManager 婧愮爜
+ * 閲嶅啓 cacheName 澶勭悊鏂规硶 鏀寔澶氬弬鏁�
+ *
+ * @author Nikita Koksharov
+ *
+ */
+@SuppressWarnings("unchecked")
+public class PlusSpringCacheManager implements CacheManager {
+
+    private boolean dynamic = true;
+
+    private boolean allowNullValues = true;
+
+    private boolean transactionAware = true;
+
+    Map<String, CacheConfig> configMap = new ConcurrentHashMap<>();
+    ConcurrentMap<String, Cache> instanceMap = new ConcurrentHashMap<>();
+
+    /**
+     * Creates CacheManager supplied by Redisson instance
+     */
+    public PlusSpringCacheManager() {
+    }
+
+
+    /**
+     * Defines possibility of storing {@code null} values.
+     * <p>
+     * Default is <code>true</code>
+     *
+     * @param allowNullValues stores if <code>true</code>
+     */
+    public void setAllowNullValues(boolean allowNullValues) {
+        this.allowNullValues = allowNullValues;
+    }
+
+    /**
+     * Defines if cache aware of Spring-managed transactions.
+     * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase.
+     * <p>
+     * Default is <code>false</code>
+     *
+     * @param transactionAware cache is transaction aware if <code>true</code>
+     */
+    public void setTransactionAware(boolean transactionAware) {
+        this.transactionAware = transactionAware;
+    }
+
+    /**
+     * Defines 'fixed' cache names.
+     * A new cache instance will not be created in dynamic for non-defined names.
+     * <p>
+     * `null` parameter setups dynamic mode
+     *
+     * @param names of caches
+     */
+    public void setCacheNames(Collection<String> names) {
+        if (names != null) {
+            for (String name : names) {
+                getCache(name);
+            }
+            dynamic = false;
+        } else {
+            dynamic = true;
+        }
+    }
+
+    /**
+     * Set cache config mapped by cache name
+     *
+     * @param config object
+     */
+    public void setConfig(Map<String, ? extends CacheConfig> config) {
+        this.configMap = (Map<String, CacheConfig>) config;
+    }
+
+    protected CacheConfig createDefaultConfig() {
+        return new CacheConfig();
+    }
+
+    @Override
+    public Cache getCache(String name) {
+        // 閲嶅啓 cacheName 鏀寔澶氬弬鏁�
+        String[] array = StringUtils.delimitedListToStringArray(name, "#");
+        name = array[0];
+
+        Cache cache = instanceMap.get(name);
+        if (cache != null) {
+            return cache;
+        }
+        if (!dynamic) {
+            return cache;
+        }
+
+        CacheConfig config = configMap.get(name);
+        if (config == null) {
+            config = createDefaultConfig();
+            configMap.put(name, config);
+        }
+
+        if (array.length > 1) {
+            config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis());
+        }
+        if (array.length > 2) {
+            config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis());
+        }
+        if (array.length > 3) {
+            config.setMaxSize(Integer.parseInt(array[3]));
+        }
+
+        if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) {
+            return createMap(name, config);
+        }
+
+        return createMapCache(name, config);
+    }
+
+    private Cache createMap(String name, CacheConfig config) {
+        RMap<Object, Object> map = RedisUtils.getClient().getMap(name);
+
+        Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, allowNullValues));
+        if (transactionAware) {
+            cache = new TransactionAwareCacheDecorator(cache);
+        }
+        Cache oldCache = instanceMap.putIfAbsent(name, cache);
+        if (oldCache != null) {
+            cache = oldCache;
+        }
+        return cache;
+    }
+
+    private Cache createMapCache(String name, CacheConfig config) {
+        RMapCache<Object, Object> map = RedisUtils.getClient().getMapCache(name);
+
+        Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, config, allowNullValues));
+        if (transactionAware) {
+            cache = new TransactionAwareCacheDecorator(cache);
+        }
+        Cache oldCache = instanceMap.putIfAbsent(name, cache);
+        if (oldCache != null) {
+            cache = oldCache;
+        } else {
+            map.setMaxSize(config.getMaxSize());
+        }
+        return cache;
+    }
+
+    @Override
+    public Collection<String> getCacheNames() {
+        return Collections.unmodifiableSet(configMap.keySet());
+    }
+
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java
new file mode 100644
index 0000000..42a88d6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java
@@ -0,0 +1,75 @@
+package org.dromara.common.redis.utils;
+
+import org.dromara.common.core.utils.SpringUtils;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.redisson.api.RMap;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+
+import java.util.Set;
+
+/**
+ * 缂撳瓨鎿嶄綔宸ュ叿绫� {@link }
+ *
+ * @author Michelle.Chung
+ * @date 2022/8/13
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@SuppressWarnings(value = {"unchecked"})
+public class CacheUtils {
+
+    private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);
+
+    /**
+     * 鑾峰彇缂撳瓨缁勫唴鎵�鏈夌殑KEY
+     *
+     * @param cacheNames 缂撳瓨缁勫悕绉�
+     */
+    public static Set<Object> keys(String cacheNames) {
+        RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
+        return rmap.keySet();
+    }
+
+    /**
+     * 鑾峰彇缂撳瓨鍊�
+     *
+     * @param cacheNames 缂撳瓨缁勫悕绉�
+     * @param key        缂撳瓨key
+     */
+    public static <T> T get(String cacheNames, Object key) {
+        Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key);
+        return wrapper != null ? (T) wrapper.get() : null;
+    }
+
+    /**
+     * 淇濆瓨缂撳瓨鍊�
+     *
+     * @param cacheNames 缂撳瓨缁勫悕绉�
+     * @param key        缂撳瓨key
+     * @param value      缂撳瓨鍊�
+     */
+    public static void put(String cacheNames, Object key, Object value) {
+        CACHE_MANAGER.getCache(cacheNames).put(key, value);
+    }
+
+    /**
+     * 鍒犻櫎缂撳瓨鍊�
+     *
+     * @param cacheNames 缂撳瓨缁勫悕绉�
+     * @param key        缂撳瓨key
+     */
+    public static void evict(String cacheNames, Object key) {
+        CACHE_MANAGER.getCache(cacheNames).evict(key);
+    }
+
+    /**
+     * 娓呯┖缂撳瓨鍊�
+     *
+     * @param cacheNames 缂撳瓨缁勫悕绉�
+     */
+    public static void clear(String cacheNames) {
+        CACHE_MANAGER.getCache(cacheNames).clear();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
new file mode 100644
index 0000000..e436a46
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java
@@ -0,0 +1,237 @@
+package org.dromara.common.redis.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.redisson.api.*;
+
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+/**
+ * 鍒嗗竷寮忛槦鍒楀伐鍏�
+ * 杞婚噺绾ч槦鍒� 閲嶉噺绾ф暟鎹噺 璇蜂娇鐢� MQ
+ * 瑕佹眰 redis 5.X 浠ヤ笂
+ *
+ * @author Lion Li
+ * @version 3.6.0 鏂板
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class QueueUtils {
+
+    private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);
+
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疄渚�
+     */
+    public static RedissonClient getClient() {
+        return CLIENT;
+    }
+
+    /**
+     * 娣诲姞鏅�氶槦鍒楁暟鎹�
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param data      鏁版嵁
+     */
+    public static <T> boolean addQueueObject(String queueName, T data) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        return queue.offer(data);
+    }
+
+    /**
+     * 閫氱敤鑾峰彇涓�涓槦鍒楁暟鎹� 娌℃湁鏁版嵁杩斿洖 null(涓嶆敮鎸佸欢杩熼槦鍒�)
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    public static <T> T getQueueObject(String queueName) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        return queue.poll();
+    }
+
+    /**
+     * 閫氱敤鍒犻櫎闃熷垪鏁版嵁(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean removeQueueObject(String queueName, T data) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        return queue.remove(data);
+    }
+
+    /**
+     * 閫氱敤閿�姣侀槦鍒� 鎵�鏈夐樆濉炵洃鍚� 鎶ラ敊(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean destroyQueue(String queueName) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        return queue.delete();
+    }
+
+    /**
+     * 娣诲姞寤惰繜闃熷垪鏁版嵁 榛樿姣
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param data      鏁版嵁
+     * @param time      寤惰繜鏃堕棿
+     */
+    public static <T> void addDelayedQueueObject(String queueName, T data, long time) {
+        addDelayedQueueObject(queueName, data, time, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 娣诲姞寤惰繜闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param data      鏁版嵁
+     * @param time      寤惰繜鏃堕棿
+     * @param timeUnit  鍗曚綅
+     */
+    public static <T> void addDelayedQueueObject(String queueName, T data, long time, TimeUnit timeUnit) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue);
+        delayedQueue.offer(data, time, timeUnit);
+    }
+
+    /**
+     * 鑾峰彇涓�涓欢杩熼槦鍒楁暟鎹� 娌℃湁鏁版嵁杩斿洖 null
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    public static <T> T getDelayedQueueObject(String queueName) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue);
+        return delayedQueue.poll();
+    }
+
+    /**
+     * 鍒犻櫎寤惰繜闃熷垪鏁版嵁
+     */
+    public static <T> boolean removeDelayedQueueObject(String queueName, T data) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue);
+        return delayedQueue.remove(data);
+    }
+
+    /**
+     * 閿�姣佸欢杩熼槦鍒� 鎵�鏈夐樆濉炵洃鍚� 鎶ラ敊
+     */
+    public static <T> void destroyDelayedQueue(String queueName) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        RDelayedQueue<T> delayedQueue = CLIENT.getDelayedQueue(queue);
+        delayedQueue.destroy();
+    }
+
+    /**
+     * 娣诲姞浼樺厛闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param data      鏁版嵁
+     */
+    public static <T> boolean addPriorityQueueObject(String queueName, T data) {
+        RPriorityBlockingQueue<T> priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName);
+        return priorityBlockingQueue.offer(data);
+    }
+
+    /**
+     * 浼樺厛闃熷垪鑾峰彇涓�涓槦鍒楁暟鎹� 娌℃湁鏁版嵁杩斿洖 null(涓嶆敮鎸佸欢杩熼槦鍒�)
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    public static <T> T getPriorityQueueObject(String queueName) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.poll();
+    }
+
+    /**
+     * 浼樺厛闃熷垪鍒犻櫎闃熷垪鏁版嵁(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean removePriorityQueueObject(String queueName, T data) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.remove(data);
+    }
+
+    /**
+     * 浼樺厛闃熷垪閿�姣侀槦鍒� 鎵�鏈夐樆濉炵洃鍚� 鎶ラ敊(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean destroyPriorityQueue(String queueName) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.delete();
+    }
+
+    /**
+     * 灏濊瘯璁剧疆 鏈夌晫闃熷垪 瀹归噺 鐢ㄤ簬闄愬埗鏁伴噺
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param capacity  瀹归噺
+     */
+    public static <T> boolean trySetBoundedQueueCapacity(String queueName, int capacity) {
+        RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName);
+        return boundedBlockingQueue.trySetCapacity(capacity);
+    }
+
+    /**
+     * 灏濊瘯璁剧疆 鏈夌晫闃熷垪 瀹归噺 鐢ㄤ簬闄愬埗鏁伴噺
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param capacity  瀹归噺
+     * @param destroy   宸插瓨鍦ㄦ槸鍚﹂攢姣�
+     */
+    public static <T> boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) {
+        RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName);
+        if (boundedBlockingQueue.isExists() && destroy) {
+            destroyQueue(queueName);
+        }
+        return boundedBlockingQueue.trySetCapacity(capacity);
+    }
+
+    /**
+     * 娣诲姞鏈夌晫闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param data      鏁版嵁
+     * @return 娣诲姞鎴愬姛 true 宸茶揪鍒扮晫闄� false
+     */
+    public static <T> boolean addBoundedQueueObject(String queueName, T data) {
+        RBoundedBlockingQueue<T> boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName);
+        return boundedBlockingQueue.offer(data);
+    }
+
+    /**
+     * 鏈夌晫闃熷垪鑾峰彇涓�涓槦鍒楁暟鎹� 娌℃湁鏁版嵁杩斿洖 null(涓嶆敮鎸佸欢杩熼槦鍒�)
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    public static <T> T getBoundedQueueObject(String queueName) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.poll();
+    }
+
+    /**
+     * 鏈夌晫闃熷垪鍒犻櫎闃熷垪鏁版嵁(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean removeBoundedQueueObject(String queueName, T data) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.remove(data);
+    }
+
+    /**
+     * 鏈夌晫闃熷垪閿�姣侀槦鍒� 鎵�鏈夐樆濉炵洃鍚� 鎶ラ敊(涓嶆敮鎸佸欢杩熼槦鍒�)
+     */
+    public static <T> boolean destroyBoundedQueue(String queueName) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.delete();
+    }
+
+    /**
+     * 璁㈤槄闃诲闃熷垪(鍙闃呮墍鏈夊疄鐜扮被 渚嬪: 寤惰繜 浼樺厛 鏈夌晫 绛�)
+     */
+    public static <T> void subscribeBlockingQueue(String queueName, Function<T, CompletionStage<Void>> consumer, boolean isDelayed) {
+        RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
+        if (isDelayed) {
+            // 璁㈤槄寤惰繜闃熷垪
+            CLIENT.getDelayedQueue(queue);
+        }
+        queue.subscribeOnElements(consumer);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
new file mode 100644
index 0000000..67be2fb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
@@ -0,0 +1,548 @@
+package org.dromara.common.redis.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.redisson.api.*;
+
+import java.time.Duration;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * redis 宸ュ叿绫�
+ *
+ * @author Lion Li
+ * @version 3.1.0 鏂板
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@SuppressWarnings(value = {"unchecked", "rawtypes"})
+public class RedisUtils {
+
+    private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class);
+
+    /**
+     * 闄愭祦
+     *
+     * @param key          闄愭祦key
+     * @param rateType     闄愭祦绫诲瀷
+     * @param rate         閫熺巼
+     * @param rateInterval 閫熺巼闂撮殧
+     * @return -1 琛ㄧず澶辫触
+     */
+    public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
+        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
+        rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
+        if (rateLimiter.tryAcquire()) {
+            return rateLimiter.availablePermits();
+        } else {
+            return -1L;
+        }
+    }
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疄渚�
+     */
+    public static RedissonClient getClient() {
+        return CLIENT;
+    }
+
+    /**
+     * 鍙戝竷閫氶亾娑堟伅
+     *
+     * @param channelKey 閫氶亾key
+     * @param msg        鍙戦�佹暟鎹�
+     * @param consumer   鑷畾涔夊鐞�
+     */
+    public static <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
+        RTopic topic = CLIENT.getTopic(channelKey);
+        topic.publish(msg);
+        consumer.accept(msg);
+    }
+
+    /**
+     * 鍙戝竷娑堟伅鍒版寚瀹氱殑棰戦亾
+     *
+     * @param channelKey 閫氶亾key
+     * @param msg        鍙戦�佹暟鎹�
+     */
+    public static <T> void publish(String channelKey, T msg) {
+        RTopic topic = CLIENT.getTopic(channelKey);
+        topic.publish(msg);
+    }
+
+    /**
+     * 璁㈤槄閫氶亾鎺ユ敹娑堟伅
+     *
+     * @param channelKey 閫氶亾key
+     * @param clazz      娑堟伅绫诲瀷
+     * @param consumer   鑷畾涔夊鐞�
+     */
+    public static <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
+        RTopic topic = CLIENT.getTopic(channelKey);
+        topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key   缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     */
+    public static <T> void setCacheObject(final String key, final T value) {
+        setCacheObject(key, value, false);
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝淇濈暀褰撳墠瀵硅薄 TTL 鏈夋晥鏈�
+     *
+     * @param key       缂撳瓨鐨勯敭鍊�
+     * @param value     缂撳瓨鐨勫��
+     * @param isSaveTtl 鏄惁淇濈暀TTL鏈夋晥鏈�(渚嬪: set涔嬪墠ttl鍓╀綑90 set涔嬪悗杩樻槸涓�90)
+     * @since Redis 6.X 浠ヤ笂浣跨敤 setAndKeepTTL 鍏煎 5.X 鏂规
+     */
+    public static <T> void setCacheObject(final String key, final T value, final boolean isSaveTtl) {
+        RBucket<T> bucket = CLIENT.getBucket(key);
+        if (isSaveTtl) {
+            try {
+                bucket.setAndKeepTTL(value);
+            } catch (Exception e) {
+                long timeToLive = bucket.remainTimeToLive();
+                if (timeToLive == -1) {
+                    setCacheObject(key, value);
+                } else {
+                    setCacheObject(key, value, Duration.ofMillis(timeToLive));
+                }
+            }
+        } else {
+            bucket.set(value);
+        }
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param value    缂撳瓨鐨勫��
+     * @param duration 鏃堕棿
+     */
+    public static <T> void setCacheObject(final String key, final T value, final Duration duration) {
+        RBatch batch = CLIENT.createBatch();
+        RBucketAsync<T> bucket = batch.getBucket(key);
+        bucket.setAsync(value);
+        bucket.expireAsync(duration);
+        batch.execute();
+    }
+
+    /**
+     * 濡傛灉涓嶅瓨鍦ㄥ垯璁剧疆 骞惰繑鍥� true 濡傛灉瀛樺湪鍒欒繑鍥� false
+     *
+     * @param key   缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     * @return set鎴愬姛鎴栧け璐�
+     */
+    public static <T> boolean setObjectIfAbsent(final String key, final T value, final Duration duration) {
+        RBucket<T> bucket = CLIENT.getBucket(key);
+        return bucket.setIfAbsent(value, duration);
+    }
+
+    /**
+     * 濡傛灉瀛樺湪鍒欒缃� 骞惰繑鍥� true 濡傛灉瀛樺湪鍒欒繑鍥� false
+     *
+     * @param key   缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     * @return set鎴愬姛鎴栧け璐�
+     */
+    public static <T> boolean setObjectIfExists(final String key, final T value, final Duration duration) {
+        RBucket<T> bucket = CLIENT.getBucket(key);
+        return bucket.setIfExists(value, duration);
+    }
+
+    /**
+     * 娉ㄥ唽瀵硅薄鐩戝惉鍣�
+     * <p>
+     * key 鐩戝惉鍣ㄩ渶寮�鍚� `notify-keyspace-events` 绛� redis 鐩稿叧閰嶇疆
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param listener 鐩戝惉鍣ㄩ厤缃�
+     */
+    public static <T> void addObjectListener(final String key, final ObjectListener listener) {
+        RBucket<T> result = CLIENT.getBucket(key);
+        result.addListener(listener);
+    }
+
+    /**
+     * 璁剧疆鏈夋晥鏃堕棿
+     *
+     * @param key     Redis閿�
+     * @param timeout 瓒呮椂鏃堕棿
+     * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    public static boolean expire(final String key, final long timeout) {
+        return expire(key, Duration.ofSeconds(timeout));
+    }
+
+    /**
+     * 璁剧疆鏈夋晥鏃堕棿
+     *
+     * @param key      Redis閿�
+     * @param duration 瓒呮椂鏃堕棿
+     * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    public static boolean expire(final String key, final Duration duration) {
+        RBucket rBucket = CLIENT.getBucket(key);
+        return rBucket.expire(duration);
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞°��
+     *
+     * @param key 缂撳瓨閿��
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public static <T> T getCacheObject(final String key) {
+        RBucket<T> rBucket = CLIENT.getBucket(key);
+        return rBucket.get();
+    }
+
+    /**
+     * 鑾峰緱key鍓╀綑瀛樻椿鏃堕棿
+     *
+     * @param key 缂撳瓨閿��
+     * @return 鍓╀綑瀛樻椿鏃堕棿
+     */
+    public static <T> long getTimeToLive(final String key) {
+        RBucket<T> rBucket = CLIENT.getBucket(key);
+        return rBucket.remainTimeToLive();
+    }
+
+    /**
+     * 鍒犻櫎鍗曚釜瀵硅薄
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     */
+    public static boolean deleteObject(final String key) {
+        return CLIENT.getBucket(key).delete();
+    }
+
+    /**
+     * 鍒犻櫎闆嗗悎瀵硅薄
+     *
+     * @param collection 澶氫釜瀵硅薄
+     */
+    public static void deleteObject(final Collection collection) {
+        RBatch batch = CLIENT.createBatch();
+        collection.forEach(t -> {
+            batch.getBucket(t.toString()).deleteAsync();
+        });
+        batch.execute();
+    }
+
+    /**
+     * 妫�鏌ョ紦瀛樺璞℃槸鍚﹀瓨鍦�
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     */
+    public static boolean isExistsObject(final String key) {
+        return CLIENT.getBucket(key).isExists();
+    }
+
+    /**
+     * 缂撳瓨List鏁版嵁
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param dataList 寰呯紦瀛樼殑List鏁版嵁
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public static <T> boolean setCacheList(final String key, final List<T> dataList) {
+        RList<T> rList = CLIENT.getList(key);
+        return rList.addAll(dataList);
+    }
+
+    /**
+     * 杩藉姞缂撳瓨List鏁版嵁
+     *
+     * @param key  缂撳瓨鐨勯敭鍊�
+     * @param data 寰呯紦瀛樼殑鏁版嵁
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public static <T> boolean addCacheList(final String key, final T data) {
+        RList<T> rList = CLIENT.getList(key);
+        return rList.add(data);
+    }
+
+    /**
+     * 娉ㄥ唽List鐩戝惉鍣�
+     * <p>
+     * key 鐩戝惉鍣ㄩ渶寮�鍚� `notify-keyspace-events` 绛� redis 鐩稿叧閰嶇疆
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param listener 鐩戝惉鍣ㄩ厤缃�
+     */
+    public static <T> void addListListener(final String key, final ObjectListener listener) {
+        RList<T> rList = CLIENT.getList(key);
+        rList.addListener(listener);
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public static <T> List<T> getCacheList(final String key) {
+        RList<T> rList = CLIENT.getList(key);
+        return rList.readAll();
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄(鑼冨洿)
+     *
+     * @param key  缂撳瓨鐨勯敭鍊�
+     * @param form 璧峰涓嬫爣
+     * @param to   鎴涓嬫爣
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public static <T> List<T> getCacheListRange(final String key, int form, int to) {
+        RList<T> rList = CLIENT.getList(key);
+        return rList.range(form, to);
+    }
+
+    /**
+     * 缂撳瓨Set
+     *
+     * @param key     缂撳瓨閿��
+     * @param dataSet 缂撳瓨鐨勬暟鎹�
+     * @return 缂撳瓨鏁版嵁鐨勫璞�
+     */
+    public static <T> boolean setCacheSet(final String key, final Set<T> dataSet) {
+        RSet<T> rSet = CLIENT.getSet(key);
+        return rSet.addAll(dataSet);
+    }
+
+    /**
+     * 杩藉姞缂撳瓨Set鏁版嵁
+     *
+     * @param key  缂撳瓨鐨勯敭鍊�
+     * @param data 寰呯紦瀛樼殑鏁版嵁
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public static <T> boolean addCacheSet(final String key, final T data) {
+        RSet<T> rSet = CLIENT.getSet(key);
+        return rSet.add(data);
+    }
+
+    /**
+     * 娉ㄥ唽Set鐩戝惉鍣�
+     * <p>
+     * key 鐩戝惉鍣ㄩ渶寮�鍚� `notify-keyspace-events` 绛� redis 鐩稿叧閰嶇疆
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param listener 鐩戝惉鍣ㄩ厤缃�
+     */
+    public static <T> void addSetListener(final String key, final ObjectListener listener) {
+        RSet<T> rSet = CLIENT.getSet(key);
+        rSet.addListener(listener);
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨剆et
+     *
+     * @param key 缂撳瓨鐨刱ey
+     * @return set瀵硅薄
+     */
+    public static <T> Set<T> getCacheSet(final String key) {
+        RSet<T> rSet = CLIENT.getSet(key);
+        return rSet.readAll();
+    }
+
+    /**
+     * 缂撳瓨Map
+     *
+     * @param key     缂撳瓨鐨勯敭鍊�
+     * @param dataMap 缂撳瓨鐨勬暟鎹�
+     */
+    public static <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
+        if (dataMap != null) {
+            RMap<String, T> rMap = CLIENT.getMap(key);
+            rMap.putAll(dataMap);
+        }
+    }
+
+    /**
+     * 娉ㄥ唽Map鐩戝惉鍣�
+     * <p>
+     * key 鐩戝惉鍣ㄩ渶寮�鍚� `notify-keyspace-events` 绛� redis 鐩稿叧閰嶇疆
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param listener 鐩戝惉鍣ㄩ厤缃�
+     */
+    public static <T> void addMapListener(final String key, final ObjectListener listener) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        rMap.addListener(listener);
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨凪ap
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @return map瀵硅薄
+     */
+    public static <T> Map<String, T> getCacheMap(final String key) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        return rMap.getAll(rMap.keySet());
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨Map鐨刱ey鍒楄〃
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @return key鍒楄〃
+     */
+    public static <T> Set<String> getCacheMapKeySet(final String key) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        return rMap.keySet();
+    }
+
+    /**
+     * 寰�Hash涓瓨鍏ユ暟鎹�
+     *
+     * @param key   Redis閿�
+     * @param hKey  Hash閿�
+     * @param value 鍊�
+     */
+    public static <T> void setCacheMapValue(final String key, final String hKey, final T value) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        rMap.put(hKey, value);
+    }
+
+    /**
+     * 鑾峰彇Hash涓殑鏁版嵁
+     *
+     * @param key  Redis閿�
+     * @param hKey Hash閿�
+     * @return Hash涓殑瀵硅薄
+     */
+    public static <T> T getCacheMapValue(final String key, final String hKey) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        return rMap.get(hKey);
+    }
+
+    /**
+     * 鍒犻櫎Hash涓殑鏁版嵁
+     *
+     * @param key  Redis閿�
+     * @param hKey Hash閿�
+     * @return Hash涓殑瀵硅薄
+     */
+    public static <T> T delCacheMapValue(final String key, final String hKey) {
+        RMap<String, T> rMap = CLIENT.getMap(key);
+        return rMap.remove(hKey);
+    }
+
+    /**
+     * 鍒犻櫎Hash涓殑鏁版嵁
+     *
+     * @param key   Redis閿�
+     * @param hKeys Hash閿�
+     */
+    public static <T> void delMultiCacheMapValue(final String key, final Set<String> hKeys) {
+        RBatch batch = CLIENT.createBatch();
+        RMapAsync<String, T> rMap = batch.getMap(key);
+        for (String hKey : hKeys) {
+            rMap.removeAsync(hKey);
+        }
+        batch.execute();
+    }
+
+    /**
+     * 鑾峰彇澶氫釜Hash涓殑鏁版嵁
+     *
+     * @param key   Redis閿�
+     * @param hKeys Hash閿泦鍚�
+     * @return Hash瀵硅薄闆嗗悎
+     */
+    public static <K, V> Map<K, V> getMultiCacheMapValue(final String key, final Set<K> hKeys) {
+        RMap<K, V> rMap = CLIENT.getMap(key);
+        return rMap.getAll(hKeys);
+    }
+
+    /**
+     * 璁剧疆鍘熷瓙鍊�
+     *
+     * @param key   Redis閿�
+     * @param value 鍊�
+     */
+    public static void setAtomicValue(String key, long value) {
+        RAtomicLong atomic = CLIENT.getAtomicLong(key);
+        atomic.set(value);
+    }
+
+    /**
+     * 鑾峰彇鍘熷瓙鍊�
+     *
+     * @param key Redis閿�
+     * @return 褰撳墠鍊�
+     */
+    public static long getAtomicValue(String key) {
+        RAtomicLong atomic = CLIENT.getAtomicLong(key);
+        return atomic.get();
+    }
+
+    /**
+     * 閫掑鍘熷瓙鍊�
+     *
+     * @param key Redis閿�
+     * @return 褰撳墠鍊�
+     */
+    public static long incrAtomicValue(String key) {
+        RAtomicLong atomic = CLIENT.getAtomicLong(key);
+        return atomic.incrementAndGet();
+    }
+
+    /**
+     * 閫掑噺鍘熷瓙鍊�
+     *
+     * @param key Redis閿�
+     * @return 褰撳墠鍊�
+     */
+    public static long decrAtomicValue(String key) {
+        RAtomicLong atomic = CLIENT.getAtomicLong(key);
+        return atomic.decrementAndGet();
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞″垪琛�
+     *
+     * @param pattern 瀛楃涓插墠缂�
+     * @return 瀵硅薄鍒楄〃
+     */
+    public static Collection<String> keys(final String pattern) {
+        Stream<String> stream = CLIENT.getKeys().getKeysStreamByPattern(pattern);
+        return stream.collect(Collectors.toList());
+    }
+
+    /**
+     * 鍒犻櫎缂撳瓨鐨勫熀鏈璞″垪琛�
+     *
+     * @param pattern 瀛楃涓插墠缂�
+     */
+    public static void deleteKeys(final String pattern) {
+        CLIENT.getKeys().deleteByPattern(pattern);
+    }
+
+    /**
+     * 妫�鏌edis涓槸鍚﹀瓨鍦╧ey
+     *
+     * @param key 閿�
+     */
+    public static Boolean hasKey(String key) {
+        RKeys rKeys = CLIENT.getKeys();
+        return rKeys.countExists(key) > 0;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..0475b19
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,2 @@
+org.dromara.common.redis.config.RedisConfig
+org.dromara.common.redis.config.CacheConfig
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/pom.xml b/eims/ruoyi-common/ruoyi-common-satoken/pom.xml
new file mode 100644
index 0000000..4df7d4d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-satoken</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <!-- RuoYi Common Redis-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <!-- Sa-Token 鏉冮檺璁よ瘉, 鍦ㄧ嚎鏂囨。锛歨ttp://sa-token.dev33.cn/ -->
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-spring-boot3-starter</artifactId>
+        </dependency>
+
+        <!-- Sa-Token 鏁村悎 jwt -->
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-jwt</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
new file mode 100644
index 0000000..61c6b9a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
@@ -0,0 +1,54 @@
+package org.dromara.common.satoken.config;
+
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
+import cn.dev33.satoken.stp.StpInterface;
+import cn.dev33.satoken.stp.StpLogic;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
+import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
+import org.dromara.common.satoken.core.service.SaPermissionImpl;
+import org.dromara.common.satoken.handler.SaTokenExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
+
+/**
+ * sa-token 閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
+public class SaTokenConfig {
+
+    @Bean
+    public StpLogic getStpLogicJwt() {
+        // Sa-Token 鏁村悎 jwt (绠�鍗曟ā寮�)
+        return new StpLogicJwtForSimple();
+    }
+
+    /**
+     * 鏉冮檺鎺ュ彛瀹炵幇(浣跨敤bean娉ㄥ叆鏂逛究鐢ㄦ埛鏇挎崲)
+     */
+    @Bean
+    public StpInterface stpInterface() {
+        return new SaPermissionImpl();
+    }
+
+    /**
+     * 鑷畾涔塪ao灞傚瓨鍌�
+     */
+    @Bean
+    public SaTokenDao saTokenDao() {
+        return new PlusSaTokenDao();
+    }
+
+    /**
+     * 寮傚父澶勭悊鍣�
+     */
+    @Bean
+    public SaTokenExceptionHandler saTokenExceptionHandler() {
+        return new SaTokenExceptionHandler();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
new file mode 100644
index 0000000..38e12c3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java
@@ -0,0 +1,172 @@
+package org.dromara.common.satoken.core.dao;
+
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.dev33.satoken.util.SaFoxUtil;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.dromara.common.redis.utils.RedisUtils;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Sa-Token鎸佷箙灞傛帴鍙�(浣跨敤妗嗘灦鑷甫RedisUtils瀹炵幇 鍗忚缁熶竴)
+ * <p>
+ * 閲囩敤 caffeine + redis 澶氱骇缂撳瓨 浼樺寲骞跺彂鏌ヨ鏁堢巼
+ *
+ * @author Lion Li
+ */
+public class PlusSaTokenDao implements SaTokenDao {
+
+    private static final Cache<String, Object> CAFFEINE = Caffeine.newBuilder()
+        // 璁剧疆鏈�鍚庝竴娆″啓鍏ユ垨璁块棶鍚庣粡杩囧浐瀹氭椂闂磋繃鏈�
+        .expireAfterWrite(5, TimeUnit.SECONDS)
+        // 鍒濆鐨勭紦瀛樼┖闂村ぇ灏�
+        .initialCapacity(100)
+        // 缂撳瓨鐨勬渶澶ф潯鏁�
+        .maximumSize(1000)
+        .build();
+
+    /**
+     * 鑾峰彇Value锛屽鏃犺繑绌�
+     */
+    @Override
+    public String get(String key) {
+        Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key));
+        return (String) o;
+    }
+
+    /**
+     * 鍐欏叆Value锛屽苟璁惧畾瀛樻椿鏃堕棿 (鍗曚綅: 绉�)
+     */
+    @Override
+    public void set(String key, String value, long timeout) {
+        if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) {
+            return;
+        }
+        // 鍒ゆ柇鏄惁涓烘案涓嶈繃鏈�
+        if (timeout == NEVER_EXPIRE) {
+            RedisUtils.setCacheObject(key, value);
+        } else {
+            RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
+        }
+        CAFFEINE.invalidate(key);
+    }
+
+    /**
+     * 淇慨鏀规寚瀹歬ey-value閿�煎 (杩囨湡鏃堕棿涓嶅彉)
+     */
+    @Override
+    public void update(String key, String value) {
+        if (RedisUtils.hasKey(key)) {
+            RedisUtils.setCacheObject(key, value, true);
+            CAFFEINE.invalidate(key);
+        }
+    }
+
+    /**
+     * 鍒犻櫎Value
+     */
+    @Override
+    public void delete(String key) {
+        RedisUtils.deleteObject(key);
+    }
+
+    /**
+     * 鑾峰彇Value鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public long getTimeout(String key) {
+        long timeout = RedisUtils.getTimeToLive(key);
+        return timeout < 0 ? timeout : timeout / 1000;
+    }
+
+    /**
+     * 淇敼Value鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public void updateTimeout(String key, long timeout) {
+        RedisUtils.expire(key, Duration.ofSeconds(timeout));
+    }
+
+
+    /**
+     * 鑾峰彇Object锛屽鏃犺繑绌�
+     */
+    @Override
+    public Object getObject(String key) {
+        Object o = CAFFEINE.get(key, k -> RedisUtils.getCacheObject(key));
+        return o;
+    }
+
+    /**
+     * 鍐欏叆Object锛屽苟璁惧畾瀛樻椿鏃堕棿 (鍗曚綅: 绉�)
+     */
+    @Override
+    public void setObject(String key, Object object, long timeout) {
+        if (timeout == 0 || timeout <= NOT_VALUE_EXPIRE) {
+            return;
+        }
+        // 鍒ゆ柇鏄惁涓烘案涓嶈繃鏈�
+        if (timeout == NEVER_EXPIRE) {
+            RedisUtils.setCacheObject(key, object);
+        } else {
+            RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
+        }
+        CAFFEINE.invalidate(key);
+    }
+
+    /**
+     * 鏇存柊Object (杩囨湡鏃堕棿涓嶅彉)
+     */
+    @Override
+    public void updateObject(String key, Object object) {
+        if (RedisUtils.hasKey(key)) {
+            RedisUtils.setCacheObject(key, object, true);
+            CAFFEINE.invalidate(key);
+        }
+    }
+
+    /**
+     * 鍒犻櫎Object
+     */
+    @Override
+    public void deleteObject(String key) {
+        RedisUtils.deleteObject(key);
+    }
+
+    /**
+     * 鑾峰彇Object鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public long getObjectTimeout(String key) {
+        long timeout = RedisUtils.getTimeToLive(key);
+        return timeout < 0 ? timeout : timeout / 1000;
+    }
+
+    /**
+     * 淇敼Object鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public void updateObjectTimeout(String key, long timeout) {
+        RedisUtils.expire(key, Duration.ofSeconds(timeout));
+    }
+
+
+    /**
+     * 鎼滅储鏁版嵁
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
+        String keyStr = prefix + "*" + keyword + "*";
+        return (List<String>) CAFFEINE.get(keyStr, k -> {
+            Collection<String> keys = RedisUtils.keys(keyStr);
+            List<String> list = new ArrayList<>(keys);
+            return SaFoxUtil.searchList(list, start, size, sortType);
+        });
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java
new file mode 100644
index 0000000..1cef9a7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java
@@ -0,0 +1,47 @@
+package org.dromara.common.satoken.core.service;
+
+import cn.dev33.satoken.stp.StpInterface;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.UserType;
+import org.dromara.common.satoken.utils.LoginHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * sa-token 鏉冮檺绠$悊瀹炵幇绫�
+ *
+ * @author Lion Li
+ */
+public class SaPermissionImpl implements StpInterface {
+
+    /**
+     * 鑾峰彇鑿滃崟鏉冮檺鍒楄〃
+     */
+    @Override
+    public List<String> getPermissionList(Object loginId, String loginType) {
+        LoginUser loginUser = LoginHelper.getLoginUser();
+        UserType userType = UserType.getUserType(loginUser.getUserType());
+        if (userType == UserType.SYS_USER) {
+            return new ArrayList<>(loginUser.getMenuPermission());
+        } else if (userType == UserType.APP_USER) {
+            // 鍏朵粬绔� 鑷鏍规嵁涓氬姟缂栧啓
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 鑾峰彇瑙掕壊鏉冮檺鍒楄〃
+     */
+    @Override
+    public List<String> getRoleList(Object loginId, String loginType) {
+        LoginUser loginUser = LoginHelper.getLoginUser();
+        UserType userType = UserType.getUserType(loginUser.getUserType());
+        if (userType == UserType.SYS_USER) {
+            return new ArrayList<>(loginUser.getRolePermission());
+        } else if (userType == UserType.APP_USER) {
+            // 鍏朵粬绔� 鑷鏍规嵁涓氬姟缂栧啓
+        }
+        return new ArrayList<>();
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java
new file mode 100644
index 0000000..a45af89
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java
@@ -0,0 +1,52 @@
+package org.dromara.common.satoken.handler;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import cn.dev33.satoken.exception.NotRoleException;
+import cn.hutool.http.HttpStatus;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * SaToken寮傚父澶勭悊鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RestControllerAdvice
+public class SaTokenExceptionHandler {
+
+    /**
+     * 鏉冮檺鐮佸紓甯�
+     */
+    @ExceptionHandler(NotPermissionException.class)
+    public R<Void> handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鏉冮檺鐮佹牎楠屽け璐�'{}'", requestURI, e.getMessage());
+        return R.fail(HttpStatus.HTTP_FORBIDDEN, "娌℃湁璁块棶鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
+    }
+
+    /**
+     * 瑙掕壊鏉冮檺寮傚父
+     */
+    @ExceptionHandler(NotRoleException.class)
+    public R<Void> handleNotRoleException(NotRoleException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',瑙掕壊鏉冮檺鏍¢獙澶辫触'{}'", requestURI, e.getMessage());
+        return R.fail(HttpStatus.HTTP_FORBIDDEN, "娌℃湁璁块棶鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
+    }
+
+    /**
+     * 璁よ瘉澶辫触
+     */
+    @ExceptionHandler(NotLoginException.class)
+    public R<Void> handleNotLoginException(NotLoginException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',璁よ瘉澶辫触'{}',鏃犳硶璁块棶绯荤粺璧勬簮", requestURI, e.getMessage());
+        return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "璁よ瘉澶辫触锛屾棤娉曡闂郴缁熻祫婧�");
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
new file mode 100644
index 0000000..4ab7d4e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
@@ -0,0 +1,202 @@
+package org.dromara.common.satoken.utils;
+
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.UserType;
+
+import java.util.Set;
+
+/**
+ * 鐧诲綍閴存潈鍔╂墜
+ * <p>
+ * user_type 涓� 鐢ㄦ埛绫诲瀷 鍚屼竴涓敤鎴疯〃 鍙互鏈夊绉嶇敤鎴风被鍨� 渚嬪 pc,app
+ * deivce 涓� 璁惧绫诲瀷 鍚屼竴涓敤鎴风被鍨� 鍙互鏈� 澶氱璁惧绫诲瀷 渚嬪 web,ios
+ * 鍙互缁勬垚 鐢ㄦ埛绫诲瀷涓庤澶囩被鍨嬪瀵瑰鐨� 鏉冮檺鐏垫椿鎺у埗
+ * <p>
+ * 澶氱敤鎴蜂綋绯� 閽堝 澶氱鐢ㄦ埛绫诲瀷 浣嗘潈闄愭帶鍒朵笉涓�鑷�
+ * 鍙互缁勬垚 澶氱敤鎴风被鍨嬭〃涓庡璁惧绫诲瀷 鍒嗗埆鎺у埗鏉冮檺
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class LoginHelper {
+
+    public static final String LOGIN_USER_KEY = "loginUser";
+    public static final String TENANT_KEY = "tenantId";
+    public static final String USER_KEY = "userId";
+    public static final String USER_NAME_KEY = "userName";
+    public static final String DEPT_KEY = "deptId";
+    public static final String DEPT_NAME_KEY = "deptName";
+    public static final String DEPT_CATEGORY_KEY = "deptCategory";
+    public static final String CLIENT_KEY = "clientid";
+
+    /**
+     * 鐧诲綍绯荤粺 鍩轰簬 璁惧绫诲瀷
+     * 閽堝鐩稿悓鐢ㄦ埛浣撶郴涓嶅悓璁惧
+     *
+     * @param loginUser 鐧诲綍鐢ㄦ埛淇℃伅
+     * @param model     閰嶇疆鍙傛暟
+     */
+    public static void login(LoginUser loginUser, SaLoginModel model) {
+        model = ObjectUtil.defaultIfNull(model, new SaLoginModel());
+        StpUtil.login(loginUser.getLoginId(),
+            model.setExtra(TENANT_KEY, loginUser.getTenantId())
+                .setExtra(USER_KEY, loginUser.getUserId())
+                .setExtra(USER_NAME_KEY, loginUser.getUsername())
+                .setExtra(DEPT_KEY, loginUser.getDeptId())
+                .setExtra(DEPT_NAME_KEY, loginUser.getDeptName())
+                .setExtra(DEPT_CATEGORY_KEY, loginUser.getDeptCategory())
+        );
+        StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛(澶氱骇缂撳瓨)
+     */
+    public static LoginUser getLoginUser() {
+        SaSession session = StpUtil.getTokenSession();
+        if (ObjectUtil.isNull(session)) {
+            return null;
+        }
+        return (LoginUser) session.get(LOGIN_USER_KEY);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鍩轰簬token
+     */
+    public static LoginUser getLoginUser(String token) {
+        SaSession session = StpUtil.getTokenSessionByToken(token);
+        if (ObjectUtil.isNull(session)) {
+            return null;
+        }
+        return (LoginUser) session.get(LOGIN_USER_KEY);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛id
+     */
+    public static Long getUserId() {
+        return Convert.toLong(getExtra(USER_KEY));
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛璐︽埛
+     */
+    public static String getUsername() {
+        return Convert.toStr(getExtra(USER_NAME_KEY));
+    }
+
+    /**
+     * 鑾峰彇绉熸埛ID
+     */
+    public static String getTenantId() {
+        return Convert.toStr(getExtra(TENANT_KEY));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬ID
+     */
+    public static Long getDeptId() {
+        return Convert.toLong(getExtra(DEPT_KEY));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍚�
+     */
+    public static String getDeptName() {
+        return Convert.toStr(getExtra(DEPT_NAME_KEY));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬绫诲埆缂栫爜
+     */
+    public static String getDeptCategory() {
+        return Convert.toStr(getExtra(DEPT_CATEGORY_KEY));
+    }
+
+    /**
+     * 鑾峰彇褰撳墠 Token 鐨勬墿灞曚俊鎭�
+     *
+     * @param key 閿��
+     * @return 瀵瑰簲鐨勬墿灞曟暟鎹�
+     */
+    private static Object getExtra(String key) {
+        try {
+            return StpUtil.getExtra(key);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛绫诲瀷
+     */
+    public static UserType getUserType() {
+        String loginType = StpUtil.getLoginIdAsString();
+        return UserType.getUserType(loginType);
+    }
+
+    /**
+     * 鏄惁涓鸿秴绾х鐞嗗憳
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public static boolean isSuperAdmin(Long userId) {
+        return UserConstants.SUPER_ADMIN_ID.equals(userId);
+    }
+
+    /**
+     * 鏄惁涓鸿秴绾х鐞嗗憳
+     *
+     * @return 缁撴灉
+     */
+    public static boolean isSuperAdmin() {
+        return isSuperAdmin(getUserId());
+    }
+
+    /**
+     * 鏄惁涓虹鎴风鐞嗗憳
+     *
+     * @param rolePermission 瑙掕壊鏉冮檺鏍囪瘑缁�
+     * @return 缁撴灉
+     */
+    public static boolean isTenantAdmin(Set<String> rolePermission) {
+        if (CollUtil.isEmpty(rolePermission)) {
+            return false;
+        }
+        return rolePermission.contains(TenantConstants.TENANT_ADMIN_ROLE_KEY);
+    }
+
+    /**
+     * 鏄惁涓虹鎴风鐞嗗憳
+     *
+     * @return 缁撴灉
+     */
+    public static boolean isTenantAdmin() {
+        return Convert.toBool(isTenantAdmin(getLoginUser().getRolePermission()));
+    }
+
+    /**
+     * 妫�鏌ュ綋鍓嶇敤鎴锋槸鍚﹀凡鐧诲綍
+     *
+     * @return 缁撴灉
+     */
+    public static boolean isLogin() {
+        try {
+            return getLoginUser() != null;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..6dd284f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.satoken.config.SaTokenConfig
diff --git a/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml b/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
new file mode 100644
index 0000000..95e1b41
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
@@ -0,0 +1,13 @@
+# 鍐呯疆閰嶇疆 涓嶅厑璁镐慨鏀� 濡傞渶淇敼璇峰湪 nacos 涓婂啓鐩稿悓閰嶇疆瑕嗙洊
+# Sa-Token閰嶇疆
+sa-token:
+  # 鍏佽鍔ㄦ�佽缃� token 鏈夋晥鏈�
+  dynamic-active-timeout: true
+  # 鍏佽浠� 璇锋眰鍙傛暟 璇诲彇 token
+  is-read-body: true
+  # 鍏佽浠� header 璇诲彇 token
+  is-read-header: true
+  # 鍏抽棴 cookie 閴存潈 浠庢牴婧愭潨缁� csrf 婕忔礊椋庨櫓
+  is-read-cookie: false
+  # token鍓嶇紑
+  token-prefix: "Bearer"
diff --git a/eims/ruoyi-common/ruoyi-common-security/pom.xml b/eims/ruoyi-common/ruoyi-common-security/pom.xml
new file mode 100644
index 0000000..5b39df2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-security/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-security</artifactId>
+
+    <description>
+        ruoyi-common-security 瀹夊叏妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
new file mode 100644
index 0000000..5fd49d1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
@@ -0,0 +1,94 @@
+package org.dromara.common.security.config;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil;
+import cn.dev33.satoken.interceptor.SaInterceptor;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.dev33.satoken.util.SaResult;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.HttpStatus;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.security.config.properties.SecurityProperties;
+import org.dromara.common.security.handler.AllUrlHandler;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 鏉冮檺瀹夊叏閰嶇疆
+ *
+ * @author Lion Li
+ */
+
+@Slf4j
+@AutoConfiguration
+@EnableConfigurationProperties(SecurityProperties.class)
+@RequiredArgsConstructor
+public class SecurityConfig implements WebMvcConfigurer {
+
+    private final SecurityProperties securityProperties;
+
+    /**
+     * 娉ㄥ唽sa-token鐨勬嫤鎴櫒
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 娉ㄥ唽璺敱鎷︽埅鍣紝鑷畾涔夐獙璇佽鍒�
+        registry.addInterceptor(new SaInterceptor(handler -> {
+                AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class);
+                // 鐧诲綍楠岃瘉 -- 鎺掗櫎澶氫釜璺緞
+                SaRouter
+                    // 鑾峰彇鎵�鏈夌殑
+                    .match(allUrlHandler.getUrls())
+                    // 瀵规湭鎺掗櫎鐨勮矾寰勮繘琛屾鏌�
+                    .check(() -> {
+                        // 妫�鏌ユ槸鍚︾櫥褰� 鏄惁鏈塼oken
+                        StpUtil.checkLogin();
+
+                        // 妫�鏌� header 涓� param 閲岀殑 clientid 涓� token 閲岀殑鏄惁涓�鑷�
+                        String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
+                        String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
+                        String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
+                        if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
+                            // token 鏃犳晥
+                            throw NotLoginException.newInstance(StpUtil.getLoginType(),
+                                "-100", "瀹㈡埛绔疘D涓嶵oken涓嶅尮閰�",
+                                StpUtil.getTokenValue());
+                        }
+
+                        // 鏈夋晥鐜囧奖鍝� 鐢ㄤ簬涓存椂娴嬭瘯
+                        // if (log.isDebugEnabled()) {
+                        //     log.info("鍓╀綑鏈夋晥鏃堕棿: {}", StpUtil.getTokenTimeout());
+                        //     log.info("涓存椂鏈夋晥鏃堕棿: {}", StpUtil.getTokenActivityTimeout());
+                        // }
+
+                    });
+            })).addPathPatterns("/**")
+            // 鎺掗櫎涓嶉渶瑕佹嫤鎴殑璺緞
+            .excludePathPatterns(securityProperties.getExcludes());
+    }
+
+    /**
+     * 瀵� actuator 鍋ュ悍妫�鏌ユ帴鍙� 鍋氳处鍙峰瘑鐮侀壌鏉�
+     */
+    @Bean
+    public SaServletFilter getSaServletFilter() {
+        String username = SpringUtils.getProperty("spring.boot.admin.client.username");
+        String password = SpringUtils.getProperty("spring.boot.admin.client.password");
+        return new SaServletFilter()
+            .addInclude("/actuator", "/actuator/**")
+            .setAuth(obj -> {
+                SaHttpBasicUtil.check(username + ":" + password);
+            })
+            .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED));
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java
new file mode 100644
index 0000000..be1cc6e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java
@@ -0,0 +1,21 @@
+package org.dromara.common.security.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Security 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "security")
+public class SecurityProperties {
+
+    /**
+     * 鎺掗櫎璺緞
+     */
+    private String[] excludes;
+
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/AllUrlHandler.java b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/AllUrlHandler.java
new file mode 100644
index 0000000..a0c6ada
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/AllUrlHandler.java
@@ -0,0 +1,39 @@
+package org.dromara.common.security.handler;
+
+import cn.hutool.core.util.ReUtil;
+import org.dromara.common.core.utils.SpringUtils;
+import lombok.Data;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * 鑾峰彇鎵�鏈塙rl閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Data
+public class AllUrlHandler implements InitializingBean {
+
+    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
+
+    private List<String> urls = new ArrayList<>();
+
+    @Override
+    public void afterPropertiesSet() {
+        Set<String> set = new HashSet<>();
+        RequestMappingHandlerMapping mapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
+        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
+        map.keySet().forEach(info -> {
+            // 鑾峰彇娉ㄨВ涓婅竟鐨� path 鏇夸唬 path variable 涓� *
+            Objects.requireNonNull(info.getPathPatternsCondition().getPatterns())
+                    .forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*")));
+        });
+        urls.addAll(set);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..6def724
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,2 @@
+org.dromara.common.security.handler.AllUrlHandler
+org.dromara.common.security.config.SecurityConfig
diff --git a/eims/ruoyi-common/ruoyi-common-sensitive/pom.xml b/eims/ruoyi-common/ruoyi-common-sensitive/pom.xml
new file mode 100644
index 0000000..fecdf09
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sensitive/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-sensitive</artifactId>
+
+    <description>
+        ruoyi-common-sensitive 鑴辨晱妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java
new file mode 100644
index 0000000..1dfc896
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java
@@ -0,0 +1,28 @@
+package org.dromara.common.sensitive.annotation;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+import org.dromara.common.sensitive.handler.SensitiveHandler;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鏁版嵁鑴辨晱娉ㄨВ
+ *
+ * @author zhujie
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@JacksonAnnotationsInside
+@JsonSerialize(using = SensitiveHandler.class)
+public @interface Sensitive {
+    SensitiveStrategy strategy();
+
+    String roleKey() default "";
+
+    String perms() default "";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java
new file mode 100644
index 0000000..7b5264b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java
@@ -0,0 +1,18 @@
+package org.dromara.common.sensitive.core;
+
+/**
+ * 鑴辨晱鏈嶅姟
+ * 榛樿绠$悊鍛樹笉杩囨护
+ * 闇�鑷鏍规嵁涓氬姟閲嶅啓瀹炵幇
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+public interface SensitiveService {
+
+    /**
+     * 鏄惁鑴辨晱
+     */
+    boolean isSensitive(String roleKey, String perms);
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
new file mode 100644
index 0000000..995dcbd
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java
@@ -0,0 +1,99 @@
+package org.dromara.common.sensitive.core;
+
+import cn.hutool.core.util.DesensitizedUtil;
+import lombok.AllArgsConstructor;
+
+import java.util.function.Function;
+
+/**
+ * 鑴辨晱绛栫暐
+ *
+ * @author Yjoioooo
+ * @version 3.6.0
+ */
+@AllArgsConstructor
+public enum SensitiveStrategy {
+
+    /**
+     * 韬唤璇佽劚鏁�
+     */
+    ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)),
+
+    /**
+     * 鎵嬫満鍙疯劚鏁�
+     */
+    PHONE(DesensitizedUtil::mobilePhone),
+
+    /**
+     * 鍦板潃鑴辨晱
+     */
+    ADDRESS(s -> DesensitizedUtil.address(s, 8)),
+
+    /**
+     * 閭鑴辨晱
+     */
+    EMAIL(DesensitizedUtil::email),
+
+    /**
+     * 閾惰鍗�
+     */
+    BANK_CARD(DesensitizedUtil::bankCard),
+
+    /**
+     * 涓枃鍚�
+     */
+    CHINESE_NAME(DesensitizedUtil::chineseName),
+
+    /**
+     * 鍥哄畾鐢佃瘽
+     */
+    FIXED_PHONE(DesensitizedUtil::fixedPhone),
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    USER_ID(s -> String.valueOf(DesensitizedUtil.userId())),
+
+    /**
+     * 瀵嗙爜
+     */
+    PASSWORD(DesensitizedUtil::password),
+
+    /**
+     * ipv4
+     */
+    IPV4(DesensitizedUtil::ipv4),
+
+    /**
+     * ipv6
+     */
+    IPV6(DesensitizedUtil::ipv6),
+
+    /**
+     * 涓浗澶ч檰杞︾墝锛屽寘鍚櫘閫氳溅杈嗐�佹柊鑳芥簮杞﹁締
+     */
+    CAR_LICENSE(DesensitizedUtil::carLicense),
+
+    /**
+     * 鍙樉绀虹涓�涓瓧绗�
+     */
+    FIRST_MASK(DesensitizedUtil::firstMask),
+
+    /**
+     * 娓呯┖涓簄ull
+     */
+    CLEAR(s -> DesensitizedUtil.clear()),
+
+    /**
+     * 娓呯┖涓�""
+     */
+    CLEAR_TO_NULL(s -> DesensitizedUtil.clearToNull());
+
+    //鍙嚜琛屾坊鍔犲叾浠栬劚鏁忕瓥鐣�
+
+    private final Function<String, String> desensitizer;
+
+    public Function<String, String> desensitizer() {
+        return desensitizer;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java
new file mode 100644
index 0000000..c76c83a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java
@@ -0,0 +1,58 @@
+package org.dromara.common.sensitive.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveService;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * 鏁版嵁鑴辨晱json搴忓垪鍖栧伐鍏�
+ *
+ * @author Yjoioooo
+ */
+@Slf4j
+public class SensitiveHandler extends JsonSerializer<String> implements ContextualSerializer {
+
+    private SensitiveStrategy strategy;
+    private String roleKey;
+    private String perms;
+
+    @Override
+    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        try {
+            SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class);
+            if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive(roleKey, perms)) {
+                gen.writeString(strategy.desensitizer().apply(value));
+            } else {
+                gen.writeString(value);
+            }
+        } catch (BeansException e) {
+            log.error("鑴辨晱瀹炵幇涓嶅瓨鍦�, 閲囩敤榛樿澶勭悊 => {}", e.getMessage());
+            gen.writeString(value);
+        }
+    }
+
+    @Override
+    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
+        Sensitive annotation = property.getAnnotation(Sensitive.class);
+        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {
+            this.strategy = annotation.strategy();
+            this.roleKey = annotation.roleKey();
+            this.perms = annotation.perms();
+            return this;
+        }
+        return prov.findValueSerializer(property.getType(), property);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sms/pom.xml b/eims/ruoyi-common/ruoyi-common-sms/pom.xml
new file mode 100644
index 0000000..932cb9d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sms/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-sms</artifactId>
+
+    <description>
+        ruoyi-common-sms 鐭俊妯″潡
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara.sms4j</groupId>
+            <artifactId>sms4j-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- RuoYi Common Redis-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
new file mode 100644
index 0000000..3a39cc2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java
@@ -0,0 +1,33 @@
+package org.dromara.common.sms.config;
+
+import org.dromara.common.sms.core.dao.PlusSmsDao;
+import org.dromara.common.sms.handler.SmsExceptionHandler;
+import org.dromara.sms4j.api.dao.SmsDao;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+
+/**
+ * 鐭俊閰嶇疆绫�
+ *
+ * @author Feng
+ */
+@AutoConfiguration(after = {RedisAutoConfiguration.class})
+public class SmsAutoConfiguration {
+
+    @Primary
+    @Bean
+    public SmsDao smsDao() {
+        return new PlusSmsDao();
+    }
+
+    /**
+     * 寮傚父澶勭悊鍣�
+     */
+    @Bean
+    public SmsExceptionHandler smsExceptionHandler() {
+        return new SmsExceptionHandler();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
new file mode 100644
index 0000000..91d8d24
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java
@@ -0,0 +1,72 @@
+package org.dromara.common.sms.core.dao;
+
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.sms4j.api.dao.SmsDao;
+
+import java.time.Duration;
+
+/**
+ * SmsDao缂撳瓨閰嶇疆 (浣跨敤妗嗘灦鑷甫RedisUtils瀹炵幇 鍗忚缁熶竴)
+ * <p>涓昏鐢ㄤ簬鐭俊閲嶈瘯鍜屾嫤鎴殑缂撳瓨
+ *
+ * @author Feng
+ */
+public class PlusSmsDao implements SmsDao {
+
+    /**
+     * 瀛樺偍
+     *
+     * @param key       閿�
+     * @param value     鍊�
+     * @param cacheTime 缂撳瓨鏃堕棿锛堝崟浣嶏細绉�)
+     */
+    @Override
+    public void set(String key, Object value, long cacheTime) {
+        RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, Duration.ofSeconds(cacheTime));
+    }
+
+    /**
+     * 瀛樺偍
+     *
+     * @param key   閿�
+     * @param value 鍊�
+     */
+    @Override
+    public void set(String key, Object value) {
+        RedisUtils.setCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key, value, true);
+    }
+
+    /**
+     * 璇诲彇
+     *
+     * @param key 閿�
+     * @return 鍊�
+     */
+    @Override
+    public Object get(String key) {
+        return RedisUtils.getCacheObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * remove
+     * <p> 鏍规嵁key绉婚櫎缂撳瓨
+     *
+     * @param key 缂撳瓨閿�
+     * @return 琚垹闄ょ殑value
+     * @author :Wind
+     */
+    @Override
+    public Object remove(String key) {
+        return RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 娓呯┖
+     */
+    @Override
+    public void clean() {
+        RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + "sms:");
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java
new file mode 100644
index 0000000..2c619a3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java
@@ -0,0 +1,30 @@
+package org.dromara.common.sms.handler;
+
+import cn.hutool.http.HttpStatus;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.sms4j.comm.exception.SmsBlendException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * SMS寮傚父澶勭悊鍣�
+ *
+ * @author AprilWind
+ */
+@Slf4j
+@RestControllerAdvice
+public class SmsExceptionHandler {
+
+    /**
+     * sms寮傚父
+     */
+    @ExceptionHandler(SmsBlendException.class)
+    public R<Void> handleSmsBlendException(SmsBlendException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓sms鐭俊寮傚父.", requestURI, e);
+        return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "鐭俊鍙戦�佸け璐ワ紝璇风◢鍚庡啀璇�...");
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..5919ce3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.sms.config.SmsAutoConfiguration
diff --git a/eims/ruoyi-common/ruoyi-common-social/pom.xml b/eims/ruoyi-common/ruoyi-common-social/pom.xml
new file mode 100644
index 0000000..9f9a965
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-social</artifactId>
+
+    <description>
+        ruoyi-common-social 鎺堟潈璁よ瘉
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>me.zhyd.oauth</groupId>
+            <artifactId>JustAuth</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java
new file mode 100644
index 0000000..19b39d8
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java
@@ -0,0 +1,23 @@
+package org.dromara.common.social.config;
+
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.AuthRedisStateCache;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Social 閰嶇疆灞炴��
+ * @author thiszhc
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(SocialProperties.class)
+public class SocialAutoConfiguration {
+
+    @Bean
+    public AuthStateCache authStateCache() {
+        return new AuthRedisStateCache();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java
new file mode 100644
index 0000000..5f49d9c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java
@@ -0,0 +1,75 @@
+package org.dromara.common.social.config.properties;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 绀句氦鐧诲綍閰嶇疆
+ *
+ * @author thiszhc
+ */
+@Data
+public class SocialLoginConfigProperties {
+
+    /**
+     * 搴旂敤 ID
+     */
+    private String clientId;
+
+    /**
+     * 搴旂敤瀵嗛挜
+     */
+    private String clientSecret;
+
+    /**
+     * 鍥炶皟鍦板潃
+     */
+    private String redirectUri;
+
+    /**
+     * 鏄惁鑾峰彇unionId
+     */
+    private boolean unionId;
+
+    /**
+     * Coding 浼佷笟鍚嶇О
+     */
+    private String codingGroupName;
+
+    /**
+     * 鏀粯瀹濆叕閽�
+     */
+    private String alipayPublicKey;
+
+    /**
+     * 浼佷笟寰俊搴旂敤ID
+     */
+    private String agentId;
+
+    /**
+     * stackoverflow api key
+     */
+    private String stackOverflowKey;
+
+    /**
+     * 璁惧ID
+     */
+    private String deviceId;
+
+    /**
+     * 瀹㈡埛绔郴缁熺被鍨�
+     */
+    private String clientOsType;
+
+    /**
+     * maxkey 鏈嶅姟鍣ㄥ湴鍧�
+     */
+    private String serverUrl;
+
+    /**
+     * 璇锋眰鑼冨洿
+     */
+    private List<String> scopes;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
new file mode 100644
index 0000000..1487a6a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
@@ -0,0 +1,24 @@
+package org.dromara.common.social.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * Social 閰嶇疆灞炴��
+ *
+ * @author thiszhc
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "justauth")
+public class SocialProperties {
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    private Map<String, SocialLoginConfigProperties> type;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
new file mode 100644
index 0000000..b95c19e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
@@ -0,0 +1,80 @@
+package org.dromara.common.social.maxkey;
+
+import cn.hutool.core.lang.Dict;
+import me.zhyd.oauth.cache.AuthStateCache;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+
+/**
+ *  @author 闀挎槬鍙摜 2023骞�03鏈�26鏃�
+ */
+public class AuthMaxKeyRequest extends AuthDefaultRequest {
+
+    public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.maxkey.server-url");
+
+    /**
+     * 璁惧畾褰掑睘鍩�
+     */
+    public AuthMaxKeyRequest(AuthConfig config) {
+        super(config, AuthMaxKeySource.MAXKEY);
+    }
+
+    public AuthMaxKeyRequest(AuthConfig config, AuthStateCache authStateCache) {
+        super(config, AuthMaxKeySource.MAXKEY, authStateCache);
+    }
+
+    @Override
+    protected AuthToken getAccessToken(AuthCallback authCallback) {
+        String body = doPostAuthorizationCode(authCallback.getCode());
+        Dict object = JsonUtils.parseMap(body);
+        // oauth/token 楠岃瘉寮傚父
+        if (object.containsKey("error")) {
+            throw new AuthException(object.getStr("error_description"));
+        }
+        // user 楠岃瘉寮傚父
+        if (object.containsKey("message")) {
+            throw new AuthException(object.getStr("message"));
+        }
+        return AuthToken.builder()
+            .accessToken(object.getStr("access_token"))
+            .refreshToken(object.getStr("refresh_token"))
+            .idToken(object.getStr("id_token"))
+            .tokenType(object.getStr("token_type"))
+            .scope(object.getStr("scope"))
+            .build();
+    }
+
+    @Override
+    protected AuthUser getUserInfo(AuthToken authToken) {
+        String body = doGetUserInfo(authToken);
+        Dict object = JsonUtils.parseMap(body);
+        // oauth/token 楠岃瘉寮傚父
+        if (object.containsKey("error")) {
+            throw new AuthException(object.getStr("error_description"));
+        }
+        // user 楠岃瘉寮傚父
+        if (object.containsKey("message")) {
+            throw new AuthException(object.getStr("message"));
+        }
+        return AuthUser.builder()
+            .uuid(object.getStr("userId"))
+            .username(object.getStr("username"))
+            .nickname(object.getStr("displayName"))
+            .avatar(object.getStr("avatar_url"))
+            .blog(object.getStr("web_url"))
+            .company(object.getStr("organization"))
+            .location(object.getStr("location"))
+            .email(object.getStr("email"))
+            .remark(object.getStr("bio"))
+            .token(authToken)
+            .source(source.toString())
+            .build();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java
new file mode 100644
index 0000000..1ff57f7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java
@@ -0,0 +1,52 @@
+package org.dromara.common.social.maxkey;
+
+import me.zhyd.oauth.config.AuthSource;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+
+/**
+ * Oauth2 榛樿鎺ュ彛璇存槑
+ *
+ * @author 闀挎槬鍙摜 2023骞�03鏈�26鏃�
+ *
+ */
+public enum AuthMaxKeySource implements AuthSource {
+
+    /**
+     * 鑷繁鎼缓鐨� maxkey 绉佹湇
+     */
+    MAXKEY {
+
+        /**
+         * 鎺堟潈鐨刟pi
+         */
+        @Override
+        public String authorize() {
+            return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/authorize";
+        }
+
+        /**
+         * 鑾峰彇accessToken鐨刟pi
+         */
+        @Override
+        public String accessToken() {
+            return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/token";
+        }
+
+        /**
+         * 鑾峰彇鐢ㄦ埛淇℃伅鐨刟pi
+         */
+        @Override
+        public String userInfo() {
+            return AuthMaxKeyRequest.SERVER_URL + "/sign/api/oauth/v20/me";
+        }
+
+        /**
+         * 骞冲彴瀵瑰簲鐨� AuthRequest 瀹炵幇绫伙紝蹇呴』缁ф壙鑷� {@link AuthDefaultRequest}
+         */
+        @Override
+        public Class<? extends AuthDefaultRequest> getTargetClass() {
+            return AuthMaxKeyRequest.class;
+        }
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
new file mode 100644
index 0000000..13649f9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
@@ -0,0 +1,100 @@
+package org.dromara.common.social.topiam;
+
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.StrUtil;
+import com.xkcoding.http.support.HttpHeader;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.cache.AuthStateCache;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+import me.zhyd.oauth.utils.HttpUtils;
+import me.zhyd.oauth.utils.UrlBuilder;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+
+import static org.dromara.common.social.topiam.AuthTopiamSource.TOPIAM;
+
+/**
+ * TopIAM 璁よ瘉璇锋眰
+ *
+ * @author xlsea
+ * @since 2024-01-06
+ */
+@Slf4j
+public class AuthTopIamRequest extends AuthDefaultRequest {
+
+    public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.topiam.server-url");
+
+    /**
+     * 璁惧畾褰掑睘鍩�
+     */
+    public AuthTopIamRequest(AuthConfig config) {
+        super(config, TOPIAM);
+    }
+
+    public AuthTopIamRequest(AuthConfig config, AuthStateCache authStateCache) {
+        super(config, TOPIAM, authStateCache);
+    }
+
+    @Override
+    protected AuthToken getAccessToken(AuthCallback authCallback) {
+        String body = doPostAuthorizationCode(authCallback.getCode());
+        Dict object = JsonUtils.parseMap(body);
+        checkResponse(object);
+        return AuthToken.builder()
+            .accessToken(object.getStr("access_token"))
+            .refreshToken(object.getStr("refresh_token"))
+            .idToken(object.getStr("id_token"))
+            .tokenType(object.getStr("token_type"))
+            .scope(object.getStr("scope"))
+            .build();
+    }
+
+    @Override
+    protected AuthUser getUserInfo(AuthToken authToken) {
+        String body = doGetUserInfo(authToken);
+        Dict object = JsonUtils.parseMap(body);
+        checkResponse(object);
+        return AuthUser.builder()
+            .uuid(object.getStr("sub"))
+            .username(object.getStr("preferred_username"))
+            .nickname(object.getStr("nickname"))
+            .avatar(object.getStr("picture"))
+            .email(object.getStr("email"))
+            .token(authToken)
+            .source(source.toString())
+            .build();
+    }
+
+
+    @Override
+    protected String doGetUserInfo(AuthToken authToken) {
+        return new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader()
+            .add("Content-Type", "application/json")
+            .add("Authorization", "Bearer " + authToken.getAccessToken()), false).getBody();
+    }
+
+
+    @Override
+    public String authorize(String state) {
+        return UrlBuilder.fromBaseUrl(super.authorize(state))
+            .queryParam("scope", StrUtil.join("%20", config.getScopes()))
+            .build();
+    }
+
+    public static void checkResponse(Dict object) {
+        // oauth/token 楠岃瘉寮傚父
+        if (object.containsKey("error")) {
+            throw new AuthException(object.getStr("error_description"));
+        }
+        // user 楠岃瘉寮傚父
+        if (object.containsKey("message")) {
+            throw new AuthException(object.getStr("message"));
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java
new file mode 100644
index 0000000..e47d6c6
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopiamSource.java
@@ -0,0 +1,51 @@
+package org.dromara.common.social.topiam;
+
+import me.zhyd.oauth.config.AuthSource;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+
+/**
+ * Oauth2 榛樿鎺ュ彛璇存槑
+ *
+ * @author xlsea
+ * @since 2024-01-06
+ */
+public enum AuthTopiamSource implements AuthSource {
+
+    /**
+     * 娴嬭瘯
+     */
+    TOPIAM {
+        /**
+         * 鎺堟潈鐨刟pi
+         */
+        @Override
+        public String authorize() {
+            return AuthTopIamRequest.SERVER_URL + "/oauth2/auth";
+        }
+
+        /**
+         * 鑾峰彇accessToken鐨刟pi
+         */
+        @Override
+        public String accessToken() {
+            return AuthTopIamRequest.SERVER_URL + "/oauth2/token";
+        }
+
+        /**
+         * 鑾峰彇鐢ㄦ埛淇℃伅鐨刟pi
+         */
+        @Override
+        public String userInfo() {
+            return AuthTopIamRequest.SERVER_URL + "/oauth2/userinfo";
+        }
+
+        /**
+         * 骞冲彴瀵瑰簲鐨� AuthRequest 瀹炵幇绫伙紝蹇呴』缁ф壙鑷� {@link AuthDefaultRequest}
+         */
+        @Override
+        public Class<? extends AuthDefaultRequest> getTargetClass() {
+            return AuthTopIamRequest.class;
+        }
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java
new file mode 100644
index 0000000..0b6ec20
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java
@@ -0,0 +1,61 @@
+package org.dromara.common.social.utils;
+
+import lombok.AllArgsConstructor;
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.redis.utils.RedisUtils;
+
+import java.time.Duration;
+
+/**
+ * 鎺堟潈鐘舵�佺紦瀛�
+ */
+@AllArgsConstructor
+public class AuthRedisStateCache implements AuthStateCache {
+
+    /**
+     * 瀛樺叆缂撳瓨
+     *
+     * @param key   缂撳瓨key
+     * @param value 缂撳瓨鍐呭
+     */
+    @Override
+    public void cache(String key, String value) {
+        // 鎺堟潈瓒呮椂鏃堕棿 榛樿涓夊垎閽�
+        RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMinutes(3));
+    }
+
+    /**
+     * 瀛樺叆缂撳瓨
+     *
+     * @param key     缂撳瓨key
+     * @param value   缂撳瓨鍐呭
+     * @param timeout 鎸囧畾缂撳瓨杩囨湡鏃堕棿(姣)
+     */
+    @Override
+    public void cache(String key, String value, long timeout) {
+        RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMillis(timeout));
+    }
+
+    /**
+     * 鑾峰彇缂撳瓨鍐呭
+     *
+     * @param key 缂撳瓨key
+     * @return 缂撳瓨鍐呭
+     */
+    @Override
+    public String get(String key) {
+        return RedisUtils.getCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key);
+    }
+
+    /**
+     * 鏄惁瀛樺湪key锛屽鏋滃搴攌ey鐨剉alue鍊煎凡杩囨湡锛屼篃杩斿洖false
+     *
+     * @param key 缂撳瓨key
+     * @return true锛氬瓨鍦╧ey锛屽苟涓攙alue娌¤繃鏈燂紱false锛歬ey涓嶅瓨鍦ㄦ垨鑰呭凡杩囨湡
+     */
+    @Override
+    public boolean containsKey(String key) {
+        return RedisUtils.hasKey(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
new file mode 100644
index 0000000..9191fca
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
@@ -0,0 +1,73 @@
+package org.dromara.common.social.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.*;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.maxkey.AuthMaxKeyRequest;
+import org.dromara.common.social.topiam.AuthTopIamRequest;
+
+/**
+ * 璁よ瘉鎺堟潈宸ュ叿绫�
+ *
+ * @author thiszhc
+ */
+public class SocialUtils  {
+
+    private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class);
+
+    @SuppressWarnings("unchecked")
+    public static AuthResponse<AuthUser> loginAuth(String source, String code, String state, SocialProperties socialProperties) throws AuthException {
+        AuthRequest authRequest = getAuthRequest(source, socialProperties);
+        AuthCallback callback = new AuthCallback();
+        callback.setCode(code);
+        callback.setState(state);
+        return authRequest.login(callback);
+    }
+
+    public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException {
+        SocialLoginConfigProperties obj = socialProperties.getType().get(source);
+         if (ObjectUtil.isNull(obj)) {
+            throw new AuthException("涓嶆敮鎸佺殑绗笁鏂圭櫥褰曠被鍨�");
+        }
+        AuthConfig.AuthConfigBuilder builder = AuthConfig.builder()
+            .clientId(obj.getClientId())
+            .clientSecret(obj.getClientSecret())
+            .redirectUri(obj.getRedirectUri())
+            .scopes(obj.getScopes());
+        return switch (source.toLowerCase()) {
+            case "dingtalk" -> new AuthDingTalkRequest(builder.build(), STATE_CACHE);
+            case "baidu" -> new AuthBaiduRequest(builder.build(), STATE_CACHE);
+            case "github" -> new AuthGithubRequest(builder.build(), STATE_CACHE);
+            case "gitee" -> new AuthGiteeRequest(builder.build(), STATE_CACHE);
+            case "weibo" -> new AuthWeiboRequest(builder.build(), STATE_CACHE);
+            case "coding" -> new AuthCodingRequest(builder.build(), STATE_CACHE);
+            case "oschina" -> new AuthOschinaRequest(builder.build(), STATE_CACHE);
+            // 鏀粯瀹濆湪鍒涘缓鍥炶皟鍦板潃鏃讹紝涓嶅厑璁镐娇鐢╨ocalhost鎴栬��127.0.0.1锛屾墍浠ヨ繖鍎跨殑鍥炶皟鍦板潃浣跨敤鐨勫眬鍩熺綉鍐呯殑ip
+            case "alipay_wallet" -> new AuthAlipayRequest(builder.build(), socialProperties.getType().get("alipay_wallet").getAlipayPublicKey(), STATE_CACHE);
+            case "qq" -> new AuthQqRequest(builder.build(), STATE_CACHE);
+            case "wechat_open" -> new AuthWeChatOpenRequest(builder.build(), STATE_CACHE);
+            case "taobao" -> new AuthTaobaoRequest(builder.build(), STATE_CACHE);
+            case "douyin" -> new AuthDouyinRequest(builder.build(), STATE_CACHE);
+            case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE);
+            case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE);
+            case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE);
+            case "stack_overflow" -> new AuthStackOverflowRequest(builder.build(), STATE_CACHE);
+            case "huawei" -> new AuthHuaweiRequest(builder.build(), STATE_CACHE);
+            case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.build(), STATE_CACHE);
+            case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE);
+            case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE);
+            case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE);
+            case "maxkey" -> new AuthMaxKeyRequest(builder.build(), STATE_CACHE);
+            case "topiam" -> new AuthTopIamRequest(builder.build(), STATE_CACHE);
+            default -> throw new AuthException("鏈幏鍙栧埌鏈夋晥鐨凙uth閰嶇疆");
+        };
+    }
+}
+
diff --git a/eims/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..fc544a0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.social.config.SocialAutoConfiguration
diff --git a/eims/ruoyi-common/ruoyi-common-sse/pom.xml b/eims/ruoyi-common/ruoyi-common-sse/pom.xml
new file mode 100644
index 0000000..ae44c98
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-sse</artifactId>
+
+    <description>
+        ruoyi-common-sse 妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java
new file mode 100644
index 0000000..0cf8054
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java
@@ -0,0 +1,36 @@
+package org.dromara.common.sse.config;
+
+import org.dromara.common.sse.controller.SseController;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.listener.SseTopicListener;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * SSE 鑷姩瑁呴厤
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@ConditionalOnProperty(value = "sse.enabled", havingValue = "true")
+@EnableConfigurationProperties(SseProperties.class)
+public class SseAutoConfiguration {
+
+    @Bean
+    public SseEmitterManager sseEmitterManager() {
+        return new SseEmitterManager();
+    }
+
+    @Bean
+    public SseTopicListener sseTopicListener() {
+        return new SseTopicListener();
+    }
+
+    @Bean
+    public SseController sseController(SseEmitterManager sseEmitterManager) {
+        return new SseController(sseEmitterManager);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java
new file mode 100644
index 0000000..ce4e173
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java
@@ -0,0 +1,21 @@
+package org.dromara.common.sse.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * SSE 閰嶇疆椤�
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties("sse")
+public class SseProperties {
+
+    private Boolean enabled;
+
+    /**
+     * 璺緞
+     */
+    private String path;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java
new file mode 100644
index 0000000..e5331e4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java
@@ -0,0 +1,87 @@
+package org.dromara.common.sse.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.stp.StpUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+
+/**
+ * SSE 鎺у埗鍣�
+ *
+ * @author Lion Li
+ */
+@RestController
+@ConditionalOnProperty(value = "sse.enabled", havingValue = "true")
+@RequiredArgsConstructor
+public class SseController implements DisposableBean {
+
+    private final SseEmitterManager sseEmitterManager;
+
+    /**
+     * 寤虹珛 SSE 杩炴帴
+     */
+    @GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public SseEmitter connect() {
+        String tokenValue = StpUtil.getTokenValue();
+        Long userId = LoginHelper.getUserId();
+        return sseEmitterManager.connect(userId, tokenValue);
+    }
+
+    /**
+     * 鍏抽棴 SSE 杩炴帴
+     */
+    @SaIgnore
+    @GetMapping(value = "${sse.path}/close")
+    public R<Void> close() {
+        String tokenValue = StpUtil.getTokenValue();
+        Long userId = LoginHelper.getUserId();
+        sseEmitterManager.disconnect(userId, tokenValue);
+        return R.ok();
+    }
+
+    /**
+     * 鍚戠壒瀹氱敤鎴峰彂閫佹秷鎭�
+     *
+     * @param userId 鐩爣鐢ㄦ埛鐨� ID
+     * @param msg    瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    @GetMapping(value = "${sse.path}/send")
+    public R<Void> send(Long userId, String msg) {
+        SseMessageDto dto = new SseMessageDto();
+        dto.setUserIds(List.of(userId));
+        dto.setMessage(msg);
+        sseEmitterManager.publishMessage(dto);
+        return R.ok();
+    }
+
+    /**
+     * 鍚戞墍鏈夌敤鎴峰彂閫佹秷鎭�
+     *
+     * @param msg 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    @GetMapping(value = "${sse.path}/sendAll")
+    public R<Void> send(String msg) {
+        sseEmitterManager.publishAll(msg);
+        return R.ok();
+    }
+
+    /**
+     * 娓呯悊璧勬簮銆傛鏂规硶鐩墠涓嶆墽琛屼换浣曟搷浣滐紝浣嗛伩鍏嶅洜鏈疄鐜拌�屽鑷撮敊璇�
+     */
+    @Override
+    public void destroy() throws Exception {
+        // 閿�姣佹椂涓嶉渶瑕佸仛浠�涔� 姝ゆ柟娉曢伩鍏嶆棤鐢ㄦ搷浣滄姤閿�
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
new file mode 100644
index 0000000..1d37a27
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java
@@ -0,0 +1,160 @@
+package org.dromara.common.sse.core;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.sse.dto.SseMessageDto;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+
+/**
+ * 绠$悊 Server-Sent Events (SSE) 杩炴帴
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SseEmitterManager {
+
+    /**
+     * 璁㈤槄鐨勯閬�
+     */
+    private final static String SSE_TOPIC = "global:sse";
+
+    private final static Map<Long, Map<String, SseEmitter>> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>();
+
+    /**
+     * 寤虹珛涓庢寚瀹氱敤鎴风殑 SSE 杩炴帴
+     *
+     * @param userId 鐢ㄦ埛鐨勫敮涓�鏍囪瘑绗︼紝鐢ㄤ簬鍖哄垎涓嶅悓鐢ㄦ埛鐨勮繛鎺�
+     * @param token  鐢ㄦ埛鐨勫敮涓�浠ょ墝锛岀敤浜庤瘑鍒叿浣撶殑杩炴帴
+     * @return 杩斿洖涓�涓� SseEmitter 瀹炰緥锛屽鎴风鍙互閫氳繃璇ュ疄渚嬫帴鏀� SSE 浜嬩欢
+     */
+    public SseEmitter connect(Long userId, String token) {
+        // 浠� USER_TOKEN_EMITTERS 涓幏鍙栨垨鍒涘缓褰撳墠鐢ㄦ埛鐨� SseEmitter 鏄犲皠琛紙ConcurrentHashMap锛�
+        // 姣忎釜鐢ㄦ埛鍙互鏈夊涓� SSE 杩炴帴锛岄�氳繃 token 杩涜鍖哄垎
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>());
+
+        // 鍒涘缓涓�涓柊鐨� SseEmitter 瀹炰緥锛岃秴鏃舵椂闂磋缃负 0 琛ㄧず鏃犻檺鍒�
+        SseEmitter emitter = new SseEmitter(0L);
+
+        emitters.put(token, emitter);
+
+        // 褰� emitter 瀹屾垚銆佽秴鏃舵垨鍙戠敓閿欒鏃讹紝浠庢槧灏勮〃涓Щ闄ゅ搴旂殑 token
+        emitter.onCompletion(() -> emitters.remove(token));
+        emitter.onTimeout(() -> emitters.remove(token));
+        emitter.onError((e) -> emitters.remove(token));
+
+        try {
+            // 鍚戝鎴风鍙戦�佷竴鏉¤繛鎺ユ垚鍔熺殑浜嬩欢
+            emitter.send(SseEmitter.event().comment("connected"));
+        } catch (IOException e) {
+            // 濡傛灉鍙戦�佹秷鎭け璐ワ紝鍒欎粠鏄犲皠琛ㄤ腑绉婚櫎 emitter
+            emitters.remove(token);
+        }
+        return emitter;
+    }
+
+    /**
+     * 鏂紑鎸囧畾鐢ㄦ埛鐨� SSE 杩炴帴
+     *
+     * @param userId 鐢ㄦ埛鐨勫敮涓�鏍囪瘑绗︼紝鐢ㄤ簬鍖哄垎涓嶅悓鐢ㄦ埛鐨勮繛鎺�
+     * @param token  鐢ㄦ埛鐨勫敮涓�浠ょ墝锛岀敤浜庤瘑鍒叿浣撶殑杩炴帴
+     */
+    public void disconnect(Long userId, String token) {
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
+        if (emitters != null) {
+            try {
+                emitters.get(token).send(SseEmitter.event().comment("disconnected"));
+            } catch (Exception ignore) {
+            }
+            emitters.remove(token);
+        }
+    }
+
+    /**
+     * 璁㈤槄SSE娑堟伅涓婚锛屽苟鎻愪緵涓�涓秷璐硅�呭嚱鏁版潵澶勭悊鎺ユ敹鍒扮殑娑堟伅
+     *
+     * @param consumer 澶勭悊SSE娑堟伅鐨勬秷璐硅�呭嚱鏁�
+     */
+    public void subscribeMessage(Consumer<SseMessageDto> consumer) {
+        RedisUtils.subscribe(SSE_TOPIC, SseMessageDto.class, consumer);
+    }
+
+    /**
+     * 鍚戞寚瀹氱殑鐢ㄦ埛浼氳瘽鍙戦�佹秷鎭�
+     *
+     * @param userId  瑕佸彂閫佹秷鎭殑鐢ㄦ埛id
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public void sendMessage(Long userId, String message) {
+        Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
+        if (emitters != null) {
+            for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
+                try {
+                    entry.getValue().send(SseEmitter.event()
+                        .name("message")
+                        .data(message));
+                } catch (Exception e) {
+                    emitters.remove(entry.getKey());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鏈満鍏ㄧ敤鎴蜂細璇濆彂閫佹秷鎭�
+     *
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public void sendMessage(String message) {
+        for (Long userId : USER_TOKEN_EMITTERS.keySet()) {
+            sendMessage(userId, message);
+        }
+    }
+
+    /**
+     * 鍙戝竷SSE璁㈤槄娑堟伅
+     *
+     * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
+     */
+    public void publishMessage(SseMessageDto sseMessageDto) {
+        List<Long> unsentUserIds = new ArrayList<>();
+        // 褰撳墠鏈嶅姟鍐呯敤鎴�,鐩存帴鍙戦�佹秷鎭�
+        for (Long userId : sseMessageDto.getUserIds()) {
+            if (USER_TOKEN_EMITTERS.containsKey(userId)) {
+                sendMessage(userId, sseMessageDto.getMessage());
+                continue;
+            }
+            unsentUserIds.add(userId);
+        }
+        // 涓嶅湪褰撳墠鏈嶅姟鍐呯敤鎴�,鍙戝竷璁㈤槄娑堟伅
+        if (CollUtil.isNotEmpty(unsentUserIds)) {
+            SseMessageDto broadcastMessage = new SseMessageDto();
+            broadcastMessage.setMessage(sseMessageDto.getMessage());
+            broadcastMessage.setUserIds(unsentUserIds);
+            RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
+                log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} session keys:{} message:{}",
+                    SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage());
+            });
+        }
+    }
+
+    /**
+     * 鍚戞墍鏈夌殑鐢ㄦ埛鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+     *
+     * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
+     */
+    public void publishAll(String message) {
+        SseMessageDto broadcastMessage = new SseMessageDto();
+        broadcastMessage.setMessage(message);
+        RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> {
+            log.info("SSE鍙戦�佷富棰樿闃呮秷鎭痶opic:{} message:{}", SSE_TOPIC, message);
+        });
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java
new file mode 100644
index 0000000..a2e1210
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java
@@ -0,0 +1,29 @@
+package org.dromara.common.sse.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 娑堟伅鐨刣to
+ *
+ * @author zendwang
+ */
+@Data
+public class SseMessageDto implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 闇�瑕佹帹閫佸埌鐨剆ession key 鍒楄〃
+     */
+    private List<Long> userIds;
+
+    /**
+     * 闇�瑕佸彂閫佺殑娑堟伅
+     */
+    private String message;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java
new file mode 100644
index 0000000..7a4dff1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java
@@ -0,0 +1,48 @@
+package org.dromara.common.sse.listener;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.Ordered;
+
+/**
+ * SSE 涓婚璁㈤槄鐩戝惉鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SseTopicListener implements ApplicationRunner, Ordered {
+
+    @Autowired
+    private SseEmitterManager sseEmitterManager;
+
+    /**
+     * 鍦⊿pring Boot搴旂敤绋嬪簭鍚姩鏃跺垵濮嬪寲SSE涓婚璁㈤槄鐩戝惉鍣�
+     *
+     * @param args 搴旂敤绋嬪簭鍙傛暟
+     * @throws Exception 鍒濆鍖栬繃绋嬩腑鍙兘鎶涘嚭鐨勫紓甯�
+     */
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        sseEmitterManager.subscribeMessage((message) -> {
+            log.info("SSE涓婚璁㈤槄鏀跺埌娑堟伅session keys={} message={}", message.getUserIds(), message.getMessage());
+            // 濡傛灉key涓嶄负绌哄氨鎸夌収key鍙戞秷鎭� 濡傛灉涓虹┖灏辩兢鍙�
+            if (CollUtil.isNotEmpty(message.getUserIds())) {
+                message.getUserIds().forEach(key -> {
+                    sseEmitterManager.sendMessage(key, message.getMessage());
+                });
+            } else {
+                sseEmitterManager.sendMessage(message.getMessage());
+            }
+        });
+        log.info("鍒濆鍖朣SE涓婚璁㈤槄鐩戝惉鍣ㄦ垚鍔�");
+    }
+
+    @Override
+    public int getOrder() {
+        return -1;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
new file mode 100644
index 0000000..c6abdc8
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java
@@ -0,0 +1,58 @@
+package org.dromara.common.sse.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.sse.core.SseEmitterManager;
+import org.dromara.common.sse.dto.SseMessageDto;
+
+/**
+ * SSE宸ュ叿绫�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class SseMessageUtils {
+
+    private final static SseEmitterManager MANAGER = SpringUtils.getBean(SseEmitterManager.class);
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�佹秷鎭�
+     *
+     * @param userId  瑕佸彂閫佹秷鎭殑鐢ㄦ埛id
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public static void sendMessage(Long userId, String message) {
+        MANAGER.sendMessage(userId, message);
+    }
+
+    /**
+     * 鏈満鍏ㄧ敤鎴蜂細璇濆彂閫佹秷鎭�
+     *
+     * @param message 瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public static void sendMessage(String message) {
+        MANAGER.sendMessage(message);
+    }
+
+    /**
+     * 鍙戝竷SSE璁㈤槄娑堟伅
+     *
+     * @param sseMessageDto 瑕佸彂甯冪殑SSE娑堟伅瀵硅薄
+     */
+    public static void publishMessage(SseMessageDto sseMessageDto) {
+        MANAGER.publishMessage(sseMessageDto);
+    }
+
+    /**
+     * 鍚戞墍鏈夌殑鐢ㄦ埛鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+     *
+     * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
+     */
+    public static void publishAll(String message) {
+        MANAGER.publishAll(message);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..b809713
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.sse.config.SseAutoConfiguration
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/pom.xml b/eims/ruoyi-common/ruoyi-common-tenant/pom.xml
new file mode 100644
index 0000000..8e1a6ab
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-tenant</artifactId>
+
+    <description>
+        ruoyi-common-tenant 绉熸埛妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
new file mode 100644
index 0000000..07302bc
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java
@@ -0,0 +1,89 @@
+package org.dromara.common.tenant.config;
+
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.mybatis.config.MybatisPlusConfig;
+import org.dromara.common.redis.config.RedisConfig;
+import org.dromara.common.redis.config.properties.RedissonProperties;
+import org.dromara.common.tenant.core.TenantSaTokenDao;
+import org.dromara.common.tenant.handle.PlusTenantLineHandler;
+import org.dromara.common.tenant.handle.TenantKeyPrefixHandler;
+import org.dromara.common.tenant.manager.TenantSpringCacheManager;
+import org.dromara.common.tenant.properties.TenantProperties;
+import org.redisson.config.ClusterServersConfig;
+import org.redisson.config.SingleServerConfig;
+import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cache.CacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+
+/**
+ * 绉熸埛閰嶇疆绫�
+ *
+ * @author Lion Li
+ */
+@EnableConfigurationProperties(TenantProperties.class)
+@AutoConfiguration(after = {RedisConfig.class})
+@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
+public class TenantConfig {
+
+    @ConditionalOnBean(MybatisPlusConfig.class)
+    @AutoConfiguration(after = {MybatisPlusConfig.class})
+    static class MybatisPlusConfiguration {
+
+        /**
+         * 澶氱鎴锋彃浠�
+         */
+        @Bean
+        public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) {
+            return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties));
+        }
+
+    }
+
+    @Bean
+    public RedissonAutoConfigurationCustomizer tenantRedissonCustomizer(RedissonProperties redissonProperties) {
+        return config -> {
+            TenantKeyPrefixHandler nameMapper = new TenantKeyPrefixHandler(redissonProperties.getKeyPrefix());
+            SingleServerConfig singleServerConfig = ReflectUtils.invokeGetter(config, "singleServerConfig");
+            if (ObjectUtil.isNotNull(singleServerConfig)) {
+                // 浣跨敤鍗曟満妯″紡
+                // 璁剧疆澶氱鎴� redis key鍓嶇紑
+                singleServerConfig.setNameMapper(nameMapper);
+                ReflectUtils.invokeSetter(config, "singleServerConfig", singleServerConfig);
+            }
+            ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig");
+            // 闆嗙兢閰嶇疆鏂瑰紡 鍙傝�冧笅鏂规敞閲�
+            if (ObjectUtil.isNotNull(clusterServersConfig)) {
+                // 璁剧疆澶氱鎴� redis key鍓嶇紑
+                clusterServersConfig.setNameMapper(nameMapper);
+                ReflectUtils.invokeSetter(config, "clusterServersConfig", clusterServersConfig);
+            }
+        };
+    }
+
+    /**
+     * 澶氱鎴风紦瀛樼鐞嗗櫒
+     */
+    @Primary
+    @Bean
+    public CacheManager tenantCacheManager() {
+        return new TenantSpringCacheManager();
+    }
+
+    /**
+     * 澶氱鎴烽壌鏉僤ao瀹炵幇
+     */
+    @Primary
+    @Bean
+    public SaTokenDao tenantSaTokenDao() {
+        return new TenantSaTokenDao();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java
new file mode 100644
index 0000000..8ad0d2c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java
@@ -0,0 +1,21 @@
+package org.dromara.common.tenant.core;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 绉熸埛鍩虹被
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class TenantEntity extends BaseEntity {
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantSaTokenDao.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantSaTokenDao.java
new file mode 100644
index 0000000..b8da28e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantSaTokenDao.java
@@ -0,0 +1,148 @@
+package org.dromara.common.tenant.core;
+
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
+
+import java.time.Duration;
+import java.util.List;
+
+/**
+ * SaToken 璁よ瘉鏁版嵁鎸佷箙灞� 閫傞厤澶氱鎴�
+ *
+ * @author Lion Li
+ */
+public class TenantSaTokenDao extends PlusSaTokenDao {
+
+    @Override
+    public String get(String key) {
+        return super.get(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    @Override
+    public void set(String key, String value, long timeout) {
+        super.set(GlobalConstants.GLOBAL_REDIS_KEY + key, value, timeout);
+    }
+
+    /**
+     * 淇慨鏀规寚瀹歬ey-value閿�煎 (杩囨湡鏃堕棿涓嶅彉)
+     */
+    @Override
+    public void update(String key, String value) {
+        long expire = getTimeout(key);
+        // -2 = 鏃犳閿�
+        if (expire == NOT_VALUE_EXPIRE) {
+            return;
+        }
+        this.set(key, value, expire);
+    }
+
+    /**
+     * 鍒犻櫎Value
+     */
+    @Override
+    public void delete(String key) {
+        super.delete(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 鑾峰彇Value鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public long getTimeout(String key) {
+        return super.getTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 淇敼Value鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public void updateTimeout(String key, long timeout) {
+        // 鍒ゆ柇鏄惁鎯宠璁剧疆涓烘案涔�
+        if (timeout == NEVER_EXPIRE) {
+            long expire = getTimeout(key);
+            if (expire == NEVER_EXPIRE) {
+                // 濡傛灉鍏跺凡缁忚璁剧疆涓烘案涔咃紝鍒欎笉浣滀换浣曞鐞�
+            } else {
+                // 濡傛灉灏氭湭琚缃负姘镐箙锛岄偅涔堝啀娆et涓�娆�
+                this.set(key, this.get(key), timeout);
+            }
+            return;
+        }
+        RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout));
+    }
+
+
+    /**
+     * 鑾峰彇Object锛屽鏃犺繑绌�
+     */
+    @Override
+    public Object getObject(String key) {
+        return super.getObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 鍐欏叆Object锛屽苟璁惧畾瀛樻椿鏃堕棿 (鍗曚綅: 绉�)
+     */
+    @Override
+    public void setObject(String key, Object object, long timeout) {
+        super.setObject(GlobalConstants.GLOBAL_REDIS_KEY + key, object, timeout);
+    }
+
+    /**
+     * 鏇存柊Object (杩囨湡鏃堕棿涓嶅彉)
+     */
+    @Override
+    public void updateObject(String key, Object object) {
+        long expire = getObjectTimeout(key);
+        // -2 = 鏃犳閿�
+        if (expire == NOT_VALUE_EXPIRE) {
+            return;
+        }
+        this.setObject(key, object, expire);
+    }
+
+    /**
+     * 鍒犻櫎Object
+     */
+    @Override
+    public void deleteObject(String key) {
+        super.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 鑾峰彇Object鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public long getObjectTimeout(String key) {
+        return super.getObjectTimeout(GlobalConstants.GLOBAL_REDIS_KEY + key);
+    }
+
+    /**
+     * 淇敼Object鐨勫墿浣欏瓨娲绘椂闂� (鍗曚綅: 绉�)
+     */
+    @Override
+    public void updateObjectTimeout(String key, long timeout) {
+        // 鍒ゆ柇鏄惁鎯宠璁剧疆涓烘案涔�
+        if (timeout == NEVER_EXPIRE) {
+            long expire = getObjectTimeout(key);
+            if (expire == NEVER_EXPIRE) {
+                // 濡傛灉鍏跺凡缁忚璁剧疆涓烘案涔咃紝鍒欎笉浣滀换浣曞鐞�
+            } else {
+                // 濡傛灉灏氭湭琚缃负姘镐箙锛岄偅涔堝啀娆et涓�娆�
+                this.setObject(key, this.getObject(key), timeout);
+            }
+            return;
+        }
+        RedisUtils.expire(GlobalConstants.GLOBAL_REDIS_KEY + key, Duration.ofSeconds(timeout));
+    }
+
+
+    /**
+     * 鎼滅储鏁版嵁
+     */
+    @Override
+    public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
+        return super.searchData(GlobalConstants.GLOBAL_REDIS_KEY + prefix, keyword, start, size, sortType);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/exception/TenantException.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/exception/TenantException.java
new file mode 100644
index 0000000..ee2bc97
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/exception/TenantException.java
@@ -0,0 +1,20 @@
+package org.dromara.common.tenant.exception;
+
+import org.dromara.common.core.exception.base.BaseException;
+
+import java.io.Serial;
+
+/**
+ * 绉熸埛寮傚父绫�
+ *
+ * @author Lion Li
+ */
+public class TenantException extends BaseException {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    public TenantException(String code, Object... args) {
+        super("tenant", code, args, null);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/PlusTenantLineHandler.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/PlusTenantLineHandler.java
new file mode 100644
index 0000000..6c93ee5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/PlusTenantLineHandler.java
@@ -0,0 +1,56 @@
+package org.dromara.common.tenant.handle;
+
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.expression.Expression;
+import net.sf.jsqlparser.expression.NullValue;
+import net.sf.jsqlparser.expression.StringValue;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.tenant.properties.TenantProperties;
+
+import java.util.List;
+
+/**
+ * 鑷畾涔夌鎴峰鐞嗗櫒
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@AllArgsConstructor
+public class PlusTenantLineHandler implements TenantLineHandler {
+
+    private final TenantProperties tenantProperties;
+
+    @Override
+    public Expression getTenantId() {
+        String tenantId = TenantHelper.getTenantId();
+        if (StringUtils.isBlank(tenantId)) {
+            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+            return new NullValue();
+        }
+        // 杩斿洖鍥哄畾绉熸埛
+        return new StringValue(tenantId);
+    }
+
+    @Override
+    public boolean ignoreTable(String tableName) {
+        String tenantId = TenantHelper.getTenantId();
+        // 鍒ゆ柇鏄惁鏈夌鎴�
+        if (StringUtils.isNotBlank(tenantId)) {
+            // 涓嶉渶瑕佽繃婊ょ鎴风殑琛�
+            List<String> excludes = tenantProperties.getExcludes();
+            // 闈炰笟鍔¤〃
+            List<String> tables = ListUtil.toList(
+                "gen_table",
+                "gen_table_column"
+            );
+            tables.addAll(excludes);
+            return tables.contains(tableName);
+        }
+        return true;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java
new file mode 100644
index 0000000..9475398
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java
@@ -0,0 +1,73 @@
+package org.dromara.common.tenant.handle;
+
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.redis.handler.KeyPrefixHandler;
+import org.dromara.common.tenant.helper.TenantHelper;
+
+/**
+ * 澶氱鎴穜edis缂撳瓨key鍓嶇紑澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class TenantKeyPrefixHandler extends KeyPrefixHandler {
+
+    public TenantKeyPrefixHandler(String keyPrefix) {
+        super(keyPrefix);
+    }
+
+    /**
+     * 澧炲姞鍓嶇紑
+     */
+    @Override
+    public String map(String name) {
+        if (StringUtils.isBlank(name)) {
+            return null;
+        }
+        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+            return super.map(name);
+        }
+        if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
+            return super.map(name);
+        }
+        String tenantId = TenantHelper.getTenantId();
+        if (StringUtils.isBlank(tenantId)) {
+            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+        }
+        if (StringUtils.startsWith(name, tenantId + "")) {
+            // 濡傛灉瀛樺湪鍒欑洿鎺ヨ繑鍥�
+            return super.map(name);
+        }
+        return super.map(tenantId + ":" + name);
+    }
+
+    /**
+     * 鍘婚櫎鍓嶇紑
+     */
+    @Override
+    public String unmap(String name) {
+        String unmap = super.unmap(name);
+        if (StringUtils.isBlank(unmap)) {
+            return null;
+        }
+        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+            return super.unmap(name);
+        }
+        if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
+            return super.unmap(name);
+        }
+        String tenantId = TenantHelper.getTenantId();
+        if (StringUtils.isBlank(tenantId)) {
+            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+        }
+        if (StringUtils.startsWith(unmap, tenantId + "")) {
+            // 濡傛灉瀛樺湪鍒欏垹闄�
+            return unmap.substring((tenantId + ":").length());
+        }
+        return unmap;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
new file mode 100644
index 0000000..b185612
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java
@@ -0,0 +1,230 @@
+package org.dromara.common.tenant.helper;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+
+import java.util.Stack;
+import java.util.function.Supplier;
+
+/**
+ * 绉熸埛鍔╂墜
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class TenantHelper {
+
+    private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
+
+    private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new ThreadLocal<>();
+
+    private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
+
+    /**
+     * 绉熸埛鍔熻兘鏄惁鍚敤
+     */
+    public static boolean isEnable() {
+        return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false);
+    }
+
+    private static IgnoreStrategy getIgnoreStrategy() {
+        Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
+        if (ignoreStrategyLocal instanceof ThreadLocal<?> IGNORE_STRATEGY_LOCAL) {
+            if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
+                return ignoreStrategy;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 寮�鍚拷鐣ョ鎴�(寮�鍚悗闇�鎵嬪姩璋冪敤 {@link #disableIgnore()} 鍏抽棴)
+     */
+    public static void enableIgnore() {
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNull(ignoreStrategy)) {
+            InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
+        } else {
+            ignoreStrategy.setTenantLine(true);
+        }
+        Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+        reentrantStack.push(reentrantStack.size() + 1);
+    }
+
+    /**
+     * 鍏抽棴蹇界暐绉熸埛
+     */
+    public static void disableIgnore() {
+        IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+        if (ObjectUtil.isNotNull(ignoreStrategy)) {
+            boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
+                && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
+                && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
+                && !Boolean.TRUE.equals(ignoreStrategy.getDataPermission())
+                && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
+            Stack<Integer> reentrantStack = REENTRANT_IGNORE.get();
+            boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
+            if (noOtherIgnoreStrategy && empty) {
+                InterceptorIgnoreHelper.clearIgnoreStrategy();
+            } else if (empty) {
+                ignoreStrategy.setTenantLine(false);
+            }
+        }
+    }
+
+    /**
+     * 鍦ㄥ拷鐣ョ鎴蜂腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static void ignore(Runnable handle) {
+        enableIgnore();
+        try {
+            handle.run();
+        } finally {
+            disableIgnore();
+        }
+    }
+
+    /**
+     * 鍦ㄥ拷鐣ョ鎴蜂腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static <T> T ignore(Supplier<T> handle) {
+        enableIgnore();
+        try {
+            return handle.get();
+        } finally {
+            disableIgnore();
+        }
+    }
+
+    public static void setDynamic(String tenantId) {
+        setDynamic(tenantId, false);
+    }
+
+    /**
+     * 璁剧疆鍔ㄦ�佺鎴�(涓�鐩存湁鏁� 闇�瑕佹墜鍔ㄦ竻鐞�)
+     * <p>
+     * 濡傛灉涓烘湭鐧诲綍鐘舵�佷笅 閭d箞鍙湪褰撳墠绾跨▼鍐呯敓鏁�
+     *
+     * @param tenantId 绉熸埛id
+     * @param global   鏄惁鍏ㄥ眬鐢熸晥
+     */
+    public static void setDynamic(String tenantId, boolean global) {
+        if (!isEnable()) {
+            return;
+        }
+        if (!isLogin() || !global) {
+            TEMP_DYNAMIC_TENANT.set(tenantId);
+            return;
+        }
+        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
+        RedisUtils.setCacheObject(cacheKey, tenantId);
+    }
+
+    /**
+     * 鑾峰彇鍔ㄦ�佺鎴�(涓�鐩存湁鏁� 闇�瑕佹墜鍔ㄦ竻鐞�)
+     * <p>
+     * 濡傛灉涓烘湭鐧诲綍鐘舵�佷笅 閭d箞鍙湪褰撳墠绾跨▼鍐呯敓鏁�
+     */
+    public static String getDynamic() {
+        if (!isEnable()) {
+            return null;
+        }
+        if (!isLogin()) {
+            return TEMP_DYNAMIC_TENANT.get();
+        }
+        // 濡傛灉绾跨▼鍐呮湁鍊� 浼樺厛杩斿洖
+        String tenantId = TEMP_DYNAMIC_TENANT.get();
+        if (StringUtils.isNotBlank(tenantId)) {
+            return tenantId;
+        }
+        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
+        tenantId = RedisUtils.getCacheObject(cacheKey);
+        return tenantId;
+    }
+
+    /**
+     * 娓呴櫎鍔ㄦ�佺鎴�
+     */
+    public static void clearDynamic() {
+        if (!isEnable()) {
+            return;
+        }
+        if (!isLogin()) {
+            TEMP_DYNAMIC_TENANT.remove();
+            return;
+        }
+        TEMP_DYNAMIC_TENANT.remove();
+        String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
+        RedisUtils.deleteObject(cacheKey);
+    }
+
+    /**
+     * 鍦ㄥ姩鎬佺鎴蜂腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static void dynamic(String tenantId, Runnable handle) {
+        setDynamic(tenantId);
+        try {
+            handle.run();
+        } finally {
+            clearDynamic();
+        }
+    }
+
+    /**
+     * 鍦ㄥ姩鎬佺鎴蜂腑鎵ц
+     *
+     * @param handle 澶勭悊鎵ц鏂规硶
+     */
+    public static <T> T dynamic(String tenantId, Supplier<T> handle) {
+        setDynamic(tenantId);
+        try {
+            return handle.get();
+        } finally {
+            clearDynamic();
+        }
+    }
+
+    /**
+     * 鑾峰彇褰撳墠绉熸埛id(鍔ㄦ�佺鎴蜂紭鍏�)
+     */
+    public static String getTenantId() {
+        if (!isEnable()) {
+            return null;
+        }
+        String tenantId = TenantHelper.getDynamic();
+        if (StringUtils.isBlank(tenantId)) {
+            tenantId = LoginHelper.getTenantId();
+        }
+        return tenantId;
+    }
+
+    private static boolean isLogin() {
+        try {
+            StpUtil.checkLogin();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java
new file mode 100644
index 0000000..346e36f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java
@@ -0,0 +1,41 @@
+package org.dromara.common.tenant.manager;
+
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.redis.manager.PlusSpringCacheManager;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.springframework.cache.Cache;
+
+/**
+ * 閲嶅啓 cacheName 澶勭悊鏂规硶 鏀寔澶氱鎴�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class TenantSpringCacheManager extends PlusSpringCacheManager {
+
+    public TenantSpringCacheManager() {
+    }
+
+    @Override
+    public Cache getCache(String name) {
+        if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
+            return super.getCache(name);
+        }
+        if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
+            return super.getCache(name);
+        }
+        String tenantId = TenantHelper.getTenantId();
+        if (StringUtils.isBlank(tenantId)) {
+            log.error("鏃犳硶鑾峰彇鏈夋晥鐨勭鎴穒d -> Null");
+        }
+        if (StringUtils.startsWith(name, tenantId)) {
+            // 濡傛灉瀛樺湪鍒欑洿鎺ヨ繑鍥�
+            return super.getCache(name);
+        }
+        return super.getCache(tenantId + ":" + name);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java
new file mode 100644
index 0000000..1675ccf
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java
@@ -0,0 +1,27 @@
+package org.dromara.common.tenant.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * 绉熸埛 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "tenant")
+public class TenantProperties {
+
+    /**
+     * 鏄惁鍚敤
+     */
+    private Boolean enable;
+
+    /**
+     * 鎺掗櫎琛�
+     */
+    private List<String> excludes;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..f837191
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.tenant.config.TenantConfig
diff --git a/eims/ruoyi-common/ruoyi-common-translation/pom.xml b/eims/ruoyi-common/ruoyi-common-translation/pom.xml
new file mode 100644
index 0000000..e77b868
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-translation</artifactId>
+
+    <description>
+        ruoyi-common-translation 閫氱敤缈昏瘧鍔熻兘
+    </description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java
new file mode 100644
index 0000000..c24aa6f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java
@@ -0,0 +1,39 @@
+package org.dromara.common.translation.annotation;
+
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.dromara.common.translation.core.handler.TranslationHandler;
+
+import java.lang.annotation.*;
+
+/**
+ * 閫氱敤缈昏瘧娉ㄨВ
+ *
+ * @author Lion Li
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+@Documented
+@JacksonAnnotationsInside
+@JsonSerialize(using = TranslationHandler.class)
+public @interface Translation {
+
+    /**
+     * 绫诲瀷 (闇�涓庡疄鐜扮被涓婄殑 {@link TranslationType} 娉ㄨВtype瀵瑰簲)
+     * <p>
+     * 榛樿鍙栧綋鍓嶅瓧娈电殑鍊� 濡傛灉璁剧疆浜� @{@link Translation#mapper()} 鍒欏彇鏄犲皠瀛楁鐨勫��
+     */
+    String type();
+
+    /**
+     * 鏄犲皠瀛楁 (濡傛灉涓嶄负绌哄垯鍙栨瀛楁鐨勫��)
+     */
+    String mapper() default "";
+
+    /**
+     * 鍏朵粬鏉′欢 渚嬪: 瀛楀吀type(sys_user_sex)
+     */
+    String other() default "";
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/TranslationType.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/TranslationType.java
new file mode 100644
index 0000000..43bfab0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/TranslationType.java
@@ -0,0 +1,23 @@
+package org.dromara.common.translation.annotation;
+
+import org.dromara.common.translation.core.TranslationInterface;
+
+import java.lang.annotation.*;
+
+/**
+ * 缈昏瘧绫诲瀷娉ㄨВ (鏍囨敞鍒皗@link TranslationInterface} 鐨勫疄鐜扮被)
+ *
+ * @author Lion Li
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Documented
+public @interface TranslationType {
+
+    /**
+     * 绫诲瀷
+     */
+    String type();
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java
new file mode 100644
index 0000000..5dcd0c1
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java
@@ -0,0 +1,50 @@
+package org.dromara.common.translation.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.core.TranslationInterface;
+import org.dromara.common.translation.core.handler.TranslationBeanSerializerModifier;
+import org.dromara.common.translation.core.handler.TranslationHandler;
+import jakarta.annotation.PostConstruct;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 缈昏瘧妯″潡閰嶇疆绫�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@AutoConfiguration
+public class TranslationConfig {
+
+    @Autowired
+    private List<TranslationInterface<?>> list;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @PostConstruct
+    public void init() {
+        Map<String, TranslationInterface<?>> map = new HashMap<>(list.size());
+        for (TranslationInterface<?> trans : list) {
+            if (trans.getClass().isAnnotationPresent(TranslationType.class)) {
+                TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class);
+                map.put(annotation.type(), trans);
+            } else {
+                log.warn(trans.getClass().getName() + " 缈昏瘧瀹炵幇绫绘湭鏍囨敞 TranslationType 娉ㄨВ!");
+            }
+        }
+        TranslationHandler.TRANSLATION_MAPPER.putAll(map);
+        // 璁剧疆 Bean 搴忓垪鍖栦慨鏀瑰櫒
+        objectMapper.setSerializerFactory(
+            objectMapper.getSerializerFactory()
+                .withSerializerModifier(new TranslationBeanSerializerModifier()));
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
new file mode 100644
index 0000000..64b6804
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
@@ -0,0 +1,39 @@
+package org.dromara.common.translation.constant;
+
+/**
+ * 缈昏瘧甯搁噺
+ *
+ * @author Lion Li
+ */
+public interface TransConstant {
+
+    /**
+     * 鐢ㄦ埛id杞处鍙�
+     */
+    String USER_ID_TO_NAME = "user_id_to_name";
+
+    /**
+     * 鐢ㄦ埛id杞敤鎴峰悕绉�
+     */
+    String USER_ID_TO_NICKNAME = "user_id_to_nickname";
+
+    /**
+     * 閮ㄩ棬id杞悕绉�
+     */
+    String DEPT_ID_TO_NAME = "dept_id_to_name";
+
+    /**
+     * 瀛楀吀type杞琹abel
+     */
+    String DICT_TYPE_TO_LABEL = "dict_type_to_label";
+
+    /**
+     * ossId杞瑄rl
+     */
+    String OSS_ID_TO_URL = "oss_id_to_url";
+
+    /**
+     * 璁惧鍚嶇Оid杞悕绉�
+     */
+    String EQU_YPE_ID_TO_NAME = "equ_type_id_to_name";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/TranslationInterface.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/TranslationInterface.java
new file mode 100644
index 0000000..e4d6dd3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/TranslationInterface.java
@@ -0,0 +1,20 @@
+package org.dromara.common.translation.core;
+
+import org.dromara.common.translation.annotation.TranslationType;
+
+/**
+ * 缈昏瘧鎺ュ彛 (瀹炵幇绫婚渶鏍囨敞 {@link TranslationType} 娉ㄨВ鏍囨槑缈昏瘧绫诲瀷)
+ *
+ * @author Lion Li
+ */
+public interface TranslationInterface<T> {
+
+    /**
+     * 缈昏瘧
+     *
+     * @param key   闇�瑕佽缈昏瘧鐨勯敭(涓嶄负绌�)
+     * @param other 鍏朵粬鍙傛暟
+     * @return 杩斿洖閿搴旂殑鍊�
+     */
+    T translation(Object key, String other);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java
new file mode 100644
index 0000000..727672f
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java
@@ -0,0 +1,29 @@
+package org.dromara.common.translation.core.handler;
+
+import com.fasterxml.jackson.databind.BeanDescription;
+import com.fasterxml.jackson.databind.SerializationConfig;
+import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
+import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
+
+import java.util.List;
+
+/**
+ * Bean 搴忓垪鍖栦慨鏀瑰櫒 瑙e喅 Null 琚崟鐙鐞嗛棶棰�
+ *
+ * @author Lion Li
+ */
+public class TranslationBeanSerializerModifier extends BeanSerializerModifier {
+
+    @Override
+    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
+                                                     List<BeanPropertyWriter> beanProperties) {
+        for (BeanPropertyWriter writer : beanProperties) {
+            // 濡傛灉搴忓垪鍖栧櫒涓� TranslationHandler 鐨勮瘽 灏� Null 鍊间篃浜ょ粰浠栧鐞�
+            if (writer.getSerializer() instanceof TranslationHandler serializer) {
+                writer.assignNullSerializer(serializer);
+            }
+        }
+        return beanProperties;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
new file mode 100644
index 0000000..bb9615b
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java
@@ -0,0 +1,65 @@
+package org.dromara.common.translation.core.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.core.TranslationInterface;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 缈昏瘧澶勭悊鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class TranslationHandler extends JsonSerializer<Object> implements ContextualSerializer {
+
+    /**
+     * 鍏ㄥ眬缈昏瘧瀹炵幇绫绘槧灏勫櫒
+     */
+    public static final Map<String, TranslationInterface<?>> TRANSLATION_MAPPER = new ConcurrentHashMap<>();
+
+    private Translation translation;
+
+    @Override
+    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        TranslationInterface<?> trans = TRANSLATION_MAPPER.get(translation.type());
+        if (ObjectUtil.isNotNull(trans)) {
+            // 濡傛灉鏄犲皠瀛楁涓嶄负绌� 鍒欏彇鏄犲皠瀛楁鐨勫��
+            if (StringUtils.isNotBlank(translation.mapper())) {
+                value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper());
+            }
+            // 濡傛灉涓� null 鐩存帴鍐欏嚭
+            if (ObjectUtil.isNull(value)) {
+                gen.writeNull();
+                return;
+            }
+            Object result = trans.translation(value, translation.other());
+            gen.writeObject(result);
+        } else {
+            gen.writeObject(value);
+        }
+    }
+
+    @Override
+    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
+        Translation translation = property.getAnnotation(Translation.class);
+        if (Objects.nonNull(translation)) {
+            this.translation = translation;
+            return this;
+        }
+        return prov.findValueSerializer(property.getType(), property);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java
new file mode 100644
index 0000000..c391437
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java
@@ -0,0 +1,29 @@
+package org.dromara.common.translation.core.impl;
+
+import org.dromara.common.core.service.DeptService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+import lombok.AllArgsConstructor;
+
+/**
+ * 閮ㄩ棬缈昏瘧瀹炵幇
+ *
+ * @author Lion Li
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.DEPT_ID_TO_NAME)
+public class DeptNameTranslationImpl implements TranslationInterface<String> {
+
+    private final DeptService deptService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String ids) {
+            return deptService.selectDeptNameByIds(ids);
+        } else if (key instanceof Long id) {
+            return deptService.selectDeptNameByIds(id.toString());
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DictTypeTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DictTypeTranslationImpl.java
new file mode 100644
index 0000000..859a93e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DictTypeTranslationImpl.java
@@ -0,0 +1,28 @@
+package org.dromara.common.translation.core.impl;
+
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+import lombok.AllArgsConstructor;
+
+/**
+ * 瀛楀吀缈昏瘧瀹炵幇
+ *
+ * @author Lion Li
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.DICT_TYPE_TO_LABEL)
+public class DictTypeTranslationImpl implements TranslationInterface<String> {
+
+    private final DictService dictService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String dictValue && StringUtils.isNotBlank(other)) {
+            return dictService.getDictLabel(other, dictValue);
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java
new file mode 100644
index 0000000..e2fef3c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java
@@ -0,0 +1,30 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.DeptService;
+import org.dromara.common.core.service.EquTypeService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * 璁惧绫诲瀷缈昏瘧瀹炵幇
+ *
+ * @author zhuguifei
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.EQU_YPE_ID_TO_NAME)
+public class EquTypeNameTranslationImpl implements TranslationInterface<String> {
+
+    private final EquTypeService equTypeService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String ids) {
+            return equTypeService.selectEquTypeNameByIds(ids);
+        } else if (key instanceof Long id) {
+            return equTypeService.selectEquTypeNameByIds(id.toString());
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java
new file mode 100644
index 0000000..b92c7f0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java
@@ -0,0 +1,29 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * 鐢ㄦ埛鍚嶇О缈昏瘧瀹炵幇
+ *
+ * @author may
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.USER_ID_TO_NICKNAME)
+public class NicknameTranslationImpl implements TranslationInterface<String> {
+
+    private final UserService userService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof Long id) {
+            return userService.selectNicknameByIds(id.toString());
+        } else if (key instanceof String ids) {
+            return userService.selectNicknameByIds(ids);
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/OssUrlTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/OssUrlTranslationImpl.java
new file mode 100644
index 0000000..fc6f6df
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/OssUrlTranslationImpl.java
@@ -0,0 +1,29 @@
+package org.dromara.common.translation.core.impl;
+
+import org.dromara.common.core.service.OssService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+import lombok.AllArgsConstructor;
+
+/**
+ * OSS缈昏瘧瀹炵幇
+ *
+ * @author Lion Li
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.OSS_ID_TO_URL)
+public class OssUrlTranslationImpl implements TranslationInterface<String> {
+
+    private final OssService ossService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String ids) {
+            return ossService.selectUrlByIds(ids);
+        } else if (key instanceof Long id) {
+            return ossService.selectUrlByIds(id.toString());
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java
new file mode 100644
index 0000000..96f1cd3
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java
@@ -0,0 +1,27 @@
+package org.dromara.common.translation.core.impl;
+
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+import lombok.AllArgsConstructor;
+
+/**
+ * 鐢ㄦ埛鍚嶇炕璇戝疄鐜�
+ *
+ * @author Lion Li
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.USER_ID_TO_NAME)
+public class UserNameTranslationImpl implements TranslationInterface<String> {
+
+    private final UserService userService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof Long id) {
+            return userService.selectUserNameById(id);
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..d3037b9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,7 @@
+org.dromara.common.translation.config.TranslationConfig
+org.dromara.common.translation.core.impl.DeptNameTranslationImpl
+org.dromara.common.translation.core.impl.DictTypeTranslationImpl
+org.dromara.common.translation.core.impl.OssUrlTranslationImpl
+org.dromara.common.translation.core.impl.UserNameTranslationImpl
+org.dromara.common.translation.core.impl.NicknameTranslationImpl
+org.dromara.common.translation.core.impl.EquTypeNameTranslationImpl
diff --git a/eims/ruoyi-common/ruoyi-common-web/pom.xml b/eims/ruoyi-common/ruoyi-common-web/pom.xml
new file mode 100644
index 0000000..5e366bc
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-web</artifactId>
+
+    <description>
+        ruoyi-common-web web鏈嶅姟
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <!-- SpringBoot Web瀹瑰櫒 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- web 瀹瑰櫒浣跨敤 undertow 鎬ц兘鏇村己 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-websockets-jsr</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-captcha</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-crypto</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java
new file mode 100644
index 0000000..650517e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java
@@ -0,0 +1,65 @@
+package org.dromara.common.web.config;
+
+import cn.hutool.captcha.CaptchaUtil;
+import cn.hutool.captcha.CircleCaptcha;
+import cn.hutool.captcha.LineCaptcha;
+import cn.hutool.captcha.ShearCaptcha;
+import org.dromara.common.web.config.properties.CaptchaProperties;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Lazy;
+
+import java.awt.*;
+
+/**
+ * 楠岃瘉鐮侀厤缃�
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(CaptchaProperties.class)
+public class CaptchaConfig {
+
+    private static final int WIDTH = 160;
+    private static final int HEIGHT = 60;
+    private static final Color BACKGROUND = Color.LIGHT_GRAY;
+    private static final Font FONT = new Font("Arial", Font.BOLD, 48);
+
+    /**
+     * 鍦嗗湀骞叉壈楠岃瘉鐮�
+     */
+    @Lazy
+    @Bean
+    public CircleCaptcha circleCaptcha() {
+        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT);
+        captcha.setBackground(BACKGROUND);
+        captcha.setFont(FONT);
+        return captcha;
+    }
+
+    /**
+     * 绾挎骞叉壈鐨勯獙璇佺爜
+     */
+    @Lazy
+    @Bean
+    public LineCaptcha lineCaptcha() {
+        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT);
+        captcha.setBackground(BACKGROUND);
+        captcha.setFont(FONT);
+        return captcha;
+    }
+
+    /**
+     * 鎵洸骞叉壈楠岃瘉鐮�
+     */
+    @Lazy
+    @Bean
+    public ShearCaptcha shearCaptcha() {
+        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT);
+        captcha.setBackground(BACKGROUND);
+        captcha.setFont(FONT);
+        return captcha;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java
new file mode 100644
index 0000000..91fff76
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java
@@ -0,0 +1,53 @@
+package org.dromara.common.web.config;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.web.config.properties.XssProperties;
+import org.dromara.common.web.filter.RepeatableFilter;
+import org.dromara.common.web.filter.XssFilter;
+import jakarta.servlet.DispatcherType;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Filter閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(XssProperties.class)
+public class FilterConfig {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @Bean
+    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
+    public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new XssFilter());
+        registration.addUrlPatterns(StringUtils.split(xssProperties.getUrlPatterns(), StringUtils.SEPARATOR));
+        registration.setName("xssFilter");
+        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+        Map<String, String> initParameters = new HashMap<>();
+        initParameters.put("excludes", xssProperties.getExcludes());
+        registration.setInitParameters(initParameters);
+        return registration;
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @Bean
+    public FilterRegistrationBean someFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new RepeatableFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("repeatableFilter");
+        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+        return registration;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/I18nConfig.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/I18nConfig.java
new file mode 100644
index 0000000..4e212cb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/I18nConfig.java
@@ -0,0 +1,22 @@
+package org.dromara.common.web.config;
+
+import org.dromara.common.web.core.I18nLocaleResolver;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.LocaleResolver;
+
+/**
+ * 鍥介檯鍖栭厤缃�
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration(before = WebMvcAutoConfiguration.class)
+public class I18nConfig {
+
+    @Bean
+    public LocaleResolver localeResolver() {
+        return new I18nLocaleResolver();
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java
new file mode 100644
index 0000000..1371913
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java
@@ -0,0 +1,61 @@
+package org.dromara.common.web.config;
+
+import org.dromara.common.web.handler.GlobalExceptionHandler;
+import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 閫氱敤閰嶇疆
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+public class ResourcesConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 鍏ㄥ眬璁块棶鎬ц兘鎷︽埅
+        registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
+    }
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+    }
+
+    /**
+     * 璺ㄥ煙閰嶇疆
+     */
+    @Bean
+    public CorsFilter corsFilter() {
+        CorsConfiguration config = new CorsConfiguration();
+        config.setAllowCredentials(true);
+        // 璁剧疆璁块棶婧愬湴鍧�
+        config.addAllowedOriginPattern("*");
+        // 璁剧疆璁块棶婧愯姹傚ご
+        config.addAllowedHeader("*");
+        // 璁剧疆璁块棶婧愯姹傛柟娉�
+        config.addAllowedMethod("*");
+        // 鏈夋晥鏈� 1800绉�
+        config.setMaxAge(1800L);
+        // 娣诲姞鏄犲皠璺緞锛屾嫤鎴竴鍒囪姹�
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", config);
+        // 杩斿洖鏂扮殑CorsFilter
+        return new CorsFilter(source);
+    }
+
+    /**
+     * 鍏ㄥ眬寮傚父澶勭悊鍣�
+     */
+    @Bean
+    public GlobalExceptionHandler globalExceptionHandler() {
+        return new GlobalExceptionHandler();
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
new file mode 100644
index 0000000..ac50dd2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
@@ -0,0 +1,34 @@
+package org.dromara.common.web.config;
+
+import io.undertow.server.DefaultByteBufferPool;
+import io.undertow.websockets.jsr.WebSocketDeploymentInfo;
+import org.dromara.common.core.utils.SpringUtils;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.core.task.VirtualThreadTaskExecutor;
+
+/**
+ * Undertow 鑷畾涔夐厤缃�
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+public class UndertowConfig implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
+
+    @Override
+    public void customize(UndertowServletWebServerFactory factory) {
+        factory.addDeploymentInfoCustomizers(deploymentInfo -> {
+            WebSocketDeploymentInfo webSocketDeploymentInfo = new WebSocketDeploymentInfo();
+            webSocketDeploymentInfo.setBuffers(new DefaultByteBufferPool(true, 1024));
+            deploymentInfo.addServletContextAttribute("io.undertow.websockets.jsr.WebSocketDeploymentInfo", webSocketDeploymentInfo);
+            // 浣跨敤铏氭嫙绾跨▼
+            if (SpringUtils.isVirtual()) {
+                VirtualThreadTaskExecutor executor = new VirtualThreadTaskExecutor("undertow-");
+                deploymentInfo.setExecutor(executor);
+                deploymentInfo.setAsyncExecutor(executor);
+            }
+        });
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java
new file mode 100644
index 0000000..bfc52f4
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java
@@ -0,0 +1,38 @@
+package org.dromara.common.web.config.properties;
+
+import org.dromara.common.web.enums.CaptchaCategory;
+import org.dromara.common.web.enums.CaptchaType;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 楠岃瘉鐮� 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "captcha")
+public class CaptchaProperties {
+
+    private Boolean enable;
+
+    /**
+     * 楠岃瘉鐮佺被鍨�
+     */
+    private CaptchaType type;
+
+    /**
+     * 楠岃瘉鐮佺被鍒�
+     */
+    private CaptchaCategory category;
+
+    /**
+     * 鏁板瓧楠岃瘉鐮佷綅鏁�
+     */
+    private Integer numberLength;
+
+    /**
+     * 瀛楃楠岃瘉鐮侀暱搴�
+     */
+    private Integer charLength;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java
new file mode 100644
index 0000000..ecf4f33
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java
@@ -0,0 +1,30 @@
+package org.dromara.common.web.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * xss杩囨护 閰嶇疆灞炴��
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "xss")
+public class XssProperties {
+
+    /**
+     * 杩囨护寮�鍏�
+     */
+    private String enabled;
+
+    /**
+     * 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+     */
+    private String excludes;
+
+    /**
+     * 鍖归厤閾炬帴
+     */
+    private String urlPatterns;
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/BaseController.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/BaseController.java
new file mode 100644
index 0000000..fd01dda
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/BaseController.java
@@ -0,0 +1,40 @@
+package org.dromara.common.web.core;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+
+/**
+ * web灞傞�氱敤鏁版嵁澶勭悊
+ *
+ * @author Lion Li
+ */
+public class BaseController {
+
+    /**
+     * 鍝嶅簲杩斿洖缁撴灉
+     *
+     * @param rows 褰卞搷琛屾暟
+     * @return 鎿嶄綔缁撴灉
+     */
+    protected R<Void> toAjax(int rows) {
+        return rows > 0 ? R.ok() : R.fail();
+    }
+
+    /**
+     * 鍝嶅簲杩斿洖缁撴灉
+     *
+     * @param result 缁撴灉
+     * @return 鎿嶄綔缁撴灉
+     */
+    protected R<Void> toAjax(boolean result) {
+        return result ? R.ok() : R.fail();
+    }
+
+    /**
+     * 椤甸潰璺宠浆
+     */
+    public String redirect(String url) {
+        return StringUtils.format("redirect:{}", url);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/I18nLocaleResolver.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/I18nLocaleResolver.java
new file mode 100644
index 0000000..98ddd06
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/I18nLocaleResolver.java
@@ -0,0 +1,31 @@
+package org.dromara.common.web.core;
+
+import org.springframework.web.servlet.LocaleResolver;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.Locale;
+
+/**
+ * 鑾峰彇璇锋眰澶村浗闄呭寲淇℃伅
+ *
+ * @author Lion Li
+ */
+public class I18nLocaleResolver implements LocaleResolver {
+
+    @Override
+    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
+        String language = httpServletRequest.getHeader("content-language");
+        Locale locale = Locale.getDefault();
+        if (language != null && language.length() > 0) {
+            String[] split = language.split("_");
+            locale = new Locale(split[0], split[1]);
+        }
+        return locale;
+    }
+
+    @Override
+    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java
new file mode 100644
index 0000000..ecf2658
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java
@@ -0,0 +1,35 @@
+package org.dromara.common.web.enums;
+
+import cn.hutool.captcha.AbstractCaptcha;
+import cn.hutool.captcha.CircleCaptcha;
+import cn.hutool.captcha.LineCaptcha;
+import cn.hutool.captcha.ShearCaptcha;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 楠岃瘉鐮佺被鍒�
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum CaptchaCategory {
+
+    /**
+     * 绾挎骞叉壈
+     */
+    LINE(LineCaptcha.class),
+
+    /**
+     * 鍦嗗湀骞叉壈
+     */
+    CIRCLE(CircleCaptcha.class),
+
+    /**
+     * 鎵洸骞叉壈
+     */
+    SHEAR(ShearCaptcha.class);
+
+    private final Class<? extends AbstractCaptcha> clazz;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaType.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaType.java
new file mode 100644
index 0000000..d0b7334
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaType.java
@@ -0,0 +1,29 @@
+package org.dromara.common.web.enums;
+
+import cn.hutool.captcha.generator.CodeGenerator;
+import cn.hutool.captcha.generator.RandomGenerator;
+import org.dromara.common.web.utils.UnsignedMathGenerator;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 楠岃瘉鐮佺被鍨�
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum CaptchaType {
+
+    /**
+     * 鏁板瓧
+     */
+    MATH(UnsignedMathGenerator.class),
+
+    /**
+     * 瀛楃
+     */
+    CHAR(RandomGenerator.class);
+
+    private final Class<? extends CodeGenerator> clazz;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatableFilter.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatableFilter.java
new file mode 100644
index 0000000..e0a3bf2
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatableFilter.java
@@ -0,0 +1,40 @@
+package org.dromara.common.web.filter;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.http.MediaType;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * Repeatable 杩囨护鍣�
+ *
+ * @author ruoyi
+ */
+public class RepeatableFilter implements Filter {
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+        ServletRequest requestWrapper = null;
+        if (request instanceof HttpServletRequest
+            && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
+            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
+        }
+        if (null == requestWrapper) {
+            chain.doFilter(request, response);
+        } else {
+            chain.doFilter(requestWrapper, response);
+        }
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatedlyRequestWrapper.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatedlyRequestWrapper.java
new file mode 100644
index 0000000..8933225
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatedlyRequestWrapper.java
@@ -0,0 +1,68 @@
+package org.dromara.common.web.filter;
+
+import cn.hutool.core.io.IoUtil;
+import org.dromara.common.core.constant.Constants;
+
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * 鏋勫缓鍙噸澶嶈鍙杋nputStream鐨剅equest
+ *
+ * @author ruoyi
+ */
+public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
+    private final byte[] body;
+
+    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
+        super(request);
+        request.setCharacterEncoding(Constants.UTF8);
+        response.setCharacterEncoding(Constants.UTF8);
+
+        body = IoUtil.readBytes(request.getInputStream(), false);
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException {
+        return new BufferedReader(new InputStreamReader(getInputStream()));
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+        return new ServletInputStream() {
+            @Override
+            public int read() throws IOException {
+                return bais.read();
+            }
+
+            @Override
+            public int available() throws IOException {
+                return body.length;
+            }
+
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+
+            }
+        };
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java
new file mode 100644
index 0000000..a6cbe8c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java
@@ -0,0 +1,62 @@
+package org.dromara.common.web.filter;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.http.HttpMethod;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 闃叉XSS鏀诲嚮鐨勮繃婊ゅ櫒
+ *
+ * @author ruoyi
+ */
+public class XssFilter implements Filter {
+    /**
+     * 鎺掗櫎閾炬帴
+     */
+    public List<String> excludes = new ArrayList<>();
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        String tempExcludes = filterConfig.getInitParameter("excludes");
+        if (StringUtils.isNotEmpty(tempExcludes)) {
+            String[] url = tempExcludes.split(StringUtils.SEPARATOR);
+            for (int i = 0; url != null && i < url.length; i++) {
+                excludes.add(url[i]);
+            }
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+        HttpServletRequest req = (HttpServletRequest) request;
+        HttpServletResponse resp = (HttpServletResponse) response;
+        if (handleExcludeURL(req, resp)) {
+            chain.doFilter(request, response);
+            return;
+        }
+        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
+        chain.doFilter(xssRequest, response);
+    }
+
+    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
+        String url = request.getServletPath();
+        String method = request.getMethod();
+        // GET DELETE 涓嶈繃婊�
+        if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) {
+            return true;
+        }
+        return StringUtils.matches(url, excludes);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java
new file mode 100644
index 0000000..4a425c5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java
@@ -0,0 +1,97 @@
+package org.dromara.common.web.filter;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HtmlUtil;
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * XSS杩囨护澶勭悊
+ *
+ * @author ruoyi
+ */
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
+    /**
+     * @param request
+     */
+    public XssHttpServletRequestWrapper(HttpServletRequest request) {
+        super(request);
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        String[] values = super.getParameterValues(name);
+        if (values != null) {
+            int length = values.length;
+            String[] escapseValues = new String[length];
+            for (int i = 0; i < length; i++) {
+                // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
+                escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
+            }
+            return escapseValues;
+        }
+        return super.getParameterValues(name);
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        // 闈瀓son绫诲瀷锛岀洿鎺ヨ繑鍥�
+        if (!isJsonRequest()) {
+            return super.getInputStream();
+        }
+
+        // 涓虹┖锛岀洿鎺ヨ繑鍥�
+        String json = StrUtil.str(IoUtil.readBytes(super.getInputStream(), false), StandardCharsets.UTF_8);
+        if (StringUtils.isEmpty(json)) {
+            return super.getInputStream();
+        }
+
+        // xss杩囨护
+        json = HtmlUtil.cleanHtmlTag(json).trim();
+        byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
+        final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes);
+        return new ServletInputStream() {
+            @Override
+            public boolean isFinished() {
+                return true;
+            }
+
+            @Override
+            public boolean isReady() {
+                return true;
+            }
+
+            @Override
+            public int available() throws IOException {
+                return jsonBytes.length;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+            }
+
+            @Override
+            public int read() throws IOException {
+                return bis.read();
+            }
+        };
+    }
+
+    /**
+     * 鏄惁鏄疛son璇锋眰
+     */
+    public boolean isJsonRequest() {
+        String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
+        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..061d3aa
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
@@ -0,0 +1,159 @@
+package org.dromara.common.web.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpStatus;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.base.BaseException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import java.io.IOException;
+
+/**
+ * 鍏ㄥ眬寮傚父澶勭悊鍣�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 璇锋眰鏂瑰紡涓嶆敮鎸�
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public R<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+                                                                HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',涓嶆敮鎸�'{}'璇锋眰", requestURI, e.getMethod());
+        return R.fail(HttpStatus.HTTP_BAD_METHOD, e.getMessage());
+    }
+
+    /**
+     * 涓氬姟寮傚父
+     */
+    @ExceptionHandler(ServiceException.class)
+    public R<Void> handleServiceException(ServiceException e, HttpServletRequest request) {
+        log.error(e.getMessage());
+        Integer code = e.getCode();
+        return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
+    }
+
+    /**
+     * 涓氬姟寮傚父
+     */
+    @ExceptionHandler(BaseException.class)
+    public R<Void> handleBaseException(BaseException e, HttpServletRequest request) {
+        log.error(e.getMessage());
+        return R.fail(e.getMessage());
+    }
+
+    /**
+     * 璇锋眰璺緞涓己灏戝繀闇�鐨勮矾寰勫彉閲�
+     */
+    @ExceptionHandler(MissingPathVariableException.class)
+    public R<Void> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰璺緞涓己灏戝繀闇�鐨勮矾寰勫彉閲�'{}',鍙戠敓绯荤粺寮傚父.", requestURI);
+        return R.fail(String.format("璇锋眰璺緞涓己灏戝繀闇�鐨勮矾寰勫彉閲廩%s]", e.getVariableName()));
+    }
+
+    /**
+     * 璇锋眰鍙傛暟绫诲瀷涓嶅尮閰�
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public R<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍙傛暟绫诲瀷涓嶅尮閰�'{}',鍙戠敓绯荤粺寮傚父.", requestURI);
+        return R.fail(String.format("璇锋眰鍙傛暟绫诲瀷涓嶅尮閰嶏紝鍙傛暟[%s]瑕佹眰绫诲瀷涓猴細'%s'锛屼絾杈撳叆鍊间负锛�'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
+    }
+
+    /**
+     * 鎵句笉鍒拌矾鐢�
+     */
+    @ExceptionHandler(NoHandlerFoundException.class)
+    public R<Void> handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}'涓嶅瓨鍦�.", requestURI);
+        return R.fail(HttpStatus.HTTP_NOT_FOUND, e.getMessage());
+    }
+
+    /**
+     * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
+     */
+    @ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(IOException.class)
+    public void handleRuntimeException(IOException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        if (requestURI.contains("sse")) {
+            // sse 缁忓父鎬ц繛鎺ヤ腑鏂� 渚嬪鍏抽棴娴忚鍣� 鐩存帴灞忚斀
+            return;
+        }
+        log.error("璇锋眰鍦板潃'{}',杩炴帴涓柇", requestURI, e);
+    }
+
+    /**
+     * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓鏈煡寮傚父.", requestURI, e);
+        return R.fail(e.getMessage());
+    }
+
+    /**
+     * 绯荤粺寮傚父
+     */
+    @ExceptionHandler(Exception.class)
+    public R<Void> handleException(Exception e, HttpServletRequest request) {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓绯荤粺寮傚父.", requestURI, e);
+        return R.fail(e.getMessage());
+    }
+
+    /**
+     * 鑷畾涔夐獙璇佸紓甯�
+     */
+    @ExceptionHandler(BindException.class)
+    public R<Void> handleBindException(BindException e) {
+        log.error(e.getMessage());
+        String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
+        return R.fail(message);
+    }
+
+    /**
+     * 鑷畾涔夐獙璇佸紓甯�
+     */
+    @ExceptionHandler(ConstraintViolationException.class)
+    public R<Void> constraintViolationException(ConstraintViolationException e) {
+        log.error(e.getMessage());
+        String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
+        return R.fail(message);
+    }
+
+    /**
+     * 鑷畾涔夐獙璇佸紓甯�
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
+        log.error(e.getMessage());
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return R.fail(message);
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
new file mode 100644
index 0000000..614a559
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java
@@ -0,0 +1,86 @@
+package org.dromara.common.web.interceptor;
+
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.map.MapUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.StopWatch;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.web.filter.RepeatedlyRequestWrapper;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.io.BufferedReader;
+import java.util.Map;
+
+/**
+ * web鐨勮皟鐢ㄦ椂闂寸粺璁℃嫤鎴櫒
+ *
+ * @author Lion Li
+ * @since 3.3.0
+ */
+@Slf4j
+public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
+
+    private final static ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String url = request.getMethod() + " " + request.getRequestURI();
+
+        // 鎵撳嵃璇锋眰鍙傛暟
+        if (isJsonRequest(request)) {
+            String jsonParam = "";
+            if (request instanceof RepeatedlyRequestWrapper) {
+                BufferedReader reader = request.getReader();
+                jsonParam = IoUtil.read(reader);
+            }
+            log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[json],鍙傛暟:[{}]", url, jsonParam);
+        } else {
+            Map<String, String[]> parameterMap = request.getParameterMap();
+            if (MapUtil.isNotEmpty(parameterMap)) {
+                String parameters = JsonUtils.toJsonString(parameterMap);
+                log.info("[PLUS]寮�濮嬭姹� => URL[{}],鍙傛暟绫诲瀷[param],鍙傛暟:[{}]", url, parameters);
+            } else {
+                log.info("[PLUS]寮�濮嬭姹� => URL[{}],鏃犲弬鏁�", url);
+            }
+        }
+
+        StopWatch stopWatch = new StopWatch();
+        KEY_CACHE.set(stopWatch);
+        stopWatch.start();
+
+        return true;
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        StopWatch stopWatch = KEY_CACHE.get();
+        stopWatch.stop();
+        log.info("[PLUS]缁撴潫璇锋眰 => URL[{}],鑰楁椂:[{}]姣", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
+        KEY_CACHE.remove();
+    }
+
+    /**
+     * 鍒ゆ柇鏈璇锋眰鐨勬暟鎹被鍨嬫槸鍚︿负json
+     *
+     * @param request request
+     * @return boolean
+     */
+    private boolean isJsonRequest(HttpServletRequest request) {
+        String contentType = request.getContentType();
+        if (contentType != null) {
+            return StringUtils.startsWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE);
+        }
+        return false;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/utils/UnsignedMathGenerator.java b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/utils/UnsignedMathGenerator.java
new file mode 100644
index 0000000..a400cff
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/utils/UnsignedMathGenerator.java
@@ -0,0 +1,88 @@
+package org.dromara.common.web.utils;
+
+import cn.hutool.captcha.generator.CodeGenerator;
+import cn.hutool.core.math.Calculator;
+import cn.hutool.core.util.CharUtil;
+import cn.hutool.core.util.RandomUtil;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.io.Serial;
+
+/**
+ * 鏃犵鍙疯绠楃敓鎴愬櫒
+ *
+ * @author Lion Li
+ */
+public class UnsignedMathGenerator implements CodeGenerator {
+
+    @Serial
+    private static final long serialVersionUID = -5514819971774091076L;
+
+    private static final String OPERATORS = "+-*";
+
+    /**
+     * 鍙備笌璁$畻鏁板瓧鏈�澶ч暱搴�
+     */
+    private final int numberLength;
+
+    /**
+     * 鏋勯��
+     */
+    public UnsignedMathGenerator() {
+        this(2);
+    }
+
+    /**
+     * 鏋勯��
+     *
+     * @param numberLength 鍙備笌璁$畻鏈�澶ф暟瀛椾綅鏁�
+     */
+    public UnsignedMathGenerator(int numberLength) {
+        this.numberLength = numberLength;
+    }
+
+    @Override
+    public String generate() {
+        final int limit = getLimit();
+        int a = RandomUtil.randomInt(limit);
+        int b = RandomUtil.randomInt(limit);
+        String max = Integer.toString(Math.max(a,b));
+        String min = Integer.toString(Math.min(a,b));
+        max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE);
+        min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE);
+
+        return max + RandomUtil.randomChar(OPERATORS) + min + '=';
+    }
+
+    @Override
+    public boolean verify(String code, String userInputCode) {
+        int result;
+        try {
+            result = Integer.parseInt(userInputCode);
+        } catch (NumberFormatException e) {
+            // 鐢ㄦ埛杈撳叆闈炴暟瀛�
+            return false;
+        }
+
+        final int calculateResult = (int) Calculator.conversion(code);
+        return result == calculateResult;
+    }
+
+    /**
+     * 鑾峰彇楠岃瘉鐮侀暱搴�
+     *
+     * @return 楠岃瘉鐮侀暱搴�
+     */
+    public int getLength() {
+        return this.numberLength * 2 + 2;
+    }
+
+    /**
+     * 鏍规嵁闀垮害鑾峰彇鍙備笌璁$畻鏁板瓧鏈�澶у��
+     *
+     * @return 鏈�澶у��
+     */
+    private int getLimit() {
+        return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength));
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..fc10a36
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,5 @@
+org.dromara.common.web.config.CaptchaConfig
+org.dromara.common.web.config.FilterConfig
+org.dromara.common.web.config.I18nConfig
+org.dromara.common.web.config.ResourcesConfig
+org.dromara.common.web.config.UndertowConfig
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/pom.xml b/eims/ruoyi-common/ruoyi-common-websocket/pom.xml
new file mode 100644
index 0000000..db86dcb
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-common</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-common-websocket</artifactId>
+
+    <description>
+        ruoyi-common-websocket 妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-satoken</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java
new file mode 100644
index 0000000..ef5cfc9
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java
@@ -0,0 +1,63 @@
+package org.dromara.common.websocket.config;
+
+import cn.hutool.core.util.StrUtil;
+import org.dromara.common.websocket.config.properties.WebSocketProperties;
+import org.dromara.common.websocket.handler.PlusWebSocketHandler;
+import org.dromara.common.websocket.interceptor.PlusWebSocketInterceptor;
+import org.dromara.common.websocket.listener.WebSocketTopicListener;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.server.HandshakeInterceptor;
+
+/**
+ * WebSocket 閰嶇疆
+ *
+ * @author zendwang
+ */
+@AutoConfiguration
+@ConditionalOnProperty(value = "websocket.enabled", havingValue = "true")
+@EnableConfigurationProperties(WebSocketProperties.class)
+@EnableWebSocket
+public class WebSocketConfig {
+
+    @Bean
+    public WebSocketConfigurer webSocketConfigurer(HandshakeInterceptor handshakeInterceptor,
+                                                   WebSocketHandler webSocketHandler, WebSocketProperties webSocketProperties) {
+        // 濡傛灉WebSocket鐨勮矾寰勪负绌猴紝鍒欒缃粯璁よ矾寰勪负 "/websocket"
+        if (StrUtil.isBlank(webSocketProperties.getPath())) {
+            webSocketProperties.setPath("/websocket");
+        }
+
+        // 濡傛灉鍏佽璺ㄥ煙璁块棶鐨勫湴鍧�涓虹┖锛屽垯璁剧疆涓� "*"锛岃〃绀哄厑璁告墍鏈夋潵婧愮殑璺ㄥ煙璇锋眰
+        if (StrUtil.isBlank(webSocketProperties.getAllowedOrigins())) {
+            webSocketProperties.setAllowedOrigins("*");
+        }
+
+        // 杩斿洖涓�涓猈ebSocketConfigurer瀵硅薄锛岀敤浜庨厤缃甒ebSocket
+        return registry -> registry
+            // 娣诲姞WebSocket澶勭悊绋嬪簭鍜屾嫤鎴櫒鍒版寚瀹氳矾寰勶紝璁剧疆鍏佽鐨勮法鍩熸潵婧�
+            .addHandler(webSocketHandler, webSocketProperties.getPath())
+            .addInterceptors(handshakeInterceptor)
+            .setAllowedOrigins(webSocketProperties.getAllowedOrigins());
+    }
+
+    @Bean
+    public HandshakeInterceptor handshakeInterceptor() {
+        return new PlusWebSocketInterceptor();
+    }
+
+    @Bean
+    public WebSocketHandler webSocketHandler() {
+        return new PlusWebSocketHandler();
+    }
+
+    @Bean
+    public WebSocketTopicListener topicListener() {
+        return new WebSocketTopicListener();
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/properties/WebSocketProperties.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/properties/WebSocketProperties.java
new file mode 100644
index 0000000..d629fe5
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/properties/WebSocketProperties.java
@@ -0,0 +1,26 @@
+package org.dromara.common.websocket.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * WebSocket 閰嶇疆椤�
+ *
+ * @author zendwang
+ */
+@ConfigurationProperties("websocket")
+@Data
+public class WebSocketProperties {
+
+    private Boolean enabled;
+
+    /**
+     * 璺緞
+     */
+    private String path;
+
+    /**
+     *  璁剧疆璁块棶婧愬湴鍧�
+     */
+    private String allowedOrigins;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java
new file mode 100644
index 0000000..e243279
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java
@@ -0,0 +1,29 @@
+package org.dromara.common.websocket.constant;
+
+/**
+ * websocket鐨勫父閲忛厤缃�
+ *
+ * @author zendwang
+ */
+public interface WebSocketConstants {
+
+    /**
+     * websocketSession涓殑鍙傛暟鐨刱ey
+     */
+    String LOGIN_USER_KEY = "loginUser";
+
+    /**
+     * 璁㈤槄鐨勯閬�
+     */
+    String WEB_SOCKET_TOPIC = "global:websocket";
+
+    /**
+     * 鍓嶇蹇冭烦妫�鏌ョ殑鍛戒护
+     */
+    String PING = "ping";
+
+    /**
+     * 鏈嶅姟绔績璺虫仮澶嶇殑瀛楃涓�
+     */
+    String PONG = "pong";
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/dto/WebSocketMessageDto.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/dto/WebSocketMessageDto.java
new file mode 100644
index 0000000..e2d4456
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/dto/WebSocketMessageDto.java
@@ -0,0 +1,29 @@
+package org.dromara.common.websocket.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 娑堟伅鐨刣to
+ *
+ * @author zendwang
+ */
+@Data
+public class WebSocketMessageDto implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 闇�瑕佹帹閫佸埌鐨剆ession key 鍒楄〃
+     */
+    private List<Long> sessionKeys;
+
+    /**
+     * 闇�瑕佸彂閫佺殑娑堟伅
+     */
+    private String message;
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java
new file mode 100644
index 0000000..8b1cc5d
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java
@@ -0,0 +1,122 @@
+package org.dromara.common.websocket.handler;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.websocket.dto.WebSocketMessageDto;
+import org.dromara.common.websocket.holder.WebSocketSessionHolder;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import org.springframework.web.socket.*;
+import org.springframework.web.socket.handler.AbstractWebSocketHandler;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
+
+/**
+ * WebSocketHandler 瀹炵幇绫�
+ *
+ * @author zendwang
+ */
+@Slf4j
+public class PlusWebSocketHandler extends AbstractWebSocketHandler {
+
+    /**
+     * 杩炴帴鎴愬姛鍚�
+     */
+    @Override
+    public void afterConnectionEstablished(WebSocketSession session) throws IOException {
+        LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
+        if (ObjectUtil.isNull(loginUser)) {
+            session.close(CloseStatus.BAD_DATA);
+            log.info("[connect] invalid token received. sessionId: {}", session.getId());
+            return;
+        }
+        WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
+        log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
+    }
+
+    /**
+     * 澶勭悊鎺ユ敹鍒扮殑鏂囨湰娑堟伅
+     *
+     * @param session WebSocket浼氳瘽
+     * @param message 鎺ユ敹鍒扮殑鏂囨湰娑堟伅
+     * @throws Exception 澶勭悊娑堟伅杩囩▼涓彲鑳芥姏鍑虹殑寮傚父
+     */
+    @Override
+    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+        // 浠嶹ebSocket浼氳瘽涓幏鍙栫櫥褰曠敤鎴蜂俊鎭�
+        LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
+
+        // 鍒涘缓WebSocket娑堟伅DTO瀵硅薄
+        WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto();
+        webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId()));
+        webSocketMessageDto.setMessage(message.getPayload());
+        WebSocketUtils.publishMessage(webSocketMessageDto);
+    }
+
+    /**
+     * 澶勭悊鎺ユ敹鍒扮殑浜岃繘鍒舵秷鎭�
+     *
+     * @param session WebSocket浼氳瘽
+     * @param message 鎺ユ敹鍒扮殑浜岃繘鍒舵秷鎭�
+     * @throws Exception 澶勭悊娑堟伅杩囩▼涓彲鑳芥姏鍑虹殑寮傚父
+     */
+    @Override
+    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
+        super.handleBinaryMessage(session, message);
+    }
+
+    /**
+     * 澶勭悊鎺ユ敹鍒扮殑Pong娑堟伅锛堝績璺崇洃娴嬶級
+     *
+     * @param session WebSocket浼氳瘽
+     * @param message 鎺ユ敹鍒扮殑Pong娑堟伅
+     * @throws Exception 澶勭悊娑堟伅杩囩▼涓彲鑳芥姏鍑虹殑寮傚父
+     */
+    @Override
+    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
+        WebSocketUtils.sendPongMessage(session);
+    }
+
+    /**
+     * 澶勭悊WebSocket浼犺緭閿欒
+     *
+     * @param session   WebSocket浼氳瘽
+     * @param exception 鍙戠敓鐨勫紓甯�
+     * @throws Exception 澶勭悊杩囩▼涓彲鑳芥姏鍑虹殑寮傚父
+     */
+    @Override
+    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+        log.error("[transport error] sessionId: {} , exception:{}", session.getId(), exception.getMessage());
+    }
+
+    /**
+     * 鍦╓ebSocket杩炴帴鍏抽棴鍚庢墽琛屾竻鐞嗘搷浣�
+     *
+     * @param session WebSocket浼氳瘽
+     * @param status  鍏抽棴鐘舵�佷俊鎭�
+     */
+    @Override
+    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
+        LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY);
+        if (ObjectUtil.isNull(loginUser)) {
+            log.info("[disconnect] invalid token received. sessionId: {}", session.getId());
+            return;
+        }
+        WebSocketSessionHolder.removeSession(loginUser.getUserId());
+        log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
+    }
+
+    /**
+     * 鎸囩ず澶勭悊绋嬪簭鏄惁鏀寔鎺ユ敹閮ㄥ垎娑堟伅
+     *
+     * @return 濡傛灉鏀寔鎺ユ敹閮ㄥ垎娑堟伅锛屽垯杩斿洖true锛涘惁鍒欒繑鍥瀎alse
+     */
+    @Override
+    public boolean supportsPartialMessages() {
+        return false;
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
new file mode 100644
index 0000000..368801c
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java
@@ -0,0 +1,70 @@
+package org.dromara.common.websocket.holder;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * WebSocketSession 鐢ㄤ簬淇濆瓨褰撳墠鎵�鏈夊湪绾跨殑浼氳瘽淇℃伅
+ *
+ * @author zendwang
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class WebSocketSessionHolder {
+
+    private static final Map<Long, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();
+
+    /**
+     * 灏哤ebSocket浼氳瘽娣诲姞鍒扮敤鎴蜂細璇滿ap涓�
+     *
+     * @param sessionKey 浼氳瘽閿紝鐢ㄤ簬妫�绱細璇�
+     * @param session    瑕佹坊鍔犵殑WebSocket浼氳瘽
+     */
+    public static void addSession(Long sessionKey, WebSocketSession session) {
+        USER_SESSION_MAP.put(sessionKey, session);
+    }
+
+    /**
+     * 浠庣敤鎴蜂細璇滿ap涓Щ闄ゆ寚瀹氫細璇濋敭瀵瑰簲鐨刉ebSocket浼氳瘽
+     *
+     * @param sessionKey 瑕佺Щ闄ょ殑浼氳瘽閿�
+     */
+    public static void removeSession(Long sessionKey) {
+        if (USER_SESSION_MAP.containsKey(sessionKey)) {
+            USER_SESSION_MAP.remove(sessionKey);
+        }
+    }
+
+    /**
+     * 鏍规嵁浼氳瘽閿粠鐢ㄦ埛浼氳瘽Map涓幏鍙朩ebSocket浼氳瘽
+     *
+     * @param sessionKey 瑕佽幏鍙栫殑浼氳瘽閿�
+     * @return 涓庣粰瀹氫細璇濋敭瀵瑰簲鐨刉ebSocket浼氳瘽锛屽鏋滀笉瀛樺湪鍒欒繑鍥瀗ull
+     */
+    public static WebSocketSession getSessions(Long sessionKey) {
+        return USER_SESSION_MAP.get(sessionKey);
+    }
+
+    /**
+     * 鑾峰彇瀛樺偍鍦ㄧ敤鎴蜂細璇滿ap涓墍鏈塛ebSocket浼氳瘽鐨勪細璇濋敭闆嗗悎
+     *
+     * @return 鎵�鏈塛ebSocket浼氳瘽鐨勪細璇濋敭闆嗗悎
+     */
+    public static Set<Long> getSessionsAll() {
+        return USER_SESSION_MAP.keySet();
+    }
+
+    /**
+     * 妫�鏌ョ粰瀹氱殑浼氳瘽閿槸鍚﹀瓨鍦ㄤ簬鐢ㄦ埛浼氳瘽Map涓�
+     *
+     * @param sessionKey 瑕佹鏌ョ殑浼氳瘽閿�
+     * @return 濡傛灉瀛樺湪瀵瑰簲鐨勪細璇濋敭锛屽垯杩斿洖true锛涘惁鍒欒繑鍥瀎alse
+     */
+    public static Boolean existSession(Long sessionKey) {
+        return USER_SESSION_MAP.containsKey(sessionKey);
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java
new file mode 100644
index 0000000..c70e377
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java
@@ -0,0 +1,75 @@
+package org.dromara.common.websocket.interceptor;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.HandshakeInterceptor;
+
+import java.util.Map;
+
+import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY;
+
+/**
+ * WebSocket鎻℃墜璇锋眰鐨勬嫤鎴櫒
+ *
+ * @author zendwang
+ */
+@Slf4j
+public class PlusWebSocketInterceptor implements HandshakeInterceptor {
+
+    /**
+     * WebSocket鎻℃墜涔嬪墠鎵ц鐨勫墠缃鐞嗘柟娉�
+     *
+     * @param request    WebSocket鎻℃墜璇锋眰
+     * @param response   WebSocket鎻℃墜鍝嶅簲
+     * @param wsHandler  WebSocket澶勭悊绋嬪簭
+     * @param attributes 涓嶹ebSocket浼氳瘽鍏宠仈鐨勫睘鎬�
+     * @return 濡傛灉鍏佽鎻℃墜缁х画杩涜锛屽垯杩斿洖true锛涘惁鍒欒繑鍥瀎alse
+     */
+    @Override
+    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
+        try {
+            // 妫�鏌ユ槸鍚︾櫥褰� 鏄惁鏈塼oken
+            LoginUser loginUser = LoginHelper.getLoginUser();
+
+            // 瑙e喅 ws 涓嶈蛋 mvc 鎷︽埅鍣ㄩ棶棰�(cloud 鐗堟湰涓嶅彈褰卞搷)
+            // 妫�鏌� header 涓� param 閲岀殑 clientid 涓� token 閲岀殑鏄惁涓�鑷�
+            String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
+            String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY);
+            String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
+            if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
+                // token 鏃犳晥
+                throw NotLoginException.newInstance(StpUtil.getLoginType(),
+                    "-100", "瀹㈡埛绔疘D涓嶵oken涓嶅尮閰�",
+                    StpUtil.getTokenValue());
+            }
+
+            attributes.put(LOGIN_USER_KEY, loginUser);
+            return true;
+        } catch (NotLoginException e) {
+            log.error("WebSocket 璁よ瘉澶辫触'{}',鏃犳硶璁块棶绯荤粺璧勬簮", e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * WebSocket鎻℃墜鎴愬姛鍚庢墽琛岀殑鍚庣疆澶勭悊鏂规硶
+     *
+     * @param request   WebSocket鎻℃墜璇锋眰
+     * @param response  WebSocket鎻℃墜鍝嶅簲
+     * @param wsHandler WebSocket澶勭悊绋嬪簭
+     * @param exception 鎻℃墜杩囩▼涓彲鑳藉嚭鐜扮殑寮傚父
+     */
+    @Override
+    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
+        // 鍦ㄨ繖涓柟娉曚腑鍙互鎵ц涓�浜涙彙鎵嬫垚鍔熷悗鐨勫悗缁鐞嗛�昏緫锛屾瘮濡傝褰曟棩蹇楁垨鑰呭叾浠栨搷浣�
+    }
+
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java
new file mode 100644
index 0000000..0ad39af
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java
@@ -0,0 +1,50 @@
+package org.dromara.common.websocket.listener;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.websocket.holder.WebSocketSessionHolder;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.Ordered;
+
+/**
+ * WebSocket 涓婚璁㈤槄鐩戝惉鍣�
+ *
+ * @author zendwang
+ */
+@Slf4j
+public class WebSocketTopicListener implements ApplicationRunner, Ordered {
+
+    /**
+     * 鍦⊿pring Boot搴旂敤绋嬪簭鍚姩鏃跺垵濮嬪寲WebSocket涓婚璁㈤槄鐩戝惉鍣�
+     *
+     * @param args 搴旂敤绋嬪簭鍙傛暟
+     * @throws Exception 鍒濆鍖栬繃绋嬩腑鍙兘鎶涘嚭鐨勫紓甯�
+     */
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        // 璁㈤槄WebSocket娑堟伅
+        WebSocketUtils.subscribeMessage((message) -> {
+            log.info("WebSocket涓婚璁㈤槄鏀跺埌娑堟伅session keys={} message={}", message.getSessionKeys(), message.getMessage());
+            // 濡傛灉key涓嶄负绌哄氨鎸夌収key鍙戞秷鎭� 濡傛灉涓虹┖灏辩兢鍙�
+            if (CollUtil.isNotEmpty(message.getSessionKeys())) {
+                message.getSessionKeys().forEach(key -> {
+                    if (WebSocketSessionHolder.existSession(key)) {
+                        WebSocketUtils.sendMessage(key, message.getMessage());
+                    }
+                });
+            } else {
+                WebSocketSessionHolder.getSessionsAll().forEach(key -> {
+                    WebSocketUtils.sendMessage(key, message.getMessage());
+                });
+            }
+        });
+        log.info("鍒濆鍖朩ebSocket涓婚璁㈤槄鐩戝惉鍣ㄦ垚鍔�");
+    }
+
+    @Override
+    public int getOrder() {
+        return -1;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
new file mode 100644
index 0000000..8c4170a
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java
@@ -0,0 +1,127 @@
+package org.dromara.common.websocket.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.websocket.dto.WebSocketMessageDto;
+import org.dromara.common.websocket.holder.WebSocketSessionHolder;
+import org.springframework.web.socket.PongMessage;
+import org.springframework.web.socket.TextMessage;
+import org.springframework.web.socket.WebSocketMessage;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static org.dromara.common.websocket.constant.WebSocketConstants.WEB_SOCKET_TOPIC;
+
+/**
+ * 宸ュ叿绫�
+ *
+ * @author zendwang
+ */
+@Slf4j
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class WebSocketUtils {
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�佹秷鎭�
+     *
+     * @param sessionKey 瑕佸彂閫佹秷鎭殑鐢ㄦ埛id
+     * @param message    瑕佸彂閫佺殑娑堟伅鍐呭
+     */
+    public static void sendMessage(Long sessionKey, String message) {
+        WebSocketSession session = WebSocketSessionHolder.getSessions(sessionKey);
+        sendMessage(session, message);
+    }
+
+    /**
+     * 璁㈤槄WebSocket娑堟伅涓婚锛屽苟鎻愪緵涓�涓秷璐硅�呭嚱鏁版潵澶勭悊鎺ユ敹鍒扮殑娑堟伅
+     *
+     * @param consumer 澶勭悊WebSocket娑堟伅鐨勬秷璐硅�呭嚱鏁�
+     */
+    public static void subscribeMessage(Consumer<WebSocketMessageDto> consumer) {
+        RedisUtils.subscribe(WEB_SOCKET_TOPIC, WebSocketMessageDto.class, consumer);
+    }
+
+    /**
+     * 鍙戝竷WebSocket璁㈤槄娑堟伅
+     *
+     * @param webSocketMessage 瑕佸彂甯冪殑WebSocket娑堟伅瀵硅薄
+     */
+    public static void publishMessage(WebSocketMessageDto webSocketMessage) {
+        List<Long> unsentSessionKeys = new ArrayList<>();
+        // 褰撳墠鏈嶅姟鍐卻ession,鐩存帴鍙戦�佹秷鎭�
+        for (Long sessionKey : webSocketMessage.getSessionKeys()) {
+            if (WebSocketSessionHolder.existSession(sessionKey)) {
+                WebSocketUtils.sendMessage(sessionKey, webSocketMessage.getMessage());
+                continue;
+            }
+            unsentSessionKeys.add(sessionKey);
+        }
+        // 涓嶅湪褰撳墠鏈嶅姟鍐卻ession,鍙戝竷璁㈤槄娑堟伅
+        if (CollUtil.isNotEmpty(unsentSessionKeys)) {
+            WebSocketMessageDto broadcastMessage = new WebSocketMessageDto();
+            broadcastMessage.setMessage(webSocketMessage.getMessage());
+            broadcastMessage.setSessionKeys(unsentSessionKeys);
+            RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> {
+                log.info(" WebSocket鍙戦�佷富棰樿闃呮秷鎭痶opic:{} session keys:{} message:{}",
+                    WEB_SOCKET_TOPIC, unsentSessionKeys, webSocketMessage.getMessage());
+            });
+        }
+    }
+
+    /**
+     * 鍚戞墍鏈夌殑WebSocket浼氳瘽鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+     *
+     * @param message 瑕佸彂甯冪殑娑堟伅鍐呭
+     */
+    public static void publishAll(String message) {
+        WebSocketMessageDto broadcastMessage = new WebSocketMessageDto();
+        broadcastMessage.setMessage(message);
+        RedisUtils.publish(WEB_SOCKET_TOPIC, broadcastMessage, consumer -> {
+            log.info("WebSocket鍙戦�佷富棰樿闃呮秷鎭痶opic:{} message:{}", WEB_SOCKET_TOPIC, message);
+        });
+    }
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�丳ong娑堟伅
+     *
+     * @param session 瑕佸彂閫丳ong娑堟伅鐨刉ebSocket浼氳瘽
+     */
+    public static void sendPongMessage(WebSocketSession session) {
+        sendMessage(session, new PongMessage());
+    }
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�佹枃鏈秷鎭�
+     *
+     * @param session WebSocket浼氳瘽
+     * @param message 瑕佸彂閫佺殑鏂囨湰娑堟伅鍐呭
+     */
+    public static void sendMessage(WebSocketSession session, String message) {
+        sendMessage(session, new TextMessage(message));
+    }
+
+    /**
+     * 鍚戞寚瀹氱殑WebSocket浼氳瘽鍙戦�乄ebSocket娑堟伅瀵硅薄
+     *
+     * @param session WebSocket浼氳瘽
+     * @param message 瑕佸彂閫佺殑WebSocket娑堟伅瀵硅薄
+     */
+    private synchronized static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
+        if (session == null || !session.isOpen()) {
+            log.warn("[send] session浼氳瘽宸茬粡鍏抽棴");
+        } else {
+            try {
+                session.sendMessage(message);
+            } catch (IOException e) {
+                log.error("[send] session({}) 鍙戦�佹秷鎭�({}) 寮傚父", session, message, e);
+            }
+        }
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..c3a7305
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.websocket.config.WebSocketConfig
diff --git a/eims/ruoyi-extend/pom.xml b/eims/ruoyi-extend/pom.xml
new file mode 100644
index 0000000..d7280ce
--- /dev/null
+++ b/eims/ruoyi-extend/pom.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-vue-plus</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>ruoyi-extend</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>ruoyi-monitor-admin</module>
+        <module>ruoyi-snailjob-server</module>
+    </modules>
+
+</project>
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/Dockerfile b/eims/ruoyi-extend/ruoyi-monitor-admin/Dockerfile
new file mode 100644
index 0000000..99aaa74
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/Dockerfile
@@ -0,0 +1,20 @@
+# 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM findepi/graalvm:java17-native
+
+LABEL maintainer="Lion Li"
+
+RUN mkdir -p /ruoyi/monitor/logs
+
+WORKDIR /ruoyi/monitor
+
+ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE 9090
+
+ADD ./target/ruoyi-monitor-admin.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
+           -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
+           -jar app.jar
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/eims/ruoyi-extend/ruoyi-monitor-admin/pom.xml
new file mode 100644
index 0000000..77c9eb7
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-extend</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>ruoyi-monitor-admin</artifactId>
+
+    <dependencies>
+        <!-- SpringBoot Web瀹瑰櫒 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- web 瀹瑰櫒浣跨敤 undertow 鎬ц兘鏇村己 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+        </dependency>
+
+        <!-- spring security 瀹夊叏璁よ瘉 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-server</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <configuration>
+<!--                    <fork>true</fork> &lt;!&ndash; 濡傛灉娌℃湁璇ラ厤缃紝devtools涓嶄細鐢熸晥 &ndash;&gt;-->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java
new file mode 100644
index 0000000..0339ebb
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java
@@ -0,0 +1,19 @@
+package org.dromara.monitor.admin;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Admin 鐩戞帶鍚姩绋嬪簭
+ *
+ * @author Lion Li
+ */
+@SpringBootApplication
+public class MonitorAdminApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(MonitorAdminApplication.class, args);
+        System.out.println("Admin 鐩戞帶鍚姩鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java
new file mode 100644
index 0000000..53d248e
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/AdminServerConfig.java
@@ -0,0 +1,31 @@
+package org.dromara.monitor.admin.config;
+
+import de.codecentric.boot.admin.server.config.EnableAdminServer;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
+import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+
+/**
+ * springboot-admin server閰嶇疆绫�
+ *
+ * @author Lion Li
+ */
+@Configuration
+@EnableAdminServer
+public class AdminServerConfig {
+
+    @Lazy
+    @Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
+    @ConditionalOnMissingBean(Executor.class)
+    public ThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder builder) {
+        return builder.build();
+    }
+
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
new file mode 100644
index 0000000..3458cc9
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
@@ -0,0 +1,54 @@
+package org.dromara.monitor.admin.config;
+
+import de.codecentric.boot.admin.server.config.AdminServerProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+/**
+ * admin 鐩戞帶 瀹夊叏閰嶇疆
+ *
+ * @author Lion Li
+ */
+@EnableWebSecurity
+@Configuration
+public class SecurityConfig {
+
+    private final String adminContextPath;
+
+    public SecurityConfig(AdminServerProperties adminServerProperties) {
+        this.adminContextPath = adminServerProperties.getContextPath();
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
+        SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
+        successHandler.setTargetUrlParameter("redirectTo");
+        successHandler.setDefaultTargetUrl(adminContextPath + "/");
+
+        return httpSecurity
+            .headers((header) ->
+                header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
+            .authorizeHttpRequests((authorize) ->
+                authorize.requestMatchers(
+                        new AntPathRequestMatcher(adminContextPath + "/assets/**"),
+                        new AntPathRequestMatcher(adminContextPath + "/login")
+                    ).permitAll()
+                    .anyRequest().authenticated())
+            .formLogin((formLogin) ->
+                formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler))
+            .logout((logout) ->
+                logout.logoutUrl(adminContextPath + "/logout"))
+            .httpBasic(Customizer.withDefaults())
+            .csrf(AbstractHttpConfigurer::disable)
+            .build();
+    }
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java
new file mode 100644
index 0000000..838eefc
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java
@@ -0,0 +1,55 @@
+package org.dromara.monitor.admin.notifier;
+
+import de.codecentric.boot.admin.server.domain.entities.Instance;
+import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
+import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
+import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
+import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+import static de.codecentric.boot.admin.server.domain.values.StatusInfo.*;
+
+/**
+ * 鑷畾涔変簨浠堕�氱煡澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Component
+public class CustomNotifier extends AbstractEventNotifier {
+
+    protected CustomNotifier(InstanceRepository repository) {
+        super(repository);
+    }
+
+    @Override
+    @SuppressWarnings("all")
+    protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
+        return Mono.fromRunnable(() -> {
+            // 瀹炰緥鐘舵�佹敼鍙樹簨浠�
+            if (event instanceof InstanceStatusChangedEvent) {
+                // 鑾峰彇瀹炰緥娉ㄥ唽鍚嶇О
+                String registName = instance.getRegistration().getName();
+                // 鑾峰彇瀹炰緥ID
+                String instanceId = event.getInstance().getValue();
+                // 鑾峰彇瀹炰緥鐘舵��
+                String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
+                // 鑾峰彇鏈嶅姟URL
+                String serviceUrl = instance.getRegistration().getServiceUrl();
+                String statusName = switch (status) {
+                    case STATUS_UP -> "鏈嶅姟涓婄嚎"; // 瀹炰緥鎴愬姛鍚姩骞跺彲浠ユ甯稿鐞嗚姹�
+                    case STATUS_OFFLINE -> "鏈嶅姟绂荤嚎"; //瀹炰緥琚墜鍔ㄦ垨鑷姩鍦颁粠鏈嶅姟涓Щ闄�
+                    case STATUS_RESTRICTED -> "鏈嶅姟鍙楅檺"; //琛ㄧず瀹炰緥鍦ㄦ煇浜涙柟闈㈠彈闄愶紝鍙兘鏃犳硶瀹屽叏鎻愪緵鎵�鏈夋湇鍔�
+                    case STATUS_OUT_OF_SERVICE -> "鍋滄鏈嶅姟鐘舵��"; //琛ㄧず瀹炰緥宸茶鏍囪涓哄仠姝㈡彁渚涙湇鍔★紝鍙兘鏄鍒掑唴缁存姢鎴栨祴璇�
+                    case STATUS_DOWN -> "鏈嶅姟涓嬬嚎"; //瀹炰緥鍥犲穿婧冦�侀敊璇垨鍏朵粬鍘熷洜鍋滄杩愯
+                    case STATUS_UNKNOWN -> "鏈嶅姟鏈煡寮傚父"; //鐩戞帶绯荤粺鏃犳硶纭畾瀹炰緥鐨勫綋鍓嶇姸鎬�
+                    default -> "鏈煡鐘舵��"; //娌℃湁鍖归厤鐨勭姸鎬�
+                };
+                log.info("Instance Status Change: 鐘舵�佸悕绉般�恵}銆�, 娉ㄥ唽鍚嶇О銆恵}銆�, 瀹炰緥ID銆恵}銆�, 鐘舵�併�恵}銆�, 鏈嶅姟URL銆恵}銆�",
+                    statusName, registName, instanceId, status, serviceUrl);
+            }
+        });
+    }
+}
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..beee587
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml
@@ -0,0 +1,48 @@
+server:
+  port: 9090
+spring:
+  application:
+    name: ruoyi-monitor-admin
+  profiles:
+    active: @profiles.active@
+
+logging:
+  config: classpath:logback-plus.xml
+
+--- # 鐩戞帶涓績鏈嶅姟绔厤缃�
+spring:
+  security:
+    user:
+      name: ruoyi
+      password: 123456
+  boot:
+    admin:
+      ui:
+        title: RuoYi-Vue-Plus鏈嶅姟鐩戞帶涓績
+      context-path: /admin
+
+--- # Actuator 鐩戞帶绔偣鐨勯厤缃」
+management:
+  endpoints:
+    web:
+      exposure:
+        include: '*'
+  endpoint:
+    health:
+      show-details: ALWAYS
+    logfile:
+      external-file: ./logs/ruoyi-monitor-admin.log
+
+--- # 鐩戞帶閰嶇疆
+spring.boot.admin.client:
+  # 澧炲姞瀹㈡埛绔紑鍏�
+  enabled: true
+  # 璁剧疆 Spring Boot Admin Server 鍦板潃
+  url: http://localhost:9090/admin
+  instance:
+    service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
+  username: ruoyi
+  password: 123456
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/banner.txt b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/banner.txt
new file mode 100644
index 0000000..5d24152
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+Application Version: ${revision}
+Spring Boot Version: ${spring-boot.version}
+ __  __             _ _                              _           _
+|  \/  |           (_) |                    /\      | |         (_)
+| \  / | ___  _ __  _| |_ ___  _ __ ______ /  \   __| |_ __ ___  _ _ __
+| |\/| |/ _ \| '_ \| | __/ _ \| '__|______/ /\ \ / _` | '_ ` _ \| | '_ \
+| |  | | (_) | | | | | || (_) | |        / ____ \ (_| | | | | | | | | | |
+|_|  |_|\___/|_| |_|_|\__\___/|_|       /_/    \_\__,_|_| |_| |_|_|_| |_|
diff --git a/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..16bb937
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="true" scanPeriod="1 seconds">
+
+    <contextName>logback</contextName>
+    <property name="log.path" value="./logs/ruoyi-monitor-admin"/>
+    <property name="console.log.pattern"
+              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
+
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${console.log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="console"/>
+        <appender-ref ref="file"/>
+    </root>
+
+</configuration>
\ No newline at end of file
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/Dockerfile b/eims/ruoyi-extend/ruoyi-snailjob-server/Dockerfile
new file mode 100644
index 0000000..a66ca66
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/Dockerfile
@@ -0,0 +1,21 @@
+# 璐濆皵瀹為獙瀹� Spring 瀹樻柟鎺ㄨ崘闀滃儚 JDK涓嬭浇鍦板潃 https://bell-sw.com/pages/downloads/
+FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
+#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds
+#FROM findepi/graalvm:java17-native
+
+LABEL maintainer="Lion Li"
+
+RUN mkdir -p /ruoyi/snailjob/logs
+
+WORKDIR /ruoyi/snailjob
+
+ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m"
+
+EXPOSE 8800
+EXPOSE 17888
+
+ADD ./target/ruoyi-snailjob-server.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \
+           -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
+           -jar app.jar
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/pom.xml b/eims/ruoyi-extend/ruoyi-snailjob-server/pom.xml
new file mode 100644
index 0000000..7348b29
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-extend</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>ruoyi-snailjob-server</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-server-starter</artifactId>
+            <version>${snailjob.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>de.codecentric</groupId>
+            <artifactId>spring-boot-admin-starter-client</artifactId>
+            <version>${spring-boot-admin.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring-boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java
new file mode 100644
index 0000000..e3a6892
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java
@@ -0,0 +1,64 @@
+package com.aizuda.snailjob.server.starter.filter;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+public class ActuatorAuthFilter implements Filter {
+
+    private final String username;
+    private final String password;
+
+    public ActuatorAuthFilter(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+        // 鑾峰彇 Authorization 澶�
+        String authHeader = request.getHeader("Authorization");
+
+        if (authHeader == null || !authHeader.startsWith("Basic ")) {
+            // 濡傛灉娌℃湁鎻愪緵 Authorization 鎴栬�呮牸寮忎笉瀵癸紝鍒欒繑鍥� 401
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+
+        // 瑙g爜 Base64 缂栫爜鐨勭敤鎴峰悕鍜屽瘑鐮�
+        String base64Credentials = authHeader.substring("Basic ".length());
+        byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
+        String credentials = new String(credDecoded, StandardCharsets.UTF_8);
+        String[] split = credentials.split(":");
+        if (split.length != 2) {
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+        // 楠岃瘉鐢ㄦ埛鍚嶅拰瀵嗙爜
+        if (!username.equals(split[0]) && password.equals(split[1])) {
+            response.setHeader("WWW-Authenticate", "Basic realm=\"realm\"");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+            return;
+        }
+        // 濡傛灉璁よ瘉鎴愬姛锛岀户缁鐞嗚姹�
+        filterChain.doFilter(request, response);
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
new file mode 100644
index 0000000..3cae8f5
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java
@@ -0,0 +1,29 @@
+package com.aizuda.snailjob.server.starter.filter;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 鏉冮檺瀹夊叏閰嶇疆
+ *
+ * @author Lion Li
+ */
+@Configuration
+public class SecurityConfig {
+
+    @Value("${spring.boot.admin.client.username}")
+    private String username;
+    @Value("${spring.boot.admin.client.password}")
+    private String password;
+
+    @Bean
+    public FilterRegistrationBean<ActuatorAuthFilter> actuatorFilterRegistrationBean() {
+        FilterRegistrationBean<ActuatorAuthFilter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(new ActuatorAuthFilter(username, password));
+        registrationBean.addUrlPatterns("/actuator", "/actuator/**");
+        return registrationBean;
+    }
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/org/dromara/snailjob/SnailJobServerApplication.java b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/org/dromara/snailjob/SnailJobServerApplication.java
new file mode 100644
index 0000000..dfab068
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/java/org/dromara/snailjob/SnailJobServerApplication.java
@@ -0,0 +1,19 @@
+package org.dromara.snailjob;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * SnailJob Server 鍚姩绋嬪簭
+ *
+ * @author opensnail
+ * @date 2024-05-17
+ */
+@SpringBootApplication
+public class SnailJobServerApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(com.aizuda.snailjob.server.SnailJobServerApplication.class, args);
+    }
+
+}
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..cbe40be
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml
@@ -0,0 +1,50 @@
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
+    username: root
+    password: root
+    hikari:
+      connection-timeout: 30000
+      validation-timeout: 5000
+      minimum-idle: 10
+      maximum-pool-size: 20
+      idle-timeout: 600000
+      max-lifetime: 900000
+      keepaliveTime: 30000
+
+--- # snail-job 鏈嶅姟绔厤缃�
+snail-job:
+  # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
+  retry-pull-page-size: 1000
+  # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
+  job-pull-page-size: 1000
+  # 鏈嶅姟绔痭etty绔彛
+  netty-port: 17888
+  # 涓�涓鎴风姣忕鏈�澶氭帴鏀剁殑閲嶈瘯鏁伴噺鎸囦护
+  limiter: 1000
+  # 鍙锋妯″紡涓嬫闀块厤缃�
+  step: 100
+  # 鏃ュ織淇濆瓨鏃堕棿(鍗曚綅: day)
+  log-storage: 90
+  # 鍥炶皟閰嶇疆
+  callback:
+    #鍥炶皟鏈�澶ф墽琛屾鏁�
+    max-count: 288
+    #闂撮殧鏃堕棿
+    trigger-interval: 900
+  retry-max-pull-count: 10
+
+--- # 鐩戞帶涓績閰嶇疆
+spring.boot.admin.client:
+  # 澧炲姞瀹㈡埛绔紑鍏�
+  enabled: true
+  url: http://localhost:9090/admin
+  instance:
+    service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
+  username: ruoyi
+  password: 123456
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..3ba983c
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml
@@ -0,0 +1,50 @@
+spring:
+  datasource:
+    type: com.zaxxer.hikari.HikariDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
+    username: root
+    password: root
+    hikari:
+      connection-timeout: 30000
+      validation-timeout: 5000
+      minimum-idle: 10
+      maximum-pool-size: 20
+      idle-timeout: 600000
+      max-lifetime: 900000
+      keepaliveTime: 30000
+
+--- # snail-job 鏈嶅姟绔厤缃�
+snail-job:
+  # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
+  retry-pull-page-size: 1000
+  # 鎷夊彇閲嶈瘯鏁版嵁鐨勬瘡鎵规鐨勫ぇ灏�
+  job-pull-page-size: 1000
+  # 鏈嶅姟绔� netty 绔彛
+  netty-port: 17888
+  # 涓�涓鎴风姣忕鏈�澶氭帴鏀剁殑閲嶈瘯鏁伴噺鎸囦护
+  limiter: 1000
+  # 鍙锋妯″紡涓嬫闀块厤缃�
+  step: 100
+  # 鏃ュ織淇濆瓨鏃堕棿(鍗曚綅: day)
+  log-storage: 90
+  # 鍥炶皟閰嶇疆
+  callback:
+    #鍥炶皟鏈�澶ф墽琛屾鏁�
+    max-count: 288
+    #闂撮殧鏃堕棿
+    trigger-interval: 900
+  retry-max-pull-count: 10
+
+--- # 鐩戞帶涓績閰嶇疆
+spring.boot.admin.client:
+  # 澧炲姞瀹㈡埛绔紑鍏�
+  enabled: true
+  url: http://localhost:9090/admin
+  instance:
+    service-host-type: IP
+    metadata:
+      username: ${spring.boot.admin.client.username}
+      userpassword: ${spring.boot.admin.client.password}
+  username: ruoyi
+  password: 123456
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml
new file mode 100644
index 0000000..ba6df45
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml
@@ -0,0 +1,39 @@
+server:
+  port: 8800
+  servlet:
+    context-path: /snail-job
+
+spring:
+  application:
+    name: ruoyi-snailjob-server
+  profiles:
+    active: @profiles.active@
+  web:
+    resources:
+      static-locations: classpath:admin/
+
+mybatis-plus:
+  typeAliasesPackage: com.aizuda.snailjob.template.datasource.persistence.po
+  global-config:
+    db-config:
+      where-strategy: NOT_EMPTY
+      capital-mode: false
+      logic-delete-value: 1
+      logic-not-delete-value: 0
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: true
+
+logging:
+  config: classpath:logback-plus.xml
+
+management:
+  endpoints:
+    web:
+      exposure:
+        include: '*'
+  endpoint:
+    health:
+      show-details: ALWAYS
+    logfile:
+      external-file: ./logs/ruoyi-snailjob-server/console.log
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/banner.txt b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/banner.txt
new file mode 100644
index 0000000..adb96c5
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/banner.txt
@@ -0,0 +1,11 @@
+Application Version: ${revision}
+Spring Boot Version: ${spring-boot.version}
+                 _ _ _       _
+                (_) (_)     | |
+ ___ _ __   __ _ _| |_  ___ | |__ ______ ___  ___ _ ____   _____ _ __
+/ __| '_ \ / _` | | | |/ _ \| '_ \______/ __|/ _ \ '__\ \ / / _ \ '__|
+\__ \ | | | (_| | | | | (_) | |_) |     \__ \  __/ |   \ V /  __/ |
+|___/_| |_|\__,_|_|_| |\___/|_.__/      |___/\___|_|    \_/ \___|_|
+                   _/ |
+                  |__/
+
diff --git a/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..a40262c
--- /dev/null
+++ b/eims/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="log.path" value="./logs/ruoyi-snailjob-server" />
+    <property name="console.log.pattern"
+              value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
+
+
+    <!-- 鎺у埗鍙拌緭鍑� -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${console.log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 鎺у埗鍙拌緭鍑� -->
+    <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/console.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/console.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶� 1澶� -->
+            <maxHistory>1</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>INFO</level>
+        </filter>
+    </appender>
+
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</FileNamePattern>
+            <MaxHistory>60</MaxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/error.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <FileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log
+            </FileNamePattern>
+            <MaxHistory>60</MaxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name ="async_info" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="file_info"/>
+    </appender>
+
+    <appender name ="async_error" class= "ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold >100</discardingThreshold>
+        <queueSize>1024</queueSize>
+        <appender-ref ref ="file_error"/>
+    </appender>
+
+    <!-- SnailJob appender -->
+    <appender name="snail_log_server_appender" class="com.aizuda.snailjob.server.common.appender.SnailJobServerLogbackAppender">
+    </appender>
+
+    <!-- 鎺у埗鍙拌緭鍑烘棩蹇楃骇鍒� -->
+    <root level="info">
+        <appender-ref ref="console" />
+        <appender-ref ref="async_info" />
+        <appender-ref ref="async_error" />
+        <appender-ref ref="snail_log_server_appender" />
+    </root>
+</configuration>
diff --git a/eims/ruoyi-modules/.DS_Store b/eims/ruoyi-modules/.DS_Store
new file mode 100644
index 0000000..5fb0384
--- /dev/null
+++ b/eims/ruoyi-modules/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/.DS_Store b/eims/ruoyi-modules/lb-eims/.DS_Store
new file mode 100644
index 0000000..5ec7eca
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/pom.xml b/eims/ruoyi-modules/lb-eims/pom.xml
new file mode 100644
index 0000000..590b88e
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/pom.xml
@@ -0,0 +1,102 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <artifactId>lb-eims</artifactId>
+    <description>
+        demo妯″潡
+    </description>
+    <dependencies>
+
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sms</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mail</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-excel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-ratelimiter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sensitive</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-encrypt</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-websocket</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>
diff --git a/eims/ruoyi-modules/lb-eims/src/.DS_Store b/eims/ruoyi-modules/lb-eims/src/.DS_Store
new file mode 100644
index 0000000..fe6c0c6
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/src/main/.DS_Store b/eims/ruoyi-modules/lb-eims/src/main/.DS_Store
new file mode 100644
index 0000000..4cafc79
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquController.java
new file mode 100644
index 0000000..2faa7e8
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquController.java
@@ -0,0 +1,107 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import org.dromara.eims.domain.bo.SysEquBo;
+import org.dromara.eims.domain.vo.SysEquVo;
+import org.dromara.eims.service.ISysEquService;
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+
+
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 銆愯澶囧彴璐︺��
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/equ")
+public class SysEquController extends BaseController {
+
+    private final ISysEquService sysEquipmentService;
+
+    /**
+     * 鏌ヨ銆愯澶囧彴璐︺�戝垪琛�
+     */
+    @SaCheckPermission("system:equipment:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysEquVo> list(SysEquBo bo, PageQuery pageQuery) {
+        return sysEquipmentService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭銆愯澶囧彴璐︺�戝垪琛�
+     */
+    @SaCheckPermission("system:equipment:export")
+    @Log(title = "銆愯澶囧彴璐︺��", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysEquBo bo, HttpServletResponse response) {
+        List<SysEquVo> list = sysEquipmentService.queryList(bo);
+        ExcelUtil.exportExcel(list, "銆愯澶囧彴璐︺��", SysEquVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇銆愯澶囧彴璐︺�戣缁嗕俊鎭�
+     *
+     * @param equId 涓婚敭
+     */
+    @SaCheckPermission("system:equipment:query")
+    @GetMapping("/{equId}")
+    public R<SysEquVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long equId) {
+        return R.ok(sysEquipmentService.queryById(equId));
+    }
+
+    /**
+     * 鏂板銆愯澶囧彴璐︺��
+     */
+    @SaCheckPermission("system:equipment:add")
+    @Log(title = "銆愯澶囧彴璐︺��", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysEquBo bo) {
+        return toAjax(sysEquipmentService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼銆愯澶囧彴璐︺��
+     */
+    @SaCheckPermission("system:equipment:edit")
+    @Log(title = "銆愯澶囧彴璐︺��", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysEquBo bo) {
+        return toAjax(sysEquipmentService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎銆愯澶囧彴璐︺��
+     *
+     * @param equIds 涓婚敭涓�
+     */
+    @SaCheckPermission("system:equipment:remove")
+    @Log(title = "銆愯澶囧彴璐︺��", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{equIds}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] equIds) {
+        return toAjax(sysEquipmentService.deleteWithValidByIds(List.of(equIds), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquTypeController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquTypeController.java
new file mode 100644
index 0000000..c0c712f
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/SysEquTypeController.java
@@ -0,0 +1,124 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.SysEquTypeVo;
+import org.dromara.eims.domain.bo.SysEquTypeBo;
+import org.dromara.eims.service.ISysEquTypeService;
+
+/**
+ * 璁惧绫诲瀷
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/equType")
+public class SysEquTypeController extends BaseController {
+
+    private final ISysEquTypeService sysEquTypeService;
+
+    /**
+     * 鏌ヨ璁惧绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:equType:list")
+    @GetMapping("/list")
+    public R<List<SysEquTypeVo>> list(SysEquTypeBo bo) {
+        List<SysEquTypeVo> list = sysEquTypeService.queryList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 鑾峰彇璁惧绫诲瀷鏍戝垪琛�
+     */
+    @SaCheckPermission("eims:equType:list")
+    @GetMapping("/tree")
+    public R<List<Tree<Long>>> equTypeTree(SysEquTypeBo bo) {
+        return R.ok(sysEquTypeService.selectEquTypeTreeList(bo));
+    }
+
+    /**
+     * 瀵煎嚭璁惧绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:equType:export")
+    @Log(title = "璁惧绫诲瀷", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysEquTypeBo bo, HttpServletResponse response) {
+        List<SysEquTypeVo> list = sysEquTypeService.queryList(bo);
+        ExcelUtil.exportExcel(list, "璁惧绫诲瀷", SysEquTypeVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇璁惧绫诲瀷璇︾粏淇℃伅
+     *
+     * @param equTypeId 涓婚敭
+     */
+    @SaCheckPermission("eims:equType:query")
+    @GetMapping("/{equTypeId}")
+    public R<SysEquTypeVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                   @PathVariable Long equTypeId) {
+        return R.ok(sysEquTypeService.queryById(equTypeId));
+    }
+
+    /**
+     * 鏂板璁惧绫诲瀷
+     */
+    @SaCheckPermission("eims:equType:add")
+    @Log(title = "璁惧绫诲瀷", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysEquTypeBo bo) {
+        return toAjax(sysEquTypeService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼璁惧绫诲瀷
+     */
+    @SaCheckPermission("eims:equType:edit")
+    @Log(title = "璁惧绫诲瀷", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysEquTypeBo bo) {
+        return toAjax(sysEquTypeService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎璁惧绫诲瀷
+     *
+     * @param equTypeIds 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:equType:remove")
+    @Log(title = "璁惧绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{equTypeIds}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] equTypeIds) {
+        if (equTypeIds == null || equTypeIds.length == 0) {
+            return R.warn("璇烽�夋嫨闇�瑕佸垹闄ょ殑鏁版嵁");
+        }
+        for (int i = 0; i < equTypeIds.length; i++) {
+            if (sysEquTypeService.hasChildByEquTypeId(equTypeIds[i])) {
+                return R.warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+            }
+        }
+
+        return toAjax(sysEquTypeService.deleteWithValidByIds(List.of(equTypeIds), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEqu.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEqu.java
new file mode 100644
index 0000000..a78de6c
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEqu.java
@@ -0,0 +1,151 @@
+package org.dromara.eims.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+
+import java.io.Serial;
+
+/**
+ * 銆愯澶囧彴璐︺�戝璞� sys_equ
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_equ")
+public class SysEqu extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "equ_id")
+    private Long equId;
+    /**
+     * 璁惧缂栫爜
+     */
+    private String equCode;
+
+
+    /**
+     * 璁惧绫诲瀷id
+     */
+    private Long equTypeId;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    private String assetNo;
+
+    /**
+     * 璁惧鍚嶇О
+
+     */
+    private String equName;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 棰濆害鍔熺巼
+     */
+    private String ratedPower;
+
+    /**
+     * 閾墝淇℃伅
+     */
+    private String plateInfo;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 鐘舵��
+     */
+    private String status;
+
+    /**
+     * 鎵�鍦ㄥ満鎵�
+     */
+    private String location;
+
+    /**
+     * 浣跨敤閮ㄩ棬锛堝叧鑱攊d锛�
+     */
+    private Long deptUsed;
+
+    /**
+     * 璐d换浜�(鍏宠仈id)
+     */
+    private Long respPerson;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    private String contactPhone;
+
+    /**
+     * 姝e紡浣跨敤鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 寮�濮嬭瘯鐢ㄦ棩鏈�
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date trialDate;
+
+    /**
+     * 璁″垝楠屾敹鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date planAcceptDate;
+
+    /**
+     * 瀹為檯楠屾敹鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date actualAcceptDate;
+
+    /**
+     * 瀵煎叆鐘舵�侊紙瀛楀吀锛�
+     */
+    private String importStatus;
+
+
+    /**
+     * 鐩樼偣鏍囧織
+     */
+    private String inventoryFlag;
+
+    /**
+     * 涓婃鐩樼偣鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date inventoryDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    private Long serviceLife;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEquType.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEquType.java
new file mode 100644
index 0000000..d64b247
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/SysEquType.java
@@ -0,0 +1,71 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 璁惧绫诲瀷瀵硅薄 sys_equ_type
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_equ_type")
+public class SysEquType extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绫诲瀷id
+     */
+    @TableId(value = "equ_type_id")
+    private Long equTypeId;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquBo.java
new file mode 100644
index 0000000..6659fd3
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquBo.java
@@ -0,0 +1,148 @@
+package org.dromara.eims.domain.bo;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.eims.domain.SysEqu;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 銆愯澶囧彴璐︺�戜笟鍔″璞� sys_equipment
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysEqu.class, reverseConvertGenerate = false)
+public class SysEquBo extends BaseEntity {
+
+    /**
+     *
+     */
+   // @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long equId;
+    /**
+     * 璁惧缂栫爜
+     */
+    private String equCode;
+    /**
+     * 璁惧绫诲瀷id
+     */
+    private Long equTypeId;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    private String assetNo;
+
+    /**
+     * 璁惧鍚嶇О
+
+     */
+    private String equName;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 棰濆畾鍔熺巼
+     */
+    private String ratedPower;
+
+    /**
+     * 閾墝淇℃伅
+     */
+    private String plateInfo;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 鐘舵��
+     */
+    private String status;
+
+    /**
+     * 鎵�鍦ㄥ満鎵�
+     */
+    private String location;
+
+    /**
+     * 浣跨敤閮ㄩ棬锛堝叧鑱攊d锛�
+     */
+    private Long deptUsed;
+
+    /**
+     * 璐d换浜�(鍏宠仈id)
+     */
+    private Long respPerson;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    private String contactPhone;
+
+    /**
+     * 姝e紡浣跨敤鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 寮�濮嬭瘯鐢ㄦ棩鏈�
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date trialDate;
+
+    /**
+     * 璁″垝楠屾敹鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date planAcceptDate;
+
+    /**
+     * 瀹為檯楠屾敹鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date actualAcceptDate;
+
+    /**
+     * 瀵煎叆鐘舵�侊紙瀛楀吀锛�
+     */
+    private String importStatus;
+    /**
+     * 鐩樼偣鏍囧織
+     */
+    private String inventoryFlag;
+
+    /**
+     * 涓婃鐩樼偣鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date inventoryDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    private Long serviceLife;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquTypeBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquTypeBo.java
new file mode 100644
index 0000000..b01b830
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/SysEquTypeBo.java
@@ -0,0 +1,69 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.SysEquType;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 璁惧绫诲瀷涓氬姟瀵硅薄 sys_equ_type
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysEquType.class, reverseConvertGenerate = false)
+public class SysEquTypeBo extends BaseEntity {
+
+    /**
+     * 绫诲瀷id
+     */
+    private Long equTypeId;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquTypeVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquTypeVo.java
new file mode 100644
index 0000000..840eede
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquTypeVo.java
@@ -0,0 +1,90 @@
+package org.dromara.eims.domain.vo;
+
+import org.dromara.eims.domain.SysEquType;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 璁惧绫诲瀷瑙嗗浘瀵硅薄 sys_equ_type
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysEquType.class)
+public class SysEquTypeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绫诲瀷id
+     */
+    @ExcelProperty(value = "绫诲瀷id")
+    private Long equTypeId;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    @ExcelProperty(value = "绫诲瀷鍚嶇О")
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    @ExcelProperty(value = "绫诲瀷缂栫爜")
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    @ExcelProperty(value = "鐖秈d")
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @ExcelProperty(value = "鏄剧ず椤哄簭")
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    @ExcelProperty(value = "鑿滃崟绫诲瀷", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "M=鐩綍,C=鑿滃崟,F=鎸夐挳")
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    @ExcelProperty(value = "鑿滃崟鍥炬爣")
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "鑿滃崟鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    private List<SysEquTypeVo> children;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquVo.java
new file mode 100644
index 0000000..5426e7d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/SysEquVo.java
@@ -0,0 +1,201 @@
+package org.dromara.eims.domain.vo;
+
+import java.util.Date;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.eims.domain.SysEqu;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 銆愯澶囧彴璐︺�戣鍥惧璞� sys_equipment
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysEqu.class)
+public class SysEquVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long equId;
+    /**
+     * 璁惧缂栫爜
+     */
+    @ExcelProperty(value = "璁惧缂栫爜")
+    private String equCode;
+
+
+    /**
+     * 璁惧绫诲瀷id
+     */
+    private Long equTypeId;
+
+    /**
+     * 璁惧绫诲瀷鍚嶇О
+     */
+    @ExcelProperty(value = "璁惧绫诲瀷")
+    @Translation(type = TransConstant.EQU_YPE_ID_TO_NAME, mapper = "equTypeId")
+    private String equTypeName;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    @ExcelProperty(value = "璧勪骇缂栧彿")
+    private String assetNo;
+
+    /**
+     * 璁惧鍚嶇О
+
+     */
+    @ExcelProperty(value = "璁惧鍚嶇О")
+    private String equName;
+
+    /**
+     * 鍨嬪彿
+     */
+    @ExcelProperty(value = "鍨嬪彿")
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    @ExcelProperty(value = "鍒堕�犲晢")
+    private String madeIn;
+
+    /**
+     * 棰濆害鍔熺巼
+     */
+    @ExcelProperty(value = "棰濆害鍔熺巼")
+    private String ratedPower;
+
+    /**
+     * 閾墝淇℃伅
+     */
+    @ExcelProperty(value = "閾墝淇℃伅")
+    private String plateInfo;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @ExcelProperty(value = "閲囪喘鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 鐘舵��
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_equ_status")
+    private String status;
+
+    /**
+     * 鎵�鍦ㄥ満鎵�
+     */
+    @ExcelProperty(value = "鎵�鍦ㄥ満鎵�")
+    private String location;
+
+    /**
+     * 浣跨敤閮ㄩ棬锛堝叧鑱攊d锛�
+     */
+    @ExcelProperty(value = "浣跨敤閮ㄩ棬", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "鍏�=鑱攊d")
+    private Long deptUsed;
+    /**
+     * 閮ㄩ棬鍚�
+     */
+    @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptUsed")
+    private String deptName;
+
+    /**
+     * 璐d换浜�(鍏宠仈id)
+     */
+    @ExcelProperty(value = "璐d换浜�(鍏宠仈id)")
+    private Long respPerson;
+    /**
+     * 閮ㄩ棬鍚�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "respPerson")
+    private String respPersonName;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    @ExcelProperty(value = "鑱旂郴鐢佃瘽")
+    private String contactPhone;
+
+    /**
+     * 姝e紡浣跨敤鏃ユ湡
+     */
+    @ExcelProperty(value = "姝e紡浣跨敤鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 寮�濮嬭瘯鐢ㄦ棩鏈�
+     */
+    @ExcelProperty(value = "寮�濮嬭瘯鐢ㄦ棩鏈�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date trialDate;
+
+    /**
+     * 璁″垝楠屾敹鏃ユ湡
+     */
+    @ExcelProperty(value = "璁″垝楠屾敹鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date planAcceptDate;
+
+    /**
+     * 瀹為檯楠屾敹鏃ユ湡
+     */
+    @ExcelProperty(value = "瀹為檯楠屾敹鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date actualAcceptDate;
+
+    /**
+     * 瀵煎叆鐘舵�侊紙瀛楀吀锛�
+     */
+    @ExcelProperty(value = "瀵煎叆鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "瀛�=鍏�")
+    private String importStatus;
+
+
+
+    /**
+     * 鐩樼偣鏍囧織
+     */
+    @ExcelProperty(value = "鐩樼偣鏍囧織")
+    private String inventoryFlag;
+
+    /**
+     * 涓婃鐩樼偣鏃ユ湡
+     */
+    @ExcelProperty(value = "涓婃鐩樼偣鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date inventoryDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    @ExcelProperty(value = "浣跨敤骞撮檺")
+    private Long serviceLife;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquMapper.java
new file mode 100644
index 0000000..1371909
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.SysEqu;
+import org.dromara.eims.domain.vo.SysEquVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 銆愯澶囧彴璐︺�慚apper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+public interface SysEquMapper extends BaseMapperPlus<SysEqu, SysEquVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquTypeMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquTypeMapper.java
new file mode 100644
index 0000000..cbf20e8
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/SysEquTypeMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.SysEquType;
+import org.dromara.eims.domain.vo.SysEquTypeVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 璁惧绫诲瀷Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+public interface SysEquTypeMapper extends BaseMapperPlus<SysEquType, SysEquTypeVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquService.java
new file mode 100644
index 0000000..d2ab9bb
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquService.java
@@ -0,0 +1,69 @@
+package org.dromara.eims.service;
+
+
+import org.dromara.eims.domain.bo.SysEquBo;
+import org.dromara.eims.domain.vo.SysEquVo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 銆愯澶囧彴璐︺�慡ervice鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+public interface ISysEquService {
+
+    /**
+     * 鏌ヨ銆愯澶囧彴璐︺��
+     *
+     * @param equId 涓婚敭
+     * @return 銆愯澶囧彴璐︺��
+     */
+    SysEquVo queryById(Long equId);
+
+    /**
+     * 鍒嗛〉鏌ヨ銆愯澶囧彴璐︺�戝垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 銆愯澶囧彴璐︺�戝垎椤靛垪琛�
+     */
+    TableDataInfo<SysEquVo> queryPageList(SysEquBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勩�愯澶囧彴璐︺�戝垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 銆愯澶囧彴璐︺�戝垪琛�
+     */
+    List<SysEquVo> queryList(SysEquBo bo);
+
+    /**
+     * 鏂板銆愯澶囧彴璐︺��
+     *
+     * @param bo 銆愯澶囧彴璐︺��
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(SysEquBo bo);
+
+    /**
+     * 淇敼銆愯澶囧彴璐︺��
+     *
+     * @param bo 銆愯澶囧彴璐︺��
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(SysEquBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゃ�愯澶囧彴璐︺�戜俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquTypeService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquTypeService.java
new file mode 100644
index 0000000..c91d35d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/ISysEquTypeService.java
@@ -0,0 +1,75 @@
+package org.dromara.eims.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.eims.domain.vo.SysEquTypeVo;
+import org.dromara.eims.domain.bo.SysEquTypeBo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 璁惧绫诲瀷Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+public interface ISysEquTypeService {
+
+    /**
+     * 鏌ヨ璁惧绫诲瀷
+     *
+     * @param equTypeId 涓婚敭
+     * @return 璁惧绫诲瀷
+     */
+    SysEquTypeVo queryById(Long equTypeId);
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勮澶囩被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 璁惧绫诲瀷鍒楄〃
+     */
+    List<SysEquTypeVo> queryList(SysEquTypeBo bo);
+
+    /**
+     * 鏂板璁惧绫诲瀷
+     *
+     * @param bo 璁惧绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(SysEquTypeBo bo);
+
+    /**
+     * 淇敼璁惧绫诲瀷
+     *
+     * @param bo 璁惧绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(SysEquTypeBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄よ澶囩被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     *
+     * @param equTypeId 璁惧绫诲瀷ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    boolean hasChildByEquTypeId(Long equTypeId);
+
+    /**
+     * 鑾峰彇璁惧绫诲瀷鏍戝垪琛�
+     *
+     * @param bo
+     * @return 鏍戝垪琛�
+     */
+    List<Tree<Long>> selectEquTypeTreeList(SysEquTypeBo bo);
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquServiceImpl.java
new file mode 100644
index 0000000..bd9b64e
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquServiceImpl.java
@@ -0,0 +1,188 @@
+package org.dromara.eims.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.eims.domain.SysEqu;
+import org.dromara.eims.domain.SysEquType;
+import org.dromara.eims.domain.bo.SysEquBo;
+import org.dromara.eims.domain.vo.SysEquTypeVo;
+import org.dromara.eims.domain.vo.SysEquVo;
+import org.dromara.eims.mapper.SysEquMapper;
+import org.dromara.eims.mapper.SysEquTypeMapper;
+import org.dromara.eims.service.ISysEquService;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * 銆愯澶囧彴璐︺�慡ervice涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-01-04
+ */
+@RequiredArgsConstructor
+@Service
+public class SysEquServiceImpl implements ISysEquService {
+
+    private final SysEquMapper baseMapper;
+    private final SysEquTypeMapper equTypeMapper;
+
+    /**
+     * 鏌ヨ銆愯澶囧彴璐︺��
+     *
+     * @param equId 涓婚敭
+     * @return 銆愯澶囧彴璐︺��
+     */
+    @Override
+    public SysEquVo queryById(Long equId){
+        return baseMapper.selectVoById(equId);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ銆愯澶囧彴璐︺�戝垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 銆愯澶囧彴璐︺�戝垎椤靛垪琛�
+     */
+    @Override
+    public TableDataInfo<SysEquVo> queryPageList(SysEquBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysEqu> lqw = buildQueryWrapper(bo);
+        Page<SysEquVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勩�愯澶囧彴璐︺�戝垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 銆愯澶囧彴璐︺�戝垪琛�
+     */
+    @Override
+    public List<SysEquVo> queryList(SysEquBo bo) {
+        LambdaQueryWrapper<SysEqu> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysEqu> buildQueryWrapper(SysEquBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SysEqu> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getAssetNo()), SysEqu::getAssetNo, bo.getAssetNo());
+        Long equTypeId = bo.getEquTypeId();
+        /**
+         * equTypeId = 0 鏃舵煡璇㈡墍鏈夎澶囷紙榛樿鏍圭洰褰昳d涓�0锛岃瑙丼ysEquTypeServiceImpl涓璼electEquTypeTreeList锛�
+         * equTypeId   涓哄叾浠栧�兼椂鍙煡褰撳墠璁惧绫诲瀷id鍜屽悗浠h澶囩被鍨媔d
+         */
+        if (equTypeId != null && equTypeId > 0) {
+            List<Long> allDescendantIds = getAllDescendantIds(equTypeId);
+            lqw.in(SysEqu::getEquTypeId,allDescendantIds);
+        }
+
+        lqw.like(StringUtils.isNotBlank(bo.getEquName()), SysEqu::getEquName, bo.getEquName());
+        lqw.eq(StringUtils.isNotBlank(bo.getModelNo()), SysEqu::getModelNo, bo.getModelNo());
+        lqw.eq(StringUtils.isNotBlank(bo.getMadeIn()), SysEqu::getMadeIn, bo.getMadeIn());
+        lqw.eq(bo.getRatedPower() != null, SysEqu::getRatedPower, bo.getRatedPower());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlateInfo()), SysEqu::getPlateInfo, bo.getPlateInfo());
+        lqw.eq(bo.getPurchaseDate() != null, SysEqu::getPurchaseDate, bo.getPurchaseDate());
+        lqw.eq(bo.getStatus() != null, SysEqu::getStatus, bo.getStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getLocation()), SysEqu::getLocation, bo.getLocation());
+        lqw.eq(bo.getDeptUsed() != null, SysEqu::getDeptUsed, bo.getDeptUsed());
+        lqw.eq(bo.getRespPerson() != null, SysEqu::getRespPerson, bo.getRespPerson());
+        lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysEqu::getContactPhone, bo.getContactPhone());
+        lqw.eq(bo.getDeployDate() != null, SysEqu::getDeployDate, bo.getDeployDate());
+        lqw.eq(bo.getTrialDate() != null, SysEqu::getTrialDate, bo.getTrialDate());
+        lqw.eq(bo.getPlanAcceptDate() != null, SysEqu::getPlanAcceptDate, bo.getPlanAcceptDate());
+        lqw.eq(bo.getActualAcceptDate() != null, SysEqu::getActualAcceptDate, bo.getActualAcceptDate());
+        lqw.eq(bo.getImportStatus() != null, SysEqu::getImportStatus, bo.getImportStatus());
+        lqw.eq(StringUtils.isNotBlank(bo.getEquCode()), SysEqu::getEquCode, bo.getEquCode());
+        lqw.eq(bo.getInventoryFlag() != null, SysEqu::getInventoryFlag, bo.getInventoryFlag());
+        lqw.eq(bo.getInventoryDate() != null, SysEqu::getInventoryDate, bo.getInventoryDate());
+        lqw.eq(bo.getServiceLife() != null, SysEqu::getServiceLife, bo.getServiceLife());
+        return lqw;
+    }
+
+    /**
+     * 鏍规嵁id锛岃幏鍙栨墍鏈夊悗浠d
+     * @param rootId
+     * @return
+     */
+    public List<Long> getAllDescendantIds(Long rootId) {
+        List<Long> result = new ArrayList<>();
+        result.add(rootId);
+        collectDescendants(rootId, result);
+        return result;
+    }
+
+    private void collectDescendants(Long currentId, List<Long> collector) {
+        QueryWrapper<SysEquType> equTypeWrapper = new QueryWrapper<>();
+        equTypeWrapper.lambda().eq(SysEquType::getParentId, currentId);
+
+        List<SysEquTypeVo> children = equTypeMapper.selectVoList(equTypeWrapper);
+        if (children != null && !children.isEmpty()) {
+            for (SysEquTypeVo child : children) {
+                Long childId = child.getEquTypeId();
+                collector.add(childId);
+                collectDescendants(childId, collector);
+            }
+        }
+    }
+    /**
+     * 鏂板銆愯澶囧彴璐︺��
+     *
+     * @param bo 銆愯澶囧彴璐︺��
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(SysEquBo bo) {
+        SysEqu add = MapstructUtils.convert(bo, SysEqu.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setEquId(add.getEquId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼銆愯澶囧彴璐︺��
+     *
+     * @param bo 銆愯澶囧彴璐︺��
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(SysEquBo bo) {
+        SysEqu update = MapstructUtils.convert(bo, SysEqu.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysEqu entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゃ�愯澶囧彴璐︺�戜俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquTypeServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquTypeServiceImpl.java
new file mode 100644
index 0000000..1bb36ab
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/SysEquTypeServiceImpl.java
@@ -0,0 +1,205 @@
+package org.dromara.eims.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.service.EquTypeService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.SysEquTypeBo;
+import org.dromara.eims.domain.vo.SysEquTypeVo;
+import org.dromara.eims.domain.SysEquType;
+import org.dromara.eims.mapper.SysEquTypeMapper;
+import org.dromara.eims.service.ISysEquTypeService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 璁惧绫诲瀷Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-01-06
+ */
+@RequiredArgsConstructor
+@Service
+public class SysEquTypeServiceImpl implements ISysEquTypeService, EquTypeService {
+
+    private final SysEquTypeMapper baseMapper;
+
+    /**
+     * 鏌ヨ璁惧绫诲瀷
+     *
+     * @param equTypeId 涓婚敭
+     * @return 璁惧绫诲瀷
+     */
+    @Override
+    public SysEquTypeVo queryById(Long equTypeId){
+        return baseMapper.selectVoById(equTypeId);
+    }
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勮澶囩被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 璁惧绫诲瀷鍒楄〃
+     */
+    @Override
+    public List<SysEquTypeVo> queryList(SysEquTypeBo bo) {
+        LambdaQueryWrapper<SysEquType> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysEquType> buildQueryWrapper(SysEquTypeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SysEquType> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getTypeName()), SysEquType::getTypeName, bo.getTypeName());
+        lqw.eq(StringUtils.isNotBlank(bo.getTypeCode()), SysEquType::getTypeCode, bo.getTypeCode());
+        lqw.eq(bo.getParentId() != null, SysEquType::getParentId, bo.getParentId());
+        lqw.eq(bo.getOrderNum() != null, SysEquType::getOrderNum, bo.getOrderNum());
+        lqw.eq(StringUtils.isNotBlank(bo.getMenuType()), SysEquType::getMenuType, bo.getMenuType());
+        lqw.eq(StringUtils.isNotBlank(bo.getIcon()), SysEquType::getIcon, bo.getIcon());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysEquType::getStatus, bo.getStatus());
+        return lqw;
+    }
+
+    /**
+     * 鏂板璁惧绫诲瀷
+     *
+     * @param bo 璁惧绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(SysEquTypeBo bo) {
+        SysEquType add = MapstructUtils.convert(bo, SysEquType.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setEquTypeId(add.getEquTypeId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼璁惧绫诲瀷
+     *
+     * @param bo 璁惧绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(SysEquTypeBo bo) {
+        SysEquType update = MapstructUtils.convert(bo, SysEquType.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysEquType entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄よ澶囩被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+    /**
+     * 妫�鏌ヨ澶囩被鍨嬩笅鏄惁瀛樺湪瀛愮被
+     *
+     * @param equTypeId  璁惧绫诲瀷id
+     * @return true false 瀛樺湪瀛愮被鍒欎笉鍏佽鍒犻櫎
+     */
+    @Override
+    public boolean hasChildByEquTypeId(Long equTypeId) {
+        return baseMapper.exists(new LambdaQueryWrapper<SysEquType>().eq(SysEquType::getParentId, equTypeId));
+    }
+    /**
+     * 鑾峰彇璁惧绫诲瀷鏍戝垪琛�
+     *
+     * @param bo
+     * @return 鏍戝垪琛�
+     */
+    @Override
+    public List<Tree<Long>> selectEquTypeTreeList(SysEquTypeBo bo) {
+        // 鍙煡璇㈡湭绂佺敤閮ㄩ棬
+        bo.setStatus(UserConstants.DEPT_NORMAL);
+        LambdaQueryWrapper<SysEquType> lqw = buildQueryWrapper(bo);
+        List<SysEquTypeVo> equTypeVoList = baseMapper.selectVoList(lqw);
+
+        for (int i = 0; i < equTypeVoList.size(); i++) {
+            SysEquTypeVo sysEquTypeVo = equTypeVoList.get(i);
+            if(sysEquTypeVo.getParentId() == null){
+                equTypeVoList.get(i).setParentId(0L);
+            }
+        }
+        //鍔犳牴鐩綍
+        SysEquTypeVo root = new SysEquTypeVo();
+        root.setEquTypeId(0L);
+        root.setMenuType("M");
+        root.setTypeName("鎵�鏈夎澶�");
+        root.setStatus("0");
+        root.setTypeCode("0");
+        root.setOrderNum(0L);
+        root.setIcon("#");
+        equTypeVoList.add(root);
+        equTypeVoList.sort((o1, o2) -> o1.getEquTypeId().compareTo(o2.getEquTypeId()));
+
+
+        return buildEquTypeTreeSelect(equTypeVoList);
+    }
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param equTypeVoList 璁惧绫诲瀷鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    public List<Tree<Long>> buildEquTypeTreeSelect(List<SysEquTypeVo> equTypeVoList) {
+        if (CollUtil.isEmpty(equTypeVoList)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeBuildUtils.build(equTypeVoList, (dept, tree) ->
+            tree.setId(dept.getEquTypeId())
+                .setParentId(dept.getParentId())
+                .setName(dept.getTypeName())
+                .setWeight(dept.getOrderNum()));
+    }
+    /**
+     * 璁惧绫诲瀷id缈昏瘧璁惧绫诲瀷鍚嶇О
+     *
+     * @param equTypeIds 瑕佺炕璇戠殑璁惧绫诲瀷id
+     * @return 璁惧绫诲瀷鍚嶇О
+     */
+    @Override
+    public String selectEquTypeNameByIds(String equTypeIds) {
+        List<String> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(equTypeIds, Convert::toLong)) {
+            SysEquTypeVo vo = SpringUtils.getAopProxy(this).queryById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                list.add(vo.getTypeName());
+            }
+        }
+        return String.join(StringUtils.SEPARATOR, list);
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/.DS_Store b/eims/ruoyi-modules/lb-eims/src/main/resources/.DS_Store
new file mode 100644
index 0000000..47bf4e4
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/.DS_Store b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/.DS_Store
new file mode 100644
index 0000000..ef897b5
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/.DS_Store
Binary files differ
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquMapper.xml
new file mode 100644
index 0000000..11602a9
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.SysEquMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquTypeMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquTypeMapper.xml
new file mode 100644
index 0000000..d8edc89
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/SysEquTypeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.SysEquTypeMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/pom.xml b/eims/ruoyi-modules/pom.xml
new file mode 100644
index 0000000..510491d
--- /dev/null
+++ b/eims/ruoyi-modules/pom.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi-vue-plus</artifactId>
+        <groupId>org.dromara</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <modules>
+        <module>ruoyi-demo</module>
+        <module>ruoyi-generator</module>
+        <module>ruoyi-job</module>
+        <module>ruoyi-system</module>
+        <module>ruoyi-workflow</module>
+        <module>lb-eims</module>
+    </modules>
+
+    <artifactId>ruoyi-modules</artifactId>
+    <packaging>pom</packaging>
+
+    <description>
+        ruoyi-modules 涓氬姟妯″潡
+    </description>
+
+</project>
diff --git a/eims/ruoyi-modules/ruoyi-demo/pom.xml b/eims/ruoyi-modules/ruoyi-demo/pom.xml
new file mode 100644
index 0000000..119fe61
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-demo</artifactId>
+
+    <description>
+        demo妯″潡
+    </description>
+
+    <dependencies>
+
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sms</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mail</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-excel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-ratelimiter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sensitive</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-encrypt</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-websocket</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java
new file mode 100644
index 0000000..47b4349
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailController.java
@@ -0,0 +1,52 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mail.utils.MailUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+
+
+/**
+ * 閭欢鍙戦�佹渚�
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/mail")
+public class MailController {
+
+    /**
+     * 鍙戦�侀偖浠�
+     *
+     * @param to      鎺ユ敹浜�
+     * @param subject 鏍囬
+     * @param text    鍐呭
+     */
+    @GetMapping("/sendSimpleMessage")
+    public R<Void> sendSimpleMessage(String to, String subject, String text) {
+        MailUtils.sendText(to, subject, text);
+        return R.ok();
+    }
+
+    /**
+     * 鍙戦�侀偖浠讹紙甯﹂檮浠讹級
+     *
+     * @param to       鎺ユ敹浜�
+     * @param subject  鏍囬
+     * @param text     鍐呭
+     * @param filePath 闄勪欢璺緞
+     */
+    @GetMapping("/sendMessageWithAttachment")
+    public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
+        MailUtils.sendText(to, subject, text, new File(filePath));
+        return R.ok();
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
new file mode 100644
index 0000000..341880c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
@@ -0,0 +1,95 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.RedisUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.Duration;
+
+/**
+ * spring-cache 婕旂ず妗堜緥
+ *
+ * @author Lion Li
+ */
+// 绫荤骇鍒� 缂撳瓨缁熶竴閰嶇疆
+//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE)
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/cache")
+public class RedisCacheController {
+
+    /**
+     * 娴嬭瘯 @Cacheable
+     * <p>
+     * 琛ㄧず杩欎釜鏂规硶鏈変簡缂撳瓨鐨勫姛鑳�,鏂规硶鐨勮繑鍥炲�间細琚紦瀛樹笅鏉�
+     * 涓嬩竴娆¤皟鐢ㄨ鏂规硶鍓�,浼氬幓妫�鏌ユ槸鍚︾紦瀛樹腑宸茬粡鏈夊��
+     * 濡傛灉鏈夊氨鐩存帴杩斿洖,涓嶈皟鐢ㄦ柟娉�
+     * 濡傛灉娌℃湁,灏辫皟鐢ㄦ柟娉�,鐒跺悗鎶婄粨鏋滅紦瀛樿捣鏉�
+     * 杩欎釜娉ㄨВ銆屼竴鑸敤鍦ㄦ煡璇㈡柟娉曚笂銆�
+     * <p>
+     * 閲嶇偣璇存槑: 缂撳瓨娉ㄨВ涓ヨ皑涓庡叾浠栫瓫閫夋暟鎹姛鑳戒竴璧蜂娇鐢�
+     * 渚嬪: 鏁版嵁鏉冮檺娉ㄨВ 浼氶�犳垚 缂撳瓨鍑荤┛ 涓� 鏁版嵁涓嶄竴鑷撮棶棰�
+     * <p>
+     * cacheNames 鍛藉悕瑙勫垯 鏌ョ湅 {@link CacheNames} 娉ㄩ噴 鏀寔澶氬弬鏁�
+     */
+    @Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
+    @GetMapping("/test1")
+    public R<String> test1(String key, String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯 @CachePut
+     * <p>
+     * 鍔犱簡@CachePut娉ㄨВ鐨勬柟娉�,浼氭妸鏂规硶鐨勮繑鍥炲�紁ut鍒扮紦瀛橀噷闈㈢紦瀛樿捣鏉�,渚涘叾瀹冨湴鏂逛娇鐢�
+     * 瀹冦�岄�氬父鐢ㄥ湪鏂板鎴栬�呭疄鏃舵洿鏂版柟娉曚笂銆�
+     * <p>
+     * cacheNames 鍛藉悕瑙勫垯 鏌ョ湅 {@link CacheNames} 娉ㄩ噴 鏀寔澶氬弬鏁�
+     */
+    @CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
+    @GetMapping("/test2")
+    public R<String> test2(String key, String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯 @CacheEvict
+     * <p>
+     * 浣跨敤浜咰acheEvict娉ㄨВ鐨勬柟娉�,浼氭竻绌烘寚瀹氱紦瀛�
+     * 銆屼竴鑸敤鍦ㄥ垹闄ょ殑鏂规硶涓娿��
+     * <p>
+     * cacheNames 鍛藉悕瑙勫垯 鏌ョ湅 {@link CacheNames} 娉ㄩ噴 鏀寔澶氬弬鏁�
+     */
+    @CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null")
+    @GetMapping("/test3")
+    public R<String> test3(String key, String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯璁剧疆杩囨湡鏃堕棿
+     * 鎵嬪姩璁剧疆杩囨湡鏃堕棿10绉�
+     * 11绉掑悗鑾峰彇 鍒ゆ柇鏄惁鐩哥瓑
+     */
+    @GetMapping("/test6")
+    public R<Boolean> test6(String key, String value) {
+        RedisUtils.setCacheObject(key, value);
+        boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
+        System.out.println("***********" + flag);
+        try {
+            Thread.sleep(11 * 1000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        Object obj = RedisUtils.getCacheObject(key);
+        return R.ok(value.equals(obj));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
new file mode 100644
index 0000000..b7e0962
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
@@ -0,0 +1,71 @@
+package org.dromara.demo.controller;
+
+import com.baomidou.lock.LockInfo;
+import com.baomidou.lock.LockTemplate;
+import com.baomidou.lock.annotation.Lock4j;
+import com.baomidou.lock.executor.RedissonLockExecutor;
+import org.dromara.common.core.domain.R;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalTime;
+
+
+/**
+ * 娴嬭瘯鍒嗗竷寮忛攣鐨勬牱渚�
+ *
+ * @author shenxinquan
+ */
+@Slf4j
+@RestController
+@RequestMapping("/demo/redisLock")
+public class RedisLockController {
+
+    @Autowired
+    private LockTemplate lockTemplate;
+
+    /**
+     * 娴嬭瘯lock4j 娉ㄨВ
+     */
+    @Lock4j(keys = {"#key"})
+    @GetMapping("/testLock4j")
+    public R<String> testLock4j(String key, String value) {
+        System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
+        try {
+            Thread.sleep(10000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯lock4j 宸ュ叿
+     */
+    @GetMapping("/testLock4jLockTemplate")
+    public R<String> testLock4jLockTemplate(String key, String value) {
+        final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
+        if (null == lockInfo) {
+            throw new RuntimeException("涓氬姟澶勭悊涓�,璇风◢鍚庡啀璇�");
+        }
+        // 鑾峰彇閿佹垚鍔燂紝澶勭悊涓氬姟
+        try {
+            try {
+                Thread.sleep(8000);
+            } catch (InterruptedException e) {
+                //
+            }
+            System.out.println("鎵ц绠�鍗曟柟娉�1 , 褰撳墠绾跨▼:" + Thread.currentThread().getName());
+        } finally {
+            //閲婃斁閿�
+            lockTemplate.releaseLock(lockInfo);
+        }
+        //缁撴潫
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java
new file mode 100644
index 0000000..bdbf033
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java
@@ -0,0 +1,47 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.RedisUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Redis 鍙戝竷璁㈤槄 婕旂ず妗堜緥
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/redis/pubsub")
+public class RedisPubSubController {
+
+    /**
+     * 鍙戝竷娑堟伅
+     *
+     * @param key   閫氶亾Key
+     * @param value 鍙戦�佸唴瀹�
+     */
+    @GetMapping("/pub")
+    public R<Void> pub(String key, String value) {
+        RedisUtils.publish(key, value, consumer -> {
+            System.out.println("鍙戝竷閫氶亾 => " + key + ", 鍙戦�佸�� => " + value);
+        });
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 璁㈤槄娑堟伅
+     *
+     * @param key 閫氶亾Key
+     */
+    @GetMapping("/sub")
+    public R<Void> sub(String key) {
+        RedisUtils.subscribe(key, String.class, msg -> {
+            System.out.println("璁㈤槄閫氶亾 => " + key + ", 鎺ユ敹鍊� => " + msg);
+        });
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisRateLimiterController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisRateLimiterController.java
new file mode 100644
index 0000000..f8adf7d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisRateLimiterController.java
@@ -0,0 +1,64 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.ratelimiter.enums.LimitType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 娴嬭瘯鍒嗗竷寮忛檺娴佹牱渚�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RestController
+@RequestMapping("/demo/rateLimiter")
+public class RedisRateLimiterController {
+
+    /**
+     * 娴嬭瘯鍏ㄥ眬闄愭祦
+     * 鍏ㄥ眬褰卞搷
+     */
+    @RateLimiter(count = 2, time = 10)
+    @GetMapping("/test")
+    public R<String> test(String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯璇锋眰IP闄愭祦
+     * 鍚屼竴IP璇锋眰鍙楀奖鍝�
+     */
+    @RateLimiter(count = 2, time = 10, limitType = LimitType.IP)
+    @GetMapping("/testip")
+    public R<String> testip(String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯闆嗙兢瀹炰緥闄愭祦
+     * 鍚姩涓や釜鍚庣鏈嶅姟浜掍笉褰卞搷
+     */
+    @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER)
+    @GetMapping("/testcluster")
+    public R<String> testcluster(String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+    /**
+     * 娴嬭瘯璇锋眰IP闄愭祦(key鍩轰簬鍙傛暟鑾峰彇)
+     * 鍚屼竴IP璇锋眰鍙楀奖鍝�
+     *
+     * 绠�鍗曞彉閲忚幏鍙� #鍙橀噺 澶嶆潅琛ㄨ揪寮� #{#鍙橀噺 != 1 ? 1 : 0}
+     */
+    @RateLimiter(count = 2, time = 10, limitType = LimitType.IP, key = "#value")
+    @GetMapping("/testObj")
+    public R<String> testObj(String value) {
+        return R.ok("鎿嶄綔鎴愬姛", value);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java
new file mode 100644
index 0000000..b993f60
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java
@@ -0,0 +1,82 @@
+package org.dromara.demo.controller;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.LinkedHashMap;
+
+/**
+ * 鐭俊婕旂ず妗堜緥
+ * 璇峰厛闃呰鏂囨。 鍚﹀垯鏃犳硶浣跨敤
+ *
+ * @author Lion Li
+ * @version 4.2.0
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/sms")
+public class SmsController {
+    /**
+     * 鍙戦�佺煭淇liyun
+     *
+     * @param phones     鐢佃瘽鍙�
+     * @param templateId 妯℃澘ID
+     */
+    @GetMapping("/sendAliyun")
+    public R<Object> sendAliyun(String phones, String templateId) {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
+        map.put("code", "1234");
+        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
+        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
+        return R.ok(smsResponse);
+    }
+
+    /**
+     * 鍙戦�佺煭淇encent
+     *
+     * @param phones     鐢佃瘽鍙�
+     * @param templateId 妯℃澘ID
+     */
+    @GetMapping("/sendTencent")
+    public R<Object> sendTencent(String phones, String templateId) {
+        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
+//        map.put("2", "娴嬭瘯娴嬭瘯");
+        map.put("1", "1234");
+        SmsBlend smsBlend = SmsFactory.getSmsBlend("config2");
+        SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map);
+        return R.ok(smsResponse);
+    }
+
+    /**
+     * 娣诲姞榛戝悕鍗�
+     *
+     * @param phone 鎵嬫満鍙�
+     */
+    @GetMapping("/addBlacklist")
+    public R<Object> addBlacklist(String phone){
+        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
+        smsBlend.joinInBlacklist(phone);
+        return R.ok();
+    }
+
+    /**
+     * 绉婚櫎榛戝悕鍗�
+     *
+     * @param phone 鎵嬫満鍙�
+     */
+    @GetMapping("/removeBlacklist")
+    public R<Object> removeBlacklist(String phone){
+        SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
+        smsBlend.removeFromBlacklist(phone);
+        return R.ok();
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/Swagger3DemoController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/Swagger3DemoController.java
new file mode 100644
index 0000000..bb02f98
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/Swagger3DemoController.java
@@ -0,0 +1,31 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * swagger3 鐢ㄦ硶绀轰緥
+ *
+ * @author Lion Li
+ */
+@RestController
+@RequestMapping("/swagger/demo")
+public class Swagger3DemoController {
+
+    /**
+     * 涓婁紶璇锋眰
+     * 蹇呴』浣跨敤 @RequestPart 娉ㄨВ鏍囨敞涓烘枃浠�
+     *
+     * @param file 鏂囦欢
+     */
+    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<String> upload(@RequestPart("file") MultipartFile file) {
+        return R.ok("鎿嶄綔鎴愬姛", file.getOriginalFilename());
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestBatchController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestBatchController.java
new file mode 100644
index 0000000..af8c77b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestBatchController.java
@@ -0,0 +1,90 @@
+package org.dromara.demo.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.demo.domain.TestDemo;
+import org.dromara.demo.mapper.TestDemoMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 娴嬭瘯鎵归噺鏂规硶
+ *
+ * @author Lion Li
+ * @date 2021-05-30
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/batch")
+public class TestBatchController extends BaseController {
+
+    /**
+     * 涓轰簡渚夸簬娴嬭瘯 鐩存帴寮曞叆mapper
+     */
+    private final TestDemoMapper testDemoMapper;
+
+    /**
+     * 鏂板鎵归噺鏂规硶 鍙畬缇庢浛浠� saveBatch 绉掔骇鎻掑叆涓婁竾鏁版嵁 (瀵筸ysql璐熻嵎杈冨ぇ)
+     * <p>
+     * 3.5.0 鐗堟湰 澧炲姞 rewriteBatchedStatements=true 鎵瑰鐞嗗弬鏁� 浣� MP 鍘熺敓鎵瑰鐞嗗彲浠ヨ揪鍒板悓鏍风殑閫熷害
+     */
+    @PostMapping("/add")
+//    @DS("slave")
+    public R<Void> add() {
+        List<TestDemo> list = new ArrayList<>();
+        for (int i = 0; i < 1000; i++) {
+            TestDemo testDemo = new TestDemo();
+            testDemo.setOrderNum(-1);
+            testDemo.setTestKey("鎵归噺鏂板");
+            testDemo.setValue("娴嬭瘯鏂板");
+            list.add(testDemo);
+        }
+        return toAjax(testDemoMapper.insertBatch(list));
+    }
+
+    /**
+     * 鏂板鎴栨洿鏂� 鍙畬缇庢浛浠� saveOrUpdateBatch 楂樻�ц兘
+     * <p>
+     * 3.5.0 鐗堟湰 澧炲姞 rewriteBatchedStatements=true 鎵瑰鐞嗗弬鏁� 浣� MP 鍘熺敓鎵瑰鐞嗗彲浠ヨ揪鍒板悓鏍风殑閫熷害
+     */
+    @PostMapping("/addOrUpdate")
+//    @DS("slave")
+    public R<Void> addOrUpdate() {
+        List<TestDemo> list = new ArrayList<>();
+        for (int i = 0; i < 1000; i++) {
+            TestDemo testDemo = new TestDemo();
+            testDemo.setOrderNum(-1);
+            testDemo.setTestKey("鎵归噺鏂板");
+            testDemo.setValue("娴嬭瘯鏂板");
+            list.add(testDemo);
+        }
+        testDemoMapper.insertBatch(list);
+        for (int i = 0; i < list.size(); i++) {
+            TestDemo testDemo = list.get(i);
+            testDemo.setTestKey("鎵归噺鏂板鎴栦慨鏀�");
+            testDemo.setValue("鎵归噺鏂板鎴栦慨鏀�");
+            if (i % 2 == 0) {
+                testDemo.setId(null);
+            }
+        }
+        return toAjax(testDemoMapper.insertOrUpdateBatch(list));
+    }
+
+    /**
+     * 鍒犻櫎鎵归噺鏂规硶
+     */
+    @DeleteMapping()
+//    @DS("slave")
+    public R<Void> remove() {
+        return toAjax(testDemoMapper.delete(new LambdaQueryWrapper<TestDemo>()
+            .eq(TestDemo::getOrderNum, -1L)));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java
new file mode 100644
index 0000000..f31c540
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java
@@ -0,0 +1,147 @@
+package org.dromara.demo.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.demo.domain.TestDemo;
+import org.dromara.demo.domain.bo.TestDemoBo;
+import org.dromara.demo.domain.bo.TestDemoImportVo;
+import org.dromara.demo.domain.vo.TestDemoVo;
+import org.dromara.demo.service.ITestDemoService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 娴嬭瘯鍗曡〃Controller
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/demo")
+public class TestDemoController extends BaseController {
+
+    private final ITestDemoService testDemoService;
+
+    /**
+     * 鏌ヨ娴嬭瘯鍗曡〃鍒楄〃
+     */
+    @SaCheckPermission("demo:demo:list")
+    @GetMapping("/list")
+    public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
+        return testDemoService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 鑷畾涔夊垎椤垫煡璇�
+     */
+    @SaCheckPermission("demo:demo:list")
+    @GetMapping("/page")
+    public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) {
+        return testDemoService.customPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎叆鏁版嵁
+     *
+     * @param file 瀵煎叆鏂囦欢
+     */
+    @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.IMPORT)
+    @SaCheckPermission("demo:demo:import")
+    @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception {
+        ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true);
+        List<TestDemo> list = MapstructUtils.convert(excelResult.getList(), TestDemo.class);
+        testDemoService.saveBatch(list);
+        return R.ok(excelResult.getAnalysis());
+    }
+
+    /**
+     * 瀵煎嚭娴嬭瘯鍗曡〃鍒楄〃
+     */
+    @SaCheckPermission("demo:demo:export")
+    @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(@Validated TestDemoBo bo, HttpServletResponse response) {
+        List<TestDemoVo> list = testDemoService.queryList(bo);
+        // 娴嬭瘯闆姳id瀵煎嚭
+//        for (TestDemoVo vo : list) {
+//            vo.setId(1234567891234567893L);
+//        }
+        ExcelUtil.exportExcel(list, "娴嬭瘯鍗曡〃", TestDemoVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇娴嬭瘯鍗曡〃璇︾粏淇℃伅
+     *
+     * @param id 娴嬭瘯ID
+     */
+    @SaCheckPermission("demo:demo:query")
+    @GetMapping("/{id}")
+    public R<TestDemoVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                 @PathVariable("id") Long id) {
+        return R.ok(testDemoService.queryById(id));
+    }
+
+    /**
+     * 鏂板娴嬭瘯鍗曡〃
+     */
+    @SaCheckPermission("demo:demo:add")
+    @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.INSERT)
+    @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
+    @PostMapping()
+    public R<Void> add(@RequestBody TestDemoBo bo) {
+        // 浣跨敤鏍¢獙宸ュ叿瀵规爣 @Validated(AddGroup.class) 娉ㄨВ
+        // 鐢ㄤ簬鍦ㄩ潪 Controller 鐨勫湴鏂规牎楠屽璞�
+        ValidatorUtils.validate(bo, AddGroup.class);
+        return toAjax(testDemoService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼娴嬭瘯鍗曡〃
+     */
+    @SaCheckPermission("demo:demo:edit")
+    @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) {
+        return toAjax(testDemoService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎娴嬭瘯鍗曡〃
+     *
+     * @param ids 娴嬭瘯ID涓�
+     */
+    @SaCheckPermission("demo:demo:remove")
+    @Log(title = "娴嬭瘯鍗曡〃", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(testDemoService.deleteWithValidByIds(Arrays.asList(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestEncryptController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestEncryptController.java
new file mode 100644
index 0000000..2b6886d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestEncryptController.java
@@ -0,0 +1,55 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.demo.domain.TestDemoEncrypt;
+import org.dromara.demo.mapper.TestDemoEncryptMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * 娴嬭瘯鏁版嵁搴撳姞瑙e瘑鍔熻兘
+ *
+ * @author Lion Li
+ */
+@Validated
+@RestController
+@RequestMapping("/demo/encrypt")
+public class TestEncryptController {
+
+    @Autowired
+    private TestDemoEncryptMapper mapper;
+    @Value("${mybatis-encryptor.enable}")
+    private Boolean encryptEnable;
+
+    /**
+     * 娴嬭瘯鏁版嵁搴撳姞瑙e瘑
+     *
+     * @param key   娴嬭瘯key
+     * @param value 娴嬭瘯value
+     */
+    @GetMapping()
+    public R<Map<String, TestDemoEncrypt>> test(String key, String value) {
+        if (!encryptEnable) {
+            throw new RuntimeException("鍔犲瘑鍔熻兘鏈紑鍚�!");
+        }
+        Map<String, TestDemoEncrypt> map = new HashMap<>(2);
+        TestDemoEncrypt demo = new TestDemoEncrypt();
+        demo.setTestKey(key);
+        demo.setValue(value);
+        mapper.insert(demo);
+        map.put("鍔犲瘑", demo);
+        TestDemoEncrypt testDemo = mapper.selectById(demo.getId());
+        map.put("瑙e瘑", testDemo);
+        return R.ok(map);
+    }
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java
new file mode 100644
index 0000000..3fd124c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java
@@ -0,0 +1,160 @@
+package org.dromara.demo.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.demo.domain.vo.ExportDemoVo;
+import org.dromara.demo.listener.ExportDemoListener;
+import org.dromara.demo.service.IExportExcelService;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴嬭瘯Excel鍔熻兘
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/excel")
+public class TestExcelController {
+
+    private final IExportExcelService exportExcelService;
+
+    /**
+     * 鍗曞垪琛ㄥ鏁版嵁
+     */
+    @GetMapping("/exportTemplateOne")
+    public void exportTemplateOne(HttpServletResponse response) {
+        Map<String, String> map = new HashMap<>();
+        map.put("title", "鍗曞垪琛ㄥ鏁版嵁");
+        map.put("test1", "鏁版嵁娴嬭瘯1");
+        map.put("test2", "鏁版嵁娴嬭瘯2");
+        map.put("test3", "鏁版嵁娴嬭瘯3");
+        map.put("test4", "鏁版嵁娴嬭瘯4");
+        map.put("testTest", "666");
+        List<TestObj> list = new ArrayList<>();
+        list.add(new TestObj("鍗曞垪琛ㄦ祴璇�1", "鍒楄〃娴嬭瘯1", "鍒楄〃娴嬭瘯2", "鍒楄〃娴嬭瘯3", "鍒楄〃娴嬭瘯4"));
+        list.add(new TestObj("鍗曞垪琛ㄦ祴璇�2", "鍒楄〃娴嬭瘯5", "鍒楄〃娴嬭瘯6", "鍒楄〃娴嬭瘯7", "鍒楄〃娴嬭瘯8"));
+        list.add(new TestObj("鍗曞垪琛ㄦ祴璇�3", "鍒楄〃娴嬭瘯9", "鍒楄〃娴嬭瘯10", "鍒楄〃娴嬭瘯11", "鍒楄〃娴嬭瘯12"));
+        ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "鍗曞垪琛�.xlsx", "excel/鍗曞垪琛�.xlsx", response);
+    }
+
+    /**
+     * 澶氬垪琛ㄥ鏁版嵁
+     */
+    @GetMapping("/exportTemplateMuliti")
+    public void exportTemplateMuliti(HttpServletResponse response) {
+        Map<String, String> map = new HashMap<>();
+        map.put("title1", "鏍囬1");
+        map.put("title2", "鏍囬2");
+        map.put("title3", "鏍囬3");
+        map.put("title4", "鏍囬4");
+        map.put("author", "Lion Li");
+        List<TestObj1> list1 = new ArrayList<>();
+        list1.add(new TestObj1("list1娴嬭瘯1", "list1娴嬭瘯2", "list1娴嬭瘯3"));
+        list1.add(new TestObj1("list1娴嬭瘯4", "list1娴嬭瘯5", "list1娴嬭瘯6"));
+        list1.add(new TestObj1("list1娴嬭瘯7", "list1娴嬭瘯8", "list1娴嬭瘯9"));
+        List<TestObj1> list2 = new ArrayList<>();
+        list2.add(new TestObj1("list2娴嬭瘯1", "list2娴嬭瘯2", "list2娴嬭瘯3"));
+        list2.add(new TestObj1("list2娴嬭瘯4", "list2娴嬭瘯5", "list2娴嬭瘯6"));
+        List<TestObj1> list3 = new ArrayList<>();
+        list3.add(new TestObj1("list3娴嬭瘯1", "list3娴嬭瘯2", "list3娴嬭瘯3"));
+        List<TestObj1> list4 = new ArrayList<>();
+        list4.add(new TestObj1("list4娴嬭瘯1", "list4娴嬭瘯2", "list4娴嬭瘯3"));
+        list4.add(new TestObj1("list4娴嬭瘯4", "list4娴嬭瘯5", "list4娴嬭瘯6"));
+        list4.add(new TestObj1("list4娴嬭瘯7", "list4娴嬭瘯8", "list4娴嬭瘯9"));
+        list4.add(new TestObj1("list4娴嬭瘯10", "list4娴嬭瘯11", "list4娴嬭瘯12"));
+        Map<String, Object> multiListMap = new HashMap<>();
+        multiListMap.put("map", map);
+        multiListMap.put("data1", list1);
+        multiListMap.put("data2", list2);
+        multiListMap.put("data3", list3);
+        multiListMap.put("data4", list4);
+        ExcelUtil.exportTemplateMultiList(multiListMap, "澶氬垪琛�.xlsx", "excel/澶氬垪琛�.xlsx", response);
+    }
+
+    /**
+     * 瀵煎嚭涓嬫媺妗�
+     *
+     * @param response /
+     */
+    @GetMapping("/exportWithOptions")
+    public void exportWithOptions(HttpServletResponse response) {
+        exportExcelService.exportWithOptions(response);
+    }
+
+    /**
+     * 澶氫釜sheet瀵煎嚭
+     */
+    @GetMapping("/exportTemplateMultiSheet")
+    public void exportTemplateMultiSheet(HttpServletResponse response) {
+        List<TestObj1> list1 = new ArrayList<>();
+        list1.add(new TestObj1("list1娴嬭瘯1", "list1娴嬭瘯2", "list1娴嬭瘯3"));
+        list1.add(new TestObj1("list1娴嬭瘯4", "list1娴嬭瘯5", "list1娴嬭瘯6"));
+        List<TestObj1> list2 = new ArrayList<>();
+        list2.add(new TestObj1("list2娴嬭瘯1", "list2娴嬭瘯2", "list2娴嬭瘯3"));
+        list2.add(new TestObj1("list2娴嬭瘯4", "list2娴嬭瘯5", "list2娴嬭瘯6"));
+        List<TestObj1> list3 = new ArrayList<>();
+        list3.add(new TestObj1("list3娴嬭瘯1", "list3娴嬭瘯2", "list3娴嬭瘯3"));
+        list3.add(new TestObj1("list3娴嬭瘯4", "list3娴嬭瘯5", "list3娴嬭瘯6"));
+        List<TestObj1> list4 = new ArrayList<>();
+        list4.add(new TestObj1("list4娴嬭瘯1", "list4娴嬭瘯2", "list4娴嬭瘯3"));
+        list4.add(new TestObj1("list4娴嬭瘯4", "list4娴嬭瘯5", "list4娴嬭瘯6"));
+
+        List<Map<String, Object>> list = new ArrayList<>();
+        Map<String, Object> sheetMap1 = new HashMap<>();
+        sheetMap1.put("data1", list1);
+        Map<String, Object> sheetMap2 = new HashMap<>();
+        sheetMap2.put("data2", list2);
+        Map<String, Object> sheetMap3 = new HashMap<>();
+        sheetMap3.put("data3", list3);
+        Map<String, Object> sheetMap4 = new HashMap<>();
+        sheetMap4.put("data4", list4);
+
+        list.add(sheetMap1);
+        list.add(sheetMap2);
+        list.add(sheetMap3);
+        list.add(sheetMap4);
+        ExcelUtil.exportTemplateMultiSheet(list, "澶歴heet鍒楄〃", "excel/澶歴heet鍒楄〃.xlsx", response);
+    }
+
+    /**
+     * 瀵煎叆琛ㄦ牸
+     */
+    @PostMapping(value = "/importWithOptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public List<ExportDemoVo> importWithOptions(@RequestPart("file") MultipartFile file) throws Exception {
+        // 澶勭悊瑙f瀽缁撴灉
+        ExcelResult<ExportDemoVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), ExportDemoVo.class, new ExportDemoListener());
+        return excelResult.getList();
+    }
+
+    @Data
+    @AllArgsConstructor
+    static class TestObj1 {
+        private String test1;
+        private String test2;
+        private String test3;
+    }
+
+    @Data
+    @AllArgsConstructor
+    static class TestObj {
+        private String name;
+        private String list1;
+        private String list2;
+        private String list3;
+        private String list4;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestI18nController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestI18nController.java
new file mode 100644
index 0000000..40393c5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestI18nController.java
@@ -0,0 +1,71 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.MessageUtils;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+
+/**
+ * 娴嬭瘯鍥介檯鍖�
+ *
+ * @author Lion Li
+ */
+@Validated
+@RestController
+@RequestMapping("/demo/i18n")
+public class TestI18nController {
+
+    /**
+     * 閫氳繃code鑾峰彇鍥介檯鍖栧唴瀹�
+     * code涓� messages.properties 涓殑 key
+     * <p>
+     * 娴嬭瘯浣跨敤 user.register.success
+     *
+     * @param code 鍥介檯鍖朿ode
+     */
+    @GetMapping()
+    public R<Void> get(String code) {
+        return R.ok(MessageUtils.message(code));
+    }
+
+    /**
+     * Validator 鏍¢獙鍥介檯鍖�
+     * 涓嶄紶鍊� 鍒嗗埆鏌ョ湅寮傚父杩斿洖
+     * <p>
+     * 娴嬭瘯浣跨敤 not.null
+     */
+    @GetMapping("/test1")
+    public R<Void> test1(@NotBlank(message = "{not.null}") String str) {
+        return R.ok(str);
+    }
+
+    /**
+     * Bean 鏍¢獙鍥介檯鍖�
+     * 涓嶄紶鍊� 鍒嗗埆鏌ョ湅寮傚父杩斿洖
+     * <p>
+     * 娴嬭瘯浣跨敤 not.null
+     */
+    @GetMapping("/test2")
+    public R<TestI18nBo> test2(@Validated TestI18nBo bo) {
+        return R.ok(bo);
+    }
+
+    @Data
+    public static class TestI18nBo {
+
+        @NotBlank(message = "{not.null}")
+        private String name;
+
+        @NotNull(message = "{not.null}")
+        @Range(min = 0, max = 100, message = "{length.not.valid}")
+        private Integer age;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestSensitiveController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestSensitiveController.java
new file mode 100644
index 0000000..eba0552
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestSensitiveController.java
@@ -0,0 +1,76 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+import lombok.Data;
+import org.dromara.common.sensitive.core.SensitiveService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 娴嬭瘯鏁版嵁鑴辨晱鎺у埗鍣�
+ * <p>
+ * 榛樿绠$悊鍛樹笉杩囨护
+ * 闇�鑷鏍规嵁涓氬姟閲嶅啓瀹炵幇
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ * @see SensitiveService
+ */
+@RestController
+@RequestMapping("/demo/sensitive")
+public class TestSensitiveController extends BaseController {
+
+    /**
+     * 娴嬭瘯鏁版嵁鑴辨晱
+     */
+    @GetMapping("/test")
+    public R<TestSensitive> test() {
+        TestSensitive testSensitive = new TestSensitive();
+        testSensitive.setIdCard("210397198608215431");
+        testSensitive.setPhone("17640125371");
+        testSensitive.setAddress("鍖椾含甯傛湞闃冲尯鏌愭煇鍥涘悎闄�1203瀹�");
+        testSensitive.setEmail("17640125371@163.com");
+        testSensitive.setBankCard("6226456952351452853");
+        return R.ok(testSensitive);
+    }
+
+    @Data
+    static class TestSensitive {
+
+        /**
+         * 韬唤璇�
+         */
+        @Sensitive(strategy = SensitiveStrategy.ID_CARD)
+        private String idCard;
+
+        /**
+         * 鐢佃瘽
+         */
+        @Sensitive(strategy = SensitiveStrategy.PHONE, roleKey = "common")
+        private String phone;
+
+        /**
+         * 鍦板潃
+         */
+        @Sensitive(strategy = SensitiveStrategy.ADDRESS, perms = "system:user:query")
+        private String address;
+
+        /**
+         * 閭
+         */
+        @Sensitive(strategy = SensitiveStrategy.EMAIL, roleKey = "common", perms = "system:user:query1")
+        private String email;
+
+        /**
+         * 閾惰鍗�
+         */
+        @Sensitive(strategy = SensitiveStrategy.BANK_CARD, roleKey = "common1", perms = "system:user:query")
+        private String bankCard;
+
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java
new file mode 100644
index 0000000..5c55205
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java
@@ -0,0 +1,107 @@
+package org.dromara.demo.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.demo.domain.bo.TestTreeBo;
+import org.dromara.demo.domain.vo.TestTreeVo;
+import org.dromara.demo.service.ITestTreeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 娴嬭瘯鏍戣〃Controller
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/tree")
+public class TestTreeController extends BaseController {
+
+    private final ITestTreeService testTreeService;
+
+    /**
+     * 鏌ヨ娴嬭瘯鏍戣〃鍒楄〃
+     */
+    @SaCheckPermission("demo:tree:list")
+    @GetMapping("/list")
+    public R<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) {
+        List<TestTreeVo> list = testTreeService.queryList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 瀵煎嚭娴嬭瘯鏍戣〃鍒楄〃
+     */
+    @SaCheckPermission("demo:tree:export")
+    @Log(title = "娴嬭瘯鏍戣〃", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public void export(@Validated TestTreeBo bo, HttpServletResponse response) {
+        List<TestTreeVo> list = testTreeService.queryList(bo);
+        ExcelUtil.exportExcel(list, "娴嬭瘯鏍戣〃", TestTreeVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇娴嬭瘯鏍戣〃璇︾粏淇℃伅
+     *
+     * @param id 娴嬭瘯鏍慖D
+     */
+    @SaCheckPermission("demo:tree:query")
+    @GetMapping("/{id}")
+    public R<TestTreeVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                 @PathVariable("id") Long id) {
+        return R.ok(testTreeService.queryById(id));
+    }
+
+    /**
+     * 鏂板娴嬭瘯鏍戣〃
+     */
+    @SaCheckPermission("demo:tree:add")
+    @Log(title = "娴嬭瘯鏍戣〃", businessType = BusinessType.INSERT)
+    @RepeatSubmit
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) {
+        return toAjax(testTreeService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼娴嬭瘯鏍戣〃
+     */
+    @SaCheckPermission("demo:tree:edit")
+    @Log(title = "娴嬭瘯鏍戣〃", businessType = BusinessType.UPDATE)
+    @RepeatSubmit
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) {
+        return toAjax(testTreeService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎娴嬭瘯鏍戣〃
+     *
+     * @param ids 娴嬭瘯鏍慖D涓�
+     */
+    @SaCheckPermission("demo:tree:remove")
+    @Log(title = "娴嬭瘯鏍戣〃", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(testTreeService.deleteWithValidByIds(Arrays.asList(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/WeSocketController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/WeSocketController.java
new file mode 100644
index 0000000..699a5e6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/WeSocketController.java
@@ -0,0 +1,33 @@
+package org.dromara.demo.controller;
+
+import org.dromara.common.core.domain.R;
+import org.dromara.common.websocket.dto.WebSocketMessageDto;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * WebSocket 婕旂ず妗堜緥
+ *
+ * @author zendwang
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/websocket")
+@Slf4j
+public class WeSocketController {
+
+    /**
+     * 鍙戝竷娑堟伅
+     *
+     * @param dto 鍙戦�佸唴瀹�
+     */
+    @GetMapping("/send")
+    public R<Void> send(WebSocketMessageDto dto) throws InterruptedException {
+        WebSocketUtils.publishMessage(dto);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java
new file mode 100644
index 0000000..16c30f8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java
@@ -0,0 +1 @@
+package org.dromara.demo.controller;
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/BoundedQueueController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/BoundedQueueController.java
new file mode 100644
index 0000000..30ec27f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/BoundedQueueController.java
@@ -0,0 +1,92 @@
+package org.dromara.demo.controller.queue;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.QueueUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RBoundedBlockingQueue;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 鏈夌晫闃熷垪 婕旂ず妗堜緥
+ * <p>
+ * 杞婚噺绾ч槦鍒� 閲嶉噺绾ф暟鎹噺 璇蜂娇鐢� MQ
+ * <p>
+ * 闆嗙兢娴嬭瘯閫氳繃 鍚屼竴涓暟鎹彧浼氳娑堣垂涓�娆� 鍋氬ソ浜嬪姟琛ュ伩
+ * 闆嗙兢娴嬭瘯娴佺▼ 鍦ㄥ叾涓竴鍙板彂閫佹暟鎹� 涓ょ鍒嗗埆璋冪敤鑾峰彇鎺ュ彛 涓�娆¤幏鍙栦竴鏉�
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/queue/bounded")
+public class BoundedQueueController {
+
+
+    /**
+     * 娣诲姞闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param capacity  瀹归噺
+     */
+    @GetMapping("/add")
+    public R<Void> add(String queueName, int capacity) {
+        // 鐢ㄥ畬浜嗕竴瀹氳閿�姣� 鍚﹀垯浼氫竴鐩村瓨鍦�
+        boolean b = QueueUtils.destroyBoundedQueue(queueName);
+        log.info("閫氶亾: {} , 鍒犻櫎: {}", queueName, b);
+        // 鍒濆鍖栬缃竴娆″嵆鍙�
+        if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) {
+            log.info("閫氶亾: {} , 璁剧疆瀹归噺: {}", queueName, capacity);
+        } else {
+            log.info("閫氶亾: {} , 璁剧疆瀹归噺澶辫触", queueName);
+            return R.fail("鎿嶄綔澶辫触");
+        }
+        for (int i = 0; i < 11; i++) {
+            String data = "data-" + i;
+            boolean flag = QueueUtils.addBoundedQueueObject(queueName, data);
+            if (flag == false) {
+                log.info("閫氶亾: {} , 鍙戦�佹暟鎹�: {} 澶辫触, 閫氶亾宸叉弧", queueName, data);
+            } else {
+                log.info("閫氶亾: {} , 鍙戦�佹暟鎹�: {}", queueName, data);
+            }
+        }
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 鍒犻櫎闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/remove")
+    public R<Void> remove(String queueName) {
+        String data = "data-" + 5;
+        if (QueueUtils.removeBoundedQueueObject(queueName, data)) {
+            log.info("閫氶亾: {} , 鍒犻櫎鏁版嵁: {}", queueName, data);
+        } else {
+            return R.fail("鎿嶄綔澶辫触");
+        }
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 鑾峰彇闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/get")
+    public R<Void> get(String queueName) {
+        String data;
+        do {
+            data = QueueUtils.getBoundedQueueObject(queueName);
+            log.info("閫氶亾: {} , 鑾峰彇鏁版嵁: {}", queueName, data);
+        } while (data != null);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java
new file mode 100644
index 0000000..b6e51d3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java
@@ -0,0 +1,97 @@
+package org.dromara.demo.controller.queue;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.QueueUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 寤惰繜闃熷垪 婕旂ず妗堜緥
+ * <p>
+ * 杞婚噺绾ч槦鍒� 閲嶉噺绾ф暟鎹噺 璇蜂娇鐢� MQ
+ * 渚嬪: 鍒涘缓璁㈠崟30鍒嗛挓鍚庤繃鏈熷鐞�
+ * <p>
+ * 闆嗙兢娴嬭瘯閫氳繃 鍚屼竴涓暟鎹彧浼氳娑堣垂涓�娆� 鍋氬ソ浜嬪姟琛ュ伩
+ * 闆嗙兢娴嬭瘯娴佺▼ 涓ゅ彴闆嗙兢鍒嗗埆寮�鍚闃� 鍦ㄥ叾涓竴鍙板彂閫佹暟鎹� 瑙傚療鎺ユ敹娑堟伅鐨勮寰�
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@SaIgnore
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/queue/delayed")
+public class DelayedQueueController {
+
+    /**
+     * 璁㈤槄闃熷垪
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/subscribe")
+    public R<Void> subscribe(String queueName) {
+        log.info("閫氶亾: {} 鐩戝惉涓�......", queueName);
+        // 椤圭洰鍒濆鍖栬缃竴娆″嵆鍙�
+        QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> {
+            // 瑙傚療鎺ユ敹鏃堕棿
+            log.info("閫氶亾: {}, 鏀跺埌鏁版嵁: {}", queueName, orderNum);
+            return CompletableFuture.runAsync(() -> {
+                // 寮傛澶勭悊鏁版嵁閫昏緫 涓嶈鍦ㄤ笂鏂瑰鐞嗕笟鍔¢�昏緫
+                log.info("鏁版嵁澶勭悊: {}", orderNum);
+            });
+        }, true);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 娣诲姞闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param orderNum  璁㈠崟鍙�
+     * @param time      寤惰繜鏃堕棿(绉�)
+     */
+    @GetMapping("/add")
+    public R<Void> add(String queueName, String orderNum, Long time) {
+        QueueUtils.addDelayedQueueObject(queueName, orderNum, time, TimeUnit.SECONDS);
+        // 瑙傚療鍙戦�佹椂闂�
+        log.info("閫氶亾: {} , 鍙戦�佹暟鎹�: {}", queueName, orderNum);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 鍒犻櫎闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param orderNum  璁㈠崟鍙�
+     */
+    @GetMapping("/remove")
+    public R<Void> remove(String queueName, String orderNum) {
+        if (QueueUtils.removeDelayedQueueObject(queueName, orderNum)) {
+            log.info("閫氶亾: {} , 鍒犻櫎鏁版嵁: {}", queueName, orderNum);
+        } else {
+            return R.fail("鎿嶄綔澶辫触");
+        }
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 閿�姣侀槦鍒�
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/destroy")
+    public R<Void> destroy(String queueName) {
+        // 鐢ㄥ畬浜嗕竴瀹氳閿�姣� 鍚﹀垯浼氫竴鐩村瓨鍦�
+        QueueUtils.destroyDelayedQueue(queueName);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityDemo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityDemo.java
new file mode 100644
index 0000000..e2449b5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityDemo.java
@@ -0,0 +1,22 @@
+package org.dromara.demo.controller.queue;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 瀹炰綋绫� 娉ㄦ剰涓嶅厑璁镐娇鐢ㄥ唴閮ㄧ被 鍚﹀垯浼氭壘涓嶅埌绫�
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@Data
+@NoArgsConstructor
+public class PriorityDemo implements Comparable<PriorityDemo> {
+    private String name;
+    private Integer orderNum;
+
+    @Override
+    public int compareTo(PriorityDemo other) {
+        return Integer.compare(getOrderNum(), other.getOrderNum());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityQueueController.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityQueueController.java
new file mode 100644
index 0000000..02c7396
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityQueueController.java
@@ -0,0 +1,89 @@
+package org.dromara.demo.controller.queue;
+
+import cn.hutool.core.util.RandomUtil;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.redis.utils.QueueUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 浼樺厛闃熷垪 婕旂ず妗堜緥
+ * <p>
+ * 杞婚噺绾ч槦鍒� 閲嶉噺绾ф暟鎹噺 璇蜂娇鐢� MQ
+ * <p>
+ * 闆嗙兢娴嬭瘯閫氳繃 鍚屼竴涓秷鎭彧浼氳娑堣垂涓�娆� 鍋氬ソ浜嬪姟琛ュ伩
+ * 闆嗙兢娴嬭瘯娴佺▼ 鍦ㄥ叾涓竴鍙板彂閫佹暟鎹� 涓ょ鍒嗗埆璋冪敤鑾峰彇鎺ュ彛 涓�娆¤幏鍙栦竴鏉�
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/demo/queue/priority")
+public class PriorityQueueController {
+
+    /**
+     * 娣诲姞闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/add")
+    public R<Void> add(String queueName) {
+        // 鐢ㄥ畬浜嗕竴瀹氳閿�姣� 鍚﹀垯浼氫竴鐩村瓨鍦�
+        boolean b = QueueUtils.destroyPriorityQueue(queueName);
+        log.info("閫氶亾: {} , 鍒犻櫎: {}", queueName, b);
+
+        for (int i = 0; i < 10; i++) {
+            int randomNum = RandomUtil.randomInt(10);
+            PriorityDemo data = new PriorityDemo();
+            data.setName("data-" + i);
+            data.setOrderNum(randomNum);
+            if (QueueUtils.addPriorityQueueObject(queueName, data)) {
+                log.info("閫氶亾: {} , 鍙戦�佹暟鎹�: {}", queueName, data);
+            } else {
+                log.info("閫氶亾: {} , 鍙戦�佹暟鎹�: {}, 鍙戦�佸け璐�", queueName, data);
+            }
+        }
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 鍒犻櫎闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     * @param name      瀵硅薄鍚�
+     * @param orderNum  鎺掑簭鍙�
+     */
+    @GetMapping("/remove")
+    public R<Void> remove(String queueName, String name, Integer orderNum) {
+        PriorityDemo data = new PriorityDemo();
+        data.setName(name);
+        data.setOrderNum(orderNum);
+        if (QueueUtils.removePriorityQueueObject(queueName, data)) {
+            log.info("閫氶亾: {} , 鍒犻櫎鏁版嵁: {}", queueName, data);
+        } else {
+            return R.fail("鎿嶄綔澶辫触");
+        }
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 鑾峰彇闃熷垪鏁版嵁
+     *
+     * @param queueName 闃熷垪鍚�
+     */
+    @GetMapping("/get")
+    public R<Void> get(String queueName) {
+        PriorityDemo data;
+        do {
+            data = QueueUtils.getPriorityQueueObject(queueName);
+            log.info("閫氶亾: {} , 鑾峰彇鏁版嵁: {}", queueName, data);
+        } while (data != null);
+        return R.ok("鎿嶄綔鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java
new file mode 100644
index 0000000..d3af0c9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java
@@ -0,0 +1,68 @@
+package org.dromara.demo.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 娴嬭瘯鍗曡〃瀵硅薄 test_demo
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("test_demo")
+public class TestDemo extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    private Long userId;
+
+    /**
+     * 鎺掑簭鍙�
+     */
+    @OrderBy(asc = false, sort = 1)
+    private Integer orderNum;
+
+    /**
+     * key閿�
+     */
+    private String testKey;
+
+    /**
+     * 鍊�
+     */
+    private String value;
+
+    /**
+     * 鐗堟湰
+     */
+    @Version
+    private Long version;
+
+    /**
+     * 鍒犻櫎鏍囧織
+     */
+    @TableLogic
+    private Long delFlag;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java
new file mode 100644
index 0000000..bdcd596
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java
@@ -0,0 +1,29 @@
+package org.dromara.demo.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.encrypt.annotation.EncryptField;
+import org.dromara.common.encrypt.enumd.AlgorithmType;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("test_demo")
+public class TestDemoEncrypt extends TestDemo {
+
+    /**
+     * key閿�
+     */
+    // @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==")
+    @EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB")
+    private String testKey;
+
+    /**
+     * 鍊�
+     */
+    // @EncryptField // 浠�涔堜篃涓嶅啓璧伴粯璁ml閰嶇疆
+    // @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5")
+    @EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5")
+    private String value;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestTree.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestTree.java
new file mode 100644
index 0000000..fd68253
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestTree.java
@@ -0,0 +1,65 @@
+package org.dromara.demo.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.Version;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 娴嬭瘯鏍戣〃瀵硅薄 test_tree
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("test_tree")
+public class TestTree extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 鐖禝D
+     */
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    private Long userId;
+
+    /**
+     * 鏍戣妭鐐瑰悕
+     */
+    private String treeName;
+
+    /**
+     * 鐗堟湰
+     */
+    @Version
+    private Long version;
+
+    /**
+     * 鍒犻櫎鏍囧織
+     */
+    @TableLogic
+    private Long delFlag;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoBo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoBo.java
new file mode 100644
index 0000000..8134677
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoBo.java
@@ -0,0 +1,62 @@
+package org.dromara.demo.domain.bo;
+
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.demo.domain.TestDemo;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * 娴嬭瘯鍗曡〃涓氬姟瀵硅薄 test_demo
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = TestDemo.class, reverseConvertGenerate = false)
+public class TestDemoBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @NotNull(message = "閮ㄩ棬id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    @NotNull(message = "鐢ㄦ埛id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long userId;
+
+    /**
+     * 鎺掑簭鍙�
+     */
+    @NotNull(message = "鎺掑簭鍙蜂笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    private Integer orderNum;
+
+    /**
+     * key閿�
+     */
+    @NotBlank(message = "key閿笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    private String testKey;
+
+    /**
+     * 鍊�
+     */
+    @NotBlank(message = "鍊间笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    private String value;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java
new file mode 100644
index 0000000..c066118
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java
@@ -0,0 +1,53 @@
+package org.dromara.demo.domain.bo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * 娴嬭瘯鍗曡〃涓氬姟瀵硅薄 test_demo
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Data
+public class TestDemoImportVo {
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @NotNull(message = "閮ㄩ棬id涓嶈兘涓虹┖")
+    @ExcelProperty(value = "閮ㄩ棬id")
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    @NotNull(message = "鐢ㄦ埛id涓嶈兘涓虹┖")
+    @ExcelProperty(value = "鐢ㄦ埛id")
+    private Long userId;
+
+    /**
+     * 鎺掑簭鍙�
+     */
+    @NotNull(message = "鎺掑簭鍙蜂笉鑳戒负绌�")
+    @ExcelProperty(value = "鎺掑簭鍙�")
+    private Long orderNum;
+
+    /**
+     * key閿�
+     */
+    @NotBlank(message = "key閿笉鑳戒负绌�")
+    @ExcelProperty(value = "key閿�")
+    private String testKey;
+
+    /**
+     * 鍊�
+     */
+    @NotBlank(message = "鍊间笉鑳戒负绌�")
+    @ExcelProperty(value = "鍊�")
+    private String value;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestTreeBo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestTreeBo.java
new file mode 100644
index 0000000..1bbac0e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestTreeBo.java
@@ -0,0 +1,54 @@
+package org.dromara.demo.domain.bo;
+
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.demo.domain.TestTree;
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 娴嬭瘯鏍戣〃涓氬姟瀵硅薄 test_tree
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = TestTree.class, reverseConvertGenerate = false)
+public class TestTreeBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 鐖禝D
+     */
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @NotNull(message = "閮ㄩ棬id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    @NotNull(message = "鐢ㄦ埛id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long userId;
+
+    /**
+     * 鏍戣妭鐐瑰悕
+     */
+    @NotBlank(message = "鏍戣妭鐐瑰悕涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String treeName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/package-info.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/package-info.java
new file mode 100644
index 0000000..cb7d83f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/package-info.java
@@ -0,0 +1 @@
+package org.dromara.demo.domain;
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java
new file mode 100644
index 0000000..95fa0d1
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java
@@ -0,0 +1,118 @@
+package org.dromara.demo.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.annotation.ExcelEnumFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.common.excel.convert.ExcelEnumConvert;
+
+/**
+ * 甯︽湁涓嬫媺閫夌殑Excel瀵煎嚭
+ *
+ * @author Emil.Zhang
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AllArgsConstructor
+@NoArgsConstructor
+public class ExportDemoVo {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鍚�", index = 0)
+    @NotEmpty(message = "鐢ㄦ埛鍚嶄笉鑳戒负绌�", groups = AddGroup.class)
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷
+     * </p>
+     * 浣跨敤ExcelEnumFormat娉ㄨВ闇�瑕佽繘琛屼笅鎷夐�夌殑閮ㄥ垎
+     */
+    @ExcelProperty(value = "鐢ㄦ埛绫诲瀷", index = 1, converter = ExcelEnumConvert.class)
+    @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info")
+    @NotEmpty(message = "鐢ㄦ埛绫诲瀷涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String userStatus;
+
+    /**
+     * 鎬у埆
+     * <p>
+     * 浣跨敤ExcelDictFormat娉ㄨВ闇�瑕佽繘琛屼笅鎷夐�夌殑閮ㄥ垎
+     */
+    @ExcelProperty(value = "鎬у埆", index = 2, converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_user_sex")
+    @NotEmpty(message = "鎬у埆涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String gender;
+
+    /**
+     * 鎵嬫満鍙�
+     */
+    @ExcelProperty(value = "鎵嬫満鍙�", index = 3)
+    @NotEmpty(message = "鎵嬫満鍙蜂笉鑳戒负绌�", groups = AddGroup.class)
+    private String phoneNumber;
+
+    /**
+     * Email
+     */
+    @ExcelProperty(value = "Email", index = 4)
+    @NotEmpty(message = "Email涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String email;
+
+    /**
+     * 鐪�
+     * <p>
+     * 绾ц仈涓嬫媺锛屼粎鍒ゆ柇鏄惁閫変簡
+     */
+    @ExcelProperty(value = "鐪�", index = 5)
+    @NotNull(message = "鐪佷笉鑳戒负绌�", groups = AddGroup.class)
+    private String province;
+
+    /**
+     * 鏁版嵁搴撲腑鐨勭渷ID
+     * </p>
+     * 澶勭悊瀹屾瘯鍚庡啀鍒ゆ柇鏄惁甯傛纭殑鍊�
+     */
+    @NotNull(message = "璇峰嬁鎵嬪姩杈撳叆", groups = EditGroup.class)
+    private Integer provinceId;
+
+    /**
+     * 甯�
+     * <p>
+     * 绾ц仈涓嬫媺
+     */
+    @ExcelProperty(value = "甯�", index = 6)
+    @NotNull(message = "甯備笉鑳戒负绌�", groups = AddGroup.class)
+    private String city;
+
+    /**
+     * 鏁版嵁搴撲腑鐨勫競ID
+     */
+    @NotNull(message = "璇峰嬁鎵嬪姩杈撳叆", groups = EditGroup.class)
+    private Integer cityId;
+
+    /**
+     * 鍘�
+     * <p>
+     * 绾ц仈涓嬫媺
+     */
+    @ExcelProperty(value = "鍘�", index = 7)
+    @NotNull(message = "鍘夸笉鑳戒负绌�", groups = AddGroup.class)
+    private String area;
+
+    /**
+     * 鏁版嵁搴撲腑鐨勫幙ID
+     */
+    @NotNull(message = "璇峰嬁鎵嬪姩杈撳叆", groups = EditGroup.class)
+    private Integer areaId;
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java
new file mode 100644
index 0000000..016c2f7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java
@@ -0,0 +1,104 @@
+package org.dromara.demo.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.demo.domain.TestDemo;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 娴嬭瘯鍗曡〃瑙嗗浘瀵硅薄 test_demo
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = TestDemo.class)
+public class TestDemoVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @ExcelProperty(value = "閮ㄩ棬id")
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    @ExcelProperty(value = "鐢ㄦ埛id")
+    private Long userId;
+
+    /**
+     * 鎺掑簭鍙�
+     */
+    @ExcelProperty(value = "鎺掑簭鍙�")
+    private Integer orderNum;
+
+    /**
+     * key閿�
+     */
+    @ExcelProperty(value = "key閿�")
+    private String testKey;
+
+    /**
+     * 鍊�
+     */
+    @ExcelProperty(value = "鍊�")
+    private String value;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+    /**
+     * 鍒涘缓浜�
+     */
+    @ExcelProperty(value = "鍒涘缓浜�")
+    private Long createBy;
+
+    /**
+     * 鍒涘缓浜鸿处鍙�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
+    @ExcelProperty(value = "鍒涘缓浜鸿处鍙�")
+    private String createByName;
+
+    /**
+     * 鏇存柊鏃堕棿
+     */
+    @ExcelProperty(value = "鏇存柊鏃堕棿")
+    private Date updateTime;
+
+    /**
+     * 鏇存柊浜�
+     */
+    @ExcelProperty(value = "鏇存柊浜�")
+    private Long updateBy;
+
+    /**
+     * 鏇存柊浜鸿处鍙�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy")
+    @ExcelProperty(value = "鏇存柊浜鸿处鍙�")
+    private String updateByName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestTreeVo.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestTreeVo.java
new file mode 100644
index 0000000..58b4bdb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestTreeVo.java
@@ -0,0 +1,64 @@
+package org.dromara.demo.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.demo.domain.TestTree;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 娴嬭瘯鏍戣〃瑙嗗浘瀵硅薄 test_tree
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = TestTree.class)
+public class TestTreeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    private Long id;
+
+    /**
+     * 鐖秈d
+     */
+    @ExcelProperty(value = "鐖秈d")
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @ExcelProperty(value = "閮ㄩ棬id")
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    @ExcelProperty(value = "鐢ㄦ埛id")
+    private Long userId;
+
+    /**
+     * 鏍戣妭鐐瑰悕
+     */
+    @ExcelProperty(value = "鏍戣妭鐐瑰悕")
+    private String treeName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/listener/ExportDemoListener.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/listener/ExportDemoListener.java
new file mode 100644
index 0000000..7bd4e1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/listener/ExportDemoListener.java
@@ -0,0 +1,68 @@
+package org.dromara.demo.listener;
+
+import cn.hutool.core.util.NumberUtil;
+import com.alibaba.excel.context.AnalysisContext;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.core.DefaultExcelListener;
+import org.dromara.common.excel.core.DropDownOptions;
+import org.dromara.demo.domain.vo.ExportDemoVo;
+
+import java.util.List;
+
+/**
+ * Excel甯︿笅鎷夋鐨勮В鏋愬鐞嗗櫒
+ *
+ * @author Emil.Zhang
+ */
+public class ExportDemoListener extends DefaultExcelListener<ExportDemoVo> {
+
+    public ExportDemoListener() {
+        // 鏄剧ず浣跨敤鏋勯�犲嚱鏁帮紝鍚﹀垯灏嗗鑷寸┖鎸囬拡
+        super(true);
+    }
+
+    @Override
+    public void invoke(ExportDemoVo data, AnalysisContext context) {
+        // 鍏堟牎楠屽繀濉�
+        ValidatorUtils.validate(data, AddGroup.class);
+
+        // 澶勭悊绾ц仈涓嬫媺鐨勯儴鍒�
+        String province = data.getProvince();
+        String city = data.getCity();
+        String area = data.getArea();
+        // 鏈鐢ㄦ埛閫夋嫨鐨勭渷
+        List<String> thisRowSelectedProvinceOption = DropDownOptions.analyzeOptionValue(province);
+        if (thisRowSelectedProvinceOption.size() == 2) {
+            String provinceIdStr = thisRowSelectedProvinceOption.get(1);
+            if (NumberUtil.isNumber(provinceIdStr)) {
+                // 涓ユ牸瑕佹眰鏁版嵁鐨勮瘽鍙互鍦ㄨ繖閲屽仛涓庢暟鎹簱鐩稿叧鐨勫垽鏂�
+                // 渚嬪鍒ゆ柇鐪佷俊鎭槸鍚﹀湪鏁版嵁搴撲腑瀛樺湪绛夛紝寤鸿缁撳悎RedisCache鍋氱紦瀛�10s锛屽噺灏戞暟鎹簱璋冪敤
+                data.setProvinceId(Integer.parseInt(provinceIdStr));
+            }
+        }
+        // 鏈鐢ㄦ埛閫夋嫨鐨勫競
+        List<String> thisRowSelectedCityOption = DropDownOptions.analyzeOptionValue(city);
+        if (thisRowSelectedCityOption.size() == 2) {
+            String cityIdStr = thisRowSelectedCityOption.get(1);
+            if (NumberUtil.isNumber(cityIdStr)) {
+                data.setCityId(Integer.parseInt(cityIdStr));
+            }
+        }
+        // 鏈鐢ㄦ埛閫夋嫨鐨勫幙
+        List<String> thisRowSelectedAreaOption = DropDownOptions.analyzeOptionValue(area);
+        if (thisRowSelectedAreaOption.size() == 2) {
+            String areaIdStr = thisRowSelectedAreaOption.get(1);
+            if (NumberUtil.isNumber(areaIdStr)) {
+                data.setAreaId(Integer.parseInt(areaIdStr));
+            }
+        }
+
+        // 澶勭悊瀹屾瘯浠ュ悗鍒ゆ柇鏄惁绗﹀悎瑙勫垯
+        ValidatorUtils.validate(data, EditGroup.class);
+
+        // 娣诲姞鍒板鐞嗙粨鏋滀腑
+        getExcelResult().getList().add(data);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoEncryptMapper.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoEncryptMapper.java
new file mode 100644
index 0000000..601f97a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoEncryptMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.demo.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.demo.domain.TestDemoEncrypt;
+
+/**
+ * 娴嬭瘯鍔犲瘑鍔熻兘
+ *
+ * @author Lion Li
+ */
+public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncrypt, TestDemoEncrypt> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
new file mode 100644
index 0000000..6aeeb50
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java
@@ -0,0 +1,60 @@
+package org.dromara.demo.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.demo.domain.TestDemo;
+import org.dromara.demo.domain.vo.TestDemoVo;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴嬭瘯鍗曡〃Mapper鎺ュ彛
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
+
+    @Override
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
+
+    @Override
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
+
+    @Override
+    @DataPermission(value = {
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    }, joinStr = "AND")
+    List<TestDemo> selectBatchIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
+
+    @Override
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    int updateById(@Param(Constants.ENTITY) TestDemo entity);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java
new file mode 100644
index 0000000..e5f4c44
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java
@@ -0,0 +1,21 @@
+package org.dromara.demo.mapper;
+
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.demo.domain.TestTree;
+import org.dromara.demo.domain.vo.TestTreeVo;
+
+/**
+ * 娴嬭瘯鏍戣〃Mapper鎺ュ彛
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@DataPermission({
+    @DataColumn(key = "deptName", value = "dept_id"),
+    @DataColumn(key = "userName", value = "user_id")
+})
+public interface TestTreeMapper extends BaseMapperPlus<TestTree, TestTreeVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java
new file mode 100644
index 0000000..ff1c4df
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java
@@ -0,0 +1 @@
+package org.dromara.demo.mapper;
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java
new file mode 100644
index 0000000..4dfa5ef
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java
@@ -0,0 +1,18 @@
+package org.dromara.demo.service;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * 瀵煎嚭涓嬫媺妗咵xcel绀轰緥
+ *
+ * @author Emil.Zhang
+ */
+public interface IExportExcelService {
+
+    /**
+     * 瀵煎嚭涓嬫媺妗�
+     *
+     * @param response /
+     */
+    void exportWithOptions(HttpServletResponse response);
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java
new file mode 100644
index 0000000..bca4192
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java
@@ -0,0 +1,71 @@
+package org.dromara.demo.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.demo.domain.TestDemo;
+import org.dromara.demo.domain.bo.TestDemoBo;
+import org.dromara.demo.domain.vo.TestDemoVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴嬭瘯鍗曡〃Service鎺ュ彛
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+public interface ITestDemoService {
+
+    /**
+     * 鏌ヨ鍗曚釜
+     *
+     * @return
+     */
+    TestDemoVo queryById(Long id);
+
+    /**
+     * 鏌ヨ鍒楄〃
+     */
+    TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery);
+
+    /**
+     * 鑷畾涔夊垎椤垫煡璇�
+     */
+    TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鍒楄〃
+     */
+    List<TestDemoVo> queryList(TestDemoBo bo);
+
+    /**
+     * 鏍规嵁鏂板涓氬姟瀵硅薄鎻掑叆娴嬭瘯鍗曡〃
+     *
+     * @param bo 娴嬭瘯鍗曡〃鏂板涓氬姟瀵硅薄
+     * @return
+     */
+    Boolean insertByBo(TestDemoBo bo);
+
+    /**
+     * 鏍规嵁缂栬緫涓氬姟瀵硅薄淇敼娴嬭瘯鍗曡〃
+     *
+     * @param bo 娴嬭瘯鍗曡〃缂栬緫涓氬姟瀵硅薄
+     * @return
+     */
+    Boolean updateByBo(TestDemoBo bo);
+
+    /**
+     * 鏍¢獙骞跺垹闄ゆ暟鎹�
+     *
+     * @param ids     涓婚敭闆嗗悎
+     * @param isValid 鏄惁鏍¢獙,true-鍒犻櫎鍓嶆牎楠�,false-涓嶆牎楠�
+     * @return
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 鎵归噺淇濆瓨
+     */
+    Boolean saveBatch(List<TestDemo> list);
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java
new file mode 100644
index 0000000..9155201
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java
@@ -0,0 +1,52 @@
+package org.dromara.demo.service;
+
+import org.dromara.demo.domain.bo.TestTreeBo;
+import org.dromara.demo.domain.vo.TestTreeVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴嬭瘯鏍戣〃Service鎺ュ彛
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+public interface ITestTreeService {
+    /**
+     * 鏌ヨ鍗曚釜
+     *
+     * @return
+     */
+    TestTreeVo queryById(Long id);
+
+    /**
+     * 鏌ヨ鍒楄〃
+     */
+    List<TestTreeVo> queryList(TestTreeBo bo);
+
+    /**
+     * 鏍规嵁鏂板涓氬姟瀵硅薄鎻掑叆娴嬭瘯鏍戣〃
+     *
+     * @param bo 娴嬭瘯鏍戣〃鏂板涓氬姟瀵硅薄
+     * @return
+     */
+    Boolean insertByBo(TestTreeBo bo);
+
+    /**
+     * 鏍规嵁缂栬緫涓氬姟瀵硅薄淇敼娴嬭瘯鏍戣〃
+     *
+     * @param bo 娴嬭瘯鏍戣〃缂栬緫涓氬姟瀵硅薄
+     * @return
+     */
+    Boolean updateByBo(TestTreeBo bo);
+
+    /**
+     * 鏍¢獙骞跺垹闄ゆ暟鎹�
+     *
+     * @param ids     涓婚敭闆嗗悎
+     * @param isValid 鏄惁鏍¢獙,true-鍒犻櫎鍓嶆牎楠�,false-涓嶆牎楠�
+     * @return
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java
new file mode 100644
index 0000000..0240e02
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java
@@ -0,0 +1,222 @@
+package org.dromara.demo.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.excel.core.DropDownOptions;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.demo.domain.vo.ExportDemoVo;
+import org.dromara.demo.service.IExportExcelService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 瀵煎嚭涓嬫媺妗咵xcel绀轰緥
+ *
+ * @author Emil.Zhang
+ */
+@Service
+@RequiredArgsConstructor
+public class ExportExcelServiceImpl implements IExportExcelService {
+
+    @Override
+    public void exportWithOptions(HttpServletResponse response) {
+        // 鍒涘缓琛ㄦ牸鏁版嵁锛屼笟鍔′腑涓�鑸�氳繃鏁版嵁搴撴煡璇�
+        List<ExportDemoVo> excelDataList = new ArrayList<>();
+        for (int i = 0; i < 3; i++) {
+            // 妯℃嫙鏁版嵁搴撲腑鐨勪竴鏉℃暟鎹�
+            ExportDemoVo everyRowData = new ExportDemoVo();
+            everyRowData.setNickName("鐢ㄦ埛-" + i);
+            everyRowData.setUserStatus(UserStatus.OK.getCode());
+            everyRowData.setGender("1");
+            everyRowData.setPhoneNumber(String.format("175%08d", i));
+            everyRowData.setEmail(String.format("175%08d", i) + "@163.com");
+            everyRowData.setProvinceId(i);
+            everyRowData.setCityId(i);
+            everyRowData.setAreaId(i);
+            excelDataList.add(everyRowData);
+        }
+
+        // 閫氳繃@ExcelIgnoreUnannotated閰嶅悎@ExcelProperty鍚堢悊鏄剧ず闇�瑕佺殑鍒�
+        // 骞堕�氳繃@DropDown娉ㄨВ鎸囧畾涓嬫媺鍊硷紝鎴栬�呴�氳繃鍒涘缓ExcelOptions鏉ユ寚瀹氫笅鎷夋
+        // 浣跨敤ExcelOptions鏃跺缓璁寚瀹氬垪index锛岄槻姝㈠嚭鐜颁笅鎷夊垪瑙f瀽涓嶅榻�
+
+        // 棣栧厛浠庢暟鎹簱涓煡璇笅鎷夋鍐呯殑鍙�夐」
+        // 杩欓噷妯℃嫙鏌ヨ缁撴灉
+        List<DemoCityData> provinceList = getProvinceList(),
+            cityList = getCityList(provinceList),
+            areaList = getAreaList(cityList);
+        int provinceIndex = 5, cityIndex = 6, areaIndex = 7;
+
+        DropDownOptions provinceToCity = DropDownOptions.buildLinkedOptions(
+            provinceList,
+            provinceIndex,
+            cityList,
+            cityIndex,
+            DemoCityData::getId,
+            DemoCityData::getPid,
+            everyOptions -> DropDownOptions.createOptionValue(
+                everyOptions.getName(),
+                everyOptions.getId()
+            )
+        );
+
+        DropDownOptions cityToArea = DropDownOptions.buildLinkedOptions(
+            cityList,
+            cityIndex,
+            areaList,
+            areaIndex,
+            DemoCityData::getId,
+            DemoCityData::getPid,
+            everyOptions -> DropDownOptions.createOptionValue(
+                everyOptions.getName(),
+                everyOptions.getId()
+            )
+        );
+
+        // 鎶婃墍鏈夌殑涓嬫媺妗嗗瓨鍌�
+        List<DropDownOptions> options = new ArrayList<>();
+        options.add(provinceToCity);
+        options.add(cityToArea);
+
+        // 鍒版涓烘鎵�鏈夌殑涓嬫媺妗嗗彲閫夐」宸插叏閮ㄩ厤缃畬姣�
+
+        // 鎺ヤ笅鏉ラ渶瑕佸皢Excel涓殑灞曠ず鏁版嵁杞崲涓哄搴旂殑涓嬫媺閫�
+        List<ExportDemoVo> outList = StreamUtils.toList(excelDataList, everyRowData -> {
+            // 鍙渶瑕佸鐞嗘病鏈変娇鐢ˊExcelDictFormat娉ㄨВ鐨勪笅鎷夋
+            // 涓�鑸潵璇达紝鍙互鐩存帴鍦ㄦ暟鎹簱鏌ヨ鍗虫煡璇㈠嚭鐪佸競鍘夸俊鎭紝杩欓噷閫氳繃妯℃嫙鎿嶄綔璧嬪��
+            everyRowData.setProvince(buildOptions(provinceList, everyRowData.getProvinceId()));
+            everyRowData.setCity(buildOptions(cityList, everyRowData.getCityId()));
+            everyRowData.setArea(buildOptions(areaList, everyRowData.getAreaId()));
+            return everyRowData;
+        });
+
+        ExcelUtil.exportExcel(outList, "涓嬫媺妗嗙ず渚�", ExportDemoVo.class, response, options);
+    }
+
+    private String buildOptions(List<DemoCityData> cityDataList, Integer id) {
+        Map<Integer, List<DemoCityData>> groupByIdMap =
+            cityDataList.stream().collect(Collectors.groupingBy(DemoCityData::getId));
+        if (groupByIdMap.containsKey(id)) {
+            DemoCityData demoCityData = groupByIdMap.get(id).get(0);
+            return DropDownOptions.createOptionValue(demoCityData.getName(), demoCityData.getId());
+        } else {
+            return StrUtil.EMPTY;
+        }
+    }
+
+    /**
+     * 妯℃嫙鏌ヨ鏁版嵁搴撴搷浣�
+     *
+     * @return /
+     */
+    private List<DemoCityData> getProvinceList() {
+        List<DemoCityData> provinceList = new ArrayList<>();
+
+        // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
+        provinceList.add(new DemoCityData(0, null, "瀹夊窘鐪�"));
+        provinceList.add(new DemoCityData(1, null, "姹熻嫃鐪�"));
+
+        return provinceList;
+    }
+
+    /**
+     * 妯℃嫙鏌ユ壘鏁版嵁搴撴搷浣滐紝闇�瑕佽繛甯︽煡璇㈠嚭鐪佺殑鏁版嵁
+     *
+     * @param provinceList 妯℃嫙鐨勭埗鐪佹暟鎹�
+     * @return /
+     */
+    private List<DemoCityData> getCityList(List<DemoCityData> provinceList) {
+        List<DemoCityData> cityList = new ArrayList<>();
+
+        // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
+        cityList.add(new DemoCityData(0, 0, "鍚堣偉甯�"));
+        cityList.add(new DemoCityData(1, 0, "鑺滄箹甯�"));
+        cityList.add(new DemoCityData(2, 1, "鍗椾含甯�"));
+        cityList.add(new DemoCityData(3, 1, "鏃犻敗甯�"));
+        cityList.add(new DemoCityData(4, 1, "寰愬窞甯�"));
+
+        selectParentData(provinceList, cityList);
+
+        return cityList;
+    }
+
+    /**
+     * 妯℃嫙鏌ユ壘鏁版嵁搴撴搷浣滐紝闇�瑕佽繛甯︽煡璇㈠嚭甯傜殑鏁版嵁
+     *
+     * @param cityList 妯℃嫙鐨勭埗甯傛暟鎹�
+     * @return /
+     */
+    private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
+        List<DemoCityData> areaList = new ArrayList<>();
+
+        // 瀹為檯涓氬姟涓竴鑸噰鐢ㄦ暟鎹簱璇诲彇鐨勫舰寮忥紝杩欓噷鐩存帴鎷兼帴鍒涘缓
+        areaList.add(new DemoCityData(0, 0, "鐟舵捣鍖�"));
+        areaList.add(new DemoCityData(1, 0, "搴愭睙鍖�"));
+        areaList.add(new DemoCityData(2, 1, "鍗楀畞鍘�"));
+        areaList.add(new DemoCityData(3, 1, "闀滄箹鍖�"));
+        areaList.add(new DemoCityData(4, 2, "鐜勬鍖�"));
+        areaList.add(new DemoCityData(5, 2, "绉︽樊鍖�"));
+        areaList.add(new DemoCityData(6, 3, "瀹滃叴甯�"));
+        areaList.add(new DemoCityData(7, 3, "鏂板惔鍖�"));
+        areaList.add(new DemoCityData(8, 4, "榧撴ゼ鍖�"));
+        areaList.add(new DemoCityData(9, 4, "涓板幙"));
+
+        selectParentData(cityList, areaList);
+
+        return areaList;
+    }
+
+    /**
+     * 妯℃嫙鏁版嵁搴撶殑鏌ヨ鐖舵暟鎹搷浣�
+     *
+     * @param parentList /
+     * @param sonList    /
+     */
+    private void selectParentData(List<DemoCityData> parentList, List<DemoCityData> sonList) {
+        Map<Integer, List<DemoCityData>> parentGroupByIdMap =
+            parentList.stream().collect(Collectors.groupingBy(DemoCityData::getId));
+
+        sonList.forEach(everySon -> {
+            if (parentGroupByIdMap.containsKey(everySon.getPid())) {
+                everySon.setPData(parentGroupByIdMap.get(everySon.getPid()).get(0));
+            }
+        });
+    }
+
+    /**
+     * 妯℃嫙鐨勬暟鎹簱鐪佸競鍘�
+     */
+    @Data
+    private static class DemoCityData {
+        /**
+         * 鏁版嵁搴搃d瀛楁
+         */
+        private Integer id;
+        /**
+         * 鏁版嵁搴損id瀛楁
+         */
+        private Integer pid;
+        /**
+         * 鏁版嵁搴搉ame瀛楁
+         */
+        private String name;
+        /**
+         * MyBatisPlus杩炲甫鏌ヨ鐖舵暟鎹�
+         */
+        private DemoCityData pData;
+
+        public DemoCityData(Integer id, Integer pid, String name) {
+            this.id = id;
+            this.pid = pid;
+            this.name = name;
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
new file mode 100644
index 0000000..3cfde3a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java
@@ -0,0 +1,116 @@
+package org.dromara.demo.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.demo.domain.TestDemo;
+import org.dromara.demo.domain.bo.TestDemoBo;
+import org.dromara.demo.domain.vo.TestDemoVo;
+import org.dromara.demo.mapper.TestDemoMapper;
+import org.dromara.demo.service.ITestDemoService;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴嬭瘯鍗曡〃Service涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+@RequiredArgsConstructor
+@Service
+public class TestDemoServiceImpl implements ITestDemoService {
+
+    private final TestDemoMapper baseMapper;
+
+    @Override
+    public TestDemoVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    @Override
+    public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
+        Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鑷畾涔夊垎椤垫煡璇�
+     */
+    @Override
+    public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo);
+        Page<TestDemoVo> result = baseMapper.customPageList(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public List<TestDemoVo> queryList(TestDemoBo bo) {
+        return baseMapper.selectVoList(buildQueryWrapper(bo));
+    }
+
+    private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey());
+        lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue());
+        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
+            TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
+        lqw.orderByAsc(TestDemo::getId);
+        return lqw;
+    }
+
+    @Override
+    public Boolean insertByBo(TestDemoBo bo) {
+        TestDemo add = MapstructUtils.convert(bo, TestDemo.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    @Override
+    public Boolean updateByBo(TestDemoBo bo) {
+        TestDemo update = MapstructUtils.convert(bo, TestDemo.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     *
+     * @param entity 瀹炰綋绫绘暟鎹�
+     */
+    private void validEntityBeforeSave(TestDemo entity) {
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+            List<TestDemo> list = baseMapper.selectBatchIds(ids);
+            if (list.size() != ids.size()) {
+                throw new ServiceException("鎮ㄦ病鏈夊垹闄ゆ潈闄�!");
+            }
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    @Override
+    public Boolean saveBatch(List<TestDemo> list) {
+        return baseMapper.insertBatch(list);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java
new file mode 100644
index 0000000..e4e548b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java
@@ -0,0 +1,88 @@
+package org.dromara.demo.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.demo.domain.TestTree;
+import org.dromara.demo.domain.bo.TestTreeBo;
+import org.dromara.demo.domain.vo.TestTreeVo;
+import org.dromara.demo.mapper.TestTreeMapper;
+import org.dromara.demo.service.ITestTreeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴嬭瘯鏍戣〃Service涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ * @date 2021-07-26
+ */
+// @DS("slave") // 鍒囨崲浠庡簱鏌ヨ
+@RequiredArgsConstructor
+@Service
+public class TestTreeServiceImpl implements ITestTreeService {
+
+    private final TestTreeMapper baseMapper;
+
+    @Override
+    public TestTreeVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    // @DS("slave") // 鍒囨崲浠庡簱鏌ヨ
+    @Override
+    public List<TestTreeVo> queryList(TestTreeBo bo) {
+        LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName());
+        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
+            TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
+        lqw.orderByAsc(TestTree::getId);
+        return lqw;
+    }
+
+    @Override
+    public Boolean insertByBo(TestTreeBo bo) {
+        TestTree add = MapstructUtils.convert(bo, TestTree.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    @Override
+    public Boolean updateByBo(TestTreeBo bo) {
+        TestTree update = MapstructUtils.convert(bo, TestTree.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     *
+     * @param entity 瀹炰綋绫绘暟鎹�
+     */
+    private void validEntityBeforeSave(TestTree entity) {
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/package-info.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/package-info.java
new file mode 100644
index 0000000..7011984
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/package-info.java
@@ -0,0 +1 @@
+package org.dromara.demo.service.impl;
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java
new file mode 100644
index 0000000..16727ff
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java
@@ -0,0 +1 @@
+package org.dromara.demo.service;
diff --git "a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\215\225\345\210\227\350\241\250.xlsx" "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\215\225\345\210\227\350\241\250.xlsx"
new file mode 100644
index 0000000..0f7347d
--- /dev/null
+++ "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\215\225\345\210\227\350\241\250.xlsx"
Binary files differ
diff --git "a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232sheet\345\210\227\350\241\250.xlsx" "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232sheet\345\210\227\350\241\250.xlsx"
new file mode 100644
index 0000000..5277f2e
--- /dev/null
+++ "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232sheet\345\210\227\350\241\250.xlsx"
Binary files differ
diff --git "a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232\345\210\227\350\241\250.xlsx" "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232\345\210\227\350\241\250.xlsx"
new file mode 100644
index 0000000..c7d11dc
--- /dev/null
+++ "b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/excel/\345\244\232\345\210\227\350\241\250.xlsx"
Binary files differ
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml
new file mode 100644
index 0000000..dbf89a3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.demo.mapper.TestDemoMapper">
+
+    <select id="customPageList" resultType="org.dromara.demo.domain.vo.TestDemoVo">
+        SELECT * FROM test_demo ${ew.customSqlSegment}
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml
new file mode 100644
index 0000000..d7975ec
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.demo.mapper.TestTreeMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/eims/ruoyi-modules/ruoyi-generator/pom.xml b/eims/ruoyi-modules/ruoyi-generator/pom.xml
new file mode 100644
index 0000000..b7fd94f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-generator</artifactId>
+
+    <description>
+        generator 浠g爜鐢熸垚
+    </description>
+
+    <dependencies>
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <!--velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.anyline</groupId>
+            <artifactId>anyline-environment-spring-data-jdbc</artifactId>
+            <version>${anyline.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.anyline</groupId>
+            <artifactId>anyline-data-jdbc-mysql</artifactId>
+            <version>${anyline.version}</version>
+        </dependency>
+
+        <!-- anyline鏀寔100+绉嶇被鍨嬫暟鎹簱 娣诲姞瀵瑰簲鐨刯dbc渚濊禆涓巃nyline瀵瑰簲鏁版嵁搴撲緷璧栧寘鍗冲彲 -->
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-oracle</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-postgresql</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
+<!--        <dependency>-->
+<!--            <groupId>org.anyline</groupId>-->
+<!--            <artifactId>anyline-data-jdbc-mssql</artifactId>-->
+<!--        <version>${anyline.version}</version>-->
+<!--        </dependency>-->
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java
new file mode 100644
index 0000000..b29f8c9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java
@@ -0,0 +1,73 @@
+package org.dromara.generator.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+/**
+ * 璇诲彇浠g爜鐢熸垚鐩稿叧閰嶇疆
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "gen")
+@PropertySource(value = {"classpath:generator.yml"}, encoding = "UTF-8")
+public class GenConfig {
+
+    /**
+     * 浣滆��
+     */
+    public static String author;
+
+    /**
+     * 鐢熸垚鍖呰矾寰�
+     */
+    public static String packageName;
+
+    /**
+     * 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸false
+     */
+    public static boolean autoRemovePre;
+
+    /**
+     * 琛ㄥ墠缂�(绫诲悕涓嶄細鍖呭惈琛ㄥ墠缂�)
+     */
+    public static String tablePrefix;
+
+    public static String getAuthor() {
+        return author;
+    }
+
+    @Value("${author}")
+    public void setAuthor(String author) {
+        GenConfig.author = author;
+    }
+
+    public static String getPackageName() {
+        return packageName;
+    }
+
+    @Value("${packageName}")
+    public void setPackageName(String packageName) {
+        GenConfig.packageName = packageName;
+    }
+
+    public static boolean getAutoRemovePre() {
+        return autoRemovePre;
+    }
+
+    @Value("${autoRemovePre}")
+    public void setAutoRemovePre(boolean autoRemovePre) {
+        GenConfig.autoRemovePre = autoRemovePre;
+    }
+
+    public static String getTablePrefix() {
+        return tablePrefix;
+    }
+
+    @Value("${tablePrefix}")
+    public void setTablePrefix(String tablePrefix) {
+        GenConfig.tablePrefix = tablePrefix;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java
new file mode 100644
index 0000000..8c0f352
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java
@@ -0,0 +1,105 @@
+package org.dromara.generator.config;
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.anyline.data.datasource.DataSourceMonitor;
+import org.anyline.data.runtime.DataRuntime;
+import org.anyline.util.ConfigTable;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * anyline 閫傞厤 鍔ㄦ�佹暟鎹簮鏀归��
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Component
+public class MyBatisDataSourceMonitor implements DataSourceMonitor {
+
+    public MyBatisDataSourceMonitor() {
+        // 璋冩暣鎵ц妯″紡涓鸿嚜瀹氫箟
+        ConfigTable.KEEP_ADAPTER = 2;
+        // 绂佺敤缂撳瓨
+        ConfigTable.METADATA_CACHE_SCOPE = 0;
+    }
+
+    private final Map<String, String> features = new HashMap<>();
+
+    /**
+     * 鏁版嵁婧愮壒寰� 鐢ㄦ潵瀹氬噯 adapter 鍖呭惈鏁版嵁搴撴垨JDBC鍗忚鍏抽敭瀛�<br/>
+     * 涓�鑸細閫氳繃 浜у搧鍚峗url 鍚堟垚 濡傛灉杩斿洖null 涓婂眰鏂规硶浼氶�氳繃driver_浜у搧鍚峗url鍚堟垚
+     *
+     * @param datasource 鏁版嵁婧�
+     * @return String 杩斿洖null鐢变笂灞傝嚜鍔ㄦ彁鍙�
+     */
+    @Override
+    public String feature(DataRuntime runtime, Object datasource) {
+        String feature = null;
+        if (datasource instanceof JdbcTemplate jdbc) {
+            DataSource ds = jdbc.getDataSource();
+            if (ds instanceof DynamicRoutingDataSource) {
+                String key = DynamicDataSourceContextHolder.peek();
+                feature = features.get(key);
+                if (null == feature) {
+                    Connection con = null;
+                    try {
+                        con = DataSourceUtils.getConnection(ds);
+                        DatabaseMetaData meta = con.getMetaData();
+                        String url = meta.getURL();
+                        feature = meta.getDatabaseProductName().toLowerCase().replace(" ", "") + "_" + url;
+                        features.put(key, feature);
+                    } catch (Exception e) {
+                        log.error(e.getMessage(), e);
+                    } finally {
+                        if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) {
+                            DataSourceUtils.releaseConnection(con, ds);
+                        }
+                    }
+                }
+            }
+        }
+        return feature;
+    }
+
+    /**
+     * 鏁版嵁婧愬敮涓�鏍囪瘑 濡傛灉涓嶅疄鐜板垯榛樿feature
+     * @param datasource 鏁版嵁婧�
+     * @return String 杩斿洖null鐢变笂灞傝嚜鍔ㄦ彁鍙�
+     */
+    @Override
+    public String key(DataRuntime runtime, Object datasource) {
+        if(datasource instanceof JdbcTemplate jdbc){
+            DataSource ds = jdbc.getDataSource();
+            if(ds instanceof DynamicRoutingDataSource){
+                return DynamicDataSourceContextHolder.peek();
+            }
+        }
+        return runtime.getKey();
+    }
+
+    /**
+     * ConfigTable.KEEP_ADAPTER=2 : 鏍规嵁褰撳墠鎺ュ彛鍒ゆ柇鏄惁淇濇寔鍚屼竴涓暟鎹簮缁戝畾鍚屼竴涓猘dapter<br/>
+     * DynamicRoutingDataSource绫诲瀷鐨勮繑鍥瀎alse,鍥犱负鍚屼竴涓狣ynamicRoutingDataSource鍙兘瀵瑰簲澶氱被鏁版嵁搴�, 濡傛灉椤圭洰涓彧鏈変竴绉嶆暟鎹簱 搴旇鐩存帴杩斿洖true
+     *
+     * @param datasource 鏁版嵁婧�
+     * @return boolean
+     */
+    @Override
+    public boolean keepAdapter(DataRuntime runtime, Object datasource) {
+        if (datasource instanceof JdbcTemplate jdbc) {
+            DataSource ds = jdbc.getDataSource();
+            return !(ds instanceof DynamicRoutingDataSource);
+        }
+        return true;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
new file mode 100644
index 0000000..c345f22
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java
@@ -0,0 +1,186 @@
+package org.dromara.generator.constant;
+
+/**
+ * 浠g爜鐢熸垚閫氱敤甯搁噺
+ *
+ * @author ruoyi
+ */
+public interface GenConstants {
+    /**
+     * 鍗曡〃锛堝鍒犳敼鏌ワ級
+     */
+    String TPL_CRUD = "crud";
+
+    /**
+     * 鏍戣〃锛堝鍒犳敼鏌ワ級
+     */
+    String TPL_TREE = "tree";
+
+    /**
+     * 鏍戠紪鐮佸瓧娈�
+     */
+    String TREE_CODE = "treeCode";
+
+    /**
+     * 鏍戠埗缂栫爜瀛楁
+     */
+    String TREE_PARENT_CODE = "treeParentCode";
+
+    /**
+     * 鏍戝悕绉板瓧娈�
+     */
+    String TREE_NAME = "treeName";
+
+    /**
+     * 涓婄骇鑿滃崟ID瀛楁
+     */
+    String PARENT_MENU_ID = "parentMenuId";
+
+    /**
+     * 涓婄骇鑿滃崟鍚嶇О瀛楁
+     */
+    String PARENT_MENU_NAME = "parentMenuName";
+
+    /**
+     * 鏁版嵁搴撳瓧绗︿覆绫诲瀷
+     */
+    String[] COLUMNTYPE_STR = {"char", "varchar", "enum", "set", "nchar", "nvarchar", "varchar2", "nvarchar2"};
+
+    /**
+     * 鏁版嵁搴撴枃鏈被鍨�
+     */
+    String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext", "binary", "varbinary", "blob",
+        "ntext", "image", "bytea"};
+
+    /**
+     * 鏁版嵁搴撴椂闂寸被鍨�
+     */
+    String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
+        "smalldatetime", "datetime2", "datetimeoffset"};
+
+    /**
+     * 鏁版嵁搴撴暟瀛楃被鍨�
+     */
+    String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
+        "bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision",
+        "smallserial", "serial", "bigserial", "money", "smallmoney"};
+
+    /**
+     * BO瀵硅薄 涓嶉渶瑕佹坊鍔犲瓧娈�
+     */
+    String[] COLUMNNAME_NOT_ADD = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+        "update_time", "version", "tenant_id"};
+
+    /**
+     * BO瀵硅薄 涓嶉渶瑕佺紪杈戝瓧娈�
+     */
+    String[] COLUMNNAME_NOT_EDIT = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+        "update_time", "version", "tenant_id"};
+
+    /**
+     * VO瀵硅薄 涓嶉渶瑕佽繑鍥炲瓧娈�
+     */
+    String[] COLUMNNAME_NOT_LIST = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+        "update_time", "version", "tenant_id"};
+
+    /**
+     * BO瀵硅薄 涓嶉渶瑕佹煡璇㈠瓧娈�
+     */
+    String[] COLUMNNAME_NOT_QUERY = {"id", "create_dept", "create_by", "create_time", "del_flag", "update_by",
+        "update_time", "remark", "version", "tenant_id"};
+
+    /**
+     * Entity鍩虹被瀛楁
+     */
+    String[] BASE_ENTITY = {"createDept", "createBy", "createTime", "updateBy", "updateTime", "tenantId"};
+
+    /**
+     * 鏂囨湰妗�
+     */
+    String HTML_INPUT = "input";
+
+    /**
+     * 鏂囨湰鍩�
+     */
+    String HTML_TEXTAREA = "textarea";
+
+    /**
+     * 涓嬫媺妗�
+     */
+    String HTML_SELECT = "select";
+
+    /**
+     * 鍗曢�夋
+     */
+    String HTML_RADIO = "radio";
+
+    /**
+     * 澶嶉�夋
+     */
+    String HTML_CHECKBOX = "checkbox";
+
+    /**
+     * 鏃ユ湡鎺т欢
+     */
+    String HTML_DATETIME = "datetime";
+
+    /**
+     * 鍥剧墖涓婁紶鎺т欢
+     */
+    String HTML_IMAGE_UPLOAD = "imageUpload";
+
+    /**
+     * 鏂囦欢涓婁紶鎺т欢
+     */
+    String HTML_FILE_UPLOAD = "fileUpload";
+
+    /**
+     * 瀵屾枃鏈帶浠�
+     */
+    String HTML_EDITOR = "editor";
+
+    /**
+     * 瀛楃涓茬被鍨�
+     */
+    String TYPE_STRING = "String";
+
+    /**
+     * 鏁村瀷
+     */
+    String TYPE_INTEGER = "Integer";
+
+    /**
+     * 闀挎暣鍨�
+     */
+    String TYPE_LONG = "Long";
+
+    /**
+     * 娴偣鍨�
+     */
+    String TYPE_DOUBLE = "Double";
+
+    /**
+     * 楂樼簿搴﹁绠楃被鍨�
+     */
+    String TYPE_BIGDECIMAL = "BigDecimal";
+
+    /**
+     * 鏃堕棿绫诲瀷
+     */
+    String TYPE_DATE = "Date";
+
+    /**
+     * 妯$硦鏌ヨ
+     */
+    String QUERY_LIKE = "LIKE";
+
+    /**
+     * 鐩哥瓑鏌ヨ
+     */
+    String QUERY_EQ = "EQ";
+
+    /**
+     * 闇�瑕�
+     */
+    String REQUIRE = "1";
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java
new file mode 100644
index 0000000..e3d4c08
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java
@@ -0,0 +1,217 @@
+package org.dromara.generator.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IoUtil;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.generator.domain.GenTable;
+import org.dromara.generator.domain.GenTableColumn;
+import org.dromara.generator.service.IGenTableService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/tool/gen")
+public class GenController extends BaseController {
+
+    private final IGenTableService genTableService;
+
+    /**
+     * 鏌ヨ浠g爜鐢熸垚鍒楄〃
+     */
+    @SaCheckPermission("tool:gen:list")
+    @GetMapping("/list")
+    public TableDataInfo<GenTable> genList(GenTable genTable, PageQuery pageQuery) {
+        return genTableService.selectPageGenTableList(genTable, pageQuery);
+    }
+
+    /**
+     * 淇敼浠g爜鐢熸垚涓氬姟
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:query")
+    @GetMapping(value = "/{tableId}")
+    public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
+        GenTable table = genTableService.selectGenTableById(tableId);
+        List<GenTable> tables = genTableService.selectGenTableAll();
+        List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
+        Map<String, Object> map = new HashMap<>(3);
+        map.put("info", table);
+        map.put("rows", list);
+        map.put("tables", tables);
+        return R.ok(map);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁搴撳垪琛�
+     */
+    @SaCheckPermission("tool:gen:list")
+    @GetMapping("/db/list")
+    public TableDataInfo<GenTable> dataList(GenTable genTable, PageQuery pageQuery) {
+        return genTableService.selectPageDbTableList(genTable, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:list")
+    @GetMapping(value = "/column/{tableId}")
+    public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
+        TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
+        List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
+        dataInfo.setRows(list);
+        dataInfo.setTotal(list.size());
+        return dataInfo;
+    }
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
+     *
+     * @param tables 琛ㄥ悕涓�
+     */
+    @SaCheckPermission("tool:gen:import")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.IMPORT)
+    @PostMapping("/importTable")
+    public R<Void> importTableSave(String tables, String dataName) {
+        String[] tableNames = Convert.toStrArray(tables);
+        // 鏌ヨ琛ㄤ俊鎭�
+        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames, dataName);
+        genTableService.importGenTable(tableList, dataName);
+        return R.ok();
+    }
+
+    /**
+     * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+     */
+    @SaCheckPermission("tool:gen:edit")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> editSave(@Validated @RequestBody GenTable genTable) {
+        genTableService.validateEdit(genTable);
+        genTableService.updateGenTable(genTable);
+        return R.ok();
+    }
+
+    /**
+     * 鍒犻櫎浠g爜鐢熸垚
+     *
+     * @param tableIds 琛↖D涓�
+     */
+    @SaCheckPermission("tool:gen:remove")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tableIds}")
+    public R<Void> remove(@PathVariable Long[] tableIds) {
+        genTableService.deleteGenTableByIds(tableIds);
+        return R.ok();
+    }
+
+    /**
+     * 棰勮浠g爜
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:preview")
+    @GetMapping("/preview/{tableId}")
+    public R<Map<String, String>> preview(@PathVariable("tableId") Long tableId) throws IOException {
+        Map<String, String> dataMap = genTableService.previewCode(tableId);
+        return R.ok(dataMap);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:code")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/download/{tableId}")
+    public void download(HttpServletResponse response, @PathVariable("tableId") Long tableId) throws IOException {
+        byte[] data = genTableService.downloadCode(tableId);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:code")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/genCode/{tableId}")
+    public R<Void> genCode(@PathVariable("tableId") Long tableId) {
+        genTableService.generatorCode(tableId);
+        return R.ok();
+    }
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     *
+     * @param tableId 琛↖D
+     */
+    @SaCheckPermission("tool:gen:edit")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @GetMapping("/synchDb/{tableId}")
+    public R<Void> synchDb(@PathVariable("tableId") Long tableId) {
+        genTableService.synchDb(tableId);
+        return R.ok();
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜
+     *
+     * @param tableIdStr 琛↖D涓�
+     */
+    @SaCheckPermission("tool:gen:code")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/batchGenCode")
+    public void batchGenCode(HttpServletResponse response, String tableIdStr) throws IOException {
+        String[] tableIds = Convert.toStrArray(tableIdStr);
+        byte[] data = genTableService.downloadCode(tableIds);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚zip鏂囦欢
+     */
+    private void genCode(HttpServletResponse response, byte[] data) throws IOException {
+        response.reset();
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
+        response.addHeader("Content-Length", "" + data.length);
+        response.setContentType("application/octet-stream; charset=UTF-8");
+        IoUtil.write(response.getOutputStream(), false, data);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁婧愬悕绉板垪琛�
+     */
+    @SaCheckPermission("tool:gen:list")
+    @GetMapping(value = "/getDataNames")
+    public R<Object> getCurrentDataSourceNameList(){
+        return R.ok(DataBaseHelper.getDataSourceNameList());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
new file mode 100644
index 0000000..f792ceb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java
@@ -0,0 +1,196 @@
+package org.dromara.generator.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.generator.constant.GenConstants;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * 涓氬姟琛� gen_table
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table")
+public class GenTable extends BaseEntity {
+
+    /**
+     * 缂栧彿
+     */
+    @TableId(value = "table_id")
+    private Long tableId;
+
+    /**
+     * 鏁版嵁婧愬悕绉�
+     */
+    @NotBlank(message = "鏁版嵁婧愬悕绉颁笉鑳戒负绌�")
+    private String dataName;
+
+    /**
+     * 琛ㄥ悕绉�
+     */
+    @NotBlank(message = "琛ㄥ悕绉颁笉鑳戒负绌�")
+    private String tableName;
+
+    /**
+     * 琛ㄦ弿杩�
+     */
+    @NotBlank(message = "琛ㄦ弿杩颁笉鑳戒负绌�")
+    private String tableComment;
+
+    /**
+     * 鍏宠仈鐖惰〃鐨勮〃鍚�
+     */
+    private String subTableName;
+
+    /**
+     * 鏈〃鍏宠仈鐖惰〃鐨勫閿悕
+     */
+    private String subTableFkName;
+
+    /**
+     * 瀹炰綋绫诲悕绉�(棣栧瓧姣嶅ぇ鍐�)
+     */
+    @NotBlank(message = "瀹炰綋绫诲悕绉颁笉鑳戒负绌�")
+    private String className;
+
+    /**
+     * 浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔 sub涓诲瓙琛ㄦ搷浣滐級
+     */
+    private String tplCategory;
+
+    /**
+     * 鐢熸垚鍖呰矾寰�
+     */
+    @NotBlank(message = "鐢熸垚鍖呰矾寰勪笉鑳戒负绌�")
+    private String packageName;
+
+    /**
+     * 鐢熸垚妯″潡鍚�
+     */
+    @NotBlank(message = "鐢熸垚妯″潡鍚嶄笉鑳戒负绌�")
+    private String moduleName;
+
+    /**
+     * 鐢熸垚涓氬姟鍚�
+     */
+    @NotBlank(message = "鐢熸垚涓氬姟鍚嶄笉鑳戒负绌�")
+    private String businessName;
+
+    /**
+     * 鐢熸垚鍔熻兘鍚�
+     */
+    @NotBlank(message = "鐢熸垚鍔熻兘鍚嶄笉鑳戒负绌�")
+    private String functionName;
+
+    /**
+     * 鐢熸垚浣滆��
+     */
+    @NotBlank(message = "浣滆�呬笉鑳戒负绌�")
+    private String functionAuthor;
+
+    /**
+     * 鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級
+     */
+    private String genType;
+
+    /**
+     * 鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級
+     */
+    @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+    private String genPath;
+
+    /**
+     * 涓婚敭淇℃伅
+     */
+    @TableField(exist = false)
+    private GenTableColumn pkColumn;
+
+    /**
+     * 琛ㄥ垪淇℃伅
+     */
+    @Valid
+    @TableField(exist = false)
+    private List<GenTableColumn> columns;
+
+    /**
+     * 鍏跺畠鐢熸垚閫夐」
+     */
+    private String options;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鏍戠紪鐮佸瓧娈�
+     */
+    @TableField(exist = false)
+    private String treeCode;
+
+    /**
+     * 鏍戠埗缂栫爜瀛楁
+     */
+    @TableField(exist = false)
+    private String treeParentCode;
+
+    /**
+     * 鏍戝悕绉板瓧娈�
+     */
+    @TableField(exist = false)
+    private String treeName;
+
+    /*
+     * 鑿滃崟id鍒楄〃
+     */
+    @TableField(exist = false)
+    private List<Long> menuIds;
+
+    /**
+     * 涓婄骇鑿滃崟ID瀛楁
+     */
+    @TableField(exist = false)
+    private String parentMenuId;
+
+    /**
+     * 涓婄骇鑿滃崟鍚嶇О瀛楁
+     */
+    @TableField(exist = false)
+    private String parentMenuName;
+
+    public boolean isTree() {
+        return isTree(this.tplCategory);
+    }
+
+    public static boolean isTree(String tplCategory) {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
+    }
+
+    public boolean isCrud() {
+        return isCrud(this.tplCategory);
+    }
+
+    public static boolean isCrud(String tplCategory) {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
+    }
+
+    public boolean isSuperColumn(String javaField) {
+        return isSuperColumn(this.tplCategory, javaField);
+    }
+
+    public static boolean isSuperColumn(String tplCategory, String javaField) {
+        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
new file mode 100644
index 0000000..e1560b4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java
@@ -0,0 +1,222 @@
+package org.dromara.generator.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.JdbcType;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 浠g爜鐢熸垚涓氬姟瀛楁琛� gen_table_column
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table_column")
+public class GenTableColumn extends BaseEntity {
+
+    /**
+     * 缂栧彿
+     */
+    @TableId(value = "column_id")
+    private Long columnId;
+
+    /**
+     * 褰掑睘琛ㄧ紪鍙�
+     */
+    private Long tableId;
+
+    /**
+     * 鍒楀悕绉�
+     */
+    private String columnName;
+
+    /**
+     * 鍒楁弿杩�
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String columnComment;
+
+    /**
+     * 鍒楃被鍨�
+     */
+    private String columnType;
+
+    /**
+     * JAVA绫诲瀷
+     */
+    private String javaType;
+
+    /**
+     * JAVA瀛楁鍚�
+     */
+    @NotBlank(message = "Java灞炴�т笉鑳戒负绌�")
+    private String javaField;
+
+    /**
+     * 鏄惁涓婚敭锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isPk;
+
+    /**
+     * 鏄惁鑷锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isIncrement;
+
+    /**
+     * 鏄惁蹇呭~锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isRequired;
+
+    /**
+     * 鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isInsert;
+
+    /**
+     * 鏄惁缂栬緫瀛楁锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isEdit;
+
+    /**
+     * 鏄惁鍒楄〃瀛楁锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isList;
+
+    /**
+     * 鏄惁鏌ヨ瀛楁锛�1鏄級
+     */
+    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
+    private String isQuery;
+
+    /**
+     * 鏌ヨ鏂瑰紡锛圗Q绛変簬銆丯E涓嶇瓑浜庛�丟T澶т簬銆丩T灏忎簬銆丩IKE妯$硦銆丅ETWEEN鑼冨洿锛�
+     */
+    private String queryType;
+
+    /**
+     * 鏄剧ず绫诲瀷锛坕nput鏂囨湰妗嗐�乼extarea鏂囨湰鍩熴�乻elect涓嬫媺妗嗐�乧heckbox澶嶉�夋銆乺adio鍗曢�夋銆乨atetime鏃ユ湡鎺т欢銆乮mage鍥剧墖涓婁紶鎺т欢銆乽pload鏂囦欢涓婁紶鎺т欢銆乪ditor瀵屾枃鏈帶浠讹級
+     */
+    private String htmlType;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    private String dictType;
+
+    /**
+     * 鎺掑簭
+     */
+    private Integer sort;
+
+    public String getCapJavaField() {
+        return StringUtils.capitalize(javaField);
+    }
+
+    public boolean isPk() {
+        return isPk(this.isPk);
+    }
+
+    public boolean isPk(String isPk) {
+        return isPk != null && StringUtils.equals("1", isPk);
+    }
+
+    public boolean isIncrement() {
+        return isIncrement(this.isIncrement);
+    }
+
+    public boolean isIncrement(String isIncrement) {
+        return isIncrement != null && StringUtils.equals("1", isIncrement);
+    }
+
+    public boolean isRequired() {
+        return isRequired(this.isRequired);
+    }
+
+    public boolean isRequired(String isRequired) {
+        return isRequired != null && StringUtils.equals("1", isRequired);
+    }
+
+    public boolean isInsert() {
+        return isInsert(this.isInsert);
+    }
+
+    public boolean isInsert(String isInsert) {
+        return isInsert != null && StringUtils.equals("1", isInsert);
+    }
+
+    public boolean isEdit() {
+        return isInsert(this.isEdit);
+    }
+
+    public boolean isEdit(String isEdit) {
+        return isEdit != null && StringUtils.equals("1", isEdit);
+    }
+
+    public boolean isList() {
+        return isList(this.isList);
+    }
+
+    public boolean isList(String isList) {
+        return isList != null && StringUtils.equals("1", isList);
+    }
+
+    public boolean isQuery() {
+        return isQuery(this.isQuery);
+    }
+
+    public boolean isQuery(String isQuery) {
+        return isQuery != null && StringUtils.equals("1", isQuery);
+    }
+
+    public boolean isSuperColumn() {
+        return isSuperColumn(this.javaField);
+    }
+
+    public static boolean isSuperColumn(String javaField) {
+        return StringUtils.equalsAnyIgnoreCase(javaField,
+            // BaseEntity
+            "createBy", "createTime", "updateBy", "updateTime",
+            // TreeEntity
+            "parentName", "parentId");
+    }
+
+    public boolean isUsableColumn() {
+        return isUsableColumn(javaField);
+    }
+
+    public static boolean isUsableColumn(String javaField) {
+        // isSuperColumn()涓殑鍚嶅崟鐢ㄤ簬閬垮厤鐢熸垚澶氫綑Domain灞炴�э紝鑻ユ煇浜涘睘鎬у湪鐢熸垚椤甸潰鏃堕渶瑕佺敤鍒颁笉鑳藉拷鐣ワ紝鍒欐斁鍦ㄦ澶勭櫧鍚嶅崟
+        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+    }
+
+    public String readConverterExp() {
+        String remarks = StringUtils.substringBetween(this.columnComment, "锛�", "锛�");
+        StringBuffer sb = new StringBuffer();
+        if (StringUtils.isNotEmpty(remarks)) {
+            for (String value : remarks.split(" ")) {
+                if (StringUtils.isNotEmpty(value)) {
+                    Object startStr = value.subSequence(0, 1);
+                    String endStr = value.substring(1);
+                    sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR);
+                }
+            }
+            return sb.deleteCharAt(sb.length() - 1).toString();
+        } else {
+            return this.columnComment;
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
new file mode 100644
index 0000000..ed8ed20
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.generator.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.generator.domain.GenTableColumn;
+
+/**
+ * 涓氬姟瀛楁 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
+public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn, GenTableColumn> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
new file mode 100644
index 0000000..63f4c15
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java
@@ -0,0 +1,45 @@
+package org.dromara.generator.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.generator.domain.GenTable;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 涓氬姟 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
+public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     *
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    List<GenTable> selectGenTableAll();
+
+    /**
+     * 鏌ヨ琛↖D涓氬姟淇℃伅
+     *
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    GenTable selectGenTableById(Long id);
+
+    /**
+     * 鏌ヨ琛ㄥ悕绉颁笟鍔′俊鎭�
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @return 涓氬姟淇℃伅
+     */
+    GenTable selectGenTableByName(String tableName);
+
+    @DS("")
+    List<String> selectTableNameList(String dataName);
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
new file mode 100644
index 0000000..99935f7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java
@@ -0,0 +1,577 @@
+package org.dromara.generator.service;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.anyline.metadata.Column;
+import org.anyline.metadata.Table;
+import org.anyline.proxy.ServiceProxy;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.generator.constant.GenConstants;
+import org.dromara.generator.domain.GenTable;
+import org.dromara.generator.domain.GenTableColumn;
+import org.dromara.generator.mapper.GenTableColumnMapper;
+import org.dromara.generator.mapper.GenTableMapper;
+import org.dromara.generator.util.GenUtils;
+import org.dromara.generator.util.VelocityInitializer;
+import org.dromara.generator.util.VelocityUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 涓氬姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class GenTableServiceImpl implements IGenTableService {
+
+    private final GenTableMapper baseMapper;
+    private final GenTableColumnMapper genTableColumnMapper;
+    private final IdentifierGenerator identifierGenerator;
+
+    private static final String[] TABLE_IGNORE = new String[]{"sj_", "act_", "flw_", "gen_"};
+
+    /**
+     * 鏌ヨ涓氬姟瀛楁鍒楄〃
+     *
+     * @param tableId 涓氬姟瀛楁缂栧彿
+     * @return 涓氬姟瀛楁闆嗗悎
+     */
+    @Override
+    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
+        return genTableColumnMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
+            .eq(GenTableColumn::getTableId, tableId)
+            .orderByAsc(GenTableColumn::getSort));
+    }
+
+    /**
+     * 鏌ヨ涓氬姟淇℃伅
+     *
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    @Override
+    public GenTable selectGenTableById(Long id) {
+        GenTable genTable = baseMapper.selectGenTableById(id);
+        setTableFromOptions(genTable);
+        return genTable;
+    }
+
+    @Override
+    public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
+        Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
+        return TableDataInfo.build(page);
+    }
+
+    private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
+        Map<String, Object> params = genTable.getParams();
+        QueryWrapper<GenTable> wrapper = Wrappers.query();
+        wrapper
+            .eq(StringUtils.isNotEmpty(genTable.getDataName()), "data_name", genTable.getDataName())
+            .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
+            .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                "create_time", params.get("beginTime"), params.get("endTime"));
+        return wrapper;
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁搴撳垪琛�
+     *
+     * @param genTable  鍖呭惈鏌ヨ鏉′欢鐨凣enTable瀵硅薄
+     * @param pageQuery 鍖呭惈鍒嗛〉淇℃伅鐨凱ageQuery瀵硅薄
+     * @return 鍖呭惈鍒嗛〉缁撴灉鐨凾ableDataInfo瀵硅薄
+     */
+    @DS("#genTable.dataName")
+    @Override
+    public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
+        // 鑾峰彇鏌ヨ鏉′欢
+        String tableName = genTable.getTableName();
+        String tableComment = genTable.getTableComment();
+
+        LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
+        if (CollUtil.isEmpty(tablesMap)) {
+            return TableDataInfo.build();
+        }
+        List<String> tableNames = baseMapper.selectTableNameList(genTable.getDataName());
+        String[] tableArrays;
+        if (CollUtil.isNotEmpty(tableNames)) {
+            tableArrays = tableNames.toArray(new String[0]);
+        } else {
+            tableArrays = new String[0];
+        }
+        // 杩囨护骞惰浆鎹㈣〃鏍兼暟鎹�
+        List<GenTable> tables = tablesMap.values().stream()
+            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> {
+                if (CollUtil.isEmpty(tableNames)) {
+                    return true;
+                }
+                return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays);
+            })
+            .filter(x -> {
+                boolean nameMatches = true;
+                boolean commentMatches = true;
+                // 杩涜琛ㄥ悕绉扮殑妯$硦鏌ヨ
+                if (StringUtils.isNotBlank(tableName)) {
+                    nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName);
+                }
+                // 杩涜琛ㄦ弿杩扮殑妯$硦鏌ヨ
+                if (StringUtils.isNotBlank(tableComment)) {
+                    commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment);
+                }
+                // 鍚屾椂鍖归厤鍚嶇О鍜屾弿杩�
+                return nameMatches && commentMatches;
+            })
+            .map(x -> {
+                GenTable gen = new GenTable();
+                gen.setTableName(x.getName());
+                gen.setTableComment(x.getComment());
+                gen.setCreateTime(x.getCreateTime());
+                gen.setUpdateTime(x.getUpdateTime());
+                return gen;
+            }).toList();
+
+        IPage<GenTable> page = pageQuery.build();
+        page.setTotal(tables.size());
+        // 鎵嬪姩鍒嗛〉 set鏁版嵁
+        page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables));
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     *
+     * @param tableNames 琛ㄥ悕绉扮粍
+     * @param dataName   鏁版嵁婧愬悕绉�
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    @DS("#dataName")
+    @Override
+    public List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName) {
+        Set<String> tableNameSet = new HashSet<>(List.of(tableNames));
+        LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
+
+        if (CollUtil.isEmpty(tablesMap)) {
+            return new ArrayList<>();
+        }
+
+        List<Table<?>> tableList = tablesMap.values().stream()
+            .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE))
+            .filter(x -> tableNameSet.contains(x.getName())).toList();
+
+        if (CollUtil.isEmpty(tableList)) {
+            return new ArrayList<>();
+        }
+        return tableList.stream().map(x -> {
+            GenTable gen = new GenTable();
+            gen.setDataName(dataName);
+            gen.setTableName(x.getName());
+            gen.setTableComment(x.getComment());
+            gen.setCreateTime(x.getCreateTime());
+            gen.setUpdateTime(x.getUpdateTime());
+            return gen;
+        }).toList();
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     *
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    @Override
+    public List<GenTable> selectGenTableAll() {
+        return baseMapper.selectGenTableAll();
+    }
+
+    /**
+     * 淇敼涓氬姟
+     *
+     * @param genTable 涓氬姟淇℃伅
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void updateGenTable(GenTable genTable) {
+        String options = JsonUtils.toJsonString(genTable.getParams());
+        genTable.setOptions(options);
+        int row = baseMapper.updateById(genTable);
+        if (row > 0) {
+            for (GenTableColumn cenTableColumn : genTable.getColumns()) {
+                genTableColumnMapper.updateById(cenTableColumn);
+            }
+        }
+    }
+
+    /**
+     * 鍒犻櫎涓氬姟瀵硅薄
+     *
+     * @param tableIds 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void deleteGenTableByIds(Long[] tableIds) {
+        List<Long> ids = Arrays.asList(tableIds);
+        baseMapper.deleteByIds(ids);
+        genTableColumnMapper.delete(new LambdaQueryWrapper<GenTableColumn>().in(GenTableColumn::getTableId, ids));
+    }
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋�
+     *
+     * @param tableList 瀵煎叆琛ㄥ垪琛�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     */
+    @DSTransactional
+    @Override
+    public void importGenTable(List<GenTable> tableList, String dataName) {
+        Long operId = LoginHelper.getUserId();
+        try {
+            for (GenTable table : tableList) {
+                String tableName = table.getTableName();
+                GenUtils.initTable(table, operId);
+                table.setDataName(dataName);
+                int row = baseMapper.insert(table);
+                if (row > 0) {
+                    // 淇濆瓨鍒椾俊鎭�
+                    List<GenTableColumn> genTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(tableName, dataName);
+                    List<GenTableColumn> saveColumns = new ArrayList<>();
+                    for (GenTableColumn column : genTableColumns) {
+                        GenUtils.initColumnField(column, table);
+                        saveColumns.add(column);
+                    }
+                    if (CollUtil.isNotEmpty(saveColumns)) {
+                        genTableColumnMapper.insertBatch(saveColumns);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new ServiceException("瀵煎叆澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     * @return 鍒椾俊鎭�
+     */
+    @DS("#dataName")
+    @Override
+    public List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName) {
+        LinkedHashMap<String, Column> columns = ServiceProxy.metadata().columns(tableName);
+        List<GenTableColumn> tableColumns = new ArrayList<>();
+        columns.forEach((columnName, column) -> {
+            GenTableColumn tableColumn = new GenTableColumn();
+            tableColumn.setIsPk(String.valueOf(column.isPrimaryKey()));
+            tableColumn.setColumnName(column.getName());
+            tableColumn.setColumnComment(column.getComment());
+            tableColumn.setColumnType(column.getTypeName().toLowerCase());
+            tableColumn.setSort(column.getPosition());
+            tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0");
+            tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1");
+            tableColumns.add(tableColumn);
+        });
+        return tableColumns;
+    }
+
+    /**
+     * 棰勮浠g爜
+     *
+     * @param tableId 琛ㄧ紪鍙�
+     * @return 棰勮鏁版嵁鍒楄〃
+     */
+    @Override
+    public Map<String, String> previewCode(Long tableId) {
+        Map<String, String> dataMap = new LinkedHashMap<>();
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = baseMapper.selectGenTableById(tableId);
+        List<Long> menuIds = new ArrayList<>();
+        for (int i = 0; i < 6; i++) {
+            menuIds.add(identifierGenerator.nextId(null).longValue());
+        }
+        table.setMenuIds(menuIds);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates) {
+            // 娓叉煋妯℃澘
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            dataMap.put(template, sw.toString());
+        }
+        return dataMap;
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     *
+     * @param tableId 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    @Override
+    public byte[] downloadCode(Long tableId) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        generatorCode(tableId, zip);
+        IoUtil.close(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     *
+     * @param tableId 琛ㄥ悕绉�
+     */
+    @Override
+    public void generatorCode(Long tableId) {
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = baseMapper.selectGenTableById(tableId);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates) {
+            if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) {
+                // 娓叉煋妯℃澘
+                StringWriter sw = new StringWriter();
+                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+                tpl.merge(context, sw);
+                try {
+                    String path = getGenPath(table, template);
+                    FileUtils.writeUtf8String(sw.toString(), path);
+                } catch (Exception e) {
+                    throw new ServiceException("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     *
+     * @param tableId 琛ㄥ悕绉�
+     */
+    @DSTransactional
+    @Override
+    public void synchDb(Long tableId) {
+        GenTable table = baseMapper.selectGenTableById(tableId);
+        List<GenTableColumn> tableColumns = table.getColumns();
+        Map<String, GenTableColumn> tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);
+
+        List<GenTableColumn> dbTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(table.getTableName(), table.getDataName());
+        if (CollUtil.isEmpty(dbTableColumns)) {
+            throw new ServiceException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
+        }
+        List<String> dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName);
+
+        List<GenTableColumn> saveColumns = new ArrayList<>();
+        dbTableColumns.forEach(column -> {
+            GenUtils.initColumnField(column, table);
+            if (tableColumnMap.containsKey(column.getColumnName())) {
+                GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
+                column.setColumnId(prevColumn.getColumnId());
+                if (column.isList()) {
+                    // 濡傛灉鏄垪琛紝缁х画淇濈暀鏌ヨ鏂瑰紡/瀛楀吀绫诲瀷閫夐」
+                    column.setDictType(prevColumn.getDictType());
+                    column.setQueryType(prevColumn.getQueryType());
+                }
+                if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
+                    && (column.isInsert() || column.isEdit())
+                    && ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
+                    // 濡傛灉鏄�(鏂板/淇敼&闈炰富閿�/闈炲拷鐣ュ強鐖跺睘鎬�)锛岀户缁繚鐣欏繀濉�/鏄剧ず绫诲瀷閫夐」
+                    column.setIsRequired(prevColumn.getIsRequired());
+                    column.setHtmlType(prevColumn.getHtmlType());
+                }
+            }
+            saveColumns.add(column);
+        });
+        if (CollUtil.isNotEmpty(saveColumns)) {
+            genTableColumnMapper.insertOrUpdateBatch(saveColumns);
+        }
+        List<GenTableColumn> delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName()));
+        if (CollUtil.isNotEmpty(delColumns)) {
+            List<Long> ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
+            if (CollUtil.isNotEmpty(ids)) {
+                genTableColumnMapper.deleteByIds(ids);
+            }
+        }
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     *
+     * @param tableIds 琛↖D鏁扮粍
+     * @return 鏁版嵁
+     */
+    @Override
+    public byte[] downloadCode(String[] tableIds) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        for (String tableId : tableIds) {
+            generatorCode(Long.parseLong(tableId), zip);
+        }
+        IoUtil.close(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 鏌ヨ琛ㄤ俊鎭苟鐢熸垚浠g爜
+     */
+    private void generatorCode(Long tableId, ZipOutputStream zip) {
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = baseMapper.selectGenTableById(tableId);
+        List<Long> menuIds = new ArrayList<>();
+        for (int i = 0; i < 6; i++) {
+            menuIds.add(identifierGenerator.nextId(null).longValue());
+        }
+        table.setMenuIds(menuIds);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates) {
+            // 娓叉煋妯℃澘
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            try {
+                // 娣诲姞鍒皕ip
+                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+                IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
+                IoUtil.close(sw);
+                zip.flush();
+                zip.closeEntry();
+            } catch (IOException e) {
+                log.error("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName(), e);
+            }
+        }
+    }
+
+    /**
+     * 淇敼淇濆瓨鍙傛暟鏍¢獙
+     *
+     * @param genTable 涓氬姟淇℃伅
+     */
+    @Override
+    public void validateEdit(GenTable genTable) {
+        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
+            String options = JsonUtils.toJsonString(genTable.getParams());
+            Dict paramsObj = JsonUtils.parseMap(options);
+            if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) {
+                throw new ServiceException("鏍戠紪鐮佸瓧娈典笉鑳戒负绌�");
+            } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) {
+                throw new ServiceException("鏍戠埗缂栫爜瀛楁涓嶈兘涓虹┖");
+            } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) {
+                throw new ServiceException("鏍戝悕绉板瓧娈典笉鑳戒负绌�");
+            }
+        }
+    }
+
+    /**
+     * 璁剧疆涓婚敭鍒椾俊鎭�
+     *
+     * @param table 涓氬姟琛ㄤ俊鎭�
+     */
+    public void setPkColumn(GenTable table) {
+        for (GenTableColumn column : table.getColumns()) {
+            if (column.isPk()) {
+                table.setPkColumn(column);
+                break;
+            }
+        }
+        if (ObjectUtil.isNull(table.getPkColumn())) {
+            table.setPkColumn(table.getColumns().get(0));
+        }
+
+    }
+
+    /**
+     * 璁剧疆浠g爜鐢熸垚鍏朵粬閫夐」鍊�
+     *
+     * @param genTable 璁剧疆鍚庣殑鐢熸垚瀵硅薄
+     */
+    public void setTableFromOptions(GenTable genTable) {
+        Dict paramsObj = JsonUtils.parseMap(genTable.getOptions());
+        if (ObjectUtil.isNotNull(paramsObj)) {
+            String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
+            String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
+            String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
+            String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+            String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
+
+            genTable.setTreeCode(treeCode);
+            genTable.setTreeParentCode(treeParentCode);
+            genTable.setTreeName(treeName);
+            genTable.setParentMenuId(parentMenuId);
+            genTable.setParentMenuName(parentMenuName);
+        }
+    }
+
+    /**
+     * 鑾峰彇浠g爜鐢熸垚鍦板潃
+     *
+     * @param table    涓氬姟琛ㄤ俊鎭�
+     * @param template 妯℃澘鏂囦欢璺緞
+     * @return 鐢熸垚鍦板潃
+     */
+    public static String getGenPath(GenTable table, String template) {
+        String genPath = table.getGenPath();
+        if (StringUtils.equals(genPath, "/")) {
+            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+        }
+        return genPath + File.separator + VelocityUtils.getFileName(template, table);
+    }
+}
+
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
new file mode 100644
index 0000000..b2c20c5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java
@@ -0,0 +1,141 @@
+package org.dromara.generator.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.generator.domain.GenTable;
+import org.dromara.generator.domain.GenTableColumn;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 涓氬姟 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface IGenTableService {
+
+    /**
+     * 鏌ヨ涓氬姟瀛楁鍒楄〃
+     *
+     * @param tableId 涓氬姟瀛楁缂栧彿
+     * @return 涓氬姟瀛楁闆嗗悎
+     */
+    List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+    /**
+     * 鏌ヨ涓氬姟鍒楄〃
+     *
+     * @param genTable 涓氬姟淇℃伅
+     * @return 涓氬姟闆嗗悎
+     */
+    TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     *
+     * @param genTable 涓氬姟淇℃伅
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     *
+     * @param tableNames 琛ㄥ悕绉扮粍
+     * @param dataName   鏁版嵁婧愬悕绉�
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName);
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     *
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    List<GenTable> selectGenTableAll();
+
+    /**
+     * 鏌ヨ涓氬姟淇℃伅
+     *
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    GenTable selectGenTableById(Long id);
+
+    /**
+     * 淇敼涓氬姟
+     *
+     * @param genTable 涓氬姟淇℃伅
+     */
+    void updateGenTable(GenTable genTable);
+
+    /**
+     * 鍒犻櫎涓氬姟淇℃伅
+     *
+     * @param tableIds 闇�瑕佸垹闄ょ殑琛ㄦ暟鎹甀D
+     */
+    void deleteGenTableByIds(Long[] tableIds);
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋�
+     *
+     * @param tableList 瀵煎叆琛ㄥ垪琛�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     */
+    void importGenTable(List<GenTable> tableList, String dataName);
+
+    /**
+     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @param dataName  鏁版嵁婧愬悕绉�
+     * @return 鍒椾俊鎭�
+     */
+    List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName);
+
+    /**
+     * 棰勮浠g爜
+     *
+     * @param tableId 琛ㄧ紪鍙�
+     * @return 棰勮鏁版嵁鍒楄〃
+     */
+    Map<String, String> previewCode(Long tableId);
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     *
+     * @param tableId 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    byte[] downloadCode(Long tableId);
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     *
+     * @param tableId 琛ㄥ悕绉�
+     */
+    void generatorCode(Long tableId);
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     *
+     * @param tableId 琛ㄥ悕绉�
+     */
+    void synchDb(Long tableId);
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     *
+     * @param tableIds 琛↖D鏁扮粍
+     * @return 鏁版嵁
+     */
+    byte[] downloadCode(String[] tableIds);
+
+    /**
+     * 淇敼淇濆瓨鍙傛暟鏍¢獙
+     *
+     * @param genTable 涓氬姟淇℃伅
+     */
+    void validateEdit(GenTable genTable);
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
new file mode 100644
index 0000000..2e6b37b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java
@@ -0,0 +1,231 @@
+package org.dromara.generator.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.RegExUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.generator.config.GenConfig;
+import org.dromara.generator.constant.GenConstants;
+import org.dromara.generator.domain.GenTable;
+import org.dromara.generator.domain.GenTableColumn;
+
+import java.util.Arrays;
+
+/**
+ * 浠g爜鐢熸垚鍣� 宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class GenUtils {
+
+    /**
+     * 鍒濆鍖栬〃淇℃伅
+     */
+    public static void initTable(GenTable genTable, Long operId) {
+        genTable.setClassName(convertClassName(genTable.getTableName()));
+        genTable.setPackageName(GenConfig.getPackageName());
+        genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
+        genTable.setBusinessName(getBusinessName(genTable.getTableName()));
+        genTable.setFunctionName(replaceText(genTable.getTableComment()));
+        genTable.setFunctionAuthor(GenConfig.getAuthor());
+        genTable.setCreateBy(operId);
+    }
+
+    /**
+     * 鍒濆鍖栧垪灞炴�у瓧娈�
+     */
+    public static void initColumnField(GenTableColumn column, GenTable table) {
+        String dataType = getDbType(column.getColumnType());
+        String columnName = column.getColumnName();
+        column.setTableId(table.getTableId());
+        column.setCreateBy(table.getCreateBy());
+        // 璁剧疆java瀛楁鍚�
+        column.setJavaField(StringUtils.toCamelCase(columnName));
+        // 璁剧疆榛樿绫诲瀷
+        column.setJavaType(GenConstants.TYPE_STRING);
+        column.setQueryType(GenConstants.QUERY_EQ);
+
+        if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
+            // 瀛楃涓查暱搴﹁秴杩�500璁剧疆涓烘枃鏈煙
+            Integer columnLength = getColumnLength(column.getColumnType());
+            String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
+            column.setHtmlType(htmlType);
+        } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
+            column.setJavaType(GenConstants.TYPE_DATE);
+            column.setHtmlType(GenConstants.HTML_DATETIME);
+        } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
+            column.setHtmlType(GenConstants.HTML_INPUT);
+
+            // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
+            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
+            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
+                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
+            }
+            // 濡傛灉鏄暣褰�
+            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
+                column.setJavaType(GenConstants.TYPE_INTEGER);
+            }
+            // 闀挎暣褰�
+            else {
+                column.setJavaType(GenConstants.TYPE_LONG);
+            }
+        }
+
+        // BO瀵硅薄 榛樿鎻掑叆鍕鹃��
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) {
+            column.setIsInsert(GenConstants.REQUIRE);
+        }
+        // BO瀵硅薄 榛樿缂栬緫鍕鹃��
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+            column.setIsEdit(GenConstants.REQUIRE);
+        }
+        // BO瀵硅薄 榛樿鏄惁蹇呭~鍕鹃��
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+            column.setIsRequired(GenConstants.REQUIRE);
+        }
+        // VO瀵硅薄 榛樿杩斿洖鍕鹃��
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
+            column.setIsList(GenConstants.REQUIRE);
+        }
+        // BO瀵硅薄 榛樿鏌ヨ鍕鹃��
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
+            column.setIsQuery(GenConstants.REQUIRE);
+        }
+
+        // 鏌ヨ瀛楁绫诲瀷
+        if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
+            column.setQueryType(GenConstants.QUERY_LIKE);
+        }
+        // 鐘舵�佸瓧娈佃缃崟閫夋
+        if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
+            column.setHtmlType(GenConstants.HTML_RADIO);
+        }
+        // 绫诲瀷&鎬у埆瀛楁璁剧疆涓嬫媺妗�
+        else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+            || StringUtils.endsWithIgnoreCase(columnName, "sex")) {
+            column.setHtmlType(GenConstants.HTML_SELECT);
+        }
+        // 鍥剧墖瀛楁璁剧疆鍥剧墖涓婁紶鎺т欢
+        else if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
+            column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
+        }
+        // 鏂囦欢瀛楁璁剧疆鏂囦欢涓婁紶鎺т欢
+        else if (StringUtils.endsWithIgnoreCase(columnName, "file")) {
+            column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
+        }
+        // 鍐呭瀛楁璁剧疆瀵屾枃鏈帶浠�
+        else if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
+            column.setHtmlType(GenConstants.HTML_EDITOR);
+        }
+    }
+
+    /**
+     * 鏍¢獙鏁扮粍鏄惁鍖呭惈鎸囧畾鍊�
+     *
+     * @param arr         鏁扮粍
+     * @param targetValue 鍊�
+     * @return 鏄惁鍖呭惈
+     */
+    public static boolean arraysContains(String[] arr, String targetValue) {
+        return Arrays.asList(arr).contains(targetValue);
+    }
+
+    /**
+     * 鑾峰彇妯″潡鍚�
+     *
+     * @param packageName 鍖呭悕
+     * @return 妯″潡鍚�
+     */
+    public static String getModuleName(String packageName) {
+        int lastIndex = packageName.lastIndexOf(".");
+        int nameLength = packageName.length();
+        return StringUtils.substring(packageName, lastIndex + 1, nameLength);
+    }
+
+    /**
+     * 鑾峰彇涓氬姟鍚�
+     *
+     * @param tableName 琛ㄥ悕
+     * @return 涓氬姟鍚�
+     */
+    public static String getBusinessName(String tableName) {
+        int firstIndex = tableName.indexOf("_");
+        int nameLength = tableName.length();
+        String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength);
+        businessName = StringUtils.toCamelCase(businessName);
+        return businessName;
+    }
+
+    /**
+     * 琛ㄥ悕杞崲鎴怞ava绫诲悕
+     *
+     * @param tableName 琛ㄥ悕绉�
+     * @return 绫诲悕
+     */
+    public static String convertClassName(String tableName) {
+        boolean autoRemovePre = GenConfig.getAutoRemovePre();
+        String tablePrefix = GenConfig.getTablePrefix();
+        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) {
+            String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR);
+            tableName = replaceFirst(tableName, searchList);
+        }
+        return StringUtils.convertToCamelCase(tableName);
+    }
+
+    /**
+     * 鎵归噺鏇挎崲鍓嶇紑
+     *
+     * @param replacementm 鏇挎崲鍊�
+     * @param searchList   鏇挎崲鍒楄〃
+     */
+    public static String replaceFirst(String replacementm, String[] searchList) {
+        String text = replacementm;
+        for (String searchString : searchList) {
+            if (replacementm.startsWith(searchString)) {
+                text = replacementm.replaceFirst(searchString, StringUtils.EMPTY);
+                break;
+            }
+        }
+        return text;
+    }
+
+    /**
+     * 鍏抽敭瀛楁浛鎹�
+     *
+     * @param text 闇�瑕佽鏇挎崲鐨勫悕瀛�
+     * @return 鏇挎崲鍚庣殑鍚嶅瓧
+     */
+    public static String replaceText(String text) {
+        return RegExUtils.replaceAll(text, "(?:琛▅鑻ヤ緷)", "");
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁搴撶被鍨嬪瓧娈�
+     *
+     * @param columnType 鍒楃被鍨�
+     * @return 鎴彇鍚庣殑鍒楃被鍨�
+     */
+    public static String getDbType(String columnType) {
+        if (StringUtils.indexOf(columnType, "(") > 0) {
+            return StringUtils.substringBefore(columnType, "(");
+        } else {
+            return columnType;
+        }
+    }
+
+    /**
+     * 鑾峰彇瀛楁闀垮害
+     *
+     * @param columnType 鍒楃被鍨�
+     * @return 鎴彇鍚庣殑鍒楃被鍨�
+     */
+    public static Integer getColumnLength(String columnType) {
+        if (StringUtils.indexOf(columnType, "(") > 0) {
+            String length = StringUtils.substringBetween(columnType, "(", ")");
+            return Integer.valueOf(length);
+        } else {
+            return 0;
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java
new file mode 100644
index 0000000..09e0121
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java
@@ -0,0 +1,35 @@
+package org.dromara.generator.util;
+
+import org.dromara.common.core.constant.Constants;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.app.Velocity;
+
+import java.util.Properties;
+
+/**
+ * VelocityEngine宸ュ巶
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class VelocityInitializer {
+
+    /**
+     * 鍒濆鍖杤m鏂规硶
+     */
+    public static void initVelocity() {
+        Properties p = new Properties();
+        try {
+            // 鍔犺浇classpath鐩綍涓嬬殑vm鏂囦欢
+            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+            // 瀹氫箟瀛楃闆�
+            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+            // 鍒濆鍖朧elocity寮曟搸锛屾寚瀹氶厤缃甈roperties
+            Velocity.init(p);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
new file mode 100644
index 0000000..6e111e3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
@@ -0,0 +1,341 @@
+package org.dromara.generator.util;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Dict;
+import org.dromara.generator.constant.GenConstants;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.generator.domain.GenTable;
+import org.dromara.generator.domain.GenTableColumn;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.VelocityContext;
+
+import java.util.*;
+
+/**
+ * 妯℃澘澶勭悊宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class VelocityUtils {
+
+    /**
+     * 椤圭洰绌洪棿璺緞
+     */
+    private static final String PROJECT_PATH = "main/java";
+
+    /**
+     * mybatis绌洪棿璺緞
+     */
+    private static final String MYBATIS_PATH = "main/resources/mapper";
+
+    /**
+     * 榛樿涓婄骇鑿滃崟锛岀郴缁熷伐鍏�
+     */
+    private static final String DEFAULT_PARENT_MENU_ID = "3";
+
+    /**
+     * 璁剧疆妯℃澘鍙橀噺淇℃伅
+     *
+     * @return 妯℃澘鍒楄〃
+     */
+    public static VelocityContext prepareContext(GenTable genTable) {
+        String moduleName = genTable.getModuleName();
+        String businessName = genTable.getBusinessName();
+        String packageName = genTable.getPackageName();
+        String tplCategory = genTable.getTplCategory();
+        String functionName = genTable.getFunctionName();
+
+        VelocityContext velocityContext = new VelocityContext();
+        velocityContext.put("tplCategory", genTable.getTplCategory());
+        velocityContext.put("tableName", genTable.getTableName());
+        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "銆愯濉啓鍔熻兘鍚嶇О銆�");
+        velocityContext.put("ClassName", genTable.getClassName());
+        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
+        velocityContext.put("moduleName", genTable.getModuleName());
+        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
+        velocityContext.put("businessName", genTable.getBusinessName());
+        velocityContext.put("basePackage", getPackagePrefix(packageName));
+        velocityContext.put("packageName", packageName);
+        velocityContext.put("author", genTable.getFunctionAuthor());
+        velocityContext.put("datetime", DateUtils.getDate());
+        velocityContext.put("pkColumn", genTable.getPkColumn());
+        velocityContext.put("importList", getImportList(genTable));
+        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
+        velocityContext.put("columns", genTable.getColumns());
+        velocityContext.put("table", genTable);
+        velocityContext.put("dicts", getDicts(genTable));
+        setMenuVelocityContext(velocityContext, genTable);
+        if (GenConstants.TPL_TREE.equals(tplCategory)) {
+            setTreeVelocityContext(velocityContext, genTable);
+        }
+        return velocityContext;
+    }
+
+    public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
+        String options = genTable.getOptions();
+        Dict paramsObj = JsonUtils.parseMap(options);
+        String parentMenuId = getParentMenuId(paramsObj);
+        context.put("parentMenuId", parentMenuId);
+    }
+
+    public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) {
+        String options = genTable.getOptions();
+        Dict paramsObj = JsonUtils.parseMap(options);
+        String treeCode = getTreecode(paramsObj);
+        String treeParentCode = getTreeParentCode(paramsObj);
+        String treeName = getTreeName(paramsObj);
+
+        context.put("treeCode", treeCode);
+        context.put("treeParentCode", treeParentCode);
+        context.put("treeName", treeName);
+        context.put("expandColumn", getExpandColumn(genTable));
+        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
+            context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE));
+        }
+        if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
+            context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME));
+        }
+    }
+
+    /**
+     * 鑾峰彇妯℃澘淇℃伅
+     *
+     * @return 妯℃澘鍒楄〃
+     */
+    public static List<String> getTemplateList(String tplCategory) {
+        List<String> templates = new ArrayList<>();
+        templates.add("vm/java/domain.java.vm");
+        templates.add("vm/java/vo.java.vm");
+        templates.add("vm/java/bo.java.vm");
+        templates.add("vm/java/mapper.java.vm");
+        templates.add("vm/java/service.java.vm");
+        templates.add("vm/java/serviceImpl.java.vm");
+        templates.add("vm/java/controller.java.vm");
+        templates.add("vm/xml/mapper.xml.vm");
+        if (DataBaseHelper.isOracle()) {
+            templates.add("vm/sql/oracle/sql.vm");
+        } else if (DataBaseHelper.isPostgerSql()) {
+            templates.add("vm/sql/postgres/sql.vm");
+        } else if (DataBaseHelper.isSqlServer()) {
+            templates.add("vm/sql/sqlserver/sql.vm");
+        } else {
+            templates.add("vm/sql/sql.vm");
+        }
+        templates.add("vm/ts/api.ts.vm");
+        templates.add("vm/ts/types.ts.vm");
+        if (GenConstants.TPL_CRUD.equals(tplCategory)) {
+            templates.add("vm/vue/index.vue.vm");
+        } else if (GenConstants.TPL_TREE.equals(tplCategory)) {
+            templates.add("vm/vue/index-tree.vue.vm");
+        }
+        return templates;
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鍚�
+     */
+    public static String getFileName(String template, GenTable genTable) {
+        // 鏂囦欢鍚嶇О
+        String fileName = "";
+        // 鍖呰矾寰�
+        String packageName = genTable.getPackageName();
+        // 妯″潡鍚�
+        String moduleName = genTable.getModuleName();
+        // 澶у啓绫诲悕
+        String className = genTable.getClassName();
+        // 涓氬姟鍚嶇О
+        String businessName = genTable.getBusinessName();
+
+        String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
+        String mybatisPath = MYBATIS_PATH + "/" + moduleName;
+        String vuePath = "vue";
+
+        if (template.contains("domain.java.vm")) {
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
+        }
+        if (template.contains("vo.java.vm")) {
+            fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className);
+        }
+        if (template.contains("bo.java.vm")) {
+            fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className);
+        }
+        if (template.contains("mapper.java.vm")) {
+            fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
+        } else if (template.contains("service.java.vm")) {
+            fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
+        } else if (template.contains("serviceImpl.java.vm")) {
+            fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+        } else if (template.contains("controller.java.vm")) {
+            fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
+        } else if (template.contains("mapper.xml.vm")) {
+            fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
+        } else if (template.contains("sql.vm")) {
+            fileName = businessName + "Menu.sql";
+        } else if (template.contains("api.ts.vm")) {
+            fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName);
+        } else if (template.contains("types.ts.vm")) {
+            fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName);
+        } else if (template.contains("index.vue.vm")) {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        } else if (template.contains("index-tree.vue.vm")) {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        }
+        return fileName;
+    }
+
+    /**
+     * 鑾峰彇鍖呭墠缂�
+     *
+     * @param packageName 鍖呭悕绉�
+     * @return 鍖呭墠缂�鍚嶇О
+     */
+    public static String getPackagePrefix(String packageName) {
+        int lastIndex = packageName.lastIndexOf(".");
+        return StringUtils.substring(packageName, 0, lastIndex);
+    }
+
+    /**
+     * 鏍规嵁鍒楃被鍨嬭幏鍙栧鍏ュ寘
+     *
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 杩斿洖闇�瑕佸鍏ョ殑鍖呭垪琛�
+     */
+    public static HashSet<String> getImportList(GenTable genTable) {
+        List<GenTableColumn> columns = genTable.getColumns();
+        HashSet<String> importList = new HashSet<>();
+        for (GenTableColumn column : columns) {
+            if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) {
+                importList.add("java.util.Date");
+                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
+            } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
+                importList.add("java.math.BigDecimal");
+            } else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) {
+                importList.add("org.dromara.common.translation.annotation.Translation");
+                importList.add("org.dromara.common.translation.constant.TransConstant");
+            }
+        }
+        return importList;
+    }
+
+    /**
+     * 鏍规嵁鍒楃被鍨嬭幏鍙栧瓧鍏哥粍
+     *
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 杩斿洖瀛楀吀缁�
+     */
+    public static String getDicts(GenTable genTable) {
+        List<GenTableColumn> columns = genTable.getColumns();
+        Set<String> dicts = new HashSet<>();
+        addDicts(dicts, columns);
+        return StringUtils.join(dicts, ", ");
+    }
+
+    /**
+     * 娣诲姞瀛楀吀鍒楄〃
+     *
+     * @param dicts 瀛楀吀鍒楄〃
+     * @param columns 鍒楅泦鍚�
+     */
+    public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) {
+        for (GenTableColumn column : columns) {
+            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
+                column.getHtmlType(),
+                new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) {
+                dicts.add("'" + column.getDictType() + "'");
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇鏉冮檺鍓嶇紑
+     *
+     * @param moduleName   妯″潡鍚嶇О
+     * @param businessName 涓氬姟鍚嶇О
+     * @return 杩斿洖鏉冮檺鍓嶇紑
+     */
+    public static String getPermissionPrefix(String moduleName, String businessName) {
+        return StringUtils.format("{}:{}", moduleName, businessName);
+    }
+
+    /**
+     * 鑾峰彇涓婄骇鑿滃崟ID瀛楁
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 涓婄骇鑿滃崟ID瀛楁
+     */
+    public static String getParentMenuId(Dict paramsObj) {
+        if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+            && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) {
+            return paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+        }
+        return DEFAULT_PARENT_MENU_ID;
+    }
+
+    /**
+     * 鑾峰彇鏍戠紪鐮�
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戠紪鐮�
+     */
+    public static String getTreecode(Map<String, Object> paramsObj) {
+        if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) {
+            return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇鏍戠埗缂栫爜
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戠埗缂栫爜
+     */
+    public static String getTreeParentCode(Dict paramsObj) {
+        if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
+            return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇鏍戝悕绉�
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戝悕绉�
+     */
+    public static String getTreeName(Dict paramsObj) {
+        if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) {
+            return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇闇�瑕佸湪鍝竴鍒椾笂闈㈡樉绀哄睍寮�鎸夐挳
+     *
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 灞曞紑鎸夐挳鍒楀簭鍙�
+     */
+    public static int getExpandColumn(GenTable genTable) {
+        String options = genTable.getOptions();
+        Dict paramsObj = JsonUtils.parseMap(options);
+        String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
+        int num = 0;
+        for (GenTableColumn column : genTable.getColumns()) {
+            if (column.isList()) {
+                num++;
+                String columnName = column.getColumnName();
+                if (columnName.equals(treeName)) {
+                    break;
+                }
+            }
+        }
+        return num;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml
new file mode 100644
index 0000000..d779d97
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml
@@ -0,0 +1,10 @@
+# 浠g爜鐢熸垚
+gen:
+  # 浣滆��
+  author: Lion Li
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: org.dromara.system
+  # 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸false
+  autoRemovePre: false
+  # 琛ㄥ墠缂�锛堢敓鎴愮被鍚嶄笉浼氬寘鍚〃鍓嶇紑锛屽涓敤閫楀彿鍒嗛殧锛�
+  tablePrefix: sys_
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
new file mode 100644
index 0000000..fc1c610
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.generator.mapper.GenTableColumnMapper">
+
+    <resultMap type="org.dromara.generator.domain.GenTableColumn" id="GenTableColumnResult">
+    </resultMap>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
new file mode 100644
index 0000000..78aa852
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.generator.mapper.GenTableMapper">
+
+    <!-- 澶氱粨鏋勫祵濂楄嚜鍔ㄦ槧灏勯渶甯︿笂姣忎釜瀹炰綋鐨勪富閿甶d 鍚﹀垯鏄犲皠浼氬け璐� -->
+    <resultMap type="org.dromara.generator.domain.GenTable" id="GenTableResult">
+        <id property="tableId" column="table_id" />
+        <collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
+    </resultMap>
+
+    <resultMap type="org.dromara.generator.domain.GenTableColumn" id="GenTableColumnResult">
+        <id property="columnId" column="column_id"/>
+    </resultMap>
+
+    <sql id="genSelect">
+        SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
+               c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+        FROM gen_table t
+                 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+    </sql>
+
+    <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
+        <include refid="genSelect"/>
+        where t.table_id = #{tableId} order by c.sort
+    </select>
+
+    <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
+        <include refid="genSelect"/>
+        where t.table_name = #{tableName} order by c.sort
+    </select>
+
+    <select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
+        <include refid="genSelect"/>
+        order by c.sort
+    </select>
+
+    <select id="selectTableNameList" resultType="java.lang.String">
+        select table_name from gen_table where data_name = #{dataName,jdbcType=VARCHAR}
+    </select>
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
new file mode 100644
index 0000000..511d37c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm
@@ -0,0 +1,50 @@
+package ${packageName}.domain.bo;
+
+import ${packageName}.domain.${ClassName};
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+/**
+ * ${functionName}涓氬姟瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
+public class ${ClassName}Bo extends BaseEntity {
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
+    /**
+     * $column.columnComment
+     */
+#if($column.insert && $column.edit)
+#set($Group="AddGroup.class, EditGroup.class")
+#elseif($column.insert)
+#set($Group="AddGroup.class")
+#elseif($column.edit)
+#set($Group="EditGroup.class")
+#end
+#if($column.required)
+#if($column.javaType == 'String')
+    @NotBlank(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
+#else
+    @NotNull(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
+#end
+#end
+    private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 0000000..6438971
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,115 @@
+package ${packageName}.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.bo.${ClassName}Bo;
+import ${packageName}.service.I${ClassName}Service;
+#if($table.crud)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/${moduleName}/${businessName}")
+public class ${ClassName}Controller extends BaseController {
+
+    private final I${ClassName}Service ${className}Service;
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     */
+    @SaCheckPermission("${permissionPrefix}:list")
+    @GetMapping("/list")
+#if($table.crud)
+    public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) {
+        return ${className}Service.queryPageList(bo, pageQuery);
+    }
+#elseif($table.tree)
+    public R<List<${ClassName}Vo>> list(${ClassName}Bo bo) {
+        List<${ClassName}Vo> list = ${className}Service.queryList(bo);
+        return R.ok(list);
+    }
+#end
+
+    /**
+     * 瀵煎嚭${functionName}鍒楄〃
+     */
+    @SaCheckPermission("${permissionPrefix}:export")
+    @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(${ClassName}Bo bo, HttpServletResponse response) {
+        List<${ClassName}Vo> list = ${className}Service.queryList(bo);
+        ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response);
+    }
+
+    /**
+     * 鑾峰彇${functionName}璇︾粏淇℃伅
+     *
+     * @param ${pkColumn.javaField} 涓婚敭
+     */
+    @SaCheckPermission("${permissionPrefix}:query")
+    @GetMapping("/{${pkColumn.javaField}}")
+    public R<${ClassName}Vo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) {
+        return R.ok(${className}Service.queryById(${pkColumn.javaField}));
+    }
+
+    /**
+     * 鏂板${functionName}
+     */
+    @SaCheckPermission("${permissionPrefix}:add")
+    @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
+        return toAjax(${className}Service.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼${functionName}
+     */
+    @SaCheckPermission("${permissionPrefix}:edit")
+    @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
+        return toAjax(${className}Service.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎${functionName}
+     *
+     * @param ${pkColumn.javaField}s 涓婚敭涓�
+     */
+    @SaCheckPermission("${permissionPrefix}:remove")
+    @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{${pkColumn.javaField}s}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
+        return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
new file mode 100644
index 0000000..205fb73
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
@@ -0,0 +1,60 @@
+package ${packageName}.domain;
+
+#foreach ($column in $columns)
+#if($column.javaField=='tenantId')
+#set($IsTenant=1)
+#end
+#end
+#if($IsTenant==1)
+import org.dromara.common.tenant.core.TenantEntity;
+#else
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+#end
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+import java.io.Serial;
+
+/**
+ * ${functionName}瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($IsTenant==1)
+#set($Entity="TenantEntity")
+#else
+#set($Entity="BaseEntity")
+#end
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("${tableName}")
+public class ${ClassName} extends ${Entity} {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+    /**
+     * $column.columnComment
+     */
+#if($column.javaField=='delFlag')
+    @TableLogic
+#end
+#if($column.javaField=='version')
+    @Version
+#end
+#if($column.isPk==1)
+    @TableId(value = "$column.columnName")
+#end
+    private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 0000000..0922401
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,15 @@
+package ${packageName}.mapper;
+
+import ${packageName}.domain.${ClassName};
+import ${packageName}.domain.vo.${ClassName}Vo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * ${functionName}Mapper鎺ュ彛
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..4db9030
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,72 @@
+package ${packageName}.service;
+
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.bo.${ClassName}Bo;
+#if($table.crud)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+#end
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * ${functionName}Service鎺ュ彛
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service {
+
+    /**
+     * 鏌ヨ${functionName}
+     *
+     * @param ${pkColumn.javaField} 涓婚敭
+     * @return ${functionName}
+     */
+    ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
+
+#if($table.crud)
+    /**
+     * 鍒嗛〉鏌ヨ${functionName}鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return ${functionName}鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
+#end
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨�${functionName}鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return ${functionName}鍒楄〃
+     */
+    List<${ClassName}Vo> queryList(${ClassName}Bo bo);
+
+    /**
+     * 鏂板${functionName}
+     *
+     * @param bo ${functionName}
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(${ClassName}Bo bo);
+
+    /**
+     * 淇敼${functionName}
+     *
+     * @param bo ${functionName}
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(${ClassName}Bo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄�${functionName}淇℃伅
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..67690ca
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,154 @@
+package ${packageName}.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+#if($table.crud)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+#end
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import ${packageName}.domain.bo.${ClassName}Bo;
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.mapper.${ClassName}Mapper;
+import ${packageName}.service.I${ClassName}Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * ${functionName}Service涓氬姟灞傚鐞�
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RequiredArgsConstructor
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service {
+
+    private final ${ClassName}Mapper baseMapper;
+
+    /**
+     * 鏌ヨ${functionName}
+     *
+     * @param ${pkColumn.javaField} 涓婚敭
+     * @return ${functionName}
+     */
+    @Override
+    public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){
+        return baseMapper.selectVoById(${pkColumn.javaField});
+    }
+
+#if($table.crud)
+    /**
+     * 鍒嗛〉鏌ヨ${functionName}鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return ${functionName}鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
+        Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+#end
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨�${functionName}鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return ${functionName}鍒楄〃
+     */
+    @Override
+    public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
+        LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
+#foreach($column in $columns)
+#if($column.query)
+#set($queryType=$column.queryType)
+#set($javaField=$column.javaField)
+#set($javaType=$column.javaType)
+#set($columnName=$column.columnName)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($mpMethod=$column.queryType.toLowerCase())
+#if($queryType != 'BETWEEN')
+#if($javaType == 'String')
+#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
+#else
+#set($condition='bo.get'+$AttrName+'() != null')
+#end
+        lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName());
+#else
+        lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null,
+            ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName"));
+#end
+#end
+#end
+        return lqw;
+    }
+
+    /**
+     * 鏂板${functionName}
+     *
+     * @param bo ${functionName}
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(${ClassName}Bo bo) {
+        ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)})
+        if (flag) {
+            bo.set$pk(add.get$pk());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼${functionName}
+     *
+     * @param bo ${functionName}
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(${ClassName}Bo bo) {
+        ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(${ClassName} entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄�${functionName}淇℃伅
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
new file mode 100644
index 0000000..c896afb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -0,0 +1,66 @@
+package ${packageName}.domain.vo;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import ${packageName}.domain.${ClassName};
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * ${functionName}瑙嗗浘瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ${ClassName}.class)
+public class ${ClassName}Vo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if($column.list)
+    /**
+     * $column.columnComment
+     */
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if(${column.dictType} && ${column.dictType} != '')
+    @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "${column.dictType}")
+#elseif($parentheseIndex != -1)
+    @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
+#else
+    @ExcelProperty(value = "${comment}")
+#end
+    private $column.javaType $column.javaField;
+
+#if($column.htmlType == "imageUpload")
+    /**
+     * ${column.columnComment}Url
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
+    private String ${column.javaField}Url";
+#end
+#end
+#end
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm
new file mode 100644
index 0000000..f6638be
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm
@@ -0,0 +1,19 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1',  '#', '', 1,  0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2',  '#', '', 1,  0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3',  '#', '', 1,  0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4',  '#', '', 1,  0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5',  '#', '', 1,  0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 103, 1, sysdate, null, null, '');
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm
new file mode 100644
index 0000000..0923392
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm
@@ -0,0 +1,20 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 103, 1, now(), null, null, '');
+
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 0000000..01824c2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm
@@ -0,0 +1,19 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 103, 1, sysdate(), null, null, '');
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm
new file mode 100644
index 0000000..bdf166e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm
@@ -0,0 +1,19 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 103, 1, getdate(), null, null, '');
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm
new file mode 100644
index 0000000..3aa4a5f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm
@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ${BusinessName}VO, ${BusinessName}Form, ${BusinessName}Query } from '@/api/${moduleName}/${businessName}/types';
+
+/**
+ * 鏌ヨ${functionName}鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> => {
+  return request({
+    url: '/${moduleName}/${businessName}/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 鏌ヨ${functionName}璇︾粏
+ * @param ${pkColumn.javaField}
+ */
+export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'get'
+  });
+};
+
+/**
+ * 鏂板${functionName}
+ * @param data
+ */
+export const add${BusinessName} = (data: ${BusinessName}Form) => {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 淇敼${functionName}
+ * @param data
+ */
+export const update${BusinessName} = (data: ${BusinessName}Form) => {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 鍒犻櫎${functionName}
+ * @param ${pkColumn.javaField}
+ */
+export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array<string | number>) => {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'delete'
+  });
+};
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
new file mode 100644
index 0000000..35a468e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
@@ -0,0 +1,64 @@
+export interface ${BusinessName}VO {
+#foreach ($column in $columns)
+#if($column.list)
+  /**
+   * $column.columnComment
+   */
+  $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+                        #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+                        #elseif($column.javaType == 'Boolean') boolean;
+                        #else string;
+                    #end
+#if($column.htmlType == "imageUpload")
+  /**
+   * ${column.columnComment}Url
+   */
+  ${column.javaField}Url: string;
+#end
+#end
+#end
+#if ($table.tree)
+    /**
+     * 瀛愬璞�
+     */
+    children: ${BusinessName}VO[];
+#end
+}
+
+export interface ${BusinessName}Form extends BaseEntity {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+  /**
+   * $column.columnComment
+   */
+  $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+                        #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+                        #elseif($column.javaType == 'Boolean') boolean;
+                        #else string;
+                    #end
+#end
+#end
+}
+
+export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{
+
+#foreach ($column in $columns)
+#if($column.query)
+  /**
+   * $column.columnComment
+   */
+  $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+                        #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+                        #elseif($column.javaType == 'Boolean') boolean;
+                        #else string;
+                    #end
+#end
+#end
+    /**
+     * 鏃ユ湡鑼冨洿鍙傛暟
+     */
+    params?: any;
+}
+
+
+
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 0000000..caf3472
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +1,498 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-input v-model="queryParams.${column.javaField}" placeholder="璇疯緭鍏�${comment}" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+                <el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
+              </el-select>
+            </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+                <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+              </el-select>
+            </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-date-picker clearable
+                v-model="queryParams.${column.javaField}"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="閫夋嫨${comment}"
+              />
+            </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+            <el-form-item label="${comment}" style="width: 308px">
+              <el-date-picker
+                v-model="dateRange${AttrName}"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="寮�濮嬫棩鏈�"
+                end-placeholder="缁撴潫鏃ユ湡"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              />
+            </el-form-item>
+#end
+#end
+#end
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+              <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">灞曞紑/鎶樺彔</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+      <el-table
+        ref="${businessName}TableRef"
+        v-loading="loading"
+        :data="${businessName}List"
+        row-key="${treeCode}"
+        :default-expand-all="isExpandAll"
+        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+      >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+        <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+        <el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
+          </template>
+        </el-table-column>
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+        <el-table-column label="${comment}" align="center" prop="${javaField}">
+          <template #default="scope">
+#if($column.htmlType == "checkbox")
+            <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+            <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+          </template>
+        </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+        <el-table-column label="${comment}" prop="${javaField}" />
+#else
+        <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+        <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="淇敼" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']" />
+            </el-tooltip>
+            <el-tooltip content="鏂板" placement="top">
+              <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']" />
+            </el-tooltip>
+            <el-tooltip content="鍒犻櫎" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']" />
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if(($column.insert || $column.edit) && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+        <el-form-item label="${comment}" prop="${treeParentCode}">
+          <el-tree-select
+            v-model="form.${treeParentCode}"
+            :data="${businessName}Options"
+            :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
+            value-key="${treeCode}"
+            placeholder="璇烽�夋嫨${comment}"
+            check-strictly
+          />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="閫夋嫨${comment}"
+          />
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}" lang="ts">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
+
+type ${BusinessName}Option = {
+  ${treeCode}: number;
+  ${treeName}: string;
+  children?: ${BusinessName}Option[];
+}
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
+
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
+#end
+
+const ${businessName}List = ref<${BusinessName}VO[]>([]);
+const ${businessName}Options = ref<${BusinessName}Option[]>([]);
+const buttonLoading = ref(false);
+const showSearch = ref(true);
+const isExpandAll = ref(true);
+const loading = ref(false);
+
+const queryFormRef = ref<ElFormInstance>();
+const ${businessName}FormRef = ref<ElFormInstance>();
+const ${businessName}TableRef = ref<ElTableInstance>()
+
+const dialog = reactive<DialogOption>({
+    visible: false,
+    title: ''
+});
+
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
+#end
+#end
+
+const initFormData: ${BusinessName}Form = {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.htmlType == "checkbox")
+    $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+    $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+}
+
+const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
+  form: {...initFormData},
+  queryParams: {
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
+    $column.javaField: undefined,
+#end
+#end
+#end
+    params: {
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+    }
+  },
+  rules: {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+const getList = async () => {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
+#end
+#end
+  const res = await list${BusinessName}(queryParams.value);
+  const data = proxy?.handleTree<${BusinessName}VO>(res.data, "${treeCode}", "${treeParentCode}");
+  if (data) {
+    ${businessName}List.value = data;
+    loading.value = false;
+  }
+}
+
+/** 鏌ヨ${functionName}涓嬫媺鏍戠粨鏋� */
+const getTreeselect = async () => {
+  const res = await list${BusinessName}();
+  ${businessName}Options.value = [];
+  const data: ${BusinessName}Option = { ${treeCode}: 0, ${treeName}: '椤剁骇鑺傜偣', children: [] };
+  data.children = proxy?.handleTree<${BusinessName}Option>(res.data, "${treeCode}", "${treeParentCode}");
+  ${businessName}Options.value.push(data);
+}
+
+// 鍙栨秷鎸夐挳
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+// 琛ㄥ崟閲嶇疆
+const reset = () => {
+  form.value = {...initFormData}
+  ${businessName}FormRef.value?.resetFields();
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  dateRange${AttrName}.value = ['', ''];
+#end
+#end
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+const handleAdd = (row?: ${BusinessName}VO) => {
+  reset();
+  getTreeselect();
+  if (row != null && row.${treeCode}) {
+    form.value.${treeParentCode} = row.${treeCode};
+  } else {
+    form.value.${treeParentCode} = 0;
+  }
+  dialog.visible = true;
+  dialog.title = "娣诲姞${functionName}";
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+const handleToggleExpandAll = () => {
+  isExpandAll.value = !isExpandAll.value;
+  toggleExpandAll(${businessName}List.value, isExpandAll.value)
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+const toggleExpandAll = (data: ${BusinessName}VO[], status: boolean) => {
+  data.forEach((item) => {
+    ${businessName}TableRef.value?.toggleRowExpansion(item, status)
+    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
+  })
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+const handleUpdate = async (row: ${BusinessName}VO) => {
+  reset();
+  await getTreeselect();
+  if (row != null) {
+    form.value.${treeParentCode} = row.${treeParentCode};
+  }
+  const res = await get${BusinessName}(row.${pkColumn.javaField});
+  Object.assign(form.value, res.data);
+#foreach ($column in $columns)
+  #if($column.htmlType == "checkbox")
+  form.value.$column.javaField = form.value.${column.javaField}.split(",");
+  #end
+#end
+  dialog.visible = true;
+  dialog.title = "淇敼${functionName}";
+}
+
+/** 鎻愪氦鎸夐挳 */
+const submitForm = () => {
+  ${businessName}FormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+      if (form.value.${pkColumn.javaField}) {
+        await update${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+      } else {
+        await add${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+      }
+      proxy?.#[[$modal]]#.msgSuccess("鎿嶄綔鎴愬姛");
+      dialog.visible = false;
+      getList();
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+const handleDelete = async (row: ${BusinessName}VO) => {
+  await proxy?.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + row.${pkColumn.javaField} + '"鐨勬暟鎹」锛�');
+  loading.value = true;
+  await del${BusinessName}(row.${pkColumn.javaField}).finally(() => loading.value = false);
+  await getList();
+  proxy?.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 0000000..a92d19a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +1,459 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-input v-model="queryParams.${column.javaField}" placeholder="璇疯緭鍏�${comment}" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable >
+                <el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
+              </el-select>
+            </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable >
+                <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+              </el-select>
+            </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+            <el-form-item label="${comment}" prop="${column.javaField}">
+              <el-date-picker clearable
+                v-model="queryParams.${column.javaField}"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨${comment}"
+              />
+            </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+            <el-form-item label="${comment}" style="width: 308px">
+              <el-date-picker
+                v-model="dateRange${AttrName}"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                type="daterange"
+                range-separator="-"
+                start-placeholder="寮�濮嬫棩鏈�"
+                end-placeholder="缁撴潫鏃ユ湡"
+                :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+              />
+            </el-form-item>
+#end
+#end
+#end
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+              <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['${moduleName}:${businessName}:remove']">鍒犻櫎</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">瀵煎嚭</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+        <el-table-column label="${comment}" align="center" prop="${javaField}" v-if="${column.list}" />
+#elseif($column.list && $column.htmlType == "datetime")
+        <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+        <el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
+          </template>
+        </el-table-column>
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+        <el-table-column label="${comment}" align="center" prop="${javaField}">
+          <template #default="scope">
+#if($column.htmlType == "checkbox")
+            <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+            <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+          </template>
+        </el-table-column>
+#elseif($column.list && "" != $javaField)
+        <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+        <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="淇敼" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="鍒犻櫎" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if(($column.insert || $column.edit) && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+                v-for="dict in ${dictType}"
+                :key="dict.value"
+                :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+                :value="parseInt(dict.value)"
+#else
+                :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+                v-for="dict in ${dictType}"
+                :key="dict.value"
+                :label="dict.value">
+                {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio value="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="璇烽�夋嫨${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+            <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}" lang="ts">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from '@/api/${moduleName}/${businessName}';
+import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
+#end
+
+const ${businessName}List = ref<${BusinessName}VO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
+#end
+#end
+
+const queryFormRef = ref<ElFormInstance>();
+const ${businessName}FormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ${BusinessName}Form = {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.htmlType == "checkbox")
+  $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+  $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+}
+const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
+    $column.javaField: undefined,
+#end
+#end
+#end
+    params: {
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+    }
+  },
+  rules: {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+const getList = async () => {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
+#end
+#end
+  const res = await list${BusinessName}(queryParams.value);
+  ${businessName}List.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 鍙栨秷鎸夐挳 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 琛ㄥ崟閲嶇疆 */
+const reset = () => {
+  form.value = {...initFormData};
+  ${businessName}FormRef.value?.resetFields();
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  dateRange${AttrName}.value = ['', ''];
+#end
+#end
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 澶氶�夋閫変腑鏁版嵁 */
+const handleSelectionChange = (selection: ${BusinessName}VO[]) => {
+  ids.value = selection.map(item => item.${pkColumn.javaField});
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "娣诲姞${functionName}";
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+const handleUpdate = async (row?: ${BusinessName}VO) => {
+  reset();
+  const _${pkColumn.javaField} = row?.${pkColumn.javaField} || ids.value[0]
+  const res = await get${BusinessName}(_${pkColumn.javaField});
+  Object.assign(form.value, res.data);
+#foreach ($column in $columns)
+  #if($column.htmlType == "checkbox")
+  form.value.$column.javaField = form.value.${column.javaField}.split(",");
+  #end
+#end
+  dialog.visible = true;
+  dialog.title = "淇敼${functionName}";
+}
+
+/** 鎻愪氦鎸夐挳 */
+const submitForm = () => {
+  ${businessName}FormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      #foreach ($column in $columns)
+        #if($column.htmlType == "checkbox")
+        form.value.$column.javaField = form.value.${column.javaField}.join(",");
+        #end
+      #end
+      if (form.value.${pkColumn.javaField}) {
+        await update${BusinessName}(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await add${BusinessName}(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.#[[$modal]]#.msgSuccess("鎿嶄綔鎴愬姛");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+const handleDelete = async (row?: ${BusinessName}VO) => {
+  const _${pkColumn.javaField}s = row?.${pkColumn.javaField} || ids.value;
+  await proxy?.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + _${pkColumn.javaField}s + '"鐨勬暟鎹」锛�').finally(() => loading.value = false);
+  await del${BusinessName}(_${pkColumn.javaField}s);
+  proxy?.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+  await getList();
+}
+
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+const handleExport = () => {
+  proxy?.download('${moduleName}/${businessName}/export', {
+    ...queryParams.value
+  }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
diff --git a/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 0000000..9fb48d9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-job/pom.xml b/eims/ruoyi-modules/ruoyi-job/pom.xml
new file mode 100644
index 0000000..2431a1c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-job/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>ruoyi-job</artifactId>
+
+    <description>
+        浠诲姟璋冨害
+    </description>
+
+    <dependencies>
+
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-json</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-job</artifactId>
+        </dependency>
+        
+    </dependencies>
+
+</project>
+
diff --git a/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java
new file mode 100644
index 0000000..2f118b0
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java
@@ -0,0 +1 @@
+package org.dromara.job;
diff --git a/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java
new file mode 100644
index 0000000..5bea9da
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java
@@ -0,0 +1,23 @@
+package org.dromara.job.snailjob;
+
+import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
+import com.aizuda.snailjob.client.job.core.dto.JobArgs;
+import com.aizuda.snailjob.client.model.ExecuteResult;
+import com.aizuda.snailjob.common.core.util.JsonUtil;
+import com.aizuda.snailjob.common.log.SnailJobLog;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author opensnail
+ * @date 2024-05-17
+ */
+@Component
+@JobExecutor(name = "testJobExecutor")
+public class TestAnnoJobExecutor {
+
+    public ExecuteResult jobExecute(JobArgs jobArgs) {
+        SnailJobLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs));
+        SnailJobLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs));
+        return ExecuteResult.success("娴嬭瘯鎴愬姛");
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java
new file mode 100644
index 0000000..6f7c21f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java
@@ -0,0 +1,19 @@
+package org.dromara.job.snailjob;
+
+import com.aizuda.snailjob.client.job.core.dto.JobArgs;
+import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor;
+import com.aizuda.snailjob.client.model.ExecuteResult;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author opensnail
+ * @date 2024-05-17
+ */
+@Component
+public class TestClassJobExecutor extends AbstractJobExecutor {
+
+    @Override
+    protected ExecuteResult doJobExecute(JobArgs jobArgs) {
+        return ExecuteResult.success("TestJobExecutor娴嬭瘯鎴愬姛");
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/pom.xml b/eims/ruoyi-modules/ruoyi-system/pom.xml
new file mode 100644
index 0000000..0fc6d55
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-system</artifactId>
+
+    <description>
+        system绯荤粺妯″潡
+    </description>
+
+    <dependencies>
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-doc</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+
+        <!-- OSS鍔熻兘妯″潡 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-oss</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+
+        <!-- excel-->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-excel</artifactId>
+        </dependency>
+
+        <!-- SMS鍔熻兘妯″潡 -->
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sms</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sensitive</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-encrypt</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-websocket</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sse</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java
new file mode 100644
index 0000000..6b7499a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java
@@ -0,0 +1,55 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.system.domain.vo.CacheListInfoVo;
+import lombok.RequiredArgsConstructor;
+import org.redisson.spring.data.connection.RedissonConnectionFactory;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+/**
+ * 缂撳瓨鐩戞帶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController {
+
+    private final RedissonConnectionFactory connectionFactory;
+
+    /**
+     * 鑾峰彇缂撳瓨鐩戞帶鍒楄〃
+     */
+    @SaCheckPermission("monitor:cache:list")
+    @GetMapping()
+    public R<CacheListInfoVo> getInfo() throws Exception {
+        RedisConnection connection = connectionFactory.getConnection();
+        Properties commandStats = connection.commands().info("commandstats");
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        if (commandStats != null) {
+            commandStats.stringPropertyNames().forEach(key -> {
+                Map<String, String> data = new HashMap<>(2);
+                String property = commandStats.getProperty(key);
+                data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+                data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+                pieList.add(data);
+            });
+        }
+
+        CacheListInfoVo infoVo = new CacheListInfoVo();
+        infoVo.setInfo(connection.commands().info());
+        infoVo.setDbSize(connection.commands().dbSize());
+        infoVo.setCommandStats(pieList);
+        return R.ok(infoVo);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
new file mode 100644
index 0000000..98ac2d5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
@@ -0,0 +1,89 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+import org.dromara.system.service.ISysLogininforService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶璁板綍
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController {
+
+    private final ISysLogininforService logininforService;
+
+    /**
+     * 鑾峰彇绯荤粺璁块棶璁板綍鍒楄〃
+     */
+    @SaCheckPermission("monitor:logininfor:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysLogininforVo> list(SysLogininforBo logininfor, PageQuery pageQuery) {
+        return logininforService.selectPageLogininforList(logininfor, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭绯荤粺璁块棶璁板綍鍒楄〃
+     */
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("monitor:logininfor:export")
+    @PostMapping("/export")
+    public void export(SysLogininforBo logininfor, HttpServletResponse response) {
+        List<SysLogininforVo> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil.exportExcel(list, "鐧诲綍鏃ュ織", SysLogininforVo.class, response);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鐧诲綍鏃ュ織
+     * @param infoIds 鏃ュ織ids
+     */
+    @SaCheckPermission("monitor:logininfor:remove")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public R<Void> remove(@PathVariable Long[] infoIds) {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    /**
+     * 娓呯悊绯荤粺璁块棶璁板綍
+     */
+    @SaCheckPermission("monitor:logininfor:remove")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public R<Void> clean() {
+        logininforService.cleanLogininfor();
+        return R.ok();
+    }
+
+    @SaCheckPermission("monitor:logininfor:unlock")
+    @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public R<Void> unlock(@PathVariable("userName") String userName) {
+        String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName;
+        if (RedisUtils.hasKey(loginName)) {
+            RedisUtils.deleteObject(loginName);
+        }
+        return R.ok();
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java
new file mode 100644
index 0000000..575aba6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java
@@ -0,0 +1,75 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+import org.dromara.system.service.ISysOperLogService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController {
+
+    private final ISysOperLogService operLogService;
+
+    /**
+     * 鑾峰彇鎿嶄綔鏃ュ織璁板綍鍒楄〃
+     */
+    @SaCheckPermission("monitor:operlog:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysOperLogVo> list(SysOperLogBo operLog, PageQuery pageQuery) {
+        return operLogService.selectPageOperLogList(operLog, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鎿嶄綔鏃ュ織璁板綍鍒楄〃
+     */
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("monitor:operlog:export")
+    @PostMapping("/export")
+    public void export(SysOperLogBo operLog, HttpServletResponse response) {
+        List<SysOperLogVo> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil.exportExcel(list, "鎿嶄綔鏃ュ織", SysOperLogVo.class, response);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鎿嶄綔鏃ュ織璁板綍
+     * @param operIds 鏃ュ織ids
+     */
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
+    @SaCheckPermission("monitor:operlog:remove")
+    @DeleteMapping("/{operIds}")
+    public R<Void> remove(@PathVariable Long[] operIds) {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    /**
+     * 娓呯悊鎿嶄綔鏃ュ織璁板綍
+     */
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.CLEAN)
+    @SaCheckPermission("monitor:operlog:remove")
+    @DeleteMapping("/clean")
+    public R<Void> clean() {
+        operLogService.cleanOperLog();
+        return R.ok();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
new file mode 100644
index 0000000..9b08c2d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
@@ -0,0 +1,130 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.dto.UserOnlineDTO;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.SysUserOnline;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController {
+
+    /**
+     * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐩戞帶鍒楄〃
+     *
+     * @param ipaddr   IP鍦板潃
+     * @param userName 鐢ㄦ埛鍚�
+     */
+    @SaCheckPermission("monitor:online:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
+        // 鑾峰彇鎵�鏈夋湭杩囨湡鐨� token
+        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        List<UserOnlineDTO> userOnlineDTOList = new ArrayList<>();
+        for (String key : keys) {
+            String token = StringUtils.substringAfterLast(key, ":");
+            // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+            if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+                continue;
+            }
+            userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token));
+        }
+        if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
+            userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+                StringUtils.equals(ipaddr, userOnline.getIpaddr()) &&
+                    StringUtils.equals(userName, userOnline.getUserName())
+            );
+        } else if (StringUtils.isNotEmpty(ipaddr)) {
+            userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+                StringUtils.equals(ipaddr, userOnline.getIpaddr())
+            );
+        } else if (StringUtils.isNotEmpty(userName)) {
+            userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+                StringUtils.equals(userName, userOnline.getUserName())
+            );
+        }
+        Collections.reverse(userOnlineDTOList);
+        userOnlineDTOList.removeAll(Collections.singleton(null));
+        List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
+        return TableDataInfo.build(userOnlineList);
+    }
+
+    /**
+     * 寮洪��鐢ㄦ埛
+     *
+     * @param tokenId token鍊�
+     */
+    @SaCheckPermission("monitor:online:forceLogout")
+    @Log(title = "鍦ㄧ嚎鐢ㄦ埛", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public R<Void> forceLogout(@PathVariable String tokenId) {
+        try {
+            StpUtil.kickoutByTokenValue(tokenId);
+        } catch (NotLoginException ignored) {
+        }
+        return R.ok();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐢ㄦ埛鐧诲綍鍦ㄧ嚎璁惧
+     */
+    @GetMapping()
+    public TableDataInfo<SysUserOnline> getInfo() {
+        // 鑾峰彇鎸囧畾璐﹀彿 id 鐨� token 闆嗗悎
+        List<String> tokenIds = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString());
+        List<UserOnlineDTO> userOnlineDTOList = tokenIds.stream()
+            .filter(token -> StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) >= -1)
+            .map(token -> (UserOnlineDTO) RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token))
+            .collect(Collectors.toList());
+        //澶嶅埗鍜屽鐞� SysUserOnline 瀵硅薄鍒楄〃
+        Collections.reverse(userOnlineDTOList);
+        userOnlineDTOList.removeAll(Collections.singleton(null));
+        List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
+        return TableDataInfo.build(userOnlineList);
+    }
+
+    /**
+     * 寮洪��褰撳墠鍦ㄧ嚎璁惧
+     *
+     * @param tokenId token鍊�
+     */
+    @Log(title = "鍦ㄧ嚎璁惧", businessType = BusinessType.FORCE)
+    @PostMapping("/{tokenId}")
+    public R<Void> remove(@PathVariable("tokenId") String tokenId) {
+        try {
+            // 鑾峰彇鎸囧畾璐﹀彿 id 鐨� token 闆嗗悎
+            List<String> keys = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString());
+            keys.stream()
+                .filter(key -> key.equals(tokenId))
+                .findFirst()
+                .ifPresent(key -> StpUtil.kickoutByTokenValue(tokenId));
+        } catch (NotLoginException ignored) {
+        }
+        return R.ok();
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
new file mode 100644
index 0000000..13be4a4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
@@ -0,0 +1,115 @@
+package org.dromara.system.controller.system;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.service.ISysClientService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 瀹㈡埛绔鐞�
+ *
+ * @author Michelle.Chung
+ * @date 2023-06-18
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/client")
+public class SysClientController extends BaseController {
+
+    private final ISysClientService sysClientService;
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+     */
+    @SaCheckPermission("system:client:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysClientVo> list(SysClientBo bo, PageQuery pageQuery) {
+        return sysClientService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭瀹㈡埛绔鐞嗗垪琛�
+     */
+    @SaCheckPermission("system:client:export")
+    @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysClientBo bo, HttpServletResponse response) {
+        List<SysClientVo> list = sysClientService.queryList(bo);
+        ExcelUtil.exportExcel(list, "瀹㈡埛绔鐞�", SysClientVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇瀹㈡埛绔鐞嗚缁嗕俊鎭�
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("system:client:query")
+    @GetMapping("/{id}")
+    public R<SysClientVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                  @PathVariable Long id) {
+        return R.ok(sysClientService.queryById(id));
+    }
+
+    /**
+     * 鏂板瀹㈡埛绔鐞�
+     */
+    @SaCheckPermission("system:client:add")
+    @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) {
+        return toAjax(sysClientService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼瀹㈡埛绔鐞�
+     */
+    @SaCheckPermission("system:client:edit")
+    @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) {
+        return toAjax(sysClientService.updateByBo(bo));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckPermission("system:client:edit")
+    @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysClientBo bo) {
+        return toAjax(sysClientService.updateUserStatus(bo.getClientId(), bo.getStatus()));
+    }
+
+    /**
+     * 鍒犻櫎瀹㈡埛绔鐞�
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("system:client:remove")
+    @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(sysClientService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java
new file mode 100644
index 0000000..c73c386
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java
@@ -0,0 +1,137 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+import org.dromara.system.service.ISysConfigService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鍙傛暟閰嶇疆 淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController {
+
+    private final ISysConfigService configService;
+
+    /**
+     * 鑾峰彇鍙傛暟閰嶇疆鍒楄〃
+     */
+    @SaCheckPermission("system:config:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysConfigVo> list(SysConfigBo config, PageQuery pageQuery) {
+        return configService.selectPageConfigList(config, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鍙傛暟閰嶇疆鍒楄〃
+     */
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:config:export")
+    @PostMapping("/export")
+    public void export(SysConfigBo config, HttpServletResponse response) {
+        List<SysConfigVo> list = configService.selectConfigList(config);
+        ExcelUtil.exportExcel(list, "鍙傛暟鏁版嵁", SysConfigVo.class, response);
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param configId 鍙傛暟ID
+     */
+    @SaCheckPermission("system:config:query")
+    @GetMapping(value = "/{configId}")
+    public R<SysConfigVo> getInfo(@PathVariable Long configId) {
+        return R.ok(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+     *
+     * @param configKey 鍙傛暟Key
+     */
+    @GetMapping(value = "/configKey/{configKey}")
+    public R<String> getConfigKey(@PathVariable String configKey) {
+        return R.ok("鎿嶄綔鎴愬姛", configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     */
+    @SaCheckPermission("system:config:add")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysConfigBo config) {
+        if (!configService.checkConfigKeyUnique(config)) {
+            return R.fail("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        configService.insertConfig(config);
+        return R.ok();
+    }
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     */
+    @SaCheckPermission("system:config:edit")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysConfigBo config) {
+        if (!configService.checkConfigKeyUnique(config)) {
+            return R.fail("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        configService.updateConfig(config);
+        return R.ok();
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟閿悕淇敼鍙傛暟閰嶇疆
+     */
+    @SaCheckPermission("system:config:edit")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateByKey")
+    public R<Void> updateByKey(@RequestBody SysConfigBo config) {
+        configService.updateConfig(config);
+        return R.ok();
+    }
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆
+     *
+     * @param configIds 鍙傛暟ID涓�
+     */
+    @SaCheckPermission("system:config:remove")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public R<Void> remove(@PathVariable Long[] configIds) {
+        configService.deleteConfigByIds(configIds);
+        return R.ok();
+    }
+
+    /**
+     * 鍒锋柊鍙傛暟缂撳瓨
+     */
+    @SaCheckPermission("system:config:remove")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public R<Void> refreshCache() {
+        configService.resetConfigCache();
+        return R.ok();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
new file mode 100644
index 0000000..968bbe9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
@@ -0,0 +1,140 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.convert.Convert;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysPostService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/dept")
+public class SysDeptController extends BaseController {
+
+    private final ISysDeptService deptService;
+    private final ISysPostService postService;
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍒楄〃
+     */
+    @SaCheckPermission("system:dept:list")
+    @GetMapping("/list")
+    public R<List<SysDeptVo>> list(SysDeptBo dept) {
+        List<SysDeptVo> depts = deptService.selectDeptList(dept);
+        return R.ok(depts);
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
+     *
+     * @param deptId 閮ㄩ棬ID
+     */
+    @SaCheckPermission("system:dept:list")
+    @GetMapping("/list/exclude/{deptId}")
+    public R<List<SysDeptVo>> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) {
+        List<SysDeptVo> depts = deptService.selectDeptList(new SysDeptBo());
+        depts.removeIf(d -> d.getDeptId().equals(deptId)
+            || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId)));
+        return R.ok(depts);
+    }
+
+    /**
+     * 鏍规嵁閮ㄩ棬缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param deptId 閮ㄩ棬ID
+     */
+    @SaCheckPermission("system:dept:query")
+    @GetMapping(value = "/{deptId}")
+    public R<SysDeptVo> getInfo(@PathVariable Long deptId) {
+        deptService.checkDeptDataScope(deptId);
+        return R.ok(deptService.selectDeptById(deptId));
+    }
+
+    /**
+     * 鏂板閮ㄩ棬
+     */
+    @SaCheckPermission("system:dept:add")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysDeptBo dept) {
+        if (!deptService.checkDeptNameUnique(dept)) {
+            return R.fail("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        }
+        return toAjax(deptService.insertDept(dept));
+    }
+
+    /**
+     * 淇敼閮ㄩ棬
+     */
+    @SaCheckPermission("system:dept:edit")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysDeptBo dept) {
+        Long deptId = dept.getDeptId();
+        deptService.checkDeptDataScope(deptId);
+        if (!deptService.checkDeptNameUnique(dept)) {
+            return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        } else if (dept.getParentId().equals(deptId)) {
+            return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
+        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {
+            if (deptService.selectNormalChildrenDeptById(deptId) > 0) {
+                return R.fail("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬!");
+            } else if (deptService.checkDeptExistUser(deptId)) {
+                return R.fail("璇ラ儴闂ㄤ笅瀛樺湪宸插垎閰嶇敤鎴凤紝涓嶈兘绂佺敤!");
+            }
+        }
+        return toAjax(deptService.updateDept(dept));
+    }
+
+    /**
+     * 鍒犻櫎閮ㄩ棬
+     *
+     * @param deptId 閮ㄩ棬ID
+     */
+    @SaCheckPermission("system:dept:remove")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{deptId}")
+    public R<Void> remove(@PathVariable Long deptId) {
+        if (deptService.hasChildByDeptId(deptId)) {
+            return R.warn("瀛樺湪涓嬬骇閮ㄩ棬,涓嶅厑璁稿垹闄�");
+        }
+        if (deptService.checkDeptExistUser(deptId)) {
+            return R.warn("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
+        }
+        if (postService.countPostByDeptId(deptId) > 0) {
+            return R.warn("閮ㄩ棬瀛樺湪宀椾綅,涓嶅厑璁稿垹闄�");
+        }
+        deptService.checkDeptDataScope(deptId);
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬閫夋嫨妗嗗垪琛�
+     *
+     * @param deptIds 閮ㄩ棬ID涓�
+     */
+    @SaCheckPermission("system:dept:query")
+    @GetMapping("/optionselect")
+    public R<List<SysDeptVo>> optionselect(@RequestParam(required = false) Long[] deptIds) {
+        return R.ok(deptService.selectDeptByIds(deptIds == null ? null : List.of(deptIds)));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java
new file mode 100644
index 0000000..5752751
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java
@@ -0,0 +1,123 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.service.ISysDictDataService;
+import org.dromara.system.service.ISysDictTypeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController {
+
+    private final ISysDictDataService dictDataService;
+    private final ISysDictTypeService dictTypeService;
+
+    /**
+     * 鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+     */
+    @SaCheckPermission("system:dict:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysDictDataVo> list(SysDictDataBo dictData, PageQuery pageQuery) {
+        return dictDataService.selectPageDictDataList(dictData, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭瀛楀吀鏁版嵁鍒楄〃
+     */
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:dict:export")
+    @PostMapping("/export")
+    public void export(SysDictDataBo dictData, HttpServletResponse response) {
+        List<SysDictDataVo> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil.exportExcel(list, "瀛楀吀鏁版嵁", SysDictDataVo.class, response);
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+     *
+     * @param dictCode 瀛楀吀code
+     */
+    @SaCheckPermission("system:dict:query")
+    @GetMapping(value = "/{dictCode}")
+    public R<SysDictDataVo> getInfo(@PathVariable Long dictCode) {
+        return R.ok(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     */
+    @GetMapping(value = "/type/{dictType}")
+    public R<List<SysDictDataVo>> dictType(@PathVariable String dictType) {
+        List<SysDictDataVo> data = dictTypeService.selectDictDataByType(dictType);
+        if (ObjectUtil.isNull(data)) {
+            data = new ArrayList<>();
+        }
+        return R.ok(data);
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @SaCheckPermission("system:dict:add")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysDictDataBo dict) {
+        if (!dictDataService.checkDictDataUnique(dict)) {
+            return R.fail("鏂板瀛楀吀鏁版嵁'" + dict.getDictValue() + "'澶辫触锛屽瓧鍏搁敭鍊煎凡瀛樺湪");
+        }
+        dictDataService.insertDictData(dict);
+        return R.ok();
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷
+     */
+    @SaCheckPermission("system:dict:edit")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysDictDataBo dict) {
+        if (!dictDataService.checkDictDataUnique(dict)) {
+            return R.fail("淇敼瀛楀吀鏁版嵁'" + dict.getDictValue() + "'澶辫触锛屽瓧鍏搁敭鍊煎凡瀛樺湪");
+        }
+        dictDataService.updateDictData(dict);
+        return R.ok();
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     *
+     * @param dictCodes 瀛楀吀code涓�
+     */
+    @SaCheckPermission("system:dict:remove")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCodes}")
+    public R<Void> remove(@PathVariable Long[] dictCodes) {
+        dictDataService.deleteDictDataByIds(dictCodes);
+        return R.ok();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java
new file mode 100644
index 0000000..67c1f51
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java
@@ -0,0 +1,125 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+import org.dromara.system.service.ISysDictTypeService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController {
+
+    private final ISysDictTypeService dictTypeService;
+
+    /**
+     * 鏌ヨ瀛楀吀绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("system:dict:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysDictTypeVo> list(SysDictTypeBo dictType, PageQuery pageQuery) {
+        return dictTypeService.selectPageDictTypeList(dictType, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭瀛楀吀绫诲瀷鍒楄〃
+     */
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:dict:export")
+    @PostMapping("/export")
+    public void export(SysDictTypeBo dictType, HttpServletResponse response) {
+        List<SysDictTypeVo> list = dictTypeService.selectDictTypeList(dictType);
+        ExcelUtil.exportExcel(list, "瀛楀吀绫诲瀷", SysDictTypeVo.class, response);
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+     *
+     * @param dictId 瀛楀吀ID
+     */
+    @SaCheckPermission("system:dict:query")
+    @GetMapping(value = "/{dictId}")
+    public R<SysDictTypeVo> getInfo(@PathVariable Long dictId) {
+        return R.ok(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @SaCheckPermission("system:dict:add")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysDictTypeBo dict) {
+        if (!dictTypeService.checkDictTypeUnique(dict)) {
+            return R.fail("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dictTypeService.insertDictType(dict);
+        return R.ok();
+    }
+
+    /**
+     * 淇敼瀛楀吀绫诲瀷
+     */
+    @SaCheckPermission("system:dict:edit")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysDictTypeBo dict) {
+        if (!dictTypeService.checkDictTypeUnique(dict)) {
+            return R.fail("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dictTypeService.updateDictType(dict);
+        return R.ok();
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     *
+     * @param dictIds 瀛楀吀ID涓�
+     */
+    @SaCheckPermission("system:dict:remove")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictIds}")
+    public R<Void> remove(@PathVariable Long[] dictIds) {
+        dictTypeService.deleteDictTypeByIds(dictIds);
+        return R.ok();
+    }
+
+    /**
+     * 鍒锋柊瀛楀吀缂撳瓨
+     */
+    @SaCheckPermission("system:dict:remove")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public R<Void> refreshCache() {
+        dictTypeService.resetDictCache();
+        return R.ok();
+    }
+
+    /**
+     * 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
+     */
+    @GetMapping("/optionselect")
+    public R<List<SysDictTypeVo>> optionselect() {
+        List<SysDictTypeVo> dictTypes = dictTypeService.selectDictTypeAll();
+        return R.ok(dictTypes);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
new file mode 100644
index 0000000..e5daa0e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
@@ -0,0 +1,174 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import cn.dev33.satoken.annotation.SaMode;
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.MenuTreeSelectVo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.dromara.system.service.ISysMenuService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鑿滃崟淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/menu")
+public class SysMenuController extends BaseController {
+
+    private final ISysMenuService menuService;
+
+    /**
+     * 鑾峰彇璺敱淇℃伅
+     *
+     * @return 璺敱淇℃伅
+     */
+    @GetMapping("/getRouters")
+    public R<List<RouterVo>> getRouters() {
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(LoginHelper.getUserId());
+        return R.ok(menuService.buildMenus(menus));
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟鍒楄〃
+     */
+    @SaCheckRole(value = {
+            TenantConstants.SUPER_ADMIN_ROLE_KEY,
+            TenantConstants.TENANT_ADMIN_ROLE_KEY
+    }, mode = SaMode.OR)
+    @SaCheckPermission("system:menu:list")
+    @GetMapping("/list")
+    public R<List<SysMenuVo>> list(SysMenuBo menu) {
+        List<SysMenuVo> menus = menuService.selectMenuList(menu, LoginHelper.getUserId());
+        return R.ok(menus);
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param menuId 鑿滃崟ID
+     */
+    @SaCheckRole(value = {
+            TenantConstants.SUPER_ADMIN_ROLE_KEY,
+            TenantConstants.TENANT_ADMIN_ROLE_KEY
+    }, mode = SaMode.OR)
+    @SaCheckPermission("system:menu:query")
+    @GetMapping(value = "/{menuId}")
+    public R<SysMenuVo> getInfo(@PathVariable Long menuId) {
+        return R.ok(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟涓嬫媺鏍戝垪琛�
+     */
+    @SaCheckPermission("system:menu:query")
+    @GetMapping("/treeselect")
+    public R<List<Tree<Long>>> treeselect(SysMenuBo menu) {
+        List<SysMenuVo> menus = menuService.selectMenuList(menu, LoginHelper.getUserId());
+        return R.ok(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 鍔犺浇瀵瑰簲瑙掕壊鑿滃崟鍒楄〃鏍�
+     *
+     * @param roleId 瑙掕壊ID
+     */
+    @SaCheckPermission("system:menu:query")
+    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+    public R<MenuTreeSelectVo> roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
+        List<SysMenuVo> menus = menuService.selectMenuList(LoginHelper.getUserId());
+        MenuTreeSelectVo selectVo = new MenuTreeSelectVo();
+        selectVo.setCheckedKeys(menuService.selectMenuListByRoleId(roleId));
+        selectVo.setMenus(menuService.buildMenuTreeSelect(menus));
+        return R.ok(selectVo);
+    }
+
+    /**
+     * 鍔犺浇瀵瑰簲绉熸埛濂楅鑿滃崟鍒楄〃鏍�
+     *
+     * @param packageId 绉熸埛濂楅ID
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:menu:query")
+    @GetMapping(value = "/tenantPackageMenuTreeselect/{packageId}")
+    public R<MenuTreeSelectVo> tenantPackageMenuTreeselect(@PathVariable("packageId") Long packageId) {
+        List<SysMenuVo> menus = menuService.selectMenuList(LoginHelper.getUserId());
+        MenuTreeSelectVo selectVo = new MenuTreeSelectVo();
+        selectVo.setCheckedKeys(menuService.selectMenuListByPackageId(packageId));
+        selectVo.setMenus(menuService.buildMenuTreeSelect(menus));
+        return R.ok(selectVo);
+    }
+
+    /**
+     * 鏂板鑿滃崟
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:menu:add")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysMenuBo menu) {
+        if (!menuService.checkMenuNameUnique(menu)) {
+            return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+            return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+        }
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 淇敼鑿滃崟
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:menu:edit")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysMenuBo menu) {
+        if (!menuService.checkMenuNameUnique(menu)) {
+            return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+            return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+        } else if (menu.getMenuId().equals(menu.getParentId())) {
+            return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
+        }
+        return toAjax(menuService.updateMenu(menu));
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟
+     *
+     * @param menuId 鑿滃崟ID
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:menu:remove")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{menuId}")
+    public R<Void> remove(@PathVariable("menuId") Long menuId) {
+        if (menuService.hasChildByMenuId(menuId)) {
+            return R.warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+        }
+        if (menuService.checkMenuExistRole(menuId)) {
+            return R.warn("鑿滃崟宸插垎閰�,涓嶅厑璁稿垹闄�");
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
new file mode 100644
index 0000000..5d65137
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
@@ -0,0 +1,90 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.sse.utils.SseMessageUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+import org.dromara.system.service.ISysNoticeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 鍏憡 淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/notice")
+public class SysNoticeController extends BaseController {
+
+    private final ISysNoticeService noticeService;
+    private final DictService dictService;
+
+    /**
+     * 鑾峰彇閫氱煡鍏憡鍒楄〃
+     */
+    @SaCheckPermission("system:notice:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysNoticeVo> list(SysNoticeBo notice, PageQuery pageQuery) {
+        return noticeService.selectPageNoticeList(notice, pageQuery);
+    }
+
+    /**
+     * 鏍规嵁閫氱煡鍏憡缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param noticeId 鍏憡ID
+     */
+    @SaCheckPermission("system:notice:query")
+    @GetMapping(value = "/{noticeId}")
+    public R<SysNoticeVo> getInfo(@PathVariable Long noticeId) {
+        return R.ok(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 鏂板閫氱煡鍏憡
+     */
+    @SaCheckPermission("system:notice:add")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysNoticeBo notice) {
+        int rows = noticeService.insertNotice(notice);
+        if (rows <= 0) {
+            return R.fail();
+        }
+        String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType());
+        SseMessageUtils.publishAll("[" + type + "] " + notice.getNoticeTitle());
+        return R.ok();
+    }
+
+    /**
+     * 淇敼閫氱煡鍏憡
+     */
+    @SaCheckPermission("system:notice:edit")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysNoticeBo notice) {
+        return toAjax(noticeService.updateNotice(notice));
+    }
+
+    /**
+     * 鍒犻櫎閫氱煡鍏憡
+     *
+     * @param noticeIds 鍏憡ID涓�
+     */
+    @SaCheckPermission("system:notice:remove")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{noticeIds}")
+    public R<Void> remove(@PathVariable Long[] noticeIds) {
+        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java
new file mode 100644
index 0000000..24ddaff
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java
@@ -0,0 +1,105 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOssConfigBo;
+import org.dromara.system.domain.vo.SysOssConfigVo;
+import org.dromara.system.service.ISysOssConfigService;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/resource/oss/config")
+public class SysOssConfigController extends BaseController {
+
+    private final ISysOssConfigService ossConfigService;
+
+    /**
+     * 鏌ヨ瀵硅薄瀛樺偍閰嶇疆鍒楄〃
+     */
+    @SaCheckPermission("system:ossConfig:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) {
+        return ossConfigService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 鑾峰彇瀵硅薄瀛樺偍閰嶇疆璇︾粏淇℃伅
+     *
+     * @param ossConfigId OSS閰嶇疆ID
+     */
+    @SaCheckPermission("system:ossConfig:list")
+    @GetMapping("/{ossConfigId}")
+    public R<SysOssConfigVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long ossConfigId) {
+        return R.ok(ossConfigService.queryById(ossConfigId));
+    }
+
+    /**
+     * 鏂板瀵硅薄瀛樺偍閰嶇疆
+     */
+    @SaCheckPermission("system:ossConfig:add")
+    @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
+        return toAjax(ossConfigService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼瀵硅薄瀛樺偍閰嶇疆
+     */
+    @SaCheckPermission("system:ossConfig:edit")
+    @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
+        return toAjax(ossConfigService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎瀵硅薄瀛樺偍閰嶇疆
+     *
+     * @param ossConfigIds OSS閰嶇疆ID涓�
+     */
+    @SaCheckPermission("system:ossConfig:remove")
+    @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ossConfigIds}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ossConfigIds) {
+        return toAjax(ossConfigService.deleteWithValidByIds(List.of(ossConfigIds), true));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckPermission("system:ossConfig:edit")
+    @Log(title = "瀵硅薄瀛樺偍鐘舵�佷慨鏀�", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {
+        return toAjax(ossConfigService.updateOssConfigStatus(bo));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
new file mode 100644
index 0000000..73ada3b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java
@@ -0,0 +1,108 @@
+package org.dromara.system.controller.system;
+
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOssBo;
+import org.dromara.system.domain.vo.SysOssUploadVo;
+import org.dromara.system.domain.vo.SysOssVo;
+import org.dromara.system.service.ISysOssService;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 鏂囦欢涓婁紶 鎺у埗灞�
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/resource/oss")
+public class SysOssController extends BaseController {
+
+    private final ISysOssService ossService;
+
+    /**
+     * 鏌ヨOSS瀵硅薄瀛樺偍鍒楄〃
+     */
+    @SaCheckPermission("system:oss:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) {
+        return ossService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨOSS瀵硅薄鍩轰簬id涓�
+     *
+     * @param ossIds OSS瀵硅薄ID涓�
+     */
+    @SaCheckPermission("system:oss:list")
+    @GetMapping("/listByIds/{ossIds}")
+    public R<List<SysOssVo>> listByIds(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                                       @PathVariable Long[] ossIds) {
+        List<SysOssVo> list = ossService.listByIds(Arrays.asList(ossIds));
+        return R.ok(list);
+    }
+
+    /**
+     * 涓婁紶OSS瀵硅薄瀛樺偍
+     *
+     * @param file 鏂囦欢
+     */
+    @SaCheckPermission("system:oss:upload")
+    @Log(title = "OSS瀵硅薄瀛樺偍", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<SysOssUploadVo> upload(@RequestPart("file") MultipartFile file) {
+        if (ObjectUtil.isNull(file)) {
+            return R.fail("涓婁紶鏂囦欢涓嶈兘涓虹┖");
+        }
+        SysOssVo oss = ossService.upload(file);
+        SysOssUploadVo uploadVo = new SysOssUploadVo();
+        uploadVo.setUrl(oss.getUrl());
+        uploadVo.setFileName(oss.getOriginalName());
+        uploadVo.setOssId(oss.getOssId().toString());
+        return R.ok(uploadVo);
+    }
+
+    /**
+     * 涓嬭浇OSS瀵硅薄
+     *
+     * @param ossId OSS瀵硅薄ID
+     */
+    @SaCheckPermission("system:oss:download")
+    @GetMapping("/download/{ossId}")
+    public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
+        ossService.download(ossId, response);
+    }
+
+    /**
+     * 鍒犻櫎OSS瀵硅薄瀛樺偍
+     *
+     * @param ossIds OSS瀵硅薄ID涓�
+     */
+    @SaCheckPermission("system:oss:remove")
+    @Log(title = "OSS瀵硅薄瀛樺偍", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ossIds}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ossIds) {
+        return toAjax(ossService.deleteWithValidByIds(List.of(ossIds), true));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
new file mode 100644
index 0000000..782bcfc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
@@ -0,0 +1,133 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.service.ISysPostService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/post")
+public class SysPostController extends BaseController {
+
+    private final ISysPostService postService;
+
+    /**
+     * 鑾峰彇宀椾綅鍒楄〃
+     */
+    @SaCheckPermission("system:post:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysPostVo> list(SysPostBo post, PageQuery pageQuery) {
+        return postService.selectPagePostList(post, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭宀椾綅鍒楄〃
+     */
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:post:export")
+    @PostMapping("/export")
+    public void export(SysPostBo post, HttpServletResponse response) {
+        List<SysPostVo> list = postService.selectPostList(post);
+        ExcelUtil.exportExcel(list, "宀椾綅鏁版嵁", SysPostVo.class, response);
+    }
+
+    /**
+     * 鏍规嵁宀椾綅缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param postId 宀椾綅ID
+     */
+    @SaCheckPermission("system:post:query")
+    @GetMapping(value = "/{postId}")
+    public R<SysPostVo> getInfo(@PathVariable Long postId) {
+        return R.ok(postService.selectPostById(postId));
+    }
+
+    /**
+     * 鏂板宀椾綅
+     */
+    @SaCheckPermission("system:post:add")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysPostBo post) {
+        if (!postService.checkPostNameUnique(post)) {
+            return R.fail("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        } else if (!postService.checkPostCodeUnique(post)) {
+            return R.fail("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        }
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 淇敼宀椾綅
+     */
+    @SaCheckPermission("system:post:edit")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysPostBo post) {
+        if (!postService.checkPostNameUnique(post)) {
+            return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        } else if (!postService.checkPostCodeUnique(post)) {
+            return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        } else if (UserConstants.POST_DISABLE.equals(post.getStatus())
+            && postService.countUserPostById(post.getPostId()) > 0) {
+            return R.fail("璇ュ矖浣嶄笅瀛樺湪宸插垎閰嶇敤鎴凤紝涓嶈兘绂佺敤!");
+        }
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅
+     *
+     * @param postIds 宀椾綅ID涓�
+     */
+    @SaCheckPermission("system:post:remove")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postIds}")
+    public R<Void> remove(@PathVariable Long[] postIds) {
+        return toAjax(postService.deletePostByIds(postIds));
+    }
+
+    /**
+     * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     *
+     * @param postIds 宀椾綅ID涓�
+     * @param deptId  閮ㄩ棬id
+     */
+    @SaCheckPermission("system:post:query")
+    @GetMapping("/optionselect")
+    public R<List<SysPostVo>> optionselect(@RequestParam(required = false) Long[] postIds, @RequestParam(required = false) Long deptId) {
+        List<SysPostVo> list = new ArrayList<>();
+        if (ObjectUtil.isNotNull(deptId)) {
+            SysPostBo post = new SysPostBo();
+            post.setDeptId(deptId);
+            list = postService.selectPostList(post);
+        } else if (postIds != null) {
+            list = postService.selectPostByIds(List.of(postIds));
+        }
+        return R.ok(list);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
new file mode 100644
index 0000000..893b381
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -0,0 +1,132 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.FileUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.MimeTypeUtils;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.bo.SysUserPasswordBo;
+import org.dromara.system.domain.bo.SysUserProfileBo;
+import org.dromara.system.domain.vo.AvatarVo;
+import org.dromara.system.domain.vo.ProfileVo;
+import org.dromara.system.domain.vo.SysOssVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysOssService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Arrays;
+
+/**
+ * 涓汉淇℃伅 涓氬姟澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController {
+
+    private final ISysUserService userService;
+    private final ISysOssService ossService;
+
+    /**
+     * 涓汉淇℃伅
+     */
+    @GetMapping
+    public R<ProfileVo> profile() {
+        SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
+        ProfileVo profileVo = new ProfileVo();
+        profileVo.setUser(user);
+        profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserId()));
+        profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserId()));
+        return R.ok(profileVo);
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛淇℃伅
+     */
+    @RepeatSubmit
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> updateProfile(@Validated @RequestBody SysUserProfileBo profile) {
+        SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class);
+        user.setUserId(LoginHelper.getUserId());
+        String username = LoginHelper.getUsername();
+        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+            return R.fail("淇敼鐢ㄦ埛'" + username + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+            return R.fail("淇敼鐢ㄦ埛'" + username + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user));
+        if (rows > 0) {
+            return R.ok();
+        }
+        return R.fail("淇敼涓汉淇℃伅寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     *
+     * @param bo 鏂版棫瀵嗙爜
+     */
+    @RepeatSubmit
+    @ApiEncrypt
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public R<Void> updatePwd(@Validated @RequestBody SysUserPasswordBo bo) {
+        SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
+        String password = user.getPassword();
+        if (!BCrypt.checkpw(bo.getOldPassword(), password)) {
+            return R.fail("淇敼瀵嗙爜澶辫触锛屾棫瀵嗙爜閿欒");
+        }
+        if (BCrypt.checkpw(bo.getNewPassword(), password)) {
+            return R.fail("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
+        }
+
+        if (userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword())) > 0) {
+            return R.ok();
+        }
+        return R.fail("淇敼瀵嗙爜寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 澶村儚涓婁紶
+     *
+     * @param avatarfile 鐢ㄦ埛澶村儚
+     */
+    @RepeatSubmit
+    @Log(title = "鐢ㄦ埛澶村儚", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<AvatarVo> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) {
+        if (!avatarfile.isEmpty()) {
+            String extension = FileUtil.extName(avatarfile.getOriginalFilename());
+            if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
+                return R.fail("鏂囦欢鏍煎紡涓嶆纭紝璇蜂笂浼�" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "鏍煎紡");
+            }
+            SysOssVo oss = ossService.upload(avatarfile);
+            String avatar = oss.getUrl();
+            if (userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId())) {
+                AvatarVo avatarVo = new AvatarVo();
+                avatarVo.setImgUrl(avatar);
+                return R.ok(avatarVo);
+            }
+        }
+        return R.fail("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java
new file mode 100644
index 0000000..d4a9dc8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java
@@ -0,0 +1,229 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.DeptTreeSelectVo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysRoleService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 瑙掕壊淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController {
+
+    private final ISysRoleService roleService;
+    private final ISysUserService userService;
+    private final ISysDeptService deptService;
+
+    /**
+     * 鑾峰彇瑙掕壊淇℃伅鍒楄〃
+     */
+    @SaCheckPermission("system:role:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysRoleVo> list(SysRoleBo role, PageQuery pageQuery) {
+        return roleService.selectPageRoleList(role, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭瑙掕壊淇℃伅鍒楄〃
+     */
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:role:export")
+    @PostMapping("/export")
+    public void export(SysRoleBo role, HttpServletResponse response) {
+        List<SysRoleVo> list = roleService.selectRoleList(role);
+        ExcelUtil.exportExcel(list, "瑙掕壊鏁版嵁", SysRoleVo.class, response);
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param roleId 瑙掕壊ID
+     */
+    @SaCheckPermission("system:role:query")
+    @GetMapping(value = "/{roleId}")
+    public R<SysRoleVo> getInfo(@PathVariable Long roleId) {
+        roleService.checkRoleDataScope(roleId);
+        return R.ok(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 鏂板瑙掕壊
+     */
+    @SaCheckPermission("system:role:add")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysRoleBo role) {
+        roleService.checkRoleAllowed(role);
+        if (!roleService.checkRoleNameUnique(role)) {
+            return R.fail("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        } else if (!roleService.checkRoleKeyUnique(role)) {
+            return R.fail("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysRoleBo role) {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        if (!roleService.checkRoleNameUnique(role)) {
+            return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        } else if (!roleService.checkRoleKeyUnique(role)) {
+            return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+
+        if (roleService.updateRole(role) > 0) {
+            roleService.cleanOnlineUserByRole(role.getRoleId());
+            return R.ok();
+        }
+        return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑱旂郴绠$悊鍛�");
+    }
+
+    /**
+     * 淇敼淇濆瓨鏁版嵁鏉冮檺
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/dataScope")
+    public R<Void> dataScope(@RequestBody SysRoleBo role) {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        return toAjax(roleService.authDataScope(role));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysRoleBo role) {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        return toAjax(roleService.updateRoleStatus(role.getRoleId(), role.getStatus()));
+    }
+
+    /**
+     * 鍒犻櫎瑙掕壊
+     *
+     * @param roleIds 瑙掕壊ID涓�
+     */
+    @SaCheckPermission("system:role:remove")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public R<Void> remove(@PathVariable Long[] roleIds) {
+        return toAjax(roleService.deleteRoleByIds(roleIds));
+    }
+
+    /**
+     * 鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     *
+     * @param roleIds 瑙掕壊ID涓�
+     */
+    @SaCheckPermission("system:role:query")
+    @GetMapping("/optionselect")
+    public R<List<SysRoleVo>> optionselect(@RequestParam(required = false) Long[] roleIds) {
+        return R.ok(roleService.selectRoleByIds(roleIds == null ? null : List.of(roleIds)));
+    }
+
+    /**
+     * 鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+     */
+    @SaCheckPermission("system:role:list")
+    @GetMapping("/authUser/allocatedList")
+    public TableDataInfo<SysUserVo> allocatedList(SysUserBo user, PageQuery pageQuery) {
+        return userService.selectAllocatedList(user, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+     */
+    @SaCheckPermission("system:role:list")
+    @GetMapping("/authUser/unallocatedList")
+    public TableDataInfo<SysUserVo> unallocatedList(SysUserBo user, PageQuery pageQuery) {
+        return userService.selectUnallocatedList(user, pageQuery);
+    }
+
+    /**
+     * 鍙栨秷鎺堟潈鐢ㄦ埛
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancel")
+    public R<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
+        return toAjax(roleService.deleteAuthUser(userRole));
+    }
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 鐢ㄦ埛ID涓�
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancelAll")
+    public R<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
+        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 鎵归噺閫夋嫨鐢ㄦ埛鎺堟潈
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 鐢ㄦ埛ID涓�
+     */
+    @SaCheckPermission("system:role:edit")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/selectAll")
+    public R<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
+        roleService.checkRoleDataScope(roleId);
+        return toAjax(roleService.insertAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 鑾峰彇瀵瑰簲瑙掕壊閮ㄩ棬鏍戝垪琛�
+     *
+     * @param roleId 瑙掕壊ID
+     */
+    @SaCheckPermission("system:role:list")
+    @GetMapping(value = "/deptTree/{roleId}")
+    public R<DeptTreeSelectVo> roleDeptTreeselect(@PathVariable("roleId") Long roleId) {
+        DeptTreeSelectVo selectVo = new DeptTreeSelectVo();
+        selectVo.setCheckedKeys(deptService.selectDeptListByRoleId(roleId));
+        selectVo.setDepts(deptService.selectDeptTreeList(new SysDeptBo()));
+        return R.ok(selectVo);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java
new file mode 100644
index 0000000..b0281cf
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java
@@ -0,0 +1,38 @@
+package org.dromara.system.controller.system;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.service.ISysSocialService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯�
+ *
+ * @author thiszhc
+ * @date 2023-06-16
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/social")
+public class SysSocialController extends BaseController {
+
+    private final ISysSocialService socialUserService;
+
+    /**
+     * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+     */
+    @GetMapping("/list")
+    public R<List<SysSocialVo>> list() {
+        return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId()));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
new file mode 100644
index 0000000..bad240c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -0,0 +1,179 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import com.baomidou.lock.annotation.Lock4j;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.service.ISysTenantService;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 绉熸埛绠$悊
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/tenant")
+@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
+public class SysTenantController extends BaseController {
+
+    private final ISysTenantService tenantService;
+
+    /**
+     * 鏌ヨ绉熸埛鍒楄〃
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysTenantVo> list(SysTenantBo bo, PageQuery pageQuery) {
+        return tenantService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭绉熸埛鍒楄〃
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:export")
+    @Log(title = "绉熸埛", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysTenantBo bo, HttpServletResponse response) {
+        List<SysTenantVo> list = tenantService.queryList(bo);
+        ExcelUtil.exportExcel(list, "绉熸埛", SysTenantVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇绉熸埛璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:query")
+    @GetMapping("/{id}")
+    public R<SysTenantVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                  @PathVariable Long id) {
+        return R.ok(tenantService.queryById(id));
+    }
+
+    /**
+     * 鏂板绉熸埛
+     */
+    @ApiEncrypt
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:add")
+    @Log(title = "绉熸埛", businessType = BusinessType.INSERT)
+    @Lock4j
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) {
+        if (!tenantService.checkCompanyNameUnique(bo)) {
+            return R.fail("鏂板绉熸埛'" + bo.getCompanyName() + "'澶辫触锛屼紒涓氬悕绉板凡瀛樺湪");
+        }
+        return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo)));
+    }
+
+    /**
+     * 淇敼绉熸埛
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:edit")
+    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) {
+        tenantService.checkTenantAllowed(bo.getTenantId());
+        if (!tenantService.checkCompanyNameUnique(bo)) {
+            return R.fail("淇敼绉熸埛'" + bo.getCompanyName() + "'澶辫触锛屽叕鍙稿悕绉板凡瀛樺湪");
+        }
+        return toAjax(tenantService.updateByBo(bo));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:edit")
+    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysTenantBo bo) {
+        tenantService.checkTenantAllowed(bo.getTenantId());
+        return toAjax(tenantService.updateTenantStatus(bo));
+    }
+
+    /**
+     * 鍒犻櫎绉熸埛
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:remove")
+    @Log(title = "绉熸埛", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(tenantService.deleteWithValidByIds(List.of(ids), true));
+    }
+
+    /**
+     * 鍔ㄦ�佸垏鎹㈢鎴�
+     *
+     * @param tenantId 绉熸埛ID
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @GetMapping("/dynamic/{tenantId}")
+    public R<Void> dynamicTenant(@NotBlank(message = "绉熸埛ID涓嶈兘涓虹┖") @PathVariable String tenantId) {
+        TenantHelper.setDynamic(tenantId, true);
+        return R.ok();
+    }
+
+    /**
+     * 娓呴櫎鍔ㄦ�佺鎴�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @GetMapping("/dynamic/clear")
+    public R<Void> dynamicClear() {
+        TenantHelper.clearDynamic();
+        return R.ok();
+    }
+
+
+    /**
+     * 鍚屾绉熸埛濂楅
+     *
+     * @param tenantId  绉熸埛id
+     * @param packageId 濂楅id
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenant:edit")
+    @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+    @GetMapping("/syncTenantPackage")
+    public R<Void> syncTenantPackage(@NotBlank(message = "绉熸埛ID涓嶈兘涓虹┖") String tenantId,
+                                     @NotNull(message = "濂楅ID涓嶈兘涓虹┖") Long packageId) {
+        return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
new file mode 100644
index 0000000..4bfe597
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
@@ -0,0 +1,142 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+import org.dromara.system.service.ISysTenantPackageService;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅绠$悊
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/tenant/package")
+@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
+public class SysTenantPackageController extends BaseController {
+
+    private final ISysTenantPackageService tenantPackageService;
+
+    /**
+     * 鏌ヨ绉熸埛濂楅鍒楄〃
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysTenantPackageVo> list(SysTenantPackageBo bo, PageQuery pageQuery) {
+        return tenantPackageService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ绉熸埛濂楅涓嬫媺閫夊垪琛�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:list")
+    @GetMapping("/selectList")
+    public R<List<SysTenantPackageVo>> selectList() {
+        return R.ok(tenantPackageService.selectList());
+    }
+
+    /**
+     * 瀵煎嚭绉熸埛濂楅鍒楄〃
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:export")
+    @Log(title = "绉熸埛濂楅", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(SysTenantPackageBo bo, HttpServletResponse response) {
+        List<SysTenantPackageVo> list = tenantPackageService.queryList(bo);
+        ExcelUtil.exportExcel(list, "绉熸埛濂楅", SysTenantPackageVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇绉熸埛濂楅璇︾粏淇℃伅
+     *
+     * @param packageId 涓婚敭
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:query")
+    @GetMapping("/{packageId}")
+    public R<SysTenantPackageVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long packageId) {
+        return R.ok(tenantPackageService.queryById(packageId));
+    }
+
+    /**
+     * 鏂板绉熸埛濂楅
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:add")
+    @Log(title = "绉熸埛濂楅", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) {
+        if (!tenantPackageService.checkPackageNameUnique(bo)) {
+            return R.fail("鏂板濂楅'" + bo.getPackageName() + "'澶辫触锛屽椁愬悕绉板凡瀛樺湪");
+        }
+        return toAjax(tenantPackageService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼绉熸埛濂楅
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:edit")
+    @Log(title = "绉熸埛濂楅", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) {
+        if (!tenantPackageService.checkPackageNameUnique(bo)) {
+            return R.fail("淇敼濂楅'" + bo.getPackageName() + "'澶辫触锛屽椁愬悕绉板凡瀛樺湪");
+        }
+        return toAjax(tenantPackageService.updateByBo(bo));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:edit")
+    @Log(title = "绉熸埛濂楅", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysTenantPackageBo bo) {
+        return toAjax(tenantPackageService.updatePackageStatus(bo));
+    }
+
+    /**
+     * 鍒犻櫎绉熸埛濂楅
+     *
+     * @param packageIds 涓婚敭涓�
+     */
+    @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+    @SaCheckPermission("system:tenantPackage:remove")
+    @Log(title = "绉熸埛濂楅", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{packageIds}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] packageIds) {
+        return toAjax(tenantPackageService.deleteWithValidByIds(List.of(packageIds), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
new file mode 100644
index 0000000..36104d6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
@@ -0,0 +1,300 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.*;
+import org.dromara.system.listener.SysUserImportListener;
+import org.dromara.system.service.*;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController {
+
+    private final ISysUserService userService;
+    private final ISysRoleService roleService;
+    private final ISysPostService postService;
+    private final ISysDeptService deptService;
+    private final ISysTenantService tenantService;
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鍒楄〃
+     */
+    @SaCheckPermission("system:user:list")
+    @GetMapping("/list")
+    public TableDataInfo<SysUserVo> list(SysUserBo user, PageQuery pageQuery) {
+        return userService.selectPageUserList(user, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鐢ㄦ埛鍒楄〃
+     */
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.EXPORT)
+    @SaCheckPermission("system:user:export")
+    @PostMapping("/export")
+    public void export(SysUserBo user, HttpServletResponse response) {
+        List<SysUserExportVo> list = userService.selectUserExportList(user);
+        ExcelUtil.exportExcel(list, "鐢ㄦ埛鏁版嵁", SysUserExportVo.class, response);
+    }
+
+    /**
+     * 瀵煎叆鏁版嵁
+     *
+     * @param file          瀵煎叆鏂囦欢
+     * @param updateSupport 鏄惁鏇存柊宸插瓨鍦ㄦ暟鎹�
+     */
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.IMPORT)
+    @SaCheckPermission("system:user:import")
+    @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    public R<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
+        ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
+        return R.ok(result.getAnalysis());
+    }
+
+    /**
+     * 鑾峰彇瀵煎叆妯℃澘
+     */
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response) {
+        ExcelUtil.exportExcel(new ArrayList<>(), "鐢ㄦ埛鏁版嵁", SysUserImportVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛淇℃伅
+     *
+     * @return 鐢ㄦ埛淇℃伅
+     */
+    @GetMapping("/getInfo")
+    public R<UserInfoVo> getInfo() {
+        UserInfoVo userInfoVo = new UserInfoVo();
+        LoginUser loginUser = LoginHelper.getLoginUser();
+        if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
+            // 瓒呯骇绠$悊鍛� 濡傛灉閲嶆柊鍔犺浇鐢ㄦ埛淇℃伅闇�娓呴櫎鍔ㄦ�佺鎴�
+            TenantHelper.clearDynamic();
+        }
+        SysUserVo user = userService.selectUserById(loginUser.getUserId());
+        if (ObjectUtil.isNull(user)) {
+            return R.fail("娌℃湁鏉冮檺璁块棶鐢ㄦ埛鏁版嵁!");
+        }
+        userInfoVo.setUser(user);
+        userInfoVo.setPermissions(loginUser.getMenuPermission());
+        userInfoVo.setRoles(loginUser.getRolePermission());
+        return R.ok(userInfoVo);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇璇︾粏淇℃伅
+     *
+     * @param userId 鐢ㄦ埛ID
+     */
+    @SaCheckPermission("system:user:query")
+    @GetMapping(value = {"/", "/{userId}"})
+    public R<SysUserInfoVo> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
+        userService.checkUserDataScope(userId);
+        SysUserInfoVo userInfoVo = new SysUserInfoVo();
+        SysRoleBo roleBo = new SysRoleBo();
+        roleBo.setStatus(UserConstants.ROLE_NORMAL);
+        List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
+        userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
+        if (ObjectUtil.isNotNull(userId)) {
+            SysUserVo sysUser = userService.selectUserById(userId);
+            userInfoVo.setUser(sysUser);
+            userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId));
+            Long deptId = sysUser.getDeptId();
+            if (ObjectUtil.isNotNull(deptId)) {
+                SysPostBo postBo = new SysPostBo();
+                postBo.setDeptId(deptId);
+                userInfoVo.setPosts(postService.selectPostList(postBo));
+                userInfoVo.setPostIds(postService.selectPostListByUserId(userId));
+            }
+        }
+        return R.ok(userInfoVo);
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛
+     */
+    @SaCheckPermission("system:user:add")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R<Void> add(@Validated @RequestBody SysUserBo user) {
+        deptService.checkDeptDataScope(user.getDeptId());
+        if (!userService.checkUserNameUnique(user)) {
+            return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+            return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+            return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        if (TenantHelper.isEnable()) {
+            if (!tenantService.checkAccountBalance(TenantHelper.getTenantId())) {
+                return R.fail("褰撳墠绉熸埛涓嬬敤鎴峰悕棰濅笉瓒筹紝璇疯仈绯荤鐞嗗憳");
+            }
+        }
+        user.setPassword(BCrypt.hashpw(user.getPassword()));
+        return toAjax(userService.insertUser(user));
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛
+     */
+    @SaCheckPermission("system:user:edit")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R<Void> edit(@Validated @RequestBody SysUserBo user) {
+        userService.checkUserAllowed(user.getUserId());
+        userService.checkUserDataScope(user.getUserId());
+        deptService.checkDeptDataScope(user.getDeptId());
+        if (!userService.checkUserNameUnique(user)) {
+            return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+            return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+            return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 鍒犻櫎鐢ㄦ埛
+     *
+     * @param userIds 瑙掕壊ID涓�
+     */
+    @SaCheckPermission("system:user:remove")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userIds}")
+    public R<Void> remove(@PathVariable Long[] userIds) {
+        if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) {
+            return R.fail("褰撳墠鐢ㄦ埛涓嶈兘鍒犻櫎");
+        }
+        return toAjax(userService.deleteUserByIds(userIds));
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID涓叉壒閲忚幏鍙栫敤鎴峰熀纭�淇℃伅
+     *
+     * @param userIds 鐢ㄦ埛ID涓�
+     * @param deptId  閮ㄩ棬ID
+     */
+    @SaCheckPermission("system:user:query")
+    @GetMapping("/optionselect")
+    public R<List<SysUserVo>> optionselect(@RequestParam(required = false) Long[] userIds,
+                                           @RequestParam(required = false) Long deptId) {
+        return R.ok(userService.selectUserByIds(userIds == null ? null : List.of(userIds), deptId));
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     */
+    @ApiEncrypt
+    @SaCheckPermission("system:user:resetPwd")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public R<Void> resetPwd(@RequestBody SysUserBo user) {
+        userService.checkUserAllowed(user.getUserId());
+        userService.checkUserDataScope(user.getUserId());
+        user.setPassword(BCrypt.hashpw(user.getPassword()));
+        return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword()));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @SaCheckPermission("system:user:edit")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public R<Void> changeStatus(@RequestBody SysUserBo user) {
+        userService.checkUserAllowed(user.getUserId());
+        userService.checkUserDataScope(user.getUserId());
+        return toAjax(userService.updateUserStatus(user.getUserId(), user.getStatus()));
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇鎺堟潈瑙掕壊
+     *
+     * @param userId 鐢ㄦ埛ID
+     */
+    @SaCheckPermission("system:user:query")
+    @GetMapping("/authRole/{userId}")
+    public R<SysUserInfoVo> authRole(@PathVariable Long userId) {
+        userService.checkUserDataScope(userId);
+        SysUserVo user = userService.selectUserById(userId);
+        List<SysRoleVo> roles = roleService.selectRolesAuthByUserId(userId);
+        SysUserInfoVo userInfoVo = new SysUserInfoVo();
+        userInfoVo.setUser(user);
+        userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
+        return R.ok(userInfoVo);
+    }
+
+    /**
+     * 鐢ㄦ埛鎺堟潈瑙掕壊
+     *
+     * @param userId  鐢ㄦ埛Id
+     * @param roleIds 瑙掕壊ID涓�
+     */
+    @SaCheckPermission("system:user:edit")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.GRANT)
+    @PutMapping("/authRole")
+    public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
+        userService.checkUserDataScope(userId);
+        userService.insertUserAuth(userId, roleIds);
+        return R.ok();
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬鏍戝垪琛�
+     */
+    @SaCheckPermission("system:user:list")
+    @GetMapping("/deptTree")
+    public R<List<Tree<Long>>> deptTree(SysDeptBo dept) {
+        return R.ok(deptService.selectDeptTreeList(dept));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬涓嬬殑鎵�鏈夌敤鎴蜂俊鎭�
+     */
+    @SaCheckPermission("system:user:list")
+    @GetMapping("/list/dept/{deptId}")
+    public R<List<SysUserVo>> listByDept(@PathVariable @NotNull Long deptId) {
+        return R.ok(userService.selectUserListByDept(deptId));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java
new file mode 100644
index 0000000..e398a20
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java
@@ -0,0 +1,47 @@
+package org.dromara.system.domain;
+
+import org.dromara.common.core.utils.StringUtils;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 缂撳瓨淇℃伅
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+public class SysCache {
+
+    /**
+     * 缂撳瓨鍚嶇О
+     */
+    private String cacheName = "";
+
+    /**
+     * 缂撳瓨閿悕
+     */
+    private String cacheKey = "";
+
+    /**
+     * 缂撳瓨鍐呭
+     */
+    private String cacheValue = "";
+
+    /**
+     * 澶囨敞
+     */
+    private String remark = "";
+
+    public SysCache(String cacheName, String remark) {
+        this.cacheName = cacheName;
+        this.remark = remark;
+    }
+
+    public SysCache(String cacheName, String cacheKey, String cacheValue) {
+        this.cacheName = StringUtils.replace(cacheName, ":", "");
+        this.cacheKey = StringUtils.replace(cacheKey, cacheName, "");
+        this.cacheValue = cacheValue;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
new file mode 100644
index 0000000..0f681be
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
@@ -0,0 +1,77 @@
+package org.dromara.system.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 鎺堟潈绠$悊瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ * @date 2023-05-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_client")
+public class SysClient extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 瀹㈡埛绔痠d
+     */
+    private String clientId;
+
+    /**
+     * 瀹㈡埛绔痥ey
+     */
+    private String clientKey;
+
+    /**
+     * 瀹㈡埛绔閽�
+     */
+    private String clientSecret;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    private String grantType;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * token娲昏穬瓒呮椂鏃堕棿
+     */
+    private Long activeTimeout;
+
+    /**
+     * token鍥哄畾瓒呮椂鏃堕棿
+     */
+    private Long timeout;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java
new file mode 100644
index 0000000..6fcb88f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java
@@ -0,0 +1,51 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 鍙傛暟閰嶇疆琛� sys_config
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_config")
+public class SysConfig extends TenantEntity {
+
+    /**
+     * 鍙傛暟涓婚敭
+     */
+    @TableId(value = "config_id")
+    private Long configId;
+
+    /**
+     * 鍙傛暟鍚嶇О
+     */
+    private String configName;
+
+    /**
+     * 鍙傛暟閿悕
+     */
+    private String configKey;
+
+    /**
+     * 鍙傛暟閿��
+     */
+    private String configValue;
+
+    /**
+     * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+     */
+    private String configType;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
new file mode 100644
index 0000000..48ca682
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
@@ -0,0 +1,83 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 閮ㄩ棬琛� sys_dept
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dept")
+public class SysDept extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @TableId(value = "dept_id")
+    private Long deptId;
+
+    /**
+     * 鐖堕儴闂↖D
+     */
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 閮ㄩ棬绫诲埆缂栫爜
+     */
+    private String deptCategory;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Integer orderNum;
+
+    /**
+     * 璐熻矗浜�
+     */
+    private Long leader;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    private String phone;
+
+    /**
+     * 閭
+     */
+    private String email;
+
+    /**
+     * 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤
+     */
+    private String status;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 绁栫骇鍒楄〃
+     */
+    private String ancestors;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
new file mode 100644
index 0000000..6884fc2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
@@ -0,0 +1,71 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 瀛楀吀鏁版嵁琛� sys_dict_data
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dict_data")
+public class SysDictData extends TenantEntity {
+
+    /**
+     * 瀛楀吀缂栫爜
+     */
+    @TableId(value = "dict_code")
+    private Long dictCode;
+
+    /**
+     * 瀛楀吀鎺掑簭
+     */
+    private Integer dictSort;
+
+    /**
+     * 瀛楀吀鏍囩
+     */
+    private String dictLabel;
+
+    /**
+     * 瀛楀吀閿��
+     */
+    private String dictValue;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    private String dictType;
+
+    /**
+     * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+     */
+    private String cssClass;
+
+    /**
+     * 琛ㄦ牸瀛楀吀鏍峰紡
+     */
+    private String listClass;
+
+    /**
+     * 鏄惁榛樿锛圷鏄� N鍚︼級
+     */
+    private String isDefault;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    public boolean getDefault() {
+        return UserConstants.YES.equals(this.isDefault);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java
new file mode 100644
index 0000000..955af85
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java
@@ -0,0 +1,41 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 瀛楀吀绫诲瀷琛� sys_dict_type
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dict_type")
+public class SysDictType extends TenantEntity {
+
+    /**
+     * 瀛楀吀涓婚敭
+     */
+    @TableId(value = "dict_id")
+    private Long dictId;
+
+    /**
+     * 瀛楀吀鍚嶇О
+     */
+    private String dictName;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    private String dictType;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java
new file mode 100644
index 0000000..c57dc0a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java
@@ -0,0 +1,85 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 绯荤粺璁块棶璁板綍琛� sys_logininfor
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_logininfor")
+public class SysLogininfor implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @TableId(value = "info_id")
+    private Long infoId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * 鐧诲綍鐘舵�� 0鎴愬姛 1澶辫触
+     */
+    private String status;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦扮偣
+     */
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String os;
+
+    /**
+     * 鎻愮ず娑堟伅
+     */
+    private String msg;
+
+    /**
+     * 璁块棶鏃堕棿
+     */
+    private Date loginTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
new file mode 100644
index 0000000..6b498a3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
@@ -0,0 +1,191 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鑿滃崟鏉冮檺琛� sys_menu
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_menu")
+public class SysMenu extends BaseEntity {
+
+    /**
+     * 鑿滃崟ID
+     */
+    @TableId(value = "menu_id")
+    private Long menuId;
+
+    /**
+     * 鐖惰彍鍗旾D
+     */
+    private Long parentId;
+
+    /**
+     * 鑿滃崟鍚嶇О
+     */
+    private String menuName;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Integer orderNum;
+
+    /**
+     * 璺敱鍦板潃
+     */
+    private String path;
+
+    /**
+     * 缁勪欢璺緞
+     */
+    private String component;
+
+    /**
+     * 璺敱鍙傛暟
+     */
+    private String queryParam;
+
+    /**
+     * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+     */
+    private String isFrame;
+
+    /**
+     * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+     */
+    private String isCache;
+
+    /**
+     * 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    private String menuType;
+
+    /**
+     * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+     */
+    private String visible;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鏉冮檺瀛楃涓�
+     */
+    private String perms;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鐖惰彍鍗曞悕绉�
+     */
+    @TableField(exist = false)
+    private String parentName;
+
+    /**
+     * 瀛愯彍鍗�
+     */
+    @TableField(exist = false)
+    private List<SysMenu> children = new ArrayList<>();
+
+    /**
+     * 鑾峰彇璺敱鍚嶇О
+     */
+    public String getRouteName() {
+        String routerName = StringUtils.capitalize(path);
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+        if (isMenuFrame()) {
+            routerName = StringUtils.EMPTY;
+        }
+        return routerName;
+    }
+
+    /**
+     * 鑾峰彇璺敱鍦板潃
+     */
+    public String getRouterPath() {
+        String routerPath = this.path;
+        // 鍐呴摼鎵撳紑澶栫綉鏂瑰紡
+        if (getParentId() != 0L && isInnerLink()) {
+            routerPath = innerLinkReplaceEach(routerPath);
+        }
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+        if (0L == getParentId() && UserConstants.TYPE_DIR.equals(getMenuType())
+            && UserConstants.NO_FRAME.equals(getIsFrame())) {
+            routerPath = "/" + this.path;
+        }
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓鸿彍鍗曪級
+        else if (isMenuFrame()) {
+            routerPath = "/";
+        }
+        return routerPath;
+    }
+
+    /**
+     * 鑾峰彇缁勪欢淇℃伅
+     */
+    public String getComponentInfo() {
+        String component = UserConstants.LAYOUT;
+        if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) {
+            component = this.component;
+        } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) {
+            component = UserConstants.INNER_LINK;
+        } else if (StringUtils.isEmpty(this.component) && isParentView()) {
+            component = UserConstants.PARENT_VIEW;
+        }
+        return component;
+    }
+
+    /**
+     * 鏄惁涓鸿彍鍗曞唴閮ㄨ烦杞�
+     */
+    public boolean isMenuFrame() {
+        return getParentId() == 0L && UserConstants.TYPE_MENU.equals(menuType) && isFrame.equals(UserConstants.NO_FRAME);
+    }
+
+    /**
+     * 鏄惁涓哄唴閾剧粍浠�
+     */
+    public boolean isInnerLink() {
+        return isFrame.equals(UserConstants.NO_FRAME) && StringUtils.ishttp(path);
+    }
+
+    /**
+     * 鏄惁涓簆arent_view缁勪欢
+     */
+    public boolean isParentView() {
+        return getParentId() != 0L && UserConstants.TYPE_DIR.equals(menuType);
+    }
+
+    /**
+     * 鍐呴摼鍩熷悕鐗规畩瀛楃鏇挎崲
+     */
+    public static String innerLinkReplaceEach(String path) {
+        return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"},
+            new String[]{"", "", "", "/", "/"});
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java
new file mode 100644
index 0000000..bfcc2bc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java
@@ -0,0 +1,51 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+
+/**
+ * 閫氱煡鍏憡琛� sys_notice
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_notice")
+public class SysNotice extends TenantEntity {
+
+    /**
+     * 鍏憡ID
+     */
+    @TableId(value = "notice_id")
+    private Long noticeId;
+
+    /**
+     * 鍏憡鏍囬
+     */
+    private String noticeTitle;
+
+    /**
+     * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+     */
+    private String noticeType;
+
+    /**
+     * 鍏憡鍐呭
+     */
+    private String noticeContent;
+
+    /**
+     * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java
new file mode 100644
index 0000000..41a8c59
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍琛� oper_log
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_oper_log")
+public class SysOperLog implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏃ュ織涓婚敭
+     */
+    @TableId(value = "oper_id")
+    private Long operId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鎿嶄綔妯″潡
+     */
+    private String title;
+
+    /**
+     * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+     */
+    private Integer businessType;
+
+    /**
+     * 璇锋眰鏂规硶
+     */
+    private String method;
+
+    /**
+     * 璇锋眰鏂瑰紡
+     */
+    private String requestMethod;
+
+    /**
+     * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+     */
+    private Integer operatorType;
+
+    /**
+     * 鎿嶄綔浜哄憳
+     */
+    private String operName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 璇锋眰url
+     */
+    private String operUrl;
+
+    /**
+     * 鎿嶄綔鍦板潃
+     */
+    private String operIp;
+
+    /**
+     * 鎿嶄綔鍦扮偣
+     */
+    private String operLocation;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    private String operParam;
+
+    /**
+     * 杩斿洖鍙傛暟
+     */
+    private String jsonResult;
+
+    /**
+     * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+     */
+    private Integer status;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    private String errorMsg;
+
+    /**
+     * 鎿嶄綔鏃堕棿
+     */
+    private Date operTime;
+
+    /**
+     * 娑堣�楁椂闂�
+     */
+    private Long costTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java
new file mode 100644
index 0000000..af88898
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java
@@ -0,0 +1,50 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * OSS瀵硅薄瀛樺偍瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_oss")
+public class SysOss extends TenantEntity {
+
+    /**
+     * 瀵硅薄瀛樺偍涓婚敭
+     */
+    @TableId(value = "oss_id")
+    private Long ossId;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String fileName;
+
+    /**
+     * 鍘熷悕
+     */
+    private String originalName;
+
+    /**
+     * 鏂囦欢鍚庣紑鍚�
+     */
+    private String fileSuffix;
+
+    /**
+     * URL鍦板潃
+     */
+    private String url;
+
+    /**
+     * 鏈嶅姟鍟�
+     */
+    private String service;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java
new file mode 100644
index 0000000..4b67d63
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java
@@ -0,0 +1,89 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_oss_config")
+public class SysOssConfig extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "oss_config_id")
+    private Long ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+    private String configKey;
+
+    /**
+     * accessKey
+     */
+    private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+    private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+    private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+    private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    private String endpoint;
+
+    /**
+     * 鑷畾涔夊煙鍚�
+     */
+    private String domain;
+
+    /**
+     * 鏄惁https锛�0鍚� 1鏄級
+     */
+    private String isHttps;
+
+    /**
+     * 鍩�
+     */
+    private String region;
+
+    /**
+     * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+     */
+    private String status;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+    private String ext1;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+     */
+    private String accessPolicy;
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java
new file mode 100644
index 0000000..2c985da
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java
@@ -0,0 +1,61 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 宀椾綅琛� sys_post
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_post")
+public class SysPost extends TenantEntity {
+
+    /**
+     * 宀椾綅搴忓彿
+     */
+    @TableId(value = "post_id")
+    private Long postId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private Long deptId;
+
+    /**
+     * 宀椾綅缂栫爜
+     */
+    private String postCode;
+
+    /**
+     * 宀椾綅鍚嶇О
+     */
+    private String postName;
+
+    /**
+     * 宀椾綅绫诲埆缂栫爜
+     */
+    private String postCategory;
+
+    /**
+     * 宀椾綅鎺掑簭
+     */
+    private Integer postSort;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
new file mode 100644
index 0000000..2b42464
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
@@ -0,0 +1,79 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 瑙掕壊琛� sys_role
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_role")
+public class SysRole extends TenantEntity {
+
+    /**
+     * 瑙掕壊ID
+     */
+    @TableId(value = "role_id")
+    private Long roleId;
+
+    /**
+     * 瑙掕壊鍚嶇О
+     */
+    private String roleName;
+
+    /**
+     * 瑙掕壊鏉冮檺
+     */
+    private String roleKey;
+
+    /**
+     * 瑙掕壊鎺掑簭
+     */
+    private Integer roleSort;
+
+    /**
+     * 鏁版嵁鑼冨洿锛�1锛氭墍鏈夋暟鎹潈闄愶紱2锛氳嚜瀹氫箟鏁版嵁鏉冮檺锛�3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺锛�4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶紱5锛氫粎鏈汉鏁版嵁鏉冮檺锛�
+     */
+    private String dataScope;
+
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
+     */
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀� 锛�
+     */
+    private Boolean deptCheckStrictly;
+
+    /**
+     * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    public SysRole(Long roleId) {
+        this.roleId = roleId;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java
new file mode 100644
index 0000000..ba77694
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 瑙掕壊鍜岄儴闂ㄥ叧鑱� sys_role_dept
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_role_dept")
+public class SysRoleDept {
+
+    /**
+     * 瑙掕壊ID
+     */
+    @TableId(type = IdType.INPUT)
+    private Long roleId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java
new file mode 100644
index 0000000..ba28f17
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 瑙掕壊鍜岃彍鍗曞叧鑱� sys_role_menu
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_role_menu")
+public class SysRoleMenu {
+
+    /**
+     * 瑙掕壊ID
+     */
+    @TableId(type = IdType.INPUT)
+    private Long roleId;
+
+    /**
+     * 鑿滃崟ID
+     */
+    private Long menuId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java
new file mode 100644
index 0000000..10f2936
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java
@@ -0,0 +1,136 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 绀句細鍖栧叧绯诲璞� sys_social
+ *
+ * @author thiszhc
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_social")
+public class SysSocial extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 鐨勫敮涓�ID
+     */
+    private String authId;
+
+    /**
+     * 鐢ㄦ埛鏉ユ簮
+     */
+    private String source;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+     */
+    private String accessToken;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private int expireIn;
+
+    /**
+     * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String refreshToken;
+
+    /**
+     * 鐢ㄦ埛鐨� open id
+     */
+    private String openId;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟閭
+     */
+    private String email;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+     */
+    private String avatar;
+
+    /**
+     * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String accessCode;
+
+    /**
+     * 鐢ㄦ埛鐨� unionid
+     */
+    private String unionId;
+
+    /**
+     * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String scope;
+
+    /**
+     * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String tokenType;
+
+    /**
+     * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String idToken;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macAlgorithm;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macKey;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String code;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthToken;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthTokenSecret;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
new file mode 100644
index 0000000..a564a40
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
@@ -0,0 +1,103 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 绉熸埛瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_tenant")
+public class SysTenant extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鑱旂郴浜�
+     */
+    private String contactUserName;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    private String contactPhone;
+
+    /**
+     * 浼佷笟鍚嶇О
+     */
+    private String companyName;
+
+    /**
+     * 缁熶竴绀句細淇$敤浠g爜
+     */
+    private String licenseNumber;
+
+    /**
+     * 鍦板潃
+     */
+    private String address;
+
+    /**
+     * 鍩熷悕
+     */
+    private String domain;
+
+    /**
+     * 浼佷笟绠�浠�
+     */
+    private String intro;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 绉熸埛濂楅缂栧彿
+     */
+    private Long packageId;
+
+    /**
+     * 杩囨湡鏃堕棿
+     */
+    private Date expireTime;
+
+    /**
+     * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+     */
+    private Long accountCount;
+
+    /**
+     * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
new file mode 100644
index 0000000..f7e423f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
@@ -0,0 +1,54 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 绉熸埛濂楅瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_tenant_package")
+public class SysTenantPackage extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绉熸埛濂楅id
+     */
+    @TableId(value = "package_id")
+    private Long packageId;
+    /**
+     * 濂楅鍚嶇О
+     */
+    private String packageName;
+    /**
+     * 鍏宠仈鑿滃崟id
+     */
+    private String menuIds;
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
+     */
+    private Boolean menuCheckStrictly;
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
new file mode 100644
index 0000000..8dde40b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄 sys_user
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_user")
+public class SysUser extends TenantEntity {
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @TableId(value = "user_id")
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+     */
+    private String userType;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆
+     */
+    private String sex;
+
+    /**
+     * 鐢ㄦ埛澶村儚
+     */
+    private Long avatar;
+
+    /**
+     * 瀵嗙爜
+     */
+    @TableField(
+        insertStrategy = FieldStrategy.NOT_EMPTY,
+        updateStrategy = FieldStrategy.NOT_EMPTY,
+        whereStrategy = FieldStrategy.NOT_EMPTY
+    )
+    private String password;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+     */
+    @TableLogic
+    private String delFlag;
+
+    /**
+     * 鏈�鍚庣櫥褰旾P
+     */
+    private String loginIp;
+
+    /**
+     * 鏈�鍚庣櫥褰曟椂闂�
+     */
+    private Date loginDate;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+    public SysUser(Long userId) {
+        this.userId = userId;
+    }
+
+    public boolean isSuperAdmin() {
+        return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java
new file mode 100644
index 0000000..ba30eb6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java
@@ -0,0 +1,63 @@
+package org.dromara.system.domain;
+
+import lombok.Data;
+
+/**
+ * 褰撳墠鍦ㄧ嚎浼氳瘽
+ *
+ * @author Lion Li
+ */
+@Data
+public class SysUserOnline {
+
+    /**
+     * 浼氳瘽缂栧彿
+     */
+    private String tokenId;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 鐢ㄦ埛鍚嶇О
+     */
+    private String userName;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦板潃
+     */
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String os;
+
+    /**
+     * 鐧诲綍鏃堕棿
+     */
+    private Long loginTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java
new file mode 100644
index 0000000..119c117
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛鍜屽矖浣嶅叧鑱� sys_user_post
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_user_post")
+public class SysUserPost {
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @TableId(type = IdType.INPUT)
+    private Long userId;
+
+    /**
+     * 宀椾綅ID
+     */
+    private Long postId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java
new file mode 100644
index 0000000..0a50e80
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛鍜岃鑹插叧鑱� sys_user_role
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_user_role")
+public class SysUserRole {
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @TableId(type = IdType.INPUT)
+    private Long userId;
+
+    /**
+     * 瑙掕壊ID
+     */
+    private Long roleId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java
new file mode 100644
index 0000000..e5f5ffa
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java
@@ -0,0 +1,80 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.system.domain.SysClient;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+import java.util.List;
+
+/**
+ * 鎺堟潈绠$悊涓氬姟瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ * @date 2023-05-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysClient.class, reverseConvertGenerate = false)
+public class SysClientBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    @NotNull(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 瀹㈡埛绔痠d
+     */
+    private String clientId;
+
+    /**
+     * 瀹㈡埛绔痥ey
+     */
+    @NotBlank(message = "瀹㈡埛绔痥ey涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String clientKey;
+
+    /**
+     * 瀹㈡埛绔閽�
+     */
+    @NotBlank(message = "瀹㈡埛绔閽ヤ笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private String clientSecret;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    @NotNull(message = "鎺堟潈绫诲瀷涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private List<String> grantTypeList;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    private String grantType;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * token娲昏穬瓒呮椂鏃堕棿
+     */
+    private Long activeTimeout;
+
+    /**
+     * token鍥哄畾瓒呮椂鏃堕棿
+     */
+    private Long timeout;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java
new file mode 100644
index 0000000..257935d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java
@@ -0,0 +1,59 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysConfig;
+
+/**
+ * 鍙傛暟閰嶇疆涓氬姟瀵硅薄 sys_config
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false)
+public class SysConfigBo extends BaseEntity {
+
+    /**
+     * 鍙傛暟涓婚敭
+     */
+    private Long configId;
+
+    /**
+     * 鍙傛暟鍚嶇О
+     */
+    @NotBlank(message = "鍙傛暟鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "鍙傛暟鍚嶇О涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String configName;
+
+    /**
+     * 鍙傛暟閿悕
+     */
+    @NotBlank(message = "鍙傛暟閿悕涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "鍙傛暟閿悕闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String configKey;
+
+    /**
+     * 鍙傛暟閿��
+     */
+    @NotBlank(message = "鍙傛暟閿�间笉鑳戒负绌�")
+    @Size(min = 0, max = 500, message = "鍙傛暟閿�奸暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+    private String configValue;
+
+    /**
+     * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+     */
+    private String configType;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
new file mode 100644
index 0000000..5f64d6f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
@@ -0,0 +1,76 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDept;
+
+/**
+ * 閮ㄩ棬涓氬姟瀵硅薄 sys_dept
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDept.class, reverseConvertGenerate = false)
+public class SysDeptBo extends BaseEntity {
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private Long deptId;
+
+    /**
+     * 鐖堕儴闂↖D
+     */
+    private Long parentId;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    @NotBlank(message = "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 30, message = "閮ㄩ棬鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String deptName;
+
+    /**
+     * 閮ㄩ棬绫诲埆缂栫爜
+     */
+    @Size(min = 0, max = 100, message = "閮ㄩ棬绫诲埆缂栫爜闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String deptCategory;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+    private Integer orderNum;
+
+    /**
+     * 璐熻矗浜�
+     */
+    private Long leader;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    @Size(min = 0, max = 11, message = "鑱旂郴鐢佃瘽闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String phone;
+
+    /**
+     * 閭
+     */
+    @Email(message = "閭鏍煎紡涓嶆纭�")
+    @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String email;
+
+    /**
+     * 閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java
new file mode 100644
index 0000000..042946c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java
@@ -0,0 +1,80 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDictData;
+
+/**
+ * 瀛楀吀鏁版嵁涓氬姟瀵硅薄 sys_dict_data
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false)
+public class SysDictDataBo extends BaseEntity {
+
+    /**
+     * 瀛楀吀缂栫爜
+     */
+    private Long dictCode;
+
+    /**
+     * 瀛楀吀鎺掑簭
+     */
+    private Integer dictSort;
+
+    /**
+     * 瀛楀吀鏍囩
+     */
+    @NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String dictLabel;
+
+    /**
+     * 瀛楀吀閿��
+     */
+    @NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
+    @Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+    private String dictValue;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String dictType;
+
+    /**
+     * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+     */
+    @Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+    private String cssClass;
+
+    /**
+     * 琛ㄦ牸鍥炴樉鏍峰紡
+     */
+    private String listClass;
+
+    /**
+     * 鏄惁榛樿锛圷鏄� N鍚︼級
+     */
+    private String isDefault;
+
+    /**
+     * 鍒涘缓閮ㄩ棬
+     */
+    private Long createDept;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java
new file mode 100644
index 0000000..fcc1ac1
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java
@@ -0,0 +1,50 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.RegexConstants;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDictType;
+
+/**
+ * 瀛楀吀绫诲瀷涓氬姟瀵硅薄 sys_dict_type
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false)
+public class SysDictTypeBo extends BaseEntity {
+
+    /**
+     * 瀛楀吀涓婚敭
+     */
+    private Long dictId;
+
+    /**
+     * 瀛楀吀鍚嶇О
+     */
+    @NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String dictName;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    @Pattern(regexp = RegexConstants.DICTIONARY_TYPE, message = "瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�")
+    private String dictType;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java
new file mode 100644
index 0000000..4646162
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java
@@ -0,0 +1,87 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.system.domain.SysLogininfor;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 绯荤粺璁块棶璁板綍涓氬姟瀵硅薄 sys_logininfor
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@AutoMapper(target = SysLogininfor.class, reverseConvertGenerate = false)
+public class SysLogininforBo {
+
+    /**
+     * 璁块棶ID
+     */
+    private Long infoId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦扮偣
+     */
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String os;
+
+    /**
+     * 鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�
+     */
+    private String status;
+
+    /**
+     * 鎻愮ず娑堟伅
+     */
+    private String msg;
+
+    /**
+     * 璁块棶鏃堕棿
+     */
+    private Date loginTime;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    private Map<String, Object> params = new HashMap<>();
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
new file mode 100644
index 0000000..fbaafaa
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
@@ -0,0 +1,110 @@
+package org.dromara.system.domain.bo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.RegexConstants;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysMenu;
+
+/**
+ * 鑿滃崟鏉冮檺涓氬姟瀵硅薄 sys_menu
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false)
+public class SysMenuBo extends BaseEntity {
+
+    /**
+     * 鑿滃崟ID
+     */
+    private Long menuId;
+
+    /**
+     * 鐖惰彍鍗旾D
+     */
+    private Long parentId;
+
+    /**
+     * 鑿滃崟鍚嶇О
+     */
+    @NotBlank(message = "鑿滃崟鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 50, message = "鑿滃崟鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String menuName;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+    private Integer orderNum;
+
+    /**
+     * 璺敱鍦板潃
+     */
+    @Size(min = 0, max = 200, message = "璺敱鍦板潃涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String path;
+
+    /**
+     * 缁勪欢璺緞
+     */
+    @Size(min = 0, max = 200, message = "缁勪欢璺緞涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String component;
+
+    /**
+     * 璺敱鍙傛暟
+     */
+    private String queryParam;
+
+    /**
+     * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+     */
+    private String isFrame;
+
+    /**
+     * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+     */
+    private String isCache;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    @NotBlank(message = "鑿滃崟绫诲瀷涓嶈兘涓虹┖")
+    private String menuType;
+
+    /**
+     * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+     */
+    private String visible;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鏉冮檺鏍囪瘑
+     */
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @Size(min = 0, max = 100, message = "鏉冮檺鏍囪瘑闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    @Pattern(regexp = RegexConstants.PERMISSION_STRING, message = "鏉冮檺鏍囪瘑蹇呴』绗﹀悎 tool:build:list 鏍煎紡")
+    private String perms;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java
new file mode 100644
index 0000000..cdcc575
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java
@@ -0,0 +1,61 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysNotice;
+
+/**
+ * 閫氱煡鍏憡涓氬姟瀵硅薄 sys_notice
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false)
+public class SysNoticeBo extends BaseEntity {
+
+    /**
+     * 鍏憡ID
+     */
+    private Long noticeId;
+
+    /**
+     * 鍏憡鏍囬
+     */
+    @Xss(message = "鍏憡鏍囬涓嶈兘鍖呭惈鑴氭湰瀛楃")
+    @NotBlank(message = "鍏憡鏍囬涓嶈兘涓虹┖")
+    @Size(min = 0, max = 50, message = "鍏憡鏍囬涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String noticeTitle;
+
+    /**
+     * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+     */
+    private String noticeType;
+
+    /**
+     * 鍏憡鍐呭
+     */
+    private String noticeContent;
+
+    /**
+     * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鍒涘缓浜哄悕绉�
+     */
+    private String createByName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java
new file mode 100644
index 0000000..f16400a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java
@@ -0,0 +1,127 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.system.domain.SysOperLog;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.AutoMappers;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍涓氬姟瀵硅薄 sys_oper_log
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+
+@Data
+@AutoMappers({
+    @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false),
+    @AutoMapper(target = OperLogEvent.class)
+})
+public class SysOperLogBo {
+
+    /**
+     * 鏃ュ織涓婚敭
+     */
+    private Long operId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 妯″潡鏍囬
+     */
+    private String title;
+
+    /**
+     * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+     */
+    private Integer businessType;
+
+    /**
+     * 涓氬姟绫诲瀷鏁扮粍
+     */
+    private Integer[] businessTypes;
+
+    /**
+     * 鏂规硶鍚嶇О
+     */
+    private String method;
+
+    /**
+     * 璇锋眰鏂瑰紡
+     */
+    private String requestMethod;
+
+    /**
+     * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+     */
+    private Integer operatorType;
+
+    /**
+     * 鎿嶄綔浜哄憳
+     */
+    private String operName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    private String deptName;
+
+    /**
+     * 璇锋眰URL
+     */
+    private String operUrl;
+
+    /**
+     * 涓绘満鍦板潃
+     */
+    private String operIp;
+
+    /**
+     * 鎿嶄綔鍦扮偣
+     */
+    private String operLocation;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    private String operParam;
+
+    /**
+     * 杩斿洖鍙傛暟
+     */
+    private String jsonResult;
+
+    /**
+     * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+     */
+    private Integer status;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    private String errorMsg;
+
+    /**
+     * 鎿嶄綔鏃堕棿
+     */
+    private Date operTime;
+
+    /**
+     * 娑堣�楁椂闂�
+     */
+    private Long costTime;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    private Map<String, Object> params = new HashMap<>();
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java
new file mode 100644
index 0000000..7cb3104
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java
@@ -0,0 +1,49 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysOss;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * OSS瀵硅薄瀛樺偍鍒嗛〉鏌ヨ瀵硅薄 sys_oss
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysOss.class, reverseConvertGenerate = false)
+public class SysOssBo extends BaseEntity {
+
+    /**
+     * ossId
+     */
+    private Long ossId;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String fileName;
+
+    /**
+     * 鍘熷悕
+     */
+    private String originalName;
+
+    /**
+     * 鏂囦欢鍚庣紑鍚�
+     */
+    private String fileSuffix;
+
+    /**
+     * URL鍦板潃
+     */
+    private String url;
+
+    /**
+     * 鏈嶅姟鍟�
+     */
+    private String service;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java
new file mode 100644
index 0000000..3dc4328
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java
@@ -0,0 +1,109 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysOssConfig;
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆涓氬姟瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysOssConfig.class, reverseConvertGenerate = false)
+public class SysOssConfigBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+    @NotBlank(message = "閰嶇疆key涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    @Size(min = 2, max = 100, message = "configKey闀垮害蹇呴』浠嬩簬{min}鍜寋max} 涔嬮棿")
+    private String configKey;
+
+    /**
+     * accessKey
+     */
+    @NotBlank(message = "accessKey涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    @Size(min = 2, max = 100, message = "accessKey闀垮害蹇呴』浠嬩簬{min}鍜寋max} 涔嬮棿")
+    private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+    @NotBlank(message = "secretKey涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    @Size(min = 2, max = 100, message = "secretKey闀垮害蹇呴』浠嬩簬{min}鍜寋max} 涔嬮棿")
+    private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+    @NotBlank(message = "妗跺悕绉颁笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    @Size(min = 2, max = 100, message = "bucketName闀垮害蹇呴』浠嬩簬{min}鍜寋max}涔嬮棿")
+    private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+    private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    @NotBlank(message = "璁块棶绔欑偣涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    @Size(min = 2, max = 100, message = "endpoint闀垮害蹇呴』浠嬩簬{min}鍜寋max}涔嬮棿")
+    private String endpoint;
+
+    /**
+     * 鑷畾涔夊煙鍚�
+     */
+    private String domain;
+
+    /**
+     * 鏄惁https锛圷=鏄�,N=鍚︼級
+     */
+    private String isHttps;
+
+    /**
+     * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+     */
+    private String status;
+
+    /**
+     * 鍩�
+     */
+    private String region;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+    private String ext1;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+     */
+    @NotBlank(message = "妗舵潈闄愮被鍨嬩笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    private String accessPolicy;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
new file mode 100644
index 0000000..09805cd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
@@ -0,0 +1,75 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysPost;
+
+/**
+ * 宀椾綅淇℃伅涓氬姟瀵硅薄 sys_post
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysPost.class, reverseConvertGenerate = false)
+public class SysPostBo extends BaseEntity {
+
+    /**
+     * 宀椾綅ID
+     */
+    private Long postId;
+
+    /**
+     * 閮ㄩ棬id锛堝崟閮ㄩ棬锛�
+     */
+    @NotNull(message = "閮ㄩ棬id涓嶈兘涓虹┖")
+    private Long deptId;
+
+    /**
+     * 褰掑睘閮ㄩ棬id锛堥儴闂ㄦ爲锛�
+     */
+    private Long belongDeptId;
+
+    /**
+     * 宀椾綅缂栫爜
+     */
+    @NotBlank(message = "宀椾綅缂栫爜涓嶈兘涓虹┖")
+    @Size(min = 0, max = 64, message = "宀椾綅缂栫爜闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String postCode;
+
+    /**
+     * 宀椾綅鍚嶇О
+     */
+    @NotBlank(message = "宀椾綅鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 50, message = "宀椾綅鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String postName;
+
+    /**
+     * 宀椾綅绫诲埆缂栫爜
+     */
+    @Size(min = 0, max = 100, message = "绫诲埆缂栫爜闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String postCategory;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+    private Integer postSort;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
new file mode 100644
index 0000000..0c8b4dc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
@@ -0,0 +1,94 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysRole;
+
+/**
+ * 瑙掕壊淇℃伅涓氬姟瀵硅薄 sys_role
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysRole.class, reverseConvertGenerate = false)
+public class SysRoleBo extends BaseEntity {
+
+    /**
+     * 瑙掕壊ID
+     */
+    private Long roleId;
+
+    /**
+     * 瑙掕壊鍚嶇О
+     */
+    @NotBlank(message = "瑙掕壊鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 30, message = "瑙掕壊鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String roleName;
+
+    /**
+     * 瑙掕壊鏉冮檺瀛楃涓�
+     */
+    @NotBlank(message = "瑙掕壊鏉冮檺瀛楃涓蹭笉鑳戒负绌�")
+    @Size(min = 0, max = 100, message = "鏉冮檺瀛楃闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String roleKey;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+    private Integer roleSort;
+
+    /**
+     * 鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級
+     */
+    private String dataScope;
+
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    private Boolean deptCheckStrictly;
+
+    /**
+     * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鑿滃崟缁�
+     */
+    private Long[] menuIds;
+
+    /**
+     * 閮ㄩ棬缁勶紙鏁版嵁鏉冮檺锛�
+     */
+    private Long[] deptIds;
+
+    public SysRoleBo(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public boolean isSuperAdmin() {
+        return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java
new file mode 100644
index 0000000..cede1e9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java
@@ -0,0 +1,142 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.tenant.core.TenantEntity;
+import org.dromara.system.domain.SysSocial;
+
+/**
+ * 绀句細鍖栧叧绯讳笟鍔″璞� sys_social
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false)
+public class SysSocialBo extends TenantEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 璁よ瘉鍞竴ID
+     */
+    @NotBlank(message = "璁よ瘉鍞竴ID涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String authId;
+
+    /**
+     * 鐢ㄦ埛鏉ユ簮
+     */
+    @NotBlank(message = "鐢ㄦ埛鏉ユ簮涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String source;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+     */
+    @NotBlank(message = "鐢ㄦ埛鐨勬巿鏉冧护鐗屼笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private String accessToken;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private int expireIn;
+
+    /**
+     * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String refreshToken;
+
+    /**
+     * 骞冲彴鍞竴id
+     */
+    private String openId;
+
+    /**
+     * 鐢ㄦ埛鐨� ID
+     */
+    @NotBlank(message = "鐢ㄦ埛鐨処D涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private Long userId;
+
+    /**
+     * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String accessCode;
+
+    /**
+     * 鐢ㄦ埛鐨� unionid
+     */
+    private String unionId;
+
+    /**
+     * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String scope;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟閭
+     */
+    private String email;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+     */
+    private String avatar;
+
+    /**
+     * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String tokenType;
+
+    /**
+     * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String idToken;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macAlgorithm;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macKey;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String code;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthToken;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthTokenSecret;
+
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java
new file mode 100644
index 0000000..e3ac642
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java
@@ -0,0 +1,114 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.system.domain.SysTenant;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+import java.util.Date;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 绉熸埛涓氬姟瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysTenant.class, reverseConvertGenerate = false)
+public class SysTenantBo extends BaseEntity {
+
+    /**
+     * id
+     */
+    @NotNull(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鑱旂郴浜�
+     */
+    @NotBlank(message = "鑱旂郴浜轰笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private String contactUserName;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    @NotBlank(message = "鑱旂郴鐢佃瘽涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String contactPhone;
+
+    /**
+     * 浼佷笟鍚嶇О
+     */
+    @NotBlank(message = "浼佷笟鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String companyName;
+
+    /**
+     * 鐢ㄦ埛鍚嶏紙鍒涘缓绯荤粺鐢ㄦ埛锛�
+     */
+    @NotBlank(message = "鐢ㄦ埛鍚嶄笉鑳戒负绌�", groups = { AddGroup.class })
+    private String username;
+
+    /**
+     * 瀵嗙爜锛堝垱寤虹郴缁熺敤鎴凤級
+     */
+    @NotBlank(message = "瀵嗙爜涓嶈兘涓虹┖", groups = { AddGroup.class })
+    private String password;
+
+    /**
+     * 缁熶竴绀句細淇$敤浠g爜
+     */
+    private String licenseNumber;
+
+    /**
+     * 鍦板潃
+     */
+    private String address;
+
+    /**
+     * 鍩熷悕
+     */
+    private String domain;
+
+    /**
+     * 浼佷笟绠�浠�
+     */
+    private String intro;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 绉熸埛濂楅缂栧彿
+     */
+    @NotNull(message = "绉熸埛濂楅涓嶈兘涓虹┖", groups = { AddGroup.class })
+    private Long packageId;
+
+    /**
+     * 杩囨湡鏃堕棿
+     */
+    private Date expireTime;
+
+    /**
+     * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+     */
+    private Long accountCount;
+
+    /**
+     * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java
new file mode 100644
index 0000000..eecbc9f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java
@@ -0,0 +1,59 @@
+package org.dromara.system.domain.bo;
+
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.system.domain.SysTenantPackage;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.AutoMapping;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 绉熸埛濂楅涓氬姟瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false)
+public class SysTenantPackageBo extends BaseEntity {
+
+    /**
+     * 绉熸埛濂楅id
+     */
+    @NotNull(message = "绉熸埛濂楅id涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long packageId;
+
+    /**
+     * 濂楅鍚嶇О
+     */
+    @NotBlank(message = "濂楅鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String packageName;
+
+    /**
+     * 鍏宠仈鑿滃崟id
+     */
+    @AutoMapping(target = "menuIds", expression = "java(org.dromara.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))")
+    private Long[] menuIds;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
new file mode 100644
index 0000000..7ad2759
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
@@ -0,0 +1,119 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysUser;
+
+/**
+ * 鐢ㄦ埛淇℃伅涓氬姟瀵硅薄 sys_user
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysUser.class, reverseConvertGenerate = false)
+public class SysUserBo extends BaseEntity {
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    @Xss(message = "鐢ㄦ埛璐﹀彿涓嶈兘鍖呭惈鑴氭湰瀛楃")
+    @NotBlank(message = "鐢ㄦ埛璐﹀彿涓嶈兘涓虹┖")
+    @Size(min = 0, max = 30, message = "鐢ㄦ埛璐﹀彿闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    @Xss(message = "鐢ㄦ埛鏄电О涓嶈兘鍖呭惈鑴氭湰瀛楃")
+    @NotBlank(message = "鐢ㄦ埛鏄电О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+     */
+    private String userType;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    @Email(message = "閭鏍煎紡涓嶆纭�")
+    @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+     */
+    private String sex;
+
+    /**
+     * 瀵嗙爜
+     */
+    private String password;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 瑙掕壊缁�
+     */
+    @Size(min = 1, message = "鐢ㄦ埛瑙掕壊涓嶈兘涓虹┖")
+    private Long[] roleIds;
+
+    /**
+     * 宀椾綅缁�
+     */
+    private Long[] postIds;
+
+    /**
+     * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
+     */
+    private Long roleId;
+
+    /**
+     * 鎺掗櫎涓嶆煡璇㈢殑鐢ㄦ埛(宸ヤ綔娴佺敤)
+     */
+    private String excludeUserIds;
+
+    public SysUserBo(Long userId) {
+        this.userId = userId;
+    }
+
+    public boolean isSuperAdmin() {
+        return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java
new file mode 100644
index 0000000..8615fcd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛瀵嗙爜淇敼bo
+ */
+@Data
+public class SysUserPasswordBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏃у瘑鐮�
+     */
+    @NotBlank(message = "鏃у瘑鐮佷笉鑳戒负绌�")
+    private String oldPassword;
+
+    /**
+     * 鏂板瘑鐮�
+     */
+    @NotBlank(message = "鏂板瘑鐮佷笉鑳戒负绌�")
+    private String newPassword;
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
new file mode 100644
index 0000000..846dd79
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
@@ -0,0 +1,53 @@
+package org.dromara.system.domain.bo;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.RegexConstants;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+
+/**
+ * 涓汉淇℃伅涓氬姟澶勭悊
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysUserProfileBo extends BaseEntity {
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    @Xss(message = "鐢ㄦ埛鏄电О涓嶈兘鍖呭惈鑴氭湰瀛楃")
+    @Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    @Sensitive(strategy = SensitiveStrategy.EMAIL)
+    @Email(message = "閭鏍煎紡涓嶆纭�")
+    @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    @Pattern(regexp = RegexConstants.MOBILE, message = "鎵嬫満鍙锋牸寮忎笉姝g‘")
+    @Sensitive(strategy = SensitiveStrategy.PHONE)
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+     */
+    private String sex;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java
new file mode 100644
index 0000000..46c020b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java
@@ -0,0 +1,18 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛澶村儚淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class AvatarVo {
+
+    /**
+     * 澶村儚鍦板潃
+     */
+    private String imgUrl;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java
new file mode 100644
index 0000000..f827cba
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java
@@ -0,0 +1,23 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 缂撳瓨鐩戞帶鍒楄〃淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class CacheListInfoVo {
+
+    private Properties info;
+
+    private Long dbSize;
+
+    private List<Map<String, String>> commandStats;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java
new file mode 100644
index 0000000..6f7db28
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java
@@ -0,0 +1,26 @@
+package org.dromara.system.domain.vo;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 瑙掕壊閮ㄩ棬鍒楄〃鏍戜俊鎭�
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class DeptTreeSelectVo {
+
+    /**
+     * 閫変腑閮ㄩ棬鍒楄〃
+     */
+    private List<Long> checkedKeys;
+
+    /**
+     * 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    private List<Tree<Long>> depts;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java
new file mode 100644
index 0000000..0724538
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java
@@ -0,0 +1,26 @@
+package org.dromara.system.domain.vo;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 瑙掕壊鑿滃崟鍒楄〃鏍戜俊鎭�
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class MenuTreeSelectVo {
+
+    /**
+     * 閫変腑鑿滃崟鍒楄〃
+     */
+    private List<Long> checkedKeys;
+
+    /**
+     * 鑿滃崟涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    private List<Tree<Long>> menus;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java
new file mode 100644
index 0000000..f720cd7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java
@@ -0,0 +1,61 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.common.core.utils.StringUtils;
+import lombok.Data;
+
+/**
+ * 璺敱鏄剧ず淇℃伅
+ *
+ * @author ruoyi
+ */
+
+@Data
+public class MetaVo {
+
+    /**
+     * 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+     */
+    private String title;
+
+    /**
+     * 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/assets/icons/svg
+     */
+    private String icon;
+
+    /**
+     * 璁剧疆涓簍rue锛屽垯涓嶄細琚� <keep-alive>缂撳瓨
+     */
+    private boolean noCache;
+
+    /**
+     * 鍐呴摼鍦板潃锛坔ttp(s)://寮�澶达級
+     */
+    private String link;
+
+    public MetaVo(String title, String icon) {
+        this.title = title;
+        this.icon = icon;
+    }
+
+    public MetaVo(String title, String icon, boolean noCache) {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+    }
+
+    public MetaVo(String title, String icon, String link) {
+        this.title = title;
+        this.icon = icon;
+        this.link = link;
+    }
+
+    public MetaVo(String title, String icon, boolean noCache, String link) {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+        if (StringUtils.ishttp(link)) {
+            this.link = link;
+        }
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java
new file mode 100644
index 0000000..c047651
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛涓汉淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class ProfileVo {
+
+    /**
+     * 鐢ㄦ埛淇℃伅
+     */
+    private SysUserVo user;
+
+    /**
+     * 鐢ㄦ埛鎵�灞炶鑹茬粍
+     */
+    private String roleGroup;
+
+    /**
+     * 鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     */
+    private String postGroup;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java
new file mode 100644
index 0000000..0d576ef
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java
@@ -0,0 +1,62 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 璺敱閰嶇疆淇℃伅
+ *
+ * @author Lion Li
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RouterVo {
+
+    /**
+     * 璺敱鍚嶅瓧
+     */
+    private String name;
+
+    /**
+     * 璺敱鍦板潃
+     */
+    private String path;
+
+    /**
+     * 鏄惁闅愯棌璺敱锛屽綋璁剧疆 true 鐨勬椂鍊欒璺敱涓嶄細鍐嶄晶杈规爮鍑虹幇
+     */
+    private boolean hidden;
+
+    /**
+     * 閲嶅畾鍚戝湴鍧�锛屽綋璁剧疆 noRedirect 鐨勬椂鍊欒璺敱鍦ㄩ潰鍖呭睉瀵艰埅涓笉鍙鐐瑰嚮
+     */
+    private String redirect;
+
+    /**
+     * 缁勪欢鍦板潃
+     */
+    private String component;
+
+    /**
+     * 璺敱鍙傛暟锛氬 {"id": 1, "name": "ry"}
+     */
+    private String query;
+
+    /**
+     * 褰撲綘涓�涓矾鐢变笅闈㈢殑 children 澹版槑鐨勮矾鐢卞ぇ浜�1涓椂锛岃嚜鍔ㄤ細鍙樻垚宓屽鐨勬ā寮�--濡傜粍浠堕〉闈�
+     */
+    private Boolean alwaysShow;
+
+    /**
+     * 鍏朵粬鍏冪礌
+     */
+    private MetaVo meta;
+
+    /**
+     * 瀛愯矾鐢�
+     */
+    private List<RouterVo> children;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java
new file mode 100644
index 0000000..34f24eb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java
@@ -0,0 +1,90 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.system.domain.SysClient;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+
+/**
+ * 鎺堟潈绠$悊瑙嗗浘瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ * @date 2023-05-15
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysClient.class)
+public class SysClientVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private Long id;
+
+    /**
+     * 瀹㈡埛绔痠d
+     */
+    @ExcelProperty(value = "瀹㈡埛绔痠d")
+    private String clientId;
+
+    /**
+     * 瀹㈡埛绔痥ey
+     */
+    @ExcelProperty(value = "瀹㈡埛绔痥ey")
+    private String clientKey;
+
+    /**
+     * 瀹㈡埛绔閽�
+     */
+    @ExcelProperty(value = "瀹㈡埛绔閽�")
+    private String clientSecret;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    @ExcelProperty(value = "鎺堟潈绫诲瀷")
+    private List<String> grantTypeList;
+
+    /**
+     * 鎺堟潈绫诲瀷
+     */
+    private String grantType;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private String deviceType;
+
+    /**
+     * token娲昏穬瓒呮椂鏃堕棿
+     */
+    @ExcelProperty(value = "token娲昏穬瓒呮椂鏃堕棿")
+    private Long activeTimeout;
+
+    /**
+     * token鍥哄畾瓒呮椂鏃堕棿
+     */
+    @ExcelProperty(value = "token鍥哄畾瓒呮椂鏃堕棿")
+    private Long timeout;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java
new file mode 100644
index 0000000..f896000
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java
@@ -0,0 +1,72 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysConfig;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 鍙傛暟閰嶇疆瑙嗗浘瀵硅薄 sys_config
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysConfig.class)
+public class SysConfigVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鍙傛暟涓婚敭
+     */
+    @ExcelProperty(value = "鍙傛暟涓婚敭")
+    private Long configId;
+
+    /**
+     * 鍙傛暟鍚嶇О
+     */
+    @ExcelProperty(value = "鍙傛暟鍚嶇О")
+    private String configName;
+
+    /**
+     * 鍙傛暟閿悕
+     */
+    @ExcelProperty(value = "鍙傛暟閿悕")
+    private String configKey;
+
+    /**
+     * 鍙傛暟閿��
+     */
+    @ExcelProperty(value = "鍙傛暟閿��")
+    private String configValue;
+
+    /**
+     * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+     */
+    @ExcelProperty(value = "绯荤粺鍐呯疆", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_yes_no")
+    private String configType;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java
new file mode 100644
index 0000000..c56fb09
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java
@@ -0,0 +1,102 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysDept;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 閮ㄩ棬瑙嗗浘瀵硅薄 sys_dept
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDept.class)
+public class SysDeptVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @ExcelProperty(value = "閮ㄩ棬id")
+    private Long deptId;
+
+    /**
+     * 鐖堕儴闂╥d
+     */
+    private Long parentId;
+
+    /**
+     * 鐖堕儴闂ㄥ悕绉�
+     */
+    private String parentName;
+
+    /**
+     * 绁栫骇鍒楄〃
+     */
+    private String ancestors;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    /**
+     * 閮ㄩ棬绫诲埆缂栫爜
+     */
+    @ExcelProperty(value = "閮ㄩ棬绫诲埆缂栫爜")
+    private String deptCategory;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Integer orderNum;
+
+    /**
+     * 璐熻矗浜篒D
+     */
+    private Long leader;
+
+    /**
+     * 璐熻矗浜�
+     */
+    @ExcelProperty(value = "璐熻矗浜�")
+    private String leaderName;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    @ExcelProperty(value = "鑱旂郴鐢佃瘽")
+    private String phone;
+
+    /**
+     * 閭
+     */
+    @ExcelProperty(value = "閭")
+    private String email;
+
+    /**
+     * 閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "閮ㄩ棬鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_normal_disable")
+    private String status;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java
new file mode 100644
index 0000000..83ea619
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java
@@ -0,0 +1,88 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysDictData;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 瀛楀吀鏁版嵁瑙嗗浘瀵硅薄 sys_dict_data
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDictData.class)
+public class SysDictDataVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瀛楀吀缂栫爜
+     */
+    @ExcelProperty(value = "瀛楀吀缂栫爜")
+    private Long dictCode;
+
+    /**
+     * 瀛楀吀鎺掑簭
+     */
+    @ExcelProperty(value = "瀛楀吀鎺掑簭")
+    private Integer dictSort;
+
+    /**
+     * 瀛楀吀鏍囩
+     */
+    @ExcelProperty(value = "瀛楀吀鏍囩")
+    private String dictLabel;
+
+    /**
+     * 瀛楀吀閿��
+     */
+    @ExcelProperty(value = "瀛楀吀閿��")
+    private String dictValue;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    @ExcelProperty(value = "瀛楀吀绫诲瀷")
+    private String dictType;
+
+    /**
+     * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+     */
+    private String cssClass;
+
+    /**
+     * 琛ㄦ牸鍥炴樉鏍峰紡
+     */
+    private String listClass;
+
+    /**
+     * 鏄惁榛樿锛圷鏄� N鍚︼級
+     */
+    @ExcelProperty(value = "鏄惁榛樿", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_yes_no")
+    private String isDefault;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java
new file mode 100644
index 0000000..e6a184f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java
@@ -0,0 +1,59 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysDictType;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 瀛楀吀绫诲瀷瑙嗗浘瀵硅薄 sys_dict_type
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDictType.class)
+public class SysDictTypeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瀛楀吀涓婚敭
+     */
+    @ExcelProperty(value = "瀛楀吀涓婚敭")
+    private Long dictId;
+
+    /**
+     * 瀛楀吀鍚嶇О
+     */
+    @ExcelProperty(value = "瀛楀吀鍚嶇О")
+    private String dictName;
+
+    /**
+     * 瀛楀吀绫诲瀷
+     */
+    @ExcelProperty(value = "瀛楀吀绫诲瀷")
+    private String dictType;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java
new file mode 100644
index 0000000..de19aea
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java
@@ -0,0 +1,106 @@
+package org.dromara.system.domain.vo;
+
+import java.util.Date;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysLogininfor;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+
+/**
+ * 绯荤粺璁块棶璁板綍瑙嗗浘瀵硅薄 sys_logininfor
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysLogininfor.class)
+public class SysLogininforVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 璁块棶ID
+     */
+    @ExcelProperty(value = "搴忓彿")
+    private Long infoId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    @ExcelProperty(value = "鐢ㄦ埛璐﹀彿")
+    private String userName;
+
+    /**
+     * 瀹㈡埛绔�
+     */
+    @ExcelProperty(value = "瀹㈡埛绔�")
+    private String clientKey;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    @ExcelProperty(value = "璁惧绫诲瀷", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_device_type")
+    private String deviceType;
+
+    /**
+     * 鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�
+     */
+    @ExcelProperty(value = "鐧诲綍鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_common_status")
+    private String status;
+
+    /**
+     * 鐧诲綍IP鍦板潃
+     */
+    @ExcelProperty(value = "鐧诲綍鍦板潃")
+    private String ipaddr;
+
+    /**
+     * 鐧诲綍鍦扮偣
+     */
+    @ExcelProperty(value = "鐧诲綍鍦扮偣")
+    private String loginLocation;
+
+    /**
+     * 娴忚鍣ㄧ被鍨�
+     */
+    @ExcelProperty(value = "娴忚鍣�")
+    private String browser;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    @ExcelProperty(value = "鎿嶄綔绯荤粺")
+    private String os;
+
+
+    /**
+     * 鎻愮ず娑堟伅
+     */
+    @ExcelProperty(value = "鎻愮ず娑堟伅")
+    private String msg;
+
+    /**
+     * 璁块棶鏃堕棿
+     */
+    @ExcelProperty(value = "璁块棶鏃堕棿")
+    private Date loginTime;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java
new file mode 100644
index 0000000..5214a33
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java
@@ -0,0 +1,116 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.system.domain.SysMenu;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 鑿滃崟鏉冮檺瑙嗗浘瀵硅薄 sys_menu
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysMenu.class)
+public class SysMenuVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鑿滃崟ID
+     */
+    private Long menuId;
+
+    /**
+     * 鑿滃崟鍚嶇О
+     */
+    private String menuName;
+
+    /**
+     * 鐖惰彍鍗旾D
+     */
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Integer orderNum;
+
+    /**
+     * 璺敱鍦板潃
+     */
+    private String path;
+
+    /**
+     * 缁勪欢璺緞
+     */
+    private String component;
+
+    /**
+     * 璺敱鍙傛暟
+     */
+    private String queryParam;
+
+    /**
+     * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+     */
+    private String isFrame;
+
+    /**
+     * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+     */
+    private String isCache;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    private String menuType;
+
+    /**
+     * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+     */
+    private String visible;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鏉冮檺鏍囪瘑
+     */
+    private String perms;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 鍒涘缓閮ㄩ棬
+     */
+    private Long createDept;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 瀛愯彍鍗�
+     */
+    private List<SysMenuVo> children = new ArrayList<>();
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java
new file mode 100644
index 0000000..afe7367
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java
@@ -0,0 +1,73 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysNotice;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 閫氱煡鍏憡瑙嗗浘瀵硅薄 sys_notice
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysNotice.class)
+public class SysNoticeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鍏憡ID
+     */
+    private Long noticeId;
+
+    /**
+     * 鍏憡鏍囬
+     */
+    private String noticeTitle;
+
+    /**
+     * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+     */
+    private String noticeType;
+
+    /**
+     * 鍏憡鍐呭
+     */
+    private String noticeContent;
+
+    /**
+     * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鍒涘缓鑰�
+     */
+    private Long createBy;
+
+    /**
+     * 鍒涘缓浜哄悕绉�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
+    private String createByName;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java
new file mode 100644
index 0000000..d9eb71d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java
@@ -0,0 +1,144 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysOperLog;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍瑙嗗浘瀵硅薄 sys_oper_log
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysOperLog.class)
+public class SysOperLogVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏃ュ織涓婚敭
+     */
+    @ExcelProperty(value = "鏃ュ織涓婚敭")
+    private Long operId;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    private String tenantId;
+
+    /**
+     * 妯″潡鏍囬
+     */
+    @ExcelProperty(value = "鎿嶄綔妯″潡")
+    private String title;
+
+    /**
+     * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+     */
+    @ExcelProperty(value = "涓氬姟绫诲瀷", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_oper_type")
+    private Integer businessType;
+
+    /**
+     * 涓氬姟绫诲瀷鏁扮粍
+     */
+    private Integer[] businessTypes;
+
+    /**
+     * 鏂规硶鍚嶇О
+     */
+    @ExcelProperty(value = "璇锋眰鏂规硶")
+    private String method;
+
+    /**
+     * 璇锋眰鏂瑰紡
+     */
+    @ExcelProperty(value = "璇锋眰鏂瑰紡")
+    private String requestMethod;
+
+    /**
+     * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+     */
+    @ExcelProperty(value = "鎿嶄綔绫诲埆", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=鍏跺畠,1=鍚庡彴鐢ㄦ埛,2=鎵嬫満绔敤鎴�")
+    private Integer operatorType;
+
+    /**
+     * 鎿嶄綔浜哄憳
+     */
+    @ExcelProperty(value = "鎿嶄綔浜哄憳")
+    private String operName;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    /**
+     * 璇锋眰URL
+     */
+    @ExcelProperty(value = "璇锋眰鍦板潃")
+    private String operUrl;
+
+    /**
+     * 涓绘満鍦板潃
+     */
+    @ExcelProperty(value = "鎿嶄綔鍦板潃")
+    private String operIp;
+
+    /**
+     * 鎿嶄綔鍦扮偣
+     */
+    @ExcelProperty(value = "鎿嶄綔鍦扮偣")
+    private String operLocation;
+
+    /**
+     * 璇锋眰鍙傛暟
+     */
+    @ExcelProperty(value = "璇锋眰鍙傛暟")
+    private String operParam;
+
+    /**
+     * 杩斿洖鍙傛暟
+     */
+    @ExcelProperty(value = "杩斿洖鍙傛暟")
+    private String jsonResult;
+
+    /**
+     * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_common_status")
+    private Integer status;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    @ExcelProperty(value = "閿欒娑堟伅")
+    private String errorMsg;
+
+    /**
+     * 鎿嶄綔鏃堕棿
+     */
+    @ExcelProperty(value = "鎿嶄綔鏃堕棿")
+    private Date operTime;
+
+    /**
+     * 娑堣�楁椂闂�
+     */
+    @ExcelProperty(value = "娑堣�楁椂闂�")
+    private Long costTime;
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java
new file mode 100644
index 0000000..e7cfde4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java
@@ -0,0 +1,97 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import org.dromara.system.domain.SysOssConfig;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆瑙嗗浘瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysOssConfig.class)
+public class SysOssConfigVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    private Long ossConfigId;
+
+    /**
+     * 閰嶇疆key
+     */
+    private String configKey;
+
+    /**
+     * accessKey
+     */
+    private String accessKey;
+
+    /**
+     * 绉橀挜
+     */
+    private String secretKey;
+
+    /**
+     * 妗跺悕绉�
+     */
+    private String bucketName;
+
+    /**
+     * 鍓嶇紑
+     */
+    private String prefix;
+
+    /**
+     * 璁块棶绔欑偣
+     */
+    private String endpoint;
+
+    /**
+     * 鑷畾涔夊煙鍚�
+     */
+    private String domain;
+
+    /**
+     * 鏄惁https锛圷=鏄�,N=鍚︼級
+     */
+    private String isHttps;
+
+    /**
+     * 鍩�
+     */
+    private String region;
+
+    /**
+     * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+     */
+    private String status;
+
+    /**
+     * 鎵╁睍瀛楁
+     */
+    private String ext1;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+     */
+    private String accessPolicy;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java
new file mode 100644
index 0000000..11e0ff8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java
@@ -0,0 +1,28 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+/**
+ * 涓婁紶瀵硅薄淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class SysOssUploadVo {
+
+    /**
+     * URL鍦板潃
+     */
+    private String url;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String fileName;
+
+    /**
+     * 瀵硅薄瀛樺偍涓婚敭
+     */
+    private String ossId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java
new file mode 100644
index 0000000..8d5c429
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java
@@ -0,0 +1,72 @@
+package org.dromara.system.domain.vo;
+
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysOss;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * OSS瀵硅薄瀛樺偍瑙嗗浘瀵硅薄 sys_oss
+ *
+ * @author Lion Li
+ */
+@Data
+@AutoMapper(target = SysOss.class)
+public class SysOssVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瀵硅薄瀛樺偍涓婚敭
+     */
+    private Long ossId;
+
+    /**
+     * 鏂囦欢鍚�
+     */
+    private String fileName;
+
+    /**
+     * 鍘熷悕
+     */
+    private String originalName;
+
+    /**
+     * 鏂囦欢鍚庣紑鍚�
+     */
+    private String fileSuffix;
+
+    /**
+     * URL鍦板潃
+     */
+    private String url;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 涓婁紶浜�
+     */
+    private Long createBy;
+
+    /**
+     * 涓婁紶浜哄悕绉�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
+    private String createByName;
+
+    /**
+     * 鏈嶅姟鍟�
+     */
+    private String service;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java
new file mode 100644
index 0000000..69be547
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java
@@ -0,0 +1,91 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysPost;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 宀椾綅淇℃伅瑙嗗浘瀵硅薄 sys_post
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysPost.class)
+public class SysPostVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 宀椾綅ID
+     */
+    @ExcelProperty(value = "宀椾綅搴忓彿")
+    private Long postId;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    @ExcelProperty(value = "閮ㄩ棬id")
+    private Long deptId;
+
+    /**
+     * 宀椾綅缂栫爜
+     */
+    @ExcelProperty(value = "宀椾綅缂栫爜")
+    private String postCode;
+
+    /**
+     * 宀椾綅鍚嶇О
+     */
+    @ExcelProperty(value = "宀椾綅鍚嶇О")
+    private String postName;
+
+    /**
+     * 宀椾綅绫诲埆缂栫爜
+     */
+    @ExcelProperty(value = "绫诲埆缂栫爜")
+    private String postCategory;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @ExcelProperty(value = "宀椾綅鎺掑簭")
+    private Integer postSort;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_normal_disable")
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+    /**
+     * 閮ㄩ棬鍚�
+     */
+    @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId")
+    private String deptName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
new file mode 100644
index 0000000..1e5cd9e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
@@ -0,0 +1,100 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysRole;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 瑙掕壊淇℃伅瑙嗗浘瀵硅薄 sys_role
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysRole.class)
+public class SysRoleVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 瑙掕壊ID
+     */
+    @ExcelProperty(value = "瑙掕壊搴忓彿")
+    private Long roleId;
+
+    /**
+     * 瑙掕壊鍚嶇О
+     */
+    @ExcelProperty(value = "瑙掕壊鍚嶇О")
+    private String roleName;
+
+    /**
+     * 瑙掕壊鏉冮檺瀛楃涓�
+     */
+    @ExcelProperty(value = "瑙掕壊鏉冮檺")
+    private String roleKey;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @ExcelProperty(value = "瑙掕壊鎺掑簭")
+    private Integer roleSort;
+
+    /**
+     * 鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級
+     */
+    @ExcelProperty(value = "鏁版嵁鑼冨洿", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "1=鎵�鏈夋暟鎹潈闄�,2=鑷畾涔夋暟鎹潈闄�,3=鏈儴闂ㄦ暟鎹潈闄�,4=鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺,5=浠呮湰浜烘暟鎹潈闄�")
+    private String dataScope;
+
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    @ExcelProperty(value = "鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    @ExcelProperty(value = "閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+    private Boolean deptCheckStrictly;
+
+    /**
+     * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "瑙掕壊鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_normal_disable")
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    @ExcelProperty(value = "鍒涘缓鏃堕棿")
+    private Date createTime;
+
+    /**
+     * 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦�
+     */
+    private boolean flag = false;
+
+    public boolean isSuperAdmin() {
+        return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java
new file mode 100644
index 0000000..948dbcc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java
@@ -0,0 +1,144 @@
+package org.dromara.system.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysSocial;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 绀句細鍖栧叧绯昏鍥惧璞� sys_social
+ *
+ * @author thiszhc
+ */
+@Data
+@AutoMapper(target = SysSocial.class)
+public class SysSocialVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    private Long id;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 鐨勫敮涓�ID
+     */
+    private String authId;
+
+    /**
+     * 鐢ㄦ埛鏉ユ簮
+     */
+    private String source;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+     */
+    private String accessToken;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private int expireIn;
+
+    /**
+     * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String refreshToken;
+
+    /**
+     * 鐢ㄦ埛鐨� open id
+     */
+    private String openId;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟閭
+     */
+    private String email;
+
+    /**
+     * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+     */
+    private String avatar;
+
+
+    /**
+     * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String accessCode;
+
+    /**
+     * 鐢ㄦ埛鐨� unionid
+     */
+    private String unionId;
+
+    /**
+     * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String scope;
+
+    /**
+     * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String tokenType;
+
+    /**
+     * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String idToken;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macAlgorithm;
+
+    /**
+     * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String macKey;
+
+    /**
+     * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+     */
+    private String code;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthToken;
+
+    /**
+     * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+     */
+    private String oauthTokenSecret;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java
new file mode 100644
index 0000000..070334b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java
@@ -0,0 +1,66 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysTenantPackage;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 绉熸埛濂楅瑙嗗浘瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysTenantPackage.class)
+public class SysTenantPackageVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 绉熸埛濂楅id
+     */
+    @ExcelProperty(value = "绉熸埛濂楅id")
+    private Long packageId;
+
+    /**
+     * 濂楅鍚嶇О
+     */
+    @ExcelProperty(value = "濂楅鍚嶇О")
+    private String packageName;
+
+    /**
+     * 鍏宠仈鑿滃崟id
+     */
+    @ExcelProperty(value = "鍏宠仈鑿滃崟id")
+    private String menuIds;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     */
+    @ExcelProperty(value = "鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+    private Boolean menuCheckStrictly;
+
+    /**
+     * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java
new file mode 100644
index 0000000..6a45315
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain.vo;
+
+import java.util.Date;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysTenant;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 绉熸埛瑙嗗浘瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysTenant.class)
+public class SysTenantVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @ExcelProperty(value = "id")
+    private Long id;
+
+    /**
+     * 绉熸埛缂栧彿
+     */
+    @ExcelProperty(value = "绉熸埛缂栧彿")
+    private String tenantId;
+
+    /**
+     * 鑱旂郴浜�
+     */
+    @ExcelProperty(value = "鑱旂郴浜�")
+    private String contactUserName;
+
+    /**
+     * 鑱旂郴鐢佃瘽
+     */
+    @ExcelProperty(value = "鑱旂郴鐢佃瘽")
+    private String contactPhone;
+
+    /**
+     * 浼佷笟鍚嶇О
+     */
+    @ExcelProperty(value = "浼佷笟鍚嶇О")
+    private String companyName;
+
+    /**
+     * 缁熶竴绀句細淇$敤浠g爜
+     */
+    @ExcelProperty(value = "缁熶竴绀句細淇$敤浠g爜")
+    private String licenseNumber;
+
+    /**
+     * 鍦板潃
+     */
+    @ExcelProperty(value = "鍦板潃")
+    private String address;
+
+    /**
+     * 鍩熷悕
+     */
+    @ExcelProperty(value = "鍩熷悕")
+    private String domain;
+
+    /**
+     * 浼佷笟绠�浠�
+     */
+    @ExcelProperty(value = "浼佷笟绠�浠�")
+    private String intro;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 绉熸埛濂楅缂栧彿
+     */
+    @ExcelProperty(value = "绉熸埛濂楅缂栧彿")
+    private Long packageId;
+
+    /**
+     * 杩囨湡鏃堕棿
+     */
+    @ExcelProperty(value = "杩囨湡鏃堕棿")
+    private Date expireTime;
+
+    /**
+     * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鏁伴噺")
+    private Long accountCount;
+
+    /**
+     * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "绉熸埛鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java
new file mode 100644
index 0000000..37ec6b7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java
@@ -0,0 +1,96 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.ReverseAutoMapping;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎嚭VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+public class SysUserExportVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+    private Long userId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    @ExcelProperty(value = "鐧诲綍鍚嶇О")
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    @ExcelProperty(value = "鐢ㄦ埛閭")
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    @ExcelProperty(value = "鎵嬫満鍙风爜")
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_user_sex")
+    private String sex;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_normal_disable")
+    private String status;
+
+    /**
+     * 鏈�鍚庣櫥褰旾P
+     */
+    @ExcelProperty(value = "鏈�鍚庣櫥褰旾P")
+    private String loginIp;
+
+    /**
+     * 鏈�鍚庣櫥褰曟椂闂�
+     */
+    @ExcelProperty(value = "鏈�鍚庣櫥褰曟椂闂�")
+    private Date loginDate;
+
+    /**
+     * 閮ㄩ棬鍚嶇О
+     */
+    @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+    private String deptName;
+
+    /**
+     * 璐熻矗浜�
+     */
+    @ExcelProperty(value = "閮ㄩ棬璐熻矗浜�")
+    private String leaderName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
new file mode 100644
index 0000000..c34a23c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
@@ -0,0 +1,76 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎叆VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+// @Accessors(chain = true) // 瀵煎叆涓嶅厑璁镐娇鐢� 浼氭壘涓嶅埌set鏂规硶
+public class SysUserImportVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    @ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+    private Long userId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    @ExcelProperty(value = "閮ㄩ棬缂栧彿")
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    @ExcelProperty(value = "鐧诲綍鍚嶇О")
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    @ExcelProperty(value = "鐢ㄦ埛閭")
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    @ExcelProperty(value = "鎵嬫満鍙风爜")
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆
+     */
+    @ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_user_sex")
+    private String sex;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "sys_normal_disable")
+    private String status;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java
new file mode 100644
index 0000000..e41355d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java
@@ -0,0 +1,40 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class SysUserInfoVo {
+
+    /**
+     * 鐢ㄦ埛淇℃伅
+     */
+    private SysUserVo user;
+
+    /**
+     * 瑙掕壊ID鍒楄〃
+     */
+    private List<Long> roleIds;
+
+    /**
+     * 瑙掕壊鍒楄〃
+     */
+    private List<SysRoleVo> roles;
+
+    /**
+     * 宀椾綅ID鍒楄〃
+     */
+    private List<Long> postIds;
+
+    /**
+     * 宀椾綅鍒楄〃
+     */
+    private List<SysPostVo> posts;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
new file mode 100644
index 0000000..86249d2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
@@ -0,0 +1,142 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysUser;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 鐢ㄦ埛淇℃伅瑙嗗浘瀵硅薄 sys_user
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysUser.class)
+public class SysUserVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    private Long userId;
+
+    /**
+     * 绉熸埛ID
+     */
+    private String tenantId;
+
+    /**
+     * 閮ㄩ棬ID
+     */
+    private Long deptId;
+
+    /**
+     * 鐢ㄦ埛璐﹀彿
+     */
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛鏄电О
+     */
+    private String nickName;
+
+    /**
+     * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+     */
+    private String userType;
+
+    /**
+     * 鐢ㄦ埛閭
+     */
+    @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit")
+    private String email;
+
+    /**
+     * 鎵嬫満鍙风爜
+     */
+    @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit")
+    private String phonenumber;
+
+    /**
+     * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+     */
+    private String sex;
+
+    /**
+     * 澶村儚鍦板潃
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL)
+    private Long avatar;
+
+    /**
+     * 瀵嗙爜
+     */
+    @JsonIgnore
+    @JsonProperty
+    private String password;
+
+    /**
+     * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 鏈�鍚庣櫥褰旾P
+     */
+    private String loginIp;
+
+    /**
+     * 鏈�鍚庣櫥褰曟椂闂�
+     */
+    private Date loginDate;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 閮ㄩ棬鍚�
+     */
+    @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId")
+    private String deptName;
+
+    /**
+     * 瑙掕壊瀵硅薄
+     */
+    private List<SysRoleVo> roles;
+
+    /**
+     * 瑙掕壊缁�
+     */
+    private Long[] roleIds;
+
+    /**
+     * 宀椾綅缁�
+     */
+    private Long[] postIds;
+
+    /**
+     * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
+     */
+    private Long roleId;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java
new file mode 100644
index 0000000..48fa92a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java
@@ -0,0 +1,30 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.util.Set;
+
+/**
+ * 鐧诲綍鐢ㄦ埛淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class UserInfoVo {
+
+    /**
+     * 鐢ㄦ埛鍩烘湰淇℃伅
+     */
+    private SysUserVo user;
+
+    /**
+     * 鑿滃崟鏉冮檺
+     */
+    private Set<String> permissions;
+
+    /**
+     * 瑙掕壊鏉冮檺
+     */
+    private Set<String> roles;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
new file mode 100644
index 0000000..c20a4ec
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
@@ -0,0 +1,119 @@
+package org.dromara.system.listener;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.digest.BCrypt;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.excel.core.ExcelListener;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysUserImportVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysUserService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ * 绯荤粺鐢ㄦ埛鑷畾涔夊鍏�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo> implements ExcelListener<SysUserImportVo> {
+
+    private final ISysUserService userService;
+
+    private final String password;
+
+    private final Boolean isUpdateSupport;
+
+    private final Long operUserId;
+
+    private int successNum = 0;
+    private int failureNum = 0;
+    private final StringBuilder successMsg = new StringBuilder();
+    private final StringBuilder failureMsg = new StringBuilder();
+
+    public SysUserImportListener(Boolean isUpdateSupport) {
+        String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword");
+        this.userService = SpringUtils.getBean(ISysUserService.class);
+        this.password = BCrypt.hashpw(initPassword);
+        this.isUpdateSupport = isUpdateSupport;
+        this.operUserId = LoginHelper.getUserId();
+    }
+
+    @Override
+    public void invoke(SysUserImportVo userVo, AnalysisContext context) {
+        SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName());
+        try {
+            // 楠岃瘉鏄惁瀛樺湪杩欎釜鐢ㄦ埛
+            if (ObjectUtil.isNull(sysUser)) {
+                SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class);
+                ValidatorUtils.validate(user);
+                user.setPassword(password);
+                user.setCreateBy(operUserId);
+                userService.insertUser(user);
+                successNum++;
+                successMsg.append("<br/>").append(successNum).append("銆佽处鍙� ").append(user.getUserName()).append(" 瀵煎叆鎴愬姛");
+            } else if (isUpdateSupport) {
+                Long userId = sysUser.getUserId();
+                SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class);
+                user.setUserId(userId);
+                ValidatorUtils.validate(user);
+                userService.checkUserAllowed(user.getUserId());
+                userService.checkUserDataScope(user.getUserId());
+                user.setUpdateBy(operUserId);
+                userService.updateUser(user);
+                successNum++;
+                successMsg.append("<br/>").append(successNum).append("銆佽处鍙� ").append(user.getUserName()).append(" 鏇存柊鎴愬姛");
+            } else {
+                failureNum++;
+                failureMsg.append("<br/>").append(failureNum).append("銆佽处鍙� ").append(sysUser.getUserName()).append(" 宸插瓨鍦�");
+            }
+        } catch (Exception e) {
+            failureNum++;
+            String msg = "<br/>" + failureNum + "銆佽处鍙� " + userVo.getUserName() + " 瀵煎叆澶辫触锛�";
+            failureMsg.append(msg).append(e.getMessage());
+            log.error(msg, e);
+        }
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+
+    }
+
+    @Override
+    public ExcelResult<SysUserImportVo> getExcelResult() {
+        return new ExcelResult<>() {
+
+            @Override
+            public String getAnalysis() {
+                if (failureNum > 0) {
+                    failureMsg.insert(0, "寰堟姳姝夛紝瀵煎叆澶辫触锛佸叡 " + failureNum + " 鏉℃暟鎹牸寮忎笉姝g‘锛岄敊璇涓嬶細");
+                    throw new ServiceException(failureMsg.toString());
+                } else {
+                    successMsg.insert(0, "鎭枩鎮紝鏁版嵁宸插叏閮ㄥ鍏ユ垚鍔燂紒鍏� " + successNum + " 鏉★紝鏁版嵁濡備笅锛�");
+                }
+                return successMsg.toString();
+            }
+
+            @Override
+            public List<SysUserImportVo> getList() {
+                return null;
+            }
+
+            @Override
+            public List<String> getErrorList() {
+                return null;
+            }
+        };
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java
new file mode 100644
index 0000000..15bcfb4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 鎺堟潈绠$悊Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ * @date 2023-05-15
+ */
+public interface SysClientMapper extends BaseMapperPlus<SysClient, SysClientVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..0eaaee8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysConfig;
+import org.dromara.system.domain.vo.SysConfigVo;
+
+/**
+ * 鍙傛暟閰嶇疆 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysConfigMapper extends BaseMapperPlus<SysConfig, SysConfigVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..08dda66
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
@@ -0,0 +1,46 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
+
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id")
+    })
+    List<SysDeptVo> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id")
+    })
+    long countDeptById(Long deptId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     *
+     * @param roleId            瑙掕壊ID
+     * @param deptCheckStrictly 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..c2f1a7c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
@@ -0,0 +1,23 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.system.domain.vo.SysDictDataVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDictDataMapper extends BaseMapperPlus<SysDictData, SysDictDataVo> {
+
+    default List<SysDictDataVo> selectDictDataByType(String dictType) {
+        return selectVoList(
+            new LambdaQueryWrapper<SysDictData>()
+                .eq(SysDictData::getDictType, dictType)
+                .orderByAsc(SysDictData::getDictSort));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..9a9bdd5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.SysDictType;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDictTypeMapper extends BaseMapperPlus<SysDictType, SysDictTypeVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java
new file mode 100644
index 0000000..85edd1d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysLogininfor;
+import org.dromara.system.domain.vo.SysLogininforVo;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysLogininforMapper extends BaseMapperPlus<SysLogininfor, SysLogininforVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..ac646c0
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
@@ -0,0 +1,76 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 鑿滃崟琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鑿滃崟鍒楄〃
+     */
+    List<SysMenu> selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper<SysMenu> queryWrapper);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    List<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    List<String> selectMenuPermsByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     *
+     * @return 鑿滃崟鍒楄〃
+     */
+    default List<SysMenu> selectMenuTreeAll() {
+        LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper<SysMenu>()
+            .in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU)
+            .eq(SysMenu::getStatus, UserConstants.MENU_NORMAL)
+            .orderByAsc(SysMenu::getParentId)
+            .orderByAsc(SysMenu::getOrderNum);
+        return this.selectList(lqw);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param roleId            瑙掕壊ID
+     * @param menuCheckStrictly 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java
new file mode 100644
index 0000000..1e27b77
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysNotice;
+import org.dromara.system.domain.vo.SysNoticeVo;
+
+/**
+ * 閫氱煡鍏憡琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysNoticeMapper extends BaseMapperPlus<SysNotice, SysNoticeVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java
new file mode 100644
index 0000000..5d20404
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysOperLog;
+import org.dromara.system.domain.vo.SysOperLogVo;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysOperLogMapper extends BaseMapperPlus<SysOperLog, SysOperLogVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java
new file mode 100644
index 0000000..f93d34d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java
@@ -0,0 +1,16 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysOssConfig;
+import org.dromara.system.domain.vo.SysOssConfigVo;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Mapper鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface SysOssConfigMapper extends BaseMapperPlus<SysOssConfig, SysOssConfigVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java
new file mode 100644
index 0000000..3da621d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysOss;
+import org.dromara.system.domain.vo.SysOssVo;
+
+/**
+ * 鏂囦欢涓婁紶 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysOssMapper extends BaseMapperPlus<SysOss, SysOssVo> {
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
new file mode 100644
index 0000000..f9bf134
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
@@ -0,0 +1,36 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.vo.SysPostVo;
+
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysPostMapper extends BaseMapperPlus<SysPost, SysPostVo> {
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "create_by")
+    })
+    Page<SysPostVo> selectPagePostList(@Param("page") Page<SysPostVo> page, @Param(Constants.WRAPPER) Wrapper<SysPost> queryWrapper);
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    List<SysPostVo> selectPostsByUserId(Long userId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java
new file mode 100644
index 0000000..3de0bb6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRoleDept;
+
+/**
+ * 瑙掕壊涓庨儴闂ㄥ叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleDeptMapper extends BaseMapperPlus<SysRoleDept, SysRoleDept> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..ac5a47e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
@@ -0,0 +1,62 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.vo.SysRoleVo;
+
+import java.util.List;
+
+/**
+ * 瑙掕壊琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "r.create_by")
+    })
+    Page<SysRoleVo> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "r.create_by")
+    })
+    List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "r.create_by")
+    })
+    SysRoleVo selectRoleById(Long roleId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<SysRoleVo> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<SysRoleVo> selectRolesByUserId(Long userId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..0a657b4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRoleMenu;
+
+/**
+ * 瑙掕壊涓庤彍鍗曞叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleMenuMapper extends BaseMapperPlus<SysRoleMenu, SysRoleMenu> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java
new file mode 100644
index 0000000..b942061
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysSocial;
+import org.dromara.system.domain.vo.SysSocialVo;
+
+/**
+ * 绀句細鍖栧叧绯籑apper鎺ュ彛
+ *
+ * @author thiszhc
+ */
+public interface SysSocialMapper extends BaseMapperPlus<SysSocial, SysSocialVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
new file mode 100644
index 0000000..7e1167a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.SysTenant;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 绉熸埛Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface SysTenantMapper extends BaseMapperPlus<SysTenant, SysTenantVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java
new file mode 100644
index 0000000..10ca170
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+
+/**
+ * 绉熸埛濂楅Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface SysTenantPackageMapper extends BaseMapperPlus<SysTenantPackage, SysTenantPackageVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..fc7fc6e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
@@ -0,0 +1,91 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysUserExportVo;
+import org.dromara.system.domain.vo.SysUserVo;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "u.dept_id"),
+        @DataColumn(key = "userName", value = "u.user_id")
+    })
+    Page<SysUserVo> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    List<SysUserVo> selectUserList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "u.user_id")
+    })
+    List<SysUserExportVo> selectUserExportList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸查厤鐢ㄦ埛瑙掕壊鍒楄〃
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "u.user_id")
+    })
+    Page<SysUserVo> selectAllocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+     *
+     * @param queryWrapper 鏌ヨ鏉′欢
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "u.user_id")
+    })
+    Page<SysUserVo> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    long countUserById(Long userId);
+
+    @Override
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper<SysUser> updateWrapper);
+
+    @Override
+    @DataPermission({
+        @DataColumn(key = "deptName", value = "dept_id"),
+        @DataColumn(key = "userName", value = "user_id")
+    })
+    int updateById(@Param(Constants.ENTITY) SysUser user);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java
new file mode 100644
index 0000000..07c1371
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUserPost;
+
+/**
+ * 鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserPostMapper extends BaseMapperPlus<SysUserPost, SysUserPost> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..e2f706c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
@@ -0,0 +1,17 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUserRole;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛涓庤鑹插叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRole, SysUserRole> {
+
+    List<Long> selectUserIdsByRoleId(Long roleId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java
new file mode 100644
index 0000000..27dad7d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java
@@ -0,0 +1,28 @@
+package org.dromara.system.runner;
+
+import org.dromara.system.service.ISysOssConfigService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鍒濆鍖� system 妯″潡瀵瑰簲涓氬姟鏁版嵁
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class SystemApplicationRunner implements ApplicationRunner {
+
+    private final ISysOssConfigService ossConfigService;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        ossConfigService.init();
+        log.info("鍒濆鍖朞SS閰嶇疆鎴愬姛");
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
new file mode 100644
index 0000000..d0f8a3c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
@@ -0,0 +1,60 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀹㈡埛绔鐞哠ervice鎺ュ彛
+ *
+ * @author Michelle.Chung
+ * @date 2023-06-18
+ */
+public interface ISysClientService {
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞�
+     */
+    SysClientVo queryById(Long id);
+
+    /**
+     * 鏌ヨ瀹㈡埛绔俊鎭熀浜庡鎴风id
+     */
+    SysClientVo queryByClientId(String clientId);
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+     */
+    TableDataInfo<SysClientVo> queryPageList(SysClientBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+     */
+    List<SysClientVo> queryList(SysClientBo bo);
+
+    /**
+     * 鏂板瀹㈡埛绔鐞�
+     */
+    Boolean insertByBo(SysClientBo bo);
+
+    /**
+     * 淇敼瀹㈡埛绔鐞�
+     */
+    Boolean updateByBo(SysClientBo bo);
+
+    /**
+     * 淇敼鐘舵��
+     */
+    int updateUserStatus(String clientId, String status);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ鎴风绠$悊淇℃伅
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java
new file mode 100644
index 0000000..f7efda7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java
@@ -0,0 +1,87 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+
+import java.util.List;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysConfigService {
+
+
+    TableDataInfo<SysConfigVo> selectPageConfigList(SysConfigBo config, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     *
+     * @param configId 鍙傛暟閰嶇疆ID
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    SysConfigVo selectConfigById(Long configId);
+
+    /**
+     * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     *
+     * @param configKey 鍙傛暟閿悕
+     * @return 鍙傛暟閿��
+     */
+    String selectConfigByKey(String configKey);
+
+    /**
+     * 鑾峰彇娉ㄥ唽寮�鍏�
+     * @param tenantId 绉熸埛id
+     * @return true寮�鍚紝false鍏抽棴
+     */
+    boolean selectRegisterEnabled(String tenantId);
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+     *
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆闆嗗悎
+     */
+    List<SysConfigVo> selectConfigList(SysConfigBo config);
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     *
+     * @param bo 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    String insertConfig(SysConfigBo bo);
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     *
+     * @param bo 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    String updateConfig(SysConfigBo bo);
+
+    /**
+     * 鎵归噺鍒犻櫎鍙傛暟淇℃伅
+     *
+     * @param configIds 闇�瑕佸垹闄ょ殑鍙傛暟ID
+     */
+    void deleteConfigByIds(Long[] configIds);
+
+    /**
+     * 閲嶇疆鍙傛暟缂撳瓨鏁版嵁
+     */
+    void resetConfigCache();
+
+    /**
+     * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+     *
+     * @param config 鍙傛暟淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkConfigKeyUnique(SysConfigBo config);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java
new file mode 100644
index 0000000..3f252f7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java
@@ -0,0 +1,26 @@
+package org.dromara.system.service;
+
+/**
+ * 閫氱敤 鏁版嵁鏉冮檺 鏈嶅姟
+ *
+ * @author Lion Li
+ */
+public interface ISysDataScopeService {
+
+    /**
+     * 鑾峰彇瑙掕壊鑷畾涔夋潈闄�
+     *
+     * @param roleId 瑙掕壊id
+     * @return 閮ㄩ棬id缁�
+     */
+    String getRoleCustom(Long roleId);
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍙婁互涓嬫潈闄�
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 閮ㄩ棬id缁�
+     */
+    String getDeptAndChild(Long deptId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
new file mode 100644
index 0000000..bf16642
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
@@ -0,0 +1,125 @@
+package org.dromara.system.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDeptService {
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     *
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    List<SysDeptVo> selectDeptList(SysDeptBo dept);
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏍戠粨鏋勪俊鎭�
+     *
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬鏍戜俊鎭泦鍚�
+     */
+    List<Tree<Long>> selectDeptTreeList(SysDeptBo dept);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    List<Tree<Long>> buildDeptTreeSelect(List<SysDeptVo> depts);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    List<Long> selectDeptListByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬淇℃伅
+     */
+    SysDeptVo selectDeptById(Long deptId);
+
+    /**
+     * 閫氳繃閮ㄩ棬ID涓叉煡璇㈤儴闂�
+     *
+     * @param deptIds 閮ㄩ棬id涓�
+     * @return 閮ㄩ棬鍒楄〃淇℃伅
+     */
+    List<SysDeptVo> selectDeptByIds(List<Long> deptIds);
+
+    /**
+     * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬鏁帮紙姝e父鐘舵�侊級
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 瀛愰儴闂ㄦ暟
+     */
+    long selectNormalChildrenDeptById(Long deptId);
+
+    /**
+     * 鏄惁瀛樺湪閮ㄩ棬瀛愯妭鐐�
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    boolean hasChildByDeptId(Long deptId);
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    boolean checkDeptExistUser(Long deptId);
+
+    /**
+     * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+     *
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkDeptNameUnique(SysDeptBo dept);
+
+    /**
+     * 鏍¢獙閮ㄩ棬鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param deptId 閮ㄩ棬id
+     */
+    void checkDeptDataScope(Long deptId);
+
+    /**
+     * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+     *
+     * @param bo 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    int insertDept(SysDeptBo bo);
+
+    /**
+     * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+     *
+     * @param bo 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    int updateDept(SysDeptBo bo);
+
+    /**
+     * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    int deleteDeptById(Long deptId);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java
new file mode 100644
index 0000000..0e697db
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java
@@ -0,0 +1,76 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDictDataService {
+
+
+    TableDataInfo<SysDictDataVo> selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+     *
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    List<SysDictDataVo> selectDictDataList(SysDictDataBo dictData);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀閿��
+     * @return 瀛楀吀鏍囩
+     */
+    String selectDictLabel(String dictType, String dictValue);
+
+    /**
+     * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+     *
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 瀛楀吀鏁版嵁
+     */
+    SysDictDataVo selectDictDataById(Long dictCode);
+
+    /**
+     * 鎵归噺鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param dictCodes 闇�瑕佸垹闄ょ殑瀛楀吀鏁版嵁ID
+     */
+    void deleteDictDataByIds(Long[] dictCodes);
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param bo 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    List<SysDictDataVo> insertDictData(SysDictDataBo bo);
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param bo 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    List<SysDictDataVo> updateDictData(SysDictDataBo bo);
+
+    /**
+     * 鏍¢獙瀛楀吀閿�兼槸鍚﹀敮涓�
+     *
+     * @param dict 瀛楀吀鏁版嵁
+     * @return 缁撴灉
+     */
+    boolean checkDictDataUnique(SysDictDataBo dict);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java
new file mode 100644
index 0000000..3b32d6c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java
@@ -0,0 +1,95 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDictTypeService {
+
+
+    TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+     *
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    List<SysDictTypeVo> selectDictTypeList(SysDictTypeBo dictType);
+
+    /**
+     * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+     *
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    List<SysDictTypeVo> selectDictTypeAll();
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    List<SysDictDataVo> selectDictDataByType(String dictType);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+     *
+     * @param dictId 瀛楀吀绫诲瀷ID
+     * @return 瀛楀吀绫诲瀷
+     */
+    SysDictTypeVo selectDictTypeById(Long dictId);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀绫诲瀷
+     */
+    SysDictTypeVo selectDictTypeByType(String dictType);
+
+    /**
+     * 鎵归噺鍒犻櫎瀛楀吀淇℃伅
+     *
+     * @param dictIds 闇�瑕佸垹闄ょ殑瀛楀吀ID
+     */
+    void deleteDictTypeByIds(Long[] dictIds);
+
+    /**
+     * 閲嶇疆瀛楀吀缂撳瓨鏁版嵁
+     */
+    void resetDictCache();
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     *
+     * @param bo 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    List<SysDictDataVo> insertDictType(SysDictTypeBo bo);
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     *
+     * @param bo 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    List<SysDictDataVo> updateDictType(SysDictTypeBo bo);
+
+    /**
+     * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    boolean checkDictTypeUnique(SysDictTypeBo dictType);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java
new file mode 100644
index 0000000..6b3b7a6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java
@@ -0,0 +1,47 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysLogininforService {
+
+
+    TableDataInfo<SysLogininforVo> selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery);
+
+    /**
+     * 鏂板绯荤粺鐧诲綍鏃ュ織
+     *
+     * @param bo 璁块棶鏃ュ織瀵硅薄
+     */
+    void insertLogininfor(SysLogininforBo bo);
+
+    /**
+     * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+     *
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     * @return 鐧诲綍璁板綍闆嗗悎
+     */
+    List<SysLogininforVo> selectLogininforList(SysLogininforBo logininfor);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+     *
+     * @param infoIds 闇�瑕佸垹闄ょ殑鐧诲綍鏃ュ織ID
+     * @return 缁撴灉
+     */
+    int deleteLogininforByIds(Long[] infoIds);
+
+    /**
+     * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+     */
+    void cleanLogininfor();
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java
new file mode 100644
index 0000000..72d705e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java
@@ -0,0 +1,147 @@
+package org.dromara.system.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 鑿滃崟 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysMenuService {
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    List<SysMenuVo> selectMenuList(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     *
+     * @param menu   鑿滃崟淇℃伅
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    Set<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    Set<String> selectMenuPermsByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    List<Long> selectMenuListByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁绉熸埛濂楅ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param packageId 绉熸埛濂楅ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    List<Long> selectMenuListByPackageId(Long packageId);
+
+    /**
+     * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+     *
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 璺敱鍒楄〃
+     */
+    List<RouterVo> buildMenus(List<SysMenu> menus);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    List<Tree<Long>> buildMenuTreeSelect(List<SysMenuVo> menus);
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    SysMenuVo selectMenuById(Long menuId);
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    boolean hasChildByMenuId(Long menuId);
+
+    /**
+     * 鏌ヨ鑿滃崟鏄惁瀛樺湪瑙掕壊
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    boolean checkMenuExistRole(Long menuId);
+
+    /**
+     * 鏂板淇濆瓨鑿滃崟淇℃伅
+     *
+     * @param bo 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    int insertMenu(SysMenuBo bo);
+
+    /**
+     * 淇敼淇濆瓨鑿滃崟淇℃伅
+     *
+     * @param bo 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    int updateMenu(SysMenuBo bo);
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    int deleteMenuById(Long menuId);
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     *
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkMenuNameUnique(SysMenuBo menu);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java
new file mode 100644
index 0000000..8ec999d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java
@@ -0,0 +1,67 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+
+import java.util.List;
+
+/**
+ * 鍏憡 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysNoticeService {
+
+
+    TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鍏憡淇℃伅
+     *
+     * @param noticeId 鍏憡ID
+     * @return 鍏憡淇℃伅
+     */
+    SysNoticeVo selectNoticeById(Long noticeId);
+
+    /**
+     * 鏌ヨ鍏憡鍒楄〃
+     *
+     * @param notice 鍏憡淇℃伅
+     * @return 鍏憡闆嗗悎
+     */
+    List<SysNoticeVo> selectNoticeList(SysNoticeBo notice);
+
+    /**
+     * 鏂板鍏憡
+     *
+     * @param bo 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    int insertNotice(SysNoticeBo bo);
+
+    /**
+     * 淇敼鍏憡
+     *
+     * @param bo 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    int updateNotice(SysNoticeBo bo);
+
+    /**
+     * 鍒犻櫎鍏憡淇℃伅
+     *
+     * @param noticeId 鍏憡ID
+     * @return 缁撴灉
+     */
+    int deleteNoticeById(Long noticeId);
+
+    /**
+     * 鎵归噺鍒犻櫎鍏憡淇℃伅
+     *
+     * @param noticeIds 闇�瑕佸垹闄ょ殑鍏憡ID
+     * @return 缁撴灉
+     */
+    int deleteNoticeByIds(Long[] noticeIds);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java
new file mode 100644
index 0000000..9573510
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java
@@ -0,0 +1,54 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+
+import java.util.List;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysOperLogService {
+
+    TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery);
+
+    /**
+     * 鏂板鎿嶄綔鏃ュ織
+     *
+     * @param bo 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    void insertOperlog(SysOperLogBo bo);
+
+    /**
+     * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+     *
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     * @return 鎿嶄綔鏃ュ織闆嗗悎
+     */
+    List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+     *
+     * @param operIds 闇�瑕佸垹闄ょ殑鎿嶄綔鏃ュ織ID
+     * @return 缁撴灉
+     */
+    int deleteOperLogByIds(Long[] operIds);
+
+    /**
+     * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+     *
+     * @param operId 鎿嶄綔ID
+     * @return 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    SysOperLogVo selectOperLogById(Long operId);
+
+    /**
+     * 娓呯┖鎿嶄綔鏃ュ織
+     */
+    void cleanOperLog();
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java
new file mode 100644
index 0000000..2f6dfc9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java
@@ -0,0 +1,64 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOssConfigBo;
+import org.dromara.system.domain.vo.SysOssConfigVo;
+
+import java.util.Collection;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Service鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface ISysOssConfigService {
+
+    /**
+     * 鍒濆鍖朞SS閰嶇疆
+     */
+    void init();
+
+    /**
+     * 鏌ヨ鍗曚釜
+     */
+    SysOssConfigVo queryById(Long ossConfigId);
+
+    /**
+     * 鏌ヨ鍒楄〃
+     */
+    TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏂板涓氬姟瀵硅薄鎻掑叆瀵硅薄瀛樺偍閰嶇疆
+     *
+     * @param bo 瀵硅薄瀛樺偍閰嶇疆鏂板涓氬姟瀵硅薄
+     * @return 缁撴灉
+     */
+    Boolean insertByBo(SysOssConfigBo bo);
+
+    /**
+     * 鏍规嵁缂栬緫涓氬姟瀵硅薄淇敼瀵硅薄瀛樺偍閰嶇疆
+     *
+     * @param bo 瀵硅薄瀛樺偍閰嶇疆缂栬緫涓氬姟瀵硅薄
+     * @return 缁撴灉
+     */
+    Boolean updateByBo(SysOssConfigBo bo);
+
+    /**
+     * 鏍¢獙骞跺垹闄ゆ暟鎹�
+     *
+     * @param ids     涓婚敭闆嗗悎
+     * @param isValid 鏄惁鏍¢獙,true-鍒犻櫎鍓嶆牎楠�,false-涓嶆牎楠�
+     * @return 缁撴灉
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 鍚敤鍋滅敤鐘舵��
+     */
+    int updateOssConfigStatus(SysOssConfigBo bo);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java
new file mode 100644
index 0000000..057c068
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java
@@ -0,0 +1,80 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOssBo;
+import org.dromara.system.domain.vo.SysOssVo;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鏂囦欢涓婁紶 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysOssService {
+
+    /**
+     * 鏌ヨOSS瀵硅薄瀛樺偍鍒楄〃
+     *
+     * @param sysOss    OSS瀵硅薄瀛樺偍鍒嗛〉鏌ヨ瀵硅薄
+     * @param pageQuery 鍒嗛〉鏌ヨ瀹炰綋绫�
+     * @return 缁撴灉
+     */
+    TableDataInfo<SysOssVo> queryPageList(SysOssBo sysOss, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁涓�缁� ossIds 鑾峰彇瀵瑰簲鐨� SysOssVo 鍒楄〃
+     *
+     * @param ossIds 涓�缁勬枃浠跺湪鏁版嵁搴撲腑鐨勫敮涓�鏍囪瘑闆嗗悎
+     * @return 鍖呭惈 SysOssVo 瀵硅薄鐨勫垪琛�
+     */
+    List<SysOssVo> listByIds(Collection<Long> ossIds);
+
+    /**
+     * 鏍规嵁 ossId 浠庣紦瀛樻垨鏁版嵁搴撲腑鑾峰彇 SysOssVo 瀵硅薄
+     *
+     * @param ossId 鏂囦欢鍦ㄦ暟鎹簱涓殑鍞竴鏍囪瘑
+     * @return SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     */
+    SysOssVo getById(Long ossId);
+
+    /**
+     * 涓婁紶 MultipartFile 鍒板璞″瓨鍌ㄦ湇鍔★紝骞朵繚瀛樻枃浠朵俊鎭埌鏁版嵁搴�
+     *
+     * @param file 瑕佷笂浼犵殑 MultipartFile 瀵硅薄
+     * @return 涓婁紶鎴愬姛鍚庣殑 SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     */
+    SysOssVo upload(MultipartFile file);
+
+    /**
+     * 涓婁紶鏂囦欢鍒板璞″瓨鍌ㄦ湇鍔★紝骞朵繚瀛樻枃浠朵俊鎭埌鏁版嵁搴�
+     *
+     * @param file 瑕佷笂浼犵殑鏂囦欢瀵硅薄
+     * @return 涓婁紶鎴愬姛鍚庣殑 SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     */
+    SysOssVo upload(File file);
+
+    /**
+     * 鏂囦欢涓嬭浇鏂规硶锛屾敮鎸佷竴娆℃�т笅杞藉畬鏁存枃浠�
+     *
+     * @param ossId    OSS瀵硅薄ID
+     * @param response HttpServletResponse瀵硅薄锛岀敤浜庤缃搷搴斿ご鍜屽悜瀹㈡埛绔彂閫佹枃浠跺唴瀹�
+     */
+    void download(Long ossId, HttpServletResponse response) throws IOException;
+
+    /**
+     * 鍒犻櫎OSS瀵硅薄瀛樺偍
+     *
+     * @param ids     OSS瀵硅薄ID涓�
+     * @param isValid 鍒ゆ柇鏄惁闇�瑕佹牎楠�
+     * @return 缁撴灉
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java
new file mode 100644
index 0000000..0116df5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java
@@ -0,0 +1,28 @@
+package org.dromara.system.service;
+
+import java.util.Set;
+
+/**
+ * 鐢ㄦ埛鏉冮檺澶勭悊
+ *
+ * @author Lion Li
+ */
+public interface ISysPermissionService {
+
+    /**
+     * 鑾峰彇瑙掕壊鏁版嵁鏉冮檺
+     *
+     * @param userId  鐢ㄦ埛id
+     * @return 瑙掕壊鏉冮檺淇℃伅
+     */
+    Set<String> getRolePermission(Long userId);
+
+    /**
+     * 鑾峰彇鑿滃崟鏁版嵁鏉冮檺
+     *
+     * @param userId  鐢ㄦ埛id
+     * @return 鑿滃崟鏉冮檺淇℃伅
+     */
+    Set<String> getMenuPermission(Long userId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
new file mode 100644
index 0000000..3751b23
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -0,0 +1,122 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysPostService {
+
+
+    TableDataInfo<SysPostVo> selectPagePostList(SysPostBo post, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 宀椾綅鍒楄〃
+     */
+    List<SysPostVo> selectPostList(SysPostBo post);
+
+    /**
+     * 鏌ヨ鎵�鏈夊矖浣�
+     *
+     * @return 宀椾綅鍒楄〃
+     */
+    List<SysPostVo> selectPostAll();
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+     *
+     * @param postId 宀椾綅ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    SysPostVo selectPostById(Long postId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑宀椾綅ID鍒楄〃
+     */
+    List<Long> selectPostListByUserId(Long userId);
+
+    /**
+     * 閫氳繃宀椾綅ID涓叉煡璇㈠矖浣�
+     *
+     * @param postIds 宀椾綅id涓�
+     * @return 宀椾綅鍒楄〃淇℃伅
+     */
+    List<SysPostVo> selectPostByIds(List<Long> postIds);
+
+    /**
+     * 鏍¢獙宀椾綅鍚嶇О
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkPostNameUnique(SysPostBo post);
+
+    /**
+     * 鏍¢獙宀椾綅缂栫爜
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkPostCodeUnique(SysPostBo post);
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    long countUserPostById(Long postId);
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 缁撴灉
+     */
+    long countPostByDeptId(Long deptId);
+
+    /**
+     * 鍒犻櫎宀椾綅淇℃伅
+     *
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    int deletePostById(Long postId);
+
+    /**
+     * 鎵归噺鍒犻櫎宀椾綅淇℃伅
+     *
+     * @param postIds 闇�瑕佸垹闄ょ殑宀椾綅ID
+     * @return 缁撴灉
+     */
+    int deletePostByIds(Long[] postIds);
+
+    /**
+     * 鏂板淇濆瓨宀椾綅淇℃伅
+     *
+     * @param bo 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    int insertPost(SysPostBo bo);
+
+    /**
+     * 淇敼淇濆瓨宀椾綅淇℃伅
+     *
+     * @param bo 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    int updatePost(SysPostBo bo);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
new file mode 100644
index 0000000..64740ae
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
@@ -0,0 +1,200 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.vo.SysRoleVo;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 瑙掕壊涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysRoleService {
+
+
+    TableDataInfo<SysRoleVo> selectPageRoleList(SysRoleBo role, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    List<SysRoleVo> selectRoleList(SysRoleBo role);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<SysRoleVo> selectRolesByUserId(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃(鍖呭惈琚巿鏉冪姸鎬�)
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<SysRoleVo> selectRolesAuthByUserId(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鏉冮檺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    Set<String> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 鏌ヨ鎵�鏈夎鑹�
+     *
+     * @return 瑙掕壊鍒楄〃
+     */
+    List<SysRoleVo> selectRoleAll();
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑瑙掕壊ID鍒楄〃
+     */
+    List<Long> selectRoleListByUserId(Long userId);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    SysRoleVo selectRoleById(Long roleId);
+
+    /**
+     * 閫氳繃瑙掕壊ID涓叉煡璇㈣鑹�
+     *
+     * @param roleIds 瑙掕壊ID涓�
+     * @return 瑙掕壊鍒楄〃淇℃伅
+     */
+    List<SysRoleVo> selectRoleByIds(List<Long> roleIds);
+
+    /**
+     * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkRoleNameUnique(SysRoleBo role);
+
+    /**
+     * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkRoleKeyUnique(SysRoleBo role);
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+     *
+     * @param role 瑙掕壊淇℃伅
+     */
+    void checkRoleAllowed(SysRoleBo role);
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param roleId 瑙掕壊id
+     */
+    void checkRoleDataScope(Long roleId);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    long countUserRoleByRoleId(Long roleId);
+
+    /**
+     * 鏂板淇濆瓨瑙掕壊淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    int insertRole(SysRoleBo bo);
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    int updateRole(SysRoleBo bo);
+
+    /**
+     * 淇敼瑙掕壊鐘舵��
+     *
+     * @param roleId 瑙掕壊ID
+     * @param status 瑙掕壊鐘舵��
+     * @return 缁撴灉
+     */
+    int updateRoleStatus(Long roleId, String status);
+
+    /**
+     * 淇敼鏁版嵁鏉冮檺淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    int authDataScope(SysRoleBo bo);
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    int deleteRoleById(Long roleId);
+
+    /**
+     * 鎵归噺鍒犻櫎瑙掕壊淇℃伅
+     *
+     * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
+     * @return 缁撴灉
+     */
+    int deleteRoleByIds(Long[] roleIds);
+
+    /**
+     * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * @return 缁撴灉
+     */
+    int deleteAuthUser(SysUserRole userRole);
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    int deleteAuthUsers(Long roleId, Long[] userIds);
+
+    /**
+     * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    int insertAuthUsers(Long roleId, Long[] userIds);
+
+    void cleanOnlineUserByRole(Long roleId);
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java
new file mode 100644
index 0000000..cc7016e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java
@@ -0,0 +1,53 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.SysSocialVo;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯籗ervice鎺ュ彛
+ *
+ * @author thiszhc
+ */
+public interface ISysSocialService {
+
+
+    /**
+     * 鏌ヨ绀句細鍖栧叧绯�
+     */
+    SysSocialVo queryById(String id);
+
+    /**
+     * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+     */
+    List<SysSocialVo> queryList(SysSocialBo bo);
+
+    /**
+     * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+     */
+    List<SysSocialVo> queryListByUserId(Long userId);
+
+    /**
+     * 鏂板鎺堟潈鍏崇郴
+     */
+    Boolean insertByBo(SysSocialBo bo);
+
+    /**
+     * 鏇存柊绀句細鍖栧叧绯�
+     */
+    Boolean updateByBo(SysSocialBo bo);
+
+    /**
+     * 鍒犻櫎绀句細鍖栧叧绯讳俊鎭�
+     */
+    Boolean deleteWithValidById(Long id);
+
+
+    /**
+     * 鏍规嵁 authId 鏌ヨ
+     */
+    List<SysSocialVo> selectByAuthId(String authId);
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
new file mode 100644
index 0000000..d060b68
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
@@ -0,0 +1,62 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅Service鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface ISysTenantPackageService {
+
+    /**
+     * 鏌ヨ绉熸埛濂楅
+     */
+    SysTenantPackageVo queryById(Long packageId);
+
+    /**
+     * 鏌ヨ绉熸埛濂楅鍒楄〃
+     */
+    TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绉熸埛濂楅宸插惎鐢ㄥ垪琛�
+     */
+    List<SysTenantPackageVo> selectList();
+
+    /**
+     * 鏌ヨ绉熸埛濂楅鍒楄〃
+     */
+    List<SysTenantPackageVo> queryList(SysTenantPackageBo bo);
+
+    /**
+     * 鏂板绉熸埛濂楅
+     */
+    Boolean insertByBo(SysTenantPackageBo bo);
+
+    /**
+     * 淇敼绉熸埛濂楅
+     */
+    Boolean updateByBo(SysTenantPackageBo bo);
+
+    /**
+     * 鏍¢獙濂楅鍚嶇О鏄惁鍞竴
+     */
+    boolean checkPackageNameUnique(SysTenantPackageBo bo);
+
+    /**
+     * 淇敼濂楅鐘舵��
+     */
+    int updatePackageStatus(SysTenantPackageBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ鎴峰椁愪俊鎭�
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
new file mode 100644
index 0000000..d12ed95
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
@@ -0,0 +1,82 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛Service鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface ISysTenantService {
+
+    /**
+     * 鏌ヨ绉熸埛
+     */
+    SysTenantVo queryById(Long id);
+
+    /**
+     * 鍩轰簬绉熸埛ID鏌ヨ绉熸埛
+     */
+    SysTenantVo queryByTenantId(String tenantId);
+
+    /**
+     * 鏌ヨ绉熸埛鍒楄〃
+     */
+    TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绉熸埛鍒楄〃
+     */
+    List<SysTenantVo> queryList(SysTenantBo bo);
+
+    /**
+     * 鏂板绉熸埛
+     */
+    Boolean insertByBo(SysTenantBo bo);
+
+    /**
+     * 淇敼绉熸埛
+     */
+    Boolean updateByBo(SysTenantBo bo);
+
+    /**
+     * 淇敼绉熸埛鐘舵��
+     */
+    int updateTenantStatus(SysTenantBo bo);
+
+    /**
+     * 鏍¢獙绉熸埛鏄惁鍏佽鎿嶄綔
+     */
+    void checkTenantAllowed(String tenantId);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ鎴蜂俊鎭�
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 鏍¢獙浼佷笟鍚嶇О鏄惁鍞竴
+     */
+    boolean checkCompanyNameUnique(SysTenantBo bo);
+
+    /**
+     * 鏍¢獙璐﹀彿浣欓
+     */
+    boolean checkAccountBalance(String tenantId);
+
+    /**
+     * 鏍¢獙鏈夋晥鏈�
+     */
+    boolean checkExpireTime(String tenantId);
+
+    /**
+     * 鍚屾绉熸埛濂楅
+     */
+    Boolean syncTenantPackage(String tenantId, Long packageId);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
new file mode 100644
index 0000000..0325a25
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
@@ -0,0 +1,222 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysUserExportVo;
+import org.dromara.system.domain.vo.SysUserVo;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysUserService {
+
+
+    TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    List<SysUserExportVo> selectUserExportList(SysUserBo user);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery);
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery);
+
+    /**
+     * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+     *
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    SysUserVo selectUserByUserName(String userName);
+
+    /**
+     * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴�
+     *
+     * @param phonenumber 鎵嬫満鍙�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    SysUserVo selectUserByPhonenumber(String phonenumber);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    SysUserVo selectUserById(Long userId);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID涓叉煡璇㈢敤鎴�
+     *
+     * @param userIds 鐢ㄦ埛ID涓�
+     * @param deptId  閮ㄩ棬id
+     * @return 鐢ㄦ埛鍒楄〃淇℃伅
+     */
+    List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    String selectUserRoleGroup(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    String selectUserPostGroup(Long userId);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkUserNameUnique(SysUserBo user);
+
+    /**
+     * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkPhoneUnique(SysUserBo user);
+
+    /**
+     * 鏍¢獙email鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    boolean checkEmailUnique(SysUserBo user);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+     *
+     * @param userId 鐢ㄦ埛ID
+     */
+    void checkUserAllowed(Long userId);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param userId 鐢ㄦ埛id
+     */
+    void checkUserDataScope(Long userId);
+
+    /**
+     * 鏂板鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    int insertUser(SysUserBo user);
+
+    /**
+     * 娉ㄥ唽鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    boolean registerUser(SysUserBo user, String tenantId);
+
+    /**
+     * 淇敼鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    int updateUser(SysUserBo user);
+
+    /**
+     * 鐢ㄦ埛鎺堟潈瑙掕壊
+     *
+     * @param userId  鐢ㄦ埛ID
+     * @param roleIds 瑙掕壊缁�
+     */
+    void insertUserAuth(Long userId, Long[] roleIds);
+
+    /**
+     * 淇敼鐢ㄦ埛鐘舵��
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @param status 甯愬彿鐘舵��
+     * @return 缁撴灉
+     */
+    int updateUserStatus(Long userId, String status);
+
+    /**
+     * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    int updateUserProfile(SysUserBo user);
+
+    /**
+     * 淇敼鐢ㄦ埛澶村儚
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @param avatar 澶村儚鍦板潃
+     * @return 缁撴灉
+     */
+    boolean updateUserAvatar(Long userId, Long avatar);
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     *
+     * @param userId   鐢ㄦ埛ID
+     * @param password 瀵嗙爜
+     * @return 缁撴灉
+     */
+    int resetUserPwd(Long userId, String password);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    int deleteUserById(Long userId);
+
+    /**
+     * 鎵归噺鍒犻櫎鐢ㄦ埛淇℃伅
+     *
+     * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    int deleteUserByIds(Long[] userIds);
+
+    /**
+     * 閫氳繃閮ㄩ棬id鏌ヨ褰撳墠閮ㄩ棬鎵�鏈夌敤鎴�
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 缁撴灉
+     */
+    List<SysUserVo> selectUserListByDept(Long deptId);
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
new file mode 100644
index 0000000..1c69243
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
@@ -0,0 +1,151 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.crypto.SecureUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.mapper.SysClientMapper;
+import org.dromara.system.service.ISysClientService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀹㈡埛绔鐞哠ervice涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ * @date 2023-06-18
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysClientServiceImpl implements ISysClientService {
+
+    private final SysClientMapper baseMapper;
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞�
+     */
+    @Override
+    public SysClientVo queryById(Long id) {
+        SysClientVo vo = baseMapper.selectVoById(id);
+        vo.setGrantTypeList(List.of(vo.getGrantType().split(",")));
+        return vo;
+    }
+
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞�
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId")
+    @Override
+    public SysClientVo queryByClientId(String clientId) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysClient>().eq(SysClient::getClientId, clientId));
+    }
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+     */
+    @Override
+    public TableDataInfo<SysClientVo> queryPageList(SysClientBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(bo);
+        Page<SysClientVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        result.getRecords().forEach(r -> r.setGrantTypeList(List.of(r.getGrantType().split(","))));
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+     */
+    @Override
+    public List<SysClientVo> queryList(SysClientBo bo) {
+        LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysClient> buildQueryWrapper(SysClientBo bo) {
+        LambdaQueryWrapper<SysClient> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getClientId()), SysClient::getClientId, bo.getClientId());
+        lqw.eq(StringUtils.isNotBlank(bo.getClientKey()), SysClient::getClientKey, bo.getClientKey());
+        lqw.eq(StringUtils.isNotBlank(bo.getClientSecret()), SysClient::getClientSecret, bo.getClientSecret());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysClient::getStatus, bo.getStatus());
+        lqw.orderByAsc(SysClient::getId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板瀹㈡埛绔鐞�
+     */
+    @Override
+    public Boolean insertByBo(SysClientBo bo) {
+        SysClient add = MapstructUtils.convert(bo, SysClient.class);
+        validEntityBeforeSave(add);
+        add.setGrantType(String.join(",", bo.getGrantTypeList()));
+        // 鐢熸垚clientid
+        String clientKey = bo.getClientKey();
+        String clientSecret = bo.getClientSecret();
+        add.setClientId(SecureUtil.md5(clientKey + clientSecret));
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼瀹㈡埛绔鐞�
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#bo.clientId")
+    @Override
+    public Boolean updateByBo(SysClientBo bo) {
+        SysClient update = MapstructUtils.convert(bo, SysClient.class);
+        validEntityBeforeSave(update);
+        update.setGrantType(String.join(",", bo.getGrantTypeList()));
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇敼鐘舵��
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId")
+    @Override
+    public int updateUserStatus(String clientId, String status) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysClient>()
+                .set(SysClient::getStatus, status)
+                .eq(SysClient::getClientId, clientId));
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysClient entity) {
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎瀹㈡埛绔鐞�
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, allEntries = true)
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..46526bd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,219 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.ConfigService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysConfig;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+import org.dromara.system.mapper.SysConfigMapper;
+import org.dromara.system.service.ISysConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
+
+    private final SysConfigMapper baseMapper;
+
+    @Override
+    public TableDataInfo<SysConfigVo> selectPageConfigList(SysConfigBo config, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysConfig> lqw = buildQueryWrapper(config);
+        Page<SysConfigVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     *
+     * @param configId 鍙傛暟閰嶇疆ID
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    @Override
+    @DS("master")
+    public SysConfigVo selectConfigById(Long configId) {
+        return baseMapper.selectVoById(configId);
+    }
+
+    /**
+     * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     *
+     * @param configKey 鍙傛暟key
+     * @return 鍙傛暟閿��
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey")
+    @Override
+    public String selectConfigByKey(String configKey) {
+        SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
+            .eq(SysConfig::getConfigKey, configKey));
+        if (ObjectUtil.isNotNull(retConfig)) {
+            return retConfig.getConfigValue();
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇娉ㄥ唽寮�鍏�
+     * @param tenantId 绉熸埛id
+     * @return true寮�鍚紝false鍏抽棴
+     */
+    @Override
+    public boolean selectRegisterEnabled(String tenantId) {
+        SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> {
+            return baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
+                .eq(SysConfig::getConfigKey, "sys.account.registerUser"));
+        });
+        if (ObjectUtil.isNull(retConfig)) {
+            return false;
+        }
+        return Convert.toBool(retConfig.getConfigValue());
+    }
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+     *
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆闆嗗悎
+     */
+    @Override
+    public List<SysConfigVo> selectConfigList(SysConfigBo config) {
+        LambdaQueryWrapper<SysConfig> lqw = buildQueryWrapper(config);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysConfig> buildQueryWrapper(SysConfigBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SysConfig> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getConfigName()), SysConfig::getConfigName, bo.getConfigName());
+        lqw.eq(StringUtils.isNotBlank(bo.getConfigType()), SysConfig::getConfigType, bo.getConfigType());
+        lqw.like(StringUtils.isNotBlank(bo.getConfigKey()), SysConfig::getConfigKey, bo.getConfigKey());
+        lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
+            SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime"));
+        lqw.orderByAsc(SysConfig::getConfigId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     *
+     * @param bo 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey")
+    @Override
+    public String insertConfig(SysConfigBo bo) {
+        SysConfig config = MapstructUtils.convert(bo, SysConfig.class);
+        int row = baseMapper.insert(config);
+        if (row > 0) {
+            return config.getConfigValue();
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     *
+     * @param bo 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey")
+    @Override
+    public String updateConfig(SysConfigBo bo) {
+        int row = 0;
+        SysConfig config = MapstructUtils.convert(bo, SysConfig.class);
+        if (config.getConfigId() != null) {
+            SysConfig temp = baseMapper.selectById(config.getConfigId());
+            if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) {
+                CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey());
+            }
+            row = baseMapper.updateById(config);
+        } else {
+            CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey());
+            row = baseMapper.update(config, new LambdaQueryWrapper<SysConfig>()
+                .eq(SysConfig::getConfigKey, config.getConfigKey()));
+        }
+        if (row > 0) {
+            return config.getConfigValue();
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鍙傛暟淇℃伅
+     *
+     * @param configIds 闇�瑕佸垹闄ょ殑鍙傛暟ID
+     */
+    @Override
+    public void deleteConfigByIds(Long[] configIds) {
+        for (Long configId : configIds) {
+            SysConfig config = baseMapper.selectById(configId);
+            if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
+                throw new ServiceException(String.format("鍐呯疆鍙傛暟銆�%1$s銆戜笉鑳藉垹闄� ", config.getConfigKey()));
+            }
+            CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey());
+        }
+        baseMapper.deleteByIds(Arrays.asList(configIds));
+    }
+
+    /**
+     * 閲嶇疆鍙傛暟缂撳瓨鏁版嵁
+     */
+    @Override
+    public void resetConfigCache() {
+        CacheUtils.clear(CacheNames.SYS_CONFIG);
+    }
+
+    /**
+     * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+     *
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkConfigKeyUnique(SysConfigBo config) {
+        long configId = ObjectUtil.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+        SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()));
+        if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟 key 鑾峰彇鍙傛暟鍊�
+     *
+     * @param configKey 鍙傛暟 key
+     * @return 鍙傛暟鍊�
+     */
+    @Override
+    public String getConfigValue(String configKey) {
+        return SpringUtils.getAopProxy(this).selectConfigByKey(configKey);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
new file mode 100644
index 0000000..018f9a0
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
@@ -0,0 +1,77 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysRoleDept;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysRoleDeptMapper;
+import org.dromara.system.service.ISysDataScopeService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 鏁版嵁鏉冮檺 瀹炵幇
+ * <p>
+ * 娉ㄦ剰: 姝ervice鍐呬笉鍏佽璋冪敤鏍囨敞`鏁版嵁鏉冮檺`娉ㄨВ鐨勬柟娉�
+ * 渚嬪: deptMapper.selectList 姝� selectList 鏂规硶鏍囨敞浜哷鏁版嵁鏉冮檺`娉ㄨВ 浼氬嚭鐜板惊鐜В鏋愮殑闂
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service("sdss")
+public class SysDataScopeServiceImpl implements ISysDataScopeService {
+
+    private final SysRoleDeptMapper roleDeptMapper;
+    private final SysDeptMapper deptMapper;
+
+    /**
+     * 鑾峰彇瑙掕壊鑷畾涔夋潈闄�
+     *
+     * @param roleId 瑙掕壊Id
+     * @return 閮ㄩ棬Id缁�
+     */
+    @Override
+    public String getRoleCustom(Long roleId) {
+        if (ObjectUtil.isNull(roleId)) {
+            return "-1";
+        }
+        List<SysRoleDept> list = roleDeptMapper.selectList(
+            new LambdaQueryWrapper<SysRoleDept>()
+                .select(SysRoleDept::getDeptId)
+                .eq(SysRoleDept::getRoleId, roleId));
+        if (CollUtil.isNotEmpty(list)) {
+            return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId()));
+        }
+        return "-1";
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍙婁互涓嬫潈闄�
+     *
+     * @param deptId 閮ㄩ棬Id
+     * @return 閮ㄩ棬Id缁�
+     */
+    @Override
+    public String getDeptAndChild(Long deptId) {
+        if (ObjectUtil.isNull(deptId)) {
+            return "-1";
+        }
+        List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
+            .select(SysDept::getDeptId)
+            .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+        List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
+        ids.add(deptId);
+        if (CollUtil.isNotEmpty(ids)) {
+            return StreamUtils.join(ids, Convert::toStr);
+        }
+        return "-1";
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..160238d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
@@ -0,0 +1,337 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.DeptService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysDeptService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟瀹炵幇
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDeptServiceImpl implements ISysDeptService, DeptService {
+
+    private final SysDeptMapper baseMapper;
+    private final SysRoleMapper roleMapper;
+    private final SysUserMapper userMapper;
+
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     *
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    @Override
+    public List<SysDeptVo> selectDeptList(SysDeptBo dept) {
+        LambdaQueryWrapper<SysDept> lqw = buildQueryWrapper(dept);
+        return baseMapper.selectDeptList(lqw);
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏍戠粨鏋勪俊鎭�
+     *
+     * @param bo 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬鏍戜俊鎭泦鍚�
+     */
+    @Override
+    public List<Tree<Long>> selectDeptTreeList(SysDeptBo bo) {
+        // 鍙煡璇㈡湭绂佺敤閮ㄩ棬
+        bo.setStatus(UserConstants.DEPT_NORMAL);
+        LambdaQueryWrapper<SysDept> lqw = buildQueryWrapper(bo);
+        List<SysDeptVo> depts = baseMapper.selectDeptList(lqw);
+        return buildDeptTreeSelect(depts);
+    }
+
+    private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
+        LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
+        lqw.eq(SysDept::getDelFlag, UserConstants.DEL_FLAG_NORMAL);
+        lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
+        lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
+        lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
+        lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
+        lqw.orderByAsc(SysDept::getAncestors);
+        lqw.orderByAsc(SysDept::getParentId);
+        lqw.orderByAsc(SysDept::getOrderNum);
+        lqw.orderByAsc(SysDept::getDeptId);
+        return lqw;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<Tree<Long>> buildDeptTreeSelect(List<SysDeptVo> depts) {
+        if (CollUtil.isEmpty(depts)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeBuildUtils.build(depts, (dept, tree) ->
+            tree.setId(dept.getDeptId())
+                .setParentId(dept.getParentId())
+                .setName(dept.getDeptName())
+                .setWeight(dept.getOrderNum()));
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    @Override
+    public List<Long> selectDeptListByRoleId(Long roleId) {
+        SysRole role = roleMapper.selectById(roleId);
+        return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly());
+    }
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬淇℃伅
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId")
+    @Override
+    public SysDeptVo selectDeptById(Long deptId) {
+        SysDeptVo dept = baseMapper.selectVoById(deptId);
+        if (ObjectUtil.isNull(dept)) {
+            return null;
+        }
+        SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper<SysDept>()
+            .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId()));
+        dept.setParentName(ObjectUtil.isNotNull(parentDept) ? parentDept.getDeptName() : null);
+        return dept;
+    }
+
+    @Override
+    public List<SysDeptVo> selectDeptByIds(List<Long> deptIds) {
+        return baseMapper.selectDeptList(new LambdaQueryWrapper<SysDept>()
+            .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader)
+            .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds));
+    }
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ閮ㄩ棬鍚嶇О
+     *
+     * @param deptIds 閮ㄩ棬ID涓查�楀彿鍒嗛殧
+     * @return 閮ㄩ棬鍚嶇О涓查�楀彿鍒嗛殧
+     */
+    @Override
+    public String selectDeptNameByIds(String deptIds) {
+        List<String> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) {
+            SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                list.add(vo.getDeptName());
+            }
+        }
+        return String.join(StringUtils.SEPARATOR, list);
+    }
+
+    /**
+     * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬鏁帮紙姝e父鐘舵�侊級
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 瀛愰儴闂ㄦ暟
+     */
+    @Override
+    public long selectNormalChildrenDeptById(Long deptId) {
+        return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>()
+            .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+    }
+
+    /**
+     * 鏄惁瀛樺湪瀛愯妭鐐�
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByDeptId(Long deptId) {
+        return baseMapper.exists(new LambdaQueryWrapper<SysDept>()
+            .eq(SysDept::getParentId, deptId));
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    @Override
+    public boolean checkDeptExistUser(Long deptId) {
+        return userMapper.exists(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getDeptId, deptId));
+    }
+
+    /**
+     * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+     *
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkDeptNameUnique(SysDeptBo dept) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDept>()
+            .eq(SysDept::getDeptName, dept.getDeptName())
+            .eq(SysDept::getParentId, dept.getParentId())
+            .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙閮ㄩ棬鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param deptId 閮ㄩ棬id
+     */
+    @Override
+    public void checkDeptDataScope(Long deptId) {
+        if (ObjectUtil.isNull(deptId)) {
+            return;
+        }
+        if (LoginHelper.isSuperAdmin()) {
+            return;
+        }
+        if (baseMapper.countDeptById(deptId) == 0) {
+            throw new ServiceException("娌℃湁鏉冮檺璁块棶閮ㄩ棬鏁版嵁锛�");
+        }
+    }
+
+    /**
+     * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+     *
+     * @param bo 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDept(SysDeptBo bo) {
+        SysDept info = baseMapper.selectById(bo.getParentId());
+        // 濡傛灉鐖惰妭鐐逛笉涓烘甯哥姸鎬�,鍒欎笉鍏佽鏂板瀛愯妭鐐�
+        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
+            throw new ServiceException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
+        }
+        SysDept dept = MapstructUtils.convert(bo, SysDept.class);
+        dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId());
+        return baseMapper.insert(dept);
+    }
+
+    /**
+     * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+     *
+     * @param bo 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId")
+    @Override
+    public int updateDept(SysDeptBo bo) {
+        SysDept dept = MapstructUtils.convert(bo, SysDept.class);
+        SysDept oldDept = baseMapper.selectById(dept.getDeptId());
+        if (!oldDept.getParentId().equals(dept.getParentId())) {
+            // 濡傛灉鏄柊鐖堕儴闂� 鍒欐牎楠屾槸鍚﹀叿鏈夋柊鐖堕儴闂ㄦ潈闄� 閬垮厤瓒婃潈
+            this.checkDeptDataScope(dept.getParentId());
+            SysDept newParentDept = baseMapper.selectById(dept.getParentId());
+            if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
+                String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
+                String oldAncestors = oldDept.getAncestors();
+                dept.setAncestors(newAncestors);
+                updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
+            }
+        }
+        int result = baseMapper.updateById(dept);
+        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+            && !StringUtils.equals(UserConstants.DEPT_NORMAL, dept.getAncestors())) {
+            // 濡傛灉璇ラ儴闂ㄦ槸鍚敤鐘舵�侊紝鍒欏惎鐢ㄨ閮ㄩ棬鐨勬墍鏈変笂绾ч儴闂�
+            updateParentDeptStatusNormal(dept);
+        }
+        return result;
+    }
+
+    /**
+     * 淇敼璇ラ儴闂ㄧ殑鐖剁骇閮ㄩ棬鐘舵��
+     *
+     * @param dept 褰撳墠閮ㄩ棬
+     */
+    private void updateParentDeptStatusNormal(SysDept dept) {
+        String ancestors = dept.getAncestors();
+        Long[] deptIds = Convert.toLongArray(ancestors);
+        baseMapper.update(null, new LambdaUpdateWrapper<SysDept>()
+            .set(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+            .in(SysDept::getDeptId, Arrays.asList(deptIds)));
+    }
+
+    /**
+     * 淇敼瀛愬厓绱犲叧绯�
+     *
+     * @param deptId       琚慨鏀圭殑閮ㄩ棬ID
+     * @param newAncestors 鏂扮殑鐖禝D闆嗗悎
+     * @param oldAncestors 鏃х殑鐖禝D闆嗗悎
+     */
+    private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
+        List<SysDept> children = baseMapper.selectList(new LambdaQueryWrapper<SysDept>()
+            .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+        List<SysDept> list = new ArrayList<>();
+        for (SysDept child : children) {
+            SysDept dept = new SysDept();
+            dept.setDeptId(child.getDeptId());
+            dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
+            list.add(dept);
+        }
+        if (CollUtil.isNotEmpty(list)) {
+            if (baseMapper.updateBatchById(list)) {
+                list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId()));
+            }
+        }
+    }
+
+    /**
+     * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId")
+    @Override
+    public int deleteDeptById(Long deptId) {
+        return baseMapper.deleteById(deptId);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..1ab0faf
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
@@ -0,0 +1,156 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.mapper.SysDictDataMapper;
+import org.dromara.system.service.ISysDictDataService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDictDataServiceImpl implements ISysDictDataService {
+
+    private final SysDictDataMapper baseMapper;
+
+    @Override
+    public TableDataInfo<SysDictDataVo> selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysDictData> lqw = buildQueryWrapper(dictData);
+        Page<SysDictDataVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+     *
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictDataVo> selectDictDataList(SysDictDataBo dictData) {
+        LambdaQueryWrapper<SysDictData> lqw = buildQueryWrapper(dictData);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysDictData> buildQueryWrapper(SysDictDataBo bo) {
+        LambdaQueryWrapper<SysDictData> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getDictSort() != null, SysDictData::getDictSort, bo.getDictSort());
+        lqw.like(StringUtils.isNotBlank(bo.getDictLabel()), SysDictData::getDictLabel, bo.getDictLabel());
+        lqw.eq(StringUtils.isNotBlank(bo.getDictType()), SysDictData::getDictType, bo.getDictType());
+        lqw.orderByAsc(SysDictData::getDictSort);
+        return lqw;
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀閿��
+     * @return 瀛楀吀鏍囩
+     */
+    @Override
+    public String selectDictLabel(String dictType, String dictValue) {
+        return baseMapper.selectOne(new LambdaQueryWrapper<SysDictData>()
+                .select(SysDictData::getDictLabel)
+                .eq(SysDictData::getDictType, dictType)
+                .eq(SysDictData::getDictValue, dictValue))
+            .getDictLabel();
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+     *
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 瀛楀吀鏁版嵁
+     */
+    @Override
+    public SysDictDataVo selectDictDataById(Long dictCode) {
+        return baseMapper.selectVoById(dictCode);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param dictCodes 闇�瑕佸垹闄ょ殑瀛楀吀鏁版嵁ID
+     */
+    @Override
+    public void deleteDictDataByIds(Long[] dictCodes) {
+        for (Long dictCode : dictCodes) {
+            SysDictData data = baseMapper.selectById(dictCode);
+            baseMapper.deleteById(dictCode);
+            CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType());
+        }
+    }
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param bo 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+    @Override
+    public List<SysDictDataVo> insertDictData(SysDictDataBo bo) {
+        SysDictData data = MapstructUtils.convert(bo, SysDictData.class);
+        int row = baseMapper.insert(data);
+        if (row > 0) {
+            return baseMapper.selectDictDataByType(data.getDictType());
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     *
+     * @param bo 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+    @Override
+    public List<SysDictDataVo> updateDictData(SysDictDataBo bo) {
+        SysDictData data = MapstructUtils.convert(bo, SysDictData.class);
+        int row = baseMapper.updateById(data);
+        if (row > 0) {
+            return baseMapper.selectDictDataByType(data.getDictType());
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 鏍¢獙瀛楀吀閿�兼槸鍚﹀敮涓�
+     *
+     * @param dict 瀛楀吀鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkDictDataUnique(SysDictDataBo dict) {
+        Long dictCode = ObjectUtil.isNull(dict.getDictCode()) ? -1L : dict.getDictCode();
+        SysDictData entity = baseMapper.selectOne(new LambdaQueryWrapper<SysDictData>()
+            .eq(SysDictData::getDictType, dict.getDictType()).eq(SysDictData::getDictValue, dict.getDictValue()));
+        if (ObjectUtil.isNotNull(entity) && !dictCode.equals(entity.getDictCode())) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..1be0b7f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
@@ -0,0 +1,258 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.system.domain.SysDictType;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+import org.dromara.system.mapper.SysDictDataMapper;
+import org.dromara.system.mapper.SysDictTypeMapper;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService {
+
+    private final SysDictTypeMapper baseMapper;
+    private final SysDictDataMapper dictDataMapper;
+
+    @Override
+    public TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysDictType> lqw = buildQueryWrapper(dictType);
+        Page<SysDictTypeVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+     *
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictTypeVo> selectDictTypeList(SysDictTypeBo dictType) {
+        LambdaQueryWrapper<SysDictType> lqw = buildQueryWrapper(dictType);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysDictType> buildQueryWrapper(SysDictTypeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SysDictType> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getDictName()), SysDictType::getDictName, bo.getDictName());
+        lqw.like(StringUtils.isNotBlank(bo.getDictType()), SysDictType::getDictType, bo.getDictType());
+        lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
+            SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime"));
+        lqw.orderByAsc(SysDictType::getDictId);
+        return lqw;
+    }
+
+    /**
+     * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+     *
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictTypeVo> selectDictTypeAll() {
+        return baseMapper.selectVoList();
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
+    @Override
+    public List<SysDictDataVo> selectDictDataByType(String dictType) {
+        List<SysDictDataVo> dictDatas = dictDataMapper.selectDictDataByType(dictType);
+        if (CollUtil.isNotEmpty(dictDatas)) {
+            return dictDatas;
+        }
+        return null;
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+     *
+     * @param dictId 瀛楀吀绫诲瀷ID
+     * @return 瀛楀吀绫诲瀷
+     */
+    @Override
+    public SysDictTypeVo selectDictTypeById(Long dictId) {
+        return baseMapper.selectVoById(dictId);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀绫诲瀷
+     */
+    @Override
+    public SysDictTypeVo selectDictTypeByType(String dictType) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictType, dictType));
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎瀛楀吀绫诲瀷淇℃伅
+     *
+     * @param dictIds 闇�瑕佸垹闄ょ殑瀛楀吀ID
+     */
+    @Override
+    public void deleteDictTypeByIds(Long[] dictIds) {
+        for (Long dictId : dictIds) {
+            SysDictType dictType = baseMapper.selectById(dictId);
+            if (dictDataMapper.exists(new LambdaQueryWrapper<SysDictData>()
+                .eq(SysDictData::getDictType, dictType.getDictType()))) {
+                throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", dictType.getDictName()));
+            }
+            CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType());
+        }
+        baseMapper.deleteByIds(Arrays.asList(dictIds));
+    }
+
+    /**
+     * 閲嶇疆瀛楀吀缂撳瓨鏁版嵁
+     */
+    @Override
+    public void resetDictCache() {
+        CacheUtils.clear(CacheNames.SYS_DICT);
+    }
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     *
+     * @param bo 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+    @Override
+    public List<SysDictDataVo> insertDictType(SysDictTypeBo bo) {
+        SysDictType dict = MapstructUtils.convert(bo, SysDictType.class);
+        int row = baseMapper.insert(dict);
+        if (row > 0) {
+            // 鏂板 type 涓嬫棤 data 鏁版嵁 杩斿洖绌洪槻姝㈢紦瀛樼┛閫�
+            return new ArrayList<>();
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     *
+     * @param bo 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public List<SysDictDataVo> updateDictType(SysDictTypeBo bo) {
+        SysDictType dict = MapstructUtils.convert(bo, SysDictType.class);
+        SysDictType oldDict = baseMapper.selectById(dict.getDictId());
+        dictDataMapper.update(null, new LambdaUpdateWrapper<SysDictData>()
+            .set(SysDictData::getDictType, dict.getDictType())
+            .eq(SysDictData::getDictType, oldDict.getDictType()));
+        int row = baseMapper.updateById(dict);
+        if (row > 0) {
+            CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType());
+            return dictDataMapper.selectDictDataByType(dict.getDictType());
+        }
+        throw new ServiceException("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+     *
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkDictTypeUnique(SysDictTypeBo dictType) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDictType>()
+            .eq(SysDictType::getDictType, dictType.getDictType())
+            .ne(ObjectUtil.isNotNull(dictType.getDictId()), SysDictType::getDictId, dictType.getDictId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏稿�艰幏鍙栧瓧鍏告爣绛�
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀鍊�
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鏍囩
+     */
+    @Override
+    public String getDictLabel(String dictType, String dictValue, String separator) {
+        List<SysDictDataVo> datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType);
+        Map<String, String> map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel);
+        if (StringUtils.containsAny(dictValue, separator)) {
+            return Arrays.stream(dictValue.split(separator))
+                .map(v -> map.getOrDefault(v, StringUtils.EMPTY))
+                .collect(Collectors.joining(separator));
+        } else {
+            return map.getOrDefault(dictValue, StringUtils.EMPTY);
+        }
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏告爣绛捐幏鍙栧瓧鍏稿��
+     *
+     * @param dictType  瀛楀吀绫诲瀷
+     * @param dictLabel 瀛楀吀鏍囩
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鍊�
+     */
+    @Override
+    public String getDictValue(String dictType, String dictLabel, String separator) {
+        List<SysDictDataVo> datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType);
+        Map<String, String> map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue);
+        if (StringUtils.containsAny(dictLabel, separator)) {
+            return Arrays.stream(dictLabel.split(separator))
+                .map(l -> map.getOrDefault(l, StringUtils.EMPTY))
+                .collect(Collectors.joining(separator));
+        } else {
+            return map.getOrDefault(dictLabel, StringUtils.EMPTY);
+        }
+    }
+
+    @Override
+    public Map<String, String> getAllDictByDictType(String dictType) {
+        List<SysDictDataVo> list = selectDictDataByType(dictType);
+        return StreamUtils.toMap(list, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
new file mode 100644
index 0000000..b95baf4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
@@ -0,0 +1,176 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ip.AddressUtils;
+import org.dromara.common.log.event.LogininforEvent;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysLogininfor;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+import org.dromara.system.mapper.SysLogininforMapper;
+import org.dromara.system.service.ISysClientService;
+import org.dromara.system.service.ISysLogininforService;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class SysLogininforServiceImpl implements ISysLogininforService {
+
+    private final SysLogininforMapper baseMapper;
+
+    private final ISysClientService clientService;
+
+    /**
+     * 璁板綍鐧诲綍淇℃伅
+     *
+     * @param logininforEvent 鐧诲綍浜嬩欢
+     */
+    @Async
+    @EventListener
+    public void recordLogininfor(LogininforEvent logininforEvent) {
+        HttpServletRequest request = logininforEvent.getRequest();
+        final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
+        final String ip = ServletUtils.getClientIP(request);
+        // 瀹㈡埛绔俊鎭�
+        String clientId = request.getHeader(LoginHelper.CLIENT_KEY);
+        SysClientVo client = null;
+        if (StringUtils.isNotBlank(clientId)) {
+            client = clientService.queryByClientId(clientId);
+        }
+
+        String address = AddressUtils.getRealAddressByIP(ip);
+        StringBuilder s = new StringBuilder();
+        s.append(getBlock(ip));
+        s.append(address);
+        s.append(getBlock(logininforEvent.getUsername()));
+        s.append(getBlock(logininforEvent.getStatus()));
+        s.append(getBlock(logininforEvent.getMessage()));
+        // 鎵撳嵃淇℃伅鍒版棩蹇�
+        log.info(s.toString(), logininforEvent.getArgs());
+        // 鑾峰彇瀹㈡埛绔搷浣滅郴缁�
+        String os = userAgent.getOs().getName();
+        // 鑾峰彇瀹㈡埛绔祻瑙堝櫒
+        String browser = userAgent.getBrowser().getName();
+        // 灏佽瀵硅薄
+        SysLogininforBo logininfor = new SysLogininforBo();
+        logininfor.setTenantId(logininforEvent.getTenantId());
+        logininfor.setUserName(logininforEvent.getUsername());
+        if (ObjectUtil.isNotNull(client)) {
+            logininfor.setClientKey(client.getClientKey());
+            logininfor.setDeviceType(client.getDeviceType());
+        }
+        logininfor.setIpaddr(ip);
+        logininfor.setLoginLocation(address);
+        logininfor.setBrowser(browser);
+        logininfor.setOs(os);
+        logininfor.setMsg(logininforEvent.getMessage());
+        // 鏃ュ織鐘舵��
+        if (StringUtils.equalsAny(logininforEvent.getStatus(), Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) {
+            logininfor.setStatus(Constants.SUCCESS);
+        } else if (Constants.LOGIN_FAIL.equals(logininforEvent.getStatus())) {
+            logininfor.setStatus(Constants.FAIL);
+        }
+        // 鎻掑叆鏁版嵁
+        insertLogininfor(logininfor);
+    }
+
+    private String getBlock(Object msg) {
+        if (msg == null) {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+
+    @Override
+    public TableDataInfo<SysLogininforVo> selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery) {
+        Map<String, Object> params = logininfor.getParams();
+        LambdaQueryWrapper<SysLogininfor> lqw = new LambdaQueryWrapper<SysLogininfor>()
+            .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
+            .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
+            .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"));
+        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
+            pageQuery.setOrderByColumn("info_id");
+            pageQuery.setIsAsc("desc");
+        }
+        Page<SysLogininforVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏂板绯荤粺鐧诲綍鏃ュ織
+     *
+     * @param bo 璁块棶鏃ュ織瀵硅薄
+     */
+    @Override
+    public void insertLogininfor(SysLogininforBo bo) {
+        SysLogininfor logininfor = MapstructUtils.convert(bo, SysLogininfor.class);
+        logininfor.setLoginTime(new Date());
+        baseMapper.insert(logininfor);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+     *
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     * @return 鐧诲綍璁板綍闆嗗悎
+     */
+    @Override
+    public List<SysLogininforVo> selectLogininforList(SysLogininforBo logininfor) {
+        Map<String, Object> params = logininfor.getParams();
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysLogininfor>()
+            .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
+            .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
+            .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"))
+            .orderByDesc(SysLogininfor::getInfoId));
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+     *
+     * @param infoIds 闇�瑕佸垹闄ょ殑鐧诲綍鏃ュ織ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteLogininforByIds(Long[] infoIds) {
+        return baseMapper.deleteByIds(Arrays.asList(infoIds));
+    }
+
+    /**
+     * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+     */
+    @Override
+    public void cleanLogininfor() {
+        baseMapper.delete(new LambdaQueryWrapper<>());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..af844c9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
@@ -0,0 +1,369 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysRoleMenu;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.MetaVo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.dromara.system.mapper.SysMenuMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysRoleMenuMapper;
+import org.dromara.system.mapper.SysTenantPackageMapper;
+import org.dromara.system.service.ISysMenuService;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * 鑿滃崟 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysMenuServiceImpl implements ISysMenuService {
+
+    private final SysMenuMapper baseMapper;
+    private final SysRoleMapper roleMapper;
+    private final SysRoleMenuMapper roleMenuMapper;
+    private final SysTenantPackageMapper tenantPackageMapper;
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenuVo> selectMenuList(Long userId) {
+        return selectMenuList(new SysMenuBo(), userId);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     *
+     * @param menu 鑿滃崟淇℃伅
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId) {
+        List<SysMenuVo> menuList;
+        // 绠$悊鍛樻樉绀烘墍鏈夎彍鍗曚俊鎭�
+        if (LoginHelper.isSuperAdmin(userId)) {
+            menuList = baseMapper.selectVoList(new LambdaQueryWrapper<SysMenu>()
+                .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
+                .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible())
+                .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus())
+                .orderByAsc(SysMenu::getParentId)
+                .orderByAsc(SysMenu::getOrderNum));
+        } else {
+            QueryWrapper<SysMenu> wrapper = Wrappers.query();
+            wrapper.inSql("r.role_id", "select role_id from sys_user_role where user_id = " + userId)
+                .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName())
+                .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible())
+                .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus())
+                .orderByAsc("m.parent_id")
+                .orderByAsc("m.order_num");
+            List<SysMenu> list = baseMapper.selectMenuListByUserId(wrapper);
+            menuList = MapstructUtils.convert(list, SysMenuVo.class);
+        }
+        return menuList;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectMenuPermsByUserId(Long userId) {
+        List<String> perms = baseMapper.selectMenuPermsByUserId(userId);
+        Set<String> permsSet = new HashSet<>();
+        for (String perm : perms) {
+            if (StringUtils.isNotEmpty(perm)) {
+                permsSet.addAll(StringUtils.splitList(perm.trim()));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectMenuPermsByRoleId(Long roleId) {
+        List<String> perms = baseMapper.selectMenuPermsByRoleId(roleId);
+        Set<String> permsSet = new HashSet<>();
+        for (String perm : perms) {
+            if (StringUtils.isNotEmpty(perm)) {
+                permsSet.addAll(StringUtils.splitList(perm.trim()));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     *
+     * @param userId 鐢ㄦ埛鍚嶇О
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuTreeByUserId(Long userId) {
+        List<SysMenu> menus;
+        if (LoginHelper.isSuperAdmin(userId)) {
+            menus = baseMapper.selectMenuTreeAll();
+        } else {
+            menus = baseMapper.selectMenuTreeByUserId(userId);
+        }
+        return getChildPerms(menus, 0);
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<Long> selectMenuListByRoleId(Long roleId) {
+        SysRole role = roleMapper.selectById(roleId);
+        return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly());
+    }
+
+    /**
+     * 鏍规嵁绉熸埛濂楅ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     *
+     * @param packageId 绉熸埛濂楅ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<Long> selectMenuListByPackageId(Long packageId) {
+        SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+        List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+        if (CollUtil.isEmpty(menuIds)) {
+            return List.of();
+        }
+        List<Long> parentIds = null;
+        if (tenantPackage.getMenuCheckStrictly()) {
+            parentIds = baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
+                .select(SysMenu::getParentId)
+                .in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);});
+        }
+        return baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
+            .in(SysMenu::getMenuId, menuIds)
+            .notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);});
+    }
+
+    /**
+     * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+     * 璺敱name鍛藉悕瑙勫垯 path棣栧瓧姣嶈浆澶у啓 + id
+     *
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 璺敱鍒楄〃
+     */
+    @Override
+    public List<RouterVo> buildMenus(List<SysMenu> menus) {
+        List<RouterVo> routers = new LinkedList<>();
+        for (SysMenu menu : menus) {
+            String name = menu.getRouteName() + menu.getMenuId();
+            RouterVo router = new RouterVo();
+            router.setHidden("1".equals(menu.getVisible()));
+            router.setName(name);
+            router.setPath(menu.getRouterPath());
+            router.setComponent(menu.getComponentInfo());
+            router.setQuery(menu.getQueryParam());
+            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+            List<SysMenu> cMenus = menu.getChildren();
+            if (CollUtil.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
+                router.setAlwaysShow(true);
+                router.setRedirect("noRedirect");
+                router.setChildren(buildMenus(cMenus));
+            } else if (menu.isMenuFrame()) {
+                String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId();
+                router.setMeta(null);
+                List<RouterVo> childrenList = new ArrayList<>();
+                RouterVo children = new RouterVo();
+                children.setPath(menu.getPath());
+                children.setComponent(menu.getComponent());
+                children.setName(frameName);
+                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+                children.setQuery(menu.getQueryParam());
+                childrenList.add(children);
+                router.setChildren(childrenList);
+            } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) {
+                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+                router.setPath("/");
+                List<RouterVo> childrenList = new ArrayList<>();
+                RouterVo children = new RouterVo();
+                String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath());
+                String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId();
+                children.setPath(routerPath);
+                children.setComponent(UserConstants.INNER_LINK);
+                children.setName(innerLinkName);
+                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
+                childrenList.add(children);
+                router.setChildren(childrenList);
+            }
+            routers.add(router);
+        }
+        return routers;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuVo> menus) {
+        if (CollUtil.isEmpty(menus)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeBuildUtils.build(menus, (menu, tree) ->
+            tree.setId(menu.getMenuId())
+                .setParentId(menu.getParentId())
+                .setName(menu.getMenuName())
+                .setWeight(menu.getOrderNum()));
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    @Override
+    public SysMenuVo selectMenuById(Long menuId) {
+        return baseMapper.selectVoById(menuId);
+    }
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByMenuId(Long menuId) {
+        return baseMapper.exists(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, menuId));
+    }
+
+    /**
+     * 鏌ヨ鑿滃崟浣跨敤鏁伴噺
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkMenuExistRole(Long menuId) {
+        return roleMenuMapper.exists(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
+    }
+
+    /**
+     * 鏂板淇濆瓨鑿滃崟淇℃伅
+     *
+     * @param bo 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertMenu(SysMenuBo bo) {
+        SysMenu menu = MapstructUtils.convert(bo, SysMenu.class);
+        return baseMapper.insert(menu);
+    }
+
+    /**
+     * 淇敼淇濆瓨鑿滃崟淇℃伅
+     *
+     * @param bo 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateMenu(SysMenuBo bo) {
+        SysMenu menu = MapstructUtils.convert(bo, SysMenu.class);
+        return baseMapper.updateById(menu);
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     *
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteMenuById(Long menuId) {
+        return baseMapper.deleteById(menuId);
+    }
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     *
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkMenuNameUnique(SysMenuBo menu) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysMenu>()
+            .eq(SysMenu::getMenuName, menu.getMenuName())
+            .eq(SysMenu::getParentId, menu.getParentId())
+            .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenu::getMenuId, menu.getMenuId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍规嵁鐖惰妭鐐圭殑ID鑾峰彇鎵�鏈夊瓙鑺傜偣
+     *
+     * @param list     鍒嗙被琛�
+     * @param parentId 浼犲叆鐨勭埗鑺傜偣ID
+     * @return String
+     */
+    private List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) {
+        List<SysMenu> returnList = new ArrayList<>();
+        for (SysMenu t : list) {
+            // 涓�銆佹牴鎹紶鍏ョ殑鏌愪釜鐖惰妭鐐笽D,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (t.getParentId() == parentId) {
+                recursionFn(list, t);
+                returnList.add(t);
+            }
+        }
+        return returnList;
+    }
+
+    /**
+     * 閫掑綊鍒楄〃
+     */
+    private void recursionFn(List<SysMenu> list, SysMenu t) {
+        // 寰楀埌瀛愯妭鐐瑰垪琛�
+        List<SysMenu> childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId()));
+        t.setChildren(childList);
+        for (SysMenu tChild : childList) {
+            // 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+            if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) {
+                recursionFn(list, tChild);
+            }
+        }
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
new file mode 100644
index 0000000..db63e61
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
@@ -0,0 +1,124 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysNotice;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysNoticeMapper;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysNoticeService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 鍏憡 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysNoticeServiceImpl implements ISysNoticeService {
+
+    private final SysNoticeMapper baseMapper;
+    private final SysUserMapper userMapper;
+
+    @Override
+    public TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);
+        Page<SysNoticeVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ鍏憡淇℃伅
+     *
+     * @param noticeId 鍏憡ID
+     * @return 鍏憡淇℃伅
+     */
+    @Override
+    public SysNoticeVo selectNoticeById(Long noticeId) {
+        return baseMapper.selectVoById(noticeId);
+    }
+
+    /**
+     * 鏌ヨ鍏憡鍒楄〃
+     *
+     * @param notice 鍏憡淇℃伅
+     * @return 鍏憡闆嗗悎
+     */
+    @Override
+    public List<SysNoticeVo> selectNoticeList(SysNoticeBo notice) {
+        LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysNotice> buildQueryWrapper(SysNoticeBo bo) {
+        LambdaQueryWrapper<SysNotice> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle());
+        lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType());
+        if (StringUtils.isNotBlank(bo.getCreateByName())) {
+            SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, bo.getCreateByName()));
+            lqw.eq(SysNotice::getCreateBy, ObjectUtil.isNotNull(sysUser) ? sysUser.getUserId() : null);
+        }
+        lqw.orderByAsc(SysNotice::getNoticeId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板鍏憡
+     *
+     * @param bo 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertNotice(SysNoticeBo bo) {
+        SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);
+        return baseMapper.insert(notice);
+    }
+
+    /**
+     * 淇敼鍏憡
+     *
+     * @param bo 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateNotice(SysNoticeBo bo) {
+        SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);
+        return baseMapper.updateById(notice);
+    }
+
+    /**
+     * 鍒犻櫎鍏憡瀵硅薄
+     *
+     * @param noticeId 鍏憡ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteNoticeById(Long noticeId) {
+        return baseMapper.deleteById(noticeId);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鍏憡淇℃伅
+     *
+     * @param noticeIds 闇�瑕佸垹闄ょ殑鍏憡ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteNoticeByIds(Long[] noticeIds) {
+        return baseMapper.deleteByIds(Arrays.asList(noticeIds));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
new file mode 100644
index 0000000..b78b9dc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
@@ -0,0 +1,146 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ip.AddressUtils;
+import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.system.domain.SysOperLog;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+import org.dromara.system.mapper.SysOperLogMapper;
+import org.dromara.system.service.ISysOperLogService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysOperLogServiceImpl implements ISysOperLogService {
+
+    private final SysOperLogMapper baseMapper;
+
+    /**
+     * 鎿嶄綔鏃ュ織璁板綍
+     *
+     * @param operLogEvent 鎿嶄綔鏃ュ織浜嬩欢
+     */
+    @Async
+    @EventListener
+    public void recordOper(OperLogEvent operLogEvent) {
+        SysOperLogBo operLog = MapstructUtils.convert(operLogEvent, SysOperLogBo.class);
+        // 杩滅▼鏌ヨ鎿嶄綔鍦扮偣
+        operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
+        insertOperlog(operLog);
+    }
+
+    @Override
+    public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) {
+        Map<String, Object> params = operLog.getParams();
+        LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
+            .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
+            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
+            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
+                SysOperLog::getBusinessType, operLog.getBusinessType())
+            .func(f -> {
+                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
+                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
+                }
+            })
+            .eq(operLog.getStatus() != null,
+                SysOperLog::getStatus, operLog.getStatus())
+            .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
+        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
+            pageQuery.setOrderByColumn("oper_id");
+            pageQuery.setIsAsc("desc");
+        }
+        Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏂板鎿嶄綔鏃ュ織
+     *
+     * @param bo 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    @Override
+    public void insertOperlog(SysOperLogBo bo) {
+        SysOperLog operLog = MapstructUtils.convert(bo, SysOperLog.class);
+        operLog.setOperTime(new Date());
+        baseMapper.insert(operLog);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+     *
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     * @return 鎿嶄綔鏃ュ織闆嗗悎
+     */
+    @Override
+    public List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog) {
+        Map<String, Object> params = operLog.getParams();
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysOperLog>()
+            .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
+            .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
+            .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
+                SysOperLog::getBusinessType, operLog.getBusinessType())
+            .func(f -> {
+                if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
+                    f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
+                }
+            })
+            .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
+                SysOperLog::getStatus, operLog.getStatus())
+            .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"))
+            .orderByDesc(SysOperLog::getOperId));
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+     *
+     * @param operIds 闇�瑕佸垹闄ょ殑鎿嶄綔鏃ュ織ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteOperLogByIds(Long[] operIds) {
+        return baseMapper.deleteByIds(Arrays.asList(operIds));
+    }
+
+    /**
+     * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+     *
+     * @param operId 鎿嶄綔ID
+     * @return 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    @Override
+    public SysOperLogVo selectOperLogById(Long operId) {
+        return baseMapper.selectVoById(operId);
+    }
+
+    /**
+     * 娓呯┖鎿嶄綔鏃ュ織
+     */
+    @Override
+    public void cleanOperLog() {
+        baseMapper.delete(new LambdaQueryWrapper<>());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
new file mode 100644
index 0000000..a1eefce
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java
@@ -0,0 +1,176 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.oss.constant.OssConstant;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.system.domain.SysOssConfig;
+import org.dromara.system.domain.bo.SysOssConfigBo;
+import org.dromara.system.domain.vo.SysOssConfigVo;
+import org.dromara.system.mapper.SysOssConfigMapper;
+import org.dromara.system.service.ISysOssConfigService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Service涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysOssConfigServiceImpl implements ISysOssConfigService {
+
+    private final SysOssConfigMapper baseMapper;
+
+    /**
+     * 椤圭洰鍚姩鏃讹紝鍒濆鍖栧弬鏁板埌缂撳瓨锛屽姞杞介厤缃被
+     */
+    @Override
+    public void init() {
+        List<SysOssConfig> list = baseMapper.selectList();
+        // 鍔犺浇OSS鍒濆鍖栭厤缃�
+        for (SysOssConfig config : list) {
+            String configKey = config.getConfigKey();
+            if ("0".equals(config.getStatus())) {
+                RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);
+            }
+            CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+        }
+    }
+
+    @Override
+    public SysOssConfigVo queryById(Long ossConfigId) {
+        return baseMapper.selectVoById(ossConfigId);
+    }
+
+    @Override
+    public TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysOssConfig> lqw = buildQueryWrapper(bo);
+        Page<SysOssConfigVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+
+    private LambdaQueryWrapper<SysOssConfig> buildQueryWrapper(SysOssConfigBo bo) {
+        LambdaQueryWrapper<SysOssConfig> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getConfigKey()), SysOssConfig::getConfigKey, bo.getConfigKey());
+        lqw.like(StringUtils.isNotBlank(bo.getBucketName()), SysOssConfig::getBucketName, bo.getBucketName());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysOssConfig::getStatus, bo.getStatus());
+        lqw.orderByAsc(SysOssConfig::getOssConfigId);
+        return lqw;
+    }
+
+    @Override
+    public Boolean insertByBo(SysOssConfigBo bo) {
+        SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class);
+        validEntityBeforeSave(config);
+        boolean flag = baseMapper.insert(config) > 0;
+        if (flag) {
+            // 浠庢暟鎹簱鏌ヨ瀹屾暣鐨勬暟鎹仛缂撳瓨
+            config = baseMapper.selectById(config.getOssConfigId());
+            CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+        }
+        return flag;
+    }
+
+    @Override
+    public Boolean updateByBo(SysOssConfigBo bo) {
+        SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class);
+        validEntityBeforeSave(config);
+        LambdaUpdateWrapper<SysOssConfig> luw = new LambdaUpdateWrapper<>();
+        luw.set(ObjectUtil.isNull(config.getPrefix()), SysOssConfig::getPrefix, "");
+        luw.set(ObjectUtil.isNull(config.getRegion()), SysOssConfig::getRegion, "");
+        luw.set(ObjectUtil.isNull(config.getExt1()), SysOssConfig::getExt1, "");
+        luw.set(ObjectUtil.isNull(config.getRemark()), SysOssConfig::getRemark, "");
+        luw.eq(SysOssConfig::getOssConfigId, config.getOssConfigId());
+        boolean flag = baseMapper.update(config, luw) > 0;
+        if (flag) {
+            // 浠庢暟鎹簱鏌ヨ瀹屾暣鐨勬暟鎹仛缂撳瓨
+            config = baseMapper.selectById(config.getOssConfigId());
+            CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+        }
+        return flag;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysOssConfig entity) {
+        if (StringUtils.isNotEmpty(entity.getConfigKey())
+            && !checkConfigKeyUnique(entity)) {
+            throw new ServiceException("鎿嶄綔閰嶇疆'" + entity.getConfigKey() + "'澶辫触, 閰嶇疆key宸插瓨鍦�!");
+        }
+    }
+
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) {
+                throw new ServiceException("绯荤粺鍐呯疆, 涓嶅彲鍒犻櫎!");
+            }
+        }
+        List<SysOssConfig> list = CollUtil.newArrayList();
+        for (Long configId : ids) {
+            SysOssConfig config = baseMapper.selectById(configId);
+            list.add(config);
+        }
+        boolean flag = baseMapper.deleteByIds(ids) > 0;
+        if (flag) {
+            list.forEach(sysOssConfig ->
+                CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, sysOssConfig.getConfigKey()));
+        }
+        return flag;
+    }
+
+    /**
+     * 鍒ゆ柇configKey鏄惁鍞竴
+     */
+    private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) {
+        long ossConfigId = ObjectUtil.isNull(sysOssConfig.getOssConfigId()) ? -1L : sysOssConfig.getOssConfigId();
+        SysOssConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysOssConfig>()
+            .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey)
+            .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey()));
+        if (ObjectUtil.isNotNull(info) && info.getOssConfigId() != ossConfigId) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 鍚敤绂佺敤鐘舵��
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateOssConfigStatus(SysOssConfigBo bo) {
+        SysOssConfig sysOssConfig = MapstructUtils.convert(bo, SysOssConfig.class);
+        int row = baseMapper.update(null, new LambdaUpdateWrapper<SysOssConfig>()
+            .set(SysOssConfig::getStatus, "1"));
+        row += baseMapper.updateById(sysOssConfig);
+        if (row > 0) {
+            RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, sysOssConfig.getConfigKey());
+        }
+        return row;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
new file mode 100644
index 0000000..1866531
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
@@ -0,0 +1,269 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.domain.dto.OssDTO;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.OssService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.oss.core.OssClient;
+import org.dromara.common.oss.entity.UploadResult;
+import org.dromara.common.oss.enumd.AccessPolicyType;
+import org.dromara.common.oss.factory.OssFactory;
+import org.dromara.system.domain.SysOss;
+import org.dromara.system.domain.bo.SysOssBo;
+import org.dromara.system.domain.vo.SysOssVo;
+import org.dromara.system.mapper.SysOssMapper;
+import org.dromara.system.service.ISysOssService;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鏂囦欢涓婁紶 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysOssServiceImpl implements ISysOssService, OssService {
+
+    private final SysOssMapper baseMapper;
+
+    /**
+     * 鏌ヨOSS瀵硅薄瀛樺偍鍒楄〃
+     *
+     * @param bo        OSS瀵硅薄瀛樺偍鍒嗛〉鏌ヨ瀵硅薄
+     * @param pageQuery 鍒嗛〉鏌ヨ瀹炰綋绫�
+     * @return 缁撴灉
+     */
+    @Override
+    public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysOss> lqw = buildQueryWrapper(bo);
+        Page<SysOssVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        List<SysOssVo> filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl);
+        result.setRecords(filterResult);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏍规嵁涓�缁� ossIds 鑾峰彇瀵瑰簲鐨� SysOssVo 鍒楄〃
+     *
+     * @param ossIds 涓�缁勬枃浠跺湪鏁版嵁搴撲腑鐨勫敮涓�鏍囪瘑闆嗗悎
+     * @return 鍖呭惈 SysOssVo 瀵硅薄鐨勫垪琛�
+     */
+    @Override
+    public List<SysOssVo> listByIds(Collection<Long> ossIds) {
+        List<SysOssVo> list = new ArrayList<>();
+        SysOssServiceImpl ossService = SpringUtils.getAopProxy(this);
+        for (Long id : ossIds) {
+            SysOssVo vo = ossService.getById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                try {
+                    list.add(this.matchingUrl(vo));
+                } catch (Exception ignored) {
+                    // 濡傛灉oss寮傚父鏃犳硶杩炴帴鍒欏皢鏁版嵁鐩存帴杩斿洖
+                    list.add(vo);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 鏍规嵁涓�缁� ossIds 鑾峰彇瀵瑰簲鏂囦欢鐨� URL 鍒楄〃
+     *
+     * @param ossIds 浠ラ�楀彿鍒嗛殧鐨� ossId 瀛楃涓�
+     * @return 浠ラ�楀彿鍒嗛殧鐨勬枃浠� URL 瀛楃涓�
+     */
+    @Override
+    public String selectUrlByIds(String ossIds) {
+        List<String> list = new ArrayList<>();
+        SysOssServiceImpl ossService = SpringUtils.getAopProxy(this);
+        for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
+            SysOssVo vo = ossService.getById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                try {
+                    list.add(this.matchingUrl(vo).getUrl());
+                } catch (Exception ignored) {
+                    // 濡傛灉oss寮傚父鏃犳硶杩炴帴鍒欏皢鏁版嵁鐩存帴杩斿洖
+                    list.add(vo.getUrl());
+                }
+            }
+        }
+        return String.join(StringUtils.SEPARATOR, list);
+    }
+
+    @Override
+    public List<OssDTO> selectByIds(String ossIds) {
+        List<OssDTO> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
+            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                try {
+                    vo.setUrl(this.matchingUrl(vo).getUrl());
+                    list.add(BeanUtil.toBean(vo, OssDTO.class));
+                } catch (Exception ignored) {
+                    // 濡傛灉oss寮傚父鏃犳硶杩炴帴鍒欏皢鏁版嵁鐩存帴杩斿洖
+                    list.add(BeanUtil.toBean(vo, OssDTO.class));
+                }
+            }
+        }
+        return list;
+    }
+
+    private LambdaQueryWrapper<SysOss> buildQueryWrapper(SysOssBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<SysOss> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName());
+        lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName());
+        lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix());
+        lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl());
+        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
+            SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
+        lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy());
+        lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService());
+        lqw.orderByAsc(SysOss::getOssId);
+        return lqw;
+    }
+
+    /**
+     * 鏍规嵁 ossId 浠庣紦瀛樻垨鏁版嵁搴撲腑鑾峰彇 SysOssVo 瀵硅薄
+     *
+     * @param ossId 鏂囦欢鍦ㄦ暟鎹簱涓殑鍞竴鏍囪瘑
+     * @return SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
+    @Override
+    public SysOssVo getById(Long ossId) {
+        return baseMapper.selectVoById(ossId);
+    }
+
+
+    /**
+     * 鏂囦欢涓嬭浇鏂规硶锛屾敮鎸佷竴娆℃�т笅杞藉畬鏁存枃浠�
+     *
+     * @param ossId    OSS瀵硅薄ID
+     * @param response HttpServletResponse瀵硅薄锛岀敤浜庤缃搷搴斿ご鍜屽悜瀹㈡埛绔彂閫佹枃浠跺唴瀹�
+     */
+    @Override
+    public void download(Long ossId, HttpServletResponse response) throws IOException {
+        SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId);
+        if (ObjectUtil.isNull(sysOss)) {
+            throw new ServiceException("鏂囦欢鏁版嵁涓嶅瓨鍦�!");
+        }
+        FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
+        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
+        OssClient storage = OssFactory.instance(sysOss.getService());
+        long contentLength = storage.download(sysOss.getFileName(), response.getOutputStream());
+        response.setContentLengthLong(contentLength);
+    }
+
+    /**
+     * 涓婁紶 MultipartFile 鍒板璞″瓨鍌ㄦ湇鍔★紝骞朵繚瀛樻枃浠朵俊鎭埌鏁版嵁搴�
+     *
+     * @param file 瑕佷笂浼犵殑 MultipartFile 瀵硅薄
+     * @return 涓婁紶鎴愬姛鍚庣殑 SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     * @throws ServiceException 濡傛灉涓婁紶杩囩▼涓彂鐢熷紓甯革紝鍒欐姏鍑� ServiceException 寮傚父
+     */
+    @Override
+    public SysOssVo upload(MultipartFile file) {
+        String originalfileName = file.getOriginalFilename();
+        String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+        OssClient storage = OssFactory.instance();
+        UploadResult uploadResult;
+        try {
+            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
+        } catch (IOException e) {
+            throw new ServiceException(e.getMessage());
+        }
+        // 淇濆瓨鏂囦欢淇℃伅
+        return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult);
+    }
+
+    /**
+     * 涓婁紶鏂囦欢鍒板璞″瓨鍌ㄦ湇鍔★紝骞朵繚瀛樻枃浠朵俊鎭埌鏁版嵁搴�
+     *
+     * @param file 瑕佷笂浼犵殑鏂囦欢瀵硅薄
+     * @return 涓婁紶鎴愬姛鍚庣殑 SysOssVo 瀵硅薄锛屽寘鍚枃浠朵俊鎭�
+     */
+    @Override
+    public SysOssVo upload(File file) {
+        String originalfileName = file.getName();
+        String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+        OssClient storage = OssFactory.instance();
+        UploadResult uploadResult = storage.uploadSuffix(file, suffix);
+        // 淇濆瓨鏂囦欢淇℃伅
+        return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult);
+    }
+
+    @NotNull
+    private SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, UploadResult uploadResult) {
+        SysOss oss = new SysOss();
+        oss.setUrl(uploadResult.getUrl());
+        oss.setFileSuffix(suffix);
+        oss.setFileName(uploadResult.getFilename());
+        oss.setOriginalName(originalfileName);
+        oss.setService(configKey);
+        baseMapper.insert(oss);
+        SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class);
+        return this.matchingUrl(sysOssVo);
+    }
+
+    /**
+     * 鍒犻櫎OSS瀵硅薄瀛樺偍
+     *
+     * @param ids     OSS瀵硅薄ID涓�
+     * @param isValid 鍒ゆ柇鏄惁闇�瑕佹牎楠�
+     * @return 缁撴灉
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        List<SysOss> list = baseMapper.selectBatchIds(ids);
+        for (SysOss sysOss : list) {
+            OssClient storage = OssFactory.instance(sysOss.getService());
+            storage.delete(sysOss.getUrl());
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    /**
+     * 妗剁被鍨嬩负 private 鐨刄RL 淇敼涓轰复鏃禪RL鏃堕暱涓�120s
+     *
+     * @param oss OSS瀵硅薄
+     * @return oss 鍖归厤Url鐨凮SS瀵硅薄
+     */
+    private SysOssVo matchingUrl(SysOssVo oss) {
+        OssClient storage = OssFactory.instance(oss.getService());
+        // 浠呬慨鏀规《绫诲瀷涓� private 鐨刄RL锛屼复鏃禪RL鏃堕暱涓�120s
+        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
+            oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120));
+        }
+        return oss;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java
new file mode 100644
index 0000000..9852821
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java
@@ -0,0 +1,61 @@
+package org.dromara.system.service.impl;
+
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.service.ISysMenuService;
+import org.dromara.system.service.ISysPermissionService;
+import org.dromara.system.service.ISysRoleService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 鐢ㄦ埛鏉冮檺澶勭悊
+ *
+ * @author ruoyi
+ */
+@RequiredArgsConstructor
+@Service
+public class SysPermissionServiceImpl implements ISysPermissionService {
+
+    private final ISysRoleService roleService;
+    private final ISysMenuService menuService;
+
+    /**
+     * 鑾峰彇瑙掕壊鏁版嵁鏉冮檺
+     *
+     * @param userId  鐢ㄦ埛id
+     * @return 瑙掕壊鏉冮檺淇℃伅
+     */
+    @Override
+    public Set<String> getRolePermission(Long userId) {
+        Set<String> roles = new HashSet<>();
+        // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+        if (LoginHelper.isSuperAdmin(userId)) {
+            roles.add(TenantConstants.SUPER_ADMIN_ROLE_KEY);
+        } else {
+            roles.addAll(roleService.selectRolePermissionByUserId(userId));
+        }
+        return roles;
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟鏁版嵁鏉冮檺
+     *
+     * @param userId  鐢ㄦ埛id
+     * @return 鑿滃崟鏉冮檺淇℃伅
+     */
+    @Override
+    public Set<String> getMenuPermission(Long userId) {
+        Set<String> perms = new HashSet<>();
+        // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+        if (LoginHelper.isSuperAdmin(userId)) {
+            perms.add("*:*:*");
+        } else {
+            perms.addAll(menuService.selectMenuPermsByUserId(userId));
+        }
+        return perms;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
new file mode 100644
index 0000000..2c38129
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -0,0 +1,242 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.SysUserPost;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysPostMapper;
+import org.dromara.system.mapper.SysUserPostMapper;
+import org.dromara.system.service.ISysPostService;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysPostServiceImpl implements ISysPostService {
+
+    private final SysPostMapper baseMapper;
+    private final SysDeptMapper deptMapper;
+    private final SysUserPostMapper userPostMapper;
+
+    @Override
+    public TableDataInfo<SysPostVo> selectPagePostList(SysPostBo post, PageQuery pageQuery) {
+        Page<SysPostVo> page = baseMapper.selectPagePostList(pageQuery.build(), buildQueryWrapper(post));
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 宀椾綅淇℃伅闆嗗悎
+     */
+    @Override
+    public List<SysPostVo> selectPostList(SysPostBo post) {
+        return baseMapper.selectVoList(buildQueryWrapper(post));
+    }
+
+    /**
+     * 鏍规嵁鏌ヨ鏉′欢鏋勫缓鏌ヨ鍖呰鍣�
+     *
+     * @param bo 鏌ヨ鏉′欢瀵硅薄
+     * @return 鏋勫缓濂界殑鏌ヨ鍖呰鍣�
+     */
+    private LambdaQueryWrapper<SysPost> buildQueryWrapper(SysPostBo bo) {
+        LambdaQueryWrapper<SysPost> wrapper = new LambdaQueryWrapper<>();
+        wrapper.like(StringUtils.isNotBlank(bo.getPostCode()), SysPost::getPostCode, bo.getPostCode())
+            .like(StringUtils.isNotBlank(bo.getPostCategory()), SysPost::getPostCategory, bo.getPostCategory())
+            .like(StringUtils.isNotBlank(bo.getPostName()), SysPost::getPostName, bo.getPostName())
+            .eq(StringUtils.isNotBlank(bo.getStatus()), SysPost::getStatus, bo.getStatus())
+            .orderByAsc(SysPost::getPostSort);
+        if (ObjectUtil.isNotNull(bo.getDeptId())) {
+            //浼樺厛鍗曢儴闂ㄦ悳绱�
+            wrapper.eq(SysPost::getDeptId, bo.getDeptId());
+        } else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) {
+            //閮ㄩ棬鏍戞悳绱�
+            wrapper.and(x -> {
+                List<Long> deptIds = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
+                        .select(SysDept::getDeptId)
+                        .apply(DataBaseHelper.findInSet(bo.getBelongDeptId(), "ancestors")))
+                    .stream()
+                    .map(SysDept::getDeptId)
+                    .collect(Collectors.toList());
+                deptIds.add(bo.getBelongDeptId());
+                x.in(SysPost::getDeptId, deptIds);
+            });
+        }
+        return wrapper;
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夊矖浣�
+     *
+     * @return 宀椾綅鍒楄〃
+     */
+    @Override
+    public List<SysPostVo> selectPostAll() {
+        return baseMapper.selectVoList(new QueryWrapper<>());
+    }
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+     *
+     * @param postId 宀椾綅ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    @Override
+    public SysPostVo selectPostById(Long postId) {
+        return baseMapper.selectVoById(postId);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑宀椾綅ID鍒楄〃
+     */
+    @Override
+    public List<Long> selectPostListByUserId(Long userId) {
+        List<SysPostVo> list = baseMapper.selectPostsByUserId(userId);
+        return StreamUtils.toList(list, SysPostVo::getPostId);
+    }
+
+    /**
+     * 閫氳繃宀椾綅ID涓叉煡璇㈠矖浣�
+     *
+     * @param postIds 宀椾綅id涓�
+     * @return 宀椾綅鍒楄〃淇℃伅
+     */
+    @Override
+    public List<SysPostVo> selectPostByIds(List<Long> postIds) {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysPost>()
+            .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode)
+            .eq(SysPost::getStatus, UserConstants.POST_NORMAL)
+            .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds));
+    }
+
+    /**
+     * 鏍¢獙宀椾綅鍚嶇О鏄惁鍞竴
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkPostNameUnique(SysPostBo post) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysPost>()
+            .eq(SysPost::getPostName, post.getPostName())
+            .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙宀椾綅缂栫爜鏄惁鍞竴
+     *
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkPostCodeUnique(SysPostBo post) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysPost>()
+            .eq(SysPost::getPostCode, post.getPostCode())
+            .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId()));
+        return !exist;
+    }
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    @Override
+    public long countUserPostById(Long postId) {
+        return userPostMapper.selectCount(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getPostId, postId));
+    }
+
+    /**
+     * 閫氳繃閮ㄩ棬ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     *
+     * @param deptId 閮ㄩ棬id
+     * @return 缁撴灉
+     */
+    @Override
+    public long countPostByDeptId(Long deptId) {
+        return baseMapper.selectCount(new LambdaQueryWrapper<SysPost>().eq(SysPost::getDeptId, deptId));
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅淇℃伅
+     *
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deletePostById(Long postId) {
+        return baseMapper.deleteById(postId);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎宀椾綅淇℃伅
+     *
+     * @param postIds 闇�瑕佸垹闄ょ殑宀椾綅ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deletePostByIds(Long[] postIds) {
+        for (Long postId : postIds) {
+            SysPost post = baseMapper.selectById(postId);
+            if (countUserPostById(postId) > 0) {
+                throw new ServiceException(String.format("%1$s宸插垎閰嶏紝涓嶈兘鍒犻櫎!", post.getPostName()));
+            }
+        }
+        return baseMapper.deleteByIds(Arrays.asList(postIds));
+    }
+
+    /**
+     * 鏂板淇濆瓨宀椾綅淇℃伅
+     *
+     * @param bo 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertPost(SysPostBo bo) {
+        SysPost post = MapstructUtils.convert(bo, SysPost.class);
+        return baseMapper.insert(post);
+    }
+
+    /**
+     * 淇敼淇濆瓨宀椾綅淇℃伅
+     *
+     * @param bo 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updatePost(SysPostBo bo) {
+        SysPost post = MapstructUtils.convert(bo, SysPost.class);
+        return baseMapper.updateById(post);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..9b8b0ec
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -0,0 +1,514 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysRoleDept;
+import org.dromara.system.domain.SysRoleMenu;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.mapper.SysRoleDeptMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysRoleMenuMapper;
+import org.dromara.system.mapper.SysUserRoleMapper;
+import org.dromara.system.service.ISysRoleService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+/**
+ * 瑙掕壊 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysRoleServiceImpl implements ISysRoleService {
+
+    private final SysRoleMapper baseMapper;
+    private final SysRoleMenuMapper roleMenuMapper;
+    private final SysUserRoleMapper userRoleMapper;
+    private final SysRoleDeptMapper roleDeptMapper;
+
+    @Override
+    public TableDataInfo<SysRoleVo> selectPageRoleList(SysRoleBo role, PageQuery pageQuery) {
+        Page<SysRoleVo> page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role));
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysRoleVo> selectRoleList(SysRoleBo role) {
+        return baseMapper.selectRoleList(this.buildQueryWrapper(role));
+    }
+
+    private Wrapper<SysRole> buildQueryWrapper(SysRoleBo bo) {
+        Map<String, Object> params = bo.getParams();
+        QueryWrapper<SysRole> wrapper = Wrappers.query();
+        wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL)
+            .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId())
+            .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName())
+            .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus())
+            .like(StringUtils.isNotBlank(bo.getRoleKey()), "r.role_key", bo.getRoleKey())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                "r.create_time", params.get("beginTime"), params.get("endTime"))
+            .orderByAsc("r.role_sort").orderByAsc("r.create_time");
+        return wrapper;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    @Override
+    public List<SysRoleVo> selectRolesByUserId(Long userId) {
+        return baseMapper.selectRolesByUserId(userId);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃(鍖呭惈琚巿鏉冪姸鎬�)
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    @Override
+    public List<SysRoleVo> selectRolesAuthByUserId(Long userId) {
+        List<SysRoleVo> userRoles = baseMapper.selectRolesByUserId(userId);
+        List<SysRoleVo> roles = selectRoleAll();
+        // 浣跨敤HashSet鎻愰珮鏌ユ壘鏁堢巼
+        Set<Long> userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId);
+        for (SysRoleVo role : roles) {
+            if (userRoleIds.contains(role.getRoleId())) {
+                role.setFlag(true);
+            }
+        }
+        return roles;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectRolePermissionByUserId(Long userId) {
+        List<SysRoleVo> perms = baseMapper.selectRolesByUserId(userId);
+        Set<String> permsSet = new HashSet<>();
+        for (SysRoleVo perm : perms) {
+            if (ObjectUtil.isNotNull(perm)) {
+                permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim()));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夎鑹�
+     *
+     * @return 瑙掕壊鍒楄〃
+     */
+    @Override
+    public List<SysRoleVo> selectRoleAll() {
+        return this.selectRoleList(new SysRoleBo());
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑瑙掕壊ID鍒楄〃
+     */
+    @Override
+    public List<Long> selectRoleListByUserId(Long userId) {
+        List<SysRoleVo> list = baseMapper.selectRolesByUserId(userId);
+        return StreamUtils.toList(list, SysRoleVo::getRoleId);
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    @Override
+    public SysRoleVo selectRoleById(Long roleId) {
+        return baseMapper.selectRoleById(roleId);
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID涓叉煡璇㈣鑹�
+     *
+     * @param roleIds 瑙掕壊ID涓�
+     * @return 瑙掕壊鍒楄〃淇℃伅
+     */
+    @Override
+    public List<SysRoleVo> selectRoleByIds(List<Long> roleIds) {
+        return baseMapper.selectRoleList(new QueryWrapper<SysRole>()
+            .eq("r.status", UserConstants.ROLE_NORMAL)
+            .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds));
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkRoleNameUnique(SysRoleBo role) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysRole>()
+            .eq(SysRole::getRoleName, role.getRoleName())
+            .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+     *
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkRoleKeyUnique(SysRoleBo role) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysRole>()
+            .eq(SysRole::getRoleKey, role.getRoleKey())
+            .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+     *
+     * @param role 瑙掕壊淇℃伅
+     */
+    @Override
+    public void checkRoleAllowed(SysRoleBo role) {
+        if (ObjectUtil.isNotNull(role.getRoleId()) && LoginHelper.isSuperAdmin(role.getRoleId())) {
+            throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
+        }
+        String[] keys = new String[]{TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY};
+        // 鏂板涓嶅厑璁镐娇鐢� 绠$悊鍛樻爣璇嗙
+        if (ObjectUtil.isNull(role.getRoleId())
+            && StringUtils.equalsAny(role.getRoleKey(), keys)) {
+            throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+        }
+        // 淇敼涓嶅厑璁镐慨鏀� 绠$悊鍛樻爣璇嗙
+        if (ObjectUtil.isNotNull(role.getRoleId())) {
+            SysRole sysRole = baseMapper.selectById(role.getRoleId());
+            // 濡傛灉鏍囪瘑绗︿笉鐩哥瓑 鍒ゆ柇涓轰慨鏀逛簡绠$悊鍛樻爣璇嗙
+            if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) {
+                if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) {
+                    throw new ServiceException("涓嶅厑璁镐慨鏀圭郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+                } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) {
+                    throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+                }
+            }
+        }
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param roleId 瑙掕壊id
+     */
+    @Override
+    public void checkRoleDataScope(Long roleId) {
+        if (ObjectUtil.isNull(roleId)) {
+            return;
+        }
+        if (LoginHelper.isSuperAdmin()) {
+            return;
+        }
+        List<SysRoleVo> roles = this.selectRoleList(new SysRoleBo(roleId));
+        if (CollUtil.isEmpty(roles)) {
+            throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鏁版嵁锛�");
+        }
+
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    @Override
+    public long countUserRoleByRoleId(Long roleId) {
+        return userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
+    }
+
+    /**
+     * 鏂板淇濆瓨瑙掕壊淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int insertRole(SysRoleBo bo) {
+        SysRole role = MapstructUtils.convert(bo, SysRole.class);
+        // 鏂板瑙掕壊淇℃伅
+        baseMapper.insert(role);
+        bo.setRoleId(role.getRoleId());
+        return insertRoleMenu(bo);
+    }
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateRole(SysRoleBo bo) {
+        SysRole role = MapstructUtils.convert(bo, SysRole.class);
+
+        if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+            throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+        }
+        // 淇敼瑙掕壊淇℃伅
+        baseMapper.updateById(role);
+        // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, role.getRoleId()));
+        return insertRoleMenu(bo);
+    }
+
+    /**
+     * 淇敼瑙掕壊鐘舵��
+     *
+     * @param roleId 瑙掕壊ID
+     * @param status 瑙掕壊鐘舵��
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateRoleStatus(Long roleId, String status) {
+        if (UserConstants.ROLE_DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) {
+            throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+        }
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysRole>()
+                .set(SysRole::getStatus, status)
+                .eq(SysRole::getRoleId, roleId));
+    }
+
+    /**
+     * 淇敼鏁版嵁鏉冮檺淇℃伅
+     *
+     * @param bo 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int authDataScope(SysRoleBo bo) {
+        SysRole role = MapstructUtils.convert(bo, SysRole.class);
+        // 淇敼瑙掕壊淇℃伅
+        baseMapper.updateById(role);
+        // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, role.getRoleId()));
+        // 鏂板瑙掕壊鍜岄儴闂ㄤ俊鎭紙鏁版嵁鏉冮檺锛�
+        return insertRoleDept(bo);
+    }
+
+    /**
+     * 鏂板瑙掕壊鑿滃崟淇℃伅
+     *
+     * @param role 瑙掕壊瀵硅薄
+     */
+    private int insertRoleMenu(SysRoleBo role) {
+        int rows = 1;
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
+        for (Long menuId : role.getMenuIds()) {
+            SysRoleMenu rm = new SysRoleMenu();
+            rm.setRoleId(role.getRoleId());
+            rm.setMenuId(menuId);
+            list.add(rm);
+        }
+        if (list.size() > 0) {
+            rows = roleMenuMapper.insertBatch(list) ? list.size() : 0;
+        }
+        return rows;
+    }
+
+    /**
+     * 鏂板瑙掕壊閮ㄩ棬淇℃伅(鏁版嵁鏉冮檺)
+     *
+     * @param role 瑙掕壊瀵硅薄
+     */
+    private int insertRoleDept(SysRoleBo role) {
+        int rows = 1;
+        // 鏂板瑙掕壊涓庨儴闂紙鏁版嵁鏉冮檺锛夌鐞�
+        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
+        for (Long deptId : role.getDeptIds()) {
+            SysRoleDept rd = new SysRoleDept();
+            rd.setRoleId(role.getRoleId());
+            rd.setDeptId(deptId);
+            list.add(rd);
+        }
+        if (list.size() > 0) {
+            rows = roleDeptMapper.insertBatch(list) ? list.size() : 0;
+        }
+        return rows;
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+     *
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteRoleById(Long roleId) {
+        // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
+        // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, roleId));
+        return baseMapper.deleteById(roleId);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎瑙掕壊淇℃伅
+     *
+     * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteRoleByIds(Long[] roleIds) {
+        for (Long roleId : roleIds) {
+            SysRole role = baseMapper.selectById(roleId);
+            checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class));
+            checkRoleDataScope(roleId);
+            if (countUserRoleByRoleId(roleId) > 0) {
+                throw new ServiceException(String.format("%1$s宸插垎閰嶏紝涓嶈兘鍒犻櫎!", role.getRoleName()));
+            }
+        }
+        List<Long> ids = Arrays.asList(roleIds);
+        // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
+        // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
+        return baseMapper.deleteByIds(ids);
+    }
+
+    /**
+     * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteAuthUser(SysUserRole userRole) {
+        int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+            .eq(SysUserRole::getRoleId, userRole.getRoleId())
+            .eq(SysUserRole::getUserId, userRole.getUserId()));
+        if (rows > 0) {
+            cleanOnlineUserByRole(userRole.getRoleId());
+        }
+        return rows;
+    }
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteAuthUsers(Long roleId, Long[] userIds) {
+        int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+            .eq(SysUserRole::getRoleId, roleId)
+            .in(SysUserRole::getUserId, Arrays.asList(userIds)));
+        if (rows > 0) {
+            cleanOnlineUserByRole(roleId);
+        }
+        return rows;
+    }
+
+    /**
+     * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊
+     *
+     * @param roleId  瑙掕壊ID
+     * @param userIds 闇�瑕佹巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertAuthUsers(Long roleId, Long[] userIds) {
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        int rows = 1;
+        List<SysUserRole> list = StreamUtils.toList(List.of(userIds), userId -> {
+            SysUserRole ur = new SysUserRole();
+            ur.setUserId(userId);
+            ur.setRoleId(roleId);
+            return ur;
+        });
+        if (CollUtil.isNotEmpty(list)) {
+            rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
+        }
+        if (rows > 0) {
+            cleanOnlineUserByRole(roleId);
+        }
+        return rows;
+    }
+
+    @Override
+    public void cleanOnlineUserByRole(Long roleId) {
+        // 濡傛灉瑙掕壊鏈粦瀹氱敤鎴� 鐩存帴杩斿洖
+        Long num = userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
+        if (num == 0) {
+            return;
+        }
+        List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+        if (CollUtil.isEmpty(keys)) {
+            return;
+        }
+        // 瑙掕壊鍏宠仈鐨勫湪绾跨敤鎴烽噺杩囧ぇ浼氬鑷磖edis闃诲鍗¢】 璋ㄦ厧鎿嶄綔
+        keys.parallelStream().forEach(key -> {
+            String token = StringUtils.substringAfterLast(key, ":");
+            // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+            if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+                return;
+            }
+            LoginUser loginUser = LoginHelper.getLoginUser(token);
+            if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
+                try {
+                    StpUtil.logoutByTokenValue(token);
+                } catch (NotLoginException ignored) {
+                }
+            }
+        });
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
new file mode 100644
index 0000000..5f4d121
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
@@ -0,0 +1,47 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.stp.StpUtil;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.sensitive.core.SensitiveService;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鑴辨晱鏈嶅姟
+ * 榛樿绠$悊鍛樹笉杩囨护
+ * 闇�鑷鏍规嵁涓氬姟閲嶅啓瀹炵幇
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@Service
+public class SysSensitiveServiceImpl implements SensitiveService {
+
+    /**
+     * 鏄惁鑴辨晱
+     */
+    @Override
+    public boolean isSensitive(String roleKey, String perms) {
+        if (!LoginHelper.isLogin()) {
+            return true;
+        }
+        boolean roleExist = StringUtils.isNotBlank(roleKey);
+        boolean permsExist = StringUtils.isNotBlank(perms);
+        if (roleExist && permsExist) {
+            if (StpUtil.hasRole(roleKey) && StpUtil.hasPermission(perms)) {
+                return false;
+            }
+        } else if (roleExist && StpUtil.hasRole(roleKey)) {
+            return false;
+        } else if (permsExist && StpUtil.hasPermission(perms)) {
+            return false;
+        }
+
+        if (TenantHelper.isEnable()) {
+            return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin();
+        }
+        return !LoginHelper.isSuperAdmin();
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java
new file mode 100644
index 0000000..9c54cbc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java
@@ -0,0 +1,112 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.system.domain.SysSocial;
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.mapper.SysSocialMapper;
+import org.dromara.system.service.ISysSocialService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯籗ervice涓氬姟灞傚鐞�
+ *
+ * @author thiszhc
+ * @date 2023-06-12
+ */
+@RequiredArgsConstructor
+@Service
+public class SysSocialServiceImpl implements ISysSocialService {
+
+    private final SysSocialMapper baseMapper;
+
+
+    /**
+     * 鏌ヨ绀句細鍖栧叧绯�
+     */
+    @Override
+    public SysSocialVo queryById(String id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鎺堟潈鍒楄〃
+     */
+    @Override
+    public List<SysSocialVo> queryList(SysSocialBo bo) {
+        LambdaQueryWrapper<SysSocial> lqw = new LambdaQueryWrapper<SysSocial>()
+            .eq(ObjectUtil.isNotNull(bo.getUserId()), SysSocial::getUserId, bo.getUserId())
+            .eq(StringUtils.isNotBlank(bo.getAuthId()), SysSocial::getAuthId, bo.getAuthId())
+            .eq(StringUtils.isNotBlank(bo.getSource()), SysSocial::getSource, bo.getSource());
+        return baseMapper.selectVoList(lqw);
+    }
+
+    @Override
+    public List<SysSocialVo> queryListByUserId(Long userId) {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysSocial>().eq(SysSocial::getUserId, userId));
+    }
+
+
+    /**
+     * 鏂板绀句細鍖栧叧绯�
+     */
+    @Override
+    public Boolean insertByBo(SysSocialBo bo) {
+        SysSocial add = MapstructUtils.convert(bo, SysSocial.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            if (add != null) {
+                bo.setId(add.getId());
+            } else {
+                return false;
+            }
+        }
+        return flag;
+    }
+
+    /**
+     * 鏇存柊绀句細鍖栧叧绯�
+     */
+    @Override
+    public Boolean updateByBo(SysSocialBo bo) {
+        SysSocial update = MapstructUtils.convert(bo, SysSocial.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(SysSocial entity) {
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+
+    /**
+     * 鍒犻櫎绀句細鍖栧叧绯�
+     */
+    @Override
+    public Boolean deleteWithValidById(Long id) {
+        return baseMapper.deleteById(id) > 0;
+    }
+
+
+    /**
+     * 鏍规嵁 authId 鏌ヨ鐢ㄦ埛淇℃伅
+     *
+     * @param authId 璁よ瘉id
+     * @return 鎺堟潈淇℃伅
+     */
+    @Override
+    public List<SysSocialVo> selectByAuthId(String authId) {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysSocial>().eq(SysSocial::getAuthId, authId));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
new file mode 100644
index 0000000..d2a72f6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
@@ -0,0 +1,157 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysTenant;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+import org.dromara.system.mapper.SysTenantMapper;
+import org.dromara.system.mapper.SysTenantPackageMapper;
+import org.dromara.system.service.ISysTenantPackageService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅Service涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
+
+    private final SysTenantPackageMapper baseMapper;
+    private final SysTenantMapper tenantMapper;
+
+    /**
+     * 鏌ヨ绉熸埛濂楅
+     */
+    @Override
+    public SysTenantPackageVo queryById(Long packageId){
+        return baseMapper.selectVoById(packageId);
+    }
+
+    /**
+     * 鏌ヨ绉熸埛濂楅鍒楄〃
+     */
+    @Override
+    public TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
+        Page<SysTenantPackageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public List<SysTenantPackageVo> selectList() {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<SysTenantPackage>()
+                .eq(SysTenantPackage::getStatus, TenantConstants.NORMAL));
+    }
+
+    /**
+     * 鏌ヨ绉熸埛濂楅鍒楄〃
+     */
+    @Override
+    public List<SysTenantPackageVo> queryList(SysTenantPackageBo bo) {
+        LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysTenantPackage> buildQueryWrapper(SysTenantPackageBo bo) {
+        LambdaQueryWrapper<SysTenantPackage> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getPackageName()), SysTenantPackage::getPackageName, bo.getPackageName());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenantPackage::getStatus, bo.getStatus());
+        lqw.orderByAsc(SysTenantPackage::getPackageId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板绉熸埛濂楅
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertByBo(SysTenantPackageBo bo) {
+        SysTenantPackage add = MapstructUtils.convert(bo, SysTenantPackage.class);
+        // 淇濆瓨鑿滃崟id
+        List<Long> menuIds = Arrays.asList(bo.getMenuIds());
+        if (CollUtil.isNotEmpty(menuIds)) {
+            add.setMenuIds(StringUtils.join(menuIds, ", "));
+        } else {
+            add.setMenuIds("");
+        }
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setPackageId(add.getPackageId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼绉熸埛濂楅
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateByBo(SysTenantPackageBo bo) {
+        SysTenantPackage update = MapstructUtils.convert(bo, SysTenantPackage.class);
+        // 淇濆瓨鑿滃崟id
+        List<Long> menuIds = Arrays.asList(bo.getMenuIds());
+        if (CollUtil.isNotEmpty(menuIds)) {
+            update.setMenuIds(StringUtils.join(menuIds, ", "));
+        } else {
+            update.setMenuIds("");
+        }
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 鏍¢獙濂楅鍚嶇О鏄惁鍞竴
+     */
+    @Override
+    public boolean checkPackageNameUnique(SysTenantPackageBo bo) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenantPackage>()
+            .eq(SysTenantPackage::getPackageName, bo.getPackageName())
+            .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId()));
+        return !exist;
+    }
+
+    /**
+     * 淇敼濂楅鐘舵��
+     *
+     * @param bo 濂楅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updatePackageStatus(SysTenantPackageBo bo) {
+        SysTenantPackage tenantPackage = MapstructUtils.convert(bo, SysTenantPackage.class);
+        return baseMapper.updateById(tenantPackage);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绉熸埛濂楅
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            boolean exists = tenantMapper.exists(new LambdaQueryWrapper<SysTenant>().in(SysTenant::getPackageId, ids));
+            if (exists) {
+                throw new ServiceException("绉熸埛濂楅宸茶浣跨敤");
+            }
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
new file mode 100644
index 0000000..d30750d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
@@ -0,0 +1,372 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.*;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.mapper.*;
+import org.dromara.system.service.ISysTenantService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 绉熸埛Service涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantServiceImpl implements ISysTenantService {
+
+    private final SysTenantMapper baseMapper;
+    private final SysTenantPackageMapper tenantPackageMapper;
+    private final SysUserMapper userMapper;
+    private final SysDeptMapper deptMapper;
+    private final SysRoleMapper roleMapper;
+    private final SysRoleMenuMapper roleMenuMapper;
+    private final SysRoleDeptMapper roleDeptMapper;
+    private final SysUserRoleMapper userRoleMapper;
+    private final SysDictTypeMapper dictTypeMapper;
+    private final SysDictDataMapper dictDataMapper;
+    private final SysConfigMapper configMapper;
+
+    /**
+     * 鏌ヨ绉熸埛
+     */
+    @Override
+    public SysTenantVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍩轰簬绉熸埛ID鏌ヨ绉熸埛
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId")
+    @Override
+    public SysTenantVo queryByTenantId(String tenantId) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantId, tenantId));
+    }
+
+    /**
+     * 鏌ヨ绉熸埛鍒楄〃
+     */
+    @Override
+    public TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
+        Page<SysTenantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绉熸埛鍒楄〃
+     */
+    @Override
+    public List<SysTenantVo> queryList(SysTenantBo bo) {
+        LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<SysTenant> buildQueryWrapper(SysTenantBo bo) {
+        LambdaQueryWrapper<SysTenant> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId());
+        lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName());
+        lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone());
+        lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName());
+        lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber());
+        lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress());
+        lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro());
+        lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain());
+        lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId());
+        lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime());
+        lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus());
+        lqw.orderByAsc(SysTenant::getId);
+        return lqw;
+    }
+
+    /**
+     * 鏂板绉熸埛
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean insertByBo(SysTenantBo bo) {
+        SysTenant add = MapstructUtils.convert(bo, SysTenant.class);
+
+        // 鑾峰彇鎵�鏈夌鎴风紪鍙�
+        List<String> tenantIds = baseMapper.selectObjs(
+            new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), x -> {return Convert.toStr(x);});
+        String tenantId = generateTenantId(tenantIds);
+        add.setTenantId(tenantId);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (!flag) {
+            throw new ServiceException("鍒涘缓绉熸埛澶辫触");
+        }
+        bo.setId(add.getId());
+
+        // 鏍规嵁濂楅鍒涘缓瑙掕壊
+        Long roleId = createTenantRole(tenantId, bo.getPackageId());
+
+        // 鍒涘缓閮ㄩ棬: 鍏徃鍚嶆槸閮ㄩ棬鍚嶇О
+        SysDept dept = new SysDept();
+        dept.setTenantId(tenantId);
+        dept.setDeptName(bo.getCompanyName());
+        dept.setParentId(Constants.TOP_PARENT_ID);
+        dept.setAncestors(Constants.TOP_PARENT_ID.toString());
+        deptMapper.insert(dept);
+        Long deptId = dept.getDeptId();
+
+        // 瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃
+        SysRoleDept roleDept = new SysRoleDept();
+        roleDept.setRoleId(roleId);
+        roleDept.setDeptId(deptId);
+        roleDeptMapper.insert(roleDept);
+
+        // 鍒涘缓绯荤粺鐢ㄦ埛
+        SysUser user = new SysUser();
+        user.setTenantId(tenantId);
+        user.setUserName(bo.getUsername());
+        user.setNickName(bo.getUsername());
+        user.setPassword(BCrypt.hashpw(bo.getPassword()));
+        user.setDeptId(deptId);
+        userMapper.insert(user);
+        //鏂板绯荤粺鐢ㄦ埛鍚庯紝榛樿褰撳墠鐢ㄦ埛涓洪儴闂ㄧ殑璐熻矗浜�
+        SysDept sd = new SysDept();
+        sd.setLeader(user.getUserId());
+        sd.setDeptId(deptId);
+        deptMapper.updateById(sd);
+
+        // 鐢ㄦ埛鍜岃鑹插叧鑱旇〃
+        SysUserRole userRole = new SysUserRole();
+        userRole.setUserId(user.getUserId());
+        userRole.setRoleId(roleId);
+        userRoleMapper.insert(userRole);
+
+        String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;
+        List<SysDictType> dictTypeList = dictTypeMapper.selectList(
+            new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getTenantId, defaultTenantId));
+        List<SysDictData> dictDataList = dictDataMapper.selectList(
+            new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getTenantId, defaultTenantId));
+        for (SysDictType dictType : dictTypeList) {
+            dictType.setDictId(null);
+            dictType.setTenantId(tenantId);
+        }
+        for (SysDictData dictData : dictDataList) {
+            dictData.setDictCode(null);
+            dictData.setTenantId(tenantId);
+        }
+        dictTypeMapper.insertBatch(dictTypeList);
+        dictDataMapper.insertBatch(dictDataList);
+
+        List<SysConfig> sysConfigList = configMapper.selectList(
+            new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getTenantId, defaultTenantId));
+        for (SysConfig config : sysConfigList) {
+            config.setConfigId(null);
+            config.setTenantId(tenantId);
+        }
+        configMapper.insertBatch(sysConfigList);
+        return true;
+    }
+
+    /**
+     * 鐢熸垚绉熸埛id
+     *
+     * @param tenantIds 宸叉湁绉熸埛id鍒楄〃
+     * @return 绉熸埛id
+     */
+    private String generateTenantId(List<String> tenantIds) {
+        // 闅忔満鐢熸垚6浣�
+        String numbers = RandomUtil.randomNumbers(6);
+        // 鍒ゆ柇鏄惁瀛樺湪锛屽鏋滃瓨鍦ㄥ垯閲嶆柊鐢熸垚
+        if (tenantIds.contains(numbers)) {
+            generateTenantId(tenantIds);
+        }
+        return numbers;
+    }
+
+    /**
+     * 鏍规嵁绉熸埛鑿滃崟鍒涘缓绉熸埛瑙掕壊
+     *
+     * @param tenantId  绉熸埛缂栧彿
+     * @param packageId 绉熸埛濂楅id
+     * @return 瑙掕壊id
+     */
+    private Long createTenantRole(String tenantId, Long packageId) {
+        // 鑾峰彇绉熸埛濂楅
+        SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+        if (ObjectUtil.isNull(tenantPackage)) {
+            throw new ServiceException("濂楅涓嶅瓨鍦�");
+        }
+        // 鑾峰彇濂楅鑿滃崟id
+        List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+
+        // 鍒涘缓瑙掕壊
+        SysRole role = new SysRole();
+        role.setTenantId(tenantId);
+        role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
+        role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY);
+        role.setRoleSort(1);
+        role.setStatus(TenantConstants.NORMAL);
+        roleMapper.insert(role);
+        Long roleId = role.getRoleId();
+
+        // 鍒涘缓瑙掕壊鑿滃崟
+        List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
+        menuIds.forEach(menuId -> {
+            SysRoleMenu roleMenu = new SysRoleMenu();
+            roleMenu.setRoleId(roleId);
+            roleMenu.setMenuId(menuId);
+            roleMenus.add(roleMenu);
+        });
+        roleMenuMapper.insertBatch(roleMenus);
+
+        return roleId;
+    }
+
+    /**
+     * 淇敼绉熸埛
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
+    @Override
+    public Boolean updateByBo(SysTenantBo bo) {
+        SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
+        tenant.setTenantId(null);
+        tenant.setPackageId(null);
+        return baseMapper.updateById(tenant) > 0;
+    }
+
+    /**
+     * 淇敼绉熸埛鐘舵��
+     *
+     * @param bo 绉熸埛淇℃伅
+     * @return 缁撴灉
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
+    @Override
+    public int updateTenantStatus(SysTenantBo bo) {
+        SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
+        return baseMapper.updateById(tenant);
+    }
+
+    /**
+     * 鏍¢獙绉熸埛鏄惁鍏佽鎿嶄綔
+     *
+     * @param tenantId 绉熸埛ID
+     */
+    @Override
+    public void checkTenantAllowed(String tenantId) {
+        if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+            throw new ServiceException("涓嶅厑璁告搷浣滅鐞嗙鎴�");
+        }
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绉熸埛
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true)
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+            if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) {
+                throw new ServiceException("瓒呯绉熸埛涓嶈兘鍒犻櫎");
+            }
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    /**
+     * 鏍¢獙浼佷笟鍚嶇О鏄惁鍞竴
+     */
+    @Override
+    public boolean checkCompanyNameUnique(SysTenantBo bo) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenant>()
+            .eq(SysTenant::getCompanyName, bo.getCompanyName())
+            .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙璐﹀彿浣欓
+     */
+    @Override
+    public boolean checkAccountBalance(String tenantId) {
+        SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
+        // 濡傛灉浣欓涓�-1浠h〃涓嶉檺鍒�
+        if (tenant.getAccountCount() == -1) {
+            return true;
+        }
+        Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>());
+        // 濡傛灉浣欓澶т簬0浠h〃杩樻湁鍙敤鍚嶉
+        return tenant.getAccountCount() - userNumber > 0;
+    }
+
+    /**
+     * 鏍¢獙鏈夋晥鏈�
+     */
+    @Override
+    public boolean checkExpireTime(String tenantId) {
+        SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
+        // 濡傛灉鏈缃繃鏈熸椂闂翠唬琛ㄤ笉闄愬埗
+        if (ObjectUtil.isNull(tenant.getExpireTime())) {
+            return true;
+        }
+        // 濡傛灉褰撳墠鏃堕棿鍦ㄨ繃鏈熸椂闂翠箣鍓嶅垯閫氳繃
+        return new Date().before(tenant.getExpireTime());
+    }
+
+    /**
+     * 鍚屾绉熸埛濂楅
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean syncTenantPackage(String tenantId, Long packageId) {
+        SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+        List<SysRole> roles = roleMapper.selectList(
+            new LambdaQueryWrapper<SysRole>().eq(SysRole::getTenantId, tenantId));
+        List<Long> roleIds = new ArrayList<>(roles.size() - 1);
+        List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+        roles.forEach(item -> {
+            if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) {
+                List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
+                menuIds.forEach(menuId -> {
+                    SysRoleMenu roleMenu = new SysRoleMenu();
+                    roleMenu.setRoleId(item.getRoleId());
+                    roleMenu.setMenuId(menuId);
+                    roleMenus.add(roleMenu);
+                });
+                roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, item.getRoleId()));
+                roleMenuMapper.insertBatch(roleMenus);
+            } else {
+                roleIds.add(item.getRoleId());
+            }
+        });
+        if (!roleIds.isEmpty()) {
+            roleMenuMapper.delete(
+                new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds));
+        }
+        return true;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..2540606
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,672 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.*;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.domain.vo.SysUserExportVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.*;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysUserServiceImpl implements ISysUserService, UserService {
+
+    private final SysUserMapper baseMapper;
+    private final SysDeptMapper deptMapper;
+    private final SysRoleMapper roleMapper;
+    private final SysPostMapper postMapper;
+    private final SysUserRoleMapper userRoleMapper;
+    private final SysUserPostMapper userPostMapper;
+
+    @Override
+    public TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery) {
+        Page<SysUserVo> page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user));
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysUserExportVo> selectUserExportList(SysUserBo user) {
+        return baseMapper.selectUserExportList(this.buildQueryWrapper(user));
+    }
+
+    private Wrapper<SysUser> buildQueryWrapper(SysUserBo user) {
+        Map<String, Object> params = user.getParams();
+        QueryWrapper<SysUser> wrapper = Wrappers.query();
+        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+            .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId())
+            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+            .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
+            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+            .between(params.get("beginTime") != null && params.get("endTime") != null,
+                "u.create_time", params.get("beginTime"), params.get("endTime"))
+            .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
+                List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
+                    .select(SysDept::getDeptId)
+                    .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
+                List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
+                ids.add(user.getDeptId());
+                w.in("u.dept_id", ids);
+            }).orderByAsc("u.user_id");
+        if (StringUtils.isNotBlank(user.getExcludeUserIds())) {
+            wrapper.notIn("u.user_id", StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong));
+        }
+        return wrapper;
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @Override
+    public TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery) {
+        QueryWrapper<SysUser> wrapper = Wrappers.query();
+        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+            .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
+            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+            .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
+            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+            .orderByAsc("u.user_id");
+        Page<SysUserVo> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @Override
+    public TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery) {
+        List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
+        QueryWrapper<SysUser> wrapper = Wrappers.query();
+        wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+            .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
+            .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
+            .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+            .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+            .orderByAsc("u.user_id");
+        Page<SysUserVo> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+     *
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @Override
+    public SysUserVo selectUserByUserName(String userName) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
+    }
+
+    /**
+     * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴�
+     *
+     * @param phonenumber 鎵嬫満鍙�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @Override
+    public SysUserVo selectUserByPhonenumber(String phonenumber) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @Override
+    public SysUserVo selectUserById(Long userId) {
+        SysUserVo user = baseMapper.selectVoById(userId);
+        if (ObjectUtil.isNull(user)) {
+            return user;
+        }
+        user.setRoles(roleMapper.selectRolesByUserId(user.getUserId()));
+        return user;
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID涓叉煡璇㈢敤鎴�
+     *
+     * @param userIds 鐢ㄦ埛ID涓�
+     * @param deptId  閮ㄩ棬id
+     * @return 鐢ㄦ埛鍒楄〃淇℃伅
+     */
+    @Override
+    public List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId) {
+        return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
+            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
+            .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
+            .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
+    }
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    @Override
+    public String selectUserRoleGroup(Long userId) {
+        List<SysRoleVo> list = roleMapper.selectRolesByUserId(userId);
+        if (CollUtil.isEmpty(list)) {
+            return StringUtils.EMPTY;
+        }
+        return StreamUtils.join(list, SysRoleVo::getRoleName);
+    }
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    @Override
+    public String selectUserPostGroup(Long userId) {
+        List<SysPostVo> list = postMapper.selectPostsByUserId(userId);
+        if (CollUtil.isEmpty(list)) {
+            return StringUtils.EMPTY;
+        }
+        return StreamUtils.join(list, SysPostVo::getPostName);
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkUserNameUnique(SysUserBo user) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getUserName, user.getUserName())
+            .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     */
+    @Override
+    public boolean checkPhoneUnique(SysUserBo user) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getPhonenumber, user.getPhonenumber())
+            .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙email鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     */
+    @Override
+    public boolean checkEmailUnique(SysUserBo user) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getEmail, user.getEmail())
+            .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+        return !exist;
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+     *
+     * @param userId 鐢ㄦ埛ID
+     */
+    @Override
+    public void checkUserAllowed(Long userId) {
+        if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) {
+            throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳鐢ㄦ埛");
+        }
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鏈夋暟鎹潈闄�
+     *
+     * @param userId 鐢ㄦ埛id
+     */
+    @Override
+    public void checkUserDataScope(Long userId) {
+        if (ObjectUtil.isNull(userId)) {
+            return;
+        }
+        if (LoginHelper.isSuperAdmin()) {
+            return;
+        }
+        if (baseMapper.countUserById(userId) == 0) {
+            throw new ServiceException("娌℃湁鏉冮檺璁块棶鐢ㄦ埛鏁版嵁锛�");
+        }
+    }
+
+    /**
+     * 鏂板淇濆瓨鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int insertUser(SysUserBo user) {
+        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+        // 鏂板鐢ㄦ埛淇℃伅
+        int rows = baseMapper.insert(sysUser);
+        user.setUserId(sysUser.getUserId());
+        // 鏂板鐢ㄦ埛宀椾綅鍏宠仈
+        insertUserPost(user, false);
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        insertUserRole(user, false);
+        return rows;
+    }
+
+    /**
+     * 娉ㄥ唽鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean registerUser(SysUserBo user, String tenantId) {
+        user.setCreateBy(0L);
+        user.setUpdateBy(0L);
+        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+        sysUser.setTenantId(tenantId);
+        return baseMapper.insert(sysUser) > 0;
+    }
+
+    /**
+     * 淇敼淇濆瓨鐢ㄦ埛淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
+    @Transactional(rollbackFor = Exception.class)
+    public int updateUser(SysUserBo user) {
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        insertUserRole(user, true);
+        // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+        insertUserPost(user, true);
+        SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+        // 闃叉閿欒鏇存柊鍚庡鑷寸殑鏁版嵁璇垹闄�
+        int flag = baseMapper.updateById(sysUser);
+        if (flag < 1) {
+            throw new ServiceException("淇敼鐢ㄦ埛" + user.getUserName() + "淇℃伅澶辫触");
+        }
+        return flag;
+    }
+
+    /**
+     * 鐢ㄦ埛鎺堟潈瑙掕壊
+     *
+     * @param userId  鐢ㄦ埛ID
+     * @param roleIds 瑙掕壊缁�
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void insertUserAuth(Long userId, Long[] roleIds) {
+        insertUserRole(userId, roleIds, true);
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛鐘舵��
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @param status 甯愬彿鐘舵��
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateUserStatus(Long userId, String status) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysUser>()
+                .set(SysUser::getStatus, status)
+                .eq(SysUser::getUserId, userId));
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId")
+    @Override
+    public int updateUserProfile(SysUserBo user) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysUser>()
+                .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName())
+                .set(SysUser::getPhonenumber, user.getPhonenumber())
+                .set(SysUser::getEmail, user.getEmail())
+                .set(SysUser::getSex, user.getSex())
+                .eq(SysUser::getUserId, user.getUserId()));
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛澶村儚
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @param avatar 澶村儚鍦板潃
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean updateUserAvatar(Long userId, Long avatar) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysUser>()
+                .set(SysUser::getAvatar, avatar)
+                .eq(SysUser::getUserId, userId)) > 0;
+    }
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     *
+     * @param userId   鐢ㄦ埛ID
+     * @param password 瀵嗙爜
+     * @return 缁撴灉
+     */
+    @Override
+    public int resetUserPwd(Long userId, String password) {
+        return baseMapper.update(null,
+            new LambdaUpdateWrapper<SysUser>()
+                .set(SysUser::getPassword, password)
+                .eq(SysUser::getUserId, userId));
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛瑙掕壊淇℃伅
+     *
+     * @param user  鐢ㄦ埛瀵硅薄
+     * @param clear 娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+     */
+    private void insertUserRole(SysUserBo user, boolean clear) {
+        this.insertUserRole(user.getUserId(), user.getRoleIds(), clear);
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛宀椾綅淇℃伅
+     *
+     * @param user  鐢ㄦ埛瀵硅薄
+     * @param clear 娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+     */
+    private void insertUserPost(SysUserBo user, boolean clear) {
+        Long[] posts = user.getPostIds();
+        if (ArrayUtil.isNotEmpty(posts)) {
+            if (clear) {
+                // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶅叧鑱�
+                userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, user.getUserId()));
+            }
+            // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+            List<SysUserPost> list = StreamUtils.toList(List.of(posts), postId -> {
+                SysUserPost up = new SysUserPost();
+                up.setUserId(user.getUserId());
+                up.setPostId(postId);
+                return up;
+            });
+            userPostMapper.insertBatch(list);
+        }
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛瑙掕壊淇℃伅
+     *
+     * @param userId  鐢ㄦ埛ID
+     * @param roleIds 瑙掕壊缁�
+     * @param clear   娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+     */
+    private void insertUserRole(Long userId, Long[] roleIds, boolean clear) {
+        if (ArrayUtil.isNotEmpty(roleIds)) {
+            List<Long> roleList = new ArrayList<>(List.of(roleIds));
+            if (!LoginHelper.isSuperAdmin(userId)) {
+                roleList.remove(UserConstants.SUPER_ADMIN_ID);
+            }
+            // 鍒ゆ柇鏄惁鍏锋湁姝よ鑹茬殑鎿嶄綔鏉冮檺
+            List<SysRoleVo> roles = roleMapper.selectRoleList(
+                new QueryWrapper<SysRole>().in("r.role_id", roleList));
+            if (CollUtil.isEmpty(roles)) {
+                throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鐨勬暟鎹�");
+            }
+            if (clear) {
+                // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+                userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
+            }
+            // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+            List<SysUserRole> list = StreamUtils.toList(roleList, roleId -> {
+                SysUserRole ur = new SysUserRole();
+                ur.setUserId(userId);
+                ur.setRoleId(roleId);
+                return ur;
+            });
+            userRoleMapper.insertBatch(list);
+        }
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteUserById(Long userId) {
+        // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
+        // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶈〃
+        userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
+        // 闃叉鏇存柊澶辫触瀵艰嚧鐨勬暟鎹垹闄�
+        int flag = baseMapper.deleteById(userId);
+        if (flag < 1) {
+            throw new ServiceException("鍒犻櫎鐢ㄦ埛澶辫触!");
+        }
+        return flag;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鐢ㄦ埛淇℃伅
+     *
+     * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteUserByIds(Long[] userIds) {
+        for (Long userId : userIds) {
+            checkUserAllowed(userId);
+            checkUserDataScope(userId);
+        }
+        List<Long> ids = List.of(userIds);
+        // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+        userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, ids));
+        // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶈〃
+        userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, ids));
+        // 闃叉鏇存柊澶辫触瀵艰嚧鐨勬暟鎹垹闄�
+        int flag = baseMapper.deleteByIds(ids);
+        if (flag < 1) {
+            throw new ServiceException("鍒犻櫎鐢ㄦ埛澶辫触!");
+        }
+        return flag;
+    }
+
+    /**
+     * 閫氳繃閮ㄩ棬id鏌ヨ褰撳墠閮ㄩ棬鎵�鏈夌敤鎴�
+     *
+     * @param deptId 閮ㄩ棬ID
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysUserVo> selectUserListByDept(Long deptId) {
+        LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
+        lqw.eq(SysUser::getDeptId, deptId);
+        lqw.orderByAsc(SysUser::getUserId);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛璐︽埛
+     */
+    @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
+    @Override
+    public String selectUserNameById(Long userId) {
+        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserName).eq(SysUser::getUserId, userId));
+        return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName();
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛璐︽埛
+     */
+    @Override
+    @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId")
+    public String selectNicknameById(Long userId) {
+        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getNickName).eq(SysUser::getUserId, userId));
+        return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName();
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+     *
+     * @param userIds 鐢ㄦ埛ID 澶氫釜鐢ㄩ�楀彿闅斿紑
+     * @return 鐢ㄦ埛璐︽埛
+     */
+    @Override
+    public String selectNicknameByIds(String userIds) {
+        List<String> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(userIds, Convert::toLong)) {
+            String nickname = SpringUtils.getAopProxy(this).selectNicknameById(id);
+            if (StringUtils.isNotBlank(nickname)) {
+                list.add(nickname);
+            }
+        }
+        return String.join(StringUtils.SEPARATOR, list);
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵嬫満鍙�
+     *
+     * @param userId 鐢ㄦ埛id
+     * @return 鐢ㄦ埛鎵嬫満鍙�
+     */
+    @Override
+    public String selectPhonenumberById(Long userId) {
+        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId));
+        return ObjectUtil.isNull(sysUser) ? null : sysUser.getPhonenumber();
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛閭
+     *
+     * @param userId 鐢ㄦ埛id
+     * @return 鐢ㄦ埛閭
+     */
+    @Override
+    public String selectEmailById(Long userId) {
+        SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getEmail).eq(SysUser::getUserId, userId));
+        return ObjectUtil.isNull(sysUser) ? null : sysUser.getEmail();
+    }
+
+    @Override
+    public List<UserDTO> selectListByIds(List<Long> userIds) {
+        if (CollUtil.isEmpty(userIds)) {
+            return List.of();
+        }
+        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
+            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
+            .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
+        return BeanUtil.copyToList(list, UserDTO.class);
+    }
+
+    @Override
+    public List<Long> selectUserIdsByRoleIds(List<Long> roleIds) {
+        List<SysUserRole> userRoles = userRoleMapper.selectList(
+            new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
+        return StreamUtils.toList(userRoles, SysUserRole::getUserId);
+    }
+
+    @Override
+    public List<UserDTO> selectUsersByRoleIds(List<Long> roleIds) {
+        if (CollUtil.isEmpty(roleIds)) {
+            return List.of();
+        }
+        List<SysUserRole> userRoles = userRoleMapper.selectList(
+            new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
+        List<Long> userIds = StreamUtils.toList(userRoles, SysUserRole::getUserId);
+        return selectListByIds(userIds);
+    }
+
+    @Override
+    public List<UserDTO> selectUsersByDeptIds(List<Long> deptIds) {
+        if (CollUtil.isEmpty(deptIds)) {
+            return List.of();
+        }
+        List<SysUserVo> list = baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber)
+            .eq(SysUser::getStatus, UserConstants.USER_NORMAL)
+            .in(CollUtil.isNotEmpty(deptIds), SysUser::getDeptId, deptIds));
+        return BeanUtil.copyToList(list, UserDTO.class);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml
new file mode 100644
index 0000000..fd150ad
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysClientMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
new file mode 100644
index 0000000..e542a10
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysConfigMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
new file mode 100644
index 0000000..6ad866f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDeptMapper">
+
+    <resultMap type="org.dromara.system.domain.vo.SysDeptVo" id="SysDeptResult">
+    </resultMap>
+
+    <select id="selectDeptList" resultMap="SysDeptResult">
+        select
+        <if test="ew.getSqlSelect != null">
+            ${ew.getSqlSelect}
+        </if>
+        <if test="ew.getSqlSelect == null">
+            *
+        </if>
+        from sys_dept ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="countDeptById" resultType="Long">
+        select count(*) from sys_dept where del_flag = '0' and dept_id = #{deptId}
+    </select>
+
+    <select id="selectDeptListByRoleId" resultType="Long">
+        select d.dept_id
+        from sys_dept d
+            left join sys_role_dept rd on d.dept_id = rd.dept_id
+        where rd.role_id = #{roleId}
+            <if test="deptCheckStrictly">
+                and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
+            </if>
+        order by d.parent_id, d.order_num
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
new file mode 100644
index 0000000..6bcce51
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDictDataMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
new file mode 100644
index 0000000..6975da4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDictTypeMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
new file mode 100644
index 0000000..c64b551
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysLogininforMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
new file mode 100644
index 0000000..9dd3f2e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysMenuMapper">
+
+    <resultMap type="org.dromara.system.domain.SysMenu" id="SysMenuResult">
+    </resultMap>
+
+    <select id="selectMenuListByUserId" resultMap="SysMenuResult">
+        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query_param, m.visible, m.status,
+        m.perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
+        from sys_menu m
+            left join sys_role_menu rm on m.menu_id = rm.menu_id
+            left join sys_role r on rm.role_id = r.role_id
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
+        select distinct m.menu_id,
+                        m.parent_id,
+                        m.menu_name,
+                        m.path,
+                        m.component,
+                        m.query_param,
+                        m.visible,
+                        m.status,
+                        m.perms,
+                        m.is_frame,
+                        m.is_cache,
+                        m.menu_type,
+                        m.icon,
+                        m.order_num,
+                        m.create_time
+        from sys_menu m
+                 left join sys_role_menu rm on m.menu_id = rm.menu_id and m.status = '0'
+                 left join sys_role r on rm.role_id = r.role_id and r.status = '0'
+        where m.menu_type in ('M', 'C')
+          and r.role_id in (select role_id from sys_user_role where user_id = #{userId})
+        order by m.parent_id, m.order_num
+    </select>
+
+    <select id="selectMenuListByRoleId" resultType="Long">
+        select m.menu_id
+        from sys_menu m
+        left join sys_role_menu rm on m.menu_id = rm.menu_id
+        where rm.role_id = #{roleId}
+        <if test="menuCheckStrictly">
+            and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id =
+            rm.menu_id and rm.role_id = #{roleId})
+        </if>
+        order by m.parent_id, m.order_num
+    </select>
+
+    <select id="selectMenuPermsByUserId" parameterType="Long" resultType="String">
+        select distinct m.perms
+        from sys_menu m
+                 left join sys_role_menu rm on m.menu_id = rm.menu_id and m.status = '0'
+                 left join sys_role r on r.role_id = rm.role_id and r.status = '0'
+        where r.role_id in (select role_id from sys_user_role where user_id = #{userId})
+    </select>
+
+    <select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">
+        select distinct m.perms
+        from sys_menu m
+                 left join sys_role_menu rm on m.menu_id = rm.menu_id
+        where m.status = '0' and rm.role_id = #{roleId}
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
new file mode 100644
index 0000000..43f494d
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysNoticeMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
new file mode 100644
index 0000000..5ef14ee
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysOperLogMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml
new file mode 100644
index 0000000..8c2c080
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysOssConfigMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml
new file mode 100644
index 0000000..d9b25bd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysOssMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
new file mode 100644
index 0000000..322403f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysPostMapper">
+
+    <resultMap type="org.dromara.system.domain.vo.SysPostVo" id="SysPostResult">
+    </resultMap>
+
+    <select id="selectPagePostList" resultMap="SysPostResult">
+        select
+        <if test="ew.getSqlSelect != null">
+            ${ew.getSqlSelect}
+        </if>
+        <if test="ew.getSqlSelect == null">
+            *
+        </if>
+        from sys_post ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectPostsByUserId" parameterType="Long" resultMap="SysPostResult">
+        select p.post_id, p.dept_id, p.post_name, p.post_code, p.post_category
+        from sys_post p
+                 left join sys_user_post up on up.post_id = p.post_id
+                 left join sys_user u on u.user_id = up.user_id
+        where u.user_id = #{userId}
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
new file mode 100644
index 0000000..1705bb2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleDeptMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
new file mode 100644
index 0000000..4ef7b1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleMapper">
+
+    <resultMap type="org.dromara.system.domain.vo.SysRoleVo" id="SysRoleResult">
+    </resultMap>
+
+    <sql id="selectRoleVo">
+        select distinct r.role_id,
+                        r.role_name,
+                        r.role_key,
+                        r.role_sort,
+                        r.data_scope,
+                        r.menu_check_strictly,
+                        r.dept_check_strictly,
+                        r.status,
+                        r.del_flag,
+                        r.create_time,
+                        r.remark
+        from sys_role r
+                 left join sys_user_role sur on sur.role_id = r.role_id
+                 left join sys_user u on u.user_id = sur.user_id
+                 left join sys_dept d on u.dept_id = d.dept_id
+    </sql>
+
+    <select id="selectPageRoleList" resultMap="SysRoleResult">
+        <include refid="selectRoleVo"/>
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectRoleList" resultMap="SysRoleResult">
+        <include refid="selectRoleVo"/>
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult">
+        <include refid="selectRoleVo"/>
+        WHERE r.del_flag = '0' and sur.user_id = #{userId}
+    </select>
+
+    <select id="selectRolesByUserId" parameterType="Long" resultMap="SysRoleResult">
+        select r.role_id,
+               r.role_name,
+               r.role_key,
+               r.role_sort,
+               r.data_scope,
+               r.status
+        from sys_role r
+        WHERE r.del_flag = '0' and r.role_id in (select role_id from sys_user_role where user_id = #{userId})
+    </select>
+
+    <select id="selectRoleById" resultMap="SysRoleResult">
+        <include refid="selectRoleVo"/>
+        WHERE r.del_flag = '0' and r.role_id = #{roleId}
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
new file mode 100644
index 0000000..f01dc5e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleMenuMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml
new file mode 100644
index 0000000..baa4b59
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysSocialMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml
new file mode 100644
index 0000000..0d96e13
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysTenantMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
new file mode 100644
index 0000000..79cf4c5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysTenantPackageMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
new file mode 100644
index 0000000..ded6fa8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserMapper">
+
+    <resultMap type="org.dromara.system.domain.vo.SysUserVo" id="SysUserResult">
+        <id property="userId" column="user_id"/>
+    </resultMap>
+    <resultMap type="org.dromara.system.domain.vo.SysUserExportVo" id="SysUserExportResult">
+        <id property="userId" column="user_id"/>
+    </resultMap>
+
+    <select id="selectPageUserList" resultMap="SysUserResult">
+        select
+        <if test="ew.getSqlSelect != null">
+            ${ew.getSqlSelect}
+        </if>
+        <if test="ew.getSqlSelect == null">
+            u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex,
+            u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark
+        </if>
+        from sys_user u
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectUserList" resultMap="SysUserResult">
+        select
+        <if test="ew.getSqlSelect != null">
+            ${ew.getSqlSelect}
+        </if>
+        <if test="ew.getSqlSelect == null">
+            u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex,
+            u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark
+        </if>
+        from sys_user u
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectUserExportList" resultMap="SysUserExportResult">
+        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex,
+            u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
+            d.dept_name, d.leader, u1.user_name as leaderName
+        from sys_user u
+            left join sys_dept d on u.dept_id = d.dept_id
+            left join sys_user u1 on u1.user_id = d.leader
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectAllocatedList" resultMap="SysUserResult">
+        select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+        from sys_user u
+             left join sys_dept d on u.dept_id = d.dept_id
+             left join sys_user_role sur on u.user_id = sur.user_id
+             left join sys_role r on r.role_id = sur.role_id
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="selectUnallocatedList" resultMap="SysUserResult">
+        select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+        from sys_user u
+             left join sys_dept d on u.dept_id = d.dept_id
+             left join sys_user_role sur on u.user_id = sur.user_id
+             left join sys_role r on r.role_id = sur.role_id
+        ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="countUserById" resultType="Long">
+        select count(*) from sys_user where del_flag = '0' and user_id = #{userId}
+    </select>
+
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
new file mode 100644
index 0000000..e9f2496
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserPostMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
new file mode 100644
index 0000000..bc52d1a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserRoleMapper">
+
+    <select id="selectUserIdsByRoleId" resultType="Long">
+        select u.user_id from sys_user u
+        inner join sys_user_role sur
+            on u.user_id = sur.user_id and sur.role_id = #{roleId}
+    </select>
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/README.md b/eims/ruoyi-modules/ruoyi-workflow/README.md
new file mode 100644
index 0000000..59096b1
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/README.md
@@ -0,0 +1,3 @@
+# 宸ヤ綔娴佽鏄�
+
+宸ヤ綔娴佺洰鍓嶅湪鏈垚鐔熼樁娈� 鍚庣画浠嶄細缁忓巻閲嶆瀯 鐢氳嚦閲嶅啓(鐢熶骇浣跨敤鍓嶈鎱庨噸鑰冭檻鍚庣画鏄惁瑕佹洿鏂扮淮鎶�)
\ No newline at end of file
diff --git a/eims/ruoyi-modules/ruoyi-workflow/pom.xml b/eims/ruoyi-modules/ruoyi-workflow/pom.xml
new file mode 100644
index 0000000..e55839e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.dromara</groupId>
+        <artifactId>ruoyi-modules</artifactId>
+        <version>${revision}</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>ruoyi-workflow</artifactId>
+
+    <description>
+        宸ヤ綔娴佹ā鍧�
+    </description>
+
+    <dependencies>
+
+        <!--寮曞叆flowable渚濊禆-->
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-spring-boot-autoconfigure</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.flowable</groupId>
+                    <artifactId>flowable-spring-security</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-spring-configurator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!-- 缁樺埗flowable娴佺▼鍥� -->
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-image-generator</artifactId>
+        </dependency>
+
+        <!-- flowable json 杞崲 -->
+        <dependency>
+            <groupId>org.flowable</groupId>
+            <artifactId>flowable-json-converter</artifactId>
+            <version>6.8.0</version>
+        </dependency>
+
+        <!-- svg杞琾ng鍥剧墖宸ュ叿-->
+        <dependency>
+            <groupId>org.apache.xmlgraphics</groupId>
+            <artifactId>batik-all</artifactId>
+            <version>1.17</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>xalan</groupId>
+                    <artifactId>xalan</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-websocket</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mail</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-sms</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-log</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-idempotent</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-excel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-translation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-tenant</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.dromara</groupId>
+            <artifactId>ruoyi-common-security</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
+
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
new file mode 100644
index 0000000..c3fcafa
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java
@@ -0,0 +1,137 @@
+package org.dromara.workflow.common.constant;
+
+
+/**
+ * 宸ヤ綔娴佸父閲�
+ *
+ * @author may
+ */
+public interface FlowConstant {
+
+    String MESSAGE_CURRENT_TASK_IS_NULL = "褰撳墠浠诲姟涓嶅瓨鍦ㄦ垨浣犱笉鏄换鍔″姙鐞嗕汉锛�";
+
+    String MESSAGE_SUSPENDED = "褰撳墠浠诲姟宸叉寕璧蜂笉鍙鎵癸紒";
+
+    /**
+     * 杩炵嚎
+     */
+    String SEQUENCE_FLOW = "sequenceFlow";
+
+    /**
+     * 骞惰缃戝叧
+     */
+    String PARALLEL_GATEWAY = "parallelGateway";
+
+    /**
+     * 鎺掑畠缃戝叧
+     */
+    String EXCLUSIVE_GATEWAY = "exclusiveGateway";
+
+    /**
+     * 鍖呭惈缃戝叧
+     */
+    String INCLUSIVE_GATEWAY = "inclusiveGateway";
+
+    /**
+     * 缁撴潫鑺傜偣
+     */
+    String END_EVENT = "endEvent";
+
+
+    /**
+     * 娴佺▼濮旀淳鏍囪瘑
+     */
+    String PENDING = "PENDING";
+
+    /**
+     * 鍊欓�変汉鏍囪瘑
+     */
+    String CANDIDATE = "candidate";
+
+    /**
+     * 浼氱浠诲姟鎬绘暟
+     */
+    String NUMBER_OF_INSTANCES = "nrOfInstances";
+
+    /**
+     * 姝e湪鎵ц鐨勪細绛炬�绘暟
+     */
+    String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
+
+    /**
+     * 宸插畬鎴愮殑浼氱浠诲姟鎬绘暟
+     */
+    String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
+
+    /**
+     * 寰幆鐨勭储寮曞�硷紝鍙互浣跨敤elementIndexVariable灞炴�т慨鏀筶oopCounter鐨勫彉閲忓悕
+     */
+    String LOOP_COUNTER = "loopCounter";
+
+    String ZIP = "ZIP";
+
+    /**
+     * 涓氬姟涓庢祦绋嬪疄渚嬪叧鑱斿璞�
+     */
+    String BUSINESS_INSTANCE_DTO = "businessInstanceDTO";
+
+    /**
+     * 娴佺▼瀹氫箟閰嶇疆
+     */
+    String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo";
+
+    /**
+     * 鑺傜偣閰嶇疆
+     */
+    String WF_NODE_CONFIG_VO = "wfNodeConfigVo";
+
+    /**
+     * 娴佺▼鍙戣捣浜�
+     */
+    String INITIATOR = "initiator";
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    String PROCESS_INSTANCE_ID = "processInstanceId";
+
+    /**
+     * 涓氬姟id
+     */
+    String BUSINESS_KEY = "businessKey";
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    String PROCESS_DEFINITION_ID = "processDefinitionId";
+
+    /**
+     * 寮�鍚烦杩囪〃杈惧紡鍙橀噺
+     */
+    String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED";
+
+    /**
+     * 妯″瀷鏍囪瘑key鍛藉悕瑙勮寖姝e垯琛ㄨ揪寮�
+     */
+    String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$";
+
+    /**
+     * 鐢ㄦ埛浠诲姟
+     */
+    String USER_TASK = "userTask";
+
+    /**
+     * 浼氱
+     */
+    String MULTI_INSTANCE = "multiInstance";
+
+    /**
+     * 鏄�
+     */
+    String TRUE = "0";
+
+    /**
+     * 鍚�
+     */
+    String FALSE = "1";
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
new file mode 100644
index 0000000..083ab7b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/FormTypeEnum.java
@@ -0,0 +1,54 @@
+package org.dromara.workflow.common.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 浠诲姟鐘舵�佹灇涓�
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum FormTypeEnum {
+    /**
+     * 鑷畾涔夎〃鍗�
+     */
+    STATIC("static", "鑷畾涔夎〃鍗�"),
+    /**
+     * 鍔ㄦ�佽〃鍗�
+     */
+    DYNAMIC("dynamic", "鍔ㄦ�佽〃鍗�");
+
+    /**
+     * 绫诲瀷
+     */
+    private final String type;
+
+    /**
+     * 鎻忚堪
+     */
+    private final String desc;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     *
+     * @param formType 琛ㄥ崟绫诲瀷
+     */
+    public static String findByType(String formType) {
+        if (StringUtils.isBlank(formType)) {
+            return StrUtil.EMPTY;
+        }
+
+        return Arrays.stream(FormTypeEnum.values())
+            .filter(statusEnum -> statusEnum.getType().equals(formType))
+            .findFirst()
+            .map(FormTypeEnum::getDesc)
+            .orElse(StrUtil.EMPTY);
+    }
+}
+
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
new file mode 100644
index 0000000..a282958
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 娑堟伅绫诲瀷鏋氫妇
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum MessageTypeEnum {
+    /**
+     * 绔欏唴淇�
+     */
+    SYSTEM_MESSAGE("1", "绔欏唴淇�"),
+    /**
+     * 閭
+     */
+    EMAIL_MESSAGE("2", "閭"),
+    /**
+     * 鐭俊
+     */
+    SMS_MESSAGE("3", "鐭俊");
+
+    private final String code;
+
+    private final String desc;
+
+    private final static Map<String, MessageTypeEnum> MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length);
+
+    static {
+        for (MessageTypeEnum messageType : MessageTypeEnum.values()) {
+            MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType);
+        }
+    }
+
+    /**
+     * 鏍规嵁娑堟伅绫诲瀷 code 鑾峰彇 MessageTypeEnum
+     * @param code 娑堟伅绫诲瀷code
+     * @return MessageTypeEnum
+     */
+    public static MessageTypeEnum getByCode(String code) {
+        return MESSAGE_TYPE_ENUM_MAP.get(code);
+    }
+}
+
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
new file mode 100644
index 0000000..7b2f55c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java
@@ -0,0 +1,94 @@
+package org.dromara.workflow.common.enums;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 浠诲姟鐘舵�佹灇涓�
+ *
+ * @author may
+ */
+@Getter
+@AllArgsConstructor
+public enum TaskStatusEnum {
+    /**
+     * 鎾ら攢
+     */
+    CANCEL("cancel", "鎾ら攢"),
+    /**
+     * 閫氳繃
+     */
+    PASS("pass", "閫氳繃"),
+    /**
+     * 寰呭鏍�
+     */
+    WAITING("waiting", "寰呭鏍�"),
+    /**
+     * 浣滃簾
+     */
+    INVALID("invalid", "浣滃簾"),
+    /**
+     * 閫�鍥�
+     */
+    BACK("back", "閫�鍥�"),
+    /**
+     * 缁堟
+     */
+    TERMINATION("termination", "缁堟"),
+    /**
+     * 杞姙
+     */
+    TRANSFER("transfer", "杞姙"),
+    /**
+     * 濮旀墭
+     */
+    PENDING("pending", "濮旀墭"),
+    /**
+     * 鎶勯��
+     */
+    COPY("copy", "鎶勯��"),
+    /**
+     * 鍔犵
+     */
+    SIGN("sign", "鍔犵"),
+    /**
+     * 鍑忕
+     */
+    SIGN_OFF("sign_off", "鍑忕"),
+    /**
+     * 瓒呮椂
+     */
+    TIMEOUT("timeout", "瓒呮椂");
+
+    /**
+     * 鐘舵��
+     */
+    private final String status;
+
+    /**
+     * 鎻忚堪
+     */
+    private final String desc;
+
+    /**
+     * 浠诲姟涓氬姟鐘舵��
+     *
+     * @param status 鐘舵��
+     */
+    public static String findByStatus(String status) {
+        if (StringUtils.isBlank(status)) {
+            return StrUtil.EMPTY;
+        }
+
+        return Arrays.stream(TaskStatusEnum.values())
+            .filter(statusEnum -> statusEnum.getStatus().equals(status))
+            .findFirst()
+            .map(TaskStatusEnum::getDesc)
+            .orElse(StrUtil.EMPTY);
+    }
+}
+
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
new file mode 100644
index 0000000..842d3d6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java
@@ -0,0 +1,148 @@
+package org.dromara.workflow.controller;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.ModelBo;
+import org.dromara.workflow.domain.vo.ModelVo;
+import org.dromara.workflow.service.IActModelService;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Model;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 妯″瀷绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/model")
+public class ActModelController extends BaseController {
+
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    private final IActModelService actModelService;
+
+
+    /**
+     * 鍒嗛〉鏌ヨ妯″瀷
+     *
+     * @param modelBo 妯″瀷鍙傛暟
+     */
+    @GetMapping("/list")
+    public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) {
+        return actModelService.page(modelBo, pageQuery);
+    }
+
+    /**
+     * 鏂板妯″瀷
+     *
+     * @param modelBo 妯″瀷璇锋眰瀵硅薄
+     */
+    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/save")
+    public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
+        return toAjax(actModelService.saveNewModel(modelBo));
+    }
+
+    /**
+     * 鏌ヨ妯″瀷
+     *
+     * @param id 妯″瀷id
+     */
+    @GetMapping("/getInfo/{id}")
+    public R<ModelVo> getInfo(@NotBlank(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable String id) {
+        return R.ok(actModelService.getInfo(id));
+    }
+
+    /**
+     * 淇敼妯″瀷淇℃伅
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     */
+    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping(value = "/update")
+    public R<Void> update(@RequestBody ModelBo modelBo) {
+        return toAjax(actModelService.update(modelBo));
+    }
+
+    /**
+     * 缂栬緫XMl妯″瀷
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     */
+    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping(value = "/editModelXml")
+    public R<Void> editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) {
+        return toAjax(actModelService.editModelXml(modelBo));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼妯″瀷
+     *
+     * @param ids 妯″瀷id
+     */
+    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @DeleteMapping("/{ids}")
+    @Transactional(rollbackFor = Exception.class)
+    public R<Void> delete(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable String[] ids) {
+        Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel);
+        return R.ok();
+    }
+
+    /**
+     * 妯″瀷閮ㄧ讲
+     *
+     * @param id 妯″瀷id
+     */
+    @Log(title = "妯″瀷绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/modelDeploy/{id}")
+    public R<Void> deploy(@NotBlank(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable("id") String id) {
+        return toAjax(actModelService.modelDeploy(id));
+    }
+
+    /**
+     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
+     *
+     * @param modelIds 妯″瀷id
+     * @param response 鐩稿簲
+     */
+    @GetMapping("/export/zip/{modelIds}")
+    public void exportZip(@NotEmpty(message = "妯″瀷id涓嶈兘涓虹┖") @PathVariable List<String> modelIds,
+                          HttpServletResponse response) {
+        actModelService.exportZip(modelIds, response);
+    }
+
+    /**
+     * 澶嶅埗妯″瀷
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     */
+    @PostMapping("/copyModel")
+    public R<Void> copyModel(@RequestBody ModelBo modelBo) {
+        return toAjax(actModelService.copyModel(modelBo));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
new file mode 100644
index 0000000..5198bd1
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessDefinitionController.java
@@ -0,0 +1,147 @@
+package org.dromara.workflow.controller;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
+import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
+import org.dromara.workflow.service.IActProcessDefinitionService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 娴佺▼瀹氫箟绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/processDefinition")
+public class ActProcessDefinitionController extends BaseController {
+
+    private final IActProcessDefinitionService actProcessDefinitionService;
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     *
+     * @param bo 鍙傛暟
+     */
+    @GetMapping("/list")
+    public TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo bo, PageQuery pageQuery) {
+        return actProcessDefinitionService.page(bo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param key 娴佺▼瀹氫箟key
+     */
+    @GetMapping("/getListByKey/{key}")
+    public R<List<ProcessDefinitionVo>> getListByKey(@NotEmpty(message = "娴佺▼瀹氫箟key涓嶈兘涓虹┖") @PathVariable String key) {
+        return R.ok("鎿嶄綔鎴愬姛", actProcessDefinitionService.getListByKey(key));
+    }
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @GetMapping("/definitionImage/{processDefinitionId}")
+    public R<String> definitionImage(@PathVariable String processDefinitionId) {
+        return R.ok("鎿嶄綔鎴愬姛", actProcessDefinitionService.definitionImage(processDefinitionId));
+    }
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @GetMapping("/definitionXml/{processDefinitionId}")
+    public R<Map<String, Object>> definitionXml(@NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
+        Map<String, Object> map = new HashMap<>();
+        String xmlStr = actProcessDefinitionService.definitionXml(processDefinitionId);
+        map.put("xml", Arrays.asList(xmlStr.split("\n")));
+        map.put("xmlStr", xmlStr);
+        return R.ok(map);
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param deploymentIds        閮ㄧ讲id
+     * @param processDefinitionIds 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{deploymentIds}/{processDefinitionIds}")
+    public R<Void> deleteDeployment(@NotNull(message = "娴佺▼閮ㄧ讲id涓嶈兘涓虹┖") @PathVariable List<String> deploymentIds,
+                                    @NotNull(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable List<String> processDefinitionIds) {
+        return toAjax(actProcessDefinitionService.deleteDeployment(deploymentIds, processDefinitionIds));
+    }
+
+    /**
+     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/updateDefinitionState/{processDefinitionId}")
+    public R<Void> updateDefinitionState(@NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
+        return toAjax(actProcessDefinitionService.updateDefinitionState(processDefinitionId));
+    }
+
+    /**
+     * 杩佺Щ娴佺▼瀹氫箟
+     *
+     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
+     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
+     */
+    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/migrationDefinition/{currentProcessDefinitionId}/{fromProcessDefinitionId}")
+    public R<Void> migrationDefinition(@NotBlank(message = "褰撳墠娴佺▼瀹氫箟id") @PathVariable String currentProcessDefinitionId,
+                                       @NotBlank(message = "闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d") @PathVariable String fromProcessDefinitionId) {
+        return toAjax(actProcessDefinitionService.migrationDefinition(currentProcessDefinitionId, fromProcessDefinitionId));
+    }
+
+    /**
+     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/convertToModel/{processDefinitionId}")
+    public R<Void> convertToModel(@NotEmpty(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖") @PathVariable String processDefinitionId) {
+        return toAjax(actProcessDefinitionService.convertToModel(processDefinitionId));
+    }
+
+    /**
+     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
+     *
+     * @param file         鏂囦欢
+     * @param categoryCode 鍒嗙被
+     */
+    @Log(title = "娴佺▼瀹氫箟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping("/deployByFile")
+    public void deployByFile(@RequestParam("file") MultipartFile file, @RequestParam("categoryCode") String categoryCode) {
+        actProcessDefinitionService.deployByFile(file, categoryCode);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java
new file mode 100644
index 0000000..931b9f5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActProcessInstanceController.java
@@ -0,0 +1,160 @@
+package org.dromara.workflow.controller;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.ProcessInstanceBo;
+import org.dromara.workflow.domain.bo.ProcessInvalidBo;
+import org.dromara.workflow.domain.bo.TaskUrgingBo;
+import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
+import org.dromara.workflow.domain.vo.ProcessInstanceVo;
+import org.dromara.workflow.service.IActProcessInstanceService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴佺▼瀹炰緥绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/processInstance")
+public class ActProcessInstanceController extends BaseController {
+
+    private final IActProcessInstanceService actProcessInstanceService;
+
+    /**
+     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
+     *
+     * @param bo 鍙傛暟
+     */
+    @GetMapping("/getPageByRunning")
+    public TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) {
+        return actProcessInstanceService.getPageByRunning(bo, pageQuery);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
+     *
+     * @param bo 鍙傛暟
+     */
+    @GetMapping("/getPageByFinish")
+    public TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) {
+        return actProcessInstanceService.getPageByFinish(bo, pageQuery);
+    }
+
+    /**
+     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥�
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @GetMapping("/getHistoryImage/{businessKey}")
+    public R<String> getHistoryImage(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
+        return R.ok("鎿嶄綔鎴愬姛", actProcessInstanceService.getHistoryImage(businessKey));
+    }
+
+    /**
+     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @GetMapping("/getHistoryList/{businessKey}")
+    public R<Map<String, Object>> getHistoryList(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
+        return R.ok("鎿嶄綔鎴愬姛", actProcessInstanceService.getHistoryList(businessKey));
+    }
+
+    /**
+     * 鑾峰彇瀹℃壒璁板綍
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @GetMapping("/getHistoryRecord/{businessKey}")
+    public R<List<ActHistoryInfoVo>> getHistoryRecord(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
+        return R.ok(actProcessInstanceService.getHistoryRecord(businessKey));
+    }
+
+    /**
+     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
+     *
+     * @param processInvalidBo 鍙傛暟
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @PostMapping("/deleteRunInstance")
+    public R<Void> deleteRunInstance(@Validated(AddGroup.class) @RequestBody ProcessInvalidBo processInvalidBo) {
+        return toAjax(actProcessInstanceService.deleteRunInstance(processInvalidBo));
+    }
+
+    /**
+     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @DeleteMapping("/deleteRunAndHisInstance/{businessKeys}")
+    public R<Void> deleteRunAndHisInstance(@NotNull(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String[] businessKeys) {
+        return toAjax(actProcessInstanceService.deleteRunAndHisInstance(Arrays.asList(businessKeys)));
+    }
+
+    /**
+     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @DeleteMapping("/deleteFinishAndHisInstance/{businessKeys}")
+    public R<Void> deleteFinishAndHisInstance(@NotNull(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String[] businessKeys) {
+        return toAjax(actProcessInstanceService.deleteFinishAndHisInstance(Arrays.asList(businessKeys)));
+    }
+
+    /**
+     * 鎾ら攢娴佺▼鐢宠
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/cancelProcessApply/{businessKey}")
+    public R<Void> cancelProcessApply(@NotBlank(message = "涓氬姟id涓嶈兘涓虹┖") @PathVariable String businessKey) {
+        return toAjax(actProcessInstanceService.cancelProcessApply(businessKey));
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
+     *
+     * @param bo 鍙傛暟
+     */
+    @GetMapping("/getPageByCurrent")
+    public TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) {
+        return actProcessInstanceService.getPageByCurrent(bo, pageQuery);
+    }
+
+    /**
+     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
+     *
+     * @param taskUrgingBo 浠诲姟鍌姙
+     */
+    @Log(title = "娴佺▼瀹炰緥绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/taskUrging")
+    public R<Void> taskUrging(@RequestBody TaskUrgingBo taskUrgingBo) {
+        return toAjax(actProcessInstanceService.taskUrging(taskUrgingBo));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
new file mode 100644
index 0000000..25724b6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java
@@ -0,0 +1,295 @@
+package org.dromara.workflow.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import jakarta.validation.constraints.NotBlank;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.WfTaskBackNode;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.TaskVo;
+import org.dromara.workflow.domain.vo.VariableVo;
+import org.dromara.workflow.service.IActTaskService;
+import org.dromara.workflow.service.IWfTaskBackNodeService;
+import org.dromara.workflow.utils.QueryUtils;
+import org.flowable.engine.TaskService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠诲姟绠$悊 鎺у埗灞�
+ *
+ * @author may
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/task")
+public class ActTaskController extends BaseController {
+
+    @Autowired(required = false)
+    private TaskService taskService;
+    private final IActTaskService actTaskService;
+    private final IWfTaskBackNodeService wfTaskBackNodeService;
+
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/startWorkFlow")
+    public R<Map<String, Object>> startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) {
+        Map<String, Object> map = actTaskService.startWorkFlow(startProcessBo);
+        return R.ok("鎻愪氦鎴愬姛", map);
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/completeTask")
+    public R<Void> completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) {
+        return toAjax(actTaskService.completeTask(completeTaskBo));
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @GetMapping("/getPageByTaskWait")
+    public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        return actTaskService.getPageByTaskWait(taskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @GetMapping("/getPageByAllTaskWait")
+    public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        return actTaskService.getPageByAllTaskWait(taskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @GetMapping("/getPageByTaskFinish")
+    public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        return actTaskService.getPageByTaskFinish(taskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @GetMapping("/getPageByTaskCopy")
+    public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
+        return actTaskService.getPageByTaskCopy(taskBo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @GetMapping("/getPageByAllTaskFinish")
+    public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        return actTaskService.getPageByAllTaskFinish(taskBo, pageQuery);
+    }
+
+    /**
+     * 绛炬敹锛堟嬀鍙栵級浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/claim/{taskId}")
+    public R<Void> claimTask(@NotBlank(message = "浠诲姟id涓嶈兘涓虹┖") @PathVariable String taskId) {
+        try {
+            taskService.claim(taskId, Convert.toStr(LoginHelper.getUserId()));
+            return R.ok();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.fail("绛炬敹浠诲姟澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 褰掕繕锛堟嬀鍙栫殑锛変换鍔�
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/returnTask/{taskId}")
+    public R<Void> returnTask(@NotBlank(message = "浠诲姟id涓嶈兘涓虹┖") @PathVariable String taskId) {
+        try {
+            taskService.setAssignee(taskId, null);
+            return R.ok();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return R.fail("褰掕繕浠诲姟澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 濮旀淳浠诲姟
+     *
+     * @param delegateBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/delegateTask")
+    public R<Void> delegateTask(@Validated({AddGroup.class}) @RequestBody DelegateBo delegateBo) {
+        return toAjax(actTaskService.delegateTask(delegateBo));
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param terminationBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @PostMapping("/terminationTask")
+    public R<Void> terminationTask(@RequestBody TerminationBo terminationBo) {
+        return toAjax(actTaskService.terminationTask(terminationBo));
+    }
+
+    /**
+     * 杞姙浠诲姟
+     *
+     * @param transmitBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/transferTask")
+    public R<Void> transferTask(@Validated({AddGroup.class}) @RequestBody TransmitBo transmitBo) {
+        return toAjax(actTaskService.transferTask(transmitBo));
+    }
+
+    /**
+     * 浼氱浠诲姟鍔犵
+     *
+     * @param addMultiBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/addMultiInstanceExecution")
+    public R<Void> addMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody AddMultiBo addMultiBo) {
+        return toAjax(actTaskService.addMultiInstanceExecution(addMultiBo));
+    }
+
+    /**
+     * 浼氱浠诲姟鍑忕
+     *
+     * @param deleteMultiBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/deleteMultiInstanceExecution")
+    public R<Void> deleteMultiInstanceExecution(@Validated({AddGroup.class}) @RequestBody DeleteMultiBo deleteMultiBo) {
+        return toAjax(actTaskService.deleteMultiInstanceExecution(deleteMultiBo));
+    }
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param backProcessBo 鍙傛暟
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/backProcess")
+    public R<String> backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo backProcessBo) {
+        return R.ok("鎿嶄綔鎴愬姛", actTaskService.backProcess(backProcessBo));
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/getTaskById/{taskId}")
+    public R<TaskVo> getTaskById(@PathVariable String taskId) {
+        return R.ok(QueryUtils.getTask(taskId));
+    }
+
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIds 浠诲姟id
+     * @param userId  鍔炵悊浜篿d
+     */
+    @Log(title = "浠诲姟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping("/updateAssignee/{taskIds}/{userId}")
+    public R<Void> updateAssignee(@PathVariable String[] taskIds, @PathVariable String userId) {
+        return toAjax(actTaskService.updateAssignee(taskIds, userId));
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鍙橀噺
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/getInstanceVariable/{taskId}")
+    public R<List<VariableVo>> getProcessInstVariable(@PathVariable String taskId) {
+        return R.ok(actTaskService.getInstanceVariable(taskId));
+    }
+
+    /**
+     * 鑾峰彇鍙┏鍥炲緱浠诲姟鑺傜偣
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     */
+    @GetMapping("/getTaskNodeList/{processInstanceId}")
+    public R<List<WfTaskBackNode>> getNodeList(@PathVariable String processInstanceId) {
+        return R.ok(CollUtil.reverse(wfTaskBackNodeService.getListByInstanceId(processInstanceId)));
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/getTaskUserIdsByAddMultiInstance/{taskId}")
+    public R<String> getTaskUserIdsByAddMultiInstance(@PathVariable String taskId) {
+        return R.ok("鎿嶄綔鎴愬姛", actTaskService.getTaskUserIdsByAddMultiInstance(taskId));
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     */
+    @GetMapping("/getListByDeleteMultiInstance/{taskId}")
+    public R<List<TaskVo>> getListByDeleteMultiInstance(@PathVariable String taskId) {
+        return R.ok(actTaskService.getListByDeleteMultiInstance(taskId));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
new file mode 100644
index 0000000..e1c246f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java
@@ -0,0 +1,106 @@
+package org.dromara.workflow.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.TestLeaveBo;
+import org.dromara.workflow.domain.vo.TestLeaveVo;
+import org.dromara.workflow.service.ITestLeaveService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 璇峰亣
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/leave")
+public class TestLeaveController extends BaseController {
+
+    private final ITestLeaveService testLeaveService;
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    @SaCheckPermission("workflow:leave:list")
+    @GetMapping("/list")
+    public TableDataInfo<TestLeaveVo> list(TestLeaveBo bo, PageQuery pageQuery) {
+        return testLeaveService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭璇峰亣鍒楄〃
+     */
+    @SaCheckPermission("workflow:leave:export")
+    @Log(title = "璇峰亣", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(TestLeaveBo bo, HttpServletResponse response) {
+        List<TestLeaveVo> list = testLeaveService.queryList(bo);
+        ExcelUtil.exportExcel(list, "璇峰亣", TestLeaveVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇璇峰亣璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("workflow:leave:query")
+    @GetMapping("/{id}")
+    public R<TestLeaveVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                  @PathVariable Long id) {
+        return R.ok(testLeaveService.queryById(id));
+    }
+
+    /**
+     * 鏂板璇峰亣
+     */
+    @SaCheckPermission("workflow:leave:add")
+    @Log(title = "璇峰亣", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<TestLeaveVo> add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) {
+        return R.ok(testLeaveService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼璇峰亣
+     */
+    @SaCheckPermission("workflow:leave:edit")
+    @Log(title = "璇峰亣", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<TestLeaveVo> edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) {
+        return R.ok(testLeaveService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎璇峰亣
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("workflow:leave:remove")
+    @Log(title = "璇峰亣", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids)));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java
new file mode 100644
index 0000000..8dced89
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfCategoryController.java
@@ -0,0 +1,106 @@
+package org.dromara.workflow.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.workflow.domain.bo.WfCategoryBo;
+import org.dromara.workflow.domain.vo.WfCategoryVo;
+import org.dromara.workflow.service.IWfCategoryService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被
+ *
+ * @author may
+ * @date 2023-06-28
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/category")
+public class WfCategoryController extends BaseController {
+
+    private final IWfCategoryService wfCategoryService;
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
+     */
+    @SaCheckPermission("workflow:category:list")
+    @GetMapping("/list")
+    public R<List<WfCategoryVo>> list(WfCategoryBo bo) {
+        List<WfCategoryVo> list = wfCategoryService.queryList(bo);
+        return R.ok(list);
+
+    }
+
+    /**
+     * 瀵煎嚭娴佺▼鍒嗙被鍒楄〃
+     */
+    @SaCheckPermission("workflow:category:export")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(WfCategoryBo bo, HttpServletResponse response) {
+        List<WfCategoryVo> list = wfCategoryService.queryList(bo);
+        ExcelUtil.exportExcel(list, "娴佺▼鍒嗙被", WfCategoryVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍒嗙被璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("workflow:category:query")
+    @GetMapping("/{id}")
+    public R<WfCategoryVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                   @PathVariable Long id) {
+        return R.ok(wfCategoryService.queryById(id));
+    }
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     */
+    @SaCheckPermission("workflow:category:add")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody WfCategoryBo bo) {
+        return toAjax(wfCategoryService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     */
+    @SaCheckPermission("workflow:category:edit")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody WfCategoryBo bo) {
+        return toAjax(wfCategoryService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼鍒嗙被
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("workflow:category:remove")
+    @Log(title = "娴佺▼鍒嗙被", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(wfCategoryService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java
new file mode 100644
index 0000000..176aba2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfDefinitionConfigController.java
@@ -0,0 +1,79 @@
+package org.dromara.workflow.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.validation.constraints.*;
+import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/definitionConfig")
+public class WfDefinitionConfigController extends BaseController {
+
+    private final IWfDefinitionConfigService wfDefinitionConfigService;
+
+
+    /**
+     * 鑾峰彇娴佺▼瀹氫箟閰嶇疆璇︾粏淇℃伅
+     *
+     * @param definitionId 涓婚敭
+     */
+    @GetMapping("/getByDefId/{definitionId}")
+    public R<WfDefinitionConfigVo> getByDefId(@NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖")
+                                              @PathVariable String definitionId) {
+        return R.ok(wfDefinitionConfigService.getByDefId(definitionId));
+    }
+
+    /**
+     * 鏂板娴佺▼瀹氫箟閰嶇疆
+     */
+    @Log(title = "娴佺▼瀹氫箟閰嶇疆", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping("/saveOrUpdate")
+    public R<Void> saveOrUpdate(@Validated(AddGroup.class) @RequestBody WfDefinitionConfigBo bo) {
+        return toAjax(wfDefinitionConfigService.saveOrUpdate(bo));
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @Log(title = "娴佺▼瀹氫箟閰嶇疆", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(wfDefinitionConfigService.deleteByIds(List.of(ids)));
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
+     *
+     * @param tableName    琛ㄥ悕
+     * @param definitionId 娴佺▼瀹氫箟id
+     */
+    @GetMapping("/getByTableNameNotDefId/{tableName}/{definitionId}")
+    public R<List<WfDefinitionConfigVo>> getByTableNameNotDefId(@NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖") @PathVariable String tableName,
+                                                                @NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖") @PathVariable String definitionId) {
+        return R.ok(wfDefinitionConfigService.getByTableNameNotDefId(tableName, definitionId));
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java
new file mode 100644
index 0000000..198e233
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/WfFormManageController.java
@@ -0,0 +1,114 @@
+package org.dromara.workflow.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.workflow.domain.vo.WfFormManageVo;
+import org.dromara.workflow.domain.bo.WfFormManageBo;
+import org.dromara.workflow.service.IWfFormManageService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 琛ㄥ崟绠$悊
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/workflow/formManage")
+public class WfFormManageController extends BaseController {
+
+    private final IWfFormManageService wfFormManageService;
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     */
+    @SaCheckPermission("workflow:formManage:list")
+    @GetMapping("/list")
+    public TableDataInfo<WfFormManageVo> list(WfFormManageBo bo, PageQuery pageQuery) {
+        return wfFormManageService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     */
+    @SaCheckPermission("workflow:formManage:list")
+    @GetMapping("/list/selectList")
+    public R<List<WfFormManageVo>> selectList() {
+        return R.ok(wfFormManageService.selectList());
+    }
+
+    /**
+     * 瀵煎嚭琛ㄥ崟绠$悊鍒楄〃
+     */
+    @SaCheckPermission("workflow:formManage:export")
+    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(WfFormManageBo bo, HttpServletResponse response) {
+        List<WfFormManageVo> list = wfFormManageService.queryList(bo);
+        ExcelUtil.exportExcel(list, "琛ㄥ崟绠$悊", WfFormManageVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇琛ㄥ崟绠$悊璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("workflow:formManage:query")
+    @GetMapping("/{id}")
+    public R<WfFormManageVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(wfFormManageService.queryById(id));
+    }
+
+    /**
+     * 鏂板琛ㄥ崟绠$悊
+     */
+    @SaCheckPermission("workflow:formManage:add")
+    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody WfFormManageBo bo) {
+        return toAjax(wfFormManageService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼琛ㄥ崟绠$悊
+     */
+    @SaCheckPermission("workflow:formManage:edit")
+    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody WfFormManageBo bo) {
+        return toAjax(wfFormManageService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎琛ㄥ崟绠$悊
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("workflow:formManage:remove")
+    @Log(title = "琛ㄥ崟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(wfFormManageService.deleteByIds(List.of(ids)));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java
new file mode 100644
index 0000000..e87fb92
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiProcinst.java
@@ -0,0 +1,152 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 娴佺▼瀹炰緥瀵硅薄 act_hi_procinst
+ *
+ * @author may
+ * @date 2023-07-22
+ */
+@Data
+@TableName("act_hi_procinst")
+public class ActHiProcinst implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "ID_")
+    private String id;
+
+    /**
+     *
+     */
+    @TableField(value = "REV_")
+    private Long rev;
+
+    /**
+     *
+     */
+    @TableField(value = "PROC_INST_ID_")
+    private String procInstId;
+
+    /**
+     *
+     */
+    @TableField(value = "BUSINESS_KEY_")
+    private String businessKey;
+
+    /**
+     *
+     */
+    @TableField(value = "PROC_DEF_ID_")
+    private String procDefId;
+
+    /**
+     *
+     */
+    @TableField(value = "START_TIME_")
+    private Date startTime;
+
+    /**
+     *
+     */
+    @TableField(value = "END_TIME_")
+    private Date endTime;
+
+    /**
+     *
+     */
+    @TableField(value = "DURATION_")
+    private Long duration;
+
+    /**
+     *
+     */
+    @TableField(value = "START_USER_ID_")
+    private String startUserId;
+
+    /**
+     *
+     */
+    @TableField(value = "START_ACT_ID_")
+    private String startActId;
+
+    /**
+     *
+     */
+    @TableField(value = "END_ACT_ID_")
+    private String endActId;
+
+    /**
+     *
+     */
+    @TableField(value = "SUPER_PROCESS_INSTANCE_ID_")
+    private String superProcessInstanceId;
+
+    /**
+     *
+     */
+    @TableField(value = "DELETE_REASON_")
+    private String deleteReason;
+
+    /**
+     *
+     */
+    @TableField(value = "TENANT_ID_")
+    private String tenantId;
+
+    /**
+     *
+     */
+    @TableField(value = "NAME_")
+    private String name;
+
+    /**
+     *
+     */
+    @TableField(value = "CALLBACK_ID_")
+    private String callbackId;
+
+    /**
+     *
+     */
+    @TableField(value = "CALLBACK_TYPE_")
+    private String callbackType;
+
+    /**
+     *
+     */
+    @TableField(value = "REFERENCE_ID_")
+    private String referenceId;
+
+    /**
+     *
+     */
+    @TableField(value = "REFERENCE_TYPE_")
+    private String referenceType;
+
+    /**
+     *
+     */
+    @TableField(value = "PROPAGATED_STAGE_INST_ID_")
+    private String propagatedStageInstId;
+
+    /**
+     *
+     */
+    @TableField(value = "BUSINESS_STATUS_")
+    private String businessStatus;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java
new file mode 100644
index 0000000..abc17b5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/ActHiTaskinst.java
@@ -0,0 +1,193 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import java.io.Serial;
+
+/**
+ * 娴佺▼鍘嗗彶浠诲姟瀵硅薄 act_hi_taskinst
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+@Data
+@TableName("act_hi_taskinst")
+public class ActHiTaskinst implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "ID_")
+    private String id;
+
+    /**
+     * 鐗堟湰
+     */
+    @TableField(value = "REV_")
+    private Long rev;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    @TableField(value = "PROC_DEF_ID_")
+    private String procDefId;
+
+    /**
+     *
+     */
+    @TableField(value = "TASK_DEF_ID_")
+    private String taskDefId;
+
+    /**
+     * 浠诲姟鑺傜偣id
+     */
+    @TableField(value = "TASK_DEF_KEY_")
+    private String taskDefKey;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    @TableField(value = "PROC_INST_ID_")
+    private String procInstId;
+
+    /**
+     * 娴佺▼鎵цid
+     */
+    @TableField(value = "EXECUTION_ID")
+    private String executionId;
+
+    /**
+     *
+     */
+    @TableField(value = "SCOPE_ID_")
+    private String scopeId;
+
+    /**
+     *
+     */
+    @TableField(value = "SUB_SCOPE_ID_")
+    private String subScopeId;
+
+    /**
+     * 鍏堢敤褰撳墠瀛楁鏍囪瘑鎶勯�佺被鍨�
+     */
+    @TableField(value = "SCOPE_TYPE_")
+    private String scopeType;
+
+    /**
+     *
+     */
+    @TableField(value = "SCOPE_DEFINITION_ID_")
+    private String scopeDefinitionId;
+
+    /**
+     *
+     */
+    @TableField(value = "PROPAGATED_STAGE_INST_ID_")
+    private String propagatedStageInstId;
+
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    @TableField(value = "NAME_")
+    private String name;
+
+    /**
+     * 鐖剁骇id
+     */
+    @TableField(value = "PARENT_TASK_ID_")
+    private String parentTaskId;
+
+    /**
+     * 鎻忚堪
+     */
+    @TableField(value = "DESCRIPTION_")
+    private String description;
+
+    /**
+     * 鍔炵悊浜�
+     */
+    @TableField(value = "OWNER_")
+    private String owner;
+
+    /**
+     * 鍔炵悊浜�
+     */
+    @TableField(value = "ASSIGNEE_")
+    private String assignee;
+
+    /**
+     * 寮�濮嬩簨浠�
+     */
+    @TableField(value = "START_TIME_")
+    private Date startTime;
+
+    /**
+     * 璁ら鏃堕棿
+     */
+    @TableField(value = "CLAIM_TIME_")
+    private Date claimTime;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    @TableField(value = "END_TIME_")
+    private Date endTime;
+
+    /**
+     * 鎸佺画鏃堕棿
+     */
+    @TableField(value = "DURATION_")
+    private Long duration;
+
+    /**
+     * 鍒犻櫎鍘熷洜
+     */
+    @TableField(value = "DELETE_REASON_")
+    private String deleteReason;
+
+    /**
+     * 浼樺厛绾�
+     */
+    @TableField(value = "PRIORITY_")
+    private Long priority;
+
+    /**
+     * 鍒版湡鏃堕棿
+     */
+    @TableField(value = "DUE_DATE_")
+    private Date dueDate;
+
+    /**
+     *
+     */
+    @TableField(value = "FORM_KEY_")
+    private String formKey;
+
+    /**
+     * 鍒嗙被
+     */
+    @TableField(value = "CATEGORY_")
+    private String category;
+
+    /**
+     * 鏈�鍚庝慨鏀规椂闂�
+     */
+    @TableField(value = "LAST_UPDATED_TIME_")
+    private Date lastUpdatedTime;
+
+    /**
+     * 绉熸埛id
+     */
+    @TableField(value = "TENANT_ID_")
+    private String tenantId;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java
new file mode 100644
index 0000000..7d42a9b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java
@@ -0,0 +1,63 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 璇峰亣瀵硅薄 test_leave
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("test_leave")
+public class TestLeave extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 璇峰亣绫诲瀷
+     */
+    private String leaveType;
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    private Date startDate;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private Date endDate;
+
+    /**
+     * 璇峰亣澶╂暟
+     */
+    private Integer leaveDays;
+
+    /**
+     * 璇峰亣鍘熷洜
+     */
+    private String remark;
+
+    /**
+     * 鐘舵��
+     */
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java
new file mode 100644
index 0000000..94a7cf5
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfCategory.java
@@ -0,0 +1,52 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 娴佺▼鍒嗙被瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("wf_category")
+public class WfCategory extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 鍒嗙被鍚嶇О
+     */
+    private String categoryName;
+
+    /**
+     * 鍒嗙被缂栫爜
+     */
+    private String categoryCode;
+
+    /**
+     * 鐖剁骇id
+     */
+    private Long parentId;
+
+    /**
+     * 鎺掑簭
+     */
+    private Long sortNum;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java
new file mode 100644
index 0000000..11dcaa0
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfDefinitionConfig.java
@@ -0,0 +1,56 @@
+package org.dromara.workflow.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆瀵硅薄 wf_definition_config
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("wf_definition_config")
+public class WfDefinitionConfig extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 琛ㄥ悕
+     */
+    private String tableName;
+
+    /**
+     * 娴佺▼瀹氫箟ID
+     */
+    private String definitionId;
+
+    /**
+     * 娴佺▼KEY
+     */
+    private String processKey;
+
+    /**
+     * 娴佺▼鐗堟湰
+     */
+    private Integer version;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java
new file mode 100644
index 0000000..47f0d7a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfFormManage.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 琛ㄥ崟绠$悊瀵硅薄 wf_form_manage
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("wf_form_manage")
+public class WfFormManage extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 琛ㄥ崟鍚嶇О
+     */
+    private String formName;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    private String formType;
+
+    /**
+     * 璺敱鍦板潃/琛ㄥ崟ID
+     */
+    private String router;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java
new file mode 100644
index 0000000..999425f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfNodeConfig.java
@@ -0,0 +1,61 @@
+package org.dromara.workflow.domain;
+
+import org.dromara.common.tenant.core.TenantEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 鑺傜偣閰嶇疆瀵硅薄 wf_node_config
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("wf_node_config")
+public class WfNodeConfig extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 琛ㄥ崟id
+     */
+    private Long formId;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    private String formType;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 鑺傜偣id
+     */
+    private String nodeId;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    private String definitionId;
+
+    /**
+     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
+     */
+    private String applyUserTask;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java
new file mode 100644
index 0000000..6f59727
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/WfTaskBackNode.java
@@ -0,0 +1,61 @@
+package org.dromara.workflow.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 鑺傜偣椹冲洖璁板綍 wf_task_back_node
+ *
+ * @author may
+ * @date 2024-03-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("wf_task_back_node")
+public class WfTaskBackNode extends TenantEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 瀹炰緥id
+     */
+    private String instanceId;
+
+    /**
+     * 鑺傜偣id
+     */
+    private String nodeId;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    private String nodeName;
+
+    /**
+     * 鎺掑簭
+     */
+    private Integer orderNo;
+
+    /**
+     * 鑺傜偣绫诲瀷
+     */
+    private String taskType;
+
+    /**
+     * 鍔炵悊浜�
+     */
+    private String assignee;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java
new file mode 100644
index 0000000..320ec64
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/AddMultiBo.java
@@ -0,0 +1,40 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 鍔犵鍙傛暟璇锋眰
+ *
+ * @author may
+ */
+@Data
+public class AddMultiBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟ID
+     */
+    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String taskId;
+
+    /**
+     * 鍔犵浜哄憳id
+     */
+    @NotEmpty(message = "鍔犵浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<Long> assignees;
+
+    /**
+     * 鍔犵浜哄憳鍚嶇О
+     */
+    @NotEmpty(message = "鍔犵浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<String> assigneeNames;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java
new file mode 100644
index 0000000..d0f4369
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java
@@ -0,0 +1,44 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+
+/**
+ * 椹冲洖鍙傛暟璇锋眰
+ *
+ * @author may
+ */
+@Data
+public class BackProcessBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟ID
+     */
+    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String taskId;
+
+    /**
+     * 娑堟伅绫诲瀷
+     */
+    private List<String> messageType;
+
+    /**
+     * 椹冲洖鐨勮妭鐐筰d(鐩墠鏈娇鐢紝鐩存帴椹冲洖鍒扮敵璇蜂汉)
+     */
+    @NotBlank(message = "椹冲洖鐨勮妭鐐逛笉鑳戒负绌�", groups = AddGroup.class)
+    private String targetActivityId;
+
+    /**
+     * 鍔炵悊鎰忚
+     */
+    private String message;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java
new file mode 100644
index 0000000..0623905
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java
@@ -0,0 +1,65 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.workflow.domain.vo.WfCopy;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 鍔炵悊浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class CompleteTaskBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟id
+     */
+    @NotBlank(message = "浠诲姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String taskId;
+
+    /**
+     * 闄勪欢id
+     */
+    private String fileId;
+
+    /**
+     * 鎶勯�佷汉鍛�
+     */
+    private List<WfCopy> wfCopyList;
+
+    /**
+     * 娑堟伅绫诲瀷
+     */
+    private List<String> messageType;
+
+    /**
+     * 鍔炵悊鎰忚
+     */
+    private String message;
+
+    /**
+     * 娴佺▼鍙橀噺
+     */
+    private Map<String, Object> variables;
+
+    public Map<String, Object> getVariables() {
+        if (variables == null) {
+            return new HashMap<>(16);
+        }
+        variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
+        return variables;
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java
new file mode 100644
index 0000000..a6846a6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DelegateBo.java
@@ -0,0 +1,38 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 濮旀淳浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class DelegateBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 濮旀淳浜篿d
+     */
+    @NotBlank(message = "濮旀淳浜篿d涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String userId;
+
+    /**
+     * 濮旀淳浜哄悕绉�
+     */
+    @NotBlank(message = "濮旀淳浜哄悕绉颁笉鑳戒负绌�", groups = {AddGroup.class})
+    private String nickName;
+
+    /**
+     * 浠诲姟id
+     */
+    @NotBlank(message = "浠诲姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String taskId;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java
new file mode 100644
index 0000000..e533167
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/DeleteMultiBo.java
@@ -0,0 +1,52 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 鍑忕鍙傛暟璇锋眰
+ *
+ * @author may
+ */
+@Data
+public class DeleteMultiBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟ID
+     */
+    @NotBlank(message = "浠诲姟ID涓嶈兘涓虹┖", groups = AddGroup.class)
+    private String taskId;
+
+    /**
+     * 鍑忕浜哄憳
+     */
+    @NotEmpty(message = "鍑忕浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<String> taskIds;
+
+    /**
+     * 鎵цid
+     */
+    @NotEmpty(message = "鎵цid涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<String> executionIds;
+
+    /**
+     * 浜哄憳id
+     */
+    @NotEmpty(message = "鍑忕浜哄憳id涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<Long> assigneeIds;
+
+    /**
+     * 浜哄憳鍚嶇О
+     */
+    @NotEmpty(message = "鍑忕浜哄憳涓嶈兘涓虹┖", groups = AddGroup.class)
+    private List<String> assigneeNames;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java
new file mode 100644
index 0000000..efe9acd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ModelBo.java
@@ -0,0 +1,66 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.workflow.common.constant.FlowConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 妯″瀷璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class ModelBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 妯″瀷id
+     */
+    @NotBlank(message = "妯″瀷ID涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private String id;
+
+    /**
+     * 妯″瀷鍚嶇О
+     */
+    @NotBlank(message = "妯″瀷鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String name;
+
+    /**
+     * 妯″瀷鏍囪瘑key
+     */
+    @NotBlank(message = "妯″瀷鏍囪瘑key涓嶈兘涓虹┖", groups = {AddGroup.class})
+    @Pattern(regexp = FlowConstant.MODEL_KEY_PATTERN, message = "妯″瀷鏍囪瘑key鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶�", groups = {AddGroup.class})
+    private String key;
+
+    /**
+     * 妯″瀷鍒嗙被
+     */
+    @NotBlank(message = "妯″瀷鍒嗙被涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String categoryCode;
+
+    /**
+     * 妯″瀷XML
+     */
+    @NotBlank(message = "妯″瀷XML涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String xml;
+
+    /**
+     * 妯″瀷SVG鍥剧墖
+     */
+    @NotBlank(message = "妯″瀷SVG涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private String svg;
+
+    /**
+     * 澶囨敞
+     */
+    private String description;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java
new file mode 100644
index 0000000..2025932
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessDefinitionBo.java
@@ -0,0 +1,34 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 娴佺▼瀹氫箟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class ProcessDefinitionBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇Оkey
+     */
+    private String key;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 妯″瀷鍒嗙被
+     */
+    private String categoryCode;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java
new file mode 100644
index 0000000..2833b3e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInstanceBo.java
@@ -0,0 +1,43 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 娴佺▼瀹炰緥璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class ProcessInstanceBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 娴佺▼key
+     */
+    private String key;
+
+    /**
+     * 浠诲姟鍙戣捣浜�
+     */
+    private String startUserId;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessKey;
+
+    /**
+     * 妯″瀷鍒嗙被
+     */
+    private String categoryCode;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java
new file mode 100644
index 0000000..41e51c2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/ProcessInvalidBo.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 娴佺▼瀹炰緥浣滃簾璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class ProcessInvalidBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓氬姟id
+     */
+    @NotBlank(message = "涓氬姟id涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String businessKey;
+
+    /**
+     * 浣滃簾鍘熷洜
+     */
+    private String deleteReason;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java
new file mode 100644
index 0000000..7af7935
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java
@@ -0,0 +1,49 @@
+package org.dromara.workflow.domain.bo;
+
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 鍚姩娴佺▼瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class StartProcessBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓氬姟鍞竴鍊糹d
+     */
+    @NotBlank(message = "涓氬姟ID涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String businessKey;
+
+    /**
+     * 琛ㄥ悕
+     */
+    @NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String tableName;
+
+    /**
+     * 娴佺▼鍙橀噺锛屽墠绔細鎻愪氦涓�涓厓绱爗'entity': {涓氬姟璇︽儏鏁版嵁瀵硅薄}}
+     */
+    private Map<String, Object> variables;
+
+    public Map<String, Object> getVariables() {
+        if (variables == null) {
+            return new HashMap<>(16);
+        }
+        variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue()));
+        return variables;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java
new file mode 100644
index 0000000..e4d99e4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/SysUserMultiBo.java
@@ -0,0 +1,39 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 鐢ㄦ埛鍔犵鏌ヨ
+ *
+ * @author may
+ */
+@Data
+public class SysUserMultiBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浜哄憳鍚嶇О
+     */
+    private String userName;
+
+    /**
+     * 浜哄憳鍚嶇О
+     */
+    private String nickName;
+
+    /**
+     * 閮ㄩ棬id
+     */
+    private String deptId;
+
+    /**
+     * 浠诲姟id
+     */
+    private String taskId;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java
new file mode 100644
index 0000000..3037479
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskBo.java
@@ -0,0 +1,33 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class TaskBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String processDefinitionName;
+
+    /**
+     * 娴佺▼瀹氫箟key
+     */
+    private String processDefinitionKey;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java
new file mode 100644
index 0000000..20856ef
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskUrgingBo.java
@@ -0,0 +1,34 @@
+package org.dromara.workflow.domain.bo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 浠诲姟鍌姙
+ *
+ * @author may
+ */
+@Data
+public class TaskUrgingBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private String processInstanceId;
+
+    /**
+     * 娑堟伅绫诲瀷
+     */
+    private List<String> messageType;
+
+    /**
+     * 鍌姙鍐呭锛堜负绌洪粯璁ょ郴缁熷唴缃俊鎭級
+     */
+    private String message;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java
new file mode 100644
index 0000000..8f2206e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TerminationBo.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 缁堟浠诲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class TerminationBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟id
+     */
+    @NotBlank(message = "浠诲姟id涓虹┖", groups = AddGroup.class)
+    private String taskId;
+
+    /**
+     * 瀹℃壒鎰忚
+     */
+    private String comment;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
new file mode 100644
index 0000000..877e981
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java
@@ -0,0 +1,80 @@
+package org.dromara.workflow.domain.bo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.workflow.domain.TestLeave;
+
+import java.util.Date;
+
+/**
+ * 璇峰亣涓氬姟瀵硅薄 test_leave
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false)
+public class TestLeaveBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 璇峰亣绫诲瀷
+     */
+    @NotBlank(message = "璇峰亣绫诲瀷涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String leaveType;
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    @NotNull(message = "寮�濮嬫椂闂翠笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date startDate;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    @NotNull(message = "缁撴潫鏃堕棿涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endDate;
+
+    /**
+     * 璇峰亣澶╂暟
+     */
+    @NotNull(message = "璇峰亣澶╂暟涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Integer leaveDays;
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    private Integer startLeaveDays;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private Integer endLeaveDays;
+
+    /**
+     * 璇峰亣鍘熷洜
+     */
+    private String remark;
+
+    /**
+     * 鐘舵��
+     */
+    private String status;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java
new file mode 100644
index 0000000..3eb6609
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TransmitBo.java
@@ -0,0 +1,37 @@
+package org.dromara.workflow.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.dromara.common.core.validate.AddGroup;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 缁堣浆鍔炲姟璇锋眰瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class TransmitBo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟id
+     */
+    @NotBlank(message = "浠诲姟id涓虹┖", groups = AddGroup.class)
+    private String taskId;
+
+    /**
+     * 杞姙浜篿d
+     */
+    @NotBlank(message = "杞姙浜轰笉鑳戒负绌�", groups = AddGroup.class)
+    private String userId;
+
+    /**
+     * 瀹℃壒鎰忚
+     */
+    private String comment;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java
new file mode 100644
index 0000000..69608fd
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfCategoryBo.java
@@ -0,0 +1,54 @@
+package org.dromara.workflow.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.workflow.domain.WfCategory;
+
+/**
+ * 娴佺▼鍒嗙被涓氬姟瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = WfCategory.class, reverseConvertGenerate = false)
+public class WfCategoryBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 鍒嗙被鍚嶇О
+     */
+    @NotBlank(message = "鍒嗙被鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String categoryName;
+
+    /**
+     * 鍒嗙被缂栫爜
+     */
+    @NotBlank(message = "鍒嗙被缂栫爜涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String categoryCode;
+
+    /**
+     * 鐖剁骇id
+     */
+    @NotNull(message = "鐖剁骇id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private Long parentId;
+
+    /**
+     * 鎺掑簭
+     */
+    private Long sortNum;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java
new file mode 100644
index 0000000..fac1770
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfDefinitionConfigBo.java
@@ -0,0 +1,59 @@
+package org.dromara.workflow.domain.bo;
+
+import org.dromara.workflow.domain.WfDefinitionConfig;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆涓氬姟瀵硅薄 wf_form_definition
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = WfDefinitionConfig.class, reverseConvertGenerate = false)
+public class WfDefinitionConfigBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 琛ㄥ悕
+     */
+    @NotBlank(message = "琛ㄥ悕涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String tableName;
+
+    /**
+     * 娴佺▼瀹氫箟ID
+     */
+    @NotBlank(message = "娴佺▼瀹氫箟ID涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String definitionId;
+
+    /**
+     * 娴佺▼KEY
+     */
+    @NotBlank(message = "娴佺▼KEY涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private String processKey;
+
+    /**
+     * 娴佺▼鐗堟湰
+     */
+    @NotNull(message = "娴佺▼鐗堟湰涓嶈兘涓虹┖", groups = {AddGroup.class})
+    private Integer version;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java
new file mode 100644
index 0000000..8afc286
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfFormManageBo.java
@@ -0,0 +1,53 @@
+package org.dromara.workflow.domain.bo;
+
+import org.dromara.workflow.domain.WfFormManage;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 琛ㄥ崟绠$悊涓氬姟瀵硅薄 wf_form_manage
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = WfFormManage.class, reverseConvertGenerate = false)
+public class WfFormManageBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 琛ㄥ崟鍚嶇О
+     */
+    @NotBlank(message = "琛ㄥ崟鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String formName;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    @NotBlank(message = "琛ㄥ崟绫诲瀷涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String formType;
+    /**
+     * 璺敱鍦板潃/琛ㄥ崟ID
+     */
+    @NotBlank(message = "璺敱鍦板潃/琛ㄥ崟ID涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String router;
+
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java
new file mode 100644
index 0000000..de518d3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/WfNodeConfigBo.java
@@ -0,0 +1,63 @@
+package org.dromara.workflow.domain.bo;
+
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 鑺傜偣閰嶇疆涓氬姟瀵硅薄 wf_node_config
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = WfNodeConfig.class, reverseConvertGenerate = false)
+public class WfNodeConfigBo extends BaseEntity {
+
+    /**
+     * 涓婚敭
+     */
+    @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = {EditGroup.class})
+    private Long id;
+
+    /**
+     * 琛ㄥ崟id
+     */
+    private Long formId;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    private String formType;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    @NotBlank(message = "鑺傜偣鍚嶇О涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String nodeName;
+
+    /**
+     * 鑺傜偣id
+     */
+    @NotBlank(message = "鑺傜偣id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String nodeId;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    @NotBlank(message = "娴佺▼瀹氫箟id涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String definitionId;
+
+    /**
+     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
+     */
+    @NotBlank(message = "鏄惁涓虹敵璇蜂汉鑺傜偣涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+    private String applyUserTask;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java
new file mode 100644
index 0000000..e4c1142
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ActHistoryInfoVo.java
@@ -0,0 +1,93 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.flowable.engine.task.Attachment;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹℃壒璁板綍瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class ActHistoryInfoVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * 浠诲姟id
+     */
+    private String id;
+    /**
+     * 鑺傜偣id
+     */
+    private String taskDefinitionKey;
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String name;
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private String processInstanceId;
+    /**
+     * 鐗堟湰
+     */
+    private Integer version;
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    private Date startTime;
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private Date endTime;
+    /**
+     * 杩愯鏃堕暱
+     */
+    private String runDuration;
+    /**
+     * 鐘舵��
+     */
+    private String status;
+    /**
+     * 鐘舵��
+     */
+    private String statusName;
+    /**
+     * 鍔炵悊浜篿d
+     */
+    private String assignee;
+
+    /**
+     * 鍔炵悊浜哄悕绉�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee")
+    private String nickName;
+
+    /**
+     * 鍔炵悊浜篿d
+     */
+    private String owner;
+
+    /**
+     * 瀹℃壒淇℃伅id
+     */
+    private String commentId;
+
+    /**
+     * 瀹℃壒淇℃伅
+     */
+    private String comment;
+
+    /**
+     * 瀹℃壒闄勪欢
+     */
+    private List<Attachment> attachmentList;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java
new file mode 100644
index 0000000..7636131
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/GraphicInfoVo.java
@@ -0,0 +1,47 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鑺傜偣鍥惧舰淇℃伅
+ *
+ * @author may
+ */
+@Data
+public class GraphicInfoVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * x鍧愭爣
+     */
+    private double x;
+
+    /**
+     * y鍧愭爣
+     */
+    private double y;
+
+    /**
+     * 鑺傜偣楂樺害
+     */
+    private double height;
+
+    /**
+     * 鑺傜偣瀹藉害
+     */
+    private double width;
+
+    /**
+     * 鑺傜偣id
+     */
+    private String nodeId;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    private String nodeName;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java
new file mode 100644
index 0000000..b2ce811
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ModelVo.java
@@ -0,0 +1,48 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 妯″瀷瑙嗗浘瀵硅薄
+ *
+ * @author may
+ */
+@Data
+public class ModelVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 妯″瀷id
+     */
+    private String id;
+
+    /**
+     * 妯″瀷鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 妯″瀷鏍囪瘑key
+     */
+    private String key;
+
+    /**
+     * 妯″瀷鍒嗙被
+     */
+    private String categoryCode;
+
+    /**
+     * 妯″瀷XML
+     */
+    private String xml;
+
+    /**
+     * 澶囨敞
+     */
+    private String description;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java
new file mode 100644
index 0000000..b998396
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/MultiInstanceVo.java
@@ -0,0 +1,33 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 澶氬疄渚嬩俊鎭�
+ *
+ * @author may
+ */
+@Data
+public class MultiInstanceVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浼氱绫诲瀷锛堜覆琛岋紝骞惰锛�
+     */
+    private Object type;
+
+    /**
+     * 浼氱浜哄憳KEY
+     */
+    private String assignee;
+
+    /**
+     * 浼氱浜哄憳闆嗗悎KEY
+     */
+    private String assigneeList;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java
new file mode 100644
index 0000000..c5876f6
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ParticipantVo.java
@@ -0,0 +1,43 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 鍙備笌鑰�
+ *
+ * @author may
+ */
+@Data
+public class ParticipantVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 缁刬d锛堣鑹瞚d锛�
+     */
+    private List<Long> groupIds;
+
+    /**
+     * 鍊欓�変汉id锛堢敤鎴穒d锛� 褰撶粍id涓嶄负绌烘椂锛屽皢缁勫唴浜哄憳鏌ュ嚭鏀惧叆candidate
+     */
+    private List<Long> candidate;
+
+    /**
+     * 鍊欓�変汉鍚嶇О锛堢敤鎴峰悕绉帮級 褰撶粍id涓嶄负绌烘椂锛屽皢缁勫唴浜哄憳鏌ュ嚭鏀惧叆candidateName
+     */
+    private List<String> candidateName;
+
+    /**
+     * 鏄惁璁ら鏍囪瘑
+     * 褰撲负绌烘椂榛樿褰撳墠浠诲姟涓嶉渶瑕佽棰�
+     * 褰撲负true鏃跺綋鍓嶄换鍔¤鏄庝负鍊欓�夋ā寮忓苟涓旀湁浜哄凡缁忚棰嗕簡浠诲姟鍙互褰掕繕锛�
+     * 褰撲负false鏃跺綋鍓嶄换鍔¤鏄庝负鍊欓�夋ā寮忚浠诲姟鏈棰嗭紝
+     */
+    private Boolean claim;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java
new file mode 100644
index 0000000..034adbb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessDefinitionVo.java
@@ -0,0 +1,70 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 娴佺▼瀹氫箟瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class ProcessDefinitionVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    private String id;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 娴佺▼瀹氫箟鏍囪瘑key
+     */
+    private String key;
+
+    /**
+     * 娴佺▼瀹氫箟鐗堟湰
+     */
+    private int version;
+
+    /**
+     * 娴佺▼瀹氫箟鎸傝捣鎴栨縺娲� 1婵�娲� 2鎸傝捣
+     */
+    private int suspensionState;
+
+    /**
+     * 娴佺▼xml鍚嶇О
+     */
+    private String resourceName;
+
+    /**
+     * 娴佺▼鍥剧墖鍚嶇О
+     */
+    private String diagramResourceName;
+
+    /**
+     * 娴佺▼閮ㄧ讲id
+     */
+    private String deploymentId;
+
+    /**
+     * 娴佺▼閮ㄧ讲鏃堕棿
+     */
+    private Date deploymentTime;
+
+    /**
+     * 娴佺▼瀹氫箟閰嶇疆
+     */
+    private WfDefinitionConfigVo wfDefinitionConfigVo;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java
new file mode 100644
index 0000000..ab3e7a1
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ProcessInstanceVo.java
@@ -0,0 +1,100 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹炰緥瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class ProcessInstanceVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private String id;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    private String processDefinitionId;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String processDefinitionName;
+
+    /**
+     * 娴佺▼瀹氫箟key
+     */
+    private String processDefinitionKey;
+
+    /**
+     * 娴佺▼瀹氫箟鐗堟湰
+     */
+    private Integer processDefinitionVersion;
+
+    /**
+     * 閮ㄧ讲id
+     */
+    private String deploymentId;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessKey;
+
+    /**
+     * 鏄惁鎸傝捣
+     */
+    private Boolean isSuspended;
+
+    /**
+     * 绉熸埛id
+     */
+    private String tenantId;
+
+    /**
+     * 鍚姩鏃堕棿
+     */
+    private Date startTime;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private Date endTime;
+
+    /**
+     * 鍚姩浜篿d
+     */
+    private String startUserId;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String businessStatus;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String businessStatusName;
+
+    /**
+     * 寰呭姙浠诲姟闆嗗悎
+     */
+    private List<TaskVo> taskVoList;
+
+    /**
+     * 鑺傜偣閰嶇疆
+     */
+    private WfNodeConfigVo wfNodeConfigVo;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java
new file mode 100644
index 0000000..466e776
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TaskVo.java
@@ -0,0 +1,173 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 浠诲姟瑙嗗浘
+ *
+ * @author may
+ */
+@Data
+public class TaskVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 浠诲姟id
+     */
+    private String id;
+
+    /**
+     * 浠诲姟鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 鎻忚堪
+     */
+    private String description;
+
+    /**
+     * 浼樺厛绾�
+     */
+    private Integer priority;
+
+    /**
+     * 璐熻矗姝や换鍔$殑浜哄憳鐨勭敤鎴穒d
+     */
+    private String owner;
+
+    /**
+     * 鍔炵悊浜篿d
+     */
+    private Long assignee;
+
+    /**
+     * 鍔炵悊浜�
+     */
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "assignee")
+    private String assigneeName;
+
+
+    /**
+     * 娴佺▼瀹炰緥id
+     */
+    private String processInstanceId;
+
+    /**
+     * 鎵цid
+     */
+    private String executionId;
+
+    /**
+     * 鏃犵敤
+     */
+    private String taskDefinitionId;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    private String processDefinitionId;
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    private Date createTime;
+
+    /**
+     * 宸插姙浠诲姟-鍒涘缓鏃堕棿
+     */
+    private Date startTime;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    private Date endTime;
+
+    /**
+     * 鑺傜偣id
+     */
+    private String taskDefinitionKey;
+
+    /**
+     * 浠诲姟鎴鏃ユ湡
+     */
+    private Date dueDate;
+
+    /**
+     * 娴佺▼绫诲埆
+     */
+    private String category;
+
+    /**
+     * 鐖剁骇浠诲姟id
+     */
+    private String parentTaskId;
+
+    /**
+     * 绉熸埛id
+     */
+    private String tenantId;
+
+    /**
+     * 璁ら鏃堕棿
+     */
+    private Date claimTime;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String businessStatus;
+
+    /**
+     * 娴佺▼鐘舵��
+     */
+    private String businessStatusName;
+
+    /**
+     * 娴佺▼瀹氫箟鍚嶇О
+     */
+    private String processDefinitionName;
+
+    /**
+     * 娴佺▼瀹氫箟key
+     */
+    private String processDefinitionKey;
+
+    /**
+     * 娴佺▼瀹氫箟鐗堟湰
+     */
+    private Integer processDefinitionVersion;
+
+    /**
+     * 鍙備笌鑰�
+     */
+    private ParticipantVo participantVo;
+
+    /**
+     * 鏄惁浼氱
+     */
+    private Boolean multiInstance;
+
+    /**
+     * 涓氬姟id
+     */
+    private String businessKey;
+
+    /**
+     * 娴佺▼瀹氫箟閰嶇疆
+     */
+    private WfDefinitionConfigVo wfDefinitionConfigVo;
+
+    /**
+     * 鑺傜偣閰嶇疆
+     */
+    private WfNodeConfigVo wfNodeConfigVo;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java
new file mode 100644
index 0000000..47886d7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java
@@ -0,0 +1,70 @@
+package org.dromara.workflow.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.workflow.domain.TestLeave;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 璇峰亣瑙嗗浘瀵硅薄 test_leave
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = TestLeave.class)
+public class TestLeaveVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 璇峰亣绫诲瀷
+     */
+    @ExcelProperty(value = "璇峰亣绫诲瀷")
+    private String leaveType;
+
+    /**
+     * 寮�濮嬫椂闂�
+     */
+    @ExcelProperty(value = "寮�濮嬫椂闂�")
+    private Date startDate;
+
+    /**
+     * 缁撴潫鏃堕棿
+     */
+    @ExcelProperty(value = "缁撴潫鏃堕棿")
+    private Date endDate;
+
+    /**
+     * 璇峰亣澶╂暟
+     */
+    @ExcelProperty(value = "璇峰亣澶╂暟")
+    private Integer leaveDays;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "璇峰亣鍘熷洜")
+    private String remark;
+
+    /**
+     * 鐘舵��
+     */
+    @ExcelProperty(value = "鐘舵��")
+    private String status;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java
new file mode 100644
index 0000000..6a26c82
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/VariableVo.java
@@ -0,0 +1,28 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 娴佺▼鍙橀噺
+ *
+ * @author may
+ */
+@Data
+public class VariableVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鍙橀噺key
+     */
+    private String key;
+
+    /**
+     * 鍙橀噺鍊�
+     */
+    private String value;
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java
new file mode 100644
index 0000000..362f646
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCategoryVo.java
@@ -0,0 +1,58 @@
+package org.dromara.workflow.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.workflow.domain.WfCategory;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 娴佺▼鍒嗙被瑙嗗浘瀵硅薄 wf_category
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = WfCategory.class)
+public class WfCategoryVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 鍒嗙被鍚嶇О
+     */
+    @ExcelProperty(value = "鍒嗙被鍚嶇О")
+    private String categoryName;
+
+    /**
+     * 鍒嗙被缂栫爜
+     */
+    @ExcelProperty(value = "鍒嗙被缂栫爜")
+    private String categoryCode;
+
+    /**
+     * 鐖剁骇id
+     */
+    @ExcelProperty(value = "鐖剁骇id")
+    private Long parentId;
+
+    /**
+     * 鎺掑簭
+     */
+    @ExcelProperty(value = "鎺掑簭")
+    private Long sortNum;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
new file mode 100644
index 0000000..88a5a21
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfCopy.java
@@ -0,0 +1,29 @@
+package org.dromara.workflow.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鎶勯��
+ *
+ * @author may
+ */
+@Data
+public class WfCopy implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛id
+     */
+    private Long userId;
+
+    /**
+     * 鐢ㄦ埛鍚嶇О
+     */
+    private String userName;
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java
new file mode 100644
index 0000000..9c7b0d7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfDefinitionConfigVo.java
@@ -0,0 +1,70 @@
+package org.dromara.workflow.domain.vo;
+
+import org.dromara.workflow.domain.WfDefinitionConfig;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆瑙嗗浘瀵硅薄 wf_definition_config
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = WfDefinitionConfig.class)
+public class WfDefinitionConfigVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 琛ㄥ悕
+     */
+    @ExcelProperty(value = "琛ㄥ悕")
+    private String tableName;
+
+    /**
+     * 娴佺▼瀹氫箟ID
+     */
+    @ExcelProperty(value = "娴佺▼瀹氫箟ID")
+    private String definitionId;
+
+    /**
+     * 娴佺▼KEY
+     */
+    @ExcelProperty(value = "娴佺▼KEY")
+    private String processKey;
+
+
+    /**
+     * 娴佺▼鐗堟湰
+     */
+    @ExcelProperty(value = "娴佺▼鐗堟湰")
+    private Integer version;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+    /**
+     * 琛ㄥ崟绠$悊
+     */
+    private WfFormManageVo wfFormManageVo;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java
new file mode 100644
index 0000000..302df23
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfFormManageVo.java
@@ -0,0 +1,63 @@
+package org.dromara.workflow.domain.vo;
+
+import org.dromara.workflow.domain.WfFormManage;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 琛ㄥ崟绠$悊瑙嗗浘瀵硅薄 wf_form_manage
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = WfFormManage.class)
+public class WfFormManageVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 琛ㄥ崟鍚嶇О
+     */
+    @ExcelProperty(value = "琛ㄥ崟鍚嶇О")
+    private String formName;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    @ExcelProperty(value = "琛ㄥ崟绫诲瀷")
+    private String formType;
+
+    /**
+     * 琛ㄥ崟绫诲瀷鍚嶇О
+     */
+    private String formTypeName;
+
+    /**
+     * 璺敱鍦板潃/琛ㄥ崟ID
+     */
+    @ExcelProperty(value = "璺敱鍦板潃/琛ㄥ崟ID")
+    private String router;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java
new file mode 100644
index 0000000..89e9d9b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/WfNodeConfigVo.java
@@ -0,0 +1,75 @@
+package org.dromara.workflow.domain.vo;
+
+import org.dromara.workflow.domain.WfNodeConfig;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 鑺傜偣閰嶇疆瑙嗗浘瀵硅薄 wf_node_config
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = WfNodeConfig.class)
+public class WfNodeConfigVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 涓婚敭
+     */
+    @ExcelProperty(value = "涓婚敭")
+    private Long id;
+
+    /**
+     * 琛ㄥ崟id
+     */
+    @ExcelProperty(value = "琛ㄥ崟id")
+    private Long formId;
+
+    /**
+     * 琛ㄥ崟绫诲瀷
+     */
+    @ExcelProperty(value = "琛ㄥ崟绫诲瀷")
+    private String formType;
+
+    /**
+     * 鑺傜偣鍚嶇О
+     */
+    @ExcelProperty(value = "鑺傜偣鍚嶇О")
+    private String nodeName;
+
+    /**
+     * 鑺傜偣id
+     */
+    @ExcelProperty(value = "鑺傜偣id")
+    private String nodeId;
+
+    /**
+     * 娴佺▼瀹氫箟id
+     */
+    @ExcelProperty(value = "娴佺▼瀹氫箟id")
+    private String definitionId;
+
+    /**
+     * 鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級
+     */
+    @ExcelProperty(value = "鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級")
+    private String applyUserTask;
+
+    /**
+     * 琛ㄥ崟绠$悊
+     */
+    private WfFormManageVo wfFormManageVo;
+
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java
new file mode 100644
index 0000000..39fd9d3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramCanvas.java
@@ -0,0 +1,108 @@
+package org.dromara.workflow.flowable;
+
+import org.flowable.bpmn.model.AssociationDirection;
+import org.flowable.image.impl.DefaultProcessDiagramCanvas;
+
+import java.awt.*;
+import java.awt.geom.Line2D;
+import java.awt.geom.RoundRectangle2D;
+
+public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
+    //璁剧疆楂樹寒绾跨殑棰滆壊  杩欓噷鎴戣缃垚缁胯壊
+    protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
+
+    public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
+        super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+    }
+
+    /**
+     * 鐢荤嚎棰滆壊璁剧疆
+     */
+    public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
+                               AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
+
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+
+        g.setPaint(CONNECTION_COLOR);
+        if (connectionType.equals("association")) {
+            g.setStroke(ASSOCIATION_STROKE);
+        } else if (highLighted) {
+            //璁剧疆绾跨殑棰滆壊
+            g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR);
+            g.setStroke(HIGHLIGHT_FLOW_STROKE);
+        }
+
+        for (int i = 1; i < xPoints.length; i++) {
+            Integer sourceX = xPoints[i - 1];
+            Integer sourceY = yPoints[i - 1];
+            Integer targetX = xPoints[i];
+            Integer targetY = yPoints[i];
+            Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
+            g.draw(line);
+        }
+
+        if (isDefault) {
+            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
+            drawDefaultSequenceFlowIndicator(line, scaleFactor);
+        }
+
+        if (conditional) {
+            Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
+            drawConditionalSequenceFlowIndicator(line, scaleFactor);
+        }
+
+        if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
+            Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
+            drawArrowHead(line, scaleFactor);
+        }
+        if (associationDirection == AssociationDirection.BOTH) {
+            Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
+            drawArrowHead(line, scaleFactor);
+        }
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+    /**
+     * 楂樹寒鑺傜偣璁剧疆
+     */
+    public void drawHighLight(int x, int y, int width, int height) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+        //璁剧疆楂樹寒鑺傜偣鐨勯鑹�
+        g.setPaint(HIGHLIGHT_COLOR);
+        g.setStroke(THICK_TASK_BORDER_STROKE);
+
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+        g.draw(rect);
+
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+    /**
+     * @description: 楂樹寒鑺傜偣绾㈣壊
+     * @param: x
+     * @param: y
+     * @param: width
+     * @param: height
+     * @return: void
+     * @author: gssong
+     * @date: 2022/4/12
+     */
+    public void drawHighLightRed(int x, int y, int width, int height) {
+        Paint originalPaint = g.getPaint();
+        Stroke originalStroke = g.getStroke();
+        //璁剧疆楂樹寒鑺傜偣鐨勯鑹�
+        g.setPaint(Color.green);
+        g.setStroke(THICK_TASK_BORDER_STROKE);
+
+        RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
+        g.draw(rect);
+
+        g.setPaint(originalPaint);
+        g.setStroke(originalStroke);
+    }
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java
new file mode 100644
index 0000000..e4793a2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/CustomDefaultProcessDiagramGenerator.java
@@ -0,0 +1,1120 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.workflow.flowable;
+
+import org.flowable.bpmn.model.Event;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+import org.flowable.image.ProcessDiagramGenerator;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.InputStream;
+import java.util.List;
+import java.util.*;
+
+/**
+ * Class to generate an image based the diagram interchange information in a BPMN 2.0 process.
+ *
+ * @author Joram Barrez
+ * @author Tijs Rademakers
+ * @author Zheng Ji
+ */
+public class CustomDefaultProcessDiagramGenerator implements ProcessDiagramGenerator {
+
+    protected Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>();
+    protected Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>();
+
+    public CustomDefaultProcessDiagramGenerator() {
+        this(1.0);
+    }
+
+    // The instructions on how to draw a certain construct is
+    // created statically and stored in a map for performance.
+    public CustomDefaultProcessDiagramGenerator(final double scaleFactor) {
+        // start event
+        activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                StartEvent startEvent = (StartEvent) flowNode;
+                if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) {
+                    EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
+                    if (eventDefinition instanceof TimerEventDefinition) {
+                        processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor);
+                    } else if (eventDefinition instanceof ErrorEventDefinition) {
+                        processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor);
+                    } else if (eventDefinition instanceof EscalationEventDefinition) {
+                        processDiagramCanvas.drawEscalationStartEvent(graphicInfo, scaleFactor);
+                    } else if (eventDefinition instanceof ConditionalEventDefinition) {
+                        processDiagramCanvas.drawConditionalStartEvent(graphicInfo, scaleFactor);
+                    } else if (eventDefinition instanceof SignalEventDefinition) {
+                        processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor);
+                    } else if (eventDefinition instanceof MessageEventDefinition) {
+                        processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor);
+                    } else {
+                        processDiagramCanvas.drawNoneStartEvent(graphicInfo);
+                    }
+                } else {
+                    List<ExtensionElement> eventTypeElements = startEvent.getExtensionElements().get("eventType");
+                    if (eventTypeElements != null && eventTypeElements.size() > 0) {
+                        processDiagramCanvas.drawEventRegistryStartEvent(graphicInfo, scaleFactor);
+
+                    } else {
+                        processDiagramCanvas.drawNoneStartEvent(graphicInfo);
+                    }
+                }
+            }
+        });
+
+        // signal catch
+        activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode;
+                if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions().isEmpty()) {
+
+                    if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
+                        processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
+                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
+                        processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
+                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
+                        processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
+                    } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof ConditionalEventDefinition) {
+                        processDiagramCanvas.drawCatchingConditionalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
+                    }
+                }
+            }
+        });
+
+        // signal throw
+        activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                ThrowEvent throwEvent = (ThrowEvent) flowNode;
+                if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) {
+                    if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
+                        processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor);
+                    } else if (throwEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) {
+                        processDiagramCanvas.drawThrowingEscalationEvent(graphicInfo, scaleFactor);
+                    } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
+                        processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor);
+                    } else {
+                        processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
+                    }
+                } else {
+                    processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
+                }
+            }
+        });
+
+        // end event
+        activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                EndEvent endEvent = (EndEvent) flowNode;
+                if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) {
+                    if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
+                        processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
+                    } else if (endEvent.getEventDefinitions().get(0) instanceof EscalationEventDefinition) {
+                        processDiagramCanvas.drawEscalationEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
+                    } else {
+                        processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
+                    }
+                } else {
+                    processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
+                }
+            }
+        });
+
+        // task
+        activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // user task
+        activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // script task
+        activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // service task
+        activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                ServiceTask serviceTask = (ServiceTask) flowNode;
+                if ("camel".equalsIgnoreCase(serviceTask.getType())) {
+                    processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor);
+                }else if (ServiceTask.HTTP_TASK.equalsIgnoreCase(serviceTask.getType())) {
+                    processDiagramCanvas.drawHttpTask(serviceTask.getName(), graphicInfo, scaleFactor);
+                } else if (ServiceTask.DMN_TASK.equalsIgnoreCase(serviceTask.getType())) {
+                    processDiagramCanvas.drawDMNTask(serviceTask.getName(), graphicInfo, scaleFactor);
+                } else if (ServiceTask.SHELL_TASK.equalsIgnoreCase(serviceTask.getType())) {
+                    processDiagramCanvas.drawShellTask(serviceTask.getName(), graphicInfo, scaleFactor);
+                } else {
+                    processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
+                }
+            }
+        });
+
+        // http service task
+        activityDrawInstructions.put(HttpServiceTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawHttpTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // receive task
+        activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // send task
+        activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // manual task
+        activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // send event service task
+        activityDrawInstructions.put(SendEventServiceTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawSendEventServiceTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // external worker service task
+        activityDrawInstructions.put(ExternalWorkerServiceTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                ServiceTask serviceTask = (ServiceTask) flowNode;
+                processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // case service task
+        activityDrawInstructions.put(CaseServiceTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawCaseServiceTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // businessRuleTask task
+        activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // exclusive gateway
+        activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor);
+            }
+        });
+
+        // inclusive gateway
+        activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor);
+            }
+        });
+
+        // parallel gateway
+        activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor);
+            }
+        });
+
+        // event based gateway
+        activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor);
+            }
+        });
+
+        // Boundary timer
+        activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode;
+                if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) {
+                    EventDefinition eventDefinition = boundaryEvent.getEventDefinitions().get(0);
+                    if (eventDefinition instanceof TimerEventDefinition) {
+                        processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof ConditionalEventDefinition) {
+                        processDiagramCanvas.drawCatchingConditionalEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof ErrorEventDefinition) {
+                        processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof EscalationEventDefinition) {
+                        processDiagramCanvas.drawCatchingEscalationEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof SignalEventDefinition) {
+                        processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof MessageEventDefinition) {
+                        processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+
+                    } else if (eventDefinition instanceof CompensateEventDefinition) {
+                        processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+                    }
+
+                } else {
+                    List<ExtensionElement> eventTypeElements = boundaryEvent.getExtensionElements().get("eventType");
+                    if (eventTypeElements != null && eventTypeElements.size() > 0) {
+                        processDiagramCanvas.drawCatchingEventRegistryEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
+                    }
+                }
+            }
+        });
+
+        // subprocess
+        activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
+                } else {
+                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
+                }
+            }
+        });
+
+        // transaction
+        activityDrawInstructions.put(Transaction.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
+                } else {
+                    processDiagramCanvas.drawExpandedTransaction(flowNode.getName(), graphicInfo, scaleFactor);
+                }
+            }
+        });
+
+        // Event subprocess
+        activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
+                } else {
+                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
+                }
+            }
+        });
+
+        // Adhoc subprocess
+        activityDrawInstructions.put(AdhocSubProcess.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                    processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
+                } else {
+                    processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
+                }
+            }
+        });
+
+        // call activity
+        activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+                processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // text annotation
+        artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
+                TextAnnotation textAnnotation = (TextAnnotation) artifact;
+                processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo, scaleFactor);
+            }
+        });
+
+        // association
+        artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() {
+
+            @Override
+            public void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
+                Association association = (Association) artifact;
+                String sourceRef = association.getSourceRef();
+                String targetRef = association.getTargetRef();
+
+                // source and target can be instance of FlowElement or Artifact
+                BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef);
+                BaseElement targetElement = bpmnModel.getFlowElement(targetRef);
+                if (sourceElement == null) {
+                    sourceElement = bpmnModel.getArtifact(sourceRef);
+                }
+                if (targetElement == null) {
+                    targetElement = bpmnModel.getArtifact(targetRef);
+                }
+                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
+                graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
+                int[] xPoints = new int[graphicInfoList.size()];
+                int[] yPoints = new int[graphicInfoList.size()];
+                for (int i = 1; i < graphicInfoList.size(); i++) {
+                    GraphicInfo graphicInfo = graphicInfoList.get(i);
+                    GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
+
+                    if (i == 1) {
+                        xPoints[0] = (int) previousGraphicInfo.getX();
+                        yPoints[0] = (int) previousGraphicInfo.getY();
+                    }
+                    xPoints[i] = (int) graphicInfo.getX();
+                    yPoints[i] = (int) graphicInfo.getY();
+                }
+
+                AssociationDirection associationDirection = association.getAssociationDirection();
+                processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor);
+            }
+        });
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
+                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
+            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateImage(imageType);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType,
+                                       List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
+                                       String labelFontName, String annotationFontName, ClassLoader customClassLoader, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(),
+            activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
+                                       String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(),
+            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generatePngDiagram(BpmnModel bpmnModel, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generatePngDiagram(bpmnModel, 1.0, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public InputStream generateJpgDiagram(BpmnModel bpmnModel) {
+        return generateJpgDiagram(bpmnModel, 1.0, false);
+    }
+
+    @Override
+    public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+        return generateDiagram(bpmnModel, "jpg", Collections.emptyList(), Collections.emptyList(), drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
+                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
+            activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, drawSequenceFlowNameWithNoLabelDI).generateBufferedImage(imageType);
+    }
+
+    public BufferedImage generateImage(BpmnModel bpmnModel, String imageType,
+                                       List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+    }
+
+    @Override
+    public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) {
+        return generateImage(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(), scaleFactor, false);
+    }
+
+    protected CustomDefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
+                                                                       List<String> highLightedActivities, List<String> highLightedFlows,
+                                                                       String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        prepareBpmnModel(bpmnModel);
+
+        CustomDefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+
+        // Draw pool shape, if process is participant in collaboration
+        for (Pool pool : bpmnModel.getPools()) {
+            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
+            processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo, scaleFactor);
+        }
+
+        // Draw lanes
+        for (Process process : bpmnModel.getProcesses()) {
+            for (Lane lane : process.getLanes()) {
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
+                processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo, scaleFactor);
+            }
+        }
+
+        // Draw activities and their sequence-flows
+        for (Process process : bpmnModel.getProcesses()) {
+            for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
+                if (!isPartOfCollapsedSubProcess(flowNode, bpmnModel)) {
+                    drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+                }
+            }
+        }
+
+        // Draw artifacts
+        for (Process process : bpmnModel.getProcesses()) {
+
+            for (Artifact artifact : process.getArtifacts()) {
+                drawArtifact(processDiagramCanvas, bpmnModel, artifact);
+            }
+
+            List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
+            if (subProcesses != null) {
+                for (SubProcess subProcess : subProcesses) {
+
+                    GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(subProcess.getId());
+                    if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                        continue;
+                    }
+
+                    if (!isPartOfCollapsedSubProcess(subProcess, bpmnModel)) {
+                        for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
+                            drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
+                        }
+                    }
+                }
+            }
+        }
+
+        return processDiagramCanvas;
+    }
+
+    protected void prepareBpmnModel(BpmnModel bpmnModel) {
+
+        // Need to make sure all elements have positive x and y.
+        // Check all graphicInfo and update the elements accordingly
+
+        List<GraphicInfo> allGraphicInfos = new ArrayList<>();
+        if (bpmnModel.getLocationMap() != null) {
+            allGraphicInfos.addAll(bpmnModel.getLocationMap().values());
+        }
+        if (bpmnModel.getLabelLocationMap() != null) {
+            allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values());
+        }
+        if (bpmnModel.getFlowLocationMap() != null) {
+            for (List<GraphicInfo> flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) {
+                allGraphicInfos.addAll(flowGraphicInfos);
+            }
+        }
+
+        if (allGraphicInfos.size() > 0) {
+
+            boolean needsTranslationX = false;
+            boolean needsTranslationY = false;
+
+            double lowestX = 0.0;
+            double lowestY = 0.0;
+
+            // Collect lowest x and y
+            for (GraphicInfo graphicInfo : allGraphicInfos) {
+
+                double x = graphicInfo.getX();
+                double y = graphicInfo.getY();
+
+                if (x < lowestX) {
+                    needsTranslationX = true;
+                    lowestX = x;
+                }
+                if (y < lowestY) {
+                    needsTranslationY = true;
+                    lowestY = y;
+                }
+
+            }
+
+            // Update all graphicInfo objects
+            if (needsTranslationX || needsTranslationY) {
+
+                double translationX = Math.abs(lowestX);
+                double translationY = Math.abs(lowestY);
+
+                for (GraphicInfo graphicInfo : allGraphicInfos) {
+                    if (needsTranslationX) {
+                        graphicInfo.setX(graphicInfo.getX() + translationX);
+                    }
+                    if (needsTranslationY) {
+                        graphicInfo.setY(graphicInfo.getY() + translationY);
+                    }
+                }
+            }
+
+        }
+
+    }
+
+    protected void drawActivity(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
+                                FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) {
+
+        ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
+        if (drawInstruction != null) {
+
+            drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
+
+            // Gather info on the multi instance marker
+            boolean multiInstanceSequential = false;
+            boolean multiInstanceParallel = false;
+            boolean collapsed = false;
+            if (flowNode instanceof Activity) {
+                Activity activity = (Activity) flowNode;
+                MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
+                if (multiInstanceLoopCharacteristics != null) {
+                    multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
+                    multiInstanceParallel = !multiInstanceSequential;
+                }
+            }
+
+            // Gather info on the collapsed marker
+            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+            if (flowNode instanceof SubProcess) {
+                collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
+            } else if (flowNode instanceof CallActivity) {
+                collapsed = true;
+            }
+
+            if (scaleFactor == 1.0) {
+                // Actually draw the markers
+                processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
+                    multiInstanceSequential, multiInstanceParallel, collapsed);
+            }
+
+            // Draw highlighted activities
+            if (highLightedActivities.contains(flowNode.getId())) {
+                drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+            } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) {
+                drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+            }
+
+        } else if (flowNode instanceof Task) {
+            activityDrawInstructions.get(Task.class).draw(processDiagramCanvas, bpmnModel, flowNode);
+
+            if (highLightedActivities.contains(flowNode.getId())) {
+                drawHighLightRed(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+            } else if (highLightedActivities.contains(Color.RED.toString() + flowNode.getId())) {
+                drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
+            }
+        }
+
+        // Outgoing transitions of activity
+        for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
+            boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
+            String defaultFlow = null;
+            if (flowNode instanceof Activity) {
+                defaultFlow = ((Activity) flowNode).getDefaultFlow();
+            } else if (flowNode instanceof Gateway) {
+                defaultFlow = ((Gateway) flowNode).getDefaultFlow();
+            }
+
+            boolean isDefault = false;
+            if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
+                isDefault = true;
+            }
+            boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && sequenceFlow.getConditionExpression().trim().length() > 0 && !(flowNode instanceof Gateway);
+
+            String sourceRef = sequenceFlow.getSourceRef();
+            String targetRef = sequenceFlow.getTargetRef();
+            FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
+            FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
+            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
+            if (graphicInfoList != null && graphicInfoList.size() > 0) {
+                graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
+                int[] xPoints = new int[graphicInfoList.size()];
+                int[] yPoints = new int[graphicInfoList.size()];
+
+                for (int i = 1; i < graphicInfoList.size(); i++) {
+                    GraphicInfo graphicInfo = graphicInfoList.get(i);
+                    GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
+
+                    if (i == 1) {
+                        xPoints[0] = (int) previousGraphicInfo.getX();
+                        yPoints[0] = (int) previousGraphicInfo.getY();
+                    }
+                    xPoints[i] = (int) graphicInfo.getX();
+                    yPoints[i] = (int) graphicInfo.getY();
+
+                }
+
+                processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
+
+                // Draw sequenceflow label
+                GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
+                if (labelGraphicInfo != null) {
+                    processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
+                } else {
+                    if (drawSequenceFlowNameWithNoLabelDI) {
+                        GraphicInfo lineCenter = getLineCenter(graphicInfoList);
+                        processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
+                    }
+
+                }
+            }
+        }
+
+        // Nested elements
+        if (flowNode instanceof FlowElementsContainer) {
+            for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
+                if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) {
+                    drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
+                        highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI);
+                }
+            }
+        }
+    }
+
+    /**
+     * This method makes coordinates of connection flow better.
+     *
+     * @param processDiagramCanvas
+     * @param bpmnModel
+     * @param sourceElement
+     * @param targetElement
+     * @param graphicInfoList
+     * @return
+     */
+    protected static List<GraphicInfo> connectionPerfectionizer(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List<GraphicInfo> graphicInfoList) {
+        GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId());
+        GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId());
+
+        CustomDefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement);
+        CustomDefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement);
+
+        return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList);
+    }
+
+    /**
+     * This method returns shape type of base element.<br>
+     * Each element can be presented as rectangle, rhombus, or ellipse.
+     *
+     * @param baseElement
+     * @return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE
+     */
+    protected static CustomDefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) {
+        if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) {
+            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle;
+        } else if (baseElement instanceof Gateway) {
+            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus;
+        } else if (baseElement instanceof Event) {
+            return CustomDefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse;
+        } else {
+            // unknown source element, just do not correct coordinates
+        }
+        return null;
+    }
+
+    protected static GraphicInfo getLineCenter(List<GraphicInfo> graphicInfoList) {
+        GraphicInfo gi = new GraphicInfo();
+
+        int[] xPoints = new int[graphicInfoList.size()];
+        int[] yPoints = new int[graphicInfoList.size()];
+
+        double length = 0;
+        double[] lengths = new double[graphicInfoList.size()];
+        lengths[0] = 0;
+        double m;
+        for (int i = 1; i < graphicInfoList.size(); i++) {
+            GraphicInfo graphicInfo = graphicInfoList.get(i);
+            GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
+
+            if (i == 1) {
+                xPoints[0] = (int) previousGraphicInfo.getX();
+                yPoints[0] = (int) previousGraphicInfo.getY();
+            }
+            xPoints[i] = (int) graphicInfo.getX();
+            yPoints[i] = (int) graphicInfo.getY();
+
+            length += Math.sqrt(
+                Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) +
+                    Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2));
+            lengths[i] = length;
+        }
+        m = length / 2;
+        int p1 = 0;
+        int p2 = 1;
+        for (int i = 1; i < lengths.length; i++) {
+            double len = lengths[i];
+            p1 = i - 1;
+            p2 = i;
+            if (len > m) {
+                break;
+            }
+        }
+
+        GraphicInfo graphicInfo1 = graphicInfoList.get(p1);
+        GraphicInfo graphicInfo2 = graphicInfoList.get(p2);
+
+        double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX();
+        double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY();
+        double OB = lengths[p2] - lengths[p1];
+        double ob = m - lengths[p1];
+        double ab = AB * ob / OB;
+        double oa = OA * ob / OB;
+
+        double mx = graphicInfo1.getX() + ab;
+        double my = graphicInfo1.getY() + oa;
+
+        gi.setX(mx);
+        gi.setY(my);
+        return gi;
+    }
+
+    protected void drawArtifact(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
+
+        ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass());
+        if (drawInstruction != null) {
+            drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact);
+        }
+    }
+
+    private static void drawHighLight(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
+        processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
+
+    }
+
+    private static void drawHighLightRed(CustomDefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
+        processDiagramCanvas.drawHighLightRed((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
+
+    }
+
+    protected static CustomDefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
+                                                                                String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
+
+        // We need to calculate maximum values to know how big the image will be in its entirety
+        double minX = Double.MAX_VALUE;
+        double maxX = 0;
+        double minY = Double.MAX_VALUE;
+        double maxY = 0;
+
+        for (Pool pool : bpmnModel.getPools()) {
+            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
+            minX = graphicInfo.getX();
+            maxX = graphicInfo.getX() + graphicInfo.getWidth();
+            minY = graphicInfo.getY();
+            maxY = graphicInfo.getY() + graphicInfo.getHeight();
+        }
+
+        List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
+        for (FlowNode flowNode : flowNodes) {
+
+            GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
+
+            // width
+            if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
+                maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
+            }
+            if (flowNodeGraphicInfo.getX() < minX) {
+                minX = flowNodeGraphicInfo.getX();
+            }
+            // height
+            if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
+                maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
+            }
+            if (flowNodeGraphicInfo.getY() < minY) {
+                minY = flowNodeGraphicInfo.getY();
+            }
+
+            for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
+                List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
+                if (graphicInfoList != null) {
+                    for (GraphicInfo graphicInfo : graphicInfoList) {
+                        // width
+                        if (graphicInfo.getX() > maxX) {
+                            maxX = graphicInfo.getX();
+                        }
+                        if (graphicInfo.getX() < minX) {
+                            minX = graphicInfo.getX();
+                        }
+                        // height
+                        if (graphicInfo.getY() > maxY) {
+                            maxY = graphicInfo.getY();
+                        }
+                        if (graphicInfo.getY() < minY) {
+                            minY = graphicInfo.getY();
+                        }
+                    }
+                }
+            }
+        }
+
+        List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
+        for (Artifact artifact : artifacts) {
+
+            GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
+
+            if (artifactGraphicInfo != null) {
+                // width
+                if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
+                    maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
+                }
+                if (artifactGraphicInfo.getX() < minX) {
+                    minX = artifactGraphicInfo.getX();
+                }
+                // height
+                if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
+                    maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
+                }
+                if (artifactGraphicInfo.getY() < minY) {
+                    minY = artifactGraphicInfo.getY();
+                }
+            }
+
+            List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
+            if (graphicInfoList != null) {
+                for (GraphicInfo graphicInfo : graphicInfoList) {
+                    // width
+                    if (graphicInfo.getX() > maxX) {
+                        maxX = graphicInfo.getX();
+                    }
+                    if (graphicInfo.getX() < minX) {
+                        minX = graphicInfo.getX();
+                    }
+                    // height
+                    if (graphicInfo.getY() > maxY) {
+                        maxY = graphicInfo.getY();
+                    }
+                    if (graphicInfo.getY() < minY) {
+                        minY = graphicInfo.getY();
+                    }
+                }
+            }
+        }
+
+        int nrOfLanes = 0;
+        for (Process process : bpmnModel.getProcesses()) {
+            for (Lane l : process.getLanes()) {
+
+                nrOfLanes++;
+
+                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
+                // // width
+                if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
+                    maxX = graphicInfo.getX() + graphicInfo.getWidth();
+                }
+                if (graphicInfo.getX() < minX) {
+                    minX = graphicInfo.getX();
+                }
+                // height
+                if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
+                    maxY = graphicInfo.getY() + graphicInfo.getHeight();
+                }
+                if (graphicInfo.getY() < minY) {
+                    minY = graphicInfo.getY();
+                }
+            }
+        }
+
+        // Special case, see https://activiti.atlassian.net/browse/ACT-1431
+        if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
+            // Nothing to show
+            minX = 0;
+            minY = 0;
+        }
+
+        return new CustomDefaultProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
+            imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
+    }
+
+    protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
+        List<Artifact> artifacts = new ArrayList<>();
+        for (Process process : bpmnModel.getProcesses()) {
+            artifacts.addAll(process.getArtifacts());
+        }
+        return artifacts;
+    }
+
+    protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
+        List<FlowNode> flowNodes = new ArrayList<>();
+        for (Process process : bpmnModel.getProcesses()) {
+            flowNodes.addAll(gatherAllFlowNodes(process));
+        }
+        return flowNodes;
+    }
+
+    protected static List<FlowNode> gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) {
+        List<FlowNode> flowNodes = new ArrayList<>();
+        for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
+            if (flowElement instanceof FlowNode) {
+                flowNodes.add((FlowNode) flowElement);
+            }
+            if (flowElement instanceof FlowElementsContainer) {
+                flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
+            }
+        }
+        return flowNodes;
+    }
+
+    protected boolean isPartOfCollapsedSubProcess(FlowElement flowElement, BpmnModel model) {
+        SubProcess subProcess = flowElement.getSubProcess();
+        if (subProcess != null) {
+            GraphicInfo graphicInfo = model.getGraphicInfo(subProcess.getId());
+            if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
+                return true;
+            }
+
+            return isPartOfCollapsedSubProcess(subProcess, model);
+        }
+
+        return false;
+    }
+
+    public Map<Class<? extends BaseElement>, ActivityDrawInstruction> getActivityDrawInstructions() {
+        return activityDrawInstructions;
+    }
+
+    public void setActivityDrawInstructions(
+        Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions) {
+        this.activityDrawInstructions = activityDrawInstructions;
+    }
+
+    public Map<Class<? extends BaseElement>, ArtifactDrawInstruction> getArtifactDrawInstructions() {
+        return artifactDrawInstructions;
+    }
+
+    public void setArtifactDrawInstructions(
+        Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions) {
+        this.artifactDrawInstructions = artifactDrawInstructions;
+    }
+
+    protected interface ActivityDrawInstruction {
+        void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode);
+    }
+
+    protected interface ArtifactDrawInstruction {
+        void draw(CustomDefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java
new file mode 100644
index 0000000..3cdfcf4
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AddSequenceMultiInstanceCmd.java
@@ -0,0 +1,61 @@
+package org.dromara.workflow.flowable.cmd;
+
+import cn.hutool.core.collection.CollUtil;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
+
+/**
+ * 涓茶鍔犵
+ *
+ * @author may
+ */
+public class AddSequenceMultiInstanceCmd implements Command<Void> {
+
+    /**
+     * 鎵цid
+     */
+    private final String executionId;
+
+    /**
+     * 浼氱浜哄憳闆嗗悎KEY
+     */
+    private final String assigneeList;
+
+    /**
+     * 鍔犵浜哄憳
+     */
+    private final List<Long> assignees;
+
+    public AddSequenceMultiInstanceCmd(String executionId, String assigneeList, List<Long> assignees) {
+        this.executionId = executionId;
+        this.assigneeList = assigneeList;
+        this.assignees = assignees;
+    }
+
+    @Override
+    public Void execute(CommandContext commandContext) {
+        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
+        ExecutionEntity entity = executionEntityManager.findById(executionId);
+        // 澶氬疄渚嬩换鍔℃�绘暟鍔� assignees.size()
+        if (entity.getVariable(NUMBER_OF_INSTANCES) instanceof Integer nrOfInstances) {
+            entity.setVariable(NUMBER_OF_INSTANCES, nrOfInstances + assignees.size());
+        }
+        // 璁剧疆娴佺▼鍙橀噺
+        if (entity.getVariable(assigneeList) instanceof List<?> userIds) {
+            CollUtil.addAll(userIds, assignees);
+            Map<String, Object> variables = new HashMap<>(16);
+            variables.put(assigneeList, userIds);
+            entity.setVariables(variables);
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java
new file mode 100644
index 0000000..20a0a5f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/AttachmentCmd.java
@@ -0,0 +1,66 @@
+package org.dromara.workflow.flowable.cmd;
+
+import cn.hutool.core.collection.CollUtil;
+import org.dromara.common.core.domain.dto.OssDTO;
+import org.dromara.common.core.service.OssService;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.AttachmentEntity;
+import org.flowable.engine.impl.persistence.entity.AttachmentEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 闄勪欢涓婁紶
+ *
+ * @author may
+ */
+public class AttachmentCmd implements Command<Boolean> {
+
+    private final String fileId;
+
+    private final String taskId;
+
+    private final String processInstanceId;
+
+    private final OssService ossService;
+
+    public AttachmentCmd(String fileId, String taskId, String processInstanceId, OssService ossService) {
+        this.fileId = fileId;
+        this.taskId = taskId;
+        this.processInstanceId = processInstanceId;
+        this.ossService = ossService;
+    }
+
+    @Override
+    public Boolean execute(CommandContext commandContext) {
+        try {
+            if (StringUtils.isNotBlank(fileId)) {
+                List<OssDTO> ossList = ossService.selectByIds(fileId);
+                if (CollUtil.isNotEmpty(ossList)) {
+                    for (OssDTO oss : ossList) {
+                        AttachmentEntityManager attachmentEntityManager = CommandContextUtil.getAttachmentEntityManager();
+                        AttachmentEntity attachmentEntity = attachmentEntityManager.create();
+                        attachmentEntity.setRevision(1);
+                        attachmentEntity.setUserId(LoginHelper.getUserId().toString());
+                        attachmentEntity.setName(oss.getOriginalName());
+                        attachmentEntity.setDescription(oss.getOriginalName());
+                        attachmentEntity.setType(oss.getFileSuffix());
+                        attachmentEntity.setTaskId(taskId);
+                        attachmentEntity.setProcessInstanceId(processInstanceId);
+                        attachmentEntity.setContentId(oss.getOssId().toString());
+                        attachmentEntity.setTime(new Date());
+                        attachmentEntityManager.insert(attachmentEntity);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return true;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java
new file mode 100644
index 0000000..215d310
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteExecutionCmd.java
@@ -0,0 +1,36 @@
+package org.dromara.workflow.flowable.cmd;
+
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+import java.io.Serializable;
+
+/**
+ * 鍒犻櫎鎵ц鏁版嵁
+ *
+ * @author may
+ */
+public class DeleteExecutionCmd implements Command<Void>, Serializable {
+
+    /**
+     * 鎵цid
+     */
+    private final String executionId;
+
+    public DeleteExecutionCmd(String executionId) {
+        this.executionId = executionId;
+    }
+
+    @Override
+    public Void execute(CommandContext commandContext) {
+        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
+        ExecutionEntity entity = executionEntityManager.findById(executionId);
+        if (entity != null) {
+            executionEntityManager.deleteExecutionAndRelatedData(entity, "", false, false);
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java
new file mode 100644
index 0000000..a61daeb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/DeleteSequenceMultiInstanceCmd.java
@@ -0,0 +1,83 @@
+package org.dromara.workflow.flowable.cmd;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.utils.StreamUtils;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.dromara.workflow.common.constant.FlowConstant.LOOP_COUNTER;
+import static org.dromara.workflow.common.constant.FlowConstant.NUMBER_OF_INSTANCES;
+
+
+/**
+ * 涓茶鍑忕
+ *
+ * @author may
+ */
+@AllArgsConstructor
+public class DeleteSequenceMultiInstanceCmd implements Command<Void> {
+
+    /**
+     * 褰撳墠鑺傜偣瀹℃壒浜哄憳id
+     */
+    private final String currentUserId;
+
+    /**
+     * 鎵цid
+     */
+    private final String executionId;
+
+    /**
+     * 浼氱浜哄憳闆嗗悎KEY
+     */
+    private final String assigneeList;
+
+    /**
+     * 鍑忕浜哄憳
+     */
+    private final List<Long> assignees;
+
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Void execute(CommandContext commandContext) {
+        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
+        ExecutionEntity entity = executionEntityManager.findById(executionId);
+        // 璁剧疆娴佺▼鍙橀噺
+        List<Long> userIds = new ArrayList<>();
+        List<Object> variable = (List<Object>) entity.getVariable(assigneeList);
+        for (Object o : variable) {
+            userIds.add(Long.valueOf(o.toString()));
+        }
+        List<Long> userIdList = new ArrayList<>();
+        userIds.forEach(e -> {
+            Long userId = StreamUtils.findFirst(assignees, id -> ObjectUtil.equals(id, e));
+            if (userId == null) {
+                userIdList.add(e);
+            }
+        });
+        // 褰撳墠浠诲姟鎵ц浣嶇疆
+        int loopCounterIndex = -1;
+        for (int i = 0; i < userIdList.size(); i++) {
+            Long userId = userIdList.get(i);
+            if (currentUserId.equals(userId.toString())) {
+                loopCounterIndex = i;
+            }
+        }
+        Map<String, Object> variables = new HashMap<>(16);
+        variables.put(NUMBER_OF_INSTANCES, userIdList.size());
+        variables.put(assigneeList, userIdList);
+        variables.put(LOOP_COUNTER, loopCounterIndex);
+        entity.setVariables(variables);
+        return null;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java
new file mode 100644
index 0000000..1f3088b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/ExecutionChildByExecutionIdCmd.java
@@ -0,0 +1,39 @@
+package org.dromara.workflow.flowable.cmd;
+
+import org.dromara.common.core.utils.StreamUtils;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
+ *
+ * @author may
+ */
+public class ExecutionChildByExecutionIdCmd implements Command<List<ExecutionEntity>>, Serializable {
+
+    /**
+     * 褰撳墠浠诲姟鎵ц瀹炰緥id
+     */
+    private final String executionId;
+
+    public ExecutionChildByExecutionIdCmd(String executionId) {
+        this.executionId = executionId;
+    }
+
+    @Override
+    public List<ExecutionEntity> execute(CommandContext commandContext) {
+        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager();
+        // 鑾峰彇褰撳墠鎵ц鏁版嵁
+        ExecutionEntity executionEntity = executionEntityManager.findById(executionId);
+        // 閫氳繃褰撳墠鎵ц鏁版嵁鐨勭埗鎵ц锛屾煡璇㈡墍鏈夊瓙鎵ц鏁版嵁
+        List<ExecutionEntity> allChildrenExecution =
+            executionEntityManager.collectChildren(executionEntity.getParent());
+        return StreamUtils.filter(allChildrenExecution, e -> !e.isActive());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java
new file mode 100644
index 0000000..3ba120a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateBusinessStatusCmd.java
@@ -0,0 +1,37 @@
+package org.dromara.workflow.flowable.cmd;
+
+import org.dromara.common.core.exception.ServiceException;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
+import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityManager;
+import org.flowable.engine.impl.util.CommandContextUtil;
+
+/**
+ * 淇敼娴佺▼鐘舵��
+ *
+ * @author may
+ */
+public class UpdateBusinessStatusCmd implements Command<Boolean> {
+
+    private final String processInstanceId;
+    private final String status;
+
+    public UpdateBusinessStatusCmd(String processInstanceId, String status) {
+        this.processInstanceId = processInstanceId;
+        this.status = status;
+    }
+
+    @Override
+    public Boolean execute(CommandContext commandContext) {
+        try {
+            HistoricProcessInstanceEntityManager manager = CommandContextUtil.getHistoricProcessInstanceEntityManager();
+            HistoricProcessInstanceEntity processInstance = manager.findById(processInstanceId);
+            processInstance.setBusinessStatus(status);
+            manager.update(processInstance);
+            return true;
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java
new file mode 100644
index 0000000..42f6d1c
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/cmd/UpdateHiTaskInstCmd.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.flowable.cmd;
+
+import org.dromara.common.core.exception.ServiceException;
+import org.flowable.common.engine.impl.interceptor.Command;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.task.service.HistoricTaskService;
+import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntity;
+
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 淇敼娴佺▼鍘嗗彶
+ *
+ * @author may
+ */
+public class UpdateHiTaskInstCmd implements Command<Boolean> {
+
+    private final List<String> taskIds;
+
+    private final String processDefinitionId;
+
+    private final String processInstanceId;
+
+    public UpdateHiTaskInstCmd(List<String> taskIds, String processDefinitionId, String processInstanceId) {
+        this.taskIds = taskIds;
+        this.processDefinitionId = processDefinitionId;
+        this.processInstanceId = processInstanceId;
+    }
+
+    @Override
+    public Boolean execute(CommandContext commandContext) {
+        try {
+            HistoricTaskService historicTaskService = CommandContextUtil.getHistoricTaskService();
+            for (String taskId : taskIds) {
+                HistoricTaskInstanceEntity historicTask = historicTaskService.getHistoricTask(taskId);
+                if (historicTask != null) {
+                    historicTask.setProcessDefinitionId(processDefinitionId);
+                    historicTask.setProcessInstanceId(processInstanceId);
+                    historicTask.setCreateTime(new Date());
+                    CommandContextUtil.getHistoricTaskService().updateHistoricTask(historicTask, true);
+                }
+            }
+            return true;
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java
new file mode 100644
index 0000000..1494bf3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/FlowableConfig.java
@@ -0,0 +1,32 @@
+package org.dromara.workflow.flowable.config;
+
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
+import org.flowable.spring.SpringProcessEngineConfiguration;
+import org.flowable.spring.boot.EngineConfigurationConfigurer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Collections;
+
+
+/**
+ * flowable閰嶇疆
+ *
+ * @author may
+ */
+@Configuration
+public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
+
+    @Autowired
+    private GlobalFlowableListener globalFlowableListener;
+    @Autowired
+    private IdentifierGenerator identifierGenerator;
+
+    @Override
+    public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
+        processEngineConfiguration.setIdGenerator(() -> identifierGenerator.nextId(null).toString());
+        processEngineConfiguration.setEventListeners(Collections.singletonList(globalFlowableListener));
+        processEngineConfiguration.addCustomJobHandler(new TaskTimeoutJobHandler());
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java
new file mode 100644
index 0000000..9bb971a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/config/GlobalFlowableListener.java
@@ -0,0 +1,139 @@
+package org.dromara.workflow.flowable.config;
+
+import cn.hutool.core.collection.CollUtil;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.flowable.handler.TaskTimeoutJobHandler;
+import org.dromara.workflow.utils.QueryUtils;
+import org.flowable.bpmn.model.BoundaryEvent;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.FlowElement;
+import org.flowable.common.engine.api.delegate.event.*;
+import org.flowable.common.engine.impl.cfg.TransactionState;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.engine.runtime.Execution;
+import org.flowable.engine.task.Comment;
+import org.flowable.job.service.TimerJobService;
+import org.flowable.job.service.impl.persistence.entity.JobEntity;
+import org.flowable.job.service.impl.persistence.entity.TimerJobEntity;
+import org.flowable.task.api.Task;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 寮曟搸璋冨害鐩戝惉
+ *
+ * @author may
+ */
+@Component
+public class GlobalFlowableListener implements FlowableEventListener {
+
+    @Autowired
+    @Lazy
+    private TaskService taskService;
+
+    @Autowired
+    @Lazy
+    private RuntimeService runtimeService;
+
+    @Autowired
+    @Lazy
+    private RepositoryService repositoryService;
+
+    @Value("${flowable.async-executor-activate}")
+    private boolean asyncExecutorActivate;
+
+    @Override
+    public void onEvent(FlowableEvent flowableEvent) {
+        if (flowableEvent instanceof FlowableEngineEvent flowableEngineEvent) {
+            FlowableEngineEventType engineEventType = (FlowableEngineEventType) flowableEvent.getType();
+            switch (engineEventType) {
+                case JOB_EXECUTION_SUCCESS -> jobExecutionSuccess((FlowableEngineEntityEvent) flowableEngineEvent);
+                case TASK_DUEDATE_CHANGED, TASK_CREATED -> {
+                    FlowableEntityEvent flowableEntityEvent = (FlowableEntityEvent) flowableEngineEvent;
+                    Object entityObject = flowableEntityEvent.getEntity();
+                    TaskEntity task = (TaskEntity) entityObject;
+                    if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) {
+                        //鍒犻櫎涔嬪墠宸茬粡瀛樺湪鐨勫畾鏃朵换鍔�
+                        TimerJobService timerJobService = CommandContextUtil.getTimerJobService();
+                        List<TimerJobEntity> timerJobEntityList = timerJobService.findTimerJobsByProcessInstanceId(task.getProcessInstanceId());
+                        if (!CollUtil.isEmpty(timerJobEntityList)) {
+                            for (TimerJobEntity timerJobEntity : timerJobEntityList) {
+                                String taskId = timerJobEntity.getJobHandlerConfiguration();
+                                if (task.getId().equals(taskId)) {
+                                    timerJobService.deleteTimerJob(timerJobEntity);
+                                }
+                            }
+                        }
+                        //鍒涘缓job瀵硅薄
+                        TimerJobEntity timer = timerJobService.createTimerJob();
+                        timer.setTenantId(TenantHelper.getTenantId());
+                        //璁剧疆job绫诲瀷
+                        timer.setJobType(JobEntity.JOB_TYPE_TIMER);
+                        timer.setJobHandlerType(TaskTimeoutJobHandler.TYPE);
+                        timer.setDuedate(task.getDueDate());
+                        timer.setProcessInstanceId(task.getProcessInstanceId());
+                        //璁剧疆浠诲姟id
+                        timer.setJobHandlerConfiguration(task.getId());
+                        //淇濆瓨骞惰Е鍙戜簨浠�
+                        timerJobService.scheduleTimerJob(timer);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean isFailOnException() {
+        return true;
+    }
+
+    @Override
+    public boolean isFireOnTransactionLifecycleEvent() {
+        return false;
+    }
+
+    @Override
+    public String getOnTransaction() {
+        return TransactionState.COMMITTED.name();
+    }
+
+    /**
+     * 澶勭悊杈圭晫瀹氭椂浜嬩欢鑷姩瀹℃壒璁板綍
+     *
+     * @param event 浜嬩欢
+     */
+    protected void jobExecutionSuccess(FlowableEngineEntityEvent event) {
+        if (event != null && StringUtils.isNotBlank(event.getExecutionId())) {
+            Execution execution = runtimeService.createExecutionQuery().executionId(event.getExecutionId()).singleResult();
+            if (execution != null) {
+                BpmnModel bpmnModel = repositoryService.getBpmnModel(event.getProcessDefinitionId());
+                FlowElement flowElement = bpmnModel.getFlowElement(execution.getActivityId());
+                if (flowElement instanceof BoundaryEvent) {
+                    String attachedToRefId = ((BoundaryEvent) flowElement).getAttachedToRefId();
+                    List<Execution> list = runtimeService.createExecutionQuery().activityId(attachedToRefId).list();
+                    for (Execution ex : list) {
+                        Task task = QueryUtils.taskQuery().executionId(ex.getId()).singleResult();
+                        if (task != null) {
+                            List<Comment> taskComments = taskService.getTaskComments(task.getId());
+                            if (CollUtil.isEmpty(taskComments)) {
+                                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), "瓒呮椂鑷姩瀹℃壒!");
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java
new file mode 100644
index 0000000..69ae70a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/FlowProcessEventHandler.java
@@ -0,0 +1,50 @@
+package org.dromara.workflow.flowable.handler;
+
+import org.dromara.common.core.domain.event.ProcessEvent;
+import org.dromara.common.core.domain.event.ProcessTaskEvent;
+import org.dromara.common.core.utils.SpringUtils;
+import org.springframework.stereotype.Component;
+
+/**
+ * 娴佺▼鐩戝惉鏈嶅姟
+ *
+ * @author may
+ * @date 2024-06-02
+ */
+@Component
+public class FlowProcessEventHandler {
+
+    /**
+     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鎻愪氦 閫�鍥� 鎾ら攢 缁堟 浣滃簾绛�)
+     *
+     * @param key         娴佺▼key
+     * @param businessKey 涓氬姟id
+     * @param status      鐘舵��
+     * @param submit      褰撲负true鏃朵负鐢宠浜鸿妭鐐瑰姙鐞�
+     */
+    public void processHandler(String key, String businessKey, String status, boolean submit) {
+        ProcessEvent processEvent = new ProcessEvent();
+        processEvent.setKey(key);
+        processEvent.setBusinessKey(businessKey);
+        processEvent.setStatus(status);
+        processEvent.setSubmit(submit);
+        SpringUtils.context().publishEvent(processEvent);
+    }
+
+    /**
+     * 鎵ц鍔炵悊浠诲姟鐩戝惉
+     *
+     * @param key               娴佺▼key
+     * @param taskDefinitionKey 瀹℃壒鑺傜偣key
+     * @param taskId            浠诲姟id
+     * @param businessKey       涓氬姟id
+     */
+    public void processTaskHandler(String key, String taskDefinitionKey, String taskId, String businessKey) {
+        ProcessTaskEvent processTaskEvent = new ProcessTaskEvent();
+        processTaskEvent.setKey(key);
+        processTaskEvent.setTaskDefinitionKey(taskDefinitionKey);
+        processTaskEvent.setTaskId(taskId);
+        processTaskEvent.setBusinessKey(businessKey);
+        SpringUtils.context().publishEvent(processTaskEvent);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java
new file mode 100644
index 0000000..61c9388
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/flowable/handler/TaskTimeoutJobHandler.java
@@ -0,0 +1,37 @@
+package org.dromara.workflow.flowable.handler;
+
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.impl.jobexecutor.TimerEventHandler;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.job.service.JobHandler;
+import org.flowable.job.service.impl.persistence.entity.JobEntity;
+import org.flowable.task.api.Task;
+import org.flowable.variable.api.delegate.VariableScope;
+
+/**
+ * 鍔炵悊瓒呮椂(杩囨湡)浠诲姟
+ *
+ * @author may
+ */
+public class TaskTimeoutJobHandler extends TimerEventHandler implements JobHandler {
+
+    public static final String TYPE = "taskTimeout";
+
+    @Override
+    public String getType() {
+        return TYPE;
+    }
+
+    @Override
+    public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
+        TaskService taskService = CommandContextUtil.getProcessEngineConfiguration(commandContext)
+            .getTaskService();
+        Task task = taskService.createTaskQuery().taskId(configuration).singleResult();
+        if (task != null) {
+            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TIMEOUT.getStatus(), "瓒呮椂鑷姩瀹℃壒!");
+            taskService.complete(configuration);
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java
new file mode 100644
index 0000000..a3a41c9
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiProcinstMapper.java
@@ -0,0 +1,16 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.workflow.domain.ActHiProcinst;
+
+/**
+ * 娴佺▼瀹炰緥Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2023-07-22
+ */
+@InterceptorIgnore(tenantLine = "true")
+public interface ActHiProcinstMapper extends BaseMapperPlus<ActHiProcinst, ActHiProcinst> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java
new file mode 100644
index 0000000..63b394b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActHiTaskinstMapper.java
@@ -0,0 +1,16 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.dromara.workflow.domain.ActHiTaskinst;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 娴佺▼鍘嗗彶浠诲姟Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+@InterceptorIgnore(tenantLine = "true")
+public interface ActHiTaskinstMapper extends BaseMapperPlus<ActHiTaskinst, ActHiTaskinst> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java
new file mode 100644
index 0000000..63c5ecb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/ActTaskMapper.java
@@ -0,0 +1,47 @@
+package org.dromara.workflow.mapper;
+
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.workflow.domain.vo.TaskVo;
+
+
+/**
+ * 浠诲姟淇℃伅Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+@InterceptorIgnore(tenantLine = "true")
+public interface ActTaskMapper extends BaseMapperPlus<TaskVo, TaskVo> {
+    /**
+     * 鑾峰彇寰呭姙淇℃伅
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<TaskVo> getTaskWaitByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
+
+    /**
+     * 鑾峰彇宸插姙
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<TaskVo> getTaskFinishByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) Wrapper<TaskVo> queryWrapper);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param page         鍒嗛〉
+     * @param queryWrapper 鏉′欢
+     * @return 缁撴灉
+     */
+    Page<TaskVo> getTaskCopyByPage(@Param("page") Page<TaskVo> page, @Param(Constants.WRAPPER) QueryWrapper<TaskVo> queryWrapper);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java
new file mode 100644
index 0000000..cd1edba
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.workflow.domain.TestLeave;
+import org.dromara.workflow.domain.vo.TestLeaveVo;
+
+/**
+ * 璇峰亣Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+public interface TestLeaveMapper extends BaseMapperPlus<TestLeave, TestLeaveVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java
new file mode 100644
index 0000000..98aea02
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfCategoryMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.workflow.domain.WfCategory;
+import org.dromara.workflow.domain.vo.WfCategoryVo;
+
+/**
+ * 娴佺▼鍒嗙被Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2023-06-27
+ */
+public interface WfCategoryMapper extends BaseMapperPlus<WfCategory, WfCategoryVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java
new file mode 100644
index 0000000..ee20882
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfDefinitionConfigMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.workflow.domain.WfDefinitionConfig;
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+public interface WfDefinitionConfigMapper extends BaseMapperPlus<WfDefinitionConfig, WfDefinitionConfigVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java
new file mode 100644
index 0000000..acf8111
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfFormManageMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.workflow.domain.WfFormManage;
+import org.dromara.workflow.domain.vo.WfFormManageVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 琛ㄥ崟绠$悊Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+public interface WfFormManageMapper extends BaseMapperPlus<WfFormManage, WfFormManageVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java
new file mode 100644
index 0000000..d2aecac
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfNodeConfigMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.workflow.domain.vo.WfNodeConfigVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 鑺傜偣閰嶇疆Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+public interface WfNodeConfigMapper extends BaseMapperPlus<WfNodeConfig, WfNodeConfigVo> {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java
new file mode 100644
index 0000000..9b291fe
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/WfTaskBackNodeMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.workflow.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.workflow.domain.WfTaskBackNode;
+
+/**
+ * 鑺傜偣椹冲洖璁板綍Mapper鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-13
+ */
+public interface WfTaskBackNodeMapper extends BaseMapperPlus<WfTaskBackNode, WfTaskBackNode> {
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java
new file mode 100644
index 0000000..e802c69
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiProcinstService.java
@@ -0,0 +1,31 @@
+package org.dromara.workflow.service;
+
+
+import org.dromara.workflow.domain.ActHiProcinst;
+
+import java.util.List;
+
+/**
+ * 娴佺▼瀹炰緥Service鎺ュ彛
+ *
+ * @author may
+ * @date 2023-07-22
+ */
+public interface IActHiProcinstService {
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ
+     *
+     * @param businessKeys 涓氬姟id
+     * @return 缁撴灉
+     */
+    List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys);
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    ActHiProcinst selectByBusinessKey(String businessKey);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java
new file mode 100644
index 0000000..ad286e2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActHiTaskinstService.java
@@ -0,0 +1,11 @@
+package org.dromara.workflow.service;
+
+
+/**
+ * 娴佺▼鍘嗗彶浠诲姟Service鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+public interface IActHiTaskinstService {
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java
new file mode 100644
index 0000000..4a6d170
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActModelService.java
@@ -0,0 +1,83 @@
+package org.dromara.workflow.service;
+
+import jakarta.servlet.http.HttpServletResponse;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.bo.ModelBo;
+import org.dromara.workflow.domain.vo.ModelVo;
+import org.flowable.engine.repository.Model;
+
+import java.util.List;
+
+
+/**
+ * 妯″瀷绠$悊 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IActModelService {
+    /**
+     * 鍒嗛〉鏌ヨ妯″瀷
+     *
+     * @param modelBo   妯″瀷鍙傛暟
+     * @param pageQuery 鍙傛暟
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery);
+
+    /**
+     * 鏂板妯″瀷
+     *
+     * @param modelBo 妯″瀷璇锋眰瀵硅薄
+     * @return 缁撴灉
+     */
+    boolean saveNewModel(ModelBo modelBo);
+
+    /**
+     * 鏌ヨ妯″瀷
+     *
+     * @param modelId 妯″瀷id
+     * @return 妯″瀷鏁版嵁
+     */
+    ModelVo getInfo(String modelId);
+
+    /**
+     * 淇敼妯″瀷淇℃伅
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    boolean update(ModelBo modelBo);
+
+    /**
+     * 缂栬緫妯″瀷XML
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    boolean editModelXml(ModelBo modelBo);
+
+    /**
+     * 妯″瀷閮ㄧ讲
+     *
+     * @param id 妯″瀷id
+     * @return 缁撴灉
+     */
+    boolean modelDeploy(String id);
+
+    /**
+     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
+     *
+     * @param modelIds 妯″瀷id
+     * @param response 鍝嶅簲
+     */
+    void exportZip(List<String> modelIds, HttpServletResponse response);
+
+    /**
+     * 澶嶅埗妯″瀷
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    boolean copyModel(ModelBo modelBo);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java
new file mode 100644
index 0000000..5d00e41
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessDefinitionService.java
@@ -0,0 +1,91 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
+import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 娴佺▼瀹氫箟 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IActProcessDefinitionService {
+    /**
+     * 鍒嗛〉鏌ヨ
+     *
+     * @param processDefinitionBo 鍙傛暟
+     * @param pageQuery           鍒嗛〉
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo processDefinitionBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param key 娴佺▼瀹氫箟key
+     * @return 缁撴灉
+     */
+    List<ProcessDefinitionVo> getListByKey(String key);
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    String definitionImage(String processDefinitionId);
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    String definitionXml(String processDefinitionId);
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param deploymentIds        閮ㄧ讲id
+     * @param processDefinitionIds 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    boolean deleteDeployment(List<String> deploymentIds, List<String> processDefinitionIds);
+
+    /**
+     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    boolean updateDefinitionState(String processDefinitionId);
+
+    /**
+     * 杩佺Щ娴佺▼瀹氫箟
+     *
+     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
+     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
+     * @return 缁撴灉
+     */
+    boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId);
+
+    /**
+     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    boolean convertToModel(String processDefinitionId);
+
+    /**
+     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
+     *
+     * @param file         鏂囦欢
+     * @param categoryCode 鍒嗙被
+     */
+    void deployByFile(MultipartFile file, String categoryCode);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java
new file mode 100644
index 0000000..ca3b6fb
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActProcessInstanceService.java
@@ -0,0 +1,110 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.bo.ProcessInstanceBo;
+import org.dromara.workflow.domain.bo.ProcessInvalidBo;
+import org.dromara.workflow.domain.bo.TaskUrgingBo;
+import org.dromara.workflow.domain.vo.ActHistoryInfoVo;
+import org.dromara.workflow.domain.vo.ProcessInstanceVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 娴佺▼瀹炰緥 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IActProcessInstanceService {
+    /**
+     * 閫氳繃娴佺▼瀹炰緥id鑾峰彇鍘嗗彶娴佺▼鍥�
+     *
+     * @param businessKey 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    String getHistoryImage(String businessKey);
+
+    /**
+     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    Map<String, Object> getHistoryList(String businessKey);
+
+    /**
+     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
+     *
+     * @param processInstanceBo 鍙傛暟
+     * @param pageQuery         鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
+
+    /**
+     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
+     *
+     * @param processInstanceBo 鍙傛暟
+     * @param pageQuery         鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
+
+    /**
+     * 鑾峰彇瀹℃壒璁板綍
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    List<ActHistoryInfoVo> getHistoryRecord(String businessKey);
+
+    /**
+     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
+     *
+     * @param processInvalidBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean deleteRunInstance(ProcessInvalidBo processInvalidBo);
+
+    /**
+     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     * @return 缁撴灉
+     */
+    boolean deleteRunAndHisInstance(List<String> businessKeys);
+
+    /**
+     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     * @return 缁撴灉
+     */
+    boolean deleteFinishAndHisInstance(List<String> businessKeys);
+
+    /**
+     * 鎾ら攢娴佺▼鐢宠
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    boolean cancelProcessApply(String businessKey);
+
+    /**
+     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
+     *
+     * @param processInstanceBo 鍙傛暟
+     * @param pageQuery         鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo processInstanceBo, PageQuery pageQuery);
+
+    /**
+     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
+     *
+     * @param taskUrgingBo 浠诲姟鍌姙
+     * @return 缁撴灉
+     */
+    boolean taskUrging(TaskUrgingBo taskUrgingBo);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java
new file mode 100644
index 0000000..8e9f763
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IActTaskService.java
@@ -0,0 +1,161 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.TaskVo;
+import org.dromara.workflow.domain.vo.VariableVo;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠诲姟 鏈嶅姟灞�
+ *
+ * @author may
+ */
+public interface IActTaskService {
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     * @return 缁撴灉
+     */
+    Map<String, Object> startWorkFlow(StartProcessBo startProcessBo);
+
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean completeTask(CompleteTaskBo completeTaskBo);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param taskBo    鍙傛暟
+     * @param pageQuery 鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
+     *
+     * @param taskBo    鍙傛暟
+     * @param pageQuery 鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery);
+
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param taskBo    鍙傛暟
+     * @param pageQuery 鍙傛暟
+     * @return 缁撴灉
+     */
+    TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param taskBo    鍙傛暟
+     * @param pageQuery 鍙傛暟
+     * @return 缁撴灉
+     */
+    TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
+     *
+     * @param taskBo    鍙傛暟
+     * @param pageQuery 鍙傛暟
+     * @return 缁撴灉
+     */
+    TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery);
+
+    /**
+     * 濮旀淳浠诲姟
+     *
+     * @param delegateBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean delegateTask(DelegateBo delegateBo);
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param terminationBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean terminationTask(TerminationBo terminationBo);
+
+    /**
+     * 杞姙浠诲姟
+     *
+     * @param transmitBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean transferTask(TransmitBo transmitBo);
+
+    /**
+     * 浼氱浠诲姟鍔犵
+     *
+     * @param addMultiBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean addMultiInstanceExecution(AddMultiBo addMultiBo);
+
+    /**
+     * 浼氱浠诲姟鍑忕
+     *
+     * @param deleteMultiBo 鍙傛暟
+     * @return 缁撴灉
+     */
+    boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo);
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param backProcessBo 鍙傛暟
+     * @return 娴佺▼瀹炰緥id
+     */
+    String backProcess(BackProcessBo backProcessBo);
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIds 浠诲姟id
+     * @param userId  鍔炵悊浜篿d
+     * @return 缁撴灉
+     */
+    boolean updateAssignee(String[] taskIds, String userId);
+
+    /**
+     * 鏌ヨ娴佺▼鍙橀噺
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<VariableVo> getInstanceVariable(String taskId);
+
+    /**
+     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    String getTaskUserIdsByAddMultiInstance(String taskId);
+
+    /**
+     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    List<TaskVo> getListByDeleteMultiInstance(String taskId);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java
new file mode 100644
index 0000000..943c919
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java
@@ -0,0 +1,48 @@
+package org.dromara.workflow.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.bo.TestLeaveBo;
+import org.dromara.workflow.domain.vo.TestLeaveVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 璇峰亣Service鎺ュ彛
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+public interface ITestLeaveService {
+
+    /**
+     * 鏌ヨ璇峰亣
+     */
+    TestLeaveVo queryById(Long id);
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    List<TestLeaveVo> queryList(TestLeaveBo bo);
+
+    /**
+     * 鏂板璇峰亣
+     */
+    TestLeaveVo insertByBo(TestLeaveBo bo);
+
+    /**
+     * 淇敼璇峰亣
+     */
+    TestLeaveVo updateByBo(TestLeaveBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄よ鍋囦俊鎭�
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java
new file mode 100644
index 0000000..acf0aa2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfCategoryService.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.service;
+
+import org.dromara.workflow.domain.WfCategory;
+import org.dromara.workflow.domain.bo.WfCategoryBo;
+import org.dromara.workflow.domain.vo.WfCategoryVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被Service鎺ュ彛
+ *
+ * @author may
+ * @date 2023-06-28
+ */
+public interface IWfCategoryService {
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被
+     */
+    WfCategoryVo queryById(Long id);
+
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
+     */
+    List<WfCategoryVo> queryList(WfCategoryBo bo);
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     */
+    Boolean insertByBo(WfCategoryBo bo);
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     */
+    Boolean updateByBo(WfCategoryBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゆ祦绋嬪垎绫讳俊鎭�
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 鎸夌収绫诲埆缂栫爜鏌ヨ
+     *
+     * @param categoryCode 鍒嗙被姣斿悧
+     * @return 缁撴灉
+     */
+    WfCategory queryByCategoryCode(String categoryCode);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java
new file mode 100644
index 0000000..fe5cf7a
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfDefinitionConfigService.java
@@ -0,0 +1,83 @@
+package org.dromara.workflow.service;
+
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆Service鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+public interface IWfDefinitionConfigService {
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    WfDefinitionConfigVo getByDefId(String definitionId);
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param tableName 琛ㄥ悕
+     * @return 缁撴灉
+     */
+    WfDefinitionConfigVo getByTableNameLastVersion(String tableName);
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param tableName    琛ㄥ悕
+     * @return 缁撴灉
+     */
+    WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName);
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param tableName    琛ㄥ悕
+     * @return 缁撴灉
+     */
+    List<WfDefinitionConfigVo> getByTableNameNotDefId(String tableName, String definitionId);
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鍒楄〃
+     *
+     * @param definitionIds 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    List<WfDefinitionConfigVo> queryList(List<String> definitionIds);
+
+
+    /**
+     * 鏂板娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    Boolean saveOrUpdate(WfDefinitionConfigBo bo);
+
+    /**
+     * 鍒犻櫎
+     *
+     * @param ids id
+     * @return 缁撴灉
+     */
+    Boolean deleteByIds(Collection<Long> ids);
+
+    /**
+     * 鎸夌収娴佺▼瀹氫箟id鍒犻櫎
+     *
+     * @param ids 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    Boolean deleteByDefIds(Collection<String> ids);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java
new file mode 100644
index 0000000..2ca2264
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfFormManageService.java
@@ -0,0 +1,81 @@
+package org.dromara.workflow.service;
+
+import org.dromara.workflow.domain.vo.WfFormManageVo;
+import org.dromara.workflow.domain.bo.WfFormManageBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 琛ㄥ崟绠$悊Service鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+public interface IWfFormManageService {
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊
+     *
+     * @param id 涓婚敭
+     * @return 缁撴灉
+     */
+    WfFormManageVo queryById(Long id);
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊
+     *
+     * @param ids 涓婚敭
+     * @return 缁撴灉
+     */
+    List<WfFormManageVo> queryByIds(List<Long> ids);
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     *
+     * @param bo        鍙傛暟
+     * @param pageQuery 鍒嗛〉
+     * @return 缁撴灉
+     */
+    TableDataInfo<WfFormManageVo> queryPageList(WfFormManageBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     *
+     * @return 缁撴灉
+     */
+    List<WfFormManageVo> selectList();
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    List<WfFormManageVo> queryList(WfFormManageBo bo);
+
+    /**
+     * 鏂板琛ㄥ崟绠$悊
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    Boolean insertByBo(WfFormManageBo bo);
+
+    /**
+     * 淇敼琛ㄥ崟绠$悊
+     *
+     * @param bo 鍙傛暟
+     * @return 缁撴灉
+     */
+    Boolean updateByBo(WfFormManageBo bo);
+
+    /**
+     * 鎵归噺鍒犻櫎琛ㄥ崟绠$悊淇℃伅
+     *
+     * @param ids 涓婚敭
+     * @return 缁撴灉
+     */
+    Boolean deleteByIds(Collection<Long> ids);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java
new file mode 100644
index 0000000..5e64d64
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfNodeConfigService.java
@@ -0,0 +1,56 @@
+package org.dromara.workflow.service;
+
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.workflow.domain.vo.WfNodeConfigVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鑺傜偣閰嶇疆Service鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+public interface IWfNodeConfigService {
+
+    /**
+     * 鏌ヨ鑺傜偣閰嶇疆
+     *
+     * @param id 涓婚敭
+     * @return 缁撴灉
+     */
+    WfNodeConfigVo queryById(Long id);
+
+    /**
+     * 淇濆瓨鑺傜偣閰嶇疆
+     *
+     * @param list 鍙傛暟
+     * @return 缁撴灉
+     */
+    Boolean saveOrUpdate(List<WfNodeConfig> list);
+
+    /**
+     * 鎵归噺鍒犻櫎鑺傜偣閰嶇疆淇℃伅
+     *
+     * @param ids 涓婚敭
+     * @return 缁撴灉
+     */
+    Boolean deleteByIds(Collection<Long> ids);
+
+    /**
+     * 鎸夌収娴佺▼瀹氫箟id鍒犻櫎
+     *
+     * @param ids 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    Boolean deleteByDefIds(Collection<String> ids);
+
+    /**
+     * 鎸夌収娴佺▼瀹氫箟id鏌ヨ
+     *
+     * @param ids 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    List<WfNodeConfigVo> selectByDefIds(Collection<String> ids);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java
new file mode 100644
index 0000000..97f9406
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IWfTaskBackNodeService.java
@@ -0,0 +1,65 @@
+package org.dromara.workflow.service;
+
+
+import org.dromara.workflow.domain.WfTaskBackNode;
+import org.flowable.task.api.Task;
+
+import java.util.List;
+
+/**
+ * 鑺傜偣椹冲洖璁板綍Service鎺ュ彛
+ *
+ * @author may
+ * @date 2024-03-13
+ */
+public interface IWfTaskBackNodeService {
+
+    /**
+     * 璁板綍瀹℃壒鑺傜偣
+     *
+     * @param task 浠诲姟
+     */
+    void recordExecuteNode(Task task);
+
+    /**
+     * 鎸夋祦绋嬪疄渚媔d鏌ヨ
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    List<WfTaskBackNode> getListByInstanceId(String processInstanceId);
+
+    /**
+     * 鎸夌収娴佺▼瀹炰緥id锛岃妭鐐筰d鏌ヨ
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     * @param nodeId            鑺傜偣id
+     * @return 缁撴灉
+     */
+    WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId);
+
+    /**
+     * 鍒犻櫎椹冲洖鍚庣殑鑺傜偣
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     * @param targetActivityId  鑺傜偣id
+     * @return 缁撴灉
+     */
+    boolean deleteBackTaskNode(String processInstanceId, String targetActivityId);
+
+    /**
+     * 鎸夋祦绋嬪疄渚媔d鍒犻櫎
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    boolean deleteByInstanceId(String processInstanceId);
+
+    /**
+     * 鎸夋祦绋嬪疄渚媔d鍒犻櫎
+     *
+     * @param processInstanceIds 娴佺▼瀹炰緥id
+     * @return 缁撴灉
+     */
+    boolean deleteByInstanceIds(List<String> processInstanceIds);
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java
new file mode 100644
index 0000000..06d607b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiProcinstServiceImpl.java
@@ -0,0 +1,51 @@
+package org.dromara.workflow.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.domain.ActHiProcinst;
+import org.dromara.workflow.mapper.ActHiProcinstMapper;
+import org.dromara.workflow.service.IActHiProcinstService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+/**
+ * 娴佺▼瀹炰緥Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2023-07-22
+ */
+@RequiredArgsConstructor
+@Service
+public class ActHiProcinstServiceImpl implements IActHiProcinstService {
+
+    private final ActHiProcinstMapper baseMapper;
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ
+     *
+     * @param businessKeys 涓氬姟id
+     */
+    @Override
+    public List<ActHiProcinst> selectByBusinessKeyIn(List<String> businessKeys) {
+        return baseMapper.selectList(new LambdaQueryWrapper<ActHiProcinst>()
+            .in(ActHiProcinst::getBusinessKey, businessKeys)
+            .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
+    }
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Override
+    public ActHiProcinst selectByBusinessKey(String businessKey) {
+        return baseMapper.selectOne(new LambdaQueryWrapper<ActHiProcinst>()
+            .eq(ActHiProcinst::getBusinessKey, businessKey)
+            .eq(TenantHelper.isEnable(), ActHiProcinst::getTenantId, TenantHelper.getTenantId()));
+
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java
new file mode 100644
index 0000000..5548f22
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActHiTaskinstServiceImpl.java
@@ -0,0 +1,18 @@
+package org.dromara.workflow.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.workflow.service.IActHiTaskinstService;
+
+
+/**
+ * 娴佺▼鍘嗗彶浠诲姟Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2024-03-02
+ */
+@RequiredArgsConstructor
+@Service
+public class ActHiTaskinstServiceImpl implements IActHiTaskinstService {
+
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
new file mode 100644
index 0000000..217538e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java
@@ -0,0 +1,431 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.ZipUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.excel.util.StringUtils;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.batik.transcoder.TranscoderInput;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.PNGTranscoder;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.workflow.domain.bo.ModelBo;
+import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
+import org.dromara.workflow.domain.vo.ModelVo;
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.workflow.service.IActModelService;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+import org.dromara.workflow.service.IWfNodeConfigService;
+import org.dromara.workflow.utils.ModelUtils;
+import org.dromara.workflow.utils.QueryUtils;
+import org.flowable.bpmn.converter.BpmnXMLConverter;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.UserTask;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.repository.Model;
+import org.flowable.engine.repository.ModelQuery;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.validation.ValidationError;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 妯″瀷绠$悊 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ActModelServiceImpl implements IActModelService {
+
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    private final IWfNodeConfigService wfNodeConfigService;
+    private final IWfDefinitionConfigService wfDefinitionConfigService;
+
+    /**
+     * 鍒嗛〉鏌ヨ妯″瀷
+     *
+     * @param modelBo 妯″瀷鍙傛暟
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) {
+        ModelQuery query = QueryUtils.modelQuery();
+        if (StringUtils.isNotBlank(modelBo.getName())) {
+            query.modelNameLike("%" + modelBo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(modelBo.getKey())) {
+            query.modelKey(modelBo.getKey());
+        }
+        if (StringUtils.isNotBlank(modelBo.getCategoryCode())) {
+            query.modelCategory(modelBo.getCategoryCode());
+        }
+        query.orderByLastUpdateTime().desc();
+        // 鍒涘缓鏃堕棿闄嶅簭鎺掑垪
+        query.orderByCreateTime().desc();
+        // 鍒嗛〉鏌ヨ
+        List<Model> modelList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        // 鎬昏褰曟暟
+        long total = query.count();
+        TableDataInfo<Model> build = TableDataInfo.build();
+        build.setRows(modelList);
+        build.setTotal(total);
+        return build;
+    }
+
+    /**
+     * 鏂板妯″瀷
+     *
+     * @param modelBo 妯″瀷璇锋眰瀵硅薄
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveNewModel(ModelBo modelBo) {
+        try {
+            int version = 0;
+            String key = modelBo.getKey();
+            String name = modelBo.getName();
+            String description = modelBo.getDescription();
+            String categoryCode = modelBo.getCategoryCode();
+            String xml = modelBo.getXml();
+            Model checkModel = QueryUtils.modelQuery().modelKey(key).singleResult();
+            if (ObjectUtil.isNotNull(checkModel)) {
+                throw new ServiceException("妯″瀷key宸插瓨鍦紒");
+            }
+            //鍒濆绌虹殑妯″瀷
+            Model model = repositoryService.newModel();
+            model.setKey(key);
+            model.setName(name);
+            model.setVersion(version);
+            model.setCategory(categoryCode);
+            model.setMetaInfo(description);
+            model.setTenantId(TenantHelper.getTenantId());
+            //淇濆瓨鍒濆鍖栫殑妯″瀷鍩烘湰淇℃伅鏁版嵁
+            repositoryService.saveModel(model);
+            repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鏌ヨ妯″瀷
+     *
+     * @param id 妯″瀷id
+     * @return 妯″瀷鏁版嵁
+     */
+    @Override
+    public ModelVo getInfo(String id) {
+        ModelVo modelVo = new ModelVo();
+        Model model = repositoryService.getModel(id);
+        if (model != null) {
+            try {
+                byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
+                modelVo.setXml(StrUtil.utf8Str(modelEditorSource));
+                modelVo.setId(model.getId());
+                modelVo.setKey(model.getKey());
+                modelVo.setName(model.getName());
+                modelVo.setCategoryCode(model.getCategory());
+                modelVo.setDescription(model.getMetaInfo());
+                return modelVo;
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+                throw new ServiceException(e.getMessage());
+            }
+        }
+        return modelVo;
+    }
+
+    /**
+     * 淇敼妯″瀷淇℃伅
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean update(ModelBo modelBo) {
+        try {
+            Model model = repositoryService.getModel(modelBo.getId());
+            List<Model> list = QueryUtils.modelQuery().modelKey(modelBo.getKey()).list();
+            list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
+                throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
+            });
+            model.setCategory(modelBo.getCategoryCode());
+            model.setMetaInfo(modelBo.getDescription());
+            repositoryService.saveModel(model);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 缂栬緫妯″瀷XML
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean editModelXml(ModelBo modelBo) {
+        try {
+            String xml = modelBo.getXml();
+            String svg = modelBo.getSvg();
+            String modelId = modelBo.getId();
+            String key = modelBo.getKey();
+            String name = modelBo.getName();
+            BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml);
+            ModelUtils.checkBpmnModel(bpmnModel);
+            Model model = repositoryService.getModel(modelId);
+            List<Model> list = QueryUtils.modelQuery().modelKey(key).list();
+            list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
+                throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
+            });
+            // 鏍¢獙key鍛藉悕瑙勮寖
+            if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
+                throw new ServiceException("妯″瀷鏍囪瘑KEY鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶达紒");
+            }
+            model.setKey(key);
+            model.setName(name);
+            model.setVersion(model.getVersion() + 1);
+            repositoryService.saveModel(model);
+            repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
+            // 杞崲鍥剧墖
+            InputStream svgStream = new ByteArrayInputStream(StrUtil.utf8Bytes(svg));
+            TranscoderInput input = new TranscoderInput(svgStream);
+
+            PNGTranscoder transcoder = new PNGTranscoder();
+            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+            TranscoderOutput output = new TranscoderOutput(outStream);
+
+            transcoder.transcode(input, output);
+            final byte[] result = outStream.toByteArray();
+            repositoryService.addModelEditorSourceExtra(model.getId(), result);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 妯″瀷閮ㄧ讲
+     *
+     * @param id 妯″瀷id
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean modelDeploy(String id) {
+        try {
+            // 鏌ヨ娴佺▼瀹氫箟妯″瀷xml
+            byte[] xmlBytes = repositoryService.getModelEditorSource(id);
+            if (ArrayUtil.isEmpty(xmlBytes)) {
+                throw new ServiceException("妯″瀷鏁版嵁涓虹┖锛岃鍏堣璁℃祦绋嬪畾涔夋ā鍨嬶紝鍐嶈繘琛岄儴缃诧紒");
+            }
+            if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8))) {
+                byte[] bytes = ModelUtils.bpmnJsonToXmlBytes(xmlBytes);
+                if (ArrayUtil.isEmpty(bytes)) {
+                    throw new ServiceException("妯″瀷涓嶈兘涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒");
+                }
+            }
+            BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xmlBytes);
+            // 鏍¢獙妯″瀷
+            ModelUtils.checkBpmnModel(bpmnModel);
+            List<ValidationError> validationErrors = repositoryService.validateProcess(bpmnModel);
+            if (CollUtil.isNotEmpty(validationErrors)) {
+                String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(","));
+                throw new ServiceException(errorMsg);
+            }
+            // 鏌ヨ妯″瀷鐨勫熀鏈俊鎭�
+            Model model = repositoryService.getModel(id);
+            ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey(model.getKey()).latestVersion().singleResult();
+            // xml璧勬簮鐨勫悕绉� 锛屽搴攁ct_ge_bytearray琛ㄤ腑鐨刵ame_瀛楁
+            String processName = model.getName() + ".bpmn20.xml";
+            // 璋冪敤閮ㄧ讲鐩稿叧鐨刟pi鏂规硶杩涜閮ㄧ讲娴佺▼瀹氫箟
+            Deployment deployment = repositoryService.createDeployment()
+                // 閮ㄧ讲鍚嶇О
+                .name(model.getName())
+                // 閮ㄧ讲鏍囪瘑key
+                .key(model.getKey())
+                // 閮ㄧ讲娴佺▼鍒嗙被
+                .category(model.getCategory())
+                // bpmn20.xml璧勬簮
+                .addBytes(processName, xmlBytes)
+                // 绉熸埛id
+                .tenantId(TenantHelper.getTenantId())
+                .deploy();
+
+            // 鏇存柊 閮ㄧ讲id 鍒版祦绋嬪畾涔夋ā鍨嬫暟鎹〃涓�
+            model.setDeploymentId(deployment.getId());
+            repositoryService.saveModel(model);
+            // 鏇存柊鍒嗙被
+            ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
+            repositoryService.setProcessDefinitionCategory(definition.getId(), model.getCategory());
+            //鏇存柊娴佺▼瀹氫箟閰嶇疆
+            if (processDefinition != null) {
+                WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(processDefinition.getId());
+                if (definitionVo != null) {
+                    wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(processDefinition.getId()));
+                    WfDefinitionConfigBo wfFormDefinition = new WfDefinitionConfigBo();
+                    wfFormDefinition.setDefinitionId(definition.getId());
+                    wfFormDefinition.setProcessKey(definition.getKey());
+                    wfFormDefinition.setTableName(definitionVo.getTableName());
+                    wfFormDefinition.setVersion(definition.getVersion());
+                    wfFormDefinition.setRemark(definitionVo.getRemark());
+                    wfDefinitionConfigService.saveOrUpdate(wfFormDefinition);
+                }
+            }
+            //鏇存柊娴佺▼鑺傜偣閰嶇疆琛ㄥ崟
+            List<UserTask> userTasks = ModelUtils.getUserTaskFlowElements(definition.getId());
+            UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId());
+            List<WfNodeConfig> wfNodeConfigList = new ArrayList<>();
+            for (UserTask userTask : userTasks) {
+                if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) {
+                    WfNodeConfig wfNodeConfig = new WfNodeConfig();
+                    wfNodeConfig.setNodeId(userTask.getId());
+                    wfNodeConfig.setNodeName(userTask.getName());
+                    wfNodeConfig.setDefinitionId(definition.getId());
+                    String[] split = userTask.getFormKey().split(StrUtil.COLON);
+                    wfNodeConfig.setFormType(split[0]);
+                    wfNodeConfig.setFormId(Long.valueOf(split[1]));
+                    wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE);
+                    wfNodeConfigList.add(wfNodeConfig);
+                }
+            }
+            if (CollUtil.isNotEmpty(wfNodeConfigList)) {
+                wfNodeConfigService.saveOrUpdate(wfNodeConfigList);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 瀵煎嚭妯″瀷zip鍘嬬缉鍖�
+     *
+     * @param modelIds 妯″瀷id
+     * @param response 鐩稿簲
+     */
+    @Override
+    public void exportZip(List<String> modelIds, HttpServletResponse response) {
+        try (ZipOutputStream zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8)) {
+            // 鍘嬬缉鍖呮枃浠跺悕
+            String zipName = "妯″瀷涓嶅瓨鍦�";
+            // 鏌ヨ妯″瀷鍩烘湰淇℃伅
+            for (String modelId : modelIds) {
+                Model model = repositoryService.getModel(modelId);
+                byte[] xmlBytes = repositoryService.getModelEditorSource(modelId);
+                if (ObjectUtil.isNotNull(model)) {
+                    if (JSONUtil.isTypeJSON(new String(xmlBytes, StandardCharsets.UTF_8)) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) {
+                        zipName = "妯″瀷涓嶈兘涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒";
+                        zos.putNextEntry(new ZipEntry(zipName + ".txt"));
+                        zos.write(zipName.getBytes(StandardCharsets.UTF_8));
+                    } else if (ArrayUtil.isEmpty(xmlBytes)) {
+                        zipName = "妯″瀷鏁版嵁涓虹┖锛岃鍏堣璁℃祦绋嬪畾涔夋ā鍨嬶紝鍐嶈繘琛岄儴缃诧紒";
+                        zos.putNextEntry(new ZipEntry(zipName + ".txt"));
+                        zos.write(zipName.getBytes(StandardCharsets.UTF_8));
+                    } else {
+                        String fileName = model.getName() + "-" + model.getKey();
+                        // 鍘嬬缉鍖呮枃浠跺悕
+                        zipName = fileName + ".zip";
+                        // 灏唜ml娣诲姞鍒板帇缂╁寘涓�(鎸囧畾xml鏂囦欢鍚嶏細璇峰亣娴佺▼.bpmn20.xml
+                        zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml"));
+                        zos.write(xmlBytes);
+                    }
+                }
+            }
+            response.setHeader("Content-Disposition",
+                "attachment; filename=" + URLEncoder.encode(zipName, StandardCharsets.UTF_8) + ".zip");
+            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+            // 鍒峰嚭鍝嶅簲娴�
+            response.flushBuffer();
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 澶嶅埗妯″瀷
+     *
+     * @param modelBo 妯″瀷鏁版嵁
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean copyModel(ModelBo modelBo) {
+        try {
+            String key = modelBo.getKey();
+            if (StringUtils.isNotBlank(key)) {
+                // 鏌ヨ妯″瀷
+                Model model = repositoryService.createModelQuery().modelId(modelBo.getId()).singleResult();
+                if (ObjectUtil.isNotNull(model)) {
+                    byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
+                    List<Model> list = QueryUtils.modelQuery().modelKey(key).list();
+                    if (CollUtil.isNotEmpty(list)) {
+                        throw new ServiceException("妯″瀷KEY宸插瓨鍦紒");
+                    }
+                    // 鏍¢獙key鍛藉悕瑙勮寖
+                    if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
+                        throw new ServiceException("妯″瀷鏍囪瘑KEY鍙兘瀛楃鎴栬�呬笅鍒掔嚎寮�澶达紒");
+                    }
+                    // 澶嶅埗妯″瀷鏁版嵁
+                    Model newModel = repositoryService.newModel();
+                    newModel.setKey(modelBo.getKey());
+                    newModel.setName(modelBo.getName());
+                    newModel.setCategory(modelBo.getCategoryCode());
+                    newModel.setVersion(1);
+                    newModel.setMetaInfo(modelBo.getDescription());
+                    newModel.setTenantId(TenantHelper.getTenantId());
+                    String xml = StrUtil.utf8Str(modelEditorSource);
+                    BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml);
+                    Process mainProcess = bpmnModel.getMainProcess();
+                    mainProcess.setId(modelBo.getKey());
+                    mainProcess.setName(modelBo.getName());
+                    byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
+                    repositoryService.saveModel(newModel);
+                    repositoryService.addModelEditorSource(newModel.getId(), xmlBytes);
+                }
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
new file mode 100644
index 0000000..77fb257
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java
@@ -0,0 +1,444 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.domain.WfCategory;
+import org.dromara.workflow.domain.WfDefinitionConfig;
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.workflow.domain.bo.ProcessDefinitionBo;
+import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
+import org.dromara.workflow.domain.vo.ProcessDefinitionVo;
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.workflow.mapper.WfDefinitionConfigMapper;
+import org.dromara.workflow.service.IActProcessDefinitionService;
+import org.dromara.workflow.service.IWfCategoryService;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+import org.dromara.workflow.service.IWfNodeConfigService;
+import org.dromara.workflow.utils.ModelUtils;
+import org.dromara.workflow.utils.QueryUtils;
+import org.flowable.bpmn.model.UserTask;
+import org.flowable.engine.ProcessMigrationService;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil;
+import org.flowable.engine.repository.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * 娴佺▼瀹氫箟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService {
+
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    @Autowired(required = false)
+    private ProcessMigrationService processMigrationService;
+    private final IWfCategoryService wfCategoryService;
+    private final IWfDefinitionConfigService wfDefinitionConfigService;
+    private final WfDefinitionConfigMapper wfDefinitionConfigMapper;
+    private final IWfNodeConfigService wfNodeConfigService;
+
+    /**
+     * 鍒嗛〉鏌ヨ
+     *
+     * @param bo 鍙傛暟
+     * @return 杩斿洖鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<ProcessDefinitionVo> page(ProcessDefinitionBo bo, PageQuery pageQuery) {
+        ProcessDefinitionQuery query = QueryUtils.definitionQuery();
+        if (StringUtils.isNotEmpty(bo.getKey())) {
+            query.processDefinitionKey(bo.getKey());
+        }
+        if (StringUtils.isNotEmpty(bo.getCategoryCode())) {
+            query.processDefinitionCategory(bo.getCategoryCode());
+        }
+        if (StringUtils.isNotEmpty(bo.getName())) {
+            query.processDefinitionNameLike("%" + bo.getName() + "%");
+        }
+        query.orderByDeploymentId().desc();
+        // 鍒嗛〉鏌ヨ
+        List<ProcessDefinitionVo> processDefinitionVoList = new ArrayList<>();
+        List<ProcessDefinition> definitionList = query.latestVersion().listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        List<Deployment> deploymentList = null;
+        if (CollUtil.isNotEmpty(definitionList)) {
+            List<String> deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId);
+            deploymentList = QueryUtils.deploymentQuery(deploymentIds).list();
+        }
+        if (CollUtil.isNotEmpty(definitionList)) {
+            List<String> ids = StreamUtils.toList(definitionList, ProcessDefinition::getId);
+            List<WfDefinitionConfigVo> wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids);
+            for (ProcessDefinition processDefinition : definitionList) {
+                ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class);
+                if (CollUtil.isNotEmpty(deploymentList)) {
+                    // 閮ㄧ讲鏃堕棿
+                    deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> {
+                        processDefinitionVo.setDeploymentTime(e.getDeploymentTime());
+                    });
+                }
+                if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
+                    wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo);
+                }
+                processDefinitionVoList.add(processDefinitionVo);
+            }
+        }
+        // 鎬昏褰曟暟
+        long total = query.count();
+        TableDataInfo<ProcessDefinitionVo> build = TableDataInfo.build();
+        build.setRows(processDefinitionVoList);
+        build.setTotal(total);
+        return build;
+    }
+
+    /**
+     * 鏌ヨ鍘嗗彶娴佺▼瀹氫箟鍒楄〃
+     *
+     * @param key 娴佺▼瀹氫箟key
+     */
+    @Override
+    public List<ProcessDefinitionVo> getListByKey(String key) {
+        List<ProcessDefinitionVo> processDefinitionVoList = new ArrayList<>();
+        ProcessDefinitionQuery query = QueryUtils.definitionQuery();
+        List<ProcessDefinition> definitionList = query.processDefinitionKey(key).list();
+        List<Deployment> deploymentList = null;
+        if (CollUtil.isNotEmpty(definitionList)) {
+            List<String> deploymentIds = StreamUtils.toList(definitionList, ProcessDefinition::getDeploymentId);
+            deploymentList = QueryUtils.deploymentQuery(deploymentIds).list();
+        }
+        if (CollUtil.isNotEmpty(definitionList)) {
+            List<String> ids = StreamUtils.toList(definitionList, ProcessDefinition::getId);
+            List<WfDefinitionConfigVo> wfDefinitionConfigVos = wfDefinitionConfigService.queryList(ids);
+            for (ProcessDefinition processDefinition : definitionList) {
+                ProcessDefinitionVo processDefinitionVo = BeanUtil.toBean(processDefinition, ProcessDefinitionVo.class);
+                if (CollUtil.isNotEmpty(deploymentList)) {
+                    // 閮ㄧ讲鏃堕棿
+                    deploymentList.stream().filter(e -> e.getId().equals(processDefinition.getDeploymentId())).findFirst().ifPresent(e -> {
+                        processDefinitionVo.setDeploymentTime(e.getDeploymentTime());
+                    });
+                    if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
+                        wfDefinitionConfigVos.stream().filter(e -> e.getDefinitionId().equals(processDefinition.getId())).findFirst().ifPresent(processDefinitionVo::setWfDefinitionConfigVo);
+                    }
+                }
+                processDefinitionVoList.add(processDefinitionVo);
+            }
+        }
+        return CollUtil.reverse(processDefinitionVoList);
+    }
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟鍥剧墖
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @SneakyThrows
+    @Override
+    public String definitionImage(String processDefinitionId) {
+        InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
+        return Base64.encode(IoUtil.readBytes(inputStream));
+    }
+
+    /**
+     * 鏌ョ湅娴佺▼瀹氫箟xml鏂囦欢
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @Override
+    public String definitionXml(String processDefinitionId) {
+        StringBuilder xml = new StringBuilder();
+        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
+        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
+        xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
+        return xml.toString();
+    }
+
+    /**
+     * 鍒犻櫎娴佺▼瀹氫箟
+     *
+     * @param deploymentIds        閮ㄧ讲id
+     * @param processDefinitionIds 娴佺▼瀹氫箟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteDeployment(List<String> deploymentIds, List<String> processDefinitionIds) {
+        try {
+            List<HistoricProcessInstance> historicProcessInstances = QueryUtils.hisInstanceQuery().deploymentIdIn(deploymentIds).list();
+            if (CollUtil.isNotEmpty(historicProcessInstances)) {
+                Set<String> defIds = StreamUtils.toSet(historicProcessInstances, HistoricProcessInstance::getProcessDefinitionId);
+                List<ProcessDefinition> processDefinitions = QueryUtils.definitionQuery().processDefinitionIds(defIds).list();
+                if (CollUtil.isNotEmpty(processDefinitions)) {
+                    Set<String> keys = StreamUtils.toSet(processDefinitions, ProcessDefinition::getKey);
+                    throw new ServiceException("褰撳墠銆�" + String.join(",", keys) + "銆戞祦绋嬪畾涔夊凡琚娇鐢ㄤ笉鍙垹闄わ紒");
+                }
+            }
+            //鍒犻櫎娴佺▼瀹氫箟
+            for (String deploymentId : deploymentIds) {
+                repositoryService.deleteDeployment(deploymentId);
+            }
+            //鍒犻櫎娴佺▼瀹氫箟閰嶇疆
+            wfDefinitionConfigService.deleteByDefIds(processDefinitionIds);
+            //鍒犻櫎鑺傜偣閰嶇疆
+            wfNodeConfigService.deleteByDefIds(processDefinitionIds);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 婵�娲绘垨鑰呮寕璧锋祦绋嬪畾涔�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @Override
+    public boolean updateDefinitionState(String processDefinitionId) {
+        try {
+            ProcessDefinition processDefinition = QueryUtils.definitionQuery()
+                .processDefinitionId(processDefinitionId).singleResult();
+            //灏嗗綋鍓嶄负鎸傝捣鐘舵�佹洿鏂颁负婵�娲荤姸鎬�
+            //鍙傛暟璇存槑锛氬弬鏁�1锛氭祦绋嬪畾涔塱d,鍙傛暟2锛氭槸鍚︽縺娲伙紙true鏄惁绾ц仈瀵瑰簲娴佺▼瀹炰緥锛屾縺娲讳簡鍒欏搴旀祦绋嬪疄渚嬮兘鍙互瀹℃壒锛夛紝
+            //鍙傛暟3锛氫粈涔堟椂鍊欐縺娲伙紝濡傛灉涓簄ull鍒欑珛鍗虫縺娲伙紝濡傛灉涓哄叿浣撴椂闂村垯鍒拌揪姝ゆ椂闂村悗婵�娲�
+            if (processDefinition.isSuspended()) {
+                repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
+            } else {
+                repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException("鎿嶄綔澶辫触:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 杩佺Щ娴佺▼瀹氫箟
+     *
+     * @param currentProcessDefinitionId 褰撳墠娴佺▼瀹氫箟id
+     * @param fromProcessDefinitionId    闇�瑕佽縼绉诲埌鐨勬祦绋嬪畾涔塱d
+     */
+
+    @Override
+    public boolean migrationDefinition(String currentProcessDefinitionId, String fromProcessDefinitionId) {
+        try {
+            // 杩佺Щ楠岃瘉
+            boolean migrationValid = processMigrationService.createProcessInstanceMigrationBuilder()
+                .migrateToProcessDefinition(currentProcessDefinitionId)
+                .validateMigrationOfProcessInstances(fromProcessDefinitionId)
+                .isMigrationValid();
+            if (!migrationValid) {
+                throw new ServiceException("娴佺▼瀹氫箟宸紓杩囧ぇ鏃犳硶杩佺Щ锛岃淇敼娴佺▼鍥�");
+            }
+            // 宸茬粨鏉熺殑娴佺▼瀹炰緥涓嶄細杩佺Щ
+            processMigrationService.createProcessInstanceMigrationBuilder()
+                .migrateToProcessDefinition(currentProcessDefinitionId)
+                .migrateProcessInstances(fromProcessDefinitionId);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 娴佺▼瀹氫箟杞崲涓烘ā鍨�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    @Override
+    public boolean convertToModel(String processDefinitionId) {
+        ProcessDefinition pd = QueryUtils.definitionQuery()
+            .processDefinitionId(processDefinitionId).singleResult();
+        InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName());
+        ModelQuery query = QueryUtils.modelQuery();
+        Model model = query.modelKey(pd.getKey()).singleResult();
+        try {
+            if (ObjectUtil.isNotNull(model)) {
+                repositoryService.addModelEditorSource(model.getId(), IoUtil.readBytes(inputStream));
+            } else {
+                Model modelData = repositoryService.newModel();
+                modelData.setKey(pd.getKey());
+                modelData.setName(pd.getName());
+                modelData.setCategory(pd.getCategory());
+                modelData.setTenantId(pd.getTenantId());
+                repositoryService.saveModel(modelData);
+                repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream));
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 閫氳繃zip鎴杧ml閮ㄧ讲娴佺▼瀹氫箟
+     *
+     * @param file         鏂囦欢
+     * @param categoryCode 鍒嗙被
+     */
+    @SneakyThrows
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deployByFile(MultipartFile file, String categoryCode) {
+
+        WfCategory wfCategory = wfCategoryService.queryByCategoryCode(categoryCode);
+        if (wfCategory == null) {
+            throw new ServiceException("娴佺▼鍒嗙被涓嶅瓨鍦�");
+        }
+        // 鏂囦欢鍚庣紑鍚�
+        String suffix = FileUtil.extName(file.getOriginalFilename());
+        InputStream inputStream = file.getInputStream();
+        if (FlowConstant.ZIP.equalsIgnoreCase(suffix)) {
+            ZipInputStream zipInputStream = null;
+            try {
+                zipInputStream = new ZipInputStream(inputStream);
+                ZipEntry zipEntry;
+                while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                    String filename = zipEntry.getName();
+                    String[] splitFilename = filename.substring(0, filename.lastIndexOf(".")).split("-");
+                    //娴佺▼鍚嶇О
+                    String processName = splitFilename[0];
+                    //娴佺▼key
+                    String processKey = splitFilename[1];
+                    ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
+                    DeploymentBuilder builder = repositoryService.createDeployment();
+                    Deployment deployment = builder.addInputStream(filename, zipInputStream)
+                        .tenantId(TenantHelper.getTenantId())
+                        .name(processName).key(processKey).category(categoryCode).deploy();
+                    ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
+                    repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode);
+                    setWfConfig(oldProcessDefinition, definition);
+                    zipInputStream.closeEntry();
+                }
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            } finally {
+                if (zipInputStream != null) {
+                    zipInputStream.close();
+                }
+            }
+            //鍒濆鍖栭厤缃暟鎹紙demo浣跨敤锛屼笉鐢ㄥ彲鍒犻櫎锛�
+            initWfDefConfig();
+        } else {
+            String originalFilename = file.getOriginalFilename();
+            if (StringUtils.containsAny(originalFilename, ResourceNameUtil.BPMN_RESOURCE_SUFFIXES)) {
+                // 鏂囦欢鍚� = 娴佺▼鍚嶇О-娴佺▼key
+                String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-");
+                if (splitFilename.length < 2) {
+                    throw new ServiceException("鏂囦欢鍚� = 娴佺▼鍚嶇О-娴佺▼KEY");
+                }
+                //娴佺▼鍚嶇О
+                String processName = splitFilename[0];
+                //娴佺▼key
+                String processKey = splitFilename[1];
+                ProcessDefinition oldProcessDefinition = QueryUtils.definitionQuery().processDefinitionKey(processKey).latestVersion().singleResult();
+                DeploymentBuilder builder = repositoryService.createDeployment();
+                Deployment deployment = builder.addInputStream(originalFilename, inputStream)
+                    .tenantId(TenantHelper.getTenantId())
+                    .name(processName).key(processKey).category(categoryCode).deploy();
+                // 鏇存柊鍒嗙被
+                ProcessDefinition definition = QueryUtils.definitionQuery().deploymentId(deployment.getId()).singleResult();
+                repositoryService.setProcessDefinitionCategory(definition.getId(), categoryCode);
+                setWfConfig(oldProcessDefinition, definition);
+            } else {
+                throw new ServiceException("鏂囦欢绫诲瀷涓婁紶閿欒锛�");
+            }
+        }
+
+    }
+
+    /**
+     * 鍒濆鍖栭厤缃暟鎹紙demo浣跨敤锛屼笉鐢ㄥ彲鍒犻櫎锛�
+     */
+    private void initWfDefConfig() {
+        List<WfDefinitionConfig> wfDefinitionConfigs = wfDefinitionConfigMapper.selectList();
+        if (CollUtil.isEmpty(wfDefinitionConfigs)) {
+            ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionKey("leave1").latestVersion().singleResult();
+            if (processDefinition != null) {
+                WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo();
+                wfDefinitionConfigBo.setDefinitionId(processDefinition.getId());
+                wfDefinitionConfigBo.setProcessKey(processDefinition.getKey());
+                wfDefinitionConfigBo.setTableName("test_leave");
+                wfDefinitionConfigBo.setVersion(processDefinition.getVersion());
+                wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo);
+            }
+        }
+
+    }
+
+    /**
+     * 璁剧疆琛ㄥ崟鍐呭
+     *
+     * @param oldProcessDefinition 閮ㄧ讲鍓嶆渶鏂版祦绋嬪畾涔�
+     * @param definition           閮ㄧ讲鍚庢渶鏂版祦绋嬪畾涔�
+     */
+    private void setWfConfig(ProcessDefinition oldProcessDefinition, ProcessDefinition definition) {
+        //鏇存柊娴佺▼瀹氫箟琛ㄥ崟
+        if (oldProcessDefinition != null) {
+            WfDefinitionConfigVo definitionVo = wfDefinitionConfigService.getByDefId(oldProcessDefinition.getId());
+            if (definitionVo != null) {
+                wfDefinitionConfigService.deleteByDefIds(Collections.singletonList(oldProcessDefinition.getId()));
+                WfDefinitionConfigBo wfDefinitionConfigBo = new WfDefinitionConfigBo();
+                wfDefinitionConfigBo.setDefinitionId(definition.getId());
+                wfDefinitionConfigBo.setProcessKey(definition.getKey());
+                wfDefinitionConfigBo.setTableName(definitionVo.getTableName());
+                wfDefinitionConfigBo.setVersion(definition.getVersion());
+                wfDefinitionConfigBo.setRemark(definitionVo.getRemark());
+                wfDefinitionConfigService.saveOrUpdate(wfDefinitionConfigBo);
+            }
+        }
+        //鏇存柊娴佺▼鑺傜偣閰嶇疆琛ㄥ崟
+        List<UserTask> userTasks = ModelUtils.getUserTaskFlowElements(definition.getId());
+        UserTask applyUserTask = ModelUtils.getApplyUserTask(definition.getId());
+        List<WfNodeConfig> wfNodeConfigList = new ArrayList<>();
+        for (UserTask userTask : userTasks) {
+            if (StringUtils.isNotBlank(userTask.getFormKey()) && userTask.getFormKey().contains(StrUtil.COLON)) {
+                WfNodeConfig wfNodeConfig = new WfNodeConfig();
+                wfNodeConfig.setNodeId(userTask.getId());
+                wfNodeConfig.setNodeName(userTask.getName());
+                wfNodeConfig.setDefinitionId(definition.getId());
+                String[] split = userTask.getFormKey().split(StrUtil.COLON);
+                wfNodeConfig.setFormType(split[0]);
+                wfNodeConfig.setFormId(Long.valueOf(split[1]));
+                wfNodeConfig.setApplyUserTask(applyUserTask.getId().equals(userTask.getId()) ? FlowConstant.TRUE : FlowConstant.FALSE);
+                wfNodeConfigList.add(wfNodeConfig);
+            }
+        }
+        if (CollUtil.isNotEmpty(wfNodeConfigList)) {
+            wfNodeConfigService.saveOrUpdate(wfNodeConfigList);
+        }
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
new file mode 100644
index 0000000..8b9b113
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java
@@ -0,0 +1,691 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.ActHiProcinst;
+import org.dromara.workflow.domain.bo.ProcessInstanceBo;
+import org.dromara.workflow.domain.bo.ProcessInvalidBo;
+import org.dromara.workflow.domain.bo.TaskUrgingBo;
+import org.dromara.workflow.domain.vo.*;
+import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator;
+import org.dromara.workflow.flowable.cmd.DeleteExecutionCmd;
+import org.dromara.workflow.flowable.cmd.ExecutionChildByExecutionIdCmd;
+import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
+import org.dromara.workflow.service.IActHiProcinstService;
+import org.dromara.workflow.service.IActProcessInstanceService;
+import org.dromara.workflow.service.IWfNodeConfigService;
+import org.dromara.workflow.service.IWfTaskBackNodeService;
+import org.dromara.workflow.utils.QueryUtils;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.engine.*;
+import org.flowable.engine.history.HistoricActivityInstance;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.runtime.ProcessInstanceQuery;
+import org.flowable.engine.task.Attachment;
+import org.flowable.engine.task.Comment;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.awt.*;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.*;
+
+/**
+ * 娴佺▼瀹炰緥 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ActProcessInstanceServiceImpl implements IActProcessInstanceService {
+
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
+    @Autowired(required = false)
+    private HistoryService historyService;
+    @Autowired(required = false)
+    private TaskService taskService;
+    @Autowired(required = false)
+    private ManagementService managementService;
+    private final IActHiProcinstService actHiProcinstService;
+    private final IWfTaskBackNodeService wfTaskBackNodeService;
+    private final IWfNodeConfigService wfNodeConfigService;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+    private final UserService userService;
+
+    @Value("${flowable.activity-font-name}")
+    private String activityFontName;
+
+    @Value("${flowable.label-font-name}")
+    private String labelFontName;
+
+    @Value("${flowable.annotation-font-name}")
+    private String annotationFontName;
+
+    /**
+     * 鍒嗛〉鏌ヨ姝e湪杩愯鐨勬祦绋嬪疄渚�
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<ProcessInstanceVo> getPageByRunning(ProcessInstanceBo bo, PageQuery pageQuery) {
+        List<ProcessInstanceVo> list = new ArrayList<>();
+        ProcessInstanceQuery query = QueryUtils.instanceQuery();
+        if (StringUtils.isNotBlank(bo.getName())) {
+            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(bo.getKey())) {
+            query.processDefinitionKey(bo.getKey());
+        }
+        if (StringUtils.isNotBlank(bo.getStartUserId())) {
+            query.startedBy(bo.getStartUserId());
+        }
+        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
+            query.processInstanceBusinessKey(bo.getBusinessKey());
+        }
+        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
+            query.processDefinitionCategory(bo.getCategoryCode());
+        }
+        query.orderByStartTime().desc();
+        List<ProcessInstance> processInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        for (ProcessInstance processInstance : processInstances) {
+            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class);
+            processInstanceVo.setIsSuspended(processInstance.isSuspended());
+            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus()));
+            list.add(processInstanceVo);
+        }
+        if (CollUtil.isNotEmpty(list)) {
+            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (ProcessInstanceVo processInstanceVo : list) {
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
+                }
+            }
+        }
+        long count = query.count();
+        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
+        build.setRows(list);
+        build.setTotal(count);
+        return build;
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ宸茬粨鏉熺殑娴佺▼瀹炰緥
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<ProcessInstanceVo> getPageByFinish(ProcessInstanceBo bo, PageQuery pageQuery) {
+        List<ProcessInstanceVo> list = new ArrayList<>();
+        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery()
+            .finished().orderByProcessInstanceEndTime().desc();
+        if (StringUtils.isNotEmpty(bo.getName())) {
+            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(bo.getKey())) {
+            query.processDefinitionKey(bo.getKey());
+        }
+        if (StringUtils.isNotEmpty(bo.getStartUserId())) {
+            query.startedBy(bo.getStartUserId());
+        }
+        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
+            query.processInstanceBusinessKey(bo.getBusinessKey());
+        }
+        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
+            query.processDefinitionCategory(bo.getCategoryCode());
+        }
+        List<HistoricProcessInstance> historicProcessInstances = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
+            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(historicProcessInstance, ProcessInstanceVo.class);
+            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(historicProcessInstance.getBusinessStatus()));
+            list.add(processInstanceVo);
+        }
+        if (CollUtil.isNotEmpty(list)) {
+            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (ProcessInstanceVo processInstanceVo : list) {
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
+                }
+            }
+        }
+        long count = query.count();
+        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
+        build.setRows(list);
+        build.setTotal(count);
+        return build;
+    }
+
+    /**
+     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥�
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @SneakyThrows
+    @Override
+    public String getHistoryImage(String businessKey) {
+        String processDefinitionId;
+        // 鑾峰彇褰撳墠鐨勬祦绋嬪疄渚�
+        ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey).singleResult();
+        // 濡傛灉娴佺▼宸茬粡缁撴潫锛屽垯寰楀埌缁撴潫鑺傜偣
+        if (Objects.isNull(processInstance)) {
+            HistoricProcessInstance pi = QueryUtils.hisInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
+            processDefinitionId = pi.getProcessDefinitionId();
+        } else {
+            // 鏍规嵁娴佺▼瀹炰緥ID鑾峰緱褰撳墠澶勪簬娲诲姩鐘舵�佺殑ActivityId鍚堥泦
+            ProcessInstance pi = QueryUtils.instanceQuery(processInstance.getProcessInstanceId()).singleResult();
+            processDefinitionId = pi.getProcessDefinitionId();
+        }
+
+        // 鑾峰緱娲诲姩鐨勮妭鐐�
+        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstance.getProcessInstanceId()).orderByHistoricActivityInstanceStartTime().asc().list();
+
+        List<String> highLightedFlows = new ArrayList<>();
+        List<String> highLightedNodes = new ArrayList<>();
+        //楂樹寒
+        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
+            if (FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType())) {
+                //楂樹寒绾�
+                highLightedFlows.add(tempActivity.getActivityId());
+            } else {
+                //楂樹寒鑺傜偣
+                if (tempActivity.getEndTime() == null) {
+                    highLightedNodes.add(Color.RED.toString() + tempActivity.getActivityId());
+                } else {
+                    highLightedNodes.add(tempActivity.getActivityId());
+                }
+            }
+        }
+        List<String> highLightedNodeList = new ArrayList<>();
+        //杩愯涓殑鑺傜偣
+        List<String> redNodeCollect = StreamUtils.filter(highLightedNodes, e -> e.contains(Color.RED.toString()));
+        //鎺掗櫎涓庤繍琛屼腑鐩稿悓鐨勮妭鐐�
+        for (String nodeId : highLightedNodes) {
+            if (!nodeId.contains(Color.RED.toString()) && !redNodeCollect.contains(Color.RED + nodeId)) {
+                highLightedNodeList.add(nodeId);
+            }
+        }
+        highLightedNodeList.addAll(redNodeCollect);
+        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
+        CustomDefaultProcessDiagramGenerator diagramGenerator = new CustomDefaultProcessDiagramGenerator();
+        InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodeList, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0, true);
+        return Base64.encode(IoUtil.readBytes(inputStream));
+    }
+
+    /**
+     * 閫氳繃涓氬姟id鑾峰彇鍘嗗彶娴佺▼鍥捐繍琛屼腑锛屽巻鍙茬瓑鑺傜偣
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Override
+    public Map<String, Object> getHistoryList(String businessKey) {
+        Map<String, Object> map = new HashMap<>();
+        List<Map<String, Object>> taskList = new ArrayList<>();
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
+        String processInstanceId = historicProcessInstance.getId();
+        StringBuilder xml = new StringBuilder();
+        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
+        // 鑾峰彇鑺傜偣
+        List<HistoricActivityInstance> highLightedFlowList = QueryUtils.hisActivityInstanceQuery(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
+        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
+            Map<String, Object> task = new HashMap<>();
+            switch (tempActivity.getActivityType()) {
+                case FlowConstant.SEQUENCE_FLOW, FlowConstant.PARALLEL_GATEWAY,
+                     FlowConstant.EXCLUSIVE_GATEWAY, FlowConstant.INCLUSIVE_GATEWAY -> {}
+                default -> {
+                    task.put("key", tempActivity.getActivityId());
+                    task.put("completed", tempActivity.getEndTime() != null);
+                    task.put("activityType", tempActivity.getActivityType());
+                    taskList.add(task);
+                }
+            }
+        }
+        ProcessInstance processInstance = QueryUtils.instanceQuery(processInstanceId).singleResult();
+        if (processInstance != null) {
+            taskList = StreamUtils.filter(taskList, e -> !e.get("activityType").equals(FlowConstant.END_EVENT));
+        }
+        //鏌ヨ鍑鸿繍琛屼腑鑺傜偣
+        List<Map<String, Object>> runtimeNodeList = StreamUtils.filter(taskList, e -> !(Boolean) e.get("completed"));
+        if (CollUtil.isNotEmpty(runtimeNodeList)) {
+            Iterator<Map<String, Object>> iterator = taskList.iterator();
+            while (iterator.hasNext()) {
+                Map<String, Object> next = iterator.next();
+                runtimeNodeList.stream().filter(t -> t.get("key").equals(next.get("key")) && (Boolean) next.get("completed")).findFirst().ifPresent(t -> iterator.remove());
+            }
+        }
+        map.put("taskList", taskList);
+        List<ActHistoryInfoVo> historyTaskList = getHistoryTaskList(processInstanceId, processDefinition.getVersion());
+        map.put("historyList", historyTaskList);
+        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
+        xml.append(IoUtil.read(inputStream, StandardCharsets.UTF_8));
+        map.put("xml", xml.toString());
+        return map;
+    }
+
+    /**
+     * 鑾峰彇鍘嗗彶浠诲姟鑺傜偣淇℃伅
+     *
+     * @param processInstanceId 娴佺▼瀹炰緥id
+     * @param version           鐗堟湰
+     */
+    private List<ActHistoryInfoVo> getHistoryTaskList(String processInstanceId, Integer version) {
+        //鏌ヨ浠诲姟鍔炵悊璁板綍
+        List<HistoricTaskInstance> list = QueryUtils.hisTaskInstanceQuery(processInstanceId).orderByHistoricTaskInstanceEndTime().desc().list();
+        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
+        List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
+        for (HistoricTaskInstance historicTaskInstance : list) {
+            ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo();
+            BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo);
+            actHistoryInfoVo.setStatus(actHistoryInfoVo.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
+            if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
+                actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
+            }
+            actHistoryInfoVo.setVersion(version);
+            actHistoryInfoVoList.add(actHistoryInfoVo);
+        }
+        List<ActHistoryInfoVo> historyInfoVoList = new ArrayList<>();
+        Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
+        for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
+            ActHistoryInfoVo historyInfoVo = new ActHistoryInfoVo();
+            if (entry.getValue().size() > 1) {
+                List<ActHistoryInfoVo> historyInfoVos = StreamUtils.filter(entry.getValue(), e -> StringUtils.isNotBlank(e.getAssignee()));
+                if (CollUtil.isNotEmpty(historyInfoVos)) {
+                    ActHistoryInfoVo infoVo = historyInfoVos.get(0);
+                    BeanUtils.copyProperties(infoVo, historyInfoVo);
+                    historyInfoVo.setStatus(infoVo.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
+                    historyInfoVo.setStartTime(infoVo.getStartTime());
+                    historyInfoVo.setEndTime(infoVo.getEndTime() == null ? null : infoVo.getEndTime());
+                    historyInfoVo.setRunDuration(infoVo.getEndTime() == null ? null : infoVo.getRunDuration());
+                    if (ObjectUtil.isEmpty(infoVo.getAssignee())) {
+                        ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(infoVo.getId(), userService);
+                        if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
+                            historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
+                        }
+                    }
+                }
+            } else {
+                actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey())).findFirst()
+                    .ifPresent(e -> {
+                        BeanUtils.copyProperties(e, historyInfoVo);
+                        historyInfoVo.setStatus(e.getEndTime() == null ? "寰呭鐞�" : "宸插鐞�");
+                        historyInfoVo.setStartTime(e.getStartTime());
+                        historyInfoVo.setEndTime(e.getEndTime() == null ? null : e.getEndTime());
+                        historyInfoVo.setRunDuration(e.getEndTime() == null ? null : e.getRunDuration());
+                        if (ObjectUtil.isEmpty(e.getAssignee())) {
+                            ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(e.getId(), userService);
+                            if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
+                                historyInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
+                            }
+                        }
+                    });
+
+            }
+            historyInfoVoList.add(historyInfoVo);
+
+        }
+        return historyInfoVoList;
+    }
+
+    /**
+     * 鑾峰彇瀹℃壒璁板綍
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Override
+    public List<ActHistoryInfoVo> getHistoryRecord(String businessKey) {
+        // 鏌ヨ浠诲姟鍔炵悊璁板綍
+        List<HistoricTaskInstance> list = QueryUtils.hisTaskBusinessKeyQuery(businessKey).orderByHistoricTaskInstanceEndTime().desc().list();
+        list = StreamUtils.sorted(list, Comparator.comparing(HistoricTaskInstance::getEndTime, Comparator.nullsFirst(Date::compareTo)).reversed());
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
+        String processInstanceId = historicProcessInstance.getId();
+        List<ActHistoryInfoVo> actHistoryInfoVoList = new ArrayList<>();
+        List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
+        //闄勪欢
+        List<Attachment> attachmentList = taskService.getProcessInstanceAttachments(processInstanceId);
+        for (HistoricTaskInstance historicTaskInstance : list) {
+            ActHistoryInfoVo actHistoryInfoVo = new ActHistoryInfoVo();
+            BeanUtils.copyProperties(historicTaskInstance, actHistoryInfoVo);
+            if (actHistoryInfoVo.getEndTime() == null) {
+                actHistoryInfoVo.setStatus(TaskStatusEnum.WAITING.getStatus());
+                actHistoryInfoVo.setStatusName(TaskStatusEnum.WAITING.getDesc());
+            }
+            if (CollUtil.isNotEmpty(processInstanceComments)) {
+                processInstanceComments.stream().filter(e -> e.getTaskId().equals(historicTaskInstance.getId())).findFirst().ifPresent(e -> {
+                    actHistoryInfoVo.setComment(e.getFullMessage());
+                    actHistoryInfoVo.setStatus(e.getType());
+                    actHistoryInfoVo.setStatusName(TaskStatusEnum.findByStatus(e.getType()));
+                });
+            }
+            if (ObjectUtil.isNotEmpty(historicTaskInstance.getDurationInMillis())) {
+                actHistoryInfoVo.setRunDuration(getDuration(historicTaskInstance.getDurationInMillis()));
+            }
+            //闄勪欢
+            if (CollUtil.isNotEmpty(attachmentList)) {
+                List<Attachment> attachments = StreamUtils.filter(attachmentList, e -> e.getTaskId().equals(historicTaskInstance.getId()));
+                if (CollUtil.isNotEmpty(attachments)) {
+                    actHistoryInfoVo.setAttachmentList(attachments);
+                }
+            }
+            //璁剧疆浜哄憳id
+            if (ObjectUtil.isEmpty(historicTaskInstance.getAssignee())) {
+                ParticipantVo participantVo = WorkflowUtils.getCurrentTaskParticipant(historicTaskInstance.getId(), userService);
+                if (ObjectUtil.isNotEmpty(participantVo) && CollUtil.isNotEmpty(participantVo.getCandidate())) {
+                    actHistoryInfoVo.setAssignee(StreamUtils.join(participantVo.getCandidate(), Convert::toStr));
+                }
+            }
+            actHistoryInfoVoList.add(actHistoryInfoVo);
+        }
+        // 瀹℃壒璁板綍
+        Map<String, List<ActHistoryInfoVo>> groupByKey = StreamUtils.groupByKey(actHistoryInfoVoList, ActHistoryInfoVo::getTaskDefinitionKey);
+        for (Map.Entry<String, List<ActHistoryInfoVo>> entry : groupByKey.entrySet()) {
+            ActHistoryInfoVo actHistoryInfoVo = BeanUtil.toBean(entry.getValue().get(0), ActHistoryInfoVo.class);
+            actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() != null).findFirst()
+                .ifPresent(e -> {
+                    actHistoryInfoVo.setStatus("宸插鐞�");
+                    actHistoryInfoVo.setStartTime(e.getStartTime());
+                });
+            actHistoryInfoVoList.stream().filter(e -> e.getTaskDefinitionKey().equals(entry.getKey()) && e.getEndTime() == null).findFirst()
+                .ifPresent(e -> {
+                    actHistoryInfoVo.setStatus("寰呭鐞�");
+                    actHistoryInfoVo.setStartTime(e.getStartTime());
+                    actHistoryInfoVo.setEndTime(null);
+                    actHistoryInfoVo.setRunDuration(null);
+                });
+        }
+        List<ActHistoryInfoVo> recordList = new ArrayList<>();
+        // 寰呭姙鐞�
+        recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() == null));
+        // 宸插姙鐞�
+        recordList.addAll(StreamUtils.filter(actHistoryInfoVoList, e -> e.getEndTime() != null));
+
+        return recordList;
+    }
+
+    /**
+     * 浠诲姟瀹屾垚鏃堕棿澶勭悊
+     *
+     * @param time 鏃堕棿
+     */
+    private String getDuration(long time) {
+
+        long day = time / (24 * 60 * 60 * 1000);
+        long hour = (time / (60 * 60 * 1000) - day * 24);
+        long minute = ((time / (60 * 1000)) - day * 24 * 60 - hour * 60);
+        long second = (time / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
+
+        if (day > 0) {
+            return day + "澶�" + hour + "灏忔椂" + minute + "鍒嗛挓";
+        }
+        if (hour > 0) {
+            return hour + "灏忔椂" + minute + "鍒嗛挓";
+        }
+        if (minute > 0) {
+            return minute + "鍒嗛挓";
+        }
+        if (second > 0) {
+            return second + "绉�";
+        } else {
+            return 0 + "绉�";
+        }
+    }
+
+    /**
+     * 浣滃簾娴佺▼瀹炰緥锛屼笉浼氬垹闄ゅ巻鍙茶褰�(鍒犻櫎杩愯涓殑瀹炰緥)
+     *
+     * @param processInvalidBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteRunInstance(ProcessInvalidBo processInvalidBo) {
+        try {
+            List<Task> list = QueryUtils.taskQuery().processInstanceBusinessKey(processInvalidBo.getBusinessKey()).list();
+            String processInstanceId = list.get(0).getProcessInstanceId();
+            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
+            if (CollUtil.isNotEmpty(subTasks)) {
+                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
+            }
+            String deleteReason = LoginHelper.getLoginUser().getNickname() + "浣滃簾浜嗗綋鍓嶇敵璇凤紒";
+            if (StringUtils.isNotBlank(processInvalidBo.getDeleteReason())) {
+                deleteReason = LoginHelper.getLoginUser().getNickname() + "浣滃簾鐞嗙敱:" + processInvalidBo.getDeleteReason();
+            }
+            for (Task task : StreamUtils.filter(list, e -> StringUtils.isBlank(e.getParentTaskId()))) {
+                taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.INVALID.getStatus(), deleteReason);
+            }
+            HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(processInstanceId).singleResult();
+            BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
+            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.INVALID.getStatus());
+            runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
+            //娴佺▼浣滃簾鐩戝惉
+            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
+                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.INVALID.getStatus(), false);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
+        try {
+            // 1.鍒犻櫎杩愯涓祦绋嬪疄渚�
+            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
+            if (CollUtil.isEmpty(actHiProcinsts)) {
+                log.warn("褰撳墠涓氬姟ID:{}鏌ヨ鍒版祦绋嬪疄渚嬩负绌猴紒", businessKeys);
+                return false;
+            }
+            List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
+            List<Task> list = QueryUtils.taskQuery(processInstanceIds).list();
+            List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
+            if (CollUtil.isNotEmpty(subTasks)) {
+                subTasks.forEach(e -> taskService.deleteTask(e.getId()));
+            }
+            runtimeService.bulkDeleteProcessInstances(processInstanceIds, LoginHelper.getUserId() + "鍒犻櫎浜嗗綋鍓嶆祦绋嬬敵璇�");
+            // 2.鍒犻櫎鍘嗗彶璁板綍
+            List<HistoricProcessInstance> historicProcessInstanceList = QueryUtils.hisInstanceQuery(new HashSet<>(processInstanceIds)).list();
+            if (ObjectUtil.isNotEmpty(historicProcessInstanceList)) {
+                historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
+            }
+            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 宸插畬鎴愮殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteFinishAndHisInstance(List<String> businessKeys) {
+        try {
+            List<ActHiProcinst> actHiProcinsts = actHiProcinstService.selectByBusinessKeyIn(businessKeys);
+            if (CollUtil.isEmpty(actHiProcinsts)) {
+                log.warn("褰撳墠涓氬姟ID:{}鏌ヨ鍒版祦绋嬪疄渚嬩负绌猴紒", businessKeys);
+                return false;
+            }
+            List<String> processInstanceIds = StreamUtils.toList(actHiProcinsts, ActHiProcinst::getId);
+            historyService.bulkDeleteHistoricProcessInstances(processInstanceIds);
+            wfTaskBackNodeService.deleteByInstanceIds(processInstanceIds);
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鎾ら攢娴佺▼鐢宠
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean cancelProcessApply(String businessKey) {
+        try {
+            ProcessInstance processInstance = QueryUtils.businessKeyQuery(businessKey)
+                .startedBy(String.valueOf(LoginHelper.getUserId())).singleResult();
+            if (ObjectUtil.isNull(processInstance)) {
+                throw new ServiceException("鎮ㄤ笉鏄祦绋嬪彂璧蜂汉,鎾ら攢澶辫触!");
+            }
+            if (processInstance.isSuspended()) {
+                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+            }
+            String processInstanceId = processInstance.getId();
+            BusinessStatusEnum.checkCancelStatus(processInstance.getBusinessStatus());
+            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
+            for (Task task : taskList) {
+                taskService.setAssignee(task.getId(), null);
+                taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.CANCEL.getStatus(), LoginHelper.getLoginUser().getNickname() + "锛氭挙閿�鐢宠");
+            }
+            HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().asc().list().get(0);
+            List<String> nodeIds = StreamUtils.toList(taskList, Task::getTaskDefinitionKey);
+            runtimeService.createChangeActivityStateBuilder()
+                .processInstanceId(processInstanceId)
+                .moveActivityIdsToSingleActivityId(nodeIds, historicTaskInstance.getTaskDefinitionKey()).changeState();
+            Task task = QueryUtils.taskQuery(processInstanceId).list().get(0);
+            taskService.setAssignee(task.getId(), historicTaskInstance.getAssignee());
+            //鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
+            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
+            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
+            //鍒犻櫎娴佺▼瀹炰緥鍨冨溇鏁版嵁
+            for (ExecutionEntity executionEntity : executionEntities) {
+                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
+                managementService.executeCommand(deleteExecutionCmd);
+            }
+            runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.CANCEL.getStatus());
+            //娴佺▼浣滃簾鐩戝惉
+            flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
+                processInstance.getBusinessKey(), BusinessStatusEnum.CANCEL.getStatus(), false);
+            return true;
+        } catch (Exception e) {
+            log.error("鎾ら攢澶辫触:" + e.getMessage(), e);
+            throw new ServiceException("鎾ら攢澶辫触:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ褰撳墠鐧诲綍浜哄崟鎹�
+     *
+     * @param bo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<ProcessInstanceVo> getPageByCurrent(ProcessInstanceBo bo, PageQuery pageQuery) {
+        List<ProcessInstanceVo> list = new ArrayList<>();
+        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
+        query.startedBy(String.valueOf(LoginHelper.getUserId()));
+        if (StringUtils.isNotBlank(bo.getName())) {
+            query.processInstanceNameLikeIgnoreCase("%" + bo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(bo.getKey())) {
+            query.processDefinitionKey(bo.getKey());
+        }
+        if (StringUtils.isNotBlank(bo.getBusinessKey())) {
+            query.processInstanceBusinessKey(bo.getBusinessKey());
+        }
+        if (StringUtils.isNotBlank(bo.getCategoryCode())) {
+            query.processDefinitionCategory(bo.getCategoryCode());
+        }
+        query.orderByProcessInstanceStartTime().desc();
+        List<HistoricProcessInstance> historicProcessInstanceList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        List<TaskVo> taskVoList = new ArrayList<>();
+        if (CollUtil.isNotEmpty(historicProcessInstanceList)) {
+            List<String> processInstanceIds = StreamUtils.toList(historicProcessInstanceList, HistoricProcessInstance::getId);
+            List<Task> taskList = QueryUtils.taskQuery(processInstanceIds).list();
+            for (Task task : taskList) {
+                taskVoList.add(BeanUtil.toBean(task, TaskVo.class));
+            }
+        }
+        for (HistoricProcessInstance processInstance : historicProcessInstanceList) {
+            ProcessInstanceVo processInstanceVo = BeanUtil.toBean(processInstance, ProcessInstanceVo.class);
+            processInstanceVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(processInstance.getBusinessStatus()));
+            if (CollUtil.isNotEmpty(taskVoList)) {
+                List<TaskVo> collect = StreamUtils.filter(taskVoList, e -> e.getProcessInstanceId().equals(processInstance.getId()));
+                processInstanceVo.setTaskVoList(CollUtil.isNotEmpty(collect) ? collect : Collections.emptyList());
+            }
+            list.add(processInstanceVo);
+        }
+        if (CollUtil.isNotEmpty(list)) {
+            List<String> processDefinitionIds = StreamUtils.toList(list, ProcessInstanceVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (ProcessInstanceVo processInstanceVo : list) {
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(processInstanceVo.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(processInstanceVo::setWfNodeConfigVo);
+                }
+            }
+        }
+        long count = query.count();
+        TableDataInfo<ProcessInstanceVo> build = TableDataInfo.build();
+        build.setRows(list);
+        build.setTotal(count);
+        return build;
+    }
+
+    /**
+     * 浠诲姟鍌姙(缁欏綋鍓嶄换鍔″姙鐞嗕汉鍙戦�佺珯鍐呬俊锛岄偖浠讹紝鐭俊绛�)
+     *
+     * @param taskUrgingBo 浠诲姟鍌姙
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean taskUrging(TaskUrgingBo taskUrgingBo) {
+        try {
+            ProcessInstance processInstance = QueryUtils.instanceQuery(taskUrgingBo.getProcessInstanceId()).singleResult();
+            if (processInstance == null) {
+                throw new ServiceException("浠诲姟宸茬粨鏉燂紒");
+            }
+            String message = taskUrgingBo.getMessage();
+            if (StringUtils.isBlank(message)) {
+                message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹繕鏈鎵癸紝璇锋偍鍙婃椂澶勭悊銆�";
+            }
+            List<Task> list = QueryUtils.taskQuery(taskUrgingBo.getProcessInstanceId()).list();
+            WorkflowUtils.sendMessage(list, processInstance.getName(), taskUrgingBo.getMessageType(), message, userService);
+        } catch (ServiceException e) {
+            throw new ServiceException(e.getMessage());
+        }
+        return true;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
new file mode 100644
index 0000000..5235d12
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java
@@ -0,0 +1,858 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.dto.RoleDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.OssService;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.ActHiTaskinst;
+import org.dromara.workflow.domain.WfTaskBackNode;
+import org.dromara.workflow.domain.bo.*;
+import org.dromara.workflow.domain.vo.*;
+import org.dromara.workflow.flowable.cmd.*;
+import org.dromara.workflow.flowable.handler.FlowProcessEventHandler;
+import org.dromara.workflow.mapper.ActHiTaskinstMapper;
+import org.dromara.workflow.mapper.ActTaskMapper;
+import org.dromara.workflow.service.IActTaskService;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+import org.dromara.workflow.service.IWfNodeConfigService;
+import org.dromara.workflow.service.IWfTaskBackNodeService;
+import org.dromara.workflow.utils.ModelUtils;
+import org.dromara.workflow.utils.QueryUtils;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.flowable.common.engine.api.FlowableObjectNotFoundException;
+import org.flowable.common.engine.impl.identity.Authentication;
+import org.flowable.engine.*;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
+import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
+import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.identitylink.api.history.HistoricIdentityLink;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+import org.flowable.variable.api.persistence.entity.VariableInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static org.dromara.workflow.common.constant.FlowConstant.*;
+
+/**
+ * 浠诲姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author may
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class ActTaskServiceImpl implements IActTaskService {
+
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
+    @Autowired(required = false)
+    private TaskService taskService;
+    @Autowired(required = false)
+    private HistoryService historyService;
+    @Autowired(required = false)
+    private IdentityService identityService;
+    @Autowired(required = false)
+    private ManagementService managementService;
+    private final ActTaskMapper actTaskMapper;
+    private final IWfTaskBackNodeService wfTaskBackNodeService;
+    private final ActHiTaskinstMapper actHiTaskinstMapper;
+    private final IWfNodeConfigService wfNodeConfigService;
+    private final IWfDefinitionConfigService wfDefinitionConfigService;
+    private final FlowProcessEventHandler flowProcessEventHandler;
+    private final UserService userService;
+    private final OssService ossService;
+
+    /**
+     * 鍚姩浠诲姟
+     *
+     * @param startProcessBo 鍚姩娴佺▼鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
+        Map<String, Object> map = new HashMap<>();
+        if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
+            throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID");
+        }
+        // 鍒ゆ柇褰撳墠涓氬姟鏄惁鍚姩杩囨祦绋�
+        HistoricProcessInstanceQuery query = QueryUtils.hisInstanceQuery();
+        HistoricProcessInstance historicProcessInstance = query.processInstanceBusinessKey(startProcessBo.getBusinessKey()).singleResult();
+        if (ObjectUtil.isNotEmpty(historicProcessInstance)) {
+            BusinessStatusEnum.checkStartStatus(historicProcessInstance.getBusinessStatus());
+        }
+        List<Task> taskResult = QueryUtils.taskQuery().processInstanceBusinessKey(startProcessBo.getBusinessKey()).list();
+        if (CollUtil.isNotEmpty(taskResult)) {
+            if (CollUtil.isNotEmpty(startProcessBo.getVariables())) {
+                taskService.setVariables(taskResult.get(0).getId(), startProcessBo.getVariables());
+            }
+            map.put(PROCESS_INSTANCE_ID, taskResult.get(0).getProcessInstanceId());
+            map.put("taskId", taskResult.get(0).getId());
+            return map;
+        }
+        WfDefinitionConfigVo wfDefinitionConfigVo = wfDefinitionConfigService.getByTableNameLastVersion(startProcessBo.getTableName());
+        if (wfDefinitionConfigVo == null) {
+            throw new ServiceException("璇峰埌娴佺▼瀹氫箟缁戝畾涓氬姟琛ㄥ悕涓庢祦绋婯EY锛�");
+        }
+        // 璁剧疆鍚姩浜�
+        identityService.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
+        Authentication.setAuthenticatedUserId(String.valueOf(LoginHelper.getUserId()));
+        // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級
+        Map<String, Object> variables = startProcessBo.getVariables();
+        // 鍚姩璺宠繃琛ㄨ揪寮�
+        variables.put(FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
+        // 娴佺▼鍙戣捣浜�
+        variables.put(INITIATOR, (String.valueOf(LoginHelper.getUserId())));
+        ProcessInstance pi;
+        try {
+            if (TenantHelper.isEnable()) {
+                pi = runtimeService.startProcessInstanceByKeyAndTenantId(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId());
+            } else {
+                pi = runtimeService.startProcessInstanceByKey(wfDefinitionConfigVo.getProcessKey(), startProcessBo.getBusinessKey(), variables);
+            }
+        } catch (FlowableObjectNotFoundException e) {
+            throw new ServiceException("鎵句笉鍒板綋鍓嶃��" + wfDefinitionConfigVo.getProcessKey() + "銆戞祦绋嬪畾涔夛紒");
+        }
+        // 灏嗘祦绋嬪畾涔夊悕绉� 浣滀负 娴佺▼瀹炰緥鍚嶇О
+        runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
+        // 鐢宠浜烘墽琛屾祦绋�
+        List<Task> taskList = QueryUtils.taskQuery(pi.getId()).list();
+        if (taskList.size() > 1) {
+            throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒");
+        }
+
+        runtimeService.updateBusinessStatus(pi.getProcessInstanceId(), BusinessStatusEnum.DRAFT.getStatus());
+        taskService.setAssignee(taskList.get(0).getId(), LoginHelper.getUserId().toString());
+        taskService.setVariable(taskList.get(0).getId(), PROCESS_INSTANCE_ID, pi.getProcessInstanceId());
+        taskService.setVariable(taskList.get(0).getId(), BUSINESS_KEY, pi.getBusinessKey());
+        map.put("processInstanceId", pi.getProcessInstanceId());
+        map.put("taskId", taskList.get(0).getId());
+        return map;
+    }
+
+    /**
+     * 鍔炵悊浠诲姟
+     *
+     * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean completeTask(CompleteTaskBo completeTaskBo) {
+        try {
+            String userId = String.valueOf(LoginHelper.getUserId());
+            Task task = WorkflowUtils.getTaskByCurrentUser(completeTaskBo.getTaskId());
+            if (task == null) {
+                throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+            }
+            if (task.isSuspended()) {
+                throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+            }
+            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            //鍔炵悊濮旀墭浠诲姟
+            if (ObjectUtil.isNotEmpty(task.getDelegationState()) && FlowConstant.PENDING.equals(task.getDelegationState().name())) {
+                taskService.resolveTask(completeTaskBo.getTaskId());
+                TaskEntity newTask = WorkflowUtils.createNewTask(task);
+                taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isNotBlank(completeTaskBo.getMessage()) ? completeTaskBo.getMessage() : StrUtil.EMPTY);
+                taskService.complete(newTask.getId());
+                return true;
+            }
+            //闄勪欢涓婁紶
+            AttachmentCmd attachmentCmd = new AttachmentCmd(completeTaskBo.getFileId(), task.getId(), task.getProcessInstanceId(), ossService);
+            managementService.executeCommand(attachmentCmd);
+            String businessStatus = WorkflowUtils.getBusinessStatus(processInstance.getBusinessKey());
+            //娴佺▼鎻愪氦鐩戝惉
+            if (BusinessStatusEnum.DRAFT.getStatus().equals(businessStatus) || BusinessStatusEnum.BACK.getStatus().equals(businessStatus) || BusinessStatusEnum.CANCEL.getStatus().equals(businessStatus)) {
+                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(), businessStatus, true);
+            }
+            runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.WAITING.getStatus());
+            //鍔炵悊鐩戝惉
+            flowProcessEventHandler.processTaskHandler(processInstance.getProcessDefinitionKey(), task.getTaskDefinitionKey(),
+                task.getId(), processInstance.getBusinessKey());
+            //鍔炵悊鎰忚
+            taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), TaskStatusEnum.PASS.getStatus(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "鍚屾剰" : completeTaskBo.getMessage());
+            //鍔炵悊浠诲姟
+            taskService.setAssignee(task.getId(), userId);
+            if (CollUtil.isNotEmpty(completeTaskBo.getVariables())) {
+                taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
+            } else {
+                taskService.complete(completeTaskBo.getTaskId());
+            }
+            //璁板綍鎵ц杩囩殑娴佺▼浠诲姟鑺傜偣
+            wfTaskBackNodeService.recordExecuteNode(task);
+            ProcessInstance pi = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            if (pi == null) {
+                UpdateBusinessStatusCmd updateBusinessStatusCmd = new UpdateBusinessStatusCmd(task.getProcessInstanceId(), BusinessStatusEnum.FINISH.getStatus());
+                managementService.executeCommand(updateBusinessStatusCmd);
+                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(), processInstance.getBusinessKey(),
+                    BusinessStatusEnum.FINISH.getStatus(), false);
+            } else {
+                List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+                for (Task t : list) {
+                    if (ModelUtils.isUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey())) {
+                        List<HistoricIdentityLink> links = historyService.getHistoricIdentityLinksForTask(t.getId());
+                        if (CollUtil.isEmpty(links) && StringUtils.isBlank(t.getAssignee())) {
+                            throw new ServiceException("涓嬩竴鑺傜偣銆�" + t.getName() + "銆戞病鏈夊姙鐞嗕汉!");
+                        }
+                    }
+                }
+
+                if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(completeTaskBo.getWfCopyList())) {
+                    TaskEntity newTask = WorkflowUtils.createNewTask(task);
+                    taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), LoginHelper.getLoginUser().getNickname() + "銆愭妱閫併�戠粰" + String.join(",", StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserName)));
+                    taskService.complete(newTask.getId());
+                    List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+                    WorkflowUtils.createCopyTask(taskList, StreamUtils.toList(completeTaskBo.getWfCopyList(), WfCopy::getUserId));
+                }
+                sendMessage(list, processInstance.getName(), completeTaskBo.getMessageType(), null);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 鍙戦�佹秷鎭�
+     *
+     * @param list        浠诲姟
+     * @param name        娴佺▼鍚嶇О
+     * @param messageType 娑堟伅绫诲瀷
+     * @param message     娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭
+     */
+    @Async
+    public void sendMessage(List<Task> list, String name, List<String> messageType, String message) {
+        WorkflowUtils.sendMessage(list, name, messageType, message, userService);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
+        List<String> roleIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
+        String userId = String.valueOf(LoginHelper.getUserId());
+        queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus());
+        queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId());
+        String ids = StreamUtils.join(roleIds, x -> "'" + x + "'");
+        queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN (" + ids + ") ) ))", userId)));
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            queryWrapper.like("t.name_", taskBo.getName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        }
+        Page<TaskVo> page = actTaskMapper.getTaskWaitByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                task.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
+                task.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊緟鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByAllTaskWait(TaskBo taskBo, PageQuery pageQuery) {
+        TaskQuery query = QueryUtils.taskQuery();
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            query.taskNameLike("%" + taskBo.getName() + "%");
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            query.processDefinitionNameLike("%" + taskBo.getProcessDefinitionName() + "%");
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            query.processDefinitionKey(taskBo.getProcessDefinitionKey());
+        }
+        query.orderByTaskCreateTime().desc();
+        List<Task> taskList = query.listPage(pageQuery.getFirstNum(), pageQuery.getPageSize());
+        List<ProcessInstance> processInstanceList = null;
+        if (CollUtil.isNotEmpty(taskList)) {
+            Set<String> processInstanceIds = StreamUtils.toSet(taskList, Task::getProcessInstanceId);
+            processInstanceList = QueryUtils.instanceQuery(processInstanceIds).list();
+        }
+        List<TaskVo> list = new ArrayList<>();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, Task::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (Task task : taskList) {
+                TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
+                if (CollUtil.isNotEmpty(processInstanceList)) {
+                    processInstanceList.stream().filter(e -> e.getId().equals(task.getProcessInstanceId())).findFirst().ifPresent(e -> {
+                        taskVo.setBusinessStatus(e.getBusinessStatus());
+                        taskVo.setBusinessStatusName(BusinessStatusEnum.findByStatus(taskVo.getBusinessStatus()));
+                        taskVo.setProcessDefinitionKey(e.getProcessDefinitionKey());
+                        taskVo.setProcessDefinitionName(e.getProcessDefinitionName());
+                        taskVo.setProcessDefinitionVersion(e.getProcessDefinitionVersion());
+                        taskVo.setBusinessKey(e.getBusinessKey());
+                    });
+                }
+                taskVo.setAssignee(StringUtils.isNotBlank(task.getAssignee()) ? Long.valueOf(task.getAssignee()) : null);
+                taskVo.setParticipantVo(WorkflowUtils.getCurrentTaskParticipant(task.getId(), userService));
+                taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(taskVo::setWfNodeConfigVo);
+                }
+                list.add(taskVo);
+            }
+        }
+        long count = query.count();
+        TableDataInfo<TaskVo> build = TableDataInfo.build();
+        build.setRows(list);
+        build.setTotal(count);
+        return build;
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        String userId = String.valueOf(LoginHelper.getUserId());
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
+        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        queryWrapper.eq("t.assignee_", userId);
+        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByTaskCopy(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        String userId = String.valueOf(LoginHelper.getUserId());
+        if (StringUtils.isNotBlank(taskBo.getName())) {
+            queryWrapper.like("t.name_", taskBo.getName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionName())) {
+            queryWrapper.like("t.processDefinitionName", taskBo.getProcessDefinitionName());
+        }
+        if (StringUtils.isNotBlank(taskBo.getProcessDefinitionKey())) {
+            queryWrapper.eq("t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        }
+        queryWrapper.eq("t.assignee_", userId);
+        Page<TaskVo> page = actTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 鏌ヨ褰撳墠绉熸埛鎵�鏈夊凡鍔炰换鍔�
+     *
+     * @param taskBo 鍙傛暟
+     */
+    @Override
+    public TableDataInfo<TaskVo> getPageByAllTaskFinish(TaskBo taskBo, PageQuery pageQuery) {
+        QueryWrapper<TaskVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getName()), "t.name_", taskBo.getName());
+        queryWrapper.like(StringUtils.isNotBlank(taskBo.getProcessDefinitionName()), "t.processDefinitionName", taskBo.getProcessDefinitionName());
+        queryWrapper.eq(StringUtils.isNotBlank(taskBo.getProcessDefinitionKey()), "t.processDefinitionKey", taskBo.getProcessDefinitionKey());
+        Page<TaskVo> page = actTaskMapper.getTaskFinishByPage(pageQuery.build(), queryWrapper);
+
+        List<TaskVo> taskList = page.getRecords();
+        if (CollUtil.isNotEmpty(taskList)) {
+            List<String> processDefinitionIds = StreamUtils.toList(taskList, TaskVo::getProcessDefinitionId);
+            List<WfNodeConfigVo> wfNodeConfigVoList = wfNodeConfigService.selectByDefIds(processDefinitionIds);
+            for (TaskVo task : taskList) {
+                task.setBusinessStatusName(BusinessStatusEnum.findByStatus(task.getBusinessStatus()));
+                if (CollUtil.isNotEmpty(wfNodeConfigVoList)) {
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && FlowConstant.TRUE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                    wfNodeConfigVoList.stream().filter(e -> e.getDefinitionId().equals(task.getProcessDefinitionId()) && e.getNodeId().equals(task.getTaskDefinitionKey()) && FlowConstant.FALSE.equals(e.getApplyUserTask())).findFirst().ifPresent(task::setWfNodeConfigVo);
+                }
+            }
+        }
+        return TableDataInfo.build(page);
+    }
+
+    /**
+     * 濮旀淳浠诲姟
+     *
+     * @param delegateBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean delegateTask(DelegateBo delegateBo) {
+        Task task = WorkflowUtils.getTaskByCurrentUser(delegateBo.getTaskId());
+
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.PENDING.getStatus(), "銆�" + LoginHelper.getLoginUser().getNickname() + "銆戝娲剧粰銆�" + delegateBo.getNickName() + "銆�");
+            //濮旀墭浠诲姟
+            taskService.delegateTask(delegateBo.getTaskId(), delegateBo.getUserId());
+            //鍔炵悊鐢熸垚鐨勪换鍔¤褰�
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 缁堟浠诲姟
+     *
+     * @param terminationBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean terminationTask(TerminationBo terminationBo) {
+        TaskQuery query = QueryUtils.taskQuery();
+        Task task = query.taskId(terminationBo.getTaskId()).singleResult();
+
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
+        BusinessStatusEnum.checkInvalidStatus(historicProcessInstance.getBusinessStatus());
+        try {
+            if (StringUtils.isBlank(terminationBo.getComment())) {
+                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇�");
+            } else {
+                terminationBo.setComment(LoginHelper.getLoginUser().getNickname() + "缁堟浜嗙敵璇凤細" + terminationBo.getComment());
+            }
+            taskService.addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.TERMINATION.getStatus(), terminationBo.getComment());
+            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+            if (CollUtil.isNotEmpty(list)) {
+                List<Task> subTasks = StreamUtils.filter(list, e -> StringUtils.isNotBlank(e.getParentTaskId()));
+                if (CollUtil.isNotEmpty(subTasks)) {
+                    subTasks.forEach(e -> taskService.deleteTask(e.getId()));
+                }
+                runtimeService.updateBusinessStatus(task.getProcessInstanceId(), BusinessStatusEnum.TERMINATION.getStatus());
+                runtimeService.deleteProcessInstance(task.getProcessInstanceId(), StrUtil.EMPTY);
+            }
+            //娴佺▼缁堟鐩戝惉
+            flowProcessEventHandler.processHandler(historicProcessInstance.getProcessDefinitionKey(),
+                historicProcessInstance.getBusinessKey(), BusinessStatusEnum.TERMINATION.getStatus(), false);
+            return true;
+        } catch (Exception e) {
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 杞姙浠诲姟
+     *
+     * @param transmitBo 鍙傛暟
+     */
+    @Override
+    public boolean transferTask(TransmitBo transmitBo) {
+        Task task = WorkflowUtils.getTaskByCurrentUser(transmitBo.getTaskId());
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), task.getProcessInstanceId(), TaskStatusEnum.TRANSFER.getStatus(), StringUtils.isNotBlank(transmitBo.getComment()) ? transmitBo.getComment() : LoginHelper.getUsername() + "杞姙浜嗕换鍔�");
+            taskService.complete(newTask.getId());
+            taskService.setAssignee(task.getId(), transmitBo.getUserId());
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 浼氱浠诲姟鍔犵
+     *
+     * @param addMultiBo 鍙傛暟
+     */
+    @Override
+    public boolean addMultiInstanceExecution(AddMultiBo addMultiBo) {
+        TaskQuery taskQuery = QueryUtils.taskQuery();
+        taskQuery.taskId(addMultiBo.getTaskId());
+        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
+            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
+        }
+        Task task = taskQuery.singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        String taskDefinitionKey = task.getTaskDefinitionKey();
+        String processInstanceId = task.getProcessInstanceId();
+        String processDefinitionId = task.getProcessDefinitionId();
+
+        try {
+            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
+            if (multiInstanceVo == null) {
+                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
+            }
+            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
+                for (Long assignee : addMultiBo.getAssignees()) {
+                    runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap(multiInstanceVo.getAssignee(), assignee));
+                }
+            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
+                AddSequenceMultiInstanceCmd addSequenceMultiInstanceCmd = new AddSequenceMultiInstanceCmd(task.getExecutionId(), multiInstanceVo.getAssigneeList(), addMultiBo.getAssignees());
+                managementService.executeCommand(addSequenceMultiInstanceCmd);
+            }
+            List<String> assigneeNames = addMultiBo.getAssigneeNames();
+            String username = LoginHelper.getUsername();
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN.getStatus(), username + "鍔犵銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 浼氱浠诲姟鍑忕
+     *
+     * @param deleteMultiBo 鍙傛暟
+     */
+    @Override
+    public boolean deleteMultiInstanceExecution(DeleteMultiBo deleteMultiBo) {
+        TaskQuery taskQuery = QueryUtils.taskQuery();
+        taskQuery.taskId(deleteMultiBo.getTaskId());
+        if (!LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin()) {
+            taskQuery.taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
+        }
+        Task task = taskQuery.singleResult();
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        String taskDefinitionKey = task.getTaskDefinitionKey();
+        String processInstanceId = task.getProcessInstanceId();
+        String processDefinitionId = task.getProcessDefinitionId();
+        try {
+            MultiInstanceVo multiInstanceVo = WorkflowUtils.isMultiInstance(processDefinitionId, taskDefinitionKey);
+            if (multiInstanceVo == null) {
+                throw new ServiceException("褰撳墠鐜妭涓嶆槸浼氱鑺傜偣");
+            }
+            if (multiInstanceVo.getType() instanceof ParallelMultiInstanceBehavior) {
+                for (String executionId : deleteMultiBo.getExecutionIds()) {
+                    runtimeService.deleteMultiInstanceExecution(executionId, false);
+                }
+                for (String taskId : deleteMultiBo.getTaskIds()) {
+                    historyService.deleteHistoricTaskInstance(taskId);
+                }
+            } else if (multiInstanceVo.getType() instanceof SequentialMultiInstanceBehavior) {
+                DeleteSequenceMultiInstanceCmd deleteSequenceMultiInstanceCmd = new DeleteSequenceMultiInstanceCmd(task.getAssignee(), task.getExecutionId(), multiInstanceVo.getAssigneeList(), deleteMultiBo.getAssigneeIds());
+                managementService.executeCommand(deleteSequenceMultiInstanceCmd);
+            }
+            List<String> assigneeNames = deleteMultiBo.getAssigneeNames();
+            String username = LoginHelper.getUsername();
+            TaskEntity newTask = WorkflowUtils.createNewTask(task);
+            taskService.addComment(newTask.getId(), processInstanceId, TaskStatusEnum.SIGN_OFF.getStatus(), username + "鍑忕銆�" + String.join(StringUtils.SEPARATOR, assigneeNames) + "銆�");
+            taskService.complete(newTask.getId());
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    /**
+     * 椹冲洖瀹℃壒
+     *
+     * @param backProcessBo 鍙傛暟
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String backProcess(BackProcessBo backProcessBo) {
+        String userId = String.valueOf(LoginHelper.getUserId());
+        Task task = WorkflowUtils.getTaskByCurrentUser(backProcessBo.getTaskId());
+
+        if (ObjectUtil.isEmpty(task)) {
+            throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
+        }
+        if (task.isSuspended()) {
+            throw new ServiceException(FlowConstant.MESSAGE_SUSPENDED);
+        }
+        try {
+            String processInstanceId = task.getProcessInstanceId();
+            ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+            //鑾峰彇骞惰缃戝叧鎵ц鍚庝繚鐣欑殑鎵ц瀹炰緥鏁版嵁
+            ExecutionChildByExecutionIdCmd childByExecutionIdCmd = new ExecutionChildByExecutionIdCmd(task.getExecutionId());
+            List<ExecutionEntity> executionEntities = managementService.executeCommand(childByExecutionIdCmd);
+            //鏍¢獙鍗曟嵁
+            BusinessStatusEnum.checkBackStatus(processInstance.getBusinessStatus());
+            //鍒ゆ柇鏄惁鏈夊涓换鍔�
+            List<Task> taskList = QueryUtils.taskQuery(processInstanceId).list();
+            String backTaskDefinitionKey = backProcessBo.getTargetActivityId();
+            taskService.addComment(task.getId(), processInstanceId, TaskStatusEnum.BACK.getStatus(), StringUtils.isNotBlank(backProcessBo.getMessage()) ? backProcessBo.getMessage() : "閫�鍥�");
+            if (taskList.size() > 1) {
+                //褰撳墠澶氫釜浠诲姟椹冲洖鍒板崟涓妭鐐�
+                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdsToSingleActivityId(taskList.stream().map(Task::getTaskDefinitionKey).distinct().collect(Collectors.toList()), backTaskDefinitionKey).changeState();
+                ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
+                actHiTaskinst.setAssignee(userId);
+                actHiTaskinst.setId(task.getId());
+                actHiTaskinstMapper.updateById(actHiTaskinst);
+            } else {
+                //褰撳墠鍗曚釜鑺傜偣椹冲洖鍗曚釜鑺傜偣
+                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId).moveActivityIdTo(task.getTaskDefinitionKey(), backTaskDefinitionKey).changeState();
+            }
+            //鍒犻櫎骞惰鐜妭鏈姙鐞嗚褰�
+            MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+            if (multiInstance == null && taskList.size() > 1) {
+                List<Task> tasks = StreamUtils.filter(taskList, e -> !e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
+                if (CollUtil.isNotEmpty(tasks)) {
+                    actHiTaskinstMapper.deleteByIds(StreamUtils.toList(tasks, Task::getId));
+                }
+            }
+
+
+            List<HistoricTaskInstance> instanceList = QueryUtils.hisTaskInstanceQuery(processInstanceId).finished().orderByHistoricTaskInstanceEndTime().desc().list();
+            List<Task> list = QueryUtils.taskQuery(processInstanceId).list();
+            for (Task t : list) {
+                instanceList.stream().filter(e -> e.getTaskDefinitionKey().equals(t.getTaskDefinitionKey())).findFirst().ifPresent(e -> {
+                    taskService.setAssignee(t.getId(), e.getAssignee());
+                });
+            }
+            //鍙戦�佹秷鎭�
+            String message = "鎮ㄧ殑銆�" + processInstance.getName() + "銆戝崟鎹凡缁忚椹冲洖锛岃鎮ㄦ敞鎰忔煡鏀躲��";
+            sendMessage(list, processInstance.getName(), backProcessBo.getMessageType(), message);
+            //鍒犻櫎娴佺▼瀹炰緥鍨冨溇鏁版嵁
+            for (ExecutionEntity executionEntity : executionEntities) {
+                DeleteExecutionCmd deleteExecutionCmd = new DeleteExecutionCmd(executionEntity.getId());
+                managementService.executeCommand(deleteExecutionCmd);
+            }
+
+            WfTaskBackNode wfTaskBackNode = wfTaskBackNodeService.getListByInstanceIdAndNodeId(task.getProcessInstanceId(), backProcessBo.getTargetActivityId());
+            if (ObjectUtil.isNotNull(wfTaskBackNode) && wfTaskBackNode.getOrderNo() == 0) {
+                runtimeService.updateBusinessStatus(processInstanceId, BusinessStatusEnum.BACK.getStatus());
+                flowProcessEventHandler.processHandler(processInstance.getProcessDefinitionKey(),
+                    processInstance.getBusinessKey(), BusinessStatusEnum.BACK.getStatus(), false);
+            }
+            //鍒犻櫎椹冲洖鍚庣殑娴佺▼鑺傜偣
+            wfTaskBackNodeService.deleteBackTaskNode(processInstanceId, backProcessBo.getTargetActivityId());
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException(e.getMessage());
+        }
+        return task.getProcessInstanceId();
+    }
+
+    /**
+     * 淇敼浠诲姟鍔炵悊浜�
+     *
+     * @param taskIds 浠诲姟id
+     * @param userId  鍔炵悊浜篿d
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateAssignee(String[] taskIds, String userId) {
+        try {
+            List<Task> list = QueryUtils.taskQuery().taskIds(Arrays.asList(taskIds)).list();
+            for (Task task : list) {
+                taskService.setAssignee(task.getId(), userId);
+            }
+        } catch (Exception e) {
+            log.error("淇敼澶辫触锛�" + e.getMessage(), e);
+            throw new ServiceException("淇敼澶辫触锛�" + e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * 鏌ヨ娴佺▼鍙橀噺
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public List<VariableVo> getInstanceVariable(String taskId) {
+        List<VariableVo> variableVoList = new ArrayList<>();
+        Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(taskId);
+        if (CollUtil.isNotEmpty(variableInstances)) {
+            for (Map.Entry<String, VariableInstance> entry : variableInstances.entrySet()) {
+                VariableVo variableVo = new VariableVo();
+                variableVo.setKey(entry.getKey());
+                variableVo.setValue(entry.getValue().getValue().toString());
+                variableVoList.add(variableVo);
+            }
+        }
+        return variableVoList;
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴佷换鍔$敤鎴烽�夋嫨鍔犵浜哄憳
+     *
+     * @param taskId 浠诲姟id
+     * @return
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public String getTaskUserIdsByAddMultiInstance(String taskId) {
+        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
+        if (task == null) {
+            throw new ServiceException("浠诲姟涓嶅瓨鍦�");
+        }
+        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+        if (multiInstance == null) {
+            return "";
+        }
+        List<Long> userIds;
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            userIds = (List<Long>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
+        } else {
+            List<Task> list = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+            userIds = StreamUtils.toList(list, e -> Long.valueOf(e.getAssignee()));
+        }
+        return StringUtils.join(userIds, StringUtils.SEPARATOR);
+    }
+
+    /**
+     * 鏌ヨ宸ヤ綔娴侀�夋嫨鍑忕浜哄憳
+     *
+     * @param taskId 浠诲姟id 浠诲姟id
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<TaskVo> getListByDeleteMultiInstance(String taskId) {
+        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
+        List<Task> taskList = QueryUtils.taskQuery(task.getProcessInstanceId()).list();
+        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+        List<TaskVo> taskListVo = new ArrayList<>();
+        if (multiInstance == null) {
+            return List.of();
+        }
+        List<Long> assigneeList = new ArrayList<>();
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            List<Object> variable = (List<Object>) runtimeService.getVariable(task.getExecutionId(), multiInstance.getAssigneeList());
+            for (Object o : variable) {
+                assigneeList.add(Long.valueOf(o.toString()));
+            }
+        }
+
+        if (multiInstance.getType() instanceof SequentialMultiInstanceBehavior) {
+            List<Long> userIds = StreamUtils.filter(assigneeList, e -> !String.valueOf(e).equals(task.getAssignee()));
+            List<UserDTO> userList = userService.selectListByIds(userIds);
+            for (Long userId : userIds) {
+                TaskVo taskVo = new TaskVo();
+                taskVo.setId("涓茶浼氱");
+                taskVo.setExecutionId("涓茶浼氱");
+                taskVo.setProcessInstanceId(task.getProcessInstanceId());
+                taskVo.setName(task.getName());
+                taskVo.setAssignee(userId);
+                if (CollUtil.isNotEmpty(userList)) {
+                    userList.stream().filter(u -> u.getUserId().toString().equals(userId.toString())).findFirst().ifPresent(u -> taskVo.setAssigneeName(u.getNickName()));
+                }
+                taskListVo.add(taskVo);
+            }
+            return taskListVo;
+        } else if (multiInstance.getType() instanceof ParallelMultiInstanceBehavior) {
+            List<Task> tasks = StreamUtils.filter(taskList, e -> StringUtils.isBlank(e.getParentTaskId()) && !e.getExecutionId().equals(task.getExecutionId()) && e.getTaskDefinitionKey().equals(task.getTaskDefinitionKey()));
+            if (CollUtil.isNotEmpty(tasks)) {
+                List<Long> userIds = StreamUtils.toList(tasks, e -> Long.valueOf(e.getAssignee()));
+                List<UserDTO> userList = userService.selectListByIds(userIds);
+                for (Task t : tasks) {
+                    TaskVo taskVo = new TaskVo();
+                    taskVo.setId(t.getId());
+                    taskVo.setExecutionId(t.getExecutionId());
+                    taskVo.setProcessInstanceId(t.getProcessInstanceId());
+                    taskVo.setName(t.getName());
+                    taskVo.setAssignee(Long.valueOf(t.getAssignee()));
+                    if (CollUtil.isNotEmpty(userList)) {
+                        userList.stream().filter(u -> u.getUserId().toString().equals(t.getAssignee())).findFirst().ifPresent(e -> taskVo.setAssigneeName(e.getNickName()));
+                    }
+                    taskListVo.add(taskVo);
+                }
+                return taskListVo;
+            }
+        }
+        return List.of();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
new file mode 100644
index 0000000..a62ce5f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java
@@ -0,0 +1,152 @@
+package org.dromara.workflow.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.event.ProcessEvent;
+import org.dromara.common.core.domain.event.ProcessTaskEvent;
+import org.dromara.common.core.enums.BusinessStatusEnum;
+import org.dromara.common.core.service.WorkflowService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.workflow.domain.TestLeave;
+import org.dromara.workflow.domain.bo.TestLeaveBo;
+import org.dromara.workflow.domain.vo.TestLeaveVo;
+import org.dromara.workflow.mapper.TestLeaveMapper;
+import org.dromara.workflow.service.ITestLeaveService;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 璇峰亣Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2023-07-21
+ */
+@RequiredArgsConstructor
+@Service
+@Slf4j
+public class TestLeaveServiceImpl implements ITestLeaveService {
+
+    private final TestLeaveMapper baseMapper;
+    private final WorkflowService workflowService;
+
+    /**
+     * 鏌ヨ璇峰亣
+     */
+    @Override
+    public TestLeaveVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    @Override
+    public TableDataInfo<TestLeaveVo> queryPageList(TestLeaveBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
+        Page<TestLeaveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ璇峰亣鍒楄〃
+     */
+    @Override
+    public List<TestLeaveVo> queryList(TestLeaveBo bo) {
+        LambdaQueryWrapper<TestLeave> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<TestLeave> buildQueryWrapper(TestLeaveBo bo) {
+        LambdaQueryWrapper<TestLeave> lqw = Wrappers.lambdaQuery();
+        lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType());
+        lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays());
+        lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays());
+        lqw.orderByDesc(BaseEntity::getCreateTime);
+        return lqw;
+    }
+
+    /**
+     * 鏂板璇峰亣
+     */
+    @Override
+    public TestLeaveVo insertByBo(TestLeaveBo bo) {
+        TestLeave add = MapstructUtils.convert(bo, TestLeave.class);
+        if (StringUtils.isBlank(add.getStatus())) {
+            add.setStatus(BusinessStatusEnum.DRAFT.getStatus());
+        }
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return MapstructUtils.convert(add, TestLeaveVo.class);
+    }
+
+    /**
+     * 淇敼璇峰亣
+     */
+    @Override
+    public TestLeaveVo updateByBo(TestLeaveBo bo) {
+        TestLeave update = MapstructUtils.convert(bo, TestLeave.class);
+        baseMapper.updateById(update);
+        return MapstructUtils.convert(update, TestLeaveVo.class);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎璇峰亣
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteWithValidByIds(Collection<Long> ids) {
+        List<String> idList = StreamUtils.toList(ids, String::valueOf);
+        workflowService.deleteRunAndHisInstance(idList);
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    /**
+     * 鎬讳綋娴佺▼鐩戝惉(渚嬪: 鎻愪氦 閫�鍥� 鎾ら攢 缁堟 浣滃簾绛�)
+     * 姝e父浣跨敤鍙渶#processEvent.key=='leave1'
+     * 绀轰緥涓轰簡鏂逛究鍒欎娇鐢╯tartsWith鍖归厤浜嗗叏閮ㄧず渚媖ey
+     *
+     * @param processEvent 鍙傛暟
+     */
+    @EventListener(condition = "#processEvent.key.startsWith('leave')")
+    public void processHandler(ProcessEvent processEvent) {
+        log.info("褰撳墠浠诲姟鎵ц浜唟}", processEvent.toString());
+        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessKey()));
+        testLeave.setStatus(processEvent.getStatus());
+        if (processEvent.isSubmit()) {
+            testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
+        }
+        baseMapper.updateById(testLeave);
+    }
+
+    /**
+     * 鎵ц鍔炵悊浠诲姟鐩戝惉
+     * 绀轰緥锛氫篃鍙�氳繃  @EventListener(condition = "#processTaskEvent.key=='leave1'")杩涜鍒ゆ柇
+     * 鍦ㄦ柟娉曚腑鍒ゆ柇娴佺▼鑺傜偣key
+     * if ("xxx".equals(processTaskEvent.getTaskDefinitionKey())) {
+     * //鎵ц涓氬姟閫昏緫
+     * }
+     *
+     * @param processTaskEvent 鍙傛暟
+     */
+    @EventListener(condition = "#processTaskEvent.key=='leave1' && #processTaskEvent.taskDefinitionKey=='Activity_14633hx'")
+    public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
+        log.info("褰撳墠浠诲姟鎵ц浜唟}", processTaskEvent.toString());
+        TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessKey()));
+        testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus());
+        baseMapper.updateById(testLeave);
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
new file mode 100644
index 0000000..e562823
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java
@@ -0,0 +1,130 @@
+package org.dromara.workflow.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.workflow.domain.WfCategory;
+import org.dromara.workflow.domain.bo.WfCategoryBo;
+import org.dromara.workflow.domain.vo.WfCategoryVo;
+import org.dromara.workflow.mapper.WfCategoryMapper;
+import org.dromara.workflow.service.IWfCategoryService;
+import org.dromara.workflow.utils.QueryUtils;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.repository.Model;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 娴佺▼鍒嗙被Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2023-06-28
+ */
+@RequiredArgsConstructor
+@Service
+public class WfCategoryServiceImpl implements IWfCategoryService {
+
+    private final WfCategoryMapper baseMapper;
+    @Autowired(required = false)
+    private RepositoryService repositoryService;
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被
+     */
+    @Override
+    public WfCategoryVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+
+    /**
+     * 鏌ヨ娴佺▼鍒嗙被鍒楄〃
+     */
+    @Override
+    public List<WfCategoryVo> queryList(WfCategoryBo bo) {
+        LambdaQueryWrapper<WfCategory> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<WfCategory> buildQueryWrapper(WfCategoryBo bo) {
+        LambdaQueryWrapper<WfCategory> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), WfCategory::getCategoryName, bo.getCategoryName());
+        lqw.eq(StringUtils.isNotBlank(bo.getCategoryCode()), WfCategory::getCategoryCode, bo.getCategoryCode());
+        return lqw;
+    }
+
+    /**
+     * 鏂板娴佺▼鍒嗙被
+     */
+    @Override
+    public Boolean insertByBo(WfCategoryBo bo) {
+        WfCategory add = MapstructUtils.convert(bo, WfCategory.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼娴佺▼鍒嗙被
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean updateByBo(WfCategoryBo bo) {
+        WfCategory update = MapstructUtils.convert(bo, WfCategory.class);
+        validEntityBeforeSave(update);
+        WfCategoryVo wfCategoryVo = baseMapper.selectVoById(bo.getId());
+        List<ProcessDefinition> processDefinitionList = QueryUtils.definitionQuery().processDefinitionCategory(wfCategoryVo.getCategoryCode()).list();
+        for (ProcessDefinition processDefinition : processDefinitionList) {
+            repositoryService.setProcessDefinitionCategory(processDefinition.getId(), bo.getCategoryCode());
+        }
+        List<Deployment> deploymentList = QueryUtils.deploymentQuery().deploymentCategory(wfCategoryVo.getCategoryCode()).list();
+        for (Deployment deployment : deploymentList) {
+            repositoryService.setDeploymentCategory(deployment.getId(), bo.getCategoryCode());
+        }
+        List<Model> modelList = QueryUtils.modelQuery().modelCategory(wfCategoryVo.getCategoryCode()).list();
+        for (Model model : modelList) {
+            model.setCategory(bo.getCategoryCode());
+            repositoryService.saveModel(model);
+        }
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(WfCategory entity) {
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼鍒嗙被
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if (isValid) {
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    /**
+     * 鎸夌収绫诲埆缂栫爜鏌ヨ
+     *
+     * @param categoryCode 鍒嗙被姣斿悧
+     */
+    @Override
+    public WfCategory queryByCategoryCode(String categoryCode) {
+        return baseMapper.selectOne(new LambdaQueryWrapper<WfCategory>().eq(WfCategory::getCategoryCode, categoryCode));
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java
new file mode 100644
index 0000000..ab55ff8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfDefinitionConfigServiceImpl.java
@@ -0,0 +1,117 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import org.dromara.common.core.utils.MapstructUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.workflow.domain.WfDefinitionConfig;
+import org.dromara.workflow.domain.bo.WfDefinitionConfigBo;
+import org.dromara.workflow.domain.vo.WfDefinitionConfigVo;
+import org.dromara.workflow.service.IWfDefinitionConfigService;
+import org.springframework.stereotype.Service;
+import org.dromara.workflow.mapper.WfDefinitionConfigMapper;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Collection;
+
+/**
+ * 娴佺▼瀹氫箟閰嶇疆Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2024-03-18
+ */
+@RequiredArgsConstructor
+@Service
+public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService {
+
+    private final WfDefinitionConfigMapper baseMapper;
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     */
+    @Override
+    public WfDefinitionConfigVo getByDefId(String definitionId) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getDefinitionId, definitionId));
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param tableName 琛ㄥ悕
+     * @return 缁撴灉
+     */
+    @Override
+    public WfDefinitionConfigVo getByTableNameLastVersion(String tableName) {
+        List<WfDefinitionConfigVo> wfDefinitionConfigVos = baseMapper.selectVoList(
+            new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, tableName).orderByDesc(WfDefinitionConfig::getVersion));
+        if (CollUtil.isNotEmpty(wfDefinitionConfigVos)) {
+            return wfDefinitionConfigVos.get(0);
+        }
+        return null;
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆
+     *
+     * @param definitionId 娴佺▼瀹氫箟id
+     * @param tableName    琛ㄥ悕
+     * @return 缁撴灉
+     */
+    @Override
+    public WfDefinitionConfigVo getByDefIdAndTableName(String definitionId, String tableName) {
+        return baseMapper.selectVoOne(new LambdaQueryWrapper<WfDefinitionConfig>()
+            .eq(WfDefinitionConfig::getDefinitionId, definitionId)
+            .eq(WfDefinitionConfig::getTableName, tableName));
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鎺掗櫎褰撳墠鏌ヨ鐨勬祦绋嬪畾涔�
+     *
+     * @param tableName    琛ㄥ悕
+     * @param definitionId 娴佺▼瀹氫箟id
+     */
+    @Override
+    public List<WfDefinitionConfigVo> getByTableNameNotDefId(String tableName, String definitionId) {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<WfDefinitionConfig>()
+            .eq(WfDefinitionConfig::getTableName, tableName)
+            .ne(WfDefinitionConfig::getDefinitionId, definitionId));
+    }
+
+    /**
+     * 鏌ヨ娴佺▼瀹氫箟閰嶇疆鍒楄〃
+     */
+    @Override
+    public List<WfDefinitionConfigVo> queryList(List<String> definitionIds) {
+        return baseMapper.selectVoList(new LambdaQueryWrapper<WfDefinitionConfig>().in(WfDefinitionConfig::getDefinitionId, definitionIds));
+    }
+
+    /**
+     * 鏂板娴佺▼瀹氫箟閰嶇疆
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean saveOrUpdate(WfDefinitionConfigBo bo) {
+        WfDefinitionConfig add = MapstructUtils.convert(bo, WfDefinitionConfig.class);
+        baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName()));
+        add.setTableName(add.getTableName().toLowerCase());
+        boolean flag = baseMapper.insertOrUpdate(add);
+        if (baseMapper.insertOrUpdate(add)) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娴佺▼瀹氫箟閰嶇疆
+     */
+    @Override
+    public Boolean deleteByIds(Collection<Long> ids) {
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    @Override
+    public Boolean deleteByDefIds(Collection<String> ids) {
+        return baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().in(WfDefinitionConfig::getDefinitionId, ids)) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java
new file mode 100644
index 0000000..da2e777
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfFormManageServiceImpl.java
@@ -0,0 +1,111 @@
+package org.dromara.workflow.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.workflow.common.enums.FormTypeEnum;
+import org.springframework.stereotype.Service;
+import org.dromara.workflow.domain.bo.WfFormManageBo;
+import org.dromara.workflow.domain.vo.WfFormManageVo;
+import org.dromara.workflow.domain.WfFormManage;
+import org.dromara.workflow.mapper.WfFormManageMapper;
+import org.dromara.workflow.service.IWfFormManageService;
+
+import java.util.List;
+import java.util.Collection;
+
+/**
+ * 琛ㄥ崟绠$悊Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2024-03-29
+ */
+@RequiredArgsConstructor
+@Service
+public class WfFormManageServiceImpl implements IWfFormManageService {
+
+    private final WfFormManageMapper baseMapper;
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊
+     */
+    @Override
+    public WfFormManageVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    @Override
+    public List<WfFormManageVo> queryByIds(List<Long> ids) {
+        return baseMapper.selectVoBatchIds(ids);
+    }
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     */
+    @Override
+    public TableDataInfo<WfFormManageVo> queryPageList(WfFormManageBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<WfFormManage> lqw = buildQueryWrapper(bo);
+        Page<WfFormManageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public List<WfFormManageVo> selectList() {
+        List<WfFormManageVo> wfFormManageVos = baseMapper.selectVoList(new LambdaQueryWrapper<WfFormManage>().orderByDesc(WfFormManage::getUpdateTime));
+        for (WfFormManageVo wfFormManageVo : wfFormManageVos) {
+            wfFormManageVo.setFormTypeName(FormTypeEnum.findByType(wfFormManageVo.getFormType()));
+        }
+        return wfFormManageVos;
+    }
+
+    /**
+     * 鏌ヨ琛ㄥ崟绠$悊鍒楄〃
+     */
+    @Override
+    public List<WfFormManageVo> queryList(WfFormManageBo bo) {
+        LambdaQueryWrapper<WfFormManage> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<WfFormManage> buildQueryWrapper(WfFormManageBo bo) {
+        LambdaQueryWrapper<WfFormManage> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getFormName()), WfFormManage::getFormName, bo.getFormName());
+        lqw.eq(StringUtils.isNotBlank(bo.getFormType()), WfFormManage::getFormType, bo.getFormType());
+        return lqw;
+    }
+
+    /**
+     * 鏂板琛ㄥ崟绠$悊
+     */
+    @Override
+    public Boolean insertByBo(WfFormManageBo bo) {
+        WfFormManage add = MapstructUtils.convert(bo, WfFormManage.class);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼琛ㄥ崟绠$悊
+     */
+    @Override
+    public Boolean updateByBo(WfFormManageBo bo) {
+        WfFormManage update = MapstructUtils.convert(bo, WfFormManage.class);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎琛ㄥ崟绠$悊
+     */
+    @Override
+    public Boolean deleteByIds(Collection<Long> ids) {
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java
new file mode 100644
index 0000000..2f71482
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfNodeConfigServiceImpl.java
@@ -0,0 +1,75 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.workflow.domain.vo.WfFormManageVo;
+import org.dromara.workflow.service.IWfFormManageService;
+import org.springframework.stereotype.Service;
+import org.dromara.workflow.domain.vo.WfNodeConfigVo;
+import org.dromara.workflow.domain.WfNodeConfig;
+import org.dromara.workflow.mapper.WfNodeConfigMapper;
+import org.dromara.workflow.service.IWfNodeConfigService;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鑺傜偣閰嶇疆Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2024-03-30
+ */
+@RequiredArgsConstructor
+@Service
+public class WfNodeConfigServiceImpl implements IWfNodeConfigService {
+
+    private final WfNodeConfigMapper baseMapper;
+    private final IWfFormManageService wfFormManageService;
+
+    /**
+     * 鏌ヨ鑺傜偣閰嶇疆
+     */
+    @Override
+    public WfNodeConfigVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 淇濆瓨鑺傜偣閰嶇疆
+     */
+    @Override
+    public Boolean saveOrUpdate(List<WfNodeConfig> list) {
+        return baseMapper.insertOrUpdateBatch(list);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鑺傜偣閰嶇疆
+     */
+    @Override
+    public Boolean deleteByIds(Collection<Long> ids) {
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+
+
+    @Override
+    public Boolean deleteByDefIds(Collection<String> ids) {
+        return baseMapper.delete(new LambdaQueryWrapper<WfNodeConfig>().in(WfNodeConfig::getDefinitionId, ids)) > 0;
+    }
+
+    @Override
+    public List<WfNodeConfigVo> selectByDefIds(Collection<String> ids) {
+        List<WfNodeConfigVo> wfNodeConfigVos = baseMapper.selectVoList(new LambdaQueryWrapper<WfNodeConfig>().in(WfNodeConfig::getDefinitionId, ids));
+        if (CollUtil.isNotEmpty(wfNodeConfigVos)) {
+            List<Long> formIds = StreamUtils.toList(wfNodeConfigVos, WfNodeConfigVo::getFormId);
+            List<WfFormManageVo> wfFormManageVos = wfFormManageService.queryByIds(formIds);
+            for (WfNodeConfigVo wfNodeConfigVo : wfNodeConfigVos) {
+                wfFormManageVos.stream().filter(e -> ObjectUtil.equals(e.getId(), wfNodeConfigVo.getFormId())).findFirst().ifPresent(wfNodeConfigVo::setWfFormManageVo);
+            }
+        }
+        return wfNodeConfigVos;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java
new file mode 100644
index 0000000..6c255d3
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfTaskBackNodeServiceImpl.java
@@ -0,0 +1,144 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.workflow.domain.WfTaskBackNode;
+import org.dromara.workflow.domain.vo.MultiInstanceVo;
+import org.dromara.workflow.mapper.WfTaskBackNodeMapper;
+import org.dromara.workflow.service.IWfTaskBackNodeService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.flowable.task.api.Task;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.dromara.workflow.common.constant.FlowConstant.MULTI_INSTANCE;
+import static org.dromara.workflow.common.constant.FlowConstant.USER_TASK;
+
+
+/**
+ * 鑺傜偣椹冲洖璁板綍Service涓氬姟灞傚鐞�
+ *
+ * @author may
+ * @date 2024-03-13
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class WfTaskBackNodeServiceImpl implements IWfTaskBackNodeService {
+
+    private final WfTaskBackNodeMapper wfTaskBackNodeMapper;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void recordExecuteNode(Task task) {
+        List<WfTaskBackNode> list = getListByInstanceId(task.getProcessInstanceId());
+        WfTaskBackNode wfTaskBackNode = new WfTaskBackNode();
+        wfTaskBackNode.setNodeId(task.getTaskDefinitionKey());
+        wfTaskBackNode.setNodeName(task.getName());
+        wfTaskBackNode.setInstanceId(task.getProcessInstanceId());
+        wfTaskBackNode.setAssignee(String.valueOf(LoginHelper.getUserId()));
+        MultiInstanceVo multiInstance = WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
+        if (ObjectUtil.isNotEmpty(multiInstance)) {
+            wfTaskBackNode.setTaskType(MULTI_INSTANCE);
+        } else {
+            wfTaskBackNode.setTaskType(USER_TASK);
+        }
+        if (CollUtil.isEmpty(list)) {
+            wfTaskBackNode.setOrderNo(0);
+            wfTaskBackNodeMapper.insert(wfTaskBackNode);
+        } else {
+            WfTaskBackNode taskNode = StreamUtils.findFirst(list, e -> e.getNodeId().equals(wfTaskBackNode.getNodeId()) && e.getOrderNo() == 0);
+            if (ObjectUtil.isEmpty(taskNode)) {
+                wfTaskBackNode.setOrderNo(list.get(0).getOrderNo() + 1);
+                WfTaskBackNode node = getListByInstanceIdAndNodeId(wfTaskBackNode.getInstanceId(), wfTaskBackNode.getNodeId());
+                if (ObjectUtil.isNotEmpty(node)) {
+                    node.setAssignee(node.getAssignee() + StringUtils.SEPARATOR + LoginHelper.getUserId());
+                    wfTaskBackNodeMapper.updateById(node);
+                } else {
+                    wfTaskBackNodeMapper.insert(wfTaskBackNode);
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<WfTaskBackNode> getListByInstanceId(String processInstanceId) {
+        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
+        wrapper.orderByDesc(WfTaskBackNode::getOrderNo);
+        return wfTaskBackNodeMapper.selectList(wrapper);
+    }
+
+    @Override
+    public WfTaskBackNode getListByInstanceIdAndNodeId(String processInstanceId, String nodeId) {
+        LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
+        queryWrapper.eq(WfTaskBackNode::getNodeId, nodeId);
+        return wfTaskBackNodeMapper.selectOne(queryWrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteBackTaskNode(String processInstanceId, String targetActivityId) {
+        try {
+            LambdaQueryWrapper<WfTaskBackNode> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
+            queryWrapper.eq(WfTaskBackNode::getNodeId, targetActivityId);
+            WfTaskBackNode actTaskNode = wfTaskBackNodeMapper.selectOne(queryWrapper);
+            if (ObjectUtil.isNotNull(actTaskNode)) {
+                Integer orderNo = actTaskNode.getOrderNo();
+                List<WfTaskBackNode> taskNodeList = getListByInstanceId(processInstanceId);
+                List<Long> ids = new ArrayList<>();
+                if (CollUtil.isNotEmpty(taskNodeList)) {
+                    for (WfTaskBackNode taskNode : taskNodeList) {
+                        if (taskNode.getOrderNo() >= orderNo) {
+                            ids.add(taskNode.getId());
+                        }
+                    }
+                }
+                if (CollUtil.isNotEmpty(ids)) {
+                    wfTaskBackNodeMapper.deleteByIds(ids);
+                }
+            }
+            return true;
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            throw new ServiceException("鍒犻櫎澶辫触");
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteByInstanceId(String processInstanceId) {
+        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(WfTaskBackNode::getInstanceId, processInstanceId);
+        List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper);
+        int delete = wfTaskBackNodeMapper.delete(wrapper);
+        if (list.size() != delete) {
+            throw new ServiceException("鍒犻櫎澶辫触");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean deleteByInstanceIds(List<String> processInstanceIds) {
+        LambdaQueryWrapper<WfTaskBackNode> wrapper = new LambdaQueryWrapper<>();
+        wrapper.in(WfTaskBackNode::getInstanceId, processInstanceIds);
+        List<WfTaskBackNode> list = wfTaskBackNodeMapper.selectList(wrapper);
+        int delete = wfTaskBackNodeMapper.delete(wrapper);
+        if (list.size() != delete) {
+            throw new ServiceException("鍒犻櫎澶辫触");
+        }
+        return true;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
new file mode 100644
index 0000000..f75a188
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
@@ -0,0 +1,121 @@
+package org.dromara.workflow.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.service.WorkflowService;
+import org.dromara.workflow.domain.ActHiProcinst;
+import org.dromara.workflow.service.IActHiProcinstService;
+import org.dromara.workflow.service.IActProcessInstanceService;
+import org.dromara.workflow.utils.WorkflowUtils;
+import org.flowable.engine.RuntimeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 閫氱敤 宸ヤ綔娴佹湇鍔″疄鐜�
+ *
+ * @author may
+ */
+@RequiredArgsConstructor
+@Service
+public class WorkflowServiceImpl implements WorkflowService {
+
+    @Autowired(required = false)
+    private RuntimeService runtimeService;
+    private final IActProcessInstanceService iActProcessInstanceService;
+    private final IActHiProcinstService iActHiProcinstService;
+    /**
+     * 杩愯涓殑瀹炰緥 鍒犻櫎绋嬪疄渚嬶紝鍒犻櫎鍘嗗彶璁板綍锛屽垹闄や笟鍔′笌娴佺▼鍏宠仈淇℃伅
+     *
+     * @param businessKeys 涓氬姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean deleteRunAndHisInstance(List<String> businessKeys) {
+        return iActProcessInstanceService.deleteRunAndHisInstance(businessKeys);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param taskId 浠诲姟id
+     */
+    @Override
+    public String getBusinessStatusByTaskId(String taskId) {
+        return WorkflowUtils.getBusinessStatusByTaskId(taskId);
+    }
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param businessKey 涓氬姟id
+     */
+    @Override
+    public String getBusinessStatus(String businessKey) {
+        return WorkflowUtils.getBusinessStatus(businessKey);
+    }
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     *
+     * @param taskId       浠诲姟id
+     * @param variableName 鍙橀噺鍚嶇О
+     * @param value        鍙橀噺鍊�
+     */
+    @Override
+    public void setVariable(String taskId, String variableName, Object value) {
+        runtimeService.setVariable(taskId, variableName, value);
+    }
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鍏ㄥ眬鍙橀噺)
+     *
+     * @param taskId    浠诲姟id
+     * @param variables 娴佺▼鍙橀噺
+     */
+    @Override
+    public void setVariables(String taskId, Map<String, Object> variables) {
+        runtimeService.setVariables(taskId, variables);
+    }
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
+     *
+     * @param taskId       浠诲姟id
+     * @param variableName 鍙橀噺鍚嶇О
+     * @param value        鍙橀噺鍊�
+     */
+    @Override
+    public void setVariableLocal(String taskId, String variableName, Object value) {
+        runtimeService.setVariableLocal(taskId, variableName, value);
+    }
+
+    /**
+     * 璁剧疆娴佺▼鍙橀噺(鏈湴鍙橀噺,闈炲叏灞�鍙橀噺)
+     *
+     * @param taskId    浠诲姟id
+     * @param variables 娴佺▼鍙橀噺
+     */
+    @Override
+    public void setVariablesLocal(String taskId, Map<String, Object> variables) {
+        runtimeService.setVariablesLocal(taskId, variables);
+    }
+
+    /**
+     * 鎸夌収涓氬姟id鏌ヨ娴佺▼瀹炰緥id
+     *
+     * @param businessKey 涓氬姟id
+     * @return 缁撴灉
+     */
+    @Override
+    public String getInstanceIdByBusinessKey(String businessKey) {
+        ActHiProcinst actHiProcinst = iActHiProcinstService.selectByBusinessKey(businessKey);
+        if (actHiProcinst == null) {
+            return StrUtil.EMPTY;
+        }
+        return actHiProcinst.getId();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java
new file mode 100644
index 0000000..7c5377e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/ModelUtils.java
@@ -0,0 +1,289 @@
+package org.dromara.workflow.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.workflow.domain.vo.MultiInstanceVo;
+import org.flowable.bpmn.converter.BpmnXMLConverter;
+import org.flowable.bpmn.model.*;
+import org.flowable.bpmn.model.Process;
+import org.flowable.editor.language.json.converter.BpmnJsonConverter;
+import org.flowable.engine.ProcessEngine;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.rmi.ServerException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 妯″瀷宸ュ叿
+ *
+ * @author may
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ModelUtils {
+
+    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
+
+    public static BpmnModel xmlToBpmnModel(String xml) throws IOException {
+        if (xml == null) {
+            throw new ServerException("xml涓嶈兘涓虹┖");
+        }
+        try {
+            InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml));
+            XMLInputFactory factory = XMLInputFactory.newInstance();
+            XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
+            return new BpmnXMLConverter().convertToBpmnModel(reader);
+        } catch (XMLStreamException e) {
+            throw new ServerException(e.getMessage());
+        }
+    }
+
+    /**
+     * bpmnModel杞负xml
+     *
+     * @param jsonBytes json
+     */
+    public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException {
+        if (jsonBytes == null) {
+            return new byte[0];
+        }
+        // 1. json瀛楄妭鐮佽浆鎴� BpmnModel 瀵硅薄
+        ObjectMapper objectMapper = JsonUtils.getObjectMapper();
+        JsonNode jsonNode = objectMapper.readTree(jsonBytes);
+        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
+
+        if (bpmnModel.getProcesses().isEmpty()) {
+            return new byte[0];
+        }
+        // 2.灏哹pmnModel杞负xml
+        return new BpmnXMLConverter().convertToXML(bpmnModel);
+    }
+
+    /**
+     * xml杞负bpmnModel
+     *
+     * @param xmlBytes xml
+     */
+    public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException {
+        ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes);
+        XMLInputFactory xif = XMLInputFactory.newInstance();
+        XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream);
+        return new BpmnXMLConverter().convertToBpmnModel(xtr);
+    }
+
+    /**
+     * 鏍¢獙妯″瀷
+     *
+     * @param bpmnModel bpmn妯″瀷
+     */
+    public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException {
+        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
+
+        checkBpmnNode(flowElements, false);
+
+        List<SubProcess> subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList());
+        if (!CollUtil.isEmpty(subProcessList)) {
+            for (SubProcess subProcess : subProcessList) {
+                Collection<FlowElement> subProcessFlowElements = subProcess.getFlowElements();
+                checkBpmnNode(subProcessFlowElements, true);
+            }
+        }
+        List<MultiInstanceVo> multiInstanceVoList = new ArrayList<>();
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) {
+                MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
+                multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem());
+                multiInstanceVoList.add(multiInstanceVo);
+            }
+        }
+
+        if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) {
+            Map<String, List<MultiInstanceVo>> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList);
+            for (Map.Entry<String, List<MultiInstanceVo>> entry : assigneeListGroup.entrySet()) {
+                List<MultiInstanceVo> value = entry.getValue();
+                if (CollectionUtil.isNotEmpty(value) && value.size() > 1) {
+                    String key = entry.getKey();
+                    throw new ServerException("浼氱浜哄憳闆嗗悎銆�" + key + "銆戦噸澶�,璇烽噸鏂拌缃泦鍚圞EY");
+                }
+            }
+        }
+    }
+
+    /**
+     * 鏍¢獙bpmn鑺傜偣鏄惁鍚堟硶
+     *
+     * @param flowElements 鑺傜偣闆嗗悎
+     * @param subtask      鏄惁瀛愭祦绋�
+     */
+    private static void checkBpmnNode(Collection<FlowElement> flowElements, boolean subtask) throws ServerException {
+
+        if (CollUtil.isEmpty(flowElements)) {
+            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄨ妭鐐�" : "蹇呴』瀛樺湪鑺傜偣锛�");
+        }
+
+        List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
+        if (CollUtil.isEmpty(startEventList)) {
+            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄥ紑濮嬭妭鐐�" : "蹇呴』瀛樺湪寮�濮嬭妭鐐癸紒");
+        }
+
+        if (startEventList.size() > 1) {
+            throw new ServerException(subtask ? "瀛愭祦绋嬪彧鑳藉瓨鍦ㄤ竴涓紑濮嬭妭鐐�" : "鍙兘瀛樺湪涓�涓紑濮嬭妭鐐癸紒");
+        }
+
+        StartEvent startEvent = startEventList.get(0);
+        List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
+        if (CollUtil.isEmpty(outgoingFlows)) {
+            throw new ServerException(subtask ? "瀛愭祦绋嬫祦绋嬭妭鐐逛负绌猴紝璇疯嚦灏戣璁′竴鏉′富绾挎祦绋嬶紒" : "娴佺▼鑺傜偣涓虹┖锛岃鑷冲皯璁捐涓�鏉′富绾挎祦绋嬶紒");
+        }
+
+        FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
+        if (!(targetFlowElement instanceof UserTask) && !subtask) {
+            throw new ServerException("寮�濮嬭妭鐐瑰悗绗竴涓妭鐐瑰繀椤绘槸鐢ㄦ埛浠诲姟锛�");
+        }
+        //寮�濮嬭妭鐐瑰悗绗竴涓妭鐐圭敵璇蜂汉鑺傜偣
+        if ((targetFlowElement instanceof UserTask) && !subtask) {
+            UserTask userTask = (UserTask) targetFlowElement;
+            if (StringUtils.isBlank(userTask.getFormKey())) {
+                throw new ServerException("鐢宠浜鸿妭鐐瑰繀椤婚�夋嫨琛ㄥ崟锛�");
+            }
+        }
+        List<EndEvent> endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList());
+        if (CollUtil.isEmpty(endEventList)) {
+            throw new ServerException(subtask ? "瀛愭祦绋嬪繀椤诲瓨鍦ㄧ粨鏉熻妭鐐癸紒" : "蹇呴』瀛樺湪缁撴潫鑺傜偣锛�");
+        }
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍏ㄩ儴鐢ㄦ埛鑺傜偣
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    public static List<UserTask> getUserTaskFlowElements(String processDefinitionId) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        List<UserTask> list = new ArrayList<>();
+        List<Process> processes = bpmnModel.getProcesses();
+        Collection<FlowElement> flowElements = processes.get(0).getFlowElements();
+        buildUserTaskFlowElements(flowElements, list);
+        return list;
+    }
+
+    /**
+     * 閫掑綊鑾峰彇鎵�鏈夎妭鐐�
+     *
+     * @param flowElements 鑺傜偣淇℃伅
+     * @param list         闆嗗悎
+     */
+    private static void buildUserTaskFlowElements(Collection<FlowElement> flowElements, List<UserTask> list) {
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof SubProcess) {
+                Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
+                buildUserTaskFlowElements(subFlowElements, list);
+            } else if (flowElement instanceof UserTask) {
+                list.add((UserTask) flowElement);
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇娴佺▼鍏ㄩ儴鑺傜偣
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    public static List<FlowElement> getFlowElements(String processDefinitionId) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        List<FlowElement> list = new ArrayList<>();
+        List<Process> processes = bpmnModel.getProcesses();
+        Collection<FlowElement> flowElements = processes.get(0).getFlowElements();
+        buildFlowElements(flowElements, list);
+        return list;
+    }
+
+    /**
+     * 閫掑綊鑾峰彇鎵�鏈夎妭鐐�
+     *
+     * @param flowElements 鑺傜偣淇℃伅
+     * @param list         闆嗗悎
+     */
+    private static void buildFlowElements(Collection<FlowElement> flowElements, List<FlowElement> list) {
+        for (FlowElement flowElement : flowElements) {
+            list.add(flowElement);
+            if (flowElement instanceof SubProcess) {
+                Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
+                buildFlowElements(subFlowElements, list);
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇鍏ㄩ儴鎵╁睍淇℃伅
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     */
+    public static Map<String, List<ExtensionElement>> getExtensionElements(String processDefinitionId) {
+        Map<String, List<ExtensionElement>> map = new HashMap<>();
+        List<FlowElement> flowElements = getFlowElements(processDefinitionId);
+        for (FlowElement flowElement : flowElements) {
+            if (flowElement instanceof UserTask && CollUtil.isNotEmpty(flowElement.getExtensionElements())) {
+                map.putAll(flowElement.getExtensionElements());
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 鑾峰彇鏌愪釜鑺傜偣鐨勬墿灞曚俊鎭�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @param flowElementId       鑺傜偣id
+     */
+    public static Map<String, List<ExtensionElement>> getExtensionElement(String processDefinitionId, String flowElementId) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        Process process = bpmnModel.getMainProcess();
+        FlowElement flowElement = process.getFlowElement(flowElementId);
+        return flowElement.getExtensionElements();
+    }
+
+    /**
+     * 鍒ゆ柇褰撳墠鑺傜偣鏄惁涓虹敤鎴蜂换鍔�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @param taskDefinitionKey   娴佺▼瀹氫箟id
+     */
+    public static boolean isUserTask(String processDefinitionId, String taskDefinitionKey) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
+        return flowNode instanceof UserTask;
+    }
+
+    /**
+     * 鑾峰彇鐢宠浜鸿妭鐐�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @return 缁撴灉
+     */
+    public static UserTask getApplyUserTask(String processDefinitionId) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
+        List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
+        StartEvent startEvent = startEventList.get(0);
+        List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
+        FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
+        return (UserTask) targetFlowElement;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java
new file mode 100644
index 0000000..df928dc
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/QueryUtils.java
@@ -0,0 +1,169 @@
+package org.dromara.workflow.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.workflow.domain.vo.TaskVo;
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.history.HistoricActivityInstanceQuery;
+import org.flowable.engine.history.HistoricProcessInstanceQuery;
+import org.flowable.engine.repository.DeploymentQuery;
+import org.flowable.engine.repository.ModelQuery;
+import org.flowable.engine.repository.ProcessDefinitionQuery;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.runtime.ProcessInstanceQuery;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 鏌ヨ宸ュ叿
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class QueryUtils {
+
+    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
+
+    public static ModelQuery modelQuery() {
+        ModelQuery query = PROCESS_ENGINE.getRepositoryService().createModelQuery();
+        if (TenantHelper.isEnable()) {
+            query.modelTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static ProcessDefinitionQuery definitionQuery() {
+        ProcessDefinitionQuery query = PROCESS_ENGINE.getRepositoryService().createProcessDefinitionQuery();
+        if (TenantHelper.isEnable()) {
+            query.processDefinitionTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static DeploymentQuery deploymentQuery() {
+        DeploymentQuery query = PROCESS_ENGINE.getRepositoryService().createDeploymentQuery();
+        if (TenantHelper.isEnable()) {
+            query.deploymentTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static DeploymentQuery deploymentQuery(String deploymentId) {
+        return deploymentQuery().deploymentId(deploymentId);
+    }
+
+    public static DeploymentQuery deploymentQuery(List<String> deploymentIds) {
+        return deploymentQuery().deploymentIds(deploymentIds);
+    }
+
+    public static HistoricTaskInstanceQuery hisTaskInstanceQuery() {
+        HistoricTaskInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricTaskInstanceQuery();
+        if (TenantHelper.isEnable()) {
+            query.taskTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static HistoricTaskInstanceQuery hisTaskInstanceQuery(String processInstanceId) {
+        return hisTaskInstanceQuery().processInstanceId(processInstanceId);
+    }
+
+    public static HistoricTaskInstanceQuery hisTaskBusinessKeyQuery(String businessKey) {
+        return hisTaskInstanceQuery().processInstanceBusinessKey(businessKey);
+    }
+
+    public static ProcessInstanceQuery instanceQuery() {
+        ProcessInstanceQuery query = PROCESS_ENGINE.getRuntimeService().createProcessInstanceQuery();
+        if (TenantHelper.isEnable()) {
+            query.processInstanceTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static ProcessInstanceQuery instanceQuery(String processInstanceId) {
+        return instanceQuery().processInstanceId(processInstanceId);
+    }
+
+    public static ProcessInstanceQuery businessKeyQuery(String businessKey) {
+        return instanceQuery().processInstanceBusinessKey(businessKey);
+    }
+
+    public static ProcessInstanceQuery instanceQuery(Set<String> processInstanceIds) {
+        return instanceQuery().processInstanceIds(processInstanceIds);
+    }
+
+    public static HistoricProcessInstanceQuery hisInstanceQuery() {
+        HistoricProcessInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricProcessInstanceQuery();
+        if (TenantHelper.isEnable()) {
+            query.processInstanceTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static HistoricProcessInstanceQuery hisInstanceQuery(String processInstanceId) {
+        return hisInstanceQuery().processInstanceId(processInstanceId);
+    }
+
+    public static HistoricProcessInstanceQuery hisBusinessKeyQuery(String businessKey) {
+        return hisInstanceQuery().processInstanceBusinessKey(businessKey);
+    }
+
+    public static HistoricProcessInstanceQuery hisInstanceQuery(Set<String> processInstanceIds) {
+        return hisInstanceQuery().processInstanceIds(processInstanceIds);
+    }
+
+    public static HistoricActivityInstanceQuery hisActivityInstanceQuery() {
+        HistoricActivityInstanceQuery query = PROCESS_ENGINE.getHistoryService().createHistoricActivityInstanceQuery();
+        if (TenantHelper.isEnable()) {
+            query.activityTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static HistoricActivityInstanceQuery hisActivityInstanceQuery(String processInstanceId) {
+        return hisActivityInstanceQuery().processInstanceId(processInstanceId);
+    }
+
+    public static TaskQuery taskQuery() {
+        TaskQuery query = PROCESS_ENGINE.getTaskService().createTaskQuery();
+        if (TenantHelper.isEnable()) {
+            query.taskTenantId(TenantHelper.getTenantId());
+        }
+        return query;
+    }
+
+    public static TaskQuery taskQuery(String processInstanceId) {
+        return taskQuery().processInstanceId(processInstanceId);
+    }
+
+    public static TaskQuery taskQuery(Collection<String> processInstanceIds) {
+        return taskQuery().processInstanceIdIn(processInstanceIds);
+    }
+
+    /**
+     * 鎸夌収浠诲姟id鏌ヨ褰撳墠浠诲姟
+     *
+     * @param taskId 浠诲姟id
+     */
+    public static TaskVo getTask(String taskId) {
+        Task task = PROCESS_ENGINE.getTaskService().createTaskQuery().taskId(taskId).singleResult();
+        if (task == null) {
+            return null;
+        }
+        ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
+        TaskVo taskVo = BeanUtil.toBean(task, TaskVo.class);
+        taskVo.setBusinessKey(processInstance.getBusinessKey());
+        taskVo.setMultiInstance(WorkflowUtils.isMultiInstance(task.getProcessDefinitionId(), task.getTaskDefinitionKey()) != null);
+        String businessStatus = WorkflowUtils.getBusinessStatus(taskVo.getBusinessKey());
+        taskVo.setBusinessStatus(businessStatus);
+        return taskVo;
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
new file mode 100644
index 0000000..d7c4472
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java
@@ -0,0 +1,295 @@
+package org.dromara.workflow.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.domain.dto.RoleDTO;
+import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.service.UserService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mail.utils.MailUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.websocket.dto.WebSocketMessageDto;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import org.dromara.workflow.common.constant.FlowConstant;
+import org.dromara.workflow.common.enums.MessageTypeEnum;
+import org.dromara.workflow.common.enums.TaskStatusEnum;
+import org.dromara.workflow.domain.ActHiTaskinst;
+import org.dromara.workflow.domain.vo.MultiInstanceVo;
+import org.dromara.workflow.domain.vo.ParticipantVo;
+import org.dromara.workflow.flowable.cmd.UpdateHiTaskInstCmd;
+import org.dromara.workflow.mapper.ActHiTaskinstMapper;
+import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.FlowNode;
+import org.flowable.common.engine.api.delegate.Expression;
+import org.flowable.engine.ProcessEngine;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
+import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior;
+import org.flowable.identitylink.api.history.HistoricIdentityLink;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+
+import java.util.*;
+
+/**
+ * 宸ヤ綔娴佸伐鍏�
+ *
+ * @author may
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class WorkflowUtils {
+
+    private static final ProcessEngine PROCESS_ENGINE = SpringUtils.getBean(ProcessEngine.class);
+    private static final ActHiTaskinstMapper ACT_HI_TASKINST_MAPPER = SpringUtils.getBean(ActHiTaskinstMapper.class);
+
+    /**
+     * 鍒涘缓涓�涓柊浠诲姟
+     *
+     * @param currentTask 鍙傛暟
+     */
+    public static TaskEntity createNewTask(Task currentTask) {
+        TaskEntity task = null;
+        if (ObjectUtil.isNotEmpty(currentTask)) {
+            task = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask();
+            task.setCategory(currentTask.getCategory());
+            task.setDescription(currentTask.getDescription());
+            task.setAssignee(currentTask.getAssignee());
+            task.setName(currentTask.getName());
+            task.setProcessDefinitionId(currentTask.getProcessDefinitionId());
+            task.setProcessInstanceId(currentTask.getProcessInstanceId());
+            task.setTaskDefinitionKey(currentTask.getTaskDefinitionKey());
+            task.setPriority(currentTask.getPriority());
+            task.setCreateTime(new Date());
+            task.setTenantId(TenantHelper.getTenantId());
+            PROCESS_ENGINE.getTaskService().saveTask(task);
+        }
+        if (ObjectUtil.isNotNull(task)) {
+            UpdateHiTaskInstCmd updateHiTaskInstCmd = new UpdateHiTaskInstCmd(Collections.singletonList(task.getId()), task.getProcessDefinitionId(), task.getProcessInstanceId());
+            PROCESS_ENGINE.getManagementService().executeCommand(updateHiTaskInstCmd);
+        }
+        return task;
+    }
+
+    /**
+     * 鎶勯�佷换鍔�
+     *
+     * @param parentTaskList 鐖剁骇浠诲姟
+     * @param userIds        浜哄憳id
+     */
+    public static void createCopyTask(List<Task> parentTaskList, List<Long> userIds) {
+        List<Task> list = new ArrayList<>();
+        String tenantId = TenantHelper.getTenantId();
+        for (Task parentTask : parentTaskList) {
+            for (Long userId : userIds) {
+                TaskEntity newTask = (TaskEntity) PROCESS_ENGINE.getTaskService().newTask();
+                newTask.setParentTaskId(parentTask.getId());
+                newTask.setAssignee(userId.toString());
+                newTask.setName("銆愭妱閫併��-" + parentTask.getName());
+                newTask.setProcessDefinitionId(parentTask.getProcessDefinitionId());
+                newTask.setProcessInstanceId(parentTask.getProcessInstanceId());
+                newTask.setTaskDefinitionKey(parentTask.getTaskDefinitionKey());
+                newTask.setTenantId(tenantId);
+                list.add(newTask);
+            }
+        }
+        PROCESS_ENGINE.getTaskService().bulkSaveTasks(list);
+        if (CollUtil.isNotEmpty(list) && CollUtil.isNotEmpty(parentTaskList)) {
+            String processInstanceId = parentTaskList.get(0).getProcessInstanceId();
+            String processDefinitionId = parentTaskList.get(0).getProcessDefinitionId();
+            List<String> taskIds = StreamUtils.toList(list, Task::getId);
+            ActHiTaskinst actHiTaskinst = new ActHiTaskinst();
+            actHiTaskinst.setProcDefId(processDefinitionId);
+            actHiTaskinst.setProcInstId(processInstanceId);
+            actHiTaskinst.setScopeType(TaskStatusEnum.COPY.getStatus());
+            actHiTaskinst.setTenantId(tenantId);
+            LambdaUpdateWrapper<ActHiTaskinst> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.in(ActHiTaskinst::getId, taskIds);
+            ACT_HI_TASKINST_MAPPER.update(actHiTaskinst, updateWrapper);
+            for (Task task : list) {
+                PROCESS_ENGINE.getTaskService().addComment(task.getId(), task.getProcessInstanceId(), TaskStatusEnum.COPY.getStatus(), StrUtil.EMPTY);
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇褰撳墠浠诲姟鍙備笌鑰�
+     *
+     * @param taskId 浠诲姟id
+     */
+    public static ParticipantVo getCurrentTaskParticipant(String taskId, UserService userService) {
+        ParticipantVo participantVo = new ParticipantVo();
+        List<HistoricIdentityLink> linksForTask = PROCESS_ENGINE.getHistoryService().getHistoricIdentityLinksForTask(taskId);
+        Task task = QueryUtils.taskQuery().taskId(taskId).singleResult();
+        if (task != null && CollUtil.isNotEmpty(linksForTask)) {
+            List<HistoricIdentityLink> groupList = StreamUtils.filter(linksForTask, e -> StringUtils.isNotBlank(e.getGroupId()));
+            if (CollUtil.isNotEmpty(groupList)) {
+                List<Long> groupIds = StreamUtils.toList(groupList, e -> Long.valueOf(e.getGroupId()));
+                List<Long> userIds = userService.selectUserIdsByRoleIds(groupIds);
+                if (CollUtil.isNotEmpty(userIds)) {
+                    participantVo.setGroupIds(groupIds);
+                    List<UserDTO> userList = userService.selectListByIds(userIds);
+                    if (CollUtil.isNotEmpty(userList)) {
+                        List<Long> userIdList = StreamUtils.toList(userList, UserDTO::getUserId);
+                        List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
+                        participantVo.setCandidate(userIdList);
+                        participantVo.setCandidateName(nickNames);
+                        participantVo.setClaim(!StringUtils.isBlank(task.getAssignee()));
+                    }
+                }
+            } else {
+                List<HistoricIdentityLink> candidateList = StreamUtils.filter(linksForTask, e -> FlowConstant.CANDIDATE.equals(e.getType()));
+                List<Long> userIdList = new ArrayList<>();
+                for (HistoricIdentityLink historicIdentityLink : linksForTask) {
+                    try {
+                        userIdList.add(Long.valueOf(historicIdentityLink.getUserId()));
+                    } catch (NumberFormatException ignored) {
+
+                    }
+                }
+                List<UserDTO> userList = userService.selectListByIds(userIdList);
+                if (CollUtil.isNotEmpty(userList)) {
+                    List<Long> userIds = StreamUtils.toList(userList, UserDTO::getUserId);
+                    List<String> nickNames = StreamUtils.toList(userList, UserDTO::getNickName);
+                    participantVo.setCandidate(userIds);
+                    participantVo.setCandidateName(nickNames);
+                    // 鍒ゆ柇褰撳墠浠诲姟鏄惁鍏锋湁澶氫釜鍔炵悊浜�
+                    if (CollUtil.isNotEmpty(candidateList) && candidateList.size() > 1) {
+                        // 濡傛灉 assignee 瀛樺湪锛屽垯璁剧疆褰撳墠浠诲姟宸茬粡琚棰�
+                        participantVo.setClaim(StringUtils.isNotBlank(task.getAssignee()));
+                    }
+                }
+            }
+        }
+        return participantVo;
+    }
+
+    /**
+     * 鍒ゆ柇褰撳墠鑺傜偣鏄惁涓轰細绛捐妭鐐�
+     *
+     * @param processDefinitionId 娴佺▼瀹氫箟id
+     * @param taskDefinitionKey   娴佺▼瀹氫箟id
+     */
+    public static MultiInstanceVo isMultiInstance(String processDefinitionId, String taskDefinitionKey) {
+        BpmnModel bpmnModel = PROCESS_ENGINE.getRepositoryService().getBpmnModel(processDefinitionId);
+        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(taskDefinitionKey);
+        MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
+        //鍒ゆ柇鏄惁涓哄苟琛屼細绛捐妭鐐�
+        if (flowNode.getBehavior() instanceof ParallelMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
+            Expression collectionExpression = behavior.getCollectionExpression();
+            String assigneeList = collectionExpression.getExpressionText();
+            String assignee = behavior.getCollectionElementVariable();
+            multiInstanceVo.setType(behavior);
+            multiInstanceVo.setAssignee(assignee);
+            multiInstanceVo.setAssigneeList(assigneeList);
+            return multiInstanceVo;
+            //鍒ゆ柇鏄惁涓轰覆琛屼細绛捐妭鐐�
+        } else if (flowNode.getBehavior() instanceof SequentialMultiInstanceBehavior behavior && behavior.getCollectionExpression() != null) {
+            Expression collectionExpression = behavior.getCollectionExpression();
+            String assigneeList = collectionExpression.getExpressionText();
+            String assignee = behavior.getCollectionElementVariable();
+            multiInstanceVo.setType(behavior);
+            multiInstanceVo.setAssignee(assignee);
+            multiInstanceVo.setAssigneeList(assigneeList);
+            return multiInstanceVo;
+        }
+        return null;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param taskId 浠诲姟id
+     */
+    public static String getBusinessStatusByTaskId(String taskId) {
+        HistoricTaskInstance historicTaskInstance = QueryUtils.hisTaskInstanceQuery().taskId(taskId).singleResult();
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisInstanceQuery(historicTaskInstance.getProcessInstanceId()).singleResult();
+        return historicProcessInstance.getBusinessStatus();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠娴佺▼鐘舵��
+     *
+     * @param businessKey 涓氬姟id
+     */
+    public static String getBusinessStatus(String businessKey) {
+        HistoricProcessInstance historicProcessInstance = QueryUtils.hisBusinessKeyQuery(businessKey).singleResult();
+        return historicProcessInstance.getBusinessStatus();
+    }
+
+    /**
+     * 鍙戦�佹秷鎭�
+     *
+     * @param list        浠诲姟
+     * @param name        娴佺▼鍚嶇О
+     * @param messageType 娑堟伅绫诲瀷
+     * @param message     娑堟伅鍐呭锛屼负绌哄垯鍙戦�侀粯璁ら厤缃殑娑堟伅鍐呭
+     */
+    public static void sendMessage(List<Task> list, String name, List<String> messageType, String message, UserService userService) {
+        Set<Long> userIds = new HashSet<>();
+        if (StringUtils.isBlank(message)) {
+            message = "鏈夋柊鐨勩��" + name + "銆戝崟鎹凡缁忔彁浜よ嚦鎮ㄧ殑寰呭姙锛岃鎮ㄥ強鏃跺鐞嗐��";
+        }
+        for (Task t : list) {
+            ParticipantVo taskParticipant = WorkflowUtils.getCurrentTaskParticipant(t.getId(), userService);
+            if (CollUtil.isNotEmpty(taskParticipant.getGroupIds())) {
+                List<Long> userIdList = userService.selectUserIdsByRoleIds(taskParticipant.getGroupIds());
+                if (CollUtil.isNotEmpty(userIdList)) {
+                    userIds.addAll(userIdList);
+                }
+            }
+            List<Long> candidate = taskParticipant.getCandidate();
+            if (CollUtil.isNotEmpty(candidate)) {
+                userIds.addAll(candidate);
+            }
+        }
+        if (CollUtil.isNotEmpty(userIds)) {
+            List<UserDTO> userList = userService.selectListByIds(new ArrayList<>(userIds));
+            for (String code : messageType) {
+                MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
+                if (ObjectUtil.isNotEmpty(messageTypeEnum)) {
+                    switch (messageTypeEnum) {
+                        case SYSTEM_MESSAGE:
+                            WebSocketMessageDto dto = new WebSocketMessageDto();
+                            dto.setSessionKeys(new ArrayList<>(userIds));
+                            dto.setMessage(message);
+                            WebSocketUtils.publishMessage(dto);
+                            break;
+                        case EMAIL_MESSAGE:
+                            MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "鍗曟嵁瀹℃壒鎻愰啋", message);
+                            break;
+                        case SMS_MESSAGE:
+                            //todo 鐭俊鍙戦��
+                            break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 鏍规嵁浠诲姟id鏌ヨ 褰撳墠鐢ㄦ埛鐨勪换鍔★紝妫�鏌� 褰撳墠浜哄憳 鏄惁鏄 taskId 鐨勫姙鐞嗕汉
+     *
+     * @param taskId 浠诲姟id
+     * @return 缁撴灉
+     */
+    public static Task getTaskByCurrentUser(String taskId) {
+        TaskQuery taskQuery = QueryUtils.taskQuery();
+        taskQuery.taskId(taskId).taskCandidateOrAssigned(String.valueOf(LoginHelper.getUserId()));
+
+        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
+        if (CollUtil.isNotEmpty(roles)) {
+            List<String> groupIds = StreamUtils.toList(roles, e -> String.valueOf(e.getRoleId()));
+            taskQuery.taskCandidateGroupIn(groupIds);
+        }
+        return taskQuery.singleResult();
+    }
+}
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml
new file mode 100644
index 0000000..dd05785
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiProcinstMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.ActHiProcinstMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml
new file mode 100644
index 0000000..7e73b60
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActHiTaskinstMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.ActHiTaskinstMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml
new file mode 100644
index 0000000..d1508ab
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/ActTaskMapper.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.ActTaskMapper">
+    <resultMap type="org.dromara.workflow.domain.vo.TaskVo" id="TaskVoResult">
+        <result property="id" column="ID_"/>
+        <result property="name" column="NAME_"/>
+        <result property="description" column="DESCRIPTION_"/>
+        <result property="priority" column="PRIORITY_"/>
+        <result property="owner" column="OWNER_"/>
+        <result property="assignee" column="ASSIGNEE_"/>
+        <result property="processInstanceId" column="PROC_INST_ID_"/>
+        <result property="executionId" column="EXECUTION_ID_"/>
+        <result property="taskDefinitionId" column="TASK_DEF_ID_"/>
+        <result property="processDefinitionId" column="PROC_DEF_ID_"/>
+        <result property="createTime" column="CREATE_TIME_"/>
+        <result property="startTime" column="START_TIME_"/>
+        <result property="endTime" column="END_TIME_"/>
+        <result property="taskDefinitionKey" column="TASK_DEF_KEY_"/>
+        <result property="dueDate" column="DUE_DATE_"/>
+        <result property="category" column="CATEGORY_"/>
+        <result property="parentTaskId" column="PARENT_TASK_ID_"/>
+        <result property="tenantId" column="TENANT_ID_"/>
+        <result property="claimTime" column="CLAIM_TIME"/>
+        <result property="businessStatus" column="BUSINESS_STATUS_"/>
+        <result property="processDefinitionName" column="processDefinitionName"/>
+        <result property="processDefinitionKey" column="processDefinitionKey"/>
+        <result property="processDefinitionVersion" column="processDefinitionVersion"/>
+        <result property="businessKey" column="BUSINESS_KEY_"/>
+
+    </resultMap>
+    <select id="getTaskWaitByPage" resultMap="TaskVoResult">
+        select *
+        from (SELECT RES.*,
+                     AHP.BUSINESS_STATUS_,
+                     AHP.BUSINESS_KEY_,
+                     ARP.NAME_ AS processDefinitionName,
+                     ARP.KEY_  AS processDefinitionKey,
+                     ARP.VERSION_  AS processDefinitionVersion
+              FROM ACT_RU_TASK RES
+                       INNER JOIN ACT_HI_PROCINST AHP ON RES.PROC_INST_ID_ = AHP.PROC_INST_ID_
+                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = RES.PROC_DEF_ID_
+              WHERE RES.PARENT_TASK_ID_ IS NULL
+              ORDER BY RES.CREATE_TIME_ DESC) t ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="getTaskFinishByPage" resultMap="TaskVoResult">
+        select *
+        from (SELECT HTI.*,
+                     AHP.BUSINESS_STATUS_,
+                     AHP.BUSINESS_KEY_,
+                     ARP.NAME_ AS processDefinitionName,
+                     ARP.KEY_  AS processDefinitionKey,
+                     ARP.VERSION_  AS processDefinitionVersion
+              FROM ACT_HI_TASKINST HTI
+                       INNER JOIN ACT_HI_PROCINST AHP ON HTI.PROC_INST_ID_ = AHP.PROC_INST_ID_
+                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = HTI.PROC_DEF_ID_
+              WHERE HTI.PARENT_TASK_ID_ IS NULL AND HTI.END_TIME_ IS NOT NULL
+              ORDER BY HTI.START_TIME_ DESC) t ${ew.getCustomSqlSegment}
+    </select>
+
+    <select id="getTaskCopyByPage" resultMap="TaskVoResult">
+        select *
+        from (SELECT AHT.*,
+                     AHP.BUSINESS_STATUS_,
+                     AHP.BUSINESS_KEY_,
+                     ARP.NAME_ as processDefinitionName,
+                     ARP.KEY_  as processDefinitionKey,
+                     ARP.VERSION_  AS processDefinitionVersion
+              FROM ACT_HI_TASKINST AHT
+                       INNER JOIN ACT_HI_PROCINST AHP ON AHT.PROC_INST_ID_ = AHP.PROC_INST_ID_
+                       INNER JOIN ACT_RE_PROCDEF ARP ON ARP.ID_ = AHT.PROC_DEF_ID_
+              WHERE AHT.PARENT_TASK_ID_ IS NOT NULL
+                and AHT.scope_type_ = 'copy'
+              ORDER BY AHT.START_TIME_ DESC) t ${ew.getCustomSqlSegment}
+    </select>
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml
new file mode 100644
index 0000000..d52f6b0
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.TestLeaveMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml
new file mode 100644
index 0000000..4375cb2
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfCategoryMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.WfCategoryMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml
new file mode 100644
index 0000000..8d579f7
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfDefinitionConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.WfDefinitionConfigMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml
new file mode 100644
index 0000000..59221f8
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfFormManageMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.WfFormManageMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml
new file mode 100644
index 0000000..b65194f
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfNodeConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.WfNodeConfigMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml
new file mode 100644
index 0000000..4a9179b
--- /dev/null
+++ b/eims/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/WfTaskBackNodeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.workflow.mapper.WfTaskBackNodeMapper">
+
+</mapper>
diff --git a/eims/script/bin/ry.bat b/eims/script/bin/ry.bat
new file mode 100644
index 0000000..ea98cbe
--- /dev/null
+++ b/eims/script/bin/ry.bat
@@ -0,0 +1,68 @@
+rem 浣跨敤鑰呭簲鏍规嵁鑷韩骞冲彴缂栫爜鑷杞崲 闃叉涔辩爜 渚嬪 win浣跨敤gbk缂栫爜
+@echo off
+
+rem jar骞崇骇鐩綍
+set AppName=ruoyi-admin.jar
+
+rem JVM鍙傛暟
+set JVM_OPTS="-Dname=%AppName%  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC"
+
+
+ECHO.
+	ECHO.  [1] 鍚姩%AppName%
+	ECHO.  [2] 鍏抽棴%AppName%
+	ECHO.  [3] 閲嶅惎%AppName%
+	ECHO.  [4] 鍚姩鐘舵�� %AppName%
+	ECHO.  [5] 閫� 鍑�
+ECHO.
+
+ECHO.璇疯緭鍏ラ�夋嫨椤圭洰鐨勫簭鍙�:
+set /p ID=
+	IF "%id%"=="1" GOTO start
+	IF "%id%"=="2" GOTO stop
+	IF "%id%"=="3" GOTO restart
+	IF "%id%"=="4" GOTO status
+	IF "%id%"=="5" EXIT
+PAUSE
+:start
+    for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
+		set pid=%%a
+		set image_name=%%b
+	)
+	if  defined pid (
+		echo %%is running
+		PAUSE
+	)
+
+start javaw %JVM_OPTS% -jar %AppName%
+
+echo  starting鈥︹��
+echo  Start %AppName% success...
+goto:eof
+
+rem 鍑芥暟stop閫氳繃jps鍛戒护鏌ユ壘pid骞剁粨鏉熻繘绋�
+:stop
+	for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
+		set pid=%%a
+		set image_name=%%b
+	)
+	if not defined pid (echo process %AppName% does not exists) else (
+		echo prepare to kill %image_name%
+		echo start kill %pid% ...
+		rem 鏍规嵁杩涚▼ID锛宬ill杩涚▼
+		taskkill /f /pid %pid%
+	)
+goto:eof
+:restart
+	call :stop
+    call :start
+goto:eof
+:status
+	for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
+		set pid=%%a
+		set image_name=%%b
+	)
+	if not defined pid (echo process %AppName% is dead ) else (
+		echo %image_name% is running
+	)
+goto:eof
diff --git a/eims/script/bin/ry.sh b/eims/script/bin/ry.sh
new file mode 100644
index 0000000..a6f5d9c
--- /dev/null
+++ b/eims/script/bin/ry.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+# ./ry.sh start 鍚姩 stop 鍋滄 restart 閲嶅惎 status 鐘舵��
+AppName=ruoyi-admin.jar
+
+# JVM鍙傛暟
+JVM_OPTS="-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC"
+APP_HOME=`pwd`
+LOG_PATH=$APP_HOME/logs/$AppName.log
+
+if [ "$1" = "" ];
+then
+    echo -e "\033[0;31m 鏈緭鍏ユ搷浣滃悕 \033[0m  \033[0;34m {start|stop|restart|status} \033[0m"
+    exit 1
+fi
+
+if [ "$AppName" = "" ];
+then
+    echo -e "\033[0;31m 鏈緭鍏ュ簲鐢ㄥ悕 \033[0m"
+    exit 1
+fi
+
+function start()
+{
+    PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
+
+    if [ x"$PID" != x"" ]; then
+        echo "$AppName is running..."
+    else
+        nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &
+        echo "Start $AppName success..."
+    fi
+}
+
+function stop()
+{
+    echo "Stop $AppName"
+
+    PID=""
+    query(){
+        PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
+    }
+
+    query
+    if [ x"$PID" != x"" ]; then
+        kill -TERM $PID
+        echo "$AppName (pid:$PID) exiting..."
+        while [ x"$PID" != x"" ]
+        do
+            sleep 1
+            query
+        done
+        echo "$AppName exited."
+    else
+        echo "$AppName already stopped."
+    fi
+}
+
+function restart()
+{
+    stop
+    sleep 2
+    start
+}
+
+function status()
+{
+    PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
+    if [ $PID != 0 ];then
+        echo "$AppName is running..."
+    else
+        echo "$AppName is not running..."
+    fi
+}
+
+case $1 in
+    start)
+    start;;
+    stop)
+    stop;;
+    restart)
+    restart;;
+    status)
+    status;;
+    *)
+
+esac
diff --git "a/eims/script/bpmn/\346\250\241\345\236\213.zip" "b/eims/script/bpmn/\346\250\241\345\236\213.zip"
new file mode 100644
index 0000000..6f30952
--- /dev/null
+++ "b/eims/script/bpmn/\346\250\241\345\236\213.zip"
Binary files differ
diff --git a/eims/script/docker/database.yml b/eims/script/docker/database.yml
new file mode 100644
index 0000000..0368fd2
--- /dev/null
+++ b/eims/script/docker/database.yml
@@ -0,0 +1,61 @@
+version: '3'
+
+services:
+  # 姝ら暅鍍忎粎鐢ㄤ簬娴嬭瘯 姝e紡鐜闇�鑷瀹夎鏁版嵁搴�
+  # SID: XE user: system password: oracle
+  oracle:
+    image: tekintian/oracle12c:latest
+    container_name: oracle
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      DBCA_TOTAL_MEMORY: 16192
+    ports:
+      - "18080:8080"
+      - "1521:1521"
+    volumes:
+      # 鏁版嵁鎸傝浇
+      - "/docker/oracle/data:/u01/app/oracle"
+    network_mode: "host"
+
+  # 姝ら暅鍍忎粎鐢ㄤ簬娴嬭瘯 姝e紡鐜闇�鑷瀹夎鏁版嵁搴�
+  sqlserver:
+    image: mcr.microsoft.com/mssql/server:2017-latest
+    container_name: sqlserver
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      ACCEPT_EULA: "Y"
+      SA_PASSWORD: "Ruoyi@123"
+    ports:
+      - "1433:1433"
+    volumes:
+      # 鏁版嵁鎸傝浇
+      - "/docker/sqlserver/data:/var/opt/mssql"
+    network_mode: "host"
+
+  postgres:
+    image: postgres:14.2
+    container_name: postgres
+    environment:
+      POSTGRES_USER: root
+      POSTGRES_PASSWORD: root
+      POSTGRES_DB: postgres
+    ports:
+      - "5432:5432"
+    volumes:
+      - /docker/postgres/data:/var/lib/postgresql/data
+    network_mode: "host"
+
+  postgres13:
+    image: postgres:13.6
+    container_name: postgres13
+    environment:
+      POSTGRES_USER: root
+      POSTGRES_PASSWORD: root
+      POSTGRES_DB: postgres
+    ports:
+      - "5433:5432"
+    volumes:
+      - /docker/postgres13/data:/var/lib/postgresql/data
+    network_mode: "host"
diff --git a/eims/script/docker/docker-compose.yml b/eims/script/docker/docker-compose.yml
new file mode 100644
index 0000000..91d97ae
--- /dev/null
+++ b/eims/script/docker/docker-compose.yml
@@ -0,0 +1,156 @@
+version: '3'
+
+services:
+  mysql:
+    image: mysql:8.0.33
+    container_name: mysql
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      # root 瀵嗙爜
+      MYSQL_ROOT_PASSWORD: root
+      # 鍒濆鍖栨暟鎹簱(鍚庣画鐨勫垵濮嬪寲sql浼氬湪杩欎釜搴撴墽琛�)
+      MYSQL_DATABASE: ry-vue
+    ports:
+      - "3306:3306"
+    volumes:
+      # 鏁版嵁鎸傝浇
+      - /docker/mysql/data/:/var/lib/mysql/
+      # 閰嶇疆鎸傝浇
+      - /docker/mysql/conf/:/etc/mysql/conf.d/
+    command:
+      # 灏唌ysql8.0榛樿瀵嗙爜绛栫暐 淇敼涓� 鍘熷厛 绛栫暐 (mysql8.0瀵瑰叾榛樿绛栫暐鍋氫簡鏇存敼 浼氬鑷村瘑鐮佹棤娉曞尮閰�)
+      --default-authentication-plugin=mysql_native_password
+      --character-set-server=utf8mb4
+      --collation-server=utf8mb4_general_ci
+      --explicit_defaults_for_timestamp=true
+      --lower_case_table_names=1
+    privileged: true
+    network_mode: "host"
+
+  nginx-web:
+    image: nginx:1.23.4
+    container_name: nginx-web
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+    ports:
+      - "80:80"
+      - "443:443"
+    volumes:
+      # 璇佷功鏄犲皠
+      - /docker/nginx/cert:/etc/nginx/cert
+      # 閰嶇疆鏂囦欢鏄犲皠
+      - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
+      # 椤甸潰鐩綍
+      - /docker/nginx/html:/usr/share/nginx/html
+      # 鏃ュ織鐩綍
+      - /docker/nginx/log:/var/log/nginx
+    privileged: true
+    network_mode: "host"
+
+  redis:
+    image: redis:6.2.12
+    container_name: redis
+    ports:
+      - "6379:6379"
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+    volumes:
+      # 閰嶇疆鏂囦欢
+      - /docker/redis/conf:/redis/config:rw
+      # 鏁版嵁鏂囦欢
+      - /docker/redis/data/:/redis/data/:rw
+    command: "redis-server /redis/config/redis.conf"
+    privileged: true
+    network_mode: "host"
+
+  minio:
+    image: minio/minio:RELEASE.2023-04-13T03-08-07Z
+    container_name: minio
+    ports:
+      # api 绔彛
+      - "9000:9000"
+      # 鎺у埗鍙扮鍙�
+      - "9001:9001"
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      # 绠$悊鍚庡彴鐢ㄦ埛鍚�
+      MINIO_ROOT_USER: ruoyi
+      # 绠$悊鍚庡彴瀵嗙爜锛屾渶灏�8涓瓧绗�
+      MINIO_ROOT_PASSWORD: ruoyi123
+      # https闇�瑕佹寚瀹氬煙鍚�
+      #MINIO_SERVER_URL: "https://xxx.com:9000"
+      #MINIO_BROWSER_REDIRECT_URL: "https://xxx.com:9001"
+      # 寮�鍚帇缂� on 寮�鍚� off 鍏抽棴
+      MINIO_COMPRESS: "off"
+      # 鎵╁睍鍚� .pdf,.doc 涓虹┖ 鎵�鏈夌被鍨嬪潎鍘嬬缉
+      MINIO_COMPRESS_EXTENSIONS: ""
+      # mime 绫诲瀷 application/pdf 涓虹┖ 鎵�鏈夌被鍨嬪潎鍘嬬缉
+      MINIO_COMPRESS_MIME_TYPES: ""
+    volumes:
+      # 鏄犲皠褰撳墠鐩綍涓嬬殑data鐩綍鑷冲鍣ㄥ唴/data鐩綍
+      - /docker/minio/data:/data
+      # 鏄犲皠閰嶇疆鐩綍
+      - /docker/minio/config:/root/.minio/
+    command: server --address ':9000' --console-address ':9001' /data  # 鎸囧畾瀹瑰櫒涓殑鐩綍 /data
+    privileged: true
+    network_mode: "host"
+
+  ruoyi-server1:
+    image: ruoyi/ruoyi-server:5.2.2
+    container_name: ruoyi-server1
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      SERVER_PORT: 8080
+    volumes:
+      # 閰嶇疆鏂囦欢
+      - /docker/server1/logs/:/ruoyi/server/logs/
+      # skywalking 鎺㈤拡
+#      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+    privileged: true
+    network_mode: "host"
+
+  ruoyi-server2:
+    image: ruoyi/ruoyi-server:5.2.2
+    container_name: ruoyi-server2
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+      SERVER_PORT: 8081
+    volumes:
+      # 閰嶇疆鏂囦欢
+      - /docker/server2/logs/:/ruoyi/server/logs/
+      # skywalking 鎺㈤拡
+#      - /docker/skywalking/agent/:/ruoyi/skywalking/agent
+    privileged: true
+    network_mode: "host"
+
+  ruoyi-monitor-admin:
+    image: ruoyi/ruoyi-monitor-admin:5.2.2
+    container_name: ruoyi-monitor-admin
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+    volumes:
+      # 閰嶇疆鏂囦欢
+      - /docker/monitor/logs/:/ruoyi/monitor/logs
+    privileged: true
+    network_mode: "host"
+
+  ruoyi-snailjob-server:
+    image: ruoyi/ruoyi-snailjob-server:5.2.2
+    container_name: ruoyi-snailjob-server
+    environment:
+      # 鏃跺尯涓婃捣
+      TZ: Asia/Shanghai
+    ports:
+      - "8800:8800"
+      - "17888:17888"
+    volumes:
+      - /docker/snailjob/logs/:/ruoyi/snailjob/logs
+    privileged: true
+    network_mode: "host"
diff --git a/eims/script/docker/nginx/conf/nginx.conf b/eims/script/docker/nginx/conf/nginx.conf
new file mode 100644
index 0000000..3c79d97
--- /dev/null
+++ b/eims/script/docker/nginx/conf/nginx.conf
@@ -0,0 +1,115 @@
+worker_processes  1;
+
+error_log  /var/log/nginx/error.log warn;
+pid        /var/run/nginx.pid;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+    sendfile        on;
+    keepalive_timeout  65;
+    # 闄愬埗body澶у皬
+    client_max_body_size 100m;
+
+    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                          '$status $body_bytes_sent "$http_referer" '
+                          '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log  /var/log/nginx/access.log  main;
+
+    upstream server {
+        ip_hash;
+        server 127.0.0.1:8080;
+        server 127.0.0.1:8081;
+    }
+
+    upstream monitor-admin {
+        server 127.0.0.1:9090;
+    }
+
+    upstream snailjob-server {
+        server 127.0.0.1:8800;
+    }
+
+    server {
+        listen       80;
+        server_name  localhost;
+
+        # https閰嶇疆鍙傝�� start
+        #listen       443 ssl;
+
+        # 璇佷功鐩存帴瀛樻斁 /docker/nginx/cert/ 鐩綍涓嬪嵆鍙� 鏇存敼璇佷功鍚嶇О鍗冲彲 鏃犻渶鏇存敼璇佷功璺緞
+        #ssl on;
+        #ssl_certificate      /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 涓篸ocker鏄犲皠璺緞 涓嶅厑璁告洿鏀�
+        #ssl_certificate_key  /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 涓篸ocker鏄犲皠璺緞 涓嶅厑璁告洿鏀�
+        #ssl_session_timeout 5m;
+        #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
+        #ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+        #ssl_prefer_server_ciphers on;
+        # https閰嶇疆鍙傝�� end
+
+        # 婕旂ず鐜閰嶇疆 鎷︽埅闄� GET POST 涔嬪鐨勬墍鏈夎姹�
+        # if ($request_method !~* GET|POST) {
+        #     rewrite  ^/(.*)$  /403;
+        # }
+
+        # location = /403 {
+        #     default_type application/json;
+        #     return 200 '{"msg":"婕旂ず妯″紡锛屼笉鍏佽鎿嶄綔","code":500}';
+        # }
+
+        # 闄愬埗澶栫綉璁块棶鍐呯綉 actuator 鐩稿叧璺緞
+        location ~ ^(/[^/]*)?/actuator.*(/.*)?$ {
+            return 403;
+        }
+
+        location / {
+            root   /usr/share/nginx/html; # docker鏄犲皠璺緞 涓嶅厑璁告洿鏀�
+            try_files $uri $uri/ /index.html;
+            index  index.html index.htm;
+        }
+
+        location /prod-api/ {
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header REMOTE-HOST $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_read_timeout 86400s;
+            # sse 涓� websocket鍙傛暟
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+            proxy_buffering off;
+            proxy_cache off;
+            proxy_pass http://server/;
+        }
+
+        # https 浼氭嫤鎴唴閾炬墍鏈夌殑 http 璇锋眰 閫犳垚鍔熻兘鏃犳硶浣跨敤
+        # 瑙e喅鏂规1 灏� admin 鏈嶅姟 涔熼厤缃垚 https
+        # 瑙e喅鏂规2 灏嗚彍鍗曢厤缃负澶栭摼璁块棶 璧扮嫭绔嬮〉闈� http 璁块棶
+        location /admin/ {
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header REMOTE-HOST $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_pass http://monitor-admin/admin/;
+        }
+
+        location /snail-job/ {
+            proxy_set_header Host $http_host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header REMOTE-HOST $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_pass http://snailjob-server/snail-job/;
+        }
+
+        error_page   500 502 503 504  /50x.html;
+        location = /50x.html {
+            root   html;
+        }
+    }
+}
diff --git a/eims/script/docker/redis/conf/redis.conf b/eims/script/docker/redis/conf/redis.conf
new file mode 100644
index 0000000..72255c6
--- /dev/null
+++ b/eims/script/docker/redis/conf/redis.conf
@@ -0,0 +1,28 @@
+# redis 瀵嗙爜
+requirepass ruoyi123
+
+# key 鐩戝惉鍣ㄩ厤缃�
+# notify-keyspace-events Ex
+
+# 閰嶇疆鎸佷箙鍖栨枃浠跺瓨鍌ㄨ矾寰�
+dir /redis/data
+# 閰嶇疆rdb
+# 15鍒嗛挓鍐呮湁鑷冲皯1涓猭ey琚洿鏀瑰垯杩涜蹇収
+save 900 1
+# 5鍒嗛挓鍐呮湁鑷冲皯10涓猭ey琚洿鏀瑰垯杩涜蹇収
+save 300 10
+# 1鍒嗛挓鍐呮湁鑷冲皯10000涓猭ey琚洿鏀瑰垯杩涜蹇収
+save 60 10000
+# 寮�鍚帇缂�
+rdbcompression yes
+# rdb鏂囦欢鍚� 鐢ㄩ粯璁ょ殑鍗冲彲
+dbfilename dump.rdb
+
+# 寮�鍚痑of
+appendonly yes
+# 鏂囦欢鍚�
+appendfilename "appendonly.aof"
+# 鎸佷箙鍖栫瓥鐣�,no:涓嶅悓姝�,everysec:姣忕涓�娆�,always:鎬绘槸鍚屾,閫熷害姣旇緝鎱�
+# appendfsync always
+appendfsync everysec
+# appendfsync no
diff --git a/eims/script/docker/redis/data/README.md b/eims/script/docker/redis/data/README.md
new file mode 100644
index 0000000..fbc5474
--- /dev/null
+++ b/eims/script/docker/redis/data/README.md
@@ -0,0 +1 @@
+鏁版嵁鐩綍 璇锋墽琛� `chmod 777 /docker/redis/data` 璧嬩簣璇诲啓鏉冮檺 鍚﹀垯灏嗘棤娉曞啓鍏ユ暟鎹�
\ No newline at end of file
diff --git a/eims/script/sql/flowable.sql b/eims/script/sql/flowable.sql
new file mode 100644
index 0000000..e8dc798
--- /dev/null
+++ b/eims/script/sql/flowable.sql
@@ -0,0 +1,176 @@
+insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, sysdate(), NULL, NULL, '');
+insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate(), NULL, NULL, '');
+
+
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate(), null, null, '');
+-- 璇峰亣鍗曚俊鎭�
+create table test_leave
+(
+    id          bigint                       not null comment '涓婚敭',
+    leave_type  varchar(255)                 not null comment '璇峰亣绫诲瀷',
+    start_date   datetime                     not null comment '寮�濮嬫椂闂�',
+    end_date     datetime                     not null comment '缁撴潫鏃堕棿',
+    leave_days  int(10)                      not null comment '璇峰亣澶╂暟',
+    remark      varchar(255)                 null comment '璇峰亣鍘熷洜',
+    status      varchar(255)                 null comment '鐘舵��',
+    create_dept bigint                       null comment '鍒涘缓閮ㄩ棬',
+    create_by   bigint                       null comment '鍒涘缓鑰�',
+    create_time datetime                     null comment '鍒涘缓鏃堕棿',
+    update_by   bigint                       null comment '鏇存柊鑰�',
+    update_time datetime                     null comment '鏇存柊鏃堕棿',
+    tenant_id   varchar(20)                  null comment '绉熸埛缂栧彿',
+    PRIMARY KEY (id) USING BTREE
+) ENGINE = InnoDB COMMENT = '璇峰亣鐢宠琛�';
+
+-- 娴佺▼鍒嗙被淇℃伅琛�
+create table wf_category
+(
+    id            bigint                       not null comment '涓婚敭'
+        primary key,
+    category_name varchar(255)                 null comment '鍒嗙被鍚嶇О',
+    category_code varchar(255)                 null comment '鍒嗙被缂栫爜',
+    parent_id     bigint                       null comment '鐖剁骇id',
+    sort_num      int(19)                      null comment '鎺掑簭',
+    tenant_id     varchar(20)                  null comment '绉熸埛缂栧彿',
+    create_dept   bigint                       null comment '鍒涘缓閮ㄩ棬',
+    create_by     bigint                       null comment '鍒涘缓鑰�',
+    create_time   datetime                     null comment '鍒涘缓鏃堕棿',
+    update_by     bigint                       null comment '鏇存柊鑰�',
+    update_time   datetime                     null comment '鏇存柊鏃堕棿',
+    constraint uni_category_code
+        unique (category_code)
+) engine=innodb comment= '娴佺▼鍒嗙被';
+INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate(), 1, sysdate());
+
+create table wf_task_back_node
+(
+    id          bigint                       not null
+        primary key,
+    node_id     varchar(255)                 not null comment '鑺傜偣id',
+    node_name   varchar(255)                 not null comment '鑺傜偣鍚嶇О',
+    order_no    int                          not null comment '鎺掑簭',
+    instance_id varchar(255)                 null comment '娴佺▼瀹炰緥id',
+    task_type   varchar(255)                 not null comment '鑺傜偣绫诲瀷',
+    assignee    varchar(2000)                not null comment '瀹℃壒浜�',
+    tenant_id   varchar(20)                  null comment '绉熸埛缂栧彿',
+    create_dept bigint                       null comment '鍒涘缓閮ㄩ棬',
+    create_by   bigint                       null comment '鍒涘缓鑰�',
+    create_time datetime                     null comment '鍒涘缓鏃堕棿',
+    update_by   bigint                       null comment '鏇存柊鑰�',
+    update_time datetime                     null comment '鏇存柊鏃堕棿'
+)
+    comment '鑺傜偣瀹℃壒璁板綍';
+
+create table wf_definition_config
+(
+    id            bigint                        not null comment '涓婚敭'
+        primary key,
+    table_name    varchar(255)                  not null comment '琛ㄥ悕',
+    definition_id varchar(255)                  not null comment '娴佺▼瀹氫箟ID',
+    process_key   varchar(255)                  not null comment '娴佺▼KEY',
+    version       int(10)                       not null comment '娴佺▼鐗堟湰',
+    create_dept   bigint                        null comment '鍒涘缓閮ㄩ棬',
+    create_by     bigint                        null comment '鍒涘缓鑰�',
+    create_time   datetime                      null comment '鍒涘缓鏃堕棿',
+    update_by     bigint                        null comment '鏇存柊鑰�',
+    update_time   datetime                      null comment '鏇存柊鏃堕棿',
+    remark        varchar(500) default ''       null comment '澶囨敞',
+    tenant_id     varchar(20)                   null comment '绉熸埛缂栧彿',
+    constraint uni_definition_id
+        unique (definition_id)
+)
+    comment '娴佺▼瀹氫箟閰嶇疆';
+
+create table wf_form_manage
+(
+    id          bigint       not null comment '涓婚敭'
+        primary key,
+    form_name   varchar(255) not null comment '琛ㄥ崟鍚嶇О',
+    form_type   varchar(255) not null comment '琛ㄥ崟绫诲瀷',
+    router      varchar(255) not null comment '璺敱鍦板潃/琛ㄥ崟ID',
+    remark      varchar(500) null comment '澶囨敞',
+    tenant_id   varchar(20)  null comment '绉熸埛缂栧彿',
+    create_dept bigint       null comment '鍒涘缓閮ㄩ棬',
+    create_by   bigint       null comment '鍒涘缓鑰�',
+    create_time datetime     null comment '鍒涘缓鏃堕棿',
+    update_by   bigint       null comment '鏇存柊鑰�',
+    update_time datetime     null comment '鏇存柊鏃堕棿'
+)
+    comment '琛ㄥ崟绠$悊';
+
+insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate(), 1, sysdate());
+
+create table wf_node_config
+(
+    id               bigint       not null comment '涓婚敭'
+        primary key,
+    form_id          bigint       null comment '琛ㄥ崟id',
+    form_type        varchar(255) null comment '琛ㄥ崟绫诲瀷',
+    node_name        varchar(255) not null comment '鑺傜偣鍚嶇О',
+    node_id          varchar(255) not null comment '鑺傜偣id',
+    definition_id    varchar(255) not null comment '娴佺▼瀹氫箟id',
+    apply_user_task  char(1)      default '0'     comment '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級',
+    create_dept      bigint       null comment '鍒涘缓閮ㄩ棬',
+    create_by        bigint       null comment '鍒涘缓鑰�',
+    create_time      datetime     null comment '鍒涘缓鏃堕棿',
+    update_by        bigint       null comment '鏇存柊鑰�',
+    update_time      datetime     null comment '鏇存柊鏃堕棿',
+    tenant_id        varchar(20)  null comment '绉熸埛缂栧彿'
+)
+    comment '鑺傜偣閰嶇疆';
+
+
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, '');
+
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate(), NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
+
+-- 琛ㄥ崟绠$悊 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
+
+-- 琛ㄥ崟绠$悊鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, sysdate(), null, null, '');
diff --git a/eims/script/sql/oracle/flowable.sql b/eims/script/sql/oracle/flowable.sql
new file mode 100644
index 0000000..65474f4
--- /dev/null
+++ b/eims/script/sql/oracle/flowable.sql
@@ -0,0 +1,261 @@
+insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, sysdate, NULL, NULL, '');
+insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, sysdate, NULL, NULL, '');
+
+
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, sysdate, null, null, '');
+
+-- 璇峰亣鍗曚俊鎭�
+create table TEST_LEAVE
+(
+    ID          NUMBER(20) not null
+        constraint PK_TEST_LEAVE
+        primary key,
+    LEAVE_TYPE  VARCHAR2(255),
+    START_DATE  DATE,
+    END_DATE    DATE,
+    LEAVE_DAYS  NUMBER(10),
+    REMARK      VARCHAR2(255),
+    STATUS      VARCHAR2(255),
+    CREATE_DEPT NUMBER(20),
+    CREATE_BY   NUMBER(20),
+    CREATE_TIME DATE,
+    UPDATE_BY   NUMBER(20),
+    UPDATE_TIME DATE,
+    TENANT_ID   VARCHAR2(20)
+);
+
+comment on table TEST_LEAVE is '璇峰亣鐢宠琛�';
+comment on column TEST_LEAVE.ID is '涓婚敭';
+comment on column TEST_LEAVE.LEAVE_TYPE is '璇峰亣绫诲瀷';
+comment on column TEST_LEAVE.START_DATE is '寮�濮嬫椂闂�';
+comment on column TEST_LEAVE.END_DATE is '缁撴潫鏃堕棿';
+comment on column TEST_LEAVE.LEAVE_DAYS is '璇峰亣澶╂暟';
+comment on column TEST_LEAVE.REMARK is '璇峰亣鍘熷洜';
+comment on column TEST_LEAVE.STATUS is '鐘舵��';
+comment on column TEST_LEAVE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column TEST_LEAVE.CREATE_BY is '鍒涘缓鑰�';
+comment on column TEST_LEAVE.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column TEST_LEAVE.UPDATE_BY is '鏇存柊鑰�';
+comment on column TEST_LEAVE.UPDATE_TIME is '鏇存柊鏃堕棿';
+comment on column TEST_LEAVE.TENANT_ID is '绉熸埛缂栧彿';
+
+-- 娴佺▼鍒嗙被淇℃伅琛�
+create table WF_CATEGORY
+(
+    ID            NUMBER(20) not null
+        constraint PK_WF_CATEGORY
+        primary key,
+    CATEGORY_NAME VARCHAR2(255),
+    CATEGORY_CODE VARCHAR2(255)
+        constraint UNI_CATEGORY_CODE
+        unique,
+    PARENT_ID     NUMBER(20),
+    SORT_NUM      NUMBER(10),
+    TENANT_ID     VARCHAR2(20),
+    CREATE_DEPT   NUMBER(20),
+    CREATE_BY     NUMBER(20),
+    CREATE_TIME   DATE,
+    UPDATE_BY     NUMBER(20),
+    UPDATE_TIME   DATE
+);
+
+comment on table WF_CATEGORY is '娴佺▼鍒嗙被';
+comment on column WF_CATEGORY.ID is '涓婚敭';
+comment on column WF_CATEGORY.CATEGORY_NAME is '鍒嗙被鍚嶇О';
+comment on column WF_CATEGORY.CATEGORY_CODE is '鍒嗙被缂栫爜';
+comment on column WF_CATEGORY.PARENT_ID is '鐖剁骇id';
+comment on column WF_CATEGORY.SORT_NUM is '鎺掑簭';
+comment on column WF_CATEGORY.TENANT_ID is '绉熸埛缂栧彿';
+comment on column WF_CATEGORY.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column WF_CATEGORY.CREATE_BY is '鍒涘缓鑰�';
+comment on column WF_CATEGORY.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column WF_CATEGORY.UPDATE_BY is '鏇存柊鑰�';
+comment on column WF_CATEGORY.UPDATE_TIME is '鏇存柊鏃堕棿';
+INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, sysdate, 1, sysdate);
+
+create table WF_TASK_BACK_NODE
+(
+    ID            NUMBER(20) not null
+        constraint PK_WF_TASK_BACK_NODE
+        primary key,
+    NODE_ID       VARCHAR2(255) not null,
+    NODE_NAME     VARCHAR2(255) not null,
+    ORDER_NO      NUMBER(20) not null,
+    INSTANCE_ID   VARCHAR2(255) not null,
+    TASK_TYPE     VARCHAR2(255) not null,
+    ASSIGNEE      VARCHAR2(2000) not null,
+    TENANT_ID     VARCHAR2(20),
+    CREATE_DEPT   NUMBER(20),
+    CREATE_BY     NUMBER(20),
+    CREATE_TIME   DATE,
+    UPDATE_BY     NUMBER(20),
+    UPDATE_TIME   DATE
+);
+comment on table WF_TASK_BACK_NODE is '鑺傜偣瀹℃壒璁板綍';
+comment on column WF_TASK_BACK_NODE.ID is '涓婚敭';
+comment on column WF_TASK_BACK_NODE.NODE_ID is '鑺傜偣id';
+comment on column WF_TASK_BACK_NODE.NODE_NAME is '鑺傜偣鍚嶇О';
+comment on column WF_TASK_BACK_NODE.ORDER_NO is '鎺掑簭';
+comment on column WF_TASK_BACK_NODE.INSTANCE_ID is '娴佺▼瀹炰緥id';
+comment on column WF_TASK_BACK_NODE.TASK_TYPE is '鑺傜偣绫诲瀷';
+comment on column WF_TASK_BACK_NODE.ASSIGNEE is '瀹℃壒浜�';
+comment on column WF_TASK_BACK_NODE.TENANT_ID is '绉熸埛缂栧彿';
+comment on column WF_TASK_BACK_NODE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column WF_TASK_BACK_NODE.CREATE_BY is '鍒涘缓鑰�';
+comment on column WF_TASK_BACK_NODE.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column WF_TASK_BACK_NODE.UPDATE_BY is '鏇存柊鑰�';
+comment on column WF_TASK_BACK_NODE.UPDATE_TIME is '鏇存柊鏃堕棿';
+
+create table WF_DEFINITION_CONFIG
+(
+    ID            NUMBER(20) NOT NULL
+        CONSTRAINT PK_WF_DEFINITION_CONFIG
+        PRIMARY KEY,
+    TABLE_NAME    VARCHAR2(255) NOT NULL,
+    DEFINITION_ID VARCHAR2(255) NOT NULL,
+    PROCESS_KEY   VARCHAR2(255) NOT NULL,
+    VERSION       NUMBER(10)    NOT NULL,
+    REMARK        VARCHAR2(500),
+    TENANT_ID     VARCHAR2(20),
+    CREATE_DEPT   NUMBER(20),
+    CREATE_BY     NUMBER(20),
+    CREATE_TIME   DATE,
+    UPDATE_BY     NUMBER(20),
+    UPDATE_TIME   DATE,
+    constraint uni_definition_id
+        unique (definition_id)
+);
+comment on table WF_DEFINITION_CONFIG is '娴佺▼瀹氫箟閰嶇疆';
+comment on column WF_DEFINITION_CONFIG.ID is '涓婚敭';
+comment on column WF_DEFINITION_CONFIG.TABLE_NAME is '琛ㄥ悕';
+comment on column WF_DEFINITION_CONFIG.DEFINITION_ID is '娴佺▼瀹氫箟ID';
+comment on column WF_DEFINITION_CONFIG.PROCESS_KEY is '娴佺▼KEY';
+comment on column WF_DEFINITION_CONFIG.VERSION is '娴佺▼鐗堟湰';
+comment on column WF_DEFINITION_CONFIG.TENANT_ID is '绉熸埛缂栧彿';
+comment on column WF_DEFINITION_CONFIG.REMARK is '澶囨敞';
+comment on column WF_DEFINITION_CONFIG.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column WF_DEFINITION_CONFIG.CREATE_BY is '鍒涘缓鑰�';
+comment on column WF_DEFINITION_CONFIG.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column WF_DEFINITION_CONFIG.UPDATE_BY is '鏇存柊鑰�';
+comment on column WF_DEFINITION_CONFIG.UPDATE_TIME is '鏇存柊鏃堕棿';
+
+create table WF_FORM_MANAGE
+(
+    ID            NUMBER(20) NOT NULL
+        CONSTRAINT PK_WF_FORM_MANAGE
+        PRIMARY KEY,
+    FORM_NAME     VARCHAR2(255) NOT NULL,
+    FORM_TYPE     VARCHAR2(255) NOT NULL,
+    ROUTER        VARCHAR2(255) NOT NULL,
+    REMARK        VARCHAR2(500),
+    TENANT_ID     VARCHAR2(20),
+    CREATE_DEPT   NUMBER(20),
+    CREATE_BY     NUMBER(20),
+    CREATE_TIME   DATE,
+    UPDATE_BY     NUMBER(20),
+    UPDATE_TIME   DATE
+);
+
+comment on table WF_FORM_MANAGE is '琛ㄥ崟绠$悊';
+comment on column WF_FORM_MANAGE.ID is '涓婚敭';
+comment on column WF_FORM_MANAGE.FORM_NAME is '琛ㄥ崟鍚嶇О';
+comment on column WF_FORM_MANAGE.FORM_TYPE is '琛ㄥ崟绫诲瀷';
+comment on column WF_FORM_MANAGE.ROUTER is '璺敱鍦板潃/琛ㄥ崟ID';
+comment on column WF_FORM_MANAGE.REMARK is '澶囨敞';
+comment on column WF_FORM_MANAGE.TENANT_ID is '绉熸埛缂栧彿';
+comment on column WF_FORM_MANAGE.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column WF_FORM_MANAGE.CREATE_BY is '鍒涘缓鑰�';
+comment on column WF_FORM_MANAGE.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column WF_FORM_MANAGE.UPDATE_BY is '鏇存柊鑰�';
+comment on column WF_FORM_MANAGE.UPDATE_TIME is '鏇存柊鏃堕棿';
+
+insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, sysdate, 1, sysdate);
+
+create table WF_NODE_CONFIG
+(
+    ID               NUMBER(20) NOT NULL
+        CONSTRAINT PK_WF_NODE_CONFIG
+        PRIMARY KEY,
+    FORM_ID          NUMBER(20),
+    FORM_TYPE        VARCHAR2(255),
+    NODE_NAME        VARCHAR2(255) NOT NULL,
+    NODE_ID          VARCHAR2(255) NOT NULL,
+    DEFINITION_ID    VARCHAR2(255) NOT NULL,
+    APPLY_USER_TASK  CHAR(1) DEFAULT '0',
+    TENANT_ID        VARCHAR2(20),
+    CREATE_DEPT      NUMBER(20),
+    CREATE_BY        NUMBER(20),
+    CREATE_TIME      DATE,
+    UPDATE_BY        NUMBER(20),
+    UPDATE_TIME      DATE
+);
+
+comment on table WF_NODE_CONFIG is '鑺傜偣閰嶇疆';
+comment on column WF_NODE_CONFIG.ID is '涓婚敭';
+comment on column WF_NODE_CONFIG.FORM_ID is '琛ㄥ崟id';
+comment on column WF_NODE_CONFIG.FORM_TYPE is '琛ㄥ崟绫诲瀷';
+comment on column WF_NODE_CONFIG.NODE_ID is '鑺傜偣id';
+comment on column WF_NODE_CONFIG.NODE_NAME is '鑺傜偣鍚嶇О';
+comment on column WF_NODE_CONFIG.DEFINITION_ID is '娴佺▼瀹氫箟id';
+comment on column WF_NODE_CONFIG.APPLY_USER_TASK is '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級';
+comment on column WF_NODE_CONFIG.TENANT_ID is '绉熸埛缂栧彿';
+comment on column WF_NODE_CONFIG.CREATE_DEPT is '鍒涘缓閮ㄩ棬';
+comment on column WF_NODE_CONFIG.CREATE_BY is '鍒涘缓鑰�';
+comment on column WF_NODE_CONFIG.CREATE_TIME is '鍒涘缓鏃堕棿';
+comment on column WF_NODE_CONFIG.UPDATE_BY is '鏇存柊鑰�';
+comment on column WF_NODE_CONFIG.UPDATE_TIME is '鏇存柊鏃堕棿';
+
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate, NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate, NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate, NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate, NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate, NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate, NULL, NULL, '');
+
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, sysdate, NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, sysdate, NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate, NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,sysdate, NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate, NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,sysdate, NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate, NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate, NULL, NULL, '鍔ㄦ�佽〃鍗�');
+
+-- 琛ㄥ崟绠$悊 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, sysdate, null, null, '琛ㄥ崟绠$悊鑿滃崟');
+
+-- 琛ㄥ崟绠$悊鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, sysdate, null, null, '');
diff --git a/eims/script/sql/oracle/oracle_ry_vue_5.X.sql b/eims/script/sql/oracle/oracle_ry_vue_5.X.sql
new file mode 100644
index 0000000..0aed89d
--- /dev/null
+++ b/eims/script/sql/oracle/oracle_ry_vue_5.X.sql
@@ -0,0 +1,1364 @@
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+create table sys_social
+(
+    id                 number(20)        not null,
+    user_id            number(20)        not null,
+    tenant_id          varchar2(20)      default null,
+    auth_id            varchar2(255)     not null,
+    source             varchar2(255)     not null,
+    open_id            varchar2(255)     default null,
+    user_name          varchar2(30)      not null,
+    nick_name          varchar2(30)      default '',
+    email              varchar2(255)     default '',
+    avatar             varchar2(500)     default '',
+    access_token       varchar2(255)     not null,
+    expire_in          number(20)        default null,
+    refresh_token      varchar2(255)     default null,
+    access_code        varchar2(255)     default null,
+    union_id           varchar2(255)     default null,
+    scope              varchar2(255)     default null,
+    token_type         varchar2(255)     default null,
+    id_token           varchar2(2000)    default null,
+    mac_algorithm      varchar2(255)     default null,
+    mac_key            varchar2(255)     default null,
+    code               varchar2(255)     default null,
+    oauth_token        varchar2(255)     default null,
+    oauth_token_secret varchar2(255)     default null,
+    create_dept        number(20),
+    create_by          number(20),
+    create_time        date,
+    update_by          number(20),
+    update_time        date,
+    del_flag           char(1)          default '0'
+);
+
+alter table sys_social add constraint pk_sys_social primary key (id);
+
+comment on table   sys_social                   is '绀句細鍖栧叧绯昏〃';
+comment on column  sys_social.id                is '涓婚敭';
+comment on column  sys_social.user_id           is '鐢ㄦ埛ID';
+comment on column  sys_social.tenant_id         is '绉熸埛id';
+comment on column  sys_social.auth_id           is '骞冲彴+骞冲彴鍞竴id';
+comment on column  sys_social.source            is '鐢ㄦ埛鏉ユ簮';
+comment on column  sys_social.open_id           is '骞冲彴缂栧彿鍞竴id';
+comment on column  sys_social.user_name         is '鐧诲綍璐﹀彿';
+comment on column  sys_social.nick_name         is '鐢ㄦ埛鏄电О';
+comment on column  sys_social.email             is '鐢ㄦ埛閭';
+comment on column  sys_social.avatar            is '澶村儚鍦板潃';
+comment on column  sys_social.access_token      is '鐢ㄦ埛鐨勬巿鏉冧护鐗�';
+comment on column  sys_social.expire_in         is '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.refresh_token     is '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.access_code       is '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.union_id          is '鐢ㄦ埛鐨� unionid';
+comment on column  sys_social.scope             is '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.token_type        is '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.id_token          is 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.mac_algorithm     is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.mac_key           is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.code              is '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.oauth_token       is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.oauth_token_secret is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column  sys_social.create_by         is '鍒涘缓鑰�';
+comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
+comment on column  sys_social.update_by         is '鏇存柊鑰�';
+comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+-- ----------------------------
+-- 绉熸埛琛�
+-- ----------------------------
+create table sys_tenant (
+    id                number(20)    not null,
+    tenant_id         varchar2(20)  not null,
+    contact_user_name varchar2(20)  default '',
+    contact_phone     varchar2(20)  default '',
+    company_name      varchar2(50)  default '',
+    license_number    varchar2(30)  default '',
+    address           varchar2(200) default '',
+    intro             varchar2(200) default '',
+    domain            varchar2(200) default '',
+    remark            varchar2(200) default '',
+    package_id        number(20)    default null,
+    expire_time       date          default null,
+    account_count     number(4)     default -1,
+    status            char(1)       default '0',
+    del_flag          char(1)       default '0',
+    create_dept       number(20)    default null,
+    create_by         number(20)    default null,
+    create_time       date,
+    update_by         number(20)    default null,
+    update_time       date
+);
+
+alter table sys_tenant add constraint pk_sys_tenant primary key (id);
+
+comment on table   sys_tenant                    is '绉熸埛琛�';
+comment on column  sys_tenant.tenant_id          is '绉熸埛缂栧彿';
+comment on column  sys_tenant.contact_phone      is '鑱旂郴鐢佃瘽';
+comment on column  sys_tenant.company_name       is '浼佷笟鍚嶇О';
+comment on column  sys_tenant.company_name       is '鑱旂郴浜�';
+comment on column  sys_tenant.license_number     is '缁熶竴绀句細淇$敤浠g爜';
+comment on column  sys_tenant.address            is '鍦板潃';
+comment on column  sys_tenant.intro              is '浼佷笟绠�浠�';
+comment on column  sys_tenant.remark             is '澶囨敞';
+comment on column  sys_tenant.package_id         is '绉熸埛濂楅缂栧彿';
+comment on column  sys_tenant.expire_time        is '杩囨湡鏃堕棿';
+comment on column  sys_tenant.account_count      is '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級';
+comment on column  sys_tenant.status             is '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant.create_dept        is '鍒涘缓閮ㄩ棬';
+comment on column  sys_tenant.create_by          is '鍒涘缓鑰�';
+comment on column  sys_tenant.create_time        is '鍒涘缓鏃堕棿';
+comment on column  sys_tenant.update_by          is '鏇存柊鑰�';
+comment on column  sys_tenant.update_time        is '鏇存柊鏃堕棿';
+
+-- ----------------------------
+-- 鍒濆鍖�-绉熸埛琛ㄦ暟鎹�
+-- ----------------------------
+
+insert into sys_tenant values(1, '000000', '绠$悊缁�', '15888888888', 'XXX鏈夐檺鍏徃', null, null, '澶氱鎴烽�氱敤鍚庡彴绠$悊绠$悊绯荤粺', null, null, null, null, -1, '0', '0', 103, 1, sysdate, null, null);
+
+
+-- ----------------------------
+-- 绉熸埛濂楅琛�
+-- ----------------------------
+create table sys_tenant_package (
+    package_id              number(20)      not null,
+    package_name            varchar2(20)    default '',
+    menu_ids                varchar2(3000)  default '',
+    remark                  varchar2(200)   default '',
+    menu_check_strictly     number(1)       default 1,
+    status                  char(1)         default '0',
+    del_flag                char(1)         default '0',
+    create_dept             number(20)      default null,
+    create_by               number(20)      default null,
+    create_time             date,
+    update_by               number(20)      default null,
+    update_time             date
+);
+
+alter table sys_tenant_package add constraint pk_sys_tenant_package primary key (package_id);
+
+comment on table   sys_tenant_package                    is '绉熸埛濂楅琛�';
+comment on column  sys_tenant_package.package_id         is '绉熸埛濂楅id';
+comment on column  sys_tenant_package.package_name       is '濂楅鍚嶇О';
+comment on column  sys_tenant_package.menu_ids           is '鍏宠仈鑿滃崟id';
+comment on column  sys_tenant_package.remark             is '澶囨敞';
+comment on column  sys_tenant_package.status             is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant_package.create_dept        is '鍒涘缓閮ㄩ棬';
+comment on column  sys_tenant_package.create_by          is '鍒涘缓鑰�';
+comment on column  sys_tenant_package.create_time        is '鍒涘缓鏃堕棿';
+comment on column  sys_tenant_package.update_by          is '鏇存柊鑰�';
+comment on column  sys_tenant_package.update_time        is '鏇存柊鏃堕棿';
+
+
+-- ----------------------------
+-- 1銆侀儴闂ㄨ〃
+-- ----------------------------
+create table sys_dept (
+  dept_id           number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  parent_id         number(20)      default 0,
+  ancestors         varchar2(500)   default '',
+  dept_name         varchar2(30)    default '',
+  dept_category     varchar2(100)   default null,
+  order_num         number(4)       default 0,
+  leader            number(20)     default null,
+  phone             varchar2(11)    default null,
+  email             varchar2(50)    default null,
+  status            char(1)         default '0',
+  del_flag          char(1)         default '0',
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date
+);
+
+alter table sys_dept add constraint pk_sys_dept primary key (dept_id);
+
+comment on table  sys_dept              is '閮ㄩ棬琛�';
+comment on column sys_dept.dept_id      is '閮ㄩ棬id';
+comment on column sys_dept.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_dept.parent_id    is '鐖堕儴闂╥d';
+comment on column sys_dept.ancestors    is '绁栫骇鍒楄〃';
+comment on column sys_dept.dept_name    is '閮ㄩ棬鍚嶇О';
+comment on column sys_dept.dept_category is '閮ㄩ棬绫诲埆缂栫爜';
+comment on column sys_dept.order_num    is '鏄剧ず椤哄簭';
+comment on column sys_dept.leader       is '璐熻矗浜�';
+comment on column sys_dept.phone        is '鑱旂郴鐢佃瘽';
+comment on column sys_dept.email        is '閭';
+comment on column sys_dept.status       is '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_dept.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_dept.create_by    is '鍒涘缓鑰�';
+comment on column sys_dept.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_dept.update_by    is '鏇存柊鑰�';
+comment on column sys_dept.update_time  is '鏇存柊鏃堕棿';
+
+-- ----------------------------
+-- 鍒濆鍖�-閮ㄩ棬琛ㄦ暟鎹�
+-- ----------------------------
+
+insert into sys_dept values(100, '000000', 0,   '0',          'XXX绉戞妧',   null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(101, '000000', 100, '0,100',      '娣卞湷鎬诲叕鍙�', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(102, '000000', 100, '0,100',      '闀挎矙鍒嗗叕鍙�', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(103, '000000', 101, '0,100,101',  '鐮斿彂閮ㄩ棬',   null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(104, '000000', 101, '0,100,101',  '甯傚満閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(105, '000000', 101, '0,100,101',  '娴嬭瘯閮ㄩ棬',   null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(106, '000000', 101, '0,100,101',  '璐㈠姟閮ㄩ棬',   null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(107, '000000', 101, '0,100,101',  '杩愮淮閮ㄩ棬',   null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(108, '000000', 102, '0,100,102',  '甯傚満閮ㄩ棬',   null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+insert into sys_dept values(109, '000000', 102, '0,100,102',  '璐㈠姟閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null);
+
+
+-- ----------------------------
+-- 2銆佺敤鎴蜂俊鎭〃
+-- ----------------------------
+create table sys_user (
+  user_id           number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  dept_id           number(20)      default null,
+  user_name         varchar2(40)    not null,
+  nick_name         varchar2(40)    not null,
+  user_type         varchar2(10)    default 'sys_user',
+  email             varchar2(50)    default '',
+  phonenumber       varchar2(11)    default '',
+  sex               char(1)         default '0',
+  avatar            number(20)      default null,
+  password          varchar2(100)   default '',
+  status            char(1)         default '0',
+  del_flag          char(1)         default '0',
+  login_ip          varchar2(128)   default '',
+  login_date        date,
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date,
+  remark            varchar2(500)   default ''
+);
+
+alter table sys_user add constraint pk_sys_user primary key (user_id);
+
+comment on table  sys_user              is '鐢ㄦ埛淇℃伅琛�';
+comment on column sys_user.user_id      is '鐢ㄦ埛ID';
+comment on column sys_user.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_user.dept_id      is '閮ㄩ棬ID';
+comment on column sys_user.user_name    is '鐢ㄦ埛璐﹀彿';
+comment on column sys_user.nick_name    is '鐢ㄦ埛鏄电О';
+comment on column sys_user.user_type    is '鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�';
+comment on column sys_user.email        is '鐢ㄦ埛閭';
+comment on column sys_user.phonenumber  is '鎵嬫満鍙风爜';
+comment on column sys_user.sex          is '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�';
+comment on column sys_user.avatar       is '澶村儚璺緞';
+comment on column sys_user.password     is '瀵嗙爜';
+comment on column sys_user.status       is '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_user.login_ip     is '鏈�鍚庣櫥褰旾P';
+comment on column sys_user.login_date   is '鏈�鍚庣櫥褰曟椂闂�';
+comment on column sys_user.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_user.create_by    is '鍒涘缓鑰�';
+comment on column sys_user.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_user.update_by    is '鏇存柊鑰�';
+comment on column sys_user.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_user.remark       is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_user values(1, '000000', 103, 'admin', '鐤媯鐨勭嫯瀛怢i', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '绠$悊鍛�');
+insert into sys_user values(3, '000000', 108, 'test', '鏈儴闂ㄥ強浠ヤ笅 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '');
+insert into sys_user values(4, '000000', 102, 'test1', '浠呮湰浜� 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '');
+
+-- ----------------------------
+-- 3銆佸矖浣嶄俊鎭〃
+-- ----------------------------
+create table sys_post (
+  post_id           number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  dept_id           number(20)      not null,
+  post_code         varchar2(64)    not null,
+  post_category     varchar2(64)    default null,
+  post_name         varchar2(50)    not null,
+  post_sort         number(4)       not null,
+  status            char(1)         not null,
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date,
+  remark            varchar2(500)
+);
+
+alter table sys_post add constraint pk_sys_post primary key (post_id);
+
+comment on table  sys_post              is '宀椾綅淇℃伅琛�';
+comment on column sys_post.post_id      is '宀椾綅ID';
+comment on column sys_post.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_post.dept_id      is '閮ㄩ棬id';
+comment on column sys_post.post_code    is '宀椾綅缂栫爜';
+comment on column sys_post.post_category is '宀椾綅绫诲埆缂栫爜';
+comment on column sys_post.post_name    is '宀椾綅鍚嶇О';
+comment on column sys_post.post_sort    is '鏄剧ず椤哄簭';
+comment on column sys_post.status       is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_post.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_post.create_by    is '鍒涘缓鑰�';
+comment on column sys_post.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_post.update_by    is '鏇存柊鑰�';
+comment on column sys_post.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_post.remark       is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-宀椾綅淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_post values(1, '000000', 103, 'ceo',  null, '钁d簨闀�',    1, '0', 103, 1, sysdate, null, null, '');
+insert into sys_post values(2, '000000', 100, 'se',   null, '椤圭洰缁忕悊',  2, '0', 103, 1, sysdate, null, null, '');
+insert into sys_post values(3, '000000', 100, 'hr',   null, '浜哄姏璧勬簮',  3, '0', 103, 1, sysdate, null, null, '');
+insert into sys_post values(4, '000000', 100, 'user', null, '鏅�氬憳宸�',  4, '0', 103, 1, sysdate, null, null, '');
+
+
+-- ----------------------------
+-- 4銆佽鑹蹭俊鎭〃
+-- ----------------------------
+create table sys_role (
+  role_id              number(20)      not null,
+  tenant_id            varchar2(20)    default '000000',
+  role_name            varchar2(30)    not null,
+  role_key             varchar2(100)   not null,
+  role_sort            number(4)       not null,
+  data_scope           char(1)         default '1',
+  menu_check_strictly  number(1)       default 1,
+  dept_check_strictly  number(1)       default 1,
+  status               char(1)         not null,
+  del_flag             char(1)         default '0',
+  create_dept          number(20)      default null,
+  create_by            number(20)      default null,
+  create_time          date,
+  update_by            number(20)      default null,
+  update_time          date,
+  remark               varchar2(500)   default null
+);
+
+alter table sys_role add constraint pk_sys_role primary key (role_id);
+
+comment on table  sys_role                       is '瑙掕壊淇℃伅琛�';
+comment on column sys_role.role_id               is '瑙掕壊ID';
+comment on column sys_role.tenant_id             is '绉熸埛缂栧彿';
+comment on column sys_role.role_name             is '瑙掕壊鍚嶇О';
+comment on column sys_role.role_key              is '瑙掕壊鏉冮檺瀛楃涓�';
+comment on column sys_role.role_sort             is '鏄剧ず椤哄簭';
+comment on column sys_role.data_scope            is '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級';
+comment on column sys_role.menu_check_strictly   is '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+comment on column sys_role.dept_check_strictly   is '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+comment on column sys_role.status                is '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_role.del_flag              is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_role.create_dept           is '鍒涘缓閮ㄩ棬';
+comment on column sys_role.create_by             is '鍒涘缓鑰�';
+comment on column sys_role.create_time           is '鍒涘缓鏃堕棿';
+comment on column sys_role.update_by             is '鏇存柊鑰�';
+comment on column sys_role.update_time           is '鏇存柊鏃堕棿';
+comment on column sys_role.remark                is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_role values('1', '000000', '瓒呯骇绠$悊鍛�',  'superadmin',  1, 1, 1, 1, '0', '0', 103, 1, sysdate, null, null, '瓒呯骇绠$悊鍛�');
+insert into sys_role values('3', '000000', '鏈儴闂ㄥ強浠ヤ笅', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate, null, null, null);
+insert into sys_role values('4', '000000', '浠呮湰浜�',      'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate, null, null, null);
+
+-- ----------------------------
+-- 5銆佽彍鍗曟潈闄愯〃
+-- ----------------------------
+create table sys_menu (
+  menu_id           number(20)      not null,
+  menu_name         varchar2(50)    not null,
+  parent_id         number(20)      default 0,
+  order_num         number(4)       default 0,
+  path              varchar2(200)    default '',
+  component         varchar2(255)    default null,
+  query_param       varchar2(255)    default null,
+  is_frame          number(1)       default 1,
+  is_cache          number(1)       default 0,
+  menu_type         char(1)         default '',
+  visible           char(1)         default 0,
+  status            char(1)         default 0,
+  perms             varchar2(100)   default null,
+  icon              varchar2(100)   default '#',
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date ,
+  remark            varchar2(500)   default ''
+);
+
+alter table sys_menu add constraint pk_sys_menu primary key (menu_id);
+
+comment on table  sys_menu              is '鑿滃崟鏉冮檺琛�';
+comment on column sys_menu.menu_id      is '鑿滃崟ID';
+comment on column sys_menu.menu_name    is '鑿滃崟鍚嶇О';
+comment on column sys_menu.parent_id    is '鐖惰彍鍗旾D';
+comment on column sys_menu.order_num    is '鏄剧ず椤哄簭';
+comment on column sys_menu.path         is '璇锋眰鍦板潃';
+comment on column sys_menu.component    is '璺敱鍦板潃';
+comment on column sys_menu.query_param  is '璺敱鍙傛暟';
+comment on column sys_menu.is_frame     is '鏄惁涓哄閾撅紙0鏄� 1鍚︼級';
+comment on column sys_menu.is_cache     is '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級';
+comment on column sys_menu.menu_type    is '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�';
+comment on column sys_menu.visible      is '鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�';
+comment on column sys_menu.status       is '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_menu.perms        is '鏉冮檺鏍囪瘑';
+comment on column sys_menu.icon         is '鑿滃崟鍥炬爣';
+comment on column sys_menu.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_menu.create_by    is '鍒涘缓鑰�';
+comment on column sys_menu.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_menu.update_by    is '鏇存柊鑰�';
+comment on column sys_menu.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_menu.remark       is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-鑿滃崟淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+-- 涓�绾ц彍鍗�
+insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',           null, '', 1, 0, 'M', '0', '0', '', 'system',   103, 1, sysdate, null, null, '绯荤粺绠$悊鐩綍');
+insert into sys_menu values('6', '绉熸埛绠$悊', '0', '2', 'tenant',           null, '', 1, 0, 'M', '0', '0', '', 'chart',    103, 1, sysdate, null, null, '绉熸埛绠$悊鐩綍');
+insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '3', 'monitor',          null, '', 1, 0, 'M', '0', '0', '', 'monitor',  103, 1, sysdate, null, null, '绯荤粺鐩戞帶鐩綍');
+insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '4', 'tool',             null, '', 1, 0, 'M', '0', '0', '', 'tool',     103, 1, sysdate, null, null, '绯荤粺宸ュ叿鐩綍');
+insert into sys_menu values('4', 'PLUS瀹樼綉', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide',    103, 1, sysdate, null, null, 'RuoYi-Vue-Plus瀹樼綉鍦板潃');
+insert into sys_menu values('5', '娴嬭瘯鑿滃崟', '0', '5', 'demo',             null, '', 1, 0, 'M', '0', '0', null, 'star', 103, 1, sysdate, null, null, '');
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('100',  '鐢ㄦ埛绠$悊',     '1',   '1', 'user',             'system/user/index',            '', 1, 0, 'C', '0', '0', 'system:user:list',            'user',          103, 1, sysdate, null, null, '鐢ㄦ埛绠$悊鑿滃崟');
+insert into sys_menu values('101',  '瑙掕壊绠$悊',     '1',   '2', 'role',             'system/role/index',            '', 1, 0, 'C', '0', '0', 'system:role:list',            'peoples',       103, 1, sysdate, null, null, '瑙掕壊绠$悊鑿滃崟');
+insert into sys_menu values('102',  '鑿滃崟绠$悊',     '1',   '3', 'menu',             'system/menu/index',            '', 1, 0, 'C', '0', '0', 'system:menu:list',            'tree-table',    103, 1, sysdate, null, null, '鑿滃崟绠$悊鑿滃崟');
+insert into sys_menu values('103',  '閮ㄩ棬绠$悊',     '1',   '4', 'dept',             'system/dept/index',            '', 1, 0, 'C', '0', '0', 'system:dept:list',            'tree',          103, 1, sysdate, null, null, '閮ㄩ棬绠$悊鑿滃崟');
+insert into sys_menu values('104',  '宀椾綅绠$悊',     '1',   '5', 'post',             'system/post/index',            '', 1, 0, 'C', '0', '0', 'system:post:list',            'post',          103, 1, sysdate, null, null, '宀椾綅绠$悊鑿滃崟');
+insert into sys_menu values('105',  '瀛楀吀绠$悊',     '1',   '6', 'dict',             'system/dict/index',            '', 1, 0, 'C', '0', '0', 'system:dict:list',            'dict',          103, 1, sysdate, null, null, '瀛楀吀绠$悊鑿滃崟');
+insert into sys_menu values('106',  '鍙傛暟璁剧疆',     '1',   '7', 'config',           'system/config/index',          '', 1, 0, 'C', '0', '0', 'system:config:list',          'edit',          103, 1, sysdate, null, null, '鍙傛暟璁剧疆鑿滃崟');
+insert into sys_menu values('107',  '閫氱煡鍏憡',     '1',   '8', 'notice',           'system/notice/index',          '', 1, 0, 'C', '0', '0', 'system:notice:list',          'message',       103, 1, sysdate, null, null, '閫氱煡鍏憡鑿滃崟');
+insert into sys_menu values('108',  '鏃ュ織绠$悊',     '1',   '9', 'log',              '',                             '', 1, 0, 'M', '0', '0', '',                            'log',           103, 1, sysdate, null, null, '鏃ュ織绠$悊鑿滃崟');
+insert into sys_menu values('109',  '鍦ㄧ嚎鐢ㄦ埛',     '2',   '1', 'online',           'monitor/online/index',         '', 1, 0, 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, sysdate, null, null, '鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+insert into sys_menu values('113',  '缂撳瓨鐩戞帶',     '2',   '5', 'cache',            'monitor/cache/index',          '', 1, 0, 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, sysdate, null, null, '缂撳瓨鐩戞帶鑿滃崟');
+insert into sys_menu values('115',  '浠g爜鐢熸垚',     '3',   '2', 'gen',              'tool/gen/index',               '', 1, 0, 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, sysdate, null, null, '浠g爜鐢熸垚鑿滃崟');
+insert into sys_menu values('121',  '绉熸埛绠$悊',     '6',   '1', 'tenant',           'system/tenant/index',          '', 1, 0, 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, sysdate, null, null, '绉熸埛绠$悊鑿滃崟');
+insert into sys_menu values('122',  '绉熸埛濂楅绠$悊', '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, sysdate, null, null, '绉熸埛濂楅绠$悊鑿滃崟');
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', 1, 0, 'C', '0', '0', 'system:client:list',          'international', 103, 1, sysdate, null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+-- springboot-admin鐩戞帶
+insert into sys_menu values('117',  'Admin鐩戞帶',   '2',    '5', 'Admin',            'monitor/admin/index',         '', 1, 0, 'C', '0', '0', 'monitor:admin:list',          'dashboard',     103, 1, sysdate, null, null, 'Admin鐩戞帶鑿滃崟');
+-- oss鑿滃崟
+insert into sys_menu values('118',  '鏂囦欢绠$悊',     '1',    '10', 'oss',             'system/oss/index',            '', 1, 0, 'C', '0', '0', 'system:oss:list',             'upload',        103, 1, sysdate, null, null, '鏂囦欢绠$悊鑿滃崟');
+-- snail-job server鎺у埗鍙�
+insert into sys_menu values('120',  '浠诲姟璋冨害涓績',  '2',    '5', 'snailjob',           'monitor/snailjob/index',        '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job',           103, 1, sysdate, null, null, 'snailjob鎺у埗鍙拌彍鍗�');
+
+-- 涓夌骇鑿滃崟
+insert into sys_menu values('500',  '鎿嶄綔鏃ュ織', '108', '1', 'operlog',    'monitor/operlog/index',    '', 1, 0, 'C', '0', '0', 'monitor:operlog:list',    'form',          103, 1, sysdate, null, null, '鎿嶄綔鏃ュ織鑿滃崟');
+insert into sys_menu values('501',  '鐧诲綍鏃ュ織', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor',    103, 1, sysdate, null, null, '鐧诲綍鏃ュ織鑿滃崟');
+-- 鐢ㄦ埛绠$悊鎸夐挳
+insert into sys_menu values('1001', '鐢ㄦ埛鏌ヨ', '100', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1002', '鐢ㄦ埛鏂板', '100', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1003', '鐢ㄦ埛淇敼', '100', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1004', '鐢ㄦ埛鍒犻櫎', '100', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1005', '鐢ㄦ埛瀵煎嚭', '100', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:export',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1006', '鐢ㄦ埛瀵煎叆', '100', '6',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:import',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1007', '閲嶇疆瀵嗙爜', '100', '7',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd',       '#', 103, 1, sysdate, null, null, '');
+-- 瑙掕壊绠$悊鎸夐挳
+insert into sys_menu values('1008', '瑙掕壊鏌ヨ', '101', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1009', '瑙掕壊鏂板', '101', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1010', '瑙掕壊淇敼', '101', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1011', '瑙掕壊鍒犻櫎', '101', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1012', '瑙掕壊瀵煎嚭', '101', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:export',         '#', 103, 1, sysdate, null, null, '');
+-- 鑿滃崟绠$悊鎸夐挳
+insert into sys_menu values('1013', '鑿滃崟鏌ヨ', '102', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1014', '鑿滃崟鏂板', '102', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1015', '鑿滃崟淇敼', '102', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1016', '鑿滃崟鍒犻櫎', '102', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove',         '#', 103, 1, sysdate, null, null, '');
+-- 閮ㄩ棬绠$悊鎸夐挳
+insert into sys_menu values('1017', '閮ㄩ棬鏌ヨ', '103', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1018', '閮ㄩ棬鏂板', '103', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1019', '閮ㄩ棬淇敼', '103', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1020', '閮ㄩ棬鍒犻櫎', '103', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove',         '#', 103, 1, sysdate, null, null, '');
+-- 宀椾綅绠$悊鎸夐挳
+insert into sys_menu values('1021', '宀椾綅鏌ヨ', '104', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1022', '宀椾綅鏂板', '104', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1023', '宀椾綅淇敼', '104', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1024', '宀椾綅鍒犻櫎', '104', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1025', '宀椾綅瀵煎嚭', '104', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:export',         '#', 103, 1, sysdate, null, null, '');
+-- 瀛楀吀绠$悊鎸夐挳
+insert into sys_menu values('1026', '瀛楀吀鏌ヨ', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1027', '瀛楀吀鏂板', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1028', '瀛楀吀淇敼', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1029', '瀛楀吀鍒犻櫎', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1030', '瀛楀吀瀵煎嚭', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export',         '#', 103, 1, sysdate, null, null, '');
+-- 鍙傛暟璁剧疆鎸夐挳
+insert into sys_menu values('1031', '鍙傛暟鏌ヨ', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query',        '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1032', '鍙傛暟鏂板', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1033', '鍙傛暟淇敼', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1034', '鍙傛暟鍒犻櫎', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1035', '鍙傛暟瀵煎嚭', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export',       '#', 103, 1, sysdate, null, null, '');
+-- 閫氱煡鍏憡鎸夐挳
+insert into sys_menu values('1036', '鍏憡鏌ヨ', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query',        '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1037', '鍏憡鏂板', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1038', '鍏憡淇敼', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1039', '鍏憡鍒犻櫎', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove',       '#', 103, 1, sysdate, null, null, '');
+-- 鎿嶄綔鏃ュ織鎸夐挳
+insert into sys_menu values('1040', '鎿嶄綔鏌ヨ', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query',      '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1041', '鎿嶄綔鍒犻櫎', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove',     '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1042', '鏃ュ織瀵煎嚭', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export',     '#', 103, 1, sysdate, null, null, '');
+-- 鐧诲綍鏃ュ織鎸夐挳
+insert into sys_menu values('1043', '鐧诲綍鏌ヨ', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1044', '鐧诲綍鍒犻櫎', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove',  '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1045', '鏃ュ織瀵煎嚭', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export',  '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1050', '璐︽埛瑙i攣', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 103, 1, sysdate, null, null, '');
+-- 鍦ㄧ嚎鐢ㄦ埛鎸夐挳
+insert into sys_menu values('1046', '鍦ㄧ嚎鏌ヨ', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1047', '鎵归噺寮洪��', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1048', '鍗曟潯寮洪��', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate, null, null, '');
+-- 浠g爜鐢熸垚鎸夐挳
+insert into sys_menu values('1055', '鐢熸垚鏌ヨ', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query',             '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1056', '鐢熸垚淇敼', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit',              '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1057', '鐢熸垚鍒犻櫎', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1058', '瀵煎叆浠g爜', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import',            '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1059', '棰勮浠g爜', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview',           '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1060', '鐢熸垚浠g爜', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code',              '#', 103, 1, sysdate, null, null, '');
+-- oss鐩稿叧鎸夐挳
+insert into sys_menu values('1600', '鏂囦欢鏌ヨ', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query',        '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1601', '鏂囦欢涓婁紶', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1602', '鏂囦欢涓嬭浇', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download',     '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1603', '鏂囦欢鍒犻櫎', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add',    '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate, null, null, '');
+-- 绉熸埛绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values('1606', '绉熸埛鏌ヨ', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1607', '绉熸埛鏂板', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add',     '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1608', '绉熸埛淇敼', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit',    '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1609', '绉熸埛鍒犻櫎', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove',  '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1610', '绉熸埛瀵煎嚭', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export',  '#', 103, 1, sysdate, null, null, '');
+-- 绉熸埛濂楅绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values('1611', '绉熸埛濂楅鏌ヨ', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1612', '绉熸埛濂楅鏂板', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add',     '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1613', '绉熸埛濂楅淇敼', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit',    '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1614', '绉熸埛濂楅鍒犻櫎', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove',  '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1615', '绉熸埛濂楅瀵煎嚭', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export',  '#', 103, 1, sysdate, null, null, '');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query',        '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export',       '#', 103, 1, sysdate, null, null, '');
+-- 娴嬭瘯鑿滃崟
+insert into sys_menu values('1500', '娴嬭瘯鍗曡〃',     '5',   '1', 'demo', 'demo/demo/index', '',  1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate, null, null, '娴嬭瘯鍗曡〃鑿滃崟');
+insert into sys_menu values('1501', '娴嬭瘯鍗曡〃鏌ヨ', '1500', '1', '#', '', '',  1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1502', '娴嬭瘯鍗曡〃鏂板', '1500', '2', '#', '', '',  1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1503', '娴嬭瘯鍗曡〃淇敼', '1500', '3', '#', '', '',  1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1504', '娴嬭瘯鍗曡〃鍒犻櫎', '1500', '4', '#', '', '',  1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1505', '娴嬭瘯鍗曡〃瀵煎嚭', '1500', '5', '#', '', '',  1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1506', '娴嬭瘯鏍戣〃',     '5',   '1', 'tree', 'demo/tree/index', '',  1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate, null, null, '娴嬭瘯鏍戣〃鑿滃崟');
+insert into sys_menu values('1507', '娴嬭瘯鏍戣〃鏌ヨ', '1506', '1', '#', '', '',  1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1508', '娴嬭瘯鏍戣〃鏂板', '1506', '2', '#', '', '',  1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1509', '娴嬭瘯鏍戣〃淇敼', '1506', '3', '#', '', '',  1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1510', '娴嬭瘯鏍戣〃鍒犻櫎', '1506', '4', '#', '', '',  1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1511', '娴嬭瘯鏍戣〃瀵煎嚭', '1506', '5', '#', '', '',  1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate, null, null, '');
+
+
+-- ----------------------------
+-- 6銆佺敤鎴峰拰瑙掕壊鍏宠仈琛�  鐢ㄦ埛N-1瑙掕壊
+-- ----------------------------
+create table sys_user_role (
+  user_id  number(20)  not null,
+  role_id  number(20)  not null
+);
+
+alter table sys_user_role add constraint pk_sys_user_role primary key (user_id, role_id);
+
+comment on table  sys_user_role              is '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+comment on column sys_user_role.user_id      is '鐢ㄦ埛ID';
+comment on column sys_user_role.role_id      is '瑙掕壊ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛鍜岃鑹插叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_role values ('1', '1');
+insert into sys_user_role values ('3', '3');
+insert into sys_user_role values ('4', '4');
+
+-- ----------------------------
+-- 7銆佽鑹插拰鑿滃崟鍏宠仈琛�  瑙掕壊1-N鑿滃崟
+-- ----------------------------
+create table sys_role_menu (
+  role_id  number(20)  not null,
+  menu_id  number(20)  not null
+);
+
+alter table sys_role_menu add constraint pk_sys_role_menu primary key (role_id, menu_id);
+
+comment on table  sys_role_menu              is '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+comment on column sys_role_menu.role_id      is '瑙掕壊ID';
+comment on column sys_role_menu.menu_id      is '鑿滃崟ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_menu values ('3', '1');
+insert into sys_role_menu values ('3', '5');
+insert into sys_role_menu values ('3', '100');
+insert into sys_role_menu values ('3', '101');
+insert into sys_role_menu values ('3', '102');
+insert into sys_role_menu values ('3', '103');
+insert into sys_role_menu values ('3', '104');
+insert into sys_role_menu values ('3', '105');
+insert into sys_role_menu values ('3', '106');
+insert into sys_role_menu values ('3', '107');
+insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '500');
+insert into sys_role_menu values ('3', '501');
+insert into sys_role_menu values ('3', '1001');
+insert into sys_role_menu values ('3', '1002');
+insert into sys_role_menu values ('3', '1003');
+insert into sys_role_menu values ('3', '1004');
+insert into sys_role_menu values ('3', '1005');
+insert into sys_role_menu values ('3', '1006');
+insert into sys_role_menu values ('3', '1007');
+insert into sys_role_menu values ('3', '1008');
+insert into sys_role_menu values ('3', '1009');
+insert into sys_role_menu values ('3', '1010');
+insert into sys_role_menu values ('3', '1011');
+insert into sys_role_menu values ('3', '1012');
+insert into sys_role_menu values ('3', '1013');
+insert into sys_role_menu values ('3', '1014');
+insert into sys_role_menu values ('3', '1015');
+insert into sys_role_menu values ('3', '1016');
+insert into sys_role_menu values ('3', '1017');
+insert into sys_role_menu values ('3', '1018');
+insert into sys_role_menu values ('3', '1019');
+insert into sys_role_menu values ('3', '1020');
+insert into sys_role_menu values ('3', '1021');
+insert into sys_role_menu values ('3', '1022');
+insert into sys_role_menu values ('3', '1023');
+insert into sys_role_menu values ('3', '1024');
+insert into sys_role_menu values ('3', '1025');
+insert into sys_role_menu values ('3', '1026');
+insert into sys_role_menu values ('3', '1027');
+insert into sys_role_menu values ('3', '1028');
+insert into sys_role_menu values ('3', '1029');
+insert into sys_role_menu values ('3', '1030');
+insert into sys_role_menu values ('3', '1031');
+insert into sys_role_menu values ('3', '1032');
+insert into sys_role_menu values ('3', '1033');
+insert into sys_role_menu values ('3', '1034');
+insert into sys_role_menu values ('3', '1035');
+insert into sys_role_menu values ('3', '1036');
+insert into sys_role_menu values ('3', '1037');
+insert into sys_role_menu values ('3', '1038');
+insert into sys_role_menu values ('3', '1039');
+insert into sys_role_menu values ('3', '1040');
+insert into sys_role_menu values ('3', '1041');
+insert into sys_role_menu values ('3', '1042');
+insert into sys_role_menu values ('3', '1043');
+insert into sys_role_menu values ('3', '1044');
+insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1500');
+insert into sys_role_menu values ('3', '1501');
+insert into sys_role_menu values ('3', '1502');
+insert into sys_role_menu values ('3', '1503');
+insert into sys_role_menu values ('3', '1504');
+insert into sys_role_menu values ('3', '1505');
+insert into sys_role_menu values ('3', '1506');
+insert into sys_role_menu values ('3', '1507');
+insert into sys_role_menu values ('3', '1508');
+insert into sys_role_menu values ('3', '1509');
+insert into sys_role_menu values ('3', '1510');
+insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('4', '5');
+insert into sys_role_menu values ('4', '1500');
+insert into sys_role_menu values ('4', '1501');
+insert into sys_role_menu values ('4', '1502');
+insert into sys_role_menu values ('4', '1503');
+insert into sys_role_menu values ('4', '1504');
+insert into sys_role_menu values ('4', '1505');
+insert into sys_role_menu values ('4', '1506');
+insert into sys_role_menu values ('4', '1507');
+insert into sys_role_menu values ('4', '1508');
+insert into sys_role_menu values ('4', '1509');
+insert into sys_role_menu values ('4', '1510');
+insert into sys_role_menu values ('4', '1511');
+
+-- ----------------------------
+-- 8銆佽鑹插拰閮ㄩ棬鍏宠仈琛�  瑙掕壊1-N閮ㄩ棬
+-- ----------------------------
+create table sys_role_dept (
+  role_id  number(20)  not null,
+  dept_id  number(20)  not null
+);
+
+alter table sys_role_dept add constraint pk_sys_role_dept primary key (role_id, dept_id);
+
+comment on table  sys_role_dept              is '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+comment on column sys_role_dept.role_id      is '瑙掕壊ID';
+comment on column sys_role_dept.dept_id      is '閮ㄩ棬ID';
+
+
+-- ----------------------------
+-- 9銆佺敤鎴蜂笌宀椾綅鍏宠仈琛�  鐢ㄦ埛1-N宀椾綅
+-- ----------------------------
+create table sys_user_post (
+  user_id number(20)  not null,
+  post_id number(20)  not null
+);
+
+alter table sys_user_post add constraint pk_sys_user_post primary key (user_id, post_id);
+
+comment on table  sys_user_post              is '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+comment on column sys_user_post.user_id      is '鐢ㄦ埛ID';
+comment on column sys_user_post.post_id      is '宀椾綅ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_post values ('1', '1');
+
+-- ----------------------------
+-- 10銆佹搷浣滄棩蹇楄褰�
+-- ----------------------------
+create table sys_oper_log (
+  oper_id           number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  title             varchar2(50)    default '',
+  business_type     number(2)       default 0,
+  method            varchar2(100)   default '',
+  request_method    varchar2(10)     default '',
+  operator_type     number(1)       default 0,
+  oper_name         varchar2(50)    default '',
+  dept_name         varchar2(50)    default '',
+  oper_url          varchar2(255)   default '',
+  oper_ip           varchar2(128)   default '',
+  oper_location     varchar2(255)   default '',
+  oper_param        varchar2(2100)  default '',
+  json_result       varchar2(2100)  default '',
+  status            number(1)       default 0,
+  error_msg         varchar2(2100)  default '',
+  oper_time         date,
+  cost_time         number(20)      default 0
+);
+
+alter table sys_oper_log add constraint pk_sys_oper_log primary key (oper_id);
+create index idx_sys_oper_log_bt on sys_oper_log (business_type);
+create index idx_sys_oper_log_s on sys_oper_log (status);
+create index idx_sys_oper_log_ot on sys_oper_log (oper_time);
+
+comment on table  sys_oper_log                is '鎿嶄綔鏃ュ織璁板綍';
+comment on column sys_oper_log.oper_id        is '鏃ュ織涓婚敭';
+comment on column sys_oper_log.tenant_id      is '绉熸埛缂栧彿';
+comment on column sys_oper_log.title          is '妯″潡鏍囬';
+comment on column sys_oper_log.business_type  is '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�';
+comment on column sys_oper_log.method         is '鏂规硶鍚嶇О';
+comment on column sys_oper_log.request_method is '璇锋眰鏂瑰紡';
+comment on column sys_oper_log.operator_type  is '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級';
+comment on column sys_oper_log.oper_name      is '鎿嶄綔浜哄憳';
+comment on column sys_oper_log.dept_name      is '閮ㄩ棬鍚嶇О';
+comment on column sys_oper_log.oper_url       is '璇锋眰URL';
+comment on column sys_oper_log.oper_ip        is '涓绘満鍦板潃';
+comment on column sys_oper_log.oper_location  is '鎿嶄綔鍦扮偣';
+comment on column sys_oper_log.oper_param     is '璇锋眰鍙傛暟';
+comment on column sys_oper_log.json_result    is '杩斿洖鍙傛暟';
+comment on column sys_oper_log.status         is '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�';
+comment on column sys_oper_log.error_msg      is '閿欒娑堟伅';
+comment on column sys_oper_log.oper_time      is '鎿嶄綔鏃堕棿';
+comment on column sys_oper_log.cost_time      is '娑堣�楁椂闂�';
+
+
+-- ----------------------------
+-- 11銆佸瓧鍏哥被鍨嬭〃
+-- ----------------------------
+create table sys_dict_type (
+  dict_id           number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  dict_name         varchar2(100)   default '',
+  dict_type         varchar2(100)   default '',
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date,
+  remark            varchar2(500)   default null
+);
+
+alter table sys_dict_type add constraint pk_sys_dict_type primary key (dict_id);
+create unique index sys_dict_type_index1 on sys_dict_type (tenant_id, dict_type);
+
+comment on table  sys_dict_type               is '瀛楀吀绫诲瀷琛�';
+comment on column sys_dict_type.dict_id       is '瀛楀吀涓婚敭';
+comment on column sys_dict_type.tenant_id     is '绉熸埛缂栧彿';
+comment on column sys_dict_type.dict_name     is '瀛楀吀鍚嶇О';
+comment on column sys_dict_type.dict_type     is '瀛楀吀绫诲瀷';
+comment on column sys_dict_type.create_dept   is '鍒涘缓閮ㄩ棬';
+comment on column sys_dict_type.create_by     is '鍒涘缓鑰�';
+comment on column sys_dict_type.create_time   is '鍒涘缓鏃堕棿';
+comment on column sys_dict_type.update_by     is '鏇存柊鑰�';
+comment on column sys_dict_type.update_time   is '鏇存柊鏃堕棿';
+comment on column sys_dict_type.remark        is '澶囨敞';
+
+insert into sys_dict_type values(1, '000000', '鐢ㄦ埛鎬у埆', 'sys_user_sex',        103, 1, sysdate, null, null, '鐢ㄦ埛鎬у埆鍒楄〃');
+insert into sys_dict_type values(2, '000000', '鑿滃崟鐘舵��', 'sys_show_hide',       103, 1, sysdate, null, null, '鑿滃崟鐘舵�佸垪琛�');
+insert into sys_dict_type values(3, '000000', '绯荤粺寮�鍏�', 'sys_normal_disable',  103, 1, sysdate, null, null, '绯荤粺寮�鍏冲垪琛�');
+insert into sys_dict_type values(6, '000000', '绯荤粺鏄惁', 'sys_yes_no',          103, 1, sysdate, null, null, '绯荤粺鏄惁鍒楄〃');
+insert into sys_dict_type values(7, '000000', '閫氱煡绫诲瀷', 'sys_notice_type',     103, 1, sysdate, null, null, '閫氱煡绫诲瀷鍒楄〃');
+insert into sys_dict_type values(8, '000000', '閫氱煡鐘舵��', 'sys_notice_status',   103, 1, sysdate, null, null, '閫氱煡鐘舵�佸垪琛�');
+insert into sys_dict_type values(9, '000000', '鎿嶄綔绫诲瀷', 'sys_oper_type',       103, 1, sysdate, null, null, '鎿嶄綔绫诲瀷鍒楄〃');
+insert into sys_dict_type values(10, '000000', '绯荤粺鐘舵��', 'sys_common_status',  103, 1, sysdate, null, null, '鐧诲綍鐘舵�佸垪琛�');
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     103, 1, sysdate, null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    103, 1, sysdate, null, null, '瀹㈡埛绔澶囩被鍨�');
+
+
+-- ----------------------------
+-- 12銆佸瓧鍏告暟鎹〃
+-- ----------------------------
+create table sys_dict_data (
+  dict_code        number(20)      not null,
+  tenant_id        varchar2(20)    default '000000',
+  dict_sort        number(4)       default 0,
+  dict_label       varchar2(100)   default '',
+  dict_value       varchar2(100)   default '',
+  dict_type        varchar2(100)   default '',
+  css_class        varchar2(100)   default null,
+  list_class       varchar2(100)   default null,
+  is_default       char(1)         default 'N',
+  create_dept      number(20)      default null,
+  create_by        number(20)      default null,
+  create_time      date,
+  update_by        number(20)      default null,
+  update_time      date,
+  remark           varchar2(500)   default null
+);
+
+alter table sys_dict_data add constraint pk_sys_dict_data primary key (dict_code);
+
+comment on table  sys_dict_data               is '瀛楀吀鏁版嵁琛�';
+comment on column sys_dict_data.dict_code     is '瀛楀吀涓婚敭';
+comment on column sys_dict_data.tenant_id     is '绉熸埛缂栧彿';
+comment on column sys_dict_data.dict_sort     is '瀛楀吀鎺掑簭';
+comment on column sys_dict_data.dict_label    is '瀛楀吀鏍囩';
+comment on column sys_dict_data.dict_value    is '瀛楀吀閿��';
+comment on column sys_dict_data.dict_type     is '瀛楀吀绫诲瀷';
+comment on column sys_dict_data.css_class     is '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�';
+comment on column sys_dict_data.list_class    is '琛ㄦ牸鍥炴樉鏍峰紡';
+comment on column sys_dict_data.is_default    is '鏄惁榛樿锛圷鏄� N鍚︼級';
+comment on column sys_dict_data.create_dept   is '鍒涘缓閮ㄩ棬';
+comment on column sys_dict_data.create_by     is '鍒涘缓鑰�';
+comment on column sys_dict_data.create_time   is '鍒涘缓鏃堕棿';
+comment on column sys_dict_data.update_by     is '鏇存柊鑰�';
+comment on column sys_dict_data.update_time   is '鏇存柊鏃堕棿';
+comment on column sys_dict_data.remark        is '澶囨敞';
+
+insert into sys_dict_data values(1, '000000', 1,  '鐢�',       '0',       'sys_user_sex',        '',   '',        'Y', 103, 1, sysdate, null, null, '鎬у埆鐢�');
+insert into sys_dict_data values(2, '000000', 2,  '濂�',       '1',       'sys_user_sex',        '',   '',        'N', 103, 1, sysdate, null, null, '鎬у埆濂�');
+insert into sys_dict_data values(3, '000000', 3,  '鏈煡',     '2',       'sys_user_sex',        '',   '',        'N', 103, 1, sysdate, null, null, '鎬у埆鏈煡');
+insert into sys_dict_data values(4, '000000', 1,  '鏄剧ず',     '0',       'sys_show_hide',       '',   'primary', 'Y', 103, 1, sysdate, null, null, '鏄剧ず鑿滃崟');
+insert into sys_dict_data values(5, '000000', 2,  '闅愯棌',     '1',       'sys_show_hide',       '',   'danger',  'N', 103, 1, sysdate, null, null, '闅愯棌鑿滃崟');
+insert into sys_dict_data values(6, '000000', 1,  '姝e父',     '0',       'sys_normal_disable',  '',   'primary', 'Y', 103, 1, sysdate, null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(7, '000000', 2,  '鍋滅敤',     '1',       'sys_normal_disable',  '',   'danger',  'N', 103, 1, sysdate, null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(12, '000000', 1,  '鏄�',       'Y',       'sys_yes_no',          '',   'primary', 'Y', 103, 1, sysdate, null, null, '绯荤粺榛樿鏄�');
+insert into sys_dict_data values(13, '000000', 2,  '鍚�',       'N',       'sys_yes_no',          '',   'danger',  'N', 103, 1, sysdate, null, null, '绯荤粺榛樿鍚�');
+insert into sys_dict_data values(14, '000000', 1,  '閫氱煡',     '1',       'sys_notice_type',     '',   'warning', 'Y', 103, 1, sysdate, null, null, '閫氱煡');
+insert into sys_dict_data values(15, '000000', 2,  '鍏憡',     '2',       'sys_notice_type',     '',   'success', 'N', 103, 1, sysdate, null, null, '鍏憡');
+insert into sys_dict_data values(16, '000000', 1,  '姝e父',     '0',       'sys_notice_status',   '',   'primary', 'Y', 103, 1, sysdate, null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(17, '000000', 2,  '鍏抽棴',     '1',       'sys_notice_status',   '',   'danger',  'N', 103, 1, sysdate, null, null, '鍏抽棴鐘舵��');
+insert into sys_dict_data values(29, '000000', 99, '鍏朵粬',     '0',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate, null, null, '鍏朵粬鎿嶄綔');
+insert into sys_dict_data values(18, '000000', 1,  '鏂板',     '1',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate, null, null, '鏂板鎿嶄綔');
+insert into sys_dict_data values(19, '000000', 2,  '淇敼',     '2',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate, null, null, '淇敼鎿嶄綔');
+insert into sys_dict_data values(20, '000000', 3,  '鍒犻櫎',     '3',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate, null, null, '鍒犻櫎鎿嶄綔');
+insert into sys_dict_data values(21, '000000', 4,  '鎺堟潈',     '4',       'sys_oper_type',       '',   'primary', 'N', 103, 1, sysdate, null, null, '鎺堟潈鎿嶄綔');
+insert into sys_dict_data values(22, '000000', 5,  '瀵煎嚭',     '5',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate, null, null, '瀵煎嚭鎿嶄綔');
+insert into sys_dict_data values(23, '000000', 6,  '瀵煎叆',     '6',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate, null, null, '瀵煎叆鎿嶄綔');
+insert into sys_dict_data values(24, '000000', 7,  '寮洪��',     '7',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate, null, null, '寮洪��鎿嶄綔');
+insert into sys_dict_data values(25, '000000', 8,  '鐢熸垚浠g爜', '8',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate, null, null, '鐢熸垚鎿嶄綔');
+insert into sys_dict_data values(26, '000000', 9,  '娓呯┖鏁版嵁', '9',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate, null, null, '娓呯┖鎿嶄綔');
+insert into sys_dict_data values(27, '000000', 1,  '鎴愬姛',     '0',       'sys_common_status',   '',   'primary', 'N', 103, 1, sysdate, null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(28, '000000', 2,  '澶辫触',     '1',       'sys_common_status',   '',   'danger',  'N', 103, 1, sysdate, null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate, null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate, null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate, null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate, null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate, null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC',      'pc',          'sys_device_type',  '',   'default', 'N', 103, 1, sysdate, null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜',     'android',    'sys_device_type',  '',   'default', 'N', 103, 1, sysdate, null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS',     'ios',         'sys_device_type',  '',   'default', 'N', 103, 1, sysdate, null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�',     'xcx',      'sys_device_type',  '',   'default', 'N', 103, 1, sysdate, null, null, '灏忕▼搴�');
+
+
+-- ----------------------------
+-- 13銆佸弬鏁伴厤缃〃
+-- ----------------------------
+create table sys_config (
+  config_id         number(20)     not null,
+  tenant_id         varchar2(20)   default '000000',
+  config_name       varchar2(100)  default '',
+  config_key        varchar2(100)  default '',
+  config_value      varchar2(100)  default '',
+  config_type       char(1)        default 'N',
+  create_dept       number(20)     default null,
+  create_by         number(20)     default null,
+  create_time       date,
+  update_by         number(20)     default null,
+  update_time       date,
+  remark            varchar2(500)  default null
+);
+alter table sys_config add constraint pk_sys_config primary key (config_id);
+
+comment on table  sys_config               is '鍙傛暟閰嶇疆琛�';
+comment on column sys_config.config_id     is '鍙傛暟涓婚敭';
+comment on column sys_config.tenant_id     is '绉熸埛缂栧彿';
+comment on column sys_config.config_name   is '鍙傛暟鍚嶇О';
+comment on column sys_config.config_key    is '鍙傛暟閿悕';
+comment on column sys_config.config_value  is '鍙傛暟閿��';
+comment on column sys_config.config_type   is '绯荤粺鍐呯疆锛圷鏄� N鍚︼級';
+comment on column sys_config.create_dept   is '鍒涘缓閮ㄩ棬';
+comment on column sys_config.create_by     is '鍒涘缓鑰�';
+comment on column sys_config.create_time   is '鍒涘缓鏃堕棿';
+comment on column sys_config.update_by     is '鏇存柊鑰�';
+comment on column sys_config.update_time   is '鏇存柊鏃堕棿';
+comment on column sys_config.remark        is '澶囨敞';
+
+insert into sys_config values(1, '000000', '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О',      'sys.index.skinName',            'skin-blue',     'Y', 103, 1, sysdate, null, null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '000000', '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',         'sys.user.initPassword',         '123456',        'Y', 103, 1, sysdate, null, null, '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '000000', '涓绘鏋堕〉-渚ц竟鏍忎富棰�',           'sys.index.sideTheme',           'theme-dark',    'Y', 103, 1, sysdate, null, null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+insert into sys_config values(5, '000000', '璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�',   'sys.account.registerUser',      'false',         'Y', 103, 1, sysdate, null, null, '鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(11, '000000', 'OSS棰勮鍒楄〃璧勬簮寮�鍏�',          'sys.oss.previewListResource',   'true',          'Y', 103, 1, sysdate, null, null, 'true:寮�鍚�, false:鍏抽棴');
+
+
+-- ----------------------------
+-- 14銆佺郴缁熻闂褰�
+-- ----------------------------
+create table sys_logininfor (
+  info_id         number(20)     not null,
+  tenant_id       varchar2(20)   default '000000',
+  user_name       varchar2(50)   default '',
+  client_key      varchar2(32)   default '',
+  device_type     varchar2(32)   default '',
+  ipaddr          varchar2(128)  default '',
+  login_location  varchar2(255)  default '',
+  browser         varchar2(50)   default '',
+  os              varchar2(50)   default '',
+  status          char(1)        default '0',
+  msg             varchar2(255)  default '',
+  login_time      date
+);
+
+alter table sys_logininfor add constraint pk_sys_logininfor primary key (info_id);
+create index idx_sys_logininfor_s on sys_logininfor (status);
+create index idx_sys_logininfor_lt on sys_logininfor (login_time);
+
+comment on table  sys_logininfor                is '绯荤粺璁块棶璁板綍';
+comment on column sys_logininfor.info_id        is '璁块棶ID';
+comment on column sys_logininfor.tenant_id      is '绉熸埛缂栧彿';
+comment on column sys_logininfor.user_name      is '鐧诲綍璐﹀彿';
+comment on column sys_logininfor.client_key     is '瀹㈡埛绔�';
+comment on column sys_logininfor.device_type    is '璁惧绫诲瀷';
+comment on column sys_logininfor.ipaddr         is '鐧诲綍IP鍦板潃';
+comment on column sys_logininfor.login_location is '鐧诲綍鍦扮偣';
+comment on column sys_logininfor.browser        is '娴忚鍣ㄧ被鍨�';
+comment on column sys_logininfor.os             is '鎿嶄綔绯荤粺';
+comment on column sys_logininfor.status         is '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�';
+comment on column sys_logininfor.msg            is '鎻愮ず娑堟伅';
+comment on column sys_logininfor.login_time     is '璁块棶鏃堕棿';
+
+
+-- ----------------------------
+-- 17銆侀�氱煡鍏憡琛�
+-- ----------------------------
+create table sys_notice (
+  notice_id         number(20)      not null,
+  tenant_id         varchar2(20)    default '000000',
+  notice_title      varchar2(50)    not null,
+  notice_type       char(1)         not null,
+  notice_content    clob            default null,
+  status            char(1)         default '0',
+  create_dept       number(20)      default null,
+  create_by         number(20)      default null,
+  create_time       date,
+  update_by         number(20)      default null,
+  update_time       date,
+  remark            varchar2(255)   default null
+);
+
+alter table sys_notice add constraint pk_sys_notice primary key (notice_id);
+
+comment on table  sys_notice                   is '閫氱煡鍏憡琛�';
+comment on column sys_notice.notice_id         is '鍏憡涓婚敭';
+comment on column sys_notice.tenant_id         is '绉熸埛缂栧彿';
+comment on column sys_notice.notice_title      is '鍏憡鏍囬';
+comment on column sys_notice.notice_type       is '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�';
+comment on column sys_notice.notice_content    is '鍏憡鍐呭';
+comment on column sys_notice.status            is '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�';
+comment on column sys_notice.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column sys_notice.create_by         is '鍒涘缓鑰�';
+comment on column sys_notice.create_time       is '鍒涘缓鏃堕棿';
+comment on column sys_notice.update_by         is '鏇存柊鑰�';
+comment on column sys_notice.update_time       is '鏇存柊鏃堕棿';
+comment on column sys_notice.remark            is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-鍏憡淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_notice values('1', '000000', '娓╅Θ鎻愰啋锛�2018-07-01 鏂扮増鏈彂甯冨暒', '2', '鏂扮増鏈唴瀹�', '0', 103, 1, sysdate, null, null, '绠$悊鍛�');
+insert into sys_notice values('2', '000000', '缁存姢閫氱煡锛�2018-07-01 绯荤粺鍑屾櫒缁存姢', '1', '缁存姢鍐呭',   '0', 103, 1, sysdate, null, null, '绠$悊鍛�');
+
+
+-- ----------------------------
+-- 18銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+create table gen_table (
+  table_id          number(20)       not null,
+  data_name         varchar2(200)    default '',
+  table_name        varchar2(200)    default '',
+  table_comment     varchar2(500)    default '',
+  sub_table_name    varchar2(64)     default null,
+  sub_table_fk_name varchar2(64)     default null,
+  class_name        varchar2(100)    default '',
+  tpl_category      varchar2(200)    default 'crud',
+  package_name      varchar2(100),
+  module_name       varchar2(30),
+  business_name     varchar2(30),
+  function_name     varchar2(50),
+  function_author   varchar2(50),
+  gen_type          char(1)          default '0',
+  gen_path          varchar2(200)    default '/',
+  options           varchar2(1000),
+  create_dept       number(20)       default null,
+  create_by         number(20)       default null,
+  create_time       date,
+  update_by         number(20)       default null,
+  update_time       date,
+  remark            varchar2(500)    default null
+);
+
+alter table gen_table add constraint pk_gen_table primary key (table_id);
+
+comment on table  gen_table                   is '浠g爜鐢熸垚涓氬姟琛�';
+comment on column gen_table.table_id          is '缂栧彿';
+comment on column gen_table.data_name         is '鏁版嵁婧愬悕绉�';
+comment on column gen_table.table_name        is '琛ㄥ悕绉�';
+comment on column gen_table.table_comment     is '琛ㄦ弿杩�';
+comment on column gen_table.sub_table_name    is '鍏宠仈瀛愯〃鐨勮〃鍚�';
+comment on column gen_table.sub_table_fk_name is '瀛愯〃鍏宠仈鐨勫閿悕';
+comment on column gen_table.class_name        is '瀹炰綋绫诲悕绉�';
+comment on column gen_table.tpl_category      is '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�';
+comment on column gen_table.package_name      is '鐢熸垚鍖呰矾寰�';
+comment on column gen_table.module_name       is '鐢熸垚妯″潡鍚�';
+comment on column gen_table.business_name     is '鐢熸垚涓氬姟鍚�';
+comment on column gen_table.function_name     is '鐢熸垚鍔熻兘鍚�';
+comment on column gen_table.function_author   is '鐢熸垚鍔熻兘浣滆��';
+comment on column gen_table.gen_type          is '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級';
+comment on column gen_table.gen_path          is '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級';
+comment on column gen_table.options           is '鍏跺畠鐢熸垚閫夐」';
+comment on column gen_table.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column gen_table.create_by         is '鍒涘缓鑰�';
+comment on column gen_table.create_time       is '鍒涘缓鏃堕棿';
+comment on column gen_table.update_by         is '鏇存柊鑰�';
+comment on column gen_table.update_time       is '鏇存柊鏃堕棿';
+comment on column gen_table.remark            is '澶囨敞';
+
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+create table gen_table_column (
+  column_id         number(20)      not null,
+  table_id          number(20),
+  column_name       varchar2(200),
+  column_comment    varchar2(500),
+  column_type       varchar2(100),
+  java_type         varchar2(500),
+  java_field        varchar2(200),
+  is_pk             char(1),
+  is_increment      char(1),
+  is_required       char(1),
+  is_insert         char(1),
+  is_edit           char(1),
+  is_list           char(1),
+  is_query          char(1),
+  query_type        varchar2(200)    default 'EQ',
+  html_type         varchar2(200),
+  dict_type         varchar2(200)    default '',
+  sort              number(4),
+  create_dept       number(20)       default null,
+  create_by         number(20)       default null,
+  create_time       date ,
+  update_by         number(20)       default null,
+  update_time       date
+);
+
+alter table gen_table_column add constraint pk_gen_table_column primary key (column_id);
+
+comment on table  gen_table_column                is '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
+comment on column gen_table_column.column_id      is '缂栧彿';
+comment on column gen_table_column.table_id       is '褰掑睘琛ㄧ紪鍙�';
+comment on column gen_table_column.column_name    is '鍒楀悕绉�';
+comment on column gen_table_column.column_comment is '鍒楁弿杩�';
+comment on column gen_table_column.column_type    is '鍒楃被鍨�';
+comment on column gen_table_column.java_type      is 'JAVA绫诲瀷';
+comment on column gen_table_column.java_field     is 'JAVA瀛楁鍚�';
+comment on column gen_table_column.is_pk          is '鏄惁涓婚敭锛�1鏄級';
+comment on column gen_table_column.is_increment   is '鏄惁鑷锛�1鏄級';
+comment on column gen_table_column.is_required    is '鏄惁蹇呭~锛�1鏄級';
+comment on column gen_table_column.is_insert      is '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級';
+comment on column gen_table_column.is_edit        is '鏄惁缂栬緫瀛楁锛�1鏄級';
+comment on column gen_table_column.is_list        is '鏄惁鍒楄〃瀛楁锛�1鏄級';
+comment on column gen_table_column.is_query       is '鏄惁鏌ヨ瀛楁锛�1鏄級';
+comment on column gen_table_column.query_type     is '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級';
+comment on column gen_table_column.html_type      is '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級';
+comment on column gen_table_column.dict_type      is '瀛楀吀绫诲瀷';
+comment on column gen_table_column.sort           is '鎺掑簭';
+comment on column gen_table_column.create_dept    is '鍒涘缓閮ㄩ棬';
+comment on column gen_table_column.create_by      is '鍒涘缓鑰�';
+comment on column gen_table_column.create_time    is '鍒涘缓鏃堕棿';
+comment on column gen_table_column.update_by      is '鏇存柊鑰�';
+comment on column gen_table_column.update_time    is '鏇存柊鏃堕棿';
+
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍琛�
+-- ----------------------------
+create table sys_oss (
+  oss_id          number(20)     not null,
+  tenant_id       varchar2(20)   default '000000',
+  file_name       varchar2(255)  not null,
+  original_name   varchar2(255)  not null,
+  file_suffix     varchar2(10)   not null,
+  url             varchar2(500)  not null,
+  service         varchar2(20)   default 'minio' not null,
+  create_dept     number(20)     default null,
+  create_by       number(20)     default null,
+  create_time     date,
+  update_by       number(20)     default null,
+  update_time     date
+);
+
+alter table sys_oss add constraint pk_sys_oss primary key (oss_id);
+
+comment on table sys_oss                    is 'OSS瀵硅薄瀛樺偍琛�';
+comment on column sys_oss.oss_id            is '瀵硅薄瀛樺偍涓婚敭';
+comment on column sys_oss.tenant_id         is '绉熸埛缂栫爜';
+comment on column sys_oss.file_name         is '鏂囦欢鍚�';
+comment on column sys_oss.original_name     is '鍘熷悕';
+comment on column sys_oss.file_suffix       is '鏂囦欢鍚庣紑鍚�';
+comment on column sys_oss.url               is 'URL鍦板潃';
+comment on column sys_oss.service           is '鏈嶅姟鍟�';
+comment on column sys_oss.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column sys_oss.create_time       is '鍒涘缓鏃堕棿';
+comment on column sys_oss.create_by         is '涓婁紶鑰�';
+comment on column sys_oss.update_time       is '鏇存柊鏃堕棿';
+comment on column sys_oss.update_by         is '鏇存柊鑰�';
+
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍鍔ㄦ�侀厤缃〃
+-- ----------------------------
+create table sys_oss_config (
+  oss_config_id   number(20)     not null,
+  tenant_id       varchar2(20)   default '000000',
+  config_key      varchar2(20)   not null,
+  access_key      varchar2(255)  default '',
+  secret_key      varchar2(255)  default '',
+  bucket_name     varchar2(255)  default '',
+  prefix          varchar2(255)  default '',
+  endpoint        varchar2(255)  default '',
+  domain          varchar2(255)  default '',
+  is_https        char(1)        default 'N',
+  region          varchar2(255)  default '',
+  access_policy   char(1)        default '1' not null,
+  status          char(1)        default '1',
+  ext1            varchar2(255)  default '',
+  remark          varchar2(500)  default null,
+  create_dept     number(20)     default null,
+  create_by       number(20)     default null,
+  create_time     date,
+  update_by       number(20)     default null,
+  update_time     date
+);
+
+alter table sys_oss_config add constraint pk_sys_oss_config primary key (oss_config_id);
+
+comment on table sys_oss_config                 is '瀵硅薄瀛樺偍閰嶇疆琛�';
+comment on column sys_oss_config.oss_config_id  is '涓婚敭';
+comment on column sys_oss_config.tenant_id      is '绉熸埛缂栫爜';
+comment on column sys_oss_config.config_key     is '閰嶇疆key';
+comment on column sys_oss_config.access_key     is 'accesskey';
+comment on column sys_oss_config.secret_key     is '绉橀挜';
+comment on column sys_oss_config.bucket_name    is '妗跺悕绉�';
+comment on column sys_oss_config.prefix         is '鍓嶇紑';
+comment on column sys_oss_config.endpoint       is '璁块棶绔欑偣';
+comment on column sys_oss_config.domain         is '鑷畾涔夊煙鍚�';
+comment on column sys_oss_config.is_https       is '鏄惁https锛圷=鏄�,N=鍚︼級';
+comment on column sys_oss_config.region         is '鍩�';
+comment on column sys_oss_config.access_policy  is '妗舵潈闄愮被鍨�(0=private 1=public 2=custom)';
+comment on column sys_oss_config.status         is '鏄惁榛樿锛�0=鏄�,1=鍚︼級';
+comment on column sys_oss_config.ext1           is '鎵╁睍瀛楁';
+comment on column sys_oss_config.remark         is '澶囨敞';
+comment on column sys_oss_config.create_dept    is '鍒涘缓閮ㄩ棬';
+comment on column sys_oss_config.create_by      is '鍒涘缓鑰�';
+comment on column sys_oss_config.create_time    is '鍒涘缓鏃堕棿';
+comment on column sys_oss_config.update_by      is '鏇存柊鑰�';
+comment on column sys_oss_config.update_time    is '鏇存柊鏃堕棿';
+
+insert into sys_oss_config values (1, '000000', 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', '127.0.0.1:9000',                '','N', '',            '1', '0', '', NULL, 103, 1, sysdate, 1, sysdate);
+insert into sys_oss_config values (2, '000000', 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 's3-cn-north-1.qiniucs.com',     '','N', '',            '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate);
+insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'oss-cn-beijing.aliyuncs.com',   '','N', '',            '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate);
+insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'cos.ap-beijing.myqcloud.com',   '','N', 'ap-beijing',  '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate);
+insert into sys_oss_config values (5, '000000', 'image',  'ruoyi',            'ruoyi123',        'ruoyi',             'image', '127.0.0.1:9000',           '','N', '',            '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate);
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+create table sys_client (
+    id                  number(20)     not null,
+    client_id           varchar2(64)   default null,
+    client_key          varchar2(32)   default null,
+    client_secret       varchar2(255)  default null,
+    grant_type          varchar2(255)  default null,
+    device_type         varchar2(32)   default null,
+    active_timeout      number(11)     default 1800,
+    timeout             number(11)     default 604800,
+    status              char(1)        default '0',
+    del_flag            char(1)        default '0',
+    create_dept         number(20)     default null,
+    create_by           number(20)     default null,
+    create_time         date,
+    update_by           number(20)     default null,
+    update_time         date
+);
+
+alter table sys_client add constraint pk_sys_client primary key (id);
+
+comment on table sys_client                         is '绯荤粺鎺堟潈琛�';
+comment on column sys_client.id                     is '涓婚敭';
+comment on column sys_client.client_id              is '瀹㈡埛绔痠d';
+comment on column sys_client.client_key             is '瀹㈡埛绔痥ey';
+comment on column sys_client.client_secret          is '瀹㈡埛绔閽�';
+comment on column sys_client.grant_type             is '鎺堟潈绫诲瀷';
+comment on column sys_client.device_type            is '璁惧绫诲瀷';
+comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
+comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
+comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
+comment on column sys_client.create_by              is '鍒涘缓鑰�';
+comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
+comment on column sys_client.update_by              is '鏇存柊鑰�';
+comment on column sys_client.update_time            is '鏇存柊鏃堕棿';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate);
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate);
+
+create table test_demo (
+    id          number(20)      not null,
+    tenant_id   varchar2(20)    default '000000',
+    dept_id     number(20)      default null,
+    user_id     number(20)      default null,
+    order_num   number(10)      default 0,
+    test_key    varchar2(255)   default null,
+    value       varchar2(255)   default null,
+    version     number(10)      default 0,
+    create_dept number(20)      default null,
+    create_time date,
+    create_by   number(20)      default null,
+    update_time date,
+    update_by   number(20)      default null,
+    del_flag    number(2)       default 0
+);
+
+alter table test_demo add constraint pk_test_demo primary key (id);
+
+comment on table  test_demo              is '娴嬭瘯鍗曡〃';
+comment on column test_demo.id           is '涓婚敭';
+comment on column test_demo.tenant_id    is '绉熸埛缂栧彿';
+comment on column test_demo.dept_id      is '閮ㄩ棬id';
+comment on column test_demo.user_id      is '鐢ㄦ埛id';
+comment on column test_demo.order_num    is '鎺掑簭鍙�';
+comment on column test_demo.test_key     is 'key閿�';
+comment on column test_demo.value        is '鍊�';
+comment on column test_demo.version      is '鐗堟湰';
+comment on column test_demo.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column test_demo.create_time  is '鍒涘缓鏃堕棿';
+comment on column test_demo.create_by    is '鍒涘缓浜�';
+comment on column test_demo.update_time  is '鏇存柊鏃堕棿';
+comment on column test_demo.update_by    is '鏇存柊浜�';
+comment on column test_demo.del_flag     is '鍒犻櫎鏍囧織';
+
+create table test_tree (
+    id          number(20)      not null,
+    tenant_id   varchar2(20)    default '000000',
+    parent_id   number(20)      default 0,
+    dept_id     number(20)      default null,
+    user_id     number(20)      default null,
+    tree_name   varchar2(255)   default null,
+    version     number(10)      default 0,
+    create_dept number(20)      default null,
+    create_time date,
+    create_by   number(20)      default null,
+    update_time date,
+    update_by   number(20)      default null,
+    del_flag    number(2)       default 0
+);
+
+alter table test_tree add constraint pk_test_tree primary key (id);
+
+comment on table  test_tree              is '娴嬭瘯鏍戣〃';
+comment on column test_tree.id           is '涓婚敭';
+comment on column test_tree.tenant_id    is '绉熸埛缂栧彿';
+comment on column test_tree.parent_id    is '鐖秈d';
+comment on column test_tree.dept_id      is '閮ㄩ棬id';
+comment on column test_tree.user_id      is '鐢ㄦ埛id';
+comment on column test_tree.tree_name    is '鍊�';
+comment on column test_tree.version      is '鐗堟湰';
+comment on column test_tree.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column test_tree.create_time  is '鍒涘缓鏃堕棿';
+comment on column test_tree.create_by    is '鍒涘缓浜�';
+comment on column test_tree.update_time  is '鏇存柊鏃堕棿';
+comment on column test_tree.update_by    is '鏇存柊浜�';
+comment on column test_tree.del_flag     is '鍒犻櫎鏍囧織';
+
+insert into test_demo values (1, '000000', 102, 4, 1, '娴嬭瘯鏁版嵁鏉冮檺', '娴嬭瘯', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (2, '000000', 102, 3, 2, '瀛愯妭鐐�1', '111', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (3, '000000', 102, 3, 3, '瀛愯妭鐐�2', '222', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (4, '000000', 108, 4, 4, '娴嬭瘯鏁版嵁', 'demo', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (5, '000000', 108, 3, 13, '瀛愯妭鐐�11', '1111', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (6, '000000', 108, 3, 12, '瀛愯妭鐐�22', '2222', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (7, '000000', 108, 3, 11, '瀛愯妭鐐�33', '3333', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (8, '000000', 108, 3, 10, '瀛愯妭鐐�44', '4444', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (9, '000000', 108, 3, 9, '瀛愯妭鐐�55', '5555', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (10, '000000', 108, 3, 8, '瀛愯妭鐐�66', '6666', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (11, '000000', 108, 3, 7, '瀛愯妭鐐�77', '7777', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (12, '000000', 108, 3, 6, '瀛愯妭鐐�88', '8888', 0, 103, sysdate, 1, null, null, 0);
+insert into test_demo values (13, '000000', 108, 3, 5, '瀛愯妭鐐�99', '9999', 0, 103, sysdate, 1, null, null, 0);
+
+insert into test_tree values (1, '000000', 0, 102, 4, '娴嬭瘯鏁版嵁鏉冮檺', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (2, '000000', 1, 102, 3, '瀛愯妭鐐�1', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (3, '000000', 2, 102, 3, '瀛愯妭鐐�2', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (4, '000000', 0, 108, 4, '娴嬭瘯鏍�1', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (5, '000000', 4, 108, 3, '瀛愯妭鐐�11', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (6, '000000', 4, 108, 3, '瀛愯妭鐐�22', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (7, '000000', 4, 108, 3, '瀛愯妭鐐�33', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (8, '000000', 5, 108, 3, '瀛愯妭鐐�44', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (9, '000000', 6, 108, 3, '瀛愯妭鐐�55', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (10, '000000', 7, 108, 3, '瀛愯妭鐐�66', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (11, '000000', 7, 108, 3, '瀛愯妭鐐�77', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (12, '000000', 10, 108, 3, '瀛愯妭鐐�88', 0, 103, sysdate, 1, null, null, 0);
+insert into test_tree values (13, '000000', 10, 108, 3, '瀛愯妭鐐�99', 0, 103, sysdate, 1, null, null, 0);
+
+
+-- ----------------------------
+-- 閽╁瓙 锛岀敤浜巗ession杩炴帴涔嬪悗 鑷姩璁剧疆榛樿鐨刣ate绫诲瀷鏍煎紡鍖� 绠�鍖栨椂闂存煡璇�
+-- 濡傞渶璁剧疆鍏跺畠閰嶇疆 鍙湪姝ら挬瀛愬唴浠绘剰澧炲姞澶勭悊璇彞
+-- 渚嬪锛� SELECT * FROM sys_user WHERE create_time BETWEEN '2022-03-01 00:00:00' AND '2022-04-01 00:00:00'
+-- ----------------------------
+create or replace trigger login_trg
+after logon on database
+begin
+execute immediate 'alter session set nls_date_format=''YYYY-MM-DD HH24:MI:SS''';
+end;
diff --git a/eims/script/sql/oracle/snail_job_oracle.sql b/eims/script/sql/oracle/snail_job_oracle.sql
new file mode 100644
index 0000000..d2e17c1
--- /dev/null
+++ b/eims/script/sql/oracle/snail_job_oracle.sql
@@ -0,0 +1,905 @@
+/*
+ SnailJob Database Transfer Tool
+ Source Server Type    : MySQL
+ Target Server Type    : Oracle
+ Date: 2024-07-06 12:49:36
+*/
+
+
+-- sj_namespace
+CREATE TABLE sj_namespace
+(
+    id          number GENERATED ALWAYS AS IDENTITY,
+    name        varchar2(64)                            NULL,
+    unique_id   varchar2(64)                            NULL,
+    description varchar2(256) DEFAULT ''                NULL,
+    deleted     smallint      DEFAULT 0                 NOT NULL,
+    create_dt   date          DEFAULT CURRENT_TIMESTAMP NOT NULL,
+    update_dt   date          DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+ALTER TABLE sj_namespace
+    ADD CONSTRAINT pk_sj_namespace PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name);
+
+COMMENT ON COLUMN sj_namespace.id IS '涓婚敭';
+COMMENT ON COLUMN sj_namespace.name IS '鍚嶇О';
+COMMENT ON COLUMN sj_namespace.unique_id IS '鍞竴id';
+COMMENT ON COLUMN sj_namespace.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_namespace.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_namespace.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_namespace.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_namespace IS '鍛藉悕绌洪棿';
+
+INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Development', 'dev', '', 0, sysdate, sysdate);
+INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Production', 'prod', '', 0, sysdate, sysdate);
+
+-- sj_group_config
+CREATE TABLE sj_group_config
+(
+    id                number GENERATED ALWAYS AS IDENTITY,
+    namespace_id      varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a'    NULL,
+    group_name        varchar2(64)  DEFAULT ''                                    NULL,
+    description       varchar2(256) DEFAULT ''                                    NULL,
+    token             varchar2(64)  DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' NULL,
+    group_status      smallint      DEFAULT 0                                     NOT NULL,
+    version           number                                                      NOT NULL,
+    group_partition   number                                                      NOT NULL,
+    id_generator_mode smallint      DEFAULT 1                                     NOT NULL,
+    init_scene        smallint      DEFAULT 0                                     NOT NULL,
+    bucket_index      number        DEFAULT 0                                     NOT NULL,
+    create_dt         date          DEFAULT CURRENT_TIMESTAMP                     NOT NULL,
+    update_dt         date          DEFAULT CURRENT_TIMESTAMP                     NOT NULL
+);
+
+ALTER TABLE sj_group_config
+    ADD CONSTRAINT pk_sj_group_config PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_group_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_group_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_group_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_group_config.description IS '缁勬弿杩�';
+COMMENT ON COLUMN sj_group_config.token IS 'token';
+COMMENT ON COLUMN sj_group_config.group_status IS '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_group_config.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_group_config.group_partition IS '鍒嗗尯';
+COMMENT ON COLUMN sj_group_config.id_generator_mode IS '鍞竴id鐢熸垚妯″紡 榛樿鍙锋妯″紡';
+COMMENT ON COLUMN sj_group_config.init_scene IS '鏄惁鍒濆鍖栧満鏅� 0:鍚� 1:鏄�';
+COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_group_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_group_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_group_config IS '缁勯厤缃�';
+
+INSERT INTO sj_group_config (namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate);
+
+-- sj_notify_config
+CREATE TABLE sj_notify_config
+(
+    id                     number GENERATED ALWAYS AS IDENTITY,
+    namespace_id           varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name             varchar2(64)                                             NULL,
+    business_id            varchar2(64)                                             NULL,
+    system_task_type       smallint      DEFAULT 3                                  NOT NULL,
+    notify_status          smallint      DEFAULT 0                                  NOT NULL,
+    recipient_ids          varchar2(128)                                            NULL,
+    notify_threshold       number        DEFAULT 0                                  NOT NULL,
+    notify_scene           smallint      DEFAULT 0                                  NOT NULL,
+    rate_limiter_status    smallint      DEFAULT 0                                  NOT NULL,
+    rate_limiter_threshold number        DEFAULT 0                                  NOT NULL,
+    description            varchar2(256) DEFAULT ''                                 NULL,
+    create_dt              date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt              date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_notify_config
+    ADD CONSTRAINT pk_sj_notify_config PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id);
+
+COMMENT ON COLUMN sj_notify_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_notify_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_notify_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_notify_config.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ';
+COMMENT ON COLUMN sj_notify_config.system_task_type IS '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_notify_config.notify_status IS '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_notify_config.recipient_ids IS '鎺ユ敹浜篿d鍒楄〃';
+COMMENT ON COLUMN sj_notify_config.notify_threshold IS '閫氱煡闃堝��';
+COMMENT ON COLUMN sj_notify_config.notify_scene IS '閫氱煡鍦烘櫙';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '闄愭祦鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '姣忕闄愭祦闃堝��';
+COMMENT ON COLUMN sj_notify_config.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_notify_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_notify_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_notify_config IS '閫氱煡閰嶇疆';
+
+-- sj_notify_recipient
+CREATE TABLE sj_notify_recipient
+(
+    id               number GENERATED ALWAYS AS IDENTITY,
+    namespace_id     varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    recipient_name   varchar2(64)                                             NULL,
+    notify_type      smallint      DEFAULT 0                                  NOT NULL,
+    notify_attribute varchar2(512)                                            NULL,
+    description      varchar2(256) DEFAULT ''                                 NULL,
+    create_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_notify_recipient
+    ADD CONSTRAINT pk_sj_notify_recipient PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id);
+
+COMMENT ON COLUMN sj_notify_recipient.id IS '涓婚敭';
+COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '鎺ユ敹浜哄悕绉�';
+COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook';
+COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '閰嶇疆灞炴��';
+COMMENT ON COLUMN sj_notify_recipient.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_notify_recipient.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_notify_recipient.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_notify_recipient IS '鍛婅閫氱煡鎺ユ敹浜�';
+
+-- sj_retry_dead_letter_0
+CREATE TABLE sj_retry_dead_letter_0
+(
+    id            number GENERATED ALWAYS AS IDENTITY,
+    namespace_id  varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    unique_id     varchar2(64)                                             NULL,
+    group_name    varchar2(64)                                             NULL,
+    scene_name    varchar2(64)                                             NULL,
+    idempotent_id varchar2(64)                                             NULL,
+    biz_no        varchar2(64)  DEFAULT ''                                 NULL,
+    executor_name varchar2(512) DEFAULT ''                                 NULL,
+    args_str      clob                                                     NULL,
+    ext_attrs     clob                                                     NULL,
+    task_type     smallint      DEFAULT 1                                  NOT NULL,
+    create_dt     date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_dead_letter_0
+    ADD CONSTRAINT pk_sj_retry_dead_letter_0 PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id);
+
+CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id);
+CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no);
+CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt);
+
+COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_retry_dead_letter_0 IS '姝讳俊闃熷垪琛�';
+
+-- sj_retry_task_0
+CREATE TABLE sj_retry_task_0
+(
+    id              number GENERATED ALWAYS AS IDENTITY,
+    namespace_id    varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    unique_id       varchar2(64)                                             NULL,
+    group_name      varchar2(64)                                             NULL,
+    scene_name      varchar2(64)                                             NULL,
+    idempotent_id   varchar2(64)                                             NULL,
+    biz_no          varchar2(64)  DEFAULT ''                                 NULL,
+    executor_name   varchar2(512) DEFAULT ''                                 NULL,
+    args_str        clob                                                     NULL,
+    ext_attrs       clob                                                     NULL,
+    next_trigger_at date                                                     NOT NULL,
+    retry_count     number        DEFAULT 0                                  NOT NULL,
+    retry_status    smallint      DEFAULT 0                                  NOT NULL,
+    task_type       smallint      DEFAULT 1                                  NOT NULL,
+    create_dt       date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt       date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_task_0
+    ADD CONSTRAINT pk_sj_retry_task_0 PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id);
+
+CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type);
+CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status);
+CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id);
+CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no);
+CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_0.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_0.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_0.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_0.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_task_0.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_task_0.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_task_0.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_0.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_retry_task_0.retry_status IS '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_retry_task_0.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_task_0.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_0.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_task_0 IS '浠诲姟琛�';
+
+-- sj_retry_task_log
+CREATE TABLE sj_retry_task_log
+(
+    id            number GENERATED ALWAYS AS IDENTITY,
+    namespace_id  varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    unique_id     varchar2(64)                                             NULL,
+    group_name    varchar2(64)                                             NULL,
+    scene_name    varchar2(64)                                             NULL,
+    idempotent_id varchar2(64)                                             NULL,
+    biz_no        varchar2(64)  DEFAULT ''                                 NULL,
+    executor_name varchar2(512) DEFAULT ''                                 NULL,
+    args_str      clob                                                     NULL,
+    ext_attrs     clob                                                     NULL,
+    retry_status  smallint      DEFAULT 0                                  NOT NULL,
+    task_type     smallint      DEFAULT 1                                  NOT NULL,
+    create_dt     date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt     date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_task_log
+    ADD CONSTRAINT pk_sj_retry_task_log PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status);
+CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id);
+CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id);
+CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no);
+CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_log.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_log.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_log.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_log.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_task_log.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_task_log.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_task_log.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_task_log.retry_status IS '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ф鏁�';
+COMMENT ON COLUMN sj_retry_task_log.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_task_log.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_log.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_task_log IS '浠诲姟鏃ュ織鍩虹淇℃伅琛�';
+
+-- sj_retry_task_log_message
+CREATE TABLE sj_retry_task_log_message
+(
+    id           number GENERATED ALWAYS AS IDENTITY,
+    namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name   varchar2(64)                                            NULL,
+    unique_id    varchar2(64)                                            NULL,
+    message      clob                                                    NULL,
+    log_num      number       DEFAULT 1                                  NOT NULL,
+    real_time    number       DEFAULT 0                                  NOT NULL,
+    create_dt    date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_task_log_message
+    ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_rt_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id);
+CREATE INDEX idx_sj_rt_log_message_02 ON sj_retry_task_log_message (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_log_message.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_log_message.message IS '寮傚父淇℃伅';
+COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '涓婃姤鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_retry_task_log_message IS '浠诲姟璋冨害鏃ュ織淇℃伅璁板綍琛�';
+
+-- sj_retry_scene_config
+CREATE TABLE sj_retry_scene_config
+(
+    id               number GENERATED ALWAYS AS IDENTITY,
+    namespace_id     varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    scene_name       varchar2(64)                                             NULL,
+    group_name       varchar2(64)                                             NULL,
+    scene_status     smallint      DEFAULT 0                                  NOT NULL,
+    max_retry_count  number        DEFAULT 5                                  NOT NULL,
+    back_off         smallint      DEFAULT 1                                  NOT NULL,
+    trigger_interval varchar2(16)  DEFAULT ''                                 NULL,
+    deadline_request number        DEFAULT 60000                              NOT NULL,
+    executor_timeout number        DEFAULT 5                                  NOT NULL,
+    route_key        smallint      DEFAULT 4                                  NOT NULL,
+    description      varchar2(256) DEFAULT ''                                 NULL,
+    create_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_scene_config
+    ADD CONSTRAINT pk_sj_retry_scene_config PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name);
+
+COMMENT ON COLUMN sj_retry_scene_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_scene_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '鏈�澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�';
+COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣';
+COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_retry_scene_config.route_key IS '璺敱绛栫暐';
+COMMENT ON COLUMN sj_retry_scene_config.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_scene_config IS '鍦烘櫙閰嶇疆';
+
+-- sj_server_node
+CREATE TABLE sj_server_node
+(
+    id           number GENERATED ALWAYS AS IDENTITY,
+    namespace_id varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name   varchar2(64)                                             NULL,
+    host_id      varchar2(64)                                             NULL,
+    host_ip      varchar2(64)                                             NULL,
+    host_port    number                                                   NOT NULL,
+    expire_at    date                                                     NOT NULL,
+    node_type    smallint                                                 NOT NULL,
+    ext_attrs    varchar2(256) DEFAULT ''                                 NULL,
+    create_dt    date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt    date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_server_node
+    ADD CONSTRAINT pk_sj_server_node PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip);
+
+CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name);
+CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type);
+
+COMMENT ON COLUMN sj_server_node.id IS '涓婚敭';
+COMMENT ON COLUMN sj_server_node.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_server_node.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_server_node.host_id IS '涓绘満id';
+COMMENT ON COLUMN sj_server_node.host_ip IS '鏈哄櫒ip';
+COMMENT ON COLUMN sj_server_node.host_port IS '鏈哄櫒绔彛';
+COMMENT ON COLUMN sj_server_node.expire_at IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN sj_server_node.node_type IS '鑺傜偣绫诲瀷 1銆佸鎴风 2銆佹槸鏈嶅姟绔�';
+COMMENT ON COLUMN sj_server_node.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_server_node.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_server_node.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_server_node IS '鏈嶅姟鍣ㄨ妭鐐�';
+
+-- sj_distributed_lock
+CREATE TABLE sj_distributed_lock
+(
+    name       varchar2(64)                              NOT NULL,
+    lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
+    locked_at  timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
+    locked_by  varchar2(255)                             NULL,
+    create_dt  date         DEFAULT CURRENT_TIMESTAMP    NOT NULL,
+    update_dt  date         DEFAULT CURRENT_TIMESTAMP    NOT NULL
+);
+
+ALTER TABLE sj_distributed_lock
+    ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name);
+
+COMMENT ON COLUMN sj_distributed_lock.name IS '閿佸悕绉�';
+COMMENT ON COLUMN sj_distributed_lock.lock_until IS '閿佸畾鏃堕暱';
+COMMENT ON COLUMN sj_distributed_lock.locked_at IS '閿佸畾鏃堕棿';
+COMMENT ON COLUMN sj_distributed_lock.locked_by IS '閿佸畾鑰�';
+COMMENT ON COLUMN sj_distributed_lock.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_distributed_lock.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_distributed_lock IS '閿佸畾琛�';
+
+-- sj_system_user
+CREATE TABLE sj_system_user
+(
+    id        number GENERATED ALWAYS AS IDENTITY,
+    username  varchar2(64)                       NULL,
+    password  varchar2(128)                      NULL,
+    role      smallint DEFAULT 0                 NOT NULL,
+    create_dt date     DEFAULT CURRENT_TIMESTAMP NOT NULL,
+    update_dt date     DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
+
+ALTER TABLE sj_system_user
+    ADD CONSTRAINT pk_sj_system_user PRIMARY KEY (id);
+
+COMMENT ON COLUMN sj_system_user.id IS '涓婚敭';
+COMMENT ON COLUMN sj_system_user.username IS '璐﹀彿';
+COMMENT ON COLUMN sj_system_user.password IS '瀵嗙爜';
+COMMENT ON COLUMN sj_system_user.role IS '瑙掕壊锛�1-鏅�氱敤鎴枫��2-绠$悊鍛�';
+COMMENT ON COLUMN sj_system_user.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_system_user.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_system_user IS '绯荤粺鐢ㄦ埛琛�';
+
+-- pwd: admin
+INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, sysdate, sysdate);
+
+-- sj_system_user_permission
+CREATE TABLE sj_system_user_permission
+(
+    id             number GENERATED ALWAYS AS IDENTITY,
+    group_name     varchar2(64)                                            NULL,
+    namespace_id   varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    system_user_id number                                                  NOT NULL,
+    create_dt      date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt      date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_system_user_permission
+    ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_su_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id);
+
+COMMENT ON COLUMN sj_system_user_permission.id IS '涓婚敭';
+COMMENT ON COLUMN sj_system_user_permission.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '绯荤粺鐢ㄦ埛id';
+COMMENT ON COLUMN sj_system_user_permission.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_system_user_permission.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_system_user_permission IS '绯荤粺鐢ㄦ埛鏉冮檺琛�';
+
+-- sj_sequence_alloc
+CREATE TABLE sj_sequence_alloc
+(
+    id           number GENERATED ALWAYS AS IDENTITY,
+    namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name   varchar2(64) DEFAULT ''                                 NULL,
+    max_id       number       DEFAULT 1                                  NOT NULL,
+    step         number       DEFAULT 100                                NOT NULL,
+    update_dt    date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_sequence_alloc
+    ADD CONSTRAINT pk_sj_sequence_alloc PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_sequence_alloc.id IS '涓婚敭';
+COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_sequence_alloc.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_sequence_alloc.max_id IS '鏈�澶d';
+COMMENT ON COLUMN sj_sequence_alloc.step IS '姝ラ暱';
+COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '鏇存柊鏃堕棿';
+COMMENT ON TABLE sj_sequence_alloc IS '鍙锋妯″紡搴忓彿ID鍒嗛厤琛�';
+
+-- sj_job
+CREATE TABLE sj_job
+(
+    id               number GENERATED ALWAYS AS IDENTITY,
+    namespace_id     varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name       varchar2(64)                                             NULL,
+    job_name         varchar2(64)                                             NULL,
+    args_str         clob          DEFAULT NULL                               NULL,
+    args_type        smallint      DEFAULT 1                                  NOT NULL,
+    next_trigger_at  number                                                   NOT NULL,
+    job_status       smallint      DEFAULT 1                                  NOT NULL,
+    task_type        smallint      DEFAULT 1                                  NOT NULL,
+    route_key        smallint      DEFAULT 4                                  NOT NULL,
+    executor_type    smallint      DEFAULT 1                                  NOT NULL,
+    executor_info    varchar2(255) DEFAULT NULL                               NULL,
+    trigger_type     smallint                                                 NOT NULL,
+    trigger_interval varchar2(255)                                            NULL,
+    block_strategy   smallint      DEFAULT 1                                  NOT NULL,
+    executor_timeout number        DEFAULT 0                                  NOT NULL,
+    max_retry_times  number        DEFAULT 0                                  NOT NULL,
+    parallel_num     number        DEFAULT 1                                  NOT NULL,
+    retry_interval   number        DEFAULT 0                                  NOT NULL,
+    bucket_index     number        DEFAULT 0                                  NOT NULL,
+    resident         smallint      DEFAULT 0                                  NOT NULL,
+    description      varchar2(256) DEFAULT ''                                 NULL,
+    ext_attrs        varchar2(256) DEFAULT ''                                 NULL,
+    deleted          smallint      DEFAULT 0                                  NOT NULL,
+    create_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_job
+    ADD CONSTRAINT pk_sj_job PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name);
+CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index);
+CREATE INDEX idx_sj_job_03 ON sj_job (create_dt);
+
+COMMENT ON COLUMN sj_job.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job.job_name IS '鍚嶇О';
+COMMENT ON COLUMN sj_job.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_job.args_type IS '鍙傛暟绫诲瀷 ';
+COMMENT ON COLUMN sj_job.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_job.job_status IS '浠诲姟鐘舵�� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_job.task_type IS '浠诲姟绫诲瀷 1銆侀泦缇� 2銆佸箍鎾� 3銆佸垏鐗�';
+COMMENT ON COLUMN sj_job.route_key IS '璺敱绛栫暐';
+COMMENT ON COLUMN sj_job.executor_type IS '鎵ц鍣ㄧ被鍨�';
+COMMENT ON COLUMN sj_job.executor_info IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_job.trigger_type IS '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿';
+COMMENT ON COLUMN sj_job.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_job.block_strategy IS '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�';
+COMMENT ON COLUMN sj_job.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_job.max_retry_times IS '鏈�澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_job.parallel_num IS '骞惰鏁�';
+COMMENT ON COLUMN sj_job.retry_interval IS '閲嶈瘯闂撮殧 ( s ) ';
+COMMENT ON COLUMN sj_job.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_job.resident IS '鏄惁鏄父椹讳换鍔�';
+COMMENT ON COLUMN sj_job.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_job.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_job.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job IS '浠诲姟淇℃伅';
+
+INSERT INTO sj_job(namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, description, ext_attrs, deleted, create_dt, update_dt) VALUES ('dev', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0, sysdate, sysdate);
+
+-- sj_job_log_message
+CREATE TABLE sj_job_log_message
+(
+    id            number GENERATED ALWAYS AS IDENTITY,
+    namespace_id  varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name    varchar2(64)                                             NULL,
+    job_id        number                                                   NOT NULL,
+    task_batch_id number                                                   NOT NULL,
+    task_id       number                                                   NOT NULL,
+    message       clob                                                     NULL,
+    log_num       number        DEFAULT 1                                  NOT NULL,
+    real_time     number        DEFAULT 0                                  NOT NULL,
+    ext_attrs     varchar2(256) DEFAULT ''                                 NULL,
+    create_dt     date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_job_log_message
+    ADD CONSTRAINT pk_sj_job_log_message PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id);
+CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt);
+CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_log_message.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_log_message.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_log_message.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_log_message.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '浠诲姟鎵规id';
+COMMENT ON COLUMN sj_job_log_message.task_id IS '璋冨害浠诲姟id';
+COMMENT ON COLUMN sj_job_log_message.message IS '璋冨害淇℃伅';
+COMMENT ON COLUMN sj_job_log_message.log_num IS '鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_log_message.real_time IS '涓婃姤鏃堕棿';
+COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_log_message.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_job_log_message IS '璋冨害鏃ュ織';
+
+-- sj_job_task
+CREATE TABLE sj_job_task
+(
+    id             number GENERATED ALWAYS AS IDENTITY,
+    namespace_id   varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name     varchar2(64)                                             NULL,
+    job_id         number                                                   NOT NULL,
+    task_batch_id  number                                                   NOT NULL,
+    parent_id      number        DEFAULT 0                                  NOT NULL,
+    task_status    smallint      DEFAULT 0                                  NOT NULL,
+    retry_count    number        DEFAULT 0                                  NOT NULL,
+    mr_stage       smallint      DEFAULT NULL                               NULL,
+    leaf           smallint      DEFAULT '1'                                NOT NULL,
+    task_name      varchar2(255) DEFAULT ''                                 NULL,
+    client_info    varchar2(128) DEFAULT NULL                               NULL,
+    wf_context     clob          DEFAULT NULL                               NULL,
+    result_message clob                                                     NULL,
+    args_str       clob          DEFAULT NULL                               NULL,
+    args_type      smallint      DEFAULT 1                                  NOT NULL,
+    ext_attrs      varchar2(256) DEFAULT ''                                 NULL,
+    create_dt      date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt      date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_job_task
+    ADD CONSTRAINT pk_sj_job_task PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status);
+CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt);
+CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_task.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_task.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_task.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_task.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_job_task.task_batch_id IS '璋冨害浠诲姟id';
+COMMENT ON COLUMN sj_job_task.parent_id IS '鐖舵墽琛屽櫒id';
+COMMENT ON COLUMN sj_job_task.task_status IS '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_job_task.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_job_task.mr_stage IS '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce';
+COMMENT ON COLUMN sj_job_task.leaf IS '鍙跺瓙鑺傜偣';
+COMMENT ON COLUMN sj_job_task.task_name IS '浠诲姟鍚嶇О';
+COMMENT ON COLUMN sj_job_task.client_info IS '瀹㈡埛绔湴鍧� clientId#ip:port';
+COMMENT ON COLUMN sj_job_task.wf_context IS '宸ヤ綔娴佸叏灞�涓婁笅鏂�';
+COMMENT ON COLUMN sj_job_task.result_message IS '鎵ц缁撴灉';
+COMMENT ON COLUMN sj_job_task.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_job_task.args_type IS '鍙傛暟绫诲瀷 ';
+COMMENT ON COLUMN sj_job_task.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_task.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_task.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_task IS '浠诲姟瀹炰緥';
+
+-- sj_job_task_batch
+CREATE TABLE sj_job_task_batch
+(
+    id                      number GENERATED ALWAYS AS IDENTITY,
+    namespace_id            varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name              varchar2(64)                                             NULL,
+    job_id                  number                                                   NOT NULL,
+    workflow_node_id        number        DEFAULT 0                                  NOT NULL,
+    parent_workflow_node_id number        DEFAULT 0                                  NOT NULL,
+    workflow_task_batch_id  number        DEFAULT 0                                  NOT NULL,
+    task_batch_status       smallint      DEFAULT 0                                  NOT NULL,
+    operation_reason        smallint      DEFAULT 0                                  NOT NULL,
+    execution_at            number        DEFAULT 0                                  NOT NULL,
+    system_task_type        smallint      DEFAULT 3                                  NOT NULL,
+    parent_id               varchar2(64)  DEFAULT ''                                 NULL,
+    ext_attrs               varchar2(256) DEFAULT ''                                 NULL,
+    deleted                 smallint      DEFAULT 0                                  NOT NULL,
+    create_dt               date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt               date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_job_task_batch
+    ADD CONSTRAINT pk_sj_job_task_batch PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status);
+CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt);
+CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name);
+CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id);
+
+COMMENT ON COLUMN sj_job_task_batch.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_task_batch.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_task_batch.job_id IS '浠诲姟id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '宸ヤ綔娴佽妭鐐筰d';
+COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '宸ヤ綔娴佷换鍔$埗鎵规id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '宸ヤ綔娴佷换鍔℃壒娆d';
+COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
+COMMENT ON COLUMN sj_job_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
+COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_job_task_batch.parent_id IS '鐖惰妭鐐�';
+COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_job_task_batch.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_task_batch.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_task_batch IS '浠诲姟鎵规';
+
+-- sj_job_summary
+CREATE TABLE sj_job_summary
+(
+    id               number GENERATED ALWAYS AS IDENTITY,
+    namespace_id     varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name       varchar2(64)  DEFAULT ''                                 NULL,
+    business_id      number                                                   NOT NULL,
+    system_task_type smallint      DEFAULT 3                                  NOT NULL,
+    trigger_at       date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    success_num      number        DEFAULT 0                                  NOT NULL,
+    fail_num         number        DEFAULT 0                                  NOT NULL,
+    fail_reason      varchar2(512) DEFAULT ''                                 NULL,
+    stop_num         number        DEFAULT 0                                  NOT NULL,
+    stop_reason      varchar2(512) DEFAULT ''                                 NULL,
+    cancel_num       number        DEFAULT 0                                  NOT NULL,
+    cancel_reason    varchar2(512) DEFAULT ''                                 NULL,
+    create_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_job_summary
+    ADD CONSTRAINT pk_sj_job_summary PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id);
+
+CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id);
+
+COMMENT ON COLUMN sj_job_summary.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_summary.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_summary.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_summary.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id ) ';
+COMMENT ON COLUMN sj_job_summary.system_task_type IS '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_job_summary.trigger_at IS '缁熻鏃堕棿';
+COMMENT ON COLUMN sj_job_summary.success_num IS '鎵ц鎴愬姛-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.fail_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.fail_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.stop_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.stop_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.cancel_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.cancel_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_summary.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job';
+
+-- sj_retry_summary
+CREATE TABLE sj_retry_summary
+(
+    id            number GENERATED ALWAYS AS IDENTITY,
+    namespace_id  varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name    varchar2(64) DEFAULT ''                                 NULL,
+    scene_name    varchar2(50) DEFAULT ''                                 NULL,
+    trigger_at    date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    running_num   number       DEFAULT 0                                  NOT NULL,
+    finish_num    number       DEFAULT 0                                  NOT NULL,
+    max_count_num number       DEFAULT 0                                  NOT NULL,
+    suspend_num   number       DEFAULT 0                                  NOT NULL,
+    create_dt     date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt     date         DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_retry_summary
+    ADD CONSTRAINT pk_sj_retry_summary PRIMARY KEY (id);
+
+CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at);
+
+CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at);
+
+COMMENT ON COLUMN sj_retry_summary.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_summary.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_summary.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_summary.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_summary.trigger_at IS '缁熻鏃堕棿';
+COMMENT ON COLUMN sj_retry_summary.running_num IS '閲嶈瘯涓�-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.finish_num IS '閲嶈瘯瀹屾垚-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.max_count_num IS '閲嶈瘯鍒拌揪鏈�澶ф鏁�-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.suspend_num IS '鏆傚仠閲嶈瘯-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_summary.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry';
+
+-- sj_workflow
+CREATE TABLE sj_workflow
+(
+    id               number GENERATED ALWAYS AS IDENTITY,
+    workflow_name    varchar2(64)                                             NULL,
+    namespace_id     varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name       varchar2(64)                                             NULL,
+    workflow_status  smallint      DEFAULT 1                                  NOT NULL,
+    trigger_type     smallint                                                 NOT NULL,
+    trigger_interval varchar2(255)                                            NULL,
+    next_trigger_at  number                                                   NOT NULL,
+    block_strategy   smallint      DEFAULT 1                                  NOT NULL,
+    executor_timeout number        DEFAULT 0                                  NOT NULL,
+    description      varchar2(256) DEFAULT ''                                 NULL,
+    flow_info        clob          DEFAULT NULL                               NULL,
+    wf_context       clob          DEFAULT NULL                               NULL,
+    bucket_index     number        DEFAULT 0                                  NOT NULL,
+    version          number                                                   NOT NULL,
+    ext_attrs        varchar2(256) DEFAULT ''                                 NULL,
+    deleted          smallint      DEFAULT 0                                  NOT NULL,
+    create_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt        date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_workflow
+    ADD CONSTRAINT pk_sj_workflow PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt);
+CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow.workflow_name IS '宸ヤ綔娴佸悕绉�';
+COMMENT ON COLUMN sj_workflow.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow.workflow_status IS '宸ヤ綔娴佺姸鎬� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_workflow.trigger_type IS '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿';
+COMMENT ON COLUMN sj_workflow.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_workflow.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_workflow.block_strategy IS '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�';
+COMMENT ON COLUMN sj_workflow.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow IS '宸ヤ綔娴�';
+
+-- sj_workflow_node
+CREATE TABLE sj_workflow_node
+(
+    id                   number GENERATED ALWAYS AS IDENTITY,
+    namespace_id         varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    node_name            varchar2(64)                                             NULL,
+    group_name           varchar2(64)                                             NULL,
+    job_id               number                                                   NOT NULL,
+    workflow_id          number                                                   NOT NULL,
+    node_type            smallint      DEFAULT 1                                  NOT NULL,
+    expression_type      smallint      DEFAULT 0                                  NOT NULL,
+    fail_strategy        smallint      DEFAULT 1                                  NOT NULL,
+    workflow_node_status smallint      DEFAULT 1                                  NOT NULL,
+    priority_level       number        DEFAULT 1                                  NOT NULL,
+    node_info            clob          DEFAULT NULL                               NULL,
+    version              number                                                   NOT NULL,
+    ext_attrs            varchar2(256) DEFAULT ''                                 NULL,
+    deleted              smallint      DEFAULT 0                                  NOT NULL,
+    create_dt            date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt            date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_workflow_node
+    ADD CONSTRAINT pk_sj_workflow_node PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt);
+CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_node.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow_node.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow_node.node_name IS '鑺傜偣鍚嶇О';
+COMMENT ON COLUMN sj_workflow_node.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow_node.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_workflow_node.workflow_id IS '宸ヤ綔娴両D';
+COMMENT ON COLUMN sj_workflow_node.node_type IS '1銆佷换鍔¤妭鐐� 2銆佹潯浠惰妭鐐�';
+COMMENT ON COLUMN sj_workflow_node.expression_type IS '1銆丼pEl銆�2銆丄viator 3銆丵L';
+COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '澶辫触绛栫暐 1銆佽烦杩� 2銆侀樆濉�';
+COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '宸ヤ綔娴佽妭鐐圭姸鎬� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_workflow_node.priority_level IS '浼樺厛绾�';
+COMMENT ON COLUMN sj_workflow_node.node_info IS '鑺傜偣淇℃伅 ';
+COMMENT ON COLUMN sj_workflow_node.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_node.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow_node.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow_node.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow_node IS '宸ヤ綔娴佽妭鐐�';
+
+-- sj_workflow_task_batch
+CREATE TABLE sj_workflow_task_batch
+(
+    id                number GENERATED ALWAYS AS IDENTITY,
+    namespace_id      varchar2(64)  DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
+    group_name        varchar2(64)                                             NULL,
+    workflow_id       number                                                   NOT NULL,
+    task_batch_status smallint      DEFAULT 0                                  NOT NULL,
+    operation_reason  smallint      DEFAULT 0                                  NOT NULL,
+    flow_info         clob          DEFAULT NULL                               NULL,
+    wf_context        clob          DEFAULT NULL                               NULL,
+    execution_at      number        DEFAULT 0                                  NOT NULL,
+    ext_attrs         varchar2(256) DEFAULT ''                                 NULL,
+    version           number        DEFAULT 1                                  NOT NULL,
+    deleted           smallint      DEFAULT 0                                  NOT NULL,
+    create_dt         date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL,
+    update_dt         date          DEFAULT CURRENT_TIMESTAMP                  NOT NULL
+);
+
+ALTER TABLE sj_workflow_task_batch
+    ADD CONSTRAINT pk_sj_workflow_task_batch PRIMARY KEY (id);
+
+CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status);
+CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt);
+CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_task_batch.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '宸ヤ綔娴佷换鍔d';
+COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
+COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '鍏ㄥ眬涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
+COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_task_batch.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow_task_batch IS '宸ヤ綔娴佹壒娆�';
diff --git a/eims/script/sql/postgres/flowable.sql b/eims/script/sql/postgres/flowable.sql
new file mode 100644
index 0000000..8a6078d
--- /dev/null
+++ b/eims/script/sql/postgres/flowable.sql
@@ -0,0 +1,275 @@
+insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, now(), NULL, NULL, '');
+insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, now(), NULL, NULL, '');
+
+
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), null, null, '');
+insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, now(), null, null, '');
+insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, now(), null, null, '');
+insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, now(), null, null, '');
+-- 璇峰亣鍗曚俊鎭�
+create table test_leave
+(
+    id          bigint not null
+        constraint test_leave_pk
+            primary key,
+    leave_type  varchar(255),
+    start_date  timestamp,
+    end_date    timestamp,
+    leave_days  bigint,
+    remark      varchar(255),
+    status      varchar(255),
+    create_dept bigint,
+    create_by   bigint,
+    create_time timestamp,
+    update_by   bigint,
+    update_time timestamp,
+    tenant_id   varchar(20)
+);
+
+comment on table test_leave is '璇峰亣鐢宠琛�';
+comment on column test_leave.id is '涓婚敭';
+comment on column test_leave.leave_type is '璇峰亣绫诲瀷';
+comment on column test_leave.start_date is '寮�濮嬫椂闂�';
+comment on column test_leave.end_date is '缁撴潫鏃堕棿';
+comment on column test_leave.remark is '璇峰亣鍘熷洜';
+comment on column test_leave.status is '鐘舵��';
+comment on column test_leave.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column test_leave.create_by is '鍒涘缓鑰�';
+comment on column test_leave.create_time is '鍒涘缓鏃堕棿';
+comment on column test_leave.update_by is '鏇存柊鑰�';
+comment on column test_leave.update_time is '鏇存柊鏃堕棿';
+comment on column test_leave.tenant_id is '绉熸埛缂栫爜';
+
+alter table test_leave
+    owner to postgres;
+
+-- 娴佺▼鍒嗙被淇℃伅琛�
+create table wf_category
+(
+    id            bigint not null
+        constraint wf_category_pk
+            primary key,
+    category_name varchar(255),
+    category_code varchar(255),
+    parent_id     bigint,
+    sort_num      bigint,
+    tenant_id     varchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   timestamp,
+    update_by     bigint,
+    update_time   timestamp
+);
+
+comment on table wf_category is '娴佺▼鍒嗙被';
+comment on column wf_category.id is '涓婚敭';
+comment on column wf_category.category_name is '鍒嗙被鍚嶇О';
+comment on column wf_category.category_code is '鍒嗙被缂栫爜';
+comment on column wf_category.parent_id is '鐖剁骇id';
+comment on column wf_category.sort_num is '鎺掑簭';
+comment on column wf_category.tenant_id is '绉熸埛id';
+comment on column wf_category.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column wf_category.create_by is '鍒涘缓鑰�';
+comment on column wf_category.create_time is '鍒涘缓鏃堕棿';
+comment on column wf_category.update_by is '淇敼鑰�';
+comment on column wf_category.update_time is '淇敼鏃堕棿';
+
+alter table wf_category
+    owner to postgres;
+
+create unique index uni_category_code
+    on wf_category (category_code);
+
+INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, now(), 1, now());
+
+create table wf_task_back_node
+(
+    id            bigint not null
+        constraint pk_wf_task_back_node
+        primary key,
+    node_id       varchar(255) not null,
+    node_name     varchar(255) not null,
+    order_no      bigint not null,
+    instance_id   varchar(255) not null,
+    task_type     varchar(255) not null,
+    assignee      varchar(2000) not null,
+    tenant_id     varchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   timestamp,
+    update_by     bigint,
+    update_time   timestamp
+);
+
+comment on table wf_task_back_node is '鑺傜偣瀹℃壒璁板綍';
+comment on column wf_task_back_node.id is '涓婚敭';
+comment on column wf_task_back_node.node_id is '鑺傜偣id';
+comment on column wf_task_back_node.node_name is '鑺傜偣鍚嶇О';
+comment on column wf_task_back_node.order_no is '鎺掑簭';
+comment on column wf_task_back_node.instance_id is '娴佺▼瀹炰緥id';
+comment on column wf_task_back_node.task_type is '鑺傜偣绫诲瀷';
+comment on column wf_task_back_node.assignee is '瀹℃壒浜�';
+comment on column wf_task_back_node.tenant_id is '绉熸埛id';
+comment on column wf_task_back_node.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column wf_task_back_node.create_by is '鍒涘缓鑰�';
+comment on column wf_task_back_node.create_time is '鍒涘缓鏃堕棿';
+comment on column wf_task_back_node.update_by is '淇敼鑰�';
+comment on column wf_task_back_node.update_time is '淇敼鏃堕棿';
+
+alter table wf_task_back_node
+    owner to postgres;
+
+create table wf_definition_config
+(
+    id            bigint not null
+        constraint pk_wf_definition_config
+        primary key,
+    table_name    varchar(255) not null,
+    definition_id varchar(255) not null,
+    process_key   varchar(255) not null,
+    version       bigint       not null,
+    tenant_id     varchar(20),
+    remark        varchar(500),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   timestamp,
+    update_by     bigint,
+    update_time   timestamp
+);
+
+comment on table wf_definition_config is '娴佺▼瀹氫箟閰嶇疆';
+comment on column wf_definition_config.id is '涓婚敭';
+comment on column wf_definition_config.table_name is '琛ㄥ悕';
+comment on column wf_definition_config.definition_id is '娴佺▼瀹氫箟ID';
+comment on column wf_definition_config.process_key is '娴佺▼KEY';
+comment on column wf_definition_config.version is '娴佺▼鐗堟湰';
+comment on column wf_definition_config.tenant_id is '绉熸埛id';
+comment on column wf_definition_config.remark is '澶囨敞';
+comment on column wf_definition_config.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column wf_definition_config.create_by is '鍒涘缓鑰�';
+comment on column wf_definition_config.create_time is '鍒涘缓鏃堕棿';
+comment on column wf_definition_config.update_by is '淇敼鑰�';
+comment on column wf_definition_config.update_time is '淇敼鏃堕棿';
+
+alter table wf_definition_config
+    owner to postgres;
+create unique index uni_definition_id
+    on wf_definition_config (definition_id);
+
+create table wf_form_manage
+(
+    id            bigint not null
+        constraint pk_wf_form_manage
+        primary key,
+    form_name     varchar(255) not null,
+    form_type     varchar(255) not null,
+    router        varchar(255) not null,
+    remark        varchar(500),
+    tenant_id     varchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   timestamp,
+    update_by     bigint,
+    update_time   timestamp
+);
+
+comment on table wf_form_manage is '琛ㄥ崟绠$悊';
+comment on column wf_form_manage.id is '涓婚敭';
+comment on column wf_form_manage.form_name is '琛ㄥ崟鍚嶇О';
+comment on column wf_form_manage.form_type is '琛ㄥ崟绫诲瀷';
+comment on column wf_form_manage.router is '璺敱鍦板潃/琛ㄥ崟ID';
+comment on column wf_form_manage.remark is '澶囨敞';
+comment on column wf_form_manage.tenant_id is '绉熸埛id';
+comment on column wf_form_manage.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column wf_form_manage.create_by is '鍒涘缓鑰�';
+comment on column wf_form_manage.create_time is '鍒涘缓鏃堕棿';
+comment on column wf_form_manage.update_by is '淇敼鑰�';
+comment on column wf_form_manage.update_time is '淇敼鏃堕棿';
+
+insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, now(), 1, now());
+
+create table wf_node_config
+(
+    id               bigint not null
+        constraint pk_wf_node_config
+            primary key,
+    form_id          bigint,
+    form_type        varchar(255),
+    node_name        varchar(255) not null,
+    node_id          varchar(255) not null,
+    definition_id    varchar(255) not null,
+    apply_user_task  char(1) default '0',
+    tenant_id        varchar(20),
+    create_dept      bigint,
+    create_by        bigint,
+    create_time      timestamp,
+    update_by        bigint,
+    update_time      timestamp
+);
+
+comment on table wf_node_config is '鑺傜偣閰嶇疆';
+comment on column wf_node_config.id is '涓婚敭';
+comment on column wf_node_config.form_id is '琛ㄥ崟id';
+comment on column wf_node_config.form_type is '琛ㄥ崟绫诲瀷';
+comment on column wf_node_config.node_id is '鑺傜偣id';
+comment on column wf_node_config.node_name is '鑺傜偣鍚嶇О';
+comment on column wf_node_config.definition_id is '娴佺▼瀹氫箟id';
+comment on column wf_node_config.apply_user_task is '鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級';
+comment on column wf_node_config.tenant_id is '绉熸埛id';
+comment on column wf_node_config.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column wf_node_config.create_by is '鍒涘缓鑰�';
+comment on column wf_node_config.create_time is '鍒涘缓鏃堕棿';
+comment on column wf_node_config.update_by is '淇敼鑰�';
+comment on column wf_node_config.update_time is '淇敼鏃堕棿';
+
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, '');
+
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, now(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, now(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,now(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,now(), NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
+
+-- 琛ㄥ崟绠$悊 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, now(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
+
+-- 琛ㄥ崟绠$悊鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, now(), null, null, '');
diff --git a/eims/script/sql/postgres/postgres_ry_vue_5.X.sql b/eims/script/sql/postgres/postgres_ry_vue_5.X.sql
new file mode 100644
index 0000000..995d738
--- /dev/null
+++ b/eims/script/sql/postgres/postgres_ry_vue_5.X.sql
@@ -0,0 +1,1356 @@
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+create table sys_social
+(
+    id                 int8             not null,
+    user_id            int8             not null,
+    tenant_id          varchar(20)      default null::varchar,
+    auth_id            varchar(255)     not null,
+    source             varchar(255)     not null,
+    open_id            varchar(255)     default null::varchar,
+    user_name          varchar(30)      not null,
+    nick_name          varchar(30)      default ''::varchar,
+    email              varchar(255)     default ''::varchar,
+    avatar             varchar(500)     default ''::varchar,
+    access_token       varchar(255)     not null,
+    expire_in          int8             default null,
+    refresh_token      varchar(255)     default null::varchar,
+    access_code        varchar(255)     default null::varchar,
+    union_id           varchar(255)     default null::varchar,
+    scope              varchar(255)     default null::varchar,
+    token_type         varchar(255)     default null::varchar,
+    id_token           varchar(2000)    default null::varchar,
+    mac_algorithm      varchar(255)     default null::varchar,
+    mac_key            varchar(255)     default null::varchar,
+    code               varchar(255)     default null::varchar,
+    oauth_token        varchar(255)     default null::varchar,
+    oauth_token_secret varchar(255)     default null::varchar,
+    create_dept        int8,
+    create_by          int8,
+    create_time        timestamp,
+    update_by          int8,
+    update_time        timestamp,
+    del_flag           char             default '0'::bpchar,
+    constraint "pk_sys_social" primary key (id)
+);
+
+comment on table   sys_social                   is '绀句細鍖栧叧绯昏〃';
+comment on column  sys_social.id                is '涓婚敭';
+comment on column  sys_social.user_id           is '鐢ㄦ埛ID';
+comment on column  sys_social.tenant_id         is '绉熸埛id';
+comment on column  sys_social.auth_id           is '骞冲彴+骞冲彴鍞竴id';
+comment on column  sys_social.source            is '鐢ㄦ埛鏉ユ簮';
+comment on column  sys_social.open_id           is '骞冲彴缂栧彿鍞竴id';
+comment on column  sys_social.user_name         is '鐧诲綍璐﹀彿';
+comment on column  sys_social.nick_name         is '鐢ㄦ埛鏄电О';
+comment on column  sys_social.email             is '鐢ㄦ埛閭';
+comment on column  sys_social.avatar            is '澶村儚鍦板潃';
+comment on column  sys_social.access_token      is '鐢ㄦ埛鐨勬巿鏉冧护鐗�';
+comment on column  sys_social.expire_in         is '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.refresh_token     is '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.access_code       is '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.union_id          is '鐢ㄦ埛鐨� unionid';
+comment on column  sys_social.scope             is '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.token_type        is '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.id_token          is 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.mac_algorithm     is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.mac_key           is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.code              is '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.oauth_token       is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.oauth_token_secret is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column  sys_social.create_by         is '鍒涘缓鑰�';
+comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
+comment on column  sys_social.update_by         is '鏇存柊鑰�';
+comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+-- ----------------------------
+-- 绉熸埛琛�
+-- ----------------------------
+create table if not exists sys_tenant
+(
+    id                int8,
+    tenant_id         varchar(20)   not null,
+    contact_user_name varchar(20)   default null::varchar,
+    contact_phone     varchar(20)   default null::varchar,
+    company_name      varchar(50)   default null::varchar,
+    license_number    varchar(30)   default null::varchar,
+    address           varchar(200)  default null::varchar,
+    intro             varchar(200)  default null::varchar,
+    domain            varchar(200)  default null::varchar,
+    remark            varchar(200)  default null::varchar,
+    package_id        int8,
+    expire_time       timestamp,
+    account_count     int4          default -1,
+    status            char          default '0'::bpchar,
+    del_flag          char          default '0'::bpchar,
+    create_dept       int8,
+    create_by         int8,
+    create_time       timestamp,
+    update_by         int8,
+    update_time       timestamp,
+    constraint "pk_sys_tenant" primary key (id)
+);
+
+
+comment on table   sys_tenant                    is '绉熸埛琛�';
+comment on column  sys_tenant.tenant_id          is '绉熸埛缂栧彿';
+comment on column  sys_tenant.contact_phone      is '鑱旂郴鐢佃瘽';
+comment on column  sys_tenant.company_name       is '浼佷笟鍚嶇О';
+comment on column  sys_tenant.company_name       is '鑱旂郴浜�';
+comment on column  sys_tenant.license_number     is '缁熶竴绀句細淇$敤浠g爜';
+comment on column  sys_tenant.address            is '鍦板潃';
+comment on column  sys_tenant.intro              is '浼佷笟绠�浠�';
+comment on column  sys_tenant.domain             is '鍩熷悕';
+comment on column  sys_tenant.remark             is '澶囨敞';
+comment on column  sys_tenant.package_id         is '绉熸埛濂楅缂栧彿';
+comment on column  sys_tenant.expire_time        is '杩囨湡鏃堕棿';
+comment on column  sys_tenant.account_count      is '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級';
+comment on column  sys_tenant.status             is '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column  sys_tenant.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant.create_dept        is '鍒涘缓閮ㄩ棬';
+comment on column  sys_tenant.create_by          is '鍒涘缓鑰�';
+comment on column  sys_tenant.create_time        is '鍒涘缓鏃堕棿';
+comment on column  sys_tenant.update_by          is '鏇存柊鑰�';
+comment on column  sys_tenant.update_time        is '鏇存柊鏃堕棿';
+
+
+-- ----------------------------
+-- 鍒濆鍖�-绉熸埛琛ㄦ暟鎹�
+-- ----------------------------
+
+insert into sys_tenant values(1, '000000', '绠$悊缁�', '15888888888', 'XXX鏈夐檺鍏徃', null, null, '澶氱鎴烽�氱敤鍚庡彴绠$悊绠$悊绯荤粺', null, null, null, null, -1, '0', '0', 103, 1, now(), null, null);
+
+
+-- ----------------------------
+-- 绉熸埛濂楅琛�
+-- ----------------------------
+create table if not exists sys_tenant_package
+(
+    package_id          int8,
+    package_name        varchar(20)     default ''::varchar,
+    menu_ids            varchar(3000)   default ''::varchar,
+    remark              varchar(200)    default ''::varchar,
+    menu_check_strictly bool            default true,
+    status              char            default '0'::bpchar,
+    del_flag            char            default '0'::bpchar,
+    create_dept         int8,
+    create_by           int8,
+    create_time         timestamp,
+    update_by           int8,
+    update_time         timestamp,
+    constraint "pk_sys_tenant_package" primary key (package_id)
+);
+
+
+comment on table   sys_tenant_package                    is '绉熸埛濂楅琛�';
+comment on column  sys_tenant_package.package_id         is '绉熸埛濂楅id';
+comment on column  sys_tenant_package.package_name       is '濂楅鍚嶇О';
+comment on column  sys_tenant_package.menu_ids           is '鍏宠仈鑿滃崟id';
+comment on column  sys_tenant_package.remark             is '澶囨敞';
+comment on column  sys_tenant_package.status             is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column  sys_tenant_package.del_flag           is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column  sys_tenant_package.create_dept        is '鍒涘缓閮ㄩ棬';
+comment on column  sys_tenant_package.create_by          is '鍒涘缓鑰�';
+comment on column  sys_tenant_package.create_time        is '鍒涘缓鏃堕棿';
+comment on column  sys_tenant_package.update_by          is '鏇存柊鑰�';
+comment on column  sys_tenant_package.update_time        is '鏇存柊鏃堕棿';
+
+
+-- ----------------------------
+-- 1銆侀儴闂ㄨ〃
+-- ----------------------------
+create table if not exists sys_dept
+(
+    dept_id     int8,
+    tenant_id   varchar(20) default '000000'::varchar,
+    parent_id   int8        default 0,
+    ancestors   varchar(500)default ''::varchar,
+    dept_name   varchar(30) default ''::varchar,
+    dept_category varchar(100) default null::varchar,
+    order_num   int4        default 0,
+    leader      int8        default null,
+    phone       varchar(11) default null::varchar,
+    email       varchar(50) default null::varchar,
+    status      char        default '0'::bpchar,
+    del_flag    char        default '0'::bpchar,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    constraint "sys_dept_pk" primary key (dept_id)
+);
+
+comment on table sys_dept               is '閮ㄩ棬琛�';
+comment on column sys_dept.dept_id      is '閮ㄩ棬ID';
+comment on column sys_dept.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_dept.parent_id    is '鐖堕儴闂↖D';
+comment on column sys_dept.ancestors    is '绁栫骇鍒楄〃';
+comment on column sys_dept.dept_name    is '閮ㄩ棬鍚嶇О';
+comment on column sys_dept.dept_category    is '閮ㄩ棬绫诲埆缂栫爜';
+comment on column sys_dept.order_num    is '鏄剧ず椤哄簭';
+comment on column sys_dept.leader       is '璐熻矗浜�';
+comment on column sys_dept.phone        is '鑱旂郴鐢佃瘽';
+comment on column sys_dept.email        is '閭';
+comment on column sys_dept.status       is '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_dept.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_dept.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_dept.create_by    is '鍒涘缓鑰�';
+comment on column sys_dept.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_dept.update_by    is '鏇存柊鑰�';
+comment on column sys_dept.update_time  is '鏇存柊鏃堕棿';
+
+-- ----------------------------
+-- 鍒濆鍖�-閮ㄩ棬琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_dept values(100, '000000', 0,   '0',          'XXX绉戞妧',   null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(101, '000000', 100, '0,100',      '娣卞湷鎬诲叕鍙�', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(102, '000000', 100, '0,100',      '闀挎矙鍒嗗叕鍙�', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(103, '000000', 101, '0,100,101',  '鐮斿彂閮ㄩ棬',   null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(104, '000000', 101, '0,100,101',  '甯傚満閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(105, '000000', 101, '0,100,101',  '娴嬭瘯閮ㄩ棬',   null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(106, '000000', 101, '0,100,101',  '璐㈠姟閮ㄩ棬',   null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(107, '000000', 101, '0,100,101',  '杩愮淮閮ㄩ棬',   null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(108, '000000', 102, '0,100,102',  '甯傚満閮ㄩ棬',   null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+insert into sys_dept values(109, '000000', 102, '0,100,102',  '璐㈠姟閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null);
+
+-- ----------------------------
+-- 2銆佺敤鎴蜂俊鎭〃
+-- ----------------------------
+create table if not exists sys_user
+(
+    user_id     int8,
+    tenant_id   varchar(20)  default '000000'::varchar,
+    dept_id     int8,
+    user_name   varchar(30)  not null,
+    nick_name   varchar(30)  not null,
+    user_type   varchar(10)  default 'sys_user'::varchar,
+    email       varchar(50)  default ''::varchar,
+    phonenumber varchar(11)  default ''::varchar,
+    sex         char         default '0'::bpchar,
+    avatar      int8,
+    password    varchar(100) default ''::varchar,
+    status      char         default '0'::bpchar,
+    del_flag    char         default '0'::bpchar,
+    login_ip    varchar(128) default ''::varchar,
+    login_date  timestamp,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    remark      varchar(500) default null::varchar,
+    constraint "sys_user_pk" primary key (user_id)
+);
+
+comment on table sys_user               is '鐢ㄦ埛淇℃伅琛�';
+comment on column sys_user.user_id      is '鐢ㄦ埛ID';
+comment on column sys_user.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_user.dept_id      is '閮ㄩ棬ID';
+comment on column sys_user.user_name    is '鐢ㄦ埛璐﹀彿';
+comment on column sys_user.nick_name    is '鐢ㄦ埛鏄电О';
+comment on column sys_user.user_type    is '鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�';
+comment on column sys_user.email        is '鐢ㄦ埛閭';
+comment on column sys_user.phonenumber  is '鎵嬫満鍙风爜';
+comment on column sys_user.sex          is '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�';
+comment on column sys_user.avatar       is '澶村儚鍦板潃';
+comment on column sys_user.password     is '瀵嗙爜';
+comment on column sys_user.status       is '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_user.del_flag     is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_user.login_ip     is '鏈�鍚庣櫥闄咺P';
+comment on column sys_user.login_date   is '鏈�鍚庣櫥闄嗘椂闂�';
+comment on column sys_user.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_user.create_by    is '鍒涘缓鑰�';
+comment on column sys_user.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_user.update_by    is '鏇存柊鑰�';
+comment on column sys_user.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_user.remark       is '澶囨敞';
+
+-- ----------------------------
+
+-- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_user values(1, '000000', 103, 'admin', '鐤媯鐨勭嫯瀛怢i', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '绠$悊鍛�');
+insert into sys_user VALUES(3, '000000', 108, 'test', '鏈儴闂ㄥ強浠ヤ笅 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 3, now(), NULL);
+insert into sys_user VALUES(4, '000000', 102, 'test1', '浠呮湰浜� 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 4, now(), NULL);
+
+-- ----------------------------
+-- 3銆佸矖浣嶄俊鎭〃
+-- ----------------------------
+create table if not exists sys_post
+(
+    post_id     int8,
+    tenant_id   varchar(20) default '000000'::varchar,
+    dept_id     int8,
+    post_code   varchar(64) not null,
+    post_category   varchar(100) default null,
+    post_name   varchar(50) not null,
+    post_sort   int4        not null,
+    status      char        not null,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    remark      varchar(500) default null::varchar,
+    constraint "sys_post_pk" primary key (post_id)
+);
+
+comment on table sys_post               is '宀椾綅淇℃伅琛�';
+comment on column sys_post.post_id      is '宀椾綅ID';
+comment on column sys_post.tenant_id    is '绉熸埛缂栧彿';
+comment on column sys_post.dept_id      is '閮ㄩ棬id';
+comment on column sys_post.post_code    is '宀椾綅缂栫爜';
+comment on column sys_post.post_category is '宀椾綅绫诲埆缂栫爜';
+comment on column sys_post.post_name    is '宀椾綅鍚嶇О';
+comment on column sys_post.post_sort    is '鏄剧ず椤哄簭';
+comment on column sys_post.status       is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_post.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_post.create_by    is '鍒涘缓鑰�';
+comment on column sys_post.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_post.update_by    is '鏇存柊鑰�';
+comment on column sys_post.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_post.remark       is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-宀椾綅淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_post values(1, '000000', 103, 'ceo',  null, '钁d簨闀�',    1, '0', 103, 1, now(), null, null, '');
+insert into sys_post values(2, '000000', 100, 'se',   null, '椤圭洰缁忕悊',  2, '0', 103, 1, now(), null, null, '');
+insert into sys_post values(3, '000000', 100, 'hr',   null, '浜哄姏璧勬簮',  3, '0', 103, 1, now(), null, null, '');
+insert into sys_post values(4, '000000', 100, 'user', null, '鏅�氬憳宸�',  4, '0', 103, 1, now(), null, null, '');
+
+-- ----------------------------
+-- 4銆佽鑹蹭俊鎭〃
+-- ----------------------------
+create table if not exists sys_role
+(
+    role_id             int8,
+    tenant_id           varchar(20)  default '000000'::varchar,
+    role_name           varchar(30)  not null,
+    role_key            varchar(100) not null,
+    role_sort           int4         not null,
+    data_scope          char         default '1'::bpchar,
+    menu_check_strictly bool         default true,
+    dept_check_strictly bool         default true,
+    status              char         not null,
+    del_flag            char         default '0'::bpchar,
+    create_dept         int8,
+    create_by           int8,
+    create_time         timestamp,
+    update_by           int8,
+    update_time         timestamp,
+    remark              varchar(500) default null::varchar,
+    constraint "sys_role_pk" primary key (role_id)
+);
+
+comment on table sys_role                       is '瑙掕壊淇℃伅琛�';
+comment on column sys_role.role_id              is '瑙掕壊ID';
+comment on column sys_role.tenant_id            is '绉熸埛缂栧彿';
+comment on column sys_role.role_name            is '瑙掕壊鍚嶇О';
+comment on column sys_role.role_key             is '瑙掕壊鏉冮檺瀛楃涓�';
+comment on column sys_role.role_sort            is '鏄剧ず椤哄簭';
+comment on column sys_role.data_scope           is '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級';
+comment on column sys_role.menu_check_strictly  is '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+comment on column sys_role.dept_check_strictly  is '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+comment on column sys_role.status               is '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_role.del_flag             is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_role.create_dept          is '鍒涘缓閮ㄩ棬';
+comment on column sys_role.create_by            is '鍒涘缓鑰�';
+comment on column sys_role.create_time          is '鍒涘缓鏃堕棿';
+comment on column sys_role.update_by            is '鏇存柊鑰�';
+comment on column sys_role.update_time          is '鏇存柊鏃堕棿';
+comment on column sys_role.remark               is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_role values('1', '000000', '瓒呯骇绠$悊鍛�',  'superadmin',  1, '1', 't', 't', '0', '0', 103, 1, now(), null, null, '瓒呯骇绠$悊鍛�');
+insert into sys_role values('3', '000000', '鏈儴闂ㄥ強浠ヤ笅', 'test1', 3, '4', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, '');
+insert into sys_role values('4', '000000', '浠呮湰浜�', 'test2', 4, '5', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, '');
+
+-- ----------------------------
+-- 5銆佽彍鍗曟潈闄愯〃
+-- ----------------------------
+create table if not exists sys_menu
+(
+    menu_id     int8,
+    menu_name   varchar(50) not null,
+    parent_id   int8         default 0,
+    order_num   int4         default 0,
+    path        varchar(200) default ''::varchar,
+    component   varchar(255) default null::varchar,
+    query_param varchar(255) default null::varchar,
+    is_frame    char         default '1'::bpchar,
+    is_cache    char         default '0'::bpchar,
+    menu_type   char         default ''::bpchar,
+    visible     char         default '0'::bpchar,
+    status      char         default '0'::bpchar,
+    perms       varchar(100) default null::varchar,
+    icon        varchar(100) default '#'::varchar,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    remark      varchar(500) default ''::varchar,
+    constraint "sys_menu_pk" primary key (menu_id)
+);
+
+comment on table sys_menu               is '鑿滃崟鏉冮檺琛�';
+comment on column sys_menu.menu_id      is '鑿滃崟ID';
+comment on column sys_menu.menu_name    is '鑿滃崟鍚嶇О';
+comment on column sys_menu.parent_id    is '鐖惰彍鍗旾D';
+comment on column sys_menu.order_num    is '鏄剧ず椤哄簭';
+comment on column sys_menu.path         is '璺敱鍦板潃';
+comment on column sys_menu.component    is '缁勪欢璺緞';
+comment on column sys_menu.query_param  is '璺敱鍙傛暟';
+comment on column sys_menu.is_frame     is '鏄惁涓哄閾撅紙0鏄� 1鍚︼級';
+comment on column sys_menu.is_cache     is '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級';
+comment on column sys_menu.menu_type    is '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�';
+comment on column sys_menu.visible      is '鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�';
+comment on column sys_menu.status       is '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_menu.perms        is '鏉冮檺鏍囪瘑';
+comment on column sys_menu.icon         is '鑿滃崟鍥炬爣';
+comment on column sys_menu.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column sys_menu.create_by    is '鍒涘缓鑰�';
+comment on column sys_menu.create_time  is '鍒涘缓鏃堕棿';
+comment on column sys_menu.update_by    is '鏇存柊鑰�';
+comment on column sys_menu.update_time  is '鏇存柊鏃堕棿';
+comment on column sys_menu.remark       is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-鑿滃崟淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+-- 涓�绾ц彍鍗�
+insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',           null, '', '1', '0', 'M', '0', '0', '', 'system',   103, 1, now(), null, null, '绯荤粺绠$悊鐩綍');
+insert into sys_menu values('6', '绯荤粺绠$悊', '0', '2', 'tenant',           null, '', '1', '0', 'M', '0', '0', '', 'chart',    103, 1, now(), null, null, '绉熸埛绠$悊鐩綍');
+insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '3', 'monitor',          null, '', '1', '0', 'M', '0', '0', '', 'monitor',  103, 1, now(), null, null, '绯荤粺鐩戞帶鐩綍');
+insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '4', 'tool',             null, '', '1', '0', 'M', '0', '0', '', 'tool',     103, 1, now(), null, null, '绯荤粺宸ュ叿鐩綍');
+insert into sys_menu values('4', 'PLUS瀹樼綉', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide',    103, 1, now(), null, null, 'RuoYi-Vue-Plus瀹樼綉鍦板潃');
+insert into sys_menu VALUES('5', '娴嬭瘯鑿滃崟', '0', '5', 'demo',             null, '', '1', '0', 'M', '0', '0', null, 'star',       103, 1, now(), null, null, '娴嬭瘯鑿滃崟');
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('100',  '鐢ㄦ埛绠$悊',     '1',   '1', 'user',             'system/user/index',            '', '1', '0', 'C', '0', '0', 'system:user:list',            'user',          103, 1, now(), null, null, '鐢ㄦ埛绠$悊鑿滃崟');
+insert into sys_menu values('101',  '瑙掕壊绠$悊',     '1',   '2', 'role',             'system/role/index',            '', '1', '0', 'C', '0', '0', 'system:role:list',            'peoples',       103, 1, now(), null, null, '瑙掕壊绠$悊鑿滃崟');
+insert into sys_menu values('102',  '鑿滃崟绠$悊',     '1',   '3', 'menu',             'system/menu/index',            '', '1', '0', 'C', '0', '0', 'system:menu:list',            'tree-table',    103, 1, now(), null, null, '鑿滃崟绠$悊鑿滃崟');
+insert into sys_menu values('103',  '閮ㄩ棬绠$悊',     '1',   '4', 'dept',             'system/dept/index',            '', '1', '0', 'C', '0', '0', 'system:dept:list',            'tree',          103, 1, now(), null, null, '閮ㄩ棬绠$悊鑿滃崟');
+insert into sys_menu values('104',  '宀椾綅绠$悊',     '1',   '5', 'post',             'system/post/index',            '', '1', '0', 'C', '0', '0', 'system:post:list',            'post',          103, 1, now(), null, null, '宀椾綅绠$悊鑿滃崟');
+insert into sys_menu values('105',  '瀛楀吀绠$悊',     '1',   '6', 'dict',             'system/dict/index',            '', '1', '0', 'C', '0', '0', 'system:dict:list',            'dict',          103, 1, now(), null, null, '瀛楀吀绠$悊鑿滃崟');
+insert into sys_menu values('106',  '鍙傛暟璁剧疆',     '1',   '7', 'config',           'system/config/index',          '', '1', '0', 'C', '0', '0', 'system:config:list',          'edit',          103, 1, now(), null, null, '鍙傛暟璁剧疆鑿滃崟');
+insert into sys_menu values('107',  '閫氱煡鍏憡',     '1',   '8', 'notice',           'system/notice/index',          '', '1', '0', 'C', '0', '0', 'system:notice:list',          'message',       103, 1, now(), null, null, '閫氱煡鍏憡鑿滃崟');
+insert into sys_menu values('108',  '鏃ュ織绠$悊',     '1',   '9', 'log',              '',                             '', '1', '0', 'M', '0', '0', '',                            'log',           103, 1, now(), null, null, '鏃ュ織绠$悊鑿滃崟');
+insert into sys_menu values('109',  '鍦ㄧ嚎鐢ㄦ埛',     '2',   '1', 'online',           'monitor/online/index',         '', '1', '0', 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, now(), null, null, '鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+insert into sys_menu values('113',  '缂撳瓨鐩戞帶',     '2',   '5', 'cache',            'monitor/cache/index',          '', '1', '0', 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, now(), null, null, '缂撳瓨鐩戞帶鑿滃崟');
+insert into sys_menu values('115',  '浠g爜鐢熸垚',     '3',   '2', 'gen',              'tool/gen/index',               '', '1', '0', 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, now(), null, null, '浠g爜鐢熸垚鑿滃崟');
+insert into sys_menu values('121',  '绉熸埛绠$悊',     '6',   '1', 'tenant',           'system/tenant/index',          '', '1', '0', 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, now(), null, null, '绉熸埛绠$悊鑿滃崟');
+insert into sys_menu values('122',  '绉熸埛濂楅绠$悊', '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', '1', '0', 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, now(), null, null, '绉熸埛濂楅绠$悊鑿滃崟');
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', '1', '0', 'C', '0', '0', 'system:client:list',          'international', 103, 1, now(), null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+
+-- springboot-admin鐩戞帶
+insert into sys_menu values('117',  'Admin鐩戞帶',   '2',   '5',  'Admin',            'monitor/admin/index',         '', '1', '0', 'C', '0', '0', 'monitor:admin:list',          'dashboard',     103, 1, now(), null, null, 'Admin鐩戞帶鑿滃崟');
+-- oss鑿滃崟
+insert into sys_menu values('118',  '鏂囦欢绠$悊',     '1',   '10', 'oss',              'system/oss/index',            '', '1', '0', 'C', '0', '0', 'system:oss:list',             'upload',        103, 1, now(), null, null, '鏂囦欢绠$悊鑿滃崟');
+-- snail-job server鎺у埗鍙�
+insert into sys_menu values('120',  '浠诲姟璋冨害涓績',  '2',   '6',  'snailjob',     'monitor/snailjob/index',    '', '1', '0', 'C', '0', '0', 'monitor:snailjob:list',          'job',           103, 1, now(), null, null, 'SnailJob鎺у埗鍙拌彍鍗�');
+
+-- 涓夌骇鑿滃崟
+insert into sys_menu values('500',  '鎿嶄綔鏃ュ織', '108', '1', 'operlog',    'monitor/operlog/index',    '', '1', '0', 'C', '0', '0', 'monitor:operlog:list',    'form',          103, 1, now(), null, null, '鎿嶄綔鏃ュ織鑿滃崟');
+insert into sys_menu values('501',  '鐧诲綍鏃ュ織', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '1', '0', 'C', '0', '0', 'monitor:logininfor:list', 'logininfor',    103, 1, now(), null, null, '鐧诲綍鏃ュ織鑿滃崟');
+-- 鐢ㄦ埛绠$悊鎸夐挳
+insert into sys_menu values('1001', '鐢ㄦ埛鏌ヨ', '100', '1',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1002', '鐢ㄦ埛鏂板', '100', '2',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1003', '鐢ㄦ埛淇敼', '100', '3',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1004', '鐢ㄦ埛鍒犻櫎', '100', '4',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:remove',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1005', '鐢ㄦ埛瀵煎嚭', '100', '5',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:export',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1006', '鐢ㄦ埛瀵煎叆', '100', '6',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:import',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1007', '閲嶇疆瀵嗙爜', '100', '7',  '', '', '', '1', '0', 'F', '0', '0', 'system:user:resetPwd',       '#', 103, 1, now(), null, null, '');
+-- 瑙掕壊绠$悊鎸夐挳
+insert into sys_menu values('1008', '瑙掕壊鏌ヨ', '101', '1',  '', '', '', '1', '0', 'F', '0', '0', 'system:role:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1009', '瑙掕壊鏂板', '101', '2',  '', '', '', '1', '0', 'F', '0', '0', 'system:role:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1010', '瑙掕壊淇敼', '101', '3',  '', '', '', '1', '0', 'F', '0', '0', 'system:role:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1011', '瑙掕壊鍒犻櫎', '101', '4',  '', '', '', '1', '0', 'F', '0', '0', 'system:role:remove',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1012', '瑙掕壊瀵煎嚭', '101', '5',  '', '', '', '1', '0', 'F', '0', '0', 'system:role:export',         '#', 103, 1, now(), null, null, '');
+-- 鑿滃崟绠$悊鎸夐挳
+insert into sys_menu values('1013', '鑿滃崟鏌ヨ', '102', '1',  '', '', '', '1', '0', 'F', '0', '0', 'system:menu:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1014', '鑿滃崟鏂板', '102', '2',  '', '', '', '1', '0', 'F', '0', '0', 'system:menu:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1015', '鑿滃崟淇敼', '102', '3',  '', '', '', '1', '0', 'F', '0', '0', 'system:menu:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1016', '鑿滃崟鍒犻櫎', '102', '4',  '', '', '', '1', '0', 'F', '0', '0', 'system:menu:remove',         '#', 103, 1, now(), null, null, '');
+-- 閮ㄩ棬绠$悊鎸夐挳
+insert into sys_menu values('1017', '閮ㄩ棬鏌ヨ', '103', '1',  '', '', '', '1', '0', 'F', '0', '0', 'system:dept:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1018', '閮ㄩ棬鏂板', '103', '2',  '', '', '', '1', '0', 'F', '0', '0', 'system:dept:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1019', '閮ㄩ棬淇敼', '103', '3',  '', '', '', '1', '0', 'F', '0', '0', 'system:dept:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1020', '閮ㄩ棬鍒犻櫎', '103', '4',  '', '', '', '1', '0', 'F', '0', '0', 'system:dept:remove',         '#', 103, 1, now(), null, null, '');
+-- 宀椾綅绠$悊鎸夐挳
+insert into sys_menu values('1021', '宀椾綅鏌ヨ', '104', '1',  '', '', '', '1', '0', 'F', '0', '0', 'system:post:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1022', '宀椾綅鏂板', '104', '2',  '', '', '', '1', '0', 'F', '0', '0', 'system:post:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1023', '宀椾綅淇敼', '104', '3',  '', '', '', '1', '0', 'F', '0', '0', 'system:post:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1024', '宀椾綅鍒犻櫎', '104', '4',  '', '', '', '1', '0', 'F', '0', '0', 'system:post:remove',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1025', '宀椾綅瀵煎嚭', '104', '5',  '', '', '', '1', '0', 'F', '0', '0', 'system:post:export',         '#', 103, 1, now(), null, null, '');
+-- 瀛楀吀绠$悊鎸夐挳
+insert into sys_menu values('1026', '瀛楀吀鏌ヨ', '105', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:query',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1027', '瀛楀吀鏂板', '105', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:add',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1028', '瀛楀吀淇敼', '105', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:edit',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1029', '瀛楀吀鍒犻櫎', '105', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:remove',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1030', '瀛楀吀瀵煎嚭', '105', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:export',         '#', 103, 1, now(), null, null, '');
+-- 鍙傛暟璁剧疆鎸夐挳
+insert into sys_menu values('1031', '鍙傛暟鏌ヨ', '106', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:query',        '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1032', '鍙傛暟鏂板', '106', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:add',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1033', '鍙傛暟淇敼', '106', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:edit',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1034', '鍙傛暟鍒犻櫎', '106', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:remove',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1035', '鍙傛暟瀵煎嚭', '106', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:export',       '#', 103, 1, now(), null, null, '');
+-- 閫氱煡鍏憡鎸夐挳
+insert into sys_menu values('1036', '鍏憡鏌ヨ', '107', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:query',        '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1037', '鍏憡鏂板', '107', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:add',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1038', '鍏憡淇敼', '107', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:edit',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1039', '鍏憡鍒犻櫎', '107', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:remove',       '#', 103, 1, now(), null, null, '');
+-- 鎿嶄綔鏃ュ織鎸夐挳
+insert into sys_menu values('1040', '鎿嶄綔鏌ヨ', '500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:query',      '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1041', '鎿嶄綔鍒犻櫎', '500', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:remove',     '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1042', '鏃ュ織瀵煎嚭', '500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:export',     '#', 103, 1, now(), null, null, '');
+-- 鐧诲綍鏃ュ織鎸夐挳
+insert into sys_menu values('1043', '鐧诲綍鏌ヨ', '501', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:query',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1044', '鐧诲綍鍒犻櫎', '501', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:remove',  '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1045', '鏃ュ織瀵煎嚭', '501', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:export',  '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1050', '璐︽埛瑙i攣', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 103, 1, now(), null, null, '');
+-- 鍦ㄧ嚎鐢ㄦ埛鎸夐挳
+insert into sys_menu values('1046', '鍦ㄧ嚎鏌ヨ', '109', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:query',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1047', '鎵归噺寮洪��', '109', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1048', '鍗曟潯寮洪��', '109', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, now(), null, null, '');
+-- 浠g爜鐢熸垚鎸夐挳
+insert into sys_menu values('1055', '鐢熸垚鏌ヨ', '115', '1', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:query',             '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1056', '鐢熸垚淇敼', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:edit',              '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1057', '鐢熸垚鍒犻櫎', '115', '3', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:remove',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1058', '瀵煎叆浠g爜', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:import',            '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1059', '棰勮浠g爜', '115', '4', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:preview',           '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1060', '鐢熸垚浠g爜', '115', '5', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:code',              '#', 103, 1, now(), null, null, '');
+-- oss鐩稿叧鎸夐挳
+insert into sys_menu values('1600', '鏂囦欢鏌ヨ', '118', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:query',        '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1601', '鏂囦欢涓婁紶', '118', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:upload',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1602', '鏂囦欢涓嬭浇', '118', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:download',     '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1603', '鏂囦欢鍒犻櫎', '118', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:remove',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add',    '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, '');
+-- 绉熸埛绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values('1606', '绉熸埛鏌ヨ', '121', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:query',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1607', '绉熸埛鏂板', '121', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:add',     '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1608', '绉熸埛淇敼', '121', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:edit',    '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1609', '绉熸埛鍒犻櫎', '121', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:remove',  '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1610', '绉熸埛瀵煎嚭', '121', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:export',  '#', 103, 1, now(), null, null, '');
+-- 绉熸埛濂楅绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values('1611', '绉熸埛濂楅鏌ヨ', '122', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:query',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1612', '绉熸埛濂楅鏂板', '122', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:add',     '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1613', '绉熸埛濂楅淇敼', '122', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:edit',    '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1614', '绉熸埛濂楅鍒犻櫎', '122', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:remove',  '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1615', '绉熸埛濂楅瀵煎嚭', '122', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:export',  '#', 103, 1, now(), null, null, '');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query',        '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export',       '#', 103, 1, now(), null, null, '');
+-- 娴嬭瘯鑿滃崟
+INSERT INTO sys_menu VALUES('1500', '娴嬭瘯鍗曡〃',     '5',   '1', 'demo', 'demo/demo/index', '',  '1', '0', 'C', '0', '0', 'demo:demo:list', '#', 103, 1, now(), NULL, NULL, '娴嬭瘯鍗曡〃鑿滃崟');
+INSERT INTO sys_menu VALUES('1501', '娴嬭瘯鍗曡〃鏌ヨ', '1500', '1', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:demo:query',                  '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1502', '娴嬭瘯鍗曡〃鏂板', '1500', '2', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:demo:add',                    '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1503', '娴嬭瘯鍗曡〃淇敼', '1500', '3', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:demo:edit',                   '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1504', '娴嬭瘯鍗曡〃鍒犻櫎', '1500', '4', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:demo:remove',                 '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1505', '娴嬭瘯鍗曡〃瀵煎嚭', '1500', '5', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:demo:export',                 '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1506', '娴嬭瘯鏍戣〃',     '5',   '1', 'tree', 'demo/tree/index', '',  '1', '0', 'C', '0', '0', 'demo:tree:list', '#', 103, 1, now(), NULL, NULL, '娴嬭瘯鏍戣〃鑿滃崟');
+INSERT INTO sys_menu VALUES('1507', '娴嬭瘯鏍戣〃鏌ヨ', '1506', '1', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:tree:query',                  '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1508', '娴嬭瘯鏍戣〃鏂板', '1506', '2', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:tree:add',                    '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1509', '娴嬭瘯鏍戣〃淇敼', '1506', '3', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:tree:edit',                   '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1510', '娴嬭瘯鏍戣〃鍒犻櫎', '1506', '4', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:tree:remove',                 '#', 103, 1, now(), NULL, NULL, '');
+INSERT INTO sys_menu VALUES('1511', '娴嬭瘯鏍戣〃瀵煎嚭', '1506', '5', '#', '', '',  '1', '0', 'F', '0', '0', 'demo:tree:export',                 '#', 103, 1, now(), NULL, NULL, '');
+
+
+-- ----------------------------
+-- 6銆佺敤鎴峰拰瑙掕壊鍏宠仈琛�  鐢ㄦ埛N-1瑙掕壊
+-- ----------------------------
+create table if not exists sys_user_role
+(
+    user_id int8 not null,
+    role_id int8 not null,
+    constraint sys_user_role_pk primary key (user_id, role_id)
+);
+
+comment on table sys_user_role              is '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+comment on column sys_user_role.user_id     is '鐢ㄦ埛ID';
+comment on column sys_user_role.role_id     is '瑙掕壊ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛鍜岃鑹插叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_role values ('1', '1');
+insert into sys_user_role values ('3', '3');
+insert into sys_user_role values ('4', '4');
+
+-- ----------------------------
+-- 7銆佽鑹插拰鑿滃崟鍏宠仈琛�  瑙掕壊1-N鑿滃崟
+-- ----------------------------
+create table if not exists sys_role_menu
+(
+    role_id int8 not null,
+    menu_id int8 not null,
+    constraint sys_role_menu_pk primary key (role_id, menu_id)
+);
+
+comment on table sys_role_menu              is '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+comment on column sys_role_menu.role_id     is '瑙掕壊ID';
+comment on column sys_role_menu.menu_id     is '鑿滃崟ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_menu values ('3', '1');
+insert into sys_role_menu values ('3', '5');
+insert into sys_role_menu values ('3', '100');
+insert into sys_role_menu values ('3', '101');
+insert into sys_role_menu values ('3', '102');
+insert into sys_role_menu values ('3', '103');
+insert into sys_role_menu values ('3', '104');
+insert into sys_role_menu values ('3', '105');
+insert into sys_role_menu values ('3', '106');
+insert into sys_role_menu values ('3', '107');
+insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '500');
+insert into sys_role_menu values ('3', '501');
+insert into sys_role_menu values ('3', '1001');
+insert into sys_role_menu values ('3', '1002');
+insert into sys_role_menu values ('3', '1003');
+insert into sys_role_menu values ('3', '1004');
+insert into sys_role_menu values ('3', '1005');
+insert into sys_role_menu values ('3', '1006');
+insert into sys_role_menu values ('3', '1007');
+insert into sys_role_menu values ('3', '1008');
+insert into sys_role_menu values ('3', '1009');
+insert into sys_role_menu values ('3', '1010');
+insert into sys_role_menu values ('3', '1011');
+insert into sys_role_menu values ('3', '1012');
+insert into sys_role_menu values ('3', '1013');
+insert into sys_role_menu values ('3', '1014');
+insert into sys_role_menu values ('3', '1015');
+insert into sys_role_menu values ('3', '1016');
+insert into sys_role_menu values ('3', '1017');
+insert into sys_role_menu values ('3', '1018');
+insert into sys_role_menu values ('3', '1019');
+insert into sys_role_menu values ('3', '1020');
+insert into sys_role_menu values ('3', '1021');
+insert into sys_role_menu values ('3', '1022');
+insert into sys_role_menu values ('3', '1023');
+insert into sys_role_menu values ('3', '1024');
+insert into sys_role_menu values ('3', '1025');
+insert into sys_role_menu values ('3', '1026');
+insert into sys_role_menu values ('3', '1027');
+insert into sys_role_menu values ('3', '1028');
+insert into sys_role_menu values ('3', '1029');
+insert into sys_role_menu values ('3', '1030');
+insert into sys_role_menu values ('3', '1031');
+insert into sys_role_menu values ('3', '1032');
+insert into sys_role_menu values ('3', '1033');
+insert into sys_role_menu values ('3', '1034');
+insert into sys_role_menu values ('3', '1035');
+insert into sys_role_menu values ('3', '1036');
+insert into sys_role_menu values ('3', '1037');
+insert into sys_role_menu values ('3', '1038');
+insert into sys_role_menu values ('3', '1039');
+insert into sys_role_menu values ('3', '1040');
+insert into sys_role_menu values ('3', '1041');
+insert into sys_role_menu values ('3', '1042');
+insert into sys_role_menu values ('3', '1043');
+insert into sys_role_menu values ('3', '1044');
+insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1500');
+insert into sys_role_menu values ('3', '1501');
+insert into sys_role_menu values ('3', '1502');
+insert into sys_role_menu values ('3', '1503');
+insert into sys_role_menu values ('3', '1504');
+insert into sys_role_menu values ('3', '1505');
+insert into sys_role_menu values ('3', '1506');
+insert into sys_role_menu values ('3', '1507');
+insert into sys_role_menu values ('3', '1508');
+insert into sys_role_menu values ('3', '1509');
+insert into sys_role_menu values ('3', '1510');
+insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('4', '5');
+insert into sys_role_menu values ('4', '1500');
+insert into sys_role_menu values ('4', '1501');
+insert into sys_role_menu values ('4', '1502');
+insert into sys_role_menu values ('4', '1503');
+insert into sys_role_menu values ('4', '1504');
+insert into sys_role_menu values ('4', '1505');
+insert into sys_role_menu values ('4', '1506');
+insert into sys_role_menu values ('4', '1507');
+insert into sys_role_menu values ('4', '1508');
+insert into sys_role_menu values ('4', '1509');
+insert into sys_role_menu values ('4', '1510');
+insert into sys_role_menu values ('4', '1511');
+
+-- ----------------------------
+-- 8銆佽鑹插拰閮ㄩ棬鍏宠仈琛�  瑙掕壊1-N閮ㄩ棬
+-- ----------------------------
+create table if not exists sys_role_dept
+(
+    role_id int8 not null,
+    dept_id int8 not null,
+    constraint sys_role_dept_pk primary key (role_id, dept_id)
+);
+
+comment on table sys_role_dept              is '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+comment on column sys_role_dept.role_id     is '瑙掕壊ID';
+comment on column sys_role_dept.dept_id     is '閮ㄩ棬ID';
+
+
+-- ----------------------------
+-- 9銆佺敤鎴蜂笌宀椾綅鍏宠仈琛�  鐢ㄦ埛1-N宀椾綅
+-- ----------------------------
+create table if not exists sys_user_post
+(
+    user_id int8 not null,
+    post_id int8 not null,
+    constraint sys_user_post_pk primary key (user_id, post_id)
+);
+
+comment on table sys_user_post              is '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+comment on column sys_user_post.user_id     is '鐢ㄦ埛ID';
+comment on column sys_user_post.post_id     is '宀椾綅ID';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_post values ('1', '1');
+
+-- ----------------------------
+-- 10銆佹搷浣滄棩蹇楄褰�
+-- ----------------------------
+create table if not exists sys_oper_log
+(
+    oper_id        int8,
+    tenant_id      varchar(20)   default '000000'::varchar,
+    title          varchar(50)   default ''::varchar,
+    business_type  int4          default 0,
+    method         varchar(100)  default ''::varchar,
+    request_method varchar(10)   default ''::varchar,
+    operator_type  int4          default 0,
+    oper_name      varchar(50)   default ''::varchar,
+    dept_name      varchar(50)   default ''::varchar,
+    oper_url       varchar(255)  default ''::varchar,
+    oper_ip        varchar(128)  default ''::varchar,
+    oper_location  varchar(255)  default ''::varchar,
+    oper_param     varchar(2000) default ''::varchar,
+    json_result    varchar(2000) default ''::varchar,
+    status         int4          default 0,
+    error_msg      varchar(2000) default ''::varchar,
+    oper_time      timestamp,
+    cost_time      int8          default 0,
+    constraint sys_oper_log_pk primary key (oper_id)
+);
+
+create index idx_sys_oper_log_bt ON sys_oper_log (business_type);
+create index idx_sys_oper_log_s ON sys_oper_log (status);
+create index idx_sys_oper_log_ot ON sys_oper_log (oper_time);
+
+comment on table sys_oper_log                   is '鎿嶄綔鏃ュ織璁板綍';
+comment on column sys_oper_log.oper_id          is '鏃ュ織涓婚敭';
+comment on column sys_oper_log.tenant_id        is '绉熸埛缂栧彿';
+comment on column sys_oper_log.title            is '妯″潡鏍囬';
+comment on column sys_oper_log.business_type    is '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�';
+comment on column sys_oper_log.method           is '鏂规硶鍚嶇О';
+comment on column sys_oper_log.request_method   is '璇锋眰鏂瑰紡';
+comment on column sys_oper_log.operator_type    is '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級';
+comment on column sys_oper_log.oper_name        is '鎿嶄綔浜哄憳';
+comment on column sys_oper_log.dept_name        is '閮ㄩ棬鍚嶇О';
+comment on column sys_oper_log.oper_url         is '璇锋眰URL';
+comment on column sys_oper_log.oper_ip          is '涓绘満鍦板潃';
+comment on column sys_oper_log.oper_location    is '鎿嶄綔鍦扮偣';
+comment on column sys_oper_log.oper_param       is '璇锋眰鍙傛暟';
+comment on column sys_oper_log.json_result      is '杩斿洖鍙傛暟';
+comment on column sys_oper_log.status           is '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�';
+comment on column sys_oper_log.error_msg        is '閿欒娑堟伅';
+comment on column sys_oper_log.oper_time        is '鎿嶄綔鏃堕棿';
+comment on column sys_oper_log.cost_time        is '娑堣�楁椂闂�';
+
+-- ----------------------------
+-- 11銆佸瓧鍏哥被鍨嬭〃
+-- ----------------------------
+create table if not exists sys_dict_type
+(
+    dict_id     int8,
+    tenant_id   varchar(20)  default '000000'::varchar,
+    dict_name   varchar(100) default ''::varchar,
+    dict_type   varchar(100) default ''::varchar,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    remark      varchar(500) default null::varchar,
+    constraint sys_dict_type_pk primary key (dict_id)
+);
+
+create unique index sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type);
+
+comment on table sys_dict_type                  is '瀛楀吀绫诲瀷琛�';
+comment on column sys_dict_type.dict_id         is '瀛楀吀涓婚敭';
+comment on column sys_dict_type.tenant_id       is '绉熸埛缂栧彿';
+comment on column sys_dict_type.dict_name       is '瀛楀吀鍚嶇О';
+comment on column sys_dict_type.dict_type       is '瀛楀吀绫诲瀷';
+comment on column sys_dict_type.create_dept     is '鍒涘缓閮ㄩ棬';
+comment on column sys_dict_type.create_by       is '鍒涘缓鑰�';
+comment on column sys_dict_type.create_time     is '鍒涘缓鏃堕棿';
+comment on column sys_dict_type.update_by       is '鏇存柊鑰�';
+comment on column sys_dict_type.update_time     is '鏇存柊鏃堕棿';
+comment on column sys_dict_type.remark          is '澶囨敞';
+
+insert into sys_dict_type values(1, '000000', '鐢ㄦ埛鎬у埆', 'sys_user_sex',        103, 1, now(), null, null, '鐢ㄦ埛鎬у埆鍒楄〃');
+insert into sys_dict_type values(2, '000000', '鑿滃崟鐘舵��', 'sys_show_hide',       103, 1, now(), null, null, '鑿滃崟鐘舵�佸垪琛�');
+insert into sys_dict_type values(3, '000000', '绯荤粺寮�鍏�', 'sys_normal_disable',  103, 1, now(), null, null, '绯荤粺寮�鍏冲垪琛�');
+insert into sys_dict_type values(6, '000000', '绯荤粺鏄惁', 'sys_yes_no',          103, 1, now(), null, null, '绯荤粺鏄惁鍒楄〃');
+insert into sys_dict_type values(7, '000000', '閫氱煡绫诲瀷', 'sys_notice_type',     103, 1, now(), null, null, '閫氱煡绫诲瀷鍒楄〃');
+insert into sys_dict_type values(8, '000000', '閫氱煡鐘舵��', 'sys_notice_status',   103, 1, now(), null, null, '閫氱煡鐘舵�佸垪琛�');
+insert into sys_dict_type values(9, '000000', '鎿嶄綔绫诲瀷', 'sys_oper_type',       103, 1, now(), null, null, '鎿嶄綔绫诲瀷鍒楄〃');
+insert into sys_dict_type values(10, '000000', '绯荤粺鐘舵��', 'sys_common_status',  103, 1, now(), null, null, '鐧诲綍鐘舵�佸垪琛�');
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     103, 1, now(), null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    103, 1, now(), null, null, '瀹㈡埛绔澶囩被鍨�');
+
+-- ----------------------------
+-- 12銆佸瓧鍏告暟鎹〃
+-- ----------------------------
+create table if not exists sys_dict_data
+(
+    dict_code   int8,
+    tenant_id   varchar(20)  default '000000'::varchar,
+    dict_sort   int4         default 0,
+    dict_label  varchar(100) default ''::varchar,
+    dict_value  varchar(100) default ''::varchar,
+    dict_type   varchar(100) default ''::varchar,
+    css_class   varchar(100) default null::varchar,
+    list_class  varchar(100) default null::varchar,
+    is_default  char         default 'N'::bpchar,
+    create_dept int8,
+    create_by   int8,
+    create_time timestamp,
+    update_by   int8,
+    update_time timestamp,
+    remark      varchar(500) default null::varchar,
+    constraint sys_dict_data_pk primary key (dict_code)
+);
+
+comment on table sys_dict_data                  is '瀛楀吀鏁版嵁琛�';
+comment on column sys_dict_data.dict_code       is '瀛楀吀缂栫爜';
+comment on column sys_dict_type.tenant_id       is '绉熸埛缂栧彿';
+comment on column sys_dict_data.dict_sort       is '瀛楀吀鎺掑簭';
+comment on column sys_dict_data.dict_label      is '瀛楀吀鏍囩';
+comment on column sys_dict_data.dict_value      is '瀛楀吀閿��';
+comment on column sys_dict_data.dict_type       is '瀛楀吀绫诲瀷';
+comment on column sys_dict_data.css_class       is '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�';
+comment on column sys_dict_data.list_class      is '琛ㄦ牸鍥炴樉鏍峰紡';
+comment on column sys_dict_data.is_default      is '鏄惁榛樿锛圷鏄� N鍚︼級';
+comment on column sys_dict_data.create_dept     is '鍒涘缓閮ㄩ棬';
+comment on column sys_dict_data.create_by       is '鍒涘缓鑰�';
+comment on column sys_dict_data.create_time     is '鍒涘缓鏃堕棿';
+comment on column sys_dict_data.update_by       is '鏇存柊鑰�';
+comment on column sys_dict_data.update_time     is '鏇存柊鏃堕棿';
+comment on column sys_dict_data.remark          is '澶囨敞';
+
+insert into sys_dict_data values(1, '000000', 1,  '鐢�',       '0',       'sys_user_sex',        '',   '',        'Y', 103, 1, now(), null, null, '鎬у埆鐢�');
+insert into sys_dict_data values(2, '000000', 2,  '濂�',       '1',       'sys_user_sex',        '',   '',        'N', 103, 1, now(), null, null, '鎬у埆濂�');
+insert into sys_dict_data values(3, '000000', 3,  '鏈煡',     '2',       'sys_user_sex',        '',   '',        'N', 103, 1, now(), null, null, '鎬у埆鏈煡');
+insert into sys_dict_data values(4, '000000', 1,  '鏄剧ず',     '0',       'sys_show_hide',       '',   'primary', 'Y', 103, 1, now(), null, null, '鏄剧ず鑿滃崟');
+insert into sys_dict_data values(5, '000000', 2,  '闅愯棌',     '1',       'sys_show_hide',       '',   'danger',  'N', 103, 1, now(), null, null, '闅愯棌鑿滃崟');
+insert into sys_dict_data values(6, '000000', 1,  '姝e父',     '0',       'sys_normal_disable',  '',   'primary', 'Y', 103, 1, now(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(7, '000000', 2,  '鍋滅敤',     '1',       'sys_normal_disable',  '',   'danger',  'N', 103, 1, now(), null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(12, '000000', 1,  '鏄�',       'Y',       'sys_yes_no',          '',   'primary', 'Y', 103, 1, now(), null, null, '绯荤粺榛樿鏄�');
+insert into sys_dict_data values(13, '000000', 2,  '鍚�',       'N',       'sys_yes_no',          '',   'danger',  'N', 103, 1, now(), null, null, '绯荤粺榛樿鍚�');
+insert into sys_dict_data values(14, '000000', 1,  '閫氱煡',     '1',       'sys_notice_type',     '',   'warning', 'Y', 103, 1, now(), null, null, '閫氱煡');
+insert into sys_dict_data values(15, '000000', 2,  '鍏憡',     '2',       'sys_notice_type',     '',   'success', 'N', 103, 1, now(), null, null, '鍏憡');
+insert into sys_dict_data values(16, '000000', 1,  '姝e父',     '0',       'sys_notice_status',   '',   'primary', 'Y', 103, 1, now(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(17, '000000', 2,  '鍏抽棴',     '1',       'sys_notice_status',   '',   'danger',  'N', 103, 1, now(), null, null, '鍏抽棴鐘舵��');
+insert into sys_dict_data values(29, '000000', 99, '鍏朵粬',     '0',       'sys_oper_type',       '',   'info',    'N', 103, 1, now(), null, null, '鍏朵粬鎿嶄綔');
+insert into sys_dict_data values(18, '000000', 1,  '鏂板',     '1',       'sys_oper_type',       '',   'info',    'N', 103, 1, now(), null, null, '鏂板鎿嶄綔');
+insert into sys_dict_data values(19, '000000', 2,  '淇敼',     '2',       'sys_oper_type',       '',   'info',    'N', 103, 1, now(), null, null, '淇敼鎿嶄綔');
+insert into sys_dict_data values(20, '000000', 3,  '鍒犻櫎',     '3',       'sys_oper_type',       '',   'danger',  'N', 103, 1, now(), null, null, '鍒犻櫎鎿嶄綔');
+insert into sys_dict_data values(21, '000000', 4,  '鎺堟潈',     '4',       'sys_oper_type',       '',   'primary', 'N', 103, 1, now(), null, null, '鎺堟潈鎿嶄綔');
+insert into sys_dict_data values(22, '000000', 5,  '瀵煎嚭',     '5',       'sys_oper_type',       '',   'warning', 'N', 103, 1, now(), null, null, '瀵煎嚭鎿嶄綔');
+insert into sys_dict_data values(23, '000000', 6,  '瀵煎叆',     '6',       'sys_oper_type',       '',   'warning', 'N', 103, 1, now(), null, null, '瀵煎叆鎿嶄綔');
+insert into sys_dict_data values(24, '000000', 7,  '寮洪��',     '7',       'sys_oper_type',       '',   'danger',  'N', 103, 1, now(), null, null, '寮洪��鎿嶄綔');
+insert into sys_dict_data values(25, '000000', 8,  '鐢熸垚浠g爜', '8',       'sys_oper_type',       '',   'warning', 'N', 103, 1, now(), null, null, '鐢熸垚鎿嶄綔');
+insert into sys_dict_data values(26, '000000', 9,  '娓呯┖鏁版嵁', '9',       'sys_oper_type',       '',   'danger',  'N', 103, 1, now(), null, null, '娓呯┖鎿嶄綔');
+insert into sys_dict_data values(27, '000000', 1,  '鎴愬姛',     '0',       'sys_common_status',   '',   'primary', 'N', 103, 1, now(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(28, '000000', 2,  '澶辫触',     '1',       'sys_common_status',   '',   'danger',  'N', 103, 1, now(), null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   '',   'default', 'N', 103, 1, now(), null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   '',   'default', 'N', 103, 1, now(), null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   '',   'default', 'N', 103, 1, now(), null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   '',   'default', 'N', 103, 1, now(), null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   '',   'default', 'N', 103, 1, now(), null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC', 'pc',              'sys_device_type',   '',   'default', 'N', 103, 1, now(), null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜', 'android',       'sys_device_type',   '',   'default', 'N', 103, 1, now(), null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS', 'ios',            'sys_device_type',   '',   'default', 'N', 103, 1, now(), null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�', 'xcx',         'sys_device_type',   '',   'default', 'N', 103, 1, now(), null, null, '灏忕▼搴�');
+
+
+-- ----------------------------
+-- 13銆佸弬鏁伴厤缃〃
+-- ----------------------------
+create table if not exists sys_config
+(
+    config_id    int8,
+    tenant_id    varchar(20)  default '000000'::varchar,
+    config_name  varchar(100) default ''::varchar,
+    config_key   varchar(100) default ''::varchar,
+    config_value varchar(500) default ''::varchar,
+    config_type  char         default 'N'::bpchar,
+    create_dept  int8,
+    create_by    int8,
+    create_time  timestamp,
+    update_by    int8,
+    update_time  timestamp,
+    remark       varchar(500) default null::varchar,
+    constraint sys_config_pk primary key (config_id)
+);
+
+comment on table sys_config                 is '鍙傛暟閰嶇疆琛�';
+comment on column sys_config.config_id      is '鍙傛暟涓婚敭';
+comment on column sys_config.tenant_id      is '绉熸埛缂栧彿';
+comment on column sys_config.config_name    is '鍙傛暟鍚嶇О';
+comment on column sys_config.config_key     is '鍙傛暟閿悕';
+comment on column sys_config.config_value   is '鍙傛暟閿��';
+comment on column sys_config.config_type    is '绯荤粺鍐呯疆锛圷鏄� N鍚︼級';
+comment on column sys_config.create_dept    is '鍒涘缓閮ㄩ棬';
+comment on column sys_config.create_by      is '鍒涘缓鑰�';
+comment on column sys_config.create_time    is '鍒涘缓鏃堕棿';
+comment on column sys_config.update_by      is '鏇存柊鑰�';
+comment on column sys_config.update_time    is '鏇存柊鏃堕棿';
+comment on column sys_config.remark         is '澶囨敞';
+
+insert into sys_config values(1, '000000', '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О',     'sys.index.skinName',            'skin-blue',     'Y', 103, 1, now(), null, null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '000000', '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',         'sys.user.initPassword',         '123456',        'Y', 103, 1, now(), null, null, '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '000000', '涓绘鏋堕〉-渚ц竟鏍忎富棰�',           'sys.index.sideTheme',           'theme-dark',    'Y', 103, 1, now(), null, null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+insert into sys_config values(5, '000000', '璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�',   'sys.account.registerUser',      'false',         'Y', 103, 1, now(), null, null, '鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(11, '000000', 'OSS棰勮鍒楄〃璧勬簮寮�鍏�',          'sys.oss.previewListResource',   'true',          'Y', 103, 1, now(), null, null, 'true:寮�鍚�, false:鍏抽棴');
+
+
+-- ----------------------------
+-- 14銆佺郴缁熻闂褰�
+-- ----------------------------
+create table if not exists sys_logininfor
+(
+    info_id        int8,
+    tenant_id      varchar(20)  default '000000'::varchar,
+    user_name      varchar(50)  default ''::varchar,
+    client_key     varchar(32)  default ''::varchar,
+    device_type    varchar(32)  default ''::varchar,
+    ipaddr         varchar(128) default ''::varchar,
+    login_location varchar(255) default ''::varchar,
+    browser        varchar(50)  default ''::varchar,
+    os             varchar(50)  default ''::varchar,
+    status         char         default '0'::bpchar,
+    msg            varchar(255) default ''::varchar,
+    login_time     timestamp,
+    constraint sys_logininfor_pk primary key (info_id)
+);
+
+create index idx_sys_logininfor_s ON sys_logininfor (status);
+create index idx_sys_logininfor_lt ON sys_logininfor (login_time);
+
+comment on table sys_logininfor                 is '绯荤粺璁块棶璁板綍';
+comment on column sys_logininfor.info_id        is '璁块棶ID';
+comment on column sys_logininfor.tenant_id      is '绉熸埛缂栧彿';
+comment on column sys_logininfor.user_name      is '鐢ㄦ埛璐﹀彿';
+comment on column sys_logininfor.client_key     is '瀹㈡埛绔�';
+comment on column sys_logininfor.device_type    is '璁惧绫诲瀷';
+comment on column sys_logininfor.ipaddr         is '鐧诲綍IP鍦板潃';
+comment on column sys_logininfor.login_location is '鐧诲綍鍦扮偣';
+comment on column sys_logininfor.browser        is '娴忚鍣ㄧ被鍨�';
+comment on column sys_logininfor.os             is '鎿嶄綔绯荤粺';
+comment on column sys_logininfor.status         is '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�';
+comment on column sys_logininfor.msg            is '鎻愮ず娑堟伅';
+comment on column sys_logininfor.login_time     is '璁块棶鏃堕棿';
+
+-- ----------------------------
+-- 17銆侀�氱煡鍏憡琛�
+-- ----------------------------
+create table if not exists sys_notice
+(
+    notice_id      int8,
+    tenant_id      varchar(20)  default '000000'::varchar,
+    notice_title   varchar(50)  not null,
+    notice_type    char         not null,
+    notice_content text,
+    status         char         default '0'::bpchar,
+    create_dept    int8,
+    create_by      int8,
+    create_time    timestamp,
+    update_by      int8,
+    update_time    timestamp,
+    remark         varchar(255) default null::varchar,
+    constraint sys_notice_pk primary key (notice_id)
+);
+
+comment on table sys_notice                 is '閫氱煡鍏憡琛�';
+comment on column sys_notice.notice_id      is '鍏憡ID';
+comment on column sys_notice.tenant_id      is '绉熸埛缂栧彿';
+comment on column sys_notice.notice_title   is '鍏憡鏍囬';
+comment on column sys_notice.notice_type    is '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�';
+comment on column sys_notice.notice_content is '鍏憡鍐呭';
+comment on column sys_notice.status         is '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�';
+comment on column sys_notice.create_dept    is '鍒涘缓閮ㄩ棬';
+comment on column sys_notice.create_by      is '鍒涘缓鑰�';
+comment on column sys_notice.create_time    is '鍒涘缓鏃堕棿';
+comment on column sys_notice.update_by      is '鏇存柊鑰�';
+comment on column sys_notice.update_time    is '鏇存柊鏃堕棿';
+comment on column sys_notice.remark         is '澶囨敞';
+
+-- ----------------------------
+-- 鍒濆鍖�-鍏憡淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_notice values('1', '000000', '娓╅Θ鎻愰啋锛�2018-07-01 鏂扮増鏈彂甯冨暒', '2', '鏂扮増鏈唴瀹�', '0', 103, 1, now(), null, null, '绠$悊鍛�');
+insert into sys_notice values('2', '000000', '缁存姢閫氱煡锛�2018-07-01 绯荤粺鍑屾櫒缁存姢', '1', '缁存姢鍐呭',   '0', 103, 1, now(), null, null, '绠$悊鍛�');
+
+
+-- ----------------------------
+-- 18銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+create table if not exists gen_table
+(
+    table_id          int8,
+    data_name         varchar(200)  default ''::varchar,
+    table_name        varchar(200)  default ''::varchar,
+    table_comment     varchar(500)  default ''::varchar,
+    sub_table_name    varchar(64)   default ''::varchar,
+    sub_table_fk_name varchar(64)   default ''::varchar,
+    class_name        varchar(100)  default ''::varchar,
+    tpl_category      varchar(200)  default 'crud'::varchar,
+    package_name      varchar(100)  default null::varchar,
+    module_name       varchar(30)   default null::varchar,
+    business_name     varchar(30)   default null::varchar,
+    function_name     varchar(50)   default null::varchar,
+    function_author   varchar(50)   default null::varchar,
+    gen_type          char          default '0'::bpchar not null,
+    gen_path          varchar(200)  default '/'::varchar,
+    options           varchar(1000) default null::varchar,
+    create_dept       int8,
+    create_by         int8,
+    create_time       timestamp,
+    update_by         int8,
+    update_time       timestamp,
+    remark            varchar(500)  default null::varchar,
+    constraint gen_table_pk primary key (table_id)
+);
+
+comment on table gen_table is '浠g爜鐢熸垚涓氬姟琛�';
+comment on column gen_table.table_id is '缂栧彿';
+comment on column gen_table.data_name is '鏁版嵁婧愬悕绉�';
+comment on column gen_table.table_name is '琛ㄥ悕绉�';
+comment on column gen_table.table_comment is '琛ㄦ弿杩�';
+comment on column gen_table.sub_table_name is '鍏宠仈瀛愯〃鐨勮〃鍚�';
+comment on column gen_table.sub_table_fk_name is '瀛愯〃鍏宠仈鐨勫閿悕';
+comment on column gen_table.class_name is '瀹炰綋绫诲悕绉�';
+comment on column gen_table.tpl_category is '浣跨敤鐨勬ā鏉匡紙CRUD鍗曡〃鎿嶄綔 TREE鏍戣〃鎿嶄綔锛�';
+comment on column gen_table.package_name is '鐢熸垚鍖呰矾寰�';
+comment on column gen_table.module_name is '鐢熸垚妯″潡鍚�';
+comment on column gen_table.business_name is '鐢熸垚涓氬姟鍚�';
+comment on column gen_table.function_name is '鐢熸垚鍔熻兘鍚�';
+comment on column gen_table.function_author is '鐢熸垚鍔熻兘浣滆��';
+comment on column gen_table.gen_type is '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級';
+comment on column gen_table.gen_path is '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級';
+comment on column gen_table.options is '鍏跺畠鐢熸垚閫夐」';
+comment on column gen_table.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column gen_table.create_by is '鍒涘缓鑰�';
+comment on column gen_table.create_time is '鍒涘缓鏃堕棿';
+comment on column gen_table.update_by is '鏇存柊鑰�';
+comment on column gen_table.update_time is '鏇存柊鏃堕棿';
+comment on column gen_table.remark is '澶囨敞';
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+create table if not exists gen_table_column
+(
+    column_id      int8,
+    table_id       int8,
+    column_name    varchar(200) default null::varchar,
+    column_comment varchar(500) default null::varchar,
+    column_type    varchar(100) default null::varchar,
+    java_type      varchar(500) default null::varchar,
+    java_field     varchar(200) default null::varchar,
+    is_pk          char         default null::bpchar,
+    is_increment   char         default null::bpchar,
+    is_required    char         default null::bpchar,
+    is_insert      char         default null::bpchar,
+    is_edit        char         default null::bpchar,
+    is_list        char         default null::bpchar,
+    is_query       char         default null::bpchar,
+    query_type     varchar(200) default 'EQ'::varchar,
+    html_type      varchar(200) default null::varchar,
+    dict_type      varchar(200) default ''::varchar,
+    sort           int4,
+    create_dept    int8,
+    create_by      int8,
+    create_time    timestamp,
+    update_by      int8,
+    update_time    timestamp,
+    constraint gen_table_column_pk primary key (column_id)
+);
+
+comment on table gen_table_column is '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
+comment on column gen_table_column.column_id is '缂栧彿';
+comment on column gen_table_column.table_id is '褰掑睘琛ㄧ紪鍙�';
+comment on column gen_table_column.column_name is '鍒楀悕绉�';
+comment on column gen_table_column.column_comment is '鍒楁弿杩�';
+comment on column gen_table_column.column_type is '鍒楃被鍨�';
+comment on column gen_table_column.java_type is 'JAVA绫诲瀷';
+comment on column gen_table_column.java_field is 'JAVA瀛楁鍚�';
+comment on column gen_table_column.is_pk is '鏄惁涓婚敭锛�1鏄級';
+comment on column gen_table_column.is_increment is '鏄惁鑷锛�1鏄級';
+comment on column gen_table_column.is_required is '鏄惁蹇呭~锛�1鏄級';
+comment on column gen_table_column.is_insert is '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級';
+comment on column gen_table_column.is_edit is '鏄惁缂栬緫瀛楁锛�1鏄級';
+comment on column gen_table_column.is_list is '鏄惁鍒楄〃瀛楁锛�1鏄級';
+comment on column gen_table_column.is_query is '鏄惁鏌ヨ瀛楁锛�1鏄級';
+comment on column gen_table_column.query_type is '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級';
+comment on column gen_table_column.html_type is '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級';
+comment on column gen_table_column.dict_type is '瀛楀吀绫诲瀷';
+comment on column gen_table_column.sort is '鎺掑簭';
+comment on column gen_table_column.create_dept is '鍒涘缓閮ㄩ棬';
+comment on column gen_table_column.create_by is '鍒涘缓鑰�';
+comment on column gen_table_column.create_time is '鍒涘缓鏃堕棿';
+comment on column gen_table_column.update_by is '鏇存柊鑰�';
+comment on column gen_table_column.update_time is '鏇存柊鏃堕棿';
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍琛�
+-- ----------------------------
+create table if not exists sys_oss
+(
+    oss_id        int8,
+    tenant_id     varchar(20)  default '000000'::varchar,
+    file_name     varchar(255) default ''::varchar not null,
+    original_name varchar(255) default ''::varchar not null,
+    file_suffix   varchar(10)  default ''::varchar not null,
+    url           varchar(500) default ''::varchar not null,
+    create_dept   int8,
+    create_by     int8,
+    create_time   timestamp,
+    update_by     int8,
+    update_time   timestamp,
+    service       varchar(20)  default 'minio'::varchar,
+    constraint sys_oss_pk primary key (oss_id)
+);
+
+comment on table sys_oss                    is 'OSS瀵硅薄瀛樺偍琛�';
+comment on column sys_oss.oss_id            is '瀵硅薄瀛樺偍涓婚敭';
+comment on column sys_oss.tenant_id         is '绉熸埛缂栫爜';
+comment on column sys_oss.file_name         is '鏂囦欢鍚�';
+comment on column sys_oss.original_name     is '鍘熷悕';
+comment on column sys_oss.file_suffix       is '鏂囦欢鍚庣紑鍚�';
+comment on column sys_oss.url               is 'URL鍦板潃';
+comment on column sys_oss.create_by         is '涓婁紶浜�';
+comment on column sys_oss.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column sys_oss.create_time       is '鍒涘缓鏃堕棿';
+comment on column sys_oss.update_by         is '鏇存柊鑰�';
+comment on column sys_oss.update_time       is '鏇存柊鏃堕棿';
+comment on column sys_oss.service           is '鏈嶅姟鍟�';
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍鍔ㄦ�侀厤缃〃
+-- ----------------------------
+create table if not exists sys_oss_config
+(
+    oss_config_id int8,
+    tenant_id     varchar(20)  default '000000'::varchar,
+    config_key    varchar(20)  default ''::varchar not null,
+    access_key    varchar(255) default ''::varchar,
+    secret_key    varchar(255) default ''::varchar,
+    bucket_name   varchar(255) default ''::varchar,
+    prefix        varchar(255) default ''::varchar,
+    endpoint      varchar(255) default ''::varchar,
+    domain        varchar(255) default ''::varchar,
+    is_https      char         default 'N'::bpchar,
+    region        varchar(255) default ''::varchar,
+    access_policy char(1)      default '1'::bpchar not null,
+    status        char         default '1'::bpchar,
+    ext1          varchar(255) default ''::varchar,
+    create_dept   int8,
+    create_by     int8,
+    create_time   timestamp,
+    update_by     int8,
+    update_time   timestamp,
+    remark        varchar(500) default ''::varchar,
+    constraint sys_oss_config_pk primary key (oss_config_id)
+);
+
+comment on table sys_oss_config                 is '瀵硅薄瀛樺偍閰嶇疆琛�';
+comment on column sys_oss_config.oss_config_id  is '涓婚敭';
+comment on column sys_oss_config.tenant_id      is '绉熸埛缂栫爜';
+comment on column sys_oss_config.config_key     is '閰嶇疆key';
+comment on column sys_oss_config.access_key     is 'accessKey';
+comment on column sys_oss_config.secret_key     is '绉橀挜';
+comment on column sys_oss_config.bucket_name    is '妗跺悕绉�';
+comment on column sys_oss_config.prefix         is '鍓嶇紑';
+comment on column sys_oss_config.endpoint       is '璁块棶绔欑偣';
+comment on column sys_oss_config.domain         is '鑷畾涔夊煙鍚�';
+comment on column sys_oss_config.is_https       is '鏄惁https锛圷=鏄�,N=鍚︼級';
+comment on column sys_oss_config.region         is '鍩�';
+comment on column sys_oss_config.access_policy  is '妗舵潈闄愮被鍨�(0=private 1=public 2=custom)';
+comment on column sys_oss_config.status         is '鏄惁榛樿锛�0=鏄�,1=鍚︼級';
+comment on column sys_oss_config.ext1           is '鎵╁睍瀛楁';
+comment on column sys_oss_config.create_dept    is '鍒涘缓閮ㄩ棬';
+comment on column sys_oss_config.create_by      is '鍒涘缓鑰�';
+comment on column sys_oss_config.create_time    is '鍒涘缓鏃堕棿';
+comment on column sys_oss_config.update_by      is '鏇存柊鑰�';
+comment on column sys_oss_config.update_time    is '鏇存柊鏃堕棿';
+comment on column sys_oss_config.remark         is '澶囨敞';
+
+insert into sys_oss_config values (1, '000000', 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', '127.0.0.1:9000',                      '','N', '',            '1', '0', '', 103, 1, now(), 1, now(), null);
+insert into sys_oss_config values (2, '000000', 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 's3-cn-north-1.qiniucs.com',           '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), null);
+insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'oss-cn-beijing.aliyuncs.com',         '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), null);
+insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'cos.ap-beijing.myqcloud.com',         '','N', 'ap-beijing',  '1', '1', '', 103, 1, now(), 1, now(), null);
+insert into sys_oss_config values (5, '000000', 'image',  'ruoyi',            'ruoyi123',        'ruoyi',             'image', '127.0.0.1:9000',                 '','N', '',            '1', '1', '', 103, 1, now(), 1, now(), NULL);
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+create table sys_client (
+    id                  int8,
+    client_id           varchar(64)   default ''::varchar,
+    client_key          varchar(32)   default ''::varchar,
+    client_secret       varchar(255)  default ''::varchar,
+    grant_type          varchar(255)  default ''::varchar,
+    device_type         varchar(32)   default ''::varchar,
+    active_timeout      int4          default 1800,
+    timeout             int4          default 604800,
+    status              char(1)       default '0'::bpchar,
+    del_flag            char(1)       default '0'::bpchar,
+    create_dept         int8,
+    create_by           int8,
+    create_time         timestamp,
+    update_by           int8,
+    update_time         timestamp,
+    constraint sys_client_pk primary key (id)
+);
+
+comment on table sys_client                         is '绯荤粺鎺堟潈琛�';
+comment on column sys_client.id                     is '涓婚敭';
+comment on column sys_client.client_id              is '瀹㈡埛绔痠d';
+comment on column sys_client.client_key             is '瀹㈡埛绔痥ey';
+comment on column sys_client.client_secret          is '瀹㈡埛绔閽�';
+comment on column sys_client.grant_type             is '鎺堟潈绫诲瀷';
+comment on column sys_client.device_type            is '璁惧绫诲瀷';
+comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
+comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
+comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
+comment on column sys_client.create_by              is '鍒涘缓鑰�';
+comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
+comment on column sys_client.update_by              is '鏇存柊鑰�';
+comment on column sys_client.update_time            is '鏇存柊鏃堕棿';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now());
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now());
+
+create table if not exists test_demo
+(
+    id          int8,
+    tenant_id   varchar(20)     default '000000',
+    dept_id     int8,
+    user_id     int8,
+    order_num   int4            default 0,
+    test_key    varchar(255),
+    value       varchar(255),
+    version     int4            default 0,
+    create_dept int8,
+    create_time timestamp,
+    create_by   int8,
+    update_time timestamp,
+    update_by   int8,
+    del_flag    int4            default 0
+);
+
+comment on table test_demo is '娴嬭瘯鍗曡〃';
+comment on column test_demo.id is '涓婚敭';
+comment on column test_demo.tenant_id is '绉熸埛缂栧彿';
+comment on column test_demo.dept_id is '閮ㄩ棬id';
+comment on column test_demo.user_id is '鐢ㄦ埛id';
+comment on column test_demo.order_num is '鎺掑簭鍙�';
+comment on column test_demo.test_key is 'key閿�';
+comment on column test_demo.value is '鍊�';
+comment on column test_demo.version is '鐗堟湰';
+comment on column test_demo.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column test_demo.create_time is '鍒涘缓鏃堕棿';
+comment on column test_demo.create_by is '鍒涘缓浜�';
+comment on column test_demo.update_time is '鏇存柊鏃堕棿';
+comment on column test_demo.update_by is '鏇存柊浜�';
+comment on column test_demo.del_flag is '鍒犻櫎鏍囧織';
+
+create table if not exists test_tree
+(
+    id          int8,
+    tenant_id   varchar(20)     default '000000',
+    parent_id   int8            default 0,
+    dept_id     int8,
+    user_id     int8,
+    tree_name   varchar(255),
+    version     int4            default 0,
+    create_dept int8,
+    create_time timestamp,
+    create_by   int8,
+    update_time timestamp,
+    update_by   int8,
+    del_flag    integer         default 0
+);
+
+comment on table test_tree is '娴嬭瘯鏍戣〃';
+comment on column test_tree.id is '涓婚敭';
+comment on column test_tree.tenant_id is '绉熸埛缂栧彿';
+comment on column test_tree.parent_id is '鐖秈d';
+comment on column test_tree.dept_id is '閮ㄩ棬id';
+comment on column test_tree.user_id is '鐢ㄦ埛id';
+comment on column test_tree.tree_name is '鍊�';
+comment on column test_tree.version is '鐗堟湰';
+comment on column test_tree.create_dept  is '鍒涘缓閮ㄩ棬';
+comment on column test_tree.create_time is '鍒涘缓鏃堕棿';
+comment on column test_tree.create_by is '鍒涘缓浜�';
+comment on column test_tree.update_time is '鏇存柊鏃堕棿';
+comment on column test_tree.update_by is '鏇存柊浜�';
+comment on column test_tree.del_flag is '鍒犻櫎鏍囧織';
+
+INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '娴嬭瘯鏁版嵁鏉冮檺', '娴嬭瘯', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '瀛愯妭鐐�1', '111', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '瀛愯妭鐐�2', '222', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '娴嬭瘯鏁版嵁', 'demo', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '瀛愯妭鐐�11', '1111', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '瀛愯妭鐐�22', '2222', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '瀛愯妭鐐�33', '3333', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '瀛愯妭鐐�44', '4444', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '瀛愯妭鐐�55', '5555', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '瀛愯妭鐐�66', '6666', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '瀛愯妭鐐�77', '7777', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '瀛愯妭鐐�88', '8888', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '瀛愯妭鐐�99', '9999', 0, 103, now(), 1, NULL, NULL, 0);
+
+INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '娴嬭瘯鏁版嵁鏉冮檺', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '瀛愯妭鐐�1', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '瀛愯妭鐐�2', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '娴嬭瘯鏍�1', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '瀛愯妭鐐�11', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '瀛愯妭鐐�22', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '瀛愯妭鐐�33', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '瀛愯妭鐐�44', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '瀛愯妭鐐�55', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '瀛愯妭鐐�66', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '瀛愯妭鐐�77', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '瀛愯妭鐐�88', 0, 103, now(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '瀛愯妭鐐�99', 0, 103, now(), 1, NULL, NULL, 0);
+
+-- 瀛楃涓茶嚜鍔ㄨ浆鏃堕棿 閬垮厤妗嗘灦鏃堕棿鏌ヨ鎶ラ敊闂
+create or replace function cast_varchar_to_timestamp(varchar) returns timestamptz as $$
+select to_timestamp($1, 'yyyy-mm-dd hh24:mi:ss');
+$$ language sql strict ;
+
+create cast (varchar as timestamptz) with function cast_varchar_to_timestamp as IMPLICIT;
diff --git a/eims/script/sql/postgres/snail_job_postgre.sql b/eims/script/sql/postgres/snail_job_postgre.sql
new file mode 100644
index 0000000..c8abc68
--- /dev/null
+++ b/eims/script/sql/postgres/snail_job_postgre.sql
@@ -0,0 +1,836 @@
+/*
+ SnailJob Database Transfer Tool
+ Source Server Type    : MySQL
+ Target Server Type    : PostgreSQL
+ Date: 2024-07-06 11:45:40
+*/
+
+
+-- sj_namespace
+CREATE TABLE sj_namespace
+(
+    id          bigserial PRIMARY KEY,
+    name        varchar(64)  NOT NULL,
+    unique_id   varchar(64)  NOT NULL,
+    description varchar(256) NOT NULL DEFAULT '',
+    deleted     smallint     NOT NULL DEFAULT 0,
+    create_dt   timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt   timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name);
+
+COMMENT ON COLUMN sj_namespace.id IS '涓婚敭';
+COMMENT ON COLUMN sj_namespace.name IS '鍚嶇О';
+COMMENT ON COLUMN sj_namespace.unique_id IS '鍞竴id';
+COMMENT ON COLUMN sj_namespace.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_namespace.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_namespace.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_namespace.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_namespace IS '鍛藉悕绌洪棿';
+
+INSERT INTO sj_namespace VALUES (1, 'Development', 'dev', '', 0, now(), now());
+INSERT INTO sj_namespace VALUES (2, 'Production', 'prod', '', 0, now(), now());
+
+-- sj_group_config
+CREATE TABLE sj_group_config
+(
+    id                bigserial PRIMARY KEY,
+    namespace_id      varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        varchar(64)  NOT NULL DEFAULT '',
+    description       varchar(256) NOT NULL DEFAULT '',
+    token             varchar(64)  NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT',
+    group_status      smallint     NOT NULL DEFAULT 0,
+    version           int          NOT NULL,
+    group_partition   int          NOT NULL,
+    id_generator_mode smallint     NOT NULL DEFAULT 1,
+    init_scene        smallint     NOT NULL DEFAULT 0,
+    bucket_index      int          NOT NULL DEFAULT 0,
+    create_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_group_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_group_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_group_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_group_config.description IS '缁勬弿杩�';
+COMMENT ON COLUMN sj_group_config.token IS 'token';
+COMMENT ON COLUMN sj_group_config.group_status IS '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_group_config.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_group_config.group_partition IS '鍒嗗尯';
+COMMENT ON COLUMN sj_group_config.id_generator_mode IS '鍞竴id鐢熸垚妯″紡 榛樿鍙锋妯″紡';
+COMMENT ON COLUMN sj_group_config.init_scene IS '鏄惁鍒濆鍖栧満鏅� 0:鍚� 1:鏄�';
+COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_group_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_group_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_group_config IS '缁勯厤缃�';
+
+INSERT INTO sj_group_config VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
+
+-- sj_notify_config
+CREATE TABLE sj_notify_config
+(
+    id                     bigserial PRIMARY KEY,
+    namespace_id           varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name             varchar(64)  NOT NULL,
+    business_id            varchar(64)  NOT NULL,
+    system_task_type       smallint     NOT NULL DEFAULT 3,
+    notify_status          smallint     NOT NULL DEFAULT 0,
+    recipient_ids          varchar(128) NOT NULL,
+    notify_threshold       int          NOT NULL DEFAULT 0,
+    notify_scene           smallint     NOT NULL DEFAULT 0,
+    rate_limiter_status    smallint     NOT NULL DEFAULT 0,
+    rate_limiter_threshold int          NOT NULL DEFAULT 0,
+    description            varchar(256) NOT NULL DEFAULT '',
+    create_dt              timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt              timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id);
+
+COMMENT ON COLUMN sj_notify_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_notify_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_notify_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_notify_config.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ';
+COMMENT ON COLUMN sj_notify_config.system_task_type IS '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_notify_config.notify_status IS '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_notify_config.recipient_ids IS '鎺ユ敹浜篿d鍒楄〃';
+COMMENT ON COLUMN sj_notify_config.notify_threshold IS '閫氱煡闃堝��';
+COMMENT ON COLUMN sj_notify_config.notify_scene IS '閫氱煡鍦烘櫙';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '闄愭祦鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '姣忕闄愭祦闃堝��';
+COMMENT ON COLUMN sj_notify_config.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_notify_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_notify_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_notify_config IS '閫氱煡閰嶇疆';
+
+-- sj_notify_recipient
+CREATE TABLE sj_notify_recipient
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    recipient_name   varchar(64)  NOT NULL,
+    notify_type      smallint     NOT NULL DEFAULT 0,
+    notify_attribute varchar(512) NOT NULL,
+    description      varchar(256) NOT NULL DEFAULT '',
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id);
+
+COMMENT ON COLUMN sj_notify_recipient.id IS '涓婚敭';
+COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '鎺ユ敹浜哄悕绉�';
+COMMENT ON COLUMN sj_notify_recipient.notify_type IS '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook';
+COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '閰嶇疆灞炴��';
+COMMENT ON COLUMN sj_notify_recipient.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_notify_recipient.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_notify_recipient.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_notify_recipient IS '鍛婅閫氱煡鎺ユ敹浜�';
+
+-- sj_retry_dead_letter_0
+CREATE TABLE sj_retry_dead_letter_0
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id     varchar(64)  NOT NULL,
+    group_name    varchar(64)  NOT NULL,
+    scene_name    varchar(64)  NOT NULL,
+    idempotent_id varchar(64)  NOT NULL,
+    biz_no        varchar(64)  NOT NULL DEFAULT '',
+    executor_name varchar(512) NOT NULL DEFAULT '',
+    args_str      text         NOT NULL,
+    ext_attrs     text         NOT NULL,
+    task_type     smallint     NOT NULL DEFAULT 1,
+    create_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id);
+
+CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id);
+CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no);
+CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt);
+
+COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_retry_dead_letter_0 IS '姝讳俊闃熷垪琛�';
+
+-- sj_retry_task_0
+CREATE TABLE sj_retry_task_0
+(
+    id              bigserial PRIMARY KEY,
+    namespace_id    varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id       varchar(64)  NOT NULL,
+    group_name      varchar(64)  NOT NULL,
+    scene_name      varchar(64)  NOT NULL,
+    idempotent_id   varchar(64)  NOT NULL,
+    biz_no          varchar(64)  NOT NULL DEFAULT '',
+    executor_name   varchar(512) NOT NULL DEFAULT '',
+    args_str        text         NOT NULL,
+    ext_attrs       text         NOT NULL,
+    next_trigger_at timestamp    NOT NULL,
+    retry_count     int          NOT NULL DEFAULT 0,
+    retry_status    smallint     NOT NULL DEFAULT 0,
+    task_type       smallint     NOT NULL DEFAULT 1,
+    create_dt       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id);
+
+CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type);
+CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status);
+CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id);
+CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no);
+CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_0.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_0.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_0.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_0.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_task_0.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_task_0.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_task_0.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_0.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_retry_task_0.retry_status IS '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_retry_task_0.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_task_0.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_0.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_task_0 IS '浠诲姟琛�';
+
+-- sj_retry_task_log
+CREATE TABLE sj_retry_task_log
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id     varchar(64)  NOT NULL,
+    group_name    varchar(64)  NOT NULL,
+    scene_name    varchar(64)  NOT NULL,
+    idempotent_id varchar(64)  NOT NULL,
+    biz_no        varchar(64)  NOT NULL DEFAULT '',
+    executor_name varchar(512) NOT NULL DEFAULT '',
+    args_str      text         NOT NULL,
+    ext_attrs     text         NOT NULL,
+    retry_status  smallint     NOT NULL DEFAULT 0,
+    task_type     smallint     NOT NULL DEFAULT 1,
+    create_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status);
+CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id);
+CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id);
+CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no);
+CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_log.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_log.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_log.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_log.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '骞傜瓑id';
+COMMENT ON COLUMN sj_retry_task_log.biz_no IS '涓氬姟缂栧彿';
+COMMENT ON COLUMN sj_retry_task_log.executor_name IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_retry_task_log.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_retry_task_log.retry_status IS '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ф鏁�';
+COMMENT ON COLUMN sj_retry_task_log.task_type IS '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�';
+COMMENT ON COLUMN sj_retry_task_log.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_log.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_task_log IS '浠诲姟鏃ュ織鍩虹淇℃伅琛�';
+
+-- sj_retry_task_log_message
+CREATE TABLE sj_retry_task_log_message
+(
+    id           bigserial PRIMARY KEY,
+    namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   varchar(64) NOT NULL,
+    unique_id    varchar(64) NOT NULL,
+    message      text        NOT NULL,
+    log_num      int         NOT NULL DEFAULT 1,
+    real_time    bigint      NOT NULL DEFAULT 0,
+    create_dt    timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id);
+CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_log_message.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '鍚岀粍涓媔d鍞竴';
+COMMENT ON COLUMN sj_retry_task_log_message.message IS '寮傚父淇℃伅';
+COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '涓婃姤鏃堕棿';
+COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_retry_task_log_message IS '浠诲姟璋冨害鏃ュ織淇℃伅璁板綍琛�';
+
+-- sj_retry_scene_config
+CREATE TABLE sj_retry_scene_config
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    scene_name       varchar(64)  NOT NULL,
+    group_name       varchar(64)  NOT NULL,
+    scene_status     smallint     NOT NULL DEFAULT 0,
+    max_retry_count  int          NOT NULL DEFAULT 5,
+    back_off         smallint     NOT NULL DEFAULT 1,
+    trigger_interval varchar(16)  NOT NULL DEFAULT '',
+    deadline_request bigint       NOT NULL DEFAULT 60000,
+    executor_timeout int          NOT NULL DEFAULT 5,
+    route_key        smallint     NOT NULL DEFAULT 4,
+    description      varchar(256) NOT NULL DEFAULT '',
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name);
+
+COMMENT ON COLUMN sj_retry_scene_config.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_scene_config.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�';
+COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '鏈�澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�';
+COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣';
+COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_retry_scene_config.route_key IS '璺敱绛栫暐';
+COMMENT ON COLUMN sj_retry_scene_config.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_scene_config IS '鍦烘櫙閰嶇疆';
+
+-- sj_server_node
+CREATE TABLE sj_server_node
+(
+    id           bigserial PRIMARY KEY,
+    namespace_id varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   varchar(64)  NOT NULL,
+    host_id      varchar(64)  NOT NULL,
+    host_ip      varchar(64)  NOT NULL,
+    host_port    int          NOT NULL,
+    expire_at    timestamp    NOT NULL,
+    node_type    smallint     NOT NULL,
+    ext_attrs    varchar(256) NULL     DEFAULT '',
+    create_dt    timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt    timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip);
+
+CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name);
+CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type);
+
+COMMENT ON COLUMN sj_server_node.id IS '涓婚敭';
+COMMENT ON COLUMN sj_server_node.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_server_node.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_server_node.host_id IS '涓绘満id';
+COMMENT ON COLUMN sj_server_node.host_ip IS '鏈哄櫒ip';
+COMMENT ON COLUMN sj_server_node.host_port IS '鏈哄櫒绔彛';
+COMMENT ON COLUMN sj_server_node.expire_at IS '杩囨湡鏃堕棿';
+COMMENT ON COLUMN sj_server_node.node_type IS '鑺傜偣绫诲瀷 1銆佸鎴风 2銆佹槸鏈嶅姟绔�';
+COMMENT ON COLUMN sj_server_node.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_server_node.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_server_node.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_server_node IS '鏈嶅姟鍣ㄨ妭鐐�';
+
+-- sj_distributed_lock
+CREATE TABLE sj_distributed_lock
+(
+    name       varchar(64)  PRIMARY KEY,
+    lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+    locked_at  timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+    locked_by  varchar(255) NOT NULL,
+    create_dt  timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt  timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+COMMENT ON COLUMN sj_distributed_lock.name IS '閿佸悕绉�';
+COMMENT ON COLUMN sj_distributed_lock.lock_until IS '閿佸畾鏃堕暱';
+COMMENT ON COLUMN sj_distributed_lock.locked_at IS '閿佸畾鏃堕棿';
+COMMENT ON COLUMN sj_distributed_lock.locked_by IS '閿佸畾鑰�';
+COMMENT ON COLUMN sj_distributed_lock.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_distributed_lock.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_distributed_lock IS '閿佸畾琛�';
+
+-- sj_system_user
+CREATE TABLE sj_system_user
+(
+    id        bigserial PRIMARY KEY,
+    username  varchar(64)  NOT NULL,
+    password  varchar(128) NOT NULL,
+    role      smallint     NOT NULL DEFAULT 0,
+    create_dt timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+COMMENT ON COLUMN sj_system_user.id IS '涓婚敭';
+COMMENT ON COLUMN sj_system_user.username IS '璐﹀彿';
+COMMENT ON COLUMN sj_system_user.password IS '瀵嗙爜';
+COMMENT ON COLUMN sj_system_user.role IS '瑙掕壊锛�1-鏅�氱敤鎴枫��2-绠$悊鍛�';
+COMMENT ON COLUMN sj_system_user.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_system_user.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_system_user IS '绯荤粺鐢ㄦ埛琛�';
+
+-- pwd: admin
+INSERT INTO sj_system_user VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now());
+
+-- sj_system_user_permission
+CREATE TABLE sj_system_user_permission
+(
+    id             bigserial PRIMARY KEY,
+    group_name     varchar(64) NOT NULL,
+    namespace_id   varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    system_user_id bigint      NOT NULL,
+    create_dt      timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id);
+
+COMMENT ON COLUMN sj_system_user_permission.id IS '涓婚敭';
+COMMENT ON COLUMN sj_system_user_permission.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '绯荤粺鐢ㄦ埛id';
+COMMENT ON COLUMN sj_system_user_permission.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_system_user_permission.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_system_user_permission IS '绯荤粺鐢ㄦ埛鏉冮檺琛�';
+
+-- sj_sequence_alloc
+CREATE TABLE sj_sequence_alloc
+(
+    id           bigserial PRIMARY KEY,
+    namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   varchar(64) NOT NULL DEFAULT '',
+    max_id       bigint      NOT NULL DEFAULT 1,
+    step         int         NOT NULL DEFAULT 100,
+    update_dt    timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_sequence_alloc.id IS '涓婚敭';
+COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_sequence_alloc.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_sequence_alloc.max_id IS '鏈�澶d';
+COMMENT ON COLUMN sj_sequence_alloc.step IS '姝ラ暱';
+COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '鏇存柊鏃堕棿';
+COMMENT ON TABLE sj_sequence_alloc IS '鍙锋妯″紡搴忓彿ID鍒嗛厤琛�';
+
+-- sj_job
+CREATE TABLE sj_job
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL,
+    job_name         varchar(64)  NOT NULL,
+    args_str         text         NULL     DEFAULT NULL,
+    args_type        smallint     NOT NULL DEFAULT 1,
+    next_trigger_at  bigint       NOT NULL,
+    job_status       smallint     NOT NULL DEFAULT 1,
+    task_type        smallint     NOT NULL DEFAULT 1,
+    route_key        smallint     NOT NULL DEFAULT 4,
+    executor_type    smallint     NOT NULL DEFAULT 1,
+    executor_info    varchar(255) NULL     DEFAULT NULL,
+    trigger_type     smallint     NOT NULL,
+    trigger_interval varchar(255) NOT NULL,
+    block_strategy   smallint     NOT NULL DEFAULT 1,
+    executor_timeout int          NOT NULL DEFAULT 0,
+    max_retry_times  int          NOT NULL DEFAULT 0,
+    parallel_num     int          NOT NULL DEFAULT 1,
+    retry_interval   int          NOT NULL DEFAULT 0,
+    bucket_index     int          NOT NULL DEFAULT 0,
+    resident         smallint     NOT NULL DEFAULT 0,
+    description      varchar(256) NOT NULL DEFAULT '',
+    ext_attrs        varchar(256) NULL     DEFAULT '',
+    deleted          smallint     NOT NULL DEFAULT 0,
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name);
+CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index);
+CREATE INDEX idx_sj_job_03 ON sj_job (create_dt);
+
+COMMENT ON COLUMN sj_job.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job.job_name IS '鍚嶇О';
+COMMENT ON COLUMN sj_job.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_job.args_type IS '鍙傛暟绫诲瀷 ';
+COMMENT ON COLUMN sj_job.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_job.job_status IS '浠诲姟鐘舵�� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_job.task_type IS '浠诲姟绫诲瀷 1銆侀泦缇� 2銆佸箍鎾� 3銆佸垏鐗�';
+COMMENT ON COLUMN sj_job.route_key IS '璺敱绛栫暐';
+COMMENT ON COLUMN sj_job.executor_type IS '鎵ц鍣ㄧ被鍨�';
+COMMENT ON COLUMN sj_job.executor_info IS '鎵ц鍣ㄥ悕绉�';
+COMMENT ON COLUMN sj_job.trigger_type IS '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿';
+COMMENT ON COLUMN sj_job.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_job.block_strategy IS '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�';
+COMMENT ON COLUMN sj_job.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_job.max_retry_times IS '鏈�澶ч噸璇曟鏁�';
+COMMENT ON COLUMN sj_job.parallel_num IS '骞惰鏁�';
+COMMENT ON COLUMN sj_job.retry_interval IS '閲嶈瘯闂撮殧 ( s ) ';
+COMMENT ON COLUMN sj_job.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_job.resident IS '鏄惁鏄父椹讳换鍔�';
+COMMENT ON COLUMN sj_job.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_job.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_job.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job IS '浠诲姟淇℃伅';
+
+INSERT INTO sj_job VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0, now(), now());
+
+-- sj_job_log_message
+CREATE TABLE sj_job_log_message
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64)  NOT NULL,
+    job_id        bigint       NOT NULL,
+    task_batch_id bigint       NOT NULL,
+    task_id       bigint       NOT NULL,
+    message       text         NOT NULL,
+    log_num       int          NOT NULL DEFAULT 1,
+    real_time     bigint       NOT NULL DEFAULT 0,
+    ext_attrs     varchar(256) NULL     DEFAULT '',
+    create_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id);
+CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt);
+CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_log_message.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_log_message.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_log_message.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_log_message.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '浠诲姟鎵规id';
+COMMENT ON COLUMN sj_job_log_message.task_id IS '璋冨害浠诲姟id';
+COMMENT ON COLUMN sj_job_log_message.message IS '璋冨害淇℃伅';
+COMMENT ON COLUMN sj_job_log_message.log_num IS '鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_log_message.real_time IS '涓婃姤鏃堕棿';
+COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_log_message.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON TABLE sj_job_log_message IS '璋冨害鏃ュ織';
+
+-- sj_job_task
+CREATE TABLE sj_job_task
+(
+    id             bigserial PRIMARY KEY,
+    namespace_id   varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name     varchar(64)  NOT NULL,
+    job_id         bigint       NOT NULL,
+    task_batch_id  bigint       NOT NULL,
+    parent_id      bigint       NOT NULL DEFAULT 0,
+    task_status    smallint     NOT NULL DEFAULT 0,
+    retry_count    int          NOT NULL DEFAULT 0,
+    mr_stage       smallint     NULL     DEFAULT NULL,
+    leaf           smallint     NOT NULL DEFAULT '1',
+    task_name      varchar(255) NOT NULL DEFAULT '',
+    client_info    varchar(128) NULL     DEFAULT NULL,
+    wf_context     text         NULL     DEFAULT NULL,
+    result_message text         NOT NULL,
+    args_str       text         NULL     DEFAULT NULL,
+    args_type      smallint     NOT NULL DEFAULT 1,
+    ext_attrs      varchar(256) NULL     DEFAULT '',
+    create_dt      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status);
+CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt);
+CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_task.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_task.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_task.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_task.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_job_task.task_batch_id IS '璋冨害浠诲姟id';
+COMMENT ON COLUMN sj_job_task.parent_id IS '鐖舵墽琛屽櫒id';
+COMMENT ON COLUMN sj_job_task.task_status IS '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_job_task.retry_count IS '閲嶈瘯娆℃暟';
+COMMENT ON COLUMN sj_job_task.mr_stage IS '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce';
+COMMENT ON COLUMN sj_job_task.leaf IS '鍙跺瓙鑺傜偣';
+COMMENT ON COLUMN sj_job_task.task_name IS '浠诲姟鍚嶇О';
+COMMENT ON COLUMN sj_job_task.client_info IS '瀹㈡埛绔湴鍧� clientId#ip:port';
+COMMENT ON COLUMN sj_job_task.wf_context IS '宸ヤ綔娴佸叏灞�涓婁笅鏂�';
+COMMENT ON COLUMN sj_job_task.result_message IS '鎵ц缁撴灉';
+COMMENT ON COLUMN sj_job_task.args_str IS '鎵ц鏂规硶鍙傛暟';
+COMMENT ON COLUMN sj_job_task.args_type IS '鍙傛暟绫诲瀷 ';
+COMMENT ON COLUMN sj_job_task.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_task.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_task.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_task IS '浠诲姟瀹炰緥';
+
+-- sj_job_task_batch
+CREATE TABLE sj_job_task_batch
+(
+    id                      bigserial PRIMARY KEY,
+    namespace_id            varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name              varchar(64)  NOT NULL,
+    job_id                  bigint       NOT NULL,
+    workflow_node_id        bigint       NOT NULL DEFAULT 0,
+    parent_workflow_node_id bigint       NOT NULL DEFAULT 0,
+    workflow_task_batch_id  bigint       NOT NULL DEFAULT 0,
+    task_batch_status       smallint     NOT NULL DEFAULT 0,
+    operation_reason        smallint     NOT NULL DEFAULT 0,
+    execution_at            bigint       NOT NULL DEFAULT 0,
+    system_task_type        smallint     NOT NULL DEFAULT 3,
+    parent_id               varchar(64)  NOT NULL DEFAULT '',
+    ext_attrs               varchar(256) NULL     DEFAULT '',
+    deleted                 smallint     NOT NULL DEFAULT 0,
+    create_dt               timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt               timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status);
+CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt);
+CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name);
+CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id);
+
+COMMENT ON COLUMN sj_job_task_batch.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_task_batch.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_task_batch.job_id IS '浠诲姟id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '宸ヤ綔娴佽妭鐐筰d';
+COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '宸ヤ綔娴佷换鍔$埗鎵规id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '宸ヤ綔娴佷换鍔℃壒娆d';
+COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
+COMMENT ON COLUMN sj_job_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
+COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_job_task_batch.parent_id IS '鐖惰妭鐐�';
+COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_job_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_job_task_batch.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_task_batch.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_task_batch IS '浠诲姟鎵规';
+
+-- sj_job_summary
+CREATE TABLE sj_job_summary
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL DEFAULT '',
+    business_id      bigint       NOT NULL,
+    system_task_type smallint     NOT NULL DEFAULT 3,
+    trigger_at       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    success_num      int          NOT NULL DEFAULT 0,
+    fail_num         int          NOT NULL DEFAULT 0,
+    fail_reason      varchar(512) NOT NULL DEFAULT '',
+    stop_num         int          NOT NULL DEFAULT 0,
+    stop_reason      varchar(512) NOT NULL DEFAULT '',
+    cancel_num       int          NOT NULL DEFAULT 0,
+    cancel_reason    varchar(512) NOT NULL DEFAULT '',
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id);
+
+CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id);
+
+COMMENT ON COLUMN sj_job_summary.id IS '涓婚敭';
+COMMENT ON COLUMN sj_job_summary.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_job_summary.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_job_summary.business_id IS '涓氬姟id  ( job_id鎴杦orkflow_id ) ';
+COMMENT ON COLUMN sj_job_summary.system_task_type IS '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟';
+COMMENT ON COLUMN sj_job_summary.trigger_at IS '缁熻鏃堕棿';
+COMMENT ON COLUMN sj_job_summary.success_num IS '鎵ц鎴愬姛-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.fail_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.fail_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.stop_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.stop_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.cancel_num IS '鎵ц澶辫触-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_job_summary.cancel_reason IS '澶辫触鍘熷洜';
+COMMENT ON COLUMN sj_job_summary.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_job_summary.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job';
+
+-- sj_retry_summary
+CREATE TABLE sj_retry_summary
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64) NOT NULL DEFAULT '',
+    scene_name    varchar(50) NOT NULL DEFAULT '',
+    trigger_at    timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    running_num   int         NOT NULL DEFAULT 0,
+    finish_num    int         NOT NULL DEFAULT 0,
+    max_count_num int         NOT NULL DEFAULT 0,
+    suspend_num   int         NOT NULL DEFAULT 0,
+    create_dt     timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt     timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at);
+
+CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at);
+
+COMMENT ON COLUMN sj_retry_summary.id IS '涓婚敭';
+COMMENT ON COLUMN sj_retry_summary.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_retry_summary.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_retry_summary.scene_name IS '鍦烘櫙鍚嶇О';
+COMMENT ON COLUMN sj_retry_summary.trigger_at IS '缁熻鏃堕棿';
+COMMENT ON COLUMN sj_retry_summary.running_num IS '閲嶈瘯涓�-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.finish_num IS '閲嶈瘯瀹屾垚-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.max_count_num IS '閲嶈瘯鍒拌揪鏈�澶ф鏁�-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.suspend_num IS '鏆傚仠閲嶈瘯-鏃ュ織鏁伴噺';
+COMMENT ON COLUMN sj_retry_summary.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_retry_summary.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry';
+
+-- sj_workflow
+CREATE TABLE sj_workflow
+(
+    id               bigserial PRIMARY KEY,
+    workflow_name    varchar(64)  NOT NULL,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL,
+    workflow_status  smallint     NOT NULL DEFAULT 1,
+    trigger_type     smallint     NOT NULL,
+    trigger_interval varchar(255) NOT NULL,
+    next_trigger_at  bigint       NOT NULL,
+    block_strategy   smallint     NOT NULL DEFAULT 1,
+    executor_timeout int          NOT NULL DEFAULT 0,
+    description      varchar(256) NOT NULL DEFAULT '',
+    flow_info        text         NULL     DEFAULT NULL,
+    wf_context       text         NULL     DEFAULT NULL,
+    bucket_index     int          NOT NULL DEFAULT 0,
+    version          int          NOT NULL,
+    ext_attrs        varchar(256) NULL     DEFAULT '',
+    deleted          smallint     NOT NULL DEFAULT 0,
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt);
+CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow.workflow_name IS '宸ヤ綔娴佸悕绉�';
+COMMENT ON COLUMN sj_workflow.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow.workflow_status IS '宸ヤ綔娴佺姸鎬� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_workflow.trigger_type IS '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿';
+COMMENT ON COLUMN sj_workflow.trigger_interval IS '闂撮殧鏃堕暱';
+COMMENT ON COLUMN sj_workflow.next_trigger_at IS '涓嬫瑙﹀彂鏃堕棿';
+COMMENT ON COLUMN sj_workflow.block_strategy IS '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�';
+COMMENT ON COLUMN sj_workflow.executor_timeout IS '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇';
+COMMENT ON COLUMN sj_workflow.description IS '鎻忚堪';
+COMMENT ON COLUMN sj_workflow.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow.wf_context IS '涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_workflow.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow IS '宸ヤ綔娴�';
+
+-- sj_workflow_node
+CREATE TABLE sj_workflow_node
+(
+    id                   bigserial PRIMARY KEY,
+    namespace_id         varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    node_name            varchar(64)  NOT NULL,
+    group_name           varchar(64)  NOT NULL,
+    job_id               bigint       NOT NULL,
+    workflow_id          bigint       NOT NULL,
+    node_type            smallint     NOT NULL DEFAULT 1,
+    expression_type      smallint     NOT NULL DEFAULT 0,
+    fail_strategy        smallint     NOT NULL DEFAULT 1,
+    workflow_node_status smallint     NOT NULL DEFAULT 1,
+    priority_level       int          NOT NULL DEFAULT 1,
+    node_info            text         NULL     DEFAULT NULL,
+    version              int          NOT NULL,
+    ext_attrs            varchar(256) NULL     DEFAULT '',
+    deleted              smallint     NOT NULL DEFAULT 0,
+    create_dt            timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt            timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt);
+CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_node.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow_node.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow_node.node_name IS '鑺傜偣鍚嶇О';
+COMMENT ON COLUMN sj_workflow_node.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow_node.job_id IS '浠诲姟淇℃伅id';
+COMMENT ON COLUMN sj_workflow_node.workflow_id IS '宸ヤ綔娴両D';
+COMMENT ON COLUMN sj_workflow_node.node_type IS '1銆佷换鍔¤妭鐐� 2銆佹潯浠惰妭鐐�';
+COMMENT ON COLUMN sj_workflow_node.expression_type IS '1銆丼pEl銆�2銆丄viator 3銆丵L';
+COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '澶辫触绛栫暐 1銆佽烦杩� 2銆侀樆濉�';
+COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '宸ヤ綔娴佽妭鐐圭姸鎬� 0銆佸叧闂��1銆佸紑鍚�';
+COMMENT ON COLUMN sj_workflow_node.priority_level IS '浼樺厛绾�';
+COMMENT ON COLUMN sj_workflow_node.node_info IS '鑺傜偣淇℃伅 ';
+COMMENT ON COLUMN sj_workflow_node.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_node.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow_node.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow_node.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow_node IS '宸ヤ綔娴佽妭鐐�';
+
+-- sj_workflow_task_batch
+CREATE TABLE sj_workflow_task_batch
+(
+    id                bigserial PRIMARY KEY,
+    namespace_id      varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        varchar(64)  NOT NULL,
+    workflow_id       bigint       NOT NULL,
+    task_batch_status smallint     NOT NULL DEFAULT 0,
+    operation_reason  smallint     NOT NULL DEFAULT 0,
+    flow_info         text         NULL     DEFAULT NULL,
+    wf_context        text         NULL     DEFAULT NULL,
+    execution_at      bigint       NOT NULL DEFAULT 0,
+    ext_attrs         varchar(256) NULL     DEFAULT '',
+    version           int          NOT NULL DEFAULT 1,
+    deleted           smallint     NOT NULL DEFAULT 0,
+    create_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status);
+CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt);
+CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_task_batch.id IS '涓婚敭';
+COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '鍛藉悕绌洪棿id';
+COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '缁勫悕绉�';
+COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '宸ヤ綔娴佷换鍔d';
+COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�';
+COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '鎿嶄綔鍘熷洜';
+COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '娴佺▼淇℃伅';
+COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '鍏ㄥ眬涓婁笅鏂�';
+COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '浠诲姟鎵ц鏃堕棿';
+COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '鎵╁睍瀛楁';
+COMMENT ON COLUMN sj_workflow_task_batch.version IS '鐗堟湰鍙�';
+COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '閫昏緫鍒犻櫎 1銆佸垹闄�';
+COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '鍒涘缓鏃堕棿';
+COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '淇敼鏃堕棿';
+COMMENT ON TABLE sj_workflow_task_batch IS '宸ヤ綔娴佹壒娆�';
diff --git a/eims/script/sql/ry_vue_5.X.sql b/eims/script/sql/ry_vue_5.X.sql
new file mode 100644
index 0000000..3e3562d
--- /dev/null
+++ b/eims/script/sql/ry_vue_5.X.sql
@@ -0,0 +1,935 @@
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+create table sys_social
+(
+    id                 bigint           not null        comment '涓婚敭',
+    user_id            bigint           not null        comment '鐢ㄦ埛ID',
+    tenant_id          varchar(20)      default null    comment '绉熸埛id',
+    auth_id            varchar(255)     not null        comment '骞冲彴+骞冲彴鍞竴id',
+    source             varchar(255)     not null        comment '鐢ㄦ埛鏉ユ簮',
+    open_id            varchar(255)     default null    comment '骞冲彴缂栧彿鍞竴id',
+    user_name          varchar(30)      not null        comment '鐧诲綍璐﹀彿',
+    nick_name          varchar(30)      default ''      comment '鐢ㄦ埛鏄电О',
+    email              varchar(255)     default ''      comment '鐢ㄦ埛閭',
+    avatar             varchar(500)     default ''      comment '澶村儚鍦板潃',
+    access_token       varchar(255)     not null        comment '鐢ㄦ埛鐨勬巿鏉冧护鐗�',
+    expire_in          int              default null    comment '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    refresh_token      varchar(255)     default null    comment '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    access_code        varchar(255)     default null    comment '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    union_id           varchar(255)     default null    comment '鐢ㄦ埛鐨� unionid',
+    scope              varchar(255)     default null    comment '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    token_type         varchar(255)     default null    comment '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    id_token           varchar(2000)    default null    comment 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    mac_algorithm      varchar(255)     default null    comment '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    mac_key            varchar(255)     default null    comment '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    code               varchar(255)     default null    comment '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    oauth_token        varchar(255)     default null    comment 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    oauth_token_secret varchar(255)     default null    comment 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    create_dept        bigint(20)                       comment '鍒涘缓閮ㄩ棬',
+    create_by          bigint(20)                       comment '鍒涘缓鑰�',
+    create_time        datetime                         comment '鍒涘缓鏃堕棿',
+    update_by          bigint(20)                       comment '鏇存柊鑰�',
+    update_time        datetime                         comment '鏇存柊鏃堕棿',
+    del_flag           char(1)          default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    PRIMARY KEY (id)
+) engine=innodb comment = '绀句細鍖栧叧绯昏〃';
+
+
+-- ----------------------------
+-- 绉熸埛琛�
+-- ----------------------------
+create table sys_tenant
+(
+    id                bigint(20)    not null        comment 'id',
+    tenant_id         varchar(20)   not null        comment '绉熸埛缂栧彿',
+    contact_user_name varchar(20)                   comment '鑱旂郴浜�',
+    contact_phone     varchar(20)                   comment '鑱旂郴鐢佃瘽',
+    company_name      varchar(50)                   comment '浼佷笟鍚嶇О',
+    license_number    varchar(30)                   comment '缁熶竴绀句細淇$敤浠g爜',
+    address           varchar(200)                  comment '鍦板潃',
+    intro             varchar(200)                  comment '浼佷笟绠�浠�',
+    domain            varchar(200)                  comment '鍩熷悕',
+    remark            varchar(200)                  comment '澶囨敞',
+    package_id        bigint(20)                    comment '绉熸埛濂楅缂栧彿',
+    expire_time       datetime                      comment '杩囨湡鏃堕棿',
+    account_count     int           default -1      comment '鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級',
+    status            char(1)       default '0'     comment '绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag          char(1)       default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept       bigint(20)                    comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)                    comment '鍒涘缓鑰�',
+    create_time       datetime                      comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)                    comment '鏇存柊鑰�',
+    update_time       datetime                      comment '鏇存柊鏃堕棿',
+    primary key (id)
+) engine=innodb comment = '绉熸埛琛�';
+
+
+-- ----------------------------
+-- 鍒濆鍖�-绉熸埛琛ㄦ暟鎹�
+-- ----------------------------
+
+insert into sys_tenant values(1, '000000', '绠$悊缁�', '15888888888', 'XXX鏈夐檺鍏徃', null, null, '澶氱鎴烽�氱敤鍚庡彴绠$悊绠$悊绯荤粺', null, null, null, null, -1, '0', '0', 103, 1, sysdate(), null, null);
+
+
+-- ----------------------------
+-- 绉熸埛濂楅琛�
+-- ----------------------------
+create table sys_tenant_package (
+    package_id              bigint(20)     not null    comment '绉熸埛濂楅id',
+    package_name            varchar(20)                comment '濂楅鍚嶇О',
+    menu_ids                varchar(3000)              comment '鍏宠仈鑿滃崟id',
+    remark                  varchar(200)               comment '澶囨敞',
+    menu_check_strictly     tinyint(1)     default 1   comment '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
+    status                  char(1)        default '0' comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag                char(1)        default '0' comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept             bigint(20)                 comment '鍒涘缓閮ㄩ棬',
+    create_by               bigint(20)                 comment '鍒涘缓鑰�',
+    create_time             datetime                   comment '鍒涘缓鏃堕棿',
+    update_by               bigint(20)                 comment '鏇存柊鑰�',
+    update_time             datetime                   comment '鏇存柊鏃堕棿',
+    primary key (package_id)
+) engine=innodb comment = '绉熸埛濂楅琛�';
+
+
+-- ----------------------------
+-- 1銆侀儴闂ㄨ〃
+-- ----------------------------
+create table sys_dept (
+    dept_id           bigint(20)      not null                   comment '閮ㄩ棬id',
+    tenant_id         varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    parent_id         bigint(20)      default 0                  comment '鐖堕儴闂╥d',
+    ancestors         varchar(500)    default ''                 comment '绁栫骇鍒楄〃',
+    dept_name         varchar(30)     default ''                 comment '閮ㄩ棬鍚嶇О',
+    dept_category     varchar(100)    default null               comment '閮ㄩ棬绫诲埆缂栫爜',
+    order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+    leader            bigint(20)      default null               comment '璐熻矗浜�',
+    phone             varchar(11)     default null               comment '鑱旂郴鐢佃瘽',
+    email             varchar(50)     default null               comment '閭',
+    status            char(1)         default '0'                comment '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    primary key (dept_id)
+) engine=innodb comment = '閮ㄩ棬琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-閮ㄩ棬琛ㄦ暟鎹�
+-- ----------------------------
+
+
+insert into sys_dept values(100, '000000', 0,   '0',          'XXX绉戞妧',   null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(101, '000000', 100, '0,100',      '娣卞湷鎬诲叕鍙�', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(102, '000000', 100, '0,100',      '闀挎矙鍒嗗叕鍙�', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(103, '000000', 101, '0,100,101',  '鐮斿彂閮ㄩ棬',   null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(104, '000000', 101, '0,100,101',  '甯傚満閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(105, '000000', 101, '0,100,101',  '娴嬭瘯閮ㄩ棬',   null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(106, '000000', 101, '0,100,101',  '璐㈠姟閮ㄩ棬',   null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(107, '000000', 101, '0,100,101',  '杩愮淮閮ㄩ棬',   null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(108, '000000', 102, '0,100,102',  '甯傚満閮ㄩ棬',   null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+insert into sys_dept values(109, '000000', 102, '0,100,102',  '璐㈠姟閮ㄩ棬',   null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null);
+
+
+-- ----------------------------
+-- 2銆佺敤鎴蜂俊鎭〃
+-- ----------------------------
+create table sys_user (
+    user_id           bigint(20)      not null                   comment '鐢ㄦ埛ID',
+    tenant_id         varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    dept_id           bigint(20)      default null               comment '閮ㄩ棬ID',
+    user_name         varchar(30)     not null                   comment '鐢ㄦ埛璐﹀彿',
+    nick_name         varchar(30)     not null                   comment '鐢ㄦ埛鏄电О',
+    user_type         varchar(10)     default 'sys_user'         comment '鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�',
+    email             varchar(50)     default ''                 comment '鐢ㄦ埛閭',
+    phonenumber       varchar(11)     default ''                 comment '鎵嬫満鍙风爜',
+    sex               char(1)         default '0'                comment '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�',
+    avatar            bigint(20)                                 comment '澶村儚鍦板潃',
+    password          varchar(100)    default ''                 comment '瀵嗙爜',
+    status            char(1)         default '0'                comment '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    login_ip          varchar(128)    default ''                 comment '鏈�鍚庣櫥褰旾P',
+    login_date        datetime                                   comment '鏈�鍚庣櫥褰曟椂闂�',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    remark            varchar(500)    default null               comment '澶囨敞',
+    primary key (user_id)
+) engine=innodb comment = '鐢ㄦ埛淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_user values(1, '000000', 103, 'admin', '鐤媯鐨勭嫯瀛怢i', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '绠$悊鍛�');
+insert into sys_user values(3, '000000', 108, 'test', '鏈儴闂ㄥ強浠ヤ笅 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 3, sysdate(), null);
+insert into sys_user values(4, '000000', 102, 'test1', '浠呮湰浜� 瀵嗙爜666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 4, sysdate(), null);
+
+-- ----------------------------
+-- 3銆佸矖浣嶄俊鎭〃
+-- ----------------------------
+create table sys_post
+(
+    post_id       bigint(20)      not null                   comment '宀椾綅ID',
+    tenant_id     varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    dept_id       bigint(20)      not null                   comment '閮ㄩ棬id',
+    post_code     varchar(64)     not null                   comment '宀椾綅缂栫爜',
+    post_category varchar(100)    default null               comment '宀椾綅绫诲埆缂栫爜',
+    post_name     varchar(50)     not null                   comment '宀椾綅鍚嶇О',
+    post_sort     int(4)          not null                   comment '鏄剧ず椤哄簭',
+    status        char(1)         not null                   comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    create_dept   bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by     bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time   datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by     bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time   datetime                                   comment '鏇存柊鏃堕棿',
+    remark        varchar(500)    default null               comment '澶囨敞',
+    primary key (post_id)
+) engine=innodb comment = '宀椾綅淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-宀椾綅淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_post values(1, '000000', 103, 'ceo',  null, '钁d簨闀�',    1, '0', 103, 1, sysdate(), null, null, '');
+insert into sys_post values(2, '000000', 100, 'se',   null, '椤圭洰缁忕悊',  2, '0', 103, 1, sysdate(), null, null, '');
+insert into sys_post values(3, '000000', 100, 'hr',   null, '浜哄姏璧勬簮',  3, '0', 103, 1, sysdate(), null, null, '');
+insert into sys_post values(4, '000000', 100, 'user', null, '鏅�氬憳宸�',  4, '0', 103, 1, sysdate(), null, null, '');
+
+
+-- ----------------------------
+-- 4銆佽鑹蹭俊鎭〃
+-- ----------------------------
+create table sys_role (
+    role_id              bigint(20)      not null                   comment '瑙掕壊ID',
+    tenant_id            varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    role_name            varchar(30)     not null                   comment '瑙掕壊鍚嶇О',
+    role_key             varchar(100)    not null                   comment '瑙掕壊鏉冮檺瀛楃涓�',
+    role_sort            int(4)          not null                   comment '鏄剧ず椤哄簭',
+    data_scope           char(1)         default '1'                comment '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級',
+    menu_check_strictly  tinyint(1)      default 1                  comment '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
+    dept_check_strictly  tinyint(1)      default 1                  comment '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
+    status               char(1)         not null                   comment '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag             char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept          bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by            bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time          datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by            bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time          datetime                                   comment '鏇存柊鏃堕棿',
+    remark               varchar(500)    default null               comment '澶囨敞',
+    primary key (role_id)
+) engine=innodb comment = '瑙掕壊淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_role values(1, '000000', '瓒呯骇绠$悊鍛�',  'superadmin',  1, 1, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '瓒呯骇绠$悊鍛�');
+insert into sys_role values(3, '000000', '鏈儴闂ㄥ強浠ヤ笅', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '');
+insert into sys_role values(4, '000000', '浠呮湰浜�',      'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '');
+
+-- ----------------------------
+-- 5銆佽彍鍗曟潈闄愯〃
+-- ----------------------------
+create table sys_menu (
+    menu_id           bigint(20)      not null                   comment '鑿滃崟ID',
+    menu_name         varchar(50)     not null                   comment '鑿滃崟鍚嶇О',
+    parent_id         bigint(20)      default 0                  comment '鐖惰彍鍗旾D',
+    order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+    path              varchar(200)    default ''                 comment '璺敱鍦板潃',
+    component         varchar(255)    default null               comment '缁勪欢璺緞',
+    query_param       varchar(255)    default null               comment '璺敱鍙傛暟',
+    is_frame          int(1)          default 1                  comment '鏄惁涓哄閾撅紙0鏄� 1鍚︼級',
+    is_cache          int(1)          default 0                  comment '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級',
+    menu_type         char(1)         default ''                 comment '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�',
+    visible           char(1)         default 0                  comment '鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�',
+    status            char(1)         default 0                  comment '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    perms             varchar(100)    default null               comment '鏉冮檺鏍囪瘑',
+    icon              varchar(100)    default '#'                comment '鑿滃崟鍥炬爣',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    remark            varchar(500)    default ''                 comment '澶囨敞',
+    primary key (menu_id)
+) engine=innodb comment = '鑿滃崟鏉冮檺琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鑿滃崟淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+-- 涓�绾ц彍鍗�
+insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',           null, '', 1, 0, 'M', '0', '0', '', 'system',   103, 1, sysdate(), null, null, '绯荤粺绠$悊鐩綍');
+insert into sys_menu values('6', '绉熸埛绠$悊', '0', '2', 'tenant',           null, '', 1, 0, 'M', '0', '0', '', 'chart',    103, 1, sysdate(), null, null, '绉熸埛绠$悊鐩綍');
+insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '3', 'monitor',          null, '', 1, 0, 'M', '0', '0', '', 'monitor',  103, 1, sysdate(), null, null, '绯荤粺鐩戞帶鐩綍');
+insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '4', 'tool',             null, '', 1, 0, 'M', '0', '0', '', 'tool',     103, 1, sysdate(), null, null, '绯荤粺宸ュ叿鐩綍');
+insert into sys_menu values('4', 'PLUS瀹樼綉', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide',    103, 1, sysdate(), null, null, 'RuoYi-Vue-Plus瀹樼綉鍦板潃');
+insert into sys_menu values('5', '娴嬭瘯鑿滃崟', '0', '5', 'demo',             null, '', 1, 0, 'M', '0', '0', '', 'star',     103, 1, sysdate(), null, null, '娴嬭瘯鑿滃崟');
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('100',  '鐢ㄦ埛绠$悊',     '1',   '1', 'user',             'system/user/index',            '', 1, 0, 'C', '0', '0', 'system:user:list',            'user',          103, 1, sysdate(), null, null, '鐢ㄦ埛绠$悊鑿滃崟');
+insert into sys_menu values('101',  '瑙掕壊绠$悊',     '1',   '2', 'role',             'system/role/index',            '', 1, 0, 'C', '0', '0', 'system:role:list',            'peoples',       103, 1, sysdate(), null, null, '瑙掕壊绠$悊鑿滃崟');
+insert into sys_menu values('102',  '鑿滃崟绠$悊',     '1',   '3', 'menu',             'system/menu/index',            '', 1, 0, 'C', '0', '0', 'system:menu:list',            'tree-table',    103, 1, sysdate(), null, null, '鑿滃崟绠$悊鑿滃崟');
+insert into sys_menu values('103',  '閮ㄩ棬绠$悊',     '1',   '4', 'dept',             'system/dept/index',            '', 1, 0, 'C', '0', '0', 'system:dept:list',            'tree',          103, 1, sysdate(), null, null, '閮ㄩ棬绠$悊鑿滃崟');
+insert into sys_menu values('104',  '宀椾綅绠$悊',     '1',   '5', 'post',             'system/post/index',            '', 1, 0, 'C', '0', '0', 'system:post:list',            'post',          103, 1, sysdate(), null, null, '宀椾綅绠$悊鑿滃崟');
+insert into sys_menu values('105',  '瀛楀吀绠$悊',     '1',   '6', 'dict',             'system/dict/index',            '', 1, 0, 'C', '0', '0', 'system:dict:list',            'dict',          103, 1, sysdate(), null, null, '瀛楀吀绠$悊鑿滃崟');
+insert into sys_menu values('106',  '鍙傛暟璁剧疆',     '1',   '7', 'config',           'system/config/index',          '', 1, 0, 'C', '0', '0', 'system:config:list',          'edit',          103, 1, sysdate(), null, null, '鍙傛暟璁剧疆鑿滃崟');
+insert into sys_menu values('107',  '閫氱煡鍏憡',     '1',   '8', 'notice',           'system/notice/index',          '', 1, 0, 'C', '0', '0', 'system:notice:list',          'message',       103, 1, sysdate(), null, null, '閫氱煡鍏憡鑿滃崟');
+insert into sys_menu values('108',  '鏃ュ織绠$悊',     '1',   '9', 'log',              '',                             '', 1, 0, 'M', '0', '0', '',                            'log',           103, 1, sysdate(), null, null, '鏃ュ織绠$悊鑿滃崟');
+insert into sys_menu values('109',  '鍦ㄧ嚎鐢ㄦ埛',     '2',   '1', 'online',           'monitor/online/index',         '', 1, 0, 'C', '0', '0', 'monitor:online:list',         'online',        103, 1, sysdate(), null, null, '鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+insert into sys_menu values('113',  '缂撳瓨鐩戞帶',     '2',   '5', 'cache',            'monitor/cache/index',          '', 1, 0, 'C', '0', '0', 'monitor:cache:list',          'redis',         103, 1, sysdate(), null, null, '缂撳瓨鐩戞帶鑿滃崟');
+insert into sys_menu values('115',  '浠g爜鐢熸垚',     '3',   '2', 'gen',              'tool/gen/index',               '', 1, 0, 'C', '0', '0', 'tool:gen:list',               'code',          103, 1, sysdate(), null, null, '浠g爜鐢熸垚鑿滃崟');
+insert into sys_menu values('121',  '绉熸埛绠$悊',     '6',   '1', 'tenant',           'system/tenant/index',          '', 1, 0, 'C', '0', '0', 'system:tenant:list',          'list',          103, 1, sysdate(), null, null, '绉熸埛绠$悊鑿滃崟');
+insert into sys_menu values('122',  '绉熸埛濂楅绠$悊',  '6',   '2', 'tenantPackage',    'system/tenantPackage/index',   '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list',   'form',          103, 1, sysdate(), null, null, '绉熸埛濂楅绠$悊鑿滃崟');
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', 1, 0, 'C', '0', '0', 'system:client:list',          'international', 103, 1, sysdate(), null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+
+-- springboot-admin鐩戞帶
+insert into sys_menu values('117',  'Admin鐩戞帶',   '2',   '5',  'Admin',            'monitor/admin/index',         '', 1, 0, 'C', '0', '0', 'monitor:admin:list',           'dashboard',     103, 1, sysdate(), null, null, 'Admin鐩戞帶鑿滃崟');
+-- oss鑿滃崟
+insert into sys_menu values('118',  '鏂囦欢绠$悊',     '1',   '10', 'oss',              'system/oss/index',            '', 1, 0, 'C', '0', '0', 'system:oss:list',              'upload',        103, 1, sysdate(), null, null, '鏂囦欢绠$悊鑿滃崟');
+-- snail-job server鎺у埗鍙�
+insert into sys_menu values('120',  '浠诲姟璋冨害涓績',  '2',   '6',  'snailjob',     'monitor/snailjob/index',    '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list',          'job',           103, 1, sysdate(), null, null, 'SnailJob鎺у埗鍙拌彍鍗�');
+
+-- 涓夌骇鑿滃崟
+insert into sys_menu values('500',  '鎿嶄綔鏃ュ織', '108', '1', 'operlog',    'monitor/operlog/index',    '', 1, 0, 'C', '0', '0', 'monitor:operlog:list',    'form',          103, 1, sysdate(), null, null, '鎿嶄綔鏃ュ織鑿滃崟');
+insert into sys_menu values('501',  '鐧诲綍鏃ュ織', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor',    103, 1, sysdate(), null, null, '鐧诲綍鏃ュ織鑿滃崟');
+-- 鐢ㄦ埛绠$悊鎸夐挳
+insert into sys_menu values('1001', '鐢ㄦ埛鏌ヨ', '100', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1002', '鐢ㄦ埛鏂板', '100', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1003', '鐢ㄦ埛淇敼', '100', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1004', '鐢ㄦ埛鍒犻櫎', '100', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1005', '鐢ㄦ埛瀵煎嚭', '100', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:export',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1006', '鐢ㄦ埛瀵煎叆', '100', '6',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:import',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1007', '閲嶇疆瀵嗙爜', '100', '7',  '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd',       '#', 103, 1, sysdate(), null, null, '');
+-- 瑙掕壊绠$悊鎸夐挳
+insert into sys_menu values('1008', '瑙掕壊鏌ヨ', '101', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1009', '瑙掕壊鏂板', '101', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1010', '瑙掕壊淇敼', '101', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1011', '瑙掕壊鍒犻櫎', '101', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1012', '瑙掕壊瀵煎嚭', '101', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:role:export',         '#', 103, 1, sysdate(), null, null, '');
+-- 鑿滃崟绠$悊鎸夐挳
+insert into sys_menu values('1013', '鑿滃崟鏌ヨ', '102', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1014', '鑿滃崟鏂板', '102', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1015', '鑿滃崟淇敼', '102', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1016', '鑿滃崟鍒犻櫎', '102', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove',         '#', 103, 1, sysdate(), null, null, '');
+-- 閮ㄩ棬绠$悊鎸夐挳
+insert into sys_menu values('1017', '閮ㄩ棬鏌ヨ', '103', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1018', '閮ㄩ棬鏂板', '103', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1019', '閮ㄩ棬淇敼', '103', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1020', '閮ㄩ棬鍒犻櫎', '103', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove',         '#', 103, 1, sysdate(), null, null, '');
+-- 宀椾綅绠$悊鎸夐挳
+insert into sys_menu values('1021', '宀椾綅鏌ヨ', '104', '1',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1022', '宀椾綅鏂板', '104', '2',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1023', '宀椾綅淇敼', '104', '3',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1024', '宀椾綅鍒犻櫎', '104', '4',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1025', '宀椾綅瀵煎嚭', '104', '5',  '', '', '', 1, 0, 'F', '0', '0', 'system:post:export',         '#', 103, 1, sysdate(), null, null, '');
+-- 瀛楀吀绠$悊鎸夐挳
+insert into sys_menu values('1026', '瀛楀吀鏌ヨ', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1027', '瀛楀吀鏂板', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1028', '瀛楀吀淇敼', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1029', '瀛楀吀鍒犻櫎', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1030', '瀛楀吀瀵煎嚭', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export',         '#', 103, 1, sysdate(), null, null, '');
+-- 鍙傛暟璁剧疆鎸夐挳
+insert into sys_menu values('1031', '鍙傛暟鏌ヨ', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1032', '鍙傛暟鏂板', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1033', '鍙傛暟淇敼', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1034', '鍙傛暟鍒犻櫎', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1035', '鍙傛暟瀵煎嚭', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export',       '#', 103, 1, sysdate(), null, null, '');
+-- 閫氱煡鍏憡鎸夐挳
+insert into sys_menu values('1036', '鍏憡鏌ヨ', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1037', '鍏憡鏂板', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1038', '鍏憡淇敼', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1039', '鍏憡鍒犻櫎', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove',       '#', 103, 1, sysdate(), null, null, '');
+-- 鎿嶄綔鏃ュ織鎸夐挳
+insert into sys_menu values('1040', '鎿嶄綔鏌ヨ', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query',      '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1041', '鎿嶄綔鍒犻櫎', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove',     '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1042', '鏃ュ織瀵煎嚭', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export',     '#', 103, 1, sysdate(), null, null, '');
+-- 鐧诲綍鏃ュ織鎸夐挳
+insert into sys_menu values('1043', '鐧诲綍鏌ヨ', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query',   '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1044', '鐧诲綍鍒犻櫎', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove',  '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1045', '鏃ュ織瀵煎嚭', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export',  '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1050', '璐︽埛瑙i攣', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 103, 1, sysdate(), null, null, '');
+-- 鍦ㄧ嚎鐢ㄦ埛鎸夐挳
+insert into sys_menu values('1046', '鍦ㄧ嚎鏌ヨ', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1047', '鎵归噺寮洪��', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1048', '鍗曟潯寮洪��', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate(), null, null, '');
+-- 浠g爜鐢熸垚鎸夐挳
+insert into sys_menu values('1055', '鐢熸垚鏌ヨ', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query',             '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1056', '鐢熸垚淇敼', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit',              '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1057', '鐢熸垚鍒犻櫎', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1058', '瀵煎叆浠g爜', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import',            '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1059', '棰勮浠g爜', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview',           '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1060', '鐢熸垚浠g爜', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code',              '#', 103, 1, sysdate(), null, null, '');
+-- oss鐩稿叧鎸夐挳
+insert into sys_menu values('1600', '鏂囦欢鏌ヨ', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1601', '鏂囦欢涓婁紶', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1602', '鏂囦欢涓嬭浇', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download',     '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1603', '鏂囦欢鍒犻櫎', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove',      '#', 103, 1, sysdate(), null, null, '');
+
+-- 绉熸埛绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('1606', '绉熸埛鏌ヨ', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query',   '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1607', '绉熸埛鏂板', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add',     '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1608', '绉熸埛淇敼', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit',    '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1609', '绉熸埛鍒犻櫎', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove',  '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1610', '绉熸埛瀵煎嚭', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export',  '#', 103, 1, sysdate(), null, null, '');
+-- 绉熸埛濂楅绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('1611', '绉熸埛濂楅鏌ヨ', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query',   '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1612', '绉熸埛濂楅鏂板', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add',     '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1613', '绉熸埛濂楅淇敼', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit',    '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1614', '绉熸埛濂楅鍒犻櫎', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove',  '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values ('1615', '绉熸埛濂楅瀵煎嚭', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export',  '#', 103, 1, sysdate(), null, null, '');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export',       '#', 103, 1, sysdate(), null, null, '');
+-- 娴嬭瘯鑿滃崟
+insert into sys_menu values('1500', '娴嬭瘯鍗曡〃',      '5',    '1', 'demo', 'demo/demo/index', '',  1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate(), null, null, '娴嬭瘯鍗曡〃鑿滃崟');
+insert into sys_menu values('1501', '娴嬭瘯鍗曡〃鏌ヨ',   '1500', '1', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:demo:query',               '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1502', '娴嬭瘯鍗曡〃鏂板',   '1500', '2', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:demo:add',                 '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1503', '娴嬭瘯鍗曡〃淇敼',   '1500', '3', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:demo:edit',                '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1504', '娴嬭瘯鍗曡〃鍒犻櫎',   '1500', '4', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:demo:remove',              '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1505', '娴嬭瘯鍗曡〃瀵煎嚭',   '1500', '5', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:demo:export',              '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1506', '娴嬭瘯鏍戣〃',      '5',    '1', 'tree', 'demo/tree/index', '',  1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate(), null, null, '娴嬭瘯鏍戣〃鑿滃崟');
+insert into sys_menu values('1507', '娴嬭瘯鏍戣〃鏌ヨ',   '1506', '1', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:tree:query',               '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1508', '娴嬭瘯鏍戣〃鏂板',   '1506', '2', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:tree:add',                 '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1509', '娴嬭瘯鏍戣〃淇敼',   '1506', '3', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:tree:edit',                '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1510', '娴嬭瘯鏍戣〃鍒犻櫎',   '1506', '4', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:tree:remove',              '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1511', '娴嬭瘯鏍戣〃瀵煎嚭',   '1506', '5', '#',    '', '',  1, 0, 'F', '0', '0', 'demo:tree:export',              '#', 103, 1, sysdate(), null, null, '');
+
+-- ----------------------------
+-- 6銆佺敤鎴峰拰瑙掕壊鍏宠仈琛�  鐢ㄦ埛N-1瑙掕壊
+-- ----------------------------
+create table sys_user_role (
+    user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+    role_id   bigint(20) not null comment '瑙掕壊ID',
+    primary key(user_id, role_id)
+) engine=innodb comment = '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛鍜岃鑹插叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_role values ('1', '1');
+insert into sys_user_role values ('3', '3');
+insert into sys_user_role values ('4', '4');
+
+-- ----------------------------
+-- 7銆佽鑹插拰鑿滃崟鍏宠仈琛�  瑙掕壊1-N鑿滃崟
+-- ----------------------------
+create table sys_role_menu (
+    role_id   bigint(20) not null comment '瑙掕壊ID',
+    menu_id   bigint(20) not null comment '鑿滃崟ID',
+    primary key(role_id, menu_id)
+) engine=innodb comment = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_menu values ('3', '1');
+insert into sys_role_menu values ('3', '5');
+insert into sys_role_menu values ('3', '100');
+insert into sys_role_menu values ('3', '101');
+insert into sys_role_menu values ('3', '102');
+insert into sys_role_menu values ('3', '103');
+insert into sys_role_menu values ('3', '104');
+insert into sys_role_menu values ('3', '105');
+insert into sys_role_menu values ('3', '106');
+insert into sys_role_menu values ('3', '107');
+insert into sys_role_menu values ('3', '108');
+insert into sys_role_menu values ('3', '500');
+insert into sys_role_menu values ('3', '501');
+insert into sys_role_menu values ('3', '1001');
+insert into sys_role_menu values ('3', '1002');
+insert into sys_role_menu values ('3', '1003');
+insert into sys_role_menu values ('3', '1004');
+insert into sys_role_menu values ('3', '1005');
+insert into sys_role_menu values ('3', '1006');
+insert into sys_role_menu values ('3', '1007');
+insert into sys_role_menu values ('3', '1008');
+insert into sys_role_menu values ('3', '1009');
+insert into sys_role_menu values ('3', '1010');
+insert into sys_role_menu values ('3', '1011');
+insert into sys_role_menu values ('3', '1012');
+insert into sys_role_menu values ('3', '1013');
+insert into sys_role_menu values ('3', '1014');
+insert into sys_role_menu values ('3', '1015');
+insert into sys_role_menu values ('3', '1016');
+insert into sys_role_menu values ('3', '1017');
+insert into sys_role_menu values ('3', '1018');
+insert into sys_role_menu values ('3', '1019');
+insert into sys_role_menu values ('3', '1020');
+insert into sys_role_menu values ('3', '1021');
+insert into sys_role_menu values ('3', '1022');
+insert into sys_role_menu values ('3', '1023');
+insert into sys_role_menu values ('3', '1024');
+insert into sys_role_menu values ('3', '1025');
+insert into sys_role_menu values ('3', '1026');
+insert into sys_role_menu values ('3', '1027');
+insert into sys_role_menu values ('3', '1028');
+insert into sys_role_menu values ('3', '1029');
+insert into sys_role_menu values ('3', '1030');
+insert into sys_role_menu values ('3', '1031');
+insert into sys_role_menu values ('3', '1032');
+insert into sys_role_menu values ('3', '1033');
+insert into sys_role_menu values ('3', '1034');
+insert into sys_role_menu values ('3', '1035');
+insert into sys_role_menu values ('3', '1036');
+insert into sys_role_menu values ('3', '1037');
+insert into sys_role_menu values ('3', '1038');
+insert into sys_role_menu values ('3', '1039');
+insert into sys_role_menu values ('3', '1040');
+insert into sys_role_menu values ('3', '1041');
+insert into sys_role_menu values ('3', '1042');
+insert into sys_role_menu values ('3', '1043');
+insert into sys_role_menu values ('3', '1044');
+insert into sys_role_menu values ('3', '1045');
+insert into sys_role_menu values ('3', '1500');
+insert into sys_role_menu values ('3', '1501');
+insert into sys_role_menu values ('3', '1502');
+insert into sys_role_menu values ('3', '1503');
+insert into sys_role_menu values ('3', '1504');
+insert into sys_role_menu values ('3', '1505');
+insert into sys_role_menu values ('3', '1506');
+insert into sys_role_menu values ('3', '1507');
+insert into sys_role_menu values ('3', '1508');
+insert into sys_role_menu values ('3', '1509');
+insert into sys_role_menu values ('3', '1510');
+insert into sys_role_menu values ('3', '1511');
+insert into sys_role_menu values ('4', '5');
+insert into sys_role_menu values ('4', '1500');
+insert into sys_role_menu values ('4', '1501');
+insert into sys_role_menu values ('4', '1502');
+insert into sys_role_menu values ('4', '1503');
+insert into sys_role_menu values ('4', '1504');
+insert into sys_role_menu values ('4', '1505');
+insert into sys_role_menu values ('4', '1506');
+insert into sys_role_menu values ('4', '1507');
+insert into sys_role_menu values ('4', '1508');
+insert into sys_role_menu values ('4', '1509');
+insert into sys_role_menu values ('4', '1510');
+insert into sys_role_menu values ('4', '1511');
+
+-- ----------------------------
+-- 8銆佽鑹插拰閮ㄩ棬鍏宠仈琛�  瑙掕壊1-N閮ㄩ棬
+-- ----------------------------
+create table sys_role_dept (
+    role_id   bigint(20) not null comment '瑙掕壊ID',
+    dept_id   bigint(20) not null comment '閮ㄩ棬ID',
+    primary key(role_id, dept_id)
+) engine=innodb comment = '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+
+-- ----------------------------
+-- 9銆佺敤鎴蜂笌宀椾綅鍏宠仈琛�  鐢ㄦ埛1-N宀椾綅
+-- ----------------------------
+create table sys_user_post
+(
+    user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+    post_id   bigint(20) not null comment '宀椾綅ID',
+    primary key (user_id, post_id)
+) engine=innodb comment = '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_post values ('1', '1');
+
+-- ----------------------------
+-- 10銆佹搷浣滄棩蹇楄褰�
+-- ----------------------------
+create table sys_oper_log (
+    oper_id           bigint(20)      not null                   comment '鏃ュ織涓婚敭',
+    tenant_id         varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    title             varchar(50)     default ''                 comment '妯″潡鏍囬',
+    business_type     int(2)          default 0                  comment '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�',
+    method            varchar(100)    default ''                 comment '鏂规硶鍚嶇О',
+    request_method    varchar(10)     default ''                 comment '璇锋眰鏂瑰紡',
+    operator_type     int(1)          default 0                  comment '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級',
+    oper_name         varchar(50)     default ''                 comment '鎿嶄綔浜哄憳',
+    dept_name         varchar(50)     default ''                 comment '閮ㄩ棬鍚嶇О',
+    oper_url          varchar(255)    default ''                 comment '璇锋眰URL',
+    oper_ip           varchar(128)    default ''                 comment '涓绘満鍦板潃',
+    oper_location     varchar(255)    default ''                 comment '鎿嶄綔鍦扮偣',
+    oper_param        varchar(2000)   default ''                 comment '璇锋眰鍙傛暟',
+    json_result       varchar(2000)   default ''                 comment '杩斿洖鍙傛暟',
+    status            int(1)          default 0                  comment '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�',
+    error_msg         varchar(2000)   default ''                 comment '閿欒娑堟伅',
+    oper_time         datetime                                   comment '鎿嶄綔鏃堕棿',
+    cost_time         bigint(20)      default 0                  comment '娑堣�楁椂闂�',
+    primary key (oper_id),
+    key idx_sys_oper_log_bt (business_type),
+    key idx_sys_oper_log_s  (status),
+    key idx_sys_oper_log_ot (oper_time)
+) engine=innodb comment = '鎿嶄綔鏃ュ織璁板綍';
+
+
+-- ----------------------------
+-- 11銆佸瓧鍏哥被鍨嬭〃
+-- ----------------------------
+create table sys_dict_type
+(
+    dict_id          bigint(20)      not null                   comment '瀛楀吀涓婚敭',
+    tenant_id        varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    dict_name        varchar(100)    default ''                 comment '瀛楀吀鍚嶇О',
+    dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+    create_dept      bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by        bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by        bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time      datetime                                   comment '鏇存柊鏃堕棿',
+    remark           varchar(500)    default null               comment '澶囨敞',
+    primary key (dict_id),
+    unique (tenant_id, dict_type)
+) engine=innodb comment = '瀛楀吀绫诲瀷琛�';
+
+insert into sys_dict_type values(1, '000000', '鐢ㄦ埛鎬у埆', 'sys_user_sex',        103, 1, sysdate(), null, null, '鐢ㄦ埛鎬у埆鍒楄〃');
+insert into sys_dict_type values(2, '000000', '鑿滃崟鐘舵��', 'sys_show_hide',       103, 1, sysdate(), null, null, '鑿滃崟鐘舵�佸垪琛�');
+insert into sys_dict_type values(3, '000000', '绯荤粺寮�鍏�', 'sys_normal_disable',  103, 1, sysdate(), null, null, '绯荤粺寮�鍏冲垪琛�');
+insert into sys_dict_type values(6, '000000', '绯荤粺鏄惁', 'sys_yes_no',          103, 1, sysdate(), null, null, '绯荤粺鏄惁鍒楄〃');
+insert into sys_dict_type values(7, '000000', '閫氱煡绫诲瀷', 'sys_notice_type',     103, 1, sysdate(), null, null, '閫氱煡绫诲瀷鍒楄〃');
+insert into sys_dict_type values(8, '000000', '閫氱煡鐘舵��', 'sys_notice_status',   103, 1, sysdate(), null, null, '閫氱煡鐘舵�佸垪琛�');
+insert into sys_dict_type values(9, '000000', '鎿嶄綔绫诲瀷', 'sys_oper_type',       103, 1, sysdate(), null, null, '鎿嶄綔绫诲瀷鍒楄〃');
+insert into sys_dict_type values(10, '000000', '绯荤粺鐘舵��', 'sys_common_status',  103, 1, sysdate(), null, null, '鐧诲綍鐘舵�佸垪琛�');
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     103, 1, sysdate(), null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    103, 1, sysdate(), null, null, '瀹㈡埛绔澶囩被鍨�');
+
+
+-- ----------------------------
+-- 12銆佸瓧鍏告暟鎹〃
+-- ----------------------------
+create table sys_dict_data
+(
+    dict_code        bigint(20)      not null                   comment '瀛楀吀缂栫爜',
+    tenant_id        varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    dict_sort        int(4)          default 0                  comment '瀛楀吀鎺掑簭',
+    dict_label       varchar(100)    default ''                 comment '瀛楀吀鏍囩',
+    dict_value       varchar(100)    default ''                 comment '瀛楀吀閿��',
+    dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+    css_class        varchar(100)    default null               comment '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�',
+    list_class       varchar(100)    default null               comment '琛ㄦ牸鍥炴樉鏍峰紡',
+    is_default       char(1)         default 'N'                comment '鏄惁榛樿锛圷鏄� N鍚︼級',
+    create_dept      bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by        bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by        bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time      datetime                                   comment '鏇存柊鏃堕棿',
+    remark           varchar(500)    default null               comment '澶囨敞',
+    primary key (dict_code)
+) engine=innodb comment = '瀛楀吀鏁版嵁琛�';
+
+insert into sys_dict_data values(1, '000000', 1,  '鐢�',       '0',       'sys_user_sex',        '',   '',        'Y', 103, 1, sysdate(), null, null, '鎬у埆鐢�');
+insert into sys_dict_data values(2, '000000', 2,  '濂�',       '1',       'sys_user_sex',        '',   '',        'N', 103, 1, sysdate(), null, null, '鎬у埆濂�');
+insert into sys_dict_data values(3, '000000', 3,  '鏈煡',     '2',       'sys_user_sex',        '',   '',        'N', 103, 1, sysdate(), null, null, '鎬у埆鏈煡');
+insert into sys_dict_data values(4, '000000', 1,  '鏄剧ず',     '0',       'sys_show_hide',       '',   'primary', 'Y', 103, 1, sysdate(), null, null, '鏄剧ず鑿滃崟');
+insert into sys_dict_data values(5, '000000', 2,  '闅愯棌',     '1',       'sys_show_hide',       '',   'danger',  'N', 103, 1, sysdate(), null, null, '闅愯棌鑿滃崟');
+insert into sys_dict_data values(6, '000000', 1,  '姝e父',     '0',       'sys_normal_disable',  '',   'primary', 'Y', 103, 1, sysdate(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(7, '000000', 2,  '鍋滅敤',     '1',       'sys_normal_disable',  '',   'danger',  'N', 103, 1, sysdate(), null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(12, '000000', 1,  '鏄�',       'Y',       'sys_yes_no',          '',   'primary', 'Y', 103, 1, sysdate(), null, null, '绯荤粺榛樿鏄�');
+insert into sys_dict_data values(13, '000000', 2,  '鍚�',       'N',       'sys_yes_no',          '',   'danger',  'N', 103, 1, sysdate(), null, null, '绯荤粺榛樿鍚�');
+insert into sys_dict_data values(14, '000000', 1,  '閫氱煡',     '1',       'sys_notice_type',     '',   'warning', 'Y', 103, 1, sysdate(), null, null, '閫氱煡');
+insert into sys_dict_data values(15, '000000', 2,  '鍏憡',     '2',       'sys_notice_type',     '',   'success', 'N', 103, 1, sysdate(), null, null, '鍏憡');
+insert into sys_dict_data values(16, '000000', 1,  '姝e父',     '0',       'sys_notice_status',   '',   'primary', 'Y', 103, 1, sysdate(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(17, '000000', 2,  '鍏抽棴',     '1',       'sys_notice_status',   '',   'danger',  'N', 103, 1, sysdate(), null, null, '鍏抽棴鐘舵��');
+insert into sys_dict_data values(29, '000000', 99, '鍏朵粬',     '0',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate(), null, null, '鍏朵粬鎿嶄綔');
+insert into sys_dict_data values(18, '000000', 1,  '鏂板',     '1',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate(), null, null, '鏂板鎿嶄綔');
+insert into sys_dict_data values(19, '000000', 2,  '淇敼',     '2',       'sys_oper_type',       '',   'info',    'N', 103, 1, sysdate(), null, null, '淇敼鎿嶄綔');
+insert into sys_dict_data values(20, '000000', 3,  '鍒犻櫎',     '3',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate(), null, null, '鍒犻櫎鎿嶄綔');
+insert into sys_dict_data values(21, '000000', 4,  '鎺堟潈',     '4',       'sys_oper_type',       '',   'primary', 'N', 103, 1, sysdate(), null, null, '鎺堟潈鎿嶄綔');
+insert into sys_dict_data values(22, '000000', 5,  '瀵煎嚭',     '5',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate(), null, null, '瀵煎嚭鎿嶄綔');
+insert into sys_dict_data values(23, '000000', 6,  '瀵煎叆',     '6',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate(), null, null, '瀵煎叆鎿嶄綔');
+insert into sys_dict_data values(24, '000000', 7,  '寮洪��',     '7',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate(), null, null, '寮洪��鎿嶄綔');
+insert into sys_dict_data values(25, '000000', 8,  '鐢熸垚浠g爜', '8',       'sys_oper_type',       '',   'warning', 'N', 103, 1, sysdate(), null, null, '鐢熸垚鎿嶄綔');
+insert into sys_dict_data values(26, '000000', 9,  '娓呯┖鏁版嵁', '9',       'sys_oper_type',       '',   'danger',  'N', 103, 1, sysdate(), null, null, '娓呯┖鎿嶄綔');
+insert into sys_dict_data values(27, '000000', 1,  '鎴愬姛',     '0',       'sys_common_status',   '',   'primary', 'N', 103, 1, sysdate(), null, null, '姝e父鐘舵��');
+insert into sys_dict_data values(28, '000000', 2,  '澶辫触',     '1',       'sys_common_status',   '',   'danger',  'N', 103, 1, sysdate(), null, null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   'el-check-tag',   'default', 'N', 103, 1, sysdate(), null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   'el-check-tag',   'default', 'N', 103, 1, sysdate(), null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   'el-check-tag',   'default', 'N', 103, 1, sysdate(), null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   'el-check-tag',   'default', 'N', 103, 1, sysdate(), null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   'el-check-tag',   'default', 'N', 103, 1, sysdate(), null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC',    'pc',         'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜', 'android',     'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS', 'ios',          'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�', 'xcx',       'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, '灏忕▼搴�');
+
+
+-- ----------------------------
+-- 13銆佸弬鏁伴厤缃〃
+-- ----------------------------
+create table sys_config (
+    config_id         bigint(20)      not null                   comment '鍙傛暟涓婚敭',
+    tenant_id         varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    config_name       varchar(100)    default ''                 comment '鍙傛暟鍚嶇О',
+    config_key        varchar(100)    default ''                 comment '鍙傛暟閿悕',
+    config_value      varchar(500)    default ''                 comment '鍙傛暟閿��',
+    config_type       char(1)         default 'N'                comment '绯荤粺鍐呯疆锛圷鏄� N鍚︼級',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    remark            varchar(500)    default null               comment '澶囨敞',
+    primary key (config_id)
+) engine=innodb comment = '鍙傛暟閰嶇疆琛�';
+
+insert into sys_config values(1, '000000', '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О',     'sys.index.skinName',            'skin-blue',     'Y', 103, 1, sysdate(), null, null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '000000', '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',        'sys.user.initPassword',         '123456',        'Y', 103, 1, sysdate(), null, null, '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '000000', '涓绘鏋堕〉-渚ц竟鏍忎富棰�',          'sys.index.sideTheme',           'theme-dark',    'Y', 103, 1, sysdate(), null, null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+insert into sys_config values(5, '000000', '璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�',  'sys.account.registerUser',      'false',         'Y', 103, 1, sysdate(), null, null, '鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(11, '000000', 'OSS棰勮鍒楄〃璧勬簮寮�鍏�',         'sys.oss.previewListResource',   'true',          'Y', 103, 1, sysdate(), null, null, 'true:寮�鍚�, false:鍏抽棴');
+
+
+-- ----------------------------
+-- 14銆佺郴缁熻闂褰�
+-- ----------------------------
+create table sys_logininfor (
+    info_id        bigint(20)     not null                  comment '璁块棶ID',
+    tenant_id      varchar(20)    default '000000'          comment '绉熸埛缂栧彿',
+    user_name      varchar(50)    default ''                comment '鐢ㄦ埛璐﹀彿',
+    client_key     varchar(32)    default ''                comment '瀹㈡埛绔�',
+    device_type    varchar(32)    default ''                comment '璁惧绫诲瀷',
+    ipaddr         varchar(128)   default ''                comment '鐧诲綍IP鍦板潃',
+    login_location varchar(255)   default ''                comment '鐧诲綍鍦扮偣',
+    browser        varchar(50)    default ''                comment '娴忚鍣ㄧ被鍨�',
+    os             varchar(50)    default ''                comment '鎿嶄綔绯荤粺',
+    status         char(1)        default '0'               comment '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�',
+    msg            varchar(255)   default ''                comment '鎻愮ず娑堟伅',
+    login_time     datetime                                 comment '璁块棶鏃堕棿',
+    primary key (info_id),
+    key idx_sys_logininfor_s  (status),
+    key idx_sys_logininfor_lt (login_time)
+) engine=innodb comment = '绯荤粺璁块棶璁板綍';
+
+
+-- ----------------------------
+-- 17銆侀�氱煡鍏憡琛�
+-- ----------------------------
+create table sys_notice (
+    notice_id         bigint(20)      not null                   comment '鍏憡ID',
+    tenant_id         varchar(20)     default '000000'           comment '绉熸埛缂栧彿',
+    notice_title      varchar(50)     not null                   comment '鍏憡鏍囬',
+    notice_type       char(1)         not null                   comment '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
+    notice_content    longblob        default null               comment '鍏憡鍐呭',
+    status            char(1)         default '0'                comment '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    remark            varchar(255)    default null               comment '澶囨敞',
+    primary key (notice_id)
+) engine=innodb comment = '閫氱煡鍏憡琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鍏憡淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_notice values('1', '000000', '娓╅Θ鎻愰啋锛�2018-07-01 鏂扮増鏈彂甯冨暒', '2', '鏂扮増鏈唴瀹�', '0', 103, 1, sysdate(), null, null, '绠$悊鍛�');
+insert into sys_notice values('2', '000000', '缁存姢閫氱煡锛�2018-07-01 绯荤粺鍑屾櫒缁存姢', '1', '缁存姢鍐呭',   '0', 103, 1, sysdate(), null, null, '绠$悊鍛�');
+
+
+-- ----------------------------
+-- 18銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+create table gen_table (
+    table_id          bigint(20)      not null                   comment '缂栧彿',
+    data_name         varchar(200)    default ''                 comment '鏁版嵁婧愬悕绉�',
+    table_name        varchar(200)    default ''                 comment '琛ㄥ悕绉�',
+    table_comment     varchar(500)    default ''                 comment '琛ㄦ弿杩�',
+    sub_table_name    varchar(64)     default null               comment '鍏宠仈瀛愯〃鐨勮〃鍚�',
+    sub_table_fk_name varchar(64)     default null               comment '瀛愯〃鍏宠仈鐨勫閿悕',
+    class_name        varchar(100)    default ''                 comment '瀹炰綋绫诲悕绉�',
+    tpl_category      varchar(200)    default 'crud'             comment '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�',
+    package_name      varchar(100)                               comment '鐢熸垚鍖呰矾寰�',
+    module_name       varchar(30)                                comment '鐢熸垚妯″潡鍚�',
+    business_name     varchar(30)                                comment '鐢熸垚涓氬姟鍚�',
+    function_name     varchar(50)                                comment '鐢熸垚鍔熻兘鍚�',
+    function_author   varchar(50)                                comment '鐢熸垚鍔熻兘浣滆��',
+    gen_type          char(1)         default '0'                comment '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級',
+    gen_path          varchar(200)    default '/'                comment '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級',
+    options           varchar(1000)                              comment '鍏跺畠鐢熸垚閫夐」',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    remark            varchar(500)    default null               comment '澶囨敞',
+    primary key (table_id)
+) engine=innodb comment = '浠g爜鐢熸垚涓氬姟琛�';
+
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+create table gen_table_column (
+    column_id         bigint(20)      not null                   comment '缂栧彿',
+    table_id          bigint(20)                                 comment '褰掑睘琛ㄧ紪鍙�',
+    column_name       varchar(200)                               comment '鍒楀悕绉�',
+    column_comment    varchar(500)                               comment '鍒楁弿杩�',
+    column_type       varchar(100)                               comment '鍒楃被鍨�',
+    java_type         varchar(500)                               comment 'JAVA绫诲瀷',
+    java_field        varchar(200)                               comment 'JAVA瀛楁鍚�',
+    is_pk             char(1)                                    comment '鏄惁涓婚敭锛�1鏄級',
+    is_increment      char(1)                                    comment '鏄惁鑷锛�1鏄級',
+    is_required       char(1)                                    comment '鏄惁蹇呭~锛�1鏄級',
+    is_insert         char(1)                                    comment '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級',
+    is_edit           char(1)                                    comment '鏄惁缂栬緫瀛楁锛�1鏄級',
+    is_list           char(1)                                    comment '鏄惁鍒楄〃瀛楁锛�1鏄級',
+    is_query          char(1)                                    comment '鏄惁鏌ヨ瀛楁锛�1鏄級',
+    query_type        varchar(200)    default 'EQ'               comment '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級',
+    html_type         varchar(200)                               comment '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級',
+    dict_type         varchar(200)    default ''                 comment '瀛楀吀绫诲瀷',
+    sort              int                                        comment '鎺掑簭',
+    create_dept       bigint(20)      default null               comment '鍒涘缓閮ㄩ棬',
+    create_by         bigint(20)      default null               comment '鍒涘缓鑰�',
+    create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+    update_by         bigint(20)      default null               comment '鏇存柊鑰�',
+    update_time       datetime                                   comment '鏇存柊鏃堕棿',
+    primary key (column_id)
+) engine=innodb comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍琛�
+-- ----------------------------
+create table sys_oss (
+    oss_id          bigint(20)   not null                   comment '瀵硅薄瀛樺偍涓婚敭',
+    tenant_id       varchar(20)           default '000000'  comment '绉熸埛缂栧彿',
+    file_name       varchar(255) not null default ''        comment '鏂囦欢鍚�',
+    original_name   varchar(255) not null default ''        comment '鍘熷悕',
+    file_suffix     varchar(10)  not null default ''        comment '鏂囦欢鍚庣紑鍚�',
+    url             varchar(500) not null                   comment 'URL鍦板潃',
+    create_dept     bigint(20)            default null      comment '鍒涘缓閮ㄩ棬',
+    create_time     datetime              default null      comment '鍒涘缓鏃堕棿',
+    create_by       bigint(20)            default null      comment '涓婁紶浜�',
+    update_time     datetime              default null      comment '鏇存柊鏃堕棿',
+    update_by       bigint(20)            default null      comment '鏇存柊浜�',
+    service         varchar(20)  not null default 'minio'   comment '鏈嶅姟鍟�',
+    primary key (oss_id)
+) engine=innodb comment ='OSS瀵硅薄瀛樺偍琛�';
+
+-- ----------------------------
+-- OSS瀵硅薄瀛樺偍鍔ㄦ�侀厤缃〃
+-- ----------------------------
+create table sys_oss_config (
+    oss_config_id   bigint(20)    not null                  comment '涓婚敭',
+    tenant_id       varchar(20)             default '000000'comment '绉熸埛缂栧彿',
+    config_key      varchar(20)   not null  default ''      comment '閰嶇疆key',
+    access_key      varchar(255)            default ''      comment 'accessKey',
+    secret_key      varchar(255)            default ''      comment '绉橀挜',
+    bucket_name     varchar(255)            default ''      comment '妗跺悕绉�',
+    prefix          varchar(255)            default ''      comment '鍓嶇紑',
+    endpoint        varchar(255)            default ''      comment '璁块棶绔欑偣',
+    domain          varchar(255)            default ''      comment '鑷畾涔夊煙鍚�',
+    is_https        char(1)                 default 'N'     comment '鏄惁https锛圷=鏄�,N=鍚︼級',
+    region          varchar(255)            default ''      comment '鍩�',
+    access_policy   char(1)       not null  default '1'     comment '妗舵潈闄愮被鍨�(0=private 1=public 2=custom)',
+    status          char(1)                 default '1'     comment '鏄惁榛樿锛�0=鏄�,1=鍚︼級',
+    ext1            varchar(255)            default ''      comment '鎵╁睍瀛楁',
+    create_dept     bigint(20)              default null    comment '鍒涘缓閮ㄩ棬',
+    create_by       bigint(20)              default null    comment '鍒涘缓鑰�',
+    create_time     datetime                default null    comment '鍒涘缓鏃堕棿',
+    update_by       bigint(20)              default null    comment '鏇存柊鑰�',
+    update_time     datetime                default null    comment '鏇存柊鏃堕棿',
+    remark          varchar(500)            default null    comment '澶囨敞',
+    primary key (oss_config_id)
+) engine=innodb comment='瀵硅薄瀛樺偍閰嶇疆琛�';
+
+insert into sys_oss_config values (1, '000000', 'minio',  'ruoyi',            'ruoyi123',        'ruoyi',             '', '127.0.0.1:9000',                '','N', '',             '1' ,'0', '', 103, 1, sysdate(), 1, sysdate(), null);
+insert into sys_oss_config values (2, '000000', 'qiniu',  'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 's3-cn-north-1.qiniucs.com',     '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
+insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi',             '', 'oss-cn-beijing.aliyuncs.com',   '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
+insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX',  'XXXXXXXXXXXXXXX', 'ruoyi-1250000000',  '', 'cos.ap-beijing.myqcloud.com',   '','N', 'ap-beijing',   '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
+insert into sys_oss_config values (5, '000000', 'image',  'ruoyi',            'ruoyi123',        'ruoyi',             'image', '127.0.0.1:9000',           '','N', '',             '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null);
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+create table sys_client (
+    id                  bigint(20)    not null            comment 'id',
+    client_id           varchar(64)   default null        comment '瀹㈡埛绔痠d',
+    client_key          varchar(32)   default null        comment '瀹㈡埛绔痥ey',
+    client_secret       varchar(255)  default null        comment '瀹㈡埛绔閽�',
+    grant_type          varchar(255)  default null        comment '鎺堟潈绫诲瀷',
+    device_type         varchar(32)   default null        comment '璁惧绫诲瀷',
+    active_timeout      int(11)       default 1800        comment 'token娲昏穬瓒呮椂鏃堕棿',
+    timeout             int(11)       default 604800      comment 'token鍥哄畾瓒呮椂',
+    status              char(1)       default '0'         comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag            char(1)       default '0'         comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept         bigint(20)    default null        comment '鍒涘缓閮ㄩ棬',
+    create_by           bigint(20)    default null        comment '鍒涘缓鑰�',
+    create_time         datetime      default null        comment '鍒涘缓鏃堕棿',
+    update_by           bigint(20)    default null        comment '鏇存柊鑰�',
+    update_time         datetime      default null        comment '鏇存柊鏃堕棿',
+    primary key (id)
+) engine=innodb comment='绯荤粺鎺堟潈琛�';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate());
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate());
+
+
+CREATE TABLE test_demo
+(
+    id          bigint(0)    NOT NULL COMMENT '涓婚敭',
+    tenant_id   varchar(20)  NULL DEFAULT '000000' COMMENT '绉熸埛缂栧彿',
+    dept_id     bigint(0)    NULL DEFAULT NULL COMMENT '閮ㄩ棬id',
+    user_id     bigint(0)    NULL DEFAULT NULL COMMENT '鐢ㄦ埛id',
+    order_num   int(0)       NULL DEFAULT 0 COMMENT '鎺掑簭鍙�',
+    test_key    varchar(255) NULL DEFAULT NULL COMMENT 'key閿�',
+    value       varchar(255) NULL DEFAULT NULL COMMENT '鍊�',
+    version     int(0)       NULL DEFAULT 0 COMMENT '鐗堟湰',
+    create_dept bigint(0)    NULL DEFAULT NULL COMMENT '鍒涘缓閮ㄩ棬',
+    create_time datetime(0)  NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    create_by   bigint(0)    NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
+    update_time datetime(0)  NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    update_by   bigint(0)    NULL DEFAULT NULL COMMENT '鏇存柊浜�',
+    del_flag    int(0)       NULL DEFAULT 0 COMMENT '鍒犻櫎鏍囧織',
+    PRIMARY KEY (id) USING BTREE
+) ENGINE = InnoDB COMMENT = '娴嬭瘯鍗曡〃';
+
+CREATE TABLE test_tree
+(
+    id          bigint(0)    NOT NULL COMMENT '涓婚敭',
+    tenant_id   varchar(20)  NULL DEFAULT '000000' COMMENT '绉熸埛缂栧彿',
+    parent_id   bigint(0)    NULL DEFAULT 0 COMMENT '鐖秈d',
+    dept_id     bigint(0)    NULL DEFAULT NULL COMMENT '閮ㄩ棬id',
+    user_id     bigint(0)    NULL DEFAULT NULL COMMENT '鐢ㄦ埛id',
+    tree_name   varchar(255) NULL DEFAULT NULL COMMENT '鍊�',
+    version     int(0)       NULL DEFAULT 0 COMMENT '鐗堟湰',
+    create_dept bigint(0)    NULL DEFAULT NULL COMMENT '鍒涘缓閮ㄩ棬',
+    create_time datetime(0)  NULL DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+    create_by   bigint(0)    NULL DEFAULT NULL COMMENT '鍒涘缓浜�',
+    update_time datetime(0)  NULL DEFAULT NULL COMMENT '鏇存柊鏃堕棿',
+    update_by   bigint(0)    NULL DEFAULT NULL COMMENT '鏇存柊浜�',
+    del_flag    int(0)       NULL DEFAULT 0 COMMENT '鍒犻櫎鏍囧織',
+    PRIMARY KEY (id) USING BTREE
+) ENGINE = InnoDB COMMENT = '娴嬭瘯鏍戣〃';
+
+INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '娴嬭瘯鏁版嵁鏉冮檺', '娴嬭瘯', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '瀛愯妭鐐�1', '111', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '瀛愯妭鐐�2', '222', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '娴嬭瘯鏁版嵁', 'demo', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '瀛愯妭鐐�11', '1111', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '瀛愯妭鐐�22', '2222', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '瀛愯妭鐐�33', '3333', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '瀛愯妭鐐�44', '4444', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '瀛愯妭鐐�55', '5555', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '瀛愯妭鐐�66', '6666', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '瀛愯妭鐐�77', '7777', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '瀛愯妭鐐�88', '8888', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '瀛愯妭鐐�99', '9999', 0, 103, sysdate(), 1, NULL, NULL, 0);
+
+INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '娴嬭瘯鏁版嵁鏉冮檺', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '瀛愯妭鐐�1', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '瀛愯妭鐐�2', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '娴嬭瘯鏍�1', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '瀛愯妭鐐�11', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '瀛愯妭鐐�22', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '瀛愯妭鐐�33', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '瀛愯妭鐐�44', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '瀛愯妭鐐�55', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '瀛愯妭鐐�66', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '瀛愯妭鐐�77', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '瀛愯妭鐐�88', 0, 103, sysdate(), 1, NULL, NULL, 0);
+INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '瀛愯妭鐐�99', 0, 103, sysdate(), 1, NULL, NULL, 0);
diff --git a/eims/script/sql/snail_job.sql b/eims/script/sql/snail_job.sql
new file mode 100644
index 0000000..c3aa760
--- /dev/null
+++ b/eims/script/sql/snail_job.sql
@@ -0,0 +1,514 @@
+SET NAMES utf8mb4;
+
+CREATE TABLE `sj_namespace`
+(
+    `id`          bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `name`        varchar(64)         NOT NULL COMMENT '鍚嶇О',
+    `unique_id`   varchar(64)         NOT NULL COMMENT '鍞竴id',
+    `description` varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `deleted`     tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`   datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`   datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_name` (`name`),
+    UNIQUE KEY `uk_unique_id` (`unique_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='鍛藉悕绌洪棿';
+
+INSERT INTO `sj_namespace` VALUES (1, 'Development', 'dev', '', 0, now(), now());
+INSERT INTO `sj_namespace` VALUES (2, 'Production', 'prod', '', 0, now(), now());
+
+CREATE TABLE `sj_group_config`
+(
+    `id`                bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`      varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`        varchar(64)         NOT NULL DEFAULT '' COMMENT '缁勫悕绉�',
+    `description`       varchar(256)        NOT NULL DEFAULT '' COMMENT '缁勬弿杩�',
+    `token`             varchar(64)         NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token',
+    `group_status`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�',
+    `version`           int(11)             NOT NULL COMMENT '鐗堟湰鍙�',
+    `group_partition`   int(11)             NOT NULL COMMENT '鍒嗗尯',
+    `id_generator_mode` tinyint(4)          NOT NULL DEFAULT 1 COMMENT '鍞竴id鐢熸垚妯″紡 榛樿鍙锋妯″紡',
+    `init_scene`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鏄惁鍒濆鍖栧満鏅� 0:鍚� 1:鏄�',
+    `bucket_index`      int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `create_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='缁勯厤缃�';
+
+INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now());
+
+CREATE TABLE `sj_notify_config`
+(
+    `id`                     bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`           varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`             varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `business_id`            varchar(64)         NOT NULL COMMENT '涓氬姟id (job_id鎴杦orkflow_id鎴杝cene_name)',
+    `system_task_type`       tinyint(4)          NOT NULL DEFAULT 3 COMMENT '浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+    `notify_status`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�',
+    `recipient_ids`          varchar(128)        NOT NULL COMMENT '鎺ユ敹浜篿d鍒楄〃',
+    `notify_threshold`       int(11)             NOT NULL DEFAULT 0 COMMENT '閫氱煡闃堝��',
+    `notify_scene`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡鍦烘櫙',
+    `rate_limiter_status`    tinyint(4)          NOT NULL DEFAULT 0 COMMENT '闄愭祦鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�',
+    `rate_limiter_threshold` int(11)             NOT NULL DEFAULT 0 COMMENT '姣忕闄愭祦闃堝��',
+    `description`            varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `create_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `business_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='閫氱煡閰嶇疆';
+
+CREATE TABLE `sj_notify_recipient`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `recipient_name`   varchar(64)         NOT NULL COMMENT '鎺ユ敹浜哄悕绉�',
+    `notify_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook',
+    `notify_attribute` varchar(512)        NOT NULL COMMENT '閰嶇疆灞炴��',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id` (`namespace_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='鍛婅閫氱煡鎺ユ敹浜�';
+
+CREATE TABLE `sj_retry_dead_letter_0`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `unique_id`     varchar(64)         NOT NULL COMMENT '鍚岀粍涓媔d鍞竴',
+    `group_name`    varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `scene_name`    varchar(64)         NOT NULL COMMENT '鍦烘櫙鍚嶇О',
+    `idempotent_id` varchar(64)         NOT NULL COMMENT '骞傜瓑id',
+    `biz_no`        varchar(64)         NOT NULL DEFAULT '' COMMENT '涓氬姟缂栧彿',
+    `executor_name` varchar(512)        NOT NULL DEFAULT '' COMMENT '鎵ц鍣ㄥ悕绉�',
+    `args_str`      text                NOT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
+    `ext_attrs`     text                NOT NULL COMMENT '鎵╁睍瀛楁',
+    `task_type`     tinyint(4)          NOT NULL DEFAULT 1 COMMENT '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `idx_idempotent_id` (`idempotent_id`),
+    KEY `idx_biz_no` (`biz_no`),
+    KEY `idx_create_dt` (`create_dt`),
+    UNIQUE KEY `uk_namespace_id_group_name_unique_id` (`namespace_id`, `group_name`, `unique_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='姝讳俊闃熷垪琛�';
+
+CREATE TABLE `sj_retry_task_0`
+(
+    `id`              bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`    varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `unique_id`       varchar(64)         NOT NULL COMMENT '鍚岀粍涓媔d鍞竴',
+    `group_name`      varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `scene_name`      varchar(64)         NOT NULL COMMENT '鍦烘櫙鍚嶇О',
+    `idempotent_id`   varchar(64)         NOT NULL COMMENT '骞傜瓑id',
+    `biz_no`          varchar(64)         NOT NULL DEFAULT '' COMMENT '涓氬姟缂栧彿',
+    `executor_name`   varchar(512)        NOT NULL DEFAULT '' COMMENT '鎵ц鍣ㄥ悕绉�',
+    `args_str`        text                NOT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
+    `ext_attrs`       text                NOT NULL COMMENT '鎵╁睍瀛楁',
+    `next_trigger_at` datetime            NOT NULL COMMENT '涓嬫瑙﹀彂鏃堕棿',
+    `retry_count`     int(11)             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯娆℃暟',
+    `retry_status`    tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ч噸璇曟鏁�',
+    `task_type`       tinyint(4)          NOT NULL DEFAULT 1 COMMENT '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+    `create_dt`       datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`       datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `idx_namespace_id_group_name_task_type` (`namespace_id`, `group_name`, `task_type`),
+    KEY `idx_namespace_id_group_name_retry_status` (`namespace_id`, `group_name`, `retry_status`),
+    KEY `idx_idempotent_id` (`idempotent_id`),
+    KEY `idx_biz_no` (`biz_no`),
+    KEY `idx_create_dt` (`create_dt`),
+    UNIQUE KEY `uk_name_unique_id` (`namespace_id`, `group_name`, `unique_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟琛�';
+
+CREATE TABLE `sj_retry_task_log`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `unique_id`     varchar(64)         NOT NULL COMMENT '鍚岀粍涓媔d鍞竴',
+    `group_name`    varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `scene_name`    varchar(64)         NOT NULL COMMENT '鍦烘櫙鍚嶇О',
+    `idempotent_id` varchar(64)         NOT NULL COMMENT '骞傜瓑id',
+    `biz_no`        varchar(64)         NOT NULL DEFAULT '' COMMENT '涓氬姟缂栧彿',
+    `executor_name` varchar(512)        NOT NULL DEFAULT '' COMMENT '鎵ц鍣ㄥ悕绉�',
+    `args_str`      text                NOT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
+    `ext_attrs`     text                NOT NULL COMMENT '鎵╁睍瀛楁',
+    `retry_status`  tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ф鏁�',
+    `task_type`     tinyint(4)          NOT NULL DEFAULT 1 COMMENT '浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `idx_retry_status` (`retry_status`),
+    KEY `idx_idempotent_id` (`idempotent_id`),
+    KEY `idx_unique_id` (`unique_id`),
+    KEY `idx_biz_no` (`biz_no`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟鏃ュ織鍩虹淇℃伅琛�';
+
+CREATE TABLE `sj_retry_task_log_message`
+(
+    `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id` varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`   varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `unique_id`    varchar(64)         NOT NULL COMMENT '鍚岀粍涓媔d鍞竴',
+    `message`      longtext            NOT NULL COMMENT '寮傚父淇℃伅',
+    `log_num`      int(11)             NOT NULL DEFAULT 1 COMMENT '鏃ュ織鏁伴噺',
+    `real_time`    bigint(13)          NOT NULL DEFAULT 0 COMMENT '涓婃姤鏃堕棿',
+    `create_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `unique_id`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟璋冨害鏃ュ織淇℃伅璁板綍琛�';
+
+CREATE TABLE `sj_retry_scene_config`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `scene_name`       varchar(64)         NOT NULL COMMENT '鍦烘櫙鍚嶇О',
+    `group_name`       varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `scene_status`     tinyint(4)          NOT NULL DEFAULT 0 COMMENT '缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�',
+    `max_retry_count`  int(11)             NOT NULL DEFAULT 5 COMMENT '鏈�澶ч噸璇曟鏁�',
+    `back_off`         tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�',
+    `trigger_interval` varchar(16)         NOT NULL DEFAULT '' COMMENT '闂撮殧鏃堕暱',
+    `deadline_request` bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣',
+    `executor_timeout` int(11) unsigned    NOT NULL DEFAULT 5 COMMENT '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+    `route_key`        tinyint(4)          NOT NULL DEFAULT 4 COMMENT '璺敱绛栫暐',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='鍦烘櫙閰嶇疆';
+
+CREATE TABLE `sj_server_node`
+(
+    `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id` varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`   varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `host_id`      varchar(64)         NOT NULL COMMENT '涓绘満id',
+    `host_ip`      varchar(64)         NOT NULL COMMENT '鏈哄櫒ip',
+    `host_port`    int(16)             NOT NULL COMMENT '鏈哄櫒绔彛',
+    `expire_at`    datetime            NOT NULL COMMENT '杩囨湡鏃堕棿',
+    `node_type`    tinyint(4)          NOT NULL COMMENT '鑺傜偣绫诲瀷 1銆佸鎴风 2銆佹槸鏈嶅姟绔�',
+    `ext_attrs`    varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `create_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_expire_at_node_type` (`expire_at`, `node_type`),
+    UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='鏈嶅姟鍣ㄨ妭鐐�';
+
+CREATE TABLE `sj_distributed_lock`
+(
+    `name`       varchar(64)         NOT NULL COMMENT '閿佸悕绉�',
+    `lock_until` timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '閿佸畾鏃堕暱',
+    `locked_at`  timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '閿佸畾鏃堕棿',
+    `locked_by`  varchar(255)        NOT NULL COMMENT '閿佸畾鑰�',
+    `create_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='閿佸畾琛�';
+
+CREATE TABLE `sj_system_user`
+(
+    `id`        bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `username`  varchar(64)         NOT NULL COMMENT '璐﹀彿',
+    `password`  varchar(128)        NOT NULL COMMENT '瀵嗙爜',
+    `role`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '瑙掕壊锛�1-鏅�氱敤鎴枫��2-绠$悊鍛�',
+    `create_dt` datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt` datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_username` (`username`) USING BTREE
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='绯荤粺鐢ㄦ埛琛�';
+
+-- pwd: admin
+INSERT INTO `sj_system_user` VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now());
+
+CREATE TABLE `sj_system_user_permission`
+(
+    `id`             bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `group_name`     varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `namespace_id`   varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `system_user_id` bigint(20)          NOT NULL COMMENT '绯荤粺鐢ㄦ埛id',
+    `create_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='绯荤粺鐢ㄦ埛鏉冮檺琛�';
+
+CREATE TABLE `sj_sequence_alloc`
+(
+    `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id` varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`   varchar(64)         NOT NULL DEFAULT '' COMMENT '缁勫悕绉�',
+    `max_id`       bigint(20)          NOT NULL DEFAULT 1 COMMENT '鏈�澶d',
+    `step`         int(11)             NOT NULL DEFAULT 100 COMMENT '姝ラ暱',
+    `update_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '鏇存柊鏃堕棿',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='鍙锋妯″紡搴忓彿ID鍒嗛厤琛�';
+
+-- 鍒嗗竷寮忚皟搴DL
+CREATE TABLE `sj_job`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`       varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `job_name`         varchar(64)         NOT NULL COMMENT '鍚嶇О',
+    `args_str`         text                         DEFAULT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
+    `args_type`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '鍙傛暟绫诲瀷 ',
+    `next_trigger_at`  bigint(13)          NOT NULL COMMENT '涓嬫瑙﹀彂鏃堕棿',
+    `job_status`       tinyint(4)          NOT NULL DEFAULT 1 COMMENT '浠诲姟鐘舵�� 0銆佸叧闂��1銆佸紑鍚�',
+    `task_type`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '浠诲姟绫诲瀷 1銆侀泦缇� 2銆佸箍鎾� 3銆佸垏鐗�',
+    `route_key`        tinyint(4)          NOT NULL DEFAULT 4 COMMENT '璺敱绛栫暐',
+    `executor_type`    tinyint(4)          NOT NULL DEFAULT 1 COMMENT '鎵ц鍣ㄧ被鍨�',
+    `executor_info`    varchar(255)                 DEFAULT NULL COMMENT '鎵ц鍣ㄥ悕绉�',
+    `trigger_type`     tinyint(4)          NOT NULL COMMENT '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿',
+    `trigger_interval` varchar(255)        NOT NULL COMMENT '闂撮殧鏃堕暱',
+    `block_strategy`   tinyint(4)          NOT NULL DEFAULT 1 COMMENT '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�',
+    `executor_timeout` int(11)             NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+    `max_retry_times`  int(11)             NOT NULL DEFAULT 0 COMMENT '鏈�澶ч噸璇曟鏁�',
+    `parallel_num`     int(11)             NOT NULL DEFAULT 1 COMMENT '骞惰鏁�',
+    `retry_interval`   int(11)             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯闂撮殧(s)',
+    `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `resident`         tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鏄惁鏄父椹讳换鍔�',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `deleted`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟淇℃伅';
+
+INSERT INTO `sj_job` VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', '', 0 , now(), now());
+
+CREATE TABLE `sj_job_log_message`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`    varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `job_id`        bigint(20)          NOT NULL COMMENT '浠诲姟淇℃伅id',
+    `task_batch_id` bigint(20)          NOT NULL COMMENT '浠诲姟鎵规id',
+    `task_id`       bigint(20)          NOT NULL COMMENT '璋冨害浠诲姟id',
+    `message`       longtext            NOT NULL COMMENT '璋冨害淇℃伅',
+    `log_num`       int(11)             NOT NULL DEFAULT 1 COMMENT '鏃ュ織鏁伴噺',
+    `real_time`     bigint(13)          NOT NULL DEFAULT 0 COMMENT '涓婃姤鏃堕棿',
+    `ext_attrs`     varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='璋冨害鏃ュ織';
+
+CREATE TABLE `sj_job_task`
+(
+    `id`             bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`   varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`     varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `job_id`         bigint(20)          NOT NULL COMMENT '浠诲姟淇℃伅id',
+    `task_batch_id`  bigint(20)          NOT NULL COMMENT '璋冨害浠诲姟id',
+    `parent_id`      bigint(20)          NOT NULL DEFAULT 0 COMMENT '鐖舵墽琛屽櫒id',
+    `task_status`    tinyint             NOT NULL DEFAULT 0 COMMENT '鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�',
+    `retry_count`    int(11)             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯娆℃暟',
+    `mr_stage`       tinyint                      DEFAULT NULL COMMENT '鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce',
+    `leaf`           tinyint             NOT NULL DEFAULT '1' COMMENT '鍙跺瓙鑺傜偣',
+    `task_name`      varchar(255)        NOT NULL DEFAULT '' COMMENT '浠诲姟鍚嶇О',
+    `client_info`    varchar(128)                 DEFAULT NULL COMMENT '瀹㈡埛绔湴鍧� clientId#ip:port',
+    `wf_context`     text                         DEFAULT NULL COMMENT '宸ヤ綔娴佸叏灞�涓婁笅鏂�',
+    `result_message` text                NOT NULL COMMENT '鎵ц缁撴灉',
+    `args_str`       text                         DEFAULT NULL COMMENT '鎵ц鏂规硶鍙傛暟',
+    `args_type`      tinyint             NOT NULL DEFAULT 1 COMMENT '鍙傛暟绫诲瀷 ',
+    `ext_attrs`      varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `create_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟瀹炰緥';
+
+CREATE TABLE `sj_job_task_batch`
+(
+    `id`                      bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`            varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`              varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `job_id`                  bigint(20)          NOT NULL COMMENT '浠诲姟id',
+    `workflow_node_id`        bigint(20)          NOT NULL DEFAULT 0 COMMENT '宸ヤ綔娴佽妭鐐筰d',
+    `parent_workflow_node_id` bigint(20)          NOT NULL DEFAULT 0 COMMENT '宸ヤ綔娴佷换鍔$埗鎵规id',
+    `workflow_task_batch_id`  bigint(20)          NOT NULL DEFAULT 0 COMMENT '宸ヤ綔娴佷换鍔℃壒娆d',
+    `task_batch_status`       tinyint(4)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�',
+    `operation_reason`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鎿嶄綔鍘熷洜',
+    `execution_at`            bigint(13)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц鏃堕棿',
+    `system_task_type`        tinyint(4)          NOT NULL DEFAULT 3 COMMENT '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+    `parent_id`               varchar(64)         NOT NULL DEFAULT '' COMMENT '鐖惰妭鐐�',
+    `ext_attrs`               varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `deleted`                 tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`               datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`               datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='浠诲姟鎵规';
+
+CREATE TABLE `sj_job_summary`
+(
+    `id`               bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`     VARCHAR(64)     NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`       VARCHAR(64)     NOT NULL DEFAULT '' COMMENT '缁勫悕绉�',
+    `business_id`      bigint          NOT NULL COMMENT '涓氬姟id (job_id鎴杦orkflow_id)',
+    `system_task_type` tinyint(4)      NOT NULL DEFAULT 3 COMMENT '浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+    `trigger_at`       datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '缁熻鏃堕棿',
+    `success_num`      int             NOT NULL DEFAULT 0 COMMENT '鎵ц鎴愬姛-鏃ュ織鏁伴噺',
+    `fail_num`         int             NOT NULL DEFAULT 0 COMMENT '鎵ц澶辫触-鏃ュ織鏁伴噺',
+    `fail_reason`      varchar(512)    NOT NULL DEFAULT '' COMMENT '澶辫触鍘熷洜',
+    `stop_num`         int             NOT NULL DEFAULT 0 COMMENT '鎵ц澶辫触-鏃ュ織鏁伴噺',
+    `stop_reason`      varchar(512)    NOT NULL DEFAULT '' COMMENT '澶辫触鍘熷洜',
+    `cancel_num`       int             NOT NULL DEFAULT 0 COMMENT '鎵ц澶辫触-鏃ュ織鏁伴噺',
+    `cancel_reason`    varchar(512)    NOT NULL DEFAULT '' COMMENT '澶辫触鍘熷洜',
+    `create_dt`        datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`        datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id),
+    UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job';
+
+CREATE TABLE `sj_retry_summary`
+(
+    `id`            bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`  VARCHAR(64)     NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`    VARCHAR(64)     NOT NULL DEFAULT '' COMMENT '缁勫悕绉�',
+    `scene_name`    VARCHAR(50)     NOT NULL DEFAULT '' COMMENT '鍦烘櫙鍚嶇О',
+    `trigger_at`    datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '缁熻鏃堕棿',
+    `running_num`   int             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯涓�-鏃ュ織鏁伴噺',
+    `finish_num`    int             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯瀹屾垚-鏃ュ織鏁伴噺',
+    `max_count_num` int             NOT NULL DEFAULT 0 COMMENT '閲嶈瘯鍒拌揪鏈�澶ф鏁�-鏃ュ織鏁伴噺',
+    `suspend_num`   int             NOT NULL DEFAULT 0 COMMENT '鏆傚仠閲嶈瘯-鏃ュ織鏁伴噺',
+    `create_dt`     datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`     datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_trigger_at` (`trigger_at`),
+    UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry';
+
+CREATE TABLE `sj_workflow`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `workflow_name`    varchar(64)         NOT NULL COMMENT '宸ヤ綔娴佸悕绉�',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`       varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `workflow_status`  tinyint(4)          NOT NULL DEFAULT 1 COMMENT '宸ヤ綔娴佺姸鎬� 0銆佸叧闂��1銆佸紑鍚�',
+    `trigger_type`     tinyint(4)          NOT NULL COMMENT '瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿',
+    `trigger_interval` varchar(255)        NOT NULL COMMENT '闂撮殧鏃堕暱',
+    `next_trigger_at`  bigint(13)          NOT NULL COMMENT '涓嬫瑙﹀彂鏃堕棿',
+    `block_strategy`   tinyint(4)          NOT NULL DEFAULT 1 COMMENT '闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�',
+    `executor_timeout` int(11)             NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '鎻忚堪',
+    `flow_info`        text                         DEFAULT NULL COMMENT '娴佺▼淇℃伅',
+    `wf_context`       text                         DEFAULT NULL COMMENT '涓婁笅鏂�',
+    `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `version`          int(11)             NOT NULL COMMENT '鐗堟湰鍙�',
+    `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `deleted`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='宸ヤ綔娴�';
+
+CREATE TABLE `sj_workflow_node`
+(
+    `id`                   bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`         varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `node_name`            varchar(64)         NOT NULL COMMENT '鑺傜偣鍚嶇О',
+    `group_name`           varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `job_id`               bigint(20)          NOT NULL COMMENT '浠诲姟淇℃伅id',
+    `workflow_id`          bigint(20)          NOT NULL COMMENT '宸ヤ綔娴両D',
+    `node_type`            tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1銆佷换鍔¤妭鐐� 2銆佹潯浠惰妭鐐�',
+    `expression_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '1銆丼pEl銆�2銆丄viator 3銆丵L',
+    `fail_strategy`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '澶辫触绛栫暐 1銆佽烦杩� 2銆侀樆濉�',
+    `workflow_node_status` tinyint(4)          NOT NULL DEFAULT 1 COMMENT '宸ヤ綔娴佽妭鐐圭姸鎬� 0銆佸叧闂��1銆佸紑鍚�',
+    `priority_level`       int(11)             NOT NULL DEFAULT 1 COMMENT '浼樺厛绾�',
+    `node_info`            text                         DEFAULT NULL COMMENT '鑺傜偣淇℃伅 ',
+    `version`              int(11)             NOT NULL COMMENT '鐗堟湰鍙�',
+    `ext_attrs`            varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `deleted`              tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`            datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`            datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='宸ヤ綔娴佽妭鐐�';
+
+CREATE TABLE `sj_workflow_task_batch`
+(
+    `id`                bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+    `namespace_id`      varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '鍛藉悕绌洪棿id',
+    `group_name`        varchar(64)         NOT NULL COMMENT '缁勫悕绉�',
+    `workflow_id`       bigint(20)          NOT NULL COMMENT '宸ヤ綔娴佷换鍔d',
+    `task_batch_status` tinyint(4)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�',
+    `operation_reason`  tinyint(4)          NOT NULL DEFAULT 0 COMMENT '鎿嶄綔鍘熷洜',
+    `flow_info`         text                         DEFAULT NULL COMMENT '娴佺▼淇℃伅',
+    `wf_context`        text                         DEFAULT NULL COMMENT '鍏ㄥ眬涓婁笅鏂�',
+    `execution_at`      bigint(13)          NOT NULL DEFAULT 0 COMMENT '浠诲姟鎵ц鏃堕棿',
+    `ext_attrs`         varchar(256)        NULL     DEFAULT '' COMMENT '鎵╁睍瀛楁',
+    `version`           int(11)              NOT NULL DEFAULT 1 COMMENT '鐗堟湰鍙�',
+    `deleted`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '閫昏緫鍒犻櫎 1銆佸垹闄�',
+    `create_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '鍒涘缓鏃堕棿',
+    `update_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '淇敼鏃堕棿',
+    PRIMARY KEY (`id`),
+    KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='宸ヤ綔娴佹壒娆�';
diff --git a/eims/script/sql/sqlserver/flowable.sql b/eims/script/sql/sqlserver/flowable.sql
new file mode 100644
index 0000000..2397c35
--- /dev/null
+++ b/eims/script/sql/sqlserver/flowable.sql
@@ -0,0 +1,456 @@
+insert into sys_menu values('11616', '宸ヤ綔娴�'  , '0',    '6', 'workflow',          '',                                 '', '1', '0', 'M', '0', '0', '',                       'workflow', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11617', '妯″瀷绠$悊', '11616', '2', 'model',             'workflow/model/index',             '', '1', '1', 'C', '0', '0', 'workflow:model:list',    'model', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11618', '鎴戠殑浠诲姟', '0', '7', 'task',              '',                                 '', '1', '0', 'M', '0', '0', '',                       'my-task', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11619', '鎴戠殑寰呭姙', '11618', '2', 'taskWaiting',       'workflow/task/taskWaiting',              '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11632', '鎴戠殑宸插姙', '11618', '3', 'taskFinish',       'workflow/task/taskFinish',              '', '1', '1', 'C', '0', '0', '',                       'finish', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11633', '鎴戠殑鎶勯��', '11618', '4', 'taskCopyList',       'workflow/task/taskCopyList',              '', '1', '1', 'C', '0', '0', '',                       'my-copy', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11620', '娴佺▼瀹氫箟', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '',                       'process-definition', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11621', '娴佺▼瀹炰緥', '11630', '1', 'processInstance',   'workflow/processInstance/index',   '', '1', '1', 'C', '0', '0', '',                       'tree-table', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11622', '娴佺▼鍒嗙被', '11616', '1', 'category',          'workflow/category/index',          '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11629', '鎴戝彂璧风殑', '11618', '1', 'myDocument',        'workflow/task/myDocument',         '', '1', '1', 'C', '0', '0', '',                       'guide', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11630', '娴佺▼鐩戞帶', '11616', '4', 'monitor',           '',                                 '', '1', '0', 'M', '0', '0', '',                       'monitor', 103, 1, getdate(), NULL, NULL, '');
+insert into sys_menu values('11631', '寰呭姙浠诲姟', '11630', '2', 'allTaskWaiting',    'workflow/task/allTaskWaiting',     '', '1', '1', 'C', '0', '0', '',                       'waiting', 103, 1, getdate(), NULL, NULL, '');
+
+
+-- 娴佺▼鍒嗙被绠$悊鐩稿叧鎸夐挳
+insert into sys_menu values ('11623', '娴佺▼鍒嗙被鏌ヨ', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1, getdate(), null, null, '');
+insert into sys_menu values ('11624', '娴佺▼鍒嗙被鏂板', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add',   '#', 103, 1, getdate(), null, null, '');
+insert into sys_menu values ('11625', '娴佺▼鍒嗙被淇敼', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit',  '#', 103, 1, getdate(), null, null, '');
+insert into sys_menu values ('11626', '娴佺▼鍒嗙被鍒犻櫎', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove','#', 103, 1, getdate(), null, null, '');
+insert into sys_menu values ('11627', '娴佺▼鍒嗙被瀵煎嚭', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export','#', 103, 1, getdate(), null, null, '');
+-- 璇峰亣鍗曚俊鎭�
+create table test_leave
+(
+    id          bigint        not null
+        primary key,
+    leave_type  nvarchar(255) not null,
+    start_date  datetime2     not null,
+    end_date    datetime2     not null,
+    leave_days  int           not null,
+    remark      nvarchar(255),
+    status      nvarchar(255),
+    create_dept bigint,
+    create_by   bigint,
+    create_time datetime2,
+    update_by   bigint,
+    update_time datetime2,
+    tenant_id   nvarchar(20)
+)
+go
+
+exec sp_addextendedproperty 'MS_Description', N'璇峰亣鐢宠琛�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'璇峰亣绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'leave_type'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'寮�濮嬫椂闂�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'start_date'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'缁撴潫鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'end_date'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'璇峰亣澶╂暟', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'leave_days'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'璇峰亣鍘熷洜', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'remark'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鐘舵��', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'status'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN',
+     'update_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'test_leave', 'COLUMN', 'tenant_id'
+go
+
+-- 娴佺▼鍒嗙被淇℃伅琛�
+create table wf_category
+(
+    id            bigint not null
+        primary key,
+    category_name nvarchar(255),
+    category_code nvarchar(255)
+        constraint uni_category_code
+        unique,
+    parent_id     bigint,
+    sort_num      int,
+    tenant_id     nvarchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   datetime2,
+    update_by     bigint,
+    update_time   datetime2
+)
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼鍒嗙被', 'SCHEMA', 'dbo', 'TABLE', 'wf_category'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒嗙被鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'category_name'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒嗙被缂栫爜', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'category_code'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鐖剁骇id', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'parent_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鎺掑簭', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'sort_num'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'tenant_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_category', 'COLUMN',
+     'update_time'
+go
+
+INSERT INTO wf_category values (1, 'OA', 'OA', 0, 0, '000000', 103, 1, getdate(), 1, getdate());
+
+create table wf_task_back_node
+(
+    id            bigint not null primary key,
+    node_id       nvarchar(255) not null,
+    node_name     nvarchar(255) not null,
+    order_no      int not null,
+    instance_id   nvarchar(255) not null,
+    task_type     nvarchar(255) not null,
+    assignee      nvarchar(2000) not null,
+    tenant_id     nvarchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   datetime2,
+    update_by     bigint,
+    update_time   datetime2
+)
+
+go
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣瀹℃壒璁板綍', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'node_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'node_name'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鎺掑簭', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'order_no'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹炰緥id', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'instance_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'task_type'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'瀹℃壒浜�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'assignee'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'tenant_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_task_back_node', 'COLUMN',
+     'update_time'
+go
+
+create table wf_definition_config
+(
+    id            bigint not null primary key,
+    table_name    nvarchar(255)  not null,
+    definition_id nvarchar(255)  not null
+        constraint uni_definition_id
+        unique,
+    process_key   nvarchar(255)  not null,
+    version       bigint         not null,
+    remark        nvarchar(500) DEFAULT ('') null,
+    tenant_id     nvarchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   datetime2,
+    update_by     bigint,
+    update_time   datetime2
+)
+
+go
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟閰嶇疆', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ悕', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'table_name'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'definition_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼KEY', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'process_key'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼鐗堟湰', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'version'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'澶囨敞', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'remark'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'tenant_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_definition_config', 'COLUMN',
+     'update_time'
+go
+
+create table wf_form_manage
+(
+    id            bigint not null primary key,
+    form_name     nvarchar(255) not null,
+    form_type     nvarchar(255) not null,
+    router        nvarchar(255) not null,
+    remark        nvarchar(500) null,
+    tenant_id     nvarchar(20),
+    create_dept   bigint,
+    create_by     bigint,
+    create_time   datetime2,
+    update_by     bigint,
+    update_time   datetime2
+)
+
+go
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绠$悊', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'form_name'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'form_type'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'璺敱鍦板潃/琛ㄥ崟ID', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'router'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'澶囨敞', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'remark'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'tenant_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_form_manage', 'COLUMN',
+     'update_time'
+go
+
+insert into wf_form_manage(id, form_name, form_type, router, remark, tenant_id, create_dept, create_by, create_time, update_by, update_time) VALUES (1, '璇峰亣鐢宠', 'static', '/workflow/leaveEdit/index', NULL, '000000', 103, 1, getdate(), 1, getdate());
+
+create table wf_node_config
+(
+    id               bigint not null primary key,
+    form_id          bigint,
+    form_type        nvarchar(255) ,
+    node_name        nvarchar(255) not null,
+    node_id          nvarchar(255) not null,
+    definition_id    nvarchar(255) not null,
+    apply_user_task  nchar default ('0')  null,
+    tenant_id        nvarchar(20),
+    create_dept      bigint,
+    create_by        bigint,
+    create_time      datetime2,
+    update_by        bigint,
+    update_time      datetime2
+)
+
+go
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣閰嶇疆', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'涓婚敭', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'form_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'琛ㄥ崟绫诲瀷', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'form_type'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣鍚嶇О', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'node_name'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鑺傜偣id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'node_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'娴佺▼瀹氫箟id', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'definition_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏄惁涓虹敵璇蜂汉鑺傜偣 锛�0鏄� 1鍚︼級', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'apply_user_task'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'绉熸埛缂栧彿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'tenant_id'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓閮ㄩ棬', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'create_dept'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'create_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鍒涘缓鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'create_time'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鑰�', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN', 'update_by'
+go
+
+exec sp_addextendedproperty 'MS_Description', N'鏇存柊鏃堕棿', 'SCHEMA', 'dbo', 'TABLE', 'wf_node_config', 'COLUMN',
+     'update_time'
+go
+
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11638, '璇峰亣鐢宠', 5, 1, 'leave', 'workflow/leave/index', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, getdate(), NULL, NULL, '璇峰亣鐢宠鑿滃崟');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11639, '璇峰亣鐢宠鏌ヨ', 11638, 1, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, getdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11640, '璇峰亣鐢宠鏂板', 11638, 2, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, getdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11641, '璇峰亣鐢宠淇敼', 11638, 3, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, getdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11642, '璇峰亣鐢宠鍒犻櫎', 11638, 4, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, getdate(), NULL, NULL, '');
+INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (11643, '璇峰亣鐢宠瀵煎嚭', 11638, 5, '#', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, getdate(), NULL, NULL, '');
+
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (13, '000000', '涓氬姟鐘舵��', 'wf_business_status', 103, 1, getdate(), NULL, NULL, '涓氬姟鐘舵�佸垪琛�');
+INSERT INTO sys_dict_type(dict_id, tenant_id, dict_name, dict_type, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (14, '000000', '琛ㄥ崟绫诲瀷', 'wf_form_type', 103, 1, getdate(), NULL, NULL, '琛ㄥ崟绫诲瀷鍒楄〃');
+
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (39, '000000', 1, '宸叉挙閿�', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸叉挙閿�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (40, '000000', 2, '鑽夌', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, getdate(), NULL, NULL, '鑽夌');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (41, '000000', 3, '寰呭鏍�', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1,getdate(), NULL, NULL, '寰呭鏍�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (42, '000000', 4, '宸插畬鎴�', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '宸插畬鎴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (43, '000000', 5, '宸蹭綔搴�', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸蹭綔搴�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (44, '000000', 6, '宸查��鍥�', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, getdate(), NULL, NULL, '宸查��鍥�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (45, '000000', 7, '宸茬粓姝�', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1,getdate(), NULL, NULL, '宸茬粓姝�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (46, '000000', 1, '鑷畾涔夎〃鍗�', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, getdate(), NULL, NULL, '鑷畾涔夎〃鍗�');
+INSERT INTO sys_dict_data(dict_code, tenant_id, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, create_dept, create_by, create_time, update_by, update_time, remark) VALUES (47, '000000', 2, '鍔ㄦ�佽〃鍗�', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, getdate(), NULL, NULL, '鍔ㄦ�佽〃鍗�');
+
+-- 琛ㄥ崟绠$悊 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11628, '琛ㄥ崟绠$悊', '11616', '5', 'formManage', 'workflow/formManage/index', 1, 0, 'C', '0', '0', 'workflow:formManage:list', 'tree-table', 103, 1, getdate(), null, null, '琛ㄥ崟绠$悊鑿滃崟');
+
+-- 琛ㄥ崟绠$悊鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11644, '琛ㄥ崟绠$悊鏌ヨ', 11628, '1',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:query',        '', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11645, '琛ㄥ崟绠$悊鏂板', 11628, '2',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:add',          '', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11646, '琛ㄥ崟绠$悊淇敼', 11628, '3',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:edit',         '', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11647, '琛ㄥ崟绠$悊鍒犻櫎', 11628, '4',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:remove',       '', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(11648, '琛ㄥ崟绠$悊瀵煎嚭', 11628, '5',  '#', '', 1, 0, 'F', '0', '0', 'workflow:formManage:export',       'tree-table', 103, 1, getdate(), null, null, '');
diff --git a/eims/script/sql/sqlserver/snail_job_sqlserver.sql b/eims/script/sql/sqlserver/snail_job_sqlserver.sql
new file mode 100644
index 0000000..249842b
--- /dev/null
+++ b/eims/script/sql/sqlserver/snail_job_sqlserver.sql
@@ -0,0 +1,2745 @@
+/*
+ SnailJob Database Transfer Tool
+ Source Server Type    : MySQL
+ Target Server Type    : Microsoft SQL Server
+ Date: 2024-07-06 12:55:47
+*/
+
+
+-- sj_namespace
+CREATE TABLE sj_namespace
+(
+    id          bigint        NOT NULL PRIMARY KEY IDENTITY,
+    name        nvarchar(64)  NOT NULL,
+    unique_id   nvarchar(64)  NOT NULL,
+    description nvarchar(256) NOT NULL DEFAULT '',
+    deleted     tinyint       NOT NULL DEFAULT 0,
+    create_dt   datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt   datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍞竴id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'unique_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_namespace'
+GO
+
+INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Development', N'dev', N'', 0, getdate(), getdate())
+GO
+INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Production', N'prod', N'', 0, getdate(), getdate())
+GO
+
+-- sj_group_config
+CREATE TABLE sj_group_config
+(
+    id                bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id      nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        nvarchar(64)  NOT NULL DEFAULT '',
+    description       nvarchar(256) NOT NULL DEFAULT '',
+    token             nvarchar(64)  NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT',
+    group_status      tinyint       NOT NULL DEFAULT 0,
+    version           int           NOT NULL,
+    group_partition   int           NOT NULL,
+    id_generator_mode tinyint       NOT NULL DEFAULT 1,
+    init_scene        tinyint       NOT NULL DEFAULT 0,
+    bucket_index      int           NOT NULL DEFAULT 0,
+    create_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勬弿杩�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'token',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'token'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'group_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐗堟湰鍙�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒嗗尯',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'group_partition'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍞竴id鐢熸垚妯″紡 榛樿鍙锋妯″紡',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'id_generator_mode'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏄惁鍒濆鍖栧満鏅� 0:鍚� 1:鏄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'init_scene'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'bucket',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'bucket_index'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勯厤缃�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_group_config'
+GO
+
+INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate())
+GO
+
+-- sj_notify_config
+CREATE TABLE sj_notify_config
+(
+    id                     bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id           nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name             nvarchar(64)  NOT NULL,
+    business_id            nvarchar(64)  NOT NULL,
+    system_task_type       tinyint       NOT NULL DEFAULT 3,
+    notify_status          tinyint       NOT NULL DEFAULT 0,
+    recipient_ids          nvarchar(128) NOT NULL,
+    notify_threshold       int           NOT NULL DEFAULT 0,
+    notify_scene           tinyint       NOT NULL DEFAULT 0,
+    rate_limiter_status    tinyint       NOT NULL DEFAULT 0,
+    rate_limiter_threshold int           NOT NULL DEFAULT 0,
+    description            nvarchar(256) NOT NULL DEFAULT '',
+    create_dt              datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt              datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name, business_id)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓氬姟id  ( job_id鎴杦orkflow_id鎴杝cene_name ) ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'business_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 1. 閲嶈瘯浠诲姟 2. 閲嶈瘯鍥炶皟 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'system_task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'notify_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎺ユ敹浜篿d鍒楄〃',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'recipient_ids'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡闃堝��',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'notify_threshold'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡鍦烘櫙',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'notify_scene'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闄愭祦鐘舵�� 0銆佹湭鍚敤 1銆佸惎鐢�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'rate_limiter_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'姣忕闄愭祦闃堝��',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'rate_limiter_threshold'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡閰嶇疆',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_config'
+GO
+
+-- sj_notify_recipient
+CREATE TABLE sj_notify_recipient
+(
+    id               bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id     nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    recipient_name   nvarchar(64)  NOT NULL,
+    notify_type      tinyint       NOT NULL DEFAULT 0,
+    notify_attribute nvarchar(512) NOT NULL,
+    description      nvarchar(256) NOT NULL DEFAULT '',
+    create_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎺ユ敹浜哄悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'recipient_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫氱煡绫诲瀷 1銆侀拤閽� 2銆侀偖浠� 3銆佷紒涓氬井淇� 4 椋炰功 5 webhook',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'notify_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閰嶇疆灞炴��',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'notify_attribute'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛婅閫氱煡鎺ユ敹浜�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_notify_recipient'
+GO
+
+-- sj_retry_dead_letter_0
+CREATE TABLE sj_retry_dead_letter_0
+(
+    id            bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id  nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id     nvarchar(64)  NOT NULL,
+    group_name    nvarchar(64)  NOT NULL,
+    scene_name    nvarchar(64)  NOT NULL,
+    idempotent_id nvarchar(64)  NOT NULL,
+    biz_no        nvarchar(64)  NOT NULL DEFAULT '',
+    executor_name nvarchar(512) NOT NULL DEFAULT '',
+    args_str      nvarchar(max) NOT NULL,
+    ext_attrs     nvarchar(max) NOT NULL,
+    task_type     tinyint       NOT NULL DEFAULT 1,
+    create_dt     datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id)
+GO
+
+CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name)
+GO
+CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id)
+GO
+CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no)
+GO
+CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚岀粍涓媔d鍞竴',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'unique_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'scene_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'骞傜瓑id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'idempotent_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓氬姟缂栧彿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'biz_no'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鍣ㄥ悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'executor_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鏂规硶鍙傛暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'args_str'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'姝讳俊闃熷垪琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_dead_letter_0'
+GO
+
+-- sj_retry_task_0
+CREATE TABLE sj_retry_task_0
+(
+    id              bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id    nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id       nvarchar(64)  NOT NULL,
+    group_name      nvarchar(64)  NOT NULL,
+    scene_name      nvarchar(64)  NOT NULL,
+    idempotent_id   nvarchar(64)  NOT NULL,
+    biz_no          nvarchar(64)  NOT NULL DEFAULT '',
+    executor_name   nvarchar(512) NOT NULL DEFAULT '',
+    args_str        nvarchar(max) NOT NULL,
+    ext_attrs       nvarchar(max) NOT NULL,
+    next_trigger_at datetime2     NOT NULL,
+    retry_count     int           NOT NULL DEFAULT 0,
+    retry_status    tinyint       NOT NULL DEFAULT 0,
+    task_type       tinyint       NOT NULL DEFAULT 1,
+    create_dt       datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt       datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id)
+GO
+
+CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name)
+GO
+CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type)
+GO
+CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status)
+GO
+CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id)
+GO
+CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no)
+GO
+CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚岀粍涓媔d鍞竴',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'unique_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'scene_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'骞傜瓑id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'idempotent_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓氬姟缂栧彿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'biz_no'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鍣ㄥ悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'executor_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鏂规硶鍙傛暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'args_str'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓嬫瑙﹀彂鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'next_trigger_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯娆℃暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'retry_count'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ч噸璇曟鏁�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'retry_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_0'
+GO
+
+-- sj_retry_task_log
+CREATE TABLE sj_retry_task_log
+(
+    id            bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id  nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    unique_id     nvarchar(64)  NOT NULL,
+    group_name    nvarchar(64)  NOT NULL,
+    scene_name    nvarchar(64)  NOT NULL,
+    idempotent_id nvarchar(64)  NOT NULL,
+    biz_no        nvarchar(64)  NOT NULL DEFAULT '',
+    executor_name nvarchar(512) NOT NULL DEFAULT '',
+    args_str      nvarchar(max) NOT NULL,
+    ext_attrs     nvarchar(max) NOT NULL,
+    retry_status  tinyint       NOT NULL DEFAULT 0,
+    task_type     tinyint       NOT NULL DEFAULT 1,
+    create_dt     datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt     datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name)
+GO
+CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status)
+GO
+CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id)
+GO
+CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id)
+GO
+CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no)
+GO
+CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚岀粍涓媔d鍞竴',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'unique_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'scene_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'骞傜瓑id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'idempotent_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓氬姟缂栧彿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'biz_no'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鍣ㄥ悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'executor_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鏂规硶鍙傛暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'args_str'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯鐘舵�� 0銆侀噸璇曚腑 1銆佹垚鍔� 2銆佹渶澶ф鏁�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'retry_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 1銆侀噸璇曟暟鎹� 2銆佸洖璋冩暟鎹�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鏃ュ織鍩虹淇℃伅琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log'
+GO
+
+-- sj_retry_task_log_message
+CREATE TABLE sj_retry_task_log_message
+(
+    id           bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   nvarchar(64)  NOT NULL,
+    unique_id    nvarchar(64)  NOT NULL,
+    message      nvarchar(max) NOT NULL,
+    log_num      int           NOT NULL DEFAULT 1,
+    real_time    bigint        NOT NULL DEFAULT 0,
+    create_dt    datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id)
+GO
+CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚岀粍涓媔d鍞竴',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'unique_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'寮傚父淇℃伅',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'message'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'log_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婃姤鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'real_time'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟璋冨害鏃ュ織淇℃伅璁板綍琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_task_log_message'
+GO
+
+-- sj_retry_scene_config
+CREATE TABLE sj_retry_scene_config
+(
+    id               bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id     nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    scene_name       nvarchar(64)  NOT NULL,
+    group_name       nvarchar(64)  NOT NULL,
+    scene_status     tinyint       NOT NULL DEFAULT 0,
+    max_retry_count  int           NOT NULL DEFAULT 5,
+    back_off         tinyint       NOT NULL DEFAULT 1,
+    trigger_interval nvarchar(16)  NOT NULL DEFAULT '',
+    deadline_request bigint        NOT NULL DEFAULT 60000,
+    executor_timeout int           NOT NULL DEFAULT 5,
+    route_key        tinyint       NOT NULL DEFAULT 4,
+    description      nvarchar(256) NOT NULL DEFAULT '',
+    create_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'scene_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勭姸鎬� 0銆佹湭鍚敤 1銆佸惎鐢�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'scene_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈�澶ч噸璇曟鏁�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'max_retry_count'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'1銆侀粯璁ょ瓑绾� 2銆佸浐瀹氶棿闅旀椂闂� 3銆丆RON 琛ㄨ揪寮�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'back_off'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闂撮殧鏃堕暱',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'trigger_interval'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'Deadline Request 璋冪敤閾捐秴鏃� 鍗曚綅姣',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'deadline_request'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'executor_timeout'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璺敱绛栫暐',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'route_key'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙閰嶇疆',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_scene_config'
+GO
+
+-- sj_server_node
+CREATE TABLE sj_server_node
+(
+    id           bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   nvarchar(64)  NOT NULL,
+    host_id      nvarchar(64)  NOT NULL,
+    host_ip      nvarchar(64)  NOT NULL,
+    host_port    int           NOT NULL,
+    expire_at    datetime2     NOT NULL,
+    node_type    tinyint       NOT NULL,
+    ext_attrs    nvarchar(256) NULL     DEFAULT '',
+    create_dt    datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt    datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip)
+GO
+
+CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name)
+GO
+CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓绘満id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'host_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈哄櫒ip',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'host_ip'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈哄櫒绔彛',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'host_port'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'杩囨湡鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'expire_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鑺傜偣绫诲瀷 1銆佸鎴风 2銆佹槸鏈嶅姟绔�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈嶅姟鍣ㄨ妭鐐�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_server_node'
+GO
+
+-- sj_distributed_lock
+CREATE TABLE sj_distributed_lock
+(
+    name       nvarchar(64)  NOT NULL PRIMARY KEY,
+    lock_until datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    locked_at  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    locked_by  nvarchar(255) NOT NULL,
+    create_dt  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt  datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閿佸悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閿佸畾鏃堕暱',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'lock_until'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閿佸畾鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'locked_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閿佸畾鑰�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'locked_by'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閿佸畾琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_distributed_lock'
+GO
+
+-- sj_system_user
+CREATE TABLE sj_system_user
+(
+    id        bigint        NOT NULL PRIMARY KEY IDENTITY,
+    username  nvarchar(64)  NOT NULL,
+    password  nvarchar(128) NOT NULL,
+    role      tinyint       NOT NULL DEFAULT 0,
+    create_dt datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璐﹀彿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'username'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'瀵嗙爜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'password'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'瑙掕壊锛�1-鏅�氱敤鎴枫��2-绠$悊鍛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'role'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'绯荤粺鐢ㄦ埛琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user'
+GO
+
+-- pwd: admin
+INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES (N'admin', N'465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', N'2', getdate(), getdate())
+GO
+
+-- sj_system_user_permission
+CREATE TABLE sj_system_user_permission
+(
+    id             bigint       NOT NULL PRIMARY KEY IDENTITY,
+    group_name     nvarchar(64) NOT NULL,
+    namespace_id   nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    system_user_id bigint       NOT NULL,
+    create_dt      datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'绯荤粺鐢ㄦ埛id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'system_user_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'绯荤粺鐢ㄦ埛鏉冮檺琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_system_user_permission'
+GO
+
+-- sj_sequence_alloc
+CREATE TABLE sj_sequence_alloc
+(
+    id           bigint       NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   nvarchar(64) NOT NULL DEFAULT '',
+    max_id       bigint       NOT NULL DEFAULT 1,
+    step         int          NOT NULL DEFAULT 100,
+    update_dt    datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈�澶d',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'max_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'姝ラ暱',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'step'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏇存柊鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍙锋妯″紡搴忓彿ID鍒嗛厤琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_sequence_alloc'
+GO
+
+-- sj_job
+CREATE TABLE sj_job
+(
+    id               bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id     nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       nvarchar(64)  NOT NULL,
+    job_name         nvarchar(64)  NOT NULL,
+    args_str         nvarchar(max) NULL     DEFAULT NULL,
+    args_type        tinyint       NOT NULL DEFAULT 1,
+    next_trigger_at  bigint        NOT NULL,
+    job_status       tinyint       NOT NULL DEFAULT 1,
+    task_type        tinyint       NOT NULL DEFAULT 1,
+    route_key        tinyint       NOT NULL DEFAULT 4,
+    executor_type    tinyint       NOT NULL DEFAULT 1,
+    executor_info    nvarchar(255) NULL     DEFAULT NULL,
+    trigger_type     tinyint       NOT NULL,
+    trigger_interval nvarchar(255) NOT NULL,
+    block_strategy   tinyint       NOT NULL DEFAULT 1,
+    executor_timeout int           NOT NULL DEFAULT 0,
+    max_retry_times  int           NOT NULL DEFAULT 0,
+    parallel_num     int           NOT NULL DEFAULT 1,
+    retry_interval   int           NOT NULL DEFAULT 0,
+    bucket_index     int           NOT NULL DEFAULT 0,
+    resident         tinyint       NOT NULL DEFAULT 0,
+    description      nvarchar(256) NOT NULL DEFAULT '',
+    ext_attrs        nvarchar(256) NULL     DEFAULT '',
+    deleted          tinyint       NOT NULL DEFAULT 0,
+    create_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name)
+GO
+CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index)
+GO
+CREATE INDEX idx_sj_job_03 ON sj_job (create_dt)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'job_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鏂规硶鍙傛暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'args_str'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍙傛暟绫诲瀷 ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'args_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓嬫瑙﹀彂鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'next_trigger_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鐘舵�� 0銆佸叧闂��1銆佸紑鍚�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'job_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 1銆侀泦缇� 2銆佸箍鎾� 3銆佸垏鐗�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璺敱绛栫暐',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'route_key'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鍣ㄧ被鍨�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'executor_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鍣ㄥ悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'executor_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'trigger_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闂撮殧鏃堕暱',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'trigger_interval'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'block_strategy'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'executor_timeout'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏈�澶ч噸璇曟鏁�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'max_retry_times'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'骞惰鏁�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'parallel_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯闂撮殧 ( s ) ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'retry_interval'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'bucket',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'bucket_index'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏄惁鏄父椹讳换鍔�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'resident'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟淇℃伅',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job'
+GO
+
+INSERT INTO sj_job (namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', N'', 0, getdate(), getdate())
+GO
+
+-- sj_job_log_message
+CREATE TABLE sj_job_log_message
+(
+    id            bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id  nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    nvarchar(64)  NOT NULL,
+    job_id        bigint        NOT NULL,
+    task_batch_id bigint        NOT NULL,
+    task_id       bigint        NOT NULL,
+    message       nvarchar(max) NOT NULL,
+    log_num       int           NOT NULL DEFAULT 1,
+    real_time     bigint        NOT NULL DEFAULT 0,
+    ext_attrs     nvarchar(256) NULL     DEFAULT '',
+    create_dt     datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id)
+GO
+CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt)
+GO
+CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟淇℃伅id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'job_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵规id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'task_batch_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璋冨害浠诲姟id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'task_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璋冨害淇℃伅',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'message'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'log_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婃姤鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'real_time'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璋冨害鏃ュ織',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_log_message'
+GO
+
+-- sj_job_task
+CREATE TABLE sj_job_task
+(
+    id             bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id   nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name     nvarchar(64)  NOT NULL,
+    job_id         bigint        NOT NULL,
+    task_batch_id  bigint        NOT NULL,
+    parent_id      bigint        NOT NULL DEFAULT 0,
+    task_status    tinyint       NOT NULL DEFAULT 0,
+    retry_count    int           NOT NULL DEFAULT 0,
+    mr_stage       tinyint       NULL     DEFAULT NULL,
+    leaf           tinyint       NOT NULL DEFAULT '1',
+    task_name      nvarchar(255) NOT NULL DEFAULT '',
+    client_info    nvarchar(128) NULL     DEFAULT NULL,
+    wf_context     nvarchar(max) NULL     DEFAULT NULL,
+    result_message nvarchar(max) NOT NULL,
+    args_str       nvarchar(max) NULL     DEFAULT NULL,
+    args_type      tinyint       NOT NULL DEFAULT 1,
+    ext_attrs      nvarchar(256) NULL     DEFAULT '',
+    create_dt      datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status)
+GO
+CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt)
+GO
+CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟淇℃伅id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'job_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'璋冨害浠诲姟id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'task_batch_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐖舵墽琛屽櫒id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'parent_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鐨勭姸鎬� 0銆佸け璐� 1銆佹垚鍔�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'task_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯娆℃暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'retry_count'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍔ㄦ�佸垎鐗囨墍澶勯樁娈� 1:map 2:reduce 3:mergeReduce',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'mr_stage'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍙跺瓙鑺傜偣',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'leaf'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'task_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'瀹㈡埛绔湴鍧� clientId#ip:port',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'client_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佸叏灞�涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'wf_context'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц缁撴灉',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'result_message'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鏂规硶鍙傛暟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'args_str'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍙傛暟绫诲瀷 ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'args_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟瀹炰緥',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task'
+GO
+
+-- sj_job_task_batch
+CREATE TABLE sj_job_task_batch
+(
+    id                      bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id            nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name              nvarchar(64)  NOT NULL,
+    job_id                  bigint        NOT NULL,
+    workflow_node_id        bigint        NOT NULL DEFAULT 0,
+    parent_workflow_node_id bigint        NOT NULL DEFAULT 0,
+    workflow_task_batch_id  bigint        NOT NULL DEFAULT 0,
+    task_batch_status       tinyint       NOT NULL DEFAULT 0,
+    operation_reason        tinyint       NOT NULL DEFAULT 0,
+    execution_at            bigint        NOT NULL DEFAULT 0,
+    system_task_type        tinyint       NOT NULL DEFAULT 3,
+    parent_id               nvarchar(64)  NOT NULL DEFAULT '',
+    ext_attrs               nvarchar(256) NULL     DEFAULT '',
+    deleted                 tinyint       NOT NULL DEFAULT 0,
+    create_dt               datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt               datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status)
+GO
+CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt)
+GO
+CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name)
+GO
+CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'job_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佽妭鐐筰d',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'workflow_node_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佷换鍔$埗鎵规id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'parent_workflow_node_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佷换鍔℃壒娆d',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'workflow_task_batch_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'task_batch_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎿嶄綔鍘熷洜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'operation_reason'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵ц鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'execution_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'system_task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐖惰妭鐐�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'parent_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵规',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_task_batch'
+GO
+
+-- sj_job_summary
+CREATE TABLE sj_job_summary
+(
+    id               bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id     nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       nvarchar(64)  NOT NULL DEFAULT '',
+    business_id      bigint        NOT NULL,
+    system_task_type tinyint       NOT NULL DEFAULT 3,
+    trigger_at       datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    success_num      int           NOT NULL DEFAULT 0,
+    fail_num         int           NOT NULL DEFAULT 0,
+    fail_reason      nvarchar(512) NOT NULL DEFAULT '',
+    stop_num         int           NOT NULL DEFAULT 0,
+    stop_reason      nvarchar(512) NOT NULL DEFAULT '',
+    cancel_num       int           NOT NULL DEFAULT 0,
+    cancel_reason    nvarchar(512) NOT NULL DEFAULT '',
+    create_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id)
+GO
+
+CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓氬姟id  ( job_id鎴杦orkflow_id ) ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'business_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟绫诲瀷 3銆丣OB浠诲姟 4銆乄ORKFLOW浠诲姟',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'system_task_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁熻鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'trigger_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц鎴愬姛-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'success_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц澶辫触-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'fail_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'澶辫触鍘熷洜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'fail_reason'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц澶辫触-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'stop_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'澶辫触鍘熷洜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'stop_reason'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵ц澶辫触-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'cancel_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'澶辫触鍘熷洜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'cancel_reason'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'DashBoard_Job',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_job_summary'
+GO
+
+-- sj_retry_summary
+CREATE TABLE sj_retry_summary
+(
+    id            bigint       NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id  nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    nvarchar(64) NOT NULL DEFAULT '',
+    scene_name    nvarchar(50) NOT NULL DEFAULT '',
+    trigger_at    datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    running_num   int          NOT NULL DEFAULT 0,
+    finish_num    int          NOT NULL DEFAULT 0,
+    max_count_num int          NOT NULL DEFAULT 0,
+    suspend_num   int          NOT NULL DEFAULT 0,
+    create_dt     datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt     datetime2    NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at)
+GO
+
+CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍦烘櫙鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'scene_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁熻鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'trigger_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯涓�-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'running_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯瀹屾垚-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'finish_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閲嶈瘯鍒拌揪鏈�澶ф鏁�-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'max_count_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鏆傚仠閲嶈瘯-鏃ュ織鏁伴噺',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'suspend_num'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'DashBoard_Retry',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_retry_summary'
+GO
+
+-- sj_workflow
+CREATE TABLE sj_workflow
+(
+    id               bigint        NOT NULL PRIMARY KEY IDENTITY,
+    workflow_name    nvarchar(64)  NOT NULL,
+    namespace_id     nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       nvarchar(64)  NOT NULL,
+    workflow_status  tinyint       NOT NULL DEFAULT 1,
+    trigger_type     tinyint       NOT NULL,
+    trigger_interval nvarchar(255) NOT NULL,
+    next_trigger_at  bigint        NOT NULL,
+    block_strategy   tinyint       NOT NULL DEFAULT 1,
+    executor_timeout int           NOT NULL DEFAULT 0,
+    description      nvarchar(256) NOT NULL DEFAULT '',
+    flow_info        nvarchar(max) NULL     DEFAULT NULL,
+    wf_context       nvarchar(max) NULL     DEFAULT NULL,
+    bucket_index     int           NOT NULL DEFAULT 0,
+    version          int           NOT NULL,
+    ext_attrs        nvarchar(256) NULL     DEFAULT '',
+    deleted          tinyint       NOT NULL DEFAULT 0,
+    create_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt)
+GO
+CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佸悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'workflow_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佺姸鎬� 0銆佸叧闂��1銆佸紑鍚�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'workflow_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'瑙﹀彂绫诲瀷 1.CRON 琛ㄨ揪寮� 2. 鍥哄畾鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'trigger_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闂撮殧鏃堕暱',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'trigger_interval'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓嬫瑙﹀彂鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'next_trigger_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'闃诲绛栫暐 1銆佷涪寮� 2銆佽鐩� 3銆佸苟琛�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'block_strategy'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵ц瓒呮椂鏃堕棿锛屽崟浣嶇',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'executor_timeout'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎻忚堪',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'description'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'娴佺▼淇℃伅',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'flow_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'wf_context'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'bucket',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'bucket_index'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐗堟湰鍙�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow'
+GO
+
+-- sj_workflow_node
+CREATE TABLE sj_workflow_node
+(
+    id                   bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id         nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    node_name            nvarchar(64)  NOT NULL,
+    group_name           nvarchar(64)  NOT NULL,
+    job_id               bigint        NOT NULL,
+    workflow_id          bigint        NOT NULL,
+    node_type            tinyint       NOT NULL DEFAULT 1,
+    expression_type      tinyint       NOT NULL DEFAULT 0,
+    fail_strategy        tinyint       NOT NULL DEFAULT 1,
+    workflow_node_status tinyint       NOT NULL DEFAULT 1,
+    priority_level       int           NOT NULL DEFAULT 1,
+    node_info            nvarchar(max) NULL     DEFAULT NULL,
+    version              int           NOT NULL,
+    ext_attrs            nvarchar(256) NULL     DEFAULT '',
+    deleted              tinyint       NOT NULL DEFAULT 0,
+    create_dt            datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt            datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt)
+GO
+CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鑺傜偣鍚嶇О',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'node_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟淇℃伅id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'job_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴両D',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'workflow_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'1銆佷换鍔¤妭鐐� 2銆佹潯浠惰妭鐐�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'node_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'1銆丼pEl銆�2銆丄viator 3銆丵L',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'expression_type'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'澶辫触绛栫暐 1銆佽烦杩� 2銆侀樆濉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'fail_strategy'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佽妭鐐圭姸鎬� 0銆佸叧闂��1銆佸紑鍚�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'workflow_node_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浼樺厛绾�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'priority_level'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鑺傜偣淇℃伅 ',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'node_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐗堟湰鍙�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佽妭鐐�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_node'
+GO
+
+-- sj_workflow_task_batch
+CREATE TABLE sj_workflow_task_batch
+(
+    id                bigint        NOT NULL PRIMARY KEY IDENTITY,
+    namespace_id      nvarchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        nvarchar(64)  NOT NULL,
+    workflow_id       bigint        NOT NULL,
+    task_batch_status tinyint       NOT NULL DEFAULT 0,
+    operation_reason  tinyint       NOT NULL DEFAULT 0,
+    flow_info         nvarchar(max) NULL     DEFAULT NULL,
+    wf_context        nvarchar(max) NULL     DEFAULT NULL,
+    execution_at      bigint        NOT NULL DEFAULT 0,
+    ext_attrs         nvarchar(256) NULL     DEFAULT '',
+    version           int           NOT NULL DEFAULT 1,
+    deleted           tinyint       NOT NULL DEFAULT 0,
+    create_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         datetime2     NOT NULL DEFAULT CURRENT_TIMESTAMP
+)
+GO
+
+CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status)
+GO
+CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt)
+GO
+CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name)
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'涓婚敭',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍛藉悕绌洪棿id',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'namespace_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'缁勫悕绉�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'group_name'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佷换鍔d',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'workflow_id'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵规鐘舵�� 0銆佸け璐� 1銆佹垚鍔�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'task_batch_status'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎿嶄綔鍘熷洜',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'operation_reason'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'娴佺▼淇℃伅',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'flow_info'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍏ㄥ眬涓婁笅鏂�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'wf_context'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'浠诲姟鎵ц鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'execution_at'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鎵╁睍瀛楁',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'ext_attrs'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鐗堟湰鍙�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'version'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'閫昏緫鍒犻櫎 1銆佸垹闄�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'deleted'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'鍒涘缓鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'create_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'淇敼鏃堕棿',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch',
+     'COLUMN', N'update_dt'
+GO
+
+EXEC sp_addextendedproperty
+     'MS_Description', N'宸ヤ綔娴佹壒娆�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sj_workflow_task_batch'
+GO
+
diff --git a/eims/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/eims/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
new file mode 100644
index 0000000..ad9a0b5
--- /dev/null
+++ b/eims/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql
@@ -0,0 +1,3549 @@
+create table sys_social
+(
+    id                 bigint            NOT NULL,
+    user_id            bigint            NOT NULL,
+    tenant_id          nvarchar(20)      NULL,
+    auth_id            nvarchar(255)     NOT NULL,
+    source             nvarchar(255)     NOT NULL,
+    open_id            nvarchar(255)     NULL,
+    user_name          nvarchar(30)      NOT NULL,
+    nick_name          nvarchar(30)      DEFAULT ('')   NULL,
+    email              nvarchar(255)     DEFAULT ('')   NULL,
+    avatar             nvarchar(500)     DEFAULT ('')   NULL,
+    access_token       nvarchar(255)     NOT NULL,
+    expire_in          bigint            NULL,
+    refresh_token      nvarchar(255)     NULL,
+    access_code        nvarchar(255)     NULL,
+    union_id           nvarchar(255)     NULL,
+    scope              nvarchar(255)     NULL,
+    token_type         nvarchar(255)     NULL,
+    id_token           nvarchar(2000)    NULL,
+    mac_algorithm      nvarchar(255)     NULL,
+    mac_key            nvarchar(255)     NULL,
+    code               nvarchar(255)     NULL,
+    oauth_token        nvarchar(255)     NULL,
+    oauth_token_secret nvarchar(255)     NULL,
+    create_dept        bigint,
+    create_by          bigint,
+    create_time        datetime2(7),
+    update_by          bigint,
+    update_time        datetime2(7),
+    del_flag           nchar             DEFAULT ('0')   NULL,
+    CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id)
+    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+    ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'user_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴+骞冲彴鍞竴id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'auth_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏉ユ簮' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'source'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴缂栧彿鍞竴id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'open_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐧诲綍璐﹀彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'user_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏄电О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'nick_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛閭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'email'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶村儚鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'avatar'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉冧护鐗�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'access_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'expire_in'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'refresh_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'access_code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨� unionid' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'union_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'scope'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'token_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'id_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'mac_algorithm'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'mac_key'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'oauth_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'oauth_token_secret'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'update_time'
+GO
+
+
+CREATE TABLE sys_tenant
+(
+    id                    bigint                          NOT NULL,
+    tenant_id             nvarchar(20)                    NOT NULL,
+    contact_user_name     nvarchar(20)                    NULL,
+    contact_phone         nvarchar(20)                    NULL,
+    company_name          nvarchar(50)                    NULL,
+    license_number        nvarchar(30)                    NULL,
+    address               nvarchar(200)                   NULL,
+    intro                 nvarchar(200)                   NULL,
+    domain                nvarchar(200)                   NULL,
+    remark                nvarchar(200)                   NULL,
+    package_id            bigint                          NULL,
+    expire_time           datetime2(7)                    NULL,
+    account_count         int             DEFAULT ((-1))  NULL,
+    status                nchar(1)        DEFAULT ('0')   NULL,
+    del_flag              nchar(1)        DEFAULT ('0')   NULL,
+    create_dept           bigint                          NULL,
+    create_by             bigint                          NULL,
+    create_time           datetime2(7)                    NULL,
+    update_by             bigint                          NULL,
+    update_time           datetime2(7)                    NULL,
+    CONSTRAINT PK__sys_tenant__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑱旂郴浜�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'contact_user_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑱旂郴鐢佃瘽' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'contact_phone'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'浼佷笟鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'company_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'缁熶竴绀句細淇$敤浠g爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'license_number'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'address'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'浼佷笟绠�浠�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'intro'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍩熷悕' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'domain'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛濂楅缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'package_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'杩囨湡鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'expire_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'account_count'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant'
+GO
+
+INSERT sys_tenant VALUES (1, N'000000', N'绠$悊缁�', N'15888888888', N'XXX鏈夐檺鍏徃', NULL, NULL, N'澶氱鎴烽�氱敤鍚庡彴绠$悊绠$悊绯荤粺', NULL, NULL, NULL, NULL, -1, N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+
+
+CREATE TABLE sys_tenant_package
+(
+    package_id            bigint                          NOT NULL,
+    package_name          nvarchar(20)                    NOT NULL,
+    menu_ids              nvarchar(20)                    NULL,
+    remark                nvarchar(200)                   NULL,
+    menu_check_strictly   tinyint         DEFAULT ((1))   NULL,
+    status                nchar(1)        DEFAULT ('0')   NULL,
+    del_flag              nchar(1)        DEFAULT ('0')   NULL,
+    create_dept           bigint                          NULL,
+    create_by             bigint                          NULL,
+    create_time           datetime2(7)                    NULL,
+    update_by             bigint                          NULL,
+    update_time           datetime2(7)                    NULL,
+    CONSTRAINT PK__sys_tenant_package__B21E8F2427725F8A PRIMARY KEY CLUSTERED (package_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛濂楅id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'package_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'濂楅鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'package_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏宠仈鑿滃崟id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'menu_ids'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛濂楅琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_tenant_package'
+GO
+
+
+CREATE TABLE gen_table
+(
+    table_id          bigint                         NOT NULL,
+    data_name         nvarchar(200) DEFAULT ''       NULL,
+    table_name        nvarchar(200) DEFAULT ''       NULL,
+    table_comment     nvarchar(500) DEFAULT ''       NULL,
+    sub_table_name    nvarchar(64)                   NULL,
+    sub_table_fk_name nvarchar(64)                   NULL,
+    class_name        nvarchar(100) DEFAULT ''       NULL,
+    tpl_category      nvarchar(200) DEFAULT ('crud') NULL,
+    package_name      nvarchar(100)                  NULL,
+    module_name       nvarchar(30)                   NULL,
+    business_name     nvarchar(30)                   NULL,
+    function_name     nvarchar(50)                   NULL,
+    function_author   nvarchar(50)                   NULL,
+    gen_type          nchar(1)      DEFAULT ('0')    NULL,
+    gen_path          nvarchar(200) DEFAULT ('/')    NULL,
+    options           nvarchar(1000)                 NULL,
+    create_dept       bigint                         NULL,
+    create_by         bigint                         NULL,
+    create_time       datetime2(7)                   NULL,
+    update_by         bigint                         NULL,
+    update_time       datetime2(7)                   NULL,
+    remark            nvarchar(500)                  NULL,
+    CONSTRAINT PK__gen_tabl__B21E8F2427725F8A PRIMARY KEY CLUSTERED (table_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'table_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏁版嵁婧愬悕绉�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'data_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'琛ㄥ悕绉�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'table_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'琛ㄦ弿杩�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'table_comment'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏宠仈瀛愯〃鐨勮〃鍚�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'sub_table_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛愯〃鍏宠仈鐨勫閿悕' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'sub_table_fk_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀹炰綋绫诲悕绉�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'class_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'tpl_category'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚鍖呰矾寰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'package_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚妯″潡鍚�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'module_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚涓氬姟鍚�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'business_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚鍔熻兘鍚�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'function_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚鍔熻兘浣滆��' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'function_author'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'gen_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'gen_path'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏跺畠鐢熸垚閫夐」' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'options'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'浠g爜鐢熸垚涓氬姟琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table'
+GO
+
+CREATE TABLE gen_table_column
+(
+    column_id      bigint                       NOT NULL,
+    table_id       bigint                       NULL,
+    column_name    nvarchar(200)                NULL,
+    column_comment nvarchar(500)                NULL,
+    column_type    nvarchar(100)                NULL,
+    java_type      nvarchar(500)                NULL,
+    java_field     nvarchar(200)                NULL,
+    is_pk          nchar(1)                     NULL,
+    is_increment   nchar(1)                     NULL,
+    is_required    nchar(1)                     NULL,
+    is_insert      nchar(1)                     NULL,
+    is_edit        nchar(1)                     NULL,
+    is_list        nchar(1)                     NULL,
+    is_query       nchar(1)                     NULL,
+    query_type     nvarchar(200) DEFAULT ('EQ') NULL,
+    html_type      nvarchar(200)                NULL,
+    dict_type      nvarchar(200) DEFAULT ''     NULL,
+    sort           int                          NULL,
+    create_dept    bigint                       NULL,
+    create_by      bigint                       NULL,
+    create_time    datetime2(7)                 NULL,
+    update_by      bigint                       NULL,
+    update_time    datetime2(7)                 NULL,
+    CONSTRAINT PK__gen_tabl__E301851F2E68B4E8 PRIMARY KEY CLUSTERED (column_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'column_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'褰掑睘琛ㄧ紪鍙�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'table_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒楀悕绉�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'column_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒楁弿杩�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'column_comment'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒楃被鍨�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'column_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'JAVA绫诲瀷' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'java_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'JAVA瀛楁鍚�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'java_field'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁涓婚敭锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_pk'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁鑷锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_increment'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁蹇呭~锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_required'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_insert'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁缂栬緫瀛楁锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_edit'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁鍒楄〃瀛楁锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_list'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁鏌ヨ瀛楁锛�1鏄級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'is_query'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'query_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'html_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀绫诲瀷' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'dict_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎺掑簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'sort'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table_column'
+GO
+
+CREATE TABLE sys_config
+(
+    config_id    bigint                      NOT NULL,
+    tenant_id    nvarchar(20)  DEFAULT '000000'  NULL,
+    config_name  nvarchar(100) DEFAULT ''    NULL,
+    config_key   nvarchar(100) DEFAULT ''    NULL,
+    config_value nvarchar(500) DEFAULT ''    NULL,
+    config_type  nchar(1)      DEFAULT ('N') NULL,
+    create_dept  bigint                      NULL,
+    create_by    bigint                      NULL,
+    create_time  datetime2(7)                NULL,
+    update_by    bigint                      NULL,
+    update_time  datetime2(7)                NULL,
+    remark       nvarchar(500)               NULL,
+    CONSTRAINT PK__sys_conf__4AD1BFF182643682 PRIMARY KEY CLUSTERED (config_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍙傛暟涓婚敭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'config_id'
+GO
+EXEC sys.sp_addextendedproperty
+     'MS_Description', N'绉熸埛缂栧彿' ,
+     'SCHEMA', N'dbo',
+     'TABLE', N'sys_config',
+     'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍙傛暟鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'config_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍙傛暟閿悕' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'config_key'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍙傛暟閿��' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'config_value'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绯荤粺鍐呯疆锛圷鏄� N鍚︼級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'config_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍙傛暟閰嶇疆琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_config'
+GO
+
+INSERT sys_config VALUES (1, N'000000', N'涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О', N'sys.index.skinName', N'skin-blue', N'Y', 103, 1, getdate(), NULL, NULL, N'钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow')
+GO
+INSERT sys_config VALUES (2, N'000000', N'鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜', N'sys.user.initPassword', N'123456', N'Y', 103, 1, getdate(), NULL, NULL, N'鍒濆鍖栧瘑鐮� 123456')
+GO
+INSERT sys_config VALUES (3, N'000000', N'涓绘鏋堕〉-渚ц竟鏍忎富棰�', N'sys.index.sideTheme', N'theme-dark', N'Y', 103, 1, getdate(), NULL, NULL, N'娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light')
+GO
+INSERT sys_config VALUES (5, N'000000', N'璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�', N'sys.account.registerUser', N'false', N'Y', 103, 1, getdate(), NULL, NULL, N'鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�')
+GO
+INSERT sys_config VALUES (11, N'000000', N'OSS棰勮鍒楄〃璧勬簮寮�鍏�', N'sys.oss.previewListResource', N'true', N'Y', 103, 1, getdate(), NULL, NULL, N'true:寮�鍚�, false:鍏抽棴');
+GO
+
+CREATE TABLE sys_dept
+(
+    dept_id     bigint                     NOT NULL,
+    tenant_id   nvarchar(20) DEFAULT ('000000') NULL,
+    parent_id   bigint       DEFAULT ((0)) NULL,
+    ancestors   nvarchar(500)DEFAULT ''    NULL,
+    dept_name   nvarchar(30)               NULL,
+    dept_category nvarchar(100) DEFAULT '' NULL,
+    order_num   int          DEFAULT ((0)) NULL,
+    leader      bigint                     NULL,
+    phone       nvarchar(11)               NULL,
+    email       nvarchar(50)               NULL,
+    status      nchar(1)     DEFAULT ('0') NULL,
+    del_flag    nchar(1)     DEFAULT ('0') NULL,
+    create_dept bigint                     NULL,
+    create_by   bigint                     NULL,
+    create_time datetime2(7)               NULL,
+    update_by   bigint                     NULL,
+    update_time datetime2(7)               NULL,
+    CONSTRAINT PK__sys_dept__DCA659747DE13804 PRIMARY KEY CLUSTERED (dept_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'dept_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐖堕儴闂╥d' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'parent_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绁栫骇鍒楄〃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'ancestors'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'dept_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬绫诲埆缂栫爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'dept_category'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず椤哄簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'order_num'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璐熻矗浜�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'leader'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑱旂郴鐢佃瘽' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'phone'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'email'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept'
+GO
+
+INSERT sys_dept VALUES (100, N'000000', 0, N'0', N'XXX绉戞妧', NULL, 0, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (101, N'000000', 100, N'0,100', N'娣卞湷鎬诲叕鍙�', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (102, N'000000', 100, N'0,100', N'闀挎矙鍒嗗叕鍙�', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (103, N'000000', 101, N'0,100,101', N'鐮斿彂閮ㄩ棬', NULL, 1, 1, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (104, N'000000', 101, N'0,100,101', N'甯傚満閮ㄩ棬', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (105, N'000000', 101, N'0,100,101', N'娴嬭瘯閮ㄩ棬', NULL, 3, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (106, N'000000', 101, N'0,100,101', N'璐㈠姟閮ㄩ棬', NULL, 4, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (107, N'000000', 101, N'0,100,101', N'杩愮淮閮ㄩ棬', NULL, 5, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (108, N'000000', 102, N'0,100,102', N'甯傚満閮ㄩ棬', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+INSERT sys_dept VALUES (109, N'000000', 102, N'0,100,102', N'璐㈠姟閮ㄩ棬', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL)
+GO
+
+CREATE TABLE sys_dict_data
+(
+    dict_code   bigint                      NOT NULL,
+    tenant_id   nvarchar(20)  DEFAULT ('000000') NULL,
+    dict_sort   int           DEFAULT ((0)) NULL,
+    dict_label  nvarchar(100) DEFAULT ''    NULL,
+    dict_value  nvarchar(100) DEFAULT ''    NULL,
+    dict_type   nvarchar(100) DEFAULT ''    NULL,
+    css_class   nvarchar(100)               NULL,
+    list_class  nvarchar(100)               NULL,
+    is_default  nchar(1)      DEFAULT ('N') NULL,
+    create_dept bigint                      NULL,
+    create_by   bigint                      NULL,
+    create_time datetime2(7)                NULL,
+    update_by   bigint                      NULL,
+    update_time datetime2(7)                NULL,
+    remark      nvarchar(500)               NULL,
+    CONSTRAINT PK__sys_dict__19CBC34B661AF3B3 PRIMARY KEY CLUSTERED (dict_code)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀缂栫爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'dict_code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀缂栫爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀鎺掑簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'dict_sort'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀鏍囩' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'dict_label'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀閿��' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'dict_value'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀绫诲瀷' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'dict_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'css_class'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'琛ㄦ牸鍥炴樉鏍峰紡' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'list_class'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁榛樿锛圷鏄� N鍚︼級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'is_default'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀鏁版嵁琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_data'
+GO
+
+INSERT sys_dict_data VALUES (1, N'000000', 1, N'鐢�', N'0', N'sys_user_sex', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'鎬у埆鐢�')
+GO
+INSERT sys_dict_data VALUES (2, N'000000', 2, N'濂�', N'1', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'鎬у埆濂�')
+GO
+INSERT sys_dict_data VALUES (3, N'000000', 3, N'鏈煡', N'2', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'鎬у埆鏈煡')
+GO
+INSERT sys_dict_data VALUES (4, N'000000', 1, N'鏄剧ず', N'0', N'sys_show_hide', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'鏄剧ず鑿滃崟')
+GO
+INSERT sys_dict_data VALUES (5, N'000000', 2, N'闅愯棌', N'1', N'sys_show_hide', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'闅愯棌鑿滃崟')
+GO
+INSERT sys_dict_data VALUES (6, N'000000', 1, N'姝e父', N'0', N'sys_normal_disable', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'姝e父鐘舵��')
+GO
+INSERT sys_dict_data VALUES (7, N'000000', 2, N'鍋滅敤', N'1', N'sys_normal_disable', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍋滅敤鐘舵��')
+GO
+INSERT sys_dict_data VALUES (8, N'000000', 1, N'姝e父', N'0', N'sys_job_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'姝e父鐘舵��')
+GO
+INSERT sys_dict_data VALUES (9, N'000000', 2, N'鏆傚仠', N'1', N'sys_job_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍋滅敤鐘舵��')
+GO
+INSERT sys_dict_data VALUES (10, N'000000', 1, N'榛樿', N'DEFAULT', N'sys_job_group', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'榛樿鍒嗙粍')
+GO
+INSERT sys_dict_data VALUES (11, N'000000', 2, N'绯荤粺', N'SYSTEM', N'sys_job_group', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'绯荤粺鍒嗙粍')
+GO
+INSERT sys_dict_data VALUES (12, N'000000', 1, N'鏄�', N'Y', N'sys_yes_no', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'绯荤粺榛樿鏄�')
+GO
+INSERT sys_dict_data VALUES (13, N'000000', 2, N'鍚�', N'N', N'sys_yes_no', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'绯荤粺榛樿鍚�')
+GO
+INSERT sys_dict_data VALUES (14, N'000000', 1, N'閫氱煡', N'1', N'sys_notice_type', N'', N'warning', N'Y', 103, 1, getdate(), NULL, NULL, N'閫氱煡')
+GO
+INSERT sys_dict_data VALUES (15, N'000000', 2, N'鍏憡', N'2', N'sys_notice_type', N'', N'success', N'N', 103, 1, getdate(), NULL, NULL, N'鍏憡')
+GO
+INSERT sys_dict_data VALUES (16, N'000000', 1, N'姝e父', N'0', N'sys_notice_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'姝e父鐘舵��')
+GO
+INSERT sys_dict_data VALUES (17, N'000000', 2, N'鍏抽棴', N'1', N'sys_notice_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍏抽棴鐘舵��')
+GO
+INSERT sys_dict_data VALUES (29, N'000000', 99, N'鍏朵粬', N'0', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'鍏朵粬鎿嶄綔');
+GO
+INSERT sys_dict_data VALUES (18, N'000000', 1, N'鏂板', N'1', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'鏂板鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (19, N'000000', 2, N'淇敼', N'2', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'淇敼鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (20, N'000000', 3, N'鍒犻櫎', N'3', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍒犻櫎鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (21, N'000000', 4, N'鎺堟潈', N'4', N'sys_oper_type', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'鎺堟潈鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (22, N'000000', 5, N'瀵煎嚭', N'5', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'瀵煎嚭鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (23, N'000000', 6, N'瀵煎叆', N'6', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'瀵煎叆鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (24, N'000000', 7, N'寮洪��', N'7', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'寮洪��鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (25, N'000000', 8, N'鐢熸垚浠g爜', N'8', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'鐢熸垚鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (26, N'000000', 9, N'娓呯┖鏁版嵁', N'9', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'娓呯┖鎿嶄綔')
+GO
+INSERT sys_dict_data VALUES (27, N'000000', 1, N'鎴愬姛', N'0', N'sys_common_status', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'姝e父鐘舵��')
+GO
+INSERT sys_dict_data VALUES (28, N'000000', 2, N'澶辫触', N'1', N'sys_common_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'鍋滅敤鐘舵��')
+GO
+INSERT sys_dict_data VALUES (30, N'000000', 0, N'瀵嗙爜璁よ瘉', N'password', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'瀵嗙爜璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (31, N'000000', 0, N'鐭俊璁よ瘉', N'sms', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'鐭俊璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (32, N'000000', 0, N'閭欢璁よ瘉', N'email', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'閭欢璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (33, N'000000', 0, N'灏忕▼搴忚璇�', N'xcx', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'灏忕▼搴忚璇�')
+GO
+INSERT sys_dict_data VALUES (34, N'000000', 0, N'涓夋柟鐧诲綍璁よ瘉', N'`social`', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'涓夋柟鐧诲綍璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'PC')
+GO
+INSERT sys_dict_data VALUES (36, N'000000', 0, N'瀹夊崜', N'`android`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'瀹夊崜')
+GO
+INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'iOS')
+GO
+INSERT sys_dict_data VALUES (38, N'000000', 0, N'灏忕▼搴�', N'`xcx`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'灏忕▼搴�')
+GO
+
+CREATE TABLE sys_dict_type
+(
+    dict_id     bigint                      NOT NULL,
+    tenant_id   nvarchar(20)  DEFAULT ('000000') NULL,
+    dict_name   nvarchar(100) DEFAULT ''    NULL,
+    dict_type   nvarchar(100) DEFAULT ''    NULL,
+    create_dept bigint                      NULL,
+    create_by   bigint                      NULL,
+    create_time datetime2(7)                NULL,
+    update_by   bigint                      NULL,
+    update_time datetime2(7)                NULL,
+    remark      nvarchar(500)               NULL,
+    CONSTRAINT PK__sys_dict__3BD4186C409C5391 PRIMARY KEY CLUSTERED (dict_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+CREATE NONCLUSTERED INDEX sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type)
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀涓婚敭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'dict_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀涓婚敭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'dict_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀绫诲瀷' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'dict_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀛楀吀绫诲瀷琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dict_type'
+GO
+
+INSERT sys_dict_type VALUES (1, N'000000', N'鐢ㄦ埛鎬у埆', N'sys_user_sex', 103, 1, getdate(), NULL, NULL, N'鐢ㄦ埛鎬у埆鍒楄〃')
+GO
+INSERT sys_dict_type VALUES (2, N'000000', N'鑿滃崟鐘舵��', N'sys_show_hide', 103, 1, getdate(), NULL, NULL, N'鑿滃崟鐘舵�佸垪琛�')
+GO
+INSERT sys_dict_type VALUES (3, N'000000', N'绯荤粺寮�鍏�', N'sys_normal_disable', 103, 1, getdate(), NULL, NULL, N'绯荤粺寮�鍏冲垪琛�')
+GO
+INSERT sys_dict_type VALUES (4, N'000000', N'浠诲姟鐘舵��', N'sys_job_status', 103, 1, getdate(), NULL, NULL, N'浠诲姟鐘舵�佸垪琛�')
+GO
+INSERT sys_dict_type VALUES (5, N'000000', N'浠诲姟鍒嗙粍', N'sys_job_group', 103, 1, getdate(), NULL, NULL, N'浠诲姟鍒嗙粍鍒楄〃')
+GO
+INSERT sys_dict_type VALUES (6, N'000000', N'绯荤粺鏄惁', N'sys_yes_no', 103, 1, getdate(), NULL, NULL, N'绯荤粺鏄惁鍒楄〃')
+GO
+INSERT sys_dict_type VALUES (7, N'000000', N'閫氱煡绫诲瀷', N'sys_notice_type', 103, 1, getdate(), NULL, NULL, N'閫氱煡绫诲瀷鍒楄〃')
+GO
+INSERT sys_dict_type VALUES (8, N'000000', N'閫氱煡鐘舵��', N'sys_notice_status', 103, 1, getdate(), NULL, NULL, N'閫氱煡鐘舵�佸垪琛�')
+GO
+INSERT sys_dict_type VALUES (9, N'000000', N'鎿嶄綔绫诲瀷', N'sys_oper_type', 103, 1, getdate(), NULL, NULL, N'鎿嶄綔绫诲瀷鍒楄〃')
+GO
+INSERT sys_dict_type VALUES (10, N'000000', N'绯荤粺鐘舵��', N'sys_common_status', 103, 1, getdate(), NULL, NULL, N'鐧诲綍鐘舵�佸垪琛�')
+GO
+INSERT sys_dict_type VALUES (11, N'000000', N'鎺堟潈绫诲瀷', N'sys_grant_type', 103, 1, getdate(), NULL, NULL, N'璁よ瘉鎺堟潈绫诲瀷')
+GO
+INSERT sys_dict_type VALUES (12, N'000000', N'璁惧绫诲瀷', N'sys_device_type', 103, 1, getdate(), NULL, NULL, N'瀹㈡埛绔澶囩被鍨�')
+GO
+
+CREATE TABLE sys_logininfor
+(
+    info_id        bigint                      NOT NULL,
+    tenant_id      nvarchar(20)  DEFAULT ('000000') NULL,
+    user_name      nvarchar(50)  DEFAULT ''    NULL,
+    client_key     nvarchar(32)  DEFAULT ''    NULL,
+    device_type    nvarchar(32)  DEFAULT ''    NULL,
+    ipaddr         nvarchar(128) DEFAULT ''    NULL,
+    login_location nvarchar(255) DEFAULT ''    NULL,
+    browser        nvarchar(50)  DEFAULT ''    NULL,
+    os             nvarchar(50)  DEFAULT ''    NULL,
+    status         nchar(1)      DEFAULT ('0') NULL,
+    msg            nvarchar(255) DEFAULT ''    NULL,
+    login_time     datetime2(7)                NULL,
+    CONSTRAINT PK__sys_logi__3D8A9C1A1854AE10 PRIMARY KEY CLUSTERED (info_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+CREATE NONCLUSTERED INDEX idx_sys_logininfor_s ON sys_logininfor (status)
+GO
+CREATE NONCLUSTERED INDEX idx_sys_logininfor_lt ON sys_logininfor (login_time)
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璁块棶ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'info_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛璐﹀彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'user_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀹㈡埛绔�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'client_key'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璁惧绫诲瀷' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'device_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐧诲綍IP鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'ipaddr'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐧诲綍鍦扮偣' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'login_location'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'娴忚鍣ㄧ被鍨�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'browser'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔绯荤粺' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'os'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎻愮ず娑堟伅' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'msg'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璁块棶鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'login_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绯荤粺璁块棶璁板綍' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor'
+GO
+
+CREATE TABLE sys_menu
+(
+    menu_id     bigint                      NOT NULL,
+    menu_name   nvarchar(50)                NOT NULL,
+    parent_id   bigint        DEFAULT ((0)) NULL,
+    order_num   int           DEFAULT ((0)) NULL,
+    path        nvarchar(200) DEFAULT ''    NULL,
+    component   nvarchar(255)               NULL,
+    query_param nvarchar(255)               NULL,
+    is_frame    int           DEFAULT ((1)) NULL,
+    is_cache    int           DEFAULT ((0)) NULL,
+    menu_type   nchar(1)      DEFAULT ''    NULL,
+    visible     nchar(1)      DEFAULT ((0)) NULL,
+    status      nchar(1)      DEFAULT ((0)) NULL,
+    perms       nvarchar(100)               NULL,
+    icon        nvarchar(100) DEFAULT ('#') NULL,
+    create_dept bigint                      NULL,
+    create_by   bigint                      NULL,
+    create_time datetime2(7)                NULL,
+    update_by   bigint                      NULL,
+    update_time datetime2(7)                NULL,
+    remark      nvarchar(500) DEFAULT ''    NULL,
+    CONSTRAINT PK__sys_menu__4CA0FADCF8545C58 PRIMARY KEY CLUSTERED (menu_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'menu_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'menu_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐖惰彍鍗旾D' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'parent_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず椤哄簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'order_num'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璺敱鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'path'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'缁勪欢璺緞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'component'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璺敱鍙傛暟' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'query_param'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁涓哄閾撅紙0鏄� 1鍚︼級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'is_frame'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'is_cache'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'menu_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'visible'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏉冮檺鏍囪瘑' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'perms'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟鍥炬爣' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'icon'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟鏉冮檺琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_menu'
+GO
+
+INSERT sys_menu VALUES (1, N'绯荤粺绠$悊', 0, 1, N'system', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'system', 103, 1, getdate(), NULL, NULL, N'绯荤粺绠$悊鐩綍')
+GO
+INSERT sys_menu VALUES (6, N'绉熸埛绠$悊', 0, 2, N'tenant', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'chart', 103, 1, getdate(), NULL, NULL, N'绉熸埛绠$悊鐩綍')
+GO
+INSERT sys_menu VALUES (2, N'绯荤粺鐩戞帶', 0, 3, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, getdate(), NULL, NULL, N'绯荤粺鐩戞帶鐩綍')
+GO
+INSERT sys_menu VALUES (3, N'绯荤粺宸ュ叿', 0, 4, N'tool', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'tool', 103, 1, getdate(), NULL, NULL, N'绯荤粺宸ュ叿鐩綍')
+GO
+INSERT sys_menu VALUES (4, N'PLUS瀹樼綉', 0, 5, N'https://gitee.com/dromara/RuoYi-Vue-Plus', null, N'', 0, 0, N'M', N'0', N'0', N'', N'guide', 103, 1, getdate(), null, null, N'RuoYi-Vue-Plus瀹樼綉鍦板潃');
+GO
+INSERT sys_menu VALUES (5, N'娴嬭瘯鑿滃崟', 0, 5, N'demo', NULL, N'', 1, 0, N'M', N'0', N'0', NULL, N'star', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (100, N'鐢ㄦ埛绠$悊', 1, 1, N'user', N'system/user/index', N'', 1, 0, N'C', N'0', N'0', N'system:user:list', N'user', 103, 1, getdate(), NULL, NULL, N'鐢ㄦ埛绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (101, N'瑙掕壊绠$悊', 1, 2, N'role', N'system/role/index', N'', 1, 0, N'C', N'0', N'0', N'system:role:list', N'peoples', 103, 1, getdate(), NULL, NULL, N'瑙掕壊绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (102, N'鑿滃崟绠$悊', 1, 3, N'menu', N'system/menu/index', N'', 1, 0, N'C', N'0', N'0', N'system:menu:list', N'tree-table', 103, 1, getdate(), NULL, NULL, N'鑿滃崟绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (103, N'閮ㄩ棬绠$悊', 1, 4, N'dept', N'system/dept/index', N'', 1, 0, N'C', N'0', N'0', N'system:dept:list', N'tree', 103, 1, getdate(), NULL, NULL, N'閮ㄩ棬绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (104, N'宀椾綅绠$悊', 1, 5, N'post', N'system/post/index', N'', 1, 0, N'C', N'0', N'0', N'system:post:list', N'post', 103, 1, getdate(), NULL, NULL, N'宀椾綅绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (105, N'瀛楀吀绠$悊', 1, 6, N'dict', N'system/dict/index', N'', 1, 0, N'C', N'0', N'0', N'system:dict:list', N'dict', 103, 1, getdate(), NULL, NULL, N'瀛楀吀绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (106, N'鍙傛暟璁剧疆', 1, 7, N'config', N'system/config/index', N'', 1, 0, N'C', N'0', N'0', N'system:config:list', N'edit', 103, 1, getdate(), NULL, NULL, N'鍙傛暟璁剧疆鑿滃崟')
+GO
+INSERT sys_menu VALUES (107, N'閫氱煡鍏憡', 1, 8, N'notice', N'system/notice/index', N'', 1, 0, N'C', N'0', N'0', N'system:notice:list', N'message', 103, 1, getdate(), NULL, NULL, N'閫氱煡鍏憡鑿滃崟')
+GO
+INSERT sys_menu VALUES (108, N'鏃ュ織绠$悊', 1, 9, N'log', N'', N'', 1, 0, N'M', N'0', N'0', N'', N'log', 103, 1, getdate(), NULL, NULL, N'鏃ュ織绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (109, N'鍦ㄧ嚎鐢ㄦ埛', 2, 1, N'online', N'monitor/online/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:online:list', N'online', 103, 1, getdate(), NULL, NULL, N'鍦ㄧ嚎鐢ㄦ埛鑿滃崟')
+GO
+INSERT sys_menu VALUES (113, N'缂撳瓨鐩戞帶', 2, 5, N'cache', N'monitor/cache/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:cache:list', N'redis', 103, 1, getdate(), NULL, NULL, N'缂撳瓨鐩戞帶鑿滃崟')
+GO
+INSERT sys_menu VALUES (115, N'浠g爜鐢熸垚', 3, 2, N'gen', N'tool/gen/index', N'', 1, 0, N'C', N'0', N'0', N'tool:gen:list', N'code', 103, 1, getdate(), NULL, NULL, N'浠g爜鐢熸垚鑿滃崟')
+GO
+INSERT sys_menu VALUES (121, N'绉熸埛绠$悊', 6, 1, N'tenant', N'system/tenant/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenant:list', N'code', 103, 1, getdate(), NULL, NULL, N'绉熸埛绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (122, N'绉熸埛濂楅绠$悊', 6, 2, N'tenantPackage', N'system/tenantPackage/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenantPackage:list', N'code', 103, 1, getdate(), NULL, NULL, N'绉熸埛濂楅绠$悊鑿滃崟')
+GO
+INSERT sys_menu VALUES (123, N'瀹㈡埛绔鐞�', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'瀹㈡埛绔鐞嗚彍鍗�')
+GO
+INSERT sys_menu VALUES (117, N'Admin鐩戞帶', 2, 5, N'Admin', N'monitor/admin/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:admin:list', N'dashboard', 103, 1, getdate(), NULL, NULL, N'Admin鐩戞帶鑿滃崟');
+GO
+INSERT sys_menu VALUES (118, N'鏂囦欢绠$悊', 1, 10, N'oss', N'system/oss/index', N'', 1, 0, N'C', '0', N'0', N'system:oss:list', N'upload', 103, 1, getdate(), NULL, NULL, N'鏂囦欢绠$悊鑿滃崟');
+GO
+INSERT sys_menu VALUES (120, N'浠诲姟璋冨害涓績', 2, 5, N'snailjob', N'monitor/snailjob/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:snailjob:list', N'job', 103, 1, getdate(), NULL, NULL, N'SnailJob鎺у埗鍙拌彍鍗�');
+GO
+INSERT sys_menu VALUES (500, N'鎿嶄綔鏃ュ織', 108, 1, N'operlog', N'monitor/operlog/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:operlog:list', N'form', 103, 1, getdate(), NULL, NULL, N'鎿嶄綔鏃ュ織鑿滃崟')
+GO
+INSERT sys_menu VALUES (501, N'鐧诲綍鏃ュ織', 108, 2, N'logininfor', N'monitor/logininfor/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:logininfor:list', N'logininfor', 103, 1, getdate(), NULL, NULL, N'鐧诲綍鏃ュ織鑿滃崟')
+GO
+INSERT sys_menu VALUES (1001, N'鐢ㄦ埛鏌ヨ', 100, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1002, N'鐢ㄦ埛鏂板', 100, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1003, N'鐢ㄦ埛淇敼', 100, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1004, N'鐢ㄦ埛鍒犻櫎', 100, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1005, N'鐢ㄦ埛瀵煎嚭', 100, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1006, N'鐢ㄦ埛瀵煎叆', 100, 6, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:import', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1007, N'閲嶇疆瀵嗙爜', 100, 7, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:resetPwd', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1008, N'瑙掕壊鏌ヨ', 101, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1009, N'瑙掕壊鏂板', 101, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1010, N'瑙掕壊淇敼', 101, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1011, N'瑙掕壊鍒犻櫎', 101, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1012, N'瑙掕壊瀵煎嚭', 101, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1013, N'鑿滃崟鏌ヨ', 102, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1014, N'鑿滃崟鏂板', 102, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1015, N'鑿滃崟淇敼', 102, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1016, N'鑿滃崟鍒犻櫎', 102, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1017, N'閮ㄩ棬鏌ヨ', 103, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1018, N'閮ㄩ棬鏂板', 103, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1019, N'閮ㄩ棬淇敼', 103, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1020, N'閮ㄩ棬鍒犻櫎', 103, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1021, N'宀椾綅鏌ヨ', 104, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1022, N'宀椾綅鏂板', 104, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1023, N'宀椾綅淇敼', 104, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1024, N'宀椾綅鍒犻櫎', 104, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1025, N'宀椾綅瀵煎嚭', 104, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1026, N'瀛楀吀鏌ヨ', 105, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1027, N'瀛楀吀鏂板', 105, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1028, N'瀛楀吀淇敼', 105, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1029, N'瀛楀吀鍒犻櫎', 105, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1030, N'瀛楀吀瀵煎嚭', 105, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1031, N'鍙傛暟鏌ヨ', 106, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1032, N'鍙傛暟鏂板', 106, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1033, N'鍙傛暟淇敼', 106, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1034, N'鍙傛暟鍒犻櫎', 106, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1035, N'鍙傛暟瀵煎嚭', 106, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1036, N'鍏憡鏌ヨ', 107, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1037, N'鍏憡鏂板', 107, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:add', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1038, N'鍏憡淇敼', 107, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1039, N'鍏憡鍒犻櫎', 107, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1040, N'鎿嶄綔鏌ヨ', 500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1041, N'鎿嶄綔鍒犻櫎', 500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1042, N'鏃ュ織瀵煎嚭', 500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1043, N'鐧诲綍鏌ヨ', 501, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1044, N'鐧诲綍鍒犻櫎', 501, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1045, N'鏃ュ織瀵煎嚭', 501, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1050, N'璐︽埛瑙i攣', 501, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:unlock',  N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1046, N'鍦ㄧ嚎鏌ヨ', 109, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1047, N'鎵归噺寮洪��', 109, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:batchLogout', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1048, N'鍗曟潯寮洪��', 109, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:forceLogout', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1055, N'鐢熸垚鏌ヨ', 115, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1056, N'鐢熸垚淇敼', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:edit', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1057, N'鐢熸垚鍒犻櫎', 115, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:remove', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1058, N'瀵煎叆浠g爜', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:import', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1059, N'棰勮浠g爜', 115, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:preview', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_menu VALUES (1060, N'鐢熸垚浠g爜', 115, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:code', N'#', 103, 1, getdate(), NULL, NULL, N'')
+GO
+-- oss鐩稿叧鎸夐挳
+INSERT sys_menu VALUES (1600, N'鏂囦欢鏌ヨ', 118, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1601, N'鏂囦欢涓婁紶', 118, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:upload', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1602, N'鏂囦欢涓嬭浇', 118, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:download', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1603, N'鏂囦欢鍒犻櫎', 118, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1620, N'閰嶇疆鍒楄〃', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1621, N'閰嶇疆娣诲姞', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1622, N'閰嶇疆缂栬緫', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1623, N'閰嶇疆鍒犻櫎', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+-- 绉熸埛绠$悊鐩稿叧鎸夐挳
+INSERT sys_menu VALUES (1606, N'绉熸埛鏌ヨ', 121, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1607, N'绉熸埛鏂板', 121, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1608, N'绉熸埛淇敼', 121, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1609, N'绉熸埛鍒犻櫎', 121, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1610, N'绉熸埛瀵煎嚭', 121, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+-- 绉熸埛濂楅绠$悊鐩稿叧鎸夐挳
+INSERT sys_menu VALUES (1611, N'绉熸埛濂楅鏌ヨ', 122, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1612, N'绉熸埛濂楅鏂板', 122, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1613, N'绉熸埛濂楅淇敼', 122, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1614, N'绉熸埛濂楅鍒犻櫎', 122, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1615, N'绉熸埛濂楅瀵煎嚭', 122, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+-- 瀹㈡埛绔鐞嗘寜閽�
+INSERT sys_menu VALUES (1061, N'瀹㈡埛绔鐞嗘煡璇�', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1062, N'瀹㈡埛绔鐞嗘柊澧�', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1063, N'瀹㈡埛绔鐞嗕慨鏀�', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1064, N'瀹㈡埛绔鐞嗗垹闄�', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1065, N'瀹㈡埛绔鐞嗗鍑�', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+-- 娴嬭瘯鑿滃崟
+INSERT sys_menu VALUES (1500, N'娴嬭瘯鍗曡〃', 5, 1, N'demo', N'demo/demo/index', N'', 1, 0, N'C', N'0', N'0', N'demo:demo:list', N'#', 103, 1, getdate(), NULL, NULL, N'娴嬭瘯鍗曡〃鑿滃崟');
+GO
+INSERT sys_menu VALUES (1501, N'娴嬭瘯鍗曡〃鏌ヨ', 1500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1502, N'娴嬭瘯鍗曡〃鏂板', 1500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1503, N'娴嬭瘯鍗曡〃淇敼', 1500, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1504, N'娴嬭瘯鍗曡〃鍒犻櫎', 1500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1505, N'娴嬭瘯鍗曡〃瀵煎嚭', 1500, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+
+INSERT sys_menu VALUES (1506, N'娴嬭瘯鏍戣〃', 5, 1, N'tree', N'demo/tree/index', N'', 1, 0, N'C', N'0', N'0', N'demo:tree:list', N'#', 103, 1, getdate(), NULL, NULL, N'娴嬭瘯鏍戣〃鑿滃崟');
+GO
+INSERT sys_menu VALUES (1507, N'娴嬭瘯鏍戣〃鏌ヨ', 1506, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1508, N'娴嬭瘯鏍戣〃鏂板', 1506, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1509, N'娴嬭瘯鏍戣〃淇敼', 1506, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1510, N'娴嬭瘯鏍戣〃鍒犻櫎', 1506, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1511, N'娴嬭瘯鏍戣〃瀵煎嚭', 1506, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+
+CREATE TABLE sys_notice
+(
+    notice_id      bigint                     NOT NULL,
+    tenant_id      nvarchar(20) DEFAULT ('000000') NULL,
+    notice_title   nvarchar(50)               NOT NULL,
+    notice_type    nchar(1)                   NOT NULL,
+    notice_content nvarchar(max)              NULL,
+    status         nchar(1)     DEFAULT ('0') NULL,
+    create_dept    bigint                     NULL,
+    create_by      bigint                     NULL,
+    create_time    datetime2(7)               NULL,
+    update_by      bigint                     NULL,
+    update_time    datetime2(7)               NULL,
+    remark         nvarchar(255)              NULL,
+    CONSTRAINT PK__sys_noti__3E82A5DB0EC94801 PRIMARY KEY CLUSTERED (notice_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+TEXTIMAGE_ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏憡ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'notice_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏憡鏍囬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'notice_title'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'notice_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏憡鍐呭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'notice_content'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閫氱煡鍏憡琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_notice'
+GO
+
+INSERT sys_notice VALUES (1, N'000000', N'娓╅Θ鎻愰啋锛�2018-07-01 鑻ヤ緷鏂扮増鏈彂甯冨暒', N'2', N'鏂扮増鏈唴瀹�', N'0', 103, 1, getdate(), NULL, NULL, N'绠$悊鍛�')
+GO
+INSERT sys_notice VALUES (2, N'000000', N'缁存姢閫氱煡锛�2018-07-01 鑻ヤ緷绯荤粺鍑屾櫒缁存姢', N'1', N'缁存姢鍐呭', N'0', 103, 1, getdate(), NULL, NULL, N'绠$悊鍛�')
+GO
+
+CREATE TABLE sys_oper_log
+(
+    oper_id        bigint                       NOT NULL,
+    tenant_id      nvarchar(20)   DEFAULT ('000000') NULL,
+    title          nvarchar(50)   DEFAULT ''    NULL,
+    business_type  int            DEFAULT ((0)) NULL,
+    method         nvarchar(100)  DEFAULT ''    NULL,
+    request_method nvarchar(10)   DEFAULT ''    NULL,
+    operator_type  int            DEFAULT ((0)) NULL,
+    oper_name      nvarchar(50)   DEFAULT ''    NULL,
+    dept_name      nvarchar(50)   DEFAULT ''    NULL,
+    oper_url       nvarchar(255)  DEFAULT ''    NULL,
+    oper_ip        nvarchar(128)  DEFAULT ''    NULL,
+    oper_location  nvarchar(255)  DEFAULT ''    NULL,
+    oper_param     nvarchar(2000) DEFAULT ''    NULL,
+    json_result    nvarchar(2000) DEFAULT ''    NULL,
+    status         int            DEFAULT ((0)) NULL,
+    error_msg      nvarchar(2000) DEFAULT ''    NULL,
+    oper_time      datetime2(7)                 NULL,
+    cost_time      bigint         DEFAULT ((0)) NULL,
+    CONSTRAINT PK__sys_oper__34723BF9BD954573 PRIMARY KEY CLUSTERED (oper_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+CREATE NONCLUSTERED INDEX idx_sys_oper_log_bt ON sys_oper_log (business_type)
+GO
+CREATE NONCLUSTERED INDEX idx_sys_oper_log_s ON sys_oper_log (status)
+GO
+CREATE NONCLUSTERED INDEX idx_sys_oper_log_ot ON sys_oper_log (oper_time)
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏃ュ織涓婚敭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'妯″潡鏍囬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'title'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'business_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏂规硶鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'method'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璇锋眰鏂瑰紡' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'request_method'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'operator_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔浜哄憳' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'dept_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璇锋眰URL' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_url'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'涓绘満鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_ip'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔鍦扮偣' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_location'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'璇锋眰鍙傛暟' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_param'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'杩斿洖鍙傛暟' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'json_result'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閿欒娑堟伅' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'error_msg'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'oper_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'娑堣�楁椂闂�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log',
+    'COLUMN', N'cost_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎿嶄綔鏃ュ織璁板綍' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oper_log'
+GO
+
+CREATE TABLE sys_post
+(
+    post_id     bigint                          NOT NULL,
+    tenant_id   nvarchar(20) DEFAULT ('000000') NULL,
+    dept_id     bigint                          NOT NULL,
+    post_code   nvarchar(64)                    NOT NULL,
+    post_category nvarchar(100)                 NULL,
+    post_name   nvarchar(50)                    NOT NULL,
+    post_sort   int                             NOT NULL,
+    status      nchar(1)                        NOT NULL,
+    create_dept bigint                          NULL,
+    create_by   bigint                          NULL,
+    create_time datetime2(7)                    NULL,
+    update_by   bigint                          NULL,
+    update_time datetime2(7)                    NULL,
+    remark      nvarchar(500)                   NULL,
+    CONSTRAINT PK__sys_post__3ED7876668E2D081 PRIMARY KEY CLUSTERED (post_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'dept_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅缂栫爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅绫诲埆缂栫爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_category'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず椤哄簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_sort'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅淇℃伅琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post'
+GO
+
+INSERT sys_post VALUES (1, N'000000', 103, N'ceo', NULL,  N'钁d簨闀�', 1, N'0', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_post VALUES (2, N'000000', 100, N'se', NULL,  N'椤圭洰缁忕悊', 2, N'0', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_post VALUES (3, N'000000', 100, N'hr', NULL,  N'浜哄姏璧勬簮', 3, N'0', 103, 1, getdate(), NULL, NULL, N'')
+GO
+INSERT sys_post VALUES (4, N'000000', 100, N'user', NULL,  N'鏅�氬憳宸�', 4, N'0', 103, 1, getdate(), NULL, NULL, N'')
+GO
+
+CREATE TABLE sys_role
+(
+    role_id             bigint                     NOT NULL,
+    tenant_id           nvarchar(20) DEFAULT ('000000') NULL,
+    role_name           nvarchar(30)               NOT NULL,
+    role_key            nvarchar(100)              NOT NULL,
+    role_sort           int                        NOT NULL,
+    data_scope          nchar(1)     DEFAULT ('1') NULL,
+    menu_check_strictly tinyint      DEFAULT ((1)) NULL,
+    dept_check_strictly tinyint      DEFAULT ((1)) NULL,
+    status              nchar(1)                   NOT NULL,
+    del_flag            nchar(1)     DEFAULT ('0') NULL,
+    create_dept         bigint                     NULL,
+    create_by           bigint                     NULL,
+    create_time         datetime2(7)               NULL,
+    update_by           bigint                     NULL,
+    update_time         datetime2(7)               NULL,
+    remark              nvarchar(500)              NULL,
+    CONSTRAINT PK__sys_role__760965CCF9383145 PRIMARY KEY CLUSTERED (role_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'role_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊鍚嶇О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'role_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊鏉冮檺瀛楃涓�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'role_key'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏄剧ず椤哄簭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'role_sort'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'data_scope'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'menu_check_strictly'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'dept_check_strictly'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊淇℃伅琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role'
+GO
+
+INSERT sys_role VALUES (1, N'000000', N'瓒呯骇绠$悊鍛�', N'superadmin', 1, N'1', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'瓒呯骇绠$悊鍛�')
+GO
+INSERT sys_role VALUES (3, N'000000', N'鏈儴闂ㄥ強浠ヤ笅', N'test1', 3, N'4', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_role VALUES (4, N'000000', N'浠呮湰浜�', N'test2', 4, N'5', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'');
+GO
+
+CREATE TABLE sys_role_dept
+(
+    role_id bigint NOT NULL,
+    dept_id bigint NOT NULL,
+    CONSTRAINT PK__sys_role__2BC3005BABBCA08A PRIMARY KEY CLUSTERED (role_id, dept_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_dept',
+    'COLUMN', N'role_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_dept',
+    'COLUMN', N'dept_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_dept'
+GO
+
+CREATE TABLE sys_role_menu
+(
+    role_id bigint NOT NULL,
+    menu_id bigint NOT NULL,
+    CONSTRAINT PK__sys_role__A2C36A6187BA4B17 PRIMARY KEY CLUSTERED (role_id, menu_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_menu',
+    'COLUMN', N'role_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鑿滃崟ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_menu',
+    'COLUMN', N'menu_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊鍜岃彍鍗曞叧鑱旇〃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_role_menu'
+GO
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+INSERT sys_role_menu VALUES (3, 1);
+GO
+INSERT sys_role_menu VALUES (3, 5);
+GO
+INSERT sys_role_menu VALUES (3, 100);
+GO
+INSERT sys_role_menu VALUES (3, 101);
+GO
+INSERT sys_role_menu VALUES (3, 102);
+GO
+INSERT sys_role_menu VALUES (3, 103);
+GO
+INSERT sys_role_menu VALUES (3, 104);
+GO
+INSERT sys_role_menu VALUES (3, 105);
+GO
+INSERT sys_role_menu VALUES (3, 106);
+GO
+INSERT sys_role_menu VALUES (3, 107);
+GO
+INSERT sys_role_menu VALUES (3, 108);
+GO
+INSERT sys_role_menu VALUES (3, 500);
+GO
+INSERT sys_role_menu VALUES (3, 501);
+GO
+INSERT sys_role_menu VALUES (3, 1001);
+GO
+INSERT sys_role_menu VALUES (3, 1002);
+GO
+INSERT sys_role_menu VALUES (3, 1003);
+GO
+INSERT sys_role_menu VALUES (3, 1004);
+GO
+INSERT sys_role_menu VALUES (3, 1005);
+GO
+INSERT sys_role_menu VALUES (3, 1006);
+GO
+INSERT sys_role_menu VALUES (3, 1007);
+GO
+INSERT sys_role_menu VALUES (3, 1008);
+GO
+INSERT sys_role_menu VALUES (3, 1009);
+GO
+INSERT sys_role_menu VALUES (3, 1010);
+GO
+INSERT sys_role_menu VALUES (3, 1011);
+GO
+INSERT sys_role_menu VALUES (3, 1012);
+GO
+INSERT sys_role_menu VALUES (3, 1013);
+GO
+INSERT sys_role_menu VALUES (3, 1014);
+GO
+INSERT sys_role_menu VALUES (3, 1015);
+GO
+INSERT sys_role_menu VALUES (3, 1016);
+GO
+INSERT sys_role_menu VALUES (3, 1017);
+GO
+INSERT sys_role_menu VALUES (3, 1018);
+GO
+INSERT sys_role_menu VALUES (3, 1019);
+GO
+INSERT sys_role_menu VALUES (3, 1020);
+GO
+INSERT sys_role_menu VALUES (3, 1021);
+GO
+INSERT sys_role_menu VALUES (3, 1022);
+GO
+INSERT sys_role_menu VALUES (3, 1023);
+GO
+INSERT sys_role_menu VALUES (3, 1024);
+GO
+INSERT sys_role_menu VALUES (3, 1025);
+GO
+INSERT sys_role_menu VALUES (3, 1026);
+GO
+INSERT sys_role_menu VALUES (3, 1027);
+GO
+INSERT sys_role_menu VALUES (3, 1028);
+GO
+INSERT sys_role_menu VALUES (3, 1029);
+GO
+INSERT sys_role_menu VALUES (3, 1030);
+GO
+INSERT sys_role_menu VALUES (3, 1031);
+GO
+INSERT sys_role_menu VALUES (3, 1032);
+GO
+INSERT sys_role_menu VALUES (3, 1033);
+GO
+INSERT sys_role_menu VALUES (3, 1034);
+GO
+INSERT sys_role_menu VALUES (3, 1035);
+GO
+INSERT sys_role_menu VALUES (3, 1036);
+GO
+INSERT sys_role_menu VALUES (3, 1037);
+GO
+INSERT sys_role_menu VALUES (3, 1038);
+GO
+INSERT sys_role_menu VALUES (3, 1039);
+GO
+INSERT sys_role_menu VALUES (3, 1040);
+GO
+INSERT sys_role_menu VALUES (3, 1041);
+GO
+INSERT sys_role_menu VALUES (3, 1042);
+GO
+INSERT sys_role_menu VALUES (3, 1043);
+GO
+INSERT sys_role_menu VALUES (3, 1044);
+GO
+INSERT sys_role_menu VALUES (3, 1045);
+GO
+INSERT sys_role_menu VALUES (3, 1500);
+GO
+INSERT sys_role_menu VALUES (3, 1501);
+GO
+INSERT sys_role_menu VALUES (3, 1502);
+GO
+INSERT sys_role_menu VALUES (3, 1503);
+GO
+INSERT sys_role_menu VALUES (3, 1504);
+GO
+INSERT sys_role_menu VALUES (3, 1505);
+GO
+INSERT sys_role_menu VALUES (3, 1506);
+GO
+INSERT sys_role_menu VALUES (3, 1507);
+GO
+INSERT sys_role_menu VALUES (3, 1508);
+GO
+INSERT sys_role_menu VALUES (3, 1509);
+GO
+INSERT sys_role_menu VALUES (3, 1510);
+GO
+INSERT sys_role_menu VALUES (3, 1511);
+GO
+INSERT sys_role_menu VALUES (4, 5);
+GO
+INSERT sys_role_menu VALUES (4, 1500);
+GO
+INSERT sys_role_menu VALUES (4, 1501);
+GO
+INSERT sys_role_menu VALUES (4, 1502);
+GO
+INSERT sys_role_menu VALUES (4, 1503);
+GO
+INSERT sys_role_menu VALUES (4, 1504);
+GO
+INSERT sys_role_menu VALUES (4, 1505);
+GO
+INSERT sys_role_menu VALUES (4, 1506);
+GO
+INSERT sys_role_menu VALUES (4, 1507);
+GO
+INSERT sys_role_menu VALUES (4, 1508);
+GO
+INSERT sys_role_menu VALUES (4, 1509);
+GO
+INSERT sys_role_menu VALUES (4, 1510);
+GO
+INSERT sys_role_menu VALUES (4, 1511);
+GO
+
+CREATE TABLE sys_user
+(
+    user_id     bigint                             NOT NULL,
+    tenant_id   nvarchar(20)  DEFAULT ('000000')   NULL,
+    dept_id     bigint                             NULL,
+    user_name   nvarchar(30)                       NOT NULL,
+    nick_name   nvarchar(30)                       NOT NULL,
+    user_type   nvarchar(10)  DEFAULT ('sys_user') NULL,
+    email       nvarchar(50)  DEFAULT ''           NULL,
+    phonenumber nvarchar(11)  DEFAULT ''           NULL,
+    sex         nchar(1)      DEFAULT ('0')        NULL,
+    avatar      bigint                             NULL,
+    password    nvarchar(100) DEFAULT ''           NULL,
+    status      nchar(1)      DEFAULT ('0')        NULL,
+    del_flag    nchar(1)      DEFAULT ('0')        NULL,
+    login_ip    nvarchar(128) DEFAULT ''           NULL,
+    login_date  datetime2(7)                       NULL,
+    create_dept bigint                             NULL,
+    create_by   bigint                             NULL,
+    create_time datetime2(7)                       NULL,
+    update_by   bigint                             NULL,
+    update_time datetime2(7)                       NULL,
+    remark      nvarchar(500)                      NULL,
+    CONSTRAINT PK__sys_user__B9BE370F79170B6A PRIMARY KEY CLUSTERED (user_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'user_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'dept_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛璐﹀彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'user_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏄电О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'nick_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'user_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛閭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'email'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎵嬫満鍙风爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'phonenumber'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'sex'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶村儚鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'avatar'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀵嗙爜' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'password'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'status'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏈�鍚庣櫥褰旾P' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'login_ip'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏈�鍚庣櫥褰曟椂闂�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'login_date'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'update_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶囨敞' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user',
+    'COLUMN', N'remark'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛淇℃伅琛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user'
+GO
+
+INSERT sys_user VALUES (1, N'000000', 103,  N'admin', N'鐤媯鐨勭嫯瀛怢i', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'绠$悊鍛�')
+GO
+INSERT sys_user VALUES (3, N'000000', 108, N'test', N'鏈儴闂ㄥ強浠ヤ笅 瀵嗙爜666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 3, getdate(), NULL);
+GO
+INSERT sys_user VALUES (4, N'000000', 102, N'test1', N'浠呮湰浜� 瀵嗙爜666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 4, getdate(), NULL);
+GO
+
+CREATE TABLE sys_user_post
+(
+    user_id bigint NOT NULL,
+    post_id bigint NOT NULL,
+    CONSTRAINT PK__sys_user__CA534F799C04589B PRIMARY KEY CLUSTERED (user_id, post_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_post',
+    'COLUMN', N'user_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'宀椾綅ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_post',
+    'COLUMN', N'post_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_post'
+GO
+
+INSERT sys_user_post VALUES (1, 1)
+GO
+
+CREATE TABLE sys_user_role
+(
+    user_id bigint NOT NULL,
+    role_id bigint NOT NULL,
+    CONSTRAINT PK__sys_user__6EDEA153FB34D8F0 PRIMARY KEY CLUSTERED (user_id, role_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_role',
+    'COLUMN', N'user_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瑙掕壊ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_role',
+    'COLUMN', N'role_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鍜岃鑹插叧鑱旇〃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_user_role'
+GO
+
+INSERT sys_user_role VALUES (1, 1)
+GO
+INSERT sys_user_role VALUES (3, 3);
+GO
+INSERT sys_user_role VALUES (4, 4);
+GO
+
+CREATE TABLE sys_oss
+(
+    oss_id        bigint                          NOT NULL,
+    tenant_id     nvarchar(20)  DEFAULT ('000000') NULL,
+    file_name     nvarchar(255) DEFAULT ''        NOT NULL,
+    original_name nvarchar(255) DEFAULT ''        NOT NULL,
+    file_suffix   nvarchar(10)  DEFAULT ''        NOT NULL,
+    url           nvarchar(500)                   NOT NULL,
+    create_dept   bigint                          NULL,
+    create_time   datetime2(7)                    NULL,
+    create_by     bigint                          NULL,
+    update_time   datetime2(7)                    NULL,
+    update_by     bigint                          NULL,
+    service       nvarchar(20)  DEFAULT ('minio') NOT NULL,
+    CONSTRAINT PK__sys_oss__91241EA442389F0D PRIMARY KEY CLUSTERED (oss_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'瀵硅薄瀛樺偍涓婚敭',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'oss_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏂囦欢鍚�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'file_name'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍘熷悕',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'original_name'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏂囦欢鍚庣紑鍚�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'file_suffix'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'URL鍦板潃',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'url'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'create_dept'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'create_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'涓婁紶浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'create_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'update_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'update_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏈嶅姟鍟�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss',
+    'COLUMN', N'service'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'OSS瀵硅薄瀛樺偍琛�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss'
+GO
+
+CREATE TABLE sys_oss_config
+(
+    oss_config_id bigint                      NOT NULL,
+    tenant_id     nvarchar(20)  DEFAULT ('000000') NULL,
+    config_key    nvarchar(20)  DEFAULT ''    NOT NULL,
+    access_key    nvarchar(255) DEFAULT ''    NULL,
+    secret_key    nvarchar(255) DEFAULT ''    NULL,
+    bucket_name   nvarchar(255) DEFAULT ''    NULL,
+    prefix        nvarchar(255) DEFAULT ''    NULL,
+    endpoint      nvarchar(255) DEFAULT ''    NULL,
+    domain        nvarchar(255) DEFAULT ''    NULL,
+    is_https      nchar(1)      DEFAULT ('N') NULL,
+    region        nvarchar(255) DEFAULT ''    NULL,
+    access_policy nchar(1)      DEFAULT ('1') NOT NULL,
+    status        nchar(1)      DEFAULT ('1') NULL,
+    ext1          nvarchar(255) DEFAULT ''    NULL,
+    create_dept   bigint                      NULL,
+    create_by     bigint                      NULL,
+    create_time   datetime2(7)                NULL,
+    update_by     bigint                      NULL,
+    update_time   datetime2(7)                NULL,
+    remark        nvarchar(500)               NULL,
+    CONSTRAINT PK__sys_oss___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (oss_config_id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'涓婚敭',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'oss_config_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛缂栧彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'閰嶇疆key',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'config_key'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'accessKey',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'access_key'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'绉橀挜',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'secret_key'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'妗跺悕绉�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'bucket_name'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍓嶇紑',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'prefix'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'璁块棶绔欑偣',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'endpoint'
+GO
+EXEC sp_addextendedproperty
+     'MS_Description', N'鑷畾涔夊煙鍚�',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sys_oss_config',
+     'COLUMN', N'domain'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏄惁https锛圷=鏄�,N=鍚︼級',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'is_https'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍩�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'region'
+GO
+EXEC sp_addextendedproperty
+     'MS_Description', N'妗舵潈闄愮被鍨�(0=private 1=public 2=custom)',
+     'SCHEMA', N'dbo',
+     'TABLE', N'sys_oss_config',
+     'COLUMN', N'access_policy'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏄惁榛樿锛�0=鏄�,1=鍚︼級',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'status'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鎵╁睍瀛楁',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'ext1'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'create_dept'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'create_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'create_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'update_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'update_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'澶囨敞',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config',
+    'COLUMN', N'remark'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'瀵硅薄瀛樺偍閰嶇疆琛�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_oss_config'
+GO
+
+INSERT INTO sys_oss_config VALUES (N'1', N'000000', N'minio', N'ruoyi',            N'ruoyi123',        N'ruoyi',            N'', N'127.0.0.1:9000',                    N'',N'N', N'',           N'1', N'0', N'', 103, 1, getdate(), 1, getdate(), NULL)
+GO
+INSERT INTO sys_oss_config VALUES (N'2', N'000000', N'qiniu', N'XXXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi',            N'', N's3-cn-north-1.qiniucs.com',         N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
+GO
+INSERT INTO sys_oss_config VALUES (N'3', N'000000', N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi',            N'', N'oss-cn-beijing.aliyuncs.com',       N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
+GO
+INSERT INTO sys_oss_config VALUES (N'4', N'000000', N'qcloud', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi-1250000000', N'', N'cos.ap-beijing.myqcloud.com',       N'',N'N', N'ap-beijing', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
+GO
+INSERT INTO sys_oss_config VALUES (N'5', N'000000', N'image',  N'ruoyi',           N'ruoyi123',        N'ruoyi',            N'image', N'127.0.0.1:9000',               N'',N'N', N'',           N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL)
+GO
+
+
+CREATE TABLE sys_client
+(
+    id                  bigint                              NOT NULL,
+    client_id           nvarchar(64)  DEFAULT ''            NULL,
+    client_key          nvarchar(32) DEFAULT ''            NULL,
+    client_secret       nvarchar(255) DEFAULT ''            NULL,
+    grant_type          nvarchar(255) DEFAULT ''            NULL,
+    device_type         nvarchar(32) DEFAULT ''            NULL,
+    active_timeout      int           DEFAULT ((1800))      NULL,
+    timeout             int           DEFAULT ((604800))    NULL,
+    status              nchar(1)      DEFAULT ('0')         NULL,
+    del_flag            nchar(1)      DEFAULT ('0')         NULL,
+    create_dept         bigint                              NULL,
+    create_by           bigint                              NULL,
+    create_time         datetime2(7)                        NULL,
+    update_by           bigint                              NULL,
+    update_time         datetime2(7)                        NULL
+    CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'涓婚敭',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'瀹㈡埛绔痠d' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'client_id'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'瀹㈡埛绔痥ey',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'client_key'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'瀹㈡埛绔閽�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'client_secret'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鎺堟潈绫诲瀷',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'grant_type'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'璁惧绫诲瀷',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'device_type'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'token娲昏穬瓒呮椂鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'active_timeout'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'token鍥哄畾瓒呮椂',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'timeout'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'status'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'create_dept'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'create_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'create_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'update_by'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client',
+    'COLUMN', N'update_time'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'绯荤粺鎺堟潈琛�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_client'
+GO
+
+INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate())
+GO
+INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate())
+GO
+
+CREATE TABLE test_demo
+(
+    id          bigint            NOT NULL,
+    tenant_id   nvarchar(20)      DEFAULT ('000000') NULL,
+    dept_id     bigint            NULL,
+    user_id     bigint            NULL,
+    order_num   int DEFAULT ((0)) NULL,
+    test_key    nvarchar(255)     NULL,
+    value       nvarchar(255)     NULL,
+    version     int DEFAULT ((0)) NULL,
+    create_dept bigint            NULL,
+    create_time datetime2(0)      NULL,
+    create_by   bigint            NULL,
+    update_time datetime2(0)      NULL,
+    update_by   bigint            NULL,
+    del_flag    int DEFAULT ((0)) NULL,
+    CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'涓婚敭',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'绉熸埛id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'dept_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'user_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鎺掑簭鍙�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'order_num'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'key閿�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'test_key'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍊�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'value'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐗堟湰',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'version'
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'create_dept'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'update_by'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo',
+    'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'娴嬭瘯鍗曡〃',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_demo'
+GO
+
+CREATE TABLE test_tree
+(
+    id          bigint               NOT NULL,
+    tenant_id   nvarchar(20)         DEFAULT ('000000') NULL,
+    parent_id   bigint DEFAULT ((0)) NULL,
+    dept_id     bigint               NULL,
+    user_id     bigint               NULL,
+    tree_name   nvarchar(255)        NULL,
+    version     int    DEFAULT ((0)) NULL,
+    create_dept bigint               NULL,
+    create_time datetime2(0)         NULL,
+    create_by   bigint               NULL,
+    update_time datetime2(0)         NULL,
+    update_by   bigint               NULL,
+    del_flag    int    DEFAULT ((0)) NULL,
+    CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'涓婚敭',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'绉熸埛id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'tenant_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐖秈d',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'parent_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'dept_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'user_id'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍊�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'tree_name'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鐗堟湰',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'version'
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'create_dept'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'create_time'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒涘缓浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'create_by'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'update_time'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏇存柊浜�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'update_by'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree',
+    'COLUMN', N'del_flag'
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'娴嬭瘯鏍戣〃',
+    'SCHEMA', N'dbo',
+    'TABLE', N'test_tree'
+GO
+
+INSERT test_demo VALUES (1, N'000000', 102, 4, 1, N'娴嬭瘯鏁版嵁鏉冮檺', N'娴嬭瘯', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (2, N'000000', 102, 3, 2, N'瀛愯妭鐐�1', N'111', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (3, N'000000', 102, 3, 3, N'瀛愯妭鐐�2', N'222', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (4, N'000000', 108, 4, 4, N'娴嬭瘯鏁版嵁', N'demo', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (5, N'000000', 108, 3, 13, N'瀛愯妭鐐�11', N'1111', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (6, N'000000', 108, 3, 12, N'瀛愯妭鐐�22', N'2222', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (7, N'000000', 108, 3, 11, N'瀛愯妭鐐�33', N'3333', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (8, N'000000', 108, 3, 10, N'瀛愯妭鐐�44', N'4444', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (9, N'000000', 108, 3, 9, N'瀛愯妭鐐�55', N'5555', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (10, N'000000', 108, 3, 8, N'瀛愯妭鐐�66', N'6666', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (11, N'000000', 108, 3, 7, N'瀛愯妭鐐�77', N'7777', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (12, N'000000', 108, 3, 6, N'瀛愯妭鐐�88', N'8888', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_demo VALUES (13, N'000000', 108, 3, 5, N'瀛愯妭鐐�99', N'9999', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+
+INSERT test_tree VALUES (1, N'000000', 0, 102, 4, N'娴嬭瘯鏁版嵁鏉冮檺', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (2, N'000000', 1, 102, 3, N'瀛愯妭鐐�1', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (3, N'000000', 2, 102, 3, N'瀛愯妭鐐�2', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (4, N'000000', 0, 108, 4, N'娴嬭瘯鏍�1', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (5, N'000000', 4, 108, 3, N'瀛愯妭鐐�11', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (6, N'000000', 4, 108, 3, N'瀛愯妭鐐�22', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (7, N'000000', 4, 108, 3, N'瀛愯妭鐐�33', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (8, N'000000', 5, 108, 3, N'瀛愯妭鐐�44', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (9, N'000000', 6, 108, 3, N'瀛愯妭鐐�55', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (10, N'000000', 7, 108, 3, N'瀛愯妭鐐�66', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (11, N'000000', 7, 108, 3, N'瀛愯妭鐐�77', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (12, N'000000', 10, 108, 3, N'瀛愯妭鐐�88', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
+INSERT test_tree VALUES (13, N'000000', 10, 108, 3, N'瀛愯妭鐐�99', 0, 103, getdate(), 1, NULL, NULL, 0);
+GO
diff --git a/eims/script/sql/update/oracle/update_5.0-5.1.sql b/eims/script/sql/update/oracle/update_5.0-5.1.sql
new file mode 100644
index 0000000..09cfae8
--- /dev/null
+++ b/eims/script/sql/update/oracle/update_5.0-5.1.sql
@@ -0,0 +1,151 @@
+ALTER TABLE gen_table ADD (data_name VARCHAR2(200) DEFAULT '');
+
+COMMENT ON COLUMN gen_table.data_name IS '鏁版嵁婧愬悕绉�';
+
+UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;
+
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+create table sys_social
+(
+    id                 number(20)       not null,
+    user_id            number(20)       not null,
+    tenant_id          varchar2(20)      default null,
+    auth_id            varchar2(255)     not null,
+    source             varchar2(255)     not null,
+    open_id            varchar2(255)     default null,
+    user_name          varchar2(30)      not null,
+    nick_name          varchar2(30)      default '',
+    email              varchar2(255)     default '',
+    avatar             varchar2(500)     default '',
+    access_token       varchar2(255)     not null,
+    expire_in          number(20)        default null,
+    refresh_token      varchar2(255)     default null,
+    access_code        varchar2(255)     default null,
+    union_id           varchar2(255)     default null,
+    scope              varchar2(255)     default null,
+    token_type         varchar2(255)     default null,
+    id_token           varchar2(255)     default null,
+    mac_algorithm      varchar2(255)     default null,
+    mac_key            varchar2(255)     default null,
+    code               varchar2(255)     default null,
+    oauth_token        varchar2(255)     default null,
+    oauth_token_secret varchar2(255)     default null,
+    create_dept        number(20),
+    create_by          number(20),
+    create_time        date,
+    update_by          number(20),
+    update_time        date,
+    del_flag           char(1)          default '0'
+);
+
+alter table sys_social add constraint pk_sys_social primary key (id);
+
+comment on table   sys_social                   is '绀句細鍖栧叧绯昏〃';
+comment on column  sys_social.id                is '涓婚敭';
+comment on column  sys_social.user_id           is '鐢ㄦ埛ID';
+comment on column  sys_social.tenant_id         is '绉熸埛id';
+comment on column  sys_social.auth_id           is '骞冲彴+骞冲彴鍞竴id';
+comment on column  sys_social.source            is '鐢ㄦ埛鏉ユ簮';
+comment on column  sys_social.open_id           is '骞冲彴缂栧彿鍞竴id';
+comment on column  sys_social.user_name         is '鐧诲綍璐﹀彿';
+comment on column  sys_social.nick_name         is '鐢ㄦ埛鏄电О';
+comment on column  sys_social.email             is '鐢ㄦ埛閭';
+comment on column  sys_social.avatar            is '澶村儚鍦板潃';
+comment on column  sys_social.access_token      is '鐢ㄦ埛鐨勬巿鏉冧护鐗�';
+comment on column  sys_social.expire_in         is '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.refresh_token     is '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.access_code       is '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.union_id          is '鐢ㄦ埛鐨� unionid';
+comment on column  sys_social.scope             is '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.token_type        is '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.id_token          is 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.mac_algorithm     is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.mac_key           is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.code              is '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.oauth_token       is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.oauth_token_secret is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column  sys_social.create_by         is '鍒涘缓鑰�';
+comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
+comment on column  sys_social.update_by         is '鏇存柊鑰�';
+comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+create table sys_client (
+    id                  number(20)    not null,
+    client_id           varchar2(64)   default null,
+    client_key          varchar2(32)   default null,
+    client_secret       varchar2(255)  default null,
+    grant_type          varchar2(255)  default null,
+    device_type         varchar2(32)   default null,
+    active_timeout      number(11)    default 1800,
+    timeout             number(11)    default 604800,
+    status              char(1)       default '0',
+    del_flag            char(1)       default '0',
+    create_dept         number(20)    default null,
+    create_by           number(20)    default null,
+    create_time         date,
+    update_by           number(20)    default null,
+    update_time         date
+);
+
+alter table sys_client add constraint pk_sys_client primary key (id);
+
+comment on table sys_client                         is '绯荤粺鎺堟潈琛�';
+comment on column sys_client.id                     is '涓婚敭';
+comment on column sys_client.client_id              is '瀹㈡埛绔痠d';
+comment on column sys_client.client_key             is '瀹㈡埛绔痥ey';
+comment on column sys_client.client_secret          is '瀹㈡埛绔閽�';
+comment on column sys_client.grant_type             is '鎺堟潈绫诲瀷';
+comment on column sys_client.device_type            is '璁惧绫诲瀷';
+comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
+comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
+comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
+comment on column sys_client.create_by              is '鍒涘缓鑰�';
+comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
+comment on column sys_client.update_by              is '鏇存柊鑰�';
+comment on column sys_client.update_time            is '鏇存柊鏃堕棿';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate);
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate);
+
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     '0', 103, 1, sysdate, null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    '0', 103, 1, sysdate, null, null, '瀹㈡埛绔澶囩被鍨�');
+
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   '',   'default', 'N', '0', 103, 1, sysdate, null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   '',   'default', 'N', '0', 103, 1, sysdate, null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   '',   'default', 'N', '0', 103, 1, sysdate, null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   '',   'default', 'N', '0', 103, 1, sysdate, null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   '',   'default', 'N', '0', 103, 1, sysdate, null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC',      'pc',          'sys_device_type',  '',   'default', 'N', '0', 103, 1, sysdate, null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜',     'android',    'sys_device_type',  '',   'default', 'N', '0', 103, 1, sysdate, null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS',     'ios',         'sys_device_type',  '',   'default', 'N', '0', 103, 1, sysdate, null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�',     'xcx',      'sys_device_type',  '',   'default', 'N', '0', 103, 1, sysdate, null, null, '灏忕▼搴�');
+
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', 1, 0, 'C', '0', '0', 'system:client:list',          'international', 103, 1, sysdate, null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query',        '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add',          '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit',         '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove',       '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export',       '#', 103, 1, sysdate, null, null, '');
+
+-- 瑙掕壊鑿滃崟鏉冮檺
+insert into sys_role_menu values ('2', '1061');
+insert into sys_role_menu values ('2', '1062');
+insert into sys_role_menu values ('2', '1063');
+insert into sys_role_menu values ('2', '1064');
+insert into sys_role_menu values ('2', '1065');
+
+
+update sys_dept set leader = null;
+ALTER TABLE sys_dept MODIFY (leader NUMBER(20))
diff --git a/eims/script/sql/update/oracle/update_5.1.0-5.1.1.sql b/eims/script/sql/update/oracle/update_5.1.0-5.1.1.sql
new file mode 100644
index 0000000..979a4bd
--- /dev/null
+++ b/eims/script/sql/update/oracle/update_5.1.0-5.1.1.sql
@@ -0,0 +1,5 @@
+ALTER TABLE sys_logininfor ADD (client_key varchar2(32) DEFAULT '');
+COMMENT ON COLUMN sys_logininfor.client_key IS '瀹㈡埛绔�';
+
+ALTER TABLE sys_logininfor ADD (device_type varchar2(32) DEFAULT '');
+COMMENT ON COLUMN sys_logininfor.device_type IS '璁惧绫诲瀷';
diff --git a/eims/script/sql/update/oracle/update_5.1.1-5.1.2.sql b/eims/script/sql/update/oracle/update_5.1.1-5.1.2.sql
new file mode 100644
index 0000000..d7c030c
--- /dev/null
+++ b/eims/script/sql/update/oracle/update_5.1.1-5.1.2.sql
@@ -0,0 +1,6 @@
+delete from sys_menu where menu_id in (1604, 1605);
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add',    '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit',   '#', 103, 1, sysdate, null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate, null, null, '');
+
diff --git a/eims/script/sql/update/oracle/update_5.1.2-5.2.0.sql b/eims/script/sql/update/oracle/update_5.1.2-5.2.0.sql
new file mode 100644
index 0000000..1aa585a
--- /dev/null
+++ b/eims/script/sql/update/oracle/update_5.1.2-5.2.0.sql
@@ -0,0 +1,9 @@
+ALTER TABLE sys_dept ADD (dept_category varchar2(100) DEFAULT NULL) COMMENT '閮ㄩ棬绫诲埆缂栫爜';
+COMMENT ON COLUMN sys_dept.dept_category IS '閮ㄩ棬绫诲埆缂栫爜';
+ALTER TABLE sys_post ADD (dept_id number(20) NOT NULL) COMMENT '閮ㄩ棬id';
+COMMENT ON COLUMN sys_post.dept_id IS '閮ㄩ棬id';
+ALTER TABLE sys_post ADD (post_category VARCHAR2(100) DEFAULT NULL) COMMENT '宀椾綅绫诲埆缂栫爜';
+COMMENT ON COLUMN sys_post.post_category IS '宀椾綅绫诲埆缂栫爜';
+UPDATE sys_post SET dept_id = 100;
+UPDATE sys_post SET dept_id = 103 where post_id = 1;
+UPDATE sys_menu SET menu_name = 'SnailJob鎺у埗鍙�', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;
diff --git a/eims/script/sql/update/postgres/update_5.0-5.1.sql b/eims/script/sql/update/postgres/update_5.0-5.1.sql
new file mode 100644
index 0000000..f5f0a5c
--- /dev/null
+++ b/eims/script/sql/update/postgres/update_5.0-5.1.sql
@@ -0,0 +1,150 @@
+ALTER TABLE gen_table ADD data_name varchar(200) default ''::varchar;
+
+COMMENT ON COLUMN gen_table.data_name IS '鏁版嵁婧愬悕绉�';
+
+UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;
+
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+create table sys_social
+(
+    id                 int8             not null,
+    user_id            int8             not null,
+    tenant_id          varchar(20)      default null::varchar,
+    auth_id            varchar(255)     not null,
+    source             varchar(255)     not null,
+    open_id            varchar(255)     default null::varchar,
+    user_name          varchar(30)      not null,
+    nick_name          varchar(30)      default ''::varchar,
+    email              varchar(255)     default ''::varchar,
+    avatar             varchar(500)     default ''::varchar,
+    access_token       varchar(255)     not null,
+    expire_in          int8             default null,
+    refresh_token      varchar(255)     default null::varchar,
+    access_code        varchar(255)     default null::varchar,
+    union_id           varchar(255)     default null::varchar,
+    scope              varchar(255)     default null::varchar,
+    token_type         varchar(255)     default null::varchar,
+    id_token           varchar(255)     default null::varchar,
+    mac_algorithm      varchar(255)     default null::varchar,
+    mac_key            varchar(255)     default null::varchar,
+    code               varchar(255)     default null::varchar,
+    oauth_token        varchar(255)     default null::varchar,
+    oauth_token_secret varchar(255)     default null::varchar,
+    create_dept        int8,
+    create_by          int8,
+    create_time        timestamp,
+    update_by          int8,
+    update_time        timestamp,
+    del_flag           char             default '0'::bpchar,
+    constraint "pk_sys_social" primary key (id)
+);
+
+comment on table   sys_social                   is '绀句細鍖栧叧绯昏〃';
+comment on column  sys_social.id                is '涓婚敭';
+comment on column  sys_social.user_id           is '鐢ㄦ埛ID';
+comment on column  sys_social.tenant_id         is '绉熸埛id';
+comment on column  sys_social.auth_id           is '骞冲彴+骞冲彴鍞竴id';
+comment on column  sys_social.source            is '鐢ㄦ埛鏉ユ簮';
+comment on column  sys_social.open_id           is '骞冲彴缂栧彿鍞竴id';
+comment on column  sys_social.user_name         is '鐧诲綍璐﹀彿';
+comment on column  sys_social.nick_name         is '鐢ㄦ埛鏄电О';
+comment on column  sys_social.email             is '鐢ㄦ埛閭';
+comment on column  sys_social.avatar            is '澶村儚鍦板潃';
+comment on column  sys_social.access_token      is '鐢ㄦ埛鐨勬巿鏉冧护鐗�';
+comment on column  sys_social.expire_in         is '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.refresh_token     is '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.access_code       is '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.union_id          is '鐢ㄦ埛鐨� unionid';
+comment on column  sys_social.scope             is '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.token_type        is '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.id_token          is 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.mac_algorithm     is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.mac_key           is '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.code              is '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�';
+comment on column  sys_social.oauth_token       is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.oauth_token_secret is 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁';
+comment on column  sys_social.create_dept       is '鍒涘缓閮ㄩ棬';
+comment on column  sys_social.create_by         is '鍒涘缓鑰�';
+comment on column  sys_social.create_time       is '鍒涘缓鏃堕棿';
+comment on column  sys_social.update_by         is '鏇存柊鑰�';
+comment on column  sys_social.update_time       is '鏇存柊鏃堕棿';
+comment on column  sys_social.del_flag          is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+drop table if exists sys_client;
+create table sys_client (
+    id                  int8,
+    client_id           varchar(64)   default ''::varchar,
+    client_key          varchar(32)   default ''::varchar,
+    client_secret       varchar(255)  default ''::varchar,
+    grant_type          varchar(255)  default ''::varchar,
+    device_type         varchar(32)   default ''::varchar,
+    active_timeout      int4          default 1800,
+    timeout             int4          default 604800,
+    status              char(1)       default '0'::bpchar,
+    del_flag            char(1)       default '0'::bpchar,
+    create_dept         int8,
+    create_by           int8,
+    create_time         timestamp,
+    update_by           int8,
+    update_time         timestamp,
+    constraint sys_client_pk primary key (id)
+);
+
+comment on table sys_client                         is '绯荤粺鎺堟潈琛�';
+comment on column sys_client.id                     is '涓婚敭';
+comment on column sys_client.client_id              is '瀹㈡埛绔痠d';
+comment on column sys_client.client_key             is '瀹㈡埛绔痥ey';
+comment on column sys_client.client_secret          is '瀹㈡埛绔閽�';
+comment on column sys_client.grant_type             is '鎺堟潈绫诲瀷';
+comment on column sys_client.device_type            is '璁惧绫诲瀷';
+comment on column sys_client.active_timeout         is 'token娲昏穬瓒呮椂鏃堕棿';
+comment on column sys_client.timeout                is 'token鍥哄畾瓒呮椂';
+comment on column sys_client.status                 is '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+comment on column sys_client.del_flag               is '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+comment on column sys_client.create_dept            is '鍒涘缓閮ㄩ棬';
+comment on column sys_client.create_by              is '鍒涘缓鑰�';
+comment on column sys_client.create_time            is '鍒涘缓鏃堕棿';
+comment on column sys_client.update_by              is '鏇存柊鑰�';
+comment on column sys_client.update_time            is '鏇存柊鏃堕棿';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now());
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now());
+
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     '0', 103, 1, now(), null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    '0', 103, 1, now(), null, null, '瀹㈡埛绔澶囩被鍨�');
+
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC', 'pc',              'sys_device_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜', 'android',       'sys_device_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS', 'ios',            'sys_device_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�', 'xcx',         'sys_device_type',   '',   'default', 'N', '0', 103, 1, now(), null, null, '灏忕▼搴�');
+
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', '1', '0', 'C', '0', '0', 'system:client:list',          'international', 103, 1, now(), null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query',        '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add',          '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit',         '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove',       '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export',       '#', 103, 1, now(), null, null, '');
+
+-- 瑙掕壊鑿滃崟鏉冮檺
+insert into sys_role_menu values ('2', '1061');
+insert into sys_role_menu values ('2', '1062');
+insert into sys_role_menu values ('2', '1063');
+insert into sys_role_menu values ('2', '1064');
+insert into sys_role_menu values ('2', '1065');
+
+
+update sys_dept set leader = null;
+ALTER TABLE sys_dept ALTER COLUMN leader TYPE int8;
diff --git a/eims/script/sql/update/postgres/update_5.1.0-5.1.1.sql b/eims/script/sql/update/postgres/update_5.1.0-5.1.1.sql
new file mode 100644
index 0000000..29f5507
--- /dev/null
+++ b/eims/script/sql/update/postgres/update_5.1.0-5.1.1.sql
@@ -0,0 +1,5 @@
+ALTER TABLE sys_logininfor ADD client_key varchar(32) default ''::varchar;
+COMMENT ON COLUMN sys_logininfor.client_key IS '瀹㈡埛绔�';
+
+ALTER TABLE sys_logininfor ADD device_type varchar(32) default ''::varchar;
+COMMENT ON COLUMN sys_logininfor.device_type IS '璁惧绫诲瀷';
diff --git a/eims/script/sql/update/postgres/update_5.1.1-5.1.2.sql b/eims/script/sql/update/postgres/update_5.1.1-5.1.2.sql
new file mode 100644
index 0000000..62eb836
--- /dev/null
+++ b/eims/script/sql/update/postgres/update_5.1.1-5.1.2.sql
@@ -0,0 +1,5 @@
+delete from sys_menu where menu_id in (1604, 1605);
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add',    '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit',   '#', 103, 1, now(), null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, '');
diff --git a/eims/script/sql/update/postgres/update_5.1.2-5.2.0.sql b/eims/script/sql/update/postgres/update_5.1.2-5.2.0.sql
new file mode 100644
index 0000000..5089a09
--- /dev/null
+++ b/eims/script/sql/update/postgres/update_5.1.2-5.2.0.sql
@@ -0,0 +1,9 @@
+ALTER TABLE sys_dept ADD COLUMN dept_category varchar(100) default null::varchar;
+COMMENT ON COLUMN sys_dept.dept_category IS '瀹㈡埛绔�';
+ALTER TABLE sys_post ADD COLUMN dept_id int8 NOT NULL;
+COMMENT ON COLUMN sys_post.dept_id IS '閮ㄩ棬id';
+ALTER TABLE sys_post ADD COLUMN post_category varchar(100) default null::varchar;
+COMMENT ON COLUMN sys_post.post_category IS '宀椾綅绫诲埆缂栫爜';
+UPDATE sys_post SET dept_id = 100;
+UPDATE sys_post SET dept_id = 103 where post_id = 1;
+UPDATE sys_menu SET menu_name = 'SnailJob鎺у埗鍙�', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;
diff --git a/eims/script/sql/update/sqlserver/update_5.0-5.1.sql b/eims/script/sql/update/sqlserver/update_5.0-5.1.sql
new file mode 100644
index 0000000..bde3813
--- /dev/null
+++ b/eims/script/sql/update/sqlserver/update_5.0-5.1.sql
@@ -0,0 +1,409 @@
+ALTER TABLE gen_table ADD data_name nvarchar(200) DEFAULT '' NULL
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'鏁版嵁婧愬悕绉�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'gen_table',
+    'COLUMN', N'data_name'
+GO
+
+UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120
+GO
+
+create table sys_social
+(
+    id                 bigint            NOT NULL,
+    user_id            bigint            NOT NULL,
+    tenant_id          nvarchar(20)      NULL,
+    auth_id            nvarchar(255)     NOT NULL,
+    source             nvarchar(255)     NOT NULL,
+    open_id            nvarchar(255)     NULL,
+    user_name          nvarchar(30)      NOT NULL,
+    nick_name          nvarchar(30)      DEFAULT ('')   NULL,
+    email              nvarchar(255)     DEFAULT ('')   NULL,
+    avatar             nvarchar(500)     DEFAULT ('')   NULL,
+    access_token       nvarchar(255)     NOT NULL,
+    expire_in          bigint            NULL,
+    refresh_token      nvarchar(255)     NULL,
+    access_code        nvarchar(255)     NULL,
+    union_id           nvarchar(255)     NULL,
+    scope              nvarchar(255)     NULL,
+    token_type         nvarchar(255)     NULL,
+    id_token           nvarchar(255)     NULL,
+    mac_algorithm      nvarchar(255)     NULL,
+    mac_key            nvarchar(255)     NULL,
+    code               nvarchar(255)     NULL,
+    oauth_token        nvarchar(255)     NULL,
+    oauth_token_secret nvarchar(255)     NULL,
+    create_dept        bigint,
+    create_by          bigint,
+    create_time        datetime2(7),
+    update_by          bigint,
+    update_time        datetime2(7),
+    del_flag           nchar             DEFAULT ('0')   NULL,
+    CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛ID' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'user_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'绉熸埛id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'tenant_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴+骞冲彴鍞竴id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'auth_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏉ユ簮' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'source'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴缂栧彿鍞竴id' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'open_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐧诲綍璐﹀彿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'user_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鏄电О' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'nick_name'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛閭' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'email'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'澶村儚鍦板潃' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'avatar'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉冧护鐗�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'access_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'expire_in'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'refresh_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'access_code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨� unionid' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'union_id'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'scope'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'token_type'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'id_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'mac_algorithm'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'mac_key'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'code'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'oauth_token'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'oauth_token_secret'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_dept'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鍒涘缓鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'create_time'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鑰�' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'update_by'
+GO
+EXEC sys.sp_addextendedproperty
+    'MS_Description', N'鏇存柊鏃堕棿' ,
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_social',
+    'COLUMN', N'update_time'
+GO
+
+
+CREATE TABLE sys_client
+(
+    id                  bigint                              NOT NULL,
+    client_id           nvarchar(64)  DEFAULT ''            NULL,
+    client_key          nvarchar(32) DEFAULT ''            NULL,
+    client_secret       nvarchar(255) DEFAULT ''            NULL,
+    grant_type          nvarchar(255) DEFAULT ''            NULL,
+    device_type         nvarchar(32) DEFAULT ''            NULL,
+    active_timeout      int           DEFAULT ((1800))      NULL,
+    timeout             int           DEFAULT ((604800))    NULL,
+    status              nchar(1)      DEFAULT ('0')         NULL,
+    del_flag            nchar(1)      DEFAULT ('0')         NULL,
+    create_dept         bigint                              NULL,
+    create_by           bigint                              NULL,
+    create_time         datetime2(7)                        NULL,
+    update_by           bigint                              NULL,
+    update_time         datetime2(7)                        NULL
+    CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id)
+        WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
+        ON [PRIMARY]
+)
+ON [PRIMARY]
+GO
+
+EXEC sp_addextendedproperty
+'MS_Description', N'涓婚敭',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'id'
+GO
+EXEC sys.sp_addextendedproperty
+'MS_Description', N'瀹㈡埛绔痠d' ,
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'client_id'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹㈡埛绔痥ey',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'client_key'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'瀹㈡埛绔閽�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'client_secret'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鎺堟潈绫诲瀷',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'grant_type'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'璁惧绫诲瀷',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'device_type'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'token娲昏穬瓒呮椂鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'active_timeout'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'token鍥哄畾瓒呮椂',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'timeout'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'status'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'del_flag'
+GO
+EXEC sys.sp_addextendedproperty
+'MS_Description', N'鍒涘缓閮ㄩ棬' ,
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'create_dept'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'create_by'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鍒涘缓鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'create_time'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鑰�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'update_by'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'鏇存柊鏃堕棿',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client',
+'COLUMN', N'update_time'
+GO
+EXEC sp_addextendedproperty
+'MS_Description', N'绯荤粺鎺堟潈琛�',
+'SCHEMA', N'dbo',
+'TABLE', N'sys_client'
+GO
+
+INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate())
+GO
+INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate())
+GO
+
+INSERT sys_dict_type VALUES (11, N'000000', N'鎺堟潈绫诲瀷', N'sys_grant_type', N'0', 103, 1, getdate(), NULL, NULL, N'璁よ瘉鎺堟潈绫诲瀷')
+GO
+INSERT sys_dict_type VALUES (12, N'000000', N'璁惧绫诲瀷', N'sys_device_type', N'0', 103, 1, getdate(), NULL, NULL, N'瀹㈡埛绔澶囩被鍨�')
+GO
+
+INSERT sys_dict_data VALUES (30, N'000000', 0, N'瀵嗙爜璁よ瘉', N'password', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'瀵嗙爜璁よ瘉');
+GO
+INSERT sys_dict_data VALUES (31, N'000000', 0, N'鐭俊璁よ瘉', N'sms', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'鐭俊璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (32, N'000000', 0, N'閭欢璁よ瘉', N'email', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'閭欢璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (33, N'000000', 0, N'灏忕▼搴忚璇�', N'xcx', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'灏忕▼搴忚璇�')
+GO
+INSERT sys_dict_data VALUES (34, N'000000', 0, N'涓夋柟鐧诲綍璁よ瘉', N'`social`', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'涓夋柟鐧诲綍璁よ瘉')
+GO
+INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'PC')
+GO
+INSERT sys_dict_data VALUES (36, N'000000', 0, N'瀹夊崜', N'`android`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'瀹夊崜')
+GO
+INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'iOS')
+GO
+INSERT sys_dict_data VALUES (38, N'000000', 0, N'灏忕▼搴�', N'`xcx`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'灏忕▼搴�')
+GO
+
+-- 浜岀骇鑿滃崟
+INSERT sys_menu VALUES (123, N'瀹㈡埛绔鐞�', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'瀹㈡埛绔鐞嗚彍鍗�')
+GO
+-- 瀹㈡埛绔鐞嗘寜閽�
+INSERT sys_menu VALUES (1061, N'瀹㈡埛绔鐞嗘煡璇�', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1062, N'瀹㈡埛绔鐞嗘柊澧�', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1063, N'瀹㈡埛绔鐞嗕慨鏀�', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1064, N'瀹㈡埛绔鐞嗗垹闄�', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1065, N'瀹㈡埛绔鐞嗗鍑�', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+
+
+-- 瑙掕壊鑿滃崟鏉冮檺
+INSERT sys_role_menu VALUES (2, 1061)
+GO
+INSERT sys_role_menu VALUES (2, 1062)
+GO
+INSERT sys_role_menu VALUES (2, 1063)
+GO
+INSERT sys_role_menu VALUES (2, 1064)
+GO
+INSERT sys_role_menu VALUES (2, 1065)
+GO
+
+
+UPDATE sys_dept SET leader = null
+GO
+ALTER TABLE sys_dept ALTER COLUMN leader bigint NULL
+GO
diff --git a/eims/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql b/eims/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql
new file mode 100644
index 0000000..2238536
--- /dev/null
+++ b/eims/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql
@@ -0,0 +1,19 @@
+ALTER TABLE sys_logininfor ADD client_key nvarchar(32) DEFAULT '' NULL
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'瀹㈡埛绔�',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'client_key'
+GO
+
+ALTER TABLE sys_logininfor ADD device_type nvarchar(32) DEFAULT '' NULL
+GO
+
+EXEC sp_addextendedproperty
+    'MS_Description', N'璁惧绫诲瀷',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_logininfor',
+    'COLUMN', N'device_type'
+GO
diff --git a/eims/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql b/eims/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql
new file mode 100644
index 0000000..9133772
--- /dev/null
+++ b/eims/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql
@@ -0,0 +1,10 @@
+DELETE FROM sys_menu WHERE menu_id IN (1604, 1605);
+GO
+INSERT sys_menu VALUES (1620, N'閰嶇疆鍒楄〃', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1621, N'閰嶇疆娣诲姞', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1622, N'閰嶇疆缂栬緫', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
+INSERT sys_menu VALUES (1623, N'閰嶇疆鍒犻櫎', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N'');
+GO
diff --git a/eims/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql b/eims/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql
new file mode 100644
index 0000000..18daca4
--- /dev/null
+++ b/eims/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql
@@ -0,0 +1,29 @@
+ALTER TABLE sys_dept ADD dept_category nvarchar(100) DEFAULT NULL
+EXEC sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬绫诲埆缂栫爜',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_dept',
+    'COLUMN', N'dept_category'
+GO
+ALTER TABLE sys_post ADD dept_id bigint NOT NULL
+GO
+ALTER TABLE sys_post ADD post_category nvarchar(100) DEFAULT NULL
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'閮ㄩ棬id',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'dept_id'
+GO
+EXEC sp_addextendedproperty
+    'MS_Description', N'宀椾綅绫诲埆缂栫爜',
+    'SCHEMA', N'dbo',
+    'TABLE', N'sys_post',
+    'COLUMN', N'post_category'
+GO
+UPDATE sys_post SET dept_id = 100
+GO
+UPDATE sys_post SET dept_id = 103 where post_id = 1
+GO
+UPDATE sys_menu SET menu_name = N'SnailJob鎺у埗鍙�', path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120
+GO
diff --git a/eims/script/sql/update/update_5.0-5.1.sql b/eims/script/sql/update/update_5.0-5.1.sql
new file mode 100644
index 0000000..871bda3
--- /dev/null
+++ b/eims/script/sql/update/update_5.0-5.1.sql
@@ -0,0 +1,101 @@
+ALTER TABLE gen_table ADD COLUMN data_name varchar(200) NULL DEFAULT '' COMMENT '鏁版嵁婧愬悕绉�' AFTER table_id;
+
+UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;
+
+-- ----------------------------
+-- 绗笁鏂瑰钩鍙版巿鏉冭〃
+-- ----------------------------
+drop table if exists sys_social;
+create table sys_social
+(
+    id                 bigint           not null        comment '涓婚敭',
+    user_id            bigint           not null        comment '鐢ㄦ埛ID',
+    tenant_id          varchar(20)      default null    comment '绉熸埛id',
+    auth_id            varchar(255)     not null        comment '骞冲彴+骞冲彴鍞竴id',
+    source             varchar(255)     not null        comment '鐢ㄦ埛鏉ユ簮',
+    open_id            varchar(255)     default null    comment '骞冲彴缂栧彿鍞竴id',
+    user_name          varchar(30)      not null        comment '鐧诲綍璐﹀彿',
+    nick_name          varchar(30)      default ''      comment '鐢ㄦ埛鏄电О',
+    email              varchar(255)     default ''      comment '鐢ㄦ埛閭',
+    avatar             varchar(500)     default ''      comment '澶村儚鍦板潃',
+    access_token       varchar(255)     not null        comment '鐢ㄦ埛鐨勬巿鏉冧护鐗�',
+    expire_in          int              default null    comment '鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    refresh_token      varchar(255)     default null    comment '鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    access_code        varchar(255)     default null    comment '骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    union_id           varchar(255)     default null    comment '鐢ㄦ埛鐨� unionid',
+    scope              varchar(255)     default null    comment '鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    token_type         varchar(255)     default null    comment '涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    id_token           varchar(255)     default null    comment 'id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    mac_algorithm      varchar(255)     default null    comment '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    mac_key            varchar(255)     default null    comment '灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    code               varchar(255)     default null    comment '鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�',
+    oauth_token        varchar(255)     default null    comment 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    oauth_token_secret varchar(255)     default null    comment 'Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁',
+    create_dept        bigint(20)                       comment '鍒涘缓閮ㄩ棬',
+    create_by          bigint(20)                       comment '鍒涘缓鑰�',
+    create_time        datetime                         comment '鍒涘缓鏃堕棿',
+    update_by          bigint(20)                       comment '鏇存柊鑰�',
+    update_time        datetime                         comment '鏇存柊鏃堕棿',
+    del_flag           char(1)          default '0'     comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    PRIMARY KEY (id)
+) engine=innodb comment = '绀句細鍖栧叧绯昏〃';
+
+
+-- ----------------------------
+-- 绯荤粺鎺堟潈琛�
+-- ----------------------------
+drop table if exists sys_client;
+create table sys_client (
+    id                  bigint(20)    not null            comment 'id',
+    client_id           varchar(64)   default null        comment '瀹㈡埛绔痠d',
+    client_key          varchar(32)   default null        comment '瀹㈡埛绔痥ey',
+    client_secret       varchar(255)  default null        comment '瀹㈡埛绔閽�',
+    grant_type          varchar(255)  default null        comment '鎺堟潈绫诲瀷',
+    device_type         varchar(32)   default null        comment '璁惧绫诲瀷',
+    active_timeout      int(11)       default 1800        comment 'token娲昏穬瓒呮椂鏃堕棿',
+    timeout             int(11)       default 604800      comment 'token鍥哄畾瓒呮椂',
+    status              char(1)       default '0'         comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+    del_flag            char(1)       default '0'         comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+    create_dept         bigint(20)    default null        comment '鍒涘缓閮ㄩ棬',
+    create_by           bigint(20)    default null        comment '鍒涘缓鑰�',
+    create_time         datetime      default null        comment '鍒涘缓鏃堕棿',
+    update_by           bigint(20)    default null        comment '鏇存柊鑰�',
+    update_time         datetime      default null        comment '鏇存柊鏃堕棿',
+    primary key (id)
+) engine=innodb comment='绯荤粺鎺堟潈琛�';
+
+insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate());
+insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate());
+
+insert into sys_dict_type values(11, '000000', '鎺堟潈绫诲瀷', 'sys_grant_type',     103, 1, sysdate(), null, null, '璁よ瘉鎺堟潈绫诲瀷');
+insert into sys_dict_type values(12, '000000', '璁惧绫诲瀷', 'sys_device_type',    103, 1, sysdate(), null, null, '瀹㈡埛绔澶囩被鍨�');
+
+insert into sys_dict_data values(30, '000000', 0,  '瀵嗙爜璁よ瘉', 'password',   'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate(), null, null, '瀵嗙爜璁よ瘉');
+insert into sys_dict_data values(31, '000000', 0,  '鐭俊璁よ瘉', 'sms',        'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate(), null, null, '鐭俊璁よ瘉');
+insert into sys_dict_data values(32, '000000', 0,  '閭欢璁よ瘉', 'email',      'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate(), null, null, '閭欢璁よ瘉');
+insert into sys_dict_data values(33, '000000', 0,  '灏忕▼搴忚璇�', 'xcx',      'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate(), null, null, '灏忕▼搴忚璇�');
+insert into sys_dict_data values(34, '000000', 0,  '涓夋柟鐧诲綍璁よ瘉', 'social', 'sys_grant_type',   '',   'default', 'N', 103, 1, sysdate(), null, null, '涓夋柟鐧诲綍璁よ瘉');
+insert into sys_dict_data values(35, '000000', 0,  'PC',    'pc',         'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, 'PC');
+insert into sys_dict_data values(36, '000000', 0,  '瀹夊崜', 'android',     'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, '瀹夊崜');
+insert into sys_dict_data values(37, '000000', 0,  'iOS', 'ios',          'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, 'iOS');
+insert into sys_dict_data values(38, '000000', 0,  '灏忕▼搴�', 'xcx',       'sys_device_type',     '',   'default', 'N', 103, 1, sysdate(), null, null, '灏忕▼搴�');
+
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('123',  '瀹㈡埛绔鐞�',   '1',   '11', 'client',           'system/client/index',          '', 1, 0, 'C', '0', '0', 'system:client:list',          'international', 103, 1, sysdate(), null, null, '瀹㈡埛绔鐞嗚彍鍗�');
+-- 瀹㈡埛绔鐞嗘寜閽�
+insert into sys_menu values('1061', '瀹㈡埛绔鐞嗘煡璇�', '123', '1',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1062', '瀹㈡埛绔鐞嗘柊澧�', '123', '2',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add',          '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1063', '瀹㈡埛绔鐞嗕慨鏀�', '123', '3',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1064', '瀹㈡埛绔鐞嗗垹闄�', '123', '4',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove',       '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1065', '瀹㈡埛绔鐞嗗鍑�', '123', '5',  '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export',       '#', 103, 1, sysdate(), null, null, '');
+
+-- 瑙掕壊鑿滃崟鏉冮檺
+insert into sys_role_menu values ('2', '1061');
+insert into sys_role_menu values ('2', '1062');
+insert into sys_role_menu values ('2', '1063');
+insert into sys_role_menu values ('2', '1064');
+insert into sys_role_menu values ('2', '1065');
+
+
+update sys_dept set leader = null;
+alter table sys_dept modify column leader bigint null default null comment '璐熻矗浜�' after order_num;
diff --git a/eims/script/sql/update/update_5.1.0-5.1.1.sql b/eims/script/sql/update/update_5.1.0-5.1.1.sql
new file mode 100644
index 0000000..1dea49b
--- /dev/null
+++ b/eims/script/sql/update/update_5.1.0-5.1.1.sql
@@ -0,0 +1,3 @@
+ALTER TABLE sys_logininfor
+    ADD COLUMN client_key VARCHAR(32)  NULL DEFAULT NULL COMMENT '瀹㈡埛绔�' AFTER `user_name`,
+    ADD COLUMN device_type VARCHAR(32) NULL DEFAULT NULL COMMENT '璁惧绫诲瀷' AFTER `client_key`;
diff --git a/eims/script/sql/update/update_5.1.1-5.1.2.sql b/eims/script/sql/update/update_5.1.1-5.1.2.sql
new file mode 100644
index 0000000..314743f
--- /dev/null
+++ b/eims/script/sql/update/update_5.1.1-5.1.2.sql
@@ -0,0 +1,5 @@
+delete from sys_menu where menu_id in (1604, 1605);
+insert into sys_menu values('1620', '閰嶇疆鍒楄〃', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1621', '閰嶇疆娣诲姞', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add',         '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1622', '閰嶇疆缂栬緫', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit',        '#', 103, 1, sysdate(), null, null, '');
+insert into sys_menu values('1623', '閰嶇疆鍒犻櫎', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove',      '#', 103, 1, sysdate(), null, null, '');
diff --git a/eims/script/sql/update/update_5.1.2-5.2.0.sql b/eims/script/sql/update/update_5.1.2-5.2.0.sql
new file mode 100644
index 0000000..33384e7
--- /dev/null
+++ b/eims/script/sql/update/update_5.1.2-5.2.0.sql
@@ -0,0 +1,5 @@
+ALTER TABLE sys_dept ADD dept_category VARCHAR(100) DEFAULT NULL COMMENT '閮ㄩ棬绫诲埆缂栫爜';
+ALTER TABLE sys_post ADD dept_id BIGINT(20) NOT NULL COMMENT '閮ㄩ棬id', ADD post_category VARCHAR(100) DEFAULT NULL COMMENT '宀椾綅绫诲埆缂栫爜';
+UPDATE sys_post SET dept_id = 100;
+UPDATE sys_post SET dept_id = 103 where post_id = 1;
+UPDATE sys_menu SET menu_name = 'SnailJob鎺у埗鍙�', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob鎺у埗鍙拌彍鍗�' WHERE menu_id = 120;

--
Gitblit v1.9.3